@wtfalch/foundry 0.42.1 → 0.44.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.
- package/dist/bootstrap/versions.d.ts +2 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.js +4 -2
- package/dist/migrations/0055_release_requests.sql +20 -0
- package/dist/migrations/0056_platform_archon_blue_green.sql +7 -0
- package/dist/migrations/0057_org_customers.sql +29 -0
- package/dist/org.d.ts +55 -0
- package/dist/org.js +90 -27
- package/dist/plan/archon-blue-green.d.ts +54 -0
- package/dist/plan/archon-blue-green.js +72 -0
- package/dist/plan/blue-green-apply.d.ts +82 -0
- package/dist/plan/blue-green-apply.js +360 -0
- package/dist/plan/blue-green.d.ts +223 -0
- package/dist/plan/blue-green.js +444 -0
- package/dist/plan/boule.d.ts +43 -2
- package/dist/plan/boule.js +48 -1
- package/dist/plan/broker-entries.d.ts +28 -0
- package/dist/plan/broker-entries.js +46 -1
- package/dist/plan/cloudflared-connector.d.ts +26 -0
- package/dist/plan/cloudflared-connector.js +37 -0
- package/dist/plan/diff.d.ts +20 -0
- package/dist/plan/diff.js +207 -20
- package/dist/plan/executor.d.ts +134 -2
- package/dist/plan/executor.js +517 -25
- package/dist/plan/hostnames.d.ts +7 -0
- package/dist/plan/hostnames.js +17 -2
- package/dist/plan/locked-hostnames.d.ts +11 -0
- package/dist/plan/locked-hostnames.js +13 -0
- package/dist/plan/mcp.d.ts +57 -0
- package/dist/plan/mcp.js +131 -0
- package/dist/plan/org-names.d.ts +2 -2
- package/dist/plan/org-names.js +16 -1
- package/dist/plan/plan-apply.d.ts +77 -0
- package/dist/plan/plan-apply.js +267 -5
- package/dist/plan/platform-diff.d.ts +9 -0
- package/dist/plan/platform-diff.js +24 -1
- package/dist/plan/platform-providers.d.ts +15 -1
- package/dist/plan/platform-providers.js +90 -5
- package/dist/plan/proxy-labels.d.ts +2 -2
- package/dist/plan/proxy-labels.js +14 -4
- package/dist/plan/release-host.d.ts +59 -0
- package/dist/plan/release-host.js +239 -0
- package/dist/plan/remote-database.d.ts +124 -0
- package/dist/plan/remote-database.js +373 -0
- package/dist/plan/worker-app-database.d.ts +148 -0
- package/dist/plan/worker-app-database.js +424 -0
- package/dist/plan/worker-app.d.ts +320 -0
- package/dist/plan/worker-app.js +792 -0
- package/dist/plan/zitadel-machine-user.d.ts +13 -1
- package/dist/plan/zitadel-machine-user.js +80 -0
- package/dist/platform.d.ts +11 -1
- package/dist/platform.js +4 -1
- package/dist/release/decide.d.ts +95 -0
- package/dist/release/decide.js +242 -0
- package/dist/release/health.d.ts +48 -0
- package/dist/release/health.js +61 -0
- package/dist/release/run.d.ts +40 -0
- package/dist/release/run.js +56 -0
- package/dist/release/state.d.ts +64 -0
- package/dist/release/state.js +126 -0
- package/dist/release/types.d.ts +54 -0
- package/dist/release/types.js +4 -0
- package/dist/requested-changes.d.ts +12 -3
- package/dist/requested-changes.js +22 -0
- package/dist/store/postgres.d.ts +8 -0
- package/dist/store/postgres.js +67 -8
- package/dist/store/schema.d.ts +188 -0
- package/dist/store/schema.js +15 -0
- package/dist/worker-app-config.d.ts +151 -0
- package/dist/worker-app-config.js +438 -0
- package/package.json +1 -1
- package/versions.digests.json +2 -1
- package/versions.json +2 -1
package/dist/plan/executor.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { OrgMailOptions, OrgMailOrg, OrgMailResult } from '@wtfalch/email/postmaster';
|
|
2
2
|
import { type CallsSfuUrls } from '../calls-sfu.js';
|
|
3
|
-
import type { DeclaredOrg, HostingBuildPack } from '../org.js';
|
|
3
|
+
import type { DeclaredOrg, HostingBuildPack, OrgId } from '../org.js';
|
|
4
4
|
import type { DeclaredOrgStore } from '../store.js';
|
|
5
|
+
import { type BlueGreenServer, type BlueGreenSubject } from './blue-green.js';
|
|
5
6
|
import { type BrokerPort } from './broker-entries.js';
|
|
6
7
|
import { type DeployHealthRuntime } from './deploy-health.js';
|
|
7
8
|
import { type StepAction } from './diff.js';
|
|
@@ -16,6 +17,9 @@ import { type OwnServicesPort } from './own-services.js';
|
|
|
16
17
|
import type { DestroyTarget, StepDestroyer, StepExecutionContext, StepExecutor } from './plan-apply.js';
|
|
17
18
|
import type { EdgePortName } from './platform-org.js';
|
|
18
19
|
import type { RequestHeaderPort } from './platform-providers.js';
|
|
20
|
+
import { type ReleaseContext, type ReleaseHost } from './release-host.js';
|
|
21
|
+
import type { WorkerAppDatabasePort } from './worker-app-database.js';
|
|
22
|
+
import { type KeysCustodyPort, type WorkerAppPort } from './worker-app.js';
|
|
19
23
|
export declare function coolifyProjectMark(org: Pick<DeclaredOrg, 'id'>): string;
|
|
20
24
|
/**
|
|
21
25
|
* The Coolify calls this executor makes, shaped to match
|
|
@@ -103,6 +107,8 @@ export interface CoolifyPort {
|
|
|
103
107
|
*/
|
|
104
108
|
getApplication(uuid: string): Promise<{
|
|
105
109
|
uuid: string;
|
|
110
|
+
/** Coolify's name for the app; a blue/green entry's recorded app is its blue copy only when this is the blue name. */
|
|
111
|
+
name?: string;
|
|
106
112
|
status?: string;
|
|
107
113
|
custom_labels?: string | null;
|
|
108
114
|
settings?: {
|
|
@@ -831,6 +837,8 @@ export interface ZitadelPort {
|
|
|
831
837
|
appType: 'web' | 'native';
|
|
832
838
|
redirectUris: string[];
|
|
833
839
|
postLogoutRedirectUris: string[];
|
|
840
|
+
/** `jwt` for an entry with `uses.auth.mcp` (providers 0.11.0). Omitted: opaque. */
|
|
841
|
+
accessTokenType?: 'jwt' | 'opaque';
|
|
834
842
|
}): Promise<{
|
|
835
843
|
appId: string;
|
|
836
844
|
clientId: string;
|
|
@@ -1116,6 +1124,25 @@ export interface ZitadelPort {
|
|
|
1116
1124
|
* reports no longer live is never attempted at all.
|
|
1117
1125
|
*/
|
|
1118
1126
|
listLoginClientPats(orgId: string, userId: string): Promise<string[]>;
|
|
1127
|
+
/**
|
|
1128
|
+
* C3: mints a read-only directory credential for one ZITADEL organisation (the company's
|
|
1129
|
+
* customers): a machine user with only the read-only organisation role, and a fresh PAT.
|
|
1130
|
+
* Idempotent on the user by `userName`; every PAT the user already holds is revoked before the
|
|
1131
|
+
* new one is minted, so a rerun leaves exactly one live token (like
|
|
1132
|
+
* {@link mintLoginClientMachineUser}). The caller holds the token and writes it to Boule's env;
|
|
1133
|
+
* it never reaches an error, a log or a recorded id. Optional: a host without it gets the
|
|
1134
|
+
* customers directory reported blocked. `zitadel-machine-user.ts` is the real implementation.
|
|
1135
|
+
*/
|
|
1136
|
+
mintOrgDirectoryReader?(orgId: string, input: {
|
|
1137
|
+
userName: string;
|
|
1138
|
+
name: string;
|
|
1139
|
+
}): Promise<{
|
|
1140
|
+
userId: string;
|
|
1141
|
+
token: string;
|
|
1142
|
+
patId: string;
|
|
1143
|
+
}>;
|
|
1144
|
+
/** C3: revokes every PAT of the directory reader, so a company that turns customers off leaves no live credential. A PAT already gone is not an error. */
|
|
1145
|
+
revokeOrgDirectoryReader?(orgId: string, userId: string): Promise<void>;
|
|
1119
1146
|
/**
|
|
1120
1147
|
* #267: adds the org's own company login host to the ZITADEL instance's
|
|
1121
1148
|
* trusted domains (`@wtfalch/providers`' `ZitadelClient.ensureTrustedDomain`)
|
|
@@ -1173,6 +1200,21 @@ export interface ZitadelPort {
|
|
|
1173
1200
|
* `createOidcApp` and `createOidcAppWithSecret` send it on themselves.
|
|
1174
1201
|
*/
|
|
1175
1202
|
updateOidcAppIdTokenUserinfoAssertion?(orgId: string, projectId: string, appId: string): Promise<boolean>;
|
|
1203
|
+
/**
|
|
1204
|
+
* Auth ADR 0002: an existing sign-in app issues JWT access tokens and holds
|
|
1205
|
+
* every `redirectUris` entry (`@wtfalch/providers` 0.11.0). Resolves `true`
|
|
1206
|
+
* when it wrote, `false` when nothing differed. Optional, with
|
|
1207
|
+
* {@link ZitadelPort.ensureAccessTokenLifetime}: a host whose client lacks
|
|
1208
|
+
* either gets every `uses.auth.mcp` reported blocked
|
|
1209
|
+
* (`FoundryPlanApplyOptions.zitadelMcp`).
|
|
1210
|
+
*/
|
|
1211
|
+
ensureOidcAppMcpAccess?(orgId: string, projectId: string, appId: string, want: {
|
|
1212
|
+
redirectUris: string[];
|
|
1213
|
+
}): Promise<boolean>;
|
|
1214
|
+
/** The instance-wide access-token lifetime, in seconds. Resolves `{ changed }`. */
|
|
1215
|
+
ensureAccessTokenLifetime?(seconds: number): Promise<{
|
|
1216
|
+
changed: boolean;
|
|
1217
|
+
}>;
|
|
1176
1218
|
}
|
|
1177
1219
|
/**
|
|
1178
1220
|
* #274 fix round 4: bridges `@wtfalch/providers`' real `ZitadelClient.
|
|
@@ -1536,6 +1578,11 @@ export interface PlatformOrgPortSource {
|
|
|
1536
1578
|
/** The platform's shared sign-in host, or `null` when none is declared. */
|
|
1537
1579
|
authHostname?(): Promise<string | null>;
|
|
1538
1580
|
}
|
|
1581
|
+
/**
|
|
1582
|
+
* C3: mints the Archon credential for one org's Boule and returns the secret. Every call rotates the
|
|
1583
|
+
* org's credential (the old secret stays valid one more hour) or issues the first.
|
|
1584
|
+
*/
|
|
1585
|
+
export type BouleArchonCredentialMinter = (orgId: OrgId) => Promise<string>;
|
|
1539
1586
|
export interface FoundryStepExecutorPorts {
|
|
1540
1587
|
coolify: CoolifyPort;
|
|
1541
1588
|
/**
|
|
@@ -1662,6 +1709,29 @@ export interface FoundryStepExecutorPorts {
|
|
|
1662
1709
|
* sets `FoundryPlanApplyOptions.edgeWorkers`).
|
|
1663
1710
|
*/
|
|
1664
1711
|
workers?: WorkersPort;
|
|
1712
|
+
/**
|
|
1713
|
+
* ADR 0002: deploys and routes an entry's `workerApp` -- see
|
|
1714
|
+
* {@link WorkerAppPort}. Optional the same way `workers` is: without it the
|
|
1715
|
+
* plan reports each Worker app blocked (the host also sets
|
|
1716
|
+
* `FoundryPlanApplyOptions.workerApps`).
|
|
1717
|
+
*/
|
|
1718
|
+
workerApps?: WorkerAppPort;
|
|
1719
|
+
/** ADR 0002: the keys custody Worker, for a `keysCustody` secret of a Worker app. */
|
|
1720
|
+
workerAppKeys?: KeysCustodyPort;
|
|
1721
|
+
/**
|
|
1722
|
+
* C3: mints the credential an org's Boule reaches Archon with (org-scoped; `orgs:request` and
|
|
1723
|
+
* `orgs:read` for that org). Archon implements it. Every call rotates the credential (the old secret
|
|
1724
|
+
* stays valid one more hour) and credentials expire after 365 days, so foundry calls it only when none
|
|
1725
|
+
* was pushed or the recorded push time is 335 days old. It reaches Boule's env as `ARCHON_CREDENTIAL` and nowhere else. Without it the host
|
|
1726
|
+
* writes no Archon credential and the plan says so.
|
|
1727
|
+
*/
|
|
1728
|
+
mintBouleArchonCredential?: BouleArchonCredentialMinter;
|
|
1729
|
+
/**
|
|
1730
|
+
* C2: the Hyperdrive config, the release's `migrations.json` and the SQL runner behind the tunnel,
|
|
1731
|
+
* for a Worker app with `workerApp.database`. Without it the plan reports that entry blocked
|
|
1732
|
+
* (the host also sets `FoundryPlanApplyOptions.workerAppDatabase`).
|
|
1733
|
+
*/
|
|
1734
|
+
workerAppDatabase?: WorkerAppDatabasePort;
|
|
1665
1735
|
/**
|
|
1666
1736
|
* Hands a just-minted, one-time secret (today: an API app's
|
|
1667
1737
|
* `clientSecret`) to the host, immediately after the provider returns it
|
|
@@ -1843,6 +1913,10 @@ export declare class FoundryStepExecutor implements StepExecutor, StepDestroyer
|
|
|
1843
1913
|
private executeScoped;
|
|
1844
1914
|
/** Whether `ensureOwnAuthMailToken` can mint: the same two inputs it blocks on. */
|
|
1845
1915
|
ownMailKeyMintable(): boolean;
|
|
1916
|
+
/** C3: whether the ZITADEL port can mint and revoke a customers directory credential. */
|
|
1917
|
+
customersDirectoryAvailable(): boolean;
|
|
1918
|
+
/** C3: whether the host supplied `mintBouleArchonCredential`. */
|
|
1919
|
+
bouleArchonCredentialAvailable(): boolean;
|
|
1846
1920
|
/** Whether the held keys can store a new company's sign-in database CA and certificate (#746). */
|
|
1847
1921
|
ownSigninDbKeysPuttable(): boolean;
|
|
1848
1922
|
/** Whether the host supplies the backup bucket the sign-in database dumps into (#746). */
|
|
@@ -1944,6 +2018,7 @@ export declare class FoundryStepExecutor implements StepExecutor, StepDestroyer
|
|
|
1944
2018
|
* "Declared changes apply" nothing is marked done until the
|
|
1945
2019
|
* live state actually matches it.
|
|
1946
2020
|
*/
|
|
2021
|
+
private workerAppDeps;
|
|
1947
2022
|
private cloudflareWorker;
|
|
1948
2023
|
/**
|
|
1949
2024
|
* Makes the no-Worker routes recorded for an entry match `patterns`: deletes
|
|
@@ -2003,6 +2078,12 @@ export declare class FoundryStepExecutor implements StepExecutor, StepDestroyer
|
|
|
2003
2078
|
* nothing: the next apply finds the account by username and mints a new code.
|
|
2004
2079
|
*/
|
|
2005
2080
|
private zitadelOwner;
|
|
2081
|
+
/** `plan/mcp.ts`: the entry's MCP audience project. */
|
|
2082
|
+
private zitadelMcpProject;
|
|
2083
|
+
/** `plan/mcp.ts`: JWT access tokens and the broker's callback on the entry's app. */
|
|
2084
|
+
private zitadelMcpAccess;
|
|
2085
|
+
/** `plan/mcp.ts`: the instance access-token lifetime. */
|
|
2086
|
+
private zitadelAccessTokenLifetime;
|
|
2006
2087
|
/**
|
|
2007
2088
|
* Switches on "user info inside the ID token" for each live sign-in app
|
|
2008
2089
|
* the planner named. An app's marker (its ZITADEL app id) is recorded and
|
|
@@ -2096,7 +2177,7 @@ export declare class FoundryStepExecutor implements StepExecutor, StepDestroyer
|
|
|
2096
2177
|
/**
|
|
2097
2178
|
* `plan/diff.ts`'s `planCustomers` (plan gap A9): the org's customers sign
|
|
2098
2179
|
* in through a second ZITADEL org, `<slug> customers`, with
|
|
2099
|
-
* self-registration
|
|
2180
|
+
* self-registration as `customers.signUp` says (off by default) and a grant to the org's app project. Staff stay in
|
|
2100
2181
|
* the org's own invite-only ZITADEL org. The space keeps the name apart from
|
|
2101
2182
|
* every issuer org, which is named by a slug and a slug has no spaces. Every call here is idempotent, so
|
|
2102
2183
|
* a re-run after a crash finishes the job.
|
|
@@ -2141,6 +2222,34 @@ export declare class FoundryStepExecutor implements StepExecutor, StepDestroyer
|
|
|
2141
2222
|
* actually be created on.
|
|
2142
2223
|
*/
|
|
2143
2224
|
private resolveServer;
|
|
2225
|
+
/**
|
|
2226
|
+
* Contract C3: every usable, reachable Coolify server, the org's primary first. The primary is
|
|
2227
|
+
* {@link resolveServer}'s (databases and single-copy services stay on it, unchanged). A server that is
|
|
2228
|
+
* down is named in `down` and left out of `servers`; it is not an error.
|
|
2229
|
+
*/
|
|
2230
|
+
resolveServers(org: DeclaredOrg, context: StepExecutionContext): Promise<{
|
|
2231
|
+
primary: {
|
|
2232
|
+
uuid: string;
|
|
2233
|
+
};
|
|
2234
|
+
servers: Array<{
|
|
2235
|
+
uuid: string;
|
|
2236
|
+
}>;
|
|
2237
|
+
down: string[];
|
|
2238
|
+
}>;
|
|
2239
|
+
/**
|
|
2240
|
+
* The release runner's outside calls for one blue/green entry (`plan/release-host.ts`), or `null` while its
|
|
2241
|
+
* blue copy is not recorded. The health token is only read here, never minted.
|
|
2242
|
+
*/
|
|
2243
|
+
releaseHost(org: DeclaredOrg, subject: BlueGreenSubject, context: ReleaseContext, renew: () => Promise<void>): ReleaseHost | null;
|
|
2244
|
+
/** Every server Coolify lists with whether it is usable and reachable, for the planner. */
|
|
2245
|
+
blueGreenServers(): Promise<BlueGreenServer[]>;
|
|
2246
|
+
/**
|
|
2247
|
+
* The blue/green steps (`plan/blue-green.ts`): `bluegreen` makes the apps and the balancer on one server,
|
|
2248
|
+
* `bluegreen-lb` only writes the balancer's weights, `bluegreen-connector` runs the tunnel's connector on a
|
|
2249
|
+
* server. A server that went down since the plan is skipped by `bluegreen-connector`'s caller, not here:
|
|
2250
|
+
* a step for it fails, which the next plan reports instead.
|
|
2251
|
+
*/
|
|
2252
|
+
private coolifyBlueGreen;
|
|
2144
2253
|
private coolifyApp;
|
|
2145
2254
|
/**
|
|
2146
2255
|
* #75: mounts a persistent volume at {@link LOG_DIR} on the app, unless one
|
|
@@ -2891,6 +3000,27 @@ export declare class FoundryStepExecutor implements StepExecutor, StepDestroyer
|
|
|
2891
3000
|
* shape {@link coolifyAgora}'s own doc comment explains.
|
|
2892
3001
|
*/
|
|
2893
3002
|
private coolifyBoule;
|
|
3003
|
+
/**
|
|
3004
|
+
* C3: the Archon credential of an org's Boule. Archon's mint rotates on every call, so it is called only
|
|
3005
|
+
* when none was pushed or the recorded push time (no secret) is 335 days old. Otherwise the held value is
|
|
3006
|
+
* written again unchanged. The secret is held first; the caller records `pushedAt` only after the env write
|
|
3007
|
+
* succeeded, so a failed hold or a failed push is mended by the next apply minting again. Errors name no secret.
|
|
3008
|
+
*/
|
|
3009
|
+
private ensureBouleArchonCredential;
|
|
3010
|
+
/**
|
|
3011
|
+
* C3: the read-only credential for the company's customers organisation. Held first. Minting revokes every
|
|
3012
|
+
* earlier token of the machine user, so a hold that failed is repaired by the next apply minting again and
|
|
3013
|
+
* leaves one live token. `null` while the customers organisation is not recorded yet.
|
|
3014
|
+
*/
|
|
3015
|
+
private ensureCustomersDirectoryCredential;
|
|
3016
|
+
/** `put`, tried up to {@link BOULE_CREDENTIAL_ATTEMPTS} times; true once one attempt succeeds. The cause is dropped. */
|
|
3017
|
+
private holdWithRetry;
|
|
3018
|
+
/**
|
|
3019
|
+
* C3: customers switched off. Revokes the directory credential's tokens first, then removes the customers
|
|
3020
|
+
* env from Boule, then forgets the held value and the user id. Each step is repeated safely, so a run that
|
|
3021
|
+
* died halfway is finished by the next. Returns true when Boule's env changed.
|
|
3022
|
+
*/
|
|
3023
|
+
private dropCustomersCredential;
|
|
2894
3024
|
/**
|
|
2895
3025
|
* Gives Boule `LETTERMINT_API_TOKEN`: the platform's held key for an org on
|
|
2896
3026
|
* the platform's own apex, else the org's `<slug>-app` token through the
|
|
@@ -3009,6 +3139,8 @@ export declare class FoundryStepExecutor implements StepExecutor, StepDestroyer
|
|
|
3009
3139
|
*/
|
|
3010
3140
|
private ownSfu;
|
|
3011
3141
|
private jobsRegistration;
|
|
3142
|
+
/** The blue/green database route (`plan/remote-database.ts`). */
|
|
3143
|
+
private remoteDatabaseRoute;
|
|
3012
3144
|
/** `deliverSecret`, tried up to {@link JOBS_DELIVERY_ATTEMPTS} times; true once one attempt succeeds. */
|
|
3013
3145
|
private deliverWithRetry;
|
|
3014
3146
|
private cloudflareTunnel;
|