@emkodev/emroute 1.8.2-beta.1 → 1.10.0-beta.1
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 +1 -1
- package/core/component/widget.component.ts +1 -1
- package/core/pipeline/pipeline.ts +11 -1
- package/core/renderer/html.renderer.ts +16 -18
- package/core/renderer/md.renderer.ts +3 -5
- package/core/renderer/ssr.renderer.ts +21 -5
- package/core/server/emroute.server.ts +9 -62
- package/core/util/widget-resolve.util.ts +2 -2
- package/core/widget/widget.registry.ts +14 -28
- package/dist/core/component/widget.component.d.ts +1 -1
- package/dist/core/component/widget.component.js +1 -1
- package/dist/core/pipeline/pipeline.d.ts +1 -0
- package/dist/core/pipeline/pipeline.js +9 -1
- package/dist/core/pipeline/pipeline.js.map +1 -1
- package/dist/core/renderer/html.renderer.js +10 -12
- package/dist/core/renderer/html.renderer.js.map +1 -1
- package/dist/core/renderer/md.renderer.js +3 -5
- package/dist/core/renderer/md.renderer.js.map +1 -1
- package/dist/core/renderer/ssr.renderer.d.ts +6 -4
- package/dist/core/renderer/ssr.renderer.js +16 -3
- package/dist/core/renderer/ssr.renderer.js.map +1 -1
- package/dist/core/server/emroute.server.d.ts +2 -4
- package/dist/core/server/emroute.server.js +7 -52
- package/dist/core/server/emroute.server.js.map +1 -1
- package/dist/core/util/widget-resolve.util.d.ts +1 -3
- package/dist/core/util/widget-resolve.util.js +2 -2
- package/dist/core/util/widget-resolve.util.js.map +1 -1
- package/dist/core/widget/widget.registry.d.ts +5 -10
- package/dist/core/widget/widget.registry.js +15 -20
- package/dist/core/widget/widget.registry.js.map +1 -1
- package/dist/emroute.js +449 -95
- package/dist/emroute.js.map +17 -14
- package/dist/runtime/cache.runtime.d.ts +31 -0
- package/dist/runtime/cache.runtime.js +107 -0
- package/dist/runtime/cache.runtime.js.map +1 -0
- package/dist/runtime/idb.runtime.d.ts +31 -0
- package/dist/runtime/idb.runtime.js +178 -0
- package/dist/runtime/idb.runtime.js.map +1 -0
- package/dist/src/element/component.element.d.ts +4 -1
- package/dist/src/element/component.element.js +4 -1
- package/dist/src/element/component.element.js.map +1 -1
- package/dist/src/index.d.ts +0 -1
- package/dist/src/index.js +0 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/renderer/spa/emroute.app.d.ts +3 -0
- package/dist/src/renderer/spa/emroute.app.js +6 -4
- package/dist/src/renderer/spa/emroute.app.js.map +1 -1
- package/dist/src/renderer/spa/mod.d.ts +4 -3
- package/dist/src/renderer/spa/mod.js +5 -3
- package/dist/src/renderer/spa/mod.js.map +1 -1
- package/dist/src/service-worker/emroute.sw.d.ts +54 -0
- package/dist/src/service-worker/emroute.sw.js +181 -0
- package/dist/src/service-worker/emroute.sw.js.map +1 -0
- package/dist/src/service-worker/mod.d.ts +8 -0
- package/dist/src/service-worker/mod.js +9 -0
- package/dist/src/service-worker/mod.js.map +1 -0
- package/package.json +16 -1
- package/runtime/cache.runtime.ts +127 -0
- package/runtime/idb.runtime.ts +203 -0
- package/src/element/component.element.ts +4 -1
- package/src/index.ts +0 -1
- package/src/renderer/spa/emroute.app.ts +11 -4
- package/src/renderer/spa/mod.ts +6 -4
- package/src/service-worker/emroute.sw.ts +264 -0
- package/src/service-worker/mod.ts +9 -0
package/dist/emroute.js
CHANGED
|
@@ -472,27 +472,6 @@ class ComponentElement extends HTMLElementBase {
|
|
|
472
472
|
}
|
|
473
473
|
}
|
|
474
474
|
|
|
475
|
-
// dist/core/widget/widget.registry.js
|
|
476
|
-
class WidgetRegistry {
|
|
477
|
-
entries = new Map;
|
|
478
|
-
add(widget, modulePath) {
|
|
479
|
-
this.entries.set(widget.name, { widget, modulePath });
|
|
480
|
-
}
|
|
481
|
-
get(name) {
|
|
482
|
-
return this.entries.get(name)?.widget;
|
|
483
|
-
}
|
|
484
|
-
getModulePath(name) {
|
|
485
|
-
return this.entries.get(name)?.modulePath;
|
|
486
|
-
}
|
|
487
|
-
[Symbol.iterator]() {
|
|
488
|
-
const entries = this.entries.values();
|
|
489
|
-
return function* () {
|
|
490
|
-
for (const entry of entries)
|
|
491
|
-
yield entry.widget;
|
|
492
|
-
}();
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
475
|
// dist/core/router/route.trie.js
|
|
497
476
|
class RouteTrie {
|
|
498
477
|
tree;
|
|
@@ -715,6 +694,13 @@ class Pipeline {
|
|
|
715
694
|
}
|
|
716
695
|
return hierarchy;
|
|
717
696
|
}
|
|
697
|
+
async findWidgetModulePath(name) {
|
|
698
|
+
const response = await this.runtime.query(WIDGETS_MANIFEST_PATH);
|
|
699
|
+
if (response.status === 404)
|
|
700
|
+
return;
|
|
701
|
+
const entries = await response.json();
|
|
702
|
+
return entries.find((e) => e.name === name)?.modulePath;
|
|
703
|
+
}
|
|
718
704
|
async loadModule(modulePath) {
|
|
719
705
|
const loader = this.moduleLoaders[modulePath];
|
|
720
706
|
if (loader) {
|
|
@@ -806,7 +792,7 @@ async function resolveRecursively(content, parse, resolve, replace, depth = 0, l
|
|
|
806
792
|
}));
|
|
807
793
|
return replace(content, replacements);
|
|
808
794
|
}
|
|
809
|
-
function resolveWidgetTags(html,
|
|
795
|
+
function resolveWidgetTags(html, getWidget, routeInfo, loadFiles, contextProvider, logger = defaultLogger) {
|
|
810
796
|
const tagPattern = /<widget-(?<name>[a-z][a-z0-9-]*)(?<attrs>\s[^>]*)?>(?<content>.*?)<\/widget-\k<name>>/gis;
|
|
811
797
|
const wrappers = new Map;
|
|
812
798
|
const ssrAttrPattern = new RegExp(`\\s${SSR_ATTR}(?:\\s|=|$)`);
|
|
@@ -820,7 +806,7 @@ function resolveWidgetTags(html, registry, routeInfo, loadFiles, contextProvider
|
|
|
820
806
|
const resolve = async (match) => {
|
|
821
807
|
const widgetName = match.groups.name;
|
|
822
808
|
const attrsString = match.groups.attrs?.trim() ?? "";
|
|
823
|
-
const widget =
|
|
809
|
+
const widget = await getWidget(widgetName);
|
|
824
810
|
if (!widget)
|
|
825
811
|
return match[0];
|
|
826
812
|
const params = parseAttrsToParams(attrsString);
|
|
@@ -1017,15 +1003,40 @@ class PageComponent extends Component {
|
|
|
1017
1003
|
}
|
|
1018
1004
|
var page_component_default = new PageComponent;
|
|
1019
1005
|
|
|
1006
|
+
// dist/core/widget/widget.registry.js
|
|
1007
|
+
function extractWidgetExport(mod) {
|
|
1008
|
+
for (const value of Object.values(mod)) {
|
|
1009
|
+
if (!value)
|
|
1010
|
+
continue;
|
|
1011
|
+
if (typeof value === "object" && "getData" in value) {
|
|
1012
|
+
return value;
|
|
1013
|
+
}
|
|
1014
|
+
if (typeof value === "function" && value.prototype?.getData) {
|
|
1015
|
+
return new value;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
return null;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1020
1021
|
// dist/core/renderer/ssr.renderer.js
|
|
1021
1022
|
class SsrRenderer {
|
|
1022
1023
|
pipeline;
|
|
1023
|
-
widgets;
|
|
1024
1024
|
logger;
|
|
1025
|
-
constructor(pipeline,
|
|
1025
|
+
constructor(pipeline, _options = {}) {
|
|
1026
1026
|
this.pipeline = pipeline;
|
|
1027
1027
|
this.logger = pipeline.logger;
|
|
1028
|
-
|
|
1028
|
+
}
|
|
1029
|
+
async resolveWidget(name) {
|
|
1030
|
+
const path = await this.pipeline.findWidgetModulePath(name);
|
|
1031
|
+
if (!path)
|
|
1032
|
+
return;
|
|
1033
|
+
try {
|
|
1034
|
+
const mod = await this.pipeline.loadModule(path);
|
|
1035
|
+
return extractWidgetExport(mod) ?? undefined;
|
|
1036
|
+
} catch (e) {
|
|
1037
|
+
this.logger.error(`[${this.label}] Failed to load widget "${name}"`, e instanceof Error ? e : undefined);
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1029
1040
|
}
|
|
1030
1041
|
async render(url, signal) {
|
|
1031
1042
|
const matched = await this.pipeline.match(url);
|
|
@@ -1190,18 +1201,16 @@ class SsrHtmlRenderer extends SsrRenderer {
|
|
|
1190
1201
|
let content = rawContent;
|
|
1191
1202
|
content = await this.expandMarkdown(content);
|
|
1192
1203
|
content = this.attributeSlots(content, route.pattern);
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
}, this.pipeline.contextProvider, this.logger);
|
|
1204
|
-
}
|
|
1204
|
+
content = await resolveWidgetTags(content, (name) => this.resolveWidget(name), routeInfo, async (name) => {
|
|
1205
|
+
const modulePath = await this.pipeline.findWidgetModulePath(name);
|
|
1206
|
+
if (modulePath) {
|
|
1207
|
+
const mod = await this.pipeline.loadModule(modulePath);
|
|
1208
|
+
const inlined = this.pipeline.getModuleFiles(mod);
|
|
1209
|
+
if (inlined)
|
|
1210
|
+
return inlined;
|
|
1211
|
+
}
|
|
1212
|
+
return {};
|
|
1213
|
+
}, this.pipeline.contextProvider, this.logger);
|
|
1205
1214
|
return { content, ...title !== undefined ? { title } : {} };
|
|
1206
1215
|
}
|
|
1207
1216
|
renderContent(component, args) {
|
|
@@ -1313,9 +1322,7 @@ class SsrMdRenderer extends SsrRenderer {
|
|
|
1313
1322
|
const { content: rawContent, title } = await this.loadRouteContent(routeInfo, route, isLeaf, signal);
|
|
1314
1323
|
let content = rawContent;
|
|
1315
1324
|
content = content.replaceAll(BARE_SLOT_BLOCK, routerSlotBlock(route.pattern));
|
|
1316
|
-
|
|
1317
|
-
content = await this.resolveWidgets(content, routeInfo);
|
|
1318
|
-
}
|
|
1325
|
+
content = await this.resolveWidgets(content, routeInfo);
|
|
1319
1326
|
return { content, ...title !== undefined ? { title } : {} };
|
|
1320
1327
|
}
|
|
1321
1328
|
renderContent(component, args) {
|
|
@@ -1339,13 +1346,13 @@ Path: \`${url.pathname}\``;
|
|
|
1339
1346
|
if (block.parseError || !block.params) {
|
|
1340
1347
|
return `> **Error** (\`${block.widgetName}\`): ${block.parseError}`;
|
|
1341
1348
|
}
|
|
1342
|
-
const widget = this.
|
|
1349
|
+
const widget = await this.resolveWidget(block.widgetName);
|
|
1343
1350
|
if (!widget) {
|
|
1344
1351
|
return `> **Error**: Unknown widget \`${block.widgetName}\``;
|
|
1345
1352
|
}
|
|
1346
1353
|
try {
|
|
1347
1354
|
let files;
|
|
1348
|
-
const modulePath = this.
|
|
1355
|
+
const modulePath = await this.pipeline.findWidgetModulePath(block.widgetName);
|
|
1349
1356
|
if (modulePath) {
|
|
1350
1357
|
const mod = await this.pipeline.loadModule(modulePath);
|
|
1351
1358
|
files = this.pipeline.getModuleFiles(mod);
|
|
@@ -1430,28 +1437,13 @@ class Emroute {
|
|
|
1430
1437
|
...config.extendContext ? { contextProvider: config.extendContext } : {},
|
|
1431
1438
|
...config.moduleLoaders ? { moduleLoaders: config.moduleLoaders } : {}
|
|
1432
1439
|
});
|
|
1433
|
-
let widgets;
|
|
1434
|
-
const widgetsResponse = await runtime.query(WIDGETS_MANIFEST_PATH);
|
|
1435
|
-
if (widgetsResponse.status !== 404) {
|
|
1436
|
-
const entries = await widgetsResponse.json();
|
|
1437
|
-
widgets = await Emroute.importWidgets(entries, runtime);
|
|
1438
|
-
}
|
|
1439
|
-
if (config.widgets) {
|
|
1440
|
-
if (!widgets)
|
|
1441
|
-
widgets = new WidgetRegistry;
|
|
1442
|
-
for (const w of config.widgets)
|
|
1443
|
-
widgets.add(w);
|
|
1444
|
-
}
|
|
1445
1440
|
let ssrHtmlRenderer = null;
|
|
1446
1441
|
let ssrMdRenderer = null;
|
|
1447
1442
|
if (spa !== "only") {
|
|
1448
1443
|
ssrHtmlRenderer = new SsrHtmlRenderer(pipeline, {
|
|
1449
|
-
...config.markdownRenderer ? { markdownRenderer: config.markdownRenderer } : {}
|
|
1450
|
-
...widgets ? { widgets } : {}
|
|
1451
|
-
});
|
|
1452
|
-
ssrMdRenderer = new SsrMdRenderer(pipeline, {
|
|
1453
|
-
...widgets ? { widgets } : {}
|
|
1444
|
+
...config.markdownRenderer ? { markdownRenderer: config.markdownRenderer } : {}
|
|
1454
1445
|
});
|
|
1446
|
+
ssrMdRenderer = new SsrMdRenderer(pipeline);
|
|
1455
1447
|
}
|
|
1456
1448
|
const title = config.title ?? "emroute";
|
|
1457
1449
|
const shellBase = spa === "root" || spa === "only" ? appBase : htmlBase;
|
|
@@ -1531,38 +1523,14 @@ class Emroute {
|
|
|
1531
1523
|
const bare = pathname === "/" ? "" : pathname.slice(1).replace(/\/$/, "");
|
|
1532
1524
|
return Response.redirect(new URL(`${base}/${bare}`, url.origin), 302);
|
|
1533
1525
|
}
|
|
1534
|
-
static extractWidgetExport(mod) {
|
|
1535
|
-
for (const value of Object.values(mod)) {
|
|
1536
|
-
if (!value)
|
|
1537
|
-
continue;
|
|
1538
|
-
if (typeof value === "object" && "getData" in value) {
|
|
1539
|
-
return value;
|
|
1540
|
-
}
|
|
1541
|
-
if (typeof value === "function" && value.prototype?.getData) {
|
|
1542
|
-
return new value;
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
return null;
|
|
1546
|
-
}
|
|
1547
|
-
static async importWidgets(entries, runtime) {
|
|
1548
|
-
const registry = new WidgetRegistry;
|
|
1549
|
-
for (const entry of entries) {
|
|
1550
|
-
try {
|
|
1551
|
-
const runtimePath = entry.modulePath.startsWith("/") ? entry.modulePath : `/${entry.modulePath}`;
|
|
1552
|
-
const mod = await runtime.loadModule(runtimePath);
|
|
1553
|
-
const instance = Emroute.extractWidgetExport(mod);
|
|
1554
|
-
if (!instance)
|
|
1555
|
-
continue;
|
|
1556
|
-
registry.add(instance, runtimePath);
|
|
1557
|
-
} catch (e) {
|
|
1558
|
-
console.error(`[emroute] Failed to load widget ${entry.modulePath}:`, e);
|
|
1559
|
-
}
|
|
1560
|
-
}
|
|
1561
|
-
return registry;
|
|
1562
|
-
}
|
|
1563
1526
|
static async buildHtmlShell(runtime, title, basePath, spa) {
|
|
1564
1527
|
const baseTag = basePath ? `
|
|
1565
1528
|
<base href="${escapeHtml(basePath)}/">` : "";
|
|
1529
|
+
let manifestTag = "";
|
|
1530
|
+
if ((await runtime.query("/manifest.json")).status !== 404) {
|
|
1531
|
+
manifestTag = `
|
|
1532
|
+
<link rel="manifest" href="/manifest.json">`;
|
|
1533
|
+
}
|
|
1566
1534
|
let cssTag = "";
|
|
1567
1535
|
if ((await runtime.query("/main.css")).status !== 404) {
|
|
1568
1536
|
cssTag = `
|
|
@@ -1591,7 +1559,7 @@ ${importMap}
|
|
|
1591
1559
|
<meta charset="utf-8">
|
|
1592
1560
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1593
1561
|
<title>${escapeHtml(title)}</title>
|
|
1594
|
-
<style>@view-transition { navigation: auto; } router-slot { display: contents; }</style>${cssTag}
|
|
1562
|
+
<style>@view-transition { navigation: auto; } router-slot { display: contents; }</style>${manifestTag}${cssTag}
|
|
1595
1563
|
</head>
|
|
1596
1564
|
<body>
|
|
1597
1565
|
<router-slot></router-slot>${importMapHtml}${scriptHtml}
|
|
@@ -2415,7 +2383,6 @@ async function bootEmrouteApp(options) {
|
|
|
2415
2383
|
const elementsResponse = await runtime.handle(ELEMENTS_MANIFEST_PATH);
|
|
2416
2384
|
const elementEntries = elementsResponse.ok ? await elementsResponse.json() : [];
|
|
2417
2385
|
const moduleLoaders = buildLazyLoaders(routeTree, widgetEntries, elementEntries, runtime);
|
|
2418
|
-
const widgets = new WidgetRegistry;
|
|
2419
2386
|
for (const entry of widgetEntries) {
|
|
2420
2387
|
ComponentElement.registerLazy(entry.name, moduleLoaders[entry.modulePath]);
|
|
2421
2388
|
}
|
|
@@ -2432,12 +2399,15 @@ async function bootEmrouteApp(options) {
|
|
|
2432
2399
|
});
|
|
2433
2400
|
}
|
|
2434
2401
|
}
|
|
2402
|
+
if (options?.extendContext) {
|
|
2403
|
+
ComponentElement.setContextProvider(options.extendContext);
|
|
2404
|
+
}
|
|
2435
2405
|
const mdRenderer = MarkdownElement.getConfiguredRenderer();
|
|
2436
2406
|
const server = await Emroute.create({
|
|
2437
2407
|
routeTree,
|
|
2438
|
-
widgets,
|
|
2439
2408
|
moduleLoaders,
|
|
2440
|
-
...mdRenderer ? { markdownRenderer: mdRenderer } : {}
|
|
2409
|
+
...mdRenderer ? { markdownRenderer: mdRenderer } : {},
|
|
2410
|
+
...options?.extendContext ? { extendContext: options.extendContext } : {}
|
|
2441
2411
|
}, runtime);
|
|
2442
2412
|
return createEmrouteApp(server, options);
|
|
2443
2413
|
}
|
|
@@ -3015,6 +2985,388 @@ function createOverlayService() {
|
|
|
3015
2985
|
dismissAll
|
|
3016
2986
|
};
|
|
3017
2987
|
}
|
|
2988
|
+
// dist/runtime/cache.runtime.js
|
|
2989
|
+
var __rewriteRelativeImportExtension2 = function(path, preserveJsx) {
|
|
2990
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
2991
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
|
|
2992
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
|
|
2993
|
+
});
|
|
2994
|
+
}
|
|
2995
|
+
return path;
|
|
2996
|
+
};
|
|
2997
|
+
|
|
2998
|
+
class CacheRuntime extends Runtime {
|
|
2999
|
+
cache = null;
|
|
3000
|
+
cacheName;
|
|
3001
|
+
constructor(cacheName, config = {}) {
|
|
3002
|
+
super(config);
|
|
3003
|
+
this.cacheName = cacheName;
|
|
3004
|
+
}
|
|
3005
|
+
async getCache() {
|
|
3006
|
+
this.cache ??= await caches.open(this.cacheName);
|
|
3007
|
+
return this.cache;
|
|
3008
|
+
}
|
|
3009
|
+
handle(resource, init) {
|
|
3010
|
+
const path = this.parsePath(resource);
|
|
3011
|
+
const method = init?.method ?? "GET";
|
|
3012
|
+
switch (method) {
|
|
3013
|
+
case "PUT":
|
|
3014
|
+
return this.write(path, init?.body ?? null);
|
|
3015
|
+
case "DELETE":
|
|
3016
|
+
return this.delete(path);
|
|
3017
|
+
default:
|
|
3018
|
+
return this.read(path);
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
query(resource, options) {
|
|
3022
|
+
if (options?.as === "text") {
|
|
3023
|
+
return this.read(this.parsePath(resource)).then(async (r) => {
|
|
3024
|
+
if (r.status === 404)
|
|
3025
|
+
throw new Error(`Not found: ${this.parsePath(resource)}`);
|
|
3026
|
+
return r.text();
|
|
3027
|
+
});
|
|
3028
|
+
}
|
|
3029
|
+
return this.handle(resource, options);
|
|
3030
|
+
}
|
|
3031
|
+
async loadModule(path) {
|
|
3032
|
+
const response = await this.read(path);
|
|
3033
|
+
if (response.status === 404) {
|
|
3034
|
+
throw new Error(`Module not found in cache: ${path}`);
|
|
3035
|
+
}
|
|
3036
|
+
const js = await response.text();
|
|
3037
|
+
const blob = new Blob([js], { type: "application/javascript" });
|
|
3038
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
3039
|
+
try {
|
|
3040
|
+
return await import(__rewriteRelativeImportExtension2(objectUrl));
|
|
3041
|
+
} finally {
|
|
3042
|
+
URL.revokeObjectURL(objectUrl);
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
async read(path) {
|
|
3046
|
+
const cache = await this.getCache();
|
|
3047
|
+
const key = new Request(this.toFakeUrl(path));
|
|
3048
|
+
const cached = await cache.match(key);
|
|
3049
|
+
if (!cached)
|
|
3050
|
+
return new Response("Not Found", { status: 404 });
|
|
3051
|
+
return cached;
|
|
3052
|
+
}
|
|
3053
|
+
async write(path, body) {
|
|
3054
|
+
const cache = await this.getCache();
|
|
3055
|
+
const ext = path.slice(path.lastIndexOf(".")).toLowerCase();
|
|
3056
|
+
const contentType = CONTENT_TYPES.get(ext) ?? "application/octet-stream";
|
|
3057
|
+
const response = new Response(body, {
|
|
3058
|
+
status: 200,
|
|
3059
|
+
headers: { "Content-Type": contentType }
|
|
3060
|
+
});
|
|
3061
|
+
await cache.put(new Request(this.toFakeUrl(path)), response);
|
|
3062
|
+
return new Response(null, { status: 204 });
|
|
3063
|
+
}
|
|
3064
|
+
async delete(path) {
|
|
3065
|
+
const cache = await this.getCache();
|
|
3066
|
+
await cache.delete(new Request(this.toFakeUrl(path)));
|
|
3067
|
+
return new Response(null, { status: 204 });
|
|
3068
|
+
}
|
|
3069
|
+
parsePath(resource) {
|
|
3070
|
+
if (typeof resource === "string")
|
|
3071
|
+
return resource;
|
|
3072
|
+
if (resource instanceof URL)
|
|
3073
|
+
return resource.pathname;
|
|
3074
|
+
return new URL(resource.url).pathname;
|
|
3075
|
+
}
|
|
3076
|
+
toFakeUrl(path) {
|
|
3077
|
+
return `https://emroute-cache${path}`;
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
|
|
3081
|
+
// dist/runtime/idb.runtime.js
|
|
3082
|
+
var __rewriteRelativeImportExtension3 = function(path, preserveJsx) {
|
|
3083
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3084
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
|
|
3085
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
|
|
3086
|
+
});
|
|
3087
|
+
}
|
|
3088
|
+
return path;
|
|
3089
|
+
};
|
|
3090
|
+
var STORE_NAME = "files";
|
|
3091
|
+
|
|
3092
|
+
class IdbRuntime extends Runtime {
|
|
3093
|
+
db = null;
|
|
3094
|
+
dbName;
|
|
3095
|
+
constructor(dbName, config = {}) {
|
|
3096
|
+
super(config);
|
|
3097
|
+
this.dbName = dbName;
|
|
3098
|
+
}
|
|
3099
|
+
open() {
|
|
3100
|
+
if (this.db)
|
|
3101
|
+
return Promise.resolve(this.db);
|
|
3102
|
+
return new Promise((resolve, reject) => {
|
|
3103
|
+
const request = indexedDB.open(this.dbName, 1);
|
|
3104
|
+
request.onupgradeneeded = () => {
|
|
3105
|
+
request.result.createObjectStore(STORE_NAME);
|
|
3106
|
+
};
|
|
3107
|
+
request.onsuccess = () => {
|
|
3108
|
+
this.db = request.result;
|
|
3109
|
+
resolve(this.db);
|
|
3110
|
+
};
|
|
3111
|
+
request.onerror = () => reject(request.error);
|
|
3112
|
+
});
|
|
3113
|
+
}
|
|
3114
|
+
handle(resource, init) {
|
|
3115
|
+
const [pathname, method, body] = this.parse(resource, init);
|
|
3116
|
+
switch (method) {
|
|
3117
|
+
case "PUT":
|
|
3118
|
+
return this.write(pathname, body);
|
|
3119
|
+
case "DELETE":
|
|
3120
|
+
return this.delete(pathname);
|
|
3121
|
+
default:
|
|
3122
|
+
return this.read(pathname);
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
query(resource, options) {
|
|
3126
|
+
if (options?.as === "text") {
|
|
3127
|
+
const pathname = this.parsePath(resource);
|
|
3128
|
+
return this.get(pathname).then((data) => {
|
|
3129
|
+
if (!data)
|
|
3130
|
+
throw new Error(`Not found: ${pathname}`);
|
|
3131
|
+
return new TextDecoder().decode(data);
|
|
3132
|
+
});
|
|
3133
|
+
}
|
|
3134
|
+
return this.handle(resource, options);
|
|
3135
|
+
}
|
|
3136
|
+
async loadModule(path) {
|
|
3137
|
+
const data = await this.get(path);
|
|
3138
|
+
if (!data)
|
|
3139
|
+
throw new Error(`Module not found in IDB: ${path}`);
|
|
3140
|
+
const buf = data.buffer;
|
|
3141
|
+
const blob = new Blob([buf], { type: "application/javascript" });
|
|
3142
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
3143
|
+
try {
|
|
3144
|
+
return await import(__rewriteRelativeImportExtension3(objectUrl));
|
|
3145
|
+
} finally {
|
|
3146
|
+
URL.revokeObjectURL(objectUrl);
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
async read(path) {
|
|
3150
|
+
if (path.endsWith("/")) {
|
|
3151
|
+
const children = await this.listChildren(path);
|
|
3152
|
+
if (children.length === 0)
|
|
3153
|
+
return new Response("Not Found", { status: 404 });
|
|
3154
|
+
return Response.json(children);
|
|
3155
|
+
}
|
|
3156
|
+
const data = await this.get(path);
|
|
3157
|
+
if (!data) {
|
|
3158
|
+
const children = await this.listChildren(path + "/");
|
|
3159
|
+
if (children.length > 0)
|
|
3160
|
+
return Response.json(children);
|
|
3161
|
+
return new Response("Not Found", { status: 404 });
|
|
3162
|
+
}
|
|
3163
|
+
const ext = path.slice(path.lastIndexOf(".")).toLowerCase();
|
|
3164
|
+
return new Response(data.buffer, {
|
|
3165
|
+
status: 200,
|
|
3166
|
+
headers: { "Content-Type": CONTENT_TYPES.get(ext) ?? "application/octet-stream" }
|
|
3167
|
+
});
|
|
3168
|
+
}
|
|
3169
|
+
async write(path, body) {
|
|
3170
|
+
const data = body ? new Uint8Array(await new Response(body).arrayBuffer()) : new Uint8Array;
|
|
3171
|
+
await this.put(path, data);
|
|
3172
|
+
return new Response(null, { status: 204 });
|
|
3173
|
+
}
|
|
3174
|
+
async delete(path) {
|
|
3175
|
+
const db = await this.open();
|
|
3176
|
+
return new Promise((resolve, reject) => {
|
|
3177
|
+
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
3178
|
+
tx.objectStore(STORE_NAME).delete(path);
|
|
3179
|
+
tx.oncomplete = () => resolve(new Response(null, { status: 204 }));
|
|
3180
|
+
tx.onerror = () => reject(tx.error);
|
|
3181
|
+
});
|
|
3182
|
+
}
|
|
3183
|
+
async get(path) {
|
|
3184
|
+
const db = await this.open();
|
|
3185
|
+
return new Promise((resolve, reject) => {
|
|
3186
|
+
const tx = db.transaction(STORE_NAME, "readonly");
|
|
3187
|
+
const req = tx.objectStore(STORE_NAME).get(path);
|
|
3188
|
+
req.onsuccess = () => resolve(req.result);
|
|
3189
|
+
req.onerror = () => reject(req.error);
|
|
3190
|
+
});
|
|
3191
|
+
}
|
|
3192
|
+
async put(path, data) {
|
|
3193
|
+
const db = await this.open();
|
|
3194
|
+
return new Promise((resolve, reject) => {
|
|
3195
|
+
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
3196
|
+
tx.objectStore(STORE_NAME).put(data, path);
|
|
3197
|
+
tx.oncomplete = () => resolve();
|
|
3198
|
+
tx.onerror = () => reject(tx.error);
|
|
3199
|
+
});
|
|
3200
|
+
}
|
|
3201
|
+
async listChildren(prefix) {
|
|
3202
|
+
const db = await this.open();
|
|
3203
|
+
return new Promise((resolve, reject) => {
|
|
3204
|
+
const tx = db.transaction(STORE_NAME, "readonly");
|
|
3205
|
+
const store = tx.objectStore(STORE_NAME);
|
|
3206
|
+
const range = IDBKeyRange.bound(prefix, prefix + "", false, false);
|
|
3207
|
+
const req = store.getAllKeys(range);
|
|
3208
|
+
req.onsuccess = () => {
|
|
3209
|
+
const entries = new Set;
|
|
3210
|
+
for (const key of req.result) {
|
|
3211
|
+
const rest = key.slice(prefix.length);
|
|
3212
|
+
const slashIdx = rest.indexOf("/");
|
|
3213
|
+
if (slashIdx === -1) {
|
|
3214
|
+
entries.add(rest);
|
|
3215
|
+
} else {
|
|
3216
|
+
entries.add(rest.slice(0, slashIdx + 1));
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
resolve([...entries]);
|
|
3220
|
+
};
|
|
3221
|
+
req.onerror = () => reject(req.error);
|
|
3222
|
+
});
|
|
3223
|
+
}
|
|
3224
|
+
parsePath(resource) {
|
|
3225
|
+
if (typeof resource === "string")
|
|
3226
|
+
return resource;
|
|
3227
|
+
if (resource instanceof URL)
|
|
3228
|
+
return resource.pathname;
|
|
3229
|
+
return new URL(resource.url).pathname;
|
|
3230
|
+
}
|
|
3231
|
+
parse(resource, init) {
|
|
3232
|
+
const pathname = this.parsePath(resource);
|
|
3233
|
+
if (typeof resource === "string" || resource instanceof URL) {
|
|
3234
|
+
return [pathname, init?.method ?? "GET", init?.body ?? null];
|
|
3235
|
+
}
|
|
3236
|
+
return [
|
|
3237
|
+
pathname,
|
|
3238
|
+
init?.method ?? resource.method,
|
|
3239
|
+
init?.body ?? resource.body
|
|
3240
|
+
];
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
|
|
3244
|
+
// dist/src/service-worker/emroute.sw.js
|
|
3245
|
+
class SwRuntime extends Runtime {
|
|
3246
|
+
cache;
|
|
3247
|
+
idb;
|
|
3248
|
+
constructor(cache, idb) {
|
|
3249
|
+
super();
|
|
3250
|
+
this.cache = cache;
|
|
3251
|
+
this.idb = idb;
|
|
3252
|
+
}
|
|
3253
|
+
handle(resource, init) {
|
|
3254
|
+
const method = init?.method ?? "GET";
|
|
3255
|
+
if (method === "PUT" || method === "DELETE") {
|
|
3256
|
+
return this.idb.handle(resource, init);
|
|
3257
|
+
}
|
|
3258
|
+
return this.cache.handle(resource, init).then(async (r) => {
|
|
3259
|
+
if (r.status !== 404)
|
|
3260
|
+
return r;
|
|
3261
|
+
return this.idb.handle(resource, init);
|
|
3262
|
+
});
|
|
3263
|
+
}
|
|
3264
|
+
query(resource, options) {
|
|
3265
|
+
if (options?.as === "text") {
|
|
3266
|
+
return this.handle(resource, options).then(async (r) => {
|
|
3267
|
+
if (r.status === 404) {
|
|
3268
|
+
const path = typeof resource === "string" ? resource : resource instanceof URL ? resource.pathname : new URL(resource.url).pathname;
|
|
3269
|
+
throw new Error(`Not found: ${path}`);
|
|
3270
|
+
}
|
|
3271
|
+
return r.text();
|
|
3272
|
+
});
|
|
3273
|
+
}
|
|
3274
|
+
return this.handle(resource, options);
|
|
3275
|
+
}
|
|
3276
|
+
async loadModule(path) {
|
|
3277
|
+
try {
|
|
3278
|
+
return await this.cache.loadModule(path);
|
|
3279
|
+
} catch {
|
|
3280
|
+
return await this.idb.loadModule(path);
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
function createEmrouteSW(options) {
|
|
3285
|
+
const { cacheName, precache, content = [], dbName = "emroute-content", origin = self.location.origin } = options;
|
|
3286
|
+
const cacheRuntime = new CacheRuntime(cacheName);
|
|
3287
|
+
const idbRuntime = new IdbRuntime(dbName);
|
|
3288
|
+
const swRuntime = new SwRuntime(cacheRuntime, idbRuntime);
|
|
3289
|
+
let emroute = null;
|
|
3290
|
+
async function getEmroute() {
|
|
3291
|
+
if (emroute)
|
|
3292
|
+
return emroute;
|
|
3293
|
+
emroute = await Emroute.create({
|
|
3294
|
+
spa: options.spa ?? "only",
|
|
3295
|
+
...options.basePath ? { basePath: options.basePath } : {},
|
|
3296
|
+
...options.title ? { title: options.title } : {},
|
|
3297
|
+
...options.markdownRenderer ? { markdownRenderer: options.markdownRenderer } : {},
|
|
3298
|
+
...options.extendContext ? { extendContext: options.extendContext } : {}
|
|
3299
|
+
}, swRuntime);
|
|
3300
|
+
return emroute;
|
|
3301
|
+
}
|
|
3302
|
+
self.addEventListener("install", (event) => {
|
|
3303
|
+
event.waitUntil((async () => {
|
|
3304
|
+
if (precache.length > 0) {
|
|
3305
|
+
const cache = await caches.open(cacheName);
|
|
3306
|
+
await Promise.all(precache.map(async (path) => {
|
|
3307
|
+
try {
|
|
3308
|
+
const response = await fetch(`${origin}${path}`);
|
|
3309
|
+
if (response.ok) {
|
|
3310
|
+
await cache.put(new Request(`https://emroute-cache${path}`), response);
|
|
3311
|
+
}
|
|
3312
|
+
} catch {
|
|
3313
|
+
console.error(`[emroute-sw] Failed to precache asset: ${path}`);
|
|
3314
|
+
}
|
|
3315
|
+
}));
|
|
3316
|
+
}
|
|
3317
|
+
if (content.length > 0) {
|
|
3318
|
+
await Promise.all(content.map(async (path) => {
|
|
3319
|
+
try {
|
|
3320
|
+
const response = await fetch(`${origin}${path}`);
|
|
3321
|
+
if (response.ok) {
|
|
3322
|
+
const data = new Uint8Array(await response.arrayBuffer());
|
|
3323
|
+
await idbRuntime.handle(path, {
|
|
3324
|
+
method: "PUT",
|
|
3325
|
+
body: data
|
|
3326
|
+
});
|
|
3327
|
+
}
|
|
3328
|
+
} catch {
|
|
3329
|
+
console.error(`[emroute-sw] Failed to precache content: ${path}`);
|
|
3330
|
+
}
|
|
3331
|
+
}));
|
|
3332
|
+
}
|
|
3333
|
+
await self.skipWaiting();
|
|
3334
|
+
})());
|
|
3335
|
+
});
|
|
3336
|
+
self.addEventListener("activate", (event) => {
|
|
3337
|
+
event.waitUntil((async () => {
|
|
3338
|
+
const keys = await caches.keys();
|
|
3339
|
+
await Promise.all(keys.filter((key) => key !== cacheName && key.startsWith("emroute")).map((key) => caches.delete(key)));
|
|
3340
|
+
await self.clients.claim();
|
|
3341
|
+
})());
|
|
3342
|
+
});
|
|
3343
|
+
self.addEventListener("fetch", (event) => {
|
|
3344
|
+
const url = new URL(event.request.url);
|
|
3345
|
+
if (url.origin !== self.location.origin)
|
|
3346
|
+
return;
|
|
3347
|
+
event.respondWith(handleFetch(event.request, url));
|
|
3348
|
+
});
|
|
3349
|
+
async function handleFetch(request, url) {
|
|
3350
|
+
if (request.mode === "navigate") {
|
|
3351
|
+
try {
|
|
3352
|
+
const server = await getEmroute();
|
|
3353
|
+
const response = await server.handleRequest(request);
|
|
3354
|
+
if (response)
|
|
3355
|
+
return response;
|
|
3356
|
+
} catch (e) {
|
|
3357
|
+
console.error("[emroute-sw] Navigation error:", e);
|
|
3358
|
+
}
|
|
3359
|
+
}
|
|
3360
|
+
const cached = await swRuntime.handle(url.pathname);
|
|
3361
|
+
if (cached.status !== 404)
|
|
3362
|
+
return cached;
|
|
3363
|
+
try {
|
|
3364
|
+
return await fetch(request);
|
|
3365
|
+
} catch {
|
|
3366
|
+
return new Response("Offline", { status: 503 });
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3018
3370
|
// dist/src/widget/page-title.widget.js
|
|
3019
3371
|
class PageTitleWidget extends WidgetComponent {
|
|
3020
3372
|
name = "page-title";
|
|
@@ -3093,23 +3445,25 @@ export {
|
|
|
3093
3445
|
scopeWidgetCss,
|
|
3094
3446
|
escapeHtml,
|
|
3095
3447
|
createOverlayService,
|
|
3448
|
+
createEmrouteSW,
|
|
3096
3449
|
createEmrouteApp,
|
|
3097
3450
|
bootEmrouteApp,
|
|
3098
|
-
WidgetRegistry,
|
|
3099
3451
|
WidgetComponent,
|
|
3100
3452
|
RouterSlot,
|
|
3101
3453
|
RouteTrie,
|
|
3102
3454
|
PageTitleWidget,
|
|
3103
3455
|
PageComponent,
|
|
3104
3456
|
MarkdownElement,
|
|
3457
|
+
IdbRuntime,
|
|
3105
3458
|
FetchRuntime,
|
|
3106
3459
|
EmrouteApp,
|
|
3107
3460
|
Emroute,
|
|
3108
3461
|
DEFAULT_BASE_PATH,
|
|
3109
3462
|
ComponentElement,
|
|
3110
3463
|
Component,
|
|
3464
|
+
CacheRuntime,
|
|
3111
3465
|
BreadcrumbWidget
|
|
3112
3466
|
};
|
|
3113
3467
|
|
|
3114
|
-
//# debugId=
|
|
3468
|
+
//# debugId=FB9DE7997217939864756E2164756E21
|
|
3115
3469
|
//# sourceMappingURL=emroute.js.map
|