@odla-ai/chapter 0.26.0 → 0.26.1
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/{copy-context-CLvhJhrF.d.ts → copy-context-Vof2eTMt.d.ts} +5 -0
- package/dist/index.cjs +8 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +2 -2
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/member/index.d.ts +2 -2
- package/dist/worker/index.cjs +123 -78
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +5 -0
- package/dist/worker/index.d.ts +5 -0
- package/dist/worker/index.js +120 -75
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -373,6 +373,7 @@ export const chapter = defineChapter({
|
|
|
373
373
|
id: "example-chapter",
|
|
374
374
|
name: "Example Chapter",
|
|
375
375
|
url: "https://chapter.example.com",
|
|
376
|
+
binding: "EXAMPLE_CHAPTER",
|
|
376
377
|
fields: {
|
|
377
378
|
person: ["name", "email", "firstName", "lastName", "phone", "linkedin"],
|
|
378
379
|
company: ["name", "domain", "industry", "location", "linkedin"],
|
|
@@ -387,7 +388,7 @@ Treat the network as websites connected by explicit delivery edges:
|
|
|
387
388
|
- each website is a node with its own `appId`, ODLA tenants/keys, CRM config,
|
|
388
389
|
Clerk application, publishable keys, issuer, roles, and local users;
|
|
389
390
|
- each `network.targets[]` entry is a directed edge from one leader to one
|
|
390
|
-
follower: `{ id, name, url, secretName?, fields }`;
|
|
391
|
+
follower: `{ id, name, url, binding?, secretName?, fields }`;
|
|
391
392
|
- the payload is a versioned, allowlisted business record
|
|
392
393
|
`{ version: 2, source: { siteId, recordId }, type, input }`, never an
|
|
393
394
|
identity-provider session, another site's pipeline/account/billing state, or
|
|
@@ -406,6 +407,32 @@ payload against its own CRM config, and writes with its own server-side
|
|
|
406
407
|
is never needed, the leader never receives the follower's database key, and
|
|
407
408
|
sites do not share a Clerk application.
|
|
408
409
|
|
|
410
|
+
When both sites are Cloudflare Workers, configure `binding` and add the matching
|
|
411
|
+
service binding to the leader's Wrangler environment. Cloudflare does not
|
|
412
|
+
reliably dispatch same-account `workers.dev` subrequests into the target
|
|
413
|
+
Worker; Chapter therefore signs against `url` but sends through the bound
|
|
414
|
+
Worker:
|
|
415
|
+
|
|
416
|
+
```jsonc
|
|
417
|
+
{
|
|
418
|
+
"env": {
|
|
419
|
+
"dev": {
|
|
420
|
+
"services": [{
|
|
421
|
+
"binding": "EXAMPLE_CHAPTER",
|
|
422
|
+
"service": "example-chapter-dev"
|
|
423
|
+
}]
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
The example assumes the follower sets its development Worker `name` explicitly
|
|
430
|
+
to `example-chapter-dev`. If it instead uses Cloudflare's named-environment
|
|
431
|
+
addressing, declare the base `service` plus `"environment": "dev"`. The binding
|
|
432
|
+
name is public configuration, not a credential. If a configured binding is
|
|
433
|
+
missing at runtime, the target fails explicitly instead of falling back to a
|
|
434
|
+
potentially misrouted public fetch.
|
|
435
|
+
|
|
409
436
|
Vault the same random value as `network_share_secret` in the follower and as
|
|
410
437
|
`network_share_example_chapter` in the leader (or set a different
|
|
411
438
|
`secretName`). No secret is placed in source, browser data, or provisioning
|
|
@@ -531,9 +558,10 @@ data.
|
|
|
531
558
|
|
|
532
559
|
Use distinct development tenants and follower origins for the first delivery:
|
|
533
560
|
|
|
534
|
-
1. Confirm every target `id` exactly equals the follower's `chapter.id`.
|
|
535
|
-
|
|
536
|
-
|
|
561
|
+
1. Confirm every target `id` exactly equals the follower's `chapter.id`. For
|
|
562
|
+
Cloudflare Workers, confirm its `binding` exists in the leader's development
|
|
563
|
+
Wrangler environment. Vault one random value as `network_share_secret` in
|
|
564
|
+
the follower and under the target's resolved `secretName` in the leader.
|
|
537
565
|
2. Confirm `GET /api/admin/network/targets` lists the development follower with
|
|
538
566
|
the expected compatible record types.
|
|
539
567
|
3. Share one test person and one test business from the leader's record drawer.
|
|
@@ -65,6 +65,10 @@ interface ChapterNetworkTarget {
|
|
|
65
65
|
name?: string;
|
|
66
66
|
/** Absolute follower origin, e.g. `https://chapter.example.com`. */
|
|
67
67
|
url: string;
|
|
68
|
+
/** Optional Cloudflare service-binding name for Worker-to-Worker delivery.
|
|
69
|
+
* The URL still defines the signed request origin; the binding only supplies
|
|
70
|
+
* the transport when a `workers.dev` subrequest cannot enter another Worker. */
|
|
71
|
+
binding?: string;
|
|
68
72
|
/** Leader-vault key holding this follower's share secret. Defaults to
|
|
69
73
|
* `network_share_<id-with-underscores>`. */
|
|
70
74
|
secretName?: string;
|
|
@@ -107,6 +111,7 @@ interface ResolvedNetworkTarget {
|
|
|
107
111
|
id: string;
|
|
108
112
|
name: string;
|
|
109
113
|
url: string;
|
|
114
|
+
binding?: string;
|
|
110
115
|
secretName: string;
|
|
111
116
|
fields?: Record<string, readonly string[]>;
|
|
112
117
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -997,6 +997,7 @@ function formationFields(crm, formation) {
|
|
|
997
997
|
// src/config.ts
|
|
998
998
|
var SLUG = /^[a-z0-9][a-z0-9-]{1,62}$/;
|
|
999
999
|
var FIELD = /^[a-z][a-zA-Z0-9_]*$/;
|
|
1000
|
+
var BINDING = /^[A-Z][A-Z0-9_]{0,127}$/;
|
|
1000
1001
|
function resolveNetwork(config, crm) {
|
|
1001
1002
|
const seen = /* @__PURE__ */ new Set();
|
|
1002
1003
|
const targets = [];
|
|
@@ -1042,10 +1043,17 @@ function resolveNetwork(config, crm) {
|
|
|
1042
1043
|
if (!/^[a-zA-Z][a-zA-Z0-9_-]{1,127}$/.test(secretName)) {
|
|
1043
1044
|
throw new Error(`defineChapter.network.targets.${target.id}.secretName: must be a vault-key identifier`);
|
|
1044
1045
|
}
|
|
1046
|
+
const binding = target.binding?.trim();
|
|
1047
|
+
if (binding && !BINDING.test(binding)) {
|
|
1048
|
+
throw new Error(
|
|
1049
|
+
`defineChapter.network.targets.${target.id}.binding: must be an uppercase Worker binding identifier`
|
|
1050
|
+
);
|
|
1051
|
+
}
|
|
1045
1052
|
targets.push({
|
|
1046
1053
|
id: target.id,
|
|
1047
1054
|
name: target.name?.trim() || target.id,
|
|
1048
1055
|
url: url.origin,
|
|
1056
|
+
...binding ? { binding } : {},
|
|
1049
1057
|
secretName,
|
|
1050
1058
|
...fields ? { fields } : {}
|
|
1051
1059
|
});
|