@swoff/cli 0.3.7 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -610
- package/dist/__tests__/assemble-sw.test.js +4 -4
- package/dist/__tests__/assemble-sw.test.js.map +1 -1
- package/dist/__tests__/config-types.test.js +7 -4
- package/dist/__tests__/config-types.test.js.map +1 -1
- package/dist/__tests__/validator.test.js +50 -1
- package/dist/__tests__/validator.test.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/commands/add.js +5 -4
- package/dist/lib/commands/add.js.map +1 -1
- package/dist/lib/commands/generate-guide.js +3 -3
- package/dist/lib/commands/generate-guide.js.map +1 -1
- package/dist/lib/commands/info.js +29 -6
- package/dist/lib/commands/info.js.map +1 -1
- package/dist/lib/config/validator.js +85 -4
- package/dist/lib/config/validator.js.map +1 -1
- package/dist/lib/generators/file-generators/client-injector.js +1 -1
- package/dist/lib/generators/file-generators/client-injector.js.map +1 -1
- package/dist/lib/generators/file-generators/fetch-wrapper.js +55 -14
- package/dist/lib/generators/file-generators/fetch-wrapper.js.map +1 -1
- package/dist/lib/generators/file-generators/generate-hooks.js +5 -1
- package/dist/lib/generators/file-generators/generate-hooks.js.map +1 -1
- package/dist/lib/generators/file-generators/gql-wrapper.js +152 -0
- package/dist/lib/generators/file-generators/gql-wrapper.js.map +1 -0
- package/dist/lib/generators/file-generators/guide-generator.js +214 -10
- package/dist/lib/generators/file-generators/guide-generator.js.map +1 -1
- package/dist/lib/generators/file-generators/mutation-queue.js +117 -49
- package/dist/lib/generators/file-generators/mutation-queue.js.map +1 -1
- package/dist/lib/generators/file-generators/mutation-state.js +126 -0
- package/dist/lib/generators/file-generators/mutation-state.js.map +1 -0
- package/dist/lib/generators/file-generators/quick-readme.js +59 -9
- package/dist/lib/generators/file-generators/quick-readme.js.map +1 -1
- package/dist/lib/generators/file-generators/server-push.js +136 -0
- package/dist/lib/generators/file-generators/server-push.js.map +1 -0
- package/dist/lib/generators/file-generators/type-definitions.js +28 -0
- package/dist/lib/generators/file-generators/type-definitions.js.map +1 -1
- package/dist/lib/generators/sw-sections/assemble-sw.js +6 -1
- package/dist/lib/generators/sw-sections/assemble-sw.js.map +1 -1
- package/dist/lib/generators/sw-sections/background-sync-handler.js +22 -8
- package/dist/lib/generators/sw-sections/background-sync-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/config-header.js +1 -1
- package/dist/lib/generators/sw-sections/config-header.js.map +1 -1
- package/dist/lib/generators/sw-sections/default-template.js +2 -1
- package/dist/lib/generators/sw-sections/default-template.js.map +1 -1
- package/dist/lib/generators/sw-sections/fetch-handler.js +137 -98
- package/dist/lib/generators/sw-sections/fetch-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/server-push-handler.js +114 -0
- package/dist/lib/generators/sw-sections/server-push-handler.js.map +1 -0
- package/dist/lib/generators/sw-sections/tag-management.js +6 -5
- package/dist/lib/generators/sw-sections/tag-management.js.map +1 -1
- package/dist/lib/generators/swoff-files-generator.js +7 -1
- package/dist/lib/generators/swoff-files-generator.js.map +1 -1
- package/dist/lib/shared/config-types.js +40 -2
- package/dist/lib/shared/config-types.js.map +1 -1
- package/package.json +1 -1
- package/templates/hooks/useCachedFetch.jsx +43 -4
- package/templates/hooks/useCachedFetch.tsx +49 -6
- package/templates/hooks/useMutation.jsx +76 -0
- package/templates/hooks/useMutation.tsx +97 -0
- package/templates/hooks/useMutationQueue.jsx +19 -11
- package/templates/hooks/useMutationQueue.tsx +30 -15
- package/templates/hooks/useMutationState.jsx +27 -0
- package/templates/hooks/useMutationState.tsx +41 -0
- package/templates/hooks/usePrefetch.jsx +10 -0
- package/templates/hooks/usePrefetch.tsx +25 -0
|
@@ -15,6 +15,30 @@ export function validateConfig(config) {
|
|
|
15
15
|
continue;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
+
else if (key === "mutationQueue") {
|
|
19
|
+
if (typeof value !== "boolean" && (typeof value !== "object" || value === null)) {
|
|
20
|
+
errors.push('Feature "mutationQueue" must be a boolean or an object');
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (typeof value === "object") {
|
|
24
|
+
const mq = value;
|
|
25
|
+
if (mq.enabled !== undefined && typeof mq.enabled !== "boolean") {
|
|
26
|
+
errors.push("features.mutationQueue.enabled must be a boolean");
|
|
27
|
+
}
|
|
28
|
+
if (mq.batchSize !== undefined && (typeof mq.batchSize !== "number" || mq.batchSize < 1 || !Number.isInteger(mq.batchSize))) {
|
|
29
|
+
errors.push("features.mutationQueue.batchSize must be a positive integer");
|
|
30
|
+
}
|
|
31
|
+
if (mq.batchDelayMs !== undefined && (typeof mq.batchDelayMs !== "number" || mq.batchDelayMs < 0 || !Number.isInteger(mq.batchDelayMs))) {
|
|
32
|
+
errors.push("features.mutationQueue.batchDelayMs must be a non-negative integer");
|
|
33
|
+
}
|
|
34
|
+
if (mq.maxRetries !== undefined && (typeof mq.maxRetries !== "number" || mq.maxRetries < 1 || !Number.isInteger(mq.maxRetries))) {
|
|
35
|
+
errors.push("features.mutationQueue.maxRetries must be a positive integer");
|
|
36
|
+
}
|
|
37
|
+
if (mq.retryBackoffMs !== undefined && (typeof mq.retryBackoffMs !== "number" || mq.retryBackoffMs < 0)) {
|
|
38
|
+
errors.push("features.mutationQueue.retryBackoffMs must be a non-negative number");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
18
42
|
else if (!KNOWN_FEATURES.includes(key)) {
|
|
19
43
|
errors.push(`Unknown feature "${key}"`);
|
|
20
44
|
continue;
|
|
@@ -45,12 +69,44 @@ export function validateConfig(config) {
|
|
|
45
69
|
}
|
|
46
70
|
if (sw.strategies && typeof sw.strategies === "object") {
|
|
47
71
|
const strategies = sw.strategies;
|
|
48
|
-
for (const [pattern,
|
|
49
|
-
if (
|
|
50
|
-
|
|
72
|
+
for (const [pattern, entry] of Object.entries(strategies)) {
|
|
73
|
+
if (typeof entry === "string") {
|
|
74
|
+
if (!VALID_STRATEGIES.includes(entry)) {
|
|
75
|
+
errors.push(`Invalid strategy "${entry}" for pattern "${pattern}". Must be one of: ${VALID_STRATEGIES.join(", ")}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (typeof entry === "object" && entry !== null) {
|
|
79
|
+
const obj = entry;
|
|
80
|
+
if (obj.strategy && !VALID_STRATEGIES.includes(obj.strategy)) {
|
|
81
|
+
errors.push(`Invalid strategy "${obj.strategy}" for pattern "${pattern}". Must be one of: ${VALID_STRATEGIES.join(", ")}`);
|
|
82
|
+
}
|
|
83
|
+
if (obj.staleTime !== undefined && (typeof obj.staleTime !== "number" || obj.staleTime < 0)) {
|
|
84
|
+
errors.push(`features.serviceWorker.strategies["${pattern}"].staleTime must be a non-negative number`);
|
|
85
|
+
}
|
|
86
|
+
if (obj.maxCacheEntries !== undefined && (typeof obj.maxCacheEntries !== "number" || obj.maxCacheEntries < 1 || !Number.isInteger(obj.maxCacheEntries))) {
|
|
87
|
+
errors.push(`features.serviceWorker.strategies["${pattern}"].maxCacheEntries must be a positive integer`);
|
|
88
|
+
}
|
|
89
|
+
if (obj.maxCacheAge !== undefined && (typeof obj.maxCacheAge !== "number" || obj.maxCacheAge < 0)) {
|
|
90
|
+
errors.push(`features.serviceWorker.strategies["${pattern}"].maxCacheAge must be a non-negative number`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
errors.push(`features.serviceWorker.strategies["${pattern}"] must be a string or an object`);
|
|
51
95
|
}
|
|
52
96
|
}
|
|
53
97
|
}
|
|
98
|
+
if (sw.staleTime !== undefined && (typeof sw.staleTime !== "number" || sw.staleTime < 0)) {
|
|
99
|
+
errors.push("features.serviceWorker.staleTime must be a non-negative number");
|
|
100
|
+
}
|
|
101
|
+
if (sw.refetchOnWindowFocus !== undefined && typeof sw.refetchOnWindowFocus !== "boolean") {
|
|
102
|
+
errors.push("features.serviceWorker.refetchOnWindowFocus must be a boolean");
|
|
103
|
+
}
|
|
104
|
+
if (sw.refetchOnReconnect !== undefined && typeof sw.refetchOnReconnect !== "boolean") {
|
|
105
|
+
errors.push("features.serviceWorker.refetchOnReconnect must be a boolean");
|
|
106
|
+
}
|
|
107
|
+
if (sw.refetchInterval !== undefined && (typeof sw.refetchInterval !== "number" || sw.refetchInterval < 0 || !Number.isInteger(sw.refetchInterval))) {
|
|
108
|
+
errors.push("features.serviceWorker.refetchInterval must be a non-negative integer");
|
|
109
|
+
}
|
|
54
110
|
if (sw.clearRuntimeOnUpdate !== undefined && typeof sw.clearRuntimeOnUpdate !== "boolean") {
|
|
55
111
|
errors.push("features.serviceWorker.clearRuntimeOnUpdate must be a boolean");
|
|
56
112
|
}
|
|
@@ -90,7 +146,8 @@ export function validateConfig(config) {
|
|
|
90
146
|
}
|
|
91
147
|
const backgroundSyncVal = features.backgroundSync;
|
|
92
148
|
const mutationQueueVal = features.mutationQueue;
|
|
93
|
-
|
|
149
|
+
const mqEnabled = typeof mutationQueueVal === "boolean" ? mutationQueueVal : mutationQueueVal?.enabled === true;
|
|
150
|
+
if (backgroundSyncVal === true && !mqEnabled) {
|
|
94
151
|
errors.push("backgroundSync requires mutationQueue to be enabled");
|
|
95
152
|
}
|
|
96
153
|
const auth = features.auth;
|
|
@@ -108,6 +165,30 @@ export function validateConfig(config) {
|
|
|
108
165
|
errors.push("features.auth.userEndpoint must be a string");
|
|
109
166
|
}
|
|
110
167
|
}
|
|
168
|
+
const graphql = features.graphql;
|
|
169
|
+
if (graphql && typeof graphql === "object") {
|
|
170
|
+
if (graphql.enabled !== undefined && typeof graphql.enabled !== "boolean") {
|
|
171
|
+
errors.push("features.graphql.enabled must be a boolean");
|
|
172
|
+
}
|
|
173
|
+
if (graphql.endpoint !== undefined && typeof graphql.endpoint !== "string") {
|
|
174
|
+
errors.push("features.graphql.endpoint must be a string");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const serverPush = features.serverPush;
|
|
178
|
+
if (serverPush && typeof serverPush === "object") {
|
|
179
|
+
if (serverPush.enabled !== undefined && typeof serverPush.enabled !== "boolean") {
|
|
180
|
+
errors.push("features.serverPush.enabled must be a boolean");
|
|
181
|
+
}
|
|
182
|
+
if (serverPush.type !== undefined && !["sse", "websocket"].includes(serverPush.type)) {
|
|
183
|
+
errors.push('features.serverPush.type must be "sse" or "websocket"');
|
|
184
|
+
}
|
|
185
|
+
if (serverPush.endpoint !== undefined && typeof serverPush.endpoint !== "string") {
|
|
186
|
+
errors.push("features.serverPush.endpoint must be a string");
|
|
187
|
+
}
|
|
188
|
+
if (serverPush.reconnectDelayMs !== undefined && (typeof serverPush.reconnectDelayMs !== "number" || serverPush.reconnectDelayMs < 0)) {
|
|
189
|
+
errors.push("features.serverPush.reconnectDelayMs must be a non-negative number");
|
|
190
|
+
}
|
|
191
|
+
}
|
|
111
192
|
}
|
|
112
193
|
const fw = config.framework;
|
|
113
194
|
if (fw !== undefined && typeof fw === "string" && !["react", "vue", "svelte", "vanilla"].includes(fw)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../src/lib/config/validator.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../src/lib/config/validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@ export function generateClientInjector(ctx) {
|
|
|
6
6
|
const ext = ctx.ext;
|
|
7
7
|
const ts = ext === "ts";
|
|
8
8
|
const pwaEnabled = ctx.config.features.pwa.enabled;
|
|
9
|
-
const mutationQueueEnabled = ctx.config.features.mutationQueue;
|
|
9
|
+
const mutationQueueEnabled = ctx.config.features.mutationQueue.enabled;
|
|
10
10
|
const crossTabSync = ctx.config.features.crossTabSync;
|
|
11
11
|
const pwaImport = pwaEnabled
|
|
12
12
|
? `import { setupPwaInstall } from "./pwa/install.${ext}";
|
|
@@ -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;
|
|
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,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC;IAEtD,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,eAAe,GAAG,YAAY;QAClC,CAAC,CAAC;;;;;;;;CAQL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,QAAQ,GAAG,8DAA8D,GAAG;CACnF,CAAC;IAEA,MAAM,IAAI,GAAG;;;;;;kEAMmD,GAAG;;;;;;;;;;;;;;;;;;;;EAoBnE,SAAS,GAAG,cAAc,GAAG,QAAQ;EACrC,OAAO,GAAG,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;OAyB3B,eAAe;;;;2CAIqB,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,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Generates fetch-wrapper.ts/js — unified fetch with caching, auth, offline queue,
|
|
2
|
+
* Generates fetch-wrapper.ts/js — unified fetch with caching, auth, offline queue, auto-invalidation,
|
|
3
|
+
* staleTime, prefetching, and cancellation.
|
|
3
4
|
*/
|
|
4
5
|
import { writeFile } from "./context.js";
|
|
5
6
|
export function generateFetchWrapper(ctx) {
|
|
@@ -10,7 +11,7 @@ export function generateFetchWrapper(ctx) {
|
|
|
10
11
|
const G = (type) => (ts ? `<${type}>` : "");
|
|
11
12
|
const tagInvalidation = ctx.config.features.tagInvalidation;
|
|
12
13
|
const authEnabled = ctx.config.features.auth.enabled;
|
|
13
|
-
const mutationQueue = ctx.config.features.mutationQueue;
|
|
14
|
+
const mutationQueue = ctx.config.features.mutationQueue.enabled;
|
|
14
15
|
const importLines = [
|
|
15
16
|
tagInvalidation
|
|
16
17
|
? `import { generateTags } from "./invalidation-tags.${ext}";`
|
|
@@ -31,9 +32,15 @@ export interface FetchWithCacheResult${G("T")} {
|
|
|
31
32
|
response${T("Response & { json(): Promise<T> }")};
|
|
32
33
|
fromCache${T("boolean")};
|
|
33
34
|
}
|
|
35
|
+
|
|
36
|
+
export interface ResolvedFetchConfig {
|
|
37
|
+
staleTime${T("number")};
|
|
38
|
+
refetchOnWindowFocus${T("boolean")};
|
|
39
|
+
refetchOnReconnect${T("boolean")};
|
|
40
|
+
refetchInterval${T("number")};
|
|
41
|
+
}
|
|
34
42
|
`
|
|
35
43
|
: "";
|
|
36
|
-
const optionsType = ts ? `FetchWithCacheOptions` : `options`;
|
|
37
44
|
const optionsInterface = ts
|
|
38
45
|
? `
|
|
39
46
|
export interface FetchWithCacheOptions extends RequestInit {
|
|
@@ -44,6 +51,7 @@ export interface FetchWithCacheOptions extends RequestInit {
|
|
|
44
51
|
invalidate?: 'auto' | string[] | false;
|
|
45
52
|
type?: 'read' | 'mutation';
|
|
46
53
|
strategy?: 'cache-first' | 'network-first' | 'stale-while-revalidate' | 'cache-only' | 'network-only';
|
|
54
|
+
staleTime?: number;
|
|
47
55
|
}
|
|
48
56
|
`
|
|
49
57
|
: "";
|
|
@@ -75,6 +83,7 @@ export interface FetchWithCacheOptions extends RequestInit {
|
|
|
75
83
|
}`
|
|
76
84
|
: "";
|
|
77
85
|
const offlineReadBlock = ` if (isRead) {
|
|
86
|
+
if (options.signal?.aborted) throw new DOMException("The operation was aborted", "AbortError");
|
|
78
87
|
const cached = await caches.match(input);
|
|
79
88
|
if (cached) return { response: cached, fromCache: true };
|
|
80
89
|
throw new Error("Offline: no cached data available");
|
|
@@ -126,13 +135,17 @@ export interface FetchWithCacheOptions extends RequestInit {
|
|
|
126
135
|
}
|
|
127
136
|
}`
|
|
128
137
|
: "";
|
|
138
|
+
const staleTimeHeaders = ` // Pass staleTime to SW if set at per-request level
|
|
139
|
+
if (options.staleTime !== undefined) {
|
|
140
|
+
headers.set("X-SW-Stale-Time", String(options.staleTime));
|
|
141
|
+
}`;
|
|
129
142
|
const code = `/**
|
|
130
143
|
* Swoff Fetch Wrapper
|
|
131
|
-
* Unified fetch with caching, auth, offline queue, auto-invalidation, and
|
|
144
|
+
* Unified fetch with caching, auth, offline queue, auto-invalidation, staleTime, prefetching, and
|
|
132
145
|
* per-request strategy override.
|
|
133
146
|
*
|
|
134
147
|
* Usage:
|
|
135
|
-
* import { fetchWithCache } from './swoff/fetch-wrapper.${ext}';
|
|
148
|
+
* import { fetchWithCache, prefetchCache } from './swoff/fetch-wrapper.${ext}';
|
|
136
149
|
*
|
|
137
150
|
* // GET — cached with auto-generated tags
|
|
138
151
|
* const { response } = await fetchWithCache("/api/todos");
|
|
@@ -153,6 +166,12 @@ export interface FetchWithCacheOptions extends RequestInit {
|
|
|
153
166
|
* staleWhileRevalidate: true,
|
|
154
167
|
* });
|
|
155
168
|
*
|
|
169
|
+
* // Set staleTime per-request (overrides config — SW handles bg refresh)
|
|
170
|
+
* await fetchWithCache("/api/todos", { staleTime: 30 });
|
|
171
|
+
*
|
|
172
|
+
* // Prefetch (fire-and-forget warm the cache)
|
|
173
|
+
* prefetchCache("/api/todos");
|
|
174
|
+
*
|
|
156
175
|
* // Override caching strategy per-request (highest priority)
|
|
157
176
|
* await fetchWithCache("/api/checkout", {
|
|
158
177
|
* method: "POST",
|
|
@@ -160,13 +179,10 @@ export interface FetchWithCacheOptions extends RequestInit {
|
|
|
160
179
|
* strategy: "network-only",
|
|
161
180
|
* });
|
|
162
181
|
*
|
|
163
|
-
* //
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
* type: "read",
|
|
168
|
-
* body: JSON.stringify({ query: "hello" }),
|
|
169
|
-
* });
|
|
182
|
+
* // Support AbortController for cancellation
|
|
183
|
+
* const controller = new AbortController();
|
|
184
|
+
* setTimeout(() => controller.abort(), 5000);
|
|
185
|
+
* const { response } = await fetchWithCache("/api/todos", { signal: controller.signal });
|
|
170
186
|
*
|
|
171
187
|
* // Offline: auto-queues writes (disable with queueOffline: false)
|
|
172
188
|
* await fetchWithCache("/api/todos", {
|
|
@@ -181,7 +197,7 @@ ${interfaceBlock}${optionsInterface}
|
|
|
181
197
|
const inFlightRequests = new Map${G("string, Promise<Response>")}();
|
|
182
198
|
|
|
183
199
|
/** 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. */
|
|
184
|
-
export async function fetchWithCache${G("T")}(input${T("RequestInfo")}, options${T("RequestInit & { tags?: string[]; staleWhileRevalidate?: boolean; auth?: boolean; queueOffline?: boolean; invalidate?: 'auto' | string[] | false; type?: 'read' | 'mutation'; strategy?: 'cache-first' | 'network-first' | 'stale-while-revalidate' | 'cache-only' | 'network-only' }")} = {})${R("Promise<FetchWithCacheResult<T>>")}{
|
|
200
|
+
export async function fetchWithCache${G("T")}(input${T("RequestInfo")}, options${T("RequestInit & { tags?: string[]; staleWhileRevalidate?: boolean; auth?: boolean; queueOffline?: boolean; invalidate?: 'auto' | string[] | false; type?: 'read' | 'mutation'; strategy?: 'cache-first' | 'network-first' | 'stale-while-revalidate' | 'cache-only' | 'network-only'; staleTime?: number }")} = {})${R("Promise<FetchWithCacheResult<T>>")}{
|
|
185
201
|
const method = (options.method || "GET").toUpperCase();
|
|
186
202
|
const isRead = options.type === "read" || (options.type !== "mutation" && (method === "GET" || method === "HEAD"));
|
|
187
203
|
const url = typeof input === "string" ? input : input.url;
|
|
@@ -204,6 +220,7 @@ ${autoTagsBlock}
|
|
|
204
220
|
if (options.strategy) {
|
|
205
221
|
headers.set("X-SW-Strategy", options.strategy);
|
|
206
222
|
}
|
|
223
|
+
${staleTimeHeaders}
|
|
207
224
|
${authBlock}${authUrlsBlock}
|
|
208
225
|
const fetchOptions${T("RequestInit")} = { ...options, headers };
|
|
209
226
|
${authCredentialsBlock}
|
|
@@ -214,14 +231,31 @@ ${offlineReadBlock}
|
|
|
214
231
|
${offlineWriteBlock}
|
|
215
232
|
}
|
|
216
233
|
|
|
234
|
+
// Check for abort before proceeding
|
|
235
|
+
if (options.signal?.aborted) {
|
|
236
|
+
throw new DOMException("The operation was aborted", "AbortError");
|
|
237
|
+
}
|
|
238
|
+
|
|
217
239
|
// Deduplicate in-flight GET requests
|
|
218
240
|
let responsePromise${T("Promise<Response>")};
|
|
219
241
|
if (isRead && inFlightRequests.has(url)) {
|
|
220
242
|
responsePromise = inFlightRequests.get(url)!.then((r) => r.clone());
|
|
221
243
|
} else {
|
|
244
|
+
const abortHandler = () => {
|
|
245
|
+
inFlightRequests.delete(url);
|
|
246
|
+
};
|
|
247
|
+
if (options.signal) {
|
|
248
|
+
options.signal.addEventListener("abort", abortHandler, { once: true });
|
|
249
|
+
}
|
|
222
250
|
responsePromise = fetch(input, fetchOptions);
|
|
223
251
|
if (isRead) {
|
|
224
|
-
|
|
252
|
+
const cleanup = () => {
|
|
253
|
+
inFlightRequests.delete(url);
|
|
254
|
+
if (options.signal) {
|
|
255
|
+
options.signal.removeEventListener("abort", abortHandler);
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
inFlightRequests.set(url, responsePromise.finally(cleanup));
|
|
225
259
|
}
|
|
226
260
|
}
|
|
227
261
|
|
|
@@ -230,6 +264,13 @@ ${autoInvalidateBlock}${auth401Block}
|
|
|
230
264
|
const fromCache = response.headers.get("X-SW-From-Cache") === "true";
|
|
231
265
|
return { response, fromCache };
|
|
232
266
|
}
|
|
267
|
+
|
|
268
|
+
/** Fire-and-forget prefetch: warms the cache for a URL without blocking. Useful for route prefetching or link hover prefetching. */
|
|
269
|
+
export function prefetchCache(input${T("RequestInfo")}, options${T("RequestInit & { tags?: string[]; staleWhileRevalidate?: boolean; auth?: boolean; queueOffline?: boolean; invalidate?: 'auto' | string[] | false; type?: 'read' | 'mutation'; strategy?: 'cache-first' | 'network-first' | 'stale-while-revalidate' | 'cache-only' | 'network-only'; staleTime?: number }")} = {})${R("void")}{
|
|
270
|
+
fetchWithCache(input, { ...options }).catch(() => {
|
|
271
|
+
// Prefetch failures are intentionally silent
|
|
272
|
+
});
|
|
273
|
+
}
|
|
233
274
|
`;
|
|
234
275
|
writeFile(ctx, `fetch-wrapper.${ext}`, code);
|
|
235
276
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-wrapper.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/fetch-wrapper.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fetch-wrapper.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/fetch-wrapper.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,15 +15,19 @@ export function generateHooks(ctx) {
|
|
|
15
15
|
if (!existsSync(hooksDir)) {
|
|
16
16
|
mkdirSync(hooksDir, { recursive: true });
|
|
17
17
|
}
|
|
18
|
+
// Always generated hooks
|
|
18
19
|
copyHook(hooksDir, "useNetworkStatus", ext);
|
|
19
20
|
copyHook(hooksDir, "useCachedFetch", ext);
|
|
21
|
+
copyHook(hooksDir, "useMutation", ext);
|
|
22
|
+
copyHook(hooksDir, "usePrefetch", ext);
|
|
23
|
+
copyHook(hooksDir, "useMutationState", ext);
|
|
20
24
|
if (config.features.pwa.enabled) {
|
|
21
25
|
copyHook(hooksDir, "useSWUpdate", ext);
|
|
22
26
|
}
|
|
23
27
|
if (config.features.auth.enabled) {
|
|
24
28
|
copyHook(hooksDir, "useAuth", ext);
|
|
25
29
|
}
|
|
26
|
-
if (config.features.mutationQueue) {
|
|
30
|
+
if (config.features.mutationQueue.enabled) {
|
|
27
31
|
copyHook(hooksDir, "useMutationQueue", ext);
|
|
28
32
|
}
|
|
29
33
|
if (config.features.pushNotifications?.enabled) {
|
|
@@ -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,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,CAAC,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,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC;QACpC,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,EAAE,GAAG,CAAC,CAAC;IAClD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { writeFile } from "./context.js";
|
|
2
|
+
export function generateGqlWrapper(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 G = (type) => (ts ? `<${type}>` : "");
|
|
8
|
+
const AS = (type) => (ts ? ` as ${type}` : "");
|
|
9
|
+
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
|
+
staleWhileRevalidate?: boolean;
|
|
16
|
+
auth?: boolean;
|
|
17
|
+
queueOffline?: boolean;
|
|
18
|
+
invalidate?: 'auto' | string[] | false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface GqlResult${G("T")} {
|
|
22
|
+
data${T("T")};
|
|
23
|
+
fromCache${T("boolean")};
|
|
24
|
+
}
|
|
25
|
+
`
|
|
26
|
+
: "";
|
|
27
|
+
const code = `/**
|
|
28
|
+
* Swoff GraphQL Wrapper
|
|
29
|
+
* Brings Swoff's caching, offline queue, and tag-based invalidation to GraphQL APIs.
|
|
30
|
+
* Hashes query + variables for deterministic cache keys and auto-generates tags
|
|
31
|
+
* from operation names. Built on top of fetchWithCache.
|
|
32
|
+
*
|
|
33
|
+
* Usage:
|
|
34
|
+
* import { fetchWithGql, queryGql, mutateGql } from './swoff/gql-wrapper.${ext}';
|
|
35
|
+
*
|
|
36
|
+
* // Query — cached with body-hash key
|
|
37
|
+
* const { data } = await queryGql("{ todos { id title } }");
|
|
38
|
+
*
|
|
39
|
+
* // Query with variables
|
|
40
|
+
* const { data: todo } = await queryGql(
|
|
41
|
+
* "query GetTodo($id: ID!) { todo(id: $id) { id title } }",
|
|
42
|
+
* { id: "42" }
|
|
43
|
+
* );
|
|
44
|
+
*
|
|
45
|
+
* // Mutation — auto-invalidates related cache tags
|
|
46
|
+
* const { data: created } = await mutateGql(
|
|
47
|
+
* "mutation CreateTodo($title: String!) { createTodo(title: $title) { id } }",
|
|
48
|
+
* { title: "New task" }
|
|
49
|
+
* );
|
|
50
|
+
*
|
|
51
|
+
* // Authenticated
|
|
52
|
+
* const { data } = await queryGql("query Me { me { name } }", {}, { auth: true });
|
|
53
|
+
*
|
|
54
|
+
* // Custom options
|
|
55
|
+
* const { data } = await queryGql(
|
|
56
|
+
* "query GetData { data { id } }",
|
|
57
|
+
* {},
|
|
58
|
+
* { staleWhileRevalidate: true, tags: ["data"] }
|
|
59
|
+
* );
|
|
60
|
+
*
|
|
61
|
+
* // Offline: mutations are auto-queued
|
|
62
|
+
* const { data } = await mutateGql(
|
|
63
|
+
* "mutation CreateTodo($title: String!) { createTodo(title: $title) { id } }",
|
|
64
|
+
* { title: "Offline task" },
|
|
65
|
+
* { queueOffline: true }
|
|
66
|
+
* );
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
import { fetchWithCache } from "./fetch-wrapper.${ext}";
|
|
70
|
+
${optionsInterface}
|
|
71
|
+
/** Extract operation name from a GraphQL document. Returns null for anonymous queries (e.g. "{ todos { id } }"). */
|
|
72
|
+
function getOperationName(query${T("string")})${T("string | null")}{
|
|
73
|
+
const match = query.match(/(query|mutation|subscription)\\s+(\\w+)/);
|
|
74
|
+
return match ? match[2] : null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Determine if a GraphQL document is a query (read) vs mutation/subscription (write). */
|
|
78
|
+
function isReadOperation(query${T("string")})${T("boolean")}{
|
|
79
|
+
const trimmed = query.trim();
|
|
80
|
+
if (trimmed.startsWith("mutation") || trimmed.startsWith("subscription")) return false;
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Hash an object into a hex string for deterministic cache keying. Uses SHA-256 via SubtleCrypto. */
|
|
85
|
+
async function bodyHash(obj${T("unknown")})${T("Promise<string>")}{
|
|
86
|
+
const json = JSON.stringify(obj);
|
|
87
|
+
const bytes = new TextEncoder().encode(json);
|
|
88
|
+
const hash = await crypto.subtle.digest("SHA-256", bytes);
|
|
89
|
+
return Array.from(new Uint8Array(hash)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 16);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Generate cache-relevant tags from a GQL operation name. e.g. "getTodos" → ["todos"], "createTodo" → ["todos", "todo"]. */
|
|
93
|
+
function tagsFromOpName(name${T("string | null")})${T("string[]")}{
|
|
94
|
+
if (!name) return [];
|
|
95
|
+
const stripped = name.replace(/^(get|fetch|list|all|query)/i, "").replace(/^(create|set|add|new|update|delete|remove)/i, "");
|
|
96
|
+
if (!stripped) return [name.toLowerCase()];
|
|
97
|
+
const tag = stripped.charAt(0).toLowerCase() + stripped.slice(1);
|
|
98
|
+
const plural = tag.replace(/s$/, "") + "s";
|
|
99
|
+
return [plural, tag];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Fetch a GraphQL endpoint with Swoff's caching, auth, offline queue, and auto-invalidation. Hashes query + variables for deterministic cache keys. */
|
|
103
|
+
export async function fetchWithGql${G("T")}(
|
|
104
|
+
query${T("string")},
|
|
105
|
+
options${T("GqlOptions")} = {}
|
|
106
|
+
)${R("Promise<GqlResult<T>>")}{
|
|
107
|
+
const isRead = isReadOperation(query);
|
|
108
|
+
const opName = getOperationName(query);
|
|
109
|
+
const variables = options.variables;
|
|
110
|
+
const hash = await bodyHash({ query, variables });
|
|
111
|
+
const tags = options.tags || tagsFromOpName(opName);
|
|
112
|
+
|
|
113
|
+
const { response, fromCache } = await fetchWithCache("${endpoint}", {
|
|
114
|
+
method: "POST",
|
|
115
|
+
body: JSON.stringify({ query, variables }),
|
|
116
|
+
headers: {
|
|
117
|
+
"Content-Type": "application/json",
|
|
118
|
+
"X-SW-Cache-Key": "gql:" + hash,
|
|
119
|
+
},
|
|
120
|
+
tags,
|
|
121
|
+
type: isRead ? "read" : "mutation",
|
|
122
|
+
staleWhileRevalidate: options.staleWhileRevalidate,
|
|
123
|
+
auth: options.auth,
|
|
124
|
+
queueOffline: options.queueOffline,
|
|
125
|
+
invalidate: options.invalidate,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const result = await response.json();
|
|
129
|
+
return { data: result.data${AS("T")}, fromCache };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Shorthand for GraphQL queries (type: "read"). Cached by default with body-hash key. */
|
|
133
|
+
export async function queryGql${G("T")}(
|
|
134
|
+
query${T("string")},
|
|
135
|
+
variables${T("Record<string, unknown> | undefined")} = undefined,
|
|
136
|
+
options${T("GqlOptions")} = {}
|
|
137
|
+
)${R("Promise<GqlResult<T>>")}{
|
|
138
|
+
return fetchWithGql${G("T")}(query, { ...options, variables });
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Shorthand for GraphQL mutations (type: "mutation"). Auto-invalidates related cache tags. */
|
|
142
|
+
export async function mutateGql${G("T")}(
|
|
143
|
+
mutation${T("string")},
|
|
144
|
+
variables${T("Record<string, unknown> | undefined")} = undefined,
|
|
145
|
+
options${T("GqlOptions")} = {}
|
|
146
|
+
)${R("Promise<GqlResult<T>>")}{
|
|
147
|
+
return fetchWithGql${G("T")}(mutation, { ...options, variables });
|
|
148
|
+
}
|
|
149
|
+
`;
|
|
150
|
+
writeFile(ctx, `gql-wrapper.${ext}`, code);
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=gql-wrapper.js.map
|
|
@@ -0,0 +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;;;;;;;;;;4BAUsB,CAAC,CAAC,GAAG,CAAC;QAC1B,CAAC,CAAC,GAAG,CAAC;aACD,CAAC,CAAC,SAAS,CAAC;;CAExB;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,IAAI,GAAG;;;;;;;8EAO+D,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kDAmC/B,GAAG;EACnD,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;;;;;;;;;;;;;;;;8BAgBpC,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"}
|