syncorejs 0.2.2 → 0.2.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/dist/_vendor/cli/app.d.mts.map +1 -1
- package/dist/_vendor/cli/app.mjs +8 -5
- package/dist/_vendor/cli/app.mjs.map +1 -1
- package/dist/_vendor/cli/context.mjs.map +1 -1
- package/dist/_vendor/cli/dev-session.mjs.map +1 -1
- package/dist/_vendor/cli/doctor.mjs.map +1 -1
- package/dist/_vendor/cli/errors.mjs.map +1 -1
- package/dist/_vendor/cli/help.mjs.map +1 -1
- package/dist/_vendor/cli/index.mjs +9 -2
- package/dist/_vendor/cli/index.mjs.map +1 -1
- package/dist/_vendor/cli/messages.mjs.map +1 -1
- package/dist/_vendor/cli/preflight.mjs.map +1 -1
- package/dist/_vendor/cli/project.mjs +20 -20
- package/dist/_vendor/cli/project.mjs.map +1 -1
- package/dist/_vendor/cli/render.mjs.map +1 -1
- package/dist/_vendor/cli/targets.mjs.map +1 -1
- package/dist/_vendor/core/cli.d.mts +8 -2
- package/dist/_vendor/core/cli.d.mts.map +1 -1
- package/dist/_vendor/core/cli.mjs +238 -64
- package/dist/_vendor/core/cli.mjs.map +1 -1
- package/dist/_vendor/core/devtools-auth.mjs.map +1 -1
- package/dist/_vendor/core/runtime/components.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/components.mjs.map +1 -1
- package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/devtools.mjs +130 -23
- package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
- package/dist/_vendor/core/runtime/functions.d.mts +388 -6
- package/dist/_vendor/core/runtime/functions.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/functions.mjs +72 -1
- package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
- package/dist/_vendor/core/runtime/id.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/id.mjs.map +1 -1
- package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs +11 -5
- package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs.map +1 -1
- package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs +123 -20
- package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs.map +1 -1
- package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs +56 -8
- package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs.map +1 -1
- package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs +49 -14
- package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs.map +1 -1
- package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs +4 -7
- package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs.map +1 -1
- package/dist/_vendor/core/runtime/internal/engines/shared.mjs +76 -1
- package/dist/_vendor/core/runtime/internal/engines/shared.mjs.map +1 -1
- package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs +1 -0
- package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs.map +1 -1
- package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs +4 -3
- package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs.map +1 -1
- package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs.map +1 -1
- package/dist/_vendor/core/runtime/internal/systemMeta.mjs.map +1 -1
- package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs +4 -0
- package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs.map +1 -1
- package/dist/_vendor/core/runtime/runtime.d.mts +1040 -9
- package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/runtime.mjs +63 -0
- package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
- package/dist/_vendor/core/transport.d.mts +2 -0
- package/dist/_vendor/core/transport.d.mts.map +1 -1
- package/dist/_vendor/core/transport.mjs +33 -24
- package/dist/_vendor/core/transport.mjs.map +1 -1
- package/dist/_vendor/devtools-protocol/index.d.ts +149 -4
- package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
- package/dist/_vendor/devtools-protocol/index.js.map +1 -1
- package/dist/_vendor/next/config.d.ts +3 -4
- package/dist/_vendor/next/config.d.ts.map +1 -1
- package/dist/_vendor/next/config.js +37 -19
- package/dist/_vendor/next/config.js.map +1 -1
- package/dist/_vendor/next/index.d.ts +109 -29
- package/dist/_vendor/next/index.d.ts.map +1 -1
- package/dist/_vendor/next/index.js +77 -17
- package/dist/_vendor/next/index.js.map +1 -1
- package/dist/_vendor/platform-expo/index.d.ts +146 -27
- package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
- package/dist/_vendor/platform-expo/index.js +76 -10
- package/dist/_vendor/platform-expo/index.js.map +1 -1
- package/dist/_vendor/platform-expo/react.js.map +1 -1
- package/dist/_vendor/platform-expo/web-sqljs-wasm.js +16 -0
- package/dist/_vendor/platform-expo/web-sqljs-wasm.js.map +1 -0
- package/dist/_vendor/platform-node/index.d.mts +173 -9
- package/dist/_vendor/platform-node/index.d.mts.map +1 -1
- package/dist/_vendor/platform-node/index.mjs +225 -94
- package/dist/_vendor/platform-node/index.mjs.map +1 -1
- package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
- package/dist/_vendor/platform-node/ipc.d.mts.map +1 -1
- package/dist/_vendor/platform-node/ipc.mjs.map +1 -1
- package/dist/_vendor/platform-web/external-change.d.ts +41 -0
- package/dist/_vendor/platform-web/external-change.d.ts.map +1 -1
- package/dist/_vendor/platform-web/external-change.js +30 -0
- package/dist/_vendor/platform-web/external-change.js.map +1 -1
- package/dist/_vendor/platform-web/index.d.ts +307 -35
- package/dist/_vendor/platform-web/index.d.ts.map +1 -1
- package/dist/_vendor/platform-web/index.js +189 -23
- package/dist/_vendor/platform-web/index.js.map +1 -1
- package/dist/_vendor/platform-web/indexeddb.d.ts +12 -0
- package/dist/_vendor/platform-web/indexeddb.d.ts.map +1 -1
- package/dist/_vendor/platform-web/indexeddb.js +10 -0
- package/dist/_vendor/platform-web/indexeddb.js.map +1 -1
- package/dist/_vendor/platform-web/opfs.d.ts +13 -0
- package/dist/_vendor/platform-web/opfs.d.ts.map +1 -1
- package/dist/_vendor/platform-web/opfs.js +12 -0
- package/dist/_vendor/platform-web/opfs.js.map +1 -1
- package/dist/_vendor/platform-web/persistence.d.ts +54 -0
- package/dist/_vendor/platform-web/persistence.d.ts.map +1 -1
- package/dist/_vendor/platform-web/persistence.js +15 -0
- package/dist/_vendor/platform-web/persistence.js.map +1 -1
- package/dist/_vendor/platform-web/react.d.ts +1 -2
- package/dist/_vendor/platform-web/react.d.ts.map +1 -1
- package/dist/_vendor/platform-web/react.js +2 -4
- package/dist/_vendor/platform-web/react.js.map +1 -1
- package/dist/_vendor/platform-web/sqljs.js +10 -1
- package/dist/_vendor/platform-web/sqljs.js.map +1 -1
- package/dist/_vendor/platform-web/web-sqljs-wasm.js +8 -0
- package/dist/_vendor/platform-web/web-sqljs-wasm.js.map +1 -0
- package/dist/_vendor/platform-web/worker.d.ts +60 -9
- package/dist/_vendor/platform-web/worker.d.ts.map +1 -1
- package/dist/_vendor/platform-web/worker.js +37 -4
- package/dist/_vendor/platform-web/worker.js.map +1 -1
- package/dist/_vendor/react/index.d.ts +196 -13
- package/dist/_vendor/react/index.d.ts.map +1 -1
- package/dist/_vendor/react/index.js +208 -17
- package/dist/_vendor/react/index.js.map +1 -1
- package/dist/_vendor/schema/definition.d.ts +129 -0
- package/dist/_vendor/schema/definition.d.ts.map +1 -1
- package/dist/_vendor/schema/definition.js +99 -0
- package/dist/_vendor/schema/definition.js.map +1 -1
- package/dist/_vendor/schema/planner.d.ts.map +1 -1
- package/dist/_vendor/schema/planner.js.map +1 -1
- package/dist/_vendor/schema/validators.d.ts +180 -4
- package/dist/_vendor/schema/validators.d.ts.map +1 -1
- package/dist/_vendor/schema/validators.js +35 -1
- package/dist/_vendor/schema/validators.js.map +1 -1
- package/dist/_vendor/svelte/index.d.ts +205 -7
- package/dist/_vendor/svelte/index.d.ts.map +1 -1
- package/dist/_vendor/svelte/index.js +199 -6
- package/dist/_vendor/svelte/index.js.map +1 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/package.json +24 -21
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
import { SyncoreBridgeClient, attachRuntimeBridge } from "../core/index.mjs";
|
|
2
2
|
//#region src/worker.ts
|
|
3
|
+
/**
|
|
4
|
+
* Syncore client that communicates with a runtime running in a browser Worker
|
|
5
|
+
* over the `postMessage` bridge.
|
|
6
|
+
*
|
|
7
|
+
* Use `createSyncoreWebWorkerClient()` or `createManagedWebWorkerClient()` to
|
|
8
|
+
* create instances. Prefer the React hooks (`useQuery`, `useMutation`, etc.)
|
|
9
|
+
* over calling this directly in React apps.
|
|
10
|
+
*/
|
|
3
11
|
var SyncoreWebWorkerClient = class extends SyncoreBridgeClient {};
|
|
4
12
|
/**
|
|
5
|
-
* Create a
|
|
13
|
+
* Create a {@link SyncoreWebWorkerClient} from a low-level message endpoint.
|
|
14
|
+
*
|
|
15
|
+
* Use this when you already have a `Worker` or `MessagePort` reference and
|
|
16
|
+
* want to wrap it manually. For the common case of spawning a new Worker from
|
|
17
|
+
* a URL, use `createSyncoreWebWorkerClient` instead.
|
|
6
18
|
*/
|
|
7
19
|
function createWebWorkerClient(endpoint) {
|
|
8
20
|
return new SyncoreWebWorkerClient(endpoint);
|
|
9
21
|
}
|
|
10
22
|
/**
|
|
11
|
-
* Create
|
|
23
|
+
* Create a {@link ManagedWebWorkerClient} using a provided Worker factory.
|
|
24
|
+
*
|
|
25
|
+
* Useful when you need control over how the Worker is constructed (e.g. to
|
|
26
|
+
* pass constructor options not exposed by `CreateWebWorkerClientProviderOptions`).
|
|
27
|
+
* For the common URL-based case, use `createSyncoreWebWorkerClient`.
|
|
12
28
|
*/
|
|
13
29
|
function createManagedWebWorkerClient(options) {
|
|
14
30
|
const worker = options.createWorker();
|
|
@@ -23,7 +39,21 @@ function createManagedWebWorkerClient(options) {
|
|
|
23
39
|
};
|
|
24
40
|
}
|
|
25
41
|
/**
|
|
26
|
-
* Create a
|
|
42
|
+
* Create a {@link ManagedWebWorkerClient} by spawning a new Worker from a URL.
|
|
43
|
+
*
|
|
44
|
+
* This is the standard way to create a main-thread client in a browser app.
|
|
45
|
+
* Pass the URL of your `syncore.worker.ts` file (which calls
|
|
46
|
+
* `createWebWorkerRuntime`) and connect the returned `client` to your React
|
|
47
|
+
* `SyncoreProvider` or Svelte context.
|
|
48
|
+
*
|
|
49
|
+
* ```ts
|
|
50
|
+
* // main.ts (or React root)
|
|
51
|
+
* import { createSyncoreWebWorkerClient } from "syncorejs/browser";
|
|
52
|
+
*
|
|
53
|
+
* const { client, dispose } = createSyncoreWebWorkerClient({
|
|
54
|
+
* workerUrl: new URL("./syncore.worker.ts", import.meta.url),
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
27
57
|
*/
|
|
28
58
|
function createSyncoreWebWorkerClient(options) {
|
|
29
59
|
return createManagedWebWorkerClient({ createWorker: () => new Worker(options.workerUrl, {
|
|
@@ -32,7 +62,10 @@ function createSyncoreWebWorkerClient(options) {
|
|
|
32
62
|
}) });
|
|
33
63
|
}
|
|
34
64
|
/**
|
|
35
|
-
*
|
|
65
|
+
* Wire a Syncore runtime factory to a worker message endpoint.
|
|
66
|
+
*
|
|
67
|
+
* Called internally by `createWebWorkerRuntime`. Exposed for cases where you
|
|
68
|
+
* need to attach a runtime to a custom bridge endpoint (e.g. a `MessagePort`).
|
|
36
69
|
*/
|
|
37
70
|
function attachWebWorkerRuntime(options) {
|
|
38
71
|
return attachRuntimeBridge(options);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.js","names":[],"sources":["../src/worker.ts"],"sourcesContent":["import {\n attachRuntimeBridge,\n type AttachRuntimeBridgeOptions,\n type AttachedRuntimeBridge,\n type BridgeQueryWatch,\n SyncoreBridgeClient,\n type SyncoreDataModel,\n type SyncoreBridgeMessageEndpoint,\n} from \"@syncore/core\";\n\nexport type WebWorkerSyncoreSchema<\n TSchema extends SyncoreDataModel = SyncoreDataModel\n> = TSchema;\nexport type SyncoreWorkerMessageEndpoint = SyncoreBridgeMessageEndpoint;\nexport type WorkerQueryWatch<TValue> = BridgeQueryWatch<TValue>;\n\nexport class SyncoreWebWorkerClient extends SyncoreBridgeClient {\n declare query: SyncoreBridgeClient[\"query\"];\n declare mutation: SyncoreBridgeClient[\"mutation\"];\n declare action: SyncoreBridgeClient[\"action\"];\n declare watchQuery: SyncoreBridgeClient[\"watchQuery\"];\n}\n\nexport type AttachWebWorkerRuntimeOptions<\n TSchema extends WebWorkerSyncoreSchema = WebWorkerSyncoreSchema\n> = AttachRuntimeBridgeOptions<TSchema>;\nexport type AttachedWebWorkerRuntime = AttachedRuntimeBridge;\n\n/**\n * A
|
|
1
|
+
{"version":3,"file":"worker.js","names":[],"sources":["../src/worker.ts"],"sourcesContent":["import {\n attachRuntimeBridge,\n type AttachRuntimeBridgeOptions,\n type AttachedRuntimeBridge,\n type BridgeQueryWatch,\n SyncoreBridgeClient,\n type SyncoreDataModel,\n type SyncoreBridgeMessageEndpoint,\n} from \"@syncore/core\";\n\n/**\n * Schema type constraint for worker-side Syncore runtimes.\n *\n * Pass any schema produced by `defineSchema()` where this type is expected.\n * Defaults to the unconstrained `SyncoreDataModel` when omitted.\n */\nexport type WebWorkerSyncoreSchema<\n TSchema extends SyncoreDataModel = SyncoreDataModel\n> = TSchema;\n/** Message endpoint shape required by the browser worker bridge (alias of `SyncoreBridgeMessageEndpoint`). */\nexport type SyncoreWorkerMessageEndpoint = SyncoreBridgeMessageEndpoint;\n/** Live-query subscription handle returned by `SyncoreWebWorkerClient.watchQuery`. */\nexport type WorkerQueryWatch<TValue> = BridgeQueryWatch<TValue>;\n\n/**\n * Syncore client that communicates with a runtime running in a browser Worker\n * over the `postMessage` bridge.\n *\n * Use `createSyncoreWebWorkerClient()` or `createManagedWebWorkerClient()` to\n * create instances. Prefer the React hooks (`useQuery`, `useMutation`, etc.)\n * over calling this directly in React apps.\n */\nexport class SyncoreWebWorkerClient extends SyncoreBridgeClient {\n declare query: SyncoreBridgeClient[\"query\"];\n declare mutation: SyncoreBridgeClient[\"mutation\"];\n declare action: SyncoreBridgeClient[\"action\"];\n declare watchQuery: SyncoreBridgeClient[\"watchQuery\"];\n}\n\n/** Options for attaching a runtime to a worker bridge endpoint. Alias of `AttachRuntimeBridgeOptions`. */\nexport type AttachWebWorkerRuntimeOptions<\n TSchema extends WebWorkerSyncoreSchema = WebWorkerSyncoreSchema\n> = AttachRuntimeBridgeOptions<TSchema>;\n/** Handle returned by `attachWebWorkerRuntime` for controlling the attached bridge. */\nexport type AttachedWebWorkerRuntime = AttachedRuntimeBridge;\n\n/**\n * A browser Worker and its associated Syncore client, bundled for easy\n * lifecycle management.\n *\n * Returned by `createSyncoreWebWorkerClient` and `createManagedWebWorkerClient`.\n * Call `dispose()` to terminate the worker and release its resources.\n */\nexport interface ManagedWebWorkerClient {\n /** The Syncore client connected to the worker. */\n client: SyncoreWebWorkerClient;\n /** The underlying `Worker` instance. Useful for low-level control. */\n worker: Worker;\n /** Terminate the worker and dispose the client. Call on app unmount or navigation. */\n dispose(): void;\n}\n\n/**\n * Options for creating a managed worker Syncore client via\n * `createSyncoreWebWorkerClient`.\n */\nexport interface CreateWebWorkerClientProviderOptions {\n /** The worker module URL passed to `new Worker(...)`. Typically an `import.meta.url`-relative `URL`. */\n workerUrl: URL | string;\n /** Worker module type. Defaults to `\"module\"` (ESM worker). */\n workerType?: WorkerOptions[\"type\"];\n /** Optional label shown in browser devtools’ Sources panel. */\n workerName?: string;\n}\n\n/**\n * Create a {@link SyncoreWebWorkerClient} from a low-level message endpoint.\n *\n * Use this when you already have a `Worker` or `MessagePort` reference and\n * want to wrap it manually. For the common case of spawning a new Worker from\n * a URL, use `createSyncoreWebWorkerClient` instead.\n */\nexport function createWebWorkerClient(\n endpoint: SyncoreWorkerMessageEndpoint\n): SyncoreWebWorkerClient {\n return new SyncoreWebWorkerClient(endpoint);\n}\n\n/**\n * Create a {@link ManagedWebWorkerClient} using a provided Worker factory.\n *\n * Useful when you need control over how the Worker is constructed (e.g. to\n * pass constructor options not exposed by `CreateWebWorkerClientProviderOptions`).\n * For the common URL-based case, use `createSyncoreWebWorkerClient`.\n */\nexport function createManagedWebWorkerClient(options: {\n createWorker: () => Worker;\n}): ManagedWebWorkerClient {\n const worker = options.createWorker();\n const client = createWebWorkerClient(worker);\n return {\n client,\n worker,\n dispose() {\n client.dispose();\n worker.terminate();\n }\n };\n}\n\n/**\n * Create a {@link ManagedWebWorkerClient} by spawning a new Worker from a URL.\n *\n * This is the standard way to create a main-thread client in a browser app.\n * Pass the URL of your `syncore.worker.ts` file (which calls\n * `createWebWorkerRuntime`) and connect the returned `client` to your React\n * `SyncoreProvider` or Svelte context.\n *\n * ```ts\n * // main.ts (or React root)\n * import { createSyncoreWebWorkerClient } from \"syncorejs/browser\";\n *\n * const { client, dispose } = createSyncoreWebWorkerClient({\n * workerUrl: new URL(\"./syncore.worker.ts\", import.meta.url),\n * });\n * ```\n */\nexport function createSyncoreWebWorkerClient(\n options: CreateWebWorkerClientProviderOptions\n): ManagedWebWorkerClient {\n return createManagedWebWorkerClient({\n createWorker: () =>\n new Worker(options.workerUrl, {\n type: options.workerType ?? \"module\",\n ...(options.workerName ? { name: options.workerName } : {})\n })\n });\n}\n\n/**\n * Wire a Syncore runtime factory to a worker message endpoint.\n *\n * Called internally by `createWebWorkerRuntime`. Exposed for cases where you\n * need to attach a runtime to a custom bridge endpoint (e.g. a `MessagePort`).\n */\nexport function attachWebWorkerRuntime(\n options: AttachWebWorkerRuntimeOptions\n): AttachedWebWorkerRuntime {\n return attachRuntimeBridge(options);\n}\n"],"mappings":";;;;;;;;;;AAgCA,IAAa,yBAAb,cAA4C,oBAAoB,CAKhE;;;;;;;;AA6CA,SAAgB,sBACd,UACwB;CACxB,OAAO,IAAI,uBAAuB,QAAQ;AAC5C;;;;;;;;AASA,SAAgB,6BAA6B,SAElB;CACzB,MAAM,SAAS,QAAQ,aAAa;CACpC,MAAM,SAAS,sBAAsB,MAAM;CAC3C,OAAO;EACL;EACA;EACA,UAAU;GACR,OAAO,QAAQ;GACf,OAAO,UAAU;EACnB;CACF;AACF;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,6BACd,SACwB;CACxB,OAAO,6BAA6B,EAClC,oBACE,IAAI,OAAO,QAAQ,WAAW;EAC5B,MAAM,QAAQ,cAAc;EAC5B,GAAI,QAAQ,aAAa,EAAE,MAAM,QAAQ,WAAW,IAAI,CAAC;CAC3D,CAAC,EACL,CAAC;AACH;;;;;;;AAQA,SAAgB,uBACd,SAC0B;CAC1B,OAAO,oBAAoB,OAAO;AACpC"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
|
-
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
2
|
import { FunctionArgs, FunctionReference, FunctionResult, PaginationOptions, PaginationResult, SyncoreClient, SyncoreQueryState, SyncoreRuntimeStatus, UsePaginatedQueryResult } from "../core/index.d.mts";
|
|
4
3
|
|
|
5
4
|
//#region src/index.d.ts
|
|
@@ -20,13 +19,46 @@ type PaginatedQueryArgs<TReference extends FunctionReference<"query">> = Functio
|
|
|
20
19
|
} ? Omit<FunctionArgs<TReference>, "paginationOpts"> : never;
|
|
21
20
|
type PaginatedQueryItem<TReference extends FunctionReference<"query">> = FunctionResult<TReference> extends PaginationResult<infer TItem> ? TItem : never;
|
|
22
21
|
/**
|
|
23
|
-
* Pass `
|
|
24
|
-
*
|
|
22
|
+
* Pass `skip` as the `args` argument to any Syncore React hook to suppress
|
|
23
|
+
* that subscription entirely.
|
|
24
|
+
*
|
|
25
|
+
* Useful when the query arguments depend on state that is not yet available
|
|
26
|
+
* (e.g. a selected item ID) — instead of conditionally calling the hook
|
|
27
|
+
* (which violates the Rules of Hooks), pass `skip` to deactivate it:
|
|
28
|
+
*
|
|
29
|
+
* ```tsx
|
|
30
|
+
* const task = useQuery(api.tasks.get, selectedId ? { id: selectedId } : skip);
|
|
31
|
+
* // task is `undefined` while selectedId is null/undefined
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* Skipped queries return `undefined` for `data`, `"skipped"` for `status`,
|
|
35
|
+
* and `false` for `isLoading`.
|
|
25
36
|
*/
|
|
26
37
|
declare const skip: "skip";
|
|
27
38
|
type Skip = typeof skip;
|
|
28
39
|
/**
|
|
29
|
-
*
|
|
40
|
+
* Provides a Syncore client to all React descendants via context.
|
|
41
|
+
*
|
|
42
|
+
* Wrap your app (or any subtree that uses Syncore hooks) with
|
|
43
|
+
* `SyncoreProvider`. All `useQuery`, `useMutation`, `useAction`, and
|
|
44
|
+
* `useQueries` calls inside the tree will automatically use the client you
|
|
45
|
+
* supply.
|
|
46
|
+
*
|
|
47
|
+
* ```tsx
|
|
48
|
+
* // For a browser worker setup
|
|
49
|
+
* const client = createBrowserWorkerClient();
|
|
50
|
+
*
|
|
51
|
+
* function App() {
|
|
52
|
+
* return (
|
|
53
|
+
* <SyncoreProvider client={client}>
|
|
54
|
+
* <TaskList />
|
|
55
|
+
* </SyncoreProvider>
|
|
56
|
+
* );
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* For Next.js apps use `SyncoreNextProvider` which also handles service worker
|
|
61
|
+
* and worker URL configuration.
|
|
30
62
|
*/
|
|
31
63
|
declare function SyncoreProvider({
|
|
32
64
|
client,
|
|
@@ -34,37 +66,188 @@ declare function SyncoreProvider({
|
|
|
34
66
|
}: {
|
|
35
67
|
client: SyncoreClient;
|
|
36
68
|
children: ReactNode;
|
|
37
|
-
}):
|
|
69
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
38
70
|
/**
|
|
39
|
-
*
|
|
71
|
+
* Returns the active `SyncoreClient` from the nearest {@link SyncoreProvider}
|
|
72
|
+
* in the React tree.
|
|
73
|
+
*
|
|
74
|
+
* Throws if called outside of a `SyncoreProvider`. Prefer the higher-level
|
|
75
|
+
* hooks (`useQuery`, `useMutation`, etc.) for common operations — use
|
|
76
|
+
* `useSyncore` only when you need direct access to the client object.
|
|
77
|
+
*
|
|
78
|
+
* ```ts
|
|
79
|
+
* const client = useSyncore();
|
|
80
|
+
* const tasks = await client.query(api.tasks.list);
|
|
81
|
+
* ```
|
|
40
82
|
*/
|
|
41
83
|
declare function useSyncore(): SyncoreClient;
|
|
42
84
|
/**
|
|
43
|
-
* Subscribe to the
|
|
85
|
+
* Subscribe to the runtime’s lifecycle status.
|
|
86
|
+
*
|
|
87
|
+
* Returns a {@link SyncoreRuntimeStatus} that updates whenever the underlying
|
|
88
|
+
* runtime changes state (e.g. starting, ready, error). Use it to gate your UI
|
|
89
|
+
* on the runtime being ready or to display an error boundary:
|
|
90
|
+
*
|
|
91
|
+
* ```tsx
|
|
92
|
+
* function TaskList() {
|
|
93
|
+
* const status = useSyncoreStatus();
|
|
94
|
+
* if (status.kind === "starting") return <Spinner />;
|
|
95
|
+
* if (status.kind === "error") return <ErrorScreen error={status.error} />;
|
|
96
|
+
* return <Tasks />;
|
|
97
|
+
* }
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* Most components do not need this — `useQuery` already incorporates runtime
|
|
101
|
+
* status into the `SyncoreQueryState.runtimeStatus` field.
|
|
44
102
|
*/
|
|
45
103
|
declare function useSyncoreStatus(): SyncoreRuntimeStatus;
|
|
46
104
|
/**
|
|
47
|
-
*
|
|
105
|
+
* Subscribe to a reactive Syncore query and return the current data.
|
|
106
|
+
*
|
|
107
|
+
* The component re-renders automatically whenever the query result changes.
|
|
108
|
+
* If the query throws, `useQuery` re-throws the error so a React error
|
|
109
|
+
* boundary can catch it — use {@link useQueryState} if you need to handle
|
|
110
|
+
* errors inline.
|
|
111
|
+
*
|
|
112
|
+
* ```tsx
|
|
113
|
+
* // Basic usage
|
|
114
|
+
* const tasks = useQuery(api.tasks.list);
|
|
115
|
+
*
|
|
116
|
+
* // With arguments
|
|
117
|
+
* const task = useQuery(api.tasks.get, { id: taskId });
|
|
118
|
+
*
|
|
119
|
+
* // Conditionally skip when arguments are not yet available
|
|
120
|
+
* const task = useQuery(api.tasks.get, taskId ? { id: taskId } : skip);
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* @param reference - A typed function reference (from the generated `api` object).
|
|
124
|
+
* @param args - The query’s arguments, or `skip` to suppress the subscription.
|
|
125
|
+
* @returns The current query result, or `undefined` while loading.
|
|
48
126
|
*/
|
|
49
127
|
declare function useQuery<TArgs, TResult>(reference: FunctionReference<"query", TArgs, TResult>, ...args: OptionalArgsTuple<TArgs> | [Skip]): TResult | undefined;
|
|
50
128
|
/**
|
|
51
|
-
*
|
|
129
|
+
* Subscribe to a reactive Syncore query and return the full
|
|
130
|
+
* {@link SyncoreQueryState} including loading, error, and runtime status.
|
|
131
|
+
*
|
|
132
|
+
* Use this instead of {@link useQuery} when you need to:
|
|
133
|
+
* - Differentiate between `undefined` data and an error.
|
|
134
|
+
* - React to `isLoading` / `isError` without relying on error boundaries.
|
|
135
|
+
* - Inspect `runtimeStatus` for the underlying runtime’s health.
|
|
136
|
+
*
|
|
137
|
+
* ```tsx
|
|
138
|
+
* const { data, isLoading, isError, error } = useQueryState(api.tasks.list);
|
|
139
|
+
*
|
|
140
|
+
* if (isLoading) return <Spinner />;
|
|
141
|
+
* if (isError) return <ErrorBanner message={error.message} />;
|
|
142
|
+
* return <TaskList tasks={data} />;
|
|
143
|
+
* ```
|
|
52
144
|
*/
|
|
53
145
|
declare function useQueryState<TArgs, TResult>(reference: FunctionReference<"query", TArgs, TResult>, ...args: OptionalArgsTuple<TArgs> | [Skip]): SyncoreQueryState<TResult>;
|
|
54
146
|
/**
|
|
55
|
-
*
|
|
147
|
+
* Returns a stable callback for executing a Syncore mutation.
|
|
148
|
+
*
|
|
149
|
+
* The returned function is type-safe: its parameter types are inferred from
|
|
150
|
+
* the mutation definition and remain stable across re-renders (no need to
|
|
151
|
+
* wrap in `useCallback`).
|
|
152
|
+
*
|
|
153
|
+
* ```tsx
|
|
154
|
+
* const createTask = useMutation(api.tasks.create);
|
|
155
|
+
*
|
|
156
|
+
* return (
|
|
157
|
+
* <button onClick={() => createTask({ title: "New task" })}>
|
|
158
|
+
* Add task
|
|
159
|
+
* </button>
|
|
160
|
+
* );
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
* @param reference - A typed mutation reference from the generated `api` object.
|
|
164
|
+
* @returns A function that, when called, executes the mutation and returns a
|
|
165
|
+
* promise that resolves to the mutation’s return value.
|
|
56
166
|
*/
|
|
57
167
|
declare function useMutation<TArgs, TResult>(reference: FunctionReference<"mutation", TArgs, TResult>): (...args: OptionalArgsTuple<TArgs>) => Promise<TResult>;
|
|
58
168
|
/**
|
|
59
|
-
*
|
|
169
|
+
* Returns a stable callback for executing a Syncore action.
|
|
170
|
+
*
|
|
171
|
+
* Identical to {@link useMutation} but for actions. Use this when the work you
|
|
172
|
+
* need to do cannot run inside a transaction (external API calls, long-running
|
|
173
|
+
* tasks, etc.).
|
|
174
|
+
*
|
|
175
|
+
* ```tsx
|
|
176
|
+
* const importTasks = useAction(api.tasks.importFromCsv);
|
|
177
|
+
*
|
|
178
|
+
* return (
|
|
179
|
+
* <button onClick={() => importTasks({ url: csvUrl })}>
|
|
180
|
+
* Import
|
|
181
|
+
* </button>
|
|
182
|
+
* );
|
|
183
|
+
* ```
|
|
184
|
+
*
|
|
185
|
+
* @param reference - A typed action reference from the generated `api` object.
|
|
186
|
+
* @returns A function that, when called, executes the action and returns a
|
|
187
|
+
* promise that resolves to the action’s return value.
|
|
60
188
|
*/
|
|
61
189
|
declare function useAction<TArgs, TResult>(reference: FunctionReference<"action", TArgs, TResult>): (...args: OptionalArgsTuple<TArgs>) => Promise<TResult>;
|
|
62
190
|
/**
|
|
63
|
-
*
|
|
191
|
+
* Subscribe to multiple Syncore queries simultaneously and receive per-entry
|
|
192
|
+
* state objects in a single hook call.
|
|
193
|
+
*
|
|
194
|
+
* More efficient than calling `useQuery` in a loop when the set of queries is
|
|
195
|
+
* known at component render time. The hook maintains only one subscription per
|
|
196
|
+
* unique `(reference, args)` combination even if entries are duplicated.
|
|
197
|
+
*
|
|
198
|
+
* ```tsx
|
|
199
|
+
* const { header, sidebar } = useQueries({
|
|
200
|
+
* header: { query: api.layout.header },
|
|
201
|
+
* sidebar: { query: api.layout.sidebar, args: { userId } },
|
|
202
|
+
* });
|
|
203
|
+
*
|
|
204
|
+
* if (header.isLoading || sidebar.isLoading) return <Spinner />;
|
|
205
|
+
* ```
|
|
206
|
+
*
|
|
207
|
+
* @param entries - A record of named query requests. Each entry can include
|
|
208
|
+
* `args: skip` to suppress that specific subscription.
|
|
209
|
+
* @returns A record with the same keys, each holding a {@link SyncoreQueryState}.
|
|
64
210
|
*/
|
|
65
211
|
declare function useQueries<TEntries extends QueriesRequestInput>(entries: TEntries): UseQueriesResult<TEntries>;
|
|
66
212
|
/**
|
|
67
|
-
*
|
|
213
|
+
* Subscribe to a paginated Syncore query, incrementally loading more pages.
|
|
214
|
+
*
|
|
215
|
+
* The query must accept a `paginationOpts` argument and return a
|
|
216
|
+
* `PaginationResult`. The hook manages cursors automatically — call the
|
|
217
|
+
* returned `loadMore` function to append the next page to the results.
|
|
218
|
+
*
|
|
219
|
+
* ```tsx
|
|
220
|
+
* const { results, status, loadMore, hasMore } = usePaginatedQuery(
|
|
221
|
+
* api.tasks.list,
|
|
222
|
+
* { projectId },
|
|
223
|
+
* { initialNumItems: 20 },
|
|
224
|
+
* );
|
|
225
|
+
*
|
|
226
|
+
* return (
|
|
227
|
+
* <>
|
|
228
|
+
* {results.map((t) => <TaskRow key={t._id} task={t} />)}
|
|
229
|
+
* {hasMore && (
|
|
230
|
+
* <button
|
|
231
|
+
* onClick={() => loadMore(20)}
|
|
232
|
+
* disabled={status === "loadingMore"}
|
|
233
|
+
* >
|
|
234
|
+
* Load more
|
|
235
|
+
* </button>
|
|
236
|
+
* )}
|
|
237
|
+
* </>
|
|
238
|
+
* );
|
|
239
|
+
* ```
|
|
240
|
+
*
|
|
241
|
+
* Pass `skip` as `args` to suppress the subscription until arguments are
|
|
242
|
+
* ready.
|
|
243
|
+
*
|
|
244
|
+
* @param reference - A typed query reference whose handler calls
|
|
245
|
+
* `ctx.db.query(…).paginate(paginationOpts)`.
|
|
246
|
+
* @param args - Arguments for the query (excluding
|
|
247
|
+
* `paginationOpts`, which is managed internally), or `skip`.
|
|
248
|
+
* @param options.initialNumItems - Number of items to load on the first page.
|
|
249
|
+
* @returns A {@link UsePaginatedQueryResult} with the accumulated results and
|
|
250
|
+
* a `loadMore` callback.
|
|
68
251
|
*/
|
|
69
252
|
declare function usePaginatedQuery<TReference extends PaginatedQueryReference>(reference: TReference, args: PaginatedQueryArgs<TReference> | Skip, options: {
|
|
70
253
|
initialNumItems: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":";;;;KA0BK,iBAAA,UACH,MAAA,uBAA6B,KAAA,IAAS,IAAA,GAAO,KAAA,KAAU,IAAA,EAAM,KAAA;AAAA,KAE1D,iBAAA,oBACgB,iBAAA,YAA6B,iBAAA,aAC9C,MAAA,uBAA6B,YAAA,CAAa,UAAA;EAExC,KAAA,EAAO,UAAA;EACP,IAAA,GAAO,YAAA,CAAa,UAAA,IAAc,IAAA;AAAA;EAGlC,KAAA,EAAO,UAAA;EACP,IAAA,EAAM,YAAA,CAAa,UAAA,IAAc,IAAA;AAAA;AAAA,KAGlC,mBAAA,GAAsB,MAAM,SAAS,iBAAA;AAAA,KAErC,kBAAA,WAA6B,MAAA,SAAe,iBAAA,qBAG7C,iBAAA,CAAkB,cAAA,CAAe,UAAA;AAAA,KAGzB,gBAAA,kBAAkC,mBAAA,qBAC7B,QAAA,GAAW,kBAAA,CAAmB,QAAA,CAAS,IAAA;AAAA,KAGnD,uBAAA,GAA0B,iBAAA,UAE7B,MAAA,mBACA,gBAAA;AAAA,KAGG,kBAAA,oBAAsC,iBAAA,aACzC,YAAA,CAAa,UAAA;EAAsB,cAAA,EAAgB,iBAAA;AAAA,IAC/C,IAAA,CAAK,YAAA,CAAa,UAAA;AAAA,KAGnB,kBAAA,oBAAsC,iBAAA,aACzC,cAAA,CAAe,UAAA,UAAoB,gBAAA,gBAC/B,KAAA;;AAvC8D;AAAA;;;;;;;;;;;;;;cAuFvD,IAAA;AAAA,KACR,IAAA,UAAc,IAAI;;;;;;;;;;;;;;;;;;;;;;AA7EoB;AAAA;;iBA8G3B,eAAA,CAAA;EACd,MAAA;EACA;AAAA;EAEA,MAAA,EAAQ,aAAA;EACR,QAAA,EAAU,SAAA;AAAA,gCACX,GAAA,CAAA,OAAA;;;;;;;;;;;;;;iBAmBe,UAAA,CAAA,GAAc,aAAa;;;;AA/HI;AAG/C;;;;;;;;;;;;;;;iBAuJgB,gBAAA,CAAA,GAAoB,oBAAoB;;;AAtJI;AAC1D;;;;;;;;;;;;AAKgB;AAAA;;;;;;;iBAmMF,QAAA,gBAAA,CACd,SAAA,EAAW,iBAAA,UAA2B,KAAA,EAAO,OAAA,MAC1C,IAAA,EAAM,iBAAA,CAAkB,KAAA,KAAU,IAAA,IACpC,OAAA;;;;;;;;;;;;;;;AAjM+B;AAAA;;iBA0NlB,aAAA,gBAAA,CACd,SAAA,EAAW,iBAAA,UAA2B,KAAA,EAAO,OAAA,MAC1C,IAAA,EAAM,iBAAA,CAAkB,KAAA,KAAU,IAAA,IACpC,iBAAA,CAAkB,OAAA;;;;;;;;;;;;;;;AAxNV;AAgDX;;;;AAAmC;AAAC;iBA4NpB,WAAA,gBAAA,CACd,SAAA,EAAW,iBAAA,aAA8B,KAAA,EAAO,OAAA,QAC3C,IAAA,EAAM,iBAAA,CAAkB,KAAA,MAAW,OAAA,CAAQ,OAAA;;;AA7N3B;AAiCvB;;;;;;;;;;;;;;;;;;iBAsNgB,SAAA,gBAAA,CACd,SAAA,EAAW,iBAAA,WAA4B,KAAA,EAAO,OAAA,QACzC,IAAA,EAAM,iBAAA,CAAkB,KAAA,MAAW,OAAA,CAAQ,OAAA;;AAlNjD;AAmBD;;;;AAA2C;AA2B3C;;;;AAAwD;AAmDxD;;;;;;;;;iBA2IgB,UAAA,kBAA4B,mBAAA,CAAA,CAC1C,OAAA,EAAS,QAAA,GACR,gBAAA,CAAiB,QAAA;;;;;;;;;;;;;;;AA1IV;AAyBV;;;;;;;;;;;;;;;;;;;;;;;;;iBA8MgB,iBAAA,oBAAqC,uBAAA,CAAA,CACnD,SAAA,EAAW,UAAA,EACX,IAAA,EAAM,kBAAA,CAAmB,UAAA,IAAc,IAAA,EACvC,OAAA;EACE,eAAA;AAAA,IAED,uBAAA,CAAwB,kBAAA,CAAmB,UAAA"}
|
|
@@ -2,8 +2,20 @@ import { createContext, useContext, useEffect, useMemo, useState } from "react";
|
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
//#region src/index.tsx
|
|
4
4
|
/**
|
|
5
|
-
* Pass `
|
|
6
|
-
*
|
|
5
|
+
* Pass `skip` as the `args` argument to any Syncore React hook to suppress
|
|
6
|
+
* that subscription entirely.
|
|
7
|
+
*
|
|
8
|
+
* Useful when the query arguments depend on state that is not yet available
|
|
9
|
+
* (e.g. a selected item ID) — instead of conditionally calling the hook
|
|
10
|
+
* (which violates the Rules of Hooks), pass `skip` to deactivate it:
|
|
11
|
+
*
|
|
12
|
+
* ```tsx
|
|
13
|
+
* const task = useQuery(api.tasks.get, selectedId ? { id: selectedId } : skip);
|
|
14
|
+
* // task is `undefined` while selectedId is null/undefined
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Skipped queries return `undefined` for `data`, `"skipped"` for `status`,
|
|
18
|
+
* and `false` for `isLoading`.
|
|
7
19
|
*/
|
|
8
20
|
const skip = "skip";
|
|
9
21
|
const defaultRuntimeStatus = {
|
|
@@ -12,7 +24,28 @@ const defaultRuntimeStatus = {
|
|
|
12
24
|
};
|
|
13
25
|
const SyncoreContext = createContext(null);
|
|
14
26
|
/**
|
|
15
|
-
*
|
|
27
|
+
* Provides a Syncore client to all React descendants via context.
|
|
28
|
+
*
|
|
29
|
+
* Wrap your app (or any subtree that uses Syncore hooks) with
|
|
30
|
+
* `SyncoreProvider`. All `useQuery`, `useMutation`, `useAction`, and
|
|
31
|
+
* `useQueries` calls inside the tree will automatically use the client you
|
|
32
|
+
* supply.
|
|
33
|
+
*
|
|
34
|
+
* ```tsx
|
|
35
|
+
* // For a browser worker setup
|
|
36
|
+
* const client = createBrowserWorkerClient();
|
|
37
|
+
*
|
|
38
|
+
* function App() {
|
|
39
|
+
* return (
|
|
40
|
+
* <SyncoreProvider client={client}>
|
|
41
|
+
* <TaskList />
|
|
42
|
+
* </SyncoreProvider>
|
|
43
|
+
* );
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* For Next.js apps use `SyncoreNextProvider` which also handles service worker
|
|
48
|
+
* and worker URL configuration.
|
|
16
49
|
*/
|
|
17
50
|
function SyncoreProvider({ client, children }) {
|
|
18
51
|
return /* @__PURE__ */ jsx(SyncoreContext.Provider, {
|
|
@@ -21,7 +54,17 @@ function SyncoreProvider({ client, children }) {
|
|
|
21
54
|
});
|
|
22
55
|
}
|
|
23
56
|
/**
|
|
24
|
-
*
|
|
57
|
+
* Returns the active `SyncoreClient` from the nearest {@link SyncoreProvider}
|
|
58
|
+
* in the React tree.
|
|
59
|
+
*
|
|
60
|
+
* Throws if called outside of a `SyncoreProvider`. Prefer the higher-level
|
|
61
|
+
* hooks (`useQuery`, `useMutation`, etc.) for common operations — use
|
|
62
|
+
* `useSyncore` only when you need direct access to the client object.
|
|
63
|
+
*
|
|
64
|
+
* ```ts
|
|
65
|
+
* const client = useSyncore();
|
|
66
|
+
* const tasks = await client.query(api.tasks.list);
|
|
67
|
+
* ```
|
|
25
68
|
*/
|
|
26
69
|
function useSyncore() {
|
|
27
70
|
const client = useContext(SyncoreContext);
|
|
@@ -29,7 +72,23 @@ function useSyncore() {
|
|
|
29
72
|
return client;
|
|
30
73
|
}
|
|
31
74
|
/**
|
|
32
|
-
* Subscribe to the
|
|
75
|
+
* Subscribe to the runtime’s lifecycle status.
|
|
76
|
+
*
|
|
77
|
+
* Returns a {@link SyncoreRuntimeStatus} that updates whenever the underlying
|
|
78
|
+
* runtime changes state (e.g. starting, ready, error). Use it to gate your UI
|
|
79
|
+
* on the runtime being ready or to display an error boundary:
|
|
80
|
+
*
|
|
81
|
+
* ```tsx
|
|
82
|
+
* function TaskList() {
|
|
83
|
+
* const status = useSyncoreStatus();
|
|
84
|
+
* if (status.kind === "starting") return <Spinner />;
|
|
85
|
+
* if (status.kind === "error") return <ErrorScreen error={status.error} />;
|
|
86
|
+
* return <Tasks />;
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* Most components do not need this — `useQuery` already incorporates runtime
|
|
91
|
+
* status into the `SyncoreQueryState.runtimeStatus` field.
|
|
33
92
|
*/
|
|
34
93
|
function useSyncoreStatus() {
|
|
35
94
|
const client = useSyncore();
|
|
@@ -48,7 +107,27 @@ function useSyncoreStatus() {
|
|
|
48
107
|
return status;
|
|
49
108
|
}
|
|
50
109
|
/**
|
|
51
|
-
*
|
|
110
|
+
* Subscribe to a reactive Syncore query and return the current data.
|
|
111
|
+
*
|
|
112
|
+
* The component re-renders automatically whenever the query result changes.
|
|
113
|
+
* If the query throws, `useQuery` re-throws the error so a React error
|
|
114
|
+
* boundary can catch it — use {@link useQueryState} if you need to handle
|
|
115
|
+
* errors inline.
|
|
116
|
+
*
|
|
117
|
+
* ```tsx
|
|
118
|
+
* // Basic usage
|
|
119
|
+
* const tasks = useQuery(api.tasks.list);
|
|
120
|
+
*
|
|
121
|
+
* // With arguments
|
|
122
|
+
* const task = useQuery(api.tasks.get, { id: taskId });
|
|
123
|
+
*
|
|
124
|
+
* // Conditionally skip when arguments are not yet available
|
|
125
|
+
* const task = useQuery(api.tasks.get, taskId ? { id: taskId } : skip);
|
|
126
|
+
* ```
|
|
127
|
+
*
|
|
128
|
+
* @param reference - A typed function reference (from the generated `api` object).
|
|
129
|
+
* @param args - The query’s arguments, or `skip` to suppress the subscription.
|
|
130
|
+
* @returns The current query result, or `undefined` while loading.
|
|
52
131
|
*/
|
|
53
132
|
function useQuery(reference, ...args) {
|
|
54
133
|
const state = useQueryState(reference, ...args);
|
|
@@ -56,7 +135,21 @@ function useQuery(reference, ...args) {
|
|
|
56
135
|
return state.data;
|
|
57
136
|
}
|
|
58
137
|
/**
|
|
59
|
-
*
|
|
138
|
+
* Subscribe to a reactive Syncore query and return the full
|
|
139
|
+
* {@link SyncoreQueryState} including loading, error, and runtime status.
|
|
140
|
+
*
|
|
141
|
+
* Use this instead of {@link useQuery} when you need to:
|
|
142
|
+
* - Differentiate between `undefined` data and an error.
|
|
143
|
+
* - React to `isLoading` / `isError` without relying on error boundaries.
|
|
144
|
+
* - Inspect `runtimeStatus` for the underlying runtime’s health.
|
|
145
|
+
*
|
|
146
|
+
* ```tsx
|
|
147
|
+
* const { data, isLoading, isError, error } = useQueryState(api.tasks.list);
|
|
148
|
+
*
|
|
149
|
+
* if (isLoading) return <Spinner />;
|
|
150
|
+
* if (isError) return <ErrorBanner message={error.message} />;
|
|
151
|
+
* return <TaskList tasks={data} />;
|
|
152
|
+
* ```
|
|
60
153
|
*/
|
|
61
154
|
function useQueryState(reference, ...args) {
|
|
62
155
|
const isSkipped = args[0] === skip;
|
|
@@ -78,21 +171,75 @@ function useQueryState(reference, ...args) {
|
|
|
78
171
|
return toQueryState(snapshot, runtimeStatus, isSkipped);
|
|
79
172
|
}
|
|
80
173
|
/**
|
|
81
|
-
*
|
|
174
|
+
* Returns a stable callback for executing a Syncore mutation.
|
|
175
|
+
*
|
|
176
|
+
* The returned function is type-safe: its parameter types are inferred from
|
|
177
|
+
* the mutation definition and remain stable across re-renders (no need to
|
|
178
|
+
* wrap in `useCallback`).
|
|
179
|
+
*
|
|
180
|
+
* ```tsx
|
|
181
|
+
* const createTask = useMutation(api.tasks.create);
|
|
182
|
+
*
|
|
183
|
+
* return (
|
|
184
|
+
* <button onClick={() => createTask({ title: "New task" })}>
|
|
185
|
+
* Add task
|
|
186
|
+
* </button>
|
|
187
|
+
* );
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
* @param reference - A typed mutation reference from the generated `api` object.
|
|
191
|
+
* @returns A function that, when called, executes the mutation and returns a
|
|
192
|
+
* promise that resolves to the mutation’s return value.
|
|
82
193
|
*/
|
|
83
194
|
function useMutation(reference) {
|
|
84
195
|
const client = useSyncore();
|
|
85
196
|
return (...args) => client.mutation(reference, normalizeOptionalArgs(args));
|
|
86
197
|
}
|
|
87
198
|
/**
|
|
88
|
-
*
|
|
199
|
+
* Returns a stable callback for executing a Syncore action.
|
|
200
|
+
*
|
|
201
|
+
* Identical to {@link useMutation} but for actions. Use this when the work you
|
|
202
|
+
* need to do cannot run inside a transaction (external API calls, long-running
|
|
203
|
+
* tasks, etc.).
|
|
204
|
+
*
|
|
205
|
+
* ```tsx
|
|
206
|
+
* const importTasks = useAction(api.tasks.importFromCsv);
|
|
207
|
+
*
|
|
208
|
+
* return (
|
|
209
|
+
* <button onClick={() => importTasks({ url: csvUrl })}>
|
|
210
|
+
* Import
|
|
211
|
+
* </button>
|
|
212
|
+
* );
|
|
213
|
+
* ```
|
|
214
|
+
*
|
|
215
|
+
* @param reference - A typed action reference from the generated `api` object.
|
|
216
|
+
* @returns A function that, when called, executes the action and returns a
|
|
217
|
+
* promise that resolves to the action’s return value.
|
|
89
218
|
*/
|
|
90
219
|
function useAction(reference) {
|
|
91
220
|
const client = useSyncore();
|
|
92
221
|
return (...args) => client.action(reference, normalizeOptionalArgs(args));
|
|
93
222
|
}
|
|
94
223
|
/**
|
|
95
|
-
*
|
|
224
|
+
* Subscribe to multiple Syncore queries simultaneously and receive per-entry
|
|
225
|
+
* state objects in a single hook call.
|
|
226
|
+
*
|
|
227
|
+
* More efficient than calling `useQuery` in a loop when the set of queries is
|
|
228
|
+
* known at component render time. The hook maintains only one subscription per
|
|
229
|
+
* unique `(reference, args)` combination even if entries are duplicated.
|
|
230
|
+
*
|
|
231
|
+
* ```tsx
|
|
232
|
+
* const { header, sidebar } = useQueries({
|
|
233
|
+
* header: { query: api.layout.header },
|
|
234
|
+
* sidebar: { query: api.layout.sidebar, args: { userId } },
|
|
235
|
+
* });
|
|
236
|
+
*
|
|
237
|
+
* if (header.isLoading || sidebar.isLoading) return <Spinner />;
|
|
238
|
+
* ```
|
|
239
|
+
*
|
|
240
|
+
* @param entries - A record of named query requests. Each entry can include
|
|
241
|
+
* `args: skip` to suppress that specific subscription.
|
|
242
|
+
* @returns A record with the same keys, each holding a {@link SyncoreQueryState}.
|
|
96
243
|
*/
|
|
97
244
|
function useQueries(entries) {
|
|
98
245
|
const client = useSyncore();
|
|
@@ -125,7 +272,44 @@ function useQueries(entries) {
|
|
|
125
272
|
]);
|
|
126
273
|
}
|
|
127
274
|
/**
|
|
128
|
-
*
|
|
275
|
+
* Subscribe to a paginated Syncore query, incrementally loading more pages.
|
|
276
|
+
*
|
|
277
|
+
* The query must accept a `paginationOpts` argument and return a
|
|
278
|
+
* `PaginationResult`. The hook manages cursors automatically — call the
|
|
279
|
+
* returned `loadMore` function to append the next page to the results.
|
|
280
|
+
*
|
|
281
|
+
* ```tsx
|
|
282
|
+
* const { results, status, loadMore, hasMore } = usePaginatedQuery(
|
|
283
|
+
* api.tasks.list,
|
|
284
|
+
* { projectId },
|
|
285
|
+
* { initialNumItems: 20 },
|
|
286
|
+
* );
|
|
287
|
+
*
|
|
288
|
+
* return (
|
|
289
|
+
* <>
|
|
290
|
+
* {results.map((t) => <TaskRow key={t._id} task={t} />)}
|
|
291
|
+
* {hasMore && (
|
|
292
|
+
* <button
|
|
293
|
+
* onClick={() => loadMore(20)}
|
|
294
|
+
* disabled={status === "loadingMore"}
|
|
295
|
+
* >
|
|
296
|
+
* Load more
|
|
297
|
+
* </button>
|
|
298
|
+
* )}
|
|
299
|
+
* </>
|
|
300
|
+
* );
|
|
301
|
+
* ```
|
|
302
|
+
*
|
|
303
|
+
* Pass `skip` as `args` to suppress the subscription until arguments are
|
|
304
|
+
* ready.
|
|
305
|
+
*
|
|
306
|
+
* @param reference - A typed query reference whose handler calls
|
|
307
|
+
* `ctx.db.query(…).paginate(paginationOpts)`.
|
|
308
|
+
* @param args - Arguments for the query (excluding
|
|
309
|
+
* `paginationOpts`, which is managed internally), or `skip`.
|
|
310
|
+
* @param options.initialNumItems - Number of items to load on the first page.
|
|
311
|
+
* @returns A {@link UsePaginatedQueryResult} with the accumulated results and
|
|
312
|
+
* a `loadMore` callback.
|
|
129
313
|
*/
|
|
130
314
|
function usePaginatedQuery(reference, args, options) {
|
|
131
315
|
if (typeof options.initialNumItems !== "number" || options.initialNumItems <= 0) throw new Error(`options.initialNumItems must be a positive number. Received ${String(options.initialNumItems)}.`);
|
|
@@ -238,16 +422,23 @@ const noOpWatch = {
|
|
|
238
422
|
};
|
|
239
423
|
function useManagedQueryWatch(client, reference, args, isSkipped = false) {
|
|
240
424
|
const argsKey = isSkipped ? skip : stableStringify(args ?? {});
|
|
241
|
-
const
|
|
242
|
-
|
|
425
|
+
const [watch, setWatch] = useState(() => noOpWatch);
|
|
426
|
+
useEffect(() => {
|
|
427
|
+
if (isSkipped) {
|
|
428
|
+
setWatch(noOpWatch);
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
const nextWatch = client.watchQuery(reference, JSON.parse(argsKey));
|
|
432
|
+
setWatch(nextWatch);
|
|
433
|
+
return () => {
|
|
434
|
+
nextWatch.dispose?.();
|
|
435
|
+
};
|
|
436
|
+
}, [
|
|
437
|
+
argsKey,
|
|
243
438
|
client,
|
|
244
439
|
isSkipped,
|
|
245
|
-
normalizedArgs,
|
|
246
440
|
reference
|
|
247
441
|
]);
|
|
248
|
-
useEffect(() => () => {
|
|
249
|
-
if (!isSkipped) watch.dispose?.();
|
|
250
|
-
}, [isSkipped, watch]);
|
|
251
442
|
return watch;
|
|
252
443
|
}
|
|
253
444
|
function normalizeOptionalArgs(args) {
|