@emkodev/emroute 1.8.2-beta.2 → 1.10.0-beta.2
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/core/component/widget.component.ts +1 -1
- package/core/pipeline/pipeline.ts +34 -1
- package/core/renderer/html.renderer.ts +16 -18
- package/core/renderer/md.renderer.ts +2 -4
- package/core/renderer/ssr.renderer.ts +5 -13
- package/core/server/emroute.server.ts +9 -25
- 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 +6 -0
- package/dist/core/pipeline/pipeline.js +31 -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 +2 -4
- package/dist/core/renderer/md.renderer.js.map +1 -1
- package/dist/core/renderer/ssr.renderer.d.ts +4 -5
- package/dist/core/renderer/ssr.renderer.js +3 -15
- package/dist/core/renderer/ssr.renderer.js.map +1 -1
- package/dist/core/server/emroute.server.d.ts +2 -2
- package/dist/core/server/emroute.server.js +7 -23
- package/dist/core/server/emroute.server.js.map +1 -1
- package/dist/core/widget/widget.registry.d.ts +3 -16
- package/dist/core/widget/widget.registry.js +3 -34
- package/dist/core/widget/widget.registry.js.map +1 -1
- package/dist/emroute.js +435 -96
- package/dist/emroute.js.map +14 -12
- 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/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.js +1 -6
- 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/index.ts +0 -1
- package/src/renderer/spa/emroute.app.ts +2 -6
- 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/core/widget/widget.registry.ts +0 -63
package/dist/emroute.js
CHANGED
|
@@ -472,47 +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
|
-
addLazy(name, modulePath) {
|
|
482
|
-
if (!this.entries.has(name)) {
|
|
483
|
-
this.entries.set(name, { modulePath });
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
get(name) {
|
|
487
|
-
return this.entries.get(name)?.widget;
|
|
488
|
-
}
|
|
489
|
-
getModulePath(name) {
|
|
490
|
-
return this.entries.get(name)?.modulePath;
|
|
491
|
-
}
|
|
492
|
-
[Symbol.iterator]() {
|
|
493
|
-
const entries = this.entries.values();
|
|
494
|
-
return function* () {
|
|
495
|
-
for (const entry of entries) {
|
|
496
|
-
if (entry.widget)
|
|
497
|
-
yield entry.widget;
|
|
498
|
-
}
|
|
499
|
-
}();
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
function extractWidgetExport(mod) {
|
|
503
|
-
for (const value of Object.values(mod)) {
|
|
504
|
-
if (!value)
|
|
505
|
-
continue;
|
|
506
|
-
if (typeof value === "object" && "getData" in value) {
|
|
507
|
-
return value;
|
|
508
|
-
}
|
|
509
|
-
if (typeof value === "function" && value.prototype?.getData) {
|
|
510
|
-
return new value;
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
return null;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
475
|
// dist/core/router/route.trie.js
|
|
517
476
|
class RouteTrie {
|
|
518
477
|
tree;
|
|
@@ -735,6 +694,33 @@ class Pipeline {
|
|
|
735
694
|
}
|
|
736
695
|
return hierarchy;
|
|
737
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
|
+
}
|
|
704
|
+
async loadWidget(name) {
|
|
705
|
+
const path = await this.findWidgetModulePath(name);
|
|
706
|
+
if (!path)
|
|
707
|
+
return;
|
|
708
|
+
const mod = await this.loadModule(path);
|
|
709
|
+
return this.extractWidgetComponent(mod);
|
|
710
|
+
}
|
|
711
|
+
extractWidgetComponent(mod) {
|
|
712
|
+
for (const value of Object.values(mod)) {
|
|
713
|
+
if (!value)
|
|
714
|
+
continue;
|
|
715
|
+
if (typeof value === "object" && "getData" in value) {
|
|
716
|
+
return value;
|
|
717
|
+
}
|
|
718
|
+
if (typeof value === "function" && value.prototype?.getData) {
|
|
719
|
+
return new value;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
738
724
|
async loadModule(modulePath) {
|
|
739
725
|
const loader = this.moduleLoaders[modulePath];
|
|
740
726
|
if (loader) {
|
|
@@ -1040,25 +1026,14 @@ var page_component_default = new PageComponent;
|
|
|
1040
1026
|
// dist/core/renderer/ssr.renderer.js
|
|
1041
1027
|
class SsrRenderer {
|
|
1042
1028
|
pipeline;
|
|
1043
|
-
widgets;
|
|
1044
1029
|
logger;
|
|
1045
|
-
constructor(pipeline,
|
|
1030
|
+
constructor(pipeline, _options = {}) {
|
|
1046
1031
|
this.pipeline = pipeline;
|
|
1047
1032
|
this.logger = pipeline.logger;
|
|
1048
|
-
this.widgets = options.widgets ?? null;
|
|
1049
1033
|
}
|
|
1050
1034
|
async resolveWidget(name) {
|
|
1051
|
-
if (!this.widgets)
|
|
1052
|
-
return;
|
|
1053
|
-
const widget = this.widgets.get(name);
|
|
1054
|
-
if (widget)
|
|
1055
|
-
return widget;
|
|
1056
|
-
const path = this.widgets.getModulePath(name);
|
|
1057
|
-
if (!path)
|
|
1058
|
-
return;
|
|
1059
1035
|
try {
|
|
1060
|
-
|
|
1061
|
-
return extractWidgetExport(mod) ?? undefined;
|
|
1036
|
+
return await this.pipeline.loadWidget(name);
|
|
1062
1037
|
} catch (e) {
|
|
1063
1038
|
this.logger.error(`[${this.label}] Failed to load widget "${name}"`, e instanceof Error ? e : undefined);
|
|
1064
1039
|
return;
|
|
@@ -1227,18 +1202,16 @@ class SsrHtmlRenderer extends SsrRenderer {
|
|
|
1227
1202
|
let content = rawContent;
|
|
1228
1203
|
content = await this.expandMarkdown(content);
|
|
1229
1204
|
content = this.attributeSlots(content, route.pattern);
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
}, this.pipeline.contextProvider, this.logger);
|
|
1241
|
-
}
|
|
1205
|
+
content = await resolveWidgetTags(content, (name) => this.resolveWidget(name), routeInfo, async (name) => {
|
|
1206
|
+
const modulePath = await this.pipeline.findWidgetModulePath(name);
|
|
1207
|
+
if (modulePath) {
|
|
1208
|
+
const mod = await this.pipeline.loadModule(modulePath);
|
|
1209
|
+
const inlined = this.pipeline.getModuleFiles(mod);
|
|
1210
|
+
if (inlined)
|
|
1211
|
+
return inlined;
|
|
1212
|
+
}
|
|
1213
|
+
return {};
|
|
1214
|
+
}, this.pipeline.contextProvider, this.logger);
|
|
1242
1215
|
return { content, ...title !== undefined ? { title } : {} };
|
|
1243
1216
|
}
|
|
1244
1217
|
renderContent(component, args) {
|
|
@@ -1350,9 +1323,7 @@ class SsrMdRenderer extends SsrRenderer {
|
|
|
1350
1323
|
const { content: rawContent, title } = await this.loadRouteContent(routeInfo, route, isLeaf, signal);
|
|
1351
1324
|
let content = rawContent;
|
|
1352
1325
|
content = content.replaceAll(BARE_SLOT_BLOCK, routerSlotBlock(route.pattern));
|
|
1353
|
-
|
|
1354
|
-
content = await this.resolveWidgets(content, routeInfo);
|
|
1355
|
-
}
|
|
1326
|
+
content = await this.resolveWidgets(content, routeInfo);
|
|
1356
1327
|
return { content, ...title !== undefined ? { title } : {} };
|
|
1357
1328
|
}
|
|
1358
1329
|
renderContent(component, args) {
|
|
@@ -1382,7 +1353,7 @@ Path: \`${url.pathname}\``;
|
|
|
1382
1353
|
}
|
|
1383
1354
|
try {
|
|
1384
1355
|
let files;
|
|
1385
|
-
const modulePath = this.
|
|
1356
|
+
const modulePath = await this.pipeline.findWidgetModulePath(block.widgetName);
|
|
1386
1357
|
if (modulePath) {
|
|
1387
1358
|
const mod = await this.pipeline.loadModule(modulePath);
|
|
1388
1359
|
files = this.pipeline.getModuleFiles(mod);
|
|
@@ -1467,31 +1438,13 @@ class Emroute {
|
|
|
1467
1438
|
...config.extendContext ? { contextProvider: config.extendContext } : {},
|
|
1468
1439
|
...config.moduleLoaders ? { moduleLoaders: config.moduleLoaders } : {}
|
|
1469
1440
|
});
|
|
1470
|
-
let widgets;
|
|
1471
|
-
const widgetsResponse = await runtime.query(WIDGETS_MANIFEST_PATH);
|
|
1472
|
-
if (widgetsResponse.status !== 404) {
|
|
1473
|
-
const entries = await widgetsResponse.json();
|
|
1474
|
-
widgets = new WidgetRegistry;
|
|
1475
|
-
for (const entry of entries) {
|
|
1476
|
-
widgets.addLazy(entry.name, entry.modulePath);
|
|
1477
|
-
}
|
|
1478
|
-
}
|
|
1479
|
-
if (config.widgets) {
|
|
1480
|
-
if (!widgets)
|
|
1481
|
-
widgets = new WidgetRegistry;
|
|
1482
|
-
for (const w of config.widgets)
|
|
1483
|
-
widgets.add(w);
|
|
1484
|
-
}
|
|
1485
1441
|
let ssrHtmlRenderer = null;
|
|
1486
1442
|
let ssrMdRenderer = null;
|
|
1487
1443
|
if (spa !== "only") {
|
|
1488
1444
|
ssrHtmlRenderer = new SsrHtmlRenderer(pipeline, {
|
|
1489
|
-
...config.markdownRenderer ? { markdownRenderer: config.markdownRenderer } : {}
|
|
1490
|
-
...widgets ? { widgets } : {}
|
|
1491
|
-
});
|
|
1492
|
-
ssrMdRenderer = new SsrMdRenderer(pipeline, {
|
|
1493
|
-
...widgets ? { widgets } : {}
|
|
1445
|
+
...config.markdownRenderer ? { markdownRenderer: config.markdownRenderer } : {}
|
|
1494
1446
|
});
|
|
1447
|
+
ssrMdRenderer = new SsrMdRenderer(pipeline);
|
|
1495
1448
|
}
|
|
1496
1449
|
const title = config.title ?? "emroute";
|
|
1497
1450
|
const shellBase = spa === "root" || spa === "only" ? appBase : htmlBase;
|
|
@@ -1574,6 +1527,11 @@ class Emroute {
|
|
|
1574
1527
|
static async buildHtmlShell(runtime, title, basePath, spa) {
|
|
1575
1528
|
const baseTag = basePath ? `
|
|
1576
1529
|
<base href="${escapeHtml(basePath)}/">` : "";
|
|
1530
|
+
let manifestTag = "";
|
|
1531
|
+
if ((await runtime.query("/manifest.json")).status !== 404) {
|
|
1532
|
+
manifestTag = `
|
|
1533
|
+
<link rel="manifest" href="/manifest.json">`;
|
|
1534
|
+
}
|
|
1577
1535
|
let cssTag = "";
|
|
1578
1536
|
if ((await runtime.query("/main.css")).status !== 404) {
|
|
1579
1537
|
cssTag = `
|
|
@@ -1602,7 +1560,7 @@ ${importMap}
|
|
|
1602
1560
|
<meta charset="utf-8">
|
|
1603
1561
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1604
1562
|
<title>${escapeHtml(title)}</title>
|
|
1605
|
-
<style>@view-transition { navigation: auto; } router-slot { display: contents; }</style>${cssTag}
|
|
1563
|
+
<style>@view-transition { navigation: auto; } router-slot { display: contents; }</style>${manifestTag}${cssTag}
|
|
1606
1564
|
</head>
|
|
1607
1565
|
<body>
|
|
1608
1566
|
<router-slot></router-slot>${importMapHtml}${scriptHtml}
|
|
@@ -2426,9 +2384,7 @@ async function bootEmrouteApp(options) {
|
|
|
2426
2384
|
const elementsResponse = await runtime.handle(ELEMENTS_MANIFEST_PATH);
|
|
2427
2385
|
const elementEntries = elementsResponse.ok ? await elementsResponse.json() : [];
|
|
2428
2386
|
const moduleLoaders = buildLazyLoaders(routeTree, widgetEntries, elementEntries, runtime);
|
|
2429
|
-
const widgets = new WidgetRegistry;
|
|
2430
2387
|
for (const entry of widgetEntries) {
|
|
2431
|
-
widgets.addLazy(entry.name, entry.modulePath);
|
|
2432
2388
|
ComponentElement.registerLazy(entry.name, moduleLoaders[entry.modulePath]);
|
|
2433
2389
|
}
|
|
2434
2390
|
for (const entry of elementEntries) {
|
|
@@ -2450,7 +2406,6 @@ async function bootEmrouteApp(options) {
|
|
|
2450
2406
|
const mdRenderer = MarkdownElement.getConfiguredRenderer();
|
|
2451
2407
|
const server = await Emroute.create({
|
|
2452
2408
|
routeTree,
|
|
2453
|
-
widgets,
|
|
2454
2409
|
moduleLoaders,
|
|
2455
2410
|
...mdRenderer ? { markdownRenderer: mdRenderer } : {},
|
|
2456
2411
|
...options?.extendContext ? { extendContext: options.extendContext } : {}
|
|
@@ -3031,6 +2986,388 @@ function createOverlayService() {
|
|
|
3031
2986
|
dismissAll
|
|
3032
2987
|
};
|
|
3033
2988
|
}
|
|
2989
|
+
// dist/runtime/cache.runtime.js
|
|
2990
|
+
var __rewriteRelativeImportExtension2 = function(path, preserveJsx) {
|
|
2991
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
2992
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
|
|
2993
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
|
|
2994
|
+
});
|
|
2995
|
+
}
|
|
2996
|
+
return path;
|
|
2997
|
+
};
|
|
2998
|
+
|
|
2999
|
+
class CacheRuntime extends Runtime {
|
|
3000
|
+
cache = null;
|
|
3001
|
+
cacheName;
|
|
3002
|
+
constructor(cacheName, config = {}) {
|
|
3003
|
+
super(config);
|
|
3004
|
+
this.cacheName = cacheName;
|
|
3005
|
+
}
|
|
3006
|
+
async getCache() {
|
|
3007
|
+
this.cache ??= await caches.open(this.cacheName);
|
|
3008
|
+
return this.cache;
|
|
3009
|
+
}
|
|
3010
|
+
handle(resource, init) {
|
|
3011
|
+
const path = this.parsePath(resource);
|
|
3012
|
+
const method = init?.method ?? "GET";
|
|
3013
|
+
switch (method) {
|
|
3014
|
+
case "PUT":
|
|
3015
|
+
return this.write(path, init?.body ?? null);
|
|
3016
|
+
case "DELETE":
|
|
3017
|
+
return this.delete(path);
|
|
3018
|
+
default:
|
|
3019
|
+
return this.read(path);
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
query(resource, options) {
|
|
3023
|
+
if (options?.as === "text") {
|
|
3024
|
+
return this.read(this.parsePath(resource)).then(async (r) => {
|
|
3025
|
+
if (r.status === 404)
|
|
3026
|
+
throw new Error(`Not found: ${this.parsePath(resource)}`);
|
|
3027
|
+
return r.text();
|
|
3028
|
+
});
|
|
3029
|
+
}
|
|
3030
|
+
return this.handle(resource, options);
|
|
3031
|
+
}
|
|
3032
|
+
async loadModule(path) {
|
|
3033
|
+
const response = await this.read(path);
|
|
3034
|
+
if (response.status === 404) {
|
|
3035
|
+
throw new Error(`Module not found in cache: ${path}`);
|
|
3036
|
+
}
|
|
3037
|
+
const js = await response.text();
|
|
3038
|
+
const blob = new Blob([js], { type: "application/javascript" });
|
|
3039
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
3040
|
+
try {
|
|
3041
|
+
return await import(__rewriteRelativeImportExtension2(objectUrl));
|
|
3042
|
+
} finally {
|
|
3043
|
+
URL.revokeObjectURL(objectUrl);
|
|
3044
|
+
}
|
|
3045
|
+
}
|
|
3046
|
+
async read(path) {
|
|
3047
|
+
const cache = await this.getCache();
|
|
3048
|
+
const key = new Request(this.toFakeUrl(path));
|
|
3049
|
+
const cached = await cache.match(key);
|
|
3050
|
+
if (!cached)
|
|
3051
|
+
return new Response("Not Found", { status: 404 });
|
|
3052
|
+
return cached;
|
|
3053
|
+
}
|
|
3054
|
+
async write(path, body) {
|
|
3055
|
+
const cache = await this.getCache();
|
|
3056
|
+
const ext = path.slice(path.lastIndexOf(".")).toLowerCase();
|
|
3057
|
+
const contentType = CONTENT_TYPES.get(ext) ?? "application/octet-stream";
|
|
3058
|
+
const response = new Response(body, {
|
|
3059
|
+
status: 200,
|
|
3060
|
+
headers: { "Content-Type": contentType }
|
|
3061
|
+
});
|
|
3062
|
+
await cache.put(new Request(this.toFakeUrl(path)), response);
|
|
3063
|
+
return new Response(null, { status: 204 });
|
|
3064
|
+
}
|
|
3065
|
+
async delete(path) {
|
|
3066
|
+
const cache = await this.getCache();
|
|
3067
|
+
await cache.delete(new Request(this.toFakeUrl(path)));
|
|
3068
|
+
return new Response(null, { status: 204 });
|
|
3069
|
+
}
|
|
3070
|
+
parsePath(resource) {
|
|
3071
|
+
if (typeof resource === "string")
|
|
3072
|
+
return resource;
|
|
3073
|
+
if (resource instanceof URL)
|
|
3074
|
+
return resource.pathname;
|
|
3075
|
+
return new URL(resource.url).pathname;
|
|
3076
|
+
}
|
|
3077
|
+
toFakeUrl(path) {
|
|
3078
|
+
return `https://emroute-cache${path}`;
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
|
|
3082
|
+
// dist/runtime/idb.runtime.js
|
|
3083
|
+
var __rewriteRelativeImportExtension3 = function(path, preserveJsx) {
|
|
3084
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3085
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
|
|
3086
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
|
|
3087
|
+
});
|
|
3088
|
+
}
|
|
3089
|
+
return path;
|
|
3090
|
+
};
|
|
3091
|
+
var STORE_NAME = "files";
|
|
3092
|
+
|
|
3093
|
+
class IdbRuntime extends Runtime {
|
|
3094
|
+
db = null;
|
|
3095
|
+
dbName;
|
|
3096
|
+
constructor(dbName, config = {}) {
|
|
3097
|
+
super(config);
|
|
3098
|
+
this.dbName = dbName;
|
|
3099
|
+
}
|
|
3100
|
+
open() {
|
|
3101
|
+
if (this.db)
|
|
3102
|
+
return Promise.resolve(this.db);
|
|
3103
|
+
return new Promise((resolve, reject) => {
|
|
3104
|
+
const request = indexedDB.open(this.dbName, 1);
|
|
3105
|
+
request.onupgradeneeded = () => {
|
|
3106
|
+
request.result.createObjectStore(STORE_NAME);
|
|
3107
|
+
};
|
|
3108
|
+
request.onsuccess = () => {
|
|
3109
|
+
this.db = request.result;
|
|
3110
|
+
resolve(this.db);
|
|
3111
|
+
};
|
|
3112
|
+
request.onerror = () => reject(request.error);
|
|
3113
|
+
});
|
|
3114
|
+
}
|
|
3115
|
+
handle(resource, init) {
|
|
3116
|
+
const [pathname, method, body] = this.parse(resource, init);
|
|
3117
|
+
switch (method) {
|
|
3118
|
+
case "PUT":
|
|
3119
|
+
return this.write(pathname, body);
|
|
3120
|
+
case "DELETE":
|
|
3121
|
+
return this.delete(pathname);
|
|
3122
|
+
default:
|
|
3123
|
+
return this.read(pathname);
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
query(resource, options) {
|
|
3127
|
+
if (options?.as === "text") {
|
|
3128
|
+
const pathname = this.parsePath(resource);
|
|
3129
|
+
return this.get(pathname).then((data) => {
|
|
3130
|
+
if (!data)
|
|
3131
|
+
throw new Error(`Not found: ${pathname}`);
|
|
3132
|
+
return new TextDecoder().decode(data);
|
|
3133
|
+
});
|
|
3134
|
+
}
|
|
3135
|
+
return this.handle(resource, options);
|
|
3136
|
+
}
|
|
3137
|
+
async loadModule(path) {
|
|
3138
|
+
const data = await this.get(path);
|
|
3139
|
+
if (!data)
|
|
3140
|
+
throw new Error(`Module not found in IDB: ${path}`);
|
|
3141
|
+
const buf = data.buffer;
|
|
3142
|
+
const blob = new Blob([buf], { type: "application/javascript" });
|
|
3143
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
3144
|
+
try {
|
|
3145
|
+
return await import(__rewriteRelativeImportExtension3(objectUrl));
|
|
3146
|
+
} finally {
|
|
3147
|
+
URL.revokeObjectURL(objectUrl);
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
async read(path) {
|
|
3151
|
+
if (path.endsWith("/")) {
|
|
3152
|
+
const children = await this.listChildren(path);
|
|
3153
|
+
if (children.length === 0)
|
|
3154
|
+
return new Response("Not Found", { status: 404 });
|
|
3155
|
+
return Response.json(children);
|
|
3156
|
+
}
|
|
3157
|
+
const data = await this.get(path);
|
|
3158
|
+
if (!data) {
|
|
3159
|
+
const children = await this.listChildren(path + "/");
|
|
3160
|
+
if (children.length > 0)
|
|
3161
|
+
return Response.json(children);
|
|
3162
|
+
return new Response("Not Found", { status: 404 });
|
|
3163
|
+
}
|
|
3164
|
+
const ext = path.slice(path.lastIndexOf(".")).toLowerCase();
|
|
3165
|
+
return new Response(data.buffer, {
|
|
3166
|
+
status: 200,
|
|
3167
|
+
headers: { "Content-Type": CONTENT_TYPES.get(ext) ?? "application/octet-stream" }
|
|
3168
|
+
});
|
|
3169
|
+
}
|
|
3170
|
+
async write(path, body) {
|
|
3171
|
+
const data = body ? new Uint8Array(await new Response(body).arrayBuffer()) : new Uint8Array;
|
|
3172
|
+
await this.put(path, data);
|
|
3173
|
+
return new Response(null, { status: 204 });
|
|
3174
|
+
}
|
|
3175
|
+
async delete(path) {
|
|
3176
|
+
const db = await this.open();
|
|
3177
|
+
return new Promise((resolve, reject) => {
|
|
3178
|
+
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
3179
|
+
tx.objectStore(STORE_NAME).delete(path);
|
|
3180
|
+
tx.oncomplete = () => resolve(new Response(null, { status: 204 }));
|
|
3181
|
+
tx.onerror = () => reject(tx.error);
|
|
3182
|
+
});
|
|
3183
|
+
}
|
|
3184
|
+
async get(path) {
|
|
3185
|
+
const db = await this.open();
|
|
3186
|
+
return new Promise((resolve, reject) => {
|
|
3187
|
+
const tx = db.transaction(STORE_NAME, "readonly");
|
|
3188
|
+
const req = tx.objectStore(STORE_NAME).get(path);
|
|
3189
|
+
req.onsuccess = () => resolve(req.result);
|
|
3190
|
+
req.onerror = () => reject(req.error);
|
|
3191
|
+
});
|
|
3192
|
+
}
|
|
3193
|
+
async put(path, data) {
|
|
3194
|
+
const db = await this.open();
|
|
3195
|
+
return new Promise((resolve, reject) => {
|
|
3196
|
+
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
3197
|
+
tx.objectStore(STORE_NAME).put(data, path);
|
|
3198
|
+
tx.oncomplete = () => resolve();
|
|
3199
|
+
tx.onerror = () => reject(tx.error);
|
|
3200
|
+
});
|
|
3201
|
+
}
|
|
3202
|
+
async listChildren(prefix) {
|
|
3203
|
+
const db = await this.open();
|
|
3204
|
+
return new Promise((resolve, reject) => {
|
|
3205
|
+
const tx = db.transaction(STORE_NAME, "readonly");
|
|
3206
|
+
const store = tx.objectStore(STORE_NAME);
|
|
3207
|
+
const range = IDBKeyRange.bound(prefix, prefix + "", false, false);
|
|
3208
|
+
const req = store.getAllKeys(range);
|
|
3209
|
+
req.onsuccess = () => {
|
|
3210
|
+
const entries = new Set;
|
|
3211
|
+
for (const key of req.result) {
|
|
3212
|
+
const rest = key.slice(prefix.length);
|
|
3213
|
+
const slashIdx = rest.indexOf("/");
|
|
3214
|
+
if (slashIdx === -1) {
|
|
3215
|
+
entries.add(rest);
|
|
3216
|
+
} else {
|
|
3217
|
+
entries.add(rest.slice(0, slashIdx + 1));
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
resolve([...entries]);
|
|
3221
|
+
};
|
|
3222
|
+
req.onerror = () => reject(req.error);
|
|
3223
|
+
});
|
|
3224
|
+
}
|
|
3225
|
+
parsePath(resource) {
|
|
3226
|
+
if (typeof resource === "string")
|
|
3227
|
+
return resource;
|
|
3228
|
+
if (resource instanceof URL)
|
|
3229
|
+
return resource.pathname;
|
|
3230
|
+
return new URL(resource.url).pathname;
|
|
3231
|
+
}
|
|
3232
|
+
parse(resource, init) {
|
|
3233
|
+
const pathname = this.parsePath(resource);
|
|
3234
|
+
if (typeof resource === "string" || resource instanceof URL) {
|
|
3235
|
+
return [pathname, init?.method ?? "GET", init?.body ?? null];
|
|
3236
|
+
}
|
|
3237
|
+
return [
|
|
3238
|
+
pathname,
|
|
3239
|
+
init?.method ?? resource.method,
|
|
3240
|
+
init?.body ?? resource.body
|
|
3241
|
+
];
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
|
|
3245
|
+
// dist/src/service-worker/emroute.sw.js
|
|
3246
|
+
class SwRuntime extends Runtime {
|
|
3247
|
+
cache;
|
|
3248
|
+
idb;
|
|
3249
|
+
constructor(cache, idb) {
|
|
3250
|
+
super();
|
|
3251
|
+
this.cache = cache;
|
|
3252
|
+
this.idb = idb;
|
|
3253
|
+
}
|
|
3254
|
+
handle(resource, init) {
|
|
3255
|
+
const method = init?.method ?? "GET";
|
|
3256
|
+
if (method === "PUT" || method === "DELETE") {
|
|
3257
|
+
return this.idb.handle(resource, init);
|
|
3258
|
+
}
|
|
3259
|
+
return this.cache.handle(resource, init).then(async (r) => {
|
|
3260
|
+
if (r.status !== 404)
|
|
3261
|
+
return r;
|
|
3262
|
+
return this.idb.handle(resource, init);
|
|
3263
|
+
});
|
|
3264
|
+
}
|
|
3265
|
+
query(resource, options) {
|
|
3266
|
+
if (options?.as === "text") {
|
|
3267
|
+
return this.handle(resource, options).then(async (r) => {
|
|
3268
|
+
if (r.status === 404) {
|
|
3269
|
+
const path = typeof resource === "string" ? resource : resource instanceof URL ? resource.pathname : new URL(resource.url).pathname;
|
|
3270
|
+
throw new Error(`Not found: ${path}`);
|
|
3271
|
+
}
|
|
3272
|
+
return r.text();
|
|
3273
|
+
});
|
|
3274
|
+
}
|
|
3275
|
+
return this.handle(resource, options);
|
|
3276
|
+
}
|
|
3277
|
+
async loadModule(path) {
|
|
3278
|
+
try {
|
|
3279
|
+
return await this.cache.loadModule(path);
|
|
3280
|
+
} catch {
|
|
3281
|
+
return await this.idb.loadModule(path);
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
function createEmrouteSW(options) {
|
|
3286
|
+
const { cacheName, precache, content = [], dbName = "emroute-content", origin = self.location.origin } = options;
|
|
3287
|
+
const cacheRuntime = new CacheRuntime(cacheName);
|
|
3288
|
+
const idbRuntime = new IdbRuntime(dbName);
|
|
3289
|
+
const swRuntime = new SwRuntime(cacheRuntime, idbRuntime);
|
|
3290
|
+
let emroute = null;
|
|
3291
|
+
async function getEmroute() {
|
|
3292
|
+
if (emroute)
|
|
3293
|
+
return emroute;
|
|
3294
|
+
emroute = await Emroute.create({
|
|
3295
|
+
spa: options.spa ?? "only",
|
|
3296
|
+
...options.basePath ? { basePath: options.basePath } : {},
|
|
3297
|
+
...options.title ? { title: options.title } : {},
|
|
3298
|
+
...options.markdownRenderer ? { markdownRenderer: options.markdownRenderer } : {},
|
|
3299
|
+
...options.extendContext ? { extendContext: options.extendContext } : {}
|
|
3300
|
+
}, swRuntime);
|
|
3301
|
+
return emroute;
|
|
3302
|
+
}
|
|
3303
|
+
self.addEventListener("install", (event) => {
|
|
3304
|
+
event.waitUntil((async () => {
|
|
3305
|
+
if (precache.length > 0) {
|
|
3306
|
+
const cache = await caches.open(cacheName);
|
|
3307
|
+
await Promise.all(precache.map(async (path) => {
|
|
3308
|
+
try {
|
|
3309
|
+
const response = await fetch(`${origin}${path}`);
|
|
3310
|
+
if (response.ok) {
|
|
3311
|
+
await cache.put(new Request(`https://emroute-cache${path}`), response);
|
|
3312
|
+
}
|
|
3313
|
+
} catch {
|
|
3314
|
+
console.error(`[emroute-sw] Failed to precache asset: ${path}`);
|
|
3315
|
+
}
|
|
3316
|
+
}));
|
|
3317
|
+
}
|
|
3318
|
+
if (content.length > 0) {
|
|
3319
|
+
await Promise.all(content.map(async (path) => {
|
|
3320
|
+
try {
|
|
3321
|
+
const response = await fetch(`${origin}${path}`);
|
|
3322
|
+
if (response.ok) {
|
|
3323
|
+
const data = new Uint8Array(await response.arrayBuffer());
|
|
3324
|
+
await idbRuntime.handle(path, {
|
|
3325
|
+
method: "PUT",
|
|
3326
|
+
body: data
|
|
3327
|
+
});
|
|
3328
|
+
}
|
|
3329
|
+
} catch {
|
|
3330
|
+
console.error(`[emroute-sw] Failed to precache content: ${path}`);
|
|
3331
|
+
}
|
|
3332
|
+
}));
|
|
3333
|
+
}
|
|
3334
|
+
await self.skipWaiting();
|
|
3335
|
+
})());
|
|
3336
|
+
});
|
|
3337
|
+
self.addEventListener("activate", (event) => {
|
|
3338
|
+
event.waitUntil((async () => {
|
|
3339
|
+
const keys = await caches.keys();
|
|
3340
|
+
await Promise.all(keys.filter((key) => key !== cacheName && key.startsWith("emroute")).map((key) => caches.delete(key)));
|
|
3341
|
+
await self.clients.claim();
|
|
3342
|
+
})());
|
|
3343
|
+
});
|
|
3344
|
+
self.addEventListener("fetch", (event) => {
|
|
3345
|
+
const url = new URL(event.request.url);
|
|
3346
|
+
if (url.origin !== self.location.origin)
|
|
3347
|
+
return;
|
|
3348
|
+
event.respondWith(handleFetch(event.request, url));
|
|
3349
|
+
});
|
|
3350
|
+
async function handleFetch(request, url) {
|
|
3351
|
+
if (request.mode === "navigate") {
|
|
3352
|
+
try {
|
|
3353
|
+
const server = await getEmroute();
|
|
3354
|
+
const response = await server.handleRequest(request);
|
|
3355
|
+
if (response)
|
|
3356
|
+
return response;
|
|
3357
|
+
} catch (e) {
|
|
3358
|
+
console.error("[emroute-sw] Navigation error:", e);
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
const cached = await swRuntime.handle(url.pathname);
|
|
3362
|
+
if (cached.status !== 404)
|
|
3363
|
+
return cached;
|
|
3364
|
+
try {
|
|
3365
|
+
return await fetch(request);
|
|
3366
|
+
} catch {
|
|
3367
|
+
return new Response("Offline", { status: 503 });
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3034
3371
|
// dist/src/widget/page-title.widget.js
|
|
3035
3372
|
class PageTitleWidget extends WidgetComponent {
|
|
3036
3373
|
name = "page-title";
|
|
@@ -3109,23 +3446,25 @@ export {
|
|
|
3109
3446
|
scopeWidgetCss,
|
|
3110
3447
|
escapeHtml,
|
|
3111
3448
|
createOverlayService,
|
|
3449
|
+
createEmrouteSW,
|
|
3112
3450
|
createEmrouteApp,
|
|
3113
3451
|
bootEmrouteApp,
|
|
3114
|
-
WidgetRegistry,
|
|
3115
3452
|
WidgetComponent,
|
|
3116
3453
|
RouterSlot,
|
|
3117
3454
|
RouteTrie,
|
|
3118
3455
|
PageTitleWidget,
|
|
3119
3456
|
PageComponent,
|
|
3120
3457
|
MarkdownElement,
|
|
3458
|
+
IdbRuntime,
|
|
3121
3459
|
FetchRuntime,
|
|
3122
3460
|
EmrouteApp,
|
|
3123
3461
|
Emroute,
|
|
3124
3462
|
DEFAULT_BASE_PATH,
|
|
3125
3463
|
ComponentElement,
|
|
3126
3464
|
Component,
|
|
3465
|
+
CacheRuntime,
|
|
3127
3466
|
BreadcrumbWidget
|
|
3128
3467
|
};
|
|
3129
3468
|
|
|
3130
|
-
//# debugId=
|
|
3469
|
+
//# debugId=2FED2FA156FADB3E64756E2164756E21
|
|
3131
3470
|
//# sourceMappingURL=emroute.js.map
|