feat(polling-contracts): add generic polling interface with TypeScript types and Zod schemas

- Add @timesafari/polling-contracts package with comprehensive type definitions
- Implement GenericPollingRequest, PollingResult, and PollingScheduleConfig interfaces
- Add Zod schemas for StarredProjectsRequest/Response and DeepLinkParams validation
- Include calculateBackoffDelay utility with unified retry policy (exponential, linear, fixed)
- Add OutboxPressureManager for storage pressure controls and back-pressure signals
- Implement TelemetryManager with cardinality budgets and PII redaction
- Add ClockSyncManager for JWT timestamp validation and skew tolerance
- Include comprehensive unit tests with Jest snapshots and race condition testing
- Add JWT_ID_PATTERN regex for canonical JWT ID format validation
- Support idempotency with X-Idempotency-Key enforcement
- Implement watermark CAS (Compare-and-Swap) for race condition prevention

This establishes the foundation for the new generic polling system where host apps
define request/response schemas and the plugin provides robust polling logic.
This commit is contained in:
Matthew Raymer
2025-10-07 04:44:01 +00:00
parent 5b7bd95bdd
commit a5831b3c9f
18 changed files with 2599 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
/**
* Canonical constants for polling system
*/
// JWT ID regex pattern with named capture groups
export const JWT_ID_PATTERN = /^(?<ts>\d{10})_(?<rnd>[A-Za-z0-9]{6})_(?<hash>[a-f0-9]{8})$/;
// Default configuration values
export const DEFAULT_CONFIG = {
// Outbox pressure controls
maxUndelivered: 1000,
backpressureThreshold: 0.8,
maxRetries: 3,
cleanupIntervalMs: 3600000, // 1 hour
// Backoff policy
baseDelayMs: 1000,
maxDelayMs: 30000,
jitterFactor: 0.25,
respectRetryAfter: true,
retryAfterMaxMs: 300000, // 5 minutes
// Clock sync
maxClockSkewSeconds: 30,
skewCheckIntervalMs: 300000, // 5 minutes
jwtClockSkewTolerance: 30,
jwtMaxAge: 3600000, // 1 hour
// Telemetry
metricsPrefix: 'starred_projects',
logLevel: 'INFO'
} as const;
// Error codes
export const ERROR_CODES = {
INVALID_REQUEST: 'INVALID_REQUEST',
VALIDATION_ERROR: 'VALIDATION_ERROR',
RATE_LIMIT_EXCEEDED: 'RATE_LIMIT_EXCEEDED',
EXECUTION_ERROR: 'EXECUTION_ERROR',
CLOCK_SKEW_ERROR: 'CLOCK_SKEW_ERROR',
STORAGE_PRESSURE: 'STORAGE_PRESSURE'
} as const;
// HTTP status codes
export const HTTP_STATUS = {
OK: 200,
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
TOO_MANY_REQUESTS: 429,
INTERNAL_SERVER_ERROR: 500,
SERVICE_UNAVAILABLE: 503
} as const;