@electric-sql/react 0.3.3 → 0.3.5
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 +1 -1
- package/dist/cjs/index.cjs +0 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.browser.mjs +1 -1
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +13 -19
- package/dist/index.legacy-esm.js +0 -1
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +0 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/react-hooks.tsx +32 -31
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ Add `useShape` to a component
|
|
|
20
20
|
import { useShape } from "@electric-sql/react"
|
|
21
21
|
|
|
22
22
|
export default function MyComponent () {
|
|
23
|
-
const { isUpToDate, data
|
|
23
|
+
const { isUpToDate, data } = useShape({
|
|
24
24
|
url: "http://my-api.com/shape/foo",
|
|
25
25
|
})
|
|
26
26
|
|
package/dist/cjs/index.cjs
CHANGED
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
|
|
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} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape<T extends Row = Row>(\n options: ShapeStreamOptions\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.value\n return shape\n}\n\nexport function sortedOptionsHash(options: ShapeStreamOptions): string {\n return JSON.stringify(options, Object.keys(options).sort())\n}\n\nexport function getShapeStream<T extends Row = Row>(\n options: ShapeStreamOptions\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return\n if (streamCache.has(shapeHash)) {\n // Return the ShapeStream\n return streamCache.get(shapeHash)! as ShapeStream<T>\n } else {\n const newShapeStream = new ShapeStream<T>(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape<T extends Row>(shapeStream: ShapeStream<T>): Shape<T> {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)! as Shape<T>\n } else {\n const newShape = new Shape<T>(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\nexport interface UseShapeResult<T extends Row = 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 error: Shape<T>[`error`]\n isError: boolean\n}\n\nfunction shapeSubscribe<T extends Row>(shape: Shape<T>, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData<T extends Row>(shape: Shape<T>): UseShapeResult<T> {\n return {\n data: [...shape.valueSync.values()],\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nfunction identity<T>(arg: T): T {\n return arg\n}\n\ninterface UseShapeOptions<SourceData extends Row, Selection>\n extends ShapeStreamOptions {\n selector?: (value: UseShapeResult<SourceData>) => Selection\n}\n\nexport function useShape<\n SourceData extends Row = 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>(options as ShapeStreamOptions)\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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAKO;AACP,mBAAkB;AAClB,2BAAiD;AAEjD,IAAM,cAAc,oBAAI,IAAyB;AACjD,IAAM,aAAa,oBAAI,IAAwB;AAE/C,SAAsB,aACpB,SACmB;AAAA;AACnB,UAAM,cAAc,eAAkB,OAAO;AAC7C,UAAM,QAAQ,SAAY,WAAW;AACrC,UAAM,MAAM;AACZ,WAAO;AAAA,EACT;AAAA;AAEO,SAAS,kBAAkB,SAAqC;AACrE,SAAO,KAAK,UAAU,SAAS,OAAO,KAAK,OAAO,EAAE,KAAK,CAAC;AAC5D;AAEO,SAAS,eACd,SACgB;AAChB,QAAM,YAAY,kBAAkB,OAAO;AAG3C,MAAI,YAAY,IAAI,SAAS,GAAG;AAE9B,WAAO,YAAY,IAAI,SAAS;AAAA,EAClC,OAAO;AACL,UAAM,iBAAiB,IAAI,0BAAe,OAAO;AAEjD,gBAAY,IAAI,WAAW,cAAc;AAGzC,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAwB,aAAuC;AAE7E,MAAI,WAAW,IAAI,WAAW,GAAG;AAE/B,WAAO,WAAW,IAAI,WAAW;AAAA,EACnC,OAAO;AACL,UAAM,WAAW,IAAI,oBAAS,WAAW;AAEzC,eAAW,IAAI,aAAa,QAAQ;AAGpC,WAAO;AAAA,EACT;AACF;AAiBA,SAAS,eAA8B,OAAiB,UAAsB;AAC5E,QAAM,cAAc,MAAM,UAAU,QAAQ;AAC5C,SAAO,MAAM;AACX,gBAAY;AAAA,EACd;AACF;AAEA,SAAS,eAA8B,OAAoC;AACzE,SAAO;AAAA,IACL,MAAM,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,SAAS,MAAM,UAAU;AAAA,IACzB;AAAA,IACA,OAAO,MAAM;AAAA,EACf;AACF;AAEA,SAAS,SAAY,KAAW;AAC9B,SAAO;AACT;AAOO,SAAS,SAGd,IAGoD;AAHpD,eACA;AAAA,eAAW;AAAA,EAvGb,IAsGE,IAEG,oBAFH,IAEG;AAAA,IADH;AAAA;AAGA,QAAM,cAAc,eAA2B,OAA6B;AAC5E,QAAM,QAAQ,SAAqB,WAAW;AAE9C,QAAM,eAAe,aAAAA,QAAM,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,iBAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,OAAO,QAAQ,CAAC;AAEpB,SAAO,aAAa;AACtB;","names":["React"]}
|
package/dist/index.browser.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var i=Object.getOwnPropertySymbols;var x=Object.prototype.hasOwnProperty,d=Object.prototype.propertyIsEnumerable;var T=(e,t)=>{var a={};for(var r in e)x.call(e,r)&&t.indexOf(r)<0&&(a[r]=e[r]);if(e!=null&&i)for(var r of i(e))t.indexOf(r)<0&&d.call(e,r)&&(a[r]=e[r]);return a};var l=(e,t,a)=>new Promise((r,p)=>{var s=o=>{try{n(a.next(o))}catch(S){p(S)}},u=o=>{try{n(a.throw(o))}catch(S){p(S)}},n=o=>o.done?r(o.value):Promise.resolve(o.value).then(s,u);n((a=a.apply(e,t)).next())});import{Shape as D,ShapeStream as O}from"@electric-sql/client";import b from"react";import{useSyncExternalStoreWithSelector as g}from"use-sync-external-store/with-selector.js";var c=new Map,h=new Map;function J(e){return l(this,null,function*(){let t=w(e),a=R(t);return yield a.value,a})}function U(e){return JSON.stringify(e,Object.keys(e).sort())}function w(e){let t=U(e);if(c.has(t))return c.get(t);{let a=new O(e);return c.set(t,a),a}}function R(e){if(h.has(e))return h.get(e);{let t=new D(e);return h.set(e,t),t}}function v(e,t){let a=e.subscribe(t);return()=>{a()}}function m(e){return{data:[...e.valueSync.values()],isError:e.error!==!1,shape:e,error:e.error}}function y(e){return e}function N(a){var r=a,{selector:e=y}=r,t=T(r,["selector"]);let p=w(t),s=R(p);return b.useMemo(()=>{let n=m(s),o=()=>n,S=f=>v(s,()=>{n=m(s),f()});return()=>g(S,o,o,e)},[s,e])()}export{R as getShape,w as getShapeStream,J as preloadShape,U as sortedOptionsHash,N as useShape};
|
|
2
2
|
//# sourceMappingURL=index.browser.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n
|
|
1
|
+
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape<T extends Row = Row>(\n options: ShapeStreamOptions\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.value\n return shape\n}\n\nexport function sortedOptionsHash(options: ShapeStreamOptions): string {\n return JSON.stringify(options, Object.keys(options).sort())\n}\n\nexport function getShapeStream<T extends Row = Row>(\n options: ShapeStreamOptions\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return\n if (streamCache.has(shapeHash)) {\n // Return the ShapeStream\n return streamCache.get(shapeHash)! as ShapeStream<T>\n } else {\n const newShapeStream = new ShapeStream<T>(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape<T extends Row>(shapeStream: ShapeStream<T>): Shape<T> {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)! as Shape<T>\n } else {\n const newShape = new Shape<T>(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\nexport interface UseShapeResult<T extends Row = 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 error: Shape<T>[`error`]\n isError: boolean\n}\n\nfunction shapeSubscribe<T extends Row>(shape: Shape<T>, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData<T extends Row>(shape: Shape<T>): UseShapeResult<T> {\n return {\n data: [...shape.valueSync.values()],\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nfunction identity<T>(arg: T): T {\n return arg\n}\n\ninterface UseShapeOptions<SourceData extends Row, Selection>\n extends ShapeStreamOptions {\n selector?: (value: UseShapeResult<SourceData>) => Selection\n}\n\nexport function useShape<\n SourceData extends Row = 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>(options as ShapeStreamOptions)\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,MAGK,uBACP,OAAOC,MAAW,QAClB,OAAS,oCAAAC,MAAwC,2CAEjD,IAAMC,EAAc,IAAI,IAClBC,EAAa,IAAI,IAEvB,SAAsBC,EACpBC,EACmB,QAAAC,EAAA,sBACnB,IAAMC,EAAcC,EAAkBH,CAAO,EACvCI,EAAQC,EAAYH,CAAW,EACrC,aAAME,EAAM,MACLA,CACT,GAEO,SAASE,EAAkBN,EAAqC,CACrE,OAAO,KAAK,UAAUA,EAAS,OAAO,KAAKA,CAAO,EAAE,KAAK,CAAC,CAC5D,CAEO,SAASG,EACdH,EACgB,CAChB,IAAMO,EAAYD,EAAkBN,CAAO,EAG3C,GAAIH,EAAY,IAAIU,CAAS,EAE3B,OAAOV,EAAY,IAAIU,CAAS,EAC3B,CACL,IAAMC,EAAiB,IAAIC,EAAeT,CAAO,EAEjD,OAAAH,EAAY,IAAIU,EAAWC,CAAc,EAGlCA,CACT,CACF,CAEO,SAASH,EAAwBH,EAAuC,CAE7E,GAAIJ,EAAW,IAAII,CAAW,EAE5B,OAAOJ,EAAW,IAAII,CAAW,EAC5B,CACL,IAAMQ,EAAW,IAAIC,EAAST,CAAW,EAEzC,OAAAJ,EAAW,IAAII,EAAaQ,CAAQ,EAG7BA,CACT,CACF,CAiBA,SAASE,EAA8BR,EAAiBS,EAAsB,CAC5E,IAAMC,EAAcV,EAAM,UAAUS,CAAQ,EAC5C,MAAO,IAAM,CACXC,EAAY,CACd,CACF,CAEA,SAASC,EAA8BX,EAAoC,CACzE,MAAO,CACL,KAAM,CAAC,GAAGA,EAAM,UAAU,OAAO,CAAC,EAClC,QAASA,EAAM,QAAU,GACzB,MAAAA,EACA,MAAOA,EAAM,KACf,CACF,CAEA,SAASY,EAAYC,EAAW,CAC9B,OAAOA,CACT,CAOO,SAASC,EAGdC,EAGoD,CAHpD,IAAAC,EAAAD,EACA,UAAAE,EAAWL,CAvGb,EAsGEI,EAEGpB,EAAAsB,EAFHF,EAEG,CADH,aAGA,IAAMlB,EAAcC,EAA2BH,CAA6B,EACtEI,EAAQC,EAAqBH,CAAW,EAqB9C,OAnBqBqB,EAAM,QAAQ,IAAM,CACvC,IAAIC,EAAkBT,EAAeX,CAAK,EACpCqB,EAAc,IAAMD,EACpBE,EAAaC,GACjBf,EAAeR,EAAO,IAAM,CAC1BoB,EAAkBT,EAAeX,CAAK,EACtCuB,EAAc,CAChB,CAAC,EAEH,MAAO,IACEC,EACLF,EACAD,EACAA,EACAJ,CACF,CAEJ,EAAG,CAACjB,EAAOiB,CAAQ,CAAC,EAEA,CACtB","names":["Shape","ShapeStream","React","useSyncExternalStoreWithSelector","streamCache","shapeCache","preloadShape","options","__async","shapeStream","getShapeStream","shape","getShape","sortedOptionsHash","shapeHash","newShapeStream","ShapeStream","newShape","Shape","shapeSubscribe","callback","unsubscribe","parseShapeData","identity","arg","useShape","_a","_b","selector","__objRest","React","latestShapeData","getSnapshot","subscribe","onStoreChange","useSyncExternalStoreWithSelector"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,32 +1,26 @@
|
|
|
1
|
-
import { ShapeStreamOptions, Shape, ShapeStream
|
|
1
|
+
import { Row, ShapeStreamOptions, Shape, ShapeStream } from '@electric-sql/client';
|
|
2
2
|
|
|
3
|
-
declare function preloadShape(options: ShapeStreamOptions): Promise<Shape
|
|
3
|
+
declare function preloadShape<T extends Row = Row>(options: ShapeStreamOptions): Promise<Shape<T>>;
|
|
4
4
|
declare function sortedOptionsHash(options: ShapeStreamOptions): string;
|
|
5
|
-
declare function getShapeStream(options: ShapeStreamOptions): ShapeStream
|
|
6
|
-
declare function getShape(shapeStream: ShapeStream): Shape
|
|
7
|
-
interface UseShapeResult {
|
|
5
|
+
declare function getShapeStream<T extends Row = Row>(options: ShapeStreamOptions): ShapeStream<T>;
|
|
6
|
+
declare function getShape<T extends Row>(shapeStream: ShapeStream<T>): Shape<T>;
|
|
7
|
+
interface UseShapeResult<T extends Row = Row> {
|
|
8
8
|
/**
|
|
9
9
|
* The array of rows that make up the Shape.
|
|
10
|
-
* @type {
|
|
10
|
+
* @type {T[]}
|
|
11
11
|
*/
|
|
12
|
-
data:
|
|
13
|
-
[key: string]: Value;
|
|
14
|
-
}[];
|
|
12
|
+
data: T[];
|
|
15
13
|
/**
|
|
16
14
|
* The Shape instance used by this useShape
|
|
17
|
-
* @type
|
|
15
|
+
* @type {Shape<T>}
|
|
18
16
|
*/
|
|
19
|
-
shape: Shape
|
|
20
|
-
error: Shape[`error`];
|
|
17
|
+
shape: Shape<T>;
|
|
18
|
+
error: Shape<T>[`error`];
|
|
21
19
|
isError: boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Has the ShapeStream caught up with the replication log from Postgres.
|
|
24
|
-
*/
|
|
25
|
-
isUpToDate: boolean;
|
|
26
20
|
}
|
|
27
|
-
interface UseShapeOptions<Selection> extends ShapeStreamOptions {
|
|
28
|
-
selector?: (value: UseShapeResult) => Selection;
|
|
21
|
+
interface UseShapeOptions<SourceData extends Row, Selection> extends ShapeStreamOptions {
|
|
22
|
+
selector?: (value: UseShapeResult<SourceData>) => Selection;
|
|
29
23
|
}
|
|
30
|
-
declare function useShape<Selection = UseShapeResult
|
|
24
|
+
declare function useShape<SourceData extends Row = Row, Selection = UseShapeResult<SourceData>>({ selector, ...options }: UseShapeOptions<SourceData, Selection>): Selection;
|
|
31
25
|
|
|
32
26
|
export { type UseShapeResult, getShape, getShapeStream, preloadShape, sortedOptionsHash, useShape };
|
package/dist/index.legacy-esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n
|
|
1
|
+
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape<T extends Row = Row>(\n options: ShapeStreamOptions\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.value\n return shape\n}\n\nexport function sortedOptionsHash(options: ShapeStreamOptions): string {\n return JSON.stringify(options, Object.keys(options).sort())\n}\n\nexport function getShapeStream<T extends Row = Row>(\n options: ShapeStreamOptions\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return\n if (streamCache.has(shapeHash)) {\n // Return the ShapeStream\n return streamCache.get(shapeHash)! as ShapeStream<T>\n } else {\n const newShapeStream = new ShapeStream<T>(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape<T extends Row>(shapeStream: ShapeStream<T>): Shape<T> {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)! as Shape<T>\n } else {\n const newShape = new Shape<T>(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\nexport interface UseShapeResult<T extends Row = 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 error: Shape<T>[`error`]\n isError: boolean\n}\n\nfunction shapeSubscribe<T extends Row>(shape: Shape<T>, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData<T extends Row>(shape: Shape<T>): UseShapeResult<T> {\n return {\n data: [...shape.valueSync.values()],\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nfunction identity<T>(arg: T): T {\n return arg\n}\n\ninterface UseShapeOptions<SourceData extends Row, Selection>\n extends ShapeStreamOptions {\n selector?: (value: UseShapeResult<SourceData>) => Selection\n}\n\nexport function useShape<\n SourceData extends Row = 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>(options as ShapeStreamOptions)\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,OAGK;AACP,OAAO,WAAW;AAClB,SAAS,wCAAwC;AAEjD,IAAM,cAAc,oBAAI,IAAyB;AACjD,IAAM,aAAa,oBAAI,IAAwB;AAE/C,eAAsB,aACpB,SACmB;AACnB,QAAM,cAAc,eAAkB,OAAO;AAC7C,QAAM,QAAQ,SAAY,WAAW;AACrC,QAAM,MAAM;AACZ,SAAO;AACT;AAEO,SAAS,kBAAkB,SAAqC;AACrE,SAAO,KAAK,UAAU,SAAS,OAAO,KAAK,OAAO,EAAE,KAAK,CAAC;AAC5D;AAEO,SAAS,eACd,SACgB;AAChB,QAAM,YAAY,kBAAkB,OAAO;AAG3C,MAAI,YAAY,IAAI,SAAS,GAAG;AAE9B,WAAO,YAAY,IAAI,SAAS;AAAA,EAClC,OAAO;AACL,UAAM,iBAAiB,IAAI,YAAe,OAAO;AAEjD,gBAAY,IAAI,WAAW,cAAc;AAGzC,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAwB,aAAuC;AAE7E,MAAI,WAAW,IAAI,WAAW,GAAG;AAE/B,WAAO,WAAW,IAAI,WAAW;AAAA,EACnC,OAAO;AACL,UAAM,WAAW,IAAI,MAAS,WAAW;AAEzC,eAAW,IAAI,aAAa,QAAQ;AAGpC,WAAO;AAAA,EACT;AACF;AAiBA,SAAS,eAA8B,OAAiB,UAAsB;AAC5E,QAAM,cAAc,MAAM,UAAU,QAAQ;AAC5C,SAAO,MAAM;AACX,gBAAY;AAAA,EACd;AACF;AAEA,SAAS,eAA8B,OAAoC;AACzE,SAAO;AAAA,IACL,MAAM,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,SAAS,MAAM,UAAU;AAAA,IACzB;AAAA,IACA,OAAO,MAAM;AAAA,EACf;AACF;AAEA,SAAS,SAAY,KAAW;AAC9B,SAAO;AACT;AAOO,SAAS,SAGd,IAGoD;AAHpD,eACA;AAAA,eAAW;AAAA,EAvGb,IAsGE,IAEG,oBAFH,IAEG;AAAA,IADH;AAAA;AAGA,QAAM,cAAc,eAA2B,OAA6B;AAC5E,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
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n
|
|
1
|
+
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape<T extends Row = Row>(\n options: ShapeStreamOptions\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.value\n return shape\n}\n\nexport function sortedOptionsHash(options: ShapeStreamOptions): string {\n return JSON.stringify(options, Object.keys(options).sort())\n}\n\nexport function getShapeStream<T extends Row = Row>(\n options: ShapeStreamOptions\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return\n if (streamCache.has(shapeHash)) {\n // Return the ShapeStream\n return streamCache.get(shapeHash)! as ShapeStream<T>\n } else {\n const newShapeStream = new ShapeStream<T>(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape<T extends Row>(shapeStream: ShapeStream<T>): Shape<T> {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)! as Shape<T>\n } else {\n const newShape = new Shape<T>(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\nexport interface UseShapeResult<T extends Row = 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 error: Shape<T>[`error`]\n isError: boolean\n}\n\nfunction shapeSubscribe<T extends Row>(shape: Shape<T>, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData<T extends Row>(shape: Shape<T>): UseShapeResult<T> {\n return {\n data: [...shape.valueSync.values()],\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nfunction identity<T>(arg: T): T {\n return arg\n}\n\ninterface UseShapeOptions<SourceData extends Row, Selection>\n extends ShapeStreamOptions {\n selector?: (value: UseShapeResult<SourceData>) => Selection\n}\n\nexport function useShape<\n SourceData extends Row = 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>(options as ShapeStreamOptions)\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,OAGK;AACP,OAAO,WAAW;AAClB,SAAS,wCAAwC;AAEjD,IAAM,cAAc,oBAAI,IAAyB;AACjD,IAAM,aAAa,oBAAI,IAAwB;AAE/C,SAAsB,aACpB,SACmB;AAAA;AACnB,UAAM,cAAc,eAAkB,OAAO;AAC7C,UAAM,QAAQ,SAAY,WAAW;AACrC,UAAM,MAAM;AACZ,WAAO;AAAA,EACT;AAAA;AAEO,SAAS,kBAAkB,SAAqC;AACrE,SAAO,KAAK,UAAU,SAAS,OAAO,KAAK,OAAO,EAAE,KAAK,CAAC;AAC5D;AAEO,SAAS,eACd,SACgB;AAChB,QAAM,YAAY,kBAAkB,OAAO;AAG3C,MAAI,YAAY,IAAI,SAAS,GAAG;AAE9B,WAAO,YAAY,IAAI,SAAS;AAAA,EAClC,OAAO;AACL,UAAM,iBAAiB,IAAI,YAAe,OAAO;AAEjD,gBAAY,IAAI,WAAW,cAAc;AAGzC,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAwB,aAAuC;AAE7E,MAAI,WAAW,IAAI,WAAW,GAAG;AAE/B,WAAO,WAAW,IAAI,WAAW;AAAA,EACnC,OAAO;AACL,UAAM,WAAW,IAAI,MAAS,WAAW;AAEzC,eAAW,IAAI,aAAa,QAAQ;AAGpC,WAAO;AAAA,EACT;AACF;AAiBA,SAAS,eAA8B,OAAiB,UAAsB;AAC5E,QAAM,cAAc,MAAM,UAAU,QAAQ;AAC5C,SAAO,MAAM;AACX,gBAAY;AAAA,EACd;AACF;AAEA,SAAS,eAA8B,OAAoC;AACzE,SAAO;AAAA,IACL,MAAM,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,SAAS,MAAM,UAAU;AAAA,IACzB;AAAA,IACA,OAAO,MAAM;AAAA,EACf;AACF;AAEA,SAAS,SAAY,KAAW;AAC9B,SAAO;AACT;AAOO,SAAS,SAGd,IAGoD;AAHpD,eACA;AAAA,eAAW;AAAA,EAvGb,IAsGE,IAEG,oBAFH,IAEG;AAAA,IADH;AAAA;AAGA,QAAM,cAAc,eAA2B,OAA6B;AAC5E,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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@electric-sql/react",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "React hooks for ElectricSQL",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cjs/index.cjs",
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
"bugs": {
|
|
29
29
|
"url": "https://github.com/electric-sql/electric/issues"
|
|
30
30
|
},
|
|
31
|
-
"homepage": "https://
|
|
31
|
+
"homepage": "https://electric-sql.com",
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"use-sync-external-store": "^1.2.2",
|
|
34
|
-
"@electric-sql/client": "0.
|
|
34
|
+
"@electric-sql/client": "0.4.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@testing-library/react": "^16.0.0",
|
package/src/react-hooks.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
Value,
|
|
3
2
|
Shape,
|
|
4
3
|
ShapeStream,
|
|
5
4
|
ShapeStreamOptions,
|
|
5
|
+
Row,
|
|
6
6
|
} from '@electric-sql/client'
|
|
7
7
|
import React from 'react'
|
|
8
8
|
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'
|
|
@@ -10,11 +10,11 @@ import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-s
|
|
|
10
10
|
const streamCache = new Map<string, ShapeStream>()
|
|
11
11
|
const shapeCache = new Map<ShapeStream, Shape>()
|
|
12
12
|
|
|
13
|
-
export async function preloadShape(
|
|
13
|
+
export async function preloadShape<T extends Row = Row>(
|
|
14
14
|
options: ShapeStreamOptions
|
|
15
|
-
): Promise<Shape
|
|
16
|
-
const shapeStream = getShapeStream(options)
|
|
17
|
-
const shape = getShape(shapeStream)
|
|
15
|
+
): Promise<Shape<T>> {
|
|
16
|
+
const shapeStream = getShapeStream<T>(options)
|
|
17
|
+
const shape = getShape<T>(shapeStream)
|
|
18
18
|
await shape.value
|
|
19
19
|
return shape
|
|
20
20
|
}
|
|
@@ -23,15 +23,17 @@ export function sortedOptionsHash(options: ShapeStreamOptions): string {
|
|
|
23
23
|
return JSON.stringify(options, Object.keys(options).sort())
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export function getShapeStream
|
|
26
|
+
export function getShapeStream<T extends Row = Row>(
|
|
27
|
+
options: ShapeStreamOptions
|
|
28
|
+
): ShapeStream<T> {
|
|
27
29
|
const shapeHash = sortedOptionsHash(options)
|
|
28
30
|
|
|
29
31
|
// If the stream is already cached, return
|
|
30
32
|
if (streamCache.has(shapeHash)) {
|
|
31
33
|
// Return the ShapeStream
|
|
32
|
-
return streamCache.get(shapeHash)!
|
|
34
|
+
return streamCache.get(shapeHash)! as ShapeStream<T>
|
|
33
35
|
} else {
|
|
34
|
-
const newShapeStream = new ShapeStream(options)
|
|
36
|
+
const newShapeStream = new ShapeStream<T>(options)
|
|
35
37
|
|
|
36
38
|
streamCache.set(shapeHash, newShapeStream)
|
|
37
39
|
|
|
@@ -40,13 +42,13 @@ export function getShapeStream(options: ShapeStreamOptions): ShapeStream {
|
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
export function getShape(shapeStream: ShapeStream): Shape {
|
|
45
|
+
export function getShape<T extends Row>(shapeStream: ShapeStream<T>): Shape<T> {
|
|
44
46
|
// If the stream is already cached, return
|
|
45
47
|
if (shapeCache.has(shapeStream)) {
|
|
46
48
|
// Return the ShapeStream
|
|
47
|
-
return shapeCache.get(shapeStream)!
|
|
49
|
+
return shapeCache.get(shapeStream)! as Shape<T>
|
|
48
50
|
} else {
|
|
49
|
-
const newShape = new Shape(shapeStream)
|
|
51
|
+
const newShape = new Shape<T>(shapeStream)
|
|
50
52
|
|
|
51
53
|
shapeCache.set(shapeStream, newShape)
|
|
52
54
|
|
|
@@ -55,36 +57,31 @@ export function getShape(shapeStream: ShapeStream): Shape {
|
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
export interface UseShapeResult {
|
|
60
|
+
export interface UseShapeResult<T extends Row = Row> {
|
|
59
61
|
/**
|
|
60
62
|
* The array of rows that make up the Shape.
|
|
61
|
-
* @type {
|
|
63
|
+
* @type {T[]}
|
|
62
64
|
*/
|
|
63
|
-
data:
|
|
65
|
+
data: T[]
|
|
64
66
|
/**
|
|
65
67
|
* The Shape instance used by this useShape
|
|
66
|
-
* @type
|
|
68
|
+
* @type {Shape<T>}
|
|
67
69
|
*/
|
|
68
|
-
shape: Shape
|
|
69
|
-
error: Shape[`error`]
|
|
70
|
+
shape: Shape<T>
|
|
71
|
+
error: Shape<T>[`error`]
|
|
70
72
|
isError: boolean
|
|
71
|
-
/**
|
|
72
|
-
* Has the ShapeStream caught up with the replication log from Postgres.
|
|
73
|
-
*/
|
|
74
|
-
isUpToDate: boolean
|
|
75
73
|
}
|
|
76
74
|
|
|
77
|
-
function shapeSubscribe(shape: Shape
|
|
75
|
+
function shapeSubscribe<T extends Row>(shape: Shape<T>, callback: () => void) {
|
|
78
76
|
const unsubscribe = shape.subscribe(callback)
|
|
79
77
|
return () => {
|
|
80
78
|
unsubscribe()
|
|
81
79
|
}
|
|
82
80
|
}
|
|
83
81
|
|
|
84
|
-
function parseShapeData(shape: Shape): UseShapeResult {
|
|
82
|
+
function parseShapeData<T extends Row>(shape: Shape<T>): UseShapeResult<T> {
|
|
85
83
|
return {
|
|
86
84
|
data: [...shape.valueSync.values()],
|
|
87
|
-
isUpToDate: shape.isUpToDate,
|
|
88
85
|
isError: shape.error !== false,
|
|
89
86
|
shape,
|
|
90
87
|
error: shape.error,
|
|
@@ -95,16 +92,20 @@ function identity<T>(arg: T): T {
|
|
|
95
92
|
return arg
|
|
96
93
|
}
|
|
97
94
|
|
|
98
|
-
interface UseShapeOptions<
|
|
99
|
-
|
|
95
|
+
interface UseShapeOptions<SourceData extends Row, Selection>
|
|
96
|
+
extends ShapeStreamOptions {
|
|
97
|
+
selector?: (value: UseShapeResult<SourceData>) => Selection
|
|
100
98
|
}
|
|
101
99
|
|
|
102
|
-
export function useShape<
|
|
103
|
-
|
|
100
|
+
export function useShape<
|
|
101
|
+
SourceData extends Row = Row,
|
|
102
|
+
Selection = UseShapeResult<SourceData>,
|
|
103
|
+
>({
|
|
104
|
+
selector = identity as (arg: UseShapeResult<SourceData>) => Selection,
|
|
104
105
|
...options
|
|
105
|
-
}: UseShapeOptions<Selection>): Selection {
|
|
106
|
-
const shapeStream = getShapeStream(options as ShapeStreamOptions)
|
|
107
|
-
const shape = getShape(shapeStream)
|
|
106
|
+
}: UseShapeOptions<SourceData, Selection>): Selection {
|
|
107
|
+
const shapeStream = getShapeStream<SourceData>(options as ShapeStreamOptions)
|
|
108
|
+
const shape = getShape<SourceData>(shapeStream)
|
|
108
109
|
|
|
109
110
|
const useShapeData = React.useMemo(() => {
|
|
110
111
|
let latestShapeData = parseShapeData(shape)
|