@shivaedev/effect-contract 0.11.0 → 0.12.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 +16 -0
- package/README.md +31 -8
- package/dist/automaticLive.d.ts +9 -7
- package/dist/automaticLive.d.ts.map +1 -1
- package/dist/automaticLive.js +52 -19
- package/dist/automaticLive.js.map +1 -1
- package/dist/bind.d.ts +11 -7
- package/dist/bind.d.ts.map +1 -1
- package/dist/bind.js +9 -36
- package/dist/bind.js.map +1 -1
- package/dist/contract.d.ts +10 -8
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +15 -7
- package/dist/contract.js.map +1 -1
- package/dist/internal/bindingOwner.d.ts +8 -0
- package/dist/internal/bindingOwner.d.ts.map +1 -0
- package/dist/internal/bindingOwner.js +16 -0
- package/dist/internal/bindingOwner.js.map +1 -0
- package/dist/internal/clientOperations.d.ts +21 -0
- package/dist/internal/clientOperations.d.ts.map +1 -0
- package/dist/internal/clientOperations.js +36 -0
- package/dist/internal/clientOperations.js.map +1 -0
- package/dist/internal/queryReactivity.d.ts +2 -1
- package/dist/internal/queryReactivity.d.ts.map +1 -1
- package/dist/internal/queryReactivity.js +5 -1
- package/dist/internal/queryReactivity.js.map +1 -1
- package/dist/keys.d.ts +5 -2
- package/dist/keys.d.ts.map +1 -1
- package/dist/keys.js +7 -4
- package/dist/keys.js.map +1 -1
- package/dist/live.d.ts +4 -2
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +5 -4
- package/dist/live.js.map +1 -1
- package/dist/makeLiveServer.d.ts +2 -2
- package/dist/makeLiveServer.d.ts.map +1 -1
- package/dist/makeLiveServer.js +3 -3
- package/dist/makeLiveServer.js.map +1 -1
- package/dist/operation.d.ts +1 -1
- package/dist/serverMetadata.d.ts +21 -12
- package/dist/serverMetadata.d.ts.map +1 -1
- package/dist/serverMetadata.js +19 -4
- package/dist/serverMetadata.js.map +1 -1
- package/package.json +6 -6
- package/src/automaticLive.ts +64 -24
- package/src/bind.ts +21 -54
- package/src/contract.ts +36 -15
- package/src/internal/bindingOwner.ts +24 -0
- package/src/internal/clientOperations.ts +74 -0
- package/src/internal/queryReactivity.ts +11 -1
- package/src/keys.ts +16 -4
- package/src/live.ts +8 -5
- package/src/makeLiveServer.ts +4 -4
- package/src/operation.ts +1 -1
- package/src/serverMetadata.ts +40 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.12.0 - 2026-10-25
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- effect-contract item reads refresh on their collection-wide `<collection>:*` key, with live hints naming each affected subscribed item.
|
|
8
|
+
|
|
9
|
+
### Breaking
|
|
10
|
+
|
|
11
|
+
- effect-sql writes returning more than 1,000 rows across all chunks of a single call announce `<table>` and `<table>:*` instead of item keys. Code registering raw `<table>:<id>` Reactivity keys outside effect-contract must also register `<table>:*`.
|
|
12
|
+
|
|
13
|
+
## 0.11.1 - 2026-10-25
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Release with updated workspace dependencies.
|
|
18
|
+
|
|
3
19
|
## 0.11.0 - 2026-10-24
|
|
4
20
|
|
|
5
21
|
### Added
|
package/README.md
CHANGED
|
@@ -231,6 +231,30 @@ The dependency rule is deliberately asymmetric:
|
|
|
231
231
|
|
|
232
232
|
Client invalidation follows RPC success. Platform database hosts also publish declared command invalidations automatically after the handler succeeds, excluding keys already announced by repository commits, using `transact` from [`effect-sql`](https://github.com/ShivaeDev/platform/tree/main/packages/effect-sql); commit-bound changes belong to [`effect-changes`](https://github.com/ShivaeDev/platform/tree/main/packages/effect-changes).
|
|
233
233
|
|
|
234
|
+
### Session-owned keys
|
|
235
|
+
|
|
236
|
+
Self-only features can declare `keyScope: "session"` without adding an owner id to query or command payloads:
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
const Preferences = contract("preferences", {
|
|
240
|
+
keyScope: "session",
|
|
241
|
+
queries: [query("self", { reads: () => [preferences.item(0)], success: Schema.String })],
|
|
242
|
+
commands: [command("save", {
|
|
243
|
+
payload: { title: Schema.String },
|
|
244
|
+
invalidates: () => [preferences.item(0)],
|
|
245
|
+
})],
|
|
246
|
+
});
|
|
247
|
+
const api = bind(Preferences, Client, { registry });
|
|
248
|
+
const self = api.self.query(undefined);
|
|
249
|
+
const saved = api.save.run({ title: "My preferences" });
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
The binding requires the session's owning registry. It scopes read registration, successful-command invalidation, live hints and reconciliation to that owner. A rejected command declares no invalidation. Query atoms and live connections belong in that registry; command and one-off query effects execute through it. Ordinary contracts keep unscoped keys and the two-argument `bind` call.
|
|
253
|
+
|
|
254
|
+
`List` and `Item` are still the key shapes. `readKeys(keys, { scope })` and `invalidationKeys(keys, { scope })` resolve the extra dimension while preserving item, list and wildcard semantics. An item invalidation refreshes that scope's item and list; a wildcard reaches only that scope's items. The client's opaque scope comes from its registry and is never sent as an owner id.
|
|
255
|
+
|
|
256
|
+
Server adapters read the RPC's `KeyScope` annotation. For `"session"`, they must obtain scope from request-local authenticated identity, then pass the same `{ scope }` to dependency registration, invalidation and `makeLiveServer.stream(keys, context)`. A shared server Layer must not capture identity, accept a client-selected scope or fall back to unscoped keys. This package supplies metadata and contextual keys; it has no server or authentication dependency.
|
|
257
|
+
|
|
234
258
|
### 4. Live invalidation and resume
|
|
235
259
|
|
|
236
260
|
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.
|
|
@@ -240,14 +264,13 @@ For a direct subscription, configure the server and `NotesClient` with `RpcSeria
|
|
|
240
264
|
```ts
|
|
241
265
|
import { Effect, Stream } from "effect";
|
|
242
266
|
import { NotesClient } from "./client.ts";
|
|
243
|
-
import { notes } from "./notes.ts";
|
|
244
267
|
|
|
245
268
|
const changes = Stream.unwrap(NotesClient.use((client) =>
|
|
246
|
-
Effect.succeed(client("notes.$changes", {
|
|
269
|
+
Effect.succeed(client("notes.$changes", { queries: [{ query: "get", payload: { id: 1 } }] })),
|
|
247
270
|
));
|
|
248
271
|
```
|
|
249
272
|
|
|
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.
|
|
273
|
+
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. References name declared queries and reuse their payload schemas; payloadless queries use `{ query: "list", payload: undefined }`. Subscription handlers resolve keys with `queryKeys(Notes.declaration.queries, queries)` from `serverMetadata.ts`, or the stream RPC's `ChangesReads` annotation, before calling `makeLiveServer.stream`. Session-scoped bindings track mounted queries per registry and drop their references on unmount or disposal. Ordinary bindings track query references when atoms are created.
|
|
251
274
|
|
|
252
275
|
For a custom transport or explicit pause/status controls, the native live APIs remain available:
|
|
253
276
|
|
|
@@ -372,14 +395,14 @@ Import the module that defines the name; the package has no root entry.
|
|
|
372
395
|
| Module | Functions and schemas |
|
|
373
396
|
| --- | --- |
|
|
374
397
|
| `operation.ts` | `query(name, { payload?, success?, rejections?, reads })`; `command(name, { payload?, success?, rejections?, invalidates })`; `stream(name, { payload?, success, rejections?, reads })`. |
|
|
375
|
-
| `contract.ts` | `contract(name, { queries?, commands?, streams? })`, returning a native RPC group with `declaration: { name, queries, commands, streams }`. |
|
|
398
|
+
| `contract.ts` | `contract(name, { queries?, commands?, streams?, keyScope? })`, returning a native RPC group with `declaration: { name, queries, commands, streams, keyScope }`. |
|
|
376
399
|
| `rejection.ts` | `fieldRejection(struct, fields?)`; lower-level `rejectionSet(specs)`, which constructs the rejection classes, union schema and failure helpers used by operations. |
|
|
377
|
-
| `keys.ts` | `collection(name, idSchema)`; `Key` schema; `readKeys(keys)` and `invalidationKeys(keys)`. |
|
|
378
|
-
| `bind.ts` | `bind(contract, atomRpcService)`, exposing `{ query, run }` for queries, `{ run }` Effects for commands and `{ run }` native Streams for streams. |
|
|
379
|
-
| `live.ts` | `LiveHint` schema; `live(runtime, { stream, resyncKeys, coalesceWindow?, resume?, retryDelay? })`, exposing `connection`, `coalesceWindow`, `paused` and `status`. |
|
|
400
|
+
| `keys.ts` | `collection(name, idSchema)`; `Key` schema; `readKeys(keys, context?)` and `invalidationKeys(keys, context?)`. |
|
|
401
|
+
| `bind.ts` | `bind(contract, atomRpcService, { registry }?)`, requiring the registry for session-scoped contracts and exposing `{ query, run }` for queries, `{ run }` Effects for commands and `{ run }` native Streams for streams. |
|
|
402
|
+
| `live.ts` | `LiveHint` schema; `live(runtime, { stream, resyncKeys, coalesceWindow?, keyContext?, resume?, retryDelay? })`, exposing `connection`, `coalesceWindow`, `paused` and `status`. |
|
|
380
403
|
| `makeLiveServer.ts` | `makeLiveServer`, an Effect requiring `Reactivity` that creates scoped server hint streams and a `resync` Effect. |
|
|
381
404
|
| `readPolicy.ts` | `authorizeReads(effect, request, policy, denied)`; `ReadPolicy`, the request-local fallible key policy used by server hint streams; `ReadPolicyMemoWindow`, a `Context.Reference<Duration.Input>` controlling each stream's memo duration. |
|
|
382
|
-
| `serverMetadata.ts` | `QueryReads`, `CommandInvalidation` and `changesRpc(name)` for server adapters. |
|
|
405
|
+
| `serverMetadata.ts` | `KeyScope`, `QueryReads`, `CommandInvalidation`, `ChangesReads`, `queryKeys(queries, references)` and `changesRpc(name, queries)` for server adapters. |
|
|
383
406
|
| `resume.ts` | `resumeSignal({ window?, native? })`, returning a native numeric signal atom. |
|
|
384
407
|
|
|
385
408
|
A query atom takes native query options as its optional second argument, for example `api.get.query({ id: 1 }, { timeToLive: "1 minute" })`. A native resume source receives a callback and returns a cleanup function.
|
package/dist/automaticLive.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { type Duration } from "effect";
|
|
2
|
-
import
|
|
2
|
+
import * as Atom from "effect/reactivity/Atom";
|
|
3
|
+
import * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
3
4
|
import type * as AtomRpc from "effect/reactivity/AtomRpc";
|
|
4
|
-
import {
|
|
5
|
-
import { type
|
|
6
|
-
import type
|
|
5
|
+
import type { BindingOwner } from "#internal/bindingOwner.ts";
|
|
6
|
+
import { type Key } from "#keys.ts";
|
|
7
|
+
import { type LiveStatus } from "#live.ts";
|
|
8
|
+
import type { changesRpc, QueryReference } from "#serverMetadata.ts";
|
|
7
9
|
export declare const LiveConnection: unique symbol;
|
|
8
10
|
export interface LiveBound {
|
|
9
11
|
readonly [LiveConnection]: {
|
|
@@ -13,13 +15,13 @@ export interface LiveBound {
|
|
|
13
15
|
};
|
|
14
16
|
}
|
|
15
17
|
export type ChangesClient = AtomRpc.AtomRpcClient<unknown, string, ReturnType<typeof changesRpc>>;
|
|
16
|
-
export declare function automaticLive(service: ChangesClient, name: string): {
|
|
18
|
+
export declare function automaticLive(service: ChangesClient, name: string, owner?: BindingOwner): {
|
|
17
19
|
subscription: {
|
|
18
20
|
coalesceWindow: Atom.Writable<Duration.Input, Duration.Input>;
|
|
19
|
-
connection: Atom.Atom<import("effect/reactivity/AsyncResult").AsyncResult<void, never>>;
|
|
20
21
|
paused: Atom.Writable<boolean, boolean>;
|
|
21
22
|
status: Atom.Writable<LiveStatus<import("effect/rpc/RpcClientError").RpcClientError>, LiveStatus<import("effect/rpc/RpcClientError").RpcClientError>>;
|
|
23
|
+
connection: Atom.Atom<import("effect/reactivity/AsyncResult").AsyncResult<void, never>>;
|
|
22
24
|
};
|
|
23
|
-
track: (
|
|
25
|
+
track: (registry: AtomRegistry.AtomRegistry | undefined, reference: QueryReference, keys: readonly Key[]) => () => void;
|
|
24
26
|
};
|
|
25
27
|
//# sourceMappingURL=automaticLive.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"automaticLive.d.ts","sourceRoot":"","sources":["../src/automaticLive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAmC,MAAM,QAAQ,CAAC;AACxE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"automaticLive.d.ts","sourceRoot":"","sources":["../src/automaticLive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAmC,MAAM,QAAQ,CAAC;AACxE,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAC/C,OAAO,KAAK,YAAY,MAAM,gCAAgC,CAAC;AAC/D,OAAO,KAAK,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,KAAK,GAAG,EAAY,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,KAAK,UAAU,EAAQ,MAAM,UAAU,CAAC;AAEjD,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIrE,eAAO,MAAM,cAAc,eAA0D,CAAC;AACtF,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,CAAC,cAAc,CAAC,EAAE;QAC1B,QAAQ,CAAC,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACvD,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;KAChD,CAAC;CACF;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC;AAOlG,wBAAgB,aAAa,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,YAAY;;;;;;;sBAI9D,YAAY,CAAC,YAAY,GAAG,SAAS,aAAa,cAAc,QAAQ,SAAS,GAAG,EAAE;EAuD/G"}
|
package/dist/automaticLive.js
CHANGED
|
@@ -1,29 +1,62 @@
|
|
|
1
1
|
import { Effect, Stream, SubscriptionRef } from "effect";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
2
|
+
import * as Atom from "effect/reactivity/Atom";
|
|
3
|
+
import * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
4
|
+
import { readKeys } from "#keys.ts";
|
|
5
|
+
import { live } from "#live.ts";
|
|
6
|
+
import { resumeSignal } from "#resume.ts";
|
|
5
7
|
export const LiveConnection = Symbol.for("@shivaedev/effect-contract/LiveConnection");
|
|
6
|
-
export function automaticLive(service, name) {
|
|
7
|
-
const
|
|
8
|
+
export function automaticLive(service, name, owner) {
|
|
9
|
+
const eager = owner === undefined ? Effect.runSync(SubscriptionRef.make(new Map())) : undefined;
|
|
8
10
|
const known = new Set();
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
const tracked = Atom.keepAlive(Atom.make(() => eager ?? Effect.runSync(SubscriptionRef.make(new Map()))));
|
|
12
|
+
function track(registry, reference, keys) {
|
|
13
|
+
const fresh = eager === undefined
|
|
14
|
+
? keys
|
|
15
|
+
: keys.filter((key) => {
|
|
16
|
+
const id = readKeys([key])[0] ?? "";
|
|
17
|
+
if (known.has(id)) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
known.add(id);
|
|
21
|
+
return true;
|
|
22
|
+
});
|
|
23
|
+
if (fresh.length === 0) {
|
|
24
|
+
return () => undefined;
|
|
20
25
|
}
|
|
26
|
+
const token = {};
|
|
27
|
+
const state = eager ?? registry?.get(tracked);
|
|
28
|
+
if (state === undefined) {
|
|
29
|
+
throw new Error("Session query tracking requires its owning registry");
|
|
30
|
+
}
|
|
31
|
+
Effect.runSync(SubscriptionRef.update(state, (current) => new Map([...current, [token, { keys: fresh, reference }]])));
|
|
32
|
+
if (eager !== undefined) {
|
|
33
|
+
return () => undefined;
|
|
34
|
+
}
|
|
35
|
+
return () => Effect.runSync(SubscriptionRef.update(state, (current) => {
|
|
36
|
+
const next = new Map(current);
|
|
37
|
+
next.delete(token);
|
|
38
|
+
return next;
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
function subscribe(current) {
|
|
42
|
+
if (current.size === 0) {
|
|
43
|
+
return Stream.never;
|
|
44
|
+
}
|
|
45
|
+
const queries = [...current.values()].map(({ reference }) => reference);
|
|
46
|
+
return Stream.unwrap(service.use((client) => Effect.succeed(client(`${name}.$changes`, { queries }))));
|
|
21
47
|
}
|
|
22
48
|
const subscription = live(service.runtime, {
|
|
49
|
+
keyContext: owner?.context,
|
|
23
50
|
resume: resumeSignal(typeof window === "undefined" ? {} : { window }),
|
|
24
|
-
resyncKeys: () => Effect.runSync(SubscriptionRef.get(keys)),
|
|
25
|
-
stream:
|
|
51
|
+
resyncKeys: (registry) => [...Effect.runSync(SubscriptionRef.get(registry.get(tracked))).values()].flatMap(({ keys }) => keys),
|
|
52
|
+
stream: Stream.unwrap(Effect.map(AtomRegistry.AtomRegistry, (registry) => SubscriptionRef.changes(registry.get(tracked)).pipe(Stream.switchMap(subscribe)))),
|
|
26
53
|
});
|
|
27
|
-
|
|
54
|
+
const connection = Atom.make((get) => {
|
|
55
|
+
if (owner !== undefined && owner.registry !== get.registry) {
|
|
56
|
+
throw new Error("A session-scoped live connection belongs to its binding registry");
|
|
57
|
+
}
|
|
58
|
+
return get(subscription.connection);
|
|
59
|
+
}).pipe(Atom.setIdleTTL(0));
|
|
60
|
+
return { subscription: { ...subscription, connection }, track };
|
|
28
61
|
}
|
|
29
62
|
//# sourceMappingURL=automaticLive.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"automaticLive.js","sourceRoot":"","sources":["../src/automaticLive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"automaticLive.js","sourceRoot":"","sources":["../src/automaticLive.ts"],"names":[],"mappings":"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"}
|
package/dist/bind.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import type { Duration } from "effect";
|
|
2
|
-
import { Effect, Stream } from "effect";
|
|
1
|
+
import type { Duration, Effect, Stream } from "effect";
|
|
3
2
|
import type { Headers } from "effect/http";
|
|
4
3
|
import type * as AsyncResult from "effect/reactivity/AsyncResult";
|
|
5
4
|
import type * as Atom from "effect/reactivity/Atom";
|
|
5
|
+
import type * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
6
6
|
import type * as AtomRpc from "effect/reactivity/AtomRpc";
|
|
7
|
-
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
7
|
+
import type * as Reactivity from "effect/reactivity/Reactivity";
|
|
8
8
|
import type { Rpc } from "effect/rpc";
|
|
9
9
|
import type { RpcClientError } from "effect/rpc/RpcClientError";
|
|
10
|
-
import { type LiveBound } from "
|
|
11
|
-
import type { Contract, Tag } from "
|
|
12
|
-
import type { CommandShape, QueryShape, StreamShape } from "
|
|
10
|
+
import { type LiveBound } from "#automaticLive.ts";
|
|
11
|
+
import type { Contract, Tag } from "#contract.ts";
|
|
12
|
+
import type { CommandShape, QueryShape, StreamShape } from "#operation.ts";
|
|
13
13
|
export type Failure<R extends Rpc.Any> = R extends Rpc.Rpc<infer _Tag, infer _Payload, infer _Success, infer _Error, infer TMiddleware, infer _Requires> ? Rpc.ErrorExit<R> | TMiddleware["error"]["Type"] | RpcClientError : never;
|
|
14
14
|
export type RunFailure<R extends Rpc.Any> = R extends Rpc.Rpc<infer _Tag, infer _Payload, infer _Success, infer _Error, infer TMiddleware, infer _Requires> ? Failure<R> | TMiddleware["~ClientError"] : never;
|
|
15
15
|
export interface QueryOptions {
|
|
@@ -39,6 +39,10 @@ type MatchingClient<TRpcs extends Rpc.Any, TClientRpcs extends Rpc.Any> = [TRpcs
|
|
|
39
39
|
}>] ? [Extract<TClientRpcs, {
|
|
40
40
|
readonly _tag: TRpcs["_tag"];
|
|
41
41
|
}>] extends [TRpcs] ? unknown : "Client must preserve the contract RPC types" : "Client must implement the contract RPCs";
|
|
42
|
-
export declare function bind<TName extends string, TQueries extends readonly QueryShape[], TCommands extends readonly CommandShape[], TRpcs extends Rpc.Any, TSelf, TId extends string, TClientRpcs extends Rpc.Any, TStreams extends readonly StreamShape[]>(contract: Contract<TName, TQueries, TCommands, TRpcs, TStreams>, service: AtomRpc.AtomRpcClient<TSelf, TId, TClientRpcs> & MatchingClient<NoInfer<TRpcs>, TClientRpcs
|
|
42
|
+
export declare function bind<TName extends string, TQueries extends readonly QueryShape[], TCommands extends readonly CommandShape[], TRpcs extends Rpc.Any, TSelf, TId extends string, TClientRpcs extends Rpc.Any, TStreams extends readonly StreamShape[], TScope extends "session" | undefined>(contract: Contract<TName, TQueries, TCommands, TRpcs, TStreams, TScope>, service: AtomRpc.AtomRpcClient<TSelf, TId, TClientRpcs> & MatchingClient<NoInfer<TRpcs>, TClientRpcs>, ...options: "session" extends TScope ? [options: {
|
|
43
|
+
readonly registry: AtomRegistry.AtomRegistry;
|
|
44
|
+
}] : [options?: {
|
|
45
|
+
readonly registry: AtomRegistry.AtomRegistry;
|
|
46
|
+
}]): Bound<TName, TQueries, TCommands, TRpcs, TSelf, TStreams> & LiveBound;
|
|
43
47
|
export {};
|
|
44
48
|
//# sourceMappingURL=bind.d.ts.map
|
package/dist/bind.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"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"}
|
package/dist/bind.js
CHANGED
|
@@ -1,40 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
});
|
|
9
|
-
function boundQuery(service, tag, query, track) {
|
|
10
|
-
const reactive = queryReactivity(service.runtime);
|
|
11
|
-
function reads(payload) {
|
|
12
|
-
return readKeys(query.reads(payload));
|
|
13
|
-
}
|
|
14
|
-
return {
|
|
15
|
-
query: (payload, options = {}) => {
|
|
16
|
-
track(query.reads(payload));
|
|
17
|
-
return reactive(service.query(tag, payload, options), reads(payload));
|
|
18
|
-
},
|
|
19
|
-
run: (payload) => service.use((client) => client(tag, payload)),
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
function boundCommand(service, tag, command) {
|
|
23
|
-
return {
|
|
24
|
-
run: (payload) => service.use((client) => client(tag, payload)).pipe(Effect.tap((result) => invalidateAfter(command.invalidates(payload, result)))),
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
function boundStream(service, tag) {
|
|
28
|
-
return {
|
|
29
|
-
run: (payload) => Stream.unwrap(service.use((client) => Effect.succeed(client(tag, payload)))),
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
export function bind(contract, service) {
|
|
33
|
-
const { name, queries, commands, streams } = contract.declaration;
|
|
34
|
-
const automatic = automaticLive(service, name);
|
|
1
|
+
import { automaticLive, LiveConnection } from "#automaticLive.ts";
|
|
2
|
+
import { bindingOwner } from "#internal/bindingOwner.ts";
|
|
3
|
+
import { boundCommand, boundQuery, boundStream } from "#internal/clientOperations.ts";
|
|
4
|
+
export function bind(contract, service, options) {
|
|
5
|
+
const { name, queries, commands, streams, keyScope } = contract.declaration;
|
|
6
|
+
const owner = bindingOwner(keyScope, options?.registry);
|
|
7
|
+
const automatic = automaticLive(service, name, owner);
|
|
35
8
|
return Object.assign(Object.fromEntries([
|
|
36
|
-
...queries.map((query) => [query.name, boundQuery(service, `${name}.${query.name}`, query, automatic.track)]),
|
|
37
|
-
...commands.map((command) => [command.name, boundCommand(service, `${name}.${command.name}`, command)]),
|
|
9
|
+
...queries.map((query) => [query.name, boundQuery(service, `${name}.${query.name}`, query, automatic.track, owner)]),
|
|
10
|
+
...commands.map((command) => [command.name, boundCommand(service, `${name}.${command.name}`, command, owner)]),
|
|
38
11
|
...streams.map((stream) => [stream.name, boundStream(service, `${name}.${stream.name}`)]),
|
|
39
12
|
]), { [LiveConnection]: automatic.subscription });
|
|
40
13
|
}
|
package/dist/bind.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bind.js","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bind.js","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAkB,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAElF,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAsEtF,MAAM,UAAU,IAAI,CACnB,QAAmJ,EACnJ,OAAwD,EACxD,OAA0D;IAE1D,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC,WAAW,CAAC;IAC5E,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACxD,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACtD,OAAO,MAAM,CAAC,MAAM,CACnB,MAAM,CAAC,WAAW,CAAC;QAClB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAU,CAAC;QAC7H,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,CAAU,CAAC;QACvH,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,CAAU,CAAC;KAClG,CAAC,EACF,EAAE,CAAC,cAAc,CAAC,EAAE,SAAS,CAAC,YAAY,EAAE,CAC5C,CAAC;AACH,CAAC"}
|
package/dist/contract.d.ts
CHANGED
|
@@ -1,31 +1,33 @@
|
|
|
1
1
|
import { type Schema } from "effect";
|
|
2
2
|
import { Rpc, RpcGroup, type RpcMiddleware, type RpcSchema } from "effect/rpc";
|
|
3
|
-
import type { CommandShape, OperationShape, QueryShape, StreamShape } from "
|
|
4
|
-
import { changesRpc } from "
|
|
3
|
+
import type { CommandShape, OperationShape, QueryShape, StreamShape } from "#operation.ts";
|
|
4
|
+
import { changesRpc } from "#serverMetadata.ts";
|
|
5
5
|
export type Tag<TContract extends string, TName extends string> = `${TContract}.${TName}`;
|
|
6
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;
|
|
7
|
-
export interface Declared<TName extends string, TQueries extends readonly QueryShape[], TCommands extends readonly CommandShape[], TStreams extends readonly StreamShape[] = readonly []> {
|
|
7
|
+
export interface Declared<TName extends string, TQueries extends readonly QueryShape[], TCommands extends readonly CommandShape[], TStreams extends readonly StreamShape[] = readonly [], TScope extends "session" | undefined = undefined> {
|
|
8
8
|
readonly commands: TCommands;
|
|
9
|
+
readonly keyScope: TScope;
|
|
9
10
|
readonly name: TName;
|
|
10
11
|
readonly queries: TQueries;
|
|
11
12
|
readonly streams: TStreams;
|
|
12
13
|
}
|
|
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> {
|
|
14
|
+
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, TQueries>>, TStreams extends readonly StreamShape[] = readonly [], TScope extends "session" | undefined = undefined> extends RpcGroup.RpcGroup<TRpcs> {
|
|
14
15
|
readonly application: RpcGroup.RpcGroup<Exclude<TRpcs, {
|
|
15
16
|
readonly _tag: `${TName}.$changes`;
|
|
16
17
|
}>>;
|
|
17
|
-
readonly declaration: Declared<TName, TQueries, TCommands, TStreams>;
|
|
18
|
-
middleware: <TM extends RpcMiddleware.AnyService>(middleware: TM) => Contract<TName, TQueries, TCommands, Rpc.AddMiddleware<TRpcs, TM>, TStreams>;
|
|
18
|
+
readonly declaration: Declared<TName, TQueries, TCommands, TStreams, TScope>;
|
|
19
|
+
middleware: <TM extends RpcMiddleware.AnyService>(middleware: TM) => Contract<TName, TQueries, TCommands, Rpc.AddMiddleware<TRpcs, TM>, TStreams, TScope>;
|
|
19
20
|
}
|
|
20
21
|
type Duplicated<TOperations extends readonly OperationShape[], TSeen extends string = never> = TOperations extends readonly [
|
|
21
22
|
infer THead extends OperationShape,
|
|
22
23
|
...infer TTail extends readonly OperationShape[]
|
|
23
24
|
] ? (THead["name"] extends TSeen ? THead["name"] : never) | Duplicated<TTail, TSeen | THead["name"]> : never;
|
|
24
25
|
type Unique<TOperations extends readonly OperationShape[]> = [Duplicated<TOperations>] extends [never] ? unknown : `Operation names must be unique; duplicated: ${Duplicated<TOperations>}`;
|
|
25
|
-
export declare function contract<const TName extends string, const TQueries extends readonly QueryShape[] = readonly [], const TCommands extends readonly CommandShape[] = readonly [], const TStreams extends readonly StreamShape[] = readonly []>(name: TName, operations: {
|
|
26
|
+
export declare function contract<const TName extends string, const TQueries extends readonly QueryShape[] = readonly [], const TCommands extends readonly CommandShape[] = readonly [], const TStreams extends readonly StreamShape[] = readonly [], const TScope extends "session" | undefined = undefined>(name: TName, operations: {
|
|
27
|
+
readonly keyScope?: TScope;
|
|
26
28
|
readonly queries?: TQueries & Unique<TQueries>;
|
|
27
29
|
readonly commands?: TCommands & Unique<[...TQueries, ...TCommands]>;
|
|
28
30
|
readonly streams?: TStreams & Unique<[...TQueries, ...TCommands, ...TStreams]>;
|
|
29
|
-
}): Contract<TName, TQueries, TCommands, OperationRpc<TName, TQueries[number] | TCommands[number] | TStreams[number]> | ReturnType<typeof changesRpc<TName>>, TStreams>;
|
|
31
|
+
}): Contract<TName, TQueries, TCommands, OperationRpc<TName, TQueries[number] | TCommands[number] | TStreams[number]> | ReturnType<typeof changesRpc<TName, TQueries>>, TStreams, TScope>;
|
|
30
32
|
export {};
|
|
31
33
|
//# 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,
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
|
package/dist/contract.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { Context } from "effect";
|
|
2
2
|
import { Rpc, RpcGroup } from "effect/rpc";
|
|
3
|
-
import { CommandInvalidation, changesRpc, QueryReads } from "
|
|
3
|
+
import { CommandInvalidation, changesRpc, KeyScope, QueryReads } from "#serverMetadata.ts";
|
|
4
4
|
function assertUnique(operations) {
|
|
5
5
|
const duplicated = operations.map(({ name }) => name).filter((name, index, names) => names.indexOf(name) !== index);
|
|
6
6
|
if (duplicated.length > 0) {
|
|
7
7
|
throw new Error(`Operation names must be unique; duplicated: ${[...new Set(duplicated)].join(", ")}`);
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
|
-
function annotations(operation) {
|
|
10
|
+
function annotations(operation, keyScope) {
|
|
11
|
+
const scope = keyScope === undefined ? Context.empty() : Context.make(KeyScope, keyScope);
|
|
11
12
|
if (operation.kind === "command") {
|
|
12
|
-
return Context.
|
|
13
|
+
return Context.add(scope, CommandInvalidation, operation.invalidates);
|
|
13
14
|
}
|
|
14
|
-
return operation.kind === "query" ? Context.
|
|
15
|
+
return operation.kind === "query" ? Context.add(scope, QueryReads, operation.reads) : scope;
|
|
15
16
|
}
|
|
16
17
|
function withDeclaration(group, application, declaration) {
|
|
17
18
|
const nativeMiddleware = group.middleware.bind(group);
|
|
@@ -22,15 +23,22 @@ function withDeclaration(group, application, declaration) {
|
|
|
22
23
|
});
|
|
23
24
|
}
|
|
24
25
|
export function contract(name, operations) {
|
|
25
|
-
const { queries = [], commands = [], streams = [] } = operations;
|
|
26
|
+
const { queries = [], commands = [], streams = [], keyScope } = operations;
|
|
26
27
|
assertUnique([...queries, ...commands, ...streams]);
|
|
27
28
|
const rpcs = [...queries, ...commands, ...streams].map((operation) => Rpc.make(`${name}.${operation.name}`, {
|
|
28
29
|
error: operation.error,
|
|
29
30
|
payload: operation.payload,
|
|
30
31
|
stream: operation.kind === "stream",
|
|
31
32
|
success: operation.success,
|
|
32
|
-
}).annotateMerge(annotations(operation)));
|
|
33
|
+
}).annotateMerge(annotations(operation, keyScope)));
|
|
33
34
|
const application = RpcGroup.make(...rpcs);
|
|
34
|
-
|
|
35
|
+
const changes = changesRpc(name, queries);
|
|
36
|
+
return withDeclaration(application.add(keyScope === undefined ? changes : changes.annotate(KeyScope, keyScope)), application, {
|
|
37
|
+
commands,
|
|
38
|
+
keyScope,
|
|
39
|
+
name,
|
|
40
|
+
queries,
|
|
41
|
+
streams,
|
|
42
|
+
});
|
|
35
43
|
}
|
|
36
44
|
//# sourceMappingURL=contract.js.map
|
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,
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
2
|
+
import type { KeyContext } from "#keys.ts";
|
|
3
|
+
export interface BindingOwner {
|
|
4
|
+
readonly context: KeyContext;
|
|
5
|
+
readonly registry: AtomRegistry.AtomRegistry;
|
|
6
|
+
}
|
|
7
|
+
export declare function bindingOwner(scope: "session" | undefined, registry?: AtomRegistry.AtomRegistry): BindingOwner | undefined;
|
|
8
|
+
//# sourceMappingURL=bindingOwner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bindingOwner.d.ts","sourceRoot":"","sources":["../../src/internal/bindingOwner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,YAAY,MAAM,gCAAgC,CAAC;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC,YAAY,CAAC;CAC7C;AAID,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,EAAE,QAAQ,CAAC,EAAE,YAAY,CAAC,YAAY,GAAG,YAAY,GAAG,SAAS,CAazH"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const contexts = new WeakMap();
|
|
2
|
+
export function bindingOwner(scope, registry) {
|
|
3
|
+
if (scope === undefined) {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
if (registry === undefined) {
|
|
7
|
+
throw new Error("A session-scoped contract requires its owning registry");
|
|
8
|
+
}
|
|
9
|
+
let context = contexts.get(registry);
|
|
10
|
+
if (context === undefined) {
|
|
11
|
+
context = { scope: crypto.randomUUID() };
|
|
12
|
+
contexts.set(registry, context);
|
|
13
|
+
}
|
|
14
|
+
return { context, registry };
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=bindingOwner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bindingOwner.js","sourceRoot":"","sources":["../../src/internal/bindingOwner.ts"],"names":[],"mappings":"AAQA,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAyC,CAAC;AAEtE,MAAM,UAAU,YAAY,CAAC,KAA4B,EAAE,QAAoC;IAC9F,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC;QACzC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Effect, type Schema, Stream } from "effect";
|
|
2
|
+
import type * as AtomRpc from "effect/reactivity/AtomRpc";
|
|
3
|
+
import type { Rpc, RpcSchema } from "effect/rpc";
|
|
4
|
+
import type { automaticLive } from "#automaticLive.ts";
|
|
5
|
+
import type { QueryOptions } from "#bind.ts";
|
|
6
|
+
import type { CommandShape, QueryShape } from "#operation.ts";
|
|
7
|
+
import type { BindingOwner } from "./bindingOwner.ts";
|
|
8
|
+
type ErasedClient = AtomRpc.AtomRpcClient<unknown, string, Rpc.Rpc<string, Schema.Top, Schema.Top, Schema.Top>>;
|
|
9
|
+
type ErasedStreamingClient = AtomRpc.AtomRpcClient<unknown, string, Rpc.Rpc<string, Schema.Top, RpcSchema.Stream<Schema.Top, Schema.Top>, Schema.Never>>;
|
|
10
|
+
export declare function boundQuery(service: ErasedClient, tag: string, query: QueryShape, track: ReturnType<typeof automaticLive>["track"], owner?: BindingOwner): {
|
|
11
|
+
query: (payload: unknown, options?: QueryOptions) => import("effect/reactivity/Atom").Atom<import("effect/reactivity/AsyncResult").AsyncResult<unknown, unknown>>;
|
|
12
|
+
run: (payload: unknown) => Effect.Effect<unknown, unknown, unknown>;
|
|
13
|
+
};
|
|
14
|
+
export declare function boundCommand(service: ErasedClient, tag: string, command: CommandShape, owner?: BindingOwner): {
|
|
15
|
+
run: (payload: unknown) => Effect.Effect<unknown, unknown, unknown>;
|
|
16
|
+
};
|
|
17
|
+
export declare function boundStream(service: ErasedStreamingClient, tag: string): {
|
|
18
|
+
run: (payload: unknown) => Stream.Stream<unknown, unknown, unknown>;
|
|
19
|
+
};
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=clientOperations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clientOperations.d.ts","sourceRoot":"","sources":["../../src/internal/clientOperations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErD,OAAO,KAAK,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAE1D,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGtD,KAAK,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAEhH,KAAK,qBAAqB,GAAG,OAAO,CAAC,aAAa,CACjD,OAAO,EACP,MAAM,EACN,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CACnF,CAAC;AAMF,wBAAgB,UAAU,CACzB,OAAO,EAAE,YAAY,EACrB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC,OAAO,CAAC,EAChD,KAAK,CAAC,EAAE,YAAY;IAInB,KAAK,YAAY,OAAO,YAAW,YAAY;IAc/C,GAAG,YAAY,OAAO;EAOvB;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,CAAC,EAAE,YAAY;IAE1G,GAAG,YAAY,OAAO;EASvB;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,qBAAqB,EAAE,GAAG,EAAE,MAAM;IAErE,GAAG,YAAY,OAAO;EAEvB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Effect, Stream } from "effect";
|
|
2
|
+
import * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
3
|
+
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
4
|
+
import { invalidationKeys, readKeys } from "#keys.ts";
|
|
5
|
+
import { queryReactivity } from "./queryReactivity.js";
|
|
6
|
+
function run(service, effect, owner) {
|
|
7
|
+
return owner === undefined ? effect : Effect.suspend(() => AtomRegistry.getResult(owner.registry, service.runtime.atom(effect)));
|
|
8
|
+
}
|
|
9
|
+
export function boundQuery(service, tag, query, track, owner) {
|
|
10
|
+
const reactive = queryReactivity(service.runtime);
|
|
11
|
+
return {
|
|
12
|
+
query: (payload, options = {}) => {
|
|
13
|
+
const atom = service.query(tag, payload, options);
|
|
14
|
+
const keys = query.reads(payload);
|
|
15
|
+
const reference = { payload, query: query.name };
|
|
16
|
+
if (owner === undefined) {
|
|
17
|
+
track(undefined, reference, keys);
|
|
18
|
+
}
|
|
19
|
+
return reactive(atom, readKeys(keys, owner?.context), (registry) => (owner === undefined ? () => undefined : track(registry, reference, keys)), owner?.registry);
|
|
20
|
+
},
|
|
21
|
+
run: (payload) => run(service, service.use((client) => client(tag, payload)), owner),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function boundCommand(service, tag, command, owner) {
|
|
25
|
+
return {
|
|
26
|
+
run: (payload) => run(service, service
|
|
27
|
+
.use((client) => client(tag, payload))
|
|
28
|
+
.pipe(Effect.tap((result) => Reactivity.invalidate(invalidationKeys(command.invalidates(payload, result), owner?.context)))), owner),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function boundStream(service, tag) {
|
|
32
|
+
return {
|
|
33
|
+
run: (payload) => Stream.unwrap(service.use((client) => Effect.succeed(client(tag, payload)))),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=clientOperations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clientOperations.js","sourceRoot":"","sources":["../../src/internal/clientOperations.ts"],"names":[],"mappings":"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"}
|