@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.
@@ -1827,12 +1827,16 @@ async function notifyAdminOfApplication(db, env, chapterId, applicationId, field
1827
1827
  }
1828
1828
 
1829
1829
  // src/worker-routes.ts
1830
- async function memberSessionApplication(db, chapterId, email) {
1830
+ async function memberSessionApplication(db, chapterId, identity) {
1831
1831
  let apps = (await db.query({ applications: { $: {
1832
- where: { emailNormalized: normalizeChapterEmail(email) },
1832
+ where: { clerkUserId: identity.userId },
1833
1833
  limit: 20
1834
1834
  } } })).applications;
1835
- if (!apps?.length) apps = (await db.query({ applications: { $: { where: { email }, limit: 20 } } })).applications;
1835
+ if (!apps?.length && identity.email) apps = (await db.query({ applications: { $: {
1836
+ where: { emailNormalized: normalizeChapterEmail(identity.email) },
1837
+ limit: 20
1838
+ } } })).applications;
1839
+ if (!apps?.length && identity.email) apps = (await db.query({ applications: { $: { where: { email: identity.email }, limit: 20 } } })).applications;
1836
1840
  const app = Array.isArray(apps) ? [...apps].sort((a, b) => Number(b.createdAt ?? 0) - Number(a.createdAt ?? 0))[0] : void 0;
1837
1841
  if (!app) return null;
1838
1842
  const meetings = (await db.query({ meetings: { $: { where: { applicationId: app.id, status: "scheduled" }, order: { createdAt: "desc" }, limit: 1 } } })).meetings;
@@ -1863,8 +1867,8 @@ var handleMe = async (req, url, env, ctx) => {
1863
1867
  const role = await ctx.roleFor(db, u);
1864
1868
  const superAdmin = await ctx.isSuperAdminEmail(db, u.email);
1865
1869
  const base = { authorized: isAdminRole(role, ctx.auth), role, superAdmin, email: u.email ?? null };
1866
- if (ctx.chapter.mode !== "chapter" || !u.email) return json(base);
1867
- const member = await memberSessionApplication(db, ctx.chapter.id, u.email);
1870
+ if (ctx.chapter.mode !== "chapter") return json(base);
1871
+ const member = await memberSessionApplication(db, ctx.chapter.id, { userId: u.userId, email: u.email });
1868
1872
  let privateMetadataSynced = false;
1869
1873
  if (member && ctx.chapter.account !== "none" && typeof member.source.clerkPrivateMetadataSyncedAt !== "number") {
1870
1874
  privateMetadataSynced = await syncApplicantPrivateMetadata(
@@ -6055,8 +6059,8 @@ function validateBuilderLibraryDocument(value, options = {}) {
6055
6059
  if (sourceType === "chapter" && (resource.scope.kind !== "chapter" || resource.scope.chapterId !== sourceAppId)) {
6056
6060
  errors.push(`document.resources.${resource.id}: Chapter sources may author only their own chapter scope`);
6057
6061
  }
6058
- if (sourceType === "built_not_found" && resource.scope.kind === "chapter") {
6059
- errors.push(`document.resources.${resource.id}: Built Not Found sources may author only built_not_found or global scope`);
6062
+ if (sourceType === "built_not_found" && resource.scope.kind === "chapter" && !(options.allowedChapterIds ?? []).includes(resource.scope.chapterId)) {
6063
+ errors.push(`document.resources.${resource.id}: Built Not Found may target only configured Chapters`);
6060
6064
  }
6061
6065
  }
6062
6066
  if (errors.length) return { ok: false, errors };
@@ -6216,12 +6220,13 @@ var handleBuilderLibraryControl = async (req, url, env, ctx) => {
6216
6220
  const checked = validateBuilderLibraryDocument(input.document, {
6217
6221
  sourceType,
6218
6222
  sourceAppId: verified.source.sourceId,
6219
- targetAppId: ctx.chapter.id
6223
+ targetAppId: ctx.chapter.id,
6224
+ ...ctx.chapter.mode === "chapter" ? { allowedChapterIds: [ctx.chapter.id] } : {}
6220
6225
  });
6221
6226
  if (!checked.ok) return json({ ok: false, reason: "invalid_document", errors: checked.errors }, 400);
6222
6227
  const document = checked.value;
6223
- if (ctx.chapter.mode === "chapter" && document.resources.some((resource) => resource.scope.kind !== "global")) {
6224
- return json({ ok: false, reason: "invalid_document", errors: ["Built Not Found may deliver only global resources to a Chapter"] }, 400);
6228
+ if (ctx.chapter.mode === "chapter" && document.resources.some((resource) => resource.scope.kind !== "global" && (resource.scope.kind !== "chapter" || resource.scope.chapterId !== ctx.chapter.id))) {
6229
+ return json({ ok: false, reason: "invalid_document", errors: ["Built Not Found may deliver only global or this Chapter's resources"] }, 400);
6225
6230
  }
6226
6231
  if (!document.target || document.target.environment !== env.ODLA_ENV) return json({ ok: false, reason: "wrong_environment" }, 409);
6227
6232
  if (!digest || await builderLibraryDigest(document) !== digest) return json({ ok: false, reason: "invalid_digest" }, 400);
@@ -6327,7 +6332,11 @@ var handleAdminBuilderLibrary = async (req, url, env, ctx) => {
6327
6332
  source: { type: "built_not_found", appId: ctx.chapter.id },
6328
6333
  resources: [...local3?.document.resources ?? [], promoted]
6329
6334
  };
6330
- const checked2 = validateBuilderLibraryDocument(document, { sourceType: "built_not_found", sourceAppId: ctx.chapter.id });
6335
+ const checked2 = validateBuilderLibraryDocument(document, {
6336
+ sourceType: "built_not_found",
6337
+ sourceAppId: ctx.chapter.id,
6338
+ allowedChapterIds: ctx.chapter.builderLibrary.sources.map((source2) => source2.sourceId)
6339
+ });
6331
6340
  if (!checked2.ok) return json({ error: "promoted resource is invalid", errors: checked2.errors }, 400);
6332
6341
  try {
6333
6342
  const saved = await saveLocalBuilderLibrary(db, checked2.value, env.ODLA_ENV, expectedRevision2, now2, actorFor(user));
@@ -6342,6 +6351,7 @@ var handleAdminBuilderLibrary = async (req, url, env, ctx) => {
6342
6351
  local: local3 ? { revision: local3.revision, document: local3.document } : null,
6343
6352
  sources: controls.map(({ sourceId, revision, digest, document, receivedAt }) => ({ sourceId, revision, digest, document, receivedAt })),
6344
6353
  localAuthoring: ctx.chapter.builderLibrary.localAuthoring,
6354
+ chapterTargets: ctx.chapter.mode === "hub" ? ctx.chapter.builderLibrary.sources.map((source) => ({ chapterId: source.sourceId })) : [{ chapterId: ctx.chapter.id }],
6345
6355
  visibility: { builtNotFoundSeesChapterSources: ctx.chapter.mode === "hub", chaptersSeeSiblingSources: false }
6346
6356
  });
6347
6357
  }
@@ -6360,7 +6370,11 @@ var handleAdminBuilderLibrary = async (req, url, env, ctx) => {
6360
6370
  const now = Date.now();
6361
6371
  const actor = actorFor(user);
6362
6372
  const authoritative = withLocalAuthority2(input.document, ctx.chapter.mode, ctx.chapter.id, expectedRevision + 1, now, actor, local3?.document);
6363
- const checked = validateBuilderLibraryDocument(authoritative, { sourceType: ctx.chapter.mode === "hub" ? "built_not_found" : "chapter", sourceAppId: ctx.chapter.id });
6373
+ const checked = validateBuilderLibraryDocument(authoritative, {
6374
+ sourceType: ctx.chapter.mode === "hub" ? "built_not_found" : "chapter",
6375
+ sourceAppId: ctx.chapter.id,
6376
+ ...ctx.chapter.mode === "hub" ? { allowedChapterIds: ctx.chapter.builderLibrary.sources.map((source) => source.sourceId) } : {}
6377
+ });
6364
6378
  if (!checked.ok) return json({ error: "invalid Builder Library", errors: checked.errors }, 400);
6365
6379
  try {
6366
6380
  const saved = await saveLocalBuilderLibrary(db, checked.value, env.ODLA_ENV, expectedRevision, now, actor);