@spooled/sdk 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@
3
3
  var os = require('os');
4
4
 
5
5
  // src/config.ts
6
- var SDK_VERSION = "1.1.0";
6
+ var SDK_VERSION = "1.2.1";
7
7
  var DEFAULT_OPTIONS = {
8
8
  concurrency: 5,
9
9
  pollInterval: 1e3,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config.ts","../../src/worker/worker.ts"],"names":["osHostname"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * SDK Configuration\n *\n * Defines configuration types and defaults for the Spooled SDK.\n */\n\n/** Retry configuration options */\nexport interface RetryConfig {\n /** Maximum number of retry attempts (default: 3) */\n maxRetries: number;\n /** Base delay in milliseconds for exponential backoff (default: 1000) */\n baseDelay: number;\n /** Maximum delay in milliseconds (default: 30000) */\n maxDelay: number;\n /** Exponential backoff factor (default: 2) */\n factor: number;\n /** Whether to add jitter to delays (default: true) */\n jitter: boolean;\n /** Custom function to determine if an error is retryable */\n retryOn?: (error: Error, attempt: number) => boolean;\n}\n\n/** Circuit breaker configuration options */\nexport interface CircuitBreakerConfig {\n /** Whether circuit breaker is enabled (default: true) */\n enabled: boolean;\n /** Number of failures before opening the circuit (default: 5) */\n failureThreshold: number;\n /** Number of successes in half-open state to close circuit (default: 3) */\n successThreshold: number;\n /** Time in milliseconds to wait before trying again after opening (default: 30000) */\n timeout: number;\n}\n\n/** Debug logging function type */\nexport type DebugFn = (message: string, meta?: unknown) => void;\n\n/** Main SDK configuration options */\nexport interface SpooledClientConfig {\n /** API key for authentication (starts with sp_live_, sp_test_, sk_live_, or sk_test_) */\n apiKey?: string;\n /** JWT access token (alternative to API key) */\n accessToken?: string;\n /** JWT refresh token for automatic token renewal */\n refreshToken?: string;\n /** Admin API key (for /api/v1/admin/* endpoints; uses X-Admin-Key header) */\n adminKey?: string;\n /** Base URL for the REST API (default: https://api.spooled.cloud) */\n baseUrl?: string;\n /** WebSocket URL for realtime events (default: derived from baseUrl, e.g., wss://api.spooled.cloud) */\n wsUrl?: string;\n /** gRPC server address (default: grpc.spooled.cloud:443) */\n grpcAddress?: string;\n /** Request timeout in milliseconds (default: 30000) */\n timeout?: number;\n /** Number of retry attempts (shorthand for retry.maxRetries) */\n retries?: number;\n /** Base retry delay in milliseconds (shorthand for retry.baseDelay) */\n retryDelay?: number;\n /** Full retry configuration */\n retry?: Partial<RetryConfig>;\n /** Circuit breaker configuration */\n circuitBreaker?: Partial<CircuitBreakerConfig>;\n /** Additional headers to include in all requests */\n headers?: Record<string, string>;\n /** Custom fetch implementation (for testing or special runtimes) */\n fetch?: typeof fetch;\n /** Custom user agent string */\n userAgent?: string;\n /** Enable debug logging */\n debug?: boolean | DebugFn;\n /** Whether to automatically refresh tokens when they expire (default: true) */\n autoRefreshToken?: boolean;\n}\n\n/** Resolved configuration with all defaults applied */\nexport interface ResolvedConfig {\n apiKey?: string;\n accessToken?: string;\n refreshToken?: string;\n adminKey?: string;\n baseUrl: string;\n wsUrl: string;\n grpcAddress: string;\n timeout: number;\n retry: RetryConfig;\n circuitBreaker: CircuitBreakerConfig;\n headers: Record<string, string>;\n fetch: typeof fetch;\n userAgent: string;\n debug: DebugFn | null;\n autoRefreshToken: boolean;\n}\n\n/** Default configuration values */\nexport const DEFAULT_CONFIG = {\n baseUrl: \"https://api.spooled.cloud\",\n wsUrl: \"wss://api.spooled.cloud\",\n grpcAddress: \"grpc.spooled.cloud:443\",\n timeout: 30000,\n retry: {\n maxRetries: 3,\n baseDelay: 1000,\n maxDelay: 30000,\n factor: 2,\n jitter: true,\n } satisfies RetryConfig,\n circuitBreaker: {\n enabled: true,\n failureThreshold: 5,\n successThreshold: 3,\n timeout: 30000,\n } satisfies CircuitBreakerConfig,\n userAgent: \"@spooled/sdk-nodejs/1.1.0\",\n autoRefreshToken: true,\n} as const;\n\n/** SDK version */\nexport const SDK_VERSION = \"1.1.0\";\n\n/** API version prefix */\nexport const API_VERSION = \"v1\";\n\n/** API base path */\nexport const API_BASE_PATH = `/api/${API_VERSION}`;\n\n/**\n * Trim surrounding whitespace from a credential string and treat an\n * all-whitespace input as unset. Mirrors the trim policy in the Go, PHP,\n * and Python SDKs so behavior is consistent across languages.\n */\nfunction normalizeCredential(value: string | undefined): string | undefined {\n if (value === undefined) {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed === \"\" ? undefined : trimmed;\n}\n\n/**\n * Resolve configuration by merging user options with defaults\n */\nexport function resolveConfig(options: SpooledClientConfig): ResolvedConfig {\n // Create debug function\n let debugFn: DebugFn | null = null;\n if (options.debug === true) {\n debugFn = (message: string, meta?: unknown) => {\n // eslint-disable-next-line no-console\n console.log(`[spooled-sdk] ${message}`, meta !== undefined ? meta : \"\");\n };\n } else if (typeof options.debug === \"function\") {\n debugFn = options.debug;\n }\n\n // Merge retry config\n const retry: RetryConfig = {\n ...DEFAULT_CONFIG.retry,\n ...options.retry,\n // Allow shorthand overrides\n ...(options.retries !== undefined && { maxRetries: options.retries }),\n ...(options.retryDelay !== undefined && { baseDelay: options.retryDelay }),\n };\n\n // Merge circuit breaker config\n const circuitBreaker: CircuitBreakerConfig = {\n ...DEFAULT_CONFIG.circuitBreaker,\n ...options.circuitBreaker,\n };\n\n // Build headers\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...options.headers,\n };\n\n // Resolve base URL first\n const baseUrl = options.baseUrl ?? DEFAULT_CONFIG.baseUrl;\n\n // Derive WebSocket URL from base URL if not explicitly set\n // Replace http(s):// with ws(s)://\n const derivedWsUrl = baseUrl.replace(/^http/, \"ws\");\n const wsUrl = options.wsUrl ?? derivedWsUrl;\n\n // Trim whitespace (including a stray trailing '\\n') from every credential.\n // Node's `undici` fetch rejects `Authorization: Bearer <key>\\n` with an\n // opaque `TypeError: HeaderValue` and users routinely paste keys from\n // `.env` files that include a newline; normalizing here keeps behavior\n // consistent with the Go, PHP, and Python SDKs.\n return {\n apiKey: normalizeCredential(options.apiKey),\n accessToken: normalizeCredential(options.accessToken),\n refreshToken: normalizeCredential(options.refreshToken),\n adminKey: normalizeCredential(options.adminKey),\n baseUrl,\n wsUrl,\n grpcAddress: options.grpcAddress ?? DEFAULT_CONFIG.grpcAddress,\n timeout: options.timeout ?? DEFAULT_CONFIG.timeout,\n retry,\n circuitBreaker,\n headers,\n fetch: options.fetch ?? globalThis.fetch,\n userAgent: options.userAgent ?? DEFAULT_CONFIG.userAgent,\n debug: debugFn,\n autoRefreshToken:\n options.autoRefreshToken ?? DEFAULT_CONFIG.autoRefreshToken,\n };\n}\n\n/**\n * Validate configuration options\n * @throws Error if configuration is invalid\n */\nexport function validateConfig(config: ResolvedConfig): void {\n // Must have at least one auth method\n if (!config.apiKey && !config.accessToken) {\n throw new Error(\n \"SpooledClient requires either apiKey or accessToken for authentication\",\n );\n }\n\n // Validate API key format if provided\n // Accept both sp_ (new standard) and sk_ (legacy) prefixes\n if (\n config.apiKey &&\n !config.apiKey.startsWith(\"sp_\") &&\n !config.apiKey.startsWith(\"sk_\")\n ) {\n throw new Error(\n \"Invalid API key format. API keys should start with sp_live_, sp_test_, sk_live_, or sk_test_\",\n );\n }\n\n // Validate baseUrl\n if (\n !config.baseUrl.startsWith(\"http://\") &&\n !config.baseUrl.startsWith(\"https://\")\n ) {\n throw new Error(\"baseUrl must start with http:// or https://\");\n }\n\n // Validate timeout\n if (config.timeout <= 0) {\n throw new Error(\"timeout must be a positive number\");\n }\n\n // Validate retry config\n if (config.retry.maxRetries < 0) {\n throw new Error(\"retry.maxRetries must be non-negative\");\n }\n if (config.retry.baseDelay <= 0) {\n throw new Error(\"retry.baseDelay must be positive\");\n }\n if (config.retry.maxDelay < config.retry.baseDelay) {\n throw new Error(\"retry.maxDelay must be >= retry.baseDelay\");\n }\n if (config.retry.factor < 1) {\n throw new Error(\"retry.factor must be >= 1\");\n }\n\n // Validate circuit breaker config\n if (config.circuitBreaker.enabled) {\n if (config.circuitBreaker.failureThreshold <= 0) {\n throw new Error(\"circuitBreaker.failureThreshold must be positive\");\n }\n if (config.circuitBreaker.successThreshold <= 0) {\n throw new Error(\"circuitBreaker.successThreshold must be positive\");\n }\n if (config.circuitBreaker.timeout <= 0) {\n throw new Error(\"circuitBreaker.timeout must be positive\");\n }\n }\n}\n","/**\n * Spooled Worker\n *\n * Worker runtime for processing jobs from a queue.\n */\n\nimport type { SpooledClient } from \"../client.js\";\nimport { SDK_VERSION } from \"../config.js\";\nimport type { JsonObject } from \"../types/common.js\";\nimport type { ClaimedJob } from \"../types/jobs.js\";\nimport type {\n SpooledWorkerOptions,\n WorkerState,\n JobHandler,\n JobContext,\n WorkerEvent,\n WorkerEventData,\n ActiveJob,\n} from \"./types.js\";\nimport { hostname as osHostname } from \"os\";\n\n/** Default options */\nconst DEFAULT_OPTIONS = {\n concurrency: 5,\n pollInterval: 1000,\n leaseDuration: 30,\n heartbeatFraction: 0.5,\n autoStart: false,\n shutdownTimeout: 30000,\n} as const;\n\n/** Event handler type */\ntype EventHandler<E extends WorkerEvent> = (data: WorkerEventData[E]) => void;\n\n/**\n * Spooled Worker\n *\n * @example\n * ```typescript\n * const worker = new SpooledWorker(client, {\n * queueName: 'my-queue',\n * concurrency: 10,\n * });\n *\n * worker.process(async (ctx) => {\n * console.log('Processing job:', ctx.jobId);\n * await doSomeWork(ctx.payload);\n * return { success: true };\n * });\n *\n * await worker.start();\n *\n * // Graceful shutdown\n * process.on('SIGTERM', () => worker.stop());\n * ```\n */\nexport class SpooledWorker {\n private readonly client: SpooledClient;\n /**\n * Options with every defaultable field filled in. `workerId` stays optional:\n * there is no sensible default for it, and omitting it is what makes the\n * server mint a UUID.\n */\n private readonly options: Required<Omit<SpooledWorkerOptions, \"workerId\">> &\n Pick<SpooledWorkerOptions, \"workerId\">;\n private readonly debug: (msg: string, meta?: unknown) => void;\n\n private state: WorkerState = \"idle\";\n private workerId: string | null = null;\n private handler: JobHandler | null = null;\n private activeJobs: Map<symbol, ActiveJob> = new Map();\n private pollTimer: ReturnType<typeof setTimeout> | null = null;\n private workerHeartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private shutdownPromise: Promise<void> | null = null;\n\n // Event handlers\n private eventHandlers: Map<WorkerEvent, Set<EventHandler<WorkerEvent>>> =\n new Map();\n\n constructor(client: SpooledClient, options: SpooledWorkerOptions) {\n this.client = client;\n this.options = {\n ...DEFAULT_OPTIONS,\n hostname: osHostname(),\n workerType: \"nodejs\",\n version: SDK_VERSION,\n metadata: {},\n ...options,\n } as Required<Omit<SpooledWorkerOptions, \"workerId\">> &\n Pick<SpooledWorkerOptions, \"workerId\">;\n\n // Get debug from client config\n const config = client.getConfig();\n this.debug = config.debug ?? (() => {});\n\n if (this.options.autoStart) {\n // Defer to next tick to allow process() to be called\n setImmediate(() => this.start());\n }\n }\n\n /**\n * Get current worker state\n */\n getState(): WorkerState {\n return this.state;\n }\n\n /**\n * Get worker ID (available after start)\n */\n getWorkerId(): string | null {\n return this.workerId;\n }\n\n /**\n * Get number of active jobs\n */\n getActiveJobCount(): number {\n return this.activeJobs.size;\n }\n\n /**\n * Register job handler\n */\n process(handler: JobHandler): void {\n if (this.state !== \"idle\") {\n throw new Error(\"Cannot set handler after worker has started\");\n }\n this.handler = handler;\n }\n\n /**\n * Start the worker\n */\n async start(): Promise<void> {\n if (this.state !== \"idle\") {\n throw new Error(`Cannot start worker in state: ${this.state}`);\n }\n\n if (!this.handler) {\n throw new Error(\"No job handler registered. Call process() first.\");\n }\n\n this.state = \"starting\";\n this.debug(`Starting worker for queue: ${this.options.queueName}`);\n\n try {\n // Register with the API\n const registration = await this.client.workers.register({\n queueName: this.options.queueName,\n workerId: this.options.workerId,\n hostname: this.options.hostname,\n workerType: this.options.workerType,\n maxConcurrency: this.options.concurrency,\n metadata: this.options.metadata,\n version: this.options.version,\n });\n\n this.workerId = registration.id;\n this.debug(`Worker registered: ${this.workerId}`, registration);\n\n // Start worker heartbeat\n const heartbeatInterval = registration.heartbeatIntervalSecs * 1000;\n this.workerHeartbeatTimer = setInterval(() => {\n this.sendWorkerHeartbeat();\n }, heartbeatInterval);\n\n // Start polling\n this.state = \"running\";\n this.emit(\"started\", {\n workerId: this.workerId,\n queueName: this.options.queueName,\n });\n this.schedulePoll();\n } catch (error) {\n this.state = \"error\";\n this.emit(\"error\", { error: error as Error });\n throw error;\n }\n }\n\n /**\n * Stop the worker gracefully\n */\n async stop(): Promise<void> {\n if (this.state !== \"running\") {\n return;\n }\n\n // Deduplicate concurrent stop calls\n if (this.shutdownPromise) {\n return this.shutdownPromise;\n }\n\n this.shutdownPromise = this.doStop();\n return this.shutdownPromise;\n }\n\n private async doStop(): Promise<void> {\n this.state = \"stopping\";\n this.debug(\"Stopping worker...\");\n\n // Stop polling\n if (this.pollTimer) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n\n // Stop worker heartbeat\n if (this.workerHeartbeatTimer) {\n clearInterval(this.workerHeartbeatTimer);\n this.workerHeartbeatTimer = null;\n }\n\n // Signal all active jobs to stop\n for (const active of this.activeJobs.values()) {\n active.abortController.abort();\n }\n\n // Wait for active jobs to complete (with timeout)\n if (this.activeJobs.size > 0) {\n this.debug(\n `Waiting for ${this.activeJobs.size} active jobs to complete...`,\n );\n\n await Promise.race([\n this.waitForActiveJobs(),\n this.sleep(this.options.shutdownTimeout),\n ]);\n\n // Force-fail any remaining jobs. Snapshot the entries first because\n // cleanupJob() mutates the activeJobs map as we go.\n const remaining = Array.from(this.activeJobs.values());\n for (const active of remaining) {\n this.debug(\n `Force-failing job ${active.job.id} due to shutdown timeout`,\n );\n await this.failJob(active.job, \"Worker shutdown timeout\");\n // The handler's finally may never run if user code ignores the abort\n // signal, so explicitly clear this exact execution's timer.\n this.cleanupJob(active);\n }\n }\n\n // Deregister worker\n if (this.workerId) {\n try {\n await this.client.workers.deregister(this.workerId);\n this.debug(\"Worker deregistered\");\n } catch (error) {\n this.debug(\"Failed to deregister worker\", error);\n }\n }\n\n this.state = \"stopped\";\n this.workerId = null;\n this.emit(\"stopped\", { workerId: this.workerId ?? \"\", reason: \"graceful\" });\n this.shutdownPromise = null;\n }\n\n /**\n * Add event listener\n */\n on<E extends WorkerEvent>(event: E, handler: EventHandler<E>): () => void {\n if (!this.eventHandlers.has(event)) {\n this.eventHandlers.set(event, new Set());\n }\n this.eventHandlers.get(event)!.add(handler as EventHandler<WorkerEvent>);\n return () => this.off(event, handler);\n }\n\n /**\n * Remove event listener\n */\n off<E extends WorkerEvent>(event: E, handler: EventHandler<E>): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.delete(handler as EventHandler<WorkerEvent>);\n }\n }\n\n // Private methods\n\n private emit<E extends WorkerEvent>(\n event: E,\n data: WorkerEventData[E],\n ): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(data);\n } catch (error) {\n this.debug(\"Event handler error\", { event, error });\n }\n });\n }\n }\n\n private schedulePoll(): void {\n if (this.state !== \"running\") {\n return;\n }\n\n this.pollTimer = setTimeout(() => this.poll(), this.options.pollInterval);\n }\n\n private async poll(): Promise<void> {\n if (this.state !== \"running\" || !this.workerId) {\n return;\n }\n\n // Check if we have capacity\n const availableSlots = this.options.concurrency - this.activeJobs.size;\n if (availableSlots <= 0) {\n this.schedulePoll();\n return;\n }\n\n try {\n // Claim jobs\n const result = await this.client.jobs.claim({\n queueName: this.options.queueName,\n workerId: this.workerId,\n limit: availableSlots,\n leaseDurationSecs: this.options.leaseDuration,\n });\n\n // Process claimed jobs\n for (const job of result.jobs) {\n this.processJob(job);\n }\n } catch (error) {\n this.debug(\"Poll failed\", error);\n this.emit(\"error\", { error: error as Error });\n }\n\n // Schedule next poll\n this.schedulePoll();\n }\n\n private processJob(job: ClaimedJob): void {\n this.emit(\"job:claimed\", { jobId: job.id, queueName: job.queueName });\n\n const abortController = new AbortController();\n const activeJob: ActiveJob = {\n executionId: Symbol(job.id),\n job,\n startedAt: new Date(),\n abortController,\n };\n\n this.activeJobs.set(activeJob.executionId, activeJob);\n\n // Capture the immutable execution so a replacement lease cannot be borrowed.\n const heartbeatInterval =\n this.options.leaseDuration * this.options.heartbeatFraction * 1000;\n activeJob.heartbeatTimer = setInterval(() => {\n this.sendJobHeartbeat(activeJob);\n }, heartbeatInterval);\n\n // Execute handler\n this.executeHandler(activeJob);\n }\n\n private async executeHandler(activeJob: ActiveJob): Promise<void> {\n const { job, abortController } = activeJob;\n const { signal } = abortController;\n\n this.emit(\"job:started\", { jobId: job.id, queueName: job.queueName });\n\n const context: JobContext = {\n jobId: job.id,\n queueName: job.queueName,\n payload: job.payload,\n retryCount: job.retryCount,\n maxRetries: job.maxRetries,\n signal,\n progress: async (percent: number, message?: string) => {\n const boundedPercent = Math.max(0, Math.min(100, percent));\n this.debug(`[${job.id}] progress ${boundedPercent}%`, message);\n },\n log: (level, message, meta) => {\n this.debug(`[${job.id}] [${level}] ${message}`, meta);\n },\n };\n\n try {\n const result = await this.handler!(context);\n\n // Check if aborted\n if (signal.aborted) {\n this.debug(`Job ${job.id} was aborted`);\n return;\n }\n\n // Complete the job\n await this.completeJob(job, result ?? undefined);\n } catch (error) {\n // Check if aborted\n if (signal.aborted) {\n this.debug(`Job ${job.id} was aborted`);\n return;\n }\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n await this.failJob(job, errorMessage);\n } finally {\n this.cleanupJob(activeJob);\n }\n }\n\n private async completeJob(\n job: ClaimedJob,\n result?: JsonObject,\n ): Promise<void> {\n if (!this.workerId) return;\n\n try {\n await this.client.jobs.complete(job.id, {\n workerId: this.workerId,\n result,\n ...(job.leaseId != null && { leaseId: job.leaseId }),\n });\n\n this.emit(\"job:completed\", {\n jobId: job.id,\n queueName: job.queueName,\n result,\n });\n } catch (error) {\n this.debug(`Failed to complete job ${job.id}`, error);\n }\n }\n\n private async failJob(job: ClaimedJob, errorMessage: string): Promise<void> {\n if (!this.workerId) return;\n\n const willRetry = job.retryCount < job.maxRetries;\n\n try {\n await this.client.jobs.fail(job.id, {\n workerId: this.workerId,\n error: errorMessage,\n ...(job.leaseId != null && { leaseId: job.leaseId }),\n });\n\n this.emit(\"job:failed\", {\n jobId: job.id,\n queueName: job.queueName,\n error: errorMessage,\n willRetry,\n });\n } catch (error) {\n this.debug(`Failed to fail job ${job.id}`, error);\n }\n }\n\n private cleanupJob(activeJob: ActiveJob): void {\n if (activeJob.heartbeatTimer) {\n clearInterval(activeJob.heartbeatTimer);\n activeJob.heartbeatTimer = undefined;\n }\n\n if (this.activeJobs.get(activeJob.executionId) === activeJob) {\n this.activeJobs.delete(activeJob.executionId);\n }\n }\n\n private async sendJobHeartbeat(activeJob: ActiveJob): Promise<void> {\n if (!this.workerId) return;\n\n const { job } = activeJob;\n\n try {\n await this.client.jobs.heartbeat(job.id, {\n workerId: this.workerId,\n leaseDurationSecs: this.options.leaseDuration,\n ...(job.leaseId != null && { leaseId: job.leaseId }),\n });\n } catch (error) {\n this.debug(`Job heartbeat failed for ${job.id}`, error);\n }\n }\n\n private async sendWorkerHeartbeat(): Promise<void> {\n if (!this.workerId || this.state !== \"running\") return;\n\n try {\n await this.client.workers.heartbeat(this.workerId, {\n currentJobs: this.activeJobs.size,\n status: \"healthy\",\n });\n } catch (error) {\n this.debug(\"Worker heartbeat failed\", error);\n }\n }\n\n private async waitForActiveJobs(): Promise<void> {\n while (this.activeJobs.size > 0) {\n await this.sleep(100);\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/config.ts","../../src/worker/worker.ts"],"names":["osHostname"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * SDK Configuration\n *\n * Defines configuration types and defaults for the Spooled SDK.\n */\n\n/** Retry configuration options */\nexport interface RetryConfig {\n /** Maximum number of retry attempts (default: 3) */\n maxRetries: number;\n /** Base delay in milliseconds for exponential backoff (default: 1000) */\n baseDelay: number;\n /** Maximum delay in milliseconds (default: 30000) */\n maxDelay: number;\n /** Exponential backoff factor (default: 2) */\n factor: number;\n /** Whether to add jitter to delays (default: true) */\n jitter: boolean;\n /** Custom function to determine if an error is retryable */\n retryOn?: (error: Error, attempt: number) => boolean;\n}\n\n/** Circuit breaker configuration options */\nexport interface CircuitBreakerConfig {\n /** Whether circuit breaker is enabled (default: true) */\n enabled: boolean;\n /** Number of failures before opening the circuit (default: 5) */\n failureThreshold: number;\n /** Number of successes in half-open state to close circuit (default: 3) */\n successThreshold: number;\n /** Time in milliseconds to wait before trying again after opening (default: 30000) */\n timeout: number;\n}\n\n/** Debug logging function type */\nexport type DebugFn = (message: string, meta?: unknown) => void;\n\n/** Main SDK configuration options */\nexport interface SpooledClientConfig {\n /** API key for authentication (starts with sp_live_, sp_test_, sk_live_, or sk_test_) */\n apiKey?: string;\n /** JWT access token (alternative to API key) */\n accessToken?: string;\n /** JWT refresh token for automatic token renewal */\n refreshToken?: string;\n /** Admin API key (for /api/v1/admin/* endpoints; uses X-Admin-Key header) */\n adminKey?: string;\n /** Base URL for the REST API (default: https://api.spooled.cloud) */\n baseUrl?: string;\n /** WebSocket URL for realtime events (default: derived from baseUrl, e.g., wss://api.spooled.cloud) */\n wsUrl?: string;\n /** gRPC server address (default: grpc.spooled.cloud:443) */\n grpcAddress?: string;\n /** Request timeout in milliseconds (default: 30000) */\n timeout?: number;\n /** Number of retry attempts (shorthand for retry.maxRetries) */\n retries?: number;\n /** Base retry delay in milliseconds (shorthand for retry.baseDelay) */\n retryDelay?: number;\n /** Full retry configuration */\n retry?: Partial<RetryConfig>;\n /** Circuit breaker configuration */\n circuitBreaker?: Partial<CircuitBreakerConfig>;\n /** Additional headers to include in all requests */\n headers?: Record<string, string>;\n /** Custom fetch implementation (for testing or special runtimes) */\n fetch?: typeof fetch;\n /** Custom user agent string */\n userAgent?: string;\n /** Enable debug logging */\n debug?: boolean | DebugFn;\n /** Whether to automatically refresh tokens when they expire (default: true) */\n autoRefreshToken?: boolean;\n}\n\n/** Resolved configuration with all defaults applied */\nexport interface ResolvedConfig {\n apiKey?: string;\n accessToken?: string;\n refreshToken?: string;\n adminKey?: string;\n baseUrl: string;\n wsUrl: string;\n grpcAddress: string;\n timeout: number;\n retry: RetryConfig;\n circuitBreaker: CircuitBreakerConfig;\n headers: Record<string, string>;\n fetch: typeof fetch;\n userAgent: string;\n debug: DebugFn | null;\n autoRefreshToken: boolean;\n}\n\n/** Default configuration values */\nexport const DEFAULT_CONFIG = {\n baseUrl: \"https://api.spooled.cloud\",\n wsUrl: \"wss://api.spooled.cloud\",\n grpcAddress: \"grpc.spooled.cloud:443\",\n timeout: 30000,\n retry: {\n maxRetries: 3,\n baseDelay: 1000,\n maxDelay: 30000,\n factor: 2,\n jitter: true,\n } satisfies RetryConfig,\n circuitBreaker: {\n enabled: true,\n failureThreshold: 5,\n successThreshold: 3,\n timeout: 30000,\n } satisfies CircuitBreakerConfig,\n userAgent: \"@spooled/sdk-nodejs/1.2.1\",\n autoRefreshToken: true,\n} as const;\n\n/** SDK version */\nexport const SDK_VERSION = \"1.2.1\";\n\n/** API version prefix */\nexport const API_VERSION = \"v1\";\n\n/** API base path */\nexport const API_BASE_PATH = `/api/${API_VERSION}`;\n\n/**\n * Trim surrounding whitespace from a credential string and treat an\n * all-whitespace input as unset. Mirrors the trim policy in the Go, PHP,\n * and Python SDKs so behavior is consistent across languages.\n */\nfunction normalizeCredential(value: string | undefined): string | undefined {\n if (value === undefined) {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed === \"\" ? undefined : trimmed;\n}\n\n/**\n * Resolve configuration by merging user options with defaults\n */\nexport function resolveConfig(options: SpooledClientConfig): ResolvedConfig {\n // Create debug function\n let debugFn: DebugFn | null = null;\n if (options.debug === true) {\n debugFn = (message: string, meta?: unknown) => {\n // eslint-disable-next-line no-console\n console.log(`[spooled-sdk] ${message}`, meta !== undefined ? meta : \"\");\n };\n } else if (typeof options.debug === \"function\") {\n debugFn = options.debug;\n }\n\n // Merge retry config\n const retry: RetryConfig = {\n ...DEFAULT_CONFIG.retry,\n ...options.retry,\n // Allow shorthand overrides\n ...(options.retries !== undefined && { maxRetries: options.retries }),\n ...(options.retryDelay !== undefined && { baseDelay: options.retryDelay }),\n };\n\n // Merge circuit breaker config\n const circuitBreaker: CircuitBreakerConfig = {\n ...DEFAULT_CONFIG.circuitBreaker,\n ...options.circuitBreaker,\n };\n\n // Build headers\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...options.headers,\n };\n\n // Resolve base URL first\n const baseUrl = options.baseUrl ?? DEFAULT_CONFIG.baseUrl;\n\n // Derive WebSocket URL from base URL if not explicitly set\n // Replace http(s):// with ws(s)://\n const derivedWsUrl = baseUrl.replace(/^http/, \"ws\");\n const wsUrl = options.wsUrl ?? derivedWsUrl;\n\n // Trim whitespace (including a stray trailing '\\n') from every credential.\n // Node's `undici` fetch rejects `Authorization: Bearer <key>\\n` with an\n // opaque `TypeError: HeaderValue` and users routinely paste keys from\n // `.env` files that include a newline; normalizing here keeps behavior\n // consistent with the Go, PHP, and Python SDKs.\n return {\n apiKey: normalizeCredential(options.apiKey),\n accessToken: normalizeCredential(options.accessToken),\n refreshToken: normalizeCredential(options.refreshToken),\n adminKey: normalizeCredential(options.adminKey),\n baseUrl,\n wsUrl,\n grpcAddress: options.grpcAddress ?? DEFAULT_CONFIG.grpcAddress,\n timeout: options.timeout ?? DEFAULT_CONFIG.timeout,\n retry,\n circuitBreaker,\n headers,\n fetch: options.fetch ?? globalThis.fetch,\n userAgent: options.userAgent ?? DEFAULT_CONFIG.userAgent,\n debug: debugFn,\n autoRefreshToken:\n options.autoRefreshToken ?? DEFAULT_CONFIG.autoRefreshToken,\n };\n}\n\n/**\n * Validate configuration options\n * @throws Error if configuration is invalid\n */\nexport function validateConfig(config: ResolvedConfig): void {\n // Must have at least one auth method\n if (!config.apiKey && !config.accessToken) {\n throw new Error(\n \"SpooledClient requires either apiKey or accessToken for authentication\",\n );\n }\n\n // Validate API key format if provided\n // Accept both sp_ (new standard) and sk_ (legacy) prefixes\n if (\n config.apiKey &&\n !config.apiKey.startsWith(\"sp_\") &&\n !config.apiKey.startsWith(\"sk_\")\n ) {\n throw new Error(\n \"Invalid API key format. API keys should start with sp_live_, sp_test_, sk_live_, or sk_test_\",\n );\n }\n\n // Validate baseUrl\n if (\n !config.baseUrl.startsWith(\"http://\") &&\n !config.baseUrl.startsWith(\"https://\")\n ) {\n throw new Error(\"baseUrl must start with http:// or https://\");\n }\n\n // Validate timeout\n if (config.timeout <= 0) {\n throw new Error(\"timeout must be a positive number\");\n }\n\n // Validate retry config\n if (config.retry.maxRetries < 0) {\n throw new Error(\"retry.maxRetries must be non-negative\");\n }\n if (config.retry.baseDelay <= 0) {\n throw new Error(\"retry.baseDelay must be positive\");\n }\n if (config.retry.maxDelay < config.retry.baseDelay) {\n throw new Error(\"retry.maxDelay must be >= retry.baseDelay\");\n }\n if (config.retry.factor < 1) {\n throw new Error(\"retry.factor must be >= 1\");\n }\n\n // Validate circuit breaker config\n if (config.circuitBreaker.enabled) {\n if (config.circuitBreaker.failureThreshold <= 0) {\n throw new Error(\"circuitBreaker.failureThreshold must be positive\");\n }\n if (config.circuitBreaker.successThreshold <= 0) {\n throw new Error(\"circuitBreaker.successThreshold must be positive\");\n }\n if (config.circuitBreaker.timeout <= 0) {\n throw new Error(\"circuitBreaker.timeout must be positive\");\n }\n }\n}\n","/**\n * Spooled Worker\n *\n * Worker runtime for processing jobs from a queue.\n */\n\nimport type { SpooledClient } from \"../client.js\";\nimport { SDK_VERSION } from \"../config.js\";\nimport type { JsonValue } from \"../types/common.js\";\nimport type { ClaimedJob } from \"../types/jobs.js\";\nimport type {\n SpooledWorkerOptions,\n WorkerState,\n JobHandler,\n JobContext,\n WorkerEvent,\n WorkerEventData,\n ActiveJob,\n} from \"./types.js\";\nimport { hostname as osHostname } from \"os\";\n\n/** Default options */\nconst DEFAULT_OPTIONS = {\n concurrency: 5,\n pollInterval: 1000,\n leaseDuration: 30,\n heartbeatFraction: 0.5,\n autoStart: false,\n shutdownTimeout: 30000,\n} as const;\n\n/** Event handler type */\ntype EventHandler<E extends WorkerEvent> = (data: WorkerEventData[E]) => void;\n\n/**\n * Spooled Worker\n *\n * @example\n * ```typescript\n * const worker = new SpooledWorker(client, {\n * queueName: 'my-queue',\n * concurrency: 10,\n * });\n *\n * worker.process(async (ctx) => {\n * console.log('Processing job:', ctx.jobId);\n * await doSomeWork(ctx.payload);\n * return { success: true };\n * });\n *\n * await worker.start();\n *\n * // Graceful shutdown\n * process.on('SIGTERM', () => worker.stop());\n * ```\n */\nexport class SpooledWorker {\n private readonly client: SpooledClient;\n /**\n * Options with every defaultable field filled in. `workerId` stays optional:\n * there is no sensible default for it, and omitting it is what makes the\n * server mint a UUID.\n */\n private readonly options: Required<Omit<SpooledWorkerOptions, \"workerId\">> &\n Pick<SpooledWorkerOptions, \"workerId\">;\n private readonly debug: (msg: string, meta?: unknown) => void;\n\n private state: WorkerState = \"idle\";\n private workerId: string | null = null;\n private handler: JobHandler | null = null;\n private activeJobs: Map<symbol, ActiveJob> = new Map();\n private pollTimer: ReturnType<typeof setTimeout> | null = null;\n private workerHeartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private shutdownPromise: Promise<void> | null = null;\n\n // Event handlers\n private eventHandlers: Map<WorkerEvent, Set<EventHandler<WorkerEvent>>> =\n new Map();\n\n constructor(client: SpooledClient, options: SpooledWorkerOptions) {\n this.client = client;\n this.options = {\n ...DEFAULT_OPTIONS,\n hostname: osHostname(),\n workerType: \"nodejs\",\n version: SDK_VERSION,\n metadata: {},\n ...options,\n } as Required<Omit<SpooledWorkerOptions, \"workerId\">> &\n Pick<SpooledWorkerOptions, \"workerId\">;\n\n // Get debug from client config\n const config = client.getConfig();\n this.debug = config.debug ?? (() => {});\n\n if (this.options.autoStart) {\n // Defer to next tick to allow process() to be called\n setImmediate(() => this.start());\n }\n }\n\n /**\n * Get current worker state\n */\n getState(): WorkerState {\n return this.state;\n }\n\n /**\n * Get worker ID (available after start)\n */\n getWorkerId(): string | null {\n return this.workerId;\n }\n\n /**\n * Get number of active jobs\n */\n getActiveJobCount(): number {\n return this.activeJobs.size;\n }\n\n /**\n * Register job handler\n */\n process(handler: JobHandler): void {\n if (this.state !== \"idle\") {\n throw new Error(\"Cannot set handler after worker has started\");\n }\n this.handler = handler;\n }\n\n /**\n * Start the worker\n */\n async start(): Promise<void> {\n if (this.state !== \"idle\") {\n throw new Error(`Cannot start worker in state: ${this.state}`);\n }\n\n if (!this.handler) {\n throw new Error(\"No job handler registered. Call process() first.\");\n }\n\n this.state = \"starting\";\n this.debug(`Starting worker for queue: ${this.options.queueName}`);\n\n try {\n // Register with the API\n const registration = await this.client.workers.register({\n queueName: this.options.queueName,\n workerId: this.options.workerId,\n hostname: this.options.hostname,\n workerType: this.options.workerType,\n maxConcurrency: this.options.concurrency,\n metadata: this.options.metadata,\n version: this.options.version,\n });\n\n this.workerId = registration.id;\n this.debug(`Worker registered: ${this.workerId}`, registration);\n\n // Start worker heartbeat\n const heartbeatInterval = registration.heartbeatIntervalSecs * 1000;\n this.workerHeartbeatTimer = setInterval(() => {\n this.sendWorkerHeartbeat();\n }, heartbeatInterval);\n\n // Start polling\n this.state = \"running\";\n this.emit(\"started\", {\n workerId: this.workerId,\n queueName: this.options.queueName,\n });\n this.schedulePoll();\n } catch (error) {\n this.state = \"error\";\n this.emit(\"error\", { error: error as Error });\n throw error;\n }\n }\n\n /**\n * Stop the worker gracefully\n */\n async stop(): Promise<void> {\n if (this.state !== \"running\") {\n return;\n }\n\n // Deduplicate concurrent stop calls\n if (this.shutdownPromise) {\n return this.shutdownPromise;\n }\n\n this.shutdownPromise = this.doStop();\n return this.shutdownPromise;\n }\n\n private async doStop(): Promise<void> {\n this.state = \"stopping\";\n this.debug(\"Stopping worker...\");\n\n // Stop polling\n if (this.pollTimer) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n\n // Stop worker heartbeat\n if (this.workerHeartbeatTimer) {\n clearInterval(this.workerHeartbeatTimer);\n this.workerHeartbeatTimer = null;\n }\n\n // Signal all active jobs to stop\n for (const active of this.activeJobs.values()) {\n active.abortController.abort();\n }\n\n // Wait for active jobs to complete (with timeout)\n if (this.activeJobs.size > 0) {\n this.debug(\n `Waiting for ${this.activeJobs.size} active jobs to complete...`,\n );\n\n await Promise.race([\n this.waitForActiveJobs(),\n this.sleep(this.options.shutdownTimeout),\n ]);\n\n // Force-fail any remaining jobs. Snapshot the entries first because\n // cleanupJob() mutates the activeJobs map as we go.\n const remaining = Array.from(this.activeJobs.values());\n for (const active of remaining) {\n this.debug(\n `Force-failing job ${active.job.id} due to shutdown timeout`,\n );\n await this.failJob(active.job, \"Worker shutdown timeout\");\n // The handler's finally may never run if user code ignores the abort\n // signal, so explicitly clear this exact execution's timer.\n this.cleanupJob(active);\n }\n }\n\n // Deregister worker\n if (this.workerId) {\n try {\n await this.client.workers.deregister(this.workerId);\n this.debug(\"Worker deregistered\");\n } catch (error) {\n this.debug(\"Failed to deregister worker\", error);\n }\n }\n\n this.state = \"stopped\";\n this.workerId = null;\n this.emit(\"stopped\", { workerId: this.workerId ?? \"\", reason: \"graceful\" });\n this.shutdownPromise = null;\n }\n\n /**\n * Add event listener\n */\n on<E extends WorkerEvent>(event: E, handler: EventHandler<E>): () => void {\n if (!this.eventHandlers.has(event)) {\n this.eventHandlers.set(event, new Set());\n }\n this.eventHandlers.get(event)!.add(handler as EventHandler<WorkerEvent>);\n return () => this.off(event, handler);\n }\n\n /**\n * Remove event listener\n */\n off<E extends WorkerEvent>(event: E, handler: EventHandler<E>): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.delete(handler as EventHandler<WorkerEvent>);\n }\n }\n\n // Private methods\n\n private emit<E extends WorkerEvent>(\n event: E,\n data: WorkerEventData[E],\n ): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(data);\n } catch (error) {\n this.debug(\"Event handler error\", { event, error });\n }\n });\n }\n }\n\n private schedulePoll(): void {\n if (this.state !== \"running\") {\n return;\n }\n\n this.pollTimer = setTimeout(() => this.poll(), this.options.pollInterval);\n }\n\n private async poll(): Promise<void> {\n if (this.state !== \"running\" || !this.workerId) {\n return;\n }\n\n // Check if we have capacity\n const availableSlots = this.options.concurrency - this.activeJobs.size;\n if (availableSlots <= 0) {\n this.schedulePoll();\n return;\n }\n\n try {\n // Claim jobs\n const result = await this.client.jobs.claim({\n queueName: this.options.queueName,\n workerId: this.workerId,\n limit: availableSlots,\n leaseDurationSecs: this.options.leaseDuration,\n });\n\n // Process claimed jobs\n for (const job of result.jobs) {\n this.processJob(job);\n }\n } catch (error) {\n this.debug(\"Poll failed\", error);\n this.emit(\"error\", { error: error as Error });\n }\n\n // Schedule next poll\n this.schedulePoll();\n }\n\n private processJob(job: ClaimedJob): void {\n this.emit(\"job:claimed\", { jobId: job.id, queueName: job.queueName });\n\n const abortController = new AbortController();\n const activeJob: ActiveJob = {\n executionId: Symbol(job.id),\n job,\n startedAt: new Date(),\n abortController,\n };\n\n this.activeJobs.set(activeJob.executionId, activeJob);\n\n // Capture the immutable execution so a replacement lease cannot be borrowed.\n const heartbeatInterval =\n this.options.leaseDuration * this.options.heartbeatFraction * 1000;\n activeJob.heartbeatTimer = setInterval(() => {\n this.sendJobHeartbeat(activeJob);\n }, heartbeatInterval);\n\n // Execute handler\n this.executeHandler(activeJob);\n }\n\n private async executeHandler(activeJob: ActiveJob): Promise<void> {\n const { job, abortController } = activeJob;\n const { signal } = abortController;\n\n this.emit(\"job:started\", { jobId: job.id, queueName: job.queueName });\n\n const context: JobContext = {\n jobId: job.id,\n queueName: job.queueName,\n payload: job.payload,\n retryCount: job.retryCount,\n maxRetries: job.maxRetries,\n signal,\n progress: async (percent: number, message?: string) => {\n const boundedPercent = Math.max(0, Math.min(100, percent));\n this.debug(`[${job.id}] progress ${boundedPercent}%`, message);\n },\n log: (level, message, meta) => {\n this.debug(`[${job.id}] [${level}] ${message}`, meta);\n },\n };\n\n try {\n const result = await this.handler!(context);\n\n // Check if aborted\n if (signal.aborted) {\n this.debug(`Job ${job.id} was aborted`);\n return;\n }\n\n // Complete the job\n await this.completeJob(job, result ?? undefined);\n } catch (error) {\n // Check if aborted\n if (signal.aborted) {\n this.debug(`Job ${job.id} was aborted`);\n return;\n }\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n await this.failJob(job, errorMessage);\n } finally {\n this.cleanupJob(activeJob);\n }\n }\n\n private async completeJob(\n job: ClaimedJob,\n result?: JsonValue,\n ): Promise<void> {\n if (!this.workerId) return;\n\n try {\n await this.client.jobs.complete(job.id, {\n workerId: this.workerId,\n result,\n ...(job.leaseId != null && { leaseId: job.leaseId }),\n });\n\n this.emit(\"job:completed\", {\n jobId: job.id,\n queueName: job.queueName,\n result,\n });\n } catch (error) {\n this.debug(`Failed to complete job ${job.id}`, error);\n }\n }\n\n private async failJob(job: ClaimedJob, errorMessage: string): Promise<void> {\n if (!this.workerId) return;\n\n const willRetry = job.retryCount < job.maxRetries;\n\n try {\n await this.client.jobs.fail(job.id, {\n workerId: this.workerId,\n error: errorMessage,\n ...(job.leaseId != null && { leaseId: job.leaseId }),\n });\n\n this.emit(\"job:failed\", {\n jobId: job.id,\n queueName: job.queueName,\n error: errorMessage,\n willRetry,\n });\n } catch (error) {\n this.debug(`Failed to fail job ${job.id}`, error);\n }\n }\n\n private cleanupJob(activeJob: ActiveJob): void {\n if (activeJob.heartbeatTimer) {\n clearInterval(activeJob.heartbeatTimer);\n activeJob.heartbeatTimer = undefined;\n }\n\n if (this.activeJobs.get(activeJob.executionId) === activeJob) {\n this.activeJobs.delete(activeJob.executionId);\n }\n }\n\n private async sendJobHeartbeat(activeJob: ActiveJob): Promise<void> {\n if (!this.workerId) return;\n\n const { job } = activeJob;\n\n try {\n await this.client.jobs.heartbeat(job.id, {\n workerId: this.workerId,\n leaseDurationSecs: this.options.leaseDuration,\n ...(job.leaseId != null && { leaseId: job.leaseId }),\n });\n } catch (error) {\n this.debug(`Job heartbeat failed for ${job.id}`, error);\n }\n }\n\n private async sendWorkerHeartbeat(): Promise<void> {\n if (!this.workerId || this.state !== \"running\") return;\n\n try {\n await this.client.workers.heartbeat(this.workerId, {\n currentJobs: this.activeJobs.size,\n status: \"healthy\",\n });\n } catch (error) {\n this.debug(\"Worker heartbeat failed\", error);\n }\n }\n\n private async waitForActiveJobs(): Promise<void> {\n while (this.activeJobs.size > 0) {\n await this.sleep(100);\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"]}
@@ -1,2 +1,2 @@
1
- export { cV as ActiveJob, b1 as JobContext, b4 as JobHandler, b6 as JobResult, c9 as SpooledWorker, ca as SpooledWorkerOptions, cv as WorkerEvent, cw as WorkerEventData, cz as WorkerState } from '../index-D_MpLQYY.cjs';
1
+ export { c_ as ActiveJob, b4 as JobContext, b7 as JobHandler, b9 as JobResult, cc as SpooledWorker, cd as SpooledWorkerOptions, cA as WorkerEvent, cB as WorkerEventData, cE as WorkerState } from '../index-CWVI9LRo.cjs';
2
2
  import '@grpc/grpc-js';
@@ -1,2 +1,2 @@
1
- export { cV as ActiveJob, b1 as JobContext, b4 as JobHandler, b6 as JobResult, c9 as SpooledWorker, ca as SpooledWorkerOptions, cv as WorkerEvent, cw as WorkerEventData, cz as WorkerState } from '../index-D_MpLQYY.js';
1
+ export { c_ as ActiveJob, b4 as JobContext, b7 as JobHandler, b9 as JobResult, cc as SpooledWorker, cd as SpooledWorkerOptions, cA as WorkerEvent, cB as WorkerEventData, cE as WorkerState } from '../index-CWVI9LRo.js';
2
2
  import '@grpc/grpc-js';
@@ -1,7 +1,7 @@
1
1
  import { hostname } from 'os';
2
2
 
3
3
  // src/config.ts
4
- var SDK_VERSION = "1.1.0";
4
+ var SDK_VERSION = "1.2.1";
5
5
  var DEFAULT_OPTIONS = {
6
6
  concurrency: 5,
7
7
  pollInterval: 1e3,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config.ts","../../src/worker/worker.ts"],"names":["osHostname"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * SDK Configuration\n *\n * Defines configuration types and defaults for the Spooled SDK.\n */\n\n/** Retry configuration options */\nexport interface RetryConfig {\n /** Maximum number of retry attempts (default: 3) */\n maxRetries: number;\n /** Base delay in milliseconds for exponential backoff (default: 1000) */\n baseDelay: number;\n /** Maximum delay in milliseconds (default: 30000) */\n maxDelay: number;\n /** Exponential backoff factor (default: 2) */\n factor: number;\n /** Whether to add jitter to delays (default: true) */\n jitter: boolean;\n /** Custom function to determine if an error is retryable */\n retryOn?: (error: Error, attempt: number) => boolean;\n}\n\n/** Circuit breaker configuration options */\nexport interface CircuitBreakerConfig {\n /** Whether circuit breaker is enabled (default: true) */\n enabled: boolean;\n /** Number of failures before opening the circuit (default: 5) */\n failureThreshold: number;\n /** Number of successes in half-open state to close circuit (default: 3) */\n successThreshold: number;\n /** Time in milliseconds to wait before trying again after opening (default: 30000) */\n timeout: number;\n}\n\n/** Debug logging function type */\nexport type DebugFn = (message: string, meta?: unknown) => void;\n\n/** Main SDK configuration options */\nexport interface SpooledClientConfig {\n /** API key for authentication (starts with sp_live_, sp_test_, sk_live_, or sk_test_) */\n apiKey?: string;\n /** JWT access token (alternative to API key) */\n accessToken?: string;\n /** JWT refresh token for automatic token renewal */\n refreshToken?: string;\n /** Admin API key (for /api/v1/admin/* endpoints; uses X-Admin-Key header) */\n adminKey?: string;\n /** Base URL for the REST API (default: https://api.spooled.cloud) */\n baseUrl?: string;\n /** WebSocket URL for realtime events (default: derived from baseUrl, e.g., wss://api.spooled.cloud) */\n wsUrl?: string;\n /** gRPC server address (default: grpc.spooled.cloud:443) */\n grpcAddress?: string;\n /** Request timeout in milliseconds (default: 30000) */\n timeout?: number;\n /** Number of retry attempts (shorthand for retry.maxRetries) */\n retries?: number;\n /** Base retry delay in milliseconds (shorthand for retry.baseDelay) */\n retryDelay?: number;\n /** Full retry configuration */\n retry?: Partial<RetryConfig>;\n /** Circuit breaker configuration */\n circuitBreaker?: Partial<CircuitBreakerConfig>;\n /** Additional headers to include in all requests */\n headers?: Record<string, string>;\n /** Custom fetch implementation (for testing or special runtimes) */\n fetch?: typeof fetch;\n /** Custom user agent string */\n userAgent?: string;\n /** Enable debug logging */\n debug?: boolean | DebugFn;\n /** Whether to automatically refresh tokens when they expire (default: true) */\n autoRefreshToken?: boolean;\n}\n\n/** Resolved configuration with all defaults applied */\nexport interface ResolvedConfig {\n apiKey?: string;\n accessToken?: string;\n refreshToken?: string;\n adminKey?: string;\n baseUrl: string;\n wsUrl: string;\n grpcAddress: string;\n timeout: number;\n retry: RetryConfig;\n circuitBreaker: CircuitBreakerConfig;\n headers: Record<string, string>;\n fetch: typeof fetch;\n userAgent: string;\n debug: DebugFn | null;\n autoRefreshToken: boolean;\n}\n\n/** Default configuration values */\nexport const DEFAULT_CONFIG = {\n baseUrl: \"https://api.spooled.cloud\",\n wsUrl: \"wss://api.spooled.cloud\",\n grpcAddress: \"grpc.spooled.cloud:443\",\n timeout: 30000,\n retry: {\n maxRetries: 3,\n baseDelay: 1000,\n maxDelay: 30000,\n factor: 2,\n jitter: true,\n } satisfies RetryConfig,\n circuitBreaker: {\n enabled: true,\n failureThreshold: 5,\n successThreshold: 3,\n timeout: 30000,\n } satisfies CircuitBreakerConfig,\n userAgent: \"@spooled/sdk-nodejs/1.1.0\",\n autoRefreshToken: true,\n} as const;\n\n/** SDK version */\nexport const SDK_VERSION = \"1.1.0\";\n\n/** API version prefix */\nexport const API_VERSION = \"v1\";\n\n/** API base path */\nexport const API_BASE_PATH = `/api/${API_VERSION}`;\n\n/**\n * Trim surrounding whitespace from a credential string and treat an\n * all-whitespace input as unset. Mirrors the trim policy in the Go, PHP,\n * and Python SDKs so behavior is consistent across languages.\n */\nfunction normalizeCredential(value: string | undefined): string | undefined {\n if (value === undefined) {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed === \"\" ? undefined : trimmed;\n}\n\n/**\n * Resolve configuration by merging user options with defaults\n */\nexport function resolveConfig(options: SpooledClientConfig): ResolvedConfig {\n // Create debug function\n let debugFn: DebugFn | null = null;\n if (options.debug === true) {\n debugFn = (message: string, meta?: unknown) => {\n // eslint-disable-next-line no-console\n console.log(`[spooled-sdk] ${message}`, meta !== undefined ? meta : \"\");\n };\n } else if (typeof options.debug === \"function\") {\n debugFn = options.debug;\n }\n\n // Merge retry config\n const retry: RetryConfig = {\n ...DEFAULT_CONFIG.retry,\n ...options.retry,\n // Allow shorthand overrides\n ...(options.retries !== undefined && { maxRetries: options.retries }),\n ...(options.retryDelay !== undefined && { baseDelay: options.retryDelay }),\n };\n\n // Merge circuit breaker config\n const circuitBreaker: CircuitBreakerConfig = {\n ...DEFAULT_CONFIG.circuitBreaker,\n ...options.circuitBreaker,\n };\n\n // Build headers\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...options.headers,\n };\n\n // Resolve base URL first\n const baseUrl = options.baseUrl ?? DEFAULT_CONFIG.baseUrl;\n\n // Derive WebSocket URL from base URL if not explicitly set\n // Replace http(s):// with ws(s)://\n const derivedWsUrl = baseUrl.replace(/^http/, \"ws\");\n const wsUrl = options.wsUrl ?? derivedWsUrl;\n\n // Trim whitespace (including a stray trailing '\\n') from every credential.\n // Node's `undici` fetch rejects `Authorization: Bearer <key>\\n` with an\n // opaque `TypeError: HeaderValue` and users routinely paste keys from\n // `.env` files that include a newline; normalizing here keeps behavior\n // consistent with the Go, PHP, and Python SDKs.\n return {\n apiKey: normalizeCredential(options.apiKey),\n accessToken: normalizeCredential(options.accessToken),\n refreshToken: normalizeCredential(options.refreshToken),\n adminKey: normalizeCredential(options.adminKey),\n baseUrl,\n wsUrl,\n grpcAddress: options.grpcAddress ?? DEFAULT_CONFIG.grpcAddress,\n timeout: options.timeout ?? DEFAULT_CONFIG.timeout,\n retry,\n circuitBreaker,\n headers,\n fetch: options.fetch ?? globalThis.fetch,\n userAgent: options.userAgent ?? DEFAULT_CONFIG.userAgent,\n debug: debugFn,\n autoRefreshToken:\n options.autoRefreshToken ?? DEFAULT_CONFIG.autoRefreshToken,\n };\n}\n\n/**\n * Validate configuration options\n * @throws Error if configuration is invalid\n */\nexport function validateConfig(config: ResolvedConfig): void {\n // Must have at least one auth method\n if (!config.apiKey && !config.accessToken) {\n throw new Error(\n \"SpooledClient requires either apiKey or accessToken for authentication\",\n );\n }\n\n // Validate API key format if provided\n // Accept both sp_ (new standard) and sk_ (legacy) prefixes\n if (\n config.apiKey &&\n !config.apiKey.startsWith(\"sp_\") &&\n !config.apiKey.startsWith(\"sk_\")\n ) {\n throw new Error(\n \"Invalid API key format. API keys should start with sp_live_, sp_test_, sk_live_, or sk_test_\",\n );\n }\n\n // Validate baseUrl\n if (\n !config.baseUrl.startsWith(\"http://\") &&\n !config.baseUrl.startsWith(\"https://\")\n ) {\n throw new Error(\"baseUrl must start with http:// or https://\");\n }\n\n // Validate timeout\n if (config.timeout <= 0) {\n throw new Error(\"timeout must be a positive number\");\n }\n\n // Validate retry config\n if (config.retry.maxRetries < 0) {\n throw new Error(\"retry.maxRetries must be non-negative\");\n }\n if (config.retry.baseDelay <= 0) {\n throw new Error(\"retry.baseDelay must be positive\");\n }\n if (config.retry.maxDelay < config.retry.baseDelay) {\n throw new Error(\"retry.maxDelay must be >= retry.baseDelay\");\n }\n if (config.retry.factor < 1) {\n throw new Error(\"retry.factor must be >= 1\");\n }\n\n // Validate circuit breaker config\n if (config.circuitBreaker.enabled) {\n if (config.circuitBreaker.failureThreshold <= 0) {\n throw new Error(\"circuitBreaker.failureThreshold must be positive\");\n }\n if (config.circuitBreaker.successThreshold <= 0) {\n throw new Error(\"circuitBreaker.successThreshold must be positive\");\n }\n if (config.circuitBreaker.timeout <= 0) {\n throw new Error(\"circuitBreaker.timeout must be positive\");\n }\n }\n}\n","/**\n * Spooled Worker\n *\n * Worker runtime for processing jobs from a queue.\n */\n\nimport type { SpooledClient } from \"../client.js\";\nimport { SDK_VERSION } from \"../config.js\";\nimport type { JsonObject } from \"../types/common.js\";\nimport type { ClaimedJob } from \"../types/jobs.js\";\nimport type {\n SpooledWorkerOptions,\n WorkerState,\n JobHandler,\n JobContext,\n WorkerEvent,\n WorkerEventData,\n ActiveJob,\n} from \"./types.js\";\nimport { hostname as osHostname } from \"os\";\n\n/** Default options */\nconst DEFAULT_OPTIONS = {\n concurrency: 5,\n pollInterval: 1000,\n leaseDuration: 30,\n heartbeatFraction: 0.5,\n autoStart: false,\n shutdownTimeout: 30000,\n} as const;\n\n/** Event handler type */\ntype EventHandler<E extends WorkerEvent> = (data: WorkerEventData[E]) => void;\n\n/**\n * Spooled Worker\n *\n * @example\n * ```typescript\n * const worker = new SpooledWorker(client, {\n * queueName: 'my-queue',\n * concurrency: 10,\n * });\n *\n * worker.process(async (ctx) => {\n * console.log('Processing job:', ctx.jobId);\n * await doSomeWork(ctx.payload);\n * return { success: true };\n * });\n *\n * await worker.start();\n *\n * // Graceful shutdown\n * process.on('SIGTERM', () => worker.stop());\n * ```\n */\nexport class SpooledWorker {\n private readonly client: SpooledClient;\n /**\n * Options with every defaultable field filled in. `workerId` stays optional:\n * there is no sensible default for it, and omitting it is what makes the\n * server mint a UUID.\n */\n private readonly options: Required<Omit<SpooledWorkerOptions, \"workerId\">> &\n Pick<SpooledWorkerOptions, \"workerId\">;\n private readonly debug: (msg: string, meta?: unknown) => void;\n\n private state: WorkerState = \"idle\";\n private workerId: string | null = null;\n private handler: JobHandler | null = null;\n private activeJobs: Map<symbol, ActiveJob> = new Map();\n private pollTimer: ReturnType<typeof setTimeout> | null = null;\n private workerHeartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private shutdownPromise: Promise<void> | null = null;\n\n // Event handlers\n private eventHandlers: Map<WorkerEvent, Set<EventHandler<WorkerEvent>>> =\n new Map();\n\n constructor(client: SpooledClient, options: SpooledWorkerOptions) {\n this.client = client;\n this.options = {\n ...DEFAULT_OPTIONS,\n hostname: osHostname(),\n workerType: \"nodejs\",\n version: SDK_VERSION,\n metadata: {},\n ...options,\n } as Required<Omit<SpooledWorkerOptions, \"workerId\">> &\n Pick<SpooledWorkerOptions, \"workerId\">;\n\n // Get debug from client config\n const config = client.getConfig();\n this.debug = config.debug ?? (() => {});\n\n if (this.options.autoStart) {\n // Defer to next tick to allow process() to be called\n setImmediate(() => this.start());\n }\n }\n\n /**\n * Get current worker state\n */\n getState(): WorkerState {\n return this.state;\n }\n\n /**\n * Get worker ID (available after start)\n */\n getWorkerId(): string | null {\n return this.workerId;\n }\n\n /**\n * Get number of active jobs\n */\n getActiveJobCount(): number {\n return this.activeJobs.size;\n }\n\n /**\n * Register job handler\n */\n process(handler: JobHandler): void {\n if (this.state !== \"idle\") {\n throw new Error(\"Cannot set handler after worker has started\");\n }\n this.handler = handler;\n }\n\n /**\n * Start the worker\n */\n async start(): Promise<void> {\n if (this.state !== \"idle\") {\n throw new Error(`Cannot start worker in state: ${this.state}`);\n }\n\n if (!this.handler) {\n throw new Error(\"No job handler registered. Call process() first.\");\n }\n\n this.state = \"starting\";\n this.debug(`Starting worker for queue: ${this.options.queueName}`);\n\n try {\n // Register with the API\n const registration = await this.client.workers.register({\n queueName: this.options.queueName,\n workerId: this.options.workerId,\n hostname: this.options.hostname,\n workerType: this.options.workerType,\n maxConcurrency: this.options.concurrency,\n metadata: this.options.metadata,\n version: this.options.version,\n });\n\n this.workerId = registration.id;\n this.debug(`Worker registered: ${this.workerId}`, registration);\n\n // Start worker heartbeat\n const heartbeatInterval = registration.heartbeatIntervalSecs * 1000;\n this.workerHeartbeatTimer = setInterval(() => {\n this.sendWorkerHeartbeat();\n }, heartbeatInterval);\n\n // Start polling\n this.state = \"running\";\n this.emit(\"started\", {\n workerId: this.workerId,\n queueName: this.options.queueName,\n });\n this.schedulePoll();\n } catch (error) {\n this.state = \"error\";\n this.emit(\"error\", { error: error as Error });\n throw error;\n }\n }\n\n /**\n * Stop the worker gracefully\n */\n async stop(): Promise<void> {\n if (this.state !== \"running\") {\n return;\n }\n\n // Deduplicate concurrent stop calls\n if (this.shutdownPromise) {\n return this.shutdownPromise;\n }\n\n this.shutdownPromise = this.doStop();\n return this.shutdownPromise;\n }\n\n private async doStop(): Promise<void> {\n this.state = \"stopping\";\n this.debug(\"Stopping worker...\");\n\n // Stop polling\n if (this.pollTimer) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n\n // Stop worker heartbeat\n if (this.workerHeartbeatTimer) {\n clearInterval(this.workerHeartbeatTimer);\n this.workerHeartbeatTimer = null;\n }\n\n // Signal all active jobs to stop\n for (const active of this.activeJobs.values()) {\n active.abortController.abort();\n }\n\n // Wait for active jobs to complete (with timeout)\n if (this.activeJobs.size > 0) {\n this.debug(\n `Waiting for ${this.activeJobs.size} active jobs to complete...`,\n );\n\n await Promise.race([\n this.waitForActiveJobs(),\n this.sleep(this.options.shutdownTimeout),\n ]);\n\n // Force-fail any remaining jobs. Snapshot the entries first because\n // cleanupJob() mutates the activeJobs map as we go.\n const remaining = Array.from(this.activeJobs.values());\n for (const active of remaining) {\n this.debug(\n `Force-failing job ${active.job.id} due to shutdown timeout`,\n );\n await this.failJob(active.job, \"Worker shutdown timeout\");\n // The handler's finally may never run if user code ignores the abort\n // signal, so explicitly clear this exact execution's timer.\n this.cleanupJob(active);\n }\n }\n\n // Deregister worker\n if (this.workerId) {\n try {\n await this.client.workers.deregister(this.workerId);\n this.debug(\"Worker deregistered\");\n } catch (error) {\n this.debug(\"Failed to deregister worker\", error);\n }\n }\n\n this.state = \"stopped\";\n this.workerId = null;\n this.emit(\"stopped\", { workerId: this.workerId ?? \"\", reason: \"graceful\" });\n this.shutdownPromise = null;\n }\n\n /**\n * Add event listener\n */\n on<E extends WorkerEvent>(event: E, handler: EventHandler<E>): () => void {\n if (!this.eventHandlers.has(event)) {\n this.eventHandlers.set(event, new Set());\n }\n this.eventHandlers.get(event)!.add(handler as EventHandler<WorkerEvent>);\n return () => this.off(event, handler);\n }\n\n /**\n * Remove event listener\n */\n off<E extends WorkerEvent>(event: E, handler: EventHandler<E>): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.delete(handler as EventHandler<WorkerEvent>);\n }\n }\n\n // Private methods\n\n private emit<E extends WorkerEvent>(\n event: E,\n data: WorkerEventData[E],\n ): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(data);\n } catch (error) {\n this.debug(\"Event handler error\", { event, error });\n }\n });\n }\n }\n\n private schedulePoll(): void {\n if (this.state !== \"running\") {\n return;\n }\n\n this.pollTimer = setTimeout(() => this.poll(), this.options.pollInterval);\n }\n\n private async poll(): Promise<void> {\n if (this.state !== \"running\" || !this.workerId) {\n return;\n }\n\n // Check if we have capacity\n const availableSlots = this.options.concurrency - this.activeJobs.size;\n if (availableSlots <= 0) {\n this.schedulePoll();\n return;\n }\n\n try {\n // Claim jobs\n const result = await this.client.jobs.claim({\n queueName: this.options.queueName,\n workerId: this.workerId,\n limit: availableSlots,\n leaseDurationSecs: this.options.leaseDuration,\n });\n\n // Process claimed jobs\n for (const job of result.jobs) {\n this.processJob(job);\n }\n } catch (error) {\n this.debug(\"Poll failed\", error);\n this.emit(\"error\", { error: error as Error });\n }\n\n // Schedule next poll\n this.schedulePoll();\n }\n\n private processJob(job: ClaimedJob): void {\n this.emit(\"job:claimed\", { jobId: job.id, queueName: job.queueName });\n\n const abortController = new AbortController();\n const activeJob: ActiveJob = {\n executionId: Symbol(job.id),\n job,\n startedAt: new Date(),\n abortController,\n };\n\n this.activeJobs.set(activeJob.executionId, activeJob);\n\n // Capture the immutable execution so a replacement lease cannot be borrowed.\n const heartbeatInterval =\n this.options.leaseDuration * this.options.heartbeatFraction * 1000;\n activeJob.heartbeatTimer = setInterval(() => {\n this.sendJobHeartbeat(activeJob);\n }, heartbeatInterval);\n\n // Execute handler\n this.executeHandler(activeJob);\n }\n\n private async executeHandler(activeJob: ActiveJob): Promise<void> {\n const { job, abortController } = activeJob;\n const { signal } = abortController;\n\n this.emit(\"job:started\", { jobId: job.id, queueName: job.queueName });\n\n const context: JobContext = {\n jobId: job.id,\n queueName: job.queueName,\n payload: job.payload,\n retryCount: job.retryCount,\n maxRetries: job.maxRetries,\n signal,\n progress: async (percent: number, message?: string) => {\n const boundedPercent = Math.max(0, Math.min(100, percent));\n this.debug(`[${job.id}] progress ${boundedPercent}%`, message);\n },\n log: (level, message, meta) => {\n this.debug(`[${job.id}] [${level}] ${message}`, meta);\n },\n };\n\n try {\n const result = await this.handler!(context);\n\n // Check if aborted\n if (signal.aborted) {\n this.debug(`Job ${job.id} was aborted`);\n return;\n }\n\n // Complete the job\n await this.completeJob(job, result ?? undefined);\n } catch (error) {\n // Check if aborted\n if (signal.aborted) {\n this.debug(`Job ${job.id} was aborted`);\n return;\n }\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n await this.failJob(job, errorMessage);\n } finally {\n this.cleanupJob(activeJob);\n }\n }\n\n private async completeJob(\n job: ClaimedJob,\n result?: JsonObject,\n ): Promise<void> {\n if (!this.workerId) return;\n\n try {\n await this.client.jobs.complete(job.id, {\n workerId: this.workerId,\n result,\n ...(job.leaseId != null && { leaseId: job.leaseId }),\n });\n\n this.emit(\"job:completed\", {\n jobId: job.id,\n queueName: job.queueName,\n result,\n });\n } catch (error) {\n this.debug(`Failed to complete job ${job.id}`, error);\n }\n }\n\n private async failJob(job: ClaimedJob, errorMessage: string): Promise<void> {\n if (!this.workerId) return;\n\n const willRetry = job.retryCount < job.maxRetries;\n\n try {\n await this.client.jobs.fail(job.id, {\n workerId: this.workerId,\n error: errorMessage,\n ...(job.leaseId != null && { leaseId: job.leaseId }),\n });\n\n this.emit(\"job:failed\", {\n jobId: job.id,\n queueName: job.queueName,\n error: errorMessage,\n willRetry,\n });\n } catch (error) {\n this.debug(`Failed to fail job ${job.id}`, error);\n }\n }\n\n private cleanupJob(activeJob: ActiveJob): void {\n if (activeJob.heartbeatTimer) {\n clearInterval(activeJob.heartbeatTimer);\n activeJob.heartbeatTimer = undefined;\n }\n\n if (this.activeJobs.get(activeJob.executionId) === activeJob) {\n this.activeJobs.delete(activeJob.executionId);\n }\n }\n\n private async sendJobHeartbeat(activeJob: ActiveJob): Promise<void> {\n if (!this.workerId) return;\n\n const { job } = activeJob;\n\n try {\n await this.client.jobs.heartbeat(job.id, {\n workerId: this.workerId,\n leaseDurationSecs: this.options.leaseDuration,\n ...(job.leaseId != null && { leaseId: job.leaseId }),\n });\n } catch (error) {\n this.debug(`Job heartbeat failed for ${job.id}`, error);\n }\n }\n\n private async sendWorkerHeartbeat(): Promise<void> {\n if (!this.workerId || this.state !== \"running\") return;\n\n try {\n await this.client.workers.heartbeat(this.workerId, {\n currentJobs: this.activeJobs.size,\n status: \"healthy\",\n });\n } catch (error) {\n this.debug(\"Worker heartbeat failed\", error);\n }\n }\n\n private async waitForActiveJobs(): Promise<void> {\n while (this.activeJobs.size > 0) {\n await this.sleep(100);\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/config.ts","../../src/worker/worker.ts"],"names":["osHostname"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * SDK Configuration\n *\n * Defines configuration types and defaults for the Spooled SDK.\n */\n\n/** Retry configuration options */\nexport interface RetryConfig {\n /** Maximum number of retry attempts (default: 3) */\n maxRetries: number;\n /** Base delay in milliseconds for exponential backoff (default: 1000) */\n baseDelay: number;\n /** Maximum delay in milliseconds (default: 30000) */\n maxDelay: number;\n /** Exponential backoff factor (default: 2) */\n factor: number;\n /** Whether to add jitter to delays (default: true) */\n jitter: boolean;\n /** Custom function to determine if an error is retryable */\n retryOn?: (error: Error, attempt: number) => boolean;\n}\n\n/** Circuit breaker configuration options */\nexport interface CircuitBreakerConfig {\n /** Whether circuit breaker is enabled (default: true) */\n enabled: boolean;\n /** Number of failures before opening the circuit (default: 5) */\n failureThreshold: number;\n /** Number of successes in half-open state to close circuit (default: 3) */\n successThreshold: number;\n /** Time in milliseconds to wait before trying again after opening (default: 30000) */\n timeout: number;\n}\n\n/** Debug logging function type */\nexport type DebugFn = (message: string, meta?: unknown) => void;\n\n/** Main SDK configuration options */\nexport interface SpooledClientConfig {\n /** API key for authentication (starts with sp_live_, sp_test_, sk_live_, or sk_test_) */\n apiKey?: string;\n /** JWT access token (alternative to API key) */\n accessToken?: string;\n /** JWT refresh token for automatic token renewal */\n refreshToken?: string;\n /** Admin API key (for /api/v1/admin/* endpoints; uses X-Admin-Key header) */\n adminKey?: string;\n /** Base URL for the REST API (default: https://api.spooled.cloud) */\n baseUrl?: string;\n /** WebSocket URL for realtime events (default: derived from baseUrl, e.g., wss://api.spooled.cloud) */\n wsUrl?: string;\n /** gRPC server address (default: grpc.spooled.cloud:443) */\n grpcAddress?: string;\n /** Request timeout in milliseconds (default: 30000) */\n timeout?: number;\n /** Number of retry attempts (shorthand for retry.maxRetries) */\n retries?: number;\n /** Base retry delay in milliseconds (shorthand for retry.baseDelay) */\n retryDelay?: number;\n /** Full retry configuration */\n retry?: Partial<RetryConfig>;\n /** Circuit breaker configuration */\n circuitBreaker?: Partial<CircuitBreakerConfig>;\n /** Additional headers to include in all requests */\n headers?: Record<string, string>;\n /** Custom fetch implementation (for testing or special runtimes) */\n fetch?: typeof fetch;\n /** Custom user agent string */\n userAgent?: string;\n /** Enable debug logging */\n debug?: boolean | DebugFn;\n /** Whether to automatically refresh tokens when they expire (default: true) */\n autoRefreshToken?: boolean;\n}\n\n/** Resolved configuration with all defaults applied */\nexport interface ResolvedConfig {\n apiKey?: string;\n accessToken?: string;\n refreshToken?: string;\n adminKey?: string;\n baseUrl: string;\n wsUrl: string;\n grpcAddress: string;\n timeout: number;\n retry: RetryConfig;\n circuitBreaker: CircuitBreakerConfig;\n headers: Record<string, string>;\n fetch: typeof fetch;\n userAgent: string;\n debug: DebugFn | null;\n autoRefreshToken: boolean;\n}\n\n/** Default configuration values */\nexport const DEFAULT_CONFIG = {\n baseUrl: \"https://api.spooled.cloud\",\n wsUrl: \"wss://api.spooled.cloud\",\n grpcAddress: \"grpc.spooled.cloud:443\",\n timeout: 30000,\n retry: {\n maxRetries: 3,\n baseDelay: 1000,\n maxDelay: 30000,\n factor: 2,\n jitter: true,\n } satisfies RetryConfig,\n circuitBreaker: {\n enabled: true,\n failureThreshold: 5,\n successThreshold: 3,\n timeout: 30000,\n } satisfies CircuitBreakerConfig,\n userAgent: \"@spooled/sdk-nodejs/1.2.1\",\n autoRefreshToken: true,\n} as const;\n\n/** SDK version */\nexport const SDK_VERSION = \"1.2.1\";\n\n/** API version prefix */\nexport const API_VERSION = \"v1\";\n\n/** API base path */\nexport const API_BASE_PATH = `/api/${API_VERSION}`;\n\n/**\n * Trim surrounding whitespace from a credential string and treat an\n * all-whitespace input as unset. Mirrors the trim policy in the Go, PHP,\n * and Python SDKs so behavior is consistent across languages.\n */\nfunction normalizeCredential(value: string | undefined): string | undefined {\n if (value === undefined) {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed === \"\" ? undefined : trimmed;\n}\n\n/**\n * Resolve configuration by merging user options with defaults\n */\nexport function resolveConfig(options: SpooledClientConfig): ResolvedConfig {\n // Create debug function\n let debugFn: DebugFn | null = null;\n if (options.debug === true) {\n debugFn = (message: string, meta?: unknown) => {\n // eslint-disable-next-line no-console\n console.log(`[spooled-sdk] ${message}`, meta !== undefined ? meta : \"\");\n };\n } else if (typeof options.debug === \"function\") {\n debugFn = options.debug;\n }\n\n // Merge retry config\n const retry: RetryConfig = {\n ...DEFAULT_CONFIG.retry,\n ...options.retry,\n // Allow shorthand overrides\n ...(options.retries !== undefined && { maxRetries: options.retries }),\n ...(options.retryDelay !== undefined && { baseDelay: options.retryDelay }),\n };\n\n // Merge circuit breaker config\n const circuitBreaker: CircuitBreakerConfig = {\n ...DEFAULT_CONFIG.circuitBreaker,\n ...options.circuitBreaker,\n };\n\n // Build headers\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...options.headers,\n };\n\n // Resolve base URL first\n const baseUrl = options.baseUrl ?? DEFAULT_CONFIG.baseUrl;\n\n // Derive WebSocket URL from base URL if not explicitly set\n // Replace http(s):// with ws(s)://\n const derivedWsUrl = baseUrl.replace(/^http/, \"ws\");\n const wsUrl = options.wsUrl ?? derivedWsUrl;\n\n // Trim whitespace (including a stray trailing '\\n') from every credential.\n // Node's `undici` fetch rejects `Authorization: Bearer <key>\\n` with an\n // opaque `TypeError: HeaderValue` and users routinely paste keys from\n // `.env` files that include a newline; normalizing here keeps behavior\n // consistent with the Go, PHP, and Python SDKs.\n return {\n apiKey: normalizeCredential(options.apiKey),\n accessToken: normalizeCredential(options.accessToken),\n refreshToken: normalizeCredential(options.refreshToken),\n adminKey: normalizeCredential(options.adminKey),\n baseUrl,\n wsUrl,\n grpcAddress: options.grpcAddress ?? DEFAULT_CONFIG.grpcAddress,\n timeout: options.timeout ?? DEFAULT_CONFIG.timeout,\n retry,\n circuitBreaker,\n headers,\n fetch: options.fetch ?? globalThis.fetch,\n userAgent: options.userAgent ?? DEFAULT_CONFIG.userAgent,\n debug: debugFn,\n autoRefreshToken:\n options.autoRefreshToken ?? DEFAULT_CONFIG.autoRefreshToken,\n };\n}\n\n/**\n * Validate configuration options\n * @throws Error if configuration is invalid\n */\nexport function validateConfig(config: ResolvedConfig): void {\n // Must have at least one auth method\n if (!config.apiKey && !config.accessToken) {\n throw new Error(\n \"SpooledClient requires either apiKey or accessToken for authentication\",\n );\n }\n\n // Validate API key format if provided\n // Accept both sp_ (new standard) and sk_ (legacy) prefixes\n if (\n config.apiKey &&\n !config.apiKey.startsWith(\"sp_\") &&\n !config.apiKey.startsWith(\"sk_\")\n ) {\n throw new Error(\n \"Invalid API key format. API keys should start with sp_live_, sp_test_, sk_live_, or sk_test_\",\n );\n }\n\n // Validate baseUrl\n if (\n !config.baseUrl.startsWith(\"http://\") &&\n !config.baseUrl.startsWith(\"https://\")\n ) {\n throw new Error(\"baseUrl must start with http:// or https://\");\n }\n\n // Validate timeout\n if (config.timeout <= 0) {\n throw new Error(\"timeout must be a positive number\");\n }\n\n // Validate retry config\n if (config.retry.maxRetries < 0) {\n throw new Error(\"retry.maxRetries must be non-negative\");\n }\n if (config.retry.baseDelay <= 0) {\n throw new Error(\"retry.baseDelay must be positive\");\n }\n if (config.retry.maxDelay < config.retry.baseDelay) {\n throw new Error(\"retry.maxDelay must be >= retry.baseDelay\");\n }\n if (config.retry.factor < 1) {\n throw new Error(\"retry.factor must be >= 1\");\n }\n\n // Validate circuit breaker config\n if (config.circuitBreaker.enabled) {\n if (config.circuitBreaker.failureThreshold <= 0) {\n throw new Error(\"circuitBreaker.failureThreshold must be positive\");\n }\n if (config.circuitBreaker.successThreshold <= 0) {\n throw new Error(\"circuitBreaker.successThreshold must be positive\");\n }\n if (config.circuitBreaker.timeout <= 0) {\n throw new Error(\"circuitBreaker.timeout must be positive\");\n }\n }\n}\n","/**\n * Spooled Worker\n *\n * Worker runtime for processing jobs from a queue.\n */\n\nimport type { SpooledClient } from \"../client.js\";\nimport { SDK_VERSION } from \"../config.js\";\nimport type { JsonValue } from \"../types/common.js\";\nimport type { ClaimedJob } from \"../types/jobs.js\";\nimport type {\n SpooledWorkerOptions,\n WorkerState,\n JobHandler,\n JobContext,\n WorkerEvent,\n WorkerEventData,\n ActiveJob,\n} from \"./types.js\";\nimport { hostname as osHostname } from \"os\";\n\n/** Default options */\nconst DEFAULT_OPTIONS = {\n concurrency: 5,\n pollInterval: 1000,\n leaseDuration: 30,\n heartbeatFraction: 0.5,\n autoStart: false,\n shutdownTimeout: 30000,\n} as const;\n\n/** Event handler type */\ntype EventHandler<E extends WorkerEvent> = (data: WorkerEventData[E]) => void;\n\n/**\n * Spooled Worker\n *\n * @example\n * ```typescript\n * const worker = new SpooledWorker(client, {\n * queueName: 'my-queue',\n * concurrency: 10,\n * });\n *\n * worker.process(async (ctx) => {\n * console.log('Processing job:', ctx.jobId);\n * await doSomeWork(ctx.payload);\n * return { success: true };\n * });\n *\n * await worker.start();\n *\n * // Graceful shutdown\n * process.on('SIGTERM', () => worker.stop());\n * ```\n */\nexport class SpooledWorker {\n private readonly client: SpooledClient;\n /**\n * Options with every defaultable field filled in. `workerId` stays optional:\n * there is no sensible default for it, and omitting it is what makes the\n * server mint a UUID.\n */\n private readonly options: Required<Omit<SpooledWorkerOptions, \"workerId\">> &\n Pick<SpooledWorkerOptions, \"workerId\">;\n private readonly debug: (msg: string, meta?: unknown) => void;\n\n private state: WorkerState = \"idle\";\n private workerId: string | null = null;\n private handler: JobHandler | null = null;\n private activeJobs: Map<symbol, ActiveJob> = new Map();\n private pollTimer: ReturnType<typeof setTimeout> | null = null;\n private workerHeartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private shutdownPromise: Promise<void> | null = null;\n\n // Event handlers\n private eventHandlers: Map<WorkerEvent, Set<EventHandler<WorkerEvent>>> =\n new Map();\n\n constructor(client: SpooledClient, options: SpooledWorkerOptions) {\n this.client = client;\n this.options = {\n ...DEFAULT_OPTIONS,\n hostname: osHostname(),\n workerType: \"nodejs\",\n version: SDK_VERSION,\n metadata: {},\n ...options,\n } as Required<Omit<SpooledWorkerOptions, \"workerId\">> &\n Pick<SpooledWorkerOptions, \"workerId\">;\n\n // Get debug from client config\n const config = client.getConfig();\n this.debug = config.debug ?? (() => {});\n\n if (this.options.autoStart) {\n // Defer to next tick to allow process() to be called\n setImmediate(() => this.start());\n }\n }\n\n /**\n * Get current worker state\n */\n getState(): WorkerState {\n return this.state;\n }\n\n /**\n * Get worker ID (available after start)\n */\n getWorkerId(): string | null {\n return this.workerId;\n }\n\n /**\n * Get number of active jobs\n */\n getActiveJobCount(): number {\n return this.activeJobs.size;\n }\n\n /**\n * Register job handler\n */\n process(handler: JobHandler): void {\n if (this.state !== \"idle\") {\n throw new Error(\"Cannot set handler after worker has started\");\n }\n this.handler = handler;\n }\n\n /**\n * Start the worker\n */\n async start(): Promise<void> {\n if (this.state !== \"idle\") {\n throw new Error(`Cannot start worker in state: ${this.state}`);\n }\n\n if (!this.handler) {\n throw new Error(\"No job handler registered. Call process() first.\");\n }\n\n this.state = \"starting\";\n this.debug(`Starting worker for queue: ${this.options.queueName}`);\n\n try {\n // Register with the API\n const registration = await this.client.workers.register({\n queueName: this.options.queueName,\n workerId: this.options.workerId,\n hostname: this.options.hostname,\n workerType: this.options.workerType,\n maxConcurrency: this.options.concurrency,\n metadata: this.options.metadata,\n version: this.options.version,\n });\n\n this.workerId = registration.id;\n this.debug(`Worker registered: ${this.workerId}`, registration);\n\n // Start worker heartbeat\n const heartbeatInterval = registration.heartbeatIntervalSecs * 1000;\n this.workerHeartbeatTimer = setInterval(() => {\n this.sendWorkerHeartbeat();\n }, heartbeatInterval);\n\n // Start polling\n this.state = \"running\";\n this.emit(\"started\", {\n workerId: this.workerId,\n queueName: this.options.queueName,\n });\n this.schedulePoll();\n } catch (error) {\n this.state = \"error\";\n this.emit(\"error\", { error: error as Error });\n throw error;\n }\n }\n\n /**\n * Stop the worker gracefully\n */\n async stop(): Promise<void> {\n if (this.state !== \"running\") {\n return;\n }\n\n // Deduplicate concurrent stop calls\n if (this.shutdownPromise) {\n return this.shutdownPromise;\n }\n\n this.shutdownPromise = this.doStop();\n return this.shutdownPromise;\n }\n\n private async doStop(): Promise<void> {\n this.state = \"stopping\";\n this.debug(\"Stopping worker...\");\n\n // Stop polling\n if (this.pollTimer) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n\n // Stop worker heartbeat\n if (this.workerHeartbeatTimer) {\n clearInterval(this.workerHeartbeatTimer);\n this.workerHeartbeatTimer = null;\n }\n\n // Signal all active jobs to stop\n for (const active of this.activeJobs.values()) {\n active.abortController.abort();\n }\n\n // Wait for active jobs to complete (with timeout)\n if (this.activeJobs.size > 0) {\n this.debug(\n `Waiting for ${this.activeJobs.size} active jobs to complete...`,\n );\n\n await Promise.race([\n this.waitForActiveJobs(),\n this.sleep(this.options.shutdownTimeout),\n ]);\n\n // Force-fail any remaining jobs. Snapshot the entries first because\n // cleanupJob() mutates the activeJobs map as we go.\n const remaining = Array.from(this.activeJobs.values());\n for (const active of remaining) {\n this.debug(\n `Force-failing job ${active.job.id} due to shutdown timeout`,\n );\n await this.failJob(active.job, \"Worker shutdown timeout\");\n // The handler's finally may never run if user code ignores the abort\n // signal, so explicitly clear this exact execution's timer.\n this.cleanupJob(active);\n }\n }\n\n // Deregister worker\n if (this.workerId) {\n try {\n await this.client.workers.deregister(this.workerId);\n this.debug(\"Worker deregistered\");\n } catch (error) {\n this.debug(\"Failed to deregister worker\", error);\n }\n }\n\n this.state = \"stopped\";\n this.workerId = null;\n this.emit(\"stopped\", { workerId: this.workerId ?? \"\", reason: \"graceful\" });\n this.shutdownPromise = null;\n }\n\n /**\n * Add event listener\n */\n on<E extends WorkerEvent>(event: E, handler: EventHandler<E>): () => void {\n if (!this.eventHandlers.has(event)) {\n this.eventHandlers.set(event, new Set());\n }\n this.eventHandlers.get(event)!.add(handler as EventHandler<WorkerEvent>);\n return () => this.off(event, handler);\n }\n\n /**\n * Remove event listener\n */\n off<E extends WorkerEvent>(event: E, handler: EventHandler<E>): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.delete(handler as EventHandler<WorkerEvent>);\n }\n }\n\n // Private methods\n\n private emit<E extends WorkerEvent>(\n event: E,\n data: WorkerEventData[E],\n ): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(data);\n } catch (error) {\n this.debug(\"Event handler error\", { event, error });\n }\n });\n }\n }\n\n private schedulePoll(): void {\n if (this.state !== \"running\") {\n return;\n }\n\n this.pollTimer = setTimeout(() => this.poll(), this.options.pollInterval);\n }\n\n private async poll(): Promise<void> {\n if (this.state !== \"running\" || !this.workerId) {\n return;\n }\n\n // Check if we have capacity\n const availableSlots = this.options.concurrency - this.activeJobs.size;\n if (availableSlots <= 0) {\n this.schedulePoll();\n return;\n }\n\n try {\n // Claim jobs\n const result = await this.client.jobs.claim({\n queueName: this.options.queueName,\n workerId: this.workerId,\n limit: availableSlots,\n leaseDurationSecs: this.options.leaseDuration,\n });\n\n // Process claimed jobs\n for (const job of result.jobs) {\n this.processJob(job);\n }\n } catch (error) {\n this.debug(\"Poll failed\", error);\n this.emit(\"error\", { error: error as Error });\n }\n\n // Schedule next poll\n this.schedulePoll();\n }\n\n private processJob(job: ClaimedJob): void {\n this.emit(\"job:claimed\", { jobId: job.id, queueName: job.queueName });\n\n const abortController = new AbortController();\n const activeJob: ActiveJob = {\n executionId: Symbol(job.id),\n job,\n startedAt: new Date(),\n abortController,\n };\n\n this.activeJobs.set(activeJob.executionId, activeJob);\n\n // Capture the immutable execution so a replacement lease cannot be borrowed.\n const heartbeatInterval =\n this.options.leaseDuration * this.options.heartbeatFraction * 1000;\n activeJob.heartbeatTimer = setInterval(() => {\n this.sendJobHeartbeat(activeJob);\n }, heartbeatInterval);\n\n // Execute handler\n this.executeHandler(activeJob);\n }\n\n private async executeHandler(activeJob: ActiveJob): Promise<void> {\n const { job, abortController } = activeJob;\n const { signal } = abortController;\n\n this.emit(\"job:started\", { jobId: job.id, queueName: job.queueName });\n\n const context: JobContext = {\n jobId: job.id,\n queueName: job.queueName,\n payload: job.payload,\n retryCount: job.retryCount,\n maxRetries: job.maxRetries,\n signal,\n progress: async (percent: number, message?: string) => {\n const boundedPercent = Math.max(0, Math.min(100, percent));\n this.debug(`[${job.id}] progress ${boundedPercent}%`, message);\n },\n log: (level, message, meta) => {\n this.debug(`[${job.id}] [${level}] ${message}`, meta);\n },\n };\n\n try {\n const result = await this.handler!(context);\n\n // Check if aborted\n if (signal.aborted) {\n this.debug(`Job ${job.id} was aborted`);\n return;\n }\n\n // Complete the job\n await this.completeJob(job, result ?? undefined);\n } catch (error) {\n // Check if aborted\n if (signal.aborted) {\n this.debug(`Job ${job.id} was aborted`);\n return;\n }\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n await this.failJob(job, errorMessage);\n } finally {\n this.cleanupJob(activeJob);\n }\n }\n\n private async completeJob(\n job: ClaimedJob,\n result?: JsonValue,\n ): Promise<void> {\n if (!this.workerId) return;\n\n try {\n await this.client.jobs.complete(job.id, {\n workerId: this.workerId,\n result,\n ...(job.leaseId != null && { leaseId: job.leaseId }),\n });\n\n this.emit(\"job:completed\", {\n jobId: job.id,\n queueName: job.queueName,\n result,\n });\n } catch (error) {\n this.debug(`Failed to complete job ${job.id}`, error);\n }\n }\n\n private async failJob(job: ClaimedJob, errorMessage: string): Promise<void> {\n if (!this.workerId) return;\n\n const willRetry = job.retryCount < job.maxRetries;\n\n try {\n await this.client.jobs.fail(job.id, {\n workerId: this.workerId,\n error: errorMessage,\n ...(job.leaseId != null && { leaseId: job.leaseId }),\n });\n\n this.emit(\"job:failed\", {\n jobId: job.id,\n queueName: job.queueName,\n error: errorMessage,\n willRetry,\n });\n } catch (error) {\n this.debug(`Failed to fail job ${job.id}`, error);\n }\n }\n\n private cleanupJob(activeJob: ActiveJob): void {\n if (activeJob.heartbeatTimer) {\n clearInterval(activeJob.heartbeatTimer);\n activeJob.heartbeatTimer = undefined;\n }\n\n if (this.activeJobs.get(activeJob.executionId) === activeJob) {\n this.activeJobs.delete(activeJob.executionId);\n }\n }\n\n private async sendJobHeartbeat(activeJob: ActiveJob): Promise<void> {\n if (!this.workerId) return;\n\n const { job } = activeJob;\n\n try {\n await this.client.jobs.heartbeat(job.id, {\n workerId: this.workerId,\n leaseDurationSecs: this.options.leaseDuration,\n ...(job.leaseId != null && { leaseId: job.leaseId }),\n });\n } catch (error) {\n this.debug(`Job heartbeat failed for ${job.id}`, error);\n }\n }\n\n private async sendWorkerHeartbeat(): Promise<void> {\n if (!this.workerId || this.state !== \"running\") return;\n\n try {\n await this.client.workers.heartbeat(this.workerId, {\n currentJobs: this.activeJobs.size,\n status: \"healthy\",\n });\n } catch (error) {\n this.debug(\"Worker heartbeat failed\", error);\n }\n }\n\n private async waitForActiveJobs(): Promise<void> {\n while (this.activeJobs.size > 0) {\n await this.sleep(100);\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spooled/sdk",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
4
4
  "type": "module",
5
5
  "description": "Official Node.js/TypeScript SDK for Spooled Cloud job queue service",
6
6
  "author": "Spooled Cloud <support@spooled.cloud>",