@odla-ai/chapter 0.47.1 → 0.47.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.
- package/dist/worker/index.cjs +113 -26
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.js +110 -17
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
package/dist/worker/index.cjs
CHANGED
|
@@ -6117,7 +6117,7 @@ var handleAdminNetworkPush = async (req, url, env, ctx) => {
|
|
|
6117
6117
|
};
|
|
6118
6118
|
|
|
6119
6119
|
// src/worker-routes-network-records-follower.ts
|
|
6120
|
-
var
|
|
6120
|
+
var import_crm10 = require("@odla-ai/crm");
|
|
6121
6121
|
var import_db9 = require("@odla-ai/db");
|
|
6122
6122
|
|
|
6123
6123
|
// src/worker-routes-network-records-common.ts
|
|
@@ -6212,6 +6212,85 @@ function restrictedRecord(record4, target) {
|
|
|
6212
6212
|
return { ...record4, ...edit ? { edit } : { edit: void 0 } };
|
|
6213
6213
|
}
|
|
6214
6214
|
|
|
6215
|
+
// src/worker-routes-network-records-search.ts
|
|
6216
|
+
var import_crm9 = require("@odla-ai/crm");
|
|
6217
|
+
var SEARCH_BATCH_SIZE = 1e3;
|
|
6218
|
+
var MAX_READER_SEARCH_POPULATION = 1e4;
|
|
6219
|
+
var ReaderSearchPopulationError = class extends Error {
|
|
6220
|
+
count;
|
|
6221
|
+
constructor(count) {
|
|
6222
|
+
super(`reader-visible search population exceeds ${MAX_READER_SEARCH_POPULATION} records`);
|
|
6223
|
+
this.name = "ReaderSearchPopulationError";
|
|
6224
|
+
this.count = count;
|
|
6225
|
+
}
|
|
6226
|
+
};
|
|
6227
|
+
function folded(value) {
|
|
6228
|
+
return value.replace(/[øØ]/gu, "o").replace(/[łŁ]/gu, "l").replace(/[đĐðÐ]/gu, "d").replace(/[æÆ]/gu, "ae").replace(/[œŒ]/gu, "oe").replace(/[þÞ]/gu, "th").replace(/ß/gu, "ss").normalize("NFKD").replace(/\p{M}/gu, "").toLocaleLowerCase("en-US").replace(/[^\p{L}\p{N}@._+-]+/gu, " ").trim();
|
|
6229
|
+
}
|
|
6230
|
+
function terms(value) {
|
|
6231
|
+
return folded(value).split(/\s+/u).filter(Boolean);
|
|
6232
|
+
}
|
|
6233
|
+
function matchesReaderIdentity(record4, search, includeEmail) {
|
|
6234
|
+
const query = terms(search);
|
|
6235
|
+
if (!query.length) return true;
|
|
6236
|
+
const name = folded(record4.name);
|
|
6237
|
+
const visible = [name, ...name.split(/\s+/u).filter(Boolean)];
|
|
6238
|
+
if (includeEmail && record4.primaryEmail) visible.push(folded(record4.primaryEmail));
|
|
6239
|
+
return query.every((term) => visible.some((candidate) => candidate.includes(term)));
|
|
6240
|
+
}
|
|
6241
|
+
function baseWhere(type, stage) {
|
|
6242
|
+
return {
|
|
6243
|
+
and: [
|
|
6244
|
+
{ type },
|
|
6245
|
+
{ archived: false },
|
|
6246
|
+
...stage ? [{ stage }] : []
|
|
6247
|
+
]
|
|
6248
|
+
};
|
|
6249
|
+
}
|
|
6250
|
+
async function listVisibleSearchPopulation(db, where, window, count) {
|
|
6251
|
+
if (count > MAX_READER_SEARCH_POPULATION) throw new ReaderSearchPopulationError(count);
|
|
6252
|
+
const offsets = Array.from(
|
|
6253
|
+
{ length: Math.ceil(count / SEARCH_BATCH_SIZE) },
|
|
6254
|
+
(_, index2) => index2 * SEARCH_BATCH_SIZE
|
|
6255
|
+
);
|
|
6256
|
+
const pages = await Promise.all(offsets.map((offset) => db.query({
|
|
6257
|
+
[import_crm9.CRM_NS.record]: { $: {
|
|
6258
|
+
where,
|
|
6259
|
+
order: { [window.sort.field]: window.sort.dir },
|
|
6260
|
+
limit: Math.min(SEARCH_BATCH_SIZE, count - offset),
|
|
6261
|
+
offset
|
|
6262
|
+
} }
|
|
6263
|
+
})));
|
|
6264
|
+
return pages.flatMap((page) => (page[import_crm9.CRM_NS.record] ?? []).map(import_crm9.rowToRecord));
|
|
6265
|
+
}
|
|
6266
|
+
async function listReaderRecords(db, type, allowed2, emailField, window) {
|
|
6267
|
+
const where = baseWhere(type, window.stage);
|
|
6268
|
+
const crmDb = db;
|
|
6269
|
+
const aggregate = await crmDb.aggregate(import_crm9.CRM_NS.record, { count: true }, { where });
|
|
6270
|
+
const candidateCount = aggregate.count ?? 0;
|
|
6271
|
+
if (window.search) {
|
|
6272
|
+
const population = await listVisibleSearchPopulation(crmDb, where, window, candidateCount);
|
|
6273
|
+
const includeEmail = Boolean(emailField && allowed2.includes(emailField));
|
|
6274
|
+
const matches = population.filter((record4) => matchesReaderIdentity(record4, window.search, includeEmail));
|
|
6275
|
+
return {
|
|
6276
|
+
records: matches.slice(window.offset, window.offset + window.limit),
|
|
6277
|
+
total: matches.length
|
|
6278
|
+
};
|
|
6279
|
+
}
|
|
6280
|
+
const result = await crmDb.query({
|
|
6281
|
+
[import_crm9.CRM_NS.record]: { $: {
|
|
6282
|
+
where,
|
|
6283
|
+
order: { [window.sort.field]: window.sort.dir },
|
|
6284
|
+
limit: window.limit,
|
|
6285
|
+
offset: window.offset
|
|
6286
|
+
} }
|
|
6287
|
+
});
|
|
6288
|
+
return {
|
|
6289
|
+
records: (result[import_crm9.CRM_NS.record] ?? []).map(import_crm9.rowToRecord),
|
|
6290
|
+
total: candidateCount
|
|
6291
|
+
};
|
|
6292
|
+
}
|
|
6293
|
+
|
|
6215
6294
|
// src/worker-routes-network-records-follower.ts
|
|
6216
6295
|
var NETWORK_MUTATION_META = "chapterNetworkMutation";
|
|
6217
6296
|
function mutationFingerprint(input) {
|
|
@@ -6231,16 +6310,16 @@ function mutationError(error) {
|
|
|
6231
6310
|
if (error?.code === "transact_guard_failed") {
|
|
6232
6311
|
return json({ error: "record changed since it was reviewed", code: "stale_revision" }, 409);
|
|
6233
6312
|
}
|
|
6234
|
-
if (error instanceof
|
|
6313
|
+
if (error instanceof import_crm10.CrmInputError) {
|
|
6235
6314
|
return json({ error: error.message, code: "invalid_transition_or_fields", ...error.fields ? { fields: error.fields } : {} }, 422);
|
|
6236
6315
|
}
|
|
6237
6316
|
return json({ error: "follower mutation failed", code: "mutation_failed" }, 500);
|
|
6238
6317
|
}
|
|
6239
6318
|
async function priorMutation(db, id) {
|
|
6240
6319
|
const result = await db.query({
|
|
6241
|
-
[
|
|
6320
|
+
[import_crm10.CRM_NS.activity]: { $: { where: { id }, limit: 1 } }
|
|
6242
6321
|
});
|
|
6243
|
-
const row = (result[
|
|
6322
|
+
const row = (result[import_crm10.CRM_NS.activity] ?? [])[0];
|
|
6244
6323
|
const meta = row?.meta;
|
|
6245
6324
|
const receipt = meta?.[NETWORK_MUTATION_META];
|
|
6246
6325
|
return typeof receipt?.fingerprint === "string" ? { fingerprint: receipt.fingerprint } : null;
|
|
@@ -6294,7 +6373,7 @@ var handleNetworkRecords = async (req, url, env, ctx) => {
|
|
|
6294
6373
|
if (prior.fingerprint !== fingerprint) {
|
|
6295
6374
|
return json({ error: "mutationId was already used for different input", code: "mutation_conflict" }, 409);
|
|
6296
6375
|
}
|
|
6297
|
-
const replayed = await (0,
|
|
6376
|
+
const replayed = await (0, import_crm10.getRecord)({ crm: ctx.chapter.crm, db }, input.recordId);
|
|
6298
6377
|
if (!replayed || replayed.type !== input.type) return json({ error: "record not found", code: "not_found" }, 404);
|
|
6299
6378
|
const result = {
|
|
6300
6379
|
version: 1,
|
|
@@ -6304,7 +6383,7 @@ var handleNetworkRecords = async (req, url, env, ctx) => {
|
|
|
6304
6383
|
};
|
|
6305
6384
|
return json(result);
|
|
6306
6385
|
}
|
|
6307
|
-
const record4 = await (0,
|
|
6386
|
+
const record4 = await (0, import_crm10.getRecord)({ crm: ctx.chapter.crm, db }, input.recordId);
|
|
6308
6387
|
if (!record4 || record4.type !== input.type) return json({ error: "record not found", code: "not_found" }, 404);
|
|
6309
6388
|
if (record4.updatedAt !== input.expectedRevision) {
|
|
6310
6389
|
return json({ error: "record changed since it was reviewed", code: "stale_revision" }, 409);
|
|
@@ -6325,7 +6404,7 @@ var handleNetworkRecords = async (req, url, env, ctx) => {
|
|
|
6325
6404
|
};
|
|
6326
6405
|
try {
|
|
6327
6406
|
const deps2 = { crm: ctx.chapter.crm, db };
|
|
6328
|
-
const updated = hasFields ? await (0,
|
|
6407
|
+
const updated = hasFields ? await (0, import_crm10.updateRecord)(deps2, {
|
|
6329
6408
|
id: record4.id,
|
|
6330
6409
|
input: fields,
|
|
6331
6410
|
mutationId: activityId,
|
|
@@ -6336,7 +6415,7 @@ var handleNetworkRecords = async (req, url, env, ctx) => {
|
|
|
6336
6415
|
authorId: `network:${verified.sender}`,
|
|
6337
6416
|
meta: auditMeta
|
|
6338
6417
|
}
|
|
6339
|
-
}) : await (0,
|
|
6418
|
+
}) : await (0, import_crm10.setStage)(deps2, {
|
|
6340
6419
|
id: record4.id,
|
|
6341
6420
|
to: input.stage,
|
|
6342
6421
|
authorId: `network:${verified.sender}`,
|
|
@@ -6367,25 +6446,33 @@ var handleNetworkRecords = async (req, url, env, ctx) => {
|
|
|
6367
6446
|
if (window.stage && !stages.some((stage) => stage.id === window.stage)) {
|
|
6368
6447
|
return json({ error: "stage is not defined for this record type" }, 400);
|
|
6369
6448
|
}
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6449
|
+
let page;
|
|
6450
|
+
try {
|
|
6451
|
+
page = await listReaderRecords(
|
|
6452
|
+
db,
|
|
6373
6453
|
type,
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
|
|
6454
|
+
allowed2,
|
|
6455
|
+
typeDef.emailField,
|
|
6456
|
+
window
|
|
6457
|
+
);
|
|
6458
|
+
} catch (error) {
|
|
6459
|
+
if (error instanceof ReaderSearchPopulationError) {
|
|
6460
|
+
return json({
|
|
6461
|
+
error: "directory search requires a narrower stage filter",
|
|
6462
|
+
code: "search_population_too_large",
|
|
6463
|
+
maximum: 1e4
|
|
6464
|
+
}, 422);
|
|
6379
6465
|
}
|
|
6380
|
-
|
|
6466
|
+
throw error;
|
|
6467
|
+
}
|
|
6381
6468
|
const response = {
|
|
6382
6469
|
version: 1,
|
|
6383
6470
|
site: { id: ctx.chapter.id, name: ctx.chapter.name },
|
|
6384
6471
|
type,
|
|
6385
6472
|
records: page.records.map((record4) => readerRecord(record4, reader, ctx.chapter.crm)),
|
|
6386
6473
|
total: page.total,
|
|
6387
|
-
limit:
|
|
6388
|
-
offset:
|
|
6474
|
+
limit: window.limit,
|
|
6475
|
+
offset: window.offset,
|
|
6389
6476
|
filters: {
|
|
6390
6477
|
stages: stages.map((stage) => ({ id: stage.id, label: stage.label ?? stage.id })),
|
|
6391
6478
|
sorts: [...NETWORK_RECORD_SORTS]
|
|
@@ -6621,7 +6708,7 @@ var handleAdminNetworkNotes = async (req, url, env, ctx) => {
|
|
|
6621
6708
|
};
|
|
6622
6709
|
|
|
6623
6710
|
// src/worker-routes-network-shared-notes.ts
|
|
6624
|
-
var
|
|
6711
|
+
var import_crm11 = require("@odla-ai/crm");
|
|
6625
6712
|
var import_db11 = require("@odla-ai/db");
|
|
6626
6713
|
var IDENTIFIER3 = /^[a-z][a-zA-Z0-9_]*$/;
|
|
6627
6714
|
var RECORD_ID3 = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,255}$/;
|
|
@@ -6651,7 +6738,7 @@ function sharedNote(activity, sourceId) {
|
|
|
6651
6738
|
}
|
|
6652
6739
|
async function listSharedNotes(db, sourceId, recordId) {
|
|
6653
6740
|
const result = await db.query({
|
|
6654
|
-
[
|
|
6741
|
+
[import_crm11.CRM_NS.activity]: {
|
|
6655
6742
|
$: {
|
|
6656
6743
|
where: {
|
|
6657
6744
|
and: [
|
|
@@ -6664,7 +6751,7 @@ async function listSharedNotes(db, sourceId, recordId) {
|
|
|
6664
6751
|
}
|
|
6665
6752
|
}
|
|
6666
6753
|
});
|
|
6667
|
-
return (result[
|
|
6754
|
+
return (result[import_crm11.CRM_NS.activity] ?? []).flatMap((activity) => {
|
|
6668
6755
|
const note = sharedNote(activity, sourceId);
|
|
6669
6756
|
return note ? [note] : [];
|
|
6670
6757
|
});
|
|
@@ -6692,7 +6779,7 @@ var handleNetworkSharedNotes = async (req, url, env, ctx) => {
|
|
|
6692
6779
|
if (!IDENTIFIER3.test(recordType) || !RECORD_ID3.test(recordId) || !reader?.sharedNotes.includes(recordType)) {
|
|
6693
6780
|
return json({ error: "shared notes are not enabled for this reader and record type" }, 403);
|
|
6694
6781
|
}
|
|
6695
|
-
const record4 = await (0,
|
|
6782
|
+
const record4 = await (0, import_crm11.getRecord)({ crm: ctx.chapter.crm, db }, recordId);
|
|
6696
6783
|
if (!record4 || record4.type !== recordType) return json({ error: "record not found" }, 404);
|
|
6697
6784
|
if (req.method === "GET") {
|
|
6698
6785
|
return json({
|
|
@@ -6714,7 +6801,7 @@ var handleNetworkSharedNotes = async (req, url, env, ctx) => {
|
|
|
6714
6801
|
}
|
|
6715
6802
|
const createdAt = Date.now();
|
|
6716
6803
|
const id = `network:${verified.sender}:${mutationId}`;
|
|
6717
|
-
const result = await (0,
|
|
6804
|
+
const result = await (0, import_crm11.addActivity)(
|
|
6718
6805
|
{
|
|
6719
6806
|
crm: ctx.chapter.crm,
|
|
6720
6807
|
db,
|
|
@@ -8287,7 +8374,7 @@ var handleAdminNetworkCommercialReadModel = async (req, url, env, ctx) => {
|
|
|
8287
8374
|
};
|
|
8288
8375
|
|
|
8289
8376
|
// src/worker-routes-formation.ts
|
|
8290
|
-
var
|
|
8377
|
+
var import_crm12 = require("@odla-ai/crm");
|
|
8291
8378
|
var SUBMISSION = /^[A-Za-z0-9_-]{8,128}$/;
|
|
8292
8379
|
var handleFormation = async (req, url, env, ctx) => {
|
|
8293
8380
|
const formation = ctx.chapter.formation;
|
|
@@ -8339,7 +8426,7 @@ var handleFormation = async (req, url, env, ctx) => {
|
|
|
8339
8426
|
const db = ctx.makeDb(env);
|
|
8340
8427
|
const id = submissionId ? await applicationIdForSubmission(`formation:${ctx.chapter.id}:${submissionId}`) : crypto.randomUUID();
|
|
8341
8428
|
try {
|
|
8342
|
-
const created = await (0,
|
|
8429
|
+
const created = await (0, import_crm12.createRecord)(
|
|
8343
8430
|
{
|
|
8344
8431
|
crm: ctx.chapter.crm,
|
|
8345
8432
|
db,
|