@wtfalch/foundry 0.33.1 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bootstrap/versions.d.ts +4 -0
- package/dist/calls-sfu.d.ts +10 -0
- package/dist/calls-sfu.js +41 -0
- package/dist/index.d.ts +14 -6
- package/dist/index.js +7 -3
- package/dist/migrations/0051_org_services.sql +13 -0
- package/dist/migrations/0052_platform_mail_relay.sql +8 -0
- package/dist/org.d.ts +18 -0
- package/dist/org.js +26 -0
- package/dist/plan/calls-matrix.d.ts +9 -0
- package/dist/plan/calls-matrix.js +17 -0
- package/dist/plan/cloudflared-connector.d.ts +7 -1
- package/dist/plan/cloudflared-connector.js +14 -1
- package/dist/plan/diff.d.ts +29 -0
- package/dist/plan/diff.js +259 -18
- package/dist/plan/executor.d.ts +112 -0
- package/dist/plan/executor.js +594 -33
- package/dist/plan/health-check-settings.d.ts +28 -0
- package/dist/plan/health-check-settings.js +36 -0
- package/dist/plan/health-gaps.d.ts +33 -0
- package/dist/plan/health-gaps.js +89 -0
- package/dist/plan/held-key-refs.d.ts +10 -0
- package/dist/plan/held-key-refs.js +10 -0
- package/dist/plan/index.d.ts +14 -6
- package/dist/plan/index.js +7 -3
- package/dist/plan/live.d.ts +5 -2
- package/dist/plan/live.js +15 -2
- package/dist/plan/locked-hostnames.d.ts +5 -2
- package/dist/plan/locked-hostnames.js +9 -1
- package/dist/plan/login-host.d.ts +62 -2
- package/dist/plan/login-host.js +104 -1
- package/dist/plan/mail-relay.d.ts +120 -0
- package/dist/plan/mail-relay.js +323 -0
- package/dist/plan/org-names.d.ts +24 -0
- package/dist/plan/org-names.js +52 -0
- package/dist/plan/own-diff.d.ts +169 -0
- package/dist/plan/own-diff.js +432 -0
- package/dist/plan/own-dns.d.ts +6 -0
- package/dist/plan/own-dns.js +15 -0
- package/dist/plan/own-limits.d.ts +22 -0
- package/dist/plan/own-limits.js +101 -0
- package/dist/plan/own-services.d.ts +193 -0
- package/dist/plan/own-services.js +167 -0
- package/dist/plan/own-sfu.d.ts +69 -0
- package/dist/plan/own-sfu.js +255 -0
- package/dist/plan/plan-apply.d.ts +78 -7
- package/dist/plan/plan-apply.js +205 -12
- package/dist/plan/platform-diff.d.ts +28 -0
- package/dist/plan/platform-diff.js +45 -3
- package/dist/plan/platform-org.d.ts +34 -0
- package/dist/plan/platform-org.js +94 -2
- package/dist/plan/platform-providers.d.ts +356 -8
- package/dist/plan/platform-providers.js +661 -353
- package/dist/plan/sign-in-org.d.ts +1 -1
- package/dist/plan/sign-in-org.js +20 -2
- package/dist/plan/zitadel-login-policy.js +1 -1
- package/dist/plan/zitadel-system-api.d.ts +22 -1
- package/dist/plan/zitadel-system-api.js +49 -8
- package/dist/platform.d.ts +8 -0
- package/dist/slug.js +1 -0
- package/dist/store/postgres.js +51 -2
- package/dist/store/schema.d.ts +51 -0
- package/dist/store/schema.js +5 -0
- package/package.json +1 -1
- package/versions.json +3 -1
|
@@ -13,6 +13,10 @@ export interface PinnedVersions {
|
|
|
13
13
|
cloudflared: string;
|
|
14
14
|
stalwart: string;
|
|
15
15
|
hc: string;
|
|
16
|
+
/** The mail relay's base image (an exact Alpine release); Postfix comes from its package repository. */
|
|
17
|
+
alpine: string;
|
|
18
|
+
/** A static busybox, copied into the MAS image so its health check has an HTTP client. */
|
|
19
|
+
busybox: string;
|
|
16
20
|
}
|
|
17
21
|
export declare function loadVersions(): PinnedVersions;
|
|
18
22
|
export declare const VERSIONS: PinnedVersions;
|
package/dist/calls-sfu.d.ts
CHANGED
|
@@ -129,6 +129,16 @@ export declare const LIVEKIT_SIGNALLING_PORT = 7880;
|
|
|
129
129
|
export declare const LIVEKIT_MEDIA_TCP_PORT = 7881;
|
|
130
130
|
/** RTP media. Matches #122's "Decided" section exactly; not the wider range `docs/research/2026-09-19-meetings-research.md` lists for embedded TURN, which #122 does not turn on. */
|
|
131
131
|
export declare const LIVEKIT_MEDIA_UDP_RANGE = "50000:60000";
|
|
132
|
+
/**
|
|
133
|
+
* The ports of one slice of the Coolify server's media ports (`services.sfuSlot`):
|
|
134
|
+
* slot n holds UDP `50000 + (n-1)*500` to `50000 + n*500 - 1` and TCP `7881 + n`.
|
|
135
|
+
* Throws for a slot outside 1..{@link SFU_SLOT_MAX}.
|
|
136
|
+
*/
|
|
137
|
+
export declare function sfuSlotPorts(slot: number): {
|
|
138
|
+
udpStart: number;
|
|
139
|
+
udpEnd: number;
|
|
140
|
+
tcp: number;
|
|
141
|
+
};
|
|
132
142
|
/**
|
|
133
143
|
* The host's private network on `vmbr1`, where the calls service reaches
|
|
134
144
|
* LiveKit's API directly (#127's "Human steps": VM 105 gets a second NIC on
|
package/dist/calls-sfu.js
CHANGED
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
* from any error `calls-sfu-deploy.mjs` prints.
|
|
54
54
|
*/
|
|
55
55
|
import { VERSIONS } from './bootstrap/versions.js';
|
|
56
|
+
import { SFU_SLOT_MAX } from './org.js';
|
|
56
57
|
// ---------------------------------------------------------------------------
|
|
57
58
|
// The guard
|
|
58
59
|
// ---------------------------------------------------------------------------
|
|
@@ -119,6 +120,27 @@ export const LIVEKIT_SIGNALLING_PORT = 7880;
|
|
|
119
120
|
export const LIVEKIT_MEDIA_TCP_PORT = 7881;
|
|
120
121
|
/** RTP media. Matches #122's "Decided" section exactly; not the wider range `docs/research/2026-09-19-meetings-research.md` lists for embedded TURN, which #122 does not turn on. */
|
|
121
122
|
export const LIVEKIT_MEDIA_UDP_RANGE = '50000:60000';
|
|
123
|
+
/** The first UDP port of slot 1 and the width of every slot's UDP range (contract section 1). */
|
|
124
|
+
const SFU_SLOT_UDP_BASE = 50000;
|
|
125
|
+
const SFU_SLOT_UDP_WIDTH = 500;
|
|
126
|
+
/** Slot n's TCP fallback port is this plus n. */
|
|
127
|
+
const SFU_SLOT_TCP_BASE = 7881;
|
|
128
|
+
/**
|
|
129
|
+
* The ports of one slice of the Coolify server's media ports (`services.sfuSlot`):
|
|
130
|
+
* slot n holds UDP `50000 + (n-1)*500` to `50000 + n*500 - 1` and TCP `7881 + n`.
|
|
131
|
+
* Throws for a slot outside 1..{@link SFU_SLOT_MAX}.
|
|
132
|
+
*/
|
|
133
|
+
export function sfuSlotPorts(slot) {
|
|
134
|
+
if (!Number.isInteger(slot) || slot < 1 || slot > SFU_SLOT_MAX) {
|
|
135
|
+
throw new Error(`sfu slot must be an integer from 1 to ${SFU_SLOT_MAX}`);
|
|
136
|
+
}
|
|
137
|
+
const udpStart = SFU_SLOT_UDP_BASE + (slot - 1) * SFU_SLOT_UDP_WIDTH;
|
|
138
|
+
return {
|
|
139
|
+
udpStart,
|
|
140
|
+
udpEnd: udpStart + SFU_SLOT_UDP_WIDTH - 1,
|
|
141
|
+
tcp: SFU_SLOT_TCP_BASE + slot,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
122
144
|
/**
|
|
123
145
|
* The host's private network on `vmbr1`, where the calls service reaches
|
|
124
146
|
* LiveKit's API directly (#127's "Human steps": VM 105 gets a second NIC on
|
|
@@ -176,6 +198,11 @@ const UNSCOPED_SIGNALLING_RULE_PATTERN = new RegExp(`^${LIVEKIT_SIGNALLING_PORT}
|
|
|
176
198
|
export function hasUnscopedSignallingRule(status) {
|
|
177
199
|
return UNSCOPED_SIGNALLING_RULE_PATTERN.test(status);
|
|
178
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* Where `cloudflared` serves its metrics, which include `/ready`. The image has no shell, so its check is
|
|
203
|
+
* the binary's own `tunnel ready` in exec form, and that command asks this address.
|
|
204
|
+
*/
|
|
205
|
+
const CLOUDFLARED_METRICS_ADDRESS = '127.0.0.1:20241';
|
|
179
206
|
/**
|
|
180
207
|
* `network_mode: host`: LiveKit's own self-hosting guide recommends this
|
|
181
208
|
* over mapping ten thousand individual UDP ports, and the SFU VM has no
|
|
@@ -193,13 +220,27 @@ export function dockerComposeYaml() {
|
|
|
193
220
|
volumes:
|
|
194
221
|
- ${LIVEKIT_CONFIG_PATH}:/etc/livekit.yaml:ro
|
|
195
222
|
command: --config /etc/livekit.yaml
|
|
223
|
+
healthcheck:
|
|
224
|
+
test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1:${LIVEKIT_SIGNALLING_PORT}/"]
|
|
225
|
+
interval: 30s
|
|
226
|
+
timeout: 5s
|
|
227
|
+
retries: 3
|
|
228
|
+
start_period: 30s
|
|
196
229
|
cloudflared:
|
|
197
230
|
image: ${CLOUDFLARED_IMAGE_REF}
|
|
198
231
|
restart: unless-stopped
|
|
199
232
|
network_mode: host
|
|
200
233
|
env_file:
|
|
201
234
|
- ${CLOUDFLARED_ENV_PATH}
|
|
235
|
+
environment:
|
|
236
|
+
TUNNEL_METRICS: ${CLOUDFLARED_METRICS_ADDRESS}
|
|
202
237
|
command: tunnel --no-autoupdate run
|
|
238
|
+
healthcheck:
|
|
239
|
+
test: ["CMD", "cloudflared", "tunnel", "--metrics", "${CLOUDFLARED_METRICS_ADDRESS}", "ready"]
|
|
240
|
+
interval: 30s
|
|
241
|
+
timeout: 5s
|
|
242
|
+
retries: 3
|
|
243
|
+
start_period: 30s
|
|
203
244
|
`;
|
|
204
245
|
}
|
|
205
246
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type { OrgId, MailMode, MailConfig, ChatConfig, CallsConfig, IssuerConfig, SiteConfig, IssuerAppKind, IssuerApp, HostingConfig, HostingEntry, EntryGate, HostingEntryUses, EntryAuth, EntryFiles, EntryAi, EnvValue, SsoConfig, GuestsConfig, SoloConfig, StorageConfig, AiConfig, BuyerAddress, BuyerIdentity, AdoptedAppForm, AdoptedApp, OwnerIdentity, OwnerMailbox, DeclaredOrg, OrgServiceSchema, } from './org.js';
|
|
2
|
-
export { APP_ENTRY_KEY, DEFAULT_GATE_LIMIT, FILES_ENTRY_PERMISSIONS, AI_ENTRY_PERMISSIONS, DEFAULT_MAIL_APPS, ORG_SERVICE_SCHEMAS, appEntry, ownerMailboxes, validateBuyerIdentity, validateHosting, validateMail, validateOwners, validateSite, } from './org.js';
|
|
1
|
+
export type { OrgId, MailMode, MailConfig, ChatConfig, CallsConfig, IssuerConfig, SiteConfig, IssuerAppKind, IssuerApp, HostingConfig, HostingEntry, EntryGate, HostingEntryUses, EntryAuth, EntryFiles, EntryAi, EnvValue, SsoConfig, GuestsConfig, SoloConfig, StorageConfig, AiConfig, BuyerAddress, BuyerIdentity, AdoptedAppForm, AdoptedApp, OwnerIdentity, OwnerMailbox, DeclaredOrg, OrgServiceSchema, ServicesConfig, } from './org.js';
|
|
2
|
+
export { APP_ENTRY_KEY, DEFAULT_GATE_LIMIT, FILES_ENTRY_PERMISSIONS, AI_ENTRY_PERMISSIONS, DEFAULT_MAIL_APPS, ORG_SERVICE_SCHEMAS, SFU_SLOT_MAX, appEntry, ownerMailboxes, ownsServices, validateBuyerIdentity, validateHosting, validateMail, validateOwners, validateServices, validateSite, } from './org.js';
|
|
3
3
|
export type { DeclaredPlatform, PlatformService, PlatformServiceKey, PlatformSfuService, } from './platform.js';
|
|
4
4
|
export { PLATFORM_SERVICE_KEYS, defaultPlatformHostname, validatePlatform, } from './platform.js';
|
|
5
5
|
import { type PinnedVersions } from './bootstrap/versions.js';
|
|
@@ -18,16 +18,22 @@ export { createPostgresAppliedVersionsStore, createPostgresDeclaredOrgStore, cre
|
|
|
18
18
|
export { createPostgresAuditLog } from './store/audit.js';
|
|
19
19
|
export type { FoundryStoreDb } from './store/postgres.js';
|
|
20
20
|
export { declaredOrgs, foundryAppliedState, foundryAppliedVersions, foundryAuditEvents, foundryDeclaredPlatform, foundryRequestedChanges, type AuditEventRow, type DeclaredOrgRow, type NewDeclaredOrgRow, type AppliedStateRow, type NewAppliedStateRow, type AppliedVersionRow, type NewAppliedVersionRow, type DeclaredPlatformRow, type NewDeclaredPlatformRow, type RequestedChangeRow, type NewRequestedChangeRow, } from './store/schema.js';
|
|
21
|
-
export type { LiveResource, ZitadelReader, CoolifyReader, CloudflareReader, FilesReader, AiReader, CmsReader, LiveReaders, PlatformCloudflareReader, PlatformCoolifyReader, PlatformLiveReaders, StepAction, PlannedStep, StepSystem, PlanDetail, OrgPostgresPlan, PlatformPlanDetail, AdoptCandidate, AdoptInput, AdoptPlan, AdoptSnapshot, AuditActor, AuditLog, AuthzGate, StepExecutor, StepDestroyer, DestroyTarget, StepExecutionContext, PlatformStepExecutor, PlatformStepExecutionContext, FoundryPlanApplyOptions, FoundryApplyOptions, UnconfirmedUpgrade, } from './plan/index.js';
|
|
21
|
+
export type { LiveResource, ZitadelReader, CoolifyReader, CloudflareReader, FilesReader, AiReader, CmsReader, LiveReaders, PlatformCloudflareReader, PlatformCoolifyReader, PlatformLiveReaders, StepAction, PlannedStep, StepSystem, PlanDetail, OrgPostgresPlan, PlatformPlanDetail, MailRoute, AdoptCandidate, AdoptInput, AdoptPlan, AdoptSnapshot, AuditActor, AuditLog, AuthzGate, StepExecutor, StepDestroyer, DestroyTarget, StepExecutionContext, PlatformStepExecutor, PlatformStepExecutionContext, FoundryPlanApplyOptions, FoundryApplyOptions, UnconfirmedUpgrade, } from './plan/index.js';
|
|
22
22
|
export { AdoptRefusedError } from './plan/index.js';
|
|
23
23
|
export { createEdgeAccess, createEdgeDns, edgeDnsRecordOwners, createEdgeRateLimits, createEdgeTunnels, createEdgeWorkers, createEdgeZones, } from './plan/index.js';
|
|
24
24
|
export type { AccessAppSummary, AccessDecision, AccessPolicyRule, AccessPort, DnsPort, EdgePlatformAccess, EdgePlatformDns, EdgePlatformRateLimits, EdgePlatformWorkers, EdgePlatformZones, EdgeZonesOptions, ZonePort, EdgeRateLimitsOptions, RateLimitPort, RateLimitRuleInput, EdgeWorkersOptions, EdgePlatformTunnels, TunnelPort, } from './plan/index.js';
|
|
25
25
|
export { readLiveResources, readLivePlatformResources, computePlanDetail, toPlan, planPlatform, toPlatformPlan, JOBS_INTERNAL_URL_SCOPE_KEY, JOBS_SCHEDULER_KEY, PLATFORM_AI_KEY, PLATFORM_AI_INTERNAL_URL_SCOPE_KEY, PLATFORM_AI_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_AI_ORGANISATION_SCOPE_KEY, PLATFORM_FILES_KEY, PLATFORM_FILES_INTERNAL_URL_SCOPE_KEY, PLATFORM_FILES_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_MAIL_INTERNAL_URL_SCOPE_KEY, PLATFORM_MAIL_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_EDGE_KEY, PLATFORM_EDGE_INTERNAL_URL_SCOPE_KEY, PLATFORM_EDGE_KEY_REF, PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF, PLATFORM_SFU_APPLIED_SCOPE_KEY, FoundryPlanApply, DeclaredOrgNotFoundError, StalePlanError, ConfirmationRequiredError, NotAuthorizedError, NotATestOrgError, DeclaredPlatformNotFoundError, PlatformStalePlanError, PlatformConfirmationRequiredError, UpgradeConfirmationRequiredError, planNeedsConfirmation, } from './plan/index.js';
|
|
26
26
|
export type { HeldKeyResolver, OrgPlatformReadiness } from './plan/index.js';
|
|
27
|
-
export { DEFAULT_ORG_PLATFORM_READINESS, ORG_PLATFORM_KEY_REFS, agoraHostValuesFromPlatform, heldPlatformKeyRefs, orgPlatformReadinessFrom, } from './plan/index.js';
|
|
27
|
+
export { DEFAULT_ORG_PLATFORM_READINESS, ORG_PLATFORM_KEY_REFS, agoraHostValuesForOwn, agoraHostValuesFromPlatform, heldOwnKeyRefs, heldPlatformKeyRefs, orgPlatformReadinessFor, orgPlatformReadinessFrom, } from './plan/index.js';
|
|
28
28
|
export type { PlatformOrgClientFactories } from './plan/index.js';
|
|
29
29
|
export { PlatformOrgBlockedError, PlatformOrgPorts } from './plan/index.js';
|
|
30
|
-
export type {
|
|
30
|
+
export type { FilesKeysMint, FilesKeysMinted, OwnFilesDeps, OwnFilesR2Key, OwnFilesR2Keys, OwnServicePorts, OwnServicesPort, OwnServicesProvision, OwnSfuDeps, ServiceTarget, } from './plan/index.js';
|
|
31
|
+
export { OWN_FILES_R2_SCOPE_KEY, OWN_FILES_R2_UNDELIVERED_SCOPE_KEY, OWN_SERVICES_APPLIED_SCOPE_KEY, OwnServicesBlockedError, orgTarget, } from './plan/index.js';
|
|
32
|
+
export type { FilesHostInput, JobsHostDeps, JobsHostInput, OwnAuthInstance, PlanOwnAuthOptions, PlanOwnFilesOptions, PlanOwnFilesR2Options, PlanOwnJobsOptions, } from './plan/index.js';
|
|
33
|
+
export { OWN_AUTH_APPLIED_GIT_REF_SCOPE_KEY, OWN_AUTH_APPLIED_HOSTNAME_SCOPE_KEY, OWN_AUTH_BLOCKED_KEY, OWN_FILES_BLOCKED_KEY, OWN_FILES_R2_BLOCKED_KEY, OWN_JOBS_BLOCKED_KEY, OWN_MAIL_BLOCKED_KEY, planOwnAuth, planOwnFiles, planOwnFilesR2, planOwnJobs, planOwnMail, provisionFilesHost, provisionJobsHost, provisionMailServer, } from './plan/index.js';
|
|
34
|
+
export type { PlanOwnSfuOptions, SfuAppDeps, SfuAppInput } from './plan/index.js';
|
|
35
|
+
export { OWN_SFU_BLOCKED_KEY, OWN_SFU_FIREWALL_KEY, planOwnSfu, provisionSfuApp, sfuConfig, sfuPortsMappings, } from './plan/index.js';
|
|
36
|
+
export type { CoolifyPort, CloudflarePort, ZitadelPort, CallsSfuPort, JobsSchedulerPort, FilesOrganisationPort, AiOrganisationPort, FoundryStepExecutorPorts, PlatformOrgPortSource, AgoraHostPort, AgoraHostValues, LoginHostBinding, LoginHostBindingsPort, LoginHostDiscoveryPort, } from './plan/index.js';
|
|
31
37
|
export { FoundryStepExecutor, NotBuiltError, healthUrls, loginHostnameFor } from './plan/index.js';
|
|
32
38
|
export type { EnsureSignInOrgOptions } from './plan/index.js';
|
|
33
39
|
export { ZITADEL_ORG_DOMAIN_SCOPE_KEY, ensureSignInOrg, registerSignInDomain, signInOrgDomain, } from './plan/index.js';
|
|
@@ -42,7 +48,7 @@ export type { MailIdentityApp, MailIdentityAudienceCheck } from './plan/index.js
|
|
|
42
48
|
export { checkMailIdentityAudience } from './plan/index.js';
|
|
43
49
|
export type { MailAllowlistApp } from './plan/index.js';
|
|
44
50
|
export { checkMailAppsAllowlist } from './plan/index.js';
|
|
45
|
-
export { FoundryPlatformStepExecutor, ProvidersPlatformCloudflareReader, ProvidersPlatformCoolifyReader, createZitadelAdminMinter, createZitadelLoginPolicy, createZitadelProjectRoles, PLATFORM_AUTH_KEY, PLATFORM_MAIL_KEY, PLATFORM_MAIL_ADMIN_KEY_DESCRIPTION, } from './plan/index.js';
|
|
51
|
+
export { FoundryPlatformStepExecutor, ProvidersPlatformCloudflareReader, ProvidersPlatformCoolifyReader, createZitadelAdminMinter, createZitadelLoginPolicy, createZitadelProjectRoles, PLATFORM_AUTH_KEY, PLATFORM_MAIL_KEY, PLATFORM_MAIL_RELAY_KEY, PLATFORM_MAIL_RELAY_ROUTES_SCOPE_KEY, PLATFORM_MAIL_ADMIN_KEY_DESCRIPTION, } from './plan/index.js';
|
|
46
52
|
export type { PlatformAuthDeps, PlatformAuthSmtp, PlatformAuthRuntime, PlatformFilesDeps, PlatformFilesRuntime, PlatformEdgeDeps, PlatformDnsFactory, PlatformAccessFactory, PlatformUptimeAccessFactory, PlatformUptimeAccessPort, PlatformUptimeDeps, PlatformWorkersFactory, PlatformWorkersPort, PlatformAccessPort, PlatformTunnelsFactory, PlatformEdgeRuntime, } from './plan/index.js';
|
|
47
53
|
export type { PlatformMailDeps, PlatformMailAdminPort, PlatformMailRuntime, } from './plan/index.js';
|
|
48
54
|
export { FILES_INTROSPECTION_SECRET_REF, FILES_MANAGEMENT_ISSUER, FILES_MANAGEMENT_KEY_ID, FILES_MANAGEMENT_KEY_REF, PLATFORM_AUTH_INSTANCE_BEARER_REF, } from './plan/index.js';
|
|
@@ -68,3 +74,5 @@ export type { RunnerDb } from './runner/db.js';
|
|
|
68
74
|
export { AlreadyRunningError, RunNotFoundError, StepFailedError, StepMismatchError, } from './runner/errors.js';
|
|
69
75
|
export { createJobRunner } from './runner/runner.js';
|
|
70
76
|
export type { CreateJobRunnerOptions, JobRunner, RunFailure, RunRecord, RunStatus, RunStepsOptions, RunnerStep, } from './runner/types.js';
|
|
77
|
+
export type { StoredApp } from './plan/health-gaps.js';
|
|
78
|
+
export { EXIT_JOBS, REPO_DOCKERFILE_CHECKED, hasRealCheck, healthGaps, } from './plan/health-gaps.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { APP_ENTRY_KEY, DEFAULT_GATE_LIMIT, FILES_ENTRY_PERMISSIONS, AI_ENTRY_PERMISSIONS, DEFAULT_MAIL_APPS, ORG_SERVICE_SCHEMAS, appEntry, ownerMailboxes, validateBuyerIdentity, validateHosting, validateMail, validateOwners, validateSite, } from './org.js';
|
|
1
|
+
export { APP_ENTRY_KEY, DEFAULT_GATE_LIMIT, FILES_ENTRY_PERMISSIONS, AI_ENTRY_PERMISSIONS, DEFAULT_MAIL_APPS, ORG_SERVICE_SCHEMAS, SFU_SLOT_MAX, appEntry, ownerMailboxes, ownsServices, validateBuyerIdentity, validateHosting, validateMail, validateOwners, validateServices, validateSite, } from './org.js';
|
|
2
2
|
export { PLATFORM_SERVICE_KEYS, defaultPlatformHostname, validatePlatform, } from './platform.js';
|
|
3
3
|
// archon#273: the pinned platform service versions the planner deploys, so a
|
|
4
4
|
// host can show declared against running. Readonly: it is the planner's own
|
|
@@ -14,8 +14,11 @@ export { declaredOrgs, foundryAppliedState, foundryAppliedVersions, foundryAudit
|
|
|
14
14
|
export { AdoptRefusedError } from './plan/index.js';
|
|
15
15
|
export { createEdgeAccess, createEdgeDns, edgeDnsRecordOwners, createEdgeRateLimits, createEdgeTunnels, createEdgeWorkers, createEdgeZones, } from './plan/index.js';
|
|
16
16
|
export { readLiveResources, readLivePlatformResources, computePlanDetail, toPlan, planPlatform, toPlatformPlan, JOBS_INTERNAL_URL_SCOPE_KEY, JOBS_SCHEDULER_KEY, PLATFORM_AI_KEY, PLATFORM_AI_INTERNAL_URL_SCOPE_KEY, PLATFORM_AI_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_AI_ORGANISATION_SCOPE_KEY, PLATFORM_FILES_KEY, PLATFORM_FILES_INTERNAL_URL_SCOPE_KEY, PLATFORM_FILES_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_MAIL_INTERNAL_URL_SCOPE_KEY, PLATFORM_MAIL_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_EDGE_KEY, PLATFORM_EDGE_INTERNAL_URL_SCOPE_KEY, PLATFORM_EDGE_KEY_REF, PLATFORM_EDGE_CLOUDFLARE_TOKEN_REF, PLATFORM_SFU_APPLIED_SCOPE_KEY, FoundryPlanApply, DeclaredOrgNotFoundError, StalePlanError, ConfirmationRequiredError, NotAuthorizedError, NotATestOrgError, DeclaredPlatformNotFoundError, PlatformStalePlanError, PlatformConfirmationRequiredError, UpgradeConfirmationRequiredError, planNeedsConfirmation, } from './plan/index.js';
|
|
17
|
-
export { DEFAULT_ORG_PLATFORM_READINESS, ORG_PLATFORM_KEY_REFS, agoraHostValuesFromPlatform, heldPlatformKeyRefs, orgPlatformReadinessFrom, } from './plan/index.js';
|
|
17
|
+
export { DEFAULT_ORG_PLATFORM_READINESS, ORG_PLATFORM_KEY_REFS, agoraHostValuesForOwn, agoraHostValuesFromPlatform, heldOwnKeyRefs, heldPlatformKeyRefs, orgPlatformReadinessFor, orgPlatformReadinessFrom, } from './plan/index.js';
|
|
18
18
|
export { PlatformOrgBlockedError, PlatformOrgPorts } from './plan/index.js';
|
|
19
|
+
export { OWN_FILES_R2_SCOPE_KEY, OWN_FILES_R2_UNDELIVERED_SCOPE_KEY, OWN_SERVICES_APPLIED_SCOPE_KEY, OwnServicesBlockedError, orgTarget, } from './plan/index.js';
|
|
20
|
+
export { OWN_AUTH_APPLIED_GIT_REF_SCOPE_KEY, OWN_AUTH_APPLIED_HOSTNAME_SCOPE_KEY, OWN_AUTH_BLOCKED_KEY, OWN_FILES_BLOCKED_KEY, OWN_FILES_R2_BLOCKED_KEY, OWN_JOBS_BLOCKED_KEY, OWN_MAIL_BLOCKED_KEY, planOwnAuth, planOwnFiles, planOwnFilesR2, planOwnJobs, planOwnMail, provisionFilesHost, provisionJobsHost, provisionMailServer, } from './plan/index.js';
|
|
21
|
+
export { OWN_SFU_BLOCKED_KEY, OWN_SFU_FIREWALL_KEY, planOwnSfu, provisionSfuApp, sfuConfig, sfuPortsMappings, } from './plan/index.js';
|
|
19
22
|
export { FoundryStepExecutor, NotBuiltError, healthUrls, loginHostnameFor } from './plan/index.js';
|
|
20
23
|
export { ZITADEL_ORG_DOMAIN_SCOPE_KEY, ensureSignInOrg, registerSignInDomain, signInOrgDomain, } from './plan/index.js';
|
|
21
24
|
export { HttpJobsSchedulerClient } from './plan/index.js';
|
|
@@ -24,7 +27,7 @@ export { ProvidersAiReader, ProvidersCloudflareReader, ProvidersCmsReader, Provi
|
|
|
24
27
|
export { adaptZitadelListApps } from './plan/index.js';
|
|
25
28
|
export { checkMailIdentityAudience } from './plan/index.js';
|
|
26
29
|
export { checkMailAppsAllowlist } from './plan/index.js';
|
|
27
|
-
export { FoundryPlatformStepExecutor, ProvidersPlatformCloudflareReader, ProvidersPlatformCoolifyReader, createZitadelAdminMinter, createZitadelLoginPolicy, createZitadelProjectRoles, PLATFORM_AUTH_KEY, PLATFORM_MAIL_KEY, PLATFORM_MAIL_ADMIN_KEY_DESCRIPTION, } from './plan/index.js';
|
|
30
|
+
export { FoundryPlatformStepExecutor, ProvidersPlatformCloudflareReader, ProvidersPlatformCoolifyReader, createZitadelAdminMinter, createZitadelLoginPolicy, createZitadelProjectRoles, PLATFORM_AUTH_KEY, PLATFORM_MAIL_KEY, PLATFORM_MAIL_RELAY_KEY, PLATFORM_MAIL_RELAY_ROUTES_SCOPE_KEY, PLATFORM_MAIL_ADMIN_KEY_DESCRIPTION, } from './plan/index.js';
|
|
28
31
|
export { FILES_INTROSPECTION_SECRET_REF, FILES_MANAGEMENT_ISSUER, FILES_MANAGEMENT_KEY_ID, FILES_MANAGEMENT_KEY_REF, PLATFORM_AUTH_INSTANCE_BEARER_REF, } from './plan/index.js';
|
|
29
32
|
export { AI_MANAGEMENT_ISSUER, AI_MANAGEMENT_KEY_ID, AI_SIGNING_KEY_REF, AiManagementKeyExistsError, createAiManagementKeyMinter, PLATFORM_AI_MANAGEMENT_KEY_REF, PLATFORM_AI_MANAGEMENT_PERMISSIONS, } from './plan/index.js';
|
|
30
33
|
export { MissingCallsSfuConnectionError, applyCallsSfuPlatformStep, callsSfuAppliedFingerprint, } from './plan/index.js';
|
|
@@ -40,3 +43,4 @@ export { bootstrapPlatform } from './bootstrap/index.js';
|
|
|
40
43
|
export { readPlatformVersionStatus, wtfalchVersionsFromPnpmLockfile, providersStatusCoolifyPort, ghCliStatusGithubPort, } from './plan/index.js';
|
|
41
44
|
export { AlreadyRunningError, RunNotFoundError, StepFailedError, StepMismatchError, } from './runner/errors.js';
|
|
42
45
|
export { createJobRunner } from './runner/runner.js';
|
|
46
|
+
export { EXIT_JOBS, REPO_DOCKERFILE_CHECKED, hasRealCheck, healthGaps, } from './plan/health-gaps.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- @wtfalch/foundry: a company's own services. `services_own` true gives the
|
|
2
|
+
-- org its own sign-in, mail, files, jobs and calls SFU; false (the default)
|
|
3
|
+
-- keeps the platform's shared ones. `services_sfu_slot` is the slice of the
|
|
4
|
+
-- server's SFU ports an own org's media server takes; no two orgs share one.
|
|
5
|
+
-- Mirrors src/store/schema.ts's `declaredOrgs` table additions.
|
|
6
|
+
|
|
7
|
+
alter table foundry_declared_orgs
|
|
8
|
+
add column if not exists services_own boolean not null default false,
|
|
9
|
+
add column if not exists services_sfu_slot integer;
|
|
10
|
+
|
|
11
|
+
create unique index if not exists foundry_declared_orgs_sfu_slot_idx
|
|
12
|
+
on foundry_declared_orgs (services_sfu_slot)
|
|
13
|
+
where services_sfu_slot is not null;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-- @wtfalch/foundry: `mail_relay` true puts one shared relay container on host
|
|
2
|
+
-- port 25, which routes each message by recipient domain to a company's own
|
|
3
|
+
-- mail server or to the platform's; false (the default) keeps the platform
|
|
4
|
+
-- Stalwart bound to port 25 directly. Mirrors src/store/schema.ts's
|
|
5
|
+
-- `foundryDeclaredPlatform` table addition.
|
|
6
|
+
|
|
7
|
+
alter table foundry_declared_platform
|
|
8
|
+
add column if not exists mail_relay boolean not null default false;
|
package/dist/org.d.ts
CHANGED
|
@@ -548,6 +548,22 @@ export declare function validateSite(org: DeclaredOrg): string | null;
|
|
|
548
548
|
* reason to pin at all.
|
|
549
549
|
*/
|
|
550
550
|
export declare function validateCalls(org: DeclaredOrg): string | null;
|
|
551
|
+
/** A company with a domain runs its own sign-in, mail, files, jobs and calls SFU in its own containers. */
|
|
552
|
+
export interface ServicesConfig {
|
|
553
|
+
/** true: own copies of the services. false (default): the platform's shared ones. */
|
|
554
|
+
own: boolean;
|
|
555
|
+
/**
|
|
556
|
+
* Which slice of the server's SFU ports this company's media server takes.
|
|
557
|
+
* Required when `own` and `calls.enabled`. 1 to {@link SFU_SLOT_MAX}.
|
|
558
|
+
* Slice n holds UDP (50000 + (n-1)*500) .. (50000 + n*500 - 1) and TCP 7881 + n.
|
|
559
|
+
*/
|
|
560
|
+
sfuSlot?: number | null;
|
|
561
|
+
}
|
|
562
|
+
export declare const SFU_SLOT_MAX = 20;
|
|
563
|
+
/** The only reader of `services.own`: an org without `services` runs the platform's shared services. */
|
|
564
|
+
export declare function ownsServices(org: Pick<DeclaredOrg, 'services'>): boolean;
|
|
565
|
+
/** The pure part of the `services` rules; that no two orgs share an `sfuSlot` is the store's check. */
|
|
566
|
+
export declare function validateServices(org: DeclaredOrg): string | null;
|
|
551
567
|
/**
|
|
552
568
|
* Per-org SSO. Decided to exist in #14 ("Also in scope") and its resolved
|
|
553
569
|
* research #3 ("per-org SSO code exists unused"); nothing about its
|
|
@@ -822,6 +838,8 @@ export interface DeclaredOrg {
|
|
|
822
838
|
site: SiteConfig;
|
|
823
839
|
/** `enabled: false`, `issuerApps: []` by default -- a brand new org has no hosted app (#71). */
|
|
824
840
|
hosting: HostingConfig;
|
|
841
|
+
/** Absent means `{ own: false }`. Optional so every existing literal and test fixture compiles unchanged, as `calls.versionPin` and `MailConfig.mailApps` do. */
|
|
842
|
+
services?: ServicesConfig;
|
|
825
843
|
sso: SsoConfig;
|
|
826
844
|
guests: GuestsConfig;
|
|
827
845
|
solo: SoloConfig;
|
package/dist/org.js
CHANGED
|
@@ -706,6 +706,32 @@ export function validateCalls(org) {
|
|
|
706
706
|
}
|
|
707
707
|
return null;
|
|
708
708
|
}
|
|
709
|
+
export const SFU_SLOT_MAX = 20;
|
|
710
|
+
/** The only reader of `services.own`: an org without `services` runs the platform's shared services. */
|
|
711
|
+
export function ownsServices(org) {
|
|
712
|
+
return org.services?.own === true;
|
|
713
|
+
}
|
|
714
|
+
/** The pure part of the `services` rules; that no two orgs share an `sfuSlot` is the store's check. */
|
|
715
|
+
export function validateServices(org) {
|
|
716
|
+
const slot = org.services?.sfuSlot ?? null;
|
|
717
|
+
if (!ownsServices(org)) {
|
|
718
|
+
return slot === null ? null : 'services.sfuSlot needs services.own';
|
|
719
|
+
}
|
|
720
|
+
if (org.domain === null) {
|
|
721
|
+
return "services.own needs the org's own domain: the issuer is auth.<domain>";
|
|
722
|
+
}
|
|
723
|
+
if (!org.issuer.usesDomain) {
|
|
724
|
+
return 'services.own needs issuer.usesDomain: the issuer is auth.<domain>';
|
|
725
|
+
}
|
|
726
|
+
if (org.mail.mode !== 'off' && !org.mail.usesDomain) {
|
|
727
|
+
return "services.own needs mail.usesDomain: the company's mail server serves its own domain";
|
|
728
|
+
}
|
|
729
|
+
if (org.calls.enabled &&
|
|
730
|
+
(slot === null || !Number.isInteger(slot) || slot < 1 || slot > SFU_SLOT_MAX)) {
|
|
731
|
+
return `services.sfuSlot must be an integer from 1 to ${SFU_SLOT_MAX} when calls are enabled`;
|
|
732
|
+
}
|
|
733
|
+
return null;
|
|
734
|
+
}
|
|
709
735
|
const ORG_NUMBER_PATTERN = /^\d{9}$/;
|
|
710
736
|
/**
|
|
711
737
|
* `null` when `buyer` is valid; otherwise the reason it is not, for a caller
|
|
@@ -47,6 +47,15 @@
|
|
|
47
47
|
export declare const SYNAPSE_IMAGE = "ghcr.io/element-hq/synapse";
|
|
48
48
|
export declare const SYNAPSE_TAG: string;
|
|
49
49
|
export declare const MAS_IMAGE: string;
|
|
50
|
+
/** MAS listens here in both the calls and the chat config (`http.listeners[0].binds`). */
|
|
51
|
+
export declare const MAS_PORT = 8080;
|
|
52
|
+
/**
|
|
53
|
+
* The inline Dockerfile of a MAS app: the published image plus its entry command. That image is distroless: no
|
|
54
|
+
* shell and no HTTP client, so Coolify's own check (always `sh -c`) cannot run in it. A static busybox is copied in
|
|
55
|
+
* and an exec-form HEALTHCHECK asks MAS's `/health` (a `SELECT 1` on its database). Coolify keeps a Dockerfile's
|
|
56
|
+
* HEALTHCHECK when its own check is off (`health_check_enabled: false`).
|
|
57
|
+
*/
|
|
58
|
+
export declare function masDockerfile(): string;
|
|
50
59
|
/** #251: the version baked into {@link MAS_IMAGE}'s `FROM` line, named on its own so a version-change line can read it without re-parsing the image string. */
|
|
51
60
|
export declare const MAS_TAG: string;
|
|
52
61
|
/**
|
|
@@ -49,6 +49,23 @@ import { VERSIONS } from '../bootstrap/versions.js';
|
|
|
49
49
|
export const SYNAPSE_IMAGE = 'ghcr.io/element-hq/synapse';
|
|
50
50
|
export const SYNAPSE_TAG = VERSIONS.synapse;
|
|
51
51
|
export const MAS_IMAGE = `ghcr.io/element-hq/matrix-authentication-service:${VERSIONS.mas}`;
|
|
52
|
+
/** MAS listens here in both the calls and the chat config (`http.listeners[0].binds`). */
|
|
53
|
+
export const MAS_PORT = 8080;
|
|
54
|
+
/**
|
|
55
|
+
* The inline Dockerfile of a MAS app: the published image plus its entry command. That image is distroless: no
|
|
56
|
+
* shell and no HTTP client, so Coolify's own check (always `sh -c`) cannot run in it. A static busybox is copied in
|
|
57
|
+
* and an exec-form HEALTHCHECK asks MAS's `/health` (a `SELECT 1` on its database). Coolify keeps a Dockerfile's
|
|
58
|
+
* HEALTHCHECK when its own check is off (`health_check_enabled: false`).
|
|
59
|
+
*/
|
|
60
|
+
export function masDockerfile() {
|
|
61
|
+
return [
|
|
62
|
+
`FROM busybox:${VERSIONS.busybox} AS busybox`,
|
|
63
|
+
`FROM ${MAS_IMAGE}`,
|
|
64
|
+
'COPY --from=busybox /bin/busybox /busybox',
|
|
65
|
+
'CMD ["server", "--config", "/config/config.yaml"]',
|
|
66
|
+
`HEALTHCHECK --interval=15s --timeout=5s --start-period=30s --retries=3 CMD ["/busybox", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:${MAS_PORT}/health"]`,
|
|
67
|
+
].join('\n');
|
|
68
|
+
}
|
|
52
69
|
/** #251: the version baked into {@link MAS_IMAGE}'s `FROM` line, named on its own so a version-change line can read it without re-parsing the image string. */
|
|
53
70
|
export const MAS_TAG = VERSIONS.mas;
|
|
54
71
|
/**
|
|
@@ -7,6 +7,12 @@ import type { CoolifyPort } from './executor.js';
|
|
|
7
7
|
* `versions.json` (#247).
|
|
8
8
|
*/
|
|
9
9
|
export declare const CLOUDFLARED_IMAGE_REF: string;
|
|
10
|
+
/**
|
|
11
|
+
* Where the connector serves its metrics, which include `/ready` (200 with at least one edge connection, else 503).
|
|
12
|
+
* The image is distroless, so its check is the binary's own `tunnel ready` in exec form: a Dockerfile HEALTHCHECK,
|
|
13
|
+
* kept by Coolify while its own check is off. The port is not published; only the container network reaches it.
|
|
14
|
+
*/
|
|
15
|
+
export declare const CLOUDFLARED_METRICS_PORT = 20241;
|
|
10
16
|
/**
|
|
11
17
|
* The inline Dockerfile a docker-image `cloudflared` app needs, copied from
|
|
12
18
|
* `scripts/shared-ingress.mjs`'s `cloudflaredDockerfile()`: the published
|
|
@@ -24,7 +30,7 @@ export declare function cloudflaredDockerfile(): string;
|
|
|
24
30
|
* archon) calls this once with its own app name and scope key.
|
|
25
31
|
*/
|
|
26
32
|
export interface EnsureCloudflaredConnectorInput {
|
|
27
|
-
coolify: Pick<CoolifyPort, 'findApplicationByName' | 'getApplication' | 'createDockerfileApplication' | 'bulkUpsertEnvs' | 'listEnvs' | 'deploy'>;
|
|
33
|
+
coolify: Pick<CoolifyPort, 'findApplicationByName' | 'getApplication' | 'createDockerfileApplication' | 'updateApplication' | 'bulkUpsertEnvs' | 'listEnvs' | 'deploy'>;
|
|
28
34
|
tunnels: Pick<TunnelPort, 'getTunnelToken'>;
|
|
29
35
|
/** The Cloudflare tunnel this connector dials into (already created and configured by the caller). */
|
|
30
36
|
tunnelId: string;
|
|
@@ -7,6 +7,12 @@ import { isNotFoundError } from './executor.js';
|
|
|
7
7
|
* `versions.json` (#247).
|
|
8
8
|
*/
|
|
9
9
|
export const CLOUDFLARED_IMAGE_REF = `cloudflare/cloudflared:${VERSIONS.cloudflared}`;
|
|
10
|
+
/**
|
|
11
|
+
* Where the connector serves its metrics, which include `/ready` (200 with at least one edge connection, else 503).
|
|
12
|
+
* The image is distroless, so its check is the binary's own `tunnel ready` in exec form: a Dockerfile HEALTHCHECK,
|
|
13
|
+
* kept by Coolify while its own check is off. The port is not published; only the container network reaches it.
|
|
14
|
+
*/
|
|
15
|
+
export const CLOUDFLARED_METRICS_PORT = 20241;
|
|
10
16
|
/**
|
|
11
17
|
* The inline Dockerfile a docker-image `cloudflared` app needs, copied from
|
|
12
18
|
* `scripts/shared-ingress.mjs`'s `cloudflaredDockerfile()`: the published
|
|
@@ -17,7 +23,12 @@ export const CLOUDFLARED_IMAGE_REF = `cloudflare/cloudflared:${VERSIONS.cloudfla
|
|
|
17
23
|
* variable `cloudflared` reads at boot.
|
|
18
24
|
*/
|
|
19
25
|
export function cloudflaredDockerfile() {
|
|
20
|
-
return
|
|
26
|
+
return [
|
|
27
|
+
`FROM ${CLOUDFLARED_IMAGE_REF}`,
|
|
28
|
+
`CMD ["tunnel", "--no-autoupdate", "--metrics", "0.0.0.0:${CLOUDFLARED_METRICS_PORT}", "run"]`,
|
|
29
|
+
`HEALTHCHECK --interval=15s --timeout=5s --start-period=30s --retries=3 CMD ["cloudflared", "tunnel", "--metrics", "127.0.0.1:${CLOUDFLARED_METRICS_PORT}", "ready"]`,
|
|
30
|
+
'',
|
|
31
|
+
].join('\n');
|
|
21
32
|
}
|
|
22
33
|
/**
|
|
23
34
|
* Finds or creates the one Coolify app that runs `cloudflared` for
|
|
@@ -79,6 +90,8 @@ export async function ensureCloudflaredConnector(input) {
|
|
|
79
90
|
});
|
|
80
91
|
appId = created.uuid;
|
|
81
92
|
justCreated = true;
|
|
93
|
+
// Before the first deploy: Coolify reads the Dockerfile's HEALTHCHECK only while its own check is off.
|
|
94
|
+
await coolify.updateApplication(appId, { health_check_enabled: false });
|
|
82
95
|
}
|
|
83
96
|
if (appId !== input.recordedConnectorAppId)
|
|
84
97
|
await input.recordAppId(appId);
|
package/dist/plan/diff.d.ts
CHANGED
|
@@ -43,6 +43,8 @@ export interface DraftStep {
|
|
|
43
43
|
export interface PlanOrgOptions {
|
|
44
44
|
/** #267: the executor was built with a `loginHostBindings` port. */
|
|
45
45
|
loginHostBindings?: boolean;
|
|
46
|
+
/** A live read said the org's login host serves OIDC discovery as `https://<host>`. Absent: not read, so Agora keeps the platform issuer. */
|
|
47
|
+
loginHostServesDiscovery?: boolean;
|
|
46
48
|
/** The executor's ZITADEL client has `updateOidcAppIdTokenUserinfoAssertion`; without it `planIdTokenUserinfo` plans nothing. */
|
|
47
49
|
zitadelIdTokenUserinfo?: boolean;
|
|
48
50
|
/** F5: the executor was built with a `broker` port. */
|
|
@@ -59,6 +61,33 @@ export interface PlanOrgOptions {
|
|
|
59
61
|
ownerInviteMail?: boolean;
|
|
60
62
|
/** The platform's own service hostnames: `edgeReservedLabels` reserves them under the org's domain, and a wildcard Worker route (`planWorkers`) keeps them out. */
|
|
61
63
|
platformHostnames?: readonly string[];
|
|
64
|
+
/** The executor was built with an `ownServices` port. Without it an own org's own-service steps are blocked. */
|
|
65
|
+
ownServices?: boolean;
|
|
66
|
+
/** An own org's Lettermint key (`orgTarget(org).refs.brokerMailKey`) is held. */
|
|
67
|
+
ownMailKeyHeld?: boolean;
|
|
68
|
+
/** The executor can mint an own org's Lettermint key (`FoundryStepExecutor.ownMailKeyMintable`). */
|
|
69
|
+
ownMailKeyMintable?: boolean;
|
|
70
|
+
/** The own jobs admin token's held-key ref holds a value. */
|
|
71
|
+
ownJobsTokenHeld?: boolean;
|
|
72
|
+
/** The own media server's key pair ref holds a value. */
|
|
73
|
+
ownSfuKeysHeld?: boolean;
|
|
74
|
+
/** The relay is declared and has applied a route list; an own org's mail server waits for it. */
|
|
75
|
+
mailRelayApplied?: boolean;
|
|
76
|
+
/** The host confirmed the ports of an own org's media server slot are open on the server. */
|
|
77
|
+
sfuPortsOpen?: boolean;
|
|
78
|
+
/** What the executor's own files dependencies supply: valid keys worker settings, and a bucket port. Absent counts as neither. */
|
|
79
|
+
ownFilesDeps?: {
|
|
80
|
+
keys: boolean;
|
|
81
|
+
bucket: boolean;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Which ports the own files storage key step needs the host supplied. Absent: the executor was not
|
|
85
|
+
* asked, and the step is neither planned nor reported.
|
|
86
|
+
*/
|
|
87
|
+
ownFilesR2Ports?: {
|
|
88
|
+
r2Keys: boolean;
|
|
89
|
+
storeR2Credentials: boolean;
|
|
90
|
+
};
|
|
62
91
|
}
|
|
63
92
|
export interface PlanDetail {
|
|
64
93
|
orgId: OrgId;
|