@odla-ai/chapter 0.24.0 → 0.25.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 +48 -32
- package/dist/{copy-context-Dp5hvj5W.d.ts → copy-context-DI21CYQ3.d.ts} +3 -4
- package/dist/index.cjs +51 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -24
- package/dist/index.d.ts +50 -24
- package/dist/index.js +51 -14
- 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 +211 -22
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +3 -4
- package/dist/worker/index.d.ts +3 -4
- package/dist/worker/index.js +211 -22
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
- package/runbooks/adopt-existing.md +93 -21
- package/runbooks/greenfield.md +31 -31
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@odla-ai/chapter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.1",
|
|
4
4
|
"description": "A leader/follower foundation for branded membership sites: shared CRM, admin, auth, payments, booking, and explicit record delivery from one defineChapter config.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://odla.ai/docs/packages/chapter",
|
|
@@ -68,6 +68,16 @@ Create or extend root `MIGRATION.md`; never replace its history. Record state
|
|
|
68
68
|
render sink;
|
|
69
69
|
- telemetry, freshness/error alerts, deploy commands, and CI auto-deploys.
|
|
70
70
|
|
|
71
|
+
For every route, record the method/path, current consumer, owning implementation
|
|
72
|
+
(`legacy`, Chapter, or an explicit host adapter), request and response schemas,
|
|
73
|
+
status/error/auth/cache behavior, and its evidence. Source evidence names the
|
|
74
|
+
checked-in path plus commit; deployment evidence names the origin plus immutable
|
|
75
|
+
Worker/deployment version. A response observed on an unversioned deployment
|
|
76
|
+
describes only that deployed build at that moment. It does not establish route
|
|
77
|
+
ownership or the contract of the branch being changed. Treat old branches, git
|
|
78
|
+
history, and unrelated deployments as leads to verify, never as the migration
|
|
79
|
+
specification.
|
|
80
|
+
|
|
71
81
|
### Freeze visual and behavior evidence
|
|
72
82
|
|
|
73
83
|
Capture representative production screenshots and measured layouts at 390,
|
|
@@ -112,15 +122,26 @@ Allowed states: `not-started`, `canary`, `parallel`, `verified`,
|
|
|
112
122
|
Install the version-matched agent guidance and inspect the automation boundary:
|
|
113
123
|
|
|
114
124
|
```sh
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
npm install \
|
|
126
|
+
@odla-ai/chapter @odla-ai/brand @odla-ai/ui \
|
|
127
|
+
@odla-ai/crm @odla-ai/db \
|
|
128
|
+
@odla-ai/calendar @odla-ai/email \
|
|
129
|
+
@odla-ai/auth-clerk @odla-ai/o11y \
|
|
130
|
+
jose preact
|
|
131
|
+
npm install --save-dev \
|
|
132
|
+
@odla-ai/cli @odla-ai/security \
|
|
133
|
+
@cloudflare/workers-types \
|
|
134
|
+
typescript vite vitest wrangler
|
|
135
|
+
npx odla-ai setup
|
|
136
|
+
npm ls @odla-ai/chapter @odla-ai/crm @odla-ai/ui @odla-ai/cli
|
|
137
|
+
npx odla-ai capabilities --json
|
|
117
138
|
```
|
|
118
139
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
140
|
+
Use normal dependency declarations while ODLA is under active development.
|
|
141
|
+
Review and commit `package.json` plus `package-lock.json`, use `npm ci` after
|
|
142
|
+
the intentional dependency update, record resolved versions in PM, and rerun
|
|
143
|
+
the frozen acceptance and Chapter conformance suites. Do not use
|
|
144
|
+
`--legacy-peer-deps` or preserve an incompatible peer.
|
|
124
145
|
|
|
125
146
|
Write `src/chapter.config.mjs` from the inventory. Make every behavior decision
|
|
126
147
|
explicit:
|
|
@@ -139,13 +160,20 @@ explicit:
|
|
|
139
160
|
|
|
140
161
|
Before deleting old schema/rules/provisioning:
|
|
141
162
|
|
|
142
|
-
1. freeze the legacy schema and rules
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
163
|
+
1. freeze the legacy schema and rules from an exact reviewed source path and
|
|
164
|
+
commit, with a recorded content digest;
|
|
165
|
+
2. make that baseline independent: use the untouched legacy source or a literal
|
|
166
|
+
fixture that does not import Chapter, the active descriptor/schema alias, or
|
|
167
|
+
another generated candidate; do not modify baseline and candidate in the
|
|
168
|
+
same approval;
|
|
169
|
+
3. normalize only approved representational differences;
|
|
170
|
+
4. compare `createChapterIntegration(chapter)` namespaces, attrs, links, rules,
|
|
171
|
+
and seeds to the independent baseline;
|
|
172
|
+
5. run a negative control by removing or changing a known field/rule on one side
|
|
173
|
+
and prove the parity test fails before trusting a green result;
|
|
174
|
+
6. fail on missing fields, widened rules, cardinality changes, renamed natural
|
|
147
175
|
keys, new client-readable data, or unapproved seed differences;
|
|
148
|
-
|
|
176
|
+
7. record every intentional delta and migration mapping in `MIGRATION.md`.
|
|
149
177
|
|
|
150
178
|
`createChapterIntegration()` inserts the group seed only when absent. Existing
|
|
151
179
|
runtime owner edits do not update from later config changes. Compare the current
|
|
@@ -163,8 +191,10 @@ At minimum audit:
|
|
|
163
191
|
- stock `JoinIsland` generates a fresh `submissionId` on each invocation, so an
|
|
164
192
|
ambiguous retry after a lost response is not idempotent even though a
|
|
165
193
|
concurrent click is disabled;
|
|
166
|
-
- `profileFields` now defaults to `[]`; enumerate
|
|
167
|
-
|
|
194
|
+
- `profileFields` now defaults to `[]`; enumerate the small account/admin
|
|
195
|
+
signals that may be mirrored into backend-only Clerk private metadata rather
|
|
196
|
+
than relying on implicit projection. Keep the application row and CRM
|
|
197
|
+
canonical;
|
|
168
198
|
- application-to-CRM projection fields;
|
|
169
199
|
- `requireDisclaimerAck` now defaults to `true`; set `false` explicitly only
|
|
170
200
|
when the existing product has no consent control, and preserve
|
|
@@ -330,10 +360,25 @@ Do not replace schema, worker, routes, and UI in one unreviewable change.
|
|
|
330
360
|
routes run before built-ins and receive Chapter's existing context
|
|
331
361
|
(`verifyUser`, `makeDb`, `roleFor`, `isAdmin`); do not verify JWTs twice.
|
|
332
362
|
3. Initially keep every bespoke endpoint as a host route. Alias legacy URLs to
|
|
333
|
-
Chapter behavior
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
363
|
+
Chapter behavior only when the route-contract matrix proves method, auth,
|
|
364
|
+
request body, response status, JSON keys/types/nesting, units, null/omission
|
|
365
|
+
semantics, and relevant headers are compatible. Matching business values
|
|
366
|
+
alone is not response-shape parity.
|
|
367
|
+
4. When contracts differ, keep the legacy route until its consumer adopts the
|
|
368
|
+
packaged Chapter component end to end, or add an explicit adapter with
|
|
369
|
+
contract tests. Do not simply repoint the existing browser code.
|
|
370
|
+
5. In Chapter 0.25, `/api/join-config` is Chapter-owned and returns the
|
|
371
|
+
group-scoped join configuration, raw cent values, policy copy, and readiness;
|
|
372
|
+
it is not a promise to reproduce a legacy route's prebuilt Stripe line items
|
|
373
|
+
or publishable key. `JoinIsland` delegates payment to `PaymentStep`, which
|
|
374
|
+
obtains `clientSecret`, `publishableKey`, and `lineItems` from
|
|
375
|
+
`POST /api/payments/subscription` after application submission and refund
|
|
376
|
+
acknowledgement. Verify this installed-version contract before retiring a
|
|
377
|
+
legacy join route.
|
|
378
|
+
6. Compare built-in and legacy behavior route by route; only then remove a host
|
|
379
|
+
route that Chapter fully owns and whose consumers use the verified Chapter
|
|
380
|
+
contract or adapter.
|
|
381
|
+
7. Keep static fallback and API handling explicit so unknown APIs cannot fall
|
|
337
382
|
through to a successful SPA document.
|
|
338
383
|
|
|
339
384
|
Test public/private method policies, body limits, idempotency, auth 401 vs 403,
|
|
@@ -437,6 +482,22 @@ Do not substitute `secrets set-clerk-key`; it writes the platform-reserved
|
|
|
437
482
|
command does not validate Clerk instance prefixes: independently confirm dev
|
|
438
483
|
uses `sk_test_`. Never put `sk_live_` in dev.
|
|
439
484
|
|
|
485
|
+
Chapter now reserves `public_metadata` for the small authorization role and
|
|
486
|
+
stores its `applicationId`/allowlisted profile snapshot in backend-only
|
|
487
|
+
`private_metadata`. After deploying the schema update, run the authenticated
|
|
488
|
+
admin repair endpoint in bounded batches:
|
|
489
|
+
|
|
490
|
+
```text
|
|
491
|
+
POST /api/admin/clerk/private-profiles/sync?offset=0&limit=50
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
Continue with each returned `nextOffset` until it is `null`. Prove that the
|
|
495
|
+
public `role` and unrelated host metadata survive, the former public
|
|
496
|
+
`applicationId`/`profile` keys are absent, the private snapshot matches the
|
|
497
|
+
latest application, and `clerkPrivateMetadataSyncedAt` plus `clerkUserId` are
|
|
498
|
+
recorded locally. The application row and CRM remain canonical; this is an
|
|
499
|
+
account/admin signal mirror, not a third editable profile database.
|
|
500
|
+
|
|
440
501
|
### Stripe
|
|
441
502
|
|
|
442
503
|
Use test resources and an isolated dev webhook. Store `stripe_secret_key` and
|
|
@@ -464,9 +525,12 @@ selected account invitation effect. Never let dev send to imported members.
|
|
|
464
525
|
|
|
465
526
|
Check in an executable acceptance manifest with:
|
|
466
527
|
|
|
467
|
-
- actual dev URLs and Worker version ids
|
|
528
|
+
- actual dev URLs and immutable Worker version ids, paired with the source
|
|
529
|
+
commit they are expected to run;
|
|
468
530
|
- deterministic synthetic member/application ids;
|
|
469
|
-
- expected
|
|
531
|
+
- expected route owners and full request/response contracts—not only paths,
|
|
532
|
+
statuses, or equal values—plus schema/counts/freshness and Chapter backend
|
|
533
|
+
marker;
|
|
470
534
|
- expected migration-readiness inputs and a `200` only when each is green;
|
|
471
535
|
- expected account, payment, booking, email, CRM, and admin outcomes;
|
|
472
536
|
- expected o11y service/release and safe trace;
|
|
@@ -492,6 +556,14 @@ Run the real journey:
|
|
|
492
556
|
`doctor`, unit tests, build, CLI smoke, a login page, and a human-looking admin
|
|
493
557
|
screen are necessary but not sufficient.
|
|
494
558
|
|
|
559
|
+
Before filing a route bug from deployed evidence, prove that the probed
|
|
560
|
+
deployment runs the intended commit/version. Repeat the request against the
|
|
561
|
+
direct candidate origin and the public domain with a unique non-secret query
|
|
562
|
+
value, capture `Age`, `Cache-Control`, `CF-Cache-Status`, `ETag`, and the Worker
|
|
563
|
+
version marker, and re-test after the documented edge/config propagation
|
|
564
|
+
window. A cached pre-deploy or pre-credential `404` is not evidence that the
|
|
565
|
+
current route is absent.
|
|
566
|
+
|
|
495
567
|
## Phase 8 — Production parallel run and cutover
|
|
496
568
|
|
|
497
569
|
Do not add production until the human approves the full dev report and both
|
package/runbooks/greenfield.md
CHANGED
|
@@ -41,8 +41,9 @@ consumer, not a visual identity to rename.
|
|
|
41
41
|
|
|
42
42
|
## Non-negotiable boundaries
|
|
43
43
|
|
|
44
|
-
1.
|
|
45
|
-
|
|
44
|
+
1. Use normal dependency declarations while ODLA is under active development.
|
|
45
|
+
Commit the lockfile, use `npm ci` for repeatable installs, and rerun
|
|
46
|
+
conformance after updates. Never use `--legacy-peer-deps`.
|
|
46
47
|
2. Build and prove `dev` before adding `prod`. Production provisioning, secret
|
|
47
48
|
transfer, deploy, DNS, billing activation, and real outbound email are human
|
|
48
49
|
checkpoints.
|
|
@@ -113,38 +114,31 @@ renamed reference site.
|
|
|
113
114
|
|
|
114
115
|
`@odla-ai/chapter` has no scaffolding binary. The agent creates the host files.
|
|
115
116
|
|
|
116
|
-
Initialize npm, install
|
|
117
|
-
agent guidance:
|
|
117
|
+
Initialize npm, install Chapter and the Preact host with normal dependency
|
|
118
|
+
declarations, then install the CLI's agent guidance:
|
|
118
119
|
|
|
119
120
|
```sh
|
|
120
121
|
npm init -y
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
@odla-ai/calendar@0.2.0 @odla-ai/email@0.3.1 \
|
|
134
|
-
@odla-ai/auth-clerk@0.4.1 @odla-ai/o11y@2.2.2 \
|
|
135
|
-
jose@6.2.3 preact@10.29.7
|
|
136
|
-
npm install --save-dev --save-exact \
|
|
137
|
-
@odla-ai/cli@0.17.1 @odla-ai/security@0.3.1 \
|
|
138
|
-
@cloudflare/workers-types@4.20260702.1 \
|
|
139
|
-
typescript@6.0.3 \
|
|
140
|
-
vite@8.1.4 vitest@4.1.10 wrangler@4.107.0
|
|
122
|
+
npm install \
|
|
123
|
+
@odla-ai/chapter @odla-ai/brand @odla-ai/ui \
|
|
124
|
+
@odla-ai/crm @odla-ai/db \
|
|
125
|
+
@odla-ai/calendar @odla-ai/email \
|
|
126
|
+
@odla-ai/auth-clerk @odla-ai/o11y \
|
|
127
|
+
jose preact
|
|
128
|
+
npm install --save-dev \
|
|
129
|
+
@odla-ai/cli @odla-ai/security \
|
|
130
|
+
@cloudflare/workers-types \
|
|
131
|
+
typescript vite vitest wrangler
|
|
132
|
+
npx odla-ai setup
|
|
133
|
+
npm ls @odla-ai/chapter @odla-ai/crm @odla-ai/ui @odla-ai/cli
|
|
141
134
|
npx odla-ai capabilities --json
|
|
142
135
|
```
|
|
143
136
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
it
|
|
137
|
+
Commit `package-lock.json`, use `npm ci` after the initial dependency change,
|
|
138
|
+
and rerun conformance whenever the lockfile resolves new ODLA versions. Do not
|
|
139
|
+
bypass peer-dependency validation. Install auth-clerk explicitly when adopting
|
|
140
|
+
the admin entry; it is an optional Chapter peer because worker-only and
|
|
141
|
+
member-only consumers do not need it.
|
|
148
142
|
|
|
149
143
|
Required host scripts:
|
|
150
144
|
|
|
@@ -341,8 +335,11 @@ both require a named app-readable vault secret `clerk_secret_key`. Keep
|
|
|
341
335
|
defaults to `true`, and `application.profileFields` defaults to `[]`. Keep all
|
|
342
336
|
three decisions explicit in the checked-in config and snapshot their resolved
|
|
343
337
|
values. A site with no consent control must deliberately set
|
|
344
|
-
`requireDisclaimerAck: false`; an application field reaches
|
|
345
|
-
|
|
338
|
+
`requireDisclaimerAck: false`; an application field reaches backend-only Clerk
|
|
339
|
+
private metadata only when it is deliberately listed in `profileFields`. Keep
|
|
340
|
+
that mirror small and use the application row/CRM as the canonical profile.
|
|
341
|
+
With `account: "invite"`, prove the first signed-in `/api/me` request completes
|
|
342
|
+
the private profile write and records `clerkPrivateMetadataSyncedAt`.
|
|
346
343
|
|
|
347
344
|
`copy` is a recursive partial of `ChapterCopy`. `defineChapter()` resolves it
|
|
348
345
|
to a complete `chapter.copy`, which is the voice source for packaged join,
|
|
@@ -704,7 +701,10 @@ Run a real deployed journey:
|
|
|
704
701
|
|
|
705
702
|
1. public home and every navigation/deep link;
|
|
706
703
|
2. join-config readiness, application submit, test payment, booking;
|
|
707
|
-
3. Clerk account/invite behavior selected by config;
|
|
704
|
+
3. Clerk account/invite behavior selected by config; prove `role` is the only
|
|
705
|
+
Chapter-owned public metadata and the allowlisted account snapshot appears
|
|
706
|
+
in private metadata. For an invite, the first authenticated `/api/me`
|
|
707
|
+
completes that write exactly once;
|
|
708
708
|
4. provisional and member area;
|
|
709
709
|
5. admin sign-in, people/CRM, application approval, meeting, billing, email;
|
|
710
710
|
6. replay/idempotency and one safe error;
|