@wtfalch/foundry 0.65.0 → 0.67.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/apps/cloudflare.d.ts +5 -0
- package/dist/apps/deploy.js +33 -1
- package/dist/apps/migrations.d.ts +3 -0
- package/dist/apps/migrations.js +32 -7
- package/dist/catalogue/copy-en.js +5 -0
- package/dist/catalogue/integrations.js +5 -0
- package/dist/entry-rules.d.ts +11 -0
- package/dist/entry-rules.js +70 -0
- package/dist/index.d.ts +9 -4
- package/dist/index.js +5 -2
- package/dist/migrations/0069_release_events.sql +16 -0
- package/dist/modules/analytics.d.ts +8 -0
- package/dist/modules/analytics.js +28 -0
- package/dist/modules/database.js +22 -3
- package/dist/modules/index.js +2 -0
- package/dist/native-build.d.ts +16 -12
- package/dist/native-build.js +16 -12
- package/dist/org.d.ts +9 -1
- package/dist/org.js +4 -1
- package/dist/plan/analytics-boule.d.ts +17 -0
- package/dist/plan/analytics-boule.js +43 -0
- package/dist/plan/analytics.d.ts +58 -0
- package/dist/plan/analytics.js +89 -0
- package/dist/plan/boule.js +2 -0
- package/dist/plan/company-backups.js +2 -0
- package/dist/plan/diff.d.ts +4 -0
- package/dist/plan/diff.js +103 -3
- package/dist/plan/entry-analytics-key.d.ts +35 -0
- package/dist/plan/entry-analytics-key.js +134 -0
- package/dist/plan/executor.d.ts +79 -6
- package/dist/plan/executor.js +379 -19
- package/dist/plan/hostnames.js +4 -0
- package/dist/plan/index.d.ts +2 -0
- package/dist/plan/index.js +1 -0
- package/dist/plan/live.d.ts +1 -1
- package/dist/plan/locked-hostnames.js +3 -0
- package/dist/plan/login-host.d.ts +8 -0
- package/dist/plan/login-host.js +8 -0
- package/dist/plan/org-names.d.ts +3 -3
- package/dist/plan/org-names.js +3 -0
- package/dist/plan/own-limits.d.ts +6 -0
- package/dist/plan/own-limits.js +1 -0
- package/dist/plan/plan-apply.d.ts +12 -0
- package/dist/plan/plan-apply.js +40 -1
- package/dist/plan/platform-diff.d.ts +17 -1
- package/dist/plan/platform-diff.js +40 -2
- package/dist/plan/platform-org.d.ts +6 -0
- package/dist/plan/platform-providers.d.ts +8 -6
- package/dist/plan/platform-providers.js +56 -10
- package/dist/plan/providers-readers.js +16 -1
- package/dist/plan/release-host.d.ts +30 -1
- package/dist/plan/release-host.js +84 -41
- package/dist/plan/release-series-reader.d.ts +26 -0
- package/dist/plan/release-series-reader.js +40 -0
- package/dist/plan/sign-in-archon.d.ts +1 -1
- package/dist/plan/sign-in-archon.js +2 -2
- package/dist/plan/stage-services.d.ts +3 -1
- package/dist/plan/stage-services.js +2 -1
- package/dist/plan/uptime-worker.js +53 -3
- package/dist/plan/worker-app-database.d.ts +12 -1
- package/dist/plan/worker-app-database.js +13 -0
- package/dist/plan/worker-app.d.ts +27 -2
- package/dist/plan/worker-app.js +52 -7
- package/dist/plan/workspace.d.ts +2 -2
- package/dist/plan/workspace.js +3 -3
- package/dist/release/decide.d.ts +2 -0
- package/dist/release/decide.js +67 -10
- package/dist/release/events.d.ts +13 -0
- package/dist/release/events.js +67 -0
- package/dist/release/health.d.ts +5 -0
- package/dist/release/health.js +3 -3
- package/dist/release/run.d.ts +7 -2
- package/dist/release/run.js +8 -0
- package/dist/release/series.d.ts +58 -0
- package/dist/release/series.js +65 -0
- package/dist/release/state.d.ts +58 -1
- package/dist/release/state.js +45 -0
- package/dist/release/types.d.ts +44 -0
- package/dist/slug.d.ts +1 -1
- package/dist/slug.js +5 -2
- package/dist/store/postgres.js +29 -3
- package/dist/store/schema.d.ts +112 -0
- package/dist/store/schema.js +9 -0
- package/dist/worker-app-config.d.ts +22 -1
- package/dist/worker-app-config.js +73 -15
- package/dist/worker-app-migrations.d.ts +6 -2
- package/dist/worker-app-migrations.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { analyticsUrlFor } from './analytics.js';
|
|
2
|
+
import { appStepKey } from './platform-diff.js';
|
|
3
|
+
/**
|
|
4
|
+
* `uses.analytics` on a server entry: one site key of its own at the company's analytics backend, minted
|
|
5
|
+
* through `POST /v1/site-keys` with the operator key and written as `ANALYTICS_URL` and `ANALYTICS_SITE_KEY` to
|
|
6
|
+
* the entry's env. The backend shows the secret once, so this follows rule 1 of CLAUDE.md "Platform steps":
|
|
7
|
+
*
|
|
8
|
+
* 1. the key's id is recorded as `analytics_key_undelivered.<entry>` and persisted before the env is written;
|
|
9
|
+
* 2. the env write is tried 3 times with the same secret; the id is the main id `analytics:key:<orgId>:<entry>`
|
|
10
|
+
* and the applied marker only after it worked, and the undelivered marker is cleared then;
|
|
11
|
+
* 3. a marker left behind (every try failed) is reported blocked and never minted again.
|
|
12
|
+
*
|
|
13
|
+
* A Worker app entry is skipped: Boule installs its keys per copy. The entry's stage gets its own key through
|
|
14
|
+
* `plan/stage-services.ts` (service `analytics`, environment `stage`), so the two differ. Removing
|
|
15
|
+
* `uses.analytics` or the entry plans the retire form: revoke the key, take both env names away.
|
|
16
|
+
*/
|
|
17
|
+
export const entryAnalyticsUndeliveredScopeKey = (entryKey) => `analytics_key_undelivered.${entryKey}`;
|
|
18
|
+
/** The address the entry's env was last written with; a change rewrites the address only. */
|
|
19
|
+
export const entryAnalyticsAppliedScopeKey = (entryKey) => `analytics_key_applied.${entryKey}`;
|
|
20
|
+
/** The id of a key that was revoked, so a stale main id is not revoked again. */
|
|
21
|
+
export const entryAnalyticsRetiredScopeKey = (entryKey) => `analytics_key_retired.${entryKey}`;
|
|
22
|
+
export const ENTRY_ANALYTICS_KEY_DELIVERY_ATTEMPTS = 3;
|
|
23
|
+
/** The name the backend knows the key by; its site derives from it. */
|
|
24
|
+
export const entryAnalyticsKeyName = (org, entryKey) => `${org.slug}-${entryKey}-analytics`;
|
|
25
|
+
/** The stage copy's key name: the backend reads the `-stage` suffix as the stage environment. */
|
|
26
|
+
export const stageAnalyticsKeyName = (org, entryKey) => `${org.slug}-${entryKey}-stage-analytics`;
|
|
27
|
+
const servesKey = (entry) => entry.uses?.analytics === true && !entry.workerApp && entry.live !== false;
|
|
28
|
+
export function planEntryAnalyticsKeys(org, recordedIds, plannedSteps, analyticsPort) {
|
|
29
|
+
const steps = [];
|
|
30
|
+
const blocked = [];
|
|
31
|
+
if (!org.hosting.enabled)
|
|
32
|
+
return { steps, blocked };
|
|
33
|
+
const planned = (system, kind, key) => plannedSteps.some((p) => p.action.system === system && p.action.kind === kind && p.action.key === key);
|
|
34
|
+
const wanted = new Map(org.hosting.entries.filter(servesKey).map((e) => [e.key, e]));
|
|
35
|
+
const mainPrefix = `analytics:key:${org.id}:`;
|
|
36
|
+
// Keys whose entry stopped using analytics or is gone: a delivered key (main id) or one minted and never
|
|
37
|
+
// delivered (undelivered marker), so the retire clears the marker and the entry can mint again later.
|
|
38
|
+
const undeliveredPrefix = entryAnalyticsUndeliveredScopeKey('');
|
|
39
|
+
const retiring = new Set();
|
|
40
|
+
for (const [name, id] of Object.entries(recordedIds)) {
|
|
41
|
+
if (!id)
|
|
42
|
+
continue;
|
|
43
|
+
const prefix = name.startsWith(mainPrefix)
|
|
44
|
+
? mainPrefix
|
|
45
|
+
: name.startsWith(undeliveredPrefix)
|
|
46
|
+
? undeliveredPrefix
|
|
47
|
+
: null;
|
|
48
|
+
if (!prefix)
|
|
49
|
+
continue;
|
|
50
|
+
const entryKey = name.slice(prefix.length);
|
|
51
|
+
if (wanted.has(entryKey) ||
|
|
52
|
+
retiring.has(entryKey) ||
|
|
53
|
+
recordedIds[entryAnalyticsRetiredScopeKey(entryKey)] === id) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
retiring.add(entryKey);
|
|
57
|
+
const key = `${mainPrefix}${entryKey}`;
|
|
58
|
+
if (!analyticsPort) {
|
|
59
|
+
blocked.push({
|
|
60
|
+
description: `${org.slug}'s ${entryKey} analytics key is not revoked, not planned: the host supplies no analytics port`,
|
|
61
|
+
key,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
else if (!recordedIds[`coolify:analytics:${org.id}`]) {
|
|
65
|
+
blocked.push({
|
|
66
|
+
description: `${org.slug}'s ${entryKey} analytics key is not revoked, not planned: the analytics backend is not recorded`,
|
|
67
|
+
key,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
steps.push({
|
|
72
|
+
action: {
|
|
73
|
+
system: 'analytics',
|
|
74
|
+
kind: 'key',
|
|
75
|
+
key: `${org.id}:${entryKey}`,
|
|
76
|
+
desired: { mode: 'retire' },
|
|
77
|
+
},
|
|
78
|
+
step: {
|
|
79
|
+
description: `revoke ${org.slug}'s ${entryKey} analytics key and take ANALYTICS_* out of its env: the entry no longer uses analytics`,
|
|
80
|
+
destroys: true,
|
|
81
|
+
migrates: false,
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
for (const entry of wanted.values()) {
|
|
87
|
+
const stepKey = appStepKey(org, entry.key);
|
|
88
|
+
const key = `analytics:key:${stepKey}`;
|
|
89
|
+
const at = `${org.slug}'s ${entry.key} analytics key`;
|
|
90
|
+
const block = (why) => blocked.push({ description: `${at} is blocked: ${why}`, key });
|
|
91
|
+
const url = analyticsUrlFor(org);
|
|
92
|
+
const undelivered = recordedIds[entryAnalyticsUndeliveredScopeKey(entry.key)];
|
|
93
|
+
if (undelivered) {
|
|
94
|
+
block(`key ${undelivered} was minted but never written to the app, and the backend shows a key once; remove the recorded id ${entryAnalyticsUndeliveredScopeKey(entry.key)} to mint a new key, which replaces that one`);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const live = recordedIds[key] &&
|
|
98
|
+
recordedIds[entryAnalyticsRetiredScopeKey(entry.key)] !== recordedIds[key];
|
|
99
|
+
if (live && recordedIds[entryAnalyticsAppliedScopeKey(entry.key)] === url)
|
|
100
|
+
continue;
|
|
101
|
+
if (!analyticsPort) {
|
|
102
|
+
block('the host supplies no analytics port');
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (!recordedIds[`coolify:analytics:${org.id}`] && !planned('coolify', 'analytics', org.id)) {
|
|
106
|
+
block("the company's analytics backend is not recorded or planned yet");
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (!recordedIds[`coolify:app:${stepKey}`] && !planned('coolify', 'app', stepKey)) {
|
|
110
|
+
block("the entry's app is not recorded yet");
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
steps.push({
|
|
114
|
+
action: {
|
|
115
|
+
system: 'analytics',
|
|
116
|
+
kind: 'key',
|
|
117
|
+
key: stepKey,
|
|
118
|
+
desired: {
|
|
119
|
+
mode: live ? 'url' : 'mint',
|
|
120
|
+
name: entryAnalyticsKeyName(org, entry.key),
|
|
121
|
+
analyticsUrl: url,
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
step: {
|
|
125
|
+
description: live
|
|
126
|
+
? `write the analytics address to ${org.slug}'s ${entry.key} env`
|
|
127
|
+
: `mint ${at}, write ANALYTICS_URL and ANALYTICS_SITE_KEY to its env, restart the app`,
|
|
128
|
+
destroys: false,
|
|
129
|
+
migrates: false,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return { steps, blocked };
|
|
134
|
+
}
|
package/dist/plan/executor.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { OrgMailOptions, OrgMailOrg, OrgMailResult } from '@wtfalch/email/p
|
|
|
2
2
|
import { type CallsSfuUrls } from '../calls-sfu.js';
|
|
3
3
|
import type { DeclaredOrg, HostingBuildPack, OrgId } from '../org.js';
|
|
4
4
|
import type { DeclaredOrgStore } from '../store.js';
|
|
5
|
+
import { type AnalyticsPort } from './analytics.js';
|
|
5
6
|
import { type BlueGreenServer, type BlueGreenSubject } from './blue-green.js';
|
|
6
7
|
import { type BouleOwnerSeed } from './boule.js';
|
|
7
8
|
import { type BrokerPort } from './broker-entries.js';
|
|
@@ -844,6 +845,11 @@ export interface ZitadelPort {
|
|
|
844
845
|
postLogoutRedirectUris: string[];
|
|
845
846
|
/** `jwt` for an entry with `uses.auth.mcp` (providers 0.11.0). Omitted: opaque. */
|
|
846
847
|
accessTokenType?: 'jwt' | 'opaque';
|
|
848
|
+
/**
|
|
849
|
+
* The instance's login host. With `loginV2.required` off an app with no base URI of its own lands on
|
|
850
|
+
* the v1 login, so every app foundry makes carries one from the start; a `required` instance ignores it.
|
|
851
|
+
*/
|
|
852
|
+
loginBaseUri?: string;
|
|
847
853
|
}): Promise<{
|
|
848
854
|
appId: string;
|
|
849
855
|
clientId: string;
|
|
@@ -1183,12 +1189,24 @@ export interface ZitadelPort {
|
|
|
1183
1189
|
updateOidcAppLoginBaseUri(orgId: string, projectId: string, appId: string, loginBaseUri: string): Promise<void>;
|
|
1184
1190
|
/**
|
|
1185
1191
|
* Lets each app's own Login V2 base URI count: foundry starts ZITADEL with `LOGINV2_REQUIRED=true`,
|
|
1186
|
-
* which makes the instance ignore it.
|
|
1192
|
+
* which makes the instance ignore it (`internal/query/oidc_client.go` in ZITADEL v4.17.3, lines 88-92:
|
|
1193
|
+
* with `required` the app's own base URI is overwritten by the instance's). Call it through
|
|
1194
|
+
* {@link allowPerAppLoginBaseUris}, which first gives every app a base URI. The host sets the instance feature (`PUT /v2/features/instance`
|
|
1187
1195
|
* with `loginV2.required` false and the instance default as `baseUri`). Called before an app is
|
|
1188
1196
|
* pointed at its own `/sign-in/` on a company that runs its own ZITADEL; the shared instance's
|
|
1189
1197
|
* bindings port does the same for the platform's. Optional: absent, nothing is called.
|
|
1190
1198
|
*/
|
|
1191
1199
|
allowPerAppLoginBaseUri?(instanceBaseUri: string): Promise<void>;
|
|
1200
|
+
/** Every organisation of the instance. Optional: {@link allowPerAppLoginBaseUris} refuses without it. */
|
|
1201
|
+
listOrgs?(): Promise<Array<{
|
|
1202
|
+
id: string;
|
|
1203
|
+
state?: string;
|
|
1204
|
+
}>>;
|
|
1205
|
+
/** Every project of an organisation. Optional: {@link allowPerAppLoginBaseUris} refuses without it. */
|
|
1206
|
+
listProjects?(orgId: string): Promise<Array<{
|
|
1207
|
+
id: string;
|
|
1208
|
+
state?: string;
|
|
1209
|
+
}>>;
|
|
1192
1210
|
/**
|
|
1193
1211
|
* Occupies `userName` in `orgId` with a machine user that has no role and
|
|
1194
1212
|
* no token, so nobody can register under that name. Idempotent: a user
|
|
@@ -1824,6 +1842,8 @@ export interface FoundryStepExecutorPorts {
|
|
|
1824
1842
|
workerAppKeys?: KeysCustodyPort;
|
|
1825
1843
|
/** F7: the keys service's per-company registrar. Without it the plan reports Boule's registrar key blocked (the host also sets `FoundryPlanApplyOptions.keysRegistrarUrl`). */
|
|
1826
1844
|
keysRegistrar?: KeysRegistrarPort;
|
|
1845
|
+
/** The company's analytics backend operator API: mints and revokes site keys. Without it the plan reports each `uses.analytics` key blocked (the host also sets `FoundryPlanApplyOptions.analyticsPort`). */
|
|
1846
|
+
analytics?: AnalyticsPort;
|
|
1827
1847
|
/**
|
|
1828
1848
|
* C3: mints the credential an org's Boule reaches Archon with (org-scoped; `orgs:request` and
|
|
1829
1849
|
* `orgs:read` for that org). Archon implements it. Every call rotates the credential (the old secret
|
|
@@ -2003,6 +2023,10 @@ export declare const BOULE_PORT = 3000;
|
|
|
2003
2023
|
export declare const KOSMOS_REPO = "wtfalch/kosmos";
|
|
2004
2024
|
export declare const KOSMOS_APP_DOCKERFILE = "/Dockerfile";
|
|
2005
2025
|
export declare const KOSMOS_PORT = 3000;
|
|
2026
|
+
/** The company's analytics backend (https://github.com/wtfalch/analytics): root Dockerfile, serves on 3000, migrates in its own start script. */
|
|
2027
|
+
export declare const ANALYTICS_REPO = "wtfalch/analytics";
|
|
2028
|
+
export declare const ANALYTICS_APP_DOCKERFILE = "/Dockerfile";
|
|
2029
|
+
export declare const ANALYTICS_PORT = 3000;
|
|
2006
2030
|
export declare const LOG_DIR = "/app/logs";
|
|
2007
2031
|
/** The company's Coolify destination (its Docker network `co-<slug>`), recorded when its first resource is created. */
|
|
2008
2032
|
export declare const COOLIFY_DESTINATION_SCOPE_KEY = "coolify_destination";
|
|
@@ -2377,6 +2401,12 @@ export declare class FoundryStepExecutor implements StepExecutor, StepDestroyer
|
|
|
2377
2401
|
* the snapshot taken before the repoint still named it.
|
|
2378
2402
|
*/
|
|
2379
2403
|
private zitadelLoginHost;
|
|
2404
|
+
/**
|
|
2405
|
+
* `{ loginBaseUri }` for an app made in the org's ZITADEL: the instance's own login host (a company's own
|
|
2406
|
+
* `auth.` host, else the shared one). Nothing when the shared host is not known. See
|
|
2407
|
+
* {@link FoundryStepExecutorPorts}' `createOidcApp` `loginBaseUri`.
|
|
2408
|
+
*/
|
|
2409
|
+
private instanceLoginBaseUriFor;
|
|
2380
2410
|
/**
|
|
2381
2411
|
* The host table of a company's own in-app login app as a bindings port that collects its edits and
|
|
2382
2412
|
* writes them once on `flush` (one redeploy, none when nothing changed). Used for a company that runs
|
|
@@ -2776,12 +2806,14 @@ export declare class FoundryStepExecutor implements StepExecutor, StepDestroyer
|
|
|
2776
2806
|
*/
|
|
2777
2807
|
private mintIfAbsent;
|
|
2778
2808
|
/**
|
|
2779
|
-
*
|
|
2780
|
-
*
|
|
2781
|
-
*
|
|
2782
|
-
*
|
|
2809
|
+
* foundry#987: nothing reads `NATIVE_BUILD_KEY` any more -- Boule calls Archon's org build
|
|
2810
|
+
* route (`/api/orgs/{orgId}/native/builds`) with its own org credential instead
|
|
2811
|
+
* (`BOULE_ARCHON_CREDENTIAL_ENV`, archon#706, boule#432). This takes the env row away from
|
|
2812
|
+
* every Boule that still has one from #970/#971; `NATIVE_BUILD_KEY_ENV` and
|
|
2813
|
+
* `NATIVE_BUILD_KEY_BYTES` are deprecated and go in the next release (the two-release removal
|
|
2814
|
+
* rule), once no live Boule holds the row any more.
|
|
2783
2815
|
*/
|
|
2784
|
-
private
|
|
2816
|
+
private dropNativeBuildKeyEnv;
|
|
2785
2817
|
/**
|
|
2786
2818
|
* `null` once the app already has one -- `AUTH_COOKIE_SECRET` is generated
|
|
2787
2819
|
* only the first time (task brief), never regenerated or overwritten, so a
|
|
@@ -3400,6 +3432,35 @@ export declare class FoundryStepExecutor implements StepExecutor, StepDestroyer
|
|
|
3400
3432
|
* shape {@link coolifyAgora}'s own doc comment explains.
|
|
3401
3433
|
*/
|
|
3402
3434
|
private coolifyBoule;
|
|
3435
|
+
/**
|
|
3436
|
+
* `plan/diff.ts`'s `planAnalyticsBackend`: the company's analytics backend as one more Coolify application
|
|
3437
|
+
* from https://github.com/wtfalch/analytics's root Dockerfile ({@link ANALYTICS_REPO}), with a database of its
|
|
3438
|
+
* own, shaped like {@link coolifyKosmos}. Its start script migrates as the owner role and then serves as the
|
|
3439
|
+
* runtime role, so `pushDatabaseUrl` gives it both URLs. It needs no sign-in client: it reads only
|
|
3440
|
+
* `AUTH_ORGANIZATION_ID` (the tenant id derives from it), `APP_URL` and the operator key.
|
|
3441
|
+
*
|
|
3442
|
+
* `ANALYTICS_OPERATOR_KEY` is made once here (`mintIfAbsent`) and written only to this app's env. No outside
|
|
3443
|
+
* service shows it once, so no undelivered marker is needed: a failed write leaves nothing live to mint twice.
|
|
3444
|
+
* Steps that call the backend's operator API read it back from this env.
|
|
3445
|
+
*
|
|
3446
|
+
* A brand new app is deployed once ({@link ANALYTICS_DEPLOYED_SCOPE_KEY}), as for Boule (#504).
|
|
3447
|
+
*/
|
|
3448
|
+
private coolifyAnalytics;
|
|
3449
|
+
/** The backend's operator key, read from its own env. Fixed text when the backend or the key is not there. */
|
|
3450
|
+
private analyticsOperatorKey;
|
|
3451
|
+
/**
|
|
3452
|
+
* C2 `coolify:analytics-boule` (`plan/analytics-boule.ts`): the backend's address and operator key into
|
|
3453
|
+
* Boule's env, then Boule restarts. `analytics_boule_applied` is recorded last. Retire takes both names away.
|
|
3454
|
+
*/
|
|
3455
|
+
private analyticsBoule;
|
|
3456
|
+
/**
|
|
3457
|
+
* `plan/entry-analytics-key.ts`: one server entry's site key (CLAUDE.md "Platform steps" rule 1). Mint: the
|
|
3458
|
+
* key's id is recorded as undelivered and persisted before anything is written; the env write is tried 3
|
|
3459
|
+
* times with the same secret; the applied address and the cleared marker come last; every try failing leaves
|
|
3460
|
+
* the marker, and the error names the id only. `url` rewrites the address. Retire revokes the key and the
|
|
3461
|
+
* env names. The operator key is read from the backend's env and never recorded.
|
|
3462
|
+
*/
|
|
3463
|
+
private analyticsEntryKey;
|
|
3403
3464
|
/**
|
|
3404
3465
|
* `plan/diff.ts`'s `planKosmos`: provisions the org's own kosmos
|
|
3405
3466
|
* (https://github.com/wtfalch/kosmos) as one more Coolify application, from
|
|
@@ -4103,4 +4164,16 @@ export declare function isNoChangesError(error: unknown): boolean;
|
|
|
4103
4164
|
* {@link ZitadelPort.updateOidcAppLoginBaseUri} that counts an app already holding the wanted base URI as
|
|
4104
4165
|
* done: ZITADEL answers that write with "No changes" and a repeat apply must not fail on it.
|
|
4105
4166
|
*/
|
|
4167
|
+
/**
|
|
4168
|
+
* Turns the instance feature `loginV2.required` off so each app's own base URI counts, and makes sure no
|
|
4169
|
+
* app can then land on ZITADEL's v1 login: with `required` off an app without a base URI of its own
|
|
4170
|
+
* (ZITADEL's own console app, an app foundry did not make, an app made later) falls back to v1, and
|
|
4171
|
+
* ZITADEL v4.17.3 gives a `required` instance's base URI to every app but ignores an app's own
|
|
4172
|
+
* (`internal/query/oidc_client.go:88-92`), so the only way is a base URI on every app. Every live OIDC
|
|
4173
|
+
* app of every organisation and project gets `instanceBaseUri` when it has none; an app that has one
|
|
4174
|
+
* keeps it. The apps are set first, while `required` still makes the instance ignore them, so no sign-in
|
|
4175
|
+
* passes through a gap. Without a way to list every app, or with a listing that may be cut short, it
|
|
4176
|
+
* throws before the feature is touched.
|
|
4177
|
+
*/
|
|
4178
|
+
export declare function allowPerAppLoginBaseUris(zitadel: Pick<ZitadelPort, 'allowPerAppLoginBaseUri' | 'listOrgs' | 'listProjects' | 'listApps' | 'updateOidcAppLoginBaseUri'>, instanceBaseUri: string): Promise<void>;
|
|
4106
4179
|
export declare function setOidcAppLoginBaseUri(zitadel: Pick<ZitadelPort, 'updateOidcAppLoginBaseUri'>, orgId: string, projectId: string, appId: string, loginBaseUri: string): Promise<void>;
|