@systemfsoftware/effect-atom 0.5.3
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/LICENSE +231 -0
- package/README.md +30 -0
- package/dist/Atom-BgqgP-Qc.d.ts +1287 -0
- package/dist/Atom-BhgqoTsf.mjs +1348 -0
- package/dist/Atom-CxKJ3i4d.d.ts +1257 -0
- package/dist/Atom-DGWqaX9a.d.ts +1257 -0
- package/dist/Atom-DVWTGeoV.mjs +1449 -0
- package/dist/Atom-NsW01Gu1.mjs +1348 -0
- package/dist/Atom.d.ts +2 -0
- package/dist/Atom.mjs +2 -0
- package/dist/AtomHttpApi.d.ts +74 -0
- package/dist/AtomHttpApi.mjs +129 -0
- package/dist/AtomRef.d.ts +91 -0
- package/dist/AtomRef.mjs +248 -0
- package/dist/AtomRpc.d.ts +73 -0
- package/dist/AtomRpc.mjs +111 -0
- package/dist/Hydration.d.ts +75 -0
- package/dist/Hydration.mjs +113 -0
- package/dist/Registry-B1ULaW2_.mjs +769 -0
- package/dist/Registry-BE4aKSZk.mjs +823 -0
- package/dist/Registry-DhP1TSer.mjs +769 -0
- package/dist/Registry.d.ts +2 -0
- package/dist/Registry.mjs +2 -0
- package/dist/Result-B2vSp_sE.d.ts +480 -0
- package/dist/Result-BHH-qTvm.d.ts +491 -0
- package/dist/Result-CAjFdzam.d.ts +490 -0
- package/dist/Result-D8FNEzuX.mjs +633 -0
- package/dist/Result-DwtHFH70.mjs +663 -0
- package/dist/Result-rlUvoHzK.mjs +624 -0
- package/dist/Result.d.ts +2 -0
- package/dist/Result.mjs +2 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.mjs +8 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/package.json +94 -0
package/dist/AtomRpc.mjs
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { O as runtime, g as keepAlive, k as serializable, l as family, tt as setIdleTTL } from "./Atom-DVWTGeoV.mjs";
|
|
3
|
+
import { j as schemaCodec } from "./Result-rlUvoHzK.mjs";
|
|
4
|
+
import * as Context from "effect/Context";
|
|
5
|
+
import * as Duration from "effect/Duration";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as Layer from "effect/Layer";
|
|
8
|
+
import * as Schema from "effect/Schema";
|
|
9
|
+
import "effect/Scope";
|
|
10
|
+
import * as Stream from "effect/Stream";
|
|
11
|
+
import * as Reactivity from "effect/unstable/reactivity/Reactivity";
|
|
12
|
+
import * as Headers from "effect/unstable/http/Headers";
|
|
13
|
+
import * as RpcClient from "effect/unstable/rpc/RpcClient";
|
|
14
|
+
import { RpcClientError } from "effect/unstable/rpc/RpcClientError";
|
|
15
|
+
import * as RpcSchema from "effect/unstable/rpc/RpcSchema";
|
|
16
|
+
//#region src/AtomRpc.ts
|
|
17
|
+
/**
|
|
18
|
+
* Connects typed RPC clients to atoms.
|
|
19
|
+
*
|
|
20
|
+
* The service created here exposes a flattened RPC client plus atom-based query
|
|
21
|
+
* and mutation helpers. Query atoms call RPCs and track asynchronous or
|
|
22
|
+
* streaming results, while mutations run RPC calls that can invalidate
|
|
23
|
+
* reactivity keys after success. Query atoms can also use request headers,
|
|
24
|
+
* time-to-live settings, and serialization keys for hydration.
|
|
25
|
+
*
|
|
26
|
+
* @since 4.0.0
|
|
27
|
+
*/
|
|
28
|
+
var AtomRpc_exports = /* @__PURE__ */ __exportAll({ Service: () => Service });
|
|
29
|
+
/**
|
|
30
|
+
* Creates a `Context.Service` class for an RPC client backed by an atom runtime.
|
|
31
|
+
*
|
|
32
|
+
* **Details**
|
|
33
|
+
*
|
|
34
|
+
* The options provide the RPC group, protocol layer, tracing options, request id generation, optional custom client
|
|
35
|
+
* effect, and runtime factory used by the query and mutation helpers.
|
|
36
|
+
*
|
|
37
|
+
* @category constructors
|
|
38
|
+
* @since 4.0.0
|
|
39
|
+
*/
|
|
40
|
+
const Service = () => (id, options) => {
|
|
41
|
+
const service = Context.Service()(id);
|
|
42
|
+
const layer = Layer.effect(service, options.makeEffect ?? RpcClient.make(options.group, {
|
|
43
|
+
...options,
|
|
44
|
+
flatten: true
|
|
45
|
+
}));
|
|
46
|
+
const protocol = options.protocol;
|
|
47
|
+
const runtime$1 = (options.runtime ?? runtime)(typeof protocol === "function" ? (get) => Layer.provide(layer, Layer.orDie(protocol(get))) : Layer.provide(layer, Layer.orDie(protocol)));
|
|
48
|
+
const isAnyWithProps = (u) => (typeof u === "object" && u !== null || typeof u === "function") && "payloadSchema" in u && "successSchema" in u && "errorSchema" in u;
|
|
49
|
+
const getRpc = (tag) => {
|
|
50
|
+
const rpc = options.group.requests.get(tag);
|
|
51
|
+
if (rpc === void 0 || !isAnyWithProps(rpc)) throw new Error(`Unknown RPC tag: ${tag}`);
|
|
52
|
+
return rpc;
|
|
53
|
+
};
|
|
54
|
+
/** `Flat` is a callable, so this narrowing is a check rather than a claim. */
|
|
55
|
+
const isErasedFlatCall = (client) => typeof client === "function";
|
|
56
|
+
function callFlat(client, tag, payload, headers, _shape) {
|
|
57
|
+
if (!isErasedFlatCall(client)) throw new Error(`RpcClient.Flat is not callable for tag: ${tag}`);
|
|
58
|
+
return client(tag, payload, { headers });
|
|
59
|
+
}
|
|
60
|
+
const resultSchema = schemaCodec;
|
|
61
|
+
const mutationFamily = family((tag) => {
|
|
62
|
+
const rpc = getRpc(tag);
|
|
63
|
+
const fnAtom = runtime$1.fn()(Effect.fnUntraced(function* ({ headers, payload, reactivityKeys }) {
|
|
64
|
+
const effect = callFlat(yield* service, tag, payload, headers, "effect");
|
|
65
|
+
return yield* reactivityKeys ? Reactivity.mutation(effect, reactivityKeys) : effect;
|
|
66
|
+
}));
|
|
67
|
+
return serializable(fnAtom, {
|
|
68
|
+
key: `AtomRpc:mutation:${tag}`,
|
|
69
|
+
schema: resultSchema(rpc.successSchema, makeErrorSchema(rpc))
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
function mutation(arg) {
|
|
73
|
+
return mutationFamily(arg);
|
|
74
|
+
}
|
|
75
|
+
const queryFamily = family((key) => {
|
|
76
|
+
const { headers, payload, reactivityKeys, tag, timeToLive } = key;
|
|
77
|
+
const rpc = getRpc(tag);
|
|
78
|
+
const isStream = RpcSchema.isStreamSchema(rpc.successSchema);
|
|
79
|
+
let atom = isStream ? runtime$1.pull(Stream.unwrap(service.use((client) => Effect.succeed(callFlat(client, tag, payload, headers, "stream"))))) : runtime$1.atom(service.use((client) => callFlat(client, tag, payload, headers, "effect")));
|
|
80
|
+
if (reactivityKeys) atom = runtime$1.factory.withReactivity(reactivityKeys)(atom);
|
|
81
|
+
if (!isStream && key.serializationKey) atom = serializable(atom, {
|
|
82
|
+
key: `AtomRpc:${key.tag}:${key.serializationKey}`,
|
|
83
|
+
schema: resultSchema(rpc.successSchema, makeErrorSchema(rpc))
|
|
84
|
+
});
|
|
85
|
+
if (timeToLive) atom = Duration.isFinite(timeToLive) ? setIdleTTL(atom, timeToLive) : keepAlive(atom);
|
|
86
|
+
return atom;
|
|
87
|
+
});
|
|
88
|
+
function query(tag, payload, options) {
|
|
89
|
+
const key = {
|
|
90
|
+
tag,
|
|
91
|
+
payload,
|
|
92
|
+
headers: options?.headers ? Headers.fromInput(options.headers) : void 0,
|
|
93
|
+
reactivityKeys: options?.reactivityKeys,
|
|
94
|
+
timeToLive: options?.timeToLive ? Duration.fromInputUnsafe(options.timeToLive) : void 0,
|
|
95
|
+
serializationKey: options?.serializationKey
|
|
96
|
+
};
|
|
97
|
+
return queryFamily(key);
|
|
98
|
+
}
|
|
99
|
+
return Object.assign(service, {
|
|
100
|
+
runtime: runtime$1,
|
|
101
|
+
mutation,
|
|
102
|
+
query
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
const makeErrorSchema = (rpc) => Schema.Union([
|
|
106
|
+
rpc.errorSchema,
|
|
107
|
+
...Array.from(rpc.middlewares, (middleware) => middleware.error),
|
|
108
|
+
RpcClientError
|
|
109
|
+
]);
|
|
110
|
+
//#endregion
|
|
111
|
+
export { Service, AtomRpc_exports as t };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { _t as Registry } from "./Atom-BgqgP-Qc.js";
|
|
2
|
+
import * as Fiber from "effect/Fiber";
|
|
3
|
+
declare namespace Hydration_d_exports {
|
|
4
|
+
export { DehydratedAtom, DehydratedAtomValue, dehydrate, hydrate };
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Marker interface for entries in a dehydrated atom registry state.
|
|
8
|
+
*
|
|
9
|
+
* @category models
|
|
10
|
+
* @since 4.0.0
|
|
11
|
+
*/
|
|
12
|
+
interface DehydratedAtom {
|
|
13
|
+
readonly '~effect/reactivity/DehydratedAtom': true;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A dehydrated serializable atom value.
|
|
17
|
+
*
|
|
18
|
+
* **Details**
|
|
19
|
+
*
|
|
20
|
+
* It stores the atom serialization key, encoded value, and dehydration
|
|
21
|
+
* timestamp.
|
|
22
|
+
*
|
|
23
|
+
* @category models
|
|
24
|
+
* @since 4.0.0
|
|
25
|
+
*/
|
|
26
|
+
interface DehydratedAtomValue extends DehydratedAtom {
|
|
27
|
+
readonly key: string;
|
|
28
|
+
readonly value: unknown;
|
|
29
|
+
readonly dehydratedAt: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Encodes the serializable atoms currently stored in a registry into dehydrated
|
|
33
|
+
* state.
|
|
34
|
+
*
|
|
35
|
+
* **Details**
|
|
36
|
+
*
|
|
37
|
+
* Only atoms marked with `Atom.serializable` are included. `encodeInitialAs`
|
|
38
|
+
* controls whether `AsyncResult.Initial` values are ignored, encoded as values,
|
|
39
|
+
* or carried as a pending update that completes when the atom leaves the
|
|
40
|
+
* initial state.
|
|
41
|
+
*
|
|
42
|
+
* @category dehydration
|
|
43
|
+
* @since 4.0.0
|
|
44
|
+
*/
|
|
45
|
+
declare const dehydrate: (registry: Registry, options?: {
|
|
46
|
+
/**
|
|
47
|
+
* How to encode `AsyncResult.Initial` values. Default is "ignore".
|
|
48
|
+
*/
|
|
49
|
+
readonly encodeInitialAs?: 'ignore' | 'deferred' | 'value-only' | undefined;
|
|
50
|
+
}) => DehydratedAtomValue[];
|
|
51
|
+
/**
|
|
52
|
+
* Applies dehydrated atom state to a registry.
|
|
53
|
+
*
|
|
54
|
+
* **When to use**
|
|
55
|
+
*
|
|
56
|
+
* Use to preload serialized atom values into a target registry before those
|
|
57
|
+
* atoms are read.
|
|
58
|
+
*
|
|
59
|
+
* **Details**
|
|
60
|
+
*
|
|
61
|
+
* Encoded values are preloaded by serialization key. Entries whose initial
|
|
62
|
+
* state was carried as pending (see `dehydrate`'s `encodeInitialAs`) update the
|
|
63
|
+
* matching registry node, or preload the resolved value, when that pending
|
|
64
|
+
* value completes.
|
|
65
|
+
*
|
|
66
|
+
* Returns a fiber that completes once every pending update has been applied to
|
|
67
|
+
* the registry. Callers that need the state fully settled — tests, SSR flushes
|
|
68
|
+
* — can join it; fire-and-forget callers can ignore it.
|
|
69
|
+
*
|
|
70
|
+
* @category hydration
|
|
71
|
+
* @since 4.0.0
|
|
72
|
+
*/
|
|
73
|
+
declare const hydrate: (registry: Registry, dehydratedState: Iterable<DehydratedAtomValue>) => Fiber.Fiber<void, never>;
|
|
74
|
+
//#endregion
|
|
75
|
+
export { DehydratedAtom, DehydratedAtomValue, dehydrate, hydrate, Hydration_d_exports as t };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { h as isSerializable, i as SerializableTypeId } from "./Atom-DVWTGeoV.mjs";
|
|
3
|
+
import { F as isResult, h as isInitial } from "./Result-rlUvoHzK.mjs";
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
import * as Clock from "effect/Clock";
|
|
6
|
+
import * as Deferred from "effect/Deferred";
|
|
7
|
+
//#region src/Hydration.ts
|
|
8
|
+
/**
|
|
9
|
+
* Saves and restores serializable atom state.
|
|
10
|
+
*
|
|
11
|
+
* `dehydrate` reads atoms marked with `Atom.serializable` from an
|
|
12
|
+
* `AtomRegistry` and returns encoded entries keyed by their serialization keys.
|
|
13
|
+
* `hydrate` preloads those entries into another registry before the atoms are
|
|
14
|
+
* read. Initial `AsyncResult` values can be ignored, encoded as values, or
|
|
15
|
+
* carried as a pending update that settles the target registry once the source
|
|
16
|
+
* atom leaves the initial state.
|
|
17
|
+
*
|
|
18
|
+
* @since 4.0.0
|
|
19
|
+
*/
|
|
20
|
+
var Hydration_exports = /* @__PURE__ */ __exportAll({
|
|
21
|
+
dehydrate: () => dehydrate,
|
|
22
|
+
hydrate: () => hydrate
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* Non-serializable completion channel for entries dehydrated in `'deferred'`
|
|
26
|
+
* mode. Keyed by entry identity so nothing appears on the public surface: the
|
|
27
|
+
* same objects `dehydrate` returns must be handed to `hydrate`. A `Deferred`
|
|
28
|
+
* cannot cross a serialization boundary anyway, so entries that do cross one
|
|
29
|
+
* are simply applied as plain preloads.
|
|
30
|
+
*/
|
|
31
|
+
const pendingResults = /* @__PURE__ */ new WeakMap();
|
|
32
|
+
/**
|
|
33
|
+
* Encodes the serializable atoms currently stored in a registry into dehydrated
|
|
34
|
+
* state.
|
|
35
|
+
*
|
|
36
|
+
* **Details**
|
|
37
|
+
*
|
|
38
|
+
* Only atoms marked with `Atom.serializable` are included. `encodeInitialAs`
|
|
39
|
+
* controls whether `AsyncResult.Initial` values are ignored, encoded as values,
|
|
40
|
+
* or carried as a pending update that completes when the atom leaves the
|
|
41
|
+
* initial state.
|
|
42
|
+
*
|
|
43
|
+
* @category dehydration
|
|
44
|
+
* @since 4.0.0
|
|
45
|
+
*/
|
|
46
|
+
const dehydrate = (registry, options) => {
|
|
47
|
+
const encodeInitialResultMode = options?.encodeInitialAs ?? "ignore";
|
|
48
|
+
const arr = [];
|
|
49
|
+
const now = Effect.runSync(Clock.currentTimeMillis);
|
|
50
|
+
registry.getNodes().forEach((node, key) => {
|
|
51
|
+
if (!isSerializable(node.atom)) return;
|
|
52
|
+
const atom = node.atom;
|
|
53
|
+
const value = node.value();
|
|
54
|
+
const isInitial$1 = isResult(value) && isInitial(value);
|
|
55
|
+
if (encodeInitialResultMode === "ignore" && isInitial$1) return;
|
|
56
|
+
if (typeof key !== "string") return;
|
|
57
|
+
const serializer = atom[SerializableTypeId];
|
|
58
|
+
const entry = {
|
|
59
|
+
"~effect/reactivity/DehydratedAtom": true,
|
|
60
|
+
key,
|
|
61
|
+
value: serializer.encode(value),
|
|
62
|
+
dehydratedAt: now
|
|
63
|
+
};
|
|
64
|
+
if (encodeInitialResultMode === "deferred" && isInitial$1) {
|
|
65
|
+
const deferred = Deferred.makeUnsafe();
|
|
66
|
+
const unsubscribe = registry.subscribe(atom, (newValue) => {
|
|
67
|
+
if (isResult(newValue) && !isInitial(newValue)) {
|
|
68
|
+
Deferred.doneUnsafe(deferred, Effect.succeed(serializer.encode(newValue)));
|
|
69
|
+
unsubscribe();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
pendingResults.set(entry, deferred);
|
|
73
|
+
}
|
|
74
|
+
arr.push(entry);
|
|
75
|
+
});
|
|
76
|
+
return arr;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Applies dehydrated atom state to a registry.
|
|
80
|
+
*
|
|
81
|
+
* **When to use**
|
|
82
|
+
*
|
|
83
|
+
* Use to preload serialized atom values into a target registry before those
|
|
84
|
+
* atoms are read.
|
|
85
|
+
*
|
|
86
|
+
* **Details**
|
|
87
|
+
*
|
|
88
|
+
* Encoded values are preloaded by serialization key. Entries whose initial
|
|
89
|
+
* state was carried as pending (see `dehydrate`'s `encodeInitialAs`) update the
|
|
90
|
+
* matching registry node, or preload the resolved value, when that pending
|
|
91
|
+
* value completes.
|
|
92
|
+
*
|
|
93
|
+
* Returns a fiber that completes once every pending update has been applied to
|
|
94
|
+
* the registry. Callers that need the state fully settled — tests, SSR flushes
|
|
95
|
+
* — can join it; fire-and-forget callers can ignore it.
|
|
96
|
+
*
|
|
97
|
+
* @category hydration
|
|
98
|
+
* @since 4.0.0
|
|
99
|
+
*/
|
|
100
|
+
const hydrate = (registry, dehydratedState) => {
|
|
101
|
+
const pending = [];
|
|
102
|
+
for (const datom of dehydratedState) {
|
|
103
|
+
registry.setSerializable(datom.key, datom.value);
|
|
104
|
+
const result = pendingResults.get(datom);
|
|
105
|
+
if (result === void 0) continue;
|
|
106
|
+
pending.push(Effect.flatMap(Deferred.await(result), (resolvedValue) => Effect.sync(() => {
|
|
107
|
+
registry.setSerializable(datom.key, resolvedValue);
|
|
108
|
+
})));
|
|
109
|
+
}
|
|
110
|
+
return Effect.runFork(Effect.forEach(pending, (effect) => effect, { discard: true }));
|
|
111
|
+
};
|
|
112
|
+
//#endregion
|
|
113
|
+
export { dehydrate, hydrate, Hydration_exports as t };
|