@wtfalch/foundry 0.36.1 → 0.38.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/index.d.ts +1 -1
- package/dist/plan/backup-gate.d.ts +3 -3
- package/dist/plan/backup-gate.js +9 -4
- package/dist/plan/company-backups.d.ts +7 -2
- package/dist/plan/company-backups.js +13 -9
- package/dist/plan/diff.js +4 -0
- package/dist/plan/executor.d.ts +8 -0
- package/dist/plan/executor.js +13 -2
- package/dist/plan/index.d.ts +2 -1
- package/dist/plan/index.js +1 -0
- package/dist/plan/mail-store.d.ts +34 -0
- package/dist/plan/mail-store.js +49 -0
- package/dist/plan/own-diff.js +15 -4
- package/dist/plan/own-services.d.ts +6 -1
- package/dist/plan/own-services.js +5 -1
- package/dist/plan/plan-apply.js +7 -3
- package/dist/plan/platform-diff.d.ts +30 -0
- package/dist/plan/platform-diff.js +62 -7
- package/dist/plan/platform-org.d.ts +15 -0
- package/dist/plan/platform-org.js +17 -1
- package/dist/plan/platform-providers.d.ts +55 -1
- package/dist/plan/platform-providers.js +205 -14
- package/dist/plan/uptime-worker.d.ts +20 -1
- package/dist/plan/uptime-worker.js +121 -3
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ export { checkMailIdentityAudience } from './plan/index.js';
|
|
|
54
54
|
export type { MailAllowlistApp } from './plan/index.js';
|
|
55
55
|
export { checkMailAppsAllowlist } from './plan/index.js';
|
|
56
56
|
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';
|
|
57
|
-
export type { PlatformAuthDeps, PlatformAuthSmtp, PlatformAuthRuntime, PlatformFilesDeps, PlatformFilesRuntime, PlatformEdgeDeps, PlatformDnsFactory, PlatformAccessFactory, PlatformUptimeAccessFactory, PlatformUptimeAccessPort, PlatformUptimeDeps, PlatformWorkersFactory, PlatformWorkersPort, PlatformAccessPort, PlatformTunnelsFactory, PlatformEdgeRuntime, } from './plan/index.js';
|
|
57
|
+
export type { PlatformAuthDeps, PlatformAuthSmtp, PlatformAuthRuntime, PlatformFilesDeps, PlatformFilesRuntime, PlatformEdgeDeps, PlatformDnsFactory, PlatformAccessFactory, PlatformUptimeAccessFactory, PlatformUptimeAccessPort, PlatformUptimeChatDeps, PlatformUptimeDeps, PlatformWorkersFactory, PlatformWorkersPort, PlatformAccessPort, PlatformTunnelsFactory, PlatformEdgeRuntime, } from './plan/index.js';
|
|
58
58
|
export type { PlatformMailDeps, PlatformMailAdminPort, PlatformMailRuntime, } from './plan/index.js';
|
|
59
59
|
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';
|
|
60
60
|
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';
|
|
@@ -52,8 +52,8 @@ export interface BackupGatePorts {
|
|
|
52
52
|
* `unconfirmedUpgrades` and before any step. A service whose database the
|
|
53
53
|
* company does not have passes (there is nothing to migrate); a database that
|
|
54
54
|
* exists with no recorded schedule, a disabled or non-S3 schedule, a failed or
|
|
55
|
-
* old dump, or an unreadable list all refuse. `mail`
|
|
56
|
-
*
|
|
55
|
+
* old dump, or an unreadable list all refuse. `mail` is covered like the rest:
|
|
56
|
+
* Stalwart's data store is a Postgres database.
|
|
57
57
|
*
|
|
58
58
|
* Where this Coolify has no executions route, the fallback is that the
|
|
59
59
|
* schedule exists, is enabled and saves to S3; that proves a dump is
|
|
@@ -88,6 +88,6 @@ export declare function requireFreshBackupsForMove(ports: MoveGatePorts): Promis
|
|
|
88
88
|
/**
|
|
89
89
|
* The platform databases an upgrade of `service` can migrate. Postgres is all three. archon, ai and
|
|
90
90
|
* integrations each migrate their own database when the new container starts. The owner company runs its own
|
|
91
|
-
* sign-in, files and jobs, so the platform has no database for them;
|
|
91
|
+
* sign-in, files and jobs, so the platform has no database for them; edge and hc have no Postgres.
|
|
92
92
|
*/
|
|
93
93
|
export declare function platformDatabasesForService(service: string): readonly string[] | 'all';
|
package/dist/plan/backup-gate.js
CHANGED
|
@@ -123,8 +123,8 @@ function freshSuccess(executions, now, maxAgeMs = BACKUP_MAX_AGE_HOURS * 3_600_0
|
|
|
123
123
|
* `unconfirmedUpgrades` and before any step. A service whose database the
|
|
124
124
|
* company does not have passes (there is nothing to migrate); a database that
|
|
125
125
|
* exists with no recorded schedule, a disabled or non-S3 schedule, a failed or
|
|
126
|
-
* old dump, or an unreadable list all refuse. `mail`
|
|
127
|
-
*
|
|
126
|
+
* old dump, or an unreadable list all refuse. `mail` is covered like the rest:
|
|
127
|
+
* Stalwart's data store is a Postgres database.
|
|
128
128
|
*
|
|
129
129
|
* Where this Coolify has no executions route, the fallback is that the
|
|
130
130
|
* schedule exists, is enabled and saves to S3; that proves a dump is
|
|
@@ -252,10 +252,15 @@ export async function requireFreshBackupsForMove(ports) {
|
|
|
252
252
|
/**
|
|
253
253
|
* The platform databases an upgrade of `service` can migrate. Postgres is all three. archon, ai and
|
|
254
254
|
* integrations each migrate their own database when the new container starts. The owner company runs its own
|
|
255
|
-
* sign-in, files and jobs, so the platform has no database for them;
|
|
255
|
+
* sign-in, files and jobs, so the platform has no database for them; edge and hc have no Postgres.
|
|
256
256
|
*/
|
|
257
257
|
export function platformDatabasesForService(service) {
|
|
258
258
|
if (service === 'postgres')
|
|
259
259
|
return 'all';
|
|
260
|
-
return service === 'archon' ||
|
|
260
|
+
return service === 'archon' ||
|
|
261
|
+
service === 'ai' ||
|
|
262
|
+
service === 'integrations' ||
|
|
263
|
+
service === 'mail'
|
|
264
|
+
? [service]
|
|
265
|
+
: [];
|
|
261
266
|
}
|
|
@@ -11,6 +11,11 @@ import type { DraftStep } from './diff.js';
|
|
|
11
11
|
* `app` is the hosting entry's database, recorded as a resource id.
|
|
12
12
|
*/
|
|
13
13
|
export declare function companyDatabaseKeys(org: Pick<DeclaredOrg, 'id'>): Readonly<Record<string, string>>;
|
|
14
|
+
/**
|
|
15
|
+
* The database a company backup schedule must name when the Coolify resource
|
|
16
|
+
* is not left to pick its first database. Absent: the resource's first database.
|
|
17
|
+
*/
|
|
18
|
+
export declare const COMPANY_BACKUP_DATABASE_NAMES: Readonly<Record<string, string>>;
|
|
14
19
|
/** What every recorded-id key of a company database's backup schedule starts with. */
|
|
15
20
|
export declare const BACKUP_SCOPE_PREFIX = "backup_";
|
|
16
21
|
/** The recorded-id key a company database's backup schedule uuid is stored under. */
|
|
@@ -22,8 +27,8 @@ export declare function databasesForService(service: string): readonly string[]
|
|
|
22
27
|
* recorded uuid and no recorded backup yet. `storageUuid` undefined means the
|
|
23
28
|
* host did not wire backups, so nothing is planned and nothing is said; null
|
|
24
29
|
* means the platform's backup storage is not registered, so each database is
|
|
25
|
-
* reported as blocked instead (rule 2). A company
|
|
26
|
-
*
|
|
30
|
+
* reported as blocked instead (rule 2). A company's mail server is one of
|
|
31
|
+
* these databases (Stalwart's data store), dumped like the rest.
|
|
27
32
|
*/
|
|
28
33
|
export declare function planCompanyBackups(org: DeclaredOrg, recordedIds: Readonly<Record<string, string>>, storageUuid: string | null | undefined): {
|
|
29
34
|
steps: DraftStep[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ownsServices } from '../org.js';
|
|
2
1
|
import { BOULE_DATABASE_SCOPE_KEY } from './boule.js';
|
|
3
2
|
import { CHAT_REKEY_MAS_DB_SCOPE_KEY, CHAT_REKEY_SYNAPSE_DB_SCOPE_KEY } from './executor.js';
|
|
3
|
+
import { MAIL_DATABASE_NAME, MAIL_DATABASE_SCOPE_KEY } from './mail-store.js';
|
|
4
4
|
/**
|
|
5
5
|
* F6: the Postgres databases of a company that get a nightly backup, and the
|
|
6
6
|
* recorded id each one's uuid sits under. The keys are second, documented
|
|
@@ -14,6 +14,7 @@ export function companyDatabaseKeys(org) {
|
|
|
14
14
|
return {
|
|
15
15
|
app: `coolify:database:${org.id}`,
|
|
16
16
|
cms: 'coolify_cms_database',
|
|
17
|
+
mail: MAIL_DATABASE_SCOPE_KEY,
|
|
17
18
|
auth: 'coolify_platform_auth_database',
|
|
18
19
|
files: 'coolify_platform_files_database',
|
|
19
20
|
jobs: 'coolify_jobs_database',
|
|
@@ -28,6 +29,13 @@ export function companyDatabaseKeys(org) {
|
|
|
28
29
|
chat_rekey_mas: CHAT_REKEY_MAS_DB_SCOPE_KEY,
|
|
29
30
|
};
|
|
30
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* The database a company backup schedule must name when the Coolify resource
|
|
34
|
+
* is not left to pick its first database. Absent: the resource's first database.
|
|
35
|
+
*/
|
|
36
|
+
export const COMPANY_BACKUP_DATABASE_NAMES = {
|
|
37
|
+
mail: MAIL_DATABASE_NAME,
|
|
38
|
+
};
|
|
31
39
|
/** What every recorded-id key of a company database's backup schedule starts with. */
|
|
32
40
|
export const BACKUP_SCOPE_PREFIX = 'backup_';
|
|
33
41
|
/** The recorded-id key a company database's backup schedule uuid is stored under. */
|
|
@@ -43,6 +51,8 @@ export function databasesForService(service) {
|
|
|
43
51
|
return ['files'];
|
|
44
52
|
case 'jobs':
|
|
45
53
|
return ['jobs'];
|
|
54
|
+
case 'mail':
|
|
55
|
+
return ['mail'];
|
|
46
56
|
case 'synapse':
|
|
47
57
|
return ['synapse', 'chat_synapse'];
|
|
48
58
|
case 'mas':
|
|
@@ -58,8 +68,8 @@ export function databasesForService(service) {
|
|
|
58
68
|
* recorded uuid and no recorded backup yet. `storageUuid` undefined means the
|
|
59
69
|
* host did not wire backups, so nothing is planned and nothing is said; null
|
|
60
70
|
* means the platform's backup storage is not registered, so each database is
|
|
61
|
-
* reported as blocked instead (rule 2). A company
|
|
62
|
-
*
|
|
71
|
+
* reported as blocked instead (rule 2). A company's mail server is one of
|
|
72
|
+
* these databases (Stalwart's data store), dumped like the rest.
|
|
63
73
|
*/
|
|
64
74
|
export function planCompanyBackups(org, recordedIds, storageUuid) {
|
|
65
75
|
const steps = [];
|
|
@@ -91,11 +101,5 @@ export function planCompanyBackups(org, recordedIds, storageUuid) {
|
|
|
91
101
|
},
|
|
92
102
|
});
|
|
93
103
|
}
|
|
94
|
-
if (ownsServices(org)) {
|
|
95
|
-
blocked.push({
|
|
96
|
-
description: `${org.slug}'s mail server keeps its data on a volume, not in Postgres: no backup covers it yet`,
|
|
97
|
-
key: 'backup-not-covered:mail',
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
104
|
return { steps, blocked };
|
|
101
105
|
}
|
package/dist/plan/diff.js
CHANGED
|
@@ -14,6 +14,7 @@ import { appHostname, tunnelDnsHostnames } from './hostnames.js';
|
|
|
14
14
|
import { lockedHostnames } from './locked-hostnames.js';
|
|
15
15
|
import { LOGIN_BINDING_SCOPE_KEY, agoraIssuerHostFor, companyLoginTunnelHost, loginBindingState, loginHostClientIds, loginHostServesAgora, loginHostnameFor, ownAuthApplied, pendingRemovalHosts, } from './login-host.js';
|
|
16
16
|
import { MAIL_COPY_COMPLETED_SCOPE_KEY, MAIL_COPY_DONE_SCOPE_KEY, parseMailCopyCompleted, } from './mail-copy.js';
|
|
17
|
+
import { mailStoreSwitchChange } from './mail-store.js';
|
|
17
18
|
import { hasAdoptedResources, networkMoveNeeded, planNetworkMove } from './network-move.js';
|
|
18
19
|
import { OWN_AUTH_BLOCKED_KEY, OWN_FILES_BLOCKED_KEY, OWN_FILES_R2_BLOCKED_KEY, OWN_JOBS_BLOCKED_KEY, OWN_MAIL_BLOCKED_KEY, OWN_SFU_BLOCKED_KEY, OWN_SFU_FIREWALL_KEY, planOwnAuth, planOwnFiles, planOwnFilesR2, planOwnJobs, planOwnMail, planOwnSfu, } from './own-diff.js';
|
|
19
20
|
import { ownDnsHostnames } from './own-dns.js';
|
|
@@ -319,6 +320,9 @@ export function computePlanDetail(org, live, recordedIds = {}, agoraHost = NO_AG
|
|
|
319
320
|
// uses, never `versionChangeLine`'s "X -> Y (redeploy)" -- nothing here
|
|
320
321
|
// ever performs that redeploy.
|
|
321
322
|
const versionChanges = [];
|
|
323
|
+
if (ownMail.step?.action.desired.switchMailStore) {
|
|
324
|
+
versionChanges.push(mailStoreSwitchChange(org.slug));
|
|
325
|
+
}
|
|
322
326
|
if (org.calls.enabled && !calls.blocked) {
|
|
323
327
|
const callsAppLive = Boolean(byKey.get(resourceKey('coolify', 'calls', org.id)));
|
|
324
328
|
const synapseChange = versionNotAppliedLine('synapse', callsAppLive, recordedIds[CALLS_SYNAPSE_APPLIED_IMAGE_TAG_SCOPE_KEY], versionPin?.calls ?? VERSIONS.synapse);
|
package/dist/plan/executor.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { type MailCopyPort } from './mail-copy.js';
|
|
|
15
15
|
import { type OwnServicesPort } from './own-services.js';
|
|
16
16
|
import type { DestroyTarget, StepDestroyer, StepExecutionContext, StepExecutor } from './plan-apply.js';
|
|
17
17
|
import type { EdgePortName } from './platform-org.js';
|
|
18
|
+
import type { RequestHeaderPort } from './platform-providers.js';
|
|
18
19
|
export declare function coolifyProjectMark(org: Pick<DeclaredOrg, 'id'>): string;
|
|
19
20
|
/**
|
|
20
21
|
* The Coolify calls this executor makes, shaped to match
|
|
@@ -1595,6 +1596,13 @@ export interface FoundryStepExecutorPorts {
|
|
|
1595
1596
|
* `edge.tunnels` (see {@link EdgePort.tunnels}). Kept for a host or a test that supplies its own.
|
|
1596
1597
|
*/
|
|
1597
1598
|
tunnels?: TunnelPort;
|
|
1599
|
+
/**
|
|
1600
|
+
* #745: the Cloudflare request header rule call, edge's `platform.requestHeaders`
|
|
1601
|
+
* (`@wtfalch/edge` 0.14.0). A company's sign-in hostname gets its header strip rule
|
|
1602
|
+
* through it before its DNS record; without it the step logs one fixed line and
|
|
1603
|
+
* writes no rule. Mail and SFU hostnames never use it.
|
|
1604
|
+
*/
|
|
1605
|
+
requestHeaders?: RequestHeaderPort;
|
|
1598
1606
|
/**
|
|
1599
1607
|
* F4.access: overrides the Access calls, which otherwise go through
|
|
1600
1608
|
* `edge.access` (see {@link EdgePort.access}). Kept for a host or a test that supplies its own.
|
package/dist/plan/executor.js
CHANGED
|
@@ -13,7 +13,7 @@ import { recordBuiltCommit } from './build-record.js';
|
|
|
13
13
|
import { MAS_TAG, SYNAPSE_IMAGE, SYNAPSE_TAG, callsMasConfigYaml, callsServerName, callsSynapseHomeserverYaml, masDockerfile, mintCallsMatrixSecrets, parseCallsDbUrl, } from './calls-matrix.js';
|
|
14
14
|
import { CHAT_MAS_PORT, CHAT_REPO, CHAT_SERVICE_DOCKERFILE, CHAT_SERVICE_PORT, CHAT_SYNAPSE_DOCKERFILE, CHAT_SYNAPSE_PORT, assertChatServerName, chatInternalNames, chatMasConfigYaml, chatRekeyedInternalNames, chatServerName, chatServiceEnvs, chatSynapseHomeserverYaml, chatUpstreams, } from './chat-matrix.js';
|
|
15
15
|
import { ensureCloudflaredConnector } from './cloudflared-connector.js';
|
|
16
|
-
import { BACKUP_SCOPE_PREFIX, backupScopeKey } from './company-backups.js';
|
|
16
|
+
import { BACKUP_SCOPE_PREFIX, COMPANY_BACKUP_DATABASE_NAMES, backupScopeKey, } from './company-backups.js';
|
|
17
17
|
import { CORE_FILES_COLLECTION_NAME, FILES_CORE_COLLECTION_SCOPE_KEY, ZITADEL_FILES_PROJECT_SCOPE_KEY, } from './core-files.js';
|
|
18
18
|
import { waitForNewDeployment, } from './deploy-health.js';
|
|
19
19
|
import { PLATFORM_NETWORK, companyNetworkName, ensureDestination, findDestination, onPlatformNetwork, placed, placedByScope, } from './destinations.js';
|
|
@@ -2633,6 +2633,7 @@ export class FoundryStepExecutor {
|
|
|
2633
2633
|
databaseUuid: databaseId,
|
|
2634
2634
|
label: `${org.slug} ${database}`,
|
|
2635
2635
|
storageUuid,
|
|
2636
|
+
databaseName: COMPANY_BACKUP_DATABASE_NAMES[database],
|
|
2636
2637
|
});
|
|
2637
2638
|
context.recordScopeId(backupScopeKey(database), uuid);
|
|
2638
2639
|
return undefined;
|
|
@@ -5749,7 +5750,12 @@ export class FoundryStepExecutor {
|
|
|
5749
5750
|
apex: hn.zone,
|
|
5750
5751
|
gitRef,
|
|
5751
5752
|
project: { ensure: () => this.ensureCoolifyProject(org, context) },
|
|
5752
|
-
network: orgNetwork({
|
|
5753
|
+
network: orgNetwork({
|
|
5754
|
+
dns: this.dnsPort(),
|
|
5755
|
+
tunnels: this.tunnelPort(),
|
|
5756
|
+
requestHeaders: this.ports.requestHeaders,
|
|
5757
|
+
zones: this.zonePort(),
|
|
5758
|
+
}, scope, `${org.slug}:auth`),
|
|
5753
5759
|
smtpSender: `noreply@${hn.mailDomain}`,
|
|
5754
5760
|
defaultRedirectUri: `https://${agoraHostnameFor(org)}`,
|
|
5755
5761
|
ownerCompany: null,
|
|
@@ -5808,12 +5814,17 @@ export class FoundryStepExecutor {
|
|
|
5808
5814
|
},
|
|
5809
5815
|
zitadel: own.zitadelFor({ issuerUrl, bearerRef: target.refs.instanceBearer }),
|
|
5810
5816
|
zitadelForInstance: undefined,
|
|
5817
|
+
runtime: {
|
|
5818
|
+
...own.provision.mail.runtime,
|
|
5819
|
+
onSecret: (value) => this.handledSecrets.add(value),
|
|
5820
|
+
},
|
|
5811
5821
|
}, target, {
|
|
5812
5822
|
hostname: action.desired.hostname,
|
|
5813
5823
|
apex: hn.mailDomain,
|
|
5814
5824
|
zone: hn.zone,
|
|
5815
5825
|
mailHost: action.desired.mailHost,
|
|
5816
5826
|
imageTag: action.desired.gitRef,
|
|
5827
|
+
switchStore: action.desired.switchMailStore === true,
|
|
5817
5828
|
hostPorts: bind ? `${bind}:${smtpPort}:25` : `${smtpPort}:25`,
|
|
5818
5829
|
issuerUrl,
|
|
5819
5830
|
mxRecord: null,
|
package/dist/plan/index.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ 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 { MAIL_STORE_SWITCH_SERVICE } from './mail-store.js';
|
|
26
27
|
export { NetworkMoveBackupMissingError, UpgradeBackupMissingError } from './backup-gate.js';
|
|
27
28
|
export type { BackupGatePorts, MoveGatePorts } from './backup-gate.js';
|
|
28
29
|
export { FoundryPlatformStepExecutor, ProvidersPlatformCloudflareReader, ProvidersPlatformCoolifyReader, PLATFORM_MAIL_ADMIN_KEY_DESCRIPTION, filesPublicHostsValue, filesShareDomains, provisionFilesHost, provisionJobsHost, provisionMailServer, } from './platform-providers.js';
|
|
@@ -63,7 +64,7 @@ export { createEdgeAccess } from './edge-access.js';
|
|
|
63
64
|
export type { AccessAppSummary, AccessDecision, AccessPolicyRule, AccessPort, EdgePlatformAccess, } from './edge-access.js';
|
|
64
65
|
export { createEdgeWorkers } from './edge-workers.js';
|
|
65
66
|
export type { EdgePlatformWorkers, EdgeWorkersOptions, PlatformWorkersPort, } from './edge-workers.js';
|
|
66
|
-
export type { PlatformUptimeAccessFactory, PlatformUptimeAccessPort, PlatformUptimeDeps, PlatformWorkersFactory, } from './uptime-worker.js';
|
|
67
|
+
export type { PlatformUptimeAccessFactory, PlatformUptimeAccessPort, PlatformUptimeChatDeps, PlatformUptimeDeps, PlatformWorkersFactory, } from './uptime-worker.js';
|
|
67
68
|
export { createEdgeRateLimits } from './edge-ratelimits.js';
|
|
68
69
|
export type { EdgePlatformRateLimits, EdgeRateLimitsOptions, RateLimitPort, RateLimitRuleInput, } from './edge-ratelimits.js';
|
|
69
70
|
export { createEdgeZones } from './edge-zones.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 { MAIL_STORE_SWITCH_SERVICE } from './mail-store.js';
|
|
13
14
|
export { NetworkMoveBackupMissingError, UpgradeBackupMissingError } from './backup-gate.js';
|
|
14
15
|
export { FoundryPlatformStepExecutor, ProvidersPlatformCloudflareReader, ProvidersPlatformCoolifyReader, PLATFORM_MAIL_ADMIN_KEY_DESCRIPTION, filesPublicHostsValue, filesShareDomains, provisionFilesHost, provisionJobsHost, provisionMailServer, } from './platform-providers.js';
|
|
15
16
|
// #171: how a host signs files management requests with the delivered key.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type VersionChangeItem } from '../plan.js';
|
|
2
|
+
/**
|
|
3
|
+
* Stalwart keeps its data (mail, accounts, settings, DKIM keys) in a Coolify
|
|
4
|
+
* Postgres, so the nightly dump of that database is the off-server backup.
|
|
5
|
+
* These keys are shared by the planners (which must not import
|
|
6
|
+
* `platform-providers.ts`) and by `provisionMailServer`.
|
|
7
|
+
*/
|
|
8
|
+
/** The recorded uuid of the mail Postgres, under the same name for the platform and every company. */
|
|
9
|
+
export declare const MAIL_DATABASE_SCOPE_KEY = "coolify_mail_database";
|
|
10
|
+
/** Recorded as {@link MAIL_STORE_POSTGRES} once the `Bootstrap` write has pointed Stalwart at the database. */
|
|
11
|
+
export declare const MAIL_STORE_SCOPE_KEY = "mail_store";
|
|
12
|
+
export declare const MAIL_STORE_POSTGRES = "postgres";
|
|
13
|
+
/** The recorded uuid of the Stalwart app (`platform-providers.ts` re-exports it under its old name). */
|
|
14
|
+
export declare const MAIL_APP_SCOPE_KEY = "coolify_platform_mail_app";
|
|
15
|
+
/** The database and its owner, and the env var Stalwart reads the password from. */
|
|
16
|
+
export declare const MAIL_DATABASE_NAME = "stalwart";
|
|
17
|
+
export declare const MAIL_DATABASE_USER = "stalwart";
|
|
18
|
+
export declare const MAIL_DATABASE_PASSWORD_ENV = "STALWART_DB_PASSWORD";
|
|
19
|
+
/** The `confirmUpgrade` name that confirms the switch (`VersionChangeItem.service`). */
|
|
20
|
+
export declare const MAIL_STORE_SWITCH_SERVICE = "mail-store";
|
|
21
|
+
/**
|
|
22
|
+
* A Stalwart app is recorded and its data store was never moved to Postgres
|
|
23
|
+
* (no mail database recorded either: a fresh instance records that before it
|
|
24
|
+
* creates the app, so a crash halfway never reads as a volume-backed server).
|
|
25
|
+
*/
|
|
26
|
+
export declare function mailStoreIsLegacy(recorded: Readonly<Record<string, string>>): boolean;
|
|
27
|
+
/** The one step description for the switch. `owner` is `the platform` or the company's slug. */
|
|
28
|
+
export declare function mailStoreSwitchDescription(owner: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* The version-change line that makes `apply` refuse the plan until
|
|
31
|
+
* `confirmUpgrade` names `mail-store`. Fixed text: it is part of the
|
|
32
|
+
* stale-plan comparison.
|
|
33
|
+
*/
|
|
34
|
+
export declare function mailStoreSwitchChange(owner: string): VersionChangeItem;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { VERSION_CHANGE_KIND } from '../plan.js';
|
|
2
|
+
/**
|
|
3
|
+
* Stalwart keeps its data (mail, accounts, settings, DKIM keys) in a Coolify
|
|
4
|
+
* Postgres, so the nightly dump of that database is the off-server backup.
|
|
5
|
+
* These keys are shared by the planners (which must not import
|
|
6
|
+
* `platform-providers.ts`) and by `provisionMailServer`.
|
|
7
|
+
*/
|
|
8
|
+
/** The recorded uuid of the mail Postgres, under the same name for the platform and every company. */
|
|
9
|
+
export const MAIL_DATABASE_SCOPE_KEY = 'coolify_mail_database';
|
|
10
|
+
/** Recorded as {@link MAIL_STORE_POSTGRES} once the `Bootstrap` write has pointed Stalwart at the database. */
|
|
11
|
+
export const MAIL_STORE_SCOPE_KEY = 'mail_store';
|
|
12
|
+
export const MAIL_STORE_POSTGRES = 'postgres';
|
|
13
|
+
/** The recorded uuid of the Stalwart app (`platform-providers.ts` re-exports it under its old name). */
|
|
14
|
+
export const MAIL_APP_SCOPE_KEY = 'coolify_platform_mail_app';
|
|
15
|
+
/** The database and its owner, and the env var Stalwart reads the password from. */
|
|
16
|
+
export const MAIL_DATABASE_NAME = 'stalwart';
|
|
17
|
+
export const MAIL_DATABASE_USER = 'stalwart';
|
|
18
|
+
export const MAIL_DATABASE_PASSWORD_ENV = 'STALWART_DB_PASSWORD';
|
|
19
|
+
/** The `confirmUpgrade` name that confirms the switch (`VersionChangeItem.service`). */
|
|
20
|
+
export const MAIL_STORE_SWITCH_SERVICE = 'mail-store';
|
|
21
|
+
/**
|
|
22
|
+
* A Stalwart app is recorded and its data store was never moved to Postgres
|
|
23
|
+
* (no mail database recorded either: a fresh instance records that before it
|
|
24
|
+
* creates the app, so a crash halfway never reads as a volume-backed server).
|
|
25
|
+
*/
|
|
26
|
+
export function mailStoreIsLegacy(recorded) {
|
|
27
|
+
return (Boolean(recorded[MAIL_APP_SCOPE_KEY]) &&
|
|
28
|
+
!recorded[MAIL_DATABASE_SCOPE_KEY] &&
|
|
29
|
+
recorded[MAIL_STORE_SCOPE_KEY] !== MAIL_STORE_POSTGRES);
|
|
30
|
+
}
|
|
31
|
+
/** The one step description for the switch. `owner` is `the platform` or the company's slug. */
|
|
32
|
+
export function mailStoreSwitchDescription(owner) {
|
|
33
|
+
return `switch ${owner}'s mail store to Postgres (recreates the mail server; mail stored there is deleted)`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The version-change line that makes `apply` refuse the plan until
|
|
37
|
+
* `confirmUpgrade` names `mail-store`. Fixed text: it is part of the
|
|
38
|
+
* stale-plan comparison.
|
|
39
|
+
*/
|
|
40
|
+
export function mailStoreSwitchChange(owner) {
|
|
41
|
+
return {
|
|
42
|
+
kind: VERSION_CHANGE_KIND,
|
|
43
|
+
service: MAIL_STORE_SWITCH_SERVICE,
|
|
44
|
+
description: `${owner}'s mail server still stores its data on a volume: moving it to Postgres recreates the server and deletes the mail stored there; confirm with confirmUpgrade "${MAIL_STORE_SWITCH_SERVICE}"`,
|
|
45
|
+
from: 'volume',
|
|
46
|
+
to: 'postgres',
|
|
47
|
+
needsConfirmation: true,
|
|
48
|
+
};
|
|
49
|
+
}
|
package/dist/plan/own-diff.js
CHANGED
|
@@ -6,6 +6,7 @@ import { brokerEntryAppliedScopeKey } from './broker-entries.js';
|
|
|
6
6
|
import { ZITADEL_FILES_PROJECT_SCOPE_KEY } from './core-files.js';
|
|
7
7
|
import { OWN_AUTH_APPLIED_HOSTNAME_SCOPE_KEY, ownAuthApplied } from './login-host.js';
|
|
8
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 { mailStoreIsLegacy, mailStoreSwitchDescription } from './mail-store.js';
|
|
9
10
|
import { ownHostnames } from './own-hostnames.js';
|
|
10
11
|
import { OWN_FILES_R2_SCOPE_KEY, OWN_SERVICES_APPLIED_SCOPE_KEY, orgTarget, } from './own-services.js';
|
|
11
12
|
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';
|
|
@@ -212,7 +213,9 @@ export function planOwnMail(options) {
|
|
|
212
213
|
const smtpPort = options.smtpPort ?? OWN_MAIL_SMTP_PORT_BASE;
|
|
213
214
|
if (!isOwnMailSmtpPort(smtpPort))
|
|
214
215
|
return blocked('its mail port is outside the range foundry uses');
|
|
215
|
-
|
|
216
|
+
const storeSwitch = mailStoreIsLegacy(recordedIds);
|
|
217
|
+
if (!storeSwitch &&
|
|
218
|
+
recordedIds[`coolify:own-mail:${org.id}`] &&
|
|
216
219
|
recordedIds[OWN_MAIL_SMTP_PORT_SCOPE_KEY] === String(smtpPort) &&
|
|
217
220
|
recordedIds[PLATFORM_MAIL_APPLIED_HOSTNAME_SCOPE_KEY] === hostname &&
|
|
218
221
|
recordedIds[PLATFORM_MAIL_APPLIED_GIT_REF_SCOPE_KEY] === gitRef &&
|
|
@@ -227,11 +230,19 @@ export function planOwnMail(options) {
|
|
|
227
230
|
system: 'coolify',
|
|
228
231
|
kind: 'own-mail',
|
|
229
232
|
key: org.id,
|
|
230
|
-
desired: {
|
|
233
|
+
desired: {
|
|
234
|
+
hostname,
|
|
235
|
+
gitRef,
|
|
236
|
+
mailHost: platformMailMxHost(platformApex),
|
|
237
|
+
smtpPort,
|
|
238
|
+
...(storeSwitch ? { switchMailStore: true } : {}),
|
|
239
|
+
},
|
|
231
240
|
},
|
|
232
241
|
step: {
|
|
233
|
-
description:
|
|
234
|
-
|
|
242
|
+
description: storeSwitch
|
|
243
|
+
? mailStoreSwitchDescription(org.slug)
|
|
244
|
+
: `provision ${org.slug}'s own mail server`,
|
|
245
|
+
destroys: storeSwitch,
|
|
235
246
|
migrates: false,
|
|
236
247
|
},
|
|
237
248
|
},
|
|
@@ -6,7 +6,7 @@ import type { DnsPort } from './edge-dns.js';
|
|
|
6
6
|
import type { ZonePort } from './edge-zones.js';
|
|
7
7
|
import type { CallsSfuPort, CloudflarePort, CoolifyPort, FilesOrganisationPort, FoundryStepExecutorPorts, JobsSchedulerPort, MailPort, ZitadelPort } from './executor.js';
|
|
8
8
|
import type { PlatformStepExecutionContext, StepExecutionContext } from './plan-apply.js';
|
|
9
|
-
import type { FoundryPlatformStepExecutorOptions, PlatformAuthDeps, PlatformDnsFactory, PlatformFilesDeps, PlatformMailDeps, PlatformTunnelPort, PlatformTunnelsFactory } from './platform-providers.js';
|
|
9
|
+
import type { FoundryPlatformStepExecutorOptions, PlatformAuthDeps, PlatformDnsFactory, PlatformFilesDeps, PlatformMailDeps, PlatformRequestHeadersFactory, PlatformTunnelPort, PlatformTunnelsFactory, RequestHeaderPort } from './platform-providers.js';
|
|
10
10
|
/** Applied-state key under which an own org's provisioned-services marker is recorded. */
|
|
11
11
|
export declare const OWN_SERVICES_APPLIED_SCOPE_KEY = "own_services_applied";
|
|
12
12
|
/**
|
|
@@ -26,6 +26,7 @@ export interface ServiceTarget {
|
|
|
26
26
|
authTunnel: string;
|
|
27
27
|
authCloudflared: string;
|
|
28
28
|
mailApp: string;
|
|
29
|
+
mailDb: string;
|
|
29
30
|
mailTunnel: string;
|
|
30
31
|
mailCloudflared: string;
|
|
31
32
|
filesDb: string;
|
|
@@ -82,10 +83,13 @@ export interface ServiceNetwork {
|
|
|
82
83
|
dns(): Promise<DnsPort>;
|
|
83
84
|
tunnels(): Promise<PlatformTunnelPort>;
|
|
84
85
|
zoneId(apex: string): Promise<string | undefined>;
|
|
86
|
+
/** Undefined when the host supplies no way to write Cloudflare request header rules. */
|
|
87
|
+
requestHeaders(): Promise<RequestHeaderPort | undefined>;
|
|
85
88
|
}
|
|
86
89
|
export declare function platformNetwork(deps: {
|
|
87
90
|
dns: PlatformDnsFactory;
|
|
88
91
|
tunnels: PlatformTunnelsFactory;
|
|
92
|
+
requestHeaders?: PlatformRequestHeadersFactory;
|
|
89
93
|
cloudflare: Pick<CloudflarePort, 'findZoneByApex'>;
|
|
90
94
|
}, scope: StepScope, step: string): ServiceNetwork;
|
|
91
95
|
/**
|
|
@@ -96,6 +100,7 @@ export declare function platformNetwork(deps: {
|
|
|
96
100
|
export declare function orgNetwork(ports: {
|
|
97
101
|
dns?: DnsPort;
|
|
98
102
|
tunnels?: PlatformTunnelPort;
|
|
103
|
+
requestHeaders?: RequestHeaderPort;
|
|
99
104
|
zones?: Pick<ZonePort, 'findZoneByApex'>;
|
|
100
105
|
}, scope: StepScope, step: string): ServiceNetwork;
|
|
101
106
|
/** Where the project comes from: the platform's 'platform' project, or the org's own. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NO_DOMAIN_ZONE } from './own-hostnames.js';
|
|
2
|
-
import { apexZoneKey, exactZone, platformDns, platformTunnels } from './platform-providers.js';
|
|
2
|
+
import { apexZoneKey, exactZone, platformDns, platformRequestHeaders, platformTunnels, } from './platform-providers.js';
|
|
3
3
|
/** The key the org's zone step records its Cloudflare zone id under. */
|
|
4
4
|
const ORG_ZONE_SCOPE_KEY = 'cloudflare_zone';
|
|
5
5
|
/** Applied-state key under which an own org's provisioned-services marker is recorded. */
|
|
@@ -17,6 +17,7 @@ export function platformTarget() {
|
|
|
17
17
|
authTunnel: 'platform-auth-tunnel',
|
|
18
18
|
authCloudflared: 'platform-auth-cloudflared',
|
|
19
19
|
mailApp: 'platform-mail-stalwart',
|
|
20
|
+
mailDb: 'platform-mail-postgres',
|
|
20
21
|
mailTunnel: 'platform-mail-tunnel',
|
|
21
22
|
mailCloudflared: 'platform-mail-cloudflared',
|
|
22
23
|
filesDb: 'platform-files-db',
|
|
@@ -66,6 +67,7 @@ export function orgTarget(org) {
|
|
|
66
67
|
authTunnel: `${s}-auth-tunnel`,
|
|
67
68
|
authCloudflared: `${s}-auth-cloudflared`,
|
|
68
69
|
mailApp: `${s}-mail-stalwart`,
|
|
70
|
+
mailDb: `${s}-mail-postgres`,
|
|
69
71
|
mailTunnel: `${s}-mail-tunnel`,
|
|
70
72
|
mailCloudflared: `${s}-mail-cloudflared`,
|
|
71
73
|
filesDb: `${s}-files-db`,
|
|
@@ -123,6 +125,7 @@ export function platformNetwork(deps, scope, step) {
|
|
|
123
125
|
return {
|
|
124
126
|
dns: () => platformDns(deps, scope.recordedIds(), step),
|
|
125
127
|
tunnels: () => platformTunnels(deps, scope.recordedIds(), step),
|
|
128
|
+
requestHeaders: () => platformRequestHeaders(deps, scope.recordedIds()),
|
|
126
129
|
zoneId: async (apex) => scope.recordedIds()[apexZoneKey(apex)] ?? (await exactZone(deps.cloudflare, apex))?.id,
|
|
127
130
|
};
|
|
128
131
|
}
|
|
@@ -143,6 +146,7 @@ export function orgNetwork(ports, scope, step) {
|
|
|
143
146
|
throw new Error(`${step}: the host supplies no tunnel port for this org`);
|
|
144
147
|
return ports.tunnels;
|
|
145
148
|
},
|
|
149
|
+
requestHeaders: async () => ports.requestHeaders,
|
|
146
150
|
zoneId: async (apex) => {
|
|
147
151
|
// The recorded zone is the company's own; `oikos.host` is never it.
|
|
148
152
|
const recorded = apex === NO_DOMAIN_ZONE ? undefined : scope.recordedIds()[ORG_ZONE_SCOPE_KEY];
|
package/dist/plan/plan-apply.js
CHANGED
|
@@ -22,7 +22,7 @@ import { findNameClashes, nameClashMessage } from './org-names.js';
|
|
|
22
22
|
import { ownHostnames } from './own-hostnames.js';
|
|
23
23
|
import { OWN_FILES_R2_UNDELIVERED_SCOPE_KEY, orgTarget } from './own-services.js';
|
|
24
24
|
import { PLATFORM_ARCHON_KEY, PLATFORM_BACKUP_DATABASE_SCOPE_KEYS, PLATFORM_FILES_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_FILES_KEY, appStepKey, planPlatform as computePlatformPlanDetail, toPlatformPlan, } from './platform-diff.js';
|
|
25
|
-
import { DEFAULT_ORG_PLATFORM_READINESS, ORG_PLATFORM_KEY_REFS, agoraHostValuesForOwn, agoraHostValuesFromPlatform, dnsBlockedReason, heldOwnKeyRefs, heldPlatformKeyRefs, orgPlatformReadinessFor, orgPlatformReadinessFrom, ownerFilesFrom, ownerSignInFrom, platformOwnerUserIdFrom, serviceGitRefsOf, } from './platform-org.js';
|
|
25
|
+
import { DEFAULT_ORG_PLATFORM_READINESS, ORG_PLATFORM_KEY_REFS, agoraHostValuesForOwn, agoraHostValuesFromPlatform, dnsBlockedReason, heldOwnKeyRefs, heldPlatformKeyRefs, orgPlatformReadinessFor, orgPlatformReadinessFrom, ownerChatFrom, ownerFilesFrom, ownerSignInFrom, platformOwnerUserIdFrom, serviceGitRefsOf, } from './platform-org.js';
|
|
26
26
|
import { PLATFORM_AUTH_BROKER_MAIL_KEY_REF, PLATFORM_BACKUP_S3_STORAGE_SCOPE_KEY, } from './platform-providers.js';
|
|
27
27
|
import { CLOUDFLARE_TUNNEL_ENTRY_ROUTES_SCOPE_KEY, CLOUDFLARE_TUNNEL_OIKOS_HOSTNAMES_SCOPE_KEY, } from './proxy-labels.js';
|
|
28
28
|
import { liveWorkers, workerTraceScopeKeys } from './worker.js';
|
|
@@ -1330,9 +1330,13 @@ export class FoundryPlanApply {
|
|
|
1330
1330
|
async platformOwnerInput(platform) {
|
|
1331
1331
|
const owner = await this.store.get(platform.ownerOrgId);
|
|
1332
1332
|
if (!owner)
|
|
1333
|
-
return { signIn: null, files: null };
|
|
1333
|
+
return { signIn: null, files: null, chat: null };
|
|
1334
1334
|
const recorded = (await this.store.getAppliedState(owner.id))?.serviceIds ?? {};
|
|
1335
|
-
return {
|
|
1335
|
+
return {
|
|
1336
|
+
signIn: ownerSignInFrom(owner, recorded),
|
|
1337
|
+
files: ownerFilesFrom(owner, recorded),
|
|
1338
|
+
chat: ownerChatFrom(owner, recorded),
|
|
1339
|
+
};
|
|
1336
1340
|
}
|
|
1337
1341
|
/**
|
|
1338
1342
|
* What the shared mail relay needs from the orgs. A route exists for an org
|
|
@@ -1030,6 +1030,25 @@ export declare const PLATFORM_UPTIME_APPLIED_SECRETS_SCOPE_KEY = "uptime_applied
|
|
|
1030
1030
|
export declare const PLATFORM_UPTIME_APPLIED_VARS_SCOPE_KEY = "uptime_applied_vars";
|
|
1031
1031
|
/** `'1'` once the step removed the Worker because the platform no longer enables it; cleared when it deploys again. */
|
|
1032
1032
|
export declare const PLATFORM_UPTIME_REMOVED_SCOPE_KEY = "uptime_removed";
|
|
1033
|
+
/**
|
|
1034
|
+
* The chat bot's room (`!id:server`), recorded as soon as chat-service names it.
|
|
1035
|
+
* Recorded before the bot's token is held, so a crash between the two leaves the room known.
|
|
1036
|
+
*/
|
|
1037
|
+
export declare const PLATFORM_UPTIME_CHAT_ROOM_ID_SCOPE_KEY = "platform_uptime_chat_room_id";
|
|
1038
|
+
/**
|
|
1039
|
+
* A random id, recorded and persisted before the chat route is called (it mints the bot's token) and
|
|
1040
|
+
* cleared once that token is held. Set while the token is not held, it means a token was minted that may
|
|
1041
|
+
* be lost, so the next call asks the route to rotate it.
|
|
1042
|
+
*/
|
|
1043
|
+
export declare const PLATFORM_UPTIME_CHAT_UNDELIVERED_SCOPE_KEY = "platform_uptime_chat_token_undelivered";
|
|
1044
|
+
/**
|
|
1045
|
+
* The Worker's plain text variables: the chat homeserver and room foundry made, under whatever the
|
|
1046
|
+
* host configured (a host value that is set wins). Unset values are left out.
|
|
1047
|
+
*/
|
|
1048
|
+
export declare function uptimeEffectiveVars(hostVars: Readonly<Record<string, string | undefined>> | undefined, chat: {
|
|
1049
|
+
homeserverUrl: string;
|
|
1050
|
+
roomId: string;
|
|
1051
|
+
} | null): Record<string, string | undefined>;
|
|
1033
1052
|
/** The digest of the Worker's plain text variables that are set; empty when none is. */
|
|
1034
1053
|
export declare function uptimeVarsDigest(vars?: Readonly<Record<string, string | undefined>>): string;
|
|
1035
1054
|
/** The Worker secret names the step sets: the three it mints, and each held one. */
|
|
@@ -1164,6 +1183,16 @@ export interface PlanPlatformOptions {
|
|
|
1164
1183
|
access: boolean;
|
|
1165
1184
|
vars: string;
|
|
1166
1185
|
};
|
|
1186
|
+
/**
|
|
1187
|
+
* The uptime Worker's chat bot, when the host wired one. `pending`: the bot's token is not held and
|
|
1188
|
+
* Company Included's chat is applied, so the step makes it. `blocked`: why it cannot yet (a fixed
|
|
1189
|
+
* line, reported without stopping the rest of the Worker). Absent: no bot path, so the plan keeps
|
|
1190
|
+
* asking for a hand-held credential.
|
|
1191
|
+
*/
|
|
1192
|
+
uptimeChat?: {
|
|
1193
|
+
pending: boolean;
|
|
1194
|
+
blocked?: string;
|
|
1195
|
+
};
|
|
1167
1196
|
/** Why Archon's step must wait: the deployment it triggered is still running. Blocks even an applied step. */
|
|
1168
1197
|
archonDeployRunning?: string;
|
|
1169
1198
|
/**
|
|
@@ -1279,6 +1308,7 @@ export declare const PLATFORM_BACKUP_DATABASE_SCOPE_KEYS: {
|
|
|
1279
1308
|
readonly archon: "coolify_platform_archon_database";
|
|
1280
1309
|
readonly ai: "coolify_platform_ai_database";
|
|
1281
1310
|
readonly integrations: "coolify_integrations_database";
|
|
1311
|
+
readonly mail: "coolify_mail_database";
|
|
1282
1312
|
};
|
|
1283
1313
|
export type PlatformBackupServiceKey = keyof typeof PLATFORM_BACKUP_DATABASE_SCOPE_KEYS;
|
|
1284
1314
|
export declare const PLATFORM_BACKUP_SERVICE_KEYS: readonly PlatformBackupServiceKey[];
|