@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
package/dist/plan/own-diff.js
CHANGED
|
@@ -4,8 +4,9 @@ import { SFU_SLOT_MAX, ownsServices } from '../org.js';
|
|
|
4
4
|
import { ZITADEL_ORG_SCOPE_KEY } from './agora.js';
|
|
5
5
|
import { brokerEntryAppliedScopeKey } from './broker-entries.js';
|
|
6
6
|
import { ZITADEL_FILES_PROJECT_SCOPE_KEY } from './core-files.js';
|
|
7
|
-
import { ownAuthApplied } from './login-host.js';
|
|
8
|
-
import { OWN_MAIL_SMTP_INTERNAL_SCOPE_KEY } from './mail-relay.js';
|
|
7
|
+
import { OWN_AUTH_APPLIED_HOSTNAME_SCOPE_KEY, ownAuthApplied } from './login-host.js';
|
|
8
|
+
import { OWN_MAIL_SMTP_INTERNAL_SCOPE_KEY, OWN_MAIL_SMTP_PORT_BASE, OWN_MAIL_SMTP_PORT_SCOPE_KEY, isOwnMailSmtpPort, } from './mail-relay.js';
|
|
9
|
+
import { ownHostnames } from './own-hostnames.js';
|
|
9
10
|
import { OWN_FILES_R2_SCOPE_KEY, OWN_SERVICES_APPLIED_SCOPE_KEY, orgTarget, } from './own-services.js';
|
|
10
11
|
import { OWN_SFU_APPLIED_HOSTNAME_SCOPE_KEY, OWN_SFU_APPLIED_SLOT_SCOPE_KEY, OWN_SFU_APPLIED_VERSION_SCOPE_KEY, OWN_SFU_DEPLOY_PENDING_SCOPE_KEY, OWN_SFU_KEYS_UNDELIVERED_SCOPE_KEY, SFU_INTERNAL_URL_SCOPE_KEY, SFU_PUBLIC_URL_SCOPE_KEY, } from './own-sfu.js';
|
|
11
12
|
import { AUTH_ZITADEL_RUN_OPTIONS, JOBS_DEPLOY_PENDING_SCOPE_KEY, JOBS_INTERNAL_URL_SCOPE_KEY, PLATFORM_AUTH_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_ADMIN_USER_SCOPE_KEY, PLATFORM_AUTH_BROKER_SCOPE_KEY, PLATFORM_AUTH_CONNECTOR_APP_SCOPE_KEY, PLATFORM_AUTH_INSTANCE_SCOPE_KEY, PLATFORM_AUTH_INSTANCE_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_LOGIN_CLIENT_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_LOGIN_CLIENT_USER_SCOPE_KEY, PLATFORM_AUTH_SMTP_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_RUN_OPTIONS_SCOPE_KEY, PLATFORM_FILES_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_FILES_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_FILES_INTERNAL_URL_SCOPE_KEY, PLATFORM_FILES_INTROSPECTION_SCOPE_KEY, PLATFORM_FILES_INTROSPECTION_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_FILES_MANAGEMENT_UNDELIVERED_SCOPE_KEY, PLATFORM_MAIL_ADMIN_KEY_SCOPE_KEY, PLATFORM_MAIL_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_MAIL_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_MAIL_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_MAIL_INTERNAL_URL_SCOPE_KEY, platformMailMxHost, } from './platform-diff.js';
|
|
@@ -21,13 +22,10 @@ export const OWN_JOBS_BLOCKED_KEY = 'own-jobs';
|
|
|
21
22
|
* blocked line is fixed text: it is part of the stale-plan comparison.
|
|
22
23
|
*/
|
|
23
24
|
export function planOwnJobs(options) {
|
|
24
|
-
const { org, recordedIds, readiness,
|
|
25
|
+
const { org, recordedIds, readiness, ownServices } = options;
|
|
25
26
|
if (!ownsServices(org))
|
|
26
27
|
return { step: null, blocked: null };
|
|
27
28
|
const blocked = (line) => ({ step: null, blocked: line });
|
|
28
|
-
if (isPlatformOrg) {
|
|
29
|
-
return blocked(`${org.slug} cannot run its own services: it is the platform's own org`);
|
|
30
|
-
}
|
|
31
29
|
const undelivered = recordedIds[JOBS_ADMIN_TOKEN_UNDELIVERED_SCOPE_KEY];
|
|
32
30
|
if (undelivered && !options.tokenHeld) {
|
|
33
31
|
return blocked(`${org.slug}'s own jobs scheduler admin token for app ${undelivered} was minted but not confirmed delivered; remove the recorded key ${JOBS_ADMIN_TOKEN_UNDELIVERED_SCOPE_KEY} to mint a new one`);
|
|
@@ -66,8 +64,7 @@ export function planOwnJobs(options) {
|
|
|
66
64
|
const BROKER_ENTRY_APPLIED_PREFIX = brokerEntryAppliedScopeKey('');
|
|
67
65
|
/** `unmanaged` key of the one line `planOwnAuth` reports. */
|
|
68
66
|
export const OWN_AUTH_BLOCKED_KEY = 'own-auth';
|
|
69
|
-
|
|
70
|
-
export const OWN_AUTH_APPLIED_HOSTNAME_SCOPE_KEY = 'own_auth_applied_hostname';
|
|
67
|
+
export { OWN_AUTH_APPLIED_HOSTNAME_SCOPE_KEY };
|
|
71
68
|
/** The auth git ref an own org's sign-in last deployed, so a changed declared ref plans the step again. */
|
|
72
69
|
export const OWN_AUTH_APPLIED_GIT_REF_SCOPE_KEY = 'own_auth_applied_git_ref';
|
|
73
70
|
/**
|
|
@@ -80,14 +77,18 @@ export const OWN_AUTH_APPLIED_GIT_REF_SCOPE_KEY = 'own_auth_applied_git_ref';
|
|
|
80
77
|
* text: it is part of the stale-plan comparison.
|
|
81
78
|
*/
|
|
82
79
|
export function planOwnAuth(options) {
|
|
83
|
-
const { org, recordedIds, readiness,
|
|
84
|
-
|
|
85
|
-
if (!ownsServices(org) || isPlatformOrg || !org.domain)
|
|
80
|
+
const { org, recordedIds, readiness, ownServices } = options;
|
|
81
|
+
if (!ownsServices(org))
|
|
86
82
|
return { step: null, blocked: null };
|
|
87
83
|
const blocked = (reason) => ({
|
|
88
84
|
step: null,
|
|
89
85
|
blocked: `${org.slug}'s own sign-in is blocked, not planned: ${reason}`,
|
|
90
86
|
});
|
|
87
|
+
// The owner's sign-in takes the apex's `auth.` name. An old shared sign-in still recorded there
|
|
88
|
+
// would be repointed at a new empty one, and every operator locked out.
|
|
89
|
+
if (readiness.platformAuthRecordedHost && readiness.platformOwnerOrgId === org.id) {
|
|
90
|
+
return blocked(`the platform's shared sign-in is still recorded at ${readiness.platformAuthRecordedHost}; this build is for a platform built from empty`);
|
|
91
|
+
}
|
|
91
92
|
if (recordedIds.zitadel_org && !recordedIds[OWN_SERVICES_APPLIED_SCOPE_KEY]) {
|
|
92
93
|
return {
|
|
93
94
|
step: null,
|
|
@@ -113,8 +114,11 @@ export function planOwnAuth(options) {
|
|
|
113
114
|
const gitRef = readiness.serviceGitRefs?.auth;
|
|
114
115
|
if (!gitRef)
|
|
115
116
|
return blocked('the platform declares no auth git ref');
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
const names = ownHostnames(org);
|
|
118
|
+
// A company without a domain has no zone of its own: it waits for the `oikos.host` zone at the platform's edge.
|
|
119
|
+
const zoneActive = org.domain ? Boolean(options.zone?.active) : Boolean(options.oikosZoneReady);
|
|
120
|
+
if (!zoneActive)
|
|
121
|
+
return blocked(`the zone for ${names.zone} is not active yet`);
|
|
118
122
|
const ownEdge = readiness.ownEdgePorts;
|
|
119
123
|
if (readiness.dnsBlocked && !(ownEdge?.dns && ownEdge.tunnels)) {
|
|
120
124
|
return blocked(readiness.dnsBlocked);
|
|
@@ -125,10 +129,14 @@ export function planOwnAuth(options) {
|
|
|
125
129
|
if (!options.mailKeyHeld && !options.mailKeyMintable) {
|
|
126
130
|
return blocked(`the held key ${orgTarget(org).refs.brokerMailKey} is not held yet`);
|
|
127
131
|
}
|
|
128
|
-
const hostname =
|
|
132
|
+
const hostname = names.auth;
|
|
129
133
|
// The broker starts only on a valid `AUTH_APPS`, and the login client is minted only once it does:
|
|
130
134
|
// the first broker entry is what lets this step finish, as the platform's first registration does.
|
|
131
|
-
|
|
135
|
+
// Archon's registration is an entry too; the platform records it, not this org, so it comes in
|
|
136
|
+
// through the readiness.
|
|
137
|
+
const brokerAppId = recordedIds[PLATFORM_AUTH_BROKER_SCOPE_KEY];
|
|
138
|
+
const brokerHoldsAnEntry = Object.keys(recordedIds).some((key) => key.startsWith(BROKER_ENTRY_APPLIED_PREFIX)) ||
|
|
139
|
+
(Boolean(brokerAppId) && readiness.archonBrokerAppId === brokerAppId);
|
|
132
140
|
const applied = Boolean(recordedIds[`coolify:own-auth:${org.id}`]) &&
|
|
133
141
|
Boolean(recordedIds[OWN_SERVICES_APPLIED_SCOPE_KEY]);
|
|
134
142
|
if (applied &&
|
|
@@ -171,8 +179,8 @@ export const OWN_MAIL_BLOCKED_KEY = 'own-mail';
|
|
|
171
179
|
* stale-plan comparison.
|
|
172
180
|
*/
|
|
173
181
|
export function planOwnMail(options) {
|
|
174
|
-
const { org, recordedIds, readiness,
|
|
175
|
-
if (!ownsServices(org) || org.mail.mode === 'off'
|
|
182
|
+
const { org, recordedIds, readiness, ownServices, mailRelayApplied, zoneActive } = options;
|
|
183
|
+
if (!ownsServices(org) || org.mail.mode === 'off') {
|
|
176
184
|
return { step: null, blocked: null };
|
|
177
185
|
}
|
|
178
186
|
const blocked = (reason) => ({
|
|
@@ -191,8 +199,6 @@ export function planOwnMail(options) {
|
|
|
191
199
|
const floating = floatingTagBlocked('Stalwart', gitRef, 'v0.16.24');
|
|
192
200
|
if (floating)
|
|
193
201
|
return blocked(`${floating} as the mail gitRef`);
|
|
194
|
-
if (!org.domain)
|
|
195
|
-
return blocked('the org declares no domain');
|
|
196
202
|
if (!ownAuthApplied(org, recordedIds)) {
|
|
197
203
|
return blocked('its own sign-in is not applied yet');
|
|
198
204
|
}
|
|
@@ -200,10 +206,14 @@ export function planOwnMail(options) {
|
|
|
200
206
|
return blocked('the shared mail relay is not applied yet');
|
|
201
207
|
}
|
|
202
208
|
if (!zoneActive)
|
|
203
|
-
return blocked(`the zone for ${org.
|
|
209
|
+
return blocked(`the zone for ${ownHostnames(org).zone} is not active yet`);
|
|
204
210
|
const platformApex = readiness.platformApex;
|
|
205
|
-
const hostname =
|
|
211
|
+
const hostname = ownHostnames(org).mail;
|
|
212
|
+
const smtpPort = options.smtpPort ?? OWN_MAIL_SMTP_PORT_BASE;
|
|
213
|
+
if (!isOwnMailSmtpPort(smtpPort))
|
|
214
|
+
return blocked('its mail port is outside the range foundry uses');
|
|
206
215
|
if (recordedIds[`coolify:own-mail:${org.id}`] &&
|
|
216
|
+
recordedIds[OWN_MAIL_SMTP_PORT_SCOPE_KEY] === String(smtpPort) &&
|
|
207
217
|
recordedIds[PLATFORM_MAIL_APPLIED_HOSTNAME_SCOPE_KEY] === hostname &&
|
|
208
218
|
recordedIds[PLATFORM_MAIL_APPLIED_GIT_REF_SCOPE_KEY] === gitRef &&
|
|
209
219
|
recordedIds[PLATFORM_MAIL_INTERNAL_URL_SCOPE_KEY] &&
|
|
@@ -217,7 +227,7 @@ export function planOwnMail(options) {
|
|
|
217
227
|
system: 'coolify',
|
|
218
228
|
kind: 'own-mail',
|
|
219
229
|
key: org.id,
|
|
220
|
-
desired: { hostname, gitRef, mailHost: platformMailMxHost(platformApex) },
|
|
230
|
+
desired: { hostname, gitRef, mailHost: platformMailMxHost(platformApex), smtpPort },
|
|
221
231
|
},
|
|
222
232
|
step: {
|
|
223
233
|
description: `provision ${org.slug}'s own mail server`,
|
|
@@ -240,10 +250,9 @@ export const OWN_SFU_FIREWALL_KEY = 'own-sfu:firewall';
|
|
|
240
250
|
* Every line is fixed text: it is part of the stale-plan comparison.
|
|
241
251
|
*/
|
|
242
252
|
export function planOwnSfu(options) {
|
|
243
|
-
const { org, recordedIds,
|
|
253
|
+
const { org, recordedIds, ownServices, zoneActive, sfuPortsOpen, readiness } = options;
|
|
244
254
|
const none = { step: null, blocked: null, firewall: null };
|
|
245
|
-
|
|
246
|
-
if (!ownsServices(org) || !org.calls.enabled || isPlatformOrg || !org.domain)
|
|
255
|
+
if (!ownsServices(org) || !org.calls.enabled)
|
|
247
256
|
return none;
|
|
248
257
|
const blocked = (line) => ({ ...none, blocked: line });
|
|
249
258
|
const slot = org.services?.sfuSlot;
|
|
@@ -270,7 +279,7 @@ export function planOwnSfu(options) {
|
|
|
270
279
|
if (!ownAuthApplied(org, recordedIds))
|
|
271
280
|
return waiting('its own sign-in is not applied yet');
|
|
272
281
|
if (!zoneActive)
|
|
273
|
-
return waiting(`the zone for ${org.
|
|
282
|
+
return waiting(`the zone for ${ownHostnames(org).zone} is not active yet`);
|
|
274
283
|
const ownEdge = readiness.ownEdgePorts;
|
|
275
284
|
if (readiness.dnsBlocked && !(ownEdge?.dns && ownEdge.tunnels)) {
|
|
276
285
|
return waiting(readiness.dnsBlocked);
|
|
@@ -278,8 +287,8 @@ export function planOwnSfu(options) {
|
|
|
278
287
|
if (!ownEdge?.tunnels && !readiness.edgeReady) {
|
|
279
288
|
return waiting('the host supplies no tunnel port and edge is not ready');
|
|
280
289
|
}
|
|
281
|
-
const hostname =
|
|
282
|
-
const version = VERSIONS.livekit;
|
|
290
|
+
const hostname = ownHostnames(org).sfu;
|
|
291
|
+
const version = org.versionPin?.sfu ?? VERSIONS.livekit;
|
|
283
292
|
const applied = Boolean(recordedIds[`coolify:own-sfu:${org.id}`]) &&
|
|
284
293
|
recordedIds[OWN_SFU_APPLIED_VERSION_SCOPE_KEY] === version &&
|
|
285
294
|
recordedIds[OWN_SFU_APPLIED_SLOT_SCOPE_KEY] === String(slot) &&
|
|
@@ -315,9 +324,8 @@ export const OWN_FILES_BLOCKED_KEY = 'own-files';
|
|
|
315
324
|
* comparison.
|
|
316
325
|
*/
|
|
317
326
|
export function planOwnFiles(options) {
|
|
318
|
-
const { org, recordedIds, readiness,
|
|
319
|
-
|
|
320
|
-
if (!ownsServices(org) || isPlatformOrg || !org.domain)
|
|
327
|
+
const { org, recordedIds, readiness, ownServices, filesDeps } = options;
|
|
328
|
+
if (!ownsServices(org))
|
|
321
329
|
return { step: null, blocked: null };
|
|
322
330
|
const blocked = (reason) => ({
|
|
323
331
|
step: null,
|
|
@@ -345,7 +353,7 @@ export function planOwnFiles(options) {
|
|
|
345
353
|
}
|
|
346
354
|
if (!filesDeps.bucket)
|
|
347
355
|
return blocked('the host supplies no bucket port');
|
|
348
|
-
const hostname =
|
|
356
|
+
const hostname = ownHostnames(org).files;
|
|
349
357
|
const applied = Boolean(recordedIds[`coolify:own-files:${org.id}`]);
|
|
350
358
|
if (applied &&
|
|
351
359
|
recordedIds[PLATFORM_FILES_APPLIED_HOSTNAME_SCOPE_KEY] === hostname &&
|
|
@@ -393,8 +401,8 @@ export const OWN_FILES_R2_BLOCKED_KEY = 'own-files-r2';
|
|
|
393
401
|
* does not block the step: the next run deletes it first. The blocked line is fixed text.
|
|
394
402
|
*/
|
|
395
403
|
export function planOwnFilesR2(options) {
|
|
396
|
-
const { org, recordedIds,
|
|
397
|
-
if (!ownsServices(org) ||
|
|
404
|
+
const { org, recordedIds, ownServices, ports } = options;
|
|
405
|
+
if (!ownsServices(org) || !ownServices) {
|
|
398
406
|
return { step: null, blocked: null };
|
|
399
407
|
}
|
|
400
408
|
if (!recordedIds[`coolify:own-files:${org.id}`])
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { DeclaredOrg } from '../org.js';
|
|
2
|
+
/** The zone a company without a domain of its own runs its services on. */
|
|
3
|
+
export declare const NO_DOMAIN_ZONE = "oikos.host";
|
|
4
|
+
/** Every hostname an own company's services answer on. */
|
|
5
|
+
export interface OwnHostnames {
|
|
6
|
+
/** `org.domain`, or {@link NO_DOMAIN_ZONE} for a company without one. */
|
|
7
|
+
zone: string;
|
|
8
|
+
/** `auth.<domain>`, or `<slug>-auth.oikos.host`. */
|
|
9
|
+
auth: string;
|
|
10
|
+
/** `mail.<domain>`, or `<slug>-mail.oikos.host`. */
|
|
11
|
+
mail: string;
|
|
12
|
+
/** `files.<domain>`, or `<slug>-files.oikos.host`. */
|
|
13
|
+
files: string;
|
|
14
|
+
/** `sfu.<domain>`, or `<slug>-sfu.oikos.host`. */
|
|
15
|
+
sfu: string;
|
|
16
|
+
/** `https://<auth>`. */
|
|
17
|
+
issuerUrl: string;
|
|
18
|
+
/** The mail domain: `<domain>`, or `<slug>.oikos.host` (names are `name@<slug>.oikos.host`). */
|
|
19
|
+
mailDomain: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The one place that decides every own-service hostname. A company with a
|
|
23
|
+
* domain (and the matching `usesDomain` for the issuer and for mail) runs on
|
|
24
|
+
* it; a company without one runs on `oikos.host`. `auth` is
|
|
25
|
+
* {@link loginHostnameFor}, so the two cannot disagree.
|
|
26
|
+
*/
|
|
27
|
+
export declare function ownHostnames(org: Pick<DeclaredOrg, 'slug' | 'domain' | 'issuer' | 'mail'>): OwnHostnames;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { loginHostnameFor } from './login-host.js';
|
|
2
|
+
/** The zone a company without a domain of its own runs its services on. */
|
|
3
|
+
export const NO_DOMAIN_ZONE = 'oikos.host';
|
|
4
|
+
/**
|
|
5
|
+
* The one place that decides every own-service hostname. A company with a
|
|
6
|
+
* domain (and the matching `usesDomain` for the issuer and for mail) runs on
|
|
7
|
+
* it; a company without one runs on `oikos.host`. `auth` is
|
|
8
|
+
* {@link loginHostnameFor}, so the two cannot disagree.
|
|
9
|
+
*/
|
|
10
|
+
export function ownHostnames(org) {
|
|
11
|
+
const { slug, domain } = org;
|
|
12
|
+
const auth = loginHostnameFor(org);
|
|
13
|
+
const name = (label) => domain ? `${label}.${domain}` : `${slug}-${label}.${NO_DOMAIN_ZONE}`;
|
|
14
|
+
const mailOnDomain = Boolean(domain) && org.mail.usesDomain;
|
|
15
|
+
return {
|
|
16
|
+
zone: domain ?? NO_DOMAIN_ZONE,
|
|
17
|
+
auth,
|
|
18
|
+
mail: mailOnDomain ? `mail.${domain}` : `${slug}-mail.${NO_DOMAIN_ZONE}`,
|
|
19
|
+
files: name('files'),
|
|
20
|
+
sfu: name('sfu'),
|
|
21
|
+
issuerUrl: `https://${auth}`,
|
|
22
|
+
mailDomain: mailOnDomain && domain ? domain : `${slug}.${NO_DOMAIN_ZONE}`,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -1,22 +1,213 @@
|
|
|
1
1
|
import type { CoolifyPort } from './executor.js';
|
|
2
|
+
import { type CapabilityTier } from './run-options.js';
|
|
2
3
|
/**
|
|
3
|
-
* The hard limits every container
|
|
4
|
-
* gets: one flat default. Field names are Coolify's (`PATCH /applications/{uuid}`
|
|
4
|
+
* The hard limits of every container foundry creates, per step (`LIMITS`). Field names are Coolify's (`PATCH /applications/{uuid}`
|
|
5
5
|
* and `PATCH /databases/{uuid}`: `limits_memory`, `limits_cpus`). Coolify has
|
|
6
6
|
* no field for a process limit, and its `custom_docker_run_options` parser drops
|
|
7
7
|
* `--pids-limit`, so 512 processes cannot be set through Coolify.
|
|
8
8
|
*/
|
|
9
9
|
export declare const OWN_LIMITS_MEMORY = "1g";
|
|
10
10
|
export declare const OWN_LIMITS_CPUS = "1";
|
|
11
|
+
/**
|
|
12
|
+
* What a step's containers get. `memory` is for applications, `dbMemory` for
|
|
13
|
+
* databases. `autoDeploy: false` makes every git application the step creates
|
|
14
|
+
* or updates deploy only when foundry deploys it; `'declared'` leaves it to
|
|
15
|
+
* the company's own hosting entry (`HostingEntry.autoDeploy`).
|
|
16
|
+
*/
|
|
17
|
+
export interface LimitProfile {
|
|
18
|
+
memory: string;
|
|
19
|
+
dbMemory: string;
|
|
20
|
+
autoDeploy: false | 'declared';
|
|
21
|
+
/** The capability options sent in `custom_docker_run_options` (`plan/run-options.ts`). */
|
|
22
|
+
capabilities: CapabilityTier;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The one table of memory limits, per step. Every container foundry creates
|
|
26
|
+
* is in a step named here. The five `own*` rows are the flat 1g the own
|
|
27
|
+
* services already ran with. A Node or Next app gets 1g, a small Postgres
|
|
28
|
+
* 512m, the Go-sized helpers (relay, boule, edge, hc) less.
|
|
29
|
+
*/
|
|
30
|
+
export declare const LIMITS: {
|
|
31
|
+
readonly ownAuth: {
|
|
32
|
+
memory: string;
|
|
33
|
+
dbMemory: string;
|
|
34
|
+
autoDeploy: false | "declared";
|
|
35
|
+
capabilities: CapabilityTier;
|
|
36
|
+
};
|
|
37
|
+
readonly ownJobs: {
|
|
38
|
+
memory: string;
|
|
39
|
+
dbMemory: string;
|
|
40
|
+
autoDeploy: false | "declared";
|
|
41
|
+
capabilities: CapabilityTier;
|
|
42
|
+
};
|
|
43
|
+
readonly ownFiles: {
|
|
44
|
+
memory: string;
|
|
45
|
+
dbMemory: string;
|
|
46
|
+
autoDeploy: false | "declared";
|
|
47
|
+
capabilities: CapabilityTier;
|
|
48
|
+
};
|
|
49
|
+
readonly ownMail: {
|
|
50
|
+
memory: string;
|
|
51
|
+
dbMemory: string;
|
|
52
|
+
autoDeploy: false | "declared";
|
|
53
|
+
capabilities: CapabilityTier;
|
|
54
|
+
};
|
|
55
|
+
readonly ownSfu: {
|
|
56
|
+
memory: string;
|
|
57
|
+
dbMemory: string;
|
|
58
|
+
autoDeploy: false | "declared";
|
|
59
|
+
capabilities: CapabilityTier;
|
|
60
|
+
};
|
|
61
|
+
/** A customer's hosting entry: capability tier B, unless the entry declares `capabilities: 'standard'`. */
|
|
62
|
+
readonly companyApp: {
|
|
63
|
+
memory: string;
|
|
64
|
+
dbMemory: string;
|
|
65
|
+
autoDeploy: false | "declared";
|
|
66
|
+
capabilities: CapabilityTier;
|
|
67
|
+
};
|
|
68
|
+
readonly companyAppStandard: {
|
|
69
|
+
memory: string;
|
|
70
|
+
dbMemory: string;
|
|
71
|
+
autoDeploy: false | "declared";
|
|
72
|
+
capabilities: CapabilityTier;
|
|
73
|
+
};
|
|
74
|
+
readonly brokerEntry: {
|
|
75
|
+
memory: string;
|
|
76
|
+
dbMemory: string;
|
|
77
|
+
autoDeploy: false | "declared";
|
|
78
|
+
capabilities: CapabilityTier;
|
|
79
|
+
};
|
|
80
|
+
readonly cms: {
|
|
81
|
+
memory: string;
|
|
82
|
+
dbMemory: string;
|
|
83
|
+
autoDeploy: false | "declared";
|
|
84
|
+
capabilities: CapabilityTier;
|
|
85
|
+
};
|
|
86
|
+
readonly chat: {
|
|
87
|
+
memory: string;
|
|
88
|
+
dbMemory: string;
|
|
89
|
+
autoDeploy: false | "declared";
|
|
90
|
+
capabilities: CapabilityTier;
|
|
91
|
+
};
|
|
92
|
+
readonly calls: {
|
|
93
|
+
memory: string;
|
|
94
|
+
dbMemory: string;
|
|
95
|
+
autoDeploy: false | "declared";
|
|
96
|
+
capabilities: CapabilityTier;
|
|
97
|
+
};
|
|
98
|
+
readonly agora: {
|
|
99
|
+
memory: string;
|
|
100
|
+
dbMemory: string;
|
|
101
|
+
autoDeploy: false | "declared";
|
|
102
|
+
capabilities: CapabilityTier;
|
|
103
|
+
};
|
|
104
|
+
readonly boule: {
|
|
105
|
+
memory: string;
|
|
106
|
+
dbMemory: string;
|
|
107
|
+
autoDeploy: false | "declared";
|
|
108
|
+
capabilities: CapabilityTier;
|
|
109
|
+
};
|
|
110
|
+
readonly companyOther: {
|
|
111
|
+
memory: string;
|
|
112
|
+
dbMemory: string;
|
|
113
|
+
autoDeploy: false | "declared";
|
|
114
|
+
capabilities: CapabilityTier;
|
|
115
|
+
};
|
|
116
|
+
readonly platformArchon: {
|
|
117
|
+
memory: string;
|
|
118
|
+
dbMemory: string;
|
|
119
|
+
autoDeploy: false | "declared";
|
|
120
|
+
capabilities: CapabilityTier;
|
|
121
|
+
};
|
|
122
|
+
readonly platformAi: {
|
|
123
|
+
memory: string;
|
|
124
|
+
dbMemory: string;
|
|
125
|
+
autoDeploy: false | "declared";
|
|
126
|
+
capabilities: CapabilityTier;
|
|
127
|
+
};
|
|
128
|
+
readonly platformIntegrations: {
|
|
129
|
+
memory: string;
|
|
130
|
+
dbMemory: string;
|
|
131
|
+
autoDeploy: false | "declared";
|
|
132
|
+
capabilities: CapabilityTier;
|
|
133
|
+
};
|
|
134
|
+
readonly platformMailRelay: {
|
|
135
|
+
memory: string;
|
|
136
|
+
dbMemory: string;
|
|
137
|
+
autoDeploy: false | "declared";
|
|
138
|
+
capabilities: CapabilityTier;
|
|
139
|
+
};
|
|
140
|
+
readonly platformIngress: {
|
|
141
|
+
memory: string;
|
|
142
|
+
dbMemory: string;
|
|
143
|
+
autoDeploy: false | "declared";
|
|
144
|
+
capabilities: CapabilityTier;
|
|
145
|
+
};
|
|
146
|
+
readonly connector: {
|
|
147
|
+
memory: string;
|
|
148
|
+
dbMemory: string;
|
|
149
|
+
autoDeploy: false | "declared";
|
|
150
|
+
capabilities: CapabilityTier;
|
|
151
|
+
};
|
|
152
|
+
readonly platformFiles: {
|
|
153
|
+
memory: string;
|
|
154
|
+
dbMemory: string;
|
|
155
|
+
autoDeploy: false | "declared";
|
|
156
|
+
capabilities: CapabilityTier;
|
|
157
|
+
};
|
|
158
|
+
readonly platformEdge: {
|
|
159
|
+
memory: string;
|
|
160
|
+
dbMemory: string;
|
|
161
|
+
autoDeploy: false | "declared";
|
|
162
|
+
capabilities: CapabilityTier;
|
|
163
|
+
};
|
|
164
|
+
readonly platformHc: {
|
|
165
|
+
memory: string;
|
|
166
|
+
dbMemory: string;
|
|
167
|
+
autoDeploy: false | "declared";
|
|
168
|
+
capabilities: CapabilityTier;
|
|
169
|
+
};
|
|
170
|
+
readonly platformMail: {
|
|
171
|
+
memory: string;
|
|
172
|
+
dbMemory: string;
|
|
173
|
+
autoDeploy: false | "declared";
|
|
174
|
+
capabilities: CapabilityTier;
|
|
175
|
+
};
|
|
176
|
+
readonly platformAuth: {
|
|
177
|
+
memory: string;
|
|
178
|
+
dbMemory: string;
|
|
179
|
+
autoDeploy: false | "declared";
|
|
180
|
+
capabilities: CapabilityTier;
|
|
181
|
+
};
|
|
182
|
+
readonly platformJobs: {
|
|
183
|
+
memory: string;
|
|
184
|
+
dbMemory: string;
|
|
185
|
+
autoDeploy: false | "declared";
|
|
186
|
+
capabilities: CapabilityTier;
|
|
187
|
+
};
|
|
188
|
+
};
|
|
11
189
|
/** The same bound the neighbouring Coolify calls in this package use for a call that may hang. */
|
|
12
190
|
export declare const OWN_LIMITS_TIMEOUT_MS = 60000;
|
|
13
191
|
type LimitsPort = Partial<Pick<CoolifyPort, 'createGithubAppApplication' | 'createDockerImageApplication' | 'createDockerfileApplication' | 'createPostgresDatabase' | 'findApplicationByName' | 'getApplication' | 'getDatabase' | 'updateApplication' | 'raw'>>;
|
|
14
192
|
/**
|
|
15
|
-
* The Coolify port
|
|
193
|
+
* The Coolify port a step uses, with the profile's memory limit set on every
|
|
16
194
|
* application and database it creates, and set again on one it finds without
|
|
17
|
-
*
|
|
18
|
-
* next apply.
|
|
19
|
-
*
|
|
195
|
+
* it, so a company provisioned before the limits existed converges on its
|
|
196
|
+
* next apply. With `autoDeploy: false` a git application is created with
|
|
197
|
+
* auto-deploy off, and one found or updated with it on is switched off. A
|
|
198
|
+
* failed limits call fails the calling step before it records its applied
|
|
199
|
+
* marker; the next run finds the resource and sets them.
|
|
200
|
+
*
|
|
201
|
+
* `scope` is a profile, or a function that gives the profile of the step now
|
|
202
|
+
* running (none: the port is used as it is).
|
|
203
|
+
*
|
|
204
|
+
* Every limits call has a 60 second timeout. A step that creates a resource
|
|
205
|
+
* and then fails on the limits call leaves a resource without limits; the
|
|
206
|
+
* next run finds it by name and sets them.
|
|
20
207
|
*/
|
|
21
|
-
export declare function limited<C extends LimitsPort>(coolify: C): C;
|
|
208
|
+
export declare function limited<C extends LimitsPort>(coolify: C, scope?: LimitProfile | (() => LimitProfile | undefined)): C;
|
|
209
|
+
/** The deps of a step with their Coolify port limited by `profile`. */
|
|
210
|
+
export declare function limitedDeps<D extends {
|
|
211
|
+
coolify: LimitsPort;
|
|
212
|
+
}>(deps: D, profile: LimitProfile): D;
|
|
22
213
|
export {};
|