@spacefast/common 0.0.23 → 0.0.26

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.
Files changed (224) hide show
  1. package/brand-assets/LICENSE-Haskoy.txt +93 -0
  2. package/brand-assets/haskoy-latin-variable.woff2 +0 -0
  3. package/brand-assets/spacefast-favicon.svg +4 -4
  4. package/brand-assets/spacefast-sf-full-bleed.svg +3 -3
  5. package/brand-assets/spacefast-wordmark.svg +2 -4
  6. package/dist/agents/connect-targets.js +1 -1
  7. package/dist/agents/private-key-oauth.d.ts +0 -1
  8. package/dist/agents/private-key-oauth.js +46 -63
  9. package/dist/brand-assets-build.js +4 -6
  10. package/dist/brand-assets.d.ts +5 -15
  11. package/dist/brand-assets.js +15 -14
  12. package/dist/config/domains.d.ts +47 -7
  13. package/dist/config/domains.js +66 -10
  14. package/dist/config/index.d.ts +0 -1
  15. package/dist/config/index.js +0 -1
  16. package/dist/contracts/abuse.d.ts +2 -0
  17. package/dist/contracts/abuse.js +12 -0
  18. package/dist/contracts/access.d.ts +124 -12
  19. package/dist/contracts/access.js +73 -9
  20. package/dist/contracts/activity.d.ts +1 -1
  21. package/dist/contracts/activity.js +5 -12
  22. package/dist/contracts/api-keys.d.ts +21 -21
  23. package/dist/contracts/api-keys.js +2 -2
  24. package/dist/contracts/beta.js +1 -1
  25. package/dist/contracts/billing.d.ts +3 -35
  26. package/dist/contracts/billing.js +33 -52
  27. package/dist/contracts/builds.d.ts +30 -18
  28. package/dist/contracts/builds.js +28 -9
  29. package/dist/contracts/channels.js +1 -1
  30. package/dist/contracts/cli.d.ts +10 -0
  31. package/dist/contracts/cli.js +10 -0
  32. package/dist/contracts/collab-public.d.ts +63 -0
  33. package/dist/contracts/collab-public.js +46 -0
  34. package/dist/contracts/comments.d.ts +282 -53
  35. package/dist/contracts/comments.js +173 -52
  36. package/dist/contracts/common.d.ts +3 -3
  37. package/dist/contracts/common.js +5 -5
  38. package/dist/contracts/crons.d.ts +35 -0
  39. package/dist/contracts/crons.js +42 -0
  40. package/dist/contracts/device-auth.d.ts +6 -6
  41. package/dist/contracts/device-auth.js +2 -2
  42. package/dist/contracts/docs.js +2 -2
  43. package/dist/contracts/domains.d.ts +38 -27
  44. package/dist/contracts/domains.js +29 -2
  45. package/dist/contracts/enums.d.ts +34 -30
  46. package/dist/contracts/enums.js +62 -48
  47. package/dist/contracts/error-code-meta.d.ts +50 -125
  48. package/dist/contracts/error-code-meta.js +29 -41
  49. package/dist/contracts/error-codes.d.ts +1 -1
  50. package/dist/contracts/error-codes.js +14 -33
  51. package/dist/contracts/execution.d.ts +47 -66
  52. package/dist/contracts/execution.js +53 -49
  53. package/dist/contracts/feature-lifecycle-core.d.ts +0 -6
  54. package/dist/contracts/feature-lifecycle-core.js +2 -31
  55. package/dist/contracts/feature-lifecycle.d.ts +12 -52
  56. package/dist/contracts/feature-lifecycle.js +16 -59
  57. package/dist/contracts/features.d.ts +48 -60
  58. package/dist/contracts/features.js +59 -51
  59. package/dist/contracts/functions.d.ts +266 -72
  60. package/dist/contracts/functions.js +260 -37
  61. package/dist/contracts/git.d.ts +28 -34
  62. package/dist/contracts/git.js +10 -11
  63. package/dist/contracts/grants.d.ts +9 -5
  64. package/dist/contracts/grants.js +18 -9
  65. package/dist/contracts/ids.js +2 -2
  66. package/dist/contracts/internal.d.ts +8 -6
  67. package/dist/contracts/internal.js +12 -12
  68. package/dist/contracts/mcp.d.ts +11 -0
  69. package/dist/contracts/mcp.js +5 -0
  70. package/dist/contracts/me.js +1 -1
  71. package/dist/contracts/oauth-resources.d.ts +4 -3
  72. package/dist/contracts/oauth-resources.js +12 -3
  73. package/dist/contracts/operations.d.ts +90 -5
  74. package/dist/contracts/operations.js +77 -3
  75. package/dist/contracts/pages.d.ts +12 -7
  76. package/dist/contracts/pages.js +24 -1
  77. package/dist/contracts/plan-policy.d.ts +0 -2
  78. package/dist/contracts/plan-policy.js +2 -3
  79. package/dist/contracts/platform.d.ts +61 -148
  80. package/dist/contracts/platform.js +70 -126
  81. package/dist/contracts/publish-archive.d.ts +508 -0
  82. package/dist/contracts/publish-archive.js +32 -0
  83. package/dist/contracts/push-new.d.ts +4 -4
  84. package/dist/contracts/quotas.js +2 -2
  85. package/dist/contracts/repository-connections.d.ts +43 -30
  86. package/dist/contracts/repository-connections.js +11 -3
  87. package/dist/contracts/resources.d.ts +12 -24
  88. package/dist/contracts/resources.js +36 -16
  89. package/dist/contracts/runtime-api.d.ts +433 -192
  90. package/dist/contracts/runtime-api.js +421 -356
  91. package/dist/contracts/runtime-app.d.ts +127 -120
  92. package/dist/contracts/runtime-app.js +19 -10
  93. package/dist/contracts/runtime-db.d.ts +5 -5
  94. package/dist/contracts/runtime-db.js +2 -2
  95. package/dist/contracts/runtime-purge.d.ts +8 -0
  96. package/dist/contracts/runtime-purge.js +7 -0
  97. package/dist/contracts/runtime-services.d.ts +219 -0
  98. package/dist/contracts/runtime-services.js +437 -0
  99. package/dist/contracts/runtime-storage.d.ts +46 -32
  100. package/dist/contracts/runtime-storage.js +31 -8
  101. package/dist/contracts/sf-config-v1.d.ts +48 -10
  102. package/dist/contracts/space-config.d.ts +69 -18
  103. package/dist/contracts/space-config.js +226 -27
  104. package/dist/contracts/spaces.d.ts +236 -450
  105. package/dist/contracts/spaces.js +131 -151
  106. package/dist/contracts/superadmin-activity.d.ts +57 -4
  107. package/dist/contracts/superadmin-activity.js +48 -2
  108. package/dist/contracts/superadmin-search.d.ts +126 -0
  109. package/dist/contracts/superadmin-search.js +61 -0
  110. package/dist/contracts/superadmin-spaces.d.ts +361 -92
  111. package/dist/contracts/superadmin-spaces.js +97 -24
  112. package/dist/contracts/superadmin-teams.d.ts +28 -10
  113. package/dist/contracts/superadmin-teams.js +5 -8
  114. package/dist/contracts/superadmin-tenants.d.ts +0 -6
  115. package/dist/contracts/superadmin-tenants.js +1 -7
  116. package/dist/contracts/superadmin.d.ts +135 -54
  117. package/dist/contracts/superadmin.js +46 -23
  118. package/dist/contracts/tags.d.ts +12 -12
  119. package/dist/contracts/tags.js +3 -3
  120. package/dist/contracts/teams.d.ts +49 -14
  121. package/dist/contracts/teams.js +40 -22
  122. package/dist/contracts/transfers.d.ts +0 -49
  123. package/dist/contracts/transfers.js +4 -8
  124. package/dist/contracts/usage.d.ts +61 -0
  125. package/dist/contracts/usage.js +64 -0
  126. package/dist/contracts/variables.d.ts +2 -7
  127. package/dist/contracts/variables.js +9 -8
  128. package/dist/contracts/webhooks.d.ts +2 -2
  129. package/dist/contracts/zero.d.ts +102 -73
  130. package/dist/contracts/zero.js +94 -32
  131. package/dist/dashboard-paths/index.d.ts +1 -1
  132. package/dist/dashboard-paths/index.js +1 -0
  133. package/dist/docs/agent-prose.d.ts +2 -2
  134. package/dist/docs/agent-prose.js +63 -70
  135. package/dist/docs/agent-setup.js +45 -15
  136. package/dist/docs/catalog.d.ts +24 -24
  137. package/dist/docs/catalog.js +35 -24
  138. package/dist/docs/error-docs.js +194 -270
  139. package/dist/docs/skills.d.ts +12 -12
  140. package/dist/docs/skills.js +4 -4
  141. package/dist/test-helpers/fetch-stub.d.ts +16 -0
  142. package/dist/test-helpers/fetch-stub.js +25 -0
  143. package/dist/utils/build-settings.d.ts +5 -1
  144. package/dist/utils/build-settings.js +91 -13
  145. package/dist/utils/canonical-json.d.ts +10 -0
  146. package/dist/utils/canonical-json.js +22 -0
  147. package/dist/utils/cast-transport.d.ts +28 -0
  148. package/dist/utils/cast-transport.js +52 -0
  149. package/dist/utils/claim-token.d.ts +0 -8
  150. package/dist/utils/claim-token.js +3 -15
  151. package/dist/utils/concurrency.js +1 -0
  152. package/dist/utils/credential-policy.d.ts +1 -1
  153. package/dist/utils/credential-policy.js +4 -3
  154. package/dist/utils/dns-instructions.js +9 -9
  155. package/dist/utils/env-file.d.ts +17 -0
  156. package/dist/utils/env-file.js +96 -0
  157. package/dist/utils/error-code.d.ts +2 -0
  158. package/dist/utils/error-code.js +8 -0
  159. package/dist/utils/generate-space-name.d.ts +8 -10
  160. package/dist/utils/generate-space-name.js +206 -21
  161. package/dist/utils/grant-decision.fixtures.json +2938 -0
  162. package/dist/utils/grants.d.ts +2 -0
  163. package/dist/utils/grants.js +26 -1
  164. package/dist/utils/gravatar.d.ts +9 -0
  165. package/dist/utils/gravatar.js +31 -0
  166. package/dist/utils/idempotency.d.ts +6 -0
  167. package/dist/utils/idempotency.js +28 -0
  168. package/dist/utils/local-space-state.d.ts +9 -16
  169. package/dist/utils/local-space-state.js +20 -50
  170. package/dist/utils/one-shot-replay.d.ts +4 -1
  171. package/dist/utils/page-colors.d.ts +14 -12
  172. package/dist/utils/page-colors.js +15 -13
  173. package/dist/utils/page-fonts.d.ts +2 -2
  174. package/dist/utils/page-fonts.js +15 -4
  175. package/dist/utils/pages.d.ts +21 -3
  176. package/dist/utils/pages.js +42 -13
  177. package/dist/utils/publish-form-data.d.ts +12 -0
  178. package/dist/utils/publish-form-data.js +10 -0
  179. package/dist/utils/publish-policy.d.ts +27 -0
  180. package/dist/utils/publish-policy.fixtures.json +403 -0
  181. package/dist/utils/publish-policy.js +45 -20
  182. package/dist/utils/push-new.d.ts +7 -0
  183. package/dist/utils/push-new.js +7 -0
  184. package/dist/utils/query-keys.d.ts +4 -5
  185. package/dist/utils/query-keys.js +2 -3
  186. package/dist/utils/runtime-paths.d.ts +5 -0
  187. package/dist/utils/runtime-paths.js +5 -0
  188. package/dist/utils/runtime-upload-batch.d.ts +0 -5
  189. package/dist/utils/runtime-upload-batch.js +1 -27
  190. package/dist/utils/runtime-upload.d.ts +6 -11
  191. package/dist/utils/runtime-upload.js +10 -13
  192. package/dist/utils/secure-local-file.js +5 -16
  193. package/dist/utils/space-config.d.ts +1 -34
  194. package/dist/utils/space-config.js +8 -326
  195. package/dist/utils/static-runtime-policy.d.ts +9 -3
  196. package/dist/utils/static-runtime-policy.fixtures.json +38 -41
  197. package/dist/utils/static-runtime-policy.js +22 -56
  198. package/dist/utils/storage-policy.d.ts +1 -1
  199. package/dist/utils/storage-policy.js +3 -1
  200. package/dist/utils/structured-error.d.ts +14 -0
  201. package/dist/utils/structured-error.js +22 -0
  202. package/dist/utils/upload-session.d.ts +4 -1
  203. package/dist/utils/upload-session.js +33 -5
  204. package/dist/utils/version-path.js +13 -4
  205. package/dist/vocabulary.d.ts +13 -11
  206. package/dist/vocabulary.js +42 -28
  207. package/package.json +7 -17
  208. package/dist/config/postgres-budget.d.ts +0 -129
  209. package/dist/config/postgres-budget.js +0 -140
  210. package/dist/config/postgres-budget.json +0 -51
  211. package/dist/contracts/archives.d.ts +0 -331
  212. package/dist/contracts/archives.js +0 -120
  213. package/dist/contracts/deployments.d.ts +0 -574
  214. package/dist/contracts/deployments.js +0 -97
  215. package/dist/contracts/sites.d.ts +0 -416
  216. package/dist/contracts/sites.js +0 -168
  217. package/dist/contracts/superadmin-queues.d.ts +0 -414
  218. package/dist/contracts/superadmin-queues.js +0 -202
  219. package/dist/contracts/superadmin-runtime.d.ts +0 -27
  220. package/dist/contracts/superadmin-runtime.js +0 -38
  221. package/dist/index.d.ts +0 -1
  222. package/dist/index.js +0 -1
  223. package/dist/utils/api.d.ts +0 -4
  224. package/dist/utils/api.js +0 -13
@@ -141,7 +141,7 @@ export function policyIsSubsetOfGrantor(requested, grantor) {
141
141
  return statement.actions.every((action) => statement.resources.every((resource) => grantorAllows(grantor, action, resource, statement.conditions)));
142
142
  }) && grantorDeniesArePreserved(requested, grantor));
143
143
  }
144
- // Request-time evaluation (internal-docs/platform.md IAM-lite): explicit deny wins,
144
+ // Request-time evaluation (the platform spec IAM-lite): explicit deny wins,
145
145
  // explicit allow permits, otherwise implicit deny. Condition keys are ANDed and an
146
146
  // unresolvable condition attribute fails closed (see `conditionsMatch`).
147
147
  export function policyAllows(input) {
@@ -152,7 +152,7 @@ export function policyAllows(input) {
152
152
  return resources.some((resource) => matchesEffect(input.policy, "allow", input.action, resource, input.conditions, "request"));
153
153
  }
154
154
  // The tenants a credential's policy grants any access to. Drives tenant
155
- // selection (internal-docs/platform.md Tenant): `X-Spacefast-Tenant-Id` may pick
155
+ // selection (the platform spec Tenant): `X-Spacefast-Tenant-Id` may pick
156
156
  // one granted tenant but is never an authority by itself, and a token spanning
157
157
  // multiple tenants must fail ambiguous requests with `tenant_selection_required`.
158
158
  export function grantedTenantsFromPolicy(policy) {
@@ -259,7 +259,7 @@ function resourceMatches(pattern, resource) {
259
259
  if (pattern.endsWith("/*")) {
260
260
  return resource === pattern.slice(0, -2) || resource.startsWith(pattern.slice(0, -1));
261
261
  }
262
- // A tenant-rooted resource is scope-wide (internal-docs/platform.md L617/L879:
262
+ // A tenant-rooted resource is scope-wide (the platform spec:
263
263
  // `stt://tenant/{t}` is a grantable StatticResource and resource grants cover
264
264
  // their subtree): it covers every resource inside that tenant. This is the
265
265
  // tenant-scoped (partner/agency) credential shape.
@@ -273,6 +273,7 @@ function conditionsMatch(statementConditions, contextConditions, effect, mode) {
273
273
  return true;
274
274
  }
275
275
  return Object.entries(statementConditions).every(([key, value]) => {
276
+ // SAFETY: Object.entries obtains key from the named RequestCondition object immediately above.
276
277
  const resolved = contextConditions?.[key];
277
278
  if (resolved === undefined && mode === "request") {
278
279
  // Fail closed on unresolvable condition attributes: the condition never
@@ -15,15 +15,15 @@ export function addressDnsInstructionsForHostname(input) {
15
15
  normalizeDnsName(instruction.name) !== hostname) {
16
16
  return [];
17
17
  }
18
- return [
19
- {
20
- type: instruction.type,
21
- name: instruction.name,
22
- value: instruction.value,
23
- purpose: instruction.purpose,
24
- ...(instruction.ttl === undefined ? {} : { ttl: instruction.ttl }),
25
- },
26
- ];
18
+ const result = {
19
+ type: instruction.type,
20
+ name: instruction.name,
21
+ value: instruction.value,
22
+ purpose: instruction.purpose,
23
+ };
24
+ if (instruction.ttl !== undefined)
25
+ result.ttl = instruction.ttl;
26
+ return [result];
27
27
  });
28
28
  }
29
29
  function normalizeAddress(value) {
@@ -0,0 +1,17 @@
1
+ export type ParsedEnvFileEntry = {
2
+ name: string;
3
+ value: string;
4
+ line: number;
5
+ };
6
+ type ValidationErrorFactory = (message: string) => Error;
7
+ export declare function parseEnvFile(content: string, options?: {
8
+ reservedStatticPrefix?: boolean;
9
+ validationError?: ValidationErrorFactory;
10
+ }): ParsedEnvFileEntry[];
11
+ export declare function loadEnvFileSource<const File extends string>(root: string, files: readonly File[], options?: {
12
+ validationError?: ValidationErrorFactory;
13
+ }): Promise<{
14
+ file: File;
15
+ content: string;
16
+ } | null>;
17
+ export {};
@@ -0,0 +1,96 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { variableNameSchema } from "../contracts/variables.js";
4
+ import { hasErrorCode } from "./error-code.js";
5
+ import { structuredValidationError } from "./structured-error.js";
6
+ const localEnvNamePattern = /^[A-Za-z_][A-Za-z0-9_]*$/;
7
+ function stripInlineComment(value) {
8
+ let quoted = null;
9
+ for (let index = 0; index < value.length; index += 1) {
10
+ const char = value[index];
11
+ if (quoted) {
12
+ if (char === "\\" && quoted === '"')
13
+ index += 1;
14
+ else if (char === quoted)
15
+ quoted = null;
16
+ continue;
17
+ }
18
+ if (char === "'" || char === '"')
19
+ quoted = char;
20
+ else if (char === "#" && (index === 0 || /\s/.test(value[index - 1] ?? ""))) {
21
+ return value.slice(0, index).trimEnd();
22
+ }
23
+ }
24
+ return value.trimEnd();
25
+ }
26
+ function unescapeDoubleQuotedValue(value) {
27
+ return value.replace(/\\([nrt"\\$])/g, (_, escaped) => {
28
+ if (escaped === "n")
29
+ return "\n";
30
+ if (escaped === "r")
31
+ return "\r";
32
+ if (escaped === "t")
33
+ return "\t";
34
+ return escaped;
35
+ });
36
+ }
37
+ function parseEnvValue(rawValue, line, error) {
38
+ const value = stripInlineComment(rawValue.trim());
39
+ if (value.startsWith('"')) {
40
+ if (!value.endsWith('"') || value.length === 1) {
41
+ throw error(`Invalid .env value on line ${line}: missing closing double quote.`);
42
+ }
43
+ return unescapeDoubleQuotedValue(value.slice(1, -1));
44
+ }
45
+ if (value.startsWith("'")) {
46
+ if (!value.endsWith("'") || value.length === 1) {
47
+ throw error(`Invalid .env value on line ${line}: missing closing single quote.`);
48
+ }
49
+ return value.slice(1, -1);
50
+ }
51
+ return value;
52
+ }
53
+ export function parseEnvFile(content, options = { reservedStatticPrefix: true }) {
54
+ const error = options.validationError ?? structuredValidationError;
55
+ const entries = new Map();
56
+ const lines = content.replace(/^\uFEFF/, "").split(/\r?\n/);
57
+ for (const [index, rawLine] of lines.entries()) {
58
+ const line = index + 1;
59
+ const trimmed = rawLine.trim();
60
+ if (!trimmed || trimmed.startsWith("#"))
61
+ continue;
62
+ const withoutExport = trimmed.startsWith("export ")
63
+ ? trimmed.slice("export ".length).trim()
64
+ : trimmed;
65
+ const equalsIndex = withoutExport.indexOf("=");
66
+ if (equalsIndex < 0)
67
+ throw error(`Invalid .env entry on line ${line}: expected NAME=value.`);
68
+ const name = withoutExport.slice(0, equalsIndex).trim();
69
+ const validName = options.reservedStatticPrefix === false
70
+ ? localEnvNamePattern.test(name)
71
+ : variableNameSchema.safeParse(name).success;
72
+ if (!validName)
73
+ throw error(`Invalid .env variable name on line ${line}: ${name}.`);
74
+ const value = parseEnvValue(withoutExport.slice(equalsIndex + 1), line, error);
75
+ if (value.length === 0) {
76
+ throw error(`Invalid .env value on line ${line}: empty values are not supported yet.`);
77
+ }
78
+ entries.set(name, { name, value, line });
79
+ }
80
+ return [...entries.values()];
81
+ }
82
+ export async function loadEnvFileSource(root, files, options = {}) {
83
+ const error = options.validationError ?? structuredValidationError;
84
+ const candidates = await Promise.all(files.map(async (file) => {
85
+ const content = await readFile(path.join(root, file), "utf8").catch((reason) => {
86
+ if (hasErrorCode(reason, "ENOENT"))
87
+ return null;
88
+ throw reason;
89
+ });
90
+ return content === null ? null : { file, content };
91
+ }));
92
+ const present = candidates.filter((candidate) => candidate !== null);
93
+ if (present.length > 1)
94
+ throw error(`Use either ${files[0]} or ${files[1]}, not both.`);
95
+ return present[0] ?? null;
96
+ }
@@ -0,0 +1,2 @@
1
+ /** True when `error` carries the given syscall-style `code` (ENOENT, EEXIST, …). */
2
+ export declare function hasErrorCode(error: unknown, code: string): boolean;
@@ -0,0 +1,8 @@
1
+ /** True when `error` carries the given syscall-style `code` (ENOENT, EEXIST, …). */
2
+ export function hasErrorCode(error, code) {
3
+ return (error !== null &&
4
+ typeof error === "object" &&
5
+ "code" in error &&
6
+ // SAFETY: The preceding checks prove error is a non-null object with a code property.
7
+ error.code === code);
8
+ }
@@ -1,14 +1,12 @@
1
1
  /**
2
- * Generates a whimsical, WordPress-flavored space title.
2
+ * Generates a short, readable space title.
3
3
  *
4
- * The pool mixes WordPress jargon (Codex, Permalink, Gutenberg, Pingback)
5
- * with engineering/web adjectives so the output reads like a tiny inside
6
- * joke instead of an auto-increment. Users can rename later, so the only
7
- * requirement is that two back-to-back calls almost never collide.
4
+ * The pool mixes a little WordPress and web flavor with broad nature, color,
5
+ * motion, and craft vocabulary. The result should suit any site instead of
6
+ * reading like a CMS inside joke, while staying compact enough for a hostname.
8
7
  *
9
- * Pool size: 32 × 32 = 1024 combinations. Combined with the collision
10
- * handling in `uniqueSpaceSlug`, per-team conflicts are very
11
- * unlikely. The generator is intentionally dependency-free so it can be
12
- * shared by the control-plane, the CLI, and any future surface.
8
+ * The generator is intentionally dependency-free so it can be shared by the
9
+ * control-plane, dashboard, CLI, and future publishing surfaces.
13
10
  */
14
- export declare function generateSpaceTitle(): string;
11
+ export declare const SPACE_TITLE_COMBINATION_COUNT: number;
12
+ export declare function generateSpaceTitle(random?: () => number): string;
@@ -1,15 +1,12 @@
1
1
  /**
2
- * Generates a whimsical, WordPress-flavored space title.
2
+ * Generates a short, readable space title.
3
3
  *
4
- * The pool mixes WordPress jargon (Codex, Permalink, Gutenberg, Pingback)
5
- * with engineering/web adjectives so the output reads like a tiny inside
6
- * joke instead of an auto-increment. Users can rename later, so the only
7
- * requirement is that two back-to-back calls almost never collide.
4
+ * The pool mixes a little WordPress and web flavor with broad nature, color,
5
+ * motion, and craft vocabulary. The result should suit any site instead of
6
+ * reading like a CMS inside joke, while staying compact enough for a hostname.
8
7
  *
9
- * Pool size: 32 × 32 = 1024 combinations. Combined with the collision
10
- * handling in `uniqueSpaceSlug`, per-team conflicts are very
11
- * unlikely. The generator is intentionally dependency-free so it can be
12
- * shared by the control-plane, the CLI, and any future surface.
8
+ * The generator is intentionally dependency-free so it can be shared by the
9
+ * control-plane, dashboard, CLI, and future publishing surfaces.
13
10
  */
14
11
  const ADJECTIVES = [
15
12
  "Atomic",
@@ -44,6 +41,102 @@ const ADJECTIVES = [
44
41
  "Templated",
45
42
  "Responsive",
46
43
  "Trackbacked",
44
+ "Agile",
45
+ "Amber",
46
+ "Ancient",
47
+ "Arctic",
48
+ "Azure",
49
+ "Balanced",
50
+ "Bold",
51
+ "Bright",
52
+ "Brisk",
53
+ "Calm",
54
+ "Candid",
55
+ "Celestial",
56
+ "Clever",
57
+ "Coastal",
58
+ "Composed",
59
+ "Cosmic",
60
+ "Crisp",
61
+ "Curious",
62
+ "Daring",
63
+ "Deep",
64
+ "Electric",
65
+ "Elegant",
66
+ "Emerald",
67
+ "Endless",
68
+ "Evergreen",
69
+ "Fluid",
70
+ "Focused",
71
+ "Gentle",
72
+ "Golden",
73
+ "Grand",
74
+ "Harmonic",
75
+ "Hidden",
76
+ "Honest",
77
+ "Indigo",
78
+ "Infinite",
79
+ "Keen",
80
+ "Kind",
81
+ "Lively",
82
+ "Lucid",
83
+ "Lunar",
84
+ "Magnetic",
85
+ "Mellow",
86
+ "Modern",
87
+ "Nimble",
88
+ "Northern",
89
+ "Open",
90
+ "Pacific",
91
+ "Patient",
92
+ "Polished",
93
+ "Prime",
94
+ "Quiet",
95
+ "Radiant",
96
+ "Rapid",
97
+ "Rare",
98
+ "Ready",
99
+ "Regal",
100
+ "Remote",
101
+ "Restless",
102
+ "Robust",
103
+ "Royal",
104
+ "Sable",
105
+ "Silent",
106
+ "Simple",
107
+ "Solar",
108
+ "Steady",
109
+ "Stellar",
110
+ "Still",
111
+ "Swift",
112
+ "Tactile",
113
+ "Tidy",
114
+ "Timeless",
115
+ "Tranquil",
116
+ "True",
117
+ "Vivid",
118
+ "Warm",
119
+ "Wild",
120
+ "Wise",
121
+ "Woven",
122
+ "Young",
123
+ "Zealous",
124
+ "Airy",
125
+ "Autumn",
126
+ "Blue",
127
+ "Clear",
128
+ "Copper",
129
+ "Distant",
130
+ "Early",
131
+ "Fresh",
132
+ "Glowing",
133
+ "Green",
134
+ "Light",
135
+ "Misty",
136
+ "Neon",
137
+ "Silver",
138
+ "Spring",
139
+ "Summer",
47
140
  ];
48
141
  const NOUNS = [
49
142
  "Codex",
@@ -78,18 +171,110 @@ const NOUNS = [
78
171
  "Gravatar",
79
172
  "Reblog",
80
173
  "Opengraph",
174
+ "Acre",
175
+ "Arcade",
176
+ "Atlas",
177
+ "Beacon",
178
+ "Birch",
179
+ "Bloom",
180
+ "Bridge",
181
+ "Brook",
182
+ "Canyon",
183
+ "Cedar",
184
+ "Circuit",
185
+ "Cloud",
186
+ "Coast",
187
+ "Comet",
188
+ "Cove",
189
+ "Creek",
190
+ "Delta",
191
+ "Dune",
192
+ "Echo",
193
+ "Ember",
194
+ "Field",
195
+ "Fjord",
196
+ "Forest",
197
+ "Forge",
198
+ "Garden",
199
+ "Grove",
200
+ "Harbor",
201
+ "Haven",
202
+ "Hill",
203
+ "Horizon",
204
+ "Island",
205
+ "Junction",
206
+ "Kite",
207
+ "Lake",
208
+ "Lantern",
209
+ "Meadow",
210
+ "Mesa",
211
+ "Moon",
212
+ "Nest",
213
+ "Oak",
214
+ "Ocean",
215
+ "Orchard",
216
+ "Peak",
217
+ "Pine",
218
+ "Plain",
219
+ "Pond",
220
+ "Prairie",
221
+ "Prism",
222
+ "Reef",
223
+ "Ridge",
224
+ "River",
225
+ "Road",
226
+ "Rock",
227
+ "Sage",
228
+ "Shore",
229
+ "Signal",
230
+ "Sky",
231
+ "Spark",
232
+ "Star",
233
+ "Stone",
234
+ "Studio",
235
+ "Summit",
236
+ "Sun",
237
+ "Trail",
238
+ "Vale",
239
+ "Valley",
240
+ "Vault",
241
+ "Wave",
242
+ "Willow",
243
+ "Wind",
244
+ "Window",
245
+ "Wood",
246
+ "Bay",
247
+ "Branch",
248
+ "Breeze",
249
+ "Canvas",
250
+ "Castle",
251
+ "Cavern",
252
+ "Cliff",
253
+ "Dawn",
254
+ "Drift",
255
+ "Falcon",
256
+ "Flame",
257
+ "Glade",
258
+ "Harborlight",
259
+ "Loom",
260
+ "Maple",
261
+ "Marsh",
262
+ "North",
263
+ "Pebble",
264
+ "Quartz",
265
+ "Rain",
266
+ "Range",
267
+ "Terrace",
268
+ "Thicket",
269
+ "Wren",
81
270
  ];
82
- function pickRandom(list) {
83
- if (list.length === 0) {
84
- throw new Error("generateSpaceName: word list is empty.");
271
+ export const SPACE_TITLE_COMBINATION_COUNT = ADJECTIVES.length * NOUNS.length;
272
+ export function generateSpaceTitle(random = Math.random) {
273
+ const index = Math.floor(random() * SPACE_TITLE_COMBINATION_COUNT);
274
+ const adjective = ADJECTIVES[Math.floor(index / NOUNS.length)];
275
+ const noun = NOUNS[index % NOUNS.length];
276
+ if (!adjective || !noun) {
277
+ throw new Error("generateSpaceName: random source must return a value from 0 up to 1.");
85
278
  }
86
- const index = Math.floor(Math.random() * list.length);
87
- const value = list[index];
88
- if (value === undefined) {
89
- throw new Error("generateSpaceName: word list contained a hole.");
90
- }
91
- return value;
92
- }
93
- export function generateSpaceTitle() {
94
- return `${pickRandom(ADJECTIVES)} ${pickRandom(NOUNS)}`;
279
+ return `${adjective} ${noun}`;
95
280
  }