@geekmidas/constructs 10.0.0-alpha.41 → 10.0.0-alpha.43

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 (196) hide show
  1. package/dist/{Cron-CMEGfRs8.d.cts → Cron-DI3nKoic.d.cts} +3 -2
  2. package/dist/Cron-DI3nKoic.d.cts.map +1 -0
  3. package/dist/{Cron-D6X4-xjB.d.mts → Cron-uYAHPnp7.d.mts} +3 -2
  4. package/dist/Cron-uYAHPnp7.d.mts.map +1 -0
  5. package/dist/{CronBuilder-DB35T5dL.cjs → CronBuilder-BoHzlWU_.cjs} +8 -3
  6. package/dist/CronBuilder-BoHzlWU_.cjs.map +1 -0
  7. package/dist/{CronBuilder-Dv0IlZs0.mjs → CronBuilder-CCgt0wCE.mjs} +9 -4
  8. package/dist/CronBuilder-CCgt0wCE.mjs.map +1 -0
  9. package/dist/{CronBuilder-O_gvButp.d.mts → CronBuilder-DaSUm2Na.d.mts} +5 -4
  10. package/dist/CronBuilder-DaSUm2Na.d.mts.map +1 -0
  11. package/dist/{CronBuilder-CEK7aOqD.d.cts → CronBuilder-g1lZLWyG.d.cts} +5 -4
  12. package/dist/CronBuilder-g1lZLWyG.d.cts.map +1 -0
  13. package/dist/{Endpoint-CQAeh1Rh.mjs → Endpoint-BDgmfml0.mjs} +2 -2
  14. package/dist/{Endpoint-CQAeh1Rh.mjs.map → Endpoint-BDgmfml0.mjs.map} +1 -1
  15. package/dist/{Endpoint-Dp5AKIXl.d.cts → Endpoint-BkzU6nn1.d.cts} +5 -4
  16. package/dist/Endpoint-BkzU6nn1.d.cts.map +1 -0
  17. package/dist/{Endpoint-DtI7heFm.d.mts → Endpoint-BpboleFh.d.mts} +5 -4
  18. package/dist/Endpoint-BpboleFh.d.mts.map +1 -0
  19. package/dist/{Endpoint-D1L9qu5C.cjs → Endpoint-wSCHSnqb.cjs} +2 -2
  20. package/dist/{Endpoint-D1L9qu5C.cjs.map → Endpoint-wSCHSnqb.cjs.map} +1 -1
  21. package/dist/{EndpointFactory-FeFRmlDZ.d.cts → EndpointFactory-BZZOleQT.d.cts} +4 -4
  22. package/dist/{EndpointFactory-CgMDvERK.d.mts.map → EndpointFactory-BZZOleQT.d.cts.map} +1 -1
  23. package/dist/{EndpointFactory-BBdNeaGJ.mjs → EndpointFactory-C9G2pz86.mjs} +3 -3
  24. package/dist/{EndpointFactory-BBdNeaGJ.mjs.map → EndpointFactory-C9G2pz86.mjs.map} +1 -1
  25. package/dist/{EndpointFactory-CgMDvERK.d.mts → EndpointFactory-DnNlYflU.d.mts} +4 -4
  26. package/dist/{EndpointFactory-FeFRmlDZ.d.cts.map → EndpointFactory-DnNlYflU.d.mts.map} +1 -1
  27. package/dist/{EndpointFactory-BZOCOaK6.cjs → EndpointFactory-G1g1kiqC.cjs} +3 -3
  28. package/dist/{EndpointFactory-BZOCOaK6.cjs.map → EndpointFactory-G1g1kiqC.cjs.map} +1 -1
  29. package/dist/Function-DuqGcbOI.d.mts +76 -0
  30. package/dist/Function-DuqGcbOI.d.mts.map +1 -0
  31. package/dist/Function-Pu-1kKZz.d.cts +76 -0
  32. package/dist/Function-Pu-1kKZz.d.cts.map +1 -0
  33. package/dist/{HonoEndpointAdaptor-Cq99r9H7.cjs → HonoEndpointAdaptor-CBoSm3TM.cjs} +3 -3
  34. package/dist/{HonoEndpointAdaptor-Cq99r9H7.cjs.map → HonoEndpointAdaptor-CBoSm3TM.cjs.map} +1 -1
  35. package/dist/{HonoEndpointAdaptor-Aui-x9Lg.mjs → HonoEndpointAdaptor-DL_fCB9O.mjs} +3 -3
  36. package/dist/{HonoEndpointAdaptor-Aui-x9Lg.mjs.map → HonoEndpointAdaptor-DL_fCB9O.mjs.map} +1 -1
  37. package/dist/{Queue-Ckmudcm8.cjs → Queue-D5jcw0mu.cjs} +6 -2
  38. package/dist/Queue-D5jcw0mu.cjs.map +1 -0
  39. package/dist/{Queue-YmvN2vEP.d.mts → Queue-DlsHRzUp.d.mts} +22 -10
  40. package/dist/Queue-DlsHRzUp.d.mts.map +1 -0
  41. package/dist/{Queue-CpQIGB_2.d.cts → Queue-HPyi0e1i.d.cts} +22 -10
  42. package/dist/Queue-HPyi0e1i.d.cts.map +1 -0
  43. package/dist/{Queue-C1uDgjxt.mjs → Queue-hwPN-t31.mjs} +6 -2
  44. package/dist/Queue-hwPN-t31.mjs.map +1 -0
  45. package/dist/{QueueBuilder-CJNcv4dy.cjs → QueueBuilder-BFQn3OzZ.cjs} +27 -4
  46. package/dist/QueueBuilder-BFQn3OzZ.cjs.map +1 -0
  47. package/dist/{QueueBuilder-XuPKZwKH.mjs → QueueBuilder-DCuYdjMw.mjs} +28 -5
  48. package/dist/QueueBuilder-DCuYdjMw.mjs.map +1 -0
  49. package/dist/{QueueBuilder-XEnnOWGe.d.cts → QueueBuilder-OSi6LkV9.d.cts} +24 -11
  50. package/dist/QueueBuilder-OSi6LkV9.d.cts.map +1 -0
  51. package/dist/{QueueBuilder-CM0WUxfw.d.mts → QueueBuilder-QHsnVt1P.d.mts} +24 -11
  52. package/dist/QueueBuilder-QHsnVt1P.d.mts.map +1 -0
  53. package/dist/{Subscriber-B91YSkZt.d.cts → Subscriber-Bpp02cGr.d.cts} +20 -9
  54. package/dist/Subscriber-Bpp02cGr.d.cts.map +1 -0
  55. package/dist/{Subscriber-BjHYe5hK.d.mts → Subscriber-CtN9R48-.d.mts} +20 -9
  56. package/dist/Subscriber-CtN9R48-.d.mts.map +1 -0
  57. package/dist/{SubscriberBuilder-Duk028pD.cjs → SubscriberBuilder-C2PwqwIl.cjs} +31 -3
  58. package/dist/SubscriberBuilder-C2PwqwIl.cjs.map +1 -0
  59. package/dist/{SubscriberBuilder-BhMphk4z.d.mts → SubscriberBuilder-CuCMFpYW.d.mts} +23 -11
  60. package/dist/SubscriberBuilder-CuCMFpYW.d.mts.map +1 -0
  61. package/dist/{SubscriberBuilder-DzQUWE08.mjs → SubscriberBuilder-DMFk_Ap1.mjs} +32 -4
  62. package/dist/SubscriberBuilder-DMFk_Ap1.mjs.map +1 -0
  63. package/dist/{SubscriberBuilder-BSpQX1JT.d.cts → SubscriberBuilder-g3fAVWgs.d.cts} +23 -11
  64. package/dist/SubscriberBuilder-g3fAVWgs.d.cts.map +1 -0
  65. package/dist/adaptors/aws.cjs +20 -4
  66. package/dist/adaptors/aws.cjs.map +1 -1
  67. package/dist/adaptors/aws.d.cts +17 -13
  68. package/dist/adaptors/aws.d.cts.map +1 -1
  69. package/dist/adaptors/aws.d.mts +17 -13
  70. package/dist/adaptors/aws.d.mts.map +1 -1
  71. package/dist/adaptors/aws.mjs +20 -4
  72. package/dist/adaptors/aws.mjs.map +1 -1
  73. package/dist/adaptors/hono.cjs +1 -1
  74. package/dist/adaptors/hono.d.cts +1 -1
  75. package/dist/adaptors/hono.d.mts +1 -1
  76. package/dist/adaptors/hono.mjs +1 -1
  77. package/dist/adaptors/testing.cjs +170 -13
  78. package/dist/adaptors/testing.cjs.map +1 -1
  79. package/dist/adaptors/testing.d.cts +38 -21
  80. package/dist/adaptors/testing.d.cts.map +1 -1
  81. package/dist/adaptors/testing.d.mts +38 -21
  82. package/dist/adaptors/testing.d.mts.map +1 -1
  83. package/dist/adaptors/testing.mjs +170 -13
  84. package/dist/adaptors/testing.mjs.map +1 -1
  85. package/dist/{auth-CMwml9QN.d.mts → auth-3OAmK42n.d.cts} +4 -4
  86. package/dist/{auth-CMwml9QN.d.mts.map → auth-3OAmK42n.d.cts.map} +1 -1
  87. package/dist/{auth-rVRDjIw_.d.cts → auth-BWbiewHa.d.mts} +4 -4
  88. package/dist/{auth-rVRDjIw_.d.cts.map → auth-BWbiewHa.d.mts.map} +1 -1
  89. package/dist/auth.d.cts +1 -1
  90. package/dist/auth.d.mts +1 -1
  91. package/dist/{cache-C9a_hVCc.d.cts → cache-CXh6GIgb.d.mts} +3 -3
  92. package/dist/{cache-C9a_hVCc.d.cts.map → cache-CXh6GIgb.d.mts.map} +1 -1
  93. package/dist/{cache-CeTMI8LR.d.mts → cache-DnGDGly3.d.cts} +3 -3
  94. package/dist/{cache-CeTMI8LR.d.mts.map → cache-DnGDGly3.d.cts.map} +1 -1
  95. package/dist/cache.d.cts +1 -1
  96. package/dist/cache.d.mts +1 -1
  97. package/dist/{construct-interface-_3zgxzXl.d.mts → construct-interface-B1AfqRl4.d.cts} +25 -3
  98. package/dist/{construct-interface-_3zgxzXl.d.mts.map → construct-interface-B1AfqRl4.d.cts.map} +1 -1
  99. package/dist/{construct-interface-_xi4BPN8.d.cts → construct-interface-DluK3_da.d.mts} +25 -3
  100. package/dist/{construct-interface-_xi4BPN8.d.cts.map → construct-interface-DluK3_da.d.mts.map} +1 -1
  101. package/dist/construct-interface.cjs +26 -0
  102. package/dist/construct-interface.cjs.map +1 -1
  103. package/dist/construct-interface.d.cts +2 -2
  104. package/dist/construct-interface.d.mts +2 -2
  105. package/dist/construct-interface.mjs +26 -1
  106. package/dist/construct-interface.mjs.map +1 -1
  107. package/dist/credential.d.cts +1 -1
  108. package/dist/credential.d.mts +1 -1
  109. package/dist/crons/index.cjs +1 -1
  110. package/dist/crons/index.d.cts +2 -2
  111. package/dist/crons/index.d.mts +2 -2
  112. package/dist/crons/index.mjs +1 -1
  113. package/dist/database/kysely.d.cts +1 -1
  114. package/dist/database/kysely.d.mts +1 -1
  115. package/dist/email.d.cts +1 -1
  116. package/dist/email.d.mts +1 -1
  117. package/dist/endpoints/index.cjs +3 -3
  118. package/dist/endpoints/index.d.cts +2 -2
  119. package/dist/endpoints/index.d.mts +2 -2
  120. package/dist/endpoints/index.mjs +3 -3
  121. package/dist/{external-api-DS3mujT5.d.mts → external-api-CWY9orcO.d.mts} +2 -2
  122. package/dist/{external-api-DS3mujT5.d.mts.map → external-api-CWY9orcO.d.mts.map} +1 -1
  123. package/dist/{external-api-LBfE-q3g.d.cts → external-api-D-5WB-sr.d.cts} +2 -2
  124. package/dist/{external-api-LBfE-q3g.d.cts.map → external-api-D-5WB-sr.d.cts.map} +1 -1
  125. package/dist/external-api.d.cts +1 -1
  126. package/dist/external-api.d.mts +1 -1
  127. package/dist/file-server.d.cts +1 -1
  128. package/dist/file-server.d.mts +1 -1
  129. package/dist/functions/index.cjs +1 -1
  130. package/dist/functions/index.d.cts +2 -1
  131. package/dist/functions/index.d.mts +2 -1
  132. package/dist/functions/index.mjs +1 -1
  133. package/dist/{functions-ZH60FE7H.cjs → functions-CbP5ZKma.cjs} +15 -3
  134. package/dist/functions-CbP5ZKma.cjs.map +1 -0
  135. package/dist/{functions-DCIfCRR-.mjs → functions-Di6n5ltG.mjs} +16 -4
  136. package/dist/{functions-DCIfCRR-.mjs.map → functions-Di6n5ltG.mjs.map} +1 -1
  137. package/dist/{index-B0kxstwf.d.cts → index-BuzRvKOQ.d.cts} +9 -71
  138. package/dist/index-BuzRvKOQ.d.cts.map +1 -0
  139. package/dist/{index-CjVEjOw0.d.mts → index-CTkKOer4.d.mts} +9 -71
  140. package/dist/index-CTkKOer4.d.mts.map +1 -0
  141. package/dist/{kysely-BJ8IQ_1P.d.mts → kysely-Bqov3fwv.d.mts} +3 -3
  142. package/dist/{kysely-BJ8IQ_1P.d.mts.map → kysely-Bqov3fwv.d.mts.map} +1 -1
  143. package/dist/{kysely-DVF8wOT4.d.cts → kysely-DTnkZsub.d.cts} +3 -3
  144. package/dist/{kysely-DVF8wOT4.d.cts.map → kysely-DTnkZsub.d.cts.map} +1 -1
  145. package/dist/mobile-app.d.cts +1 -1
  146. package/dist/mobile-app.d.mts +1 -1
  147. package/dist/object-storage.d.cts +1 -1
  148. package/dist/object-storage.d.mts +1 -1
  149. package/dist/queue/index.cjs +2 -2
  150. package/dist/queue/index.d.cts +2 -2
  151. package/dist/queue/index.d.mts +2 -2
  152. package/dist/queue/index.mjs +2 -2
  153. package/dist/rest-api.cjs +1 -1
  154. package/dist/rest-api.d.cts +3 -3
  155. package/dist/rest-api.d.mts +3 -3
  156. package/dist/rest-api.mjs +1 -1
  157. package/dist/site.d.cts +1 -1
  158. package/dist/site.d.mts +1 -1
  159. package/dist/subscribers/index.cjs +1 -1
  160. package/dist/subscribers/index.d.cts +2 -2
  161. package/dist/subscribers/index.d.mts +2 -2
  162. package/dist/subscribers/index.mjs +1 -1
  163. package/dist/worker.cjs +26 -10
  164. package/dist/worker.cjs.map +1 -1
  165. package/dist/worker.d.cts +38 -22
  166. package/dist/worker.d.cts.map +1 -1
  167. package/dist/worker.d.mts +38 -22
  168. package/dist/worker.d.mts.map +1 -1
  169. package/dist/worker.mjs +26 -10
  170. package/dist/worker.mjs.map +1 -1
  171. package/package.json +31 -31
  172. package/dist/Cron-CMEGfRs8.d.cts.map +0 -1
  173. package/dist/Cron-D6X4-xjB.d.mts.map +0 -1
  174. package/dist/CronBuilder-CEK7aOqD.d.cts.map +0 -1
  175. package/dist/CronBuilder-DB35T5dL.cjs.map +0 -1
  176. package/dist/CronBuilder-Dv0IlZs0.mjs.map +0 -1
  177. package/dist/CronBuilder-O_gvButp.d.mts.map +0 -1
  178. package/dist/Endpoint-Dp5AKIXl.d.cts.map +0 -1
  179. package/dist/Endpoint-DtI7heFm.d.mts.map +0 -1
  180. package/dist/Queue-C1uDgjxt.mjs.map +0 -1
  181. package/dist/Queue-Ckmudcm8.cjs.map +0 -1
  182. package/dist/Queue-CpQIGB_2.d.cts.map +0 -1
  183. package/dist/Queue-YmvN2vEP.d.mts.map +0 -1
  184. package/dist/QueueBuilder-CJNcv4dy.cjs.map +0 -1
  185. package/dist/QueueBuilder-CM0WUxfw.d.mts.map +0 -1
  186. package/dist/QueueBuilder-XEnnOWGe.d.cts.map +0 -1
  187. package/dist/QueueBuilder-XuPKZwKH.mjs.map +0 -1
  188. package/dist/Subscriber-B91YSkZt.d.cts.map +0 -1
  189. package/dist/Subscriber-BjHYe5hK.d.mts.map +0 -1
  190. package/dist/SubscriberBuilder-BSpQX1JT.d.cts.map +0 -1
  191. package/dist/SubscriberBuilder-BhMphk4z.d.mts.map +0 -1
  192. package/dist/SubscriberBuilder-Duk028pD.cjs.map +0 -1
  193. package/dist/SubscriberBuilder-DzQUWE08.mjs.map +0 -1
  194. package/dist/functions-ZH60FE7H.cjs.map +0 -1
  195. package/dist/index-B0kxstwf.d.cts.map +0 -1
  196. package/dist/index-CjVEjOw0.d.mts.map +0 -1
@@ -1,14 +1,14 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_rolldown_runtime = require("../rolldown-runtime-y5ARvAq5.cjs");
3
3
  const require_auth = require("../auth.cjs");
4
- const require_functions = require("../functions-ZH60FE7H.cjs");
5
- const require_Endpoint = require("../Endpoint-D1L9qu5C.cjs");
6
- const require_Queue = require("../Queue-Ckmudcm8.cjs");
4
+ const require_functions = require("../functions-CbP5ZKma.cjs");
5
+ const require_Endpoint = require("../Endpoint-wSCHSnqb.cjs");
6
+ const require_Queue = require("../Queue-D5jcw0mu.cjs");
7
7
  const require_email = require("../email.cjs");
8
8
  const require_database_kysely = require("../database/kysely.cjs");
9
9
  const require_lazyAccessors = require("../lazyAccessors-hJKGv8Ay.cjs");
10
10
  const require_Topic = require("../Topic-CkxOTrMv.cjs");
11
- const require_HonoEndpointAdaptor = require("../HonoEndpointAdaptor-Cq99r9H7.cjs");
11
+ const require_HonoEndpointAdaptor = require("../HonoEndpointAdaptor-CBoSm3TM.cjs");
12
12
  const require_processAudits = require("../processAudits-D_2W5x8k.cjs");
13
13
  let _geekmidas_manifest = require("@geekmidas/manifest");
14
14
  let _geekmidas_errors = require("@geekmidas/errors");
@@ -345,7 +345,8 @@ var TestFunctionAdaptor = class TestFunctionAdaptor {
345
345
  /**
346
346
  * In-memory test driver for a {@link Queue} worker. Hand it a batch of messages
347
347
  * and it registers the queue's services, runs the handler in a request context,
348
- * and returns the handler result — no SQS/pg-boss required.
348
+ * and returns the handler result — no SQS/pg-boss required. A queue with a
349
+ * database gets `db` registered from it, or the one the request passes.
349
350
  *
350
351
  * @example
351
352
  * const adapter = new TestQueueAdaptor(ordersQueue);
@@ -364,6 +365,7 @@ var TestQueueAdaptor = class TestQueueAdaptor {
364
365
  async invoke(request) {
365
366
  const logger = this.queue.logger.child({ test: true });
366
367
  const services = request.services ?? await this.serviceDiscovery.register(this.queue.services);
368
+ const db = request.db !== void 0 ? request.db : await this.getDatabase();
367
369
  const requestId = `test-${Date.now()}`;
368
370
  return (0, _geekmidas_services.runWithRequestContext)({
369
371
  logger,
@@ -372,9 +374,15 @@ var TestQueueAdaptor = class TestQueueAdaptor {
372
374
  }, () => this.queue.handler({
373
375
  messages: request.messages,
374
376
  services,
375
- logger
377
+ logger,
378
+ db
376
379
  }));
377
380
  }
381
+ async getDatabase() {
382
+ const service = this.queue.databaseService;
383
+ if (!service) return void 0;
384
+ return (await this.serviceDiscovery.register([service]))[service.serviceName];
385
+ }
378
386
  };
379
387
  //#endregion
380
388
  //#region src/subscribers/TestSubscriberAdaptor.ts
@@ -393,6 +401,7 @@ var TestSubscriberAdaptor = class TestSubscriberAdaptor {
393
401
  let services;
394
402
  if (request.services) services = request.services;
395
403
  else services = await this.serviceDiscovery.register(this.subscriber.services);
404
+ const db = request.db !== void 0 ? request.db : await this.getDatabase();
396
405
  const filteredEvents = this.filterEvents(request.events);
397
406
  if (filteredEvents.length === 0) return { batchItemFailures: [] };
398
407
  const requestId = `test-${Date.now()}`;
@@ -404,7 +413,8 @@ var TestSubscriberAdaptor = class TestSubscriberAdaptor {
404
413
  const result = await this.subscriber.handler({
405
414
  events: filteredEvents,
406
415
  services,
407
- logger
416
+ logger,
417
+ db
408
418
  });
409
419
  let output = result;
410
420
  if (this.subscriber.outputSchema && result) {
@@ -415,6 +425,11 @@ var TestSubscriberAdaptor = class TestSubscriberAdaptor {
415
425
  return output;
416
426
  });
417
427
  }
428
+ async getDatabase() {
429
+ const service = this.subscriber.databaseService;
430
+ if (!service) return void 0;
431
+ return (await this.serviceDiscovery.register([service]))[service.serviceName];
432
+ }
418
433
  filterEvents(events) {
419
434
  if (!this.subscriber.subscribedEvents) return events;
420
435
  return events.filter((event) => this.subscriber.subscribedEvents.includes(event.type));
@@ -518,7 +533,16 @@ function featureTest(options = {}) {
518
533
  if (isLocal(new URL(request.url))) return;
519
534
  print.error();
520
535
  } });
521
- restoreFetch = (0, _geekmidas_testkit_context.installContextFetch)();
536
+ const restoreStamp = (0, _geekmidas_testkit_context.installContextFetch)();
537
+ const stamped = globalThis.fetch;
538
+ globalThis.fetch = deliveringFetch(stamped, (id) => {
539
+ const state = contexts.get(id);
540
+ return state ? deliver(app, state, id) : Promise.resolve();
541
+ });
542
+ restoreFetch = () => {
543
+ globalThis.fetch = stamped;
544
+ restoreStamp();
545
+ };
522
546
  });
523
547
  (0, vitest.afterAll)(() => {
524
548
  restoreFetch();
@@ -533,7 +557,9 @@ function featureTest(options = {}) {
533
557
  surfaces: /* @__PURE__ */ new Map(),
534
558
  auth: /* @__PURE__ */ new Map(),
535
559
  addresses: /* @__PURE__ */ new Set(),
536
- published: /* @__PURE__ */ new Map()
560
+ published: /* @__PURE__ */ new Map(),
561
+ pending: [],
562
+ delivering: false
537
563
  };
538
564
  const readMail = app.readMail;
539
565
  if (readMail) state.mailbox = (address) => {
@@ -573,8 +599,8 @@ function featureTest(options = {}) {
573
599
  return state.mailbox(address);
574
600
  },
575
601
  published: (channel) => [...state.published.get(channel.id) ?? []],
576
- subscriber: (subscriber) => new TestSubscriberAdaptor(subscriber, state.discovery),
577
- queue: (queue) => new TestQueueAdaptor(queue, state.discovery)
602
+ subscriber: (subscriber) => thenDeliver(new TestSubscriberAdaptor(subscriber, state.discovery), () => deliver(app, state, id)),
603
+ queue: (queue) => thenDeliver(new TestQueueAdaptor(queue, state.discovery), () => deliver(app, state, id))
578
604
  });
579
605
  } finally {
580
606
  restore();
@@ -610,6 +636,10 @@ async function load(manifest, modules) {
610
636
  const imported = async ({ file, export: name }) => (modules[file] ?? await import(file))[name];
611
637
  const constructs = await Promise.all(Object.values(manifest.constructs).map(({ source }) => imported(source)));
612
638
  const endpoints = (await Promise.all(manifest.endpoints.map(({ source }) => imported(source)))).filter((value) => require_Endpoint.Endpoint.isEndpoint(value));
639
+ const subscribers = (await Promise.all((manifest.subscribers ?? []).map(async ({ source }) => ({
640
+ name: source.export,
641
+ subscriber: await imported(source)
642
+ })))).filter((entry) => entry.subscriber?.__IS_SUBSCRIBER__ === true);
613
643
  const unique = (values) => [...new Set(values)];
614
644
  const databases = unique(constructs.filter((value) => value instanceof require_database_kysely.KyselyDatabase));
615
645
  const auths = unique(constructs.filter((value) => value instanceof require_auth.BetterAuth));
@@ -623,6 +653,7 @@ async function load(manifest, modules) {
623
653
  auths,
624
654
  emails,
625
655
  channels,
656
+ subscribers,
626
657
  ...inbox ? { readMail: (0, _geekmidas_testkit_mailbox.createMailbox)({ inbox }) } : {}
627
658
  };
628
659
  }
@@ -634,10 +665,15 @@ async function load(manifest, modules) {
634
665
  function recorders(channels, state) {
635
666
  return channels.map((channel) => {
636
667
  const publisher = { async publish(messages) {
637
- state.published.set(channel.id, [...state.published.get(channel.id) ?? [], ...messages.map(({ type, payload }) => ({
668
+ const sent = messages.map(({ type, payload }) => ({
638
669
  type,
639
670
  payload
640
- }))]);
671
+ }));
672
+ state.published.set(channel.id, [...state.published.get(channel.id) ?? [], ...sent]);
673
+ state.pending.push({
674
+ channel,
675
+ messages: sent
676
+ });
641
677
  } };
642
678
  return {
643
679
  serviceName: channel.service.serviceName,
@@ -671,6 +707,90 @@ function databasesFor(factories, databases) {
671
707
  * the one place a test's connection can be handed over. Outside a test it is
672
708
  * the database it always was.
673
709
  */
710
+ /** Rounds of delivery before a chain of consumers is called a loop. */
711
+ const MAX_DELIVERY_ROUNDS = 25;
712
+ /**
713
+ * Deliver what this test published, in-process, as the broker would — and
714
+ * keep delivering what the consumers publish in turn, until nothing is left.
715
+ *
716
+ * - A queue's messages go to its one consumer, as a batch.
717
+ * - A topic's events go to every subscriber that named their type, and only
718
+ * those: fan-out, as the filter policy (SNS) or the per-subscriber queue
719
+ * (pg-boss) does it.
720
+ * - Each payload is checked against the consumer's schema first. Turning an
721
+ * SNS envelope or an SQS record into `{ type, payload }` is each adaptor's
722
+ * job and tested there; what is tested here is what the handler is handed.
723
+ * - Consumers run as the server side of this test, so their databases are
724
+ * this test's transactions and their writes roll back with it.
725
+ * - A consumer that throws fails the test. Deployed, the message would be
726
+ * retried; here a retry would only hide the bug.
727
+ */
728
+ async function deliver(app, state, id) {
729
+ if (state.delivering) return;
730
+ state.delivering = true;
731
+ try {
732
+ for (let round = 0; state.pending.length > 0; round++) {
733
+ if (round === MAX_DELIVERY_ROUNDS) throw new DeliveryDidNotSettle(MAX_DELIVERY_ROUNDS, [...new Set(state.pending.map(({ channel }) => channel.id))]);
734
+ for (const { channel, messages } of state.pending.splice(0)) if (channel instanceof require_Queue.Queue) await toQueue(channel, messages, state, id);
735
+ else await toSubscribers(channel, messages, app, state, id);
736
+ }
737
+ } finally {
738
+ state.delivering = false;
739
+ }
740
+ }
741
+ async function toQueue(queue, messages, state, id) {
742
+ const payloads = [];
743
+ for (const message of messages) payloads.push(await accepted(queue.messageSchema, message, `queue '${queue.name}'`));
744
+ await (0, _geekmidas_testkit_context.runAsServer)(id, () => new TestQueueAdaptor(queue, state.discovery).invoke({ messages: payloads })).catch((error) => {
745
+ throw new DeliveryFailed(`queue '${queue.name}'`, messages, error);
746
+ });
747
+ }
748
+ async function toSubscribers(topic, messages, app, state, id) {
749
+ for (const { name, subscriber } of app.subscribers) {
750
+ if (subscriber.topicName !== topic.name) continue;
751
+ const named = messages.filter(({ type }) => (subscriber.subscribedEvents ?? []).includes(type));
752
+ if (named.length === 0) continue;
753
+ const consumer = `subscriber '${name}'`;
754
+ const events = [];
755
+ for (const message of named) {
756
+ const schema = topic.eventSchemas[message.type];
757
+ events.push({
758
+ type: message.type,
759
+ payload: await accepted(schema, message, consumer)
760
+ });
761
+ }
762
+ await (0, _geekmidas_testkit_context.runAsServer)(id, () => new TestSubscriberAdaptor(subscriber, state.discovery).invoke({ events })).catch((error) => {
763
+ throw new DeliveryFailed(consumer, named, error);
764
+ });
765
+ }
766
+ }
767
+ /** The payload, if the consumer's schema takes it — what the handler is handed. */
768
+ async function accepted(schema, message, consumer) {
769
+ const standard = schema?.["~standard"];
770
+ if (!standard) return message.payload;
771
+ const result = await standard.validate(message.payload);
772
+ if (result.issues) throw new MessageRejected(consumer, message, result.issues);
773
+ return result.value;
774
+ }
775
+ /** `fetch`, delivering what the test published once each of its requests answers. */
776
+ function deliveringFetch(inner, settle) {
777
+ return async (input, init) => {
778
+ const context = (0, _geekmidas_testkit_context.currentTestContext)();
779
+ const response = await inner(input, init);
780
+ if (context?.side === "client") await settle(context.id);
781
+ return response;
782
+ };
783
+ }
784
+ /** An adaptor whose `invoke` delivers what it published before returning. */
785
+ function thenDeliver(adaptor, settle) {
786
+ const invoke = adaptor.invoke.bind(adaptor);
787
+ adaptor.invoke = (async (...args) => {
788
+ const result = await invoke(...args);
789
+ await settle();
790
+ return result;
791
+ });
792
+ return adaptor;
793
+ }
674
794
  function bindToTests(database) {
675
795
  if (bound.has(database)) return;
676
796
  bound.add(database);
@@ -841,6 +961,43 @@ var UnknownFactory = class extends Error {
841
961
  this.name = "UnknownFactory";
842
962
  }
843
963
  };
964
+ /** A published message the consumer's own schema refuses. */
965
+ var MessageRejected = class extends Error {
966
+ consumer;
967
+ published;
968
+ issues;
969
+ constructor(consumer, published, issues) {
970
+ super(`${consumer} refuses '${published.type}': ${issues.map((issue) => issue.message).join("; ")}. What is published must be what the consumer's schema takes — fix the producer, or the schema.`);
971
+ this.consumer = consumer;
972
+ this.published = published;
973
+ this.issues = issues;
974
+ this.name = "MessageRejected";
975
+ }
976
+ };
977
+ /** A consumer that threw while handling what the test published. */
978
+ var DeliveryFailed = class extends Error {
979
+ consumer;
980
+ messages;
981
+ cause;
982
+ constructor(consumer, messages, cause) {
983
+ super(`${consumer} failed handling ${messages.map(({ type }) => `'${type}'`).join(", ")}: ${cause?.message ?? String(cause)}. Deployed, the message would be retried; here the failure is the result.`, { cause });
984
+ this.consumer = consumer;
985
+ this.messages = messages;
986
+ this.cause = cause;
987
+ this.name = "DeliveryFailed";
988
+ }
989
+ };
990
+ /** Consumers that kept publishing to each other without settling. */
991
+ var DeliveryDidNotSettle = class extends Error {
992
+ rounds;
993
+ channels;
994
+ constructor(rounds, channels) {
995
+ super(`Delivery did not settle after ${rounds} rounds — consumers are still publishing to ${channels.join(", ")}. A consumer that publishes to what triggers it loops forever deployed too.`);
996
+ this.rounds = rounds;
997
+ this.channels = channels;
998
+ this.name = "DeliveryDidNotSettle";
999
+ }
1000
+ };
844
1001
  //#endregion
845
1002
  exports.NoInbox = NoInbox;
846
1003
  exports.NoTestManifest = NoTestManifest;