@electric-sql/react 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +4 -2
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +35 -0
- package/dist/index.browser.mjs +1 -1
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.legacy-esm.js +3 -2
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +3 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +35 -29
- package/src/react-hooks.tsx +10 -6
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -103,7 +104,7 @@ function getShapeStream(options) {
|
|
|
103
104
|
const shapeHash = sortedOptionsHash(options);
|
|
104
105
|
if (streamCache.has(shapeHash)) {
|
|
105
106
|
const stream = streamCache.get(shapeHash);
|
|
106
|
-
if (!
|
|
107
|
+
if (!((_a = stream.options.signal) == null ? void 0 : _a.aborted)) {
|
|
107
108
|
return stream;
|
|
108
109
|
}
|
|
109
110
|
streamCache.delete(shapeHash);
|
|
@@ -116,7 +117,7 @@ function getShapeStream(options) {
|
|
|
116
117
|
function getShape(shapeStream) {
|
|
117
118
|
var _a;
|
|
118
119
|
if (shapeCache.has(shapeStream)) {
|
|
119
|
-
if (!
|
|
120
|
+
if (!((_a = shapeStream.options.signal) == null ? void 0 : _a.aborted)) {
|
|
120
121
|
return shapeCache.get(shapeStream);
|
|
121
122
|
}
|
|
122
123
|
streamCache.delete(sortedOptionsHash(shapeStream.options));
|
|
@@ -139,6 +140,7 @@ function parseShapeData(shape) {
|
|
|
139
140
|
lastSyncedAt: shape.lastSyncedAt(),
|
|
140
141
|
isError: shape.error !== false,
|
|
141
142
|
shape,
|
|
143
|
+
stream: shape.stream,
|
|
142
144
|
error: shape.error
|
|
143
145
|
};
|
|
144
146
|
}
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts","../../src/react-hooks.tsx"],"sourcesContent":["export * from './react-hooks'\n","import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n GetExtensions,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ntype UnknownShape = Shape<Row<unknown>>\ntype UnknownShapeStream = ShapeStream<Row<unknown>>\n\nconst streamCache = new Map<string, UnknownShapeStream>()\nconst shapeCache = new Map<UnknownShapeStream, UnknownShape>()\n\nexport async function preloadShape<T extends Row<unknown> = Row>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.rows\n return shape\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction sortObjectKeys(obj: any): any {\n if (typeof obj !== `object` || obj === null) return obj\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys)\n }\n\n return (\n Object.keys(obj)\n .sort()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n .reduce<Record<string, any>>((sorted, key) => {\n sorted[key] = sortObjectKeys(obj[key])\n return sorted\n }, {})\n )\n}\n\nexport function sortedOptionsHash<T>(options: ShapeStreamOptions<T>): string {\n return JSON.stringify(sortObjectKeys(options))\n}\n\nexport function getShapeStream<T extends Row<unknown>>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return it if valid\n if (streamCache.has(shapeHash)) {\n const stream = streamCache.get(shapeHash)! as ShapeStream<T>\n if (!stream.
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts","../../src/react-hooks.tsx"],"sourcesContent":["export * from './react-hooks'\n","import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n GetExtensions,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ntype UnknownShape = Shape<Row<unknown>>\ntype UnknownShapeStream = ShapeStream<Row<unknown>>\n\nconst streamCache = new Map<string, UnknownShapeStream>()\nconst shapeCache = new Map<UnknownShapeStream, UnknownShape>()\n\nexport async function preloadShape<T extends Row<unknown> = Row>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.rows\n return shape\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction sortObjectKeys(obj: any): any {\n if (typeof obj !== `object` || obj === null) return obj\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys)\n }\n\n return (\n Object.keys(obj)\n .sort()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n .reduce<Record<string, any>>((sorted, key) => {\n sorted[key] = sortObjectKeys(obj[key])\n return sorted\n }, {})\n )\n}\n\nexport function sortedOptionsHash<T>(options: ShapeStreamOptions<T>): string {\n return JSON.stringify(sortObjectKeys(options))\n}\n\nexport function getShapeStream<T extends Row<unknown>>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return it if valid\n if (streamCache.has(shapeHash)) {\n const stream = streamCache.get(shapeHash)! as ShapeStream<T>\n if (!stream.options.signal?.aborted) {\n return stream\n }\n\n // if stream is aborted, remove it and related shapes\n streamCache.delete(shapeHash)\n shapeCache.delete(stream)\n }\n\n const newShapeStream = new ShapeStream<T>(options)\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n}\n\nexport function getShape<T extends Row<unknown>>(\n shapeStream: ShapeStream<T>\n): Shape<T> {\n // If the stream is already cached, return it if valid\n if (shapeCache.has(shapeStream)) {\n if (!shapeStream.options.signal?.aborted) {\n return shapeCache.get(shapeStream)! as Shape<T>\n }\n\n // if stream is aborted, remove it and related shapes\n streamCache.delete(sortedOptionsHash(shapeStream.options))\n shapeCache.delete(shapeStream)\n }\n\n const newShape = new Shape<T>(shapeStream)\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n}\n\nexport interface UseShapeResult<T extends Row<unknown> = Row> {\n /**\n * The array of rows that make up the Shape.\n * @type {T[]}\n */\n data: T[]\n /**\n * The Shape instance used by this useShape\n * @type {Shape<T>}\n */\n shape: Shape<T>\n /**\n * The ShapeStream instance used by this Shape\n * @type {ShapeStream<T>}\n */\n stream: ShapeStream<T>\n /** True during initial fetch. False afterwise. */\n isLoading: boolean\n /** Unix time at which we last synced. Undefined when `isLoading` is true. */\n lastSyncedAt?: number\n error: Shape<T>[`error`]\n isError: boolean\n}\n\nfunction shapeSubscribe<T extends Row<unknown>>(\n shape: Shape<T>,\n callback: () => void\n) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData<T extends Row<unknown>>(\n shape: Shape<T>\n): UseShapeResult<T> {\n return {\n data: shape.currentRows,\n isLoading: shape.isLoading(),\n lastSyncedAt: shape.lastSyncedAt(),\n isError: shape.error !== false,\n shape,\n stream: shape.stream as ShapeStream<T>,\n error: shape.error,\n }\n}\n\nfunction identity<T>(arg: T): T {\n return arg\n}\n\ninterface UseShapeOptions<SourceData extends Row<unknown>, Selection>\n extends ShapeStreamOptions<GetExtensions<SourceData>> {\n selector?: (value: UseShapeResult<SourceData>) => Selection\n}\n\nexport function useShape<\n SourceData extends Row<unknown> = Row,\n Selection = UseShapeResult<SourceData>,\n>({\n selector = identity as (arg: UseShapeResult<SourceData>) => Selection,\n ...options\n}: UseShapeOptions<SourceData, Selection>): Selection {\n const shapeStream = getShapeStream<SourceData>(\n options as ShapeStreamOptions<GetExtensions<SourceData>>\n )\n const shape = getShape<SourceData>(shapeStream)\n\n const useShapeData = React.useMemo(() => {\n let latestShapeData = parseShapeData(shape)\n const getSnapshot = () => latestShapeData\n const subscribe = (onStoreChange: () => void) =>\n shapeSubscribe(shape, () => {\n latestShapeData = parseShapeData(shape)\n onStoreChange()\n })\n\n return () => {\n return useSyncExternalStoreWithSelector(\n subscribe,\n getSnapshot,\n getSnapshot,\n selector\n )\n }\n }, [shape, selector])\n\n return useShapeData()\n}\n"],"mappings":"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","names":["React"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Row, ShapeStreamOptions, GetExtensions, Shape, ShapeStream } from '@electric-sql/client';
|
|
2
|
+
|
|
3
|
+
declare function preloadShape<T extends Row<unknown> = Row>(options: ShapeStreamOptions<GetExtensions<T>>): Promise<Shape<T>>;
|
|
4
|
+
declare function sortedOptionsHash<T>(options: ShapeStreamOptions<T>): string;
|
|
5
|
+
declare function getShapeStream<T extends Row<unknown>>(options: ShapeStreamOptions<GetExtensions<T>>): ShapeStream<T>;
|
|
6
|
+
declare function getShape<T extends Row<unknown>>(shapeStream: ShapeStream<T>): Shape<T>;
|
|
7
|
+
interface UseShapeResult<T extends Row<unknown> = Row> {
|
|
8
|
+
/**
|
|
9
|
+
* The array of rows that make up the Shape.
|
|
10
|
+
* @type {T[]}
|
|
11
|
+
*/
|
|
12
|
+
data: T[];
|
|
13
|
+
/**
|
|
14
|
+
* The Shape instance used by this useShape
|
|
15
|
+
* @type {Shape<T>}
|
|
16
|
+
*/
|
|
17
|
+
shape: Shape<T>;
|
|
18
|
+
/**
|
|
19
|
+
* The ShapeStream instance used by this Shape
|
|
20
|
+
* @type {ShapeStream<T>}
|
|
21
|
+
*/
|
|
22
|
+
stream: ShapeStream<T>;
|
|
23
|
+
/** True during initial fetch. False afterwise. */
|
|
24
|
+
isLoading: boolean;
|
|
25
|
+
/** Unix time at which we last synced. Undefined when `isLoading` is true. */
|
|
26
|
+
lastSyncedAt?: number;
|
|
27
|
+
error: Shape<T>[`error`];
|
|
28
|
+
isError: boolean;
|
|
29
|
+
}
|
|
30
|
+
interface UseShapeOptions<SourceData extends Row<unknown>, Selection> extends ShapeStreamOptions<GetExtensions<SourceData>> {
|
|
31
|
+
selector?: (value: UseShapeResult<SourceData>) => Selection;
|
|
32
|
+
}
|
|
33
|
+
declare function useShape<SourceData extends Row<unknown> = Row, Selection = UseShapeResult<SourceData>>({ selector, ...options }: UseShapeOptions<SourceData, Selection>): Selection;
|
|
34
|
+
|
|
35
|
+
export { type UseShapeResult, getShape, getShapeStream, preloadShape, sortedOptionsHash, useShape };
|
package/dist/index.browser.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var w=Object.getOwnPropertySymbols;var y=Object.prototype.hasOwnProperty,g=Object.prototype.propertyIsEnumerable;var l=(e,n)=>{var t={};for(var a in e)y.call(e,a)&&n.indexOf(a)<0&&(t[a]=e[a]);if(e!=null&&w)for(var a of w(e))n.indexOf(a)<0&&g.call(e,a)&&(t[a]=e[a]);return t};var
|
|
1
|
+
var w=Object.getOwnPropertySymbols;var y=Object.prototype.hasOwnProperty,g=Object.prototype.propertyIsEnumerable;var l=(e,n)=>{var t={};for(var a in e)y.call(e,a)&&n.indexOf(a)<0&&(t[a]=e[a]);if(e!=null&&w)for(var a of w(e))n.indexOf(a)<0&&g.call(e,a)&&(t[a]=e[a]);return t};var T=(e,n,t)=>new Promise((a,o)=>{var s=r=>{try{S(t.next(r))}catch(p){o(p)}},h=r=>{try{S(t.throw(r))}catch(p){o(p)}},S=r=>r.done?a(r.value):Promise.resolve(r.value).then(s,h);S((t=t.apply(e,n)).next())});import{Shape as k,ShapeStream as D}from"@electric-sql/client";import O from"react";import{useSyncExternalStoreWithSelector as U}from"use-sync-external-store/with-selector.js";var i=new Map,u=new Map;function J(e){return T(this,null,function*(){let n=f(e),t=x(n);return yield t.rows,t})}function c(e){return typeof e!="object"||e===null?e:Array.isArray(e)?e.map(c):Object.keys(e).sort().reduce((n,t)=>(n[t]=c(e[t]),n),{})}function d(e){return JSON.stringify(c(e))}function f(e){var a;let n=d(e);if(i.has(n)){let o=i.get(n);if(!((a=o.options.signal)!=null&&a.aborted))return o;i.delete(n),u.delete(o)}let t=new D(e);return i.set(n,t),t}function x(e){var t;if(u.has(e)){if(!((t=e.options.signal)!=null&&t.aborted))return u.get(e);i.delete(d(e.options)),u.delete(e)}let n=new k(e);return u.set(e,n),n}function b(e,n){let t=e.subscribe(n);return()=>{t()}}function m(e){return{data:e.currentRows,isLoading:e.isLoading(),lastSyncedAt:e.lastSyncedAt(),isError:e.error!==!1,shape:e,stream:e.stream,error:e.error}}function E(e){return e}function K(t){var a=t,{selector:e=E}=a,n=l(a,["selector"]);let o=f(n),s=x(o);return O.useMemo(()=>{let S=m(s),r=()=>S,p=R=>b(s,()=>{S=m(s),R()});return()=>U(p,r,r,e)},[s,e])()}export{x as getShape,f as getShapeStream,J as preloadShape,d as sortedOptionsHash,K as useShape};
|
|
2
2
|
//# sourceMappingURL=index.browser.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n GetExtensions,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ntype UnknownShape = Shape<Row<unknown>>\ntype UnknownShapeStream = ShapeStream<Row<unknown>>\n\nconst streamCache = new Map<string, UnknownShapeStream>()\nconst shapeCache = new Map<UnknownShapeStream, UnknownShape>()\n\nexport async function preloadShape<T extends Row<unknown> = Row>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.rows\n return shape\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction sortObjectKeys(obj: any): any {\n if (typeof obj !== `object` || obj === null) return obj\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys)\n }\n\n return (\n Object.keys(obj)\n .sort()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n .reduce<Record<string, any>>((sorted, key) => {\n sorted[key] = sortObjectKeys(obj[key])\n return sorted\n }, {})\n )\n}\n\nexport function sortedOptionsHash<T>(options: ShapeStreamOptions<T>): string {\n return JSON.stringify(sortObjectKeys(options))\n}\n\nexport function getShapeStream<T extends Row<unknown>>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return it if valid\n if (streamCache.has(shapeHash)) {\n const stream = streamCache.get(shapeHash)! as ShapeStream<T>\n if (!stream.
|
|
1
|
+
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n GetExtensions,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ntype UnknownShape = Shape<Row<unknown>>\ntype UnknownShapeStream = ShapeStream<Row<unknown>>\n\nconst streamCache = new Map<string, UnknownShapeStream>()\nconst shapeCache = new Map<UnknownShapeStream, UnknownShape>()\n\nexport async function preloadShape<T extends Row<unknown> = Row>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.rows\n return shape\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction sortObjectKeys(obj: any): any {\n if (typeof obj !== `object` || obj === null) return obj\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys)\n }\n\n return (\n Object.keys(obj)\n .sort()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n .reduce<Record<string, any>>((sorted, key) => {\n sorted[key] = sortObjectKeys(obj[key])\n return sorted\n }, {})\n )\n}\n\nexport function sortedOptionsHash<T>(options: ShapeStreamOptions<T>): string {\n return JSON.stringify(sortObjectKeys(options))\n}\n\nexport function getShapeStream<T extends Row<unknown>>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return it if valid\n if (streamCache.has(shapeHash)) {\n const stream = streamCache.get(shapeHash)! as ShapeStream<T>\n if (!stream.options.signal?.aborted) {\n return stream\n }\n\n // if stream is aborted, remove it and related shapes\n streamCache.delete(shapeHash)\n shapeCache.delete(stream)\n }\n\n const newShapeStream = new ShapeStream<T>(options)\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n}\n\nexport function getShape<T extends Row<unknown>>(\n shapeStream: ShapeStream<T>\n): Shape<T> {\n // If the stream is already cached, return it if valid\n if (shapeCache.has(shapeStream)) {\n if (!shapeStream.options.signal?.aborted) {\n return shapeCache.get(shapeStream)! as Shape<T>\n }\n\n // if stream is aborted, remove it and related shapes\n streamCache.delete(sortedOptionsHash(shapeStream.options))\n shapeCache.delete(shapeStream)\n }\n\n const newShape = new Shape<T>(shapeStream)\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n}\n\nexport interface UseShapeResult<T extends Row<unknown> = Row> {\n /**\n * The array of rows that make up the Shape.\n * @type {T[]}\n */\n data: T[]\n /**\n * The Shape instance used by this useShape\n * @type {Shape<T>}\n */\n shape: Shape<T>\n /**\n * The ShapeStream instance used by this Shape\n * @type {ShapeStream<T>}\n */\n stream: ShapeStream<T>\n /** True during initial fetch. False afterwise. */\n isLoading: boolean\n /** Unix time at which we last synced. Undefined when `isLoading` is true. */\n lastSyncedAt?: number\n error: Shape<T>[`error`]\n isError: boolean\n}\n\nfunction shapeSubscribe<T extends Row<unknown>>(\n shape: Shape<T>,\n callback: () => void\n) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData<T extends Row<unknown>>(\n shape: Shape<T>\n): UseShapeResult<T> {\n return {\n data: shape.currentRows,\n isLoading: shape.isLoading(),\n lastSyncedAt: shape.lastSyncedAt(),\n isError: shape.error !== false,\n shape,\n stream: shape.stream as ShapeStream<T>,\n error: shape.error,\n }\n}\n\nfunction identity<T>(arg: T): T {\n return arg\n}\n\ninterface UseShapeOptions<SourceData extends Row<unknown>, Selection>\n extends ShapeStreamOptions<GetExtensions<SourceData>> {\n selector?: (value: UseShapeResult<SourceData>) => Selection\n}\n\nexport function useShape<\n SourceData extends Row<unknown> = Row,\n Selection = UseShapeResult<SourceData>,\n>({\n selector = identity as (arg: UseShapeResult<SourceData>) => Selection,\n ...options\n}: UseShapeOptions<SourceData, Selection>): Selection {\n const shapeStream = getShapeStream<SourceData>(\n options as ShapeStreamOptions<GetExtensions<SourceData>>\n )\n const shape = getShape<SourceData>(shapeStream)\n\n const useShapeData = React.useMemo(() => {\n let latestShapeData = parseShapeData(shape)\n const getSnapshot = () => latestShapeData\n const subscribe = (onStoreChange: () => void) =>\n shapeSubscribe(shape, () => {\n latestShapeData = parseShapeData(shape)\n onStoreChange()\n })\n\n return () => {\n return useSyncExternalStoreWithSelector(\n subscribe,\n getSnapshot,\n getSnapshot,\n selector\n )\n }\n }, [shape, selector])\n\n return useShapeData()\n}\n"],"mappings":"geAAA,OACE,SAAAA,EACA,eAAAC,MAIK,uBACP,OAAOC,MAAW,QAClB,OAAS,oCAAAC,MAAwC,2CAKjD,IAAMC,EAAc,IAAI,IAClBC,EAAa,IAAI,IAEvB,SAAsBC,EACpBC,EACmB,QAAAC,EAAA,sBACnB,IAAMC,EAAcC,EAAkBH,CAAO,EACvCI,EAAQC,EAAYH,CAAW,EACrC,aAAME,EAAM,KACLA,CACT,GAGA,SAASE,EAAeC,EAAe,CACrC,OAAI,OAAOA,GAAQ,UAAYA,IAAQ,KAAaA,EAEhD,MAAM,QAAQA,CAAG,EACZA,EAAI,IAAID,CAAc,EAI7B,OAAO,KAAKC,CAAG,EACZ,KAAK,EAEL,OAA4B,CAACC,EAAQC,KACpCD,EAAOC,CAAG,EAAIH,EAAeC,EAAIE,CAAG,CAAC,EAC9BD,GACN,CAAC,CAAC,CAEX,CAEO,SAASE,EAAqBV,EAAwC,CAC3E,OAAO,KAAK,UAAUM,EAAeN,CAAO,CAAC,CAC/C,CAEO,SAASG,EACdH,EACgB,CAlDlB,IAAAW,EAmDE,IAAMC,EAAYF,EAAkBV,CAAO,EAG3C,GAAIH,EAAY,IAAIe,CAAS,EAAG,CAC9B,IAAMC,EAAShB,EAAY,IAAIe,CAAS,EACxC,GAAI,GAACD,EAAAE,EAAO,QAAQ,SAAf,MAAAF,EAAuB,SAC1B,OAAOE,EAIThB,EAAY,OAAOe,CAAS,EAC5Bd,EAAW,OAAOe,CAAM,CAC1B,CAEA,IAAMC,EAAiB,IAAIC,EAAef,CAAO,EACjD,OAAAH,EAAY,IAAIe,EAAWE,CAAc,EAGlCA,CACT,CAEO,SAAST,EACdH,EACU,CA1EZ,IAAAS,EA4EE,GAAIb,EAAW,IAAII,CAAW,EAAG,CAC/B,GAAI,GAACS,EAAAT,EAAY,QAAQ,SAApB,MAAAS,EAA4B,SAC/B,OAAOb,EAAW,IAAII,CAAW,EAInCL,EAAY,OAAOa,EAAkBR,EAAY,OAAO,CAAC,EACzDJ,EAAW,OAAOI,CAAW,CAC/B,CAEA,IAAMc,EAAW,IAAIC,EAASf,CAAW,EACzC,OAAAJ,EAAW,IAAII,EAAac,CAAQ,EAG7BA,CACT,CA0BA,SAASE,EACPd,EACAe,EACA,CACA,IAAMC,EAAchB,EAAM,UAAUe,CAAQ,EAC5C,MAAO,IAAM,CACXC,EAAY,CACd,CACF,CAEA,SAASC,EACPjB,EACmB,CACnB,MAAO,CACL,KAAMA,EAAM,YACZ,UAAWA,EAAM,UAAU,EAC3B,aAAcA,EAAM,aAAa,EACjC,QAASA,EAAM,QAAU,GACzB,MAAAA,EACA,OAAQA,EAAM,OACd,MAAOA,EAAM,KACf,CACF,CAEA,SAASkB,EAAYC,EAAW,CAC9B,OAAOA,CACT,CAOO,SAASC,EAGdb,EAGoD,CAHpD,IAAAc,EAAAd,EACA,UAAAe,EAAWJ,CA1Jb,EAyJEG,EAEGzB,EAAA2B,EAFHF,EAEG,CADH,aAGA,IAAMvB,EAAcC,EAClBH,CACF,EACMI,EAAQC,EAAqBH,CAAW,EAqB9C,OAnBqB0B,EAAM,QAAQ,IAAM,CACvC,IAAIC,EAAkBR,EAAejB,CAAK,EACpC0B,EAAc,IAAMD,EACpBE,EAAaC,GACjBd,EAAed,EAAO,IAAM,CAC1ByB,EAAkBR,EAAejB,CAAK,EACtC4B,EAAc,CAChB,CAAC,EAEH,MAAO,IACEC,EACLF,EACAD,EACAA,EACAJ,CACF,CAEJ,EAAG,CAACtB,EAAOsB,CAAQ,CAAC,EAEA,CACtB","names":["Shape","ShapeStream","React","useSyncExternalStoreWithSelector","streamCache","shapeCache","preloadShape","options","__async","shapeStream","getShapeStream","shape","getShape","sortObjectKeys","obj","sorted","key","sortedOptionsHash","_a","shapeHash","stream","newShapeStream","ShapeStream","newShape","Shape","shapeSubscribe","callback","unsubscribe","parseShapeData","identity","arg","useShape","_b","selector","__objRest","React","latestShapeData","getSnapshot","subscribe","onStoreChange","useSyncExternalStoreWithSelector"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,11 @@ interface UseShapeResult<T extends Row<unknown> = Row> {
|
|
|
15
15
|
* @type {Shape<T>}
|
|
16
16
|
*/
|
|
17
17
|
shape: Shape<T>;
|
|
18
|
+
/**
|
|
19
|
+
* The ShapeStream instance used by this Shape
|
|
20
|
+
* @type {ShapeStream<T>}
|
|
21
|
+
*/
|
|
22
|
+
stream: ShapeStream<T>;
|
|
18
23
|
/** True during initial fetch. False afterwise. */
|
|
19
24
|
isLoading: boolean;
|
|
20
25
|
/** Unix time at which we last synced. Undefined when `isLoading` is true. */
|
package/dist/index.legacy-esm.js
CHANGED
|
@@ -47,7 +47,7 @@ function getShapeStream(options) {
|
|
|
47
47
|
const shapeHash = sortedOptionsHash(options);
|
|
48
48
|
if (streamCache.has(shapeHash)) {
|
|
49
49
|
const stream = streamCache.get(shapeHash);
|
|
50
|
-
if (!
|
|
50
|
+
if (!((_a = stream.options.signal) == null ? void 0 : _a.aborted)) {
|
|
51
51
|
return stream;
|
|
52
52
|
}
|
|
53
53
|
streamCache.delete(shapeHash);
|
|
@@ -60,7 +60,7 @@ function getShapeStream(options) {
|
|
|
60
60
|
function getShape(shapeStream) {
|
|
61
61
|
var _a;
|
|
62
62
|
if (shapeCache.has(shapeStream)) {
|
|
63
|
-
if (!
|
|
63
|
+
if (!((_a = shapeStream.options.signal) == null ? void 0 : _a.aborted)) {
|
|
64
64
|
return shapeCache.get(shapeStream);
|
|
65
65
|
}
|
|
66
66
|
streamCache.delete(sortedOptionsHash(shapeStream.options));
|
|
@@ -83,6 +83,7 @@ function parseShapeData(shape) {
|
|
|
83
83
|
lastSyncedAt: shape.lastSyncedAt(),
|
|
84
84
|
isError: shape.error !== false,
|
|
85
85
|
shape,
|
|
86
|
+
stream: shape.stream,
|
|
86
87
|
error: shape.error
|
|
87
88
|
};
|
|
88
89
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n GetExtensions,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ntype UnknownShape = Shape<Row<unknown>>\ntype UnknownShapeStream = ShapeStream<Row<unknown>>\n\nconst streamCache = new Map<string, UnknownShapeStream>()\nconst shapeCache = new Map<UnknownShapeStream, UnknownShape>()\n\nexport async function preloadShape<T extends Row<unknown> = Row>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.rows\n return shape\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction sortObjectKeys(obj: any): any {\n if (typeof obj !== `object` || obj === null) return obj\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys)\n }\n\n return (\n Object.keys(obj)\n .sort()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n .reduce<Record<string, any>>((sorted, key) => {\n sorted[key] = sortObjectKeys(obj[key])\n return sorted\n }, {})\n )\n}\n\nexport function sortedOptionsHash<T>(options: ShapeStreamOptions<T>): string {\n return JSON.stringify(sortObjectKeys(options))\n}\n\nexport function getShapeStream<T extends Row<unknown>>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return it if valid\n if (streamCache.has(shapeHash)) {\n const stream = streamCache.get(shapeHash)! as ShapeStream<T>\n if (!stream.
|
|
1
|
+
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n GetExtensions,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ntype UnknownShape = Shape<Row<unknown>>\ntype UnknownShapeStream = ShapeStream<Row<unknown>>\n\nconst streamCache = new Map<string, UnknownShapeStream>()\nconst shapeCache = new Map<UnknownShapeStream, UnknownShape>()\n\nexport async function preloadShape<T extends Row<unknown> = Row>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.rows\n return shape\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction sortObjectKeys(obj: any): any {\n if (typeof obj !== `object` || obj === null) return obj\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys)\n }\n\n return (\n Object.keys(obj)\n .sort()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n .reduce<Record<string, any>>((sorted, key) => {\n sorted[key] = sortObjectKeys(obj[key])\n return sorted\n }, {})\n )\n}\n\nexport function sortedOptionsHash<T>(options: ShapeStreamOptions<T>): string {\n return JSON.stringify(sortObjectKeys(options))\n}\n\nexport function getShapeStream<T extends Row<unknown>>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return it if valid\n if (streamCache.has(shapeHash)) {\n const stream = streamCache.get(shapeHash)! as ShapeStream<T>\n if (!stream.options.signal?.aborted) {\n return stream\n }\n\n // if stream is aborted, remove it and related shapes\n streamCache.delete(shapeHash)\n shapeCache.delete(stream)\n }\n\n const newShapeStream = new ShapeStream<T>(options)\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n}\n\nexport function getShape<T extends Row<unknown>>(\n shapeStream: ShapeStream<T>\n): Shape<T> {\n // If the stream is already cached, return it if valid\n if (shapeCache.has(shapeStream)) {\n if (!shapeStream.options.signal?.aborted) {\n return shapeCache.get(shapeStream)! as Shape<T>\n }\n\n // if stream is aborted, remove it and related shapes\n streamCache.delete(sortedOptionsHash(shapeStream.options))\n shapeCache.delete(shapeStream)\n }\n\n const newShape = new Shape<T>(shapeStream)\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n}\n\nexport interface UseShapeResult<T extends Row<unknown> = Row> {\n /**\n * The array of rows that make up the Shape.\n * @type {T[]}\n */\n data: T[]\n /**\n * The Shape instance used by this useShape\n * @type {Shape<T>}\n */\n shape: Shape<T>\n /**\n * The ShapeStream instance used by this Shape\n * @type {ShapeStream<T>}\n */\n stream: ShapeStream<T>\n /** True during initial fetch. False afterwise. */\n isLoading: boolean\n /** Unix time at which we last synced. Undefined when `isLoading` is true. */\n lastSyncedAt?: number\n error: Shape<T>[`error`]\n isError: boolean\n}\n\nfunction shapeSubscribe<T extends Row<unknown>>(\n shape: Shape<T>,\n callback: () => void\n) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData<T extends Row<unknown>>(\n shape: Shape<T>\n): UseShapeResult<T> {\n return {\n data: shape.currentRows,\n isLoading: shape.isLoading(),\n lastSyncedAt: shape.lastSyncedAt(),\n isError: shape.error !== false,\n shape,\n stream: shape.stream as ShapeStream<T>,\n error: shape.error,\n }\n}\n\nfunction identity<T>(arg: T): T {\n return arg\n}\n\ninterface UseShapeOptions<SourceData extends Row<unknown>, Selection>\n extends ShapeStreamOptions<GetExtensions<SourceData>> {\n selector?: (value: UseShapeResult<SourceData>) => Selection\n}\n\nexport function useShape<\n SourceData extends Row<unknown> = Row,\n Selection = UseShapeResult<SourceData>,\n>({\n selector = identity as (arg: UseShapeResult<SourceData>) => Selection,\n ...options\n}: UseShapeOptions<SourceData, Selection>): Selection {\n const shapeStream = getShapeStream<SourceData>(\n options as ShapeStreamOptions<GetExtensions<SourceData>>\n )\n const shape = getShape<SourceData>(shapeStream)\n\n const useShapeData = React.useMemo(() => {\n let latestShapeData = parseShapeData(shape)\n const getSnapshot = () => latestShapeData\n const subscribe = (onStoreChange: () => void) =>\n shapeSubscribe(shape, () => {\n latestShapeData = parseShapeData(shape)\n onStoreChange()\n })\n\n return () => {\n return useSyncExternalStoreWithSelector(\n subscribe,\n getSnapshot,\n getSnapshot,\n selector\n )\n }\n }, [shape, selector])\n\n return useShapeData()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,OAIK;AACP,OAAO,WAAW;AAClB,SAAS,wCAAwC;AAKjD,IAAM,cAAc,oBAAI,IAAgC;AACxD,IAAM,aAAa,oBAAI,IAAsC;AAE7D,eAAsB,aACpB,SACmB;AACnB,QAAM,cAAc,eAAkB,OAAO;AAC7C,QAAM,QAAQ,SAAY,WAAW;AACrC,QAAM,MAAM;AACZ,SAAO;AACT;AAGA,SAAS,eAAe,KAAe;AACrC,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO;AAEpD,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IAAI,IAAI,cAAc;AAAA,EAC/B;AAEA,SACE,OAAO,KAAK,GAAG,EACZ,KAAK,EAEL,OAA4B,CAAC,QAAQ,QAAQ;AAC5C,WAAO,GAAG,IAAI,eAAe,IAAI,GAAG,CAAC;AACrC,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEX;AAEO,SAAS,kBAAqB,SAAwC;AAC3E,SAAO,KAAK,UAAU,eAAe,OAAO,CAAC;AAC/C;AAEO,SAAS,eACd,SACgB;AAlDlB;AAmDE,QAAM,YAAY,kBAAkB,OAAO;AAG3C,MAAI,YAAY,IAAI,SAAS,GAAG;AAC9B,UAAM,SAAS,YAAY,IAAI,SAAS;AACxC,QAAI,GAAC,YAAO,QAAQ,WAAf,mBAAuB,UAAS;AACnC,aAAO;AAAA,IACT;AAGA,gBAAY,OAAO,SAAS;AAC5B,eAAW,OAAO,MAAM;AAAA,EAC1B;AAEA,QAAM,iBAAiB,IAAI,YAAe,OAAO;AACjD,cAAY,IAAI,WAAW,cAAc;AAGzC,SAAO;AACT;AAEO,SAAS,SACd,aACU;AA1EZ;AA4EE,MAAI,WAAW,IAAI,WAAW,GAAG;AAC/B,QAAI,GAAC,iBAAY,QAAQ,WAApB,mBAA4B,UAAS;AACxC,aAAO,WAAW,IAAI,WAAW;AAAA,IACnC;AAGA,gBAAY,OAAO,kBAAkB,YAAY,OAAO,CAAC;AACzD,eAAW,OAAO,WAAW;AAAA,EAC/B;AAEA,QAAM,WAAW,IAAI,MAAS,WAAW;AACzC,aAAW,IAAI,aAAa,QAAQ;AAGpC,SAAO;AACT;AA0BA,SAAS,eACP,OACA,UACA;AACA,QAAM,cAAc,MAAM,UAAU,QAAQ;AAC5C,SAAO,MAAM;AACX,gBAAY;AAAA,EACd;AACF;AAEA,SAAS,eACP,OACmB;AACnB,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,WAAW,MAAM,UAAU;AAAA,IAC3B,cAAc,MAAM,aAAa;AAAA,IACjC,SAAS,MAAM,UAAU;AAAA,IACzB;AAAA,IACA,QAAQ,MAAM;AAAA,IACd,OAAO,MAAM;AAAA,EACf;AACF;AAEA,SAAS,SAAY,KAAW;AAC9B,SAAO;AACT;AAOO,SAAS,SAGd,IAGoD;AAHpD,eACA;AAAA,eAAW;AAAA,EA1Jb,IAyJE,IAEG,oBAFH,IAEG;AAAA,IADH;AAAA;AAGA,QAAM,cAAc;AAAA,IAClB;AAAA,EACF;AACA,QAAM,QAAQ,SAAqB,WAAW;AAE9C,QAAM,eAAe,MAAM,QAAQ,MAAM;AACvC,QAAI,kBAAkB,eAAe,KAAK;AAC1C,UAAM,cAAc,MAAM;AAC1B,UAAM,YAAY,CAAC,kBACjB,eAAe,OAAO,MAAM;AAC1B,wBAAkB,eAAe,KAAK;AACtC,oBAAc;AAAA,IAChB,CAAC;AAEH,WAAO,MAAM;AACX,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,OAAO,QAAQ,CAAC;AAEpB,SAAO,aAAa;AACtB;","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -69,7 +69,7 @@ function getShapeStream(options) {
|
|
|
69
69
|
const shapeHash = sortedOptionsHash(options);
|
|
70
70
|
if (streamCache.has(shapeHash)) {
|
|
71
71
|
const stream = streamCache.get(shapeHash);
|
|
72
|
-
if (!
|
|
72
|
+
if (!((_a = stream.options.signal) == null ? void 0 : _a.aborted)) {
|
|
73
73
|
return stream;
|
|
74
74
|
}
|
|
75
75
|
streamCache.delete(shapeHash);
|
|
@@ -82,7 +82,7 @@ function getShapeStream(options) {
|
|
|
82
82
|
function getShape(shapeStream) {
|
|
83
83
|
var _a;
|
|
84
84
|
if (shapeCache.has(shapeStream)) {
|
|
85
|
-
if (!
|
|
85
|
+
if (!((_a = shapeStream.options.signal) == null ? void 0 : _a.aborted)) {
|
|
86
86
|
return shapeCache.get(shapeStream);
|
|
87
87
|
}
|
|
88
88
|
streamCache.delete(sortedOptionsHash(shapeStream.options));
|
|
@@ -105,6 +105,7 @@ function parseShapeData(shape) {
|
|
|
105
105
|
lastSyncedAt: shape.lastSyncedAt(),
|
|
106
106
|
isError: shape.error !== false,
|
|
107
107
|
shape,
|
|
108
|
+
stream: shape.stream,
|
|
108
109
|
error: shape.error
|
|
109
110
|
};
|
|
110
111
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n GetExtensions,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ntype UnknownShape = Shape<Row<unknown>>\ntype UnknownShapeStream = ShapeStream<Row<unknown>>\n\nconst streamCache = new Map<string, UnknownShapeStream>()\nconst shapeCache = new Map<UnknownShapeStream, UnknownShape>()\n\nexport async function preloadShape<T extends Row<unknown> = Row>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.rows\n return shape\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction sortObjectKeys(obj: any): any {\n if (typeof obj !== `object` || obj === null) return obj\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys)\n }\n\n return (\n Object.keys(obj)\n .sort()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n .reduce<Record<string, any>>((sorted, key) => {\n sorted[key] = sortObjectKeys(obj[key])\n return sorted\n }, {})\n )\n}\n\nexport function sortedOptionsHash<T>(options: ShapeStreamOptions<T>): string {\n return JSON.stringify(sortObjectKeys(options))\n}\n\nexport function getShapeStream<T extends Row<unknown>>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return it if valid\n if (streamCache.has(shapeHash)) {\n const stream = streamCache.get(shapeHash)! as ShapeStream<T>\n if (!stream.
|
|
1
|
+
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n GetExtensions,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ntype UnknownShape = Shape<Row<unknown>>\ntype UnknownShapeStream = ShapeStream<Row<unknown>>\n\nconst streamCache = new Map<string, UnknownShapeStream>()\nconst shapeCache = new Map<UnknownShapeStream, UnknownShape>()\n\nexport async function preloadShape<T extends Row<unknown> = Row>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.rows\n return shape\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction sortObjectKeys(obj: any): any {\n if (typeof obj !== `object` || obj === null) return obj\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys)\n }\n\n return (\n Object.keys(obj)\n .sort()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n .reduce<Record<string, any>>((sorted, key) => {\n sorted[key] = sortObjectKeys(obj[key])\n return sorted\n }, {})\n )\n}\n\nexport function sortedOptionsHash<T>(options: ShapeStreamOptions<T>): string {\n return JSON.stringify(sortObjectKeys(options))\n}\n\nexport function getShapeStream<T extends Row<unknown>>(\n options: ShapeStreamOptions<GetExtensions<T>>\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return it if valid\n if (streamCache.has(shapeHash)) {\n const stream = streamCache.get(shapeHash)! as ShapeStream<T>\n if (!stream.options.signal?.aborted) {\n return stream\n }\n\n // if stream is aborted, remove it and related shapes\n streamCache.delete(shapeHash)\n shapeCache.delete(stream)\n }\n\n const newShapeStream = new ShapeStream<T>(options)\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n}\n\nexport function getShape<T extends Row<unknown>>(\n shapeStream: ShapeStream<T>\n): Shape<T> {\n // If the stream is already cached, return it if valid\n if (shapeCache.has(shapeStream)) {\n if (!shapeStream.options.signal?.aborted) {\n return shapeCache.get(shapeStream)! as Shape<T>\n }\n\n // if stream is aborted, remove it and related shapes\n streamCache.delete(sortedOptionsHash(shapeStream.options))\n shapeCache.delete(shapeStream)\n }\n\n const newShape = new Shape<T>(shapeStream)\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n}\n\nexport interface UseShapeResult<T extends Row<unknown> = Row> {\n /**\n * The array of rows that make up the Shape.\n * @type {T[]}\n */\n data: T[]\n /**\n * The Shape instance used by this useShape\n * @type {Shape<T>}\n */\n shape: Shape<T>\n /**\n * The ShapeStream instance used by this Shape\n * @type {ShapeStream<T>}\n */\n stream: ShapeStream<T>\n /** True during initial fetch. False afterwise. */\n isLoading: boolean\n /** Unix time at which we last synced. Undefined when `isLoading` is true. */\n lastSyncedAt?: number\n error: Shape<T>[`error`]\n isError: boolean\n}\n\nfunction shapeSubscribe<T extends Row<unknown>>(\n shape: Shape<T>,\n callback: () => void\n) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData<T extends Row<unknown>>(\n shape: Shape<T>\n): UseShapeResult<T> {\n return {\n data: shape.currentRows,\n isLoading: shape.isLoading(),\n lastSyncedAt: shape.lastSyncedAt(),\n isError: shape.error !== false,\n shape,\n stream: shape.stream as ShapeStream<T>,\n error: shape.error,\n }\n}\n\nfunction identity<T>(arg: T): T {\n return arg\n}\n\ninterface UseShapeOptions<SourceData extends Row<unknown>, Selection>\n extends ShapeStreamOptions<GetExtensions<SourceData>> {\n selector?: (value: UseShapeResult<SourceData>) => Selection\n}\n\nexport function useShape<\n SourceData extends Row<unknown> = Row,\n Selection = UseShapeResult<SourceData>,\n>({\n selector = identity as (arg: UseShapeResult<SourceData>) => Selection,\n ...options\n}: UseShapeOptions<SourceData, Selection>): Selection {\n const shapeStream = getShapeStream<SourceData>(\n options as ShapeStreamOptions<GetExtensions<SourceData>>\n )\n const shape = getShape<SourceData>(shapeStream)\n\n const useShapeData = React.useMemo(() => {\n let latestShapeData = parseShapeData(shape)\n const getSnapshot = () => latestShapeData\n const subscribe = (onStoreChange: () => void) =>\n shapeSubscribe(shape, () => {\n latestShapeData = parseShapeData(shape)\n onStoreChange()\n })\n\n return () => {\n return useSyncExternalStoreWithSelector(\n subscribe,\n getSnapshot,\n getSnapshot,\n selector\n )\n }\n }, [shape, selector])\n\n return useShapeData()\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,37 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@electric-sql/react",
|
|
3
|
-
"version": "0.6.0",
|
|
4
3
|
"description": "React hooks for ElectricSQL",
|
|
5
|
-
"
|
|
6
|
-
"main": "dist/cjs/index.cjs",
|
|
7
|
-
"module": "dist/index.legacy-esm.js",
|
|
8
|
-
"types": "dist/index.d.ts",
|
|
9
|
-
"exports": {
|
|
10
|
-
"./package.json": "./package.json",
|
|
11
|
-
".": {
|
|
12
|
-
"types": "./dist/index.d.ts",
|
|
13
|
-
"import": "./dist/index.mjs",
|
|
14
|
-
"default": "./dist/cjs/index.cjs"
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"dist",
|
|
19
|
-
"src"
|
|
20
|
-
],
|
|
21
|
-
"sideEffects": false,
|
|
22
|
-
"repository": {
|
|
23
|
-
"type": "git",
|
|
24
|
-
"url": "git+https://github.com/electric-sql/electric.git"
|
|
25
|
-
},
|
|
4
|
+
"version": "0.6.2",
|
|
26
5
|
"author": "ElectricSQL team and contributors.",
|
|
27
|
-
"license": "Apache-2",
|
|
28
6
|
"bugs": {
|
|
29
7
|
"url": "https://github.com/electric-sql/electric/issues"
|
|
30
8
|
},
|
|
31
|
-
"homepage": "https://electric-sql.com",
|
|
32
9
|
"dependencies": {
|
|
33
10
|
"use-sync-external-store": "^1.2.2",
|
|
34
|
-
"@electric-sql/client": "0.9.
|
|
11
|
+
"@electric-sql/client": "0.9.1"
|
|
35
12
|
},
|
|
36
13
|
"devDependencies": {
|
|
37
14
|
"@testing-library/react": "^16.0.0",
|
|
@@ -50,12 +27,34 @@
|
|
|
50
27
|
"pg": "^8.12.0",
|
|
51
28
|
"prettier": "^3.3.2",
|
|
52
29
|
"react": "^18.3.1",
|
|
30
|
+
"react-dom": "^18.3.1",
|
|
53
31
|
"shx": "^0.3.4",
|
|
54
32
|
"tsup": "^8.0.1",
|
|
55
33
|
"typescript": "^5.5.2",
|
|
56
34
|
"uuid": "^10.0.0",
|
|
57
35
|
"vitest": "^2.0.2"
|
|
58
36
|
},
|
|
37
|
+
"exports": {
|
|
38
|
+
"./package.json": "./package.json",
|
|
39
|
+
".": {
|
|
40
|
+
"import": {
|
|
41
|
+
"types": "./dist/index.d.ts",
|
|
42
|
+
"default": "./dist/index.mjs"
|
|
43
|
+
},
|
|
44
|
+
"require": {
|
|
45
|
+
"types": "./dist/cjs/index.d.cts",
|
|
46
|
+
"default": "./dist/cjs/index.cjs"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"files": [
|
|
51
|
+
"dist",
|
|
52
|
+
"src"
|
|
53
|
+
],
|
|
54
|
+
"homepage": "https://electric-sql.com",
|
|
55
|
+
"license": "Apache-2",
|
|
56
|
+
"main": "dist/cjs/index.cjs",
|
|
57
|
+
"module": "dist/index.legacy-esm.js",
|
|
59
58
|
"peerDependencies": {
|
|
60
59
|
"react": "^18.3.1"
|
|
61
60
|
},
|
|
@@ -64,6 +63,13 @@
|
|
|
64
63
|
"optional": true
|
|
65
64
|
}
|
|
66
65
|
},
|
|
66
|
+
"repository": {
|
|
67
|
+
"type": "git",
|
|
68
|
+
"url": "git+https://github.com/electric-sql/electric.git"
|
|
69
|
+
},
|
|
70
|
+
"sideEffects": false,
|
|
71
|
+
"type": "module",
|
|
72
|
+
"types": "dist/index.d.ts",
|
|
67
73
|
"typesVersions": {
|
|
68
74
|
"*": {
|
|
69
75
|
"*": [
|
|
@@ -72,10 +78,10 @@
|
|
|
72
78
|
}
|
|
73
79
|
},
|
|
74
80
|
"scripts": {
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"build": "shx rm -rf dist && concurrently \"tsup\" \"tsc -p tsconfig.build.json\"",
|
|
81
|
+
"build": "shx rm -rf dist && tsup && tsc -p tsconfig.build.json",
|
|
82
|
+
"format": "eslint . --fix",
|
|
78
83
|
"stylecheck": "eslint . --quiet",
|
|
79
|
-
"
|
|
84
|
+
"test": "pnpm exec vitest",
|
|
85
|
+
"typecheck": "tsc -p tsconfig.json"
|
|
80
86
|
}
|
|
81
87
|
}
|
package/src/react-hooks.tsx
CHANGED
|
@@ -54,17 +54,16 @@ export function getShapeStream<T extends Row<unknown>>(
|
|
|
54
54
|
// If the stream is already cached, return it if valid
|
|
55
55
|
if (streamCache.has(shapeHash)) {
|
|
56
56
|
const stream = streamCache.get(shapeHash)! as ShapeStream<T>
|
|
57
|
-
if (!stream.
|
|
57
|
+
if (!stream.options.signal?.aborted) {
|
|
58
58
|
return stream
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
// if stream is
|
|
61
|
+
// if stream is aborted, remove it and related shapes
|
|
62
62
|
streamCache.delete(shapeHash)
|
|
63
63
|
shapeCache.delete(stream)
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
const newShapeStream = new ShapeStream<T>(options)
|
|
67
|
-
|
|
68
67
|
streamCache.set(shapeHash, newShapeStream)
|
|
69
68
|
|
|
70
69
|
// Return the created shape
|
|
@@ -76,17 +75,16 @@ export function getShape<T extends Row<unknown>>(
|
|
|
76
75
|
): Shape<T> {
|
|
77
76
|
// If the stream is already cached, return it if valid
|
|
78
77
|
if (shapeCache.has(shapeStream)) {
|
|
79
|
-
if (!shapeStream.
|
|
78
|
+
if (!shapeStream.options.signal?.aborted) {
|
|
80
79
|
return shapeCache.get(shapeStream)! as Shape<T>
|
|
81
80
|
}
|
|
82
81
|
|
|
83
|
-
// if stream is
|
|
82
|
+
// if stream is aborted, remove it and related shapes
|
|
84
83
|
streamCache.delete(sortedOptionsHash(shapeStream.options))
|
|
85
84
|
shapeCache.delete(shapeStream)
|
|
86
85
|
}
|
|
87
86
|
|
|
88
87
|
const newShape = new Shape<T>(shapeStream)
|
|
89
|
-
|
|
90
88
|
shapeCache.set(shapeStream, newShape)
|
|
91
89
|
|
|
92
90
|
// Return the created shape
|
|
@@ -104,6 +102,11 @@ export interface UseShapeResult<T extends Row<unknown> = Row> {
|
|
|
104
102
|
* @type {Shape<T>}
|
|
105
103
|
*/
|
|
106
104
|
shape: Shape<T>
|
|
105
|
+
/**
|
|
106
|
+
* The ShapeStream instance used by this Shape
|
|
107
|
+
* @type {ShapeStream<T>}
|
|
108
|
+
*/
|
|
109
|
+
stream: ShapeStream<T>
|
|
107
110
|
/** True during initial fetch. False afterwise. */
|
|
108
111
|
isLoading: boolean
|
|
109
112
|
/** Unix time at which we last synced. Undefined when `isLoading` is true. */
|
|
@@ -131,6 +134,7 @@ function parseShapeData<T extends Row<unknown>>(
|
|
|
131
134
|
lastSyncedAt: shape.lastSyncedAt(),
|
|
132
135
|
isError: shape.error !== false,
|
|
133
136
|
shape,
|
|
137
|
+
stream: shape.stream as ShapeStream<T>,
|
|
134
138
|
error: shape.error,
|
|
135
139
|
}
|
|
136
140
|
}
|