@geekmidas/constructs 10.0.0-alpha.37 → 10.0.0-alpha.38
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/dist/{Cron-CA2oa2nC.d.cts → Cron-Brs_n_vQ.d.cts} +2 -2
- package/dist/{Cron-B_iuyNxr.d.mts.map → Cron-Brs_n_vQ.d.cts.map} +1 -1
- package/dist/{Cron-B_iuyNxr.d.mts → Cron-C18-2Lgb.d.mts} +2 -2
- package/dist/{Cron-CA2oa2nC.d.cts.map → Cron-C18-2Lgb.d.mts.map} +1 -1
- package/dist/{CronBuilder-B_KqaodP.d.cts → CronBuilder-4WnWKR40.d.cts} +4 -4
- package/dist/{CronBuilder-BIKCLWu7.d.mts.map → CronBuilder-4WnWKR40.d.cts.map} +1 -1
- package/dist/{CronBuilder-BIKCLWu7.d.mts → CronBuilder-CGv51EoE.d.mts} +4 -4
- package/dist/{CronBuilder-B_KqaodP.d.cts.map → CronBuilder-CGv51EoE.d.mts.map} +1 -1
- package/dist/{Endpoint-1-XYQSx0.d.cts → Endpoint-BkhPHCuX.d.cts} +4 -4
- package/dist/{Endpoint-1-XYQSx0.d.cts.map → Endpoint-BkhPHCuX.d.cts.map} +1 -1
- package/dist/{Endpoint-GFIxYb9L.d.mts → Endpoint-DkiD0GJs.d.mts} +4 -4
- package/dist/{Endpoint-GFIxYb9L.d.mts.map → Endpoint-DkiD0GJs.d.mts.map} +1 -1
- package/dist/{EndpointFactory-BCZdh_u3.d.mts → EndpointFactory-WJzZfkTW.d.mts} +4 -4
- package/dist/{EndpointFactory-BCZdh_u3.d.mts.map → EndpointFactory-WJzZfkTW.d.mts.map} +1 -1
- package/dist/{EndpointFactory-BnK_YkW1.d.cts → EndpointFactory-n96CT_Ys.d.cts} +4 -4
- package/dist/{EndpointFactory-BnK_YkW1.d.cts.map → EndpointFactory-n96CT_Ys.d.cts.map} +1 -1
- package/dist/{SubscriberBuilder-CjDGSTZc.d.cts → SubscriberBuilder-CIXTozBi.d.cts} +2 -2
- package/dist/{SubscriberBuilder-C2FRfd26.d.mts.map → SubscriberBuilder-CIXTozBi.d.cts.map} +1 -1
- package/dist/{SubscriberBuilder-C2FRfd26.d.mts → SubscriberBuilder-CMBzPdRX.d.mts} +2 -2
- package/dist/{SubscriberBuilder-CjDGSTZc.d.cts.map → SubscriberBuilder-CMBzPdRX.d.mts.map} +1 -1
- package/dist/adaptors/aws.d.cts +3 -3
- package/dist/adaptors/aws.d.mts +3 -3
- package/dist/adaptors/hono.d.cts +1 -1
- package/dist/adaptors/hono.d.mts +1 -1
- package/dist/adaptors/testing.cjs +44 -6
- package/dist/adaptors/testing.cjs.map +1 -1
- package/dist/adaptors/testing.d.cts +18 -4
- package/dist/adaptors/testing.d.cts.map +1 -1
- package/dist/adaptors/testing.d.mts +18 -4
- package/dist/adaptors/testing.d.mts.map +1 -1
- package/dist/adaptors/testing.mjs +44 -6
- package/dist/adaptors/testing.mjs.map +1 -1
- package/dist/{auth-c6nWnvD8.d.cts → auth-6Cdx5amw.d.cts} +2 -2
- package/dist/{auth-c6nWnvD8.d.cts.map → auth-6Cdx5amw.d.cts.map} +1 -1
- package/dist/{auth-pS_U1H_X.d.mts → auth-B_c9b54v.d.mts} +2 -2
- package/dist/{auth-pS_U1H_X.d.mts.map → auth-B_c9b54v.d.mts.map} +1 -1
- package/dist/auth.d.cts +1 -1
- package/dist/auth.d.mts +1 -1
- package/dist/{cache-B2s0b-ss.d.mts → cache-CSJHbgwS.d.cts} +3 -3
- package/dist/{cache-B2s0b-ss.d.mts.map → cache-CSJHbgwS.d.cts.map} +1 -1
- package/dist/{cache-CYe2Kzjc.d.cts → cache-HHg5No4L.d.mts} +3 -3
- package/dist/{cache-CYe2Kzjc.d.cts.map → cache-HHg5No4L.d.mts.map} +1 -1
- package/dist/cache.d.cts +1 -1
- package/dist/cache.d.mts +1 -1
- package/dist/{construct-interface-D2gesxos.d.mts → construct-interface-BLG_BEH5.d.mts} +3 -3
- package/dist/{construct-interface-D2gesxos.d.mts.map → construct-interface-BLG_BEH5.d.mts.map} +1 -1
- package/dist/{construct-interface-DPusCUSQ.d.cts → construct-interface-DcNaRKoC.d.cts} +3 -3
- package/dist/{construct-interface-DPusCUSQ.d.cts.map → construct-interface-DcNaRKoC.d.cts.map} +1 -1
- package/dist/construct-interface.cjs +3 -3
- package/dist/construct-interface.cjs.map +1 -1
- package/dist/construct-interface.d.cts +1 -1
- package/dist/construct-interface.d.mts +1 -1
- package/dist/construct-interface.mjs +3 -3
- package/dist/construct-interface.mjs.map +1 -1
- package/dist/credential.cjs +22 -9
- package/dist/credential.cjs.map +1 -1
- package/dist/credential.d.cts +12 -2
- package/dist/credential.d.cts.map +1 -1
- package/dist/credential.d.mts +12 -2
- package/dist/credential.d.mts.map +1 -1
- package/dist/credential.mjs +22 -10
- package/dist/credential.mjs.map +1 -1
- package/dist/crons/index.d.cts +2 -2
- package/dist/crons/index.d.mts +2 -2
- package/dist/database/kysely.d.cts +1 -1
- package/dist/database/kysely.d.mts +1 -1
- package/dist/email.d.cts +1 -1
- package/dist/email.d.mts +1 -1
- package/dist/endpoints/index.d.cts +2 -2
- package/dist/endpoints/index.d.mts +2 -2
- package/dist/external-api-BKOb2jSC.d.cts +86 -0
- package/dist/external-api-BKOb2jSC.d.cts.map +1 -0
- package/dist/external-api-CZHev1Oh.d.mts +86 -0
- package/dist/external-api-CZHev1Oh.d.mts.map +1 -0
- package/dist/external-api.cjs +124 -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 +121 -0
- package/dist/external-api.mjs.map +1 -0
- package/dist/file-server.d.cts +1 -1
- package/dist/file-server.d.mts +1 -1
- package/dist/functions/index.d.cts +1 -1
- package/dist/functions/index.d.mts +1 -1
- package/dist/{index-yb3fXNyH.d.mts → index-DwveWr3c.d.mts} +2 -2
- package/dist/{index-BI23K3wy.d.cts.map → index-DwveWr3c.d.mts.map} +1 -1
- package/dist/{index-BI23K3wy.d.cts → index-Dzkdm-IE.d.cts} +2 -2
- package/dist/{index-yb3fXNyH.d.mts.map → index-Dzkdm-IE.d.cts.map} +1 -1
- package/dist/{kysely-CEVXacPN.d.cts → kysely-Dy8nNgvk.d.cts} +3 -3
- package/dist/{kysely-CEVXacPN.d.cts.map → kysely-Dy8nNgvk.d.cts.map} +1 -1
- package/dist/{kysely-mcTdPNhl.d.mts → kysely-QLoPapbM.d.mts} +3 -3
- package/dist/{kysely-mcTdPNhl.d.mts.map → kysely-QLoPapbM.d.mts.map} +1 -1
- package/dist/mobile-app.d.cts +1 -1
- package/dist/mobile-app.d.mts +1 -1
- package/dist/object-storage.d.cts +1 -1
- package/dist/object-storage.d.mts +1 -1
- package/dist/queue/index.d.cts +1 -1
- package/dist/queue/index.d.mts +1 -1
- package/dist/rest-api.d.cts +3 -3
- package/dist/rest-api.d.mts +3 -3
- package/dist/site.d.cts +1 -1
- package/dist/site.d.mts +1 -1
- package/dist/subscribers/index.d.cts +1 -1
- package/dist/subscribers/index.d.mts +1 -1
- package/dist/worker.d.cts +5 -5
- package/dist/worker.d.mts +5 -5
- package/package.json +41 -31
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache-
|
|
1
|
+
{"version":3,"file":"cache-HHg5No4L.d.mts","names":["Cache","CacheClient"],"sources":["../src/cache.ts"],"mappings":";;;;;UA6BiB;;;;;;;;EAQhB;;EAEA;;cAGYA,QAAM,0CACP,UAAU,OAAOC;mBAaV;WAXT,IAAI;WACJ,SAAS,QAAQ,aAAa,QAAQA;;;;;mBAM9B;EAEjB,YACC,IAAI,cAAc,QACD,UAAS;EAc3B,WAAW;;;;;;;;;;;;UAuBG"}
|
package/dist/cache.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as CacheOptions, t as Cache } from "./cache-
|
|
1
|
+
import { n as CacheOptions, t as Cache } from "./cache-CSJHbgwS.cjs";
|
|
2
2
|
export { Cache, CacheOptions };
|
package/dist/cache.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as CacheOptions, t as Cache } from "./cache-
|
|
1
|
+
import { n as CacheOptions, t as Cache } from "./cache-HHg5No4L.mjs";
|
|
2
2
|
export { Cache, CacheOptions };
|
|
@@ -140,10 +140,10 @@ declare function isConsumable(value: unknown): value is Consumable;
|
|
|
140
140
|
* The service behind either face.
|
|
141
141
|
*
|
|
142
142
|
* `.database()` and the publisher slots take a construct now; they took a
|
|
143
|
-
* `Service` before and still do, because
|
|
144
|
-
*
|
|
143
|
+
* `Service` before and still do, because not every hand-written service has a
|
|
144
|
+
* construct to stand for it.
|
|
145
145
|
*/
|
|
146
146
|
declare function serviceOf<TName extends string, TClient>(source: Consumable<TName, TClient> | Service<TName, TClient>): Service<TName, TClient>;
|
|
147
147
|
//#endregion
|
|
148
148
|
export { Infer as a, ServicesOf as c, edgesWith as d, idsOf as f, servicesOf as h, Declarable as i, derivedFrom as l, serviceOf as m, Construct as n, NameOf as o, isConsumable as p, Consumable as r, NotAConstruct as s, Authenticator as t, edgeTo as u };
|
|
149
|
-
//# sourceMappingURL=construct-interface-
|
|
149
|
+
//# sourceMappingURL=construct-interface-BLG_BEH5.d.mts.map
|
package/dist/{construct-interface-D2gesxos.d.mts.map → construct-interface-BLG_BEH5.d.mts.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"construct-interface-
|
|
1
|
+
{"version":3,"file":"construct-interface-BLG_BEH5.d.mts","names":[],"sources":["../src/construct-interface.ts"],"mappings":";;;;;;;;;;;;;UA8BiB,UAAU,+BAA+B;;WAEhD,IAAI;;;;;;;;EASb,WAAW;;;;;;;;WASF,UAAU,mCAEhB,QAAQ,aAAa,QAAQ;;;;;;;;;;;UAYhB,WAAW;WAClB,IAAI;EACb,WAAW;;;;;;;;;;UAWK,cAAc,4BAA4B;EAC1D,OACC,SAAS,SACT,WAAW,wBACT,QAAQ;;;;;;;;;;;;;;iBAeI,OAAO,WAAW,aAAa;;KAWnC,MAAM,KACjB,UAAU,wBAAwB,WAAW;;KAGlC,OAAO,KAClB,UAAU,gBAAgB,kBAAkB;;;;;;;;;;;UAY5B,WAAW,+BAA+B;WACjD,IAAI;WACJ,SAAS,QAAQ,aAAa,QAAQ;EAC/C,WAAW;;;;;;;;;;KAWA,WAAW,mBAAmB,mBACxC,WAAW,IAAI,EAAE;;;;;;;;iBAUH,iBAAiB,mBAAmB,cACnD,YAAY,IACV,WAAW;;;;;;;;;;iBAiBE,MACf,qBAAqB,cACrB;;cAMY,sBAAsB;WACb;EAArB,YAAqB;;;;;;;;;;iBAoCN,YAAY,UAAU,SACrC,SAAS,GACT;EAAa;IACX;;;;;iBASa,UACf,kBACA;iBAce,aAAa,iBAAiB,SAAS;;;;;;;;iBAmBvC,UAAU,sBAAsB,SAC/C,QAAQ,WAAW,OAAO,WAAW,QAAQ,OAAO,WAClD,QAAQ,OAAO"}
|
|
@@ -140,10 +140,10 @@ declare function isConsumable(value: unknown): value is Consumable;
|
|
|
140
140
|
* The service behind either face.
|
|
141
141
|
*
|
|
142
142
|
* `.database()` and the publisher slots take a construct now; they took a
|
|
143
|
-
* `Service` before and still do, because
|
|
144
|
-
*
|
|
143
|
+
* `Service` before and still do, because not every hand-written service has a
|
|
144
|
+
* construct to stand for it.
|
|
145
145
|
*/
|
|
146
146
|
declare function serviceOf<TName extends string, TClient>(source: Consumable<TName, TClient> | Service<TName, TClient>): Service<TName, TClient>;
|
|
147
147
|
//#endregion
|
|
148
148
|
export { Infer as a, ServicesOf as c, edgesWith as d, idsOf as f, servicesOf as h, Declarable as i, derivedFrom as l, serviceOf as m, Construct as n, NameOf as o, isConsumable as p, Consumable as r, NotAConstruct as s, Authenticator as t, edgeTo as u };
|
|
149
|
-
//# sourceMappingURL=construct-interface-
|
|
149
|
+
//# sourceMappingURL=construct-interface-DcNaRKoC.d.cts.map
|
package/dist/{construct-interface-DPusCUSQ.d.cts.map → construct-interface-DcNaRKoC.d.cts.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"construct-interface-
|
|
1
|
+
{"version":3,"file":"construct-interface-DcNaRKoC.d.cts","names":[],"sources":["../src/construct-interface.ts"],"mappings":";;;;;;;;;;;;;UA8BiB,UAAU,+BAA+B;;WAEhD,IAAI;;;;;;;;EASb,WAAW;;;;;;;;WASF,UAAU,mCAEhB,QAAQ,aAAa,QAAQ;;;;;;;;;;;UAYhB,WAAW;WAClB,IAAI;EACb,WAAW;;;;;;;;;;UAWK,cAAc,4BAA4B;EAC1D,OACC,SAAS,SACT,WAAW,wBACT,QAAQ;;;;;;;;;;;;;;iBAeI,OAAO,WAAW,aAAa;;KAWnC,MAAM,KACjB,UAAU,wBAAwB,WAAW;;KAGlC,OAAO,KAClB,UAAU,gBAAgB,kBAAkB;;;;;;;;;;;UAY5B,WAAW,+BAA+B;WACjD,IAAI;WACJ,SAAS,QAAQ,aAAa,QAAQ;EAC/C,WAAW;;;;;;;;;;KAWA,WAAW,mBAAmB,mBACxC,WAAW,IAAI,EAAE;;;;;;;;iBAUH,iBAAiB,mBAAmB,cACnD,YAAY,IACV,WAAW;;;;;;;;;;iBAiBE,MACf,qBAAqB,cACrB;;cAMY,sBAAsB;WACb;EAArB,YAAqB;;;;;;;;;;iBAoCN,YAAY,UAAU,SACrC,SAAS,GACT;EAAa;IACX;;;;;iBASa,UACf,kBACA;iBAce,aAAa,iBAAiB,SAAS;;;;;;;;iBAmBvC,UAAU,sBAAsB,SAC/C,QAAQ,WAAW,OAAO,WAAW,QAAQ,OAAO,WAClD,QAAQ,OAAO"}
|
|
@@ -50,7 +50,7 @@ var NotAConstruct = class extends Error {
|
|
|
50
50
|
value;
|
|
51
51
|
constructor(value) {
|
|
52
52
|
const name = typeof value === "object" && value !== null && "serviceName" in value ? `the service '${String(value.serviceName)}'` : `a ${typeof value}`;
|
|
53
|
-
super(`.dependsOn() takes constructs, and was given ${name}. Pass it to .services([…]) instead
|
|
53
|
+
super(`.dependsOn() takes constructs, and was given ${name}. Pass it to .services([…]) instead.`);
|
|
54
54
|
this.value = value;
|
|
55
55
|
this.name = "NotAConstruct";
|
|
56
56
|
}
|
|
@@ -98,8 +98,8 @@ function isConsumable(value) {
|
|
|
98
98
|
* The service behind either face.
|
|
99
99
|
*
|
|
100
100
|
* `.database()` and the publisher slots take a construct now; they took a
|
|
101
|
-
* `Service` before and still do, because
|
|
102
|
-
*
|
|
101
|
+
* `Service` before and still do, because not every hand-written service has a
|
|
102
|
+
* construct to stand for it.
|
|
103
103
|
*/
|
|
104
104
|
function serviceOf(source) {
|
|
105
105
|
return isConsumable(source) ? source.service : source;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"construct-interface.cjs","names":[],"sources":["../src/construct-interface.ts"],"sourcesContent":["/**\n * The construct contract.\n *\n * A construct is three things at once — an infrastructure requirement at build\n * time, a runtime capability, and something other code can consume — which is\n * what forces exactly these three members.\n *\n * An **interface**, not a base class: `Endpoint`, `Cron`, `Queue`, and `Topic`\n * can satisfy it without inheritance surgery, a lifted `Service` can satisfy it\n * as a plain object, and `.dependsOn()` gets its enforcement structurally — a\n * `Service` (`{ serviceName, register }`) simply does not match\n * `{ id, declare, service }`, with no `instanceof` anywhere.\n *\n * Lives in its own module while the existing abstract `Construct` class is\n * still in use; it takes that name once the class is gone.\n */\n\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Declaration, Dependency } from '@geekmidas/manifest';\nimport type { Service } from '@geekmidas/services';\n\n/**\n * @typeParam TName - the construct's canonical id, PascalCase. Keeping it a\n * literal is what lets the service key be `Uncapitalize<TName>` — a TypeScript\n * intrinsic, so no custom transform needs a runtime twin.\n * @typeParam TClient - what consuming this construct hands you. `never` means it\n * owns no address and cannot be consumed: a `Cron` is fired by a schedule and a\n * `Subscriber` is reached through its topic, so `.dependsOn()` on either is a\n * compile error rather than a stub that throws.\n */\nexport interface Construct<TName extends string = string, TClient = never> {\n\t/** Canonical, PascalCase, unique within the manifest. */\n\treadonly id: TName;\n\n\t/**\n\t * The build-time face: what this construct contributes to the manifest.\n\t *\n\t * Returns an array because some constructs contribute more than one node — a\n\t * queue declares the queue and its worker, a database declares its migrator\n\t * and seeder. Most return one.\n\t */\n\tdeclare(): Declaration[];\n\n\t/**\n\t * The consumable face — the address this construct owns, as a client.\n\t *\n\t * A field assigned once rather than a getter. `Construct.getEnvironment`\n\t * caches by service *object*, and `Topic.publisher` returns a fresh literal\n\t * on every access, so that cache never hits for topics or queues today.\n\t */\n\treadonly service: [TClient] extends [never]\n\t\t? never\n\t\t: Service<Uncapitalize<TName>, TClient>;\n}\n\n/**\n * The build-time face alone — an id and what it contributes to the manifest.\n *\n * Weaker than {@link Consumable} on purpose. An edge is not always an\n * injection: a site depending on an API needs that API's *address at build\n * time* and has no service record to put a client into, so requiring one would\n * make the weakest kind of edge impossible to express with the strongest\n * interface. Discovery asks this same question and nothing more.\n */\nexport interface Declarable<TName extends string = string> {\n\treadonly id: TName;\n\tdeclare(): Declaration[];\n}\n\n/**\n * A construct that authenticates requests — what `RestApi.auth()` takes.\n *\n * `verify` is the one thing every provider shares: given a request's headers,\n * whose request is it — the session, or `null` when there is none. Whether the\n * provider is a server mounted beside the API, deployed elsewhere, or an issuer\n * somebody else runs is its own business; a surface only ever asks this.\n */\nexport interface Authenticator<TSession = unknown> extends Declarable {\n\tverify(\n\t\theaders: Headers,\n\t\tenvParser: EnvironmentParser<{}>,\n\t): Promise<TSession | null>;\n}\n\n/**\n * The edge that points at a construct.\n *\n * A construct's *canonical* node is the one carrying its own id — the others are\n * things it owns rather than things it is, like the signing secret beside an\n * auth server — so the kind an edge records is read off that node instead of\n * being written down beside it. Hand-written kinds are the same fact stated\n * twice, and the copy is what goes stale when a construct changes what it\n * declares.\n *\n * @throws {NotAConstruct} when the value declares nothing under its own id.\n */\nexport function edgeTo(construct: Declarable): Dependency {\n\tconst canonical = construct\n\t\t.declare()\n\t\t.find((declaration) => declaration.id === construct.id);\n\n\tif (!canonical) throw new NotAConstruct(construct);\n\n\treturn { target: construct.id, kind: canonical.kind };\n}\n\n/** What consuming a construct hands you. */\nexport type Infer<C> =\n\tC extends Construct<string, infer TClient> ? TClient : never;\n\n/** A construct's canonical id. */\nexport type NameOf<C> =\n\tC extends Construct<infer TName, unknown> ? TName : never;\n\n/**\n * What `.dependsOn([…])` accepts: a construct that owns a client.\n *\n * Structural, and deliberately narrower than {@link Construct} — it is the\n * face a *consumer* needs, so the builders can accept a database, a bucket, a\n * mail sender, a queue, or a topic without importing any of them. A plain\n * `Service` is not one of these, which is the point: constructs-only confines\n * env sniffing to `.services()` and the explicit lift, so retiring that method\n * retires implicit inference with it.\n */\nexport interface Consumable<TName extends string = string, TClient = unknown> {\n\treadonly id: TName;\n\treadonly service: Service<Uncapitalize<TName>, TClient>;\n\tdeclare(): Declaration[];\n}\n\n/**\n * The services a list of constructs dissolves into.\n *\n * A mapped tuple, so `[db, uploads]` types as `[Service<'orders', Kysely<DB>>,\n * Service<'uploads', StorageClient>]` and the handler's service record gains\n * both keys — the same machinery `.services()` already uses, which is why\n * `dependsOn` needs no type plumbing of its own.\n */\nexport type ServicesOf<T extends readonly Consumable[]> = {\n\t[K in keyof T]: T[K]['service'];\n};\n\n/**\n * The services of a list of constructs, at runtime.\n *\n * @throws {NotAConstruct} when handed something else. The type already refuses\n * it, but a JavaScript caller gets no such warning, and a `Service` slipping\n * through would fail later as an undefined key in the handler.\n */\nexport function servicesOf<const T extends readonly Consumable[]>(\n\tconstructs: T,\n): ServicesOf<T> {\n\treturn constructs.map((construct) => {\n\t\tif (!isConsumable(construct)) throw new NotAConstruct(construct);\n\n\t\treturn construct.service;\n\t}) as ServicesOf<T>;\n}\n\n/**\n * The other half of `servicesOf`: the same edge, as the manifest records it.\n *\n * `.dependsOn()` used to keep only the services, which is what a handler runs\n * with — and an id cannot be recovered from a service name reliably, so the\n * edges were gone by the time the build could read them. Both halves are taken\n * from one call now, and `existing` is folded in so repeated `.dependsOn()`\n * calls accumulate the way `.services()` already does.\n */\nexport function idsOf(\n\tconstructs: readonly Consumable[],\n\texisting: readonly string[] = [],\n): string[] {\n\treturn [...new Set([...existing, ...constructs.map(({ id }) => id)])];\n}\n\n/** Something that is not a construct was passed to `.dependsOn()`. */\nexport class NotAConstruct extends Error {\n\tconstructor(readonly value: unknown) {\n\t\tconst name =\n\t\t\ttypeof value === 'object' && value !== null && 'serviceName' in value\n\t\t\t\t? `the service '${String((value as { serviceName: unknown }).serviceName)}'`\n\t\t\t\t: `a ${typeof value}`;\n\n\t\tsuper(\n\t\t\t`.dependsOn() takes constructs, and was given ${name}. ` +\n\t\t\t\t`Pass it to .services([…]) instead, or lift it with ` +\n\t\t\t\t`Construct.fromService().`,\n\t\t);\n\t\tthis.name = 'NotAConstruct';\n\t}\n}\n\n/**\n * Whether a value is a construct rather than a bare `Service`.\n *\n * Structural rather than `instanceof`: a construct from a second copy of\n * `@geekmidas/constructs` — a linked workspace, two versions in a lockfile — is\n * still a construct, and `instanceof` is exactly the check that says otherwise.\n */\n/**\n * The construct a service was derived from — the \\`users\\` topic, for\n * \\`users.publisher\\`. A symbol, so it rides on the service object without\n * becoming part of its shape.\n */\nconst DERIVED_FROM = Symbol.for('@geekmidas/constructs/derivedFrom');\n\n/**\n * Mark a service as standing for the construct it was derived from.\n *\n * \\`.publisher(users.publisher)\\` takes a service, not the topic, and an id\n * cannot be recovered from a service name. Without the mark the edge was lost:\n * the manifest never heard that the API publishes to \\`users\\`, so the app's\n * container was composed without \\`USERS_PUBLISHER_CONNECTION_STRING\\`.\n */\nexport function derivedFrom<S extends Service>(\n\tservice: S,\n\tconstruct: { id: string },\n): S {\n\tObject.defineProperty(service, DERIVED_FROM, { value: construct.id });\n\treturn service;\n}\n\n/**\n * \\`existing\\`, with the edge a service stands for — a construct's own id, or\n * the id a derived service was marked with. Unchanged for a plain service.\n */\nexport function edgesWith(\n\tservice: unknown,\n\texisting: readonly string[] = [],\n): string[] {\n\tif (isConsumable(service)) return idsOf([service], existing);\n\n\tconst id =\n\t\ttypeof service === 'object' && service !== null\n\t\t\t? (service as { [DERIVED_FROM]?: unknown })[DERIVED_FROM]\n\t\t\t: undefined;\n\n\treturn typeof id === 'string'\n\t\t? [...new Set([...existing, id])]\n\t\t: [...existing];\n}\n\nexport function isConsumable(value: unknown): value is Consumable {\n\tif (typeof value !== 'object' || value === null) return false;\n\n\tconst candidate = value as Partial<Consumable>;\n\n\treturn (\n\t\ttypeof candidate.id === 'string' &&\n\t\ttypeof candidate.declare === 'function' &&\n\t\ttypeof (candidate.service as Service | undefined)?.serviceName === 'string'\n\t);\n}\n\n/**\n * The service behind either face.\n *\n * `.database()` and the publisher slots take a construct now; they took a\n * `Service` before and still do, because a hand-written one is exactly what\n * `Construct.fromService` exists to lift and not everything has been lifted.\n */\nexport function serviceOf<TName extends string, TClient>(\n\tsource: Consumable<TName, TClient> | Service<TName, TClient>,\n): Service<TName, TClient> {\n\t// A construct's service key is `Uncapitalize<TName>` and the slot is typed\n\t// by `TName`; the two describe the same key, and only the cast says so.\n\treturn isConsumable(source)\n\t\t? (source.service as unknown as Service<TName, TClient>)\n\t\t: (source as Service<TName, TClient>);\n}\n"],"mappings":";;;;;;;;;;;;;;AAgGA,SAAgB,OAAO,WAAmC;CACzD,MAAM,YAAY,UAChB,QAAQ,CAAC,CACT,MAAM,gBAAgB,YAAY,OAAO,UAAU,EAAE;CAEvD,IAAI,CAAC,WAAW,MAAM,IAAI,cAAc,SAAS;CAEjD,OAAO;EAAE,QAAQ,UAAU;EAAI,MAAM,UAAU;CAAK;AACrD;;;;;;;;AA6CA,SAAgB,WACf,YACgB;CAChB,OAAO,WAAW,KAAK,cAAc;EACpC,IAAI,CAAC,aAAa,SAAS,GAAG,MAAM,IAAI,cAAc,SAAS;EAE/D,OAAO,UAAU;CAClB,CAAC;AACF;;;;;;;;;;AAWA,SAAgB,MACf,YACA,WAA8B,CAAC,GACpB;CACX,OAAO,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,UAAU,GAAG,WAAW,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;AACrE;;AAGA,IAAa,gBAAb,cAAmC,MAAM;CACnB;CAArB,YAAY,OAAyB;EACpC,MAAM,OACL,OAAO,UAAU,YAAY,UAAU,QAAQ,iBAAiB,QAC7D,gBAAgB,OAAQ,MAAmC,WAAW,EAAE,KACxE,KAAK,OAAO;EAEhB,MACC,gDAAgD,KAAK,8EAGtD;EAVoB,KAAA,QAAA;EAWpB,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;;AAcA,MAAM,eAAe,OAAO,IAAI,mCAAmC;;;;;;;;;AAUnE,SAAgB,YACf,SACA,WACI;CACJ,OAAO,eAAe,SAAS,cAAc,EAAE,OAAO,UAAU,GAAG,CAAC;CACpE,OAAO;AACR;;;;;AAMA,SAAgB,UACf,SACA,WAA8B,CAAC,GACpB;CACX,IAAI,aAAa,OAAO,GAAG,OAAO,MAAM,CAAC,OAAO,GAAG,QAAQ;CAE3D,MAAM,KACL,OAAO,YAAY,YAAY,YAAY,OACvC,QAAyC,gBAC1C,KAAA;CAEJ,OAAO,OAAO,OAAO,WAClB,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,CAAC,IAC9B,CAAC,GAAG,QAAQ;AAChB;AAEA,SAAgB,aAAa,OAAqC;CACjE,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CAExD,MAAM,YAAY;CAElB,OACC,OAAO,UAAU,OAAO,YACxB,OAAO,UAAU,YAAY,cAC7B,OAAQ,UAAU,SAAiC,gBAAgB;AAErE;;;;;;;;AASA,SAAgB,UACf,QAC0B;CAG1B,OAAO,aAAa,MAAM,IACtB,OAAO,UACP;AACL"}
|
|
1
|
+
{"version":3,"file":"construct-interface.cjs","names":[],"sources":["../src/construct-interface.ts"],"sourcesContent":["/**\n * The construct contract.\n *\n * A construct is three things at once — an infrastructure requirement at build\n * time, a runtime capability, and something other code can consume — which is\n * what forces exactly these three members.\n *\n * An **interface**, not a base class: `Endpoint`, `Cron`, `Queue`, and `Topic`\n * can satisfy it without inheritance surgery, a lifted `Service` can satisfy it\n * as a plain object, and `.dependsOn()` gets its enforcement structurally — a\n * `Service` (`{ serviceName, register }`) simply does not match\n * `{ id, declare, service }`, with no `instanceof` anywhere.\n *\n * Lives in its own module while the existing abstract `Construct` class is\n * still in use; it takes that name once the class is gone.\n */\n\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Declaration, Dependency } from '@geekmidas/manifest';\nimport type { Service } from '@geekmidas/services';\n\n/**\n * @typeParam TName - the construct's canonical id, PascalCase. Keeping it a\n * literal is what lets the service key be `Uncapitalize<TName>` — a TypeScript\n * intrinsic, so no custom transform needs a runtime twin.\n * @typeParam TClient - what consuming this construct hands you. `never` means it\n * owns no address and cannot be consumed: a `Cron` is fired by a schedule and a\n * `Subscriber` is reached through its topic, so `.dependsOn()` on either is a\n * compile error rather than a stub that throws.\n */\nexport interface Construct<TName extends string = string, TClient = never> {\n\t/** Canonical, PascalCase, unique within the manifest. */\n\treadonly id: TName;\n\n\t/**\n\t * The build-time face: what this construct contributes to the manifest.\n\t *\n\t * Returns an array because some constructs contribute more than one node — a\n\t * queue declares the queue and its worker, a database declares its migrator\n\t * and seeder. Most return one.\n\t */\n\tdeclare(): Declaration[];\n\n\t/**\n\t * The consumable face — the address this construct owns, as a client.\n\t *\n\t * A field assigned once rather than a getter. `Construct.getEnvironment`\n\t * caches by service *object*, and `Topic.publisher` returns a fresh literal\n\t * on every access, so that cache never hits for topics or queues today.\n\t */\n\treadonly service: [TClient] extends [never]\n\t\t? never\n\t\t: Service<Uncapitalize<TName>, TClient>;\n}\n\n/**\n * The build-time face alone — an id and what it contributes to the manifest.\n *\n * Weaker than {@link Consumable} on purpose. An edge is not always an\n * injection: a site depending on an API needs that API's *address at build\n * time* and has no service record to put a client into, so requiring one would\n * make the weakest kind of edge impossible to express with the strongest\n * interface. Discovery asks this same question and nothing more.\n */\nexport interface Declarable<TName extends string = string> {\n\treadonly id: TName;\n\tdeclare(): Declaration[];\n}\n\n/**\n * A construct that authenticates requests — what `RestApi.auth()` takes.\n *\n * `verify` is the one thing every provider shares: given a request's headers,\n * whose request is it — the session, or `null` when there is none. Whether the\n * provider is a server mounted beside the API, deployed elsewhere, or an issuer\n * somebody else runs is its own business; a surface only ever asks this.\n */\nexport interface Authenticator<TSession = unknown> extends Declarable {\n\tverify(\n\t\theaders: Headers,\n\t\tenvParser: EnvironmentParser<{}>,\n\t): Promise<TSession | null>;\n}\n\n/**\n * The edge that points at a construct.\n *\n * A construct's *canonical* node is the one carrying its own id — the others are\n * things it owns rather than things it is, like the signing secret beside an\n * auth server — so the kind an edge records is read off that node instead of\n * being written down beside it. Hand-written kinds are the same fact stated\n * twice, and the copy is what goes stale when a construct changes what it\n * declares.\n *\n * @throws {NotAConstruct} when the value declares nothing under its own id.\n */\nexport function edgeTo(construct: Declarable): Dependency {\n\tconst canonical = construct\n\t\t.declare()\n\t\t.find((declaration) => declaration.id === construct.id);\n\n\tif (!canonical) throw new NotAConstruct(construct);\n\n\treturn { target: construct.id, kind: canonical.kind };\n}\n\n/** What consuming a construct hands you. */\nexport type Infer<C> =\n\tC extends Construct<string, infer TClient> ? TClient : never;\n\n/** A construct's canonical id. */\nexport type NameOf<C> =\n\tC extends Construct<infer TName, unknown> ? TName : never;\n\n/**\n * What `.dependsOn([…])` accepts: a construct that owns a client.\n *\n * Structural, and deliberately narrower than {@link Construct} — it is the\n * face a *consumer* needs, so the builders can accept a database, a bucket, a\n * mail sender, a queue, or a topic without importing any of them. A plain\n * `Service` is not one of these, which is the point: constructs-only confines\n * env sniffing to `.services()` and the explicit lift, so retiring that method\n * retires implicit inference with it.\n */\nexport interface Consumable<TName extends string = string, TClient = unknown> {\n\treadonly id: TName;\n\treadonly service: Service<Uncapitalize<TName>, TClient>;\n\tdeclare(): Declaration[];\n}\n\n/**\n * The services a list of constructs dissolves into.\n *\n * A mapped tuple, so `[db, uploads]` types as `[Service<'orders', Kysely<DB>>,\n * Service<'uploads', StorageClient>]` and the handler's service record gains\n * both keys — the same machinery `.services()` already uses, which is why\n * `dependsOn` needs no type plumbing of its own.\n */\nexport type ServicesOf<T extends readonly Consumable[]> = {\n\t[K in keyof T]: T[K]['service'];\n};\n\n/**\n * The services of a list of constructs, at runtime.\n *\n * @throws {NotAConstruct} when handed something else. The type already refuses\n * it, but a JavaScript caller gets no such warning, and a `Service` slipping\n * through would fail later as an undefined key in the handler.\n */\nexport function servicesOf<const T extends readonly Consumable[]>(\n\tconstructs: T,\n): ServicesOf<T> {\n\treturn constructs.map((construct) => {\n\t\tif (!isConsumable(construct)) throw new NotAConstruct(construct);\n\n\t\treturn construct.service;\n\t}) as ServicesOf<T>;\n}\n\n/**\n * The other half of `servicesOf`: the same edge, as the manifest records it.\n *\n * `.dependsOn()` used to keep only the services, which is what a handler runs\n * with — and an id cannot be recovered from a service name reliably, so the\n * edges were gone by the time the build could read them. Both halves are taken\n * from one call now, and `existing` is folded in so repeated `.dependsOn()`\n * calls accumulate the way `.services()` already does.\n */\nexport function idsOf(\n\tconstructs: readonly Consumable[],\n\texisting: readonly string[] = [],\n): string[] {\n\treturn [...new Set([...existing, ...constructs.map(({ id }) => id)])];\n}\n\n/** Something that is not a construct was passed to `.dependsOn()`. */\nexport class NotAConstruct extends Error {\n\tconstructor(readonly value: unknown) {\n\t\tconst name =\n\t\t\ttypeof value === 'object' && value !== null && 'serviceName' in value\n\t\t\t\t? `the service '${String((value as { serviceName: unknown }).serviceName)}'`\n\t\t\t\t: `a ${typeof value}`;\n\n\t\tsuper(\n\t\t\t`.dependsOn() takes constructs, and was given ${name}. ` +\n\t\t\t\t`Pass it to .services([…]) instead.`,\n\t\t);\n\t\tthis.name = 'NotAConstruct';\n\t}\n}\n\n/**\n * Whether a value is a construct rather than a bare `Service`.\n *\n * Structural rather than `instanceof`: a construct from a second copy of\n * `@geekmidas/constructs` — a linked workspace, two versions in a lockfile — is\n * still a construct, and `instanceof` is exactly the check that says otherwise.\n */\n/**\n * The construct a service was derived from — the \\`users\\` topic, for\n * \\`users.publisher\\`. A symbol, so it rides on the service object without\n * becoming part of its shape.\n */\nconst DERIVED_FROM = Symbol.for('@geekmidas/constructs/derivedFrom');\n\n/**\n * Mark a service as standing for the construct it was derived from.\n *\n * \\`.publisher(users.publisher)\\` takes a service, not the topic, and an id\n * cannot be recovered from a service name. Without the mark the edge was lost:\n * the manifest never heard that the API publishes to \\`users\\`, so the app's\n * container was composed without \\`USERS_PUBLISHER_CONNECTION_STRING\\`.\n */\nexport function derivedFrom<S extends Service>(\n\tservice: S,\n\tconstruct: { id: string },\n): S {\n\tObject.defineProperty(service, DERIVED_FROM, { value: construct.id });\n\treturn service;\n}\n\n/**\n * \\`existing\\`, with the edge a service stands for — a construct's own id, or\n * the id a derived service was marked with. Unchanged for a plain service.\n */\nexport function edgesWith(\n\tservice: unknown,\n\texisting: readonly string[] = [],\n): string[] {\n\tif (isConsumable(service)) return idsOf([service], existing);\n\n\tconst id =\n\t\ttypeof service === 'object' && service !== null\n\t\t\t? (service as { [DERIVED_FROM]?: unknown })[DERIVED_FROM]\n\t\t\t: undefined;\n\n\treturn typeof id === 'string'\n\t\t? [...new Set([...existing, id])]\n\t\t: [...existing];\n}\n\nexport function isConsumable(value: unknown): value is Consumable {\n\tif (typeof value !== 'object' || value === null) return false;\n\n\tconst candidate = value as Partial<Consumable>;\n\n\treturn (\n\t\ttypeof candidate.id === 'string' &&\n\t\ttypeof candidate.declare === 'function' &&\n\t\ttypeof (candidate.service as Service | undefined)?.serviceName === 'string'\n\t);\n}\n\n/**\n * The service behind either face.\n *\n * `.database()` and the publisher slots take a construct now; they took a\n * `Service` before and still do, because not every hand-written service has a\n * construct to stand for it.\n */\nexport function serviceOf<TName extends string, TClient>(\n\tsource: Consumable<TName, TClient> | Service<TName, TClient>,\n): Service<TName, TClient> {\n\t// A construct's service key is `Uncapitalize<TName>` and the slot is typed\n\t// by `TName`; the two describe the same key, and only the cast says so.\n\treturn isConsumable(source)\n\t\t? (source.service as unknown as Service<TName, TClient>)\n\t\t: (source as Service<TName, TClient>);\n}\n"],"mappings":";;;;;;;;;;;;;;AAgGA,SAAgB,OAAO,WAAmC;CACzD,MAAM,YAAY,UAChB,QAAQ,CAAC,CACT,MAAM,gBAAgB,YAAY,OAAO,UAAU,EAAE;CAEvD,IAAI,CAAC,WAAW,MAAM,IAAI,cAAc,SAAS;CAEjD,OAAO;EAAE,QAAQ,UAAU;EAAI,MAAM,UAAU;CAAK;AACrD;;;;;;;;AA6CA,SAAgB,WACf,YACgB;CAChB,OAAO,WAAW,KAAK,cAAc;EACpC,IAAI,CAAC,aAAa,SAAS,GAAG,MAAM,IAAI,cAAc,SAAS;EAE/D,OAAO,UAAU;CAClB,CAAC;AACF;;;;;;;;;;AAWA,SAAgB,MACf,YACA,WAA8B,CAAC,GACpB;CACX,OAAO,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,UAAU,GAAG,WAAW,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;AACrE;;AAGA,IAAa,gBAAb,cAAmC,MAAM;CACnB;CAArB,YAAY,OAAyB;EACpC,MAAM,OACL,OAAO,UAAU,YAAY,UAAU,QAAQ,iBAAiB,QAC7D,gBAAgB,OAAQ,MAAmC,WAAW,EAAE,KACxE,KAAK,OAAO;EAEhB,MACC,gDAAgD,KAAK,qCAEtD;EAToB,KAAA,QAAA;EAUpB,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;;AAcA,MAAM,eAAe,OAAO,IAAI,mCAAmC;;;;;;;;;AAUnE,SAAgB,YACf,SACA,WACI;CACJ,OAAO,eAAe,SAAS,cAAc,EAAE,OAAO,UAAU,GAAG,CAAC;CACpE,OAAO;AACR;;;;;AAMA,SAAgB,UACf,SACA,WAA8B,CAAC,GACpB;CACX,IAAI,aAAa,OAAO,GAAG,OAAO,MAAM,CAAC,OAAO,GAAG,QAAQ;CAE3D,MAAM,KACL,OAAO,YAAY,YAAY,YAAY,OACvC,QAAyC,gBAC1C,KAAA;CAEJ,OAAO,OAAO,OAAO,WAClB,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,CAAC,IAC9B,CAAC,GAAG,QAAQ;AAChB;AAEA,SAAgB,aAAa,OAAqC;CACjE,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CAExD,MAAM,YAAY;CAElB,OACC,OAAO,UAAU,OAAO,YACxB,OAAO,UAAU,YAAY,cAC7B,OAAQ,UAAU,SAAiC,gBAAgB;AAErE;;;;;;;;AASA,SAAgB,UACf,QAC0B;CAG1B,OAAO,aAAa,MAAM,IACtB,OAAO,UACP;AACL"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as Infer, c as ServicesOf, d as edgesWith, f as idsOf, h as servicesOf, i as Declarable, l as derivedFrom, m as serviceOf, n as Construct, o as NameOf, p as isConsumable, r as Consumable, s as NotAConstruct, t as Authenticator, u as edgeTo } from "./construct-interface-
|
|
1
|
+
import { a as Infer, c as ServicesOf, d as edgesWith, f as idsOf, h as servicesOf, i as Declarable, l as derivedFrom, m as serviceOf, n as Construct, o as NameOf, p as isConsumable, r as Consumable, s as NotAConstruct, t as Authenticator, u as edgeTo } from "./construct-interface-DcNaRKoC.cjs";
|
|
2
2
|
export { Authenticator, Construct, Consumable, Declarable, Infer, NameOf, NotAConstruct, ServicesOf, derivedFrom, edgeTo, edgesWith, idsOf, isConsumable, serviceOf, servicesOf };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as Infer, c as ServicesOf, d as edgesWith, f as idsOf, h as servicesOf, i as Declarable, l as derivedFrom, m as serviceOf, n as Construct, o as NameOf, p as isConsumable, r as Consumable, s as NotAConstruct, t as Authenticator, u as edgeTo } from "./construct-interface-
|
|
1
|
+
import { a as Infer, c as ServicesOf, d as edgesWith, f as idsOf, h as servicesOf, i as Declarable, l as derivedFrom, m as serviceOf, n as Construct, o as NameOf, p as isConsumable, r as Consumable, s as NotAConstruct, t as Authenticator, u as edgeTo } from "./construct-interface-BLG_BEH5.mjs";
|
|
2
2
|
export { Authenticator, Construct, Consumable, Declarable, Infer, NameOf, NotAConstruct, ServicesOf, derivedFrom, edgeTo, edgesWith, idsOf, isConsumable, serviceOf, servicesOf };
|
|
@@ -49,7 +49,7 @@ var NotAConstruct = class extends Error {
|
|
|
49
49
|
value;
|
|
50
50
|
constructor(value) {
|
|
51
51
|
const name = typeof value === "object" && value !== null && "serviceName" in value ? `the service '${String(value.serviceName)}'` : `a ${typeof value}`;
|
|
52
|
-
super(`.dependsOn() takes constructs, and was given ${name}. Pass it to .services([…]) instead
|
|
52
|
+
super(`.dependsOn() takes constructs, and was given ${name}. Pass it to .services([…]) instead.`);
|
|
53
53
|
this.value = value;
|
|
54
54
|
this.name = "NotAConstruct";
|
|
55
55
|
}
|
|
@@ -97,8 +97,8 @@ function isConsumable(value) {
|
|
|
97
97
|
* The service behind either face.
|
|
98
98
|
*
|
|
99
99
|
* `.database()` and the publisher slots take a construct now; they took a
|
|
100
|
-
* `Service` before and still do, because
|
|
101
|
-
*
|
|
100
|
+
* `Service` before and still do, because not every hand-written service has a
|
|
101
|
+
* construct to stand for it.
|
|
102
102
|
*/
|
|
103
103
|
function serviceOf(source) {
|
|
104
104
|
return isConsumable(source) ? source.service : source;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"construct-interface.mjs","names":[],"sources":["../src/construct-interface.ts"],"sourcesContent":["/**\n * The construct contract.\n *\n * A construct is three things at once — an infrastructure requirement at build\n * time, a runtime capability, and something other code can consume — which is\n * what forces exactly these three members.\n *\n * An **interface**, not a base class: `Endpoint`, `Cron`, `Queue`, and `Topic`\n * can satisfy it without inheritance surgery, a lifted `Service` can satisfy it\n * as a plain object, and `.dependsOn()` gets its enforcement structurally — a\n * `Service` (`{ serviceName, register }`) simply does not match\n * `{ id, declare, service }`, with no `instanceof` anywhere.\n *\n * Lives in its own module while the existing abstract `Construct` class is\n * still in use; it takes that name once the class is gone.\n */\n\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Declaration, Dependency } from '@geekmidas/manifest';\nimport type { Service } from '@geekmidas/services';\n\n/**\n * @typeParam TName - the construct's canonical id, PascalCase. Keeping it a\n * literal is what lets the service key be `Uncapitalize<TName>` — a TypeScript\n * intrinsic, so no custom transform needs a runtime twin.\n * @typeParam TClient - what consuming this construct hands you. `never` means it\n * owns no address and cannot be consumed: a `Cron` is fired by a schedule and a\n * `Subscriber` is reached through its topic, so `.dependsOn()` on either is a\n * compile error rather than a stub that throws.\n */\nexport interface Construct<TName extends string = string, TClient = never> {\n\t/** Canonical, PascalCase, unique within the manifest. */\n\treadonly id: TName;\n\n\t/**\n\t * The build-time face: what this construct contributes to the manifest.\n\t *\n\t * Returns an array because some constructs contribute more than one node — a\n\t * queue declares the queue and its worker, a database declares its migrator\n\t * and seeder. Most return one.\n\t */\n\tdeclare(): Declaration[];\n\n\t/**\n\t * The consumable face — the address this construct owns, as a client.\n\t *\n\t * A field assigned once rather than a getter. `Construct.getEnvironment`\n\t * caches by service *object*, and `Topic.publisher` returns a fresh literal\n\t * on every access, so that cache never hits for topics or queues today.\n\t */\n\treadonly service: [TClient] extends [never]\n\t\t? never\n\t\t: Service<Uncapitalize<TName>, TClient>;\n}\n\n/**\n * The build-time face alone — an id and what it contributes to the manifest.\n *\n * Weaker than {@link Consumable} on purpose. An edge is not always an\n * injection: a site depending on an API needs that API's *address at build\n * time* and has no service record to put a client into, so requiring one would\n * make the weakest kind of edge impossible to express with the strongest\n * interface. Discovery asks this same question and nothing more.\n */\nexport interface Declarable<TName extends string = string> {\n\treadonly id: TName;\n\tdeclare(): Declaration[];\n}\n\n/**\n * A construct that authenticates requests — what `RestApi.auth()` takes.\n *\n * `verify` is the one thing every provider shares: given a request's headers,\n * whose request is it — the session, or `null` when there is none. Whether the\n * provider is a server mounted beside the API, deployed elsewhere, or an issuer\n * somebody else runs is its own business; a surface only ever asks this.\n */\nexport interface Authenticator<TSession = unknown> extends Declarable {\n\tverify(\n\t\theaders: Headers,\n\t\tenvParser: EnvironmentParser<{}>,\n\t): Promise<TSession | null>;\n}\n\n/**\n * The edge that points at a construct.\n *\n * A construct's *canonical* node is the one carrying its own id — the others are\n * things it owns rather than things it is, like the signing secret beside an\n * auth server — so the kind an edge records is read off that node instead of\n * being written down beside it. Hand-written kinds are the same fact stated\n * twice, and the copy is what goes stale when a construct changes what it\n * declares.\n *\n * @throws {NotAConstruct} when the value declares nothing under its own id.\n */\nexport function edgeTo(construct: Declarable): Dependency {\n\tconst canonical = construct\n\t\t.declare()\n\t\t.find((declaration) => declaration.id === construct.id);\n\n\tif (!canonical) throw new NotAConstruct(construct);\n\n\treturn { target: construct.id, kind: canonical.kind };\n}\n\n/** What consuming a construct hands you. */\nexport type Infer<C> =\n\tC extends Construct<string, infer TClient> ? TClient : never;\n\n/** A construct's canonical id. */\nexport type NameOf<C> =\n\tC extends Construct<infer TName, unknown> ? TName : never;\n\n/**\n * What `.dependsOn([…])` accepts: a construct that owns a client.\n *\n * Structural, and deliberately narrower than {@link Construct} — it is the\n * face a *consumer* needs, so the builders can accept a database, a bucket, a\n * mail sender, a queue, or a topic without importing any of them. A plain\n * `Service` is not one of these, which is the point: constructs-only confines\n * env sniffing to `.services()` and the explicit lift, so retiring that method\n * retires implicit inference with it.\n */\nexport interface Consumable<TName extends string = string, TClient = unknown> {\n\treadonly id: TName;\n\treadonly service: Service<Uncapitalize<TName>, TClient>;\n\tdeclare(): Declaration[];\n}\n\n/**\n * The services a list of constructs dissolves into.\n *\n * A mapped tuple, so `[db, uploads]` types as `[Service<'orders', Kysely<DB>>,\n * Service<'uploads', StorageClient>]` and the handler's service record gains\n * both keys — the same machinery `.services()` already uses, which is why\n * `dependsOn` needs no type plumbing of its own.\n */\nexport type ServicesOf<T extends readonly Consumable[]> = {\n\t[K in keyof T]: T[K]['service'];\n};\n\n/**\n * The services of a list of constructs, at runtime.\n *\n * @throws {NotAConstruct} when handed something else. The type already refuses\n * it, but a JavaScript caller gets no such warning, and a `Service` slipping\n * through would fail later as an undefined key in the handler.\n */\nexport function servicesOf<const T extends readonly Consumable[]>(\n\tconstructs: T,\n): ServicesOf<T> {\n\treturn constructs.map((construct) => {\n\t\tif (!isConsumable(construct)) throw new NotAConstruct(construct);\n\n\t\treturn construct.service;\n\t}) as ServicesOf<T>;\n}\n\n/**\n * The other half of `servicesOf`: the same edge, as the manifest records it.\n *\n * `.dependsOn()` used to keep only the services, which is what a handler runs\n * with — and an id cannot be recovered from a service name reliably, so the\n * edges were gone by the time the build could read them. Both halves are taken\n * from one call now, and `existing` is folded in so repeated `.dependsOn()`\n * calls accumulate the way `.services()` already does.\n */\nexport function idsOf(\n\tconstructs: readonly Consumable[],\n\texisting: readonly string[] = [],\n): string[] {\n\treturn [...new Set([...existing, ...constructs.map(({ id }) => id)])];\n}\n\n/** Something that is not a construct was passed to `.dependsOn()`. */\nexport class NotAConstruct extends Error {\n\tconstructor(readonly value: unknown) {\n\t\tconst name =\n\t\t\ttypeof value === 'object' && value !== null && 'serviceName' in value\n\t\t\t\t? `the service '${String((value as { serviceName: unknown }).serviceName)}'`\n\t\t\t\t: `a ${typeof value}`;\n\n\t\tsuper(\n\t\t\t`.dependsOn() takes constructs, and was given ${name}. ` +\n\t\t\t\t`Pass it to .services([…]) instead, or lift it with ` +\n\t\t\t\t`Construct.fromService().`,\n\t\t);\n\t\tthis.name = 'NotAConstruct';\n\t}\n}\n\n/**\n * Whether a value is a construct rather than a bare `Service`.\n *\n * Structural rather than `instanceof`: a construct from a second copy of\n * `@geekmidas/constructs` — a linked workspace, two versions in a lockfile — is\n * still a construct, and `instanceof` is exactly the check that says otherwise.\n */\n/**\n * The construct a service was derived from — the \\`users\\` topic, for\n * \\`users.publisher\\`. A symbol, so it rides on the service object without\n * becoming part of its shape.\n */\nconst DERIVED_FROM = Symbol.for('@geekmidas/constructs/derivedFrom');\n\n/**\n * Mark a service as standing for the construct it was derived from.\n *\n * \\`.publisher(users.publisher)\\` takes a service, not the topic, and an id\n * cannot be recovered from a service name. Without the mark the edge was lost:\n * the manifest never heard that the API publishes to \\`users\\`, so the app's\n * container was composed without \\`USERS_PUBLISHER_CONNECTION_STRING\\`.\n */\nexport function derivedFrom<S extends Service>(\n\tservice: S,\n\tconstruct: { id: string },\n): S {\n\tObject.defineProperty(service, DERIVED_FROM, { value: construct.id });\n\treturn service;\n}\n\n/**\n * \\`existing\\`, with the edge a service stands for — a construct's own id, or\n * the id a derived service was marked with. Unchanged for a plain service.\n */\nexport function edgesWith(\n\tservice: unknown,\n\texisting: readonly string[] = [],\n): string[] {\n\tif (isConsumable(service)) return idsOf([service], existing);\n\n\tconst id =\n\t\ttypeof service === 'object' && service !== null\n\t\t\t? (service as { [DERIVED_FROM]?: unknown })[DERIVED_FROM]\n\t\t\t: undefined;\n\n\treturn typeof id === 'string'\n\t\t? [...new Set([...existing, id])]\n\t\t: [...existing];\n}\n\nexport function isConsumable(value: unknown): value is Consumable {\n\tif (typeof value !== 'object' || value === null) return false;\n\n\tconst candidate = value as Partial<Consumable>;\n\n\treturn (\n\t\ttypeof candidate.id === 'string' &&\n\t\ttypeof candidate.declare === 'function' &&\n\t\ttypeof (candidate.service as Service | undefined)?.serviceName === 'string'\n\t);\n}\n\n/**\n * The service behind either face.\n *\n * `.database()` and the publisher slots take a construct now; they took a\n * `Service` before and still do, because a hand-written one is exactly what\n * `Construct.fromService` exists to lift and not everything has been lifted.\n */\nexport function serviceOf<TName extends string, TClient>(\n\tsource: Consumable<TName, TClient> | Service<TName, TClient>,\n): Service<TName, TClient> {\n\t// A construct's service key is `Uncapitalize<TName>` and the slot is typed\n\t// by `TName`; the two describe the same key, and only the cast says so.\n\treturn isConsumable(source)\n\t\t? (source.service as unknown as Service<TName, TClient>)\n\t\t: (source as Service<TName, TClient>);\n}\n"],"mappings":";;;;;;;;;;;;;AAgGA,SAAgB,OAAO,WAAmC;CACzD,MAAM,YAAY,UAChB,QAAQ,CAAC,CACT,MAAM,gBAAgB,YAAY,OAAO,UAAU,EAAE;CAEvD,IAAI,CAAC,WAAW,MAAM,IAAI,cAAc,SAAS;CAEjD,OAAO;EAAE,QAAQ,UAAU;EAAI,MAAM,UAAU;CAAK;AACrD;;;;;;;;AA6CA,SAAgB,WACf,YACgB;CAChB,OAAO,WAAW,KAAK,cAAc;EACpC,IAAI,CAAC,aAAa,SAAS,GAAG,MAAM,IAAI,cAAc,SAAS;EAE/D,OAAO,UAAU;CAClB,CAAC;AACF;;;;;;;;;;AAWA,SAAgB,MACf,YACA,WAA8B,CAAC,GACpB;CACX,OAAO,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,UAAU,GAAG,WAAW,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;AACrE;;AAGA,IAAa,gBAAb,cAAmC,MAAM;CACnB;CAArB,YAAY,OAAyB;EACpC,MAAM,OACL,OAAO,UAAU,YAAY,UAAU,QAAQ,iBAAiB,QAC7D,gBAAgB,OAAQ,MAAmC,WAAW,EAAE,KACxE,KAAK,OAAO;EAEhB,MACC,gDAAgD,KAAK,8EAGtD;EAVoB,KAAA,QAAA;EAWpB,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;;AAcA,MAAM,eAAe,OAAO,IAAI,mCAAmC;;;;;;;;;AAUnE,SAAgB,YACf,SACA,WACI;CACJ,OAAO,eAAe,SAAS,cAAc,EAAE,OAAO,UAAU,GAAG,CAAC;CACpE,OAAO;AACR;;;;;AAMA,SAAgB,UACf,SACA,WAA8B,CAAC,GACpB;CACX,IAAI,aAAa,OAAO,GAAG,OAAO,MAAM,CAAC,OAAO,GAAG,QAAQ;CAE3D,MAAM,KACL,OAAO,YAAY,YAAY,YAAY,OACvC,QAAyC,gBAC1C,KAAA;CAEJ,OAAO,OAAO,OAAO,WAClB,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,CAAC,IAC9B,CAAC,GAAG,QAAQ;AAChB;AAEA,SAAgB,aAAa,OAAqC;CACjE,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CAExD,MAAM,YAAY;CAElB,OACC,OAAO,UAAU,OAAO,YACxB,OAAO,UAAU,YAAY,cAC7B,OAAQ,UAAU,SAAiC,gBAAgB;AAErE;;;;;;;;AASA,SAAgB,UACf,QAC0B;CAG1B,OAAO,aAAa,MAAM,IACtB,OAAO,UACP;AACL"}
|
|
1
|
+
{"version":3,"file":"construct-interface.mjs","names":[],"sources":["../src/construct-interface.ts"],"sourcesContent":["/**\n * The construct contract.\n *\n * A construct is three things at once — an infrastructure requirement at build\n * time, a runtime capability, and something other code can consume — which is\n * what forces exactly these three members.\n *\n * An **interface**, not a base class: `Endpoint`, `Cron`, `Queue`, and `Topic`\n * can satisfy it without inheritance surgery, a lifted `Service` can satisfy it\n * as a plain object, and `.dependsOn()` gets its enforcement structurally — a\n * `Service` (`{ serviceName, register }`) simply does not match\n * `{ id, declare, service }`, with no `instanceof` anywhere.\n *\n * Lives in its own module while the existing abstract `Construct` class is\n * still in use; it takes that name once the class is gone.\n */\n\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Declaration, Dependency } from '@geekmidas/manifest';\nimport type { Service } from '@geekmidas/services';\n\n/**\n * @typeParam TName - the construct's canonical id, PascalCase. Keeping it a\n * literal is what lets the service key be `Uncapitalize<TName>` — a TypeScript\n * intrinsic, so no custom transform needs a runtime twin.\n * @typeParam TClient - what consuming this construct hands you. `never` means it\n * owns no address and cannot be consumed: a `Cron` is fired by a schedule and a\n * `Subscriber` is reached through its topic, so `.dependsOn()` on either is a\n * compile error rather than a stub that throws.\n */\nexport interface Construct<TName extends string = string, TClient = never> {\n\t/** Canonical, PascalCase, unique within the manifest. */\n\treadonly id: TName;\n\n\t/**\n\t * The build-time face: what this construct contributes to the manifest.\n\t *\n\t * Returns an array because some constructs contribute more than one node — a\n\t * queue declares the queue and its worker, a database declares its migrator\n\t * and seeder. Most return one.\n\t */\n\tdeclare(): Declaration[];\n\n\t/**\n\t * The consumable face — the address this construct owns, as a client.\n\t *\n\t * A field assigned once rather than a getter. `Construct.getEnvironment`\n\t * caches by service *object*, and `Topic.publisher` returns a fresh literal\n\t * on every access, so that cache never hits for topics or queues today.\n\t */\n\treadonly service: [TClient] extends [never]\n\t\t? never\n\t\t: Service<Uncapitalize<TName>, TClient>;\n}\n\n/**\n * The build-time face alone — an id and what it contributes to the manifest.\n *\n * Weaker than {@link Consumable} on purpose. An edge is not always an\n * injection: a site depending on an API needs that API's *address at build\n * time* and has no service record to put a client into, so requiring one would\n * make the weakest kind of edge impossible to express with the strongest\n * interface. Discovery asks this same question and nothing more.\n */\nexport interface Declarable<TName extends string = string> {\n\treadonly id: TName;\n\tdeclare(): Declaration[];\n}\n\n/**\n * A construct that authenticates requests — what `RestApi.auth()` takes.\n *\n * `verify` is the one thing every provider shares: given a request's headers,\n * whose request is it — the session, or `null` when there is none. Whether the\n * provider is a server mounted beside the API, deployed elsewhere, or an issuer\n * somebody else runs is its own business; a surface only ever asks this.\n */\nexport interface Authenticator<TSession = unknown> extends Declarable {\n\tverify(\n\t\theaders: Headers,\n\t\tenvParser: EnvironmentParser<{}>,\n\t): Promise<TSession | null>;\n}\n\n/**\n * The edge that points at a construct.\n *\n * A construct's *canonical* node is the one carrying its own id — the others are\n * things it owns rather than things it is, like the signing secret beside an\n * auth server — so the kind an edge records is read off that node instead of\n * being written down beside it. Hand-written kinds are the same fact stated\n * twice, and the copy is what goes stale when a construct changes what it\n * declares.\n *\n * @throws {NotAConstruct} when the value declares nothing under its own id.\n */\nexport function edgeTo(construct: Declarable): Dependency {\n\tconst canonical = construct\n\t\t.declare()\n\t\t.find((declaration) => declaration.id === construct.id);\n\n\tif (!canonical) throw new NotAConstruct(construct);\n\n\treturn { target: construct.id, kind: canonical.kind };\n}\n\n/** What consuming a construct hands you. */\nexport type Infer<C> =\n\tC extends Construct<string, infer TClient> ? TClient : never;\n\n/** A construct's canonical id. */\nexport type NameOf<C> =\n\tC extends Construct<infer TName, unknown> ? TName : never;\n\n/**\n * What `.dependsOn([…])` accepts: a construct that owns a client.\n *\n * Structural, and deliberately narrower than {@link Construct} — it is the\n * face a *consumer* needs, so the builders can accept a database, a bucket, a\n * mail sender, a queue, or a topic without importing any of them. A plain\n * `Service` is not one of these, which is the point: constructs-only confines\n * env sniffing to `.services()` and the explicit lift, so retiring that method\n * retires implicit inference with it.\n */\nexport interface Consumable<TName extends string = string, TClient = unknown> {\n\treadonly id: TName;\n\treadonly service: Service<Uncapitalize<TName>, TClient>;\n\tdeclare(): Declaration[];\n}\n\n/**\n * The services a list of constructs dissolves into.\n *\n * A mapped tuple, so `[db, uploads]` types as `[Service<'orders', Kysely<DB>>,\n * Service<'uploads', StorageClient>]` and the handler's service record gains\n * both keys — the same machinery `.services()` already uses, which is why\n * `dependsOn` needs no type plumbing of its own.\n */\nexport type ServicesOf<T extends readonly Consumable[]> = {\n\t[K in keyof T]: T[K]['service'];\n};\n\n/**\n * The services of a list of constructs, at runtime.\n *\n * @throws {NotAConstruct} when handed something else. The type already refuses\n * it, but a JavaScript caller gets no such warning, and a `Service` slipping\n * through would fail later as an undefined key in the handler.\n */\nexport function servicesOf<const T extends readonly Consumable[]>(\n\tconstructs: T,\n): ServicesOf<T> {\n\treturn constructs.map((construct) => {\n\t\tif (!isConsumable(construct)) throw new NotAConstruct(construct);\n\n\t\treturn construct.service;\n\t}) as ServicesOf<T>;\n}\n\n/**\n * The other half of `servicesOf`: the same edge, as the manifest records it.\n *\n * `.dependsOn()` used to keep only the services, which is what a handler runs\n * with — and an id cannot be recovered from a service name reliably, so the\n * edges were gone by the time the build could read them. Both halves are taken\n * from one call now, and `existing` is folded in so repeated `.dependsOn()`\n * calls accumulate the way `.services()` already does.\n */\nexport function idsOf(\n\tconstructs: readonly Consumable[],\n\texisting: readonly string[] = [],\n): string[] {\n\treturn [...new Set([...existing, ...constructs.map(({ id }) => id)])];\n}\n\n/** Something that is not a construct was passed to `.dependsOn()`. */\nexport class NotAConstruct extends Error {\n\tconstructor(readonly value: unknown) {\n\t\tconst name =\n\t\t\ttypeof value === 'object' && value !== null && 'serviceName' in value\n\t\t\t\t? `the service '${String((value as { serviceName: unknown }).serviceName)}'`\n\t\t\t\t: `a ${typeof value}`;\n\n\t\tsuper(\n\t\t\t`.dependsOn() takes constructs, and was given ${name}. ` +\n\t\t\t\t`Pass it to .services([…]) instead.`,\n\t\t);\n\t\tthis.name = 'NotAConstruct';\n\t}\n}\n\n/**\n * Whether a value is a construct rather than a bare `Service`.\n *\n * Structural rather than `instanceof`: a construct from a second copy of\n * `@geekmidas/constructs` — a linked workspace, two versions in a lockfile — is\n * still a construct, and `instanceof` is exactly the check that says otherwise.\n */\n/**\n * The construct a service was derived from — the \\`users\\` topic, for\n * \\`users.publisher\\`. A symbol, so it rides on the service object without\n * becoming part of its shape.\n */\nconst DERIVED_FROM = Symbol.for('@geekmidas/constructs/derivedFrom');\n\n/**\n * Mark a service as standing for the construct it was derived from.\n *\n * \\`.publisher(users.publisher)\\` takes a service, not the topic, and an id\n * cannot be recovered from a service name. Without the mark the edge was lost:\n * the manifest never heard that the API publishes to \\`users\\`, so the app's\n * container was composed without \\`USERS_PUBLISHER_CONNECTION_STRING\\`.\n */\nexport function derivedFrom<S extends Service>(\n\tservice: S,\n\tconstruct: { id: string },\n): S {\n\tObject.defineProperty(service, DERIVED_FROM, { value: construct.id });\n\treturn service;\n}\n\n/**\n * \\`existing\\`, with the edge a service stands for — a construct's own id, or\n * the id a derived service was marked with. Unchanged for a plain service.\n */\nexport function edgesWith(\n\tservice: unknown,\n\texisting: readonly string[] = [],\n): string[] {\n\tif (isConsumable(service)) return idsOf([service], existing);\n\n\tconst id =\n\t\ttypeof service === 'object' && service !== null\n\t\t\t? (service as { [DERIVED_FROM]?: unknown })[DERIVED_FROM]\n\t\t\t: undefined;\n\n\treturn typeof id === 'string'\n\t\t? [...new Set([...existing, id])]\n\t\t: [...existing];\n}\n\nexport function isConsumable(value: unknown): value is Consumable {\n\tif (typeof value !== 'object' || value === null) return false;\n\n\tconst candidate = value as Partial<Consumable>;\n\n\treturn (\n\t\ttypeof candidate.id === 'string' &&\n\t\ttypeof candidate.declare === 'function' &&\n\t\ttypeof (candidate.service as Service | undefined)?.serviceName === 'string'\n\t);\n}\n\n/**\n * The service behind either face.\n *\n * `.database()` and the publisher slots take a construct now; they took a\n * `Service` before and still do, because not every hand-written service has a\n * construct to stand for it.\n */\nexport function serviceOf<TName extends string, TClient>(\n\tsource: Consumable<TName, TClient> | Service<TName, TClient>,\n): Service<TName, TClient> {\n\t// A construct's service key is `Uncapitalize<TName>` and the slot is typed\n\t// by `TName`; the two describe the same key, and only the cast says so.\n\treturn isConsumable(source)\n\t\t? (source.service as unknown as Service<TName, TClient>)\n\t\t: (source as Service<TName, TClient>);\n}\n"],"mappings":";;;;;;;;;;;;;AAgGA,SAAgB,OAAO,WAAmC;CACzD,MAAM,YAAY,UAChB,QAAQ,CAAC,CACT,MAAM,gBAAgB,YAAY,OAAO,UAAU,EAAE;CAEvD,IAAI,CAAC,WAAW,MAAM,IAAI,cAAc,SAAS;CAEjD,OAAO;EAAE,QAAQ,UAAU;EAAI,MAAM,UAAU;CAAK;AACrD;;;;;;;;AA6CA,SAAgB,WACf,YACgB;CAChB,OAAO,WAAW,KAAK,cAAc;EACpC,IAAI,CAAC,aAAa,SAAS,GAAG,MAAM,IAAI,cAAc,SAAS;EAE/D,OAAO,UAAU;CAClB,CAAC;AACF;;;;;;;;;;AAWA,SAAgB,MACf,YACA,WAA8B,CAAC,GACpB;CACX,OAAO,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,UAAU,GAAG,WAAW,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;AACrE;;AAGA,IAAa,gBAAb,cAAmC,MAAM;CACnB;CAArB,YAAY,OAAyB;EACpC,MAAM,OACL,OAAO,UAAU,YAAY,UAAU,QAAQ,iBAAiB,QAC7D,gBAAgB,OAAQ,MAAmC,WAAW,EAAE,KACxE,KAAK,OAAO;EAEhB,MACC,gDAAgD,KAAK,qCAEtD;EAToB,KAAA,QAAA;EAUpB,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;;AAcA,MAAM,eAAe,OAAO,IAAI,mCAAmC;;;;;;;;;AAUnE,SAAgB,YACf,SACA,WACI;CACJ,OAAO,eAAe,SAAS,cAAc,EAAE,OAAO,UAAU,GAAG,CAAC;CACpE,OAAO;AACR;;;;;AAMA,SAAgB,UACf,SACA,WAA8B,CAAC,GACpB;CACX,IAAI,aAAa,OAAO,GAAG,OAAO,MAAM,CAAC,OAAO,GAAG,QAAQ;CAE3D,MAAM,KACL,OAAO,YAAY,YAAY,YAAY,OACvC,QAAyC,gBAC1C,KAAA;CAEJ,OAAO,OAAO,OAAO,WAClB,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,CAAC,IAC9B,CAAC,GAAG,QAAQ;AAChB;AAEA,SAAgB,aAAa,OAAqC;CACjE,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CAExD,MAAM,YAAY;CAElB,OACC,OAAO,UAAU,OAAO,YACxB,OAAO,UAAU,YAAY,cAC7B,OAAQ,UAAU,SAAiC,gBAAgB;AAErE;;;;;;;;AASA,SAAgB,UACf,QAC0B;CAG1B,OAAO,aAAa,MAAM,IACtB,OAAO,UACP;AACL"}
|
package/dist/credential.cjs
CHANGED
|
@@ -54,7 +54,7 @@ var Credential = class {
|
|
|
54
54
|
this.options = options;
|
|
55
55
|
const canonical = (0, _geekmidas_manifest.canonicalId)(id);
|
|
56
56
|
this.id = canonical;
|
|
57
|
-
this.keys = {
|
|
57
|
+
this.keys = { credentials: (0, _geekmidas_manifest.provideKey)(canonical, "credentials") };
|
|
58
58
|
this.service = {
|
|
59
59
|
serviceName: (0, _geekmidas_manifest.serviceKey)(canonical),
|
|
60
60
|
register: (registerOptions) => this.connect(registerOptions)
|
|
@@ -64,7 +64,7 @@ var Credential = class {
|
|
|
64
64
|
return [{
|
|
65
65
|
kind: "credential",
|
|
66
66
|
id: this.id,
|
|
67
|
-
provides: [this.keys.
|
|
67
|
+
provides: [this.keys.credentials]
|
|
68
68
|
}];
|
|
69
69
|
}
|
|
70
70
|
connect(options) {
|
|
@@ -72,16 +72,28 @@ var Credential = class {
|
|
|
72
72
|
this.resolved ??= this.resolve(options);
|
|
73
73
|
return this.resolved;
|
|
74
74
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
return await (0, _geekmidas_schema_parser.parseSchema)(this.options.schema, decode(raw));
|
|
79
|
-
} catch (issues) {
|
|
80
|
-
throw new MalformedCredential(this.id, this.keys.credential, issues);
|
|
81
|
-
}
|
|
75
|
+
resolve(options) {
|
|
76
|
+
return readCredentials(this.id, this.keys.credentials, this.options.schema, options.envParser);
|
|
82
77
|
}
|
|
83
78
|
};
|
|
84
79
|
/**
|
|
80
|
+
* A credentials key, read and validated against its schema.
|
|
81
|
+
*
|
|
82
|
+
* Shared with every construct that holds a third party's credentials — an
|
|
83
|
+
* `ExternalApi` reads its own the same way — so the shape a stage stores and
|
|
84
|
+
* the error a bad value raises are the same everywhere.
|
|
85
|
+
*
|
|
86
|
+
* @throws {MalformedCredential} when the value is not what the schema says.
|
|
87
|
+
*/
|
|
88
|
+
async function readCredentials(id, key, schema, envParser) {
|
|
89
|
+
const { raw } = envParser.create((get) => ({ raw: get(key).string() })).parse();
|
|
90
|
+
try {
|
|
91
|
+
return await (0, _geekmidas_schema_parser.parseSchema)(schema, decode(raw));
|
|
92
|
+
} catch (issues) {
|
|
93
|
+
throw new MalformedCredential(id, key, issues);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
85
97
|
* The raw environment value as the thing the schema should see.
|
|
86
98
|
*
|
|
87
99
|
* JSON when it is JSON, and the string itself when it is not — a credential
|
|
@@ -126,5 +138,6 @@ function describe(issues) {
|
|
|
126
138
|
//#endregion
|
|
127
139
|
exports.Credential = Credential;
|
|
128
140
|
exports.MalformedCredential = MalformedCredential;
|
|
141
|
+
exports.readCredentials = readCredentials;
|
|
129
142
|
|
|
130
143
|
//# sourceMappingURL=credential.cjs.map
|
package/dist/credential.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credential.cjs","names":["canonicalId","provideKey","serviceKey","parseSchema"],"sources":["../src/credential.ts"],"sourcesContent":["/**\n * `Credential` — a third-party credential with a shape.\n *\n * The answer to the design's first open question, \"where does `Secret` sit?\".\n * It sits beside a secret rather than replacing it, because the two differ by\n * *lifecycle* and that is the only difference worth two kinds for: a secret is\n * generated and rotated by the platform and is one opaque string, while a\n * credential is issued by someone else, arrives with several fields, and is\n * worth validating on the way in.\n *\n * ```ts\n * export const stripe = new Credential('Stripe', {\n * schema: z.object({ secretKey: z.string(), webhookSecret: z.string() }),\n * });\n *\n * // in a handler — no await, already parsed and validated\n * services.stripe.secretKey\n * ```\n *\n * **Nothing about it is async at the call site**, which is the part that looks\n * like it should be hard and is not. `Service.register()` may return a promise\n * and `ServiceDiscovery` awaits every one before a handler runs, so fetching a\n * value and validating it — including when a StandardSchema's `~standard.validate`\n * returns a promise of its own — both happen inside that existing seam.\n *\n * **One key holding JSON, not one key per field.** That is the shape a secret\n * manager stores, and it is the only shape that works with an arbitrary\n * StandardSchema: the spec has no introspection API, so enumerating a schema's\n * fields means reaching into one library's internals (`.shape`) and being wrong\n * for every other.\n */\n\nimport {\n\ttype ConstructName,\n\tcanonicalId,\n\ttype Declaration,\n\tprovideKey,\n\tserviceKey,\n} from '@geekmidas/manifest';\nimport { parseSchema } from '@geekmidas/schema/parser';\nimport type { Service, ServiceRegisterOptions } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Consumable } from './construct-interface';\n\n/** What a credential's schema yields. */\ntype Value<TSchema extends StandardSchemaV1> =\n\tStandardSchemaV1.InferOutput<TSchema>;\n\nexport interface CredentialOptions<TSchema extends StandardSchemaV1> {\n\t/**\n\t * What the credential must look like.\n\t *\n\t * Validated at registration, so a malformed or half-set credential fails\n\t * when the process starts rather than on the first request that needs the\n\t * one field somebody forgot.\n\t */\n\tschema: TSchema;\n\t/**\n\t * Re-resolve on every registration instead of once per process.\n\t *\n\t * Off by default: a credential is resolved once and reused, because the\n\t * alternative is a fetch on every request. The cost of that default is that\n\t * a rotated credential needs a restart, which is the right trade for a value\n\t * that changes a few times a year — and this is the escape hatch for when it\n\t * is not.\n\t */\n\trefresh?: boolean;\n}\n\nexport class Credential<\n\tTName extends string = string,\n\tTSchema extends StandardSchemaV1 = StandardSchemaV1,\n> implements Consumable<TName, Value<TSchema>>\n{\n\t// `Consumable` rather than `Construct`, and not by preference: `Construct`\n\t// types its service as `[TClient] extends [never] ? never : Service<…>` so\n\t// that a `Cron` cannot be depended on, and TypeScript cannot evaluate that\n\t// conditional while `TClient` is still a type parameter. Every construct\n\t// with a concrete client satisfies `Construct`; the first one whose client\n\t// is generic cannot. `Consumable` is the face `.dependsOn()` requires and\n\t// carries no conditional, so it is the honest annotation here.\n\treadonly id: TName;\n\treadonly service: Service<Uncapitalize<TName>, Value<TSchema>>;\n\n\t/**\n\t * Declared once and read by both `declare()` and `connect()`, so the key the\n\t * target publishes and the key the client reads cannot drift.\n\t */\n\tprivate readonly keys: {
|
|
1
|
+
{"version":3,"file":"credential.cjs","names":["canonicalId","provideKey","serviceKey","parseSchema"],"sources":["../src/credential.ts"],"sourcesContent":["/**\n * `Credential` — a third-party credential with a shape.\n *\n * The answer to the design's first open question, \"where does `Secret` sit?\".\n * It sits beside a secret rather than replacing it, because the two differ by\n * *lifecycle* and that is the only difference worth two kinds for: a secret is\n * generated and rotated by the platform and is one opaque string, while a\n * credential is issued by someone else, arrives with several fields, and is\n * worth validating on the way in.\n *\n * ```ts\n * export const stripe = new Credential('Stripe', {\n * schema: z.object({ secretKey: z.string(), webhookSecret: z.string() }),\n * });\n *\n * // in a handler — no await, already parsed and validated\n * services.stripe.secretKey\n * ```\n *\n * **Nothing about it is async at the call site**, which is the part that looks\n * like it should be hard and is not. `Service.register()` may return a promise\n * and `ServiceDiscovery` awaits every one before a handler runs, so fetching a\n * value and validating it — including when a StandardSchema's `~standard.validate`\n * returns a promise of its own — both happen inside that existing seam.\n *\n * **One key holding JSON, not one key per field.** That is the shape a secret\n * manager stores, and it is the only shape that works with an arbitrary\n * StandardSchema: the spec has no introspection API, so enumerating a schema's\n * fields means reaching into one library's internals (`.shape`) and being wrong\n * for every other.\n */\n\nimport {\n\ttype ConstructName,\n\tcanonicalId,\n\ttype Declaration,\n\tprovideKey,\n\tserviceKey,\n} from '@geekmidas/manifest';\nimport { parseSchema } from '@geekmidas/schema/parser';\nimport type { Service, ServiceRegisterOptions } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Consumable } from './construct-interface';\n\n/** What a credential's schema yields. */\ntype Value<TSchema extends StandardSchemaV1> =\n\tStandardSchemaV1.InferOutput<TSchema>;\n\nexport interface CredentialOptions<TSchema extends StandardSchemaV1> {\n\t/**\n\t * What the credential must look like.\n\t *\n\t * Validated at registration, so a malformed or half-set credential fails\n\t * when the process starts rather than on the first request that needs the\n\t * one field somebody forgot.\n\t */\n\tschema: TSchema;\n\t/**\n\t * Re-resolve on every registration instead of once per process.\n\t *\n\t * Off by default: a credential is resolved once and reused, because the\n\t * alternative is a fetch on every request. The cost of that default is that\n\t * a rotated credential needs a restart, which is the right trade for a value\n\t * that changes a few times a year — and this is the escape hatch for when it\n\t * is not.\n\t */\n\trefresh?: boolean;\n}\n\nexport class Credential<\n\tTName extends string = string,\n\tTSchema extends StandardSchemaV1 = StandardSchemaV1,\n> implements Consumable<TName, Value<TSchema>>\n{\n\t// `Consumable` rather than `Construct`, and not by preference: `Construct`\n\t// types its service as `[TClient] extends [never] ? never : Service<…>` so\n\t// that a `Cron` cannot be depended on, and TypeScript cannot evaluate that\n\t// conditional while `TClient` is still a type parameter. Every construct\n\t// with a concrete client satisfies `Construct`; the first one whose client\n\t// is generic cannot. `Consumable` is the face `.dependsOn()` requires and\n\t// carries no conditional, so it is the honest annotation here.\n\treadonly id: TName;\n\treadonly service: Service<Uncapitalize<TName>, Value<TSchema>>;\n\n\t/**\n\t * Declared once and read by both `declare()` and `connect()`, so the key the\n\t * target publishes and the key the client reads cannot drift.\n\t */\n\tprivate readonly keys: { credentials: string };\n\n\t/**\n\t * The resolved value, held as the *promise* rather than the value.\n\t *\n\t * Caching the promise is what makes two concurrent registrations share one\n\t * resolution: caching the value would let both start before either finished,\n\t * which is a duplicated fetch every cold start rather than never.\n\t */\n\tprivate resolved?: Promise<Value<TSchema>>;\n\n\tconstructor(\n\t\tid: ConstructName<TName>,\n\t\tprivate readonly options: CredentialOptions<TSchema>,\n\t) {\n\t\tconst canonical = canonicalId(id as string);\n\n\t\tthis.id = canonical as TName;\n\t\tthis.keys = { credentials: provideKey(canonical, 'credentials') };\n\n\t\t// A field, not a getter: consumers cache services by object identity.\n\t\tthis.service = {\n\t\t\tserviceName: serviceKey(canonical) as Uncapitalize<TName>,\n\t\t\tregister: (registerOptions) => this.connect(registerOptions),\n\t\t};\n\t}\n\n\tdeclare(): Declaration[] {\n\t\treturn [\n\t\t\t{\n\t\t\t\tkind: 'credential',\n\t\t\t\tid: this.id,\n\t\t\t\tprovides: [this.keys.credentials],\n\t\t\t},\n\t\t];\n\t}\n\n\tprivate connect(options: ServiceRegisterOptions): Promise<Value<TSchema>> {\n\t\tif (this.options.refresh) return this.resolve(options);\n\n\t\tthis.resolved ??= this.resolve(options);\n\n\t\treturn this.resolved;\n\t}\n\n\tprivate resolve(options: ServiceRegisterOptions): Promise<Value<TSchema>> {\n\t\treturn readCredentials(\n\t\t\tthis.id,\n\t\t\tthis.keys.credentials,\n\t\t\tthis.options.schema,\n\t\t\toptions.envParser,\n\t\t);\n\t}\n}\n\n/**\n * A credentials key, read and validated against its schema.\n *\n * Shared with every construct that holds a third party's credentials — an\n * `ExternalApi` reads its own the same way — so the shape a stage stores and\n * the error a bad value raises are the same everywhere.\n *\n * @throws {MalformedCredential} when the value is not what the schema says.\n */\nexport async function readCredentials<TSchema extends StandardSchemaV1>(\n\tid: string,\n\tkey: string,\n\tschema: TSchema,\n\tenvParser: ServiceRegisterOptions['envParser'],\n): Promise<Value<TSchema>> {\n\tconst { raw } = envParser\n\t\t.create((get) => ({ raw: get(key).string() }))\n\t\t.parse();\n\n\ttry {\n\t\treturn await parseSchema(schema, decode(raw));\n\t} catch (issues) {\n\t\tthrow new MalformedCredential(id, key, issues);\n\t}\n}\n\n/**\n * The raw environment value as the thing the schema should see.\n *\n * JSON when it is JSON, and the string itself when it is not — a credential\n * with a single opaque field is ordinary, and requiring `\"…\"` around it would\n * be ceremony that every operator setting one by hand would get wrong once.\n */\nfunction decode(raw: string): unknown {\n\tconst value = raw.startsWith(JSON_SCHEME)\n\t\t? raw.slice(JSON_SCHEME.length)\n\t\t: raw;\n\n\ttry {\n\t\treturn JSON.parse(value);\n\t} catch {\n\t\treturn value;\n\t}\n}\n\n/**\n * The explicit form, for the case a credential legitimately *is* a JSON string\n * and must not be parsed into an object. Rare, and cheaper to support than to\n * explain.\n */\nconst JSON_SCHEME = 'json:';\n\n/** A credential was set, and is not what its schema says it should be. */\nexport class MalformedCredential extends Error {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly key: string,\n\t\treadonly issues: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`${key} is not a valid ${id} credential. ` +\n\t\t\t\t`It is validated where it is read, so this is the value that is set ` +\n\t\t\t\t`rather than the code that uses it: ${describe(issues)}`,\n\t\t);\n\t\tthis.name = 'MalformedCredential';\n\t}\n}\n\n/** StandardSchema issues as one line. */\nfunction describe(issues: unknown): string {\n\tif (!Array.isArray(issues)) return String(issues);\n\n\treturn issues\n\t\t.map((issue: StandardSchemaV1.Issue) => {\n\t\t\tconst path = issue.path\n\t\t\t\t?.map((segment) =>\n\t\t\t\t\ttypeof segment === 'object' ? String(segment.key) : String(segment),\n\t\t\t\t)\n\t\t\t\t.join('.');\n\n\t\t\treturn path ? `${path}: ${issue.message}` : issue.message;\n\t\t})\n\t\t.join('; ');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqEA,IAAa,aAAb,MAIA;CA4BmB;CApBlB;CACA;;;;;CAMA;;;;;;;;CASA;CAEA,YACC,IACA,SACC;EADgB,KAAA,UAAA;EAEjB,MAAM,aAAA,GAAYA,oBAAAA,YAAAA,CAAY,EAAY;EAE1C,KAAK,KAAK;EACV,KAAK,OAAO,EAAE,cAAA,GAAaC,oBAAAA,WAAAA,CAAW,WAAW,aAAa,EAAE;EAGhE,KAAK,UAAU;GACd,cAAA,GAAaC,oBAAAA,WAAAA,CAAW,SAAS;GACjC,WAAW,oBAAoB,KAAK,QAAQ,eAAe;EAC5D;CACD;CAEA,UAAyB;EACxB,OAAO,CACN;GACC,MAAM;GACN,IAAI,KAAK;GACT,UAAU,CAAC,KAAK,KAAK,WAAW;EACjC,CACD;CACD;CAEA,QAAgB,SAA0D;EACzE,IAAI,KAAK,QAAQ,SAAS,OAAO,KAAK,QAAQ,OAAO;EAErD,KAAK,aAAa,KAAK,QAAQ,OAAO;EAEtC,OAAO,KAAK;CACb;CAEA,QAAgB,SAA0D;EACzE,OAAO,gBACN,KAAK,IACL,KAAK,KAAK,aACV,KAAK,QAAQ,QACb,QAAQ,SACT;CACD;AACD;;;;;;;;;;AAWA,eAAsB,gBACrB,IACA,KACA,QACA,WAC0B;CAC1B,MAAM,EAAE,QAAQ,UACd,QAAQ,SAAS,EAAE,KAAK,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAC7C,MAAM;CAER,IAAI;EACH,OAAO,OAAA,GAAMC,yBAAAA,YAAAA,CAAY,QAAQ,OAAO,GAAG,CAAC;CAC7C,SAAS,QAAQ;EAChB,MAAM,IAAI,oBAAoB,IAAI,KAAK,MAAM;CAC9C;AACD;;;;;;;;AASA,SAAS,OAAO,KAAsB;CACrC,MAAM,QAAQ,IAAI,WAAW,WAAW,IACrC,IAAI,MAAM,YAAY,MAAM,IAC5B;CAEH,IAAI;EACH,OAAO,KAAK,MAAM,KAAK;CACxB,QAAQ;EACP,OAAO;CACR;AACD;;;;;;AAOA,MAAM,cAAc;;AAGpB,IAAa,sBAAb,cAAyC,MAAM;CAEpC;CACA;CACA;CAHV,YACC,IACA,KACA,QACC;EACD,MACC,GAAG,IAAI,kBAAkB,GAAG,qHAEW,SAAS,MAAM,GACvD;EARS,KAAA,KAAA;EACA,KAAA,MAAA;EACA,KAAA,SAAA;EAOT,KAAK,OAAO;CACb;AACD;;AAGA,SAAS,SAAS,QAAyB;CAC1C,IAAI,CAAC,MAAM,QAAQ,MAAM,GAAG,OAAO,OAAO,MAAM;CAEhD,OAAO,OACL,KAAK,UAAkC;EACvC,MAAM,OAAO,MAAM,MAChB,KAAK,YACN,OAAO,YAAY,WAAW,OAAO,QAAQ,GAAG,IAAI,OAAO,OAAO,CACnE,CAAC,CACA,KAAK,GAAG;EAEV,OAAO,OAAO,GAAG,KAAK,IAAI,MAAM,YAAY,MAAM;CACnD,CAAC,CAAC,CACD,KAAK,IAAI;AACZ"}
|
package/dist/credential.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as StandardSchemaV1 } from "./index-CeEtxDmK.cjs";
|
|
2
|
-
import { r as Consumable } from "./construct-interface-
|
|
3
|
-
import { Service } from "@geekmidas/services";
|
|
2
|
+
import { r as Consumable } from "./construct-interface-DcNaRKoC.cjs";
|
|
3
|
+
import { Service, ServiceRegisterOptions } from "@geekmidas/services";
|
|
4
4
|
import { ConstructName, Declaration } from "@geekmidas/manifest";
|
|
5
5
|
//#region src/credential.d.ts
|
|
6
6
|
/** What a credential's schema yields. */
|
|
@@ -47,6 +47,16 @@ export declare class Credential<TName extends string = string, TSchema extends S
|
|
|
47
47
|
private connect;
|
|
48
48
|
private resolve;
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* A credentials key, read and validated against its schema.
|
|
52
|
+
*
|
|
53
|
+
* Shared with every construct that holds a third party's credentials — an
|
|
54
|
+
* `ExternalApi` reads its own the same way — so the shape a stage stores and
|
|
55
|
+
* the error a bad value raises are the same everywhere.
|
|
56
|
+
*
|
|
57
|
+
* @throws {MalformedCredential} when the value is not what the schema says.
|
|
58
|
+
*/
|
|
59
|
+
export declare function readCredentials<TSchema extends StandardSchemaV1>(id: string, key: string, schema: TSchema, envParser: ServiceRegisterOptions['envParser']): Promise<Value<TSchema>>;
|
|
50
60
|
/** A credential was set, and is not what its schema says it should be. */
|
|
51
61
|
export declare class MalformedCredential extends Error {
|
|
52
62
|
readonly id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credential.d.cts","names":[],"sources":["../src/credential.ts"],"mappings":";;;;;;KA6CK,MAAM,gBAAgB,oBAC1B,iBAAiB,YAAY;iBAEb,kBAAkB,gBAAgB;;;;;;;;EAQlD,QAAQ;;;;;;;;;;EAUR;;qBAGY,WACZ,+BACA,gBAAgB,mBAAmB,6BACvB,WAAW,OAAO,MAAM;mBA6BlB;WApBT,IAAI;WACJ,SAAS,QAAQ,aAAa,QAAQ,MAAM;;;;;mBAMpC;;;;;;;;UAST;EAER,YACC,IAAI,cAAc,QACD,SAAS,kBAAkB;EAc7C,WAAW;UAUH;
|
|
1
|
+
{"version":3,"file":"credential.d.cts","names":[],"sources":["../src/credential.ts"],"mappings":";;;;;;KA6CK,MAAM,gBAAgB,oBAC1B,iBAAiB,YAAY;iBAEb,kBAAkB,gBAAgB;;;;;;;;EAQlD,QAAQ;;;;;;;;;;EAUR;;qBAGY,WACZ,+BACA,gBAAgB,mBAAmB,6BACvB,WAAW,OAAO,MAAM;mBA6BlB;WApBT,IAAI;WACJ,SAAS,QAAQ,aAAa,QAAQ,MAAM;;;;;mBAMpC;;;;;;;;UAST;EAER,YACC,IAAI,cAAc,QACD,SAAS,kBAAkB;EAc7C,WAAW;UAUH;UAQA;;;;;;;;;;;wBAmBa,gBAAgB,gBAAgB,kBACrD,YACA,aACA,QAAQ,SACR,WAAW,sCACT,QAAQ,MAAM;;qBAuCJ,4BAA4B;WAE9B;WACA;WACA;EAHV,YACU,YACA,aACA"}
|
package/dist/credential.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as StandardSchemaV1 } from "./index-CeEtxDmK.mjs";
|
|
2
|
-
import { r as Consumable } from "./construct-interface-
|
|
2
|
+
import { r as Consumable } from "./construct-interface-BLG_BEH5.mjs";
|
|
3
3
|
import { ConstructName, Declaration } from "@geekmidas/manifest";
|
|
4
|
-
import { Service } from "@geekmidas/services";
|
|
4
|
+
import { Service, ServiceRegisterOptions } from "@geekmidas/services";
|
|
5
5
|
//#region src/credential.d.ts
|
|
6
6
|
/** What a credential's schema yields. */
|
|
7
7
|
type Value<TSchema extends StandardSchemaV1> = StandardSchemaV1.InferOutput<TSchema>;
|
|
@@ -47,6 +47,16 @@ export declare class Credential<TName extends string = string, TSchema extends S
|
|
|
47
47
|
private connect;
|
|
48
48
|
private resolve;
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* A credentials key, read and validated against its schema.
|
|
52
|
+
*
|
|
53
|
+
* Shared with every construct that holds a third party's credentials — an
|
|
54
|
+
* `ExternalApi` reads its own the same way — so the shape a stage stores and
|
|
55
|
+
* the error a bad value raises are the same everywhere.
|
|
56
|
+
*
|
|
57
|
+
* @throws {MalformedCredential} when the value is not what the schema says.
|
|
58
|
+
*/
|
|
59
|
+
export declare function readCredentials<TSchema extends StandardSchemaV1>(id: string, key: string, schema: TSchema, envParser: ServiceRegisterOptions['envParser']): Promise<Value<TSchema>>;
|
|
50
60
|
/** A credential was set, and is not what its schema says it should be. */
|
|
51
61
|
export declare class MalformedCredential extends Error {
|
|
52
62
|
readonly id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credential.d.mts","names":[],"sources":["../src/credential.ts"],"mappings":";;;;;;KA6CK,MAAM,gBAAgB,oBAC1B,iBAAiB,YAAY;iBAEb,kBAAkB,gBAAgB;;;;;;;;EAQlD,QAAQ;;;;;;;;;;EAUR;;qBAGY,WACZ,+BACA,gBAAgB,mBAAmB,6BACvB,WAAW,OAAO,MAAM;mBA6BlB;WApBT,IAAI;WACJ,SAAS,QAAQ,aAAa,QAAQ,MAAM;;;;;mBAMpC;;;;;;;;UAST;EAER,YACC,IAAI,cAAc,QACD,SAAS,kBAAkB;EAc7C,WAAW;UAUH;
|
|
1
|
+
{"version":3,"file":"credential.d.mts","names":[],"sources":["../src/credential.ts"],"mappings":";;;;;;KA6CK,MAAM,gBAAgB,oBAC1B,iBAAiB,YAAY;iBAEb,kBAAkB,gBAAgB;;;;;;;;EAQlD,QAAQ;;;;;;;;;;EAUR;;qBAGY,WACZ,+BACA,gBAAgB,mBAAmB,6BACvB,WAAW,OAAO,MAAM;mBA6BlB;WApBT,IAAI;WACJ,SAAS,QAAQ,aAAa,QAAQ,MAAM;;;;;mBAMpC;;;;;;;;UAST;EAER,YACC,IAAI,cAAc,QACD,SAAS,kBAAkB;EAc7C,WAAW;UAUH;UAQA;;;;;;;;;;;wBAmBa,gBAAgB,gBAAgB,kBACrD,YACA,aACA,QAAQ,SACR,WAAW,sCACT,QAAQ,MAAM;;qBAuCJ,4BAA4B;WAE9B;WACA;WACA;EAHV,YACU,YACA,aACA"}
|
package/dist/credential.mjs
CHANGED
|
@@ -53,7 +53,7 @@ var Credential = class {
|
|
|
53
53
|
this.options = options;
|
|
54
54
|
const canonical = canonicalId(id);
|
|
55
55
|
this.id = canonical;
|
|
56
|
-
this.keys = {
|
|
56
|
+
this.keys = { credentials: provideKey(canonical, "credentials") };
|
|
57
57
|
this.service = {
|
|
58
58
|
serviceName: serviceKey(canonical),
|
|
59
59
|
register: (registerOptions) => this.connect(registerOptions)
|
|
@@ -63,7 +63,7 @@ var Credential = class {
|
|
|
63
63
|
return [{
|
|
64
64
|
kind: "credential",
|
|
65
65
|
id: this.id,
|
|
66
|
-
provides: [this.keys.
|
|
66
|
+
provides: [this.keys.credentials]
|
|
67
67
|
}];
|
|
68
68
|
}
|
|
69
69
|
connect(options) {
|
|
@@ -71,16 +71,28 @@ var Credential = class {
|
|
|
71
71
|
this.resolved ??= this.resolve(options);
|
|
72
72
|
return this.resolved;
|
|
73
73
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
try {
|
|
77
|
-
return await parseSchema(this.options.schema, decode(raw));
|
|
78
|
-
} catch (issues) {
|
|
79
|
-
throw new MalformedCredential(this.id, this.keys.credential, issues);
|
|
80
|
-
}
|
|
74
|
+
resolve(options) {
|
|
75
|
+
return readCredentials(this.id, this.keys.credentials, this.options.schema, options.envParser);
|
|
81
76
|
}
|
|
82
77
|
};
|
|
83
78
|
/**
|
|
79
|
+
* A credentials key, read and validated against its schema.
|
|
80
|
+
*
|
|
81
|
+
* Shared with every construct that holds a third party's credentials — an
|
|
82
|
+
* `ExternalApi` reads its own the same way — so the shape a stage stores and
|
|
83
|
+
* the error a bad value raises are the same everywhere.
|
|
84
|
+
*
|
|
85
|
+
* @throws {MalformedCredential} when the value is not what the schema says.
|
|
86
|
+
*/
|
|
87
|
+
async function readCredentials(id, key, schema, envParser) {
|
|
88
|
+
const { raw } = envParser.create((get) => ({ raw: get(key).string() })).parse();
|
|
89
|
+
try {
|
|
90
|
+
return await parseSchema(schema, decode(raw));
|
|
91
|
+
} catch (issues) {
|
|
92
|
+
throw new MalformedCredential(id, key, issues);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
84
96
|
* The raw environment value as the thing the schema should see.
|
|
85
97
|
*
|
|
86
98
|
* JSON when it is JSON, and the string itself when it is not — a credential
|
|
@@ -123,6 +135,6 @@ function describe(issues) {
|
|
|
123
135
|
}).join("; ");
|
|
124
136
|
}
|
|
125
137
|
//#endregion
|
|
126
|
-
export { Credential, MalformedCredential };
|
|
138
|
+
export { Credential, MalformedCredential, readCredentials };
|
|
127
139
|
|
|
128
140
|
//# sourceMappingURL=credential.mjs.map
|
package/dist/credential.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credential.mjs","names":[],"sources":["../src/credential.ts"],"sourcesContent":["/**\n * `Credential` — a third-party credential with a shape.\n *\n * The answer to the design's first open question, \"where does `Secret` sit?\".\n * It sits beside a secret rather than replacing it, because the two differ by\n * *lifecycle* and that is the only difference worth two kinds for: a secret is\n * generated and rotated by the platform and is one opaque string, while a\n * credential is issued by someone else, arrives with several fields, and is\n * worth validating on the way in.\n *\n * ```ts\n * export const stripe = new Credential('Stripe', {\n * schema: z.object({ secretKey: z.string(), webhookSecret: z.string() }),\n * });\n *\n * // in a handler — no await, already parsed and validated\n * services.stripe.secretKey\n * ```\n *\n * **Nothing about it is async at the call site**, which is the part that looks\n * like it should be hard and is not. `Service.register()` may return a promise\n * and `ServiceDiscovery` awaits every one before a handler runs, so fetching a\n * value and validating it — including when a StandardSchema's `~standard.validate`\n * returns a promise of its own — both happen inside that existing seam.\n *\n * **One key holding JSON, not one key per field.** That is the shape a secret\n * manager stores, and it is the only shape that works with an arbitrary\n * StandardSchema: the spec has no introspection API, so enumerating a schema's\n * fields means reaching into one library's internals (`.shape`) and being wrong\n * for every other.\n */\n\nimport {\n\ttype ConstructName,\n\tcanonicalId,\n\ttype Declaration,\n\tprovideKey,\n\tserviceKey,\n} from '@geekmidas/manifest';\nimport { parseSchema } from '@geekmidas/schema/parser';\nimport type { Service, ServiceRegisterOptions } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Consumable } from './construct-interface';\n\n/** What a credential's schema yields. */\ntype Value<TSchema extends StandardSchemaV1> =\n\tStandardSchemaV1.InferOutput<TSchema>;\n\nexport interface CredentialOptions<TSchema extends StandardSchemaV1> {\n\t/**\n\t * What the credential must look like.\n\t *\n\t * Validated at registration, so a malformed or half-set credential fails\n\t * when the process starts rather than on the first request that needs the\n\t * one field somebody forgot.\n\t */\n\tschema: TSchema;\n\t/**\n\t * Re-resolve on every registration instead of once per process.\n\t *\n\t * Off by default: a credential is resolved once and reused, because the\n\t * alternative is a fetch on every request. The cost of that default is that\n\t * a rotated credential needs a restart, which is the right trade for a value\n\t * that changes a few times a year — and this is the escape hatch for when it\n\t * is not.\n\t */\n\trefresh?: boolean;\n}\n\nexport class Credential<\n\tTName extends string = string,\n\tTSchema extends StandardSchemaV1 = StandardSchemaV1,\n> implements Consumable<TName, Value<TSchema>>\n{\n\t// `Consumable` rather than `Construct`, and not by preference: `Construct`\n\t// types its service as `[TClient] extends [never] ? never : Service<…>` so\n\t// that a `Cron` cannot be depended on, and TypeScript cannot evaluate that\n\t// conditional while `TClient` is still a type parameter. Every construct\n\t// with a concrete client satisfies `Construct`; the first one whose client\n\t// is generic cannot. `Consumable` is the face `.dependsOn()` requires and\n\t// carries no conditional, so it is the honest annotation here.\n\treadonly id: TName;\n\treadonly service: Service<Uncapitalize<TName>, Value<TSchema>>;\n\n\t/**\n\t * Declared once and read by both `declare()` and `connect()`, so the key the\n\t * target publishes and the key the client reads cannot drift.\n\t */\n\tprivate readonly keys: {
|
|
1
|
+
{"version":3,"file":"credential.mjs","names":[],"sources":["../src/credential.ts"],"sourcesContent":["/**\n * `Credential` — a third-party credential with a shape.\n *\n * The answer to the design's first open question, \"where does `Secret` sit?\".\n * It sits beside a secret rather than replacing it, because the two differ by\n * *lifecycle* and that is the only difference worth two kinds for: a secret is\n * generated and rotated by the platform and is one opaque string, while a\n * credential is issued by someone else, arrives with several fields, and is\n * worth validating on the way in.\n *\n * ```ts\n * export const stripe = new Credential('Stripe', {\n * schema: z.object({ secretKey: z.string(), webhookSecret: z.string() }),\n * });\n *\n * // in a handler — no await, already parsed and validated\n * services.stripe.secretKey\n * ```\n *\n * **Nothing about it is async at the call site**, which is the part that looks\n * like it should be hard and is not. `Service.register()` may return a promise\n * and `ServiceDiscovery` awaits every one before a handler runs, so fetching a\n * value and validating it — including when a StandardSchema's `~standard.validate`\n * returns a promise of its own — both happen inside that existing seam.\n *\n * **One key holding JSON, not one key per field.** That is the shape a secret\n * manager stores, and it is the only shape that works with an arbitrary\n * StandardSchema: the spec has no introspection API, so enumerating a schema's\n * fields means reaching into one library's internals (`.shape`) and being wrong\n * for every other.\n */\n\nimport {\n\ttype ConstructName,\n\tcanonicalId,\n\ttype Declaration,\n\tprovideKey,\n\tserviceKey,\n} from '@geekmidas/manifest';\nimport { parseSchema } from '@geekmidas/schema/parser';\nimport type { Service, ServiceRegisterOptions } from '@geekmidas/services';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Consumable } from './construct-interface';\n\n/** What a credential's schema yields. */\ntype Value<TSchema extends StandardSchemaV1> =\n\tStandardSchemaV1.InferOutput<TSchema>;\n\nexport interface CredentialOptions<TSchema extends StandardSchemaV1> {\n\t/**\n\t * What the credential must look like.\n\t *\n\t * Validated at registration, so a malformed or half-set credential fails\n\t * when the process starts rather than on the first request that needs the\n\t * one field somebody forgot.\n\t */\n\tschema: TSchema;\n\t/**\n\t * Re-resolve on every registration instead of once per process.\n\t *\n\t * Off by default: a credential is resolved once and reused, because the\n\t * alternative is a fetch on every request. The cost of that default is that\n\t * a rotated credential needs a restart, which is the right trade for a value\n\t * that changes a few times a year — and this is the escape hatch for when it\n\t * is not.\n\t */\n\trefresh?: boolean;\n}\n\nexport class Credential<\n\tTName extends string = string,\n\tTSchema extends StandardSchemaV1 = StandardSchemaV1,\n> implements Consumable<TName, Value<TSchema>>\n{\n\t// `Consumable` rather than `Construct`, and not by preference: `Construct`\n\t// types its service as `[TClient] extends [never] ? never : Service<…>` so\n\t// that a `Cron` cannot be depended on, and TypeScript cannot evaluate that\n\t// conditional while `TClient` is still a type parameter. Every construct\n\t// with a concrete client satisfies `Construct`; the first one whose client\n\t// is generic cannot. `Consumable` is the face `.dependsOn()` requires and\n\t// carries no conditional, so it is the honest annotation here.\n\treadonly id: TName;\n\treadonly service: Service<Uncapitalize<TName>, Value<TSchema>>;\n\n\t/**\n\t * Declared once and read by both `declare()` and `connect()`, so the key the\n\t * target publishes and the key the client reads cannot drift.\n\t */\n\tprivate readonly keys: { credentials: string };\n\n\t/**\n\t * The resolved value, held as the *promise* rather than the value.\n\t *\n\t * Caching the promise is what makes two concurrent registrations share one\n\t * resolution: caching the value would let both start before either finished,\n\t * which is a duplicated fetch every cold start rather than never.\n\t */\n\tprivate resolved?: Promise<Value<TSchema>>;\n\n\tconstructor(\n\t\tid: ConstructName<TName>,\n\t\tprivate readonly options: CredentialOptions<TSchema>,\n\t) {\n\t\tconst canonical = canonicalId(id as string);\n\n\t\tthis.id = canonical as TName;\n\t\tthis.keys = { credentials: provideKey(canonical, 'credentials') };\n\n\t\t// A field, not a getter: consumers cache services by object identity.\n\t\tthis.service = {\n\t\t\tserviceName: serviceKey(canonical) as Uncapitalize<TName>,\n\t\t\tregister: (registerOptions) => this.connect(registerOptions),\n\t\t};\n\t}\n\n\tdeclare(): Declaration[] {\n\t\treturn [\n\t\t\t{\n\t\t\t\tkind: 'credential',\n\t\t\t\tid: this.id,\n\t\t\t\tprovides: [this.keys.credentials],\n\t\t\t},\n\t\t];\n\t}\n\n\tprivate connect(options: ServiceRegisterOptions): Promise<Value<TSchema>> {\n\t\tif (this.options.refresh) return this.resolve(options);\n\n\t\tthis.resolved ??= this.resolve(options);\n\n\t\treturn this.resolved;\n\t}\n\n\tprivate resolve(options: ServiceRegisterOptions): Promise<Value<TSchema>> {\n\t\treturn readCredentials(\n\t\t\tthis.id,\n\t\t\tthis.keys.credentials,\n\t\t\tthis.options.schema,\n\t\t\toptions.envParser,\n\t\t);\n\t}\n}\n\n/**\n * A credentials key, read and validated against its schema.\n *\n * Shared with every construct that holds a third party's credentials — an\n * `ExternalApi` reads its own the same way — so the shape a stage stores and\n * the error a bad value raises are the same everywhere.\n *\n * @throws {MalformedCredential} when the value is not what the schema says.\n */\nexport async function readCredentials<TSchema extends StandardSchemaV1>(\n\tid: string,\n\tkey: string,\n\tschema: TSchema,\n\tenvParser: ServiceRegisterOptions['envParser'],\n): Promise<Value<TSchema>> {\n\tconst { raw } = envParser\n\t\t.create((get) => ({ raw: get(key).string() }))\n\t\t.parse();\n\n\ttry {\n\t\treturn await parseSchema(schema, decode(raw));\n\t} catch (issues) {\n\t\tthrow new MalformedCredential(id, key, issues);\n\t}\n}\n\n/**\n * The raw environment value as the thing the schema should see.\n *\n * JSON when it is JSON, and the string itself when it is not — a credential\n * with a single opaque field is ordinary, and requiring `\"…\"` around it would\n * be ceremony that every operator setting one by hand would get wrong once.\n */\nfunction decode(raw: string): unknown {\n\tconst value = raw.startsWith(JSON_SCHEME)\n\t\t? raw.slice(JSON_SCHEME.length)\n\t\t: raw;\n\n\ttry {\n\t\treturn JSON.parse(value);\n\t} catch {\n\t\treturn value;\n\t}\n}\n\n/**\n * The explicit form, for the case a credential legitimately *is* a JSON string\n * and must not be parsed into an object. Rare, and cheaper to support than to\n * explain.\n */\nconst JSON_SCHEME = 'json:';\n\n/** A credential was set, and is not what its schema says it should be. */\nexport class MalformedCredential extends Error {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly key: string,\n\t\treadonly issues: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`${key} is not a valid ${id} credential. ` +\n\t\t\t\t`It is validated where it is read, so this is the value that is set ` +\n\t\t\t\t`rather than the code that uses it: ${describe(issues)}`,\n\t\t);\n\t\tthis.name = 'MalformedCredential';\n\t}\n}\n\n/** StandardSchema issues as one line. */\nfunction describe(issues: unknown): string {\n\tif (!Array.isArray(issues)) return String(issues);\n\n\treturn issues\n\t\t.map((issue: StandardSchemaV1.Issue) => {\n\t\t\tconst path = issue.path\n\t\t\t\t?.map((segment) =>\n\t\t\t\t\ttypeof segment === 'object' ? String(segment.key) : String(segment),\n\t\t\t\t)\n\t\t\t\t.join('.');\n\n\t\t\treturn path ? `${path}: ${issue.message}` : issue.message;\n\t\t})\n\t\t.join('; ');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqEA,IAAa,aAAb,MAIA;CA4BmB;CApBlB;CACA;;;;;CAMA;;;;;;;;CASA;CAEA,YACC,IACA,SACC;EADgB,KAAA,UAAA;EAEjB,MAAM,YAAY,YAAY,EAAY;EAE1C,KAAK,KAAK;EACV,KAAK,OAAO,EAAE,aAAa,WAAW,WAAW,aAAa,EAAE;EAGhE,KAAK,UAAU;GACd,aAAa,WAAW,SAAS;GACjC,WAAW,oBAAoB,KAAK,QAAQ,eAAe;EAC5D;CACD;CAEA,UAAyB;EACxB,OAAO,CACN;GACC,MAAM;GACN,IAAI,KAAK;GACT,UAAU,CAAC,KAAK,KAAK,WAAW;EACjC,CACD;CACD;CAEA,QAAgB,SAA0D;EACzE,IAAI,KAAK,QAAQ,SAAS,OAAO,KAAK,QAAQ,OAAO;EAErD,KAAK,aAAa,KAAK,QAAQ,OAAO;EAEtC,OAAO,KAAK;CACb;CAEA,QAAgB,SAA0D;EACzE,OAAO,gBACN,KAAK,IACL,KAAK,KAAK,aACV,KAAK,QAAQ,QACb,QAAQ,SACT;CACD;AACD;;;;;;;;;;AAWA,eAAsB,gBACrB,IACA,KACA,QACA,WAC0B;CAC1B,MAAM,EAAE,QAAQ,UACd,QAAQ,SAAS,EAAE,KAAK,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAC7C,MAAM;CAER,IAAI;EACH,OAAO,MAAM,YAAY,QAAQ,OAAO,GAAG,CAAC;CAC7C,SAAS,QAAQ;EAChB,MAAM,IAAI,oBAAoB,IAAI,KAAK,MAAM;CAC9C;AACD;;;;;;;;AASA,SAAS,OAAO,KAAsB;CACrC,MAAM,QAAQ,IAAI,WAAW,WAAW,IACrC,IAAI,MAAM,YAAY,MAAM,IAC5B;CAEH,IAAI;EACH,OAAO,KAAK,MAAM,KAAK;CACxB,QAAQ;EACP,OAAO;CACR;AACD;;;;;;AAOA,MAAM,cAAc;;AAGpB,IAAa,sBAAb,cAAyC,MAAM;CAEpC;CACA;CACA;CAHV,YACC,IACA,KACA,QACC;EACD,MACC,GAAG,IAAI,kBAAkB,GAAG,qHAEW,SAAS,MAAM,GACvD;EARS,KAAA,KAAA;EACA,KAAA,MAAA;EACA,KAAA,SAAA;EAOT,KAAK,OAAO;CACb;AACD;;AAGA,SAAS,SAAS,QAAyB;CAC1C,IAAI,CAAC,MAAM,QAAQ,MAAM,GAAG,OAAO,OAAO,MAAM;CAEhD,OAAO,OACL,KAAK,UAAkC;EACvC,MAAM,OAAO,MAAM,MAChB,KAAK,YACN,OAAO,YAAY,WAAW,OAAO,QAAQ,GAAG,IAAI,OAAO,OAAO,CACnE,CAAC,CACA,KAAK,GAAG;EAEV,OAAO,OAAO,GAAG,KAAK,IAAI,MAAM,YAAY,MAAM;CACnD,CAAC,CAAC,CACD,KAAK,IAAI;AACZ"}
|
package/dist/crons/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as ScheduleExpression, n as CronExpression, r as RateExpression, t as Cron } from "../Cron-
|
|
2
|
-
import { t as CronBuilder } from "../CronBuilder-
|
|
1
|
+
import { i as ScheduleExpression, n as CronExpression, r as RateExpression, t as Cron } from "../Cron-Brs_n_vQ.cjs";
|
|
2
|
+
import { t as CronBuilder } from "../CronBuilder-4WnWKR40.cjs";
|
|
3
3
|
//#region src/crons/schedule.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* A schedule a cron runner can take, as standard five-field cron.
|
package/dist/crons/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as ScheduleExpression, n as CronExpression, r as RateExpression, t as Cron } from "../Cron-
|
|
2
|
-
import { t as CronBuilder } from "../CronBuilder-
|
|
1
|
+
import { i as ScheduleExpression, n as CronExpression, r as RateExpression, t as Cron } from "../Cron-C18-2Lgb.mjs";
|
|
2
|
+
import { t as CronBuilder } from "../CronBuilder-CGv51EoE.mjs";
|
|
3
3
|
//#region src/crons/schedule.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* A schedule a cron runner can take, as standard five-field cron.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as KyselyDatabaseOptions, r as ReadOnlyDatabase, t as KyselyDatabase } from "../kysely-
|
|
1
|
+
import { n as KyselyDatabaseOptions, r as ReadOnlyDatabase, t as KyselyDatabase } from "../kysely-Dy8nNgvk.cjs";
|
|
2
2
|
export { KyselyDatabase, KyselyDatabaseOptions, ReadOnlyDatabase };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as KyselyDatabaseOptions, r as ReadOnlyDatabase, t as KyselyDatabase } from "../kysely-
|
|
1
|
+
import { n as KyselyDatabaseOptions, r as ReadOnlyDatabase, t as KyselyDatabase } from "../kysely-QLoPapbM.mjs";
|
|
2
2
|
export { KyselyDatabase, KyselyDatabaseOptions, ReadOnlyDatabase };
|
package/dist/email.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as Construct } from "./construct-interface-
|
|
1
|
+
import { n as Construct } from "./construct-interface-DcNaRKoC.cjs";
|
|
2
2
|
import { Service } from "@geekmidas/services";
|
|
3
3
|
import { ConstructName, Declaration } from "@geekmidas/manifest";
|
|
4
4
|
import { EmailClient, TemplateRecord } from "@geekmidas/emailkit";
|
package/dist/email.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as Construct } from "./construct-interface-
|
|
1
|
+
import { n as Construct } from "./construct-interface-BLG_BEH5.mjs";
|
|
2
2
|
import { ConstructName, Declaration } from "@geekmidas/manifest";
|
|
3
3
|
import { EmailClient, TemplateRecord } from "@geekmidas/emailkit";
|
|
4
4
|
import { Service } from "@geekmidas/services";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as StandardSchemaV1 } from "../index-CeEtxDmK.cjs";
|
|
2
2
|
import { t as Construct } from "../Construct-DTqYvkPG.cjs";
|
|
3
|
-
import { A as getSecurityScheme, C as Authorizer, D as OAuthFlows, E as OAuthFlow, O as SecurityScheme, S as MappedAudit, T as BuiltInSecuritySchemeId, _ as RlsBypass, a as EndpointContext, b as RlsContextExtractor, c as EndpointSchemas, d as ResponseBuilder, g as RLS_BYPASS, h as SessionAuth, i as Endpoint, j as isBuiltInSecurityScheme, k as createAuthorizer, l as EndpointSurface, m as NoAuthenticator, n as ConvertRouteParams, o as EndpointHandler, r as CookieFn, s as EndpointOutput, u as HeaderFn, v as RlsConfig, w as BUILT_IN_SECURITY_SCHEMES, x as ActorExtractor, y as RlsContext } from "../Endpoint-
|
|
4
|
-
import { n as EndpointBuilder, t as EndpointFactory } from "../EndpointFactory-
|
|
3
|
+
import { A as getSecurityScheme, C as Authorizer, D as OAuthFlows, E as OAuthFlow, O as SecurityScheme, S as MappedAudit, T as BuiltInSecuritySchemeId, _ as RlsBypass, a as EndpointContext, b as RlsContextExtractor, c as EndpointSchemas, d as ResponseBuilder, g as RLS_BYPASS, h as SessionAuth, i as Endpoint, j as isBuiltInSecurityScheme, k as createAuthorizer, l as EndpointSurface, m as NoAuthenticator, n as ConvertRouteParams, o as EndpointHandler, r as CookieFn, s as EndpointOutput, u as HeaderFn, v as RlsConfig, w as BUILT_IN_SECURITY_SCHEMES, x as ActorExtractor, y as RlsContext } from "../Endpoint-BkhPHCuX.cjs";
|
|
4
|
+
import { n as EndpointBuilder, t as EndpointFactory } from "../EndpointFactory-n96CT_Ys.cjs";
|
|
5
5
|
import { EnvironmentParser } from "@geekmidas/envkit";
|
|
6
6
|
import { EventPublisher, MappedEvent } from "@geekmidas/events";
|
|
7
7
|
import { Logger } from "@geekmidas/logger";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as StandardSchemaV1 } from "../index-CeEtxDmK.mjs";
|
|
2
2
|
import { t as Construct } from "../Construct-pVadmURD.mjs";
|
|
3
|
-
import { A as getSecurityScheme, C as Authorizer, D as OAuthFlows, E as OAuthFlow, O as SecurityScheme, S as MappedAudit, T as BuiltInSecuritySchemeId, _ as RlsBypass, a as EndpointContext, b as RlsContextExtractor, c as EndpointSchemas, d as ResponseBuilder, g as RLS_BYPASS, h as SessionAuth, i as Endpoint, j as isBuiltInSecurityScheme, k as createAuthorizer, l as EndpointSurface, m as NoAuthenticator, n as ConvertRouteParams, o as EndpointHandler, r as CookieFn, s as EndpointOutput, u as HeaderFn, v as RlsConfig, w as BUILT_IN_SECURITY_SCHEMES, x as ActorExtractor, y as RlsContext } from "../Endpoint-
|
|
4
|
-
import { n as EndpointBuilder, t as EndpointFactory } from "../EndpointFactory-
|
|
3
|
+
import { A as getSecurityScheme, C as Authorizer, D as OAuthFlows, E as OAuthFlow, O as SecurityScheme, S as MappedAudit, T as BuiltInSecuritySchemeId, _ as RlsBypass, a as EndpointContext, b as RlsContextExtractor, c as EndpointSchemas, d as ResponseBuilder, g as RLS_BYPASS, h as SessionAuth, i as Endpoint, j as isBuiltInSecurityScheme, k as createAuthorizer, l as EndpointSurface, m as NoAuthenticator, n as ConvertRouteParams, o as EndpointHandler, r as CookieFn, s as EndpointOutput, u as HeaderFn, v as RlsConfig, w as BUILT_IN_SECURITY_SCHEMES, x as ActorExtractor, y as RlsContext } from "../Endpoint-DkiD0GJs.mjs";
|
|
4
|
+
import { n as EndpointBuilder, t as EndpointFactory } from "../EndpointFactory-WJzZfkTW.mjs";
|
|
5
5
|
import { EnvironmentParser } from "@geekmidas/envkit";
|
|
6
6
|
import { EventPublisher, MappedEvent } from "@geekmidas/events";
|
|
7
7
|
import { Service, ServiceDiscovery } from "@geekmidas/services";
|