@wtfalch/foundry 0.60.0 → 0.62.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/apps/cloudflare.d.ts +173 -0
- package/dist/apps/cloudflare.js +17 -0
- package/dist/apps/deploy.d.ts +116 -0
- package/dist/apps/deploy.js +791 -0
- package/dist/apps/github.d.ts +47 -0
- package/dist/apps/github.js +201 -0
- package/dist/apps/index.d.ts +9 -0
- package/dist/apps/index.js +9 -0
- package/dist/apps/migrations.d.ts +110 -0
- package/dist/apps/migrations.js +458 -0
- package/dist/audit/connector.d.ts +43 -0
- package/dist/audit/connector.js +22 -0
- package/dist/audit/evidence.d.ts +49 -0
- package/dist/audit/evidence.js +56 -0
- package/dist/audit/index.d.ts +9 -0
- package/dist/audit/index.js +9 -0
- package/dist/audit/migrations.d.ts +5 -0
- package/dist/audit/migrations.js +5 -0
- package/dist/audit/registry.d.ts +49 -0
- package/dist/audit/registry.js +44 -0
- package/dist/audit/seal.d.ts +49 -0
- package/dist/audit/seal.js +131 -0
- package/dist/audit/sealer-role.d.ts +33 -0
- package/dist/audit/sealer-role.js +56 -0
- package/dist/audit/signer.d.ts +40 -0
- package/dist/audit/signer.js +78 -0
- package/dist/audit/tick.d.ts +36 -0
- package/dist/audit/tick.js +87 -0
- package/dist/catalogue/copy-en.d.ts +1 -0
- package/dist/catalogue/copy-en.js +129 -0
- package/dist/catalogue/index.d.ts +9 -0
- package/dist/catalogue/index.js +21 -0
- package/dist/catalogue/integrations.d.ts +4 -0
- package/dist/catalogue/integrations.js +104 -0
- package/dist/catalogue/systems.d.ts +7 -0
- package/dist/catalogue/systems.js +31 -0
- package/dist/catalogue/types.d.ts +110 -0
- package/dist/catalogue/types.js +1 -0
- package/dist/entry-rules.d.ts +53 -0
- package/dist/entry-rules.js +71 -0
- package/dist/hosted-label.d.ts +13 -0
- package/dist/hosted-label.js +81 -0
- package/dist/index.d.ts +14 -5
- package/dist/index.js +7 -3
- package/dist/migrations/0062_hosting_github.sql +6 -0
- package/dist/migrations/0063_boule_apps.sql +7 -0
- package/dist/migrations/0064_requested_changes_boule_apps.sql +6 -0
- package/dist/migrations/0065_native_build_runs.sql +32 -0
- package/dist/migrations/0066_org_kosmos.sql +10 -0
- package/dist/modules/ai.d.ts +3 -0
- package/dist/modules/ai.js +64 -0
- package/dist/modules/assistants.d.ts +3 -0
- package/dist/modules/assistants.js +72 -0
- package/dist/modules/audit-ledger.d.ts +29 -0
- package/dist/modules/audit-ledger.js +49 -0
- package/dist/modules/audit.d.ts +7 -0
- package/dist/modules/audit.js +44 -0
- package/dist/modules/database.d.ts +23 -0
- package/dist/modules/database.js +189 -0
- package/dist/modules/email.d.ts +3 -0
- package/dist/modules/email.js +18 -0
- package/dist/modules/entry-parts.d.ts +23 -0
- package/dist/modules/entry-parts.js +63 -0
- package/dist/modules/files.d.ts +3 -0
- package/dist/modules/files.js +64 -0
- package/dist/modules/index.d.ts +74 -0
- package/dist/modules/index.js +774 -0
- package/dist/modules/jobs.d.ts +3 -0
- package/dist/modules/jobs.js +23 -0
- package/dist/modules/organisations.d.ts +3 -0
- package/dist/modules/organisations.js +20 -0
- package/dist/modules/outputs.d.ts +9 -0
- package/dist/modules/outputs.js +38 -0
- package/dist/modules/sign-in.d.ts +3 -0
- package/dist/modules/sign-in.js +197 -0
- package/dist/modules/signed-records.d.ts +3 -0
- package/dist/modules/signed-records.js +32 -0
- package/dist/modules/types.d.ts +194 -0
- package/dist/modules/types.js +1 -0
- package/dist/modules/workspaces.d.ts +3 -0
- package/dist/modules/workspaces.js +75 -0
- package/dist/native-build.d.ts +70 -0
- package/dist/native-build.js +92 -0
- package/dist/org.d.ts +184 -24
- package/dist/org.js +444 -49
- package/dist/plan/agora.d.ts +1 -1
- package/dist/plan/agora.js +4 -0
- package/dist/plan/apps-db-route.d.ts +90 -0
- package/dist/plan/apps-db-route.js +168 -0
- package/dist/plan/apps-zones.d.ts +56 -0
- package/dist/plan/apps-zones.js +118 -0
- package/dist/plan/archon-blue-green.js +11 -1
- package/dist/plan/blue-green-apply.d.ts +37 -1
- package/dist/plan/blue-green-apply.js +55 -15
- package/dist/plan/blue-green.d.ts +60 -8
- package/dist/plan/blue-green.js +115 -10
- package/dist/plan/boule.d.ts +23 -1
- package/dist/plan/boule.js +35 -2
- package/dist/plan/broker-entries.d.ts +28 -3
- package/dist/plan/broker-entries.js +74 -3
- package/dist/plan/broker-registrar.d.ts +168 -0
- package/dist/plan/broker-registrar.js +440 -0
- package/dist/plan/broker-workspaces-database.d.ts +48 -0
- package/dist/plan/broker-workspaces-database.js +87 -0
- package/dist/plan/deploy-health.js +9 -2
- package/dist/plan/desktop-callback.js +15 -7
- package/dist/plan/diff.d.ts +8 -2
- package/dist/plan/diff.js +552 -104
- package/dist/plan/edge-access.d.ts +6 -0
- package/dist/plan/edge-access.js +1 -0
- package/dist/plan/edge-dns.d.ts +6 -0
- package/dist/plan/edge-dns.js +9 -7
- package/dist/plan/entry-ai-key.d.ts +1 -1
- package/dist/plan/entry-ai-key.js +2 -2
- package/dist/plan/entry-audit.d.ts +58 -0
- package/dist/plan/entry-audit.js +122 -0
- package/dist/plan/entry-customer-grants.d.ts +75 -0
- package/dist/plan/entry-customer-grants.js +154 -0
- package/dist/plan/entry-edge-key.d.ts +26 -1
- package/dist/plan/entry-edge-key.js +42 -3
- package/dist/plan/entry-jobs.d.ts +64 -0
- package/dist/plan/entry-jobs.js +92 -0
- package/dist/plan/entry-repo-key-apply.d.ts +55 -0
- package/dist/plan/entry-repo-key-apply.js +185 -0
- package/dist/plan/entry-repo-key.d.ts +92 -0
- package/dist/plan/entry-repo-key.js +235 -0
- package/dist/plan/entry-workspaces.d.ts +55 -0
- package/dist/plan/entry-workspaces.js +90 -0
- package/dist/plan/executor.d.ts +231 -19
- package/dist/plan/executor.js +1648 -129
- package/dist/plan/gates.d.ts +1 -1
- package/dist/plan/gates.js +62 -9
- package/dist/plan/github-deploy-keys.d.ts +78 -0
- package/dist/plan/github-deploy-keys.js +305 -0
- package/dist/plan/github-source.d.ts +53 -0
- package/dist/plan/github-source.js +140 -0
- package/dist/plan/held-key-refs.d.ts +12 -0
- package/dist/plan/held-key-refs.js +12 -0
- package/dist/plan/hostnames.d.ts +9 -0
- package/dist/plan/hostnames.js +28 -1
- package/dist/plan/index.d.ts +9 -0
- package/dist/plan/index.js +6 -0
- package/dist/plan/jobs-scheduler-http.js +3 -0
- package/dist/plan/keys-registrar-http.d.ts +32 -0
- package/dist/plan/keys-registrar-http.js +105 -0
- package/dist/plan/keys-registrar.d.ts +67 -0
- package/dist/plan/keys-registrar.js +103 -0
- package/dist/plan/kosmos.d.ts +56 -0
- package/dist/plan/kosmos.js +84 -0
- package/dist/plan/live.d.ts +1 -1
- package/dist/plan/locked-hostnames.d.ts +2 -2
- package/dist/plan/locked-hostnames.js +7 -4
- package/dist/plan/login-host.js +11 -5
- package/dist/plan/machine-paths.d.ts +36 -0
- package/dist/plan/machine-paths.js +137 -0
- package/dist/plan/mcp.d.ts +1 -1
- package/dist/plan/mcp.js +49 -17
- package/dist/plan/org-apps-admin.d.ts +108 -0
- package/dist/plan/org-apps-admin.js +434 -0
- package/dist/plan/org-names.d.ts +3 -3
- package/dist/plan/org-names.js +15 -2
- package/dist/plan/org-postgres-migrate.js +1 -0
- package/dist/plan/own-diff.d.ts +23 -0
- package/dist/plan/own-diff.js +53 -0
- package/dist/plan/own-hostnames.d.ts +2 -0
- package/dist/plan/own-hostnames.js +1 -0
- package/dist/plan/own-jobs-route.d.ts +47 -0
- package/dist/plan/own-jobs-route.js +91 -0
- package/dist/plan/own-limits.d.ts +6 -0
- package/dist/plan/own-limits.js +1 -0
- package/dist/plan/own-services.d.ts +4 -0
- package/dist/plan/own-services.js +4 -0
- package/dist/plan/plan-apply.d.ts +39 -0
- package/dist/plan/plan-apply.js +163 -9
- package/dist/plan/platform-diff.d.ts +2 -2
- package/dist/plan/platform-diff.js +7 -2
- package/dist/plan/platform-org.d.ts +30 -0
- package/dist/plan/platform-org.js +12 -1
- package/dist/plan/platform-providers.d.ts +2 -0
- package/dist/plan/platform-providers.js +13 -2
- package/dist/plan/post-logout-uris.d.ts +1 -1
- package/dist/plan/post-logout-uris.js +12 -3
- package/dist/plan/private-pages.d.ts +26 -0
- package/dist/plan/private-pages.js +39 -0
- package/dist/plan/providers-readers.js +20 -1
- package/dist/plan/proxy-labels.d.ts +12 -1
- package/dist/plan/proxy-labels.js +32 -2
- package/dist/plan/release-host.d.ts +6 -2
- package/dist/plan/release-host.js +36 -8
- package/dist/plan/stage-env.d.ts +19 -1
- package/dist/plan/stage-env.js +25 -1
- package/dist/plan/stage-guards.d.ts +20 -0
- package/dist/plan/stage-guards.js +24 -0
- package/dist/plan/stage-isolation.d.ts +24 -0
- package/dist/plan/stage-isolation.js +29 -1
- package/dist/plan/worker-app-database.d.ts +46 -42
- package/dist/plan/worker-app-database.js +150 -153
- package/dist/plan/worker-app.d.ts +5 -65
- package/dist/plan/worker-app.js +28 -105
- package/dist/plan/worker.d.ts +2 -2
- package/dist/plan/worker.js +2 -1
- package/dist/plan/workspace-client.d.ts +25 -0
- package/dist/plan/workspace-client.js +48 -0
- package/dist/plan/workspace-sign-in.d.ts +55 -0
- package/dist/plan/workspace-sign-in.js +273 -0
- package/dist/plan/workspace-worker.d.ts +4 -0
- package/dist/plan/workspace-worker.js +13 -0
- package/dist/plan/workspace.d.ts +101 -0
- package/dist/plan/workspace.js +305 -0
- package/dist/release/decide.d.ts +30 -1
- package/dist/release/decide.js +73 -11
- package/dist/release/health.d.ts +8 -3
- package/dist/release/health.js +58 -5
- package/dist/release/migration-compatibility.d.ts +66 -0
- package/dist/release/migration-compatibility.js +340 -0
- package/dist/release/run.d.ts +2 -5
- package/dist/release/run.js +4 -0
- package/dist/release/state.d.ts +3 -1
- package/dist/release/state.js +6 -0
- package/dist/release/types.d.ts +20 -0
- package/dist/requested-changes.d.ts +11 -2
- package/dist/requested-changes.js +13 -1
- package/dist/service-labels.d.ts +4 -0
- package/dist/service-labels.js +11 -0
- package/dist/slug.d.ts +2 -0
- package/dist/slug.js +20 -7
- package/dist/store/postgres.js +25 -2
- package/dist/store/schema.d.ts +73 -1
- package/dist/store/schema.js +10 -0
- package/dist/worker-app-config.d.ts +1 -11
- package/dist/worker-app-config.js +4 -17
- package/dist/worker-app-migrations.d.ts +105 -0
- package/dist/worker-app-migrations.js +166 -0
- package/dist/worker-app-upload.d.ts +103 -0
- package/dist/worker-app-upload.js +128 -0
- package/package.json +19 -2
|
@@ -16,7 +16,7 @@ import type { PlanDetail } from './plan/diff.js';
|
|
|
16
16
|
* lowering or leaving a limit unchanged -- raising either one needs
|
|
17
17
|
* approval too, until a billing field exists to say what the raise costs.
|
|
18
18
|
*/
|
|
19
|
-
export type RequestableField = 'calls' | 'customers' | 'storageLimit' | 'aiLimit' | 'domain' | 'mailTier' | 'app' | 'build';
|
|
19
|
+
export type RequestableField = 'calls' | 'customers' | 'storageLimit' | 'aiLimit' | 'domain' | 'mailTier' | 'app' | 'build' | 'bouleApps';
|
|
20
20
|
export declare const REQUESTABLE_FIELDS: readonly RequestableField[];
|
|
21
21
|
/** Turn the org's own calls Matrix stack (`org.ts`'s `CallsConfig.enabled`) on or off. */
|
|
22
22
|
export interface CallsChange {
|
|
@@ -75,12 +75,21 @@ export interface BuildChange {
|
|
|
75
75
|
release: string;
|
|
76
76
|
build: BuildJson;
|
|
77
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Turn `org.boule.apps` on or off (`org.ts`'s `BouleApp.apps`). The company's own Boule turns it on when it makes
|
|
80
|
+
* its first app, so no infra is provisioned that is not in use. On is `auto`. Off retires the edge key, both
|
|
81
|
+
* registrar keys and the apps database route (steps with `destroys: true`), so it always needs a person.
|
|
82
|
+
*/
|
|
83
|
+
export interface BouleAppsChange {
|
|
84
|
+
field: 'bouleApps';
|
|
85
|
+
enabled: boolean;
|
|
86
|
+
}
|
|
78
87
|
/**
|
|
79
88
|
* One company-requested change to its own declared org, keyed by
|
|
80
89
|
* {@link RequestableField}. `classifyChange` and the store both switch on
|
|
81
90
|
* `.field`.
|
|
82
91
|
*/
|
|
83
|
-
export type RequestedChangeValue = CallsChange | CustomersChange | StorageLimitChange | AiLimitChange | DomainChange | MailTierChange | AppChange | BuildChange;
|
|
92
|
+
export type RequestedChangeValue = CallsChange | CustomersChange | StorageLimitChange | AiLimitChange | DomainChange | MailTierChange | AppChange | BuildChange | BouleAppsChange;
|
|
84
93
|
/**
|
|
85
94
|
* `auto`: nothing further is required -- archon may carry the request
|
|
86
95
|
* straight into a plan and apply it. `approval`: a human must approve the
|
|
@@ -8,6 +8,7 @@ export const REQUESTABLE_FIELDS = [
|
|
|
8
8
|
'mailTier',
|
|
9
9
|
'app',
|
|
10
10
|
'build',
|
|
11
|
+
'bouleApps',
|
|
11
12
|
];
|
|
12
13
|
/**
|
|
13
14
|
* Thrown by {@link classifyChange} (and by the requested-change store's
|
|
@@ -44,6 +45,8 @@ function applyRequestedChange(org, change) {
|
|
|
44
45
|
return { ...org, domain: change.domain };
|
|
45
46
|
case 'mailTier':
|
|
46
47
|
return { ...org, mail: { ...org.mail, mode: change.mode } };
|
|
48
|
+
case 'bouleApps':
|
|
49
|
+
return { ...org, boule: { ...org.boule, apps: change.enabled } };
|
|
47
50
|
case 'app':
|
|
48
51
|
case 'build':
|
|
49
52
|
return org;
|
|
@@ -121,8 +124,17 @@ export function classifyChange(org, change, plan) {
|
|
|
121
124
|
throw new RequestedChangeError(`'${change.field}' is not a requestable field`);
|
|
122
125
|
}
|
|
123
126
|
// Archon validates the whole company for these; nothing waits for approval.
|
|
124
|
-
if (change.field === 'app' || change.field === 'build')
|
|
127
|
+
if (change.field === 'app' || change.field === 'build') {
|
|
125
128
|
return 'auto';
|
|
129
|
+
}
|
|
130
|
+
if (change.field === 'bouleApps') {
|
|
131
|
+
if (typeof change.enabled !== 'boolean') {
|
|
132
|
+
throw new RequestedChangeError('bouleApps needs enabled, true or false');
|
|
133
|
+
}
|
|
134
|
+
// Turning on provisions only what the first app needs. Turning off retires credentials and routes
|
|
135
|
+
// (`destroys: true` steps), so it needs a person whether or not a plan was given.
|
|
136
|
+
return change.enabled ? 'auto' : 'approval';
|
|
137
|
+
}
|
|
126
138
|
if (change.field === 'customers') {
|
|
127
139
|
validateCustomersChange(change);
|
|
128
140
|
// The org after the change must still pass the rule apply checks, for example open registration
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** The labels an own org's services answer on, so no hosting entry may take them. */
|
|
2
|
+
export declare const OWN_SERVICE_LABELS: readonly ["auth", "mail", "files", "sfu"];
|
|
3
|
+
/** The first label of every name foundry itself serves for a company: its own services, Agora, Boule, the cms studio, calls, the sign-in host and file shares. */
|
|
4
|
+
export declare const FOUNDRY_SERVICE_LABELS: ReadonlySet<string>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** The labels an own org's services answer on, so no hosting entry may take them. */
|
|
2
|
+
export const OWN_SERVICE_LABELS = ['auth', 'mail', 'files', 'sfu'];
|
|
3
|
+
/** The first label of every name foundry itself serves for a company: its own services, Agora, Boule, the cms studio, calls, the sign-in host and file shares. */
|
|
4
|
+
export const FOUNDRY_SERVICE_LABELS = new Set([
|
|
5
|
+
...OWN_SERVICE_LABELS,
|
|
6
|
+
'agora',
|
|
7
|
+
'boule',
|
|
8
|
+
'cms',
|
|
9
|
+
'calls',
|
|
10
|
+
'share',
|
|
11
|
+
]);
|
package/dist/slug.d.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
export declare const RESERVED_SLUGS: ReadonlySet<string>;
|
|
3
3
|
/** Every platform app, tunnel, project and database name starts `platform-`, so no company slug may. */
|
|
4
4
|
export declare const RESERVED_SLUG_PREFIX = "platform-";
|
|
5
|
+
/** Whether `label` ends in a suffix reserved for another org's own hostname (`-stage`, `-pr-<n>`, `-calls`, `-agora`, `-boule`, `-kosmos`, `-auth`, `-mail`, `-files`, `-sfu`, `-cms`). */
|
|
6
|
+
export declare function hasBarredSlugSuffix(label: string): boolean;
|
|
5
7
|
/**
|
|
6
8
|
* Why {@link validateSlug} refused a candidate slug, by name so a caller —
|
|
7
9
|
* `store/postgres.ts`'s `DeclaredOrgError`, eventually the operator page —
|
package/dist/slug.js
CHANGED
|
@@ -138,6 +138,14 @@ const AGORA_SUFFIX = /-agora$/;
|
|
|
138
138
|
* one that opts in.
|
|
139
139
|
*/
|
|
140
140
|
const BOULE_SUFFIX = /-boule$/;
|
|
141
|
+
/**
|
|
142
|
+
* `<something>-kosmos` — a level-1 org's own kosmos hostname
|
|
143
|
+
* (`<slug>-kosmos.oikos.host`, foundry#949). Kosmos is opt-in, the same way
|
|
144
|
+
* {@link CALLS_SUFFIX} guards a feature an org can decline: a slug ending
|
|
145
|
+
* `-kosmos` is only barred because it collides with that one org's own
|
|
146
|
+
* hostname once kosmos is on, not because every org gets one.
|
|
147
|
+
*/
|
|
148
|
+
const KOSMOS_SUFFIX = /-kosmos$/;
|
|
141
149
|
/** `<something>-auth|-mail|-files|-sfu|-cms` — an own company's service hostnames on oikos.host (`plan/own-hostnames.ts`). */
|
|
142
150
|
const OWN_SERVICE_SUFFIX = /-(auth|mail|files|sfu|cms)$/;
|
|
143
151
|
/**
|
|
@@ -151,6 +159,16 @@ const OWN_SERVICE_SUFFIX = /-(auth|mail|files|sfu|cms)$/;
|
|
|
151
159
|
* `names-`.
|
|
152
160
|
*/
|
|
153
161
|
const NAMES_PREFIX = /^names(-|$)/;
|
|
162
|
+
/** Whether `label` ends in a suffix reserved for another org's own hostname (`-stage`, `-pr-<n>`, `-calls`, `-agora`, `-boule`, `-kosmos`, `-auth`, `-mail`, `-files`, `-sfu`, `-cms`). */
|
|
163
|
+
export function hasBarredSlugSuffix(label) {
|
|
164
|
+
return (STAGE_SUFFIX.test(label) ||
|
|
165
|
+
PR_SUFFIX.test(label) ||
|
|
166
|
+
CALLS_SUFFIX.test(label) ||
|
|
167
|
+
AGORA_SUFFIX.test(label) ||
|
|
168
|
+
BOULE_SUFFIX.test(label) ||
|
|
169
|
+
KOSMOS_SUFFIX.test(label) ||
|
|
170
|
+
OWN_SERVICE_SUFFIX.test(label));
|
|
171
|
+
}
|
|
154
172
|
/**
|
|
155
173
|
* Validates a candidate org slug against every rule #28 decided. Returns
|
|
156
174
|
* `null` when the slug is acceptable, or a {@link SlugRejection} naming
|
|
@@ -177,15 +195,10 @@ export function validateSlug(slug) {
|
|
|
177
195
|
message: `slug '${slug}' is 'names' or starts with 'names-', a prefix edge reserves for its own platform tunnels and refuses to create a company tunnel under (#535)`,
|
|
178
196
|
};
|
|
179
197
|
}
|
|
180
|
-
if (
|
|
181
|
-
PR_SUFFIX.test(slug) ||
|
|
182
|
-
CALLS_SUFFIX.test(slug) ||
|
|
183
|
-
AGORA_SUFFIX.test(slug) ||
|
|
184
|
-
BOULE_SUFFIX.test(slug) ||
|
|
185
|
-
OWN_SERVICE_SUFFIX.test(slug)) {
|
|
198
|
+
if (hasBarredSlugSuffix(slug)) {
|
|
186
199
|
return {
|
|
187
200
|
reason: 'environment-suffix',
|
|
188
|
-
message: `slug '${slug}' ends with an environment suffix ('-stage', '-pr-<digits>', '-calls', '-agora', '-boule', '-auth', '-mail', '-files', '-sfu' or '-cms') reserved for another org's own hostname (#28, #145, #164, #161) — 'acme-calls' is only legal as acme's calls hostname, 'acme-agora' only as acme's Agora hostname, 'acme-boule' only as acme's Boule hostname, never as an org slug in its own right`,
|
|
201
|
+
message: `slug '${slug}' ends with an environment suffix ('-stage', '-pr-<digits>', '-calls', '-agora', '-boule', '-kosmos', '-auth', '-mail', '-files', '-sfu' or '-cms') reserved for another org's own hostname (#28, #145, #164, #161, #949) — 'acme-calls' is only legal as acme's calls hostname, 'acme-agora' only as acme's Agora hostname, 'acme-boule' only as acme's Boule hostname, 'acme-kosmos' only as acme's kosmos hostname, never as an org slug in its own right`,
|
|
189
202
|
};
|
|
190
203
|
}
|
|
191
204
|
return null;
|
package/dist/store/postgres.js
CHANGED
|
@@ -161,12 +161,30 @@ function rowToOrg(row) {
|
|
|
161
161
|
? { customers: { enabled: row.customersEnabled, signUp: row.customersSignUp } }
|
|
162
162
|
: {}),
|
|
163
163
|
// Omitted while unset. Validated on read: a stored value is not trusted.
|
|
164
|
-
...(row.bouleBlueGreen
|
|
165
|
-
? {
|
|
164
|
+
...(row.bouleBlueGreen || row.bouleApps
|
|
165
|
+
? {
|
|
166
|
+
boule: {
|
|
167
|
+
...(row.bouleBlueGreen
|
|
168
|
+
? { blueGreen: readBlueGreen(row.bouleBlueGreen, 'boule') }
|
|
169
|
+
: {}),
|
|
170
|
+
...(row.bouleApps ? { apps: true } : {}),
|
|
171
|
+
},
|
|
172
|
+
}
|
|
166
173
|
: {}),
|
|
167
174
|
...(row.agoraBlueGreen
|
|
168
175
|
? { agora: { blueGreen: readBlueGreen(row.agoraBlueGreen, 'agora') } }
|
|
169
176
|
: {}),
|
|
177
|
+
// Omitted while unset, as `boule`/`agora` are. Validated on read, the same way.
|
|
178
|
+
...(row.kosmosBlueGreen || row.kosmosEnabled
|
|
179
|
+
? {
|
|
180
|
+
kosmos: {
|
|
181
|
+
...(row.kosmosBlueGreen
|
|
182
|
+
? { blueGreen: readBlueGreen(row.kosmosBlueGreen, 'kosmos') }
|
|
183
|
+
: {}),
|
|
184
|
+
...(row.kosmosEnabled ? { enabled: true } : {}),
|
|
185
|
+
},
|
|
186
|
+
}
|
|
187
|
+
: {}),
|
|
170
188
|
...(row.versionPin ? { versionPin: readVersionPin(row) } : {}),
|
|
171
189
|
site: { enabled: row.siteEnabled, usesDomain: row.siteUsesDomain },
|
|
172
190
|
hosting: {
|
|
@@ -177,6 +195,7 @@ function rowToOrg(row) {
|
|
|
177
195
|
entries: row.hostingEntries.map((entry) => storedEntryToEntry(entry, row.hostingUsesDomain)),
|
|
178
196
|
gateLimit: row.hostingGateLimit,
|
|
179
197
|
repos: row.hostingRepos,
|
|
198
|
+
...(row.hostingGithub ? { github: row.hostingGithub } : {}),
|
|
180
199
|
},
|
|
181
200
|
sso: { enabled: row.ssoEnabled },
|
|
182
201
|
guests: { enabled: row.guestsEnabled },
|
|
@@ -230,7 +249,10 @@ function orgToRow(org) {
|
|
|
230
249
|
customersEnabled: org.customers?.enabled ?? false,
|
|
231
250
|
customersSignUp: org.customers?.signUp ?? false,
|
|
232
251
|
bouleBlueGreen: org.boule?.blueGreen ?? null,
|
|
252
|
+
bouleApps: org.boule?.apps ?? false,
|
|
233
253
|
agoraBlueGreen: org.agora?.blueGreen ?? null,
|
|
254
|
+
kosmosEnabled: org.kosmos?.enabled ?? false,
|
|
255
|
+
kosmosBlueGreen: org.kosmos?.blueGreen ?? null,
|
|
234
256
|
servicesOwn: org.services?.own ?? false,
|
|
235
257
|
servicesSfuSlot: org.services?.sfuSlot ?? null,
|
|
236
258
|
versionPin: org.versionPin && Object.keys(org.versionPin).length > 0 ? org.versionPin : null,
|
|
@@ -243,6 +265,7 @@ function orgToRow(org) {
|
|
|
243
265
|
hostingEntries: org.hosting.entries,
|
|
244
266
|
hostingGateLimit: org.hosting.gateLimit,
|
|
245
267
|
hostingRepos: normalizeHostingRepos(org.hosting.repos),
|
|
268
|
+
hostingGithub: org.hosting.github ?? null,
|
|
246
269
|
ssoEnabled: org.sso.enabled,
|
|
247
270
|
guestsEnabled: org.guests.enabled,
|
|
248
271
|
soloEnabled: org.solo.enabled,
|
package/dist/store/schema.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AppEnvSource, BlueGreenConfig, HostingEntry, IssuerApp, OwnerIdentity } from '../org.js';
|
|
1
|
+
import type { AppEnvSource, BlueGreenConfig, HostingEntry, HostingGithub, IssuerApp, OwnerIdentity } from '../org.js';
|
|
2
2
|
import type { Plan } from '../plan.js';
|
|
3
3
|
import type { Checkpoint, DestroyRecord } from '../state.js';
|
|
4
4
|
/**
|
|
@@ -444,6 +444,59 @@ export declare const declaredOrgs: import("drizzle-orm/pg-core").PgTableWithColu
|
|
|
444
444
|
}, {}, {
|
|
445
445
|
$type: BlueGreenConfig | null;
|
|
446
446
|
}>;
|
|
447
|
+
bouleApps: import("drizzle-orm/pg-core").PgColumn<{
|
|
448
|
+
name: "boule_apps";
|
|
449
|
+
tableName: "foundry_declared_orgs";
|
|
450
|
+
dataType: "boolean";
|
|
451
|
+
columnType: "PgBoolean";
|
|
452
|
+
data: boolean;
|
|
453
|
+
driverParam: boolean;
|
|
454
|
+
notNull: true;
|
|
455
|
+
hasDefault: true;
|
|
456
|
+
isPrimaryKey: false;
|
|
457
|
+
isAutoincrement: false;
|
|
458
|
+
hasRuntimeDefault: false;
|
|
459
|
+
enumValues: undefined;
|
|
460
|
+
baseColumn: never;
|
|
461
|
+
identity: undefined;
|
|
462
|
+
generated: undefined;
|
|
463
|
+
}, {}, {}>;
|
|
464
|
+
kosmosEnabled: import("drizzle-orm/pg-core").PgColumn<{
|
|
465
|
+
name: "kosmos_enabled";
|
|
466
|
+
tableName: "foundry_declared_orgs";
|
|
467
|
+
dataType: "boolean";
|
|
468
|
+
columnType: "PgBoolean";
|
|
469
|
+
data: boolean;
|
|
470
|
+
driverParam: boolean;
|
|
471
|
+
notNull: true;
|
|
472
|
+
hasDefault: true;
|
|
473
|
+
isPrimaryKey: false;
|
|
474
|
+
isAutoincrement: false;
|
|
475
|
+
hasRuntimeDefault: false;
|
|
476
|
+
enumValues: undefined;
|
|
477
|
+
baseColumn: never;
|
|
478
|
+
identity: undefined;
|
|
479
|
+
generated: undefined;
|
|
480
|
+
}, {}, {}>;
|
|
481
|
+
kosmosBlueGreen: import("drizzle-orm/pg-core").PgColumn<{
|
|
482
|
+
name: "kosmos_blue_green";
|
|
483
|
+
tableName: "foundry_declared_orgs";
|
|
484
|
+
dataType: "json";
|
|
485
|
+
columnType: "PgJsonb";
|
|
486
|
+
data: BlueGreenConfig | null;
|
|
487
|
+
driverParam: unknown;
|
|
488
|
+
notNull: false;
|
|
489
|
+
hasDefault: false;
|
|
490
|
+
isPrimaryKey: false;
|
|
491
|
+
isAutoincrement: false;
|
|
492
|
+
hasRuntimeDefault: false;
|
|
493
|
+
enumValues: undefined;
|
|
494
|
+
baseColumn: never;
|
|
495
|
+
identity: undefined;
|
|
496
|
+
generated: undefined;
|
|
497
|
+
}, {}, {
|
|
498
|
+
$type: BlueGreenConfig | null;
|
|
499
|
+
}>;
|
|
447
500
|
versionPin: import("drizzle-orm/pg-core").PgColumn<{
|
|
448
501
|
name: "version_pin";
|
|
449
502
|
tableName: "foundry_declared_orgs";
|
|
@@ -711,6 +764,25 @@ export declare const declaredOrgs: import("drizzle-orm/pg-core").PgTableWithColu
|
|
|
711
764
|
}, {}, {
|
|
712
765
|
$type: string[];
|
|
713
766
|
}>;
|
|
767
|
+
hostingGithub: import("drizzle-orm/pg-core").PgColumn<{
|
|
768
|
+
name: "hosting_github";
|
|
769
|
+
tableName: "foundry_declared_orgs";
|
|
770
|
+
dataType: "json";
|
|
771
|
+
columnType: "PgJsonb";
|
|
772
|
+
data: HostingGithub | null;
|
|
773
|
+
driverParam: unknown;
|
|
774
|
+
notNull: false;
|
|
775
|
+
hasDefault: false;
|
|
776
|
+
isPrimaryKey: false;
|
|
777
|
+
isAutoincrement: false;
|
|
778
|
+
hasRuntimeDefault: false;
|
|
779
|
+
enumValues: undefined;
|
|
780
|
+
baseColumn: never;
|
|
781
|
+
identity: undefined;
|
|
782
|
+
generated: undefined;
|
|
783
|
+
}, {}, {
|
|
784
|
+
$type: HostingGithub | null;
|
|
785
|
+
}>;
|
|
714
786
|
ssoEnabled: import("drizzle-orm/pg-core").PgColumn<{
|
|
715
787
|
name: "sso_enabled";
|
|
716
788
|
tableName: "foundry_declared_orgs";
|
package/dist/store/schema.js
CHANGED
|
@@ -46,6 +46,11 @@ export const declaredOrgs = pgTable('foundry_declared_orgs', {
|
|
|
46
46
|
// OrgBuiltinApp.blueGreen (org.ts) of Boule and Agora; `migrations/0059_org_builtin_blue_green.sql`. Null is off.
|
|
47
47
|
bouleBlueGreen: jsonb('boule_blue_green').$type(),
|
|
48
48
|
agoraBlueGreen: jsonb('agora_blue_green').$type(),
|
|
49
|
+
// BouleApp.apps (org.ts): Boule runs apps for the company; `migrations/0063_boule_apps.sql`.
|
|
50
|
+
bouleApps: boolean('boule_apps').notNull().default(false),
|
|
51
|
+
// KosmosApp (org.ts, foundry#949): the company's own kosmos, set up only when asked; `migrations/0066_org_kosmos.sql`.
|
|
52
|
+
kosmosEnabled: boolean('kosmos_enabled').notNull().default(false),
|
|
53
|
+
kosmosBlueGreen: jsonb('kosmos_blue_green').$type(),
|
|
49
54
|
// VersionPin (org.ts): null follows the platform. `migrations/0053_org_version_pin.sql`.
|
|
50
55
|
versionPin: jsonb('version_pin').$type(),
|
|
51
56
|
// SiteConfig (org.ts, T10). A brand new org has no cms site.
|
|
@@ -76,6 +81,11 @@ export const declaredOrgs = pgTable('foundry_declared_orgs', {
|
|
|
76
81
|
hostingGateLimit: integer('hosting_gate_limit').notNull().default(3),
|
|
77
82
|
// HostingConfig.repos (org.ts); migrations/0060. Lowercase `wtfalch/<name>` strings.
|
|
78
83
|
hostingRepos: jsonb('hosting_repos').notNull().default([]).$type(),
|
|
84
|
+
// HostingConfig.github (org.ts); migrations/0062. Null: the company has no GitHub App installation.
|
|
85
|
+
hostingGithub: jsonb('hosting_github').$type(),
|
|
86
|
+
// migrations/0065 added `hosting_native_apps` for foundry#948; foundry#951 dropped the column from
|
|
87
|
+
// use (Boule owns native settings now, estate#262) but not from the database -- a migration only
|
|
88
|
+
// adds in this release, since idle and live share one database. The column stays, unread.
|
|
79
89
|
ssoEnabled: boolean('sso_enabled').notNull().default(false),
|
|
80
90
|
guestsEnabled: boolean('guests_enabled').notNull().default(false),
|
|
81
91
|
soloEnabled: boolean('solo_enabled').notNull().default(false),
|
|
@@ -80,14 +80,8 @@ export declare const WORKER_APP_COMPATIBILITY_FLAGS: ReadonlySet<string>;
|
|
|
80
80
|
export declare const WORKER_APP_INSTANCE_TYPES: ReadonlySet<string>;
|
|
81
81
|
/** The most instances one container class may scale to. */
|
|
82
82
|
export declare const WORKER_APP_MAX_INSTANCES = 100;
|
|
83
|
-
|
|
84
|
-
export declare const WORKER_APP_KEYS_SECRET = "KEYS_CREDENTIAL";
|
|
83
|
+
export { WORKER_APP_APPEND_ONLY_MAX, WORKER_APP_GRANTS_MAX, WORKER_APP_KEYS_SECRET, WORKER_APP_RESERVED_NAMES, } from './entry-rules.js';
|
|
85
84
|
export declare const WORKER_APP_KEYS_URL_VAR = "KEYS_URL";
|
|
86
|
-
/**
|
|
87
|
-
* Names foundry writes into a Worker app's environment itself, so a
|
|
88
|
-
* declaration may not use them as a binding, secret or var.
|
|
89
|
-
*/
|
|
90
|
-
export declare const WORKER_APP_RESERVED_NAMES: RegExp;
|
|
91
85
|
/** True when the entry needs the org's Postgres database: a Coolify app with `database`, or a Worker app with `workerApp.database`. */
|
|
92
86
|
export declare const entryHasDatabase: (entry: {
|
|
93
87
|
database: boolean;
|
|
@@ -97,10 +91,6 @@ export declare const entryHasDatabase: (entry: {
|
|
|
97
91
|
}) => boolean;
|
|
98
92
|
/** The Hyperdrive binding of a Worker app with `database`. */
|
|
99
93
|
export declare const WORKER_APP_HYPERDRIVE_BINDING = "HYPERDRIVE";
|
|
100
|
-
/** The most tables `database.appendOnly` may name, and the shape of one name (`table` or `schema.table`). */
|
|
101
|
-
export declare const WORKER_APP_APPEND_ONLY_MAX = 100;
|
|
102
|
-
/** The most functions `database.grants` may name, and the shape of one signature. It is spliced into SQL, so nothing else passes. */
|
|
103
|
-
export declare const WORKER_APP_GRANTS_MAX = 100;
|
|
104
94
|
/** Hex characters of the org id's sha256 in a host id. */
|
|
105
95
|
export declare const WORKER_APP_HOST_ID_HASH_LENGTH = 12;
|
|
106
96
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
+
import { WORKER_APP_ENV_NAME as ENV_NAME, WORKER_APP_FUNCTION_SIGNATURE as FUNCTION_SIGNATURE, SECRET_LIKE_NAME as SECRET_NAME, WORKER_APP_TABLE_NAME as TABLE_NAME, WORKER_APP_APPEND_ONLY_MAX, WORKER_APP_GRANTS_MAX, WORKER_APP_KEYS_SECRET, WORKER_APP_RESERVED_NAMES, } from './entry-rules.js';
|
|
2
3
|
import { validateSlug } from './slug.js';
|
|
3
4
|
/** The compatibility flags a Worker app may ask for. */
|
|
4
5
|
export const WORKER_APP_COMPATIBILITY_FLAGS = new Set(['nodejs_compat']);
|
|
@@ -12,24 +13,12 @@ export const WORKER_APP_INSTANCE_TYPES = new Set([
|
|
|
12
13
|
]);
|
|
13
14
|
/** The most instances one container class may scale to. */
|
|
14
15
|
export const WORKER_APP_MAX_INSTANCES = 100;
|
|
15
|
-
|
|
16
|
-
export const WORKER_APP_KEYS_SECRET = 'KEYS_CREDENTIAL';
|
|
16
|
+
export { WORKER_APP_APPEND_ONLY_MAX, WORKER_APP_GRANTS_MAX, WORKER_APP_KEYS_SECRET, WORKER_APP_RESERVED_NAMES, } from './entry-rules.js';
|
|
17
17
|
export const WORKER_APP_KEYS_URL_VAR = 'KEYS_URL';
|
|
18
|
-
/**
|
|
19
|
-
* Names foundry writes into a Worker app's environment itself, so a
|
|
20
|
-
* declaration may not use them as a binding, secret or var.
|
|
21
|
-
*/
|
|
22
|
-
export const WORKER_APP_RESERVED_NAMES = /^(AUTH_.*|KEYS_.*|MCP_.*|HYPERDRIVE)$/;
|
|
23
18
|
/** True when the entry needs the org's Postgres database: a Coolify app with `database`, or a Worker app with `workerApp.database`. */
|
|
24
19
|
export const entryHasDatabase = (entry) => entry.database || Boolean(entry.workerApp?.database);
|
|
25
20
|
/** The Hyperdrive binding of a Worker app with `database`. */
|
|
26
21
|
export const WORKER_APP_HYPERDRIVE_BINDING = 'HYPERDRIVE';
|
|
27
|
-
/** The most tables `database.appendOnly` may name, and the shape of one name (`table` or `schema.table`). */
|
|
28
|
-
export const WORKER_APP_APPEND_ONLY_MAX = 100;
|
|
29
|
-
const TABLE_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,62}(\.[A-Za-z_][A-Za-z0-9_]{0,62})?$/;
|
|
30
|
-
/** The most functions `database.grants` may name, and the shape of one signature. It is spliced into SQL, so nothing else passes. */
|
|
31
|
-
export const WORKER_APP_GRANTS_MAX = 100;
|
|
32
|
-
const FUNCTION_SIGNATURE = /^[A-Za-z_][A-Za-z0-9_]{0,62}(\.[A-Za-z_][A-Za-z0-9_]{0,62})?\(([a-z][a-z0-9_]*( [a-z][a-z0-9_]*)?(, [a-z][a-z0-9_]*( [a-z][a-z0-9_]*)?)*)?\)$/;
|
|
33
22
|
/** The custody Worker's host id shape for a derived (app) host, and its limit. */
|
|
34
23
|
const HOST_ID = /^app-[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
35
24
|
const HOST_ID_MAX_LENGTH = 64;
|
|
@@ -58,12 +47,10 @@ const LABEL = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
|
58
47
|
const RELEASE_ASSET_URL = /^https:\/\/github\.com\/wtfalch\/([A-Za-z0-9._-]+)\/releases\/download\/([A-Za-z0-9._+-]+)\/([A-Za-z0-9._+-]+)$/;
|
|
59
48
|
const SHA256_HEX = /^[0-9a-f]{64}$/;
|
|
60
49
|
const DIGEST = /^sha256:[0-9a-f]{64}$/;
|
|
61
|
-
const ENV_NAME = /^[A-Z][A-Z0-9_]{0,63}$/;
|
|
62
50
|
const CLASS_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
|
|
63
51
|
const MIGRATION_TAG = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
64
52
|
const IMAGE_REPOSITORY = /^[a-z0-9]+([._-][a-z0-9]+)*(:[0-9]+)?(\/[a-z0-9]+([._-][a-z0-9]+)*)+$/;
|
|
65
53
|
const COMPAT_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
66
|
-
const SECRET_NAME = /_(KEY|SECRET|TOKEN|PASSWORD)$/;
|
|
67
54
|
const VAR_MAX_LENGTH = 1000;
|
|
68
55
|
/**
|
|
69
56
|
* Checks an artifact reference: an https URL with no userinfo, query or
|
|
@@ -206,9 +193,9 @@ export function validateEntryWorkerApp(entry, hosting, names) {
|
|
|
206
193
|
if (Object.keys(entry.env).length > 0) {
|
|
207
194
|
return `${at} has no Coolify app, so env does not apply: use workerApp.vars or workerApp.secrets`;
|
|
208
195
|
}
|
|
209
|
-
const unsupported = Object.keys(entry.uses ?? {}).find((use) => use !== 'auth');
|
|
196
|
+
const unsupported = Object.keys(entry.uses ?? {}).find((use) => use !== 'auth' && use !== 'audit');
|
|
210
197
|
if (unsupported)
|
|
211
|
-
return `${at} supports uses.auth only, not uses.${unsupported}`;
|
|
198
|
+
return `${at} supports uses.auth and uses.audit only, not uses.${unsupported}`;
|
|
212
199
|
if (entry.key.length > WORKER_NAME_MAX_LENGTH - WORKER_NAME_FIXED_LENGTH) {
|
|
213
200
|
return `${at} entry key is too long: the deployed Worker's name (an 8-character org hash, the key, and "${WORKER_APP_NAME_SUFFIX}") must fit Cloudflare's ${WORKER_NAME_MAX_LENGTH}-character limit`;
|
|
214
201
|
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A Worker app's database changes (the release's `migrations.json`), pure and shared: the
|
|
3
|
+
* platform apply (`plan/worker-app-database.ts`) and `@wtfalch/foundry/apps` both run them
|
|
4
|
+
* through `runWorkerAppMigrations` with their own SQL runner. No node beyond crypto, no network.
|
|
5
|
+
*/
|
|
6
|
+
/** One migration of a release's `migrations.json`. */
|
|
7
|
+
export interface DatabaseMigration {
|
|
8
|
+
id: string;
|
|
9
|
+
sql: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The SQL a Worker app's database changes need, as the owner `O` of the database: the platform
|
|
13
|
+
* path reaches it through an Access tunnel (`HyperdriveOrigin`), a company's own Postgres by URL
|
|
14
|
+
* (`@wtfalch/foundry/apps`). Every method is idempotent.
|
|
15
|
+
*/
|
|
16
|
+
export interface WorkerAppMigrationRunner<O> {
|
|
17
|
+
/** The migration ids the database's ledger holds, in the order applied. */
|
|
18
|
+
appliedMigrationIds(owner: O): Promise<string[]>;
|
|
19
|
+
/** Runs `migration.sql` and records `migration.id` in the ledger in one transaction. */
|
|
20
|
+
applyMigration(owner: O, migration: DatabaseMigration): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Creates or updates the `runtime.user` role with `runtime.password`, grants it DML on the
|
|
23
|
+
* tables, revokes UPDATE, DELETE and TRUNCATE from it on each `appendOnly` table, and grants
|
|
24
|
+
* it EXECUTE on each `grants` function.
|
|
25
|
+
*/
|
|
26
|
+
ensureRuntimeRole(input: {
|
|
27
|
+
owner: O;
|
|
28
|
+
runtime: {
|
|
29
|
+
user: string;
|
|
30
|
+
password: string;
|
|
31
|
+
};
|
|
32
|
+
appendOnly: string[];
|
|
33
|
+
grants: string[];
|
|
34
|
+
}): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
export declare const WORKER_APP_MIGRATION_TIMEOUT_MS = 300000;
|
|
37
|
+
export declare const MIGRATIONS_ASSET_NAME = "migrations.json";
|
|
38
|
+
/**
|
|
39
|
+
* Reads a release's `migrations.json`. `null` text is an absent file: no migrations. A file that is
|
|
40
|
+
* not a list of `{id, sql}` with unique ids is refused, naming no SQL.
|
|
41
|
+
*/
|
|
42
|
+
export declare function parseMigrations(text: string | null): DatabaseMigration[];
|
|
43
|
+
/**
|
|
44
|
+
* A present `migrations.json` runs as the database owner, so its bytes must be the ones the
|
|
45
|
+
* declaration pinned. No file needs no digest; a file with no declared digest, or a different
|
|
46
|
+
* one, is refused before it is parsed. The message names neither the SQL nor the wanted digest.
|
|
47
|
+
*/
|
|
48
|
+
export declare function verifyMigrationsDigest(text: string | null, declared: string | undefined): void;
|
|
49
|
+
/** The URL of `migrations.json` beside the module: the same release, another file. */
|
|
50
|
+
export declare const migrationsUrl: (artifactUrl: string) => string;
|
|
51
|
+
/**
|
|
52
|
+
* The migrations the database does not hold, in order. The applied ledger must be the first
|
|
53
|
+
* migrations of the file: a missing or reordered one is refused (migrations are append-only).
|
|
54
|
+
*/
|
|
55
|
+
export declare function unappliedDatabaseMigrations(all: readonly DatabaseMigration[], applied: readonly string[]): DatabaseMigration[];
|
|
56
|
+
/** A migration the platform adds for a module (today `uses.audit`: the pinned `@wtfalch/audit` migrations). */
|
|
57
|
+
export interface PlatformMigration extends DatabaseMigration {
|
|
58
|
+
}
|
|
59
|
+
/** A platform migration not run because the app already ships it, and how that was known. */
|
|
60
|
+
export interface SkippedPlatformMigration {
|
|
61
|
+
id: string;
|
|
62
|
+
/** `same id` or `same sql` (a copy under another id), plain words for the log. */
|
|
63
|
+
why: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The platform migrations still to run, in order, and the ones skipped because the release's own list carries
|
|
67
|
+
* them (same id, or the same SQL under another id: Candor ships its own copy of the audit migrations).
|
|
68
|
+
* A platform migration the database's ledger already holds is neither: it ran before. Never applies twice.
|
|
69
|
+
*/
|
|
70
|
+
export declare function pendingPlatformMigrations(platform: readonly PlatformMigration[], own: readonly DatabaseMigration[], applied: readonly string[]): {
|
|
71
|
+
pending: PlatformMigration[];
|
|
72
|
+
skipped: SkippedPlatformMigration[];
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* The build's database changes, shared by the platform apply and `@wtfalch/foundry/apps`:
|
|
76
|
+
* `text` (the release's `migrations.json`, `null` when it has none) is checked against
|
|
77
|
+
* `want.migrationsSha256`, parsed, the unapplied migrations run in order as the owner (each
|
|
78
|
+
* recorded by the runner's ledger), then the runtime role is made true. A failed migration
|
|
79
|
+
* throws; those before it stay applied. Messages start with `at` and name no SQL.
|
|
80
|
+
*/
|
|
81
|
+
export declare function runWorkerAppMigrations<O>(runner: WorkerAppMigrationRunner<O>, owner: O, text: string | null, want: {
|
|
82
|
+
appendOnly: readonly string[];
|
|
83
|
+
grants?: readonly string[];
|
|
84
|
+
migrationsSha256?: string;
|
|
85
|
+
}, runtime: {
|
|
86
|
+
user: string;
|
|
87
|
+
password: string;
|
|
88
|
+
}, opts: {
|
|
89
|
+
at: string;
|
|
90
|
+
call: <T>(label: string, task: () => Promise<T>, ms?: number) => Promise<T>;
|
|
91
|
+
migrationTimeoutMs?: number;
|
|
92
|
+
/** After each migration, with every id applied so far. */
|
|
93
|
+
onApplied?: (done: string[]) => Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Migrations a module needs that the app need not ship (`uses.audit`). They run first, each once, unless the
|
|
96
|
+
* release's own list carries the same one; their ids are not part of the release's append-only check.
|
|
97
|
+
*/
|
|
98
|
+
platform?: readonly PlatformMigration[];
|
|
99
|
+
/** One plain line per skipped platform migration. */
|
|
100
|
+
log?: (line: string) => void;
|
|
101
|
+
}): Promise<{
|
|
102
|
+
applied: string[];
|
|
103
|
+
ran: string[];
|
|
104
|
+
skipped: SkippedPlatformMigration[];
|
|
105
|
+
}>;
|