@wtfalch/foundry 0.17.1 → 0.19.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.
Files changed (44) hide show
  1. package/dist/bootstrap/declare.d.ts +11 -2
  2. package/dist/bootstrap/declare.js +20 -11
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.js +2 -1
  5. package/dist/migrations/0045_names_to_edge.sql +107 -0
  6. package/dist/org.d.ts +17 -17
  7. package/dist/org.js +48 -58
  8. package/dist/plan/agora.d.ts +25 -0
  9. package/dist/plan/agora.js +25 -0
  10. package/dist/plan/boule.d.ts +8 -0
  11. package/dist/plan/boule.js +8 -0
  12. package/dist/plan/diff.d.ts +3 -1
  13. package/dist/plan/diff.js +115 -52
  14. package/dist/plan/entry-edge-key.d.ts +79 -0
  15. package/dist/plan/{entry-names-key.js → entry-edge-key.js} +90 -66
  16. package/dist/plan/executor.d.ts +87 -42
  17. package/dist/plan/executor.js +277 -120
  18. package/dist/plan/index.d.ts +2 -2
  19. package/dist/plan/index.js +1 -1
  20. package/dist/plan/live.d.ts +3 -3
  21. package/dist/plan/login-host.d.ts +15 -11
  22. package/dist/plan/login-host.js +16 -16
  23. package/dist/plan/plan-apply.d.ts +6 -5
  24. package/dist/plan/plan-apply.js +40 -38
  25. package/dist/plan/platform-diff.d.ts +22 -22
  26. package/dist/plan/platform-diff.js +45 -45
  27. package/dist/plan/platform-org-ports.d.ts +1 -0
  28. package/dist/plan/platform-org-ports.js +3 -0
  29. package/dist/plan/platform-org.d.ts +8 -8
  30. package/dist/plan/platform-org.js +7 -7
  31. package/dist/plan/platform-providers.d.ts +17 -16
  32. package/dist/plan/platform-providers.js +136 -118
  33. package/dist/plan/providers-readers.d.ts +34 -11
  34. package/dist/plan/providers-readers.js +72 -15
  35. package/dist/plan/step-system.js +1 -1
  36. package/dist/plan/{edge-worker.d.ts → worker.d.ts} +53 -33
  37. package/dist/plan/{edge-worker.js → worker.js} +92 -54
  38. package/dist/platform.d.ts +3 -3
  39. package/dist/platform.js +1 -1
  40. package/dist/store/postgres.js +7 -7
  41. package/dist/store/schema.d.ts +6 -6
  42. package/dist/store/schema.js +4 -4
  43. package/package.json +1 -1
  44. package/dist/plan/entry-names-key.d.ts +0 -73
@@ -698,32 +698,32 @@ export const PLATFORM_FILES_MANAGEMENT_UNDELIVERED_SCOPE_KEY = 'files_management
698
698
  export const PLATFORM_FILES_APPLIED_HOSTNAME_SCOPE_KEY = 'files_applied_hostname';
699
699
  export const PLATFORM_FILES_APPLIED_GIT_REF_SCOPE_KEY = 'files_applied_git_ref';
700
700
  /**
701
- * #478: the resource key `planNames` plans under and
701
+ * #478: the resource key `planEdge` plans under and
702
702
  * `FoundryPlatformStepExecutor` dispatches on -- the {@link PLATFORM_FILES_KEY}
703
- * shape for the names host (https://github.com/wtfalch/names). `runPlatformSteps`
704
- * records the app's uuid under `coolify:app:platform:names` once the step
705
- * succeeds, which is what stops `planNames` planning it again.
703
+ * shape for the edge host (https://github.com/wtfalch/edge). `runPlatformSteps`
704
+ * records the app's uuid under `coolify:app:platform:edge` once the step
705
+ * succeeds, which is what stops `planEdge` planning it again.
706
706
  */
707
- export const PLATFORM_NAMES_KEY = 'platform:names';
707
+ export const PLATFORM_EDGE_KEY = 'platform:edge';
708
708
  /**
709
- * #478: the held-key ref the names platform secret's full value is
709
+ * #478: the held-key ref the edge platform secret's full value is
710
710
  * delivered under, once, by {@link FoundryStepExecutorPorts.deliverSecret} --
711
711
  * never the host's app env, which gets only its SHA-256 hash
712
- * (`NAMES_PLATFORM_KEY_HASH`). Archon's own `NamesPort` reads the full
713
- * secret back from this ref to call names' `mintKey`/`revokeKey`/
712
+ * (`EDGE_PLATFORM_KEY_HASH`). Archon's own `EdgePort` reads the full
713
+ * secret back from this ref to call edge' `mintKey`/`revokeKey`/
714
714
  * `setReservedLabels`.
715
715
  */
716
- export const PLATFORM_NAMES_KEY_REF = 'names:platform:key';
716
+ export const PLATFORM_EDGE_KEY_REF = 'edge:platform:key';
717
717
  /**
718
- * #478: the held-key ref for names' own Cloudflare API token (tunnel edit +
718
+ * #478: the held-key ref for edge' own Cloudflare API token (tunnel edit +
719
719
  * DNS edit on one account) -- the issue's own "never Archon's token": this
720
- * is a narrower, names-only credential a human provisions and holds
721
- * separately from whatever broader token `PlatformNamesDeps.cloudflare`
720
+ * is a narrower, edge-only credential a human provisions and holds
721
+ * separately from whatever broader token `PlatformEdgeDeps.cloudflare`
722
722
  * uses to stand the host itself up on Coolify.
723
723
  */
724
- export const PLATFORM_NAMES_CLOUDFLARE_TOKEN_REF = 'cloudflare:names:apiToken';
724
+ export const PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF = 'cloudflare:edge:apiToken';
725
725
  /**
726
- * #478: scope keys (colon-free) for the names platform key, the
726
+ * #478: scope keys (colon-free) for the edge platform key, the
727
727
  * {@link PLATFORM_FILES_MANAGEMENT_UNDELIVERED_SCOPE_KEY} pattern once:
728
728
  * the undelivered id is recorded and persisted the moment the secret is
729
729
  * minted, before delivery; the guard is recorded only once it was delivered
@@ -731,16 +731,16 @@ export const PLATFORM_NAMES_CLOUDFLARE_TOKEN_REF = 'cloudflare:names:apiToken';
731
731
  * means the secret is lost (never kept past that point): the planner
732
732
  * reports it and never mints again. Neither key holds the secret itself.
733
733
  */
734
- export const PLATFORM_NAMES_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY = 'names_platform_key_undelivered';
735
- export const PLATFORM_NAMES_PLATFORM_KEY_SET_SCOPE_KEY = 'names_platform_key_set';
734
+ export const PLATFORM_EDGE_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY = 'edge_platform_key_undelivered';
735
+ export const PLATFORM_EDGE_PLATFORM_KEY_SET_SCOPE_KEY = 'edge_platform_key_set';
736
736
  /**
737
737
  * #478: the hostname and `gitRef` the last successful names run applied.
738
- * `planNames` plans the step again when either differs from the declared
738
+ * `planEdge` plans the step again when either differs from the declared
739
739
  * value; a re-run updates `git_branch` and the runner env and redeploys,
740
740
  * and mints no new platform key (the guards above hold).
741
741
  */
742
- export const PLATFORM_NAMES_APPLIED_HOSTNAME_SCOPE_KEY = 'names_applied_hostname';
743
- export const PLATFORM_NAMES_APPLIED_GIT_REF_SCOPE_KEY = 'names_applied_git_ref';
742
+ export const PLATFORM_EDGE_APPLIED_HOSTNAME_SCOPE_KEY = 'edge_applied_hostname';
743
+ export const PLATFORM_EDGE_APPLIED_GIT_REF_SCOPE_KEY = 'edge_applied_git_ref';
744
744
  /**
745
745
  * #167: the platform's own diff engine, mirroring `diff.ts`'s
746
746
  * `computePlanDetail` for the one shared {@link DeclaredPlatform} record
@@ -755,7 +755,7 @@ export const PLATFORM_NAMES_APPLIED_GIT_REF_SCOPE_KEY = 'names_applied_git_ref';
755
755
  * Scope for #167: the frame plus one step, {@link planApexZone}. #173 adds
756
756
  * {@link planJobs}, #170 adds {@link planSfu}, #168 adds {@link planAuth},
757
757
  * #169 adds {@link planMail}, #174 adds {@link planIntegrations}, #171 adds
758
- * {@link planFiles}, #172 adds {@link planAi}, #478 adds {@link planNames}
758
+ * {@link planFiles}, #172 adds {@link planAi}, #478 adds {@link planEdge}
759
759
  * and #175 adds
760
760
  * {@link planArchon}, the same way #19 shipped org plan/apply against
761
761
  * three singletons before #27, #71, #80 and the rest added the remaining
@@ -805,10 +805,10 @@ export function planPlatform(platform, live, options = {}) {
805
805
  const ai = planAi(platform, recordedIds, blocked.ai);
806
806
  if (ai.step)
807
807
  plannedSteps.push(ai.step);
808
- // #478: independent of auth and files -- the names host needs neither.
809
- const names = planNames(platform, recordedIds, blocked.names);
810
- if (names.step)
811
- plannedSteps.push(names.step);
808
+ // #478: independent of auth and files -- the edge host needs neither.
809
+ const edge = planEdge(platform, recordedIds, blocked.edge);
810
+ if (edge.step)
811
+ plannedSteps.push(edge.step);
812
812
  // #175: last, on purpose. Archon's sign-in client lives in the sign-in
813
813
  // `planAuth` builds, and its env reads what every other service's step
814
814
  // records or delivers, so in one apply it runs after all of them.
@@ -842,9 +842,9 @@ export function planPlatform(platform, live, options = {}) {
842
842
  integrations.blocked
843
843
  ? null
844
844
  : versionChangeLine('integrations', recordedIds[PLATFORM_INTEGRATIONS_APPLIED_GITREF_SCOPE_KEY], platform.integrations.gitRef, 'git ref, redeploy'),
845
- names.blocked
845
+ edge.blocked
846
846
  ? null
847
- : versionChangeLine('names', recordedIds[PLATFORM_NAMES_APPLIED_GIT_REF_SCOPE_KEY], platform.names.gitRef, 'git ref, redeploy'),
847
+ : versionChangeLine('edge', recordedIds[PLATFORM_EDGE_APPLIED_GIT_REF_SCOPE_KEY], platform.edge.gitRef, 'git ref, redeploy'),
848
848
  auth.blocked
849
849
  ? null
850
850
  : versionNotAppliedLine('zitadel', Boolean(recordedIds[resourceKey('coolify', 'app', PLATFORM_AUTH_KEY)]), recordedIds[PLATFORM_AUTH_ZITADEL_APPLIED_IMAGE_TAG_SCOPE_KEY], VERSIONS.zitadel),
@@ -876,8 +876,8 @@ export function planPlatform(platform, live, options = {}) {
876
876
  unmanaged.push({ description: files.blocked, key: 'files' });
877
877
  if (ai.blocked)
878
878
  unmanaged.push({ description: ai.blocked, key: 'ai' });
879
- if (names.blocked)
880
- unmanaged.push({ description: names.blocked, key: 'names' });
879
+ if (edge.blocked)
880
+ unmanaged.push({ description: edge.blocked, key: 'edge' });
881
881
  if (archon.blocked)
882
882
  unmanaged.push({ description: archon.blocked, key: 'archon' });
883
883
  // #398: the old integrations key stays pinned until Archon holds the new
@@ -1747,13 +1747,13 @@ function planFiles(platform, recordedIds, executorBlocked, authReady, drifted) {
1747
1747
  };
1748
1748
  }
1749
1749
  /**
1750
- * #478: the names host (https://github.com/wtfalch/names) -- its database
1750
+ * #478: the edge host (https://github.com/wtfalch/edge) -- its database
1751
1751
  * (owner and runtime roles), its one Coolify app (no separate migrate app:
1752
1752
  * the Dockerfile migrates inside the runner's own entrypoint, see
1753
- * `provisionPlatformNames`'s own doc comment), foundry's own platform key
1753
+ * `provisionPlatformEdge`'s own doc comment), foundry's own platform key
1754
1754
  * (minted once, its hash alone written to the runner) and a Cloudflare
1755
- * tunnel + DNS record at `platform.names.hostname`. One `coolify:app` step
1756
- * keyed {@link PLATFORM_NAMES_KEY}, the {@link planFiles} bundling shape,
1755
+ * tunnel + DNS record at `platform.edge.hostname`. One `coolify:app` step
1756
+ * keyed {@link PLATFORM_EDGE_KEY}, the {@link planFiles} bundling shape,
1757
1757
  * public like {@link planMail}/{@link planAuth} rather than internal-only
1758
1758
  * like {@link planFiles}/{@link planAi}.
1759
1759
  *
@@ -1764,23 +1764,23 @@ function planFiles(platform, recordedIds, executorBlocked, authReady, drifted) {
1764
1764
  *
1765
1765
  * Blocked, not planned: a platform key minted but never delivered (lost,
1766
1766
  * `ServiceError`-free the way {@link planFiles}'s own management-key check
1767
- * is), or `executorBlocked` -- the host built no names dependencies, or
1767
+ * is), or `executorBlocked` -- the host built no edge dependencies, or
1768
1768
  * (CLAUDE.md's "Human steps") no Cloudflare API token is held yet under
1769
- * {@link PLATFORM_NAMES_CLOUDFLARE_TOKEN_REF}.
1769
+ * {@link PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF}.
1770
1770
  */
1771
- function planNames(platform, recordedIds, executorBlocked) {
1772
- if (!platform.names.enabled)
1771
+ function planEdge(platform, recordedIds, executorBlocked) {
1772
+ if (!platform.edge.enabled)
1773
1773
  return { step: null, blocked: null };
1774
- const undelivered = recordedIds[PLATFORM_NAMES_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY];
1775
- if (undelivered && !recordedIds[PLATFORM_NAMES_PLATFORM_KEY_SET_SCOPE_KEY]) {
1774
+ const undelivered = recordedIds[PLATFORM_EDGE_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY];
1775
+ if (undelivered && !recordedIds[PLATFORM_EDGE_PLATFORM_KEY_SET_SCOPE_KEY]) {
1776
1776
  return {
1777
1777
  step: null,
1778
- blocked: `the names host is blocked, not planned: its platform key (${undelivered}) was minted but never delivered and cannot be shown again; remove the recorded key ${PLATFORM_NAMES_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY} to mint a new one`,
1778
+ blocked: `the edge host is blocked, not planned: its platform key (${undelivered}) was minted but never delivered and cannot be shown again; remove the recorded key ${PLATFORM_EDGE_PLATFORM_KEY_UNDELIVERED_SCOPE_KEY} to mint a new one`,
1779
1779
  };
1780
1780
  }
1781
- const applied = Boolean(recordedIds[resourceKey('coolify', 'app', PLATFORM_NAMES_KEY)]) &&
1782
- recordedIds[PLATFORM_NAMES_APPLIED_HOSTNAME_SCOPE_KEY] === platform.names.hostname &&
1783
- recordedIds[PLATFORM_NAMES_APPLIED_GIT_REF_SCOPE_KEY] === platform.names.gitRef;
1781
+ const applied = Boolean(recordedIds[resourceKey('coolify', 'app', PLATFORM_EDGE_KEY)]) &&
1782
+ recordedIds[PLATFORM_EDGE_APPLIED_HOSTNAME_SCOPE_KEY] === platform.edge.hostname &&
1783
+ recordedIds[PLATFORM_EDGE_APPLIED_GIT_REF_SCOPE_KEY] === platform.edge.gitRef;
1784
1784
  if (applied)
1785
1785
  return { step: null, blocked: null };
1786
1786
  if (executorBlocked)
@@ -1790,11 +1790,11 @@ function planNames(platform, recordedIds, executorBlocked) {
1790
1790
  action: {
1791
1791
  system: 'coolify',
1792
1792
  kind: 'app',
1793
- key: PLATFORM_NAMES_KEY,
1794
- desired: { hostname: platform.names.hostname, gitRef: platform.names.gitRef },
1793
+ key: PLATFORM_EDGE_KEY,
1794
+ desired: { hostname: platform.edge.hostname, gitRef: platform.edge.gitRef },
1795
1795
  },
1796
1796
  step: {
1797
- description: `provision the names host at ${platform.names.hostname}, with its own database and foundry's platform key`,
1797
+ description: `provision the edge host at ${platform.edge.hostname}, with its own database and foundry's platform key`,
1798
1798
  destroys: false,
1799
1799
  migrates: false,
1800
1800
  },
@@ -45,6 +45,7 @@ export declare class PlatformOrgPorts {
45
45
  files(): Promise<FilesOrganisationPort>;
46
46
  ai(): Promise<AiOrganisationPort>;
47
47
  jobs(): Promise<JobsSchedulerPort>;
48
+ authHostname(): Promise<string | null>;
48
49
  private recorded;
49
50
  private held;
50
51
  }
@@ -47,6 +47,9 @@ export class PlatformOrgPorts {
47
47
  const token = await this.held('jobs', JOBS_ADMIN_TOKEN_REF);
48
48
  return new HttpJobsSchedulerClient(`https://${platform.jobs.hostname}`, token, this.options.fetch);
49
49
  }
50
+ async authHostname() {
51
+ return (await this.options.store.get())?.auth.hostname ?? null;
52
+ }
50
53
  async recorded(service, scopeKey) {
51
54
  const value = (await this.options.store.getServiceIds())[scopeKey];
52
55
  if (!value) {
@@ -88,16 +88,16 @@ export interface OrgPlatformReadiness {
88
88
  /** The jobs scheduler (#173) is enabled, applied, and its admin token is held. */
89
89
  jobsReady: boolean;
90
90
  /**
91
- * #317 (F7) and #478: the names service is declared `enabled`, its own
92
- * `coolify:app` deploy step has applied (`provisionPlatformNames`), and
93
- * the host's executor was built with a `NamesPort` -- the same
91
+ * #317 (F7) and #478: the edge service is declared `enabled`, its own
92
+ * `coolify:app` deploy step has applied (`provisionPlatformEdge`), and
93
+ * the host's executor was built with an `EdgePort` -- the same
94
94
  * `filesReady`/`aiReady` "declared and applied" shape now that #478 built
95
95
  * the deploy step #317 shipped ahead of (this field's own doc comment
96
96
  * used to say there was none; N1 is no longer deployed by hand).
97
97
  */
98
- namesReady: boolean;
99
- /** `https://<platform.names.hostname>`, which an entry with `uses.names` gets as `NAMES_URL`. `null` until `namesReady`. */
100
- namesUrl?: string | null;
98
+ edgeReady: boolean;
99
+ /** `https://<platform.edge.hostname>`, which an entry with `uses.edge` gets as `EDGE_URL`. `null` until `edgeReady`. */
100
+ edgeUrl?: string | null;
101
101
  /**
102
102
  * The ref of a platform key an applied service needs that is not held yet,
103
103
  * `null` when it is held or when the service is not applied. A ref only,
@@ -166,8 +166,8 @@ export declare function orgPlatformReadinessFrom(platform: DeclaredPlatform, pla
166
166
  heldRefs?: ReadonlySet<string>,
167
167
  /** True when the host wired no held-keys reader ({@link OrgPlatformReadiness.noKeyReader}). */
168
168
  noKeyReader?: boolean,
169
- /** #317: true when the host's executor was built with a `NamesPort` ({@link OrgPlatformReadiness.namesReady}). */
170
- namesPortPresent?: boolean): OrgPlatformReadiness;
169
+ /** #317: true when the host's executor was built with an `EdgePort` ({@link OrgPlatformReadiness.edgeReady}). */
170
+ edgePortPresent?: boolean): OrgPlatformReadiness;
171
171
  /**
172
172
  * #177: {@link AgoraHostValues} derived from the same platform state, rather
173
173
  * than requiring a bespoke host-supplied `AgoraHostPort` for values the
@@ -1,4 +1,4 @@
1
- import { JOBS_SCHEDULER_KEY, PLATFORM_AI_INTERNAL_URL_SCOPE_KEY, PLATFORM_AI_KEY, PLATFORM_AUTH_KEY, PLATFORM_FILES_INTERNAL_URL_SCOPE_KEY, PLATFORM_FILES_KEY, PLATFORM_MAIL_INTERNAL_URL_SCOPE_KEY, PLATFORM_MAIL_KEY, PLATFORM_MAIL_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_NAMES_KEY, platformMailMxHost, } from './platform-diff.js';
1
+ import { JOBS_SCHEDULER_KEY, PLATFORM_AI_INTERNAL_URL_SCOPE_KEY, PLATFORM_AI_KEY, PLATFORM_AUTH_KEY, PLATFORM_EDGE_KEY, PLATFORM_FILES_INTERNAL_URL_SCOPE_KEY, PLATFORM_FILES_KEY, PLATFORM_MAIL_INTERNAL_URL_SCOPE_KEY, PLATFORM_MAIL_KEY, PLATFORM_MAIL_ZITADEL_PROJECT_SCOPE_KEY, platformMailMxHost, } from './platform-diff.js';
2
2
  import { FILES_MANAGEMENT_KEY_REF, JOBS_ADMIN_TOKEN_REF, PLATFORM_AI_MANAGEMENT_KEY_REF, } from './platform-providers.js';
3
3
  /**
4
4
  * #443: the no-domain company mail apex -- `<slug>.oikos.host`, the same
@@ -32,7 +32,7 @@ export const DEFAULT_ORG_PLATFORM_READINESS = {
32
32
  callsReady: false,
33
33
  authReady: false,
34
34
  jobsReady: false,
35
- namesReady: false,
35
+ edgeReady: false,
36
36
  missingKeys: { files: null, ai: null, jobs: null },
37
37
  };
38
38
  /** The held-key refs an org step needs from the platform, one per service. */
@@ -80,13 +80,13 @@ export function orgPlatformReadinessFrom(platform, platformRecordedIds,
80
80
  heldRefs,
81
81
  /** True when the host wired no held-keys reader ({@link OrgPlatformReadiness.noKeyReader}). */
82
82
  noKeyReader = false,
83
- /** #317: true when the host's executor was built with a `NamesPort` ({@link OrgPlatformReadiness.namesReady}). */
84
- namesPortPresent = false) {
83
+ /** #317: true when the host's executor was built with an `EdgePort` ({@link OrgPlatformReadiness.edgeReady}). */
84
+ edgePortPresent = false) {
85
85
  const mailApplied = platform.mail.enabled && coolifyAppApplied(platformRecordedIds, PLATFORM_MAIL_KEY);
86
86
  const filesApplied = platform.files.enabled && coolifyAppApplied(platformRecordedIds, PLATFORM_FILES_KEY);
87
87
  const aiApplied = platform.ai.enabled && coolifyAppApplied(platformRecordedIds, PLATFORM_AI_KEY);
88
88
  const jobsApplied = platform.jobs.enabled && Boolean(platformRecordedIds[`coolify:jobs:${JOBS_SCHEDULER_KEY}`]);
89
- const namesApplied = platform.names.enabled && coolifyAppApplied(platformRecordedIds, PLATFORM_NAMES_KEY);
89
+ const edgeApplied = platform.edge.enabled && coolifyAppApplied(platformRecordedIds, PLATFORM_EDGE_KEY);
90
90
  const missing = (applied, ref) => applied && heldRefs !== undefined && !heldRefs.has(ref) ? ref : null;
91
91
  const missingKeys = {
92
92
  files: missing(filesApplied, ORG_PLATFORM_KEY_REFS.files),
@@ -113,8 +113,8 @@ namesPortPresent = false) {
113
113
  callsReady: platform.sfu.enabled,
114
114
  authReady: platform.auth.enabled && coolifyAppApplied(platformRecordedIds, PLATFORM_AUTH_KEY),
115
115
  jobsReady: jobsApplied && missingKeys.jobs === null,
116
- namesReady: namesApplied && namesPortPresent,
117
- namesUrl: namesApplied && namesPortPresent ? `https://${platform.names.hostname}` : null,
116
+ edgeReady: edgeApplied && edgePortPresent,
117
+ edgeUrl: edgeApplied && edgePortPresent ? `https://${platform.edge.hostname}` : null,
118
118
  missingKeys,
119
119
  ...(noKeyReader ? { noKeyReader } : {}),
120
120
  };
@@ -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
  */
@@ -640,8 +640,9 @@ export declare const PLATFORM_AI_MANAGEMENT_KEY_REF = "ai:platform:managementKey
640
640
  * What Archon's management key may do in ai: exactly `ai`'s own
641
641
  * `ARCHON_AI_PERMISSIONS` (`apps/host/scripts/authz/bootstrap-archon.ts`) --
642
642
  * configuration only (offerings, provisioning, offers, budgets, usage, cost)
643
- * plus deleting (archiving) an organisation, never connections, runs or
644
- * webhooks. ai's `/v1/platform/keys` route refuses any permission outside
643
+ * plus deleting (archiving) an organisation and setting another
644
+ * organisation's webhook address and budget, never connections, runs or
645
+ * webhook deliveries. ai's `/v1/platform/keys` route refuses any permission outside
645
646
  * this same list, so a request for more than this is a 403, not a wider key.
646
647
  */
647
648
  export declare const PLATFORM_AI_MANAGEMENT_PERMISSIONS: readonly string[];
@@ -822,7 +823,7 @@ export declare const FILES_MANAGEMENT_KEY_ID = "foundry-1";
822
823
  export declare const FILES_MANAGEMENT_KEY_REF = "files:platform:managementKey";
823
824
  /** The ref the files host's introspection client secret is delivered under. */
824
825
  export declare const FILES_INTROSPECTION_SECRET_REF = "zitadel:platform:files:introspection";
825
- export interface PlatformNamesRuntime {
826
+ export interface PlatformEdgeRuntime {
826
827
  fetch?: typeof fetch;
827
828
  sleep?: (ms: number) => Promise<void>;
828
829
  now?: () => number;
@@ -831,17 +832,17 @@ export interface PlatformNamesRuntime {
831
832
  readyTimeoutMs?: number;
832
833
  readyIntervalMs?: number;
833
834
  }
834
- export interface PlatformNamesDeps {
835
+ export interface PlatformEdgeDeps {
835
836
  coolify: Pick<CoolifyPort, 'findProjectByName' | 'createProject' | 'findOrCreateEnvironment' | 'listServers' | 'findApplicationByName' | 'getApplication' | 'requireGithubApp' | 'createGithubAppApplication' | 'createDockerfileApplication' | 'listDatabases' | 'createPostgresDatabase' | 'getDatabase' | 'bulkUpsertEnvs' | 'listEnvs' | 'updateApplication' | 'deploy' | 'deployAndWait' | 'raw'>;
836
837
  cloudflare: Pick<CloudflarePort, 'findZoneByApex' | 'findTunnelByName' | 'createTunnel' | 'putTunnelConfig' | 'getTunnelToken' | 'findDnsRecord' | 'createDnsRecord' | 'updateDnsRecord'>;
837
838
  deliverSecret: FoundryStepExecutorPorts['deliverSecret'];
838
839
  /**
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
840
+ * Reads the edge service's own Cloudflare API token back, held under
841
+ * {@link PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF} -- a human step (the issue's
841
842
  * own "Human steps"), never minted here: foundry has no Cloudflare
842
843
  * account of its own to carve that token out of. Absent, or with nothing
843
844
  * held under that ref yet, is reported blocked by `blockedSteps`
844
- * ({@link namesBlockedReason}), never planned to throw.
845
+ * ({@link edgeBlockedReason}), never planned to throw.
845
846
  */
846
847
  heldKeys?: {
847
848
  resolve(ref: string): Promise<string | null>;
@@ -853,7 +854,7 @@ export interface PlatformNamesDeps {
853
854
  */
854
855
  cloudflareAccountId?: string;
855
856
  /** Clock, sleep and fetch for the readiness wait and delivery retries; real ones by default. */
856
- runtime?: PlatformNamesRuntime;
857
+ runtime?: PlatformEdgeRuntime;
857
858
  }
858
859
  /**
859
860
  * #174: everything {@link provisionPlatformIntegrations} needs beyond