theokit 0.12.0 → 0.13.0

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 (131) hide show
  1. package/dist/{actions-virtual-module-SQDY3V5X.js → actions-virtual-module-3CDQTWOC.js} +6 -6
  2. package/dist/{actions-virtual-module-PNPRCEOS.js → actions-virtual-module-EIPXX4ZB.js} +3 -3
  3. package/dist/adapters/web-shim.d.ts +67 -0
  4. package/dist/adapters/ws-shim.d.ts +55 -0
  5. package/dist/agent-events-DosDXkSV.d.ts +94 -0
  6. package/dist/agents-typed-client-SAWAAH7K.js +142 -0
  7. package/dist/agents-typed-client-SAWAAH7K.js.map +1 -0
  8. package/dist/agents-typed-client-UTEQUA63.js +143 -0
  9. package/dist/agents-typed-client-UTEQUA63.js.map +1 -0
  10. package/dist/{app-typed-client-5GYEOYP3.js → app-typed-client-7PBFWZUE.js} +3 -3
  11. package/dist/{app-typed-client-QG7BVZYW.js → app-typed-client-CSOK7NPC.js} +6 -6
  12. package/dist/audit-log-BQWM5YLG.d.ts +60 -0
  13. package/dist/body-parser-web-FV5HWCY3.js +71 -0
  14. package/dist/body-parser-web-FV5HWCY3.js.map +1 -0
  15. package/dist/boot/index.d.ts +39 -0
  16. package/dist/{build-QFRLSEZ4.js → build-HXND27XG.js} +11 -11
  17. package/dist/{chunk-223EFY5X.js → chunk-2J7XU3PW.js} +68 -27
  18. package/dist/chunk-2J7XU3PW.js.map +1 -0
  19. package/dist/{chunk-RESN62GB.js → chunk-2KZQPDYR.js} +5 -48
  20. package/dist/chunk-2KZQPDYR.js.map +1 -0
  21. package/dist/chunk-3S3BNW5K.js +445 -0
  22. package/dist/chunk-3S3BNW5K.js.map +1 -0
  23. package/dist/{chunk-6FYD34NX.js → chunk-BQDGES7C.js} +28 -28
  24. package/dist/{chunk-6FYD34NX.js.map → chunk-BQDGES7C.js.map} +1 -1
  25. package/dist/chunk-EXP56GFQ.js +52 -0
  26. package/dist/chunk-EXP56GFQ.js.map +1 -0
  27. package/dist/chunk-F4YUPDJ2.js +115 -0
  28. package/dist/chunk-F4YUPDJ2.js.map +1 -0
  29. package/dist/{chunk-NAZ4E2GT.js → chunk-KXA37ONC.js} +2 -2
  30. package/dist/chunk-NHJMZCAS.js +32 -0
  31. package/dist/chunk-NHJMZCAS.js.map +1 -0
  32. package/dist/{chunk-43D6XNDR.js → chunk-O62MW4MT.js} +91 -18
  33. package/dist/chunk-O62MW4MT.js.map +1 -0
  34. package/dist/chunk-RSVN727G.js +1 -0
  35. package/dist/{chunk-7CBRKNQA.js → chunk-RYTZYFSD.js} +198 -6
  36. package/dist/chunk-RYTZYFSD.js.map +1 -0
  37. package/dist/chunk-UNLA45FY.js +235 -0
  38. package/dist/chunk-UNLA45FY.js.map +1 -0
  39. package/dist/{chunk-GFMQJHXX.js → chunk-WR4F4EEZ.js} +1082 -1074
  40. package/dist/chunk-WR4F4EEZ.js.map +1 -0
  41. package/dist/{chunk-AD74EAK3.js → chunk-ZSTZXR2D.js} +1 -30
  42. package/dist/chunk-ZSTZXR2D.js.map +1 -0
  43. package/dist/cli/index.js +5 -5
  44. package/dist/client/index.d.ts +418 -0
  45. package/dist/client/index.js +84 -3
  46. package/dist/client/index.js.map +1 -1
  47. package/dist/csrf-BBrEZSBW.d.ts +107 -0
  48. package/dist/csrf-readiness-store-CjIoub3U.d.ts +43 -0
  49. package/dist/define-websocket-CdK94O-D.d.ts +64 -0
  50. package/dist/{dev-GBXOTXUP.js → dev-OWW4XVIH.js} +10 -10
  51. package/dist/{dev-emit-FEFEDLZF.js → dev-emit-5MDSBP5D.js} +3 -3
  52. package/dist/{dev-emit-O4EGOSNV.js → dev-emit-QH2YGZXN.js} +2 -2
  53. package/dist/devtools/entry.d.ts +5 -0
  54. package/dist/error-envelope-BsNzzAV5.d.ts +62 -0
  55. package/dist/health-route-C0hk64_U.d.ts +57 -0
  56. package/dist/index-B40qUSrQ.d.ts +575 -0
  57. package/dist/index.d.ts +361 -0
  58. package/dist/index.js +6 -4
  59. package/dist/index.js.map +1 -1
  60. package/dist/internal-api-4YTJDITC.js +83 -0
  61. package/dist/internal-api-EFKZWIYZ.js +66 -0
  62. package/dist/internal-api-EFKZWIYZ.js.map +1 -0
  63. package/dist/job-backend-CgC8Xf33.d.ts +68 -0
  64. package/dist/match-CfbEFRG4.d.ts +26 -0
  65. package/dist/{openapi-VR6AFBLJ.js → openapi-FHY6HC6I.js} +7 -7
  66. package/dist/plugin-runner-BGBkzgi0.d.ts +95 -0
  67. package/dist/plugin-types-DNJGxr4Z.d.ts +79 -0
  68. package/dist/rate-limit-BdNDZ3vt.d.ts +58 -0
  69. package/dist/rate-limit-store-BEJnhWdw.d.ts +72 -0
  70. package/dist/react-query/index.d.ts +33 -0
  71. package/dist/{registry-Q2TZQLUH.js → registry-34LL7NF4.js} +1 -1
  72. package/dist/{routes-LRYOIIAI.js → routes-EW7TP7NJ.js} +2 -2
  73. package/dist/schema-BpH6ivDY.d.ts +74 -0
  74. package/dist/server/agent/index.d.ts +229 -0
  75. package/dist/server/agent/index.js +2 -1
  76. package/dist/server/auth/index.d.ts +419 -0
  77. package/dist/server/cost/index.d.ts +177 -0
  78. package/dist/server/cron/index.d.ts +208 -0
  79. package/dist/server/define/index.d.ts +313 -0
  80. package/dist/server/define/index.js +4 -2
  81. package/dist/server/http/index.d.ts +11 -0
  82. package/dist/server/index.d.ts +848 -0
  83. package/dist/server/index.js +9 -294
  84. package/dist/server/index.js.map +1 -1
  85. package/dist/server/jobs/index.d.ts +348 -0
  86. package/dist/server/observability/index.d.ts +324 -0
  87. package/dist/server/plugins/index.d.ts +17 -0
  88. package/dist/server/rate-limit/index.d.ts +105 -0
  89. package/dist/server/realtime/index.d.ts +15 -0
  90. package/dist/server/scan/index.d.ts +126 -0
  91. package/dist/server/scan/index.js +1 -1
  92. package/dist/server/security/index.d.ts +193 -0
  93. package/dist/server/storage/index.d.ts +22 -0
  94. package/dist/server/webhook/index.d.ts +148 -0
  95. package/dist/{start-3ZHAXSJE.js → start-KIQ5TTLR.js} +76 -13
  96. package/dist/start-KIQ5TTLR.js.map +1 -0
  97. package/dist/storage-manager-C4jsO0Tp.d.ts +89 -0
  98. package/dist/storage-types-DsDTCPbp.d.ts +96 -0
  99. package/dist/vite-plugin/index.d.ts +115 -0
  100. package/dist/vite-plugin/index.js +6 -4
  101. package/dist/{vite-plugin-WO72VLYR.js → vite-plugin-RK66K26Z.js} +7 -7
  102. package/dist/vite-plugin-RK66K26Z.js.map +1 -0
  103. package/package.json +4 -4
  104. package/dist/chunk-223EFY5X.js.map +0 -1
  105. package/dist/chunk-3LVRAGAZ.js +0 -73
  106. package/dist/chunk-3LVRAGAZ.js.map +0 -1
  107. package/dist/chunk-43D6XNDR.js.map +0 -1
  108. package/dist/chunk-7CBRKNQA.js.map +0 -1
  109. package/dist/chunk-AD74EAK3.js.map +0 -1
  110. package/dist/chunk-GFMQJHXX.js.map +0 -1
  111. package/dist/chunk-PBEH6NXR.js +0 -44
  112. package/dist/chunk-PBEH6NXR.js.map +0 -1
  113. package/dist/chunk-PIVX3DYW.js +0 -142
  114. package/dist/chunk-PIVX3DYW.js.map +0 -1
  115. package/dist/chunk-PPPR5DGR.js +0 -1
  116. package/dist/chunk-RESN62GB.js.map +0 -1
  117. package/dist/start-3ZHAXSJE.js.map +0 -1
  118. /package/dist/{actions-virtual-module-SQDY3V5X.js.map → actions-virtual-module-3CDQTWOC.js.map} +0 -0
  119. /package/dist/{actions-virtual-module-PNPRCEOS.js.map → actions-virtual-module-EIPXX4ZB.js.map} +0 -0
  120. /package/dist/{app-typed-client-5GYEOYP3.js.map → app-typed-client-7PBFWZUE.js.map} +0 -0
  121. /package/dist/{app-typed-client-QG7BVZYW.js.map → app-typed-client-CSOK7NPC.js.map} +0 -0
  122. /package/dist/{build-QFRLSEZ4.js.map → build-HXND27XG.js.map} +0 -0
  123. /package/dist/{chunk-NAZ4E2GT.js.map → chunk-KXA37ONC.js.map} +0 -0
  124. /package/dist/{chunk-PPPR5DGR.js.map → chunk-RSVN727G.js.map} +0 -0
  125. /package/dist/{dev-GBXOTXUP.js.map → dev-OWW4XVIH.js.map} +0 -0
  126. /package/dist/{dev-emit-FEFEDLZF.js.map → dev-emit-5MDSBP5D.js.map} +0 -0
  127. /package/dist/{dev-emit-O4EGOSNV.js.map → dev-emit-QH2YGZXN.js.map} +0 -0
  128. /package/dist/{vite-plugin-WO72VLYR.js.map → internal-api-4YTJDITC.js.map} +0 -0
  129. /package/dist/{openapi-VR6AFBLJ.js.map → openapi-FHY6HC6I.js.map} +0 -0
  130. /package/dist/{registry-Q2TZQLUH.js.map → registry-34LL7NF4.js.map} +0 -0
  131. /package/dist/{routes-LRYOIIAI.js.map → routes-EW7TP7NJ.js.map} +0 -0
@@ -0,0 +1,348 @@
1
+ import { J as JobBackend, a as JobEnqueueInput, b as JobLease } from '../../job-backend-CgC8Xf33.js';
2
+ export { N as NonRetryableError } from '../../job-backend-CgC8Xf33.js';
3
+ import { S as StorageManager, P as PostgresFactory } from '../../storage-manager-C4jsO0Tp.js';
4
+ import { a as PoolLike } from '../../storage-types-DsDTCPbp.js';
5
+
6
+ /**
7
+ * Job primitive types (R0.5.5-9).
8
+ *
9
+ * @see docs/adr/0002-job-backend-interface-neutral-contract.md
10
+ * @see docs/adr/0003-enqueue-returns-void-transactional-outbox.md
11
+ */
12
+ /**
13
+ * Type registry for jobs. Users extend via module augmentation:
14
+ *
15
+ * ```ts
16
+ * declare module 'theokit/server' {
17
+ * interface JobRegistry {
18
+ * 'process-document': { documentId: string }
19
+ * 'send-email': { to: string; subject: string }
20
+ * }
21
+ * }
22
+ * ```
23
+ *
24
+ * Once augmented, `ctx.queue.enqueue<'process-document'>(...)` gets full
25
+ * type inference on the `input` argument.
26
+ */
27
+ interface JobRegistry {
28
+ }
29
+ interface JobContext<TInput = unknown> {
30
+ /** W3C trace_id propagated from the originating request or cron. */
31
+ readonly traceId: string;
32
+ /** The job's input, type-narrowed per JobRegistry entry. */
33
+ readonly input: TInput;
34
+ /** Abort signal triggered when the worker stops or lease times out. */
35
+ readonly signal: AbortSignal;
36
+ /** Attempt number (1-indexed). */
37
+ readonly attempt: number;
38
+ }
39
+ interface JobOptions<TInput = unknown> {
40
+ /** Optional Zod schema (or any `.parse(value)`-shaped object) for input validation. */
41
+ input?: {
42
+ parse: (value: unknown) => TInput;
43
+ };
44
+ /** Maximum dispatch attempts (default 1 — no retry surprise per ADR-0003). */
45
+ maxAttempts?: number;
46
+ /** Handler. Returns `void` per ADR-0003 — no workflow API. */
47
+ handler: (ctx: JobContext<TInput>) => Promise<void> | void;
48
+ }
49
+ interface JobDefinition<TInput = unknown> {
50
+ readonly name: string;
51
+ readonly maxAttempts: number;
52
+ readonly hasInputSchema: boolean;
53
+ readonly handler: (ctx: JobContext<TInput>) => Promise<void> | void;
54
+ readonly inputSchema?: {
55
+ parse: (value: unknown) => TInput;
56
+ };
57
+ }
58
+
59
+ /**
60
+ * Declare a background job. Pure identity helper — no registration side
61
+ * effect; the build-time scanner (T2.3) discovers definitions by walking
62
+ * `server/jobs/` and emits `.theokit/jobs.json`.
63
+ *
64
+ * Per ADR-0003, handler returns `void` (or `Promise<void>`); no workflow
65
+ * API. To run another job after this one, call `ctx.queue.enqueue` from
66
+ * the handler.
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * // server/jobs/process-document.ts
71
+ * import { defineJob } from 'theokit/server'
72
+ * import { z } from 'zod'
73
+ *
74
+ * export default defineJob('process-document', {
75
+ * input: z.object({ documentId: z.string() }),
76
+ * maxAttempts: 3,
77
+ * async handler({ input, traceId }) {
78
+ * // process input.documentId
79
+ * },
80
+ * })
81
+ * ```
82
+ */
83
+ declare function defineJob<TInput = unknown>(name: string, options: JobOptions<TInput>): JobDefinition<TInput>;
84
+
85
+ /**
86
+ * Thrown when a plugin or middleware decorates `ctx.<key>` with a value
87
+ * that the framework would also like to inject (e.g., `ctx.queue` from
88
+ * the jobs backend wiring).
89
+ *
90
+ * Per EC-202 of system-100-percent-functional-plan: silent override is a
91
+ * latent bug class. Fail loud so the conflict surfaces immediately.
92
+ */
93
+ declare class DuplicateContextKeyError extends Error {
94
+ readonly key: string;
95
+ readonly code = "DUPLICATE_CONTEXT_KEY";
96
+ constructor(key: string, opts?: {
97
+ reason?: string;
98
+ });
99
+ }
100
+
101
+ /**
102
+ * In-memory job backend for dev + tests + single-instance prototypes.
103
+ *
104
+ * Zero external dependencies. Storage is two Maps:
105
+ * - `pending: Map<jobId, PendingEntry>` — all enqueued jobs (locked or not)
106
+ * - `idempotencyMap: Map<key, { jobId; expiresAt }>` — dedup window
107
+ *
108
+ * Per ADR-0002: this is one of two first-party backends shipped in core.
109
+ * Production deploys plug in PostgresJobBackend (T3.1).
110
+ *
111
+ * EC-104 (jobs-crons-webhooks-cost-tracking-plan): registers a
112
+ * `process.on('beforeExit')` handler that clears pending dispatch timers
113
+ * and logs a warning with the dropped count. Failure mode is visible,
114
+ * not silent. `destroy()` removes the listener for test isolation.
115
+ */
116
+ interface InMemoryJobBackendOptions {
117
+ /** Maximum pending entries before oldest is dropped + warning logged. */
118
+ maxPending?: number;
119
+ }
120
+ declare class InMemoryJobBackend implements JobBackend {
121
+ #private;
122
+ readonly name = "memory";
123
+ constructor(opts?: InMemoryJobBackendOptions);
124
+ enqueue(input: JobEnqueueInput): Promise<{
125
+ jobId: string;
126
+ }>;
127
+ dequeue(opts: {
128
+ batchSize?: number;
129
+ lockSeconds?: number;
130
+ }): Promise<JobLease[]>;
131
+ ack(jobId: string): Promise<void>;
132
+ nack(jobId: string, opts: {
133
+ error: string;
134
+ nonRetryable?: boolean;
135
+ }): Promise<void>;
136
+ idempotency(key: string, ttlSeconds: number): Promise<{
137
+ jobId: string;
138
+ } | null>;
139
+ /**
140
+ * Remove the beforeExit listener and clear all pending timers.
141
+ * Idempotent — safe to call multiple times. Use in test teardown to
142
+ * avoid leaking listeners across vitest test files.
143
+ */
144
+ destroy(): void;
145
+ /** EC-104 test hook — invokes the shutdown handler synchronously. */
146
+ triggerBeforeExitForTest(): void;
147
+ }
148
+
149
+ interface PostgresJobBackendOptions {
150
+ pool: PoolLike;
151
+ /** Table name override (default `theokit_jobs`). */
152
+ tableName?: string;
153
+ }
154
+ declare class PostgresJobBackend implements JobBackend {
155
+ #private;
156
+ readonly name = "postgres";
157
+ constructor(opts: PostgresJobBackendOptions);
158
+ /**
159
+ * T2.1 — Construct a `PostgresJobBackend` using a pool managed by the
160
+ * shared `StorageManager`. The manager caches the pool per `dbName`, so
161
+ * repeated calls (in the same process) re-use the same connection pool.
162
+ *
163
+ * Equivalent to:
164
+ * ```ts
165
+ * const pool = manager.usePostgres(dbName, factory)
166
+ * new PostgresJobBackend({ pool, ...options })
167
+ * ```
168
+ *
169
+ * Errors thrown by the manager (unknown dbName, dangling server reference,
170
+ * manager already disposed) propagate to the caller with actionable text.
171
+ *
172
+ * @see ADR-0007
173
+ */
174
+ static fromStorageManager(manager: StorageManager, dbName: string, factory: PostgresFactory, options?: Omit<PostgresJobBackendOptions, 'pool'>): PostgresJobBackend;
175
+ /**
176
+ * Create or upgrade the schema. Idempotent (uses IF NOT EXISTS).
177
+ * Call once at process start; safe to re-run on every deploy.
178
+ */
179
+ migrate(): Promise<void>;
180
+ enqueue(input: JobEnqueueInput): Promise<{
181
+ jobId: string;
182
+ }>;
183
+ dequeue(opts: {
184
+ batchSize?: number;
185
+ lockSeconds?: number;
186
+ }): Promise<JobLease[]>;
187
+ ack(jobId: string): Promise<void>;
188
+ nack(jobId: string, opts: {
189
+ error: string;
190
+ nonRetryable?: boolean;
191
+ }): Promise<void>;
192
+ idempotency(key: string, _ttlSeconds: number): Promise<{
193
+ jobId: string;
194
+ } | null>;
195
+ }
196
+
197
+ /**
198
+ * Transactional outbox buffer for `ctx.queue.enqueue` (T2.5).
199
+ *
200
+ * Lifecycle (wired in `http/execute.ts` by T2.5 integration step):
201
+ * 1. Request handler invoked → create per-request outbox.
202
+ * 2. Handler calls `ctx.queue.enqueue(...)` → outbox.push(entry).
203
+ * 3a. Response committed (`res.on('finish')` + statusCode < 400) →
204
+ * outbox.flush(backend.enqueue).
205
+ * 3b. Response errors (statusCode >= 400, handler throws, `res.on('close')`
206
+ * without finish) → outbox.discard().
207
+ *
208
+ * Invariants:
209
+ * - Outbox NEVER dispatches before commit. Backend.enqueue is NEVER
210
+ * called on the request hot path.
211
+ * - Handler throws → ZERO jobs dispatched. KEY guarantee from ADR-0003.
212
+ *
213
+ * EC-107: when `backend.enqueue` throws DURING flush (after response
214
+ * committed), we log + continue. The response is already gone; partial
215
+ * dispatch is better than zero. Each failure goes to `onError` (default:
216
+ * `console.warn`).
217
+ */
218
+ interface OutboxFlushOptions {
219
+ /**
220
+ * Called once per failed entry. Default: `console.warn` with the
221
+ * entry name (NOT input — privacy). Throw nothing back to caller —
222
+ * flush always completes.
223
+ */
224
+ onError?: (entryName: string, errorMessage: string) => void;
225
+ }
226
+ interface Outbox {
227
+ push(entry: JobEnqueueInput): void;
228
+ drain(): JobEnqueueInput[];
229
+ discard(): void;
230
+ size(): number;
231
+ /**
232
+ * Dispatch all buffered entries via `dispatcher`. Returns after all
233
+ * entries attempted. Per-entry failures invoke `opts.onError` (or
234
+ * default warn) and do NOT abort the loop.
235
+ */
236
+ flush(dispatcher: (entry: JobEnqueueInput) => Promise<unknown>, opts?: OutboxFlushOptions): Promise<void>;
237
+ }
238
+ declare function createOutbox(): Outbox;
239
+
240
+ /**
241
+ * Options forwarded to `backend.enqueue` at outbox flush time.
242
+ */
243
+ interface EnqueueOptions {
244
+ /** Optional idempotency key for at-most-once dispatch within TTL. */
245
+ idempotencyKey?: string;
246
+ /** Optional delay before the job becomes available. */
247
+ delaySeconds?: number;
248
+ }
249
+ /**
250
+ * Typed queue client. Per ADR-0003, `enqueue` returns `void` and buffers
251
+ * to the per-request outbox. `enqueueWithId` is the log-correlation
252
+ * variant that resolves to `{ jobId }` AFTER the outbox flushes.
253
+ *
254
+ * Type inference: `JobName extends keyof JobRegistry`. Users extend the
255
+ * `JobRegistry` interface via module augmentation (see `job-types.ts`).
256
+ * Without augmentation, all enqueue calls compile-error with "Type X is
257
+ * not assignable to type never" — documented in EC-110 as a known onboarding
258
+ * friction.
259
+ */
260
+ interface QueueClient {
261
+ /** Buffer a job to the outbox. Returns void (fire-and-forget). */
262
+ enqueue<JobName extends keyof JobRegistry>(name: JobName, input: JobRegistry[JobName], opts?: EnqueueOptions): void;
263
+ /**
264
+ * Buffer a job AND return a Promise that resolves with the jobId
265
+ * AFTER the outbox flushes (i.e., after the response commits). NOT a
266
+ * handle to await the job result — there is no result API.
267
+ */
268
+ enqueueWithId<JobName extends keyof JobRegistry>(name: JobName, input: JobRegistry[JobName], opts?: EnqueueOptions): Promise<{
269
+ jobId: string;
270
+ }>;
271
+ }
272
+ interface CreateQueueClientOptions {
273
+ /** W3C traceparent to propagate to enqueued jobs. */
274
+ traceparent?: string;
275
+ }
276
+ /**
277
+ * Create a per-request queue client wired to a backend + outbox.
278
+ *
279
+ * The backend is referenced only to resolve `enqueueWithId` jobIds at
280
+ * flush time — `enqueue` itself does NOT call backend on the hot path
281
+ * (transactional outbox guarantee per ADR-0003).
282
+ */
283
+ declare function createQueueClient(backend: JobBackend, outbox: Outbox, opts?: CreateQueueClientOptions): QueueClient;
284
+ /**
285
+ * Outbox dispatcher that bridges enqueueWithId's hidden promise channel
286
+ * (`__resolveJobId` / `__rejectJobId`) to the backend.enqueue result.
287
+ *
288
+ * Use this when the request lifecycle hooks call `outbox.flush(...)`.
289
+ */
290
+ declare function createOutboxDispatcher(backend: JobBackend): (entry: JobEnqueueInput) => Promise<unknown>;
291
+
292
+ /**
293
+ * Job runner — pulls leases from a backend and invokes the matching
294
+ * handler. Each invocation wires up `JobContext` with:
295
+ * - `traceId` extracted from the lease's `traceparent` header (W3C
296
+ * Trace Context per R0.5.9), OR a fresh generated trace_id when
297
+ * the upstream had no traceparent OR it was malformed.
298
+ * - `attempt` from the lease.
299
+ * - `signal` that aborts when the lease times out.
300
+ *
301
+ * `tick()` runs one dequeue+dispatch cycle and returns when all leases
302
+ * have been ack'd or nack'd. Production deploys call `tick()` in a loop
303
+ * with backoff (the loop is outside this module's scope).
304
+ *
305
+ * EC-6 (trace continuity edge): when a lease has no traceparent OR a
306
+ * malformed one, the handler still gets a valid traceId (generated) —
307
+ * never null/undefined. The job MAY itself enqueue child jobs that
308
+ * continue the new trace_id.
309
+ */
310
+ interface JobRunner {
311
+ /** Run one dequeue+dispatch cycle. */
312
+ tick(opts?: {
313
+ batchSize?: number;
314
+ lockSeconds?: number;
315
+ }): Promise<number>;
316
+ }
317
+ declare function createJobRunner(backend: JobBackend, definitions: readonly JobDefinition[]): JobRunner;
318
+
319
+ interface JobNode {
320
+ readonly name: string;
321
+ readonly filePath: string;
322
+ readonly maxAttempts: number;
323
+ readonly hasInputSchema: boolean;
324
+ }
325
+ declare class DuplicateJobNameError extends Error {
326
+ readonly jobName: string;
327
+ readonly filePaths: readonly string[];
328
+ readonly code = "DUPLICATE_JOB_NAME";
329
+ constructor(jobName: string, filePaths: readonly string[]);
330
+ }
331
+ declare function scanJobs(jobsDir: string): Promise<JobNode[]>;
332
+
333
+ declare const JOB_MANIFEST_SCHEMA_VERSION: 1;
334
+ interface JobManifestEntry {
335
+ readonly name: string;
336
+ readonly filePath: string;
337
+ readonly maxAttempts: number;
338
+ readonly hasInputSchema: boolean;
339
+ }
340
+ interface JobManifest {
341
+ readonly schemaVersion: typeof JOB_MANIFEST_SCHEMA_VERSION;
342
+ readonly generatedAt: string;
343
+ readonly jobs: readonly JobManifestEntry[];
344
+ }
345
+ declare function buildJobManifest(nodes: readonly JobNode[], projectRoot?: string): JobManifest;
346
+ declare function writeJobManifest(path: string, input: readonly JobNode[] | JobManifest, projectRoot?: string): void;
347
+
348
+ export { DuplicateContextKeyError, DuplicateJobNameError, type EnqueueOptions, InMemoryJobBackend, type InMemoryJobBackendOptions, JOB_MANIFEST_SCHEMA_VERSION, JobBackend, type JobContext, type JobDefinition, JobEnqueueInput, JobLease, type JobManifest, type JobManifestEntry, type JobNode, type JobOptions, type JobRegistry, type JobRunner, type Outbox, type OutboxFlushOptions, PoolLike, PostgresJobBackend, type PostgresJobBackendOptions, type QueueClient, buildJobManifest, createJobRunner, createOutbox, createOutboxDispatcher, createQueueClient, defineJob, scanJobs, writeJobManifest };
@@ -0,0 +1,324 @@
1
+ export { a as AuditEvent, A as AuditLogger, J as JsonStdoutSink, c as createNoOpLogger, s as safeAudit } from '../../audit-log-BQWM5YLG.js';
2
+ import { IncomingMessage } from 'node:http';
3
+
4
+ /**
5
+ * Request log primitive (T6.2 of architecture-review-remediation-plan).
6
+ *
7
+ * Split out from `logger.ts` per PV-12 (SRP) — the file previously mixed
8
+ * 3 concerns (factory, warnOnce, request log). This module owns ONLY the
9
+ * `logRequest` flow + the devtools broadcast best-effort forwarder.
10
+ *
11
+ * Public API surface is unchanged — `logger.ts` re-exports `logRequest`
12
+ * + `RequestLog` + `LoggerFn` for backward compat.
13
+ */
14
+
15
+ interface RequestLog {
16
+ level: string;
17
+ method: string;
18
+ url: string;
19
+ status: number;
20
+ duration: number;
21
+ requestId: string;
22
+ timestamp: string;
23
+ }
24
+ type LoggerFn = (log: RequestLog) => void;
25
+ declare function logRequest(info: Omit<RequestLog, 'level' | 'timestamp'>, customLogger?: LoggerFn, req?: IncomingMessage): void;
26
+
27
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
28
+ interface StructuredLog {
29
+ level: string;
30
+ msg: string;
31
+ timestamp: string;
32
+ [key: string]: unknown;
33
+ }
34
+ interface TheoLogger {
35
+ debug(msg: string, context?: Record<string, unknown>): void;
36
+ info(msg: string, context?: Record<string, unknown>): void;
37
+ warn(msg: string, context?: Record<string, unknown>): void;
38
+ error(msg: string, context?: Record<string, unknown>): void;
39
+ child(context: Record<string, unknown>): TheoLogger;
40
+ }
41
+ declare function createLogger(options?: {
42
+ level?: LogLevel;
43
+ output?: (log: StructuredLog) => void;
44
+ context?: Record<string, unknown>;
45
+ }): TheoLogger;
46
+ /**
47
+ * Reset internal state. Test-only export — do not call from production.
48
+ */
49
+ declare function _resetWarnOnceForTests(): void;
50
+ /**
51
+ * Emit a structured warning ONCE per key. Subsequent calls with the same
52
+ * key are suppressed. Used for cutover-style warnings (e.g. CSRF warn)
53
+ * that would otherwise flood logs under load.
54
+ *
55
+ * Convention: key is `<event>:<method>:<path>` — see callers in csrf.ts.
56
+ *
57
+ * EC-2: payload may contain circular references. Wrap `JSON.stringify`
58
+ * in try/catch so a malformed payload doesn't crash the request handler.
59
+ */
60
+ declare function warnOnce(key: string, payload: Record<string, unknown>): void;
61
+
62
+ declare function levenshtein(a: string, b: string): number;
63
+ declare function findSuggestion(input: string, candidates: string[], maxDistance?: number): string | null;
64
+
65
+ /**
66
+ * ObservabilityAdapter — interface contract for all observability backends.
67
+ *
68
+ * Per ADR D455: framework adapter owns request/response spans.
69
+ * SDK adapter owns agent/tool/LLM spans. Both can emit to the same backend.
70
+ *
71
+ * Per ADR D456: implementations can be lightweight (50 LoC OTLP serializer)
72
+ * or full OTel SDK wrappers via defineObservabilityAdapter().
73
+ */
74
+ interface SpanAttributes {
75
+ [key: string]: string | number | boolean | undefined;
76
+ }
77
+ /** Handle to an active span — setAttribute, setStatus, end. */
78
+ interface SpanHandle {
79
+ /** Set a key-value attribute on this span. */
80
+ setAttribute(key: string, value: string | number | boolean): void;
81
+ /** Set the span's status (ok, error). */
82
+ setStatus(status: 'ok' | 'error', message?: string): void;
83
+ /** End the span (records duration). Idempotent — second call is a no-op. */
84
+ end(): void;
85
+ }
86
+ /** Core adapter interface. Every observability backend implements this. */
87
+ interface ObservabilityAdapter {
88
+ /** Human-readable adapter name (e.g., 'console', 'theo-cloud', 'noop'). */
89
+ readonly name: string;
90
+ /** Start a new span. Returns a handle to set attributes and end it. */
91
+ startSpan(name: string, attributes?: SpanAttributes): SpanHandle;
92
+ /** Increment a counter metric. */
93
+ counter(name: string, value: number, attributes?: SpanAttributes): void;
94
+ /** Record a histogram value (e.g., duration, size). */
95
+ histogram(name: string, value: number, attributes?: SpanAttributes): void;
96
+ /** Emit a structured log. */
97
+ log(level: 'debug' | 'info' | 'warn' | 'error', message: string, attributes?: SpanAttributes): void;
98
+ /** Flush any buffered telemetry (async — may involve I/O). */
99
+ flush(): Promise<void>;
100
+ /** Shutdown the adapter (flush + release resources). Idempotent. */
101
+ shutdown(): Promise<void>;
102
+ }
103
+
104
+ /**
105
+ * NoopObservabilityAdapter — silent fallback.
106
+ *
107
+ * All methods are no-ops. Never throws, never blocks.
108
+ * Used as the default when no other adapter is configured.
109
+ * EC-2: startSpan after shutdown returns a noop span (no crash).
110
+ */
111
+
112
+ declare class NoopObservabilityAdapter implements ObservabilityAdapter {
113
+ readonly name = "noop";
114
+ private isShutdown;
115
+ startSpan(_name: string, _attributes?: SpanAttributes): SpanHandle;
116
+ counter(_name: string, _value: number, _attributes?: SpanAttributes): void;
117
+ histogram(_name: string, _value: number, _attributes?: SpanAttributes): void;
118
+ log(_level: 'debug' | 'info' | 'warn' | 'error', _message: string, _attributes?: SpanAttributes): void;
119
+ flush(): Promise<void>;
120
+ shutdown(): Promise<void>;
121
+ }
122
+
123
+ /**
124
+ * ConsoleObservabilityAdapter — dev-mode console output.
125
+ *
126
+ * Emits JSON-structured lines to a configurable writer (default: process.stderr).
127
+ * Inspired by Hono middleware timing pattern.
128
+ */
129
+
130
+ interface ConsoleAdapterOptions {
131
+ /** Writer function — defaults to process.stderr.write. */
132
+ write?: (line: string) => void;
133
+ }
134
+ declare class ConsoleObservabilityAdapter implements ObservabilityAdapter {
135
+ readonly name = "console";
136
+ private write;
137
+ private isShutdown;
138
+ private spans;
139
+ constructor(options?: ConsoleAdapterOptions);
140
+ startSpan(name: string, attributes?: SpanAttributes): SpanHandle;
141
+ counter(name: string, value: number, attributes?: SpanAttributes): void;
142
+ histogram(name: string, value: number, attributes?: SpanAttributes): void;
143
+ log(level: 'debug' | 'info' | 'warn' | 'error', message: string, attributes?: SpanAttributes): void;
144
+ flush(): Promise<void>;
145
+ shutdown(): Promise<void>;
146
+ private emitSpan;
147
+ private emit;
148
+ }
149
+
150
+ /**
151
+ * TheoCloudObservabilityAdapter — OTLP/HTTP batched export for TheoCloud.
152
+ *
153
+ * Zero-config via env vars (THEO_CLOUD_INGEST_URL, THEO_CLOUD_API_KEY).
154
+ * Batches spans and flushes via native fetch() POST.
155
+ *
156
+ * EC-1: flush failure logs warning, does NOT throw, does NOT retry (KISS).
157
+ * EC-2: startSpan after shutdown returns noop span.
158
+ */
159
+
160
+ interface TheoCloudAdapterOptions {
161
+ /** TheoCloud ingest endpoint URL. */
162
+ ingestUrl: string;
163
+ /** TheoCloud API key for authentication. */
164
+ token: string;
165
+ /** Flush interval in ms (default: 5000). */
166
+ flushIntervalMs?: number;
167
+ /** Mock fetch for testing (never in production). */
168
+ _mockFetch?: typeof globalThis.fetch;
169
+ }
170
+ declare class TheoCloudObservabilityAdapter implements ObservabilityAdapter {
171
+ readonly name = "theo-cloud";
172
+ private pendingSpans;
173
+ private isShutdown;
174
+ private readonly opts;
175
+ constructor(options: TheoCloudAdapterOptions);
176
+ startSpan(name: string, attributes?: SpanAttributes): SpanHandle;
177
+ counter(_name: string, _value: number, _attributes?: SpanAttributes): void;
178
+ histogram(_name: string, _value: number, _attributes?: SpanAttributes): void;
179
+ log(_level: 'debug' | 'info' | 'warn' | 'error', _message: string, _attributes?: SpanAttributes): void;
180
+ flush(): Promise<void>;
181
+ shutdown(): Promise<void>;
182
+ }
183
+
184
+ /**
185
+ * Adapter registry — resolves the active observability adapter.
186
+ *
187
+ * Per ADR D457 (v1.1) priority chain:
188
+ * 1. Explicit config (theo.config.ts observability.provider) — ALWAYS wins
189
+ * 2. THEO_CLOUD_INGEST_URL env → theo-cloud adapter
190
+ * 3. NODE_ENV=development → console adapter
191
+ * 4. Fallback → noop adapter
192
+ */
193
+
194
+ interface ResolveAdapterOptions {
195
+ env: Record<string, string | undefined>;
196
+ config?: {
197
+ provider?: ObservabilityAdapter;
198
+ };
199
+ }
200
+ /**
201
+ * Resolve the observability adapter from config + env.
202
+ * Called once at boot — returns the active adapter for the process lifetime.
203
+ */
204
+ declare function resolveAdapter(options: ResolveAdapterOptions): ObservabilityAdapter;
205
+
206
+ /**
207
+ * Auto-instrumentation middleware — creates spans for every HTTP request.
208
+ *
209
+ * Registers as a standard TheoKit plugin via existing hook system.
210
+ * No changes to plugin-runner needed.
211
+ *
212
+ * Per blueprint Pattern 2 (Hono middleware timing):
213
+ * - onRequest: start span with method + path
214
+ * - onResponse: end span with status + duration
215
+ * - onError: set span status to error
216
+ */
217
+
218
+ interface PluginContext {
219
+ requestId: string;
220
+ request: {
221
+ method: string;
222
+ url: string;
223
+ };
224
+ response?: {
225
+ statusCode: number;
226
+ };
227
+ }
228
+ interface ObservabilityPlugin {
229
+ name: string;
230
+ onRequest(ctx: PluginContext): Promise<void>;
231
+ onResponse(ctx: PluginContext): Promise<void>;
232
+ onError(ctx: PluginContext & {
233
+ error: unknown;
234
+ }): Promise<void>;
235
+ }
236
+ /**
237
+ * Create an observability plugin that auto-instruments HTTP requests.
238
+ *
239
+ * EC-5: For SSE responses, span ends on response close, not headers sent.
240
+ * The caller should invoke onResponse when the stream actually closes.
241
+ */
242
+ declare function createObservabilityPlugin(adapter: ObservabilityAdapter): ObservabilityPlugin;
243
+
244
+ /**
245
+ * defineObservabilityAdapter() — public API for custom adapters.
246
+ *
247
+ * The escape hatch for self-host users who want Datadog, Grafana, Honeycomb, etc.
248
+ * Validates the adapter shape and returns a typed ObservabilityAdapter.
249
+ *
250
+ * @example
251
+ * ```ts
252
+ * const datadogAdapter = defineObservabilityAdapter({
253
+ * name: 'datadog',
254
+ * startSpan: (name, attrs) => { ... },
255
+ * counter: (name, value) => { ... },
256
+ * histogram: (name, value) => { ... },
257
+ * log: (level, message) => { ... },
258
+ * flush: async () => { ... },
259
+ * shutdown: async () => { ... },
260
+ * })
261
+ *
262
+ * // theo.config.ts
263
+ * export default defineConfig({
264
+ * observability: { provider: datadogAdapter },
265
+ * })
266
+ * ```
267
+ */
268
+
269
+ interface DefineAdapterConfig {
270
+ name: string;
271
+ startSpan(name: string, attributes?: SpanAttributes): SpanHandle;
272
+ counter(name: string, value: number, attributes?: SpanAttributes): void;
273
+ histogram(name: string, value: number, attributes?: SpanAttributes): void;
274
+ log(level: 'debug' | 'info' | 'warn' | 'error', message: string, attributes?: SpanAttributes): void;
275
+ flush(): Promise<void>;
276
+ shutdown(): Promise<void>;
277
+ }
278
+ declare function defineObservabilityAdapter(config: DefineAdapterConfig): ObservabilityAdapter;
279
+
280
+ /**
281
+ * SpanHandle implementation — records timing + attributes.
282
+ *
283
+ * Used by console and theo-cloud adapters. Noop adapter uses NoopSpan.
284
+ */
285
+
286
+ interface SpanData {
287
+ name: string;
288
+ attributes: Record<string, string | number | boolean>;
289
+ status: 'ok' | 'error';
290
+ statusMessage?: string;
291
+ startTimeMs: number;
292
+ endTimeMs?: number;
293
+ durationMs?: number;
294
+ }
295
+ declare class SpanImpl implements SpanHandle {
296
+ private readonly data;
297
+ private ended;
298
+ constructor(name: string, attributes?: SpanAttributes);
299
+ setAttribute(key: string, value: string | number | boolean): void;
300
+ setStatus(status: 'ok' | 'error', message?: string): void;
301
+ end(): void;
302
+ /** Read-only access to span data (for adapters to export). */
303
+ getData(): SpanData;
304
+ isEnded(): boolean;
305
+ }
306
+ /** Noop span — used by NoopAdapter and post-shutdown fallback (EC-2). */
307
+ declare class NoopSpan implements SpanHandle {
308
+ setAttribute(): void;
309
+ setStatus(): void;
310
+ end(): void;
311
+ }
312
+
313
+ /**
314
+ * Lightweight OTLP JSON serializer — ~50 LoC, no @opentelemetry/* dependency.
315
+ *
316
+ * Per ADR D456: in-house serializer for the theo-cloud adapter.
317
+ * Produces valid ExportTraceServiceRequest JSON (OTLP v1.0).
318
+ * Pinned to OTLP JSON v1.0 (stable since 2023).
319
+ */
320
+
321
+ /** Convert SpanData[] to OTLP JSON bytes (Uint8Array). */
322
+ declare function serializeSpansToOtlp(spans: SpanData[], serviceName?: string): Uint8Array;
323
+
324
+ export { ConsoleObservabilityAdapter, type LogLevel, type LoggerFn, NoopObservabilityAdapter, NoopSpan, type ObservabilityAdapter, type RequestLog, type SpanAttributes, type SpanHandle, SpanImpl, type StructuredLog, TheoCloudObservabilityAdapter, type TheoLogger, _resetWarnOnceForTests, createLogger, createObservabilityPlugin, defineObservabilityAdapter, findSuggestion, levenshtein, logRequest, resolveAdapter, serializeSpansToOtlp, warnOnce };
@@ -0,0 +1,17 @@
1
+ import { P as PluginRunner } from '../../plugin-runner-BGBkzgi0.js';
2
+ export { D as DuplicateDecorationError, a as DuplicatePluginError } from '../../plugin-runner-BGBkzgi0.js';
3
+ import '../../plugin-types-DNJGxr4Z.js';
4
+ import 'node:http';
5
+
6
+ declare class InvalidPluginShapeError extends Error {
7
+ constructor(index: number, reason: string);
8
+ }
9
+ /**
10
+ * Build a PluginRunner from a list of plugins typically declared in
11
+ * `theo.config.ts` under the `plugins` field. Returns `undefined` when no
12
+ * plugins are configured so callers can pass `undefined` to `executeRoute`
13
+ * and preserve the zero-overhead path.
14
+ */
15
+ declare function createPluginRunnerFromConfig(plugins: unknown): Promise<PluginRunner | undefined>;
16
+
17
+ export { InvalidPluginShapeError, PluginRunner, createPluginRunnerFromConfig };