@geekmidas/manifest 9.0.2 → 10.0.0-alpha.1

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.d.cts CHANGED
@@ -1,22 +1,1071 @@
1
- //#region src/index.d.ts
1
+ //#region src/declaration.d.ts
2
+ /**
3
+ * The construct manifest — the contract between what an application declares
4
+ * and what a target adapter provisions.
5
+ *
6
+ * Kinds are added here as each one lands, not up front: a declaration for a
7
+ * construct nobody has built yet is a guess that the implementation will
8
+ * contradict. See `docs/design/constructs-paradigm.md`.
9
+ */
10
+ /**
11
+ * A construct's canonical id — PascalCase, unique within the manifest.
12
+ *
13
+ * Inputs canonicalise, so `uploads`, `Uploads`, `user_uploads`, and
14
+ * `user-uploads` are the *same* id rather than four that collide. Everything
15
+ * else derives from it: the service key is its `Uncapitalize`, the env prefix
16
+ * its SCREAMING_SNAKE form, the cloud name its kebab form scoped by stage and
17
+ * app.
18
+ */
19
+ type ConstructId = string;
20
+ type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
21
+ /**
22
+ * Constrains a construct name at the point it is written.
23
+ *
24
+ * Resolves to the name itself when valid, and otherwise to a string explaining
25
+ * why — so the compiler reports *"not assignable to type 'a construct name
26
+ * cannot start with a digit'"* rather than the unhelpful `never`.
27
+ *
28
+ * Only the cases a template-literal type can see are caught here; `canonicalId`
29
+ * enforces the rest at runtime, which is also what covers JavaScript callers.
30
+ *
31
+ * @example new ObjectStorage('Uploads') // ok
32
+ * @example new ObjectStorage('2fa') // a construct name cannot start with a digit
33
+ */
34
+ type ConstructName<S extends string> = S extends '' ? 'a construct name cannot be empty' : S extends `${Digit}${string}` ? 'a construct name cannot start with a digit' : S;
35
+ /** Shared by every declaration. */
36
+ interface Node {
37
+ id: ConstructId;
38
+ /**
39
+ * Env keys this construct resolves onto anything that depends on it.
40
+ * Names only — the values are composed by the adapter from the provisioned
41
+ * resource's own attributes.
42
+ */
43
+ provides?: readonly string[];
44
+ /**
45
+ * Env keys this construct needs. Derivable from `dependencies`, so it is an
46
+ * assertion rather than an input: the adapter composes env from the edges and
47
+ * checks the result against this, which catches app/infra drift at synth.
48
+ */
49
+ requires?: readonly string[];
50
+ }
51
+ /**
52
+ * A dependency edge. Records only *what* is depended on — never permissions.
53
+ * From one edge the framework derives env and the runtime binding; a target
54
+ * adapter separately derives cloud access.
55
+ */
56
+ interface Dependency<TTarget extends ConstructId = ConstructId> {
57
+ /**
58
+ * The {@link ConstructId} of the consumed construct. Left open here because a
59
+ * declaration is written before the manifest that contains it; once assembled,
60
+ * `IdsOf` narrows it and the build's reference-integrity check enforces it.
61
+ */
62
+ target: TTarget;
63
+ kind: DeclarationKind;
64
+ }
65
+ /** Anything with a handler. */
66
+ interface Fn extends Node {
67
+ handler: string;
68
+ dependencies: readonly Dependency[];
69
+ }
70
+ /** Blob storage. `--target=aws` provisions a bucket. */
71
+ interface ObjectsDeclaration extends Node {
72
+ kind: 'objects';
73
+ versioned?: boolean;
74
+ }
75
+ /**
76
+ * A domain that serves a bucket's objects.
77
+ *
78
+ * Its own construct rather than a flag on the bucket, because three things it
79
+ * has to express are not properties of a bucket: a surface can front several
80
+ * origins, a bucket can have several surfaces over it, and issuing a
81
+ * certificate and writing a DNS record is a domain lifecycle that has no
82
+ * business living inside an `objects` provisioner. It shares its infrastructure
83
+ * with a static site rather than with storage — a site is the same
84
+ * distribution over a build output instead of over live contents.
85
+ *
86
+ * It derives from the bucket by `of`, which costs the one thing the flag gave
87
+ * for free: the bucket alone no longer says whether it is served, and finding
88
+ * out means finding whoever points at it. That is answered the way every other
89
+ * derivation is — the reference check at manifest build, so an unresolvable
90
+ * origin is a build failure and `gkm` can name, for any bucket, the surfaces
91
+ * over it.
92
+ *
93
+ * Private by default. `open` is an exception list, because a bucket where
94
+ * forgetting a flag publishes user uploads is the wrong default — and paths
95
+ * rather than per-object flags, because a path pattern is what the
96
+ * infrastructure actually enforces and a per-object ACL is a thing nobody
97
+ * audits.
98
+ *
99
+ * "Open" never means the bucket is world-readable. It means the server serves
100
+ * that path without a signature; the bucket is private in both cases.
101
+ */
102
+ interface FileServerDeclaration extends Node {
103
+ kind: 'file-server';
104
+ /** The bucket whose objects it serves. */
105
+ of: ConstructId;
106
+ /**
107
+ * Paths served without a signature — everything else requires one.
108
+ *
109
+ * Globs, matched most-literally by the infrastructure: a CDN keys its
110
+ * behaviours off path patterns, and a bucket policy names prefixes.
111
+ */
112
+ open?: readonly string[];
113
+ }
114
+ /**
115
+ * Outbound email.
116
+ *
117
+ * Provides one `smtp://` URL and nothing else, because email is delivered over
118
+ * SMTP whatever the provider — Mailpit locally, SES through its SMTP interface,
119
+ * Resend and Postmark through theirs. There is no `provider` field here for the
120
+ * same reason there is no `ses://` scheme: which service delivers the mail
121
+ * differs between dev and prod, so by this design's own test it is stage-varying
122
+ * config rather than a structural fact about the app.
123
+ *
124
+ * What *is* structural is only that the app sends mail at all. The sending
125
+ * domain is not: it is `myapp.test` locally and `example.com` deployed, so it
126
+ * fails the same test the provider does and resolves at deploy alongside every
127
+ * other address.
128
+ */
129
+ interface EmailDeclaration extends Node {
130
+ kind: 'email';
131
+ }
132
+ /**
133
+ * A logical database, its schema, and the roles that reach it.
134
+ *
135
+ * Provides one key — the *runtime* role's URL. The owner URL exists but is
136
+ * deliberately absent from `provides`: it is wired by the adapter straight into
137
+ * the migrator and seeder this construct declares, so no edge in any manifest
138
+ * can name it and nothing else can be granted it by mistake.
139
+ */
2
140
  /**
3
- * Deployment manifest types — the build output of `gkm build` that enumerates a
4
- * project's deployable units (routes, functions, crons, subscribers, queues)
5
- * with the metadata an infrastructure layer needs to provision them.
141
+ * The Postgres major versions this toolbox provisions.
6
142
  *
7
- * `gkm build` writes a single TypeScript module per provider
8
- * (`<out>/manifest/aws.ts`) of the form:
143
+ * A union rather than a string, because the two targets that read it are not
144
+ * equally forgiving: locally it becomes a container tag, where a typo yields a
145
+ * confusing pull failure, and on AWS it becomes an engine version, where a
146
+ * wrong value fails partway through a deploy. Both are better as a compile
147
+ * error.
148
+ *
149
+ * The union is what this toolbox knows how to name, not a promise that every
150
+ * target offers every one of them. A deployed stage is limited by the engine
151
+ * catalogue in its region, so check before pinning an unusual version:
152
+ *
153
+ * ```
154
+ * aws rds describe-db-engine-versions --engine postgres \
155
+ * --query 'DBEngineVersions[].EngineVersion' --output text
156
+ * ```
157
+ *
158
+ * RDS offered 11 through 18 in `eu-west-1` when this was written. 11 and 12 are
159
+ * left out because they are past upstream end-of-life: still provisionable, but
160
+ * not something to make easy to reach for.
161
+ */
162
+ type PostgresVersion = 13 | 14 | 15 | 16 | 17 | 18;
163
+ /**
164
+ * The version used when a database names none.
165
+ *
166
+ * The point is not which number this is but that there is only one of them.
167
+ * Local ran 18 while Aurora provisioned its own default of 17.7, and nothing in
168
+ * any declaration recorded the difference — a stage could behave differently
169
+ * from a developer's machine for a reason neither could see. Both now read
170
+ * this.
171
+ */
172
+ declare const DEFAULT_POSTGRES_VERSION: PostgresVersion;
173
+ interface DatabaseDeclaration extends Node {
174
+ kind: 'database';
175
+ engine?: 'postgres';
176
+ /**
177
+ * The engine's major version, read by every target that provisions one.
178
+ *
179
+ * Declared rather than configured per target, because a version set in a
180
+ * compose file and a version set in a deploy config are two statements of
181
+ * one fact — and they had already drifted apart, silently, by a major.
182
+ *
183
+ * Defaults to {@link DEFAULT_POSTGRES_VERSION}.
184
+ */
185
+ version?: PostgresVersion;
186
+ /**
187
+ * The schema, pinned on both roles' `search_path`. Names the role the schema
188
+ * plays rather than restating the database's own name, so `app` reads
189
+ * correctly beside `auth` and `pgboss`.
190
+ */
191
+ schema?: string;
192
+ /**
193
+ * Whether to provision the owner/runtime role split. Off falls back to the
194
+ * cluster's master credential in both URLs — a deliberate downgrade, not a
195
+ * default. See `roles: false` in the design doc.
196
+ */
197
+ roles?: boolean;
198
+ }
199
+ /**
200
+ * A read-only endpoint on an existing database or schema.
201
+ *
202
+ * Provisions no cluster of its own — `of` names the parent it reads from.
203
+ * Read-only is enforced by the role's grants rather than by which endpoint it
204
+ * resolves to, so falling back to the writer where no replica exists stays safe.
205
+ */
206
+ interface DatabaseReaderDeclaration extends Node {
207
+ kind: 'database-reader';
208
+ of: ConstructId;
209
+ }
210
+ /**
211
+ * A second schema inside an existing database, with its own role(s) and URL.
212
+ *
213
+ * The mechanism behind tenancy: the parent's role holds no grant on these
214
+ * tables at all. pg-boss is an instance of this rather than a special case.
215
+ */
216
+ interface DatabaseSchemaDeclaration extends Node {
217
+ kind: 'database-schema';
218
+ of: ConstructId;
219
+ schema: string;
220
+ }
221
+ /**
222
+ * A generated secret — a signing key, a token, anything with no address.
223
+ *
224
+ * It provides a value rather than a URL, which is why it is a node of its own
225
+ * instead of a field on whatever needs it: the thing that generates it, the
226
+ * thing that stores it, and the thing that reads it are three different systems
227
+ * deployed, and one derived string locally.
228
+ */
229
+ interface SecretDeclaration extends Node {
230
+ kind: 'secret';
231
+ }
232
+ /**
233
+ * A third-party credential with a shape.
234
+ *
235
+ * Distinct from {@link SecretDeclaration} by *lifecycle*, which is the only
236
+ * distinction worth having two kinds for. A secret is generated and rotated by
237
+ * the platform — `gkm secrets`, `sst secret set` — and is one opaque string
238
+ * whose name is its key. A credential is issued by someone else, arrives with
239
+ * several fields, and is validated on the way in: a Stripe key pair, an OAuth
240
+ * client, a webhook signing secret.
241
+ *
242
+ * It provides one key holding a JSON object, rather than one key per field.
243
+ * That is what a secret manager actually stores, and it is also the only shape
244
+ * that works with an arbitrary StandardSchema — the spec has no introspection
245
+ * API, so enumerating a schema's fields means reaching into one library's
246
+ * internals and being wrong for every other.
247
+ */
248
+ interface CredentialDeclaration extends Node {
249
+ kind: 'credential';
250
+ }
251
+ /**
252
+ * An identity provider somebody else runs.
253
+ *
254
+ * Provisions nothing — the issuer already exists — so a target's whole job is
255
+ * to hand the process an issuer and an audience, and the verifier discovers the
256
+ * rest at runtime.
257
+ *
258
+ * It is a node rather than a field on whatever authenticates through it because
259
+ * two surfaces can name the same provider, and because *which* population a
260
+ * surface admits is a fact worth reading off the graph: an admin console
261
+ * authenticated by the customer auth server is a finding, and it is only
262
+ * visible if both are declarations.
263
+ */
264
+ interface OidcDeclaration extends Node {
265
+ kind: 'oidc';
266
+ /**
267
+ * The issuer, when it does not vary by deployment.
268
+ *
269
+ * Absent means it arrives in the environment instead — a staging tenant, a
270
+ * per-customer directory. The audience is never here: it identifies one
271
+ * deployment to the provider.
272
+ */
273
+ issuer?: string;
274
+ }
275
+ /**
276
+ * A key/value cache.
277
+ *
278
+ * Provides one URL. What is *in* that URL is the backend's business — Upstash's
279
+ * REST API, a Redis endpoint, or a table in a database — and the scheme is what
280
+ * picks the client, exactly as it does for object storage.
281
+ *
282
+ * Two ways to declare one, and the difference is a real statement rather than a
283
+ * spelling. `new Cache('Sessions')` says *this app caches*, leaving where to the
284
+ * deployment; `orders.cache('Sessions')` says *this app caches in that
285
+ * database*, which is a fact about the application and belongs in its code. The
286
+ * second is the same strengthening `orders.schema('AuthDb')` is over declaring a
287
+ * second database.
288
+ */
289
+ interface CacheDeclaration extends Node {
290
+ kind: 'cache';
291
+ /**
292
+ * The database this cache lives in, when it lives in one.
293
+ *
294
+ * Present only for a cache derived from a database. It removes a guess the
295
+ * backend selection otherwise has to make — "the declared database" is
296
+ * unambiguous with one and arbitrary with two — and it means the table's
297
+ * schema and the role that reaches it come from the parent rather than from
298
+ * a second convention.
299
+ */
300
+ of?: ConstructId;
301
+ /**
302
+ * The table entries are kept in, resolved against the connection's
303
+ * `search_path`. Defaults to `cache`.
304
+ */
305
+ table?: string;
306
+ }
307
+ /**
308
+ * An HTTP surface and the handlers mounted on it.
309
+ *
310
+ * The first kind that is not a resource in the ordinary sense: it owns an
311
+ * address, and the functions it triggers are *nested inside it* rather than
312
+ * listed beside it, because position carries the trigger — a handler here is
313
+ * reached by its method and path and by nothing else.
314
+ *
315
+ * `authorizers` are names. A bare string is resolved by the target (`iam`), while
316
+ * a {@link ConstructId} names a construct that carries its own implementation,
317
+ * its database dependency, and its session typing.
318
+ */
319
+ interface RestApiDeclaration extends Node {
320
+ kind: 'rest-api';
321
+ /**
322
+ * Where the process serving it is built from, relative to the workspace
323
+ * root — the same thing a `site` says, for the same reason.
324
+ *
325
+ * A surface is a deploy unit: one of these is one server. Without it the
326
+ * deploy had to ask the *config* which apps to build, and a surface could
327
+ * never be its own process because it was not in that list. Two surfaces in
328
+ * one app then had to share one container, which is how an auth server ended
329
+ * up mounted into an API by a hook.
330
+ *
331
+ * Optional, and its absence is meaningful: a surface with no app of its own
332
+ * is served by the surface that named it — an auth server mounted into the
333
+ * API that called `.auth()` on it, rather than a second container nobody
334
+ * asked for.
335
+ */
336
+ app?: AppSpec;
337
+ /**
338
+ * The construct that authenticates this surface.
339
+ *
340
+ * An edge like any other — so the auth server learns this surface's origin,
341
+ * and the two share a cookie domain — but a *named* one, because "who
342
+ * authenticates me" is a different fact from "who I happen to call", and
343
+ * only one of them decides what a request is allowed to be.
344
+ *
345
+ * It is the id rather than the client: what every endpoint consumes is
346
+ * `verify(request) → Session | null`, and that is the one thing every
347
+ * provider shares. A surface names its authenticator; the target decides
348
+ * what verifying means.
349
+ */
350
+ auth?: ConstructId;
351
+ /**
352
+ * CORS tunables for this surface.
353
+ *
354
+ * *Who* may call it is never here — that is derived from the constructs
355
+ * declaring an edge to this surface, and arrives as `<ID>_TRUSTED_ORIGINS`.
356
+ * A hand-written origin list is the thing this model removes; these are the
357
+ * knobs that genuinely cannot be derived from a graph.
358
+ *
359
+ * Omitted entirely, a surface still gets CORS — with the derived origins and
360
+ * sensible defaults. There is nothing to opt into.
361
+ */
362
+ cors?: {
363
+ /** Preflight cache lifetime in seconds. Default 86400. */
364
+ maxAge?: number;
365
+ /** Whether the browser may send credentials. Default true. */
366
+ credentials?: boolean;
367
+ /** Extra request headers to allow, beyond content-type and authorization. */
368
+ allowHeaders?: readonly string[];
369
+ /** Response headers the browser may read. */
370
+ exposeHeaders?: readonly string[];
371
+ };
372
+ authorizers?: readonly string[];
373
+ /** The authorizer applied where an endpoint names none. */
374
+ defaultAuthorizer?: string;
375
+ /**
376
+ * Every route on this surface.
377
+ *
378
+ * Complete, always — a manifest that says "the routes are over there, run
379
+ * this glob to find them" is not a manifest, it is a pointer to one. An
380
+ * earlier version carried a `routes` glob for an application's own API and
381
+ * left this empty, which meant the document *claimed no routes* while five
382
+ * existed. Being incomplete is a gap; being wrong is worse.
383
+ *
384
+ * So a surface takes its endpoints as a list and reads method, path and
385
+ * handler off them. That also removes a duplicate: the glob was written once
386
+ * in `gkm.config.ts` and again on the construct, two strings that could
387
+ * disagree about the same thing.
388
+ */
389
+ endpoints: readonly RestApiEndpoint[];
390
+ /**
391
+ * Other surfaces this one calls.
392
+ *
393
+ * **Not a dependency, and deliberately not spelled like one.** A dependency
394
+ * is an injection: `resolveEdges` gives a function exactly the constructs it
395
+ * declared and nothing else, which is what makes least privilege fall out of
396
+ * the graph instead of out of discipline. A surface-level `dependencies`
397
+ * would hand *every route* on this API whatever the surface named — which is
398
+ * precisely the over-granting that rule exists to prevent.
399
+ *
400
+ * What this records is weaker and only flows one way: it puts this API's
401
+ * origin on the called surface's trusted-origin list. Nothing links from it,
402
+ * nothing is granted by it, and per-route edges stay on the endpoints where
403
+ * they belong.
404
+ */
405
+ calls?: readonly Dependency[];
406
+ }
407
+ /** One glob, or several. Mirrors the CLI's `Routes` without depending on it. */
408
+ type Glob = string | readonly string[];
409
+ /**
410
+ * How the process serving a declaration is built and run.
411
+ *
412
+ * The half of an application that a graph genuinely cannot derive. *What*
413
+ * exists — a surface, a site, the edges between them — is declared and read
414
+ * back from the manifest. *Where its source lives and which globs find its
415
+ * code* is not derivable from anything: it is a fact about a directory.
416
+ *
417
+ * It lives on the declaration rather than in a config `apps` block because the
418
+ * two were the same list written twice, and the copy in config was the one that
419
+ * could disagree. A site declared `path: 'apps/web'` and an app entry declared
420
+ * `path: 'apps/web'`, and nothing checked them against each other; a surface
421
+ * that config had no entry for simply never deployed.
422
+ *
423
+ * Only the declaration that *is* an app carries one. Two surfaces in one
424
+ * process means one of them has the spec and the other collapses onto it —
425
+ * which is the same rule that decides deploy units, now stated once.
426
+ */
427
+ /**
428
+ * Where an app's code lives when nobody says otherwise.
429
+ *
430
+ * One glob, every kind — the same rule the `constructs` glob follows. A handler
431
+ * in one of these directories is found; anywhere else needs a `code` glob, and
432
+ * saying so is the whole reason the field still exists.
433
+ */
434
+ declare const DEFAULT_APP_CODE = "./{endpoints,functions,crons,queues,topics,subscribers}/**/*.ts";
435
+ interface AppSpec {
436
+ /**
437
+ * Where its source lives, relative to the workspace root.
438
+ *
439
+ * Optional, and normally omitted: `apps/<kebab-id>` when that directory
440
+ * exists, and the workspace root otherwise. An `Api` construct in a
441
+ * monorepo means `apps/api`, and in a single-app project it means `.` —
442
+ * both of which are answerable by looking, which is why neither was worth
443
+ * making someone write down.
444
+ *
445
+ * Set one only when the layout is genuinely different, e.g.
446
+ * `path: 'services/api'`.
447
+ */
448
+ path?: string;
449
+ /**
450
+ * The port it answers on locally.
451
+ *
452
+ * Optional, and normally omitted: ports are assigned in a stable order so
453
+ * that adding a site does not renumber the others. Set one only when
454
+ * something outside the workspace has to know it in advance.
455
+ */
456
+ port?: number;
457
+ /**
458
+ * One glob that finds everything this app defines, relative to `path`.
459
+ *
460
+ * Every export of every matching module is inspected, and each kind is
461
+ * picked out by whatever recognises it — the same rule the `constructs`
462
+ * glob already follows. A glob per kind was the specialness this model
463
+ * removes: five patterns that had to be kept in step, where a handler in the
464
+ * wrong directory simply never loaded and nothing said so.
465
+ *
466
+ * The per-kind fields below still work, and still win where both are given,
467
+ * because a single-app `defineConfig` has always been written that way.
468
+ *
469
+ * Optional, and normally omitted: the conventional directories under
470
+ * `path`, which is `DEFAULT_APP_CODE`. A glob is worth writing only when
471
+ * the code is somewhere else.
472
+ */
473
+ code?: Glob;
474
+ /** Globs that find one kind of thing. Prefer `code`. */
475
+ routes?: Glob;
476
+ functions?: Glob;
477
+ crons?: Glob;
478
+ queues?: Glob;
479
+ topics?: Glob;
480
+ subscribers?: Glob;
481
+ /** `./config/env#envParser` — module, optionally with an export. */
482
+ envParser?: string;
483
+ logger?: string;
484
+ telescope?: string | boolean | Record<string, unknown>;
485
+ studio?: string | boolean | Record<string, unknown>;
486
+ openapi?: boolean | Record<string, unknown>;
487
+ runtime?: 'node' | 'bun';
488
+ /** Env files to load, in order. */
489
+ env?: Glob;
490
+ /** Entry module for an app the build does not generate. */
491
+ entry?: string;
492
+ /** Modules to import when sniffing which env vars a frontend reads. */
493
+ config?: {
494
+ client?: string;
495
+ server?: string;
496
+ };
497
+ }
498
+ /**
499
+ * A frontend — a construct like any other, which is what removes the last
500
+ * mechanism that ran in parallel to the graph.
501
+ *
502
+ * Its edges are what make it worth declaring. A site depending on an API is the
503
+ * single fact behind four things that are hand-maintained otherwise: the site's
504
+ * build-time `VITE_API_URL`, the API's CORS origins, the auth server's trusted
505
+ * origins, and which generated client lands in which app. None of those are
506
+ * declared anywhere here, because all four are the *same* edge read from one
507
+ * end or the other.
508
+ *
509
+ * `variant` is the framework, because the framework changes the code you write:
510
+ * it selects how the values are delivered (`VITE_`, `NEXT_PUBLIC_`, a
511
+ * `config.json`), never which values there are.
512
+ */
513
+ interface SiteDeclaration extends Node {
514
+ kind: 'site';
515
+ variant: 'static' | 'next' | 'tanstack';
516
+ /**
517
+ * How it is built and run, `path` included.
518
+ *
519
+ * Required, where a surface's is optional: a site is always its own app.
520
+ * There is no arrangement in which two sites are one process.
521
+ */
522
+ app?: AppSpec;
523
+ /**
524
+ * Whether this is the site the base domain points at.
525
+ *
526
+ * Structural rather than config: *which* site is primary does not vary by
527
+ * stage, even though its hostname does — that is what `app.domain` is for.
528
+ *
529
+ * Only meaningful when a project has more than one site, and then only when
530
+ * none of them is named `web`. The convention still holds first, because it
531
+ * is a convention people already rely on.
532
+ */
533
+ root?: boolean;
534
+ /**
535
+ * What it calls. On a node rather than on a handler because a site has no
536
+ * single entrypoint — the whole app is the consumer.
537
+ */
538
+ dependencies: readonly Dependency[];
539
+ }
540
+ /** One route on a surface. */
541
+ interface RestApiEndpoint extends Fn {
542
+ method: string;
543
+ path: string;
544
+ authorizer?: string;
545
+ }
546
+ /**
547
+ * A point-to-point queue and the single consumer that drains it.
548
+ *
549
+ * Provides one key, the producer's connection string. The protocol in it picks
550
+ * the transport — `pgboss://` locally, `sqs://` deployed — so a producer names
551
+ * no broker, exactly as a database consumer names no cloud.
552
+ *
553
+ * The consumer side provides nothing: a worker is reached *through* its queue,
554
+ * so there is no second key and nothing can depend on a handler.
555
+ */
556
+ interface QueueDeclaration extends Node {
557
+ kind: 'queue';
558
+ /** FIFO ordering, where the transport offers it. */
559
+ fifo?: boolean;
560
+ /**
561
+ * The single consumer that drains it.
562
+ *
563
+ * Nested rather than listed beside the queue, because **position carries the
564
+ * trigger**: a handler here is reached by messages arriving on this queue and
565
+ * by nothing else, so there is no `trigger` field to keep in step with it.
566
+ */
567
+ worker: Fn;
568
+ }
569
+ /**
570
+ * A topic — pub/sub fan-out, one publisher and any number of subscribers.
571
+ *
572
+ * Like a queue it provides only the producer's string; a subscriber is bound to
573
+ * the topic rather than depending on it, so the binding is an edge the deploy
574
+ * target reads, not an env key. Locally both sides meet on the same pg-boss
575
+ * connection, which is why the subscriber needs no key of its own.
576
+ */
577
+ interface TopicDeclaration extends Node {
578
+ kind: 'topic';
579
+ /** The event type names this topic carries. */
580
+ events: readonly string[];
581
+ /**
582
+ * The handlers bound to it, each with the events it wants.
583
+ *
584
+ * Nested for the same reason a queue's worker is: position is the trigger. A
585
+ * subscriber is *bound* to a topic rather than depending on it, which is why
586
+ * it holds no key of its own and cannot be reached except through the topic.
587
+ */
588
+ subscribers: readonly (Fn & {
589
+ events: readonly string[];
590
+ })[];
591
+ }
592
+ /**
593
+ * A function invoked directly, with no surface in front of it.
594
+ *
595
+ * An `Fn` rather than a `Node`, because a function *is* a handler — there is no
596
+ * resource beside it to declare. It provides its own address, so something else
597
+ * can depend on it and be given a way to call it.
598
+ */
599
+ interface FunctionDeclaration extends Fn {
600
+ kind: 'function';
601
+ }
602
+ /**
603
+ * A function on a schedule.
604
+ *
605
+ * The schedule is the trigger and it is structural: *that* something runs
606
+ * nightly is a fact about the application, while which timezone a stage
607
+ * interprets it in is not.
608
+ */
609
+ interface CronDeclaration extends Fn {
610
+ kind: 'cron';
611
+ /** A rate or cron expression, e.g. `rate(1 day)`. */
612
+ schedule: string;
613
+ }
614
+ /**
615
+ * Every declaration. A discriminated union, so `kind` gives exhaustiveness *and*
616
+ * per-kind fields — there is no separate enum to keep in step, and no shape
617
+ * carrying fields that belong to a different kind.
618
+ */
619
+ type Declaration = ObjectsDeclaration | FileServerDeclaration | EmailDeclaration | DatabaseDeclaration | DatabaseReaderDeclaration | DatabaseSchemaDeclaration | CacheDeclaration | SecretDeclaration | CredentialDeclaration | RestApiDeclaration | SiteDeclaration | OidcDeclaration | QueueDeclaration | TopicDeclaration | FunctionDeclaration | CronDeclaration;
620
+ /** A declaration that provisions nothing of its own and names a parent. */
621
+ /**
622
+ * A declaration that names a parent.
623
+ *
624
+ * A union rather than an `Extract`, because one kind is *optionally* derived: a
625
+ * cache lives in a database when it was declared from one and stands alone
626
+ * otherwise, so `of` is optional on it and an `Extract<…, { of: ConstructId }>`
627
+ * would not select it. {@link isDerived} tests the value rather than the kind
628
+ * for exactly that reason.
629
+ */
630
+ type DerivedDeclaration = Extract<Declaration, {
631
+ of: ConstructId;
632
+ }> | CacheDeclaration;
633
+ type DerivedKind = DerivedDeclaration['kind'];
634
+ /**
635
+ * What each kind may derive from.
636
+ *
637
+ * Small enough to state exhaustively, and stating it makes cycles impossible
638
+ * without a graph walk: readers are terminal, so no chain can return to its
639
+ * start. There is no `writer` — the database *is* the writer, which is what
640
+ * keeps a replica from being reached by accident.
641
+ */
642
+ declare const DERIVES_FROM: Readonly<Record<DerivedKind, readonly string[]>>;
643
+ type DeclarationKind = Declaration['kind'];
644
+ /**
645
+ * The manifest: every construct keyed by its id.
646
+ *
647
+ * Flat rather than grouped, because `Dependency.target` resolves as
648
+ * `m[target]` — a lookup that stays O(1) and identical whether the edge points
649
+ * at a resource, a surface, or another function.
650
+ *
651
+ * Use it as a **constraint, not an annotation**. `gkm build` emits
652
+ * `as const satisfies ConstructManifest`, which checks the shape while keeping
653
+ * every id, kind, and provided key a literal — annotating with this type
654
+ * instead would widen them all to `string` and consumers could no longer select
655
+ * anything:
9
656
  *
10
657
  * ```ts
11
- * export const manifest = { routes: [...], functions: [...], ... } as const;
12
- * export type Route = (typeof manifest.routes)[number];
13
- * // ...derived types
658
+ * export const manifest = {
659
+ * Uploads: { kind: 'objects', id: 'Uploads', provides: ['UPLOADS_URL'] },
660
+ * } as const satisfies ConstructManifest;
661
+ *
662
+ * type Ids = IdsOf<typeof manifest>; // 'Uploads'
663
+ * type Env = ProvidedKeys<typeof manifest, 'Uploads'>; // 'UPLOADS_URL'
14
664
  * ```
665
+ */
666
+ type ConstructManifest = Readonly<Record<ConstructId, Declaration>>;
667
+ /** Every id in a manifest. */
668
+ type IdsOf<M extends ConstructManifest> = Extract<keyof M, string>;
669
+ /** The declaration for one id. */
670
+ type DeclarationOf<M extends ConstructManifest, K extends IdsOf<M>> = M[K];
671
+ /** Every id of a given kind — what an adapter iterates when provisioning. */
672
+ type IdsOfKind<M extends ConstructManifest, K extends DeclarationKind> = { [Id in IdsOf<M>]: M[Id]['kind'] extends K ? Id : never }[IdsOf<M>];
673
+ /** The env keys one construct provides. */
674
+ type ProvidedKeys<M extends ConstructManifest, K extends IdsOf<M>> = M[K] extends {
675
+ provides: readonly (infer P)[];
676
+ } ? P : never;
677
+ /** Every env key any construct in the manifest provides. */
678
+ type AllProvidedKeys<M extends ConstructManifest> = { [Id in IdsOf<M>]: ProvidedKeys<M, Id> }[IdsOf<M>];
679
+ /**
680
+ * What each kind provides, by role rather than by provider syntax.
681
+ *
682
+ * This is the contract between the construct that declares a key and the cloud
683
+ * component that supplies its value — an interface rather than shared code,
684
+ * because a shared codec would have to contain `bucket` and `region`, and
685
+ * provider words in the neutral layer is the problem this design exists to fix.
686
+ *
687
+ * How a value is composed and parsed stays private to each provider pair, so
688
+ * `s3://` and `gs://` never appear here.
689
+ */
690
+ interface ProvidesByKind {
691
+ objects: {
692
+ url: string;
693
+ };
694
+ /** Where the served objects answer. Public: a browser is the point of it. */
695
+ 'file-server': {
696
+ url: string;
697
+ };
698
+ /**
699
+ * An `smtp://` URL, credentials included — never shippable — and the
700
+ * identity mail is sent from.
701
+ *
702
+ * The sending address is the one thing about mail that genuinely differs per
703
+ * stage (`myapp.test` locally, a verified domain deployed), so it travels
704
+ * beside the URL rather than being written into the construct.
705
+ */
706
+ email: {
707
+ url: string;
708
+ from: string;
709
+ };
710
+ /**
711
+ * One key, the runtime role's. The owner URL is not here by design — see
712
+ * {@link DatabaseDeclaration}.
713
+ */
714
+ database: {
715
+ url: string;
716
+ };
717
+ 'database-reader': {
718
+ url: string;
719
+ };
720
+ 'database-schema': {
721
+ url: string;
722
+ };
723
+ /** The endpoint and its token, in one string. */
724
+ cache: {
725
+ url: string;
726
+ };
727
+ /**
728
+ * Where the surface answers, who may call it, and the domain its cookies
729
+ * are scoped to.
730
+ *
731
+ * Only `url` is a fact about the surface itself. The other two are read off
732
+ * its *inbound* edges — every construct that depends on it — which is why a
733
+ * surface never lists its own callers: nothing enumerates the things that
734
+ * point at it, the graph already does.
735
+ *
736
+ * `trustedOrigins` and `cookieDomain` are one key each rather than a list
737
+ * and a structure, because both cross a process boundary as environment.
738
+ */
739
+ 'rest-api': {
740
+ url: string;
741
+ /** Comma-separated. Empty when nothing declares an edge to this surface. */
742
+ trustedOrigins: string;
743
+ /**
744
+ * The parent domain shared by the surface and its callers, leading dot
745
+ * included — `.example.com`. Absent where there is nothing to share:
746
+ * one host locally, unrelated hosts deployed.
747
+ */
748
+ cookieDomain: string;
749
+ };
750
+ /** The value itself. A secret has no address to hand out instead. */
751
+ secret: {
752
+ value: string;
753
+ };
754
+ /**
755
+ * The credential as one JSON object, parsed and validated by the construct
756
+ * that declared the schema.
757
+ */
758
+ credential: {
759
+ credential: string;
760
+ };
761
+ /**
762
+ * The producer's connection string. One key, not two: the consumer is
763
+ * reached through the queue rather than by an address of its own.
764
+ */
765
+ queue: {
766
+ publisherConnectionString: string;
767
+ };
768
+ topic: {
769
+ publisherConnectionString: string;
770
+ };
771
+ /** Where to invoke it — what lets something else depend on a function. */
772
+ function: {
773
+ url: string;
774
+ };
775
+ /** A cron is reached by its schedule and by nothing else, so it provides none. */
776
+ cron: Record<never, never>;
777
+ /** Where the site is served. Public for the same reason an API's is. */
778
+ site: {
779
+ url: string;
780
+ };
781
+ /**
782
+ * Where tokens come from and which audience they must carry.
783
+ *
784
+ * Two keys because the halves have different lifetimes: the issuer may be a
785
+ * fact about the product, the audience is always a fact about one
786
+ * deployment.
787
+ */
788
+ oidc: {
789
+ issuer: string;
790
+ audience: string;
791
+ };
792
+ }
793
+ type Provides<K extends keyof ProvidesByKind> = ProvidesByKind[K];
794
+ /**
795
+ * Which provided values may be shipped to a browser.
796
+ *
797
+ * Drives client-side prefixing (`VITE_`, `NEXT_PUBLIC_`) and nothing else — it
798
+ * is not a restriction on what may be depended on, since a server-side consumer
799
+ * can legitimately use any of them. A bucket's `url` presigns and stays private.
800
+ */
801
+ declare const PUBLIC: { readonly [K in keyof ProvidesByKind]: readonly (keyof ProvidesByKind[K])[] };
802
+ //#endregion
803
+ //#region src/derive.d.ts
804
+ /** Whether a declaration names a parent. */
805
+ declare function isDerived(declaration: Declaration): declaration is DerivedDeclaration & {
806
+ of: ConstructId;
807
+ };
808
+ /**
809
+ * Check every derived construct against its parent.
810
+ *
811
+ * Two rules: the parent exists, and its kind may vend this one. Together they
812
+ * make cycles unreachable — a reader is terminal, so no chain of `of` can
813
+ * return to where it started, and no walk is needed to prove it.
814
+ */
815
+ declare function assertDerivations(manifest: ConstructManifest): void;
816
+ /**
817
+ * The order constructs must be provisioned in: every parent before its children.
818
+ *
819
+ * Resources are leaves and so come first in any order; only derived nodes
820
+ * constrain the sequence, and they form a shallow forest rather than a general
821
+ * graph. This walks each node's ancestors on demand instead of running a full
822
+ * topological sort, which is the same result at this depth and reads as what it
823
+ * is.
824
+ *
825
+ * Assumes {@link assertDerivations} has passed — a missing parent would
826
+ * otherwise be a silent omission here rather than an error.
827
+ */
828
+ declare function provisionOrder(manifest: ConstructManifest): string[];
829
+ /**
830
+ * Every edge a declaration carries, wherever the kind happens to keep them.
831
+ *
832
+ * Dependencies live in two places by design: on a node when the whole construct
833
+ * is the consumer (a site), and on each nested handler when the construct is a
834
+ * surface (a `rest-api`, whose routes each depend on their own things and
835
+ * nothing more). Flattening that difference here is what lets every consumer of
836
+ * the graph — reverse lookups, filtering, reference checks — ask one question.
837
+ */
838
+ declare function dependenciesOf(declaration: Declaration): readonly Dependency[];
839
+ /**
840
+ * The ids that depend on one construct — the graph read backwards.
841
+ *
842
+ * This is the whole mechanism behind CORS origins and trusted origins. Both are
843
+ * lists of *callers*, and a caller is exactly an inbound edge, so neither is
844
+ * ever written down: a surface that listed its own callers would have to be
845
+ * edited every time something new called it, which is the hand-maintained list
846
+ * this replaces.
847
+ *
848
+ * Sorted, because it feeds a comma-separated env value that would otherwise
849
+ * change whenever the manifest's key order did — and a value that churns is a
850
+ * container that redeploys for no reason.
851
+ */
852
+ declare function dependentsOf(manifest: ConstructManifest, id: ConstructId): string[];
853
+ /**
854
+ * How each site variant names a value it ships to the browser.
855
+ *
856
+ * The prefix *is* the framework's contract — `VITE_`, `NEXT_PUBLIC_` and
857
+ * `EXPO_PUBLIC_` all mean "inline this into the bundle" — so it is the one thing
858
+ * a variant changes, and it changes nothing else.
859
+ */
860
+ declare const PUBLIC_PREFIX: Record<SiteDeclaration['variant'], string>;
861
+ /**
862
+ * The keys a site's bundle needs, mapped to the key each value comes from —
863
+ * `{ VITE_API_URL: 'API_URL' }`.
864
+ *
865
+ * A rename, not a second derivation: `API_URL` is resolved once, by whatever
866
+ * resolved it for the server, and the site reads the same value under the name
867
+ * its bundler will inline. That is what keeps a site and its API from coming to
868
+ * disagree about where the API is.
869
+ *
870
+ * Filtered by `PUBLIC` rather than by what the site asked for. A site may
871
+ * legitimately depend on anything — its server half, where it has one, reads env
872
+ * exactly as a function does — so this is not a restriction on edges. It decides
873
+ * one thing: which values may be prefixed into a bundle, which is what keeps
874
+ * `ORDERS_URL` and its password out of a JavaScript file served to the public.
875
+ *
876
+ * Shared by every target for the same reason `providedKeyFor` is: a site built
877
+ * locally and the same site built by a deploy must inline the same names.
878
+ */
879
+ declare function publicEnvFor(declaration: SiteDeclaration, manifest: ConstructManifest): Record<string, string>;
880
+ //# sourceMappingURL=derive.d.ts.map
881
+ //#endregion
882
+ //#region src/errors.d.ts
883
+ /**
884
+ * Manifest errors.
15
885
  *
16
- * This is the dependency-free data contract shared between the producer
17
- * (`@geekmidas/cli`) and consumers (e.g. `@geekmidas/cloud/sst`'s `fromManifest`
18
- * integrators).
886
+ * Messages state the rule, which is constant; the offending value is a field.
887
+ * An interpolated message cannot be matched on, reads differently every time it
888
+ * is thrown, and carries user input into every log line that touches it.
19
889
  */
890
+ /** A construct id that cannot survive the names derived from it. */
891
+ declare class InvalidConstructId extends Error {
892
+ /** What was passed in. */
893
+ readonly input: string;
894
+ /** What canonicalising it produced, which is what failed the rule. */
895
+ readonly canonical: string;
896
+ constructor(input: string, canonical: string);
897
+ }
898
+ /** A derived construct naming a parent the manifest does not contain. */
899
+ declare class UnknownParent extends Error {
900
+ /** The derived construct. */
901
+ readonly id: string;
902
+ /** The parent it named. */
903
+ readonly of: string;
904
+ /** Ids the manifest does contain, for the caller to match against. */
905
+ readonly available: readonly string[];
906
+ constructor(id: string, of: string, available: readonly string[]);
907
+ }
908
+ /**
909
+ * A derived construct naming a parent that may not vend it — a reader of a
910
+ * reader, a schema of a schema.
911
+ */
912
+ declare class IllegalDerivation extends Error {
913
+ readonly id: string;
914
+ readonly kind: string;
915
+ /** The kind of the parent it named. */
916
+ readonly parentKind: string;
917
+ /** The parent kinds that may vend this one. */
918
+ readonly allowed: readonly string[];
919
+ constructor(id: string, kind: string, parentKind: string, allowed: readonly string[]);
920
+ }
921
+ //# sourceMappingURL=errors.d.ts.map
922
+ //#endregion
923
+ //#region src/naming.d.ts
924
+ /**
925
+ * `UPPER_SNAKE_CASE`, with numbers kept against the word they follow.
926
+ *
927
+ * Matches `environmentCase` in `@geekmidas/envkit`, which reads the values these
928
+ * names key. The two must agree exactly, so this is the implementation and that
929
+ * one should defer to it.
930
+ *
931
+ * @example environmentCase('sendEmail') // 'SEND_EMAIL'
932
+ * @example environmentCase('api2') // 'API2' (digit joins its word)
933
+ */
934
+ declare function environmentCase(name: string): string;
935
+ /**
936
+ * The env key a construct provides for one of its roles.
937
+ *
938
+ * @example provideKey('Uploads', 'url') // 'UPLOADS_URL'
939
+ * @example provideKey('Uploads', 'cdnUrl') // 'UPLOADS_CDN_URL'
940
+ */
941
+ declare function provideKey(id: string, role: string): string;
942
+ /**
943
+ * A construct's canonical id — PascalCase.
944
+ *
945
+ * `uploads`, `Uploads`, `user_uploads`, and `user-uploads` all canonicalise to
946
+ * the same id, so declaring two of them is a duplicate rather than a collision
947
+ * to detect.
948
+ *
949
+ * Runtime only. Writing the id in PascalCase is what keeps the *type* usable:
950
+ * the service key is `Uncapitalize<TName>`, a TypeScript intrinsic, so no
951
+ * type-level transform is needed and none has to be kept in step with this one.
952
+ *
953
+ * @example canonicalId('user-uploads') // 'UserUploads'
954
+ */
955
+ declare function canonicalId(input: string): string;
956
+ /**
957
+ * The key a construct is reached under in the service record.
958
+ *
959
+ * The runtime twin of `Uncapitalize<TName>`, which types it — they must agree,
960
+ * so they live next to each other rather than being re-derived by each
961
+ * construct.
962
+ *
963
+ * @example serviceKey('UserUploads') // 'userUploads' → services.userUploads
964
+ */
965
+ declare function serviceKey(id: string): string;
966
+ /**
967
+ * The table a cache keeps its entries in, when nobody named one.
968
+ *
969
+ * Derived from the cache's own id rather than fixed at `cache`, because a
970
+ * database may hold more than one and two caches sharing a table share a
971
+ * keyspace — `orders.cache('Sessions')` and `orders.cache('Rates')` would
972
+ * silently read each other's entries and evict each other's keys.
973
+ *
974
+ * Prefixed rather than suffixed so every cache sorts together in `\dt`, and
975
+ * prefixed at all so a cache named for a thing the application also stores —
976
+ * `orders.cache('Users')` — cannot collide with the table holding that thing.
977
+ *
978
+ * Read by whoever composes the URL and by whoever creates the table, so both
979
+ * default the same way.
980
+ *
981
+ * @example cacheTable('Sessions') // 'cache_sessions'
982
+ */
983
+ declare function cacheTable(id: string): string;
984
+ /**
985
+ * Kebab-cases an identifier, acronym- and digit-aware.
986
+ *
987
+ * `userName` → `user-name`, `APIKey` → `api-key`, `S3Bucket` → `s3-bucket`.
988
+ *
989
+ * The last of those is why this is here rather than `snakecase(id)` with the
990
+ * underscores swapped: lodash splits a digit from the letter beside it, so
991
+ * `S3Bucket` became `s-3-bucket` on one provider and `s3-bucket` on the other.
992
+ * Two implementations of one rule, agreeing on every id anybody had tried.
993
+ *
994
+ * `environmentCase` already corrected for the same thing in the other
995
+ * direction — `api2` keeps its digit — so the two spellings of "kebab this id"
996
+ * in this file did not even agree with each other.
997
+ */
998
+ declare function kebabCase(value: string): string;
999
+ /**
1000
+ * The physical name a target provisions a construct under — lowercase kebab,
1001
+ * scoped so two stages or apps sharing an account cannot collide.
1002
+ *
1003
+ * **One rule, every provider.** A construct is named the same thing on AWS and
1004
+ * on Dokploy, which is what lets a name be read across them: `Database` in the
1005
+ * `production` stage of `kitchen-sink` is `production-kitchen-sink-database`
1006
+ * wherever it lands. The SST target's `prefixedName` is this function under
1007
+ * another signature and defers to it.
1008
+ *
1009
+ * Idempotent in its prefix: an id that already carries the scope is not given a
1010
+ * second one, so composing names cannot double up.
1011
+ *
1012
+ * @example cloudName({ stage: 'prod', app: 'myapp' }, 'UserUploads')
1013
+ * // 'prod-myapp-user-uploads'
1014
+ */
1015
+ declare function cloudName(scope: {
1016
+ stage: string;
1017
+ app: string;
1018
+ }, id: string): string;
1019
+ /**
1020
+ * {@link cloudName} for a caller that holds its scope as a list.
1021
+ *
1022
+ * The SST target's stacks add a segment of their own, so the prefix is not
1023
+ * always two parts — which is the only reason this signature exists.
1024
+ */
1025
+ declare function scopedName(scope: readonly string[], id: string): string;
1026
+ /**
1027
+ * The domain a cookie must be scoped to so a surface and its callers share it.
1028
+ *
1029
+ * Derived from the addresses rather than configured, for the same reason the
1030
+ * origins are: the set of things that talk to a surface is already in the graph,
1031
+ * and the domain they have in common is a fact about that set. Returned with the
1032
+ * leading dot a `Domain` attribute wants.
1033
+ *
1034
+ * Returns `undefined` when there is nothing to scope, which is the common case
1035
+ * and not a failure:
1036
+ *
1037
+ * - **One host.** Locally everything is `localhost` on different ports, and
1038
+ * cookies ignore the port — so a `Domain` would add nothing and `.localhost`
1039
+ * is not a domain a browser will accept.
1040
+ * - **Nothing in common.** Unrelated hosts cannot share a cookie at all, and
1041
+ * emitting the longest common suffix anyway would be a value that silently
1042
+ * fails to set.
1043
+ *
1044
+ * **The public-suffix limit, stated rather than discovered.** Two apps on
1045
+ * `a.vercel.app` and `b.vercel.app` share `.vercel.app`, which every browser
1046
+ * rejects because it is a registrable suffix rather than a registrable domain.
1047
+ * Resolving that correctly needs the Public Suffix List, which is a downloaded,
1048
+ * expiring dataset — so this requires at least two labels and otherwise trusts
1049
+ * the addresses, and the value stays overridable for the case it gets wrong.
1050
+ */
1051
+ declare function cookieDomain(urls: readonly string[]): string | undefined;
1052
+ /**
1053
+ * The env key a construct's provided role actually becomes.
1054
+ *
1055
+ * Almost always `provideKey(id, role)` — and `secret` is the exception, because
1056
+ * a secret's *name* is its key: `Auth` signs with `AUTH_SECRET`, which is also
1057
+ * what better-auth's own tooling looks for, and qualifying it by role would
1058
+ * produce `AUTH_SECRET_VALUE`.
1059
+ *
1060
+ * It lives here rather than in each target because two targets deriving the
1061
+ * same key separately is exactly the drift the app/infra contract check exists
1062
+ * to catch — and a check deriving the key differently from the thing it checks
1063
+ * cannot catch anything.
1064
+ */
1065
+ declare function providedKeyFor(id: string, kind: DeclarationKind, role: string): string;
1066
+ //# sourceMappingURL=naming.d.ts.map
1067
+ //#endregion
1068
+ //#region src/index.d.ts
20
1069
  /**
21
1070
  * A manifest field is either a flat list or, when the build is partitioned
22
1071
  * (e.g. by authorizer), an object keyed by partition name. Readonly-tolerant so
@@ -37,6 +1086,15 @@ interface RouteInfo {
37
1086
  memorySize?: number;
38
1087
  /** Required environment variables (a trailing `?` marks an optional var). */
39
1088
  environment?: readonly string[];
1089
+ /**
1090
+ * The constructs this handler declared an edge to, by id.
1091
+ *
1092
+ * What `.dependsOn()` was given, carried through the build so the manifest
1093
+ * records the edge rather than only its shadow. `environment` is that shadow —
1094
+ * the keys the handler reads — and it cannot be turned back into edges, which
1095
+ * is why both exist and only this one grants anything.
1096
+ */
1097
+ dependencies?: readonly string[];
40
1098
  /** Authorizer name: `none`, `iam`, or a declared authorizer. */
41
1099
  authorizer: string;
42
1100
  }
@@ -47,6 +1105,15 @@ interface FunctionInfo {
47
1105
  timeout?: number;
48
1106
  memorySize?: number;
49
1107
  environment?: readonly string[];
1108
+ /**
1109
+ * The constructs this handler declared an edge to, by id.
1110
+ *
1111
+ * What `.dependsOn()` was given, carried through the build so the manifest
1112
+ * records the edge rather than only its shadow. `environment` is that shadow —
1113
+ * the keys the handler reads — and it cannot be turned back into edges, which
1114
+ * is why both exist and only this one grants anything.
1115
+ */
1116
+ dependencies?: readonly string[];
50
1117
  }
51
1118
  /** A scheduled (cron) function. */
52
1119
  interface CronInfo {
@@ -57,6 +1124,15 @@ interface CronInfo {
57
1124
  timeout?: number;
58
1125
  memorySize?: number;
59
1126
  environment?: readonly string[];
1127
+ /**
1128
+ * The constructs this handler declared an edge to, by id.
1129
+ *
1130
+ * What `.dependsOn()` was given, carried through the build so the manifest
1131
+ * records the edge rather than only its shadow. `environment` is that shadow —
1132
+ * the keys the handler reads — and it cannot be turned back into edges, which
1133
+ * is why both exist and only this one grants anything.
1134
+ */
1135
+ dependencies?: readonly string[];
60
1136
  }
61
1137
  /** An event subscriber function (topic/queue resolved by `transport`). */
62
1138
  interface SubscriberInfo {
@@ -70,6 +1146,15 @@ interface SubscriberInfo {
70
1146
  timeout?: number;
71
1147
  memorySize?: number;
72
1148
  environment?: readonly string[];
1149
+ /**
1150
+ * The constructs this handler declared an edge to, by id.
1151
+ *
1152
+ * What `.dependsOn()` was given, carried through the build so the manifest
1153
+ * records the edge rather than only its shadow. `environment` is that shadow —
1154
+ * the keys the handler reads — and it cannot be turned back into edges, which
1155
+ * is why both exist and only this one grants anything.
1156
+ */
1157
+ dependencies?: readonly string[];
73
1158
  }
74
1159
  /**
75
1160
  * A pub/sub topic — fan-out. A *resource* (no handler): it declares the event
@@ -94,6 +1179,12 @@ interface QueueInfo {
94
1179
  timeout?: number;
95
1180
  memorySize?: number;
96
1181
  environment?: readonly string[];
1182
+ /**
1183
+ * The constructs the worker declared an edge to, by id.
1184
+ *
1185
+ * See {@link RouteInfo.dependencies} — same field, same reason.
1186
+ */
1187
+ dependencies?: readonly string[];
97
1188
  }
98
1189
  /**
99
1190
  * The full deployment manifest — the shape of `export const manifest` in a
@@ -109,6 +1200,7 @@ interface Manifest {
109
1200
  topics?: ManifestField<TopicInfo>;
110
1201
  }
111
1202
  //# sourceMappingURL=index.d.ts.map
1203
+
112
1204
  //#endregion
113
- export { CronInfo, FunctionInfo, Manifest, ManifestField, QueueInfo, RouteInfo, SubscriberInfo, TopicInfo, flattenManifestField };
1205
+ export { AllProvidedKeys, AppSpec, CacheDeclaration, ConstructId, ConstructManifest, ConstructName, CredentialDeclaration, CronDeclaration, CronInfo, DEFAULT_APP_CODE, DEFAULT_POSTGRES_VERSION, DERIVES_FROM, DatabaseDeclaration, DatabaseReaderDeclaration, DatabaseSchemaDeclaration, Declaration, DeclarationKind, DeclarationOf, Dependency, DerivedDeclaration, DerivedKind, EmailDeclaration, FileServerDeclaration, Fn, FunctionDeclaration, FunctionInfo, Glob, IdsOf, IdsOfKind, IllegalDerivation, InvalidConstructId, Manifest, ManifestField, Node, ObjectsDeclaration, OidcDeclaration, PUBLIC, PUBLIC_PREFIX, PostgresVersion, ProvidedKeys, Provides, ProvidesByKind, QueueDeclaration, QueueInfo, RestApiDeclaration, RestApiEndpoint, RouteInfo, SecretDeclaration, SiteDeclaration, SubscriberInfo, TopicDeclaration, TopicInfo, UnknownParent, assertDerivations, cacheTable, canonicalId, cloudName, cookieDomain, dependenciesOf, dependentsOf, environmentCase, flattenManifestField, isDerived, kebabCase, provideKey, providedKeyFor, provisionOrder, publicEnvFor, scopedName, serviceKey };
114
1206
  //# sourceMappingURL=index.d.cts.map