@geekmidas/manifest 10.0.0-alpha.1 → 10.0.0-alpha.100

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 CHANGED
@@ -1,13 +1,12 @@
1
- //#region rolldown:runtime
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
7
  var __getProtoOf = Object.getPrototypeOf;
7
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __commonJS = (cb, mod) => function() {
9
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
- };
9
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
11
10
  var __copyProps = (to, from, except, desc) => {
12
11
  if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
13
12
  key = keys[i];
@@ -18,13 +17,11 @@ var __copyProps = (to, from, except, desc) => {
18
17
  }
19
18
  return to;
20
19
  };
21
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
22
21
  value: mod,
23
22
  enumerable: true
24
23
  }) : target, mod));
25
-
26
24
  //#endregion
27
-
28
25
  //#region src/declaration.ts
29
26
  /**
30
27
  * The version used when a database names none.
@@ -37,31 +34,18 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
37
34
  */
38
35
  const DEFAULT_POSTGRES_VERSION = 18;
39
36
  /**
40
- * How the process serving a declaration is built and run.
41
- *
42
- * The half of an application that a graph genuinely cannot derive. *What*
43
- * exists — a surface, a site, the edges between them — is declared and read
44
- * back from the manifest. *Where its source lives and which globs find its
45
- * code* is not derivable from anything: it is a fact about a directory.
46
- *
47
- * It lives on the declaration rather than in a config `apps` block because the
48
- * two were the same list written twice, and the copy in config was the one that
49
- * could disagree. A site declared `path: 'apps/web'` and an app entry declared
50
- * `path: 'apps/web'`, and nothing checked them against each other; a surface
51
- * that config had no entry for simply never deployed.
52
- *
53
- * Only the declaration that *is* an app carries one. Two surfaces in one
54
- * process means one of them has the spec and the other collapses onto it —
55
- * which is the same rule that decides deploy units, now stated once.
56
- */
57
- /**
58
- * Where an app's code lives when nobody says otherwise.
37
+ * What a `Telemetry` node provides to each process with an edge to it.
59
38
  *
60
- * One glob, every kind — the same rule the `constructs` glob follows. A handler
61
- * in one of these directories is found; anywhere else needs a `code` glob, and
62
- * saying so is the whole reason the field still exists.
39
+ * `OTEL_SERVICE_NAME` is resolved per process — the app's name — so it is
40
+ * listed here but composed by whichever target hands it over.
63
41
  */
64
- const DEFAULT_APP_CODE = "./{endpoints,functions,crons,queues,topics,subscribers}/**/*.ts";
42
+ const TELEMETRY_KEYS = [
43
+ "OTEL_EXPORTER_OTLP_ENDPOINT",
44
+ "OTEL_EXPORTER_OTLP_HEADERS",
45
+ "OTEL_SERVICE_NAME",
46
+ "OTEL_TRACES_SAMPLER",
47
+ "OTEL_TRACES_SAMPLER_ARG"
48
+ ];
65
49
  /**
66
50
  * What each kind may derive from.
67
51
  *
@@ -86,22 +70,26 @@ const DERIVES_FROM = {
86
70
  const PUBLIC = {
87
71
  objects: [],
88
72
  "file-server": ["url"],
89
- email: [],
73
+ email: ["inboxUrl"],
90
74
  database: [],
91
75
  "database-reader": [],
92
76
  "database-schema": [],
93
77
  cache: [],
94
78
  secret: [],
95
79
  credential: [],
80
+ encryption: [],
96
81
  "rest-api": ["url"],
97
82
  queue: [],
98
83
  topic: [],
99
84
  oidc: ["issuer", "audience"],
85
+ "external-api": [],
100
86
  function: [],
101
87
  cron: [],
102
- site: ["url"]
88
+ "mobile-app": [],
89
+ site: ["url"],
90
+ worker: [],
91
+ telemetry: []
103
92
  };
104
-
105
93
  //#endregion
106
94
  //#region src/errors.ts
107
95
  /**
@@ -160,20 +148,9 @@ var IllegalDerivation = class extends Error {
160
148
  this.allowed = allowed;
161
149
  }
162
150
  };
163
-
164
151
  //#endregion
165
- //#region ../../node_modules/.pnpm/lodash.snakecase@4.1.1/node_modules/lodash.snakecase/index.js
166
- var require_lodash = __commonJS({ "../../node_modules/.pnpm/lodash.snakecase@4.1.1/node_modules/lodash.snakecase/index.js"(exports, module) {
167
- /**
168
- * lodash (Custom Build) <https://lodash.com/>
169
- * Build: `lodash modularize exports="npm" -o ./`
170
- * Copyright jQuery Foundation and other contributors <https://jquery.org/>
171
- * Released under MIT license <https://lodash.com/license>
172
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
173
- * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
174
- */
175
- /** Used as references for various `Number` constants. */
176
- var INFINITY = Infinity;
152
+ //#region src/naming.ts
153
+ var import_lodash_snakecase = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
177
154
  /** `Object#toString` result references. */
178
155
  var symbolTag = "[object Symbol]";
179
156
  /** Used to match words composed of alphanumeric characters. */
@@ -181,15 +158,46 @@ var require_lodash = __commonJS({ "../../node_modules/.pnpm/lodash.snakecase@4.1
181
158
  /** Used to match Latin Unicode letters (excluding mathematical operators). */
182
159
  var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
183
160
  /** Used to compose unicode character classes. */
184
- var rsAstralRange = "\\ud800-\\udfff", rsComboMarksRange = "\\u0300-\\u036f\\ufe20-\\ufe23", rsComboSymbolsRange = "\\u20d0-\\u20f0", rsDingbatRange = "\\u2700-\\u27bf", rsLowerRange = "a-z\\xdf-\\xf6\\xf8-\\xff", rsMathOpRange = "\\xac\\xb1\\xd7\\xf7", rsNonCharRange = "\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf", rsPunctuationRange = "\\u2000-\\u206f", 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", rsUpperRange = "A-Z\\xc0-\\xd6\\xd8-\\xde", rsVarRange = "\\ufe0e\\ufe0f", rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
161
+ var rsAstralRange = "\\ud800-\\udfff";
162
+ var rsComboMarksRange = "\\u0300-\\u036f\\ufe20-\\ufe23";
163
+ var rsComboSymbolsRange = "\\u20d0-\\u20f0";
164
+ var rsDingbatRange = "\\u2700-\\u27bf";
165
+ var rsLowerRange = "a-z\\xdf-\\xf6\\xf8-\\xff";
166
+ var rsMathOpRange = "\\xac\\xb1\\xd7\\xf7";
167
+ var rsNonCharRange = "\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf";
168
+ var rsPunctuationRange = "\\u2000-\\u206f";
169
+ var 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";
170
+ var rsUpperRange = "A-Z\\xc0-\\xd6\\xd8-\\xde";
171
+ var rsVarRange = "\\ufe0e\\ufe0f";
172
+ var rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
185
173
  /** Used to compose unicode capture groups. */
186
- var rsApos = "['’]", rsBreak = "[" + rsBreakRange + "]", rsCombo = "[" + rsComboMarksRange + rsComboSymbolsRange + "]", rsDigits = "\\d+", rsDingbat = "[" + rsDingbatRange + "]", rsLower = "[" + rsLowerRange + "]", rsMisc = "[^" + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + "]", rsFitz = "\\ud83c[\\udffb-\\udfff]", rsModifier = "(?:" + rsCombo + "|" + rsFitz + ")", rsNonAstral = "[^" + rsAstralRange + "]", rsRegional = "(?:\\ud83c[\\udde6-\\uddff]){2}", rsSurrPair = "[\\ud800-\\udbff][\\udc00-\\udfff]", rsUpper = "[" + rsUpperRange + "]", rsZWJ = "\\u200d";
174
+ var rsApos = "['’]";
175
+ var rsBreak = "[" + rsBreakRange + "]";
176
+ var rsCombo = "[" + rsComboMarksRange + rsComboSymbolsRange + "]";
177
+ var rsDigits = "\\d+";
178
+ var rsDingbat = "[" + rsDingbatRange + "]";
179
+ var rsLower = "[" + rsLowerRange + "]";
180
+ var rsMisc = "[^" + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + "]";
181
+ var rsModifier = "(?:" + rsCombo + "|\\ud83c[\\udffb-\\udfff])";
182
+ var rsNonAstral = "[^" + rsAstralRange + "]";
183
+ var rsRegional = "(?:\\ud83c[\\udde6-\\uddff]){2}";
184
+ var rsSurrPair = "[\\ud800-\\udbff][\\udc00-\\udfff]";
185
+ var rsUpper = "[" + rsUpperRange + "]";
186
+ var rsZWJ = "\\u200d";
187
187
  /** Used to compose unicode regexes. */
188
- var rsLowerMisc = "(?:" + rsLower + "|" + rsMisc + ")", rsUpperMisc = "(?:" + rsUpper + "|" + rsMisc + ")", rsOptLowerContr = "(?:" + rsApos + "(?:d|ll|m|re|s|t|ve))?", rsOptUpperContr = "(?:" + rsApos + "(?:D|LL|M|RE|S|T|VE))?", reOptMod = rsModifier + "?", rsOptVar = "[" + rsVarRange + "]?", rsOptJoin = "(?:" + rsZWJ + "(?:" + [
188
+ var rsLowerMisc = "(?:" + rsLower + "|" + rsMisc + ")";
189
+ var rsUpperMisc = "(?:" + rsUpper + "|" + rsMisc + ")";
190
+ var rsOptLowerContr = "(?:" + rsApos + "(?:d|ll|m|re|s|t|ve))?";
191
+ var rsOptUpperContr = "(?:" + rsApos + "(?:D|LL|M|RE|S|T|VE))?";
192
+ var reOptMod = rsModifier + "?";
193
+ var rsOptVar = "[" + rsVarRange + "]?";
194
+ var rsOptJoin = "(?:" + rsZWJ + "(?:" + [
189
195
  rsNonAstral,
190
196
  rsRegional,
191
197
  rsSurrPair
192
- ].join("|") + ")" + rsOptVar + reOptMod + ")*", rsSeq = rsOptVar + reOptMod + rsOptJoin, rsEmoji = "(?:" + [
198
+ ].join("|") + ")" + rsOptVar + reOptMod + ")*";
199
+ var rsSeq = rsOptVar + reOptMod + rsOptJoin;
200
+ var rsEmoji = "(?:" + [
193
201
  rsDingbat,
194
202
  rsRegional,
195
203
  rsSurrPair
@@ -488,18 +496,17 @@ var require_lodash = __commonJS({ "../../node_modules/.pnpm/lodash.snakecase@4.1
488
496
  function unicodeWords(string) {
489
497
  return string.match(reUnicodeWord) || [];
490
498
  }
491
- /** Used for built-in method references. */
492
- var objectProto = Object.prototype;
493
499
  /**
494
500
  * Used to resolve the
495
501
  * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
496
502
  * of values.
497
503
  */
498
- var objectToString = objectProto.toString;
504
+ var objectToString = Object.prototype.toString;
499
505
  /** Built-in value references. */
500
506
  var Symbol = root.Symbol;
501
507
  /** Used to convert symbols to primitives and strings. */
502
- var symbolProto = Symbol ? Symbol.prototype : void 0, symbolToString = symbolProto ? symbolProto.toString : void 0;
508
+ var symbolProto = Symbol ? Symbol.prototype : void 0;
509
+ var symbolToString = symbolProto ? symbolProto.toString : void 0;
503
510
  /**
504
511
  * The base implementation of `_.toString` which doesn't convert nullish
505
512
  * values to empty strings.
@@ -512,7 +519,7 @@ var require_lodash = __commonJS({ "../../node_modules/.pnpm/lodash.snakecase@4.1
512
519
  if (typeof value == "string") return value;
513
520
  if (isSymbol(value)) return symbolToString ? symbolToString.call(value) : "";
514
521
  var result = value + "";
515
- return result == "0" && 1 / value == -INFINITY ? "-0" : result;
522
+ return result == "0" && 1 / value == -Infinity ? "-0" : result;
516
523
  }
517
524
  /**
518
525
  * Creates a function like `_.camelCase`.
@@ -669,11 +676,7 @@ var require_lodash = __commonJS({ "../../node_modules/.pnpm/lodash.snakecase@4.1
669
676
  return string.match(pattern) || [];
670
677
  }
671
678
  module.exports = snakeCase;
672
- } });
673
-
674
- //#endregion
675
- //#region src/naming.ts
676
- var import_lodash = __toESM(require_lodash(), 1);
679
+ })))(), 1);
677
680
  /**
678
681
  * `UPPER_SNAKE_CASE`, with numbers kept against the word they follow.
679
682
  *
@@ -685,7 +688,7 @@ var import_lodash = __toESM(require_lodash(), 1);
685
688
  * @example environmentCase('api2') // 'API2' (digit joins its word)
686
689
  */
687
690
  function environmentCase(name) {
688
- return (0, import_lodash.default)(name).toUpperCase().replace(/_\d+/g, (r) => r.replace("_", ""));
691
+ return (0, import_lodash_snakecase.default)(name).toUpperCase().replace(/_\d+/g, (r) => r.replace("_", ""));
689
692
  }
690
693
  /**
691
694
  * The env key a construct provides for one of its roles.
@@ -710,7 +713,7 @@ function provideKey(id, role) {
710
713
  * @example canonicalId('user-uploads') // 'UserUploads'
711
714
  */
712
715
  function canonicalId(input) {
713
- const id = (0, import_lodash.default)(input).split("_").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
716
+ const id = (0, import_lodash_snakecase.default)(input).split("_").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
714
717
  if (!VALID_ID.test(id)) throw new InvalidConstructId(input, id);
715
718
  return id;
716
719
  }
@@ -860,9 +863,10 @@ function cookieDomain(urls) {
860
863
  * cannot catch anything.
861
864
  */
862
865
  function providedKeyFor(id, kind, role) {
863
- return kind === "secret" ? environmentCase(id) : provideKey(id, role);
866
+ if (kind === "secret") return environmentCase(id);
867
+ if (kind === "telemetry") return "OTEL_EXPORTER_OTLP_ENDPOINT";
868
+ return provideKey(id, role);
864
869
  }
865
-
866
870
  //#endregion
867
871
  //#region src/derive.ts
868
872
  /** Whether a declaration names a parent. */
@@ -924,10 +928,15 @@ function dependenciesOf(declaration) {
924
928
  const own = "dependencies" in declaration ? declaration.dependencies ?? [] : [];
925
929
  const calls = "calls" in declaration ? declaration.calls ?? [] : [];
926
930
  const nested = declaration.kind === "rest-api" ? declaration.endpoints.flatMap((endpoint) => endpoint.dependencies) : [];
931
+ const telemetry = "telemetry" in declaration && typeof declaration.telemetry === "string" ? [{
932
+ target: declaration.telemetry,
933
+ kind: "telemetry"
934
+ }] : [];
927
935
  return [
928
936
  ...own,
929
937
  ...calls,
930
- ...nested
938
+ ...nested,
939
+ ...telemetry
931
940
  ];
932
941
  }
933
942
  /**
@@ -961,7 +970,8 @@ function dependentsOf(manifest, id) {
961
970
  const PUBLIC_PREFIX = {
962
971
  static: "VITE_",
963
972
  tanstack: "VITE_",
964
- next: "NEXT_PUBLIC_"
973
+ next: "NEXT_PUBLIC_",
974
+ expo: "EXPO_PUBLIC_"
965
975
  };
966
976
  /**
967
977
  * The keys a site's bundle needs, mapped to the key each value comes from —
@@ -994,39 +1004,232 @@ function publicEnvFor(declaration, manifest) {
994
1004
  }
995
1005
  return keys;
996
1006
  }
997
-
998
1007
  //#endregion
999
- //#region src/index.ts
1000
- /** Flatten a manifest field (array or partitioned) into a plain array. */
1001
- function flattenManifestField(field) {
1002
- if (!field) return [];
1003
- return Array.isArray(field) ? [...field] : Object.values(field).flat();
1008
+ //#region src/encryption.ts
1009
+ /**
1010
+ * The `kms://` URL an `Encryption` construct reads on AWS.
1011
+ *
1012
+ * Here because two packages meet on it: `@geekmidas/cloud` composes it from
1013
+ * the keys it provisioned, and `@geekmidas/constructs` parses it to reach
1014
+ * them. One function, so the two cannot disagree about a parameter's name.
1015
+ */
1016
+ const KMS_SCHEME = "kms:";
1017
+ /**
1018
+ * `kms://<region>?key=<key arn>&index=<hmac key arn>[&endpoint=<url>]`
1019
+ *
1020
+ * `endpoint` reaches an emulator instead of AWS — floci, locally and in tests —
1021
+ * the same parameter an `sns://` connection string carries for the same reason.
1022
+ */
1023
+ function kmsUrl(input) {
1024
+ const query = new URLSearchParams({
1025
+ key: input.key,
1026
+ index: input.index,
1027
+ ...input.endpoint ? { endpoint: input.endpoint } : {}
1028
+ });
1029
+ return `${KMS_SCHEME}//${input.region}?${query}`;
1030
+ }
1031
+ //#endregion
1032
+ //#region src/external.ts
1033
+ /** The key in a by-stage `url` that answers for every stage not listed. */
1034
+ const DEFAULT_STAGE_URL = "default";
1035
+ /**
1036
+ * Where an external API answers on a deployed stage.
1037
+ *
1038
+ * One URL answers every stage; a record answers by stage name, falling back
1039
+ * to `default`. Read at build and deploy, so a stage nobody gave a URL fails
1040
+ * there — with the stage named — rather than at the first request.
1041
+ *
1042
+ * @throws {NoUrlForStage} when a record names neither the stage nor a default.
1043
+ */
1044
+ function externalApiUrl(declaration, stage) {
1045
+ const { url } = declaration;
1046
+ if (typeof url === "string") return url;
1047
+ const resolved = url[stage] ?? url["default"];
1048
+ if (!resolved) throw new NoUrlForStage(declaration.id, stage, Object.keys(url));
1049
+ return resolved;
1004
1050
  }
1005
-
1051
+ /** An external API's `url` record has nothing for the stage being deployed. */
1052
+ var NoUrlForStage = class extends Error {
1053
+ id;
1054
+ stage;
1055
+ stages;
1056
+ constructor(id, stage, stages) {
1057
+ super(`'${id}' has no URL for the stage '${stage}': its url names ${stages.length ? stages.map((s) => `'${s}'`).join(", ") : "no stages"}. Add '${stage}', or a '${DEFAULT_STAGE_URL}' for every stage not listed.`);
1058
+ this.id = id;
1059
+ this.stage = stage;
1060
+ this.stages = stages;
1061
+ this.name = "NoUrlForStage";
1062
+ }
1063
+ };
1006
1064
  //#endregion
1007
- exports.DEFAULT_APP_CODE = DEFAULT_APP_CODE;
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
1087
+ //#region src/migrations.ts
1088
+ /** Where every construct's folder lives, from the project root. */
1089
+ const MIGRATIONS_ROOT = "db";
1090
+ /** The two folders a construct's folder holds, and nothing else. */
1091
+ const DATABASE_FOLDERS = ["migrations", "seeds"];
1092
+ /**
1093
+ * The constructs that take migrations, parents before the tenants inside them.
1094
+ *
1095
+ * A database and each schema tenant: every one has an owner role and a schema
1096
+ * of its own, and so a history of its own. A reader has neither — it reads its
1097
+ * parent's schema — and a cache's table is created by provisioning, not by a
1098
+ * migration anyone writes.
1099
+ */
1100
+ function migrationTargets(manifest) {
1101
+ return provisionOrder(manifest).flatMap((id) => {
1102
+ const declaration = manifest[id];
1103
+ if (!declaration) return [];
1104
+ if (declaration.kind === "database") return [target(id)];
1105
+ if (declaration.kind === "database-schema") return [{
1106
+ ...target(id),
1107
+ of: declaration.of
1108
+ }];
1109
+ return [];
1110
+ });
1111
+ }
1112
+ /**
1113
+ * A construct's folder, relative to the project root.
1114
+ *
1115
+ * Named by the construct — `AuthDatabase` is `db/auth-database` — in the case
1116
+ * every other name outside TypeScript takes. Lowercase, because a folder that
1117
+ * differs from another only in case is two folders on Linux and one on a Mac;
1118
+ * and `canonicalId` reads it back to the construct exactly, which is how a
1119
+ * folder naming nothing is caught rather than skipped.
1120
+ */
1121
+ function databaseFolder(id) {
1122
+ return `db/${kebabCase(id)}`;
1123
+ }
1124
+ /** Where a construct's migrations live: `db/auth-database/migrations`. */
1125
+ function migrationFolder(id) {
1126
+ return `${databaseFolder(id)}/migrations`;
1127
+ }
1128
+ /**
1129
+ * Where a construct's seeds live: `db/auth-database/seeds`.
1130
+ *
1131
+ * Reference data the app needs to run — a permission catalogue, roles, lookup
1132
+ * tables. Seeds are upserts run on every pass, after the migrations, so a
1133
+ * changed seed is applied by running it again. Sample data is factories'.
1134
+ */
1135
+ function seedFolder(id) {
1136
+ return `${databaseFolder(id)}/seeds`;
1137
+ }
1138
+ function target(id) {
1139
+ return {
1140
+ id,
1141
+ folder: databaseFolder(id),
1142
+ migrations: migrationFolder(id),
1143
+ seeds: seedFolder(id)
1144
+ };
1145
+ }
1146
+ //#endregion
1147
+ //#region src/mobile.ts
1148
+ /**
1149
+ * How a mobile app is reached: its URL scheme, and the origins a surface trusts
1150
+ * for it.
1151
+ *
1152
+ * Stated once, here, because three targets ask — the local one (`gkm dev`,
1153
+ * `gkm test`), Dokploy and AWS — and a scheme one of them derived differently
1154
+ * would be an app whose sign-in callback the auth server refuses on exactly one
1155
+ * of them.
1156
+ */
1157
+ /**
1158
+ * An app's scheme: the one given, or the project's name made a valid scheme.
1159
+ *
1160
+ * One for every stage. A development build and the store build register the
1161
+ * same scheme, so the auth server of whichever stage a build talks to trusts
1162
+ * it, and nothing about the app differs between stages but its URLs.
1163
+ *
1164
+ * A scheme is a letter followed by letters, digits, `+`, `-` or `.` — so
1165
+ * `Corner Shop` becomes `corner-shop`, and a name that starts with a digit gets a
1166
+ * leading `app`.
1167
+ */
1168
+ function schemeBase(project, given) {
1169
+ const raw = (given ?? project).toLowerCase().replace(/[^a-z0-9+.-]+/g, "-").replace(/^-+|-+$/g, "");
1170
+ if (!raw) return "app";
1171
+ return /^[a-z]/.test(raw) ? raw : `app${raw}`;
1172
+ }
1173
+ /**
1174
+ * The origins a surface trusts for a mobile caller.
1175
+ *
1176
+ * Better Auth's Expo plugin sends the app's scheme as its origin
1177
+ * (`shop://`), and a link can carry a path after it (`shop://*`).
1178
+ * In development, Expo Go sends `exp://<host>:<port>` instead — so a local
1179
+ * stage adds the hosts a device actually reaches Metro on, and Metro's port
1180
+ * when the target placed it: a whole subnet is not trusted because one phone
1181
+ * is on it.
1182
+ */
1183
+ function mobileOrigins(scheme, metro) {
1184
+ return [
1185
+ `${scheme}://`,
1186
+ `${scheme}://*`,
1187
+ ...(metro?.hosts ?? []).flatMap((host) => [`exp://${host}:${metro?.port ?? "*"}`, `exp://${host}:${metro?.port ?? "*"}/**`])
1188
+ ];
1189
+ }
1190
+ /** Whether an origin is a web one — what a cookie domain is derived from. */
1191
+ function isWebOrigin(origin) {
1192
+ return origin.startsWith("http://") || origin.startsWith("https://");
1193
+ }
1194
+ //#endregion
1195
+ exports.CLIENT_IP_HEADER = CLIENT_IP_HEADER;
1196
+ exports.DATABASE_FOLDERS = DATABASE_FOLDERS;
1008
1197
  exports.DEFAULT_POSTGRES_VERSION = DEFAULT_POSTGRES_VERSION;
1198
+ exports.DEFAULT_STAGE_URL = DEFAULT_STAGE_URL;
1009
1199
  exports.DERIVES_FROM = DERIVES_FROM;
1010
1200
  exports.IllegalDerivation = IllegalDerivation;
1011
1201
  exports.InvalidConstructId = InvalidConstructId;
1202
+ exports.KMS_SCHEME = KMS_SCHEME;
1203
+ exports.MIGRATIONS_ROOT = MIGRATIONS_ROOT;
1204
+ exports.NoUrlForStage = NoUrlForStage;
1012
1205
  exports.PUBLIC = PUBLIC;
1013
1206
  exports.PUBLIC_PREFIX = PUBLIC_PREFIX;
1207
+ exports.TELEMETRY_KEYS = TELEMETRY_KEYS;
1014
1208
  exports.UnknownParent = UnknownParent;
1015
1209
  exports.assertDerivations = assertDerivations;
1016
1210
  exports.cacheTable = cacheTable;
1017
1211
  exports.canonicalId = canonicalId;
1018
1212
  exports.cloudName = cloudName;
1019
1213
  exports.cookieDomain = cookieDomain;
1214
+ exports.databaseFolder = databaseFolder;
1020
1215
  exports.dependenciesOf = dependenciesOf;
1021
1216
  exports.dependentsOf = dependentsOf;
1022
1217
  exports.environmentCase = environmentCase;
1023
- exports.flattenManifestField = flattenManifestField;
1218
+ exports.externalApiUrl = externalApiUrl;
1024
1219
  exports.isDerived = isDerived;
1220
+ exports.isWebOrigin = isWebOrigin;
1025
1221
  exports.kebabCase = kebabCase;
1222
+ exports.kmsUrl = kmsUrl;
1223
+ exports.migrationFolder = migrationFolder;
1224
+ exports.migrationTargets = migrationTargets;
1225
+ exports.mobileOrigins = mobileOrigins;
1026
1226
  exports.provideKey = provideKey;
1027
1227
  exports.providedKeyFor = providedKeyFor;
1028
1228
  exports.provisionOrder = provisionOrder;
1029
1229
  exports.publicEnvFor = publicEnvFor;
1230
+ exports.schemeBase = schemeBase;
1030
1231
  exports.scopedName = scopedName;
1232
+ exports.seedFolder = seedFolder;
1031
1233
  exports.serviceKey = serviceKey;
1234
+
1032
1235
  //# sourceMappingURL=index.cjs.map