@lls/offline 24.27.0-ff4d6c28 → 24.28.0-0854ed80

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/lib/index.js CHANGED
@@ -13,7 +13,7 @@ var tryCatch = (fn) => {
13
13
  var makeSyncWorker = (offlineWorker2, methodNames, dbg) => {
14
14
  const dic = {};
15
15
  const cbks = {};
16
- const fn = ({ data: { eventId, methodName, results, error, arg } = {} } = {}) => {
16
+ const fn = ({ source, data: { eventId, methodName, results, error, arg } = {} }) => {
17
17
  if (eventId && eventId in dic) {
18
18
  if (error) {
19
19
  dic[eventId].reject(error);
@@ -21,22 +21,38 @@ var makeSyncWorker = (offlineWorker2, methodNames, dbg) => {
21
21
  dic[eventId].resolve(results);
22
22
  }
23
23
  } else {
24
- if (methodName && !methodName.startsWith("async") && !(methodName in cbks)) {
24
+ if (methodName && !(methodName in cbks)) {
25
25
  console.error(`syncWorker: unknown methodName cbk ${dbg}`, eventId, methodName, error);
26
26
  }
27
27
  }
28
- methodName && cbks[methodName]?.(arg);
28
+ methodName && cbks[methodName]?.({ source, ...arg });
29
29
  };
30
30
  const makeFn = (methodName) => {
31
31
  return ({ ports, ...arg } = {}) => {
32
32
  return new Promise((resolve, reject) => {
33
33
  const eventId = `${methodName}:${Date.now()}-${Math.random().toFixed(5)}`;
34
- dic[eventId] = { resolve, reject };
35
- offlineWorker2.postMessage({ eventId, methodName, arg }, ports);
34
+ let resolved = false;
35
+ const timeout = setTimeout(() => {
36
+ console.warn("slow request for", methodName, arg, eventId);
37
+ }, 3e3);
38
+ const doResolve = (arg2) => {
39
+ if (!resolved) {
40
+ resolved = true;
41
+ clearTimeout(timeout);
42
+ resolve(arg2);
43
+ }
44
+ };
45
+ dic[eventId] = { resolve: doResolve, reject };
46
+ if (ports) {
47
+ offlineWorker2.postMessage({ eventId, methodName, arg }, ports);
48
+ } else {
49
+ offlineWorker2.postMessage({ eventId, methodName, arg });
50
+ }
36
51
  });
37
52
  };
38
53
  };
39
- const obj = Object.assign(Object.fromEntries(methodNames.map((name) => [name, makeFn(name)])), {
54
+ const fns = Object.fromEntries(methodNames.map((name) => [name, makeFn(name)]));
55
+ const obj = Object.assign(fns, {
40
56
  on: (key, fn2) => {
41
57
  cbks[key] = fn2;
42
58
  }
@@ -53,30 +69,32 @@ var makeSyncWorker = (offlineWorker2, methodNames, dbg) => {
53
69
  };
54
70
  var a = (a2) => a2;
55
71
  var makeSyncHandler = a(
56
- (sender, services) => ({
72
+ (services) => ({
57
73
  canHandle: (methodName) => {
58
74
  return methodName in services;
59
75
  },
60
- handle: async ({ data: { eventId, methodName, arg } = {}, ports }) => {
76
+ handle: async ({ data: { eventId, methodName, arg } = {}, source, ports, target }) => {
77
+ const emitter = source?.postMessage && source || target?.postMessage && target || self;
61
78
  try {
62
79
  if (typeof methodName === "string" && methodName in services && services[methodName]) {
63
80
  const results = await services[methodName](arg, { ports });
64
- sender.postMessage({ eventId, methodName, results });
81
+ emitter.postMessage({ eventId, methodName, results });
65
82
  return;
66
83
  }
67
84
  throw new Error(`invalid methodName ${Object.keys(services)} |${String(methodName)}`);
68
85
  } catch (e) {
69
86
  console.debug("failed", e);
70
- sender.postMessage({ eventId, methodName, error: e });
87
+ emitter.postMessage({ eventId, methodName, error: e });
71
88
  }
72
89
  }
73
90
  })
74
91
  );
75
92
  var combineHandlers = (...handlers) => {
76
- return ({ data: { methodName, ...data } = {}, ports }) => {
93
+ return (message) => {
94
+ const methodName = String("methodName" in message.data ? message.data.methodName : "");
77
95
  for (const h of handlers) {
78
- if (h.canHandle(String(methodName))) {
79
- return h.handle({ data: { methodName, ...data }, ports });
96
+ if (h.canHandle(methodName)) {
97
+ return h.handle(message);
80
98
  }
81
99
  }
82
100
  console.error("no handlers matched", methodName);
@@ -113,14 +131,6 @@ var fetchWorkerPromise = new Promise(
113
131
  return fetchWorker;
114
132
  })
115
133
  );
116
- var setWorkersReady;
117
- var workersReadyPromise = new Promise((resolve) => {
118
- setWorkersReady = resolve;
119
- });
120
- var setBooksLoaded;
121
- var setBooksLoadedPromise = new Promise((resolve) => {
122
- setBooksLoaded = resolve;
123
- });
124
134
  var installWorker = async ({
125
135
  skipLoadBooks = false,
126
136
  primaryOnly = false,
@@ -135,7 +145,7 @@ var installWorker = async ({
135
145
  const fetchWorker = await fetchWorkerPromise;
136
146
  const configureOptions = { storage, zipBaseUrl, checkUpdates, confEnv };
137
147
  if (nativeReadFile) {
138
- const wwHandler = makeSyncHandler(offlineWorker, { nativeReadFile, nativeWriteFile, nativeListZips });
148
+ const wwHandler = makeSyncHandler({ nativeReadFile, nativeWriteFile, nativeListZips });
139
149
  offlineWorker.onmessage = combineHandlers(handler, wwHandler);
140
150
  if (storage !== "native") {
141
151
  console.warn("nativeReadFile given, ignoring storage", storage);
@@ -143,13 +153,17 @@ var installWorker = async ({
143
153
  offlineWorkerSync.configure({ ...configureOptions, storage: "native" });
144
154
  } else {
145
155
  offlineWorker.onmessage = handler.handle;
146
- offlineWorkerSync.configure(configureOptions);
156
+ await offlineWorkerSync.configure(configureOptions);
147
157
  }
148
- offlineWorkerSync.on("ready", setWorkersReady);
149
158
  const channel = new MessageChannel();
150
- offlineWorkerSync.initChannel({ ports: [channel.port1] });
151
- fetchWorker.postMessage({ methodName: "initChannel" }, [channel.port2]);
152
- fetchWorker.postMessage({ methodName: "configure", arg: { storage, confEnv } });
159
+ await offlineWorkerSync.initChannel({ ports: [channel.port1] });
160
+ const { handler: fetchWorkerHandler, ...fetchWorkerSync } = makeSyncWorker(fetchWorker, [
161
+ "initChannel",
162
+ "configure"
163
+ ]);
164
+ navigator.serviceWorker.onmessage = combineHandlers(fetchWorkerHandler);
165
+ await fetchWorkerSync.initChannel({ ports: [channel.port2] });
166
+ await fetchWorkerSync.configure({ storage, confEnv });
153
167
  offlineWorkerSync.on("opfsProgress", () => {
154
168
  });
155
169
  if (!primaryOnly) {
@@ -158,9 +172,9 @@ var installWorker = async ({
158
172
  if (!skipLoadBooks) {
159
173
  await offlineWorkerSync.loadBooks({ primaryOnly });
160
174
  }
161
- setBooksLoaded();
162
175
  };
163
176
  var useOfflineWorker_default = ({
177
+ skipLoadBooks,
164
178
  primaryOnly = false,
165
179
  nativeReadFile,
166
180
  nativeWriteFile,
@@ -174,6 +188,7 @@ var useOfflineWorker_default = ({
174
188
  useEffect(() => {
175
189
  const fn = async () => {
176
190
  await installWorker({
191
+ skipLoadBooks,
177
192
  primaryOnly,
178
193
  nativeReadFile,
179
194
  nativeWriteFile,
@@ -183,16 +198,25 @@ var useOfflineWorker_default = ({
183
198
  checkUpdates,
184
199
  confEnv
185
200
  });
186
- await Promise.all([workersReadyPromise, setBooksLoadedPromise]);
187
201
  fetch(window.location.href.replace(window.location.search, ""));
188
202
  setReady(true);
189
203
  };
190
204
  fn();
191
- }, [primaryOnly, nativeReadFile, nativeWriteFile, nativeListZips, storage, zipBaseUrl, checkUpdates, confEnv]);
205
+ }, [
206
+ skipLoadBooks,
207
+ primaryOnly,
208
+ nativeReadFile,
209
+ nativeWriteFile,
210
+ nativeListZips,
211
+ storage,
212
+ zipBaseUrl,
213
+ checkUpdates,
214
+ confEnv
215
+ ]);
192
216
  const loadBook = useCallback(
193
- async ({ id, forceRefresh }, cbk) => {
194
- offlineWorkerSync.on("opfsProgress", cbk);
195
- return await offlineWorkerSync.loadBook({ id, forceRefresh });
217
+ async ({ forceRefresh, ...idOrUri }, cbk) => {
218
+ cbk && offlineWorkerSync.on("opfsProgress", cbk);
219
+ return await offlineWorkerSync.loadBook({ id: "id" in idOrUri ? idOrUri.id : idOrUri.uri, forceRefresh });
196
220
  },
197
221
  []
198
222
  );
@@ -207,6 +231,40 @@ var useOfflineWorker_default = ({
207
231
  reset
208
232
  };
209
233
  };
234
+
235
+ // src/store/index.ts
236
+ import { persistReducer } from "redux-persist";
237
+ var persistEntitiesReducer = (entitiesReducer, CONF_ENV) => {
238
+ const getKey = (key) => `store:${CONF_ENV}:${key}`;
239
+ return persistReducer(
240
+ {
241
+ key: "entities",
242
+ storage: {
243
+ getItem: async (key) => localStorage.getItem(getKey(key)) || "{}",
244
+ setItem: async (key, item) => localStorage.setItem(getKey(key), item),
245
+ removeItem: async (key) => localStorage.removeItem(getKey(key))
246
+ },
247
+ whitelist: ["lexicalFlowers"],
248
+ version: 1,
249
+ debug: true,
250
+ throttle: 1e3
251
+ // lexicalFlowers is small, we may persist it fast
252
+ },
253
+ entitiesReducer
254
+ );
255
+ };
256
+
257
+ // src/store/offlinePersist.tsx
258
+ import { persistStore } from "redux-persist";
259
+ import { PersistGate } from "redux-persist/integration/react";
260
+ import { useMemo } from "react";
261
+ import { jsx } from "react/jsx-runtime";
262
+ var OfflinePersist = ({ store, children }) => {
263
+ const persistor = useMemo(() => persistStore(store), [store]);
264
+ return /* @__PURE__ */ jsx(PersistGate, { loading: null, persistor, children });
265
+ };
210
266
  export {
267
+ OfflinePersist,
268
+ persistEntitiesReducer,
211
269
  useOfflineWorker_default as useOfflineWorker
212
270
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lls/offline",
3
- "version": "24.27.0-ff4d6c28",
3
+ "version": "24.28.0-0854ed80",
4
4
  "description": "offline",
5
5
  "main": "./lib/index.js",
6
6
  "module": "./lib/index.js",
@@ -48,14 +48,15 @@
48
48
  "nock": "14.0.5",
49
49
  "react": "18.3.1",
50
50
  "react-dom": "18.3.1",
51
+ "redux": "5.0.1",
51
52
  "typescript": "5.8.3",
52
53
  "vite": "7.0.7",
53
54
  "vite-tsconfig-paths": "5.1.4",
54
55
  "zod": "3.25.50",
55
- "@lls/vitescripts": "24.27.0-ff4d6c28"
56
+ "@lls/vitescripts": "24.28.0-0854ed80"
56
57
  },
57
58
  "dependencies": {
58
- "fflate": "0.8.2"
59
+ "redux-persist": "6.0.0"
59
60
  },
60
61
  "scripts": {
61
62
  "start": "pnpm ladle serve",