@odla-ai/chapter 0.42.0 → 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 +32 -4
- package/dist/{chunk-MMDWXTJU.js → chunk-HWUTCXBV.js} +44 -1
- package/dist/chunk-HWUTCXBV.js.map +1 -0
- package/dist/{copy-context-DuJkH4U9.d.ts → copy-context-BBPsYe24.d.ts} +27 -1
- package/dist/index.cjs +144 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -3
- package/dist/index.d.ts +75 -3
- package/dist/index.js +144 -16
- 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 +745 -163
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +73 -2
- package/dist/worker/index.d.ts +73 -2
- package/dist/worker/index.js +730 -148
- package/dist/worker/index.js.map +1 -1
- package/package.json +2 -2
- package/runbooks/greenfield.md +3 -0
- package/dist/chunk-MMDWXTJU.js.map +0 -1
package/README.md
CHANGED
|
@@ -888,6 +888,11 @@ export const chapter = defineChapter({
|
|
|
888
888
|
},
|
|
889
889
|
// Separate write consent: browsing never implies note permission.
|
|
890
890
|
sharedNotes: ["person"],
|
|
891
|
+
// Separate again: name the exact profile fields and record types the
|
|
892
|
+
// parent may mutate. Omission keeps the edge read-only.
|
|
893
|
+
editableFields: { person: ["name", "email", "phone", "linkedin"] },
|
|
894
|
+
stageTransitions: ["person"],
|
|
895
|
+
admissionGrants: true,
|
|
891
896
|
}],
|
|
892
897
|
},
|
|
893
898
|
});
|
|
@@ -896,14 +901,34 @@ export const chapter = defineChapter({
|
|
|
896
901
|
`GET /api/network/records` requires the edge HMAC and rejects signed senders not
|
|
897
902
|
listed in `network.readers`. Results are capped at 50 records, offset-paged,
|
|
898
903
|
search-bounded, and projected to the reader's field list. Pipeline stage and
|
|
899
|
-
record timestamps
|
|
904
|
+
record timestamps, optimistic `revision`, and explicitly delegated edit
|
|
905
|
+
metadata are the only metadata outside that list; application
|
|
900
906
|
narrative, billing, account state, activities, and notes do not cross unless
|
|
901
907
|
the follower explicitly names a corresponding CRM field.
|
|
902
908
|
|
|
903
909
|
The leader's authenticated `GET /api/admin/network/records` proxy signs the
|
|
904
910
|
follower request server-to-server, so neither the browser session nor the
|
|
905
|
-
vaulted edge secret crosses sites.
|
|
906
|
-
|
|
911
|
+
vaulted edge secret crosses sites. When both halves of an edge opt in,
|
|
912
|
+
`PATCH /api/admin/network/records` accepts one bounded field patch or lifecycle
|
|
913
|
+
destination with the follower-authored `expectedRevision`, current stage, and a
|
|
914
|
+
stable mutation id. The follower revalidates its CRM schema, identity/email
|
|
915
|
+
rules, pipeline gates, and atomic revision guard; it remains source of truth and
|
|
916
|
+
records the leader peer plus initiating admin in the CRM activity audit. A
|
|
917
|
+
retry with the same input is idempotent, while stale state is `409`, an
|
|
918
|
+
undelegated operation is `403`, invalid fields or transitions are `422`, and
|
|
919
|
+
ordinary browse-only edges remain read-only.
|
|
920
|
+
|
|
921
|
+
Admission decisions use a separate default-deny lane. With
|
|
922
|
+
`admissionGrants: true` on both halves of an edge, the leader's
|
|
923
|
+
`POST /api/admin/network/admissions` resolves the person's current email from
|
|
924
|
+
its CRM, persists the complete desired target document, and delivers it through
|
|
925
|
+
the configured service binding or signed URL. Delivery state is durable as
|
|
926
|
+
`saved`, `pending`, `acknowledged`, `retrying`, or `rejected`; retry and revoke
|
|
927
|
+
routes publish the same or a higher desired revision. A follower may declare an
|
|
928
|
+
admission-only reader without `fields`, which does not make CRM records
|
|
929
|
+
browsable or editable.
|
|
930
|
+
|
|
931
|
+
The Network detail view also has two deliberate note lanes:
|
|
907
932
|
|
|
908
933
|
- `GET/POST /api/admin/network/notes` stores private annotations in the
|
|
909
934
|
leader's deny-all `networkNotes` namespace. They are keyed to the follower's
|
|
@@ -935,6 +960,9 @@ export const chapter = defineChapter({
|
|
|
935
960
|
company: ["name", "domain", "industry", "location", "linkedin"],
|
|
936
961
|
},
|
|
937
962
|
sharedNotes: ["person"],
|
|
963
|
+
editableFields: { person: ["name", "email", "phone", "linkedin"] },
|
|
964
|
+
stageTransitions: ["person"],
|
|
965
|
+
admissionGrants: true,
|
|
938
966
|
}],
|
|
939
967
|
},
|
|
940
968
|
});
|
|
@@ -945,7 +973,7 @@ Treat the network as websites connected by explicit delivery edges:
|
|
|
945
973
|
- each website is a node with its own `appId`, ODLA tenants/keys, CRM config,
|
|
946
974
|
Clerk application, publishable keys, issuer, roles, and local users;
|
|
947
975
|
- each `network.targets[]` entry is a directed edge from one leader to one
|
|
948
|
-
follower: `{ id, name, url, binding?, secretName?, fields }`;
|
|
976
|
+
follower: `{ id, name, url, binding?, secretName?, fields, editableFields?, stageTransitions?, admissionGrants? }`;
|
|
949
977
|
- the payload is a versioned, allowlisted business record
|
|
950
978
|
`{ version: 2, source: { siteId, recordId }, type, input }`, never an
|
|
951
979
|
identity-provider session, another site's pipeline/account/billing state, or
|
|
@@ -1620,6 +1620,48 @@ function admissionGrantsWorkspace(label = "Admission") {
|
|
|
1620
1620
|
render: (ctx) => /* @__PURE__ */ jsx16(AdmissionGrantsWorkspace, { getToken: ctx.getToken })
|
|
1621
1621
|
};
|
|
1622
1622
|
}
|
|
1623
|
+
function LeaderAdmissionAction(props) {
|
|
1624
|
+
const [decision, setDecision] = useState11("waive_interview");
|
|
1625
|
+
const [note, setNote] = useState11("");
|
|
1626
|
+
const [busy, setBusy] = useState11(false);
|
|
1627
|
+
const [error, setError] = useState11(null);
|
|
1628
|
+
const submit = async () => {
|
|
1629
|
+
setBusy(true);
|
|
1630
|
+
setError(null);
|
|
1631
|
+
try {
|
|
1632
|
+
const result = await adminFetch(props.getToken, "/api/admin/network/admissions", {
|
|
1633
|
+
method: "POST",
|
|
1634
|
+
body: JSON.stringify({
|
|
1635
|
+
targetId: props.targetId,
|
|
1636
|
+
personId: props.personId,
|
|
1637
|
+
decision,
|
|
1638
|
+
...note.trim() ? { note: note.trim() } : {},
|
|
1639
|
+
mutationId: crypto.randomUUID()
|
|
1640
|
+
})
|
|
1641
|
+
});
|
|
1642
|
+
props.onSaved?.(result);
|
|
1643
|
+
} catch (cause) {
|
|
1644
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
1645
|
+
} finally {
|
|
1646
|
+
setBusy(false);
|
|
1647
|
+
}
|
|
1648
|
+
};
|
|
1649
|
+
return /* @__PURE__ */ jsxs13("div", { style: { display: "grid", gap: 8 }, children: [
|
|
1650
|
+
/* @__PURE__ */ jsxs13("label", { children: [
|
|
1651
|
+
"Interview",
|
|
1652
|
+
/* @__PURE__ */ jsxs13("select", { value: decision, onChange: (event) => setDecision(event.currentTarget.value), children: [
|
|
1653
|
+
/* @__PURE__ */ jsx16("option", { value: "waive_interview", children: "Already completed" }),
|
|
1654
|
+
/* @__PURE__ */ jsx16("option", { value: "require_interview", children: "Required" })
|
|
1655
|
+
] })
|
|
1656
|
+
] }),
|
|
1657
|
+
/* @__PURE__ */ jsxs13("label", { children: [
|
|
1658
|
+
"Internal note",
|
|
1659
|
+
/* @__PURE__ */ jsx16("input", { maxLength: 2e3, value: note, onInput: (event) => setNote(event.currentTarget.value) })
|
|
1660
|
+
] }),
|
|
1661
|
+
/* @__PURE__ */ jsx16("button", { className: "btn secondary", type: "button", disabled: busy, onClick: () => void submit(), children: busy ? "Saving\u2026" : "Prepare for chapter" }),
|
|
1662
|
+
error ? /* @__PURE__ */ jsx16("p", { role: "alert", children: error }) : null
|
|
1663
|
+
] });
|
|
1664
|
+
}
|
|
1623
1665
|
|
|
1624
1666
|
// src/ui/admin-settings-workspace.tsx
|
|
1625
1667
|
import { Tabs as Tabs2 } from "@odla-ai/ui/components";
|
|
@@ -2709,6 +2751,7 @@ export {
|
|
|
2709
2751
|
LeaderNetworkOverview,
|
|
2710
2752
|
AdmissionGrantsWorkspace,
|
|
2711
2753
|
admissionGrantsWorkspace,
|
|
2754
|
+
LeaderAdmissionAction,
|
|
2712
2755
|
availabilitySection,
|
|
2713
2756
|
BuilderLibraryAdmin,
|
|
2714
2757
|
builderLibrarySection,
|
|
@@ -2722,4 +2765,4 @@ export {
|
|
|
2722
2765
|
defaultAdminSections,
|
|
2723
2766
|
meetingsSection
|
|
2724
2767
|
};
|
|
2725
|
-
//# sourceMappingURL=chunk-
|
|
2768
|
+
//# sourceMappingURL=chunk-HWUTCXBV.js.map
|