@shivaedev/effect-contract 0.8.0 → 0.10.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 +17 -0
- package/README.md +19 -2
- package/dist/contract.d.ts +3 -2
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js.map +1 -1
- package/dist/internal/liveInvalidation.d.ts +12 -0
- package/dist/internal/liveInvalidation.d.ts.map +1 -0
- package/dist/internal/liveInvalidation.js +14 -0
- package/dist/internal/liveInvalidation.js.map +1 -0
- package/dist/internal/queryReactivity.d.ts +0 -2
- package/dist/internal/queryReactivity.d.ts.map +1 -1
- package/dist/internal/queryReactivity.js +45 -25
- package/dist/internal/queryReactivity.js.map +1 -1
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +8 -5
- package/dist/live.js.map +1 -1
- package/dist/queryCoalesceWindow.d.ts +4 -0
- package/dist/queryCoalesceWindow.d.ts.map +1 -0
- package/dist/queryCoalesceWindow.js +11 -0
- package/dist/queryCoalesceWindow.js.map +1 -0
- package/package.json +4 -4
- package/src/contract.ts +8 -2
- package/src/internal/liveInvalidation.ts +21 -0
- package/src/internal/queryReactivity.ts +45 -30
- package/src/live.ts +8 -5
- package/src/queryCoalesceWindow.ts +13 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.0 - 2026-10-19
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Choose a live changed-hint coalescing window per bound query with React's `useQuery(atom, { coalesceWindow })`, keeping the session window as the default. Queries over one connection refetch on their own schedules; changing the option does not reconnect or refetch queries.
|
|
8
|
+
- Configure a bound query's window through its registry with `queryCoalesceWindow(query)` from `@shivaedev/effect-contract/queryCoalesceWindow.ts`.
|
|
9
|
+
|
|
10
|
+
## 0.9.0 - 2026-10-19
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Contracts include their reserved `<namespace>.$changes` stream in native RPC client types, with the same middleware as declared operations. Subscribe through a client typed from the contract without a cast or a separate Changes group.
|
|
15
|
+
|
|
16
|
+
### Breaking
|
|
17
|
+
|
|
18
|
+
- Native contract handler builders now require the reserved `$changes` handler. When a Platform host supplies it, build application handlers with `contract.omit("<namespace>.$changes").of(...)` and `.toLayer(...)`, while retaining the full contract for the host and client. Standalone servers and test clients must supply a changes stream handler. Remove hand-built Changes groups and use the contract directly.
|
|
19
|
+
|
|
3
20
|
## 0.8.0 - 2026-10-19
|
|
4
21
|
|
|
5
22
|
### Added
|
package/README.md
CHANGED
|
@@ -105,7 +105,7 @@ const missing = Get.reject.NoteMissing({ id: 9 });
|
|
|
105
105
|
Implement the contract with native `of` and `toLayer`:
|
|
106
106
|
|
|
107
107
|
```ts
|
|
108
|
-
import { Effect, Ref } from "effect";
|
|
108
|
+
import { Effect, Ref, Stream } from "effect";
|
|
109
109
|
import { Create, Get, Note, Notes, Rename } from "./notes.ts";
|
|
110
110
|
|
|
111
111
|
export const NotesHandlers = Notes.toLayer(Effect.gen(function* () {
|
|
@@ -119,6 +119,7 @@ export const NotesHandlers = Notes.toLayer(Effect.gen(function* () {
|
|
|
119
119
|
});
|
|
120
120
|
const save = (note: Note) => Ref.update(stored, (all) => new Map([...all, [note.id, note]])).pipe(Effect.as(note));
|
|
121
121
|
return Notes.of({
|
|
122
|
+
"notes.$changes": () => Stream.never,
|
|
122
123
|
"notes.get": ({ id }) => find(id),
|
|
123
124
|
"notes.list": () => Effect.map(Ref.get(stored), (all) => [...all.values()]),
|
|
124
125
|
"notes.rename": ({ id, title }) => title.trim() === ""
|
|
@@ -131,7 +132,7 @@ export const NotesHandlers = Notes.toLayer(Effect.gen(function* () {
|
|
|
131
132
|
}));
|
|
132
133
|
```
|
|
133
134
|
|
|
134
|
-
Save this module as `handlers.ts`. An application can put repository and service calls in these handlers. The contract checks handler result and rejection types; it does not implement persistence, authorization or transactions.
|
|
135
|
+
Save this module as `handlers.ts`. An application can put repository and service calls in these handlers. The contract checks handler result and rejection types; it does not implement persistence, authorization or transactions. This in-memory server keeps the reserved change stream open without publishing hints. When a Platform host supplies that handler, build application handlers from `Notes.omit("notes.$changes")` and keep `Notes` as the host and client group.
|
|
135
136
|
|
|
136
137
|
Native `.middleware(M)` returns a contract that retains its declarations. For example, a native middleware service can supply request identity:
|
|
137
138
|
|
|
@@ -191,6 +192,8 @@ const readOnce = api.get.run({ id: 1 });
|
|
|
191
192
|
const rename = api.rename.run({ id: 1, title: "Uno" });
|
|
192
193
|
```
|
|
193
194
|
|
|
195
|
+
`queryCoalesceWindow(query)` from `@shivaedev/effect-contract/queryCoalesceWindow.ts` returns a writable native atom for that bound query's live changed-hint window. Set it through the query's registry to a Duration, or `undefined` to use the live connection's default. Changing it does not refetch or reconnect; the next window uses the new value. React consumers can set it with `useQuery(query, { coalesceWindow: "2 seconds" })`.
|
|
196
|
+
|
|
194
197
|
`one` and `list` are native query atoms. `readOnce` and `rename` are Effects for individual calls. A query's Effect requires `NotesClient`; a command's Effect also requires native `Reactivity`. Commands expose `run`, and have no `query` member.
|
|
195
198
|
|
|
196
199
|
Mount the atoms and run commands through the service's atom runtime in the same registry:
|
|
@@ -232,6 +235,20 @@ Client invalidation follows RPC success. Platform database hosts also publish de
|
|
|
232
235
|
|
|
233
236
|
Platform database hosts serve the contract's reserved `<contract>.$changes` stream automatically. With NDJSON transport, `bind` and a React `SessionBoundary` connect query atoms without an application subscribe operation or `live()` call. The boundary finds bound APIs returned directly by `connect` or as properties such as `client.api`. See [automatic changes](https://github.com/ShivaeDev/platform/blob/main/docs/framework/changes.md) for defaults.
|
|
234
237
|
|
|
238
|
+
For a direct subscription, configure the server and `NotesClient` with `RpcSerialization.layerNdjson` and use the client already typed from `Notes`:
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
import { Effect, Stream } from "effect";
|
|
242
|
+
import { NotesClient } from "./client.ts";
|
|
243
|
+
import { notes } from "./notes.ts";
|
|
244
|
+
|
|
245
|
+
const changes = Stream.unwrap(NotesClient.use((client) =>
|
|
246
|
+
Effect.succeed(client("notes.$changes", { keys: [notes.item(1)] })),
|
|
247
|
+
));
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
The contract includes the reserved stream's payload, `LiveHint` elements and middleware failures in its native RPC type. The subscription uses the contract's middleware and needs no separate RPC group or cast. The caller owns stream consumption and interruption.
|
|
251
|
+
|
|
235
252
|
For a custom transport or explicit pause/status controls, the native live APIs remain available:
|
|
236
253
|
|
|
237
254
|
Declare subscriptions with `stream` in the same contract. Its `success` schema describes each element, and its `rejections` become the native stream error schema. `bind` exposes `run(payload)` as a native `Stream`, preserving declared rejections, middleware errors and RPC client errors. Completion and client interruption release the server subscription. The compiler rejects a unary client for a streaming operation.
|
package/dist/contract.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Schema } from "effect";
|
|
2
2
|
import { Rpc, RpcGroup, type RpcMiddleware, type RpcSchema } from "effect/rpc";
|
|
3
3
|
import type { CommandShape, OperationShape, QueryShape, StreamShape } from "./operation.ts";
|
|
4
|
+
import { changesRpc } from "./serverMetadata.ts";
|
|
4
5
|
export type Tag<TContract extends string, TName extends string> = `${TContract}.${TName}`;
|
|
5
6
|
export type OperationRpc<TContract extends string, TOperation> = TOperation extends OperationShape ? TOperation extends StreamShape ? Rpc.Rpc<Tag<TContract, TOperation["name"]>, TOperation["payload"], RpcSchema.Stream<TOperation["success"], TOperation["error"]>, Schema.Never> : Rpc.Rpc<Tag<TContract, TOperation["name"]>, TOperation["payload"], TOperation["success"], TOperation["error"]> : never;
|
|
6
7
|
export interface Declared<TName extends string, TQueries extends readonly QueryShape[], TCommands extends readonly CommandShape[], TStreams extends readonly StreamShape[] = readonly []> {
|
|
@@ -9,7 +10,7 @@ export interface Declared<TName extends string, TQueries extends readonly QueryS
|
|
|
9
10
|
readonly queries: TQueries;
|
|
10
11
|
readonly streams: TStreams;
|
|
11
12
|
}
|
|
12
|
-
export interface Contract<TName extends string, TQueries extends readonly QueryShape[], TCommands extends readonly CommandShape[], TRpcs extends Rpc.Any = OperationRpc<TName, TQueries[number] | TCommands[number]
|
|
13
|
+
export interface Contract<TName extends string, TQueries extends readonly QueryShape[], TCommands extends readonly CommandShape[], TRpcs extends Rpc.Any = OperationRpc<TName, TQueries[number] | TCommands[number]> | ReturnType<typeof changesRpc<TName>>, TStreams extends readonly StreamShape[] = readonly []> extends RpcGroup.RpcGroup<TRpcs> {
|
|
13
14
|
readonly declaration: Declared<TName, TQueries, TCommands, TStreams>;
|
|
14
15
|
middleware: <TM extends RpcMiddleware.AnyService>(middleware: TM) => Contract<TName, TQueries, TCommands, Rpc.AddMiddleware<TRpcs, TM>, TStreams>;
|
|
15
16
|
}
|
|
@@ -22,6 +23,6 @@ export declare function contract<const TName extends string, const TQueries exte
|
|
|
22
23
|
readonly queries?: TQueries & Unique<TQueries>;
|
|
23
24
|
readonly commands?: TCommands & Unique<[...TQueries, ...TCommands]>;
|
|
24
25
|
readonly streams?: TStreams & Unique<[...TQueries, ...TCommands, ...TStreams]>;
|
|
25
|
-
}): Contract<TName, TQueries, TCommands, OperationRpc<TName, TQueries[number] | TCommands[number] | TStreams[number]
|
|
26
|
+
}): Contract<TName, TQueries, TCommands, OperationRpc<TName, TQueries[number] | TCommands[number] | TStreams[number]> | ReturnType<typeof changesRpc<TName>>, TStreams>;
|
|
26
27
|
export {};
|
|
27
28
|
//# sourceMappingURL=contract.d.ts.map
|
package/dist/contract.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
|
package/dist/contract.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAe,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAsC,MAAM,YAAY,CAAC;AAE/E,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AA4ClF,SAAS,YAAY,CAAC,UAAqC;IAC1D,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC;IACpH,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvG,CAAC;AACF,CAAC;AAED,SAAS,WAAW,CAAC,SAAkD;IACtE,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,OAAO,CAAC,IAAI,CAAC,mBAAmB,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,SAAS,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;AACjG,CAAC;AAYD,SAAS,eAAe,CAAC,KAAY,EAAE,WAAwB;IAC9D,MAAM,gBAAgB,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtD,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;QAC3B,WAAW;QACX,UAAU,EAAE,CAAC,UAAoC,EAAE,EAAE,CAAC,eAAe,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC;KAChH,CAAC,CAAC;AACJ,CAAC;
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAe,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAsC,MAAM,YAAY,CAAC;AAE/E,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AA4ClF,SAAS,YAAY,CAAC,UAAqC;IAC1D,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC;IACpH,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvG,CAAC;AACF,CAAC;AAED,SAAS,WAAW,CAAC,SAAkD;IACtE,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,OAAO,CAAC,IAAI,CAAC,mBAAmB,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,SAAS,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;AACjG,CAAC;AAYD,SAAS,eAAe,CAAC,KAAY,EAAE,WAAwB;IAC9D,MAAM,gBAAgB,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtD,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;QAC3B,WAAW;QACX,UAAU,EAAE,CAAC,UAAoC,EAAE,EAAE,CAAC,eAAe,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC;KAChH,CAAC,CAAC;AACJ,CAAC;AAqBD,MAAM,UAAU,QAAQ,CACvB,IAAY,EACZ,UAAgJ;IAEhJ,MAAM,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,EAAE,EAAE,OAAO,GAAG,EAAE,EAAE,GAAG,UAAU,CAAC;IACjE,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,CAAC,GAAG,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CACpE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC,IAAI,EAAE,EAAE;QACrC,KAAK,EAAE,SAAS,CAAC,KAAK;QACtB,OAAO,EAAE,SAAS,CAAC,OAAO;QAC1B,MAAM,EAAE,SAAS,CAAC,IAAI,KAAK,QAAQ;QACnC,OAAO,EAAE,SAAS,CAAC,OAAO;KAC1B,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CACxC,CAAC;IACF,OAAO,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AACxG,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Duration } from "effect";
|
|
2
|
+
import type * as Reactivity from "effect/reactivity/Reactivity";
|
|
3
|
+
interface Batch {
|
|
4
|
+
readonly active: () => boolean;
|
|
5
|
+
readonly seen: Set<() => void>;
|
|
6
|
+
readonly window: Duration.Input | undefined;
|
|
7
|
+
}
|
|
8
|
+
export declare const liveBatches: WeakMap<Reactivity.Reactivity, Batch>;
|
|
9
|
+
export declare function liveKeys(keys: readonly string[]): string[];
|
|
10
|
+
export declare function invalidateLive(reactivity: Reactivity.Reactivity, keys: readonly string[], active: () => boolean, window?: Duration.Input): void;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=liveInvalidation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"liveInvalidation.d.ts","sourceRoot":"","sources":["../../src/internal/liveInvalidation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAEhE,UAAU,KAAK;IACd,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,GAAG,SAAS,CAAC;CAC5C;AACD,eAAO,MAAM,WAAW,uCAA8C,CAAC;AACvE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,YAE/C;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,UAAU,CAAC,UAAU,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,OAAO,EAAE,MAAM,CAAC,EAAE,QAAQ,CAAC,KAAK,QAOxI"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const liveBatches = new WeakMap();
|
|
2
|
+
export function liveKeys(keys) {
|
|
3
|
+
return keys.map((key) => `@shivaedev/live:${key}`);
|
|
4
|
+
}
|
|
5
|
+
export function invalidateLive(reactivity, keys, active, window) {
|
|
6
|
+
liveBatches.set(reactivity, { active, seen: new Set(), window });
|
|
7
|
+
try {
|
|
8
|
+
reactivity.invalidateUnsafe(window === undefined ? keys : liveKeys(keys));
|
|
9
|
+
}
|
|
10
|
+
finally {
|
|
11
|
+
liveBatches.delete(reactivity);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=liveInvalidation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"liveInvalidation.js","sourceRoot":"","sources":["../../src/internal/liveInvalidation.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,EAAgC,CAAC;AACvE,MAAM,UAAU,QAAQ,CAAC,IAAuB;IAC/C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,mBAAmB,GAAG,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,UAAiC,EAAE,IAAuB,EAAE,MAAqB,EAAE,MAAuB;IACxI,WAAW,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACjE,IAAI,CAAC;QACJ,UAAU,CAAC,gBAAgB,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3E,CAAC;YAAS,CAAC;QACV,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC;AACF,CAAC"}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import * as AsyncResult from "effect/reactivity/AsyncResult";
|
|
2
2
|
import * as Atom from "effect/reactivity/Atom";
|
|
3
|
-
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
4
|
-
export declare function invalidateLive(reactivity: Reactivity.Reactivity, keys: readonly string[], active: () => boolean): void;
|
|
5
3
|
export declare function queryReactivity<R, E>(runtime: Atom.AtomRuntime<R, E>): (atom: Atom.Atom<AsyncResult.AsyncResult<unknown, unknown>>, keys: readonly string[]) => Atom.Atom<AsyncResult.AsyncResult<unknown, unknown>>;
|
|
6
4
|
//# sourceMappingURL=queryReactivity.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queryReactivity.d.ts","sourceRoot":"","sources":["../../src/internal/queryReactivity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,WAAW,MAAM,+BAA+B,CAAC;AAC7D,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"queryReactivity.d.ts","sourceRoot":"","sources":["../../src/internal/queryReactivity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,WAAW,MAAM,+BAA+B,CAAC;AAC7D,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAK/C,wBAAgB,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,sEAIzC,SAAS,MAAM,EAAE,0DAuF5C"}
|
|
@@ -1,17 +1,9 @@
|
|
|
1
|
-
import { Effect } from "effect";
|
|
1
|
+
import { Duration, Effect } from "effect";
|
|
2
2
|
import * as AsyncResult from "effect/reactivity/AsyncResult";
|
|
3
3
|
import * as Atom from "effect/reactivity/Atom";
|
|
4
4
|
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
batches.set(reactivity, { active, seen: new Set() });
|
|
8
|
-
try {
|
|
9
|
-
reactivity.invalidateUnsafe(keys);
|
|
10
|
-
}
|
|
11
|
-
finally {
|
|
12
|
-
batches.delete(reactivity);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
5
|
+
import { queryCoalesceWindow } from "#queryCoalesceWindow.ts";
|
|
6
|
+
import { liveBatches, liveKeys } from "./liveInvalidation.js";
|
|
15
7
|
export function queryReactivity(runtime) {
|
|
16
8
|
const service = runtime.atom(Effect.service(Reactivity.Reactivity));
|
|
17
9
|
const cached = new WeakMap();
|
|
@@ -28,22 +20,50 @@ export function queryReactivity(runtime) {
|
|
|
28
20
|
}
|
|
29
21
|
const reactivity = context.value;
|
|
30
22
|
let pending;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
batch.seen.add(invalidate);
|
|
38
|
-
if (get.once(source).waiting) {
|
|
39
|
-
pending = batch.active;
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
23
|
+
let timer;
|
|
24
|
+
function clear() {
|
|
25
|
+
clearTimeout(timer);
|
|
26
|
+
timer = undefined;
|
|
43
27
|
pending = undefined;
|
|
44
|
-
get.refresh(source);
|
|
45
28
|
}
|
|
46
|
-
|
|
29
|
+
function refresh(active) {
|
|
30
|
+
if (!active()) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (get.once(source).waiting) {
|
|
34
|
+
pending = active;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
pending = undefined;
|
|
38
|
+
get.refresh(source);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function changed() {
|
|
42
|
+
const batch = liveBatches.get(reactivity);
|
|
43
|
+
if (batch === undefined || batch.seen.has(changed)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
batch.seen.add(changed);
|
|
47
|
+
const delay = Duration.toMillis(Duration.fromInputUnsafe(get.once(queryCoalesceWindow(wrapped)) ?? batch.window ?? 0));
|
|
48
|
+
if (delay === 0) {
|
|
49
|
+
clear();
|
|
50
|
+
get.refresh(source);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
timer ??= setTimeout(() => {
|
|
54
|
+
timer = undefined;
|
|
55
|
+
refresh(batch.active);
|
|
56
|
+
}, delay);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
get.addFinalizer(clear);
|
|
60
|
+
get.addFinalizer(reactivity.registerUnsafe(liveKeys(keys), changed));
|
|
61
|
+
get.addFinalizer(reactivity.registerUnsafe(keys, () => {
|
|
62
|
+
if (!liveBatches.has(reactivity)) {
|
|
63
|
+
clear();
|
|
64
|
+
get.refresh(source);
|
|
65
|
+
}
|
|
66
|
+
}));
|
|
47
67
|
get.subscribe(source, (value) => {
|
|
48
68
|
get.setSelf(value);
|
|
49
69
|
if (pending !== undefined && !value.waiting) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queryReactivity.js","sourceRoot":"","sources":["../../src/internal/queryReactivity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"queryReactivity.js","sourceRoot":"","sources":["../../src/internal/queryReactivity.ts"],"names":[],"mappings":"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"}
|
package/dist/live.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../src/live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,QAAQ,EAAU,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9E,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAG/C,OAAO,EAAoB,GAAG,EAAY,MAAM,WAAW,CAAC;AAE5D,eAAO,MAAM,QAAQ;;;;;;;;;;;;IAGnB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAC;AAC5C,MAAM,WAAW,UAAU,CAAC,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,YAAY,GAAG,MAAM,GAAG,cAAc,CAAC;IAC5D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AACD,MAAM,WAAW,WAAW,CAAC,CAAC,EAAE,CAAC;IAChC,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,SAAS,GAAG,EAAE,GAAG,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC;IAC7D,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;CAC/C;AAID,wBAAgB,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,aAAa,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC;;;;;
|
|
1
|
+
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../src/live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,QAAQ,EAAU,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9E,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAG/C,OAAO,EAAoB,GAAG,EAAY,MAAM,WAAW,CAAC;AAE5D,eAAO,MAAM,QAAQ;;;;;;;;;;;;IAGnB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAC;AAC5C,MAAM,WAAW,UAAU,CAAC,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,YAAY,GAAG,MAAM,GAAG,cAAc,CAAC;IAC5D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AACD,MAAM,WAAW,WAAW,CAAC,CAAC,EAAE,CAAC;IAChC,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,SAAS,GAAG,EAAE,GAAG,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC;IAC7D,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;CAC/C;AAID,wBAAgB,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,aAAa,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC;;;;;EA2FhH"}
|
package/dist/live.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Duration, Effect, Option, Schema, Stream } from "effect";
|
|
2
2
|
import * as Atom from "effect/reactivity/Atom";
|
|
3
3
|
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
4
|
-
import { invalidateLive } from "#internal/
|
|
4
|
+
import { invalidateLive } from "#internal/liveInvalidation.ts";
|
|
5
5
|
import { invalidationKeys, Key, readKeys } from "./keys.js";
|
|
6
6
|
export const LiveHint = Schema.Union([
|
|
7
7
|
Schema.Struct({ _tag: Schema.Literal("Changed"), keys: Schema.Array(Key) }),
|
|
@@ -32,19 +32,22 @@ export function live(runtime, options) {
|
|
|
32
32
|
clear();
|
|
33
33
|
});
|
|
34
34
|
function changed(changedKeys) {
|
|
35
|
-
const
|
|
35
|
+
const window = get.once(coalesceWindow);
|
|
36
|
+
const keys = invalidationKeys(changedKeys);
|
|
37
|
+
invalidateLive(reactivity, keys, () => active && !get.once(paused), window);
|
|
38
|
+
const delay = Duration.toMillis(Duration.fromInputUnsafe(window));
|
|
36
39
|
if (delay === 0) {
|
|
37
|
-
reactivity.
|
|
40
|
+
invalidateLive(reactivity, keys, () => active && !get.once(paused));
|
|
38
41
|
return;
|
|
39
42
|
}
|
|
40
43
|
for (const key of invalidationKeys(changedKeys)) {
|
|
41
44
|
pending.add(key);
|
|
42
45
|
}
|
|
43
46
|
timer ??= setTimeout(() => {
|
|
44
|
-
const
|
|
47
|
+
const queued = [...pending];
|
|
45
48
|
clear();
|
|
46
49
|
if (!get.once(paused)) {
|
|
47
|
-
invalidateLive(reactivity,
|
|
50
|
+
invalidateLive(reactivity, queued, () => active && !get.once(paused));
|
|
48
51
|
}
|
|
49
52
|
}, delay);
|
|
50
53
|
}
|
package/dist/live.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live.js","sourceRoot":"","sources":["../src/live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9E,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAC/C,OAAO,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"live.js","sourceRoot":"","sources":["../src/live.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryCoalesceWindow.d.ts","sourceRoot":"","sources":["../src/queryCoalesceWindow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAI/C,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,GAAG,SAAS,CAAC,CAOrG"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as Atom from "effect/reactivity/Atom";
|
|
2
|
+
const windows = new WeakMap();
|
|
3
|
+
export function queryCoalesceWindow(query) {
|
|
4
|
+
let window = windows.get(query);
|
|
5
|
+
if (window === undefined) {
|
|
6
|
+
window = Atom.keepAlive(Atom.make(undefined));
|
|
7
|
+
windows.set(query, window);
|
|
8
|
+
}
|
|
9
|
+
return window;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=queryCoalesceWindow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryCoalesceWindow.js","sourceRoot":"","sources":["../src/queryCoalesceWindow.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAE/C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAiE,CAAC;AAE7F,MAAM,UAAU,mBAAmB,CAAI,KAAmB;IACzD,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAA6B,SAAS,CAAC,CAAC,CAAC;QAC1E,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/effect-contract",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Typed query and command contracts over native Effect RPC and reactivity",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/effect-contract#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
"@effect/platform-node": "4.0.4",
|
|
48
48
|
"@effect/vitest": "4.0.4",
|
|
49
49
|
"@shivaedev/effect-test": "0.7.1",
|
|
50
|
-
"@shivaedev/effect-test-sql": "0.
|
|
51
|
-
"@shivaedev/quality": "0.
|
|
52
|
-
"@shivaedev/test-story": "0.
|
|
50
|
+
"@shivaedev/effect-test-sql": "0.8.1",
|
|
51
|
+
"@shivaedev/quality": "0.31.0",
|
|
52
|
+
"@shivaedev/test-story": "0.17.0",
|
|
53
53
|
"@types/node": "24.19.2",
|
|
54
54
|
"effect": "4.0.4",
|
|
55
55
|
"esbuild": "0.28.2",
|
package/src/contract.ts
CHANGED
|
@@ -27,7 +27,7 @@ export interface Contract<
|
|
|
27
27
|
TName extends string,
|
|
28
28
|
TQueries extends readonly QueryShape[],
|
|
29
29
|
TCommands extends readonly CommandShape[],
|
|
30
|
-
TRpcs extends Rpc.Any = OperationRpc<TName, TQueries[number] | TCommands[number]
|
|
30
|
+
TRpcs extends Rpc.Any = OperationRpc<TName, TQueries[number] | TCommands[number]> | ReturnType<typeof changesRpc<TName>>,
|
|
31
31
|
TStreams extends readonly StreamShape[] = readonly [],
|
|
32
32
|
> extends RpcGroup.RpcGroup<TRpcs> {
|
|
33
33
|
readonly declaration: Declared<TName, TQueries, TCommands, TStreams>;
|
|
@@ -89,7 +89,13 @@ export function contract<
|
|
|
89
89
|
readonly commands?: TCommands & Unique<[...TQueries, ...TCommands]>;
|
|
90
90
|
readonly streams?: TStreams & Unique<[...TQueries, ...TCommands, ...TStreams]>;
|
|
91
91
|
},
|
|
92
|
-
): Contract<
|
|
92
|
+
): Contract<
|
|
93
|
+
TName,
|
|
94
|
+
TQueries,
|
|
95
|
+
TCommands,
|
|
96
|
+
OperationRpc<TName, TQueries[number] | TCommands[number] | TStreams[number]> | ReturnType<typeof changesRpc<TName>>,
|
|
97
|
+
TStreams
|
|
98
|
+
>;
|
|
93
99
|
export function contract(
|
|
94
100
|
name: string,
|
|
95
101
|
operations: { readonly queries?: readonly QueryShape[]; readonly commands?: readonly CommandShape[]; readonly streams?: readonly StreamShape[] },
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Duration } from "effect";
|
|
2
|
+
import type * as Reactivity from "effect/reactivity/Reactivity";
|
|
3
|
+
|
|
4
|
+
interface Batch {
|
|
5
|
+
readonly active: () => boolean;
|
|
6
|
+
readonly seen: Set<() => void>;
|
|
7
|
+
readonly window: Duration.Input | undefined;
|
|
8
|
+
}
|
|
9
|
+
export const liveBatches = new WeakMap<Reactivity.Reactivity, Batch>();
|
|
10
|
+
export function liveKeys(keys: readonly string[]) {
|
|
11
|
+
return keys.map((key) => `@shivaedev/live:${key}`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function invalidateLive(reactivity: Reactivity.Reactivity, keys: readonly string[], active: () => boolean, window?: Duration.Input) {
|
|
15
|
+
liveBatches.set(reactivity, { active, seen: new Set(), window });
|
|
16
|
+
try {
|
|
17
|
+
reactivity.invalidateUnsafe(window === undefined ? keys : liveKeys(keys));
|
|
18
|
+
} finally {
|
|
19
|
+
liveBatches.delete(reactivity);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -1,22 +1,9 @@
|
|
|
1
|
-
import { Effect } from "effect";
|
|
1
|
+
import { Duration, Effect } from "effect";
|
|
2
2
|
import * as AsyncResult from "effect/reactivity/AsyncResult";
|
|
3
3
|
import * as Atom from "effect/reactivity/Atom";
|
|
4
4
|
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
readonly active: () => boolean;
|
|
8
|
-
readonly seen: Set<() => void>;
|
|
9
|
-
}
|
|
10
|
-
const batches = new WeakMap<Reactivity.Reactivity, Batch>();
|
|
11
|
-
|
|
12
|
-
export function invalidateLive(reactivity: Reactivity.Reactivity, keys: readonly string[], active: () => boolean) {
|
|
13
|
-
batches.set(reactivity, { active, seen: new Set() });
|
|
14
|
-
try {
|
|
15
|
-
reactivity.invalidateUnsafe(keys);
|
|
16
|
-
} finally {
|
|
17
|
-
batches.delete(reactivity);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
5
|
+
import { queryCoalesceWindow } from "#queryCoalesceWindow.ts";
|
|
6
|
+
import { liveBatches, liveKeys } from "./liveInvalidation.ts";
|
|
20
7
|
|
|
21
8
|
export function queryReactivity<R, E>(runtime: Atom.AtomRuntime<R, E>) {
|
|
22
9
|
const service = runtime.atom(Effect.service(Reactivity.Reactivity));
|
|
@@ -40,22 +27,50 @@ export function queryReactivity<R, E>(runtime: Atom.AtomRuntime<R, E>) {
|
|
|
40
27
|
}
|
|
41
28
|
const reactivity = context.value;
|
|
42
29
|
let pending: (() => boolean) | undefined;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
batch.seen.add(invalidate);
|
|
50
|
-
if (get.once(source).waiting) {
|
|
51
|
-
pending = batch.active;
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
30
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
31
|
+
function clear() {
|
|
32
|
+
clearTimeout(timer);
|
|
33
|
+
timer = undefined;
|
|
55
34
|
pending = undefined;
|
|
56
|
-
get.refresh(source);
|
|
57
35
|
}
|
|
58
|
-
|
|
36
|
+
function refresh(active: () => boolean) {
|
|
37
|
+
if (!active()) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (get.once(source).waiting) {
|
|
41
|
+
pending = active;
|
|
42
|
+
} else {
|
|
43
|
+
pending = undefined;
|
|
44
|
+
get.refresh(source);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function changed() {
|
|
48
|
+
const batch = liveBatches.get(reactivity);
|
|
49
|
+
if (batch === undefined || batch.seen.has(changed)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
batch.seen.add(changed);
|
|
53
|
+
const delay = Duration.toMillis(Duration.fromInputUnsafe(get.once(queryCoalesceWindow(wrapped)) ?? batch.window ?? 0));
|
|
54
|
+
if (delay === 0) {
|
|
55
|
+
clear();
|
|
56
|
+
get.refresh(source);
|
|
57
|
+
} else {
|
|
58
|
+
timer ??= setTimeout(() => {
|
|
59
|
+
timer = undefined;
|
|
60
|
+
refresh(batch.active);
|
|
61
|
+
}, delay);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
get.addFinalizer(clear);
|
|
65
|
+
get.addFinalizer(reactivity.registerUnsafe(liveKeys(keys), changed));
|
|
66
|
+
get.addFinalizer(
|
|
67
|
+
reactivity.registerUnsafe(keys, () => {
|
|
68
|
+
if (!liveBatches.has(reactivity)) {
|
|
69
|
+
clear();
|
|
70
|
+
get.refresh(source);
|
|
71
|
+
}
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
59
74
|
get.subscribe(source, (value) => {
|
|
60
75
|
get.setSelf(value);
|
|
61
76
|
if (pending !== undefined && !value.waiting) {
|
package/src/live.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Cause, Duration, Effect, Option, Schema, Stream } from "effect";
|
|
2
2
|
import * as Atom from "effect/reactivity/Atom";
|
|
3
3
|
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
4
|
-
import { invalidateLive } from "#internal/
|
|
4
|
+
import { invalidateLive } from "#internal/liveInvalidation.ts";
|
|
5
5
|
import { invalidationKeys, Key, readKeys } from "./keys.ts";
|
|
6
6
|
|
|
7
7
|
export const LiveHint = Schema.Union([
|
|
@@ -50,19 +50,22 @@ export function live<R, E, TRuntimeError>(runtime: Atom.AtomRuntime<R, TRuntimeE
|
|
|
50
50
|
clear();
|
|
51
51
|
});
|
|
52
52
|
function changed(changedKeys: readonly Key[]) {
|
|
53
|
-
const
|
|
53
|
+
const window = get.once(coalesceWindow);
|
|
54
|
+
const keys = invalidationKeys(changedKeys);
|
|
55
|
+
invalidateLive(reactivity, keys, () => active && !get.once(paused), window);
|
|
56
|
+
const delay = Duration.toMillis(Duration.fromInputUnsafe(window));
|
|
54
57
|
if (delay === 0) {
|
|
55
|
-
reactivity.
|
|
58
|
+
invalidateLive(reactivity, keys, () => active && !get.once(paused));
|
|
56
59
|
return;
|
|
57
60
|
}
|
|
58
61
|
for (const key of invalidationKeys(changedKeys)) {
|
|
59
62
|
pending.add(key);
|
|
60
63
|
}
|
|
61
64
|
timer ??= setTimeout(() => {
|
|
62
|
-
const
|
|
65
|
+
const queued = [...pending];
|
|
63
66
|
clear();
|
|
64
67
|
if (!get.once(paused)) {
|
|
65
|
-
invalidateLive(reactivity,
|
|
68
|
+
invalidateLive(reactivity, queued, () => active && !get.once(paused));
|
|
66
69
|
}
|
|
67
70
|
}, delay);
|
|
68
71
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Duration } from "effect";
|
|
2
|
+
import * as Atom from "effect/reactivity/Atom";
|
|
3
|
+
|
|
4
|
+
const windows = new WeakMap<Atom.Atom<unknown>, Atom.Writable<Duration.Input | undefined>>();
|
|
5
|
+
|
|
6
|
+
export function queryCoalesceWindow<A>(query: Atom.Atom<A>): Atom.Writable<Duration.Input | undefined> {
|
|
7
|
+
let window = windows.get(query);
|
|
8
|
+
if (window === undefined) {
|
|
9
|
+
window = Atom.keepAlive(Atom.make<Duration.Input | undefined>(undefined));
|
|
10
|
+
windows.set(query, window);
|
|
11
|
+
}
|
|
12
|
+
return window;
|
|
13
|
+
}
|