@gaganref/confect-foldkit 0.0.0-stage → 10.3.1-fork.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,123 @@
1
+ import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
+ import { Client, WebSocketClientError } from "./Client.js";
3
+ import { FunctionError, allocateRequest, getSubscriptionRequest } from "./PaginatedQuery.js";
4
+ import * as Effect from "effect/Effect";
5
+ import * as Option from "effect/Option";
6
+ import * as Match from "effect/Match";
7
+ import * as PaginationError from "@confect/core/PaginationError";
8
+ import * as Result from "effect/Result";
9
+ import * as Schema from "effect/Schema";
10
+ import * as Stream from "effect/Stream";
11
+ //#region src/Subscription.ts
12
+ var Subscription_exports = /* @__PURE__ */ __exportAll({
13
+ paginatedQuery: () => paginatedQuery,
14
+ reactiveQuery: () => reactiveQuery,
15
+ reactiveQueryStream: () => reactiveQueryStream
16
+ });
17
+ const paginatedError = (error) => Match.value(error).pipe(Match.when(Schema.isSchemaError, (schemaError) => schemaError), Match.when(Match.instanceOf(WebSocketClientError), (clientError) => PaginationError.fromConvexQueryError(clientError.cause).pipe(Option.getOrElse(() => clientError))), Match.when(Match.any, (functionError) => PaginationError.fromConvexErrorData(functionError).pipe(Option.getOrElse(() => FunctionError({ error: functionError })))), Match.exhaustive);
18
+ /**
19
+ * A `dependenciesToStream` body for a hand-written subscription entry: runs the
20
+ * ref as a reactive query against the `Client` resource and maps every emission
21
+ * and every failure into a Message. Query failures are values, so the
22
+ * subscription remains live and can later emit a successful result.
23
+ *
24
+ * Prefer `reactiveQuery`, which builds the whole entry; reach for this when you
25
+ * need control over the entry's dependencies (custom gating, extra
26
+ * dependencies).
27
+ */
28
+ const reactiveQueryStream = (ref, handlers) => (...args) => Client.pipe(Effect.map((client) => client.reactiveQueryResult(ref, ...args)), Stream.unwrap, Stream.map(Result.match({
29
+ onSuccess: handlers.onSuccess,
30
+ onFailure: handlers.onError
31
+ })));
32
+ /**
33
+ * A complete Foldkit subscription entry for a Confect reactive query. The
34
+ * leading thunk fixes the `Model` type (TypeScript cannot partially infer type
35
+ * arguments), so the `args` extractor's parameter is already typed. Pass the
36
+ * result as an entry value to `Subscription.make`:
37
+ *
38
+ * ```ts
39
+ * import * as Confect from "@confect/foldkit";
40
+ * import * as Subscription from "foldkit/subscription";
41
+ *
42
+ * const subscriptions = Subscription.make<
43
+ * Model,
44
+ * Message,
45
+ * Confect.Client.Client
46
+ * >()(() => ({
47
+ * note: Confect.Subscription.reactiveQuery<Model>()(
48
+ * refs.public.notes.get,
49
+ * {
50
+ * args: (model) =>
51
+ * Option.map(model.noteId, (noteId) => ({ noteId })),
52
+ * onSuccess: (note) => SucceededGetNote({ note }),
53
+ * onError: (error) => FailedGetNote({ message: String(error) }),
54
+ * },
55
+ * ),
56
+ * }));
57
+ * ```
58
+ *
59
+ * The entry's dependencies are the query args wrapped in `Option`: `None`
60
+ * closes the subscription, a change from one `Some` to another unsubscribes and
61
+ * resubscribes with the new args, and structurally equal args leave the
62
+ * subscription running (equivalence is derived from the ref's args schema).
63
+ * Queries without args may omit `args`, leaving the subscription always open.
64
+ */
65
+ const reactiveQuery = () => (ref, config) => {
66
+ const modelToArgs = config.args;
67
+ return {
68
+ dependenciesSchema: Schema.Struct({ args: Schema.Option(ref.args) }),
69
+ modelToDependencies: (model) => ({ args: modelToArgs === void 0 ? Option.some({}) : modelToArgs(model) }),
70
+ dependenciesToStream: ({ args }) => Option.match(args, {
71
+ onNone: () => Stream.empty,
72
+ onSome: (someArgs) => reactiveQueryStream(ref, config)(someArgs)
73
+ })
74
+ };
75
+ };
76
+ const paginatedQuery = () => (machine, config) => {
77
+ const ref = machine.ref;
78
+ const composedArgsSchema = ref.args;
79
+ const requestEquivalence = Schema.toEquivalence(machine.subscriptionRequestSchema);
80
+ const optionalRequestEquivalence = Option.makeEquivalence((left, right) => requestEquivalence({
81
+ ...left,
82
+ paginationId: Option.none()
83
+ }, {
84
+ ...right,
85
+ paginationId: Option.none()
86
+ }));
87
+ return {
88
+ dependenciesSchema: Schema.Struct({ request: Schema.Option(machine.subscriptionRequestSchema) }),
89
+ modelToDependencies: (model) => ({ request: Match.value(config.state(model)).pipe(Match.tag("Idle", () => Option.none()), Match.tag("Active", (state) => Option.some(getSubscriptionRequest(state))), Match.exhaustive) }),
90
+ keepAliveEquivalence: (left, right) => optionalRequestEquivalence(left.request, right.request),
91
+ dependenciesToStream: ({ request }) => Option.match(request, {
92
+ onNone: () => Stream.empty,
93
+ onSome: (subscriptionRequest) => Stream.unwrap(Effect.gen(function* () {
94
+ const client = yield* Client;
95
+ const paginationId = yield* client.resolvePaginationId(subscriptionRequest.paginationId);
96
+ const allocatedRequest = allocateRequest(subscriptionRequest, paginationId);
97
+ const { descriptor, options } = allocatedRequest;
98
+ const composedArgs = composedArgsSchema.make({
99
+ ...allocatedRequest.args,
100
+ paginationOpts: {
101
+ numItems: options.initialNumItems,
102
+ cursor: descriptor.cursor,
103
+ id: paginationId,
104
+ ...Match.value(options.maximumRowsRead).pipe(Match.when(void 0, () => ({})), Match.when(Match.defined, (maximumRowsRead) => ({ maximumRowsRead })), Match.exhaustive),
105
+ ...Match.value(options.maximumBytesRead).pipe(Match.when(void 0, () => ({})), Match.when(Match.defined, (maximumBytesRead) => ({ maximumBytesRead })), Match.exhaustive),
106
+ ...Option.match(descriptor.endCursor, {
107
+ onNone: () => ({}),
108
+ onSome: (endCursor) => ({ endCursor })
109
+ })
110
+ }
111
+ });
112
+ return client.reactiveQueryResult(ref, composedArgs).pipe(Stream.map((result) => config.onSettled({
113
+ request: allocatedRequest,
114
+ result: Result.mapError(result, paginatedError)
115
+ })));
116
+ }))
117
+ })
118
+ };
119
+ };
120
+ //#endregion
121
+ export { Subscription_exports, paginatedQuery, reactiveQuery, reactiveQueryStream };
122
+
123
+ //# sourceMappingURL=Subscription.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Subscription.js","names":["Client.WebSocketClientError","PaginatedQuery.FunctionError","PaginatedQuery.getSubscriptionRequest","Client.Client","PaginatedQuery.allocateRequest"],"sources":["../src/Subscription.ts"],"sourcesContent":["import * as PaginationError from \"@confect/core/PaginationError\";\nimport type * as Ref from \"@confect/core/Ref\";\nimport * as Effect from \"effect/Effect\";\nimport type * as Equivalence from \"effect/Equivalence\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as Result from \"effect/Result\";\nimport * as Schema from \"effect/Schema\";\nimport * as Stream from \"effect/Stream\";\nimport type * as FoldkitSubscription from \"foldkit/subscription\";\nimport * as PaginatedQuery from \"./PaginatedQuery\";\nimport * as Client from \"./Client\";\n\n/**\n * Everything a reactive query subscription against `Query` can fail with: the\n * ref's typed error (if it declares an `error` schema), a transport-level\n * `WebSocketClientError`, or a `SchemaError` from encoding args or decoding\n * returns.\n */\nexport type Error<Query extends Ref.AnyConfectPublicQuery> =\n | Ref.Error<Query>\n | Client.WebSocketClientError\n | Schema.SchemaError;\n\nconst paginatedError = <Query extends Ref.AnyConfectPublicPaginatedQuery>(\n error: Error<Query>,\n): PaginatedQuery.Error<Query> =>\n Match.value(error).pipe(\n Match.when(Schema.isSchemaError, (schemaError) => schemaError),\n Match.when(Match.instanceOf(Client.WebSocketClientError), (clientError) =>\n PaginationError.fromConvexQueryError(clientError.cause).pipe(\n Option.getOrElse(() => clientError),\n ),\n ),\n Match.when(Match.any, (functionError) =>\n PaginationError.fromConvexErrorData(functionError).pipe(\n Option.getOrElse(() =>\n PaginatedQuery.FunctionError({ error: functionError }),\n ),\n ),\n ),\n Match.exhaustive,\n ) as PaginatedQuery.Error<Query>;\n\n/**\n * The dependency record of a `reactiveQuery` entry. `None` means the\n * subscription is closed; a change from one `Some` to another tears the server\n * subscription down and reopens it with the new args.\n */\nexport interface Dependencies<Query extends Ref.AnyConfectPublicQuery> {\n readonly args: Option.Option<Ref.Args<Query>>;\n}\n\n/**\n * Maps a reactive query's emissions into the app's Messages. Every failure—the\n * ref's typed error, a transport error, or a codec error—arrives via `onError`,\n * so the resulting stream's error channel is `never`, as Foldkit requires.\n */\nexport interface Handlers<\n Query extends Ref.AnyConfectPublicQuery,\n SuccessMessage,\n ErrorMessage,\n> {\n readonly onSuccess: (returns: Ref.Returns<Query>) => SuccessMessage;\n readonly onError: (error: Error<Query>) => ErrorMessage;\n}\n\n/**\n * The `args` extractor is required whenever the query declares args; queries\n * without args may omit it, in which case the subscription is always open.\n */\ntype ArgsConfig<Query extends Ref.AnyConfectPublicQuery, Model> = {\n readonly args?: (model: Model) => Option.Option<Ref.Args<Query>>;\n} & (keyof Ref.Args<Query> extends never\n ? unknown\n : {\n readonly args: (model: Model) => Option.Option<Ref.Args<Query>>;\n });\n\n/**\n * A `dependenciesToStream` body for a hand-written subscription entry: runs the\n * ref as a reactive query against the `Client` resource and maps every emission\n * and every failure into a Message. Query failures are values, so the\n * subscription remains live and can later emit a successful result.\n *\n * Prefer `reactiveQuery`, which builds the whole entry; reach for this when you\n * need control over the entry's dependencies (custom gating, extra\n * dependencies).\n */\nexport const reactiveQueryStream =\n <Query extends Ref.AnyConfectPublicQuery, SuccessMessage, ErrorMessage>(\n ref: Query,\n handlers: Handlers<Query, SuccessMessage, ErrorMessage>,\n ) =>\n (\n ...args: Ref.OptionalArgs<Query>\n ): Stream.Stream<SuccessMessage | ErrorMessage, never, Client.Client> =>\n Client.Client.pipe(\n Effect.map((client) => client.reactiveQueryResult(ref, ...args)),\n Stream.unwrap,\n Stream.map(\n Result.match({\n onSuccess: handlers.onSuccess,\n onFailure: handlers.onError,\n }),\n ),\n );\n\n/**\n * A complete Foldkit subscription entry for a Confect reactive query. The\n * leading thunk fixes the `Model` type (TypeScript cannot partially infer type\n * arguments), so the `args` extractor's parameter is already typed. Pass the\n * result as an entry value to `Subscription.make`:\n *\n * ```ts\n * import * as Confect from \"@confect/foldkit\";\n * import * as Subscription from \"foldkit/subscription\";\n *\n * const subscriptions = Subscription.make<\n * Model,\n * Message,\n * Confect.Client.Client\n * >()(() => ({\n * note: Confect.Subscription.reactiveQuery<Model>()(\n * refs.public.notes.get,\n * {\n * args: (model) =>\n * Option.map(model.noteId, (noteId) => ({ noteId })),\n * onSuccess: (note) => SucceededGetNote({ note }),\n * onError: (error) => FailedGetNote({ message: String(error) }),\n * },\n * ),\n * }));\n * ```\n *\n * The entry's dependencies are the query args wrapped in `Option`: `None`\n * closes the subscription, a change from one `Some` to another unsubscribes and\n * resubscribes with the new args, and structurally equal args leave the\n * subscription running (equivalence is derived from the ref's args schema).\n * Queries without args may omit `args`, leaving the subscription always open.\n */\nexport const reactiveQuery =\n <Model>() =>\n <Query extends Ref.AnyConfectPublicQuery, SuccessMessage, ErrorMessage>(\n ref: Query,\n config: Handlers<Query, SuccessMessage, ErrorMessage> &\n ArgsConfig<Query, Model>,\n ): FoldkitSubscription.EntryWithoutKeepAlive<\n Model,\n SuccessMessage | ErrorMessage,\n Dependencies<Query>,\n Client.Client\n > => {\n const modelToArgs = config.args;\n\n return {\n dependenciesSchema: Schema.Struct({\n args: Schema.Option(ref.args),\n }),\n modelToDependencies: (model) => ({\n args:\n modelToArgs === undefined\n ? Option.some({} as Ref.Args<Query>)\n : modelToArgs(model),\n }),\n dependenciesToStream: ({ args }) =>\n Option.match(args, {\n onNone: () => Stream.empty,\n onSome: (someArgs) => reactiveQueryStream(ref, config)(someArgs),\n }),\n };\n };\n\n/**\n * A complete Foldkit subscription entry that keeps exactly one live reactive\n * page subscription in sync with a `PaginatedQuery` machine in the Model. The\n * machine state is the single source of truth: navigation and split-pinning\n * change the derived args, while `Idle` closes the subscription. Pagination ids\n * are allocated here and installed by the first settlement.\n *\n * The leading thunk fixes the `Model` type (TypeScript cannot partially infer\n * type arguments), so the `state` extractor's parameter is already typed:\n *\n * ```ts\n * import * as Confect from \"@confect/foldkit\";\n * import * as Subscription from \"foldkit/subscription\";\n *\n * const subscriptions = Subscription.make<\n * Model,\n * Message,\n * Confect.Client.Client\n * >()(() => ({\n * notesPage: Confect.Subscription.paginatedQuery<Model>()(Notes, {\n * state: (model) => model.notes,\n * onSettled: (settlement) => SettledGetNotesPage({ settlement }),\n * }),\n * }));\n * ```\n *\n * Pass the settlement to `PaginatedQuery.settle` in `update`. The request\n * identity is included in both success and failure Messages, so superseded\n * outcomes cannot settle a newer page or pagination session. Query failures do\n * not close the Convex subscription; a later result can recover naturally.\n */\ntype DependenciesSchema<Dependencies_> = Schema.Schema<Dependencies_> & {\n readonly fields: Schema.Struct.Fields;\n};\n\ntype EntryWithKeepAlive<Model, Message, Dependencies_, Services> = {\n readonly dependenciesSchema: DependenciesSchema<Dependencies_>;\n readonly modelToDependencies: (model: Model) => Dependencies_;\n readonly keepAliveEquivalence: Equivalence.Equivalence<Dependencies_>;\n readonly dependenciesToStream: (\n dependencies: Dependencies_,\n readDependencies: () => Dependencies_,\n ) => Stream.Stream<Message, never, Services>;\n};\n\nexport const paginatedQuery =\n <Model>() =>\n <\n PaginatedQueryRef extends Ref.AnyConfectPublicPaginatedQuery,\n SettledMessage,\n >(\n machine: PaginatedQuery.PaginatedQuery<PaginatedQueryRef>,\n config: {\n readonly state: (\n model: Model,\n ) => PaginatedQuery.State<\n PaginatedQuery.Item<PaginatedQueryRef>,\n PaginatedQuery.UserArgs<PaginatedQueryRef>,\n PaginatedQuery.Error<PaginatedQueryRef>\n >;\n readonly onSettled: (\n settlement: PaginatedQuery.Settlement<\n PaginatedQuery.Item<PaginatedQueryRef>,\n PaginatedQuery.UserArgs<PaginatedQueryRef>,\n PaginatedQuery.Error<PaginatedQueryRef>\n >,\n ) => SettledMessage;\n },\n ): EntryWithKeepAlive<\n Model,\n SettledMessage,\n {\n readonly request: Option.Option<\n PaginatedQuery.SubscriptionRequest<\n PaginatedQuery.UserArgs<PaginatedQueryRef>\n >\n >;\n },\n Client.Client\n > => {\n const ref = machine.ref;\n const composedArgsSchema = ref.args;\n const requestEquivalence = Schema.toEquivalence(\n machine.subscriptionRequestSchema,\n );\n const optionalRequestEquivalence = Option.makeEquivalence<\n PaginatedQuery.SubscriptionRequest<\n PaginatedQuery.UserArgs<PaginatedQueryRef>\n >\n >((left, right) =>\n requestEquivalence(\n { ...left, paginationId: Option.none() },\n { ...right, paginationId: Option.none() },\n ),\n );\n\n return {\n dependenciesSchema: Schema.Struct({\n request: Schema.Option(machine.subscriptionRequestSchema),\n }),\n modelToDependencies: (model) => ({\n request: Match.value(config.state(model)).pipe(\n Match.tag(\"Idle\", () => Option.none()),\n Match.tag(\"Active\", (state) =>\n Option.some(PaginatedQuery.getSubscriptionRequest(state)),\n ),\n Match.exhaustive,\n ),\n }),\n keepAliveEquivalence: (left, right) =>\n optionalRequestEquivalence(left.request, right.request),\n dependenciesToStream: ({\n request,\n }): Stream.Stream<SettledMessage, never, Client.Client> =>\n Option.match(request, {\n onNone: () => Stream.empty,\n onSome: (subscriptionRequest) =>\n Stream.unwrap(\n Effect.gen(function* () {\n const client = yield* Client.Client;\n const paginationId = yield* client.resolvePaginationId(\n subscriptionRequest.paginationId,\n );\n const allocatedRequest = PaginatedQuery.allocateRequest(\n subscriptionRequest,\n paginationId,\n );\n const { descriptor, options } = allocatedRequest;\n const composedArgs = composedArgsSchema.make({\n ...allocatedRequest.args,\n paginationOpts: {\n numItems: options.initialNumItems,\n cursor: descriptor.cursor,\n id: paginationId,\n ...Match.value(options.maximumRowsRead).pipe(\n Match.when(undefined, () => ({})),\n Match.when(Match.defined, (maximumRowsRead) => ({\n maximumRowsRead,\n })),\n Match.exhaustive,\n ),\n ...Match.value(options.maximumBytesRead).pipe(\n Match.when(undefined, () => ({})),\n Match.when(Match.defined, (maximumBytesRead) => ({\n maximumBytesRead,\n })),\n Match.exhaustive,\n ),\n ...Option.match(descriptor.endCursor, {\n onNone: () => ({}),\n onSome: (endCursor) => ({ endCursor }),\n }),\n },\n });\n return client.reactiveQueryResult(ref, composedArgs).pipe(\n Stream.map((result) =>\n config.onSettled({\n request: allocatedRequest,\n result: Result.mapError(result, paginatedError),\n }),\n ),\n );\n }),\n ),\n }),\n };\n };\n"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
+ return target;
11
+ };
12
+ //#endregion
13
+ export { __exportAll };
@@ -0,0 +1,5 @@
1
+ export * as Client from "./Client";
2
+ export * as Command from "./Command";
3
+ export * as PaginatedQuery from "./PaginatedQuery";
4
+ export * as Subscription from "./Subscription";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,OAAO,MAAM,WAAW,CAAC;AACrC,OAAO,KAAK,cAAc,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,YAAY,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ import { Client_exports } from "./Client.js";
2
+ import { Command_exports } from "./Command.js";
3
+ import { PaginatedQuery_exports } from "./PaginatedQuery.js";
4
+ import { Subscription_exports } from "./Subscription.js";
5
+ export { Client_exports as Client, Command_exports as Command, PaginatedQuery_exports as PaginatedQuery, Subscription_exports as Subscription };
package/package.json CHANGED
@@ -1,6 +1,58 @@
1
1
  {
2
2
  "name": "@gaganref/confect-foldkit",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "10.3.1-fork.2",
4
+ "peerDependencies": {
5
+ "@confect/core": "npm:@gaganref/confect-core@10.3.1-fork.2",
6
+ "@confect/js": "npm:@gaganref/confect-js@10.3.1-fork.2",
7
+ "effect": "^4.0.0",
8
+ "foldkit": "^0.165.0"
9
+ },
10
+ "description": "Client-side bindings for Foldkit apps",
11
+ "author": "RJ Dellecese",
12
+ "bugs": {
13
+ "url": "https://github.com/gaganref/confect"
14
+ },
15
+ "engines": {
16
+ "node": ">=24"
17
+ },
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "default": "./dist/index.js"
22
+ },
23
+ "./*": {
24
+ "types": "./dist/*.d.ts",
25
+ "default": "./dist/*.js"
26
+ },
27
+ "./package.json": "./package.json"
28
+ },
29
+ "files": [
30
+ "CHANGELOG.md",
31
+ "LICENSE",
32
+ "README.md",
33
+ "dist",
34
+ "!dist/*.tsbuildinfo",
35
+ "package.json",
36
+ "src"
37
+ ],
38
+ "homepage": "https://confect.dev",
39
+ "keywords": [
40
+ "convex",
41
+ "effect",
42
+ "foldkit"
43
+ ],
44
+ "license": "ISC",
45
+ "main": "./dist/index.js",
46
+ "module": "./dist/index.js",
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "git+https://github.com/gaganref/confect.git"
50
+ },
51
+ "sideEffects": false,
52
+ "type": "module",
53
+ "types": "./dist/index.d.ts",
54
+ "publishConfig": {
55
+ "registry": "https://registry.npmjs.org",
56
+ "access": "public"
57
+ }
6
58
  }
package/src/Client.ts ADDED
@@ -0,0 +1,53 @@
1
+ import * as WebSocketClient from "@confect/js/WebSocketClient";
2
+ import type { ConvexClient } from "convex/browser";
3
+ import * as Context from "effect/Context";
4
+ import * as Effect from "effect/Effect";
5
+ import * as Layer from "effect/Layer";
6
+ import * as Option from "effect/Option";
7
+ import * as Ref from "effect/Ref";
8
+
9
+ /**
10
+ * Builds the Foldkit-facing Confect client around one WebSocket client. The
11
+ * pagination id allocator shares the WebSocket client's lifetime because its
12
+ * ids are cache-busters for that client's query cache.
13
+ */
14
+ export const make = (webSocketClient: WebSocketClient.WebSocketClient) =>
15
+ Effect.gen(function* () {
16
+ const paginationId = yield* Ref.make(0);
17
+
18
+ return {
19
+ ...webSocketClient,
20
+ resolvePaginationId: (restored: Option.Option<number>) =>
21
+ Ref.modify(paginationId, (current) =>
22
+ Option.match(restored, {
23
+ onNone: () => [current + 1, current + 1],
24
+ onSome: (id) => [id, Math.max(current, id)],
25
+ }),
26
+ ),
27
+ };
28
+ });
29
+
30
+ /**
31
+ * The application-scoped Confect client used by Foldkit Commands and
32
+ * Subscriptions. It combines the WebSocket API with the pagination-session id
33
+ * allocator required by Convex's query cache.
34
+ */
35
+ export const Client = Context.Service<Effect.Success<ReturnType<typeof make>>>(
36
+ "@confect/foldkit/Client",
37
+ );
38
+
39
+ export type Client = typeof Client.Identifier;
40
+
41
+ /**
42
+ * Constructs one scoped client for a Foldkit application's `resources`.
43
+ */
44
+ export const layer = (
45
+ address: string,
46
+ options?: ConstructorParameters<typeof ConvexClient>[1],
47
+ ) =>
48
+ Layer.effect(
49
+ Client,
50
+ Effect.flatMap(WebSocketClient.WebSocketClient, make),
51
+ ).pipe(Layer.provide(WebSocketClient.layer(address, options)));
52
+
53
+ export { WebSocketClientError } from "@confect/js/WebSocketClient";