srasm 0.0.0 → 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.
- package/dist/index.cjs +162 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +41 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +124 -0
- package/dist/index.js.map +1 -0
- package/package.json +21 -5
- package/dist/assets/index-DcNG4owL.js +0 -1951
- package/dist/assets/index-DrIpgKtZ.css +0 -1
- package/dist/index.html +0 -16
- package/dist/vite.svg +0 -1
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
createStateStore: () => createStateStore,
|
|
34
|
+
logClick: () => logClick
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
|
|
38
|
+
// src/context/createStateStore.tsx
|
|
39
|
+
var import_react = __toESM(require("react"), 1);
|
|
40
|
+
|
|
41
|
+
// src/utils/deepEqual.ts
|
|
42
|
+
function deepEqual(obj1, obj2) {
|
|
43
|
+
if (obj1 === obj2) return true;
|
|
44
|
+
if (typeof obj1 !== "object" || typeof obj2 !== "object" || obj1 === null || obj2 === null) {
|
|
45
|
+
return Object.is(obj1, obj2);
|
|
46
|
+
}
|
|
47
|
+
const keys1 = Object.keys(obj1);
|
|
48
|
+
const keys2 = Object.keys(obj2);
|
|
49
|
+
if (keys1.length !== keys2.length) return false;
|
|
50
|
+
for (const key of keys1) {
|
|
51
|
+
if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/context/createStateStore.tsx
|
|
59
|
+
var import_with_selector = require("use-sync-external-store/with-selector");
|
|
60
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
61
|
+
function createStateStore(initialSlices) {
|
|
62
|
+
let storeState = { ...initialSlices };
|
|
63
|
+
const sliceListeners = /* @__PURE__ */ new Map();
|
|
64
|
+
const getSliceListeners = (k) => {
|
|
65
|
+
let set = sliceListeners.get(k);
|
|
66
|
+
if (!set) {
|
|
67
|
+
set = /* @__PURE__ */ new Set();
|
|
68
|
+
sliceListeners.set(k, set);
|
|
69
|
+
}
|
|
70
|
+
return set;
|
|
71
|
+
};
|
|
72
|
+
const subscribeSlice = (key, listener) => {
|
|
73
|
+
const set = getSliceListeners(key);
|
|
74
|
+
set.add(listener);
|
|
75
|
+
return () => set.delete(listener);
|
|
76
|
+
};
|
|
77
|
+
const emitSlice = (key) => {
|
|
78
|
+
getSliceListeners(key).forEach((l) => l());
|
|
79
|
+
};
|
|
80
|
+
const updateSlice = (key, payload, useDeepEqualCheck) => {
|
|
81
|
+
const current = storeState[key];
|
|
82
|
+
let next = current;
|
|
83
|
+
if (typeof payload === "function") {
|
|
84
|
+
next = payload(current);
|
|
85
|
+
if (Object.is(current, next)) return;
|
|
86
|
+
if (useDeepEqualCheck && deepEqual(current, next)) return;
|
|
87
|
+
} else {
|
|
88
|
+
if (typeof current === "object" && current !== null && typeof payload === "object" && payload !== null) {
|
|
89
|
+
next = { ...current, ...payload };
|
|
90
|
+
if (useDeepEqualCheck && deepEqual(current, next)) return;
|
|
91
|
+
} else {
|
|
92
|
+
if (Object.is(current, payload)) return;
|
|
93
|
+
if (useDeepEqualCheck && deepEqual(current, payload)) return;
|
|
94
|
+
next = payload;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (!Object.is(storeState[key], next)) {
|
|
98
|
+
storeState = { ...storeState, [key]: next };
|
|
99
|
+
emitSlice(key);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
function useSRASM(slice, selector, options) {
|
|
103
|
+
const selected = (0, import_with_selector.useSyncExternalStoreWithSelector)(
|
|
104
|
+
(listener) => subscribeSlice(slice, listener),
|
|
105
|
+
() => storeState[slice],
|
|
106
|
+
() => initialSlices[slice],
|
|
107
|
+
selector ?? ((s) => s),
|
|
108
|
+
options?.isEqual ?? Object.is
|
|
109
|
+
);
|
|
110
|
+
const setState = (0, import_react.useCallback)(
|
|
111
|
+
(payload) => updateSlice(slice, payload, !!options?.useDeepEqualCheck),
|
|
112
|
+
[slice, options?.useDeepEqualCheck]
|
|
113
|
+
);
|
|
114
|
+
return { state: selected, setState };
|
|
115
|
+
}
|
|
116
|
+
function useSRASMAsync(slice, fetcher, tags = []) {
|
|
117
|
+
const { state, setState } = useSRASM(slice);
|
|
118
|
+
const [loading, setLoading] = import_react.default.useState(false);
|
|
119
|
+
const [error, setError] = import_react.default.useState(null);
|
|
120
|
+
const fetchData = (0, import_react.useCallback)(async () => {
|
|
121
|
+
setLoading(true);
|
|
122
|
+
setError(null);
|
|
123
|
+
try {
|
|
124
|
+
const data = await fetcher();
|
|
125
|
+
setState(data);
|
|
126
|
+
} catch (err) {
|
|
127
|
+
setError(err);
|
|
128
|
+
} finally {
|
|
129
|
+
setLoading(false);
|
|
130
|
+
}
|
|
131
|
+
}, [slice, fetcher, setState]);
|
|
132
|
+
import_react.default.useEffect(() => {
|
|
133
|
+
fetchData();
|
|
134
|
+
}, [JSON.stringify(tags)]);
|
|
135
|
+
return {
|
|
136
|
+
data: state,
|
|
137
|
+
loading,
|
|
138
|
+
error,
|
|
139
|
+
refetch: fetchData
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const SRASMProvider = ({
|
|
143
|
+
children
|
|
144
|
+
}) => {
|
|
145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
146
|
+
};
|
|
147
|
+
return { SRASMProvider, useSRASM, useSRASMAsync };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/ml/globalLogs.ts
|
|
151
|
+
var logClick = (event) => {
|
|
152
|
+
const key = "click_events";
|
|
153
|
+
const existing = JSON.parse(localStorage.getItem(key) || "[]");
|
|
154
|
+
existing.push(event);
|
|
155
|
+
localStorage.setItem(key, JSON.stringify(existing));
|
|
156
|
+
};
|
|
157
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
158
|
+
0 && (module.exports = {
|
|
159
|
+
createStateStore,
|
|
160
|
+
logClick
|
|
161
|
+
});
|
|
162
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/context/createStateStore.tsx","../src/utils/deepEqual.ts","../src/ml/globalLogs.ts"],"sourcesContent":["// Core state management\r\nexport { createStateStore } from \"./context\";\r\n\r\n// Utilities / ML helpers\r\nexport { logClick } from \"./ml\";\r\nexport type { ClickEvent } from \"./ml\";\r\n","import React, { useCallback } from \"react\";\r\nimport { deepEqual } from \"../utils\";\r\nimport { useSyncExternalStoreWithSelector } from \"use-sync-external-store/with-selector\";\r\n/**\r\n * Creates a state store with the given initial state slices.\r\n * The state store is used by the `useSRASM` hook to provide a strongly-typed\r\n * way of accessing and updating the state.\r\n *\r\n * @param {Slices} initialSlices The initial state slices to be used by the state store.\r\n * @return {{ SRASMProvider: React.FC<{ children: React.ReactNode; relevantCode?: { fileName: string; code: string }[] | undefined; additionalSlices?: any[] | undefined }>; useSRASM: <K extends SliceKey, Selected = Slices[K]>(slice: K, selector?: (s: Slices[K]) => Selected, options?: { useDeepEqualCheck?: boolean; isEqual?: (a: Selected, b: Selected) => boolean; }) => useSRASMReturn }}\r\n * The returned object contains the `SRASMProvider` context provider component and the `useSRASM` hook.\r\n * The `SRASMProvider` component should be used to wrap your application, providing the necessary state and error handling to SRASM components.\r\n * The `useSRASM` hook can be used by your React components to access and update the state.\r\n */\r\nexport function createStateStore<Slices extends Record<string, any>>(\r\n initialSlices: Slices,\r\n) {\r\n type SliceKey = keyof Slices;\r\n\r\n let storeState: Slices = { ...initialSlices };\r\n\r\n const sliceListeners = new Map<SliceKey, Set<() => void>>();\r\n // const activeRequests = new Map<SliceKey, Promise<any>>();\r\n\r\n /**\r\n * Returns a set of listeners for the given slice key.\r\n * If no listeners are registered for the key, a new set is created and stored.\r\n * @param {SliceKey} k\r\n * @returns {Set<() => void>}\r\n */\r\n const getSliceListeners = (k: SliceKey) => {\r\n let set = sliceListeners.get(k);\r\n if (!set) {\r\n set = new Set();\r\n sliceListeners.set(k, set);\r\n }\r\n return set;\r\n };\r\n\r\n /**\r\n * Subscribes to the slice with the given key, adding the given\r\n * listener to the set of listeners for that slice.\r\n *\r\n * Returns a function that can be used to unsubscribe the given\r\n * listener from the slice.\r\n *\r\n * @param {SliceKey} key The key of the slice to subscribe to.\r\n * @param {() => void} listener The listener to add to the slice.\r\n * @returns {() => void} A function to unsubscribe the listener from the slice.\r\n */\r\n const subscribeSlice = (key: SliceKey, listener: () => void) => {\r\n const set = getSliceListeners(key);\r\n set.add(listener);\r\n return () => set.delete(listener);\r\n };\r\n\r\n /**\r\n * Emits the slice with the given key, calling all listeners\r\n * that are currently subscribed to that slice.\r\n *\r\n * This is used internally by the `useSRASM` hook to notify\r\n * components when the slice they are subscribed to changes.\r\n *\r\n * @param {SliceKey} key The key of the slice to emit.\r\n */\r\n const emitSlice = (key: SliceKey) => {\r\n getSliceListeners(key).forEach((l) => l());\r\n };\r\n\r\n /**\r\n * Updates the slice with the given key, using the given payload to\r\n * determine the new value of the slice. If the payload is a function,\r\n * it will be called with the current value of the slice as its argument.\r\n *\r\n * If the payload is not a function, it will be used as the new value\r\n * of the slice. If the current and new values are equal (using a\r\n * deep equality check if useDeepEqualCheck is true), the slice will\r\n * not be updated.\r\n *\r\n * @param {SliceKey} key The key of the slice to update.\r\n * @param {any} payload The payload to use to update the slice.\r\n * @param {boolean} useDeepEqualCheck Whether to use a deep equality\r\n * check when comparing the current and new values of the slice.\r\n */\r\n const updateSlice = (\r\n key: SliceKey,\r\n payload: any,\r\n useDeepEqualCheck: boolean,\r\n ) => {\r\n const current = storeState[key];\r\n let next = current;\r\n\r\n if (typeof payload === \"function\") {\r\n next = payload(current);\r\n if (Object.is(current, next)) return;\r\n if (useDeepEqualCheck && deepEqual(current, next)) return;\r\n } else {\r\n if (\r\n typeof current === \"object\" &&\r\n current !== null &&\r\n typeof payload === \"object\" &&\r\n payload !== null\r\n ) {\r\n next = { ...(current as any), ...(payload as any) };\r\n if (useDeepEqualCheck && deepEqual(current, next)) return;\r\n } else {\r\n if (Object.is(current, payload)) return;\r\n if (useDeepEqualCheck && deepEqual(current, payload)) return;\r\n next = payload;\r\n }\r\n }\r\n\r\n if (!Object.is(storeState[key], next)) {\r\n storeState = { ...storeState, [key]: next };\r\n emitSlice(key);\r\n }\r\n };\r\n\r\n /**\r\n * Hook to use a slice of the global state.\r\n * @param {SliceKey} slice The key of the slice to use.\r\n * @param {((s: Slices[K]) => Selected) | undefined} selector\r\n * A function to select the desired value from the slice.\r\n * @param {useSRASMOptions} options Options for the hook.\r\n * @returns {useSRASMReturn} An object with the selected state and a\r\n * function to update the state.\r\n *\r\n * The `useSRASM` hook allows you to use a slice of the global state\r\n * in your React components. It takes a slice key as its first argument and\r\n * an optional selector function as its second argument. The selector function\r\n * is called with the slice state as its argument and should return the desired value\r\n * from the slice state.\r\n *\r\n * The hook returns an object with two properties: `state` and `setState`. The\r\n * `state` property contains the selected value from the slice state, and the\r\n * `setState` property is a function that can be used to update the slice state.\r\n *\r\n * The `options` object can be used to customize the behavior of the hook. It\r\n * accepts two properties: `useDeepEqualCheck` and `isEqual`. The\r\n * `useDeepEqualCheck` property is a boolean that indicates whether to use a deep\r\n * equality check when comparing the current and new values of the slice state.\r\n * The `isEqual` property is a function that is used to compare the current and\r\n * new values of the slice state. If not provided, the hook will use the `Object.is`\r\n * function to compare the values.\r\n */\r\n function useSRASM<K extends SliceKey, Selected = Slices[K]>(\r\n slice: K,\r\n selector?: (s: Slices[K]) => Selected,\r\n options?: {\r\n useDeepEqualCheck?: boolean;\r\n isEqual?: (a: Selected, b: Selected) => boolean;\r\n },\r\n ) {\r\n const selected = useSyncExternalStoreWithSelector(\r\n (listener) => subscribeSlice(slice, listener),\r\n () => storeState[slice],\r\n () => initialSlices[slice],\r\n selector ?? ((s: Selected) => s as Selected),\r\n options?.isEqual ?? Object.is,\r\n );\r\n\r\n type SliceUpdater<S> = Partial<S> | ((prev: S) => Partial<S>);\r\n\r\n const setState = useCallback(\r\n (payload: SliceUpdater<Slices[K]>) =>\r\n updateSlice(slice, payload, !!options?.useDeepEqualCheck),\r\n [slice, options?.useDeepEqualCheck],\r\n );\r\n\r\n return { state: selected, setState };\r\n }\r\n\r\n /**\r\n * Hook to asynchronously fetch and manage a slice state.\r\n * @param {SliceKey} slice The slice key.\r\n * @param {() => Promise<Slices[K]>} fetcher The async function to fetch data.\r\n * @param {any[]} tags Array of dependencies. specific tags that trigger refetch.\r\n * @returns {{ data: Slices[K]; loading: boolean; error: any; refetch: () => void }}\r\n */\r\n function useSRASMAsync<K extends SliceKey>(\r\n slice: K,\r\n fetcher: () => Promise<Slices[K]>,\r\n tags: any[] = [],\r\n ) {\r\n const { state, setState } = useSRASM(slice);\r\n const [loading, setLoading] = React.useState(false);\r\n const [error, setError] = React.useState<any>(null);\r\n\r\n const fetchData = useCallback(async () => {\r\n // Deduping: if a request is already active for this slice, don't start another?\r\n // For now, let's allow it but simple tracking.\r\n setLoading(true);\r\n setError(null);\r\n\r\n try {\r\n const data = await fetcher();\r\n setState(data);\r\n } catch (err) {\r\n setError(err);\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [slice, fetcher, setState]); // tags are handled in useEffect\r\n\r\n React.useEffect(() => {\r\n // Simple \"auto-fetch\" on mount or tag change\r\n // In a real lib we would check if data exists/is fresh.\r\n fetchData();\r\n }, [JSON.stringify(tags)]); // deeply compare tags simple approach\r\n\r\n return {\r\n data: state,\r\n loading,\r\n error,\r\n refetch: fetchData,\r\n };\r\n }\r\n\r\n /**\r\n * @note Can be need at the future\r\n * A context provider that wraps your application and provides\r\n * the necessary state and error handling to SRASM components.\r\n *\r\n * @param {React.ReactNode} children The components to be rendered within\r\n * the provider.\r\n * @param {({ fileName: string; code: string }[] | undefined} relevantCode\r\n * An optional array of objects containing the file name and code of the\r\n * relevant code snippets to be used for AI error debugging.\r\n * @param {any[] | undefined} additionalSlices An optional array of\r\n * additional slices to be passed to the AI error debugging system.\r\n */\r\n const SRASMProvider = ({\r\n children,\r\n }: {\r\n children: React.ReactNode;\r\n }) => {\r\n return <>{children}</>;\r\n };\r\n\r\n return { SRASMProvider, useSRASM, useSRASMAsync };\r\n}\r\n","export function deepEqual(\r\n obj1: Record<string, any>,\r\n obj2: Record<string, any>\r\n) {\r\n if (obj1 === obj2) return true; // Handles primitive values and same object references\r\n\r\n // If one is null or not object, compare with Object.is\r\n if (\r\n typeof obj1 !== \"object\" ||\r\n typeof obj2 !== \"object\" ||\r\n obj1 === null ||\r\n obj2 === null\r\n ) {\r\n return Object.is(obj1, obj2);\r\n }\r\n\r\n const keys1 = Object.keys(obj1);\r\n const keys2 = Object.keys(obj2);\r\n\r\n if (keys1.length !== keys2.length) return false; // Different number of properties\r\n\r\n for (const key of keys1) {\r\n if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {\r\n return false; // Key missing or values not deeply equal\r\n }\r\n }\r\n return true;\r\n}\r\n","export type ClickEvent = {\r\n itemId: string;\r\n categoryId: string;\r\n ts: number;\r\n};\r\n\r\nexport const logClick = (event: ClickEvent) => {\r\n const key = \"click_events\";\r\n const existing = JSON.parse(localStorage.getItem(key) || \"[]\");\r\n existing.push(event);\r\n localStorage.setItem(key, JSON.stringify(existing));\r\n};\r\n\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAmC;;;ACA5B,SAAS,UACd,MACA,MACA;AACA,MAAI,SAAS,KAAM,QAAO;AAG1B,MACE,OAAO,SAAS,YAChB,OAAO,SAAS,YAChB,SAAS,QACT,SAAS,MACT;AACA,WAAO,OAAO,GAAG,MAAM,IAAI;AAAA,EAC7B;AAEA,QAAM,QAAQ,OAAO,KAAK,IAAI;AAC9B,QAAM,QAAQ,OAAO,KAAK,IAAI;AAE9B,MAAI,MAAM,WAAW,MAAM,OAAQ,QAAO;AAE1C,aAAW,OAAO,OAAO;AACvB,QAAI,CAAC,MAAM,SAAS,GAAG,KAAK,CAAC,UAAU,KAAK,GAAG,GAAG,KAAK,GAAG,CAAC,GAAG;AAC5D,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;;;ADzBA,2BAAiD;AA0OtC;AA9NJ,SAAS,iBACd,eACA;AAGA,MAAI,aAAqB,EAAE,GAAG,cAAc;AAE5C,QAAM,iBAAiB,oBAAI,IAA+B;AAS1D,QAAM,oBAAoB,CAAC,MAAgB;AACzC,QAAI,MAAM,eAAe,IAAI,CAAC;AAC9B,QAAI,CAAC,KAAK;AACR,YAAM,oBAAI,IAAI;AACd,qBAAe,IAAI,GAAG,GAAG;AAAA,IAC3B;AACA,WAAO;AAAA,EACT;AAaA,QAAM,iBAAiB,CAAC,KAAe,aAAyB;AAC9D,UAAM,MAAM,kBAAkB,GAAG;AACjC,QAAI,IAAI,QAAQ;AAChB,WAAO,MAAM,IAAI,OAAO,QAAQ;AAAA,EAClC;AAWA,QAAM,YAAY,CAAC,QAAkB;AACnC,sBAAkB,GAAG,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;AAAA,EAC3C;AAiBA,QAAM,cAAc,CAClB,KACA,SACA,sBACG;AACH,UAAM,UAAU,WAAW,GAAG;AAC9B,QAAI,OAAO;AAEX,QAAI,OAAO,YAAY,YAAY;AACjC,aAAO,QAAQ,OAAO;AACtB,UAAI,OAAO,GAAG,SAAS,IAAI,EAAG;AAC9B,UAAI,qBAAqB,UAAU,SAAS,IAAI,EAAG;AAAA,IACrD,OAAO;AACL,UACE,OAAO,YAAY,YACnB,YAAY,QACZ,OAAO,YAAY,YACnB,YAAY,MACZ;AACA,eAAO,EAAE,GAAI,SAAiB,GAAI,QAAgB;AAClD,YAAI,qBAAqB,UAAU,SAAS,IAAI,EAAG;AAAA,MACrD,OAAO;AACL,YAAI,OAAO,GAAG,SAAS,OAAO,EAAG;AACjC,YAAI,qBAAqB,UAAU,SAAS,OAAO,EAAG;AACtD,eAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI,CAAC,OAAO,GAAG,WAAW,GAAG,GAAG,IAAI,GAAG;AACrC,mBAAa,EAAE,GAAG,YAAY,CAAC,GAAG,GAAG,KAAK;AAC1C,gBAAU,GAAG;AAAA,IACf;AAAA,EACF;AA6BA,WAAS,SACP,OACA,UACA,SAIA;AACA,UAAM,eAAW;AAAA,MACf,CAAC,aAAa,eAAe,OAAO,QAAQ;AAAA,MAC5C,MAAM,WAAW,KAAK;AAAA,MACtB,MAAM,cAAc,KAAK;AAAA,MACzB,aAAa,CAAC,MAAgB;AAAA,MAC9B,SAAS,WAAW,OAAO;AAAA,IAC7B;AAIA,UAAM,eAAW;AAAA,MACf,CAAC,YACC,YAAY,OAAO,SAAS,CAAC,CAAC,SAAS,iBAAiB;AAAA,MAC1D,CAAC,OAAO,SAAS,iBAAiB;AAAA,IACpC;AAEA,WAAO,EAAE,OAAO,UAAU,SAAS;AAAA,EACrC;AASA,WAAS,cACP,OACA,SACA,OAAc,CAAC,GACf;AACA,UAAM,EAAE,OAAO,SAAS,IAAI,SAAS,KAAK;AAC1C,UAAM,CAAC,SAAS,UAAU,IAAI,aAAAA,QAAM,SAAS,KAAK;AAClD,UAAM,CAAC,OAAO,QAAQ,IAAI,aAAAA,QAAM,SAAc,IAAI;AAElD,UAAM,gBAAY,0BAAY,YAAY;AAGxC,iBAAW,IAAI;AACf,eAAS,IAAI;AAEb,UAAI;AACF,cAAM,OAAO,MAAM,QAAQ;AAC3B,iBAAS,IAAI;AAAA,MACf,SAAS,KAAK;AACZ,iBAAS,GAAG;AAAA,MACd,UAAE;AACA,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF,GAAG,CAAC,OAAO,SAAS,QAAQ,CAAC;AAE7B,iBAAAA,QAAM,UAAU,MAAM;AAGpB,gBAAU;AAAA,IACZ,GAAG,CAAC,KAAK,UAAU,IAAI,CAAC,CAAC;AAEzB,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAeA,QAAM,gBAAgB,CAAC;AAAA,IACrB;AAAA,EACF,MAEM;AACJ,WAAO,2EAAG,UAAS;AAAA,EACrB;AAEA,SAAO,EAAE,eAAe,UAAU,cAAc;AAClD;;;AE1OO,IAAM,WAAW,CAAC,UAAsB;AAC7C,QAAM,MAAM;AACZ,QAAM,WAAW,KAAK,MAAM,aAAa,QAAQ,GAAG,KAAK,IAAI;AAC7D,WAAS,KAAK,KAAK;AACnB,eAAa,QAAQ,KAAK,KAAK,UAAU,QAAQ,CAAC;AACpD;","names":["React"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a state store with the given initial state slices.
|
|
6
|
+
* The state store is used by the `useSRASM` hook to provide a strongly-typed
|
|
7
|
+
* way of accessing and updating the state.
|
|
8
|
+
*
|
|
9
|
+
* @param {Slices} initialSlices The initial state slices to be used by the state store.
|
|
10
|
+
* @return {{ SRASMProvider: React.FC<{ children: React.ReactNode; relevantCode?: { fileName: string; code: string }[] | undefined; additionalSlices?: any[] | undefined }>; useSRASM: <K extends SliceKey, Selected = Slices[K]>(slice: K, selector?: (s: Slices[K]) => Selected, options?: { useDeepEqualCheck?: boolean; isEqual?: (a: Selected, b: Selected) => boolean; }) => useSRASMReturn }}
|
|
11
|
+
* The returned object contains the `SRASMProvider` context provider component and the `useSRASM` hook.
|
|
12
|
+
* The `SRASMProvider` component should be used to wrap your application, providing the necessary state and error handling to SRASM components.
|
|
13
|
+
* The `useSRASM` hook can be used by your React components to access and update the state.
|
|
14
|
+
*/
|
|
15
|
+
declare function createStateStore<Slices extends Record<string, any>>(initialSlices: Slices): {
|
|
16
|
+
SRASMProvider: ({ children, }: {
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
19
|
+
useSRASM: <K extends keyof Slices, Selected = Slices[K]>(slice: K, selector?: (s: Slices[K]) => Selected, options?: {
|
|
20
|
+
useDeepEqualCheck?: boolean;
|
|
21
|
+
isEqual?: (a: Selected, b: Selected) => boolean;
|
|
22
|
+
}) => {
|
|
23
|
+
state: Selected;
|
|
24
|
+
setState: (payload: Partial<Slices[K]> | ((prev: Slices[K]) => Partial<Slices[K]>)) => void;
|
|
25
|
+
};
|
|
26
|
+
useSRASMAsync: <K extends keyof Slices>(slice: K, fetcher: () => Promise<Slices[K]>, tags?: any[]) => {
|
|
27
|
+
data: Slices[K];
|
|
28
|
+
loading: boolean;
|
|
29
|
+
error: any;
|
|
30
|
+
refetch: () => Promise<void>;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
type ClickEvent = {
|
|
35
|
+
itemId: string;
|
|
36
|
+
categoryId: string;
|
|
37
|
+
ts: number;
|
|
38
|
+
};
|
|
39
|
+
declare const logClick: (event: ClickEvent) => void;
|
|
40
|
+
|
|
41
|
+
export { type ClickEvent, createStateStore, logClick };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a state store with the given initial state slices.
|
|
6
|
+
* The state store is used by the `useSRASM` hook to provide a strongly-typed
|
|
7
|
+
* way of accessing and updating the state.
|
|
8
|
+
*
|
|
9
|
+
* @param {Slices} initialSlices The initial state slices to be used by the state store.
|
|
10
|
+
* @return {{ SRASMProvider: React.FC<{ children: React.ReactNode; relevantCode?: { fileName: string; code: string }[] | undefined; additionalSlices?: any[] | undefined }>; useSRASM: <K extends SliceKey, Selected = Slices[K]>(slice: K, selector?: (s: Slices[K]) => Selected, options?: { useDeepEqualCheck?: boolean; isEqual?: (a: Selected, b: Selected) => boolean; }) => useSRASMReturn }}
|
|
11
|
+
* The returned object contains the `SRASMProvider` context provider component and the `useSRASM` hook.
|
|
12
|
+
* The `SRASMProvider` component should be used to wrap your application, providing the necessary state and error handling to SRASM components.
|
|
13
|
+
* The `useSRASM` hook can be used by your React components to access and update the state.
|
|
14
|
+
*/
|
|
15
|
+
declare function createStateStore<Slices extends Record<string, any>>(initialSlices: Slices): {
|
|
16
|
+
SRASMProvider: ({ children, }: {
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
19
|
+
useSRASM: <K extends keyof Slices, Selected = Slices[K]>(slice: K, selector?: (s: Slices[K]) => Selected, options?: {
|
|
20
|
+
useDeepEqualCheck?: boolean;
|
|
21
|
+
isEqual?: (a: Selected, b: Selected) => boolean;
|
|
22
|
+
}) => {
|
|
23
|
+
state: Selected;
|
|
24
|
+
setState: (payload: Partial<Slices[K]> | ((prev: Slices[K]) => Partial<Slices[K]>)) => void;
|
|
25
|
+
};
|
|
26
|
+
useSRASMAsync: <K extends keyof Slices>(slice: K, fetcher: () => Promise<Slices[K]>, tags?: any[]) => {
|
|
27
|
+
data: Slices[K];
|
|
28
|
+
loading: boolean;
|
|
29
|
+
error: any;
|
|
30
|
+
refetch: () => Promise<void>;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
type ClickEvent = {
|
|
35
|
+
itemId: string;
|
|
36
|
+
categoryId: string;
|
|
37
|
+
ts: number;
|
|
38
|
+
};
|
|
39
|
+
declare const logClick: (event: ClickEvent) => void;
|
|
40
|
+
|
|
41
|
+
export { type ClickEvent, createStateStore, logClick };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// src/context/createStateStore.tsx
|
|
2
|
+
import React, { useCallback } from "react";
|
|
3
|
+
|
|
4
|
+
// src/utils/deepEqual.ts
|
|
5
|
+
function deepEqual(obj1, obj2) {
|
|
6
|
+
if (obj1 === obj2) return true;
|
|
7
|
+
if (typeof obj1 !== "object" || typeof obj2 !== "object" || obj1 === null || obj2 === null) {
|
|
8
|
+
return Object.is(obj1, obj2);
|
|
9
|
+
}
|
|
10
|
+
const keys1 = Object.keys(obj1);
|
|
11
|
+
const keys2 = Object.keys(obj2);
|
|
12
|
+
if (keys1.length !== keys2.length) return false;
|
|
13
|
+
for (const key of keys1) {
|
|
14
|
+
if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// src/context/createStateStore.tsx
|
|
22
|
+
import { useSyncExternalStoreWithSelector } from "use-sync-external-store/with-selector";
|
|
23
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
24
|
+
function createStateStore(initialSlices) {
|
|
25
|
+
let storeState = { ...initialSlices };
|
|
26
|
+
const sliceListeners = /* @__PURE__ */ new Map();
|
|
27
|
+
const getSliceListeners = (k) => {
|
|
28
|
+
let set = sliceListeners.get(k);
|
|
29
|
+
if (!set) {
|
|
30
|
+
set = /* @__PURE__ */ new Set();
|
|
31
|
+
sliceListeners.set(k, set);
|
|
32
|
+
}
|
|
33
|
+
return set;
|
|
34
|
+
};
|
|
35
|
+
const subscribeSlice = (key, listener) => {
|
|
36
|
+
const set = getSliceListeners(key);
|
|
37
|
+
set.add(listener);
|
|
38
|
+
return () => set.delete(listener);
|
|
39
|
+
};
|
|
40
|
+
const emitSlice = (key) => {
|
|
41
|
+
getSliceListeners(key).forEach((l) => l());
|
|
42
|
+
};
|
|
43
|
+
const updateSlice = (key, payload, useDeepEqualCheck) => {
|
|
44
|
+
const current = storeState[key];
|
|
45
|
+
let next = current;
|
|
46
|
+
if (typeof payload === "function") {
|
|
47
|
+
next = payload(current);
|
|
48
|
+
if (Object.is(current, next)) return;
|
|
49
|
+
if (useDeepEqualCheck && deepEqual(current, next)) return;
|
|
50
|
+
} else {
|
|
51
|
+
if (typeof current === "object" && current !== null && typeof payload === "object" && payload !== null) {
|
|
52
|
+
next = { ...current, ...payload };
|
|
53
|
+
if (useDeepEqualCheck && deepEqual(current, next)) return;
|
|
54
|
+
} else {
|
|
55
|
+
if (Object.is(current, payload)) return;
|
|
56
|
+
if (useDeepEqualCheck && deepEqual(current, payload)) return;
|
|
57
|
+
next = payload;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!Object.is(storeState[key], next)) {
|
|
61
|
+
storeState = { ...storeState, [key]: next };
|
|
62
|
+
emitSlice(key);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
function useSRASM(slice, selector, options) {
|
|
66
|
+
const selected = useSyncExternalStoreWithSelector(
|
|
67
|
+
(listener) => subscribeSlice(slice, listener),
|
|
68
|
+
() => storeState[slice],
|
|
69
|
+
() => initialSlices[slice],
|
|
70
|
+
selector ?? ((s) => s),
|
|
71
|
+
options?.isEqual ?? Object.is
|
|
72
|
+
);
|
|
73
|
+
const setState = useCallback(
|
|
74
|
+
(payload) => updateSlice(slice, payload, !!options?.useDeepEqualCheck),
|
|
75
|
+
[slice, options?.useDeepEqualCheck]
|
|
76
|
+
);
|
|
77
|
+
return { state: selected, setState };
|
|
78
|
+
}
|
|
79
|
+
function useSRASMAsync(slice, fetcher, tags = []) {
|
|
80
|
+
const { state, setState } = useSRASM(slice);
|
|
81
|
+
const [loading, setLoading] = React.useState(false);
|
|
82
|
+
const [error, setError] = React.useState(null);
|
|
83
|
+
const fetchData = useCallback(async () => {
|
|
84
|
+
setLoading(true);
|
|
85
|
+
setError(null);
|
|
86
|
+
try {
|
|
87
|
+
const data = await fetcher();
|
|
88
|
+
setState(data);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
setError(err);
|
|
91
|
+
} finally {
|
|
92
|
+
setLoading(false);
|
|
93
|
+
}
|
|
94
|
+
}, [slice, fetcher, setState]);
|
|
95
|
+
React.useEffect(() => {
|
|
96
|
+
fetchData();
|
|
97
|
+
}, [JSON.stringify(tags)]);
|
|
98
|
+
return {
|
|
99
|
+
data: state,
|
|
100
|
+
loading,
|
|
101
|
+
error,
|
|
102
|
+
refetch: fetchData
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const SRASMProvider = ({
|
|
106
|
+
children
|
|
107
|
+
}) => {
|
|
108
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
109
|
+
};
|
|
110
|
+
return { SRASMProvider, useSRASM, useSRASMAsync };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/ml/globalLogs.ts
|
|
114
|
+
var logClick = (event) => {
|
|
115
|
+
const key = "click_events";
|
|
116
|
+
const existing = JSON.parse(localStorage.getItem(key) || "[]");
|
|
117
|
+
existing.push(event);
|
|
118
|
+
localStorage.setItem(key, JSON.stringify(existing));
|
|
119
|
+
};
|
|
120
|
+
export {
|
|
121
|
+
createStateStore,
|
|
122
|
+
logClick
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context/createStateStore.tsx","../src/utils/deepEqual.ts","../src/ml/globalLogs.ts"],"sourcesContent":["import React, { useCallback } from \"react\";\r\nimport { deepEqual } from \"../utils\";\r\nimport { useSyncExternalStoreWithSelector } from \"use-sync-external-store/with-selector\";\r\n/**\r\n * Creates a state store with the given initial state slices.\r\n * The state store is used by the `useSRASM` hook to provide a strongly-typed\r\n * way of accessing and updating the state.\r\n *\r\n * @param {Slices} initialSlices The initial state slices to be used by the state store.\r\n * @return {{ SRASMProvider: React.FC<{ children: React.ReactNode; relevantCode?: { fileName: string; code: string }[] | undefined; additionalSlices?: any[] | undefined }>; useSRASM: <K extends SliceKey, Selected = Slices[K]>(slice: K, selector?: (s: Slices[K]) => Selected, options?: { useDeepEqualCheck?: boolean; isEqual?: (a: Selected, b: Selected) => boolean; }) => useSRASMReturn }}\r\n * The returned object contains the `SRASMProvider` context provider component and the `useSRASM` hook.\r\n * The `SRASMProvider` component should be used to wrap your application, providing the necessary state and error handling to SRASM components.\r\n * The `useSRASM` hook can be used by your React components to access and update the state.\r\n */\r\nexport function createStateStore<Slices extends Record<string, any>>(\r\n initialSlices: Slices,\r\n) {\r\n type SliceKey = keyof Slices;\r\n\r\n let storeState: Slices = { ...initialSlices };\r\n\r\n const sliceListeners = new Map<SliceKey, Set<() => void>>();\r\n // const activeRequests = new Map<SliceKey, Promise<any>>();\r\n\r\n /**\r\n * Returns a set of listeners for the given slice key.\r\n * If no listeners are registered for the key, a new set is created and stored.\r\n * @param {SliceKey} k\r\n * @returns {Set<() => void>}\r\n */\r\n const getSliceListeners = (k: SliceKey) => {\r\n let set = sliceListeners.get(k);\r\n if (!set) {\r\n set = new Set();\r\n sliceListeners.set(k, set);\r\n }\r\n return set;\r\n };\r\n\r\n /**\r\n * Subscribes to the slice with the given key, adding the given\r\n * listener to the set of listeners for that slice.\r\n *\r\n * Returns a function that can be used to unsubscribe the given\r\n * listener from the slice.\r\n *\r\n * @param {SliceKey} key The key of the slice to subscribe to.\r\n * @param {() => void} listener The listener to add to the slice.\r\n * @returns {() => void} A function to unsubscribe the listener from the slice.\r\n */\r\n const subscribeSlice = (key: SliceKey, listener: () => void) => {\r\n const set = getSliceListeners(key);\r\n set.add(listener);\r\n return () => set.delete(listener);\r\n };\r\n\r\n /**\r\n * Emits the slice with the given key, calling all listeners\r\n * that are currently subscribed to that slice.\r\n *\r\n * This is used internally by the `useSRASM` hook to notify\r\n * components when the slice they are subscribed to changes.\r\n *\r\n * @param {SliceKey} key The key of the slice to emit.\r\n */\r\n const emitSlice = (key: SliceKey) => {\r\n getSliceListeners(key).forEach((l) => l());\r\n };\r\n\r\n /**\r\n * Updates the slice with the given key, using the given payload to\r\n * determine the new value of the slice. If the payload is a function,\r\n * it will be called with the current value of the slice as its argument.\r\n *\r\n * If the payload is not a function, it will be used as the new value\r\n * of the slice. If the current and new values are equal (using a\r\n * deep equality check if useDeepEqualCheck is true), the slice will\r\n * not be updated.\r\n *\r\n * @param {SliceKey} key The key of the slice to update.\r\n * @param {any} payload The payload to use to update the slice.\r\n * @param {boolean} useDeepEqualCheck Whether to use a deep equality\r\n * check when comparing the current and new values of the slice.\r\n */\r\n const updateSlice = (\r\n key: SliceKey,\r\n payload: any,\r\n useDeepEqualCheck: boolean,\r\n ) => {\r\n const current = storeState[key];\r\n let next = current;\r\n\r\n if (typeof payload === \"function\") {\r\n next = payload(current);\r\n if (Object.is(current, next)) return;\r\n if (useDeepEqualCheck && deepEqual(current, next)) return;\r\n } else {\r\n if (\r\n typeof current === \"object\" &&\r\n current !== null &&\r\n typeof payload === \"object\" &&\r\n payload !== null\r\n ) {\r\n next = { ...(current as any), ...(payload as any) };\r\n if (useDeepEqualCheck && deepEqual(current, next)) return;\r\n } else {\r\n if (Object.is(current, payload)) return;\r\n if (useDeepEqualCheck && deepEqual(current, payload)) return;\r\n next = payload;\r\n }\r\n }\r\n\r\n if (!Object.is(storeState[key], next)) {\r\n storeState = { ...storeState, [key]: next };\r\n emitSlice(key);\r\n }\r\n };\r\n\r\n /**\r\n * Hook to use a slice of the global state.\r\n * @param {SliceKey} slice The key of the slice to use.\r\n * @param {((s: Slices[K]) => Selected) | undefined} selector\r\n * A function to select the desired value from the slice.\r\n * @param {useSRASMOptions} options Options for the hook.\r\n * @returns {useSRASMReturn} An object with the selected state and a\r\n * function to update the state.\r\n *\r\n * The `useSRASM` hook allows you to use a slice of the global state\r\n * in your React components. It takes a slice key as its first argument and\r\n * an optional selector function as its second argument. The selector function\r\n * is called with the slice state as its argument and should return the desired value\r\n * from the slice state.\r\n *\r\n * The hook returns an object with two properties: `state` and `setState`. The\r\n * `state` property contains the selected value from the slice state, and the\r\n * `setState` property is a function that can be used to update the slice state.\r\n *\r\n * The `options` object can be used to customize the behavior of the hook. It\r\n * accepts two properties: `useDeepEqualCheck` and `isEqual`. The\r\n * `useDeepEqualCheck` property is a boolean that indicates whether to use a deep\r\n * equality check when comparing the current and new values of the slice state.\r\n * The `isEqual` property is a function that is used to compare the current and\r\n * new values of the slice state. If not provided, the hook will use the `Object.is`\r\n * function to compare the values.\r\n */\r\n function useSRASM<K extends SliceKey, Selected = Slices[K]>(\r\n slice: K,\r\n selector?: (s: Slices[K]) => Selected,\r\n options?: {\r\n useDeepEqualCheck?: boolean;\r\n isEqual?: (a: Selected, b: Selected) => boolean;\r\n },\r\n ) {\r\n const selected = useSyncExternalStoreWithSelector(\r\n (listener) => subscribeSlice(slice, listener),\r\n () => storeState[slice],\r\n () => initialSlices[slice],\r\n selector ?? ((s: Selected) => s as Selected),\r\n options?.isEqual ?? Object.is,\r\n );\r\n\r\n type SliceUpdater<S> = Partial<S> | ((prev: S) => Partial<S>);\r\n\r\n const setState = useCallback(\r\n (payload: SliceUpdater<Slices[K]>) =>\r\n updateSlice(slice, payload, !!options?.useDeepEqualCheck),\r\n [slice, options?.useDeepEqualCheck],\r\n );\r\n\r\n return { state: selected, setState };\r\n }\r\n\r\n /**\r\n * Hook to asynchronously fetch and manage a slice state.\r\n * @param {SliceKey} slice The slice key.\r\n * @param {() => Promise<Slices[K]>} fetcher The async function to fetch data.\r\n * @param {any[]} tags Array of dependencies. specific tags that trigger refetch.\r\n * @returns {{ data: Slices[K]; loading: boolean; error: any; refetch: () => void }}\r\n */\r\n function useSRASMAsync<K extends SliceKey>(\r\n slice: K,\r\n fetcher: () => Promise<Slices[K]>,\r\n tags: any[] = [],\r\n ) {\r\n const { state, setState } = useSRASM(slice);\r\n const [loading, setLoading] = React.useState(false);\r\n const [error, setError] = React.useState<any>(null);\r\n\r\n const fetchData = useCallback(async () => {\r\n // Deduping: if a request is already active for this slice, don't start another?\r\n // For now, let's allow it but simple tracking.\r\n setLoading(true);\r\n setError(null);\r\n\r\n try {\r\n const data = await fetcher();\r\n setState(data);\r\n } catch (err) {\r\n setError(err);\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [slice, fetcher, setState]); // tags are handled in useEffect\r\n\r\n React.useEffect(() => {\r\n // Simple \"auto-fetch\" on mount or tag change\r\n // In a real lib we would check if data exists/is fresh.\r\n fetchData();\r\n }, [JSON.stringify(tags)]); // deeply compare tags simple approach\r\n\r\n return {\r\n data: state,\r\n loading,\r\n error,\r\n refetch: fetchData,\r\n };\r\n }\r\n\r\n /**\r\n * @note Can be need at the future\r\n * A context provider that wraps your application and provides\r\n * the necessary state and error handling to SRASM components.\r\n *\r\n * @param {React.ReactNode} children The components to be rendered within\r\n * the provider.\r\n * @param {({ fileName: string; code: string }[] | undefined} relevantCode\r\n * An optional array of objects containing the file name and code of the\r\n * relevant code snippets to be used for AI error debugging.\r\n * @param {any[] | undefined} additionalSlices An optional array of\r\n * additional slices to be passed to the AI error debugging system.\r\n */\r\n const SRASMProvider = ({\r\n children,\r\n }: {\r\n children: React.ReactNode;\r\n }) => {\r\n return <>{children}</>;\r\n };\r\n\r\n return { SRASMProvider, useSRASM, useSRASMAsync };\r\n}\r\n","export function deepEqual(\r\n obj1: Record<string, any>,\r\n obj2: Record<string, any>\r\n) {\r\n if (obj1 === obj2) return true; // Handles primitive values and same object references\r\n\r\n // If one is null or not object, compare with Object.is\r\n if (\r\n typeof obj1 !== \"object\" ||\r\n typeof obj2 !== \"object\" ||\r\n obj1 === null ||\r\n obj2 === null\r\n ) {\r\n return Object.is(obj1, obj2);\r\n }\r\n\r\n const keys1 = Object.keys(obj1);\r\n const keys2 = Object.keys(obj2);\r\n\r\n if (keys1.length !== keys2.length) return false; // Different number of properties\r\n\r\n for (const key of keys1) {\r\n if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {\r\n return false; // Key missing or values not deeply equal\r\n }\r\n }\r\n return true;\r\n}\r\n","export type ClickEvent = {\r\n itemId: string;\r\n categoryId: string;\r\n ts: number;\r\n};\r\n\r\nexport const logClick = (event: ClickEvent) => {\r\n const key = \"click_events\";\r\n const existing = JSON.parse(localStorage.getItem(key) || \"[]\");\r\n existing.push(event);\r\n localStorage.setItem(key, JSON.stringify(existing));\r\n};\r\n\r\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "srasm",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.2",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"files": [
|
|
6
|
+
"files": [
|
|
7
|
+
"dist",
|
|
8
|
+
"README.md",
|
|
9
|
+
"LICENSE"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"require": "./dist/index.cjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
7
18
|
"scripts": {
|
|
8
19
|
"dev": "vite",
|
|
9
|
-
"build": "
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"prepublishOnly": "npm run build",
|
|
10
22
|
"lint": "eslint .",
|
|
11
23
|
"preview": "vite preview",
|
|
12
|
-
"debug": " npx eslint . --debug"
|
|
13
|
-
"prepublishOnly": "npm run build"
|
|
24
|
+
"debug": " npx eslint . --debug"
|
|
14
25
|
},
|
|
15
26
|
"dependencies": {
|
|
16
27
|
"@langchain/core": "^1.1.0",
|
|
@@ -36,6 +47,10 @@
|
|
|
36
47
|
"tailwindcss": "^4.1.18",
|
|
37
48
|
"use-sync-external-store": "^1.6.0"
|
|
38
49
|
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"react": ">=18",
|
|
52
|
+
"react-dom": ">=18"
|
|
53
|
+
},
|
|
39
54
|
"devDependencies": {
|
|
40
55
|
"@tailwindcss/postcss": "^4.1.18",
|
|
41
56
|
"@testing-library/dom": "^10.4.1",
|
|
@@ -49,6 +64,7 @@
|
|
|
49
64
|
"baseline-browser-mapping": "^2.9.15",
|
|
50
65
|
"happy-dom": "^20.0.11",
|
|
51
66
|
"jsdom": "^27.0.1",
|
|
67
|
+
"tsup": "^8.5.1",
|
|
52
68
|
"typescript": "~5.9.3",
|
|
53
69
|
"vite": "^7.2.2",
|
|
54
70
|
"vitest": "^4.0.16"
|