@wtfalch/foundry 0.34.0 → 0.35.2
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/bootstrap.d.ts +1 -1
- package/dist/bootstrap/bootstrap.js +49 -11
- package/dist/bootstrap/declare.d.ts +12 -5
- package/dist/bootstrap/declare.js +33 -18
- package/dist/bootstrap/versions.d.ts +20 -0
- package/dist/bootstrap/versions.js +46 -0
- package/dist/calls-sfu.js +3 -3
- package/dist/index.d.ts +9 -4
- package/dist/index.js +5 -2
- package/dist/migrations/0053_heartbeats_provider.sql +9 -0
- package/dist/migrations/0053_org_version_pin.sql +6 -0
- package/dist/org.d.ts +60 -14
- package/dist/org.js +118 -28
- package/dist/plan/backup-gate.d.ts +93 -0
- package/dist/plan/backup-gate.js +261 -0
- package/dist/plan/broker-entries.d.ts +9 -1
- package/dist/plan/broker-entries.js +20 -3
- package/dist/plan/build-record.d.ts +56 -0
- package/dist/plan/build-record.js +109 -0
- package/dist/plan/calls-matrix.js +3 -3
- package/dist/plan/cloudflared-connector.js +2 -2
- package/dist/plan/company-backups.d.ts +31 -0
- package/dist/plan/company-backups.js +101 -0
- package/dist/plan/deploy-health.d.ts +12 -2
- package/dist/plan/deploy-health.js +3 -1
- package/dist/plan/destinations.d.ts +73 -0
- package/dist/plan/destinations.js +217 -0
- package/dist/plan/diff.d.ts +17 -8
- package/dist/plan/diff.js +131 -131
- package/dist/plan/edge-access.d.ts +15 -0
- package/dist/plan/edge-access.js +21 -2
- package/dist/plan/executor.d.ts +166 -7
- package/dist/plan/executor.js +547 -106
- package/dist/plan/health-targets.d.ts +1 -3
- package/dist/plan/health-targets.js +36 -36
- package/dist/plan/held-key-refs.d.ts +5 -0
- package/dist/plan/held-key-refs.js +5 -0
- package/dist/plan/hostnames.d.ts +10 -0
- package/dist/plan/hostnames.js +14 -0
- package/dist/plan/index.d.ts +5 -0
- package/dist/plan/index.js +3 -0
- package/dist/plan/live.d.ts +6 -0
- package/dist/plan/live.js +3 -2
- package/dist/plan/locked-hostnames.d.ts +2 -1
- package/dist/plan/locked-hostnames.js +16 -3
- package/dist/plan/login-host.d.ts +9 -20
- package/dist/plan/login-host.js +10 -25
- package/dist/plan/mail-relay.d.ts +48 -29
- package/dist/plan/mail-relay.js +145 -68
- package/dist/plan/network-move.d.ts +20 -0
- package/dist/plan/network-move.js +41 -0
- package/dist/plan/oikos-ingress.d.ts +111 -0
- package/dist/plan/oikos-ingress.js +231 -0
- package/dist/plan/org-names.d.ts +8 -2
- package/dist/plan/org-names.js +57 -1
- package/dist/plan/own-diff.d.ts +9 -8
- package/dist/plan/own-diff.js +42 -34
- package/dist/plan/own-hostnames.d.ts +27 -0
- package/dist/plan/own-hostnames.js +24 -0
- package/dist/plan/own-limits.d.ts +198 -7
- package/dist/plan/own-limits.js +163 -32
- package/dist/plan/own-services.js +3 -1
- package/dist/plan/own-sfu.js +3 -2
- package/dist/plan/plan-apply.d.ts +47 -7
- package/dist/plan/plan-apply.js +184 -38
- package/dist/plan/platform-diff.d.ts +133 -17
- package/dist/plan/platform-diff.js +231 -68
- package/dist/plan/platform-org.d.ts +79 -10
- package/dist/plan/platform-org.js +93 -13
- package/dist/plan/platform-providers.d.ts +118 -73
- package/dist/plan/platform-providers.js +799 -241
- package/dist/plan/proxy-labels.d.ts +57 -11
- package/dist/plan/proxy-labels.js +94 -14
- package/dist/plan/run-options.d.ts +19 -0
- package/dist/plan/run-options.js +46 -0
- package/dist/plan/zitadel-login-policy.d.ts +1 -1
- package/dist/plan/zitadel-login-policy.js +76 -8
- package/dist/platform.d.ts +32 -0
- package/dist/platform.js +16 -0
- package/dist/provision.d.ts +2 -0
- package/dist/provision.js +3 -1
- package/dist/slug.d.ts +3 -1
- package/dist/slug.js +25 -3
- package/dist/store/postgres.js +43 -1
- package/dist/store/schema.d.ts +36 -0
- package/dist/store/schema.js +4 -0
- package/package.json +3 -3
- package/versions.digests.json +11 -0
|
@@ -71,9 +71,7 @@ export interface HealthTarget {
|
|
|
71
71
|
* the broker whenever the org has them; then whichever of hosting or site
|
|
72
72
|
* the org runs, if either.
|
|
73
73
|
*/
|
|
74
|
-
export declare function healthTargets(org: DeclaredOrg
|
|
75
|
-
platform?: DeclaredPlatform | null;
|
|
76
|
-
}): HealthTarget[];
|
|
74
|
+
export declare function healthTargets(org: DeclaredOrg): HealthTarget[];
|
|
77
75
|
/**
|
|
78
76
|
* The seven platform services #541 names (`platform:auth`, `platform:archon`,
|
|
79
77
|
* `platform:mail`, `platform:ai`, `platform:files`, `platform:integrations`,
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { appEntry } from '../org.js';
|
|
2
2
|
import { agoraHostnameFor } from './agora.js';
|
|
3
3
|
import { bouleHostnameFor } from './boule.js';
|
|
4
|
-
import { isPlatformOwnOrg } from './diff.js';
|
|
5
4
|
import { callsHostnameFor, cmsHostnameFor } from './executor.js';
|
|
6
5
|
import { isBehindGate } from './gates.js';
|
|
7
|
-
import { entryHostnames } from './hostnames.js';
|
|
6
|
+
import { entryHostnames, siteHostnameFor } from './hostnames.js';
|
|
8
7
|
import { loginHostnameFor } from './login-host.js';
|
|
9
8
|
function okExpect() {
|
|
10
9
|
return { status: 200 };
|
|
@@ -25,12 +24,8 @@ const STALWART_READY_PATH = '/healthz/ready';
|
|
|
25
24
|
const CHAT_SERVICE_HEALTH_PATH = '/_chat/health';
|
|
26
25
|
const CALLS_HEALTH_PATH = '/healthz';
|
|
27
26
|
/** Boule, Agora and the company's own login host: every org gets these, with no flag to check (the "Why" this issue opens with). */
|
|
28
|
-
function alwaysOnTargets(org
|
|
29
|
-
|
|
30
|
-
// `loginHostnameFor` (#488; `login-host.ts`, `diff.ts`'s `planLoginHost`).
|
|
31
|
-
const loginHost = platform && isPlatformOwnOrg(org, platform.ownerOrgId)
|
|
32
|
-
? platform.auth.hostname
|
|
33
|
-
: loginHostnameFor(org);
|
|
27
|
+
function alwaysOnTargets(org) {
|
|
28
|
+
const loginHost = loginHostnameFor(org);
|
|
34
29
|
return [
|
|
35
30
|
{
|
|
36
31
|
service: 'boule',
|
|
@@ -62,14 +57,10 @@ function alwaysOnTargets(org, platform) {
|
|
|
62
57
|
];
|
|
63
58
|
}
|
|
64
59
|
/**
|
|
65
|
-
* The
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* `'auth-broker'` target, under `platform.auth.hostname`. This target still
|
|
70
|
-
* belongs in a company's own list (#541: "Include ... the broker when the
|
|
71
|
-
* company has them") so a status page scoped to one company shows every
|
|
72
|
-
* service that company's sign-in actually depends on, even a shared one.
|
|
60
|
+
* The company's own sign-in broker (`broker-entries.ts`), when it depends on
|
|
61
|
+
* it: any hosting entry declaring `uses.auth` signs in through it. Its
|
|
62
|
+
* `/healthy` is not routed to the outside, so no URL is built here (#541:
|
|
63
|
+
* "Include ... the broker when the company has them").
|
|
73
64
|
*/
|
|
74
65
|
function brokerTarget(org) {
|
|
75
66
|
const usesBroker = org.hosting.entries.some((entry) => Boolean(entry.uses?.auth));
|
|
@@ -82,14 +73,13 @@ function brokerTarget(org) {
|
|
|
82
73
|
depth: 'shallow',
|
|
83
74
|
restartSafe: false,
|
|
84
75
|
behindAccess: false,
|
|
85
|
-
reason: "the sign-in broker
|
|
76
|
+
reason: "the company's own sign-in broker answers on its internal network only (broker-entries.ts): its /healthy is not routed to the outside, so there is no URL to probe",
|
|
86
77
|
};
|
|
87
78
|
}
|
|
88
79
|
/**
|
|
89
|
-
* Mail, when this company's mail is not off.
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* `platformHealthTargets`'s own `'mail'` target is the real, reachable one.
|
|
80
|
+
* Mail, when this company's mail is not off. The company runs its own
|
|
81
|
+
* Stalwart (`own-mail`), reached only by the shared relay on the internal
|
|
82
|
+
* network, so there is no public URL to build here.
|
|
93
83
|
*/
|
|
94
84
|
function mailTarget(org) {
|
|
95
85
|
if (org.mail.mode === 'off')
|
|
@@ -101,7 +91,7 @@ function mailTarget(org) {
|
|
|
101
91
|
depth: 'deep',
|
|
102
92
|
restartSafe: false,
|
|
103
93
|
behindAccess: false,
|
|
104
|
-
reason: "
|
|
94
|
+
reason: "the company's own Stalwart is reached by the shared relay on the internal network only, so it has no public address to probe",
|
|
105
95
|
};
|
|
106
96
|
}
|
|
107
97
|
/**
|
|
@@ -200,11 +190,11 @@ function appTargets(org) {
|
|
|
200
190
|
if (org.hosting.enabled && appEntry(org.hosting)) {
|
|
201
191
|
return org.hosting.entries.map((entry) => hostingEntryTarget(org, entry));
|
|
202
192
|
}
|
|
203
|
-
if (org.site.enabled
|
|
193
|
+
if (org.site.enabled) {
|
|
204
194
|
return [
|
|
205
195
|
{
|
|
206
196
|
service: 'site',
|
|
207
|
-
url: `https://${org
|
|
197
|
+
url: `https://${siteHostnameFor(org)}${DEFAULT_API_HEALTH_PATH}`,
|
|
208
198
|
expect: okExpect(),
|
|
209
199
|
depth: 'deep',
|
|
210
200
|
restartSafe: true,
|
|
@@ -228,8 +218,8 @@ function appTargets(org) {
|
|
|
228
218
|
* the broker whenever the org has them; then whichever of hosting or site
|
|
229
219
|
* the org runs, if either.
|
|
230
220
|
*/
|
|
231
|
-
export function healthTargets(org
|
|
232
|
-
const targets = alwaysOnTargets(org
|
|
221
|
+
export function healthTargets(org) {
|
|
222
|
+
const targets = alwaysOnTargets(org);
|
|
233
223
|
const broker = brokerTarget(org);
|
|
234
224
|
if (broker)
|
|
235
225
|
targets.push(broker);
|
|
@@ -308,8 +298,10 @@ function internalOnlyTarget(service, reason) {
|
|
|
308
298
|
* one anyway.
|
|
309
299
|
*/
|
|
310
300
|
export function platformHealthTargets(platform) {
|
|
301
|
+
// The platform's own sign-in, mail and files are off (each company runs its own), so a target
|
|
302
|
+
// for a service that is not enabled would point at a host that does not exist.
|
|
311
303
|
return [
|
|
312
|
-
...authTargets(platform),
|
|
304
|
+
...(platform.auth.enabled ? authTargets(platform) : []),
|
|
313
305
|
{
|
|
314
306
|
service: 'archon',
|
|
315
307
|
// `provisionPlatformArchon` always puts a Cloudflare Access app in front
|
|
@@ -322,16 +314,24 @@ export function platformHealthTargets(platform) {
|
|
|
322
314
|
restartSafe: false,
|
|
323
315
|
behindAccess: true,
|
|
324
316
|
},
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
317
|
+
...(platform.mail.enabled
|
|
318
|
+
? [
|
|
319
|
+
{
|
|
320
|
+
service: 'mail',
|
|
321
|
+
url: `https://${platform.mail.hostname}${STALWART_READY_PATH}`,
|
|
322
|
+
expect: okExpect(),
|
|
323
|
+
depth: 'deep',
|
|
324
|
+
restartSafe: false,
|
|
325
|
+
behindAccess: false,
|
|
326
|
+
},
|
|
327
|
+
]
|
|
328
|
+
: []),
|
|
333
329
|
internalOnlyTarget('ai', "platform:ai's runner is created with no Coolify domains, tunnel, DNS record or Access app (platform-providers.ts) -- nothing public to probe yet"),
|
|
334
|
-
|
|
330
|
+
...(platform.files.enabled
|
|
331
|
+
? [
|
|
332
|
+
internalOnlyTarget('files', "platform:files' runner is created with no domains either, the same as platform:auth's apps (platform-providers.ts) -- nothing public to probe yet"),
|
|
333
|
+
]
|
|
334
|
+
: []),
|
|
335
335
|
{
|
|
336
336
|
service: 'integrations',
|
|
337
337
|
url: null,
|
|
@@ -6,5 +6,10 @@
|
|
|
6
6
|
export declare const JOBS_ADMIN_TOKEN_REF = "jobs:scheduler:adminToken";
|
|
7
7
|
/** The ref the AI management key is delivered under; the host's `AiOrganisationPort` adapter reads it back. */
|
|
8
8
|
export declare const PLATFORM_AI_MANAGEMENT_KEY_REF = "ai:platform:managementKey";
|
|
9
|
+
/**
|
|
10
|
+
* The install's edge label token (`proxy-labels.ts` `EDGE_LABEL`): minted once, held, and written into the
|
|
11
|
+
* labels of every container foundry routes, so Traefik can be told to route only those.
|
|
12
|
+
*/
|
|
13
|
+
export declare const PROXY_LABEL_TOKEN_REF = "proxy:labels:token";
|
|
9
14
|
/** The ref the management private key (PKCS#8 PEM) is delivered under. */
|
|
10
15
|
export declare const FILES_MANAGEMENT_KEY_REF = "files:platform:managementKey";
|
|
@@ -6,5 +6,10 @@
|
|
|
6
6
|
export const JOBS_ADMIN_TOKEN_REF = 'jobs:scheduler:adminToken';
|
|
7
7
|
/** The ref the AI management key is delivered under; the host's `AiOrganisationPort` adapter reads it back. */
|
|
8
8
|
export const PLATFORM_AI_MANAGEMENT_KEY_REF = 'ai:platform:managementKey';
|
|
9
|
+
/**
|
|
10
|
+
* The install's edge label token (`proxy-labels.ts` `EDGE_LABEL`): minted once, held, and written into the
|
|
11
|
+
* labels of every container foundry routes, so Traefik can be told to route only those.
|
|
12
|
+
*/
|
|
13
|
+
export const PROXY_LABEL_TOKEN_REF = 'proxy:labels:token';
|
|
9
14
|
/** The ref the management private key (PKCS#8 PEM) is delivered under. */
|
|
10
15
|
export const FILES_MANAGEMENT_KEY_REF = 'files:platform:managementKey';
|
package/dist/plan/hostnames.d.ts
CHANGED
|
@@ -38,6 +38,16 @@ export declare function tunnelDomainList(names: readonly string[]): string[];
|
|
|
38
38
|
export declare function coolifyTunnelDomains(names: readonly string[]): string;
|
|
39
39
|
/** What `domains` held on an `app` entry's Coolify app before entries had hostnames. */
|
|
40
40
|
export declare function legacyAppHostname(org: DeclaredOrg): string;
|
|
41
|
+
/**
|
|
42
|
+
* The public address of the org's cms site: its domain, or `<slug>.oikos.host`
|
|
43
|
+
* for a company without one (served by the shared `*.oikos.host` wildcard).
|
|
44
|
+
*/
|
|
45
|
+
export declare function siteHostnameFor(org: DeclaredOrg): string;
|
|
46
|
+
/**
|
|
47
|
+
* The cms studio's address: `cms.<domain>`, or `<slug>-cms.oikos.host` for a
|
|
48
|
+
* company without a domain (one label, so the free wildcard certificate covers it).
|
|
49
|
+
*/
|
|
50
|
+
export declare function cmsStudioHostnameFor(org: DeclaredOrg): string;
|
|
41
51
|
/**
|
|
42
52
|
* `share.<domain>` when hosting is on and an entry declares
|
|
43
53
|
* `uses.files.shareHost`, else `null`. The files service answers public
|
package/dist/plan/hostnames.js
CHANGED
|
@@ -63,6 +63,20 @@ export function coolifyTunnelDomains(names) {
|
|
|
63
63
|
export function legacyAppHostname(org) {
|
|
64
64
|
return org.hosting.usesDomain && org.domain ? org.domain : `${org.slug}.oikos.host`;
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* The public address of the org's cms site: its domain, or `<slug>.oikos.host`
|
|
68
|
+
* for a company without one (served by the shared `*.oikos.host` wildcard).
|
|
69
|
+
*/
|
|
70
|
+
export function siteHostnameFor(org) {
|
|
71
|
+
return org.site.usesDomain && org.domain ? org.domain : `${org.slug}.oikos.host`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The cms studio's address: `cms.<domain>`, or `<slug>-cms.oikos.host` for a
|
|
75
|
+
* company without a domain (one label, so the free wildcard certificate covers it).
|
|
76
|
+
*/
|
|
77
|
+
export function cmsStudioHostnameFor(org) {
|
|
78
|
+
return org.site.usesDomain && org.domain ? `cms.${org.domain}` : `${org.slug}-cms.oikos.host`;
|
|
79
|
+
}
|
|
66
80
|
/**
|
|
67
81
|
* `share.<domain>` when hosting is on and an entry declares
|
|
68
82
|
* `uses.files.shareHost`, else `null`. The files service answers public
|
package/dist/plan/index.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export { AdoptRefusedError } from './adopt.js';
|
|
|
23
23
|
export type { AuditActor, AuditLog, AuthzGate, StepExecutor, StepDestroyer, DestroyTarget, StepExecutionContext, PlatformStepExecutor, PlatformStepExecutionContext, FoundryPlanApplyOptions, FoundryApplyOptions, } from './plan-apply.js';
|
|
24
24
|
export { FoundryPlanApply, DeclaredOrgNotFoundError, StalePlanError, ConfirmationRequiredError, NotAuthorizedError, NotATestOrgError, DeclaredPlatformNotFoundError, PlatformStalePlanError, PlatformConfirmationRequiredError, UpgradeConfirmationRequiredError, planNeedsConfirmation, } from './plan-apply.js';
|
|
25
25
|
export type { UnconfirmedUpgrade } from './confirm-upgrade.js';
|
|
26
|
+
export { NetworkMoveBackupMissingError, UpgradeBackupMissingError } from './backup-gate.js';
|
|
27
|
+
export type { BackupGatePorts, MoveGatePorts } from './backup-gate.js';
|
|
26
28
|
export { FoundryPlatformStepExecutor, ProvidersPlatformCloudflareReader, ProvidersPlatformCoolifyReader, PLATFORM_MAIL_ADMIN_KEY_DESCRIPTION, filesPublicHostsValue, filesShareDomains, provisionFilesHost, provisionJobsHost, provisionMailServer, } from './platform-providers.js';
|
|
27
29
|
export type { FilesHostInput, JobsHostDeps, JobsHostInput, MailServerInput, PlatformAuthDeps, PlatformAuthSmtp, PlatformAuthRuntime, PlatformFilesDeps, PlatformFilesRuntime, PlatformEdgeDeps, PlatformDnsFactory, PlatformAccessFactory, PlatformAccessPort, PlatformTunnelsFactory, PlatformEdgeRuntime, } from './platform-providers.js';
|
|
28
30
|
export type { PlatformMailDeps, PlatformMailAdminPort, PlatformMailRuntime, } from './platform-providers.js';
|
|
@@ -43,6 +45,8 @@ export type { BrokerPort } from './broker-entries.js';
|
|
|
43
45
|
export { PlatformBrokerPort } from './broker-entries.js';
|
|
44
46
|
export type { LoginHostBinding, LoginHostBindingsPort, LoginHostDiscoveryPort, } from './login-host.js';
|
|
45
47
|
export { loginHostnameFor } from './login-host.js';
|
|
48
|
+
export { NO_DOMAIN_ZONE, ownHostnames } from './own-hostnames.js';
|
|
49
|
+
export type { OwnHostnames } from './own-hostnames.js';
|
|
46
50
|
export type { MailIdentityApp, MailIdentityAudienceCheck } from './mail-identity.js';
|
|
47
51
|
export { checkMailIdentityAudience } from './mail-identity.js';
|
|
48
52
|
export type { MailAllowlistApp } from './mail-identity-allowlist.js';
|
|
@@ -71,3 +75,4 @@ export { adaptZitadelListApps } from './executor.js';
|
|
|
71
75
|
export { HttpJobsSchedulerClient } from './jobs-scheduler-http.js';
|
|
72
76
|
export type { OrgAppVersionRef, OrgAppVersionStatus, WtfalchPackageDrift, PlatformVersionStatus, ReadPlatformVersionStatusOptions, StatusCoolifyPort, StatusGithubPort, GhExec as StatusGhExec, } from './version-status.js';
|
|
73
77
|
export { readPlatformVersionStatus, wtfalchVersionsFromPnpmLockfile, providersStatusCoolifyPort, ghCliStatusGithubPort, } from './version-status.js';
|
|
78
|
+
export { COMPANY_DESTINATION_NAME_PREFIX, COMPANY_NETWORKS, DEFAULT_MAX_DESTINATIONS, DestinationCapacityError, PLATFORM_NETWORK, companyNetworkName, ensureDestination, findDestination, placed, placedOnPlatform, validateNetworkName, } from './destinations.js';
|
package/dist/plan/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export { OWN_FILES_R2_SCOPE_KEY, OWN_FILES_R2_UNDELIVERED_SCOPE_KEY, OWN_SERVICE
|
|
|
10
10
|
export { PlatformOrgBlockedError, PlatformOrgPorts } from './platform-org-ports.js';
|
|
11
11
|
export { AdoptRefusedError } from './adopt.js';
|
|
12
12
|
export { FoundryPlanApply, DeclaredOrgNotFoundError, StalePlanError, ConfirmationRequiredError, NotAuthorizedError, NotATestOrgError, DeclaredPlatformNotFoundError, PlatformStalePlanError, PlatformConfirmationRequiredError, UpgradeConfirmationRequiredError, planNeedsConfirmation, } from './plan-apply.js';
|
|
13
|
+
export { NetworkMoveBackupMissingError, UpgradeBackupMissingError } from './backup-gate.js';
|
|
13
14
|
export { FoundryPlatformStepExecutor, ProvidersPlatformCloudflareReader, ProvidersPlatformCoolifyReader, PLATFORM_MAIL_ADMIN_KEY_DESCRIPTION, filesPublicHostsValue, filesShareDomains, provisionFilesHost, provisionJobsHost, provisionMailServer, } from './platform-providers.js';
|
|
14
15
|
// #171: how a host signs files management requests with the delivered key.
|
|
15
16
|
export { FILES_INTROSPECTION_SECRET_REF, FILES_MANAGEMENT_ISSUER, FILES_MANAGEMENT_KEY_ID, FILES_MANAGEMENT_KEY_REF, PLATFORM_AUTH_INSTANCE_BEARER_REF, } from './platform-providers.js';
|
|
@@ -22,6 +23,7 @@ export { MAIL_COPY_COMPLETED_SCOPE_KEY, MAIL_COPY_DONE_SCOPE_KEY, MissingMailCop
|
|
|
22
23
|
export { ProvidersAiReader, ProvidersCloudflareReader, ProvidersCmsReader, ProvidersCoolifyReader, ProvidersZitadelReader, storeLoginHostResolver, storeScopeResolver, storeRecordedIds, } from './providers-readers.js';
|
|
23
24
|
export { PlatformBrokerPort } from './broker-entries.js';
|
|
24
25
|
export { loginHostnameFor } from './login-host.js';
|
|
26
|
+
export { NO_DOMAIN_ZONE, ownHostnames } from './own-hostnames.js';
|
|
25
27
|
export { checkMailIdentityAudience } from './mail-identity.js';
|
|
26
28
|
export { checkMailAppsAllowlist } from './mail-identity-allowlist.js';
|
|
27
29
|
export { FoundryStepExecutor, NotBuiltError, healthUrls } from './executor.js';
|
|
@@ -36,3 +38,4 @@ export { createEdgeTunnels } from './edge-tunnels.js';
|
|
|
36
38
|
export { adaptZitadelListApps } from './executor.js';
|
|
37
39
|
export { HttpJobsSchedulerClient } from './jobs-scheduler-http.js';
|
|
38
40
|
export { readPlatformVersionStatus, wtfalchVersionsFromPnpmLockfile, providersStatusCoolifyPort, ghCliStatusGithubPort, } from './version-status.js';
|
|
41
|
+
export { COMPANY_DESTINATION_NAME_PREFIX, COMPANY_NETWORKS, DEFAULT_MAX_DESTINATIONS, DestinationCapacityError, PLATFORM_NETWORK, companyNetworkName, ensureDestination, findDestination, placed, placedOnPlatform, validateNetworkName, } from './destinations.js';
|
package/dist/plan/live.d.ts
CHANGED
|
@@ -121,6 +121,12 @@ export interface PlatformCloudflareReader {
|
|
|
121
121
|
/** #173: the platform's own Coolify-hosted jobs scheduler (`platform-diff.ts`'s `planJobs`). */
|
|
122
122
|
export interface PlatformCoolifyReader {
|
|
123
123
|
listResources(): Promise<LiveResource[]>;
|
|
124
|
+
/** Optional: with it the platform plan reads each recorded app's running commit and notes a build that differs (`build-record.ts`). */
|
|
125
|
+
listApplicationDeployments?(uuid: string, take?: number): Promise<Array<{
|
|
126
|
+
deployment_uuid: string;
|
|
127
|
+
commit?: string;
|
|
128
|
+
status: string;
|
|
129
|
+
}>>;
|
|
124
130
|
}
|
|
125
131
|
export interface PlatformLiveReaders {
|
|
126
132
|
cloudflare: PlatformCloudflareReader;
|
package/dist/plan/live.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ownsServices } from '../org.js';
|
|
2
|
+
import { ownHostnames } from './own-hostnames.js';
|
|
2
3
|
import { OWN_SERVICES_APPLIED_SCOPE_KEY, orgTarget } from './own-services.js';
|
|
3
4
|
/** Every live resource foundry can see for `orgId`, across all six systems. */
|
|
4
5
|
export async function readLiveResources(orgId, readers, org, orgRecordedIds) {
|
|
@@ -16,11 +17,11 @@ export async function readLiveResources(orgId, readers, org, orgRecordedIds) {
|
|
|
16
17
|
}
|
|
17
18
|
/** An own org's ZITADEL is its own instance: nothing is read until it is applied, and never from the shared one. */
|
|
18
19
|
async function readOwnZitadel(orgId, readers, org, recordedIds) {
|
|
19
|
-
if (!readers.zitadelFor || !
|
|
20
|
+
if (!readers.zitadelFor || !recordedIds[OWN_SERVICES_APPLIED_SCOPE_KEY])
|
|
20
21
|
return [];
|
|
21
22
|
const refs = orgTarget(org).refs;
|
|
22
23
|
return readers
|
|
23
|
-
.zitadelFor({ issuerUrl:
|
|
24
|
+
.zitadelFor({ issuerUrl: ownHostnames(org).issuerUrl, bearerRef: refs.instanceBearer })
|
|
24
25
|
.listResources(orgId);
|
|
25
26
|
}
|
|
26
27
|
/** Every live resource foundry can see for the platform, across every wired reader (#167, #173). */
|
|
@@ -6,6 +6,7 @@ export declare const OWN_SERVICE_LABELS: readonly ["auth", "mail", "files", "sfu
|
|
|
6
6
|
* take one: Agora, Boule, the cms studio when the site is on, calls when it uses the
|
|
7
7
|
* domain, the sign-in host when the issuer does, `auth.`, `mail.`, `files.` and
|
|
8
8
|
* `sfu.` for an org that runs its own services, and every platform service
|
|
9
|
-
* hostname that falls under the domain.
|
|
9
|
+
* hostname that falls under the domain. An own org with no domain holds its
|
|
10
|
+
* oikos.host service names; any other org with no domain holds none.
|
|
10
11
|
*/
|
|
11
12
|
export declare function lockedHostnames(org: DeclaredOrg, platformHostnames: readonly string[]): Set<string>;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { ownsServices } from '../org.js';
|
|
2
2
|
import { agoraHostnameFor } from './agora.js';
|
|
3
3
|
import { bouleHostnameFor } from './boule.js';
|
|
4
|
+
import { cmsStudioHostnameFor, siteHostnameFor } from './hostnames.js';
|
|
4
5
|
import { loginHostnameFor } from './login-host.js';
|
|
6
|
+
import { ownHostnames } from './own-hostnames.js';
|
|
5
7
|
/** The labels an own org's services answer on, so no hosting entry may take them. */
|
|
6
8
|
export const OWN_SERVICE_LABELS = ['auth', 'mail', 'files', 'sfu'];
|
|
7
9
|
/**
|
|
@@ -9,17 +11,28 @@ export const OWN_SERVICE_LABELS = ['auth', 'mail', 'files', 'sfu'];
|
|
|
9
11
|
* take one: Agora, Boule, the cms studio when the site is on, calls when it uses the
|
|
10
12
|
* domain, the sign-in host when the issuer does, `auth.`, `mail.`, `files.` and
|
|
11
13
|
* `sfu.` for an org that runs its own services, and every platform service
|
|
12
|
-
* hostname that falls under the domain.
|
|
14
|
+
* hostname that falls under the domain. An own org with no domain holds its
|
|
15
|
+
* oikos.host service names; any other org with no domain holds none.
|
|
13
16
|
*/
|
|
14
17
|
export function lockedHostnames(org, platformHostnames) {
|
|
15
18
|
const { domain } = org;
|
|
16
19
|
const locked = new Set();
|
|
17
|
-
if (!domain)
|
|
20
|
+
if (!domain) {
|
|
21
|
+
if (ownsServices(org)) {
|
|
22
|
+
const own = ownHostnames(org);
|
|
23
|
+
for (const hostname of [own.auth, own.mail, own.files, own.sfu])
|
|
24
|
+
locked.add(hostname);
|
|
25
|
+
}
|
|
26
|
+
if (org.site.enabled) {
|
|
27
|
+
locked.add(siteHostnameFor(org));
|
|
28
|
+
locked.add(cmsStudioHostnameFor(org));
|
|
29
|
+
}
|
|
18
30
|
return locked;
|
|
31
|
+
}
|
|
19
32
|
locked.add(agoraHostnameFor(org));
|
|
20
33
|
locked.add(bouleHostnameFor(org));
|
|
21
34
|
if (org.site.enabled)
|
|
22
|
-
locked.add(
|
|
35
|
+
locked.add(cmsStudioHostnameFor(org));
|
|
23
36
|
if (org.calls.enabled && org.calls.usesDomain)
|
|
24
37
|
locked.add(`calls.${domain}`);
|
|
25
38
|
if (org.issuer.usesDomain)
|
|
@@ -22,33 +22,20 @@ import { type DeclaredOrg } from '../org.js';
|
|
|
22
22
|
* org's own `<slug>.oikos.host` can collide with this subdomain, the same
|
|
23
23
|
* way `AGORA_SUFFIX` reserves `-agora`.
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* that host itself. That host must never get a trusted
|
|
29
|
-
* domain or a login binding of its own:
|
|
30
|
-
* Archon's login-host write throws on a duplicate host, and `auth`'s own
|
|
31
|
-
* `company-host.ts` denies every request through one, the shared one
|
|
32
|
-
* included (`planLoginHost` and `zitadelLoginHost` skip both for it).
|
|
25
|
+
* Every company, the platform owner included, signs in on its own sign-in
|
|
26
|
+
* server at this host (`ownHostnames(org).auth` is this function): a domain is
|
|
27
|
+
* never required.
|
|
33
28
|
*/
|
|
34
|
-
export declare function loginHostnameFor(org: DeclaredOrg): string;
|
|
35
|
-
/**
|
|
36
|
-
* The login host the login-host step plans for an org: the shared instance's
|
|
37
|
-
* own host when `sharedHost` is given (the platform's own org), the company's
|
|
38
|
-
* own host otherwise. `planLoginHost` and {@link agoraIssuerHostFor} both
|
|
39
|
-
* read it here, so Agora's issuer and the login host cannot disagree.
|
|
40
|
-
*/
|
|
41
|
-
export declare function orgLoginHost(org: DeclaredOrg, sharedHost: string | null): string;
|
|
29
|
+
export declare function loginHostnameFor(org: Pick<DeclaredOrg, 'slug' | 'domain' | 'issuer'>): string;
|
|
42
30
|
/**
|
|
43
31
|
* The login host Agora may take as its issuer, and whether the org's pair is
|
|
44
32
|
* one Agora refuses. Agora accepts an issuer host on its own address's
|
|
45
33
|
* registrable domain, or `<slug>-auth.oikos.host` for `<slug>-agora.oikos.host`.
|
|
46
|
-
* `host` is null for
|
|
47
|
-
* for a domain with `issuer.usesDomain` off, where the login host
|
|
34
|
+
* `host` is null for a domain with `issuer.usesDomain` off, where the login host
|
|
48
35
|
* `<slug>-auth.oikos.host` and the Agora address `agora.<domain>` are
|
|
49
36
|
* refused together (`mismatch`).
|
|
50
37
|
*/
|
|
51
|
-
export declare function agoraIssuerHostFor(org: DeclaredOrg
|
|
38
|
+
export declare function agoraIssuerHostFor(org: DeclaredOrg): {
|
|
52
39
|
host: string | null;
|
|
53
40
|
mismatch: boolean;
|
|
54
41
|
};
|
|
@@ -77,6 +64,8 @@ export declare function discoveryNamesHost(host: string, answer: {
|
|
|
77
64
|
* leaves.
|
|
78
65
|
*/
|
|
79
66
|
export declare function readLoginHostDiscovery(port: LoginHostDiscoveryPort | undefined, host: string, timeoutMs?: number): Promise<boolean>;
|
|
67
|
+
/** The hostname an own org's sign-in last applied at, so a changed domain plans the step again. */
|
|
68
|
+
export declare const OWN_AUTH_APPLIED_HOSTNAME_SCOPE_KEY = "own_auth_applied_hostname";
|
|
80
69
|
/**
|
|
81
70
|
* True once the org's own sign-in step has applied (`coolify:own-auth:<org.id>`
|
|
82
71
|
* in its recorded ids). An own org has no login-host step: its issuer host is
|
|
@@ -175,4 +164,4 @@ export declare function pendingRemovalState(hosts: readonly string[]): string;
|
|
|
175
164
|
* the shared instance's and is routed by the platform auth tunnel. Otherwise
|
|
176
165
|
* `null`, and always `null` for an own org. The tier 1 host rides the shared `*.oikos.host` tunnel.
|
|
177
166
|
*/
|
|
178
|
-
export declare function companyLoginTunnelHost(org: DeclaredOrg
|
|
167
|
+
export declare function companyLoginTunnelHost(org: DeclaredOrg): string | null;
|
package/dist/plan/login-host.js
CHANGED
|
@@ -24,14 +24,9 @@ import { BOULE_CLIENT_ID_SCOPE_KEY } from './boule.js';
|
|
|
24
24
|
* org's own `<slug>.oikos.host` can collide with this subdomain, the same
|
|
25
25
|
* way `AGORA_SUFFIX` reserves `-agora`.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* that host itself. That host must never get a trusted
|
|
31
|
-
* domain or a login binding of its own:
|
|
32
|
-
* Archon's login-host write throws on a duplicate host, and `auth`'s own
|
|
33
|
-
* `company-host.ts` denies every request through one, the shared one
|
|
34
|
-
* included (`planLoginHost` and `zitadelLoginHost` skip both for it).
|
|
27
|
+
* Every company, the platform owner included, signs in on its own sign-in
|
|
28
|
+
* server at this host (`ownHostnames(org).auth` is this function): a domain is
|
|
29
|
+
* never required.
|
|
35
30
|
*/
|
|
36
31
|
export function loginHostnameFor(org) {
|
|
37
32
|
// `issuer.usesDomain` is the issuer's opt-in into the org's domain
|
|
@@ -42,27 +37,15 @@ export function loginHostnameFor(org) {
|
|
|
42
37
|
}
|
|
43
38
|
return `${org.slug}-auth.oikos.host`;
|
|
44
39
|
}
|
|
45
|
-
/**
|
|
46
|
-
* The login host the login-host step plans for an org: the shared instance's
|
|
47
|
-
* own host when `sharedHost` is given (the platform's own org), the company's
|
|
48
|
-
* own host otherwise. `planLoginHost` and {@link agoraIssuerHostFor} both
|
|
49
|
-
* read it here, so Agora's issuer and the login host cannot disagree.
|
|
50
|
-
*/
|
|
51
|
-
export function orgLoginHost(org, sharedHost) {
|
|
52
|
-
return sharedHost ?? loginHostnameFor(org);
|
|
53
|
-
}
|
|
54
40
|
/**
|
|
55
41
|
* The login host Agora may take as its issuer, and whether the org's pair is
|
|
56
42
|
* one Agora refuses. Agora accepts an issuer host on its own address's
|
|
57
43
|
* registrable domain, or `<slug>-auth.oikos.host` for `<slug>-agora.oikos.host`.
|
|
58
|
-
* `host` is null for
|
|
59
|
-
* for a domain with `issuer.usesDomain` off, where the login host
|
|
44
|
+
* `host` is null for a domain with `issuer.usesDomain` off, where the login host
|
|
60
45
|
* `<slug>-auth.oikos.host` and the Agora address `agora.<domain>` are
|
|
61
46
|
* refused together (`mismatch`).
|
|
62
47
|
*/
|
|
63
|
-
export function agoraIssuerHostFor(org
|
|
64
|
-
if (isPlatformOrg)
|
|
65
|
-
return { host: null, mismatch: false };
|
|
48
|
+
export function agoraIssuerHostFor(org) {
|
|
66
49
|
if (org.domain && !org.issuer.usesDomain)
|
|
67
50
|
return { host: null, mismatch: true };
|
|
68
51
|
return { host: loginHostnameFor(org), mismatch: false };
|
|
@@ -110,6 +93,8 @@ export async function readLoginHostDiscovery(port, host, timeoutMs = LOGIN_HOST_
|
|
|
110
93
|
clearTimeout(timer);
|
|
111
94
|
}
|
|
112
95
|
}
|
|
96
|
+
/** The hostname an own org's sign-in last applied at, so a changed domain plans the step again. */
|
|
97
|
+
export const OWN_AUTH_APPLIED_HOSTNAME_SCOPE_KEY = 'own_auth_applied_hostname';
|
|
113
98
|
/**
|
|
114
99
|
* True once the org's own sign-in step has applied (`coolify:own-auth:<org.id>`
|
|
115
100
|
* in its recorded ids). An own org has no login-host step: its issuer host is
|
|
@@ -211,9 +196,9 @@ export function pendingRemovalState(hosts) {
|
|
|
211
196
|
* the shared instance's and is routed by the platform auth tunnel. Otherwise
|
|
212
197
|
* `null`, and always `null` for an own org. The tier 1 host rides the shared `*.oikos.host` tunnel.
|
|
213
198
|
*/
|
|
214
|
-
export function companyLoginTunnelHost(org
|
|
215
|
-
// An own org's sign-in stack publishes
|
|
199
|
+
export function companyLoginTunnelHost(org) {
|
|
200
|
+
// An own org's sign-in stack publishes its host through its own tunnel.
|
|
216
201
|
if (ownsServices(org))
|
|
217
202
|
return null;
|
|
218
|
-
return org.domain && org.issuer.usesDomain
|
|
203
|
+
return org.domain && org.issuer.usesDomain ? loginHostnameFor(org) : null;
|
|
219
204
|
}
|