@odla-ai/chapter 0.29.0 → 0.31.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.
@@ -136,7 +136,7 @@ function createWorkerContext(options) {
136
136
  }
137
137
 
138
138
  // src/worker-routes.ts
139
- var import_crm2 = require("@odla-ai/crm");
139
+ var import_crm3 = require("@odla-ai/crm");
140
140
 
141
141
  // src/discussion-reference-security.ts
142
142
  async function authorizeCrmDiscussionReference(req, env, fetcher = fetch) {
@@ -180,6 +180,9 @@ async function authorizeCrmDiscussionReference(req, env, fetcher = fetch) {
180
180
  }
181
181
  }
182
182
 
183
+ // src/member.ts
184
+ var import_crm = require("@odla-ai/crm");
185
+
183
186
  // src/application-id.ts
184
187
  var APPLICATION_ID_DOMAIN = "odla-ai/chapter/application/v1:";
185
188
  async function applicationIdForSubmission(submissionId) {
@@ -218,7 +221,9 @@ function applicantProfile(chapter, fields) {
218
221
  }
219
222
  async function submitApplication(db, chapter, fields, opts) {
220
223
  const app = chapter.application;
221
- for (const f of app.required) {
224
+ const fieldStates = (0, import_crm.resolveFieldStates)(app.conditions ?? {}, fields, app.required);
225
+ for (const [f, state] of Object.entries(fieldStates)) {
226
+ if (!state.required) continue;
222
227
  const v = fields[f];
223
228
  if (typeof v !== "string" || v.trim() === "") return { ok: false, error: `${f} is required` };
224
229
  }
@@ -237,10 +242,17 @@ async function submitApplication(db, chapter, fields, opts) {
237
242
  const id = opts.submissionId ? await applicationIdForSubmission(opts.submissionId) : opts.newId();
238
243
  const row = { id, status: chapter.pipeline.initial, createdAt: opts.now };
239
244
  for (const f of [...app.required, ...app.optional]) {
245
+ if (fieldStates[f]?.visible === false) continue;
240
246
  if (typeof fields[f] === "string") row[f] = fields[f].trim();
241
247
  }
242
248
  if (fields.focus !== void 0) row.focus = clampArray(fields.focus, app.maxArrayLen);
243
249
  if (opts.groupId) row.groupId = opts.groupId;
250
+ if (typeof fields.tierId === "string" && fields.tierId) {
251
+ if (opts.tierIds && !opts.tierIds.includes(fields.tierId)) {
252
+ return { ok: false, error: "tierId is not an offered tier" };
253
+ }
254
+ row.tierId = fields.tierId;
255
+ }
244
256
  if (acked) row.disclaimerAckAt = opts.now;
245
257
  const { duplicate } = await db.transact(
246
258
  [{ t: "update", ns: "applications", id, attrs: row }],
@@ -248,12 +260,15 @@ async function submitApplication(db, chapter, fields, opts) {
248
260
  );
249
261
  return { ok: true, id, duplicate, status: chapter.pipeline.initial, disclaimerAckAt: acked ? opts.now : null };
250
262
  }
251
- function joinConfig(group, paymentsReady) {
263
+ function joinConfig(group, paymentsReady, tiers = [], conditions = {}) {
252
264
  return {
253
265
  id: group.id,
254
266
  name: group.name,
255
267
  standardPriceCents: group.standardPriceCents ?? 0,
256
268
  foundingDiscountCents: group.foundingDiscountCents ?? 0,
269
+ tiers: [...tiers],
270
+ // The browser evaluates the same conditions the server enforces.
271
+ conditions,
257
272
  disclaimerText: group.disclaimerText ?? "",
258
273
  refundPolicyText: group.refundPolicyText ?? "",
259
274
  trustCopy: group.trustCopy ?? "",
@@ -263,6 +278,79 @@ function joinConfig(group, paymentsReady) {
263
278
  };
264
279
  }
265
280
 
281
+ // src/tiers.ts
282
+ function tierIsFree(tier) {
283
+ return !(tier.priceCents > 0) && !tier.stripePriceId;
284
+ }
285
+ function tierPayable(tier, group, hasSecretKey) {
286
+ if (tierIsFree(tier)) return true;
287
+ return Boolean(group.stripePublishableKey && tier.stripePriceId && hasSecretKey);
288
+ }
289
+ function byOrder(a, b) {
290
+ return a.sortOrder - b.sortOrder || a.id.localeCompare(b.id);
291
+ }
292
+ function resolveTiers(group, rows2 = []) {
293
+ const stored = rows2.filter((tier) => tier.active);
294
+ if (stored.length) return [...stored].sort(byOrder);
295
+ return [{
296
+ id: "standard",
297
+ groupId: String(group.id ?? ""),
298
+ name: "Membership",
299
+ priceCents: group.standardPriceCents ?? 0,
300
+ ...group.stripePriceId ? { stripePriceId: group.stripePriceId } : {},
301
+ sortOrder: 0,
302
+ active: true
303
+ }];
304
+ }
305
+ function offerableTiers(tiers, group, hasSecretKey) {
306
+ return tiers.filter((tier) => tier.active && tierPayable(tier, group, hasSecretKey));
307
+ }
308
+ function findTier(tiers, tierId) {
309
+ if (!tierId) return tiers.length === 1 ? tiers[0] : null;
310
+ return tiers.find((tier) => tier.id === tierId) ?? null;
311
+ }
312
+ function joinConfigTiers(tiers) {
313
+ return tiers.map((tier) => ({
314
+ id: tier.id,
315
+ name: tier.name,
316
+ priceCents: tier.priceCents,
317
+ blurb: tier.blurb ?? "",
318
+ free: tierIsFree(tier)
319
+ }));
320
+ }
321
+
322
+ // src/tiers-store.ts
323
+ function rowToTier(row, groupId) {
324
+ return {
325
+ id: String(row.id ?? ""),
326
+ groupId: String(row.groupId ?? groupId),
327
+ name: String(row.name ?? ""),
328
+ priceCents: typeof row.priceCents === "number" ? row.priceCents : 0,
329
+ ...typeof row.stripePriceId === "string" && row.stripePriceId ? { stripePriceId: row.stripePriceId } : {},
330
+ ...typeof row.blurb === "string" ? { blurb: row.blurb } : {},
331
+ sortOrder: typeof row.sortOrder === "number" ? row.sortOrder : 0,
332
+ // A row that never set `active` is offered; only an explicit false retires
333
+ // a tier, so a half-seeded row cannot silently hide a membership.
334
+ active: row.active !== false
335
+ };
336
+ }
337
+ async function loadTiers(db, group) {
338
+ const groupId = String(group.id ?? "");
339
+ let rows2;
340
+ try {
341
+ rows2 = (await db.query({
342
+ tiers: { $: { where: { groupId }, order: { sortOrder: "asc" }, limit: 100 } }
343
+ })).tiers;
344
+ } catch {
345
+ rows2 = void 0;
346
+ }
347
+ const list = Array.isArray(rows2) ? rows2.map((row) => rowToTier(row, groupId)) : [];
348
+ return resolveTiers(group, list);
349
+ }
350
+ async function loadOfferableTiers(db, group, hasSecretKey) {
351
+ return offerableTiers(await loadTiers(db, group), group, hasSecretKey);
352
+ }
353
+
266
354
  // src/scheduling.ts
267
355
  var SCHEDULING_DEFAULTS = {
268
356
  slotMinutes: 45,
@@ -492,7 +580,7 @@ async function createClerkUser(secretKey, input, fetchImpl = fetch) {
492
580
  }
493
581
 
494
582
  // src/network.ts
495
- var import_crm = require("@odla-ai/crm");
583
+ var import_crm2 = require("@odla-ai/crm");
496
584
 
497
585
  // src/network-contract.ts
498
586
  var DEFAULT_SHARE_FIELDS = {
@@ -594,14 +682,14 @@ async function upsertPerson(deps, opts) {
594
682
  const { crm_record } = await deps.db.query({ crm_record: { $: { where: { type: "person", primaryEmail: email }, limit: 1 } } });
595
683
  const existing = crm_record?.[0];
596
684
  if (existing && typeof existing.id === "string") {
597
- await (0, import_crm.updateRecord)(crmDeps3, { id: existing.id, input: opts.input });
685
+ await (0, import_crm2.updateRecord)(crmDeps3, { id: existing.id, input: opts.input });
598
686
  return { recordId: existing.id };
599
687
  }
600
- const created = await (0, import_crm.createRecord)(crmDeps3, { type: "person", input: opts.input, mutationId: opts.mutationId });
688
+ const created = await (0, import_crm2.createRecord)(crmDeps3, { type: "person", input: opts.input, mutationId: opts.mutationId });
601
689
  return { recordId: created.id };
602
690
  }
603
691
  async function findSharedRecord(deps, record, tag) {
604
- const structured = await (0, import_crm.getRecordByOrigin)(
692
+ const structured = await (0, import_crm2.getRecordByOrigin)(
605
693
  { crm: deps.crm, db: deps.db, now: deps.now, newId: deps.newId },
606
694
  record.sourceId,
607
695
  record.sourceRecordId
@@ -653,11 +741,11 @@ async function projectSharedRecord(deps, shared, options = {}) {
653
741
  const existing = await findSharedRecord(deps, record, tag);
654
742
  let recordId;
655
743
  if (existing && typeof existing.id === "string") {
656
- await (0, import_crm.updateRecord)(crmDeps3, { id: existing.id, input: record.input });
744
+ await (0, import_crm2.updateRecord)(crmDeps3, { id: existing.id, input: record.input });
657
745
  recordId = existing.id;
658
746
  } else {
659
747
  recordId = `network_${shortHash(`${record.sourceId}\0${record.type}\0${record.sourceRecordId}`)}`;
660
- await (0, import_crm.createRecord)({ ...crmDeps3, newId: () => recordId }, {
748
+ await (0, import_crm2.createRecord)({ ...crmDeps3, newId: () => recordId }, {
661
749
  type: record.type,
662
750
  input: record.input,
663
751
  mutationId: `share-create:${tag}`
@@ -667,7 +755,7 @@ async function projectSharedRecord(deps, shared, options = {}) {
667
755
  [{ t: "update", ns: "crm_tag", id: tag, attrs: { key: `${recordId}:${tag}`, recordId, tag, createdAt: deps.now() } }],
668
756
  { mutationId: `share-map:${tag}:${recordId}` }
669
757
  );
670
- await (0, import_crm.upsertRecordOrigin)(crmDeps3, {
758
+ await (0, import_crm2.upsertRecordOrigin)(crmDeps3, {
671
759
  recordId,
672
760
  sourceId: record.sourceId,
673
761
  sourceRecordId: record.sourceRecordId,
@@ -982,7 +1070,7 @@ var handleCrm = async (req, url, env, ctx) => {
982
1070
  const crmBase = ctx.crmBase;
983
1071
  if (url.pathname !== crmBase && !url.pathname.startsWith(crmBase + "/")) return null;
984
1072
  const db = ctx.makeDb(env);
985
- const routes = (0, import_crm2.createCrmRoutes)({
1073
+ const routes = (0, import_crm3.createCrmRoutes)({
986
1074
  crm: ctx.chapter.crm,
987
1075
  db,
988
1076
  authorize: async (r) => {
@@ -1012,7 +1100,15 @@ var handleMember = async (req, url, env, ctx) => {
1012
1100
  if (!group) return json({ error: "not found" }, 404);
1013
1101
  const stripeKey = await getVaultSecret(db, "stripe_secret_key");
1014
1102
  const paymentsReady = Boolean(group.stripePublishableKey && group.stripePriceId && stripeKey);
1015
- return json({ ...joinConfig(group, paymentsReady), copy: chapter.copy.join });
1103
+ const offered = await loadOfferableTiers(
1104
+ db,
1105
+ group,
1106
+ Boolean(stripeKey)
1107
+ );
1108
+ return json({
1109
+ ...joinConfig(group, paymentsReady, joinConfigTiers(offered), chapter.application.conditions),
1110
+ copy: chapter.copy.join
1111
+ });
1016
1112
  }
1017
1113
  if (req.method === "GET" && url.pathname === "/api/join/resume") {
1018
1114
  const applicationId = url.searchParams.get("application") ?? "";
@@ -1051,9 +1147,11 @@ var handleMember = async (req, url, env, ctx) => {
1051
1147
  const group = Array.isArray(groups) ? groups[0] : void 0;
1052
1148
  if (!group) return json({ error: "not found" }, 404);
1053
1149
  const stripeKey = await getVaultSecret(db, "stripe_secret_key");
1054
- const paymentsReady = Boolean(group.stripePublishableKey && group.stripePriceId && stripeKey);
1055
1150
  const status = String(app.status ?? "");
1056
- if (!paymentsReady) return json({ state: "booking", applicationId });
1151
+ const offered = await loadOfferableTiers(db, group, Boolean(stripeKey));
1152
+ const tier = findTier(offered, typeof app.tierId === "string" ? app.tierId : null);
1153
+ const payable = Boolean(tier) && !tierIsFree(tier) && tierPayable(tier, group, Boolean(stripeKey));
1154
+ if (!payable) return json({ state: "booking", applicationId });
1057
1155
  if (status === chapter.pipeline.initial && app.stripeSubscriptionId) {
1058
1156
  return json({ state: "paymentPending", applicationId });
1059
1157
  }
@@ -1072,11 +1170,13 @@ var handleMember = async (req, url, env, ctx) => {
1072
1170
  }
1073
1171
  const submissionId = typeof parsed.submissionId === "string" ? parsed.submissionId : void 0;
1074
1172
  const db = ctx.makeDb(env);
1173
+ const offeredTierIds = typeof parsed.tierId === "string" && parsed.tierId ? (await loadTiers(db, { id: chapter.id })).map((tier) => tier.id) : void 0;
1075
1174
  const result = await submitApplication(db, chapter, parsed, {
1076
1175
  submissionId,
1077
1176
  groupId: chapter.id,
1078
1177
  now: Date.now(),
1079
- newId: () => crypto.randomUUID()
1178
+ newId: () => crypto.randomUUID(),
1179
+ ...offeredTierIds ? { tierIds: offeredTierIds } : {}
1080
1180
  });
1081
1181
  if (!result.ok) return json({ error: result.error }, 400);
1082
1182
  if (!result.duplicate) {
@@ -1154,7 +1254,7 @@ var handleNetworkShared = async (req, url, env, ctx) => {
1154
1254
  };
1155
1255
 
1156
1256
  // src/crm-sync.ts
1157
- var import_crm3 = require("@odla-ai/crm");
1257
+ var import_crm4 = require("@odla-ai/crm");
1158
1258
  var str = (v) => typeof v === "string" ? v : v == null ? "" : String(v);
1159
1259
  var crmDeps = (db, ctx) => ({
1160
1260
  crm: ctx.chapter.crm,
@@ -1201,16 +1301,16 @@ async function syncApplicationToCrm(deps, opts) {
1201
1301
  let recordId;
1202
1302
  if (existing && typeof existing.id === "string") {
1203
1303
  recordId = existing.id;
1204
- await (0, import_crm3.updateRecord)(recordDeps, { id: recordId, input });
1304
+ await (0, import_crm4.updateRecord)(recordDeps, { id: recordId, input });
1205
1305
  } else {
1206
- const created = await (0, import_crm3.createRecord)(recordDeps, { type: "person", input, ...stage ? { stage } : {} });
1306
+ const created = await (0, import_crm4.createRecord)(recordDeps, { type: "person", input, ...stage ? { stage } : {} });
1207
1307
  recordId = created.id;
1208
1308
  }
1209
1309
  if (existing && stage && existing.stage !== stage) {
1210
- await (0, import_crm3.setStage)(recordDeps, { id: recordId, to: stage, authorId: "system", mutationId: `crm:stage:${recordId}:${stage}` }).catch(() => void 0);
1310
+ await (0, import_crm4.setStage)(recordDeps, { id: recordId, to: stage, authorId: "system", mutationId: `crm:stage:${recordId}:${stage}` }).catch(() => void 0);
1211
1311
  }
1212
1312
  await deps.db.transact([{ t: "update", ns: "crm_record", id: recordId, attrs: billingColumns(opts.app) }]);
1213
- await (0, import_crm3.linkIdentity)(recordDeps, { recordId, email: emailKey, mutationId: `crm:link:${recordId}:${emailKey}` }).catch(() => void 0);
1313
+ await (0, import_crm4.linkIdentity)(recordDeps, { recordId, email: emailKey, mutationId: `crm:link:${recordId}:${emailKey}` }).catch(() => void 0);
1214
1314
  return recordId;
1215
1315
  }
1216
1316
  async function backfillCrm(deps) {
@@ -1660,9 +1760,16 @@ async function startSubscription(req, env, ctx) {
1660
1760
  if (!app) return json({ error: "not found" }, 404);
1661
1761
  if (app.status !== "submitted") return json({ error: "already processed" }, 409);
1662
1762
  const group = await firstRow2(db, "groups", { where: { id: String(app.groupId ?? ctx.chapter.id) }, limit: 1 });
1663
- const priceId = group?.stripePriceId;
1664
1763
  const secretKey = await getVaultSecret(db, "stripe_secret_key");
1665
- if (!group || !priceId || !secretKey) return json({ error: "payments not configured" }, 503);
1764
+ if (!group || !secretKey) return json({ error: "payments not configured" }, 503);
1765
+ const tier = findTier(
1766
+ await loadTiers(db, group),
1767
+ typeof app.tierId === "string" ? app.tierId : null
1768
+ );
1769
+ if (!tier) return json({ error: "tier not found", code: "tier_unresolved" }, 400);
1770
+ if (tierIsFree(tier)) return json({ error: "tier is free", code: "tier_not_payable" }, 409);
1771
+ const priceId = tier.stripePriceId;
1772
+ if (!priceId) return json({ error: "payments not configured" }, 503);
1666
1773
  const provider = createStripeProvider({ secretKey });
1667
1774
  let result;
1668
1775
  try {
@@ -2637,7 +2744,7 @@ var handleAdminComms = async (req, url, env, ctx) => {
2637
2744
  };
2638
2745
 
2639
2746
  // src/worker-routes-network.ts
2640
- var import_crm5 = require("@odla-ai/crm");
2747
+ var import_crm6 = require("@odla-ai/crm");
2641
2748
  var import_db4 = require("@odla-ai/db");
2642
2749
 
2643
2750
  // src/worker-network-fetch.ts
@@ -2655,7 +2762,7 @@ function fetchNetworkTarget(env, target, destination, init) {
2655
2762
  }
2656
2763
 
2657
2764
  // src/worker-network-push.ts
2658
- var import_crm4 = require("@odla-ai/crm");
2765
+ var import_crm5 = require("@odla-ai/crm");
2659
2766
  var import_db3 = require("@odla-ai/db");
2660
2767
  async function pushNetworkRecord(db, env, ctx, target, record) {
2661
2768
  const secret = await getVaultSecret(db, target.secretName);
@@ -2667,7 +2774,7 @@ async function pushNetworkRecord(db, env, ctx, target, record) {
2667
2774
  };
2668
2775
  if (!secret) {
2669
2776
  const error = `vault secret "${target.secretName}" is missing`;
2670
- await (0, import_crm4.recordDeliveryAttempt)(crmDeps3, {
2777
+ await (0, import_crm5.recordDeliveryAttempt)(crmDeps3, {
2671
2778
  recordId: record.id,
2672
2779
  targetId: target.id,
2673
2780
  status: "failed",
@@ -2706,7 +2813,7 @@ async function pushNetworkRecord(db, env, ctx, target, record) {
2706
2813
  const responseBody = await res.json().catch(() => ({}));
2707
2814
  if (!res.ok) {
2708
2815
  const error = responseBody.error ?? "follower rejected the record";
2709
- await (0, import_crm4.recordDeliveryAttempt)(crmDeps3, {
2816
+ await (0, import_crm5.recordDeliveryAttempt)(crmDeps3, {
2710
2817
  recordId: record.id,
2711
2818
  targetId: target.id,
2712
2819
  status: "failed",
@@ -2721,7 +2828,7 @@ async function pushNetworkRecord(db, env, ctx, target, record) {
2721
2828
  error
2722
2829
  };
2723
2830
  }
2724
- await (0, import_crm4.recordDeliveryAttempt)(crmDeps3, {
2831
+ await (0, import_crm5.recordDeliveryAttempt)(crmDeps3, {
2725
2832
  recordId: record.id,
2726
2833
  targetId: target.id,
2727
2834
  status: "delivered",
@@ -2737,7 +2844,7 @@ async function pushNetworkRecord(db, env, ctx, target, record) {
2737
2844
  };
2738
2845
  } catch (err) {
2739
2846
  const error = err instanceof Error ? err.message : "delivery failed";
2740
- await (0, import_crm4.recordDeliveryAttempt)(crmDeps3, {
2847
+ await (0, import_crm5.recordDeliveryAttempt)(crmDeps3, {
2741
2848
  recordId: record.id,
2742
2849
  targetId: target.id,
2743
2850
  status: "failed",
@@ -2778,7 +2885,7 @@ var handleNetworkSnapshot = async (req, url, env, ctx) => {
2778
2885
  const verified = await (0, import_db4.verifyFederatedRequest)(req, { secret });
2779
2886
  if (!verified.ok) return json({ error: "unauthorized", reason: verified.reason }, 401);
2780
2887
  const types = await Promise.all(
2781
- Object.keys(ctx.chapter.crm.config.types).map((type) => (0, import_crm5.typeSummary)({ crm: ctx.chapter.crm, db }, type))
2888
+ Object.keys(ctx.chapter.crm.config.types).map((type) => (0, import_crm6.typeSummary)({ crm: ctx.chapter.crm, db }, type))
2782
2889
  );
2783
2890
  const snapshot = {
2784
2891
  version: 1,
@@ -2876,7 +2983,7 @@ var handleAdminNetworkPush = async (req, url, env, ctx) => {
2876
2983
  if (requested.size !== body.targetIds.length) return json({ error: "targetIds must contain unique strings" }, 400);
2877
2984
  const targets = ctx.chapter.network.targets.filter((target) => requested.has(target.id));
2878
2985
  if (targets.length !== requested.size) return json({ error: "one or more targetIds are not configured" }, 400);
2879
- const record = await (0, import_crm5.getRecord)({ crm: ctx.chapter.crm, db: got.db }, body.recordId);
2986
+ const record = await (0, import_crm6.getRecord)({ crm: ctx.chapter.crm, db: got.db }, body.recordId);
2880
2987
  if (!record) return json({ error: "record not found" }, 404);
2881
2988
  const results = await Promise.all(
2882
2989
  targets.map((target) => pushNetworkRecord(got.db, env, ctx, target, record))
@@ -2885,7 +2992,7 @@ var handleAdminNetworkPush = async (req, url, env, ctx) => {
2885
2992
  };
2886
2993
 
2887
2994
  // src/worker-routes-network-records.ts
2888
- var import_crm6 = require("@odla-ai/crm");
2995
+ var import_crm7 = require("@odla-ai/crm");
2889
2996
  var import_db5 = require("@odla-ai/db");
2890
2997
  var IDENTIFIER = /^[a-z][a-zA-Z0-9_]*$/;
2891
2998
  var MAX_PAGE = 50;
@@ -2939,7 +3046,7 @@ var handleNetworkRecords = async (req, url, env, ctx) => {
2939
3046
  if (limit == null || offset == null || search.length > MAX_SEARCH) {
2940
3047
  return json({ error: "invalid pagination or search parameters" }, 400);
2941
3048
  }
2942
- const page = await (0, import_crm6.listRecords)(
3049
+ const page = await (0, import_crm7.listRecords)(
2943
3050
  { crm: ctx.chapter.crm, db },
2944
3051
  {
2945
3052
  type,
@@ -3103,7 +3210,7 @@ var handleAdminNetworkNotes = async (req, url, env, ctx) => {
3103
3210
  };
3104
3211
 
3105
3212
  // src/worker-routes-network-shared-notes.ts
3106
- var import_crm7 = require("@odla-ai/crm");
3213
+ var import_crm8 = require("@odla-ai/crm");
3107
3214
  var import_db6 = require("@odla-ai/db");
3108
3215
  var IDENTIFIER3 = /^[a-z][a-zA-Z0-9_]*$/;
3109
3216
  var RECORD_ID2 = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,255}$/;
@@ -3133,7 +3240,7 @@ function sharedNote(activity, sourceId) {
3133
3240
  }
3134
3241
  async function listSharedNotes(db, sourceId, recordId) {
3135
3242
  const result = await db.query({
3136
- [import_crm7.CRM_NS.activity]: {
3243
+ [import_crm8.CRM_NS.activity]: {
3137
3244
  $: {
3138
3245
  where: {
3139
3246
  and: [
@@ -3146,7 +3253,7 @@ async function listSharedNotes(db, sourceId, recordId) {
3146
3253
  }
3147
3254
  }
3148
3255
  });
3149
- return (result[import_crm7.CRM_NS.activity] ?? []).flatMap((activity) => {
3256
+ return (result[import_crm8.CRM_NS.activity] ?? []).flatMap((activity) => {
3150
3257
  const note = sharedNote(activity, sourceId);
3151
3258
  return note ? [note] : [];
3152
3259
  });
@@ -3174,7 +3281,7 @@ var handleNetworkSharedNotes = async (req, url, env, ctx) => {
3174
3281
  if (!IDENTIFIER3.test(recordType) || !RECORD_ID2.test(recordId) || !reader?.sharedNotes.includes(recordType)) {
3175
3282
  return json({ error: "shared notes are not enabled for this reader and record type" }, 403);
3176
3283
  }
3177
- const record = await (0, import_crm7.getRecord)({ crm: ctx.chapter.crm, db }, recordId);
3284
+ const record = await (0, import_crm8.getRecord)({ crm: ctx.chapter.crm, db }, recordId);
3178
3285
  if (!record || record.type !== recordType) return json({ error: "record not found" }, 404);
3179
3286
  if (req.method === "GET") {
3180
3287
  return json({
@@ -3196,7 +3303,7 @@ var handleNetworkSharedNotes = async (req, url, env, ctx) => {
3196
3303
  }
3197
3304
  const createdAt = Date.now();
3198
3305
  const id = `network:${verified.sender}:${mutationId}`;
3199
- const result = await (0, import_crm7.addActivity)(
3306
+ const result = await (0, import_crm8.addActivity)(
3200
3307
  {
3201
3308
  crm: ctx.chapter.crm,
3202
3309
  db,
@@ -3287,7 +3394,7 @@ var handleAdminNetworkSharedNotes = async (req, url, env, ctx) => {
3287
3394
  };
3288
3395
 
3289
3396
  // src/worker-routes-formation.ts
3290
- var import_crm8 = require("@odla-ai/crm");
3397
+ var import_crm9 = require("@odla-ai/crm");
3291
3398
 
3292
3399
  // src/formation.ts
3293
3400
  function formationFields(crm, formation) {
@@ -3353,7 +3460,7 @@ var handleFormation = async (req, url, env, ctx) => {
3353
3460
  const db = ctx.makeDb(env);
3354
3461
  const id = submissionId ? await applicationIdForSubmission(`formation:${ctx.chapter.id}:${submissionId}`) : crypto.randomUUID();
3355
3462
  try {
3356
- const created = await (0, import_crm8.createRecord)(
3463
+ const created = await (0, import_crm9.createRecord)(
3357
3464
  {
3358
3465
  crm: ctx.chapter.crm,
3359
3466
  db,