@geekmidas/manifest 10.0.0-alpha.15 → 10.0.0-alpha.151

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
@@ -33,6 +33,27 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
33
33
  * this.
34
34
  */
35
35
  const DEFAULT_POSTGRES_VERSION = 18;
36
+ /** A site's subdomain that means every subdomain — see `SiteDeclaration`. */
37
+ const WILDCARD_SUBDOMAIN = "*";
38
+ /**
39
+ * Whether a declaration is a site answering on every subdomain.
40
+ */
41
+ function isWildcardSite(declaration) {
42
+ return declaration?.kind === "site" && declaration.subdomain === "*";
43
+ }
44
+ /**
45
+ * What a `Telemetry` node provides to each process with an edge to it.
46
+ *
47
+ * `OTEL_SERVICE_NAME` is resolved per process — the app's name — so it is
48
+ * listed here but composed by whichever target hands it over.
49
+ */
50
+ const TELEMETRY_KEYS = [
51
+ "OTEL_EXPORTER_OTLP_ENDPOINT",
52
+ "OTEL_EXPORTER_OTLP_HEADERS",
53
+ "OTEL_SERVICE_NAME",
54
+ "OTEL_TRACES_SAMPLER",
55
+ "OTEL_TRACES_SAMPLER_ARG"
56
+ ];
36
57
  /**
37
58
  * What each kind may derive from.
38
59
  *
@@ -57,21 +78,27 @@ const DERIVES_FROM = {
57
78
  const PUBLIC = {
58
79
  objects: [],
59
80
  "file-server": ["url"],
60
- email: [],
81
+ email: ["inboxUrl"],
82
+ inbox: [],
61
83
  database: [],
62
84
  "database-reader": [],
63
85
  "database-schema": [],
64
86
  cache: [],
65
87
  secret: [],
66
88
  credential: [],
89
+ encryption: [],
67
90
  "rest-api": ["url"],
91
+ "websocket-api": ["url"],
68
92
  queue: [],
69
93
  topic: [],
70
94
  oidc: ["issuer", "audience"],
95
+ "external-api": [],
71
96
  function: [],
72
97
  cron: [],
98
+ "mobile-app": [],
73
99
  site: ["url"],
74
- worker: []
100
+ worker: [],
101
+ telemetry: []
75
102
  };
76
103
  //#endregion
77
104
  //#region src/errors.ts
@@ -846,7 +873,9 @@ function cookieDomain(urls) {
846
873
  * cannot catch anything.
847
874
  */
848
875
  function providedKeyFor(id, kind, role) {
849
- return kind === "secret" ? environmentCase(id) : provideKey(id, role);
876
+ if (kind === "secret") return environmentCase(id);
877
+ if (kind === "telemetry") return "OTEL_EXPORTER_OTLP_ENDPOINT";
878
+ return provideKey(id, role);
850
879
  }
851
880
  //#endregion
852
881
  //#region src/derive.ts
@@ -907,12 +936,17 @@ function provisionOrder(manifest) {
907
936
  */
908
937
  function dependenciesOf(declaration) {
909
938
  const own = "dependencies" in declaration ? declaration.dependencies ?? [] : [];
910
- const calls = "calls" in declaration ? declaration.calls ?? [] : [];
911
- const nested = declaration.kind === "rest-api" ? declaration.endpoints.flatMap((endpoint) => endpoint.dependencies) : [];
939
+ const auth = (declaration.kind === "rest-api" || declaration.kind === "websocket-api") && declaration.auth ? [declaration.auth] : [];
940
+ const nested = declaration.kind === "rest-api" ? declaration.endpoints.flatMap((endpoint) => endpoint.dependencies) : declaration.kind === "websocket-api" ? (declaration.routes ?? []).flatMap((route) => route.dependencies) : [];
941
+ const telemetry = "telemetry" in declaration && typeof declaration.telemetry === "string" ? [{
942
+ target: declaration.telemetry,
943
+ kind: "telemetry"
944
+ }] : [];
912
945
  return [
913
946
  ...own,
914
- ...calls,
915
- ...nested
947
+ ...auth,
948
+ ...nested,
949
+ ...telemetry
916
950
  ];
917
951
  }
918
952
  /**
@@ -946,11 +980,13 @@ function dependentsOf(manifest, id) {
946
980
  const PUBLIC_PREFIX = {
947
981
  static: "VITE_",
948
982
  tanstack: "VITE_",
949
- next: "NEXT_PUBLIC_"
983
+ next: "NEXT_PUBLIC_",
984
+ expo: "EXPO_PUBLIC_"
950
985
  };
951
986
  /**
952
987
  * The keys a site's bundle needs, mapped to the key each value comes from —
953
- * `{ VITE_API_URL: 'API_URL' }`.
988
+ * `{ VITE_API_URL: 'API_URL' }` — its edges' public values, and a site's own
989
+ * address (`{ VITE_WEB_URL: 'WEB_URL' }`).
954
990
  *
955
991
  * A rename, not a second derivation: `API_URL` is resolved once, by whatever
956
992
  * resolved it for the server, and the site reads the same value under the name
@@ -969,6 +1005,14 @@ const PUBLIC_PREFIX = {
969
1005
  function publicEnvFor(declaration, manifest) {
970
1006
  const prefix = PUBLIC_PREFIX[declaration.variant];
971
1007
  const keys = {};
1008
+ if (declaration.kind === "site") {
1009
+ const own = provideKey(declaration.id, "url");
1010
+ keys[`${prefix}${own}`] = own;
1011
+ }
1012
+ if (isWildcardSite(declaration)) for (const role of ["domain", "protectedSubdomains"]) {
1013
+ const key = provideKey(declaration.id, role);
1014
+ keys[`${prefix}${key}`] = key;
1015
+ }
972
1016
  for (const edge of declaration.dependencies) {
973
1017
  const target = manifest[edge.target];
974
1018
  if (!target) continue;
@@ -980,36 +1024,425 @@ function publicEnvFor(declaration, manifest) {
980
1024
  return keys;
981
1025
  }
982
1026
  //#endregion
983
- //#region src/index.ts
984
- /** Flatten a manifest field (array or partitioned) into a plain array. */
985
- function flattenManifestField(field) {
986
- if (!field) return [];
987
- return Array.isArray(field) ? [...field] : Object.values(field).flat();
1027
+ //#region src/derived.ts
1028
+ /** Where a processor keeps what it made, in the bucket it reads. */
1029
+ const DERIVED_PREFIX = ".gkm-derived/";
1030
+ /** How long a derivative is kept when its file server does not say. */
1031
+ const DEFAULT_DERIVED_DAYS = 30;
1032
+ /**
1033
+ * The days a bucket keeps what is under each prefix: what it declared, and —
1034
+ * when a file server over it has processors — the derived prefix, for the
1035
+ * longest any of those servers asked. `undefined` when it expires nothing.
1036
+ */
1037
+ function bucketExpiry(manifest, bucketId) {
1038
+ const expire = { ...manifest[bucketId]?.expire ?? {} };
1039
+ const processed = Object.values(manifest).filter((d) => d.kind === "file-server" && d.of === bucketId && (d.processors?.length ?? 0) > 0);
1040
+ if (processed.length > 0 && expire[".gkm-derived/"] === void 0) expire[DERIVED_PREFIX] = Math.max(...processed.map((s) => s.derivedDays ?? 30));
1041
+ return Object.keys(expire).length > 0 ? expire : void 0;
1042
+ }
1043
+ //#endregion
1044
+ //#region src/encryption.ts
1045
+ /**
1046
+ * The `kms://` URL an `Encryption` construct reads on AWS.
1047
+ *
1048
+ * Here because two packages meet on it: `@geekmidas/cloud` composes it from
1049
+ * the keys it provisioned, and `@geekmidas/constructs` parses it to reach
1050
+ * them. One function, so the two cannot disagree about a parameter's name.
1051
+ */
1052
+ const KMS_SCHEME = "kms:";
1053
+ /**
1054
+ * `kms://<region>?key=<key arn>&index=<hmac key arn>[&endpoint=<url>]`
1055
+ *
1056
+ * `endpoint` reaches an emulator instead of AWS — floci, locally and in tests —
1057
+ * the same parameter an `sns://` connection string carries for the same reason.
1058
+ */
1059
+ function kmsUrl(input) {
1060
+ const query = new URLSearchParams({
1061
+ key: input.key,
1062
+ index: input.index,
1063
+ ...input.endpoint ? { endpoint: input.endpoint } : {}
1064
+ });
1065
+ return `${KMS_SCHEME}//${input.region}?${query}`;
1066
+ }
1067
+ //#endregion
1068
+ //#region src/external.ts
1069
+ /** The key in a by-stage `url` that answers for every stage not listed. */
1070
+ const DEFAULT_STAGE_URL = "default";
1071
+ /**
1072
+ * Where an external API answers on a deployed stage.
1073
+ *
1074
+ * One URL answers every stage; a record answers by stage name, falling back
1075
+ * to `default`. Read at build and deploy, so a stage nobody gave a URL fails
1076
+ * there — with the stage named — rather than at the first request.
1077
+ *
1078
+ * @throws {NoUrlForStage} when a record names neither the stage nor a default.
1079
+ */
1080
+ function externalApiUrl(declaration, stage) {
1081
+ const { url } = declaration;
1082
+ if (typeof url === "string") return url;
1083
+ const resolved = url[stage] ?? url["default"];
1084
+ if (!resolved) throw new NoUrlForStage(declaration.id, stage, Object.keys(url));
1085
+ return resolved;
1086
+ }
1087
+ /** An external API's `url` record has nothing for the stage being deployed. */
1088
+ var NoUrlForStage = class extends Error {
1089
+ id;
1090
+ stage;
1091
+ stages;
1092
+ constructor(id, stage, stages) {
1093
+ 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.`);
1094
+ this.id = id;
1095
+ this.stage = stage;
1096
+ this.stages = stages;
1097
+ this.name = "NoUrlForStage";
1098
+ }
1099
+ };
1100
+ //#endregion
1101
+ //#region src/headers.ts
1102
+ /**
1103
+ * Headers gkm reserves for its own services' calls to each other.
1104
+ *
1105
+ * Shared by `@geekmidas/constructs`, which sends and reads them, and
1106
+ * `@geekmidas/cli`, whose edges strip them from every request that arrives
1107
+ * from outside — so the two cannot name them differently.
1108
+ */
1109
+ /**
1110
+ * The address of the client a service-to-service call is made on behalf of.
1111
+ *
1112
+ * An API asking its auth server for a session sends the client's address in
1113
+ * this rather than `X-Forwarded-For`: a forwarding header marks a request as
1114
+ * outside traffic, which would start the auth server's span in a new trace,
1115
+ * and the address is still needed — Better Auth rate-limits per client.
1116
+ *
1117
+ * Reserved: the stack's edge (Caddy, Traefik, the `gkm dev` edge) removes it
1118
+ * from every request that does not carry the stack's token
1119
+ * ({@link EDGE_TOKEN_HEADER}), and the auth server ignores it on any request
1120
+ * that neither carries the token nor is an internal caller's, so it cannot be
1121
+ * spoofed from outside.
1122
+ */
1123
+ const CLIENT_IP_HEADER = "x-gkm-client-ip";
1124
+ /**
1125
+ * The token a service of a stack sends beside {@link CLIENT_IP_HEADER} when
1126
+ * it calls a sibling through the stack's edge, at its public address.
1127
+ *
1128
+ * A request carries a forwarding header once it has passed an edge, so the
1129
+ * peer alone no longer says it came from inside the stack. The token does:
1130
+ * it is derived from the stage's seed, handed to every process of the stack
1131
+ * as {@link EDGE_TOKEN_KEY}, and known to the edge. The edge keeps
1132
+ * `x-gkm-client-ip` only on a request carrying it, and strips the header from
1133
+ * every other; the auth server honours the header only from an internal
1134
+ * caller or a request carrying its own token. A browser never has it.
1135
+ */
1136
+ const EDGE_TOKEN_HEADER = "x-gkm-edge-token";
1137
+ /** Where a stack's processes read the token {@link EDGE_TOKEN_HEADER} carries. */
1138
+ const EDGE_TOKEN_KEY = "GKM_EDGE_TOKEN";
1139
+ //#endregion
1140
+ //#region src/inbox.ts
1141
+ /** The event type a received message is announced as on its inbox's topic. */
1142
+ const INBOX_EVENT = "email.received";
1143
+ /**
1144
+ * Where an inbox's raw messages are kept in its bucket: SES's S3 action
1145
+ * writes `<prefix><message id>`, and `gkm dev` and the test mailbox write the
1146
+ * same layout.
1147
+ */
1148
+ const INBOX_MESSAGES_PREFIX = "messages/";
1149
+ /**
1150
+ * The recipient `address` is to `inbox` on `domain`, or `undefined` when the
1151
+ * inbox does not receive at it.
1152
+ *
1153
+ * - The local part is a declared address, or one with a `+tag` after it.
1154
+ * - Without `subdomains`, the domain is the stage's domain itself; with it,
1155
+ * exactly one label in front of the stage's domain — `acme.fixwell.example`
1156
+ * — and never the bare domain, whose mail would belong to no tenant.
1157
+ *
1158
+ * Case-insensitive, as mail addresses are in practice.
1159
+ */
1160
+ function inboxRecipient(address, inbox, domain) {
1161
+ const normalized = address.trim().toLowerCase();
1162
+ const at = normalized.lastIndexOf("@");
1163
+ if (at <= 0) return void 0;
1164
+ const localPart = normalized.slice(0, at);
1165
+ const host = normalized.slice(at + 1);
1166
+ const base = domain.toLowerCase();
1167
+ let subdomain;
1168
+ if (inbox.subdomains) {
1169
+ if (!host.endsWith(`.${base}`)) return void 0;
1170
+ subdomain = host.slice(0, -(base.length + 1));
1171
+ if (!subdomain || subdomain.includes(".")) return void 0;
1172
+ } else if (host !== base) return;
1173
+ const plus = localPart.indexOf("+");
1174
+ const local = plus === -1 ? localPart : localPart.slice(0, plus);
1175
+ const tag = plus === -1 ? void 0 : localPart.slice(plus + 1);
1176
+ if (!inbox.addresses.some((declared) => declared.toLowerCase() === local)) return;
1177
+ return {
1178
+ address: normalized,
1179
+ local,
1180
+ ...tag ? { tag } : {},
1181
+ ...subdomain ? { subdomain } : {}
1182
+ };
1183
+ }
1184
+ /**
1185
+ * The recipients a deployed receipt rule names for `inbox` on `domain`.
1186
+ *
1187
+ * Without `subdomains`, each address on the domain: SES matches an address
1188
+ * condition's `+label` variants too, so `requests@` takes `requests+t_8f3k@`.
1189
+ * With it, every subdomain (`.fixwell.example`): a condition cannot say
1190
+ * "`requests` on any subdomain", so the rule takes the subdomains' mail and
1191
+ * the decoder in front of the handler drops what {@link inboxRecipient} does
1192
+ * not match.
1193
+ */
1194
+ function receiptRecipients(inbox, domain) {
1195
+ const base = domain.toLowerCase();
1196
+ return inbox.subdomains ? [`.${base}`] : inbox.addresses.map((address) => `${address.toLowerCase()}@${base}`);
1197
+ }
1198
+ //#endregion
1199
+ //#region src/migrations.ts
1200
+ /** Where every construct's folder lives, from the project root. */
1201
+ const MIGRATIONS_ROOT = "db";
1202
+ /** The two folders a construct's folder holds, and nothing else. */
1203
+ const DATABASE_FOLDERS = ["migrations", "seeds"];
1204
+ /**
1205
+ * The constructs that take migrations, parents before the tenants inside them.
1206
+ *
1207
+ * A database and each schema tenant: every one has an owner role and a schema
1208
+ * of its own, and so a history of its own. A reader has neither — it reads its
1209
+ * parent's schema — and a cache's table is created by provisioning, not by a
1210
+ * migration anyone writes.
1211
+ */
1212
+ function migrationTargets(manifest) {
1213
+ return provisionOrder(manifest).flatMap((id) => {
1214
+ const declaration = manifest[id];
1215
+ if (!declaration) return [];
1216
+ if (declaration.kind === "database") return [target(id)];
1217
+ if (declaration.kind === "database-schema") return [{
1218
+ ...target(id),
1219
+ of: declaration.of
1220
+ }];
1221
+ return [];
1222
+ });
1223
+ }
1224
+ /**
1225
+ * A construct's folder, relative to the project root.
1226
+ *
1227
+ * Named by the construct — `AuthDatabase` is `db/auth-database` — in the case
1228
+ * every other name outside TypeScript takes. Lowercase, because a folder that
1229
+ * differs from another only in case is two folders on Linux and one on a Mac;
1230
+ * and `canonicalId` reads it back to the construct exactly, which is how a
1231
+ * folder naming nothing is caught rather than skipped.
1232
+ */
1233
+ function databaseFolder(id) {
1234
+ return `db/${kebabCase(id)}`;
1235
+ }
1236
+ /** Where a construct's migrations live: `db/auth-database/migrations`. */
1237
+ function migrationFolder(id) {
1238
+ return `${databaseFolder(id)}/migrations`;
1239
+ }
1240
+ /**
1241
+ * Where a construct's seeds live: `db/auth-database/seeds`.
1242
+ *
1243
+ * Reference data the app needs to run — a permission catalogue, roles, lookup
1244
+ * tables. Seeds are upserts run on every pass, after the migrations, so a
1245
+ * changed seed is applied by running it again. Sample data is factories'.
1246
+ */
1247
+ function seedFolder(id) {
1248
+ return `${databaseFolder(id)}/seeds`;
1249
+ }
1250
+ function target(id) {
1251
+ return {
1252
+ id,
1253
+ folder: databaseFolder(id),
1254
+ migrations: migrationFolder(id),
1255
+ seeds: seedFolder(id)
1256
+ };
1257
+ }
1258
+ //#endregion
1259
+ //#region src/mobile.ts
1260
+ /**
1261
+ * How a mobile app is reached: its URL scheme, and the origins a surface trusts
1262
+ * for it.
1263
+ *
1264
+ * Stated once, here, because three targets ask — the local one (`gkm dev`,
1265
+ * `gkm test`), Dokploy and AWS — and a scheme one of them derived differently
1266
+ * would be an app whose sign-in callback the auth server refuses on exactly one
1267
+ * of them.
1268
+ */
1269
+ /**
1270
+ * An app's scheme: the one given, or the project's name made a valid scheme.
1271
+ *
1272
+ * One for every stage. A development build and the store build register the
1273
+ * same scheme, so the auth server of whichever stage a build talks to trusts
1274
+ * it, and nothing about the app differs between stages but its URLs.
1275
+ *
1276
+ * A scheme is a letter followed by letters, digits, `+`, `-` or `.` — so
1277
+ * `Corner Shop` becomes `corner-shop`, and a name that starts with a digit gets a
1278
+ * leading `app`.
1279
+ */
1280
+ function schemeBase(project, given) {
1281
+ const raw = (given ?? project).toLowerCase().replace(/[^a-z0-9+.-]+/g, "-").replace(/^-+|-+$/g, "");
1282
+ if (!raw) return "app";
1283
+ return /^[a-z]/.test(raw) ? raw : `app${raw}`;
1284
+ }
1285
+ /**
1286
+ * The origins a surface trusts for a mobile caller.
1287
+ *
1288
+ * Better Auth's Expo plugin sends the app's scheme as its origin
1289
+ * (`shop://`), and a link can carry a path after it (`shop://*`).
1290
+ * In development, Expo Go sends `exp://<host>:<port>` instead — so a local
1291
+ * stage adds the hosts a device actually reaches Metro on, and Metro's port
1292
+ * when the target placed it: a whole subnet is not trusted because one phone
1293
+ * is on it.
1294
+ */
1295
+ function mobileOrigins(scheme, metro) {
1296
+ return [
1297
+ `${scheme}://`,
1298
+ `${scheme}://*`,
1299
+ ...(metro?.hosts ?? []).flatMap((host) => [`exp://${host}:${metro?.port ?? "*"}`, `exp://${host}:${metro?.port ?? "*"}/**`])
1300
+ ];
1301
+ }
1302
+ /** Whether an origin is a web one — what a cookie domain is derived from. */
1303
+ function isWebOrigin(origin) {
1304
+ return origin.startsWith("http://") || origin.startsWith("https://");
1305
+ }
1306
+ //#endregion
1307
+ //#region src/origins.ts
1308
+ /**
1309
+ * Whether a request from `origin` comes from one of `trusted`.
1310
+ *
1311
+ * An entry matches exactly — scheme, host and port — or, written
1312
+ * `https://*.example.com`, matches any one label in place of the `*`:
1313
+ * `https://acme.example.com`, never `https://example.com` and never
1314
+ * `https://a.b.example.com`. That is the origin a wildcard site's tenants
1315
+ * call from, and it is as wide as a wildcard certificate, no wider.
1316
+ *
1317
+ * A bare `*` trusts nothing: a surface that answers any origin has not said
1318
+ * which sites are its own.
1319
+ */
1320
+ function trustsOrigin(origin, trusted) {
1321
+ const request = parse(origin);
1322
+ if (!request) return false;
1323
+ return trusted.some((entry) => {
1324
+ const allowed = parse(entry);
1325
+ if (!allowed) return false;
1326
+ if (allowed.scheme !== request.scheme) return false;
1327
+ if (allowed.port !== request.port) return false;
1328
+ const domain = wildcardDomainOf(allowed.host);
1329
+ if (domain === void 0) return allowed.host === request.host;
1330
+ const dot = request.host.indexOf(".");
1331
+ return dot > 0 && LABEL.test(request.host.slice(0, dot)) && request.host.slice(dot + 1) === domain;
1332
+ });
1333
+ }
1334
+ /**
1335
+ * The domain under a wildcard host — `example.com` for `*.example.com` — or
1336
+ * `undefined` for a host that is not one.
1337
+ */
1338
+ function wildcardDomainOf(host) {
1339
+ return host.startsWith("*.") ? host.slice(2) : void 0;
1340
+ }
1341
+ /** One DNS label, as a tenant's slug is. */
1342
+ const LABEL = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
1343
+ function parse(origin) {
1344
+ if (!origin || origin === "*") return void 0;
1345
+ try {
1346
+ const url = new URL(origin);
1347
+ if (url.origin === "null") return void 0;
1348
+ return {
1349
+ scheme: url.protocol,
1350
+ host: url.hostname.toLowerCase(),
1351
+ port: url.port
1352
+ };
1353
+ } catch {
1354
+ return;
1355
+ }
1356
+ }
1357
+ //#endregion
1358
+ //#region src/secret.ts
1359
+ /**
1360
+ * What a generated secret looks like, and the one way every stage draws it.
1361
+ *
1362
+ * A server deploy draws from `crypto`, `gkm dev` and `gkm test` from a hash of
1363
+ * the project, stage and id, and an AWS deploy asks Pulumi for the same
1364
+ * alphabet. Sharing this is what keeps a password that passes a third party's
1365
+ * rules on one stage from failing them on the next.
1366
+ */
1367
+ /** 43 characters from 64 is 256 bits — as much as anything here needs. */
1368
+ const SECRET_LENGTH = 43;
1369
+ /**
1370
+ * Two symbols nothing has to escape — not a URL, a connection string, a shell
1371
+ * or a `.env` file — which with letters and digits is base64url's alphabet.
1372
+ */
1373
+ const SECRET_SYMBOLS = "-_";
1374
+ const LETTERS_AND_DIGITS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
1375
+ /**
1376
+ * A secret in `format`, each character chosen by `pick(n)` — an integer in
1377
+ * `[0, n)` from whatever source the caller trusts.
1378
+ *
1379
+ * When there are symbols, one is guaranteed: a rule that demands a symbol is
1380
+ * the reason anyone names them, and leaving it to chance fails it often —
1381
+ * about one draw in seven at 24 characters.
1382
+ */
1383
+ function drawSecret(pick, format = {}) {
1384
+ const length = format.length ?? 43;
1385
+ const symbols = [...new Set(format.symbols ?? "-_")].join("");
1386
+ const alphabet = LETTERS_AND_DIGITS + symbols;
1387
+ const chars = Array.from({ length }, () => alphabet[pick(alphabet.length)]);
1388
+ if (symbols && !chars.some((char) => symbols.includes(char))) chars[pick(length)] = symbols[pick(symbols.length)];
1389
+ return chars.join("");
988
1390
  }
989
1391
  //#endregion
1392
+ exports.CLIENT_IP_HEADER = CLIENT_IP_HEADER;
1393
+ exports.DATABASE_FOLDERS = DATABASE_FOLDERS;
1394
+ exports.DEFAULT_DERIVED_DAYS = DEFAULT_DERIVED_DAYS;
990
1395
  exports.DEFAULT_POSTGRES_VERSION = DEFAULT_POSTGRES_VERSION;
1396
+ exports.DEFAULT_STAGE_URL = DEFAULT_STAGE_URL;
1397
+ exports.DERIVED_PREFIX = DERIVED_PREFIX;
991
1398
  exports.DERIVES_FROM = DERIVES_FROM;
1399
+ exports.EDGE_TOKEN_HEADER = EDGE_TOKEN_HEADER;
1400
+ exports.EDGE_TOKEN_KEY = EDGE_TOKEN_KEY;
1401
+ exports.INBOX_EVENT = INBOX_EVENT;
1402
+ exports.INBOX_MESSAGES_PREFIX = INBOX_MESSAGES_PREFIX;
992
1403
  exports.IllegalDerivation = IllegalDerivation;
993
1404
  exports.InvalidConstructId = InvalidConstructId;
1405
+ exports.KMS_SCHEME = KMS_SCHEME;
1406
+ exports.MIGRATIONS_ROOT = MIGRATIONS_ROOT;
1407
+ exports.NoUrlForStage = NoUrlForStage;
994
1408
  exports.PUBLIC = PUBLIC;
995
1409
  exports.PUBLIC_PREFIX = PUBLIC_PREFIX;
1410
+ exports.SECRET_LENGTH = SECRET_LENGTH;
1411
+ exports.SECRET_SYMBOLS = SECRET_SYMBOLS;
1412
+ exports.TELEMETRY_KEYS = TELEMETRY_KEYS;
996
1413
  exports.UnknownParent = UnknownParent;
1414
+ exports.WILDCARD_SUBDOMAIN = WILDCARD_SUBDOMAIN;
997
1415
  exports.assertDerivations = assertDerivations;
1416
+ exports.bucketExpiry = bucketExpiry;
998
1417
  exports.cacheTable = cacheTable;
999
1418
  exports.canonicalId = canonicalId;
1000
1419
  exports.cloudName = cloudName;
1001
1420
  exports.cookieDomain = cookieDomain;
1421
+ exports.databaseFolder = databaseFolder;
1002
1422
  exports.dependenciesOf = dependenciesOf;
1003
1423
  exports.dependentsOf = dependentsOf;
1424
+ exports.drawSecret = drawSecret;
1004
1425
  exports.environmentCase = environmentCase;
1005
- exports.flattenManifestField = flattenManifestField;
1426
+ exports.externalApiUrl = externalApiUrl;
1427
+ exports.inboxRecipient = inboxRecipient;
1006
1428
  exports.isDerived = isDerived;
1429
+ exports.isWebOrigin = isWebOrigin;
1430
+ exports.isWildcardSite = isWildcardSite;
1007
1431
  exports.kebabCase = kebabCase;
1432
+ exports.kmsUrl = kmsUrl;
1433
+ exports.migrationFolder = migrationFolder;
1434
+ exports.migrationTargets = migrationTargets;
1435
+ exports.mobileOrigins = mobileOrigins;
1008
1436
  exports.provideKey = provideKey;
1009
1437
  exports.providedKeyFor = providedKeyFor;
1010
1438
  exports.provisionOrder = provisionOrder;
1011
1439
  exports.publicEnvFor = publicEnvFor;
1440
+ exports.receiptRecipients = receiptRecipients;
1441
+ exports.schemeBase = schemeBase;
1012
1442
  exports.scopedName = scopedName;
1443
+ exports.seedFolder = seedFolder;
1013
1444
  exports.serviceKey = serviceKey;
1445
+ exports.trustsOrigin = trustsOrigin;
1446
+ exports.wildcardDomainOf = wildcardDomainOf;
1014
1447
 
1015
1448
  //# sourceMappingURL=index.cjs.map