@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.
- package/CHANGELOG.md +495 -0
- package/LICENSE +7 -0
- package/README.md +16 -2
- package/dist/Client.d.ts +69 -0
- package/dist/Client.d.ts.map +1 -0
- package/dist/Client.js +44 -0
- package/dist/Client.js.map +1 -0
- package/dist/Command.d.ts +162 -0
- package/dist/Command.d.ts.map +1 -0
- package/dist/Command.js +115 -0
- package/dist/Command.js.map +1 -0
- package/dist/PaginatedQuery.d.ts +291 -0
- package/dist/PaginatedQuery.d.ts.map +1 -0
- package/dist/PaginatedQuery.js +395 -0
- package/dist/PaginatedQuery.js.map +1 -0
- package/dist/Subscription.d.ts +134 -0
- package/dist/Subscription.d.ts.map +1 -0
- package/dist/Subscription.js +123 -0
- package/dist/Subscription.js.map +1 -0
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/package.json +55 -3
- package/src/Client.ts +53 -0
- package/src/Command.ts +456 -0
- package/src/PaginatedQuery.ts +1066 -0
- package/src/Subscription.ts +340 -0
- package/src/index.ts +4 -0
|
@@ -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 };
|
package/dist/index.d.ts
ADDED
|
@@ -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": "
|
|
4
|
-
"
|
|
5
|
-
|
|
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";
|