jg-sw 1.0.0 → 1.1.0
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/API.md +576 -0
- package/CHANGELOG.md +24 -25
- package/README.md +2 -34
- package/dist/build/config/config.d.ts +2 -0
- package/dist/build/config/config.js +11 -6
- package/dist/build/config/config.js.map +1 -1
- package/dist/build/config/firebase.js +8 -5
- package/dist/build/config/firebase.js.map +1 -1
- package/dist/build/config/schema.d.ts +2 -0
- package/dist/build/config/schema.js +2 -0
- package/dist/build/config/schema.js.map +1 -1
- package/dist/build/precache/precache.js +6 -2
- package/dist/build/precache/precache.js.map +1 -1
- package/dist/build/service-worker/service-worker.d.ts +4 -0
- package/dist/build/service-worker/service-worker.js +4 -0
- package/dist/build/service-worker/service-worker.js.map +1 -1
- package/dist/runtime/installation/installation.d.ts +4 -0
- package/dist/runtime/installation/installation.js +10 -3
- package/dist/runtime/installation/installation.js.map +1 -1
- package/dist/runtime/registration/registration.d.ts +5 -2
- package/dist/runtime/registration/registration.js +18 -6
- package/dist/runtime/registration/registration.js.map +1 -1
- package/dist/runtime/shared/errors.d.ts +1 -0
- package/dist/runtime/shared/errors.js +1 -0
- package/dist/runtime/shared/errors.js.map +1 -1
- package/dist/runtime/shared/types.d.ts +2 -1
- package/dist/runtime/shared/types.js.map +1 -1
- package/dist/runtime/state/state.d.ts +4 -0
- package/dist/runtime/state/state.js +4 -0
- package/dist/runtime/state/state.js.map +1 -1
- package/dist/runtime/update/update.d.ts +2 -0
- package/dist/runtime/update/update.js +2 -0
- package/dist/runtime/update/update.js.map +1 -1
- package/package.json +9 -6
package/API.md
ADDED
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
# <a id="api-reference"></a>jg-sw API reference
|
|
2
|
+
|
|
3
|
+
Every export of `jg-sw@1.1.0`, 26 in all, with its signature, its errors, and an example. It's generated from the package's TSDoc.
|
|
4
|
+
|
|
5
|
+
## <a id="api-entry-main"></a>`jg-sw`
|
|
6
|
+
|
|
7
|
+
- Functions: [`canInstallApp`](#api-canInstallApp), [`getServiceWorkerSnapshot`](#api-getServiceWorkerSnapshot), [`installApp`](#api-installApp), [`registerServiceWorker`](#api-registerServiceWorker), [`subscribeToServiceWorker`](#api-subscribeToServiceWorker), [`updateApp`](#api-updateApp)
|
|
8
|
+
- Constants: [`DEFAULT_SERVICE_WORKER_PATH`](#api-DEFAULT_SERVICE_WORKER_PATH), [`DEFAULT_SERVICE_WORKER_SCOPE`](#api-DEFAULT_SERVICE_WORKER_SCOPE), [`ERRORS`](#api-ERRORS), [`REGISTRATION_DURATION_SECONDS`](#api-REGISTRATION_DURATION_SECONDS), [`SKIP_WAITING_MESSAGE_TYPE`](#api-SKIP_WAITING_MESSAGE_TYPE), [`UPDATE_INSTALL_TIMEOUT_SECONDS`](#api-UPDATE_INSTALL_TIMEOUT_SECONDS)
|
|
9
|
+
- Interfaces: [`IBeforeInstallPromptEvent`](#api-IBeforeInstallPromptEvent)
|
|
10
|
+
- Types: [`IAppInstallationState`](#api-IAppInstallationState), [`IInstallationPromptOutcome`](#api-IInstallationPromptOutcome), [`IRegisterServiceWorkerOptions`](#api-IRegisterServiceWorkerOptions), [`IServiceWorkerSnapshot`](#api-IServiceWorkerSnapshot), [`IUserChoice`](#api-IUserChoice)
|
|
11
|
+
|
|
12
|
+
### <a id="api-functions"></a>Functions in `jg-sw`
|
|
13
|
+
|
|
14
|
+
#### <a id="api-canInstallApp"></a>`canInstallApp`
|
|
15
|
+
|
|
16
|
+
*Function*
|
|
17
|
+
|
|
18
|
+
Checks whether installApp can show the installation prompt now: the browser offered one, and the page doesn't already run as the installed app. Only Chromium-based browsers offer it.
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
canInstallApp(): boolean
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Returns** `boolean`: Whether the app can be installed.
|
|
25
|
+
|
|
26
|
+
**Example**
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { canInstallApp } from 'jg-sw';
|
|
30
|
+
|
|
31
|
+
installButton.hidden = !canInstallApp();
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
#### <a id="api-getServiceWorkerSnapshot"></a>`getServiceWorkerSnapshot`
|
|
35
|
+
|
|
36
|
+
*Function*
|
|
37
|
+
|
|
38
|
+
Reads the service worker's state: its registration, its newest worker, whether an update waits, and whether the app can be installed. The same object comes back until something changes, so it can be passed to React's useSyncExternalStore, during server rendering too.
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
getServiceWorkerSnapshot(): IServiceWorkerSnapshot
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Returns** `IServiceWorkerSnapshot`: The snapshot.
|
|
45
|
+
|
|
46
|
+
**Example**
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { getServiceWorkerSnapshot, subscribeToServiceWorker } from 'jg-sw';
|
|
50
|
+
|
|
51
|
+
const { hasWaitingWorker, installation } = useSyncExternalStore(
|
|
52
|
+
subscribeToServiceWorker,
|
|
53
|
+
getServiceWorkerSnapshot,
|
|
54
|
+
getServiceWorkerSnapshot,
|
|
55
|
+
);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### <a id="api-installApp"></a>`installApp`
|
|
59
|
+
|
|
60
|
+
*Function*
|
|
61
|
+
|
|
62
|
+
Shows the browser's installation prompt and resolves to the user's answer, also kept in the snapshot as installation.promptOutcome. The browser offers each prompt once, so canInstallApp is false afterwards until it offers another.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
installApp(): Promise<IInstallationPromptOutcome>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Returns** `Promise<IInstallationPromptOutcome>`: A promise that resolves to 'accepted' or 'dismissed'.
|
|
69
|
+
|
|
70
|
+
**Throws**
|
|
71
|
+
|
|
72
|
+
- `NO_APP_INSTALLER`: The app can't be installed because the browser didn't offer the prompt.
|
|
73
|
+
- `UNKNOWN_INSTALLATION_PROMPT_ERROR`: The installation prompt failed.
|
|
74
|
+
|
|
75
|
+
**Example**
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { installApp } from 'jg-sw';
|
|
79
|
+
|
|
80
|
+
installButton.addEventListener('click', async () => {
|
|
81
|
+
const outcome = await installApp(); // 'accepted' or 'dismissed'
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### <a id="api-registerServiceWorker"></a>`registerServiceWorker`
|
|
86
|
+
|
|
87
|
+
*Function*
|
|
88
|
+
|
|
89
|
+
Registers the service worker and starts following its updates and whether the app can be installed. Later calls return the first call's promise. It never rejects: a failure lands in the snapshot's registrationError, an Exception with SW_NO_BROWSER_SUPPORT, EMPTY_SW_REGISTRATION, or SW_REGISTRATION_FAILED as its code, and the browser's error as its cause.
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
registerServiceWorker(
|
|
93
|
+
options?: IRegisterServiceWorkerOptions,
|
|
94
|
+
): Promise<IServiceWorkerSnapshot>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Parameters**
|
|
98
|
+
|
|
99
|
+
- `options?` `IRegisterServiceWorkerOptions`: The worker's path and registration options, and whether to log. Defaults to `{}`.
|
|
100
|
+
|
|
101
|
+
**Returns** `Promise<IServiceWorkerSnapshot>`: A promise that resolves to the snapshot once the registration settles.
|
|
102
|
+
|
|
103
|
+
**Example**
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { hasErrorCode } from 'jg-exception';
|
|
107
|
+
import { ERRORS, registerServiceWorker } from 'jg-sw';
|
|
108
|
+
|
|
109
|
+
const { registration, registrationError } = await registerServiceWorker();
|
|
110
|
+
if (hasErrorCode(registrationError, ERRORS.SW_NO_BROWSER_SUPPORT)) {
|
|
111
|
+
// the browser has no service workers
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### <a id="api-subscribeToServiceWorker"></a>`subscribeToServiceWorker`
|
|
116
|
+
|
|
117
|
+
*Function*
|
|
118
|
+
|
|
119
|
+
Calls a listener whenever the snapshot changes, such as when an update finishes installing or the app becomes installable.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
subscribeToServiceWorker(listener: () => void): () => void
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Parameters**
|
|
126
|
+
|
|
127
|
+
- `listener` `() => void`: The function to call, without arguments; read the new state with getServiceWorkerSnapshot.
|
|
128
|
+
|
|
129
|
+
**Returns** `() => void`: A function that stops the calls.
|
|
130
|
+
|
|
131
|
+
**Example**
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { getServiceWorkerSnapshot, subscribeToServiceWorker } from 'jg-sw';
|
|
135
|
+
|
|
136
|
+
const unsubscribe = subscribeToServiceWorker(() => {
|
|
137
|
+
if (getServiceWorkerSnapshot().hasWaitingWorker) {
|
|
138
|
+
showUpdateBanner();
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### <a id="api-updateApp"></a>`updateApp`
|
|
144
|
+
|
|
145
|
+
*Function*
|
|
146
|
+
|
|
147
|
+
Updates the app to its newest version and reloads the page once, never in a loop. When a new version waits, it activates it and reloads once the new worker controls the page. Otherwise, it checks for one, waits up to UPDATE_INSTALL_TIMEOUT_SECONDS for it to install, then activates it the same way. When nothing new is found, the installation fails, or the time runs out, it reloads the page as it is.
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
updateApp(): Promise<void>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Returns** `Promise<void>`: A promise that resolves once the new worker was asked to activate, or the page started reloading.
|
|
154
|
+
|
|
155
|
+
**Example**
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import { getServiceWorkerSnapshot, updateApp } from 'jg-sw';
|
|
159
|
+
|
|
160
|
+
if (getServiceWorkerSnapshot().hasWaitingWorker) {
|
|
161
|
+
updateButton.addEventListener('click', () => updateApp());
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### <a id="api-constants"></a>Constants in `jg-sw`
|
|
166
|
+
|
|
167
|
+
#### <a id="api-DEFAULT_SERVICE_WORKER_PATH"></a>`DEFAULT_SERVICE_WORKER_PATH`
|
|
168
|
+
|
|
169
|
+
*Constant*
|
|
170
|
+
|
|
171
|
+
the path the runtime registers the worker from, and the Vite plugin serves it at in development
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
const DEFAULT_SERVICE_WORKER_PATH: "/sw.js"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### <a id="api-DEFAULT_SERVICE_WORKER_SCOPE"></a>`DEFAULT_SERVICE_WORKER_SCOPE`
|
|
178
|
+
|
|
179
|
+
*Constant*
|
|
180
|
+
|
|
181
|
+
the scope the runtime registers the worker with
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
const DEFAULT_SERVICE_WORKER_SCOPE: "/"
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### <a id="api-ERRORS"></a>`ERRORS`
|
|
188
|
+
|
|
189
|
+
*Constant*
|
|
190
|
+
|
|
191
|
+
the codes for every error thrown or reported by the runtime
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
const ERRORS: { SW_NO_BROWSER_SUPPORT: "SW_NO_BROWSER_SUPPORT"; EMPTY_SW_REGISTRATION: "EMPTY_SW_REGISTRATION"; SW_REGISTRATION_FAILED: "SW_REGISTRATION_FAILED"; NO_APP_INSTALLER: "NO_APP_INSTALLER"; UNKNOWN_INSTALLATION_PROMPT_ERROR: "UNKNOWN_INSTALLATION_PROMPT_ERROR" }
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
#### <a id="api-REGISTRATION_DURATION_SECONDS"></a>`REGISTRATION_DURATION_SECONDS`
|
|
198
|
+
|
|
199
|
+
*Constant*
|
|
200
|
+
|
|
201
|
+
the seconds a registration usually takes, for apps that wait before reading the snapshot
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
const REGISTRATION_DURATION_SECONDS: 5
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
#### <a id="api-SKIP_WAITING_MESSAGE_TYPE"></a>`SKIP_WAITING_MESSAGE_TYPE`
|
|
208
|
+
|
|
209
|
+
*Constant*
|
|
210
|
+
|
|
211
|
+
the type of the message the runtime posts to make a waiting worker activate
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
const SKIP_WAITING_MESSAGE_TYPE: "JG_SW_SKIP_WAITING"
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
#### <a id="api-UPDATE_INSTALL_TIMEOUT_SECONDS"></a>`UPDATE_INSTALL_TIMEOUT_SECONDS`
|
|
218
|
+
|
|
219
|
+
*Constant*
|
|
220
|
+
|
|
221
|
+
the seconds updateApp waits for a new worker to finish installing before it reloads anyway
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
const UPDATE_INSTALL_TIMEOUT_SECONDS: 30
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### <a id="api-interfaces"></a>Interfaces in `jg-sw`
|
|
228
|
+
|
|
229
|
+
#### <a id="api-IBeforeInstallPromptEvent"></a>`IBeforeInstallPromptEvent`
|
|
230
|
+
|
|
231
|
+
*Interface*
|
|
232
|
+
|
|
233
|
+
the event Chromium-based browsers fire when the app can be installed, which lets the app show the installation prompt when it chooses
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
interface IBeforeInstallPromptEvent extends Event {
|
|
237
|
+
readonly platforms: string[];
|
|
238
|
+
readonly userChoice: Promise<IUserChoice>;
|
|
239
|
+
prompt(): Promise<void>;
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Members**
|
|
244
|
+
|
|
245
|
+
- `platforms: string[]` (property): the platforms the event was dispatched for, such as 'web' or 'play'
|
|
246
|
+
- `userChoice: Promise<IUserChoice>` (property): resolves to the user's answer once the prompt closes
|
|
247
|
+
- `prompt(): Promise<void>` (method): shows the installation prompt
|
|
248
|
+
|
|
249
|
+
### <a id="api-types"></a>Types in `jg-sw`
|
|
250
|
+
|
|
251
|
+
#### <a id="api-IAppInstallationState"></a>`IAppInstallationState`
|
|
252
|
+
|
|
253
|
+
*Type*
|
|
254
|
+
|
|
255
|
+
whether the app can be installed, and what happened when it was offered
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
type IAppInstallationState = {
|
|
259
|
+
canInstall: boolean;
|
|
260
|
+
isAppInstalled: boolean | undefined;
|
|
261
|
+
isRunningInstalledApp: boolean;
|
|
262
|
+
promptOutcome: IInstallationPromptOutcome | undefined;
|
|
263
|
+
};
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**Members**
|
|
267
|
+
|
|
268
|
+
- `canInstall: boolean` (property): whether installApp can show the installation prompt now
|
|
269
|
+
- `isAppInstalled: boolean | undefined` (property): true once the browser reports the app was installed, undefined until then
|
|
270
|
+
- `isRunningInstalledApp: boolean` (property): whether the page runs as the installed app, in a standalone window
|
|
271
|
+
- `promptOutcome: IInstallationPromptOutcome | undefined` (property): the user's answer to the last prompt installApp showed, undefined until one is answered
|
|
272
|
+
|
|
273
|
+
#### <a id="api-IInstallationPromptOutcome"></a>`IInstallationPromptOutcome`
|
|
274
|
+
|
|
275
|
+
*Type*
|
|
276
|
+
|
|
277
|
+
the action the user took on the installation prompt
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
type IInstallationPromptOutcome = 'accepted' | 'dismissed';
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
#### <a id="api-IRegisterServiceWorkerOptions"></a>`IRegisterServiceWorkerOptions`
|
|
284
|
+
|
|
285
|
+
*Type*
|
|
286
|
+
|
|
287
|
+
the options registerServiceWorker accepts
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
type IRegisterServiceWorkerOptions = {
|
|
291
|
+
path?: string;
|
|
292
|
+
options?: RegistrationOptions;
|
|
293
|
+
debugMode?: boolean;
|
|
294
|
+
};
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**Members**
|
|
298
|
+
|
|
299
|
+
- `path: string` (property): the worker's script. Defaults to DEFAULT_SERVICE_WORKER_PATH, '/sw.js'
|
|
300
|
+
- `options: RegistrationOptions` (property): the options passed to navigator.serviceWorker.register. Defaults to { scope: '/' }
|
|
301
|
+
- `debugMode: boolean` (property): logs the registration, update, and installation events to the console
|
|
302
|
+
|
|
303
|
+
#### <a id="api-IServiceWorkerSnapshot"></a>`IServiceWorkerSnapshot`
|
|
304
|
+
|
|
305
|
+
*Type*
|
|
306
|
+
|
|
307
|
+
the service worker's state. The object keeps its identity until something changes, so useSyncExternalStore(subscribeToServiceWorker, getServiceWorkerSnapshot) re-renders only on changes
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
type IServiceWorkerSnapshot = {
|
|
311
|
+
registration: ServiceWorkerRegistration | undefined;
|
|
312
|
+
worker: ServiceWorker | undefined;
|
|
313
|
+
registrationError: Exception | undefined;
|
|
314
|
+
hasWaitingWorker: boolean;
|
|
315
|
+
installation: IAppInstallationState;
|
|
316
|
+
};
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Members**
|
|
320
|
+
|
|
321
|
+
- `registration: ServiceWorkerRegistration | undefined` (property): the registration, once registerServiceWorker succeeds
|
|
322
|
+
- `worker: ServiceWorker | undefined` (property): the newest worker: the installing one, else the waiting one, else the active one
|
|
323
|
+
- `registrationError: Exception | undefined` (property): why the registration failed, with one of the ERRORS codes
|
|
324
|
+
- `hasWaitingWorker: boolean` (property): whether a new version is installed and waits to activate, which updateApp does
|
|
325
|
+
- `installation: IAppInstallationState` (property): whether the app can be installed, and what happened when it was offered
|
|
326
|
+
|
|
327
|
+
#### <a id="api-IUserChoice"></a>`IUserChoice`
|
|
328
|
+
|
|
329
|
+
*Type*
|
|
330
|
+
|
|
331
|
+
the user's answer to the installation prompt
|
|
332
|
+
|
|
333
|
+
```ts
|
|
334
|
+
type IUserChoice = {
|
|
335
|
+
outcome: IInstallationPromptOutcome;
|
|
336
|
+
platform: string;
|
|
337
|
+
};
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Members**
|
|
341
|
+
|
|
342
|
+
- `outcome: IInstallationPromptOutcome` (property)
|
|
343
|
+
- `platform: string` (property)
|
|
344
|
+
|
|
345
|
+
## <a id="api-entry-build"></a>`jg-sw/build`
|
|
346
|
+
|
|
347
|
+
- Functions: [`buildServiceWorker`](#api-build-buildServiceWorker), [`readServiceWorkerConfig`](#api-build-readServiceWorkerConfig), [`serviceWorkerPlugin`](#api-build-serviceWorkerPlugin), [`writeServiceWorker`](#api-build-writeServiceWorker)
|
|
348
|
+
- Constants: [`ERRORS`](#api-build-ERRORS), [`ServiceWorkerConfigSchema`](#api-build-ServiceWorkerConfigSchema)
|
|
349
|
+
- Types: [`IBuildServiceWorkerOptions`](#api-build-IBuildServiceWorkerOptions), [`IServiceWorkerConfig`](#api-build-IServiceWorkerConfig)
|
|
350
|
+
|
|
351
|
+
### <a id="api-build-functions"></a>Functions in `jg-sw/build`
|
|
352
|
+
|
|
353
|
+
#### <a id="api-build-buildServiceWorker"></a>`buildServiceWorker`
|
|
354
|
+
|
|
355
|
+
*Function*
|
|
356
|
+
|
|
357
|
+
Generates the service worker's source from a config, without writing it. Every generated worker gets a new cache name, `<cacheNamePrefix>--<10 random characters>`, so a new deployment replaces the previous one's cache when it activates.
|
|
358
|
+
|
|
359
|
+
```ts
|
|
360
|
+
buildServiceWorker(
|
|
361
|
+
config: { outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "base" } | { outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "firebase-fcm"; firebaseConfigProcessEnvKey: string; firebaseSdkVersion: string },
|
|
362
|
+
options?: IBuildServiceWorkerOptions,
|
|
363
|
+
): Promise<string>
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Parameters**
|
|
367
|
+
|
|
368
|
+
- `config` `{ outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "base" } | { outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "firebase-fcm"; firebaseConfigProcessEnvKey: string; firebaseSdkVersion: string }`: The service worker config, as read by readServiceWorkerConfig or written inline.
|
|
369
|
+
- `options?` `IBuildServiceWorkerOptions`: The environment the firebase-fcm template reads its Firebase config from, whether the worker caches (false for development), and the directory paths are resolved from. Defaults to `{}`.
|
|
370
|
+
|
|
371
|
+
**Returns** `Promise<string>`: A promise that resolves to the worker's source.
|
|
372
|
+
|
|
373
|
+
**Throws**
|
|
374
|
+
|
|
375
|
+
- `FAILED_TO_READ_BASE_CONFIG`: The service worker config is invalid.
|
|
376
|
+
- `INVALID_TEMPLATE_NAME`: The template must be 'base' or 'firebase-fcm'.
|
|
377
|
+
- `INVALID_FIREBASE_SDK_VERSION`: The Firebase SDK version must be a version such as 12.4.0.
|
|
378
|
+
- `INVALID_ENVIRONMENT`: The environment isn't supported, or the firebase-fcm template needs one.
|
|
379
|
+
- `NOT_A_PATH_ELEMENT`: An asset to precache is outside outDir, or isn't a file or a directory.
|
|
380
|
+
- `FAILED_TO_BUILD_CONFIG`: Unable to load the environment file.
|
|
381
|
+
- `INVALID_FIREBASE_CONFIG`: The environment variable that holds the Firebase config is missing or
|
|
382
|
+
- empty.
|
|
383
|
+
- `FAILED_TO_READ_FIREBASE_CONFIG`: Unable to read the Firebase config from the environment
|
|
384
|
+
- variable.
|
|
385
|
+
|
|
386
|
+
**Example**
|
|
387
|
+
|
|
388
|
+
```ts
|
|
389
|
+
import { buildServiceWorker } from 'jg-sw/build';
|
|
390
|
+
|
|
391
|
+
const source = await buildServiceWorker(
|
|
392
|
+
{
|
|
393
|
+
outDir: 'dist',
|
|
394
|
+
cacheNamePrefix: 'my-app',
|
|
395
|
+
template: 'base',
|
|
396
|
+
includeToPrecache: ['/', '/assets'],
|
|
397
|
+
excludeFilesFromPrecache: [],
|
|
398
|
+
excludeMIMETypesFromCache: ['application/json'],
|
|
399
|
+
},
|
|
400
|
+
{ caching: true },
|
|
401
|
+
);
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
#### <a id="api-build-readServiceWorkerConfig"></a>`readServiceWorkerConfig`
|
|
405
|
+
|
|
406
|
+
*Function*
|
|
407
|
+
|
|
408
|
+
Reads and validates a service worker config file, such as `jg-sw.config.json`.
|
|
409
|
+
|
|
410
|
+
```ts
|
|
411
|
+
readServiceWorkerConfig(
|
|
412
|
+
path: string,
|
|
413
|
+
): Promise<{ outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "base" } | { outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "firebase-fcm"; firebaseConfigProcessEnvKey: string; firebaseSdkVersion: string }>
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
**Parameters**
|
|
417
|
+
|
|
418
|
+
- `path` `string`: The config file's path.
|
|
419
|
+
|
|
420
|
+
**Returns** `Promise<{ outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "base" } | { outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "firebase-fcm"; firebaseConfigProcessEnvKey: string; firebaseSdkVersion: string }>`: A promise that resolves to the config.
|
|
421
|
+
|
|
422
|
+
**Throws**
|
|
423
|
+
|
|
424
|
+
- `FAILED_TO_READ_BASE_CONFIG`: Unable to read the service worker config, or it is invalid.
|
|
425
|
+
- `INVALID_TEMPLATE_NAME`: The template must be 'base' or 'firebase-fcm'.
|
|
426
|
+
- `INVALID_FIREBASE_SDK_VERSION`: The Firebase SDK version must be a version such as 12.4.0.
|
|
427
|
+
|
|
428
|
+
**Example**
|
|
429
|
+
|
|
430
|
+
```ts
|
|
431
|
+
import { readServiceWorkerConfig } from 'jg-sw/build';
|
|
432
|
+
|
|
433
|
+
const config = await readServiceWorkerConfig('jg-sw.config.json');
|
|
434
|
+
config.template; // 'base'
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
#### <a id="api-build-serviceWorkerPlugin"></a>`serviceWorkerPlugin`
|
|
438
|
+
|
|
439
|
+
*Function*
|
|
440
|
+
|
|
441
|
+
Creates a Vite plugin that generates the service worker. After a production build, it writes `sw.js` into the config's outDir, once the client bundle is written. During development, the dev server answers `/sw.js` with a worker generated with `caching: false`, so every request reaches the dev server and updates show up without stale caches. Paths are resolved from Vite's root unless `cwd` is set. When generating fails, the build fails with writeServiceWorker's error, and the dev server answers the worker's request with it.
|
|
442
|
+
|
|
443
|
+
```ts
|
|
444
|
+
serviceWorkerPlugin(
|
|
445
|
+
options: { config: string | { outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "base" } | { outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "firebase-fcm"; firebaseConfigProcessEnvKey: string; firebaseSdkVersion: string } } & IBuildServiceWorkerOptions,
|
|
446
|
+
): Plugin
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
**Parameters**
|
|
450
|
+
|
|
451
|
+
- `options` `{ config: string | { outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "base" } | { outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "firebase-fcm"; firebaseConfigProcessEnvKey: string; firebaseSdkVersion: string } } & IBuildServiceWorkerOptions`: The config, as a file path or an object, plus the build options. The dev server uses the environment option, or `development` when it isn't set.
|
|
452
|
+
|
|
453
|
+
**Returns** `Plugin`: The Vite plugin.
|
|
454
|
+
|
|
455
|
+
**Example**
|
|
456
|
+
|
|
457
|
+
```ts
|
|
458
|
+
// vite.config.ts
|
|
459
|
+
import { defineConfig } from 'vite';
|
|
460
|
+
import { serviceWorkerPlugin } from 'jg-sw/build';
|
|
461
|
+
|
|
462
|
+
export default defineConfig({
|
|
463
|
+
plugins: [serviceWorkerPlugin({ config: 'jg-sw.config.json', environment: 'production' })],
|
|
464
|
+
});
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
#### <a id="api-build-writeServiceWorker"></a>`writeServiceWorker`
|
|
468
|
+
|
|
469
|
+
*Function*
|
|
470
|
+
|
|
471
|
+
Generates the service worker and writes it to `sw.js` in the config's outDir, after the app's build has written its files there.
|
|
472
|
+
|
|
473
|
+
```ts
|
|
474
|
+
writeServiceWorker(
|
|
475
|
+
config: { outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "base" } | { outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "firebase-fcm"; firebaseConfigProcessEnvKey: string; firebaseSdkVersion: string },
|
|
476
|
+
options?: IBuildServiceWorkerOptions,
|
|
477
|
+
): Promise<string>
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
**Parameters**
|
|
481
|
+
|
|
482
|
+
- `config` `{ outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "base" } | { outDir: string; cacheNamePrefix: string; includeToPrecache: string[]; excludeFilesFromPrecache: string[]; excludeMIMETypesFromCache: string[]; template: "firebase-fcm"; firebaseConfigProcessEnvKey: string; firebaseSdkVersion: string }`: The service worker config, as read by readServiceWorkerConfig or written inline.
|
|
483
|
+
- `options?` `IBuildServiceWorkerOptions`: The environment the firebase-fcm template reads its Firebase config from, whether the worker caches (false for development), and the directory paths are resolved from. Defaults to `{}`.
|
|
484
|
+
|
|
485
|
+
**Returns** `Promise<string>`: A promise that resolves to the written file's path.
|
|
486
|
+
|
|
487
|
+
**Throws**
|
|
488
|
+
|
|
489
|
+
- `FAILED_TO_READ_BASE_CONFIG`: The service worker config is invalid.
|
|
490
|
+
- `INVALID_TEMPLATE_NAME`: The template must be 'base' or 'firebase-fcm'.
|
|
491
|
+
- `INVALID_FIREBASE_SDK_VERSION`: The Firebase SDK version must be a version such as 12.4.0.
|
|
492
|
+
- `INVALID_ENVIRONMENT`: The environment isn't supported, or the firebase-fcm template needs one.
|
|
493
|
+
- `NOT_A_PATH_ELEMENT`: An asset to precache is outside outDir, or isn't a file or a directory.
|
|
494
|
+
- `FAILED_TO_BUILD_CONFIG`: Unable to load the environment file.
|
|
495
|
+
- `INVALID_FIREBASE_CONFIG`: The environment variable that holds the Firebase config is missing or
|
|
496
|
+
- empty.
|
|
497
|
+
- `FAILED_TO_READ_FIREBASE_CONFIG`: Unable to read the Firebase config from the environment
|
|
498
|
+
- variable.
|
|
499
|
+
|
|
500
|
+
**Example**
|
|
501
|
+
|
|
502
|
+
```ts
|
|
503
|
+
import { readServiceWorkerConfig, writeServiceWorker } from 'jg-sw/build';
|
|
504
|
+
|
|
505
|
+
const config = await readServiceWorkerConfig('jg-sw.config.json');
|
|
506
|
+
await writeServiceWorker(config, { environment: 'production' }); // '/app/dist/sw.js'
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### <a id="api-build-constants"></a>Constants in `jg-sw/build`
|
|
510
|
+
|
|
511
|
+
#### <a id="api-build-ERRORS"></a>`ERRORS`
|
|
512
|
+
|
|
513
|
+
*Constant*
|
|
514
|
+
|
|
515
|
+
the codes for every error thrown by the build side
|
|
516
|
+
|
|
517
|
+
```ts
|
|
518
|
+
const ERRORS: { INVALID_TEMPLATE_NAME: "INVALID_TEMPLATE_NAME"; NOT_A_PATH_ELEMENT: "NOT_A_PATH_ELEMENT"; FAILED_TO_READ_BASE_CONFIG: "FAILED_TO_READ_BASE_CONFIG"; INVALID_FIREBASE_CONFIG: "INVALID_FIREBASE_CONFIG"; INVALID_ENVIRONMENT: "INVALID_ENVIRONMENT"; FAILED_TO_BUILD_CONFIG: "FAILED_TO_BUILD_CONFIG"; FAILED_TO_READ_FIREBASE_CONFIG: "FAILED_TO_READ_FIREBASE_CONFIG"; INVALID_FIREBASE_SDK_VERSION: "INVALID_FIREBASE_SDK_VERSION" }
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
#### <a id="api-build-ServiceWorkerConfigSchema"></a>`ServiceWorkerConfigSchema`
|
|
522
|
+
|
|
523
|
+
*Constant*
|
|
524
|
+
|
|
525
|
+
The schema of a service worker config: the `jg-sw.config.json` file the CLI reads, or the object passed to `buildServiceWorker`. `template` selects the worker: `base` caches the app, and `firebase-fcm` also shows Firebase Cloud Messaging notifications.
|
|
526
|
+
|
|
527
|
+
```ts
|
|
528
|
+
const ServiceWorkerConfigSchema: ZodDiscriminatedUnion<[ZodObject<{ outDir: ZodString; cacheNamePrefix: ZodString; includeToPrecache: ZodArray<ZodString>; excludeFilesFromPrecache: ZodArray<ZodString>; excludeMIMETypesFromCache: ZodArray<ZodString>; template: ZodLiteral<"base"> }, $strict>, ZodObject<{ outDir: ZodString; cacheNamePrefix: ZodString; includeToPrecache: ZodArray<ZodString>; excludeFilesFromPrecache: ZodArray<ZodString>; excludeMIMETypesFromCache: ZodArray<ZodString>; template: ZodLiteral<"firebase-fcm">; firebaseConfigProcessEnvKey: ZodString; firebaseSdkVersion: ZodString }, $strict>], "template">
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
**Example**
|
|
532
|
+
|
|
533
|
+
```ts
|
|
534
|
+
import { ServiceWorkerConfigSchema } from 'jg-sw/build';
|
|
535
|
+
|
|
536
|
+
const config = ServiceWorkerConfigSchema.parse({
|
|
537
|
+
outDir: 'dist',
|
|
538
|
+
cacheNamePrefix: 'my-app',
|
|
539
|
+
template: 'base',
|
|
540
|
+
includeToPrecache: ['/', '/index.html', '/assets'],
|
|
541
|
+
excludeFilesFromPrecache: [],
|
|
542
|
+
excludeMIMETypesFromCache: ['application/json'],
|
|
543
|
+
});
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### <a id="api-build-types"></a>Types in `jg-sw/build`
|
|
547
|
+
|
|
548
|
+
#### <a id="api-build-IBuildServiceWorkerOptions"></a>`IBuildServiceWorkerOptions`
|
|
549
|
+
|
|
550
|
+
*Type*
|
|
551
|
+
|
|
552
|
+
the options buildServiceWorker and writeServiceWorker accept
|
|
553
|
+
|
|
554
|
+
```ts
|
|
555
|
+
type IBuildServiceWorkerOptions = {
|
|
556
|
+
environment?: 'development' | 'staging' | 'production';
|
|
557
|
+
caching?: boolean;
|
|
558
|
+
cwd?: string;
|
|
559
|
+
};
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
**Members**
|
|
563
|
+
|
|
564
|
+
- `environment: "development" | "staging" | "production"` (property): the environment whose file the firebase-fcm template reads its Firebase config from: .env, .env.staging, or .env.production. The firebase-fcm template requires it
|
|
565
|
+
- `caching: boolean` (property): false leaves out precaching, cache cleanup, and the fetch handler, for development. Defaults to true
|
|
566
|
+
- `cwd: string` (property): the directory outDir and the environment files are resolved from. Defaults to process.cwd()
|
|
567
|
+
|
|
568
|
+
#### <a id="api-build-IServiceWorkerConfig"></a>`IServiceWorkerConfig`
|
|
569
|
+
|
|
570
|
+
*Type*
|
|
571
|
+
|
|
572
|
+
a service worker config, validated by ServiceWorkerConfigSchema
|
|
573
|
+
|
|
574
|
+
```ts
|
|
575
|
+
type IServiceWorkerConfig = z.infer<typeof ServiceWorkerConfigSchema>;
|
|
576
|
+
```
|
package/CHANGELOG.md
CHANGED
|
@@ -1,36 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.0
|
|
4
|
+
|
|
5
|
+
A fresh start: breaking changes in a minor version, once, because nothing depended on 1.0.x.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `ERRORS.SW_REGISTRATION_FAILED`, the code of a registration the browser rejects, with the browser's error as `cause`.
|
|
10
|
+
- `API.md`, the full API reference, generated from the TSDoc of the version it ships with, so it can be read from `node_modules` without a browser.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- `registrationError` in the snapshot is an `Exception` with one of the `ERRORS` codes, instead of an encoded message.
|
|
15
|
+
- Errors are `Exception`s from `jg-exception` 1.1.0: the code, the data, and the cause each have their own field, nothing is encoded into the message, and `toJSON()` and `toString()` follow `jg-exception`.
|
|
16
|
+
- Error messages say what failed at that step and keep the error underneath as `cause`, instead of repeating its message, so `extractMessage` prints each layer of the chain once.
|
|
17
|
+
|
|
18
|
+
## 1.0.1
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- Published by CI from `jesusgraterol/jg-packages`, with npm provenance. The code is the same as 1.0.0.
|
|
23
|
+
|
|
3
24
|
## 1.0.0
|
|
4
25
|
|
|
5
|
-
The first release
|
|
26
|
+
The first release.
|
|
6
27
|
|
|
7
28
|
### Added
|
|
8
29
|
|
|
9
|
-
- `registerServiceWorker`, `getServiceWorkerSnapshot`, `subscribeToServiceWorker`, `updateApp`, `canInstallApp`, and `installApp`,
|
|
30
|
+
- `registerServiceWorker`, `getServiceWorkerSnapshot`, `subscribeToServiceWorker`, `updateApp`, `canInstallApp`, and `installApp`, with `ERRORS` and the `REGISTRATION_DURATION_SECONDS`, `UPDATE_INSTALL_TIMEOUT_SECONDS`, `DEFAULT_SERVICE_WORKER_PATH`, `DEFAULT_SERVICE_WORKER_SCOPE`, and `SKIP_WAITING_MESSAGE_TYPE` constants.
|
|
10
31
|
- A snapshot whose identity changes only with the state, for `useSyncExternalStore`, with `hasWaitingWorker` and the installation state.
|
|
11
32
|
- `jg-sw/build`, with `buildServiceWorker`, `writeServiceWorker`, `readServiceWorkerConfig`, `ServiceWorkerConfigSchema`, and `ERRORS`, the codes of every error it throws.
|
|
12
33
|
- `serviceWorkerPlugin`, a Vite plugin that writes the worker after a build and serves it without caching in development.
|
|
13
34
|
- The `jg-sw` CLI, with `--config`, `--environment`, `--no-caching`, and `--help`.
|
|
14
|
-
-
|
|
15
|
-
- `caching: false` and `--no-caching`, which generate a worker without precaching, cache cleanup, or a fetch handler.
|
|
16
|
-
- The `INVALID_FIREBASE_SDK_VERSION` code.
|
|
17
|
-
|
|
18
|
-
### Changed
|
|
19
|
-
|
|
20
|
-
- `updateApp()` activates the waiting worker and reloads once it controls the page. Without one, it waits up to 30 seconds for a new worker to install, and reloads as it is when none installs.
|
|
21
|
-
- `registerServiceWorker()` resolves once the registration settles, never rejects, and returns the first call's promise on later calls.
|
|
22
|
-
- `installApp()` resolves to the prompt's outcome.
|
|
23
|
-
- The install prompt is tracked from the first `registerServiceWorker()` call, before the registration settles.
|
|
24
|
-
- Logs appear only with `debugMode`, and nothing touches `window` or `navigator` when the module loads.
|
|
25
|
-
- The worker never caches responses marked `Cache-Control: no-store` or `private`.
|
|
26
|
-
- The config file is named `jg-sw.config.json`, and the Firebase background hook `self.jgSwFcmBackgroundMessageHandler`.
|
|
27
|
-
- `firebaseSdkVersion` must be a version such as `12.4.0`. An invalid template fails with `INVALID_TEMPLATE_NAME`, and an unsupported environment with `INVALID_ENVIRONMENT`, whatever the template.
|
|
28
|
-
- Environment files load with Node.js's `process.loadEnvFile`.
|
|
29
|
-
- Precached paths are URL paths from `outDir`, with `#`, `?`, and `%` percent-encoded and each directory's files sorted. A path outside `outDir` fails with `NOT_A_PATH_ELEMENT`.
|
|
30
|
-
- Values written into the worker are serialized as JSON.
|
|
31
|
-
- Errors are `Exception`s from `jg-exception`.
|
|
32
|
-
|
|
33
|
-
### Removed
|
|
34
|
-
|
|
35
|
-
- The `SWService` object and its `ISWService`, `IAppInstallerService`, and `ISWRegistrationOptions` types.
|
|
36
|
-
- Running the CLI on import, and the `dotenv` and `argv-utils` dependencies.
|
|
35
|
+
- A generated worker that activates when the page posts the skip-waiting message, never caches responses marked `Cache-Control: no-store` or `private`, and can be generated without caching for development.
|