@swoff/cli 0.3.3 → 0.3.5
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 +23 -15
- package/dist/__tests__/assemble-sw.test.js +26 -11
- package/dist/__tests__/assemble-sw.test.js.map +1 -1
- package/dist/__tests__/cli-integration.test.js +11 -14
- package/dist/__tests__/cli-integration.test.js.map +1 -1
- package/dist/__tests__/config-types.test.js +19 -22
- package/dist/__tests__/config-types.test.js.map +1 -1
- package/dist/__tests__/file-generators.test.js +9 -97
- package/dist/__tests__/file-generators.test.js.map +1 -1
- package/dist/__tests__/loader.test.js +6 -6
- package/dist/__tests__/loader.test.js.map +1 -1
- package/dist/__tests__/validator.test.js +47 -38
- package/dist/__tests__/validator.test.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/cli/help.js +3 -3
- package/dist/lib/cli/help.js.map +1 -1
- package/dist/lib/commands/add.js +14 -5
- package/dist/lib/commands/add.js.map +1 -1
- package/dist/lib/commands/generate-guide.js +122 -0
- package/dist/lib/commands/generate-guide.js.map +1 -0
- package/dist/lib/commands/generate.js +7 -10
- package/dist/lib/commands/generate.js.map +1 -1
- package/dist/lib/commands/info.js +10 -4
- package/dist/lib/commands/info.js.map +1 -1
- package/dist/lib/commands/init.js +6 -12
- package/dist/lib/commands/init.js.map +1 -1
- package/dist/lib/commands/validate.js +8 -2
- package/dist/lib/commands/validate.js.map +1 -1
- package/dist/lib/config/validator.js +52 -51
- package/dist/lib/config/validator.js.map +1 -1
- package/dist/lib/generators/file-generators/auth-fetch.js +156 -0
- package/dist/lib/generators/file-generators/auth-fetch.js.map +1 -0
- package/dist/lib/generators/file-generators/auth-state.js +38 -0
- package/dist/lib/generators/file-generators/auth-state.js.map +1 -0
- package/dist/lib/generators/file-generators/auth-store.js +127 -0
- package/dist/lib/generators/file-generators/auth-store.js.map +1 -0
- package/dist/lib/generators/file-generators/auth-user.js +95 -0
- package/dist/lib/generators/file-generators/auth-user.js.map +1 -0
- package/dist/lib/generators/file-generators/context.js.map +1 -1
- package/dist/lib/generators/file-generators/generate-hooks.js +167 -0
- package/dist/lib/generators/file-generators/generate-hooks.js.map +1 -0
- package/dist/lib/generators/file-generators/mutation-queue.js +27 -5
- package/dist/lib/generators/file-generators/mutation-queue.js.map +1 -1
- package/dist/lib/generators/file-generators/store.js +1 -1
- package/dist/lib/generators/file-generators/store.js.map +1 -1
- package/dist/lib/generators/file-generators/sw-generator-build.js +1 -1
- package/dist/lib/generators/file-generators/sw-injector.js +5 -2
- package/dist/lib/generators/file-generators/sw-injector.js.map +1 -1
- package/dist/lib/generators/file-generators/type-definitions.js +4 -1
- package/dist/lib/generators/file-generators/type-definitions.js.map +1 -1
- package/dist/lib/generators/sw-sections/assemble-sw.js +6 -4
- package/dist/lib/generators/sw-sections/assemble-sw.js.map +1 -1
- package/dist/lib/generators/sw-sections/background-sync-handler.js +9 -6
- package/dist/lib/generators/sw-sections/background-sync-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/config-header.js +2 -2
- package/dist/lib/generators/sw-sections/config-header.js.map +1 -1
- package/dist/lib/generators/sw-sections/message-handler.js +12 -2
- package/dist/lib/generators/sw-sections/message-handler.js.map +1 -1
- package/dist/lib/generators/swoff-files-generator.js +11 -2
- package/dist/lib/generators/swoff-files-generator.js.map +1 -1
- package/dist/lib/shared/config-types.js +34 -24
- package/dist/lib/shared/config-types.js.map +1 -1
- package/dist/lib/utils/detect-framework.js +33 -0
- package/dist/lib/utils/detect-framework.js.map +1 -0
- package/package.json +2 -3
- package/src/lib/templates/sw-template.js +0 -61
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates auth-user.ts/js — fetch, cache, and invalidate current user.
|
|
3
|
+
*/
|
|
4
|
+
import { writeFile } from "./context.js";
|
|
5
|
+
export function generateAuthUser(ctx) {
|
|
6
|
+
const ext = ctx.ext;
|
|
7
|
+
const userEndpoint = ctx.config.features.auth.userEndpoint;
|
|
8
|
+
const code = `/**
|
|
9
|
+
* Current User — fetch, cache, and invalidate the current user for offline access.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* import { fetchCurrentUser, cacheUser, getCachedUser, clearCachedUser } from "./auth-user.${ext}";
|
|
13
|
+
*
|
|
14
|
+
* await fetchCurrentUser(); // Fetch from server & cache
|
|
15
|
+
* const user = await getCachedUser(); // Get cached (offline-capable)
|
|
16
|
+
* await clearCachedUser(); // Clear on logout
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { authenticatedFetch } from "./auth-fetch.${ext}";
|
|
20
|
+
|
|
21
|
+
const DB_NAME = "swoff-auth-user";
|
|
22
|
+
const STORE_NAME = "current-user";
|
|
23
|
+
|
|
24
|
+
function openAuthDB() {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
const request = indexedDB.open(DB_NAME, 1);
|
|
27
|
+
request.onupgradeneeded = (e) => {
|
|
28
|
+
const db = e.target.result;
|
|
29
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
30
|
+
db.createObjectStore(STORE_NAME, { keyPath: "key" });
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
request.onsuccess = (e) => resolve(e.target.result);
|
|
34
|
+
request.onerror = (e) => reject(e.target.error);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Fetch current user from your backend and cache locally.
|
|
40
|
+
* Uses userEndpoint from swoff.config.json.
|
|
41
|
+
*/
|
|
42
|
+
export async function fetchCurrentUser() {
|
|
43
|
+
const response = await authenticatedFetch("${userEndpoint}");
|
|
44
|
+
if (!response.ok) throw new Error("Failed to fetch user");
|
|
45
|
+
|
|
46
|
+
const user = await response.json();
|
|
47
|
+
await cacheUser(user);
|
|
48
|
+
return user;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Store user in IndexedDB for offline access.
|
|
53
|
+
*/
|
|
54
|
+
export async function cacheUser(user) {
|
|
55
|
+
const db = await openAuthDB();
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
58
|
+
const store = tx.objectStore(STORE_NAME);
|
|
59
|
+
store.put({ key: "user", value: user });
|
|
60
|
+
tx.oncomplete = () => resolve();
|
|
61
|
+
tx.onerror = () => reject(tx.error);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get cached user — works offline.
|
|
67
|
+
*/
|
|
68
|
+
export async function getCachedUser() {
|
|
69
|
+
const db = await openAuthDB();
|
|
70
|
+
return new Promise((resolve, reject) => {
|
|
71
|
+
const tx = db.transaction(STORE_NAME, "readonly");
|
|
72
|
+
const store = tx.objectStore(STORE_NAME);
|
|
73
|
+
const request = store.get("user");
|
|
74
|
+
request.onsuccess = () => resolve(request.result?.value || null);
|
|
75
|
+
request.onerror = () => reject(request.error);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Clear cached user on logout.
|
|
81
|
+
*/
|
|
82
|
+
export async function clearCachedUser() {
|
|
83
|
+
const db = await openAuthDB();
|
|
84
|
+
return new Promise((resolve, reject) => {
|
|
85
|
+
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
86
|
+
const store = tx.objectStore(STORE_NAME);
|
|
87
|
+
store.delete("user");
|
|
88
|
+
tx.oncomplete = () => resolve();
|
|
89
|
+
tx.onerror = () => reject(tx.error);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
`;
|
|
93
|
+
writeFile(ctx, `auth-user.${ext}`, code);
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=auth-user.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-user.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/auth-user.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,gBAAgB,CAAC,GAAqB;IACpD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC;IAE3D,MAAM,IAAI,GAAG;;;;gGAIiF,GAAG;;;;;;;mDAOhD,GAAG;;;;;;;;;;;;;;;;;;;;;;;;+CAwBP,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiD1D,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAY5B,MAAM,UAAU,cAAc,CAAC,GAAqB;IAClD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAqB,EAAE,QAAgB,EAAE,IAAY;IAC7E,cAAc,CAAC,GAAG,CAAC,CAAC;IACpB,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;IAClD,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,QAAQ,EAAE,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { writeFileSync, existsSync, mkdirSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
export function generateHooks(ctx) {
|
|
4
|
+
const { config, swoffDir, ext, frameworkName } = ctx;
|
|
5
|
+
if (frameworkName !== "react")
|
|
6
|
+
return;
|
|
7
|
+
const hooksDir = join(swoffDir, "hooks");
|
|
8
|
+
if (!existsSync(hooksDir)) {
|
|
9
|
+
mkdirSync(hooksDir, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
if (config.features.pwa.enabled) {
|
|
12
|
+
writePWAHooks(hooksDir, ext);
|
|
13
|
+
}
|
|
14
|
+
if (config.features.auth.enabled) {
|
|
15
|
+
writeAuthHook(hooksDir, ext);
|
|
16
|
+
}
|
|
17
|
+
if (config.features.mutationQueue) {
|
|
18
|
+
writeMutationQueueHook(hooksDir, ext);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function writePWAHooks(dir, ext) {
|
|
22
|
+
writeFileSync(join(dir, `usePWAUpdate.${ext}x`), `import { useState, useEffect, useCallback } from "react";
|
|
23
|
+
|
|
24
|
+
export function usePWAUpdate() {
|
|
25
|
+
const [state, setState] = useState({
|
|
26
|
+
updateStatus: "idle",
|
|
27
|
+
currentVersion: null as string | null,
|
|
28
|
+
availableVersion: null as string | null,
|
|
29
|
+
progress: 0,
|
|
30
|
+
forceUpdate: false,
|
|
31
|
+
error: null as string | null,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
setState((s) => ({ ...s, currentVersion: (window as any).currentSWVersion || null }));
|
|
36
|
+
|
|
37
|
+
const onAvailable = (e: CustomEvent) => setState((s) => ({
|
|
38
|
+
...s,
|
|
39
|
+
updateStatus: "available" as const,
|
|
40
|
+
availableVersion: e.detail.version,
|
|
41
|
+
forceUpdate: (window as any).swUpdateRequired || false,
|
|
42
|
+
}));
|
|
43
|
+
const onProgress = (e: CustomEvent) => setState((s) => ({
|
|
44
|
+
...s,
|
|
45
|
+
updateStatus: "downloading" as const,
|
|
46
|
+
progress: e.detail.percent,
|
|
47
|
+
}));
|
|
48
|
+
const onReady = () => setState((s) => ({ ...s, updateStatus: "idle" as const, progress: 0 }));
|
|
49
|
+
const onError = () => setState((s) => ({ ...s, error: "SW registration failed" }));
|
|
50
|
+
|
|
51
|
+
window.addEventListener("sw-update-available", onAvailable as EventListener);
|
|
52
|
+
window.addEventListener("sw-progress", onProgress as EventListener);
|
|
53
|
+
window.addEventListener("sw-ready", onReady);
|
|
54
|
+
window.addEventListener("sw-error", onError);
|
|
55
|
+
return () => {
|
|
56
|
+
window.removeEventListener("sw-update-available", onAvailable as EventListener);
|
|
57
|
+
window.removeEventListener("sw-progress", onProgress as EventListener);
|
|
58
|
+
window.removeEventListener("sw-ready", onReady);
|
|
59
|
+
window.removeEventListener("sw-error", onError);
|
|
60
|
+
};
|
|
61
|
+
}, []);
|
|
62
|
+
|
|
63
|
+
const acceptUpdate = useCallback(async () => {
|
|
64
|
+
if (!state.availableVersion) return;
|
|
65
|
+
const { handleUpdateApproved } = await import("../sw-injector.${ext}");
|
|
66
|
+
await handleUpdateApproved(state.availableVersion);
|
|
67
|
+
}, [state.availableVersion]);
|
|
68
|
+
|
|
69
|
+
const dismissUpdate = useCallback(() => {
|
|
70
|
+
sessionStorage.setItem("sw-dismissed-update", "true");
|
|
71
|
+
setState((s) => ({ ...s, updateStatus: "idle" }));
|
|
72
|
+
}, []);
|
|
73
|
+
|
|
74
|
+
return { ...state, acceptUpdate, dismissUpdate };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function useSWProgress() {
|
|
78
|
+
const [state, setState] = useState({
|
|
79
|
+
status: "idle" as "idle" | "installing",
|
|
80
|
+
progress: 0,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
const onProgress = (e: CustomEvent) => setState({
|
|
85
|
+
status: "installing",
|
|
86
|
+
progress: e.detail.percent,
|
|
87
|
+
});
|
|
88
|
+
const onReady = () => setState({ status: "idle", progress: 0 });
|
|
89
|
+
|
|
90
|
+
window.addEventListener("sw-progress", onProgress as EventListener);
|
|
91
|
+
window.addEventListener("sw-ready", onReady);
|
|
92
|
+
return () => {
|
|
93
|
+
window.removeEventListener("sw-progress", onProgress as EventListener);
|
|
94
|
+
window.removeEventListener("sw-ready", onReady);
|
|
95
|
+
};
|
|
96
|
+
}, []);
|
|
97
|
+
|
|
98
|
+
return state;
|
|
99
|
+
}
|
|
100
|
+
`);
|
|
101
|
+
// useSWProgress is included in the same file
|
|
102
|
+
}
|
|
103
|
+
function writeAuthHook(dir, ext) {
|
|
104
|
+
writeFileSync(join(dir, `useAuth.${ext}x`), `import { useState, useEffect } from "react";
|
|
105
|
+
import { getAuthState } from "../auth-state.${ext}";
|
|
106
|
+
|
|
107
|
+
export function useAuth() {
|
|
108
|
+
const [state, setState] = useState({
|
|
109
|
+
authenticated: false,
|
|
110
|
+
user: null as Record<string, unknown> | null,
|
|
111
|
+
online: navigator.onLine,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
getAuthState().then(setState);
|
|
116
|
+
|
|
117
|
+
const onOnline = () => setState((s) => ({ ...s, online: true }));
|
|
118
|
+
const onOffline = () => setState((s) => ({ ...s, online: false }));
|
|
119
|
+
const onAuthChange = () => getAuthState().then(setState);
|
|
120
|
+
|
|
121
|
+
window.addEventListener("online", onOnline);
|
|
122
|
+
window.addEventListener("offline", onOffline);
|
|
123
|
+
window.addEventListener("sw-auth-state-change", onAuthChange);
|
|
124
|
+
|
|
125
|
+
return () => {
|
|
126
|
+
window.removeEventListener("online", onOnline);
|
|
127
|
+
window.removeEventListener("offline", onOffline);
|
|
128
|
+
window.removeEventListener("sw-auth-state-change", onAuthChange);
|
|
129
|
+
};
|
|
130
|
+
}, []);
|
|
131
|
+
|
|
132
|
+
return state;
|
|
133
|
+
}
|
|
134
|
+
`);
|
|
135
|
+
}
|
|
136
|
+
function writeMutationQueueHook(dir, ext) {
|
|
137
|
+
writeFileSync(join(dir, `useMutationQueue.${ext}x`), `import { useState, useEffect } from "react";
|
|
138
|
+
import { getPendingCount } from "../mutation-queue.${ext}";
|
|
139
|
+
|
|
140
|
+
export function useMutationQueue() {
|
|
141
|
+
const [state, setState] = useState<{
|
|
142
|
+
pending: number;
|
|
143
|
+
lastSync: { succeeded: number; failed: number } | null;
|
|
144
|
+
}>({ pending: 0, lastSync: null });
|
|
145
|
+
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
getPendingCount().then((count: number) => setState((s) => ({ ...s, pending: count })));
|
|
148
|
+
|
|
149
|
+
const onSync = (e: CustomEvent) => setState({
|
|
150
|
+
pending: 0,
|
|
151
|
+
lastSync: { succeeded: e.detail.succeeded, failed: e.detail.failed },
|
|
152
|
+
});
|
|
153
|
+
const onChange = async () => setState((s) => ({ ...s, pending: await getPendingCount() }));
|
|
154
|
+
|
|
155
|
+
window.addEventListener("mutation-sync-complete", onSync as EventListener);
|
|
156
|
+
window.addEventListener("mutation-queue-changed", onChange);
|
|
157
|
+
return () => {
|
|
158
|
+
window.removeEventListener("mutation-sync-complete", onSync as EventListener);
|
|
159
|
+
window.removeEventListener("mutation-queue-changed", onChange);
|
|
160
|
+
};
|
|
161
|
+
}, []);
|
|
162
|
+
|
|
163
|
+
return state;
|
|
164
|
+
}
|
|
165
|
+
`);
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=generate-hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-hooks.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/generate-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,MAAM,UAAU,aAAa,CAAC,GAAqB;IACjD,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC;IACrD,IAAI,aAAa,KAAK,OAAO;QAAE,OAAO;IAEtC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAChC,aAAa,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,aAAa,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;QAClC,sBAAsB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,GAAW,EAAE,GAAW;IAC7C,aAAa,CACX,IAAI,CAAC,GAAG,EAAE,gBAAgB,GAAG,GAAG,CAAC,EACjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEA2CgE,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCtE,CACE,CAAC;IAEF,6CAA6C;AAC/C,CAAC;AAED,SAAS,aAAa,CAAC,GAAW,EAAE,GAAW;IAC7C,aAAa,CACX,IAAI,CAAC,GAAG,EAAE,WAAW,GAAG,GAAG,CAAC,EAC5B;8CAC0C,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BhD,CACE,CAAC;AACJ,CAAC;AAED,SAAS,sBAAsB,CAAC,GAAW,EAAE,GAAW;IACtD,aAAa,CACX,IAAI,CAAC,GAAG,EAAE,oBAAoB,GAAG,GAAG,CAAC,EACrC;qDACiD,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BvD,CACE,CAAC;AACJ,CAAC"}
|
|
@@ -4,12 +4,25 @@
|
|
|
4
4
|
import { writeFile } from "./context.js";
|
|
5
5
|
export function generateMutationQueue(ctx) {
|
|
6
6
|
const ext = ctx.ext;
|
|
7
|
+
const authEnabled = ctx.config.features.auth.enabled;
|
|
8
|
+
const importLines = authEnabled
|
|
9
|
+
? `import { getAuth } from "./auth-store.${ext}";
|
|
10
|
+
`
|
|
11
|
+
: "";
|
|
12
|
+
const authReplayBlock = authEnabled
|
|
13
|
+
? ` const auth = await getAuth();
|
|
14
|
+
const authHeader = auth?.token ? { Authorization: \`Bearer \${auth.token}\` } : {};
|
|
15
|
+
`
|
|
16
|
+
: "";
|
|
17
|
+
const authHeadersSpread = authEnabled
|
|
18
|
+
? ` ...authHeader,`
|
|
19
|
+
: "";
|
|
7
20
|
const code = `/**
|
|
8
21
|
* Swoff Mutation Queue
|
|
9
22
|
* Queue offline writes and sync when connection returns.
|
|
10
23
|
*
|
|
11
24
|
* Usage:
|
|
12
|
-
* import { queueMutation, processMutationQueue, getPendingCount } from './swoff/mutation-queue.${ext}';
|
|
25
|
+
* import { queueMutation, processMutationQueue, flushMutations, getPendingCount } from './swoff/mutation-queue.${ext}';
|
|
13
26
|
*
|
|
14
27
|
* // Queue a mutation
|
|
15
28
|
* await queueMutation({
|
|
@@ -21,10 +34,13 @@ export function generateMutationQueue(ctx) {
|
|
|
21
34
|
* tempId: "temp_abc123",
|
|
22
35
|
* });
|
|
23
36
|
*
|
|
37
|
+
* // Flush queued mutations (e.g., after login)
|
|
38
|
+
* await flushMutations();
|
|
39
|
+
*
|
|
24
40
|
* // Auto-processes on online event
|
|
25
41
|
*/
|
|
26
42
|
|
|
27
|
-
const DB_NAME = "swoff-queue";
|
|
43
|
+
${importLines}const DB_NAME = "swoff-queue";
|
|
28
44
|
const STORE_NAME = "mutations";
|
|
29
45
|
const MAX_RETRIES = 5;
|
|
30
46
|
|
|
@@ -77,7 +93,7 @@ export async function processMutationQueue() {
|
|
|
77
93
|
isSyncing = true;
|
|
78
94
|
|
|
79
95
|
try {
|
|
80
|
-
const db = await openQueueDB();
|
|
96
|
+
${authReplayBlock} const db = await openQueueDB();
|
|
81
97
|
const tx = db.transaction(STORE_NAME, "readonly");
|
|
82
98
|
const store = tx.objectStore(STORE_NAME);
|
|
83
99
|
const index = store.index("by-timestamp");
|
|
@@ -103,7 +119,7 @@ export async function processMutationQueue() {
|
|
|
103
119
|
method: item.method,
|
|
104
120
|
headers: {
|
|
105
121
|
"Content-Type": "application/json",
|
|
106
|
-
...item.headers,
|
|
122
|
+
${authHeadersSpread} ...item.headers,
|
|
107
123
|
},
|
|
108
124
|
body: JSON.stringify(item.body),
|
|
109
125
|
});
|
|
@@ -141,6 +157,12 @@ export async function processMutationQueue() {
|
|
|
141
157
|
}
|
|
142
158
|
}
|
|
143
159
|
|
|
160
|
+
export async function flushMutations() {
|
|
161
|
+
await processMutationQueue();
|
|
162
|
+
}
|
|
163
|
+
`;
|
|
164
|
+
// Helper functions (unchanged) are appended outside the template string
|
|
165
|
+
const helpers = `
|
|
144
166
|
async function removeFromQueue(id) {
|
|
145
167
|
const db = await openQueueDB();
|
|
146
168
|
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
@@ -220,6 +242,6 @@ export async function getPendingCount() {
|
|
|
220
242
|
});
|
|
221
243
|
}
|
|
222
244
|
`;
|
|
223
|
-
writeFile(ctx, `mutation-queue.${ext}`, code);
|
|
245
|
+
writeFile(ctx, `mutation-queue.${ext}`, code + helpers);
|
|
224
246
|
}
|
|
225
247
|
//# sourceMappingURL=mutation-queue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutation-queue.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/mutation-queue.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,qBAAqB,CAAC,GAAqB;IACzD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,IAAI,GAAG;;;;;
|
|
1
|
+
{"version":3,"file":"mutation-queue.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/mutation-queue.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,qBAAqB,CAAC,GAAqB;IACzD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;IAErD,MAAM,WAAW,GAAG,WAAW;QAC7B,CAAC,CAAC,yCAAyC,GAAG;CACjD;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,eAAe,GAAG,WAAW;QACjC,CAAC,CAAC;;CAEL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,iBAAiB,GAAG,WAAW;QACnC,CAAC,CAAC,4BAA4B;QAC9B,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,IAAI,GAAG;;;;;oHAKqG,GAAG;;;;;;;;;;;;;;;;;;EAkBrH,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqDX,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;EA0Bf,iBAAiB;;;;;;;;;;;;;;+DAc4C,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BjE,CAAC;IAEA,wEAAwE;IACxE,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;qDAyBmC,GAAG;;;;;;kDAMN,GAAG;;;kDAGH,GAAG;;;;;;;;;;;;;;;;;yEAiBoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4B3E,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,kBAAkB,GAAG,EAAE,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC;AAC1D,CAAC"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { writeFile } from "./context.js";
|
|
5
5
|
export function generateStore(ctx) {
|
|
6
6
|
const ext = ctx.ext;
|
|
7
|
-
const dbName =
|
|
7
|
+
const dbName = "app-db";
|
|
8
8
|
const code = `/**
|
|
9
9
|
* Swoff IndexedDB Store
|
|
10
10
|
* Generic CRUD operations for app's IndexedDB database.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,aAAa,CAAC,GAAqB;IACjD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,aAAa,CAAC,GAAqB;IACjD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,MAAM,GAAG,QAAQ,CAAC;IAExB,MAAM,IAAI,GAAG;;;;;oFAKqE,GAAG;;;;;;;mBAOpE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDxB,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -72,7 +72,7 @@ const assetsToCache = combined.map(url => ({ url, options: {} }));
|
|
|
72
72
|
let sw = template;
|
|
73
73
|
sw = sw.replace('// [[CACHE_NAME]]', \`CACHE_NAME = 'sw-v\${version}'\`);
|
|
74
74
|
sw = sw.replace('// [[ASSETS_LIST]]', \`ASSETS_TO_CACHE = \${JSON.stringify(assetsToCache, null, 2)}\`);
|
|
75
|
-
sw = sw.replace('// [[AUTO_SKIP_WAITING]]', \`const AUTO_SKIP_WAITING = \${config.serviceWorker?.autoActivate || false};\`);
|
|
75
|
+
sw = sw.replace('// [[AUTO_SKIP_WAITING]]', \`const AUTO_SKIP_WAITING = \${config.features?.serviceWorker?.autoActivate || false};\`);
|
|
76
76
|
|
|
77
77
|
writeFileSync(join(outDir, swFile), sw);
|
|
78
78
|
writeFileSync(join(outDir, 'version.json'), JSON.stringify({
|
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { writeFile } from "./context.js";
|
|
5
5
|
export function generateSwInjector(ctx) {
|
|
6
|
-
const autoRegister = ctx.config.serviceWorker.autoRegister;
|
|
7
|
-
const autoActivate = ctx.config.serviceWorker.autoActivate;
|
|
6
|
+
const autoRegister = ctx.config.features.serviceWorker.autoRegister;
|
|
7
|
+
const autoActivate = ctx.config.features.serviceWorker.autoActivate;
|
|
8
8
|
const pwaEnabled = ctx.config.features.pwa.enabled;
|
|
9
9
|
const preventDefaultInstall = ctx.config.features.pwa.preventDefaultInstall;
|
|
10
10
|
const crossTabSync = ctx.config.features.crossTabSync;
|
|
11
11
|
const ext = ctx.ext;
|
|
12
12
|
const mutationQueueEnabled = ctx.config.features.mutationQueue;
|
|
13
|
+
const authEnabled = ctx.config.features.auth.enabled;
|
|
13
14
|
const code = `/**
|
|
14
15
|
* Swoff SW Injector
|
|
15
16
|
* Framework-agnostic SW registration, PWA install support, and cross-tab sync.
|
|
@@ -32,6 +33,8 @@ export function generateSwInjector(ctx) {
|
|
|
32
33
|
* mutation-sync-complete - Queued mutations synced (detail: { succeeded, failed })
|
|
33
34
|
* mutation-queue-changed - Queue modified
|
|
34
35
|
* mutation-rollback - Mutation exhausted retries (detail: { method, url, tempId, previousData })
|
|
36
|
+
* sw-auth-unauthorized - 401 response received (token expired or invalid)${authEnabled ? `
|
|
37
|
+
* sw-auth-state-change - Login or logout (detail: { authenticated: boolean })` : ""}
|
|
35
38
|
*
|
|
36
39
|
* Window properties:
|
|
37
40
|
* window.latestSWVersion - Latest version from version.json
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sw-injector.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/sw-injector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,kBAAkB,CAAC,GAAqB;IACtD,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"sw-injector.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/sw-injector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,kBAAkB,CAAC,GAAqB;IACtD,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC;IACpE,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC;IACpE,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC;IACnD,MAAM,qBAAqB,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,qBAAqB,CAAC;IAC5E,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC;IACtD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IAEpB,MAAM,oBAAoB,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC;IAE/D,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;IAErD,MAAM,IAAI,GAAG;;;;;8DAK+C,GAAG;;;;;;;;;;;;;;;;;+EAiBc,WAAW,CAAC,CAAC,CAAC;kFACX,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;EAarF,oBAAoB,CAAC,CAAC,CAAC,0DAA0D,GAAG;CACrF,CAAC,CAAC,CAAC,EAAE;wBACkB,YAAY;wBACZ,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgJlC,UAAU,CAAC,CAAC,CAAC;;;;;QAKP,qBAAqB;;;;;;;;;;;;;;;;;;;;;CAqB5B,CAAC,CAAC,CAAC,EAAE;EACJ,oBAAoB,CAAC,CAAC,CAAC;;;CAGxB,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BJ,YAAY,CAAC,CAAC,CAAC;;;;;;;;CAQhB,CAAC,CAAC,CAAC,EAAE;;CAEL,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,eAAe,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -5,6 +5,9 @@ import { writeFile } from "./context.js";
|
|
|
5
5
|
export function generateTypeDefinitions(ctx) {
|
|
6
6
|
if (ctx.ext !== "ts")
|
|
7
7
|
return;
|
|
8
|
+
const authBlock = ctx.config.features.auth.enabled ? `
|
|
9
|
+
swAuthState?: "authenticated" | "unauthenticated" | "loading";
|
|
10
|
+
swCurrentUser?: object | null;` : "";
|
|
8
11
|
const code = `interface BeforeInstallPromptEvent extends Event {
|
|
9
12
|
prompt(): Promise<void>;
|
|
10
13
|
userChoice: Promise<{ outcome: "accepted" | "dismissed" }>;
|
|
@@ -20,7 +23,7 @@ declare global {
|
|
|
20
23
|
swUpdateRequired?: boolean;
|
|
21
24
|
swMinSupportedVersion?: string;
|
|
22
25
|
swReady?: boolean;
|
|
23
|
-
swError?: boolean
|
|
26
|
+
swError?: boolean;${authBlock}
|
|
24
27
|
}
|
|
25
28
|
}
|
|
26
29
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type-definitions.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/type-definitions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,uBAAuB,CAAC,GAAqB;IAC3D,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI;QAAE,OAAO;IAE7B,MAAM,IAAI,GAAG
|
|
1
|
+
{"version":3,"file":"type-definitions.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/type-definitions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,uBAAuB,CAAC,GAAqB;IAC3D,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI;QAAE,OAAO;IAE7B,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;;mCAEpB,CAAC,CAAC,CAAC,EAAE,CAAC;IAEvC,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;wBAeS,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2ChC,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -29,7 +29,8 @@ function collectAssets(dir, baseDir) {
|
|
|
29
29
|
return assets;
|
|
30
30
|
}
|
|
31
31
|
export function assembleSW(config, version, projectRoot) {
|
|
32
|
-
const { serviceWorker
|
|
32
|
+
const { serviceWorker } = config.features;
|
|
33
|
+
const { features } = config;
|
|
33
34
|
const outputDir = config.build?.outputDir || "dist";
|
|
34
35
|
const swFilename = config.build?.swFilename || "sw";
|
|
35
36
|
const fallback = ["/index.html"];
|
|
@@ -49,11 +50,11 @@ export function assembleSW(config, version, projectRoot) {
|
|
|
49
50
|
let sw = getDefaultTemplate();
|
|
50
51
|
sw = sw.replace("// [[CACHE_NAME]]", `CACHE_NAME = 'sw-v${version}'`);
|
|
51
52
|
sw = sw.replace("// [[ASSETS_LIST]]", `ASSETS_TO_CACHE = ${JSON.stringify(assetsToCache.map((url) => ({ url, options: {} })), null, 2)}`);
|
|
52
|
-
sw = sw.replace("// [[AUTO_SKIP_WAITING]]", `const AUTO_SKIP_WAITING = ${
|
|
53
|
+
sw = sw.replace("// [[AUTO_SKIP_WAITING]]", `const AUTO_SKIP_WAITING = ${serviceWorker.autoActivate};`);
|
|
53
54
|
sw = sw.replace("// [[FETCH_HANDLER]]", generateFetchHandler(serviceWorker, features.tagInvalidation));
|
|
54
55
|
sw = sw.replace("// [[ACTIVATE_HANDLER]]", generateActivateHandler(serviceWorker.clearRuntimeOnUpdate));
|
|
55
56
|
sw = sw.replace("// [[INSTALL_HANDLER]]", generateInstallHandler());
|
|
56
|
-
sw = sw.replace("// [[MESSAGE_HANDLER]]", generateMessageHandler(features.tagInvalidation));
|
|
57
|
+
sw = sw.replace("// [[MESSAGE_HANDLER]]", generateMessageHandler(features.tagInvalidation, features.auth.enabled));
|
|
57
58
|
if (features.tagInvalidation) {
|
|
58
59
|
sw = sw.replace("// [[TAG_MANAGEMENT]]", generateTagManagement());
|
|
59
60
|
}
|
|
@@ -62,7 +63,8 @@ export function assembleSW(config, version, projectRoot) {
|
|
|
62
63
|
}
|
|
63
64
|
sw = `${generateConfigHeader(config, version)}\n\n${sw}`;
|
|
64
65
|
if (features.backgroundSync) {
|
|
65
|
-
|
|
66
|
+
const authType = features.auth.enabled ? features.auth.type : undefined;
|
|
67
|
+
sw += `\n\n${generateBackgroundSyncHandler(authType)}`;
|
|
66
68
|
}
|
|
67
69
|
return sw;
|
|
68
70
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assemble-sw.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/assemble-sw.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAE7E,SAAS,aAAa,CAAC,GAAW,EAAE,OAAe;IACjD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEhC,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;QACnD,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAmB,EAAE,OAAe,EAAE,WAAoB;IACnF,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"assemble-sw.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/assemble-sw.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
* Generates Background Sync event handler for the SW.
|
|
3
3
|
* Processes mutation queue when browser sync fires.
|
|
4
4
|
*/
|
|
5
|
-
export function generateBackgroundSyncHandler() {
|
|
5
|
+
export function generateBackgroundSyncHandler(authType) {
|
|
6
|
+
const credentialsLine = authType === "cookie"
|
|
7
|
+
? ` credentials: "same-origin",`
|
|
8
|
+
: "";
|
|
6
9
|
return `
|
|
7
10
|
self.addEventListener("sync", (event) => {
|
|
8
11
|
if (event.tag === "sync-mutations") {
|
|
@@ -10,11 +13,11 @@ self.addEventListener("sync", (event) => {
|
|
|
10
13
|
}
|
|
11
14
|
});
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const SW_MAX_RETRIES = 5;
|
|
16
|
+
const SW_DB_NAME = "swoff-queue";
|
|
17
|
+
const SW_STORE_NAME = "mutations";
|
|
18
|
+
const SW_MAX_RETRIES = 5;
|
|
17
19
|
|
|
20
|
+
async function processMutationQueueInSW() {
|
|
18
21
|
let succeeded = 0;
|
|
19
22
|
let failed = 0;
|
|
20
23
|
const tagsToInvalidate = new Set();
|
|
@@ -53,7 +56,7 @@ async function processMutationQueueInSW() {
|
|
|
53
56
|
method: item.method,
|
|
54
57
|
headers: { "Content-Type": "application/json", ...item.headers },
|
|
55
58
|
body: JSON.stringify(item.body),
|
|
56
|
-
});
|
|
59
|
+
${credentialsLine} });
|
|
57
60
|
if (!response.ok) throw new Error(\`HTTP \${response.status}\`);
|
|
58
61
|
|
|
59
62
|
if (item.tags) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"background-sync-handler.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/background-sync-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,UAAU,6BAA6B;
|
|
1
|
+
{"version":3,"file":"background-sync-handler.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/background-sync-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,UAAU,6BAA6B,CAAC,QAAiB;IAC7D,MAAM,eAAe,GAAG,QAAQ,KAAK,QAAQ;QAC3C,CAAC,CAAC,uCAAuC;QACzC,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkDP,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgDf,CAAC;AACH,CAAC"}
|
|
@@ -7,8 +7,8 @@ export function generateConfigHeader(config, resolvedVersion) {
|
|
|
7
7
|
* Generated from swoff.config.json
|
|
8
8
|
* DO NOT EDIT MANUALLY
|
|
9
9
|
* Version: ${resolvedVersion}
|
|
10
|
-
* Features: versionedSw=${config.features.versionedSw}, mutationQueue=${config.features.mutationQueue}, backgroundSync=${config.features.backgroundSync}, tagInvalidation=${config.features.tagInvalidation}
|
|
11
|
-
* Default Strategy: ${config.serviceWorker.defaultStrategy}
|
|
10
|
+
* Features: versionedSw=${config.features.serviceWorker.versionedSw}, mutationQueue=${config.features.mutationQueue}, backgroundSync=${config.features.backgroundSync}, tagInvalidation=${config.features.tagInvalidation}
|
|
11
|
+
* Default Strategy: ${config.features.serviceWorker.defaultStrategy}
|
|
12
12
|
* See: https://swoff.netlify.app/docs
|
|
13
13
|
*/`;
|
|
14
14
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-header.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/config-header.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,UAAU,oBAAoB,CAAC,MAAmB,EAAE,eAAuB;IAC/E,OAAO;;;;cAIK,eAAe;2BACF,MAAM,CAAC,QAAQ,CAAC,WAAW,mBAAmB,MAAM,CAAC,QAAQ,CAAC,aAAa,oBAAoB,MAAM,CAAC,QAAQ,CAAC,cAAc,qBAAqB,MAAM,CAAC,QAAQ,CAAC,eAAe;
|
|
1
|
+
{"version":3,"file":"config-header.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/config-header.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,UAAU,oBAAoB,CAAC,MAAmB,EAAE,eAAuB;IAC/E,OAAO;;;;cAIK,eAAe;2BACF,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,WAAW,mBAAmB,MAAM,CAAC,QAAQ,CAAC,aAAa,oBAAoB,MAAM,CAAC,QAAQ,CAAC,cAAc,qBAAqB,MAAM,CAAC,QAAQ,CAAC,eAAe;uBACnM,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,eAAe;;IAEhE,CAAC;AACL,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Generates the SW message event handler (SKIP_WAITING, INVALIDATE_TAG).
|
|
2
|
+
* Generates the SW message event handler (SKIP_WAITING, INVALIDATE_TAG, CLEAR_RUNTIME_CACHE).
|
|
3
3
|
*/
|
|
4
|
-
export function generateMessageHandler(tagInvalidation) {
|
|
4
|
+
export function generateMessageHandler(tagInvalidation, authEnabled) {
|
|
5
5
|
let code = `
|
|
6
6
|
self.addEventListener("message", (event) => {
|
|
7
7
|
if (event.data.type === "SKIP_WAITING") {
|
|
@@ -11,6 +11,16 @@ self.addEventListener("message", (event) => {
|
|
|
11
11
|
code += `
|
|
12
12
|
if (event.data.type === "INVALIDATE_TAG" && event.data.tag) {
|
|
13
13
|
event.waitUntil(invalidateByTag(event.data.tag));
|
|
14
|
+
}`;
|
|
15
|
+
}
|
|
16
|
+
if (authEnabled) {
|
|
17
|
+
code += `
|
|
18
|
+
if (event.data.type === "CLEAR_RUNTIME_CACHE") {
|
|
19
|
+
event.waitUntil(
|
|
20
|
+
caches.delete(CACHE_NAME_RUNTIME).then(() => {
|
|
21
|
+
return caches.open(CACHE_NAME_RUNTIME);
|
|
22
|
+
}),
|
|
23
|
+
);
|
|
14
24
|
}`;
|
|
15
25
|
}
|
|
16
26
|
code += `
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-handler.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/message-handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,UAAU,sBAAsB,CAAC,eAAwB;
|
|
1
|
+
{"version":3,"file":"message-handler.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/message-handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,UAAU,sBAAsB,CAAC,eAAwB,EAAE,WAAoB;IACnF,IAAI,IAAI,GAAG;;;;IAIT,CAAC;IAEH,IAAI,eAAe,EAAE,CAAC;QACpB,IAAI,IAAI;;;IAGR,CAAC;IACH,CAAC;IAED,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,IAAI;;;;;;;IAOR,CAAC;IACH,CAAC;IAED,IAAI,IAAI;IACN,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -22,12 +22,16 @@ import { generateMutationQueue } from "./file-generators/mutation-queue.js";
|
|
|
22
22
|
import { generateStore } from "./file-generators/store.js";
|
|
23
23
|
import { generateReconcile } from "./file-generators/reconcile.js";
|
|
24
24
|
import { generateBackgroundSync } from "./file-generators/background-sync.js";
|
|
25
|
-
import { generateIndexedDB } from "./file-generators/indexeddb.js";
|
|
26
25
|
import { generatePwaInstall } from "./file-generators/pwa-install.js";
|
|
27
26
|
import { generateManifest } from "./file-generators/manifest.js";
|
|
28
27
|
import { generateInvalidationTags } from "./file-generators/invalidation-tags.js";
|
|
28
|
+
import { generateAuthStore } from "./file-generators/auth-store.js";
|
|
29
|
+
import { generateAuthFetch } from "./file-generators/auth-fetch.js";
|
|
30
|
+
import { generateAuthUser } from "./file-generators/auth-user.js";
|
|
31
|
+
import { generateAuthState } from "./file-generators/auth-state.js";
|
|
29
32
|
import { generateSwGeneratorBuild } from "./file-generators/sw-generator-build.js";
|
|
30
33
|
import { generateTypeDefinitions } from "./file-generators/type-definitions.js";
|
|
34
|
+
import { generateHooks } from "./file-generators/generate-hooks.js";
|
|
31
35
|
export function generateFiles(ctx, onFile) {
|
|
32
36
|
const steps = [
|
|
33
37
|
{ name: "sw-template", gen: () => generateSwTemplate(ctx), enabled: true },
|
|
@@ -38,12 +42,16 @@ export function generateFiles(ctx, onFile) {
|
|
|
38
42
|
{ name: "reconcile", gen: () => generateReconcile(ctx), enabled: ctx.config.features.mutationQueue },
|
|
39
43
|
{ name: "mutation-queue", gen: () => generateMutationQueue(ctx), enabled: ctx.config.features.mutationQueue },
|
|
40
44
|
{ name: "background-sync", gen: () => generateBackgroundSync(ctx), enabled: ctx.config.features.backgroundSync },
|
|
41
|
-
{ name: "
|
|
45
|
+
{ name: "auth-store", gen: () => generateAuthStore(ctx), enabled: ctx.config.features.auth.enabled },
|
|
46
|
+
{ name: "auth-fetch", gen: () => generateAuthFetch(ctx), enabled: ctx.config.features.auth.enabled },
|
|
47
|
+
{ name: "auth-user", gen: () => generateAuthUser(ctx), enabled: ctx.config.features.auth.enabled },
|
|
48
|
+
{ name: "auth-state", gen: () => generateAuthState(ctx), enabled: ctx.config.features.auth.enabled },
|
|
42
49
|
{ name: "sw-generator", gen: () => generateSwGeneratorBuild(ctx), enabled: true },
|
|
43
50
|
{ name: "swoff.d.ts", gen: () => generateTypeDefinitions(ctx), enabled: ctx.ext === "ts" },
|
|
44
51
|
{ name: "pwa-install", gen: () => generatePwaInstall(ctx), enabled: ctx.config.features.pwa.enabled },
|
|
45
52
|
{ name: "manifest.json", gen: () => generateManifest(ctx), enabled: ctx.config.features.pwa.enabled },
|
|
46
53
|
{ name: "invalidation-tags", gen: () => generateInvalidationTags(ctx), enabled: ctx.config.features.tagInvalidation },
|
|
54
|
+
{ name: "hooks", gen: () => generateHooks(ctx), enabled: ctx.config.framework === "react" },
|
|
47
55
|
];
|
|
48
56
|
for (const step of steps) {
|
|
49
57
|
if (!step.enabled)
|
|
@@ -77,6 +85,7 @@ if (fileURLToPath(import.meta.url) === fileURLToPath(new URL(process.argv[1], "f
|
|
|
77
85
|
swoffDir,
|
|
78
86
|
ext,
|
|
79
87
|
generatedFiles,
|
|
88
|
+
frameworkName: config.framework ?? "vanilla",
|
|
80
89
|
};
|
|
81
90
|
const ttyStatus = process.stdout.isTTY
|
|
82
91
|
? (msg) => {
|