solid-objects 0.14.0 → 0.14.2
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 +40 -0
- package/README.md +47 -8
- package/dist/examples/quickstart-report.js +1 -1
- package/dist/examples/quickstart-report.js.map +1 -1
- package/dist/reference.d.ts +16 -1
- package/dist/reference.d.ts.map +1 -1
- package/dist/reference.js +12 -0
- package/dist/reference.js.map +1 -1
- package/dist/signals.d.ts +9 -0
- package/dist/signals.d.ts.map +1 -0
- package/dist/signals.js +299 -0
- package/dist/signals.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/api.md +63 -0
- package/docs/correctness.md +6 -1
- package/docs/fit.md +3 -1
- package/docs/operations.md +7 -0
- package/docs/parity.md +15 -4
- package/docs/support.md +15 -0
- package/examples/at-least-once/actor.ts +13 -0
- package/examples/at-least-once/demo.ts +129 -0
- package/examples/at-least-once/effect-worker.ts +62 -0
- package/examples/at-least-once/sink.ts +34 -0
- package/examples/quickstart-report.ts +1 -1
- package/package.json +11 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.14.2 - 2026-08-24
|
|
4
|
+
|
|
5
|
+
- State that background pickup needs `runtime.run(signal)`
|
|
6
|
+
([#22](https://github.com/cardmagic/solid-objects-js/issues/22)). The
|
|
7
|
+
README's programming-model example works without it because the caller's
|
|
8
|
+
own path executes the call, and nothing on that page said that a process
|
|
9
|
+
which installs and then waits claims nothing. An external prober built a
|
|
10
|
+
two-process harness from the README and read the unclaimed messages as
|
|
11
|
+
stranded. The README and `docs/operations.md` now state it, and
|
|
12
|
+
`test/background-pickup.test.ts` pins it: a sent message reads `ready`
|
|
13
|
+
after `install()`, and `completed` once `run(signal)` starts the roles.
|
|
14
|
+
- Build the same example with `configure()` and address the actor as
|
|
15
|
+
`Cart.ref("cart-123")`, matching every other reference example in the
|
|
16
|
+
documentation. `createRuntime()` deliberately leaves the process default
|
|
17
|
+
unset, so the static form needs `configure()`.
|
|
18
|
+
- Add `examples/at-least-once` and `pnpm run test:at-least-once`
|
|
19
|
+
([#23](https://github.com/cardmagic/solid-objects-js/issues/23)): an
|
|
20
|
+
executable proof that the at-least-once clause fires and that the
|
|
21
|
+
documented remedy absorbs it. An effect worker crashes between the
|
|
22
|
+
external sink write and the acknowledgement; after restart the sink
|
|
23
|
+
reads 2 with deduplication off, and 1 when a guard on the stable
|
|
24
|
+
effect id is in place. The state commit happens exactly once in both
|
|
25
|
+
runs, and both deliveries carry the same effect id. CI runs the demo
|
|
26
|
+
alongside the recovery demo.
|
|
27
|
+
|
|
28
|
+
## 0.14.1 - 2026-08-23
|
|
29
|
+
|
|
30
|
+
- Add `solid-objects/signals`, live signals on actor references
|
|
31
|
+
([#24](https://github.com/cardmagic/solid-objects-js/issues/24)). One
|
|
32
|
+
side-effect import enables `reference.live`: read-only signals on the
|
|
33
|
+
proposed standard JavaScript signals API (`signal-polyfill`, a new
|
|
34
|
+
optional peer dependency) that subscribe through an in-process
|
|
35
|
+
`runtime.realtime` session when first watched and unsubscribe after a
|
|
36
|
+
linger when the last watcher leaves. Value-broadcast observables feed
|
|
37
|
+
named signals; `live.snapshot` re-fetches the authorized snapshot on
|
|
38
|
+
each accepted envelope; `live.payloads.<name>` carries personalized
|
|
39
|
+
payload projections under their independent revision fences; stale
|
|
40
|
+
revisions are fenced. Works in Node and
|
|
41
|
+
in the browser runtime.
|
|
42
|
+
|
|
3
43
|
## 0.14.0 - 2026-08-23
|
|
4
44
|
|
|
5
45
|
- Add `solid-objects/database/shared-sqlite-wasm`, the transparent
|
package/README.md
CHANGED
|
@@ -18,8 +18,9 @@ reminders, the effects, and the realtime invalidations in the database the
|
|
|
18
18
|
application already operates.
|
|
19
19
|
|
|
20
20
|
The same runtime also runs inside a browser worker on SQLite WASM, with
|
|
21
|
-
durable actor state in the origin's private file system
|
|
22
|
-
|
|
21
|
+
durable actor state in the origin's private file system, and its offline
|
|
22
|
+
writes can replay onto a Node **or Rails** backend over one shared wire
|
|
23
|
+
contract. See [Solid Objects in the browser](#solid-objects-in-the-browser).
|
|
23
24
|
|
|
24
25
|
> **Early release:** the correctness core has automated coverage. That coverage
|
|
25
26
|
> includes the supported databases, the Chromium browser client, the browser
|
|
@@ -38,7 +39,7 @@ durable actor state in the origin's private file system. See
|
|
|
38
39
|
## The programming model
|
|
39
40
|
|
|
40
41
|
```typescript
|
|
41
|
-
import { Actor,
|
|
42
|
+
import { Actor, configure } from "solid-objects"
|
|
42
43
|
import { sqlite } from "solid-objects/database/sqlite"
|
|
43
44
|
|
|
44
45
|
class Cart extends Actor {
|
|
@@ -52,7 +53,7 @@ class Cart extends Actor {
|
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
const runtime =
|
|
56
|
+
const runtime = configure({
|
|
56
57
|
database: sqlite({ path: "cart.sqlite3" }),
|
|
57
58
|
authorizeMessage: () => true,
|
|
58
59
|
authorizeQuery: () => true,
|
|
@@ -61,7 +62,7 @@ const runtime = createRuntime({
|
|
|
61
62
|
await runtime.install()
|
|
62
63
|
|
|
63
64
|
try {
|
|
64
|
-
const cart =
|
|
65
|
+
const cart = Cart.ref("cart-123")
|
|
65
66
|
await Promise.all([cart.add({ sku: "blue-shirt" }), cart.add({ sku: "green-hat" })])
|
|
66
67
|
} finally {
|
|
67
68
|
await runtime.close()
|
|
@@ -72,6 +73,18 @@ Both calls enter the durable mailbox for `cart-123`. They execute in order and
|
|
|
72
73
|
commit one state transition at a time, even when different requests or Node.js
|
|
73
74
|
processes submit them concurrently.
|
|
74
75
|
|
|
76
|
+
`install()` prepares the database and starts nothing. The example above finishes
|
|
77
|
+
because the caller's own path executes each call. A process serves background
|
|
78
|
+
work only after `runtime.run(signal)` starts its roles, so a process that
|
|
79
|
+
installs and then waits never claims a ready message. Nothing is lost while no
|
|
80
|
+
process runs. The message stays ready until one does.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const controller = new AbortController()
|
|
84
|
+
process.on("SIGTERM", () => controller.abort())
|
|
85
|
+
await runtime.run(controller.signal)
|
|
86
|
+
```
|
|
87
|
+
|
|
75
88
|
## Run it now with SQLite
|
|
76
89
|
|
|
77
90
|
Node.js 24.4.0 or newer is required. Node.js 24.15 or newer is preferred,
|
|
@@ -333,9 +346,35 @@ Two companions complete the local-first story:
|
|
|
333
346
|
every operation, and other tabs invoke through a `BroadcastChannel` client
|
|
334
347
|
by name.
|
|
335
348
|
- `solid-objects/transmit` drains the transactional effects outbox to a
|
|
336
|
-
server
|
|
337
|
-
|
|
338
|
-
|
|
349
|
+
server with at-least-once delivery, per-actor order, and an idempotent
|
|
350
|
+
server ingest, so offline writes reconcile when the network returns.
|
|
351
|
+
|
|
352
|
+
### The backend can be Rails, not only Node
|
|
353
|
+
|
|
354
|
+
The browser runtime does not require a Node server behind it. The transmit
|
|
355
|
+
wire contract is shared with the Ruby gem
|
|
356
|
+
([solid-objects-ruby](https://github.com/cardmagic/solid-objects-ruby)):
|
|
357
|
+
`SolidObjects::Transmission.receive` accepts the same envelopes as the Node
|
|
358
|
+
ingest `receiveTransmitEnvelope`, dedups on the same `transmit:<effectId>`
|
|
359
|
+
key, and both repositories pin the contract with one shared fixture file.
|
|
360
|
+
A browser front end on `solid-objects/browser/host` inside a Rails
|
|
361
|
+
application therefore replays its offline writes directly onto Ruby server
|
|
362
|
+
actors — no Node service in between:
|
|
363
|
+
|
|
364
|
+
```ruby
|
|
365
|
+
class TransmitController < ApplicationController
|
|
366
|
+
def create
|
|
367
|
+
head :forbidden and return unless authenticated_device?
|
|
368
|
+
|
|
369
|
+
SolidObjects::Transmission.receive(JSON.parse(request.body.read))
|
|
370
|
+
head :ok
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
The Ruby side of the family shipped in `solid_objects` 0.14.0, released the
|
|
376
|
+
same day as this package's 0.14.0
|
|
377
|
+
([solid-objects-ruby#49](https://github.com/cardmagic/solid-objects-ruby/pull/49)).
|
|
339
378
|
|
|
340
379
|
The wire shapes are documented in the
|
|
341
380
|
[browser protocol](docs/browser-protocol.md), the API in the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const INSTALL_COMMAND = "npm install solid-objects";
|
|
2
2
|
const AGENT_PROMPT = "where would the solid-objects library be best used in this app?";
|
|
3
|
-
const DOCUMENTATION_URL = "https://solidobjects.dev/
|
|
3
|
+
const DOCUMENTATION_URL = "https://solidobjects.dev/js";
|
|
4
4
|
export function formatQuickstartPlan(plan) {
|
|
5
5
|
return [
|
|
6
6
|
"Solid Objects quickstart",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quickstart-report.js","sourceRoot":"","sources":["../../examples/quickstart-report.ts"],"names":[],"mappings":"AAaA,MAAM,eAAe,GAAG,2BAA2B,CAAA;AACnD,MAAM,YAAY,GAAG,iEAAiE,CAAA;AACtF,MAAM,iBAAiB,GAAG
|
|
1
|
+
{"version":3,"file":"quickstart-report.js","sourceRoot":"","sources":["../../examples/quickstart-report.ts"],"names":[],"mappings":"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"}
|
package/dist/reference.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Actor, ActorClass } from "./actor.js";
|
|
2
2
|
import type { SolidObjectsRuntime } from "./runtime.js";
|
|
3
|
-
import type { AsyncInvocationOptions, DeepReadonly, DestroyOptions, InvocationOptions, JsonObject, MessageStatus, SnapshotOptions } from "./types.js";
|
|
3
|
+
import type { AsyncInvocationOptions, DeepReadonly, DestroyOptions, InvocationOptions, JsonObject, JsonValue, MessageStatus, SnapshotOptions } from "./types.js";
|
|
4
4
|
type FunctionKeys<Value> = {
|
|
5
5
|
[Key in keyof Value]-?: Value[Key] extends (...argumentsValue: any[]) => any ? Key : never;
|
|
6
6
|
}[keyof Value];
|
|
@@ -63,7 +63,21 @@ export declare class ActorMessageSenderCore<ActorType extends Actor> {
|
|
|
63
63
|
constructor(reference: ActorReferenceCore<ActorType>);
|
|
64
64
|
with(options: AsyncInvocationOptions): ActorMessageSender<ActorType>;
|
|
65
65
|
}
|
|
66
|
+
export interface LiveSignal<Value> {
|
|
67
|
+
get(): Value;
|
|
68
|
+
}
|
|
69
|
+
export type ActorLiveSignals<ActorType extends Actor> = {
|
|
70
|
+
readonly snapshot: LiveSignal<ActorSnapshot<ActorType> | undefined>;
|
|
71
|
+
readonly payloads: {
|
|
72
|
+
readonly [name: string]: LiveSignal<DeepReadonly<JsonValue> | undefined>;
|
|
73
|
+
};
|
|
74
|
+
} & {
|
|
75
|
+
readonly [name: string]: LiveSignal<DeepReadonly<JsonValue> | undefined>;
|
|
76
|
+
};
|
|
77
|
+
export type LiveSignalsFactory = (reference: ActorReferenceCore<Actor>) => object;
|
|
78
|
+
export declare function installLiveSignals(factory: LiveSignalsFactory): void;
|
|
66
79
|
export declare class ActorReferenceCore<ActorType extends Actor> {
|
|
80
|
+
#private;
|
|
67
81
|
readonly send: ActorMessageSender<ActorType>;
|
|
68
82
|
readonly runtime: SolidObjectsRuntime;
|
|
69
83
|
readonly actorClass: ActorClass<ActorType>;
|
|
@@ -80,6 +94,7 @@ export declare class ActorReferenceCore<ActorType extends Actor> {
|
|
|
80
94
|
queries: ReadonlySet<string>;
|
|
81
95
|
});
|
|
82
96
|
with(options: InvocationOptions): ActorInvoker<ActorType>;
|
|
97
|
+
get live(): ActorLiveSignals<ActorType>;
|
|
83
98
|
snapshot(options?: SnapshotOptions): Promise<ActorSnapshot<ActorType>>;
|
|
84
99
|
destroy(options?: DestroyOptions): Promise<boolean>;
|
|
85
100
|
}
|
package/dist/reference.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reference.d.ts","sourceRoot":"","sources":["../src/reference.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"reference.d.ts","sourceRoot":"","sources":["../src/reference.ts"],"names":[],"mappings":"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"}
|
package/dist/reference.js
CHANGED
|
@@ -45,6 +45,10 @@ export class ActorMessageSenderCore {
|
|
|
45
45
|
return createMessageSender(this.reference, options);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
+
let liveSignalsFactory;
|
|
49
|
+
export function installLiveSignals(factory) {
|
|
50
|
+
liveSignalsFactory = factory;
|
|
51
|
+
}
|
|
48
52
|
export class ActorReferenceCore {
|
|
49
53
|
send;
|
|
50
54
|
runtime;
|
|
@@ -65,6 +69,14 @@ export class ActorReferenceCore {
|
|
|
65
69
|
with(options) {
|
|
66
70
|
return createInvoker(this, options);
|
|
67
71
|
}
|
|
72
|
+
#live;
|
|
73
|
+
get live() {
|
|
74
|
+
if (!liveSignalsFactory) {
|
|
75
|
+
throw new Error('ref.live is inactive; import "solid-objects/signals" once to enable live signals');
|
|
76
|
+
}
|
|
77
|
+
this.#live ??= liveSignalsFactory(this);
|
|
78
|
+
return this.#live;
|
|
79
|
+
}
|
|
68
80
|
snapshot(options = {}) {
|
|
69
81
|
return this.runtime.snapshot(this, options);
|
|
70
82
|
}
|
package/dist/reference.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reference.js","sourceRoot":"","sources":["../src/reference.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"reference.js","sourceRoot":"","sources":["../src/reference.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type { ActorLiveSignals, LiveSignal } from "./reference.js";
|
|
2
|
+
export interface LiveSignalsConfiguration {
|
|
3
|
+
lingerMilliseconds?: number;
|
|
4
|
+
retryMilliseconds?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare function configureLiveSignals(configuration: LiveSignalsConfiguration): void;
|
|
7
|
+
export declare function liveEntryCount(runtime: object): number;
|
|
8
|
+
export declare function activeLiveSubscriptionCount(): number;
|
|
9
|
+
//# sourceMappingURL=signals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../src/signals.ts"],"names":[],"mappings":"AAWA,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAElE,MAAM,WAAW,wBAAwB;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AASD,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,wBAAwB,GAAG,IAAI,CAgBlF;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAQtD;AAED,wBAAgB,2BAA2B,IAAI,MAAM,CAEpD"}
|
package/dist/signals.js
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { Signal } from "signal-polyfill";
|
|
2
|
+
import { installLiveSignals, } from "./reference.js";
|
|
3
|
+
const SNAPSHOT_KEY = "snapshot";
|
|
4
|
+
const PAYLOADS_KEY = "payloads";
|
|
5
|
+
let lingerMilliseconds = 1_000;
|
|
6
|
+
let retryMilliseconds = 1_000;
|
|
7
|
+
const openSessions = new Set();
|
|
8
|
+
export function configureLiveSignals(configuration) {
|
|
9
|
+
if (configuration.lingerMilliseconds !== undefined) {
|
|
10
|
+
if (!Number.isFinite(configuration.lingerMilliseconds) ||
|
|
11
|
+
configuration.lingerMilliseconds < 0) {
|
|
12
|
+
throw new TypeError("lingerMilliseconds must be a non-negative number");
|
|
13
|
+
}
|
|
14
|
+
lingerMilliseconds = configuration.lingerMilliseconds;
|
|
15
|
+
}
|
|
16
|
+
if (configuration.retryMilliseconds !== undefined) {
|
|
17
|
+
if (!Number.isFinite(configuration.retryMilliseconds) || configuration.retryMilliseconds < 0) {
|
|
18
|
+
throw new TypeError("retryMilliseconds must be a non-negative number");
|
|
19
|
+
}
|
|
20
|
+
retryMilliseconds = configuration.retryMilliseconds;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function liveEntryCount(runtime) {
|
|
24
|
+
const entries = entriesByRuntime.get(runtime);
|
|
25
|
+
if (!entries)
|
|
26
|
+
return 0;
|
|
27
|
+
let alive = 0;
|
|
28
|
+
for (const reference of entries.values()) {
|
|
29
|
+
if (reference.deref() !== undefined)
|
|
30
|
+
alive += 1;
|
|
31
|
+
}
|
|
32
|
+
return alive;
|
|
33
|
+
}
|
|
34
|
+
export function activeLiveSubscriptionCount() {
|
|
35
|
+
return openSessions.size;
|
|
36
|
+
}
|
|
37
|
+
class LiveActorEntry {
|
|
38
|
+
#reference;
|
|
39
|
+
#states = new Map();
|
|
40
|
+
#mirrors = new Map();
|
|
41
|
+
#snapshotState = new Signal.State(undefined);
|
|
42
|
+
#snapshotMirror;
|
|
43
|
+
#payloadStates = new Map();
|
|
44
|
+
#payloadMirrors = new Map();
|
|
45
|
+
#payloadWatcherCounts = new Map();
|
|
46
|
+
#payloadFences = new Map();
|
|
47
|
+
#payloadsProxy;
|
|
48
|
+
#watcherCount = 0;
|
|
49
|
+
#snapshotWatcherCount = 0;
|
|
50
|
+
#session;
|
|
51
|
+
#linger;
|
|
52
|
+
#instanceId;
|
|
53
|
+
#revision = -1n;
|
|
54
|
+
#refreshing = false;
|
|
55
|
+
#refreshQueued = false;
|
|
56
|
+
#retry;
|
|
57
|
+
constructor(reference) {
|
|
58
|
+
this.#reference = reference;
|
|
59
|
+
}
|
|
60
|
+
signalFor(name) {
|
|
61
|
+
const existing = this.#mirrors.get(name);
|
|
62
|
+
if (existing)
|
|
63
|
+
return existing;
|
|
64
|
+
const state = this.stateFor(name);
|
|
65
|
+
const mirror = new Signal.Computed(() => state.get(), {
|
|
66
|
+
[Signal.subtle.watched]: () => this.retain({ snapshot: false }),
|
|
67
|
+
[Signal.subtle.unwatched]: () => this.release({ snapshot: false }),
|
|
68
|
+
});
|
|
69
|
+
this.#mirrors.set(name, mirror);
|
|
70
|
+
return mirror;
|
|
71
|
+
}
|
|
72
|
+
payloadsProxy() {
|
|
73
|
+
this.#payloadsProxy ??= new Proxy({}, {
|
|
74
|
+
get: (_target, property) => {
|
|
75
|
+
if (typeof property !== "string")
|
|
76
|
+
return undefined;
|
|
77
|
+
return this.payloadSignalFor(property);
|
|
78
|
+
},
|
|
79
|
+
has: (_target, property) => typeof property === "string",
|
|
80
|
+
});
|
|
81
|
+
return this.#payloadsProxy;
|
|
82
|
+
}
|
|
83
|
+
payloadSignalFor(name) {
|
|
84
|
+
const existing = this.#payloadMirrors.get(name);
|
|
85
|
+
if (existing)
|
|
86
|
+
return existing;
|
|
87
|
+
const state = this.payloadStateFor(name);
|
|
88
|
+
const mirror = new Signal.Computed(() => state.get(), {
|
|
89
|
+
[Signal.subtle.watched]: () => {
|
|
90
|
+
this.#payloadWatcherCounts.set(name, (this.#payloadWatcherCounts.get(name) ?? 0) + 1);
|
|
91
|
+
this.retain({ snapshot: false, payloadName: name });
|
|
92
|
+
},
|
|
93
|
+
[Signal.subtle.unwatched]: () => {
|
|
94
|
+
const count = (this.#payloadWatcherCounts.get(name) ?? 1) - 1;
|
|
95
|
+
if (count <= 0)
|
|
96
|
+
this.#payloadWatcherCounts.delete(name);
|
|
97
|
+
else
|
|
98
|
+
this.#payloadWatcherCounts.set(name, count);
|
|
99
|
+
this.release({ snapshot: false });
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
this.#payloadMirrors.set(name, mirror);
|
|
103
|
+
return mirror;
|
|
104
|
+
}
|
|
105
|
+
payloadStateFor(name) {
|
|
106
|
+
let state = this.#payloadStates.get(name);
|
|
107
|
+
if (!state) {
|
|
108
|
+
state = new Signal.State(undefined);
|
|
109
|
+
this.#payloadStates.set(name, state);
|
|
110
|
+
}
|
|
111
|
+
return state;
|
|
112
|
+
}
|
|
113
|
+
snapshotSignal() {
|
|
114
|
+
this.#snapshotMirror ??= new Signal.Computed(() => this.#snapshotState.get(), {
|
|
115
|
+
[Signal.subtle.watched]: () => this.retain({ snapshot: true }),
|
|
116
|
+
[Signal.subtle.unwatched]: () => this.release({ snapshot: true }),
|
|
117
|
+
});
|
|
118
|
+
return this.#snapshotMirror;
|
|
119
|
+
}
|
|
120
|
+
stateFor(name) {
|
|
121
|
+
let state = this.#states.get(name);
|
|
122
|
+
if (!state) {
|
|
123
|
+
state = new Signal.State(undefined);
|
|
124
|
+
this.#states.set(name, state);
|
|
125
|
+
}
|
|
126
|
+
return state;
|
|
127
|
+
}
|
|
128
|
+
retain(options) {
|
|
129
|
+
this.#watcherCount += 1;
|
|
130
|
+
if (options.snapshot)
|
|
131
|
+
this.#snapshotWatcherCount += 1;
|
|
132
|
+
if (this.#linger !== undefined) {
|
|
133
|
+
clearTimeout(this.#linger);
|
|
134
|
+
this.#linger = undefined;
|
|
135
|
+
}
|
|
136
|
+
if (!this.#session)
|
|
137
|
+
this.open();
|
|
138
|
+
else if (options.payloadName !== undefined)
|
|
139
|
+
this.sendSubscribe(this.#session);
|
|
140
|
+
else if (options.snapshot)
|
|
141
|
+
void this.refreshSnapshot();
|
|
142
|
+
}
|
|
143
|
+
release(options) {
|
|
144
|
+
this.#watcherCount -= 1;
|
|
145
|
+
if (options.snapshot)
|
|
146
|
+
this.#snapshotWatcherCount -= 1;
|
|
147
|
+
if (this.#watcherCount > 0)
|
|
148
|
+
return;
|
|
149
|
+
if (this.#linger !== undefined)
|
|
150
|
+
clearTimeout(this.#linger);
|
|
151
|
+
this.#linger = setTimeout(() => {
|
|
152
|
+
this.#linger = undefined;
|
|
153
|
+
if (this.#watcherCount === 0)
|
|
154
|
+
this.close();
|
|
155
|
+
}, lingerMilliseconds);
|
|
156
|
+
}
|
|
157
|
+
open() {
|
|
158
|
+
if (this.#retry !== undefined) {
|
|
159
|
+
clearTimeout(this.#retry);
|
|
160
|
+
this.#retry = undefined;
|
|
161
|
+
}
|
|
162
|
+
const session = this.#reference.runtime.realtime.connect({
|
|
163
|
+
authorizationContext: undefined,
|
|
164
|
+
send: (envelope) => this.receive(envelope),
|
|
165
|
+
});
|
|
166
|
+
this.#session = session;
|
|
167
|
+
openSessions.add(this);
|
|
168
|
+
void this.sendSubscribe(session)
|
|
169
|
+
.then(() => this.refreshSnapshot())
|
|
170
|
+
.catch((error) => {
|
|
171
|
+
this.#reference.runtime.settings.logger.warn({
|
|
172
|
+
event: "solid_objects.live_signals.subscribe_failed",
|
|
173
|
+
actorType: this.#reference.actorType,
|
|
174
|
+
actorId: this.#reference.actorId,
|
|
175
|
+
error: error instanceof Error ? error.name : "Error",
|
|
176
|
+
});
|
|
177
|
+
if (this.#session !== session)
|
|
178
|
+
return;
|
|
179
|
+
this.close();
|
|
180
|
+
if (this.#watcherCount === 0)
|
|
181
|
+
return;
|
|
182
|
+
this.#retry = setTimeout(() => {
|
|
183
|
+
this.#retry = undefined;
|
|
184
|
+
if (this.#watcherCount > 0 && !this.#session)
|
|
185
|
+
this.open();
|
|
186
|
+
}, retryMilliseconds);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
sendSubscribe(session) {
|
|
190
|
+
const payloadNames = [...this.#payloadWatcherCounts.keys()];
|
|
191
|
+
return session.receive({
|
|
192
|
+
version: 1,
|
|
193
|
+
action: "subscribe",
|
|
194
|
+
actorType: this.#reference.actorType,
|
|
195
|
+
actorId: this.#reference.actorId,
|
|
196
|
+
...(payloadNames.length > 0 ? { payloads: payloadNames } : {}),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
close() {
|
|
200
|
+
if (this.#retry !== undefined) {
|
|
201
|
+
clearTimeout(this.#retry);
|
|
202
|
+
this.#retry = undefined;
|
|
203
|
+
}
|
|
204
|
+
const session = this.#session;
|
|
205
|
+
if (!session)
|
|
206
|
+
return;
|
|
207
|
+
this.#session = undefined;
|
|
208
|
+
openSessions.delete(this);
|
|
209
|
+
session.close();
|
|
210
|
+
}
|
|
211
|
+
receive(envelope) {
|
|
212
|
+
if (envelope.kind === "payload") {
|
|
213
|
+
this.receivePayload(envelope);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (envelope.kind !== "invalidation")
|
|
217
|
+
return;
|
|
218
|
+
const revision = BigInt(envelope.revision);
|
|
219
|
+
if (this.#instanceId === envelope.instanceId && revision <= this.#revision)
|
|
220
|
+
return;
|
|
221
|
+
this.#instanceId = envelope.instanceId;
|
|
222
|
+
this.#revision = revision;
|
|
223
|
+
for (const [name, value] of Object.entries(envelope.observables)) {
|
|
224
|
+
this.stateFor(name).set(value);
|
|
225
|
+
}
|
|
226
|
+
void this.refreshSnapshot();
|
|
227
|
+
}
|
|
228
|
+
receivePayload(envelope) {
|
|
229
|
+
const revision = BigInt(envelope.revision);
|
|
230
|
+
const fence = this.#payloadFences.get(envelope.name);
|
|
231
|
+
if (fence && fence.instanceId === envelope.instanceId && revision <= fence.revision)
|
|
232
|
+
return;
|
|
233
|
+
this.#payloadFences.set(envelope.name, { instanceId: envelope.instanceId, revision });
|
|
234
|
+
this.payloadStateFor(envelope.name).set(envelope.payload);
|
|
235
|
+
}
|
|
236
|
+
async refreshSnapshot() {
|
|
237
|
+
if (this.#snapshotWatcherCount === 0)
|
|
238
|
+
return;
|
|
239
|
+
if (this.#refreshing) {
|
|
240
|
+
this.#refreshQueued = true;
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
this.#refreshing = true;
|
|
244
|
+
try {
|
|
245
|
+
const snapshot = await this.#reference.snapshot();
|
|
246
|
+
this.#snapshotState.set(snapshot);
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
this.#reference.runtime.settings.logger.warn({
|
|
250
|
+
event: "solid_objects.live_signals.snapshot_failed",
|
|
251
|
+
actorType: this.#reference.actorType,
|
|
252
|
+
actorId: this.#reference.actorId,
|
|
253
|
+
error: error instanceof Error ? error.name : "Error",
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
finally {
|
|
257
|
+
this.#refreshing = false;
|
|
258
|
+
if (this.#refreshQueued) {
|
|
259
|
+
this.#refreshQueued = false;
|
|
260
|
+
void this.refreshSnapshot();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const entriesByRuntime = new WeakMap();
|
|
266
|
+
const collectedEntries = new FinalizationRegistry((held) => {
|
|
267
|
+
if (held.entries.get(held.key)?.deref() === undefined)
|
|
268
|
+
held.entries.delete(held.key);
|
|
269
|
+
});
|
|
270
|
+
installLiveSignals((reference) => {
|
|
271
|
+
let entries = entriesByRuntime.get(reference.runtime);
|
|
272
|
+
if (!entries) {
|
|
273
|
+
entries = new Map();
|
|
274
|
+
entriesByRuntime.set(reference.runtime, entries);
|
|
275
|
+
}
|
|
276
|
+
const key = `${reference.actorType} ${reference.actorId}`;
|
|
277
|
+
let entry = entries.get(key)?.deref();
|
|
278
|
+
if (!entry) {
|
|
279
|
+
entry = new LiveActorEntry(reference);
|
|
280
|
+
entries.set(key, new WeakRef(entry));
|
|
281
|
+
collectedEntries.register(entry, { entries, key });
|
|
282
|
+
}
|
|
283
|
+
const resolved = entry;
|
|
284
|
+
return new Proxy({}, {
|
|
285
|
+
get(_target, property) {
|
|
286
|
+
if (typeof property !== "string")
|
|
287
|
+
return undefined;
|
|
288
|
+
if (property === SNAPSHOT_KEY)
|
|
289
|
+
return resolved.snapshotSignal();
|
|
290
|
+
if (property === PAYLOADS_KEY)
|
|
291
|
+
return resolved.payloadsProxy();
|
|
292
|
+
return resolved.signalFor(property);
|
|
293
|
+
},
|
|
294
|
+
has(_target, property) {
|
|
295
|
+
return typeof property === "string";
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
//# sourceMappingURL=signals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signals.js","sourceRoot":"","sources":["../src/signals.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.14.
|
|
1
|
+
export declare const VERSION = "0.14.2";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = "0.14.
|
|
1
|
+
export const VERSION = "0.14.2";
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
package/docs/api.md
CHANGED
|
@@ -29,6 +29,8 @@ generic signatures; this index explains the supported role of every export.
|
|
|
29
29
|
only its name in the durable envelope when it changes.
|
|
30
30
|
- `ObservableBroadcast`: the immutable marker type returned by either helper.
|
|
31
31
|
- `VERSION`: running package version.
|
|
32
|
+
- `reference.live`: read-only live signals for an actor, enabled by the
|
|
33
|
+
`solid-objects/signals` entry point documented below.
|
|
32
34
|
- `ActorClass`, `ActorReference`, `ActorMessageSender`, `ActorSnapshot`,
|
|
33
35
|
`ActorOperationNames`, `ActorQueryNames`, `StagedOperations`, and
|
|
34
36
|
`ScheduledOperations`: inferred actor-class and fluent-dispatch types.
|
|
@@ -492,6 +494,67 @@ The transmit wire contract is shared with the Ruby gem
|
|
|
492
494
|
([solid-objects-ruby#49](https://github.com/cardmagic/solid-objects-ruby/pull/49));
|
|
493
495
|
`compatibility/transmit-envelopes.json` pins it in both repositories.
|
|
494
496
|
|
|
497
|
+
## `solid-objects/signals`
|
|
498
|
+
|
|
499
|
+
Live signals: the read-side adapter on the proposed standard JavaScript
|
|
500
|
+
signals API. One side-effect import enables `reference.live`:
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
import "solid-objects/signals"
|
|
504
|
+
|
|
505
|
+
const counter = Counter.ref("page-hits")
|
|
506
|
+
counter.live.count // a read-only signal of the broadcast observable
|
|
507
|
+
counter.live.snapshot // a read-only signal of the authorized snapshot
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
One property, three tenses: `snapshot.count` is one committed read,
|
|
511
|
+
`await counter.count` asks the actor now, and `counter.live.count` stays
|
|
512
|
+
current. From Lit, `watch(counter.live.count)` with the `SignalWatcher`
|
|
513
|
+
mixin renders it with no further glue; any consumer of the standard
|
|
514
|
+
signals API composes the same way.
|
|
515
|
+
|
|
516
|
+
- `configureLiveSignals(options)`: tune the lifecycle.
|
|
517
|
+
`LiveSignalsConfiguration` carries `lingerMilliseconds` (default one
|
|
518
|
+
second): how long a signal with no watchers keeps its subscription
|
|
519
|
+
before the session closes; and `retryMilliseconds` (default one
|
|
520
|
+
second): how long a still-watched signal waits before it retries a
|
|
521
|
+
denied or failed subscription.
|
|
522
|
+
- `activeLiveSubscriptionCount()` and `liveEntryCount(runtime)`: open
|
|
523
|
+
sessions and live per-actor entries, for diagnostics and leak tests.
|
|
524
|
+
The cache holds entries through weak references: one canonical entry
|
|
525
|
+
per actor for as long as any proxy or signal for it is reachable, so
|
|
526
|
+
two references to one actor can never open competing subscriptions,
|
|
527
|
+
and an entry whose signals are all garbage-collected leaves the cache
|
|
528
|
+
with them.
|
|
529
|
+
- `ActorLiveSignals` and `LiveSignal`: the structural types on
|
|
530
|
+
`reference.live`. `LiveSignal` exposes only `get()`, so the package
|
|
531
|
+
types never require the optional peer; at runtime every signal is a
|
|
532
|
+
standard `Signal.Computed`, read-only by construction.
|
|
533
|
+
|
|
534
|
+
Behavior:
|
|
535
|
+
|
|
536
|
+
- A signal subscribes its actor through an in-process
|
|
537
|
+
`runtime.realtime` session when the first watcher arrives and closes
|
|
538
|
+
the session after the linger when the last watcher leaves. The
|
|
539
|
+
subscription authorizes through `authorizeSubscription` with an
|
|
540
|
+
undefined authorization context.
|
|
541
|
+
- Value-broadcast observables set their named signals from each
|
|
542
|
+
envelope. Invalidation-only observables stay `undefined` by design;
|
|
543
|
+
`live.snapshot` re-fetches the authorized snapshot (coalesced) on
|
|
544
|
+
every accepted envelope, so private-value flows read from there.
|
|
545
|
+
- Personalized payload projections arrive as
|
|
546
|
+
`live.payloads.<name>` signals. A newly watched payload name re-sends
|
|
547
|
+
the subscription with the grown name list, and each payload keeps the
|
|
548
|
+
independent per-name revision fence the wire protocol gives it.
|
|
549
|
+
Payloads evaluate under the live session's authorization context.
|
|
550
|
+
- Envelopes apply only on a monotonic revision advance for the same
|
|
551
|
+
instance, the same fence the browser client uses.
|
|
552
|
+
- `snapshot` and `payloads` are reserved names on `live`; observables
|
|
553
|
+
with those names are shadowed.
|
|
554
|
+
- `signal-polyfill` is an optional peer dependency. Nothing loads it
|
|
555
|
+
until the `solid-objects/signals` entry is imported; `reference.live`
|
|
556
|
+
throws a pointer to that import otherwise.
|
|
557
|
+
|
|
495
558
|
## `solid-objects/web`
|
|
496
559
|
|
|
497
560
|
- `createDashboard(options)` creates an immutable `SolidObjectsDashboard` with
|
package/docs/correctness.md
CHANGED
|
@@ -58,7 +58,12 @@
|
|
|
58
58
|
|
|
59
59
|
- At-least-once execution means actor code may begin more than once. State and
|
|
60
60
|
staged intents from a failed turn roll back, but arbitrary external work does
|
|
61
|
-
not. External systems need stable idempotency keys.
|
|
61
|
+
not. External systems need stable idempotency keys. This clause is
|
|
62
|
+
observable, not decorative: `pnpm run test:at-least-once` crashes an
|
|
63
|
+
effect worker between the sink write and the acknowledgement, restarts
|
|
64
|
+
it, and shows the sink reading 2 with deduplication off — then shows a
|
|
65
|
+
guard on the stable effect id absorbing the same duplicate, with the
|
|
66
|
+
sink reading 1. The state commit happens exactly once in both runs.
|
|
62
67
|
- The activation fence protects the Solid Objects commit. It cannot revoke or
|
|
63
68
|
undo network calls, files, emails, payments, or other external effects.
|
|
64
69
|
- One identity processes one write operation at a time. This is the ordering
|
package/docs/fit.md
CHANGED
|
@@ -16,7 +16,9 @@ or realtime projections.
|
|
|
16
16
|
durable coordination there.
|
|
17
17
|
- A local-first application needs the same actor model in the browser:
|
|
18
18
|
durable per-user state on SQLite WASM, one runtime shared across tabs, and
|
|
19
|
-
an outbox that syncs to a server
|
|
19
|
+
an outbox that syncs to a server when the network allows. The server side
|
|
20
|
+
can be a Node runtime or a Rails application through the Ruby gem's
|
|
21
|
+
transmit ingest; the wire contract is shared.
|
|
20
22
|
|
|
21
23
|
## Prefer a row transaction when
|
|
22
24
|
|
package/docs/operations.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Operations
|
|
2
2
|
|
|
3
|
+
`install()` prepares the database and starts nothing. A process serves
|
|
4
|
+
background work only after `runtime.run(signal)` starts its roles. A process
|
|
5
|
+
that registers actors, installs, and then waits never claims a ready message,
|
|
6
|
+
and work enqueued with `send` stays ready until some process runs the roles.
|
|
7
|
+
A direct call or an explicit `sync` needs no running role, because the caller's
|
|
8
|
+
own path executes it.
|
|
9
|
+
|
|
3
10
|
Runtime roles use durable polling as the correctness fallback. Consecutive
|
|
4
11
|
empty passes double each role's wait from `pollingIntervalMilliseconds` to
|
|
5
12
|
`idlePollingIntervalMilliseconds`, which defaults to one second. Processed
|
package/docs/parity.md
CHANGED
|
@@ -4,7 +4,7 @@ This ledger tracks capability parity with the Ruby `solid_objects` gem.
|
|
|
4
4
|
Parity means preserving a capability and its correctness or security boundary,
|
|
5
5
|
not copying a Rails API into Node.
|
|
6
6
|
|
|
7
|
-
Reference: Ruby `solid_objects` 0.
|
|
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
|
|
9
9
|
earlier JavaScript releases.
|
|
10
10
|
|
|
@@ -143,12 +143,23 @@ complete:
|
|
|
143
143
|
replay deduplication, and recovery after an offline period, on SQLite,
|
|
144
144
|
PostgreSQL, and MySQL.
|
|
145
145
|
|
|
146
|
+
## JavaScript-only: live signals
|
|
147
|
+
|
|
148
|
+
`reference.live` (the `solid-objects/signals` entry) adapts committed
|
|
149
|
+
actor state to the proposed standard JavaScript signals API, so
|
|
150
|
+
signal-consuming renderers track actors with no manual registration. No
|
|
151
|
+
Ruby row exists because the slot it fills is already native in Rails:
|
|
152
|
+
the gem's Turbo and Action Cable component surface re-renders partials
|
|
153
|
+
from the same committed observables. Each runtime renders with its
|
|
154
|
+
ecosystem's primitive; the guarantee — views track committed state under
|
|
155
|
+
revision fencing and the same privacy model — is what parity preserves.
|
|
156
|
+
|
|
146
157
|
## Shared capability: the transmit family
|
|
147
158
|
|
|
148
159
|
The transmit family is the one part of the browser work that both runtimes
|
|
149
|
-
share. The Ruby gem
|
|
150
|
-
[solid-objects-ruby#49](https://github.com/cardmagic/solid-objects-ruby/pull/49)
|
|
151
|
-
|
|
160
|
+
share. The Ruby gem ships it in `0.14.0`
|
|
161
|
+
([solid-objects-ruby#49](https://github.com/cardmagic/solid-objects-ruby/pull/49),
|
|
162
|
+
from proposals [#47](https://github.com/cardmagic/solid-objects-ruby/issues/47)
|
|
152
163
|
and [#48](https://github.com/cardmagic/solid-objects-ruby/issues/48)):
|
|
153
164
|
`SolidObjects::Transmission.receive` is the ingest, and `Actor#transmit`
|
|
154
165
|
with `register_transmit` is the staging side. Identifiers differ by
|
package/docs/support.md
CHANGED
|
@@ -18,6 +18,21 @@ The package is ESM-only. PostgreSQL, MySQL, Redis, and SQLite WASM require
|
|
|
18
18
|
their optional peer dependency. The Node SQLite adapter has no driver
|
|
19
19
|
dependency beyond Node.js.
|
|
20
20
|
|
|
21
|
+
The browser runtime is tested in Chromium. The APIs it needs are standard,
|
|
22
|
+
so other engines work where those APIs exist; verify them on the exact
|
|
23
|
+
engine you target:
|
|
24
|
+
|
|
25
|
+
- Persistent storage needs OPFS sync access handles in a dedicated worker.
|
|
26
|
+
Chromium has them; Safari added them in 16.4; Firefox added them in 111.
|
|
27
|
+
- The multi-tab hosts need the Web Locks API and `BroadcastChannel`, which
|
|
28
|
+
every current engine provides.
|
|
29
|
+
- An embedded WebView is not the platform browser. Cordova and other
|
|
30
|
+
WKWebView or Android WebView shells can lack OPFS even when the device's
|
|
31
|
+
browser has it. `sqliteWasm({ storage: "persistent" })` fails fast where
|
|
32
|
+
OPFS is missing, and temporary storage still works wherever the WASM
|
|
33
|
+
module loads, so probe the target WebView before you commit to durable
|
|
34
|
+
in-app state.
|
|
35
|
+
|
|
21
36
|
The browser runtime needs two platform capabilities:
|
|
22
37
|
|
|
23
38
|
- Persistent storage uses the OPFS SAH pool VFS, which needs a secure context
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Actor } from "solid-objects"
|
|
2
|
+
|
|
3
|
+
export class DeliveryCounter extends Actor {
|
|
4
|
+
static override readonly actorType = "DeliveryCounter"
|
|
5
|
+
|
|
6
|
+
count = 0
|
|
7
|
+
|
|
8
|
+
deliver(): number {
|
|
9
|
+
this.count += 1
|
|
10
|
+
this.emit("record", { arguments: {} })
|
|
11
|
+
return this.count
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import assert from "node:assert/strict"
|
|
2
|
+
import { fork, type ChildProcess } from "node:child_process"
|
|
3
|
+
import { mkdtemp, rm } from "node:fs/promises"
|
|
4
|
+
import { tmpdir } from "node:os"
|
|
5
|
+
import { join } from "node:path"
|
|
6
|
+
import { fileURLToPath } from "node:url"
|
|
7
|
+
import { createRuntime } from "solid-objects"
|
|
8
|
+
import { sqlite } from "solid-objects/database/sqlite"
|
|
9
|
+
import { DeliveryCounter } from "./actor.ts"
|
|
10
|
+
import { readSink } from "./sink.ts"
|
|
11
|
+
|
|
12
|
+
const directory = await mkdtemp(join(tmpdir(), "solid-objects-at-least-once-"))
|
|
13
|
+
const databasePath = join(directory, "state.sqlite3")
|
|
14
|
+
const runtime = createRuntime({
|
|
15
|
+
database: sqlite({ path: databasePath, timeoutMilliseconds: 2_000, lockRetryAttempts: 20 }),
|
|
16
|
+
leaseDurationMilliseconds: 250,
|
|
17
|
+
leaseRenewalIntervalMilliseconds: 50,
|
|
18
|
+
processHeartbeatIntervalMilliseconds: 75,
|
|
19
|
+
processAliveThresholdMilliseconds: 300,
|
|
20
|
+
workerCount: 1,
|
|
21
|
+
effectWorkerCount: 0,
|
|
22
|
+
reminderSchedulerCount: 0,
|
|
23
|
+
retentionIntervalMilliseconds: 0,
|
|
24
|
+
deadProcessCleanupIntervalMilliseconds: 0,
|
|
25
|
+
authorizeMessage: () => true,
|
|
26
|
+
authorizeQuery: () => true,
|
|
27
|
+
authorizeAdministration: () => true,
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
runtime.register(DeliveryCounter)
|
|
32
|
+
await runtime.install()
|
|
33
|
+
const duplicate = await proveDuplicateAtSink()
|
|
34
|
+
const remedy = await proveDeduplicationAbsorbsIt()
|
|
35
|
+
process.stdout.write(`${JSON.stringify({ duplicate, remedy }, null, 2)}\n`)
|
|
36
|
+
} finally {
|
|
37
|
+
await runtime.close()
|
|
38
|
+
await rm(directory, { recursive: true })
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function proveDuplicateAtSink(): Promise<{
|
|
42
|
+
stateCommits: number
|
|
43
|
+
sinkDeliveries: number
|
|
44
|
+
sameEffectId: boolean
|
|
45
|
+
attempts: number[]
|
|
46
|
+
}> {
|
|
47
|
+
const sinkPath = join(directory, "sink-dedup-off.json")
|
|
48
|
+
await stageOneDelivery("dedup-off")
|
|
49
|
+
await crashThenRecover({ sinkPath, deduplicate: "off" })
|
|
50
|
+
|
|
51
|
+
const sink = await readSink(sinkPath)
|
|
52
|
+
const snapshot = await runtime.ref(DeliveryCounter, "dedup-off").snapshot()
|
|
53
|
+
assert.equal(snapshot.count, 1, "the state commit happened exactly once")
|
|
54
|
+
assert.equal(sink.deliveries.length, 2, "the sink observed the duplicate")
|
|
55
|
+
assert.equal(
|
|
56
|
+
sink.deliveries[0]?.effectId,
|
|
57
|
+
sink.deliveries[1]?.effectId,
|
|
58
|
+
"both deliveries carried the same stable effect id",
|
|
59
|
+
)
|
|
60
|
+
return {
|
|
61
|
+
stateCommits: snapshot.count,
|
|
62
|
+
sinkDeliveries: sink.deliveries.length,
|
|
63
|
+
sameEffectId: sink.deliveries[0]?.effectId === sink.deliveries[1]?.effectId,
|
|
64
|
+
attempts: sink.deliveries.map((delivery) => delivery.attempt),
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function proveDeduplicationAbsorbsIt(): Promise<{
|
|
69
|
+
stateCommits: number
|
|
70
|
+
sinkDeliveries: number
|
|
71
|
+
}> {
|
|
72
|
+
const sinkPath = join(directory, "sink-dedup-on.json")
|
|
73
|
+
await stageOneDelivery("dedup-on")
|
|
74
|
+
await crashThenRecover({ sinkPath, deduplicate: "on" })
|
|
75
|
+
|
|
76
|
+
const sink = await readSink(sinkPath)
|
|
77
|
+
const snapshot = await runtime.ref(DeliveryCounter, "dedup-on").snapshot()
|
|
78
|
+
assert.equal(snapshot.count, 1, "the state commit happened exactly once")
|
|
79
|
+
assert.equal(sink.deliveries.length, 1, "the stable effect id absorbed the duplicate")
|
|
80
|
+
return { stateCommits: snapshot.count, sinkDeliveries: sink.deliveries.length }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function stageOneDelivery(actorId: string): Promise<void> {
|
|
84
|
+
const message = await runtime.ref(DeliveryCounter, actorId).send.deliver()
|
|
85
|
+
const worker = runtime.worker()
|
|
86
|
+
try {
|
|
87
|
+
let processed = 0
|
|
88
|
+
for (let attempt = 0; attempt < 200 && processed === 0; attempt += 1) {
|
|
89
|
+
processed = await worker.runOnce({ activationRetention: "release" })
|
|
90
|
+
if (processed === 0) await new Promise((resolve) => setTimeout(resolve, 10))
|
|
91
|
+
}
|
|
92
|
+
assert.equal(processed, 1, "the actor turn committed and staged the effect")
|
|
93
|
+
} finally {
|
|
94
|
+
await worker.stop()
|
|
95
|
+
}
|
|
96
|
+
assert.equal(await message.status(), "completed")
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function crashThenRecover(options: {
|
|
100
|
+
sinkPath: string
|
|
101
|
+
deduplicate: "on" | "off"
|
|
102
|
+
}): Promise<void> {
|
|
103
|
+
const crashing = spawnEffectWorker({ ...options, mode: "crash" })
|
|
104
|
+
const crashExit = await crashing.finished
|
|
105
|
+
assert.equal(crashExit, 1, "the first delivery crashed before acknowledgement")
|
|
106
|
+
|
|
107
|
+
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
108
|
+
|
|
109
|
+
const recovering = spawnEffectWorker({ ...options, mode: "complete" })
|
|
110
|
+
const recoveryExit = await recovering.finished
|
|
111
|
+
assert.equal(recoveryExit, 0, "the second delivery completed and acknowledged")
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function spawnEffectWorker(options: {
|
|
115
|
+
sinkPath: string
|
|
116
|
+
deduplicate: "on" | "off"
|
|
117
|
+
mode: "crash" | "complete"
|
|
118
|
+
}): { child: ChildProcess; finished: Promise<number | null> } {
|
|
119
|
+
const child = fork(
|
|
120
|
+
fileURLToPath(new URL("./effect-worker.ts", import.meta.url)),
|
|
121
|
+
[databasePath, options.sinkPath, options.mode, options.deduplicate],
|
|
122
|
+
{ stdio: ["ignore", "inherit", "inherit", "ipc"] },
|
|
123
|
+
)
|
|
124
|
+
const finished = new Promise<number | null>((resolve, reject) => {
|
|
125
|
+
child.once("exit", (code) => resolve(code))
|
|
126
|
+
child.once("error", reject)
|
|
127
|
+
})
|
|
128
|
+
return { child, finished }
|
|
129
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { createRuntime } from "solid-objects"
|
|
2
|
+
import { sqlite } from "solid-objects/database/sqlite"
|
|
3
|
+
import { DeliveryCounter } from "./actor.ts"
|
|
4
|
+
import { recordDelivery } from "./sink.ts"
|
|
5
|
+
|
|
6
|
+
const databasePath = requiredArgument(2)
|
|
7
|
+
const sinkPath = requiredArgument(3)
|
|
8
|
+
const mode = requiredArgument(4)
|
|
9
|
+
const deduplicate = requiredArgument(5) === "on"
|
|
10
|
+
|
|
11
|
+
const runtime = createRuntime({
|
|
12
|
+
database: sqlite({ path: databasePath, timeoutMilliseconds: 2_000, lockRetryAttempts: 20 }),
|
|
13
|
+
pollingIntervalMilliseconds: 10,
|
|
14
|
+
leaseDurationMilliseconds: 250,
|
|
15
|
+
leaseRenewalIntervalMilliseconds: 50,
|
|
16
|
+
processHeartbeatIntervalMilliseconds: 75,
|
|
17
|
+
processAliveThresholdMilliseconds: 300,
|
|
18
|
+
workerCount: 0,
|
|
19
|
+
effectWorkerCount: 1,
|
|
20
|
+
reminderSchedulerCount: 0,
|
|
21
|
+
retentionIntervalMilliseconds: 0,
|
|
22
|
+
deadProcessCleanupIntervalMilliseconds: 0,
|
|
23
|
+
authorizeMessage: () => true,
|
|
24
|
+
authorizeQuery: () => true,
|
|
25
|
+
authorizeAdministration: () => true,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
runtime.register(DeliveryCounter)
|
|
29
|
+
runtime.registerEffect("record", async (_argumentsValue, context) => {
|
|
30
|
+
const { applied } = await recordDelivery({
|
|
31
|
+
path: sinkPath,
|
|
32
|
+
effectId: context.id,
|
|
33
|
+
attempt: context.attempt,
|
|
34
|
+
deduplicate,
|
|
35
|
+
})
|
|
36
|
+
process.send?.({ event: "sink.recorded", effectId: context.id, applied })
|
|
37
|
+
if (mode === "crash") {
|
|
38
|
+
process.exit(1)
|
|
39
|
+
}
|
|
40
|
+
return null
|
|
41
|
+
})
|
|
42
|
+
await runtime.install()
|
|
43
|
+
const effectWorker = runtime.effectWorker()
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
let processed = 0
|
|
47
|
+
for (let attempt = 0; attempt < 200 && processed === 0; attempt += 1) {
|
|
48
|
+
processed = await effectWorker.runOnce()
|
|
49
|
+
if (processed === 0) await new Promise((resolve) => setTimeout(resolve, 10))
|
|
50
|
+
}
|
|
51
|
+
if (processed === 0) throw new Error("no effect became claimable")
|
|
52
|
+
process.send?.({ event: "effects.finished", processed })
|
|
53
|
+
} finally {
|
|
54
|
+
await effectWorker.stop()
|
|
55
|
+
await runtime.close()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function requiredArgument(index: number): string {
|
|
59
|
+
const value = process.argv[index]
|
|
60
|
+
if (!value) throw new TypeError(`argument ${index - 1} is required`)
|
|
61
|
+
return value
|
|
62
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises"
|
|
2
|
+
|
|
3
|
+
export interface SinkDelivery {
|
|
4
|
+
effectId: string
|
|
5
|
+
attempt: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface SinkState {
|
|
9
|
+
deliveries: SinkDelivery[]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function readSink(path: string): Promise<SinkState> {
|
|
13
|
+
try {
|
|
14
|
+
const parsed: SinkState = JSON.parse(await readFile(path, "utf-8"))
|
|
15
|
+
return parsed
|
|
16
|
+
} catch (error) {
|
|
17
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return { deliveries: [] }
|
|
18
|
+
throw error
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function recordDelivery(options: {
|
|
23
|
+
path: string
|
|
24
|
+
effectId: string
|
|
25
|
+
attempt: number
|
|
26
|
+
deduplicate: boolean
|
|
27
|
+
}): Promise<{ applied: boolean }> {
|
|
28
|
+
const sink = await readSink(options.path)
|
|
29
|
+
const seen = sink.deliveries.some((delivery) => delivery.effectId === options.effectId)
|
|
30
|
+
if (options.deduplicate && seen) return { applied: false }
|
|
31
|
+
sink.deliveries.push({ effectId: options.effectId, attempt: options.attempt })
|
|
32
|
+
await writeFile(options.path, JSON.stringify(sink, null, 2))
|
|
33
|
+
return { applied: true }
|
|
34
|
+
}
|
|
@@ -13,7 +13,7 @@ interface QuickstartCheck {
|
|
|
13
13
|
|
|
14
14
|
const INSTALL_COMMAND = "npm install solid-objects"
|
|
15
15
|
const AGENT_PROMPT = "where would the solid-objects library be best used in this app?"
|
|
16
|
-
const DOCUMENTATION_URL = "https://solidobjects.dev/
|
|
16
|
+
const DOCUMENTATION_URL = "https://solidobjects.dev/js"
|
|
17
17
|
|
|
18
18
|
export function formatQuickstartPlan(plan: {
|
|
19
19
|
sameIdentityCalls: number
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solid-objects",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.2",
|
|
4
4
|
"description": "Race-free realtime state per application identity, backed by your SQL database",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -78,6 +78,10 @@
|
|
|
78
78
|
"types": "./dist/browser/tab-host.d.ts",
|
|
79
79
|
"import": "./dist/browser/tab-host.js"
|
|
80
80
|
},
|
|
81
|
+
"./signals": {
|
|
82
|
+
"types": "./dist/signals.d.ts",
|
|
83
|
+
"import": "./dist/signals.js"
|
|
84
|
+
},
|
|
81
85
|
"./transmit": {
|
|
82
86
|
"types": "./dist/transmit.d.ts",
|
|
83
87
|
"import": "./dist/transmit.js"
|
|
@@ -103,6 +107,7 @@
|
|
|
103
107
|
"test:mysql": "vitest run test/mysql.test.ts",
|
|
104
108
|
"test:package": "node scripts/release-artifact-smoke.mjs",
|
|
105
109
|
"test:recovery": "pnpm run build && node examples/failure-recovery/demo.ts",
|
|
110
|
+
"test:at-least-once": "pnpm run build && node examples/at-least-once/demo.ts",
|
|
106
111
|
"test:redis": "vitest run test/redis-wake-up.test.ts",
|
|
107
112
|
"test:watch": "vitest",
|
|
108
113
|
"benchmark": "pnpm run build && node benchmarks/run.ts",
|
|
@@ -121,12 +126,14 @@
|
|
|
121
126
|
"pg": "^8.23.0",
|
|
122
127
|
"prettier": "^3.9.6",
|
|
123
128
|
"redis": "^6.2.1",
|
|
129
|
+
"signal-polyfill": "^0.2.2",
|
|
124
130
|
"typescript": "^5.9.0",
|
|
125
131
|
"vitest": "^4.1.10",
|
|
126
132
|
"ws": "^8.21.3"
|
|
127
133
|
},
|
|
128
134
|
"peerDependencies": {
|
|
129
135
|
"@sqlite.org/sqlite-wasm": ">=3.50.0-build1",
|
|
136
|
+
"signal-polyfill": ">=0.2.2",
|
|
130
137
|
"mysql2": "^3.23.3",
|
|
131
138
|
"pg": "^8.23.0",
|
|
132
139
|
"redis": "^6.2.1"
|
|
@@ -135,6 +142,9 @@
|
|
|
135
142
|
"@sqlite.org/sqlite-wasm": {
|
|
136
143
|
"optional": true
|
|
137
144
|
},
|
|
145
|
+
"signal-polyfill": {
|
|
146
|
+
"optional": true
|
|
147
|
+
},
|
|
138
148
|
"mysql2": {
|
|
139
149
|
"optional": true
|
|
140
150
|
},
|