@electric-sql/react 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,11 +20,11 @@ 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 } = useShape({
23
+ const { isLoading, data } = useShape({
24
24
  url: "http://my-api.com/shape/foo",
25
25
  })
26
26
 
27
- if (!isUpToDate) {
27
+ if (isLoading) {
28
28
  return <div>loading</div>
29
29
  }
30
30
 
@@ -132,7 +132,9 @@ function useShape(_a) {
132
132
  } = _b, options = __objRest(_b, [
133
133
  "selector"
134
134
  ]);
135
- const shapeStream = getShapeStream(options);
135
+ const shapeStream = getShapeStream(
136
+ options
137
+ );
136
138
  const shape = getShape(shapeStream);
137
139
  const useShapeData = import_react.default.useMemo(() => {
138
140
  let latestShapeData = parseShapeData(shape);
@@ -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} 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 /** 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>(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 isLoading: shape.isLoading(),\n lastSyncedAt: shape.lastSyncedAt(),\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;AAqBA,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,WAAW,MAAM,UAAU;AAAA,IAC3B,cAAc,MAAM,aAAa;AAAA,IACjC,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,EA7Gb,IA4GE,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"]}
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.value\n return shape\n}\n\nexport function sortedOptionsHash<T>(options: ShapeStreamOptions<T>): string {\n return JSON.stringify(options, Object.keys(options).sort())\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\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<unknown>>(\n shapeStream: ShapeStream<T>\n): 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<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 /** 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.valueSync.values()],\n isLoading: shape.isLoading(),\n lastSyncedAt: shape.lastSyncedAt(),\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<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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAMO;AACP,mBAAkB;AAClB,2BAAiD;AAKjD,IAAM,cAAc,oBAAI,IAAgC;AACxD,IAAM,aAAa,oBAAI,IAAsC;AAE7D,SAAsB,aACpB,SACmB;AAAA;AACnB,UAAM,cAAc,eAAkB,OAAO;AAC7C,UAAM,QAAQ,SAAY,WAAW;AACrC,UAAM,MAAM;AACZ,WAAO;AAAA,EACT;AAAA;AAEO,SAAS,kBAAqB,SAAwC;AAC3E,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,SACd,aACU;AAEV,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;AAqBA,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,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,WAAW,MAAM,UAAU;AAAA,IAC3B,cAAc,MAAM,aAAa;AAAA,IACjC,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,EAxHb,IAuHE,IAEG,oBAFH,IAEG;AAAA,IADH;AAAA;AAGA,QAAM,cAAc;AAAA,IAClB;AAAA,EACF;AACA,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"]}
@@ -1,2 +1,2 @@
1
- var h=Object.getOwnPropertySymbols;var f=Object.prototype.hasOwnProperty,x=Object.prototype.propertyIsEnumerable;var l=(e,t)=>{var a={};for(var r in e)f.call(e,r)&&t.indexOf(r)<0&&(a[r]=e[r]);if(e!=null&&h)for(var r of h(e))t.indexOf(r)<0&&x.call(e,r)&&(a[r]=e[r]);return a};var T=(e,t,a)=>new Promise((r,p)=>{var n=o=>{try{s(a.next(o))}catch(S){p(S)}},u=o=>{try{s(a.throw(o))}catch(S){p(S)}},s=o=>o.done?r(o.value):Promise.resolve(o.value).then(n,u);s((a=a.apply(e,t)).next())});import{Shape as b,ShapeStream as g}from"@electric-sql/client";import D from"react";import{useSyncExternalStoreWithSelector as O}from"use-sync-external-store/with-selector.js";var c=new Map,i=new Map;function j(e){return T(this,null,function*(){let t=d(e),a=w(t);return yield a.value,a})}function y(e){return JSON.stringify(e,Object.keys(e).sort())}function d(e){let t=y(e);if(c.has(t))return c.get(t);{let a=new g(e);return c.set(t,a),a}}function w(e){if(i.has(e))return i.get(e);{let t=new b(e);return i.set(e,t),t}}function U(e,t){let a=e.subscribe(t);return()=>{a()}}function m(e){return{data:[...e.valueSync.values()],isLoading:e.isLoading(),lastSyncedAt:e.lastSyncedAt(),isError:e.error!==!1,shape:e,error:e.error}}function v(e){return e}function k(a){var r=a,{selector:e=v}=r,t=l(r,["selector"]);let p=d(t),n=w(p);return D.useMemo(()=>{let s=m(n),o=()=>s,S=R=>U(n,()=>{s=m(n),R()});return()=>O(S,o,o,e)},[n,e])()}export{w as getShape,d as getShapeStream,j as preloadShape,y as sortedOptionsHash,k as useShape};
1
+ var h=Object.getOwnPropertySymbols;var R=Object.prototype.hasOwnProperty,f=Object.prototype.propertyIsEnumerable;var w=(e,t)=>{var n={};for(var a in e)R.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(e!=null&&h)for(var a of h(e))t.indexOf(a)<0&&f.call(e,a)&&(n[a]=e[a]);return n};var T=(e,t,n)=>new Promise((a,p)=>{var r=o=>{try{s(n.next(o))}catch(S){p(S)}},c=o=>{try{s(n.throw(o))}catch(S){p(S)}},s=o=>o.done?a(o.value):Promise.resolve(o.value).then(r,c);s((n=n.apply(e,t)).next())});import{Shape as k,ShapeStream as D}from"@electric-sql/client";import b from"react";import{useSyncExternalStoreWithSelector as g}from"use-sync-external-store/with-selector.js";var u=new Map,i=new Map;function H(e){return T(this,null,function*(){let t=m(e),n=d(t);return yield n.value,n})}function U(e){return JSON.stringify(e,Object.keys(e).sort())}function m(e){let t=U(e);if(u.has(t))return u.get(t);{let n=new D(e);return u.set(t,n),n}}function d(e){if(i.has(e))return i.get(e);{let t=new k(e);return i.set(e,t),t}}function y(e,t){let n=e.subscribe(t);return()=>{n()}}function l(e){return{data:[...e.valueSync.values()],isLoading:e.isLoading(),lastSyncedAt:e.lastSyncedAt(),isError:e.error!==!1,shape:e,error:e.error}}function O(e){return e}function j(n){var a=n,{selector:e=O}=a,t=w(a,["selector"]);let p=m(t),r=d(p);return b.useMemo(()=>{let s=l(r),o=()=>s,S=x=>y(r,()=>{s=l(r),x()});return()=>g(S,o,o,e)},[r,e])()}export{d as getShape,m as getShapeStream,H as preloadShape,U as sortedOptionsHash,j 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} 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 /** 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>(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 isLoading: shape.isLoading(),\n lastSyncedAt: shape.lastSyncedAt(),\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,CAqBA,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,UAAWA,EAAM,UAAU,EAC3B,aAAcA,EAAM,aAAa,EACjC,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,CA7Gb,EA4GEI,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"]}
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.value\n return shape\n}\n\nexport function sortedOptionsHash<T>(options: ShapeStreamOptions<T>): string {\n return JSON.stringify(options, Object.keys(options).sort())\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\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<unknown>>(\n shapeStream: ShapeStream<T>\n): 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<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 /** 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.valueSync.values()],\n isLoading: shape.isLoading(),\n lastSyncedAt: shape.lastSyncedAt(),\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<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,MACLA,CACT,GAEO,SAASE,EAAqBN,EAAwC,CAC3E,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,EACdH,EACU,CAEV,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,CAqBA,SAASE,EACPR,EACAS,EACA,CACA,IAAMC,EAAcV,EAAM,UAAUS,CAAQ,EAC5C,MAAO,IAAM,CACXC,EAAY,CACd,CACF,CAEA,SAASC,EACPX,EACmB,CACnB,MAAO,CACL,KAAM,CAAC,GAAGA,EAAM,UAAU,OAAO,CAAC,EAClC,UAAWA,EAAM,UAAU,EAC3B,aAAcA,EAAM,aAAa,EACjC,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,CAxHb,EAuHEI,EAEGpB,EAAAsB,EAFHF,EAEG,CADH,aAGA,IAAMlB,EAAcC,EAClBH,CACF,EACMI,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,10 +1,10 @@
1
- import { Row, ShapeStreamOptions, Shape, ShapeStream } from '@electric-sql/client';
1
+ import { Row, ShapeStreamOptions, GetExtensions, Shape, ShapeStream } from '@electric-sql/client';
2
2
 
3
- declare function preloadShape<T extends Row = Row>(options: ShapeStreamOptions): Promise<Shape<T>>;
4
- declare function sortedOptionsHash(options: ShapeStreamOptions): string;
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> {
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
8
  /**
9
9
  * The array of rows that make up the Shape.
10
10
  * @type {T[]}
@@ -22,9 +22,9 @@ interface UseShapeResult<T extends Row = Row> {
22
22
  error: Shape<T>[`error`];
23
23
  isError: boolean;
24
24
  }
25
- interface UseShapeOptions<SourceData extends Row, Selection> extends ShapeStreamOptions {
25
+ interface UseShapeOptions<SourceData extends Row<unknown>, Selection> extends ShapeStreamOptions<GetExtensions<SourceData>> {
26
26
  selector?: (value: UseShapeResult<SourceData>) => Selection;
27
27
  }
28
- declare function useShape<SourceData extends Row = Row, Selection = UseShapeResult<SourceData>>({ selector, ...options }: UseShapeOptions<SourceData, Selection>): Selection;
28
+ declare function useShape<SourceData extends Row<unknown> = Row, Selection = UseShapeResult<SourceData>>({ selector, ...options }: UseShapeOptions<SourceData, Selection>): Selection;
29
29
 
30
30
  export { type UseShapeResult, getShape, getShapeStream, preloadShape, sortedOptionsHash, useShape };
@@ -76,7 +76,9 @@ function useShape(_a) {
76
76
  } = _b, options = __objRest(_b, [
77
77
  "selector"
78
78
  ]);
79
- const shapeStream = getShapeStream(options);
79
+ const shapeStream = getShapeStream(
80
+ options
81
+ );
80
82
  const shape = getShape(shapeStream);
81
83
  const useShapeData = React.useMemo(() => {
82
84
  let latestShapeData = parseShapeData(shape);
@@ -1 +1 @@
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 /** 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>(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 isLoading: shape.isLoading(),\n lastSyncedAt: shape.lastSyncedAt(),\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;AAqBA,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,WAAW,MAAM,UAAU;AAAA,IAC3B,cAAc,MAAM,aAAa;AAAA,IACjC,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,EA7Gb,IA4GE,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":[]}
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.value\n return shape\n}\n\nexport function sortedOptionsHash<T>(options: ShapeStreamOptions<T>): string {\n return JSON.stringify(options, Object.keys(options).sort())\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\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<unknown>>(\n shapeStream: ShapeStream<T>\n): 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<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 /** 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.valueSync.values()],\n isLoading: shape.isLoading(),\n lastSyncedAt: shape.lastSyncedAt(),\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<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;AAEO,SAAS,kBAAqB,SAAwC;AAC3E,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,SACd,aACU;AAEV,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;AAqBA,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,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,WAAW,MAAM,UAAU;AAAA,IAC3B,cAAc,MAAM,aAAa;AAAA,IACjC,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,EAxHb,IAuHE,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
@@ -98,7 +98,9 @@ function useShape(_a) {
98
98
  } = _b, options = __objRest(_b, [
99
99
  "selector"
100
100
  ]);
101
- const shapeStream = getShapeStream(options);
101
+ const shapeStream = getShapeStream(
102
+ options
103
+ );
102
104
  const shape = getShape(shapeStream);
103
105
  const useShapeData = React.useMemo(() => {
104
106
  let latestShapeData = parseShapeData(shape);
@@ -1 +1 @@
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 /** 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>(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 isLoading: shape.isLoading(),\n lastSyncedAt: shape.lastSyncedAt(),\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;AAqBA,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,WAAW,MAAM,UAAU;AAAA,IAC3B,cAAc,MAAM,aAAa;AAAA,IACjC,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,EA7Gb,IA4GE,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":[]}
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.value\n return shape\n}\n\nexport function sortedOptionsHash<T>(options: ShapeStreamOptions<T>): string {\n return JSON.stringify(options, Object.keys(options).sort())\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\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<unknown>>(\n shapeStream: ShapeStream<T>\n): 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<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 /** 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.valueSync.values()],\n isLoading: shape.isLoading(),\n lastSyncedAt: shape.lastSyncedAt(),\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<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,SAAsB,aACpB,SACmB;AAAA;AACnB,UAAM,cAAc,eAAkB,OAAO;AAC7C,UAAM,QAAQ,SAAY,WAAW;AACrC,UAAM,MAAM;AACZ,WAAO;AAAA,EACT;AAAA;AAEO,SAAS,kBAAqB,SAAwC;AAC3E,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,SACd,aACU;AAEV,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;AAqBA,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,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,WAAW,MAAM,UAAU;AAAA,IAC3B,cAAc,MAAM,aAAa;AAAA,IACjC,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,EAxHb,IAuHE,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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electric-sql/react",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
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://electric-sql.com",
32
32
  "dependencies": {
33
33
  "use-sync-external-store": "^1.2.2",
34
- "@electric-sql/client": "0.5.1"
34
+ "@electric-sql/client": "0.6.1"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@testing-library/react": "^16.0.0",
@@ -3,15 +3,19 @@ import {
3
3
  ShapeStream,
4
4
  ShapeStreamOptions,
5
5
  Row,
6
+ GetExtensions,
6
7
  } from '@electric-sql/client'
7
8
  import React from 'react'
8
9
  import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'
9
10
 
10
- const streamCache = new Map<string, ShapeStream>()
11
- const shapeCache = new Map<ShapeStream, Shape>()
11
+ type UnknownShape = Shape<Row<unknown>>
12
+ type UnknownShapeStream = ShapeStream<Row<unknown>>
12
13
 
13
- export async function preloadShape<T extends Row = Row>(
14
- options: ShapeStreamOptions
14
+ const streamCache = new Map<string, UnknownShapeStream>()
15
+ const shapeCache = new Map<UnknownShapeStream, UnknownShape>()
16
+
17
+ export async function preloadShape<T extends Row<unknown> = Row>(
18
+ options: ShapeStreamOptions<GetExtensions<T>>
15
19
  ): Promise<Shape<T>> {
16
20
  const shapeStream = getShapeStream<T>(options)
17
21
  const shape = getShape<T>(shapeStream)
@@ -19,12 +23,12 @@ export async function preloadShape<T extends Row = Row>(
19
23
  return shape
20
24
  }
21
25
 
22
- export function sortedOptionsHash(options: ShapeStreamOptions): string {
26
+ export function sortedOptionsHash<T>(options: ShapeStreamOptions<T>): string {
23
27
  return JSON.stringify(options, Object.keys(options).sort())
24
28
  }
25
29
 
26
- export function getShapeStream<T extends Row = Row>(
27
- options: ShapeStreamOptions
30
+ export function getShapeStream<T extends Row<unknown>>(
31
+ options: ShapeStreamOptions<GetExtensions<T>>
28
32
  ): ShapeStream<T> {
29
33
  const shapeHash = sortedOptionsHash(options)
30
34
 
@@ -42,7 +46,9 @@ export function getShapeStream<T extends Row = Row>(
42
46
  }
43
47
  }
44
48
 
45
- export function getShape<T extends Row>(shapeStream: ShapeStream<T>): Shape<T> {
49
+ export function getShape<T extends Row<unknown>>(
50
+ shapeStream: ShapeStream<T>
51
+ ): Shape<T> {
46
52
  // If the stream is already cached, return
47
53
  if (shapeCache.has(shapeStream)) {
48
54
  // Return the ShapeStream
@@ -57,7 +63,7 @@ export function getShape<T extends Row>(shapeStream: ShapeStream<T>): Shape<T> {
57
63
  }
58
64
  }
59
65
 
60
- export interface UseShapeResult<T extends Row = Row> {
66
+ export interface UseShapeResult<T extends Row<unknown> = Row> {
61
67
  /**
62
68
  * The array of rows that make up the Shape.
63
69
  * @type {T[]}
@@ -76,14 +82,19 @@ export interface UseShapeResult<T extends Row = Row> {
76
82
  isError: boolean
77
83
  }
78
84
 
79
- function shapeSubscribe<T extends Row>(shape: Shape<T>, callback: () => void) {
85
+ function shapeSubscribe<T extends Row<unknown>>(
86
+ shape: Shape<T>,
87
+ callback: () => void
88
+ ) {
80
89
  const unsubscribe = shape.subscribe(callback)
81
90
  return () => {
82
91
  unsubscribe()
83
92
  }
84
93
  }
85
94
 
86
- function parseShapeData<T extends Row>(shape: Shape<T>): UseShapeResult<T> {
95
+ function parseShapeData<T extends Row<unknown>>(
96
+ shape: Shape<T>
97
+ ): UseShapeResult<T> {
87
98
  return {
88
99
  data: [...shape.valueSync.values()],
89
100
  isLoading: shape.isLoading(),
@@ -98,19 +109,21 @@ function identity<T>(arg: T): T {
98
109
  return arg
99
110
  }
100
111
 
101
- interface UseShapeOptions<SourceData extends Row, Selection>
102
- extends ShapeStreamOptions {
112
+ interface UseShapeOptions<SourceData extends Row<unknown>, Selection>
113
+ extends ShapeStreamOptions<GetExtensions<SourceData>> {
103
114
  selector?: (value: UseShapeResult<SourceData>) => Selection
104
115
  }
105
116
 
106
117
  export function useShape<
107
- SourceData extends Row = Row,
118
+ SourceData extends Row<unknown> = Row,
108
119
  Selection = UseShapeResult<SourceData>,
109
120
  >({
110
121
  selector = identity as (arg: UseShapeResult<SourceData>) => Selection,
111
122
  ...options
112
123
  }: UseShapeOptions<SourceData, Selection>): Selection {
113
- const shapeStream = getShapeStream<SourceData>(options as ShapeStreamOptions)
124
+ const shapeStream = getShapeStream<SourceData>(
125
+ options as ShapeStreamOptions<GetExtensions<SourceData>>
126
+ )
114
127
  const shape = getShape<SourceData>(shapeStream)
115
128
 
116
129
  const useShapeData = React.useMemo(() => {