@electric-sql/react 0.0.9 → 0.0.10

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.
@@ -0,0 +1,184 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
9
+ var __objRest = (source, exclude) => {
10
+ var target = {};
11
+ for (var prop in source)
12
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
13
+ target[prop] = source[prop];
14
+ if (source != null && __getOwnPropSymbols)
15
+ for (var prop of __getOwnPropSymbols(source)) {
16
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
17
+ target[prop] = source[prop];
18
+ }
19
+ return target;
20
+ };
21
+ var __export = (target, all) => {
22
+ for (var name in all)
23
+ __defProp(target, name, { get: all[name], enumerable: true });
24
+ };
25
+ var __copyProps = (to, from, except, desc) => {
26
+ if (from && typeof from === "object" || typeof from === "function") {
27
+ for (let key of __getOwnPropNames(from))
28
+ if (!__hasOwnProp.call(to, key) && key !== except)
29
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
30
+ }
31
+ return to;
32
+ };
33
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
34
+ // If the importer is in node compatibility mode or this is not an ESM
35
+ // file that has been converted to a CommonJS file using a Babel-
36
+ // compatible transform (i.e. "__esModule" has not been set), then set
37
+ // "default" to the CommonJS "module.exports" for node compatibility.
38
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
39
+ mod
40
+ ));
41
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
42
+ var __async = (__this, __arguments, generator) => {
43
+ return new Promise((resolve, reject) => {
44
+ var fulfilled = (value) => {
45
+ try {
46
+ step(generator.next(value));
47
+ } catch (e) {
48
+ reject(e);
49
+ }
50
+ };
51
+ var rejected = (value) => {
52
+ try {
53
+ step(generator.throw(value));
54
+ } catch (e) {
55
+ reject(e);
56
+ }
57
+ };
58
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
59
+ step((generator = generator.apply(__this, __arguments)).next());
60
+ });
61
+ };
62
+
63
+ // src/index.ts
64
+ var src_exports = {};
65
+ __export(src_exports, {
66
+ ShapesProvider: () => ShapesProvider,
67
+ getShape: () => getShape,
68
+ getShapeStream: () => getShapeStream,
69
+ preloadShape: () => preloadShape,
70
+ sortedOptionsHash: () => sortedOptionsHash,
71
+ useShape: () => useShape,
72
+ useShapeContext: () => useShapeContext
73
+ });
74
+ module.exports = __toCommonJS(src_exports);
75
+
76
+ // src/react-hooks.tsx
77
+ var import_next = require("@electric-sql/next");
78
+ var import_react = __toESM(require("react"), 1);
79
+ var import_with_selector = require("use-sync-external-store/with-selector.js");
80
+ var ShapesContext = (0, import_react.createContext)(null);
81
+ var streamCache = /* @__PURE__ */ new Map();
82
+ var shapeCache = /* @__PURE__ */ new Map();
83
+ function preloadShape(options) {
84
+ return __async(this, null, function* () {
85
+ const shapeStream = getShapeStream(options);
86
+ const shape = getShape(shapeStream);
87
+ yield shape.value;
88
+ return shape;
89
+ });
90
+ }
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;
103
+ }
104
+ function getShapeStream(options) {
105
+ const shapeHash = sortedOptionsHash(options);
106
+ if (streamCache.has(shapeHash)) {
107
+ return streamCache.get(shapeHash);
108
+ } else {
109
+ const newShapeStream = new import_next.ShapeStream(options);
110
+ streamCache.set(shapeHash, newShapeStream);
111
+ return newShapeStream;
112
+ }
113
+ }
114
+ function getShape(shapeStream) {
115
+ if (shapeCache.has(shapeStream)) {
116
+ return shapeCache.get(shapeStream);
117
+ } else {
118
+ const newShape = new import_next.Shape(shapeStream);
119
+ shapeCache.set(shapeStream, newShape);
120
+ return newShape;
121
+ }
122
+ }
123
+ function ShapesProvider({ children }) {
124
+ return /* @__PURE__ */ import_react.default.createElement(ShapesContext.Provider, { value: { getShape, getShapeStream } }, children);
125
+ }
126
+ function useShapeContext() {
127
+ const context = (0, import_react.useContext)(ShapesContext);
128
+ if (!context) {
129
+ throw new Error(`useShapeContext must be used within a ShapeProvider`);
130
+ }
131
+ return context;
132
+ }
133
+ function shapeSubscribe(shape, callback) {
134
+ const unsubscribe = shape.subscribe(callback);
135
+ return () => {
136
+ unsubscribe();
137
+ };
138
+ }
139
+ function parseShapeData(shape) {
140
+ return {
141
+ data: [...shape.valueSync.values()],
142
+ isUpToDate: shape.isUpToDate,
143
+ isError: shape.error !== false,
144
+ shape,
145
+ error: shape.error
146
+ };
147
+ }
148
+ var identity = (arg) => arg;
149
+ function useShape(_a) {
150
+ var _b = _a, {
151
+ selector = identity
152
+ } = _b, options = __objRest(_b, [
153
+ "selector"
154
+ ]);
155
+ const { getShape: getShape2, getShapeStream: getShapeStream2 } = useShapeContext();
156
+ const shapeStream = getShapeStream2(options);
157
+ const shape = getShape2(shapeStream);
158
+ const latestShapeData = (0, import_react.useRef)(parseShapeData(shape));
159
+ const getSnapshot = import_react.default.useCallback(() => latestShapeData.current, []);
160
+ const shapeData = (0, import_with_selector.useSyncExternalStoreWithSelector)(
161
+ (0, import_react.useCallback)(
162
+ (onStoreChange) => shapeSubscribe(shape, () => {
163
+ latestShapeData.current = parseShapeData(shape);
164
+ onStoreChange();
165
+ }),
166
+ [shape]
167
+ ),
168
+ getSnapshot,
169
+ getSnapshot,
170
+ selector
171
+ );
172
+ return shapeData;
173
+ }
174
+ // Annotate the CommonJS export names for ESM import in node:
175
+ 0 && (module.exports = {
176
+ ShapesProvider,
177
+ getShape,
178
+ getShapeStream,
179
+ preloadShape,
180
+ sortedOptionsHash,
181
+ useShape,
182
+ useShapeContext
183
+ });
184
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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"]}
@@ -0,0 +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};
2
+ //# sourceMappingURL=index.browser.mjs.map
@@ -0,0 +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"]}
@@ -0,0 +1,42 @@
1
+ import { ShapeStreamOptions, Shape, ShapeStream, JsonSerializable } from '@electric-sql/next';
2
+ import React from 'react';
3
+
4
+ interface ShapeContextType {
5
+ getShape: (shapeStream: ShapeStream) => Shape;
6
+ getShapeStream: (options: ShapeStreamOptions) => ShapeStream;
7
+ }
8
+ declare function preloadShape(options: ShapeStreamOptions): Promise<Shape>;
9
+ declare function sortedOptionsHash(options: ShapeStreamOptions): string;
10
+ declare function getShapeStream(options: ShapeStreamOptions): ShapeStream;
11
+ declare function getShape(shapeStream: ShapeStream): Shape;
12
+ interface ShapeProviderProps {
13
+ children: React.ReactNode;
14
+ }
15
+ declare function ShapesProvider({ children }: ShapeProviderProps): JSX.Element;
16
+ declare function useShapeContext(): ShapeContextType;
17
+ interface UseShapeResult {
18
+ /**
19
+ * The array of rows that make up the Shape.
20
+ * @type {{ [key: string]: JsonSerializable }[]}
21
+ */
22
+ data: {
23
+ [key: string]: JsonSerializable;
24
+ }[];
25
+ /**
26
+ * The Shape instance used by this useShape
27
+ * @type(Shape)
28
+ */
29
+ shape: Shape;
30
+ error: Shape[`error`];
31
+ isError: boolean;
32
+ /**
33
+ * Has the ShapeStream caught up with the replication log from Postgres.
34
+ */
35
+ isUpToDate: boolean;
36
+ }
37
+ interface UseShapeOptions<Selection> extends ShapeStreamOptions {
38
+ selector?: (value: UseShapeResult) => Selection;
39
+ }
40
+ declare function useShape<Selection = UseShapeResult>({ selector, ...options }: UseShapeOptions<Selection>): Selection;
41
+
42
+ export { ShapesProvider, getShape, getShapeStream, preloadShape, sortedOptionsHash, useShape, useShapeContext };
@@ -0,0 +1,125 @@
1
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
2
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
3
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
4
+ var __objRest = (source, exclude) => {
5
+ var target = {};
6
+ for (var prop in source)
7
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
8
+ target[prop] = source[prop];
9
+ if (source != null && __getOwnPropSymbols)
10
+ for (var prop of __getOwnPropSymbols(source)) {
11
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
12
+ target[prop] = source[prop];
13
+ }
14
+ return target;
15
+ };
16
+
17
+ // src/react-hooks.tsx
18
+ import {
19
+ Shape,
20
+ ShapeStream
21
+ } from "@electric-sql/next";
22
+ import React, { createContext, useCallback, useContext, useRef } from "react";
23
+ import { useSyncExternalStoreWithSelector } from "use-sync-external-store/with-selector.js";
24
+ var ShapesContext = createContext(null);
25
+ var streamCache = /* @__PURE__ */ new Map();
26
+ var shapeCache = /* @__PURE__ */ new Map();
27
+ async function preloadShape(options) {
28
+ const shapeStream = getShapeStream(options);
29
+ const shape = getShape(shapeStream);
30
+ await shape.value;
31
+ return shape;
32
+ }
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;
45
+ }
46
+ function getShapeStream(options) {
47
+ const shapeHash = sortedOptionsHash(options);
48
+ if (streamCache.has(shapeHash)) {
49
+ return streamCache.get(shapeHash);
50
+ } else {
51
+ const newShapeStream = new ShapeStream(options);
52
+ streamCache.set(shapeHash, newShapeStream);
53
+ return newShapeStream;
54
+ }
55
+ }
56
+ function getShape(shapeStream) {
57
+ if (shapeCache.has(shapeStream)) {
58
+ return shapeCache.get(shapeStream);
59
+ } else {
60
+ const newShape = new Shape(shapeStream);
61
+ shapeCache.set(shapeStream, newShape);
62
+ return newShape;
63
+ }
64
+ }
65
+ function ShapesProvider({ children }) {
66
+ return /* @__PURE__ */ React.createElement(ShapesContext.Provider, { value: { getShape, getShapeStream } }, children);
67
+ }
68
+ function useShapeContext() {
69
+ const context = useContext(ShapesContext);
70
+ if (!context) {
71
+ throw new Error(`useShapeContext must be used within a ShapeProvider`);
72
+ }
73
+ return context;
74
+ }
75
+ function shapeSubscribe(shape, callback) {
76
+ const unsubscribe = shape.subscribe(callback);
77
+ return () => {
78
+ unsubscribe();
79
+ };
80
+ }
81
+ function parseShapeData(shape) {
82
+ return {
83
+ data: [...shape.valueSync.values()],
84
+ isUpToDate: shape.isUpToDate,
85
+ isError: shape.error !== false,
86
+ shape,
87
+ error: shape.error
88
+ };
89
+ }
90
+ var identity = (arg) => arg;
91
+ function useShape(_a) {
92
+ var _b = _a, {
93
+ selector = identity
94
+ } = _b, options = __objRest(_b, [
95
+ "selector"
96
+ ]);
97
+ const { getShape: getShape2, getShapeStream: getShapeStream2 } = useShapeContext();
98
+ const shapeStream = getShapeStream2(options);
99
+ const shape = getShape2(shapeStream);
100
+ const latestShapeData = useRef(parseShapeData(shape));
101
+ const getSnapshot = React.useCallback(() => latestShapeData.current, []);
102
+ const shapeData = useSyncExternalStoreWithSelector(
103
+ useCallback(
104
+ (onStoreChange) => shapeSubscribe(shape, () => {
105
+ latestShapeData.current = parseShapeData(shape);
106
+ onStoreChange();
107
+ }),
108
+ [shape]
109
+ ),
110
+ getSnapshot,
111
+ getSnapshot,
112
+ selector
113
+ );
114
+ return shapeData;
115
+ }
116
+ export {
117
+ ShapesProvider,
118
+ getShape,
119
+ getShapeStream,
120
+ preloadShape,
121
+ sortedOptionsHash,
122
+ useShape,
123
+ useShapeContext
124
+ };
125
+ //# sourceMappingURL=index.legacy-esm.js.map
@@ -0,0 +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"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,147 @@
1
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
2
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
3
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
4
+ var __objRest = (source, exclude) => {
5
+ var target = {};
6
+ for (var prop in source)
7
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
8
+ target[prop] = source[prop];
9
+ if (source != null && __getOwnPropSymbols)
10
+ for (var prop of __getOwnPropSymbols(source)) {
11
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
12
+ target[prop] = source[prop];
13
+ }
14
+ return target;
15
+ };
16
+ var __async = (__this, __arguments, generator) => {
17
+ return new Promise((resolve, reject) => {
18
+ var fulfilled = (value) => {
19
+ try {
20
+ step(generator.next(value));
21
+ } catch (e) {
22
+ reject(e);
23
+ }
24
+ };
25
+ var rejected = (value) => {
26
+ try {
27
+ step(generator.throw(value));
28
+ } catch (e) {
29
+ reject(e);
30
+ }
31
+ };
32
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
33
+ step((generator = generator.apply(__this, __arguments)).next());
34
+ });
35
+ };
36
+
37
+ // src/react-hooks.tsx
38
+ import {
39
+ Shape,
40
+ ShapeStream
41
+ } from "@electric-sql/next";
42
+ import React, { createContext, useCallback, useContext, useRef } from "react";
43
+ import { useSyncExternalStoreWithSelector } from "use-sync-external-store/with-selector.js";
44
+ var ShapesContext = createContext(null);
45
+ var streamCache = /* @__PURE__ */ new Map();
46
+ var shapeCache = /* @__PURE__ */ new Map();
47
+ function preloadShape(options) {
48
+ return __async(this, null, function* () {
49
+ const shapeStream = getShapeStream(options);
50
+ const shape = getShape(shapeStream);
51
+ yield shape.value;
52
+ return shape;
53
+ });
54
+ }
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;
67
+ }
68
+ function getShapeStream(options) {
69
+ const shapeHash = sortedOptionsHash(options);
70
+ if (streamCache.has(shapeHash)) {
71
+ return streamCache.get(shapeHash);
72
+ } else {
73
+ const newShapeStream = new ShapeStream(options);
74
+ streamCache.set(shapeHash, newShapeStream);
75
+ return newShapeStream;
76
+ }
77
+ }
78
+ function getShape(shapeStream) {
79
+ if (shapeCache.has(shapeStream)) {
80
+ return shapeCache.get(shapeStream);
81
+ } else {
82
+ const newShape = new Shape(shapeStream);
83
+ shapeCache.set(shapeStream, newShape);
84
+ return newShape;
85
+ }
86
+ }
87
+ function ShapesProvider({ children }) {
88
+ return /* @__PURE__ */ React.createElement(ShapesContext.Provider, { value: { getShape, getShapeStream } }, children);
89
+ }
90
+ function useShapeContext() {
91
+ const context = useContext(ShapesContext);
92
+ if (!context) {
93
+ throw new Error(`useShapeContext must be used within a ShapeProvider`);
94
+ }
95
+ return context;
96
+ }
97
+ function shapeSubscribe(shape, callback) {
98
+ const unsubscribe = shape.subscribe(callback);
99
+ return () => {
100
+ unsubscribe();
101
+ };
102
+ }
103
+ function parseShapeData(shape) {
104
+ return {
105
+ data: [...shape.valueSync.values()],
106
+ isUpToDate: shape.isUpToDate,
107
+ isError: shape.error !== false,
108
+ shape,
109
+ error: shape.error
110
+ };
111
+ }
112
+ var identity = (arg) => arg;
113
+ function useShape(_a) {
114
+ var _b = _a, {
115
+ selector = identity
116
+ } = _b, options = __objRest(_b, [
117
+ "selector"
118
+ ]);
119
+ const { getShape: getShape2, getShapeStream: getShapeStream2 } = useShapeContext();
120
+ const shapeStream = getShapeStream2(options);
121
+ const shape = getShape2(shapeStream);
122
+ const latestShapeData = useRef(parseShapeData(shape));
123
+ const getSnapshot = React.useCallback(() => latestShapeData.current, []);
124
+ const shapeData = useSyncExternalStoreWithSelector(
125
+ useCallback(
126
+ (onStoreChange) => shapeSubscribe(shape, () => {
127
+ latestShapeData.current = parseShapeData(shape);
128
+ onStoreChange();
129
+ }),
130
+ [shape]
131
+ ),
132
+ getSnapshot,
133
+ getSnapshot,
134
+ selector
135
+ );
136
+ return shapeData;
137
+ }
138
+ export {
139
+ ShapesProvider,
140
+ getShape,
141
+ getShapeStream,
142
+ preloadShape,
143
+ sortedOptionsHash,
144
+ useShape,
145
+ useShapeContext
146
+ };
147
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +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":"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","names":["getShape","getShapeStream"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electric-sql/react",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
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.0"
34
+ "@electric-sql/next": "0.1.1"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@testing-library/react": "^16.0.0",
@@ -72,7 +72,7 @@
72
72
  }
73
73
  },
74
74
  "scripts": {
75
- "test": "npx vitest",
75
+ "test": "pnpm exec vitest",
76
76
  "typecheck": "tsc -p tsconfig.json",
77
77
  "build": "shx rm -rf dist && concurrently \"tsup\" \"tsc -p tsconfig.build.json\"",
78
78
  "stylecheck": "eslint . --quiet",
@@ -5,7 +5,7 @@ import {
5
5
  ShapeStreamOptions,
6
6
  } from '@electric-sql/next'
7
7
  import React, { createContext, useCallback, useContext, useRef } from 'react'
8
- import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector'
8
+ import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'
9
9
 
10
10
  interface ShapeContextType {
11
11
  getShape: (shapeStream: ShapeStream) => Shape