@wtfalch/foundry 0.17.1 → 0.18.0

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.
@@ -132,11 +132,11 @@ export interface FoundryPlatformStepExecutorOptions {
132
132
  */
133
133
  ai?: PlatformAiDeps;
134
134
  /**
135
- * #478: dependencies for `coolify:app` keyed {@link PLATFORM_NAMES_KEY} --
135
+ * #478: dependencies for `coolify:app` keyed {@link PLATFORM_EDGE_KEY} --
136
136
  * optional for the same reason as `auth`; a host that declares
137
- * `platform.names.enabled` without it gets the step reported as blocked.
137
+ * `platform.edge.enabled` without it gets the step reported as blocked.
138
138
  */
139
- names?: PlatformNamesDeps;
139
+ edge?: PlatformEdgeDeps;
140
140
  /**
141
141
  * #175: dependencies for `coolify:app` keyed {@link PLATFORM_ARCHON_KEY}
142
142
  * -- optional for the same reason as {@link auth}.
@@ -203,8 +203,8 @@ export interface FoundryPlatformStepExecutorOptions {
203
203
  * #172 adds `coolify:app` keyed {@link PLATFORM_AI_KEY}, the platform's AI
204
204
  * host ({@link provisionPlatformAi}), once a host passes {@link PlatformAiDeps}.
205
205
  *
206
- * #478 adds `coolify:app` keyed {@link PLATFORM_NAMES_KEY}, the names host
207
- * ({@link provisionPlatformNames}), once a host passes {@link PlatformNamesDeps}.
206
+ * #478 adds `coolify:app` keyed {@link PLATFORM_EDGE_KEY}, the edge host
207
+ * ({@link provisionPlatformEdge}), once a host passes {@link PlatformEdgeDeps}.
208
208
  *
209
209
  * #175 adds `coolify:app` keyed {@link PLATFORM_ARCHON_KEY}, Archon itself
210
210
  * ({@link provisionPlatformArchon}), once a host passes
@@ -225,7 +225,7 @@ export declare class FoundryPlatformStepExecutor implements PlatformStepExecutor
225
225
  private readonly integrations?;
226
226
  private readonly files?;
227
227
  private readonly ai?;
228
- private readonly names?;
228
+ private readonly edge?;
229
229
  private readonly archon?;
230
230
  private readonly backup?;
231
231
  constructor(cloudflare: Pick<CloudflarePort, 'findZoneByApex' | 'createZone'>, declaredOrgStore: Pick<DeclaredOrgStore, 'findOrgIdForZone' | 'list' | 'get'>, options?: FoundryPlatformStepExecutorOptions);
@@ -236,7 +236,7 @@ export declare class FoundryPlatformStepExecutor implements PlatformStepExecutor
236
236
  files?: string;
237
237
  integrations?: string;
238
238
  ai?: string;
239
- names?: string;
239
+ edge?: string;
240
240
  archon?: string;
241
241
  mail?: string;
242
242
  backupExecutorMissing?: boolean;
@@ -428,7 +428,7 @@ export interface PlatformArchonDeps {
428
428
  zitadelForInstance?: (issuerUrl: string) => PlatformArchonDeps['zitadel'];
429
429
  /**
430
430
  * Who the Cloudflare Access app in front of Archon lets through. Host
431
- * config, not `DeclaredPlatform`: the platform record names services, not
431
+ * config, not `DeclaredPlatform`: the platform record edge services, not
432
432
  * people. Empty blocks the step (`blockedSteps`) rather than building an
433
433
  * Access app nobody can pass.
434
434
  */
@@ -822,7 +822,7 @@ export declare const FILES_MANAGEMENT_KEY_ID = "foundry-1";
822
822
  export declare const FILES_MANAGEMENT_KEY_REF = "files:platform:managementKey";
823
823
  /** The ref the files host's introspection client secret is delivered under. */
824
824
  export declare const FILES_INTROSPECTION_SECRET_REF = "zitadel:platform:files:introspection";
825
- export interface PlatformNamesRuntime {
825
+ export interface PlatformEdgeRuntime {
826
826
  fetch?: typeof fetch;
827
827
  sleep?: (ms: number) => Promise<void>;
828
828
  now?: () => number;
@@ -831,17 +831,17 @@ export interface PlatformNamesRuntime {
831
831
  readyTimeoutMs?: number;
832
832
  readyIntervalMs?: number;
833
833
  }
834
- export interface PlatformNamesDeps {
834
+ export interface PlatformEdgeDeps {
835
835
  coolify: Pick<CoolifyPort, 'findProjectByName' | 'createProject' | 'findOrCreateEnvironment' | 'listServers' | 'findApplicationByName' | 'getApplication' | 'requireGithubApp' | 'createGithubAppApplication' | 'createDockerfileApplication' | 'listDatabases' | 'createPostgresDatabase' | 'getDatabase' | 'bulkUpsertEnvs' | 'listEnvs' | 'updateApplication' | 'deploy' | 'deployAndWait' | 'raw'>;
836
836
  cloudflare: Pick<CloudflarePort, 'findZoneByApex' | 'findTunnelByName' | 'createTunnel' | 'putTunnelConfig' | 'getTunnelToken' | 'findDnsRecord' | 'createDnsRecord' | 'updateDnsRecord'>;
837
837
  deliverSecret: FoundryStepExecutorPorts['deliverSecret'];
838
838
  /**
839
- * Reads the names service's own Cloudflare API token back, held under
840
- * {@link PLATFORM_NAMES_CLOUDFLARE_TOKEN_REF} -- a human step (the issue's
839
+ * Reads the edge service's own Cloudflare API token back, held under
840
+ * {@link PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF} -- a human step (the issue's
841
841
  * own "Human steps"), never minted here: foundry has no Cloudflare
842
842
  * account of its own to carve that token out of. Absent, or with nothing
843
843
  * held under that ref yet, is reported blocked by `blockedSteps`
844
- * ({@link namesBlockedReason}), never planned to throw.
844
+ * ({@link edgeBlockedReason}), never planned to throw.
845
845
  */
846
846
  heldKeys?: {
847
847
  resolve(ref: string): Promise<string | null>;
@@ -853,7 +853,7 @@ export interface PlatformNamesDeps {
853
853
  */
854
854
  cloudflareAccountId?: string;
855
855
  /** Clock, sleep and fetch for the readiness wait and delivery retries; real ones by default. */
856
- runtime?: PlatformNamesRuntime;
856
+ runtime?: PlatformEdgeRuntime;
857
857
  }
858
858
  /**
859
859
  * #174: everything {@link provisionPlatformIntegrations} needs beyond
@@ -7,7 +7,7 @@ import { ensureCloudflaredConnector } from './cloudflared-connector.js';
7
7
  import { waitForDeploymentFinished, waitForHealthyVersion, waitForNewDeployment, } from './deploy-health.js';
8
8
  import { ACCESS_POLICY_NAME, getDatabaseStarted, isNotFoundError, isRunningOrStarting, } from './executor.js';
9
9
  import { coolifyDomains, filesShareHostname } from './hostnames.js';
10
- import { AUTH_ZITADEL_RUN_OPTIONS, JOBS_SCHEDULER_KEY, PLATFORM_AI_APPLIED_GITREF_SCOPE_KEY, PLATFORM_AI_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_AI_DEPLOY_PENDING_SCOPE_KEY, PLATFORM_AI_INTERNAL_URL_SCOPE_KEY, PLATFORM_AI_KEY, PLATFORM_AI_MANAGEMENT_KEY_CONFLICT_SCOPE_KEY, PLATFORM_AI_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_AI_MANAGEMENT_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_AI_MIGRATE_BLOCKED_SCOPE_KEY, PLATFORM_AI_ORGANISATION_SCOPE_KEY, PLATFORM_AI_SIGNING_KEY_SET_SCOPE_KEY, PLATFORM_AI_SIGNING_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_BROKER_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_OPERATOR_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_ROLLING_UPDATE_SCOPE_KEY, PLATFORM_ARCHON_CONNECTOR_APP_SCOPE_KEY, PLATFORM_ARCHON_COOLIFY_READ_TOKEN_REF, PLATFORM_ARCHON_ENVS_DEPLOYED_SCOPE_KEY, PLATFORM_ARCHON_GATE_CLOSED_SCOPE_KEY, PLATFORM_ARCHON_INTEGRATIONS_KEY_SYNCED_SCOPE_KEY, PLATFORM_ARCHON_KEY, PLATFORM_ARCHON_MASTER_CLOUDFLARE_TOKEN_REF, PLATFORM_ARCHON_MASTER_COOLIFY_TOKEN_REF, PLATFORM_ARCHON_MASTER_COOLIFY_URL_REF, PLATFORM_AUTH_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_ADMIN_USER_SCOPE_KEY, PLATFORM_AUTH_BROKER_DEPLOYED_SCOPE_KEY, PLATFORM_AUTH_BROKER_SCOPE_KEY, PLATFORM_AUTH_CONNECTOR_APP_SCOPE_KEY, PLATFORM_AUTH_INSTANCE_SCOPE_KEY, PLATFORM_AUTH_INSTANCE_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_KEY, PLATFORM_AUTH_LOGIN_CLIENT_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_LOGIN_CLIENT_USER_SCOPE_KEY, PLATFORM_AUTH_OWNER_INVITE_SCOPE_KEY, PLATFORM_AUTH_SMTP_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_APPLIED_IMAGE_TAG_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_RUN_OPTIONS_SCOPE_KEY, PLATFORM_BACKUP_DATABASE_SCOPE_KEYS, PLATFORM_BACKUP_SERVICE_KEYS, PLATFORM_FILES_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_FILES_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_FILES_INTERNAL_URL_SCOPE_KEY, PLATFORM_FILES_INTROSPECTION_SCOPE_KEY, PLATFORM_FILES_INTROSPECTION_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_KEY, PLATFORM_FILES_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_FILES_MANAGEMENT_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_INTEGRATIONS_APPLIED_GITREF_SCOPE_KEY, PLATFORM_INTEGRATIONS_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY, PLATFORM_INTEGRATIONS_KEY_ID_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_ROTATION_PREVIOUS_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_ROTATION_REQUESTED_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_ROTATION_UNDELIVERED_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_SET_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_INTEGRATIONS_RUNNER_KEYRING_DEPLOYED_SCOPE_KEY, PLATFORM_MAIL_ADMIN_KEY_SCOPE_KEY, PLATFORM_MAIL_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_MAIL_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_MAIL_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_MAIL_CONNECTOR_APP_SCOPE_KEY, PLATFORM_MAIL_INTERNAL_URL_SCOPE_KEY, PLATFORM_MAIL_KEY, PLATFORM_MAIL_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_NAMES_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_NAMES_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_NAMES_CLOUDFLARE_TOKEN_REF, PLATFORM_NAMES_KEY, PLATFORM_NAMES_KEY_REF, PLATFORM_NAMES_PLATFORM_KEY_SET_SCOPE_KEY, PLATFORM_NAMES_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY, archonBootstrapOperator, parseBrokerDeployRecord, parseLoginClientRecord, platformMailMxHost, } from './platform-diff.js';
10
+ import { AUTH_ZITADEL_RUN_OPTIONS, JOBS_SCHEDULER_KEY, PLATFORM_AI_APPLIED_GITREF_SCOPE_KEY, PLATFORM_AI_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_AI_DEPLOY_PENDING_SCOPE_KEY, PLATFORM_AI_INTERNAL_URL_SCOPE_KEY, PLATFORM_AI_KEY, PLATFORM_AI_MANAGEMENT_KEY_CONFLICT_SCOPE_KEY, PLATFORM_AI_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_AI_MANAGEMENT_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_AI_MIGRATE_BLOCKED_SCOPE_KEY, PLATFORM_AI_ORGANISATION_SCOPE_KEY, PLATFORM_AI_SIGNING_KEY_SET_SCOPE_KEY, PLATFORM_AI_SIGNING_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_BROKER_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_OPERATOR_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_ROLLING_UPDATE_SCOPE_KEY, PLATFORM_ARCHON_CONNECTOR_APP_SCOPE_KEY, PLATFORM_ARCHON_COOLIFY_READ_TOKEN_REF, PLATFORM_ARCHON_ENVS_DEPLOYED_SCOPE_KEY, PLATFORM_ARCHON_GATE_CLOSED_SCOPE_KEY, PLATFORM_ARCHON_INTEGRATIONS_KEY_SYNCED_SCOPE_KEY, PLATFORM_ARCHON_KEY, PLATFORM_ARCHON_MASTER_CLOUDFLARE_TOKEN_REF, PLATFORM_ARCHON_MASTER_COOLIFY_TOKEN_REF, PLATFORM_ARCHON_MASTER_COOLIFY_URL_REF, PLATFORM_AUTH_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_ADMIN_USER_SCOPE_KEY, PLATFORM_AUTH_BROKER_DEPLOYED_SCOPE_KEY, PLATFORM_AUTH_BROKER_SCOPE_KEY, PLATFORM_AUTH_CONNECTOR_APP_SCOPE_KEY, PLATFORM_AUTH_INSTANCE_SCOPE_KEY, PLATFORM_AUTH_INSTANCE_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_KEY, PLATFORM_AUTH_LOGIN_CLIENT_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_LOGIN_CLIENT_USER_SCOPE_KEY, PLATFORM_AUTH_OWNER_INVITE_SCOPE_KEY, PLATFORM_AUTH_SMTP_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_APPLIED_IMAGE_TAG_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_RUN_OPTIONS_SCOPE_KEY, PLATFORM_BACKUP_DATABASE_SCOPE_KEYS, PLATFORM_BACKUP_SERVICE_KEYS, PLATFORM_EDGE_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_EDGE_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF, PLATFORM_EDGE_KEY, PLATFORM_EDGE_KEY_REF, PLATFORM_EDGE_PLATFORM_KEY_SET_SCOPE_KEY, PLATFORM_EDGE_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_FILES_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_FILES_INTERNAL_URL_SCOPE_KEY, PLATFORM_FILES_INTROSPECTION_SCOPE_KEY, PLATFORM_FILES_INTROSPECTION_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_KEY, PLATFORM_FILES_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_FILES_MANAGEMENT_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_INTEGRATIONS_APPLIED_GITREF_SCOPE_KEY, PLATFORM_INTEGRATIONS_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY, PLATFORM_INTEGRATIONS_KEY_ID_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_ROTATION_PREVIOUS_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_ROTATION_REQUESTED_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_ROTATION_UNDELIVERED_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_SET_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_INTEGRATIONS_RUNNER_KEYRING_DEPLOYED_SCOPE_KEY, PLATFORM_MAIL_ADMIN_KEY_SCOPE_KEY, PLATFORM_MAIL_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_MAIL_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_MAIL_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_MAIL_CONNECTOR_APP_SCOPE_KEY, PLATFORM_MAIL_INTERNAL_URL_SCOPE_KEY, PLATFORM_MAIL_KEY, PLATFORM_MAIL_ZITADEL_PROJECT_SCOPE_KEY, archonBootstrapOperator, parseBrokerDeployRecord, parseLoginClientRecord, platformMailMxHost, } from './platform-diff.js';
11
11
  import { applyCallsSfuPlatformStep } from './platform-sfu.js';
12
12
  import { CreateInstanceError, createZitadelInstance, generateSystemApiKeypair, instanceWithoutBearerMessage, systemApiUsersEnv, } from './zitadel-system-api.js';
13
13
  /** The key `runPlatformSteps` records the apex zone's id under (`system:kind:key`). */
@@ -94,8 +94,8 @@ const JOBS_SCHEDULER_REPO = 'wtfalch/jobs';
94
94
  * #172 adds `coolify:app` keyed {@link PLATFORM_AI_KEY}, the platform's AI
95
95
  * host ({@link provisionPlatformAi}), once a host passes {@link PlatformAiDeps}.
96
96
  *
97
- * #478 adds `coolify:app` keyed {@link PLATFORM_NAMES_KEY}, the names host
98
- * ({@link provisionPlatformNames}), once a host passes {@link PlatformNamesDeps}.
97
+ * #478 adds `coolify:app` keyed {@link PLATFORM_EDGE_KEY}, the edge host
98
+ * ({@link provisionPlatformEdge}), once a host passes {@link PlatformEdgeDeps}.
99
99
  *
100
100
  * #175 adds `coolify:app` keyed {@link PLATFORM_ARCHON_KEY}, Archon itself
101
101
  * ({@link provisionPlatformArchon}), once a host passes
@@ -116,7 +116,7 @@ export class FoundryPlatformStepExecutor {
116
116
  integrations;
117
117
  files;
118
118
  ai;
119
- names;
119
+ edge;
120
120
  archon;
121
121
  backup;
122
122
  constructor(cloudflare, declaredOrgStore, options = {}) {
@@ -130,7 +130,7 @@ export class FoundryPlatformStepExecutor {
130
130
  this.integrations = options.integrations;
131
131
  this.files = options.files;
132
132
  this.ai = options.ai;
133
- this.names = options.names;
133
+ this.edge = options.edge;
134
134
  this.archon = options.archon;
135
135
  this.backup = options.backup;
136
136
  }
@@ -217,14 +217,14 @@ export class FoundryPlatformStepExecutor {
217
217
  blocked.ai =
218
218
  "the platform's AI host is blocked, not planned: its signing key is already pinned but the host built the platform executor without a held-key reader to read back its private half (PlatformAiDeps.heldKeys)";
219
219
  }
220
- if (platform.names.enabled && !this.names) {
221
- blocked.names =
222
- 'the names host is blocked, not planned: the host built the platform executor without its names dependencies';
220
+ if (platform.edge.enabled && !this.edge) {
221
+ blocked.edge =
222
+ 'the edge host is blocked, not planned: the host built the platform executor without its edge dependencies';
223
223
  }
224
- else if (platform.names.enabled && this.names) {
225
- const namesBlocked = await namesBlockedReason(this.names);
226
- if (namesBlocked)
227
- blocked.names = namesBlocked;
224
+ else if (platform.edge.enabled && this.edge) {
225
+ const edgeBlocked = await edgeBlockedReason(this.edge);
226
+ if (edgeBlocked)
227
+ blocked.edge = edgeBlocked;
228
228
  }
229
229
  if (platform.archon.enabled) {
230
230
  if (!this.archon) {
@@ -375,11 +375,11 @@ export class FoundryPlatformStepExecutor {
375
375
  }
376
376
  return provisionPlatformAi(context, this.ai);
377
377
  }
378
- if (action.system === 'coolify' && action.kind === 'app' && action.key === PLATFORM_NAMES_KEY) {
379
- if (!this.names) {
380
- throw new Error('platform:names needs FoundryPlatformStepExecutor to be constructed with its names dependencies (#478)');
378
+ if (action.system === 'coolify' && action.kind === 'app' && action.key === PLATFORM_EDGE_KEY) {
379
+ if (!this.edge) {
380
+ throw new Error('platform:edge needs FoundryPlatformStepExecutor to be constructed with its edge dependencies (#478)');
381
381
  }
382
- return provisionPlatformNames(context, this.names);
382
+ return provisionPlatformEdge(context, this.edge);
383
383
  }
384
384
  if (action.system === 'coolify' &&
385
385
  action.kind === 'app' &&
@@ -5105,74 +5105,74 @@ shareDomains) {
5105
5105
  await record(PLATFORM_FILES_APPLIED_GIT_REF_SCOPE_KEY, gitRef);
5106
5106
  return { resourceId: runnerApp.appId };
5107
5107
  }
5108
- /** https://github.com/wtfalch/names -- root Dockerfile, one `runner` target (see {@link provisionPlatformNames}'s own doc comment for why there is no `migration` target any more). */
5109
- const NAMES_REPO = 'wtfalch/names';
5110
- const PLATFORM_NAMES_PROJECT = 'platform';
5111
- const PLATFORM_NAMES_DB_NAME = 'platform-names-db';
5112
- const NAMES_APP_NAME = 'names';
5108
+ /** https://github.com/wtfalch/edge -- root Dockerfile, one `runner` target (see {@link provisionPlatformEdge}'s own doc comment for why there is no `migration` target any more). */
5109
+ const EDGE_REPO = 'wtfalch/edge';
5110
+ const PLATFORM_EDGE_PROJECT = 'platform';
5111
+ const PLATFORM_EDGE_DB_NAME = 'platform-edge-db';
5112
+ const EDGE_APP_NAME = 'edge';
5113
5113
  /** The app's fixed `custom_internal_name`, the way `platform:files`' runner names itself. */
5114
- const NAMES_RUNNER_INTERNAL_NAME = 'platform-names';
5114
+ const EDGE_RUNNER_INTERNAL_NAME = 'platform-edge';
5115
5115
  /** The runner's port (its Dockerfile: `PORT=3000`, `EXPOSE 3000`). */
5116
- const NAMES_PORT = '3000';
5116
+ const EDGE_PORT = '3000';
5117
5117
  /** The Postgres database name, and the owner role's name per the host's own `.env.example`. */
5118
- const NAMES_DB = 'names';
5119
- const NAMES_OWNER_ROLE = 'names_owner';
5118
+ const EDGE_DB = 'names';
5119
+ const EDGE_OWNER_ROLE = 'names_owner';
5120
5120
  /** The restricted runtime role `migrate.mjs`'s own `ensureRuntimeRole` creates or syncs at every boot. */
5121
- const NAMES_RUNTIME_ROLE = 'names_rt';
5122
- const NAMES_TUNNEL_NAME = 'platform-names-tunnel';
5123
- /** #197: the one Coolify app that runs `cloudflared` for {@link NAMES_TUNNEL_NAME}. */
5124
- const NAMES_CLOUDFLARED_APP_NAME = 'platform-names-cloudflared';
5125
- const PLATFORM_NAMES_PROJECT_SCOPE_KEY = 'coolify_project_platform_names';
5126
- const PLATFORM_NAMES_DB_SCOPE_KEY = 'coolify_platform_names_database';
5127
- const PLATFORM_NAMES_APP_SCOPE_KEY = 'coolify_platform_names_app';
5128
- const PLATFORM_NAMES_TUNNEL_SCOPE_KEY = 'cloudflare_platform_names_tunnel';
5129
- const PLATFORM_NAMES_CONNECTOR_APP_SCOPE_KEY = 'coolify_platform_names_connector_app';
5121
+ const EDGE_RUNTIME_ROLE = 'names_rt';
5122
+ const EDGE_TUNNEL_NAME = 'platform-edge-tunnel';
5123
+ /** #197: the one Coolify app that runs `cloudflared` for {@link EDGE_TUNNEL_NAME}. */
5124
+ const EDGE_CLOUDFLARED_APP_NAME = 'platform-edge-cloudflared';
5125
+ const PLATFORM_EDGE_PROJECT_SCOPE_KEY = 'coolify_project_platform_edge';
5126
+ const PLATFORM_EDGE_DB_SCOPE_KEY = 'coolify_platform_edge_database';
5127
+ const PLATFORM_EDGE_APP_SCOPE_KEY = 'coolify_platform_edge_app';
5128
+ const PLATFORM_EDGE_TUNNEL_SCOPE_KEY = 'cloudflare_platform_edge_tunnel';
5129
+ const PLATFORM_EDGE_CONNECTOR_APP_SCOPE_KEY = 'coolify_platform_edge_connector_app';
5130
5130
  /**
5131
5131
  * Written only when absent, never overwritten -- the `PLATFORM_FILES_RUNNER_DEFAULTS`
5132
5132
  * convention, so an operator's own cap or rate survives every apply. Values
5133
5133
  * are the host's own `.env.example` defaults.
5134
5134
  */
5135
- const PLATFORM_NAMES_RUNNER_DEFAULTS = [
5135
+ const PLATFORM_EDGE_RUNNER_DEFAULTS = [
5136
5136
  { key: 'MAX_CLAIMS_PER_ORGANISATION', value: '100' },
5137
- { key: 'NAMES_RATE_BURST', value: '10' },
5138
- { key: 'NAMES_RATE_PER_SECOND', value: '0.5' },
5137
+ { key: 'EDGE_RATE_BURST', value: '10' },
5138
+ { key: 'EDGE_RATE_PER_SECOND', value: '0.5' },
5139
5139
  ];
5140
5140
  /**
5141
- * Why `coolify:app` keyed {@link PLATFORM_NAMES_KEY} cannot be planned yet,
5142
- * or `null` when it can -- the host built no names dependencies (checked by
5141
+ * Why `coolify:app` keyed {@link PLATFORM_EDGE_KEY} cannot be planned yet,
5142
+ * or `null` when it can -- the host built no edge dependencies (checked by
5143
5143
  * the caller, `FoundryPlatformStepExecutor.blockedSteps`, before this is
5144
5144
  * even called), no Cloudflare API token held under
5145
- * {@link PLATFORM_NAMES_CLOUDFLARE_TOKEN_REF} (CLAUDE.md's "Human steps"),
5145
+ * {@link PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF} (CLAUDE.md's "Human steps"),
5146
5146
  * or no Cloudflare account id supplied beside it.
5147
5147
  */
5148
- async function namesBlockedReason(names) {
5148
+ async function edgeBlockedReason(names) {
5149
5149
  let token;
5150
5150
  try {
5151
- token = (await names.heldKeys?.resolve(PLATFORM_NAMES_CLOUDFLARE_TOKEN_REF)) ?? null;
5151
+ token = (await names.heldKeys?.resolve(PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF)) ?? null;
5152
5152
  }
5153
5153
  catch {
5154
5154
  token = null;
5155
5155
  }
5156
5156
  if (!token) {
5157
- return `the names host is blocked, not planned: no Cloudflare API token is held under ${PLATFORM_NAMES_CLOUDFLARE_TOKEN_REF} yet (the names service's own token, tunnel edit + DNS edit, never the platform's) -- a human step`;
5157
+ return `the edge host is blocked, not planned: no Cloudflare API token is held under ${PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF} yet (the edge service's own token, tunnel edit + DNS edit, never the platform's) -- a human step`;
5158
5158
  }
5159
5159
  if (!names.cloudflareAccountId) {
5160
- return 'the names host is blocked, not planned: the host supplies no Cloudflare account id (PlatformNamesDeps.cloudflareAccountId) for the token above';
5160
+ return 'the edge host is blocked, not planned: the host supplies no Cloudflare account id (PlatformEdgeDeps.cloudflareAccountId) for the token above';
5161
5161
  }
5162
5162
  return null;
5163
5163
  }
5164
5164
  /**
5165
- * #478: makes `coolify:app` keyed {@link PLATFORM_NAMES_KEY} true -- the
5166
- * names host (https://github.com/wtfalch/names), its own database, and
5167
- * foundry's own platform key, reached at `platform.names.hostname` through
5165
+ * #478: makes `coolify:app` keyed {@link PLATFORM_EDGE_KEY} true -- the
5166
+ * edge host (https://github.com/wtfalch/edge), its own database, and
5167
+ * foundry's own platform key, reached at `platform.edge.hostname` through
5168
5168
  * a Cloudflare tunnel and DNS record (the public-service shape
5169
5169
  * {@link provisionPlatformMail}/{@link provisionPlatformAuth} use, not
5170
- * `platform:files`' internal-only one -- `NAMES_URL` has to be reachable by
5170
+ * `platform:files`' internal-only one -- `EDGE_URL` has to be reachable by
5171
5171
  * every org's own app, which runs outside this Coolify network, and by
5172
5172
  * Archon).
5173
5173
  *
5174
5174
  * One Coolify app only, unlike `platform:files`/`platform:ai`'s separate
5175
- * `migrate` app: names' own Dockerfile dropped its `migration` target
5175
+ * `migrate` app: edge' own Dockerfile dropped its `migration` target
5176
5176
  * (its own comment: no generated package's Coolify app ever built or ran
5177
5177
  * that stage, which once shipped `wtfalch/cms` with an empty database and
5178
5178
  * no runtime role). `apps/host/scripts/start.sh` now runs `migrate.mjs`
@@ -5188,27 +5188,27 @@ async function namesBlockedReason(names) {
5188
5188
  * restricted `names_rt` role is never created here -- `migrate.mjs`'s own
5189
5189
  * `ensureRuntimeRole` call creates or syncs it and sets its password from
5190
5190
  * `DATABASE_URL` at every boot, so this function only has to mint that
5191
- * password once and reuse it (`ensureNamesRuntimeUrl`, the
5191
+ * password once and reuse it (`ensureEdgeRuntimeUrl`, the
5192
5192
  * `ensureFilesRuntimeUrl` shape) -- never rotated, since the role's
5193
5193
  * password is set from it on every migration.
5194
5194
  *
5195
5195
  * The platform key follows `platform:files`' management-key discipline
5196
5196
  * (CLAUDE.md rule 1): a random secret is minted once, its id recorded
5197
- * undelivered and persisted before {@link PlatformNamesDeps.deliverSecret}
5197
+ * undelivered and persisted before {@link PlatformEdgeDeps.deliverSecret}
5198
5198
  * is even tried, and the guard recorded only once delivery AND the env
5199
- * write (the SHA-256 hash, as `NAMES_PLATFORM_KEY_HASH`) both succeeded. The
5199
+ * write (the SHA-256 hash, as `EDGE_PLATFORM_KEY_HASH`) both succeeded. The
5200
5200
  * secret itself is never written to the host's own env, logged, returned
5201
5201
  * or put in an error -- only its hash ever reaches names, and the full
5202
- * value goes to {@link PlatformNamesDeps.deliverSecret} under
5203
- * {@link PLATFORM_NAMES_KEY_REF} alone, for Archon's own `NamesPort` to read
5204
- * back later when it mints or revokes an entry's own names key.
5202
+ * value goes to {@link PlatformEdgeDeps.deliverSecret} under
5203
+ * {@link PLATFORM_EDGE_KEY_REF} alone, for Archon's own `EdgePort` to read
5204
+ * back later when it mints or revokes an entry's own edge key.
5205
5205
  *
5206
5206
  * `CLOUDFLARE_API_TOKEN`/`CLOUDFLARE_ACCOUNT_ID` on the runner are never
5207
- * minted here either: they are the names service's own credential (never
5208
- * Archon's), read back from {@link PlatformNamesDeps.heldKeys} under
5209
- * {@link PLATFORM_NAMES_CLOUDFLARE_TOKEN_REF} once a human has put one there
5207
+ * minted here either: they are the edge service's own credential (never
5208
+ * Archon's), read back from {@link PlatformEdgeDeps.heldKeys} under
5209
+ * {@link PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF} once a human has put one there
5210
5210
  * (the issue's own "Human steps") -- `blockedSteps`
5211
- * ({@link namesBlockedReason}) reports the step blocked, not planned, until
5211
+ * ({@link edgeBlockedReason}) reports the step blocked, not planned, until
5212
5212
  * then.
5213
5213
  *
5214
5214
  * Every part is safe to run again after a throw partway, `platform:files`'
@@ -5220,49 +5220,49 @@ async function namesBlockedReason(names) {
5220
5220
  * app redeploys, with no new secret minted.
5221
5221
  *
5222
5222
  * Known gaps, left for review:
5223
- * - `NAMES_MAX_QUEUE_DEPTH` (the host's `.env.example`) is not set; the host
5223
+ * - `EDGE_MAX_QUEUE_DEPTH` (the host's `.env.example`) is not set; the host
5224
5224
  * falls back to its own default.
5225
- * - `NAMES_TRUST_CF_CONNECTING_IP` is always written `true` rather than
5225
+ * - `EDGE_TRUST_CF_CONNECTING_IP` is always written `true` rather than
5226
5226
  * left to the host's own default, since this step always puts the
5227
5227
  * runner behind the Cloudflare tunnel it also creates.
5228
5228
  */
5229
- async function provisionPlatformNames(context, deps) {
5229
+ async function provisionPlatformEdge(context, deps) {
5230
5230
  const { platform } = context;
5231
- const hostname = platform.names.hostname;
5232
- const gitRef = platform.names.gitRef;
5231
+ const hostname = platform.edge.hostname;
5232
+ const gitRef = platform.edge.gitRef;
5233
5233
  const recorded = context.recordedIds();
5234
5234
  const runtime = deps.runtime ?? {};
5235
5235
  const sleep = runtime.sleep ?? defaultSleep;
5236
5236
  const attempts = runtime.deliverAttempts ?? 3;
5237
- const cloudflareToken = await deps.heldKeys?.resolve(PLATFORM_NAMES_CLOUDFLARE_TOKEN_REF);
5237
+ const cloudflareToken = await deps.heldKeys?.resolve(PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF);
5238
5238
  if (!cloudflareToken || !deps.cloudflareAccountId) {
5239
- throw new Error(`platform:names needs the names service's own Cloudflare API token (held under ${PLATFORM_NAMES_CLOUDFLARE_TOKEN_REF}) and account id (PlatformNamesDeps.cloudflareAccountId); names never becomes healthy without them`);
5239
+ throw new Error(`platform:edge needs the edge service's own Cloudflare API token (held under ${PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF}) and account id (PlatformEdgeDeps.cloudflareAccountId); names never becomes healthy without them`);
5240
5240
  }
5241
5241
  // Never plan-and-throw (CLAUDE.md rule 2): the planner reports a lost
5242
5242
  // secret and plans nothing; this is the same rule for a caller that
5243
5243
  // reaches the step anyway.
5244
- const lostKey = recorded[PLATFORM_NAMES_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY];
5245
- if (lostKey && !recorded[PLATFORM_NAMES_PLATFORM_KEY_SET_SCOPE_KEY]) {
5246
- throw new Error(`platform:names: the platform key (${lostKey}) was minted but never delivered; remove the recorded key ${PLATFORM_NAMES_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY} to mint a new one`);
5244
+ const lostKey = recorded[PLATFORM_EDGE_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY];
5245
+ if (lostKey && !recorded[PLATFORM_EDGE_PLATFORM_KEY_SET_SCOPE_KEY]) {
5246
+ throw new Error(`platform:edge: the platform key (${lostKey}) was minted but never delivered; remove the recorded key ${PLATFORM_EDGE_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY} to mint a new one`);
5247
5247
  }
5248
5248
  const record = async (key, id) => {
5249
5249
  context.recordScopeId(key, id);
5250
5250
  await context.persist?.();
5251
5251
  };
5252
- let projectUuid = recorded[PLATFORM_NAMES_PROJECT_SCOPE_KEY];
5252
+ let projectUuid = recorded[PLATFORM_EDGE_PROJECT_SCOPE_KEY];
5253
5253
  if (!projectUuid) {
5254
- const found = await deps.coolify.findProjectByName(PLATFORM_NAMES_PROJECT);
5254
+ const found = await deps.coolify.findProjectByName(PLATFORM_EDGE_PROJECT);
5255
5255
  projectUuid = found
5256
5256
  ? found.uuid
5257
- : (await deps.coolify.createProject(PLATFORM_NAMES_PROJECT)).uuid;
5258
- await record(PLATFORM_NAMES_PROJECT_SCOPE_KEY, projectUuid);
5257
+ : (await deps.coolify.createProject(PLATFORM_EDGE_PROJECT)).uuid;
5258
+ await record(PLATFORM_EDGE_PROJECT_SCOPE_KEY, projectUuid);
5259
5259
  }
5260
5260
  const { environment } = await deps.coolify.findOrCreateEnvironment(projectUuid, 'production');
5261
5261
  const server = await resolvePlatformServer(deps.coolify);
5262
5262
  // ---- database ----------------------------------------------------------
5263
- let dbId = recorded[PLATFORM_NAMES_DB_SCOPE_KEY];
5263
+ let dbId = recorded[PLATFORM_EDGE_DB_SCOPE_KEY];
5264
5264
  if (!dbId) {
5265
- const found = (await deps.coolify.listDatabases()).find((db) => db.name === PLATFORM_NAMES_DB_NAME && db.environment_id === environment.id);
5265
+ const found = (await deps.coolify.listDatabases()).find((db) => db.name === PLATFORM_EDGE_DB_NAME && db.environment_id === environment.id);
5266
5266
  if (found) {
5267
5267
  dbId = found.uuid;
5268
5268
  }
@@ -5272,20 +5272,20 @@ async function provisionPlatformNames(context, deps) {
5272
5272
  server_uuid: server.uuid,
5273
5273
  environment_name: environment.name,
5274
5274
  environment_uuid: environment.uuid,
5275
- name: PLATFORM_NAMES_DB_NAME,
5276
- postgres_db: NAMES_DB,
5277
- postgres_user: NAMES_OWNER_ROLE,
5275
+ name: PLATFORM_EDGE_DB_NAME,
5276
+ postgres_db: EDGE_DB,
5277
+ postgres_user: EDGE_OWNER_ROLE,
5278
5278
  });
5279
5279
  dbId = created.uuid;
5280
5280
  }
5281
- await record(PLATFORM_NAMES_DB_SCOPE_KEY, dbId);
5281
+ await record(PLATFORM_EDGE_DB_SCOPE_KEY, dbId);
5282
5282
  }
5283
5283
  const db = await getDatabaseStarted(deps.coolify, dbId);
5284
5284
  if (!db.internal_db_url) {
5285
- throw new Error('coolify:app for the platform (names): the database has no internal_db_url yet -- retry this apply once Coolify reports one');
5285
+ throw new Error('coolify:app for the platform (edge): the database has no internal_db_url yet -- retry this apply once Coolify reports one');
5286
5286
  }
5287
5287
  // ---- the app -------------------------------------------------------------
5288
- const app = await findOrCreatePlatformApp(deps.coolify, NAMES_APP_NAME, environment, async () => {
5288
+ const app = await findOrCreatePlatformApp(deps.coolify, EDGE_APP_NAME, environment, async () => {
5289
5289
  const githubApp = await deps.coolify.requireGithubApp();
5290
5290
  return deps.coolify.createGithubAppApplication({
5291
5291
  project_uuid: projectUuid,
@@ -5293,41 +5293,41 @@ async function provisionPlatformNames(context, deps) {
5293
5293
  environment_name: environment.name,
5294
5294
  environment_uuid: environment.uuid,
5295
5295
  github_app_uuid: githubApp.uuid,
5296
- git_repository: NAMES_REPO,
5296
+ git_repository: EDGE_REPO,
5297
5297
  git_branch: gitRef,
5298
5298
  build_pack: 'dockerfile',
5299
- name: NAMES_APP_NAME,
5299
+ name: EDGE_APP_NAME,
5300
5300
  });
5301
5301
  });
5302
5302
  const appId = app.appId;
5303
- await record(PLATFORM_NAMES_APP_SCOPE_KEY, appId);
5303
+ await record(PLATFORM_EDGE_APP_SCOPE_KEY, appId);
5304
5304
  // Set on every run, not only after a create: a throw right after the
5305
5305
  // create must not leave the app on the wrong target for good, and a
5306
5306
  // changed `gitRef` has to reach an app made on an earlier one.
5307
5307
  await deps.coolify.updateApplication(appId, {
5308
5308
  dockerfile_target_build: 'runner',
5309
- custom_internal_name: NAMES_RUNNER_INTERNAL_NAME,
5309
+ custom_internal_name: EDGE_RUNNER_INTERNAL_NAME,
5310
5310
  git_branch: gitRef,
5311
5311
  });
5312
- const runtimeUrl = await ensureNamesRuntimeUrl(deps.coolify, appId, db.internal_db_url);
5312
+ const runtimeUrl = await ensureEdgeRuntimeUrl(deps.coolify, appId, db.internal_db_url);
5313
5313
  // ---- the platform key, once ----------------------------------------------
5314
5314
  // The recorded `set` id *is* the hash (never read back from Coolify's own
5315
5315
  // env, which can be missing or stale on a re-apply): the hash is never
5316
5316
  // secret, so it doubles as both the undelivered id and the value the base
5317
5317
  // env below writes, with nothing extra to compute or a live read that
5318
5318
  // could fall back to a blank value.
5319
- let keyHash = recorded[PLATFORM_NAMES_PLATFORM_KEY_SET_SCOPE_KEY] ?? '';
5319
+ let keyHash = recorded[PLATFORM_EDGE_PLATFORM_KEY_SET_SCOPE_KEY] ?? '';
5320
5320
  if (!keyHash) {
5321
5321
  const secret = randomBytes(32).toString('base64url');
5322
5322
  keyHash = createHash('sha256').update(secret).digest('hex');
5323
- await record(PLATFORM_NAMES_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY, keyHash);
5324
- await deliverWithRetry(deps.deliverSecret, PLATFORM_NAMES_KEY_REF, secret, attempts, sleep, 'the names platform key', 'platform:names');
5323
+ await record(PLATFORM_EDGE_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY, keyHash);
5324
+ await deliverWithRetry(deps.deliverSecret, PLATFORM_EDGE_KEY_REF, secret, attempts, sleep, 'the edge platform key', 'platform:edge');
5325
5325
  // Recorded as soon as delivery succeeds, before the env write below (the
5326
5326
  // base env block, further down, is what actually writes the hash) --
5327
5327
  // so a failed or crashed env write is simply retried on the next apply
5328
5328
  // instead of leaving an undelivered secret with no `set` partner and no
5329
5329
  // way to recover but a hand edit of the recorded ids.
5330
- await record(PLATFORM_NAMES_PLATFORM_KEY_SET_SCOPE_KEY, keyHash);
5330
+ await record(PLATFORM_EDGE_PLATFORM_KEY_SET_SCOPE_KEY, keyHash);
5331
5331
  }
5332
5332
  // ---- base env, written on every run --------------------------------------
5333
5333
  await deps.coolify.bulkUpsertEnvs(appId, [
@@ -5336,18 +5336,18 @@ async function provisionPlatformNames(context, deps) {
5336
5336
  { key: 'APP_URL', value: `https://${hostname}` },
5337
5337
  { key: 'CLOUDFLARE_API_TOKEN', value: cloudflareToken },
5338
5338
  { key: 'CLOUDFLARE_ACCOUNT_ID', value: deps.cloudflareAccountId },
5339
- { key: 'NAMES_TRUST_CF_CONNECTING_IP', value: 'true' },
5339
+ { key: 'EDGE_TRUST_CF_CONNECTING_IP', value: 'true' },
5340
5340
  { key: 'NODE_ENV', value: 'production' },
5341
- { key: 'NAMES_PLATFORM_KEY_HASH', value: keyHash },
5342
- ...(await missingEnvs(deps.coolify, appId, PLATFORM_NAMES_RUNNER_DEFAULTS)),
5341
+ { key: 'EDGE_PLATFORM_KEY_HASH', value: keyHash },
5342
+ ...(await missingEnvs(deps.coolify, appId, PLATFORM_EDGE_RUNNER_DEFAULTS)),
5343
5343
  ]);
5344
5344
  // ---- tunnel and DNS -------------------------------------------------------
5345
- const existingTunnel = await deps.cloudflare.findTunnelByName(NAMES_TUNNEL_NAME);
5346
- const tunnel = existingTunnel ?? (await deps.cloudflare.createTunnel(NAMES_TUNNEL_NAME));
5347
- await record(PLATFORM_NAMES_TUNNEL_SCOPE_KEY, tunnel.id);
5345
+ const existingTunnel = await deps.cloudflare.findTunnelByName(EDGE_TUNNEL_NAME);
5346
+ const tunnel = existingTunnel ?? (await deps.cloudflare.createTunnel(EDGE_TUNNEL_NAME));
5347
+ await record(PLATFORM_EDGE_TUNNEL_SCOPE_KEY, tunnel.id);
5348
5348
  await deps.cloudflare.putTunnelConfig(tunnel.id, {
5349
5349
  ingress: [
5350
- { hostname, service: `http://${NAMES_RUNNER_INTERNAL_NAME}:${NAMES_PORT}` },
5350
+ { hostname, service: `http://${EDGE_RUNNER_INTERNAL_NAME}:${EDGE_PORT}` },
5351
5351
  { service: 'http_status:404' },
5352
5352
  ],
5353
5353
  });
@@ -5356,16 +5356,16 @@ async function provisionPlatformNames(context, deps) {
5356
5356
  coolify: deps.coolify,
5357
5357
  cloudflare: deps.cloudflare,
5358
5358
  tunnelId: tunnel.id,
5359
- appName: NAMES_CLOUDFLARED_APP_NAME,
5359
+ appName: EDGE_CLOUDFLARED_APP_NAME,
5360
5360
  projectUuid,
5361
5361
  environment,
5362
5362
  resolveServer: async () => server,
5363
- recordedConnectorAppId: recorded[PLATFORM_NAMES_CONNECTOR_APP_SCOPE_KEY] ?? null,
5364
- recordAppId: (connectorAppId) => record(PLATFORM_NAMES_CONNECTOR_APP_SCOPE_KEY, connectorAppId),
5363
+ recordedConnectorAppId: recorded[PLATFORM_EDGE_CONNECTOR_APP_SCOPE_KEY] ?? null,
5364
+ recordAppId: (connectorAppId) => record(PLATFORM_EDGE_CONNECTOR_APP_SCOPE_KEY, connectorAppId),
5365
5365
  });
5366
5366
  const zoneId = recorded[apexZoneKey(platform.apex)] ?? (await exactZone(deps.cloudflare, platform.apex))?.id;
5367
5367
  if (!zoneId) {
5368
- throw new Error(`platform:names: no Cloudflare zone for ${platform.apex} to put ${hostname} in`);
5368
+ throw new Error(`platform:edge: no Cloudflare zone for ${platform.apex} to put ${hostname} in`);
5369
5369
  }
5370
5370
  const dnsTarget = `${tunnel.id}.cfargotunnel.com`;
5371
5371
  const [dnsRecord] = await deps.cloudflare.findDnsRecord(zoneId, hostname, 'CNAME');
@@ -5390,10 +5390,10 @@ async function provisionPlatformNames(context, deps) {
5390
5390
  // helper (deployment-record check, then the `/api/health` probe) can run
5391
5391
  // in one call -- unlike `platform:mail`, nothing here needs to happen
5392
5392
  // between the two phases.
5393
- await waitForNewDeployment(deps.coolify, appId, { kind: 'ready', url: `https://${hostname}/api/health` }, runtime, sleep, 'platform:names', `names stays at ${recorded[PLATFORM_NAMES_APPLIED_GIT_REF_SCOPE_KEY] ?? 'no recorded ref'}`);
5393
+ await waitForNewDeployment(deps.coolify, appId, { kind: 'ready', url: `https://${hostname}/api/health` }, runtime, sleep, 'platform:edge', `edge stays at ${recorded[PLATFORM_EDGE_APPLIED_GIT_REF_SCOPE_KEY] ?? 'no recorded ref'}`);
5394
5394
  // Last: a run that failed anywhere above is planned again.
5395
- context.recordScopeId(PLATFORM_NAMES_APPLIED_HOSTNAME_SCOPE_KEY, hostname);
5396
- await record(PLATFORM_NAMES_APPLIED_GIT_REF_SCOPE_KEY, gitRef);
5395
+ context.recordScopeId(PLATFORM_EDGE_APPLIED_HOSTNAME_SCOPE_KEY, hostname);
5396
+ await record(PLATFORM_EDGE_APPLIED_GIT_REF_SCOPE_KEY, gitRef);
5397
5397
  return { resourceId: appId };
5398
5398
  }
5399
5399
  /**
@@ -5403,7 +5403,7 @@ async function provisionPlatformNames(context, deps) {
5403
5403
  * throws a message with no part of the URL in it, since the URL carries the
5404
5404
  * owner's password.
5405
5405
  */
5406
- async function ensureNamesRuntimeUrl(coolify, appId, dbInternalUrl) {
5406
+ async function ensureEdgeRuntimeUrl(coolify, appId, dbInternalUrl) {
5407
5407
  const existing = (await coolify.listEnvs(appId)).find((e) => e.key === 'DATABASE_URL' && !e.is_preview && e.value);
5408
5408
  if (existing)
5409
5409
  return existing.value;
@@ -5414,10 +5414,10 @@ async function ensureNamesRuntimeUrl(coolify, appId, dbInternalUrl) {
5414
5414
  ({ host, pathname, search } = new URL(dbInternalUrl));
5415
5415
  }
5416
5416
  catch {
5417
- throw new Error("coolify:app for the platform (names): the database's internal_db_url could not be parsed to build the runtime DATABASE_URL");
5417
+ throw new Error("coolify:app for the platform (edge): the database's internal_db_url could not be parsed to build the runtime DATABASE_URL");
5418
5418
  }
5419
5419
  const password = randomBytes(24).toString('base64url');
5420
- return `postgres://${NAMES_RUNTIME_ROLE}:${password}@${host}${pathname}${search}`;
5420
+ return `postgres://${EDGE_RUNTIME_ROLE}:${password}@${host}${pathname}${search}`;
5421
5421
  }
5422
5422
  function aiKeys(deps) {
5423
5423
  const keys = deps?.keys;
@@ -4,7 +4,7 @@ const PLATFORM_APP_SYSTEMS = {
4
4
  'platform:mail': 'stalwart',
5
5
  'platform:files': 'files',
6
6
  'platform:ai': 'ai',
7
- 'platform:names': 'names',
7
+ 'platform:edge': 'edge',
8
8
  };
9
9
  /** The system `action` touches. The one place that decides it, so no planner sets it by hand. */
10
10
  export function stepSystemOf(action) {