@auxilium/datalynk-client 1.5.2 โ 1.6.1
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/api.d.ts +27 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/auth.d.ts +2 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/chat-entry.d.ts +3 -0
- package/dist/chat-entry.d.ts.map +1 -0
- package/dist/chat-gui.d.ts +64 -0
- package/dist/chat-gui.d.ts.map +1 -0
- package/dist/chat-gui.view.d.ts +3 -0
- package/dist/chat-gui.view.d.ts.map +1 -0
- package/dist/chat.cjs +2202 -0
- package/dist/chat.d.ts +75 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.mjs +2198 -0
- package/dist/index.cjs +347 -23
- package/dist/index.mjs +347 -23
- package/dist/offline-auth.d.ts +5 -0
- package/dist/offline-auth.d.ts.map +1 -0
- package/dist/service.worker.mjs +113 -14
- package/dist/socket.d.ts +14 -1
- package/dist/socket.d.ts.map +1 -1
- package/package.json +7 -2
package/dist/service.worker.mjs
CHANGED
|
@@ -2,8 +2,80 @@ import {Api} from 'https://datalynk-client.primary.auxilium.world/dist/index.mjs
|
|
|
2
2
|
|
|
3
3
|
let api = null;
|
|
4
4
|
const CACHE_NAME = 'datalynk';
|
|
5
|
+
const STATE_CACHE = 'datalynk-app-state';
|
|
5
6
|
let ONLINE = true;
|
|
6
7
|
const netChan = 'BroadcastChannel' in self ? new BroadcastChannel('sw-net') : null;
|
|
8
|
+
let updateQueue = Promise.resolve();
|
|
9
|
+
|
|
10
|
+
function safeAsset(url) {
|
|
11
|
+
return ['http:', 'https:'].includes(url.protocol)
|
|
12
|
+
&& !/\/(api|login|logout|settings)(\/|$)/i.test(url.pathname)
|
|
13
|
+
&& ![...url.searchParams.keys()].some(key => /token|auth|secret|key|session|password/i.test(key));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function activeCacheName() {
|
|
17
|
+
const state = await caches.open(STATE_CACHE);
|
|
18
|
+
const response = await state.match(self.location.origin + '/datalynk-app-active');
|
|
19
|
+
return response ? response.text() : CACHE_NAME;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function activeCache() {
|
|
23
|
+
return caches.open(await activeCacheName());
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function updateAppAssets(values) {
|
|
27
|
+
updateQueue = updateQueue.catch(() => {}).then(async () => {
|
|
28
|
+
const urls = [...new Set(values.map(value => {
|
|
29
|
+
try {
|
|
30
|
+
const url = new URL(value, self.location.origin);
|
|
31
|
+
url.hash = '';
|
|
32
|
+
return safeAsset(url) && (url.origin === self.location.origin
|
|
33
|
+
|| !/\.(?:png|jpe?g|gif|webp|svg)(?:$|\?)/i.test(url.href)) ? url.href : null;
|
|
34
|
+
} catch { return null; }
|
|
35
|
+
}).filter(Boolean))];
|
|
36
|
+
if(!urls.length) return;
|
|
37
|
+
const previousName = await activeCacheName();
|
|
38
|
+
const nextName = 'datalynk-app-' + Date.now() + '-' + Math.random().toString(36).slice(2);
|
|
39
|
+
const previous = await caches.open(previousName);
|
|
40
|
+
const next = await caches.open(nextName);
|
|
41
|
+
try {
|
|
42
|
+
for(const request of await previous.keys()) {
|
|
43
|
+
if(new URL(request.url).pathname === new URL(urls[0]).pathname
|
|
44
|
+
&& new URL(request.url).origin === new URL(urls[0]).origin) continue;
|
|
45
|
+
const saved = await previous.match(request);
|
|
46
|
+
if(saved && safeAsset(new URL(request.url))) await next.put(request, saved);
|
|
47
|
+
}
|
|
48
|
+
for(const url of urls) {
|
|
49
|
+
const response = await fetch(url, {mode: new URL(url).origin === self.location.origin ? 'same-origin' : 'no-cors'});
|
|
50
|
+
if((!response.ok && response.type !== 'opaque') || response.headers.has('set-cookie')
|
|
51
|
+
|| /private|no-store/i.test(response.headers.get('cache-control') || '')
|
|
52
|
+
|| (/\.json$/i.test(new URL(url).pathname) && !/\bpublic\b/i.test(response.headers.get('cache-control') || ''))
|
|
53
|
+
|| (/\.(?:m?js|css)(?:$|\?)/i.test(url) && /text\/html/i.test(response.headers.get('content-type') || '')))
|
|
54
|
+
throw new Error('Offline app update incomplete: ' + url);
|
|
55
|
+
if(response.type === 'opaque' && await previous.match(url)) continue;
|
|
56
|
+
await next.put(url, response);
|
|
57
|
+
}
|
|
58
|
+
for(const request of await previous.keys()) {
|
|
59
|
+
if(new URL(request.url).pathname === new URL(urls[0]).pathname
|
|
60
|
+
&& new URL(request.url).origin === new URL(urls[0]).origin) continue;
|
|
61
|
+
if(await next.match(request)) continue;
|
|
62
|
+
const saved = await previous.match(request);
|
|
63
|
+
if(saved && safeAsset(new URL(request.url))) await next.put(request, saved);
|
|
64
|
+
}
|
|
65
|
+
const state = await caches.open(STATE_CACHE);
|
|
66
|
+
await state.put(self.location.origin + '/datalynk-app-active', new Response(nextName));
|
|
67
|
+
} catch(error) {
|
|
68
|
+
await caches.delete(nextName);
|
|
69
|
+
console.warn(error);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if(previousName !== nextName) {
|
|
73
|
+
try { await caches.delete(previousName); }
|
|
74
|
+
catch(error) { console.warn('Unable to remove previous app cache', error); }
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
return updateQueue;
|
|
78
|
+
}
|
|
7
79
|
|
|
8
80
|
function broadcastStatus(online) {
|
|
9
81
|
if(ONLINE === online) return;
|
|
@@ -40,7 +112,17 @@ self.addEventListener('activate', (event) => {
|
|
|
40
112
|
event.waitUntil((async () => {
|
|
41
113
|
await self.clients.claim();
|
|
42
114
|
|
|
115
|
+
const appCache = await activeCache();
|
|
116
|
+
for(const request of await appCache.keys())
|
|
117
|
+
if(!safeAsset(new URL(request.url))
|
|
118
|
+
|| (/\.json$/i.test(new URL(request.url).pathname)
|
|
119
|
+
&& !/\bpublic\b/i.test((await appCache.match(request))?.headers.get('cache-control') || '')))
|
|
120
|
+
await appCache.delete(request);
|
|
121
|
+
|
|
43
122
|
const keys = await caches.keys();
|
|
123
|
+
const activeName = await activeCacheName();
|
|
124
|
+
await Promise.all(keys.filter(k => k.startsWith('datalynk-app-')
|
|
125
|
+
&& k !== STATE_CACHE && k !== activeName).map(k => caches.delete(k)));
|
|
44
126
|
await Promise.all(
|
|
45
127
|
keys.filter((k) => k.startsWith('app-cache-') && k !== CACHE_NAME)
|
|
46
128
|
.map((k) => caches.delete(k))
|
|
@@ -76,32 +158,45 @@ self.addEventListener('fetch', (event) => {
|
|
|
76
158
|
}
|
|
77
159
|
|
|
78
160
|
event.respondWith((async () => {
|
|
79
|
-
const cache = await
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
161
|
+
const cache = await activeCache();
|
|
162
|
+
const url = new URL(request.url);
|
|
163
|
+
const appFile = request.mode === 'navigate' || ['script', 'style', 'image', 'font', 'worker'].includes(request.destination);
|
|
164
|
+
const staticJson = url.origin === self.location.origin && /\.json$/i.test(url.pathname) && !request.destination;
|
|
165
|
+
const cacheable = (appFile || staticJson) && safeAsset(url) && !request.headers.has('authorization')
|
|
166
|
+
&& !request.headers.has('range') && (url.origin === self.location.origin || request.destination !== 'image');
|
|
85
167
|
try {
|
|
86
168
|
const networkResponse = await fetch(request);
|
|
87
169
|
broadcastStatus(true);
|
|
88
|
-
if(networkResponse.status === 404)
|
|
89
|
-
await
|
|
90
|
-
return
|
|
170
|
+
if((networkResponse.status === 404 || networkResponse.status >= 500) && cacheable) {
|
|
171
|
+
const cached = await (await activeCache()).match(request, {ignoreSearch: request.mode === 'navigate'});
|
|
172
|
+
if(cached) { broadcastStatus(false); return cached; }
|
|
91
173
|
}
|
|
92
174
|
const isCacheable = networkResponse.ok || networkResponse.type === 'opaque';
|
|
93
|
-
|
|
175
|
+
const saved = cacheable && await cache.match(request, {ignoreSearch: request.mode === 'navigate'});
|
|
176
|
+
if(isCacheable && cacheable && (networkResponse.ok || !saved)
|
|
177
|
+
&& (!staticJson || /\bpublic\b/i.test(networkResponse.headers.get('cache-control') || ''))
|
|
178
|
+
&& !networkResponse.headers.has('set-cookie')
|
|
179
|
+
&& !/private|no-store/i.test(networkResponse.headers.get('cache-control') || '')
|
|
180
|
+
&& !(/\.(?:m?js|css)(?:$|\?)/i.test(url.href) && /text\/html/i.test(networkResponse.headers.get('content-type') || ''))) {
|
|
94
181
|
const isOpaqueNav = networkResponse.type === 'opaque' && request.mode === 'navigate';
|
|
95
182
|
if (!isOpaqueNav) {
|
|
96
|
-
event.waitUntil(
|
|
183
|
+
event.waitUntil((async () => {
|
|
184
|
+
const current = await activeCache();
|
|
185
|
+
const key = request.mode === 'navigate' ? url.origin + url.pathname : request;
|
|
186
|
+
await current.put(key, networkResponse.clone());
|
|
187
|
+
if(request.mode === 'navigate')
|
|
188
|
+
for(const old of await current.keys())
|
|
189
|
+
if(old.url !== key && new URL(old.url).origin === url.origin && new URL(old.url).pathname === url.pathname)
|
|
190
|
+
await current.delete(old);
|
|
191
|
+
})());
|
|
97
192
|
}
|
|
98
193
|
}
|
|
99
194
|
return networkResponse;
|
|
100
195
|
} catch {
|
|
101
196
|
broadcastStatus(false);
|
|
102
|
-
const cached = await
|
|
197
|
+
const cached = cacheable && await (await activeCache()).match(request, {ignoreSearch: request.mode === 'navigate'});
|
|
103
198
|
if(cached) return cached;
|
|
104
|
-
if(request.mode === 'navigate') {
|
|
199
|
+
if(cacheable && request.mode === 'navigate') {
|
|
105
200
|
const fallback = (await cache.match('/')) || (await cache.match('/index.html'));
|
|
106
201
|
if(fallback) return fallback;
|
|
107
202
|
}
|
|
@@ -116,6 +211,9 @@ self.addEventListener('fetch', (event) => {
|
|
|
116
211
|
});
|
|
117
212
|
|
|
118
213
|
self.addEventListener('message', async (event) => {
|
|
214
|
+
if(Array.isArray(event.data?.offlineAssets)) {
|
|
215
|
+
event.waitUntil(updateAppAssets(event.data.offlineAssets));
|
|
216
|
+
}
|
|
119
217
|
if(event.data?.options) { // ๐ง Update settings
|
|
120
218
|
api = new Api(event.data.options.url, { ...event.data.options, serviceWorker: false, replayOfflineQueue: false });
|
|
121
219
|
await setSettings(event.data.options);
|
|
@@ -128,6 +226,7 @@ self.addEventListener('message', async (event) => {
|
|
|
128
226
|
await setSettings({token});
|
|
129
227
|
}
|
|
130
228
|
if(event.data?.clearCache) { // ๐งน Clear cache
|
|
131
|
-
await caches.delete(
|
|
229
|
+
await caches.delete(await activeCacheName());
|
|
230
|
+
await caches.delete(STATE_CACHE);
|
|
132
231
|
}
|
|
133
232
|
});
|
package/dist/socket.d.ts
CHANGED
|
@@ -43,6 +43,10 @@ export type WebRTCEvent = {
|
|
|
43
43
|
export type SocketOptions = {
|
|
44
44
|
/** Set connection URL or disable with false */
|
|
45
45
|
url?: string | false;
|
|
46
|
+
/** Use one-time socket tickets only when explicitly enabled by a chat-capable host. */
|
|
47
|
+
authentication?: 'token' | 'ticket';
|
|
48
|
+
/** Optional realm used by backward-compatible token authentication. */
|
|
49
|
+
realm?: string;
|
|
46
50
|
};
|
|
47
51
|
/** Callback shape */
|
|
48
52
|
export type SocketListener<T = SocketEvent<any>> = (event: T) => any;
|
|
@@ -55,6 +59,7 @@ export declare class Socket {
|
|
|
55
59
|
private listeners;
|
|
56
60
|
private retry?;
|
|
57
61
|
private socket?;
|
|
62
|
+
private connectGeneration;
|
|
58
63
|
open: boolean;
|
|
59
64
|
constructor(api: Api, options?: SocketOptions);
|
|
60
65
|
/**
|
|
@@ -76,7 +81,14 @@ export declare class Socket {
|
|
|
76
81
|
* Connect socket client to socket server
|
|
77
82
|
* @param {number} timeout Retry to connect every x seconds
|
|
78
83
|
*/
|
|
79
|
-
connect(timeout?: number): void
|
|
84
|
+
connect(timeout?: number): void | Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Ticket-authenticated connection path, used only once a chat-capable host switches
|
|
87
|
+
* this instance to `authentication: 'ticket'` (see Api.openChat). Entirely separate
|
|
88
|
+
* from the token path above so existing non-chat consumers are never affected.
|
|
89
|
+
*/
|
|
90
|
+
private connectWithTicket;
|
|
91
|
+
private scheduleReconnect;
|
|
80
92
|
/**
|
|
81
93
|
* Send data to socket server
|
|
82
94
|
*
|
|
@@ -91,5 +103,6 @@ export declare class Socket {
|
|
|
91
103
|
* @return {Unsubscribe} Run returned function to unsubscribe callback
|
|
92
104
|
*/
|
|
93
105
|
sliceEvents(slice: number | number[] | string | string[], callback: SocketListener<SocketEventSlice>): Unsubscribe;
|
|
106
|
+
private normalizeUrl;
|
|
94
107
|
}
|
|
95
108
|
//# sourceMappingURL=socket.d.ts.map
|
package/dist/socket.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../src/socket.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,GAAG,EAAC,MAAM,OAAO,CAAC;AAE1B,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,CAAC,CAAA;CACP,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,WAAW,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GACvC,CAAC;IAAC,SAAS,EAAE;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,CAAA;CAAC,GAC7C;IAAC,YAAY,EAAE;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,CAAA;CAAC,GAC/C;IAAC,KAAK,EAAE;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,yBAAyB,CAAA;KAAC,CAAA;CAAC,GACtF;IAAC,MAAM,EAAE;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,yBAAyB,CAAA;KAAC,CAAA;CAAC,CAAC,CAAC;AAE1F,yBAAyB;AACzB,MAAM,MAAM,aAAa,GAAG;IAC3B,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../src/socket.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,GAAG,EAAC,MAAM,OAAO,CAAC;AAE1B,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,CAAC,CAAA;CACP,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,WAAW,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GACvC,CAAC;IAAC,SAAS,EAAE;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,CAAA;CAAC,GAC7C;IAAC,YAAY,EAAE;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,CAAA;CAAC,GAC/C;IAAC,KAAK,EAAE;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,yBAAyB,CAAA;KAAC,CAAA;CAAC,GACtF;IAAC,MAAM,EAAE;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,yBAAyB,CAAA;KAAC,CAAA;CAAC,CAAC,CAAC;AAE1F,yBAAyB;AACzB,MAAM,MAAM,aAAa,GAAG;IAC3B,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,uFAAuF;IACvF,cAAc,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACpC,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;CACf,CAAA;AAED,qBAAqB;AACrB,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,GAAG,CAAC;AACrE,8CAA8C;AAC9C,MAAM,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;AAErC,iCAAiC;AACjC,qBAAa,MAAM;IAQN,OAAO,CAAC,QAAQ,CAAC,GAAG;aAAuB,OAAO,EAAE,aAAa;IAP7E,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,KAAK,CAAC,CAAM;IACpB,OAAO,CAAC,MAAM,CAAC,CAAY;IAC3B,OAAO,CAAC,iBAAiB,CAAK;IAE9B,IAAI,UAAS;gBAEgB,GAAG,EAAE,GAAG,EAAkB,OAAO,GAAE,aAAkB;IAWlF;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,IAAI,GAAG,WAAW;IAOnE;;OAEG;IACH,KAAK;IAUL;;;OAGG;IACH,OAAO,CAAC,OAAO,GAAE,MAAW;IAiC5B;;;;OAIG;YACW,iBAAiB;IA6D/B,OAAO,CAAC,iBAAiB;IASzB;;;;OAIG;IACH,IAAI,CAAC,OAAO,EAAE,GAAG;IAKjB;;;;;;OAMG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,MAAM,EAAE,EAAE,QAAQ,EAAE,cAAc,CAAC,gBAAgB,CAAC,GAAG,WAAW;IAWlH,OAAO,CAAC,YAAY;CAUpB"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@auxilium/datalynk-client",
|
|
3
3
|
"description": "Datalynk client library",
|
|
4
4
|
"repository": "https://gitlab.auxiliumgroup.com/auxilium/datalynk/datalynk-client",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.6.1",
|
|
6
6
|
"author": "Auxilium Group <devops@auxiliumgroup.com>",
|
|
7
7
|
"private": false,
|
|
8
8
|
"main": "./dist/index.cjs",
|
|
@@ -13,13 +13,18 @@
|
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"import": "./dist/index.mjs",
|
|
15
15
|
"require": "./dist/index.cjs"
|
|
16
|
+
},
|
|
17
|
+
"./chat": {
|
|
18
|
+
"types": "./dist/chat-entry.d.ts",
|
|
19
|
+
"import": "./dist/chat.mjs",
|
|
20
|
+
"require": "./dist/chat.cjs"
|
|
16
21
|
}
|
|
17
22
|
},
|
|
18
23
|
"bin": {
|
|
19
24
|
"datalynk-models": "./bin/datalynk-models.mjs"
|
|
20
25
|
},
|
|
21
26
|
"scripts": {
|
|
22
|
-
"build": "tsc && npx vite build",
|
|
27
|
+
"build": "tsc && npx vite build && npx vite build --config vite.chat.config.ts",
|
|
23
28
|
"postbuild": "node -e \"const fs=require('fs');fs.cpSync('src/service.worker.mjs','dist/service.worker.mjs')\"",
|
|
24
29
|
"test": "npm run build && node --test test/*.test.mjs",
|
|
25
30
|
"datalynk-models": "node --no-warnings ./bin/datalynk-models.mjs",
|