solid-objects 0.15.2 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +157 -0
- package/README.md +1 -1
- package/dist/actor-runtime.d.ts +9 -1
- package/dist/actor-runtime.d.ts.map +1 -1
- package/dist/actor.d.ts +22 -4
- package/dist/actor.d.ts.map +1 -1
- package/dist/actor.js +81 -2
- package/dist/actor.js.map +1 -1
- package/dist/broadcast-worker.js +1 -1
- package/dist/broadcast-worker.js.map +1 -1
- package/dist/cloudflare/configuration.d.ts +3 -1
- package/dist/cloudflare/configuration.d.ts.map +1 -1
- package/dist/cloudflare/configuration.js +4 -0
- package/dist/cloudflare/configuration.js.map +1 -1
- package/dist/cloudflare/engine.d.ts +4 -0
- package/dist/cloudflare/engine.d.ts.map +1 -1
- package/dist/cloudflare/engine.js +91 -24
- 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 +8 -0
- package/dist/cloudflare/runtime.d.ts.map +1 -1
- package/dist/cloudflare/runtime.js +52 -1
- package/dist/cloudflare/runtime.js.map +1 -1
- package/dist/cloudflare/storage.d.ts +2 -0
- package/dist/cloudflare/storage.d.ts.map +1 -1
- package/dist/cloudflare/storage.js +10 -0
- package/dist/cloudflare/storage.js.map +1 -1
- package/dist/configuration.d.ts +9 -5
- package/dist/configuration.d.ts.map +1 -1
- package/dist/configuration.js +43 -7
- package/dist/configuration.js.map +1 -1
- package/dist/database/types.d.ts +4 -0
- package/dist/database/types.d.ts.map +1 -1
- package/dist/dead-letter-scopes.d.ts +75 -0
- package/dist/dead-letter-scopes.d.ts.map +1 -0
- package/dist/dead-letter-scopes.js +157 -0
- package/dist/dead-letter-scopes.js.map +1 -0
- package/dist/dead-letters.d.ts +5 -0
- package/dist/dead-letters.d.ts.map +1 -1
- package/dist/dead-letters.js +16 -0
- package/dist/dead-letters.js.map +1 -1
- package/dist/definition.d.ts +2 -0
- package/dist/definition.d.ts.map +1 -1
- package/dist/definition.js +1 -1
- package/dist/definition.js.map +1 -1
- package/dist/doctor.d.ts +1 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +35 -2
- package/dist/doctor.js.map +1 -1
- package/dist/effect-recovery-coordinator.d.ts +2 -0
- package/dist/effect-recovery-coordinator.d.ts.map +1 -1
- package/dist/effect-recovery-coordinator.js +5 -2
- package/dist/effect-recovery-coordinator.js.map +1 -1
- package/dist/effect-worker.js +1 -1
- package/dist/effect-worker.js.map +1 -1
- package/dist/errors.d.ts +4 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +7 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/outcome.d.ts +18 -0
- package/dist/outcome.d.ts.map +1 -0
- package/dist/outcome.js +2 -0
- package/dist/outcome.js.map +1 -0
- package/dist/platform/uuid.d.ts +1 -0
- package/dist/platform/uuid.d.ts.map +1 -1
- package/dist/platform/uuid.js +5 -0
- package/dist/platform/uuid.js.map +1 -1
- package/dist/records.d.ts +6 -0
- package/dist/records.d.ts.map +1 -1
- package/dist/redrive.d.ts +60 -0
- package/dist/redrive.d.ts.map +1 -0
- package/dist/redrive.js +239 -0
- package/dist/redrive.js.map +1 -0
- package/dist/reference.d.ts +17 -3
- package/dist/reference.d.ts.map +1 -1
- package/dist/reference.js +10 -0
- package/dist/reference.js.map +1 -1
- package/dist/reminder-scheduler.js +1 -1
- package/dist/reminder-scheduler.js.map +1 -1
- package/dist/repository.d.ts +34 -4
- package/dist/repository.d.ts.map +1 -1
- package/dist/repository.js +124 -21
- package/dist/repository.js.map +1 -1
- package/dist/runtime.d.ts +42 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +263 -6
- package/dist/runtime.js.map +1 -1
- package/dist/schema.d.ts +1 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +97 -1
- package/dist/schema.js.map +1 -1
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/wake-up/postgresql.d.ts +4 -2
- package/dist/wake-up/postgresql.d.ts.map +1 -1
- package/dist/wake-up/postgresql.js +9 -0
- package/dist/wake-up/postgresql.js.map +1 -1
- package/dist/wake-up/redis.d.ts +2 -1
- package/dist/wake-up/redis.d.ts.map +1 -1
- package/dist/wake-up/redis.js +6 -0
- package/dist/wake-up/redis.js.map +1 -1
- package/dist/wake-up-selection.d.ts +22 -0
- package/dist/wake-up-selection.d.ts.map +1 -0
- package/dist/wake-up-selection.js +198 -0
- package/dist/wake-up-selection.js.map +1 -0
- package/dist/wake-up.d.ts +15 -0
- package/dist/wake-up.d.ts.map +1 -1
- package/dist/wake-up.js +6 -0
- package/dist/wake-up.js.map +1 -1
- package/dist/worker.js +1 -1
- package/dist/worker.js.map +1 -1
- package/docs/api.md +202 -6
- package/docs/cloudflare.md +1 -0
- package/docs/configuration.md +52 -22
- package/docs/correctness.md +8 -0
- package/docs/dashboard.md +9 -0
- package/docs/fit.md +3 -1
- package/docs/operations.md +104 -7
- package/docs/parity.md +105 -25
- package/package.json +1 -1
package/docs/parity.md
CHANGED
|
@@ -51,26 +51,26 @@ SQL waiters read results and status from one statement. Ruby already checks
|
|
|
51
51
|
completion and returns the result from the same loaded message; no Ruby change
|
|
52
52
|
is needed for the JavaScript stale-result race fix.
|
|
53
53
|
|
|
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
|
-
| Fluent committed calls and background delivery | Native | `await reference.operation()` and `reference.send.operation()`.
|
|
58
|
-
| 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.
|
|
59
|
-
| 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.
|
|
60
|
-
| 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.
|
|
61
|
-
| Bounded claim candidate scan | Native | A configurable ordered scan continues to another ready actor when a worker loses the first candidate's lease race.
|
|
62
|
-
| Backpressure and payload caps | Partial | Serialization enforces a shared maximum JSON nesting depth, raising `InvalidPayload`, and an optional caller-supplied `maxBytes` limit, raising `PayloadTooLarge`; reminder names are bounded to 255 characters. Distributed per-actor rate limits
|
|
63
|
-
| 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.
|
|
64
|
-
| 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.
|
|
65
|
-
| Actor-to-actor delivery | Native | `sendTo(reference).operation()` stages delivery in the source actor commit.
|
|
66
|
-
| One-shot and recurring reminders | Native | Scheduling, replacement events, catch-up policy, stale-claim recovery, pausing, authorized inspection, and idempotent resume are implemented.
|
|
67
|
-
| Same-database commit actions | Native | Registered actions receive source-message identity, mailbox sequence, activation generation, and the fenced transaction connection.
|
|
68
|
-
| 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.
|
|
69
|
-
| 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.
|
|
70
|
-
| 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.
|
|
71
|
-
| 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.
|
|
72
|
-
| Result recovery and sync timeout diagnostics | Native | Status, result, and wait reauthorize the stored operation; terminal failure raises structured `MessageFailed`; whole-call adapter deadlines distinguish enqueue, wait, database, activation, and mailbox blockers.
|
|
73
|
-
| Result lookup by request ID
|
|
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
|
+
| Fluent committed calls and background delivery | Native | `await reference.operation()` and `reference.send.operation()`. |
|
|
58
|
+
| 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. |
|
|
59
|
+
| 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. |
|
|
60
|
+
| 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. |
|
|
61
|
+
| Bounded claim candidate scan | Native | A configurable ordered scan continues to another ready actor when a worker loses the first candidate's lease race. |
|
|
62
|
+
| Backpressure and payload caps | Partial | Serialization enforces a shared maximum JSON nesting depth, raising `InvalidPayload`, and an optional caller-supplied `maxBytes` limit, raising `PayloadTooLarge`; reminder names are bounded to 255 characters. 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. |
|
|
63
|
+
| 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. |
|
|
64
|
+
| 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. |
|
|
65
|
+
| Actor-to-actor delivery | Native | `sendTo(reference).operation()` stages delivery in the source actor commit. |
|
|
66
|
+
| One-shot and recurring reminders | Native | Scheduling, replacement events, catch-up policy, stale-claim recovery, pausing, authorized inspection, and idempotent resume are implemented. |
|
|
67
|
+
| Same-database commit actions | Native | Registered actions receive source-message identity, mailbox sequence, activation generation, and the fenced transaction connection. |
|
|
68
|
+
| 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. |
|
|
69
|
+
| 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. |
|
|
70
|
+
| 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. |
|
|
71
|
+
| 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. |
|
|
72
|
+
| Result recovery and sync timeout diagnostics | Native | Status, result, and wait reauthorize the stored operation; terminal failure raises structured `MessageFailed`; whole-call adapter deadlines distinguish enqueue, wait, database, activation, and mailbox blockers. |
|
|
73
|
+
| 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
74
|
|
|
75
75
|
Effect callback envelopes are typed with `EffectFailurePayload`,
|
|
76
76
|
`EffectSuccessPayload`, and `SerializedError` in both SQL and Cloudflare.
|
|
@@ -106,11 +106,86 @@ Ruby field names; this does not change runtime delivery semantics.
|
|
|
106
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
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
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
109
|
+
Both runtimes select a wake-up adapter automatically. `wakeUp` takes a name or
|
|
110
|
+
an adapter and defaults to `"automatic"`, which prefers a configured Redis URL,
|
|
111
|
+
then PostgreSQL notifications, then polling. Selection proves the PostgreSQL
|
|
112
|
+
path with a probe notification, because `LISTEN` does not survive a transaction
|
|
113
|
+
pooler. Each runtime reports what it installed, whether that crosses processes,
|
|
114
|
+
its measured floor, and why, and warns once when live processes share a
|
|
115
|
+
database and the installed adapter cannot reach them. MySQL still polls in both
|
|
116
|
+
runtimes, because MySQL has no notification channel.
|
|
117
|
+
|
|
118
|
+
A requested adapter that the environment cannot provide polls instead and says
|
|
119
|
+
so in both runtimes, rather than claim a cross-process wake-up that cannot
|
|
120
|
+
happen. Only a name that does not exist is refused.
|
|
121
|
+
|
|
122
|
+
Three details differ, and each follows from the language rather than from the
|
|
123
|
+
feature. The pooled-session warning is emitted once per runtime here and once
|
|
124
|
+
per process in Ruby, because this runtime supports several runtimes in one
|
|
125
|
+
process. A configured adapter must implement `watch`, `notify`, and `close`
|
|
126
|
+
here, while Ruby requires `signal` and `wait` and treats `watch` and `stop` as
|
|
127
|
+
optional, which is each runtime's own adapter contract. A selection that a later
|
|
128
|
+
edit of the settings makes impossible is reported once here and raised in Ruby;
|
|
129
|
+
both runtimes refuse an unknown name when the configuration is built, so this
|
|
130
|
+
only reaches code that changes the setting afterwards.
|
|
131
|
+
|
|
132
|
+
## Dead letters, retry, and redrive
|
|
133
|
+
|
|
134
|
+
Both runtimes scope dead letters by kind through one receiver, retry a dead
|
|
135
|
+
message, effect, or broadcast, redrive a whole scope as a durable and idempotent
|
|
136
|
+
task, bound that task to the rows that were dead when it started, advance it in
|
|
137
|
+
bounded batches, and write one administration event per retry and per task
|
|
138
|
+
transition, in the transaction that causes it. The filters, the resource names,
|
|
139
|
+
the audit actions, and the configuration defaults match.
|
|
140
|
+
|
|
141
|
+
Two details differ. This runtime filters on a `failed_at_ms` stamp that schema
|
|
142
|
+
version 11 adds, while Ruby filters on the `updated_at` column Active Record
|
|
143
|
+
already maintains. The Durable Objects engine keeps its own message and outbox
|
|
144
|
+
tables inside each object, so these scopes cover the SQL backends here; its
|
|
145
|
+
`deadLetters` call is unchanged.
|
|
146
|
+
|
|
147
|
+
## Result lookup
|
|
148
|
+
|
|
149
|
+
Both runtimes rebuild a `MessageReference` from a request id or an idempotency
|
|
150
|
+
key, scope each lookup through the receiver that matches its index, authorize it
|
|
151
|
+
with the hook the original call ran, and report absence, an unregistered actor,
|
|
152
|
+
and a refusal the same way. `outcome` reports the status, result, error,
|
|
153
|
+
rejection, and attempt count in both.
|
|
154
|
+
|
|
155
|
+
Three details differ, and all come from the runtimes rather than the feature.
|
|
156
|
+
This runtime stores a result for every completed message, so a lookup answers
|
|
157
|
+
one for asynchronous work; Ruby stores a result only for `sync` delivery, so a
|
|
158
|
+
lookup there answers the status and the error but not the result. This runtime
|
|
159
|
+
needed a new unique index on `request_id`, added as schema version 12, because
|
|
160
|
+
its table constrained the pair `(actor_type, actor_id, request_id)`; the Ruby
|
|
161
|
+
schema has carried a global unique index since its first migration. The error
|
|
162
|
+
record also differs: Ruby's `ErrorRecord` carries `class_name`, `message`, and
|
|
163
|
+
`backtrace`, while this runtime persists only `name` and `message`, because
|
|
164
|
+
`safeError` has never stored a stack. An `outcome` here reports what failed, not
|
|
165
|
+
where.
|
|
166
|
+
|
|
167
|
+
Both runtimes tell a pruned message from one that never existed the same way.
|
|
168
|
+
An actor remembers the idempotency keys of its own last
|
|
169
|
+
`retained_idempotency_keys` / `retainedIdempotencyKeys` finished turns, written
|
|
170
|
+
in the instance row the executor updates anyway, so a key lookup raises
|
|
171
|
+
`MessagePruned` for a message retention removed and answers absent for a
|
|
172
|
+
message that never existed. Each remembered key carries its operation and original arguments, so the
|
|
173
|
+
pruned answer runs the same authorization a lookup of the surviving row
|
|
174
|
+
would. Both also bound the serialized memory, because an
|
|
175
|
+
idempotency key has no length limit and the memory outlives the message row; an
|
|
176
|
+
actor drops its oldest keys until the list fits. The original operation selects the message or query authorization hook in both. A request id lookup answers absent in both cases,
|
|
177
|
+
because the runtime generates a request id and no actor remembers one.
|
|
178
|
+
|
|
179
|
+
Remembered arguments count toward the serialized memory limit and remain until
|
|
180
|
+
the entry is evicted or the instance is removed. Entries from older versions
|
|
181
|
+
that lack arguments return absence after pruning because their original
|
|
182
|
+
authorization cannot be reproduced.
|
|
183
|
+
|
|
184
|
+
The Durable Objects backend answers a key lookup and a request id lookup
|
|
185
|
+
through the actor that holds the row, and it remembers keys in the same
|
|
186
|
+
instance record. It cannot answer `findBy({ requestId })` without a reference,
|
|
187
|
+
because a Durable Object indexes only its own messages, so that form raises
|
|
188
|
+
`UnsupportedCapability`.
|
|
114
189
|
|
|
115
190
|
## Realtime and browser behavior
|
|
116
191
|
|
|
@@ -235,3 +310,8 @@ checks. Per-effect recovery timeouts extend the runtime heartbeat threshold
|
|
|
235
310
|
(milliseconds in JS, seconds in Ruby). Cloudflare returns emit handles but rejects
|
|
236
311
|
process-heartbeat recovery options and intents before commit. See
|
|
237
312
|
[the transaction protocol](effect-recovery.md).
|
|
313
|
+
|
|
314
|
+
On SQLite, both runtimes mark the `status = 'processing'` test in the recovery
|
|
315
|
+
candidate query with `likelihood()`. The candidate scan then starts from the
|
|
316
|
+
effects poll index, also when `sqlite_stat1` shows that most effects have one
|
|
317
|
+
status.
|