@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/assets/fetch-worker.js +200 -71
- package/lib/assets/offline-worker.js +135 -669
- package/lib/index.js +91 -33
- package/package.json +4 -3
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 && !
|
|
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
|
-
|
|
35
|
-
|
|
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
|
|
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
|
-
(
|
|
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
|
-
|
|
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
|
-
|
|
87
|
+
emitter.postMessage({ eventId, methodName, error: e });
|
|
71
88
|
}
|
|
72
89
|
}
|
|
73
90
|
})
|
|
74
91
|
);
|
|
75
92
|
var combineHandlers = (...handlers) => {
|
|
76
|
-
return (
|
|
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(
|
|
79
|
-
return h.handle(
|
|
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(
|
|
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
|
-
|
|
152
|
-
|
|
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
|
-
}, [
|
|
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 ({
|
|
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.
|
|
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.
|
|
56
|
+
"@lls/vitescripts": "24.28.0-0854ed80"
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
58
|
-
"
|
|
59
|
+
"redux-persist": "6.0.0"
|
|
59
60
|
},
|
|
60
61
|
"scripts": {
|
|
61
62
|
"start": "pnpm ladle serve",
|