@wtfalch/foundry 0.4.0 → 0.6.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/bootstrap/bootstrap.d.ts +111 -0
- package/dist/bootstrap/bootstrap.js +323 -0
- package/dist/bootstrap/declare.d.ts +36 -0
- package/dist/bootstrap/declare.js +99 -0
- package/dist/bootstrap/drive.d.ts +40 -0
- package/dist/bootstrap/drive.js +51 -0
- package/dist/bootstrap/index.d.ts +3 -0
- package/dist/bootstrap/index.js +1 -0
- package/dist/calls-sfu-deploy-support.d.ts +17 -6
- package/dist/calls-sfu-deploy-support.js +19 -7
- package/dist/calls-sfu-keys.d.ts +21 -0
- package/dist/calls-sfu-keys.js +27 -0
- package/dist/calls-sfu-ssh-adapter.d.ts +55 -0
- package/dist/calls-sfu-ssh-adapter.js +78 -0
- package/dist/calls-sfu-ssh-client.d.ts +49 -0
- package/dist/calls-sfu-ssh-client.js +82 -0
- package/dist/calls-sfu.d.ts +36 -12
- package/dist/calls-sfu.js +41 -9
- package/dist/index.d.ts +38 -7
- package/dist/index.js +20 -4
- package/dist/migrations/0016_platform.sql +61 -0
- package/dist/migrations/0017_requested_changes.sql +42 -0
- package/dist/migrations/0018_platform_apply.sql +19 -0
- package/dist/migrations/0019_mail_owner_mailbox.sql +15 -0
- package/dist/migrations/0020_mail_apps.sql +7 -0
- package/dist/migrations/0021_mail_role_mailboxes.sql +6 -0
- package/dist/org.d.ts +81 -0
- package/dist/org.js +96 -0
- package/dist/plan/agora.d.ts +77 -0
- package/dist/plan/agora.js +127 -0
- package/dist/plan/cloudflared-connector.d.ts +70 -0
- package/dist/plan/cloudflared-connector.js +106 -0
- package/dist/plan/diff.d.ts +20 -3
- package/dist/plan/diff.js +713 -115
- package/dist/plan/executor.d.ts +680 -172
- package/dist/plan/executor.js +755 -189
- package/dist/plan/index.d.ts +28 -5
- package/dist/plan/index.js +15 -2
- package/dist/plan/jobs-scheduler-http.d.ts +29 -0
- package/dist/plan/jobs-scheduler-http.js +50 -0
- package/dist/plan/live.d.ts +51 -2
- package/dist/plan/live.js +8 -0
- package/dist/plan/mail-copy.d.ts +125 -0
- package/dist/plan/mail-copy.js +166 -0
- package/dist/plan/mail-identity-allowlist.d.ts +50 -0
- package/dist/plan/mail-identity-allowlist.js +11 -0
- package/dist/plan/mail-identity.d.ts +68 -0
- package/dist/plan/mail-identity.js +17 -0
- package/dist/plan/plan-apply.d.ts +197 -3
- package/dist/plan/plan-apply.js +278 -9
- package/dist/plan/platform-diff.d.ts +487 -0
- package/dist/plan/platform-diff.js +1220 -0
- package/dist/plan/platform-org-ports.d.ts +50 -0
- package/dist/plan/platform-org-ports.js +70 -0
- package/dist/plan/platform-org.d.ts +121 -0
- package/dist/plan/platform-org.js +115 -0
- package/dist/plan/platform-providers.d.ts +615 -0
- package/dist/plan/platform-providers.js +4410 -0
- package/dist/plan/platform-sfu.d.ts +128 -0
- package/dist/plan/platform-sfu.js +142 -0
- package/dist/plan/providers-readers.js +22 -1
- package/dist/plan/zitadel-machine-user.d.ts +83 -0
- package/dist/plan/zitadel-machine-user.js +238 -0
- package/dist/plan.d.ts +6 -0
- package/dist/platform.d.ts +55 -0
- package/dist/platform.js +46 -0
- package/dist/requested-changes.d.ts +118 -0
- package/dist/requested-changes.js +125 -0
- package/dist/slug.js +15 -2
- package/dist/store/audit.js +4 -2
- package/dist/store/postgres.d.ts +29 -1
- package/dist/store/postgres.js +203 -4
- package/dist/store/schema.d.ts +755 -0
- package/dist/store/schema.js +70 -0
- package/dist/store.d.ts +53 -0
- package/package.json +1 -1
package/dist/store/postgres.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { eq, sql } from 'drizzle-orm';
|
|
2
|
-
import { validateBuyerIdentity, validateDomain, validateHosting, validateOwner, validateSite, } from '../org.js';
|
|
1
|
+
import { asc, eq, sql } from 'drizzle-orm';
|
|
2
|
+
import { DEFAULT_MAIL_APPS, DEFAULT_NO_REPLY_LOCAL_PART, validateBuyerIdentity, validateDomain, validateHosting, validateMail, validateOwner, validateSite, } from '../org.js';
|
|
3
|
+
import { validatePlatform } from '../platform.js';
|
|
4
|
+
import { RequestedChangeError, classifyChange } from '../requested-changes.js';
|
|
3
5
|
import { validateSlug } from '../slug.js';
|
|
4
|
-
import { declaredOrgs, foundryAppliedState, } from './schema.js';
|
|
6
|
+
import { declaredOrgs, foundryAppliedState, foundryDeclaredPlatform, foundryRequestedChanges, } from './schema.js';
|
|
5
7
|
const UNIQUE_VIOLATION = '23505';
|
|
6
8
|
/** `migrations/0004_slug_unique.sql` / `migrations/0015_domain_unique.sql`'s index names, read back off a caught unique-violation to tell which one fired. */
|
|
7
9
|
const SLUG_UNIQUE_INDEX = 'foundry_declared_orgs_slug_idx';
|
|
@@ -57,7 +59,14 @@ function rowToOrg(row) {
|
|
|
57
59
|
slug: row.slug,
|
|
58
60
|
displayName: row.displayName,
|
|
59
61
|
domain: row.domain,
|
|
60
|
-
mail: {
|
|
62
|
+
mail: {
|
|
63
|
+
mode: row.mailMode,
|
|
64
|
+
usesDomain: row.mailUsesDomain,
|
|
65
|
+
ownerMailboxAddress: row.ownerMailboxAddress,
|
|
66
|
+
noReplyLocalPart: row.noReplyLocalPart,
|
|
67
|
+
mailApps: row.mailApps,
|
|
68
|
+
roleMailboxes: row.roleMailboxes,
|
|
69
|
+
},
|
|
61
70
|
chat: { usesDomain: row.chatUsesDomain },
|
|
62
71
|
calls: { enabled: row.callsEnabled, usesDomain: row.callsUsesDomain },
|
|
63
72
|
issuer: { usesDomain: row.issuerUsesDomain },
|
|
@@ -94,6 +103,10 @@ function orgToRow(org) {
|
|
|
94
103
|
domain: org.domain,
|
|
95
104
|
mailMode: org.mail.mode,
|
|
96
105
|
mailUsesDomain: org.mail.usesDomain,
|
|
106
|
+
ownerMailboxAddress: org.mail.ownerMailboxAddress ?? null,
|
|
107
|
+
noReplyLocalPart: org.mail.noReplyLocalPart ?? DEFAULT_NO_REPLY_LOCAL_PART,
|
|
108
|
+
mailApps: org.mail.mailApps ?? [...DEFAULT_MAIL_APPS],
|
|
109
|
+
roleMailboxes: org.mail.roleMailboxes ?? [],
|
|
97
110
|
chatUsesDomain: org.chat.usesDomain,
|
|
98
111
|
callsEnabled: org.calls.enabled,
|
|
99
112
|
callsUsesDomain: org.calls.usesDomain,
|
|
@@ -254,6 +267,16 @@ export function createPostgresDeclaredOrgStore(db) {
|
|
|
254
267
|
if (reason)
|
|
255
268
|
throw new DeclaredOrgError(`owner invalid: ${reason}`);
|
|
256
269
|
}
|
|
270
|
+
// #162: same place `requireValidOwner` checks the owner, on both `create`
|
|
271
|
+
// and the merged result of `update`. Deliberately does not require
|
|
272
|
+
// `mail.ownerMailboxAddress` just because mail is on -- `validateMail`'s
|
|
273
|
+
// own doc comment says why. Also covers #34's `mailApps` check, folded
|
|
274
|
+
// into the same `validateMail`.
|
|
275
|
+
function requireValidMail(org) {
|
|
276
|
+
const reason = validateMail(org);
|
|
277
|
+
if (reason)
|
|
278
|
+
throw new DeclaredOrgError(`mail invalid: ${reason} (#162)`);
|
|
279
|
+
}
|
|
257
280
|
return {
|
|
258
281
|
async create(org) {
|
|
259
282
|
requireValidSlug(org.slug);
|
|
@@ -263,6 +286,7 @@ export function createPostgresDeclaredOrgStore(db) {
|
|
|
263
286
|
requireValidHosting(org);
|
|
264
287
|
requireValidSite(org);
|
|
265
288
|
requireValidOwner(org);
|
|
289
|
+
requireValidMail(org);
|
|
266
290
|
try {
|
|
267
291
|
await db.insert(declaredOrgs).values(orgToRow(org));
|
|
268
292
|
}
|
|
@@ -287,6 +311,12 @@ export function createPostgresDeclaredOrgStore(db) {
|
|
|
287
311
|
const [row] = await db.select().from(declaredOrgs).where(eq(declaredOrgs.id, id)).limit(1);
|
|
288
312
|
return row ? rowToOrg(row) : null;
|
|
289
313
|
},
|
|
314
|
+
// #133: ordered by display name, the same `asc(...)` shape
|
|
315
|
+
// `createPostgresRequestedChangeStore.listForOrg` already uses below.
|
|
316
|
+
async list() {
|
|
317
|
+
const rows = await db.select().from(declaredOrgs).orderBy(asc(declaredOrgs.displayName));
|
|
318
|
+
return rows.map(rowToOrg);
|
|
319
|
+
},
|
|
290
320
|
async slugTaken(slug) {
|
|
291
321
|
const [row] = await db
|
|
292
322
|
.select({ id: declaredOrgs.id })
|
|
@@ -336,6 +366,7 @@ export function createPostgresDeclaredOrgStore(db) {
|
|
|
336
366
|
requireValidHosting(next);
|
|
337
367
|
requireValidSite(next);
|
|
338
368
|
requireValidOwner(next);
|
|
369
|
+
requireValidMail(next);
|
|
339
370
|
try {
|
|
340
371
|
await db
|
|
341
372
|
.update(declaredOrgs)
|
|
@@ -405,3 +436,171 @@ export function createPostgresDeclaredOrgStore(db) {
|
|
|
405
436
|
},
|
|
406
437
|
};
|
|
407
438
|
}
|
|
439
|
+
/**
|
|
440
|
+
* Thrown by `put` when `validatePlatform` (`../platform.js`) refuses the
|
|
441
|
+
* platform given to it -- same "throw with a reason" shape
|
|
442
|
+
* {@link DeclaredOrgError} gives `create`/`update`.
|
|
443
|
+
*/
|
|
444
|
+
export class PlatformError extends Error {
|
|
445
|
+
constructor(message) {
|
|
446
|
+
super(message);
|
|
447
|
+
this.name = 'PlatformError';
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
/** `migrations/0016_platform.sql`'s singleton row -- `id` is always `true`, the only value its `check (id)` constraint allows. */
|
|
451
|
+
const PLATFORM_ROW_ID = true;
|
|
452
|
+
function rowToPlatform(row) {
|
|
453
|
+
return {
|
|
454
|
+
ownerOrgId: row.ownerOrgId,
|
|
455
|
+
apex: row.apex,
|
|
456
|
+
auth: { enabled: row.authEnabled, hostname: row.authHostname, gitRef: row.authGitRef },
|
|
457
|
+
mail: { enabled: row.mailEnabled, hostname: row.mailHostname, gitRef: row.mailGitRef },
|
|
458
|
+
sfu: { enabled: row.sfuEnabled, hostname: row.sfuHostname, gitRef: row.sfuGitRef },
|
|
459
|
+
files: { enabled: row.filesEnabled, hostname: row.filesHostname, gitRef: row.filesGitRef },
|
|
460
|
+
ai: { enabled: row.aiEnabled, hostname: row.aiHostname, gitRef: row.aiGitRef },
|
|
461
|
+
jobs: { enabled: row.jobsEnabled, hostname: row.jobsHostname, gitRef: row.jobsGitRef },
|
|
462
|
+
integrations: {
|
|
463
|
+
enabled: row.integrationsEnabled,
|
|
464
|
+
hostname: row.integrationsHostname,
|
|
465
|
+
gitRef: row.integrationsGitRef,
|
|
466
|
+
},
|
|
467
|
+
archon: {
|
|
468
|
+
enabled: row.archonEnabled,
|
|
469
|
+
hostname: row.archonHostname,
|
|
470
|
+
gitRef: row.archonGitRef,
|
|
471
|
+
},
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
function platformToRow(platform) {
|
|
475
|
+
return {
|
|
476
|
+
id: PLATFORM_ROW_ID,
|
|
477
|
+
ownerOrgId: platform.ownerOrgId,
|
|
478
|
+
apex: platform.apex,
|
|
479
|
+
authEnabled: platform.auth.enabled,
|
|
480
|
+
authHostname: platform.auth.hostname,
|
|
481
|
+
authGitRef: platform.auth.gitRef,
|
|
482
|
+
mailEnabled: platform.mail.enabled,
|
|
483
|
+
mailHostname: platform.mail.hostname,
|
|
484
|
+
mailGitRef: platform.mail.gitRef,
|
|
485
|
+
sfuEnabled: platform.sfu.enabled,
|
|
486
|
+
sfuHostname: platform.sfu.hostname,
|
|
487
|
+
sfuGitRef: platform.sfu.gitRef,
|
|
488
|
+
filesEnabled: platform.files.enabled,
|
|
489
|
+
filesHostname: platform.files.hostname,
|
|
490
|
+
filesGitRef: platform.files.gitRef,
|
|
491
|
+
aiEnabled: platform.ai.enabled,
|
|
492
|
+
aiHostname: platform.ai.hostname,
|
|
493
|
+
aiGitRef: platform.ai.gitRef,
|
|
494
|
+
jobsEnabled: platform.jobs.enabled,
|
|
495
|
+
jobsHostname: platform.jobs.hostname,
|
|
496
|
+
jobsGitRef: platform.jobs.gitRef,
|
|
497
|
+
integrationsEnabled: platform.integrations.enabled,
|
|
498
|
+
integrationsHostname: platform.integrations.hostname,
|
|
499
|
+
integrationsGitRef: platform.integrations.gitRef,
|
|
500
|
+
archonEnabled: platform.archon.enabled,
|
|
501
|
+
archonHostname: platform.archon.hostname,
|
|
502
|
+
archonGitRef: platform.archon.gitRef,
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* `PlatformStore` (`../store.ts`) on Postgres, for #166: get and put the one
|
|
507
|
+
* {@link DeclaredPlatform}, beside `createPostgresDeclaredOrgStore` above.
|
|
508
|
+
* `put` validates with `../platform.js`'s `validatePlatform` and then
|
|
509
|
+
* upserts onto the fixed singleton row `migrations/0016_platform.sql`
|
|
510
|
+
* declares -- the first call creates it, every later call replaces it, and
|
|
511
|
+
* the table's own `check (id)` constraint is what actually refuses a second
|
|
512
|
+
* row, not this function.
|
|
513
|
+
*/
|
|
514
|
+
export function createPostgresPlatformStore(db) {
|
|
515
|
+
return {
|
|
516
|
+
async get() {
|
|
517
|
+
const [row] = await db.select().from(foundryDeclaredPlatform).limit(1);
|
|
518
|
+
return row ? rowToPlatform(row) : null;
|
|
519
|
+
},
|
|
520
|
+
async put(platform) {
|
|
521
|
+
const reason = validatePlatform(platform);
|
|
522
|
+
if (reason)
|
|
523
|
+
throw new PlatformError(reason);
|
|
524
|
+
const row = platformToRow(platform);
|
|
525
|
+
await db
|
|
526
|
+
.insert(foundryDeclaredPlatform)
|
|
527
|
+
.values(row)
|
|
528
|
+
.onConflictDoUpdate({ target: foundryDeclaredPlatform.id, set: row });
|
|
529
|
+
},
|
|
530
|
+
async getServiceIds() {
|
|
531
|
+
const [row] = await db
|
|
532
|
+
.select({ serviceIds: foundryDeclaredPlatform.serviceIds })
|
|
533
|
+
.from(foundryDeclaredPlatform)
|
|
534
|
+
.limit(1);
|
|
535
|
+
return row?.serviceIds ?? {};
|
|
536
|
+
},
|
|
537
|
+
async putServiceIds(serviceIds) {
|
|
538
|
+
await db.update(foundryDeclaredPlatform).set({ serviceIds });
|
|
539
|
+
},
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* `value`'s own field-specific payload, stripped of its `field` -- that is
|
|
544
|
+
* a column of its own (`foundryRequestedChanges.field`), not repeated
|
|
545
|
+
* inside the jsonb.
|
|
546
|
+
*/
|
|
547
|
+
function requestedChangePayload(value) {
|
|
548
|
+
const { field, ...payload } = value;
|
|
549
|
+
return payload;
|
|
550
|
+
}
|
|
551
|
+
function rowToRequestedChange(row) {
|
|
552
|
+
return {
|
|
553
|
+
id: row.id,
|
|
554
|
+
orgId: row.orgId,
|
|
555
|
+
value: { field: row.field, ...row.value },
|
|
556
|
+
requestedBy: row.requestedBy,
|
|
557
|
+
createdAt: row.createdAt.toISOString(),
|
|
558
|
+
state: row.state,
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* `RequestedChangeStore` (`../store.ts`) on Postgres, for #178: classify and
|
|
563
|
+
* store a company's own requested setting change on its declared org, beside
|
|
564
|
+
* `createPostgresDeclaredOrgStore` and `createPostgresPlatformStore` above.
|
|
565
|
+
* `create` classifies with `../requested-changes.js`'s `classifyChange`
|
|
566
|
+
* against the `org` given to it -- this store never loads the org itself,
|
|
567
|
+
* the same "caller already has it" choice `PlatformStore.put`'s `platform`
|
|
568
|
+
* argument makes -- and stores the result as the request's initial `state`.
|
|
569
|
+
*/
|
|
570
|
+
export function createPostgresRequestedChangeStore(db) {
|
|
571
|
+
return {
|
|
572
|
+
async create({ orgId, org, value, requestedBy }) {
|
|
573
|
+
const classification = classifyChange(org, value);
|
|
574
|
+
const state = classification === 'auto' ? 'auto' : 'needs_approval';
|
|
575
|
+
const [row] = await db
|
|
576
|
+
.insert(foundryRequestedChanges)
|
|
577
|
+
.values({
|
|
578
|
+
orgId,
|
|
579
|
+
field: value.field,
|
|
580
|
+
value: requestedChangePayload(value),
|
|
581
|
+
requestedBy,
|
|
582
|
+
state,
|
|
583
|
+
})
|
|
584
|
+
.returning();
|
|
585
|
+
if (!row)
|
|
586
|
+
throw new RequestedChangeError('insert returned no row');
|
|
587
|
+
return rowToRequestedChange(row);
|
|
588
|
+
},
|
|
589
|
+
async get(id) {
|
|
590
|
+
const [row] = await db
|
|
591
|
+
.select()
|
|
592
|
+
.from(foundryRequestedChanges)
|
|
593
|
+
.where(eq(foundryRequestedChanges.id, id))
|
|
594
|
+
.limit(1);
|
|
595
|
+
return row ? rowToRequestedChange(row) : null;
|
|
596
|
+
},
|
|
597
|
+
async listForOrg(orgId) {
|
|
598
|
+
const rows = await db
|
|
599
|
+
.select()
|
|
600
|
+
.from(foundryRequestedChanges)
|
|
601
|
+
.where(eq(foundryRequestedChanges.orgId, orgId))
|
|
602
|
+
.orderBy(asc(foundryRequestedChanges.createdAt));
|
|
603
|
+
return rows.map(rowToRequestedChange);
|
|
604
|
+
},
|
|
605
|
+
};
|
|
606
|
+
}
|