solid-objects 0.16.0 → 0.17.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 +78 -0
- package/README.md +1 -0
- package/dist/actor-runtime.d.ts +7 -0
- package/dist/actor-runtime.d.ts.map +1 -1
- package/dist/actor.d.ts +1 -0
- package/dist/actor.d.ts.map +1 -1
- package/dist/actor.js +3 -0
- package/dist/actor.js.map +1 -1
- package/dist/cloudflare/engine.d.ts +1 -0
- package/dist/cloudflare/engine.d.ts.map +1 -1
- package/dist/cloudflare/engine.js +118 -15
- package/dist/cloudflare/engine.js.map +1 -1
- package/dist/cloudflare/records.d.ts +2 -0
- package/dist/cloudflare/records.d.ts.map +1 -1
- package/dist/cloudflare/runtime.d.ts +7 -0
- package/dist/cloudflare/runtime.d.ts.map +1 -1
- package/dist/cloudflare/runtime.js +13 -0
- package/dist/cloudflare/runtime.js.map +1 -1
- package/dist/configuration.d.ts +10 -0
- package/dist/configuration.d.ts.map +1 -1
- package/dist/configuration.js.map +1 -1
- package/dist/diagnostics.d.ts +37 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +73 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/doctor.js +1 -1
- package/dist/doctor.js.map +1 -1
- package/dist/effect-recovery-coordinator.d.ts.map +1 -1
- package/dist/effect-recovery-coordinator.js +4 -1
- package/dist/effect-recovery-coordinator.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +14 -1
- package/dist/realtime.js.map +1 -1
- package/dist/reference.d.ts +11 -0
- package/dist/reference.d.ts.map +1 -1
- package/dist/reference.js +22 -0
- package/dist/reference.js.map +1 -1
- package/dist/repository.d.ts +1 -1
- package/dist/repository.d.ts.map +1 -1
- package/dist/repository.js +7 -6
- package/dist/repository.js.map +1 -1
- package/dist/runtime.d.ts +8 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +108 -32
- package/dist/runtime.js.map +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +20 -5
- package/dist/schema.js.map +1 -1
- package/dist/serialization.js +3 -5
- package/dist/serialization.js.map +1 -1
- package/dist/telemetry.d.ts +22 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +126 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/transmit.js +2 -2
- package/dist/transmit.js.map +1 -1
- package/dist/turn.js +2 -2
- package/dist/turn.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/wake-up-notification.d.ts.map +1 -1
- package/dist/wake-up-notification.js +9 -1
- package/dist/wake-up-notification.js.map +1 -1
- package/docs/api.md +25 -3
- package/docs/authorization.md +6 -0
- package/docs/observability.md +192 -0
- package/docs/parity.md +89 -72
- package/package.json +3 -3
package/docs/parity.md
CHANGED
|
@@ -4,18 +4,15 @@ This ledger tracks capability parity with the Ruby `solid_objects` gem.
|
|
|
4
4
|
Parity preserves a capability and its correctness or security boundary. It does
|
|
5
5
|
not copy a Rails API into Node.
|
|
6
6
|
|
|
7
|
-
Reference: Ruby `solid_objects` 0.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
The
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
scope boundaries that the Ruby reference shares: the partial guard row, the
|
|
17
|
-
backpressure row, and the shared planned result-lookup row. They are not missing
|
|
18
|
-
Ruby capabilities.
|
|
7
|
+
Reference: Ruby `solid_objects` 0.17.0. The JavaScript package began at the Ruby
|
|
8
|
+
design's `0.12` capability generation; that version number did not imply earlier
|
|
9
|
+
JavaScript releases.
|
|
10
|
+
|
|
11
|
+
The SQL runtimes share durable identity, ordered mailboxes, fenced commits,
|
|
12
|
+
effects, reminders, authorization, administration, and realtime guarantees.
|
|
13
|
+
Transport- and framework-neutral JavaScript APIs replace Rails-specific surfaces.
|
|
14
|
+
The partial write-guard and backpressure rows below record their actual limits.
|
|
15
|
+
Browser and Cloudflare hosting have separate scope boundaries later in this file.
|
|
19
16
|
|
|
20
17
|
`0.14.0` also adds `runtime.enqueueInternalMessage()`,
|
|
21
18
|
`runtime.enqueueInternalMessageInTransaction()`, and
|
|
@@ -32,7 +29,7 @@ such boundary between a gem and its dependents.
|
|
|
32
29
|
Operation-reference typing is runtime-specific: TypeScript infers scheduled and
|
|
33
30
|
transmitted operations from the concrete receiver, and checks literal effect
|
|
34
31
|
callback names. Ruby offers opt-in RBS generation from declared application types
|
|
35
|
-
|
|
32
|
+
since Ruby 0.14.7.
|
|
36
33
|
Both preserve runtime operation validation and global effect/commit-action names;
|
|
37
34
|
this does not imply automatic TypeScript-style inference in Ruby.
|
|
38
35
|
|
|
@@ -51,60 +48,63 @@ SQL waiters read results and status from one statement. Ruby already checks
|
|
|
51
48
|
completion and returns the result from the same loaded message; no Ruby change
|
|
52
49
|
is needed for the JavaScript stale-result race fix.
|
|
53
50
|
|
|
54
|
-
| Capability | Status | TypeScript shape or remaining work
|
|
55
|
-
| ------------------------------------------------------------------------------------------------------------- | ------- |
|
|
56
|
-
| Actor registry, durable identity, JSON state, and adjacent state migrations | Native | Ordinary classes, static actor types, inferred state, explicit migrations, and isolated runtime context across every actor-instance callback.
|
|
57
|
-
|
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
|
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
|
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
68
|
-
|
|
|
69
|
-
|
|
|
70
|
-
|
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
|
51
|
+
| Capability | Status | TypeScript shape or remaining work |
|
|
52
|
+
| ------------------------------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
53
|
+
| Actor registry, durable identity, JSON state, and adjacent state migrations | Native | Ordinary classes, static actor types, inferred state, explicit migrations, and isolated runtime context across every actor-instance callback. |
|
|
54
|
+
| Query and projection purity | Native | Both runtimes reject state mutation and staged effects, recovery checks, commit actions, reminders, or outbound messages in queries, observable projections, and personalized payloads. Projection guards compare the complete staged work, including same-count replacements. Query and observable violations fail terminally with `QueryMutatedState`; payload violations fail only that payload. Snapshot projection reads enforce the same rule. |
|
|
55
|
+
| JSON property preservation | Native | Reserved property names such as `__proto__`, `constructor`, and `prototype` remain ordinary data, including through size checks and immutable copies. Both suites consume `compatibility/json-values.json`. |
|
|
56
|
+
| Fluent committed calls and background delivery | Native | `await reference.operation()` and `reference.send.operation()`. |
|
|
57
|
+
| Ordered mailbox, sequence allocation, idempotency, retries, dead letters, leases, renewal, and fenced commits | Native | Relational ready/claimed membership tables, distinct generated request IDs and caller idempotency keys, durable history, adapter-appropriate sequence locking, and PostgreSQL/MySQL row locks held from fence validation through commit. |
|
|
58
|
+
| Domain rejection and strict poison ordering | Native | Rejections accept JavaScript identifier-style codes and roll back without retry; invalid codes fail terminally, while retryable failures block later operations until completion or dead-lettering. |
|
|
59
|
+
| Bounded activation passes and hot-actor fairness | Native | Configurable turn-count and elapsed-time budgets bound each pass, then move only that actor's already-due memberships behind actors already waiting. |
|
|
60
|
+
| Bounded claim candidate scan | Native | A configurable ordered scan continues to another ready actor when a worker loses the first candidate's lease race. |
|
|
61
|
+
| Backpressure and payload caps | Partial | Serialization enforces a shared maximum JSON nesting depth, raising `InvalidPayload`, and an optional caller-supplied `maxBytes` limit, raising `PayloadTooLarge`; keyed reminder names are bounded to 255 characters in JS and 191 in Ruby. These existing database limits remain runtime-specific; use at most 191 ASCII characters for a name shared across runtimes. Distributed per-actor rate limits, global admission control, and cache-capacity eviction are not planned in either runtime. They are hot, request-path, and loss-tolerant, so one durable ordered message per check is the wrong shape. Solid Objects Pro answers them with grouped and ephemeral operations, which [fit](fit.md) describes. |
|
|
62
|
+
| Idle activation cache | Native | Long-running workers retain hydrated actors under renewable fenced leases, restore public state after failed turns, and release on timeout, fairness yield, lease loss, or shutdown. |
|
|
63
|
+
| Transactional effects and outcome operations | Native | At-least-once handlers receive immutable stable effect, attempt, source-message, and actor identity; success and failure operations also receive the originally staged arguments for correlation. Typed callback envelopes are exported. |
|
|
64
|
+
| Actor-to-actor delivery | Native | `sendTo(reference).operation()` stages delivery in the source actor commit. |
|
|
65
|
+
| One-shot and recurring reminders | Native | Scheduling, cancellation by name/key/handle, read-your-writes inspection, catch-up policy, stale-claim recovery, pausing, and authorized resume. Cancellation cannot recall an already-enqueued occurrence. |
|
|
66
|
+
| Same-database commit actions | Native | Registered actions receive source-message identity, mailbox sequence, activation generation, and the fenced transaction connection. |
|
|
67
|
+
| Ambient transaction rejection | Native | Committed calls and message waits fail before blocking when the current async context already owns a transaction on the Solid Objects adapter. |
|
|
68
|
+
| Direct application-write isolation during actor code | Partial | `guardApplicationDatabase()` fails closed for operations, projections, migrations, and commit actions; only the supplied fenced commit-action connection may write. Unwrapped clients cannot be intercepted. |
|
|
69
|
+
| Committed snapshots | Native | `snapshot()` returns authorized persisted fields and inferred getters from one read-only committed state image; realtime replay reads explicit observables without mailbox history. |
|
|
70
|
+
| Actor destruction and incarnation fencing | Native | Authorized cascading deletion creates a fresh instance ID on recreation; an authorized waiter receives `ActorDestroyed` when that incarnation disappears. |
|
|
71
|
+
| Result recovery and sync timeout diagnostics | Native | Status, result, outcome, and wait reauthorize the original stored operation and arguments. All delivery modes retain immutable JSON results under the result-size cap. Result reads raise terminal rejection/failure errors; outcome returns them as data. Whole-call deadlines distinguish enqueue, wait, database, activation, and mailbox blockers. |
|
|
72
|
+
| Result lookup by request ID and idempotency key | Native | `runtime.findBy({ requestId })` and `reference.findBy({ idempotencyKey })` rebuild a `MessageReference`, authorized with the hook the original call ran. An actor remembers the keys of its own finished turns, so a key lookup separates a pruned message from one that never existed. |
|
|
74
73
|
|
|
75
74
|
Effect callback envelopes are typed with `EffectFailurePayload`,
|
|
76
75
|
`EffectSuccessPayload`, and `SerializedError` in both SQL and Cloudflare.
|
|
77
|
-
Ruby RBS contracts
|
|
78
|
-
Ruby field names; this does not change runtime delivery semantics.
|
|
76
|
+
Ruby publishes RBS contracts with native Ruby field names; this does not change runtime delivery semantics.
|
|
79
77
|
|
|
80
78
|
## Operations
|
|
81
79
|
|
|
82
|
-
| Capability | Status | TypeScript shape or remaining work
|
|
83
|
-
| ----------------------------------------------------------------------------- | ------ |
|
|
84
|
-
| Process registration, heartbeats, stale claim recovery, and graceful shutdown | Native | Runtime roles persist host, PID, runtime versions, draining and stopped transitions, cooperative cancellation, and a bounded shutdown deadline; cleanup recovers stale claims.
|
|
85
|
-
| Failed-role replacement | Native | Built-in and registered roles are rebuilt through their factories with capped backoff; shutdown is the terminal replacement boundary.
|
|
86
|
-
| Additional supervised components | Native | `registerComponent()` builds, validates, runs, and stops application components with the runtime.
|
|
87
|
-
| Dead-letter inspection and retry | Native | `runtime.deadLetters` provides deny-by-default immutable inspection and idempotent durable retry linkage.
|
|
88
|
-
| Reconciliation reads | Native | Authorized cursor pages cover active, quiet, and orphaned instances; bounded state batches are migrated and deeply frozen.
|
|
89
|
-
| Message, process, and opt-in instance retention | Native | Supervised scheduling bounds message and process growth; authorized manual APIs add preview and keep destructive instance expiration explicit. SQL instance pruning uses an index on actor type and update time.
|
|
90
|
-
| Doctor and schema verification | Native | Structured checks cover configuration, schema/version shape, adapter server versions, neutral-context policy probes, live roles, and a targeted round trip.
|
|
91
|
-
| CLI | Native | The packaged executable loads an application runtime and exposes start, diagnostics, processes, dead letters, reminders, and explicit retention pruning as JSON.
|
|
92
|
-
| Operator dashboard | Native |
|
|
93
|
-
|
|
|
94
|
-
|
|
|
95
|
-
|
|
|
80
|
+
| Capability | Status | TypeScript shape or remaining work |
|
|
81
|
+
| ----------------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
82
|
+
| Process registration, heartbeats, stale claim recovery, and graceful shutdown | Native | Runtime roles persist host, PID, runtime versions, draining and stopped transitions, cooperative cancellation, and a bounded shutdown deadline; cleanup recovers stale claims. |
|
|
83
|
+
| Failed-role replacement | Native | Built-in and registered roles are rebuilt through their factories with capped backoff; shutdown is the terminal replacement boundary. |
|
|
84
|
+
| Additional supervised components | Native | `registerComponent()` builds, validates, runs, and stops application components with the runtime. |
|
|
85
|
+
| Dead-letter inspection and retry | Native | `runtime.deadLetters` provides deny-by-default immutable inspection and idempotent durable retry linkage. |
|
|
86
|
+
| Reconciliation reads | Native | Authorized cursor pages cover active, quiet, and orphaned instances; bounded state batches are migrated and deeply frozen. |
|
|
87
|
+
| Message, process, and opt-in instance retention | Native | Supervised scheduling bounds message and process growth; authorized manual APIs add preview and keep destructive instance expiration explicit. SQL instance pruning uses an index on actor type and update time. |
|
|
88
|
+
| Doctor and schema verification | Native | Structured checks cover configuration, schema/version shape, adapter server versions, neutral-context policy probes, live roles, and a targeted round trip. |
|
|
89
|
+
| CLI | Native | The packaged executable loads an application runtime and exposes start, diagnostics, processes, dead letters, reminders, and explicit retention pruning as JSON. |
|
|
90
|
+
| Operator dashboard | Native | Fetch and Node/Connect mounting, authorized views and actions, CSRF, filtering, paging, charts, and extensions match the Rack dashboard. Both dashboards expose individual retries and pause/resume; bulk redrive is available through the administration APIs. Pause does not interrupt an in-flight turn. |
|
|
91
|
+
| Bulk redrive and administration audit | Native | Message, effect, and broadcast scopes support idempotent retry and durable, bounded, cancellable redrive. Retry and task transitions persist administration identity in audit rows. |
|
|
92
|
+
| Structured instrumentation | Native | Versioned events, metric samples, isolated observers, and bounded authorized diagnostics match Ruby. Both test suites check SQL event attributes against `compatibility/telemetry-events.json`; only JS activation events add their turn's message fields. Both runtimes log exporter and observer failures, require observer callbacks, and cap local observers at 1,000. Timeout events share wait reasons, activation owner IDs, and string generations; see [observability](observability.md). Durable Objects uses host instrumentation and remote diagnostics, sends fewer attributes, and does not send `sync.timeout`. |
|
|
93
|
+
| Large committed state warning | Native | `warnStateBytes` reports one `solid_objects.state.large` event, holding the actor type, actor ID, byte count, and threshold, when a committed image passes a 128 KB soft threshold. The event holds no application state, and it reports after the commit. The Ruby gem carries the same event and the same 5 MB hard default from `0.14.3`, as `warn_state_bytes`. Its threshold defaults to 64 KB rather than 128 KB, because its measured curve falls sooner: it keeps 55% of its empty-state throughput at 13 KB, where this package keeps 98% at 16 KB. |
|
|
94
|
+
| Public test helper | Native | `runtime.testing` provides role-selective deterministic draining, explicit-time due-reminder execution, and dependency-ordered reset without relying on cascades. |
|
|
96
95
|
|
|
97
96
|
## Databases and wake-up
|
|
98
97
|
|
|
99
|
-
| Capability
|
|
100
|
-
|
|
|
101
|
-
| SQLite
|
|
102
|
-
| PostgreSQL
|
|
103
|
-
| MySQL
|
|
104
|
-
| Durable polling fallback
|
|
105
|
-
| In-process wake-up
|
|
106
|
-
|
|
|
107
|
-
|
|
|
98
|
+
| Capability | Status | TypeScript shape or remaining work |
|
|
99
|
+
| --------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
100
|
+
| SQLite | Native | Uses built-in `node:sqlite`, serialized process-local access, bounded transient writer retries, foreign keys, strict tables, database time, and deadline-bounded access and lock waits. Ruby uses a yielding busy handler for background writes so a waiting thread lets the lock holder commit, including on Rails 7.1/7.2; both preserve synchronous deadlines. |
|
|
101
|
+
| PostgreSQL | Native | Optional `pg` 8.23 peer, bounded pooling, 64-bit schema, row-locked sequences, server checks, and deadline-bounded pool, statement, and lock waits. |
|
|
102
|
+
| MySQL | Native | Optional `mysql2` 3.23 peer, bounded pooling, InnoDB schema, row-locked sequences, scoped deadlock retry, and deadline-bounded pool, query, and lock waits. Ruby also tests a second client, `trilogy`; Node has no comparable second MySQL client, so only `mysql2` is tracked here. |
|
|
103
|
+
| Durable polling fallback | Native | Every role progresses without a notification service. Effects, reminders, and broadcasts use canonical ordered polling indexes; PostgreSQL and MySQL lock only the selected row with `FOR UPDATE SKIP LOCKED`. Broadcasts and reminders compare separate available and stale-recovery probes, preserve the oldest-first choice, and retry past candidates locked by another claimant. |
|
|
104
|
+
| In-process wake-up | Native | A generation-based adapter prevents claim-to-wait signal loss. It is the polling fallback or an explicit opt-out from automatic cross-process selection. |
|
|
105
|
+
| Automatic wake-up selection | Native | Prefer configured Redis, then proven PostgreSQL notifications, then polling. Probe failures warn and report the resolved capability; MySQL needs Redis for cross-process wake-up. |
|
|
106
|
+
| PostgreSQL wake-up | Native | `database.wakeUp()` uses one dedicated event-driven client, role-specific `LISTEN/NOTIFY`, generation fencing, reconnectable listeners, and durable polling fallback. |
|
|
107
|
+
| Redis wake-up | Native | An optional `redis` peer provides role-specific Pub/Sub over separate lazy publisher/subscriber connections, with bounded failures and durable polling fallback. |
|
|
108
108
|
|
|
109
109
|
Both runtimes select a wake-up adapter automatically. `wakeUp` takes a name or
|
|
110
110
|
an adapter and defaults to `"automatic"`, which prefers a configured Redis URL,
|
|
@@ -152,11 +152,14 @@ with the hook the original call ran, and report absence, an unregistered actor,
|
|
|
152
152
|
and a refusal the same way. `outcome` reports the status, result, error,
|
|
153
153
|
rejection, and attempt count in both.
|
|
154
154
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
155
|
+
Both runtimes retain JSON results for synchronous, background, and internal
|
|
156
|
+
messages under the configured result-size cap. Every status, result, and outcome
|
|
157
|
+
read rechecks authorization against the original operation and arguments.
|
|
158
|
+
`result` raises terminal failures; `outcome` exposes them as data. Results discarded
|
|
159
|
+
by older Ruby workers cannot be recovered retroactively.
|
|
160
|
+
|
|
161
|
+
Two storage details differ. This runtime needed a new unique index on
|
|
162
|
+
`request_id`, added as schema version 12, because
|
|
160
163
|
its table constrained the pair `(actor_type, actor_id, request_id)`; the Ruby
|
|
161
164
|
schema has carried a global unique index since its first migration. The error
|
|
162
165
|
record also differs: Ruby's `ErrorRecord` carries `class_name`, `message`, and
|
|
@@ -189,15 +192,15 @@ because a Durable Object indexes only its own messages, so that form raises
|
|
|
189
192
|
|
|
190
193
|
## Realtime and browser behavior
|
|
191
194
|
|
|
192
|
-
| Capability | Status | TypeScript shape or remaining work
|
|
193
|
-
| ------------------------------------------------------------ | -------------- |
|
|
194
|
-
| Explicit observable projection and durable invalidations | Native | `observables()` is opt-in and invalidation-only by default. `broadcastValue()` sends changed values; `broadcastInvalidation()` explicitly sends only changed names while comparing the real value. Private or subscriber-specific values belong behind invalidation-only component endpoints or in typed payloads.
|
|
195
|
-
| Action Cable channels and signed stream names | Not applicable | `runtime.realtime` provides authenticated transport-neutral sessions; the host owns its HTTP/WebSocket server and authentication.
|
|
196
|
-
| Authorized subscriptions | Native | Each request is denied by default and authorized before actor lookup; sessions replay committed observables and fence ordered durable revisions. Multi-process hosts explicitly bridge their shared transport.
|
|
197
|
-
| Turbo scalar replacement | Not applicable | The browser client exposes invalidations to application rendering code. Framework adapters can be separate packages.
|
|
198
|
-
| Keyed component refresh, morph/replace, and batch coalescing | Native | A typed framework-neutral registry selects explicit dependencies, coalesces batch requests, aborts superseded work, fences each target, and delegates synchronous application strategy to the host.
|
|
199
|
-
| Personalized payload broadcasts | Native |
|
|
200
|
-
| Real-browser compatibility suite | Native | Playwright exercises subscription replay over native WebSocket, incarnation/revision fences, payload delivery, component batching, and cancellation in Chromium.
|
|
195
|
+
| Capability | Status | TypeScript shape or remaining work |
|
|
196
|
+
| ------------------------------------------------------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
197
|
+
| Explicit observable projection and durable invalidations | Native | `observables()` is opt-in and invalidation-only by default. `broadcastValue()` sends changed values; `broadcastInvalidation()` explicitly sends only changed names while comparing the real value. Private or subscriber-specific values belong behind invalidation-only component endpoints or in typed payloads. |
|
|
198
|
+
| Action Cable channels and signed stream names | Not applicable | `runtime.realtime` provides authenticated transport-neutral sessions; the host owns its HTTP/WebSocket server and authentication. |
|
|
199
|
+
| Authorized subscriptions | Native | Each request is denied by default and authorized before actor lookup; sessions replay committed observables and fence ordered durable revisions. Multi-process hosts explicitly bridge their shared transport. |
|
|
200
|
+
| Turbo scalar replacement | Not applicable | The browser client exposes invalidations to application rendering code. Framework adapters can be separate packages. |
|
|
201
|
+
| Keyed component refresh, morph/replace, and batch coalescing | Native | A typed framework-neutral registry selects explicit dependencies, coalesces batch requests, aborts superseded work, fences each target, and delegates synchronous application strategy to the host. |
|
|
202
|
+
| Personalized payload broadcasts | Native | Both runtimes evaluate each personalized payload on an isolated actor from the same committed snapshot, including generated defaults, reject state mutation and staged work, prevent application database writes, and enforce the configured payload byte limit. They reauthorize as queries, isolate failures, and carry independent revision fences. |
|
|
203
|
+
| Real-browser compatibility suite | Native | Playwright exercises subscription replay over native WebSocket, incarnation/revision fences, payload delivery, component batching, and cancellation in Chromium. |
|
|
201
204
|
|
|
202
205
|
## JavaScript-only: the browser runtime
|
|
203
206
|
|
|
@@ -257,6 +260,8 @@ and [#48](https://github.com/cardmagic/solid-objects-ruby/issues/48)):
|
|
|
257
260
|
with `register_transmit` is the staging side. Identifiers differ by
|
|
258
261
|
runtime idiom, but both sides guarantee the same wire contract:
|
|
259
262
|
|
|
263
|
+
- transmit siblings preserve staging order within each source message, including retries;
|
|
264
|
+
- explicit `arguments: null` is invalid; only omission defaults to an empty object;
|
|
260
265
|
- envelope keys are camelCase (`effectId`, `actorType`, `actorId`,
|
|
261
266
|
`operation`, and an optional `arguments` that defaults to an empty
|
|
262
267
|
object);
|
|
@@ -264,6 +269,13 @@ runtime idiom, but both sides guarantee the same wire contract:
|
|
|
264
269
|
- a replay with changed arguments raises the idempotency conflict on both
|
|
265
270
|
sides and leaves the first application intact.
|
|
266
271
|
|
|
272
|
+
JavaScript schema migration 14 adds an effect position for ordering within a
|
|
273
|
+
source message. Ruby uses its existing sequential effect primary key. Existing
|
|
274
|
+
JS rows receive position zero and retain their earlier ID-based tie-break;
|
|
275
|
+
their original staging order cannot be reconstructed. Run `runtime.install()`
|
|
276
|
+
before starting upgraded workers. The stronger ordering applies to effects
|
|
277
|
+
staged by upgraded workers.
|
|
278
|
+
|
|
267
279
|
`compatibility/transmit-envelopes.json` is committed to both repositories
|
|
268
280
|
with a consuming test on each side, so the contract is enforced from both
|
|
269
281
|
sides of the repository boundary. Manual cross-runtime QA (Node to Rails
|
|
@@ -310,3 +322,8 @@ checks. Per-effect recovery timeouts extend the runtime heartbeat threshold
|
|
|
310
322
|
(milliseconds in JS, seconds in Ruby). Cloudflare returns emit handles but rejects
|
|
311
323
|
process-heartbeat recovery options and intents before commit. See
|
|
312
324
|
[the transaction protocol](effect-recovery.md).
|
|
325
|
+
|
|
326
|
+
On SQLite, both runtimes mark the `status = 'processing'` test in the recovery
|
|
327
|
+
candidate query with `likelihood()`. The candidate scan then starts from the
|
|
328
|
+
effects poll index, also when `sqlite_stat1` shows that most effects have one
|
|
329
|
+
status.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solid-objects",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Race-free realtime state per application identity, backed by your SQL database",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -115,8 +115,8 @@
|
|
|
115
115
|
"test": "vitest run",
|
|
116
116
|
"test:browser": "pnpm run build && playwright test",
|
|
117
117
|
"test:coverage": "vitest run --coverage",
|
|
118
|
-
"test:postgresql": "vitest run test/postgresql.test.ts test/effect-recovery.test.ts test/instance-retention.test.ts",
|
|
119
|
-
"test:mysql": "vitest run test/mysql.test.ts test/effect-recovery.test.ts test/instance-retention.test.ts",
|
|
118
|
+
"test:postgresql": "vitest run test/postgresql.test.ts test/effect-recovery.test.ts test/instance-retention.test.ts test/transmit-ordering.test.ts",
|
|
119
|
+
"test:mysql": "vitest run test/mysql.test.ts test/effect-recovery.test.ts test/instance-retention.test.ts test/transmit-ordering.test.ts",
|
|
120
120
|
"test:package": "node scripts/release-artifact-smoke.mjs",
|
|
121
121
|
"test:recovery": "pnpm run build && node examples/failure-recovery/demo.ts",
|
|
122
122
|
"test:at-least-once": "pnpm run build && node examples/at-least-once/demo.ts",
|