@remix-run/assets 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +185 -104
- package/dist/assets.d.ts +4 -1
- package/dist/assets.d.ts.map +1 -1
- package/dist/lib/access.d.ts +29 -2
- package/dist/lib/access.d.ts.map +1 -1
- package/dist/lib/access.js +52 -26
- package/dist/lib/asset-server.d.ts +61 -25
- package/dist/lib/asset-server.d.ts.map +1 -1
- package/dist/lib/asset-server.js +127 -55
- package/dist/lib/compilation-error.d.ts +1 -1
- package/dist/lib/compilation-error.d.ts.map +1 -1
- package/dist/lib/files/compiler.d.ts +1 -1
- package/dist/lib/files/compiler.d.ts.map +1 -1
- package/dist/lib/files/compiler.js +28 -31
- package/dist/lib/files/config.d.ts +6 -0
- package/dist/lib/files/config.d.ts.map +1 -1
- package/dist/lib/files/config.js +9 -0
- package/dist/lib/fingerprint.d.ts +0 -4
- package/dist/lib/fingerprint.d.ts.map +1 -1
- package/dist/lib/fingerprint.js +0 -4
- package/dist/lib/hmr.d.ts +7 -0
- package/dist/lib/hmr.d.ts.map +1 -1
- package/dist/lib/hmr.js +198 -25
- package/dist/lib/injected-packages.d.ts +3 -2
- package/dist/lib/injected-packages.d.ts.map +1 -1
- package/dist/lib/injected-packages.js +11 -8
- package/dist/lib/inspection.d.ts +39 -0
- package/dist/lib/inspection.d.ts.map +1 -0
- package/dist/lib/inspection.js +160 -0
- package/dist/lib/routes.d.ts +12 -3
- package/dist/lib/routes.d.ts.map +1 -1
- package/dist/lib/routes.js +124 -80
- package/dist/lib/scripts/compiler.d.ts +8 -2
- package/dist/lib/scripts/compiler.d.ts.map +1 -1
- package/dist/lib/scripts/compiler.js +188 -38
- package/dist/lib/scripts/emit.d.ts +2 -1
- package/dist/lib/scripts/emit.d.ts.map +1 -1
- package/dist/lib/scripts/emit.js +25 -16
- package/dist/lib/scripts/resolve.d.ts +7 -1
- package/dist/lib/scripts/resolve.d.ts.map +1 -1
- package/dist/lib/scripts/resolve.js +119 -12
- package/dist/lib/scripts/specifiers.d.ts +2 -0
- package/dist/lib/scripts/specifiers.d.ts.map +1 -0
- package/dist/lib/scripts/specifiers.js +9 -0
- package/dist/lib/scripts/transform.d.ts +2 -3
- package/dist/lib/scripts/transform.d.ts.map +1 -1
- package/dist/lib/scripts/transform.js +4 -18
- package/dist/lib/styles/compiler.d.ts +0 -1
- package/dist/lib/styles/compiler.d.ts.map +1 -1
- package/dist/lib/styles/compiler.js +105 -25
- package/dist/lib/styles/emit.d.ts +2 -1
- package/dist/lib/styles/emit.d.ts.map +1 -1
- package/dist/lib/styles/emit.js +12 -10
- package/dist/lib/styles/resolve.d.ts +0 -1
- package/dist/lib/styles/resolve.d.ts.map +1 -1
- package/dist/lib/styles/resolve.js +8 -9
- package/dist/lib/styles/transform.d.ts +0 -2
- package/dist/lib/styles/transform.d.ts.map +1 -1
- package/dist/lib/styles/transform.js +2 -9
- package/dist/lib/virtual-store.d.ts +8 -0
- package/dist/lib/virtual-store.d.ts.map +1 -0
- package/dist/lib/virtual-store.js +100 -0
- package/package.json +6 -6
- package/src/assets.ts +9 -1
- package/src/lib/access.ts +83 -30
- package/src/lib/asset-server.ts +224 -94
- package/src/lib/compilation-error.ts +4 -3
- package/src/lib/files/compiler.ts +32 -42
- package/src/lib/files/config.ts +17 -0
- package/src/lib/fingerprint.ts +0 -9
- package/src/lib/hmr.ts +210 -26
- package/src/lib/injected-packages.ts +16 -10
- package/src/lib/inspection.ts +229 -0
- package/src/lib/routes.ts +158 -126
- package/src/lib/scripts/compiler.ts +240 -54
- package/src/lib/scripts/emit.ts +34 -19
- package/src/lib/scripts/resolve.ts +175 -13
- package/src/lib/scripts/specifiers.ts +11 -0
- package/src/lib/scripts/transform.ts +6 -25
- package/src/lib/styles/compiler.ts +137 -39
- package/src/lib/styles/emit.ts +18 -13
- package/src/lib/styles/resolve.ts +8 -10
- package/src/lib/styles/transform.ts +2 -12
- package/src/lib/virtual-store.ts +124 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/lib/fingerprint.ts"],"names":[],"mappings":"AAGA,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAIhG;AAED,
|
|
1
|
+
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/lib/fingerprint.ts"],"names":[],"mappings":"AAGA,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAIhG;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG;IACxD,QAAQ,EAAE,MAAM,CAAA;IAChB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC,CAyBA;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAahG;AAED,wBAAgB,iCAAiC,CAAC,oBAAoB,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAE7F"}
|
package/dist/lib/fingerprint.js
CHANGED
|
@@ -5,10 +5,6 @@ export async function hashContent(content) {
|
|
|
5
5
|
let hashBuffer = await crypto.subtle.digest('SHA-256', bytes);
|
|
6
6
|
return Buffer.from(hashBuffer).toString('base64url').slice(0, 6);
|
|
7
7
|
}
|
|
8
|
-
export async function generateFingerprint(args) {
|
|
9
|
-
let content = typeof args.content === 'string' ? args.content : Buffer.from(args.content).toString('base64');
|
|
10
|
-
return hashContent(JSON.stringify([content, args.buildId]));
|
|
11
|
-
}
|
|
12
8
|
export function parseFingerprintSuffix(pathname) {
|
|
13
9
|
let lastSlashIndex = pathname.lastIndexOf('/');
|
|
14
10
|
let directory = lastSlashIndex >= 0 ? pathname.slice(0, lastSlashIndex + 1) : '';
|
package/dist/lib/hmr.d.ts
CHANGED
|
@@ -13,6 +13,11 @@ export type HmrPayload = {
|
|
|
13
13
|
updates: Array<{
|
|
14
14
|
/** Importing module whose dependency-accept handler accepts this update. */
|
|
15
15
|
acceptedPath?: string;
|
|
16
|
+
/** Import map entries required before this update can be evaluated. */
|
|
17
|
+
importMap?: {
|
|
18
|
+
imports: Record<string, string>;
|
|
19
|
+
scopes?: Record<string, Record<string, string>>;
|
|
20
|
+
};
|
|
16
21
|
/** Public URL of the changed JavaScript module. */
|
|
17
22
|
path: string;
|
|
18
23
|
/** Identifies a JavaScript module update. */
|
|
@@ -32,6 +37,8 @@ export type HmrPayload = {
|
|
|
32
37
|
type: 'browser:reload';
|
|
33
38
|
};
|
|
34
39
|
export declare function createHmrClientSource(options: {
|
|
40
|
+
dataKey: string;
|
|
35
41
|
eventPathname: string;
|
|
42
|
+
moduleImporter: string | null;
|
|
36
43
|
}): string;
|
|
37
44
|
//# sourceMappingURL=hmr.d.ts.map
|
package/dist/lib/hmr.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../../src/lib/hmr.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAClB;IACE,8DAA8D;IAC9D,IAAI,EAAE,eAAe,CAAA;CACtB,GACD;IACE,iEAAiE;IACjE,OAAO,EAAE,KAAK,CACV;QACE,4EAA4E;QAC5E,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,mDAAmD;QACnD,IAAI,EAAE,MAAM,CAAA;QACZ,6CAA6C;QAC7C,IAAI,EAAE,IAAI,CAAA;KACX,GACD;QACE,4CAA4C;QAC5C,IAAI,EAAE,MAAM,CAAA;QACZ,sCAAsC;QACtC,IAAI,EAAE,KAAK,CAAA;KACZ,CACJ,CAAA;IACD,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,IAAI,EAAE,gBAAgB,CAAA;CACvB,GACD;IACE,mFAAmF;IACnF,IAAI,EAAE,gBAAgB,CAAA;CACvB,CAAA;AAEL,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;
|
|
1
|
+
{"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../../src/lib/hmr.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAClB;IACE,8DAA8D;IAC9D,IAAI,EAAE,eAAe,CAAA;CACtB,GACD;IACE,iEAAiE;IACjE,OAAO,EAAE,KAAK,CACV;QACE,4EAA4E;QAC5E,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,uEAAuE;QACvE,SAAS,CAAC,EAAE;YACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;YAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;SAChD,CAAA;QACD,mDAAmD;QACnD,IAAI,EAAE,MAAM,CAAA;QACZ,6CAA6C;QAC7C,IAAI,EAAE,IAAI,CAAA;KACX,GACD;QACE,4CAA4C;QAC5C,IAAI,EAAE,MAAM,CAAA;QACZ,sCAAsC;QACtC,IAAI,EAAE,KAAK,CAAA;KACZ,CACJ,CAAA;IACD,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,IAAI,EAAE,gBAAgB,CAAA;CACvB,GACD;IACE,mFAAmF;IACnF,IAAI,EAAE,gBAAgB,CAAA;CACvB,CAAA;AAEL,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;IAC7C,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B,GAAG,MAAM,CAmhBT"}
|
package/dist/lib/hmr.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export function createHmrClientSource(options) {
|
|
2
2
|
return `
|
|
3
|
+
${options.moduleImporter
|
|
4
|
+
? `import { importModule as __remixImport } from ${JSON.stringify(options.moduleImporter)}`
|
|
5
|
+
: 'const __remixImport = (specifier) => import(specifier)'}
|
|
6
|
+
|
|
3
7
|
const contexts = new Map()
|
|
4
8
|
const dataByPath = new Map()
|
|
5
9
|
|
|
@@ -71,6 +75,13 @@ let reconnectPending = false
|
|
|
71
75
|
let pageReloadTimer
|
|
72
76
|
let failedJavaScriptUpdates = new Map()
|
|
73
77
|
let stylesheetUpdatePromise = Promise.resolve()
|
|
78
|
+
let installedImportMap = { imports: new Map(), scopes: new Map() }
|
|
79
|
+
let processedScripts = new WeakSet()
|
|
80
|
+
|
|
81
|
+
let observer = new MutationObserver(processMutations)
|
|
82
|
+
observer.observe(document, { childList: true })
|
|
83
|
+
observer.observe(document.head, { childList: true })
|
|
84
|
+
processImportMaps()
|
|
74
85
|
|
|
75
86
|
let events = new EventSource(${JSON.stringify(options.eventPathname)})
|
|
76
87
|
|
|
@@ -96,11 +107,18 @@ events.onerror = () => {
|
|
|
96
107
|
|
|
97
108
|
events.onmessage = (event) => {
|
|
98
109
|
let payload = JSON.parse(event.data)
|
|
110
|
+
if (payload.type === 'browser:update') {
|
|
111
|
+
let update = payload.data?.[${JSON.stringify(options.dataKey)}]
|
|
112
|
+
if (!update) return
|
|
113
|
+
handleBrowserUpdate(update).catch((error) => {
|
|
114
|
+
console.error('[remix] HMR update failed', error)
|
|
115
|
+
if (update.updates.some((entry) => entry.type !== 'js')) reloadPage()
|
|
116
|
+
})
|
|
117
|
+
return
|
|
118
|
+
}
|
|
99
119
|
handlePayload(payload).catch((error) => {
|
|
100
120
|
console.error('[remix] HMR update failed', error)
|
|
101
|
-
|
|
102
|
-
reloadPage()
|
|
103
|
-
}
|
|
121
|
+
reloadPage()
|
|
104
122
|
})
|
|
105
123
|
}
|
|
106
124
|
|
|
@@ -115,27 +133,28 @@ async function handlePayload(payload) {
|
|
|
115
133
|
await dispatchCustomEvent(payload.type, payload)
|
|
116
134
|
return
|
|
117
135
|
}
|
|
136
|
+
}
|
|
118
137
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
138
|
+
async function handleBrowserUpdate(payload) {
|
|
139
|
+
for (let update of payload.updates) {
|
|
140
|
+
if (update.type === 'css') {
|
|
141
|
+
let updated = await queueStylesheetUpdate(update.path, payload.timestamp)
|
|
142
|
+
if (updated) console.debug('[remix] HMR updated stylesheet', update.path)
|
|
143
|
+
continue
|
|
144
|
+
}
|
|
126
145
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
146
|
+
try {
|
|
147
|
+
if (update.importMap && !installImportMap(update.importMap)) return
|
|
148
|
+
let updated = await updateJavaScriptModule(
|
|
149
|
+
update.path,
|
|
150
|
+
update.acceptedPath ?? update.path,
|
|
151
|
+
payload.timestamp,
|
|
152
|
+
)
|
|
153
|
+
failedJavaScriptUpdates.delete(update.path)
|
|
154
|
+
if (updated) console.debug('[remix] HMR accepted update', update.path)
|
|
155
|
+
} catch (error) {
|
|
156
|
+
failedJavaScriptUpdates.set(update.path, update.acceptedPath ?? update.path)
|
|
157
|
+
throw error
|
|
139
158
|
}
|
|
140
159
|
}
|
|
141
160
|
}
|
|
@@ -204,7 +223,7 @@ async function updateJavaScriptModule(path, acceptedPath, timestamp) {
|
|
|
204
223
|
await callback(previousContext.data)
|
|
205
224
|
}
|
|
206
225
|
|
|
207
|
-
let updatedModule = await
|
|
226
|
+
let updatedModule = await __remixImport(withTimestamp(path, timestamp), import.meta.url)
|
|
208
227
|
previousContext.invalidated = false
|
|
209
228
|
previousContext.updating = true
|
|
210
229
|
try {
|
|
@@ -227,7 +246,7 @@ async function updateJavaScriptModule(path, acceptedPath, timestamp) {
|
|
|
227
246
|
}
|
|
228
247
|
}
|
|
229
248
|
|
|
230
|
-
let updatedModule = await
|
|
249
|
+
let updatedModule = await __remixImport(withTimestamp(acceptedPath, timestamp), import.meta.url)
|
|
231
250
|
previousContext.invalidated = false
|
|
232
251
|
previousContext.updating = true
|
|
233
252
|
try {
|
|
@@ -258,7 +277,7 @@ async function propagateInvalidatedJavaScriptModule(path, timestamp) {
|
|
|
258
277
|
await callback(importerContext.data)
|
|
259
278
|
}
|
|
260
279
|
|
|
261
|
-
let updatedModule = await
|
|
280
|
+
let updatedModule = await __remixImport(withTimestamp(path, timestamp), import.meta.url)
|
|
262
281
|
importerContext.invalidated = false
|
|
263
282
|
importerContext.updating = true
|
|
264
283
|
try {
|
|
@@ -346,6 +365,160 @@ function withTimestamp(path, timestamp) {
|
|
|
346
365
|
return url.pathname + url.search
|
|
347
366
|
}
|
|
348
367
|
|
|
368
|
+
function installImportMap(importMap) {
|
|
369
|
+
processMutations(observer.takeRecords())
|
|
370
|
+
processImportMaps()
|
|
371
|
+
let delta = getImportMapDelta(installedImportMap, importMap)
|
|
372
|
+
if (delta === null) {
|
|
373
|
+
reloadPage()
|
|
374
|
+
return false
|
|
375
|
+
}
|
|
376
|
+
if (!delta) return true
|
|
377
|
+
|
|
378
|
+
let script = document.createElement('script')
|
|
379
|
+
script.setAttribute('data-rmx-import-map', '')
|
|
380
|
+
script.type = 'importmap'
|
|
381
|
+
script.textContent = JSON.stringify(delta)
|
|
382
|
+
document.head.appendChild(script)
|
|
383
|
+
processedScripts.add(script)
|
|
384
|
+
mergeImportMap(installedImportMap, delta)
|
|
385
|
+
return true
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function processImportMap(script) {
|
|
389
|
+
if (processedScripts.has(script)) return
|
|
390
|
+
processedScripts.add(script)
|
|
391
|
+
|
|
392
|
+
let importMap
|
|
393
|
+
try {
|
|
394
|
+
importMap = JSON.parse(script.textContent ?? '')
|
|
395
|
+
} catch {
|
|
396
|
+
return
|
|
397
|
+
}
|
|
398
|
+
if (!importMap || typeof importMap !== 'object') return
|
|
399
|
+
mergeImportMap(installedImportMap, importMap)
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function processImportMaps() {
|
|
403
|
+
for (let script of document.querySelectorAll('script[type="importmap"]')) {
|
|
404
|
+
processImportMap(script)
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function processMutations(mutations) {
|
|
409
|
+
for (let mutation of mutations) {
|
|
410
|
+
if (mutation.type !== 'childList') continue
|
|
411
|
+
for (let node of mutation.addedNodes) {
|
|
412
|
+
if (node instanceof HTMLScriptElement && node.matches('script[type="importmap"]')) {
|
|
413
|
+
processImportMap(node)
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function getImportMapDelta(installed, importMap) {
|
|
420
|
+
let imports = getImportMapImportsDelta(installed.imports, importMap.imports)
|
|
421
|
+
if (imports === null) return null
|
|
422
|
+
|
|
423
|
+
let scopes
|
|
424
|
+
if (importMap.scopes && typeof importMap.scopes === 'object') {
|
|
425
|
+
scopes = {}
|
|
426
|
+
for (let [scope, entries] of Object.entries(importMap.scopes)) {
|
|
427
|
+
let normalizedScope = normalizeImportMapUrl(scope)
|
|
428
|
+
if (!normalizedScope || !entries || typeof entries !== 'object') continue
|
|
429
|
+
let installedEntries = installed.scopes.get(normalizedScope) ?? new Map()
|
|
430
|
+
let entriesDelta = getImportMapImportsDelta(installedEntries, entries, scope)
|
|
431
|
+
if (entriesDelta === null) return null
|
|
432
|
+
if (entriesDelta) scopes[scope] = entriesDelta
|
|
433
|
+
}
|
|
434
|
+
if (Object.keys(scopes).length === 0) scopes = undefined
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (!imports && !scopes) return undefined
|
|
438
|
+
return {
|
|
439
|
+
...(imports ? { imports } : null),
|
|
440
|
+
...(scopes ? { scopes } : null),
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function getImportMapImportsDelta(installed, entries, scope) {
|
|
445
|
+
if (!entries || typeof entries !== 'object') return undefined
|
|
446
|
+
let delta = {}
|
|
447
|
+
for (let [specifier, href] of Object.entries(entries)) {
|
|
448
|
+
if (href !== null && typeof href !== 'string') continue
|
|
449
|
+
let normalizedSpecifier = normalizeImportMapSpecifier(specifier)
|
|
450
|
+
if (!normalizedSpecifier) continue
|
|
451
|
+
let normalizedHref = normalizeImportMapAddress(href)
|
|
452
|
+
let existing = installed.get(normalizedSpecifier)
|
|
453
|
+
if (existing === normalizedHref) continue
|
|
454
|
+
if (existing !== undefined) {
|
|
455
|
+
let scopeDescription = scope ? \` in scope "\${scope}"\` : ''
|
|
456
|
+
console.warn(
|
|
457
|
+
\`[remix] HMR reloading page after import map conflict for "\${specifier}"\${scopeDescription}: \` +
|
|
458
|
+
formatImportMapAddress(existing) +
|
|
459
|
+
' is already installed, but the new map points to ' +
|
|
460
|
+
formatImportMapAddress(normalizedHref),
|
|
461
|
+
)
|
|
462
|
+
return null
|
|
463
|
+
}
|
|
464
|
+
delta[specifier] = href
|
|
465
|
+
}
|
|
466
|
+
return Object.keys(delta).length > 0 ? delta : undefined
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function mergeImportMap(installed, importMap) {
|
|
470
|
+
mergeImportMapImports(installed.imports, importMap.imports)
|
|
471
|
+
if (!importMap.scopes || typeof importMap.scopes !== 'object') return
|
|
472
|
+
for (let [scope, entries] of Object.entries(importMap.scopes)) {
|
|
473
|
+
let normalizedScope = normalizeImportMapUrl(scope)
|
|
474
|
+
if (!normalizedScope || !entries || typeof entries !== 'object') continue
|
|
475
|
+
let installedEntries = installed.scopes.get(normalizedScope)
|
|
476
|
+
if (!installedEntries) {
|
|
477
|
+
installedEntries = new Map()
|
|
478
|
+
installed.scopes.set(normalizedScope, installedEntries)
|
|
479
|
+
}
|
|
480
|
+
mergeImportMapImports(installedEntries, entries)
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function mergeImportMapImports(installed, entries) {
|
|
485
|
+
if (!entries || typeof entries !== 'object') return
|
|
486
|
+
for (let [specifier, href] of Object.entries(entries)) {
|
|
487
|
+
if (href !== null && typeof href !== 'string') continue
|
|
488
|
+
let normalizedSpecifier = normalizeImportMapSpecifier(specifier)
|
|
489
|
+
if (!normalizedSpecifier || installed.has(normalizedSpecifier)) continue
|
|
490
|
+
installed.set(normalizedSpecifier, normalizeImportMapAddress(href))
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function normalizeImportMapSpecifier(specifier) {
|
|
495
|
+
if (
|
|
496
|
+
specifier.startsWith('/') ||
|
|
497
|
+
specifier.startsWith('./') ||
|
|
498
|
+
specifier.startsWith('../') ||
|
|
499
|
+
URL.canParse(specifier)
|
|
500
|
+
) {
|
|
501
|
+
return normalizeImportMapUrl(specifier)
|
|
502
|
+
}
|
|
503
|
+
return specifier
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function normalizeImportMapAddress(href) {
|
|
507
|
+
return href === null ? null : normalizeImportMapUrl(href)
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function formatImportMapAddress(href) {
|
|
511
|
+
return href === null ? 'null' : '"' + href + '"'
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function normalizeImportMapUrl(value) {
|
|
515
|
+
try {
|
|
516
|
+
return new URL(value, document.baseURI).href
|
|
517
|
+
} catch {
|
|
518
|
+
return null
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
349
522
|
function reloadPage() {
|
|
350
523
|
if (pageReloadTimer) clearTimeout(pageReloadTimer)
|
|
351
524
|
pageReloadTimer = setTimeout(() => {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export declare function isInjectedPackageFilePath(filePath: string): boolean;
|
|
2
|
-
export declare function
|
|
3
|
-
|
|
2
|
+
export declare function getInjectedPackageMountConfigs(): {
|
|
3
|
+
mounts: Record<string, string>;
|
|
4
4
|
rootDir: string;
|
|
5
5
|
}[];
|
|
6
|
+
export declare function getInjectedPackageRoots(): readonly string[];
|
|
6
7
|
export declare function getInjectedPackageNameForSpecifier(specifier: string): string | null;
|
|
7
8
|
export declare function mayContainInjectedPackageSpecifier(sourceText: string): boolean;
|
|
8
9
|
export declare function maskAuthoredInjectedPackageSpecifier(specifier: string): string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"injected-packages.d.ts","sourceRoot":"","sources":["../../src/lib/injected-packages.ts"],"names":[],"mappings":"AAiBA,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAWnE;AAED,wBAAgB,8BAA8B,IAAI;IAChD,
|
|
1
|
+
{"version":3,"file":"injected-packages.d.ts","sourceRoot":"","sources":["../../src/lib/injected-packages.ts"],"names":[],"mappings":"AAiBA,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAWnE;AAED,wBAAgB,8BAA8B,IAAI;IAChD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,OAAO,EAAE,MAAM,CAAA;CAChB,EAAE,CAYF;AAED,wBAAgB,uBAAuB,IAAI,SAAS,MAAM,EAAE,CAI3D;AAED,wBAAgB,kCAAkC,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAcnF;AAED,wBAAgB,kCAAkC,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE9E;AAED,wBAAgB,oCAAoC,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASrF;AAED,wBAAgB,uCAAuC,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYxF;AAWD,wBAAgB,8BAA8B,IAAI,MAAM,CAEvD"}
|
|
@@ -16,18 +16,21 @@ export function isInjectedPackageFilePath(filePath) {
|
|
|
16
16
|
}
|
|
17
17
|
return false;
|
|
18
18
|
}
|
|
19
|
-
export function
|
|
19
|
+
export function getInjectedPackageMountConfigs() {
|
|
20
20
|
return injectedPackageNames.map((packageName) => {
|
|
21
21
|
let { packageRoot } = getResolvedInjectedPackage(packageName);
|
|
22
|
-
let {
|
|
22
|
+
let { fileRoot, routeRoot } = getInjectedPackageRoute(packageRoot, packageName);
|
|
23
23
|
return {
|
|
24
|
-
|
|
25
|
-
[
|
|
24
|
+
mounts: {
|
|
25
|
+
[getInjectedPackageMountPath(packageName)]: fileRoot,
|
|
26
26
|
},
|
|
27
27
|
rootDir: routeRoot,
|
|
28
28
|
};
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
+
export function getInjectedPackageRoots() {
|
|
32
|
+
return injectedPackageNames.map((packageName) => getResolvedInjectedPackage(packageName).packageRoot);
|
|
33
|
+
}
|
|
31
34
|
export function getInjectedPackageNameForSpecifier(specifier) {
|
|
32
35
|
for (let injectedSpecifier of generatedInjectedPackageSpecifiers) {
|
|
33
36
|
if (specifier === injectedSpecifier) {
|
|
@@ -88,13 +91,13 @@ function getResolvedInjectedPackage(packageName) {
|
|
|
88
91
|
resolvedInjectedPackages.set(packageName, resolvedInjectedPackage);
|
|
89
92
|
return resolvedInjectedPackage;
|
|
90
93
|
}
|
|
91
|
-
function
|
|
92
|
-
return `${injectedPackagesBasePath}/${packageName}
|
|
94
|
+
function getInjectedPackageMountPath(packageName) {
|
|
95
|
+
return `${injectedPackagesBasePath}/${packageName}`;
|
|
93
96
|
}
|
|
94
97
|
function getInjectedPackageRoute(packageRoot, packageName) {
|
|
95
98
|
if (!packageRoot.endsWith(`/${packageName}`)) {
|
|
96
99
|
return {
|
|
97
|
-
|
|
100
|
+
fileRoot: packageRoot.slice(getFilePathDirectory(packageRoot).length + 1),
|
|
98
101
|
routeRoot: getFilePathDirectory(packageRoot),
|
|
99
102
|
};
|
|
100
103
|
}
|
|
@@ -103,7 +106,7 @@ function getInjectedPackageRoute(packageRoot, packageName) {
|
|
|
103
106
|
routeRoot = getFilePathDirectory(routeRoot);
|
|
104
107
|
}
|
|
105
108
|
return {
|
|
106
|
-
|
|
109
|
+
fileRoot: packageName,
|
|
107
110
|
routeRoot,
|
|
108
111
|
};
|
|
109
112
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { AccessPolicy, AssetAccessDetails } from './access.ts';
|
|
2
|
+
import type { CompiledRoutes } from './routes.ts';
|
|
3
|
+
/** How the asset server handles an inspected file. */
|
|
4
|
+
export type AssetKind = 'file' | 'script' | 'style' | 'unsupported';
|
|
5
|
+
/** Browser-reachability result for an inspected asset. */
|
|
6
|
+
export type AssetStatus = 'denied' | 'missing' | 'not-allowed' | 'reachable' | 'unmapped' | 'unsupported';
|
|
7
|
+
/** Diagnostic information about a configured asset URL or file path. */
|
|
8
|
+
export interface AssetDetails {
|
|
9
|
+
/** Access-control decision and the rules responsible for it. */
|
|
10
|
+
access?: AssetAccessDetails;
|
|
11
|
+
/** Absolute mapped file path. */
|
|
12
|
+
filePath?: string;
|
|
13
|
+
/** Configured filesystem mount root that matched the asset. */
|
|
14
|
+
fileRoot?: string;
|
|
15
|
+
/** Browser-reachability result. */
|
|
16
|
+
status: AssetStatus;
|
|
17
|
+
/** How the asset server handles the file. */
|
|
18
|
+
type?: AssetKind;
|
|
19
|
+
/** Stable public URL pathname for the asset. */
|
|
20
|
+
url?: string;
|
|
21
|
+
/** Public mount root that matched the asset. */
|
|
22
|
+
urlRoot?: string;
|
|
23
|
+
}
|
|
24
|
+
interface AssetInspectorOptions {
|
|
25
|
+
accessPolicy: AccessPolicy;
|
|
26
|
+
allowFiles: readonly string[];
|
|
27
|
+
fileExtensions: readonly string[];
|
|
28
|
+
rootDir: string;
|
|
29
|
+
routes: CompiledRoutes;
|
|
30
|
+
}
|
|
31
|
+
export interface AssetInspector {
|
|
32
|
+
/** Returns diagnostic information for a public URL or file path. */
|
|
33
|
+
getAssetDetails(input: string): Promise<AssetDetails>;
|
|
34
|
+
/** Returns every file currently reachable through the configured asset server. */
|
|
35
|
+
getAssets(): Promise<AssetDetails[]>;
|
|
36
|
+
}
|
|
37
|
+
export declare function createAssetInspector(options: AssetInspectorOptions): AssetInspector;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=inspection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspection.d.ts","sourceRoot":"","sources":["../../src/lib/inspection.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAInE,OAAO,KAAK,EAAmB,cAAc,EAAE,MAAM,aAAa,CAAA;AAOlE,sDAAsD;AACtD,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,aAAa,CAAA;AAEnE,0DAA0D;AAC1D,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,SAAS,GACT,aAAa,GACb,WAAW,GACX,UAAU,GACV,aAAa,CAAA;AAEjB,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mCAAmC;IACnC,MAAM,EAAE,WAAW,CAAA;IACnB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,UAAU,qBAAqB;IAC7B,YAAY,EAAE,YAAY,CAAA;IAC1B,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;IAC7B,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,cAAc,CAAA;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,oEAAoE;IACpE,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IACrD,kFAAkF;IAClF,SAAS,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAA;CACrC;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,cAAc,CA4BnF"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as fsPromises from 'node:fs/promises';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { parseFingerprintSuffix } from './fingerprint.js';
|
|
6
|
+
import { getInjectedPackageRoots } from './injected-packages.js';
|
|
7
|
+
import { isAbsoluteFilePath, normalizeFilePath, resolveFilePath } from './paths.js';
|
|
8
|
+
import { supportedScriptExtensions } from './scripts/resolve.js';
|
|
9
|
+
import { isStyleFilePath } from './styles/compiler.js';
|
|
10
|
+
const scriptExtensions = new Set(supportedScriptExtensions);
|
|
11
|
+
const globSyntaxPattern = /[*?[\]{}()!+@]/;
|
|
12
|
+
export function createAssetInspector(options) {
|
|
13
|
+
let fileExtensions = new Set(options.fileExtensions.map((extension) => extension.toLowerCase()));
|
|
14
|
+
return {
|
|
15
|
+
async getAssetDetails(input) {
|
|
16
|
+
let routeMatch = await resolveInput(input, options);
|
|
17
|
+
if (routeMatch === null)
|
|
18
|
+
return { status: 'unmapped' };
|
|
19
|
+
return inspectRouteMatch(routeMatch, options, fileExtensions);
|
|
20
|
+
},
|
|
21
|
+
async getAssets() {
|
|
22
|
+
let filePaths = await discoverFilePaths(options);
|
|
23
|
+
let assets = [];
|
|
24
|
+
for (let filePath of filePaths) {
|
|
25
|
+
let routeMatch = options.routes.matchFilePath(filePath);
|
|
26
|
+
if (routeMatch === null)
|
|
27
|
+
continue;
|
|
28
|
+
let details = await inspectRouteMatch(routeMatch, options, fileExtensions);
|
|
29
|
+
if (details.status === 'reachable')
|
|
30
|
+
assets.push(details);
|
|
31
|
+
}
|
|
32
|
+
assets.sort((left, right) => {
|
|
33
|
+
let urlOrder = (left.url ?? '').localeCompare(right.url ?? '');
|
|
34
|
+
return urlOrder === 0 ? (left.filePath ?? '').localeCompare(right.filePath ?? '') : urlOrder;
|
|
35
|
+
});
|
|
36
|
+
return assets;
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async function resolveInput(input, options) {
|
|
41
|
+
if (input.startsWith('file://')) {
|
|
42
|
+
return options.routes.matchFilePath(fileURLToPath(input));
|
|
43
|
+
}
|
|
44
|
+
if (/^[A-Za-z][A-Za-z\d+.-]*:\/\//.test(input)) {
|
|
45
|
+
let pathname = parseFingerprintSuffix(new URL(input).pathname).pathname;
|
|
46
|
+
return options.routes.matchUrlPathname(pathname);
|
|
47
|
+
}
|
|
48
|
+
let filePath = resolveFilePath(options.rootDir, input);
|
|
49
|
+
if (!input.startsWith('/') || isAbsoluteFilePath(input)) {
|
|
50
|
+
if (await pathExists(filePath))
|
|
51
|
+
return options.routes.matchFilePath(filePath);
|
|
52
|
+
if (!input.startsWith('/'))
|
|
53
|
+
return options.routes.matchFilePath(filePath);
|
|
54
|
+
}
|
|
55
|
+
let pathname = parseFingerprintSuffix(new URL(input, 'http://remix.run').pathname).pathname;
|
|
56
|
+
return options.routes.matchUrlPathname(pathname);
|
|
57
|
+
}
|
|
58
|
+
async function inspectRouteMatch(routeMatch, options, fileExtensions) {
|
|
59
|
+
let exists = await pathExists(routeMatch.filePath);
|
|
60
|
+
let identityPath = exists ? fs.realpathSync(routeMatch.filePath) : routeMatch.filePath;
|
|
61
|
+
let normalizedIdentityPath = normalizeFilePath(identityPath);
|
|
62
|
+
let access = options.accessPolicy.inspect(normalizedIdentityPath);
|
|
63
|
+
let type = getAssetKind(routeMatch.filePath, fileExtensions);
|
|
64
|
+
let details = {
|
|
65
|
+
access,
|
|
66
|
+
filePath: routeMatch.filePath,
|
|
67
|
+
fileRoot: routeMatch.fileRoot,
|
|
68
|
+
type,
|
|
69
|
+
url: routeMatch.urlPathname,
|
|
70
|
+
urlRoot: routeMatch.urlRoot,
|
|
71
|
+
};
|
|
72
|
+
if (!exists)
|
|
73
|
+
return { ...details, status: 'missing' };
|
|
74
|
+
if (!access.allowed) {
|
|
75
|
+
return { ...details, status: access.deniedBy === undefined ? 'not-allowed' : 'denied' };
|
|
76
|
+
}
|
|
77
|
+
if (type === 'unsupported')
|
|
78
|
+
return { ...details, status: 'unsupported' };
|
|
79
|
+
return { ...details, status: 'reachable' };
|
|
80
|
+
}
|
|
81
|
+
function getAssetKind(filePath, fileExtensions) {
|
|
82
|
+
let extension = path.extname(filePath).toLowerCase();
|
|
83
|
+
if (scriptExtensions.has(extension))
|
|
84
|
+
return 'script';
|
|
85
|
+
if (isStyleFilePath(filePath))
|
|
86
|
+
return 'style';
|
|
87
|
+
if (fileExtensions.has(extension))
|
|
88
|
+
return 'file';
|
|
89
|
+
return 'unsupported';
|
|
90
|
+
}
|
|
91
|
+
async function discoverFilePaths(options) {
|
|
92
|
+
let roots = new Set();
|
|
93
|
+
for (let pattern of options.allowFiles) {
|
|
94
|
+
roots.add(resolveDiscoveryRoot(options.rootDir, pattern));
|
|
95
|
+
}
|
|
96
|
+
for (let packageRoot of options.accessPolicy.getAllowedPackageRoots()) {
|
|
97
|
+
roots.add(packageRoot);
|
|
98
|
+
}
|
|
99
|
+
for (let packageRoot of getInjectedPackageRoots()) {
|
|
100
|
+
roots.add(packageRoot);
|
|
101
|
+
}
|
|
102
|
+
let filePaths = new Set();
|
|
103
|
+
for (let root of roots) {
|
|
104
|
+
await collectFiles(root, filePaths);
|
|
105
|
+
}
|
|
106
|
+
return [...filePaths];
|
|
107
|
+
}
|
|
108
|
+
function resolveDiscoveryRoot(rootDir, pattern) {
|
|
109
|
+
let dynamicIndex = pattern.search(globSyntaxPattern);
|
|
110
|
+
if (dynamicIndex === -1)
|
|
111
|
+
return resolveFilePath(rootDir, pattern);
|
|
112
|
+
let rawStaticPrefix = pattern.slice(0, dynamicIndex);
|
|
113
|
+
let staticPrefix = rawStaticPrefix.replace(/[/\\]+$/, '');
|
|
114
|
+
if (staticPrefix.length === 0)
|
|
115
|
+
return rootDir;
|
|
116
|
+
return resolveFilePath(rootDir, /[/\\]$/.test(rawStaticPrefix) ? staticPrefix : path.dirname(staticPrefix));
|
|
117
|
+
}
|
|
118
|
+
async function collectFiles(root, filePaths) {
|
|
119
|
+
let stat;
|
|
120
|
+
try {
|
|
121
|
+
stat = await fsPromises.stat(root);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
if (isPathNotFoundError(error))
|
|
125
|
+
return;
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
if (stat.isFile()) {
|
|
129
|
+
filePaths.add(normalizeFilePath(root));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (!stat.isDirectory())
|
|
133
|
+
return;
|
|
134
|
+
let entries = await fsPromises.readdir(root, { withFileTypes: true });
|
|
135
|
+
for (let entry of entries) {
|
|
136
|
+
let entryPath = path.join(root, entry.name);
|
|
137
|
+
if (entry.isDirectory()) {
|
|
138
|
+
await collectFiles(entryPath, filePaths);
|
|
139
|
+
}
|
|
140
|
+
else if (entry.isFile()) {
|
|
141
|
+
filePaths.add(normalizeFilePath(entryPath));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async function pathExists(filePath) {
|
|
146
|
+
try {
|
|
147
|
+
await fsPromises.access(filePath);
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
if (isPathNotFoundError(error))
|
|
152
|
+
return false;
|
|
153
|
+
throw error;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function isPathNotFoundError(error) {
|
|
157
|
+
return (error instanceof Error &&
|
|
158
|
+
'code' in error &&
|
|
159
|
+
(error.code === 'ENOENT' || error.code === 'ENOTDIR'));
|
|
160
|
+
}
|
package/dist/lib/routes.d.ts
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
interface
|
|
2
|
-
|
|
1
|
+
interface MountConfig {
|
|
2
|
+
mounts: Readonly<Record<string, string>>;
|
|
3
3
|
rootDir: string;
|
|
4
4
|
}
|
|
5
5
|
export interface CompiledRoutes {
|
|
6
6
|
resolveUrlPathname(pathname: string): string | null;
|
|
7
|
+
matchUrlPathname(pathname: string): AssetRouteMatch | null;
|
|
7
8
|
toUrlPathname(filePath: string): string | null;
|
|
9
|
+
matchFilePath(filePath: string): AssetRouteMatch | null;
|
|
8
10
|
}
|
|
9
|
-
export
|
|
11
|
+
export interface AssetRouteMatch {
|
|
12
|
+
filePath: string;
|
|
13
|
+
fileRoot: string;
|
|
14
|
+
urlPathname: string;
|
|
15
|
+
urlRoot: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function compileRoutes(basePath: string, mountConfigs: readonly MountConfig[]): CompiledRoutes;
|
|
18
|
+
export declare function resolveMountFileRoot(rootDir: string, fileRoot: string): string;
|
|
10
19
|
export {};
|
|
11
20
|
//# sourceMappingURL=routes.d.ts.map
|
package/dist/lib/routes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/lib/routes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/lib/routes.ts"],"names":[],"mappings":"AASA,UAAU,WAAW;IACnB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACxC,OAAO,EAAE,MAAM,CAAA;CAChB;AASD,MAAM,WAAW,cAAc;IAC7B,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACnD,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAAA;IAC1D,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAC9C,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAAA;CACxD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,SAAS,WAAW,EAAE,GACnC,cAAc,CA8DhB;AAuCD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAU9E"}
|