@geekmidas/manifest 10.0.0-alpha.84 → 10.0.0-alpha.86
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/index.cjs +23 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +22 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +23 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1062,6 +1062,28 @@ var NoUrlForStage = class extends Error {
|
|
|
1062
1062
|
}
|
|
1063
1063
|
};
|
|
1064
1064
|
//#endregion
|
|
1065
|
+
//#region src/headers.ts
|
|
1066
|
+
/**
|
|
1067
|
+
* Headers gkm reserves for its own services' calls to each other.
|
|
1068
|
+
*
|
|
1069
|
+
* Shared by `@geekmidas/constructs`, which sends and reads them, and
|
|
1070
|
+
* `@geekmidas/cli`, whose edges strip them from every request that arrives
|
|
1071
|
+
* from outside — so the two cannot name them differently.
|
|
1072
|
+
*/
|
|
1073
|
+
/**
|
|
1074
|
+
* The address of the client a service-to-service call is made on behalf of.
|
|
1075
|
+
*
|
|
1076
|
+
* An API asking its auth server for a session sends the client's address in
|
|
1077
|
+
* this rather than `X-Forwarded-For`: a forwarding header marks a request as
|
|
1078
|
+
* outside traffic, which would start the auth server's span in a new trace,
|
|
1079
|
+
* and the address is still needed — Better Auth rate-limits per client.
|
|
1080
|
+
*
|
|
1081
|
+
* Reserved: the stack's edge (Caddy, Traefik, the `gkm dev` edge) removes it
|
|
1082
|
+
* from incoming requests, and the auth server ignores it on any request that
|
|
1083
|
+
* is not an internal caller's, so it cannot be spoofed from outside.
|
|
1084
|
+
*/
|
|
1085
|
+
const CLIENT_IP_HEADER = "x-gkm-client-ip";
|
|
1086
|
+
//#endregion
|
|
1065
1087
|
//#region src/migrations.ts
|
|
1066
1088
|
/** Where every construct's folder lives, from the project root. */
|
|
1067
1089
|
const MIGRATIONS_ROOT = "db";
|
|
@@ -1170,6 +1192,7 @@ function isWebOrigin(origin) {
|
|
|
1170
1192
|
return origin.startsWith("http://") || origin.startsWith("https://");
|
|
1171
1193
|
}
|
|
1172
1194
|
//#endregion
|
|
1195
|
+
exports.CLIENT_IP_HEADER = CLIENT_IP_HEADER;
|
|
1173
1196
|
exports.DATABASE_FOLDERS = DATABASE_FOLDERS;
|
|
1174
1197
|
exports.DEFAULT_POSTGRES_VERSION = DEFAULT_POSTGRES_VERSION;
|
|
1175
1198
|
exports.DEFAULT_STAGE_URL = DEFAULT_STAGE_URL;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["snakecase"],"sources":["../src/declaration.ts","../src/errors.ts","../../../node_modules/.pnpm/lodash.snakecase@4.1.1/node_modules/lodash.snakecase/index.js","../src/naming.ts","../src/derive.ts","../src/encryption.ts","../src/external.ts","../src/migrations.ts","../src/mobile.ts"],"sourcesContent":["/**\n * The construct manifest — the contract between what an application declares\n * and what a target adapter provisions.\n *\n * Kinds are added here as each one lands, not up front: a declaration for a\n * construct nobody has built yet is a guess that the implementation will\n * contradict. See `docs/design/constructs-paradigm.md`.\n */\n\n/**\n * A construct's canonical id — PascalCase, unique within the manifest.\n *\n * Inputs canonicalise, so `uploads`, `Uploads`, `user_uploads`, and\n * `user-uploads` are the *same* id rather than four that collide. Everything\n * else derives from it: the service key is its `Uncapitalize`, the env prefix\n * its SCREAMING_SNAKE form, the cloud name its kebab form scoped by stage and\n * app.\n */\nexport type ConstructId = string;\n\ntype Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';\n\n/**\n * Constrains a construct name at the point it is written.\n *\n * Resolves to the name itself when valid, and otherwise to a string explaining\n * why — so the compiler reports *\"not assignable to type 'a construct name\n * cannot start with a digit'\"* rather than the unhelpful `never`.\n *\n * Only the cases a template-literal type can see are caught here; `canonicalId`\n * enforces the rest at runtime, which is also what covers JavaScript callers.\n *\n * @example new ObjectStorage('Uploads') // ok\n * @example new ObjectStorage('2fa') // a construct name cannot start with a digit\n */\nexport type ConstructName<S extends string> = S extends ''\n\t? 'a construct name cannot be empty'\n\t: S extends `${Digit}${string}`\n\t\t? 'a construct name cannot start with a digit'\n\t\t: S;\n\n/** Shared by every declaration. */\nexport interface Node {\n\tid: ConstructId;\n\t/**\n\t * Env keys this construct resolves onto anything that depends on it.\n\t * Names only — the values are composed by the adapter from the provisioned\n\t * resource's own attributes.\n\t */\n\tprovides?: readonly string[];\n\t/**\n\t * Env keys this construct needs. Derivable from `dependencies`, so it is an\n\t * assertion rather than an input: the adapter composes env from the edges and\n\t * checks the result against this, which catches app/infra drift at synth.\n\t */\n\trequires?: readonly string[];\n}\n\n/**\n * A dependency edge. Records only *what* is depended on — never permissions.\n * From one edge the framework derives env and the runtime binding; a target\n * adapter separately derives cloud access.\n */\nexport interface Dependency<TTarget extends ConstructId = ConstructId> {\n\t/**\n\t * The {@link ConstructId} of the consumed construct. Left open here because a\n\t * declaration is written before the manifest that contains it; once assembled,\n\t * `IdsOf` narrows it and the build's reference-integrity check enforces it.\n\t */\n\ttarget: TTarget;\n\tkind: DeclarationKind;\n}\n\n/** Anything with a handler. */\nexport interface Fn extends Node {\n\thandler: string;\n\tdependencies: readonly Dependency[];\n}\n\n// ---------------------------------------------------------------------------\n// Kinds\n// ---------------------------------------------------------------------------\n\n/** Blob storage. `--target=aws` provisions a bucket. */\nexport interface ObjectsDeclaration extends Node {\n\tkind: 'objects';\n\tversioned?: boolean;\n}\n\n/**\n * A domain that serves a bucket's objects.\n *\n * Its own construct rather than a flag on the bucket, because three things it\n * has to express are not properties of a bucket: a surface can front several\n * origins, a bucket can have several surfaces over it, and issuing a\n * certificate and writing a DNS record is a domain lifecycle that has no\n * business living inside an `objects` provisioner. It shares its infrastructure\n * with a static site rather than with storage — a site is the same\n * distribution over a build output instead of over live contents.\n *\n * It derives from the bucket by `of`, which costs the one thing the flag gave\n * for free: the bucket alone no longer says whether it is served, and finding\n * out means finding whoever points at it. That is answered the way every other\n * derivation is — the reference check at manifest build, so an unresolvable\n * origin is a build failure and `gkm` can name, for any bucket, the surfaces\n * over it.\n *\n * Private by default. `open` is an exception list, because a bucket where\n * forgetting a flag publishes user uploads is the wrong default — and paths\n * rather than per-object flags, because a path pattern is what the\n * infrastructure actually enforces and a per-object ACL is a thing nobody\n * audits.\n *\n * \"Open\" never means the bucket is world-readable. It means the server serves\n * that path without a signature; the bucket is private in both cases.\n */\nexport interface FileServerDeclaration extends Node {\n\tkind: 'file-server';\n\t/** The bucket whose objects it serves. */\n\tof: ConstructId;\n\t/**\n\t * Paths served without a signature — everything else requires one.\n\t *\n\t * Globs, matched most-literally by the infrastructure: a CDN keys its\n\t * behaviours off path patterns, and a bucket policy names prefixes.\n\t */\n\topen?: readonly string[];\n}\n\n/**\n * Outbound email.\n *\n * Provides one `smtp://` URL and nothing else, because email is delivered over\n * SMTP whatever the provider — Mailpit locally, SES through its SMTP interface,\n * Resend and Postmark through theirs. There is no `provider` field here for the\n * same reason there is no `ses://` scheme: which service delivers the mail\n * differs between dev and prod, so by this design's own test it is stage-varying\n * config rather than a structural fact about the app.\n *\n * What *is* structural is only that the app sends mail at all. The sending\n * domain is not: it is `myapp.test` locally and `example.com` deployed, so it\n * fails the same test the provider does and resolves at deploy alongside every\n * other address.\n */\nexport interface EmailDeclaration extends Node {\n\tkind: 'email';\n}\n\n/**\n * A logical database, its schema, and the roles that reach it.\n *\n * Provides one key — the *runtime* role's URL. The owner URL exists but is\n * deliberately absent from `provides`: it is wired by the adapter straight into\n * the migrator and seeder this construct declares, so no edge in any manifest\n * can name it and nothing else can be granted it by mistake.\n */\n/**\n * The Postgres major versions this toolbox provisions.\n *\n * A union rather than a string, because the two targets that read it are not\n * equally forgiving: locally it becomes a container tag, where a typo yields a\n * confusing pull failure, and on AWS it becomes an engine version, where a\n * wrong value fails partway through a deploy. Both are better as a compile\n * error.\n *\n * The union is what this toolbox knows how to name, not a promise that every\n * target offers every one of them. A deployed stage is limited by the engine\n * catalogue in its region, so check before pinning an unusual version:\n *\n * ```\n * aws rds describe-db-engine-versions --engine postgres \\\n * --query 'DBEngineVersions[].EngineVersion' --output text\n * ```\n *\n * RDS offered 11 through 18 in `eu-west-1` when this was written. 11 and 12 are\n * left out because they are past upstream end-of-life: still provisionable, but\n * not something to make easy to reach for.\n */\nexport type PostgresVersion = 13 | 14 | 15 | 16 | 17 | 18;\n\n/**\n * The version used when a database names none.\n *\n * The point is not which number this is but that there is only one of them.\n * Local ran 18 while Aurora provisioned its own default of 17.7, and nothing in\n * any declaration recorded the difference — a stage could behave differently\n * from a developer's machine for a reason neither could see. Both now read\n * this.\n */\nexport const DEFAULT_POSTGRES_VERSION: PostgresVersion = 18;\n\nexport interface DatabaseDeclaration extends Node {\n\tkind: 'database';\n\tengine?: 'postgres';\n\t/**\n\t * The engine's major version, read by every target that provisions one.\n\t *\n\t * Declared rather than configured per target, because a version set in a\n\t * compose file and a version set in a deploy config are two statements of\n\t * one fact — and they had already drifted apart, silently, by a major.\n\t *\n\t * Defaults to {@link DEFAULT_POSTGRES_VERSION}.\n\t */\n\tversion?: PostgresVersion;\n\t/**\n\t * The schema, pinned on both roles' `search_path`. Names the role the schema\n\t * plays rather than restating the database's own name, so `app` reads\n\t * correctly beside `auth` and `pgboss`.\n\t */\n\tschema?: string;\n\t/**\n\t * Whether to provision the owner/runtime role split. Off falls back to the\n\t * cluster's master credential in both URLs — a deliberate downgrade, not a\n\t * default. See `roles: false` in the design doc.\n\t */\n\troles?: boolean;\n}\n\n/**\n * A read-only endpoint on an existing database or schema.\n *\n * Provisions no cluster of its own — `of` names the parent it reads from.\n * Read-only is enforced by the role's grants rather than by which endpoint it\n * resolves to, so falling back to the writer where no replica exists stays safe.\n */\nexport interface DatabaseReaderDeclaration extends Node {\n\tkind: 'database-reader';\n\tof: ConstructId;\n}\n\n/**\n * A second schema inside an existing database, with its own role(s) and URL.\n *\n * The mechanism behind tenancy: the parent's role holds no grant on these\n * tables at all. pg-boss is an instance of this rather than a special case.\n */\nexport interface DatabaseSchemaDeclaration extends Node {\n\tkind: 'database-schema';\n\tof: ConstructId;\n\tschema: string;\n}\n\n/**\n * A generated secret — a signing key, a token, anything with no address.\n *\n * It provides a value rather than a URL, which is why it is a node of its own\n * instead of a field on whatever needs it: the thing that generates it, the\n * thing that stores it, and the thing that reads it are three different systems\n * deployed, and one derived string locally.\n */\nexport interface SecretDeclaration extends Node {\n\tkind: 'secret';\n}\n\n/**\n * A third-party credential with a shape.\n *\n * Distinct from {@link SecretDeclaration} by *lifecycle*, which is the only\n * distinction worth having two kinds for. A secret is generated and rotated by\n * the platform — `gkm secrets`, `sst secret set` — and is one opaque string\n * whose name is its key. A credential is issued by someone else, arrives with\n * several fields, and is validated on the way in: a Stripe key pair, an OAuth\n * client, a webhook signing secret.\n *\n * It provides one key holding a JSON object, rather than one key per field.\n * That is what a secret manager actually stores, and it is also the only shape\n * that works with an arbitrary StandardSchema — the spec has no introspection\n * API, so enumerating a schema's fields means reaching into one library's\n * internals and being wrong for every other.\n */\nexport interface CredentialDeclaration extends Node {\n\tkind: 'credential';\n}\n\n/**\n * A key that encrypts what the application stores.\n *\n * It provides one URL, and the scheme picks the cipher the way a queue's\n * connection string picks its broker: a keyring the process holds\n * (`aes256gcm://`) locally and on a server, a KMS key (`kms://`) on AWS. The\n * value is the platform's to generate and the app never names a cipher.\n *\n * A node rather than a field on whatever encrypts, for the reason a secret is:\n * what holds the key, what grants access to it, and what uses it are three\n * systems deployed — and an edge to it is what grants a function the key.\n */\nexport interface EncryptionDeclaration extends Node {\n\tkind: 'encryption';\n}\n\n/**\n * An HTTP API somebody else runs — Polar, Stripe, a payment gateway.\n *\n * Provisions nothing, like {@link OidcDeclaration}: the API already exists. What\n * makes it a node rather than a URL somebody writes into `.env` is that its\n * address changes by stage — the real one deployed, a fake locally and in\n * tests — and switching it is the target's job, not each app's.\n *\n * The fake is not here, and that is deliberate: it lives in `test/fakes/<id>.ts`,\n * which only gkm reads, so nothing in a deployed bundle can reach it. Its\n * credentials are a second key holding JSON, issued per stage the way a\n * {@link CredentialDeclaration}'s are.\n */\nexport interface ExternalApiDeclaration extends Node {\n\tkind: 'external-api';\n\t/**\n\t * Where it answers deployed: one URL for every stage, or one per stage name,\n\t * with `default` for any stage not listed. A local or test stage never reads\n\t * this — it is handed the fake.\n\t */\n\turl: string | Readonly<Record<string, string>>;\n}\n\n/**\n * An identity provider somebody else runs.\n *\n * Provisions nothing — the issuer already exists — so a target's whole job is\n * to hand the process an issuer and an audience, and the verifier discovers the\n * rest at runtime.\n *\n * It is a node rather than a field on whatever authenticates through it because\n * two surfaces can name the same provider, and because *which* population a\n * surface admits is a fact worth reading off the graph: an admin console\n * authenticated by the customer auth server is a finding, and it is only\n * visible if both are declarations.\n */\nexport interface OidcDeclaration extends Node {\n\tkind: 'oidc';\n\t/**\n\t * The issuer, when it does not vary by deployment.\n\t *\n\t * Absent means it arrives in the environment instead — a staging tenant, a\n\t * per-customer directory. The audience is never here: it identifies one\n\t * deployment to the provider.\n\t */\n\tissuer?: string;\n}\n\n/**\n * A key/value cache.\n *\n * Provides one URL. What is *in* that URL is the backend's business — Upstash's\n * REST API, a Redis endpoint, or a table in a database — and the scheme is what\n * picks the client, exactly as it does for object storage.\n *\n * Two ways to declare one, and the difference is a real statement rather than a\n * spelling. `new Cache('Sessions')` says *this app caches*, leaving where to the\n * deployment; `orders.cache('Sessions')` says *this app caches in that\n * database*, which is a fact about the application and belongs in its code. The\n * second is the same strengthening `orders.schema('AuthDb')` is over declaring a\n * second database.\n */\nexport interface CacheDeclaration extends Node {\n\tkind: 'cache';\n\t/**\n\t * The database this cache lives in, when it lives in one.\n\t *\n\t * Present only for a cache derived from a database. It removes a guess the\n\t * backend selection otherwise has to make — \"the declared database\" is\n\t * unambiguous with one and arbitrary with two — and it means the table's\n\t * schema and the role that reaches it come from the parent rather than from\n\t * a second convention.\n\t */\n\tof?: ConstructId;\n\t/**\n\t * The table entries are kept in, resolved against the connection's\n\t * `search_path`. Defaults to `cache`.\n\t */\n\ttable?: string;\n}\n\n/**\n * An HTTP surface and the handlers mounted on it.\n *\n * The first kind that is not a resource in the ordinary sense: it owns an\n * address, and the functions it triggers are *nested inside it* rather than\n * listed beside it, because position carries the trigger — a handler here is\n * reached by its method and path and by nothing else.\n *\n * `authorizers` are names. A bare string is resolved by the target (`iam`), while\n * a {@link ConstructId} names a construct that carries its own implementation,\n * its database dependency, and its session typing.\n */\nexport interface RestApiDeclaration extends Node {\n\tkind: 'rest-api';\n\t/**\n\t * The label it answers on under a stage's domain — `api` for\n\t * `api.myapp.com`, from `deploy.domains` — and under the project locally,\n\t * `api.myapp.localhost`. Absent, its id kebab-cased.\n\t */\n\tsubdomain?: string;\n\t/**\n\t * The app that serves this surface, relative to the workspace root.\n\t *\n\t * Required, and the only thing about its process a surface says: its code\n\t * is found through the workspace's `constructs` glob, and ports are\n\t * assigned in a stable order. Nothing infers it from the id.\n\t */\n\tpath: string;\n\t/** Whether this surface streams into a Telescope. */\n\ttelescope?: true;\n\t/**\n\t * The construct that authenticates this surface.\n\t *\n\t * An edge like any other — so the auth server learns this surface's origin,\n\t * and the two share a cookie domain — but a *named* one, because \"who\n\t * authenticates me\" is a different fact from \"who I happen to call\", and\n\t * only one of them decides what a request is allowed to be.\n\t *\n\t * It is the id rather than the client: what every endpoint consumes is\n\t * `verify(request) → Session | null`, and that is the one thing every\n\t * provider shares. A surface names its authenticator; the target decides\n\t * what verifying means.\n\t */\n\tauth?: ConstructId;\n\t/**\n\t * CORS tunables for this surface.\n\t *\n\t * *Who* may call it is never here — that is derived from the constructs\n\t * declaring an edge to this surface, and arrives as `<ID>_TRUSTED_ORIGINS`.\n\t * A hand-written origin list is the thing this model removes; these are the\n\t * knobs that genuinely cannot be derived from a graph.\n\t *\n\t * Omitted entirely, a surface still gets CORS — with the derived origins and\n\t * sensible defaults. There is nothing to opt into.\n\t */\n\tcors?: {\n\t\t/** Preflight cache lifetime in seconds. Default 86400. */\n\t\tmaxAge?: number;\n\t\t/** Whether the browser may send credentials. Default true. */\n\t\tcredentials?: boolean;\n\t\t/** Extra request headers to allow, beyond content-type and authorization. */\n\t\tallowHeaders?: readonly string[];\n\t\t/** Response headers the browser may read. */\n\t\texposeHeaders?: readonly string[];\n\t};\n\tauthorizers?: readonly string[];\n\t/** The authorizer applied where an endpoint names none. */\n\tdefaultAuthorizer?: string;\n\t/**\n\t * Every route on this surface.\n\t *\n\t * Complete, always — a manifest that says \"the routes are over there, run\n\t * this glob to find them\" is not a manifest, it is a pointer to one. An\n\t * earlier version carried a `routes` glob for an application's own API and\n\t * left this empty, which meant the document *claimed no routes* while five\n\t * existed. Being incomplete is a gap; being wrong is worse.\n\t *\n\t * So a surface takes its endpoints as a list and reads method, path and\n\t * handler off them. That also removes a duplicate: the glob was written once\n\t * in `gkm.config.ts` and again on the construct, two strings that could\n\t * disagree about the same thing.\n\t */\n\tendpoints: readonly RestApiEndpoint[];\n\t/**\n\t * Other surfaces this one calls.\n\t *\n\t * **Not a dependency, and deliberately not spelled like one.** A dependency\n\t * is an injection: `resolveEdges` gives a function exactly the constructs it\n\t * declared and nothing else, which is what makes least privilege fall out of\n\t * the graph instead of out of discipline. A surface-level `dependencies`\n\t * would hand *every route* on this API whatever the surface named — which is\n\t * precisely the over-granting that rule exists to prevent.\n\t *\n\t * What this records is weaker and only flows one way: it puts this API's\n\t * origin on the called surface's trusted-origin list. Nothing links from it,\n\t * nothing is granted by it, and per-route edges stay on the endpoints where\n\t * they belong.\n\t */\n\tcalls?: readonly Dependency[];\n\t/**\n\t * The `Telemetry` node this surface's process emits through, by id — an\n\t * edge, read by `dependenciesOf` like any other.\n\t */\n\ttelemetry?: ConstructId;\n}\n\n/** One glob, or several. Mirrors the CLI's `Routes` without depending on it. */\nexport type Glob = string | readonly string[];\n\n/**\n * How the process serving a declaration is built and run.\n *\n * The half of an application that a graph genuinely cannot derive. *What*\n * exists — a surface, a site, the edges between them — is declared and read\n * back from the manifest. *Where its source lives and which globs find its\n * code* is not derivable from anything: it is a fact about a directory.\n *\n * It lives on the declaration rather than in a config `apps` block because the\n * two were the same list written twice, and the copy in config was the one that\n * could disagree. A site declared `path: 'apps/web'` and an app entry declared\n * `path: 'apps/web'`, and nothing checked them against each other; a surface\n * that config had no entry for simply never deployed.\n *\n * Only the declaration that *is* an app carries one. Two surfaces in one\n * process means one of them has the spec and the other collapses onto it —\n * which is the same rule that decides deploy units, now stated once.\n */\nexport interface AppSpec {\n\t/** Where its source lives, relative to the workspace root. */\n\tpath: string;\n\t/**\n\t * The port it answers on locally.\n\t *\n\t * Optional, and normally omitted: ports are assigned in a stable order so\n\t * that adding a site does not renumber the others.\n\t */\n\tport?: number;\n\ttelescope?: string | boolean | Record<string, unknown>;\n\tstudio?: string | boolean | Record<string, unknown>;\n\topenapi?: boolean | Record<string, unknown>;\n\truntime?: 'node' | 'bun';\n\t/** Env files to load, in order. */\n\tenv?: Glob;\n\t/** Entry module for an app the build does not generate. */\n\tentry?: string;\n\t/** Modules to import when sniffing which env vars a frontend reads. */\n\tconfig?: { client?: string; server?: string };\n}\n\n/**\n * A frontend — a construct like any other, which is what removes the last\n * mechanism that ran in parallel to the graph.\n *\n * Its edges are what make it worth declaring. A site depending on an API is the\n * single fact behind four things that are hand-maintained otherwise: the site's\n * build-time `VITE_API_URL`, the API's CORS origins, the auth server's trusted\n * origins, and which generated client lands in which app. None of those are\n * declared anywhere here, because all four are the *same* edge read from one\n * end or the other.\n *\n * `variant` is the framework, because the framework changes the code you write:\n * it selects how the values are delivered (`VITE_`, `NEXT_PUBLIC_`, a\n * `config.json`), never which values there are.\n */\nexport interface SiteDeclaration extends Node {\n\tkind: 'site';\n\tvariant: 'static' | 'next' | 'tanstack';\n\t/**\n\t * The label it answers on under a stage's domain — `api` for\n\t * `api.myapp.com`, from `deploy.domains` — and under the project locally,\n\t * `api.myapp.localhost`. Absent, its id kebab-cased.\n\t */\n\tsubdomain?: string;\n\t/**\n\t * How it is built and run, `path` included.\n\t *\n\t * Required: a site is always its own app, and says where it lives.\n\t */\n\tapp: AppSpec;\n\t/**\n\t * Whether this is the site the base domain points at.\n\t *\n\t * Structural rather than config: *which* site is primary does not vary by\n\t * stage, even though its hostname does — that is what `app.domain` is for.\n\t *\n\t * Only meaningful when a project has more than one site, and then only when\n\t * none of them is named `web`. The convention still holds first, because it\n\t * is a convention people already rely on.\n\t */\n\troot?: boolean;\n\t/**\n\t * What it calls. On a node rather than on a handler because a site has no\n\t * single entrypoint — the whole app is the consumer.\n\t */\n\tdependencies: readonly Dependency[];\n\t/**\n\t * The `Telemetry` node it emits through, by id. A site is handed none of\n\t * the node's keys: they are a server's, and `PUBLIC.telemetry` is empty, so\n\t * nothing of it can reach a bundle.\n\t */\n\ttelemetry?: ConstructId;\n}\n\n/**\n * A mobile app — Expo — declared like a site, for the same reason: its edges\n * are what make it worth declaring.\n *\n * It differs from a site in one way that matters. A browser is reached at an\n * origin; an app is reached through its URL *scheme*. So what a surface trusts\n * for it is `shop://`, not an address, and what it provides is that scheme —\n * the same on every stage.\n *\n * It ships through its own toolchain (EAS, the stores), so nothing deploys it:\n * it is an app the targets derive for, never one they run.\n */\nexport interface MobileAppDeclaration extends Node {\n\tkind: 'mobile-app';\n\t/** Which toolchain builds it. Expo is the one that ships. */\n\tvariant: 'expo';\n\t/** Where it lives — `path` included. */\n\tapp: AppSpec;\n\t/**\n\t * Its URL scheme: `shop`.\n\t *\n\t * Normally omitted, and then it is the project's name. The same on every\n\t * stage.\n\t */\n\tscheme?: string;\n\t/** What it calls — the surfaces whose URLs it is built with. */\n\tdependencies: readonly Dependency[];\n}\n\n/**\n * A process with no port.\n *\n * The sibling of `RestApiDeclaration`, and the answer to a question the model\n * could not previously state: *what runs this cron?* A cron, a subscriber and a\n * queue consumer all have to run somewhere, and until now the only thing that\n * said where was the directory the file happened to sit in — so a background\n * job was owned by a glob, and a project that was nothing but background jobs\n * had to declare an HTTP surface with no routes on it to be deployable at all.\n *\n * It takes no authorizer. A `RestApi` needs one because an HTTP surface can\n * ship open by omission; nothing calls a worker from outside, so there is no\n * default to get wrong. That difference is the reason these are two constructs\n * rather than one with a flag.\n */\nexport interface WorkerDeclaration extends Node {\n\tkind: 'worker';\n\t/**\n\t * A worker declares no app, because it is not one.\n\t *\n\t * It names the process that runs a cron, a subscriber or a queue consumer.\n\t * On a server target that process is a container of its own, built from the\n\t * app whose directory holds the work — so the worker needs no path to say\n\t * where its code is.\n\t */\n\t/** Surfaces and resources it calls, which is what grants it access. */\n\tdependencies?: readonly Dependency[];\n\t/** The `Telemetry` node its process emits through, by id. */\n\ttelemetry?: ConstructId;\n}\n\n/** One route on a surface. */\nexport interface RestApiEndpoint extends Fn {\n\tmethod: string;\n\tpath: string;\n\tauthorizer?: string;\n}\n\n/**\n * A point-to-point queue and the single consumer that drains it.\n *\n * Provides one key, the producer's connection string. The protocol in it picks\n * the transport — `pgboss://` locally, `sqs://` deployed — so a producer names\n * no broker, exactly as a database consumer names no cloud.\n *\n * The consumer side provides nothing: a worker is reached *through* its queue,\n * so there is no second key and nothing can depend on a handler.\n */\nexport interface QueueDeclaration extends Node {\n\tkind: 'queue';\n\t/** FIFO ordering, where the transport offers it. */\n\tfifo?: boolean;\n\t/**\n\t * The single consumer that drains it.\n\t *\n\t * Nested rather than listed beside the queue, because **position carries the\n\t * trigger**: a handler here is reached by messages arriving on this queue and\n\t * by nothing else, so there is no `trigger` field to keep in step with it.\n\t */\n\tworker: Fn;\n}\n\n/**\n * A topic — pub/sub fan-out, one publisher and any number of subscribers.\n *\n * Like a queue it provides only the producer's string; a subscriber is bound to\n * the topic rather than depending on it, so the binding is an edge the deploy\n * target reads, not an env key. Locally both sides meet on the same pg-boss\n * connection, which is why the subscriber needs no key of its own.\n */\nexport interface TopicDeclaration extends Node {\n\tkind: 'topic';\n\t/** The event type names this topic carries. */\n\tevents: readonly string[];\n\t/**\n\t * The handlers bound to it, each with the events it wants.\n\t *\n\t * Nested for the same reason a queue's worker is: position is the trigger. A\n\t * subscriber is *bound* to a topic rather than depending on it, which is why\n\t * it holds no key of its own and cannot be reached except through the topic.\n\t */\n\tsubscribers: readonly (Fn & { events: readonly string[] })[];\n}\n\n/**\n * A function invoked directly, with no surface in front of it.\n *\n * An `Fn` rather than a `Node`, because a function *is* a handler — there is no\n * resource beside it to declare. It provides its own address, so something else\n * can depend on it and be given a way to call it.\n */\nexport interface FunctionDeclaration extends Fn {\n\tkind: 'function';\n}\n\n/**\n * A function on a schedule.\n *\n * The schedule is the trigger and it is structural: *that* something runs\n * nightly is a fact about the application, while which timezone a stage\n * interprets it in is not.\n */\nexport interface CronDeclaration extends Fn {\n\tkind: 'cron';\n\t/** A rate or cron expression, e.g. `rate(1 day)`. */\n\tschedule: string;\n}\n\n/**\n * Every declaration. A discriminated union, so `kind` gives exhaustiveness *and*\n * per-kind fields — there is no separate enum to keep in step, and no shape\n * carrying fields that belong to a different kind.\n */\n/**\n * What an application emits — traces and logs over OTLP — and never where it\n * goes: the deploy picks the provider and the sample rate, per stage.\n *\n * A node like any other, so each process that uses it is an edge from its\n * surface, worker or site, and the keys it provides reach exactly those\n * processes. The keys are OpenTelemetry's own, not the node's id: an SDK reads\n * `OTEL_EXPORTER_OTLP_ENDPOINT` and nothing else.\n */\nexport interface TelemetryDeclaration extends Node {\n\tkind: 'telemetry';\n\t/** Request paths no span is recorded for — `/health`. A trailing `*` matches a prefix. */\n\tignorePaths?: readonly string[];\n\t/** Resource attributes every span and log carries — `service.namespace`. */\n\tattributes?: Readonly<Record<string, string>>;\n}\n\n/**\n * What a `Telemetry` node provides to each process with an edge to it.\n *\n * `OTEL_SERVICE_NAME` is resolved per process — the app's name — so it is\n * listed here but composed by whichever target hands it over.\n */\nexport const TELEMETRY_KEYS = [\n\t'OTEL_EXPORTER_OTLP_ENDPOINT',\n\t'OTEL_EXPORTER_OTLP_HEADERS',\n\t'OTEL_SERVICE_NAME',\n\t'OTEL_TRACES_SAMPLER',\n\t'OTEL_TRACES_SAMPLER_ARG',\n] as const;\n\nexport type TelemetryKey = (typeof TELEMETRY_KEYS)[number];\n\nexport type Declaration =\n\t| ObjectsDeclaration\n\t| FileServerDeclaration\n\t| EmailDeclaration\n\t| DatabaseDeclaration\n\t| DatabaseReaderDeclaration\n\t| DatabaseSchemaDeclaration\n\t| CacheDeclaration\n\t| SecretDeclaration\n\t| CredentialDeclaration\n\t| EncryptionDeclaration\n\t| RestApiDeclaration\n\t| SiteDeclaration\n\t| MobileAppDeclaration\n\t| WorkerDeclaration\n\t| OidcDeclaration\n\t| ExternalApiDeclaration\n\t| QueueDeclaration\n\t| TopicDeclaration\n\t| FunctionDeclaration\n\t| CronDeclaration\n\t| TelemetryDeclaration;\n\n/** A declaration that provisions nothing of its own and names a parent. */\n/**\n * A declaration that names a parent.\n *\n * A union rather than an `Extract`, because one kind is *optionally* derived: a\n * cache lives in a database when it was declared from one and stands alone\n * otherwise, so `of` is optional on it and an `Extract<…, { of: ConstructId }>`\n * would not select it. {@link isDerived} tests the value rather than the kind\n * for exactly that reason.\n */\nexport type DerivedDeclaration =\n\t| Extract<Declaration, { of: ConstructId }>\n\t| CacheDeclaration;\n\nexport type DerivedKind = DerivedDeclaration['kind'];\n\n/**\n * What each kind may derive from.\n *\n * Small enough to state exhaustively, and stating it makes cycles impossible\n * without a graph walk: readers are terminal, so no chain can return to its\n * start. There is no `writer` — the database *is* the writer, which is what\n * keeps a replica from being reached by accident.\n */\nexport const DERIVES_FROM: Readonly<Record<DerivedKind, readonly string[]>> = {\n\t'database-reader': ['database', 'database-schema'],\n\t'database-schema': ['database'],\n\t// A file server derives from what it serves. Unlike the database pair it\n\t// shares the parent's *contents* rather than its credentials, which is why\n\t// it is a construct of its own and only its node is derived.\n\t'file-server': ['objects'],\n\t// A cache in a database is a table in it, reached by the same role — so it\n\t// derives from either a database or a tenant of one, and a tenant's cache\n\t// lands in the tenant's schema without naming it.\n\tcache: ['database', 'database-schema'],\n};\n\nexport type DeclarationKind = Declaration['kind'];\n\n/**\n * The manifest: every construct keyed by its id.\n *\n * Flat rather than grouped, because `Dependency.target` resolves as\n * `m[target]` — a lookup that stays O(1) and identical whether the edge points\n * at a resource, a surface, or another function.\n *\n * Use it as a **constraint, not an annotation**. `gkm build` emits\n * `as const satisfies ConstructManifest`, which checks the shape while keeping\n * every id, kind, and provided key a literal — annotating with this type\n * instead would widen them all to `string` and consumers could no longer select\n * anything:\n *\n * ```ts\n * export const constructs = {\n * Uploads: { kind: 'objects', id: 'Uploads', provides: ['UPLOADS_URL'] },\n * } as const satisfies ConstructManifest;\n *\n * type Ids = IdsOf<typeof constructs>; // 'Uploads'\n * type Env = ProvidedKeys<typeof constructs, 'Uploads'>; // 'UPLOADS_URL'\n * ```\n */\nexport type ConstructManifest = Readonly<Record<ConstructId, Declaration>>;\n\n// ---------------------------------------------------------------------------\n// Selecting from a concrete manifest\n// ---------------------------------------------------------------------------\n\n/** Every id in a manifest. */\nexport type IdsOf<M extends ConstructManifest> = Extract<keyof M, string>;\n\n/** The declaration for one id. */\nexport type DeclarationOf<\n\tM extends ConstructManifest,\n\tK extends IdsOf<M>,\n> = M[K];\n\n/** Every id of a given kind — what an adapter iterates when provisioning. */\nexport type IdsOfKind<\n\tM extends ConstructManifest,\n\tK extends DeclarationKind,\n> = {\n\t[Id in IdsOf<M>]: M[Id]['kind'] extends K ? Id : never;\n}[IdsOf<M>];\n\n/** The env keys one construct provides. */\nexport type ProvidedKeys<\n\tM extends ConstructManifest,\n\tK extends IdsOf<M>,\n> = M[K] extends { provides: readonly (infer P)[] } ? P : never;\n\n/** Every env key any construct in the manifest provides. */\nexport type AllProvidedKeys<M extends ConstructManifest> = {\n\t[Id in IdsOf<M>]: ProvidedKeys<M, Id>;\n}[IdsOf<M>];\n\n// ---------------------------------------------------------------------------\n// The app ↔ infra contract\n// ---------------------------------------------------------------------------\n\n/**\n * What each kind provides, by role rather than by provider syntax.\n *\n * This is the contract between the construct that declares a key and the cloud\n * component that supplies its value — an interface rather than shared code,\n * because a shared codec would have to contain `bucket` and `region`, and\n * provider words in the neutral layer is the problem this design exists to fix.\n *\n * How a value is composed and parsed stays private to each provider pair, so\n * `s3://` and `gs://` never appear here.\n */\nexport interface ProvidesByKind {\n\tobjects: { url: string };\n\t/** Where the served objects answer. Public: a browser is the point of it. */\n\t'file-server': { url: string };\n\t/**\n\t * An `smtp://` URL, credentials included — never shippable — and the\n\t * identity mail is sent from.\n\t *\n\t * The sending address is the one thing about mail that genuinely differs per\n\t * stage (`myapp.test` locally, a verified domain deployed), so it travels\n\t * beside the URL rather than being written into the construct.\n\t */\n\temail: {\n\t\turl: string;\n\t\tfrom: string;\n\t\t/**\n\t\t * Where the mail it sent can be read — Mailpit's web inbox. Local\n\t\t * stages only: deployed mail has no inbox, so nothing deployed supplies\n\t\t * it, and an app that reads it falls back to the phone's own mail app.\n\t\t */\n\t\tinboxUrl?: string;\n\t};\n\t/**\n\t * One key, the runtime role's. The owner URL is not here by design — see\n\t * {@link DatabaseDeclaration}.\n\t */\n\tdatabase: { url: string };\n\t'database-reader': { url: string };\n\t'database-schema': { url: string };\n\t/** The endpoint and its token, in one string. */\n\tcache: { url: string };\n\t/**\n\t * Where the surface answers, who may call it, and the domain its cookies\n\t * are scoped to.\n\t *\n\t * Only `url` is a fact about the surface itself. The other two are read off\n\t * its *inbound* edges — every construct that depends on it — which is why a\n\t * surface never lists its own callers: nothing enumerates the things that\n\t * point at it, the graph already does.\n\t *\n\t * `trustedOrigins` and `cookieDomain` are one key each rather than a list\n\t * and a structure, because both cross a process boundary as environment.\n\t */\n\t'rest-api': {\n\t\turl: string;\n\t\t/** Comma-separated. Empty when nothing declares an edge to this surface. */\n\t\ttrustedOrigins: string;\n\t\t/**\n\t\t * The parent domain shared by the surface and its callers, leading dot\n\t\t * included — `.example.com`. Absent where there is nothing to share:\n\t\t * one host locally, unrelated hosts deployed.\n\t\t */\n\t\tcookieDomain: string;\n\t};\n\t/** The value itself. A secret has no address to hand out instead. */\n\tsecret: { value: string };\n\t/**\n\t * The credential as one JSON object, parsed and validated by the construct\n\t * that declared the schema.\n\t */\n\tcredential: { credentials: string };\n\t/** Where the key is: a keyring, or a KMS key and its HMAC key. */\n\tencryption: { url: string };\n\t/**\n\t * The producer's connection string. One key, not two: the consumer is\n\t * reached through the queue rather than by an address of its own.\n\t */\n\tqueue: { publisherConnectionString: string };\n\ttopic: { publisherConnectionString: string };\n\t/** Where to invoke it — what lets something else depend on a function. */\n\tfunction: { url: string };\n\t/** A cron is reached by its schedule and by nothing else, so it provides none. */\n\tcron: Record<never, never>;\n\t/** Where the site is served. Public for the same reason an API's is. */\n\tsite: { url: string };\n\t/**\n\t * The URL scheme it answers on — `shop`, on every stage. What its\n\t * `app.config.ts` registers and what the surfaces it calls trust.\n\t */\n\t'mobile-app': { scheme: string };\n\t/**\n\t * Where tokens come from and which audience they must carry.\n\t *\n\t * Two keys because the halves have different lifetimes: the issuer may be a\n\t * fact about the product, the audience is always a fact about one\n\t * deployment.\n\t */\n\toidc: { issuer: string; audience: string };\n\t/**\n\t * Where it answers — the provider, or its fake — and the credentials it\n\t * was issued for this stage, as one JSON object.\n\t */\n\t'external-api': { url: string; credentials: string };\n\t/**\n\t * A worker is reached by nothing — it reaches out, to a queue, a schedule,\n\t * a topic. So it publishes no address, the way a cron does not.\n\t */\n\tworker: Record<never, never>;\n\t// Its keys are OpenTelemetry's, not prefixed by the node's id — see\n\t// `TELEMETRY_KEYS`.\n\ttelemetry: Record<never, never>;\n}\n\nexport type Provides<K extends keyof ProvidesByKind> = ProvidesByKind[K];\n\n/**\n * Which provided values may be shipped to a browser.\n *\n * Drives client-side prefixing (`VITE_`, `NEXT_PUBLIC_`) and nothing else — it\n * is not a restriction on what may be depended on, since a server-side consumer\n * can legitimately use any of them. A bucket's `url` presigns and stays private.\n */\nexport const PUBLIC: {\n\treadonly [K in keyof ProvidesByKind]: readonly (keyof ProvidesByKind[K])[];\n} = {\n\tobjects: [],\n\t// The address a browser fetches an image from. The bucket's own URL is not\n\t// here and must not be: it presigns, and a presigner in a bundle is a\n\t// credential in a bundle.\n\t'file-server': ['url'],\n\t// Not the URL — it carries the SMTP credentials in its userinfo. The inbox\n\t// is a page a browser opens, and exists only locally: it is how a site or\n\t// a phone opens the sign-in link the server just sent, without fishing it\n\t// out of Mailpit by hand.\n\temail: ['inboxUrl'],\n\t// A connection string is never shippable, whichever role it carries.\n\tdatabase: [],\n\t'database-reader': [],\n\t'database-schema': [],\n\t// Carries its token, and a cache a browser can write is a cache it can\n\t// poison.\n\tcache: [],\n\t// The whole point of one.\n\tsecret: [],\n\t// A credential a browser can read is a credential anyone can read. A\n\t// publishable key belongs in the site's own config, not in this.\n\tcredential: [],\n\t// A keyring in a bundle is a key anyone can read.\n\tencryption: [],\n\t// A URL a browser calls is a URL a browser may hold. The other two are not\n\t// secret either — they are simply server-side facts, and prefixing a value\n\t// into a bundle that nothing there reads is how a bundle grows keys nobody\n\t// can account for.\n\t'rest-api': ['url'],\n\t// Carries broker credentials, and a browser that can publish to a queue can\n\t// forge any job the worker trusts.\n\tqueue: [],\n\ttopic: [],\n\t// A browser doing the sign-in flow needs both, and neither is secret: an\n\t// issuer is a public URL and an audience is a client id, which is the half\n\t// of an OAuth client that is meant to be seen.\n\toidc: ['issuer', 'audience'],\n\t// Called from the server with credentials a browser must never hold, and\n\t// the address alone is no use to anyone without them.\n\t'external-api': [],\n\t// An invocation address is not a public one: reaching it is IAM's business,\n\t// not a browser's.\n\tfunction: [],\n\tcron: [],\n\t// Read by its `app.config.ts` at build time, never shipped as a variable.\n\t'mobile-app': [],\n\t// Its own address, which it needs in order to build absolute links to\n\t// itself — and which an email templating a link to it needs too.\n\tsite: ['url'],\n\t// Nothing calls a worker, so there is no address to hand anyone. It reaches\n\t// out — to a queue, a schedule, a topic — and is reached by none of them.\n\tworker: [],\n\t// An exporter's endpoint and headers are a server's: the headers are a\n\t// credential, and a browser exports through its API's ingest route, never\n\t// to the provider. Nothing of a `Telemetry` node is ever inlined.\n\ttelemetry: [],\n};\n","/**\n * Manifest errors.\n *\n * Messages state the rule, which is constant; the offending value is a field.\n * An interpolated message cannot be matched on, reads differently every time it\n * is thrown, and carries user input into every log line that touches it.\n */\n\n/** A construct id that cannot survive the names derived from it. */\nexport class InvalidConstructId extends Error {\n\t/** What was passed in. */\n\treadonly input: string;\n\t/** What canonicalising it produced, which is what failed the rule. */\n\treadonly canonical: string;\n\n\tconstructor(input: string, canonical: string) {\n\t\tsuper(\n\t\t\t'A construct id must start with a letter and contain only letters and digits',\n\t\t);\n\t\tthis.name = 'InvalidConstructId';\n\t\tthis.input = input;\n\t\tthis.canonical = canonical;\n\t}\n}\n\n/** A derived construct naming a parent the manifest does not contain. */\nexport class UnknownParent extends Error {\n\t/** The derived construct. */\n\treadonly id: string;\n\t/** The parent it named. */\n\treadonly of: string;\n\t/** Ids the manifest does contain, for the caller to match against. */\n\treadonly available: readonly string[];\n\n\tconstructor(id: string, of: string, available: readonly string[]) {\n\t\tsuper('A derived construct must name a parent present in the manifest');\n\t\tthis.name = 'UnknownParent';\n\t\tthis.id = id;\n\t\tthis.of = of;\n\t\tthis.available = available;\n\t}\n}\n\n/**\n * A derived construct naming a parent that may not vend it — a reader of a\n * reader, a schema of a schema.\n */\nexport class IllegalDerivation extends Error {\n\treadonly id: string;\n\treadonly kind: string;\n\t/** The kind of the parent it named. */\n\treadonly parentKind: string;\n\t/** The parent kinds that may vend this one. */\n\treadonly allowed: readonly string[];\n\n\tconstructor(\n\t\tid: string,\n\t\tkind: string,\n\t\tparentKind: string,\n\t\tallowed: readonly string[],\n\t) {\n\t\tsuper('A derived construct must name a parent whose kind may vend it');\n\t\tthis.name = 'IllegalDerivation';\n\t\tthis.id = id;\n\t\tthis.kind = kind;\n\t\tthis.parentKind = parentKind;\n\t\tthis.allowed = allowed;\n\t}\n}\n","/**\n * lodash (Custom Build) <https://lodash.com/>\n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright jQuery Foundation and other contributors <https://jquery.org/>\n * Released under MIT license <https://lodash.com/license>\n * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>\n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as references for various `Number` constants. */\nvar INFINITY = 1 / 0;\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/** Used to match words composed of alphanumeric characters. */\nvar reAsciiWord = /[^\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\x7f]+/g;\n\n/** Used to match Latin Unicode letters (excluding mathematical operators). */\nvar reLatin = /[\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\xff\\u0100-\\u017f]/g;\n\n/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f\\\\ufe20-\\\\ufe23',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20f0',\n rsDingbatRange = '\\\\u2700-\\\\u27bf',\n rsLowerRange = 'a-z\\\\xdf-\\\\xf6\\\\xf8-\\\\xff',\n rsMathOpRange = '\\\\xac\\\\xb1\\\\xd7\\\\xf7',\n rsNonCharRange = '\\\\x00-\\\\x2f\\\\x3a-\\\\x40\\\\x5b-\\\\x60\\\\x7b-\\\\xbf',\n rsPunctuationRange = '\\\\u2000-\\\\u206f',\n rsSpaceRange = ' \\\\t\\\\x0b\\\\f\\\\xa0\\\\ufeff\\\\n\\\\r\\\\u2028\\\\u2029\\\\u1680\\\\u180e\\\\u2000\\\\u2001\\\\u2002\\\\u2003\\\\u2004\\\\u2005\\\\u2006\\\\u2007\\\\u2008\\\\u2009\\\\u200a\\\\u202f\\\\u205f\\\\u3000',\n rsUpperRange = 'A-Z\\\\xc0-\\\\xd6\\\\xd8-\\\\xde',\n rsVarRange = '\\\\ufe0e\\\\ufe0f',\n rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;\n\n/** Used to compose unicode capture groups. */\nvar rsApos = \"['\\u2019]\",\n rsBreak = '[' + rsBreakRange + ']',\n rsCombo = '[' + rsComboMarksRange + rsComboSymbolsRange + ']',\n rsDigits = '\\\\d+',\n rsDingbat = '[' + rsDingbatRange + ']',\n rsLower = '[' + rsLowerRange + ']',\n rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsUpper = '[' + rsUpperRange + ']',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar rsLowerMisc = '(?:' + rsLower + '|' + rsMisc + ')',\n rsUpperMisc = '(?:' + rsUpper + '|' + rsMisc + ')',\n rsOptLowerContr = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',\n rsOptUpperContr = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',\n reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq;\n\n/** Used to match apostrophes. */\nvar reApos = RegExp(rsApos, 'g');\n\n/**\n * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and\n * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).\n */\nvar reComboMark = RegExp(rsCombo, 'g');\n\n/** Used to match complex or compound words. */\nvar reUnicodeWord = RegExp([\n rsUpper + '?' + rsLower + '+' + rsOptLowerContr + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',\n rsUpperMisc + '+' + rsOptUpperContr + '(?=' + [rsBreak, rsUpper + rsLowerMisc, '$'].join('|') + ')',\n rsUpper + '?' + rsLowerMisc + '+' + rsOptLowerContr,\n rsUpper + '+' + rsOptUpperContr,\n rsDigits,\n rsEmoji\n].join('|'), 'g');\n\n/** Used to detect strings that need a more robust regexp to match words. */\nvar reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;\n\n/** Used to map Latin Unicode letters to basic Latin letters. */\nvar deburredLetters = {\n // Latin-1 Supplement block.\n '\\xc0': 'A', '\\xc1': 'A', '\\xc2': 'A', '\\xc3': 'A', '\\xc4': 'A', '\\xc5': 'A',\n '\\xe0': 'a', '\\xe1': 'a', '\\xe2': 'a', '\\xe3': 'a', '\\xe4': 'a', '\\xe5': 'a',\n '\\xc7': 'C', '\\xe7': 'c',\n '\\xd0': 'D', '\\xf0': 'd',\n '\\xc8': 'E', '\\xc9': 'E', '\\xca': 'E', '\\xcb': 'E',\n '\\xe8': 'e', '\\xe9': 'e', '\\xea': 'e', '\\xeb': 'e',\n '\\xcc': 'I', '\\xcd': 'I', '\\xce': 'I', '\\xcf': 'I',\n '\\xec': 'i', '\\xed': 'i', '\\xee': 'i', '\\xef': 'i',\n '\\xd1': 'N', '\\xf1': 'n',\n '\\xd2': 'O', '\\xd3': 'O', '\\xd4': 'O', '\\xd5': 'O', '\\xd6': 'O', '\\xd8': 'O',\n '\\xf2': 'o', '\\xf3': 'o', '\\xf4': 'o', '\\xf5': 'o', '\\xf6': 'o', '\\xf8': 'o',\n '\\xd9': 'U', '\\xda': 'U', '\\xdb': 'U', '\\xdc': 'U',\n '\\xf9': 'u', '\\xfa': 'u', '\\xfb': 'u', '\\xfc': 'u',\n '\\xdd': 'Y', '\\xfd': 'y', '\\xff': 'y',\n '\\xc6': 'Ae', '\\xe6': 'ae',\n '\\xde': 'Th', '\\xfe': 'th',\n '\\xdf': 'ss',\n // Latin Extended-A block.\n '\\u0100': 'A', '\\u0102': 'A', '\\u0104': 'A',\n '\\u0101': 'a', '\\u0103': 'a', '\\u0105': 'a',\n '\\u0106': 'C', '\\u0108': 'C', '\\u010a': 'C', '\\u010c': 'C',\n '\\u0107': 'c', '\\u0109': 'c', '\\u010b': 'c', '\\u010d': 'c',\n '\\u010e': 'D', '\\u0110': 'D', '\\u010f': 'd', '\\u0111': 'd',\n '\\u0112': 'E', '\\u0114': 'E', '\\u0116': 'E', '\\u0118': 'E', '\\u011a': 'E',\n '\\u0113': 'e', '\\u0115': 'e', '\\u0117': 'e', '\\u0119': 'e', '\\u011b': 'e',\n '\\u011c': 'G', '\\u011e': 'G', '\\u0120': 'G', '\\u0122': 'G',\n '\\u011d': 'g', '\\u011f': 'g', '\\u0121': 'g', '\\u0123': 'g',\n '\\u0124': 'H', '\\u0126': 'H', '\\u0125': 'h', '\\u0127': 'h',\n '\\u0128': 'I', '\\u012a': 'I', '\\u012c': 'I', '\\u012e': 'I', '\\u0130': 'I',\n '\\u0129': 'i', '\\u012b': 'i', '\\u012d': 'i', '\\u012f': 'i', '\\u0131': 'i',\n '\\u0134': 'J', '\\u0135': 'j',\n '\\u0136': 'K', '\\u0137': 'k', '\\u0138': 'k',\n '\\u0139': 'L', '\\u013b': 'L', '\\u013d': 'L', '\\u013f': 'L', '\\u0141': 'L',\n '\\u013a': 'l', '\\u013c': 'l', '\\u013e': 'l', '\\u0140': 'l', '\\u0142': 'l',\n '\\u0143': 'N', '\\u0145': 'N', '\\u0147': 'N', '\\u014a': 'N',\n '\\u0144': 'n', '\\u0146': 'n', '\\u0148': 'n', '\\u014b': 'n',\n '\\u014c': 'O', '\\u014e': 'O', '\\u0150': 'O',\n '\\u014d': 'o', '\\u014f': 'o', '\\u0151': 'o',\n '\\u0154': 'R', '\\u0156': 'R', '\\u0158': 'R',\n '\\u0155': 'r', '\\u0157': 'r', '\\u0159': 'r',\n '\\u015a': 'S', '\\u015c': 'S', '\\u015e': 'S', '\\u0160': 'S',\n '\\u015b': 's', '\\u015d': 's', '\\u015f': 's', '\\u0161': 's',\n '\\u0162': 'T', '\\u0164': 'T', '\\u0166': 'T',\n '\\u0163': 't', '\\u0165': 't', '\\u0167': 't',\n '\\u0168': 'U', '\\u016a': 'U', '\\u016c': 'U', '\\u016e': 'U', '\\u0170': 'U', '\\u0172': 'U',\n '\\u0169': 'u', '\\u016b': 'u', '\\u016d': 'u', '\\u016f': 'u', '\\u0171': 'u', '\\u0173': 'u',\n '\\u0174': 'W', '\\u0175': 'w',\n '\\u0176': 'Y', '\\u0177': 'y', '\\u0178': 'Y',\n '\\u0179': 'Z', '\\u017b': 'Z', '\\u017d': 'Z',\n '\\u017a': 'z', '\\u017c': 'z', '\\u017e': 'z',\n '\\u0132': 'IJ', '\\u0133': 'ij',\n '\\u0152': 'Oe', '\\u0153': 'oe',\n '\\u0149': \"'n\", '\\u017f': 'ss'\n};\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/**\n * A specialized version of `_.reduce` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @param {*} [accumulator] The initial value.\n * @param {boolean} [initAccum] Specify using the first element of `array` as\n * the initial value.\n * @returns {*} Returns the accumulated value.\n */\nfunction arrayReduce(array, iteratee, accumulator, initAccum) {\n var index = -1,\n length = array ? array.length : 0;\n\n if (initAccum && length) {\n accumulator = array[++index];\n }\n while (++index < length) {\n accumulator = iteratee(accumulator, array[index], index, array);\n }\n return accumulator;\n}\n\n/**\n * Splits an ASCII `string` into an array of its words.\n *\n * @private\n * @param {string} The string to inspect.\n * @returns {Array} Returns the words of `string`.\n */\nfunction asciiWords(string) {\n return string.match(reAsciiWord) || [];\n}\n\n/**\n * The base implementation of `_.propertyOf` without support for deep paths.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Function} Returns the new accessor function.\n */\nfunction basePropertyOf(object) {\n return function(key) {\n return object == null ? undefined : object[key];\n };\n}\n\n/**\n * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A\n * letters to basic Latin letters.\n *\n * @private\n * @param {string} letter The matched letter to deburr.\n * @returns {string} Returns the deburred letter.\n */\nvar deburrLetter = basePropertyOf(deburredLetters);\n\n/**\n * Checks if `string` contains a word composed of Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a word is found, else `false`.\n */\nfunction hasUnicodeWord(string) {\n return reHasUnicodeWord.test(string);\n}\n\n/**\n * Splits a Unicode `string` into an array of its words.\n *\n * @private\n * @param {string} The string to inspect.\n * @returns {Array} Returns the words of `string`.\n */\nfunction unicodeWords(string) {\n return string.match(reUnicodeWord) || [];\n}\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolToString = symbolProto ? symbolProto.toString : undefined;\n\n/**\n * The base implementation of `_.toString` which doesn't convert nullish\n * values to empty strings.\n *\n * @private\n * @param {*} value The value to process.\n * @returns {string} Returns the string.\n */\nfunction baseToString(value) {\n // Exit early for strings to avoid a performance hit in some environments.\n if (typeof value == 'string') {\n return value;\n }\n if (isSymbol(value)) {\n return symbolToString ? symbolToString.call(value) : '';\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\n/**\n * Creates a function like `_.camelCase`.\n *\n * @private\n * @param {Function} callback The function to combine each word.\n * @returns {Function} Returns the new compounder function.\n */\nfunction createCompounder(callback) {\n return function(string) {\n return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');\n };\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return !!value && typeof value == 'object';\n}\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && objectToString.call(value) == symbolTag);\n}\n\n/**\n * Converts `value` to a string. An empty string is returned for `null`\n * and `undefined` values. The sign of `-0` is preserved.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {string} Returns the string.\n * @example\n *\n * _.toString(null);\n * // => ''\n *\n * _.toString(-0);\n * // => '-0'\n *\n * _.toString([1, 2, 3]);\n * // => '1,2,3'\n */\nfunction toString(value) {\n return value == null ? '' : baseToString(value);\n}\n\n/**\n * Deburrs `string` by converting\n * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)\n * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)\n * letters to basic Latin letters and removing\n * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to deburr.\n * @returns {string} Returns the deburred string.\n * @example\n *\n * _.deburr('déjà vu');\n * // => 'deja vu'\n */\nfunction deburr(string) {\n string = toString(string);\n return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');\n}\n\n/**\n * Converts `string` to\n * [snake case](https://en.wikipedia.org/wiki/Snake_case).\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to convert.\n * @returns {string} Returns the snake cased string.\n * @example\n *\n * _.snakeCase('Foo Bar');\n * // => 'foo_bar'\n *\n * _.snakeCase('fooBar');\n * // => 'foo_bar'\n *\n * _.snakeCase('--FOO-BAR--');\n * // => 'foo_bar'\n */\nvar snakeCase = createCompounder(function(result, word, index) {\n return result + (index ? '_' : '') + word.toLowerCase();\n});\n\n/**\n * Splits `string` into an array of its words.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to inspect.\n * @param {RegExp|string} [pattern] The pattern to match words.\n * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.\n * @returns {Array} Returns the words of `string`.\n * @example\n *\n * _.words('fred, barney, & pebbles');\n * // => ['fred', 'barney', 'pebbles']\n *\n * _.words('fred, barney, & pebbles', /[^, ]+/g);\n * // => ['fred', 'barney', '&', 'pebbles']\n */\nfunction words(string, pattern, guard) {\n string = toString(string);\n pattern = guard ? undefined : pattern;\n\n if (pattern === undefined) {\n return hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);\n }\n return string.match(pattern) || [];\n}\n\nmodule.exports = snakeCase;\n","/**\n * Name derivation — the single source for turning a construct's id into the\n * names that appear elsewhere.\n *\n * These live here rather than in each consumer because `@geekmidas/constructs`\n * derives a key when it declares, and `@geekmidas/cloud` derives the same key\n * when it supplies the value. Two implementations of the same rule is precisely\n * the drift this design exists to remove.\n */\n\nimport snakecase from 'lodash.snakecase';\nimport type { DeclarationKind } from './declaration';\n\nimport { InvalidConstructId } from './errors';\n\n/**\n * `UPPER_SNAKE_CASE`, with numbers kept against the word they follow.\n *\n * Matches `environmentCase` in `@geekmidas/envkit`, which reads the values these\n * names key. The two must agree exactly, so this is the implementation and that\n * one should defer to it.\n *\n * @example environmentCase('sendEmail') // 'SEND_EMAIL'\n * @example environmentCase('api2') // 'API2' (digit joins its word)\n */\nexport function environmentCase(name: string): string {\n\treturn snakecase(name)\n\t\t.toUpperCase()\n\t\t.replace(/_\\d+/g, (r) => r.replace('_', ''));\n}\n\n/**\n * The env key a construct provides for one of its roles.\n *\n * @example provideKey('Uploads', 'url') // 'UPLOADS_URL'\n * @example provideKey('Uploads', 'cdnUrl') // 'UPLOADS_CDN_URL'\n */\nexport function provideKey(id: string, role: string): string {\n\treturn environmentCase(`${id}_${role}`);\n}\n\n/**\n * A construct's canonical id — PascalCase.\n *\n * `uploads`, `Uploads`, `user_uploads`, and `user-uploads` all canonicalise to\n * the same id, so declaring two of them is a duplicate rather than a collision\n * to detect.\n *\n * Runtime only. Writing the id in PascalCase is what keeps the *type* usable:\n * the service key is `Uncapitalize<TName>`, a TypeScript intrinsic, so no\n * type-level transform is needed and none has to be kept in step with this one.\n *\n * @example canonicalId('user-uploads') // 'UserUploads'\n */\nexport function canonicalId(input: string): string {\n\t// `upperFirst(camelCase(x))` by another route — snakecase is already a\n\t// dependency, and adding lodash.camelcase for the same result is not worth it.\n\tconst id = snakecase(input)\n\t\t.split('_')\n\t\t.filter(Boolean)\n\t\t.map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n\t\t.join('');\n\n\tif (!VALID_ID.test(id)) throw new InvalidConstructId(input, id);\n\treturn id;\n}\n\n/**\n * A canonical id: PascalCase, letters and digits only.\n *\n * Narrower than a JavaScript identifier — `_id` and `$ref` are legal JavaScript\n * and rejected here — because the id also has to survive `environmentCase` into\n * an env key and `cloudName` into a DNS-safe resource name.\n */\nconst VALID_ID = /^[A-Z][A-Za-z0-9]*$/;\n\n/**\n * The key a construct is reached under in the service record.\n *\n * The runtime twin of `Uncapitalize<TName>`, which types it — they must agree,\n * so they live next to each other rather than being re-derived by each\n * construct.\n *\n * @example serviceKey('UserUploads') // 'userUploads' → services.userUploads\n */\nexport function serviceKey(id: string): string {\n\treturn id.charAt(0).toLowerCase() + id.slice(1);\n}\n\n/**\n * The table a cache keeps its entries in, when nobody named one.\n *\n * Derived from the cache's own id rather than fixed at `cache`, because a\n * database may hold more than one and two caches sharing a table share a\n * keyspace — `orders.cache('Sessions')` and `orders.cache('Rates')` would\n * silently read each other's entries and evict each other's keys.\n *\n * Prefixed rather than suffixed so every cache sorts together in `\\dt`, and\n * prefixed at all so a cache named for a thing the application also stores —\n * `orders.cache('Users')` — cannot collide with the table holding that thing.\n *\n * Read by whoever composes the URL and by whoever creates the table, so both\n * default the same way.\n *\n * @example cacheTable('Sessions') // 'cache_sessions'\n */\nexport function cacheTable(id: string): string {\n\treturn `cache_${id.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase()}`;\n}\n\n/**\n * Kebab-cases an identifier, acronym- and digit-aware.\n *\n * `userName` → `user-name`, `APIKey` → `api-key`, `S3Bucket` → `s3-bucket`.\n *\n * The last of those is why this is here rather than `snakecase(id)` with the\n * underscores swapped: lodash splits a digit from the letter beside it, so\n * `S3Bucket` became `s-3-bucket` on one provider and `s3-bucket` on the other.\n * Two implementations of one rule, agreeing on every id anybody had tried.\n *\n * `environmentCase` already corrected for the same thing in the other\n * direction — `api2` keeps its digit — so the two spellings of \"kebab this id\"\n * in this file did not even agree with each other.\n */\nexport function kebabCase(value: string): string {\n\treturn value\n\t\t.replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')\n\t\t.replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n\t\t.replace(/[\\s_]+/g, '-')\n\t\t.toLowerCase();\n}\n\n/**\n * The physical name a target provisions a construct under — lowercase kebab,\n * scoped so two stages or apps sharing an account cannot collide.\n *\n * **One rule, every provider.** A construct is named the same thing on AWS and\n * on Dokploy, which is what lets a name be read across them: `Database` in the\n * `production` stage of `kitchen-sink` is `production-kitchen-sink-database`\n * wherever it lands. The SST target's `prefixedName` is this function under\n * another signature and defers to it.\n *\n * Idempotent in its prefix: an id that already carries the scope is not given a\n * second one, so composing names cannot double up.\n *\n * @example cloudName({ stage: 'prod', app: 'myapp' }, 'UserUploads')\n * // 'prod-myapp-user-uploads'\n */\nexport function cloudName(\n\tscope: { stage: string; app: string },\n\tid: string,\n): string {\n\treturn scopedName([scope.stage, scope.app], id);\n}\n\n/**\n * {@link cloudName} for a caller that holds its scope as a list.\n *\n * The SST target's stacks add a segment of their own, so the prefix is not\n * always two parts — which is the only reason this signature exists.\n */\nexport function scopedName(scope: readonly string[], id: string): string {\n\tconst prefix = scope.join('-').toLowerCase();\n\tconst name = kebabCase(id);\n\n\treturn name.startsWith(prefix) ? name : `${prefix}-${name}`;\n}\n\n/**\n * The domain a cookie must be scoped to so a surface and its callers share it.\n *\n * Derived from the addresses rather than configured, for the same reason the\n * origins are: the set of things that talk to a surface is already in the graph,\n * and the domain they have in common is a fact about that set. Returned with the\n * leading dot a `Domain` attribute wants.\n *\n * Returns `undefined` when there is nothing to scope, which is the common case\n * and not a failure:\n *\n * - **One host.** Locally everything is `localhost` on different ports, and\n * cookies ignore the port — so a `Domain` would add nothing and `.localhost`\n * is not a domain a browser will accept.\n * - **Nothing in common.** Unrelated hosts cannot share a cookie at all, and\n * emitting the longest common suffix anyway would be a value that silently\n * fails to set.\n *\n * **The public-suffix limit, stated rather than discovered.** Two apps on\n * `a.vercel.app` and `b.vercel.app` share `.vercel.app`, which every browser\n * rejects because it is a registrable suffix rather than a registrable domain.\n * Resolving that correctly needs the Public Suffix List, which is a downloaded,\n * expiring dataset — so this requires at least two labels and otherwise trusts\n * the addresses, and the value stays overridable for the case it gets wrong.\n */\nexport function cookieDomain(urls: readonly string[]): string | undefined {\n\tconst hosts = new Set<string>();\n\n\tfor (const url of urls) {\n\t\ttry {\n\t\t\tconst { hostname } = new URL(url);\n\t\t\t// An IP address has no parent to share: `.0.0.1` is not a domain.\n\t\t\tif (/^\\d+(\\.\\d+){3}$/.test(hostname) || hostname.includes(':')) return;\n\t\t\thosts.add(hostname.toLowerCase());\n\t\t} catch {\n\t\t\t// Not an address. Nothing to derive from, and guessing is worse than\n\t\t\t// leaving the attribute off.\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (hosts.size === 0) return;\n\t// One host already shares its cookies with itself, whatever the port.\n\tif (hosts.size === 1) return;\n\n\tconst [first = [], ...rest] = [...hosts].map((host) =>\n\t\thost.split('.').reverse(),\n\t);\n\tconst shared: string[] = [];\n\n\tfor (const [index, label] of first.entries()) {\n\t\tif (!rest.every((labels) => labels[index] === label)) break;\n\t\tshared.push(label);\n\t}\n\n\t// One shared label is a TLD — `.com` is not a cookie domain.\n\tif (shared.length < 2) return;\n\n\treturn `.${shared.reverse().join('.')}`;\n}\n\n/**\n * The env key a construct's provided role actually becomes.\n *\n * Almost always `provideKey(id, role)` — and `secret` is the exception, because\n * a secret's *name* is its key: `Auth` signs with `AUTH_SECRET`, which is also\n * what better-auth's own tooling looks for, and qualifying it by role would\n * produce `AUTH_SECRET_VALUE`.\n *\n * It lives here rather than in each target because two targets deriving the\n * same key separately is exactly the drift the app/infra contract check exists\n * to catch — and a check deriving the key differently from the thing it checks\n * cannot catch anything.\n */\nexport function providedKeyFor(\n\tid: string,\n\tkind: DeclarationKind,\n\trole: string,\n): string {\n\tif (kind === 'secret') return environmentCase(id);\n\t// OpenTelemetry's own variable, whatever the node is called: an SDK reads\n\t// nothing else.\n\tif (kind === 'telemetry') return 'OTEL_EXPORTER_OTLP_ENDPOINT';\n\treturn provideKey(id, role);\n}\n","/**\n * Derived constructs — the ones that provision nothing of their own.\n *\n * A reader is an endpoint on an existing cluster; a schema tenant is a schema\n * inside an existing database. Both name their parent through `of`, and both\n * stay top-level entries so that `dependencies[].target` keeps resolving as\n * `m[target]` and every id remains a key in the map.\n *\n * The rules here are pure and manifest-only: they hold for any target adapter,\n * so an app is wrong before a deploy is attempted rather than during one.\n */\n\nimport type {\n\tConstructId,\n\tConstructManifest,\n\tDeclaration,\n\tDependency,\n\tDerivedDeclaration,\n\tMobileAppDeclaration,\n\tSiteDeclaration,\n} from './declaration';\nimport { DERIVES_FROM, PUBLIC } from './declaration';\nimport { IllegalDerivation, UnknownParent } from './errors';\nimport { provideKey } from './naming';\n\n/** Whether a declaration names a parent. */\nexport function isDerived(\n\tdeclaration: Declaration,\n): declaration is DerivedDeclaration & { of: ConstructId } {\n\t// Both halves, because one kind is *optionally* derived: a cache declared\n\t// from a database names it, and a cache declared on its own names nothing.\n\t// Testing only the kind would make every standalone cache look like a\n\t// derivation with a missing parent.\n\treturn (\n\t\tdeclaration.kind in DERIVES_FROM &&\n\t\t'of' in declaration &&\n\t\ttypeof declaration.of === 'string'\n\t);\n}\n\n/**\n * Check every derived construct against its parent.\n *\n * Two rules: the parent exists, and its kind may vend this one. Together they\n * make cycles unreachable — a reader is terminal, so no chain of `of` can\n * return to where it started, and no walk is needed to prove it.\n */\nexport function assertDerivations(manifest: ConstructManifest): void {\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tif (!isDerived(declaration)) continue;\n\n\t\tconst parent = manifest[declaration.of];\n\t\tif (!parent) {\n\t\t\tthrow new UnknownParent(id, declaration.of, Object.keys(manifest));\n\t\t}\n\n\t\tconst allowed = DERIVES_FROM[declaration.kind];\n\t\tif (!allowed.includes(parent.kind)) {\n\t\t\tthrow new IllegalDerivation(id, declaration.kind, parent.kind, allowed);\n\t\t}\n\t}\n}\n\n/**\n * The order constructs must be provisioned in: every parent before its children.\n *\n * Resources are leaves and so come first in any order; only derived nodes\n * constrain the sequence, and they form a shallow forest rather than a general\n * graph. This walks each node's ancestors on demand instead of running a full\n * topological sort, which is the same result at this depth and reads as what it\n * is.\n *\n * Assumes {@link assertDerivations} has passed — a missing parent would\n * otherwise be a silent omission here rather than an error.\n */\nexport function provisionOrder(manifest: ConstructManifest): string[] {\n\tconst ordered: string[] = [];\n\tconst placed = new Set<string>();\n\n\tconst place = (id: string): void => {\n\t\tif (placed.has(id)) return;\n\t\tconst declaration = manifest[id];\n\t\tif (!declaration) return;\n\n\t\t// Mark before recursing: `assertDerivations` rules cycles out, and marking\n\t\t// first means a manifest that skipped that check terminates anyway.\n\t\tplaced.add(id);\n\t\tif (isDerived(declaration)) place(declaration.of);\n\t\tordered.push(id);\n\t};\n\n\tfor (const id of Object.keys(manifest)) place(id);\n\n\treturn ordered;\n}\n\n/**\n * Every edge a declaration carries, wherever the kind happens to keep them.\n *\n * Dependencies live in two places by design: on a node when the whole construct\n * is the consumer (a site), and on each nested handler when the construct is a\n * surface (a `rest-api`, whose routes each depend on their own things and\n * nothing more). Flattening that difference here is what lets every consumer of\n * the graph — reverse lookups, filtering, reference checks — ask one question.\n */\nexport function dependenciesOf(\n\tdeclaration: Declaration,\n): readonly Dependency[] {\n\tconst own =\n\t\t'dependencies' in declaration ? (declaration.dependencies ?? []) : [];\n\n\t// A surface's `calls` is a caller relationship rather than an injection, so\n\t// it is read here — reverse lookups want it — and is never a dependency\n\t// anything links from. See `RestApiDeclaration.calls`.\n\tconst calls = 'calls' in declaration ? (declaration.calls ?? []) : [];\n\n\tconst nested =\n\t\tdeclaration.kind === 'rest-api'\n\t\t\t? declaration.endpoints.flatMap((endpoint) => endpoint.dependencies)\n\t\t\t: [];\n\n\t// The `Telemetry` node a process emits through: an edge like any other, so\n\t// the keys it provides follow it to exactly the processes that use it.\n\tconst telemetry =\n\t\t'telemetry' in declaration && typeof declaration.telemetry === 'string'\n\t\t\t? [{ target: declaration.telemetry, kind: 'telemetry' as const }]\n\t\t\t: [];\n\n\treturn [...own, ...calls, ...nested, ...telemetry];\n}\n\n/**\n * The ids that depend on one construct — the graph read backwards.\n *\n * This is the whole mechanism behind CORS origins and trusted origins. Both are\n * lists of *callers*, and a caller is exactly an inbound edge, so neither is\n * ever written down: a surface that listed its own callers would have to be\n * edited every time something new called it, which is the hand-maintained list\n * this replaces.\n *\n * Sorted, because it feeds a comma-separated env value that would otherwise\n * change whenever the manifest's key order did — and a value that churns is a\n * container that redeploys for no reason.\n */\nexport function dependentsOf(\n\tmanifest: ConstructManifest,\n\tid: ConstructId,\n): string[] {\n\tconst callers: string[] = [];\n\n\tfor (const [callerId, declaration] of Object.entries(manifest)) {\n\t\tif (callerId === id) continue;\n\t\tif (dependenciesOf(declaration).some((edge) => edge.target === id)) {\n\t\t\tcallers.push(callerId);\n\t\t}\n\t}\n\n\treturn callers.sort();\n}\n\n/**\n * How each site variant names a value it ships to the browser.\n *\n * The prefix *is* the framework's contract — `VITE_`, `NEXT_PUBLIC_` and\n * `EXPO_PUBLIC_` all mean \"inline this into the bundle\" — so it is the one thing\n * a variant changes, and it changes nothing else.\n */\nexport const PUBLIC_PREFIX: Record<\n\tSiteDeclaration['variant'] | MobileAppDeclaration['variant'],\n\tstring\n> = {\n\tstatic: 'VITE_',\n\ttanstack: 'VITE_',\n\tnext: 'NEXT_PUBLIC_',\n\texpo: 'EXPO_PUBLIC_',\n};\n\n/**\n * The keys a site's bundle needs, mapped to the key each value comes from —\n * `{ VITE_API_URL: 'API_URL' }`.\n *\n * A rename, not a second derivation: `API_URL` is resolved once, by whatever\n * resolved it for the server, and the site reads the same value under the name\n * its bundler will inline. That is what keeps a site and its API from coming to\n * disagree about where the API is.\n *\n * Filtered by `PUBLIC` rather than by what the site asked for. A site may\n * legitimately depend on anything — its server half, where it has one, reads env\n * exactly as a function does — so this is not a restriction on edges. It decides\n * one thing: which values may be prefixed into a bundle, which is what keeps\n * `ORDERS_URL` and its password out of a JavaScript file served to the public.\n *\n * Shared by every target for the same reason `providedKeyFor` is: a site built\n * locally and the same site built by a deploy must inline the same names.\n */\nexport function publicEnvFor(\n\tdeclaration: SiteDeclaration | MobileAppDeclaration,\n\tmanifest: ConstructManifest,\n): Record<string, string> {\n\tconst prefix = PUBLIC_PREFIX[declaration.variant];\n\tconst keys: Record<string, string> = {};\n\n\tfor (const edge of declaration.dependencies) {\n\t\tconst target = manifest[edge.target];\n\t\tif (!target) continue;\n\n\t\tfor (const role of PUBLIC[target.kind] ?? []) {\n\t\t\tconst key = provideKey(edge.target, role as string);\n\t\t\tkeys[`${prefix}${key}`] = key;\n\t\t}\n\t}\n\n\treturn keys;\n}\n","/**\n * The `kms://` URL an `Encryption` construct reads on AWS.\n *\n * Here because two packages meet on it: `@geekmidas/cloud` composes it from\n * the keys it provisioned, and `@geekmidas/constructs` parses it to reach\n * them. One function, so the two cannot disagree about a parameter's name.\n */\n\nexport const KMS_SCHEME = 'kms:';\n\n/**\n * `kms://<region>?key=<key arn>&index=<hmac key arn>[&endpoint=<url>]`\n *\n * `endpoint` reaches an emulator instead of AWS — floci, locally and in tests —\n * the same parameter an `sns://` connection string carries for the same reason.\n */\nexport function kmsUrl(input: {\n\tregion: string;\n\tkey: string;\n\tindex: string;\n\tendpoint?: string;\n}): string {\n\tconst query = new URLSearchParams({\n\t\tkey: input.key,\n\t\tindex: input.index,\n\t\t...(input.endpoint ? { endpoint: input.endpoint } : {}),\n\t});\n\treturn `${KMS_SCHEME}//${input.region}?${query}`;\n}\n","import type { ExternalApiDeclaration } from './declaration';\n\n/** The key in a by-stage `url` that answers for every stage not listed. */\nexport const DEFAULT_STAGE_URL = 'default';\n\n/**\n * Where an external API answers on a deployed stage.\n *\n * One URL answers every stage; a record answers by stage name, falling back\n * to `default`. Read at build and deploy, so a stage nobody gave a URL fails\n * there — with the stage named — rather than at the first request.\n *\n * @throws {NoUrlForStage} when a record names neither the stage nor a default.\n */\nexport function externalApiUrl(\n\tdeclaration: Pick<ExternalApiDeclaration, 'id' | 'url'>,\n\tstage: string,\n): string {\n\tconst { url } = declaration;\n\tif (typeof url === 'string') return url;\n\n\tconst resolved = url[stage] ?? url[DEFAULT_STAGE_URL];\n\tif (!resolved) {\n\t\tthrow new NoUrlForStage(declaration.id, stage, Object.keys(url));\n\t}\n\n\treturn resolved;\n}\n\n/** An external API's `url` record has nothing for the stage being deployed. */\nexport class NoUrlForStage extends Error {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly stage: string,\n\t\treadonly stages: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`'${id}' has no URL for the stage '${stage}': its url names ` +\n\t\t\t\t`${stages.length ? stages.map((s) => `'${s}'`).join(', ') : 'no stages'}. ` +\n\t\t\t\t`Add '${stage}', or a '${DEFAULT_STAGE_URL}' for every stage not listed.`,\n\t\t);\n\t\tthis.name = 'NoUrlForStage';\n\t}\n}\n","/**\n * Which constructs take migrations, where their files live, and in what order\n * they run — resolved once, from the manifest.\n *\n * `gkm migrate`, `gkm test`, `gkm migration` and every deploy target ask the\n * same question. Each deriving it on its own is how one of them comes to\n * migrate a reader, skip a tenant, or run a tenant's files before the parent\n * that owns its schema exists.\n */\n\nimport type { ConstructId, ConstructManifest } from './declaration';\nimport { provisionOrder } from './derive';\nimport { kebabCase } from './naming';\n\n/** Where every construct's folder lives, from the project root. */\nexport const MIGRATIONS_ROOT = 'db';\n\n/** The two folders a construct's folder holds, and nothing else. */\nexport const DATABASE_FOLDERS = ['migrations', 'seeds'] as const;\n\n/** One construct whose schema is changed by migrations. */\nexport interface MigrationTarget {\n\t/** The construct's canonical id, e.g. `AuthDatabase`. */\n\tid: ConstructId;\n\t/** Its folder, relative to the project root: `db/auth-database`. */\n\tfolder: string;\n\t/** Its schema's history: `db/auth-database/migrations`. */\n\tmigrations: string;\n\t/** The reference data it needs to run: `db/auth-database/seeds`. */\n\tseeds: string;\n\t/** For a schema tenant, the database it lives in. */\n\tof?: ConstructId;\n}\n\n/**\n * The constructs that take migrations, parents before the tenants inside them.\n *\n * A database and each schema tenant: every one has an owner role and a schema\n * of its own, and so a history of its own. A reader has neither — it reads its\n * parent's schema — and a cache's table is created by provisioning, not by a\n * migration anyone writes.\n */\nexport function migrationTargets(\n\tmanifest: ConstructManifest,\n): MigrationTarget[] {\n\treturn provisionOrder(manifest).flatMap((id) => {\n\t\tconst declaration = manifest[id];\n\t\tif (!declaration) return [];\n\n\t\tif (declaration.kind === 'database') return [target(id)];\n\t\tif (declaration.kind === 'database-schema') {\n\t\t\treturn [{ ...target(id), of: declaration.of }];\n\t\t}\n\n\t\treturn [];\n\t});\n}\n\n/**\n * A construct's folder, relative to the project root.\n *\n * Named by the construct — `AuthDatabase` is `db/auth-database` — in the case\n * every other name outside TypeScript takes. Lowercase, because a folder that\n * differs from another only in case is two folders on Linux and one on a Mac;\n * and `canonicalId` reads it back to the construct exactly, which is how a\n * folder naming nothing is caught rather than skipped.\n */\nexport function databaseFolder(id: ConstructId): string {\n\treturn `${MIGRATIONS_ROOT}/${kebabCase(id)}`;\n}\n\n/** Where a construct's migrations live: `db/auth-database/migrations`. */\nexport function migrationFolder(id: ConstructId): string {\n\treturn `${databaseFolder(id)}/migrations`;\n}\n\n/**\n * Where a construct's seeds live: `db/auth-database/seeds`.\n *\n * Reference data the app needs to run — a permission catalogue, roles, lookup\n * tables. Seeds are upserts run on every pass, after the migrations, so a\n * changed seed is applied by running it again. Sample data is factories'.\n */\nexport function seedFolder(id: ConstructId): string {\n\treturn `${databaseFolder(id)}/seeds`;\n}\n\nfunction target(id: ConstructId): MigrationTarget {\n\treturn {\n\t\tid,\n\t\tfolder: databaseFolder(id),\n\t\tmigrations: migrationFolder(id),\n\t\tseeds: seedFolder(id),\n\t};\n}\n","/**\n * How a mobile app is reached: its URL scheme, and the origins a surface trusts\n * for it.\n *\n * Stated once, here, because three targets ask — the local one (`gkm dev`,\n * `gkm test`), Dokploy and AWS — and a scheme one of them derived differently\n * would be an app whose sign-in callback the auth server refuses on exactly one\n * of them.\n */\n\n/**\n * An app's scheme: the one given, or the project's name made a valid scheme.\n *\n * One for every stage. A development build and the store build register the\n * same scheme, so the auth server of whichever stage a build talks to trusts\n * it, and nothing about the app differs between stages but its URLs.\n *\n * A scheme is a letter followed by letters, digits, `+`, `-` or `.` — so\n * `Corner Shop` becomes `corner-shop`, and a name that starts with a digit gets a\n * leading `app`.\n */\nexport function schemeBase(project: string, given?: string): string {\n\tconst raw = (given ?? project)\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9+.-]+/g, '-')\n\t\t.replace(/^-+|-+$/g, '');\n\tif (!raw) return 'app';\n\treturn /^[a-z]/.test(raw) ? raw : `app${raw}`;\n}\n\n/** Where an Expo development server runs, for the `exp://` origins it sends. */\nexport interface MetroHost {\n\t/** The hosts a device reaches it on: the LAN address, `localhost`. */\n\thosts: readonly string[];\n\t/** Metro's port, when the target placed it — otherwise any port. */\n\tport?: number;\n}\n\n/**\n * The origins a surface trusts for a mobile caller.\n *\n * Better Auth's Expo plugin sends the app's scheme as its origin\n * (`shop://`), and a link can carry a path after it (`shop://*`).\n * In development, Expo Go sends `exp://<host>:<port>` instead — so a local\n * stage adds the hosts a device actually reaches Metro on, and Metro's port\n * when the target placed it: a whole subnet is not trusted because one phone\n * is on it.\n */\nexport function mobileOrigins(scheme: string, metro?: MetroHost): string[] {\n\treturn [\n\t\t`${scheme}://`,\n\t\t`${scheme}://*`,\n\t\t...(metro?.hosts ?? []).flatMap((host) => [\n\t\t\t`exp://${host}:${metro?.port ?? '*'}`,\n\t\t\t`exp://${host}:${metro?.port ?? '*'}/**`,\n\t\t]),\n\t];\n}\n\n/** Whether an origin is a web one — what a cookie domain is derived from. */\nexport function isWebOrigin(origin: string): boolean {\n\treturn origin.startsWith('http://') || origin.startsWith('https://');\n}\n"],"x_google_ignoreList":[2],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6LA,MAAa,2BAA4C;;;;;;;AAsiBzD,MAAa,iBAAiB;CAC7B;CACA;CACA;CACA;CACA;AACD;;;;;;;;;AAmDA,MAAa,eAAiE;CAC7E,mBAAmB,CAAC,YAAY,iBAAiB;CACjD,mBAAmB,CAAC,UAAU;CAI9B,eAAe,CAAC,SAAS;CAIzB,OAAO,CAAC,YAAY,iBAAiB;AACtC;;;;;;;;AA2LA,MAAa,SAET;CACH,SAAS,CAAC;CAIV,eAAe,CAAC,KAAK;CAKrB,OAAO,CAAC,UAAU;CAElB,UAAU,CAAC;CACX,mBAAmB,CAAC;CACpB,mBAAmB,CAAC;CAGpB,OAAO,CAAC;CAER,QAAQ,CAAC;CAGT,YAAY,CAAC;CAEb,YAAY,CAAC;CAKb,YAAY,CAAC,KAAK;CAGlB,OAAO,CAAC;CACR,OAAO,CAAC;CAIR,MAAM,CAAC,UAAU,UAAU;CAG3B,gBAAgB,CAAC;CAGjB,UAAU,CAAC;CACX,MAAM,CAAC;CAEP,cAAc,CAAC;CAGf,MAAM,CAAC,KAAK;CAGZ,QAAQ,CAAC;CAIT,WAAW,CAAC;AACb;;;;;;;;;;;ACphCA,IAAa,qBAAb,cAAwC,MAAM;;CAE7C;;CAEA;CAEA,YAAY,OAAe,WAAmB;EAC7C,MACC,6EACD;EACA,KAAK,OAAO;EACZ,KAAK,QAAQ;EACb,KAAK,YAAY;CAClB;AACD;;AAGA,IAAa,gBAAb,cAAmC,MAAM;;CAExC;;CAEA;;CAEA;CAEA,YAAY,IAAY,IAAY,WAA8B;EACjE,MAAM,gEAAgE;EACtE,KAAK,OAAO;EACZ,KAAK,KAAK;EACV,KAAK,KAAK;EACV,KAAK,YAAY;CAClB;AACD;;;;;AAMA,IAAa,oBAAb,cAAuC,MAAM;CAC5C;CACA;;CAEA;;CAEA;CAEA,YACC,IACA,MACA,YACA,SACC;EACD,MAAM,+DAA+D;EACrE,KAAK,OAAO;EACZ,KAAK,KAAK;EACV,KAAK,OAAO;EACZ,KAAK,aAAa;EAClB,KAAK,UAAU;CAChB;AACD;;;;;CCvDA,IAAI,YAAY;;CAGhB,IAAI,cAAc;;CAGlB,IAAI,UAAU;;CAGd,IAAI,gBAAgB;CAChB,IAAA,oBAAoB;CACpB,IAAA,sBAAsB;CACtB,IAAA,iBAAiB;CACjB,IAAA,eAAe;CACf,IAAA,gBAAgB;CAChB,IAAA,iBAAiB;CACjB,IAAA,qBAAqB;CACrB,IAAA,eAAe;CACf,IAAA,eAAe;CACf,IAAA,aAAa;CACb,IAAA,eAAe,gBAAgB,iBAAiB,qBAAqB;;CAGzE,IAAI,SAAS;CACT,IAAA,UAAU,MAAM,eAAe;CAC/B,IAAA,UAAU,MAAM,oBAAoB,sBAAsB;CAC1D,IAAA,WAAW;CACX,IAAA,YAAY,MAAM,iBAAiB;CACnC,IAAA,UAAU,MAAM,eAAe;CAC/B,IAAA,SAAS,OAAO,gBAAgB,eAAe,WAAW,iBAAiB,eAAe,eAAe;CAEzG,IAAA,aAAa,QAAQ,UAAU;CAC/B,IAAA,cAAc,OAAO,gBAAgB;CACrC,IAAA,aAAa;CACb,IAAA,aAAa;CACb,IAAA,UAAU,MAAM,eAAe;CAC/B,IAAA,QAAQ;;CAGZ,IAAI,cAAc,QAAQ,UAAU,MAAM,SAAS;CAC/C,IAAA,cAAc,QAAQ,UAAU,MAAM,SAAS;CAC/C,IAAA,kBAAkB,QAAQ,SAAS;CACnC,IAAA,kBAAkB,QAAQ,SAAS;CACnC,IAAA,WAAW,aAAa;CACxB,IAAA,WAAW,MAAM,aAAa;CAC9B,IAAA,YAAY,QAAQ,QAAQ,QAAQ;EAAC;EAAa;EAAY;CAAU,CAAC,CAAC,KAAK,GAAG,IAAI,MAAM,WAAW,WAAW;CAClH,IAAA,QAAQ,WAAW,WAAW;CAC9B,IAAA,UAAU,QAAQ;EAAC;EAAW;EAAY;CAAU,CAAC,CAAC,KAAK,GAAG,IAAI,MAAM;;CAG5E,IAAI,SAAS,OAAO,QAAQ,GAAG;;;;;CAM/B,IAAI,cAAc,OAAO,SAAS,GAAG;;CAGrC,IAAI,gBAAgB,OAAO;EACzB,UAAU,MAAM,UAAU,MAAM,kBAAkB,QAAQ;GAAC;GAAS;GAAS;EAAG,CAAC,CAAC,KAAK,GAAG,IAAI;EAC9F,cAAc,MAAM,kBAAkB,QAAQ;GAAC;GAAS,UAAU;GAAa;EAAG,CAAC,CAAC,KAAK,GAAG,IAAI;EAChG,UAAU,MAAM,cAAc,MAAM;EACpC,UAAU,MAAM;EAChB;EACA;CACF,CAAC,CAAC,KAAK,GAAG,GAAG,GAAG;;CAGhB,IAAI,mBAAmB;;CAGvB,IAAI,kBAAkB;EAEpB,KAAQ;EAAM,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAC1E,KAAQ;EAAM,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAC1E,KAAQ;EAAM,KAAQ;EACtB,KAAQ;EAAM,KAAQ;EACtB,KAAQ;EAAM,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAChD,KAAQ;EAAM,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAChD,KAAQ;EAAM,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAChD,KAAQ;EAAM,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAChD,KAAQ;EAAM,KAAQ;EACtB,KAAQ;EAAM,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAC1E,KAAQ;EAAM,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAC1E,KAAQ;EAAM,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAChD,KAAQ;EAAM,KAAQ;EAAK,KAAQ;EAAK,KAAQ;EAChD,KAAQ;EAAM,KAAQ;EAAK,KAAQ;EACnC,KAAQ;EAAM,KAAQ;EACtB,KAAQ;EAAM,KAAQ;EACtB,KAAQ;EAER,KAAU;EAAM,KAAU;EAAK,KAAU;EACzC,KAAU;EAAM,KAAU;EAAK,KAAU;EACzC,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EACxD,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EACxD,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EACxD,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EAAK,KAAU;EACvE,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EAAK,KAAU;EACvE,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EACxD,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EACxD,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EACxD,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EAAK,KAAU;EACvE,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EAAK,KAAU;EACvE,KAAU;EAAM,KAAU;EAC1B,KAAU;EAAM,KAAU;EAAK,KAAU;EACzC,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EAAK,KAAU;EACvE,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EAAK,KAAU;EACvE,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EACxD,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EACxD,KAAU;EAAM,KAAU;EAAK,KAAU;EACzC,KAAU;EAAM,KAAU;EAAK,KAAU;EACzC,KAAU;EAAM,KAAU;EAAK,KAAU;EACzC,KAAU;EAAM,KAAU;EAAK,KAAU;EACzC,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EACxD,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EACxD,KAAU;EAAM,KAAU;EAAK,KAAU;EACzC,KAAU;EAAM,KAAU;EAAK,KAAU;EACzC,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EAAK,KAAU;EAAK,KAAU;EACtF,KAAU;EAAM,KAAU;EAAK,KAAU;EAAK,KAAU;EAAK,KAAU;EAAK,KAAU;EACtF,KAAU;EAAM,KAAU;EAC1B,KAAU;EAAM,KAAU;EAAK,KAAU;EACzC,KAAU;EAAM,KAAU;EAAK,KAAU;EACzC,KAAU;EAAM,KAAU;EAAK,KAAU;EACzC,KAAU;EAAM,KAAU;EAC1B,KAAU;EAAM,KAAU;EAC1B,KAAU;EAAM,KAAU;CAC5B;;CAGA,IAAI,aAAa,OAAO,UAAU,YAAY,UAAU,OAAO,WAAW,UAAU;;CAGpF,IAAI,WAAW,OAAO,QAAQ,YAAY,QAAQ,KAAK,WAAW,UAAU;;CAG5E,IAAI,OAAO,cAAc,YAAY,SAAS,aAAa,CAAC,CAAC;;;;;;;;;;;;;CAc7D,SAAS,YAAY,OAAO,UAAU,aAAa,WAAW;EAC5D,IAAI,QAAQ,IACR,SAAS,QAAQ,MAAM,SAAS;EAEpC,IAAI,aAAa,QACf,cAAc,MAAM,EAAE;EAExB,OAAO,EAAE,QAAQ,QACf,cAAc,SAAS,aAAa,MAAM,QAAQ,OAAO,KAAK;EAEhE,OAAO;CACT;;;;;;;;CASA,SAAS,WAAW,QAAQ;EAC1B,OAAO,OAAO,MAAM,WAAW,KAAK,CAAC;CACvC;;;;;;;;CASA,SAAS,eAAe,QAAQ;EAC9B,OAAO,SAAS,KAAK;GACnB,OAAO,UAAU,OAAO,KAAA,IAAY,OAAO;EAC7C;CACF;;;;;;;;;CAUA,IAAI,eAAe,eAAe,eAAe;;;;;;;;CASjD,SAAS,eAAe,QAAQ;EAC9B,OAAO,iBAAiB,KAAK,MAAM;CACrC;;;;;;;;CASA,SAAS,aAAa,QAAQ;EAC5B,OAAO,OAAO,MAAM,aAAa,KAAK,CAAC;CACzC;;;;;;CAUA,IAAI,iBAPc,OAAO,UAOQ;;CAGjC,IAAI,SAAS,KAAK;;CAGlB,IAAI,cAAc,SAAS,OAAO,YAAY,KAAA;CAC1C,IAAA,iBAAiB,cAAc,YAAY,WAAW,KAAA;;;;;;;;;CAU1D,SAAS,aAAa,OAAO;EAE3B,IAAI,OAAO,SAAS,UAClB,OAAO;EAET,IAAI,SAAS,KAAK,GAChB,OAAO,iBAAiB,eAAe,KAAK,KAAK,IAAI;EAEvD,IAAI,SAAU,QAAQ;EACtB,OAAQ,UAAU,OAAQ,IAAI,SAAU,YAAa,OAAO;CAC9D;;;;;;;;CASA,SAAS,iBAAiB,UAAU;EAClC,OAAO,SAAS,QAAQ;GACtB,OAAO,YAAY,MAAM,OAAO,MAAM,CAAC,CAAC,QAAQ,QAAQ,EAAE,CAAC,GAAG,UAAU,EAAE;EAC5E;CACF;;;;;;;;;;;;;;;;;;;;;;;;;CA0BA,SAAS,aAAa,OAAO;EAC3B,OAAO,CAAC,CAAC,SAAS,OAAO,SAAS;CACpC;;;;;;;;;;;;;;;;;;CAmBA,SAAS,SAAS,OAAO;EACvB,OAAO,OAAO,SAAS,YACpB,aAAa,KAAK,KAAK,eAAe,KAAK,KAAK,KAAK;CAC1D;;;;;;;;;;;;;;;;;;;;;;CAuBA,SAAS,SAAS,OAAO;EACvB,OAAO,SAAS,OAAO,KAAK,aAAa,KAAK;CAChD;;;;;;;;;;;;;;;;;;;CAoBA,SAAS,OAAO,QAAQ;EACtB,SAAS,SAAS,MAAM;EACxB,OAAO,UAAU,OAAO,QAAQ,SAAS,YAAY,CAAC,CAAC,QAAQ,aAAa,EAAE;CAChF;;;;;;;;;;;;;;;;;;;;;;CAuBA,IAAI,YAAY,iBAAiB,SAAS,QAAQ,MAAM,OAAO;EAC7D,OAAO,UAAU,QAAQ,MAAM,MAAM,KAAK,YAAY;CACxD,CAAC;;;;;;;;;;;;;;;;;;;;CAqBD,SAAS,MAAM,QAAQ,SAAS,OAAO;EACrC,SAAS,SAAS,MAAM;EACxB,UAAU,QAAQ,KAAA,IAAY;EAE9B,IAAI,YAAY,KAAA,GACd,OAAO,eAAe,MAAM,IAAI,aAAa,MAAM,IAAI,WAAW,MAAM;EAE1E,OAAO,OAAO,MAAM,OAAO,KAAK,CAAC;CACnC;CAEA,OAAO,UAAU;;;;;;;;;;;;ACzZjB,SAAgB,gBAAgB,MAAsB;CACrD,QAAA,GAAOA,wBAAAA,QAAAA,CAAU,IAAI,CAAC,CACpB,YAAY,CAAC,CACb,QAAQ,UAAU,MAAM,EAAE,QAAQ,KAAK,EAAE,CAAC;AAC7C;;;;;;;AAQA,SAAgB,WAAW,IAAY,MAAsB;CAC5D,OAAO,gBAAgB,GAAG,GAAG,GAAG,MAAM;AACvC;;;;;;;;;;;;;;AAeA,SAAgB,YAAY,OAAuB;CAGlD,MAAM,MAAA,GAAKA,wBAAAA,QAAAA,CAAU,KAAK,CAAC,CACzB,MAAM,GAAG,CAAC,CACV,OAAO,OAAO,CAAC,CACf,KAAK,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAC3D,KAAK,EAAE;CAET,IAAI,CAAC,SAAS,KAAK,EAAE,GAAG,MAAM,IAAI,mBAAmB,OAAO,EAAE;CAC9D,OAAO;AACR;;;;;;;;AASA,MAAM,WAAW;;;;;;;;;;AAWjB,SAAgB,WAAW,IAAoB;CAC9C,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,GAAG,MAAM,CAAC;AAC/C;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,WAAW,IAAoB;CAC9C,OAAO,SAAS,GAAG,QAAQ,sBAAsB,OAAO,CAAC,CAAC,YAAY;AACvE;;;;;;;;;;;;;;;AAgBA,SAAgB,UAAU,OAAuB;CAChD,OAAO,MACL,QAAQ,yBAAyB,OAAO,CAAC,CACzC,QAAQ,sBAAsB,OAAO,CAAC,CACtC,QAAQ,WAAW,GAAG,CAAC,CACvB,YAAY;AACf;;;;;;;;;;;;;;;;;AAkBA,SAAgB,UACf,OACA,IACS;CACT,OAAO,WAAW,CAAC,MAAM,OAAO,MAAM,GAAG,GAAG,EAAE;AAC/C;;;;;;;AAQA,SAAgB,WAAW,OAA0B,IAAoB;CACxE,MAAM,SAAS,MAAM,KAAK,GAAG,CAAC,CAAC,YAAY;CAC3C,MAAM,OAAO,UAAU,EAAE;CAEzB,OAAO,KAAK,WAAW,MAAM,IAAI,OAAO,GAAG,OAAO,GAAG;AACtD;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,aAAa,MAA6C;CACzE,MAAM,wBAAQ,IAAI,IAAY;CAE9B,KAAK,MAAM,OAAO,MACjB,IAAI;EACH,MAAM,EAAE,aAAa,IAAI,IAAI,GAAG;EAEhC,IAAI,kBAAkB,KAAK,QAAQ,KAAK,SAAS,SAAS,GAAG,GAAG;EAChE,MAAM,IAAI,SAAS,YAAY,CAAC;CACjC,QAAQ;EAGP;CACD;CAGD,IAAI,MAAM,SAAS,GAAG;CAEtB,IAAI,MAAM,SAAS,GAAG;CAEtB,MAAM,CAAC,QAAQ,CAAC,GAAG,GAAG,QAAQ,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,SAC7C,KAAK,MAAM,GAAG,CAAC,CAAC,QAAQ,CACzB;CACA,MAAM,SAAmB,CAAC;CAE1B,KAAK,MAAM,CAAC,OAAO,UAAU,MAAM,QAAQ,GAAG;EAC7C,IAAI,CAAC,KAAK,OAAO,WAAW,OAAO,WAAW,KAAK,GAAG;EACtD,OAAO,KAAK,KAAK;CAClB;CAGA,IAAI,OAAO,SAAS,GAAG;CAEvB,OAAO,IAAI,OAAO,QAAQ,CAAC,CAAC,KAAK,GAAG;AACrC;;;;;;;;;;;;;;AAeA,SAAgB,eACf,IACA,MACA,MACS;CACT,IAAI,SAAS,UAAU,OAAO,gBAAgB,EAAE;CAGhD,IAAI,SAAS,aAAa,OAAO;CACjC,OAAO,WAAW,IAAI,IAAI;AAC3B;;;;AClOA,SAAgB,UACf,aAC0D;CAK1D,OACC,YAAY,QAAQ,gBACpB,QAAQ,eACR,OAAO,YAAY,OAAO;AAE5B;;;;;;;;AASA,SAAgB,kBAAkB,UAAmC;CACpE,KAAK,MAAM,CAAC,IAAI,gBAAgB,OAAO,QAAQ,QAAQ,GAAG;EACzD,IAAI,CAAC,UAAU,WAAW,GAAG;EAE7B,MAAM,SAAS,SAAS,YAAY;EACpC,IAAI,CAAC,QACJ,MAAM,IAAI,cAAc,IAAI,YAAY,IAAI,OAAO,KAAK,QAAQ,CAAC;EAGlE,MAAM,UAAU,aAAa,YAAY;EACzC,IAAI,CAAC,QAAQ,SAAS,OAAO,IAAI,GAChC,MAAM,IAAI,kBAAkB,IAAI,YAAY,MAAM,OAAO,MAAM,OAAO;CAExE;AACD;;;;;;;;;;;;;AAcA,SAAgB,eAAe,UAAuC;CACrE,MAAM,UAAoB,CAAC;CAC3B,MAAM,yBAAS,IAAI,IAAY;CAE/B,MAAM,SAAS,OAAqB;EACnC,IAAI,OAAO,IAAI,EAAE,GAAG;EACpB,MAAM,cAAc,SAAS;EAC7B,IAAI,CAAC,aAAa;EAIlB,OAAO,IAAI,EAAE;EACb,IAAI,UAAU,WAAW,GAAG,MAAM,YAAY,EAAE;EAChD,QAAQ,KAAK,EAAE;CAChB;CAEA,KAAK,MAAM,MAAM,OAAO,KAAK,QAAQ,GAAG,MAAM,EAAE;CAEhD,OAAO;AACR;;;;;;;;;;AAWA,SAAgB,eACf,aACwB;CACxB,MAAM,MACL,kBAAkB,cAAe,YAAY,gBAAgB,CAAC,IAAK,CAAC;CAKrE,MAAM,QAAQ,WAAW,cAAe,YAAY,SAAS,CAAC,IAAK,CAAC;CAEpE,MAAM,SACL,YAAY,SAAS,aAClB,YAAY,UAAU,SAAS,aAAa,SAAS,YAAY,IACjE,CAAC;CAIL,MAAM,YACL,eAAe,eAAe,OAAO,YAAY,cAAc,WAC5D,CAAC;EAAE,QAAQ,YAAY;EAAW,MAAM;CAAqB,CAAC,IAC9D,CAAC;CAEL,OAAO;EAAC,GAAG;EAAK,GAAG;EAAO,GAAG;EAAQ,GAAG;CAAS;AAClD;;;;;;;;;;;;;;AAeA,SAAgB,aACf,UACA,IACW;CACX,MAAM,UAAoB,CAAC;CAE3B,KAAK,MAAM,CAAC,UAAU,gBAAgB,OAAO,QAAQ,QAAQ,GAAG;EAC/D,IAAI,aAAa,IAAI;EACrB,IAAI,eAAe,WAAW,CAAC,CAAC,MAAM,SAAS,KAAK,WAAW,EAAE,GAChE,QAAQ,KAAK,QAAQ;CAEvB;CAEA,OAAO,QAAQ,KAAK;AACrB;;;;;;;;AASA,MAAa,gBAGT;CACH,QAAQ;CACR,UAAU;CACV,MAAM;CACN,MAAM;AACP;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,aACf,aACA,UACyB;CACzB,MAAM,SAAS,cAAc,YAAY;CACzC,MAAM,OAA+B,CAAC;CAEtC,KAAK,MAAM,QAAQ,YAAY,cAAc;EAC5C,MAAM,SAAS,SAAS,KAAK;EAC7B,IAAI,CAAC,QAAQ;EAEb,KAAK,MAAM,QAAQ,OAAO,OAAO,SAAS,CAAC,GAAG;GAC7C,MAAM,MAAM,WAAW,KAAK,QAAQ,IAAc;GAClD,KAAK,GAAG,SAAS,SAAS;EAC3B;CACD;CAEA,OAAO;AACR;;;;;;;;;;AC7MA,MAAa,aAAa;;;;;;;AAQ1B,SAAgB,OAAO,OAKZ;CACV,MAAM,QAAQ,IAAI,gBAAgB;EACjC,KAAK,MAAM;EACX,OAAO,MAAM;EACb,GAAI,MAAM,WAAW,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;CACtD,CAAC;CACD,OAAO,GAAG,WAAW,IAAI,MAAM,OAAO,GAAG;AAC1C;;;;ACzBA,MAAa,oBAAoB;;;;;;;;;;AAWjC,SAAgB,eACf,aACA,OACS;CACT,MAAM,EAAE,QAAQ;CAChB,IAAI,OAAO,QAAQ,UAAU,OAAO;CAEpC,MAAM,WAAW,IAAI,UAAU,IAAA;CAC/B,IAAI,CAAC,UACJ,MAAM,IAAI,cAAc,YAAY,IAAI,OAAO,OAAO,KAAK,GAAG,CAAC;CAGhE,OAAO;AACR;;AAGA,IAAa,gBAAb,cAAmC,MAAM;CAE9B;CACA;CACA;CAHV,YACC,IACA,OACA,QACC;EACD,MACC,IAAI,GAAG,8BAA8B,MAAM,mBACvC,OAAO,SAAS,OAAO,KAAK,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,YAAY,SAChE,MAAM,WAAW,kBAAkB,8BAC7C;EARS,KAAA,KAAA;EACA,KAAA,QAAA;EACA,KAAA,SAAA;EAOT,KAAK,OAAO;CACb;AACD;;;;AC5BA,MAAa,kBAAkB;;AAG/B,MAAa,mBAAmB,CAAC,cAAc,OAAO;;;;;;;;;AAwBtD,SAAgB,iBACf,UACoB;CACpB,OAAO,eAAe,QAAQ,CAAC,CAAC,SAAS,OAAO;EAC/C,MAAM,cAAc,SAAS;EAC7B,IAAI,CAAC,aAAa,OAAO,CAAC;EAE1B,IAAI,YAAY,SAAS,YAAY,OAAO,CAAC,OAAO,EAAE,CAAC;EACvD,IAAI,YAAY,SAAS,mBACxB,OAAO,CAAC;GAAE,GAAG,OAAO,EAAE;GAAG,IAAI,YAAY;EAAG,CAAC;EAG9C,OAAO,CAAC;CACT,CAAC;AACF;;;;;;;;;;AAWA,SAAgB,eAAe,IAAyB;CACvD,OAAO,MAAsB,UAAU,EAAE;AAC1C;;AAGA,SAAgB,gBAAgB,IAAyB;CACxD,OAAO,GAAG,eAAe,EAAE,EAAE;AAC9B;;;;;;;;AASA,SAAgB,WAAW,IAAyB;CACnD,OAAO,GAAG,eAAe,EAAE,EAAE;AAC9B;AAEA,SAAS,OAAO,IAAkC;CACjD,OAAO;EACN;EACA,QAAQ,eAAe,EAAE;EACzB,YAAY,gBAAgB,EAAE;EAC9B,OAAO,WAAW,EAAE;CACrB;AACD;;;;;;;;;;;;;;;;;;;;;;;ACzEA,SAAgB,WAAW,SAAiB,OAAwB;CACnE,MAAM,OAAO,SAAS,QAAA,CACpB,YAAY,CAAC,CACb,QAAQ,kBAAkB,GAAG,CAAC,CAC9B,QAAQ,YAAY,EAAE;CACxB,IAAI,CAAC,KAAK,OAAO;CACjB,OAAO,SAAS,KAAK,GAAG,IAAI,MAAM,MAAM;AACzC;;;;;;;;;;;AAoBA,SAAgB,cAAc,QAAgB,OAA6B;CAC1E,OAAO;EACN,GAAG,OAAO;EACV,GAAG,OAAO;EACV,IAAI,OAAO,SAAS,CAAC,EAAA,CAAG,SAAS,SAAS,CACzC,SAAS,KAAK,GAAG,OAAO,QAAQ,OAChC,SAAS,KAAK,GAAG,OAAO,QAAQ,IAAI,IACrC,CAAC;CACF;AACD;;AAGA,SAAgB,YAAY,QAAyB;CACpD,OAAO,OAAO,WAAW,SAAS,KAAK,OAAO,WAAW,UAAU;AACpE"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["snakecase"],"sources":["../src/declaration.ts","../src/errors.ts","../../../node_modules/.pnpm/lodash.snakecase@4.1.1/node_modules/lodash.snakecase/index.js","../src/naming.ts","../src/derive.ts","../src/encryption.ts","../src/external.ts","../src/headers.ts","../src/migrations.ts","../src/mobile.ts"],"sourcesContent":["/**\n * The construct manifest — the contract between what an application declares\n * and what a target adapter provisions.\n *\n * Kinds are added here as each one lands, not up front: a declaration for a\n * construct nobody has built yet is a guess that the implementation will\n * contradict. See `docs/design/constructs-paradigm.md`.\n */\n\n/**\n * A construct's canonical id — PascalCase, unique within the manifest.\n *\n * Inputs canonicalise, so `uploads`, `Uploads`, `user_uploads`, and\n * `user-uploads` are the *same* id rather than four that collide. Everything\n * else derives from it: the service key is its `Uncapitalize`, the env prefix\n * its SCREAMING_SNAKE form, the cloud name its kebab form scoped by stage and\n * app.\n */\nexport type ConstructId = string;\n\ntype Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';\n\n/**\n * Constrains a construct name at the point it is written.\n *\n * Resolves to the name itself when valid, and otherwise to a string explaining\n * why — so the compiler reports *\"not assignable to type 'a construct name\n * cannot start with a digit'\"* rather than the unhelpful `never`.\n *\n * Only the cases a template-literal type can see are caught here; `canonicalId`\n * enforces the rest at runtime, which is also what covers JavaScript callers.\n *\n * @example new ObjectStorage('Uploads') // ok\n * @example new ObjectStorage('2fa') // a construct name cannot start with a digit\n */\nexport type ConstructName<S extends string> = S extends ''\n\t? 'a construct name cannot be empty'\n\t: S extends `${Digit}${string}`\n\t\t? 'a construct name cannot start with a digit'\n\t\t: S;\n\n/** Shared by every declaration. */\nexport interface Node {\n\tid: ConstructId;\n\t/**\n\t * Env keys this construct resolves onto anything that depends on it.\n\t * Names only — the values are composed by the adapter from the provisioned\n\t * resource's own attributes.\n\t */\n\tprovides?: readonly string[];\n\t/**\n\t * Env keys this construct needs. Derivable from `dependencies`, so it is an\n\t * assertion rather than an input: the adapter composes env from the edges and\n\t * checks the result against this, which catches app/infra drift at synth.\n\t */\n\trequires?: readonly string[];\n}\n\n/**\n * A dependency edge. Records only *what* is depended on — never permissions.\n * From one edge the framework derives env and the runtime binding; a target\n * adapter separately derives cloud access.\n */\nexport interface Dependency<TTarget extends ConstructId = ConstructId> {\n\t/**\n\t * The {@link ConstructId} of the consumed construct. Left open here because a\n\t * declaration is written before the manifest that contains it; once assembled,\n\t * `IdsOf` narrows it and the build's reference-integrity check enforces it.\n\t */\n\ttarget: TTarget;\n\tkind: DeclarationKind;\n}\n\n/** Anything with a handler. */\nexport interface Fn extends Node {\n\thandler: string;\n\tdependencies: readonly Dependency[];\n}\n\n// ---------------------------------------------------------------------------\n// Kinds\n// ---------------------------------------------------------------------------\n\n/** Blob storage. `--target=aws` provisions a bucket. */\nexport interface ObjectsDeclaration extends Node {\n\tkind: 'objects';\n\tversioned?: boolean;\n}\n\n/**\n * A domain that serves a bucket's objects.\n *\n * Its own construct rather than a flag on the bucket, because three things it\n * has to express are not properties of a bucket: a surface can front several\n * origins, a bucket can have several surfaces over it, and issuing a\n * certificate and writing a DNS record is a domain lifecycle that has no\n * business living inside an `objects` provisioner. It shares its infrastructure\n * with a static site rather than with storage — a site is the same\n * distribution over a build output instead of over live contents.\n *\n * It derives from the bucket by `of`, which costs the one thing the flag gave\n * for free: the bucket alone no longer says whether it is served, and finding\n * out means finding whoever points at it. That is answered the way every other\n * derivation is — the reference check at manifest build, so an unresolvable\n * origin is a build failure and `gkm` can name, for any bucket, the surfaces\n * over it.\n *\n * Private by default. `open` is an exception list, because a bucket where\n * forgetting a flag publishes user uploads is the wrong default — and paths\n * rather than per-object flags, because a path pattern is what the\n * infrastructure actually enforces and a per-object ACL is a thing nobody\n * audits.\n *\n * \"Open\" never means the bucket is world-readable. It means the server serves\n * that path without a signature; the bucket is private in both cases.\n */\nexport interface FileServerDeclaration extends Node {\n\tkind: 'file-server';\n\t/** The bucket whose objects it serves. */\n\tof: ConstructId;\n\t/**\n\t * Paths served without a signature — everything else requires one.\n\t *\n\t * Globs, matched most-literally by the infrastructure: a CDN keys its\n\t * behaviours off path patterns, and a bucket policy names prefixes.\n\t */\n\topen?: readonly string[];\n}\n\n/**\n * Outbound email.\n *\n * Provides one `smtp://` URL and nothing else, because email is delivered over\n * SMTP whatever the provider — Mailpit locally, SES through its SMTP interface,\n * Resend and Postmark through theirs. There is no `provider` field here for the\n * same reason there is no `ses://` scheme: which service delivers the mail\n * differs between dev and prod, so by this design's own test it is stage-varying\n * config rather than a structural fact about the app.\n *\n * What *is* structural is only that the app sends mail at all. The sending\n * domain is not: it is `myapp.test` locally and `example.com` deployed, so it\n * fails the same test the provider does and resolves at deploy alongside every\n * other address.\n */\nexport interface EmailDeclaration extends Node {\n\tkind: 'email';\n}\n\n/**\n * A logical database, its schema, and the roles that reach it.\n *\n * Provides one key — the *runtime* role's URL. The owner URL exists but is\n * deliberately absent from `provides`: it is wired by the adapter straight into\n * the migrator and seeder this construct declares, so no edge in any manifest\n * can name it and nothing else can be granted it by mistake.\n */\n/**\n * The Postgres major versions this toolbox provisions.\n *\n * A union rather than a string, because the two targets that read it are not\n * equally forgiving: locally it becomes a container tag, where a typo yields a\n * confusing pull failure, and on AWS it becomes an engine version, where a\n * wrong value fails partway through a deploy. Both are better as a compile\n * error.\n *\n * The union is what this toolbox knows how to name, not a promise that every\n * target offers every one of them. A deployed stage is limited by the engine\n * catalogue in its region, so check before pinning an unusual version:\n *\n * ```\n * aws rds describe-db-engine-versions --engine postgres \\\n * --query 'DBEngineVersions[].EngineVersion' --output text\n * ```\n *\n * RDS offered 11 through 18 in `eu-west-1` when this was written. 11 and 12 are\n * left out because they are past upstream end-of-life: still provisionable, but\n * not something to make easy to reach for.\n */\nexport type PostgresVersion = 13 | 14 | 15 | 16 | 17 | 18;\n\n/**\n * The version used when a database names none.\n *\n * The point is not which number this is but that there is only one of them.\n * Local ran 18 while Aurora provisioned its own default of 17.7, and nothing in\n * any declaration recorded the difference — a stage could behave differently\n * from a developer's machine for a reason neither could see. Both now read\n * this.\n */\nexport const DEFAULT_POSTGRES_VERSION: PostgresVersion = 18;\n\nexport interface DatabaseDeclaration extends Node {\n\tkind: 'database';\n\tengine?: 'postgres';\n\t/**\n\t * The engine's major version, read by every target that provisions one.\n\t *\n\t * Declared rather than configured per target, because a version set in a\n\t * compose file and a version set in a deploy config are two statements of\n\t * one fact — and they had already drifted apart, silently, by a major.\n\t *\n\t * Defaults to {@link DEFAULT_POSTGRES_VERSION}.\n\t */\n\tversion?: PostgresVersion;\n\t/**\n\t * The schema, pinned on both roles' `search_path`. Names the role the schema\n\t * plays rather than restating the database's own name, so `app` reads\n\t * correctly beside `auth` and `pgboss`.\n\t */\n\tschema?: string;\n\t/**\n\t * Whether to provision the owner/runtime role split. Off falls back to the\n\t * cluster's master credential in both URLs — a deliberate downgrade, not a\n\t * default. See `roles: false` in the design doc.\n\t */\n\troles?: boolean;\n}\n\n/**\n * A read-only endpoint on an existing database or schema.\n *\n * Provisions no cluster of its own — `of` names the parent it reads from.\n * Read-only is enforced by the role's grants rather than by which endpoint it\n * resolves to, so falling back to the writer where no replica exists stays safe.\n */\nexport interface DatabaseReaderDeclaration extends Node {\n\tkind: 'database-reader';\n\tof: ConstructId;\n}\n\n/**\n * A second schema inside an existing database, with its own role(s) and URL.\n *\n * The mechanism behind tenancy: the parent's role holds no grant on these\n * tables at all. pg-boss is an instance of this rather than a special case.\n */\nexport interface DatabaseSchemaDeclaration extends Node {\n\tkind: 'database-schema';\n\tof: ConstructId;\n\tschema: string;\n}\n\n/**\n * A generated secret — a signing key, a token, anything with no address.\n *\n * It provides a value rather than a URL, which is why it is a node of its own\n * instead of a field on whatever needs it: the thing that generates it, the\n * thing that stores it, and the thing that reads it are three different systems\n * deployed, and one derived string locally.\n */\nexport interface SecretDeclaration extends Node {\n\tkind: 'secret';\n}\n\n/**\n * A third-party credential with a shape.\n *\n * Distinct from {@link SecretDeclaration} by *lifecycle*, which is the only\n * distinction worth having two kinds for. A secret is generated and rotated by\n * the platform — `gkm secrets`, `sst secret set` — and is one opaque string\n * whose name is its key. A credential is issued by someone else, arrives with\n * several fields, and is validated on the way in: a Stripe key pair, an OAuth\n * client, a webhook signing secret.\n *\n * It provides one key holding a JSON object, rather than one key per field.\n * That is what a secret manager actually stores, and it is also the only shape\n * that works with an arbitrary StandardSchema — the spec has no introspection\n * API, so enumerating a schema's fields means reaching into one library's\n * internals and being wrong for every other.\n */\nexport interface CredentialDeclaration extends Node {\n\tkind: 'credential';\n}\n\n/**\n * A key that encrypts what the application stores.\n *\n * It provides one URL, and the scheme picks the cipher the way a queue's\n * connection string picks its broker: a keyring the process holds\n * (`aes256gcm://`) locally and on a server, a KMS key (`kms://`) on AWS. The\n * value is the platform's to generate and the app never names a cipher.\n *\n * A node rather than a field on whatever encrypts, for the reason a secret is:\n * what holds the key, what grants access to it, and what uses it are three\n * systems deployed — and an edge to it is what grants a function the key.\n */\nexport interface EncryptionDeclaration extends Node {\n\tkind: 'encryption';\n}\n\n/**\n * An HTTP API somebody else runs — Polar, Stripe, a payment gateway.\n *\n * Provisions nothing, like {@link OidcDeclaration}: the API already exists. What\n * makes it a node rather than a URL somebody writes into `.env` is that its\n * address changes by stage — the real one deployed, a fake locally and in\n * tests — and switching it is the target's job, not each app's.\n *\n * The fake is not here, and that is deliberate: it lives in `test/fakes/<id>.ts`,\n * which only gkm reads, so nothing in a deployed bundle can reach it. Its\n * credentials are a second key holding JSON, issued per stage the way a\n * {@link CredentialDeclaration}'s are.\n */\nexport interface ExternalApiDeclaration extends Node {\n\tkind: 'external-api';\n\t/**\n\t * Where it answers deployed: one URL for every stage, or one per stage name,\n\t * with `default` for any stage not listed. A local or test stage never reads\n\t * this — it is handed the fake.\n\t */\n\turl: string | Readonly<Record<string, string>>;\n}\n\n/**\n * An identity provider somebody else runs.\n *\n * Provisions nothing — the issuer already exists — so a target's whole job is\n * to hand the process an issuer and an audience, and the verifier discovers the\n * rest at runtime.\n *\n * It is a node rather than a field on whatever authenticates through it because\n * two surfaces can name the same provider, and because *which* population a\n * surface admits is a fact worth reading off the graph: an admin console\n * authenticated by the customer auth server is a finding, and it is only\n * visible if both are declarations.\n */\nexport interface OidcDeclaration extends Node {\n\tkind: 'oidc';\n\t/**\n\t * The issuer, when it does not vary by deployment.\n\t *\n\t * Absent means it arrives in the environment instead — a staging tenant, a\n\t * per-customer directory. The audience is never here: it identifies one\n\t * deployment to the provider.\n\t */\n\tissuer?: string;\n}\n\n/**\n * A key/value cache.\n *\n * Provides one URL. What is *in* that URL is the backend's business — Upstash's\n * REST API, a Redis endpoint, or a table in a database — and the scheme is what\n * picks the client, exactly as it does for object storage.\n *\n * Two ways to declare one, and the difference is a real statement rather than a\n * spelling. `new Cache('Sessions')` says *this app caches*, leaving where to the\n * deployment; `orders.cache('Sessions')` says *this app caches in that\n * database*, which is a fact about the application and belongs in its code. The\n * second is the same strengthening `orders.schema('AuthDb')` is over declaring a\n * second database.\n */\nexport interface CacheDeclaration extends Node {\n\tkind: 'cache';\n\t/**\n\t * The database this cache lives in, when it lives in one.\n\t *\n\t * Present only for a cache derived from a database. It removes a guess the\n\t * backend selection otherwise has to make — \"the declared database\" is\n\t * unambiguous with one and arbitrary with two — and it means the table's\n\t * schema and the role that reaches it come from the parent rather than from\n\t * a second convention.\n\t */\n\tof?: ConstructId;\n\t/**\n\t * The table entries are kept in, resolved against the connection's\n\t * `search_path`. Defaults to `cache`.\n\t */\n\ttable?: string;\n}\n\n/**\n * An HTTP surface and the handlers mounted on it.\n *\n * The first kind that is not a resource in the ordinary sense: it owns an\n * address, and the functions it triggers are *nested inside it* rather than\n * listed beside it, because position carries the trigger — a handler here is\n * reached by its method and path and by nothing else.\n *\n * `authorizers` are names. A bare string is resolved by the target (`iam`), while\n * a {@link ConstructId} names a construct that carries its own implementation,\n * its database dependency, and its session typing.\n */\nexport interface RestApiDeclaration extends Node {\n\tkind: 'rest-api';\n\t/**\n\t * The label it answers on under a stage's domain — `api` for\n\t * `api.myapp.com`, from `deploy.domains` — and under the project locally,\n\t * `api.myapp.localhost`. Absent, its id kebab-cased.\n\t */\n\tsubdomain?: string;\n\t/**\n\t * The app that serves this surface, relative to the workspace root.\n\t *\n\t * Required, and the only thing about its process a surface says: its code\n\t * is found through the workspace's `constructs` glob, and ports are\n\t * assigned in a stable order. Nothing infers it from the id.\n\t */\n\tpath: string;\n\t/** Whether this surface streams into a Telescope. */\n\ttelescope?: true;\n\t/**\n\t * The construct that authenticates this surface.\n\t *\n\t * An edge like any other — so the auth server learns this surface's origin,\n\t * and the two share a cookie domain — but a *named* one, because \"who\n\t * authenticates me\" is a different fact from \"who I happen to call\", and\n\t * only one of them decides what a request is allowed to be.\n\t *\n\t * It is the id rather than the client: what every endpoint consumes is\n\t * `verify(request) → Session | null`, and that is the one thing every\n\t * provider shares. A surface names its authenticator; the target decides\n\t * what verifying means.\n\t */\n\tauth?: ConstructId;\n\t/**\n\t * CORS tunables for this surface.\n\t *\n\t * *Who* may call it is never here — that is derived from the constructs\n\t * declaring an edge to this surface, and arrives as `<ID>_TRUSTED_ORIGINS`.\n\t * A hand-written origin list is the thing this model removes; these are the\n\t * knobs that genuinely cannot be derived from a graph.\n\t *\n\t * Omitted entirely, a surface still gets CORS — with the derived origins and\n\t * sensible defaults. There is nothing to opt into.\n\t */\n\tcors?: {\n\t\t/** Preflight cache lifetime in seconds. Default 86400. */\n\t\tmaxAge?: number;\n\t\t/** Whether the browser may send credentials. Default true. */\n\t\tcredentials?: boolean;\n\t\t/** Extra request headers to allow, beyond content-type and authorization. */\n\t\tallowHeaders?: readonly string[];\n\t\t/** Response headers the browser may read. */\n\t\texposeHeaders?: readonly string[];\n\t};\n\tauthorizers?: readonly string[];\n\t/** The authorizer applied where an endpoint names none. */\n\tdefaultAuthorizer?: string;\n\t/**\n\t * Every route on this surface.\n\t *\n\t * Complete, always — a manifest that says \"the routes are over there, run\n\t * this glob to find them\" is not a manifest, it is a pointer to one. An\n\t * earlier version carried a `routes` glob for an application's own API and\n\t * left this empty, which meant the document *claimed no routes* while five\n\t * existed. Being incomplete is a gap; being wrong is worse.\n\t *\n\t * So a surface takes its endpoints as a list and reads method, path and\n\t * handler off them. That also removes a duplicate: the glob was written once\n\t * in `gkm.config.ts` and again on the construct, two strings that could\n\t * disagree about the same thing.\n\t */\n\tendpoints: readonly RestApiEndpoint[];\n\t/**\n\t * Other surfaces this one calls.\n\t *\n\t * **Not a dependency, and deliberately not spelled like one.** A dependency\n\t * is an injection: `resolveEdges` gives a function exactly the constructs it\n\t * declared and nothing else, which is what makes least privilege fall out of\n\t * the graph instead of out of discipline. A surface-level `dependencies`\n\t * would hand *every route* on this API whatever the surface named — which is\n\t * precisely the over-granting that rule exists to prevent.\n\t *\n\t * What this records is weaker and only flows one way: it puts this API's\n\t * origin on the called surface's trusted-origin list. Nothing links from it,\n\t * nothing is granted by it, and per-route edges stay on the endpoints where\n\t * they belong.\n\t */\n\tcalls?: readonly Dependency[];\n\t/**\n\t * The `Telemetry` node this surface's process emits through, by id — an\n\t * edge, read by `dependenciesOf` like any other.\n\t */\n\ttelemetry?: ConstructId;\n}\n\n/** One glob, or several. Mirrors the CLI's `Routes` without depending on it. */\nexport type Glob = string | readonly string[];\n\n/**\n * How the process serving a declaration is built and run.\n *\n * The half of an application that a graph genuinely cannot derive. *What*\n * exists — a surface, a site, the edges between them — is declared and read\n * back from the manifest. *Where its source lives and which globs find its\n * code* is not derivable from anything: it is a fact about a directory.\n *\n * It lives on the declaration rather than in a config `apps` block because the\n * two were the same list written twice, and the copy in config was the one that\n * could disagree. A site declared `path: 'apps/web'` and an app entry declared\n * `path: 'apps/web'`, and nothing checked them against each other; a surface\n * that config had no entry for simply never deployed.\n *\n * Only the declaration that *is* an app carries one. Two surfaces in one\n * process means one of them has the spec and the other collapses onto it —\n * which is the same rule that decides deploy units, now stated once.\n */\nexport interface AppSpec {\n\t/** Where its source lives, relative to the workspace root. */\n\tpath: string;\n\t/**\n\t * The port it answers on locally.\n\t *\n\t * Optional, and normally omitted: ports are assigned in a stable order so\n\t * that adding a site does not renumber the others.\n\t */\n\tport?: number;\n\ttelescope?: string | boolean | Record<string, unknown>;\n\tstudio?: string | boolean | Record<string, unknown>;\n\topenapi?: boolean | Record<string, unknown>;\n\truntime?: 'node' | 'bun';\n\t/** Env files to load, in order. */\n\tenv?: Glob;\n\t/** Entry module for an app the build does not generate. */\n\tentry?: string;\n\t/** Modules to import when sniffing which env vars a frontend reads. */\n\tconfig?: { client?: string; server?: string };\n}\n\n/**\n * A frontend — a construct like any other, which is what removes the last\n * mechanism that ran in parallel to the graph.\n *\n * Its edges are what make it worth declaring. A site depending on an API is the\n * single fact behind four things that are hand-maintained otherwise: the site's\n * build-time `VITE_API_URL`, the API's CORS origins, the auth server's trusted\n * origins, and which generated client lands in which app. None of those are\n * declared anywhere here, because all four are the *same* edge read from one\n * end or the other.\n *\n * `variant` is the framework, because the framework changes the code you write:\n * it selects how the values are delivered (`VITE_`, `NEXT_PUBLIC_`, a\n * `config.json`), never which values there are.\n */\nexport interface SiteDeclaration extends Node {\n\tkind: 'site';\n\tvariant: 'static' | 'next' | 'tanstack';\n\t/**\n\t * The label it answers on under a stage's domain — `api` for\n\t * `api.myapp.com`, from `deploy.domains` — and under the project locally,\n\t * `api.myapp.localhost`. Absent, its id kebab-cased.\n\t */\n\tsubdomain?: string;\n\t/**\n\t * How it is built and run, `path` included.\n\t *\n\t * Required: a site is always its own app, and says where it lives.\n\t */\n\tapp: AppSpec;\n\t/**\n\t * Whether this is the site the base domain points at.\n\t *\n\t * Structural rather than config: *which* site is primary does not vary by\n\t * stage, even though its hostname does — that is what `app.domain` is for.\n\t *\n\t * Only meaningful when a project has more than one site, and then only when\n\t * none of them is named `web`. The convention still holds first, because it\n\t * is a convention people already rely on.\n\t */\n\troot?: boolean;\n\t/**\n\t * What it calls. On a node rather than on a handler because a site has no\n\t * single entrypoint — the whole app is the consumer.\n\t */\n\tdependencies: readonly Dependency[];\n\t/**\n\t * The `Telemetry` node it emits through, by id. A site is handed none of\n\t * the node's keys: they are a server's, and `PUBLIC.telemetry` is empty, so\n\t * nothing of it can reach a bundle.\n\t */\n\ttelemetry?: ConstructId;\n}\n\n/**\n * A mobile app — Expo — declared like a site, for the same reason: its edges\n * are what make it worth declaring.\n *\n * It differs from a site in one way that matters. A browser is reached at an\n * origin; an app is reached through its URL *scheme*. So what a surface trusts\n * for it is `shop://`, not an address, and what it provides is that scheme —\n * the same on every stage.\n *\n * It ships through its own toolchain (EAS, the stores), so nothing deploys it:\n * it is an app the targets derive for, never one they run.\n */\nexport interface MobileAppDeclaration extends Node {\n\tkind: 'mobile-app';\n\t/** Which toolchain builds it. Expo is the one that ships. */\n\tvariant: 'expo';\n\t/** Where it lives — `path` included. */\n\tapp: AppSpec;\n\t/**\n\t * Its URL scheme: `shop`.\n\t *\n\t * Normally omitted, and then it is the project's name. The same on every\n\t * stage.\n\t */\n\tscheme?: string;\n\t/** What it calls — the surfaces whose URLs it is built with. */\n\tdependencies: readonly Dependency[];\n}\n\n/**\n * A process with no port.\n *\n * The sibling of `RestApiDeclaration`, and the answer to a question the model\n * could not previously state: *what runs this cron?* A cron, a subscriber and a\n * queue consumer all have to run somewhere, and until now the only thing that\n * said where was the directory the file happened to sit in — so a background\n * job was owned by a glob, and a project that was nothing but background jobs\n * had to declare an HTTP surface with no routes on it to be deployable at all.\n *\n * It takes no authorizer. A `RestApi` needs one because an HTTP surface can\n * ship open by omission; nothing calls a worker from outside, so there is no\n * default to get wrong. That difference is the reason these are two constructs\n * rather than one with a flag.\n */\nexport interface WorkerDeclaration extends Node {\n\tkind: 'worker';\n\t/**\n\t * A worker declares no app, because it is not one.\n\t *\n\t * It names the process that runs a cron, a subscriber or a queue consumer.\n\t * On a server target that process is a container of its own, built from the\n\t * app whose directory holds the work — so the worker needs no path to say\n\t * where its code is.\n\t */\n\t/** Surfaces and resources it calls, which is what grants it access. */\n\tdependencies?: readonly Dependency[];\n\t/** The `Telemetry` node its process emits through, by id. */\n\ttelemetry?: ConstructId;\n}\n\n/** One route on a surface. */\nexport interface RestApiEndpoint extends Fn {\n\tmethod: string;\n\tpath: string;\n\tauthorizer?: string;\n}\n\n/**\n * A point-to-point queue and the single consumer that drains it.\n *\n * Provides one key, the producer's connection string. The protocol in it picks\n * the transport — `pgboss://` locally, `sqs://` deployed — so a producer names\n * no broker, exactly as a database consumer names no cloud.\n *\n * The consumer side provides nothing: a worker is reached *through* its queue,\n * so there is no second key and nothing can depend on a handler.\n */\nexport interface QueueDeclaration extends Node {\n\tkind: 'queue';\n\t/** FIFO ordering, where the transport offers it. */\n\tfifo?: boolean;\n\t/**\n\t * The single consumer that drains it.\n\t *\n\t * Nested rather than listed beside the queue, because **position carries the\n\t * trigger**: a handler here is reached by messages arriving on this queue and\n\t * by nothing else, so there is no `trigger` field to keep in step with it.\n\t */\n\tworker: Fn;\n}\n\n/**\n * A topic — pub/sub fan-out, one publisher and any number of subscribers.\n *\n * Like a queue it provides only the producer's string; a subscriber is bound to\n * the topic rather than depending on it, so the binding is an edge the deploy\n * target reads, not an env key. Locally both sides meet on the same pg-boss\n * connection, which is why the subscriber needs no key of its own.\n */\nexport interface TopicDeclaration extends Node {\n\tkind: 'topic';\n\t/** The event type names this topic carries. */\n\tevents: readonly string[];\n\t/**\n\t * The handlers bound to it, each with the events it wants.\n\t *\n\t * Nested for the same reason a queue's worker is: position is the trigger. A\n\t * subscriber is *bound* to a topic rather than depending on it, which is why\n\t * it holds no key of its own and cannot be reached except through the topic.\n\t */\n\tsubscribers: readonly (Fn & { events: readonly string[] })[];\n}\n\n/**\n * A function invoked directly, with no surface in front of it.\n *\n * An `Fn` rather than a `Node`, because a function *is* a handler — there is no\n * resource beside it to declare. It provides its own address, so something else\n * can depend on it and be given a way to call it.\n */\nexport interface FunctionDeclaration extends Fn {\n\tkind: 'function';\n}\n\n/**\n * A function on a schedule.\n *\n * The schedule is the trigger and it is structural: *that* something runs\n * nightly is a fact about the application, while which timezone a stage\n * interprets it in is not.\n */\nexport interface CronDeclaration extends Fn {\n\tkind: 'cron';\n\t/** A rate or cron expression, e.g. `rate(1 day)`. */\n\tschedule: string;\n}\n\n/**\n * Every declaration. A discriminated union, so `kind` gives exhaustiveness *and*\n * per-kind fields — there is no separate enum to keep in step, and no shape\n * carrying fields that belong to a different kind.\n */\n/**\n * What an application emits — traces and logs over OTLP — and never where it\n * goes: the deploy picks the provider and the sample rate, per stage.\n *\n * A node like any other, so each process that uses it is an edge from its\n * surface, worker or site, and the keys it provides reach exactly those\n * processes. The keys are OpenTelemetry's own, not the node's id: an SDK reads\n * `OTEL_EXPORTER_OTLP_ENDPOINT` and nothing else.\n */\nexport interface TelemetryDeclaration extends Node {\n\tkind: 'telemetry';\n\t/** Request paths no span is recorded for — `/health`. A trailing `*` matches a prefix. */\n\tignorePaths?: readonly string[];\n\t/** Resource attributes every span and log carries — `service.namespace`. */\n\tattributes?: Readonly<Record<string, string>>;\n}\n\n/**\n * What a `Telemetry` node provides to each process with an edge to it.\n *\n * `OTEL_SERVICE_NAME` is resolved per process — the app's name — so it is\n * listed here but composed by whichever target hands it over.\n */\nexport const TELEMETRY_KEYS = [\n\t'OTEL_EXPORTER_OTLP_ENDPOINT',\n\t'OTEL_EXPORTER_OTLP_HEADERS',\n\t'OTEL_SERVICE_NAME',\n\t'OTEL_TRACES_SAMPLER',\n\t'OTEL_TRACES_SAMPLER_ARG',\n] as const;\n\nexport type TelemetryKey = (typeof TELEMETRY_KEYS)[number];\n\nexport type Declaration =\n\t| ObjectsDeclaration\n\t| FileServerDeclaration\n\t| EmailDeclaration\n\t| DatabaseDeclaration\n\t| DatabaseReaderDeclaration\n\t| DatabaseSchemaDeclaration\n\t| CacheDeclaration\n\t| SecretDeclaration\n\t| CredentialDeclaration\n\t| EncryptionDeclaration\n\t| RestApiDeclaration\n\t| SiteDeclaration\n\t| MobileAppDeclaration\n\t| WorkerDeclaration\n\t| OidcDeclaration\n\t| ExternalApiDeclaration\n\t| QueueDeclaration\n\t| TopicDeclaration\n\t| FunctionDeclaration\n\t| CronDeclaration\n\t| TelemetryDeclaration;\n\n/** A declaration that provisions nothing of its own and names a parent. */\n/**\n * A declaration that names a parent.\n *\n * A union rather than an `Extract`, because one kind is *optionally* derived: a\n * cache lives in a database when it was declared from one and stands alone\n * otherwise, so `of` is optional on it and an `Extract<…, { of: ConstructId }>`\n * would not select it. {@link isDerived} tests the value rather than the kind\n * for exactly that reason.\n */\nexport type DerivedDeclaration =\n\t| Extract<Declaration, { of: ConstructId }>\n\t| CacheDeclaration;\n\nexport type DerivedKind = DerivedDeclaration['kind'];\n\n/**\n * What each kind may derive from.\n *\n * Small enough to state exhaustively, and stating it makes cycles impossible\n * without a graph walk: readers are terminal, so no chain can return to its\n * start. There is no `writer` — the database *is* the writer, which is what\n * keeps a replica from being reached by accident.\n */\nexport const DERIVES_FROM: Readonly<Record<DerivedKind, readonly string[]>> = {\n\t'database-reader': ['database', 'database-schema'],\n\t'database-schema': ['database'],\n\t// A file server derives from what it serves. Unlike the database pair it\n\t// shares the parent's *contents* rather than its credentials, which is why\n\t// it is a construct of its own and only its node is derived.\n\t'file-server': ['objects'],\n\t// A cache in a database is a table in it, reached by the same role — so it\n\t// derives from either a database or a tenant of one, and a tenant's cache\n\t// lands in the tenant's schema without naming it.\n\tcache: ['database', 'database-schema'],\n};\n\nexport type DeclarationKind = Declaration['kind'];\n\n/**\n * The manifest: every construct keyed by its id.\n *\n * Flat rather than grouped, because `Dependency.target` resolves as\n * `m[target]` — a lookup that stays O(1) and identical whether the edge points\n * at a resource, a surface, or another function.\n *\n * Use it as a **constraint, not an annotation**. `gkm build` emits\n * `as const satisfies ConstructManifest`, which checks the shape while keeping\n * every id, kind, and provided key a literal — annotating with this type\n * instead would widen them all to `string` and consumers could no longer select\n * anything:\n *\n * ```ts\n * export const constructs = {\n * Uploads: { kind: 'objects', id: 'Uploads', provides: ['UPLOADS_URL'] },\n * } as const satisfies ConstructManifest;\n *\n * type Ids = IdsOf<typeof constructs>; // 'Uploads'\n * type Env = ProvidedKeys<typeof constructs, 'Uploads'>; // 'UPLOADS_URL'\n * ```\n */\nexport type ConstructManifest = Readonly<Record<ConstructId, Declaration>>;\n\n// ---------------------------------------------------------------------------\n// Selecting from a concrete manifest\n// ---------------------------------------------------------------------------\n\n/** Every id in a manifest. */\nexport type IdsOf<M extends ConstructManifest> = Extract<keyof M, string>;\n\n/** The declaration for one id. */\nexport type DeclarationOf<\n\tM extends ConstructManifest,\n\tK extends IdsOf<M>,\n> = M[K];\n\n/** Every id of a given kind — what an adapter iterates when provisioning. */\nexport type IdsOfKind<\n\tM extends ConstructManifest,\n\tK extends DeclarationKind,\n> = {\n\t[Id in IdsOf<M>]: M[Id]['kind'] extends K ? Id : never;\n}[IdsOf<M>];\n\n/** The env keys one construct provides. */\nexport type ProvidedKeys<\n\tM extends ConstructManifest,\n\tK extends IdsOf<M>,\n> = M[K] extends { provides: readonly (infer P)[] } ? P : never;\n\n/** Every env key any construct in the manifest provides. */\nexport type AllProvidedKeys<M extends ConstructManifest> = {\n\t[Id in IdsOf<M>]: ProvidedKeys<M, Id>;\n}[IdsOf<M>];\n\n// ---------------------------------------------------------------------------\n// The app ↔ infra contract\n// ---------------------------------------------------------------------------\n\n/**\n * What each kind provides, by role rather than by provider syntax.\n *\n * This is the contract between the construct that declares a key and the cloud\n * component that supplies its value — an interface rather than shared code,\n * because a shared codec would have to contain `bucket` and `region`, and\n * provider words in the neutral layer is the problem this design exists to fix.\n *\n * How a value is composed and parsed stays private to each provider pair, so\n * `s3://` and `gs://` never appear here.\n */\nexport interface ProvidesByKind {\n\tobjects: { url: string };\n\t/** Where the served objects answer. Public: a browser is the point of it. */\n\t'file-server': { url: string };\n\t/**\n\t * An `smtp://` URL, credentials included — never shippable — and the\n\t * identity mail is sent from.\n\t *\n\t * The sending address is the one thing about mail that genuinely differs per\n\t * stage (`myapp.test` locally, a verified domain deployed), so it travels\n\t * beside the URL rather than being written into the construct.\n\t */\n\temail: {\n\t\turl: string;\n\t\tfrom: string;\n\t\t/**\n\t\t * Where the mail it sent can be read — Mailpit's web inbox. Local\n\t\t * stages only: deployed mail has no inbox, so nothing deployed supplies\n\t\t * it, and an app that reads it falls back to the phone's own mail app.\n\t\t */\n\t\tinboxUrl?: string;\n\t};\n\t/**\n\t * One key, the runtime role's. The owner URL is not here by design — see\n\t * {@link DatabaseDeclaration}.\n\t */\n\tdatabase: { url: string };\n\t'database-reader': { url: string };\n\t'database-schema': { url: string };\n\t/** The endpoint and its token, in one string. */\n\tcache: { url: string };\n\t/**\n\t * Where the surface answers, who may call it, and the domain its cookies\n\t * are scoped to.\n\t *\n\t * Only `url` is a fact about the surface itself. The other two are read off\n\t * its *inbound* edges — every construct that depends on it — which is why a\n\t * surface never lists its own callers: nothing enumerates the things that\n\t * point at it, the graph already does.\n\t *\n\t * `trustedOrigins` and `cookieDomain` are one key each rather than a list\n\t * and a structure, because both cross a process boundary as environment.\n\t */\n\t'rest-api': {\n\t\turl: string;\n\t\t/** Comma-separated. Empty when nothing declares an edge to this surface. */\n\t\ttrustedOrigins: string;\n\t\t/**\n\t\t * The parent domain shared by the surface and its callers, leading dot\n\t\t * included — `.example.com`. Absent where there is nothing to share:\n\t\t * one host locally, unrelated hosts deployed.\n\t\t */\n\t\tcookieDomain: string;\n\t};\n\t/** The value itself. A secret has no address to hand out instead. */\n\tsecret: { value: string };\n\t/**\n\t * The credential as one JSON object, parsed and validated by the construct\n\t * that declared the schema.\n\t */\n\tcredential: { credentials: string };\n\t/** Where the key is: a keyring, or a KMS key and its HMAC key. */\n\tencryption: { url: string };\n\t/**\n\t * The producer's connection string. One key, not two: the consumer is\n\t * reached through the queue rather than by an address of its own.\n\t */\n\tqueue: { publisherConnectionString: string };\n\ttopic: { publisherConnectionString: string };\n\t/** Where to invoke it — what lets something else depend on a function. */\n\tfunction: { url: string };\n\t/** A cron is reached by its schedule and by nothing else, so it provides none. */\n\tcron: Record<never, never>;\n\t/** Where the site is served. Public for the same reason an API's is. */\n\tsite: { url: string };\n\t/**\n\t * The URL scheme it answers on — `shop`, on every stage. What its\n\t * `app.config.ts` registers and what the surfaces it calls trust.\n\t */\n\t'mobile-app': { scheme: string };\n\t/**\n\t * Where tokens come from and which audience they must carry.\n\t *\n\t * Two keys because the halves have different lifetimes: the issuer may be a\n\t * fact about the product, the audience is always a fact about one\n\t * deployment.\n\t */\n\toidc: { issuer: string; audience: string };\n\t/**\n\t * Where it answers — the provider, or its fake — and the credentials it\n\t * was issued for this stage, as one JSON object.\n\t */\n\t'external-api': { url: string; credentials: string };\n\t/**\n\t * A worker is reached by nothing — it reaches out, to a queue, a schedule,\n\t * a topic. So it publishes no address, the way a cron does not.\n\t */\n\tworker: Record<never, never>;\n\t// Its keys are OpenTelemetry's, not prefixed by the node's id — see\n\t// `TELEMETRY_KEYS`.\n\ttelemetry: Record<never, never>;\n}\n\nexport type Provides<K extends keyof ProvidesByKind> = ProvidesByKind[K];\n\n/**\n * Which provided values may be shipped to a browser.\n *\n * Drives client-side prefixing (`VITE_`, `NEXT_PUBLIC_`) and nothing else — it\n * is not a restriction on what may be depended on, since a server-side consumer\n * can legitimately use any of them. A bucket's `url` presigns and stays private.\n */\nexport const PUBLIC: {\n\treadonly [K in keyof ProvidesByKind]: readonly (keyof ProvidesByKind[K])[];\n} = {\n\tobjects: [],\n\t// The address a browser fetches an image from. The bucket's own URL is not\n\t// here and must not be: it presigns, and a presigner in a bundle is a\n\t// credential in a bundle.\n\t'file-server': ['url'],\n\t// Not the URL — it carries the SMTP credentials in its userinfo. The inbox\n\t// is a page a browser opens, and exists only locally: it is how a site or\n\t// a phone opens the sign-in link the server just sent, without fishing it\n\t// out of Mailpit by hand.\n\temail: ['inboxUrl'],\n\t// A connection string is never shippable, whichever role it carries.\n\tdatabase: [],\n\t'database-reader': [],\n\t'database-schema': [],\n\t// Carries its token, and a cache a browser can write is a cache it can\n\t// poison.\n\tcache: [],\n\t// The whole point of one.\n\tsecret: [],\n\t// A credential a browser can read is a credential anyone can read. A\n\t// publishable key belongs in the site's own config, not in this.\n\tcredential: [],\n\t// A keyring in a bundle is a key anyone can read.\n\tencryption: [],\n\t// A URL a browser calls is a URL a browser may hold. The other two are not\n\t// secret either — they are simply server-side facts, and prefixing a value\n\t// into a bundle that nothing there reads is how a bundle grows keys nobody\n\t// can account for.\n\t'rest-api': ['url'],\n\t// Carries broker credentials, and a browser that can publish to a queue can\n\t// forge any job the worker trusts.\n\tqueue: [],\n\ttopic: [],\n\t// A browser doing the sign-in flow needs both, and neither is secret: an\n\t// issuer is a public URL and an audience is a client id, which is the half\n\t// of an OAuth client that is meant to be seen.\n\toidc: ['issuer', 'audience'],\n\t// Called from the server with credentials a browser must never hold, and\n\t// the address alone is no use to anyone without them.\n\t'external-api': [],\n\t// An invocation address is not a public one: reaching it is IAM's business,\n\t// not a browser's.\n\tfunction: [],\n\tcron: [],\n\t// Read by its `app.config.ts` at build time, never shipped as a variable.\n\t'mobile-app': [],\n\t// Its own address, which it needs in order to build absolute links to\n\t// itself — and which an email templating a link to it needs too.\n\tsite: ['url'],\n\t// Nothing calls a worker, so there is no address to hand anyone. It reaches\n\t// out — to a queue, a schedule, a topic — and is reached by none of them.\n\tworker: [],\n\t// An exporter's endpoint and headers are a server's: the headers are a\n\t// credential, and a browser exports through its API's ingest route, never\n\t// to the provider. Nothing of a `Telemetry` node is ever inlined.\n\ttelemetry: [],\n};\n","/**\n * Manifest errors.\n *\n * Messages state the rule, which is constant; the offending value is a field.\n * An interpolated message cannot be matched on, reads differently every time it\n * is thrown, and carries user input into every log line that touches it.\n */\n\n/** A construct id that cannot survive the names derived from it. */\nexport class InvalidConstructId extends Error {\n\t/** What was passed in. */\n\treadonly input: string;\n\t/** What canonicalising it produced, which is what failed the rule. */\n\treadonly canonical: string;\n\n\tconstructor(input: string, canonical: string) {\n\t\tsuper(\n\t\t\t'A construct id must start with a letter and contain only letters and digits',\n\t\t);\n\t\tthis.name = 'InvalidConstructId';\n\t\tthis.input = input;\n\t\tthis.canonical = canonical;\n\t}\n}\n\n/** A derived construct naming a parent the manifest does not contain. */\nexport class UnknownParent extends Error {\n\t/** The derived construct. */\n\treadonly id: string;\n\t/** The parent it named. */\n\treadonly of: string;\n\t/** Ids the manifest does contain, for the caller to match against. */\n\treadonly available: readonly string[];\n\n\tconstructor(id: string, of: string, available: readonly string[]) {\n\t\tsuper('A derived construct must name a parent present in the manifest');\n\t\tthis.name = 'UnknownParent';\n\t\tthis.id = id;\n\t\tthis.of = of;\n\t\tthis.available = available;\n\t}\n}\n\n/**\n * A derived construct naming a parent that may not vend it — a reader of a\n * reader, a schema of a schema.\n */\nexport class IllegalDerivation extends Error {\n\treadonly id: string;\n\treadonly kind: string;\n\t/** The kind of the parent it named. */\n\treadonly parentKind: string;\n\t/** The parent kinds that may vend this one. */\n\treadonly allowed: readonly string[];\n\n\tconstructor(\n\t\tid: string,\n\t\tkind: string,\n\t\tparentKind: string,\n\t\tallowed: readonly string[],\n\t) {\n\t\tsuper('A derived construct must name a parent whose kind may vend it');\n\t\tthis.name = 'IllegalDerivation';\n\t\tthis.id = id;\n\t\tthis.kind = kind;\n\t\tthis.parentKind = parentKind;\n\t\tthis.allowed = allowed;\n\t}\n}\n","/**\n * lodash (Custom Build) <https://lodash.com/>\n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright jQuery Foundation and other contributors <https://jquery.org/>\n * Released under MIT license <https://lodash.com/license>\n * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>\n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as references for various `Number` constants. */\nvar INFINITY = 1 / 0;\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/** Used to match words composed of alphanumeric characters. */\nvar reAsciiWord = /[^\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\x7f]+/g;\n\n/** Used to match Latin Unicode letters (excluding mathematical operators). */\nvar reLatin = /[\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\xff\\u0100-\\u017f]/g;\n\n/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f\\\\ufe20-\\\\ufe23',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20f0',\n rsDingbatRange = '\\\\u2700-\\\\u27bf',\n rsLowerRange = 'a-z\\\\xdf-\\\\xf6\\\\xf8-\\\\xff',\n rsMathOpRange = '\\\\xac\\\\xb1\\\\xd7\\\\xf7',\n rsNonCharRange = '\\\\x00-\\\\x2f\\\\x3a-\\\\x40\\\\x5b-\\\\x60\\\\x7b-\\\\xbf',\n rsPunctuationRange = '\\\\u2000-\\\\u206f',\n rsSpaceRange = ' \\\\t\\\\x0b\\\\f\\\\xa0\\\\ufeff\\\\n\\\\r\\\\u2028\\\\u2029\\\\u1680\\\\u180e\\\\u2000\\\\u2001\\\\u2002\\\\u2003\\\\u2004\\\\u2005\\\\u2006\\\\u2007\\\\u2008\\\\u2009\\\\u200a\\\\u202f\\\\u205f\\\\u3000',\n rsUpperRange = 'A-Z\\\\xc0-\\\\xd6\\\\xd8-\\\\xde',\n rsVarRange = '\\\\ufe0e\\\\ufe0f',\n rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;\n\n/** Used to compose unicode capture groups. */\nvar rsApos = \"['\\u2019]\",\n rsBreak = '[' + rsBreakRange + ']',\n rsCombo = '[' + rsComboMarksRange + rsComboSymbolsRange + ']',\n rsDigits = '\\\\d+',\n rsDingbat = '[' + rsDingbatRange + ']',\n rsLower = '[' + rsLowerRange + ']',\n rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsUpper = '[' + rsUpperRange + ']',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar rsLowerMisc = '(?:' + rsLower + '|' + rsMisc + ')',\n rsUpperMisc = '(?:' + rsUpper + '|' + rsMisc + ')',\n rsOptLowerContr = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',\n rsOptUpperContr = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',\n reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq;\n\n/** Used to match apostrophes. */\nvar reApos = RegExp(rsApos, 'g');\n\n/**\n * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and\n * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).\n */\nvar reComboMark = RegExp(rsCombo, 'g');\n\n/** Used to match complex or compound words. */\nvar reUnicodeWord = RegExp([\n rsUpper + '?' + rsLower + '+' + rsOptLowerContr + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',\n rsUpperMisc + '+' + rsOptUpperContr + '(?=' + [rsBreak, rsUpper + rsLowerMisc, '$'].join('|') + ')',\n rsUpper + '?' + rsLowerMisc + '+' + rsOptLowerContr,\n rsUpper + '+' + rsOptUpperContr,\n rsDigits,\n rsEmoji\n].join('|'), 'g');\n\n/** Used to detect strings that need a more robust regexp to match words. */\nvar reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;\n\n/** Used to map Latin Unicode letters to basic Latin letters. */\nvar deburredLetters = {\n // Latin-1 Supplement block.\n '\\xc0': 'A', '\\xc1': 'A', '\\xc2': 'A', '\\xc3': 'A', '\\xc4': 'A', '\\xc5': 'A',\n '\\xe0': 'a', '\\xe1': 'a', '\\xe2': 'a', '\\xe3': 'a', '\\xe4': 'a', '\\xe5': 'a',\n '\\xc7': 'C', '\\xe7': 'c',\n '\\xd0': 'D', '\\xf0': 'd',\n '\\xc8': 'E', '\\xc9': 'E', '\\xca': 'E', '\\xcb': 'E',\n '\\xe8': 'e', '\\xe9': 'e', '\\xea': 'e', '\\xeb': 'e',\n '\\xcc': 'I', '\\xcd': 'I', '\\xce': 'I', '\\xcf': 'I',\n '\\xec': 'i', '\\xed': 'i', '\\xee': 'i', '\\xef': 'i',\n '\\xd1': 'N', '\\xf1': 'n',\n '\\xd2': 'O', '\\xd3': 'O', '\\xd4': 'O', '\\xd5': 'O', '\\xd6': 'O', '\\xd8': 'O',\n '\\xf2': 'o', '\\xf3': 'o', '\\xf4': 'o', '\\xf5': 'o', '\\xf6': 'o', '\\xf8': 'o',\n '\\xd9': 'U', '\\xda': 'U', '\\xdb': 'U', '\\xdc': 'U',\n '\\xf9': 'u', '\\xfa': 'u', '\\xfb': 'u', '\\xfc': 'u',\n '\\xdd': 'Y', '\\xfd': 'y', '\\xff': 'y',\n '\\xc6': 'Ae', '\\xe6': 'ae',\n '\\xde': 'Th', '\\xfe': 'th',\n '\\xdf': 'ss',\n // Latin Extended-A block.\n '\\u0100': 'A', '\\u0102': 'A', '\\u0104': 'A',\n '\\u0101': 'a', '\\u0103': 'a', '\\u0105': 'a',\n '\\u0106': 'C', '\\u0108': 'C', '\\u010a': 'C', '\\u010c': 'C',\n '\\u0107': 'c', '\\u0109': 'c', '\\u010b': 'c', '\\u010d': 'c',\n '\\u010e': 'D', '\\u0110': 'D', '\\u010f': 'd', '\\u0111': 'd',\n '\\u0112': 'E', '\\u0114': 'E', '\\u0116': 'E', '\\u0118': 'E', '\\u011a': 'E',\n '\\u0113': 'e', '\\u0115': 'e', '\\u0117': 'e', '\\u0119': 'e', '\\u011b': 'e',\n '\\u011c': 'G', '\\u011e': 'G', '\\u0120': 'G', '\\u0122': 'G',\n '\\u011d': 'g', '\\u011f': 'g', '\\u0121': 'g', '\\u0123': 'g',\n '\\u0124': 'H', '\\u0126': 'H', '\\u0125': 'h', '\\u0127': 'h',\n '\\u0128': 'I', '\\u012a': 'I', '\\u012c': 'I', '\\u012e': 'I', '\\u0130': 'I',\n '\\u0129': 'i', '\\u012b': 'i', '\\u012d': 'i', '\\u012f': 'i', '\\u0131': 'i',\n '\\u0134': 'J', '\\u0135': 'j',\n '\\u0136': 'K', '\\u0137': 'k', '\\u0138': 'k',\n '\\u0139': 'L', '\\u013b': 'L', '\\u013d': 'L', '\\u013f': 'L', '\\u0141': 'L',\n '\\u013a': 'l', '\\u013c': 'l', '\\u013e': 'l', '\\u0140': 'l', '\\u0142': 'l',\n '\\u0143': 'N', '\\u0145': 'N', '\\u0147': 'N', '\\u014a': 'N',\n '\\u0144': 'n', '\\u0146': 'n', '\\u0148': 'n', '\\u014b': 'n',\n '\\u014c': 'O', '\\u014e': 'O', '\\u0150': 'O',\n '\\u014d': 'o', '\\u014f': 'o', '\\u0151': 'o',\n '\\u0154': 'R', '\\u0156': 'R', '\\u0158': 'R',\n '\\u0155': 'r', '\\u0157': 'r', '\\u0159': 'r',\n '\\u015a': 'S', '\\u015c': 'S', '\\u015e': 'S', '\\u0160': 'S',\n '\\u015b': 's', '\\u015d': 's', '\\u015f': 's', '\\u0161': 's',\n '\\u0162': 'T', '\\u0164': 'T', '\\u0166': 'T',\n '\\u0163': 't', '\\u0165': 't', '\\u0167': 't',\n '\\u0168': 'U', '\\u016a': 'U', '\\u016c': 'U', '\\u016e': 'U', '\\u0170': 'U', '\\u0172': 'U',\n '\\u0169': 'u', '\\u016b': 'u', '\\u016d': 'u', '\\u016f': 'u', '\\u0171': 'u', '\\u0173': 'u',\n '\\u0174': 'W', '\\u0175': 'w',\n '\\u0176': 'Y', '\\u0177': 'y', '\\u0178': 'Y',\n '\\u0179': 'Z', '\\u017b': 'Z', '\\u017d': 'Z',\n '\\u017a': 'z', '\\u017c': 'z', '\\u017e': 'z',\n '\\u0132': 'IJ', '\\u0133': 'ij',\n '\\u0152': 'Oe', '\\u0153': 'oe',\n '\\u0149': \"'n\", '\\u017f': 'ss'\n};\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/**\n * A specialized version of `_.reduce` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @param {*} [accumulator] The initial value.\n * @param {boolean} [initAccum] Specify using the first element of `array` as\n * the initial value.\n * @returns {*} Returns the accumulated value.\n */\nfunction arrayReduce(array, iteratee, accumulator, initAccum) {\n var index = -1,\n length = array ? array.length : 0;\n\n if (initAccum && length) {\n accumulator = array[++index];\n }\n while (++index < length) {\n accumulator = iteratee(accumulator, array[index], index, array);\n }\n return accumulator;\n}\n\n/**\n * Splits an ASCII `string` into an array of its words.\n *\n * @private\n * @param {string} The string to inspect.\n * @returns {Array} Returns the words of `string`.\n */\nfunction asciiWords(string) {\n return string.match(reAsciiWord) || [];\n}\n\n/**\n * The base implementation of `_.propertyOf` without support for deep paths.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Function} Returns the new accessor function.\n */\nfunction basePropertyOf(object) {\n return function(key) {\n return object == null ? undefined : object[key];\n };\n}\n\n/**\n * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A\n * letters to basic Latin letters.\n *\n * @private\n * @param {string} letter The matched letter to deburr.\n * @returns {string} Returns the deburred letter.\n */\nvar deburrLetter = basePropertyOf(deburredLetters);\n\n/**\n * Checks if `string` contains a word composed of Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a word is found, else `false`.\n */\nfunction hasUnicodeWord(string) {\n return reHasUnicodeWord.test(string);\n}\n\n/**\n * Splits a Unicode `string` into an array of its words.\n *\n * @private\n * @param {string} The string to inspect.\n * @returns {Array} Returns the words of `string`.\n */\nfunction unicodeWords(string) {\n return string.match(reUnicodeWord) || [];\n}\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolToString = symbolProto ? symbolProto.toString : undefined;\n\n/**\n * The base implementation of `_.toString` which doesn't convert nullish\n * values to empty strings.\n *\n * @private\n * @param {*} value The value to process.\n * @returns {string} Returns the string.\n */\nfunction baseToString(value) {\n // Exit early for strings to avoid a performance hit in some environments.\n if (typeof value == 'string') {\n return value;\n }\n if (isSymbol(value)) {\n return symbolToString ? symbolToString.call(value) : '';\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\n/**\n * Creates a function like `_.camelCase`.\n *\n * @private\n * @param {Function} callback The function to combine each word.\n * @returns {Function} Returns the new compounder function.\n */\nfunction createCompounder(callback) {\n return function(string) {\n return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');\n };\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return !!value && typeof value == 'object';\n}\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && objectToString.call(value) == symbolTag);\n}\n\n/**\n * Converts `value` to a string. An empty string is returned for `null`\n * and `undefined` values. The sign of `-0` is preserved.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {string} Returns the string.\n * @example\n *\n * _.toString(null);\n * // => ''\n *\n * _.toString(-0);\n * // => '-0'\n *\n * _.toString([1, 2, 3]);\n * // => '1,2,3'\n */\nfunction toString(value) {\n return value == null ? '' : baseToString(value);\n}\n\n/**\n * Deburrs `string` by converting\n * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)\n * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)\n * letters to basic Latin letters and removing\n * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to deburr.\n * @returns {string} Returns the deburred string.\n * @example\n *\n * _.deburr('déjà vu');\n * // => 'deja vu'\n */\nfunction deburr(string) {\n string = toString(string);\n return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');\n}\n\n/**\n * Converts `string` to\n * [snake case](https://en.wikipedia.org/wiki/Snake_case).\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to convert.\n * @returns {string} Returns the snake cased string.\n * @example\n *\n * _.snakeCase('Foo Bar');\n * // => 'foo_bar'\n *\n * _.snakeCase('fooBar');\n * // => 'foo_bar'\n *\n * _.snakeCase('--FOO-BAR--');\n * // => 'foo_bar'\n */\nvar snakeCase = createCompounder(function(result, word, index) {\n return result + (index ? '_' : '') + word.toLowerCase();\n});\n\n/**\n * Splits `string` into an array of its words.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to inspect.\n * @param {RegExp|string} [pattern] The pattern to match words.\n * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.\n * @returns {Array} Returns the words of `string`.\n * @example\n *\n * _.words('fred, barney, & pebbles');\n * // => ['fred', 'barney', 'pebbles']\n *\n * _.words('fred, barney, & pebbles', /[^, ]+/g);\n * // => ['fred', 'barney', '&', 'pebbles']\n */\nfunction words(string, pattern, guard) {\n string = toString(string);\n pattern = guard ? undefined : pattern;\n\n if (pattern === undefined) {\n return hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);\n }\n return string.match(pattern) || [];\n}\n\nmodule.exports = snakeCase;\n","/**\n * Name derivation — the single source for turning a construct's id into the\n * names that appear elsewhere.\n *\n * These live here rather than in each consumer because `@geekmidas/constructs`\n * derives a key when it declares, and `@geekmidas/cloud` derives the same key\n * when it supplies the value. Two implementations of the same rule is precisely\n * the drift this design exists to remove.\n */\n\nimport snakecase from 'lodash.snakecase';\nimport type { DeclarationKind } from './declaration';\n\nimport { InvalidConstructId } from './errors';\n\n/**\n * `UPPER_SNAKE_CASE`, with numbers kept against the word they follow.\n *\n * Matches `environmentCase` in `@geekmidas/envkit`, which reads the values these\n * names key. The two must agree exactly, so this is the implementation and that\n * one should defer to it.\n *\n * @example environmentCase('sendEmail') // 'SEND_EMAIL'\n * @example environmentCase('api2') // 'API2' (digit joins its word)\n */\nexport function environmentCase(name: string): string {\n\treturn snakecase(name)\n\t\t.toUpperCase()\n\t\t.replace(/_\\d+/g, (r) => r.replace('_', ''));\n}\n\n/**\n * The env key a construct provides for one of its roles.\n *\n * @example provideKey('Uploads', 'url') // 'UPLOADS_URL'\n * @example provideKey('Uploads', 'cdnUrl') // 'UPLOADS_CDN_URL'\n */\nexport function provideKey(id: string, role: string): string {\n\treturn environmentCase(`${id}_${role}`);\n}\n\n/**\n * A construct's canonical id — PascalCase.\n *\n * `uploads`, `Uploads`, `user_uploads`, and `user-uploads` all canonicalise to\n * the same id, so declaring two of them is a duplicate rather than a collision\n * to detect.\n *\n * Runtime only. Writing the id in PascalCase is what keeps the *type* usable:\n * the service key is `Uncapitalize<TName>`, a TypeScript intrinsic, so no\n * type-level transform is needed and none has to be kept in step with this one.\n *\n * @example canonicalId('user-uploads') // 'UserUploads'\n */\nexport function canonicalId(input: string): string {\n\t// `upperFirst(camelCase(x))` by another route — snakecase is already a\n\t// dependency, and adding lodash.camelcase for the same result is not worth it.\n\tconst id = snakecase(input)\n\t\t.split('_')\n\t\t.filter(Boolean)\n\t\t.map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n\t\t.join('');\n\n\tif (!VALID_ID.test(id)) throw new InvalidConstructId(input, id);\n\treturn id;\n}\n\n/**\n * A canonical id: PascalCase, letters and digits only.\n *\n * Narrower than a JavaScript identifier — `_id` and `$ref` are legal JavaScript\n * and rejected here — because the id also has to survive `environmentCase` into\n * an env key and `cloudName` into a DNS-safe resource name.\n */\nconst VALID_ID = /^[A-Z][A-Za-z0-9]*$/;\n\n/**\n * The key a construct is reached under in the service record.\n *\n * The runtime twin of `Uncapitalize<TName>`, which types it — they must agree,\n * so they live next to each other rather than being re-derived by each\n * construct.\n *\n * @example serviceKey('UserUploads') // 'userUploads' → services.userUploads\n */\nexport function serviceKey(id: string): string {\n\treturn id.charAt(0).toLowerCase() + id.slice(1);\n}\n\n/**\n * The table a cache keeps its entries in, when nobody named one.\n *\n * Derived from the cache's own id rather than fixed at `cache`, because a\n * database may hold more than one and two caches sharing a table share a\n * keyspace — `orders.cache('Sessions')` and `orders.cache('Rates')` would\n * silently read each other's entries and evict each other's keys.\n *\n * Prefixed rather than suffixed so every cache sorts together in `\\dt`, and\n * prefixed at all so a cache named for a thing the application also stores —\n * `orders.cache('Users')` — cannot collide with the table holding that thing.\n *\n * Read by whoever composes the URL and by whoever creates the table, so both\n * default the same way.\n *\n * @example cacheTable('Sessions') // 'cache_sessions'\n */\nexport function cacheTable(id: string): string {\n\treturn `cache_${id.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase()}`;\n}\n\n/**\n * Kebab-cases an identifier, acronym- and digit-aware.\n *\n * `userName` → `user-name`, `APIKey` → `api-key`, `S3Bucket` → `s3-bucket`.\n *\n * The last of those is why this is here rather than `snakecase(id)` with the\n * underscores swapped: lodash splits a digit from the letter beside it, so\n * `S3Bucket` became `s-3-bucket` on one provider and `s3-bucket` on the other.\n * Two implementations of one rule, agreeing on every id anybody had tried.\n *\n * `environmentCase` already corrected for the same thing in the other\n * direction — `api2` keeps its digit — so the two spellings of \"kebab this id\"\n * in this file did not even agree with each other.\n */\nexport function kebabCase(value: string): string {\n\treturn value\n\t\t.replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')\n\t\t.replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n\t\t.replace(/[\\s_]+/g, '-')\n\t\t.toLowerCase();\n}\n\n/**\n * The physical name a target provisions a construct under — lowercase kebab,\n * scoped so two stages or apps sharing an account cannot collide.\n *\n * **One rule, every provider.** A construct is named the same thing on AWS and\n * on Dokploy, which is what lets a name be read across them: `Database` in the\n * `production` stage of `kitchen-sink` is `production-kitchen-sink-database`\n * wherever it lands. The SST target's `prefixedName` is this function under\n * another signature and defers to it.\n *\n * Idempotent in its prefix: an id that already carries the scope is not given a\n * second one, so composing names cannot double up.\n *\n * @example cloudName({ stage: 'prod', app: 'myapp' }, 'UserUploads')\n * // 'prod-myapp-user-uploads'\n */\nexport function cloudName(\n\tscope: { stage: string; app: string },\n\tid: string,\n): string {\n\treturn scopedName([scope.stage, scope.app], id);\n}\n\n/**\n * {@link cloudName} for a caller that holds its scope as a list.\n *\n * The SST target's stacks add a segment of their own, so the prefix is not\n * always two parts — which is the only reason this signature exists.\n */\nexport function scopedName(scope: readonly string[], id: string): string {\n\tconst prefix = scope.join('-').toLowerCase();\n\tconst name = kebabCase(id);\n\n\treturn name.startsWith(prefix) ? name : `${prefix}-${name}`;\n}\n\n/**\n * The domain a cookie must be scoped to so a surface and its callers share it.\n *\n * Derived from the addresses rather than configured, for the same reason the\n * origins are: the set of things that talk to a surface is already in the graph,\n * and the domain they have in common is a fact about that set. Returned with the\n * leading dot a `Domain` attribute wants.\n *\n * Returns `undefined` when there is nothing to scope, which is the common case\n * and not a failure:\n *\n * - **One host.** Locally everything is `localhost` on different ports, and\n * cookies ignore the port — so a `Domain` would add nothing and `.localhost`\n * is not a domain a browser will accept.\n * - **Nothing in common.** Unrelated hosts cannot share a cookie at all, and\n * emitting the longest common suffix anyway would be a value that silently\n * fails to set.\n *\n * **The public-suffix limit, stated rather than discovered.** Two apps on\n * `a.vercel.app` and `b.vercel.app` share `.vercel.app`, which every browser\n * rejects because it is a registrable suffix rather than a registrable domain.\n * Resolving that correctly needs the Public Suffix List, which is a downloaded,\n * expiring dataset — so this requires at least two labels and otherwise trusts\n * the addresses, and the value stays overridable for the case it gets wrong.\n */\nexport function cookieDomain(urls: readonly string[]): string | undefined {\n\tconst hosts = new Set<string>();\n\n\tfor (const url of urls) {\n\t\ttry {\n\t\t\tconst { hostname } = new URL(url);\n\t\t\t// An IP address has no parent to share: `.0.0.1` is not a domain.\n\t\t\tif (/^\\d+(\\.\\d+){3}$/.test(hostname) || hostname.includes(':')) return;\n\t\t\thosts.add(hostname.toLowerCase());\n\t\t} catch {\n\t\t\t// Not an address. Nothing to derive from, and guessing is worse than\n\t\t\t// leaving the attribute off.\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (hosts.size === 0) return;\n\t// One host already shares its cookies with itself, whatever the port.\n\tif (hosts.size === 1) return;\n\n\tconst [first = [], ...rest] = [...hosts].map((host) =>\n\t\thost.split('.').reverse(),\n\t);\n\tconst shared: string[] = [];\n\n\tfor (const [index, label] of first.entries()) {\n\t\tif (!rest.every((labels) => labels[index] === label)) break;\n\t\tshared.push(label);\n\t}\n\n\t// One shared label is a TLD — `.com` is not a cookie domain.\n\tif (shared.length < 2) return;\n\n\treturn `.${shared.reverse().join('.')}`;\n}\n\n/**\n * The env key a construct's provided role actually becomes.\n *\n * Almost always `provideKey(id, role)` — and `secret` is the exception, because\n * a secret's *name* is its key: `Auth` signs with `AUTH_SECRET`, which is also\n * what better-auth's own tooling looks for, and qualifying it by role would\n * produce `AUTH_SECRET_VALUE`.\n *\n * It lives here rather than in each target because two targets deriving the\n * same key separately is exactly the drift the app/infra contract check exists\n * to catch — and a check deriving the key differently from the thing it checks\n * cannot catch anything.\n */\nexport function providedKeyFor(\n\tid: string,\n\tkind: DeclarationKind,\n\trole: string,\n): string {\n\tif (kind === 'secret') return environmentCase(id);\n\t// OpenTelemetry's own variable, whatever the node is called: an SDK reads\n\t// nothing else.\n\tif (kind === 'telemetry') return 'OTEL_EXPORTER_OTLP_ENDPOINT';\n\treturn provideKey(id, role);\n}\n","/**\n * Derived constructs — the ones that provision nothing of their own.\n *\n * A reader is an endpoint on an existing cluster; a schema tenant is a schema\n * inside an existing database. Both name their parent through `of`, and both\n * stay top-level entries so that `dependencies[].target` keeps resolving as\n * `m[target]` and every id remains a key in the map.\n *\n * The rules here are pure and manifest-only: they hold for any target adapter,\n * so an app is wrong before a deploy is attempted rather than during one.\n */\n\nimport type {\n\tConstructId,\n\tConstructManifest,\n\tDeclaration,\n\tDependency,\n\tDerivedDeclaration,\n\tMobileAppDeclaration,\n\tSiteDeclaration,\n} from './declaration';\nimport { DERIVES_FROM, PUBLIC } from './declaration';\nimport { IllegalDerivation, UnknownParent } from './errors';\nimport { provideKey } from './naming';\n\n/** Whether a declaration names a parent. */\nexport function isDerived(\n\tdeclaration: Declaration,\n): declaration is DerivedDeclaration & { of: ConstructId } {\n\t// Both halves, because one kind is *optionally* derived: a cache declared\n\t// from a database names it, and a cache declared on its own names nothing.\n\t// Testing only the kind would make every standalone cache look like a\n\t// derivation with a missing parent.\n\treturn (\n\t\tdeclaration.kind in DERIVES_FROM &&\n\t\t'of' in declaration &&\n\t\ttypeof declaration.of === 'string'\n\t);\n}\n\n/**\n * Check every derived construct against its parent.\n *\n * Two rules: the parent exists, and its kind may vend this one. Together they\n * make cycles unreachable — a reader is terminal, so no chain of `of` can\n * return to where it started, and no walk is needed to prove it.\n */\nexport function assertDerivations(manifest: ConstructManifest): void {\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tif (!isDerived(declaration)) continue;\n\n\t\tconst parent = manifest[declaration.of];\n\t\tif (!parent) {\n\t\t\tthrow new UnknownParent(id, declaration.of, Object.keys(manifest));\n\t\t}\n\n\t\tconst allowed = DERIVES_FROM[declaration.kind];\n\t\tif (!allowed.includes(parent.kind)) {\n\t\t\tthrow new IllegalDerivation(id, declaration.kind, parent.kind, allowed);\n\t\t}\n\t}\n}\n\n/**\n * The order constructs must be provisioned in: every parent before its children.\n *\n * Resources are leaves and so come first in any order; only derived nodes\n * constrain the sequence, and they form a shallow forest rather than a general\n * graph. This walks each node's ancestors on demand instead of running a full\n * topological sort, which is the same result at this depth and reads as what it\n * is.\n *\n * Assumes {@link assertDerivations} has passed — a missing parent would\n * otherwise be a silent omission here rather than an error.\n */\nexport function provisionOrder(manifest: ConstructManifest): string[] {\n\tconst ordered: string[] = [];\n\tconst placed = new Set<string>();\n\n\tconst place = (id: string): void => {\n\t\tif (placed.has(id)) return;\n\t\tconst declaration = manifest[id];\n\t\tif (!declaration) return;\n\n\t\t// Mark before recursing: `assertDerivations` rules cycles out, and marking\n\t\t// first means a manifest that skipped that check terminates anyway.\n\t\tplaced.add(id);\n\t\tif (isDerived(declaration)) place(declaration.of);\n\t\tordered.push(id);\n\t};\n\n\tfor (const id of Object.keys(manifest)) place(id);\n\n\treturn ordered;\n}\n\n/**\n * Every edge a declaration carries, wherever the kind happens to keep them.\n *\n * Dependencies live in two places by design: on a node when the whole construct\n * is the consumer (a site), and on each nested handler when the construct is a\n * surface (a `rest-api`, whose routes each depend on their own things and\n * nothing more). Flattening that difference here is what lets every consumer of\n * the graph — reverse lookups, filtering, reference checks — ask one question.\n */\nexport function dependenciesOf(\n\tdeclaration: Declaration,\n): readonly Dependency[] {\n\tconst own =\n\t\t'dependencies' in declaration ? (declaration.dependencies ?? []) : [];\n\n\t// A surface's `calls` is a caller relationship rather than an injection, so\n\t// it is read here — reverse lookups want it — and is never a dependency\n\t// anything links from. See `RestApiDeclaration.calls`.\n\tconst calls = 'calls' in declaration ? (declaration.calls ?? []) : [];\n\n\tconst nested =\n\t\tdeclaration.kind === 'rest-api'\n\t\t\t? declaration.endpoints.flatMap((endpoint) => endpoint.dependencies)\n\t\t\t: [];\n\n\t// The `Telemetry` node a process emits through: an edge like any other, so\n\t// the keys it provides follow it to exactly the processes that use it.\n\tconst telemetry =\n\t\t'telemetry' in declaration && typeof declaration.telemetry === 'string'\n\t\t\t? [{ target: declaration.telemetry, kind: 'telemetry' as const }]\n\t\t\t: [];\n\n\treturn [...own, ...calls, ...nested, ...telemetry];\n}\n\n/**\n * The ids that depend on one construct — the graph read backwards.\n *\n * This is the whole mechanism behind CORS origins and trusted origins. Both are\n * lists of *callers*, and a caller is exactly an inbound edge, so neither is\n * ever written down: a surface that listed its own callers would have to be\n * edited every time something new called it, which is the hand-maintained list\n * this replaces.\n *\n * Sorted, because it feeds a comma-separated env value that would otherwise\n * change whenever the manifest's key order did — and a value that churns is a\n * container that redeploys for no reason.\n */\nexport function dependentsOf(\n\tmanifest: ConstructManifest,\n\tid: ConstructId,\n): string[] {\n\tconst callers: string[] = [];\n\n\tfor (const [callerId, declaration] of Object.entries(manifest)) {\n\t\tif (callerId === id) continue;\n\t\tif (dependenciesOf(declaration).some((edge) => edge.target === id)) {\n\t\t\tcallers.push(callerId);\n\t\t}\n\t}\n\n\treturn callers.sort();\n}\n\n/**\n * How each site variant names a value it ships to the browser.\n *\n * The prefix *is* the framework's contract — `VITE_`, `NEXT_PUBLIC_` and\n * `EXPO_PUBLIC_` all mean \"inline this into the bundle\" — so it is the one thing\n * a variant changes, and it changes nothing else.\n */\nexport const PUBLIC_PREFIX: Record<\n\tSiteDeclaration['variant'] | MobileAppDeclaration['variant'],\n\tstring\n> = {\n\tstatic: 'VITE_',\n\ttanstack: 'VITE_',\n\tnext: 'NEXT_PUBLIC_',\n\texpo: 'EXPO_PUBLIC_',\n};\n\n/**\n * The keys a site's bundle needs, mapped to the key each value comes from —\n * `{ VITE_API_URL: 'API_URL' }`.\n *\n * A rename, not a second derivation: `API_URL` is resolved once, by whatever\n * resolved it for the server, and the site reads the same value under the name\n * its bundler will inline. That is what keeps a site and its API from coming to\n * disagree about where the API is.\n *\n * Filtered by `PUBLIC` rather than by what the site asked for. A site may\n * legitimately depend on anything — its server half, where it has one, reads env\n * exactly as a function does — so this is not a restriction on edges. It decides\n * one thing: which values may be prefixed into a bundle, which is what keeps\n * `ORDERS_URL` and its password out of a JavaScript file served to the public.\n *\n * Shared by every target for the same reason `providedKeyFor` is: a site built\n * locally and the same site built by a deploy must inline the same names.\n */\nexport function publicEnvFor(\n\tdeclaration: SiteDeclaration | MobileAppDeclaration,\n\tmanifest: ConstructManifest,\n): Record<string, string> {\n\tconst prefix = PUBLIC_PREFIX[declaration.variant];\n\tconst keys: Record<string, string> = {};\n\n\tfor (const edge of declaration.dependencies) {\n\t\tconst target = manifest[edge.target];\n\t\tif (!target) continue;\n\n\t\tfor (const role of PUBLIC[target.kind] ?? []) {\n\t\t\tconst key = provideKey(edge.target, role as string);\n\t\t\tkeys[`${prefix}${key}`] = key;\n\t\t}\n\t}\n\n\treturn keys;\n}\n","/**\n * The `kms://` URL an `Encryption` construct reads on AWS.\n *\n * Here because two packages meet on it: `@geekmidas/cloud` composes it from\n * the keys it provisioned, and `@geekmidas/constructs` parses it to reach\n * them. One function, so the two cannot disagree about a parameter's name.\n */\n\nexport const KMS_SCHEME = 'kms:';\n\n/**\n * `kms://<region>?key=<key arn>&index=<hmac key arn>[&endpoint=<url>]`\n *\n * `endpoint` reaches an emulator instead of AWS — floci, locally and in tests —\n * the same parameter an `sns://` connection string carries for the same reason.\n */\nexport function kmsUrl(input: {\n\tregion: string;\n\tkey: string;\n\tindex: string;\n\tendpoint?: string;\n}): string {\n\tconst query = new URLSearchParams({\n\t\tkey: input.key,\n\t\tindex: input.index,\n\t\t...(input.endpoint ? { endpoint: input.endpoint } : {}),\n\t});\n\treturn `${KMS_SCHEME}//${input.region}?${query}`;\n}\n","import type { ExternalApiDeclaration } from './declaration';\n\n/** The key in a by-stage `url` that answers for every stage not listed. */\nexport const DEFAULT_STAGE_URL = 'default';\n\n/**\n * Where an external API answers on a deployed stage.\n *\n * One URL answers every stage; a record answers by stage name, falling back\n * to `default`. Read at build and deploy, so a stage nobody gave a URL fails\n * there — with the stage named — rather than at the first request.\n *\n * @throws {NoUrlForStage} when a record names neither the stage nor a default.\n */\nexport function externalApiUrl(\n\tdeclaration: Pick<ExternalApiDeclaration, 'id' | 'url'>,\n\tstage: string,\n): string {\n\tconst { url } = declaration;\n\tif (typeof url === 'string') return url;\n\n\tconst resolved = url[stage] ?? url[DEFAULT_STAGE_URL];\n\tif (!resolved) {\n\t\tthrow new NoUrlForStage(declaration.id, stage, Object.keys(url));\n\t}\n\n\treturn resolved;\n}\n\n/** An external API's `url` record has nothing for the stage being deployed. */\nexport class NoUrlForStage extends Error {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly stage: string,\n\t\treadonly stages: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`'${id}' has no URL for the stage '${stage}': its url names ` +\n\t\t\t\t`${stages.length ? stages.map((s) => `'${s}'`).join(', ') : 'no stages'}. ` +\n\t\t\t\t`Add '${stage}', or a '${DEFAULT_STAGE_URL}' for every stage not listed.`,\n\t\t);\n\t\tthis.name = 'NoUrlForStage';\n\t}\n}\n","/**\n * Headers gkm reserves for its own services' calls to each other.\n *\n * Shared by `@geekmidas/constructs`, which sends and reads them, and\n * `@geekmidas/cli`, whose edges strip them from every request that arrives\n * from outside — so the two cannot name them differently.\n */\n\n/**\n * The address of the client a service-to-service call is made on behalf of.\n *\n * An API asking its auth server for a session sends the client's address in\n * this rather than `X-Forwarded-For`: a forwarding header marks a request as\n * outside traffic, which would start the auth server's span in a new trace,\n * and the address is still needed — Better Auth rate-limits per client.\n *\n * Reserved: the stack's edge (Caddy, Traefik, the `gkm dev` edge) removes it\n * from incoming requests, and the auth server ignores it on any request that\n * is not an internal caller's, so it cannot be spoofed from outside.\n */\nexport const CLIENT_IP_HEADER = 'x-gkm-client-ip';\n","/**\n * Which constructs take migrations, where their files live, and in what order\n * they run — resolved once, from the manifest.\n *\n * `gkm migrate`, `gkm test`, `gkm migration` and every deploy target ask the\n * same question. Each deriving it on its own is how one of them comes to\n * migrate a reader, skip a tenant, or run a tenant's files before the parent\n * that owns its schema exists.\n */\n\nimport type { ConstructId, ConstructManifest } from './declaration';\nimport { provisionOrder } from './derive';\nimport { kebabCase } from './naming';\n\n/** Where every construct's folder lives, from the project root. */\nexport const MIGRATIONS_ROOT = 'db';\n\n/** The two folders a construct's folder holds, and nothing else. */\nexport const DATABASE_FOLDERS = ['migrations', 'seeds'] as const;\n\n/** One construct whose schema is changed by migrations. */\nexport interface MigrationTarget {\n\t/** The construct's canonical id, e.g. `AuthDatabase`. */\n\tid: ConstructId;\n\t/** Its folder, relative to the project root: `db/auth-database`. */\n\tfolder: string;\n\t/** Its schema's history: `db/auth-database/migrations`. */\n\tmigrations: string;\n\t/** The reference data it needs to run: `db/auth-database/seeds`. */\n\tseeds: string;\n\t/** For a schema tenant, the database it lives in. */\n\tof?: ConstructId;\n}\n\n/**\n * The constructs that take migrations, parents before the tenants inside them.\n *\n * A database and each schema tenant: every one has an owner role and a schema\n * of its own, and so a history of its own. A reader has neither — it reads its\n * parent's schema — and a cache's table is created by provisioning, not by a\n * migration anyone writes.\n */\nexport function migrationTargets(\n\tmanifest: ConstructManifest,\n): MigrationTarget[] {\n\treturn provisionOrder(manifest).flatMap((id) => {\n\t\tconst declaration = manifest[id];\n\t\tif (!declaration) return [];\n\n\t\tif (declaration.kind === 'database') return [target(id)];\n\t\tif (declaration.kind === 'database-schema') {\n\t\t\treturn [{ ...target(id), of: declaration.of }];\n\t\t}\n\n\t\treturn [];\n\t});\n}\n\n/**\n * A construct's folder, relative to the project root.\n *\n * Named by the construct — `AuthDatabase` is `db/auth-database` — in the case\n * every other name outside TypeScript takes. Lowercase, because a folder that\n * differs from another only in case is two folders on Linux and one on a Mac;\n * and `canonicalId` reads it back to the construct exactly, which is how a\n * folder naming nothing is caught rather than skipped.\n */\nexport function databaseFolder(id: ConstructId): string {\n\treturn `${MIGRATIONS_ROOT}/${kebabCase(id)}`;\n}\n\n/** Where a construct's migrations live: `db/auth-database/migrations`. */\nexport function migrationFolder(id: ConstructId): string {\n\treturn `${databaseFolder(id)}/migrations`;\n}\n\n/**\n * Where a construct's seeds live: `db/auth-database/seeds`.\n *\n * Reference data the app needs to run — a permission catalogue, roles, lookup\n * tables. Seeds are upserts run on every pass, after the migrations, so a\n * changed seed is applied by running it again. Sample data is factories'.\n */\nexport function seedFolder(id: ConstructId): string {\n\treturn `${databaseFolder(id)}/seeds`;\n}\n\nfunction target(id: ConstructId): MigrationTarget {\n\treturn {\n\t\tid,\n\t\tfolder: databaseFolder(id),\n\t\tmigrations: migrationFolder(id),\n\t\tseeds: seedFolder(id),\n\t};\n}\n","/**\n * How a mobile app is reached: its URL scheme, and the origins a surface trusts\n * for it.\n *\n * Stated once, here, because three targets ask — the local one (`gkm dev`,\n * `gkm test`), Dokploy and AWS — and a scheme one of them derived differently\n * would be an app whose sign-in callback the auth server refuses on exactly one\n * of them.\n */\n\n/**\n * An app's scheme: the one given, or the project's name made a valid scheme.\n *\n * One for every stage. A development build and the store build register the\n * same scheme, so the auth server of whichever stage a build talks to trusts\n * it, and nothing about the app differs between stages but its URLs.\n *\n * A scheme is a letter followed by letters, digits, `+`, `-` or `.` — so\n * `Corner Shop` becomes `corner-shop`, and a name that starts with a digit gets a\n * leading `app`.\n */\nexport function schemeBase(project: string, given?: string): string {\n\tconst raw = (given ?? project)\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9+.-]+/g, '-')\n\t\t.replace(/^-+|-+$/g, '');\n\tif (!raw) return 'app';\n\treturn /^[a-z]/.test(raw) ? raw : `app${raw}`;\n}\n\n/** Where an Expo development server runs, for the `exp://` origins it sends. */\nexport interface MetroHost {\n\t/** The hosts a device reaches it on: the LAN address, `localhost`. */\n\thosts: readonly string[];\n\t/** Metro's port, when the target placed it — otherwise any port. */\n\tport?: number;\n}\n\n/**\n * The origins a surface trusts for a mobile caller.\n *\n * Better Auth's Expo plugin sends the app's scheme as its origin\n * (`shop://`), and a link can carry a path after it (`shop://*`).\n * In development, Expo Go sends `exp://<host>:<port>` instead — so a local\n * stage adds the hosts a device actually reaches Metro on, and Metro's port\n * when the target placed it: a whole subnet is not trusted because one phone\n * is on it.\n */\nexport function mobileOrigins(scheme: string, metro?: MetroHost): string[] {\n\treturn [\n\t\t`${scheme}://`,\n\t\t`${scheme}://*`,\n\t\t...(metro?.hosts ?? []).flatMap((host) => [\n\t\t\t`exp://${host}:${metro?.port ?? '*'}`,\n\t\t\t`exp://${host}:${metro?.port ?? '*'}/**`,\n\t\t]),\n\t];\n}\n\n/** Whether an origin is a web one — what a cookie domain is derived from. */\nexport function isWebOrigin(origin: string): boolean {\n\treturn origin.startsWith('http://') || origin.startsWith('https://');\n}\n"],"x_google_ignoreList":[2],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1080,6 +1080,28 @@ export declare class NoUrlForStage extends Error {
|
|
|
1080
1080
|
constructor(id: string, stage: string, stages: readonly string[]);
|
|
1081
1081
|
}
|
|
1082
1082
|
//#endregion
|
|
1083
|
+
//#region src/headers.d.ts
|
|
1084
|
+
/**
|
|
1085
|
+
* Headers gkm reserves for its own services' calls to each other.
|
|
1086
|
+
*
|
|
1087
|
+
* Shared by `@geekmidas/constructs`, which sends and reads them, and
|
|
1088
|
+
* `@geekmidas/cli`, whose edges strip them from every request that arrives
|
|
1089
|
+
* from outside — so the two cannot name them differently.
|
|
1090
|
+
*/
|
|
1091
|
+
/**
|
|
1092
|
+
* The address of the client a service-to-service call is made on behalf of.
|
|
1093
|
+
*
|
|
1094
|
+
* An API asking its auth server for a session sends the client's address in
|
|
1095
|
+
* this rather than `X-Forwarded-For`: a forwarding header marks a request as
|
|
1096
|
+
* outside traffic, which would start the auth server's span in a new trace,
|
|
1097
|
+
* and the address is still needed — Better Auth rate-limits per client.
|
|
1098
|
+
*
|
|
1099
|
+
* Reserved: the stack's edge (Caddy, Traefik, the `gkm dev` edge) removes it
|
|
1100
|
+
* from incoming requests, and the auth server ignores it on any request that
|
|
1101
|
+
* is not an internal caller's, so it cannot be spoofed from outside.
|
|
1102
|
+
*/
|
|
1103
|
+
export declare const CLIENT_IP_HEADER = "x-gkm-client-ip";
|
|
1104
|
+
//#endregion
|
|
1083
1105
|
//#region src/migrations.d.ts
|
|
1084
1106
|
/** Where every construct's folder lives, from the project root. */
|
|
1085
1107
|
export declare const MIGRATIONS_ROOT = "db";
|