@wtfalch/foundry 0.16.13 → 0.16.14
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.
|
@@ -125,6 +125,18 @@ export declare const PLATFORM_ARCHON_APPLIED_BROKER_SCOPE_KEY = "archon_applied_
|
|
|
125
125
|
* between is repaired by the next one.
|
|
126
126
|
*/
|
|
127
127
|
export declare const PLATFORM_ARCHON_GATE_CLOSED_SCOPE_KEY = "archon_gate_closed";
|
|
128
|
+
/**
|
|
129
|
+
* The ZITADEL SMTP provider (Lettermint) `provisionPlatformAuth` configured on
|
|
130
|
+
* the platform's instance, recorded as the provider id. Without it ZITADEL
|
|
131
|
+
* cannot send the owner's invite, so a platform applied before it existed
|
|
132
|
+
* plans the auth step again.
|
|
133
|
+
*/
|
|
134
|
+
export declare const PLATFORM_AUTH_SMTP_SCOPE_KEY = "zitadel_platform_smtp_provider_id";
|
|
135
|
+
/**
|
|
136
|
+
* The platform owner's ZITADEL user id, recorded once the invite email was
|
|
137
|
+
* requested, so the invite goes out once. `none` when no owner is declared.
|
|
138
|
+
*/
|
|
139
|
+
export declare const PLATFORM_AUTH_OWNER_INVITE_SCOPE_KEY = "zitadel_platform_owner_invite_user_id";
|
|
128
140
|
export declare const PLATFORM_AUTH_ADMIN_USER_SCOPE_KEY = "zitadel_platform_admin_user_id";
|
|
129
141
|
export declare const PLATFORM_AUTH_ADMIN_UNDELIVERED_SCOPE_KEY = "zitadel_platform_admin_user_undelivered";
|
|
130
142
|
/** #283: the created instance's id, recorded once its owner token is delivered. */
|
|
@@ -145,6 +145,18 @@ export const PLATFORM_ARCHON_APPLIED_BROKER_SCOPE_KEY = 'archon_applied_broker_a
|
|
|
145
145
|
* between is repaired by the next one.
|
|
146
146
|
*/
|
|
147
147
|
export const PLATFORM_ARCHON_GATE_CLOSED_SCOPE_KEY = 'archon_gate_closed';
|
|
148
|
+
/**
|
|
149
|
+
* The ZITADEL SMTP provider (Lettermint) `provisionPlatformAuth` configured on
|
|
150
|
+
* the platform's instance, recorded as the provider id. Without it ZITADEL
|
|
151
|
+
* cannot send the owner's invite, so a platform applied before it existed
|
|
152
|
+
* plans the auth step again.
|
|
153
|
+
*/
|
|
154
|
+
export const PLATFORM_AUTH_SMTP_SCOPE_KEY = 'zitadel_platform_smtp_provider_id';
|
|
155
|
+
/**
|
|
156
|
+
* The platform owner's ZITADEL user id, recorded once the invite email was
|
|
157
|
+
* requested, so the invite goes out once. `none` when no owner is declared.
|
|
158
|
+
*/
|
|
159
|
+
export const PLATFORM_AUTH_OWNER_INVITE_SCOPE_KEY = 'zitadel_platform_owner_invite_user_id';
|
|
148
160
|
export const PLATFORM_AUTH_ADMIN_USER_SCOPE_KEY = 'zitadel_platform_admin_user_id';
|
|
149
161
|
export const PLATFORM_AUTH_ADMIN_UNDELIVERED_SCOPE_KEY = 'zitadel_platform_admin_user_undelivered';
|
|
150
162
|
/** #283: the created instance's id, recorded once its owner token is delivered. */
|
|
@@ -1131,6 +1143,10 @@ function planAuth(platform, recordedIds, executorBlocked, executorMissing, authD
|
|
|
1131
1143
|
brokerApplied &&
|
|
1132
1144
|
brokerDeployed &&
|
|
1133
1145
|
loginClientApplied &&
|
|
1146
|
+
// Mail and the owner's invite: a platform applied before they existed
|
|
1147
|
+
// plans the step again, which only adds them.
|
|
1148
|
+
Boolean(recordedIds[PLATFORM_AUTH_SMTP_SCOPE_KEY]) &&
|
|
1149
|
+
Boolean(recordedIds[PLATFORM_AUTH_OWNER_INVITE_SCOPE_KEY]) &&
|
|
1134
1150
|
// The ZITADEL run options reach the container only through the auth
|
|
1135
1151
|
// step's redeploy, so a platform recorded before them still plans it.
|
|
1136
1152
|
recordedIds[PLATFORM_AUTH_ZITADEL_RUN_OPTIONS_SCOPE_KEY] === AUTH_ZITADEL_RUN_OPTIONS) {
|
|
@@ -13,13 +13,32 @@ import { type CallsSfuPlatformDeps } from './platform-sfu.js';
|
|
|
13
13
|
* positions, so every #167-era caller of {@link FoundryPlatformStepExecutor}
|
|
14
14
|
* (zone only) keeps compiling with this third argument simply omitted.
|
|
15
15
|
*/
|
|
16
|
+
/**
|
|
17
|
+
* The SMTP call `provisionPlatformAuth` makes on the instance's ZITADEL.
|
|
18
|
+
* `@wtfalch/providers` gains it in 0.7.2; stated here so foundry compiles
|
|
19
|
+
* against 0.7.1 and tests use fakes.
|
|
20
|
+
*/
|
|
21
|
+
export interface PlatformZitadelSmtp {
|
|
22
|
+
ensureSmtpProvider(config: {
|
|
23
|
+
host: string;
|
|
24
|
+
user: string;
|
|
25
|
+
password: string;
|
|
26
|
+
senderAddress: string;
|
|
27
|
+
senderName: string;
|
|
28
|
+
tls: boolean;
|
|
29
|
+
description: string;
|
|
30
|
+
}): Promise<{
|
|
31
|
+
id: string;
|
|
32
|
+
changed: boolean;
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
16
35
|
export interface PlatformAuthDeps {
|
|
17
36
|
coolify: Pick<CoolifyPort, 'findProjectByName' | 'createProject' | 'findOrCreateEnvironment' | 'listServers' | 'findApplicationByName' | 'getApplication' | 'requireGithubApp' | 'createGithubAppApplication' | 'createDockerImageApplication' | 'createDockerfileApplication' | 'createPostgresDatabase' | 'getDatabase' | 'bulkUpsertEnvs' | 'listEnvs' | 'updateApplication' | 'deploy' | 'raw'>;
|
|
18
37
|
cloudflare: Pick<CloudflarePort, 'findZoneByApex' | 'findTunnelByName' | 'createTunnel' | 'putTunnelConfig' | 'findDnsRecord' | 'createDnsRecord' | 'updateDnsRecord'
|
|
19
38
|
/** #197: fetches the tunnel's connector token for {@link ensureCloudflaredConnector}. */
|
|
20
39
|
| 'getTunnelToken'>;
|
|
21
40
|
/** Must target the platform's own new instance (its issuer), or `zitadelForInstance` must be set. */
|
|
22
|
-
zitadel: Pick<ZitadelPort, 'findOrCreateOrg' | 'mintAdminMachineUser' | 'mintLoginClientMachineUser' | 'listLoginClientPats'
|
|
41
|
+
zitadel: Pick<ZitadelPort, 'findOrCreateOrg' | 'mintAdminMachineUser' | 'mintLoginClientMachineUser' | 'listLoginClientPats' | 'inviteOrgOwner'> & PlatformZitadelSmtp;
|
|
23
42
|
/**
|
|
24
43
|
* Builds the ZITADEL port for the new instance from its issuer URL
|
|
25
44
|
* (`https://<auth.hostname>`). When set it is used instead of
|
|
@@ -198,7 +217,7 @@ export declare class FoundryPlatformStepExecutor implements PlatformStepExecutor
|
|
|
198
217
|
private readonly ai?;
|
|
199
218
|
private readonly archon?;
|
|
200
219
|
private readonly backup?;
|
|
201
|
-
constructor(cloudflare: Pick<CloudflarePort, 'findZoneByApex' | 'createZone'>, declaredOrgStore: Pick<DeclaredOrgStore, 'findOrgIdForZone' | 'list'>, options?: FoundryPlatformStepExecutorOptions);
|
|
220
|
+
constructor(cloudflare: Pick<CloudflarePort, 'findZoneByApex' | 'createZone'>, declaredOrgStore: Pick<DeclaredOrgStore, 'findOrgIdForZone' | 'list' | 'get'>, options?: FoundryPlatformStepExecutorOptions);
|
|
202
221
|
blockedSteps(platform: DeclaredPlatform, recordedIds?: Readonly<Record<string, string>>): Promise<{
|
|
203
222
|
auth?: string;
|
|
204
223
|
authExecutorMissing?: boolean;
|
|
@@ -6,7 +6,7 @@ import { redactSecrets } from '../calls-sfu-deploy-support.js';
|
|
|
6
6
|
import { ensureCloudflaredConnector } from './cloudflared-connector.js';
|
|
7
7
|
import { ACCESS_POLICY_NAME, getDatabaseStarted, isNotFoundError, isRunningOrStarting, } from './executor.js';
|
|
8
8
|
import { coolifyDomains } from './hostnames.js';
|
|
9
|
-
import { AUTH_ZITADEL_RUN_OPTIONS, JOBS_SCHEDULER_KEY, PLATFORM_AI_APPLIED_GITREF_SCOPE_KEY, PLATFORM_AI_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_AI_DEPLOY_PENDING_SCOPE_KEY, PLATFORM_AI_INTERNAL_URL_SCOPE_KEY, PLATFORM_AI_KEY, PLATFORM_AI_MANAGEMENT_KEY_CONFLICT_SCOPE_KEY, PLATFORM_AI_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_AI_MANAGEMENT_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_AI_MIGRATE_BLOCKED_SCOPE_KEY, PLATFORM_AI_ORGANISATION_SCOPE_KEY, PLATFORM_AI_RUNNER_DEPLOYMENT_SCOPE_KEY, PLATFORM_AI_SIGNING_KEY_SET_SCOPE_KEY, PLATFORM_AI_SIGNING_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_BROKER_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_ARCHON_CONNECTOR_APP_SCOPE_KEY, PLATFORM_ARCHON_GATE_CLOSED_SCOPE_KEY, PLATFORM_ARCHON_KEY, PLATFORM_ARCHON_MASTER_CLOUDFLARE_TOKEN_REF, PLATFORM_ARCHON_MASTER_COOLIFY_TOKEN_REF, PLATFORM_ARCHON_MASTER_COOLIFY_URL_REF, PLATFORM_AUTH_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_ADMIN_USER_SCOPE_KEY, PLATFORM_AUTH_BROKER_DEPLOYED_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_KEY, PLATFORM_AUTH_LOGIN_CLIENT_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_LOGIN_CLIENT_USER_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_APPLIED_IMAGE_TAG_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_RUN_OPTIONS_SCOPE_KEY, PLATFORM_BACKUP_DATABASE_SCOPE_KEYS, PLATFORM_BACKUP_SERVICE_KEYS, 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_KEY, PLATFORM_FILES_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_FILES_MANAGEMENT_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_INTEGRATIONS_APPLIED_GITREF_SCOPE_KEY, PLATFORM_INTEGRATIONS_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY, PLATFORM_INTEGRATIONS_KEY_SET_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_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_CONNECTOR_APP_SCOPE_KEY, PLATFORM_MAIL_INTERNAL_URL_SCOPE_KEY, PLATFORM_MAIL_KEY, PLATFORM_MAIL_ZITADEL_PROJECT_SCOPE_KEY, parseBrokerDeployRecord, parseLoginClientRecord, platformMailMxHost, } from './platform-diff.js';
|
|
9
|
+
import { AUTH_ZITADEL_RUN_OPTIONS, JOBS_SCHEDULER_KEY, PLATFORM_AI_APPLIED_GITREF_SCOPE_KEY, PLATFORM_AI_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_AI_DEPLOY_PENDING_SCOPE_KEY, PLATFORM_AI_INTERNAL_URL_SCOPE_KEY, PLATFORM_AI_KEY, PLATFORM_AI_MANAGEMENT_KEY_CONFLICT_SCOPE_KEY, PLATFORM_AI_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_AI_MANAGEMENT_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_AI_MIGRATE_BLOCKED_SCOPE_KEY, PLATFORM_AI_ORGANISATION_SCOPE_KEY, PLATFORM_AI_RUNNER_DEPLOYMENT_SCOPE_KEY, PLATFORM_AI_SIGNING_KEY_SET_SCOPE_KEY, PLATFORM_AI_SIGNING_KEY_UNDELIVERED_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_BROKER_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_GIT_REF_SCOPE_KEY, PLATFORM_ARCHON_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_ARCHON_CONNECTOR_APP_SCOPE_KEY, PLATFORM_ARCHON_GATE_CLOSED_SCOPE_KEY, PLATFORM_ARCHON_KEY, PLATFORM_ARCHON_MASTER_CLOUDFLARE_TOKEN_REF, PLATFORM_ARCHON_MASTER_COOLIFY_TOKEN_REF, PLATFORM_ARCHON_MASTER_COOLIFY_URL_REF, PLATFORM_AUTH_ADMIN_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_ADMIN_USER_SCOPE_KEY, PLATFORM_AUTH_BROKER_DEPLOYED_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_KEY, PLATFORM_AUTH_LOGIN_CLIENT_UNDELIVERED_SCOPE_KEY, PLATFORM_AUTH_LOGIN_CLIENT_USER_SCOPE_KEY, PLATFORM_AUTH_OWNER_INVITE_SCOPE_KEY, PLATFORM_AUTH_SMTP_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_APPLIED_IMAGE_TAG_SCOPE_KEY, PLATFORM_AUTH_ZITADEL_RUN_OPTIONS_SCOPE_KEY, PLATFORM_BACKUP_DATABASE_SCOPE_KEYS, PLATFORM_BACKUP_SERVICE_KEYS, 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_KEY, PLATFORM_FILES_MANAGEMENT_KEY_SCOPE_KEY, PLATFORM_FILES_MANAGEMENT_UNDELIVERED_SCOPE_KEY, PLATFORM_FILES_ZITADEL_PROJECT_SCOPE_KEY, PLATFORM_INTEGRATIONS_APPLIED_GITREF_SCOPE_KEY, PLATFORM_INTEGRATIONS_APPLIED_HOSTNAME_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY, PLATFORM_INTEGRATIONS_KEY_SET_SCOPE_KEY, PLATFORM_INTEGRATIONS_KEY_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_CONNECTOR_APP_SCOPE_KEY, PLATFORM_MAIL_INTERNAL_URL_SCOPE_KEY, PLATFORM_MAIL_KEY, PLATFORM_MAIL_ZITADEL_PROJECT_SCOPE_KEY, parseBrokerDeployRecord, parseLoginClientRecord, platformMailMxHost, } from './platform-diff.js';
|
|
10
10
|
import { applyCallsSfuPlatformStep } from './platform-sfu.js';
|
|
11
11
|
import { CreateInstanceError, createZitadelInstance, generateSystemApiKeypair, instanceWithoutBearerMessage, systemApiUsersEnv, } from './zitadel-system-api.js';
|
|
12
12
|
/** The key `runPlatformSteps` records the apex zone's id under (`system:kind:key`). */
|
|
@@ -302,7 +302,8 @@ export class FoundryPlatformStepExecutor {
|
|
|
302
302
|
if (!this.auth) {
|
|
303
303
|
throw new Error('platform:auth needs FoundryPlatformStepExecutor to be constructed with its auth dependencies (#168)');
|
|
304
304
|
}
|
|
305
|
-
|
|
305
|
+
const company = await this.declaredOrgStore.get(context.platform.ownerOrgId);
|
|
306
|
+
return provisionPlatformAuth(context, this.auth, company?.owners ?? []);
|
|
306
307
|
}
|
|
307
308
|
if (action.system === 'coolify' && action.kind === 'app' && action.key === PLATFORM_FILES_KEY) {
|
|
308
309
|
if (!this.files) {
|
|
@@ -856,7 +857,7 @@ async function liveLoginClientTokenHash(coolify, appId) {
|
|
|
856
857
|
* #197: a `cloudflared` connector for this tunnel is run
|
|
857
858
|
* ({@link ensureCloudflaredConnector}), so `hostname` answers.
|
|
858
859
|
*/
|
|
859
|
-
async function provisionPlatformAuth(context, deps) {
|
|
860
|
+
async function provisionPlatformAuth(context, deps, owners = []) {
|
|
860
861
|
const { platform } = context;
|
|
861
862
|
const hostname = platform.auth.hostname;
|
|
862
863
|
const gitRef = platform.auth.gitRef;
|
|
@@ -1403,8 +1404,62 @@ async function provisionPlatformAuth(context, deps) {
|
|
|
1403
1404
|
// own doc comment, and `authLoginClientDrifted`'s, for why.
|
|
1404
1405
|
await record(PLATFORM_AUTH_LOGIN_CLIENT_USER_SCOPE_KEY, loginClientRecordValue(loginClientUserId, loginClientPatId, loginClientToken));
|
|
1405
1406
|
}
|
|
1407
|
+
// ---- ZITADEL mail and the owner's invite ----------------------------------
|
|
1408
|
+
// The token is the held key, else the broker's live env. Absent, nothing
|
|
1409
|
+
// here can run; `authBrokerBlockedReason` already reports it by name.
|
|
1410
|
+
const mailToken = heldMailKey || (await currentEnvValue(deps.coolify, brokerAppId, 'LETTERMINT_API_TOKEN'));
|
|
1411
|
+
if (mailToken) {
|
|
1412
|
+
const mailZitadel = deps.zitadelForInstance?.(`https://${hostname}`) ?? deps.zitadel;
|
|
1413
|
+
try {
|
|
1414
|
+
// Runs every time the step does (idempotent), so a rotated token lands.
|
|
1415
|
+
const smtp = await mailZitadel.ensureSmtpProvider({
|
|
1416
|
+
host: PLATFORM_AUTH_SMTP_HOST,
|
|
1417
|
+
user: PLATFORM_AUTH_SMTP_USER,
|
|
1418
|
+
password: mailToken,
|
|
1419
|
+
senderAddress: `noreply@${platform.apex}`,
|
|
1420
|
+
senderName: PLATFORM_AUTH_MAIL_SENDER_NAME,
|
|
1421
|
+
tls: true,
|
|
1422
|
+
description: PLATFORM_AUTH_SMTP_DESCRIPTION,
|
|
1423
|
+
});
|
|
1424
|
+
await record(PLATFORM_AUTH_SMTP_SCOPE_KEY, smtp.id);
|
|
1425
|
+
}
|
|
1426
|
+
catch {
|
|
1427
|
+
throw new Error(`platform:auth: could not configure ZITADEL's SMTP provider for ${hostname}; the cause is left out because it can carry the Lettermint key`);
|
|
1428
|
+
}
|
|
1429
|
+
if (!context.recordedIds()[PLATFORM_AUTH_OWNER_INVITE_SCOPE_KEY]) {
|
|
1430
|
+
const owner = owners[0];
|
|
1431
|
+
if (!owner) {
|
|
1432
|
+
// No owner declared: nothing to invite. Recorded so the step is not replanned for it.
|
|
1433
|
+
await record(PLATFORM_AUTH_OWNER_INVITE_SCOPE_KEY, 'none');
|
|
1434
|
+
}
|
|
1435
|
+
else {
|
|
1436
|
+
const ownerOrgId = context.recordedIds()[PLATFORM_ZITADEL_ORG_SCOPE_KEY] ??
|
|
1437
|
+
(await mailZitadel.findOrCreateOrg(PLATFORM_AUTH_ORG_NAME)).org.id;
|
|
1438
|
+
await record(PLATFORM_ZITADEL_ORG_SCOPE_KEY, ownerOrgId);
|
|
1439
|
+
let invitedUserId;
|
|
1440
|
+
try {
|
|
1441
|
+
({ userId: invitedUserId } = await mailZitadel.inviteOrgOwner(ownerOrgId, {
|
|
1442
|
+
givenName: owner.givenName,
|
|
1443
|
+
familyName: owner.familyName,
|
|
1444
|
+
email: owner.email,
|
|
1445
|
+
}));
|
|
1446
|
+
}
|
|
1447
|
+
catch {
|
|
1448
|
+
throw new Error(`platform:auth: could not invite the platform owner into ZITADEL org ${ownerOrgId}; the cause is left out because it can carry the owner's email`);
|
|
1449
|
+
}
|
|
1450
|
+
await record(PLATFORM_AUTH_OWNER_INVITE_SCOPE_KEY, invitedUserId);
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1406
1454
|
return { resourceId: zitadelAppId };
|
|
1407
1455
|
}
|
|
1456
|
+
/** Lettermint's SMTP relay, as ZITADEL's SMTP provider wants it: `host:port`, STARTTLS. */
|
|
1457
|
+
const PLATFORM_AUTH_SMTP_HOST = 'smtp.lettermint.co:587';
|
|
1458
|
+
const PLATFORM_AUTH_SMTP_USER = 'lettermint';
|
|
1459
|
+
/** Marks the provider as foundry's, so `ensureSmtpProvider` finds it again. */
|
|
1460
|
+
const PLATFORM_AUTH_SMTP_DESCRIPTION = 'foundry:platform:lettermint';
|
|
1461
|
+
/** The same name the broker's `from` uses (`Company Included <noreply@apex>`). */
|
|
1462
|
+
const PLATFORM_AUTH_MAIL_SENDER_NAME = 'Company Included';
|
|
1408
1463
|
// ---------------------------------------------------------------------------
|
|
1409
1464
|
// #169: the platform's own mail server (Stalwart)
|
|
1410
1465
|
// ---------------------------------------------------------------------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wtfalch/foundry",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.14",
|
|
4
4
|
"description": "Foundry's SDK: the declared org's types, the plan and apply contracts, and the state store's interface.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@wtfalch/audit": "0.6.0",
|
|
44
44
|
"@wtfalch/auth": "0.16.0",
|
|
45
45
|
"@wtfalch/email": "^0.17.0",
|
|
46
|
-
"@wtfalch/providers": "0.
|
|
46
|
+
"@wtfalch/providers": "0.7.2",
|
|
47
47
|
"ssh2": "1.17.0",
|
|
48
48
|
"zod": "4.6.5"
|
|
49
49
|
},
|