@wtfalch/foundry 0.62.0 → 0.64.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 (91) hide show
  1. package/dist/apps/index.d.ts +1 -0
  2. package/dist/apps/index.js +1 -0
  3. package/dist/apps/server-entry.d.ts +43 -0
  4. package/dist/apps/server-entry.js +99 -0
  5. package/dist/bootstrap/declare.js +4 -1
  6. package/dist/bootstrap/versions.d.ts +2 -0
  7. package/dist/build-json.d.ts +25 -0
  8. package/dist/build-json.js +61 -0
  9. package/dist/catalogue/copy-en.js +10 -0
  10. package/dist/catalogue/integrations.js +10 -0
  11. package/dist/index.d.ts +8 -4
  12. package/dist/index.js +3 -2
  13. package/dist/migrations/0067_requested_changes_kosmos.sql +6 -0
  14. package/dist/migrations/0068_platform_registry.sql +17 -0
  15. package/dist/modules/customer-grants.d.ts +3 -0
  16. package/dist/modules/customer-grants.js +28 -0
  17. package/dist/modules/index.js +49 -1
  18. package/dist/modules/repository.d.ts +6 -0
  19. package/dist/modules/repository.js +40 -0
  20. package/dist/modules/types.d.ts +8 -0
  21. package/dist/native-build.d.ts +7 -27
  22. package/dist/native-build.js +7 -27
  23. package/dist/org.d.ts +19 -1
  24. package/dist/org.js +45 -3
  25. package/dist/plan/archon-blue-green.d.ts +5 -0
  26. package/dist/plan/archon-blue-green.js +2 -0
  27. package/dist/plan/blue-green-apply.d.ts +5 -0
  28. package/dist/plan/blue-green-apply.js +197 -22
  29. package/dist/plan/blue-green.d.ts +61 -2
  30. package/dist/plan/blue-green.js +80 -6
  31. package/dist/plan/boule.d.ts +1 -1
  32. package/dist/plan/boule.js +2 -0
  33. package/dist/plan/broker-entries.d.ts +9 -0
  34. package/dist/plan/broker-entries.js +29 -0
  35. package/dist/plan/diff.d.ts +5 -0
  36. package/dist/plan/diff.js +21 -2
  37. package/dist/plan/edge-access.d.ts +2 -3
  38. package/dist/plan/edge-access.js +7 -0
  39. package/dist/plan/executor.d.ts +71 -1
  40. package/dist/plan/executor.js +491 -56
  41. package/dist/plan/index.d.ts +2 -0
  42. package/dist/plan/index.js +1 -0
  43. package/dist/plan/jobs-scheduler-http.d.ts +2 -0
  44. package/dist/plan/jobs-scheduler-http.js +11 -0
  45. package/dist/plan/own-limits.d.ts +6 -0
  46. package/dist/plan/own-limits.js +1 -0
  47. package/dist/plan/plan-apply.d.ts +51 -1
  48. package/dist/plan/plan-apply.js +298 -25
  49. package/dist/plan/platform-diff.d.ts +23 -1
  50. package/dist/plan/platform-diff.js +96 -0
  51. package/dist/plan/platform-org.d.ts +2 -0
  52. package/dist/plan/platform-providers.d.ts +46 -1
  53. package/dist/plan/platform-providers.js +156 -1
  54. package/dist/plan/platform-registry-keys.d.ts +58 -0
  55. package/dist/plan/platform-registry-keys.js +69 -0
  56. package/dist/plan/platform-registry.d.ts +67 -0
  57. package/dist/plan/platform-registry.js +298 -0
  58. package/dist/plan/release-host.d.ts +31 -2
  59. package/dist/plan/release-host.js +114 -6
  60. package/dist/plan/stage-copy-host.d.ts +104 -0
  61. package/dist/plan/stage-copy-host.js +259 -0
  62. package/dist/plan/stage-copy.js +44 -0
  63. package/dist/plan/stage-env.d.ts +9 -0
  64. package/dist/plan/stage-env.js +38 -0
  65. package/dist/plan/stage-guards.d.ts +57 -1
  66. package/dist/plan/stage-guards.js +106 -0
  67. package/dist/plan/stage-isolation.js +56 -0
  68. package/dist/plan/stage-services.d.ts +93 -0
  69. package/dist/plan/stage-services.js +153 -0
  70. package/dist/plan/stage-signin.d.ts +152 -0
  71. package/dist/plan/stage-signin.js +133 -0
  72. package/dist/plan/stage-sink.d.ts +2 -0
  73. package/dist/plan/stage-sink.js +6 -1
  74. package/dist/platform.d.ts +7 -1
  75. package/dist/platform.js +1 -0
  76. package/dist/release/decide.d.ts +12 -0
  77. package/dist/release/decide.js +37 -2
  78. package/dist/release/run.d.ts +71 -1
  79. package/dist/release/run.js +92 -8
  80. package/dist/release/state.d.ts +14 -1
  81. package/dist/release/state.js +43 -0
  82. package/dist/release/types.d.ts +20 -0
  83. package/dist/release/types.js +2 -0
  84. package/dist/requested-changes.d.ts +11 -2
  85. package/dist/requested-changes.js +11 -0
  86. package/dist/store/postgres.js +8 -0
  87. package/dist/store/schema.d.ts +51 -0
  88. package/dist/store/schema.js +4 -0
  89. package/package.json +3 -2
  90. package/versions.digests.json +1 -0
  91. package/versions.json +1 -0
@@ -49,6 +49,8 @@ export { StageRestoreError, StageRestoreRefusedError, createStageCopyPort, execR
49
49
  export type { Runner, StageCopyPortDeps } from './stage-copy-port.js';
50
50
  export type { CallsSfuConnection, CallsSfuConnectionPort, CallsSfuKeysPort, CallsSfuSshConnector, CallsSfuPlatformDeps, } from './platform-sfu.js';
51
51
  export { MissingCallsSfuConnectionError, applyCallsSfuPlatformStep, callsSfuAppliedFingerprint, } from './platform-sfu.js';
52
+ export type { PlatformRegistryDeps, PlatformRegistryRuntime } from './platform-registry.js';
53
+ export { PLATFORM_REGISTRY_PULL_PASSWORD_REF, PLATFORM_REGISTRY_PUSH_PASSWORD_REF, PLATFORM_REGISTRY_PUSH_USER, platformRegistryPushCredential, } from './platform-registry-keys.js';
52
54
  export type { MailCopyJob, MailCopyPort, MailCopyStepResult } from './mail-copy.js';
53
55
  export { MAIL_COPY_COMPLETED_SCOPE_KEY, MAIL_COPY_DONE_SCOPE_KEY, MissingMailCopyAccountsError, MissingMailCopySourceTokenError, MissingMailCopyStalwartTokenError, parseMailCopyCompleted, runMailCopyStep, } from './mail-copy.js';
54
56
  export type { ScopeResolver, RecordedIds, DnsRecordOwners } from './providers-readers.js';
@@ -30,6 +30,7 @@ export { STAGE_SINK_APPLIED_SCOPE_KEY, STAGE_SINK_IMAGE_REF, STAGE_SINK_SMTP_POR
30
30
  export { STAGE_COPY_EXCLUDED_TABLES, StageCopyFailedError, StageCopyRefusedError, stageCopy, tableExcluded, undoStageCopy, } from './stage-copy.js';
31
31
  export { StageRestoreError, StageRestoreRefusedError, createStageCopyPort, execRunner, } from './stage-copy-port.js';
32
32
  export { MissingCallsSfuConnectionError, applyCallsSfuPlatformStep, callsSfuAppliedFingerprint, } from './platform-sfu.js';
33
+ export { PLATFORM_REGISTRY_PULL_PASSWORD_REF, PLATFORM_REGISTRY_PUSH_PASSWORD_REF, PLATFORM_REGISTRY_PUSH_USER, platformRegistryPushCredential, } from './platform-registry-keys.js';
33
34
  export { MAIL_COPY_COMPLETED_SCOPE_KEY, MAIL_COPY_DONE_SCOPE_KEY, MissingMailCopyAccountsError, MissingMailCopySourceTokenError, MissingMailCopyStalwartTokenError, parseMailCopyCompleted, runMailCopyStep, } from './mail-copy.js';
34
35
  export { ProvidersAiReader, ProvidersCloudflareReader, ProvidersCmsReader, ProvidersCoolifyReader, ProvidersZitadelReader, storeLoginHostResolver, storeScopeResolver, storeRecordedIds, } from './providers-readers.js';
35
36
  export { PlatformBrokerPort } from './broker-entries.js';
@@ -26,4 +26,6 @@ export declare class HttpJobsSchedulerClient implements JobsSchedulerPort {
26
26
  secret?: string;
27
27
  syncKey?: string;
28
28
  }>;
29
+ /** `DELETE /admin/projects/<name>`. A refusal throws with the status only. */
30
+ deleteProject(name: string): Promise<void>;
29
31
  }
@@ -50,4 +50,15 @@ export class HttpJobsSchedulerClient {
50
50
  syncKey: typeof fields.syncKey === 'string' ? fields.syncKey : undefined,
51
51
  };
52
52
  }
53
+ /** `DELETE /admin/projects/<name>`. A refusal throws with the status only. */
54
+ async deleteProject(name) {
55
+ const response = await this.fetchImpl(`${this.baseUrl}/admin/projects/${encodeURIComponent(name)}`, {
56
+ method: 'DELETE',
57
+ headers: { authorization: `Bearer ${this.adminToken}` },
58
+ signal: AbortSignal.timeout(ADMIN_CALL_TIMEOUT_MS),
59
+ });
60
+ if (response.status === 200 || response.status === 204)
61
+ return;
62
+ throw Object.assign(new Error(`jobs scheduler: DELETE /admin/projects/<name> answered ${response.status}`), { status: response.status });
63
+ }
53
64
  }
@@ -173,6 +173,12 @@ export declare const LIMITS: {
173
173
  autoDeploy: false | "declared";
174
174
  capabilities: CapabilityTier;
175
175
  };
176
+ readonly platformRegistry: {
177
+ memory: string;
178
+ dbMemory: string;
179
+ autoDeploy: false | "declared";
180
+ capabilities: CapabilityTier;
181
+ };
176
182
  readonly platformMail: {
177
183
  memory: string;
178
184
  dbMemory: string;
@@ -40,6 +40,7 @@ export const LIMITS = {
40
40
  platformFiles: profile('1g'),
41
41
  platformEdge: profile('512m'),
42
42
  platformHc: profile('512m'),
43
+ platformRegistry: profile('256m'),
43
44
  platformMail: profile('1g'),
44
45
  platformAuth: profile('1g'),
45
46
  platformJobs: profile('1g'),
@@ -4,7 +4,7 @@ import { type AuditSealingOptions } from '../audit/tick.js';
4
4
  import type { DeclaredOrg, HostingEntry, OrgId } from '../org.js';
5
5
  import type { Plan, PlanStep } from '../plan.js';
6
6
  import type { DeclaredPlatform } from '../platform.js';
7
- import type { ReleaseStore } from '../release/state.js';
7
+ import { type ReleaseStore } from '../release/state.js';
8
8
  import type { JobRunner } from '../runner/types.js';
9
9
  import type { AppliedState } from '../state.js';
10
10
  import { type AppliedVersionsStore, type DeclaredOrgStore, type PlatformStore } from '../store.js';
@@ -224,11 +224,21 @@ export interface StepExecutor {
224
224
  }>>;
225
225
  /** Whether the company's stage mail sink app (by Coolify id) is stopped or gone, read live. Optional: an executor without it reads the sink as up. */
226
226
  stageSinkDown?(appId: string): Promise<boolean>;
227
+ /** Which stage-guard ports the host has; they decide the guard names in the applied structure hash. Optional: neither. */
228
+ stageGuardPorts?(): {
229
+ probes: boolean;
230
+ access: boolean;
231
+ };
227
232
  /**
228
233
  * The release runner's outside calls for one blue/green entry (`plan/release-host.ts`); `null` while its blue
229
234
  * copy is not recorded. Optional: an executor without it runs no release.
230
235
  */
231
236
  releaseHost?(org: DeclaredOrg, subject: BlueGreenSubject, context: ReleaseContext, renew: () => Promise<void>): ReleaseHost | null;
237
+ /**
238
+ * One release tick for one subject: the recorded stage gate's list follows the people holding `releases:preview`,
239
+ * owners staying. Never throws. Optional: an executor without it leaves every gate as it is.
240
+ */
241
+ syncStageGateMembers?(org: DeclaredOrg, subject: BlueGreenSubject, context: ReleaseContext): Promise<void>;
232
242
  /** Whether the executor's held keys can store a Worker app database's CA and certificate. Absent: true. */
233
243
  workerAppDbKeysPuttable?(): boolean;
234
244
  /** Whether the host supplies the backup bucket a Worker app database dumps into. Absent: true. */
@@ -305,6 +315,8 @@ export interface PlatformDriftedSteps {
305
315
  authApps?: boolean;
306
316
  /** The host sets it. */
307
317
  edge?: boolean;
318
+ /** A usable, reachable Coolify server has no registry login for the current host and passwords. */
319
+ registryLogins?: boolean;
308
320
  /** #380 */
309
321
  files?: boolean;
310
322
  backupStorage?: boolean;
@@ -340,6 +352,8 @@ export interface PlatformStepExecutor {
340
352
  backupExecutorMissing?: boolean;
341
353
  /** #540: see `PlanPlatformOptions.blocked.hc` (`platform-diff.ts`). */
342
354
  hc?: string;
355
+ /** See `PlanPlatformOptions.blocked.registry` (`platform-diff.ts`). */
356
+ registry?: string;
343
357
  /** #540: see `PlanPlatformOptions.blocked.heartbeatsExecutorMissing` (`platform-diff.ts`). */
344
358
  heartbeatsExecutorMissing?: boolean;
345
359
  /** foundry#542: see `PlanPlatformOptions.blocked.uptime` (`platform-diff.ts`). */
@@ -373,8 +387,12 @@ export interface PlatformStepExecutor {
373
387
  servers?: BlueGreenServer[];
374
388
  blocked?: string;
375
389
  }>;
390
+ /** The stage guards platform-archon can make now, by name; they go into its applied structure hash. */
391
+ archonStageGuardNames?(platform: DeclaredPlatform, recorded: Readonly<Record<string, string>>, owner: PlatformOwnerInput): string[];
376
392
  /** The release runner's outside calls for platform-archon (`plan/release-host.ts`); `null` while its app is not recorded. */
377
393
  releaseHost?(platform: DeclaredPlatform, subject: BlueGreenSubject, context: ReleaseContext, renew: () => Promise<void>): ReleaseHost | null;
394
+ /** As {@link FoundryStepExecutor.syncStageGateMembers}, for platform-archon's own stage gate (orgId `platform`). */
395
+ syncStageGateMembers?(platform: DeclaredPlatform, subject: BlueGreenSubject, context: ReleaseContext): Promise<void>;
378
396
  execute(action: StepAction, context: PlatformStepExecutionContext): Promise<{
379
397
  resourceId?: string;
380
398
  } | undefined>;
@@ -633,6 +651,14 @@ export interface FoundryPlanApplyOptions {
633
651
  now?: () => Date;
634
652
  /** #441: how long a mutation lease lasts before another caller may take it over. Defaults to 30 minutes. */
635
653
  leaseTtlMs?: number;
654
+ /**
655
+ * A stage copy runs without the org's lease and takes it for a moment each time it records something. When an
656
+ * apply or a tick holds the lease it waits `waitMs` and tries again, up to `tries` times. Defaults to 30 s and 10.
657
+ */
658
+ copyLeaseRetry?: {
659
+ tries: number;
660
+ waitMs: number;
661
+ };
636
662
  /**
637
663
  * #441 (part b): a durable, DB-row-backed record of `apply`, `destroy`,
638
664
  * `adopt` and `release` for one org, held under the same mutation lease
@@ -730,6 +756,7 @@ export declare class FoundryPlanApply implements PlanApply {
730
756
  private readonly onlySteps;
731
757
  private readonly now;
732
758
  private readonly leaseTtlMs;
759
+ private readonly copyLeaseRetry;
733
760
  private readonly appliedVersions;
734
761
  private readonly backupGate;
735
762
  private readonly platformDeps;
@@ -900,6 +927,25 @@ export declare class FoundryPlanApply implements PlanApply {
900
927
  target: string;
901
928
  error?: string;
902
929
  }>>;
930
+ /**
931
+ * Phase 2 for one org: takes the copy lock of each stage copy request under the org's lease, then runs the
932
+ * copies after the lease is released. While a copy runs, every other tick and apply for the org goes on, a
933
+ * hard-fail rollback included; the copy records through short leases ({@link copyContext}).
934
+ */
935
+ private runOrgStageCopies;
936
+ /** Phase 2 for platform-archon; see {@link runOrgStageCopies}. */
937
+ private runPlatformStageCopies;
938
+ /**
939
+ * Runs one claimed copy with no lease held, then records its outcome and consumes the request. A lost lock
940
+ * throws (`StaleLeaseError`) and leaves the request open.
941
+ */
942
+ private runClaimedCopy;
943
+ /**
944
+ * The recorded ids a copy reads and writes, without the org's lease. It reads a snapshot taken when the lock was
945
+ * claimed; each `persist` takes the lease for a moment, re-reads the stored ids and writes only the keys the
946
+ * copy changed, so a tick that ran in between loses nothing. The lease may be busy: it waits and tries again.
947
+ */
948
+ private copyContext;
903
949
  /**
904
950
  * The recurring audit sealing run (foundry#929): seals every ledger registered by an `audit:ledger` step with the
905
951
  * platform signer and has the timestamp authority stamp the new checkpoints. Foundry has no scheduler, so the host
@@ -907,6 +953,10 @@ export declare class FoundryPlanApply implements PlanApply {
907
953
  * log line say what happened and why when nothing did. It writes nothing to the org's records.
908
954
  */
909
955
  runAuditSealTick(): Promise<SealResult[]>;
956
+ /**
957
+ * One org's release run. `defer`: stage copy requests stay open and `deferred` says whether there were any.
958
+ * `claim`: the copies this run decided on, each with its lock taken, for {@link runClaimedCopy}.
959
+ */
910
960
  private runOrgReleaseTick;
911
961
  /** An own org with calls on: the host's answer about its slot's ports. A failure or a slow answer is "not open". */
912
962
  private readSfuPortsOpen;