@odla-ai/chapter 0.46.0 → 0.47.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/index.d.cts CHANGED
@@ -604,7 +604,7 @@ interface ChapterScheduling {
604
604
  *
605
605
  * - `"claim"` reads a role ladder from a JWT claim (the member-site model:
606
606
  * `provisional → member → admin`). Admin is the last (highest) rung; the
607
- * read-only `superAdmins` tier sits above it.
607
+ * Studio-managed super-admin tier sits above it.
608
608
  * - `"table"` gates on the deny-all `admins` allowlist (the hub model):
609
609
  * a binary "email is an admin or isn't", set only in odla Studio.
610
610
  *
@@ -616,10 +616,13 @@ interface ChapterAuth {
616
616
  /** Role ladder low→high, for `source: "claim"`. The last entry is admin.
617
617
  * Default `["provisional", "member", "admin"]`. */
618
618
  ladder?: readonly string[];
619
- /** Provision the read-only `superAdmins` tier table — the only tier that may
620
- * create/modify admins, and (like every namespace) deny-all + written only in
621
- * odla Studio. Default: `true` for `"claim"`, `false` for `"table"`. */
619
+ /** Enable the Studio-managed super-admin tier — the only tier that may
620
+ * create/modify admins. Default: `true` for `"claim"`, `false` for `"table"`. */
622
621
  superAdmins?: boolean;
622
+ /** Authority behind the super-admin tier. `"table"` preserves the legacy
623
+ * app allowlist; `"odla"` reads protected `$users.role`. Default `"table"`
624
+ * for backward compatibility. */
625
+ superAdminSource?: "table" | "odla";
623
626
  }
624
627
  /** The fully-resolved auth policy (defaults applied) carried on the {@link Chapter}. */
625
628
  interface ResolvedAuth {
@@ -629,6 +632,7 @@ interface ResolvedAuth {
629
632
  /** The highest ladder rung (last entry) — the "admin" gate. */
630
633
  adminRole: string;
631
634
  superAdmins: boolean;
635
+ superAdminSource: "none" | "table" | "odla";
632
636
  }
633
637
  /** The application status pipeline. Which statuses exist, and the subsets a site
634
638
  * allows a call to be booked from / an application approved from. Defaults to
@@ -1199,8 +1203,9 @@ declare function createChapterIntegration(chapter: Chapter, options?: ChapterInt
1199
1203
  *
1200
1204
  * Operational tables (`applications`/`groups`/`meetings`/`emailLog`) are added in
1201
1205
  * `chapter` mode only. The auth tables follow {@link ResolvedAuth}: `source:
1202
- * "table"` adds the `admins` allowlist (hub/BNF); `superAdmins` adds the
1203
- * read-only super-admin tier (default on for the `"claim"` ladder). A `"claim"`
1206
+ * "table"` adds the `admins` allowlist (hub/BNF); `superAdminSource: "table"`
1207
+ * adds the legacy read-only super-admin tier (the backward-compatible default).
1208
+ * `superAdminSource: "odla"` uses reserved `$users` and adds no app namespace. A `"claim"`
1204
1209
  * chapter therefore emits the reference namespace set — `applications`,
1205
1210
  * `groups`, `meetings`, `emailLog`, `stripeEventReceipts`, `superAdmins` — with
1206
1211
  * no `admins` table. */
@@ -1563,6 +1568,8 @@ declare function buildGroupSeed(config: ChapterConfig): Record<string, unknown>;
1563
1568
  * Apply defaults + validate the auth config into a {@link ResolvedAuth}. Defaults
1564
1569
  * by mode: `chapter` → the `provisional/member/admin` claim ladder with the
1565
1570
  * `superAdmins` tier; `hub` → the `admins` allowlist table with no super tier.
1571
+ * Existing sites retain the legacy `superAdmins` table unless they explicitly
1572
+ * select protected odla user roles.
1566
1573
  * Throws at import on a bad policy.
1567
1574
  */
1568
1575
  declare function resolveAuth(mode: ChapterMode, auth: ChapterAuth | undefined): ResolvedAuth;
@@ -1572,7 +1579,7 @@ declare function roleFromClaim(payload: Record<string, unknown>, auth: ResolvedA
1572
1579
  /** Does a role meet the admin bar (the highest ladder rung)? */
1573
1580
  declare function isAdminRole(role: string, auth: ResolvedAuth): boolean;
1574
1581
  /** Inputs to the role-change guard — resolved by the caller (route) from the
1575
- * identity provider + the read-only `superAdmins` table. */
1582
+ * identity provider + the configured Studio-managed super-admin authority. */
1576
1583
  interface RoleChangeContext {
1577
1584
  actorId: string;
1578
1585
  actorIsSuper: boolean;
@@ -1596,8 +1603,8 @@ type GuardResult = {
1596
1603
  * none re-derives it. Denies: an out-of-ladder role; changing your own role;
1597
1604
  * touching a super-admin unless you are one; and (when a `superAdmins` tier
1598
1605
  * exists) creating or altering an admin unless you are a super-admin. Note the
1599
- * super-admin tier itself is never writable here — it lives in the read-only
1600
- * `superAdmins` table, set only in odla Studio.
1606
+ * super-admin tier itself is never writable here — it is set only in odla
1607
+ * Studio, either as a protected `$users.role` or in the legacy allowlist.
1601
1608
  */
1602
1609
  declare function canChangeRole(ctx: RoleChangeContext): GuardResult;
1603
1610
  /** Structural view of odla-db's tenant-vault read, so chapter takes no runtime
package/dist/index.d.ts CHANGED
@@ -604,7 +604,7 @@ interface ChapterScheduling {
604
604
  *
605
605
  * - `"claim"` reads a role ladder from a JWT claim (the member-site model:
606
606
  * `provisional → member → admin`). Admin is the last (highest) rung; the
607
- * read-only `superAdmins` tier sits above it.
607
+ * Studio-managed super-admin tier sits above it.
608
608
  * - `"table"` gates on the deny-all `admins` allowlist (the hub model):
609
609
  * a binary "email is an admin or isn't", set only in odla Studio.
610
610
  *
@@ -616,10 +616,13 @@ interface ChapterAuth {
616
616
  /** Role ladder low→high, for `source: "claim"`. The last entry is admin.
617
617
  * Default `["provisional", "member", "admin"]`. */
618
618
  ladder?: readonly string[];
619
- /** Provision the read-only `superAdmins` tier table — the only tier that may
620
- * create/modify admins, and (like every namespace) deny-all + written only in
621
- * odla Studio. Default: `true` for `"claim"`, `false` for `"table"`. */
619
+ /** Enable the Studio-managed super-admin tier — the only tier that may
620
+ * create/modify admins. Default: `true` for `"claim"`, `false` for `"table"`. */
622
621
  superAdmins?: boolean;
622
+ /** Authority behind the super-admin tier. `"table"` preserves the legacy
623
+ * app allowlist; `"odla"` reads protected `$users.role`. Default `"table"`
624
+ * for backward compatibility. */
625
+ superAdminSource?: "table" | "odla";
623
626
  }
624
627
  /** The fully-resolved auth policy (defaults applied) carried on the {@link Chapter}. */
625
628
  interface ResolvedAuth {
@@ -629,6 +632,7 @@ interface ResolvedAuth {
629
632
  /** The highest ladder rung (last entry) — the "admin" gate. */
630
633
  adminRole: string;
631
634
  superAdmins: boolean;
635
+ superAdminSource: "none" | "table" | "odla";
632
636
  }
633
637
  /** The application status pipeline. Which statuses exist, and the subsets a site
634
638
  * allows a call to be booked from / an application approved from. Defaults to
@@ -1199,8 +1203,9 @@ declare function createChapterIntegration(chapter: Chapter, options?: ChapterInt
1199
1203
  *
1200
1204
  * Operational tables (`applications`/`groups`/`meetings`/`emailLog`) are added in
1201
1205
  * `chapter` mode only. The auth tables follow {@link ResolvedAuth}: `source:
1202
- * "table"` adds the `admins` allowlist (hub/BNF); `superAdmins` adds the
1203
- * read-only super-admin tier (default on for the `"claim"` ladder). A `"claim"`
1206
+ * "table"` adds the `admins` allowlist (hub/BNF); `superAdminSource: "table"`
1207
+ * adds the legacy read-only super-admin tier (the backward-compatible default).
1208
+ * `superAdminSource: "odla"` uses reserved `$users` and adds no app namespace. A `"claim"`
1204
1209
  * chapter therefore emits the reference namespace set — `applications`,
1205
1210
  * `groups`, `meetings`, `emailLog`, `stripeEventReceipts`, `superAdmins` — with
1206
1211
  * no `admins` table. */
@@ -1563,6 +1568,8 @@ declare function buildGroupSeed(config: ChapterConfig): Record<string, unknown>;
1563
1568
  * Apply defaults + validate the auth config into a {@link ResolvedAuth}. Defaults
1564
1569
  * by mode: `chapter` → the `provisional/member/admin` claim ladder with the
1565
1570
  * `superAdmins` tier; `hub` → the `admins` allowlist table with no super tier.
1571
+ * Existing sites retain the legacy `superAdmins` table unless they explicitly
1572
+ * select protected odla user roles.
1566
1573
  * Throws at import on a bad policy.
1567
1574
  */
1568
1575
  declare function resolveAuth(mode: ChapterMode, auth: ChapterAuth | undefined): ResolvedAuth;
@@ -1572,7 +1579,7 @@ declare function roleFromClaim(payload: Record<string, unknown>, auth: ResolvedA
1572
1579
  /** Does a role meet the admin bar (the highest ladder rung)? */
1573
1580
  declare function isAdminRole(role: string, auth: ResolvedAuth): boolean;
1574
1581
  /** Inputs to the role-change guard — resolved by the caller (route) from the
1575
- * identity provider + the read-only `superAdmins` table. */
1582
+ * identity provider + the configured Studio-managed super-admin authority. */
1576
1583
  interface RoleChangeContext {
1577
1584
  actorId: string;
1578
1585
  actorIsSuper: boolean;
@@ -1596,8 +1603,8 @@ type GuardResult = {
1596
1603
  * none re-derives it. Denies: an out-of-ladder role; changing your own role;
1597
1604
  * touching a super-admin unless you are one; and (when a `superAdmins` tier
1598
1605
  * exists) creating or altering an admin unless you are a super-admin. Note the
1599
- * super-admin tier itself is never writable here — it lives in the read-only
1600
- * `superAdmins` table, set only in odla Studio.
1606
+ * super-admin tier itself is never writable here — it is set only in odla
1607
+ * Studio, either as a protected `$users.role` or in the legacy allowlist.
1601
1608
  */
1602
1609
  declare function canChangeRole(ctx: RoleChangeContext): GuardResult;
1603
1610
  /** Structural view of odla-db's tenant-vault read, so chapter takes no runtime
package/dist/index.js CHANGED
@@ -801,7 +801,7 @@ function chapterDb(mode, auth, includeNetworkNotes = false, application = resolv
801
801
  }
802
802
  }
803
803
  if (auth.source === "table") entities.admins = admins;
804
- if (auth.superAdmins) entities.superAdmins = superAdmins;
804
+ if (auth.superAdminSource === "table") entities.superAdmins = superAdmins;
805
805
  if (includeNetworkNotes) entities.networkNotes = networkNotes;
806
806
  if (includeBuilderLibrary) {
807
807
  entities.builderLibraryControls = builderLibraryControls;
@@ -984,7 +984,12 @@ function resolveAuth(mode, auth) {
984
984
  }
985
985
  const adminRole = ladder[ladder.length - 1];
986
986
  const superAdmins2 = a.superAdmins ?? source === "claim";
987
- return { source, claim, ladder, adminRole, superAdmins: superAdmins2 };
987
+ const configuredSuperSource = a.superAdminSource ?? "table";
988
+ if (configuredSuperSource !== "table" && configuredSuperSource !== "odla") {
989
+ throw new Error(`defineChapter.auth.superAdminSource: must be "table" or "odla" \u2014 got ${JSON.stringify(a.superAdminSource)}`);
990
+ }
991
+ const superAdminSource = superAdmins2 ? configuredSuperSource : "none";
992
+ return { source, claim, ladder, adminRole, superAdmins: superAdmins2, superAdminSource };
988
993
  }
989
994
  function roleFromClaim(payload, auth) {
990
995
  const raw2 = payload[auth.claim];