@earendil-works/chord 1.3.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 +54 -0
- package/README.md +129 -10
- 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 +8 -0
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +15 -0
- 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 +9 -3
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +21 -9
- 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 +54 -0
- package/dist/sqlite/cloudflare.d.ts.map +1 -0
- package/dist/sqlite/cloudflare.js +144 -0
- package/dist/sqlite/cloudflare.js.map +1 -0
- package/dist/sqlite/database.d.ts +40 -0
- package/dist/sqlite/database.d.ts.map +1 -0
- package/dist/sqlite/database.js +2 -0
- package/dist/sqlite/database.js.map +1 -0
- package/dist/sqlite/index.d.ts +4 -0
- package/dist/sqlite/index.d.ts.map +1 -0
- package/dist/sqlite/index.js +3 -0
- package/dist/sqlite/index.js.map +1 -0
- package/dist/sqlite/migrations.d.ts +10 -0
- package/dist/sqlite/migrations.d.ts.map +1 -0
- package/dist/sqlite/migrations.js +33 -0
- package/dist/sqlite/migrations.js.map +1 -0
- package/dist/sqlite/node.d.ts +41 -0
- package/dist/sqlite/node.d.ts.map +1 -0
- package/dist/sqlite/node.js +191 -0
- package/dist/sqlite/node.js.map +1 -0
- package/dist/sqlite/schema.d.ts +3 -0
- package/dist/sqlite/schema.d.ts.map +1 -0
- package/dist/sqlite/schema.js +10 -0
- package/dist/sqlite/schema.js.map +1 -0
- package/dist/telemetry-sqlite/index.d.ts +24 -0
- package/dist/telemetry-sqlite/index.d.ts.map +1 -0
- package/dist/telemetry-sqlite/index.js +273 -0
- package/dist/telemetry-sqlite/index.js.map +1 -0
- package/dist/telemetry-sqlite/store.d.ts +9 -0
- package/dist/telemetry-sqlite/store.d.ts.map +1 -0
- package/dist/telemetry-sqlite/store.js +110 -0
- package/dist/telemetry-sqlite/store.js.map +1 -0
- 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 +42 -5
- package/src/delta/README.md +69 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: One Store
|
|
3
|
+
kind: walkthrough
|
|
4
|
+
kicker: A walkthrough · Chord v2 and p3 · 2026-10-21
|
|
5
|
+
subtitle: How one transactional store keeps a p3 session's transcript, documents and plugin tables consistent, taught one concept at a time
|
|
6
|
+
model: anthropic/claude-sonnet-5-5
|
|
7
|
+
sources:
|
|
8
|
+
- packages/chord/docs/next/store/book.md
|
|
9
|
+
- packages/chord/docs/next/decisions.md
|
|
10
|
+
- apps/p2/docs/p3-reviews/store-review-summary.md
|
|
11
|
+
- apps/p2/docs/p3-reviews/store-bulk-migrations.md
|
|
12
|
+
- apps/p2/docs/p3-reviews/session-data-scenarios.md
|
|
13
|
+
- apps/p2/docs/p3-reviews/store-proposal.md
|
|
14
|
+
- packages/durable/src/storage/sqlite/storage.ts
|
|
15
|
+
- packages/durable/src/session/session.ts
|
|
16
|
+
truth: The decision log (redesign-decisions.md, entries "The store", "S1" to "S17", "Context last") wins over everything; the book (book.md) is written from it; store-proposal.md and session-data-scenarios.md are earlier drafts and the discussion, superseded where the log differs; the Durable sources show today's code, before the S1 change.
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
:::tutor
|
|
20
|
+
Audience: the owner of p3 and Chord, who decided this design in one long discussion and wants to understand it end to
|
|
21
|
+
end, or a developer joining the work who knows TypeScript, SQLite and pi-durable but not this store. Use the book's
|
|
22
|
+
running example throughout: Mario's session S1 on his laptop, the file-history plugin with its `edits` table, entry
|
|
23
|
+
812, the rename of `a/` to `b/` over 10,000 rows, continuing on the desktop. Read the matching book chapter before each
|
|
24
|
+
concept and check decisions in the log. Be concrete: code, short traces with seq numbers, small tables. Short messages;
|
|
25
|
+
one figure per concept at most. When the reader asks why something was not done another way, answer from the book's
|
|
26
|
+
"What We Tried and Dropped" chapter and the log.
|
|
27
|
+
:::
|
|
28
|
+
|
|
29
|
+
:::intro
|
|
30
|
+
#### What this is about
|
|
31
|
+
|
|
32
|
+
A p3 session must be self-contained: everything it owns lives in its own store and directory, so it can be exported,
|
|
33
|
+
imported into another p3, synced to Radius and continued on another device. Three kinds of owners write into a
|
|
34
|
+
session: Durable (the transcript), Chord objects (persisted documents) and plugins (their own tables). This walkthrough
|
|
35
|
+
explains the store they all share and why it is built that way.
|
|
36
|
+
|
|
37
|
+
#### The example
|
|
38
|
+
|
|
39
|
+
Mario works in session S1 on his laptop. A plugin called **file-history** records every file edit in its table
|
|
40
|
+
`edits`: path, the conversation entry that made it (say entry 812), the time. He renames the directory `a/` to `b/`
|
|
41
|
+
(10,000 rows change). In the evening he continues S1 on his desktop; another day he exports it and a colleague imports
|
|
42
|
+
it. Every concept follows this session through one mechanism.
|
|
43
|
+
|
|
44
|
+
#### How it progresses
|
|
45
|
+
|
|
46
|
+
Eleven concepts in four parts: the problem and what was dropped; how the store writes (commit queue, seq, adoption,
|
|
47
|
+
completion); how it reads and stores documents and tables (text order, the documents engine, bulk operations and
|
|
48
|
+
migrations; blobs and derived data); and how a session moves (sync, takeover, export) plus the rules left to plugin authors.
|
|
49
|
+
:::
|
|
50
|
+
|
|
51
|
+
# The problem {#problem part="Why one store"}
|
|
52
|
+
Book "Before we begin" and chapter I. Must cover: P1 (a session is self-contained; the server only mirrors); three
|
|
53
|
+
owners (Durable, Chord objects, plugins); the trace where file-history's own `history.sqlite` and Durable's log sync
|
|
54
|
+
separately and entry 812 dangles or points to the wrong entry after takeover; what is missing is one order across
|
|
55
|
+
storages. A short trace or a steps figure helps.
|
|
56
|
+
|
|
57
|
+
:::check
|
|
58
|
+
1. Both of S1's storages are consistent on their own. Why can the desktop still end up in a state the laptop never had?
|
|
59
|
+
+++ answers
|
|
60
|
+
1. Because nothing orders the changes of one storage relative to the other: the desktop can receive history.sqlite up to the edit but Durable's log only up to the commit before it (or the reverse), a combination that never existed on the laptop.
|
|
61
|
+
:::
|
|
62
|
+
|
|
63
|
+
# What was dropped {#dropped}
|
|
64
|
+
Book chapter II; log entry "The store" (its list of rejected options) and S16. Must cover the main dropped options and
|
|
65
|
+
the reason for each: derived-only plugin data, opaque directories, export hooks, plugin record logs with apply, several
|
|
66
|
+
storages with a shared position counter, recorded SQLite statements, raw SQL reads, an IndexedDB-only API; inside the
|
|
67
|
+
store: generic JSON rows, store-maintained index entries, code point order with replaced surrogates, text equality only.
|
|
68
|
+
Point out what the final design kept from them (one order, recorded operations, a small query language).
|
|
69
|
+
|
|
70
|
+
:::check
|
|
71
|
+
1. Why was "record the plugin's SQL statements and replay them on the replica" dropped, while bulk operations are now recorded as operations and replayed?
|
|
72
|
+
+++ answers
|
|
73
|
+
1. Arbitrary SQL can produce different results on a replica (random(), datetime('now'), unordered INSERT ... SELECT, other SQLite versions); the store's bulk operations use only the store's own expressions, specified once and identical on every backend, plus a row count check.
|
|
74
|
+
:::
|
|
75
|
+
|
|
76
|
+
# The store and its tables {#store part="Writing"}
|
|
77
|
+
Book chapter III; log "The store", S14, S16. Must cover: layers (owners, store with documents engine, tables and commit
|
|
78
|
+
step, backends); a table belongs to one object (address host, object type, table name); `defineTable` with typed key
|
|
79
|
+
and indexed columns (`str` or `int`) in a flat `columns` record of real columns, nesting only inside `json<T>()` columns (typed but not queryable); one transaction API
|
|
80
|
+
`self.tx(fn, ctx)`; index definitions are recorded in the outbox (contents never travel); Durable keeps its storages and gains `StoreStorage`; context last.
|
|
81
|
+
|
|
82
|
+
:::check
|
|
83
|
+
1. In `edits`, which fields can a query filter on, and where does the rest of the row live?
|
|
84
|
+
+++ answers
|
|
85
|
+
1. Every scalar column (str, int, bool, num) is a real column and can be filtered; keys and indexes need str or int; json(...) columns hold JSON text, typed when read but not queryable or indexable.
|
|
86
|
+
:::
|
|
87
|
+
|
|
88
|
+
# Lines, the commit queue and the seq {#commit}
|
|
89
|
+
Book chapter IV; log S1, S3, S9, S10. Must cover: lines (per Chord object, per Durable Session) serialize whole
|
|
90
|
+
transactions, the commit queue serializes only the short final step; one seq per store, Durable sees gaps and only
|
|
91
|
+
compares seqs; adoption inside the step with `Storage.commit(writes, adopt, context)`; why (the trace where Durable
|
|
92
|
+
adopts 41 before file-history adopts 40); listeners still run afterwards and read a complete prefix; a commit is done
|
|
93
|
+
only on the backend's terminal success; ambiguous outcomes stop the store; ids derived at open. The book's sequence
|
|
94
|
+
figure of two objects and a Durable turn helps.
|
|
95
|
+
|
|
96
|
+
:::check
|
|
97
|
+
1. Object A commits seq 40 and Durable commits 41. Without S1, how could a routine see 41 but not 40?
|
|
98
|
+
2. Why is it harmless that Durable's seqs now have gaps?
|
|
99
|
+
+++ answers
|
|
100
|
+
1. Each owner adopted in its own continuation after the disk commit; Durable's continuation ran first, so a routine triggered by 41 read A's in-memory state still at 39. With S1 both adoptions run inside the commit step, in seq order.
|
|
101
|
+
2. Durable only compares seqs (created_at <= at, seq > base); it never computes seq + 1 to find a neighbouring commit.
|
|
102
|
+
:::
|
|
103
|
+
|
|
104
|
+
# Reading and text order {#reading part="Reading and storing"}
|
|
105
|
+
Book chapter V; log S4, S12, S16. Must cover: the small query language (where operators, orderBy, limit, cursor; no
|
|
106
|
+
joins, grouping, projections at first); JavaScript and SQLite order strings differently (the ~ vs 😀 example); the
|
|
107
|
+
decision: JavaScript order everywhere, SQLite stores key and indexed text as UTF-16 BLOBs (big-endian), lossless,
|
|
108
|
+
measured costs; no normalization; cursors carry direction and logical values; multi-query reads in one read
|
|
109
|
+
transaction, no global snapshot.
|
|
110
|
+
|
|
111
|
+
:::check
|
|
112
|
+
1. A plugin pages through `edits` by path with a cursor. Why would it break if SQLite stored paths as ordinary TEXT while the memory backend compared JS strings?
|
|
113
|
+
2. What does the UTF-16 BLOB encoding cost, according to the measurements?
|
|
114
|
+
+++ answers
|
|
115
|
+
1. SQLite would order by UTF-8 bytes and JS by UTF-16 code units; they disagree for characters between U+E000 and U+FFFF versus emoji, so a cursor taken from one order skips or repeats rows in the other (and tests on the memory backend would not show what SQLite does).
|
|
116
|
+
2. Mostly JS encoding and decoding plus twice the bytes for ASCII: about +40% on bulk inserts, +62% file size in the test; SQLite's own range scans are about 4% slower when values are not decoded from the BLOBs.
|
|
117
|
+
:::
|
|
118
|
+
|
|
119
|
+
# The documents engine {#documents}
|
|
120
|
+
Book chapter VI; log S11, S13. Must cover: Durable and Chord persist documents the same way, so the store has one
|
|
121
|
+
engine; address (namespace, owner, kind, key) with an opaque owner string filled by each adapter (Durable: session,
|
|
122
|
+
conversation:7, task:31; Chord: host/object type); find, load, list outside the step, create, change, retire inside it;
|
|
123
|
+
load reconstructs base plus deltas once, the engine keeps nothing in memory; Durable's Session caches and evicts as
|
|
124
|
+
today; fork copies are reconstructed by StoreStorage before the commit step.
|
|
125
|
+
|
|
126
|
+
:::check
|
|
127
|
+
1. Who decides that a conversation's documents fork and rewind with it: the documents engine or Durable's adapter?
|
|
128
|
+
+++ answers
|
|
129
|
+
1. Durable's adapter (StoreStorage): the engine only sees an opaque owner string such as "conversation:7"; the meaning of that owner stays with Durable.
|
|
130
|
+
:::
|
|
131
|
+
|
|
132
|
+
# Bulk operations and migrations {#bulk}
|
|
133
|
+
Book chapter VII; log S17; store-bulk-migrations.md. Must cover: the five writes (put, update, delete, updateWhere,
|
|
134
|
+
deleteWhere); the rename of a/ to b/ as one recorded operation with a row count (about 150 bytes instead of about 40
|
|
135
|
+
MB), compiled to one SQL UPDATE on the UTF-16 BLOB column; the replica runs the same operation and compares the count;
|
|
136
|
+
the set expressions and why they are limited (identical behaviour on every backend; no JSON operands yet); migrations:
|
|
137
|
+
changes inside json(...) columns on access via migrate(row, from), column changes as recorded alters, key and indexed columns eagerly by recorded table changes plus an update
|
|
138
|
+
step or a rows step (scan + tx.update in chunks, migrating then ready, resume after a crash). The book's migration steps
|
|
139
|
+
figure helps.
|
|
140
|
+
|
|
141
|
+
:::check
|
|
142
|
+
1. Version 4 of `edits` adds an indexed column `dir` computed with dirname(path). Why can this not migrate on access, and how does it run instead?
|
|
143
|
+
2. A replica applies the rename and affects 9,998 rows instead of 10,000. What happens?
|
|
144
|
+
+++ answers
|
|
145
|
+
1. An index over a column filled only on access would silently miss unmigrated rows; so it runs eagerly on the driver before the object goes live: a recorded alter adds the column, then a rows step scans in key order and writes dir with tx.update, chunk by chunk, until the table is marked ready.
|
|
146
|
+
2. The counts differ, so the replica stops applying that store and restores it from a snapshot: divergence is detected, not silent.
|
|
147
|
+
:::
|
|
148
|
+
|
|
149
|
+
# Blobs and derived data {#easy}
|
|
150
|
+
Book chapter VIII "The Easy Parts"; log "Blobs and derived data". Must cover: blobs are app-layer files named by the
|
|
151
|
+
hash of their content, written before the row or document that names them; export copies them, import checks hashes;
|
|
152
|
+
sync uploads every blob present and not yet uploaded before each batch (no reference tracking); no deletion before the
|
|
153
|
+
session is deleted; derived data is never shipped and is repaired by a catch-up routine (the artifacts full-text index
|
|
154
|
+
example: normal save, crash after commit, import).
|
|
155
|
+
|
|
156
|
+
:::check
|
|
157
|
+
1. Why does the sync layer not need to know which rows reference which blobs?
|
|
158
|
+
2. The process dies between the artifact document's commit and the index update. What fixes the index?
|
|
159
|
+
+++ answers
|
|
160
|
+
1. A blob is always written before the commit that names it, so uploading every blob present before each batch guarantees that any hash a batch names has its file on Radius already.
|
|
161
|
+
2. The catch-up routine on the next start: it compares the index with the documents, finds version 3 missing and indexes it from the blob.
|
|
162
|
+
:::
|
|
163
|
+
|
|
164
|
+
# Sync and takeover {#sync part="Moving a session"}
|
|
165
|
+
Book chapter IX; log S3, S5, S6, S7. Must cover: the outbox record is written in the same backend transaction;
|
|
166
|
+
parallel uploads, resubmit until acknowledged, trim after acknowledgement; a replica applies whole batches in order
|
|
167
|
+
(from equals its applied head), later batches wait; compaction is safe because batches apply whole; pull-back after a
|
|
168
|
+
power loss; losing the driver role splits the session (new id) without rollback, and why rollback is impossible.
|
|
169
|
+
|
|
170
|
+
:::check
|
|
171
|
+
1. The laptop committed 40 and 41 locally after the desktop took over. What happens to those commits?
|
|
172
|
+
+++ answers
|
|
173
|
+
1. Nothing is rolled back: when Radius refuses the laptop's upload for an old epoch, the laptop's copy becomes a separate session with a new id, keeps 40 and 41, and never syncs with S1 again; S1 continues on the desktop.
|
|
174
|
+
:::
|
|
175
|
+
|
|
176
|
+
# Export, import and the rules left to plugins {#export}
|
|
177
|
+
Book chapters IX ("Export and import") and X; log S2, S4, S8. Must cover: export holds the commit queue so the
|
|
178
|
+
archive is one head, includes tables of plugins that are not installed, never derived data; import restores into a
|
|
179
|
+
fresh store and the server mirrors the catalog; rules: nothing leaves a transaction before it commits (reference the
|
|
180
|
+
tool-call entry, not the tool-result entry); work that finishes out of order is the app's concern (routine handlers
|
|
181
|
+
never overlap: chain or drop stale results); text compares like JS strings; prefer updateWhere over loops of puts.
|
|
182
|
+
|
|
183
|
+
:::check
|
|
184
|
+
1. The file-history plugin wants to store which entry made an edit. Which entry can it safely reference, and why?
|
|
185
|
+
+++ answers
|
|
186
|
+
1. The assistant entry with the tool call: it is committed before the tool runs. The tool-result entry does not exist yet while the tool runs, and its id is handed out only inside the harness's later transaction.
|
|
187
|
+
:::
|
|
188
|
+
|
|
189
|
+
# What comes next {#next part="Where it stands"}
|
|
190
|
+
Book "What's Next"; log entries. Must cover: everything decided on 2026-10-21; the pi change (adopt argument, Session
|
|
191
|
+
rejection handling, mintId wording, traceIn context last); the store in packages/chord/src/next (about 1,650 lines
|
|
192
|
+
estimated); StoreStorage passing Durable's conformance suite; the sync layer later; open points (new id of a split
|
|
193
|
+
session, chunk size, whether IndexedDB is needed while sqlite-wasm covers the browser).
|
package/docs/spec.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
This document specifies the runtime in `src`. Where it and the code disagree, the disagreement is a bug. [Known limitations and decisions](#12-known-limitations-and-decisions) lists what the runtime does not do yet and the choices the sections below leave open.
|
|
4
4
|
|
|
5
5
|
Hard constraints:
|
|
6
|
-
- Chord's runtime depends only on its own `delta` module (tracker, applyImmutable, encoder/decoder, diff) and Node/browser built-ins plus `
|
|
6
|
+
- Chord's runtime depends only on its own `delta` module (tracker, applyImmutable, encoder/decoder, diff) and Node/browser built-ins, plus `@earendil-works/pi-telemetry` for telemetry and `@earendil-works/pi-schema` for schemas. No other Pi packages.
|
|
7
7
|
- Built-in plugins are trusted, loaded from source in-process. The plugin loader uses dynamic `import()` with a cache-busting query (owner-approved exception, `TODO(loader)`: replace with an isolating, evicting loader; old module copies leak; TUI plugins need isolation).
|
|
8
8
|
- Hot reload is required. Host restart only for Chord/runtime code changes or host-level crash recovery.
|
|
9
9
|
|
|
@@ -29,23 +29,23 @@ Contracts are runtime values for every type (shipped bundles have no TypeScript;
|
|
|
29
29
|
```ts
|
|
30
30
|
export const Chat = remote("pi.chat", {
|
|
31
31
|
version: 1, // contract version: a plain number, bumped only on breaking changes
|
|
32
|
-
input:
|
|
32
|
+
input: obj({ session: str(), conversation: num() }),
|
|
33
33
|
host: hostFamily("session:", "session"), // where its objects live: `session:` + input.session
|
|
34
34
|
variants: {
|
|
35
35
|
viewer: { state: { view: ViewSchema } },
|
|
36
36
|
participant: {
|
|
37
37
|
state: { view: ViewSchema },
|
|
38
|
-
methods: { send: method(SendSchema,
|
|
38
|
+
methods: { send: method(SendSchema, obj({ submissionId: num() })) },
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
export const Index = local("pi.index", {
|
|
44
44
|
version: 1,
|
|
45
|
-
input:
|
|
45
|
+
input: obj({ session: str() }),
|
|
46
46
|
members: {
|
|
47
|
-
search: method(
|
|
48
|
-
onChange: method(
|
|
47
|
+
search: method(obj({ query: str() }), arr(Hit)),
|
|
48
|
+
onChange: method({ type: "function", parameters: [Change], returnType: { type: "void" } }, Unsubscribe), // non-JSON allowed for locals
|
|
49
49
|
harness: opaque("pi.durable-harness@1"), // native object, by name+version
|
|
50
50
|
},
|
|
51
51
|
});
|
|
@@ -81,7 +81,7 @@ Factories are synchronous; returning a promise throws. A declaration has a name
|
|
|
81
81
|
host.serve(StatusStore, ({ session }, _host, self) => {
|
|
82
82
|
const status = self.state("status", StatusSchema, { running: false, tasks: 0 }, // schema required, initial value
|
|
83
83
|
{ version: 2, migrate: (old, from) => upgrade(old, from) }); // per cell; default version 1
|
|
84
|
-
const errors = self.state("errors",
|
|
84
|
+
const errors = self.state("errors", arr(str()), []);
|
|
85
85
|
const catalog = self.get(Catalog, {}); // reference; identity = canonical address (+ at)
|
|
86
86
|
const watch = self.resource("watch", {
|
|
87
87
|
version: 1, deps: [catalog], exclusive: false,
|
|
@@ -278,8 +278,8 @@ The tests cover at least: lifetime/references/linger/forced disposal/gone; activ
|
|
|
278
278
|
- **Joining during a reload.** Participants are the child hosts in step when a reload starts. A child whose hello arrives while it runs is decided when it ends: in step, or reconciled to the committed code version; a child already behind is fenced at once, so the calls its roots make meanwhile are admitted in the parent's code version. A reconciliation that is running when a reload starts syncs its child only after that reload ended, against the code version it committed. A reconciliation announces the parent's retired code versions before its `prepare`.
|
|
279
279
|
- **Two-version rule.** An object of a changed type created after a commit has only new code; a previous-code-version root calling it gets `superseded`.
|
|
280
280
|
- **Validation.** Remote calls are validated at reference dispatch, in-host too: a direct binding against the provider's schema, a binding through an adapter against the consumer's. A provider validates each snapshot and reset of a remote state member once per (re)subscription, against the consumer's contract through an `accepts` adapter and the provider's otherwise; ops are validated only in dev mode. At reload, the new provider's description must cover the old provider's when the version is unchanged, in addition to the check against live consumers and facets' `uses`.
|
|
281
|
-
- **Contracts.** Local contracts list their members, so a loading reference knows whether a member is a method, state or opaque. Canonical identity omits input fields equal to their default;
|
|
282
|
-
- **Principals.** A root ctx at ingress acts as its principal (`host.root(fn, { principal })`); contexts inside objects act as `host`. The acceptor decides a link's kind and name (`accept(link, { principal, kind, name })`); only configured host links are addressable, carry roots and may vote, and control frames are accepted only from the parent. Clients never carry roots or code versions. Relaying needs a matching `route`; `authorize(principal, hostName)` runs before `resolve` and again after, and revoking or re-stamping a principal closes its relays at once. `invalidatePrincipal(match)` re-stamps or closes matching links and propagates pattern matches to child hosts.
|
|
281
|
+
- **Contracts.** Local contracts list their members, so a loading reference knows whether a member is a method, state or opaque. Canonical identity omits input fields equal to their default; use `opt(str({ default }))` (pi-schema) to let callers omit them. Provider variants must cover consumer variants; members the consumer's contract does not list are hidden. Schema change detection compares canonical JSON, so reordering `anyOf` branches counts as a change. Fingerprints use a non-cryptographic 64-bit hash: synchronous and browser-safe; contracts are trusted.
|
|
282
|
+
- **Principals.** A root ctx at ingress acts as its principal (`host.root(fn, { principal })`); contexts inside objects act as `host`. The acceptor decides a link's kind and name (`accept(link, { principal, kind, name })`); only configured host links are addressable, carry roots and may vote, and control frames are accepted only from the parent. Clients never carry roots or code versions. Relaying needs a matching `route`; `authorize(principal, hostName)` runs before `resolve` and again after, and revoking or re-stamping a principal closes its relays at once. The host `resolve` returns is admitted before that second check, so a refused, revoked or released relay never leaves a spawned host's link unread. `invalidatePrincipal(match)` re-stamps or closes matching links and propagates pattern matches to child hosts.
|
|
283
283
|
- **Cells and readables.** A value returned from `change` replaces the value and is always validated; `replace` transfers ownership without copying; by default (`{ diff }` overrides) it publishes a diff when the new value reuses a container of the old one at the same key, else `r`. `subscribe(fn)` delivers values, starting with the current one; `events(fn)` delivers `snap`, then `ops`, or `reset`. Reference state members are stable readables that throw `not_ready` while loading and `not_in_variant` outside the variant, and reset when their source moves; a listener added before they are readable gets its snapshot then. Remote state members stay hydrated while the reference is held.
|
|
284
284
|
- **References and calls.** A reference's identity is its address; a second `self.get` of the same address in one run returns the same reference. A reference call without ctx, or with a task ctx, starts a fresh root in the current code version; a ctx whose call or root already settled is refused (`aborted/expired`), one from another host `invalid/foreign_ctx`. Calling a reference inside a factory throws `not_ready`.
|
|
285
285
|
- **Resources and disposal.** New and replaced exclusive resources open at the gate, and so do non-exclusive resources of the same object that depend on them. A new object for an address that is still being disposed waits for that disposal. A resource open that completes after its signal aborted closes its value at once.
|
package/docs/tutorial.md
CHANGED
|
@@ -45,11 +45,12 @@ shuts down its objects and connections.
|
|
|
45
45
|
|
|
46
46
|
Before callers can use an object, they need to agree on its name and members.
|
|
47
47
|
That agreement is a **contract**: a runtime value that also gives TypeScript its
|
|
48
|
-
types. A **schema** describes a value's shape
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
`method(
|
|
52
|
-
|
|
48
|
+
types. A **schema** describes a value's shape: plain JSON Schema, which we write
|
|
49
|
+
with the builders of `@earendil-works/pi-schema` (`obj`, `str`, `num`, ...;
|
|
50
|
+
`{ open: true }` lets an object carry fields it does not name).
|
|
51
|
+
`method(args, result)` declares a method by its argument and result schemas:
|
|
52
|
+
`method()` takes no arguments and returns nothing, and
|
|
53
|
+
`method(undefined, str())`, used below, takes no arguments and returns a string.
|
|
53
54
|
|
|
54
55
|
Start with a label for a named list. `local` means only code inside this host
|
|
55
56
|
can reach it. The input `{ list: "family" }` identifies which list we want;
|
|
@@ -59,8 +60,8 @@ it is not an argument to `label`.
|
|
|
59
60
|
```ts
|
|
60
61
|
const TodoLabel = local("tutorial.todos", {
|
|
61
62
|
version: 1,
|
|
62
|
-
input:
|
|
63
|
-
members: { label: method(undefined,
|
|
63
|
+
input: obj({ list: str() }, { open: true }),
|
|
64
|
+
members: { label: method(undefined, str()) },
|
|
64
65
|
});
|
|
65
66
|
```
|
|
66
67
|
|
|
@@ -116,17 +117,17 @@ name, because it holds nothing a reload must keep.
|
|
|
116
117
|
|
|
117
118
|
<!-- example:03-contract -->
|
|
118
119
|
```ts
|
|
119
|
-
const Todo =
|
|
120
|
-
const Rows =
|
|
120
|
+
const Todo = obj({ text: str(), done: bool() }, { open: true });
|
|
121
|
+
const Rows = arr(Todo);
|
|
121
122
|
const TodoStore = local("tutorial.todos", {
|
|
122
123
|
version: 1,
|
|
123
|
-
input:
|
|
124
|
+
input: obj({ list: str() }, { open: true }),
|
|
124
125
|
members: {
|
|
125
|
-
label: method(undefined,
|
|
126
|
+
label: method(undefined, str()),
|
|
126
127
|
rows: Rows,
|
|
127
|
-
openCount:
|
|
128
|
-
add: method(
|
|
129
|
-
finish: method(
|
|
128
|
+
openCount: num(),
|
|
129
|
+
add: method(obj({ text: str() }, { open: true })),
|
|
130
|
+
finish: method(obj({ index: int() }, { open: true })),
|
|
130
131
|
reset: method(Rows),
|
|
131
132
|
},
|
|
132
133
|
});
|
|
@@ -230,13 +231,13 @@ to a declared resource, without reading the resource during the factory.
|
|
|
230
231
|
```ts
|
|
231
232
|
const Database = local("tutorial.database", {
|
|
232
233
|
version: 1,
|
|
233
|
-
input:
|
|
234
|
+
input: obj({}, { open: true }),
|
|
234
235
|
members: { db: opaque<{ saved: string[] }>("tutorial.database@1") },
|
|
235
236
|
});
|
|
236
237
|
const SavedTodos = local("tutorial.saved-todos", {
|
|
237
238
|
version: 1,
|
|
238
|
-
input:
|
|
239
|
-
members: { add: method(
|
|
239
|
+
input: obj({ list: str() }, { open: true }),
|
|
240
|
+
members: { add: method(obj({ text: str() }, { open: true })) },
|
|
240
241
|
});
|
|
241
242
|
const host = createHost({ self: "server" });
|
|
242
243
|
let opens = 0;
|
|
@@ -338,13 +339,13 @@ puts every `Todos` object on the host named `server`. Section 6 uses that.
|
|
|
338
339
|
```ts
|
|
339
340
|
const Todos = remote("tutorial.todo-view", {
|
|
340
341
|
version: 1,
|
|
341
|
-
input:
|
|
342
|
+
input: obj({ list: str() }, { open: true }),
|
|
342
343
|
host: hostNamed("server"),
|
|
343
344
|
variants: {
|
|
344
345
|
viewer: { state: { rows: Rows } },
|
|
345
346
|
editor: {
|
|
346
347
|
state: { rows: Rows },
|
|
347
|
-
methods: { add: method(
|
|
348
|
+
methods: { add: method(obj({ text: str() }, { open: true })) },
|
|
348
349
|
},
|
|
349
350
|
},
|
|
350
351
|
});
|
|
@@ -499,8 +500,8 @@ test; they are not stored application state.
|
|
|
499
500
|
```ts
|
|
500
501
|
const Activity = local("tutorial.activity", {
|
|
501
502
|
version: 1,
|
|
502
|
-
input:
|
|
503
|
-
members: { seen:
|
|
503
|
+
input: obj({}, { open: true }),
|
|
504
|
+
members: { seen: num() },
|
|
504
505
|
});
|
|
505
506
|
const host = createHost({ self: "server" });
|
|
506
507
|
host.serve(TodoStore, todoFactory);
|
|
@@ -509,7 +510,7 @@ const seeded = Promise.withResolvers<void>();
|
|
|
509
510
|
const stopped = Promise.withResolvers<void>();
|
|
510
511
|
host.serve(Activity, (_input, _principal, self) => {
|
|
511
512
|
const todos = self.get(TodoStore, { list: "family" });
|
|
512
|
-
const seen = self.state("seen",
|
|
513
|
+
const seen = self.state("seen", num(), 0);
|
|
513
514
|
self.on("rows", todos.rows, (rows, ctx) => {
|
|
514
515
|
seen.replace(ctx, rows?.length ?? 0);
|
|
515
516
|
if (rows?.length === 1) observed.resolve();
|
|
@@ -570,7 +571,7 @@ default lifetime, `"referenced"`, are still created only when referenced.
|
|
|
570
571
|
<!-- example:08 -->
|
|
571
572
|
```ts
|
|
572
573
|
const Actions = defineRegistry<(ctx: Ctx) => Promise<number>>("tutorial.actions");
|
|
573
|
-
const Menu = local("tutorial.menu", { version: 1, input:
|
|
574
|
+
const Menu = local("tutorial.menu", { version: 1, input: obj({}, { open: true }) });
|
|
574
575
|
let click: (() => Promise<number>) | undefined;
|
|
575
576
|
const storeFacet: Facet = {
|
|
576
577
|
name: "todo-store",
|
|
@@ -745,7 +746,7 @@ const { label: _label, ...members } = TodoStore.def.members;
|
|
|
745
746
|
const RenamedStore = local("tutorial.todos", {
|
|
746
747
|
version: 2,
|
|
747
748
|
input: TodoStore.def.input,
|
|
748
|
-
members: { ...members, heading: method(undefined,
|
|
749
|
+
members: { ...members, heading: method(undefined, str()) },
|
|
749
750
|
});
|
|
750
751
|
await host.reload([
|
|
751
752
|
{
|
|
@@ -890,7 +891,7 @@ tutorial's source-matching check, not by the application.
|
|
|
890
891
|
```ts
|
|
891
892
|
import assert from "node:assert/strict";
|
|
892
893
|
import { readFileSync } from "node:fs";
|
|
893
|
-
import { type Static,
|
|
894
|
+
import { arr, bool, int, num, obj, type Static, str } from "@earendil-works/pi-schema";
|
|
894
895
|
import { it, onTestFinished } from "vitest";
|
|
895
896
|
import {
|
|
896
897
|
type Ctx,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@earendil-works/chord",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Typed host runtime for plugins, contracts, replicated state, and RPC over JSON links",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -31,6 +31,31 @@
|
|
|
31
31
|
"types": "./dist/node.d.ts",
|
|
32
32
|
"import": "./dist/node.js"
|
|
33
33
|
},
|
|
34
|
+
"./telemetry-sqlite": {
|
|
35
|
+
"source": "./src/telemetry-sqlite/index.ts",
|
|
36
|
+
"types": "./dist/telemetry-sqlite/index.d.ts",
|
|
37
|
+
"import": "./dist/telemetry-sqlite/index.js"
|
|
38
|
+
},
|
|
39
|
+
"./next": {
|
|
40
|
+
"source": "./src/next/index.ts",
|
|
41
|
+
"types": "./dist/next/index.d.ts",
|
|
42
|
+
"import": "./dist/next/index.js"
|
|
43
|
+
},
|
|
44
|
+
"./sqlite": {
|
|
45
|
+
"source": "./src/sqlite/index.ts",
|
|
46
|
+
"types": "./dist/sqlite/index.d.ts",
|
|
47
|
+
"import": "./dist/sqlite/index.js"
|
|
48
|
+
},
|
|
49
|
+
"./sqlite/node": {
|
|
50
|
+
"source": "./src/sqlite/node.ts",
|
|
51
|
+
"types": "./dist/sqlite/node.d.ts",
|
|
52
|
+
"import": "./dist/sqlite/node.js"
|
|
53
|
+
},
|
|
54
|
+
"./sqlite/cloudflare": {
|
|
55
|
+
"source": "./src/sqlite/cloudflare.ts",
|
|
56
|
+
"types": "./dist/sqlite/cloudflare.d.ts",
|
|
57
|
+
"import": "./dist/sqlite/cloudflare.js"
|
|
58
|
+
},
|
|
34
59
|
"./package.json": "./package.json"
|
|
35
60
|
},
|
|
36
61
|
"sideEffects": false,
|
|
@@ -42,7 +67,7 @@
|
|
|
42
67
|
"src/delta/README.md"
|
|
43
68
|
],
|
|
44
69
|
"scripts": {
|
|
45
|
-
"clean": "
|
|
70
|
+
"clean": "node ../../scripts/package-files.mjs clean dist",
|
|
46
71
|
"build": "tsc -p tsconfig.build.json",
|
|
47
72
|
"test": "vitest --run",
|
|
48
73
|
"prepublishOnly": "npm run clean && npm run build"
|
|
@@ -65,12 +90,24 @@
|
|
|
65
90
|
"node": ">=22.19.0"
|
|
66
91
|
},
|
|
67
92
|
"dependencies": {
|
|
68
|
-
"
|
|
93
|
+
"@earendil-works/pi-schema": "1.5.0",
|
|
94
|
+
"@earendil-works/pi-telemetry": "1.5.0"
|
|
95
|
+
},
|
|
96
|
+
"peerDependencies": {
|
|
97
|
+
"esbuild": "0.28.2",
|
|
98
|
+
"ws": "8.21.0"
|
|
99
|
+
},
|
|
100
|
+
"peerDependenciesMeta": {
|
|
101
|
+
"esbuild": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
104
|
+
"ws": {
|
|
105
|
+
"optional": true
|
|
106
|
+
}
|
|
69
107
|
},
|
|
70
108
|
"devDependencies": {
|
|
71
109
|
"@types/ws": "8.18.2",
|
|
72
|
-
"
|
|
73
|
-
"vitest": "4.1.11",
|
|
110
|
+
"vitest": "4.1.12",
|
|
74
111
|
"ws": "8.21.0"
|
|
75
112
|
}
|
|
76
113
|
}
|
package/src/delta/README.md
CHANGED
|
@@ -82,6 +82,35 @@ Parsing a separately serialized message per replica is also a valid detachment.
|
|
|
82
82
|
`decode()` does not copy payloads, so decoding one in-memory `WireOp[]` for two
|
|
83
83
|
mutable replicas makes them alias each other.
|
|
84
84
|
|
|
85
|
+
## Slow consumers
|
|
86
|
+
|
|
87
|
+
`PendingOps` holds the batches one consumer has not taken yet (a watch listener
|
|
88
|
+
that is still running, a link whose window is full) and folds them while they
|
|
89
|
+
wait, so what it hands over replays to the same value with fewer ops:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { PendingOps } from "@earendil-works/chord/delta";
|
|
93
|
+
|
|
94
|
+
const pending = new PendingOps();
|
|
95
|
+
pending.push(prepared.ops); // for each adopted batch, while the consumer is busy
|
|
96
|
+
// When the consumer is ready again:
|
|
97
|
+
const batch = pending.take();
|
|
98
|
+
const ops = batch.kind === "ops" ? batch.ops : [["r", tracker.value]];
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- A leaf op (an append, or a set of a primitive) folds into the last pending leaf
|
|
102
|
+
op on its path: `a` + `a` join, `s` replaces `s` or `a`, an `a` after a string `s`
|
|
103
|
+
appends into it. `["a", ["text"], "he"]`, `["s", ["n"], 1]`, `["a", ["text"], "y"]`
|
|
104
|
+
becomes `["a", ["text"], "hey"]`, `["s", ["n"], 1]`.
|
|
105
|
+
- Any other op (`p`, `m`, `d`, `t`, `s` of an object or array) ends folding into
|
|
106
|
+
the ops before it, as it may change what a path names; `r` drops them.
|
|
107
|
+
- Past 10,000 pending ops after folding, only `replace` stays: the owner sends the
|
|
108
|
+
current value as `[["r", value]]`.
|
|
109
|
+
- One batch is handed over as received; received batches and op tuples are never
|
|
110
|
+
mutated, so the same batch can feed other consumers.
|
|
111
|
+
- It folds ops of the tracker, `diffRevisions()` and `appendText()`; it does not
|
|
112
|
+
validate or normalize hand-written ops.
|
|
113
|
+
|
|
85
114
|
## Do and don't
|
|
86
115
|
|
|
87
116
|
- Do build a fresh root and then transfer it; validate untrusted roots at your ingestion boundary.
|
|
@@ -125,6 +154,8 @@ Growing `length` inserts `null`; shrinking it removes elements.
|
|
|
125
154
|
|
|
126
155
|
`tracker.value` is the latest adopted revision. `beginChange()` opens an overlay
|
|
127
156
|
draft over it and never modifies it. A draft may stay open across `await`.
|
|
157
|
+
A draft dropped without `prepare()` or `abort()` stays referenced by its
|
|
158
|
+
tracker until the tracker's next `beginChange()` or `adopt()`.
|
|
128
159
|
`prepare()` materializes the candidate and ops and does not change authority.
|
|
129
160
|
`adopt()` checks the preparation and swaps the root pointer.
|
|
130
161
|
|
|
@@ -181,9 +212,47 @@ and restores `Op` tuples. Use one encoder/decoder pair per ordered state stream.
|
|
|
181
212
|
Path IDs span batches and an `r` resets both dictionaries. After a decode or
|
|
182
213
|
apply error, discard the decoder and replica and recover from a later `r`.
|
|
183
214
|
|
|
215
|
+
## Growing strings: use `appendText`
|
|
216
|
+
|
|
217
|
+
The footgun: appending to a string through a draft costs the string's whole length on every change, not the length of
|
|
218
|
+
what you append.
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
const change = tracker.beginChange();
|
|
222
|
+
change.state.message.text += chunk; // looks like O(chunk)
|
|
223
|
+
const prepared = change.prepare(); // emits ["a", ["message", "text"], chunk], but costs O(text.length)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The draft's proxy only sees the finished new string, never the chunk, so `prepare()` recovers the append by checking
|
|
227
|
+
that the new string starts with the old one. That check reads the whole string, and V8 first copies a string built by
|
|
228
|
+
`+=` (a rope) into one flat piece. There is no fast path: measured on Node 24 and 26, 20,000 changes appending 40
|
|
229
|
+
characters each, up to 800 KB, take about 2.4 s with the check and about 1 ms without it. A stream of N chunks into one
|
|
230
|
+
string therefore costs O(N x length) in total: quadratic.
|
|
231
|
+
|
|
232
|
+
The fix: hand Delta the chunk.
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
import { appendText } from "@earendil-works/chord/delta";
|
|
236
|
+
|
|
237
|
+
appendText(change.state.message, "text", chunk); // records ["a", path, chunk]: O(chunk), no compare, no copy
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
- `appendText(parent, key, text)` takes the parent draft and a key whose type is exactly `string` (not optional, not a
|
|
241
|
+
string literal type), so the compiler refuses `appendText(block, "type", …)`.
|
|
242
|
+
- Several appends to one key in one change become one op. A plain assignment or deletion of the same key in that change
|
|
243
|
+
falls back to the compare, as does an append after a plain write.
|
|
244
|
+
- The appended text is copied into a string of its own, so neither the op nor the new value keeps a larger string
|
|
245
|
+
alive.
|
|
246
|
+
- Use it wherever a string grows by appends across many changes (streamed answers, tool output, logs). A one-off
|
|
247
|
+
assignment is fine with `=`.
|
|
248
|
+
- Derives cannot use it: `diffRevisions()` compares two revisions it did not write, so a derive producing a growing
|
|
249
|
+
string pays O(length) per delivery.
|
|
250
|
+
|
|
184
251
|
## Limits and footguns
|
|
185
252
|
|
|
186
253
|
- No freezing. Mutating any immutable value corrupts state silently.
|
|
254
|
+
- Appending to a string through a draft (`draft.text += chunk`) costs O(string length) per change; use `appendText`
|
|
255
|
+
(section "Growing strings").
|
|
187
256
|
- In-process sharing: local handles, cell subscribers, and `replicatedState` subscribers receive the provider's containers. A consumer mutation corrupts authority and makes remote replicas diverge.
|
|
188
257
|
- A change inside a large flat array copies that array's pointer storage for the new revision.
|
|
189
258
|
- Placement validation costs time and memory on bulk inserts. In a benchmark unshifting 100k three-field objects, it added about 19 ms and 20 MiB of transient heap.
|