@odla-ai/chapter 0.42.1 → 0.42.2
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/README.md +13 -1
- package/dist/{chunk-MMDWXTJU.js → chunk-HWUTCXBV.js} +44 -1
- package/dist/chunk-HWUTCXBV.js.map +1 -0
- package/dist/{copy-context-BNUzbL5g.d.ts → copy-context-BBPsYe24.d.ts} +9 -1
- package/dist/index.cjs +88 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -2
- package/dist/index.d.ts +10 -2
- package/dist/index.js +88 -10
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +14 -3
- package/dist/ui/admin/index.js +3 -1
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.js +3 -1
- package/dist/ui/member/index.d.ts +2 -2
- package/dist/worker/index.cjs +477 -144
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +55 -2
- package/dist/worker/index.d.ts +55 -2
- package/dist/worker/index.js +453 -120
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-MMDWXTJU.js.map +0 -1
|
@@ -193,6 +193,9 @@ interface ChapterNetworkTarget {
|
|
|
193
193
|
/** Record types on which this leader permits remote lifecycle transitions.
|
|
194
194
|
* The follower must independently opt in and remains pipeline authority. */
|
|
195
195
|
stageTransitions?: readonly string[];
|
|
196
|
+
/** Allow package-owned desired admission decisions for existing leader CRM
|
|
197
|
+
* people to be delivered to this target. Omitted means default deny. */
|
|
198
|
+
admissionGrants?: boolean;
|
|
196
199
|
}
|
|
197
200
|
/** One signed peer allowed to browse a privacy-bounded projection of this
|
|
198
201
|
* site's CRM. The follower owns this allowlist; a leader target declaration
|
|
@@ -202,7 +205,7 @@ interface ChapterNetworkReader {
|
|
|
202
205
|
id: string;
|
|
203
206
|
/** Per-record-type field allowlist. Omitted types and fields never leave
|
|
204
207
|
* this site. Record id, name, stage, and timestamps are bounded metadata. */
|
|
205
|
-
fields
|
|
208
|
+
fields?: Record<string, readonly string[]>;
|
|
206
209
|
/** Record types on which this reader may append an explicitly shared note.
|
|
207
210
|
* Omitted by default: browse permission never silently grants write access.
|
|
208
211
|
* Shared notes land in the follower CRM activity feed. */
|
|
@@ -214,6 +217,9 @@ interface ChapterNetworkReader {
|
|
|
214
217
|
/** Local CRM record types on which this reader may request a lifecycle
|
|
215
218
|
* transition. Chapter still enforces the local pipeline and gates. */
|
|
216
219
|
stageTransitions?: readonly string[];
|
|
220
|
+
/** Accept signed desired admission decisions from this reader. Independent
|
|
221
|
+
* of record browsing; an admission-only reader may omit `fields`. */
|
|
222
|
+
admissionGrants?: boolean;
|
|
217
223
|
}
|
|
218
224
|
/** Leader/follower network configuration. A follower needs no code config to
|
|
219
225
|
* receive pushed records. It must explicitly declare `readers` before any peer
|
|
@@ -258,6 +264,7 @@ interface ResolvedNetworkTarget {
|
|
|
258
264
|
sharedNotes: readonly string[];
|
|
259
265
|
editableFields: Record<string, readonly string[]>;
|
|
260
266
|
stageTransitions: readonly string[];
|
|
267
|
+
admissionGrants?: boolean;
|
|
261
268
|
}
|
|
262
269
|
/** A validated follower-owned record projection for one signed reader. */
|
|
263
270
|
interface ResolvedNetworkReader {
|
|
@@ -266,6 +273,7 @@ interface ResolvedNetworkReader {
|
|
|
266
273
|
sharedNotes: readonly string[];
|
|
267
274
|
editableFields: Record<string, readonly string[]>;
|
|
268
275
|
stageTransitions: readonly string[];
|
|
276
|
+
admissionGrants?: boolean;
|
|
269
277
|
}
|
|
270
278
|
/** Fully-resolved leader network configuration. */
|
|
271
279
|
interface ResolvedNetwork {
|
package/dist/index.cjs
CHANGED
|
@@ -486,6 +486,50 @@ var admissionGrantRevisionsEntity = {
|
|
|
486
486
|
receivedAt: attr2("number", { indexed: true })
|
|
487
487
|
}
|
|
488
488
|
};
|
|
489
|
+
var leaderAdmissionAssignmentsEntity = {
|
|
490
|
+
attrs: {
|
|
491
|
+
id: id(),
|
|
492
|
+
targetId: attr2("string", { indexed: true }),
|
|
493
|
+
personId: attr2("string", { indexed: true }),
|
|
494
|
+
grantId: attr2("string", { indexed: true }),
|
|
495
|
+
decision: attr2("string", { indexed: true }),
|
|
496
|
+
note: attr2("string", { optional: true }),
|
|
497
|
+
expiresAt: attr2("number", { optional: true, indexed: true }),
|
|
498
|
+
active: attr2("boolean", { indexed: true }),
|
|
499
|
+
lastMutationId: attr2("string", { indexed: true }),
|
|
500
|
+
lastRequestDigest: attr2("string"),
|
|
501
|
+
createdAt: attr2("number", { indexed: true }),
|
|
502
|
+
createdBy: attr2("string", { indexed: true }),
|
|
503
|
+
updatedAt: attr2("number", { indexed: true }),
|
|
504
|
+
updatedBy: attr2("string", { indexed: true })
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
var leaderAdmissionDeliveriesEntity = {
|
|
508
|
+
attrs: {
|
|
509
|
+
id: id(),
|
|
510
|
+
targetId: attr2("string", { indexed: true }),
|
|
511
|
+
environment: attr2("string", { indexed: true }),
|
|
512
|
+
revision: attr2("number", { indexed: true }),
|
|
513
|
+
digest: attr2("string", { indexed: true }),
|
|
514
|
+
envelope: attr2("json"),
|
|
515
|
+
status: attr2("string", { indexed: true }),
|
|
516
|
+
attempts: attr2("number", { indexed: true }),
|
|
517
|
+
lastAttemptAt: attr2("number", { optional: true, indexed: true }),
|
|
518
|
+
lastError: attr2("string", { optional: true }),
|
|
519
|
+
acknowledgedAt: attr2("number", { optional: true, indexed: true }),
|
|
520
|
+
updatedAt: attr2("number", { indexed: true })
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
var leaderAdmissionMutationsEntity = {
|
|
524
|
+
attrs: {
|
|
525
|
+
id: id(),
|
|
526
|
+
targetId: attr2("string", { indexed: true }),
|
|
527
|
+
personId: attr2("string", { indexed: true }),
|
|
528
|
+
requestDigest: attr2("string", { indexed: true }),
|
|
529
|
+
revision: attr2("number", { indexed: true }),
|
|
530
|
+
createdAt: attr2("number", { indexed: true })
|
|
531
|
+
}
|
|
532
|
+
};
|
|
489
533
|
|
|
490
534
|
// src/schema-gifts.ts
|
|
491
535
|
var attr3 = (type, flags = {}) => ({
|
|
@@ -757,7 +801,7 @@ var emailLog = {
|
|
|
757
801
|
sentAt: attr4("number", { indexed: true })
|
|
758
802
|
}
|
|
759
803
|
};
|
|
760
|
-
function chapterDb(mode, auth, includeNetworkNotes = false, application = resolveApplication(void 0), includeSignupControl = false, includeMemberContent = false, includeBuilderLibrary = false) {
|
|
804
|
+
function chapterDb(mode, auth, includeNetworkNotes = false, application = resolveApplication(void 0), includeSignupControl = false, includeMemberContent = false, includeBuilderLibrary = false, includeLeaderAdmissions = false) {
|
|
761
805
|
const entities = {};
|
|
762
806
|
if (mode === "chapter") {
|
|
763
807
|
entities.applications = applicationsFor(application);
|
|
@@ -785,6 +829,11 @@ function chapterDb(mode, auth, includeNetworkNotes = false, application = resolv
|
|
|
785
829
|
entities.builderLibraryControls = builderLibraryControls;
|
|
786
830
|
entities.builderLibraryLocal = builderLibraryLocal;
|
|
787
831
|
}
|
|
832
|
+
if (includeLeaderAdmissions) {
|
|
833
|
+
entities.leaderAdmissionAssignments = leaderAdmissionAssignmentsEntity;
|
|
834
|
+
entities.leaderAdmissionDeliveries = leaderAdmissionDeliveriesEntity;
|
|
835
|
+
entities.leaderAdmissionMutations = leaderAdmissionMutationsEntity;
|
|
836
|
+
}
|
|
788
837
|
const schema = { entities, links: {} };
|
|
789
838
|
const rules = {};
|
|
790
839
|
for (const ns of Object.keys(entities)) {
|
|
@@ -1591,6 +1640,13 @@ function validateStageTransitions(opts) {
|
|
|
1591
1640
|
throw new Error(`${opts.path}: must contain unique, readable CRM types with pipelines`);
|
|
1592
1641
|
}
|
|
1593
1642
|
}
|
|
1643
|
+
function validateAdmissionCapability(path, enabled, crm) {
|
|
1644
|
+
if (!enabled) return;
|
|
1645
|
+
const person = crm.config.types.person;
|
|
1646
|
+
if (!person?.emailField || person.fields[person.emailField]?.type !== "email") {
|
|
1647
|
+
throw new Error(`${path}: requires a CRM person type with an emailField`);
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1594
1650
|
function resolveNetwork(config, crm) {
|
|
1595
1651
|
const seen = /* @__PURE__ */ new Set();
|
|
1596
1652
|
const targets = [];
|
|
@@ -1664,6 +1720,11 @@ function resolveNetwork(config, crm) {
|
|
|
1664
1720
|
crm,
|
|
1665
1721
|
readable: readableFields
|
|
1666
1722
|
});
|
|
1723
|
+
validateAdmissionCapability(
|
|
1724
|
+
`defineChapter.network.targets.${target.id}.admissionGrants`,
|
|
1725
|
+
target.admissionGrants,
|
|
1726
|
+
crm
|
|
1727
|
+
);
|
|
1667
1728
|
targets.push({
|
|
1668
1729
|
id: target.id,
|
|
1669
1730
|
name: target.name?.trim() || target.id,
|
|
@@ -1673,7 +1734,8 @@ function resolveNetwork(config, crm) {
|
|
|
1673
1734
|
...fields ? { fields } : {},
|
|
1674
1735
|
sharedNotes,
|
|
1675
1736
|
editableFields,
|
|
1676
|
-
stageTransitions
|
|
1737
|
+
stageTransitions,
|
|
1738
|
+
...target.admissionGrants === true ? { admissionGrants: true } : {}
|
|
1677
1739
|
});
|
|
1678
1740
|
}
|
|
1679
1741
|
const readerIds = /* @__PURE__ */ new Set();
|
|
@@ -1686,9 +1748,12 @@ function resolveNetwork(config, crm) {
|
|
|
1686
1748
|
throw new Error(`defineChapter.network.readers: duplicate reader "${reader.id}"`);
|
|
1687
1749
|
}
|
|
1688
1750
|
readerIds.add(reader.id);
|
|
1689
|
-
const
|
|
1690
|
-
|
|
1691
|
-
|
|
1751
|
+
const readerFields = reader.fields ?? {};
|
|
1752
|
+
const entries = Object.entries(readerFields);
|
|
1753
|
+
if (entries.length === 0 && !reader.admissionGrants) {
|
|
1754
|
+
throw new Error(
|
|
1755
|
+
`defineChapter.network.readers.${reader.id}.fields: at least one CRM type is required unless this is an admission-only reader`
|
|
1756
|
+
);
|
|
1692
1757
|
}
|
|
1693
1758
|
for (const [type, names] of entries) {
|
|
1694
1759
|
if (!FIELD.test(type) || names.length === 0 || names.some((name) => !FIELD.test(name))) {
|
|
@@ -1718,23 +1783,35 @@ function resolveNetwork(config, crm) {
|
|
|
1718
1783
|
path: `defineChapter.network.readers.${reader.id}.sharedNotes`,
|
|
1719
1784
|
values: sharedNotes,
|
|
1720
1785
|
crm,
|
|
1721
|
-
fields:
|
|
1786
|
+
fields: readerFields
|
|
1722
1787
|
});
|
|
1723
1788
|
const editableFields = reader.editableFields ?? {};
|
|
1724
1789
|
validateEditableFields({
|
|
1725
1790
|
path: `defineChapter.network.readers.${reader.id}.editableFields`,
|
|
1726
1791
|
values: editableFields,
|
|
1727
1792
|
crm,
|
|
1728
|
-
readable:
|
|
1793
|
+
readable: readerFields
|
|
1729
1794
|
});
|
|
1730
1795
|
const stageTransitions = reader.stageTransitions ?? [];
|
|
1731
1796
|
validateStageTransitions({
|
|
1732
1797
|
path: `defineChapter.network.readers.${reader.id}.stageTransitions`,
|
|
1733
1798
|
values: stageTransitions,
|
|
1734
1799
|
crm,
|
|
1735
|
-
readable:
|
|
1800
|
+
readable: readerFields
|
|
1801
|
+
});
|
|
1802
|
+
validateAdmissionCapability(
|
|
1803
|
+
`defineChapter.network.readers.${reader.id}.admissionGrants`,
|
|
1804
|
+
reader.admissionGrants,
|
|
1805
|
+
crm
|
|
1806
|
+
);
|
|
1807
|
+
readers.push({
|
|
1808
|
+
id: reader.id,
|
|
1809
|
+
fields: readerFields,
|
|
1810
|
+
sharedNotes,
|
|
1811
|
+
editableFields,
|
|
1812
|
+
stageTransitions,
|
|
1813
|
+
...reader.admissionGrants === true ? { admissionGrants: true } : {}
|
|
1736
1814
|
});
|
|
1737
|
-
readers.push({ id: reader.id, fields: reader.fields, sharedNotes, editableFields, stageTransitions });
|
|
1738
1815
|
}
|
|
1739
1816
|
return { targets, readers };
|
|
1740
1817
|
}
|
|
@@ -1865,7 +1942,8 @@ function defineChapter(config) {
|
|
|
1865
1942
|
application,
|
|
1866
1943
|
Boolean(signupControl),
|
|
1867
1944
|
Boolean(memberContent),
|
|
1868
|
-
Boolean(builderLibrary)
|
|
1945
|
+
Boolean(builderLibrary),
|
|
1946
|
+
network.targets.some((target) => target.admissionGrants)
|
|
1869
1947
|
);
|
|
1870
1948
|
const services = config.services ?? ["db", "calendar", "o11y"];
|
|
1871
1949
|
const account = config.account ?? "none";
|