@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
@@ -3,303 +3,11 @@
3
3
  * staleTime, prefetching, and cancellation.
4
4
  */
5
5
  import { writeFile } from "./context.js";
6
+ import { generateFetchWrapperCode } from "../../../runtime/fetch-wrapper.js";
6
7
  export function generateFetchWrapper(ctx) {
7
8
  const ext = ctx.ext;
8
9
  const ts = ext === "ts";
9
- const T = (type) => (ts ? `: ${type}` : "");
10
- const R = (type) => (ts ? `: ${type} ` : " ");
11
- const G = (type) => (ts ? `<${type}>` : "");
12
- const tagInvalidation = ctx.config.features.tagInvalidation.enabled;
13
- const authEnabled = ctx.config.features.auth.enabled;
14
- const mutationQueue = ctx.config.features.mutationQueue.enabled;
15
- const importLines = [
16
- tagInvalidation
17
- ? `import { generateTags, invalidateUrl${tagInvalidation && mutationQueue ? ", expandCascading" : ""} } from "./invalidation-tags.${ext}";`
18
- : "",
19
- tagInvalidation ? `import { invalidateByTags } from "./cache.${ext}";` : "",
20
- authEnabled
21
- ? `import { getAuth, clearAuth, withAuthHeaders, isAuthUrl, AUTH_WITH_CREDENTIALS } from "./auth/store.${ext}";`
22
- : "",
23
- mutationQueue
24
- ? `import { queueMutation } from "./mutation-queue.${ext}";`
25
- : "",
26
- ]
27
- .filter(Boolean)
28
- .join("\n");
29
- const interfaceBlock = ts
30
- ? `
31
- export interface FetchWithCacheResult${G("T")} {
32
- response${T("Response & { json(): Promise<T> }")};
33
- fromCache${T("boolean")};
34
- queued${T("boolean")};
35
- }
36
- `
37
- : "";
38
- const optionsInterface = ts
39
- ? `
40
- export interface FetchWithCacheOptions extends RequestInit {
41
- tags?: string[];
42
- auth?: boolean;
43
- queueOffline?: boolean;
44
- invalidate?: 'auto' | string[] | false;
45
- type?: 'read' | 'mutation';
46
- strategy?: 'cache-first' | 'network-first' | 'stale-while-revalidate' | 'cache-only' | 'network-only' | 'reactive';
47
- staleTime?: number;
48
- /** Custom response validation for mutation success. Default: res.ok. Use this when your API returns 200 with { success: false } for logical failures. */
49
- validateSuccess?: (response: Response) => boolean | Promise<boolean>;
50
- /** Override the URL used for auto-invalidation. Defaults to the request URL. Useful when the mutation URL differs from the cache tag URL. */
51
- invalidateUrl?: string;
52
- }
53
- `
54
- : "";
55
- const authBlock = authEnabled
56
- ? `
57
- if (options.auth) {
58
- const auth = await getAuth();
59
- withAuthHeaders(headers, auth);
60
- }`
61
- : "";
62
- const authUrlsBlock = authEnabled
63
- ? `
64
- // Auth endpoints bypass SW cache
65
- if (options.auth && isAuthUrl(url) && !headers.has("X-SW-Cache-Strategy")) {
66
- headers.set("X-SW-Cache-Strategy", "mutation");
67
- }`
68
- : "";
69
- const authCredentialsBlock = authEnabled
70
- ? `
71
- if (AUTH_WITH_CREDENTIALS) {
72
- fetchOptions.credentials = "include";
73
- }`
74
- : "";
75
- const auth401Block = authEnabled
76
- ? `
77
- if (options.auth && response.status === 401) {
78
- await clearAuth();
79
- window.dispatchEvent(new CustomEvent("sw-auth-unauthorized"));
80
- }`
81
- : "";
82
- const mutationTagsBlock = tagInvalidation && mutationQueue
83
- ? ` // Pre-compute invalidation tags for SW-side IDB storage
84
- let mutationTags: string[] = [];
85
- if (!isRead) {
86
- const invalidateSetting = options.invalidate !== false ? (options.invalidate || 'auto') : false;
87
- if (invalidateSetting !== false) {
88
- if (Array.isArray(invalidateSetting)) {
89
- mutationTags = invalidateSetting;
90
- } else {
91
- mutationTags = generateTags(url);
92
- mutationTags = expandCascading(mutationTags);
93
- }
94
- headers.set("X-SW-Invalidate-Tags", mutationTags.join(","));
95
- }
96
- }`
97
- : ` let mutationTags: string[] = options.tags || [];`;
98
- const offlineReadCatchBlock = ` if (options.signal?.aborted) throw new DOMException("The operation was aborted", "AbortError");
99
- const cached = await caches.match(input);
100
- if (cached) return { response: cached, fromCache: true, queued: false };
101
- throw new Error("Offline: no cached data available");`;
102
- const offlineWriteFallbackBlock = mutationQueue
103
- ? ` if (options.queueOffline !== false) {
104
- await queueMutation({
105
- method,
106
- url,
107
- body: options.body,
108
- headers: {},
109
- tags: mutationTags,
110
- timestamp: Date.now(),
111
- });
112
- return {
113
- response: new Response(JSON.stringify({ queued: true }), { status: 202, headers: { "Content-Type": "application/json" } }),
114
- fromCache: false,
115
- queued: true,
116
- };
117
- }`
118
- : ``;
119
- const autoInvalidateBlock = tagInvalidation
120
- ? `
121
- // Auto-invalidate after mutation success (skip if SW queued it)
122
- const mutationSuccess = options.validateSuccess ? await options.validateSuccess(response) : response.ok;
123
- const mutationQueued = response.headers.get("X-SW-Mutation-Queued") === "true";
124
- if (!isRead && mutationSuccess && !mutationQueued) {
125
- const invalidateSetting = options.invalidate !== false ? (options.invalidate || 'auto') : false;
126
- if (invalidateSetting !== false) {
127
- const invalidateTarget = options.invalidateUrl || url;
128
- if (Array.isArray(invalidateSetting)) {
129
- await invalidateByTags(invalidateSetting);
130
- } else {
131
- await invalidateUrl(invalidateTarget);
132
- }
133
- }
134
- }`
135
- : "";
136
- const autoTagsBlock = tagInvalidation
137
- ? `
138
- // Auto-generate tags from URL if not provided
139
- if (!options.tags && isRead) {
140
- const urlTags = generateTags(url);
141
- if (urlTags.length > 0) {
142
- headers.set("X-SW-Cache-Tags", urlTags.join(","));
143
- }
144
- }`
145
- : "";
146
- const code = `/**
147
- * Swoff Fetch Wrapper
148
- * Unified fetch with caching, auth, offline queue, auto-invalidation, staleTime, prefetching, and
149
- * per-request strategy override.
150
- *
151
- * Usage:
152
- * import { fetchWithCache, prefetchCache } from './swoff/fetch-wrapper.${ext}';
153
- *
154
- * // GET — cached with auto-generated tags
155
- * const { response } = await fetchWithCache("/api/todos");
156
- * const data = await response.json();
157
- *
158
- * // POST — mutation with auto-invalidation
159
- * await fetchWithCache("/api/todos", {
160
- * method: "POST",
161
- * body: JSON.stringify({ title: "New task" }),
162
- * });
163
- *
164
- * // Skip auto-invalidation, invalidate manually later
165
- * await fetchWithCache("/api/todos", {
166
- * method: "POST",
167
- * body: JSON.stringify({ title: "New" }),
168
- * invalidate: false,
169
- * });
170
- *
171
- * // Validate mutation success with custom logic
172
- * await fetchWithCache("/api/todos", {
173
- * method: "POST",
174
- * body: JSON.stringify({ title: "New" }),
175
- * validateSuccess: (res) => res.status === 200,
176
- * });
177
- *
178
- * // Custom tags for caching (read) + explicit invalidate tags (mutation)
179
- * await fetchWithCache("/api/todos", {
180
- * tags: ["custom-tag"],
181
- * invalidate: ["custom-tag"],
182
- * });
183
- *
184
- * // Authenticated request (works with bearer, cookie, custom)
185
- * const { response: userRes } = await fetchWithCache("/api/me", { auth: true });
186
- *
187
- * // Prefetch (fire-and-forget warm the cache)
188
- * prefetchCache("/api/todos");
189
- *
190
- * // Override caching strategy per-request (highest priority)
191
- * await fetchWithCache("/api/checkout", {
192
- * method: "POST",
193
- * type: "read",
194
- * strategy: "network-only",
195
- * });
196
- *
197
- * // Support AbortController for cancellation
198
- * const controller = new AbortController();
199
- * setTimeout(() => controller.abort(), 5000);
200
- * const { response } = await fetchWithCache("/api/todos", { signal: controller.signal });
201
- *
202
- * // Offline: auto-queues writes (disable with queueOffline: false)
203
- * await fetchWithCache("/api/todos", {
204
- * method: "POST",
205
- * body: JSON.stringify({ title: "Offline task" }),
206
- * });
207
- * // When back online, processMutationQueue() replays them
208
- */
209
-
210
- ${importLines}
211
- ${interfaceBlock}${optionsInterface}
212
- const inFlightRequests = new Map${G("string, Promise<Response>")}();
213
-
214
- /** Fetch with caching, auth, offline queue, auto-invalidation, and per-request strategy override. Returns { response, fromCache }. Use { auth: true } for authenticated requests — works with bearer, cookie, and custom auth types. */
215
- export async function fetchWithCache${G("T")}(input${T("RequestInfo")}, options${T("RequestInit & FetchWithCacheOptions")} = {})${R("Promise<FetchWithCacheResult<T>>")}{
216
- const method = (options.method || "GET").toUpperCase();
217
- const isRead = options.type === "read" || (options.type !== "mutation" && (method === "GET" || method === "HEAD" || method === "OPTIONS"));
218
- const url = typeof input === "string" ? input : input.url;
219
-
220
- const headers = new Headers(options.headers);
221
-
222
- // Set cache strategy
223
- if (!headers.has("X-SW-Cache-Strategy")) {
224
- headers.set("X-SW-Cache-Strategy", isRead ? "read" : "mutation");
225
- }
226
- ${autoTagsBlock}
227
- // Custom tags override auto-generated
228
- if (options.tags && options.tags.length > 0) {
229
- headers.set("X-SW-Cache-Tags", options.tags.join(","));
230
- }
231
-
232
- if (options.strategy) {
233
- headers.set("X-SW-Strategy", options.strategy);
234
- }
235
- if (options.staleTime !== undefined) {
236
- headers.set("X-SW-Stale-Time", String(options.staleTime));
237
- }
238
- ${authBlock}${authUrlsBlock}
239
- // Forward no-queue option to SW
240
- if (options.queueOffline === false) {
241
- headers.set("X-SW-No-Queue", "true");
242
- }
243
-
244
- const fetchOptions${T("RequestInit")} = { ...options, headers };
245
- ${authCredentialsBlock}
246
-
247
- // Check for abort before proceeding
248
- if (options.signal?.aborted) {
249
- throw new DOMException("The operation was aborted", "AbortError");
250
- }
251
- ${mutationTagsBlock}
252
- // Deduplicate in-flight GET requests
253
- let responsePromise${T("Promise<Response>")};
254
- if (isRead && inFlightRequests.has(url)) {
255
- responsePromise = inFlightRequests.get(url)!.then((r) => r.clone());
256
- } else {
257
- const abortHandler = () => {
258
- inFlightRequests.delete(url);
259
- };
260
- if (options.signal) {
261
- options.signal.addEventListener("abort", abortHandler, { once: true });
262
- }
263
- responsePromise = fetch(input, fetchOptions);
264
- if (isRead) {
265
- const cleanup = () => {
266
- inFlightRequests.delete(url);
267
- if (options.signal) {
268
- options.signal.removeEventListener("abort", abortHandler);
269
- }
270
- };
271
- inFlightRequests.set(url, responsePromise.finally(cleanup));
272
- }
273
- }
274
-
275
- let response${T("Response")};
276
- try {
277
- response = await responsePromise;
278
- } catch (err) {
279
- if (err instanceof TypeError) {
280
- if (isRead) {
281
- ${offlineReadCatchBlock}
282
- }
283
- // SW not controlling — fallback to client-side queue
284
- if (!navigator.serviceWorker?.controller) {
285
- ${offlineWriteFallbackBlock}
286
- }
287
- }
288
- throw err;
289
- }
290
- ${autoInvalidateBlock}${auth401Block}
291
- const fromCache = response.headers.get("X-SW-From-Cache") === "true";
292
- const queued = response.headers.get("X-SW-Mutation-Queued") === "true";
293
- return { response, fromCache, queued };
294
- }
295
-
296
- /** Fire-and-forget prefetch: warms the cache for a URL without blocking. Useful for route prefetching or link hover prefetching. */
297
- export function prefetchCache(input${T("RequestInfo")}, options${T("RequestInit & FetchWithCacheOptions")} = {})${R("void")}{
298
- fetchWithCache(input, { ...options }).catch(() => {
299
- // Prefetch failures are intentionally silent
300
- });
301
- }
302
- `;
303
- writeFile(ctx, `fetch-wrapper.${ext}`, code);
10
+ const code = generateFetchWrapperCode({ ts, ext }, ctx.config.features.auth.enabled, ctx.config.features.auth.userEndpoint, ctx.config.features.mutationQueue.enabled, ctx.config.features.serviceWorker.requestBatchWindowMs);
11
+ writeFile(ctx, `fetch/core.${ext}`, code);
304
12
  }
305
13
  //# sourceMappingURL=fetch-wrapper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fetch-wrapper.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/fetch-wrapper.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fetch-wrapper.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/fetch-wrapper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAE7E,MAAM,UAAU,oBAAoB,CAAC,GAAqB;IACxD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IAExB,MAAM,IAAI,GAAG,wBAAwB,CACnC,EAAE,EAAE,EAAE,GAAG,EAAE,EACX,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAChC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EACrC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EACzC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,oBAAoB,CACvD,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { copyFileSync, existsSync, mkdirSync } from "fs";
2
+ import { join, dirname } from "path";
3
+ import { fileURLToPath } from "url";
4
+ const __dirname = dirname(fileURLToPath(import.meta.url));
5
+ const templatesDir = join(__dirname, "../../../../templates");
6
+ function copyAdapter(frameworkDir, name, ext, outputDir) {
7
+ const src = join(frameworkDir, `${name}.${ext}x`);
8
+ if (existsSync(src)) {
9
+ copyFileSync(src, join(outputDir, `${name}.${ext}x`));
10
+ }
11
+ else {
12
+ const jsSrc = src.replace(`.${ext}x`, ".jsx");
13
+ if (existsSync(jsSrc)) {
14
+ copyFileSync(jsSrc, join(outputDir, `${name}.${ext}x`));
15
+ }
16
+ }
17
+ }
18
+ const ADAPTERS = [
19
+ { name: "useNetworkStatus" },
20
+ { name: "useCachedFetch" },
21
+ { name: "useMutation" },
22
+ { name: "usePrefetch" },
23
+ { name: "useMutationState" },
24
+ { name: "useCacheInvalidation" },
25
+ { name: "useSwoffReset" },
26
+ { name: "useIsFetching" },
27
+ { name: "useSWUpdate", condition: (c) => c.config.features.pwa.enabled },
28
+ { name: "useAuth", condition: (c) => c.config.features.auth.enabled },
29
+ { name: "useMutationQueue", condition: (c) => c.config.features.mutationQueue.enabled },
30
+ { name: "usePushSubscription", condition: (c) => c.config.features.pushNotifications?.enabled ?? false },
31
+ { name: "useBackgroundSync", condition: (c) => !!c.config.features.backgroundSync },
32
+ ];
33
+ const OUTPUT_SUBDIRS = {
34
+ react: "adapters",
35
+ vue: "adapters",
36
+ svelte: "adapters",
37
+ solid: "adapters",
38
+ };
39
+ export function generateFrameworkAdapters(ctx) {
40
+ const subdir = OUTPUT_SUBDIRS[ctx.frameworkName];
41
+ if (!subdir)
42
+ return;
43
+ const frameworkDir = join(templatesDir, ctx.frameworkName);
44
+ if (!existsSync(frameworkDir))
45
+ return;
46
+ const outDir = join(ctx.swoffDir, subdir);
47
+ if (!existsSync(outDir)) {
48
+ mkdirSync(outDir, { recursive: true });
49
+ }
50
+ for (const a of ADAPTERS) {
51
+ if (!a.condition || a.condition(ctx)) {
52
+ copyAdapter(frameworkDir, a.name, ctx.ext, outDir);
53
+ }
54
+ }
55
+ }
56
+ //# sourceMappingURL=generate-framework-adapters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-framework-adapters.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/generate-framework-adapters.ts"],"names":[],"mappings":"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"}
@@ -36,8 +36,9 @@ export function generateHooks(ctx) {
36
36
  if (config.features.backgroundSync) {
37
37
  copyHook(hooksDir, "useBackgroundSync", ext);
38
38
  }
39
- if (config.features.tagInvalidation.enabled) {
40
- copyHook(hooksDir, "useCacheInvalidation", ext);
41
- }
39
+ copyHook(hooksDir, "useCacheInvalidation", ext);
40
+ // Phase 2 — always generated
41
+ copyHook(hooksDir, "useSwoffReset", ext);
42
+ copyHook(hooksDir, "useIsFetching", ext);
42
43
  }
43
44
  //# sourceMappingURL=generate-hooks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"generate-hooks.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/generate-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAGpC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,6BAA6B,CAAC,CAAC;AAEpE,SAAS,QAAQ,CAAC,QAAgB,EAAE,IAAY,EAAE,GAAW;IAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,GAAG,IAAI,IAAI,GAAG,GAAG,CAAC,CAAC;IAClD,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,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,yBAAyB;IACzB,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,CAAC,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,CAAC,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,CAAC,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC;IAE5C,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAChC,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,CAAC,CAAC;IACzC,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;QAC1C,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,EAAE,CAAC;QAC/C,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC;QACnC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,EAAE,GAAG,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC;QAC5C,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,EAAE,GAAG,CAAC,CAAC;IAClD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"generate-hooks.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/generate-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAGpC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,6BAA6B,CAAC,CAAC;AAEpE,SAAS,QAAQ,CAAC,QAAgB,EAAE,IAAY,EAAE,GAAW;IAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,GAAG,IAAI,IAAI,GAAG,GAAG,CAAC,CAAC;IAClD,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,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,yBAAyB;IACzB,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,CAAC,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,CAAC,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,CAAC,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC;IAE5C,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAChC,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,CAAC,CAAC;IACzC,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;QAC1C,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,EAAE,CAAC;QAC/C,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC;QACnC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,EAAE,GAAG,CAAC,CAAC;IAC/C,CAAC;IACD,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,EAAE,GAAG,CAAC,CAAC;IAEhD,6BAA6B;IAC7B,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,CAAC,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,CAAC,CAAC;AAC3C,CAAC"}
@@ -1,139 +1,10 @@
1
1
  import { writeFile } from "./context.js";
2
+ import { generateGqlWrapperCode } from "../../../runtime/gql-wrapper.js";
2
3
  export function generateGqlWrapper(ctx) {
3
4
  const ext = ctx.ext;
4
5
  const ts = ext === "ts";
5
- const T = (type) => (ts ? `: ${type}` : "");
6
- const R = (type) => (ts ? `: ${type} ` : " ");
7
- const G = (type) => (ts ? `<${type}>` : "");
8
- const AS = (type) => (ts ? ` as ${type}` : "");
9
6
  const endpoint = ctx.config.features.graphql.endpoint;
10
- const optionsInterface = ts
11
- ? `
12
- export interface GqlOptions {
13
- variables?: Record<string, unknown>;
14
- tags?: string[];
15
- auth?: boolean;
16
- queueOffline?: boolean;
17
- invalidate?: 'auto' | string[] | false;
18
- }
19
- `
20
- : "";
21
- const code = `/**
22
- * Swoff GraphQL Wrapper
23
- * Brings Swoff's caching, offline queue, and tag-based invalidation to GraphQL APIs.
24
- * Hashes query + variables for deterministic cache keys and auto-generates tags
25
- * from operation names. Built on top of fetchWithCache.
26
- *
27
- * Usage:
28
- * import { fetchWithGql, queryGql, mutateGql } from './swoff/gql-wrapper.${ext}';
29
- *
30
- * // Query — cached with body-hash key
31
- * const { data } = await queryGql("{ todos { id title } }");
32
- *
33
- * // Query with variables
34
- * const { data: todo } = await queryGql(
35
- * "query GetTodo($id: ID!) { todo(id: $id) { id title } }",
36
- * { id: "42" }
37
- * );
38
- *
39
- * // Mutation — auto-invalidates related cache tags
40
- * const { data: created } = await mutateGql(
41
- * "mutation CreateTodo($title: String!) { createTodo(title: $title) { id } }",
42
- * { title: "New task" }
43
- * );
44
- *
45
- * // Authenticated
46
- * const { data } = await queryGql("query Me { me { name } }", {}, { auth: true });
47
- *
48
- * // Offline: mutations are auto-queued
49
- * const { data } = await mutateGql(
50
- * "mutation CreateTodo($title: String!) { createTodo(title: $title) { id } }",
51
- * { title: "Offline task" },
52
- * { queueOffline: true }
53
- * );
54
- */
55
-
56
- import { fetchWithCache } from "./fetch-wrapper.${ext}";
57
- import type { GqlResult } from "./swoff";
58
- ${optionsInterface}
59
- /** Extract operation name from a GraphQL document. Returns null for anonymous queries (e.g. "{ todos { id } }"). */
60
- function getOperationName(query${T("string")})${T("string | null")}{
61
- const match = query.match(/(query|mutation|subscription)\\s+(\\w+)/);
62
- return match ? match[2] : null;
63
- }
64
-
65
- /** Determine if a GraphQL document is a query (read) vs mutation/subscription (write). */
66
- function isReadOperation(query${T("string")})${T("boolean")}{
67
- const trimmed = query.trim();
68
- if (trimmed.startsWith("mutation") || trimmed.startsWith("subscription")) return false;
69
- return true;
70
- }
71
-
72
- /** Hash an object into a hex string for deterministic cache keying. Uses SHA-256 via SubtleCrypto. */
73
- async function bodyHash(obj${T("unknown")})${T("Promise<string>")}{
74
- const json = JSON.stringify(obj);
75
- const bytes = new TextEncoder().encode(json);
76
- const hash = await crypto.subtle.digest("SHA-256", bytes);
77
- return Array.from(new Uint8Array(hash)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 16);
78
- }
79
-
80
- /** Generate cache-relevant tags from a GQL operation name. e.g. "getTodos" → ["todos"], "createTodo" → ["todos", "todo"]. */
81
- function tagsFromOpName(name${T("string | null")})${T("string[]")}{
82
- if (!name) return [];
83
- const stripped = name.replace(/^(get|fetch|list|all|query)/i, "").replace(/^(create|set|add|new|update|delete|remove)/i, "");
84
- if (!stripped) return [name.toLowerCase()];
85
- const tag = stripped.charAt(0).toLowerCase() + stripped.slice(1);
86
- const plural = tag.replace(/s$/, "") + "s";
87
- return [plural, tag];
88
- }
89
-
90
- /** Fetch a GraphQL endpoint with Swoff's caching, auth, offline queue, and auto-invalidation. Hashes query + variables for deterministic cache keys. */
91
- export async function fetchWithGql${G("T")}(
92
- query${T("string")},
93
- options${T("GqlOptions")} = {}
94
- )${R("Promise<GqlResult<T>>")}{
95
- const isRead = isReadOperation(query);
96
- const opName = getOperationName(query);
97
- const variables = options.variables;
98
- const hash = await bodyHash({ query, variables });
99
- const tags = options.tags || tagsFromOpName(opName);
100
-
101
- const { response, fromCache } = await fetchWithCache("${endpoint}", {
102
- method: "POST",
103
- body: JSON.stringify({ query, variables }),
104
- headers: {
105
- "Content-Type": "application/json",
106
- "X-SW-Cache-Key": "gql:" + hash,
107
- },
108
- tags,
109
- type: isRead ? "read" : "mutation",
110
- auth: options.auth,
111
- queueOffline: options.queueOffline,
112
- invalidate: options.invalidate,
113
- });
114
-
115
- const result = await response.json();
116
- return { data: result.data${AS("T")}, fromCache };
117
- }
118
-
119
- /** Shorthand for GraphQL queries (type: "read"). Cached by default with body-hash key. */
120
- export async function queryGql${G("T")}(
121
- query${T("string")},
122
- variables${T("Record<string, unknown> | undefined")} = undefined,
123
- options${T("GqlOptions")} = {}
124
- )${R("Promise<GqlResult<T>>")}{
125
- return fetchWithGql${G("T")}(query, { ...options, variables });
126
- }
127
-
128
- /** Shorthand for GraphQL mutations (type: "mutation"). Auto-invalidates related cache tags. */
129
- export async function mutateGql${G("T")}(
130
- mutation${T("string")},
131
- variables${T("Record<string, unknown> | undefined")} = undefined,
132
- options${T("GqlOptions")} = {}
133
- )${R("Promise<GqlResult<T>>")}{
134
- return fetchWithGql${G("T")}(mutation, { ...options, variables });
135
- }
136
- `;
137
- writeFile(ctx, `gql-wrapper.${ext}`, code);
7
+ const code = generateGqlWrapperCode({ ts, ext }, endpoint);
8
+ writeFile(ctx, `graphql/index.${ext}`, code);
138
9
  }
139
10
  //# sourceMappingURL=gql-wrapper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gql-wrapper.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/gql-wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,kBAAkB,CAAC,GAAqB;IACtD,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,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpD,MAAM,EAAE,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC;IAEtD,MAAM,gBAAgB,GAAG,EAAE;QACzB,CAAC,CAAC;;;;;;;;CAQL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,IAAI,GAAG;;;;;;;8EAO+D,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;kDA4B/B,GAAG;;EAEnD,gBAAgB;;iCAEe,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC;;;;;;gCAMlC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC;;;;;;;6BAO9B,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,iBAAiB,CAAC;;;;;;;;8BAQnC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC;;;;;;;;;;oCAU7B,CAAC,CAAC,GAAG,CAAC;SACjC,CAAC,CAAC,QAAQ,CAAC;WACT,CAAC,CAAC,YAAY,CAAC;GACvB,CAAC,CAAC,uBAAuB,CAAC;;;;;;;0DAO6B,QAAQ;;;;;;;;;;;;;;;8BAepC,EAAE,CAAC,GAAG,CAAC;;;;gCAIL,CAAC,CAAC,GAAG,CAAC;SAC7B,CAAC,CAAC,QAAQ,CAAC;aACP,CAAC,CAAC,qCAAqC,CAAC;WAC1C,CAAC,CAAC,YAAY,CAAC;GACvB,CAAC,CAAC,uBAAuB,CAAC;uBACN,CAAC,CAAC,GAAG,CAAC;;;;iCAII,CAAC,CAAC,GAAG,CAAC;YAC3B,CAAC,CAAC,QAAQ,CAAC;aACV,CAAC,CAAC,qCAAqC,CAAC;WAC1C,CAAC,CAAC,YAAY,CAAC;GACvB,CAAC,CAAC,uBAAuB,CAAC;uBACN,CAAC,CAAC,GAAG,CAAC;;CAE5B,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,eAAe,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC"}
1
+ {"version":3,"file":"gql-wrapper.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/gql-wrapper.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,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IACxB,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC;IAEtD,MAAM,IAAI,GAAG,sBAAsB,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;IAE3D,SAAS,CAAC,GAAG,EAAE,iBAAiB,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC/C,CAAC"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Generates GUIDE.md — points user to online documentation.
2
+ * Generates GUIDE.md — points user to online documentation and PWA asset info.
3
3
  */
4
4
  import { writeFile } from "./context.js";
5
5
  export function generateGuide(ctx) {
@@ -9,6 +9,34 @@ export function generateGuide(ctx) {
9
9
  w("");
10
10
  w("Your project was generated with Swoff. All generated files live in `swoff/`.");
11
11
  w("");
12
+ if (ctx.config.features.pwa.enabled && ctx.config.features.pwa.assets.source) {
13
+ w("## PWA Assets");
14
+ w("");
15
+ w("PWA assets (icons, favicon, OG image, splash screens) will be generated from your");
16
+ w(` source logo during \`swoff generate\`.`);
17
+ w("");
18
+ w("To regenerate manually:");
19
+ w("");
20
+ w(" swoff assets --source <path>");
21
+ w("");
22
+ w("### What gets generated");
23
+ w("");
24
+ w("- PWA icons: 64×64, 192×192, 512×512, maskable 512×512");
25
+ w("- Apple touch icon: 180×180");
26
+ w("- Apple splash screens: all device resolutions");
27
+ w("- Favicon: SVG + ICO (16×16, 32×32, 48×48)");
28
+ w("- OG image: 1200×630 (also used for Twitter card)");
29
+ w("");
30
+ w("After generation, reference these assets in your app manually. Run \`swoff assets\` for a copy-paste guide with the exact <link> and <meta> tags.");
31
+ w("");
32
+ w("### Source logo requirements");
33
+ w("");
34
+ w("- **SVG** recommended — produces the best quality at all sizes");
35
+ w("- PNG or JPG accepted — will be upscaled if needed");
36
+ w("- Minimum 512×512 for crisp icons");
37
+ w("- Transparent backgrounds work well with theme colors");
38
+ w("");
39
+ }
12
40
  w("For the full documentation, visit:");
13
41
  w("");
14
42
  w("- **Documentation** — https://swoff.dev/docs");
@@ -1 +1 @@
1
- {"version":3,"file":"guide-generator.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/guide-generator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,aAAa,CAAC,GAAqB;IACjD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEvC,CAAC,CAAC,2BAA2B,CAAC,CAAC;IAC/B,CAAC,CAAC,EAAE,CAAC,CAAC;IACN,CAAC,CACC,8EAA8E,CAC/E,CAAC;IACF,CAAC,CAAC,EAAE,CAAC,CAAC;IACN,CAAC,CAAC,oCAAoC,CAAC,CAAC;IACxC,CAAC,CAAC,EAAE,CAAC,CAAC;IACN,CAAC,CAAC,8CAA8C,CAAC,CAAC;IAClD,CAAC,CAAC,EAAE,CAAC,CAAC;IACN,CAAC,CAAC,uFAAuF,CAAC,CAAC;IAC3F,CAAC,CAAC,EAAE,CAAC,CAAC;IAEN,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/C,CAAC"}
1
+ {"version":3,"file":"guide-generator.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/guide-generator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,aAAa,CAAC,GAAqB;IACjD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEvC,CAAC,CAAC,2BAA2B,CAAC,CAAC;IAC/B,CAAC,CAAC,EAAE,CAAC,CAAC;IACN,CAAC,CACC,8EAA8E,CAC/E,CAAC;IACF,CAAC,CAAC,EAAE,CAAC,CAAC;IAEN,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QAC7E,CAAC,CAAC,eAAe,CAAC,CAAC;QACnB,CAAC,CAAC,EAAE,CAAC,CAAC;QACN,CAAC,CAAC,mFAAmF,CAAC,CAAC;QACvF,CAAC,CAAC,yCAAyC,CAAC,CAAC;QAC7C,CAAC,CAAC,EAAE,CAAC,CAAC;QACN,CAAC,CAAC,yBAAyB,CAAC,CAAC;QAC7B,CAAC,CAAC,EAAE,CAAC,CAAC;QACN,CAAC,CAAC,gCAAgC,CAAC,CAAC;QACpC,CAAC,CAAC,EAAE,CAAC,CAAC;QACN,CAAC,CAAC,yBAAyB,CAAC,CAAC;QAC7B,CAAC,CAAC,EAAE,CAAC,CAAC;QACN,CAAC,CAAC,wDAAwD,CAAC,CAAC;QAC5D,CAAC,CAAC,6BAA6B,CAAC,CAAC;QACjC,CAAC,CAAC,gDAAgD,CAAC,CAAC;QACpD,CAAC,CAAC,4CAA4C,CAAC,CAAC;QAChD,CAAC,CAAC,mDAAmD,CAAC,CAAC;QACvD,CAAC,CAAC,EAAE,CAAC,CAAC;QACN,CAAC,CAAC,mJAAmJ,CAAC,CAAC;QACvJ,CAAC,CAAC,EAAE,CAAC,CAAC;QACN,CAAC,CAAC,8BAA8B,CAAC,CAAC;QAClC,CAAC,CAAC,EAAE,CAAC,CAAC;QACN,CAAC,CAAC,gEAAgE,CAAC,CAAC;QACpE,CAAC,CAAC,oDAAoD,CAAC,CAAC;QACxD,CAAC,CAAC,mCAAmC,CAAC,CAAC;QACvC,CAAC,CAAC,uDAAuD,CAAC,CAAC;QAC3D,CAAC,CAAC,EAAE,CAAC,CAAC;IACR,CAAC;IAED,CAAC,CAAC,oCAAoC,CAAC,CAAC;IACxC,CAAC,CAAC,EAAE,CAAC,CAAC;IACN,CAAC,CAAC,8CAA8C,CAAC,CAAC;IAClD,CAAC,CAAC,EAAE,CAAC,CAAC;IACN,CAAC,CAAC,uFAAuF,CAAC,CAAC;IAC3F,CAAC,CAAC,EAAE,CAAC,CAAC;IAEN,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/C,CAAC"}