@odla-ai/chapter 0.39.1 → 0.39.2

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/README.md CHANGED
@@ -517,11 +517,20 @@ it on both the Built Not Found hub and each participating Chapter:
517
517
 
518
518
  ```ts
519
519
  // Built Not Found
520
+ network: {
521
+ targets: [
522
+ { id: "oakland", url: "https://oakland.example", binding: "OAKLAND" },
523
+ { id: "denver", url: "https://denver.example", binding: "DENVER" },
524
+ ],
525
+ },
520
526
  builderLibrary: {
521
527
  sources: [{ sourceId: "oakland" }, { sourceId: "denver" }],
522
528
  },
523
529
 
524
530
  // Oakland
531
+ network: {
532
+ readers: [{ id: "built-not-found", fields: { person: ["name"] } }],
533
+ },
525
534
  builderLibrary: {
526
535
  sources: [{ sourceId: "built-not-found" }],
527
536
  },
@@ -544,18 +553,22 @@ Saving a library item never creates or changes a member page.
544
553
  An authenticated admin or site-building agent reads the bounded, published-only
545
554
  manifest from `/api/admin/builder-library/manifest`. On Built Not Found, pass a
546
555
  configured `chapterId` query parameter; on a Chapter, the server fixes the
547
- viewer to that Chapter. Signed delivery uses the dedicated
548
- `builder_library_control_secret` vault key and never reuses CRM, member-content,
549
- or signup-control credentials.
556
+ viewer to that Chapter. Every Builder source must already be the corresponding
557
+ `network.target` (on Built Not Found) or `network.reader` (on a Chapter). Signed
558
+ delivery reuses that Chapter network edge: the Chapter's existing
559
+ `network_share_secret` is the same value Built Not Found already stores as
560
+ `network_share_<chapter_id>`. Builder Library declares and provisions no secret
561
+ of its own.
550
562
 
551
563
  ```bash
552
564
  odla-ai chapter builder-library validate --file oakland-library.json --source-type chapter --source oakland --json
553
565
  odla-ai chapter builder-library manifest --file oakland-library.json --chapter oakland --json
554
566
  odla-ai chapter builder-library deliver --file oakland-library.json \
555
- --url https://builtnotfoundcapital.com --from-env BUILDER_LIBRARY_SECRET --json
567
+ --url https://builtnotfoundcapital.com --from-env NETWORK_SHARE_SECRET --json
556
568
  ```
557
569
 
558
- The signing secret is accepted only from a named environment variable or stdin.
570
+ The existing network share secret is accepted only from a named environment
571
+ variable or stdin; it is never copied into Builder Library config or argv.
559
572
  For a Built Not Found local document, add `--target oakland --environment dev`;
560
573
  the CLI signs only its global resources for that Chapter, never BNF-only items.
561
574
 
@@ -118,16 +118,14 @@ interface ResolvedMemberContent {
118
118
  interface ChapterBuilderLibrary {
119
119
  /** Keep local admin authoring enabled. Defaults to true. */
120
120
  localAuthoring?: boolean;
121
- /** Signed sources this app accepts. Hub sources are Chapters; Chapter sources are Built Not Found. */
121
+ /** Existing Chapter-network peers this app accepts. Hub sources must be
122
+ * configured network targets; a Chapter source must be a configured reader. */
122
123
  sources?: readonly {
123
124
  sourceId: string;
124
- /** Vault key holding the dedicated Builder Library edge secret. */
125
- secretName?: string;
126
125
  }[];
127
126
  }
128
127
  interface ResolvedBuilderLibrarySource {
129
128
  sourceId: string;
130
- secretName: string;
131
129
  }
132
130
  /** Validated Builder Library settings carried on a resolved Chapter. */
133
131
  interface ResolvedBuilderLibrary {
package/dist/index.cjs CHANGED
@@ -1710,8 +1710,7 @@ function resolveMemberContent(input) {
1710
1710
 
1711
1711
  // src/config-builder-library.ts
1712
1712
  var SLUG4 = /^[a-z0-9][a-z0-9-]{1,62}$/;
1713
- var SECRET_NAME3 = /^[a-z][a-z0-9_]{1,127}$/;
1714
- function resolveBuilderLibrary(mode, input) {
1713
+ function resolveBuilderLibrary(mode, input, network = { targets: [], readers: [] }) {
1715
1714
  if (!input) return null;
1716
1715
  if (input.sources !== void 0 && !Array.isArray(input.sources)) {
1717
1716
  throw new Error("defineChapter.builderLibrary.sources: must be an array");
@@ -1731,11 +1730,19 @@ function resolveBuilderLibrary(mode, input) {
1731
1730
  throw new Error(`defineChapter.builderLibrary.sources: duplicate source "${source.sourceId}"`);
1732
1731
  }
1733
1732
  seen.add(source.sourceId);
1734
- const secretName = source.secretName?.trim() || "builder_library_control_secret";
1735
- if (!SECRET_NAME3.test(secretName)) {
1736
- throw new Error(`defineChapter.builderLibrary.sources[${index}].secretName: must be a vault-key identifier`);
1733
+ if ("secretName" in source) {
1734
+ throw new Error(
1735
+ `defineChapter.builderLibrary.sources[${index}].secretName: remove this field; Builder Library reuses the Chapter network edge`
1736
+ );
1737
1737
  }
1738
- return { sourceId: source.sourceId, secretName };
1738
+ const networkPeer = mode === "hub" ? network.targets.some((target) => target.id === source.sourceId) : network.readers.some((reader) => reader.id === source.sourceId);
1739
+ if (!networkPeer) {
1740
+ const side = mode === "hub" ? "targets" : "readers";
1741
+ throw new Error(
1742
+ `defineChapter.builderLibrary.sources[${index}]: "${source.sourceId}" must already be configured in network.${side}`
1743
+ );
1744
+ }
1745
+ return { sourceId: source.sourceId };
1739
1746
  });
1740
1747
  return { enabled: true, localAuthoring: input.localAuthoring !== false, sources };
1741
1748
  }
@@ -1774,7 +1781,7 @@ function defineChapter(config) {
1774
1781
  const network = resolveNetwork(config, crm);
1775
1782
  const signupControl = resolveSignupControl(config.signupControl);
1776
1783
  const memberContent = resolveMemberContent(config.memberContent);
1777
- const builderLibrary = resolveBuilderLibrary(mode, config.builderLibrary);
1784
+ const builderLibrary = resolveBuilderLibrary(mode, config.builderLibrary, network);
1778
1785
  const formation = resolveLeaderFormation(config.formation, crm);
1779
1786
  if (signupControl && mode !== "chapter") {
1780
1787
  throw new Error("defineChapter.signupControl: only chapter-mode followers can receive signup control");
@@ -2098,13 +2105,6 @@ function createChapterIntegration(chapter, options = {}) {
2098
2105
  ...emails?.debugEmail ? { debugEmail: emails.debugEmail } : {}
2099
2106
  });
2100
2107
  const seeds = [...crmDesc.seeds ?? []];
2101
- const builderLibrarySecrets = [...new Set(
2102
- chapter.builderLibrary?.sources.map((source) => source.secretName) ?? []
2103
- )].map((name) => ({
2104
- name,
2105
- description: "Signing secret for private Builder Library delivery from a configured source.",
2106
- required: true
2107
- }));
2108
2108
  const group = chapter.groupSeed();
2109
2109
  if (group) {
2110
2110
  seeds.push({ id: "group", ns: "groups", key: { attr: "id", value: chapter.id }, attrs: { ...group, createdAt: now } });
@@ -2137,7 +2137,7 @@ function createChapterIntegration(chapter, options = {}) {
2137
2137
  },
2138
2138
  rules: { ...crmDesc.rules, ...chapter.rules },
2139
2139
  seeds,
2140
- secrets: builderLibrarySecrets,
2140
+ secrets: [],
2141
2141
  probes: [
2142
2142
  ...crmDesc.probes ?? [],
2143
2143
  // The snapshot route is deliberately private. A credential-free smoke