@geekmidas/constructs 10.0.0-alpha.12 → 10.0.0-alpha.120
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.
- package/README.md +222 -158
- package/dist/Construct-B7AXn0xH.d.mts +230 -0
- package/dist/Construct-B7AXn0xH.d.mts.map +1 -0
- package/dist/Construct-CFW0zjdD.d.cts +230 -0
- package/dist/Construct-CFW0zjdD.d.cts.map +1 -0
- package/dist/{Construct-BD5neF7w.mjs → Construct-CKUA-CTA.mjs} +35 -35
- package/dist/Construct-CKUA-CTA.mjs.map +1 -0
- package/dist/{Construct-CyS3RpTL.cjs → Construct-DEOVauyA.cjs} +55 -49
- package/dist/Construct-DEOVauyA.cjs.map +1 -0
- package/dist/{Cron-DmQ8vQ4b.d.cts → Cron-bdGRSROY.d.cts} +15 -9
- package/dist/Cron-bdGRSROY.d.cts.map +1 -0
- package/dist/{Cron-dh4rUgib.d.mts → Cron-i4Uetezh.d.mts} +15 -9
- package/dist/Cron-i4Uetezh.d.mts.map +1 -0
- package/dist/CronBuilder-9H4BnD6W.d.mts +47 -0
- package/dist/CronBuilder-9H4BnD6W.d.mts.map +1 -0
- package/dist/{CronBuilder-Da0C0edR.cjs → CronBuilder-BXTG10u5.cjs} +47 -31
- package/dist/CronBuilder-BXTG10u5.cjs.map +1 -0
- package/dist/CronBuilder-B_24LZpn.d.cts +47 -0
- package/dist/CronBuilder-B_24LZpn.d.cts.map +1 -0
- package/dist/{CronBuilder-CYKT5RiO.mjs → CronBuilder-D3sF9tS_.mjs} +37 -21
- package/dist/CronBuilder-D3sF9tS_.mjs.map +1 -0
- package/dist/{Endpoint-BjWKinFA.d.mts → Endpoint-CeFkSwh5.d.mts} +129 -99
- package/dist/Endpoint-CeFkSwh5.d.mts.map +1 -0
- package/dist/{Endpoint-dav89W6-.d.cts → Endpoint-DgrpG15P.d.cts} +127 -97
- package/dist/Endpoint-DgrpG15P.d.cts.map +1 -0
- package/dist/{Endpoint-DCQPMdUX.mjs → Endpoint-gPXhHKhJ.mjs} +208 -100
- package/dist/Endpoint-gPXhHKhJ.mjs.map +1 -0
- package/dist/{Endpoint-DcWXE-SZ.cjs → Endpoint-yhR2T2Wt.cjs} +248 -122
- package/dist/Endpoint-yhR2T2Wt.cjs.map +1 -0
- package/dist/{EndpointFactory-CdWB7wPw.cjs → EndpointFactory-CSrAyazj.cjs} +361 -112
- package/dist/EndpointFactory-CSrAyazj.cjs.map +1 -0
- package/dist/{index-lAO9egTb.d.mts → EndpointFactory-Cc863XJS.d.cts} +190 -136
- package/dist/EndpointFactory-Cc863XJS.d.cts.map +1 -0
- package/dist/{index-Bd5FqCoe.d.cts → EndpointFactory-Dbw9ugkX.d.mts} +189 -135
- package/dist/EndpointFactory-Dbw9ugkX.d.mts.map +1 -0
- package/dist/{EndpointFactory-CjV8F_lJ.mjs → EndpointFactory-c2ZugGig.mjs} +283 -76
- package/dist/EndpointFactory-c2ZugGig.mjs.map +1 -0
- package/dist/Function-B0uZhZnU.d.cts +76 -0
- package/dist/Function-B0uZhZnU.d.cts.map +1 -0
- package/dist/Function-B_9R7Zy1.d.mts +76 -0
- package/dist/Function-B_9R7Zy1.d.mts.map +1 -0
- package/dist/{HonoEndpointAdaptor-DtL9j19R.cjs → HonoEndpointAdaptor-CN1jjUBJ.cjs} +115 -71
- package/dist/HonoEndpointAdaptor-CN1jjUBJ.cjs.map +1 -0
- package/dist/{HonoEndpointAdaptor-P1ahhZHu.mjs → HonoEndpointAdaptor-euH1oSdY.mjs} +105 -64
- package/dist/HonoEndpointAdaptor-euH1oSdY.mjs.map +1 -0
- package/dist/{Queue-D7ZuwBhy.d.cts → Queue-B-dDXyjF.d.mts} +48 -48
- package/dist/Queue-B-dDXyjF.d.mts.map +1 -0
- package/dist/Queue-BhuofM3k.cjs +109 -0
- package/dist/Queue-BhuofM3k.cjs.map +1 -0
- package/dist/{Queue-gVGfi2Yk.d.mts → Queue-JbIjVtTf.d.cts} +49 -49
- package/dist/Queue-JbIjVtTf.d.cts.map +1 -0
- package/dist/Queue-cmhqEBOB.mjs +104 -0
- package/dist/Queue-cmhqEBOB.mjs.map +1 -0
- package/dist/QueueBuilder-48W-q8In.d.mts +75 -0
- package/dist/QueueBuilder-48W-q8In.d.mts.map +1 -0
- package/dist/QueueBuilder-DXu1qxT1.mjs +118 -0
- package/dist/QueueBuilder-DXu1qxT1.mjs.map +1 -0
- package/dist/QueueBuilder-DdU2klPu.cjs +135 -0
- package/dist/QueueBuilder-DdU2klPu.cjs.map +1 -0
- package/dist/QueueBuilder-MfpkJ3R9.d.cts +75 -0
- package/dist/QueueBuilder-MfpkJ3R9.d.cts.map +1 -0
- package/dist/{Subscriber-2mEi0ImH.d.cts → Subscriber-CEt7kHkc.d.cts} +29 -20
- package/dist/Subscriber-CEt7kHkc.d.cts.map +1 -0
- package/dist/{Subscriber-xTJ9ayPN.d.mts → Subscriber-dsxc5LKa.d.mts} +29 -20
- package/dist/Subscriber-dsxc5LKa.d.mts.map +1 -0
- package/dist/SubscriberBuilder-BRa_nrmH.d.cts +67 -0
- package/dist/SubscriberBuilder-BRa_nrmH.d.cts.map +1 -0
- package/dist/SubscriberBuilder-D9bkrYzH.d.mts +67 -0
- package/dist/SubscriberBuilder-D9bkrYzH.d.mts.map +1 -0
- package/dist/{SubscriberBuilder-BjkbeT9l.mjs → SubscriberBuilder-DRXfxWn_.mjs} +50 -24
- package/dist/SubscriberBuilder-DRXfxWn_.mjs.map +1 -0
- package/dist/{SubscriberBuilder-4OPehf2R.cjs → SubscriberBuilder-M2EAgQhC.cjs} +61 -36
- package/dist/SubscriberBuilder-M2EAgQhC.cjs.map +1 -0
- package/dist/Topic-D2R0r24C.mjs +99 -0
- package/dist/Topic-D2R0r24C.mjs.map +1 -0
- package/dist/Topic-DwS3QO0m.cjs +104 -0
- package/dist/Topic-DwS3QO0m.cjs.map +1 -0
- package/dist/adaptors/aws.cjs +200 -246
- package/dist/adaptors/aws.cjs.map +1 -1
- package/dist/adaptors/aws.d.cts +58 -62
- package/dist/adaptors/aws.d.cts.map +1 -1
- package/dist/adaptors/aws.d.mts +59 -63
- package/dist/adaptors/aws.d.mts.map +1 -1
- package/dist/adaptors/aws.mjs +171 -219
- package/dist/adaptors/aws.mjs.map +1 -1
- package/dist/adaptors/hono.cjs +3 -10
- package/dist/adaptors/hono.d.cts +7 -16
- package/dist/adaptors/hono.d.cts.map +1 -1
- package/dist/adaptors/hono.d.mts +9 -18
- package/dist/adaptors/hono.d.mts.map +1 -1
- package/dist/adaptors/hono.mjs +2 -10
- package/dist/adaptors/testing.cjs +765 -99
- package/dist/adaptors/testing.cjs.map +1 -1
- package/dist/adaptors/testing.d.cts +351 -54
- package/dist/adaptors/testing.d.cts.map +1 -1
- package/dist/adaptors/testing.d.mts +351 -54
- package/dist/adaptors/testing.d.mts.map +1 -1
- package/dist/adaptors/testing.mjs +726 -78
- package/dist/adaptors/testing.mjs.map +1 -1
- package/dist/auth-BMCJN30Y.d.cts +268 -0
- package/dist/auth-BMCJN30Y.d.cts.map +1 -0
- package/dist/auth-D_0788uW.d.mts +268 -0
- package/dist/auth-D_0788uW.d.mts.map +1 -0
- package/dist/auth.cjs +301 -33
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +2 -108
- package/dist/auth.d.mts +2 -108
- package/dist/auth.mjs +289 -27
- package/dist/auth.mjs.map +1 -1
- package/dist/{cache-BrRz3fEB.d.mts → cache-5QZzh5Er.d.mts} +3 -6
- package/dist/cache-5QZzh5Er.d.mts.map +1 -0
- package/dist/{cache-BtZY_tHe.d.cts → cache-DnGDGly3.d.cts} +3 -6
- package/dist/cache-DnGDGly3.d.cts.map +1 -0
- package/dist/cache.cjs +68 -2
- package/dist/cache.cjs.map +1 -0
- package/dist/cache.d.cts +1 -2
- package/dist/cache.d.mts +1 -2
- package/dist/cache.mjs +67 -2
- package/dist/cache.mjs.map +1 -0
- package/dist/cipher-C1lEFX63.mjs +225 -0
- package/dist/cipher-C1lEFX63.mjs.map +1 -0
- package/dist/cipher-CVxfwLjk.cjs +332 -0
- package/dist/cipher-CVxfwLjk.cjs.map +1 -0
- package/dist/cipher-DSDxPRIp.d.cts +106 -0
- package/dist/cipher-DSDxPRIp.d.cts.map +1 -0
- package/dist/cipher-DSDxPRIp.d.mts +106 -0
- package/dist/cipher-DSDxPRIp.d.mts.map +1 -0
- package/dist/{clone-DblgEZZa.mjs → clone-EKNovYHu.mjs} +3 -3
- package/dist/clone-EKNovYHu.mjs.map +1 -0
- package/dist/{clone-Dy0cR2SZ.cjs → clone-UGJpvQnL.cjs} +7 -8
- package/dist/clone-UGJpvQnL.cjs.map +1 -0
- package/dist/{construct-interface-D9d4Gm4p.d.cts → construct-interface-B1AfqRl4.d.cts} +42 -11
- package/dist/construct-interface-B1AfqRl4.d.cts.map +1 -0
- package/dist/{construct-interface-g5GM5pwR.d.mts → construct-interface-ZvYQbivO.d.mts} +42 -11
- package/dist/construct-interface-ZvYQbivO.d.mts.map +1 -0
- package/dist/construct-interface.cjs +113 -7
- package/dist/construct-interface.cjs.map +1 -0
- package/dist/construct-interface.d.cts +2 -2
- package/dist/construct-interface.d.mts +2 -2
- package/dist/construct-interface.mjs +106 -2
- package/dist/construct-interface.mjs.map +1 -0
- package/dist/credential-DYymbp_7.cjs +257 -0
- package/dist/credential-DYymbp_7.cjs.map +1 -0
- package/dist/credential-DfSAOOdY.mjs +222 -0
- package/dist/credential-DfSAOOdY.mjs.map +1 -0
- package/dist/credential.cjs +8 -96
- package/dist/credential.d.cts +2 -61
- package/dist/credential.d.mts +2 -61
- package/dist/credential.mjs +2 -94
- package/dist/crons/index.cjs +129 -7
- package/dist/crons/index.cjs.map +1 -1
- package/dist/crons/index.d.cts +45 -11
- package/dist/crons/index.d.cts.map +1 -1
- package/dist/crons/index.d.mts +45 -11
- package/dist/crons/index.d.mts.map +1 -1
- package/dist/crons/index.mjs +127 -8
- package/dist/crons/index.mjs.map +1 -1
- package/dist/database/kysely.cjs +4 -181
- package/dist/database/kysely.d.cts +2 -152
- package/dist/database/kysely.d.mts +2 -152
- package/dist/database/kysely.mjs +2 -180
- package/dist/email.cjs +25 -12
- package/dist/email.cjs.map +1 -1
- package/dist/email.d.cts +3 -7
- package/dist/email.d.cts.map +1 -1
- package/dist/email.d.mts +4 -8
- package/dist/email.d.mts.map +1 -1
- package/dist/email.mjs +16 -3
- package/dist/email.mjs.map +1 -1
- package/dist/encryption/kms.cjs +95 -0
- package/dist/encryption/kms.cjs.map +1 -0
- package/dist/encryption/kms.d.cts +7 -0
- package/dist/encryption/kms.d.cts.map +1 -0
- package/dist/encryption/kms.d.mts +7 -0
- package/dist/encryption/kms.d.mts.map +1 -0
- package/dist/encryption/kms.mjs +93 -0
- package/dist/encryption/kms.mjs.map +1 -0
- package/dist/encryption.cjs +116 -0
- package/dist/encryption.cjs.map +1 -0
- package/dist/encryption.d.cts +37 -0
- package/dist/encryption.d.cts.map +1 -0
- package/dist/encryption.d.mts +37 -0
- package/dist/encryption.d.mts.map +1 -0
- package/dist/encryption.mjs +101 -0
- package/dist/encryption.mjs.map +1 -0
- package/dist/endpoints/index.cjs +27 -16
- package/dist/endpoints/index.d.cts +105 -7
- package/dist/endpoints/index.d.cts.map +1 -0
- package/dist/endpoints/index.d.mts +105 -7
- package/dist/endpoints/index.d.mts.map +1 -0
- package/dist/endpoints/index.mjs +6 -10
- package/dist/expire-C586zznE.d.cts +38 -0
- package/dist/expire-C586zznE.d.cts.map +1 -0
- package/dist/expire-C586zznE.d.mts +38 -0
- package/dist/expire-C586zznE.d.mts.map +1 -0
- package/dist/expire-CieftS01.cjs +67 -0
- package/dist/expire-CieftS01.cjs.map +1 -0
- package/dist/expire-CpzUAfr9.mjs +50 -0
- package/dist/expire-CpzUAfr9.mjs.map +1 -0
- package/dist/external-api.cjs +106 -0
- package/dist/external-api.cjs.map +1 -0
- package/dist/external-api.d.cts +2 -0
- package/dist/external-api.d.mts +2 -0
- package/dist/external-api.mjs +103 -0
- package/dist/external-api.mjs.map +1 -0
- package/dist/fake-B7rvi4Qp.d.cts +201 -0
- package/dist/fake-B7rvi4Qp.d.cts.map +1 -0
- package/dist/fake-JXbkdao8.d.mts +201 -0
- package/dist/fake-JXbkdao8.d.mts.map +1 -0
- package/dist/file-server.cjs +66 -11
- package/dist/file-server.cjs.map +1 -1
- package/dist/file-server.d.cts +25 -10
- package/dist/file-server.d.cts.map +1 -1
- package/dist/file-server.d.mts +25 -10
- package/dist/file-server.d.mts.map +1 -1
- package/dist/file-server.mjs +58 -4
- package/dist/file-server.mjs.map +1 -1
- package/dist/functions/index.cjs +3 -6
- package/dist/functions/index.d.cts +3 -4
- package/dist/functions/index.d.mts +3 -4
- package/dist/functions/index.mjs +2 -6
- package/dist/{functions-14lpEFL4.mjs → functions-CTI-hDem.mjs} +376 -238
- package/dist/{functions-14lpEFL4.mjs.map → functions-CTI-hDem.mjs.map} +1 -1
- package/dist/{functions-i_la-N5r.cjs → functions-D7O5SGVc.cjs} +414 -264
- package/dist/functions-D7O5SGVc.cjs.map +1 -0
- package/dist/index-Cd2w-DRL.d.cts +115 -0
- package/dist/index-Cd2w-DRL.d.cts.map +1 -0
- package/dist/index-DdRjYhiJ.d.cts +119 -0
- package/dist/index-DdRjYhiJ.d.cts.map +1 -0
- package/dist/index-DdRjYhiJ.d.mts +119 -0
- package/dist/index-DdRjYhiJ.d.mts.map +1 -0
- package/dist/index-aBIcAiH5.d.mts +115 -0
- package/dist/index-aBIcAiH5.d.mts.map +1 -0
- package/dist/index.cjs +6 -3
- package/dist/index.d.cts +27 -4
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +27 -4
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +3 -3
- package/dist/kysely-BHYV-WC-.d.cts +216 -0
- package/dist/kysely-BHYV-WC-.d.cts.map +1 -0
- package/dist/kysely-CAW3QSqp.d.mts +216 -0
- package/dist/kysely-CAW3QSqp.d.mts.map +1 -0
- package/dist/kysely-Cs4uPO8k.mjs +371 -0
- package/dist/kysely-Cs4uPO8k.mjs.map +1 -0
- package/dist/kysely-CukArHJ0.cjs +384 -0
- package/dist/kysely-CukArHJ0.cjs.map +1 -0
- package/dist/{telemetry-C3L0iS28.d.cts → lambdaTelemetry-8vnmVZQ5.d.cts} +3 -6
- package/dist/lambdaTelemetry-8vnmVZQ5.d.cts.map +1 -0
- package/dist/{telemetry-D7bVFLGi.d.mts → lambdaTelemetry-8vnmVZQ5.d.mts} +3 -6
- package/dist/lambdaTelemetry-8vnmVZQ5.d.mts.map +1 -0
- package/dist/mobile-app.cjs +74 -0
- package/dist/mobile-app.cjs.map +1 -0
- package/dist/mobile-app.d.cts +73 -0
- package/dist/mobile-app.d.cts.map +1 -0
- package/dist/mobile-app.d.mts +73 -0
- package/dist/mobile-app.d.mts.map +1 -0
- package/dist/mobile-app.mjs +73 -0
- package/dist/mobile-app.mjs.map +1 -0
- package/dist/object-storage.cjs +26 -11
- package/dist/object-storage.cjs.map +1 -1
- package/dist/object-storage.d.cts +12 -7
- package/dist/object-storage.d.cts.map +1 -1
- package/dist/object-storage.d.mts +12 -7
- package/dist/object-storage.d.mts.map +1 -1
- package/dist/object-storage.mjs +18 -5
- package/dist/object-storage.mjs.map +1 -1
- package/dist/queue/index.cjs +6 -189
- package/dist/queue/index.d.cts +3 -60
- package/dist/queue/index.d.mts +3 -60
- package/dist/queue/index.mjs +3 -186
- package/dist/random-password.cjs +86 -0
- package/dist/random-password.cjs.map +1 -0
- package/dist/random-password.d.cts +30 -0
- package/dist/random-password.d.cts.map +1 -0
- package/dist/random-password.d.mts +30 -0
- package/dist/random-password.d.mts.map +1 -0
- package/dist/random-password.mjs +84 -0
- package/dist/random-password.mjs.map +1 -0
- package/dist/{lazyAccessors-BoJN3SMd.mjs → readRequestBody-BTIl3k-D.mjs} +117 -60
- package/dist/readRequestBody-BTIl3k-D.mjs.map +1 -0
- package/dist/readRequestBody-Dej_L3c4.cjs +342 -0
- package/dist/readRequestBody-Dej_L3c4.cjs.map +1 -0
- package/dist/requestLogger-BZcXwdBs.cjs +207 -0
- package/dist/requestLogger-BZcXwdBs.cjs.map +1 -0
- package/dist/requestLogger-pA4gi3E1.mjs +178 -0
- package/dist/requestLogger-pA4gi3E1.mjs.map +1 -0
- package/dist/rest-api.cjs +90 -59
- package/dist/rest-api.cjs.map +1 -1
- package/dist/rest-api.d.cts +70 -42
- package/dist/rest-api.d.cts.map +1 -1
- package/dist/rest-api.d.mts +70 -42
- package/dist/rest-api.d.mts.map +1 -1
- package/dist/rest-api.mjs +82 -51
- package/dist/rest-api.mjs.map +1 -1
- package/dist/{chunk-DWy1uDak.cjs → rolldown-runtime-y5ARvAq5.cjs} +14 -18
- package/dist/runSubscriber-BHvJ8POr.mjs +109 -0
- package/dist/runSubscriber-BHvJ8POr.mjs.map +1 -0
- package/dist/runSubscriber-D8nLXIv1.cjs +126 -0
- package/dist/runSubscriber-D8nLXIv1.cjs.map +1 -0
- package/dist/shutdown-BMJmAhSt.cjs +38 -0
- package/dist/shutdown-BMJmAhSt.cjs.map +1 -0
- package/dist/shutdown-C7xa8x9S.mjs +27 -0
- package/dist/shutdown-C7xa8x9S.mjs.map +1 -0
- package/dist/site.cjs +33 -7
- package/dist/site.cjs.map +1 -1
- package/dist/site.d.cts +17 -7
- package/dist/site.d.cts.map +1 -1
- package/dist/site.d.mts +17 -7
- package/dist/site.d.mts.map +1 -1
- package/dist/site.mjs +29 -3
- package/dist/site.mjs.map +1 -1
- package/dist/stages-BSCF19o2.d.cts +56 -0
- package/dist/stages-BSCF19o2.d.cts.map +1 -0
- package/dist/stages-BSCF19o2.d.mts +56 -0
- package/dist/stages-BSCF19o2.d.mts.map +1 -0
- package/dist/subscribers/index.cjs +118 -6
- package/dist/subscribers/index.cjs.map +1 -0
- package/dist/subscribers/index.d.cts +51 -6
- package/dist/subscribers/index.d.cts.map +1 -0
- package/dist/subscribers/index.d.mts +51 -6
- package/dist/subscribers/index.d.mts.map +1 -0
- package/dist/subscribers/index.mjs +115 -5
- package/dist/subscribers/index.mjs.map +1 -0
- package/dist/surfaceEnv-CNimK76p.cjs +56 -0
- package/dist/surfaceEnv-CNimK76p.cjs.map +1 -0
- package/dist/surfaceEnv-wMT5QzgZ.mjs +45 -0
- package/dist/surfaceEnv-wMT5QzgZ.mjs.map +1 -0
- package/dist/telemetry-B48RLjyk.d.cts +40 -0
- package/dist/telemetry-B48RLjyk.d.cts.map +1 -0
- package/dist/telemetry-BEoBn6GO.d.mts +40 -0
- package/dist/telemetry-BEoBn6GO.d.mts.map +1 -0
- package/dist/telemetry.cjs +56 -0
- package/dist/telemetry.cjs.map +1 -0
- package/dist/telemetry.d.cts +2 -0
- package/dist/telemetry.d.mts +2 -0
- package/dist/telemetry.mjs +55 -0
- package/dist/telemetry.mjs.map +1 -0
- package/dist/topic/index.cjs +3 -137
- package/dist/topic/index.d.cts +2 -4
- package/dist/topic/index.d.mts +2 -4
- package/dist/topic/index.mjs +2 -134
- package/dist/tracing-Bbj1uoFJ.mjs +127 -0
- package/dist/tracing-Bbj1uoFJ.mjs.map +1 -0
- package/dist/tracing-C0ooU0V2.cjs +150 -0
- package/dist/tracing-C0ooU0V2.cjs.map +1 -0
- package/dist/{types-BlAkSuGI.d.cts → types-DMuSQeLL.d.cts} +3 -5
- package/dist/types-DMuSQeLL.d.cts.map +1 -0
- package/dist/{types-aKksMEWL.d.mts → types-DMuSQeLL.d.mts} +3 -5
- package/dist/types-DMuSQeLL.d.mts.map +1 -0
- package/dist/types.d.cts +1 -1
- package/dist/types.d.mts +1 -1
- package/dist/types.mjs +1 -0
- package/dist/worker.cjs +59 -34
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.cts +70 -45
- package/dist/worker.d.cts.map +1 -1
- package/dist/worker.d.mts +71 -45
- package/dist/worker.d.mts.map +1 -1
- package/dist/worker.mjs +54 -29
- package/dist/worker.mjs.map +1 -1
- package/package.json +115 -41
- package/dist/Construct-BD5neF7w.mjs.map +0 -1
- package/dist/Construct-C0ijr2qp.d.cts +0 -117
- package/dist/Construct-C0ijr2qp.d.cts.map +0 -1
- package/dist/Construct-Ct8nalEi.d.mts +0 -117
- package/dist/Construct-Ct8nalEi.d.mts.map +0 -1
- package/dist/Construct-CyS3RpTL.cjs.map +0 -1
- package/dist/Cron-DmQ8vQ4b.d.cts.map +0 -1
- package/dist/Cron-dh4rUgib.d.mts.map +0 -1
- package/dist/CronBuilder-BquXDbDI.d.cts +0 -44
- package/dist/CronBuilder-BquXDbDI.d.cts.map +0 -1
- package/dist/CronBuilder-CGgY2080.d.mts +0 -44
- package/dist/CronBuilder-CGgY2080.d.mts.map +0 -1
- package/dist/CronBuilder-CYKT5RiO.mjs.map +0 -1
- package/dist/CronBuilder-Da0C0edR.cjs.map +0 -1
- package/dist/Endpoint-BjWKinFA.d.mts.map +0 -1
- package/dist/Endpoint-DCQPMdUX.mjs.map +0 -1
- package/dist/Endpoint-DcWXE-SZ.cjs.map +0 -1
- package/dist/Endpoint-dav89W6-.d.cts.map +0 -1
- package/dist/EndpointFactory-CdWB7wPw.cjs.map +0 -1
- package/dist/EndpointFactory-CjV8F_lJ.mjs.map +0 -1
- package/dist/HonoEndpointAdaptor-DtL9j19R.cjs.map +0 -1
- package/dist/HonoEndpointAdaptor-P1ahhZHu.mjs.map +0 -1
- package/dist/Queue-D7ZuwBhy.d.cts.map +0 -1
- package/dist/Queue-gVGfi2Yk.d.mts.map +0 -1
- package/dist/Subscriber-2mEi0ImH.d.cts.map +0 -1
- package/dist/Subscriber-xTJ9ayPN.d.mts.map +0 -1
- package/dist/SubscriberBuilder-4OPehf2R.cjs.map +0 -1
- package/dist/SubscriberBuilder-BjkbeT9l.mjs.map +0 -1
- package/dist/SubscriberBuilder-Dptmo-1A.d.mts +0 -62
- package/dist/SubscriberBuilder-Dptmo-1A.d.mts.map +0 -1
- package/dist/SubscriberBuilder-waNhzjSM.d.cts +0 -62
- package/dist/SubscriberBuilder-waNhzjSM.d.cts.map +0 -1
- package/dist/Topic-19QeHBIR.d.cts +0 -91
- package/dist/Topic-19QeHBIR.d.cts.map +0 -1
- package/dist/Topic-DuFeqkBh.d.mts +0 -91
- package/dist/Topic-DuFeqkBh.d.mts.map +0 -1
- package/dist/auth.d.cts.map +0 -1
- package/dist/auth.d.mts.map +0 -1
- package/dist/cache-0ANvRQnD.mjs +0 -51
- package/dist/cache-0ANvRQnD.mjs.map +0 -1
- package/dist/cache-3WSvAulx.cjs +0 -57
- package/dist/cache-3WSvAulx.cjs.map +0 -1
- package/dist/cache-BrRz3fEB.d.mts.map +0 -1
- package/dist/cache-BtZY_tHe.d.cts.map +0 -1
- package/dist/clone-DblgEZZa.mjs.map +0 -1
- package/dist/clone-Dy0cR2SZ.cjs.map +0 -1
- package/dist/construct-interface-BfjcOD_E.cjs +0 -117
- package/dist/construct-interface-BfjcOD_E.cjs.map +0 -1
- package/dist/construct-interface-D9d4Gm4p.d.cts.map +0 -1
- package/dist/construct-interface-Z4CpS8tK.mjs +0 -81
- package/dist/construct-interface-Z4CpS8tK.mjs.map +0 -1
- package/dist/construct-interface-g5GM5pwR.d.mts.map +0 -1
- package/dist/credential.cjs.map +0 -1
- package/dist/credential.d.cts.map +0 -1
- package/dist/credential.d.mts.map +0 -1
- package/dist/credential.mjs.map +0 -1
- package/dist/database/kysely.cjs.map +0 -1
- package/dist/database/kysely.d.cts.map +0 -1
- package/dist/database/kysely.d.mts.map +0 -1
- package/dist/database/kysely.mjs.map +0 -1
- package/dist/functions-i_la-N5r.cjs.map +0 -1
- package/dist/index-Bd5FqCoe.d.cts.map +0 -1
- package/dist/index-BknhM6Ux.d.mts +0 -31
- package/dist/index-BknhM6Ux.d.mts.map +0 -1
- package/dist/index-CBSfrowv.d.cts +0 -31
- package/dist/index-CBSfrowv.d.cts.map +0 -1
- package/dist/index-D24Xm79M.d.cts +0 -171
- package/dist/index-D24Xm79M.d.cts.map +0 -1
- package/dist/index-_ajboYxK.d.mts +0 -171
- package/dist/index-_ajboYxK.d.mts.map +0 -1
- package/dist/index-lAO9egTb.d.mts.map +0 -1
- package/dist/lazyAccessors-BoJN3SMd.mjs.map +0 -1
- package/dist/lazyAccessors-e3j2oE2m.cjs +0 -274
- package/dist/lazyAccessors-e3j2oE2m.cjs.map +0 -1
- package/dist/processAudits-CGqttuXm.cjs +0 -92
- package/dist/processAudits-CGqttuXm.cjs.map +0 -1
- package/dist/processAudits-Dmts9H_b.mjs +0 -80
- package/dist/processAudits-Dmts9H_b.mjs.map +0 -1
- package/dist/queue/index.cjs.map +0 -1
- package/dist/queue/index.d.cts.map +0 -1
- package/dist/queue/index.d.mts.map +0 -1
- package/dist/queue/index.mjs.map +0 -1
- package/dist/surfaceEnv-BFXEms2f.cjs +0 -39
- package/dist/surfaceEnv-BFXEms2f.cjs.map +0 -1
- package/dist/surfaceEnv-C3Ktahea.mjs +0 -27
- package/dist/surfaceEnv-C3Ktahea.mjs.map +0 -1
- package/dist/telemetry-C3L0iS28.d.cts.map +0 -1
- package/dist/telemetry-D7bVFLGi.d.mts.map +0 -1
- package/dist/topic/index.cjs.map +0 -1
- package/dist/topic/index.mjs.map +0 -1
- package/dist/types-BlAkSuGI.d.cts.map +0 -1
- package/dist/types-aKksMEWL.d.mts.map +0 -1
package/README.md
CHANGED
|
@@ -26,21 +26,20 @@ pnpm add @geekmidas/constructs
|
|
|
26
26
|
|
|
27
27
|
```typescript
|
|
28
28
|
// The HTTP surface. Endpoints are built from it — `api.get(…)`, or
|
|
29
|
-
// `api.
|
|
29
|
+
// `api.database(db)` for a branch that a group of endpoints shares.
|
|
30
30
|
import { RestApi } from '@geekmidas/constructs/rest-api';
|
|
31
31
|
|
|
32
32
|
// Endpoint internals: the factory a surface hands you, and the builder it
|
|
33
33
|
// returns. There is no free-standing `e` — an endpoint belongs to a surface.
|
|
34
34
|
import { EndpointBuilder, EndpointFactory } from '@geekmidas/constructs/endpoints';
|
|
35
35
|
|
|
36
|
-
//
|
|
37
|
-
|
|
36
|
+
// The process with no port. Crons, topic subscribers, queues and functions
|
|
37
|
+
// are built from it — `worker.cron(…)`, `worker.topic(…)`, `worker.queue(…)`,
|
|
38
|
+
// `worker.input(…)` — and carry its logger.
|
|
39
|
+
import { Worker } from '@geekmidas/constructs/worker';
|
|
38
40
|
|
|
39
|
-
//
|
|
40
|
-
import {
|
|
41
|
-
|
|
42
|
-
// Subscribers
|
|
43
|
-
import { s, SubscriberBuilder } from '@geekmidas/constructs/subscribers';
|
|
41
|
+
// A declared event contract. Its publisher is its `service`.
|
|
42
|
+
import { Topic } from '@geekmidas/constructs/topic';
|
|
44
43
|
```
|
|
45
44
|
|
|
46
45
|
## Quick Start
|
|
@@ -126,15 +125,31 @@ export const searchUsers = api
|
|
|
126
125
|
});
|
|
127
126
|
```
|
|
128
127
|
|
|
128
|
+
### The Worker
|
|
129
|
+
|
|
130
|
+
Everything that is not an HTTP route is built from a `Worker`: the process
|
|
131
|
+
that runs a schedule, drains a queue or consumes a topic. It takes no
|
|
132
|
+
authorizer, because nothing reaches it from outside.
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// constructs/worker.ts
|
|
136
|
+
import { Worker } from '@geekmidas/constructs/worker';
|
|
137
|
+
import { database } from './database';
|
|
138
|
+
import { logger } from './logger';
|
|
139
|
+
|
|
140
|
+
// `.database(…)` is where a server target keeps cron schedules.
|
|
141
|
+
export const worker = new Worker('Jobs', { logger }).database(database);
|
|
142
|
+
```
|
|
143
|
+
|
|
129
144
|
### Cloud Functions
|
|
130
145
|
|
|
131
|
-
Create
|
|
146
|
+
Create functions with input/output validation:
|
|
132
147
|
|
|
133
148
|
```typescript
|
|
134
|
-
import {
|
|
149
|
+
import { worker } from '../constructs/worker';
|
|
135
150
|
import { z } from 'zod';
|
|
136
151
|
|
|
137
|
-
export const processOrder =
|
|
152
|
+
export const processOrder = worker
|
|
138
153
|
.input(z.object({
|
|
139
154
|
orderId: z.string(),
|
|
140
155
|
items: z.array(z.object({
|
|
@@ -145,13 +160,12 @@ export const processOrder = f
|
|
|
145
160
|
.output(z.object({
|
|
146
161
|
orderId: z.string(),
|
|
147
162
|
status: z.enum(['processing', 'completed', 'failed']),
|
|
148
|
-
processedAt: z.
|
|
163
|
+
processedAt: z.iso.datetime()
|
|
149
164
|
}))
|
|
150
165
|
.timeout(300000) // 5 minutes
|
|
151
166
|
.handle(async ({ input, logger }) => {
|
|
152
167
|
logger.info(`Processing order ${input.orderId}`);
|
|
153
168
|
|
|
154
|
-
// Process order logic
|
|
155
169
|
for (const item of input.items) {
|
|
156
170
|
logger.info(`Processing item ${item.id}, quantity: ${item.quantity}`);
|
|
157
171
|
}
|
|
@@ -166,87 +180,99 @@ export const processOrder = f
|
|
|
166
180
|
|
|
167
181
|
### Scheduled Tasks (Crons)
|
|
168
182
|
|
|
169
|
-
Define cron jobs with schedules:
|
|
170
|
-
|
|
171
183
|
```typescript
|
|
172
|
-
import {
|
|
184
|
+
import { worker } from '../constructs/worker';
|
|
173
185
|
|
|
174
186
|
// Daily report at 9 AM UTC
|
|
175
|
-
export const dailyReport =
|
|
176
|
-
.
|
|
187
|
+
export const dailyReport = worker
|
|
188
|
+
.cron('cron(0 9 * * ? *)')
|
|
177
189
|
.timeout(600000) // 10 minutes
|
|
178
190
|
.handle(async ({ logger }) => {
|
|
179
|
-
logger.info('Generating daily report');
|
|
180
|
-
|
|
181
|
-
const reportDate = new Date().toISOString().split('T')[0];
|
|
182
191
|
const reportData = {
|
|
183
|
-
date:
|
|
192
|
+
date: new Date().toISOString().split('T')[0],
|
|
184
193
|
totalOrders: 150,
|
|
185
|
-
totalRevenue: 12500.00
|
|
186
194
|
};
|
|
187
195
|
|
|
188
|
-
logger.info('Daily report generated'
|
|
196
|
+
logger.info(reportData, 'Daily report generated');
|
|
189
197
|
return reportData;
|
|
190
198
|
});
|
|
191
199
|
|
|
192
200
|
// Hourly cleanup
|
|
193
|
-
export const hourlyCleanup =
|
|
194
|
-
.
|
|
195
|
-
.
|
|
196
|
-
.handle(async ({ logger }) => {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
+
export const hourlyCleanup = worker
|
|
202
|
+
.cron('rate(1 hour)')
|
|
203
|
+
.dependsOn([database])
|
|
204
|
+
.handle(async ({ services, logger }) => {
|
|
205
|
+
const result = await services.database
|
|
206
|
+
.deleteFrom('sessions')
|
|
207
|
+
.where('expires_at', '<', new Date())
|
|
208
|
+
.executeTakeFirst();
|
|
201
209
|
|
|
202
|
-
|
|
210
|
+
logger.info({ deleted: Number(result.numDeletedRows) }, 'Cleaned up');
|
|
203
211
|
});
|
|
204
212
|
```
|
|
205
213
|
|
|
206
|
-
|
|
214
|
+
On AWS a cron is an EventBridge rule; on a server the worker schedules it in
|
|
215
|
+
the database it was given.
|
|
216
|
+
|
|
217
|
+
### Topics and Subscribers
|
|
207
218
|
|
|
208
|
-
|
|
219
|
+
A topic declares the event contract once. A subscriber binds to it from the
|
|
220
|
+
worker and is typed by it:
|
|
209
221
|
|
|
210
222
|
```typescript
|
|
211
|
-
|
|
223
|
+
// constructs/topics.ts
|
|
224
|
+
import { Topic } from '@geekmidas/constructs/topic';
|
|
212
225
|
import { z } from 'zod';
|
|
213
226
|
|
|
214
|
-
export const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}))
|
|
221
|
-
.handle(async ({ events, logger }) => {
|
|
222
|
-
logger.info(
|
|
223
|
-
{ eventCount: events.length },
|
|
224
|
-
'Processing user events'
|
|
225
|
-
);
|
|
227
|
+
export const users = new Topic('Users', {
|
|
228
|
+
events: {
|
|
229
|
+
'user.created': z.object({ userId: z.string(), email: z.email() }),
|
|
230
|
+
'user.updated': z.object({ userId: z.string(), changes: z.array(z.string()) }),
|
|
231
|
+
},
|
|
232
|
+
});
|
|
226
233
|
|
|
234
|
+
// subscribers/userEvents.ts
|
|
235
|
+
export const userEventsSubscriber = worker
|
|
236
|
+
.topic(users)
|
|
237
|
+
.subscribe(['user.created', 'user.updated'])
|
|
238
|
+
.handle(async ({ events, logger }) => {
|
|
227
239
|
for (const event of events) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
case 'user.created':
|
|
231
|
-
logger.info({ userId: event.data.userId }, 'User created');
|
|
232
|
-
break;
|
|
233
|
-
case 'user.updated':
|
|
234
|
-
logger.info({ userId: event.data.userId }, 'User updated');
|
|
235
|
-
break;
|
|
236
|
-
case 'user.deleted':
|
|
237
|
-
logger.info({ userId: event.data.userId }, 'User deleted');
|
|
238
|
-
break;
|
|
239
|
-
}
|
|
240
|
-
} catch (error) {
|
|
241
|
-
logger.error({ error, event }, 'Failed to process event');
|
|
242
|
-
throw error;
|
|
243
|
-
}
|
|
240
|
+
// event.type narrows event.payload to that event's schema
|
|
241
|
+
logger.info({ type: event.type, userId: event.payload.userId }, 'User event');
|
|
244
242
|
}
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
245
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
246
|
+
A subscriber is bound, not handed a publisher. One that emits follow-ups
|
|
247
|
+
depends on the topic it emits to: `.dependsOn([notifications])`.
|
|
248
|
+
|
|
249
|
+
### Queues
|
|
250
|
+
|
|
251
|
+
A queue and its one consumer are one construct. Producers send by depending on
|
|
252
|
+
it:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// queues/emails.ts
|
|
256
|
+
export const emails = worker
|
|
257
|
+
.queue('Emails')
|
|
258
|
+
.message(z.object({ to: z.email(), template: z.enum(['welcome']) }))
|
|
259
|
+
.dependsOn([mail])
|
|
260
|
+
.handle(async ({ messages, services }) => {
|
|
261
|
+
for (const { to, template } of messages) {
|
|
262
|
+
await services.mail.sendTemplate(template, { to, subject: 'Welcome', props: {} });
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// endpoints/invites.ts
|
|
267
|
+
export const invite = api
|
|
268
|
+
.post('/invites')
|
|
269
|
+
.body(z.object({ email: z.email() }))
|
|
270
|
+
.dependsOn([emails])
|
|
271
|
+
.handle(async ({ body, services }) => {
|
|
272
|
+
// `type` is the queue's name exactly as written
|
|
273
|
+
await services.emails.publish([
|
|
274
|
+
{ type: 'Emails', payload: { to: body.email, template: 'welcome' } },
|
|
275
|
+
]);
|
|
250
276
|
});
|
|
251
277
|
```
|
|
252
278
|
|
|
@@ -289,7 +315,7 @@ For custom authentication methods, use `.securitySchemes()` on the surface's fac
|
|
|
289
315
|
```typescript
|
|
290
316
|
import { api } from '../constructs/api';
|
|
291
317
|
|
|
292
|
-
const router = api
|
|
318
|
+
const router = api
|
|
293
319
|
.securitySchemes({
|
|
294
320
|
// Custom OAuth2 with specific flows
|
|
295
321
|
oauth2: {
|
|
@@ -328,7 +354,7 @@ Set a default authorizer for every endpoint built from one branch:
|
|
|
328
354
|
// A branch of the surface's factory, with a default every endpoint on it
|
|
329
355
|
// inherits. (The surface's own `default` does the same thing for every
|
|
330
356
|
// endpoint it serves — this narrows it for one group.)
|
|
331
|
-
const router = api.
|
|
357
|
+
const router = api.authorizer('jwt');
|
|
332
358
|
|
|
333
359
|
// Protected by default
|
|
334
360
|
export const getProfile = router
|
|
@@ -344,99 +370,69 @@ export const getHealth = router
|
|
|
344
370
|
.handle(async () => ({ status: 'ok' }));
|
|
345
371
|
```
|
|
346
372
|
|
|
347
|
-
###
|
|
373
|
+
### Dependencies
|
|
348
374
|
|
|
349
|
-
|
|
375
|
+
`.dependsOn([...])` takes constructs. Each one's client lands in the handler's
|
|
376
|
+
`services` under the construct's own id, and the edge is what the manifest
|
|
377
|
+
records — so the environment, the runtime client and the cloud access all come
|
|
378
|
+
from the one line:
|
|
350
379
|
|
|
351
380
|
```typescript
|
|
352
381
|
import { api } from '../constructs/api';
|
|
353
|
-
import
|
|
354
|
-
import type { EnvironmentParser } from '@geekmidas/envkit';
|
|
355
|
-
import { Kysely } from 'kysely';
|
|
382
|
+
import { database } from '../constructs/database';
|
|
356
383
|
import { z } from 'zod';
|
|
357
384
|
|
|
358
|
-
// Define a database service
|
|
359
|
-
const databaseService = {
|
|
360
|
-
serviceName: 'database' as const,
|
|
361
|
-
async register(envParser: EnvironmentParser<{}>) {
|
|
362
|
-
const config = envParser.create((get) => ({
|
|
363
|
-
url: get('DATABASE_URL').string()
|
|
364
|
-
})).parse();
|
|
365
|
-
|
|
366
|
-
const db = new Kysely({ /* config */ });
|
|
367
|
-
return db;
|
|
368
|
-
}
|
|
369
|
-
} satisfies Service<'database', Kysely<Database>>;
|
|
370
|
-
|
|
371
|
-
// Use service in endpoint
|
|
372
385
|
export const getUserFromDb = api
|
|
373
386
|
.get('/users/:id')
|
|
374
387
|
.params(z.object({ id: z.string() }))
|
|
375
|
-
.
|
|
388
|
+
.dependsOn([database])
|
|
376
389
|
.handle(async ({ params, services }) => {
|
|
377
|
-
// services.database is
|
|
378
|
-
|
|
390
|
+
// services.database is a Kysely client typed by the construct's schema
|
|
391
|
+
return services.database
|
|
379
392
|
.selectFrom('users')
|
|
380
393
|
.where('id', '=', params.id)
|
|
381
394
|
.selectAll()
|
|
382
395
|
.executeTakeFirst();
|
|
383
|
-
|
|
384
|
-
return user;
|
|
385
396
|
});
|
|
386
397
|
```
|
|
387
398
|
|
|
399
|
+
A hand-written `Service` still works through `.services()` on every builder,
|
|
400
|
+
for code that has not moved to a construct yet. It records no edge, so a deploy
|
|
401
|
+
target cannot grant it anything.
|
|
402
|
+
|
|
388
403
|
### Event Publishing
|
|
389
404
|
|
|
390
|
-
|
|
405
|
+
An endpoint, function or cron publishes to a topic with `.event(topic, …)`,
|
|
406
|
+
once its handler has succeeded:
|
|
391
407
|
|
|
392
408
|
```typescript
|
|
393
|
-
import {
|
|
394
|
-
import type { Service } from '@geekmidas/services';
|
|
395
|
-
import type { EventPublisher, PublishableMessage } from '@geekmidas/events';
|
|
396
|
-
import { z } from 'zod';
|
|
397
|
-
|
|
398
|
-
// Define event types
|
|
399
|
-
type UserEvents =
|
|
400
|
-
| PublishableMessage<'user.created', { userId: string; email: string }>
|
|
401
|
-
| PublishableMessage<'user.updated', { userId: string }>;
|
|
402
|
-
|
|
403
|
-
// Create event publisher service
|
|
404
|
-
const userEventPublisher = {
|
|
405
|
-
serviceName: 'userEventPublisher' as const,
|
|
406
|
-
async register(envParser: EnvironmentParser<{}>) {
|
|
407
|
-
const config = envParser.create((get) => ({
|
|
408
|
-
publisherUrl: get('EVENT_PUBLISHER_URL').string()
|
|
409
|
-
})).parse();
|
|
409
|
+
import { users } from '../constructs/topics';
|
|
410
410
|
|
|
411
|
-
|
|
412
|
-
return Publisher.fromConnectionString<UserEvents>(config.publisherUrl);
|
|
413
|
-
}
|
|
414
|
-
} satisfies Service<'userEventPublisher', EventPublisher<UserEvents>>;
|
|
415
|
-
|
|
416
|
-
// Use in endpoint with event publishing
|
|
417
|
-
export const createUser = api
|
|
411
|
+
export const createUser = router
|
|
418
412
|
.post('/users')
|
|
419
|
-
.body(z.object({
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}))
|
|
428
|
-
.handle(async ({ body, publish }) => {
|
|
429
|
-
const user = {
|
|
430
|
-
id: crypto.randomUUID(),
|
|
431
|
-
name: body.name,
|
|
432
|
-
email: body.email
|
|
433
|
-
};
|
|
434
|
-
|
|
435
|
-
// Events are automatically published after successful execution
|
|
436
|
-
return user;
|
|
437
|
-
});
|
|
413
|
+
.body(z.object({ name: z.string(), email: z.email() }))
|
|
414
|
+
.output(z.object({ id: z.string(), name: z.string(), email: z.email() }))
|
|
415
|
+
.event(users, {
|
|
416
|
+
type: 'user.created',
|
|
417
|
+
payload: (user) => ({ userId: user.id, email: user.email }),
|
|
418
|
+
when: (user) => !user.email.endsWith('@example.com'), // optional
|
|
419
|
+
})
|
|
420
|
+
.handle(async ({ body }) => ({ id: crypto.randomUUID(), ...body }));
|
|
438
421
|
```
|
|
439
422
|
|
|
423
|
+
- `type` is checked against the topic's events, and `payload` against that
|
|
424
|
+
event's schema.
|
|
425
|
+
- `.event()` is repeatable across topics. Two calls to two topics publish to
|
|
426
|
+
each, every event through its own topic's publisher.
|
|
427
|
+
- It also puts the topic's publisher in the handler as `services.users`, as
|
|
428
|
+
`.dependsOn([users])` would, for events the handler decides on:
|
|
429
|
+
`await services.users.publish([{ type: 'user.updated', payload }])`.
|
|
430
|
+
- A failed publish is logged, never thrown — the handler already succeeded.
|
|
431
|
+
|
|
432
|
+
The publisher reads `USERS_PUBLISHER_CONNECTION_STRING`, which only constructs
|
|
433
|
+
that publish to the topic are given, and picks its transport from the protocol:
|
|
434
|
+
`pgboss://` locally, `sns://` deployed.
|
|
435
|
+
|
|
440
436
|
### Database Context
|
|
441
437
|
|
|
442
438
|
Inject a database instance directly into the handler context using `.database()`:
|
|
@@ -633,10 +629,11 @@ For complex scenarios, use `ctx.auditor` to record audits manually within your h
|
|
|
633
629
|
|
|
634
630
|
```typescript
|
|
635
631
|
export const processOrder = api
|
|
636
|
-
.
|
|
637
|
-
.database(databaseService)
|
|
638
|
-
.services([paymentService])
|
|
632
|
+
.database(database)
|
|
639
633
|
.auditor(auditStorageService)
|
|
634
|
+
.post('/orders')
|
|
635
|
+
// `payments` is an ExternalApi whose client has `charge()`
|
|
636
|
+
.dependsOn([payments])
|
|
640
637
|
.actor(({ session }) => ({ id: session.userId, type: 'user' }))
|
|
641
638
|
.handle(async ({ body, db, services, auditor }) => {
|
|
642
639
|
// db is automatically the transaction when auditor uses KyselyAuditStorage
|
|
@@ -647,7 +644,7 @@ export const processOrder = api
|
|
|
647
644
|
.executeTakeFirstOrThrow();
|
|
648
645
|
|
|
649
646
|
// Manual audit for payment (external service call)
|
|
650
|
-
const payment = await services.
|
|
647
|
+
const payment = await services.payments.charge(order.total);
|
|
651
648
|
auditor.audit('payment.processed', {
|
|
652
649
|
orderId: order.id,
|
|
653
650
|
amount: order.total,
|
|
@@ -908,6 +905,69 @@ export const sendMessage = api
|
|
|
908
905
|
});
|
|
909
906
|
```
|
|
910
907
|
|
|
908
|
+
## Feature Tests
|
|
909
|
+
|
|
910
|
+
A feature test drives an app the way it runs deployed: a browser signs in and
|
|
911
|
+
calls the API, the API asks the auth server who is calling, each over its URL,
|
|
912
|
+
and every database is in its own transaction, rolled back after the test.
|
|
913
|
+
Nothing runs as a server — each URL an app's constructs answer on is served
|
|
914
|
+
in-process through MSW, from the real handler, for the test that made the
|
|
915
|
+
request. Postgres, Mailpit and MinIO are the real local ones `gkm test` starts.
|
|
916
|
+
|
|
917
|
+
Nothing is declared in test code. `gkm test` writes `.gkm/test/` into each app:
|
|
918
|
+
|
|
919
|
+
- `manifest.json` — which construct and endpoint is exported where, and the
|
|
920
|
+
test stage's environment, keyed as the constructs derive their keys;
|
|
921
|
+
- `clients/<surface>.ts` — each surface's typed client, from the same generator
|
|
922
|
+
`gkm build` uses;
|
|
923
|
+
- `index.ts` — a `Browser` with a client per surface (`Api` → `browser.api`)
|
|
924
|
+
and per auth server (`browser.auth`, its better-auth plugins paired with
|
|
925
|
+
their client plugins), and the configured `it`.
|
|
926
|
+
|
|
927
|
+
Map it once in the app's `package.json` — `"imports": { "#test":
|
|
928
|
+
"./.gkm/test/index.ts" }` — and a test is:
|
|
929
|
+
|
|
930
|
+
```typescript
|
|
931
|
+
import { it } from '#test';
|
|
932
|
+
|
|
933
|
+
it('shows the signed-in user their orders', async ({ browser, db, factories }) => {
|
|
934
|
+
const factory = await factories.get('database');
|
|
935
|
+
await factory.insert('orders', { email: 'ada@shop.test' });
|
|
936
|
+
|
|
937
|
+
await browser.signIn('ada@shop.test');
|
|
938
|
+
const { orders } = await browser.api.get('/orders');
|
|
939
|
+
expect(orders).toHaveLength(1);
|
|
940
|
+
|
|
941
|
+
const app = await db.get('database');
|
|
942
|
+
expect(await app.selectFrom('orders').selectAll().execute()).toHaveLength(1);
|
|
943
|
+
});
|
|
944
|
+
```
|
|
945
|
+
|
|
946
|
+
- **`browser`** — already the global `fetch`; its cookie jar follows the
|
|
947
|
+
browser's rules, so a session cookie set for the wrong domain never reaches
|
|
948
|
+
the API.
|
|
949
|
+
- **`browser.signIn(email)`** — when the auth server has the magic-link plugin
|
|
950
|
+
and the app sends mail: the link requested, read from the inbox and
|
|
951
|
+
followed, as a person signs in. Returns the session the auth server reports.
|
|
952
|
+
- **`db.get(name)`** — the app's own databases by service name
|
|
953
|
+
(`db.get('database')`), each this test's transaction, typed by its schema.
|
|
954
|
+
Opened on first use by whatever reaches it first — the test, a factory, an
|
|
955
|
+
endpoint — and the same one for all of them. A tenant an auth server owns is
|
|
956
|
+
not among them: it is reached through the auth server, as the app reaches
|
|
957
|
+
it. Nor is a reader.
|
|
958
|
+
- **`factories.get(name)`** — each of those databases' factory, from
|
|
959
|
+
`test/factories/<construct>.ts` at the project root, on the same
|
|
960
|
+
transaction: `(await factories.get('database')).insert('users', …)`.
|
|
961
|
+
- **`mailbox(address)`** — the mail actually sent, read from Mailpit.
|
|
962
|
+
- **`published(topic | queue)`** — what the test published or enqueued.
|
|
963
|
+
Nothing is delivered: a subscriber or a worker is run on its own with
|
|
964
|
+
**`subscriber(s).invoke({ events })`** / **`queue(q).invoke({ messages })`**,
|
|
965
|
+
on the test's services and transactions.
|
|
966
|
+
- Each database construct — the app's and each schema tenant — gets its own
|
|
967
|
+
transaction on its own connection, as deployed.
|
|
968
|
+
- A request that belongs to no running test is refused with
|
|
969
|
+
`UnknownTestContext` rather than reaching another test's data.
|
|
970
|
+
|
|
911
971
|
## AWS Lambda Adapters
|
|
912
972
|
|
|
913
973
|
Deploy your constructs to AWS Lambda:
|
|
@@ -1034,19 +1094,19 @@ Every construct has an async `getEnvironment()` method that returns the environm
|
|
|
1034
1094
|
|
|
1035
1095
|
```typescript
|
|
1036
1096
|
import { api } from '../constructs/api';
|
|
1037
|
-
import {
|
|
1038
|
-
import {
|
|
1097
|
+
import { cache } from '../constructs/cache';
|
|
1098
|
+
import { database } from '../constructs/database';
|
|
1039
1099
|
|
|
1040
1100
|
const endpoint = api
|
|
1041
1101
|
.get('/users')
|
|
1042
|
-
.
|
|
1102
|
+
.dependsOn([database, cache])
|
|
1043
1103
|
.handle(async ({ services }) => {
|
|
1044
1104
|
// Implementation
|
|
1045
1105
|
});
|
|
1046
1106
|
|
|
1047
1107
|
// Detect required environment variables
|
|
1048
1108
|
const envVars = await endpoint.getEnvironment();
|
|
1049
|
-
// Returns: ['
|
|
1109
|
+
// Returns: ['DATABASE_URL', 'SESSIONS_URL'] (sorted alphabetically)
|
|
1050
1110
|
```
|
|
1051
1111
|
|
|
1052
1112
|
### How It Works
|
|
@@ -1134,33 +1194,37 @@ This manifest can then be used by infrastructure-as-code tools (Terraform, CDK,
|
|
|
1134
1194
|
- **Deduplication**: Each variable listed once even if used by multiple services
|
|
1135
1195
|
- **Sorted Output**: Variables always returned in alphabetical order
|
|
1136
1196
|
- **Error Resilient**: Parse failures don't affect detection
|
|
1137
|
-
- **
|
|
1197
|
+
- **Topic Support**: A topic named by `.event(topic, …)` contributes its `<ID>_PUBLISHER_CONNECTION_STRING`
|
|
1138
1198
|
|
|
1139
1199
|
### Example with Multiple Services
|
|
1140
1200
|
|
|
1141
1201
|
```typescript
|
|
1142
1202
|
import { api } from '../constructs/api';
|
|
1143
|
-
import {
|
|
1144
|
-
import {
|
|
1145
|
-
import {
|
|
1203
|
+
import { cache } from '../constructs/cache';
|
|
1204
|
+
import { database } from '../constructs/database';
|
|
1205
|
+
import { mail } from '../constructs/email';
|
|
1206
|
+
import { users } from '../constructs/topics';
|
|
1146
1207
|
|
|
1147
1208
|
const endpoint = api
|
|
1148
1209
|
.post('/users')
|
|
1149
|
-
.
|
|
1210
|
+
.dependsOn([database, cache, mail])
|
|
1211
|
+
.output(userSchema)
|
|
1212
|
+
.event(users, {
|
|
1213
|
+
type: 'user.created',
|
|
1214
|
+
payload: (user) => ({ userId: user.id, email: user.email }),
|
|
1215
|
+
})
|
|
1150
1216
|
.handle(async ({ services }) => {
|
|
1151
1217
|
// Create user
|
|
1152
1218
|
});
|
|
1153
1219
|
|
|
1154
|
-
//
|
|
1220
|
+
// Detects the keys of every construct it names
|
|
1155
1221
|
const envVars = await endpoint.getEnvironment();
|
|
1156
1222
|
// Returns: [
|
|
1157
|
-
// 'CACHE_URL',
|
|
1158
1223
|
// 'DATABASE_URL',
|
|
1159
|
-
// '
|
|
1160
|
-
// '
|
|
1161
|
-
// '
|
|
1162
|
-
// '
|
|
1163
|
-
// 'SMTP_PASS'
|
|
1224
|
+
// 'MAIL_FROM',
|
|
1225
|
+
// 'MAIL_URL',
|
|
1226
|
+
// 'SESSIONS_URL',
|
|
1227
|
+
// 'USERS_PUBLISHER_CONNECTION_STRING'
|
|
1164
1228
|
// ]
|
|
1165
1229
|
```
|
|
1166
1230
|
|