@beignet/core 0.0.32 → 0.0.34

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 (139) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +409 -34
  3. package/dist/application/index.d.ts.map +1 -1
  4. package/dist/application/index.js +63 -47
  5. package/dist/application/index.js.map +1 -1
  6. package/dist/contracts/contract-builder.d.ts +0 -4
  7. package/dist/contracts/contract-builder.d.ts.map +1 -1
  8. package/dist/contracts/contract-builder.js +0 -6
  9. package/dist/contracts/contract-builder.js.map +1 -1
  10. package/dist/events/index.d.ts +6 -0
  11. package/dist/events/index.d.ts.map +1 -1
  12. package/dist/events/index.js +20 -10
  13. package/dist/events/index.js.map +1 -1
  14. package/dist/flags/index.d.ts +0 -4
  15. package/dist/flags/index.d.ts.map +1 -1
  16. package/dist/flags/index.js +0 -4
  17. package/dist/flags/index.js.map +1 -1
  18. package/dist/jobs/index.d.ts +415 -4
  19. package/dist/jobs/index.d.ts.map +1 -1
  20. package/dist/jobs/index.js +392 -3
  21. package/dist/jobs/index.js.map +1 -1
  22. package/dist/notifications/index.d.ts +194 -10
  23. package/dist/notifications/index.d.ts.map +1 -1
  24. package/dist/notifications/index.js +397 -59
  25. package/dist/notifications/index.js.map +1 -1
  26. package/dist/outbox/index.d.ts +150 -1
  27. package/dist/outbox/index.d.ts.map +1 -1
  28. package/dist/outbox/index.js +170 -1
  29. package/dist/outbox/index.js.map +1 -1
  30. package/dist/ports/events.d.ts +2 -2
  31. package/dist/ports/index.d.ts +7 -2
  32. package/dist/ports/index.d.ts.map +1 -1
  33. package/dist/ports/index.js +2 -1
  34. package/dist/ports/index.js.map +1 -1
  35. package/dist/providers/instrumentation.d.ts +4 -0
  36. package/dist/providers/instrumentation.d.ts.map +1 -1
  37. package/dist/providers/instrumentation.js.map +1 -1
  38. package/dist/providers/provider.d.ts +1 -1
  39. package/dist/schedules/index.d.ts +8 -7
  40. package/dist/schedules/index.d.ts.map +1 -1
  41. package/dist/schedules/index.js +47 -16
  42. package/dist/schedules/index.js.map +1 -1
  43. package/dist/server/hooks/index.d.ts +1 -0
  44. package/dist/server/hooks/index.d.ts.map +1 -1
  45. package/dist/server/hooks/index.js +1 -0
  46. package/dist/server/hooks/index.js.map +1 -1
  47. package/dist/server/hooks/rate-limit.d.ts +26 -13
  48. package/dist/server/hooks/rate-limit.d.ts.map +1 -1
  49. package/dist/server/hooks/rate-limit.js +28 -34
  50. package/dist/server/hooks/rate-limit.js.map +1 -1
  51. package/dist/server/hooks/security.d.ts +179 -0
  52. package/dist/server/hooks/security.d.ts.map +1 -0
  53. package/dist/server/hooks/security.js +225 -0
  54. package/dist/server/hooks/security.js.map +1 -0
  55. package/dist/server/index.d.ts +8 -0
  56. package/dist/server/index.d.ts.map +1 -1
  57. package/dist/server/index.js +8 -0
  58. package/dist/server/index.js.map +1 -1
  59. package/dist/server/instrumentation.d.ts.map +1 -1
  60. package/dist/server/instrumentation.js +22 -6
  61. package/dist/server/instrumentation.js.map +1 -1
  62. package/dist/server/request-context.d.ts +4 -0
  63. package/dist/server/request-context.d.ts.map +1 -1
  64. package/dist/server/request-context.js +3 -0
  65. package/dist/server/request-context.js.map +1 -1
  66. package/dist/server/runtime-integrity.d.ts +84 -0
  67. package/dist/server/runtime-integrity.d.ts.map +1 -0
  68. package/dist/server/runtime-integrity.js +160 -0
  69. package/dist/server/runtime-integrity.js.map +1 -0
  70. package/dist/server/server.d.ts +10 -10
  71. package/dist/server/server.d.ts.map +1 -1
  72. package/dist/server/server.js +75 -11
  73. package/dist/server/server.js.map +1 -1
  74. package/dist/server/trusted-proxy.d.ts +77 -0
  75. package/dist/server/trusted-proxy.d.ts.map +1 -0
  76. package/dist/server/trusted-proxy.js +129 -0
  77. package/dist/server/trusted-proxy.js.map +1 -0
  78. package/dist/tasks/index.d.ts +6 -7
  79. package/dist/tasks/index.d.ts.map +1 -1
  80. package/dist/tasks/index.js +22 -5
  81. package/dist/tasks/index.js.map +1 -1
  82. package/dist/tenancy/index.d.ts +41 -0
  83. package/dist/tenancy/index.d.ts.map +1 -0
  84. package/dist/tenancy/index.js +34 -0
  85. package/dist/tenancy/index.js.map +1 -0
  86. package/dist/testing/index.d.ts +1 -1
  87. package/dist/testing/index.d.ts.map +1 -1
  88. package/dist/testing/index.js +1 -0
  89. package/dist/testing/index.js.map +1 -1
  90. package/dist/tracing/execution.d.ts +14 -0
  91. package/dist/tracing/execution.d.ts.map +1 -0
  92. package/dist/tracing/execution.js +17 -0
  93. package/dist/tracing/execution.js.map +1 -0
  94. package/dist/tracing/index.d.ts +49 -0
  95. package/dist/tracing/index.d.ts.map +1 -1
  96. package/dist/tracing/index.js +59 -0
  97. package/dist/tracing/index.js.map +1 -1
  98. package/dist/uploads/client.d.ts.map +1 -1
  99. package/dist/uploads/client.js +44 -6
  100. package/dist/uploads/client.js.map +1 -1
  101. package/dist/uploads/index.d.ts +71 -0
  102. package/dist/uploads/index.d.ts.map +1 -1
  103. package/dist/uploads/index.js +344 -15
  104. package/dist/uploads/index.js.map +1 -1
  105. package/dist/webhooks/index.d.ts +55 -4
  106. package/dist/webhooks/index.d.ts.map +1 -1
  107. package/dist/webhooks/index.js +106 -2
  108. package/dist/webhooks/index.js.map +1 -1
  109. package/package.json +5 -5
  110. package/skills/app-architecture/SKILL.md +31 -2
  111. package/src/application/index.ts +88 -56
  112. package/src/contracts/contract-builder.ts +0 -7
  113. package/src/events/index.ts +27 -14
  114. package/src/flags/index.ts +0 -5
  115. package/src/jobs/index.ts +895 -7
  116. package/src/notifications/index.ts +678 -70
  117. package/src/outbox/index.ts +358 -2
  118. package/src/ports/events.ts +2 -2
  119. package/src/ports/index.ts +17 -1
  120. package/src/providers/instrumentation.ts +4 -0
  121. package/src/providers/provider.ts +1 -1
  122. package/src/schedules/index.ts +60 -26
  123. package/src/server/hooks/index.ts +10 -0
  124. package/src/server/hooks/rate-limit.ts +52 -46
  125. package/src/server/hooks/security.ts +503 -0
  126. package/src/server/index.ts +8 -0
  127. package/src/server/instrumentation.ts +25 -5
  128. package/src/server/request-context.ts +7 -0
  129. package/src/server/runtime-integrity.ts +322 -0
  130. package/src/server/server.ts +88 -35
  131. package/src/server/trusted-proxy.ts +249 -0
  132. package/src/tasks/index.ts +29 -12
  133. package/src/tenancy/index.ts +55 -0
  134. package/src/testing/index.ts +2 -0
  135. package/src/tracing/execution.ts +37 -0
  136. package/src/tracing/index.ts +137 -0
  137. package/src/uploads/client.ts +65 -6
  138. package/src/uploads/index.ts +539 -14
  139. package/src/webhooks/index.ts +238 -9
@@ -269,6 +269,116 @@ export interface OutboxMarkFailedInput {
269
269
  now?: Date;
270
270
  }
271
271
 
272
+ /**
273
+ * Default maximum messages returned from outbox admin list calls.
274
+ */
275
+ export const DEFAULT_OUTBOX_ADMIN_LIST_LIMIT = 50;
276
+
277
+ /**
278
+ * Shared filters for outbox admin read operations.
279
+ */
280
+ export interface OutboxMessageQuery {
281
+ /**
282
+ * Status or statuses to include.
283
+ */
284
+ status?: OutboxMessageStatus | readonly OutboxMessageStatus[];
285
+ /**
286
+ * Message kind to include.
287
+ */
288
+ kind?: OutboxMessageKind;
289
+ /**
290
+ * Event or job name to include.
291
+ */
292
+ name?: string;
293
+ /**
294
+ * Include messages last updated before this timestamp.
295
+ */
296
+ updatedBefore?: Date;
297
+ /**
298
+ * Include delivered messages delivered before this timestamp.
299
+ */
300
+ deliveredBefore?: Date;
301
+ }
302
+
303
+ /**
304
+ * Options for listing outbox messages through the admin port.
305
+ */
306
+ export interface OutboxListMessagesOptions extends OutboxMessageQuery {
307
+ /**
308
+ * Maximum messages to return. Defaults to
309
+ * `DEFAULT_OUTBOX_ADMIN_LIST_LIMIT`.
310
+ */
311
+ limit?: number;
312
+ }
313
+
314
+ /**
315
+ * Options for counting outbox messages through the admin port.
316
+ */
317
+ export interface OutboxCountMessagesOptions extends OutboxMessageQuery {}
318
+
319
+ /**
320
+ * Input for returning a dead-lettered message to the pending queue.
321
+ */
322
+ export interface OutboxRequeueMessageInput {
323
+ /**
324
+ * Dead-lettered message ID.
325
+ */
326
+ id: string;
327
+ /**
328
+ * Earliest time the message may be claimed again. Defaults to `now`.
329
+ */
330
+ availableAt?: Date;
331
+ /**
332
+ * Reset attempts to zero before requeueing. Defaults to preserving the
333
+ * attempt count so operators can decide whether to grant a fresh retry
334
+ * budget.
335
+ */
336
+ resetAttempts?: boolean;
337
+ /**
338
+ * Requeue timestamp.
339
+ */
340
+ now?: Date;
341
+ }
342
+
343
+ /**
344
+ * Input for purging dead-lettered messages.
345
+ */
346
+ export interface OutboxPurgeDeadLetteredInput {
347
+ /**
348
+ * Only purge messages last updated before this timestamp. Omit only when the
349
+ * caller intentionally wants to purge all dead-lettered messages.
350
+ */
351
+ before?: Date;
352
+ /**
353
+ * Maximum messages to purge.
354
+ */
355
+ limit?: number;
356
+ }
357
+
358
+ /**
359
+ * Input for pruning delivered messages.
360
+ */
361
+ export interface OutboxPruneDeliveredInput {
362
+ /**
363
+ * Prune delivered messages delivered before this timestamp.
364
+ */
365
+ before: Date;
366
+ /**
367
+ * Maximum messages to prune.
368
+ */
369
+ limit?: number;
370
+ }
371
+
372
+ /**
373
+ * Result for outbox admin delete operations.
374
+ */
375
+ export interface OutboxDeleteResult {
376
+ /**
377
+ * Number of rows deleted.
378
+ */
379
+ deleted: number;
380
+ }
381
+
272
382
  /**
273
383
  * App-facing outbox storage port.
274
384
  *
@@ -294,10 +404,48 @@ export interface OutboxPort {
294
404
  markFailed(input: OutboxMarkFailedInput): Promise<void>;
295
405
  }
296
406
 
407
+ /**
408
+ * Operational outbox admin port.
409
+ *
410
+ * Keep this separate from `OutboxPort` so request and drain contexts can expose
411
+ * only the hot-path delivery operations. Wire this port into maintenance
412
+ * contexts for CLI commands, runbooks, and devtools.
413
+ */
414
+ export interface OutboxAdminPort {
415
+ /**
416
+ * List messages ordered by newest update first.
417
+ */
418
+ listMessages(
419
+ options?: OutboxListMessagesOptions,
420
+ ): Promise<readonly OutboxMessage[]>;
421
+ /**
422
+ * Count messages matching admin filters.
423
+ */
424
+ countMessages(options?: OutboxCountMessagesOptions): Promise<number>;
425
+ /**
426
+ * Fetch one message by ID.
427
+ */
428
+ getMessage(id: string): Promise<OutboxMessage | null>;
429
+ /**
430
+ * Return a dead-lettered message to pending state.
431
+ */
432
+ requeueMessage(input: OutboxRequeueMessageInput): Promise<OutboxMessage>;
433
+ /**
434
+ * Delete dead-lettered messages.
435
+ */
436
+ purgeDeadLettered(
437
+ input?: OutboxPurgeDeadLetteredInput,
438
+ ): Promise<OutboxDeleteResult>;
439
+ /**
440
+ * Delete delivered messages older than a retention cutoff.
441
+ */
442
+ pruneDelivered(input: OutboxPruneDeliveredInput): Promise<OutboxDeleteResult>;
443
+ }
444
+
297
445
  /**
298
446
  * In-memory outbox for tests and local examples.
299
447
  */
300
- export interface MemoryOutboxPort extends OutboxPort {
448
+ export interface MemoryOutboxPort extends OutboxPort, OutboxAdminPort {
301
449
  /**
302
450
  * Current message snapshots.
303
451
  */
@@ -504,6 +652,22 @@ export class OutboxClaimError extends Error {
504
652
  }
505
653
  }
506
654
 
655
+ /**
656
+ * Error thrown when an outbox admin operation cannot be completed safely.
657
+ */
658
+ export class OutboxAdminError extends Error {
659
+ /**
660
+ * Message ID involved in the admin error, when applicable.
661
+ */
662
+ readonly id?: string;
663
+
664
+ constructor(args: { message: string; id?: string }) {
665
+ super(args.message);
666
+ this.name = "OutboxAdminError";
667
+ this.id = args.id;
668
+ }
669
+ }
670
+
507
671
  function assertNonEmptyString(name: string, value: string): void {
508
672
  if (typeof value !== "string" || value.trim().length === 0) {
509
673
  throw new Error(`${name} must be a non-empty string`);
@@ -516,6 +680,12 @@ function assertPositiveInteger(name: string, value: number): void {
516
680
  }
517
681
  }
518
682
 
683
+ function assertValidDate(name: string, value: Date): void {
684
+ if (!(value instanceof Date) || Number.isNaN(value.getTime())) {
685
+ throw new Error(`${name} must be a valid Date`);
686
+ }
687
+ }
688
+
519
689
  function cloneDate(value: Date): Date {
520
690
  return new Date(value.getTime());
521
691
  }
@@ -645,6 +815,75 @@ function copyMessage(message: OutboxMessage): OutboxMessage {
645
815
  };
646
816
  }
647
817
 
818
+ function normalizeStatusFilter(
819
+ status: OutboxMessageQuery["status"],
820
+ ): ReadonlySet<OutboxMessageStatus> | undefined {
821
+ if (status === undefined) return undefined;
822
+ return new Set(Array.isArray(status) ? status : [status]);
823
+ }
824
+
825
+ function messageMatchesQuery(
826
+ message: OutboxMessage,
827
+ query: OutboxMessageQuery = {},
828
+ ): boolean {
829
+ const statuses = normalizeStatusFilter(query.status);
830
+ if (statuses && !statuses.has(message.status)) return false;
831
+ if (query.kind !== undefined && message.kind !== query.kind) return false;
832
+ if (query.name !== undefined && message.name !== query.name) return false;
833
+ if (
834
+ query.updatedBefore !== undefined &&
835
+ message.updatedAt.getTime() >= query.updatedBefore.getTime()
836
+ ) {
837
+ return false;
838
+ }
839
+ if (
840
+ query.deliveredBefore !== undefined &&
841
+ (message.deliveredAt === null ||
842
+ message.deliveredAt.getTime() >= query.deliveredBefore.getTime())
843
+ ) {
844
+ return false;
845
+ }
846
+ return true;
847
+ }
848
+
849
+ function compareMessagesForAdminList(
850
+ left: OutboxMessage,
851
+ right: OutboxMessage,
852
+ ): number {
853
+ const updated = right.updatedAt.getTime() - left.updatedAt.getTime();
854
+ if (updated !== 0) return updated;
855
+ const created = right.createdAt.getTime() - left.createdAt.getTime();
856
+ if (created !== 0) return created;
857
+ return right.id.localeCompare(left.id);
858
+ }
859
+
860
+ function compareMessagesForAdminCleanup(
861
+ left: OutboxMessage,
862
+ right: OutboxMessage,
863
+ ): number {
864
+ const updated = left.updatedAt.getTime() - right.updatedAt.getTime();
865
+ if (updated !== 0) return updated;
866
+ const created = left.createdAt.getTime() - right.createdAt.getTime();
867
+ if (created !== 0) return created;
868
+ return left.id.localeCompare(right.id);
869
+ }
870
+
871
+ function compareDeliveredMessagesForPrune(
872
+ left: OutboxMessage,
873
+ right: OutboxMessage,
874
+ ): number {
875
+ const delivered =
876
+ (left.deliveredAt?.getTime() ?? 0) - (right.deliveredAt?.getTime() ?? 0);
877
+ if (delivered !== 0) return delivered;
878
+ return compareMessagesForAdminCleanup(left, right);
879
+ }
880
+
881
+ function resolveAdminListLimit(limit: number | undefined): number {
882
+ const resolved = limit ?? DEFAULT_OUTBOX_ADMIN_LIST_LIMIT;
883
+ assertPositiveInteger("limit", resolved);
884
+ return resolved;
885
+ }
886
+
648
887
  function toClaimedMessage(message: OutboxMessage): ClaimedOutboxMessage {
649
888
  if (
650
889
  message.status !== "claimed" ||
@@ -764,6 +1003,120 @@ export function createMemoryOutbox(
764
1003
  return [...messages.values()].map(copyMessage);
765
1004
  },
766
1005
 
1006
+ async listMessages(options = {}) {
1007
+ const limit = resolveAdminListLimit(options.limit);
1008
+ if (options.updatedBefore) {
1009
+ assertValidDate("updatedBefore", options.updatedBefore);
1010
+ }
1011
+ if (options.deliveredBefore) {
1012
+ assertValidDate("deliveredBefore", options.deliveredBefore);
1013
+ }
1014
+
1015
+ return [...messages.values()]
1016
+ .filter((message) => messageMatchesQuery(message, options))
1017
+ .sort(compareMessagesForAdminList)
1018
+ .slice(0, limit)
1019
+ .map(copyMessage);
1020
+ },
1021
+
1022
+ async countMessages(options = {}) {
1023
+ if (options.updatedBefore) {
1024
+ assertValidDate("updatedBefore", options.updatedBefore);
1025
+ }
1026
+ if (options.deliveredBefore) {
1027
+ assertValidDate("deliveredBefore", options.deliveredBefore);
1028
+ }
1029
+
1030
+ return [...messages.values()].filter((message) =>
1031
+ messageMatchesQuery(message, options),
1032
+ ).length;
1033
+ },
1034
+
1035
+ async getMessage(id) {
1036
+ assertNonEmptyString("id", id);
1037
+ const message = messages.get(id);
1038
+ return message ? copyMessage(message) : null;
1039
+ },
1040
+
1041
+ async requeueMessage(input) {
1042
+ assertNonEmptyString("id", input.id);
1043
+ const message = messages.get(input.id);
1044
+ if (!message) {
1045
+ throw new OutboxAdminError({
1046
+ id: input.id,
1047
+ message: `Outbox message "${input.id}" does not exist.`,
1048
+ });
1049
+ }
1050
+ if (message.status !== "deadLettered") {
1051
+ throw new OutboxAdminError({
1052
+ id: input.id,
1053
+ message: `Outbox message "${input.id}" is not dead-lettered.`,
1054
+ });
1055
+ }
1056
+
1057
+ const now = input.now ?? storeNow();
1058
+ const availableAt = input.availableAt ?? now;
1059
+ assertValidDate("now", now);
1060
+ assertValidDate("availableAt", availableAt);
1061
+
1062
+ message.status = "pending";
1063
+ message.availableAt = cloneDate(availableAt);
1064
+ message.claimToken = null;
1065
+ message.claimedAt = null;
1066
+ message.lockedUntil = null;
1067
+ if (input.resetAttempts) message.attempts = 0;
1068
+ message.updatedAt = cloneDate(now);
1069
+
1070
+ return copyMessage(message);
1071
+ },
1072
+
1073
+ async purgeDeadLettered(input = {}) {
1074
+ const limit =
1075
+ input.limit === undefined
1076
+ ? undefined
1077
+ : resolveAdminListLimit(input.limit);
1078
+ if (input.before) assertValidDate("before", input.before);
1079
+
1080
+ const candidates = [...messages.values()]
1081
+ .filter(
1082
+ (message) =>
1083
+ message.status === "deadLettered" &&
1084
+ (input.before === undefined ||
1085
+ message.updatedAt.getTime() < input.before.getTime()),
1086
+ )
1087
+ .sort(compareMessagesForAdminCleanup)
1088
+ .slice(0, limit);
1089
+
1090
+ for (const message of candidates) {
1091
+ messages.delete(message.id);
1092
+ }
1093
+
1094
+ return { deleted: candidates.length };
1095
+ },
1096
+
1097
+ async pruneDelivered(input) {
1098
+ assertValidDate("before", input.before);
1099
+ const limit =
1100
+ input.limit === undefined
1101
+ ? undefined
1102
+ : resolveAdminListLimit(input.limit);
1103
+ const candidates = [...messages.values()]
1104
+ .filter(
1105
+ (message) =>
1106
+ message.status === "delivered" &&
1107
+ message.deliveredAt !== null &&
1108
+ message.deliveredAt.getTime() < input.before.getTime(),
1109
+ )
1110
+ .sort(compareDeliveredMessagesForPrune)
1111
+ .slice(0, limit);
1112
+
1113
+ for (const message of candidates) {
1114
+ messages.delete(message.id);
1115
+ }
1116
+
1117
+ return { deleted: candidates.length };
1118
+ },
1119
+
767
1120
  async enqueue(input) {
768
1121
  const message = createOutboxMessage(input, {
769
1122
  createId: createStoreId,
@@ -1058,7 +1411,10 @@ async function deliverOutboxMessage(
1058
1411
  }
1059
1412
  )[SINGLE_ATTEMPT_DISPATCH];
1060
1413
  if (singleAttempt) {
1061
- await singleAttempt(job, payload);
1414
+ await singleAttempt(job, payload, {
1415
+ attempt: message.attempts,
1416
+ maxAttempts: message.maxAttempts,
1417
+ });
1062
1418
  return;
1063
1419
  }
1064
1420
 
@@ -51,9 +51,9 @@ export type InferJobPayload<J extends JobDef> = InferContractJobPayload<J>;
51
51
  *
52
52
  * @example
53
53
  * ```ts
54
- * import { createInMemoryEventBus } from "@beignet/provider-event-bus-memory";
54
+ * import { createMemoryEventBus } from "@beignet/provider-event-bus-memory";
55
55
  *
56
- * const eventBus = createInMemoryEventBus();
56
+ * const eventBus = createMemoryEventBus();
57
57
  *
58
58
  * // Subscribe to an event
59
59
  * const unsubscribe = eventBus.subscribe(UserRegistered, (payload) => {
@@ -224,7 +224,6 @@ export {
224
224
  createMemoryFlags,
225
225
  createStaticFlags,
226
226
  defineFlag,
227
- defineFlagRegistry,
228
227
  defineFlags,
229
228
  evaluateFlag,
230
229
  getFlagDetails,
@@ -281,14 +280,22 @@ export type {
281
280
  */
282
281
  export type {
283
282
  ClaimedOutboxMessage,
283
+ OutboxAdminPort,
284
284
  OutboxClaimBatchOptions,
285
+ OutboxCountMessagesOptions,
286
+ OutboxDeleteResult,
285
287
  OutboxEnqueueInput,
288
+ OutboxListMessagesOptions,
286
289
  OutboxMarkDeliveredInput,
287
290
  OutboxMarkFailedInput,
288
291
  OutboxMessage,
289
292
  OutboxMessageKind,
293
+ OutboxMessageQuery,
290
294
  OutboxMessageStatus,
291
295
  OutboxPort,
296
+ OutboxPruneDeliveredInput,
297
+ OutboxPurgeDeadLetteredInput,
298
+ OutboxRequeueMessageInput,
292
299
  } from "../outbox/index.js";
293
300
  /**
294
301
  * Payments port exports.
@@ -359,6 +366,15 @@ export {
359
366
  SearchOptionsError,
360
367
  searchDocuments,
361
368
  } from "../search/index.js";
369
+ /**
370
+ * Tenant scope exports.
371
+ */
372
+ export type { TenantScope } from "../tenancy/index.js";
373
+ export {
374
+ createTenantScope,
375
+ requireTenantScope,
376
+ tenantScopeId,
377
+ } from "../tenancy/index.js";
362
378
  /**
363
379
  * Webhook exports.
364
380
  *
@@ -39,6 +39,10 @@ export interface BaseProviderInstrumentationEvent {
39
39
  * W3C traceparent header value, when available.
40
40
  */
41
41
  traceparent?: string;
42
+ /**
43
+ * W3C tracestate value associated with the current operation.
44
+ */
45
+ tracestate?: string;
42
46
  /**
43
47
  * Watcher category used by devtools and instrumentation sinks.
44
48
  */
@@ -170,7 +170,7 @@ export interface ServiceProviderMetadata {
170
170
  *
171
171
  * @example
172
172
  * ```ts
173
- * const redisCacheProvider = createProvider({
173
+ * const cacheProvider = createProvider({
174
174
  * name: "cache-redis",
175
175
  * config: {
176
176
  * schema: z.object({ URL: z.string().url() }),
@@ -1,4 +1,6 @@
1
1
  import type { StandardSchemaV1 } from "@standard-schema/spec";
2
+ import { runWithResolvedTracingContext } from "../tracing/execution.js";
3
+ import type { TracingPort } from "../tracing/index.js";
2
4
 
3
5
  /**
4
6
  * Any Standard Schema compatible validator.
@@ -134,9 +136,7 @@ export interface ScheduleHandleArgs<S extends ScheduleDef, Ctx> {
134
136
  * Parsed schedule payload.
135
137
  */
136
138
  payload: InferSchedulePayload<S>;
137
- /**
138
- * Handler context.
139
- */
139
+ /** Handler context. */
140
140
  ctx: Ctx;
141
141
  /**
142
142
  * Run metadata.
@@ -219,10 +219,10 @@ export type ScheduleRunArgs<
219
219
  Ctx,
220
220
  Payload = unknown,
221
221
  > = ScheduleRunOptions<Payload> & {
222
- /**
223
- * Handler context.
224
- */
225
- ctx: Ctx;
222
+ /** Handler context or factory resolved inside the schedule span. */
223
+ ctx: Ctx | (() => MaybePromise<Ctx>);
224
+ /** Runtime tracing port used before a lazy context factory runs. */
225
+ tracing?: TracingPort;
226
226
  };
227
227
 
228
228
  /**
@@ -374,6 +374,8 @@ export interface InlineScheduleRunnerOptions<Ctx> {
374
374
  * Static schedule context or factory evaluated for each run.
375
375
  */
376
376
  ctx?: Ctx | (() => MaybePromise<Ctx>);
377
+ /** Runtime tracing port used before a lazy context factory runs. */
378
+ tracing?: TracingPort;
377
379
  /**
378
380
  * Clock used when run timestamps are not provided.
379
381
  */
@@ -575,14 +577,33 @@ function createRunContext(
575
577
  };
576
578
  }
577
579
 
578
- async function resolveCtx<Ctx>(
579
- ctx: Ctx | (() => MaybePromise<Ctx>) | undefined,
580
- ): Promise<Ctx> {
581
- if (typeof ctx === "function") {
582
- return (ctx as () => MaybePromise<Ctx>)();
583
- }
580
+ function scheduleTraceOperation(
581
+ schedule: ScheduleDef,
582
+ options: ScheduleRunOptions<unknown>,
583
+ ) {
584
+ const attributes = {
585
+ "beignet.schedule.name": schedule.name,
586
+ ...(options.attempt === undefined
587
+ ? {}
588
+ : { "beignet.schedule.attempt": options.attempt }),
589
+ ...(options.source === undefined
590
+ ? {}
591
+ : { "beignet.schedule.source": options.source }),
592
+ } as const;
593
+ const metricAttributes = {
594
+ "beignet.schedule.name": schedule.name,
595
+ ...(options.attempt === undefined
596
+ ? {}
597
+ : { "beignet.schedule.attempt": options.attempt }),
598
+ } as const;
584
599
 
585
- return ctx as Ctx;
600
+ return {
601
+ name: `beignet.schedule ${schedule.name}`,
602
+ type: "schedule" as const,
603
+ kind: "consumer" as const,
604
+ attributes,
605
+ metricAttributes,
606
+ };
586
607
  }
587
608
 
588
609
  async function resolveSchedulePayload<S extends ScheduleDef>(
@@ -739,14 +760,21 @@ export async function runSchedule<
739
760
  schedule: S,
740
761
  args: ScheduleRunArgs<Ctx, InferSchedulePayload<S>>,
741
762
  ): Promise<void> {
742
- const run = createRunContext(args, () => new Date());
743
- const payload = await resolveSchedulePayload(schedule, args, run);
744
-
745
- await schedule.handle({
746
- schedule,
747
- payload,
763
+ await runWithResolvedTracingContext({
764
+ tracing: args.tracing,
748
765
  ctx: args.ctx,
749
- run,
766
+ operation: scheduleTraceOperation(schedule, args),
767
+ run: async (ctx) => {
768
+ const run = createRunContext(args, () => new Date());
769
+ const payload = await resolveSchedulePayload(schedule, args, run);
770
+
771
+ await schedule.handle({
772
+ schedule,
773
+ payload,
774
+ ctx,
775
+ run,
776
+ });
777
+ },
750
778
  });
751
779
  }
752
780
 
@@ -780,11 +808,17 @@ export function createInlineScheduleRunner<Ctx>(
780
808
  options.onHookError,
781
809
  lifecycleArgs,
782
810
  );
783
- await schedule.handle({
784
- schedule,
785
- payload,
786
- ctx: await resolveCtx(options.ctx),
787
- run,
811
+ await runWithResolvedTracingContext({
812
+ tracing: options.tracing,
813
+ ctx: options.ctx as Ctx | (() => MaybePromise<Ctx>),
814
+ operation: scheduleTraceOperation(schedule, runOptions),
815
+ run: (ctx) =>
816
+ schedule.handle({
817
+ schedule,
818
+ payload: payload as InferSchedulePayload<S>,
819
+ ctx,
820
+ run,
821
+ }),
788
822
  });
789
823
  await recordScheduleEvent(options, schedule, "completed", run, {
790
824
  payload,
@@ -46,6 +46,16 @@ export {
46
46
  type RateLimitIpSource,
47
47
  type RateLimitOptions,
48
48
  } from "./rate-limit.js";
49
+ export {
50
+ applySecurityHeaders,
51
+ type CsrfFailureReason,
52
+ type CsrfHooksOptions,
53
+ type CsrfTokenOptions,
54
+ createCsrfHooks,
55
+ createSecurityHeadersHooks,
56
+ type SecurityHeadersOptions,
57
+ type StrictTransportSecurityOptions,
58
+ } from "./security.js";
49
59
 
50
60
  /**
51
61
  * Flatten hook arrays into a single hook list.