@opengeni/worker-bundle 2.0.1 → 2.0.3-canary.36199476632001

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.
Files changed (63) hide show
  1. package/dist/activities/agent-turn/agent-build.d.ts +2 -0
  2. package/dist/activities/agent-turn/code-search.d.ts +60 -0
  3. package/dist/activities/agent-turn/codex-capacity.d.ts +13 -0
  4. package/dist/activities/agent-turn/errors.d.ts +12 -1
  5. package/dist/activities/agent-turn/failure-settlement.d.ts +1 -1
  6. package/dist/activities/agent-turn/governance-model.d.ts +2 -0
  7. package/dist/activities/agent-turn/history.d.ts +2 -0
  8. package/dist/activities/agent-turn/media-artifacts.d.ts +5 -3
  9. package/dist/activities/agent-turn/session-title.d.ts +32 -2
  10. package/dist/activities/agent-turn/tool-environment.d.ts +4 -0
  11. package/dist/activities/context-compaction.d.ts +10 -2
  12. package/dist/activities/knowledge-indexing.d.ts +19 -0
  13. package/dist/activities/retained-screenshots.d.ts +7 -2
  14. package/dist/activities/sandbox-lease.d.ts +3 -4
  15. package/dist/{activities-control-QA6OLRQY.js → activities-control-I72CRMAE.js} +283 -35
  16. package/dist/activities-control-I72CRMAE.js.map +1 -0
  17. package/dist/{activities-turn-YVVKCGAK.js → activities-turn-CSDKK4N3.js} +531 -77
  18. package/dist/activities-turn-CSDKK4N3.js.map +1 -0
  19. package/dist/artifact-outbox-entry.js +3 -0
  20. package/dist/artifact-outbox-entry.js.map +1 -1
  21. package/dist/{chunk-M3NVMF2V.js → chunk-7M6G2SCF.js} +172 -17
  22. package/dist/chunk-7M6G2SCF.js.map +1 -0
  23. package/dist/{chunk-I7HKKMUJ.js → chunk-DSPP6CZL.js} +48 -3
  24. package/dist/chunk-DSPP6CZL.js.map +1 -0
  25. package/dist/index.js +10 -5
  26. package/dist/index.js.map +1 -1
  27. package/dist/observability-metrics.d.ts +11 -1
  28. package/dist/sandbox-resume.d.ts +46 -0
  29. package/dist/workflow-bundle.js +80 -2
  30. package/dist/workflows/session.d.ts +30 -0
  31. package/package.json +20 -19
  32. package/src/activities/agent-turn/agent-build.ts +4 -0
  33. package/src/activities/agent-turn/code-search.ts +275 -0
  34. package/src/activities/agent-turn/codex-capacity.ts +37 -2
  35. package/src/activities/agent-turn/compaction-prep.ts +52 -16
  36. package/src/activities/agent-turn/errors.ts +67 -4
  37. package/src/activities/agent-turn/failure-settlement.ts +40 -8
  38. package/src/activities/agent-turn/governance-model.ts +17 -1
  39. package/src/activities/agent-turn/history.ts +14 -1
  40. package/src/activities/agent-turn/media-artifacts.ts +2 -1
  41. package/src/activities/agent-turn/run.ts +4 -0
  42. package/src/activities/agent-turn/sandbox-establish.ts +12 -1
  43. package/src/activities/agent-turn/sandbox-runtime.ts +25 -9
  44. package/src/activities/agent-turn/session-title.ts +73 -3
  45. package/src/activities/agent-turn/stream-attempt.ts +27 -15
  46. package/src/activities/agent-turn/tool-environment.ts +65 -0
  47. package/src/activities/context-compaction.ts +49 -14
  48. package/src/activities/knowledge-indexing.ts +240 -15
  49. package/src/activities/retained-screenshots.ts +82 -11
  50. package/src/activities/sandbox-lease.ts +141 -21
  51. package/src/activities/scheduled-tasks.ts +18 -2
  52. package/src/activity-services.ts +16 -4
  53. package/src/editable-artifact-hint-broker.ts +3 -0
  54. package/src/index.ts +2 -2
  55. package/src/observability-metrics.ts +70 -1
  56. package/src/personal-github-git-credentials.ts +2 -0
  57. package/src/sandbox-resume.ts +211 -5
  58. package/src/workflows/activities.ts +14 -1
  59. package/src/workflows/session.ts +102 -6
  60. package/dist/activities-control-QA6OLRQY.js.map +0 -1
  61. package/dist/activities-turn-YVVKCGAK.js.map +0 -1
  62. package/dist/chunk-I7HKKMUJ.js.map +0 -1
  63. package/dist/chunk-M3NVMF2V.js.map +0 -1
@@ -130,6 +130,9 @@ async function connectEditableArtifactHintBroker(input) {
130
130
  name,
131
131
  reconnect: true,
132
132
  maxReconnectAttempts: -1,
133
+ // Same policy as the event bus: a broker or auth-callout restart must not
134
+ // permanently close this connection after two identical auth errors.
135
+ ignoreAuthErrorAbort: true,
133
136
  reconnectTimeWait: 2e3,
134
137
  reconnectJitter: 1e3,
135
138
  reconnectJitterTLS: 1e3,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/editable-artifact-outbox-service.ts","../src/editable-artifact-outbox-dispatcher.ts","../src/editable-artifact-hint-broker.ts","../src/artifact-outbox-entry.ts"],"sourcesContent":["import {\n dbSearchPath,\n getArtifactOutboxSettings,\n resolveNatsControlPlaneAuth,\n type ArtifactOutboxSettings,\n} from \"@opengeni/config\";\nimport type { EditableArtifactOutboxDispatchSummary } from \"@opengeni/core\";\nimport { createObservability, type Observability } from \"@opengeni/observability\";\n\nimport {\n EDITABLE_ARTIFACT_OUTBOX_DATABASE_URL_ENV,\n EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE,\n createEditableArtifactOutboxWorker,\n type EditableArtifactOutboxWorkerRuntime,\n} from \"./editable-artifact-outbox-dispatcher\";\nimport type { EditableArtifactHintNatsAuth } from \"./editable-artifact-hint-broker\";\n\nexport type EditableArtifactOutboxServiceState =\n | \"starting\"\n | \"ready\"\n | \"draining\"\n | \"stopped\"\n | \"failed\";\n\nexport interface EditableArtifactOutboxRuntimePort {\n start(): Promise<void>;\n drain(): boolean;\n stop(): Promise<void>;\n check(signal?: AbortSignal): Promise<void>;\n readonly dispatcher: Readonly<{\n dispatchOnce(): Promise<EditableArtifactOutboxDispatchSummary>;\n }>;\n}\n\nexport type EditableArtifactOutboxService = Readonly<{\n state(): EditableArtifactOutboxServiceState;\n run(): Promise<void>;\n drain(reason?: string): boolean;\n close(): Promise<void>;\n dispatchOnce(): Promise<EditableArtifactOutboxDispatchSummary>;\n fetch(request: Request): Promise<Response>;\n}>;\n\nexport type CreateEditableArtifactOutboxServiceInput = Readonly<{\n runtime: EditableArtifactOutboxRuntimePort;\n observability: Observability;\n serviceName: string;\n environment: string;\n deploymentRevision?: string;\n readinessTimeoutMs?: number;\n}>;\n\nexport type ProductionEditableArtifactOutboxServiceOptions = Readonly<{\n settings: ArtifactOutboxSettings;\n databaseUrl: string;\n declaredDatabaseRole: string;\n natsUrl: string;\n natsAuth: EditableArtifactHintNatsAuth;\n owner: string;\n databasePoolSize?: number;\n batchSize?: number;\n concurrency?: number;\n leaseDurationMs?: number;\n leaseRenewIntervalMs?: number;\n pollIntervalMs?: number;\n publishTimeoutMs?: number;\n retryBaseMs?: number;\n retryMaxMs?: number;\n}>;\n\n/** Compose the independently supervised production outbox dispatcher. */\nexport async function createProductionEditableArtifactOutboxService(\n options: ProductionEditableArtifactOutboxServiceOptions,\n): Promise<EditableArtifactOutboxService> {\n if (options.declaredDatabaseRole !== EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE) {\n throw new Error(\"Artifact outbox dispatcher database role declaration is invalid\");\n }\n const observability = createObservability(options.settings, {\n component: \"artifact-outbox-dispatcher\",\n });\n const databaseSearchPath = dbSearchPath(options.settings);\n const runtime = await createEditableArtifactOutboxWorker({\n dispatcherDatabaseUrl: options.databaseUrl,\n ...(databaseSearchPath ? { databaseSearchPath } : {}),\n ...(options.databasePoolSize === undefined\n ? {}\n : { databasePoolSize: options.databasePoolSize }),\n natsUrl: options.natsUrl,\n natsAuth: options.natsAuth,\n owner: options.owner,\n dispatcher: {\n ...(options.batchSize === undefined ? {} : { batchSize: options.batchSize }),\n ...(options.concurrency === undefined ? {} : { concurrency: options.concurrency }),\n ...(options.leaseDurationMs === undefined\n ? {}\n : { leaseDurationMs: options.leaseDurationMs }),\n ...(options.leaseRenewIntervalMs === undefined\n ? {}\n : { leaseRenewIntervalMs: options.leaseRenewIntervalMs }),\n ...(options.pollIntervalMs === undefined ? {} : { pollIntervalMs: options.pollIntervalMs }),\n ...(options.publishTimeoutMs === undefined\n ? {}\n : { publishTimeoutMs: options.publishTimeoutMs }),\n ...(options.retryBaseMs === undefined ? {} : { retryBaseMs: options.retryBaseMs }),\n ...(options.retryMaxMs === undefined ? {} : { retryMaxMs: options.retryMaxMs }),\n },\n metrics: {\n increment(outcome, count = 1) {\n observability.incrementCounter({\n name: \"opengeni_artifact_outbox_dispatch_total\",\n help: \"Editable artifact outbox dispatch actions by closed outcome.\",\n labels: { outcome },\n amount: count,\n });\n },\n observePublishSeconds(outcome, seconds) {\n observability.observeHistogram({\n name: \"opengeni_artifact_outbox_publish_seconds\",\n help: \"Editable artifact broker publication latency by closed outcome.\",\n labels: { outcome },\n value: seconds,\n });\n },\n },\n logger: {\n warn(message, attributes) {\n observability.warn(message, {\n errorClass: \"WorkerOperationError\",\n errorCode: \"worker_operation_failed\",\n origin: \"worker\",\n outcome: typeof attributes.code === \"string\" ? attributes.code : \"unknown\",\n });\n },\n },\n });\n return createEditableArtifactOutboxService({\n runtime,\n observability,\n serviceName: options.settings.serviceName,\n environment: options.settings.environment,\n deploymentRevision: options.settings.deploymentRevision,\n });\n}\n\nexport function createEditableArtifactOutboxService(\n input: CreateEditableArtifactOutboxServiceInput,\n): EditableArtifactOutboxService {\n let state: EditableArtifactOutboxServiceState = \"starting\";\n let runPromise: Promise<void> | null = null;\n let closePromise: Promise<void> | null = null;\n let readinessPromise: Promise<void> | null = null;\n const readinessTimeoutMs = input.readinessTimeoutMs ?? 2_000;\n\n const ready = (): Promise<void> => {\n if (readinessPromise) return readinessPromise;\n const abort = new AbortController();\n const check = withTimeout(input.runtime.check(abort.signal), readinessTimeoutMs, abort);\n readinessPromise = check;\n void check.then(\n () => {\n if (readinessPromise === check) readinessPromise = null;\n },\n () => {\n if (readinessPromise === check) readinessPromise = null;\n },\n );\n return check;\n };\n\n const run = (): Promise<void> => {\n if (runPromise) return runPromise;\n if (state !== \"starting\") {\n return Promise.reject(new Error(\"Artifact outbox dispatcher service cannot be restarted\"));\n }\n runPromise = (async () => {\n try {\n await ready();\n if ((state as EditableArtifactOutboxServiceState) === \"draining\") {\n state = \"stopped\";\n return;\n }\n const running = input.runtime.start();\n state = \"ready\";\n await running;\n const exitWasDraining = (state as EditableArtifactOutboxServiceState) === \"draining\";\n state = exitWasDraining ? \"stopped\" : \"failed\";\n if (!exitWasDraining) {\n throw new Error(\"Artifact outbox dispatcher exited without a drain request\");\n }\n } catch (error) {\n const caughtState = state as EditableArtifactOutboxServiceState;\n if (caughtState !== \"draining\" && caughtState !== \"stopped\") state = \"failed\";\n throw error;\n }\n })();\n return runPromise;\n };\n\n const drain = (_reason = \"shutdown\"): boolean => {\n if (state === \"draining\" || state === \"stopped\" || state === \"failed\") return false;\n state = \"draining\";\n input.runtime.drain();\n return true;\n };\n\n const close = (): Promise<void> => {\n if (closePromise) return closePromise;\n closePromise = (async () => {\n drain(\"close\");\n if (runPromise) await runPromise.catch(() => undefined);\n await input.runtime.stop();\n if (state !== \"failed\") state = \"stopped\";\n })();\n return closePromise;\n };\n\n const fetch = async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n if (request.method !== \"GET\") {\n return Response.json({ error: \"method_not_allowed\" }, { status: 405 });\n }\n if (url.pathname === \"/healthz\") {\n const ok = state !== \"failed\" && state !== \"stopped\";\n return Response.json(\n {\n service: input.serviceName,\n component: \"artifact-outbox-dispatcher\",\n environment: input.environment,\n ...(input.deploymentRevision ? { deploymentRevision: input.deploymentRevision } : {}),\n state,\n ok,\n },\n { status: ok ? 200 : 503 },\n );\n }\n if (url.pathname === \"/readyz\") {\n if (state !== \"ready\") {\n return Response.json(\n {\n ok: false,\n state,\n checks: { databaseRole: { ok: false }, nats: { ok: false } },\n },\n { status: 503 },\n );\n }\n try {\n await ready();\n return Response.json({\n ok: true,\n state,\n checks: { databaseRole: { ok: true }, nats: { ok: true } },\n });\n } catch {\n return Response.json(\n {\n ok: false,\n state,\n checks: { databaseRole: { ok: false }, nats: { ok: false } },\n },\n { status: 503 },\n );\n }\n }\n if (url.pathname === \"/metrics\") {\n return new Response(await input.observability.prometheusMetrics(), {\n status: 200,\n headers: { \"content-type\": \"text/plain; version=0.0.4; charset=utf-8\" },\n });\n }\n return Response.json({ error: \"not_found\" }, { status: 404 });\n };\n\n return Object.freeze({\n state: () => state,\n run,\n drain,\n close,\n dispatchOnce: async () => await input.runtime.dispatcher.dispatchOnce(),\n fetch,\n });\n}\n\nexport type EditableArtifactOutboxSidecarEnvironment = Readonly<{\n databaseUrl: string;\n declaredDatabaseRole: string;\n owner: string;\n httpPort: number;\n databasePoolSize: number;\n batchSize: number;\n concurrency: number;\n leaseDurationMs: number;\n leaseRenewIntervalMs: number;\n pollIntervalMs: number;\n publishTimeoutMs: number;\n retryBaseMs: number;\n retryMaxMs: number;\n}>;\n\nexport function readEditableArtifactOutboxSidecarEnvironment(\n environment: NodeJS.ProcessEnv = process.env,\n): EditableArtifactOutboxSidecarEnvironment | null {\n if (environment.OPENGENI_ARTIFACT_OUTBOX_ENABLED !== \"true\") return null;\n const declaredDatabaseRole = required(environment, \"OPENGENI_ARTIFACT_OUTBOX_DATABASE_ROLE\");\n if (declaredDatabaseRole !== EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE) {\n throw new Error(\"OPENGENI_ARTIFACT_OUTBOX_DATABASE_ROLE is invalid\");\n }\n const result = {\n databaseUrl: required(environment, EDITABLE_ARTIFACT_OUTBOX_DATABASE_URL_ENV),\n declaredDatabaseRole,\n owner:\n environment.OPENGENI_ARTIFACT_OUTBOX_OWNER?.trim() ||\n `artifact-outbox-${process.pid}-${crypto.randomUUID()}`,\n httpPort: integer(environment, \"OPENGENI_ARTIFACT_OUTBOX_HTTP_PORT\", 9466, 1, 65_535),\n databasePoolSize: integer(environment, \"OPENGENI_ARTIFACT_OUTBOX_DB_POOL_SIZE\", 4, 1, 8),\n batchSize: integer(environment, \"OPENGENI_ARTIFACT_OUTBOX_BATCH_SIZE\", 32, 1, 1_000),\n concurrency: integer(environment, \"OPENGENI_ARTIFACT_OUTBOX_CONCURRENCY\", 8, 1, 128),\n leaseDurationMs: integer(\n environment,\n \"OPENGENI_ARTIFACT_OUTBOX_LEASE_MS\",\n 30_000,\n 1_000,\n 86_400_000,\n ),\n leaseRenewIntervalMs: integer(\n environment,\n \"OPENGENI_ARTIFACT_OUTBOX_RENEW_MS\",\n 10_000,\n 100,\n 43_199_999,\n ),\n pollIntervalMs: integer(environment, \"OPENGENI_ARTIFACT_OUTBOX_POLL_MS\", 500, 10, 60_000),\n publishTimeoutMs: integer(\n environment,\n \"OPENGENI_ARTIFACT_OUTBOX_PUBLISH_TIMEOUT_MS\",\n 5_000,\n 100,\n 60_000,\n ),\n retryBaseMs: integer(environment, \"OPENGENI_ARTIFACT_OUTBOX_RETRY_BASE_MS\", 500, 10, 60_000),\n retryMaxMs: integer(\n environment,\n \"OPENGENI_ARTIFACT_OUTBOX_RETRY_MAX_MS\",\n 60_000,\n 10,\n 86_400_000,\n ),\n } as const;\n if (result.leaseRenewIntervalMs >= result.leaseDurationMs) {\n throw new Error(\"OPENGENI_ARTIFACT_OUTBOX_RENEW_MS must be less than lease duration\");\n }\n if (result.retryBaseMs > result.retryMaxMs) {\n throw new Error(\"OPENGENI_ARTIFACT_OUTBOX_RETRY_BASE_MS must not exceed retry max\");\n }\n return Object.freeze(result);\n}\n\nexport async function createOutboxSidecarFromEnvironment(\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<Readonly<{ service: EditableArtifactOutboxService; httpPort: number }> | null> {\n const sidecar = readEditableArtifactOutboxSidecarEnvironment(environment);\n if (!sidecar) return null;\n const settings = getArtifactOutboxSettings(environment);\n const controlPlaneAuth = resolveNatsControlPlaneAuth(settings);\n const natsAuth: EditableArtifactHintNatsAuth = controlPlaneAuth\n ? {\n kind: \"user-password\",\n user: controlPlaneAuth.user,\n pass: controlPlaneAuth.password,\n }\n : { kind: \"anonymous\" };\n const service = await createProductionEditableArtifactOutboxService({\n settings,\n databaseUrl: sidecar.databaseUrl,\n declaredDatabaseRole: sidecar.declaredDatabaseRole,\n natsUrl: settings.natsUrl,\n natsAuth,\n owner: sidecar.owner,\n databasePoolSize: sidecar.databasePoolSize,\n batchSize: sidecar.batchSize,\n concurrency: sidecar.concurrency,\n leaseDurationMs: sidecar.leaseDurationMs,\n leaseRenewIntervalMs: sidecar.leaseRenewIntervalMs,\n pollIntervalMs: sidecar.pollIntervalMs,\n publishTimeoutMs: sidecar.publishTimeoutMs,\n retryBaseMs: sidecar.retryBaseMs,\n retryMaxMs: sidecar.retryMaxMs,\n });\n return Object.freeze({ service, httpPort: sidecar.httpPort });\n}\n\nasync function withTimeout<T>(\n promise: Promise<T>,\n milliseconds: number,\n abort: AbortController,\n): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n abort.abort();\n reject(new Error(\"readiness check timed out\"));\n }, milliseconds);\n }),\n ]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\nfunction required(environment: NodeJS.ProcessEnv, name: string): string {\n const value = environment[name]?.trim();\n if (!value) throw new Error(`${name} is required when artifact outbox dispatch is enabled`);\n return value;\n}\n\nfunction integer(\n environment: NodeJS.ProcessEnv,\n name: string,\n fallback: number,\n minimum: number,\n maximum: number,\n): number {\n const raw = environment[name];\n const value = raw === undefined ? fallback : Number(raw);\n if (!Number.isSafeInteger(value) || value < minimum || value > maximum) {\n throw new Error(`${name} is outside its allowed range`);\n }\n return value;\n}\n\n// Compile-time assurance that production composition satisfies the service port.\nconst _runtimePort: EditableArtifactOutboxRuntimePort | undefined = undefined as\n | EditableArtifactOutboxWorkerRuntime\n | undefined;\nvoid _runtimePort;\n","import {\n EditableArtifactLiveOutboxDispatcher,\n MathEditableArtifactOutboxRandom,\n SystemEditableArtifactLiveClock,\n SystemEditableArtifactLiveScheduler,\n type EditableArtifactOutboxDispatcherOptions,\n type EditableArtifactOutboxLoggerPort,\n type EditableArtifactOutboxMetricsPort,\n type EditableArtifactOutboxDispatcherStorePort,\n type EditableArtifactLiveOutboxRecord,\n} from \"@opengeni/core\";\nimport {\n PostgresEditableArtifactStore,\n createDb,\n dbSql,\n type Database,\n type DbClient,\n} from \"@opengeni/db\";\n\nimport {\n connectEditableArtifactHintBroker,\n type ConfirmedNatsEditableArtifactHintBroker,\n type EditableArtifactHintNatsAuth,\n} from \"./editable-artifact-hint-broker\";\n\nexport const EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE =\n \"opengeni_artifact_outbox_dispatcher\";\nexport const EDITABLE_ARTIFACT_OUTBOX_DATABASE_URL_ENV = \"OPENGENI_ARTIFACT_OUTBOX_DATABASE_URL\";\n\nexport type EditableArtifactOutboxWorkerOptions = Readonly<{\n /** Must authenticate as the dedicated dispatcher role, never the generic app role. */\n dispatcherDatabaseUrl: string;\n databaseSearchPath?: string;\n databasePoolSize?: number;\n natsUrl: string;\n natsAuth: EditableArtifactHintNatsAuth;\n owner?: string;\n dispatcher?: Omit<EditableArtifactOutboxDispatcherOptions, \"owner\">;\n metrics?: EditableArtifactOutboxMetricsPort;\n logger?: EditableArtifactOutboxLoggerPort;\n}>;\n\n/** Explicit lifecycle handle; hosts supervise `start()` and await `stop()` on drain. */\nexport class EditableArtifactOutboxWorkerRuntime {\n private readonly abort = new AbortController();\n private running: Promise<void> | null = null;\n private closing: Promise<void> | null = null;\n\n constructor(\n readonly dispatcher: EditableArtifactLiveOutboxDispatcher,\n private readonly broker: ConfirmedNatsEditableArtifactHintBroker,\n private readonly database: DbClient,\n ) {}\n\n start(): Promise<void> {\n if (this.closing) return Promise.reject(new Error(\"Artifact outbox worker is stopping\"));\n this.running ??= this.dispatcher.run(this.abort.signal);\n return this.running;\n }\n\n drain(): boolean {\n if (this.abort.signal.aborted) return false;\n this.abort.abort();\n return true;\n }\n\n async check(signal?: AbortSignal): Promise<void> {\n if (this.abort.signal.aborted || this.closing) {\n throw new Error(\"Artifact outbox worker is stopping\");\n }\n await Promise.all([\n assertDedicatedOutboxDispatcherDatabaseRole(this.database.db),\n this.broker.check(signal),\n ]);\n }\n\n stop(): Promise<void> {\n if (this.closing) return this.closing;\n this.closing = this.stopOnce();\n return this.closing;\n }\n\n private async stopOnce(): Promise<void> {\n this.drain();\n const running = this.running ? await Promise.allSettled([this.running]) : [];\n const cleanup = await Promise.allSettled([this.broker.close(), this.database.close()]);\n const failure = [...running, ...cleanup].find(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n if (failure) throw failure.reason;\n }\n}\n\n/**\n * Production composition. DB grants make the role a narrow capability: it can\n * execute only lease-fenced dispatcher functions and cannot read artifact rows.\n */\nexport async function createEditableArtifactOutboxWorker(\n options: EditableArtifactOutboxWorkerOptions,\n): Promise<EditableArtifactOutboxWorkerRuntime> {\n const dispatcherDatabaseUrl = dedicatedDispatcherDatabaseUrl(options.dispatcherDatabaseUrl);\n const databasePoolSize = options.databasePoolSize ?? 2;\n if (!Number.isSafeInteger(databasePoolSize) || databasePoolSize < 1 || databasePoolSize > 8) {\n throw new TypeError(\"Artifact outbox dispatcher DB pool size must be 1-8\");\n }\n const database = createDb(dispatcherDatabaseUrl, {\n max: databasePoolSize,\n ...(options.databaseSearchPath ? { searchPath: options.databaseSearchPath } : {}),\n });\n let broker: ConfirmedNatsEditableArtifactHintBroker;\n try {\n await assertDedicatedOutboxDispatcherDatabaseRole(database.db);\n broker = await connectEditableArtifactHintBroker({\n natsUrl: options.natsUrl,\n auth: options.natsAuth,\n });\n } catch (error) {\n await database.close();\n throw error;\n }\n const persistence = new PostgresEditableArtifactStore(database.db);\n const store = dispatcherStore(persistence);\n const dispatcher = new EditableArtifactLiveOutboxDispatcher(\n {\n store,\n broker,\n clock: new SystemEditableArtifactLiveClock(),\n scheduler: new SystemEditableArtifactLiveScheduler(),\n random: new MathEditableArtifactOutboxRandom(),\n ...(options.metrics ? { metrics: options.metrics } : {}),\n ...(options.logger ? { logger: options.logger } : {}),\n },\n {\n owner: options.owner ?? `artifact-outbox:${crypto.randomUUID()}`,\n ...options.dispatcher,\n },\n );\n return new EditableArtifactOutboxWorkerRuntime(dispatcher, broker, database);\n}\n\n/**\n * Verify the database identity and its negative capability at runtime. A DSN\n * username check alone is insufficient because PostgreSQL role inheritance,\n * SET ROLE, or a mis-provisioned grant could otherwise widen this worker.\n */\nexport async function assertDedicatedOutboxDispatcherDatabaseRole(db: Database): Promise<void> {\n const raw = await db.execute<{\n current_role: string;\n session_role: string;\n can_access_any_relation: boolean;\n can_access_any_sequence: boolean;\n }>(dbSql`\n select\n current_user::text as current_role,\n session_user::text as session_role,\n exists (\n select 1\n from pg_catalog.pg_class relation_row\n join pg_catalog.pg_namespace namespace_row\n on namespace_row.oid = relation_row.relnamespace\n where namespace_row.nspname = current_schema()\n and relation_row.relkind in ('r', 'p', 'v', 'm', 'f')\n and (\n has_table_privilege(current_user, relation_row.oid, 'SELECT')\n or has_table_privilege(current_user, relation_row.oid, 'INSERT')\n or has_table_privilege(current_user, relation_row.oid, 'UPDATE')\n or has_table_privilege(current_user, relation_row.oid, 'DELETE')\n or has_table_privilege(current_user, relation_row.oid, 'TRUNCATE')\n or has_table_privilege(current_user, relation_row.oid, 'REFERENCES')\n or has_table_privilege(current_user, relation_row.oid, 'TRIGGER')\n or has_any_column_privilege(current_user, relation_row.oid, 'SELECT')\n or has_any_column_privilege(current_user, relation_row.oid, 'INSERT')\n or has_any_column_privilege(current_user, relation_row.oid, 'UPDATE')\n or has_any_column_privilege(current_user, relation_row.oid, 'REFERENCES')\n )\n ) as can_access_any_relation,\n exists (\n select 1\n from pg_catalog.pg_class sequence_row\n join pg_catalog.pg_namespace namespace_row\n on namespace_row.oid = sequence_row.relnamespace\n where namespace_row.nspname = current_schema()\n and sequence_row.relkind = 'S'\n and (\n has_sequence_privilege(current_user, sequence_row.oid, 'USAGE')\n or has_sequence_privilege(current_user, sequence_row.oid, 'SELECT')\n or has_sequence_privilege(current_user, sequence_row.oid, 'UPDATE')\n )\n ) as can_access_any_sequence\n `);\n const rows = Array.isArray(raw) ? raw : ((raw as unknown as { rows?: unknown[] }).rows ?? []);\n const row = rows[0] as\n | {\n current_role?: unknown;\n session_role?: unknown;\n can_access_any_relation?: unknown;\n can_access_any_sequence?: unknown;\n }\n | undefined;\n if (\n row?.current_role !== EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE ||\n row.session_role !== EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE ||\n row.can_access_any_relation !== false ||\n row.can_access_any_sequence !== false\n ) {\n throw new Error(\"Artifact outbox dispatcher database connection has an unsafe role posture\");\n }\n}\n\nfunction dispatcherStore(\n persistence: PostgresEditableArtifactStore,\n): EditableArtifactOutboxDispatcherStorePort {\n return {\n claimLiveOutbox: async (input) =>\n (await persistence.claimLiveOutbox(\n input,\n )) as unknown as readonly EditableArtifactLiveOutboxRecord[],\n renewLiveOutbox: async (input) => await persistence.renewLiveOutbox(input),\n markLiveOutboxPublished: async (input) => await persistence.markLiveOutboxPublished(input),\n retryLiveOutbox: async (input) => await persistence.retryLiveOutbox(input),\n deadLetterLiveOutbox: async (input) => await persistence.deadLetterLiveOutbox(input),\n };\n}\n\nexport function dedicatedDispatcherDatabaseUrl(raw: string): string {\n if (typeof raw !== \"string\" || raw.length > 8_192 || raw.trim() !== raw) {\n throw new TypeError(`${EDITABLE_ARTIFACT_OUTBOX_DATABASE_URL_ENV} is malformed`);\n }\n let url: URL;\n try {\n url = new URL(raw);\n } catch (cause) {\n throw new TypeError(`${EDITABLE_ARTIFACT_OUTBOX_DATABASE_URL_ENV} is malformed`, { cause });\n }\n if (\n (url.protocol !== \"postgres:\" && url.protocol !== \"postgresql:\") ||\n decodeURIComponent(url.username) !== EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE\n ) {\n throw new TypeError(\n `${EDITABLE_ARTIFACT_OUTBOX_DATABASE_URL_ENV} must authenticate as ${EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE}`,\n );\n }\n return raw;\n}\n","import {\n EDITABLE_ARTIFACT_HINT_MAX_BYTES,\n type EditableArtifactHintBrokerPort,\n} from \"@opengeni/core\";\nimport { connect, type NatsConnection } from \"@opengeni/events\";\n\nconst DEFAULT_CONNECTION_NAME = \"opengeni-editable-artifact-outbox\";\n\nexport type EditableArtifactHintNatsAuth =\n | Readonly<{ kind: \"user-password\"; user: string; pass: string }>\n | Readonly<{ kind: \"token\"; token: string }>\n | Readonly<{ kind: \"anonymous\" }>;\n\nexport type EditableArtifactHintNatsBrokerOptions = Readonly<{\n maxHintBytes?: number;\n}>;\n\nexport type EditableArtifactHintNatsConnection = Pick<\n NatsConnection,\n \"publish\" | \"flush\" | \"drain\" | \"close\" | \"closed\" | \"isClosed\" | \"isDraining\"\n>;\n\n/**\n * Core-NATS adapter for the durable outbox. A publish resolves only after a\n * server round-trip flush ACK. Reconnect buffering may create duplicates after\n * a timeout; hints are intentionally idempotent wakeups for durable gap-fill.\n */\nexport class ConfirmedNatsEditableArtifactHintBroker implements EditableArtifactHintBrokerPort {\n private readonly maxHintBytes: number;\n\n constructor(\n private readonly connection: EditableArtifactHintNatsConnection,\n options: EditableArtifactHintNatsBrokerOptions = {},\n ) {\n this.maxHintBytes = options.maxHintBytes ?? EDITABLE_ARTIFACT_HINT_MAX_BYTES;\n if (\n !Number.isSafeInteger(this.maxHintBytes) ||\n this.maxHintBytes < 1 ||\n this.maxHintBytes > EDITABLE_ARTIFACT_HINT_MAX_BYTES\n ) {\n throw new TypeError(\"Editable artifact NATS hint byte limit is invalid\");\n }\n }\n\n async publish(\n input: Readonly<{\n subject: string;\n payload: Uint8Array;\n signal: AbortSignal;\n }>,\n ): Promise<void> {\n assertSubject(input.subject);\n if (\n !(input.payload instanceof Uint8Array) ||\n input.payload.byteLength < 1 ||\n input.payload.byteLength > this.maxHintBytes\n ) {\n throw new EditableArtifactNatsHintPublishError(\n \"broker_backpressure\",\n \"Editable artifact hint exceeds the NATS envelope\",\n );\n }\n if (input.signal.aborted) throw abortedPublish();\n if (this.connection.isClosed() || this.connection.isDraining()) {\n throw new EditableArtifactNatsHintPublishError(\n \"broker_unavailable\",\n \"Editable artifact NATS connection is closed\",\n );\n }\n try {\n this.connection.publish(input.subject, input.payload);\n await abortable(this.connection.flush(), input.signal);\n } catch (error) {\n if (input.signal.aborted) throw abortedPublish();\n if (error instanceof EditableArtifactNatsHintPublishError) throw error;\n throw new EditableArtifactNatsHintPublishError(\n \"broker_unavailable\",\n \"Editable artifact NATS publish was not acknowledged\",\n { cause: error },\n );\n }\n }\n\n /**\n * A readiness probe must prove the server is reachable, not merely that the\n * client object has not observed closure yet. `flush()` is a bounded NATS\n * round trip and has the same acknowledgement semantics as publication.\n */\n async check(signal: AbortSignal = new AbortController().signal): Promise<void> {\n if (signal.aborted) throw abortedPublish();\n if (this.connection.isClosed() || this.connection.isDraining()) {\n throw new EditableArtifactNatsHintPublishError(\n \"broker_unavailable\",\n \"Editable artifact NATS connection is unavailable\",\n );\n }\n try {\n await abortable(this.connection.flush(), signal);\n } catch (error) {\n if (error instanceof EditableArtifactNatsHintPublishError) throw error;\n throw new EditableArtifactNatsHintPublishError(\n \"broker_unavailable\",\n \"Editable artifact NATS readiness round trip failed\",\n { cause: error },\n );\n }\n }\n\n async close(drainTimeoutMs = 5_000): Promise<void> {\n if (!Number.isSafeInteger(drainTimeoutMs) || drainTimeoutMs < 1 || drainTimeoutMs > 30_000) {\n throw new TypeError(\"Editable artifact NATS drain timeout is invalid\");\n }\n if (this.connection.isClosed()) return;\n if (this.connection.isDraining()) {\n await this.connection.closed();\n return;\n }\n let timer: ReturnType<typeof setTimeout> | undefined;\n const drain = this.connection.drain();\n const outcome = await Promise.race([\n drain.then(\n () => \"drained\" as const,\n () => \"failed\" as const,\n ),\n new Promise<\"timed_out\">((resolve) => {\n timer = setTimeout(() => resolve(\"timed_out\"), drainTimeoutMs);\n }),\n ]);\n if (timer) clearTimeout(timer);\n if (outcome !== \"drained\" && !this.connection.isClosed()) {\n await this.connection.close();\n }\n }\n}\n\nexport class EditableArtifactNatsHintPublishError extends Error {\n constructor(\n readonly code: \"broker_unavailable\" | \"broker_backpressure\",\n message: string,\n options?: ErrorOptions,\n ) {\n super(message, options);\n this.name = \"EditableArtifactNatsHintPublishError\";\n }\n}\n\n/** Opens one resilient dispatcher identity; callers own `broker.close()`. */\nexport async function connectEditableArtifactHintBroker(\n input: Readonly<{\n natsUrl: string;\n auth: EditableArtifactHintNatsAuth;\n name?: string;\n maxHintBytes?: number;\n }>,\n): Promise<ConfirmedNatsEditableArtifactHintBroker> {\n const natsUrl = boundedText(input.natsUrl, \"NATS URL\", 2_048);\n const name = boundedText(input.name ?? DEFAULT_CONNECTION_NAME, \"NATS connection name\", 128);\n const auth = natsAuthOptions(input.auth);\n const connection = await connect({\n servers: natsUrl,\n name,\n reconnect: true,\n maxReconnectAttempts: -1,\n reconnectTimeWait: 2_000,\n reconnectJitter: 1_000,\n reconnectJitterTLS: 1_000,\n waitOnFirstConnect: true,\n pingInterval: 20_000,\n maxPingOut: 3,\n ...auth,\n });\n return new ConfirmedNatsEditableArtifactHintBroker(connection, {\n ...(input.maxHintBytes === undefined ? {} : { maxHintBytes: input.maxHintBytes }),\n });\n}\n\nfunction natsAuthOptions(auth: EditableArtifactHintNatsAuth): {\n user?: string;\n pass?: string;\n token?: string;\n} {\n if (auth.kind === \"anonymous\") return {};\n if (auth.kind === \"token\") return { token: boundedText(auth.token, \"NATS token\", 4_096) };\n return {\n user: boundedText(auth.user, \"NATS user\", 256),\n pass: boundedText(auth.pass, \"NATS password\", 4_096),\n };\n}\n\nfunction assertSubject(subject: string): void {\n const bytes = new TextEncoder().encode(subject).byteLength;\n if (\n bytes < 1 ||\n bytes > 1_024 ||\n subject.startsWith(\".\") ||\n subject.endsWith(\".\") ||\n subject.includes(\"..\") ||\n /[\\s*>]/u.test(subject)\n ) {\n throw new EditableArtifactNatsHintPublishError(\n \"broker_backpressure\",\n \"Editable artifact NATS subject is malformed\",\n );\n }\n}\n\nfunction boundedText(value: string, label: string, maxBytes: number): string {\n const bytes = new TextEncoder().encode(value).byteLength;\n if (bytes < 1 || bytes > maxBytes || value.trim() !== value) {\n throw new TypeError(`${label} is malformed`);\n }\n return value;\n}\n\nfunction abortedPublish(): EditableArtifactNatsHintPublishError {\n return new EditableArtifactNatsHintPublishError(\n \"broker_unavailable\",\n \"Editable artifact NATS publish was aborted\",\n );\n}\n\nasync function abortable(operation: Promise<void>, signal: AbortSignal): Promise<void> {\n if (signal.aborted) throw abortedPublish();\n let remove: () => void = () => undefined;\n const aborted = new Promise<never>((_resolve, reject) => {\n const onAbort = () => reject(abortedPublish());\n signal.addEventListener(\"abort\", onAbort, { once: true });\n remove = () => signal.removeEventListener(\"abort\", onAbort);\n });\n try {\n await Promise.race([operation, aborted]);\n } finally {\n remove();\n }\n}\n","import { createOutboxSidecarFromEnvironment } from \"./editable-artifact-outbox-service\";\n\n/** Dedicated process: no Temporal/control worker is created or imported here. */\nexport async function runEditableArtifactOutboxSidecar(\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<void> {\n const configured = await createOutboxSidecarFromEnvironment(environment);\n if (!configured) throw new Error(\"Editable artifact outbox sidecar is disabled\");\n const server = Bun.serve({\n hostname: \"0.0.0.0\",\n port: configured.httpPort,\n fetch: configured.service.fetch,\n });\n const stop = () => configured.service.drain(\"process signal\");\n process.on(\"SIGTERM\", stop);\n process.on(\"SIGINT\", stop);\n try {\n await configured.service.run();\n } finally {\n process.off(\"SIGTERM\", stop);\n process.off(\"SIGINT\", stop);\n server.stop(true);\n await configured.service.close();\n }\n}\n\nif (import.meta.main) {\n await runEditableArtifactOutboxSidecar();\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/editable-artifact-outbox-service.ts","../src/editable-artifact-outbox-dispatcher.ts","../src/editable-artifact-hint-broker.ts","../src/artifact-outbox-entry.ts"],"sourcesContent":["import {\n dbSearchPath,\n getArtifactOutboxSettings,\n resolveNatsControlPlaneAuth,\n type ArtifactOutboxSettings,\n} from \"@opengeni/config\";\nimport type { EditableArtifactOutboxDispatchSummary } from \"@opengeni/core\";\nimport { createObservability, type Observability } from \"@opengeni/observability\";\n\nimport {\n EDITABLE_ARTIFACT_OUTBOX_DATABASE_URL_ENV,\n EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE,\n createEditableArtifactOutboxWorker,\n type EditableArtifactOutboxWorkerRuntime,\n} from \"./editable-artifact-outbox-dispatcher\";\nimport type { EditableArtifactHintNatsAuth } from \"./editable-artifact-hint-broker\";\n\nexport type EditableArtifactOutboxServiceState =\n | \"starting\"\n | \"ready\"\n | \"draining\"\n | \"stopped\"\n | \"failed\";\n\nexport interface EditableArtifactOutboxRuntimePort {\n start(): Promise<void>;\n drain(): boolean;\n stop(): Promise<void>;\n check(signal?: AbortSignal): Promise<void>;\n readonly dispatcher: Readonly<{\n dispatchOnce(): Promise<EditableArtifactOutboxDispatchSummary>;\n }>;\n}\n\nexport type EditableArtifactOutboxService = Readonly<{\n state(): EditableArtifactOutboxServiceState;\n run(): Promise<void>;\n drain(reason?: string): boolean;\n close(): Promise<void>;\n dispatchOnce(): Promise<EditableArtifactOutboxDispatchSummary>;\n fetch(request: Request): Promise<Response>;\n}>;\n\nexport type CreateEditableArtifactOutboxServiceInput = Readonly<{\n runtime: EditableArtifactOutboxRuntimePort;\n observability: Observability;\n serviceName: string;\n environment: string;\n deploymentRevision?: string;\n readinessTimeoutMs?: number;\n}>;\n\nexport type ProductionEditableArtifactOutboxServiceOptions = Readonly<{\n settings: ArtifactOutboxSettings;\n databaseUrl: string;\n declaredDatabaseRole: string;\n natsUrl: string;\n natsAuth: EditableArtifactHintNatsAuth;\n owner: string;\n databasePoolSize?: number;\n batchSize?: number;\n concurrency?: number;\n leaseDurationMs?: number;\n leaseRenewIntervalMs?: number;\n pollIntervalMs?: number;\n publishTimeoutMs?: number;\n retryBaseMs?: number;\n retryMaxMs?: number;\n}>;\n\n/** Compose the independently supervised production outbox dispatcher. */\nexport async function createProductionEditableArtifactOutboxService(\n options: ProductionEditableArtifactOutboxServiceOptions,\n): Promise<EditableArtifactOutboxService> {\n if (options.declaredDatabaseRole !== EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE) {\n throw new Error(\"Artifact outbox dispatcher database role declaration is invalid\");\n }\n const observability = createObservability(options.settings, {\n component: \"artifact-outbox-dispatcher\",\n });\n const databaseSearchPath = dbSearchPath(options.settings);\n const runtime = await createEditableArtifactOutboxWorker({\n dispatcherDatabaseUrl: options.databaseUrl,\n ...(databaseSearchPath ? { databaseSearchPath } : {}),\n ...(options.databasePoolSize === undefined\n ? {}\n : { databasePoolSize: options.databasePoolSize }),\n natsUrl: options.natsUrl,\n natsAuth: options.natsAuth,\n owner: options.owner,\n dispatcher: {\n ...(options.batchSize === undefined ? {} : { batchSize: options.batchSize }),\n ...(options.concurrency === undefined ? {} : { concurrency: options.concurrency }),\n ...(options.leaseDurationMs === undefined\n ? {}\n : { leaseDurationMs: options.leaseDurationMs }),\n ...(options.leaseRenewIntervalMs === undefined\n ? {}\n : { leaseRenewIntervalMs: options.leaseRenewIntervalMs }),\n ...(options.pollIntervalMs === undefined ? {} : { pollIntervalMs: options.pollIntervalMs }),\n ...(options.publishTimeoutMs === undefined\n ? {}\n : { publishTimeoutMs: options.publishTimeoutMs }),\n ...(options.retryBaseMs === undefined ? {} : { retryBaseMs: options.retryBaseMs }),\n ...(options.retryMaxMs === undefined ? {} : { retryMaxMs: options.retryMaxMs }),\n },\n metrics: {\n increment(outcome, count = 1) {\n observability.incrementCounter({\n name: \"opengeni_artifact_outbox_dispatch_total\",\n help: \"Editable artifact outbox dispatch actions by closed outcome.\",\n labels: { outcome },\n amount: count,\n });\n },\n observePublishSeconds(outcome, seconds) {\n observability.observeHistogram({\n name: \"opengeni_artifact_outbox_publish_seconds\",\n help: \"Editable artifact broker publication latency by closed outcome.\",\n labels: { outcome },\n value: seconds,\n });\n },\n },\n logger: {\n warn(message, attributes) {\n observability.warn(message, {\n errorClass: \"WorkerOperationError\",\n errorCode: \"worker_operation_failed\",\n origin: \"worker\",\n outcome: typeof attributes.code === \"string\" ? attributes.code : \"unknown\",\n });\n },\n },\n });\n return createEditableArtifactOutboxService({\n runtime,\n observability,\n serviceName: options.settings.serviceName,\n environment: options.settings.environment,\n deploymentRevision: options.settings.deploymentRevision,\n });\n}\n\nexport function createEditableArtifactOutboxService(\n input: CreateEditableArtifactOutboxServiceInput,\n): EditableArtifactOutboxService {\n let state: EditableArtifactOutboxServiceState = \"starting\";\n let runPromise: Promise<void> | null = null;\n let closePromise: Promise<void> | null = null;\n let readinessPromise: Promise<void> | null = null;\n const readinessTimeoutMs = input.readinessTimeoutMs ?? 2_000;\n\n const ready = (): Promise<void> => {\n if (readinessPromise) return readinessPromise;\n const abort = new AbortController();\n const check = withTimeout(input.runtime.check(abort.signal), readinessTimeoutMs, abort);\n readinessPromise = check;\n void check.then(\n () => {\n if (readinessPromise === check) readinessPromise = null;\n },\n () => {\n if (readinessPromise === check) readinessPromise = null;\n },\n );\n return check;\n };\n\n const run = (): Promise<void> => {\n if (runPromise) return runPromise;\n if (state !== \"starting\") {\n return Promise.reject(new Error(\"Artifact outbox dispatcher service cannot be restarted\"));\n }\n runPromise = (async () => {\n try {\n await ready();\n if ((state as EditableArtifactOutboxServiceState) === \"draining\") {\n state = \"stopped\";\n return;\n }\n const running = input.runtime.start();\n state = \"ready\";\n await running;\n const exitWasDraining = (state as EditableArtifactOutboxServiceState) === \"draining\";\n state = exitWasDraining ? \"stopped\" : \"failed\";\n if (!exitWasDraining) {\n throw new Error(\"Artifact outbox dispatcher exited without a drain request\");\n }\n } catch (error) {\n const caughtState = state as EditableArtifactOutboxServiceState;\n if (caughtState !== \"draining\" && caughtState !== \"stopped\") state = \"failed\";\n throw error;\n }\n })();\n return runPromise;\n };\n\n const drain = (_reason = \"shutdown\"): boolean => {\n if (state === \"draining\" || state === \"stopped\" || state === \"failed\") return false;\n state = \"draining\";\n input.runtime.drain();\n return true;\n };\n\n const close = (): Promise<void> => {\n if (closePromise) return closePromise;\n closePromise = (async () => {\n drain(\"close\");\n if (runPromise) await runPromise.catch(() => undefined);\n await input.runtime.stop();\n if (state !== \"failed\") state = \"stopped\";\n })();\n return closePromise;\n };\n\n const fetch = async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n if (request.method !== \"GET\") {\n return Response.json({ error: \"method_not_allowed\" }, { status: 405 });\n }\n if (url.pathname === \"/healthz\") {\n const ok = state !== \"failed\" && state !== \"stopped\";\n return Response.json(\n {\n service: input.serviceName,\n component: \"artifact-outbox-dispatcher\",\n environment: input.environment,\n ...(input.deploymentRevision ? { deploymentRevision: input.deploymentRevision } : {}),\n state,\n ok,\n },\n { status: ok ? 200 : 503 },\n );\n }\n if (url.pathname === \"/readyz\") {\n if (state !== \"ready\") {\n return Response.json(\n {\n ok: false,\n state,\n checks: { databaseRole: { ok: false }, nats: { ok: false } },\n },\n { status: 503 },\n );\n }\n try {\n await ready();\n return Response.json({\n ok: true,\n state,\n checks: { databaseRole: { ok: true }, nats: { ok: true } },\n });\n } catch {\n return Response.json(\n {\n ok: false,\n state,\n checks: { databaseRole: { ok: false }, nats: { ok: false } },\n },\n { status: 503 },\n );\n }\n }\n if (url.pathname === \"/metrics\") {\n return new Response(await input.observability.prometheusMetrics(), {\n status: 200,\n headers: { \"content-type\": \"text/plain; version=0.0.4; charset=utf-8\" },\n });\n }\n return Response.json({ error: \"not_found\" }, { status: 404 });\n };\n\n return Object.freeze({\n state: () => state,\n run,\n drain,\n close,\n dispatchOnce: async () => await input.runtime.dispatcher.dispatchOnce(),\n fetch,\n });\n}\n\nexport type EditableArtifactOutboxSidecarEnvironment = Readonly<{\n databaseUrl: string;\n declaredDatabaseRole: string;\n owner: string;\n httpPort: number;\n databasePoolSize: number;\n batchSize: number;\n concurrency: number;\n leaseDurationMs: number;\n leaseRenewIntervalMs: number;\n pollIntervalMs: number;\n publishTimeoutMs: number;\n retryBaseMs: number;\n retryMaxMs: number;\n}>;\n\nexport function readEditableArtifactOutboxSidecarEnvironment(\n environment: NodeJS.ProcessEnv = process.env,\n): EditableArtifactOutboxSidecarEnvironment | null {\n if (environment.OPENGENI_ARTIFACT_OUTBOX_ENABLED !== \"true\") return null;\n const declaredDatabaseRole = required(environment, \"OPENGENI_ARTIFACT_OUTBOX_DATABASE_ROLE\");\n if (declaredDatabaseRole !== EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE) {\n throw new Error(\"OPENGENI_ARTIFACT_OUTBOX_DATABASE_ROLE is invalid\");\n }\n const result = {\n databaseUrl: required(environment, EDITABLE_ARTIFACT_OUTBOX_DATABASE_URL_ENV),\n declaredDatabaseRole,\n owner:\n environment.OPENGENI_ARTIFACT_OUTBOX_OWNER?.trim() ||\n `artifact-outbox-${process.pid}-${crypto.randomUUID()}`,\n httpPort: integer(environment, \"OPENGENI_ARTIFACT_OUTBOX_HTTP_PORT\", 9466, 1, 65_535),\n databasePoolSize: integer(environment, \"OPENGENI_ARTIFACT_OUTBOX_DB_POOL_SIZE\", 4, 1, 8),\n batchSize: integer(environment, \"OPENGENI_ARTIFACT_OUTBOX_BATCH_SIZE\", 32, 1, 1_000),\n concurrency: integer(environment, \"OPENGENI_ARTIFACT_OUTBOX_CONCURRENCY\", 8, 1, 128),\n leaseDurationMs: integer(\n environment,\n \"OPENGENI_ARTIFACT_OUTBOX_LEASE_MS\",\n 30_000,\n 1_000,\n 86_400_000,\n ),\n leaseRenewIntervalMs: integer(\n environment,\n \"OPENGENI_ARTIFACT_OUTBOX_RENEW_MS\",\n 10_000,\n 100,\n 43_199_999,\n ),\n pollIntervalMs: integer(environment, \"OPENGENI_ARTIFACT_OUTBOX_POLL_MS\", 500, 10, 60_000),\n publishTimeoutMs: integer(\n environment,\n \"OPENGENI_ARTIFACT_OUTBOX_PUBLISH_TIMEOUT_MS\",\n 5_000,\n 100,\n 60_000,\n ),\n retryBaseMs: integer(environment, \"OPENGENI_ARTIFACT_OUTBOX_RETRY_BASE_MS\", 500, 10, 60_000),\n retryMaxMs: integer(\n environment,\n \"OPENGENI_ARTIFACT_OUTBOX_RETRY_MAX_MS\",\n 60_000,\n 10,\n 86_400_000,\n ),\n } as const;\n if (result.leaseRenewIntervalMs >= result.leaseDurationMs) {\n throw new Error(\"OPENGENI_ARTIFACT_OUTBOX_RENEW_MS must be less than lease duration\");\n }\n if (result.retryBaseMs > result.retryMaxMs) {\n throw new Error(\"OPENGENI_ARTIFACT_OUTBOX_RETRY_BASE_MS must not exceed retry max\");\n }\n return Object.freeze(result);\n}\n\nexport async function createOutboxSidecarFromEnvironment(\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<Readonly<{ service: EditableArtifactOutboxService; httpPort: number }> | null> {\n const sidecar = readEditableArtifactOutboxSidecarEnvironment(environment);\n if (!sidecar) return null;\n const settings = getArtifactOutboxSettings(environment);\n const controlPlaneAuth = resolveNatsControlPlaneAuth(settings);\n const natsAuth: EditableArtifactHintNatsAuth = controlPlaneAuth\n ? {\n kind: \"user-password\",\n user: controlPlaneAuth.user,\n pass: controlPlaneAuth.password,\n }\n : { kind: \"anonymous\" };\n const service = await createProductionEditableArtifactOutboxService({\n settings,\n databaseUrl: sidecar.databaseUrl,\n declaredDatabaseRole: sidecar.declaredDatabaseRole,\n natsUrl: settings.natsUrl,\n natsAuth,\n owner: sidecar.owner,\n databasePoolSize: sidecar.databasePoolSize,\n batchSize: sidecar.batchSize,\n concurrency: sidecar.concurrency,\n leaseDurationMs: sidecar.leaseDurationMs,\n leaseRenewIntervalMs: sidecar.leaseRenewIntervalMs,\n pollIntervalMs: sidecar.pollIntervalMs,\n publishTimeoutMs: sidecar.publishTimeoutMs,\n retryBaseMs: sidecar.retryBaseMs,\n retryMaxMs: sidecar.retryMaxMs,\n });\n return Object.freeze({ service, httpPort: sidecar.httpPort });\n}\n\nasync function withTimeout<T>(\n promise: Promise<T>,\n milliseconds: number,\n abort: AbortController,\n): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n abort.abort();\n reject(new Error(\"readiness check timed out\"));\n }, milliseconds);\n }),\n ]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\nfunction required(environment: NodeJS.ProcessEnv, name: string): string {\n const value = environment[name]?.trim();\n if (!value) throw new Error(`${name} is required when artifact outbox dispatch is enabled`);\n return value;\n}\n\nfunction integer(\n environment: NodeJS.ProcessEnv,\n name: string,\n fallback: number,\n minimum: number,\n maximum: number,\n): number {\n const raw = environment[name];\n const value = raw === undefined ? fallback : Number(raw);\n if (!Number.isSafeInteger(value) || value < minimum || value > maximum) {\n throw new Error(`${name} is outside its allowed range`);\n }\n return value;\n}\n\n// Compile-time assurance that production composition satisfies the service port.\nconst _runtimePort: EditableArtifactOutboxRuntimePort | undefined = undefined as\n | EditableArtifactOutboxWorkerRuntime\n | undefined;\nvoid _runtimePort;\n","import {\n EditableArtifactLiveOutboxDispatcher,\n MathEditableArtifactOutboxRandom,\n SystemEditableArtifactLiveClock,\n SystemEditableArtifactLiveScheduler,\n type EditableArtifactOutboxDispatcherOptions,\n type EditableArtifactOutboxLoggerPort,\n type EditableArtifactOutboxMetricsPort,\n type EditableArtifactOutboxDispatcherStorePort,\n type EditableArtifactLiveOutboxRecord,\n} from \"@opengeni/core\";\nimport {\n PostgresEditableArtifactStore,\n createDb,\n dbSql,\n type Database,\n type DbClient,\n} from \"@opengeni/db\";\n\nimport {\n connectEditableArtifactHintBroker,\n type ConfirmedNatsEditableArtifactHintBroker,\n type EditableArtifactHintNatsAuth,\n} from \"./editable-artifact-hint-broker\";\n\nexport const EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE =\n \"opengeni_artifact_outbox_dispatcher\";\nexport const EDITABLE_ARTIFACT_OUTBOX_DATABASE_URL_ENV = \"OPENGENI_ARTIFACT_OUTBOX_DATABASE_URL\";\n\nexport type EditableArtifactOutboxWorkerOptions = Readonly<{\n /** Must authenticate as the dedicated dispatcher role, never the generic app role. */\n dispatcherDatabaseUrl: string;\n databaseSearchPath?: string;\n databasePoolSize?: number;\n natsUrl: string;\n natsAuth: EditableArtifactHintNatsAuth;\n owner?: string;\n dispatcher?: Omit<EditableArtifactOutboxDispatcherOptions, \"owner\">;\n metrics?: EditableArtifactOutboxMetricsPort;\n logger?: EditableArtifactOutboxLoggerPort;\n}>;\n\n/** Explicit lifecycle handle; hosts supervise `start()` and await `stop()` on drain. */\nexport class EditableArtifactOutboxWorkerRuntime {\n private readonly abort = new AbortController();\n private running: Promise<void> | null = null;\n private closing: Promise<void> | null = null;\n\n constructor(\n readonly dispatcher: EditableArtifactLiveOutboxDispatcher,\n private readonly broker: ConfirmedNatsEditableArtifactHintBroker,\n private readonly database: DbClient,\n ) {}\n\n start(): Promise<void> {\n if (this.closing) return Promise.reject(new Error(\"Artifact outbox worker is stopping\"));\n this.running ??= this.dispatcher.run(this.abort.signal);\n return this.running;\n }\n\n drain(): boolean {\n if (this.abort.signal.aborted) return false;\n this.abort.abort();\n return true;\n }\n\n async check(signal?: AbortSignal): Promise<void> {\n if (this.abort.signal.aborted || this.closing) {\n throw new Error(\"Artifact outbox worker is stopping\");\n }\n await Promise.all([\n assertDedicatedOutboxDispatcherDatabaseRole(this.database.db),\n this.broker.check(signal),\n ]);\n }\n\n stop(): Promise<void> {\n if (this.closing) return this.closing;\n this.closing = this.stopOnce();\n return this.closing;\n }\n\n private async stopOnce(): Promise<void> {\n this.drain();\n const running = this.running ? await Promise.allSettled([this.running]) : [];\n const cleanup = await Promise.allSettled([this.broker.close(), this.database.close()]);\n const failure = [...running, ...cleanup].find(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n if (failure) throw failure.reason;\n }\n}\n\n/**\n * Production composition. DB grants make the role a narrow capability: it can\n * execute only lease-fenced dispatcher functions and cannot read artifact rows.\n */\nexport async function createEditableArtifactOutboxWorker(\n options: EditableArtifactOutboxWorkerOptions,\n): Promise<EditableArtifactOutboxWorkerRuntime> {\n const dispatcherDatabaseUrl = dedicatedDispatcherDatabaseUrl(options.dispatcherDatabaseUrl);\n const databasePoolSize = options.databasePoolSize ?? 2;\n if (!Number.isSafeInteger(databasePoolSize) || databasePoolSize < 1 || databasePoolSize > 8) {\n throw new TypeError(\"Artifact outbox dispatcher DB pool size must be 1-8\");\n }\n const database = createDb(dispatcherDatabaseUrl, {\n max: databasePoolSize,\n ...(options.databaseSearchPath ? { searchPath: options.databaseSearchPath } : {}),\n });\n let broker: ConfirmedNatsEditableArtifactHintBroker;\n try {\n await assertDedicatedOutboxDispatcherDatabaseRole(database.db);\n broker = await connectEditableArtifactHintBroker({\n natsUrl: options.natsUrl,\n auth: options.natsAuth,\n });\n } catch (error) {\n await database.close();\n throw error;\n }\n const persistence = new PostgresEditableArtifactStore(database.db);\n const store = dispatcherStore(persistence);\n const dispatcher = new EditableArtifactLiveOutboxDispatcher(\n {\n store,\n broker,\n clock: new SystemEditableArtifactLiveClock(),\n scheduler: new SystemEditableArtifactLiveScheduler(),\n random: new MathEditableArtifactOutboxRandom(),\n ...(options.metrics ? { metrics: options.metrics } : {}),\n ...(options.logger ? { logger: options.logger } : {}),\n },\n {\n owner: options.owner ?? `artifact-outbox:${crypto.randomUUID()}`,\n ...options.dispatcher,\n },\n );\n return new EditableArtifactOutboxWorkerRuntime(dispatcher, broker, database);\n}\n\n/**\n * Verify the database identity and its negative capability at runtime. A DSN\n * username check alone is insufficient because PostgreSQL role inheritance,\n * SET ROLE, or a mis-provisioned grant could otherwise widen this worker.\n */\nexport async function assertDedicatedOutboxDispatcherDatabaseRole(db: Database): Promise<void> {\n const raw = await db.execute<{\n current_role: string;\n session_role: string;\n can_access_any_relation: boolean;\n can_access_any_sequence: boolean;\n }>(dbSql`\n select\n current_user::text as current_role,\n session_user::text as session_role,\n exists (\n select 1\n from pg_catalog.pg_class relation_row\n join pg_catalog.pg_namespace namespace_row\n on namespace_row.oid = relation_row.relnamespace\n where namespace_row.nspname = current_schema()\n and relation_row.relkind in ('r', 'p', 'v', 'm', 'f')\n and (\n has_table_privilege(current_user, relation_row.oid, 'SELECT')\n or has_table_privilege(current_user, relation_row.oid, 'INSERT')\n or has_table_privilege(current_user, relation_row.oid, 'UPDATE')\n or has_table_privilege(current_user, relation_row.oid, 'DELETE')\n or has_table_privilege(current_user, relation_row.oid, 'TRUNCATE')\n or has_table_privilege(current_user, relation_row.oid, 'REFERENCES')\n or has_table_privilege(current_user, relation_row.oid, 'TRIGGER')\n or has_any_column_privilege(current_user, relation_row.oid, 'SELECT')\n or has_any_column_privilege(current_user, relation_row.oid, 'INSERT')\n or has_any_column_privilege(current_user, relation_row.oid, 'UPDATE')\n or has_any_column_privilege(current_user, relation_row.oid, 'REFERENCES')\n )\n ) as can_access_any_relation,\n exists (\n select 1\n from pg_catalog.pg_class sequence_row\n join pg_catalog.pg_namespace namespace_row\n on namespace_row.oid = sequence_row.relnamespace\n where namespace_row.nspname = current_schema()\n and sequence_row.relkind = 'S'\n and (\n has_sequence_privilege(current_user, sequence_row.oid, 'USAGE')\n or has_sequence_privilege(current_user, sequence_row.oid, 'SELECT')\n or has_sequence_privilege(current_user, sequence_row.oid, 'UPDATE')\n )\n ) as can_access_any_sequence\n `);\n const rows = Array.isArray(raw) ? raw : ((raw as unknown as { rows?: unknown[] }).rows ?? []);\n const row = rows[0] as\n | {\n current_role?: unknown;\n session_role?: unknown;\n can_access_any_relation?: unknown;\n can_access_any_sequence?: unknown;\n }\n | undefined;\n if (\n row?.current_role !== EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE ||\n row.session_role !== EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE ||\n row.can_access_any_relation !== false ||\n row.can_access_any_sequence !== false\n ) {\n throw new Error(\"Artifact outbox dispatcher database connection has an unsafe role posture\");\n }\n}\n\nfunction dispatcherStore(\n persistence: PostgresEditableArtifactStore,\n): EditableArtifactOutboxDispatcherStorePort {\n return {\n claimLiveOutbox: async (input) =>\n (await persistence.claimLiveOutbox(\n input,\n )) as unknown as readonly EditableArtifactLiveOutboxRecord[],\n renewLiveOutbox: async (input) => await persistence.renewLiveOutbox(input),\n markLiveOutboxPublished: async (input) => await persistence.markLiveOutboxPublished(input),\n retryLiveOutbox: async (input) => await persistence.retryLiveOutbox(input),\n deadLetterLiveOutbox: async (input) => await persistence.deadLetterLiveOutbox(input),\n };\n}\n\nexport function dedicatedDispatcherDatabaseUrl(raw: string): string {\n if (typeof raw !== \"string\" || raw.length > 8_192 || raw.trim() !== raw) {\n throw new TypeError(`${EDITABLE_ARTIFACT_OUTBOX_DATABASE_URL_ENV} is malformed`);\n }\n let url: URL;\n try {\n url = new URL(raw);\n } catch (cause) {\n throw new TypeError(`${EDITABLE_ARTIFACT_OUTBOX_DATABASE_URL_ENV} is malformed`, { cause });\n }\n if (\n (url.protocol !== \"postgres:\" && url.protocol !== \"postgresql:\") ||\n decodeURIComponent(url.username) !== EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE\n ) {\n throw new TypeError(\n `${EDITABLE_ARTIFACT_OUTBOX_DATABASE_URL_ENV} must authenticate as ${EDITABLE_ARTIFACT_OUTBOX_DISPATCHER_DATABASE_ROLE}`,\n );\n }\n return raw;\n}\n","import {\n EDITABLE_ARTIFACT_HINT_MAX_BYTES,\n type EditableArtifactHintBrokerPort,\n} from \"@opengeni/core\";\nimport { connect, type NatsConnection } from \"@opengeni/events\";\n\nconst DEFAULT_CONNECTION_NAME = \"opengeni-editable-artifact-outbox\";\n\nexport type EditableArtifactHintNatsAuth =\n | Readonly<{ kind: \"user-password\"; user: string; pass: string }>\n | Readonly<{ kind: \"token\"; token: string }>\n | Readonly<{ kind: \"anonymous\" }>;\n\nexport type EditableArtifactHintNatsBrokerOptions = Readonly<{\n maxHintBytes?: number;\n}>;\n\nexport type EditableArtifactHintNatsConnection = Pick<\n NatsConnection,\n \"publish\" | \"flush\" | \"drain\" | \"close\" | \"closed\" | \"isClosed\" | \"isDraining\"\n>;\n\n/**\n * Core-NATS adapter for the durable outbox. A publish resolves only after a\n * server round-trip flush ACK. Reconnect buffering may create duplicates after\n * a timeout; hints are intentionally idempotent wakeups for durable gap-fill.\n */\nexport class ConfirmedNatsEditableArtifactHintBroker implements EditableArtifactHintBrokerPort {\n private readonly maxHintBytes: number;\n\n constructor(\n private readonly connection: EditableArtifactHintNatsConnection,\n options: EditableArtifactHintNatsBrokerOptions = {},\n ) {\n this.maxHintBytes = options.maxHintBytes ?? EDITABLE_ARTIFACT_HINT_MAX_BYTES;\n if (\n !Number.isSafeInteger(this.maxHintBytes) ||\n this.maxHintBytes < 1 ||\n this.maxHintBytes > EDITABLE_ARTIFACT_HINT_MAX_BYTES\n ) {\n throw new TypeError(\"Editable artifact NATS hint byte limit is invalid\");\n }\n }\n\n async publish(\n input: Readonly<{\n subject: string;\n payload: Uint8Array;\n signal: AbortSignal;\n }>,\n ): Promise<void> {\n assertSubject(input.subject);\n if (\n !(input.payload instanceof Uint8Array) ||\n input.payload.byteLength < 1 ||\n input.payload.byteLength > this.maxHintBytes\n ) {\n throw new EditableArtifactNatsHintPublishError(\n \"broker_backpressure\",\n \"Editable artifact hint exceeds the NATS envelope\",\n );\n }\n if (input.signal.aborted) throw abortedPublish();\n if (this.connection.isClosed() || this.connection.isDraining()) {\n throw new EditableArtifactNatsHintPublishError(\n \"broker_unavailable\",\n \"Editable artifact NATS connection is closed\",\n );\n }\n try {\n this.connection.publish(input.subject, input.payload);\n await abortable(this.connection.flush(), input.signal);\n } catch (error) {\n if (input.signal.aborted) throw abortedPublish();\n if (error instanceof EditableArtifactNatsHintPublishError) throw error;\n throw new EditableArtifactNatsHintPublishError(\n \"broker_unavailable\",\n \"Editable artifact NATS publish was not acknowledged\",\n { cause: error },\n );\n }\n }\n\n /**\n * A readiness probe must prove the server is reachable, not merely that the\n * client object has not observed closure yet. `flush()` is a bounded NATS\n * round trip and has the same acknowledgement semantics as publication.\n */\n async check(signal: AbortSignal = new AbortController().signal): Promise<void> {\n if (signal.aborted) throw abortedPublish();\n if (this.connection.isClosed() || this.connection.isDraining()) {\n throw new EditableArtifactNatsHintPublishError(\n \"broker_unavailable\",\n \"Editable artifact NATS connection is unavailable\",\n );\n }\n try {\n await abortable(this.connection.flush(), signal);\n } catch (error) {\n if (error instanceof EditableArtifactNatsHintPublishError) throw error;\n throw new EditableArtifactNatsHintPublishError(\n \"broker_unavailable\",\n \"Editable artifact NATS readiness round trip failed\",\n { cause: error },\n );\n }\n }\n\n async close(drainTimeoutMs = 5_000): Promise<void> {\n if (!Number.isSafeInteger(drainTimeoutMs) || drainTimeoutMs < 1 || drainTimeoutMs > 30_000) {\n throw new TypeError(\"Editable artifact NATS drain timeout is invalid\");\n }\n if (this.connection.isClosed()) return;\n if (this.connection.isDraining()) {\n await this.connection.closed();\n return;\n }\n let timer: ReturnType<typeof setTimeout> | undefined;\n const drain = this.connection.drain();\n const outcome = await Promise.race([\n drain.then(\n () => \"drained\" as const,\n () => \"failed\" as const,\n ),\n new Promise<\"timed_out\">((resolve) => {\n timer = setTimeout(() => resolve(\"timed_out\"), drainTimeoutMs);\n }),\n ]);\n if (timer) clearTimeout(timer);\n if (outcome !== \"drained\" && !this.connection.isClosed()) {\n await this.connection.close();\n }\n }\n}\n\nexport class EditableArtifactNatsHintPublishError extends Error {\n constructor(\n readonly code: \"broker_unavailable\" | \"broker_backpressure\",\n message: string,\n options?: ErrorOptions,\n ) {\n super(message, options);\n this.name = \"EditableArtifactNatsHintPublishError\";\n }\n}\n\n/** Opens one resilient dispatcher identity; callers own `broker.close()`. */\nexport async function connectEditableArtifactHintBroker(\n input: Readonly<{\n natsUrl: string;\n auth: EditableArtifactHintNatsAuth;\n name?: string;\n maxHintBytes?: number;\n }>,\n): Promise<ConfirmedNatsEditableArtifactHintBroker> {\n const natsUrl = boundedText(input.natsUrl, \"NATS URL\", 2_048);\n const name = boundedText(input.name ?? DEFAULT_CONNECTION_NAME, \"NATS connection name\", 128);\n const auth = natsAuthOptions(input.auth);\n const connection = await connect({\n servers: natsUrl,\n name,\n reconnect: true,\n maxReconnectAttempts: -1,\n // Same policy as the event bus: a broker or auth-callout restart must not\n // permanently close this connection after two identical auth errors.\n ignoreAuthErrorAbort: true,\n reconnectTimeWait: 2_000,\n reconnectJitter: 1_000,\n reconnectJitterTLS: 1_000,\n waitOnFirstConnect: true,\n pingInterval: 20_000,\n maxPingOut: 3,\n ...auth,\n });\n return new ConfirmedNatsEditableArtifactHintBroker(connection, {\n ...(input.maxHintBytes === undefined ? {} : { maxHintBytes: input.maxHintBytes }),\n });\n}\n\nfunction natsAuthOptions(auth: EditableArtifactHintNatsAuth): {\n user?: string;\n pass?: string;\n token?: string;\n} {\n if (auth.kind === \"anonymous\") return {};\n if (auth.kind === \"token\") return { token: boundedText(auth.token, \"NATS token\", 4_096) };\n return {\n user: boundedText(auth.user, \"NATS user\", 256),\n pass: boundedText(auth.pass, \"NATS password\", 4_096),\n };\n}\n\nfunction assertSubject(subject: string): void {\n const bytes = new TextEncoder().encode(subject).byteLength;\n if (\n bytes < 1 ||\n bytes > 1_024 ||\n subject.startsWith(\".\") ||\n subject.endsWith(\".\") ||\n subject.includes(\"..\") ||\n /[\\s*>]/u.test(subject)\n ) {\n throw new EditableArtifactNatsHintPublishError(\n \"broker_backpressure\",\n \"Editable artifact NATS subject is malformed\",\n );\n }\n}\n\nfunction boundedText(value: string, label: string, maxBytes: number): string {\n const bytes = new TextEncoder().encode(value).byteLength;\n if (bytes < 1 || bytes > maxBytes || value.trim() !== value) {\n throw new TypeError(`${label} is malformed`);\n }\n return value;\n}\n\nfunction abortedPublish(): EditableArtifactNatsHintPublishError {\n return new EditableArtifactNatsHintPublishError(\n \"broker_unavailable\",\n \"Editable artifact NATS publish was aborted\",\n );\n}\n\nasync function abortable(operation: Promise<void>, signal: AbortSignal): Promise<void> {\n if (signal.aborted) throw abortedPublish();\n let remove: () => void = () => undefined;\n const aborted = new Promise<never>((_resolve, reject) => {\n const onAbort = () => reject(abortedPublish());\n signal.addEventListener(\"abort\", onAbort, { once: true });\n remove = () => signal.removeEventListener(\"abort\", onAbort);\n });\n try {\n await Promise.race([operation, aborted]);\n } finally {\n remove();\n }\n}\n","import { createOutboxSidecarFromEnvironment } from \"./editable-artifact-outbox-service\";\n\n/** Dedicated process: no Temporal/control worker is created or imported here. */\nexport async function runEditableArtifactOutboxSidecar(\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<void> {\n const configured = await createOutboxSidecarFromEnvironment(environment);\n if (!configured) throw new Error(\"Editable artifact outbox sidecar is disabled\");\n const server = Bun.serve({\n hostname: \"0.0.0.0\",\n port: configured.httpPort,\n fetch: configured.service.fetch,\n });\n const stop = () => configured.service.drain(\"process signal\");\n process.on(\"SIGTERM\", stop);\n process.on(\"SIGINT\", stop);\n try {\n await configured.service.run();\n } finally {\n process.off(\"SIGTERM\", stop);\n process.off(\"SIGINT\", stop);\n server.stop(true);\n await configured.service.close();\n }\n}\n\nif (import.meta.main) {\n await runEditableArtifactOutboxSidecar();\n}\n"],"mappings":"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","names":[]}
@@ -1,10 +1,19 @@
1
1
  import {
2
- observabilityEventLogger
3
- } from "./chunk-I7HKKMUJ.js";
2
+ observabilityEventBusOptions
3
+ } from "./chunk-DSPP6CZL.js";
4
4
 
5
5
  // src/activity-services.ts
6
- import { dbSearchPath, getSettings, resolveNatsControlPlaneAuth } from "@opengeni/config";
7
- import { configureChildLifecycleNotices, createDb } from "@opengeni/db";
6
+ import {
7
+ codeSearchDeploymentPolicy,
8
+ dbSearchPath,
9
+ getSettings,
10
+ resolveNatsControlPlaneAuth
11
+ } from "@opengeni/config";
12
+ import {
13
+ configureChildLifecycleNotices,
14
+ configureCodeSearchDeploymentPolicy,
15
+ createDb
16
+ } from "@opengeni/db";
8
17
  import { createNatsEventBus } from "@opengeni/events";
9
18
  import { createObservability } from "@opengeni/observability";
10
19
  import { resolveCatalogSettings } from "@opengeni/core";
@@ -403,6 +412,7 @@ function createSharedActivityServices(dependencies) {
403
412
  const db = dependencies.db ?? dbClient.db;
404
413
  const resolvedSettings = (await resolveCatalogSettings(db, settings)).settings;
405
414
  configureChildLifecycleNotices({ enabled: settings.childLifecycleNoticesEnabled });
415
+ configureCodeSearchDeploymentPolicy(codeSearchDeploymentPolicy(settings));
406
416
  return {
407
417
  settings: resolvedSettings,
408
418
  catalogSourceSettings: settings,
@@ -410,7 +420,7 @@ function createSharedActivityServices(dependencies) {
410
420
  bus: dependencies.bus ?? await createNatsEventBus(
411
421
  settings.natsUrl,
412
422
  controlPlaneAuth ? { user: controlPlaneAuth.user, pass: controlPlaneAuth.password } : void 0,
413
- { logger: observabilityEventLogger(observability) }
423
+ observabilityEventBusOptions(observability)
414
424
  ),
415
425
  objectStorage: dependencies.objectStorage ?? createObjectStorage(settings),
416
426
  observability,
@@ -5049,7 +5059,8 @@ import {
5049
5059
  import {
5050
5060
  effectiveSandboxLifecycle,
5051
5061
  sandboxArchiveCaptureTimeoutMs,
5052
- sandboxLifecycleTransitionWaitMs
5062
+ sandboxLifecycleTransitionWaitMs,
5063
+ sandboxWarmRateMicrosPerSecond
5053
5064
  } from "@opengeni/config";
5054
5065
  import { randomUUID as randomUUID3 } from "crypto";
5055
5066
 
@@ -5190,6 +5201,42 @@ var SandboxSiblingWarmingTimeoutError = class extends SandboxWarmingTimeoutError
5190
5201
  this.name = "SandboxSiblingWarmingTimeoutError";
5191
5202
  }
5192
5203
  };
5204
+ var disposedUnreadyFreshSandboxErrors = /* @__PURE__ */ new WeakSet();
5205
+ function isReplaceableFreshSandboxReadinessTimeout(error) {
5206
+ return error instanceof SandboxExecReadinessTimeoutError && disposedUnreadyFreshSandboxErrors.has(error);
5207
+ }
5208
+ var FRESH_SANDBOX_READINESS_REPLACEMENT_BASE_DELAY_MS = 2e3;
5209
+ var FRESH_SANDBOX_READINESS_REPLACEMENT_JITTER_MS = 8e3;
5210
+ function freshSandboxReadinessReplacementDelayMs(random = Math.random) {
5211
+ const sample = random();
5212
+ const unit = Number.isFinite(sample) ? Math.min(Math.max(sample, 0), 1 - Number.EPSILON) : 0;
5213
+ return FRESH_SANDBOX_READINESS_REPLACEMENT_BASE_DELAY_MS + Math.floor(unit * FRESH_SANDBOX_READINESS_REPLACEMENT_JITTER_MS);
5214
+ }
5215
+ var FRESH_SANDBOX_READINESS_REPLACEMENTS_PER_TURN_ATTEMPT = 1;
5216
+ function createFreshSandboxReadinessReplacementBudget() {
5217
+ return { remaining: FRESH_SANDBOX_READINESS_REPLACEMENTS_PER_TURN_ATTEMPT };
5218
+ }
5219
+ function recordFreshSandboxReadinessReplacement(metrics, backend, outcome) {
5220
+ try {
5221
+ metrics?.onSandboxReadinessReplacement?.({ backend, outcome });
5222
+ } catch {
5223
+ }
5224
+ }
5225
+ async function sleepUnlessCancelled(ms, signal) {
5226
+ if (signal?.aborted) return false;
5227
+ if (ms <= 0) return true;
5228
+ return await new Promise((resolve) => {
5229
+ const onAbort = () => {
5230
+ clearTimeout(timer);
5231
+ resolve(false);
5232
+ };
5233
+ const timer = setTimeout(() => {
5234
+ signal?.removeEventListener("abort", onAbort);
5235
+ resolve(true);
5236
+ }, ms);
5237
+ signal?.addEventListener("abort", onAbort, { once: true });
5238
+ });
5239
+ }
5193
5240
  var SandboxLeaseInstanceLostError = class extends SandboxLeaseSupersededError {
5194
5241
  constructor(sandboxGroupId, leaseEpoch, lostInstanceId) {
5195
5242
  super(sandboxGroupId, leaseEpoch);
@@ -5639,6 +5686,69 @@ async function persistWarmWorkspaceSnapshot(services, ids, session, leaseEpoch,
5639
5686
  }
5640
5687
  }
5641
5688
  async function resumeBoxForTurn(services, ids, kind, holderId) {
5689
+ try {
5690
+ return await resumeBoxForTurnOnce(services, ids, kind, holderId);
5691
+ } catch (error) {
5692
+ if (!isReplaceableFreshSandboxReadinessTimeout(error)) throw error;
5693
+ const readiness = error;
5694
+ const warn = (message, fields) => {
5695
+ if (services.observability) services.observability.warn(message, fields);
5696
+ else console.warn(message, fields);
5697
+ };
5698
+ const identity = {
5699
+ workspaceId: ids.workspaceId,
5700
+ sessionId: ids.sessionId,
5701
+ sandboxGroupId: ids.sandboxGroupId,
5702
+ backend: readiness.backend,
5703
+ instanceId: readiness.instanceId,
5704
+ readinessTimeoutMs: readiness.timeoutMs
5705
+ };
5706
+ const budget = services.freshSandboxReadinessReplacementBudget ?? createFreshSandboxReadinessReplacementBudget();
5707
+ if (budget.remaining <= 0) {
5708
+ recordFreshSandboxReadinessReplacement(
5709
+ services.sandboxMetrics,
5710
+ readiness.backend,
5711
+ "budget_spent"
5712
+ );
5713
+ warn(
5714
+ "sandbox command-readiness timed out on a fresh box; this turn attempt already used its replacement",
5715
+ identity
5716
+ );
5717
+ throw error;
5718
+ }
5719
+ budget.remaining -= 1;
5720
+ const delayMs = await (services.freshSandboxReadinessReplacementDelayMs ?? freshSandboxReadinessReplacementDelayMs)();
5721
+ warn("sandbox command-readiness timed out on a fresh box; replacing it once after jitter", {
5722
+ ...identity,
5723
+ replacementDelayMs: delayMs
5724
+ });
5725
+ if (!await sleepUnlessCancelled(delayMs, services.cancellationSignal)) {
5726
+ recordFreshSandboxReadinessReplacement(
5727
+ services.sandboxMetrics,
5728
+ readiness.backend,
5729
+ "cancelled"
5730
+ );
5731
+ throw error;
5732
+ }
5733
+ try {
5734
+ const replaced = await resumeBoxForTurnOnce(services, ids, kind, holderId);
5735
+ recordFreshSandboxReadinessReplacement(
5736
+ services.sandboxMetrics,
5737
+ readiness.backend,
5738
+ "replaced"
5739
+ );
5740
+ return replaced;
5741
+ } catch (replacementError) {
5742
+ recordFreshSandboxReadinessReplacement(
5743
+ services.sandboxMetrics,
5744
+ readiness.backend,
5745
+ services.cancellationSignal?.aborted ? "cancelled" : replacementError instanceof SandboxExecReadinessTimeoutError ? "failed_again" : "replacement_failed"
5746
+ );
5747
+ throw replacementError;
5748
+ }
5749
+ }
5750
+ }
5751
+ async function resumeBoxForTurnOnce(services, ids, kind, holderId) {
5642
5752
  const { db, settings } = services;
5643
5753
  const os = ids.os ?? "linux";
5644
5754
  const leaseTtlMs = settings.sandboxLeaseTtlMs;
@@ -5711,6 +5821,10 @@ async function resumeBoxForTurn(services, ids, kind, holderId) {
5711
5821
  holderId,
5712
5822
  subjectId: ids.sessionId,
5713
5823
  backend: ids.backend,
5824
+ warmBilling: {
5825
+ mode: settings.sandboxWarmBillingMode,
5826
+ rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond(settings, ids.backend)
5827
+ },
5714
5828
  os,
5715
5829
  // IMAGE IS SHARED STATE (B3): thread the resolved image so the lease stamps it +
5716
5830
  // conflicts on a live box already running a different image. A
@@ -5795,7 +5909,8 @@ async function resumeBoxForTurn(services, ids, kind, holderId) {
5795
5909
  kind,
5796
5910
  holderId,
5797
5911
  expectedEpoch: heartbeat2.expectedEpoch,
5798
- leaseTtlMs: heartbeat2.leaseTtlMs
5912
+ leaseTtlMs: heartbeat2.leaseTtlMs,
5913
+ billingMode: services.settings.sandboxWarmBillingMode
5799
5914
  }).then(async (status) => {
5800
5915
  if (heartbeat2 !== holderLeaseHeartbeat) return;
5801
5916
  if (!status.holderAlive) {
@@ -6074,9 +6189,15 @@ async function resumeBoxForTurn(services, ids, kind, holderId) {
6074
6189
  });
6075
6190
  createdEstablished = established;
6076
6191
  throwIfReleasedOrCancelled();
6077
- await waitForSandboxExecReadiness(established, MODAL_EXEC_READINESS_TIMEOUT_MS, {
6078
- sandboxGroupId: ids.sandboxGroupId
6079
- });
6192
+ if (services.verifySpawnedSandboxReadiness) {
6193
+ await services.verifySpawnedSandboxReadiness(established, {
6194
+ sandboxGroupId: ids.sandboxGroupId
6195
+ });
6196
+ } else {
6197
+ await waitForSandboxExecReadiness(established, MODAL_EXEC_READINESS_TIMEOUT_MS, {
6198
+ sandboxGroupId: ids.sandboxGroupId
6199
+ });
6200
+ }
6080
6201
  await maybeRenewProviderExpiration(true);
6081
6202
  throwIfReleasedOrCancelled();
6082
6203
  const resumeEnvelope = requirePersistableReplacementSandboxEnvelope(
@@ -6170,6 +6291,9 @@ async function resumeBoxForTurn(services, ids, kind, holderId) {
6170
6291
  }
6171
6292
  await release();
6172
6293
  recordSandboxWarmingTimeout(services.sandboxMetrics, error);
6294
+ if (terminated && createdEstablished && error instanceof SandboxExecReadinessTimeoutError && error.instanceId === createdEstablished.instanceId && (createdEstablished.origin === "created" || createdEstablished.origin === "restored") && !createdEstablished.providerContinuity) {
6295
+ disposedUnreadyFreshSandboxErrors.add(error);
6296
+ }
6173
6297
  throw sandboxProvisionStageError(rematerialization ? "archive_recovery" : "create", error);
6174
6298
  }
6175
6299
  }
@@ -8685,10 +8809,14 @@ import {
8685
8809
  describeCompactionProviderRejection,
8686
8810
  isMcpRequestTimeoutError,
8687
8811
  isMcpTransportConnectivityError,
8688
- isModalTaskExecStartDnsResolutionError,
8812
+ isModalTaskExecStartPreDispatchUnavailableError,
8813
+ isRoutingMutationOutcomeUnknownError,
8689
8814
  RoutingWorkspaceRootChangedError,
8690
8815
  SandboxMaterializationVerificationError,
8691
8816
  materializationVerificationDiagnostic,
8817
+ PROVIDER_QUOTA_EXHAUSTED_CODE,
8818
+ classifyProviderQuotaError,
8819
+ providerQuotaExhaustedMessage,
8692
8820
  SelfhostedWorkspaceRootChangedError,
8693
8821
  UNKNOWN_MODEL_FINISH_REASON_CODE
8694
8822
  } from "@opengeni/runtime";
@@ -9206,6 +9334,7 @@ function sandboxFilePath(resource, file) {
9206
9334
 
9207
9335
  // src/activities/agent-turn/errors.ts
9208
9336
  import {
9337
+ CODEX_USAGE_LIMIT_ERROR_TYPE,
9209
9338
  CodexReloginRequired,
9210
9339
  classifyCodexEncryptedArtifactRejection,
9211
9340
  classifyCodexResponseTimeoutError,
@@ -9250,7 +9379,7 @@ function providerRecoveryResult(input) {
9250
9379
  };
9251
9380
  }
9252
9381
  const providerDelay = input.retryAfterMs !== null && input.retryAfterMs !== void 0 && Number.isFinite(input.retryAfterMs) && input.retryAfterMs > 0 ? Math.ceil(input.retryAfterMs) : null;
9253
- const continueDelayMs = input.failureCode === "provider_rate_limited" ? providerDelay ?? PROVIDER_BACKPRESSURE_DELAY_MS : input.failureCode === "provider_unavailable" || input.failureCode === "upstream_connectivity_unavailable" || input.failureCode === "sandbox_command_start_unavailable" || input.failureCode === "mcp_transport_timeout" || input.failureCode === "mcp_transport_unavailable" || input.failureCode === POST_COMPACTION_CONTINUATION_EMPTY_CODE ? Math.max(
9382
+ const continueDelayMs = input.failureCode === "provider_rate_limited" ? providerDelay ?? PROVIDER_BACKPRESSURE_DELAY_MS : input.failureCode === "provider_unavailable" || input.failureCode === "upstream_connectivity_unavailable" || input.failureCode === "sandbox_command_start_unavailable" || input.failureCode === "mcp_transport_timeout" || input.failureCode === "mcp_transport_unavailable" || input.failureCode === "turn_execution_policy_definition_mismatch" || input.failureCode === POST_COMPACTION_CONTINUATION_EMPTY_CODE ? Math.max(
9254
9383
  providerDelay ?? 0,
9255
9384
  PROVIDER_CONNECTIVITY_BACKOFF_MS[Math.min(
9256
9385
  Math.max(Math.trunc(input.attemptNumber) - 1, 0),
@@ -9489,6 +9618,12 @@ function compactionFailureReasonFromError(error) {
9489
9618
  `the model provider rejected the compaction request (${describeCompactionProviderRejection(rejection)}). Active history was preserved. ${COMPACTION_PROVIDER_REJECTION_GUIDANCE}`
9490
9619
  );
9491
9620
  }
9621
+ const quota = classifyProviderQuotaExhaustionError(error);
9622
+ if (quota) {
9623
+ return compactionFailureReason(
9624
+ `${providerQuotaExhaustedMessage(quota.scope)} Active history was preserved.`
9625
+ );
9626
+ }
9492
9627
  if (error instanceof CompactionProviderResponseError || error instanceof EmptyCompactionSummaryError) {
9493
9628
  return compactionFailureReason(error.message);
9494
9629
  }
@@ -9497,13 +9632,15 @@ function compactionFailureReasonFromError(error) {
9497
9632
  }
9498
9633
  function compactionFailureTurnEventPayload(error, overrides = {}) {
9499
9634
  const rejection = compactionProviderRejection(error);
9635
+ const quota = rejection ? null : classifyProviderQuotaExhaustionError(error);
9500
9636
  return {
9501
9637
  error: overrides.error ?? compactionFailureReasonFromError(error),
9502
9638
  code: "context_compaction_failed",
9503
9639
  retryable: false,
9504
9640
  recovery: "user_message",
9505
9641
  compacted: false,
9506
- ...rejection ? { providerRejection: rejection } : {}
9642
+ ...rejection ? { providerRejection: rejection } : {},
9643
+ ...quota ? { quotaScope: quota.scope } : {}
9507
9644
  };
9508
9645
  }
9509
9646
  function isCompactionSummaryFailure(error) {
@@ -9607,6 +9744,13 @@ function isTransientProviderError(error) {
9607
9744
  message
9608
9745
  );
9609
9746
  }
9747
+ function hasCodexUsageLimitType(error) {
9748
+ return collectErrorStrings(error).some((value) => value.includes(CODEX_USAGE_LIMIT_ERROR_TYPE));
9749
+ }
9750
+ function classifyProviderQuotaExhaustionError(error) {
9751
+ if (isCodexTransportError(error) || isXaiSubscriptionTransportError(error)) return null;
9752
+ return classifyProviderQuotaError(error);
9753
+ }
9610
9754
  function classifyXaiCredentialFailure(error) {
9611
9755
  if (isProviderSafetyRefusal(error)) return null;
9612
9756
  let relogin = error;
@@ -9724,9 +9868,9 @@ function baseAgentRunFailurePayload(error, options = {}) {
9724
9868
  retryable: true
9725
9869
  };
9726
9870
  }
9727
- if (isModalTaskExecStartDnsResolutionError(error)) {
9871
+ if (!isRoutingMutationOutcomeUnknownError(error) && isModalTaskExecStartPreDispatchUnavailableError(error)) {
9728
9872
  return {
9729
- error: "The managed sandbox command transport was temporarily unreachable before the command started. The same turn will retry after a short delay.",
9873
+ error: "The managed sandbox command router was not ready before the command was sent. The same turn will retry after a short delay.",
9730
9874
  code: "sandbox_command_start_unavailable",
9731
9875
  retryable: true
9732
9876
  };
@@ -9783,7 +9927,7 @@ function baseAgentRunFailurePayload(error, options = {}) {
9783
9927
  };
9784
9928
  }
9785
9929
  const usageLimit = classifyCodexUsageLimitError(error);
9786
- if (usageLimit) {
9930
+ if (usageLimit && (isCodexTransportError(error) || hasCodexUsageLimitType(error))) {
9787
9931
  return codexUsageLimitFailurePayload(usageLimit, message);
9788
9932
  }
9789
9933
  const codexTimeout = classifyCodexResponseTimeoutError(error, {
@@ -9828,6 +9972,16 @@ function baseAgentRunFailurePayload(error, options = {}) {
9828
9972
  retryable: true
9829
9973
  };
9830
9974
  }
9975
+ const quota = classifyProviderQuotaExhaustionError(error);
9976
+ if (quota) {
9977
+ return {
9978
+ error: providerQuotaExhaustedMessage(quota.scope),
9979
+ code: PROVIDER_QUOTA_EXHAUSTED_CODE,
9980
+ retryable: false,
9981
+ quotaScope: quota.scope,
9982
+ ...message ? { detail: message } : {}
9983
+ };
9984
+ }
9831
9985
  if (status === 429 || code === "rate_limit_exceeded" || /(?:too many requests|rate.?limit|\b429\b)/i.test(message)) {
9832
9986
  return {
9833
9987
  error: "Model provider rate limit hit. Try again in a minute or lower the reasoning effort.",
@@ -9983,6 +10137,7 @@ export {
9983
10137
  persistWorkspaceArchiveCandidate,
9984
10138
  putVersion1TarArchiveOrInline,
9985
10139
  sandboxLeaseHolderIdForAttempt,
10140
+ createFreshSandboxReadinessReplacementBudget,
9986
10141
  waitForWarmSnapshot,
9987
10142
  maybePersistWarmWorkspaceSnapshot,
9988
10143
  resumeBoxForTurn,
@@ -10064,4 +10219,4 @@ export {
10064
10219
  codexUsageLimitFailurePayload,
10065
10220
  CODEX_USAGE_LIMIT_MAX_RESUME_MS
10066
10221
  };
10067
- //# sourceMappingURL=chunk-M3NVMF2V.js.map
10222
+ //# sourceMappingURL=chunk-7M6G2SCF.js.map