@electric-sql/react 0.0.10 → 0.1.0

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 CHANGED
@@ -6,6 +6,8 @@ Electric provides an HTTP interface to Postgres to enable massive number of clie
6
6
 
7
7
  This packages exposes a `useShape` hook for pulling shape data into your React components.
8
8
 
9
+ The `ShapesProvider` caches shapes globally so re-using shapes in multiple components is cheap.
10
+
9
11
  ## Install
10
12
 
11
13
  `npm i @electricsql/react`
@@ -29,8 +31,7 @@ import { useShape } from "@electric-sql/react"
29
31
 
30
32
  export default function MyComponent () {
31
33
  const { isUpToDate, data as fooData } = useShape({
32
- shape: { table: `foo` },
33
- baseUrl: "http://my-api.com/",
34
+ url: "http://my-api.com/shape/foo",
34
35
  })
35
36
 
36
37
  if (!isUpToDate) {
@@ -89,17 +89,7 @@ function preloadShape(options) {
89
89
  });
90
90
  }
91
91
  function sortedOptionsHash(options) {
92
- const shapeDef = JSON.stringify(
93
- options.shape,
94
- Object.keys(options.shape).sort()
95
- );
96
- const _a = options, { shape } = _a, optionsWithoutShapeDef = __objRest(_a, ["shape"]);
97
- const allOptions = JSON.stringify(
98
- optionsWithoutShapeDef,
99
- Object.keys(options).sort()
100
- );
101
- const shapeHash = shapeDef + allOptions;
102
- return shapeHash;
92
+ return JSON.stringify(options, Object.keys(options).sort());
103
93
  }
104
94
  function getShapeStream(options) {
105
95
  const shapeHash = sortedOptionsHash(options);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts","../../src/react-hooks.tsx"],"sourcesContent":["export * from './react-hooks'\n","import {\n JsonSerializable,\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n} from '@electric-sql/next'\nimport React, { createContext, useCallback, useContext, useRef } from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ninterface ShapeContextType {\n getShape: (shapeStream: ShapeStream) => Shape\n getShapeStream: (options: ShapeStreamOptions) => ShapeStream\n}\n\n// Create a Context\nconst ShapesContext = createContext<ShapeContextType | null>(null)\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape(\n options: ShapeStreamOptions\n): Promise<Shape> {\n const shapeStream = getShapeStream(options)\n const shape = getShape(shapeStream)\n await shape.value\n return shape\n}\n\nexport function sortedOptionsHash(options: ShapeStreamOptions): string {\n const shapeDef = JSON.stringify(\n options.shape,\n Object.keys(options.shape).sort()\n )\n // eslint-disable-next-line\n const { shape, ...optionsWithoutShapeDef } = options\n const allOptions = JSON.stringify(\n optionsWithoutShapeDef,\n Object.keys(options).sort()\n )\n const shapeHash = shapeDef + allOptions\n\n return shapeHash\n}\n\nexport function getShapeStream(options: ShapeStreamOptions): ShapeStream {\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)!\n } else {\n const newShapeStream = new ShapeStream(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape(shapeStream: ShapeStream): Shape {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)!\n } else {\n const newShape = new Shape(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\ninterface ShapeProviderProps {\n children: React.ReactNode\n}\n\n// Shapes Provider Component\nexport function ShapesProvider({ children }: ShapeProviderProps): JSX.Element {\n // Provide the context value\n return (\n <ShapesContext.Provider value={{ getShape, getShapeStream }}>\n {children}\n </ShapesContext.Provider>\n )\n}\n\nexport function useShapeContext() {\n const context = useContext(ShapesContext)\n if (!context) {\n throw new Error(`useShapeContext must be used within a ShapeProvider`)\n }\n return context\n}\n\ninterface UseShapeResult {\n /**\n * The array of rows that make up the Shape.\n * @type {{ [key: string]: JsonSerializable }[]}\n */\n data: { [key: string]: JsonSerializable }[]\n /**\n * The Shape instance used by this useShape\n * @type(Shape)\n */\n shape: Shape\n error: Shape[`error`]\n isError: boolean\n /**\n * Has the ShapeStream caught up with the replication log from Postgres.\n */\n isUpToDate: boolean\n}\n\nfunction shapeSubscribe(shape: Shape, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData(shape: Shape): UseShapeResult {\n return {\n data: [...shape.valueSync.values()],\n isUpToDate: shape.isUpToDate,\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nconst identity = (arg: unknown) => arg\n\ninterface UseShapeOptions<Selection> extends ShapeStreamOptions {\n selector?: (value: UseShapeResult) => Selection\n}\n\nexport function useShape<Selection = UseShapeResult>({\n selector = identity as never,\n ...options\n}: UseShapeOptions<Selection>): Selection {\n const { getShape, getShapeStream } = useShapeContext()\n const shapeStream = getShapeStream(options as ShapeStreamOptions)\n const shape = getShape(shapeStream)\n\n const latestShapeData = useRef(parseShapeData(shape))\n const getSnapshot = React.useCallback(() => latestShapeData.current, [])\n const shapeData = useSyncExternalStoreWithSelector(\n useCallback(\n (onStoreChange) =>\n shapeSubscribe(shape, () => {\n latestShapeData.current = parseShapeData(shape)\n onStoreChange()\n }),\n [shape]\n ),\n getSnapshot,\n getSnapshot,\n selector\n )\n\n return shapeData\n}\n"],"mappings":"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","names":["React","getShape","getShapeStream"]}
1
+ {"version":3,"sources":["../../src/index.ts","../../src/react-hooks.tsx"],"sourcesContent":["export * from './react-hooks'\n","import {\n JsonSerializable,\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n} from '@electric-sql/next'\nimport React, { createContext, useCallback, useContext, useRef } from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ninterface ShapeContextType {\n getShape: (shapeStream: ShapeStream) => Shape\n getShapeStream: (options: ShapeStreamOptions) => ShapeStream\n}\n\n// Create a Context\nconst ShapesContext = createContext<ShapeContextType | null>(null)\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape(\n options: ShapeStreamOptions\n): Promise<Shape> {\n const shapeStream = getShapeStream(options)\n const shape = getShape(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(options: ShapeStreamOptions): ShapeStream {\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)!\n } else {\n const newShapeStream = new ShapeStream(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape(shapeStream: ShapeStream): Shape {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)!\n } else {\n const newShape = new Shape(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\ninterface ShapeProviderProps {\n children: React.ReactNode\n}\n\n// Shapes Provider Component\nexport function ShapesProvider({ children }: ShapeProviderProps): JSX.Element {\n // Provide the context value\n return (\n <ShapesContext.Provider value={{ getShape, getShapeStream }}>\n {children}\n </ShapesContext.Provider>\n )\n}\n\nexport function useShapeContext() {\n const context = useContext(ShapesContext)\n if (!context) {\n throw new Error(`useShapeContext must be used within a ShapeProvider`)\n }\n return context\n}\n\ninterface UseShapeResult {\n /**\n * The array of rows that make up the Shape.\n * @type {{ [key: string]: JsonSerializable }[]}\n */\n data: { [key: string]: JsonSerializable }[]\n /**\n * The Shape instance used by this useShape\n * @type(Shape)\n */\n shape: Shape\n error: Shape[`error`]\n isError: boolean\n /**\n * Has the ShapeStream caught up with the replication log from Postgres.\n */\n isUpToDate: boolean\n}\n\nfunction shapeSubscribe(shape: Shape, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData(shape: Shape): UseShapeResult {\n return {\n data: [...shape.valueSync.values()],\n isUpToDate: shape.isUpToDate,\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nconst identity = (arg: unknown) => arg\n\ninterface UseShapeOptions<Selection> extends ShapeStreamOptions {\n selector?: (value: UseShapeResult) => Selection\n}\n\nexport function useShape<Selection = UseShapeResult>({\n selector = identity as never,\n ...options\n}: UseShapeOptions<Selection>): Selection {\n const { getShape, getShapeStream } = useShapeContext()\n const shapeStream = getShapeStream(options as ShapeStreamOptions)\n const shape = getShape(shapeStream)\n\n const latestShapeData = useRef(parseShapeData(shape))\n const getSnapshot = React.useCallback(() => latestShapeData.current, [])\n const shapeData = useSyncExternalStoreWithSelector(\n useCallback(\n (onStoreChange) =>\n shapeSubscribe(shape, () => {\n latestShapeData.current = parseShapeData(shape)\n onStoreChange()\n }),\n [shape]\n ),\n getSnapshot,\n getSnapshot,\n selector\n )\n\n return shapeData\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,kBAKO;AACP,mBAAsE;AACtE,2BAAiD;AAQjD,IAAM,oBAAgB,4BAAuC,IAAI;AAEjE,IAAM,cAAc,oBAAI,IAAyB;AACjD,IAAM,aAAa,oBAAI,IAAwB;AAE/C,SAAsB,aACpB,SACgB;AAAA;AAChB,UAAM,cAAc,eAAe,OAAO;AAC1C,UAAM,QAAQ,SAAS,WAAW;AAClC,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,eAAe,SAA0C;AACvE,QAAM,YAAY,kBAAkB,OAAO;AAG3C,MAAI,YAAY,IAAI,SAAS,GAAG;AAE9B,WAAO,YAAY,IAAI,SAAS;AAAA,EAClC,OAAO;AACL,UAAM,iBAAiB,IAAI,wBAAY,OAAO;AAE9C,gBAAY,IAAI,WAAW,cAAc;AAGzC,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAS,aAAiC;AAExD,MAAI,WAAW,IAAI,WAAW,GAAG;AAE/B,WAAO,WAAW,IAAI,WAAW;AAAA,EACnC,OAAO;AACL,UAAM,WAAW,IAAI,kBAAM,WAAW;AAEtC,eAAW,IAAI,aAAa,QAAQ;AAGpC,WAAO;AAAA,EACT;AACF;AAOO,SAAS,eAAe,EAAE,SAAS,GAAoC;AAE5E,SACE,6BAAAA,QAAA,cAAC,cAAc,UAAd,EAAuB,OAAO,EAAE,UAAU,eAAe,KACvD,QACH;AAEJ;AAEO,SAAS,kBAAkB;AAChC,QAAM,cAAU,yBAAW,aAAa;AACxC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;AAqBA,SAAS,eAAe,OAAc,UAAsB;AAC1D,QAAM,cAAc,MAAM,UAAU,QAAQ;AAC5C,SAAO,MAAM;AACX,gBAAY;AAAA,EACd;AACF;AAEA,SAAS,eAAe,OAA8B;AACpD,SAAO;AAAA,IACL,MAAM,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,YAAY,MAAM;AAAA,IAClB,SAAS,MAAM,UAAU;AAAA,IACzB;AAAA,IACA,OAAO,MAAM;AAAA,EACf;AACF;AAEA,IAAM,WAAW,CAAC,QAAiB;AAM5B,SAAS,SAAqC,IAGX;AAHW,eACnD;AAAA,eAAW;AAAA,EAlIb,IAiIqD,IAEhD,oBAFgD,IAEhD;AAAA,IADH;AAAA;AAGA,QAAM,EAAE,UAAAC,WAAU,gBAAAC,gBAAe,IAAI,gBAAgB;AACrD,QAAM,cAAcA,gBAAe,OAA6B;AAChE,QAAM,QAAQD,UAAS,WAAW;AAElC,QAAM,sBAAkB,qBAAO,eAAe,KAAK,CAAC;AACpD,QAAM,cAAc,aAAAD,QAAM,YAAY,MAAM,gBAAgB,SAAS,CAAC,CAAC;AACvE,QAAM,gBAAY;AAAA,QAChB;AAAA,MACE,CAAC,kBACC,eAAe,OAAO,MAAM;AAC1B,wBAAgB,UAAU,eAAe,KAAK;AAC9C,sBAAc;AAAA,MAChB,CAAC;AAAA,MACH,CAAC,KAAK;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO;AACT;","names":["React","getShape","getShapeStream"]}
@@ -1,2 +1,2 @@
1
- var l=Object.getOwnPropertySymbols;var v=Object.prototype.hasOwnProperty,C=Object.prototype.propertyIsEnumerable;var i=(e,t)=>{var a={};for(var r in e)v.call(e,r)&&t.indexOf(r)<0&&(a[r]=e[r]);if(e!=null&&l)for(var r of l(e))t.indexOf(r)<0&&C.call(e,r)&&(a[r]=e[r]);return a};var m=(e,t,a)=>new Promise((r,o)=>{var h=n=>{try{s(a.next(n))}catch(S){o(S)}},p=n=>{try{s(a.throw(n))}catch(S){o(S)}},s=n=>n.done?r(n.value):Promise.resolve(n.value).then(h,p);s((a=a.apply(e,t)).next())});import{Shape as w,ShapeStream as y}from"@electric-sql/next";import x,{createContext as D,useCallback as P,useContext as U,useRef as R}from"react";import{useSyncExternalStoreWithSelector as k}from"use-sync-external-store/with-selector.js";var d=D(null),c=new Map,u=new Map;function A(e){return m(this,null,function*(){let t=b(e),a=O(t);return yield a.value,a})}function E(e){let t=JSON.stringify(e.shape,Object.keys(e.shape).sort()),p=e,{shape:a}=p,r=i(p,["shape"]),o=JSON.stringify(r,Object.keys(e).sort());return t+o}function b(e){let t=E(e);if(c.has(t))return c.get(t);{let a=new y(e);return c.set(t,a),a}}function O(e){if(u.has(e))return u.get(e);{let t=new w(e);return u.set(e,t),t}}function B({children:e}){return x.createElement(d.Provider,{value:{getShape:O,getShapeStream:b}},e)}function J(){let e=U(d);if(!e)throw new Error("useShapeContext must be used within a ShapeProvider");return e}function T(e,t){let a=e.subscribe(t);return()=>{a()}}function f(e){return{data:[...e.valueSync.values()],isUpToDate:e.isUpToDate,isError:e.error!==!1,shape:e,error:e.error}}var H=e=>e;function F(a){var r=a,{selector:e=H}=r,t=i(r,["selector"]);let{getShape:o,getShapeStream:h}=J(),p=h(t),s=o(p),n=R(f(s)),S=x.useCallback(()=>n.current,[]);return k(P(g=>T(s,()=>{n.current=f(s),g()}),[s]),S,S,e)}export{B as ShapesProvider,O as getShape,b as getShapeStream,A as preloadShape,E as sortedOptionsHash,F as useShape,J as useShapeContext};
1
+ var u=Object.getOwnPropertySymbols;var C=Object.prototype.hasOwnProperty,O=Object.prototype.propertyIsEnumerable;var l=(e,t)=>{var a={};for(var r in e)C.call(e,r)&&t.indexOf(r)<0&&(a[r]=e[r]);if(e!=null&&u)for(var r of u(e))t.indexOf(r)<0&&O.call(e,r)&&(a[r]=e[r]);return a};var m=(e,t,a)=>new Promise((r,p)=>{var S=n=>{try{o(a.next(n))}catch(s){p(s)}},h=n=>{try{o(a.throw(n))}catch(s){p(s)}},o=n=>n.done?r(n.value):Promise.resolve(n.value).then(S,h);o((a=a.apply(e,t)).next())});import{Shape as w,ShapeStream as y}from"@electric-sql/next";import x,{createContext as P,useCallback as U,useContext as D,useRef as R}from"react";import{useSyncExternalStoreWithSelector as k}from"use-sync-external-store/with-selector.js";var d=P(null),i=new Map,c=new Map;function A(e){return m(this,null,function*(){let t=b(e),a=g(t);return yield a.value,a})}function E(e){return JSON.stringify(e,Object.keys(e).sort())}function b(e){let t=E(e);if(i.has(t))return i.get(t);{let a=new y(e);return i.set(t,a),a}}function g(e){if(c.has(e))return c.get(e);{let t=new w(e);return c.set(e,t),t}}function B({children:e}){return x.createElement(d.Provider,{value:{getShape:g,getShapeStream:b}},e)}function T(){let e=D(d);if(!e)throw new Error("useShapeContext must be used within a ShapeProvider");return e}function J(e,t){let a=e.subscribe(t);return()=>{a()}}function f(e){return{data:[...e.valueSync.values()],isUpToDate:e.isUpToDate,isError:e.error!==!1,shape:e,error:e.error}}var z=e=>e;function F(a){var r=a,{selector:e=z}=r,t=l(r,["selector"]);let{getShape:p,getShapeStream:S}=T(),h=S(t),o=p(h),n=R(f(o)),s=x.useCallback(()=>n.current,[]);return k(U(v=>J(o,()=>{n.current=f(o),v()}),[o]),s,s,e)}export{B as ShapesProvider,g as getShape,b as getShapeStream,A as preloadShape,E as sortedOptionsHash,F as useShape,T as useShapeContext};
2
2
  //# sourceMappingURL=index.browser.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n JsonSerializable,\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n} from '@electric-sql/next'\nimport React, { createContext, useCallback, useContext, useRef } from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ninterface ShapeContextType {\n getShape: (shapeStream: ShapeStream) => Shape\n getShapeStream: (options: ShapeStreamOptions) => ShapeStream\n}\n\n// Create a Context\nconst ShapesContext = createContext<ShapeContextType | null>(null)\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape(\n options: ShapeStreamOptions\n): Promise<Shape> {\n const shapeStream = getShapeStream(options)\n const shape = getShape(shapeStream)\n await shape.value\n return shape\n}\n\nexport function sortedOptionsHash(options: ShapeStreamOptions): string {\n const shapeDef = JSON.stringify(\n options.shape,\n Object.keys(options.shape).sort()\n )\n // eslint-disable-next-line\n const { shape, ...optionsWithoutShapeDef } = options\n const allOptions = JSON.stringify(\n optionsWithoutShapeDef,\n Object.keys(options).sort()\n )\n const shapeHash = shapeDef + allOptions\n\n return shapeHash\n}\n\nexport function getShapeStream(options: ShapeStreamOptions): ShapeStream {\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)!\n } else {\n const newShapeStream = new ShapeStream(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape(shapeStream: ShapeStream): Shape {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)!\n } else {\n const newShape = new Shape(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\ninterface ShapeProviderProps {\n children: React.ReactNode\n}\n\n// Shapes Provider Component\nexport function ShapesProvider({ children }: ShapeProviderProps): JSX.Element {\n // Provide the context value\n return (\n <ShapesContext.Provider value={{ getShape, getShapeStream }}>\n {children}\n </ShapesContext.Provider>\n )\n}\n\nexport function useShapeContext() {\n const context = useContext(ShapesContext)\n if (!context) {\n throw new Error(`useShapeContext must be used within a ShapeProvider`)\n }\n return context\n}\n\ninterface UseShapeResult {\n /**\n * The array of rows that make up the Shape.\n * @type {{ [key: string]: JsonSerializable }[]}\n */\n data: { [key: string]: JsonSerializable }[]\n /**\n * The Shape instance used by this useShape\n * @type(Shape)\n */\n shape: Shape\n error: Shape[`error`]\n isError: boolean\n /**\n * Has the ShapeStream caught up with the replication log from Postgres.\n */\n isUpToDate: boolean\n}\n\nfunction shapeSubscribe(shape: Shape, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData(shape: Shape): UseShapeResult {\n return {\n data: [...shape.valueSync.values()],\n isUpToDate: shape.isUpToDate,\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nconst identity = (arg: unknown) => arg\n\ninterface UseShapeOptions<Selection> extends ShapeStreamOptions {\n selector?: (value: UseShapeResult) => Selection\n}\n\nexport function useShape<Selection = UseShapeResult>({\n selector = identity as never,\n ...options\n}: UseShapeOptions<Selection>): Selection {\n const { getShape, getShapeStream } = useShapeContext()\n const shapeStream = getShapeStream(options as ShapeStreamOptions)\n const shape = getShape(shapeStream)\n\n const latestShapeData = useRef(parseShapeData(shape))\n const getSnapshot = React.useCallback(() => latestShapeData.current, [])\n const shapeData = useSyncExternalStoreWithSelector(\n useCallback(\n (onStoreChange) =>\n shapeSubscribe(shape, () => {\n latestShapeData.current = parseShapeData(shape)\n onStoreChange()\n }),\n [shape]\n ),\n getSnapshot,\n getSnapshot,\n selector\n )\n\n return shapeData\n}\n"],"mappings":"geAAA,OAEE,SAAAA,EACA,eAAAC,MAEK,qBACP,OAAOC,GAAS,iBAAAC,EAAe,eAAAC,EAAa,cAAAC,EAAY,UAAAC,MAAc,QACtE,OAAS,oCAAAC,MAAwC,2CAQjD,IAAMC,EAAgBC,EAAuC,IAAI,EAE3DC,EAAc,IAAI,IAClBC,EAAa,IAAI,IAEvB,SAAsBC,EACpBC,EACgB,QAAAC,EAAA,sBAChB,IAAMC,EAAcC,EAAeH,CAAO,EACpCI,EAAQC,EAASH,CAAW,EAClC,aAAME,EAAM,MACLA,CACT,GAEO,SAASE,EAAkBN,EAAqC,CACrE,IAAMO,EAAW,KAAK,UACpBP,EAAQ,MACR,OAAO,KAAKA,EAAQ,KAAK,EAAE,KAAK,CAClC,EAE6CQ,EAAAR,EAArC,OAAAI,CAnCV,EAmC+CI,EAA3BC,EAAAC,EAA2BF,EAA3B,CAAV,UACFG,EAAa,KAAK,UACtBF,EACA,OAAO,KAAKT,CAAO,EAAE,KAAK,CAC5B,EAGA,OAFkBO,EAAWI,CAG/B,CAEO,SAASR,EAAeH,EAA0C,CACvE,IAAMY,EAAYN,EAAkBN,CAAO,EAG3C,GAAIH,EAAY,IAAIe,CAAS,EAE3B,OAAOf,EAAY,IAAIe,CAAS,EAC3B,CACL,IAAMC,EAAiB,IAAIC,EAAYd,CAAO,EAE9C,OAAAH,EAAY,IAAIe,EAAWC,CAAc,EAGlCA,CACT,CACF,CAEO,SAASR,EAASH,EAAiC,CAExD,GAAIJ,EAAW,IAAII,CAAW,EAE5B,OAAOJ,EAAW,IAAII,CAAW,EAC5B,CACL,IAAMa,EAAW,IAAIC,EAAMd,CAAW,EAEtC,OAAAJ,EAAW,IAAII,EAAaa,CAAQ,EAG7BA,CACT,CACF,CAOO,SAASE,EAAe,CAAE,SAAAC,CAAS,EAAoC,CAE5E,OACEC,EAAA,cAACxB,EAAc,SAAd,CAAuB,MAAO,CAAE,SAAAU,EAAU,eAAAF,CAAe,GACvDe,CACH,CAEJ,CAEO,SAASE,GAAkB,CAChC,IAAMC,EAAUC,EAAW3B,CAAa,EACxC,GAAI,CAAC0B,EACH,MAAM,IAAI,MAAM,qDAAqD,EAEvE,OAAOA,CACT,CAqBA,SAASE,EAAenB,EAAcoB,EAAsB,CAC1D,IAAMC,EAAcrB,EAAM,UAAUoB,CAAQ,EAC5C,MAAO,IAAM,CACXC,EAAY,CACd,CACF,CAEA,SAASC,EAAetB,EAA8B,CACpD,MAAO,CACL,KAAM,CAAC,GAAGA,EAAM,UAAU,OAAO,CAAC,EAClC,WAAYA,EAAM,WAClB,QAASA,EAAM,QAAU,GACzB,MAAAA,EACA,MAAOA,EAAM,KACf,CACF,CAEA,IAAMuB,EAAYC,GAAiBA,EAM5B,SAASC,EAAqCrB,EAGX,CAHW,IAAAsB,EAAAtB,EACnD,UAAAuB,EAAWJ,CA9Ib,EA6IqDG,EAEhD9B,EAAAU,EAFgDoB,EAEhD,CADH,aAGA,GAAM,CAAE,SAAAzB,EAAU,eAAAF,CAAe,EAAIiB,EAAgB,EAC/ClB,EAAcC,EAAeH,CAA6B,EAC1DI,EAAQC,EAASH,CAAW,EAE5B8B,EAAkBC,EAAOP,EAAetB,CAAK,CAAC,EAC9C8B,EAAcf,EAAM,YAAY,IAAMa,EAAgB,QAAS,CAAC,CAAC,EAevE,OAdkBG,EAChBC,EACGC,GACCd,EAAenB,EAAO,IAAM,CAC1B4B,EAAgB,QAAUN,EAAetB,CAAK,EAC9CiC,EAAc,CAChB,CAAC,EACH,CAACjC,CAAK,CACR,EACA8B,EACAA,EACAH,CACF,CAGF","names":["Shape","ShapeStream","React","createContext","useCallback","useContext","useRef","useSyncExternalStoreWithSelector","ShapesContext","createContext","streamCache","shapeCache","preloadShape","options","__async","shapeStream","getShapeStream","shape","getShape","sortedOptionsHash","shapeDef","_a","optionsWithoutShapeDef","__objRest","allOptions","shapeHash","newShapeStream","ShapeStream","newShape","Shape","ShapesProvider","children","React","useShapeContext","context","useContext","shapeSubscribe","callback","unsubscribe","parseShapeData","identity","arg","useShape","_b","selector","latestShapeData","useRef","getSnapshot","useSyncExternalStoreWithSelector","useCallback","onStoreChange"]}
1
+ {"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n JsonSerializable,\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n} from '@electric-sql/next'\nimport React, { createContext, useCallback, useContext, useRef } from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ninterface ShapeContextType {\n getShape: (shapeStream: ShapeStream) => Shape\n getShapeStream: (options: ShapeStreamOptions) => ShapeStream\n}\n\n// Create a Context\nconst ShapesContext = createContext<ShapeContextType | null>(null)\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape(\n options: ShapeStreamOptions\n): Promise<Shape> {\n const shapeStream = getShapeStream(options)\n const shape = getShape(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(options: ShapeStreamOptions): ShapeStream {\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)!\n } else {\n const newShapeStream = new ShapeStream(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape(shapeStream: ShapeStream): Shape {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)!\n } else {\n const newShape = new Shape(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\ninterface ShapeProviderProps {\n children: React.ReactNode\n}\n\n// Shapes Provider Component\nexport function ShapesProvider({ children }: ShapeProviderProps): JSX.Element {\n // Provide the context value\n return (\n <ShapesContext.Provider value={{ getShape, getShapeStream }}>\n {children}\n </ShapesContext.Provider>\n )\n}\n\nexport function useShapeContext() {\n const context = useContext(ShapesContext)\n if (!context) {\n throw new Error(`useShapeContext must be used within a ShapeProvider`)\n }\n return context\n}\n\ninterface UseShapeResult {\n /**\n * The array of rows that make up the Shape.\n * @type {{ [key: string]: JsonSerializable }[]}\n */\n data: { [key: string]: JsonSerializable }[]\n /**\n * The Shape instance used by this useShape\n * @type(Shape)\n */\n shape: Shape\n error: Shape[`error`]\n isError: boolean\n /**\n * Has the ShapeStream caught up with the replication log from Postgres.\n */\n isUpToDate: boolean\n}\n\nfunction shapeSubscribe(shape: Shape, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData(shape: Shape): UseShapeResult {\n return {\n data: [...shape.valueSync.values()],\n isUpToDate: shape.isUpToDate,\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nconst identity = (arg: unknown) => arg\n\ninterface UseShapeOptions<Selection> extends ShapeStreamOptions {\n selector?: (value: UseShapeResult) => Selection\n}\n\nexport function useShape<Selection = UseShapeResult>({\n selector = identity as never,\n ...options\n}: UseShapeOptions<Selection>): Selection {\n const { getShape, getShapeStream } = useShapeContext()\n const shapeStream = getShapeStream(options as ShapeStreamOptions)\n const shape = getShape(shapeStream)\n\n const latestShapeData = useRef(parseShapeData(shape))\n const getSnapshot = React.useCallback(() => latestShapeData.current, [])\n const shapeData = useSyncExternalStoreWithSelector(\n useCallback(\n (onStoreChange) =>\n shapeSubscribe(shape, () => {\n latestShapeData.current = parseShapeData(shape)\n onStoreChange()\n }),\n [shape]\n ),\n getSnapshot,\n getSnapshot,\n selector\n )\n\n return shapeData\n}\n"],"mappings":"geAAA,OAEE,SAAAA,EACA,eAAAC,MAEK,qBACP,OAAOC,GAAS,iBAAAC,EAAe,eAAAC,EAAa,cAAAC,EAAY,UAAAC,MAAc,QACtE,OAAS,oCAAAC,MAAwC,2CAQjD,IAAMC,EAAgBC,EAAuC,IAAI,EAE3DC,EAAc,IAAI,IAClBC,EAAa,IAAI,IAEvB,SAAsBC,EACpBC,EACgB,QAAAC,EAAA,sBAChB,IAAMC,EAAcC,EAAeH,CAAO,EACpCI,EAAQC,EAASH,CAAW,EAClC,aAAME,EAAM,MACLA,CACT,GAEO,SAASE,EAAkBN,EAAqC,CACrE,OAAO,KAAK,UAAUA,EAAS,OAAO,KAAKA,CAAO,EAAE,KAAK,CAAC,CAC5D,CAEO,SAASG,EAAeH,EAA0C,CACvE,IAAMO,EAAYD,EAAkBN,CAAO,EAG3C,GAAIH,EAAY,IAAIU,CAAS,EAE3B,OAAOV,EAAY,IAAIU,CAAS,EAC3B,CACL,IAAMC,EAAiB,IAAIC,EAAYT,CAAO,EAE9C,OAAAH,EAAY,IAAIU,EAAWC,CAAc,EAGlCA,CACT,CACF,CAEO,SAASH,EAASH,EAAiC,CAExD,GAAIJ,EAAW,IAAII,CAAW,EAE5B,OAAOJ,EAAW,IAAII,CAAW,EAC5B,CACL,IAAMQ,EAAW,IAAIC,EAAMT,CAAW,EAEtC,OAAAJ,EAAW,IAAII,EAAaQ,CAAQ,EAG7BA,CACT,CACF,CAOO,SAASE,EAAe,CAAE,SAAAC,CAAS,EAAoC,CAE5E,OACEC,EAAA,cAACnB,EAAc,SAAd,CAAuB,MAAO,CAAE,SAAAU,EAAU,eAAAF,CAAe,GACvDU,CACH,CAEJ,CAEO,SAASE,GAAkB,CAChC,IAAMC,EAAUC,EAAWtB,CAAa,EACxC,GAAI,CAACqB,EACH,MAAM,IAAI,MAAM,qDAAqD,EAEvE,OAAOA,CACT,CAqBA,SAASE,EAAed,EAAce,EAAsB,CAC1D,IAAMC,EAAchB,EAAM,UAAUe,CAAQ,EAC5C,MAAO,IAAM,CACXC,EAAY,CACd,CACF,CAEA,SAASC,EAAejB,EAA8B,CACpD,MAAO,CACL,KAAM,CAAC,GAAGA,EAAM,UAAU,OAAO,CAAC,EAClC,WAAYA,EAAM,WAClB,QAASA,EAAM,QAAU,GACzB,MAAAA,EACA,MAAOA,EAAM,KACf,CACF,CAEA,IAAMkB,EAAYC,GAAiBA,EAM5B,SAASC,EAAqCC,EAGX,CAHW,IAAAC,EAAAD,EACnD,UAAAE,EAAWL,CAlIb,EAiIqDI,EAEhD1B,EAAA4B,EAFgDF,EAEhD,CADH,aAGA,GAAM,CAAE,SAAArB,EAAU,eAAAF,CAAe,EAAIY,EAAgB,EAC/Cb,EAAcC,EAAeH,CAA6B,EAC1DI,EAAQC,EAASH,CAAW,EAE5B2B,EAAkBC,EAAOT,EAAejB,CAAK,CAAC,EAC9C2B,EAAcjB,EAAM,YAAY,IAAMe,EAAgB,QAAS,CAAC,CAAC,EAevE,OAdkBG,EAChBC,EACGC,GACChB,EAAed,EAAO,IAAM,CAC1ByB,EAAgB,QAAUR,EAAejB,CAAK,EAC9C8B,EAAc,CAChB,CAAC,EACH,CAAC9B,CAAK,CACR,EACA2B,EACAA,EACAJ,CACF,CAGF","names":["Shape","ShapeStream","React","createContext","useCallback","useContext","useRef","useSyncExternalStoreWithSelector","ShapesContext","createContext","streamCache","shapeCache","preloadShape","options","__async","shapeStream","getShapeStream","shape","getShape","sortedOptionsHash","shapeHash","newShapeStream","ShapeStream","newShape","Shape","ShapesProvider","children","React","useShapeContext","context","useContext","shapeSubscribe","callback","unsubscribe","parseShapeData","identity","arg","useShape","_a","_b","selector","__objRest","latestShapeData","useRef","getSnapshot","useSyncExternalStoreWithSelector","useCallback","onStoreChange"]}
@@ -31,17 +31,7 @@ async function preloadShape(options) {
31
31
  return shape;
32
32
  }
33
33
  function sortedOptionsHash(options) {
34
- const shapeDef = JSON.stringify(
35
- options.shape,
36
- Object.keys(options.shape).sort()
37
- );
38
- const _a = options, { shape } = _a, optionsWithoutShapeDef = __objRest(_a, ["shape"]);
39
- const allOptions = JSON.stringify(
40
- optionsWithoutShapeDef,
41
- Object.keys(options).sort()
42
- );
43
- const shapeHash = shapeDef + allOptions;
44
- return shapeHash;
34
+ return JSON.stringify(options, Object.keys(options).sort());
45
35
  }
46
36
  function getShapeStream(options) {
47
37
  const shapeHash = sortedOptionsHash(options);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n JsonSerializable,\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n} from '@electric-sql/next'\nimport React, { createContext, useCallback, useContext, useRef } from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ninterface ShapeContextType {\n getShape: (shapeStream: ShapeStream) => Shape\n getShapeStream: (options: ShapeStreamOptions) => ShapeStream\n}\n\n// Create a Context\nconst ShapesContext = createContext<ShapeContextType | null>(null)\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape(\n options: ShapeStreamOptions\n): Promise<Shape> {\n const shapeStream = getShapeStream(options)\n const shape = getShape(shapeStream)\n await shape.value\n return shape\n}\n\nexport function sortedOptionsHash(options: ShapeStreamOptions): string {\n const shapeDef = JSON.stringify(\n options.shape,\n Object.keys(options.shape).sort()\n )\n // eslint-disable-next-line\n const { shape, ...optionsWithoutShapeDef } = options\n const allOptions = JSON.stringify(\n optionsWithoutShapeDef,\n Object.keys(options).sort()\n )\n const shapeHash = shapeDef + allOptions\n\n return shapeHash\n}\n\nexport function getShapeStream(options: ShapeStreamOptions): ShapeStream {\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)!\n } else {\n const newShapeStream = new ShapeStream(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape(shapeStream: ShapeStream): Shape {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)!\n } else {\n const newShape = new Shape(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\ninterface ShapeProviderProps {\n children: React.ReactNode\n}\n\n// Shapes Provider Component\nexport function ShapesProvider({ children }: ShapeProviderProps): JSX.Element {\n // Provide the context value\n return (\n <ShapesContext.Provider value={{ getShape, getShapeStream }}>\n {children}\n </ShapesContext.Provider>\n )\n}\n\nexport function useShapeContext() {\n const context = useContext(ShapesContext)\n if (!context) {\n throw new Error(`useShapeContext must be used within a ShapeProvider`)\n }\n return context\n}\n\ninterface UseShapeResult {\n /**\n * The array of rows that make up the Shape.\n * @type {{ [key: string]: JsonSerializable }[]}\n */\n data: { [key: string]: JsonSerializable }[]\n /**\n * The Shape instance used by this useShape\n * @type(Shape)\n */\n shape: Shape\n error: Shape[`error`]\n isError: boolean\n /**\n * Has the ShapeStream caught up with the replication log from Postgres.\n */\n isUpToDate: boolean\n}\n\nfunction shapeSubscribe(shape: Shape, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData(shape: Shape): UseShapeResult {\n return {\n data: [...shape.valueSync.values()],\n isUpToDate: shape.isUpToDate,\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nconst identity = (arg: unknown) => arg\n\ninterface UseShapeOptions<Selection> extends ShapeStreamOptions {\n selector?: (value: UseShapeResult) => Selection\n}\n\nexport function useShape<Selection = UseShapeResult>({\n selector = identity as never,\n ...options\n}: UseShapeOptions<Selection>): Selection {\n const { getShape, getShapeStream } = useShapeContext()\n const shapeStream = getShapeStream(options as ShapeStreamOptions)\n const shape = getShape(shapeStream)\n\n const latestShapeData = useRef(parseShapeData(shape))\n const getSnapshot = React.useCallback(() => latestShapeData.current, [])\n const shapeData = useSyncExternalStoreWithSelector(\n useCallback(\n (onStoreChange) =>\n shapeSubscribe(shape, () => {\n latestShapeData.current = parseShapeData(shape)\n onStoreChange()\n }),\n [shape]\n ),\n getSnapshot,\n getSnapshot,\n selector\n )\n\n return shapeData\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA;AAAA,EAEE;AAAA,EACA;AAAA,OAEK;AACP,OAAO,SAAS,eAAe,aAAa,YAAY,cAAc;AACtE,SAAS,wCAAwC;AAQjD,IAAM,gBAAgB,cAAuC,IAAI;AAEjE,IAAM,cAAc,oBAAI,IAAyB;AACjD,IAAM,aAAa,oBAAI,IAAwB;AAE/C,eAAsB,aACpB,SACgB;AAChB,QAAM,cAAc,eAAe,OAAO;AAC1C,QAAM,QAAQ,SAAS,WAAW;AAClC,QAAM,MAAM;AACZ,SAAO;AACT;AAEO,SAAS,kBAAkB,SAAqC;AACrE,QAAM,WAAW,KAAK;AAAA,IACpB,QAAQ;AAAA,IACR,OAAO,KAAK,QAAQ,KAAK,EAAE,KAAK;AAAA,EAClC;AAEA,QAA6C,cAArC,QAnCV,IAmC+C,IAA3B,mCAA2B,IAA3B,CAAV;AACR,QAAM,aAAa,KAAK;AAAA,IACtB;AAAA,IACA,OAAO,KAAK,OAAO,EAAE,KAAK;AAAA,EAC5B;AACA,QAAM,YAAY,WAAW;AAE7B,SAAO;AACT;AAEO,SAAS,eAAe,SAA0C;AACvE,QAAM,YAAY,kBAAkB,OAAO;AAG3C,MAAI,YAAY,IAAI,SAAS,GAAG;AAE9B,WAAO,YAAY,IAAI,SAAS;AAAA,EAClC,OAAO;AACL,UAAM,iBAAiB,IAAI,YAAY,OAAO;AAE9C,gBAAY,IAAI,WAAW,cAAc;AAGzC,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAS,aAAiC;AAExD,MAAI,WAAW,IAAI,WAAW,GAAG;AAE/B,WAAO,WAAW,IAAI,WAAW;AAAA,EACnC,OAAO;AACL,UAAM,WAAW,IAAI,MAAM,WAAW;AAEtC,eAAW,IAAI,aAAa,QAAQ;AAGpC,WAAO;AAAA,EACT;AACF;AAOO,SAAS,eAAe,EAAE,SAAS,GAAoC;AAE5E,SACE,oCAAC,cAAc,UAAd,EAAuB,OAAO,EAAE,UAAU,eAAe,KACvD,QACH;AAEJ;AAEO,SAAS,kBAAkB;AAChC,QAAM,UAAU,WAAW,aAAa;AACxC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;AAqBA,SAAS,eAAe,OAAc,UAAsB;AAC1D,QAAM,cAAc,MAAM,UAAU,QAAQ;AAC5C,SAAO,MAAM;AACX,gBAAY;AAAA,EACd;AACF;AAEA,SAAS,eAAe,OAA8B;AACpD,SAAO;AAAA,IACL,MAAM,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,YAAY,MAAM;AAAA,IAClB,SAAS,MAAM,UAAU;AAAA,IACzB;AAAA,IACA,OAAO,MAAM;AAAA,EACf;AACF;AAEA,IAAM,WAAW,CAAC,QAAiB;AAM5B,SAAS,SAAqC,IAGX;AAHW,eACnD;AAAA,eAAW;AAAA,EA9Ib,IA6IqD,IAEhD,oBAFgD,IAEhD;AAAA,IADH;AAAA;AAGA,QAAM,EAAE,UAAAA,WAAU,gBAAAC,gBAAe,IAAI,gBAAgB;AACrD,QAAM,cAAcA,gBAAe,OAA6B;AAChE,QAAM,QAAQD,UAAS,WAAW;AAElC,QAAM,kBAAkB,OAAO,eAAe,KAAK,CAAC;AACpD,QAAM,cAAc,MAAM,YAAY,MAAM,gBAAgB,SAAS,CAAC,CAAC;AACvE,QAAM,YAAY;AAAA,IAChB;AAAA,MACE,CAAC,kBACC,eAAe,OAAO,MAAM;AAC1B,wBAAgB,UAAU,eAAe,KAAK;AAC9C,sBAAc;AAAA,MAChB,CAAC;AAAA,MACH,CAAC,KAAK;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO;AACT;","names":["getShape","getShapeStream"]}
1
+ {"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n JsonSerializable,\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n} from '@electric-sql/next'\nimport React, { createContext, useCallback, useContext, useRef } from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ninterface ShapeContextType {\n getShape: (shapeStream: ShapeStream) => Shape\n getShapeStream: (options: ShapeStreamOptions) => ShapeStream\n}\n\n// Create a Context\nconst ShapesContext = createContext<ShapeContextType | null>(null)\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape(\n options: ShapeStreamOptions\n): Promise<Shape> {\n const shapeStream = getShapeStream(options)\n const shape = getShape(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(options: ShapeStreamOptions): ShapeStream {\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)!\n } else {\n const newShapeStream = new ShapeStream(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape(shapeStream: ShapeStream): Shape {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)!\n } else {\n const newShape = new Shape(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\ninterface ShapeProviderProps {\n children: React.ReactNode\n}\n\n// Shapes Provider Component\nexport function ShapesProvider({ children }: ShapeProviderProps): JSX.Element {\n // Provide the context value\n return (\n <ShapesContext.Provider value={{ getShape, getShapeStream }}>\n {children}\n </ShapesContext.Provider>\n )\n}\n\nexport function useShapeContext() {\n const context = useContext(ShapesContext)\n if (!context) {\n throw new Error(`useShapeContext must be used within a ShapeProvider`)\n }\n return context\n}\n\ninterface UseShapeResult {\n /**\n * The array of rows that make up the Shape.\n * @type {{ [key: string]: JsonSerializable }[]}\n */\n data: { [key: string]: JsonSerializable }[]\n /**\n * The Shape instance used by this useShape\n * @type(Shape)\n */\n shape: Shape\n error: Shape[`error`]\n isError: boolean\n /**\n * Has the ShapeStream caught up with the replication log from Postgres.\n */\n isUpToDate: boolean\n}\n\nfunction shapeSubscribe(shape: Shape, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData(shape: Shape): UseShapeResult {\n return {\n data: [...shape.valueSync.values()],\n isUpToDate: shape.isUpToDate,\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nconst identity = (arg: unknown) => arg\n\ninterface UseShapeOptions<Selection> extends ShapeStreamOptions {\n selector?: (value: UseShapeResult) => Selection\n}\n\nexport function useShape<Selection = UseShapeResult>({\n selector = identity as never,\n ...options\n}: UseShapeOptions<Selection>): Selection {\n const { getShape, getShapeStream } = useShapeContext()\n const shapeStream = getShapeStream(options as ShapeStreamOptions)\n const shape = getShape(shapeStream)\n\n const latestShapeData = useRef(parseShapeData(shape))\n const getSnapshot = React.useCallback(() => latestShapeData.current, [])\n const shapeData = useSyncExternalStoreWithSelector(\n useCallback(\n (onStoreChange) =>\n shapeSubscribe(shape, () => {\n latestShapeData.current = parseShapeData(shape)\n onStoreChange()\n }),\n [shape]\n ),\n getSnapshot,\n getSnapshot,\n selector\n )\n\n return shapeData\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA;AAAA,EAEE;AAAA,EACA;AAAA,OAEK;AACP,OAAO,SAAS,eAAe,aAAa,YAAY,cAAc;AACtE,SAAS,wCAAwC;AAQjD,IAAM,gBAAgB,cAAuC,IAAI;AAEjE,IAAM,cAAc,oBAAI,IAAyB;AACjD,IAAM,aAAa,oBAAI,IAAwB;AAE/C,eAAsB,aACpB,SACgB;AAChB,QAAM,cAAc,eAAe,OAAO;AAC1C,QAAM,QAAQ,SAAS,WAAW;AAClC,QAAM,MAAM;AACZ,SAAO;AACT;AAEO,SAAS,kBAAkB,SAAqC;AACrE,SAAO,KAAK,UAAU,SAAS,OAAO,KAAK,OAAO,EAAE,KAAK,CAAC;AAC5D;AAEO,SAAS,eAAe,SAA0C;AACvE,QAAM,YAAY,kBAAkB,OAAO;AAG3C,MAAI,YAAY,IAAI,SAAS,GAAG;AAE9B,WAAO,YAAY,IAAI,SAAS;AAAA,EAClC,OAAO;AACL,UAAM,iBAAiB,IAAI,YAAY,OAAO;AAE9C,gBAAY,IAAI,WAAW,cAAc;AAGzC,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAS,aAAiC;AAExD,MAAI,WAAW,IAAI,WAAW,GAAG;AAE/B,WAAO,WAAW,IAAI,WAAW;AAAA,EACnC,OAAO;AACL,UAAM,WAAW,IAAI,MAAM,WAAW;AAEtC,eAAW,IAAI,aAAa,QAAQ;AAGpC,WAAO;AAAA,EACT;AACF;AAOO,SAAS,eAAe,EAAE,SAAS,GAAoC;AAE5E,SACE,oCAAC,cAAc,UAAd,EAAuB,OAAO,EAAE,UAAU,eAAe,KACvD,QACH;AAEJ;AAEO,SAAS,kBAAkB;AAChC,QAAM,UAAU,WAAW,aAAa;AACxC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;AAqBA,SAAS,eAAe,OAAc,UAAsB;AAC1D,QAAM,cAAc,MAAM,UAAU,QAAQ;AAC5C,SAAO,MAAM;AACX,gBAAY;AAAA,EACd;AACF;AAEA,SAAS,eAAe,OAA8B;AACpD,SAAO;AAAA,IACL,MAAM,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,YAAY,MAAM;AAAA,IAClB,SAAS,MAAM,UAAU;AAAA,IACzB;AAAA,IACA,OAAO,MAAM;AAAA,EACf;AACF;AAEA,IAAM,WAAW,CAAC,QAAiB;AAM5B,SAAS,SAAqC,IAGX;AAHW,eACnD;AAAA,eAAW;AAAA,EAlIb,IAiIqD,IAEhD,oBAFgD,IAEhD;AAAA,IADH;AAAA;AAGA,QAAM,EAAE,UAAAA,WAAU,gBAAAC,gBAAe,IAAI,gBAAgB;AACrD,QAAM,cAAcA,gBAAe,OAA6B;AAChE,QAAM,QAAQD,UAAS,WAAW;AAElC,QAAM,kBAAkB,OAAO,eAAe,KAAK,CAAC;AACpD,QAAM,cAAc,MAAM,YAAY,MAAM,gBAAgB,SAAS,CAAC,CAAC;AACvE,QAAM,YAAY;AAAA,IAChB;AAAA,MACE,CAAC,kBACC,eAAe,OAAO,MAAM;AAC1B,wBAAgB,UAAU,eAAe,KAAK;AAC9C,sBAAc;AAAA,MAChB,CAAC;AAAA,MACH,CAAC,KAAK;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO;AACT;","names":["getShape","getShapeStream"]}
package/dist/index.mjs CHANGED
@@ -53,17 +53,7 @@ function preloadShape(options) {
53
53
  });
54
54
  }
55
55
  function sortedOptionsHash(options) {
56
- const shapeDef = JSON.stringify(
57
- options.shape,
58
- Object.keys(options.shape).sort()
59
- );
60
- const _a = options, { shape } = _a, optionsWithoutShapeDef = __objRest(_a, ["shape"]);
61
- const allOptions = JSON.stringify(
62
- optionsWithoutShapeDef,
63
- Object.keys(options).sort()
64
- );
65
- const shapeHash = shapeDef + allOptions;
66
- return shapeHash;
56
+ return JSON.stringify(options, Object.keys(options).sort());
67
57
  }
68
58
  function getShapeStream(options) {
69
59
  const shapeHash = sortedOptionsHash(options);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n JsonSerializable,\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n} from '@electric-sql/next'\nimport React, { createContext, useCallback, useContext, useRef } from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ninterface ShapeContextType {\n getShape: (shapeStream: ShapeStream) => Shape\n getShapeStream: (options: ShapeStreamOptions) => ShapeStream\n}\n\n// Create a Context\nconst ShapesContext = createContext<ShapeContextType | null>(null)\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape(\n options: ShapeStreamOptions\n): Promise<Shape> {\n const shapeStream = getShapeStream(options)\n const shape = getShape(shapeStream)\n await shape.value\n return shape\n}\n\nexport function sortedOptionsHash(options: ShapeStreamOptions): string {\n const shapeDef = JSON.stringify(\n options.shape,\n Object.keys(options.shape).sort()\n )\n // eslint-disable-next-line\n const { shape, ...optionsWithoutShapeDef } = options\n const allOptions = JSON.stringify(\n optionsWithoutShapeDef,\n Object.keys(options).sort()\n )\n const shapeHash = shapeDef + allOptions\n\n return shapeHash\n}\n\nexport function getShapeStream(options: ShapeStreamOptions): ShapeStream {\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)!\n } else {\n const newShapeStream = new ShapeStream(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape(shapeStream: ShapeStream): Shape {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)!\n } else {\n const newShape = new Shape(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\ninterface ShapeProviderProps {\n children: React.ReactNode\n}\n\n// Shapes Provider Component\nexport function ShapesProvider({ children }: ShapeProviderProps): JSX.Element {\n // Provide the context value\n return (\n <ShapesContext.Provider value={{ getShape, getShapeStream }}>\n {children}\n </ShapesContext.Provider>\n )\n}\n\nexport function useShapeContext() {\n const context = useContext(ShapesContext)\n if (!context) {\n throw new Error(`useShapeContext must be used within a ShapeProvider`)\n }\n return context\n}\n\ninterface UseShapeResult {\n /**\n * The array of rows that make up the Shape.\n * @type {{ [key: string]: JsonSerializable }[]}\n */\n data: { [key: string]: JsonSerializable }[]\n /**\n * The Shape instance used by this useShape\n * @type(Shape)\n */\n shape: Shape\n error: Shape[`error`]\n isError: boolean\n /**\n * Has the ShapeStream caught up with the replication log from Postgres.\n */\n isUpToDate: boolean\n}\n\nfunction shapeSubscribe(shape: Shape, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData(shape: Shape): UseShapeResult {\n return {\n data: [...shape.valueSync.values()],\n isUpToDate: shape.isUpToDate,\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nconst identity = (arg: unknown) => arg\n\ninterface UseShapeOptions<Selection> extends ShapeStreamOptions {\n selector?: (value: UseShapeResult) => Selection\n}\n\nexport function useShape<Selection = UseShapeResult>({\n selector = identity as never,\n ...options\n}: UseShapeOptions<Selection>): Selection {\n const { getShape, getShapeStream } = useShapeContext()\n const shapeStream = getShapeStream(options as ShapeStreamOptions)\n const shape = getShape(shapeStream)\n\n const latestShapeData = useRef(parseShapeData(shape))\n const getSnapshot = React.useCallback(() => latestShapeData.current, [])\n const shapeData = useSyncExternalStoreWithSelector(\n useCallback(\n (onStoreChange) =>\n shapeSubscribe(shape, () => {\n latestShapeData.current = parseShapeData(shape)\n onStoreChange()\n }),\n [shape]\n ),\n getSnapshot,\n getSnapshot,\n selector\n )\n\n return shapeData\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,EAEE;AAAA,EACA;AAAA,OAEK;AACP,OAAO,SAAS,eAAe,aAAa,YAAY,cAAc;AACtE,SAAS,wCAAwC;AAQjD,IAAM,gBAAgB,cAAuC,IAAI;AAEjE,IAAM,cAAc,oBAAI,IAAyB;AACjD,IAAM,aAAa,oBAAI,IAAwB;AAE/C,SAAsB,aACpB,SACgB;AAAA;AAChB,UAAM,cAAc,eAAe,OAAO;AAC1C,UAAM,QAAQ,SAAS,WAAW;AAClC,UAAM,MAAM;AACZ,WAAO;AAAA,EACT;AAAA;AAEO,SAAS,kBAAkB,SAAqC;AACrE,QAAM,WAAW,KAAK;AAAA,IACpB,QAAQ;AAAA,IACR,OAAO,KAAK,QAAQ,KAAK,EAAE,KAAK;AAAA,EAClC;AAEA,QAA6C,cAArC,QAnCV,IAmC+C,IAA3B,mCAA2B,IAA3B,CAAV;AACR,QAAM,aAAa,KAAK;AAAA,IACtB;AAAA,IACA,OAAO,KAAK,OAAO,EAAE,KAAK;AAAA,EAC5B;AACA,QAAM,YAAY,WAAW;AAE7B,SAAO;AACT;AAEO,SAAS,eAAe,SAA0C;AACvE,QAAM,YAAY,kBAAkB,OAAO;AAG3C,MAAI,YAAY,IAAI,SAAS,GAAG;AAE9B,WAAO,YAAY,IAAI,SAAS;AAAA,EAClC,OAAO;AACL,UAAM,iBAAiB,IAAI,YAAY,OAAO;AAE9C,gBAAY,IAAI,WAAW,cAAc;AAGzC,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAS,aAAiC;AAExD,MAAI,WAAW,IAAI,WAAW,GAAG;AAE/B,WAAO,WAAW,IAAI,WAAW;AAAA,EACnC,OAAO;AACL,UAAM,WAAW,IAAI,MAAM,WAAW;AAEtC,eAAW,IAAI,aAAa,QAAQ;AAGpC,WAAO;AAAA,EACT;AACF;AAOO,SAAS,eAAe,EAAE,SAAS,GAAoC;AAE5E,SACE,oCAAC,cAAc,UAAd,EAAuB,OAAO,EAAE,UAAU,eAAe,KACvD,QACH;AAEJ;AAEO,SAAS,kBAAkB;AAChC,QAAM,UAAU,WAAW,aAAa;AACxC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;AAqBA,SAAS,eAAe,OAAc,UAAsB;AAC1D,QAAM,cAAc,MAAM,UAAU,QAAQ;AAC5C,SAAO,MAAM;AACX,gBAAY;AAAA,EACd;AACF;AAEA,SAAS,eAAe,OAA8B;AACpD,SAAO;AAAA,IACL,MAAM,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,YAAY,MAAM;AAAA,IAClB,SAAS,MAAM,UAAU;AAAA,IACzB;AAAA,IACA,OAAO,MAAM;AAAA,EACf;AACF;AAEA,IAAM,WAAW,CAAC,QAAiB;AAM5B,SAAS,SAAqC,IAGX;AAHW,eACnD;AAAA,eAAW;AAAA,EA9Ib,IA6IqD,IAEhD,oBAFgD,IAEhD;AAAA,IADH;AAAA;AAGA,QAAM,EAAE,UAAAA,WAAU,gBAAAC,gBAAe,IAAI,gBAAgB;AACrD,QAAM,cAAcA,gBAAe,OAA6B;AAChE,QAAM,QAAQD,UAAS,WAAW;AAElC,QAAM,kBAAkB,OAAO,eAAe,KAAK,CAAC;AACpD,QAAM,cAAc,MAAM,YAAY,MAAM,gBAAgB,SAAS,CAAC,CAAC;AACvE,QAAM,YAAY;AAAA,IAChB;AAAA,MACE,CAAC,kBACC,eAAe,OAAO,MAAM;AAC1B,wBAAgB,UAAU,eAAe,KAAK;AAC9C,sBAAc;AAAA,MAChB,CAAC;AAAA,MACH,CAAC,KAAK;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO;AACT;","names":["getShape","getShapeStream"]}
1
+ {"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n JsonSerializable,\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n} from '@electric-sql/next'\nimport React, { createContext, useCallback, useContext, useRef } from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\ninterface ShapeContextType {\n getShape: (shapeStream: ShapeStream) => Shape\n getShapeStream: (options: ShapeStreamOptions) => ShapeStream\n}\n\n// Create a Context\nconst ShapesContext = createContext<ShapeContextType | null>(null)\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape(\n options: ShapeStreamOptions\n): Promise<Shape> {\n const shapeStream = getShapeStream(options)\n const shape = getShape(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(options: ShapeStreamOptions): ShapeStream {\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)!\n } else {\n const newShapeStream = new ShapeStream(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape(shapeStream: ShapeStream): Shape {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)!\n } else {\n const newShape = new Shape(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\ninterface ShapeProviderProps {\n children: React.ReactNode\n}\n\n// Shapes Provider Component\nexport function ShapesProvider({ children }: ShapeProviderProps): JSX.Element {\n // Provide the context value\n return (\n <ShapesContext.Provider value={{ getShape, getShapeStream }}>\n {children}\n </ShapesContext.Provider>\n )\n}\n\nexport function useShapeContext() {\n const context = useContext(ShapesContext)\n if (!context) {\n throw new Error(`useShapeContext must be used within a ShapeProvider`)\n }\n return context\n}\n\ninterface UseShapeResult {\n /**\n * The array of rows that make up the Shape.\n * @type {{ [key: string]: JsonSerializable }[]}\n */\n data: { [key: string]: JsonSerializable }[]\n /**\n * The Shape instance used by this useShape\n * @type(Shape)\n */\n shape: Shape\n error: Shape[`error`]\n isError: boolean\n /**\n * Has the ShapeStream caught up with the replication log from Postgres.\n */\n isUpToDate: boolean\n}\n\nfunction shapeSubscribe(shape: Shape, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData(shape: Shape): UseShapeResult {\n return {\n data: [...shape.valueSync.values()],\n isUpToDate: shape.isUpToDate,\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nconst identity = (arg: unknown) => arg\n\ninterface UseShapeOptions<Selection> extends ShapeStreamOptions {\n selector?: (value: UseShapeResult) => Selection\n}\n\nexport function useShape<Selection = UseShapeResult>({\n selector = identity as never,\n ...options\n}: UseShapeOptions<Selection>): Selection {\n const { getShape, getShapeStream } = useShapeContext()\n const shapeStream = getShapeStream(options as ShapeStreamOptions)\n const shape = getShape(shapeStream)\n\n const latestShapeData = useRef(parseShapeData(shape))\n const getSnapshot = React.useCallback(() => latestShapeData.current, [])\n const shapeData = useSyncExternalStoreWithSelector(\n useCallback(\n (onStoreChange) =>\n shapeSubscribe(shape, () => {\n latestShapeData.current = parseShapeData(shape)\n onStoreChange()\n }),\n [shape]\n ),\n getSnapshot,\n getSnapshot,\n selector\n )\n\n return shapeData\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,EAEE;AAAA,EACA;AAAA,OAEK;AACP,OAAO,SAAS,eAAe,aAAa,YAAY,cAAc;AACtE,SAAS,wCAAwC;AAQjD,IAAM,gBAAgB,cAAuC,IAAI;AAEjE,IAAM,cAAc,oBAAI,IAAyB;AACjD,IAAM,aAAa,oBAAI,IAAwB;AAE/C,SAAsB,aACpB,SACgB;AAAA;AAChB,UAAM,cAAc,eAAe,OAAO;AAC1C,UAAM,QAAQ,SAAS,WAAW;AAClC,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,eAAe,SAA0C;AACvE,QAAM,YAAY,kBAAkB,OAAO;AAG3C,MAAI,YAAY,IAAI,SAAS,GAAG;AAE9B,WAAO,YAAY,IAAI,SAAS;AAAA,EAClC,OAAO;AACL,UAAM,iBAAiB,IAAI,YAAY,OAAO;AAE9C,gBAAY,IAAI,WAAW,cAAc;AAGzC,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAS,aAAiC;AAExD,MAAI,WAAW,IAAI,WAAW,GAAG;AAE/B,WAAO,WAAW,IAAI,WAAW;AAAA,EACnC,OAAO;AACL,UAAM,WAAW,IAAI,MAAM,WAAW;AAEtC,eAAW,IAAI,aAAa,QAAQ;AAGpC,WAAO;AAAA,EACT;AACF;AAOO,SAAS,eAAe,EAAE,SAAS,GAAoC;AAE5E,SACE,oCAAC,cAAc,UAAd,EAAuB,OAAO,EAAE,UAAU,eAAe,KACvD,QACH;AAEJ;AAEO,SAAS,kBAAkB;AAChC,QAAM,UAAU,WAAW,aAAa;AACxC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;AAqBA,SAAS,eAAe,OAAc,UAAsB;AAC1D,QAAM,cAAc,MAAM,UAAU,QAAQ;AAC5C,SAAO,MAAM;AACX,gBAAY;AAAA,EACd;AACF;AAEA,SAAS,eAAe,OAA8B;AACpD,SAAO;AAAA,IACL,MAAM,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,YAAY,MAAM;AAAA,IAClB,SAAS,MAAM,UAAU;AAAA,IACzB;AAAA,IACA,OAAO,MAAM;AAAA,EACf;AACF;AAEA,IAAM,WAAW,CAAC,QAAiB;AAM5B,SAAS,SAAqC,IAGX;AAHW,eACnD;AAAA,eAAW;AAAA,EAlIb,IAiIqD,IAEhD,oBAFgD,IAEhD;AAAA,IADH;AAAA;AAGA,QAAM,EAAE,UAAAA,WAAU,gBAAAC,gBAAe,IAAI,gBAAgB;AACrD,QAAM,cAAcA,gBAAe,OAA6B;AAChE,QAAM,QAAQD,UAAS,WAAW;AAElC,QAAM,kBAAkB,OAAO,eAAe,KAAK,CAAC;AACpD,QAAM,cAAc,MAAM,YAAY,MAAM,gBAAgB,SAAS,CAAC,CAAC;AACvE,QAAM,YAAY;AAAA,IAChB;AAAA,MACE,CAAC,kBACC,eAAe,OAAO,MAAM;AAC1B,wBAAgB,UAAU,eAAe,KAAK;AAC9C,sBAAc;AAAA,MAChB,CAAC;AAAA,MACH,CAAC,KAAK;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO;AACT;","names":["getShape","getShapeStream"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electric-sql/react",
3
- "version": "0.0.10",
3
+ "version": "0.1.0",
4
4
  "description": "React hooks for ElectricSQL",
5
5
  "type": "module",
6
6
  "main": "dist/cjs/index.cjs",
@@ -31,7 +31,7 @@
31
31
  "homepage": "https://next.electric-sql.com",
32
32
  "dependencies": {
33
33
  "use-sync-external-store": "^1.2.2",
34
- "@electric-sql/next": "0.1.1"
34
+ "@electric-sql/next": "0.2.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@testing-library/react": "^16.0.0",
@@ -28,19 +28,7 @@ export async function preloadShape(
28
28
  }
29
29
 
30
30
  export function sortedOptionsHash(options: ShapeStreamOptions): string {
31
- const shapeDef = JSON.stringify(
32
- options.shape,
33
- Object.keys(options.shape).sort()
34
- )
35
- // eslint-disable-next-line
36
- const { shape, ...optionsWithoutShapeDef } = options
37
- const allOptions = JSON.stringify(
38
- optionsWithoutShapeDef,
39
- Object.keys(options).sort()
40
- )
41
- const shapeHash = shapeDef + allOptions
42
-
43
- return shapeHash
31
+ return JSON.stringify(options, Object.keys(options).sort())
44
32
  }
45
33
 
46
34
  export function getShapeStream(options: ShapeStreamOptions): ShapeStream {