@heychunky/core 0.14.0 → 0.15.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/admin/apps.d.ts +3 -0
- package/dist/admin/apps.d.ts.map +1 -1
- package/dist/admin/apps.js +16 -2
- package/dist/admin/apps.js.map +1 -1
- package/dist/admin/index.d.ts +2 -0
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +2 -0
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/migrations.d.ts +19 -0
- package/dist/admin/migrations.d.ts.map +1 -1
- package/dist/admin/migrations.js +27 -0
- package/dist/admin/migrations.js.map +1 -1
- package/dist/admin/orgs.d.ts +142 -0
- package/dist/admin/orgs.d.ts.map +1 -0
- package/dist/admin/orgs.js +166 -0
- package/dist/admin/orgs.js.map +1 -0
- package/dist/admin/register.d.ts +98 -0
- package/dist/admin/register.d.ts.map +1 -0
- package/dist/admin/register.js +191 -0
- package/dist/admin/register.js.map +1 -0
- package/dist/services/db.d.ts +16 -0
- package/dist/services/db.d.ts.map +1 -1
- package/dist/services/db.js +27 -22
- package/dist/services/db.js.map +1 -1
- package/package.json +3 -2
- package/register/0001-baseline/01-invite-requests.sql +11 -0
- package/register/0001-baseline/02-invite-requests-email-key.sql +1 -0
- package/register/0001-baseline/03-login-codes.sql +12 -0
- package/register/0001-baseline/04-login-codes-email-idx.sql +1 -0
- package/register/0001-baseline/05-notifications.sql +11 -0
- package/register/0001-baseline/06-notifications-unread-idx.sql +1 -0
- package/register/0001-baseline/07-users.sql +13 -0
- package/register/0001-baseline/08-users-email-key.sql +1 -0
- package/register/0001-baseline/09-users-one-superadmin.sql +1 -0
- package/register/0001-baseline/10-users-username-unique.sql +1 -0
- package/register/0001-baseline/11-api-tokens.sql +13 -0
- package/register/0001-baseline/12-apps.sql +14 -0
- package/register/0001-baseline/13-apps-name-key.sql +1 -0
- package/register/0001-baseline/14-apps-owner-idx.sql +1 -0
- package/register/0001-baseline/15-contexts.sql +9 -0
- package/register/0001-baseline/16-credit-ledger.sql +10 -0
- package/register/0001-baseline/17-credit-ledger-user.sql +1 -0
- package/register/0001-baseline/18-runs.sql +16 -0
- package/register/0001-baseline/19-sessions.sql +10 -0
- package/register/0001-baseline/20-sessions-user-idx.sql +1 -0
- package/register/0001-baseline/21-app-chunks.sql +7 -0
- package/register/0001-baseline/22-context-members.sql +10 -0
- package/register/0002-orgs/01-orgs.sql +14 -0
- package/register/0002-orgs/02-orgs-name-key.sql +1 -0
- package/register/0002-orgs/03-org-members.sql +10 -0
- package/register/0002-orgs/04-org-members-user-idx.sql +1 -0
- package/register/0002-orgs/05-apps-org-id.sql +1 -0
- package/register/0002-orgs/06-apps-org-idx.sql +1 -0
- package/register/0002-orgs/07-apps-org-name-key.sql +1 -0
- package/register/0002-orgs/08-credit-ledger-org-id.sql +1 -0
- package/register/0002-orgs/09-credit-ledger-org-idx.sql +1 -0
- package/register/0002-orgs/10-api-tokens-org-id.sql +1 -0
- package/register/0002-orgs/11-api-tokens-created-by.sql +1 -0
- package/register/0002-orgs/12-backfill-personal-orgs.sql +15 -0
- package/register/0002-orgs/13-backfill-org-members.sql +12 -0
- package/register/0002-orgs/14-backfill-apps-org.sql +14 -0
- package/register/0002-orgs/15-backfill-credit-ledger-org.sql +11 -0
- package/register/0002-orgs/16-backfill-api-tokens-org.sql +12 -0
- package/register/README.md +73 -0
package/dist/admin/apps.d.ts
CHANGED
|
@@ -19,6 +19,9 @@ import type { User } from "./users.ts";
|
|
|
19
19
|
export interface App {
|
|
20
20
|
id: string;
|
|
21
21
|
name: string;
|
|
22
|
+
/** The tenancy boundary. Null only for an owner who has claimed no username. */
|
|
23
|
+
org_id: string | null;
|
|
24
|
+
/** Who created it. Provenance, not tenancy — see orgs.ts. */
|
|
22
25
|
owner_id: string;
|
|
23
26
|
org: string | null;
|
|
24
27
|
repo: string | null;
|
package/dist/admin/apps.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/admin/apps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,WAAW,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;CAClC;AAED,sEAAsE;AACtE,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBACX,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAKzC;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;CACxC;AAED,2EAA2E;AAC3E,wBAAsB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAc5F;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBtF;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/admin/apps.ts"],"names":[],"mappings":"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"}
|
package/dist/admin/apps.js
CHANGED
|
@@ -66,9 +66,23 @@ export async function assertCanCreate(owner, register) {
|
|
|
66
66
|
*/
|
|
67
67
|
export async function recordApp(app, register) {
|
|
68
68
|
const conn = register;
|
|
69
|
-
const { rows } = await conn.write(
|
|
70
|
-
|
|
69
|
+
const { rows } = await conn.write(
|
|
70
|
+
// `org_id` is derived rather than passed, and derived the same way the
|
|
71
|
+
// backfill derived it: through the owner's username to their personal
|
|
72
|
+
// organisation. A caller that had to supply it is a caller that can supply
|
|
73
|
+
// the wrong one, and the invariant `heychunky register verify` asserts —
|
|
74
|
+
// every app is in an organisation — would then hold only until the next
|
|
75
|
+
// app was made.
|
|
76
|
+
//
|
|
77
|
+
// Kept on conflict, never overwritten. Re-running provisioning fills in
|
|
78
|
+
// what a partial run could not; it must not move an app between tenants.
|
|
79
|
+
`insert into apps (name, owner_id, org_id, org, repo, vercel_project, neon_project, provisioned)
|
|
80
|
+
values ($1, $2,
|
|
81
|
+
(select o.id from orgs o join users u on lower(o.name) = lower(u.username)
|
|
82
|
+
where u.id = $2 and o.kind = 'personal'),
|
|
83
|
+
$3, $4, $5, $6, $7)
|
|
71
84
|
on conflict (lower(name)) do update set
|
|
85
|
+
org_id = coalesce(apps.org_id, excluded.org_id),
|
|
72
86
|
org = coalesce(excluded.org, apps.org),
|
|
73
87
|
repo = coalesce(excluded.repo, apps.repo),
|
|
74
88
|
vercel_project = coalesce(excluded.vercel_project, apps.vercel_project),
|
package/dist/admin/apps.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.js","sourceRoot":"","sources":["../../src/admin/apps.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"apps.js","sourceRoot":"","sources":["../../src/admin/apps.ts"],"names":[],"mappings":"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"}
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -8,11 +8,13 @@ export * from "./secrets/infisical.ts";
|
|
|
8
8
|
export * from "./syncenv.ts";
|
|
9
9
|
export * from "./master.ts";
|
|
10
10
|
export * from "./apps.ts";
|
|
11
|
+
export * from "./orgs.ts";
|
|
11
12
|
export * from "./users.ts";
|
|
12
13
|
export * from "./run.ts";
|
|
13
14
|
export * from "./provision.ts";
|
|
14
15
|
export * from "./decommission.ts";
|
|
15
16
|
export * from "./migrations.ts";
|
|
17
|
+
export * from "./register.ts";
|
|
16
18
|
export * from "./promote.ts";
|
|
17
19
|
export * from "./runs.ts";
|
|
18
20
|
export * from "./entrypoints.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAG5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAG5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC"}
|
package/dist/admin/index.js
CHANGED
|
@@ -8,11 +8,13 @@ export * from "./secrets/infisical.js";
|
|
|
8
8
|
export * from "./syncenv.js";
|
|
9
9
|
export * from "./master.js";
|
|
10
10
|
export * from "./apps.js";
|
|
11
|
+
export * from "./orgs.js";
|
|
11
12
|
export * from "./users.js";
|
|
12
13
|
export * from "./run.js";
|
|
13
14
|
export * from "./provision.js";
|
|
14
15
|
export * from "./decommission.js";
|
|
15
16
|
export * from "./migrations.js";
|
|
17
|
+
export * from "./register.js";
|
|
16
18
|
export * from "./promote.js";
|
|
17
19
|
export * from "./runs.js";
|
|
18
20
|
export * from "./entrypoints.js";
|
package/dist/admin/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAE5B,+CAA+C;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAE5B,+CAA+C;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC"}
|
|
@@ -95,4 +95,23 @@ export declare function pending(all: Migration[], have: Set<string>): Migration[
|
|
|
95
95
|
* failed, and running them anyway turns one clear error into several.
|
|
96
96
|
*/
|
|
97
97
|
export declare function apply(db: Ledger, migrations: Migration[], watch?: (m: Migration) => void): Promise<number>;
|
|
98
|
+
/**
|
|
99
|
+
* Record statements as applied without running them.
|
|
100
|
+
*
|
|
101
|
+
* For a database that predates its ledger. The register is the case this was
|
|
102
|
+
* written for — `apps` and `users` were typed into psql long before anything
|
|
103
|
+
* wrote them down, so the first migration file describing them is a record of
|
|
104
|
+
* what is already there rather than work to do. Running it would fail on every
|
|
105
|
+
* `create table`, and failing is not the answer: the database is *correct*, it
|
|
106
|
+
* simply has no receipt.
|
|
107
|
+
*
|
|
108
|
+
* Deliberately separate from `apply`, and deliberately not a flag on it. One
|
|
109
|
+
* function that either runs SQL or does not, depending on an argument, is one
|
|
110
|
+
* a caller can get backwards — and getting this one backwards means a schema
|
|
111
|
+
* change silently skipped, discovered later as a missing column in production.
|
|
112
|
+
*
|
|
113
|
+
* Only ever right when somebody has looked at the database and confirmed the
|
|
114
|
+
* statements are already true of it. There is no way to check that from here.
|
|
115
|
+
*/
|
|
116
|
+
export declare function adopt(db: Ledger, migrations: Migration[]): Promise<string[]>;
|
|
98
117
|
//# sourceMappingURL=migrations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../src/admin/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9C,kEAAkE;AAClE,eAAO,MAAM,cAAc,eAAe,CAAC;AAE3C,oEAAoE;AACpE,eAAO,MAAM,MAAM,0BAA0B,CAAC;AAE9C,wEAAwE;AACxE,MAAM,WAAW,SAAS;IACxB,sEAAsE;IACtE,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;CACb;AAED,8DAA8D;AAC9D,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAI3E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAIlD;AAED,oEAAoE;AACpE,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK5D;AAED;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAS9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS,EAAE,CAExE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,KAAK,CACzB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,SAAS,EAAE,EACvB,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,GAC7B,OAAO,CAAC,MAAM,CAAC,CAUjB"}
|
|
1
|
+
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../src/admin/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9C,kEAAkE;AAClE,eAAO,MAAM,cAAc,eAAe,CAAC;AAE3C,oEAAoE;AACpE,eAAO,MAAM,MAAM,0BAA0B,CAAC;AAE9C,wEAAwE;AACxE,MAAM,WAAW,SAAS;IACxB,sEAAsE;IACtE,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;CACb;AAED,8DAA8D;AAC9D,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAI3E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAIlD;AAED,oEAAoE;AACpE,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK5D;AAED;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAS9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS,EAAE,CAExE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,KAAK,CACzB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,SAAS,EAAE,EACvB,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,GAC7B,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAQlF"}
|
package/dist/admin/migrations.js
CHANGED
|
@@ -90,4 +90,31 @@ export async function apply(db, migrations, watch) {
|
|
|
90
90
|
}
|
|
91
91
|
return ran;
|
|
92
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Record statements as applied without running them.
|
|
95
|
+
*
|
|
96
|
+
* For a database that predates its ledger. The register is the case this was
|
|
97
|
+
* written for — `apps` and `users` were typed into psql long before anything
|
|
98
|
+
* wrote them down, so the first migration file describing them is a record of
|
|
99
|
+
* what is already there rather than work to do. Running it would fail on every
|
|
100
|
+
* `create table`, and failing is not the answer: the database is *correct*, it
|
|
101
|
+
* simply has no receipt.
|
|
102
|
+
*
|
|
103
|
+
* Deliberately separate from `apply`, and deliberately not a flag on it. One
|
|
104
|
+
* function that either runs SQL or does not, depending on an argument, is one
|
|
105
|
+
* a caller can get backwards — and getting this one backwards means a schema
|
|
106
|
+
* change silently skipped, discovered later as a missing column in production.
|
|
107
|
+
*
|
|
108
|
+
* Only ever right when somebody has looked at the database and confirmed the
|
|
109
|
+
* statements are already true of it. There is no way to check that from here.
|
|
110
|
+
*/
|
|
111
|
+
export async function adopt(db, migrations) {
|
|
112
|
+
await ensureLedger(db);
|
|
113
|
+
const recorded = [];
|
|
114
|
+
for (const m of migrations) {
|
|
115
|
+
await db.write(`insert into ${LEDGER} (id) values ($1) on conflict (id) do nothing`, [m.id]);
|
|
116
|
+
recorded.push(m.id);
|
|
117
|
+
}
|
|
118
|
+
return recorded;
|
|
119
|
+
}
|
|
93
120
|
//# sourceMappingURL=migrations.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/admin/migrations.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/admin/migrations.ts"],"names":[],"mappings":"AA6BA,kEAAkE;AAClE,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAE3C,oEAAoE;AACpE,MAAM,CAAC,MAAM,MAAM,GAAG,uBAAuB,CAAC;AAe9C;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,EAAQ,EAAE,IAAY,EAAE,KAAa;IACjE,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACnF,OAAO,GAAG,cAAc,IAAI,KAAK,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC;AACzF,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,uCAAuC,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACpF,OAAO,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC;QACvC,oEAAoE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACpF,CAAC;AAED,oEAAoE;AACpE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAU;IAC3C,MAAM,EAAE,CAAC,KAAK,CACZ,8BAA8B,MAAM,IAAI;QACtC,qEAAqE,CACxE,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,EAAU;IACtC,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,kBAAkB,MAAM,EAAE,CAAC,CAAC;QAC5D,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,uCAAuC,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,GAAG,EAAE,CAAC;QAC5E,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,OAAO,CAAC,GAAgB,EAAE,IAAiB;IACzD,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC1F,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CACzB,EAAU,EACV,UAAuB,EACvB,KAA8B;IAE9B,MAAM,YAAY,CAAC,EAAE,CAAC,CAAC;IACvB,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QACX,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACtB,MAAM,EAAE,CAAC,KAAK,CAAC,eAAe,MAAM,+CAA+C,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7F,GAAG,IAAI,CAAC,CAAC;IACX,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,EAAU,EAAE,UAAuB;IAC7D,MAAM,YAAY,CAAC,EAAE,CAAC,CAAC;IACvB,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,EAAE,CAAC,KAAK,CAAC,eAAe,MAAM,+CAA+C,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7F,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tenancy boundary.
|
|
3
|
+
*
|
|
4
|
+
* An **organisation** is what owns things. A **user** is a person who builds.
|
|
5
|
+
* Not the users of anybody's app — Carmel's citizens are a Carmel City concept
|
|
6
|
+
* and stay in Carmel's database; these are the people who make apps here.
|
|
7
|
+
*
|
|
8
|
+
* `owner_id` on `apps` was the boundary until now, and a person is the wrong
|
|
9
|
+
* shape for one: it cannot be shared, it cannot be handed over, and it cannot
|
|
10
|
+
* hold a plan two people are both paying against. `org_id` is the boundary and
|
|
11
|
+
* `owner_id` survives beside it as provenance — who created this.
|
|
12
|
+
*
|
|
13
|
+
* **An organisation's name is the publish scope.** The curated shelf keeps bare
|
|
14
|
+
* names because somebody chose them; everyone else publishes under a scope, and
|
|
15
|
+
* `@carmelcity/auth` needs no second entity to explain what `carmelcity` is. It
|
|
16
|
+
* is also the URL segment a signed-in session is scoped by, which is why the
|
|
17
|
+
* database insists it is a slug rather than a title: one string, three jobs,
|
|
18
|
+
* and nothing anywhere has to remember which spelling it is holding.
|
|
19
|
+
*
|
|
20
|
+
* **The organisation is not the GitHub organisation — it has one.** Carmel's
|
|
21
|
+
* organisation is `carmelcity` here and `carmelcity` on GitHub today, and
|
|
22
|
+
* nothing should be built on those staying equal; `github_org`, `vercel_team`
|
|
23
|
+
* and `vault_folder` are where a provider's own name for the same tenant goes.
|
|
24
|
+
*
|
|
25
|
+
* **One level.** No spaces or workspaces inside an organisation until something
|
|
26
|
+
* needs one.
|
|
27
|
+
*
|
|
28
|
+
* Two kinds of role, and they live in different places on purpose. `superadmin`
|
|
29
|
+
* is a factory role and stays on the user, where a partial unique index permits
|
|
30
|
+
* exactly one of them. `admin` and `publisher` are organisation roles and live
|
|
31
|
+
* on the membership. One column for both would let an organisation's own admin
|
|
32
|
+
* inherit the factory.
|
|
33
|
+
*/
|
|
34
|
+
import type { Register } from "./master.ts";
|
|
35
|
+
import type { PlanKey } from "./users.ts";
|
|
36
|
+
/** What somebody may do inside one organisation. Never a factory role. */
|
|
37
|
+
export declare const ORG_ROLES: readonly ["admin", "publisher"];
|
|
38
|
+
export type OrgRole = (typeof ORG_ROLES)[number];
|
|
39
|
+
/**
|
|
40
|
+
* Whether an organisation is a person or a group.
|
|
41
|
+
*
|
|
42
|
+
* `personal` is made for you when you claim a username and is never made any
|
|
43
|
+
* other way, which is what keeps a name meaning one thing across the People
|
|
44
|
+
* page, the shelf and the URL.
|
|
45
|
+
*/
|
|
46
|
+
export declare const ORG_KINDS: readonly ["personal", "team"];
|
|
47
|
+
export type OrgKind = (typeof ORG_KINDS)[number];
|
|
48
|
+
/**
|
|
49
|
+
* The shape a name may take.
|
|
50
|
+
*
|
|
51
|
+
* The same rule as a chunk's scope and a username, because they are the same
|
|
52
|
+
* string. Enforced by a check constraint as well as here — a rule that lives
|
|
53
|
+
* only in TypeScript is a rule the next caller writes around.
|
|
54
|
+
*/
|
|
55
|
+
export declare const ORG_NAME: RegExp;
|
|
56
|
+
export interface Org {
|
|
57
|
+
id: string;
|
|
58
|
+
/** The publish scope and the URL segment. Unique without case. */
|
|
59
|
+
name: string;
|
|
60
|
+
kind: OrgKind;
|
|
61
|
+
/** What this tenant may spend. The plan moved here from the user. */
|
|
62
|
+
plan: PlanKey;
|
|
63
|
+
/** A provider's own name for the same tenant. Null until one is linked. */
|
|
64
|
+
github_org: string | null;
|
|
65
|
+
vercel_team: string | null;
|
|
66
|
+
vault_folder: string | null;
|
|
67
|
+
created_at: string;
|
|
68
|
+
}
|
|
69
|
+
/** An organisation with what the person asking may do in it. */
|
|
70
|
+
export interface Membership extends Org {
|
|
71
|
+
role: OrgRole;
|
|
72
|
+
}
|
|
73
|
+
/** Refused because the name belongs to an organisation that is not personal. */
|
|
74
|
+
export declare class OrgNameTakenError extends Error {
|
|
75
|
+
constructor(name: string);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Give a user the organisation that matches their username.
|
|
79
|
+
*
|
|
80
|
+
* Runs in the same moment as claiming the name, because a name that is yours on
|
|
81
|
+
* the People page and somebody else's on the shelf would be worse than having
|
|
82
|
+
* no names at all. Safe to run again: if the membership insert fails the name is
|
|
83
|
+
* still theirs and the organisation is still there, which is the right way round
|
|
84
|
+
* — a person without their scope yet is inconvenienced, a person whose scope
|
|
85
|
+
* belongs to somebody else is a bug you cannot undo.
|
|
86
|
+
*
|
|
87
|
+
* Three statements rather than one because the client sends one statement per
|
|
88
|
+
* request. The insert is the check for the same reason `claimUsername`'s is: two
|
|
89
|
+
* people reaching for a name in the same second is a race only the unique index
|
|
90
|
+
* can settle.
|
|
91
|
+
*
|
|
92
|
+
* The read between the two writes is not ceremony. `on conflict do nothing` is
|
|
93
|
+
* silent about *why* it did nothing, and the one case that matters is a team
|
|
94
|
+
* organisation already holding this name — adding the caller to that as an admin
|
|
95
|
+
* would hand them somebody else's tenant. So it is looked at, and refused.
|
|
96
|
+
*/
|
|
97
|
+
export declare function claimPersonalOrg(userId: string, username: string, register: Register): Promise<Org>;
|
|
98
|
+
/** The organisations this person belongs to, personal one first. */
|
|
99
|
+
export declare function orgsFor(userId: string, register: Register): Promise<Membership[]>;
|
|
100
|
+
/**
|
|
101
|
+
* Whether this person may publish under this name.
|
|
102
|
+
*
|
|
103
|
+
* Membership is the whole answer — both roles publish, which is what makes
|
|
104
|
+
* `publisher` worth having as the one that cannot also invite people.
|
|
105
|
+
*/
|
|
106
|
+
export declare function mayPublish(userId: string, org: string, register: Register): Promise<boolean>;
|
|
107
|
+
/**
|
|
108
|
+
* What must be true of the register once organisations are backfilled.
|
|
109
|
+
*
|
|
110
|
+
* Written as data, and as violations rather than assertions, for one reason:
|
|
111
|
+
* **a wrong backfill does not fail loudly.** It sits looking fine until the day
|
|
112
|
+
* reads move onto `org_id`, and then it is one customer seeing another's apps.
|
|
113
|
+
* Nothing about that shows up in a test — the schema is right either way — so
|
|
114
|
+
* the proof has to be a question asked of the live rows.
|
|
115
|
+
*
|
|
116
|
+
* Every check counts rows that should not exist. Zero is the only passing
|
|
117
|
+
* answer, which means a check that is wrong tends to fail rather than pass, and
|
|
118
|
+
* a table that is empty passes honestly rather than vacuously hiding a bug.
|
|
119
|
+
*
|
|
120
|
+
* Exported so the CLI can print the SQL beside the count. A verification
|
|
121
|
+
* somebody has to take on trust is not one.
|
|
122
|
+
*/
|
|
123
|
+
export declare const ORG_CHECKS: readonly {
|
|
124
|
+
check: string;
|
|
125
|
+
sql: string;
|
|
126
|
+
}[];
|
|
127
|
+
export interface CheckResult {
|
|
128
|
+
check: string;
|
|
129
|
+
sql: string;
|
|
130
|
+
/** Rows that should not exist. Anything but zero is a finding. */
|
|
131
|
+
found: number;
|
|
132
|
+
ok: boolean;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Ask the register all of them.
|
|
136
|
+
*
|
|
137
|
+
* Read-only, and safe to run before the migration as well as after — a check
|
|
138
|
+
* against a table that does not exist yet is a failure worth seeing rather than
|
|
139
|
+
* one to swallow, so nothing here catches.
|
|
140
|
+
*/
|
|
141
|
+
export declare function verifyOrgs(register: Register): Promise<CheckResult[]>;
|
|
142
|
+
//# sourceMappingURL=orgs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orgs.d.ts","sourceRoot":"","sources":["../../src/admin/orgs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,0EAA0E;AAC1E,eAAO,MAAM,SAAS,iCAAkC,CAAC;AACzD,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,+BAAgC,CAAC;AACvD,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,QAAyB,CAAC;AAE/C,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,qEAAqE;IACrE,IAAI,EAAE,OAAO,CAAC;IACd,2EAA2E;IAC3E,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,gEAAgE;AAChE,MAAM,WAAW,UAAW,SAAQ,GAAG;IACrC,IAAI,EAAE,OAAO,CAAC;CACf;AAED,gFAAgF;AAChF,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,IAAI,EAAE,MAAM;CAIzB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,GAAG,CAAC,CAwBd;AAED,oEAAoE;AACpE,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAQvF;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU,EAAE,SAAS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EAqD/D,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,OAAO,CAAC;CACb;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAQ3E"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/** What somebody may do inside one organisation. Never a factory role. */
|
|
2
|
+
export const ORG_ROLES = ["admin", "publisher"];
|
|
3
|
+
/**
|
|
4
|
+
* Whether an organisation is a person or a group.
|
|
5
|
+
*
|
|
6
|
+
* `personal` is made for you when you claim a username and is never made any
|
|
7
|
+
* other way, which is what keeps a name meaning one thing across the People
|
|
8
|
+
* page, the shelf and the URL.
|
|
9
|
+
*/
|
|
10
|
+
export const ORG_KINDS = ["personal", "team"];
|
|
11
|
+
/**
|
|
12
|
+
* The shape a name may take.
|
|
13
|
+
*
|
|
14
|
+
* The same rule as a chunk's scope and a username, because they are the same
|
|
15
|
+
* string. Enforced by a check constraint as well as here — a rule that lives
|
|
16
|
+
* only in TypeScript is a rule the next caller writes around.
|
|
17
|
+
*/
|
|
18
|
+
export const ORG_NAME = /^[a-z0-9][a-z0-9-]*$/;
|
|
19
|
+
/** Refused because the name belongs to an organisation that is not personal. */
|
|
20
|
+
export class OrgNameTakenError extends Error {
|
|
21
|
+
constructor(name) {
|
|
22
|
+
super(`"${name}" is a team organisation, so it cannot also be somebody's personal one.`);
|
|
23
|
+
this.name = "OrgNameTakenError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Give a user the organisation that matches their username.
|
|
28
|
+
*
|
|
29
|
+
* Runs in the same moment as claiming the name, because a name that is yours on
|
|
30
|
+
* the People page and somebody else's on the shelf would be worse than having
|
|
31
|
+
* no names at all. Safe to run again: if the membership insert fails the name is
|
|
32
|
+
* still theirs and the organisation is still there, which is the right way round
|
|
33
|
+
* — a person without their scope yet is inconvenienced, a person whose scope
|
|
34
|
+
* belongs to somebody else is a bug you cannot undo.
|
|
35
|
+
*
|
|
36
|
+
* Three statements rather than one because the client sends one statement per
|
|
37
|
+
* request. The insert is the check for the same reason `claimUsername`'s is: two
|
|
38
|
+
* people reaching for a name in the same second is a race only the unique index
|
|
39
|
+
* can settle.
|
|
40
|
+
*
|
|
41
|
+
* The read between the two writes is not ceremony. `on conflict do nothing` is
|
|
42
|
+
* silent about *why* it did nothing, and the one case that matters is a team
|
|
43
|
+
* organisation already holding this name — adding the caller to that as an admin
|
|
44
|
+
* would hand them somebody else's tenant. So it is looked at, and refused.
|
|
45
|
+
*/
|
|
46
|
+
export async function claimPersonalOrg(userId, username, register) {
|
|
47
|
+
if (!ORG_NAME.test(username))
|
|
48
|
+
throw new Error(`"${username}" is not a name an organisation can have.`);
|
|
49
|
+
await register.write(`insert into orgs (name, kind, plan)
|
|
50
|
+
select $1, 'personal', coalesce(u.plan, 'free') from users u where u.id = $2
|
|
51
|
+
on conflict (lower(name)) do nothing`, [username, userId]);
|
|
52
|
+
const { rows } = await register.query("select * from orgs where lower(name) = lower($1)", [username]);
|
|
53
|
+
const org = rows[0];
|
|
54
|
+
if (!org)
|
|
55
|
+
throw new Error(`No user ${userId}, so "${username}" belongs to nobody.`);
|
|
56
|
+
if (org.kind !== "personal")
|
|
57
|
+
throw new OrgNameTakenError(username);
|
|
58
|
+
await register.write(`insert into org_members (org_id, user_id, role) values ($1, $2, 'admin')
|
|
59
|
+
on conflict (org_id, user_id) do nothing`, [org.id, userId]);
|
|
60
|
+
return org;
|
|
61
|
+
}
|
|
62
|
+
/** The organisations this person belongs to, personal one first. */
|
|
63
|
+
export async function orgsFor(userId, register) {
|
|
64
|
+
const { rows } = await register.query(`select o.*, m.role from orgs o join org_members m on m.org_id = o.id
|
|
65
|
+
where m.user_id = $1
|
|
66
|
+
order by (o.kind = 'personal') desc, o.name`, [userId]);
|
|
67
|
+
return rows;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Whether this person may publish under this name.
|
|
71
|
+
*
|
|
72
|
+
* Membership is the whole answer — both roles publish, which is what makes
|
|
73
|
+
* `publisher` worth having as the one that cannot also invite people.
|
|
74
|
+
*/
|
|
75
|
+
export async function mayPublish(userId, org, register) {
|
|
76
|
+
const { rows } = await register.query(`select 1 from org_members m join orgs o on o.id = m.org_id
|
|
77
|
+
where m.user_id = $1 and lower(o.name) = lower($2)`, [userId, org]);
|
|
78
|
+
return rows.length > 0;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* What must be true of the register once organisations are backfilled.
|
|
82
|
+
*
|
|
83
|
+
* Written as data, and as violations rather than assertions, for one reason:
|
|
84
|
+
* **a wrong backfill does not fail loudly.** It sits looking fine until the day
|
|
85
|
+
* reads move onto `org_id`, and then it is one customer seeing another's apps.
|
|
86
|
+
* Nothing about that shows up in a test — the schema is right either way — so
|
|
87
|
+
* the proof has to be a question asked of the live rows.
|
|
88
|
+
*
|
|
89
|
+
* Every check counts rows that should not exist. Zero is the only passing
|
|
90
|
+
* answer, which means a check that is wrong tends to fail rather than pass, and
|
|
91
|
+
* a table that is empty passes honestly rather than vacuously hiding a bug.
|
|
92
|
+
*
|
|
93
|
+
* Exported so the CLI can print the SQL beside the count. A verification
|
|
94
|
+
* somebody has to take on trust is not one.
|
|
95
|
+
*/
|
|
96
|
+
export const ORG_CHECKS = [
|
|
97
|
+
{
|
|
98
|
+
check: "users with a username and no personal organisation",
|
|
99
|
+
sql: `select count(*) as n from users u where u.username is not null
|
|
100
|
+
and not exists (select 1 from orgs o
|
|
101
|
+
where lower(o.name) = lower(u.username) and o.kind = 'personal')`,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
check: "personal organisations whose name is nobody's username",
|
|
105
|
+
sql: `select count(*) as n from orgs o where o.kind = 'personal'
|
|
106
|
+
and not exists (select 1 from users u where lower(u.username) = lower(o.name))`,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
check: "personal organisations without exactly one admin member",
|
|
110
|
+
sql: `select count(*) as n from orgs o where o.kind = 'personal'
|
|
111
|
+
and (select count(*) from org_members m
|
|
112
|
+
where m.org_id = o.id and m.role = 'admin') <> 1`,
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
check: "members of an organisation they are not in the register of",
|
|
116
|
+
sql: `select count(*) as n from org_members m
|
|
117
|
+
where not exists (select 1 from users u where u.id = m.user_id)`,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
check: "apps in no organisation",
|
|
121
|
+
sql: "select count(*) as n from apps where org_id is null",
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
check: "apps whose organisation is not their owner's personal one",
|
|
125
|
+
sql: `select count(*) as n from apps a
|
|
126
|
+
join users u on u.id = a.owner_id
|
|
127
|
+
where a.org_id is not null
|
|
128
|
+
and a.org_id is distinct from
|
|
129
|
+
(select o.id from orgs o
|
|
130
|
+
where lower(o.name) = lower(u.username) and o.kind = 'personal')`,
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
check: "apps whose owner has claimed no username, so can have no organisation",
|
|
134
|
+
sql: `select count(*) as n from apps a join users u on u.id = a.owner_id
|
|
135
|
+
where u.username is null`,
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
check: "credit entries in no organisation",
|
|
139
|
+
sql: "select count(*) as n from credit_ledger where org_id is null",
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
check: "api tokens in no organisation",
|
|
143
|
+
sql: "select count(*) as n from api_tokens where org_id is null",
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
check: "api tokens with no recorded creator",
|
|
147
|
+
sql: "select count(*) as n from api_tokens where created_by is null",
|
|
148
|
+
},
|
|
149
|
+
];
|
|
150
|
+
/**
|
|
151
|
+
* Ask the register all of them.
|
|
152
|
+
*
|
|
153
|
+
* Read-only, and safe to run before the migration as well as after — a check
|
|
154
|
+
* against a table that does not exist yet is a failure worth seeing rather than
|
|
155
|
+
* one to swallow, so nothing here catches.
|
|
156
|
+
*/
|
|
157
|
+
export async function verifyOrgs(register) {
|
|
158
|
+
const out = [];
|
|
159
|
+
for (const { check, sql } of ORG_CHECKS) {
|
|
160
|
+
const { rows } = await register.query(sql);
|
|
161
|
+
const found = Number(rows[0]?.["n"] ?? 0);
|
|
162
|
+
out.push({ check, sql, found, ok: found === 0 });
|
|
163
|
+
}
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=orgs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orgs.js","sourceRoot":"","sources":["../../src/admin/orgs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { type Migration } from "./migrations.ts";
|
|
2
|
+
import type { Register } from "./master.ts";
|
|
3
|
+
/** The name of the change a statement belongs to — its directory. */
|
|
4
|
+
export declare const changeOf: (id: string) => string;
|
|
5
|
+
/**
|
|
6
|
+
* Every statement the register's schema is made of, in order.
|
|
7
|
+
*
|
|
8
|
+
* Read rather than declared, so the SQL lives in `.sql` files somebody can
|
|
9
|
+
* review as SQL. A directory with no `.sql` in it is not an error — it is a
|
|
10
|
+
* change whose files have not been written yet, and an empty answer is the
|
|
11
|
+
* honest one.
|
|
12
|
+
*/
|
|
13
|
+
export declare function registerMigrations(): Promise<Migration[]>;
|
|
14
|
+
export interface RegisterState {
|
|
15
|
+
/** Every statement in this Core, in order. */
|
|
16
|
+
all: Migration[];
|
|
17
|
+
/** What this register has already had. */
|
|
18
|
+
had: Set<string>;
|
|
19
|
+
/** What it owes, in the order it owes them. */
|
|
20
|
+
owed: Migration[];
|
|
21
|
+
/** Statements among the owed that alter or discard what is already there. */
|
|
22
|
+
destructive: Migration[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* What this register has had, and what it still owes.
|
|
26
|
+
*
|
|
27
|
+
* Asks without creating: a register that has never been migrated has no ledger
|
|
28
|
+
* table, and `applied` reads that as "none" rather than making one. This is the
|
|
29
|
+
* call an unconfirmed plan makes, and a plan that wrote to the database would
|
|
30
|
+
* not be a plan.
|
|
31
|
+
*/
|
|
32
|
+
export declare function registerState(register: Register): Promise<RegisterState>;
|
|
33
|
+
/** A migration that would alter or discard, without the separate opt-in. */
|
|
34
|
+
export declare class DestructiveMigrationError extends Error {
|
|
35
|
+
readonly migrations: Migration[];
|
|
36
|
+
constructor(migrations: Migration[]);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Bring the register up to what this Core describes.
|
|
40
|
+
*
|
|
41
|
+
* The destructive guard is the same distinction `promote` draws and for the
|
|
42
|
+
* same reason: confirming says "yes, run these"; accepting destruction says
|
|
43
|
+
* "yes, to a dropped column on the database that knows who everybody is". One
|
|
44
|
+
* yes covering both hides the one that cannot be undone by redeploying.
|
|
45
|
+
*/
|
|
46
|
+
export declare function migrateRegister(register: Register, opts?: {
|
|
47
|
+
acceptDestructive?: boolean;
|
|
48
|
+
}, watch?: (m: Migration) => void): Promise<{
|
|
49
|
+
ran: number;
|
|
50
|
+
migrations: Migration[];
|
|
51
|
+
}>;
|
|
52
|
+
/**
|
|
53
|
+
* The relation a `create` statement makes.
|
|
54
|
+
*
|
|
55
|
+
* Only the two forms the register's schema is written in, and undefined for
|
|
56
|
+
* anything else — which is the point. A statement whose effect cannot be named
|
|
57
|
+
* cannot be checked, and `adoptChange` refuses rather than guessing.
|
|
58
|
+
*/
|
|
59
|
+
export declare function relationOf(sql: string): {
|
|
60
|
+
kind: "table" | "index";
|
|
61
|
+
name: string;
|
|
62
|
+
} | undefined;
|
|
63
|
+
/** Refused because the register does not hold what it was asked to vouch for. */
|
|
64
|
+
export declare class MissingFromRegisterError extends Error {
|
|
65
|
+
readonly missing: {
|
|
66
|
+
id: string;
|
|
67
|
+
relation: string;
|
|
68
|
+
}[];
|
|
69
|
+
constructor(change: string, missing: {
|
|
70
|
+
id: string;
|
|
71
|
+
relation: string;
|
|
72
|
+
}[]);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Record one change as applied, having run none of it.
|
|
76
|
+
*
|
|
77
|
+
* The register predates its own ledger, so `0001-baseline` describes tables
|
|
78
|
+
* that have been there for months. Running it would fail on the first `create
|
|
79
|
+
* table`; skipping it would leave every later change looking like it depends on
|
|
80
|
+
* something that never happened. Recording it is the truth: those statements
|
|
81
|
+
* are already true of this database.
|
|
82
|
+
*
|
|
83
|
+
* **Checked rather than trusted.** The failure this command can cause is
|
|
84
|
+
* invisible — a false receipt, and then a schema change silently skipped
|
|
85
|
+
* forever after — so every statement's relation is looked up in the catalog
|
|
86
|
+
* first, and a change that is not entirely true of this register is refused
|
|
87
|
+
* with the missing pieces named. That matters most where databases have
|
|
88
|
+
* drifted: the factory's production register has a `runs` table and its dev one
|
|
89
|
+
* does not, and the honest answer there is "apply that one, adopt the rest"
|
|
90
|
+
* rather than a receipt covering both.
|
|
91
|
+
*
|
|
92
|
+
* Named rather than inferred. "Mark everything pending as done" would be a
|
|
93
|
+
* command that quietly swallows a real migration somebody meant to run — so a
|
|
94
|
+
* caller has to say which change it means, and mean it. A full statement id is
|
|
95
|
+
* accepted as well as a change name, which is how the operator resolves drift.
|
|
96
|
+
*/
|
|
97
|
+
export declare function adoptChange(register: Register, change: string): Promise<string[]>;
|
|
98
|
+
//# sourceMappingURL=register.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/admin/register.ts"],"names":[],"mappings":"AAoCA,OAAO,EAAiD,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAChG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAY5C,qEAAqE;AACrE,eAAO,MAAM,QAAQ,GAAI,IAAI,MAAM,KAAG,MAAgC,CAAC;AAEvE;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAgB/D;AAED,MAAM,WAAW,aAAa;IAC5B,8CAA8C;IAC9C,GAAG,EAAE,SAAS,EAAE,CAAC;IACjB,0CAA0C;IAC1C,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACjB,+CAA+C;IAC/C,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,6EAA6E;IAC7E,WAAW,EAAE,SAAS,EAAE,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAC,CAK9E;AAED,4EAA4E;AAC5E,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,UAAU,EAAE,SAAS,EAAE,CAAC;gBACrB,UAAU,EAAE,SAAS,EAAE;CASpC;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,QAAQ,EAClB,IAAI,GAAE;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAO,EAC1C,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,GAC7B,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,SAAS,EAAE,CAAA;CAAE,CAAC,CAOnD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAU7F;AAED,iFAAiF;AACjF,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;gBACzC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE;CASxE;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA6BvF"}
|