@odla-ai/chapter 0.40.2 → 0.40.3

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.
@@ -407,16 +407,20 @@ interface AdminBuilderLibraryData {
407
407
  receivedAt: number;
408
408
  }[];
409
409
  localAuthoring: boolean;
410
+ /** Closed set of Chapter destinations the server will accept. */
411
+ chapterTargets: {
412
+ chapterId: string;
413
+ }[];
410
414
  visibility: {
411
415
  builtNotFoundSeesChapterSources: boolean;
412
416
  chaptersSeeSiblingSources: false;
413
417
  };
414
418
  }
415
- /** Private source-material editor, visibly separate from member publishing. */
419
+ /** CMS-style private source-material list and editor. */
416
420
  declare function BuilderLibraryAdmin({ ctx, initialData }: {
417
421
  ctx: AdminSectionContext;
418
422
  initialData?: AdminBuilderLibraryData;
419
- }): preact.JSX.Element;
423
+ }): JSX.Element;
420
424
  /** Reusable private Builder Library section for the standard Settings workspace. */
421
425
  declare function builderLibrarySection(): AdminSection;
422
426
 
@@ -33,7 +33,7 @@ import {
33
33
  networkRecordsWorkspace,
34
34
  peopleSection,
35
35
  useAdminResource
36
- } from "../../chunk-4K2Q5JBC.js";
36
+ } from "../../chunk-O22RRPBT.js";
37
37
  import {
38
38
  ChapterCopyProvider,
39
39
  useChapterCopy
package/dist/ui/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  networkRecordsWorkspace,
59
59
  peopleSection,
60
60
  useAdminResource
61
- } from "../chunk-4K2Q5JBC.js";
61
+ } from "../chunk-O22RRPBT.js";
62
62
  import {
63
63
  BrandStyle,
64
64
  ChapterCopyProvider,
@@ -1855,12 +1855,16 @@ async function notifyAdminOfApplication(db, env, chapterId, applicationId, field
1855
1855
  }
1856
1856
 
1857
1857
  // src/worker-routes.ts
1858
- async function memberSessionApplication(db, chapterId, email) {
1858
+ async function memberSessionApplication(db, chapterId, identity) {
1859
1859
  let apps = (await db.query({ applications: { $: {
1860
- where: { emailNormalized: normalizeChapterEmail(email) },
1860
+ where: { clerkUserId: identity.userId },
1861
1861
  limit: 20
1862
1862
  } } })).applications;
1863
- if (!apps?.length) apps = (await db.query({ applications: { $: { where: { email }, limit: 20 } } })).applications;
1863
+ if (!apps?.length && identity.email) apps = (await db.query({ applications: { $: {
1864
+ where: { emailNormalized: normalizeChapterEmail(identity.email) },
1865
+ limit: 20
1866
+ } } })).applications;
1867
+ if (!apps?.length && identity.email) apps = (await db.query({ applications: { $: { where: { email: identity.email }, limit: 20 } } })).applications;
1864
1868
  const app = Array.isArray(apps) ? [...apps].sort((a, b) => Number(b.createdAt ?? 0) - Number(a.createdAt ?? 0))[0] : void 0;
1865
1869
  if (!app) return null;
1866
1870
  const meetings = (await db.query({ meetings: { $: { where: { applicationId: app.id, status: "scheduled" }, order: { createdAt: "desc" }, limit: 1 } } })).meetings;
@@ -1891,8 +1895,8 @@ var handleMe = async (req, url, env, ctx) => {
1891
1895
  const role = await ctx.roleFor(db, u);
1892
1896
  const superAdmin = await ctx.isSuperAdminEmail(db, u.email);
1893
1897
  const base = { authorized: isAdminRole(role, ctx.auth), role, superAdmin, email: u.email ?? null };
1894
- if (ctx.chapter.mode !== "chapter" || !u.email) return json(base);
1895
- const member = await memberSessionApplication(db, ctx.chapter.id, u.email);
1898
+ if (ctx.chapter.mode !== "chapter") return json(base);
1899
+ const member = await memberSessionApplication(db, ctx.chapter.id, { userId: u.userId, email: u.email });
1896
1900
  let privateMetadataSynced = false;
1897
1901
  if (member && ctx.chapter.account !== "none" && typeof member.source.clerkPrivateMetadataSyncedAt !== "number") {
1898
1902
  privateMetadataSynced = await syncApplicantPrivateMetadata(
@@ -6079,8 +6083,8 @@ function validateBuilderLibraryDocument(value, options = {}) {
6079
6083
  if (sourceType === "chapter" && (resource.scope.kind !== "chapter" || resource.scope.chapterId !== sourceAppId)) {
6080
6084
  errors.push(`document.resources.${resource.id}: Chapter sources may author only their own chapter scope`);
6081
6085
  }
6082
- if (sourceType === "built_not_found" && resource.scope.kind === "chapter") {
6083
- errors.push(`document.resources.${resource.id}: Built Not Found sources may author only built_not_found or global scope`);
6086
+ if (sourceType === "built_not_found" && resource.scope.kind === "chapter" && !(options.allowedChapterIds ?? []).includes(resource.scope.chapterId)) {
6087
+ errors.push(`document.resources.${resource.id}: Built Not Found may target only configured Chapters`);
6084
6088
  }
6085
6089
  }
6086
6090
  if (errors.length) return { ok: false, errors };
@@ -6240,12 +6244,13 @@ var handleBuilderLibraryControl = async (req, url, env, ctx) => {
6240
6244
  const checked = validateBuilderLibraryDocument(input.document, {
6241
6245
  sourceType,
6242
6246
  sourceAppId: verified.source.sourceId,
6243
- targetAppId: ctx.chapter.id
6247
+ targetAppId: ctx.chapter.id,
6248
+ ...ctx.chapter.mode === "chapter" ? { allowedChapterIds: [ctx.chapter.id] } : {}
6244
6249
  });
6245
6250
  if (!checked.ok) return json({ ok: false, reason: "invalid_document", errors: checked.errors }, 400);
6246
6251
  const document = checked.value;
6247
- if (ctx.chapter.mode === "chapter" && document.resources.some((resource) => resource.scope.kind !== "global")) {
6248
- return json({ ok: false, reason: "invalid_document", errors: ["Built Not Found may deliver only global resources to a Chapter"] }, 400);
6252
+ if (ctx.chapter.mode === "chapter" && document.resources.some((resource) => resource.scope.kind !== "global" && (resource.scope.kind !== "chapter" || resource.scope.chapterId !== ctx.chapter.id))) {
6253
+ return json({ ok: false, reason: "invalid_document", errors: ["Built Not Found may deliver only global or this Chapter's resources"] }, 400);
6249
6254
  }
6250
6255
  if (!document.target || document.target.environment !== env.ODLA_ENV) return json({ ok: false, reason: "wrong_environment" }, 409);
6251
6256
  if (!digest || await builderLibraryDigest(document) !== digest) return json({ ok: false, reason: "invalid_digest" }, 400);
@@ -6351,7 +6356,11 @@ var handleAdminBuilderLibrary = async (req, url, env, ctx) => {
6351
6356
  source: { type: "built_not_found", appId: ctx.chapter.id },
6352
6357
  resources: [...local3?.document.resources ?? [], promoted]
6353
6358
  };
6354
- const checked2 = validateBuilderLibraryDocument(document, { sourceType: "built_not_found", sourceAppId: ctx.chapter.id });
6359
+ const checked2 = validateBuilderLibraryDocument(document, {
6360
+ sourceType: "built_not_found",
6361
+ sourceAppId: ctx.chapter.id,
6362
+ allowedChapterIds: ctx.chapter.builderLibrary.sources.map((source2) => source2.sourceId)
6363
+ });
6355
6364
  if (!checked2.ok) return json({ error: "promoted resource is invalid", errors: checked2.errors }, 400);
6356
6365
  try {
6357
6366
  const saved = await saveLocalBuilderLibrary(db, checked2.value, env.ODLA_ENV, expectedRevision2, now2, actorFor(user));
@@ -6366,6 +6375,7 @@ var handleAdminBuilderLibrary = async (req, url, env, ctx) => {
6366
6375
  local: local3 ? { revision: local3.revision, document: local3.document } : null,
6367
6376
  sources: controls.map(({ sourceId, revision, digest, document, receivedAt }) => ({ sourceId, revision, digest, document, receivedAt })),
6368
6377
  localAuthoring: ctx.chapter.builderLibrary.localAuthoring,
6378
+ chapterTargets: ctx.chapter.mode === "hub" ? ctx.chapter.builderLibrary.sources.map((source) => ({ chapterId: source.sourceId })) : [{ chapterId: ctx.chapter.id }],
6369
6379
  visibility: { builtNotFoundSeesChapterSources: ctx.chapter.mode === "hub", chaptersSeeSiblingSources: false }
6370
6380
  });
6371
6381
  }
@@ -6384,7 +6394,11 @@ var handleAdminBuilderLibrary = async (req, url, env, ctx) => {
6384
6394
  const now = Date.now();
6385
6395
  const actor = actorFor(user);
6386
6396
  const authoritative = withLocalAuthority2(input.document, ctx.chapter.mode, ctx.chapter.id, expectedRevision + 1, now, actor, local3?.document);
6387
- const checked = validateBuilderLibraryDocument(authoritative, { sourceType: ctx.chapter.mode === "hub" ? "built_not_found" : "chapter", sourceAppId: ctx.chapter.id });
6397
+ const checked = validateBuilderLibraryDocument(authoritative, {
6398
+ sourceType: ctx.chapter.mode === "hub" ? "built_not_found" : "chapter",
6399
+ sourceAppId: ctx.chapter.id,
6400
+ ...ctx.chapter.mode === "hub" ? { allowedChapterIds: ctx.chapter.builderLibrary.sources.map((source) => source.sourceId) } : {}
6401
+ });
6388
6402
  if (!checked.ok) return json({ error: "invalid Builder Library", errors: checked.errors }, 400);
6389
6403
  try {
6390
6404
  const saved = await saveLocalBuilderLibrary(db, checked.value, env.ODLA_ENV, expectedRevision, now, actor);