solid-objects 0.14.3 → 0.14.5
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 +65 -2
- package/README.md +159 -431
- package/dist/configuration.d.ts +1 -0
- package/dist/configuration.d.ts.map +1 -1
- package/dist/configuration.js +2 -0
- package/dist/configuration.js.map +1 -1
- package/dist/definition.d.ts +5 -0
- package/dist/definition.d.ts.map +1 -1
- package/dist/definition.js +12 -1
- package/dist/definition.js.map +1 -1
- package/dist/runtime.d.ts +12 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +38 -11
- package/dist/runtime.js.map +1 -1
- package/dist/serialization.d.ts +1 -0
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +6 -1
- package/dist/serialization.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/api.md +2 -2
- package/docs/authorization.md +2 -2
- package/docs/benchmarks.md +39 -2
- package/docs/configuration.md +12 -0
- package/docs/correctness.md +8 -8
- package/docs/fit.md +9 -1
- package/docs/parity.md +19 -18
- package/docs/state-and-lifecycle.md +30 -1
- package/package.json +2 -1
package/docs/parity.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Design parity ledger
|
|
2
2
|
|
|
3
3
|
This ledger tracks capability parity with the Ruby `solid_objects` gem.
|
|
4
|
-
Parity
|
|
5
|
-
not
|
|
4
|
+
Parity preserves a capability and its correctness or security boundary. It does
|
|
5
|
+
not copy a Rails API into Node.
|
|
6
6
|
|
|
7
7
|
Reference: Ruby `solid_objects` 0.14.0. The JavaScript package began at the
|
|
8
8
|
Ruby design's `0.12` capability generation; that version number did not imply
|
|
@@ -63,19 +63,20 @@ such boundary between a gem and its dependents.
|
|
|
63
63
|
|
|
64
64
|
## Operations
|
|
65
65
|
|
|
66
|
-
| Capability | Status | TypeScript shape or remaining work
|
|
67
|
-
| ----------------------------------------------------------------------------- | ------ |
|
|
68
|
-
| 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.
|
|
69
|
-
| Failed-role replacement | Native | Built-in and registered roles are rebuilt through their factories with capped backoff; shutdown is the terminal replacement boundary.
|
|
70
|
-
| Additional supervised components | Native | `registerComponent()` builds, validates, runs, and stops application components with the runtime.
|
|
71
|
-
| Dead-letter inspection and retry | Native | `runtime.deadLetters` provides deny-by-default immutable inspection and idempotent durable retry linkage.
|
|
72
|
-
| Reconciliation reads | Native | Authorized cursor pages cover active, quiet, and orphaned instances; bounded state batches are migrated and deeply frozen.
|
|
73
|
-
| 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.
|
|
74
|
-
| 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.
|
|
75
|
-
| CLI | Native | The packaged executable loads an application runtime and exposes start, diagnostics, processes, dead letters, reminders, and explicit retention pruning as JSON.
|
|
76
|
-
| Operator dashboard | Native | The opt-in `solid-objects/web` export provides Fetch and Node/Connect mounting, authorized runtime views and actions, session-backed CSRF, filtering, paging, charts, and immutable extension hooks. Matches the Ruby dashboard's own documented limits: no audit trail of admin actions, dead-letter retry is one at a time, and pause sets a flag rather than interrupting an in-flight turn.
|
|
77
|
-
| Structured instrumentation | Native | An isolated transport-neutral sink emits immutable lifecycle metadata and structurally excludes application payloads.
|
|
78
|
-
|
|
|
66
|
+
| Capability | Status | TypeScript shape or remaining work |
|
|
67
|
+
| ----------------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
68
|
+
| 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. |
|
|
69
|
+
| Failed-role replacement | Native | Built-in and registered roles are rebuilt through their factories with capped backoff; shutdown is the terminal replacement boundary. |
|
|
70
|
+
| Additional supervised components | Native | `registerComponent()` builds, validates, runs, and stops application components with the runtime. |
|
|
71
|
+
| Dead-letter inspection and retry | Native | `runtime.deadLetters` provides deny-by-default immutable inspection and idempotent durable retry linkage. |
|
|
72
|
+
| Reconciliation reads | Native | Authorized cursor pages cover active, quiet, and orphaned instances; bounded state batches are migrated and deeply frozen. |
|
|
73
|
+
| 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. |
|
|
74
|
+
| 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. |
|
|
75
|
+
| CLI | Native | The packaged executable loads an application runtime and exposes start, diagnostics, processes, dead letters, reminders, and explicit retention pruning as JSON. |
|
|
76
|
+
| Operator dashboard | Native | The opt-in `solid-objects/web` export provides Fetch and Node/Connect mounting, authorized runtime views and actions, session-backed CSRF, filtering, paging, charts, and immutable extension hooks. Matches the Ruby dashboard's own documented limits: no audit trail of admin actions, dead-letter retry is one at a time, and pause sets a flag rather than interrupting an in-flight turn. |
|
|
77
|
+
| Structured instrumentation | Native | An isolated transport-neutral sink emits immutable lifecycle metadata and structurally excludes application payloads. |
|
|
78
|
+
| 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. |
|
|
79
|
+
| Public test helper | Native | `runtime.testing` provides role-selective deterministic draining, explicit-time due-reminder execution, and dependency-ordered reset without relying on cascades. |
|
|
79
80
|
|
|
80
81
|
## Databases and wake-up
|
|
81
82
|
|
|
@@ -151,8 +152,8 @@ signal-consuming renderers track actors with no manual registration. No
|
|
|
151
152
|
Ruby row exists because the slot it fills is already native in Rails:
|
|
152
153
|
the gem's Turbo and Action Cable component surface re-renders partials
|
|
153
154
|
from the same committed observables. Each runtime renders with its
|
|
154
|
-
ecosystem's primitive
|
|
155
|
-
revision fencing and the same privacy model
|
|
155
|
+
ecosystem's primitive. Parity here preserves the guarantee: views track
|
|
156
|
+
committed state under revision fencing and the same privacy model.
|
|
156
157
|
|
|
157
158
|
## Shared capability: the transmit family
|
|
158
159
|
|
|
@@ -163,7 +164,7 @@ from proposals [#47](https://github.com/cardmagic/solid-objects-ruby/issues/47)
|
|
|
163
164
|
and [#48](https://github.com/cardmagic/solid-objects-ruby/issues/48)):
|
|
164
165
|
`SolidObjects::Transmission.receive` is the ingest, and `Actor#transmit`
|
|
165
166
|
with `register_transmit` is the staging side. Identifiers differ by
|
|
166
|
-
runtime idiom
|
|
167
|
+
runtime idiom, but both sides guarantee the same wire contract:
|
|
167
168
|
|
|
168
169
|
- envelope keys are camelCase (`effectId`, `actorType`, `actorId`,
|
|
169
170
|
`operation`, and an optional `arguments` that defaults to an empty
|
|
@@ -18,7 +18,36 @@ fields, then walks its prototype chain to discover methods and getters.
|
|
|
18
18
|
|
|
19
19
|
The constructor must establish every persisted field and must not depend on
|
|
20
20
|
external state. Solid Objects invokes it at four points: class validation,
|
|
21
|
-
default creation, state hydration, and snapshot projection.
|
|
21
|
+
default creation, state hydration, and snapshot projection. Because the
|
|
22
|
+
constructor must not depend on external state, the runtime computes the default
|
|
23
|
+
state once for each registered class and gives each caller a detached copy.
|
|
24
|
+
|
|
25
|
+
## State size and throughput
|
|
26
|
+
|
|
27
|
+
Solid Objects commits the whole state image on each turn. The turn therefore
|
|
28
|
+
reads, encodes, and writes every persisted field, and its cost grows with the
|
|
29
|
+
size of the state rather than with the size of the change.
|
|
30
|
+
|
|
31
|
+
Measured on August 29, 2026 on an Apple M5, macOS 26.6, Node.js 24.18.0, and
|
|
32
|
+
SQLite 3.53.1 through `node:sqlite`. One actor, one `increment()` operation,
|
|
33
|
+
sequential turns, 300 measured operations per row, and the `0.14.4` source
|
|
34
|
+
tree.
|
|
35
|
+
|
|
36
|
+
| Persisted state | ms per operation | Operations per second |
|
|
37
|
+
| --------------: | ---------------: | --------------------: |
|
|
38
|
+
| 0 KB | 1.60 | 625 |
|
|
39
|
+
| 16 KB | 1.64 | 611 |
|
|
40
|
+
| 128 KB | 2.53 | 395 |
|
|
41
|
+
| 1 MB | 9.32 | 107 |
|
|
42
|
+
|
|
43
|
+
These are developer-laptop numbers. They show the shape of the curve, not a
|
|
44
|
+
capacity guarantee. See [Benchmarks](benchmarks.md#large-state) for the harness
|
|
45
|
+
and the earlier numbers.
|
|
46
|
+
|
|
47
|
+
Keep one actor's state small, and divide a large state across more identities.
|
|
48
|
+
`warnStateBytes` reports one `solid_objects.state.large` instrumentation event
|
|
49
|
+
when a committed image passes its threshold, which defaults to 128 KB.
|
|
50
|
+
`maxStateBytes` is the hard limit, and it fails the turn.
|
|
22
51
|
|
|
23
52
|
## Observable broadcast modes
|
|
24
53
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solid-objects",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.5",
|
|
4
4
|
"description": "Race-free realtime state per application identity, backed by your SQL database",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -112,6 +112,7 @@
|
|
|
112
112
|
"test:watch": "vitest",
|
|
113
113
|
"benchmark": "pnpm run build && node benchmarks/run.ts",
|
|
114
114
|
"benchmark:idle": "pnpm run build && node benchmarks/idle.ts",
|
|
115
|
+
"benchmark:large-state": "pnpm run build && node benchmarks/large-state.ts",
|
|
115
116
|
"pack:check": "pnpm pack --dry-run && node scripts/check-package.mjs",
|
|
116
117
|
"prepack": "pnpm run build"
|
|
117
118
|
},
|