syncorejs 0.2.1 → 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/README.md +2 -1
- package/dist/_vendor/cli/app.d.mts.map +1 -1
- package/dist/_vendor/cli/app.mjs +330 -46
- package/dist/_vendor/cli/app.mjs.map +1 -1
- package/dist/_vendor/cli/context.mjs +27 -9
- 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 +513 -46
- 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 +5 -4
- package/dist/_vendor/cli/messages.mjs.map +1 -1
- package/dist/_vendor/cli/preflight.mjs.map +1 -1
- package/dist/_vendor/cli/project.mjs +125 -27
- package/dist/_vendor/cli/project.mjs.map +1 -1
- package/dist/_vendor/cli/render.mjs +57 -9
- package/dist/_vendor/cli/render.mjs.map +1 -1
- package/dist/_vendor/cli/targets.mjs +4 -3
- package/dist/_vendor/cli/targets.mjs.map +1 -1
- package/dist/_vendor/core/cli.d.mts +20 -4
- package/dist/_vendor/core/cli.d.mts.map +1 -1
- package/dist/_vendor/core/cli.mjs +458 -133
- package/dist/_vendor/core/cli.mjs.map +1 -1
- package/dist/_vendor/core/devtools-auth.mjs +60 -0
- package/dist/_vendor/core/devtools-auth.mjs.map +1 -0
- package/dist/_vendor/core/index.d.mts +5 -3
- package/dist/_vendor/core/index.mjs +22 -2
- package/dist/_vendor/core/index.mjs.map +1 -1
- package/dist/_vendor/core/runtime/components.d.mts +111 -0
- package/dist/_vendor/core/runtime/components.d.mts.map +1 -0
- package/dist/_vendor/core/runtime/components.mjs +186 -0
- package/dist/_vendor/core/runtime/components.mjs.map +1 -0
- package/dist/_vendor/core/runtime/devtools.d.mts +4 -4
- package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/devtools.mjs +178 -60
- package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
- package/dist/_vendor/core/runtime/functions.d.mts +398 -16
- package/dist/_vendor/core/runtime/functions.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/functions.mjs +74 -3
- 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 +83 -0
- package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs +720 -0
- package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs +234 -0
- package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs +255 -0
- package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs +200 -0
- package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/shared.mjs +252 -0
- package/dist/_vendor/core/runtime/internal/engines/shared.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs +145 -0
- package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs +221 -0
- package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs +32 -0
- package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/systemMeta.mjs +61 -0
- package/dist/_vendor/core/runtime/internal/systemMeta.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs +41 -0
- package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs.map +1 -0
- package/dist/_vendor/core/runtime/runtime.d.mts +1187 -202
- package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/runtime.mjs +73 -1365
- package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
- package/dist/_vendor/core/transport.d.mts +113 -0
- package/dist/_vendor/core/transport.d.mts.map +1 -0
- package/dist/_vendor/core/transport.mjs +428 -0
- package/dist/_vendor/core/transport.mjs.map +1 -0
- package/dist/_vendor/devtools-protocol/index.d.ts +187 -4
- package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
- package/dist/_vendor/devtools-protocol/index.js +25 -9
- 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 +104 -26
- package/dist/_vendor/next/index.js.map +1 -1
- package/dist/_vendor/platform-expo/index.d.ts +156 -37
- package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
- package/dist/_vendor/platform-expo/index.js +80 -12
- package/dist/_vendor/platform-expo/index.js.map +1 -1
- package/dist/_vendor/platform-expo/react.d.ts.map +1 -1
- package/dist/_vendor/platform-expo/react.js +11 -10
- 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 +192 -24
- package/dist/_vendor/platform-node/index.d.mts.map +1 -1
- package/dist/_vendor/platform-node/index.mjs +236 -97
- package/dist/_vendor/platform-node/index.mjs.map +1 -1
- package/dist/_vendor/platform-node/ipc-react.d.mts.map +1 -1
- package/dist/_vendor/platform-node/ipc-react.mjs +15 -2
- package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
- package/dist/_vendor/platform-node/ipc.d.mts +11 -35
- package/dist/_vendor/platform-node/ipc.d.mts.map +1 -1
- package/dist/_vendor/platform-node/ipc.mjs +3 -273
- package/dist/_vendor/platform-node/ipc.mjs.map +1 -1
- package/dist/_vendor/platform-web/external-change.d.ts +43 -1
- package/dist/_vendor/platform-web/external-change.d.ts.map +1 -1
- package/dist/_vendor/platform-web/external-change.js +32 -1
- package/dist/_vendor/platform-web/external-change.js.map +1 -1
- package/dist/_vendor/platform-web/index.d.ts +323 -51
- package/dist/_vendor/platform-web/index.d.ts.map +1 -1
- package/dist/_vendor/platform-web/index.js +233 -30
- 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 +27 -13
- 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 +71 -44
- package/dist/_vendor/platform-web/worker.d.ts.map +1 -1
- package/dist/_vendor/platform-web/worker.js +40 -271
- package/dist/_vendor/platform-web/worker.js.map +1 -1
- package/dist/_vendor/react/index.d.ts +222 -23
- package/dist/_vendor/react/index.d.ts.map +1 -1
- package/dist/_vendor/react/index.js +476 -63
- package/dist/_vendor/react/index.js.map +1 -1
- package/dist/_vendor/schema/definition.d.ts +151 -37
- package/dist/_vendor/schema/definition.d.ts.map +1 -1
- package/dist/_vendor/schema/definition.js +102 -20
- package/dist/_vendor/schema/definition.js.map +1 -1
- package/dist/_vendor/schema/index.d.ts +4 -4
- package/dist/_vendor/schema/index.js +2 -2
- package/dist/_vendor/schema/planner.d.ts +19 -2
- package/dist/_vendor/schema/planner.d.ts.map +1 -1
- package/dist/_vendor/schema/planner.js +79 -3
- package/dist/_vendor/schema/planner.js.map +1 -1
- package/dist/_vendor/schema/validators.d.ts +279 -83
- package/dist/_vendor/schema/validators.d.ts.map +1 -1
- package/dist/_vendor/schema/validators.js +330 -38
- package/dist/_vendor/schema/validators.js.map +1 -1
- package/dist/_vendor/svelte/index.d.ts +245 -19
- package/dist/_vendor/svelte/index.d.ts.map +1 -1
- package/dist/_vendor/svelte/index.js +443 -20
- 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/components.d.ts +2 -0
- package/dist/components.js +2 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/package.json +29 -21
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.tsx"],"sourcesContent":["import {\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useMemo,\n useState\n} from \"react\";\nimport type {\n FunctionReference,\n SyncoreClient,\n SyncoreWatch\n} from \"@syncore/core\";\n\ntype ManagedSyncoreWatch<TResult> = SyncoreWatch<TResult> & {\n dispose?: () => void;\n};\n\ntype OptionalArgsTuple<TArgs> =\n Record<never, never> extends TArgs ? [args?: TArgs] : [args: TArgs];\n\n/**\n * Pass `\"skip\"` as the args argument to `useQuery` to suppress the subscription\n * entirely and return `undefined` without contacting the runtime.\n */\nexport const skip = \"skip\" as const;\ntype Skip = typeof skip;\n\nconst SyncoreContext = createContext<SyncoreClient | null>(null);\n\n/**\n * Provide a Syncore client to React descendants.\n *\n * Wrap your app with this component to use Syncore hooks like `useQuery` and\n * `useMutation`.\n */\nexport function SyncoreProvider({\n client,\n children\n}: {\n client: SyncoreClient;\n children: ReactNode;\n}) {\n return (\n <SyncoreContext.Provider value={client}>{children}</SyncoreContext.Provider>\n );\n}\n\n/**\n * Read the active Syncore client from React context.\n *\n * Throws if used outside of {@link SyncoreProvider}.\n */\nexport function useSyncore(): SyncoreClient {\n const client = useContext(SyncoreContext);\n if (!client) {\n throw new Error(\"SyncoreProvider is missing from the React tree.\");\n }\n return client;\n}\n\n/**\n * Load a reactive Syncore query within a React component.\n *\n * The hook subscribes automatically and re-renders whenever the local query\n * result changes. Pass `\"skip\"` as the second argument to suppress the\n * subscription entirely and return `undefined` without contacting the runtime.\n */\nexport function useQuery<TArgs, TResult>(\n reference: FunctionReference<\"query\", TArgs, TResult>,\n ...args: OptionalArgsTuple<TArgs> | [Skip]\n): TResult | undefined {\n const isSkipped = args[0] === skip;\n const client = useSyncore();\n const watch = useManagedQueryWatch(\n client,\n reference,\n isSkipped\n ? undefined\n : normalizeOptionalArgs(args as OptionalArgsTuple<TArgs>),\n isSkipped\n );\n const [snapshot, setSnapshot] = useState(() =>\n isSkipped ? noOpSnapshot : readWatchSnapshot(watch)\n );\n\n useEffect(() => {\n if (isSkipped) {\n setSnapshot(noOpSnapshot);\n return;\n }\n const sync = () => {\n setSnapshot(readWatchSnapshot(watch));\n };\n sync();\n return watch.onUpdate(sync);\n }, [watch, isSkipped]);\n\n if (snapshot.error) {\n throw snapshot.error;\n }\n\n return snapshot.result;\n}\n\nconst noOpSnapshot = { result: undefined, error: undefined };\n\nconst noOpWatch: ManagedSyncoreWatch<never> = {\n onUpdate: () => () => {},\n localQueryResult: () => undefined,\n localQueryError: () => undefined\n};\n\n/**\n * Construct a stable function that executes a Syncore mutation.\n */\nexport function useMutation<TArgs, TResult>(\n reference: FunctionReference<\"mutation\", TArgs, TResult>\n): (...args: OptionalArgsTuple<TArgs>) => Promise<TResult> {\n const client = useSyncore();\n return (...args) => client.mutation(reference, normalizeOptionalArgs(args));\n}\n\n/**\n * Construct a stable function that executes a Syncore action.\n */\nexport function useAction<TArgs, TResult>(\n reference: FunctionReference<\"action\", TArgs, TResult>\n): (...args: OptionalArgsTuple<TArgs>) => Promise<TResult> {\n const client = useSyncore();\n return (...args) => client.action(reference, normalizeOptionalArgs(args));\n}\n\n/**\n * Load several Syncore queries at once using explicit keys.\n */\nexport function useQueries<TResult>(\n entries: Array<{\n key: string;\n reference: FunctionReference<\"query\">;\n args?: Record<string, unknown>;\n }>\n): Record<string, TResult | undefined> {\n const client = useSyncore();\n const entriesKey = stableStringify(\n entries.map((entry) => ({\n key: entry.key,\n referenceName: entry.reference.name,\n args: entry.args ?? {}\n }))\n );\n const normalizedEntries = useMemo(\n () =>\n JSON.parse(entriesKey) as Array<{\n key: string;\n referenceName: string;\n args: Record<string, unknown>;\n }>,\n [entriesKey]\n );\n const watches = useMemo(\n () =>\n normalizedEntries.map((entry) => ({\n key: entry.key,\n watch: client.watchQuery(\n { kind: \"query\", name: entry.referenceName },\n entry.args\n ) as ManagedSyncoreWatch<TResult>\n })),\n [client, normalizedEntries]\n );\n const [snapshot, setSnapshot] = useState(() => readQueriesSnapshot(watches));\n\n useEffect(\n () => () => {\n for (const entry of watches) {\n entry.watch.dispose?.();\n }\n },\n [watches]\n );\n\n useEffect(() => {\n const sync = () => {\n setSnapshot(readQueriesSnapshot(watches));\n };\n sync();\n const cleanups = watches.map((entry) => entry.watch.onUpdate(sync));\n return () => {\n for (const cleanup of cleanups) {\n cleanup();\n }\n };\n }, [watches]);\n\n return snapshot;\n}\n\nfunction useManagedQueryWatch<TArgs, TResult>(\n client: SyncoreClient,\n reference: FunctionReference<\"query\", TArgs, TResult>,\n args?: TArgs,\n isSkipped?: boolean\n): ManagedSyncoreWatch<TResult> {\n const argsKey = isSkipped ? \"skip\" : stableStringify(args ?? {});\n const normalizedArgs = useMemo(\n () => (isSkipped ? undefined : (JSON.parse(argsKey) as TArgs)),\n [argsKey, isSkipped]\n );\n const watch = useMemo<ManagedSyncoreWatch<TResult>>(\n () =>\n isSkipped\n ? noOpWatch\n : (client.watchQuery(\n reference,\n normalizedArgs!\n ) as ManagedSyncoreWatch<TResult>),\n [client, normalizedArgs, reference, isSkipped]\n );\n\n useEffect(\n () => () => {\n if (!isSkipped) watch.dispose?.();\n },\n [watch, isSkipped]\n );\n\n return watch;\n}\n\nfunction normalizeOptionalArgs<TArgs>(\n args: [] | [TArgs] | readonly unknown[]\n): TArgs {\n return (args[0] ?? {}) as TArgs;\n}\n\nfunction readWatchSnapshot<TResult>(watch: SyncoreWatch<TResult>): {\n result: TResult | undefined;\n error: Error | undefined;\n} {\n return {\n result: watch.localQueryResult(),\n error: watch.localQueryError()\n };\n}\n\nfunction readQueriesSnapshot<TResult>(\n watches: Array<{\n key: string;\n watch: ManagedSyncoreWatch<TResult>;\n }>\n): Record<string, TResult | undefined> {\n return Object.fromEntries(\n watches.map((entry) => [entry.key, entry.watch.localQueryResult()])\n );\n}\n\nfunction stableStringify(value: unknown): string {\n return JSON.stringify(sortValue(value));\n}\n\nfunction sortValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(sortValue);\n }\n if (value && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, nested]) => [key, sortValue(nested)])\n );\n }\n return value;\n}\n"],"mappings":";;;;;;;AAyBA,MAAa,OAAO;AAGpB,MAAM,iBAAiB,cAAoC,KAAK;;;;;;;AAQhE,SAAgB,gBAAgB,EAC9B,QACA,YAIC;AACD,QACE,oBAAC,eAAe,UAAhB;EAAyB,OAAO;EAAS;EAAmC,CAAA;;;;;;;AAShF,SAAgB,aAA4B;CAC1C,MAAM,SAAS,WAAW,eAAe;AACzC,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,kDAAkD;AAEpE,QAAO;;;;;;;;;AAUT,SAAgB,SACd,WACA,GAAG,MACkB;CACrB,MAAM,YAAY,KAAK,OAAO;CAE9B,MAAM,QAAQ,qBADC,YAAY,EAGzB,WACA,YACI,KAAA,IACA,sBAAsB,KAAiC,EAC3D,UACD;CACD,MAAM,CAAC,UAAU,eAAe,eAC9B,YAAY,eAAe,kBAAkB,MAAM,CACpD;AAED,iBAAgB;AACd,MAAI,WAAW;AACb,eAAY,aAAa;AACzB;;EAEF,MAAM,aAAa;AACjB,eAAY,kBAAkB,MAAM,CAAC;;AAEvC,QAAM;AACN,SAAO,MAAM,SAAS,KAAK;IAC1B,CAAC,OAAO,UAAU,CAAC;AAEtB,KAAI,SAAS,MACX,OAAM,SAAS;AAGjB,QAAO,SAAS;;AAGlB,MAAM,eAAe;CAAE,QAAQ,KAAA;CAAW,OAAO,KAAA;CAAW;AAE5D,MAAM,YAAwC;CAC5C,sBAAsB;CACtB,wBAAwB,KAAA;CACxB,uBAAuB,KAAA;CACxB;;;;AAKD,SAAgB,YACd,WACyD;CACzD,MAAM,SAAS,YAAY;AAC3B,SAAQ,GAAG,SAAS,OAAO,SAAS,WAAW,sBAAsB,KAAK,CAAC;;;;;AAM7E,SAAgB,UACd,WACyD;CACzD,MAAM,SAAS,YAAY;AAC3B,SAAQ,GAAG,SAAS,OAAO,OAAO,WAAW,sBAAsB,KAAK,CAAC;;;;;AAM3E,SAAgB,WACd,SAKqC;CACrC,MAAM,SAAS,YAAY;CAC3B,MAAM,aAAa,gBACjB,QAAQ,KAAK,WAAW;EACtB,KAAK,MAAM;EACX,eAAe,MAAM,UAAU;EAC/B,MAAM,MAAM,QAAQ,EAAE;EACvB,EAAE,CACJ;CACD,MAAM,oBAAoB,cAEtB,KAAK,MAAM,WAAW,EAKxB,CAAC,WAAW,CACb;CACD,MAAM,UAAU,cAEZ,kBAAkB,KAAK,WAAW;EAChC,KAAK,MAAM;EACX,OAAO,OAAO,WACZ;GAAE,MAAM;GAAS,MAAM,MAAM;GAAe,EAC5C,MAAM,KACP;EACF,EAAE,EACL,CAAC,QAAQ,kBAAkB,CAC5B;CACD,MAAM,CAAC,UAAU,eAAe,eAAe,oBAAoB,QAAQ,CAAC;AAE5E,uBACc;AACV,OAAK,MAAM,SAAS,QAClB,OAAM,MAAM,WAAW;IAG3B,CAAC,QAAQ,CACV;AAED,iBAAgB;EACd,MAAM,aAAa;AACjB,eAAY,oBAAoB,QAAQ,CAAC;;AAE3C,QAAM;EACN,MAAM,WAAW,QAAQ,KAAK,UAAU,MAAM,MAAM,SAAS,KAAK,CAAC;AACnE,eAAa;AACX,QAAK,MAAM,WAAW,SACpB,UAAS;;IAGZ,CAAC,QAAQ,CAAC;AAEb,QAAO;;AAGT,SAAS,qBACP,QACA,WACA,MACA,WAC8B;CAC9B,MAAM,UAAU,YAAY,SAAS,gBAAgB,QAAQ,EAAE,CAAC;CAChE,MAAM,iBAAiB,cACd,YAAY,KAAA,IAAa,KAAK,MAAM,QAAQ,EACnD,CAAC,SAAS,UAAU,CACrB;CACD,MAAM,QAAQ,cAEV,YACI,YACC,OAAO,WACN,WACA,eACD,EACP;EAAC;EAAQ;EAAgB;EAAW;EAAU,CAC/C;AAED,uBACc;AACV,MAAI,CAAC,UAAW,OAAM,WAAW;IAEnC,CAAC,OAAO,UAAU,CACnB;AAED,QAAO;;AAGT,SAAS,sBACP,MACO;AACP,QAAQ,KAAK,MAAM,EAAE;;AAGvB,SAAS,kBAA2B,OAGlC;AACA,QAAO;EACL,QAAQ,MAAM,kBAAkB;EAChC,OAAO,MAAM,iBAAiB;EAC/B;;AAGH,SAAS,oBACP,SAIqC;AACrC,QAAO,OAAO,YACZ,QAAQ,KAAK,UAAU,CAAC,MAAM,KAAK,MAAM,MAAM,kBAAkB,CAAC,CAAC,CACpE;;AAGH,SAAS,gBAAgB,OAAwB;AAC/C,QAAO,KAAK,UAAU,UAAU,MAAM,CAAC;;AAGzC,SAAS,UAAU,OAAyB;AAC1C,KAAI,MAAM,QAAQ,MAAM,CACtB,QAAO,MAAM,IAAI,UAAU;AAE7B,KAAI,SAAS,OAAO,UAAU,SAC5B,QAAO,OAAO,YACZ,OAAO,QAAQ,MAAiC,CAC7C,MAAM,CAAC,OAAO,CAAC,WAAW,KAAK,cAAc,MAAM,CAAC,CACpD,KAAK,CAAC,KAAK,YAAY,CAAC,KAAK,UAAU,OAAO,CAAC,CAAC,CACpD;AAEH,QAAO"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.tsx"],"sourcesContent":["import {\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useMemo,\n useState\n} from \"react\";\nimport type {\n FunctionArgs,\n FunctionReference,\n FunctionResult,\n PaginationOptions,\n PaginationResult,\n SyncoreClient,\n SyncorePaginatedQueryStatus,\n SyncoreQueryState,\n SyncoreRuntimeStatus,\n SyncoreWatch,\n UsePaginatedQueryResult\n} from \"@syncore/core\";\n\ntype ManagedSyncoreWatch<TResult> = SyncoreWatch<TResult> & {\n dispose?: () => void;\n};\n\ntype OptionalArgsTuple<TArgs> =\n Record<never, never> extends TArgs ? [args?: TArgs] : [args: TArgs];\n\ntype QueryRequestInput<\n TReference extends FunctionReference<\"query\"> = FunctionReference<\"query\">\n> = Record<never, never> extends FunctionArgs<TReference>\n ? {\n query: TReference;\n args?: FunctionArgs<TReference> | Skip;\n }\n : {\n query: TReference;\n args: FunctionArgs<TReference> | Skip;\n };\n\ntype QueriesRequestInput = Record<string, QueryRequestInput>;\n\ntype QueryStateForEntry<TEntry> = TEntry extends QueryRequestInput<\n infer TReference\n>\n ? SyncoreQueryState<FunctionResult<TReference>>\n : never;\n\nexport type UseQueriesResult<TEntries extends QueriesRequestInput> = {\n [TKey in keyof TEntries]: QueryStateForEntry<TEntries[TKey]>;\n};\n\ntype PaginatedQueryReference = FunctionReference<\n \"query\",\n Record<string, unknown>,\n PaginationResult<unknown>\n>;\n\ntype PaginatedQueryArgs<TReference extends FunctionReference<\"query\">> =\n FunctionArgs<TReference> extends { paginationOpts: PaginationOptions }\n ? Omit<FunctionArgs<TReference>, \"paginationOpts\">\n : never;\n\ntype PaginatedQueryItem<TReference extends FunctionReference<\"query\">> =\n FunctionResult<TReference> extends PaginationResult<infer TItem>\n ? TItem\n : never;\n\ntype QuerySnapshot<TResult> = {\n data: TResult | undefined;\n error: Error | undefined;\n};\n\ntype NormalizedQueryEntry = {\n key: string;\n referenceName: string;\n args: Record<string, unknown>;\n skipped: boolean;\n};\n\ntype PaginatedQueryInternalState = {\n requestKey: string;\n nextPageKey: number;\n pages: Array<{\n key: string;\n cursor: string | null;\n numItems: number;\n }>;\n};\n\ntype QueryObserverRecord = {\n requestKey: string;\n snapshot: QuerySnapshot<unknown>;\n unsubscribe: () => void;\n watch?: ManagedSyncoreWatch<unknown>;\n};\n\n/**\n * Pass `skip` as the `args` argument to any Syncore React hook to suppress\n * that subscription entirely.\n *\n * Useful when the query arguments depend on state that is not yet available\n * (e.g. a selected item ID) — instead of conditionally calling the hook\n * (which violates the Rules of Hooks), pass `skip` to deactivate it:\n *\n * ```tsx\n * const task = useQuery(api.tasks.get, selectedId ? { id: selectedId } : skip);\n * // task is `undefined` while selectedId is null/undefined\n * ```\n *\n * Skipped queries return `undefined` for `data`, `\"skipped\"` for `status`,\n * and `false` for `isLoading`.\n */\nexport const skip = \"skip\" as const;\ntype Skip = typeof skip;\n\nconst defaultRuntimeStatus: SyncoreRuntimeStatus = {\n kind: \"starting\",\n reason: \"booting\"\n};\n\nconst SyncoreContext = createContext<SyncoreClient | null>(null);\n\n/**\n * Provides a Syncore client to all React descendants via context.\n *\n * Wrap your app (or any subtree that uses Syncore hooks) with\n * `SyncoreProvider`. All `useQuery`, `useMutation`, `useAction`, and\n * `useQueries` calls inside the tree will automatically use the client you\n * supply.\n *\n * ```tsx\n * // For a browser worker setup\n * const client = createBrowserWorkerClient();\n *\n * function App() {\n * return (\n * <SyncoreProvider client={client}>\n * <TaskList />\n * </SyncoreProvider>\n * );\n * }\n * ```\n *\n * For Next.js apps use `SyncoreNextProvider` which also handles service worker\n * and worker URL configuration.\n */\nexport function SyncoreProvider({\n client,\n children\n}: {\n client: SyncoreClient;\n children: ReactNode;\n}) {\n return (\n <SyncoreContext.Provider value={client}>{children}</SyncoreContext.Provider>\n );\n}\n\n/**\n * Returns the active `SyncoreClient` from the nearest {@link SyncoreProvider}\n * in the React tree.\n *\n * Throws if called outside of a `SyncoreProvider`. Prefer the higher-level\n * hooks (`useQuery`, `useMutation`, etc.) for common operations — use\n * `useSyncore` only when you need direct access to the client object.\n *\n * ```ts\n * const client = useSyncore();\n * const tasks = await client.query(api.tasks.list);\n * ```\n */\nexport function useSyncore(): SyncoreClient {\n const client = useContext(SyncoreContext);\n if (!client) {\n throw new Error(\"SyncoreProvider is missing from the React tree.\");\n }\n return client;\n}\n\n/**\n * Subscribe to the runtime’s lifecycle status.\n *\n * Returns a {@link SyncoreRuntimeStatus} that updates whenever the underlying\n * runtime changes state (e.g. starting, ready, error). Use it to gate your UI\n * on the runtime being ready or to display an error boundary:\n *\n * ```tsx\n * function TaskList() {\n * const status = useSyncoreStatus();\n * if (status.kind === \"starting\") return <Spinner />;\n * if (status.kind === \"error\") return <ErrorScreen error={status.error} />;\n * return <Tasks />;\n * }\n * ```\n *\n * Most components do not need this — `useQuery` already incorporates runtime\n * status into the `SyncoreQueryState.runtimeStatus` field.\n */\nexport function useSyncoreStatus(): SyncoreRuntimeStatus {\n const client = useSyncore();\n const watch = useMemo(\n () => client.watchRuntimeStatus() as ManagedSyncoreWatch<SyncoreRuntimeStatus>,\n [client]\n );\n const [status, setStatus] = useState<SyncoreRuntimeStatus>(() =>\n readRuntimeStatusSnapshot(watch)\n );\n\n useEffect(() => {\n const sync = () => {\n setStatus(readRuntimeStatusSnapshot(watch));\n };\n sync();\n return watch.onUpdate(sync);\n }, [watch]);\n\n useEffect(\n () => () => {\n watch.dispose?.();\n },\n [watch]\n );\n\n return status;\n}\n\n/**\n * Subscribe to a reactive Syncore query and return the current data.\n *\n * The component re-renders automatically whenever the query result changes.\n * If the query throws, `useQuery` re-throws the error so a React error\n * boundary can catch it — use {@link useQueryState} if you need to handle\n * errors inline.\n *\n * ```tsx\n * // Basic usage\n * const tasks = useQuery(api.tasks.list);\n *\n * // With arguments\n * const task = useQuery(api.tasks.get, { id: taskId });\n *\n * // Conditionally skip when arguments are not yet available\n * const task = useQuery(api.tasks.get, taskId ? { id: taskId } : skip);\n * ```\n *\n * @param reference - A typed function reference (from the generated `api` object).\n * @param args - The query’s arguments, or `skip` to suppress the subscription.\n * @returns The current query result, or `undefined` while loading.\n */\nexport function useQuery<TArgs, TResult>(\n reference: FunctionReference<\"query\", TArgs, TResult>,\n ...args: OptionalArgsTuple<TArgs> | [Skip]\n): TResult | undefined {\n const state = useQueryState(reference, ...(args as OptionalArgsTuple<TArgs> | [Skip]));\n if (state.error) {\n throw state.error;\n }\n return state.data;\n}\n\n/**\n * Subscribe to a reactive Syncore query and return the full\n * {@link SyncoreQueryState} including loading, error, and runtime status.\n *\n * Use this instead of {@link useQuery} when you need to:\n * - Differentiate between `undefined` data and an error.\n * - React to `isLoading` / `isError` without relying on error boundaries.\n * - Inspect `runtimeStatus` for the underlying runtime’s health.\n *\n * ```tsx\n * const { data, isLoading, isError, error } = useQueryState(api.tasks.list);\n *\n * if (isLoading) return <Spinner />;\n * if (isError) return <ErrorBanner message={error.message} />;\n * return <TaskList tasks={data} />;\n * ```\n */\nexport function useQueryState<TArgs, TResult>(\n reference: FunctionReference<\"query\", TArgs, TResult>,\n ...args: OptionalArgsTuple<TArgs> | [Skip]\n): SyncoreQueryState<TResult> {\n const isSkipped = args[0] === skip;\n const client = useSyncore();\n const runtimeStatus = useSyncoreStatus();\n const watch = useManagedQueryWatch(\n client,\n reference,\n isSkipped\n ? undefined\n : normalizeOptionalArgs(args as OptionalArgsTuple<TArgs>),\n isSkipped\n );\n const [snapshot, setSnapshot] = useState<QuerySnapshot<TResult>>(() =>\n isSkipped ? noOpSnapshot : readWatchSnapshot(watch)\n );\n\n useEffect(() => {\n if (isSkipped) {\n setSnapshot(noOpSnapshot);\n return;\n }\n const sync = () => {\n setSnapshot(readWatchSnapshot(watch));\n };\n sync();\n return watch.onUpdate(sync);\n }, [watch, isSkipped]);\n\n return toQueryState(snapshot, runtimeStatus, isSkipped);\n}\n\n/**\n * Returns a stable callback for executing a Syncore mutation.\n *\n * The returned function is type-safe: its parameter types are inferred from\n * the mutation definition and remain stable across re-renders (no need to\n * wrap in `useCallback`).\n *\n * ```tsx\n * const createTask = useMutation(api.tasks.create);\n *\n * return (\n * <button onClick={() => createTask({ title: \"New task\" })}>\n * Add task\n * </button>\n * );\n * ```\n *\n * @param reference - A typed mutation reference from the generated `api` object.\n * @returns A function that, when called, executes the mutation and returns a\n * promise that resolves to the mutation’s return value.\n */\nexport function useMutation<TArgs, TResult>(\n reference: FunctionReference<\"mutation\", TArgs, TResult>\n): (...args: OptionalArgsTuple<TArgs>) => Promise<TResult> {\n const client = useSyncore();\n return (...args) => client.mutation(reference, normalizeOptionalArgs(args));\n}\n\n/**\n * Returns a stable callback for executing a Syncore action.\n *\n * Identical to {@link useMutation} but for actions. Use this when the work you\n * need to do cannot run inside a transaction (external API calls, long-running\n * tasks, etc.).\n *\n * ```tsx\n * const importTasks = useAction(api.tasks.importFromCsv);\n *\n * return (\n * <button onClick={() => importTasks({ url: csvUrl })}>\n * Import\n * </button>\n * );\n * ```\n *\n * @param reference - A typed action reference from the generated `api` object.\n * @returns A function that, when called, executes the action and returns a\n * promise that resolves to the action’s return value.\n */\nexport function useAction<TArgs, TResult>(\n reference: FunctionReference<\"action\", TArgs, TResult>\n): (...args: OptionalArgsTuple<TArgs>) => Promise<TResult> {\n const client = useSyncore();\n return (...args) => client.action(reference, normalizeOptionalArgs(args));\n}\n\n/**\n * Subscribe to multiple Syncore queries simultaneously and receive per-entry\n * state objects in a single hook call.\n *\n * More efficient than calling `useQuery` in a loop when the set of queries is\n * known at component render time. The hook maintains only one subscription per\n * unique `(reference, args)` combination even if entries are duplicated.\n *\n * ```tsx\n * const { header, sidebar } = useQueries({\n * header: { query: api.layout.header },\n * sidebar: { query: api.layout.sidebar, args: { userId } },\n * });\n *\n * if (header.isLoading || sidebar.isLoading) return <Spinner />;\n * ```\n *\n * @param entries - A record of named query requests. Each entry can include\n * `args: skip` to suppress that specific subscription.\n * @returns A record with the same keys, each holding a {@link SyncoreQueryState}.\n */\nexport function useQueries<TEntries extends QueriesRequestInput>(\n entries: TEntries\n): UseQueriesResult<TEntries> {\n const client = useSyncore();\n const runtimeStatus = useSyncoreStatus();\n const entriesKey = stableStringify(\n Object.entries(entries)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, entry]) => ({\n key,\n referenceName: entry.query.name,\n skipped: entry.args === skip,\n args:\n entry.args === skip\n ? {}\n : normalizeOptionalArgs([entry.args ?? {}] as [] | [unknown])\n }))\n );\n const normalizedEntries = useMemo(\n () => JSON.parse(entriesKey) as NormalizedQueryEntry[],\n [entriesKey]\n );\n const [observer] = useState(() => new ReactQueriesObserver(client));\n const [, setVersion] = useState(0);\n\n if (observer.client !== client) {\n observer.replaceClient(client);\n }\n\n useEffect(() => () => observer.destroy(), [observer]);\n\n useEffect(() => {\n observer.setEntries(normalizedEntries);\n setVersion((value) => value + 1);\n return observer.subscribe(() => {\n setVersion((value) => value + 1);\n });\n }, [normalizedEntries, observer]);\n\n const snapshot = observer.getSnapshot(normalizedEntries);\n\n return useMemo(() => {\n return Object.fromEntries(\n normalizedEntries.map((entry) => [\n entry.key,\n toQueryState(\n snapshot[entry.key] ?? noOpSnapshot,\n runtimeStatus,\n entry.skipped\n )\n ])\n ) as UseQueriesResult<TEntries>;\n }, [normalizedEntries, runtimeStatus, snapshot]);\n}\n\n/**\n * Subscribe to a paginated Syncore query, incrementally loading more pages.\n *\n * The query must accept a `paginationOpts` argument and return a\n * `PaginationResult`. The hook manages cursors automatically — call the\n * returned `loadMore` function to append the next page to the results.\n *\n * ```tsx\n * const { results, status, loadMore, hasMore } = usePaginatedQuery(\n * api.tasks.list,\n * { projectId },\n * { initialNumItems: 20 },\n * );\n *\n * return (\n * <>\n * {results.map((t) => <TaskRow key={t._id} task={t} />)}\n * {hasMore && (\n * <button\n * onClick={() => loadMore(20)}\n * disabled={status === \"loadingMore\"}\n * >\n * Load more\n * </button>\n * )}\n * </>\n * );\n * ```\n *\n * Pass `skip` as `args` to suppress the subscription until arguments are\n * ready.\n *\n * @param reference - A typed query reference whose handler calls\n * `ctx.db.query(…).paginate(paginationOpts)`.\n * @param args - Arguments for the query (excluding\n * `paginationOpts`, which is managed internally), or `skip`.\n * @param options.initialNumItems - Number of items to load on the first page.\n * @returns A {@link UsePaginatedQueryResult} with the accumulated results and\n * a `loadMore` callback.\n */\nexport function usePaginatedQuery<TReference extends PaginatedQueryReference>(\n reference: TReference,\n args: PaginatedQueryArgs<TReference> | Skip,\n options: {\n initialNumItems: number;\n }\n): UsePaginatedQueryResult<PaginatedQueryItem<TReference>> {\n if (\n typeof options.initialNumItems !== \"number\" ||\n options.initialNumItems <= 0\n ) {\n throw new Error(\n `options.initialNumItems must be a positive number. Received ${String(\n options.initialNumItems\n )}.`\n );\n }\n\n const runtimeStatus = useSyncoreStatus();\n const isSkipped = args === skip;\n const normalizedArgs = isSkipped ? {} : (args ?? {});\n const requestKey = stableStringify({\n referenceName: reference.name,\n args: normalizedArgs,\n initialNumItems: options.initialNumItems,\n skipped: isSkipped\n });\n const createInitialState = useMemo(\n () => () =>\n ({\n requestKey,\n nextPageKey: 1,\n pages: isSkipped\n ? []\n : [\n {\n key: \"0\",\n cursor: null,\n numItems: options.initialNumItems\n }\n ]\n }) satisfies PaginatedQueryInternalState,\n [isSkipped, options.initialNumItems, requestKey]\n );\n const [state, setState] = useState<PaginatedQueryInternalState>(\n createInitialState\n );\n\n let currentState = state;\n if (currentState.requestKey !== requestKey) {\n currentState = createInitialState();\n setState(currentState);\n }\n\n const pageQueries = useMemo(() => {\n const requests: Record<string, QueryRequestInput> = {};\n for (const page of currentState.pages) {\n requests[page.key] = {\n query: reference,\n args: {\n ...(normalizedArgs as Record<string, unknown>),\n paginationOpts: {\n cursor: page.cursor,\n numItems: page.numItems\n }\n }\n };\n }\n return requests;\n }, [currentState.pages, normalizedArgs, reference]);\n const pageStates = useQueries(pageQueries);\n\n const derived = useMemo(() => {\n const pages: Array<PaginationResult<PaginatedQueryItem<TReference>>> = [];\n let error: Error | undefined;\n\n for (const page of currentState.pages) {\n const pageState =\n pageStates[page.key as keyof typeof pageStates] as\n | SyncoreQueryState<PaginationResult<PaginatedQueryItem<TReference>>>\n | undefined;\n if (!pageState || pageState.status === \"loading\") {\n break;\n }\n if (pageState.status === \"error\") {\n error = pageState.error;\n break;\n }\n if (pageState.data) {\n pages.push(pageState.data);\n }\n }\n\n const results = pages.flatMap((page) => page.page);\n const lastLoadedPage = pages.at(-1);\n const lastRequestedKey = currentState.pages.at(-1)?.key;\n const lastRequestedState = lastRequestedKey\n ? (pageStates[lastRequestedKey as keyof typeof pageStates] as\n | SyncoreQueryState<PaginationResult<PaginatedQueryItem<TReference>>>\n | undefined)\n : undefined;\n const isLoading = !isSkipped && pages.length === 0 && !error;\n const isLoadingMore =\n currentState.pages.length > pages.length ||\n (!!lastRequestedState && lastRequestedState.status === \"loading\" && pages.length > 0);\n const hasMore = !!lastLoadedPage && !lastLoadedPage.isDone;\n const status: SyncorePaginatedQueryStatus = error\n ? \"error\"\n : isSkipped\n ? \"ready\"\n : isLoading\n ? \"loading\"\n : isLoadingMore\n ? \"loadingMore\"\n : hasMore\n ? \"ready\"\n : \"exhausted\";\n\n return {\n pages,\n results,\n error,\n isLoading,\n isLoadingMore,\n hasMore,\n cursor: lastLoadedPage?.cursor ?? null,\n status\n };\n }, [currentState.pages, isSkipped, pageStates]);\n\n return {\n ...derived,\n runtimeStatus,\n loadMore(numItems = options.initialNumItems) {\n if (\n isSkipped ||\n derived.error ||\n derived.isLoadingMore ||\n !derived.hasMore ||\n !derived.cursor\n ) {\n return;\n }\n\n setState((previous) => ({\n ...previous,\n nextPageKey: previous.nextPageKey + 1,\n pages: [\n ...previous.pages,\n {\n key: String(previous.nextPageKey),\n cursor: derived.cursor,\n numItems\n }\n ]\n }));\n }\n };\n}\n\nconst noOpSnapshot: QuerySnapshot<never> = {\n data: undefined,\n error: undefined\n};\n\nconst noOpWatch: ManagedSyncoreWatch<never> = {\n onUpdate: () => () => undefined,\n localQueryResult: () => undefined,\n localQueryError: () => undefined\n};\n\nfunction useManagedQueryWatch<TArgs, TResult>(\n client: SyncoreClient,\n reference: FunctionReference<\"query\", TArgs, TResult>,\n args?: TArgs,\n isSkipped = false\n): ManagedSyncoreWatch<TResult> {\n const argsKey = isSkipped ? skip : stableStringify(args ?? {});\n const [watch, setWatch] = useState<ManagedSyncoreWatch<TResult>>(\n () => noOpWatch\n );\n\n useEffect(() => {\n if (isSkipped) {\n setWatch(noOpWatch);\n return;\n }\n\n const nextWatch = client.watchQuery(\n reference,\n JSON.parse(argsKey) as TArgs\n ) as ManagedSyncoreWatch<TResult>;\n setWatch(nextWatch);\n\n return () => {\n nextWatch.dispose?.();\n };\n }, [argsKey, client, isSkipped, reference]);\n\n return watch;\n}\n\nfunction normalizeOptionalArgs<TArgs>(\n args: [] | [TArgs] | readonly unknown[]\n): TArgs {\n return (args[0] ?? {}) as TArgs;\n}\n\nfunction readWatchSnapshot<TResult>(\n watch: SyncoreWatch<TResult>\n): QuerySnapshot<TResult> {\n return {\n data: watch.localQueryResult(),\n error: watch.localQueryError()\n };\n}\n\nfunction readQueriesSnapshot(\n records: Array<{\n key: string;\n snapshot: QuerySnapshot<unknown>;\n }>\n): Record<string, QuerySnapshot<unknown>> {\n return Object.fromEntries(\n records.map((entry) => [entry.key, entry.snapshot])\n );\n}\n\nfunction readRuntimeStatusSnapshot(\n watch: SyncoreWatch<SyncoreRuntimeStatus>\n): SyncoreRuntimeStatus {\n return watch.localQueryResult() ?? defaultRuntimeStatus;\n}\n\nfunction toQueryState<TResult>(\n snapshot: QuerySnapshot<TResult>,\n runtimeStatus: SyncoreRuntimeStatus,\n isSkipped: boolean\n): SyncoreQueryState<TResult> {\n if (isSkipped) {\n return {\n data: undefined,\n error: undefined,\n status: \"skipped\",\n runtimeStatus,\n isLoading: false,\n isError: false,\n isReady: false\n };\n }\n\n const status =\n snapshot.error !== undefined\n ? \"error\"\n : snapshot.data === undefined\n ? \"loading\"\n : \"success\";\n\n return {\n data: snapshot.data,\n error: snapshot.error,\n status,\n runtimeStatus,\n isLoading: status === \"loading\",\n isError: status === \"error\",\n isReady: status === \"success\"\n };\n}\n\nfunction stableStringify(value: unknown): string {\n return JSON.stringify(sortValue(value));\n}\n\nfunction sortValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(sortValue);\n }\n if (value && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, nested]) => [key, sortValue(nested)])\n );\n }\n return value;\n}\n\nclass ReactQueriesObserver {\n readonly client: SyncoreClient;\n private readonly listeners = new Set<() => void>();\n private readonly records = new Map<string, QueryObserverRecord>();\n\n constructor(client: SyncoreClient) {\n this.client = client;\n }\n\n replaceClient(client: SyncoreClient): void {\n this.destroy();\n (this as { client: SyncoreClient }).client = client;\n }\n\n setEntries(entries: NormalizedQueryEntry[]): void {\n const activeKeys = new Set(entries.map((entry) => entry.key));\n\n for (const entry of entries) {\n const requestKey = `${entry.referenceName}:${stableStringify(entry.args)}:${String(\n entry.skipped\n )}`;\n const current = this.records.get(entry.key);\n if (current?.requestKey === requestKey) {\n continue;\n }\n\n current?.unsubscribe();\n current?.watch?.dispose?.();\n\n if (entry.skipped) {\n this.records.set(entry.key, {\n requestKey,\n snapshot: noOpSnapshot,\n unsubscribe: () => undefined\n });\n continue;\n }\n\n const watch = this.client.watchQuery(\n { kind: \"query\", name: entry.referenceName },\n entry.args\n ) as ManagedSyncoreWatch<unknown>;\n const record: QueryObserverRecord = {\n requestKey,\n snapshot: readWatchSnapshot(watch),\n unsubscribe: () => undefined,\n watch\n };\n record.unsubscribe = watch.onUpdate(() => {\n record.snapshot = readWatchSnapshot(watch);\n this.notify();\n });\n this.records.set(entry.key, record);\n }\n\n for (const [key, record] of this.records.entries()) {\n if (activeKeys.has(key)) {\n continue;\n }\n record.unsubscribe();\n record.watch?.dispose?.();\n this.records.delete(key);\n }\n }\n\n getSnapshot(entries: NormalizedQueryEntry[]): Record<string, QuerySnapshot<unknown>> {\n return readQueriesSnapshot(\n entries.map((entry) => ({\n key: entry.key,\n snapshot: this.records.get(entry.key)?.snapshot ?? noOpSnapshot\n }))\n );\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n destroy(): void {\n for (const record of this.records.values()) {\n record.unsubscribe();\n record.watch?.dispose?.();\n }\n this.records.clear();\n }\n\n private notify(): void {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Infer, ObjectValidator, ObjectValidatorShape, Validator } from "./validators.js";
|
|
1
|
+
import { FieldPaths, Infer, InferStorage, ObjectValidator, ObjectValidatorShape, Validator, ValidatorDescription } from "./validators.js";
|
|
2
2
|
|
|
3
3
|
//#region src/definition.d.ts
|
|
4
|
+
type Expand<T> = { [TKey in keyof T]: T[TKey] } & {};
|
|
4
5
|
interface IndexDefinition {
|
|
5
6
|
name: string;
|
|
6
7
|
fields: string[];
|
|
@@ -12,87 +13,200 @@ interface SearchIndexDefinition {
|
|
|
12
13
|
}
|
|
13
14
|
interface TableDefinitionOptions {
|
|
14
15
|
tableName?: string;
|
|
16
|
+
componentPath?: string;
|
|
17
|
+
componentName?: string;
|
|
15
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* The built-in system fields automatically added to every Syncore document.
|
|
21
|
+
*
|
|
22
|
+
* You never supply these when inserting; Syncore sets them for you.
|
|
23
|
+
* - `_id` — A unique string identifier for the document. Use `s.id(tableName)` to
|
|
24
|
+
* type foreign-key fields that reference this value.
|
|
25
|
+
* - `_creationTime` — Unix timestamp (milliseconds) when the document was inserted.
|
|
26
|
+
*/
|
|
16
27
|
interface TableDocumentSystemFields {
|
|
17
28
|
_id: string;
|
|
18
29
|
_creationTime: number;
|
|
19
30
|
}
|
|
31
|
+
type GenericTableIndexes = Record<string, readonly string[]>;
|
|
32
|
+
type GenericTableSearchIndexes = Record<string, {
|
|
33
|
+
searchField: string;
|
|
34
|
+
filterFields: string;
|
|
35
|
+
}>;
|
|
20
36
|
/**
|
|
21
|
-
*
|
|
37
|
+
* A typed table definition that describes the shape, indexes, and search
|
|
38
|
+
* indexes for a single Syncore table.
|
|
39
|
+
*
|
|
40
|
+
* You create `TableDefinition` instances with {@link defineTable} and attach
|
|
41
|
+
* indexes with the fluent `.index()` and `.searchIndex()` methods. The type
|
|
42
|
+
* parameters track the validator shape, registered indexes, and search indexes
|
|
43
|
+
* so that {@link QueryBuilder} can enforce correct field names at compile time.
|
|
22
44
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
45
|
+
* You almost never reference `TableDefinition` directly — it is the value
|
|
46
|
+
* produced by `defineTable` and consumed internally by `defineSchema`.
|
|
25
47
|
*/
|
|
26
|
-
declare class TableDefinition<TValidator extends Validator<unknown>> {
|
|
48
|
+
declare class TableDefinition<TValidator extends Validator<Record<string, unknown>, Record<string, unknown>, string>, TIndexes = Record<never, never>, TSearchIndexes = Record<never, never>> {
|
|
27
49
|
readonly validator: TValidator;
|
|
28
50
|
readonly indexes: IndexDefinition[];
|
|
29
51
|
readonly searchIndexes: SearchIndexDefinition[];
|
|
30
52
|
readonly options: TableDefinitionOptions;
|
|
53
|
+
readonly document: Infer<TValidator>;
|
|
54
|
+
readonly storageDocument: InferStorage<TValidator>;
|
|
55
|
+
readonly fieldPaths: FieldPaths<TValidator>;
|
|
56
|
+
readonly indexesByName: TIndexes;
|
|
57
|
+
readonly searchIndexesByName: TSearchIndexes;
|
|
31
58
|
constructor(validator: TValidator, options?: TableDefinitionOptions);
|
|
32
59
|
/**
|
|
33
|
-
*
|
|
60
|
+
* Register a named index on one or more fields of this table.
|
|
34
61
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
62
|
+
* Indexes allow efficient range queries via `ctx.db.query(table).withIndex()`.
|
|
63
|
+
* The first field listed is the primary sort key; additional fields refine
|
|
64
|
+
* within equal values of the first key.
|
|
65
|
+
*
|
|
66
|
+
* **Rules**
|
|
67
|
+
* - An index must cover at least one field.
|
|
68
|
+
* - Field names must be top-level paths that exist in the table validator.
|
|
69
|
+
* - Index names must be unique within the table.
|
|
70
|
+
* - Index definitions are immutable after creation — changing the fields of
|
|
71
|
+
* an existing index requires a manual migration.
|
|
72
|
+
*
|
|
73
|
+
* ```ts
|
|
74
|
+
* defineTable({ status: s.string(), createdAt: s.number(), ownerId: s.string() })
|
|
75
|
+
* .index("by_owner_and_status", ["ownerId", "status"])
|
|
76
|
+
* .index("by_created", ["createdAt"])
|
|
77
|
+
* ```
|
|
38
78
|
*/
|
|
39
|
-
index(name:
|
|
79
|
+
index<const TIndexName extends string, TFirstField extends FieldPaths<TValidator>, TRestFields extends FieldPaths<TValidator>[]>(name: TIndexName, fields: [TFirstField, ...TRestFields]): TableDefinition<TValidator, Expand<TIndexes & Record<TIndexName, readonly [TFirstField, ...TRestFields]>>, TSearchIndexes>;
|
|
40
80
|
/**
|
|
41
|
-
*
|
|
81
|
+
* Register a named full-text search index on this table.
|
|
82
|
+
*
|
|
83
|
+
* Search indexes power `ctx.db.query(table).withSearchIndex()` queries. Each
|
|
84
|
+
* search index specifies:
|
|
85
|
+
* - A single `searchField` that is tokenised and indexed for full-text
|
|
86
|
+
* matching.
|
|
87
|
+
* - Zero or more `filterFields` that can be used to narrow results with
|
|
88
|
+
* equality conditions.
|
|
42
89
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
90
|
+
* ```ts
|
|
91
|
+
* defineTable({ title: s.string(), status: s.string(), ownerId: s.string() })
|
|
92
|
+
* .searchIndex("search_title", {
|
|
93
|
+
* searchField: "title",
|
|
94
|
+
* filterFields: ["status", "ownerId"],
|
|
95
|
+
* })
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* In a query handler:
|
|
99
|
+
* ```ts
|
|
100
|
+
* const results = await ctx.db
|
|
101
|
+
* .query("tasks")
|
|
102
|
+
* .withSearchIndex("search_title", (q) =>
|
|
103
|
+
* q.search("title", searchText).eq("status", "todo")
|
|
104
|
+
* )
|
|
105
|
+
* .collect();
|
|
106
|
+
* ```
|
|
46
107
|
*/
|
|
47
|
-
searchIndex(name:
|
|
48
|
-
searchField:
|
|
49
|
-
filterFields?:
|
|
50
|
-
}):
|
|
108
|
+
searchIndex<const TIndexName extends string, TSearchField extends FieldPaths<TValidator>, TFilterField extends FieldPaths<TValidator> = never>(name: TIndexName, config: {
|
|
109
|
+
searchField: TSearchField;
|
|
110
|
+
filterFields?: TFilterField[];
|
|
111
|
+
}): TableDefinition<TValidator, TIndexes, Expand<TSearchIndexes & Record<TIndexName, {
|
|
112
|
+
searchField: TSearchField;
|
|
113
|
+
filterFields: TFilterField;
|
|
114
|
+
}>>>;
|
|
115
|
+
parse(value: unknown): Infer<TValidator>;
|
|
116
|
+
serialize(value: Infer<TValidator>): InferStorage<TValidator>;
|
|
117
|
+
deserialize(value: unknown): Infer<TValidator>;
|
|
118
|
+
parseAndSerialize(value: unknown): InferStorage<TValidator>;
|
|
119
|
+
describe(): ValidatorDescription;
|
|
51
120
|
}
|
|
52
|
-
type AnyTableDefinition = TableDefinition<Validator<unknown
|
|
121
|
+
type AnyTableDefinition = TableDefinition<Validator<Record<string, unknown>, Record<string, unknown>, string>, GenericTableIndexes, GenericTableSearchIndexes>;
|
|
53
122
|
type InferDocument<TTable extends AnyTableDefinition> = Infer<TTable["validator"]> & TableDocumentSystemFields;
|
|
54
|
-
type InferTableInput<TTable extends AnyTableDefinition> =
|
|
123
|
+
type InferTableInput<TTable extends AnyTableDefinition> = Infer<TTable["validator"]>;
|
|
124
|
+
type TableFieldPaths<TTable> = TTable extends TableDefinition<infer TValidator, unknown, unknown> ? FieldPaths<TValidator> : never;
|
|
125
|
+
type TableIndexes<TTable> = TTable extends TableDefinition<Validator<Record<string, unknown>, Record<string, unknown>, string>, infer TIndexes, unknown> ? TIndexes : never;
|
|
126
|
+
type TableSearchIndexes<TTable> = TTable extends TableDefinition<Validator<Record<string, unknown>, Record<string, unknown>, string>, unknown, infer TSearchIndexes> ? TSearchIndexes : never;
|
|
127
|
+
type TableIndexNames<TTable> = Extract<keyof TableIndexes<TTable>, string>;
|
|
128
|
+
type TableSearchIndexNames<TTable> = Extract<keyof TableSearchIndexes<TTable>, string>;
|
|
129
|
+
type TableIndexFields<TTable, TIndexName extends TableIndexNames<TTable>> = TableIndexes<TTable>[TIndexName];
|
|
130
|
+
type TableSearchIndexConfig<TTable, TIndexName extends TableSearchIndexNames<TTable>> = TableSearchIndexes<TTable>[TIndexName];
|
|
131
|
+
type TableFieldDefinitionSummary = {
|
|
132
|
+
name: string;
|
|
133
|
+
validator: ReturnType<AnyTableDefinition["describe"]>;
|
|
134
|
+
storage: ReturnType<AnyTableDefinition["describe"]>;
|
|
135
|
+
optional: boolean;
|
|
136
|
+
};
|
|
55
137
|
/**
|
|
56
|
-
* Define a table
|
|
138
|
+
* Define a Syncore table by specifying its field validators.
|
|
57
139
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
140
|
+
* `defineTable` is the building block of your data model. Pass a validator map
|
|
141
|
+
* (keys are field names, values are `s.*` validators) or a single `s.object()`
|
|
142
|
+
* validator. Chain `.index()` and `.searchIndex()` to register query indexes.
|
|
143
|
+
*
|
|
144
|
+
* The system fields `_id` and `_creationTime` are added automatically and
|
|
145
|
+
* should not be included in the shape.
|
|
60
146
|
*
|
|
61
|
-
* @example
|
|
62
147
|
* ```ts
|
|
148
|
+
* import { defineTable, s } from "syncorejs";
|
|
149
|
+
*
|
|
63
150
|
* const tasks = defineTable({
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
151
|
+
* title: s.string(),
|
|
152
|
+
* status: s.enum(["todo", "done"] as const),
|
|
153
|
+
* projectId: s.nullable(s.id("projects")),
|
|
154
|
+
* dueAt: s.optional(s.number()),
|
|
155
|
+
* })
|
|
156
|
+
* .index("by_project", ["projectId"])
|
|
157
|
+
* .index("by_status", ["status"])
|
|
158
|
+
* .searchIndex("search_title", { searchField: "title", filterFields: ["status"] });
|
|
67
159
|
* ```
|
|
68
160
|
*/
|
|
69
|
-
declare function defineTable<TShape extends ObjectValidatorShape>(validator: TShape): TableDefinition<ObjectValidator<TShape>>;
|
|
70
|
-
declare function defineTable<TValidator extends Validator<unknown>>(validator: TValidator): TableDefinition<TValidator>;
|
|
161
|
+
declare function defineTable<const TShape extends ObjectValidatorShape>(validator: TShape): TableDefinition<ObjectValidator<TShape>>;
|
|
162
|
+
declare function defineTable<TValidator extends Validator<Record<string, unknown>, Record<string, unknown>, string>>(validator: TValidator): TableDefinition<TValidator>;
|
|
71
163
|
interface SyncoreSchemaDefinition {
|
|
72
164
|
[tableName: string]: AnyTableDefinition;
|
|
73
165
|
}
|
|
74
|
-
|
|
166
|
+
/**
|
|
167
|
+
* The typed data model produced by {@link defineSchema}.
|
|
168
|
+
*
|
|
169
|
+
* `SyncoreSchema` holds the table map and is the value you export from
|
|
170
|
+
* `syncore/schema.ts`. The runtime, context types, and codegen all reference
|
|
171
|
+
* this type to ensure end-to-end type safety between your schema definition
|
|
172
|
+
* and your function handlers.
|
|
173
|
+
*/
|
|
174
|
+
declare class SyncoreSchema<TTables> {
|
|
75
175
|
readonly tables: TTables;
|
|
76
176
|
constructor(tables: TTables);
|
|
77
177
|
getTable<TTableName extends Extract<keyof TTables, string>>(tableName: TTableName): TTables[TTableName];
|
|
78
178
|
tableNames(): Array<Extract<keyof TTables, string>>;
|
|
79
179
|
}
|
|
80
180
|
/**
|
|
81
|
-
* Define the
|
|
181
|
+
* Define the complete data model for a Syncore app.
|
|
82
182
|
*
|
|
83
|
-
*
|
|
183
|
+
* Pass an object whose keys are table names and values are `defineTable()`
|
|
184
|
+
* results. The resulting schema is passed to the runtime options and to the
|
|
185
|
+
* code generator.
|
|
186
|
+
*
|
|
187
|
+
* **Typical file: `syncore/schema.ts`**
|
|
84
188
|
*
|
|
85
|
-
* @example
|
|
86
189
|
* ```ts
|
|
190
|
+
* import { defineSchema, defineTable, s } from "syncorejs";
|
|
191
|
+
*
|
|
87
192
|
* export default defineSchema({
|
|
88
193
|
* tasks: defineTable({
|
|
89
|
-
*
|
|
90
|
-
*
|
|
194
|
+
* title: s.string(),
|
|
195
|
+
* status: s.enum(["todo", "done"] as const),
|
|
196
|
+
* projectId: s.nullable(s.id("projects")),
|
|
91
197
|
* })
|
|
198
|
+
* .index("by_project", ["projectId"]),
|
|
199
|
+
*
|
|
200
|
+
* projects: defineTable({
|
|
201
|
+
* name: s.string(),
|
|
202
|
+
* archivedAt: s.optional(s.number()),
|
|
203
|
+
* }),
|
|
92
204
|
* });
|
|
93
205
|
* ```
|
|
206
|
+
*
|
|
207
|
+
* @param tables - A map of table names to their `TableDefinition` values.
|
|
94
208
|
*/
|
|
95
|
-
declare function defineSchema<TTables extends SyncoreSchemaDefinition>(tables: TTables): SyncoreSchema<TTables>;
|
|
209
|
+
declare function defineSchema<const TTables extends SyncoreSchemaDefinition>(tables: TTables): SyncoreSchema<TTables>;
|
|
96
210
|
//#endregion
|
|
97
|
-
export { AnyTableDefinition, IndexDefinition, InferDocument, InferTableInput, SearchIndexDefinition, SyncoreSchema, SyncoreSchemaDefinition, TableDefinition, TableDefinitionOptions, TableDocumentSystemFields, defineSchema, defineTable };
|
|
211
|
+
export { AnyTableDefinition, GenericTableIndexes, GenericTableSearchIndexes, IndexDefinition, InferDocument, InferTableInput, SearchIndexDefinition, SyncoreSchema, SyncoreSchemaDefinition, TableDefinition, TableDefinitionOptions, TableDocumentSystemFields, TableFieldDefinitionSummary, TableFieldPaths, TableIndexFields, TableIndexNames, TableIndexes, TableSearchIndexConfig, TableSearchIndexNames, TableSearchIndexes, defineSchema, defineTable };
|
|
98
212
|
//# sourceMappingURL=definition.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","names":[],"sources":["../src/definition.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"definition.d.ts","names":[],"sources":["../src/definition.ts"],"mappings":";;;KAaK,MAAA,uBAA6B,CAAA,GAAI,CAAA,CAAE,IAAA;AAAA,UAEvB,eAAA;EACf,IAAA;EACA,MAAM;AAAA;AAAA,UAGS,qBAAA;EACf,IAAA;EACA,WAAA;EACA,YAAA;AAAA;AAAA,UAGe,sBAAA;EACf,SAAA;EACA,aAAA;EACA,aAAA;AAAA;AAdF;;;;AAEQ;AAGR;;;AALA,UAyBiB,yBAAA;EACf,GAAA;EACA,aAAa;AAAA;AAAA,KAGH,mBAAA,GAAsB,MAAM;AAAA,KAE5B,yBAAA,GAA4B,MAAM;EAG1C,WAAA;EACA,YAAA;AAAA;;;;;;AAtBW;AAWf;;;;AAEe;AAGf;cAsBa,eAAA,oBACQ,SAAA,CAAU,MAAA,mBAAyB,MAAA,uCAC3C,MAAA,iCACM,MAAA;EAAA,SAaC,SAAA,EAAW,UAAA;EAAA,SAXpB,OAAA,EAAS,eAAA;EAAA,SACT,aAAA,EAAe,qBAAA;EAAA,SACf,OAAA,EAAS,sBAAA;EAAA,SAED,QAAA,EAAU,KAAA,CAAM,UAAA;EAAA,SAChB,eAAA,EAAiB,YAAA,CAAa,UAAA;EAAA,SAC9B,UAAA,EAAY,UAAA,CAAW,UAAA;EAAA,SACvB,aAAA,EAAe,QAAA;EAAA,SACf,mBAAA,EAAqB,cAAA;cAGpB,SAAA,EAAW,UAAA,EAC3B,OAAA,GAAU,sBAAA;EAjCE;AAAA;AAgBhB;;;;;;;;;;;;;;;;;;EA0CE,KAAA,sDAEsB,UAAA,CAAW,UAAA,uBACX,UAAA,CAAW,UAAA,IAAA,CAE/B,IAAA,EAAM,UAAA,EACN,MAAA,GAAS,WAAA,KAAgB,WAAA,IACxB,eAAA,CACD,UAAA,EACA,MAAA,CAAO,QAAA,GAAW,MAAA,CAAO,UAAA,YAAsB,WAAA,KAAgB,WAAA,KAC/D,cAAA;EAvCoC;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgFtC,WAAA,uDAEuB,UAAA,CAAW,UAAA,wBACX,UAAA,CAAW,UAAA,UAAA,CAEhC,IAAA,EAAM,UAAA,EACN,MAAA;IACE,WAAA,EAAa,YAAA;IACb,YAAA,GAAe,YAAA;EAAA,IAEhB,eAAA,CACD,UAAA,EACA,QAAA,EACA,MAAA,CACE,cAAA,GACE,MAAA,CACE,UAAA;IAEE,WAAA,EAAa,YAAA;IACb,YAAA,EAAc,YAAA;EAAA;EA0BxB,KAAA,CAAM,KAAA,YAAiB,KAAA,CAAM,UAAA;EAI7B,SAAA,CAAU,KAAA,EAAO,KAAA,CAAM,UAAA,IAAc,YAAA,CAAa,UAAA;EAIlD,WAAA,CAAY,KAAA,YAAiB,KAAA,CAAM,UAAA;EAInC,iBAAA,CAAkB,KAAA,YAAiB,YAAA,CAAa,UAAA;EAIhD,QAAA,CAAA,GAJ+C,oBAAA;AAAA;AAAA,KASrC,kBAAA,GAAqB,eAAA,CAC/B,SAAA,CAAU,MAAA,mBAAyB,MAAA,4BACnC,mBAAA,EACA,yBAAA;AAAA,KAGU,aAAA,gBAA6B,kBAAA,IAAsB,KAAA,CAC7D,MAAA,iBAEA,yBAAA;AAAA,KAEU,eAAA,gBAA+B,kBAAA,IAAsB,KAAA,CAC/D,MAAA;AAAA,KAGU,eAAA,WAA0B,MAAA,SAAe,eAAA,uCAKjD,UAAA,CAAW,UAAA;AAAA,KAGH,YAAA,WAAuB,MAAA,SAAe,eAAA,CAChD,SAAA,CAAU,MAAA,mBAAyB,MAAA,uDAIjC,QAAA;AAAA,KAGQ,kBAAA,WAA6B,MAAA,SAAe,eAAA,CACtD,SAAA,CAAU,MAAA,mBAAyB,MAAA,6DAIjC,cAAA;AAAA,KAGQ,eAAA,WAA0B,OAAA,OAC9B,YAAA,CAAa,MAAA;AAAA,KAIT,qBAAA,WAAgC,OAAA,OACpC,kBAAA,CAAmB,MAAA;AAAA,KAIf,gBAAA,4BAES,eAAA,CAAgB,MAAA,KACjC,YAAA,CAAa,MAAA,EAAQ,UAAA;AAAA,KAEb,sBAAA,4BAES,qBAAA,CAAsB,MAAA,KACvC,kBAAA,CAAmB,MAAA,EAAQ,UAAA;AAAA,KAEnB,2BAAA;EACV,IAAA;EACA,SAAA,EAAW,UAAA,CAAW,kBAAA;EACtB,OAAA,EAAS,UAAA,CAAW,kBAAA;EACpB,QAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;iBA2Bc,WAAA,sBAAiC,oBAAA,CAAA,CAC/C,SAAA,EAAW,MAAA,GACV,eAAA,CAAgB,eAAA,CAAgB,MAAA;AAAA,iBACnB,WAAA,oBACK,SAAA,CAAU,MAAA,mBAAyB,MAAA,2BAAA,CACtD,SAAA,EAAW,UAAA,GAAa,eAAA,CAAgB,UAAA;AAAA,UAezB,uBAAA;EAAA,CACd,SAAA,WAAoB,kBAAkB;AAAA;;;;;;;;;cAW5B,aAAA;EAAA,SACiB,MAAA,EAAQ,OAAA;cAAR,MAAA,EAAQ,OAAA;EAEpC,QAAA,oBAA4B,OAAA,OAAc,OAAA,UAAA,CACxC,SAAA,EAAW,UAAA,GACV,OAAA,CAAQ,UAAA;EASX,UAAA,CAAA,GAAc,KAAA,CAAM,OAAA,OAAc,OAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoCpB,YAAA,uBAAmC,uBAAA,CAAA,CACjD,MAAA,EAAQ,OAAA,GACP,aAAA,CAAc,OAAA"}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
import { ensureObjectValidator } from "./validators.js";
|
|
1
|
+
import { describeValidator, deserializeValue, ensureObjectValidator, serializeValue } from "./validators.js";
|
|
2
2
|
//#region src/definition.ts
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* A typed table definition that describes the shape, indexes, and search
|
|
5
|
+
* indexes for a single Syncore table.
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
7
|
+
* You create `TableDefinition` instances with {@link defineTable} and attach
|
|
8
|
+
* indexes with the fluent `.index()` and `.searchIndex()` methods. The type
|
|
9
|
+
* parameters track the validator shape, registered indexes, and search indexes
|
|
10
|
+
* so that {@link QueryBuilder} can enforce correct field names at compile time.
|
|
11
|
+
*
|
|
12
|
+
* You almost never reference `TableDefinition` directly — it is the value
|
|
13
|
+
* produced by `defineTable` and consumed internally by `defineSchema`.
|
|
8
14
|
*/
|
|
9
15
|
var TableDefinition = class {
|
|
16
|
+
validator;
|
|
10
17
|
indexes = [];
|
|
11
18
|
searchIndexes = [];
|
|
12
19
|
options;
|
|
@@ -15,39 +22,97 @@ var TableDefinition = class {
|
|
|
15
22
|
this.options = options ?? {};
|
|
16
23
|
}
|
|
17
24
|
/**
|
|
18
|
-
*
|
|
25
|
+
* Register a named index on one or more fields of this table.
|
|
26
|
+
*
|
|
27
|
+
* Indexes allow efficient range queries via `ctx.db.query(table).withIndex()`.
|
|
28
|
+
* The first field listed is the primary sort key; additional fields refine
|
|
29
|
+
* within equal values of the first key.
|
|
30
|
+
*
|
|
31
|
+
* **Rules**
|
|
32
|
+
* - An index must cover at least one field.
|
|
33
|
+
* - Field names must be top-level paths that exist in the table validator.
|
|
34
|
+
* - Index names must be unique within the table.
|
|
35
|
+
* - Index definitions are immutable after creation — changing the fields of
|
|
36
|
+
* an existing index requires a manual migration.
|
|
19
37
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
38
|
+
* ```ts
|
|
39
|
+
* defineTable({ status: s.string(), createdAt: s.number(), ownerId: s.string() })
|
|
40
|
+
* .index("by_owner_and_status", ["ownerId", "status"])
|
|
41
|
+
* .index("by_created", ["createdAt"])
|
|
42
|
+
* ```
|
|
23
43
|
*/
|
|
24
44
|
index(name, fields) {
|
|
25
45
|
this.indexes.push({
|
|
26
46
|
name,
|
|
27
|
-
fields
|
|
47
|
+
fields: [...fields]
|
|
28
48
|
});
|
|
29
49
|
return this;
|
|
30
50
|
}
|
|
31
51
|
/**
|
|
32
|
-
*
|
|
52
|
+
* Register a named full-text search index on this table.
|
|
53
|
+
*
|
|
54
|
+
* Search indexes power `ctx.db.query(table).withSearchIndex()` queries. Each
|
|
55
|
+
* search index specifies:
|
|
56
|
+
* - A single `searchField` that is tokenised and indexed for full-text
|
|
57
|
+
* matching.
|
|
58
|
+
* - Zero or more `filterFields` that can be used to narrow results with
|
|
59
|
+
* equality conditions.
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* defineTable({ title: s.string(), status: s.string(), ownerId: s.string() })
|
|
63
|
+
* .searchIndex("search_title", {
|
|
64
|
+
* searchField: "title",
|
|
65
|
+
* filterFields: ["status", "ownerId"],
|
|
66
|
+
* })
|
|
67
|
+
* ```
|
|
33
68
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
69
|
+
* In a query handler:
|
|
70
|
+
* ```ts
|
|
71
|
+
* const results = await ctx.db
|
|
72
|
+
* .query("tasks")
|
|
73
|
+
* .withSearchIndex("search_title", (q) =>
|
|
74
|
+
* q.search("title", searchText).eq("status", "todo")
|
|
75
|
+
* )
|
|
76
|
+
* .collect();
|
|
77
|
+
* ```
|
|
37
78
|
*/
|
|
38
79
|
searchIndex(name, config) {
|
|
39
80
|
this.searchIndexes.push({
|
|
40
81
|
name,
|
|
41
82
|
searchField: config.searchField,
|
|
42
|
-
filterFields: config.filterFields ?? []
|
|
83
|
+
filterFields: [...config.filterFields ?? []]
|
|
43
84
|
});
|
|
44
85
|
return this;
|
|
45
86
|
}
|
|
87
|
+
parse(value) {
|
|
88
|
+
return this.validator.parse(value);
|
|
89
|
+
}
|
|
90
|
+
serialize(value) {
|
|
91
|
+
return serializeValue(this.validator, value);
|
|
92
|
+
}
|
|
93
|
+
deserialize(value) {
|
|
94
|
+
return deserializeValue(this.validator, value);
|
|
95
|
+
}
|
|
96
|
+
parseAndSerialize(value) {
|
|
97
|
+
return this.serialize(this.parse(value));
|
|
98
|
+
}
|
|
99
|
+
describe() {
|
|
100
|
+
return describeValidator(this.validator);
|
|
101
|
+
}
|
|
46
102
|
};
|
|
47
103
|
function defineTable(validator) {
|
|
48
|
-
return new TableDefinition(ensureObjectValidator(validator));
|
|
104
|
+
return new TableDefinition(isValidatorLike(validator) ? validator : ensureObjectValidator(validator));
|
|
49
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* The typed data model produced by {@link defineSchema}.
|
|
108
|
+
*
|
|
109
|
+
* `SyncoreSchema` holds the table map and is the value you export from
|
|
110
|
+
* `syncore/schema.ts`. The runtime, context types, and codegen all reference
|
|
111
|
+
* this type to ensure end-to-end type safety between your schema definition
|
|
112
|
+
* and your function handlers.
|
|
113
|
+
*/
|
|
50
114
|
var SyncoreSchema = class {
|
|
115
|
+
tables;
|
|
51
116
|
constructor(tables) {
|
|
52
117
|
this.tables = tables;
|
|
53
118
|
}
|
|
@@ -61,23 +126,40 @@ var SyncoreSchema = class {
|
|
|
61
126
|
}
|
|
62
127
|
};
|
|
63
128
|
/**
|
|
64
|
-
* Define the
|
|
129
|
+
* Define the complete data model for a Syncore app.
|
|
130
|
+
*
|
|
131
|
+
* Pass an object whose keys are table names and values are `defineTable()`
|
|
132
|
+
* results. The resulting schema is passed to the runtime options and to the
|
|
133
|
+
* code generator.
|
|
65
134
|
*
|
|
66
|
-
*
|
|
135
|
+
* **Typical file: `syncore/schema.ts`**
|
|
67
136
|
*
|
|
68
|
-
* @example
|
|
69
137
|
* ```ts
|
|
138
|
+
* import { defineSchema, defineTable, s } from "syncorejs";
|
|
139
|
+
*
|
|
70
140
|
* export default defineSchema({
|
|
71
141
|
* tasks: defineTable({
|
|
72
|
-
*
|
|
73
|
-
*
|
|
142
|
+
* title: s.string(),
|
|
143
|
+
* status: s.enum(["todo", "done"] as const),
|
|
144
|
+
* projectId: s.nullable(s.id("projects")),
|
|
74
145
|
* })
|
|
146
|
+
* .index("by_project", ["projectId"]),
|
|
147
|
+
*
|
|
148
|
+
* projects: defineTable({
|
|
149
|
+
* name: s.string(),
|
|
150
|
+
* archivedAt: s.optional(s.number()),
|
|
151
|
+
* }),
|
|
75
152
|
* });
|
|
76
153
|
* ```
|
|
154
|
+
*
|
|
155
|
+
* @param tables - A map of table names to their `TableDefinition` values.
|
|
77
156
|
*/
|
|
78
157
|
function defineSchema(tables) {
|
|
79
158
|
return new SyncoreSchema(tables);
|
|
80
159
|
}
|
|
160
|
+
function isValidatorLike(value) {
|
|
161
|
+
return typeof value.parse === "function";
|
|
162
|
+
}
|
|
81
163
|
//#endregion
|
|
82
164
|
export { SyncoreSchema, TableDefinition, defineSchema, defineTable };
|
|
83
165
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.js","names":[],"sources":["../src/definition.ts"],"sourcesContent":["import {\n ensureObjectValidator,\n type Infer,\n type ObjectValidatorShape,\n type Validator\n} from \"./validators.js\";\nimport type { ObjectValidator } from \"./validators.js\";\n\nexport interface IndexDefinition {\n name: string;\n fields: string[];\n}\n\nexport interface SearchIndexDefinition {\n name: string;\n searchField: string;\n filterFields: string[];\n}\n\nexport interface TableDefinitionOptions {\n tableName?: string;\n}\n\nexport interface TableDocumentSystemFields {\n _id: string;\n _creationTime: number;\n}\n\n/**\n * Describes a Syncore table and its indexes.\n *\n * Create tables with {@link defineTable} and then chain index helpers to make\n * queries faster and more expressive.\n */\nexport class TableDefinition<TValidator extends Validator<unknown>> {\n readonly indexes: IndexDefinition[] = [];\n readonly searchIndexes: SearchIndexDefinition[] = [];\n readonly options: TableDefinitionOptions;\n\n constructor(\n public readonly validator: TValidator,\n options?: TableDefinitionOptions\n ) {\n this.options = options ?? {};\n }\n\n /**\n * Add a named index for querying a table by one or more fields.\n *\n * @param name - The index name used from `ctx.db.query(...).withIndex(...)`.\n * @param fields - The fields that participate in the index.\n * @returns The same table definition for chaining.\n */\n index(name: string, fields: string[]): this {\n this.indexes.push({ name, fields });\n return this;\n }\n\n /**\n * Add a search index for text search.\n *\n * @param name - The search index name used from `withSearchIndex(...)`.\n * @param config - The indexed search field and optional filter fields.\n * @returns The same table definition for chaining.\n */\n searchIndex(\n name: string,\n config: { searchField: string; filterFields?: string[] }\n ): this {\n this.searchIndexes.push({\n name,\n searchField: config.searchField,\n filterFields: config.filterFields ?? []\n });\n return this;\n }\n}\n\nexport type AnyTableDefinition = TableDefinition<Validator<unknown>>;\n\nexport type InferDocument<TTable extends AnyTableDefinition> = Infer<\n TTable[\"validator\"]\n> &\n TableDocumentSystemFields;\n\nexport type InferTableInput<TTable extends AnyTableDefinition> = Omit<\n InferDocument<TTable>,\n keyof TableDocumentSystemFields\n>;\n\n/**\n * Define a table in a Syncore schema.\n *\n * Pass an object of validators describing the document fields stored in the\n * table. Chain `.index(...)` or `.searchIndex(...)` to add query helpers.\n *\n * @example\n * ```ts\n * const tasks = defineTable({\n * text: v.string(),\n * done: v.boolean()\n * }).index(\"by_done\", [\"done\"]);\n * ```\n */\nexport function defineTable<TShape extends ObjectValidatorShape>(\n validator: TShape\n): TableDefinition<ObjectValidator<TShape>>;\nexport function defineTable<TValidator extends Validator<unknown>>(\n validator: TValidator\n): TableDefinition<TValidator>;\nexport function defineTable<TShape extends ObjectValidatorShape>(\n validator: TShape | Validator<unknown>\n): TableDefinition<Validator<unknown>> {\n return new TableDefinition(ensureObjectValidator(validator));\n}\n\nexport interface SyncoreSchemaDefinition {\n [tableName: string]: AnyTableDefinition;\n}\n\nexport class SyncoreSchema<TTables extends SyncoreSchemaDefinition> {\n constructor(public readonly tables: TTables) {}\n\n getTable<TTableName extends Extract<keyof TTables, string>>(\n tableName: TTableName\n ): TTables[TTableName] {\n const table = this.tables[tableName];\n if (!table) {\n throw new Error(`Unknown table \"${tableName}\".`);\n }\n return table;\n }\n\n tableNames(): Array<Extract<keyof TTables, string>> {\n return Object.keys(this.tables) as Array<Extract<keyof TTables, string>>;\n }\n}\n\n/**\n * Define the tables that make up your Syncore app.\n *\n * The returned schema is used by runtimes, code generation, and type inference.\n *\n * @example\n * ```ts\n * export default defineSchema({\n * tasks: defineTable({\n * text: v.string(),\n * done: v.boolean()\n * })\n * });\n * ```\n */\nexport function defineSchema<TTables extends SyncoreSchemaDefinition>(\n tables: TTables\n): SyncoreSchema<TTables> {\n return new SyncoreSchema(tables);\n}\n"],"mappings":";;;;;;;;AAkCA,IAAa,kBAAb,MAAoE;CAClE,UAAsC,EAAE;CACxC,gBAAkD,EAAE;CACpD;CAEA,YACE,WACA,SACA;AAFgB,OAAA,YAAA;AAGhB,OAAK,UAAU,WAAW,EAAE;;;;;;;;;CAU9B,MAAM,MAAc,QAAwB;AAC1C,OAAK,QAAQ,KAAK;GAAE;GAAM;GAAQ,CAAC;AACnC,SAAO;;;;;;;;;CAUT,YACE,MACA,QACM;AACN,OAAK,cAAc,KAAK;GACtB;GACA,aAAa,OAAO;GACpB,cAAc,OAAO,gBAAgB,EAAE;GACxC,CAAC;AACF,SAAO;;;AAoCX,SAAgB,YACd,WACqC;AACrC,QAAO,IAAI,gBAAgB,sBAAsB,UAAU,CAAC;;AAO9D,IAAa,gBAAb,MAAoE;CAClE,YAAY,QAAiC;AAAjB,OAAA,SAAA;;CAE5B,SACE,WACqB;EACrB,MAAM,QAAQ,KAAK,OAAO;AAC1B,MAAI,CAAC,MACH,OAAM,IAAI,MAAM,kBAAkB,UAAU,IAAI;AAElD,SAAO;;CAGT,aAAoD;AAClD,SAAO,OAAO,KAAK,KAAK,OAAO;;;;;;;;;;;;;;;;;;AAmBnC,SAAgB,aACd,QACwB;AACxB,QAAO,IAAI,cAAc,OAAO"}
|
|
1
|
+
{"version":3,"file":"definition.js","names":[],"sources":["../src/definition.ts"],"sourcesContent":["import {\n describeValidator,\n deserializeValue,\n ensureObjectValidator,\n serializeValue,\n type FieldPaths,\n type Infer,\n type InferStorage,\n type ObjectValidator,\n type ObjectValidatorShape,\n type Validator\n} from \"./validators.js\";\n\ntype Expand<T> = { [TKey in keyof T]: T[TKey] } & {};\n\nexport interface IndexDefinition {\n name: string;\n fields: string[];\n}\n\nexport interface SearchIndexDefinition {\n name: string;\n searchField: string;\n filterFields: string[];\n}\n\nexport interface TableDefinitionOptions {\n tableName?: string;\n componentPath?: string;\n componentName?: string;\n}\n\n/**\n * The built-in system fields automatically added to every Syncore document.\n *\n * You never supply these when inserting; Syncore sets them for you.\n * - `_id` — A unique string identifier for the document. Use `s.id(tableName)` to\n * type foreign-key fields that reference this value.\n * - `_creationTime` — Unix timestamp (milliseconds) when the document was inserted.\n */\nexport interface TableDocumentSystemFields {\n _id: string;\n _creationTime: number;\n}\n\nexport type GenericTableIndexes = Record<string, readonly string[]>;\n\nexport type GenericTableSearchIndexes = Record<\n string,\n {\n searchField: string;\n filterFields: string;\n }\n>;\n\n/**\n * A typed table definition that describes the shape, indexes, and search\n * indexes for a single Syncore table.\n *\n * You create `TableDefinition` instances with {@link defineTable} and attach\n * indexes with the fluent `.index()` and `.searchIndex()` methods. The type\n * parameters track the validator shape, registered indexes, and search indexes\n * so that {@link QueryBuilder} can enforce correct field names at compile time.\n *\n * You almost never reference `TableDefinition` directly — it is the value\n * produced by `defineTable` and consumed internally by `defineSchema`.\n */\nexport class TableDefinition<\n TValidator extends Validator<Record<string, unknown>, Record<string, unknown>, string>,\n TIndexes = Record<never, never>,\n TSearchIndexes = Record<never, never>\n> {\n readonly indexes: IndexDefinition[] = [];\n readonly searchIndexes: SearchIndexDefinition[] = [];\n readonly options: TableDefinitionOptions;\n\n declare readonly document: Infer<TValidator>;\n declare readonly storageDocument: InferStorage<TValidator>;\n declare readonly fieldPaths: FieldPaths<TValidator>;\n declare readonly indexesByName: TIndexes;\n declare readonly searchIndexesByName: TSearchIndexes;\n\n constructor(\n public readonly validator: TValidator,\n options?: TableDefinitionOptions\n ) {\n this.options = options ?? {};\n }\n\n /**\n * Register a named index on one or more fields of this table.\n *\n * Indexes allow efficient range queries via `ctx.db.query(table).withIndex()`.\n * The first field listed is the primary sort key; additional fields refine\n * within equal values of the first key.\n *\n * **Rules**\n * - An index must cover at least one field.\n * - Field names must be top-level paths that exist in the table validator.\n * - Index names must be unique within the table.\n * - Index definitions are immutable after creation — changing the fields of\n * an existing index requires a manual migration.\n *\n * ```ts\n * defineTable({ status: s.string(), createdAt: s.number(), ownerId: s.string() })\n * .index(\"by_owner_and_status\", [\"ownerId\", \"status\"])\n * .index(\"by_created\", [\"createdAt\"])\n * ```\n */\n index<\n const TIndexName extends string,\n TFirstField extends FieldPaths<TValidator>,\n TRestFields extends FieldPaths<TValidator>[]\n >(\n name: TIndexName,\n fields: [TFirstField, ...TRestFields]\n ): TableDefinition<\n TValidator,\n Expand<TIndexes & Record<TIndexName, readonly [TFirstField, ...TRestFields]>>,\n TSearchIndexes\n > {\n this.indexes.push({\n name,\n fields: [...fields]\n });\n return this as unknown as TableDefinition<\n TValidator,\n Expand<TIndexes & Record<TIndexName, readonly [TFirstField, ...TRestFields]>>,\n TSearchIndexes\n >;\n }\n\n /**\n * Register a named full-text search index on this table.\n *\n * Search indexes power `ctx.db.query(table).withSearchIndex()` queries. Each\n * search index specifies:\n * - A single `searchField` that is tokenised and indexed for full-text\n * matching.\n * - Zero or more `filterFields` that can be used to narrow results with\n * equality conditions.\n *\n * ```ts\n * defineTable({ title: s.string(), status: s.string(), ownerId: s.string() })\n * .searchIndex(\"search_title\", {\n * searchField: \"title\",\n * filterFields: [\"status\", \"ownerId\"],\n * })\n * ```\n *\n * In a query handler:\n * ```ts\n * const results = await ctx.db\n * .query(\"tasks\")\n * .withSearchIndex(\"search_title\", (q) =>\n * q.search(\"title\", searchText).eq(\"status\", \"todo\")\n * )\n * .collect();\n * ```\n */\n searchIndex<\n const TIndexName extends string,\n TSearchField extends FieldPaths<TValidator>,\n TFilterField extends FieldPaths<TValidator> = never\n >(\n name: TIndexName,\n config: {\n searchField: TSearchField;\n filterFields?: TFilterField[];\n }\n ): TableDefinition<\n TValidator,\n TIndexes,\n Expand<\n TSearchIndexes &\n Record<\n TIndexName,\n {\n searchField: TSearchField;\n filterFields: TFilterField;\n }\n >\n >\n > {\n this.searchIndexes.push({\n name,\n searchField: config.searchField,\n filterFields: [...(config.filterFields ?? [])]\n });\n return this as unknown as TableDefinition<\n TValidator,\n TIndexes,\n Expand<\n TSearchIndexes &\n Record<\n TIndexName,\n {\n searchField: TSearchField;\n filterFields: TFilterField;\n }\n >\n >\n >;\n }\n\n parse(value: unknown): Infer<TValidator> {\n return this.validator.parse(value) as Infer<TValidator>;\n }\n\n serialize(value: Infer<TValidator>): InferStorage<TValidator> {\n return serializeValue(this.validator, value) as InferStorage<TValidator>;\n }\n\n deserialize(value: unknown): Infer<TValidator> {\n return deserializeValue(this.validator, value) as Infer<TValidator>;\n }\n\n parseAndSerialize(value: unknown): InferStorage<TValidator> {\n return this.serialize(this.parse(value));\n }\n\n describe() {\n return describeValidator(this.validator);\n }\n}\n\nexport type AnyTableDefinition = TableDefinition<\n Validator<Record<string, unknown>, Record<string, unknown>, string>,\n GenericTableIndexes,\n GenericTableSearchIndexes\n>;\n\nexport type InferDocument<TTable extends AnyTableDefinition> = Infer<\n TTable[\"validator\"]\n> &\n TableDocumentSystemFields;\n\nexport type InferTableInput<TTable extends AnyTableDefinition> = Infer<\n TTable[\"validator\"]\n>;\n\nexport type TableFieldPaths<TTable> = TTable extends TableDefinition<\n infer TValidator,\n unknown,\n unknown\n>\n ? FieldPaths<TValidator>\n : never;\n\nexport type TableIndexes<TTable> = TTable extends TableDefinition<\n Validator<Record<string, unknown>, Record<string, unknown>, string>,\n infer TIndexes,\n unknown\n>\n ? TIndexes\n : never;\n\nexport type TableSearchIndexes<TTable> = TTable extends TableDefinition<\n Validator<Record<string, unknown>, Record<string, unknown>, string>,\n unknown,\n infer TSearchIndexes\n>\n ? TSearchIndexes\n : never;\n\nexport type TableIndexNames<TTable> = Extract<\n keyof TableIndexes<TTable>,\n string\n>;\n\nexport type TableSearchIndexNames<TTable> = Extract<\n keyof TableSearchIndexes<TTable>,\n string\n>;\n\nexport type TableIndexFields<\n TTable,\n TIndexName extends TableIndexNames<TTable>\n> = TableIndexes<TTable>[TIndexName];\n\nexport type TableSearchIndexConfig<\n TTable,\n TIndexName extends TableSearchIndexNames<TTable>\n> = TableSearchIndexes<TTable>[TIndexName];\n\nexport type TableFieldDefinitionSummary = {\n name: string;\n validator: ReturnType<AnyTableDefinition[\"describe\"]>;\n storage: ReturnType<AnyTableDefinition[\"describe\"]>;\n optional: boolean;\n};\n\n/**\n * Define a Syncore table by specifying its field validators.\n *\n * `defineTable` is the building block of your data model. Pass a validator map\n * (keys are field names, values are `s.*` validators) or a single `s.object()`\n * validator. Chain `.index()` and `.searchIndex()` to register query indexes.\n *\n * The system fields `_id` and `_creationTime` are added automatically and\n * should not be included in the shape.\n *\n * ```ts\n * import { defineTable, s } from \"syncorejs\";\n *\n * const tasks = defineTable({\n * title: s.string(),\n * status: s.enum([\"todo\", \"done\"] as const),\n * projectId: s.nullable(s.id(\"projects\")),\n * dueAt: s.optional(s.number()),\n * })\n * .index(\"by_project\", [\"projectId\"])\n * .index(\"by_status\", [\"status\"])\n * .searchIndex(\"search_title\", { searchField: \"title\", filterFields: [\"status\"] });\n * ```\n */\nexport function defineTable<const TShape extends ObjectValidatorShape>(\n validator: TShape\n): TableDefinition<ObjectValidator<TShape>>;\nexport function defineTable<\n TValidator extends Validator<Record<string, unknown>, Record<string, unknown>, string>\n>(validator: TValidator): TableDefinition<TValidator>;\nexport function defineTable<const TShape extends ObjectValidatorShape>(\n validator:\n | TShape\n | Validator<Record<string, unknown>, Record<string, unknown>, string>\n): TableDefinition<\n Validator<Record<string, unknown>, Record<string, unknown>, string>\n> {\n const normalized: Validator<Record<string, unknown>, Record<string, unknown>, string> =\n isValidatorLike(validator)\n ? validator\n : ensureObjectValidator(validator);\n return new TableDefinition(normalized);\n}\n\nexport interface SyncoreSchemaDefinition {\n [tableName: string]: AnyTableDefinition;\n}\n\n/**\n * The typed data model produced by {@link defineSchema}.\n *\n * `SyncoreSchema` holds the table map and is the value you export from\n * `syncore/schema.ts`. The runtime, context types, and codegen all reference\n * this type to ensure end-to-end type safety between your schema definition\n * and your function handlers.\n */\nexport class SyncoreSchema<TTables> {\n constructor(public readonly tables: TTables) {}\n\n getTable<TTableName extends Extract<keyof TTables, string>>(\n tableName: TTableName\n ): TTables[TTableName] {\n const tables = this.tables as Record<string, unknown>;\n const table = tables[tableName];\n if (!table) {\n throw new Error(`Unknown table \"${tableName}\".`);\n }\n return table as TTables[TTableName];\n }\n\n tableNames(): Array<Extract<keyof TTables, string>> {\n return Object.keys(this.tables as Record<string, unknown>) as Array<\n Extract<keyof TTables, string>\n >;\n }\n}\n\n/**\n * Define the complete data model for a Syncore app.\n *\n * Pass an object whose keys are table names and values are `defineTable()`\n * results. The resulting schema is passed to the runtime options and to the\n * code generator.\n *\n * **Typical file: `syncore/schema.ts`**\n *\n * ```ts\n * import { defineSchema, defineTable, s } from \"syncorejs\";\n *\n * export default defineSchema({\n * tasks: defineTable({\n * title: s.string(),\n * status: s.enum([\"todo\", \"done\"] as const),\n * projectId: s.nullable(s.id(\"projects\")),\n * })\n * .index(\"by_project\", [\"projectId\"]),\n *\n * projects: defineTable({\n * name: s.string(),\n * archivedAt: s.optional(s.number()),\n * }),\n * });\n * ```\n *\n * @param tables - A map of table names to their `TableDefinition` values.\n */\nexport function defineSchema<const TTables extends SyncoreSchemaDefinition>(\n tables: TTables\n): SyncoreSchema<TTables> {\n return new SyncoreSchema(tables);\n}\n\nfunction isValidatorLike(\n value: Validator<Record<string, unknown>, Record<string, unknown>, string> | ObjectValidatorShape\n): value is Validator<Record<string, unknown>, Record<string, unknown>, string> {\n return typeof (value as Validator<unknown, unknown, string>).parse === \"function\";\n}\n"],"mappings":";;;;;;;;;;;;;;AAmEA,IAAa,kBAAb,MAIE;CAYkB;CAXlB,UAAsC,CAAC;CACvC,gBAAkD,CAAC;CACnD;CAQA,YACE,WACA,SACA;EAFgB,KAAA,YAAA;EAGhB,KAAK,UAAU,WAAW,CAAC;CAC7B;;;;;;;;;;;;;;;;;;;;;CAsBA,MAKE,MACA,QAKA;EACA,KAAK,QAAQ,KAAK;GAChB;GACA,QAAQ,CAAC,GAAG,MAAM;EACpB,CAAC;EACD,OAAO;CAKT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BA,YAKE,MACA,QAiBA;EACA,KAAK,cAAc,KAAK;GACtB;GACA,aAAa,OAAO;GACpB,cAAc,CAAC,GAAI,OAAO,gBAAgB,CAAC,CAAE;EAC/C,CAAC;EACD,OAAO;CAcT;CAEA,MAAM,OAAmC;EACvC,OAAO,KAAK,UAAU,MAAM,KAAK;CACnC;CAEA,UAAU,OAAoD;EAC5D,OAAO,eAAe,KAAK,WAAW,KAAK;CAC7C;CAEA,YAAY,OAAmC;EAC7C,OAAO,iBAAiB,KAAK,WAAW,KAAK;CAC/C;CAEA,kBAAkB,OAA0C;EAC1D,OAAO,KAAK,UAAU,KAAK,MAAM,KAAK,CAAC;CACzC;CAEA,WAAW;EACT,OAAO,kBAAkB,KAAK,SAAS;CACzC;AACF;AAkGA,SAAgB,YACd,WAKA;CAKA,OAAO,IAAI,gBAHT,gBAAgB,SAAS,IACvB,YACA,sBAAsB,SAAS,CACE;AACvC;;;;;;;;;AAcA,IAAa,gBAAb,MAAoC;CACN;CAA5B,YAAY,QAAiC;EAAjB,KAAA,SAAA;CAAkB;CAE9C,SACE,WACqB;EAErB,MAAM,QADS,KAAK,OACC;EACrB,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,kBAAkB,UAAU,GAAG;EAEjD,OAAO;CACT;CAEA,aAAoD;EAClD,OAAO,OAAO,KAAK,KAAK,MAAiC;CAG3D;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,aACd,QACwB;CACxB,OAAO,IAAI,cAAc,MAAM;AACjC;AAEA,SAAS,gBACP,OAC8E;CAC9E,OAAO,OAAQ,MAA8C,UAAU;AACzE"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnyValidator, ArrayValidator, BooleanValidator, IdValidator, Infer, LiteralValidator, NullValidator, NumberValidator, ObjectValidator, ObjectValidatorShape, OptionalValidator, StringValidator, Validator, ValidatorBuilderApi, ValidatorDescription, ValidatorKind, ValidatorMap, describeValidator, ensureObjectValidator,
|
|
2
|
-
import { AnyTableDefinition, IndexDefinition, InferDocument, InferTableInput, SearchIndexDefinition, SyncoreSchema, SyncoreSchemaDefinition, TableDefinition, TableDefinitionOptions, TableDocumentSystemFields, defineSchema, defineTable } from "./definition.js";
|
|
3
|
-
import { SchemaMigrationPlan, SchemaSnapshot, TableSnapshot, createSchemaSnapshot, diffSchemaSnapshots, parseSchemaSnapshot, renderCreateIndexStatement, renderCreateSearchIndexStatement, renderCreateTableStatement, renderMigrationSql, searchIndexTableName } from "./planner.js";
|
|
4
|
-
export { AnyTableDefinition, AnyValidator, ArrayValidator, BooleanValidator, IdValidator, IndexDefinition, Infer, InferDocument, InferTableInput, LiteralValidator, NullValidator, NumberValidator, ObjectValidator, ObjectValidatorShape, OptionalValidator, SchemaMigrationPlan, SchemaSnapshot, SearchIndexDefinition, StringValidator, SyncoreSchema, SyncoreSchemaDefinition, TableDefinition, TableDefinitionOptions, TableDocumentSystemFields, TableSnapshot, Validator, ValidatorBuilderApi, ValidatorDescription, ValidatorKind, ValidatorMap, createSchemaSnapshot, defineSchema, defineTable, describeValidator, diffSchemaSnapshots, ensureObjectValidator, parseSchemaSnapshot, renderCreateIndexStatement, renderCreateSearchIndexStatement, renderCreateTableStatement, renderMigrationSql, searchIndexTableName,
|
|
1
|
+
import { AnyValidator, ArrayValidator, BooleanValidator, CodecValidator, EnumValidator, FieldPaths, IdValidator, Infer, InferStorage, JoinFieldPaths, LiteralValidator, NullValidator, NumberValidator, ObjectValidator, ObjectValidatorShape, OptionalValidator, RecordValidator, StringValidator, UnionValidator, Validator, ValidatorBuilderApi, ValidatorDescription, ValidatorKind, ValidatorMap, describeValidator, deserializeValue, ensureObjectValidator, isValidator, s, serializeValue } from "./validators.js";
|
|
2
|
+
import { AnyTableDefinition, GenericTableIndexes, GenericTableSearchIndexes, IndexDefinition, InferDocument, InferTableInput, SearchIndexDefinition, SyncoreSchema, SyncoreSchemaDefinition, TableDefinition, TableDefinitionOptions, TableDocumentSystemFields, TableFieldDefinitionSummary, TableFieldPaths, TableIndexFields, TableIndexNames, TableIndexes, TableSearchIndexConfig, TableSearchIndexNames, TableSearchIndexes, defineSchema, defineTable } from "./definition.js";
|
|
3
|
+
import { SchemaMigrationPlan, SchemaSnapshot, TableFieldSnapshot, TableSnapshot, createSchemaSnapshot, diffSchemaSnapshots, parseSchemaSnapshot, renderCreateIndexStatement, renderCreateSearchIndexStatement, renderCreateTableStatement, renderMigrationSql, searchIndexTableName } from "./planner.js";
|
|
4
|
+
export { AnyTableDefinition, AnyValidator, ArrayValidator, BooleanValidator, CodecValidator, EnumValidator, FieldPaths, GenericTableIndexes, GenericTableSearchIndexes, IdValidator, IndexDefinition, Infer, InferDocument, InferStorage, InferTableInput, JoinFieldPaths, LiteralValidator, NullValidator, NumberValidator, ObjectValidator, ObjectValidatorShape, OptionalValidator, RecordValidator, SchemaMigrationPlan, SchemaSnapshot, SearchIndexDefinition, StringValidator, SyncoreSchema, SyncoreSchemaDefinition, TableDefinition, TableDefinitionOptions, TableDocumentSystemFields, TableFieldDefinitionSummary, TableFieldPaths, TableFieldSnapshot, TableIndexFields, TableIndexNames, TableIndexes, TableSearchIndexConfig, TableSearchIndexNames, TableSearchIndexes, TableSnapshot, UnionValidator, Validator, ValidatorBuilderApi, ValidatorDescription, ValidatorKind, ValidatorMap, createSchemaSnapshot, defineSchema, defineTable, describeValidator, deserializeValue, diffSchemaSnapshots, ensureObjectValidator, isValidator, parseSchemaSnapshot, renderCreateIndexStatement, renderCreateSearchIndexStatement, renderCreateTableStatement, renderMigrationSql, s, searchIndexTableName, serializeValue };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnyValidator, ArrayValidator, BooleanValidator, IdValidator, LiteralValidator, NullValidator, NumberValidator, ObjectValidator, OptionalValidator, StringValidator, describeValidator, ensureObjectValidator,
|
|
1
|
+
import { AnyValidator, ArrayValidator, BooleanValidator, CodecValidator, EnumValidator, IdValidator, LiteralValidator, NullValidator, NumberValidator, ObjectValidator, OptionalValidator, RecordValidator, StringValidator, UnionValidator, describeValidator, deserializeValue, ensureObjectValidator, isValidator, s, serializeValue } from "./validators.js";
|
|
2
2
|
import { SyncoreSchema, TableDefinition, defineSchema, defineTable } from "./definition.js";
|
|
3
3
|
import { createSchemaSnapshot, diffSchemaSnapshots, parseSchemaSnapshot, renderCreateIndexStatement, renderCreateSearchIndexStatement, renderCreateTableStatement, renderMigrationSql, searchIndexTableName } from "./planner.js";
|
|
4
|
-
export { AnyValidator, ArrayValidator, BooleanValidator, IdValidator, LiteralValidator, NullValidator, NumberValidator, ObjectValidator, OptionalValidator, StringValidator, SyncoreSchema, TableDefinition, createSchemaSnapshot, defineSchema, defineTable, describeValidator, diffSchemaSnapshots, ensureObjectValidator, parseSchemaSnapshot, renderCreateIndexStatement, renderCreateSearchIndexStatement, renderCreateTableStatement, renderMigrationSql, searchIndexTableName,
|
|
4
|
+
export { AnyValidator, ArrayValidator, BooleanValidator, CodecValidator, EnumValidator, IdValidator, LiteralValidator, NullValidator, NumberValidator, ObjectValidator, OptionalValidator, RecordValidator, StringValidator, SyncoreSchema, TableDefinition, UnionValidator, createSchemaSnapshot, defineSchema, defineTable, describeValidator, deserializeValue, diffSchemaSnapshots, ensureObjectValidator, isValidator, parseSchemaSnapshot, renderCreateIndexStatement, renderCreateSearchIndexStatement, renderCreateTableStatement, renderMigrationSql, s, searchIndexTableName, serializeValue };
|