@earendil-works/chord 1.4.0 → 1.5.0
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/CHANGELOG.md +41 -0
- package/README.md +79 -14
- package/dist/cell.d.ts +7 -7
- package/dist/cell.d.ts.map +1 -1
- package/dist/cell.js.map +1 -1
- package/dist/context/index.d.ts +1 -1
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +1 -1
- package/dist/context/index.js.map +1 -1
- package/dist/contract.d.ts +51 -52
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +19 -24
- package/dist/contract.js.map +1 -1
- package/dist/delta/apply-immutable-trusted.js +3 -4
- package/dist/delta/apply-immutable-trusted.js.map +1 -1
- package/dist/delta/diff.d.ts.map +1 -1
- package/dist/delta/diff.js +5 -3
- package/dist/delta/diff.js.map +1 -1
- package/dist/delta/index.d.ts +9 -1
- package/dist/delta/index.d.ts.map +1 -1
- package/dist/delta/index.js +15 -11
- package/dist/delta/index.js.map +1 -1
- package/dist/delta/pending.d.ts +36 -0
- package/dist/delta/pending.d.ts.map +1 -0
- package/dist/delta/pending.js +143 -0
- package/dist/delta/pending.js.map +1 -0
- package/dist/delta/tracker.d.ts +12 -0
- package/dist/delta/tracker.d.ts.map +1 -1
- package/dist/delta/tracker.js +109 -39
- package/dist/delta/tracker.js.map +1 -1
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +9 -7
- package/dist/host.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/next/contracts/accepts.d.ts +81 -0
- package/dist/next/contracts/accepts.d.ts.map +1 -0
- package/dist/next/contracts/accepts.js +123 -0
- package/dist/next/contracts/accepts.js.map +1 -0
- package/dist/next/contracts/contract.d.ts +121 -0
- package/dist/next/contracts/contract.d.ts.map +1 -0
- package/dist/next/contracts/contract.js +50 -0
- package/dist/next/contracts/contract.js.map +1 -0
- package/dist/next/contracts/declare.d.ts +107 -0
- package/dist/next/contracts/declare.d.ts.map +1 -0
- package/dist/next/contracts/declare.js +136 -0
- package/dist/next/contracts/declare.js.map +1 -0
- package/dist/next/contracts/evolve.d.ts +92 -0
- package/dist/next/contracts/evolve.d.ts.map +1 -0
- package/dist/next/contracts/evolve.js +179 -0
- package/dist/next/contracts/evolve.js.map +1 -0
- package/dist/next/contracts/fingerprint.d.ts +16 -0
- package/dist/next/contracts/fingerprint.d.ts.map +1 -0
- package/dist/next/contracts/fingerprint.js +50 -0
- package/dist/next/contracts/fingerprint.js.map +1 -0
- package/dist/next/contracts/history.d.ts +71 -0
- package/dist/next/contracts/history.d.ts.map +1 -0
- package/dist/next/contracts/history.js +3 -0
- package/dist/next/contracts/history.js.map +1 -0
- package/dist/next/contracts/host-kind.d.ts +40 -0
- package/dist/next/contracts/host-kind.d.ts.map +1 -0
- package/dist/next/contracts/host-kind.js +37 -0
- package/dist/next/contracts/host-kind.js.map +1 -0
- package/dist/next/contracts/index.d.ts +7 -0
- package/dist/next/contracts/index.d.ts.map +1 -0
- package/dist/next/contracts/index.js +6 -0
- package/dist/next/contracts/index.js.map +1 -0
- package/dist/next/contracts/internal.d.ts +10 -0
- package/dist/next/contracts/internal.d.ts.map +1 -0
- package/dist/next/contracts/internal.js +9 -0
- package/dist/next/contracts/internal.js.map +1 -0
- package/dist/next/contracts/names.d.ts +3 -0
- package/dist/next/contracts/names.d.ts.map +1 -0
- package/dist/next/contracts/names.js +13 -0
- package/dist/next/contracts/names.js.map +1 -0
- package/dist/next/contracts/params.d.ts +28 -0
- package/dist/next/contracts/params.d.ts.map +1 -0
- package/dist/next/contracts/params.js +50 -0
- package/dist/next/contracts/params.js.map +1 -0
- package/dist/next/contracts/schema.d.ts +102 -0
- package/dist/next/contracts/schema.d.ts.map +1 -0
- package/dist/next/contracts/schema.js +103 -0
- package/dist/next/contracts/schema.js.map +1 -0
- package/dist/next/contracts/snapshot.d.ts +16 -0
- package/dist/next/contracts/snapshot.d.ts.map +1 -0
- package/dist/next/contracts/snapshot.js +167 -0
- package/dist/next/contracts/snapshot.js.map +1 -0
- package/dist/next/data/args.d.ts +50 -0
- package/dist/next/data/args.d.ts.map +1 -0
- package/dist/next/data/args.js +83 -0
- package/dist/next/data/args.js.map +1 -0
- package/dist/next/data/errors.d.ts +73 -0
- package/dist/next/data/errors.d.ts.map +1 -0
- package/dist/next/data/errors.js +107 -0
- package/dist/next/data/errors.js.map +1 -0
- package/dist/next/data/failure.d.ts +26 -0
- package/dist/next/data/failure.d.ts.map +1 -0
- package/dist/next/data/failure.js +72 -0
- package/dist/next/data/failure.js.map +1 -0
- package/dist/next/data/index.d.ts +4 -0
- package/dist/next/data/index.d.ts.map +1 -0
- package/dist/next/data/index.js +4 -0
- package/dist/next/data/index.js.map +1 -0
- package/dist/next/data/internal.d.ts +7 -0
- package/dist/next/data/internal.d.ts.map +1 -0
- package/dist/next/data/internal.js +8 -0
- package/dist/next/data/internal.js.map +1 -0
- package/dist/next/data/params.d.ts +20 -0
- package/dist/next/data/params.d.ts.map +1 -0
- package/dist/next/data/params.js +31 -0
- package/dist/next/data/params.js.map +1 -0
- package/dist/next/data/principal.d.ts +17 -0
- package/dist/next/data/principal.d.ts.map +1 -0
- package/dist/next/data/principal.js +41 -0
- package/dist/next/data/principal.js.map +1 -0
- package/dist/next/data/validator.d.ts +12 -0
- package/dist/next/data/validator.d.ts.map +1 -0
- package/dist/next/data/validator.js +34 -0
- package/dist/next/data/validator.js.map +1 -0
- package/dist/next/documents/address-source.d.ts +20 -0
- package/dist/next/documents/address-source.d.ts.map +1 -0
- package/dist/next/documents/address-source.js +44 -0
- package/dist/next/documents/address-source.js.map +1 -0
- package/dist/next/documents/definition.d.ts +84 -0
- package/dist/next/documents/definition.d.ts.map +1 -0
- package/dist/next/documents/definition.js +73 -0
- package/dist/next/documents/definition.js.map +1 -0
- package/dist/next/documents/documents.d.ts +106 -0
- package/dist/next/documents/documents.d.ts.map +1 -0
- package/dist/next/documents/documents.js +224 -0
- package/dist/next/documents/documents.js.map +1 -0
- package/dist/next/documents/fence.d.ts +9 -0
- package/dist/next/documents/fence.d.ts.map +1 -0
- package/dist/next/documents/fence.js +15 -0
- package/dist/next/documents/fence.js.map +1 -0
- package/dist/next/documents/handles.d.ts +76 -0
- package/dist/next/documents/handles.d.ts.map +1 -0
- package/dist/next/documents/handles.js +66 -0
- package/dist/next/documents/handles.js.map +1 -0
- package/dist/next/documents/index.d.ts +4 -0
- package/dist/next/documents/index.d.ts.map +1 -0
- package/dist/next/documents/index.js +3 -0
- package/dist/next/documents/index.js.map +1 -0
- package/dist/next/documents/internal.d.ts +9 -0
- package/dist/next/documents/internal.d.ts.map +1 -0
- package/dist/next/documents/internal.js +9 -0
- package/dist/next/documents/internal.js.map +1 -0
- package/dist/next/documents/keyed-slot.d.ts +103 -0
- package/dist/next/documents/keyed-slot.d.ts.map +1 -0
- package/dist/next/documents/keyed-slot.js +395 -0
- package/dist/next/documents/keyed-slot.js.map +1 -0
- package/dist/next/documents/line.d.ts +7 -0
- package/dist/next/documents/line.d.ts.map +1 -0
- package/dist/next/documents/line.js +14 -0
- package/dist/next/documents/line.js.map +1 -0
- package/dist/next/documents/persistence.d.ts +104 -0
- package/dist/next/documents/persistence.d.ts.map +1 -0
- package/dist/next/documents/persistence.js +128 -0
- package/dist/next/documents/persistence.js.map +1 -0
- package/dist/next/documents/residency.d.ts +31 -0
- package/dist/next/documents/residency.d.ts.map +1 -0
- package/dist/next/documents/residency.js +93 -0
- package/dist/next/documents/residency.js.map +1 -0
- package/dist/next/documents/slot.d.ts +109 -0
- package/dist/next/documents/slot.d.ts.map +1 -0
- package/dist/next/documents/slot.js +181 -0
- package/dist/next/documents/slot.js.map +1 -0
- package/dist/next/documents/transaction.d.ts +133 -0
- package/dist/next/documents/transaction.d.ts.map +1 -0
- package/dist/next/documents/transaction.js +409 -0
- package/dist/next/documents/transaction.js.map +1 -0
- package/dist/next/host/activity.d.ts +31 -0
- package/dist/next/host/activity.d.ts.map +1 -0
- package/dist/next/host/activity.js +40 -0
- package/dist/next/host/activity.js.map +1 -0
- package/dist/next/host/adapted.d.ts +49 -0
- package/dist/next/host/adapted.d.ts.map +1 -0
- package/dist/next/host/adapted.js +214 -0
- package/dist/next/host/adapted.js.map +1 -0
- package/dist/next/host/attempt.d.ts +278 -0
- package/dist/next/host/attempt.d.ts.map +1 -0
- package/dist/next/host/attempt.js +1072 -0
- package/dist/next/host/attempt.js.map +1 -0
- package/dist/next/host/backoff.d.ts +29 -0
- package/dist/next/host/backoff.d.ts.map +1 -0
- package/dist/next/host/backoff.js +69 -0
- package/dist/next/host/backoff.js.map +1 -0
- package/dist/next/host/ctx.d.ts +47 -0
- package/dist/next/host/ctx.d.ts.map +1 -0
- package/dist/next/host/ctx.js +108 -0
- package/dist/next/host/ctx.js.map +1 -0
- package/dist/next/host/deadline.d.ts +12 -0
- package/dist/next/host/deadline.d.ts.map +1 -0
- package/dist/next/host/deadline.js +40 -0
- package/dist/next/host/deadline.js.map +1 -0
- package/dist/next/host/dependencies.d.ts +65 -0
- package/dist/next/host/dependencies.d.ts.map +1 -0
- package/dist/next/host/dependencies.js +115 -0
- package/dist/next/host/dependencies.js.map +1 -0
- package/dist/next/host/destination.d.ts +48 -0
- package/dist/next/host/destination.d.ts.map +1 -0
- package/dist/next/host/destination.js +101 -0
- package/dist/next/host/destination.js.map +1 -0
- package/dist/next/host/facet.d.ts +79 -0
- package/dist/next/host/facet.d.ts.map +1 -0
- package/dist/next/host/facet.js +55 -0
- package/dist/next/host/facet.js.map +1 -0
- package/dist/next/host/follow.d.ts +52 -0
- package/dist/next/host/follow.d.ts.map +1 -0
- package/dist/next/host/follow.js +207 -0
- package/dist/next/host/follow.js.map +1 -0
- package/dist/next/host/host.d.ts +495 -0
- package/dist/next/host/host.d.ts.map +1 -0
- package/dist/next/host/host.js +1075 -0
- package/dist/next/host/host.js.map +1 -0
- package/dist/next/host/index.d.ts +17 -0
- package/dist/next/host/index.d.ts.map +1 -0
- package/dist/next/host/index.js +6 -0
- package/dist/next/host/index.js.map +1 -0
- package/dist/next/host/internal.d.ts +10 -0
- package/dist/next/host/internal.d.ts.map +1 -0
- package/dist/next/host/internal.js +8 -0
- package/dist/next/host/internal.js.map +1 -0
- package/dist/next/host/members.d.ts +50 -0
- package/dist/next/host/members.d.ts.map +1 -0
- package/dist/next/host/members.js +107 -0
- package/dist/next/host/members.js.map +1 -0
- package/dist/next/host/native.d.ts +55 -0
- package/dist/next/host/native.d.ts.map +1 -0
- package/dist/next/host/native.js +92 -0
- package/dist/next/host/native.js.map +1 -0
- package/dist/next/host/object.d.ts +290 -0
- package/dist/next/host/object.d.ts.map +1 -0
- package/dist/next/host/object.js +1127 -0
- package/dist/next/host/object.js.map +1 -0
- package/dist/next/host/parked.d.ts +23 -0
- package/dist/next/host/parked.d.ts.map +1 -0
- package/dist/next/host/parked.js +79 -0
- package/dist/next/host/parked.js.map +1 -0
- package/dist/next/host/presence.d.ts +34 -0
- package/dist/next/host/presence.d.ts.map +1 -0
- package/dist/next/host/presence.js +117 -0
- package/dist/next/host/presence.js.map +1 -0
- package/dist/next/host/ref-state.d.ts +53 -0
- package/dist/next/host/ref-state.d.ts.map +1 -0
- package/dist/next/host/ref-state.js +83 -0
- package/dist/next/host/ref-state.js.map +1 -0
- package/dist/next/host/reference-keys.d.ts +36 -0
- package/dist/next/host/reference-keys.d.ts.map +1 -0
- package/dist/next/host/reference-keys.js +168 -0
- package/dist/next/host/reference-keys.js.map +1 -0
- package/dist/next/host/reference-source.d.ts +65 -0
- package/dist/next/host/reference-source.d.ts.map +1 -0
- package/dist/next/host/reference-source.js +285 -0
- package/dist/next/host/reference-source.js.map +1 -0
- package/dist/next/host/reference.d.ts +308 -0
- package/dist/next/host/reference.d.ts.map +1 -0
- package/dist/next/host/reference.js +775 -0
- package/dist/next/host/reference.js.map +1 -0
- package/dist/next/host/retry-on.d.ts +28 -0
- package/dist/next/host/retry-on.d.ts.map +1 -0
- package/dist/next/host/retry-on.js +52 -0
- package/dist/next/host/retry-on.js.map +1 -0
- package/dist/next/host/revocation.d.ts +16 -0
- package/dist/next/host/revocation.d.ts.map +1 -0
- package/dist/next/host/revocation.js +27 -0
- package/dist/next/host/revocation.js.map +1 -0
- package/dist/next/host/root.d.ts +27 -0
- package/dist/next/host/root.d.ts.map +1 -0
- package/dist/next/host/root.js +68 -0
- package/dist/next/host/root.js.map +1 -0
- package/dist/next/host/route.d.ts +64 -0
- package/dist/next/host/route.d.ts.map +1 -0
- package/dist/next/host/route.js +190 -0
- package/dist/next/host/route.js.map +1 -0
- package/dist/next/host/routines.d.ts +76 -0
- package/dist/next/host/routines.d.ts.map +1 -0
- package/dist/next/host/routines.js +350 -0
- package/dist/next/host/routines.js.map +1 -0
- package/dist/next/host/sleep.d.ts +9 -0
- package/dist/next/host/sleep.d.ts.map +1 -0
- package/dist/next/host/sleep.js +40 -0
- package/dist/next/host/sleep.js.map +1 -0
- package/dist/next/host/staging.d.ts +94 -0
- package/dist/next/host/staging.d.ts.map +1 -0
- package/dist/next/host/staging.js +302 -0
- package/dist/next/host/staging.js.map +1 -0
- package/dist/next/host/unbound.d.ts +30 -0
- package/dist/next/host/unbound.d.ts.map +1 -0
- package/dist/next/host/unbound.js +67 -0
- package/dist/next/host/unbound.js.map +1 -0
- package/dist/next/host/uuid.d.ts +3 -0
- package/dist/next/host/uuid.d.ts.map +1 -0
- package/dist/next/host/uuid.js +38 -0
- package/dist/next/host/uuid.js.map +1 -0
- package/dist/next/index.d.ts +28 -0
- package/dist/next/index.d.ts.map +1 -0
- package/dist/next/index.js +18 -0
- package/dist/next/index.js.map +1 -0
- package/dist/next/jobs/definition.d.ts +96 -0
- package/dist/next/jobs/definition.d.ts.map +1 -0
- package/dist/next/jobs/definition.js +83 -0
- package/dist/next/jobs/definition.js.map +1 -0
- package/dist/next/jobs/index.d.ts +5 -0
- package/dist/next/jobs/index.d.ts.map +1 -0
- package/dist/next/jobs/index.js +3 -0
- package/dist/next/jobs/index.js.map +1 -0
- package/dist/next/jobs/internal.d.ts +3 -0
- package/dist/next/jobs/internal.d.ts.map +1 -0
- package/dist/next/jobs/internal.js +4 -0
- package/dist/next/jobs/internal.js.map +1 -0
- package/dist/next/jobs/job.d.ts +152 -0
- package/dist/next/jobs/job.d.ts.map +1 -0
- package/dist/next/jobs/job.js +320 -0
- package/dist/next/jobs/job.js.map +1 -0
- package/dist/next/jobs/persisted.d.ts +38 -0
- package/dist/next/jobs/persisted.d.ts.map +1 -0
- package/dist/next/jobs/persisted.js +95 -0
- package/dist/next/jobs/persisted.js.map +1 -0
- package/dist/next/jobs/records.d.ts +231 -0
- package/dist/next/jobs/records.d.ts.map +1 -0
- package/dist/next/jobs/records.js +869 -0
- package/dist/next/jobs/records.js.map +1 -0
- package/dist/next/jobs/run-states.d.ts +69 -0
- package/dist/next/jobs/run-states.d.ts.map +1 -0
- package/dist/next/jobs/run-states.js +228 -0
- package/dist/next/jobs/run-states.js.map +1 -0
- package/dist/next/jobs/run.d.ts +113 -0
- package/dist/next/jobs/run.d.ts.map +1 -0
- package/dist/next/jobs/run.js +200 -0
- package/dist/next/jobs/run.js.map +1 -0
- package/dist/next/jobs/running.d.ts +44 -0
- package/dist/next/jobs/running.d.ts.map +1 -0
- package/dist/next/jobs/running.js +117 -0
- package/dist/next/jobs/running.js.map +1 -0
- package/dist/next/jobs/stored.d.ts +63 -0
- package/dist/next/jobs/stored.d.ts.map +1 -0
- package/dist/next/jobs/stored.js +55 -0
- package/dist/next/jobs/stored.js.map +1 -0
- package/dist/next/link/binary.d.ts +4 -0
- package/dist/next/link/binary.d.ts.map +1 -0
- package/dist/next/link/binary.js +534 -0
- package/dist/next/link/binary.js.map +1 -0
- package/dist/next/link/channel.d.ts +63 -0
- package/dist/next/link/channel.d.ts.map +1 -0
- package/dist/next/link/channel.js +202 -0
- package/dist/next/link/channel.js.map +1 -0
- package/dist/next/link/errors.d.ts +7 -0
- package/dist/next/link/errors.d.ts.map +1 -0
- package/dist/next/link/errors.js +21 -0
- package/dist/next/link/errors.js.map +1 -0
- package/dist/next/link/index.d.ts +8 -0
- package/dist/next/link/index.d.ts.map +1 -0
- package/dist/next/link/index.js +8 -0
- package/dist/next/link/index.js.map +1 -0
- package/dist/next/link/internal.d.ts +9 -0
- package/dist/next/link/internal.d.ts.map +1 -0
- package/dist/next/link/internal.js +10 -0
- package/dist/next/link/internal.js.map +1 -0
- package/dist/next/link/ipc.d.ts +22 -0
- package/dist/next/link/ipc.d.ts.map +1 -0
- package/dist/next/link/ipc.js +64 -0
- package/dist/next/link/ipc.js.map +1 -0
- package/dist/next/link/link.d.ts +34 -0
- package/dist/next/link/link.d.ts.map +1 -0
- package/dist/next/link/link.js +87 -0
- package/dist/next/link/link.js.map +1 -0
- package/dist/next/link/message.d.ts +249 -0
- package/dist/next/link/message.d.ts.map +1 -0
- package/dist/next/link/message.js +123 -0
- package/dist/next/link/message.js.map +1 -0
- package/dist/next/link/part.d.ts +80 -0
- package/dist/next/link/part.d.ts.map +1 -0
- package/dist/next/link/part.js +164 -0
- package/dist/next/link/part.js.map +1 -0
- package/dist/next/link/text.d.ts +6 -0
- package/dist/next/link/text.d.ts.map +1 -0
- package/dist/next/link/text.js +335 -0
- package/dist/next/link/text.js.map +1 -0
- package/dist/next/link/values.d.ts +40 -0
- package/dist/next/link/values.d.ts.map +1 -0
- package/dist/next/link/values.js +117 -0
- package/dist/next/link/values.js.map +1 -0
- package/dist/next/link/websocket.d.ts +26 -0
- package/dist/next/link/websocket.d.ts.map +1 -0
- package/dist/next/link/websocket.js +91 -0
- package/dist/next/link/websocket.js.map +1 -0
- package/dist/next/registries/contribution.d.ts +50 -0
- package/dist/next/registries/contribution.d.ts.map +1 -0
- package/dist/next/registries/contribution.js +129 -0
- package/dist/next/registries/contribution.js.map +1 -0
- package/dist/next/registries/entries.d.ts +18 -0
- package/dist/next/registries/entries.d.ts.map +1 -0
- package/dist/next/registries/entries.js +42 -0
- package/dist/next/registries/entries.js.map +1 -0
- package/dist/next/registries/index.d.ts +3 -0
- package/dist/next/registries/index.d.ts.map +1 -0
- package/dist/next/registries/index.js +5 -0
- package/dist/next/registries/index.js.map +1 -0
- package/dist/next/registries/internal.d.ts +4 -0
- package/dist/next/registries/internal.d.ts.map +1 -0
- package/dist/next/registries/internal.js +5 -0
- package/dist/next/registries/internal.js.map +1 -0
- package/dist/next/registries/record.d.ts +94 -0
- package/dist/next/registries/record.d.ts.map +1 -0
- package/dist/next/registries/record.js +253 -0
- package/dist/next/registries/record.js.map +1 -0
- package/dist/next/registries/registry.d.ts +74 -0
- package/dist/next/registries/registry.d.ts.map +1 -0
- package/dist/next/registries/registry.js +14 -0
- package/dist/next/registries/registry.js.map +1 -0
- package/dist/next/registries/value.d.ts +48 -0
- package/dist/next/registries/value.d.ts.map +1 -0
- package/dist/next/registries/value.js +199 -0
- package/dist/next/registries/value.js.map +1 -0
- package/dist/next/remote/calls.d.ts +25 -0
- package/dist/next/remote/calls.d.ts.map +1 -0
- package/dist/next/remote/calls.js +62 -0
- package/dist/next/remote/calls.js.map +1 -0
- package/dist/next/remote/consumer.d.ts +42 -0
- package/dist/next/remote/consumer.d.ts.map +1 -0
- package/dist/next/remote/consumer.js +343 -0
- package/dist/next/remote/consumer.js.map +1 -0
- package/dist/next/remote/hold.d.ts +130 -0
- package/dist/next/remote/hold.d.ts.map +1 -0
- package/dist/next/remote/hold.js +537 -0
- package/dist/next/remote/hold.js.map +1 -0
- package/dist/next/remote/host-link.d.ts +77 -0
- package/dist/next/remote/host-link.d.ts.map +1 -0
- package/dist/next/remote/host-link.js +182 -0
- package/dist/next/remote/host-link.js.map +1 -0
- package/dist/next/remote/internal.d.ts +6 -0
- package/dist/next/remote/internal.d.ts.map +1 -0
- package/dist/next/remote/internal.js +6 -0
- package/dist/next/remote/internal.js.map +1 -0
- package/dist/next/remote/path.d.ts +46 -0
- package/dist/next/remote/path.d.ts.map +1 -0
- package/dist/next/remote/path.js +73 -0
- package/dist/next/remote/path.js.map +1 -0
- package/dist/next/remote/provider.d.ts +76 -0
- package/dist/next/remote/provider.d.ts.map +1 -0
- package/dist/next/remote/provider.js +506 -0
- package/dist/next/remote/provider.js.map +1 -0
- package/dist/next/remote/relay.d.ts +58 -0
- package/dist/next/remote/relay.d.ts.map +1 -0
- package/dist/next/remote/relay.js +117 -0
- package/dist/next/remote/relay.js.map +1 -0
- package/dist/next/remote/remote-object.d.ts +133 -0
- package/dist/next/remote/remote-object.d.ts.map +1 -0
- package/dist/next/remote/remote-object.js +411 -0
- package/dist/next/remote/remote-object.js.map +1 -0
- package/dist/next/remote/replica.d.ts +59 -0
- package/dist/next/remote/replica.d.ts.map +1 -0
- package/dist/next/remote/replica.js +125 -0
- package/dist/next/remote/replica.js.map +1 -0
- package/dist/next/state/batch.d.ts +64 -0
- package/dist/next/state/batch.d.ts.map +1 -0
- package/dist/next/state/batch.js +163 -0
- package/dist/next/state/batch.js.map +1 -0
- package/dist/next/state/derive.d.ts +52 -0
- package/dist/next/state/derive.d.ts.map +1 -0
- package/dist/next/state/derive.js +182 -0
- package/dist/next/state/derive.js.map +1 -0
- package/dist/next/state/index.d.ts +6 -0
- package/dist/next/state/index.d.ts.map +1 -0
- package/dist/next/state/index.js +4 -0
- package/dist/next/state/index.js.map +1 -0
- package/dist/next/state/internal.d.ts +6 -0
- package/dist/next/state/internal.d.ts.map +1 -0
- package/dist/next/state/internal.js +8 -0
- package/dist/next/state/internal.js.map +1 -0
- package/dist/next/state/native-source.d.ts +106 -0
- package/dist/next/state/native-source.d.ts.map +1 -0
- package/dist/next/state/native-source.js +240 -0
- package/dist/next/state/native-source.js.map +1 -0
- package/dist/next/state/watchable.d.ts +114 -0
- package/dist/next/state/watchable.d.ts.map +1 -0
- package/dist/next/state/watchable.js +156 -0
- package/dist/next/state/watchable.js.map +1 -0
- package/dist/next/state/writable.d.ts +32 -0
- package/dist/next/state/writable.d.ts.map +1 -0
- package/dist/next/state/writable.js +49 -0
- package/dist/next/state/writable.js.map +1 -0
- package/dist/next/store/adapter.d.ts +67 -0
- package/dist/next/store/adapter.d.ts.map +1 -0
- package/dist/next/store/adapter.js +118 -0
- package/dist/next/store/adapter.js.map +1 -0
- package/dist/next/store/allocator.d.ts +17 -0
- package/dist/next/store/allocator.d.ts.map +1 -0
- package/dist/next/store/allocator.js +30 -0
- package/dist/next/store/allocator.js.map +1 -0
- package/dist/next/store/applier.d.ts +8 -0
- package/dist/next/store/applier.d.ts.map +1 -0
- package/dist/next/store/applier.js +375 -0
- package/dist/next/store/applier.js.map +1 -0
- package/dist/next/store/apply-batch.d.ts +12 -0
- package/dist/next/store/apply-batch.d.ts.map +1 -0
- package/dist/next/store/apply-batch.js +83 -0
- package/dist/next/store/apply-batch.js.map +1 -0
- package/dist/next/store/archive.d.ts +32 -0
- package/dist/next/store/archive.d.ts.map +1 -0
- package/dist/next/store/archive.js +129 -0
- package/dist/next/store/archive.js.map +1 -0
- package/dist/next/store/backend.d.ts +10 -0
- package/dist/next/store/backend.d.ts.map +1 -0
- package/dist/next/store/backend.js +15 -0
- package/dist/next/store/backend.js.map +1 -0
- package/dist/next/store/catalog.d.ts +24 -0
- package/dist/next/store/catalog.d.ts.map +1 -0
- package/dist/next/store/catalog.js +17 -0
- package/dist/next/store/catalog.js.map +1 -0
- package/dist/next/store/claims.d.ts +23 -0
- package/dist/next/store/claims.d.ts.map +1 -0
- package/dist/next/store/claims.js +65 -0
- package/dist/next/store/claims.js.map +1 -0
- package/dist/next/store/columns.d.ts +77 -0
- package/dist/next/store/columns.d.ts.map +1 -0
- package/dist/next/store/columns.js +77 -0
- package/dist/next/store/columns.js.map +1 -0
- package/dist/next/store/engine.d.ts +176 -0
- package/dist/next/store/engine.d.ts.map +1 -0
- package/dist/next/store/engine.js +283 -0
- package/dist/next/store/engine.js.map +1 -0
- package/dist/next/store/evaluate.d.ts +17 -0
- package/dist/next/store/evaluate.d.ts.map +1 -0
- package/dist/next/store/evaluate.js +128 -0
- package/dist/next/store/evaluate.js.map +1 -0
- package/dist/next/store/export.d.ts +17 -0
- package/dist/next/store/export.d.ts.map +1 -0
- package/dist/next/store/export.js +200 -0
- package/dist/next/store/export.js.map +1 -0
- package/dist/next/store/expression.d.ts +150 -0
- package/dist/next/store/expression.d.ts.map +1 -0
- package/dist/next/store/expression.js +268 -0
- package/dist/next/store/expression.js.map +1 -0
- package/dist/next/store/import.d.ts +10 -0
- package/dist/next/store/import.d.ts.map +1 -0
- package/dist/next/store/import.js +276 -0
- package/dist/next/store/import.js.map +1 -0
- package/dist/next/store/index.d.ts +16 -0
- package/dist/next/store/index.d.ts.map +1 -0
- package/dist/next/store/index.js +13 -0
- package/dist/next/store/index.js.map +1 -0
- package/dist/next/store/json-column.d.ts +33 -0
- package/dist/next/store/json-column.d.ts.map +1 -0
- package/dist/next/store/json-column.js +61 -0
- package/dist/next/store/json-column.js.map +1 -0
- package/dist/next/store/jsonl.d.ts +9 -0
- package/dist/next/store/jsonl.d.ts.map +1 -0
- package/dist/next/store/jsonl.js +61 -0
- package/dist/next/store/jsonl.js.map +1 -0
- package/dist/next/store/outbox.d.ts +26 -0
- package/dist/next/store/outbox.d.ts.map +1 -0
- package/dist/next/store/outbox.js +80 -0
- package/dist/next/store/outbox.js.map +1 -0
- package/dist/next/store/query.d.ts +39 -0
- package/dist/next/store/query.d.ts.map +1 -0
- package/dist/next/store/query.js +97 -0
- package/dist/next/store/query.js.map +1 -0
- package/dist/next/store/refusal.d.ts +15 -0
- package/dist/next/store/refusal.d.ts.map +1 -0
- package/dist/next/store/refusal.js +36 -0
- package/dist/next/store/refusal.js.map +1 -0
- package/dist/next/store/rows.d.ts +80 -0
- package/dist/next/store/rows.d.ts.map +1 -0
- package/dist/next/store/rows.js +183 -0
- package/dist/next/store/rows.js.map +1 -0
- package/dist/next/store/schema.d.ts +25 -0
- package/dist/next/store/schema.d.ts.map +1 -0
- package/dist/next/store/schema.js +115 -0
- package/dist/next/store/schema.js.map +1 -0
- package/dist/next/store/sql.d.ts +73 -0
- package/dist/next/store/sql.d.ts.map +1 -0
- package/dist/next/store/sql.js +234 -0
- package/dist/next/store/sql.js.map +1 -0
- package/dist/next/store/step.d.ts +48 -0
- package/dist/next/store/step.d.ts.map +1 -0
- package/dist/next/store/step.js +50 -0
- package/dist/next/store/step.js.map +1 -0
- package/dist/next/store/store.d.ts +161 -0
- package/dist/next/store/store.d.ts.map +1 -0
- package/dist/next/store/store.js +627 -0
- package/dist/next/store/store.js.map +1 -0
- package/dist/next/store/table-changes.d.ts +29 -0
- package/dist/next/store/table-changes.d.ts.map +1 -0
- package/dist/next/store/table-changes.js +102 -0
- package/dist/next/store/table-changes.js.map +1 -0
- package/dist/next/store/table-evolve.d.ts +74 -0
- package/dist/next/store/table-evolve.d.ts.map +1 -0
- package/dist/next/store/table-evolve.js +201 -0
- package/dist/next/store/table-evolve.js.map +1 -0
- package/dist/next/store/table-handle.d.ts +67 -0
- package/dist/next/store/table-handle.d.ts.map +1 -0
- package/dist/next/store/table-handle.js +101 -0
- package/dist/next/store/table-handle.js.map +1 -0
- package/dist/next/store/table-history.d.ts +75 -0
- package/dist/next/store/table-history.d.ts.map +1 -0
- package/dist/next/store/table-history.js +42 -0
- package/dist/next/store/table-history.js.map +1 -0
- package/dist/next/store/table-migration.d.ts +16 -0
- package/dist/next/store/table-migration.d.ts.map +1 -0
- package/dist/next/store/table-migration.js +202 -0
- package/dist/next/store/table-migration.js.map +1 -0
- package/dist/next/store/table-writes.d.ts +125 -0
- package/dist/next/store/table-writes.d.ts.map +1 -0
- package/dist/next/store/table-writes.js +165 -0
- package/dist/next/store/table-writes.js.map +1 -0
- package/dist/next/store/table.d.ts +80 -0
- package/dist/next/store/table.d.ts.map +1 -0
- package/dist/next/store/table.js +103 -0
- package/dist/next/store/table.js.map +1 -0
- package/dist/next/store/text.d.ts +14 -0
- package/dist/next/store/text.d.ts.map +1 -0
- package/dist/next/store/text.js +51 -0
- package/dist/next/store/text.js.map +1 -0
- package/dist/next/store/writes.d.ts +5 -0
- package/dist/next/store/writes.d.ts.map +1 -0
- package/dist/next/store/writes.js +4 -0
- package/dist/next/store/writes.js.map +1 -0
- package/dist/next-node/compression.d.ts +7 -0
- package/dist/next-node/compression.d.ts.map +1 -0
- package/dist/next-node/compression.js +24 -0
- package/dist/next-node/compression.js.map +1 -0
- package/dist/next-node/http/admission.d.ts +63 -0
- package/dist/next-node/http/admission.d.ts.map +1 -0
- package/dist/next-node/http/admission.js +134 -0
- package/dist/next-node/http/admission.js.map +1 -0
- package/dist/next-node/http/authenticate.d.ts +21 -0
- package/dist/next-node/http/authenticate.d.ts.map +1 -0
- package/dist/next-node/http/authenticate.js +34 -0
- package/dist/next-node/http/authenticate.js.map +1 -0
- package/dist/next-node/http/cookies.d.ts +24 -0
- package/dist/next-node/http/cookies.d.ts.map +1 -0
- package/dist/next-node/http/cookies.js +62 -0
- package/dist/next-node/http/cookies.js.map +1 -0
- package/dist/next-node/http/file.d.ts +23 -0
- package/dist/next-node/http/file.d.ts.map +1 -0
- package/dist/next-node/http/file.js +94 -0
- package/dist/next-node/http/file.js.map +1 -0
- package/dist/next-node/http/headers.d.ts +37 -0
- package/dist/next-node/http/headers.d.ts.map +1 -0
- package/dist/next-node/http/headers.js +129 -0
- package/dist/next-node/http/headers.js.map +1 -0
- package/dist/next-node/http/http.d.ts +100 -0
- package/dist/next-node/http/http.d.ts.map +1 -0
- package/dist/next-node/http/http.js +462 -0
- package/dist/next-node/http/http.js.map +1 -0
- package/dist/next-node/http/incoming.d.ts +19 -0
- package/dist/next-node/http/incoming.d.ts.map +1 -0
- package/dist/next-node/http/incoming.js +31 -0
- package/dist/next-node/http/incoming.js.map +1 -0
- package/dist/next-node/http/index.d.ts +11 -0
- package/dist/next-node/http/index.d.ts.map +1 -0
- package/dist/next-node/http/index.js +12 -0
- package/dist/next-node/http/index.js.map +1 -0
- package/dist/next-node/http/node.d.ts +78 -0
- package/dist/next-node/http/node.d.ts.map +1 -0
- package/dist/next-node/http/node.js +291 -0
- package/dist/next-node/http/node.js.map +1 -0
- package/dist/next-node/http/request.d.ts +54 -0
- package/dist/next-node/http/request.d.ts.map +1 -0
- package/dist/next-node/http/request.js +116 -0
- package/dist/next-node/http/request.js.map +1 -0
- package/dist/next-node/http/response.d.ts +63 -0
- package/dist/next-node/http/response.d.ts.map +1 -0
- package/dist/next-node/http/response.js +202 -0
- package/dist/next-node/http/response.js.map +1 -0
- package/dist/next-node/http/router.d.ts +114 -0
- package/dist/next-node/http/router.d.ts.map +1 -0
- package/dist/next-node/http/router.js +261 -0
- package/dist/next-node/http/router.js.map +1 -0
- package/dist/next-node/http/upgrades.d.ts +58 -0
- package/dist/next-node/http/upgrades.d.ts.map +1 -0
- package/dist/next-node/http/upgrades.js +184 -0
- package/dist/next-node/http/upgrades.js.map +1 -0
- package/dist/next-node/plugins/build.d.ts +57 -0
- package/dist/next-node/plugins/build.d.ts.map +1 -0
- package/dist/next-node/plugins/build.js +334 -0
- package/dist/next-node/plugins/build.js.map +1 -0
- package/dist/next-node/plugins/discover.d.ts +36 -0
- package/dist/next-node/plugins/discover.d.ts.map +1 -0
- package/dist/next-node/plugins/discover.js +91 -0
- package/dist/next-node/plugins/discover.js.map +1 -0
- package/dist/next-node/plugins/evaluate.d.ts +33 -0
- package/dist/next-node/plugins/evaluate.d.ts.map +1 -0
- package/dist/next-node/plugins/evaluate.js +98 -0
- package/dist/next-node/plugins/evaluate.js.map +1 -0
- package/dist/next-node/plugins/index.d.ts +9 -0
- package/dist/next-node/plugins/index.d.ts.map +1 -0
- package/dist/next-node/plugins/index.js +11 -0
- package/dist/next-node/plugins/index.js.map +1 -0
- package/dist/next-node/plugins/install.d.ts +13 -0
- package/dist/next-node/plugins/install.d.ts.map +1 -0
- package/dist/next-node/plugins/install.js +37 -0
- package/dist/next-node/plugins/install.js.map +1 -0
- package/dist/next-node/plugins/plugins.d.ts +135 -0
- package/dist/next-node/plugins/plugins.d.ts.map +1 -0
- package/dist/next-node/plugins/plugins.js +206 -0
- package/dist/next-node/plugins/plugins.js.map +1 -0
- package/dist/next-node/plugins/runtime.d.ts +41 -0
- package/dist/next-node/plugins/runtime.d.ts.map +1 -0
- package/dist/next-node/plugins/runtime.js +136 -0
- package/dist/next-node/plugins/runtime.js.map +1 -0
- package/dist/next-node/plugins/stack.d.ts +16 -0
- package/dist/next-node/plugins/stack.d.ts.map +1 -0
- package/dist/next-node/plugins/stack.js +61 -0
- package/dist/next-node/plugins/stack.js.map +1 -0
- package/dist/next-node/plugins/watcher.d.ts +58 -0
- package/dist/next-node/plugins/watcher.d.ts.map +1 -0
- package/dist/next-node/plugins/watcher.js +281 -0
- package/dist/next-node/plugins/watcher.js.map +1 -0
- package/dist/next-node/workers/control.d.ts +83 -0
- package/dist/next-node/workers/control.d.ts.map +1 -0
- package/dist/next-node/workers/control.js +77 -0
- package/dist/next-node/workers/control.js.map +1 -0
- package/dist/next-node/workers/index.d.ts +5 -0
- package/dist/next-node/workers/index.d.ts.map +1 -0
- package/dist/next-node/workers/index.js +7 -0
- package/dist/next-node/workers/index.js.map +1 -0
- package/dist/next-node/workers/lock.d.ts +21 -0
- package/dist/next-node/workers/lock.d.ts.map +1 -0
- package/dist/next-node/workers/lock.js +137 -0
- package/dist/next-node/workers/lock.js.map +1 -0
- package/dist/next-node/workers/main.d.ts +46 -0
- package/dist/next-node/workers/main.d.ts.map +1 -0
- package/dist/next-node/workers/main.js +230 -0
- package/dist/next-node/workers/main.js.map +1 -0
- package/dist/next-node/workers/process.d.ts +42 -0
- package/dist/next-node/workers/process.d.ts.map +1 -0
- package/dist/next-node/workers/process.js +125 -0
- package/dist/next-node/workers/process.js.map +1 -0
- package/dist/next-node/workers/workers.d.ts +80 -0
- package/dist/next-node/workers/workers.d.ts.map +1 -0
- package/dist/next-node/workers/workers.js +572 -0
- package/dist/next-node/workers/workers.js.map +1 -0
- package/dist/object.d.ts +4 -4
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +3 -4
- package/dist/object.js.map +1 -1
- package/dist/output.d.ts +1 -1
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +4 -2
- package/dist/output.js.map +1 -1
- package/dist/remote.d.ts.map +1 -1
- package/dist/remote.js +2 -2
- package/dist/remote.js.map +1 -1
- package/dist/schema.d.ts +8 -4
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +180 -5
- package/dist/schema.js.map +1 -1
- package/dist/sqlite/cloudflare.d.ts +2 -0
- package/dist/sqlite/cloudflare.d.ts.map +1 -1
- package/dist/sqlite/cloudflare.js +10 -0
- package/dist/sqlite/cloudflare.js.map +1 -1
- package/dist/sqlite/database.d.ts +5 -2
- package/dist/sqlite/database.d.ts.map +1 -1
- package/dist/sqlite/database.js.map +1 -1
- package/dist/sqlite/node.d.ts +4 -1
- package/dist/sqlite/node.d.ts.map +1 -1
- package/dist/sqlite/node.js +22 -5
- package/dist/sqlite/node.js.map +1 -1
- package/dist/watch.d.ts +194 -0
- package/dist/watch.d.ts.map +1 -0
- package/dist/watch.js +383 -0
- package/dist/watch.js.map +1 -0
- package/dist/wire.d.ts +174 -193
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +81 -80
- package/dist/wire.js.map +1 -1
- package/docs/guide.md +15 -15
- package/docs/next/benchmarks.md +959 -0
- package/docs/next/decisions.md +2957 -0
- package/docs/next/dependencies/book.md +1671 -0
- package/docs/next/dependencies/index.html +2641 -0
- package/docs/next/dependencies/model.md +330 -0
- package/docs/next/design.md +2554 -0
- package/docs/next/durable-observers/book.md +432 -0
- package/docs/next/durable-observers/index.html +517 -0
- package/docs/next/flow-control/book.md +333 -0
- package/docs/next/flow-control/fold/index.html +265 -0
- package/docs/next/flow-control/index.html +548 -0
- package/docs/next/flow-control/window/index.html +228 -0
- package/docs/next/guide-plugins-hosts/book.md +607 -0
- package/docs/next/guide-plugins-hosts/index.html +652 -0
- package/docs/next/http-workers/book.md +378 -0
- package/docs/next/http-workers/index.html +515 -0
- package/docs/next/layer-1.md +311 -0
- package/docs/next/layer-2.md +216 -0
- package/docs/next/plugin-model/book.md +186 -0
- package/docs/next/plugin-model/index.html +310 -0
- package/docs/next/plugin-primer/book.md +273 -0
- package/docs/next/plugin-primer/index.html +430 -0
- package/docs/next/slice-1.md +236 -0
- package/docs/next/slice-10.md +285 -0
- package/docs/next/slice-11.md +93 -0
- package/docs/next/slice-2.md +174 -0
- package/docs/next/slice-3a.md +296 -0
- package/docs/next/slice-3b.md +197 -0
- package/docs/next/slice-4.md +146 -0
- package/docs/next/slice-4a.md +418 -0
- package/docs/next/slice-4b.md +208 -0
- package/docs/next/slice-5.md +281 -0
- package/docs/next/slice-6a.md +676 -0
- package/docs/next/slice-6b.md +332 -0
- package/docs/next/slice-7a.md +130 -0
- package/docs/next/slice-7b/book.md +608 -0
- package/docs/next/slice-7b/index.html +842 -0
- package/docs/next/slice-7b.md +255 -0
- package/docs/next/slice-7c.md +165 -0
- package/docs/next/slice-8.md +194 -0
- package/docs/next/slices.md +230 -0
- package/docs/next/store/book.md +665 -0
- package/docs/next/store/index.html +861 -0
- package/docs/next/store/walkthrough.md +193 -0
- package/docs/spec.md +9 -9
- package/docs/tutorial.md +26 -25
- package/package.json +22 -6
- package/src/delta/README.md +69 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# L1: data and contracts (spec)
|
|
2
|
+
|
|
3
|
+
Status: **approved (owner, 2026-10-22)**, rewritten 2026-10-22 as the single source for a from-scratch implementation
|
|
4
|
+
(the first implementation was discarded for code quality). Every rule here is decided; the decision log
|
|
5
|
+
(`packages/chord/docs/next/decisions.md`) has the reasons. Code style: the section "Chord v2 Code Style" of the root
|
|
6
|
+
`AGENTS.md`.
|
|
7
|
+
|
|
8
|
+
## What L1 is
|
|
9
|
+
|
|
10
|
+
Everything about **data** that the upper layers need and that does not depend on hosts, objects or links: how an
|
|
11
|
+
object type is declared and evolves (contracts), what a value is, how params become an identity, how arguments are
|
|
12
|
+
checked, what a principal key is, what an error is. Pure functions, types and weak caches; no I/O.
|
|
13
|
+
|
|
14
|
+
Source: `packages/chord/src/next/contracts/` (declarations) and `packages/chord/src/next/data/` (per-call checks,
|
|
15
|
+
principals, errors), split into files by concept. Everything else under `src/next/` is the frozen old kernel: never
|
|
16
|
+
imported, never edited. Reused: `src/context/` (`Context`, `BACKGROUND_CONTEXT`, `context.telemetry`) and
|
|
17
|
+
`src/json.ts` (`JsonValue`), both unchanged. Schemas were TypeBox 1.3 when L1 was built; since the schema switch (2026-11-01) they are pi-schema's plain JSON Schema (design §3 "Values"). The TypeBox details below are historical.
|
|
18
|
+
|
|
19
|
+
## 1. Values
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
type Value = null | boolean | number | string | Uint8Array | Value[] | { [key: string]: Value };
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- JSON plus byte leaves. No `undefined` inside values, no non-finite numbers, no foreign prototypes, no accessors.
|
|
26
|
+
- Values from links are already strict JSON plus bytes; values from same-host code are plain data **by convention**,
|
|
27
|
+
immutable once handed over. L1 never walks, copies or freezes a value to enforce that. State is never checked.
|
|
28
|
+
- `canonicalJson(value: JsonValue, context)`: sorted object keys, `-0` written as `0`. Used only for principal and
|
|
29
|
+
revocation keys, which are JSON (no bytes), so it lives with principals.
|
|
30
|
+
|
|
31
|
+
## 2. Contracts: declarations
|
|
32
|
+
|
|
33
|
+
A contract is the declared type of an object: name, kind, version, params, members. Two kinds:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
const Notes = remote("notes", {
|
|
37
|
+
version: 1,
|
|
38
|
+
params: { session: str() },
|
|
39
|
+
variants: {
|
|
40
|
+
editor: { state: { notes: arr(Note) }, methods: { add: method(obj({ text: str() }), str()), clear: method() } },
|
|
41
|
+
reader: { state: { notes: arr(PublicNote) } },
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
const Info = local("app.session-info", {
|
|
45
|
+
version: 1,
|
|
46
|
+
params: {},
|
|
47
|
+
members: { init: obj({ title: str() }), clear: method() }, // a schema is state, method(...) is a method
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- `remote` has variants (per-principal views, at least one); `local` has one flat `members` map and no variants.
|
|
52
|
+
- `method()`, `method(args)`, `method(args, result)`, `method(undefined, result)`. An omitted side is `null` on the
|
|
53
|
+
wire: a no-argument method is called with `null`.
|
|
54
|
+
- **Variants (D11):** a member name has the same kind (state or method) in every variant that has it; a method has the
|
|
55
|
+
same signature (args and result) in every variant; state schemas may differ per variant (redaction). Enforced in the
|
|
56
|
+
types of `remote(...)` and at declaration (for untyped callers).
|
|
57
|
+
- **Closed argument objects (Q12):** every object schema inside a method's arguments sets
|
|
58
|
+
`additionalProperties: false`, nested ones included, raw `Type.Object` included; record schemas (`map`) are allowed.
|
|
59
|
+
Checked once per declared or edited method, at declaration. `obj()` always produces closed objects and cannot be
|
|
60
|
+
opened.
|
|
61
|
+
- Declaration checks (the types cannot express them for JavaScript callers): nonempty name, version a positive safe
|
|
62
|
+
integer, no unknown declaration keys, params policy (section 4), D11, closed arguments, the schema vocabulary
|
|
63
|
+
(below). Each fails with an `Error` naming the path (`notes.editor.methods.add.args`).
|
|
64
|
+
- Declarations are immutable by convention: a contract holds Chord-owned snapshots of its schemas (copied once at
|
|
65
|
+
declaration, so later changes to the app's schema objects cannot desync validation from the fingerprint), never the
|
|
66
|
+
app's schema objects. Nothing in L1 is frozen (owner, 2026-10-22). Contracts are branded: hand-built or spread copies are refused by `evolve`, `checkAccepts`
|
|
67
|
+
and `bindProvider` (a private `WeakMap` from contract to its data).
|
|
68
|
+
- **Placement** is not part of L1 contracts: the `placement` field arrives with host kinds (L7) and is never part of
|
|
69
|
+
the fingerprint.
|
|
70
|
+
|
|
71
|
+
### Schema helpers
|
|
72
|
+
|
|
73
|
+
`str({ min, max, pattern })`, `num({ min, max })`, `int({ min, max })`, `bool()`, `nul()`, `lit(v)`, `oneOf(...literals)`,
|
|
74
|
+
`union([...])`, `obj(props)`, `arr(items, { min, max })`, `map(value)` (string-keyed record), `opt(schema)`,
|
|
75
|
+
`bytes({ min, max })`, `unknown()`, and `type Static`. They return ordinary TypeBox schemas, so `Static` and TypeBox's
|
|
76
|
+
compiler work unchanged. `min`/`max` mean string length, numeric bounds or array length.
|
|
77
|
+
|
|
78
|
+
`bytes()` is a `Uint8Array` leaf with optional length bounds, checked by `instanceof` and length, never enumerated.
|
|
79
|
+
Its enumerable form is the data marker `{ type: "bytes", minLength?, maxLength? }`; the TypeBox check is attached
|
|
80
|
+
non-enumerably and rebuilt from the marker whenever a schema is snapshotted, so no callback is ever copied from app
|
|
81
|
+
data.
|
|
82
|
+
|
|
83
|
+
**Vocabulary (rejected at declaration otherwise):** data primitives, arrays and tuples, objects and records, unions and
|
|
84
|
+
intersections, `$defs`/`$ref` (use `$ref` for recursion), constraints (`pattern`, `format`, bounds, `multipleOf`,
|
|
85
|
+
`uniqueItems`, property counts), `default`, `readOnly`/`writeOnly`, annotations, bytes. Rejected: conditional and
|
|
86
|
+
dependent schemas, `not`, `contains`, `propertyNames`, `unevaluated*`, `contentSchema`, `definitions`, unknown
|
|
87
|
+
keywords, TypeBox's executable features (`Unsafe` other than bytes, refinements, transforms), accessors, symbol keys,
|
|
88
|
+
cyclic objects, non-JSON data.
|
|
89
|
+
|
|
90
|
+
### Fingerprint
|
|
91
|
+
|
|
92
|
+
Every version gets a fingerprint at declaration: `hash64` (a portable 64-bit hash, two FNV-style lanes, 16 hex
|
|
93
|
+
characters; not a security boundary) of `JSON.stringify({ normalFormVersion, value })` over a **normal form**:
|
|
94
|
+
|
|
95
|
+
- object keys sorted; `required` and `enum` sorted; union, intersection and tuple order **kept** (it is meaning);
|
|
96
|
+
- annotations dropped on schema nodes only (`title`, `description`, `examples`, `$comment`, `deprecated`); defaults,
|
|
97
|
+
formats, patterns, bounds and `additionalProperties` kept;
|
|
98
|
+
- params as ordered `[fieldName, schema]` pairs (declaration order is identity order); members as sorted dictionaries;
|
|
99
|
+
- `{ kind: "remote", params, variants }` or `{ kind: "local", params, members }`; placement excluded.
|
|
100
|
+
|
|
101
|
+
`NORMAL_FORM_VERSION = 2` is exported; changing the normal form changes it and is a link-protocol change.
|
|
102
|
+
One schema-aware walk produces both the snapshot and the normal form.
|
|
103
|
+
|
|
104
|
+
### Evolution (Q10)
|
|
105
|
+
|
|
106
|
+
A history starts with a base written in full (`remote()`/`local()` with an explicit version). `evolve(prev, (e) =>
|
|
107
|
+
e...)` appends the next version (`prev.version + 1`) with structured edits:
|
|
108
|
+
|
|
109
|
+
| Edit | Meaning |
|
|
110
|
+
| --- | --- |
|
|
111
|
+
| `state(variant, name, schema)` | change one state member (local: `state(name, schema)`) |
|
|
112
|
+
| `addState(variant, name, schema)` | add a state member |
|
|
113
|
+
| `removeState(variant, name)` | remove a state member |
|
|
114
|
+
| `args(name, schema)`, `result(name, schema)` | change one side of a method in every variant that has it |
|
|
115
|
+
| `method(name, args, result)` | replace both sides |
|
|
116
|
+
| `addMethod(variant, name, args, result)` | add a method (local: no variant); to another variant only with the same signature |
|
|
117
|
+
| `removeMethod(name)` | remove a method from every variant |
|
|
118
|
+
|
|
119
|
+
- Params and the variant set never change by evolution. A change to either is a **new history base**: a new full
|
|
120
|
+
declaration with an explicit version and no accepted older versions.
|
|
121
|
+
- A member's kind never changes, also not after a removal and re-add. Checks run after every edit.
|
|
122
|
+
- `evolve` must return the builder it was given (no foreign builders). Every version is materialized and
|
|
123
|
+
fingerprinted at declaration, so an old plugin's copy of v1 has the same fingerprint as the history's v1.
|
|
124
|
+
- The types track the whole history: `Contract` carries the version, the current description and every step with its
|
|
125
|
+
edits, so `checkAccepts` can require exactly the right mappings at compile time.
|
|
126
|
+
|
|
127
|
+
### Accepted versions and mappings
|
|
128
|
+
|
|
129
|
+
A provider may accept older versions of its contract with mappings it owns:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
const NotesV2 = evolve(NotesV1, (e) => e.state("editor", "notes", arr(NoteV2)).args("add", NoteV2));
|
|
133
|
+
const accepts = {
|
|
134
|
+
1: {
|
|
135
|
+
state: { editor: { notes: (current) => current.map(toV1) } }, // current member -> old member
|
|
136
|
+
methods: { add: { args: (old) => toV2(old) } }, // old args -> current args
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
checkAccepts(NotesV2, accepts); // { versions: [{ version: 1, fingerprint }] }
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`checkAccepts(contract, accepts)` is pure: it validates the table without calling any mapping and returns the accepted
|
|
143
|
+
versions with their fingerprints. Mappings are **direct** (old to current, never chained). For accepted version `v`,
|
|
144
|
+
considering every edit after `v`, a mapping is required exactly for:
|
|
145
|
+
|
|
146
|
+
- a changed state member: `(currentMember) => oldMember`;
|
|
147
|
+
- a removed state member: `(currentVariantState) => oldMember` (the whole current state of that variant), or
|
|
148
|
+
`"refuse"`;
|
|
149
|
+
- a method whose args changed: `{ args: (old) => current }`; whose result changed: `{ result: (current) => old }`;
|
|
150
|
+
both: both functions;
|
|
151
|
+
- a removed method (from any variant that had it in `v`): `{ call: async (oldArgs, context) => oldResult }` or
|
|
152
|
+
`"refuse"`; `call` and `"refuse"` are also allowed for changed methods.
|
|
153
|
+
|
|
154
|
+
Added members need nothing. No-op edits and changes made and reverted still require (identity) mappings: the check is
|
|
155
|
+
by edit, not by schema comparison. Unknown versions, the current version, missing mappings, unnecessary keys and wrong
|
|
156
|
+
shapes fail at declaration with the path (`notes accepts[1].methods.add`). An absent `state` or `methods` section means
|
|
157
|
+
empty and is allowed only when nothing is required there. The same rules hold at the type level (`AcceptsTable`).
|
|
158
|
+
|
|
159
|
+
`Implementation<typeof Contract>` derives the provider's shape: per variant, state getters `() => value`; methods
|
|
160
|
+
`(args, context) => Promise<result>`.
|
|
161
|
+
|
|
162
|
+
## 3. Principals
|
|
163
|
+
|
|
164
|
+
- The app's principal type `P` is plain JSON with a `kind` field: no schema, no version, never persisted by Chord
|
|
165
|
+
(objects persist their own projection, e.g. chat's `Author`).
|
|
166
|
+
- `principalKey(principal, context, customKey?)`: default `canonicalJson(principal)`; an app may pass its own key
|
|
167
|
+
function, which must be the same on every host. Cached per principal object in `WeakMap`s; a custom key function's
|
|
168
|
+
cache is keyed by the function too, so a dropped function is never retained by a live principal.
|
|
169
|
+
- `revocationKeys(principal, revokedBy, context)`: the canonical JSON of each JSON value `revokedBy(principal)`
|
|
170
|
+
returns (`host.revoke` is L7).
|
|
171
|
+
|
|
172
|
+
## 4. Params and identity
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
const { params, key } = checkParams(Notes, { session: "S1" }, context); // throws invalid/params
|
|
176
|
+
const identity = identityKey(Notes, key, principalKey(principal)); // "notes|S1|<principal key>"
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
- Declaration policy: params are a flat record of required fields, each `str()`, `int()`, `bool()` or a union of
|
|
180
|
+
string literals (`oneOf("chat", "agent")`), constraints allowed; no defaults, optional, nested, bytes, numbers other
|
|
181
|
+
than integers. Checked in the types and at declaration.
|
|
182
|
+
- `checkParams(contract, raw, context)`: one compiled closed-object check of `raw` (constraints enforced), the compiled
|
|
183
|
+
validator cached per contract in a `WeakMap`. Then the key is the field values in declared order, each escaped
|
|
184
|
+
(`\` and `|`), joined with `|`. It returns the caller's own object: no pre-check walk, no copy, no freeze.
|
|
185
|
+
- `identityKey(contract, key, principalKey)`: `name|key|principalKey`, each part escaped; `local` takes no principal
|
|
186
|
+
key (by type). The key is an in-process map key; links carry the params themselves.
|
|
187
|
+
|
|
188
|
+
## 5. Arguments
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
const provider = bindProvider(NotesV2, accepts); // once per registration and reload
|
|
192
|
+
const checked = checkArgs(provider, "add", raw, boundVersion, ctx); // invalid/args with path
|
|
193
|
+
// { kind: "method"; args (current shape); result?: (current) => old } | { kind: "call"; args (old shape); call }
|
|
194
|
+
checkArgs(provider, "clear", null, 2, ctx); // no-argument methods take null
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
- `bindProvider(contract, accepts)` runs `checkAccepts` once and keeps the app's accepts table as it is (immutable by
|
|
198
|
+
convention; no copy, no freeze). It builds a private dispatch table, held in a `WeakMap` keyed by the returned
|
|
199
|
+
provider: accepted version -> method -> `{ schema, validator, mapping }`. Validators compile on first use per
|
|
200
|
+
(version, method); a weak cache keyed by schema object lets equal schema objects share a compiled validator.
|
|
201
|
+
- `checkArgs(provider, method, raw, boundVersion, context)`: three map lookups, one compiled check against the
|
|
202
|
+
provider's schema for that version, then at most one direct `args` mapping old -> current. It returns a tagged
|
|
203
|
+
value (owner, 2026-10-22): `{ kind: "method"; args; result? }` (args in the current shape; `result` maps the current
|
|
204
|
+
result back for an old-version caller) or `{ kind: "call"; args; call }` (a replaced method: the checked old args
|
|
205
|
+
and the provider's `call`, which L4 invokes). Current-version calls are never mapped. Unknown method:
|
|
206
|
+
`invalid/member`. Version not accepted, or `"refuse"`: `contract_mismatch`. Mapping output is trusted.
|
|
207
|
+
- Every caller is checked, `local` included (Q15). Unknown fields fail (closed schemas); nothing is stripped, copied,
|
|
208
|
+
frozen or defaulted. Results and state are never checked.
|
|
209
|
+
- Memory: a binding lives as long as its registration and the calls in flight. No module-level strong cache holds a
|
|
210
|
+
contract, binding, schema or validator.
|
|
211
|
+
- TypeBox keeps its last build in module-level accumulators: after every `Compile`, reset them (`ResetFunctions`,
|
|
212
|
+
`ResetExternal`, in `finally`), so no build state is retained.
|
|
213
|
+
|
|
214
|
+
### A failed check
|
|
215
|
+
|
|
216
|
+
A failed compiled check uses TypeBox's public `Errors(schema, value)` and reports the first error. The error is
|
|
217
|
+
`invalid/args` or `invalid/params`, message `args/text: <TypeBox's message>` (fixed text for the two common cases:
|
|
218
|
+
`args/extra: unknown field`, `args/text: missing`), `details: { path }` with TypeBox's
|
|
219
|
+
instance path (`/text`, `/` for the root), including missing (`required`) and unknown (`additionalProperties`)
|
|
220
|
+
fields at their own path. TypeBox does not escape `/` and `~` inside keys, so a key containing them makes the path
|
|
221
|
+
ambiguous (owner, 2026-10-22: accepted; it is a diagnostic).
|
|
222
|
+
|
|
223
|
+
## 6. Errors
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
type ChordErrorCode = "invalid" | "contract_mismatch" | "forbidden" | "gone" | "not_ready" | "released"
|
|
227
|
+
| "too_large" | "unavailable" | "aborted";
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
| Code | Reasons |
|
|
231
|
+
| --- | --- |
|
|
232
|
+
| `invalid` | required: `args`, `params`, `member`, `placement`, `reentrant`, `read_after_bulk`, `cycle` |
|
|
233
|
+
| `contract_mismatch` | optional: `updating` |
|
|
234
|
+
| `unavailable` | optional: `locked`, `park_timeout` |
|
|
235
|
+
| `too_large` | optional: `part` |
|
|
236
|
+
| others | none |
|
|
237
|
+
|
|
238
|
+
- One `ChordError` class (an `Error`), with `code`, `reason`, `message`, `details?: JsonValue`. The constructor,
|
|
239
|
+
instances and JSON form are tagged unions: a wrong pairing is a type error, and narrowing on `code` narrows
|
|
240
|
+
`reason`. `toJSON()` emits `{ code, reason?, message, details? }`; stack and cause never cross the wire.
|
|
241
|
+
- `PROTOCOL_VERSION = 1` is exported. Reasons and pairings are link protocol: adding or moving one bumps it. A test
|
|
242
|
+
pins the table together with the version and fails with "bump PROTOCOL_VERSION" when they diverge. L6 compares the
|
|
243
|
+
version in the handshake before accepting anything.
|
|
244
|
+
- `chordErrorFromJson(raw)`: `raw` is fresh JSON from the link decoder (a trust boundary). Checks the envelope only:
|
|
245
|
+
known code, a reason allowed for that code (required for `invalid`), string message, no other keys. `details` is
|
|
246
|
+
kept by reference: no walk, no copy, no counters.
|
|
247
|
+
- Helpers: `isChordError(error, code?)`, `invalid(reason, message, details?)`, `asChordError(error, label)` (wraps a
|
|
248
|
+
foreign error as `unavailable`).
|
|
249
|
+
- `FailureCause = { kind: "transient"; error } | { kind: "broken"; error }`: the failing stage decides, never the
|
|
250
|
+
error code. `broken(cause)` marks an open's failure as broken (bad configuration); `openFailure(cause, label)` turns
|
|
251
|
+
an open's thrown value into the cause. Used by L4.
|
|
252
|
+
- Plugin errors have their own shape (L4); they never use Chord reasons.
|
|
253
|
+
|
|
254
|
+
## Cost per hop
|
|
255
|
+
|
|
256
|
+
| Hop | Work |
|
|
257
|
+
| --- | --- |
|
|
258
|
+
| a `get` | one compiled closed-object check, one joined key; no walk, no copy |
|
|
259
|
+
| a call | three map lookups, one compiled check, at most one direct mapping; no copy |
|
|
260
|
+
| first `get` of a contract | one compilation |
|
|
261
|
+
| first call per accepted version and method | one compilation (or a cache hit by schema object) |
|
|
262
|
+
| a failed check | one counted diagnostic walk (`Errors` builds the whole list on this rare path) |
|
|
263
|
+
| a first default principal key, a revocation key | one canonical walk |
|
|
264
|
+
| declaration | snapshot, closure check per method, fingerprint per version |
|
|
265
|
+
| binding | `checkAccepts` once, dispatch table built, nothing compiled |
|
|
266
|
+
| a state change | nothing in L1 |
|
|
267
|
+
|
|
268
|
+
**Counters:** `chord.data.walks`, `chord.data.validations`, `chord.data.compilations` are telemetry counters
|
|
269
|
+
(`context.telemetry.metrics?.counter(name).add(1)`), always on. The function doing the work counts it; call sites never
|
|
270
|
+
count for others. Tests assert them per hop with the in-memory telemetry adapter.
|
|
271
|
+
|
|
272
|
+
## Footguns
|
|
273
|
+
|
|
274
|
+
- A provider must not mutate arguments or params it received (caller-owned, immutable by convention).
|
|
275
|
+
- `principalKey` must be the same function on every host; a different one splits identities silently.
|
|
276
|
+
- Params keys must escape the separator, so two different params never join to one key.
|
|
277
|
+
- Mappings are direct: when version 3 arrives, every still-accepted version's mappings are updated (compose step
|
|
278
|
+
functions: `(old) => v2to3(v1to2(old))`).
|
|
279
|
+
|
|
280
|
+
## Tests (one group per mechanism, every case)
|
|
281
|
+
|
|
282
|
+
- Contracts: every declaration check with its error path; D11 (kind and signature across variants, at runtime and
|
|
283
|
+
in the types); closed arguments (nested, raw `Type.Object`, records allowed, edits checked, state not checked);
|
|
284
|
+
schema vocabulary (each rejected feature); bytes (marker, bounds, check rebuilt after snapshot, no callback copied);
|
|
285
|
+
snapshots are independent of later changes to the app's schema objects; branding (spread copies refused).
|
|
286
|
+
- Fingerprints: stable across key order and annotations; sensitive to defaults, bounds, union order, params order,
|
|
287
|
+
`additionalProperties`; the same v1 from a separate declaration; local vs remote differ; a fixed known hash for one
|
|
288
|
+
fixed contract (protects the normal form).
|
|
289
|
+
- Evolution: each edit; kind changes refused (also remove then re-add); params and variant set fixed; new bases;
|
|
290
|
+
long chains (versions beyond 9, 99); history types.
|
|
291
|
+
- Accepts: every required-mapping rule above, at runtime and at the type level (`@ts-expect-error` for missing,
|
|
292
|
+
unnecessary and wrongly typed mappings); `"refuse"`; `call`; direct mapping over several versions; no mapping is
|
|
293
|
+
invoked by `checkAccepts`.
|
|
294
|
+
- Params: missing, extra and wrong fields with their paths; literal membership; constraints; the same key whatever
|
|
295
|
+
the property order; separator escaping (no two params join to one key); declaration refusals.
|
|
296
|
+
- Arguments: unknown fields (nested too); no copy (identity of the passed object); `local` and `remote`; bytes by
|
|
297
|
+
`instanceof` and length; old version checked with the old schema then mapped; current never mapped; `null` for
|
|
298
|
+
no-argument methods; unknown method; unaccepted version; `"refuse"`; lazy compilation (counted once per version and
|
|
299
|
+
method).
|
|
300
|
+
- Principals: default key, custom key, caching (no second walk), revocation keys.
|
|
301
|
+
- Errors: tagged union in types (`@ts-expect-error` for wrong pairings); JSON round trip; envelope checks (each
|
|
302
|
+
refusal); details kept by reference; the pinned protocol table; `FailureCause`, `broken`, `openFailure`.
|
|
303
|
+
- Cost guards: the counters per hop in the table above.
|
|
304
|
+
- GC: dropped contracts, bindings, dispatch tables, mappings, schemas and validators are collected after the last call
|
|
305
|
+
settles; params validators per contract; custom principal-key functions dropped while their principals live; nothing
|
|
306
|
+
retained by TypeBox's build accumulators.
|
|
307
|
+
|
|
308
|
+
## Size
|
|
309
|
+
|
|
310
|
+
Target: well below 1,500 source lines for `contracts/` and `data/` together, tests excluded. The type-level history
|
|
311
|
+
and mapping types are the heaviest part; keep the rest lean.
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# L2: watchables and derives (spec, for the owner's approval)
|
|
2
|
+
|
|
3
|
+
Status: **superseded (owner, 2026-10-22)**: the L2 code built from this spec was discarded (too much generic
|
|
4
|
+
machinery for callers that did not exist yet: nodes, sinks, deliveries, publications) and the build switched to
|
|
5
|
+
vertical slices (`slices.md`). Still valid: the section "Decided while specifying" below, and Chord's shared watch
|
|
6
|
+
handle (`src/watch.ts`). Everything else here is background only; do not implement from it.
|
|
7
|
+
|
|
8
|
+
Original status: approved; open points decided (below). The single source for implementing L2; every rule comes from the decision log
|
|
9
|
+
(`packages/chord/docs/next/decisions.md`: "Watchable and one watch API", W1, W2, W3, W4, W12, W14, Q14, R23, R24,
|
|
10
|
+
"Changing contributions, `self.writable`", "Cost counters") unless marked **Decision needed**. Code style: the section
|
|
11
|
+
"Chord v2 Code Style" of the root `AGENTS.md`.
|
|
12
|
+
|
|
13
|
+
## What L2 is
|
|
14
|
+
|
|
15
|
+
Everything observable on one host, and how a change travels: a value changes inside a **publication** (one atomic step
|
|
16
|
+
that may change many sources), the derives over it are recomputed right after, and every consumer sees each
|
|
17
|
+
publication once, completely, in order. No objects, no storage, no links: L3 (store) publishes document commits
|
|
18
|
+
through it, L4 (objects) builds members from it, L6 (links) encodes what it flushes, L9 (registries) composes from it.
|
|
19
|
+
|
|
20
|
+
Source: `packages/chord/src/next/watch/` (one directory; files by concept). Reused unchanged: Chord's shared
|
|
21
|
+
`src/watch.ts` (the watch-handle types **and implementation**, moved there from Durable's `CommittedWatch` by a pi change
|
|
22
|
+
first, owner 2026-10-22; Durable uses the same implementation), `src/delta/` (`Op`, `diffRevisions`), `src/context/`,
|
|
23
|
+
`src/json.ts`, and L1's `next/data` errors (`invalid/reentrant`). Nothing from `next-frozen/`.
|
|
24
|
+
|
|
25
|
+
## 1. The two kinds
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
interface Watchable<T extends JsonValue> { // documents, derives, reference members, constant(v), Durable views
|
|
29
|
+
readonly value: T;
|
|
30
|
+
watch(context: Context): Promise<WatchHandle<T>>; // listener (value, ops, context)
|
|
31
|
+
}
|
|
32
|
+
interface NativeWatchable<T> { // writable(initial), composed registry values
|
|
33
|
+
readonly value: T;
|
|
34
|
+
watch(context: Context): Promise<NativeWatchHandle<T>>; // listener (value, context)
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- A `Watchable` carries JSON and changes with ops (Delta's `Op[]`): the ops turn the previous value into the next.
|
|
39
|
+
Values are immutable by convention: a new value shares unchanged parts with the old one; nobody mutates a value.
|
|
40
|
+
- A `NativeWatchable` carries any in-process value (functions, runtimes); a change is a new value by identity
|
|
41
|
+
(`!==`). Mutating a native value in place notifies nobody. It has no ops and can never be a contract state member or
|
|
42
|
+
go on the wire (Q14, W4).
|
|
43
|
+
- Both carry a runtime kind tag (`"json"` / `"native"`), so L4 can refuse a native one as state with one comparison
|
|
44
|
+
(no value walk).
|
|
45
|
+
|
|
46
|
+
## 2. Publications (W1, W12)
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const publication = createPublication(); // one per host
|
|
50
|
+
publication.publish(() => { // one atomic step
|
|
51
|
+
notes.set(nextNotes, ops); // adopt: pointer swap + mark
|
|
52
|
+
index.set(nextIndex, indexOps);
|
|
53
|
+
}); // flush runs here, synchronously, before publish returns
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- `createPublication()` returns the host's publication. A **source** (`jsonSource(initial, publication)`,
|
|
57
|
+
`writable(initial, publication)`) belongs to one publication.
|
|
58
|
+
- `publish(adopt)` runs `adopt` synchronously. Inside it, `source.set(value, ops)` (JSON) or `source.set(value)`
|
|
59
|
+
(native) swaps the value and **marks**: dependent derives become dirty, and the ops are appended by reference to each
|
|
60
|
+
watch's queue and each sink's batch. O(1) per dependent. Then, still synchronously and without any `await`, the
|
|
61
|
+
**flush**:
|
|
62
|
+
1. recompute every dirty derive that has a consumer, in dependency order (each derive once per flush, after all its
|
|
63
|
+
sources), diffing its old and new value with `diffRevisions` into ops, and marking its own dependents;
|
|
64
|
+
2. deliver each touched sink its batch for this publication (section 6);
|
|
65
|
+
3. call the publication's flush listeners once (L6 uses this to send one message per link);
|
|
66
|
+
4. schedule the queued watch frames (their listeners run later, asynchronously, in order).
|
|
67
|
+
- Every change goes through `publish`: L3's commit step (after the backend commit; S1), in-memory commits (no store
|
|
68
|
+
seq, the publication's own counter, W12), `writable.set` (which publishes itself), registry recomposition and
|
|
69
|
+
inbound wire batches. Each publication has a number (a counter per publication) for ordering and lazy checks.
|
|
70
|
+
- **Reentrancy:** during `adopt` and the flush, `publish`, `watch`, `attach`, a sink's `detach` and `writable.set`
|
|
71
|
+
throw `invalid/reentrant` (W1: no new transaction, watch or release inside the step). Stopping a watch handle is
|
|
72
|
+
allowed anywhere: it only detaches, and delivery tolerates removal during iteration.
|
|
73
|
+
- **Contexts** (context last, required, as in Durable): `createPublication(context)` keeps the host's context (it
|
|
74
|
+
counts lazy-read computes, since a getter has none); `publish(adopt, context)` and `writable.set(value, context)` take the context
|
|
75
|
+
that counts the flush's work and becomes the frames' context. `publication.number` is public (L3's in-memory commit
|
|
76
|
+
number, W12); `publication.onFlush(listener)` returns its removal.
|
|
77
|
+
- **Source ends:** a JSON source has `set(value, ops)`, `retire()`, `end()` and `end({ error })`, all only inside
|
|
78
|
+
`publish` (events in publication order), delivered in that publication's flush after its batch: watches retire, end
|
|
79
|
+
or fail; sinks get a retirement as `update(null, [["r", null]])` then `end()`, an end as `end()`, a failure as
|
|
80
|
+
`fail(error)`. A failed source's `value` throws its error, so derives over it fail with the same error; a retirement
|
|
81
|
+
is a change to `null` for derives over it; an end changes nothing for them. `watch` or `attach` on an ended source
|
|
82
|
+
returns a handle or sink ended the same way. A writable has only `set`.
|
|
83
|
+
- A source set outside `publish` throws (a programming error, `Error`, not a ChordError).
|
|
84
|
+
|
|
85
|
+
## 3. Derives (W1, W4, W14, R24)
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
const count = derive([notes], ([n]) => n.list.length, publication);
|
|
89
|
+
const visible = derive([notes, settings], ([n, s]) => ({ list: n.list.filter(...), theme: s.theme }), publication);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- `derive(sources, compute, publication)`: sources are `Watchable`s and `NativeWatchable`s (mixed) created by L2 on
|
|
93
|
+
the same publication (sources, derives, writables, constants; a foreign watchable such as a Durable view becomes an
|
|
94
|
+
L2 source first, L3d); `compute` is a synchronous pure function of their current values; the result is JSON and the
|
|
95
|
+
derive is a `Watchable`.
|
|
96
|
+
- **Attached only while consumed:** a derive with at least one consumer (a watch, a sink, or a consumed derive over
|
|
97
|
+
it) is attached to its sources and recomputed in the flush. A derive without consumers holds no subscription; reading
|
|
98
|
+
its `value` recomputes it if any source's publication number moved since its last compute (lazy). So an unused
|
|
99
|
+
derive never keeps work or memory alive, and nothing leaks when consumers go away.
|
|
100
|
+
- Ops: when a consumed derive recomputes, `diffRevisions(old, new)` gives its ops (identity short-circuit: unchanged
|
|
101
|
+
shared subtrees cost one `===`). A native source's change marks the derive dirty without ops. A recompute that
|
|
102
|
+
returns the identical value (`===`) publishes nothing.
|
|
103
|
+
- **Dependency order:** a derive's rank is one more than its highest-ranked source; the flush recomputes by rank.
|
|
104
|
+
Sources exist before the derive, so cycles cannot be built (cross-object cycles are rejected at activation, Q5, L4).
|
|
105
|
+
- **A throwing derive** fails only itself: its `value` throws the error, its watches end `{ reason: "failed", error }`,
|
|
106
|
+
its sinks get a failure, and derives over it fail with the same error. It stays failed (broken: no automatic
|
|
107
|
+
retry; L4 rebuilds it on reload). The publication and every other consumer continue.
|
|
108
|
+
- No `previous` (W14). The footgun and its remedy are documentation: a derive that builds new objects for unchanged
|
|
109
|
+
data costs O(value) per flush per consumer; `mapShared` (section 7) keeps unchanged elements identical.
|
|
110
|
+
|
|
111
|
+
## 4. Constant and writable (R23, W4)
|
|
112
|
+
|
|
113
|
+
- `constant(value)`: a `Watchable` that never changes; its watches never get a frame and end only by `stop` or
|
|
114
|
+
cancellation. No publication needed. Used for start data.
|
|
115
|
+
- `writable(initial, publication)`: a `NativeWatchable` with `set(value)`; `set` publishes by itself (one publication
|
|
116
|
+
per call); an identical value (`===`) publishes nothing. Used for registry contributions known only at runtime.
|
|
117
|
+
|
|
118
|
+
## 5. Watch handles (W2, W3; Chord's shared implementation)
|
|
119
|
+
|
|
120
|
+
L2 does not implement watch handles: it uses the one implementation in Chord's `src/watch.ts` (Durable's semantics,
|
|
121
|
+
moved there by the pi change). Sources create a handle per `watch(context)` and feed it: `advance` per publication
|
|
122
|
+
(during the flush, by reference), `retire`, `end`, `end({ error })`, cancellation from the context's signal.
|
|
123
|
+
|
|
124
|
+
- `watch(context)` returns the handle at once (the Promise resolves immediately for local sources; L5 reference
|
|
125
|
+
members may wait). It holds the value current at acquisition and buffers every later publication.
|
|
126
|
+
- `start(listener)` installs the one listener; frames are delivered in order, each awaited, never inline; the listener
|
|
127
|
+
gets a context without the abort signal.
|
|
128
|
+
- **Overflow:** after 100 pending frames the backlog collapses: JSON to one frame `[["r", newest]]`, native to the
|
|
129
|
+
newest value.
|
|
130
|
+
- **Retirement** is an explicit source event (`source.retire()`, used by L3 for retired documents): the last frame is
|
|
131
|
+
`[["r", null]]` with value `null`, then the watch ends `retired`. Never inferred from a `null` value (W2a).
|
|
132
|
+
- **Ends:** `stopped`, `cancelled`, `retired`, `ended` (the source ended), `failed { error }` (the source failed, e.g.
|
|
133
|
+
a throwing derive), `listener_error { error }`; `stop` drops pending frames and never aborts or awaits a running call.
|
|
134
|
+
Termination clears every reference into the source (W3).
|
|
135
|
+
- `NativeWatchHandle<T>`: the same lifecycle with listener `(value, context)`.
|
|
136
|
+
- **W2b** (routines delivering the acquisition value first) is L8's.
|
|
137
|
+
|
|
138
|
+
## 6. Sinks (internal, for L6 and L9)
|
|
139
|
+
|
|
140
|
+
A sink is a synchronous consumer inside the flush, used where a watch's asynchronous delivery is too late: the wire
|
|
141
|
+
encoder (L6: one part per hold, one message per link per publication) and registry composition (L9).
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
const sink = attach(watchable, { update(value, ops) {...}, fail(error) {...}, end() {...} }); // returns detach()
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
- `update` is called once per publication that touched the source, during the flush, with that publication's ops
|
|
148
|
+
(several sets of one source within one publication arrive as one batch, in order). Native sources: `update(value)`.
|
|
149
|
+
- A sink counts as a consumer (derives over the source stay attached). `detach()` removes it; detaching inside the
|
|
150
|
+
flush throws `invalid/reentrant`.
|
|
151
|
+
- Not exported to apps; L4-L9 import it from `next/watch`.
|
|
152
|
+
|
|
153
|
+
## 7. `mapShared` (W14, design §12)
|
|
154
|
+
|
|
155
|
+
`mapShared(f)` returns a function over arrays that calls `f` only for elements it has not seen (by identity) and
|
|
156
|
+
returns the previous result for unchanged ones, so a derive over a list of 2,000 notes with one change builds one new
|
|
157
|
+
object and `diffRevisions` emits one op. The cache is a `WeakMap` from source element to result.
|
|
158
|
+
|
|
159
|
+
## Cost per hop
|
|
160
|
+
|
|
161
|
+
| Hop | Work |
|
|
162
|
+
| --- | --- |
|
|
163
|
+
| a publication | per set source: pointer swap, O(1) per dependent (mark, append ops by reference) |
|
|
164
|
+
| flush | each dirty consumed derive: one compute plus one `diffRevisions`; nothing for unconsumed derives |
|
|
165
|
+
| a watch frame | the value and ops by reference; no copy, no diff |
|
|
166
|
+
| a sink update | the ops by reference |
|
|
167
|
+
| an unconsumed derive read | one compute if a source moved, else nothing |
|
|
168
|
+
| constant | nothing |
|
|
169
|
+
|
|
170
|
+
**Counters** (telemetry, the function doing the work counts it): `chord.watch.computes` (derive computes) and
|
|
171
|
+
`chord.watch.diffs` (`diffRevisions` calls). No walks or copies anywhere in L2.
|
|
172
|
+
|
|
173
|
+
## Footguns
|
|
174
|
+
|
|
175
|
+
- A derive that rebuilds unchanged data costs O(value) per flush per consumer (use `mapShared`; R24: changing one
|
|
176
|
+
item of a flat array still copies the array's slots).
|
|
177
|
+
- Mutating a value in place breaks every consumer silently (immutable by convention).
|
|
178
|
+
- Async work in a derive is impossible by design; it belongs in a routine (L8) writing an in-memory document.
|
|
179
|
+
|
|
180
|
+
## Tests (one group per mechanism, every case)
|
|
181
|
+
|
|
182
|
+
- Publication: several sources in one publication reach a watch as consecutive frames and a sink as one batch;
|
|
183
|
+
publication numbers increase; setting outside `publish` throws.
|
|
184
|
+
- Derives: dependency order (diamond: A→B, A→C, B+C→D computes D once, after B and C); identical result publishes
|
|
185
|
+
nothing; native source marks without ops; lazy read recomputes only after a source moved; attach on first consumer,
|
|
186
|
+
detach after the last (no subscription left; GC); a chain A→B→C where B throws (C fails, A's other consumers
|
|
187
|
+
continue); a failed derive stays failed.
|
|
188
|
+
- Two sources published alternately with a derive over both: the derive sees every combination exactly once per
|
|
189
|
+
publication.
|
|
190
|
+
- Reentrancy: `publish`, `watch`, `attach`, `writable.set`, `detach` inside a derive and inside a sink throw
|
|
191
|
+
`invalid/reentrant`; `stop` inside a sink or listener is allowed and delivery continues correctly.
|
|
192
|
+
- Watch handles (the handle itself is tested in Chord's shared tests): through L2 sources, a watch started after 150
|
|
193
|
+
publications; retire; end and fail from the source; stop during a running call; cancellation by the context.
|
|
194
|
+
- Constant and writable: constant never delivers; writable identical set publishes nothing.
|
|
195
|
+
- `mapShared`: unchanged elements return the identical result; a changed element is recomputed.
|
|
196
|
+
- Sinks: one batch per publication; failure and end; detach.
|
|
197
|
+
- Cost guards: computes and diffs per hop (an unconsumed derive computes nothing on publish).
|
|
198
|
+
- GC: stopped handles hold no source; unconsumed derives hold no subscription and are collected with their sources;
|
|
199
|
+
`mapShared` caches drop with their elements; retained revisions after overflow are bounded (W1's GC count).
|
|
200
|
+
|
|
201
|
+
## Size
|
|
202
|
+
|
|
203
|
+
Target: about 500 source lines, tests excluded.
|
|
204
|
+
|
|
205
|
+
## Decided while specifying (owner, 2026-10-22)
|
|
206
|
+
|
|
207
|
+
- **Watchable state is JSON only.** No bytes in documents, derives, reference members or any watchable value; bytes
|
|
208
|
+
appear only in method arguments and results (passed whole, carried as raw byte segments by L6) and in chunked
|
|
209
|
+
transfers. Delta stays JSON-only. Supersedes W4's "JSON plus bytes" for watchables.
|
|
210
|
+
- **`mapShared` lives in `next/watch/`** for now; it moves into Delta when v2 goes upstream.
|
|
211
|
+
- **C10 rejected:** `constant` (JSON `Watchable`) and `writable` (`NativeWatchable`) stay two, because Q14 needs the
|
|
212
|
+
kind distinction.
|
|
213
|
+
- **One publication per host** (`createPublication()`, created by the host and passed to every source, derive and
|
|
214
|
+
writable on it; apps never see it), never a module-level singleton.
|
|
215
|
+
- **No CBOR:** the wire stays JSON plus raw byte segments (R1, Q4); revisit only if L6 benchmarks show encoding as a
|
|
216
|
+
bottleneck.
|