@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
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `wtfalch/shell`'s `build-app.yml`: the one GitHub Actions workflow that
|
|
3
|
+
* builds and signs a company's native app shell (estate
|
|
4
|
+
* `.plans/2026-10-22-app-shells.md`). Boule now owns the `NativeAppConfig`,
|
|
5
|
+
* the build runs and the company's store keys (estate#262, foundry#951);
|
|
6
|
+
* foundry keeps only two things, both in this file: dispatching the
|
|
7
|
+
* workflow, and the key Boule presents when it asks the host (Archon) to
|
|
8
|
+
* dispatch it.
|
|
9
|
+
*
|
|
10
|
+
* Neither function here is wired into `plan/diff.ts` or `plan/executor.ts`:
|
|
11
|
+
* `dispatchNativeBuild` runs inside Archon's own `/api/native/builds`
|
|
12
|
+
* route, not foundry's apply loop, and `mintNativeBuildKey` is left for the
|
|
13
|
+
* host to call from wherever it writes Boule's env (`executor.ts`'s
|
|
14
|
+
* `coolifyBoule`, the same way it already calls `mintIfAbsent` for
|
|
15
|
+
* `BOULE_OWNER_SEED_SECRET_ENV`) once that wiring has its own review --
|
|
16
|
+
* adding it here would touch every one of this package's Boule-convergence
|
|
17
|
+
* fixtures for one new env var, which is a larger change than this issue
|
|
18
|
+
* asks for.
|
|
19
|
+
*/
|
|
20
|
+
export declare const NATIVE_BUILD_REPO = "wtfalch/shell";
|
|
21
|
+
export declare const NATIVE_BUILD_WORKFLOW_FILE = "build-app.yml";
|
|
22
|
+
export declare const NATIVE_BUILD_WORKFLOW_REF = "main";
|
|
23
|
+
/** Every GitHub call this module makes is cut off after this long. */
|
|
24
|
+
export declare const NATIVE_BUILD_DISPATCH_TIMEOUT_MS = 20000;
|
|
25
|
+
/** A `build-app.yml` dispatch that failed. The text is fixed: it never holds the token or a response body. */
|
|
26
|
+
export declare class NativeBuildDispatchError extends Error {
|
|
27
|
+
readonly status: number | null;
|
|
28
|
+
constructor(status: number | null);
|
|
29
|
+
}
|
|
30
|
+
export interface NativeBuildDispatchDeps {
|
|
31
|
+
/** A GitHub token that may dispatch workflows in {@link NATIVE_BUILD_REPO}. */
|
|
32
|
+
token: string;
|
|
33
|
+
/** Global fetch by default; tests give their own. */
|
|
34
|
+
fetchImpl?: typeof fetch;
|
|
35
|
+
timeoutMs?: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Dispatches `build-app.yml` with exactly `{ runId, origin }` as its inputs:
|
|
39
|
+
* `runId` is the run the caller (Archon, behind its own `/api/native/builds`
|
|
40
|
+
* route) already made, `origin` is the company's Boule address the job
|
|
41
|
+
* reports its status back to and trades its OIDC token for keys at. Foundry
|
|
42
|
+
* keeps no run store of its own any more -- Boule does -- so this is the one
|
|
43
|
+
* thing left for foundry to do with a run: start it.
|
|
44
|
+
*/
|
|
45
|
+
export declare function dispatchNativeBuild(deps: NativeBuildDispatchDeps, run: {
|
|
46
|
+
runId: string;
|
|
47
|
+
origin: string;
|
|
48
|
+
}): Promise<void>;
|
|
49
|
+
/** The env name Boule presents this key under, to Archon's native-build route. */
|
|
50
|
+
export declare const NATIVE_BUILD_KEY_ENV = "NATIVE_BUILD_KEY";
|
|
51
|
+
export declare const NATIVE_BUILD_KEY_BYTES = 32;
|
|
52
|
+
/** The one thing {@link mintNativeBuildKey} needs from Coolify: a live app's env, to check whether it already has a key. */
|
|
53
|
+
export interface NativeBuildKeyEnvPort {
|
|
54
|
+
listEnvs(appId: string): Promise<ReadonlyArray<{
|
|
55
|
+
key: string;
|
|
56
|
+
value: string;
|
|
57
|
+
is_preview: boolean;
|
|
58
|
+
}>>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Mints the per-company key Boule presents to Archon's native-build route
|
|
62
|
+
* (estate#262), the same way every other per-company key in this codebase is
|
|
63
|
+
* minted (estate#207): a random value, written to Boule's env once and never
|
|
64
|
+
* rotated, kept unchanged on every later apply once it is there. Returns
|
|
65
|
+
* `null` when Boule's env already holds one -- the caller then writes
|
|
66
|
+
* nothing, so the live value stands. `onSecret`, when given, is told the
|
|
67
|
+
* minted value so the caller can keep it out of its own logs and error
|
|
68
|
+
* messages.
|
|
69
|
+
*/
|
|
70
|
+
export declare function mintNativeBuildKey(coolify: NativeBuildKeyEnvPort, appId: string, onSecret?: (value: string) => void): Promise<string | null>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* `wtfalch/shell`'s `build-app.yml`: the one GitHub Actions workflow that
|
|
4
|
+
* builds and signs a company's native app shell (estate
|
|
5
|
+
* `.plans/2026-10-22-app-shells.md`). Boule now owns the `NativeAppConfig`,
|
|
6
|
+
* the build runs and the company's store keys (estate#262, foundry#951);
|
|
7
|
+
* foundry keeps only two things, both in this file: dispatching the
|
|
8
|
+
* workflow, and the key Boule presents when it asks the host (Archon) to
|
|
9
|
+
* dispatch it.
|
|
10
|
+
*
|
|
11
|
+
* Neither function here is wired into `plan/diff.ts` or `plan/executor.ts`:
|
|
12
|
+
* `dispatchNativeBuild` runs inside Archon's own `/api/native/builds`
|
|
13
|
+
* route, not foundry's apply loop, and `mintNativeBuildKey` is left for the
|
|
14
|
+
* host to call from wherever it writes Boule's env (`executor.ts`'s
|
|
15
|
+
* `coolifyBoule`, the same way it already calls `mintIfAbsent` for
|
|
16
|
+
* `BOULE_OWNER_SEED_SECRET_ENV`) once that wiring has its own review --
|
|
17
|
+
* adding it here would touch every one of this package's Boule-convergence
|
|
18
|
+
* fixtures for one new env var, which is a larger change than this issue
|
|
19
|
+
* asks for.
|
|
20
|
+
*/
|
|
21
|
+
export const NATIVE_BUILD_REPO = 'wtfalch/shell';
|
|
22
|
+
export const NATIVE_BUILD_WORKFLOW_FILE = 'build-app.yml';
|
|
23
|
+
export const NATIVE_BUILD_WORKFLOW_REF = 'main';
|
|
24
|
+
/** Every GitHub call this module makes is cut off after this long. */
|
|
25
|
+
export const NATIVE_BUILD_DISPATCH_TIMEOUT_MS = 20_000;
|
|
26
|
+
/** A `build-app.yml` dispatch that failed. The text is fixed: it never holds the token or a response body. */
|
|
27
|
+
export class NativeBuildDispatchError extends Error {
|
|
28
|
+
status;
|
|
29
|
+
constructor(status) {
|
|
30
|
+
super(status === null
|
|
31
|
+
? `dispatching ${NATIVE_BUILD_WORKFLOW_FILE} did not answer`
|
|
32
|
+
: `dispatching ${NATIVE_BUILD_WORKFLOW_FILE} failed with status ${status}`);
|
|
33
|
+
this.status = status;
|
|
34
|
+
this.name = 'NativeBuildDispatchError';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Dispatches `build-app.yml` with exactly `{ runId, origin }` as its inputs:
|
|
39
|
+
* `runId` is the run the caller (Archon, behind its own `/api/native/builds`
|
|
40
|
+
* route) already made, `origin` is the company's Boule address the job
|
|
41
|
+
* reports its status back to and trades its OIDC token for keys at. Foundry
|
|
42
|
+
* keeps no run store of its own any more -- Boule does -- so this is the one
|
|
43
|
+
* thing left for foundry to do with a run: start it.
|
|
44
|
+
*/
|
|
45
|
+
export async function dispatchNativeBuild(deps, run) {
|
|
46
|
+
const doFetch = deps.fetchImpl ?? fetch;
|
|
47
|
+
const timeoutMs = deps.timeoutMs ?? NATIVE_BUILD_DISPATCH_TIMEOUT_MS;
|
|
48
|
+
let response;
|
|
49
|
+
try {
|
|
50
|
+
response = await doFetch(`https://api.github.com/repos/${NATIVE_BUILD_REPO}/actions/workflows/${NATIVE_BUILD_WORKFLOW_FILE}/dispatches`, {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
headers: {
|
|
53
|
+
Authorization: `Bearer ${deps.token}`,
|
|
54
|
+
Accept: 'application/vnd.github+json',
|
|
55
|
+
'X-GitHub-Api-Version': '2022-11-28',
|
|
56
|
+
'Content-Type': 'application/json',
|
|
57
|
+
},
|
|
58
|
+
body: JSON.stringify({
|
|
59
|
+
ref: NATIVE_BUILD_WORKFLOW_REF,
|
|
60
|
+
inputs: { runId: run.runId, origin: run.origin },
|
|
61
|
+
}),
|
|
62
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
console.error(`native build: dispatch did not answer (${error instanceof Error ? error.name : 'error'})`);
|
|
67
|
+
throw new NativeBuildDispatchError(null);
|
|
68
|
+
}
|
|
69
|
+
if (!response.ok)
|
|
70
|
+
throw new NativeBuildDispatchError(response.status);
|
|
71
|
+
}
|
|
72
|
+
/** The env name Boule presents this key under, to Archon's native-build route. */
|
|
73
|
+
export const NATIVE_BUILD_KEY_ENV = 'NATIVE_BUILD_KEY';
|
|
74
|
+
export const NATIVE_BUILD_KEY_BYTES = 32;
|
|
75
|
+
/**
|
|
76
|
+
* Mints the per-company key Boule presents to Archon's native-build route
|
|
77
|
+
* (estate#262), the same way every other per-company key in this codebase is
|
|
78
|
+
* minted (estate#207): a random value, written to Boule's env once and never
|
|
79
|
+
* rotated, kept unchanged on every later apply once it is there. Returns
|
|
80
|
+
* `null` when Boule's env already holds one -- the caller then writes
|
|
81
|
+
* nothing, so the live value stands. `onSecret`, when given, is told the
|
|
82
|
+
* minted value so the caller can keep it out of its own logs and error
|
|
83
|
+
* messages.
|
|
84
|
+
*/
|
|
85
|
+
export async function mintNativeBuildKey(coolify, appId, onSecret) {
|
|
86
|
+
const envs = await coolify.listEnvs(appId);
|
|
87
|
+
if (envs.some((e) => e.key === NATIVE_BUILD_KEY_ENV && !e.is_preview))
|
|
88
|
+
return null;
|
|
89
|
+
const value = randomBytes(NATIVE_BUILD_KEY_BYTES).toString('base64url');
|
|
90
|
+
onSecret?.(value);
|
|
91
|
+
return value;
|
|
92
|
+
}
|
package/dist/org.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type WorkerAppConfig } from './worker-app-config.js';
|
|
2
2
|
export type { WorkerAppConfig } from './worker-app-config.js';
|
|
3
|
+
export { AI_ENTRY_PERMISSIONS, FILES_ENTRY_PERMISSIONS, MCP_PATH, ONBOARDING_PATH_MAX_LENGTH, ROOM_STEPS_MAX, ROOM_STEPS_MIN, ROOM_TEXT_MAX, WORKSPACE_ROLE, WORKSPACE_ROLES_MAX, } from './entry-rules.js';
|
|
3
4
|
/**
|
|
4
5
|
* Opaque, minted by foundry when an org is created. Keys the declared org,
|
|
5
6
|
* the applied state, every estate-wide service's id map, and the chat
|
|
@@ -218,6 +219,11 @@ export interface IssuerApp {
|
|
|
218
219
|
* validates is always one Coolify itself accepts.
|
|
219
220
|
*/
|
|
220
221
|
export type HostingBuildPack = 'dockerfile' | 'nixpacks' | 'static' | 'dockercompose';
|
|
222
|
+
/** The company's GitHub App installation: the numeric installation id and the account (user or org login) it is installed on. */
|
|
223
|
+
export interface HostingGithub {
|
|
224
|
+
installationId: number;
|
|
225
|
+
account: string;
|
|
226
|
+
}
|
|
221
227
|
/**
|
|
222
228
|
* The org's hosted apps and what runs beside them (#71, part of #14's
|
|
223
229
|
* adopted/standard/bespoke map) -- distinct from the cms site (`SiteConfig`
|
|
@@ -233,6 +239,12 @@ export type HostingBuildPack = 'dockerfile' | 'nixpacks' | 'static' | 'dockercom
|
|
|
233
239
|
* be true.
|
|
234
240
|
*/
|
|
235
241
|
export interface HostingConfig {
|
|
242
|
+
/**
|
|
243
|
+
* The company's installation of the platform's GitHub App. With it an entry's `repo` may be
|
|
244
|
+
* `<account>/<name>` as well as `wtfalch/<name>`, and the planner makes the company its own Coolify GitHub
|
|
245
|
+
* source (`coolify:github-source`) from the installation id. Absent: only `wtfalch/<name>`.
|
|
246
|
+
*/
|
|
247
|
+
github?: HostingGithub;
|
|
236
248
|
/** The org's apps run on Coolify. */
|
|
237
249
|
enabled: boolean;
|
|
238
250
|
/** Served on `DeclaredOrg.domain` (and its Cloudflare zone managed) instead of `<slug>.oikos.host` (`../slug.ts`). */
|
|
@@ -289,7 +301,7 @@ export type AccessRule = {
|
|
|
289
301
|
/** The key of the entry that is today's one app: the Coolify app named `<slug>`. */
|
|
290
302
|
export declare const APP_ENTRY_KEY = "app";
|
|
291
303
|
/** Why a validator refused. `code` is stable and never reworded; `message` is for people. */
|
|
292
|
-
export type OrgRefusalCode = 'hosting_tunnel_needs_hosting' | 'issuer_app_name_missing' | 'issuer_app_name_not_unique' | 'issuer_app_kind_unknown' | 'issuer_app_name_reserved_agora' | 'issuer_app_name_reserved_boule' | 'hosting_needs_entry' | 'hosting_main_count' | 'entry_key_not_unique' | 'ai_webhook_path_not_unique' | 'worker_route_not_unique' | 'database_not_unique' | 'access_hostname_not_unique' | 'access_hostname_invalid' | 'access_needs_hosting' | 'access_kind_unknown' | 'access_service_token_name_missing' | 'access_hostname_locked' | 'access_hostname_not_served' | 'gate_limit_invalid' | 'hosting_repo_invalid' | 'gate_needs_domain' | 'gate_key_invalid' | 'gate_key_not_unique' | 'gate_needs_hostname' | 'gate_hostname_not_entry_hostname' | 'gate_hostname_held_twice' | 'gate_hostname_locked' | 'gate_limit_exceeded' | 'wildcard_needs_domain' | 'wildcard_held_twice' | 'hostnames_need_domain' | 'hostname_needed' | 'hostname_invalid' | 'hostname_not_unique' | 'hostname_locked' | 'entry_key_invalid' | 'entry_key_reserved' | 'entry_repo_invalid' | 'entry_folder_invalid' | 'entry_branch_empty' | 'entry_build_pack_unknown' | 'entry_build_pack_unavailable' | 'entry_port_invalid' | 'entry_health_path_invalid' | 'entry_capabilities_invalid' | 'entry_database_needs_hosting' | 'blue_green_needs_hostname' | 'env_name_empty' | 'env_name_reserved' | 'env_source_platform_mail_key' | 'env_source_unknown' | 'env_shared_secret_name_invalid' | 'env_held_secret_name_mismatch' | 'env_held_secret_name_invalid' | 'env_looks_like_secret' | 'builtin_app_invalid' | 'blue_green_not_object' | 'blue_green_steps_length' | 'blue_green_steps_range' | 'blue_green_steps_order' | 'blue_green_steps_end' | 'blue_green_hold_invalid' | 'volumes_not_list' | 'volumes_too_many' | 'volume_name_invalid' | 'volume_name_logs' | 'volume_name_not_unique' | 'volume_mount_path_invalid' | 'volume_mount_path_too_long' | 'volume_mount_path_log_dir' | 'volume_mount_path_forbidden' | 'volume_mount_path_not_unique' | 'auth_needs_hosting' | 'auth_users_invalid' | 'auth_registration_invalid' | 'registration_open_needs_customers' | 'auth_replaces_broker_entry_invalid' | 'auth_replaces_broker_entry_owned' | 'auth_needs_exact_hostname' | 'mcp_needs_open_customers' | 'mcp_path_invalid' | 'mcp_onboarding_path_invalid' | 'auth_sign_in_invalid' | 'email_code_needs_customers' | 'auth_room_invalid' | 'auth_room_needs_customers' | 'auth_room_not_unique' | 'client_name_taken' | 'ai_needs_hosting' | 'ai_offerings_invalid' | 'ai_permissions_invalid' | 'ai_webhook_path_invalid' | 'ai_webhook_needs_exact_hostname' | 'ai_env_clash' | 'files_needs_hosting' | 'files_collections_invalid' | 'files_permissions_invalid' | 'files_share_host_invalid' | 'files_share_host_needs_domain' | 'files_env_clash' | 'worker_needs_hosting' | 'worker_needs_repo' | 'worker_key_too_long' | 'worker_artifact_invalid' | 'worker_route_invalid' | 'worker_route_off_domain' | 'worker_rate_limit_name_missing' | 'worker_rate_limit_namespace_missing' | 'worker_rate_limit_invalid' | 'worker_rate_limit_period_invalid' | 'worker_app_invalid' | 'edge_not_true' | 'edge_needs_hosting' | 'edge_needs_domain' | 'edge_env_clash' | 'customers_invalid' | 'customers_sign_up_needs_enabled' | 'registration_open_needs_sign_up';
|
|
304
|
+
export type OrgRefusalCode = 'hosting_tunnel_needs_hosting' | 'issuer_app_name_missing' | 'issuer_app_name_not_unique' | 'issuer_app_kind_unknown' | 'issuer_app_name_reserved_agora' | 'issuer_app_name_reserved_boule' | 'issuer_app_name_reserved_kosmos' | 'hosting_needs_entry' | 'hosting_main_count' | 'entry_key_not_unique' | 'ai_webhook_path_not_unique' | 'worker_route_not_unique' | 'database_not_unique' | 'access_hostname_not_unique' | 'access_hostname_invalid' | 'access_needs_hosting' | 'access_kind_unknown' | 'access_service_token_name_missing' | 'access_hostname_locked' | 'access_hostname_not_served' | 'gate_limit_invalid' | 'hosting_repo_invalid' | 'hosting_github_invalid' | 'gate_needs_domain' | 'gate_key_invalid' | 'gate_key_not_unique' | 'gate_needs_hostname' | 'gate_hostname_not_entry_hostname' | 'gate_hostname_held_twice' | 'gate_hostname_locked' | 'gate_limit_exceeded' | 'wildcard_needs_domain' | 'wildcard_held_twice' | 'hostnames_need_domain' | 'hostname_needed' | 'hostname_invalid' | 'hostname_not_unique' | 'hostname_locked' | 'hosted_name_invalid' | 'hosted_name_not_unique' | 'hosted_name_worker_app' | 'entry_workspace_invalid' | 'entry_workspace_unsupported' | 'entry_live_needs_workspace' | 'entry_live_commit_invalid' | 'gate_key_taken_by_workspace' | 'gate_key_taken_by_private_page' | 'private_page_invalid' | 'private_page_path_invalid' | 'private_page_duplicate' | 'private_page_limit' | 'private_page_needs_hosting' | 'private_page_roles_invalid' | 'private_page_people_invalid' | 'entry_key_invalid' | 'entry_key_reserved' | 'entry_repo_invalid' | 'entry_folder_invalid' | 'entry_branch_empty' | 'entry_build_pack_unknown' | 'entry_build_pack_unavailable' | 'entry_port_invalid' | 'entry_health_path_invalid' | 'entry_capabilities_invalid' | 'entry_database_needs_hosting' | 'blue_green_needs_hostname' | 'env_name_empty' | 'env_name_reserved' | 'env_source_platform_mail_key' | 'env_source_unknown' | 'env_shared_secret_name_invalid' | 'env_held_secret_name_mismatch' | 'env_held_secret_name_invalid' | 'env_looks_like_secret' | 'builtin_app_invalid' | 'blue_green_not_object' | 'blue_green_steps_length' | 'blue_green_steps_range' | 'blue_green_steps_order' | 'blue_green_steps_end' | 'blue_green_hold_invalid' | 'blue_green_advance_invalid' | 'blue_green_min_requests_invalid' | 'blue_green_error_margin_invalid' | 'blue_green_staff_first_invalid' | 'volumes_not_list' | 'volumes_too_many' | 'volume_name_invalid' | 'volume_name_logs' | 'volume_name_not_unique' | 'volume_mount_path_invalid' | 'volume_mount_path_too_long' | 'volume_mount_path_log_dir' | 'volume_mount_path_forbidden' | 'volume_mount_path_not_unique' | 'auth_needs_hosting' | 'auth_users_invalid' | 'auth_registration_invalid' | 'registration_open_needs_customers' | 'auth_replaces_broker_entry_invalid' | 'auth_replaces_broker_entry_owned' | 'auth_needs_exact_hostname' | 'mcp_needs_open_customers' | 'mcp_path_invalid' | 'mcp_onboarding_path_invalid' | 'auth_sign_in_invalid' | 'email_code_needs_customers' | 'auth_room_invalid' | 'auth_room_needs_customers' | 'auth_room_not_unique' | 'client_name_taken' | 'workspaces_needs_customers' | 'workspaces_needs_server' | 'workspaces_roles_invalid' | 'workspaces_role_reserved' | 'workspaces_invite_path_invalid' | 'workspaces_env_clash' | 'ai_needs_hosting' | 'ai_offerings_invalid' | 'ai_permissions_invalid' | 'ai_webhook_path_invalid' | 'ai_webhook_needs_exact_hostname' | 'ai_env_clash' | 'files_needs_hosting' | 'files_collections_invalid' | 'files_permissions_invalid' | 'files_share_host_invalid' | 'files_share_host_needs_domain' | 'files_env_clash' | 'worker_needs_hosting' | 'worker_needs_repo' | 'worker_needs_own_repo' | 'worker_key_too_long' | 'worker_artifact_invalid' | 'worker_route_invalid' | 'worker_route_off_domain' | 'worker_rate_limit_name_missing' | 'worker_rate_limit_namespace_missing' | 'worker_rate_limit_invalid' | 'worker_rate_limit_period_invalid' | 'worker_app_invalid' | 'edge_not_true' | 'edge_needs_hosting' | 'edge_needs_domain' | 'edge_env_clash' | 'mail_not_true' | 'mail_needs_hosting' | 'mail_env_clash' | 'jobs_not_true' | 'jobs_needs_hosting' | 'jobs_env_clash' | 'customer_grants_not_true' | 'customer_grants_needs_customers' | 'customer_grants_env_clash' | 'repo_use_invalid' | 'repo_use_needs_repo' | 'repo_use_env_clash' | 'audit_not_true' | 'audit_needs_hosting' | 'audit_needs_worker_database' | 'customers_invalid' | 'customers_sign_up_needs_enabled' | 'registration_open_needs_sign_up';
|
|
293
305
|
/**
|
|
294
306
|
* One refusal: a stable `code`, the dotted `path` into {@link DeclaredOrg} it is about
|
|
295
307
|
* (`hosting.entries.terminal.uses.auth.registration`) and the sentence for people.
|
|
@@ -322,6 +334,11 @@ export interface HostingEntry {
|
|
|
322
334
|
buildPack: HostingBuildPack;
|
|
323
335
|
/** The port the app listens on. `null` is Coolify's default. */
|
|
324
336
|
port: number | null;
|
|
337
|
+
/**
|
|
338
|
+
* The app's live address on the platform's apps domain: `<hostedName>.companyincluded.app`. A
|
|
339
|
+
* label {@link hostedLabelRefusal} accepts; unique within the org (the host checks it across orgs).
|
|
340
|
+
*/
|
|
341
|
+
hostedName?: string;
|
|
325
342
|
/**
|
|
326
343
|
* The org's main app: served at the org's main address (`<slug>.oikos.host`, or the domain's
|
|
327
344
|
* apex), whatever its key. An entry keyed {@link APP_ENTRY_KEY} with `main` unset is main.
|
|
@@ -374,8 +391,8 @@ export interface HostingEntry {
|
|
|
374
391
|
* F8: a Cloudflare Worker foundry deploys from this entry's own repo,
|
|
375
392
|
* beside the app, on the org's own zone. Only our own repos may use this
|
|
376
393
|
* (#318: outside customers need Workers for Platforms, not built yet), so
|
|
377
|
-
* `validateEntryWorker` refuses it unless `repo` is set
|
|
378
|
-
*
|
|
394
|
+
* `validateEntryWorker` refuses it unless `repo` is set and under `wtfalch`
|
|
395
|
+
* ({@link REPO}; a company's own GitHub account is refused) and the route's zone
|
|
379
396
|
* is the org's own domain.
|
|
380
397
|
*/
|
|
381
398
|
worker?: WorkerConfig;
|
|
@@ -390,7 +407,63 @@ export interface HostingEntry {
|
|
|
390
407
|
* blue and a green copy behind a load balancer on every server it manages, and the tunnel routes to the balancer.
|
|
391
408
|
*/
|
|
392
409
|
blueGreen?: BlueGreenConfig;
|
|
410
|
+
/**
|
|
411
|
+
* A private workspace for the app: it runs at `workspaceHost(slug, key)` behind a Cloudflare Access gate that
|
|
412
|
+
* lets in the company's people and `testers`. A server entry's workspace is the blue/green stage machinery
|
|
413
|
+
* (its own empty database, the stage mail sink, the stage guards) without colors; a `workerApp` entry's is a
|
|
414
|
+
* second Worker script `<slug>-<key>-work`. See `plan/workspace.ts`. Not combined with `blueGreen`.
|
|
415
|
+
*/
|
|
416
|
+
workspace?: EntryWorkspace;
|
|
417
|
+
/**
|
|
418
|
+
* Whether the app is live. Absent means true. `false` plans no public hostname, DNS record, live app or live
|
|
419
|
+
* Worker: only the workspace exists, so it needs `workspace`. Setting it to true makes the live app from the
|
|
420
|
+
* commit the workspace runs, with its own database; the workspace stays.
|
|
421
|
+
*/
|
|
422
|
+
live?: boolean;
|
|
423
|
+
/**
|
|
424
|
+
* The 40 character commit the live app runs, set by a promote. Needs `workspace` and a server (repo) entry.
|
|
425
|
+
* When set, the live app is made from it and later moved to it (`git_commit_sha` patched, then deployed),
|
|
426
|
+
* whatever the workspace runs. Absent: the app is made from the workspace's commit and stays there. It may be
|
|
427
|
+
* a commit the workspace never ran (a rollback).
|
|
428
|
+
*/
|
|
429
|
+
liveCommit?: string;
|
|
430
|
+
/**
|
|
431
|
+
* Parts of the app only the company's people may open, each gated by a path-scoped Cloudflare Access
|
|
432
|
+
* application on `<host><path>`, on the live hosts and (with a `workspace`) on the workspace host. See
|
|
433
|
+
* `plan/private-pages.ts`.
|
|
434
|
+
*/
|
|
435
|
+
privatePages?: PrivatePage[];
|
|
436
|
+
}
|
|
437
|
+
/** One private page of an entry. */
|
|
438
|
+
export interface PrivatePage {
|
|
439
|
+
/** Starts with `/`; letters, digits and `. _ ~ - /`; no query, no trailing slash, not `/` itself. */
|
|
440
|
+
path: string;
|
|
441
|
+
/** The company's role ids that may open the page. Foundry cannot resolve roles; see `people`. */
|
|
442
|
+
roles: string[];
|
|
443
|
+
/**
|
|
444
|
+
* The company people holding `roles`, as email addresses, resolved by the host that declares the org (as
|
|
445
|
+
* `workspace.testers` is supplied). The gate admits the owners plus these. Absent: the owners only.
|
|
446
|
+
*/
|
|
447
|
+
people?: string[];
|
|
448
|
+
}
|
|
449
|
+
export declare const MAX_PRIVATE_PAGES = 20;
|
|
450
|
+
export declare const MAX_PRIVATE_PAGE_ROLES = 50;
|
|
451
|
+
export declare const MAX_PRIVATE_PAGE_PEOPLE = 200;
|
|
452
|
+
export declare const PRIVATE_PAGE_PATH: RegExp;
|
|
453
|
+
/** The keys of the Access gates private pages get: `pp-` (live) or `wp-` (workspace) and 16 hex characters. */
|
|
454
|
+
export declare const PRIVATE_PAGE_GATE_KEY: RegExp;
|
|
455
|
+
/** A full git commit: 40 lowercase hex characters. */
|
|
456
|
+
export declare const FULL_COMMIT_SHA: RegExp;
|
|
457
|
+
/** The people outside the company who may open an entry's workspace. */
|
|
458
|
+
export interface EntryWorkspace {
|
|
459
|
+
/** Email addresses, at most {@link MAX_WORKSPACE_TESTERS}, distinct when lowercased. */
|
|
460
|
+
testers: string[];
|
|
393
461
|
}
|
|
462
|
+
export declare const MAX_WORKSPACE_TESTERS = 50;
|
|
463
|
+
/** An entry is live unless it says `live: false`. */
|
|
464
|
+
export declare const isLiveEntry: (entry: Pick<HostingEntry, "live">) => boolean;
|
|
465
|
+
/** Trimmed, lowercased and distinct testers, in the order first seen. The planner and hosts read testers through this. */
|
|
466
|
+
export declare function normalizeTesters(testers: readonly string[]): string[];
|
|
394
467
|
/**
|
|
395
468
|
* `boule` and `agora` on a company: the built-in apps foundry runs for every company (`<slug>-boule`,
|
|
396
469
|
* `<slug>-agora`). Only blue/green is declared here; absent means off. Optional so every existing literal and
|
|
@@ -399,11 +472,46 @@ export interface HostingEntry {
|
|
|
399
472
|
export interface OrgBuiltinApp {
|
|
400
473
|
blueGreen?: BlueGreenConfig;
|
|
401
474
|
}
|
|
475
|
+
/**
|
|
476
|
+
* The company's Boule. `apps` (F3, F5, F7) turns on the managed-apps platform keys: Boule installs and runs apps
|
|
477
|
+
* for the company, so foundry gives it an edge key that may deploy the company's own Workers
|
|
478
|
+
* (`plan/entry-edge-key.ts`), a registrar key at the sign-in broker (`plan/broker-registrar.ts`) and a registrar key
|
|
479
|
+
* at the signed-records service (`plan/keys-registrar.ts`). Absent is off. Boule's apps are not in `hosting.entries`,
|
|
480
|
+
* so this switch is how the plan knows the company has any.
|
|
481
|
+
*/
|
|
482
|
+
export interface BouleApp extends OrgBuiltinApp {
|
|
483
|
+
apps?: boolean;
|
|
484
|
+
}
|
|
485
|
+
/** True while the company's Boule runs apps (`org.boule.apps`). */
|
|
486
|
+
export declare const appsOn: (org: Pick<DeclaredOrg, "boule">) => boolean;
|
|
487
|
+
/**
|
|
488
|
+
* The company's kosmos: its own creative workspace (canvas, libraries, photos, pages) that drives the
|
|
489
|
+
* frontend of its apps. Unlike Boule and Agora, which every company runs, kosmos is set up only when the
|
|
490
|
+
* company asks (William, 2026-10-22) -- absent, or `enabled` absent or `false`, plans nothing for it.
|
|
491
|
+
* `enabled: true` plans its ZITADEL client, its database and its live and idle copies; turning it back off
|
|
492
|
+
* parks the app but keeps the database, the same rule every other switched-off service follows.
|
|
493
|
+
*/
|
|
494
|
+
export interface KosmosApp extends OrgBuiltinApp {
|
|
495
|
+
enabled?: boolean;
|
|
496
|
+
}
|
|
497
|
+
/** True while the company's kosmos is turned on (`org.kosmos.enabled`). */
|
|
498
|
+
export declare const kosmosOn: (org: Pick<DeclaredOrg, "kosmos">) => boolean;
|
|
402
499
|
/** The traffic steps (percent to the new color) and the hold at each step. Both default in `plan/blue-green.ts`. */
|
|
403
500
|
export interface BlueGreenConfig {
|
|
404
501
|
/** Ascending, each 1..100, ending at 100. */
|
|
405
502
|
steps?: number[];
|
|
406
503
|
stepHoldMinutes?: number;
|
|
504
|
+
/**
|
|
505
|
+
* How a step is left. `signal` (default): the hold passed and the error rate matches the old color's.
|
|
506
|
+
* `time`: the hold passed and the error rate is not failing. `approval`: a person approves each step.
|
|
507
|
+
*/
|
|
508
|
+
advance?: 'time' | 'signal' | 'approval';
|
|
509
|
+
/** Requests the new color needs before its error rate counts (whole number 1..100000). Default 20. */
|
|
510
|
+
minRequests?: number;
|
|
511
|
+
/** The new color matches the old while its error rate is at most the old plus this (0..1). Default 0.02. */
|
|
512
|
+
errorMargin?: number;
|
|
513
|
+
/** A promote deploys the idle color and holds it at weight 0 for staff until an `open` action. Default false. */
|
|
514
|
+
staffFirst?: boolean;
|
|
407
515
|
}
|
|
408
516
|
/** One named volume on a hosting entry's app. */
|
|
409
517
|
export interface EntryVolume {
|
|
@@ -498,6 +606,16 @@ export interface EntryAuth {
|
|
|
498
606
|
* `users: 'customers'`.
|
|
499
607
|
*/
|
|
500
608
|
signIn?: 'password' | 'email-code';
|
|
609
|
+
/**
|
|
610
|
+
* The entry's own customers get workspaces in the broker: they make one, invite people by email and give
|
|
611
|
+
* each member one of `roles`. The first role is the owner role. `invitePath` is the page on the entry's
|
|
612
|
+
* host the invitation mail links to (`<host><invitePath>?token=`). Needs `users: 'customers'` and an
|
|
613
|
+
* entry that runs as a server. The entry gets `WORKSPACES_URL` and `WORKSPACES_API_KEY`.
|
|
614
|
+
*/
|
|
615
|
+
workspaces?: {
|
|
616
|
+
roles: string[];
|
|
617
|
+
invitePath: string;
|
|
618
|
+
};
|
|
501
619
|
/**
|
|
502
620
|
* The left-half text of the customers' sign-in window. Written on the
|
|
503
621
|
* customers organisation as metadata `wtfalch.room` (JSON, keys in the
|
|
@@ -506,6 +624,8 @@ export interface EntryAuth {
|
|
|
506
624
|
*/
|
|
507
625
|
room?: EntryAuthRoom;
|
|
508
626
|
}
|
|
627
|
+
/** The env names `uses.auth.workspaces` writes; `env` may not name them. */
|
|
628
|
+
export declare const WORKSPACES_ENTRY_ENV_NAMES: readonly ["WORKSPACES_URL", "WORKSPACES_API_KEY"];
|
|
509
629
|
export interface EntryAuthRoom {
|
|
510
630
|
name: string;
|
|
511
631
|
headline: string;
|
|
@@ -514,20 +634,6 @@ export interface EntryAuthRoom {
|
|
|
514
634
|
description?: string;
|
|
515
635
|
steps?: number;
|
|
516
636
|
}
|
|
517
|
-
/** Longest value of each `uses.auth.room` text field. */
|
|
518
|
-
export declare const ROOM_TEXT_MAX: {
|
|
519
|
-
readonly name: 40;
|
|
520
|
-
readonly headline: 120;
|
|
521
|
-
readonly line: 200;
|
|
522
|
-
readonly title: 60;
|
|
523
|
-
readonly description: 200;
|
|
524
|
-
};
|
|
525
|
-
export declare const ROOM_STEPS_MIN = 2;
|
|
526
|
-
export declare const ROOM_STEPS_MAX = 9;
|
|
527
|
-
/** `uses.auth.mcp.onboardingPath`: absolute, no query, no fragment, no dot segments. */
|
|
528
|
-
export declare const ONBOARDING_PATH_MAX_LENGTH = 200;
|
|
529
|
-
/** The MCP endpoint path: absolute, plain characters, no dot segments, no query. */
|
|
530
|
-
export declare const MCP_PATH: RegExp;
|
|
531
637
|
/**
|
|
532
638
|
* AI for one entry: a key below the org's own ai key, the `AI_*` env and,
|
|
533
639
|
* with `webhookPath`, the ai webhook. `offerings` is what the app may call,
|
|
@@ -540,8 +646,6 @@ export interface EntryAi {
|
|
|
540
646
|
permissions?: string[];
|
|
541
647
|
webhookPath?: string;
|
|
542
648
|
}
|
|
543
|
-
/** What an entry's ai key may hold: the most the org's own key holds. */
|
|
544
|
-
export declare const AI_ENTRY_PERMISSIONS: readonly ["ai.offerings:invoke", "ai.runs:create"];
|
|
545
649
|
/** The env names `uses.ai` writes; `env` may not name them. */
|
|
546
650
|
export declare const AI_ENTRY_ENV_NAMES: readonly ["AI_URL", "AI_ORGANISATION_ID", "AI_API_KEY", "AI_WEBHOOK_SECRET", "AI_OFFERINGS_JSON"];
|
|
547
651
|
/**
|
|
@@ -559,8 +663,6 @@ export interface EntryFiles {
|
|
|
559
663
|
permissions?: string[];
|
|
560
664
|
shareHost?: boolean;
|
|
561
665
|
}
|
|
562
|
-
/** What an entry's files key may hold: read and write on its collections, and the most the org's own key holds besides minting. */
|
|
563
|
-
export declare const FILES_ENTRY_PERMISSIONS: readonly ["files.collections:read", "files.files:read", "files.files:download", "files.files:upload", "files.files:replace", "files.files:delete"];
|
|
564
666
|
/** The env names `uses.files` always writes, besides one `FILES_COLLECTION_<NAME>_ID` per collection. */
|
|
565
667
|
export declare const FILES_ENTRY_ENV_NAMES: readonly ["FILES_URL", "FILES_ORGANISATION_ID", "FILES_API_KEY"];
|
|
566
668
|
export declare const filesCollectionEnvName: (name: string) => string;
|
|
@@ -576,9 +678,49 @@ export interface HostingEntryUses {
|
|
|
576
678
|
* org `domain`.
|
|
577
679
|
*/
|
|
578
680
|
edge?: true;
|
|
681
|
+
/**
|
|
682
|
+
* The entry sends mail from the company's mail domain: it gets the company's
|
|
683
|
+
* Lettermint token and `MAIL_FROM`, as the main app does. In a workspace the
|
|
684
|
+
* stage gets the mail sink's env only (`stageMailEnv`).
|
|
685
|
+
*/
|
|
686
|
+
mail?: true;
|
|
687
|
+
/**
|
|
688
|
+
* The entry is a project of its own in the jobs scheduler and gets
|
|
689
|
+
* `JOBS_SCHEDULER_URL` (the scheduler's public origin), `JOBS_SIGNING_SECRET`
|
|
690
|
+
* and `JOBS_SYNC_KEY` (`plan/entry-jobs.ts`). Blocked, not planned, until the
|
|
691
|
+
* scheduler's public route (`plan/own-jobs-route.ts`) is recorded: the owner
|
|
692
|
+
* company's for a company on shared services, the company's own otherwise.
|
|
693
|
+
* A workspace gets none of the three.
|
|
694
|
+
*/
|
|
695
|
+
jobs?: true;
|
|
696
|
+
/**
|
|
697
|
+
* The app keeps a tamper-evident audit log (`@wtfalch/audit`). A Worker app with a database: the append-only
|
|
698
|
+
* tables and the two chain functions are derived (`audit/ledger-set.ts`), never listed by hand, and the
|
|
699
|
+
* platform's sealing service signs and anchors the ledger on a schedule with a key the app never holds
|
|
700
|
+
* (`plan/entry-audit.ts`, `audit/`). The erase functions are not granted.
|
|
701
|
+
*/
|
|
702
|
+
audit?: true;
|
|
703
|
+
/**
|
|
704
|
+
* The app implements Boule's customer-grants routes under `/api/customer-grants`, called by a machine
|
|
705
|
+
* (Boule), not a person. F11 only lets that path through a gated host (`entryMachinePaths`); F13 builds
|
|
706
|
+
* the rest (the credential, the app env and Boule's entry).
|
|
707
|
+
*/
|
|
708
|
+
customerGrants?: true;
|
|
709
|
+
/**
|
|
710
|
+
* F12: the entry gets credentials for its own `repo`: a GitHub deploy key made for it (write only with
|
|
711
|
+
* `access: 'write'`), delivered as `GIT_REPO_URL` (`git@github.com:<owner>/<name>.git`) and `GIT_SSH_KEY`
|
|
712
|
+
* (`plan/entry-repo-key.ts`). Needs `repo`. Removed with the entry or the flag; a workspace copy gets none.
|
|
713
|
+
*/
|
|
714
|
+
repo?: {
|
|
715
|
+
access: 'read' | 'write';
|
|
716
|
+
};
|
|
579
717
|
}
|
|
580
718
|
/** The env names `uses.edge` writes; `env` may not name them (#317). */
|
|
581
719
|
export declare const EDGE_ENTRY_ENV_NAMES: readonly ["EDGE_URL", "EDGE_API_KEY"];
|
|
720
|
+
/** The env names `uses.mail` writes; `env` may not name them. */
|
|
721
|
+
export declare const MAIL_ENTRY_ENV_NAMES: readonly ["LETTERMINT_API_TOKEN", "MAIL_FROM"];
|
|
722
|
+
/** The env names `uses.jobs` writes; `env` may not name them. */
|
|
723
|
+
export declare const JOBS_ENTRY_ENV_NAMES: readonly ["JOBS_SCHEDULER_URL", "JOBS_SIGNING_SECRET", "JOBS_SYNC_KEY"];
|
|
582
724
|
/**
|
|
583
725
|
* A plain string is pushed as it is, so `validateHosting` refuses one that
|
|
584
726
|
* looks like a secret. `{ from }` names a value the plan already mints.
|
|
@@ -661,10 +803,26 @@ export interface HostingNames {
|
|
|
661
803
|
export declare function normalizeHostingRepos(repos: readonly string[] | undefined): string[];
|
|
662
804
|
/** {@link validateHosting} with the code and path of the first refusal. */
|
|
663
805
|
export declare function refuseHosting(hosting: HostingConfig, names?: HostingNames): OrgRefusal | null;
|
|
806
|
+
/**
|
|
807
|
+
* The company's GitHub config when `repo` is under its account, else `undefined`: such an entry is built
|
|
808
|
+
* through the company's own Coolify source, any other through the platform's. Read it only through this.
|
|
809
|
+
*/
|
|
810
|
+
export declare function companyGithubFor(hosting: Pick<HostingConfig, 'github'>, repo: string | null): HostingGithub | undefined;
|
|
664
811
|
/** `blueGreen`: steps ascending, each a whole number 1..100, the last 100; a hold of 1..1440 minutes. */
|
|
665
812
|
export declare function validateBlueGreen(value: unknown, at: string): string | null;
|
|
666
|
-
/**
|
|
667
|
-
|
|
813
|
+
/**
|
|
814
|
+
* {@link refuseBlueGreen} for the `blueGreen` of the company's Boule, Agora and kosmos; the same codes.
|
|
815
|
+
* Also refuses an `issuerApps` entry named `kosmos` while kosmos is on -- the same reservation
|
|
816
|
+
* {@link refuseHosting}'s own loop already gives Agora and Boule, but kosmos is opt-in, so it is checked here
|
|
817
|
+
* instead, the same way {@link validateSite} reserves `cms` only while `site.enabled` is true.
|
|
818
|
+
*/
|
|
819
|
+
export declare function refuseBuiltinBlueGreen(org: Pick<DeclaredOrg, 'boule' | 'agora' | 'kosmos' | 'hosting'>): OrgRefusal | null;
|
|
820
|
+
/** The env names `uses.repo` writes; `env` may not name them. */
|
|
821
|
+
export declare const REPO_ENTRY_ENV_NAMES: readonly ["GIT_REPO_URL", "GIT_SSH_KEY"];
|
|
822
|
+
/** The env name `uses.customerGrants` writes; `env` may not name it. */
|
|
823
|
+
export declare const CUSTOMER_GRANTS_ENTRY_ENV_NAMES: readonly ["CUSTOMER_GRANTS_CREDENTIAL"];
|
|
824
|
+
/** The platform zone new app addresses (`<hostedName>.companyincluded.app`) and every workspace live in. */
|
|
825
|
+
export declare const APPS_DOMAIN = "companyincluded.app";
|
|
668
826
|
export declare function validateDomain(domain: string): string | null;
|
|
669
827
|
/**
|
|
670
828
|
* A broker entry name foundry writes itself: Archon's, and any company's Boule.
|
|
@@ -1082,9 +1240,11 @@ export interface DeclaredOrg {
|
|
|
1082
1240
|
/** Absent means `{ inApp: true }`. Optional so every existing literal and fixture compiles unchanged. */
|
|
1083
1241
|
signIn?: SignInConfig;
|
|
1084
1242
|
/** The company's Boule. Absent means no blue/green. */
|
|
1085
|
-
boule?:
|
|
1243
|
+
boule?: BouleApp;
|
|
1086
1244
|
/** The company's Agora, a static app: its release moves on hard fails and time only. Absent means no blue/green. */
|
|
1087
1245
|
agora?: OrgBuiltinApp;
|
|
1246
|
+
/** The company's kosmos. Absent or `enabled: false` means it is not set up (2026-10-22). */
|
|
1247
|
+
kosmos?: KosmosApp;
|
|
1088
1248
|
/** Absent means `{ enabled: false, signUp: false }`. Optional so every existing literal and fixture compiles unchanged. */
|
|
1089
1249
|
customers?: CustomersConfig;
|
|
1090
1250
|
/** Parts of this company held on their own version. Absent or null follows the platform. Ignored for the owner company. */
|