@wtfalch/foundry 0.34.0 → 0.35.1
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 +770 -231
- 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/store/postgres.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { and, asc, desc, eq, ne, sql } from 'drizzle-orm';
|
|
2
|
-
import { APP_ENTRY_KEY, DEFAULT_MAIL_APPS, DEFAULT_NO_REPLY_LOCAL_PART, validateBuyerIdentity, validateCalls, validateDomain, validateHosting, validateMail, validateOwners, validateServices, validateSite, } from '../org.js';
|
|
2
|
+
import { APP_ENTRY_KEY, DEFAULT_MAIL_APPS, DEFAULT_NO_REPLY_LOCAL_PART, validateBuyerIdentity, validateCalls, validateDomain, validateDomainClaim, validateHosting, validateMail, validateOwners, validateServices, validateSite, validateVersionPin, } from '../org.js';
|
|
3
3
|
import { lockedHostnames } from '../plan/locked-hostnames.js';
|
|
4
4
|
import { findNameClashes, nameClashMessage } from '../plan/org-names.js';
|
|
5
5
|
import { validatePlatform } from '../platform.js';
|
|
@@ -146,6 +146,8 @@ function rowToOrg(row) {
|
|
|
146
146
|
},
|
|
147
147
|
}
|
|
148
148
|
: {}),
|
|
149
|
+
// Omitted while unset. Validated on read: a stored value is not trusted.
|
|
150
|
+
...(row.versionPin ? { versionPin: readVersionPin(row) } : {}),
|
|
149
151
|
site: { enabled: row.siteEnabled, usesDomain: row.siteUsesDomain },
|
|
150
152
|
hosting: {
|
|
151
153
|
enabled: row.hostingEnabled,
|
|
@@ -169,6 +171,14 @@ function rowToOrg(row) {
|
|
|
169
171
|
test: row.isTest,
|
|
170
172
|
};
|
|
171
173
|
}
|
|
174
|
+
function readVersionPin(row) {
|
|
175
|
+
const pin = row.versionPin;
|
|
176
|
+
const reason = validateVersionPin({ versionPin: pin });
|
|
177
|
+
if (reason) {
|
|
178
|
+
throw new DeclaredOrgError(`stored org ${row.slug} has an invalid versionPin: ${reason}`);
|
|
179
|
+
}
|
|
180
|
+
return pin;
|
|
181
|
+
}
|
|
172
182
|
function orgToRow(org) {
|
|
173
183
|
return {
|
|
174
184
|
id: org.id,
|
|
@@ -190,6 +200,7 @@ function orgToRow(org) {
|
|
|
190
200
|
issuerUsesDomain: org.issuer.usesDomain,
|
|
191
201
|
servicesOwn: org.services?.own ?? false,
|
|
192
202
|
servicesSfuSlot: org.services?.sfuSlot ?? null,
|
|
203
|
+
versionPin: org.versionPin && Object.keys(org.versionPin).length > 0 ? org.versionPin : null,
|
|
193
204
|
siteEnabled: org.site.enabled,
|
|
194
205
|
siteUsesDomain: org.site.usesDomain,
|
|
195
206
|
hostingEnabled: org.hosting.enabled,
|
|
@@ -288,6 +299,29 @@ export function createPostgresDeclaredOrgStore(db) {
|
|
|
288
299
|
if (reason)
|
|
289
300
|
throw new DeclaredOrgError(`domain invalid: ${reason} (#131)`);
|
|
290
301
|
}
|
|
302
|
+
// The platform's apex and every other company's domain are read here, so a claim is checked against what is declared now.
|
|
303
|
+
async function requireDomainClaim(org) {
|
|
304
|
+
if (org.domain === null)
|
|
305
|
+
return;
|
|
306
|
+
const [platformRow] = await db
|
|
307
|
+
.select({
|
|
308
|
+
apex: foundryDeclaredPlatform.apex,
|
|
309
|
+
ownerOrgId: foundryDeclaredPlatform.ownerOrgId,
|
|
310
|
+
})
|
|
311
|
+
.from(foundryDeclaredPlatform)
|
|
312
|
+
.limit(1);
|
|
313
|
+
const others = await db
|
|
314
|
+
.select({ id: declaredOrgs.id, domain: declaredOrgs.domain })
|
|
315
|
+
.from(declaredOrgs)
|
|
316
|
+
.where(ne(declaredOrgs.id, org.id));
|
|
317
|
+
const reason = validateDomainClaim(org.domain, {
|
|
318
|
+
orgId: org.id,
|
|
319
|
+
platform: platformRow ?? null,
|
|
320
|
+
others,
|
|
321
|
+
});
|
|
322
|
+
if (reason)
|
|
323
|
+
throw new DeclaredOrgError(`domain invalid: ${reason}`);
|
|
324
|
+
}
|
|
291
325
|
function requireValidLimit(fieldName, value) {
|
|
292
326
|
if (value !== null && !NON_NEGATIVE_INTEGER.test(value)) {
|
|
293
327
|
throw new DeclaredOrgError(`${fieldName} '${value}' must be a bigint-safe decimal string of a non-negative integer, or null for uncapped (#27)`);
|
|
@@ -357,6 +391,9 @@ export function createPostgresDeclaredOrgStore(db) {
|
|
|
357
391
|
const reason = validateCalls(org);
|
|
358
392
|
if (reason)
|
|
359
393
|
throw new DeclaredOrgError(`calls invalid: ${reason} (#259)`);
|
|
394
|
+
const pinReason = validateVersionPin(org);
|
|
395
|
+
if (pinReason)
|
|
396
|
+
throw new DeclaredOrgError(`versionPin invalid: ${pinReason}`);
|
|
360
397
|
}
|
|
361
398
|
// Own-service rules, on `create` and on the merged result of `update`; no
|
|
362
399
|
// two orgs share an `sfuSlot` (the unique index catches the race this misses).
|
|
@@ -396,6 +433,7 @@ export function createPostgresDeclaredOrgStore(db) {
|
|
|
396
433
|
requireValidCalls(org);
|
|
397
434
|
await requireValidServices(org);
|
|
398
435
|
await requireNoNameClash(org);
|
|
436
|
+
await requireDomainClaim(org);
|
|
399
437
|
try {
|
|
400
438
|
await db.insert(declaredOrgs).values(orgToRow(org));
|
|
401
439
|
}
|
|
@@ -505,6 +543,8 @@ export function createPostgresDeclaredOrgStore(db) {
|
|
|
505
543
|
requireValidCalls(next);
|
|
506
544
|
await requireValidServices(next);
|
|
507
545
|
await requireNoNameClash(next);
|
|
546
|
+
if (next.domain !== current.domain)
|
|
547
|
+
await requireDomainClaim(next);
|
|
508
548
|
try {
|
|
509
549
|
// #351: with `expectedVersion` the version check is part of this one
|
|
510
550
|
// statement, so an edit that lands after the read above makes it match
|
|
@@ -689,6 +729,7 @@ function rowToPlatform(row) {
|
|
|
689
729
|
gitRef: row.coolifyGitRef,
|
|
690
730
|
},
|
|
691
731
|
uptime: { enabled: row.uptimeEnabled, tag: row.uptimeTag, sha256: row.uptimeSha256 },
|
|
732
|
+
heartbeatsProvider: row.heartbeatsProvider,
|
|
692
733
|
};
|
|
693
734
|
}
|
|
694
735
|
function platformToRow(platform) {
|
|
@@ -736,6 +777,7 @@ function platformToRow(platform) {
|
|
|
736
777
|
uptimeEnabled: platform.uptime.enabled,
|
|
737
778
|
uptimeTag: platform.uptime.tag,
|
|
738
779
|
uptimeSha256: platform.uptime.sha256,
|
|
780
|
+
heartbeatsProvider: platform.heartbeatsProvider,
|
|
739
781
|
};
|
|
740
782
|
}
|
|
741
783
|
/**
|
package/dist/store/schema.d.ts
CHANGED
|
@@ -355,6 +355,25 @@ export declare const declaredOrgs: import("drizzle-orm/pg-core").PgTableWithColu
|
|
|
355
355
|
identity: undefined;
|
|
356
356
|
generated: undefined;
|
|
357
357
|
}, {}, {}>;
|
|
358
|
+
versionPin: import("drizzle-orm/pg-core").PgColumn<{
|
|
359
|
+
name: "version_pin";
|
|
360
|
+
tableName: "foundry_declared_orgs";
|
|
361
|
+
dataType: "json";
|
|
362
|
+
columnType: "PgJsonb";
|
|
363
|
+
data: Record<string, string>;
|
|
364
|
+
driverParam: unknown;
|
|
365
|
+
notNull: false;
|
|
366
|
+
hasDefault: false;
|
|
367
|
+
isPrimaryKey: false;
|
|
368
|
+
isAutoincrement: false;
|
|
369
|
+
hasRuntimeDefault: false;
|
|
370
|
+
enumValues: undefined;
|
|
371
|
+
baseColumn: never;
|
|
372
|
+
identity: undefined;
|
|
373
|
+
generated: undefined;
|
|
374
|
+
}, {}, {
|
|
375
|
+
$type: Record<string, string>;
|
|
376
|
+
}>;
|
|
358
377
|
siteEnabled: import("drizzle-orm/pg-core").PgColumn<{
|
|
359
378
|
name: "site_enabled";
|
|
360
379
|
tableName: "foundry_declared_orgs";
|
|
@@ -2170,6 +2189,23 @@ export declare const foundryDeclaredPlatform: import("drizzle-orm/pg-core").PgTa
|
|
|
2170
2189
|
identity: undefined;
|
|
2171
2190
|
generated: undefined;
|
|
2172
2191
|
}, {}, {}>;
|
|
2192
|
+
heartbeatsProvider: import("drizzle-orm/pg-core").PgColumn<{
|
|
2193
|
+
name: "heartbeats_provider";
|
|
2194
|
+
tableName: "foundry_declared_platform";
|
|
2195
|
+
dataType: "string";
|
|
2196
|
+
columnType: "PgText";
|
|
2197
|
+
data: string;
|
|
2198
|
+
driverParam: string;
|
|
2199
|
+
notNull: true;
|
|
2200
|
+
hasDefault: true;
|
|
2201
|
+
isPrimaryKey: false;
|
|
2202
|
+
isAutoincrement: false;
|
|
2203
|
+
hasRuntimeDefault: false;
|
|
2204
|
+
enumValues: [string, ...string[]];
|
|
2205
|
+
baseColumn: never;
|
|
2206
|
+
identity: undefined;
|
|
2207
|
+
generated: undefined;
|
|
2208
|
+
}, {}, {}>;
|
|
2173
2209
|
serviceIds: import("drizzle-orm/pg-core").PgColumn<{
|
|
2174
2210
|
name: "service_ids";
|
|
2175
2211
|
tableName: "foundry_declared_platform";
|
package/dist/store/schema.js
CHANGED
|
@@ -38,6 +38,8 @@ export const declaredOrgs = pgTable('foundry_declared_orgs', {
|
|
|
38
38
|
// ServicesConfig (org.ts): false and null are the platform's shared services.
|
|
39
39
|
servicesOwn: boolean('services_own').notNull().default(false),
|
|
40
40
|
servicesSfuSlot: integer('services_sfu_slot'),
|
|
41
|
+
// VersionPin (org.ts): null follows the platform. `migrations/0053_org_version_pin.sql`.
|
|
42
|
+
versionPin: jsonb('version_pin').$type(),
|
|
41
43
|
// SiteConfig (org.ts, T10). A brand new org has no cms site.
|
|
42
44
|
siteEnabled: boolean('site_enabled').notNull().default(false),
|
|
43
45
|
siteUsesDomain: boolean('site_uses_domain').notNull().default(false),
|
|
@@ -203,6 +205,8 @@ export const foundryDeclaredPlatform = pgTable('foundry_declared_platform', {
|
|
|
203
205
|
uptimeEnabled: boolean('uptime_enabled').notNull().default(true),
|
|
204
206
|
uptimeTag: text('uptime_tag').notNull().default(''),
|
|
205
207
|
uptimeSha256: text('uptime_sha256').notNull().default(''),
|
|
208
|
+
/** foundry#544, `migrations/0053_heartbeats_provider.sql`: which Healthchecks instance manages the heartbeat checks, decoupled from `hcEnabled` above. */
|
|
209
|
+
heartbeatsProvider: text('heartbeats_provider').notNull().default('self-hosted'),
|
|
206
210
|
/** `migrations/0018_platform_apply.sql`: the platform's applied state, `system:kind:key` to provider id. */
|
|
207
211
|
serviceIds: jsonb('service_ids').$type().notNull().default({}),
|
|
208
212
|
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wtfalch/foundry",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.1",
|
|
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",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"type": "module",
|
|
12
|
-
"files": ["dist", "versions.json"],
|
|
12
|
+
"files": ["dist", "versions.json", "versions.digests.json"],
|
|
13
13
|
"exports": {
|
|
14
14
|
".": {
|
|
15
15
|
"types": "./dist/index.d.ts",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@wtfalch/audit": "0.6.0",
|
|
46
46
|
"@wtfalch/auth": "0.16.0",
|
|
47
|
-
"@wtfalch/edge": "0.
|
|
47
|
+
"@wtfalch/edge": "0.13.0",
|
|
48
48
|
"@wtfalch/email": "^0.20.0",
|
|
49
49
|
"@wtfalch/providers": "0.7.5",
|
|
50
50
|
"ssh2": "1.17.0",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"zitadel": "sha256:2ec2a42551862ca59dc752c321c7041358dea8b33b63ea5e021ec499ad5e2d9f",
|
|
3
|
+
"synapse": "sha256:6b95dd129e35e97e8032cb759e5db4a516a5f7ef6c98d34d716fea1ae239b62a",
|
|
4
|
+
"mas": "sha256:52c18ffcc940220a3b6aa5985b7e09d24ac27f5ed10a4d660c312e48f73ff105",
|
|
5
|
+
"livekit": "sha256:6fd3b7088874c4d119160dd688798dfec852bc014786d392caad15f6f63912a3",
|
|
6
|
+
"cloudflared": "sha256:072c067d25ccbe61d46e18f0d0723255f2bb5304f7317caa95b27031520ff92c",
|
|
7
|
+
"stalwart": "sha256:ec011be228596e37e65f41aab17deed573859614430472f7eeb42178c50d87b7",
|
|
8
|
+
"hc": "sha256:aa08a61b0dcfd83f1332eab195d5cec1b595ae076eb8388cadf8a3d597114f9b",
|
|
9
|
+
"alpine": "sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1",
|
|
10
|
+
"busybox": "sha256:5cec3fc171c87218698e85a52af7087de727372aae264a787b8112901a5b0092"
|
|
11
|
+
}
|