@sweidos/eidos 1.0.16 → 1.0.19
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/README.md +199 -22
- package/dist/eidos-sw.js +164 -180
- package/dist/eidos.cjs.js +37 -0
- package/dist/eidos.cjs.js.map +1 -1
- package/dist/eidos.es.js +37 -0
- package/dist/eidos.es.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/query.cjs.js +48 -0
- package/dist/query.d.ts +81 -0
- package/dist/query.js +48 -0
- package/dist/vite.cjs.js +31 -0
- package/dist/vite.d.ts +28 -0
- package/dist/vite.js +31 -0
- package/package.json +24 -4
package/dist/eidos-sw.js
CHANGED
|
@@ -1,229 +1,213 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// 1. App shell caching — dashboard works offline after first visit
|
|
4
|
-
// 2. API resource caching — strategies declared via resource()
|
|
5
|
-
|
|
6
|
-
const CACHE_VERSION = 'v1'
|
|
7
|
-
const SHELL_CACHE = `eidos-shell-${CACHE_VERSION}`
|
|
8
|
-
const API_CACHE = `eidos-resources-${CACHE_VERSION}`
|
|
9
|
-
|
|
1
|
+
const CACHE_VERSION = "v1";
|
|
2
|
+
const CACHE_PREFIX = "eidos";
|
|
10
3
|
const runtimeConfig = {
|
|
11
|
-
resources: new Map(),
|
|
12
|
-
simulateOffline: false
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
self.addEventListener(
|
|
18
|
-
event.waitUntil(self.skipWaiting())
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
// ── Activate ──────────────────────────────────────────────────────────────────
|
|
22
|
-
|
|
23
|
-
self.addEventListener('activate', (event) => {
|
|
4
|
+
resources: /* @__PURE__ */ new Map(),
|
|
5
|
+
simulateOffline: false
|
|
6
|
+
};
|
|
7
|
+
self.addEventListener("install", (event) => {
|
|
8
|
+
event.waitUntil(self.skipWaiting());
|
|
9
|
+
});
|
|
10
|
+
self.addEventListener("activate", (event) => {
|
|
24
11
|
event.waitUntil(
|
|
25
12
|
Promise.all([
|
|
26
13
|
self.clients.claim(),
|
|
27
|
-
caches
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
.map((k) => caches.delete(k))
|
|
14
|
+
// Purge stale caches from previous versions
|
|
15
|
+
caches.keys().then(
|
|
16
|
+
(keys) => Promise.all(
|
|
17
|
+
keys.filter((k) => k.startsWith(CACHE_PREFIX) && !k.endsWith(CACHE_VERSION)).map((k) => caches.delete(k))
|
|
32
18
|
)
|
|
33
|
-
)
|
|
19
|
+
)
|
|
34
20
|
])
|
|
35
|
-
)
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
self.addEventListener('message', (event) => {
|
|
41
|
-
const data = event.data
|
|
42
|
-
if (!data?.type) return
|
|
43
|
-
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
self.addEventListener("message", (event) => {
|
|
24
|
+
const data = event.data;
|
|
25
|
+
if (!data?.type) return;
|
|
44
26
|
switch (data.type) {
|
|
45
|
-
case
|
|
46
|
-
|
|
27
|
+
case "EIDOS_REGISTER_RESOURCE": {
|
|
28
|
+
const url = data.url;
|
|
29
|
+
const patternSrc = data.pattern;
|
|
30
|
+
runtimeConfig.resources.set(url, {
|
|
47
31
|
strategy: data.strategy,
|
|
48
|
-
cacheName: data.cacheName ??
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
32
|
+
cacheName: data.cacheName ?? `${CACHE_PREFIX}-resources-${CACHE_VERSION}`,
|
|
33
|
+
...patternSrc !== void 0 && { pattern: new RegExp(patternSrc) }
|
|
34
|
+
});
|
|
35
|
+
event.source?.postMessage({ type: "EIDOS_RESOURCE_REGISTERED", url });
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
case "EIDOS_UNREGISTER_RESOURCE": {
|
|
39
|
+
runtimeConfig.resources.delete(data.url);
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
case "EIDOS_SIMULATE_OFFLINE": {
|
|
43
|
+
runtimeConfig.simulateOffline = data.enabled;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
case "EIDOS_CLEAR_CACHE": {
|
|
47
|
+
const targetUrl = data.url;
|
|
48
|
+
const reg = targetUrl ? runtimeConfig.resources.get(targetUrl) : void 0;
|
|
49
|
+
const cacheName = reg?.cacheName ?? `${CACHE_PREFIX}-resources-${CACHE_VERSION}`;
|
|
50
|
+
caches.open(cacheName).then(async (cache) => {
|
|
51
|
+
if (targetUrl) {
|
|
52
|
+
const keys = await cache.keys();
|
|
53
|
+
const isCrossOrigin = targetUrl.startsWith("http");
|
|
65
54
|
await Promise.all(
|
|
66
|
-
keys.filter((
|
|
67
|
-
|
|
55
|
+
keys.filter((req) => {
|
|
56
|
+
const reqUrl = req.url;
|
|
57
|
+
const p = new URL(reqUrl).pathname;
|
|
58
|
+
if (reg?.pattern) {
|
|
59
|
+
return reg.pattern.test(isCrossOrigin ? reqUrl : p);
|
|
60
|
+
}
|
|
61
|
+
return isCrossOrigin ? reqUrl === targetUrl : p === targetUrl;
|
|
62
|
+
}).map((req) => cache.delete(req))
|
|
63
|
+
);
|
|
68
64
|
} else {
|
|
69
|
-
|
|
70
|
-
await Promise.all(keys.map((k) => cache.delete(k)))
|
|
65
|
+
await cache.keys().then((keys) => Promise.all(keys.map((k) => cache.delete(k))));
|
|
71
66
|
}
|
|
72
|
-
notifyClients({ type:
|
|
73
|
-
})
|
|
74
|
-
break
|
|
67
|
+
notifyClients({ type: "EIDOS_CACHE_CLEARED", url: targetUrl });
|
|
68
|
+
});
|
|
69
|
+
break;
|
|
75
70
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
break
|
|
71
|
+
case "EIDOS_PING":
|
|
72
|
+
event.source?.postMessage({ type: "EIDOS_PONG" });
|
|
73
|
+
break;
|
|
80
74
|
}
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
75
|
+
});
|
|
76
|
+
self.addEventListener("fetch", (event) => {
|
|
77
|
+
if (event.request.method !== "GET") return;
|
|
78
|
+
const requestUrl = event.request.url;
|
|
79
|
+
const pathname = new URL(requestUrl).pathname;
|
|
80
|
+
let reg = runtimeConfig.resources.get(requestUrl) ?? runtimeConfig.resources.get(pathname);
|
|
81
|
+
if (!reg) {
|
|
82
|
+
for (const [key, registration] of runtimeConfig.resources) {
|
|
83
|
+
if (!registration.pattern) continue;
|
|
84
|
+
const target = key.startsWith("http") ? requestUrl : pathname;
|
|
85
|
+
if (registration.pattern.test(target)) {
|
|
86
|
+
reg = registration;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
96
90
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
event.respondWith(appShell(event.request))
|
|
91
|
+
if (!reg) return;
|
|
92
|
+
if (reg.strategy === "stale-while-revalidate" && !runtimeConfig.simulateOffline) {
|
|
93
|
+
event.respondWith(staleWhileRevalidate(event, event.request, pathname, reg.cacheName));
|
|
94
|
+
return;
|
|
102
95
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const cache = await caches.open(SHELL_CACHE)
|
|
109
|
-
const cached = await cache.match(request)
|
|
110
|
-
|
|
111
|
-
const refresh = fetch(request)
|
|
112
|
-
.then((resp) => {
|
|
113
|
-
if (resp.ok) cache.put(request, resp.clone())
|
|
114
|
-
return resp
|
|
115
|
-
})
|
|
116
|
-
.catch(() => null)
|
|
117
|
-
|
|
118
|
-
if (cached) {
|
|
119
|
-
refresh // update in background
|
|
120
|
-
return cached
|
|
96
|
+
event.respondWith(handleFetch(event.request, pathname, reg));
|
|
97
|
+
});
|
|
98
|
+
async function handleFetch(request, pathname, reg) {
|
|
99
|
+
if (runtimeConfig.simulateOffline) {
|
|
100
|
+
return serveOffline(request, pathname, reg.cacheName);
|
|
121
101
|
}
|
|
122
|
-
|
|
123
|
-
const fresh = await refresh
|
|
124
|
-
return fresh ?? new Response(
|
|
125
|
-
'<html><body><h2>Offline</h2><p>Visit this page while online first.</p></body></html>',
|
|
126
|
-
{ status: 503, headers: { 'Content-Type': 'text/html' } }
|
|
127
|
-
)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// ── API caching strategies ────────────────────────────────────────────────────
|
|
131
|
-
|
|
132
|
-
async function handleApiResource(request, pathname, reg) {
|
|
133
|
-
if (runtimeConfig.simulateOffline) return serveOffline(request, pathname, reg.cacheName)
|
|
134
|
-
|
|
135
102
|
switch (reg.strategy) {
|
|
136
|
-
case
|
|
137
|
-
|
|
138
|
-
case
|
|
139
|
-
|
|
103
|
+
case "cache-first":
|
|
104
|
+
return cacheFirst(request, pathname, reg.cacheName);
|
|
105
|
+
case "stale-while-revalidate":
|
|
106
|
+
return staleWhileRevalidate(null, request, pathname, reg.cacheName);
|
|
107
|
+
case "network-first":
|
|
108
|
+
return networkFirst(request, pathname, reg.cacheName);
|
|
109
|
+
default:
|
|
110
|
+
return fetch(request);
|
|
140
111
|
}
|
|
141
112
|
}
|
|
142
|
-
|
|
143
113
|
async function cacheFirst(request, pathname, cacheName) {
|
|
144
|
-
const cache
|
|
145
|
-
const cached = await cache.match(request)
|
|
114
|
+
const cache = await caches.open(cacheName);
|
|
115
|
+
const cached = await cache.match(request);
|
|
146
116
|
if (cached) {
|
|
147
|
-
notifyClients({ type:
|
|
148
|
-
return cached
|
|
117
|
+
notifyClients({ type: "EIDOS_CACHE_HIT", url: pathname, strategy: "cache-first" });
|
|
118
|
+
return cached;
|
|
149
119
|
}
|
|
150
120
|
try {
|
|
151
|
-
const response = await fetch(request)
|
|
121
|
+
const response = await fetch(request);
|
|
152
122
|
if (response.ok) {
|
|
153
|
-
await cache.put(request, response.clone())
|
|
154
|
-
notifyClients({ type:
|
|
123
|
+
await cache.put(request, response.clone());
|
|
124
|
+
notifyClients({ type: "EIDOS_CACHE_UPDATED", url: pathname, strategy: "cache-first" });
|
|
155
125
|
}
|
|
156
|
-
return response
|
|
126
|
+
return response;
|
|
157
127
|
} catch {
|
|
158
|
-
notifyClients({ type:
|
|
159
|
-
return offlineErrorResponse(pathname)
|
|
128
|
+
notifyClients({ type: "EIDOS_NETWORK_ERROR", url: pathname });
|
|
129
|
+
return offlineErrorResponse(pathname);
|
|
160
130
|
}
|
|
161
131
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
})
|
|
179
|
-
|
|
132
|
+
async function staleWhileRevalidate(event, request, pathname, cacheName) {
|
|
133
|
+
const cache = await caches.open(cacheName);
|
|
134
|
+
const cached = await cache.match(request);
|
|
135
|
+
const revalidatePromise = fetch(request).then(async (response) => {
|
|
136
|
+
if (response.ok) {
|
|
137
|
+
await cache.put(request, response.clone());
|
|
138
|
+
notifyClients({
|
|
139
|
+
type: "EIDOS_CACHE_UPDATED",
|
|
140
|
+
url: pathname,
|
|
141
|
+
strategy: "stale-while-revalidate"
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return response;
|
|
145
|
+
}).catch(() => {
|
|
146
|
+
notifyClients({ type: "EIDOS_NETWORK_ERROR", url: pathname, strategy: "stale-while-revalidate" });
|
|
147
|
+
});
|
|
180
148
|
if (cached) {
|
|
181
|
-
|
|
182
|
-
|
|
149
|
+
event?.waitUntil(revalidatePromise);
|
|
150
|
+
notifyClients({
|
|
151
|
+
type: "EIDOS_CACHE_HIT",
|
|
152
|
+
url: pathname,
|
|
153
|
+
strategy: "stale-while-revalidate"
|
|
154
|
+
});
|
|
155
|
+
return cached;
|
|
183
156
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
return fresh ?? offlineErrorResponse(pathname)
|
|
157
|
+
const fresh = await revalidatePromise;
|
|
158
|
+
return fresh ?? offlineErrorResponse(pathname);
|
|
187
159
|
}
|
|
188
|
-
|
|
189
160
|
async function networkFirst(request, pathname, cacheName) {
|
|
190
|
-
const cache = await caches.open(cacheName)
|
|
161
|
+
const cache = await caches.open(cacheName);
|
|
191
162
|
try {
|
|
192
|
-
const response = await fetch(request)
|
|
163
|
+
const response = await fetch(request, { signal: AbortSignal.timeout(3e3) });
|
|
193
164
|
if (response.ok) {
|
|
194
|
-
await cache.put(request, response.clone())
|
|
195
|
-
notifyClients({ type:
|
|
165
|
+
await cache.put(request, response.clone());
|
|
166
|
+
notifyClients({ type: "EIDOS_CACHE_UPDATED", url: pathname, strategy: "network-first" });
|
|
196
167
|
}
|
|
197
|
-
return response
|
|
168
|
+
return response;
|
|
198
169
|
} catch {
|
|
199
|
-
const cached = await cache.match(request)
|
|
170
|
+
const cached = await cache.match(request);
|
|
200
171
|
if (cached) {
|
|
201
|
-
notifyClients({ type:
|
|
202
|
-
return cached
|
|
172
|
+
notifyClients({ type: "EIDOS_CACHE_HIT", url: pathname, strategy: "network-first" });
|
|
173
|
+
return cached;
|
|
203
174
|
}
|
|
204
|
-
notifyClients({ type:
|
|
205
|
-
return offlineErrorResponse(pathname)
|
|
175
|
+
notifyClients({ type: "EIDOS_NETWORK_ERROR", url: pathname });
|
|
176
|
+
return offlineErrorResponse(pathname);
|
|
206
177
|
}
|
|
207
178
|
}
|
|
208
|
-
|
|
209
179
|
async function serveOffline(request, pathname, cacheName) {
|
|
210
|
-
const cache
|
|
211
|
-
const cached = await cache.match(request)
|
|
180
|
+
const cache = await caches.open(cacheName);
|
|
181
|
+
const cached = await cache.match(request);
|
|
212
182
|
if (cached) {
|
|
213
|
-
notifyClients({ type:
|
|
214
|
-
return cached
|
|
183
|
+
notifyClients({ type: "EIDOS_CACHE_HIT", url: pathname, strategy: "offline-simulation", simulated: true });
|
|
184
|
+
return cached;
|
|
215
185
|
}
|
|
216
|
-
return offlineErrorResponse(pathname)
|
|
186
|
+
return offlineErrorResponse(pathname);
|
|
217
187
|
}
|
|
218
|
-
|
|
219
188
|
function offlineErrorResponse(pathname) {
|
|
220
189
|
return new Response(
|
|
221
|
-
JSON.stringify({
|
|
222
|
-
|
|
223
|
-
|
|
190
|
+
JSON.stringify({
|
|
191
|
+
error: "offline",
|
|
192
|
+
message: `No cached response available for ${pathname}`,
|
|
193
|
+
eidos: true
|
|
194
|
+
}),
|
|
195
|
+
{
|
|
196
|
+
status: 503,
|
|
197
|
+
headers: {
|
|
198
|
+
"Content-Type": "application/json",
|
|
199
|
+
"X-Eidos-Offline": "true"
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
);
|
|
224
203
|
}
|
|
225
|
-
|
|
226
204
|
async function notifyClients(message) {
|
|
227
|
-
const clients = await self.clients.matchAll({ includeUncontrolled: true })
|
|
228
|
-
clients.forEach((
|
|
205
|
+
const clients = await self.clients.matchAll({ includeUncontrolled: true });
|
|
206
|
+
clients.forEach((client) => client.postMessage(message));
|
|
229
207
|
}
|
|
208
|
+
self.addEventListener("sync", (event) => {
|
|
209
|
+
const syncEvent = event;
|
|
210
|
+
if (syncEvent.tag === "eidos-queue-replay") {
|
|
211
|
+
syncEvent.waitUntil(notifyClients({ type: "EIDOS_BACKGROUND_SYNC" }));
|
|
212
|
+
}
|
|
213
|
+
});
|
package/dist/eidos.cjs.js
CHANGED
|
@@ -58,6 +58,9 @@ const useEidosStore = {
|
|
|
58
58
|
};
|
|
59
59
|
let _registration = null;
|
|
60
60
|
let _pendingMessages = [];
|
|
61
|
+
function getSwRegistration() {
|
|
62
|
+
return _registration;
|
|
63
|
+
}
|
|
61
64
|
async function registerServiceWorker(swPath) {
|
|
62
65
|
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
|
|
63
66
|
useEidosStore.getState().setSwStatus("unsupported");
|
|
@@ -106,11 +109,26 @@ function sendToWorker(message) {
|
|
|
106
109
|
_pendingMessages.push(message);
|
|
107
110
|
}
|
|
108
111
|
}
|
|
112
|
+
let _bgSyncHandler = null;
|
|
113
|
+
function registerBgSyncHandler(fn) {
|
|
114
|
+
_bgSyncHandler = fn;
|
|
115
|
+
}
|
|
116
|
+
function isBgSyncSupported() {
|
|
117
|
+
try {
|
|
118
|
+
return typeof navigator !== "undefined" && "serviceWorker" in navigator && _registration !== null && "sync" in _registration;
|
|
119
|
+
} catch {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
109
123
|
function onSwMessage(event) {
|
|
110
124
|
const data = event.data;
|
|
111
125
|
if (!(data == null ? void 0 : data.type)) return;
|
|
112
126
|
const store = useEidosStore.getState();
|
|
113
127
|
const { type, url } = data;
|
|
128
|
+
if (type === "EIDOS_BACKGROUND_SYNC") {
|
|
129
|
+
_bgSyncHandler == null ? void 0 : _bgSyncHandler();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
114
132
|
if (!url) return;
|
|
115
133
|
switch (type) {
|
|
116
134
|
case "EIDOS_CACHE_HIT": {
|
|
@@ -150,6 +168,10 @@ function flushPendingMessages() {
|
|
|
150
168
|
_pendingMessages = [];
|
|
151
169
|
}
|
|
152
170
|
const _registry = /* @__PURE__ */ new Map();
|
|
171
|
+
let _queryInvalidator = null;
|
|
172
|
+
function setQueryInvalidator(fn) {
|
|
173
|
+
_queryInvalidator = fn;
|
|
174
|
+
}
|
|
153
175
|
function isPattern(url) {
|
|
154
176
|
return url.includes("*") || /:[^/]+/.test(url);
|
|
155
177
|
}
|
|
@@ -296,6 +318,7 @@ function resource(url, config) {
|
|
|
296
318
|
cacheMisses: 0
|
|
297
319
|
});
|
|
298
320
|
}
|
|
321
|
+
_queryInvalidator == null ? void 0 : _queryInvalidator(["eidos", url]);
|
|
299
322
|
},
|
|
300
323
|
unregister: () => {
|
|
301
324
|
_registry.delete(url);
|
|
@@ -512,6 +535,13 @@ async function persistAndQueue(actionId, actionName, args, config) {
|
|
|
512
535
|
};
|
|
513
536
|
await idbAddToQueue(item);
|
|
514
537
|
useEidosStore.getState().addQueueItem(item);
|
|
538
|
+
try {
|
|
539
|
+
const reg = getSwRegistration();
|
|
540
|
+
if (reg && "sync" in reg) {
|
|
541
|
+
await reg.sync.register("eidos-queue-replay");
|
|
542
|
+
}
|
|
543
|
+
} catch {
|
|
544
|
+
}
|
|
515
545
|
return {
|
|
516
546
|
queued: true,
|
|
517
547
|
id,
|
|
@@ -605,6 +635,11 @@ async function initEidos(config = {}) {
|
|
|
605
635
|
await registerServiceWorker(swPath);
|
|
606
636
|
} catch {
|
|
607
637
|
}
|
|
638
|
+
registerBgSyncHandler(() => {
|
|
639
|
+
if (useEidosStore.getState().isOnline) {
|
|
640
|
+
setTimeout(replayQueue, 200);
|
|
641
|
+
}
|
|
642
|
+
});
|
|
608
643
|
if (autoReplay) {
|
|
609
644
|
let prevIsOnline = useEidosStore.getState().isOnline;
|
|
610
645
|
useEidosStore.subscribe(() => {
|
|
@@ -711,9 +746,11 @@ exports.eidosResource = eidosResource;
|
|
|
711
746
|
exports.eidosStatus = eidosStatus;
|
|
712
747
|
exports.eidosStore = eidosStore;
|
|
713
748
|
exports.initEidos = initEidos;
|
|
749
|
+
exports.isBgSyncSupported = isBgSyncSupported;
|
|
714
750
|
exports.replayQueue = replayQueue;
|
|
715
751
|
exports.resource = resource;
|
|
716
752
|
exports.setOfflineSimulation = setOfflineSimulation;
|
|
753
|
+
exports.setQueryInvalidator = setQueryInvalidator;
|
|
717
754
|
exports.useEidos = useEidos;
|
|
718
755
|
exports.useEidosAction = useEidosAction;
|
|
719
756
|
exports.useEidosOnDrain = useEidosOnDrain;
|