@odla-ai/chapter 0.30.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.
- package/dist/chunk-IVXVECKR.js +15 -0
- package/dist/chunk-IVXVECKR.js.map +1 -0
- package/dist/{chunk-IOHVFBXH.js → chunk-QWMP6TSM.js} +75 -34
- package/dist/chunk-QWMP6TSM.js.map +1 -0
- package/dist/{copy-context-efEMF_aD.d.ts → copy-context-HAhNTZdl.d.ts} +54 -19
- package/dist/index.cjs +168 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +160 -21
- package/dist/index.d.ts +160 -21
- package/dist/index.js +150 -2
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +2 -2
- package/dist/ui/conditions/index.d.ts +29 -0
- package/dist/ui/conditions/index.js +32 -0
- package/dist/ui/conditions/index.js.map +1 -0
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.js +10 -3
- package/dist/ui/member/index.d.ts +62 -3
- package/dist/ui/member/index.js +10 -3
- package/dist/worker/index.cjs +146 -39
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +54 -19
- package/dist/worker/index.d.ts +54 -19
- package/dist/worker/index.js +115 -8
- package/dist/worker/index.js.map +1 -1
- package/package.json +6 -2
- package/dist/chunk-IOHVFBXH.js.map +0 -1
package/dist/worker/index.cjs
CHANGED
|
@@ -136,7 +136,7 @@ function createWorkerContext(options) {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
// src/worker-routes.ts
|
|
139
|
-
var
|
|
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
|
-
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
1304
|
+
await (0, import_crm4.updateRecord)(recordDeps, { id: recordId, input });
|
|
1205
1305
|
} else {
|
|
1206
|
-
const created = await (0,
|
|
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,
|
|
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,
|
|
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 || !
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
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
|
-
[
|
|
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[
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
3463
|
+
const created = await (0, import_crm9.createRecord)(
|
|
3357
3464
|
{
|
|
3358
3465
|
crm: ctx.chapter.crm,
|
|
3359
3466
|
db,
|