@electric-sql/react 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ export * from './react-hooks';
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export * from './react-hooks';
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './react-hooks'\n"],"mappings":"AAAA,cAAc;","names":[]}
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import { Shape, ShapeStream, ShapeStreamOptions, JsonSerializable } from '@electric-sql/next';
3
+ interface ShapeContextType {
4
+ getShape: (shapeStream: ShapeStream) => Shape;
5
+ getShapeStream: (options: ShapeStreamOptions) => ShapeStream;
6
+ }
7
+ export declare function preloadShape(options: ShapeStreamOptions): Promise<Shape>;
8
+ export declare function sortedOptionsHash(options: ShapeStreamOptions): string;
9
+ export declare function getShapeStream(options: ShapeStreamOptions): ShapeStream;
10
+ export declare function getShape(shapeStream: ShapeStream): Shape;
11
+ interface ShapeProviderProps {
12
+ children: React.ReactNode;
13
+ }
14
+ export declare function ShapesProvider({ children }: ShapeProviderProps): JSX.Element;
15
+ export declare function useShapeContext(): ShapeContextType;
16
+ interface UseShapeResult {
17
+ /**
18
+ * The array of rows that make up the Shape.
19
+ * @type {JsonSerializable}
20
+ */
21
+ data: JsonSerializable[];
22
+ /**
23
+ * The Shape instance used by this useShape
24
+ * @type(Shape)
25
+ */
26
+ shape: Shape;
27
+ error: Shape[`error`];
28
+ isError: boolean;
29
+ /**
30
+ * Has the ShapeStream caught up with the replication log from Postgres.
31
+ */
32
+ isUpToDate: boolean;
33
+ }
34
+ export declare function useShape(options: ShapeStreamOptions): UseShapeResult;
35
+ export {};
@@ -0,0 +1,130 @@
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
+ import React, { createContext, useEffect, useContext, useState } from "react";
37
+ import {
38
+ Shape,
39
+ ShapeStream
40
+ } from "@electric-sql/next";
41
+ const ShapesContext = createContext(null);
42
+ const streamCache = /* @__PURE__ */ new Map();
43
+ const shapeCache = /* @__PURE__ */ new Map();
44
+ function preloadShape(options) {
45
+ return __async(this, null, function* () {
46
+ const shapeStream = getShapeStream(options);
47
+ const shape = getShape(shapeStream);
48
+ yield shape.value;
49
+ return shape;
50
+ });
51
+ }
52
+ function sortedOptionsHash(options) {
53
+ const shapeDef = JSON.stringify(
54
+ options.shape,
55
+ Object.keys(options.shape).sort()
56
+ );
57
+ const _a = options, { shape } = _a, optionsWithoutShapeDef = __objRest(_a, ["shape"]);
58
+ const allOptions = JSON.stringify(
59
+ optionsWithoutShapeDef,
60
+ Object.keys(options).sort()
61
+ );
62
+ const shapeHash = shapeDef + allOptions;
63
+ return shapeHash;
64
+ }
65
+ function getShapeStream(options) {
66
+ const shapeHash = sortedOptionsHash(options);
67
+ if (streamCache.has(shapeHash)) {
68
+ return streamCache.get(shapeHash);
69
+ } else {
70
+ const newShapeStream = new ShapeStream(options);
71
+ streamCache.set(shapeHash, newShapeStream);
72
+ return newShapeStream;
73
+ }
74
+ }
75
+ function getShape(shapeStream) {
76
+ if (shapeCache.has(shapeStream)) {
77
+ return shapeCache.get(shapeStream);
78
+ } else {
79
+ const newShape = new Shape(shapeStream);
80
+ shapeCache.set(shapeStream, newShape);
81
+ return newShape;
82
+ }
83
+ }
84
+ function ShapesProvider({ children }) {
85
+ return /* @__PURE__ */ React.createElement(ShapesContext.Provider, { value: { getShape, getShapeStream } }, children);
86
+ }
87
+ function useShapeContext() {
88
+ const context = useContext(ShapesContext);
89
+ if (!context) {
90
+ throw new Error(`useShapeContext must be used within a ShapeProvider`);
91
+ }
92
+ return context;
93
+ }
94
+ function useShape(options) {
95
+ const { getShape: getShape2, getShapeStream: getShapeStream2 } = useShapeContext();
96
+ const shapeStream = getShapeStream2(options);
97
+ const shape = getShape2(shapeStream);
98
+ const [shapeData, setShapeData] = useState({
99
+ data: [...shape.valueSync.values()],
100
+ isUpToDate: shape.isUpToDate,
101
+ isError: shape.error !== false,
102
+ shape,
103
+ error: shape.error
104
+ });
105
+ useEffect(() => {
106
+ const unsubscribe = shape.subscribe((map) => {
107
+ setShapeData({
108
+ data: [...map.values()],
109
+ isUpToDate: shape.isUpToDate,
110
+ isError: shape.error !== false,
111
+ shape,
112
+ error: shape.error
113
+ });
114
+ });
115
+ return () => {
116
+ unsubscribe();
117
+ };
118
+ }, []);
119
+ return shapeData;
120
+ }
121
+ export {
122
+ ShapesProvider,
123
+ getShape,
124
+ getShapeStream,
125
+ preloadShape,
126
+ sortedOptionsHash,
127
+ useShape,
128
+ useShapeContext
129
+ };
130
+ //# sourceMappingURL=react-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import React, { createContext, useEffect, useContext, useState } from 'react'\nimport {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n JsonSerializable,\n} from '@electric-sql/next'\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 {JsonSerializable}\n */\n data: 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\nexport function useShape(options: ShapeStreamOptions): UseShapeResult {\n const { getShape, getShapeStream } = useShapeContext()\n const shapeStream = getShapeStream(options)\n const shape = getShape(shapeStream)\n const [shapeData, setShapeData] = useState<UseShapeResult>({\n data: [...shape.valueSync.values()],\n isUpToDate: shape.isUpToDate,\n isError: shape.error !== false,\n shape,\n error: shape.error,\n })\n\n useEffect(() => {\n // Subscribe to updates.\n const unsubscribe = shape.subscribe((map) => {\n setShapeData({\n data: [...map.values()],\n isUpToDate: shape.isUpToDate,\n isError: shape.error !== false,\n shape,\n error: shape.error,\n })\n })\n\n return () => {\n unsubscribe()\n }\n }, [])\n\n return shapeData\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,SAAS,eAAe,WAAW,YAAY,gBAAgB;AACtE;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAQP,MAAM,gBAAgB,cAAuC,IAAI;AAEjE,MAAM,cAAc,oBAAI,IAAyB;AACjD,MAAM,aAAa,oBAAI,IAAwB;AAE/C,SAAsB,aACpB,SACgB;AAAA;AAChB,UAAM,cAAc,eAAe,OAAO;AAC1C,UAAM,QAAQ,SAAS,WAAW;AAClC,UAAM,MAAM;AACZ,WAAO;AAAA,EACT;AAAA;AAEO,SAAS,kBAAkB,SAAqC;AACrE,QAAM,WAAW,KAAK;AAAA,IACpB,QAAQ;AAAA,IACR,OAAO,KAAK,QAAQ,KAAK,EAAE,KAAK;AAAA,EAClC;AAEA,QAA6C,cAArC,QAlCV,IAkC+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;AAqBO,SAAS,SAAS,SAA6C;AACpE,QAAM,EAAE,UAAAA,WAAU,gBAAAC,gBAAe,IAAI,gBAAgB;AACrD,QAAM,cAAcA,gBAAe,OAAO;AAC1C,QAAM,QAAQD,UAAS,WAAW;AAClC,QAAM,CAAC,WAAW,YAAY,IAAI,SAAyB;AAAA,IACzD,MAAM,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,YAAY,MAAM;AAAA,IAClB,SAAS,MAAM,UAAU;AAAA,IACzB;AAAA,IACA,OAAO,MAAM;AAAA,EACf,CAAC;AAED,YAAU,MAAM;AAEd,UAAM,cAAc,MAAM,UAAU,CAAC,QAAQ;AAC3C,mBAAa;AAAA,QACX,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC;AAAA,QACtB,YAAY,MAAM;AAAA,QAClB,SAAS,MAAM,UAAU;AAAA,QACzB;AAAA,QACA,OAAO,MAAM;AAAA,MACf,CAAC;AAAA,IACH,CAAC;AAED,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO;AACT;","names":["getShape","getShapeStream"]}
@@ -0,0 +1,111 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __rest = (this && this.__rest) || function (s, e) {
11
+ var t = {};
12
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
13
+ t[p] = s[p];
14
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
15
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
16
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
17
+ t[p[i]] = s[p[i]];
18
+ }
19
+ return t;
20
+ };
21
+ import React, { createContext, useEffect, useContext, useState } from 'react';
22
+ import { Shape, ShapeStream, } from '@electric-sql/next';
23
+ // Create a Context
24
+ const ShapesContext = createContext(null);
25
+ const streamCache = new Map();
26
+ const shapeCache = new Map();
27
+ export function preloadShape(options) {
28
+ return __awaiter(this, void 0, void 0, function* () {
29
+ const shapeStream = getShapeStream(options);
30
+ const shape = getShape(shapeStream);
31
+ yield shape.value;
32
+ return shape;
33
+ });
34
+ }
35
+ export function sortedOptionsHash(options) {
36
+ const shapeDef = JSON.stringify(options.shape, Object.keys(options.shape).sort());
37
+ // eslint-disable-next-line
38
+ const { shape } = options, optionsWithoutShapeDef = __rest(options, ["shape"]);
39
+ const allOptions = JSON.stringify(optionsWithoutShapeDef, Object.keys(options).sort());
40
+ const shapeHash = shapeDef + allOptions;
41
+ return shapeHash;
42
+ }
43
+ export function getShapeStream(options) {
44
+ const shapeHash = sortedOptionsHash(options);
45
+ // If the stream is already cached, return
46
+ if (streamCache.has(shapeHash)) {
47
+ // Return the ShapeStream
48
+ return streamCache.get(shapeHash);
49
+ }
50
+ else {
51
+ const newShapeStream = new ShapeStream(options);
52
+ streamCache.set(shapeHash, newShapeStream);
53
+ // Return the created shape
54
+ return newShapeStream;
55
+ }
56
+ }
57
+ export function getShape(shapeStream) {
58
+ // If the stream is already cached, return
59
+ if (shapeCache.has(shapeStream)) {
60
+ // Return the ShapeStream
61
+ return shapeCache.get(shapeStream);
62
+ }
63
+ else {
64
+ const newShape = new Shape(shapeStream);
65
+ shapeCache.set(shapeStream, newShape);
66
+ // Return the created shape
67
+ return newShape;
68
+ }
69
+ }
70
+ // Shapes Provider Component
71
+ export function ShapesProvider({ children }) {
72
+ // Provide the context value
73
+ return (<ShapesContext.Provider value={{ getShape, getShapeStream }}>
74
+ {children}
75
+ </ShapesContext.Provider>);
76
+ }
77
+ export function useShapeContext() {
78
+ const context = useContext(ShapesContext);
79
+ if (!context) {
80
+ throw new Error(`useShapeContext must be used within a ShapeProvider`);
81
+ }
82
+ return context;
83
+ }
84
+ export function useShape(options) {
85
+ const { getShape, getShapeStream } = useShapeContext();
86
+ const shapeStream = getShapeStream(options);
87
+ const shape = getShape(shapeStream);
88
+ const [shapeData, setShapeData] = useState({
89
+ data: [...shape.valueSync.values()],
90
+ isUpToDate: shape.isUpToDate,
91
+ isError: shape.error !== false,
92
+ shape,
93
+ error: shape.error,
94
+ });
95
+ useEffect(() => {
96
+ // Subscribe to updates.
97
+ const unsubscribe = shape.subscribe((map) => {
98
+ setShapeData({
99
+ data: [...map.values()],
100
+ isUpToDate: shape.isUpToDate,
101
+ isError: shape.error !== false,
102
+ shape,
103
+ error: shape.error,
104
+ });
105
+ });
106
+ return () => {
107
+ unsubscribe();
108
+ };
109
+ }, []);
110
+ return shapeData;
111
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electric-sql/react",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "React hooks for ElectricSQL",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,7 +18,7 @@
18
18
  },
19
19
  "homepage": "https://github.com/electric-sql/electric-next#readme",
20
20
  "dependencies": {
21
- "@electric-sql/next": "0.0.1"
21
+ "@electric-sql/next": "0.0.2"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@testing-library/react": "^16.0.0",