@swoff/cli 0.3.9 → 0.3.10

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.
Files changed (216) hide show
  1. package/dist/__tests__/assemble-sw.test.js +8 -17
  2. package/dist/__tests__/assemble-sw.test.js.map +1 -1
  3. package/dist/__tests__/cli-integration.test.js +2 -2
  4. package/dist/__tests__/cli-integration.test.js.map +1 -1
  5. package/dist/__tests__/config-types.test.js +18 -8
  6. package/dist/__tests__/config-types.test.js.map +1 -1
  7. package/dist/__tests__/file-generators.test.js +3 -3
  8. package/dist/__tests__/file-generators.test.js.map +1 -1
  9. package/dist/__tests__/loader.test.js +5 -1
  10. package/dist/__tests__/loader.test.js.map +1 -1
  11. package/dist/__tests__/validator.test.js +6 -13
  12. package/dist/__tests__/validator.test.js.map +1 -1
  13. package/dist/index.js +39 -35
  14. package/dist/index.js.map +1 -1
  15. package/dist/lib/cli/help.js +13 -8
  16. package/dist/lib/cli/help.js.map +1 -1
  17. package/dist/lib/commands/add.js +38 -8
  18. package/dist/lib/commands/add.js.map +1 -1
  19. package/dist/lib/commands/assets.js +37 -0
  20. package/dist/lib/commands/assets.js.map +1 -0
  21. package/dist/lib/commands/clean.js +33 -17
  22. package/dist/lib/commands/clean.js.map +1 -1
  23. package/dist/lib/commands/generate-assets.js +44 -0
  24. package/dist/lib/commands/generate-assets.js.map +1 -0
  25. package/dist/lib/commands/generate-guide.js +22 -29
  26. package/dist/lib/commands/generate-guide.js.map +1 -1
  27. package/dist/lib/commands/generate.js +16 -9
  28. package/dist/lib/commands/generate.js.map +1 -1
  29. package/dist/lib/commands/info.js +36 -45
  30. package/dist/lib/commands/info.js.map +1 -1
  31. package/dist/lib/commands/init.js +25 -3
  32. package/dist/lib/commands/init.js.map +1 -1
  33. package/dist/lib/commands/validate.js +1 -1
  34. package/dist/lib/commands/validate.js.map +1 -1
  35. package/dist/lib/config/loader.js +25 -20
  36. package/dist/lib/config/loader.js.map +1 -1
  37. package/dist/lib/config/validator.js +20 -11
  38. package/dist/lib/config/validator.js.map +1 -1
  39. package/dist/lib/generators/asset-generator/dependency-resolver.js +76 -0
  40. package/dist/lib/generators/asset-generator/dependency-resolver.js.map +1 -0
  41. package/dist/lib/generators/asset-generator/generate.js +111 -0
  42. package/dist/lib/generators/asset-generator/generate.js.map +1 -0
  43. package/dist/lib/generators/asset-generator/guide.js +43 -0
  44. package/dist/lib/generators/asset-generator/guide.js.map +1 -0
  45. package/dist/lib/generators/asset-generator/html-patcher.js +65 -0
  46. package/dist/lib/generators/asset-generator/html-patcher.js.map +1 -0
  47. package/dist/lib/generators/asset-generator/ico-encoder.js +29 -0
  48. package/dist/lib/generators/asset-generator/ico-encoder.js.map +1 -0
  49. package/dist/lib/generators/asset-generator/manifest-patcher.js +23 -0
  50. package/dist/lib/generators/asset-generator/manifest-patcher.js.map +1 -0
  51. package/dist/lib/generators/asset-generator/maskable.js +15 -0
  52. package/dist/lib/generators/asset-generator/maskable.js.map +1 -0
  53. package/dist/lib/generators/asset-generator/rasterize.js +32 -0
  54. package/dist/lib/generators/asset-generator/rasterize.js.map +1 -0
  55. package/dist/lib/generators/asset-generator/sizes.js +25 -0
  56. package/dist/lib/generators/asset-generator/sizes.js.map +1 -0
  57. package/dist/lib/generators/file-generators/api-config.js +6 -0
  58. package/dist/lib/generators/file-generators/api-config.js.map +1 -0
  59. package/dist/lib/generators/file-generators/auth-state.js +2 -34
  60. package/dist/lib/generators/file-generators/auth-state.js.map +1 -1
  61. package/dist/lib/generators/file-generators/auth-store.js +2 -250
  62. package/dist/lib/generators/file-generators/auth-store.js.map +1 -1
  63. package/dist/lib/generators/file-generators/auth-user.js +3 -81
  64. package/dist/lib/generators/file-generators/auth-user.js.map +1 -1
  65. package/dist/lib/generators/file-generators/background-sync.js +2 -57
  66. package/dist/lib/generators/file-generators/background-sync.js.map +1 -1
  67. package/dist/lib/generators/file-generators/cache.js +2 -30
  68. package/dist/lib/generators/file-generators/cache.js.map +1 -1
  69. package/dist/lib/generators/file-generators/client-injector.js +2 -130
  70. package/dist/lib/generators/file-generators/client-injector.js.map +1 -1
  71. package/dist/lib/generators/file-generators/fetch-state.js +6 -0
  72. package/dist/lib/generators/file-generators/fetch-state.js.map +1 -0
  73. package/dist/lib/generators/file-generators/fetch-wrapper.js +3 -295
  74. package/dist/lib/generators/file-generators/fetch-wrapper.js.map +1 -1
  75. package/dist/lib/generators/file-generators/generate-framework-adapters.js +56 -0
  76. package/dist/lib/generators/file-generators/generate-framework-adapters.js.map +1 -0
  77. package/dist/lib/generators/file-generators/generate-hooks.js +4 -3
  78. package/dist/lib/generators/file-generators/generate-hooks.js.map +1 -1
  79. package/dist/lib/generators/file-generators/gql-wrapper.js +3 -132
  80. package/dist/lib/generators/file-generators/gql-wrapper.js.map +1 -1
  81. package/dist/lib/generators/file-generators/guide-generator.js +29 -1
  82. package/dist/lib/generators/file-generators/guide-generator.js.map +1 -1
  83. package/dist/lib/generators/file-generators/invalidation-tags.js +3 -258
  84. package/dist/lib/generators/file-generators/invalidation-tags.js.map +1 -1
  85. package/dist/lib/generators/file-generators/manifest.js +13 -3
  86. package/dist/lib/generators/file-generators/manifest.js.map +1 -1
  87. package/dist/lib/generators/file-generators/mutation-queue.js +3 -305
  88. package/dist/lib/generators/file-generators/mutation-queue.js.map +1 -1
  89. package/dist/lib/generators/file-generators/mutation-state.js +2 -117
  90. package/dist/lib/generators/file-generators/mutation-state.js.map +1 -1
  91. package/dist/lib/generators/file-generators/push.js +6 -138
  92. package/dist/lib/generators/file-generators/push.js.map +1 -1
  93. package/dist/lib/generators/file-generators/pwa-install.js +11 -84
  94. package/dist/lib/generators/file-generators/pwa-install.js.map +1 -1
  95. package/dist/lib/generators/file-generators/reset.js +6 -0
  96. package/dist/lib/generators/file-generators/reset.js.map +1 -0
  97. package/dist/lib/generators/file-generators/server-push.js +3 -134
  98. package/dist/lib/generators/file-generators/server-push.js.map +1 -1
  99. package/dist/lib/generators/file-generators/sw-generator-build.js +4 -4
  100. package/dist/lib/generators/file-generators/sw-injector.js +9 -230
  101. package/dist/lib/generators/file-generators/sw-injector.js.map +1 -1
  102. package/dist/lib/generators/file-generators/type-definitions.js +2 -111
  103. package/dist/lib/generators/file-generators/type-definitions.js.map +1 -1
  104. package/dist/lib/generators/sw-generator.js +5 -5
  105. package/dist/lib/generators/sw-generator.js.map +1 -1
  106. package/dist/lib/generators/sw-sections/activate-handler.js +25 -3
  107. package/dist/lib/generators/sw-sections/activate-handler.js.map +1 -1
  108. package/dist/lib/generators/sw-sections/assemble-sw.js +13 -12
  109. package/dist/lib/generators/sw-sections/assemble-sw.js.map +1 -1
  110. package/dist/lib/generators/sw-sections/background-sync-handler.js +14 -7
  111. package/dist/lib/generators/sw-sections/background-sync-handler.js.map +1 -1
  112. package/dist/lib/generators/sw-sections/config-header.js +1 -1
  113. package/dist/lib/generators/sw-sections/config-header.js.map +1 -1
  114. package/dist/lib/generators/sw-sections/fetch-handler.js +165 -104
  115. package/dist/lib/generators/sw-sections/fetch-handler.js.map +1 -1
  116. package/dist/lib/generators/sw-sections/glob-matcher-code.js.map +1 -0
  117. package/dist/lib/generators/sw-sections/server-push-handler.js +12 -0
  118. package/dist/lib/generators/sw-sections/server-push-handler.js.map +1 -1
  119. package/dist/lib/generators/sw-sections/tag-management.js +6 -4
  120. package/dist/lib/generators/sw-sections/tag-management.js.map +1 -1
  121. package/dist/lib/generators/swoff-files-generator.js +66 -35
  122. package/dist/lib/generators/swoff-files-generator.js.map +1 -1
  123. package/dist/lib/shared/config-types.js +89 -28
  124. package/dist/lib/shared/config-types.js.map +1 -1
  125. package/dist/runtime/api-config.js +18 -0
  126. package/dist/runtime/api-config.js.map +1 -0
  127. package/dist/runtime/auth-state.js +35 -0
  128. package/dist/runtime/auth-state.js.map +1 -0
  129. package/dist/runtime/auth-store.js +273 -0
  130. package/dist/runtime/auth-store.js.map +1 -0
  131. package/dist/runtime/auth-user.js +168 -0
  132. package/dist/runtime/auth-user.js.map +1 -0
  133. package/dist/runtime/background-sync.js +59 -0
  134. package/dist/runtime/background-sync.js.map +1 -0
  135. package/dist/runtime/cache.js +30 -0
  136. package/dist/runtime/cache.js.map +1 -0
  137. package/dist/runtime/client-injector.js +136 -0
  138. package/dist/runtime/client-injector.js.map +1 -0
  139. package/dist/runtime/fetch-state.js +42 -0
  140. package/dist/runtime/fetch-state.js.map +1 -0
  141. package/dist/runtime/fetch-wrapper.js +355 -0
  142. package/dist/runtime/fetch-wrapper.js.map +1 -0
  143. package/dist/runtime/gql-wrapper.js +135 -0
  144. package/dist/runtime/gql-wrapper.js.map +1 -0
  145. package/dist/runtime/invalidation-tags.js +260 -0
  146. package/dist/runtime/invalidation-tags.js.map +1 -0
  147. package/dist/runtime/mutation-queue.js +304 -0
  148. package/dist/runtime/mutation-queue.js.map +1 -0
  149. package/dist/runtime/mutation-state.js +117 -0
  150. package/dist/runtime/mutation-state.js.map +1 -0
  151. package/dist/runtime/push.js +138 -0
  152. package/dist/runtime/push.js.map +1 -0
  153. package/dist/runtime/pwa-index.js +11 -0
  154. package/dist/runtime/pwa-index.js.map +1 -0
  155. package/dist/runtime/pwa-injector.js +44 -0
  156. package/dist/runtime/pwa-injector.js.map +1 -0
  157. package/dist/runtime/pwa-install.js +83 -0
  158. package/dist/runtime/pwa-install.js.map +1 -0
  159. package/dist/runtime/pwa-prompt.js +54 -0
  160. package/dist/runtime/pwa-prompt.js.map +1 -0
  161. package/dist/runtime/reset.js +148 -0
  162. package/dist/runtime/reset.js.map +1 -0
  163. package/dist/runtime/server-push.js +148 -0
  164. package/dist/runtime/server-push.js.map +1 -0
  165. package/dist/runtime/sw-injector.js +236 -0
  166. package/dist/runtime/sw-injector.js.map +1 -0
  167. package/dist/runtime/type-definitions.js +138 -0
  168. package/dist/runtime/type-definitions.js.map +1 -0
  169. package/dist/runtime/utils.js +27 -0
  170. package/dist/runtime/utils.js.map +1 -0
  171. package/package.json +3 -2
  172. package/templates/react/useAuth.jsx +106 -0
  173. package/templates/react/useAuth.tsx +118 -0
  174. package/templates/{hooks → react}/useBackgroundSync.jsx +6 -4
  175. package/templates/{hooks → react}/useBackgroundSync.tsx +6 -4
  176. package/templates/{hooks → react}/useCacheInvalidation.jsx +2 -2
  177. package/templates/react/useCacheInvalidation.tsx +52 -0
  178. package/templates/react/useCachedFetch.jsx +140 -0
  179. package/templates/react/useCachedFetch.tsx +160 -0
  180. package/templates/react/useIsFetching.jsx +32 -0
  181. package/templates/react/useIsFetching.tsx +32 -0
  182. package/templates/react/useMutation.jsx +141 -0
  183. package/templates/react/useMutation.tsx +180 -0
  184. package/templates/react/useMutationQueue.jsx +69 -0
  185. package/templates/react/useMutationQueue.tsx +83 -0
  186. package/templates/react/useNetworkStatus.jsx +61 -0
  187. package/templates/react/useNetworkStatus.tsx +76 -0
  188. package/templates/react/usePrefetch.jsx +32 -0
  189. package/templates/react/usePrefetch.tsx +42 -0
  190. package/templates/{hooks → react}/usePushSubscription.jsx +4 -4
  191. package/templates/{hooks → react}/usePushSubscription.tsx +4 -4
  192. package/templates/{hooks → react}/useSWUpdate.jsx +3 -3
  193. package/templates/{hooks → react}/useSWUpdate.tsx +4 -4
  194. package/templates/react/useSwoffReset.jsx +32 -0
  195. package/templates/react/useSwoffReset.tsx +39 -0
  196. package/docs/API.md +0 -565
  197. package/docs/ARCHITECTURE.md +0 -374
  198. package/docs/CLI.md +0 -148
  199. package/docs/COMPARISON.md +0 -192
  200. package/docs/CONFIG.md +0 -277
  201. package/docs/ECOSYSTEM.md +0 -33
  202. package/templates/hooks/useAuth.jsx +0 -30
  203. package/templates/hooks/useAuth.tsx +0 -30
  204. package/templates/hooks/useCacheInvalidation.tsx +0 -19
  205. package/templates/hooks/useCachedFetch.jsx +0 -69
  206. package/templates/hooks/useCachedFetch.tsx +0 -81
  207. package/templates/hooks/useMutation.jsx +0 -76
  208. package/templates/hooks/useMutation.tsx +0 -109
  209. package/templates/hooks/useMutationQueue.jsx +0 -43
  210. package/templates/hooks/useMutationQueue.tsx +0 -50
  211. package/templates/hooks/useNetworkStatus.jsx +0 -19
  212. package/templates/hooks/useNetworkStatus.tsx +0 -19
  213. package/templates/hooks/usePrefetch.jsx +0 -10
  214. package/templates/hooks/usePrefetch.tsx +0 -25
  215. /package/templates/{hooks → react}/useMutationState.jsx +0 -0
  216. /package/templates/{hooks → react}/useMutationState.tsx +0 -0
@@ -8,260 +8,12 @@
8
8
  * user display. After a page refresh, re-login is required.
9
9
  */
10
10
  import { writeFile } from "./context.js";
11
- function generateWithAuthHeaders(authType, ts, R, T) {
12
- const a = T("AuthData | null");
13
- const h = T("Headers");
14
- const hd = T("Headers");
15
- switch (authType) {
16
- case "cookie":
17
- return `/** Inject auth headers. For cookie auth, credentials are handled via AUTH_WITH_CREDENTIALS. */
18
- export function withAuthHeaders(headers${hd}, _auth${a})${h}{
19
- return headers;
20
- }`;
21
- case "bearer":
22
- return `/** Inject Bearer token into request headers. */
23
- export function withAuthHeaders(headers${hd}, auth${a})${h}{
24
- if (auth?.token) {
25
- headers.set("Authorization", \`Bearer \${auth.token}\`);
26
- }
27
- return headers;
28
- }`;
29
- case "custom":
30
- return `/** Inject custom auth headers. Edit this function to match your backend. */
31
- export function withAuthHeaders(headers${hd}, auth${a})${h}{
32
- // --- EDIT THIS BLOCK FOR YOUR BACKEND ---
33
- // if (auth?.token) {
34
- // headers.set("X-Auth-Token", auth.token);
35
- // }
36
- // --- END OF EDITABLE BLOCK ---
37
- return headers;
38
- }`;
39
- default:
40
- return `export function withAuthHeaders(headers${hd}, auth${a})${h}{
41
- if (auth?.token) {
42
- headers.set("Authorization", \`Bearer \${auth.token}\`);
43
- }
44
- return headers;
45
- }`;
46
- }
47
- }
48
- function generateIsAuthUrl(refreshPath, userEndpoint, ts, R, T) {
49
- return `/** Check if a URL is an auth endpoint that should bypass the SW cache. */
50
- export function isAuthUrl(url${T("string")})${R("boolean")}{
51
- const authPaths = [
52
- "/login",
53
- "/logout",
54
- "/register",
55
- "/api/login",
56
- "/api/logout",
57
- "/api/register",
58
- "${refreshPath}",
59
- "${userEndpoint}",
60
- ];
61
- return authPaths.some((path) => url.includes(path));
62
- }`;
63
- }
64
- function generateEnsureValidAuth(cookieAuth, ts, R, T, PT, refreshPath, ext) {
65
- const cr = cookieAuth ? ` credentials: "include" as RequestCredentials,` : "";
66
- return `/** Refresh the auth token via the refresh endpoint. Uses plain fetch to bypass SW cache. */
67
- let refreshPromise${T("Promise<AuthData | null> | null")} = null;
68
-
69
- export async function ensureValidAuth()${R("Promise<AuthData | null>")}{
70
- const auth = await getAuth();
71
- if (!auth) return null;
72
- if (!auth.expiresAt || Date.now() < auth.expiresAt) return auth;
73
-
74
- if (!refreshPromise) {
75
- refreshPromise = (async () => {
76
- const headers = new Headers({ "Content-Type": "application/json" });
77
- withAuthHeaders(headers, auth);
78
- try {
79
- const response = await fetch("${refreshPath}", {
80
- method: "POST",
81
- headers,
82
- ${cr} });
83
-
84
- if (!response.ok) {
85
- await clearAuth();
86
- window.dispatchEvent(new CustomEvent("sw-auth-unauthorized"));
87
- return null;
88
- }
89
-
90
- const data = await response.json();
91
- const updated = { ...auth, token: data.token, expiresAt: data.expiresAt };
92
- await setAuth(updated);
93
- return updated;
94
- } catch {
95
- await clearAuth();
96
- window.dispatchEvent(new CustomEvent("sw-auth-unauthorized"));
97
- return null;
98
- }
99
- })();
100
- }
101
-
102
- try {
103
- return await refreshPromise;
104
- } finally {
105
- refreshPromise = null;
106
- }
107
- }`;
108
- }
11
+ import { generateAuthStoreCode } from "../../../runtime/auth-store.js";
109
12
  export function generateAuthStore(ctx) {
110
13
  const ext = ctx.ext;
111
14
  const ts = ext === "ts";
112
- const T = (type) => (ts ? `: ${type}` : "");
113
- const R = (type) => (ts ? `: ${type} ` : " ");
114
- const PT = (type) => (ts ? `<${type}>` : "");
115
- const AS = (type) => (ts ? ` as ${type}` : "");
116
15
  const authConfig = ctx.config.features.auth;
117
- const { refreshPath, userEndpoint, type } = authConfig;
118
- const authDataInterface = ts
119
- ? `export interface AuthData {
120
- token?: string;
121
- user?: Record<string, unknown>;
122
- expiresAt?: number;
123
- }
124
-
125
- export interface AuthResponse extends Record<string, unknown> {
126
- // Uncomment and type the fields your backend's login response returns:
127
- // token: string;
128
- // user: Record<string, unknown>;
129
- // expiresAt?: number;
130
- }
131
-
132
- `
133
- : "";
134
- const createAuthFromResponseBlock = ts
135
- ? `/** Extract AuthData from your backend's login response. Edit this function to match your backend's response shape. */
136
- export function createAuthFromResponse(response: AuthResponse): AuthData {
137
- // --- EDIT THIS TO MATCH YOUR BACKEND ---
138
- const data = response as Record<string, unknown>;
139
- return {
140
- token: data.token as string,
141
- user: data.user as Record<string, unknown> | undefined,
142
- expiresAt: data.expiresAt as number | undefined,
143
- };
144
- // --- END OF EDITABLE BLOCK ---
145
- }
146
- `
147
- : `/** Extract AuthData from your backend's login response. Edit this function to match your backend's response shape. */
148
- export function createAuthFromResponse(response) {
149
- // --- EDIT THIS TO MATCH YOUR BACKEND ---
150
- return {
151
- token: response.token,
152
- user: response.user,
153
- expiresAt: response.expiresAt,
154
- };
155
- // --- END OF EDITABLE BLOCK ---
156
- }
157
- `;
158
- const code = `/**
159
- * Auth Store — Token in memory only; user info in IndexedDB for offline access.
160
- *
161
- * Security:
162
- * The Bearer token lives in JavaScript memory and is cleared on page refresh.
163
- * Only { user, expiresAt } is persisted to IndexedDB so the app can display
164
- * user info offline. After a page refresh, re-login is required.
165
- *
166
- * Usage:
167
- * import { setAuth, getAuth, clearAuth, isAuthValid } from "./auth/store.${ext}";
168
- *
169
- * await setAuth({ token, user, expiresAt });
170
- * const auth = await getAuth();
171
- * await clearAuth();
172
- */
173
-
174
- ${authDataInterface}const DB_NAME = "swoff-auth";
175
- const STORE_NAME = "auth";
176
-
177
- let memoryAuth${T("AuthData | null")} = null;
178
-
179
- ${createAuthFromResponseBlock}
180
- function openAuthDB()${R("Promise<IDBDatabase>")}{
181
- return new Promise${PT("IDBDatabase")}((resolve, reject) => {
182
- const request = indexedDB.open(DB_NAME, 1);
183
- request.onupgradeneeded = (e) => {
184
- const db = (e.target${AS("IDBOpenDBRequest")}).result;
185
- if (!db.objectStoreNames.contains(STORE_NAME)) {
186
- db.createObjectStore(STORE_NAME, { keyPath: "key" });
187
- }
188
- };
189
- request.onsuccess = (e) => resolve((e.target${AS("IDBOpenDBRequest")}).result);
190
- request.onerror = (e) => reject((e.target${AS("IDBRequest")}).error);
191
- });
192
- }
193
-
194
- async function persistUserData(authData${T("AuthData | null")})${R("Promise<void>")}{
195
- // Only persist { user, expiresAt } — never the token
196
- const userData = { user: authData?.user, expiresAt: authData?.expiresAt };
197
- const db = await openAuthDB();
198
- return new Promise${PT("void")}((resolve, reject) => {
199
- const tx = db.transaction(STORE_NAME, "readwrite");
200
- const store = tx.objectStore(STORE_NAME);
201
- const request = store.put({ key: "session", value: userData });
202
- request.onsuccess = () => resolve();
203
- request.onerror = () => reject((request${AS("IDBRequest")}).error);
204
- });
205
- }
206
-
207
- async function loadUserData()${R("Promise<{ user?: Record<string, unknown>; expiresAt?: number } | null>")}{
208
- const db = await openAuthDB();
209
- return new Promise((resolve, reject) => {
210
- const tx = db.transaction(STORE_NAME, "readonly");
211
- const store = tx.objectStore(STORE_NAME);
212
- const request = store.get("session");
213
- request.onsuccess = () => resolve((request${AS("IDBRequest")}).result?.value ?? null);
214
- request.onerror = () => reject((request${AS("IDBRequest")}).error);
215
- });
216
- }
217
-
218
- async function clearPersistedData()${R("Promise<void>")}{
219
- const db = await openAuthDB();
220
- return new Promise${PT("void")}((resolve, reject) => {
221
- const tx = db.transaction(STORE_NAME, "readwrite");
222
- const store = tx.objectStore(STORE_NAME);
223
- const request = store.delete("session");
224
- request.onsuccess = () => resolve();
225
- request.onerror = () => reject((request${AS("IDBRequest")}).error);
226
- });
227
- }
228
-
229
- /** Store auth data in memory and persist user info to IndexedDB for offline access. */
230
- export async function setAuth(authData${T("AuthData")})${R("Promise<void>")}{
231
- memoryAuth = authData;
232
- await persistUserData(authData);
233
- }
234
-
235
- /** Get auth data from memory (or IndexedDB if memory is empty after page refresh). */
236
- export async function getAuth()${R("Promise<AuthData | null>")}{
237
- if (memoryAuth) return memoryAuth;
238
-
239
- const userData = await loadUserData();
240
- if (userData) {
241
- memoryAuth = userData;
242
- }
243
- return memoryAuth;
244
- }
245
-
246
- /** Clear auth from memory and IndexedDB. Call on logout or 401. */
247
- export async function clearAuth()${R("Promise<void>")}{
248
- memoryAuth = null;
249
- await clearPersistedData();
250
- }
251
-
252
- /** Check if auth exists and has not expired. Returns true if no expiresAt is set. */
253
- export function isAuthValid(auth${T("AuthData | null")})${R("boolean")}{
254
- if (!auth) return false;
255
- if (!auth.expiresAt) return true;
256
- return Date.now() < auth.expiresAt;
257
- }
258
-
259
- ${type === "cookie" ? `export const AUTH_WITH_CREDENTIALS = true;` : `export const AUTH_WITH_CREDENTIALS = false;`}
260
-
261
- ${generateWithAuthHeaders(type, ts, R, T)}
262
- ${generateIsAuthUrl(refreshPath, userEndpoint, ts, R, T)}
263
- ${generateEnsureValidAuth(type === "cookie", ts, R, T, PT, refreshPath, ext)}
264
- `;
16
+ const code = generateAuthStoreCode({ ts, ext }, authConfig.type, authConfig.refreshPath, authConfig.userEndpoint);
265
17
  writeFile(ctx, `auth/store.${ext}`, code);
266
18
  }
267
19
  //# sourceMappingURL=auth-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/auth-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/auth-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAEvE,MAAM,UAAU,iBAAiB,CAAC,GAAqB;IACrD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IACxB,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;IAE5C,MAAM,IAAI,GAAG,qBAAqB,CAChC,EAAE,EAAE,EAAE,GAAG,EAAE,EACX,UAAU,CAAC,IAAI,EACf,UAAU,CAAC,WAAW,EACtB,UAAU,CAAC,YAAY,CACxB,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC"}
@@ -2,90 +2,12 @@
2
2
  * Generates auth-user.ts/js — fetch, cache, and invalidate current user.
3
3
  */
4
4
  import { writeFile } from "./context.js";
5
+ import { generateAuthUserCode } from "../../../runtime/auth-user.js";
5
6
  export function generateAuthUser(ctx) {
6
7
  const ext = ctx.ext;
7
8
  const ts = ext === "ts";
8
- const T = (type) => (ts ? `: ${type}` : "");
9
- const R = (type) => (ts ? `: ${type} ` : " ");
10
- const PT = (type) => (ts ? `<${type}>` : "");
11
- const AS = (type) => (ts ? ` as ${type}` : "");
12
- const userEndpoint = ctx.config.features.auth.userEndpoint;
13
- const code = `/**
14
- * Current User — fetch, cache, and invalidate the current user for offline access.
15
- *
16
- * Usage:
17
- * import { fetchCurrentUser, cacheUser, getCachedUser, clearCachedUser } from "./auth/user.${ext}";
18
- *
19
- * await fetchCurrentUser(); // Fetch from server & cache
20
- * const user = await getCachedUser(); // Get cached (offline-capable)
21
- * await clearCachedUser(); // Clear on logout
22
- */
23
-
24
- import { fetchWithCache } from "../fetch-wrapper.${ext}";
25
-
26
- const DB_NAME = "swoff-auth-user";
27
- const STORE_NAME = "current-user";
28
-
29
- function openAuthDB()${R("Promise<IDBDatabase>")}{
30
- return new Promise${PT("IDBDatabase")}((resolve, reject) => {
31
- const request = indexedDB.open(DB_NAME, 1);
32
- request.onupgradeneeded = (e) => {
33
- const db = (e.target${AS("IDBOpenDBRequest")}).result;
34
- if (!db.objectStoreNames.contains(STORE_NAME)) {
35
- db.createObjectStore(STORE_NAME, { keyPath: "key" });
36
- }
37
- };
38
- request.onsuccess = (e) => resolve((e.target${AS("IDBOpenDBRequest")}).result);
39
- request.onerror = (e) => reject((e.target${AS("IDBRequest")}).error);
40
- });
41
- }
42
-
43
- /** Fetch current user from the user endpoint and cache the result in IndexedDB. */
44
- export async function fetchCurrentUser()${R("Promise<Record<string, unknown>>")}{
45
- const { response } = await fetchWithCache("${userEndpoint}", { auth: true });
46
- if (!response.ok) throw new Error("Failed to fetch user");
47
-
48
- const user = await response.json();
49
- await cacheUser(user);
50
- return user;
51
- }
52
-
53
- /** Persist user data to IndexedDB for offline access. */
54
- export async function cacheUser(user${T("Record<string, unknown>")})${R("Promise<void>")}{
55
- const db = await openAuthDB();
56
- return new Promise<void>((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
- /** Load user data from IndexedDB cache (no token — only user object survives refresh). */
66
- export async function getCachedUser()${R("Promise<Record<string, unknown> | null>")}{
67
- const db = await openAuthDB();
68
- return new Promise${PT("Record<string, unknown> | null")}((resolve, reject) => {
69
- const tx = db.transaction(STORE_NAME, "readonly");
70
- const store = tx.objectStore(STORE_NAME);
71
- const request = store.get("user");
72
- request.onsuccess = () => resolve((request${AS("IDBRequest")}).result?.value ?? null);
73
- request.onerror = () => reject((request${AS("IDBRequest")}).error);
74
- });
75
- }
76
-
77
- /** Remove user data from IndexedDB cache. Call on logout. */
78
- export async function clearCachedUser()${R("Promise<void>")}{
79
- const db = await openAuthDB();
80
- return new Promise${PT("void")}((resolve, reject) => {
81
- const tx = db.transaction(STORE_NAME, "readwrite");
82
- const store = tx.objectStore(STORE_NAME);
83
- store.delete("user");
84
- tx.oncomplete = () => resolve();
85
- tx.onerror = () => reject((tx${AS("IDBTransaction")}).error);
86
- });
87
- }
88
- `;
9
+ const authConfig = ctx.config.features.auth;
10
+ const code = generateAuthUserCode({ ts, ext }, authConfig.refreshPath, authConfig.userEndpoint, authConfig.type);
89
11
  writeFile(ctx, `auth/user.${ext}`, code);
90
12
  }
91
13
  //# sourceMappingURL=auth-user.js.map
@@ -1 +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,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IACxB,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpD,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACtD,MAAM,EAAE,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACrD,MAAM,EAAE,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC;IAE3D,MAAM,IAAI,GAAG;;;;gGAIiF,GAAG;;;;;;;mDAOhD,GAAG;;;;;uBAK/B,CAAC,CAAC,sBAAsB,CAAC;sBAC1B,EAAE,CAAC,aAAa,CAAC;;;4BAGX,EAAE,CAAC,kBAAkB,CAAC;;;;;kDAKA,EAAE,CAAC,kBAAkB,CAAC;+CACzB,EAAE,CAAC,YAAY,CAAC;;;;;0CAKrB,CAAC,CAAC,kCAAkC,CAAC;+CAChC,YAAY;;;;;;;;;sCASrB,CAAC,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC;;;;;;;;;;;;uCAYjD,CAAC,CAAC,yCAAyC,CAAC;;sBAE7D,EAAE,CAAC,gCAAgC,CAAC;;;;gDAIV,EAAE,CAAC,YAAY,CAAC;6CACnB,EAAE,CAAC,YAAY,CAAC;;;;;yCAKpB,CAAC,CAAC,eAAe,CAAC;;sBAErC,EAAE,CAAC,MAAM,CAAC;;;;;mCAKG,EAAE,CAAC,gBAAgB,CAAC;;;CAGtD,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC"}
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;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,MAAM,UAAU,gBAAgB,CAAC,GAAqB;IACpD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IACxB,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;IAE5C,MAAM,IAAI,GAAG,oBAAoB,CAC/B,EAAE,EAAE,EAAE,GAAG,EAAE,EACX,UAAU,CAAC,WAAW,EACtB,UAAU,CAAC,YAAY,EACvB,UAAU,CAAC,IAAI,CAChB,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC"}
@@ -2,63 +2,8 @@
2
2
  * Generates background-sync.js - Background Sync API registration.
3
3
  */
4
4
  import { writeFile } from "./context.js";
5
+ import { generateBackgroundSyncCode } from "../../../runtime/background-sync.js";
5
6
  export function generateBackgroundSync(ctx) {
6
- const ext = ctx.ext;
7
- const ts = ext === "ts";
8
- const T = (type) => (ts ? `: ${type}` : "");
9
- const R = (type) => (ts ? `: ${type} ` : " ");
10
- const code = `/**
11
- * Swoff Background Sync
12
- * Register sync events for processing mutation queue after tab close.
13
- * Falls back to online event listener in unsupported browsers.
14
- *
15
- * Usage:
16
- * import { syncWhenPossible } from './swoff/background-sync.${ext}';
17
- *
18
- * await syncWhenPossible({
19
- * method: "POST",
20
- * url: "/api/todos",
21
- * body: { title: "Grocery" },
22
- * tags: ["todos"],
23
- * tags: ["todos"],
24
- * });
25
- */
26
-
27
- import { queueMutation, processMutationQueue, getPendingCount } from "./mutation-queue.${ext}";
28
-
29
- const SYNC_TAG = "sync-mutations";
30
-
31
- async function registerSync()${R("Promise<void>")}{
32
- if (!("serviceWorker" in navigator) || !("SyncManager" in window)) {
33
- window.addEventListener("online", processMutationQueue, { once: true });
34
- return;
35
- }
36
-
37
- try {
38
- const registration = await navigator.serviceWorker.ready;
39
- await registration.sync.register(SYNC_TAG);
40
- } catch {
41
- window.addEventListener("online", processMutationQueue, { once: true });
42
- }
43
- }
44
-
45
- /** Queue a mutation and register a background sync event so it runs even after tab close. */
46
- export async function syncWhenPossible(mutation${T("object")})${R("Promise<void>")}{
47
- await queueMutation(mutation);
48
- await registerSync();
49
- }
50
-
51
- /** Re-register a background sync if mutations are still pending. Called automatically after each sync cycle. */
52
- export async function retrySync()${R("Promise<void>")}{
53
- if (!("serviceWorker" in navigator) || !("SyncManager" in window)) return;
54
- const count = await getPendingCount();
55
- if (count > 0) {
56
- await registerSync();
57
- }
58
- }
59
-
60
- window.addEventListener("mutation-sync-complete", retrySync);
61
- `;
62
- writeFile(ctx, `background-sync.${ext}`, code);
7
+ writeFile(ctx, `offline/sync.${ctx.ext}`, generateBackgroundSyncCode({ ts: ctx.ext === "ts", ext: ctx.ext }));
63
8
  }
64
9
  //# sourceMappingURL=background-sync.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"background-sync.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/background-sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,sBAAsB,CAAC,GAAqB;IAC1D,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IACxB,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpD,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEtD,MAAM,IAAI,GAAG;;;;;;iEAMkD,GAAG;;;;;;;;;;;yFAWqB,GAAG;;;;+BAI7D,CAAC,CAAC,eAAe,CAAC;;;;;;;;;;;;;;;iDAeA,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC;;;;;;mCAM/C,CAAC,CAAC,eAAe,CAAC;;;;;;;;;CASpD,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,mBAAmB,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC"}
1
+ {"version":3,"file":"background-sync.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/background-sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAEjF,MAAM,UAAU,sBAAsB,CAAC,GAAqB;IAC1D,SAAS,CAAC,GAAG,EAAE,gBAAgB,GAAG,CAAC,GAAG,EAAE,EAAE,0BAA0B,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,GAAG,KAAK,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;AAChH,CAAC"}
@@ -1,34 +1,6 @@
1
1
  import { writeFile } from "./context.js";
2
+ import { generateCacheCode } from "../../../runtime/cache.js";
2
3
  export function generateCache(ctx) {
3
- const ext = ctx.ext;
4
- const ts = ext === "ts";
5
- const T = (type) => (ts ? `: ${type}` : "");
6
- const R = (type) => (ts ? `: ${type} ` : " ");
7
- const code = `/**
8
- * Swoff Cache Invalidation
9
- * Framework-agnostic cache tag invalidation.
10
- *
11
- * Usage:
12
- * import { invalidateByTag, invalidateByTags } from './swoff/cache.${ext}';
13
- *
14
- * // After a mutation, invalidate related cache
15
- * await invalidateByTag("todos");
16
- */
17
-
18
- /** Invalidate all cached responses tagged with the given tag. Sends INVALIDATE_TAG to the SW; the client-injector dispatches cache-invalidated on SW confirmation. */
19
- export async function invalidateByTag(tag${T("string")})${R("Promise<void>")}{
20
- if (!navigator.serviceWorker?.controller) return;
21
- navigator.serviceWorker.controller.postMessage({
22
- type: "INVALIDATE_TAG",
23
- tag,
24
- });
25
- }
26
-
27
- /** Invalidate all cached responses matching any of the given tags. */
28
- export async function invalidateByTags(tags${T("string[]")})${R("Promise<void>")}{
29
- await Promise.all(tags.map((tag) => invalidateByTag(tag)));
30
- }
31
- `;
32
- writeFile(ctx, `cache.${ext}`, code);
4
+ writeFile(ctx, `cache/index.${ctx.ext}`, generateCacheCode({ ts: ctx.ext === "ts", ext: ctx.ext }));
33
5
  }
34
6
  //# sourceMappingURL=cache.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,aAAa,CAAC,GAAqB;IACjD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IACxB,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpD,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEtD,MAAM,IAAI,GAAG;;;;;wEAKyD,GAAG;;;;;;;2CAOhC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC;;;;;;;;;6CAS/B,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC;;;CAG/E,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC"}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,MAAM,UAAU,aAAa,CAAC,GAAqB;IACjD,SAAS,CAAC,GAAG,EAAE,eAAe,GAAG,CAAC,GAAG,EAAE,EAAE,iBAAiB,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,GAAG,KAAK,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;AACtG,CAAC"}
@@ -2,139 +2,11 @@
2
2
  * Generates client-injector.{js|ts} - orchestrator that wires feature modules together.
3
3
  */
4
4
  import { writeFile } from "./context.js";
5
+ import { generateClientInjectorCode } from "../../../runtime/client-injector.js";
5
6
  export function generateClientInjector(ctx) {
6
7
  const ext = ctx.ext;
7
8
  const ts = ext === "ts";
8
- const pwaEnabled = ctx.config.features.pwa.enabled;
9
- const mutationQueueEnabled = ctx.config.features.mutationQueue.enabled;
10
- const tagInvalidation = ctx.config.features.tagInvalidation.enabled;
11
- const pwaImport = pwaEnabled
12
- ? `import { setupPwaInstall } from "./pwa/install.${ext}";
13
- `
14
- : "";
15
- const pwaCall = pwaEnabled ? `setupPwaInstall();\n` : "";
16
- const mutationImport = mutationQueueEnabled
17
- ? `import { processMutationQueue } from "./mutation-queue.${ext}";
18
- `
19
- : "";
20
- const mutationOnlineListener = mutationQueueEnabled
21
- ? `
22
- // --- Mutation Queue Online Listener ---
23
- window.addEventListener("online", processMutationQueue);
24
- `
25
- : "";
26
- const onlineRefetchListener = `
27
- // --- Online Refetch Listener ---
28
- // When connectivity returns, the SW checks stale cache entries and refetches them.
29
- window.addEventListener("online", () => {
30
- if (navigator.serviceWorker.controller) {
31
- navigator.serviceWorker.controller.postMessage({ type: "ONLINE" });
32
- }
33
- });
34
- `;
35
- const focusListener = `
36
- // --- Focus Listener for Reactive Strategy ---
37
- // Notifies the SW when the tab gains focus so it can refresh stale reactive entries.
38
- // Uses visibilitychange only (covers tab switch, window refocus, alt-tab) — single source avoids duplicate FOCUS messages.
39
- if (typeof document !== "undefined") {
40
- document.addEventListener("visibilitychange", () => {
41
- if (document.visibilityState === "visible" && navigator.serviceWorker.controller) {
42
- navigator.serviceWorker.controller.postMessage({ type: "FOCUS" });
43
- }
44
- });
45
- }
46
- `;
47
- const invalidationHandler = tagInvalidation
48
- ? `
49
- if (event.data.type === "TAG_INVALIDATED" && event.data.tag) {
50
- window.dispatchEvent(
51
- new CustomEvent("cache-invalidated", {
52
- detail: { tags: [event.data.tag] },
53
- })
54
- );
55
- }
56
- `
57
- : "";
58
- const swImport = `import { initServiceWorker as swInit } from "./sw/injector.${ext}";
59
- `;
60
- const code = `/**
61
- * Swoff Client Injector
62
- * Orchestrates SW registration, PWA install, and cross-tab sync.
63
- * Single entry point for all Swoff client-side features.
64
- *
65
- * Usage:
66
- * import { initServiceWorker } from './swoff/client-injector.${ext}';
67
- * initServiceWorker();
68
- *
69
- * Window events (dispatched by this module):
70
- * sw-progress - Download progress (detail: { percent, downloaded, total })
71
- * sw-ready - SW active and controlling page
72
- * sw-error - SW registration failed
73
- * cache-invalidated - Cache entries cleared on SW confirmation (detail: { tags })
74
- * swoff:cache-updated - Background refresh completed (detail: { url })
75
- * mutation-sync-complete - Queued mutations synced (detail: { succeeded, failed })
76
- * mutation-sync-progress - Batch progress during sync (detail: { succeeded, failed, total, current })
77
- * mutation-queue-changed - Queue modified
78
- *
79
- * Window events (dispatched by feature modules):
80
- * pwa-installable - PWA can be installed (detail: { isInstallable: true })
81
- * pwa-installed - User accepted install (detail: { outcome: 'accepted' })
82
- * sw-auth-unauthorized - 401 response received
83
- * sw-auth-state-change - Login or logout (detail: { authenticated: boolean })
84
- * sw-update-available - New version ready (detail: { version })
85
- * sw-version-detected - Version info available
86
- */
87
- ${pwaImport}${mutationImport}${swImport}
88
- ${pwaCall}${mutationOnlineListener}${onlineRefetchListener}${focusListener}
89
- // --- SW Message Listener ---
90
- if (typeof window !== "undefined" && "serviceWorker" in navigator) {
91
- navigator.serviceWorker.addEventListener("message", (event) => {
92
- if (event.data.type === "CACHE_UPDATED") {
93
- window.dispatchEvent(
94
- new CustomEvent("swoff:cache-updated", {
95
- detail: { url: event.data.url },
96
- })
97
- );
98
- }
99
- if (event.data.type === "SW_PROGRESS") {
100
- const { percent, downloaded, total } = event.data;
101
- window.dispatchEvent(
102
- new CustomEvent("sw-progress", {
103
- detail: { percent, downloaded, total },
104
- })
105
- );
106
- }
107
- if (event.data.type === "BACKGROUND_SYNC_PROGRESS") {
108
- window.dispatchEvent(
109
- new CustomEvent("mutation-sync-progress", {
110
- detail: event.data.detail,
111
- })
112
- );
113
- }
114
- if (event.data.type === "BACKGROUND_SYNC_COMPLETE") {
115
- const { succeeded, failed, tags } = event.data.detail;
116
- window.dispatchEvent(
117
- new CustomEvent("mutation-sync-complete", {
118
- detail: { succeeded, failed },
119
- })
120
- );
121
- if (tags && tags.length > 0) {
122
- window.dispatchEvent(
123
- new CustomEvent("cache-invalidated", { detail: { tags } })
124
- );
125
- }
126
- window.dispatchEvent(new CustomEvent("mutation-queue-changed"));
127
- }
128
- if (event.data.type === "MUTATION_STORED") {
129
- processMutationQueue();
130
- }${invalidationHandler} });
131
- }
132
-
133
- /** Initialize SW registration and all client-side features (PWA install, mutation queue, cross-tab sync). Call once at app startup. */
134
- export async function initServiceWorker()${ts ? ": Promise<void>" : " "}{
135
- await swInit();
136
- }
137
- `;
9
+ const code = generateClientInjectorCode({ ts, ext }, ctx.config.features.pwa.enabled, ctx.config.features.mutationQueue.enabled, ctx.config.features.serverPush?.enabled ?? false);
138
10
  writeFile(ctx, `client-injector.${ext}`, code);
139
11
  }
140
12
  //# sourceMappingURL=client-injector.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-injector.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/client-injector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,sBAAsB,CAAC,GAAqB;IAC1D,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IACxB,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC;IACnD,MAAM,oBAAoB,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC;IACvE,MAAM,eAAe,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,OAAO,CAAC;IAEpE,MAAM,SAAS,GAAG,UAAU;QAC1B,CAAC,CAAC,kDAAkD,GAAG;CAC1D;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,CAAC;IAEzD,MAAM,cAAc,GAAG,oBAAoB;QACzC,CAAC,CAAC,0DAA0D,GAAG;CAClE;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,sBAAsB,GAAG,oBAAoB;QACjD,CAAC,CAAC;;;CAGL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,qBAAqB,GAAG;;;;;;;;CAQ/B,CAAC;IAEA,MAAM,aAAa,GAAG;;;;;;;;;;;CAWvB,CAAC;IAEA,MAAM,mBAAmB,GAAG,eAAe;QACzC,CAAC,CAAC;;;;;;;;CAQL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,QAAQ,GAAG,8DAA8D,GAAG;CACnF,CAAC;IAEA,MAAM,IAAI,GAAG;;;;;;kEAMmD,GAAG;;;;;;;;;;;;;;;;;;;;;EAqBnE,SAAS,GAAG,cAAc,GAAG,QAAQ;EACrC,OAAO,GAAG,sBAAsB,GAAG,qBAAqB,GAAG,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0CnE,mBAAmB;;;;2CAIiB,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG;;;CAGtE,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,mBAAmB,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC"}
1
+ {"version":3,"file":"client-injector.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/client-injector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAEjF,MAAM,UAAU,sBAAsB,CAAC,GAAqB;IAC1D,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IAExB,MAAM,IAAI,GAAG,0BAA0B,CACrC,EAAE,EAAE,EAAE,GAAG,EAAE,EACX,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAC/B,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EACzC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,IAAI,KAAK,CACjD,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE,mBAAmB,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { writeFile } from "./context.js";
2
+ import { generateFetchStateCode } from "../../../runtime/fetch-state.js";
3
+ export function generateFetchState(ctx) {
4
+ writeFile(ctx, `fetch/state.${ctx.ext}`, generateFetchStateCode({ ts: ctx.ext === "ts", ext: ctx.ext }));
5
+ }
6
+ //# sourceMappingURL=fetch-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-state.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/fetch-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAEzE,MAAM,UAAU,kBAAkB,CAAC,GAAqB;IACtD,SAAS,CAAC,GAAG,EAAE,eAAe,GAAG,CAAC,GAAG,EAAE,EAAE,sBAAsB,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,GAAG,KAAK,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;AAC3G,CAAC"}