@markless/router 0.5.0 → 0.6.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/dist/create-server-entry-DaYssO9x.js +1331 -0
- package/dist/index-BjxpxRL7.d.ts +248 -0
- package/dist/index.d.ts +2 -233
- package/dist/index.js +64 -15
- package/dist/request-locals-z3rJTizs.js +90 -0
- package/dist/route-manifest-DMizh42B.js +456 -0
- package/dist/typescript-plugin.cjs +1 -1
- package/dist/typescript-plugin.js +1 -1
- package/dist/vite/runtime/create-route-discovery.js +1 -1
- package/dist/vite/runtime/create-server-entry.d.ts +16 -0
- package/dist/vite/runtime/create-server-entry.js +2 -658
- package/dist/vite/runtime/mdx-route.d.ts +21 -2
- package/dist/vite/runtime/mdx-route.js +5 -2
- package/dist/vite.js +205 -37
- package/package.json +4 -4
- package/src/vite/entries/fragment-entry.ts +283 -29
- package/dist/fragment-navigation-CIiNnFFc.js +0 -323
- package/dist/link-attributes-nY1Qkmx2.js +0 -7
- package/dist/request-files-Ca8E0FOo.js +0 -233
- package/dist/request-locals-BFPF6Vdm.js +0 -28
- package/dist/route-manifest-Bw_nFohL.js +0 -189
|
@@ -368,9 +368,23 @@ type ProtocolViewPayload = {
|
|
|
368
368
|
* Element children of the parent that stand before the rows. Rows occupy
|
|
369
369
|
* `[rowStartOffset, rowStartOffset + items.length)` among the parent's child
|
|
370
370
|
* elements; a repeat whose rows begin at 0 omits the field. A repeat whose
|
|
371
|
-
* prefix has no compile-time element count
|
|
371
|
+
* prefix has no compile-time element count says `rowEndOffset` instead, or
|
|
372
|
+
* ships no record at all when its suffix has none either.
|
|
372
373
|
*/
|
|
373
374
|
readonly rowStartOffset?: number;
|
|
375
|
+
/**
|
|
376
|
+
* Element children of the parent that stand after the rows, set only when
|
|
377
|
+
* the prefix has no compile-time element count. Rows then occupy the
|
|
378
|
+
* `items.length` element children ending `rowEndOffset` before the last.
|
|
379
|
+
*/
|
|
380
|
+
readonly rowEndOffset?: number;
|
|
381
|
+
/**
|
|
382
|
+
* The browser can never change these rows: the collection and every value a
|
|
383
|
+
* row shows are fixed once the page is served, so the record carries no row
|
|
384
|
+
* markup and resume neither follows the collection nor loads row-building
|
|
385
|
+
* code. Pay-per-use: a repeat whose rows can change omits the field.
|
|
386
|
+
*/
|
|
387
|
+
readonly fixed?: true;
|
|
374
388
|
/**
|
|
375
389
|
* The `@empty` arm's finished markup, for the mint that raises it when the
|
|
376
390
|
* collection empties after resume and takes it back out when a row returns.
|
|
@@ -756,11 +770,13 @@ type RuntimeGraphDelete = {
|
|
|
756
770
|
readonly graphNodeId: string;
|
|
757
771
|
readonly path: ReadonlyArray<string>;
|
|
758
772
|
};
|
|
773
|
+
/** DOM work a subscription holds back until its whole pass has run, so it lands in one task with that pass's journal. */
|
|
774
|
+
type RuntimeGraphCommit = () => void | Promise<void>;
|
|
759
775
|
type RuntimeGraphSubscription = {
|
|
760
776
|
readonly id: string;
|
|
761
777
|
readonly graphNodeId: string;
|
|
762
778
|
readonly path?: ReadonlyArray<string>;
|
|
763
|
-
readonly run: (value: unknown) => DomJournalResult | void | Promise<DomJournalResult | void>;
|
|
779
|
+
readonly run: (value: unknown) => DomJournalResult | RuntimeGraphCommit | void | Promise<DomJournalResult | RuntimeGraphCommit | void>;
|
|
764
780
|
};
|
|
765
781
|
/**
|
|
766
782
|
* Told about a write the moment it lands, before the flush that write schedules.
|
|
@@ -820,6 +836,8 @@ type RuntimeGraph = {
|
|
|
820
836
|
readonly settleWriteObservers?: () => Promise<void> | undefined;
|
|
821
837
|
/** Whether a write is waiting on a flush that has not yet reached the journal. */
|
|
822
838
|
readonly hasPendingFlush?: () => boolean;
|
|
839
|
+
/** Keeps the scheduled flush back until each returned release has run once; `flush()` itself still runs. */
|
|
840
|
+
readonly holdFlush?: () => () => void;
|
|
823
841
|
readonly subscribeJournal: (listener: DomJournalListener) => () => void;
|
|
824
842
|
readonly flush: () => Promise<void>;
|
|
825
843
|
readonly takeJournal: () => DomJournalEntry[];
|
|
@@ -897,6 +915,7 @@ type ResumeDomEvent = {
|
|
|
897
915
|
readonly bubbles?: boolean;
|
|
898
916
|
readonly preventDefault?: () => void;
|
|
899
917
|
readonly stopPropagation?: () => void;
|
|
918
|
+
readonly composedPath?: () => ReadonlyArray<ResumeDomElement>;
|
|
900
919
|
__marklessPressHost?: ResumeDomElement;
|
|
901
920
|
};
|
|
902
921
|
type ResumeSharedPatchEvent = {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { i as protocolStateVersion, n as protocolInstanceQualifies, t as protocolInstancePath } from "../../protocol-constants-B4WxrZAS.js";
|
|
2
|
+
//#endregion
|
|
2
3
|
//#region ../serializer/src/storage-cookie.ts
|
|
3
4
|
const STORAGE_RENDER_CONTEXT_READER = "storageValue";
|
|
4
5
|
//#endregion
|
|
@@ -582,9 +583,11 @@ const marklessDecodeScalarCell = (c, g, s) => {
|
|
|
582
583
|
const marklessFindElementAtDomOrderIndex = (r, i) => {
|
|
583
584
|
let c = r.__marklessCensus;
|
|
584
585
|
if (!c) {
|
|
585
|
-
const w = document.createTreeWalker(r,
|
|
586
|
+
const w = document.createTreeWalker(r, 129);
|
|
586
587
|
c = r.__marklessCensus = r.nodeType === 1 ? [r] : [];
|
|
587
|
-
for (let n; n = w.nextNode();) c.push(n);
|
|
588
|
+
for (let n; n = w.nextNode();) if (n.nodeType !== 8) c.push(n);
|
|
589
|
+
else if (n.data === "markless:page-start") c.length = 1;
|
|
590
|
+
else if (n.data === "markless:page-end") break;
|
|
588
591
|
}
|
|
589
592
|
return c[i];
|
|
590
593
|
};
|
package/dist/vite.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { r as transformRequestFileSource } from "./request-files-Ca8E0FOo.js";
|
|
1
|
+
import { c as PREFETCH_ATTRIBUTE, l as REPLACE_ATTRIBUTE, s as LINK_ATTRIBUTE, u as SCROLL_ATTRIBUTE } from "./request-locals-z3rJTizs.js";
|
|
2
|
+
import { l as transformRequestFileSource, n as buildRouteManifestFromFileIds, o as normalizeRouteFileId, r as isPageModuleFile, t as assertNoEndpointConflicts } from "./route-manifest-DMizh42B.js";
|
|
4
3
|
import { t as __marklessRouteHref } from "./route-href-CGooO_g6.js";
|
|
5
4
|
import { r as protocolIslandSegment } from "./protocol-constants-B4WxrZAS.js";
|
|
6
|
-
import { a as startFragmentNavigation, s as listenForLinkIntent } from "./
|
|
5
|
+
import { a as runFragmentNavigation, i as FRAGMENT_PATH_PREFIX, n as routerLinkBridgeModules, o as startFragmentNavigation, s as listenForLinkIntent } from "./create-server-entry-DaYssO9x.js";
|
|
7
6
|
import { dirname, extname, isAbsolute, join, normalize, relative, resolve } from "pathe";
|
|
8
7
|
import { decodePath, joinURL, parsePath, parseQuery, parseURL, stringifyQuery, withLeadingSlash, withQuery, withoutLeadingSlash } from "ufo";
|
|
9
8
|
import { existsSync } from "node:fs";
|
|
10
9
|
import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
11
10
|
import { nitro } from "nitro/vite";
|
|
12
11
|
import { minifySync, sortUserPlugins } from "vite";
|
|
13
|
-
import { isClientPrimarySourceRequest, isExecutionLogChunk, isMarklessNavigationPack, isRenderDataSourceRequest, isResumeSourceRequest, isRouteNavigationSourceRequest, isSymbolOnlySourceRequest, lazyStartupPackName, marklessDeferredChunkFileNames, optimizedDepsToInclude, plannedLandingFiles, startupPackOfLazy, symbolVirtualModuleSourceFile } from "@markless/bundler/preload";
|
|
14
|
-
import {
|
|
12
|
+
import { isClientPrimarySourceRequest, isExecutionLogChunk, isMarklessNavigationPack, isRenderDataSourceRequest, isResumeSourceRequest, isRouteNavigationSourceRequest, isSymbolOnlySourceRequest, lazyStartupPackName, marklessDeferredChunkFileNames, optimizedDepsToInclude, plannedLandingFiles, resolverVirtualModuleSourceFile, startupPackOfLazy, symbolVirtualModuleSourceFile, warmEvaluatedImports } from "@markless/bundler/preload";
|
|
13
|
+
import { MARKLESS_BUILD_PREFIX, MARKLESS_CHUNK_SPECIFIER_PREFIX, MARKLESS_IMPORT_MAP_ASSET, MARKLESS_PUBLIC_BUILD_METADATA_FILES, importMapScript, marklessBuildManifestDir } from "@markless/bundler/rolldown";
|
|
15
14
|
import { parseModule } from "@tsrx/yuku";
|
|
16
15
|
import { toHtml } from "hast-util-to-html";
|
|
17
16
|
import { HastReader, createMdxHastHandle, defineHastPlugin, dropHandle, materializeHastTree, resolveHastSubscriptions, serializeHandle, visitHastHandle } from "satteri";
|
|
@@ -119,6 +118,7 @@ function createLinkTypes() {
|
|
|
119
118
|
//#endregion
|
|
120
119
|
//#region src/vite/route-typegen.ts
|
|
121
120
|
const PAGE_EXTENSIONS = /* @__PURE__ */ new Set([".tsrx", ".mdx"]);
|
|
121
|
+
const ENDPOINT_EXTENSIONS = /* @__PURE__ */ new Set([".ts"]);
|
|
122
122
|
function routeTypegenPlugin() {
|
|
123
123
|
let root = "";
|
|
124
124
|
return {
|
|
@@ -137,26 +137,25 @@ function routeTypegenPlugin() {
|
|
|
137
137
|
async function writeRouteTypes(fs, root) {
|
|
138
138
|
const pageFiles = await discoverPageFiles(fs, root);
|
|
139
139
|
const manifest = buildRouteManifestFromFileIds(pageFiles);
|
|
140
|
+
assertNoEndpointConflicts(manifest, await discoverFiles(fs, root, "api", ENDPOINT_EXTENSIONS));
|
|
140
141
|
await writeIfChanged(fs, join(root, routeTypesEnvPath), routeTypesEnvDeclaration);
|
|
141
142
|
await writeIfChanged(fs, join(root, routeTypesOutputPath), createRouteTypesDeclaration(manifest));
|
|
142
143
|
}
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
function discoverPageFiles(fs, root) {
|
|
145
|
+
return discoverFiles(fs, root, "pages", PAGE_EXTENSIONS);
|
|
146
|
+
}
|
|
147
|
+
async function discoverFiles(fs, root, dir, extensions) {
|
|
145
148
|
const files = [];
|
|
146
|
-
await
|
|
149
|
+
await collectFiles(fs, root, join(root, dir), extensions, files);
|
|
147
150
|
return files.toSorted((left, right) => left.localeCompare(right));
|
|
148
151
|
}
|
|
149
|
-
async function
|
|
152
|
+
async function collectFiles(fs, root, dir, extensions, files) {
|
|
150
153
|
const entries = await readdirIfExists(fs, dir);
|
|
151
|
-
await Promise.all(entries.map((entry) =>
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
await collectPageFiles(fs, root, path, files);
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
if (entry.isFile() && PAGE_EXTENSIONS.has(extname(path))) files.push(withLeadingSlash(relative(root, path)));
|
|
154
|
+
await Promise.all(entries.map(async (entry) => {
|
|
155
|
+
const path = join(dir, entry.name);
|
|
156
|
+
if (entry.isDirectory()) await collectFiles(fs, root, path, extensions, files);
|
|
157
|
+
else if (entry.isFile() && extensions.has(extname(path))) files.push(withLeadingSlash(relative(root, path)));
|
|
158
|
+
}));
|
|
160
159
|
}
|
|
161
160
|
async function readdirIfExists(fs, dir) {
|
|
162
161
|
try {
|
|
@@ -513,7 +512,8 @@ function createClientAssetsManifest(input) {
|
|
|
513
512
|
resume: input.resumeEntry,
|
|
514
513
|
...input.prerenderWakeEntry ? { prerenderWake: input.prerenderWakeEntry } : {},
|
|
515
514
|
navigation: input.navigationEntry,
|
|
516
|
-
...input.fragmentEntry ? { fragment: input.fragmentEntry } : {}
|
|
515
|
+
...input.fragmentEntry ? { fragment: input.fragmentEntry } : {},
|
|
516
|
+
...input.fragmentImports?.length ? { fragmentImports: input.fragmentImports } : {}
|
|
517
517
|
},
|
|
518
518
|
routes: {
|
|
519
519
|
navigation: sortRouteMap(input.routes.navigation),
|
|
@@ -602,7 +602,8 @@ async function validateClientAssetsManifest(input, base, clientOutDir) {
|
|
|
602
602
|
resume: requiredString(input.entries.resume, "entries.resume"),
|
|
603
603
|
...input.entries.prerenderWake !== void 0 ? { prerenderWake: requiredString(input.entries.prerenderWake, "entries.prerenderWake") } : {},
|
|
604
604
|
navigation: requiredString(input.entries.navigation, "entries.navigation"),
|
|
605
|
-
...input.entries.fragment !== void 0 ? { fragment: requiredString(input.entries.fragment, "entries.fragment") } : {}
|
|
605
|
+
...input.entries.fragment !== void 0 ? { fragment: requiredString(input.entries.fragment, "entries.fragment") } : {},
|
|
606
|
+
...input.entries.fragmentImports !== void 0 ? { fragmentImports: requiredStrings(input.entries.fragmentImports, "entries.fragmentImports") } : {}
|
|
606
607
|
};
|
|
607
608
|
const routes = {
|
|
608
609
|
navigation: routeMap(input.routes.navigation, "routes.navigation"),
|
|
@@ -616,6 +617,7 @@ async function validateClientAssetsManifest(input, base, clientOutDir) {
|
|
|
616
617
|
...entries.prerenderWake !== void 0 ? [entries.prerenderWake] : [],
|
|
617
618
|
entries.navigation,
|
|
618
619
|
...entries.fragment !== void 0 ? [entries.fragment] : [],
|
|
620
|
+
...entries.fragmentImports ?? [],
|
|
619
621
|
...Object.values(routes.navigation).flat(),
|
|
620
622
|
...Object.values(routes.ssr).flat(),
|
|
621
623
|
...Object.values(routes.styles).flat(),
|
|
@@ -640,6 +642,10 @@ async function validateClientAssetsManifest(input, base, clientOutDir) {
|
|
|
640
642
|
...importMap ? { importMap } : {}
|
|
641
643
|
};
|
|
642
644
|
}
|
|
645
|
+
function requiredStrings(input, label) {
|
|
646
|
+
if (!Array.isArray(input)) throw clientAssetsManifestError(`has invalid ${label}`);
|
|
647
|
+
return input.map((item, index) => requiredString(item, `${label}[${index}]`));
|
|
648
|
+
}
|
|
643
649
|
function routeMap(input, label) {
|
|
644
650
|
if (!isRecord$1(input)) throw clientAssetsManifestError(`has invalid ${label}`);
|
|
645
651
|
const routes = {};
|
|
@@ -840,7 +846,7 @@ function emitQueuedResumeContainerEvent(source, { censusRepair = true } = {}) {
|
|
|
840
846
|
" const root = input.root;",
|
|
841
847
|
censusRepair ? " if (root.__marklessShifted) return import('@markless/web/fns/served-census-repair').then((census) => (census.marklessRepairCensus(root), resumeContainerEvent(input)));" : "",
|
|
842
848
|
" if (!root.__marklessDispatch) {",
|
|
843
|
-
" let handler = marklessResumeContainerEvent, tail = Promise.resolve(), done = tail, lastEvent = null, lastEventTime = undefined;",
|
|
849
|
+
" let handler = marklessResumeContainerEvent, tail = Promise.resolve(), done = tail, lastEvent = null, lastEventTime = undefined, seen = new WeakMap();",
|
|
844
850
|
" root.__marklessRegisterDispatch = next => {",
|
|
845
851
|
" const fallback = handler;",
|
|
846
852
|
" handler = input => next(input, fallback);",
|
|
@@ -848,7 +854,8 @@ function emitQueuedResumeContainerEvent(source, { censusRepair = true } = {}) {
|
|
|
848
854
|
" root.__marklessDispatch = next => {",
|
|
849
855
|
" const event = next.event, eventTime = event?.timeStamp;",
|
|
850
856
|
" if (event && next.eventRecord && next.element) event.__marklessPressHost ??= next.element;",
|
|
851
|
-
" if (event === lastEvent && eventTime === lastEventTime) return done;",
|
|
857
|
+
" if ((event === lastEvent && eventTime === lastEventTime) || (seen.has(event) && seen.get(event) === eventTime)) return done;",
|
|
858
|
+
" if (Object(event) === event) seen.set(event, eventTime);",
|
|
852
859
|
" lastEvent = event;",
|
|
853
860
|
" lastEventTime = eventTime;",
|
|
854
861
|
" let release;",
|
|
@@ -1444,6 +1451,63 @@ function nodes(value) {
|
|
|
1444
1451
|
return Array.isArray(value) ? value.filter((item) => node(item)) : [];
|
|
1445
1452
|
}
|
|
1446
1453
|
//#endregion
|
|
1454
|
+
//#region src/vite/nitro-fragment-requests.ts
|
|
1455
|
+
function fragmentRequestModule() {
|
|
1456
|
+
return {
|
|
1457
|
+
name: "markless-router:fragment-requests",
|
|
1458
|
+
async setup(nitro) {
|
|
1459
|
+
const dir = join(nitro.options.buildDir, "markless-router");
|
|
1460
|
+
const plugin = join(dir, "fragment-requests.mjs");
|
|
1461
|
+
await mkdir(dir, { recursive: true });
|
|
1462
|
+
await writeFile(plugin, [
|
|
1463
|
+
`const prefix = ${JSON.stringify(`${FRAGMENT_PATH_PREFIX}/`)};`,
|
|
1464
|
+
"export default function fragmentRequests(nitroApp) {",
|
|
1465
|
+
" nitroApp.hooks?.hook('request', (event) => {",
|
|
1466
|
+
" const { pathname } = event.url;",
|
|
1467
|
+
" if (!pathname.startsWith(prefix)) return;",
|
|
1468
|
+
" const page = new URL(event.url.href);",
|
|
1469
|
+
" page.pathname = pathname.slice(prefix.length - 1);",
|
|
1470
|
+
" event.url = page;",
|
|
1471
|
+
" });",
|
|
1472
|
+
"}",
|
|
1473
|
+
""
|
|
1474
|
+
].join("\n"));
|
|
1475
|
+
nitro.options.plugins.push(plugin);
|
|
1476
|
+
}
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
//#endregion
|
|
1480
|
+
//#region src/vite/nitro-prerender.ts
|
|
1481
|
+
function serverBuildState() {
|
|
1482
|
+
return { entry: void 0 };
|
|
1483
|
+
}
|
|
1484
|
+
function recordServerEntry(state, outDir, bundle, isServerEntry) {
|
|
1485
|
+
if (!outDir) return;
|
|
1486
|
+
const entries = Object.values(bundle).filter((item) => item.type === "chunk" && item.isEntry);
|
|
1487
|
+
const entry = entries.find((chunk) => chunk.facadeModuleId && isServerEntry(chunk.facadeModuleId)) ?? (entries.length === 1 ? entries[0] : void 0);
|
|
1488
|
+
if (entry) state.entry = resolve(outDir, entry.fileName);
|
|
1489
|
+
}
|
|
1490
|
+
function prerenderRendererModule(state) {
|
|
1491
|
+
return {
|
|
1492
|
+
name: "markless-router:prerender-renderer",
|
|
1493
|
+
setup(nitro) {
|
|
1494
|
+
nitro.hooks.hook("prerender:config", async (config) => {
|
|
1495
|
+
if (!state.entry) return;
|
|
1496
|
+
const dir = join(nitro.options.buildDir, "markless-router");
|
|
1497
|
+
const handler = join(dir, "prerender-renderer.mjs");
|
|
1498
|
+
await mkdir(dir, { recursive: true });
|
|
1499
|
+
await writeFile(handler, [
|
|
1500
|
+
`import * as service from ${JSON.stringify(state.entry)};`,
|
|
1501
|
+
"const server = service.default ?? service;",
|
|
1502
|
+
"export default ({ req }) => server.fetch(req);",
|
|
1503
|
+
""
|
|
1504
|
+
].join("\n"));
|
|
1505
|
+
config.renderer = { handler };
|
|
1506
|
+
});
|
|
1507
|
+
}
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
//#endregion
|
|
1447
1511
|
//#region src/vite/index.ts
|
|
1448
1512
|
const PAGE_SERVER_ONLY_PROPS = [{
|
|
1449
1513
|
exportName: "default",
|
|
@@ -1467,6 +1531,7 @@ const FRAGMENT_ENTRY_PATH_ID = "virtual:markless-router/fragment-entry-path";
|
|
|
1467
1531
|
const ROUTE_PRELOADS_ID = "virtual:markless-router/route-preloads";
|
|
1468
1532
|
const ROUTE_PRELOADS_PLACEHOLDER = "__MARKLESS_ROUTER_ROUTE_PRELOADS__";
|
|
1469
1533
|
const DOCUMENT_STYLESHEETS_PLACEHOLDER = "__MARKLESS_ROUTER_DOCUMENT_STYLESHEETS__";
|
|
1534
|
+
const LINK_BRIDGE_PATHS_PLACEHOLDER = "__MARKLESS_ROUTER_LINK_BRIDGE_PATHS__";
|
|
1470
1535
|
const SERVER_ENTRY_ID = "virtual:markless-router/server-entry";
|
|
1471
1536
|
const ROUTE_HREF_ID = "virtual:markless-router/route-href";
|
|
1472
1537
|
const ROUTER_OPTIONS_ID = "virtual:markless-router/options";
|
|
@@ -1507,7 +1572,7 @@ function router(options = {}) {
|
|
|
1507
1572
|
const fragmentEntry = resumeEntryState();
|
|
1508
1573
|
const routePreloads = routePreloadState();
|
|
1509
1574
|
return [
|
|
1510
|
-
routerConfigPlugin(nitroPlugins, resumeEntry, prerenderWakeEntry, navigationEntry, routePreloads, fragmentEntry),
|
|
1575
|
+
routerConfigPlugin(nitroPlugins, resumeEntry, prerenderWakeEntry, navigationEntry, routePreloads, fragmentEntry, serverBuildState()),
|
|
1511
1576
|
devSourceModuleRequestPlugin(),
|
|
1512
1577
|
pageServerOnlyPropsPlugin(),
|
|
1513
1578
|
mdxTransformPlugin(),
|
|
@@ -1516,6 +1581,7 @@ function router(options = {}) {
|
|
|
1516
1581
|
anchorTransformPlugin(),
|
|
1517
1582
|
htmlTransformPlugin(),
|
|
1518
1583
|
virtualModulesPlugin(resumeEntry, prerenderWakeEntry, navigationEntry, routePreloads, options, fragmentEntry),
|
|
1584
|
+
linkBridgeFilesPlugin(navigationEntry, fragmentEntry, options),
|
|
1519
1585
|
nitroPlugins
|
|
1520
1586
|
];
|
|
1521
1587
|
}
|
|
@@ -1523,7 +1589,9 @@ function pageServerOnlyPropsPlugin() {
|
|
|
1523
1589
|
return {
|
|
1524
1590
|
name: "markless-router:page-server-only-props",
|
|
1525
1591
|
configResolved(config) {
|
|
1526
|
-
config.plugins.find((plugin) => typeof plugin.api?.declareServerOnlyProps === "function")
|
|
1592
|
+
const markless = config.plugins.find((plugin) => typeof plugin.api?.declareServerOnlyProps === "function");
|
|
1593
|
+
markless?.api.declareServerOnlyProps((moduleId) => isPageModuleFile(normalizeRouteFileId(moduleId)) ? PAGE_SERVER_ONLY_PROPS : void 0);
|
|
1594
|
+
markless?.api.declareRouteModules?.((moduleId) => isPageModuleFile(normalizeRouteFileId(moduleId)));
|
|
1527
1595
|
}
|
|
1528
1596
|
};
|
|
1529
1597
|
}
|
|
@@ -1547,7 +1615,7 @@ function devSourceModuleRequestPlugin() {
|
|
|
1547
1615
|
}
|
|
1548
1616
|
};
|
|
1549
1617
|
}
|
|
1550
|
-
function routerConfigPlugin(nitroPluginsFromRouter, resumeEntry, prerenderWakeEntry, navigationEntry, routePreloads, fragmentEntry = resumeEntryState()) {
|
|
1618
|
+
function routerConfigPlugin(nitroPluginsFromRouter, resumeEntry, prerenderWakeEntry, navigationEntry, routePreloads, fragmentEntry = resumeEntryState(), serverBuild = serverBuildState()) {
|
|
1551
1619
|
let clientOutDir = "";
|
|
1552
1620
|
let clientEnvironmentName = "";
|
|
1553
1621
|
let clientEnvironmentConfig;
|
|
@@ -1581,7 +1649,7 @@ function routerConfigPlugin(nitroPluginsFromRouter, resumeEntry, prerenderWakeEn
|
|
|
1581
1649
|
ssrEnvironment.build.rolldownOptions.input ??= scopedVirtualEntryId(SERVER_ENTRY_ID, config.root);
|
|
1582
1650
|
const serverWatch = withWatchIgnores(config.server?.watch);
|
|
1583
1651
|
return {
|
|
1584
|
-
nitro: createNitroConfig(config.nitro, config.root, serverWatch.ignored, env?.command === "build"),
|
|
1652
|
+
nitro: createNitroConfig(config.nitro, config.root, serverWatch.ignored, env?.command === "build", serverBuild),
|
|
1585
1653
|
server: {
|
|
1586
1654
|
...config.server,
|
|
1587
1655
|
watch: serverWatch
|
|
@@ -1642,6 +1710,7 @@ function routerConfigPlugin(nitroPluginsFromRouter, resumeEntry, prerenderWakeEn
|
|
|
1642
1710
|
prerenderWakeEntry.fileName = manifest.entries.prerenderWake ? clientAssetFileName(manifest.entries.prerenderWake, manifest.base) : void 0;
|
|
1643
1711
|
navigationEntry.fileName = clientAssetFileName(manifest.entries.navigation, manifest.base);
|
|
1644
1712
|
fragmentEntry.fileName = manifest.entries.fragment ? clientAssetFileName(manifest.entries.fragment, manifest.base) : void 0;
|
|
1713
|
+
fragmentEntry.imports = manifest.entries.fragmentImports;
|
|
1645
1714
|
routePreloads.routes = manifest.routes;
|
|
1646
1715
|
routePreloads.persisted = true;
|
|
1647
1716
|
routePreloads.importMap = manifest.importMap;
|
|
@@ -1660,7 +1729,17 @@ function routerConfigPlugin(nitroPluginsFromRouter, resumeEntry, prerenderWakeEn
|
|
|
1660
1729
|
const navigationChunk = Object.values(bundle).find((item) => item.type === "chunk" && isVirtualEntryChunk(item, NAVIGATION_ENTRY_ORIGIN));
|
|
1661
1730
|
if (navigationChunk) navigationEntry.fileName = navigationChunk.fileName;
|
|
1662
1731
|
const fragmentChunk = Object.values(bundle).find((item) => item.type === "chunk" && isVirtualEntryChunk(item, FRAGMENT_ENTRY_ORIGIN));
|
|
1663
|
-
if (fragmentChunk)
|
|
1732
|
+
if (fragmentChunk) {
|
|
1733
|
+
fragmentEntry.fileName = fragmentChunk.fileName;
|
|
1734
|
+
const everyChunk = new Map(outputChunks(bundle).map((chunk) => [chunk.fileName, chunk]));
|
|
1735
|
+
const closure = /* @__PURE__ */ new Set();
|
|
1736
|
+
includeChunk(closure, {
|
|
1737
|
+
chunks: everyChunk,
|
|
1738
|
+
everyChunk
|
|
1739
|
+
}, fragmentChunk.fileName);
|
|
1740
|
+
closure.delete(fragmentChunk.fileName);
|
|
1741
|
+
fragmentEntry.imports = [...closure].map((fileName) => joinURL(routePreloads.base, fileName));
|
|
1742
|
+
}
|
|
1664
1743
|
routePreloads.routes = routeModulePreloadsFromBundle({
|
|
1665
1744
|
base: routePreloads.base,
|
|
1666
1745
|
bundle,
|
|
@@ -1680,15 +1759,19 @@ function routerConfigPlugin(nitroPluginsFromRouter, resumeEntry, prerenderWakeEn
|
|
|
1680
1759
|
resumeEntry: joinURL(routePreloads.base, resumeEntry.fileName),
|
|
1681
1760
|
...prerenderWakeEntry.fileName ? { prerenderWakeEntry: joinURL(routePreloads.base, prerenderWakeEntry.fileName) } : {},
|
|
1682
1761
|
navigationEntry: joinURL(routePreloads.base, navigationEntry.fileName),
|
|
1683
|
-
...fragmentEntry.fileName ? {
|
|
1762
|
+
...fragmentEntry.fileName ? {
|
|
1763
|
+
fragmentEntry: joinURL(routePreloads.base, fragmentEntry.fileName),
|
|
1764
|
+
fragmentImports: fragmentEntry.imports
|
|
1765
|
+
} : {},
|
|
1684
1766
|
routes: routePreloads.routes
|
|
1685
1767
|
});
|
|
1686
1768
|
}
|
|
1687
1769
|
}
|
|
1688
1770
|
},
|
|
1689
|
-
async writeBundle(
|
|
1771
|
+
async writeBundle(options, bundle) {
|
|
1690
1772
|
const environment = this.environment;
|
|
1691
1773
|
const isClientEnvironment = environment?.name ? environment.name === clientEnvironmentName : environment?.config === clientEnvironmentConfig;
|
|
1774
|
+
if (productionBuild && environment?.name === "ssr") recordServerEntry(serverBuild, options.dir, bundle, (id) => id.startsWith(`\0${SERVER_ENTRY_ID}`));
|
|
1692
1775
|
if (!productionBuild || !isClientEnvironment) return;
|
|
1693
1776
|
if (!pendingClientAssets) throw new Error("Markless Router client build finished without a client-assets manifest.");
|
|
1694
1777
|
const renames = bundle ? chunkRenamesSince(capturedChunkNames, bundle) : /* @__PURE__ */ new Map();
|
|
@@ -1701,6 +1784,7 @@ function routerConfigPlugin(nitroPluginsFromRouter, resumeEntry, prerenderWakeEn
|
|
|
1701
1784
|
navigationEntry,
|
|
1702
1785
|
fragmentEntry
|
|
1703
1786
|
]) if (entry.fileName) entry.fileName = renames.get(entry.fileName) ?? entry.fileName;
|
|
1787
|
+
fragmentEntry.imports = pendingClientAssets.entries.fragmentImports;
|
|
1704
1788
|
}
|
|
1705
1789
|
const importMap = bundle?.[MARKLESS_IMPORT_MAP_ASSET];
|
|
1706
1790
|
if (importMap?.type === "asset") pendingClientAssets = {
|
|
@@ -1744,6 +1828,7 @@ function requestFileIdForTransform(root, id) {
|
|
|
1744
1828
|
if (!isAbsolute(pathname)) return;
|
|
1745
1829
|
const relativeFileId = root ? withoutLeadingSlash(normalize(relative(root, pathname))) : withoutLeadingSlash(normalize(pathname));
|
|
1746
1830
|
if (relativeFileId.startsWith("api/") || relativeFileId.startsWith("middleware/")) return relativeFileId;
|
|
1831
|
+
if (relativeFileId.startsWith("pages/")) return void 0;
|
|
1747
1832
|
return relativeFileId.match(/(?:^|\/)((?:api|middleware)\/.+\.ts)$/)?.[1];
|
|
1748
1833
|
}
|
|
1749
1834
|
function requestFileBuildTransformPlugin(root) {
|
|
@@ -1760,7 +1845,7 @@ function requestFileBuildTransformPlugin(root) {
|
|
|
1760
1845
|
}
|
|
1761
1846
|
};
|
|
1762
1847
|
}
|
|
1763
|
-
function createNitroConfig(nitroConfig, root = ".", serverWatchIgnored = [], isBuild = false) {
|
|
1848
|
+
function createNitroConfig(nitroConfig, root = ".", serverWatchIgnored = [], isBuild = false, serverBuild = serverBuildState()) {
|
|
1764
1849
|
const scanDirs = Array.isArray(nitroConfig?.scanDirs) ? nitroConfig.scanDirs.filter((dir) => typeof dir === "string") : [];
|
|
1765
1850
|
const watchOptions = withWatchIgnores(nitroConfig?.watchOptions, serverWatchIgnored);
|
|
1766
1851
|
const publicAssets = Array.isArray(nitroConfig?.publicAssets) ? nitroConfig.publicAssets : [];
|
|
@@ -1780,9 +1865,15 @@ function createNitroConfig(nitroConfig, root = ".", serverWatchIgnored = [], isB
|
|
|
1780
1865
|
...publicAssets
|
|
1781
1866
|
],
|
|
1782
1867
|
routesDir: nitroConfig?.routesDir ?? ".output/markless/router/nitro-routes",
|
|
1868
|
+
modules: [
|
|
1869
|
+
...nitroConfig?.modules ?? [],
|
|
1870
|
+
fragmentRequestModule(),
|
|
1871
|
+
...isBuild ? [prerenderRendererModule(serverBuild)] : []
|
|
1872
|
+
],
|
|
1783
1873
|
...isBuild && { routeRules: {
|
|
1784
1874
|
[`/${MARKLESS_BUILD_PREFIX}**`]: { headers: { "cache-control": "public, max-age=31536000, immutable" } },
|
|
1785
|
-
|
|
1875
|
+
[`/_markless/links/**`]: { headers: { "cache-control": "public, max-age=31536000, immutable" } },
|
|
1876
|
+
...Object.fromEntries(MARKLESS_PUBLIC_BUILD_METADATA_FILES.map((file) => [`/${file}`, { headers: { "cache-control": "public, max-age=0, must-revalidate" } }])),
|
|
1786
1877
|
...nitroConfig?.routeRules
|
|
1787
1878
|
} },
|
|
1788
1879
|
rolldownConfig: withRequestFileBuildPlugin(nitroConfig?.rolldownConfig, root),
|
|
@@ -1935,8 +2026,75 @@ function linkIntentEnabled(options) {
|
|
|
1935
2026
|
return options.prefetch !== false;
|
|
1936
2027
|
}
|
|
1937
2028
|
function entryPathSource(exportName, entry, entryId, root) {
|
|
1938
|
-
const
|
|
1939
|
-
|
|
2029
|
+
return `export const ${exportName} = ${JSON.stringify(entryPath(entry, entryId, root))};`;
|
|
2030
|
+
}
|
|
2031
|
+
function entryPath(entry, entryId, root) {
|
|
2032
|
+
return entry.fileName ? joinURL(entry.base, entry.fileName) : joinURL(entry.base, "@id", scopedVirtualEntryId(entryId, root));
|
|
2033
|
+
}
|
|
2034
|
+
function linkBridgeFilesPlugin(navigationEntry, fragmentEntry, options) {
|
|
2035
|
+
let root = "";
|
|
2036
|
+
let base = "/";
|
|
2037
|
+
let clientOutDir = "";
|
|
2038
|
+
let debug = false;
|
|
2039
|
+
let modules = [];
|
|
2040
|
+
return {
|
|
2041
|
+
name: "markless-router:link-bridge-files",
|
|
2042
|
+
apply: "build",
|
|
2043
|
+
sharedDuringBuild: true,
|
|
2044
|
+
configResolved(config) {
|
|
2045
|
+
root = config.root;
|
|
2046
|
+
base = config.base;
|
|
2047
|
+
debug = config.define?.__MARKLESS_DEBUG_ENABLED__ === "true";
|
|
2048
|
+
const client = Object.values(config.environments).find((environment) => environment.consumer === "client");
|
|
2049
|
+
if (client) clientOutDir = resolve(config.root, client.build.outDir);
|
|
2050
|
+
},
|
|
2051
|
+
generateBundle: {
|
|
2052
|
+
order: "post",
|
|
2053
|
+
async handler(_options, bundle) {
|
|
2054
|
+
if (this.environment?.name !== "ssr") return;
|
|
2055
|
+
const chunks = outputChunks(bundle);
|
|
2056
|
+
const target = chunks.find((chunk) => chunk.code?.includes(LINK_BRIDGE_PATHS_PLACEHOLDER));
|
|
2057
|
+
if (!target) return;
|
|
2058
|
+
if (!navigationEntry.fileName) throw new Error("Markless Router built its server entry before its navigation entry.");
|
|
2059
|
+
const documentFile = join(root, "document.tsrx");
|
|
2060
|
+
const documentSource = await readFile(documentFile, "utf8").catch(() => void 0);
|
|
2061
|
+
const built = routerLinkBridgeModules({
|
|
2062
|
+
base,
|
|
2063
|
+
navigationEntryPath: entryPath(navigationEntry, NAVIGATION_ENTRY_ID, root),
|
|
2064
|
+
fragmentEntryPath: entryPath(fragmentEntry, FRAGMENT_ENTRY_ID, root),
|
|
2065
|
+
fragmentEntryImports: fragmentEntry.imports,
|
|
2066
|
+
fragmentNavigationSource: minifiedFragmentNavigationSource(),
|
|
2067
|
+
fragmentNavigationRunSource: minifiedFragmentNavigationSource(runFragmentNavigation),
|
|
2068
|
+
prefetch: options.prefetch,
|
|
2069
|
+
documentNavigation: documentNavigationFor(documentSource, documentFile),
|
|
2070
|
+
routeFileIds: bundledPageFileIds(chunks, root),
|
|
2071
|
+
debug
|
|
2072
|
+
});
|
|
2073
|
+
modules = built;
|
|
2074
|
+
target.code = target.code.replace(LINK_BRIDGE_PATHS_PLACEHOLDER, jsStringLiteralContent(JSON.stringify(built.slice(0, 2).map((module) => module.path))));
|
|
2075
|
+
}
|
|
2076
|
+
},
|
|
2077
|
+
async writeBundle() {
|
|
2078
|
+
if (this.environment?.name !== "ssr" || modules.length === 0) return;
|
|
2079
|
+
const prefix = base.replace(/\/?$/, "/");
|
|
2080
|
+
for (const module of modules) {
|
|
2081
|
+
const file = join(clientOutDir, module.path.slice(prefix.length));
|
|
2082
|
+
await mkdir(dirname(file), { recursive: true });
|
|
2083
|
+
await writeFile(file, module.source, "utf8");
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
2088
|
+
function bundledPageFileIds(chunks, root) {
|
|
2089
|
+
const files = /* @__PURE__ */ new Set();
|
|
2090
|
+
for (const chunk of chunks) for (const id of chunk.moduleIds ?? []) {
|
|
2091
|
+
if (id.startsWith("\0")) continue;
|
|
2092
|
+
const pathname = decodePath(parseURL(id).pathname);
|
|
2093
|
+
if (!isAbsolute(pathname)) continue;
|
|
2094
|
+
const file = normalizeRouteFileId(relative(root, pathname));
|
|
2095
|
+
if (isPageModuleFile(file)) files.add(file);
|
|
2096
|
+
}
|
|
2097
|
+
return [...files];
|
|
1940
2098
|
}
|
|
1941
2099
|
function serverEntrySource(root, options) {
|
|
1942
2100
|
const query = rootScopeQuery(root);
|
|
@@ -1950,14 +2108,17 @@ function serverEntrySource(root, options) {
|
|
|
1950
2108
|
`import { pageModuleLoaders, routeFileIds } from '${ROUTE_DISCOVERY_ID}${query}';`,
|
|
1951
2109
|
`import { documentNavigation } from '${ROUTER_OPTIONS_ID}${query}';`,
|
|
1952
2110
|
`const documentModuleLoaders = import.meta.glob(['/document.tsrx']);`,
|
|
2111
|
+
`const linkBridgePathsJson = globalThis.__marklessRouterLinkBridgePathsJson ?? ${JSON.stringify(LINK_BRIDGE_PATHS_PLACEHOLDER)};`,
|
|
1953
2112
|
`const entry = createServerEntry({`,
|
|
1954
2113
|
` dev: import.meta.env.DEV,`,
|
|
2114
|
+
` linkBridgePaths: linkBridgePathsJson === ${JSON.stringify(LINK_BRIDGE_PATHS_PLACEHOLDER)} ? undefined : JSON.parse(linkBridgePathsJson),`,
|
|
1955
2115
|
` base: import.meta.env.BASE_URL,`,
|
|
1956
2116
|
` resumeEntryPath,`,
|
|
1957
2117
|
` prerenderWakeEntryPath,`,
|
|
1958
2118
|
` navigationEntryPath,`,
|
|
1959
2119
|
` fragmentEntryPath,`,
|
|
1960
2120
|
` fragmentNavigationSource: ${JSON.stringify(minifiedFragmentNavigationSource())},`,
|
|
2121
|
+
` fragmentNavigationRunSource: ${JSON.stringify(minifiedFragmentNavigationSource(runFragmentNavigation))},`,
|
|
1961
2122
|
...options.prefetch === false ? [" prefetch: false,"] : [],
|
|
1962
2123
|
` routeModulePreloads,`,
|
|
1963
2124
|
` routeSsrModulePreloads,`,
|
|
@@ -1973,8 +2134,8 @@ function serverEntrySource(root, options) {
|
|
|
1973
2134
|
`export default entry;`
|
|
1974
2135
|
].join("\n");
|
|
1975
2136
|
}
|
|
1976
|
-
function minifiedFragmentNavigationSource() {
|
|
1977
|
-
const result = minifySync("markless-fragment-navigation.js", `export default (${
|
|
2137
|
+
function minifiedFragmentNavigationSource(source = startFragmentNavigation) {
|
|
2138
|
+
const result = minifySync("markless-fragment-navigation.js", `export default (${source.toString()});`, {
|
|
1978
2139
|
compress: true,
|
|
1979
2140
|
mangle: true,
|
|
1980
2141
|
module: true
|
|
@@ -2086,6 +2247,10 @@ function routeModulePreloadsFromBundle(input) {
|
|
|
2086
2247
|
routeChunkFileNames.add(chunk.fileName);
|
|
2087
2248
|
}
|
|
2088
2249
|
const symbolChunks = symbolChunksBySourceFile(chunks);
|
|
2250
|
+
const resolverSourceFiles = new Set(allChunks.flatMap((chunk) => (chunk.moduleIds ?? []).flatMap((moduleId) => {
|
|
2251
|
+
const sourceFile = resolverVirtualModuleSourceFile(moduleId.startsWith("\0") ? moduleId.slice(1) : moduleId);
|
|
2252
|
+
return sourceFile ? [sourceModulePathname(sourceFile)] : [];
|
|
2253
|
+
})));
|
|
2089
2254
|
const polyfillFileNames = new Set(chunks.filter((chunk) => chunk.facadeModuleId && input.navigationPolyfillIds?.has(chunk.facadeModuleId)).map((chunk) => chunk.fileName));
|
|
2090
2255
|
const navigation = {};
|
|
2091
2256
|
const ssr = {};
|
|
@@ -2135,8 +2300,10 @@ function routeModulePreloadsFromBundle(input) {
|
|
|
2135
2300
|
}
|
|
2136
2301
|
includeChunk(ssrFileNames, landingScope, landingChunk.fileName, true);
|
|
2137
2302
|
const routeSourceFiles = sourceFilesForChunks(/* @__PURE__ */ new Set([...navigationFileNames, ...ssrFileNames]), chunksByFileName);
|
|
2303
|
+
let routeHasSymbols = false;
|
|
2138
2304
|
for (const [sourceFile, symbolFileNames] of symbolChunks) {
|
|
2139
2305
|
if (!routeSourceFiles.has(sourceFile)) continue;
|
|
2306
|
+
routeHasSymbols = true;
|
|
2140
2307
|
for (const fileName of symbolFileNames) {
|
|
2141
2308
|
includeChunk(navigationFileNames, scope, fileName, true);
|
|
2142
2309
|
includeChunk(ssrFileNames, landingScope, fileName, true);
|
|
@@ -2145,6 +2312,7 @@ function routeModulePreloadsFromBundle(input) {
|
|
|
2145
2312
|
const styleFileNames = /* @__PURE__ */ new Set([...navigationFileNames, ...ssrFileNames]);
|
|
2146
2313
|
const planned = plannedLanding?.get(routeFile);
|
|
2147
2314
|
if (planned) narrowToPlanned(ssrFileNames, planned, landingScope, [input.resumeChunk, input.prerenderWakeChunk]);
|
|
2315
|
+
for (const fileName of ssrFileNames) for (const specifier of warmEvaluatedImports(everyChunk.get(fileName)?.code ?? "")) includeChunk(ssrFileNames, landingScope, normalize(join(dirname(fileName), specifier)));
|
|
2148
2316
|
navigation[routeFile] = [...navigationFileNames].map((fileName) => joinURL(input.base, fileName));
|
|
2149
2317
|
const firstEventPath = /* @__PURE__ */ new Set();
|
|
2150
2318
|
const lazySiblings = [...ssrFileNames].filter((fileName) => {
|
|
@@ -2157,7 +2325,7 @@ function routeModulePreloadsFromBundle(input) {
|
|
|
2157
2325
|
for (const fileName of routeScopedDynamicImports(entry, routeFile)) includeChunk(firstEventPath, landingScope, fileName);
|
|
2158
2326
|
}
|
|
2159
2327
|
for (const fileName of lazySiblings) includeChunk(firstEventPath, landingScope, fileName);
|
|
2160
|
-
ssr[routeFile] = [...[...firstEventPath].filter((fileName) => ssrFileNames.has(fileName)), ...[...ssrFileNames].filter((fileName) => !firstEventPath.has(fileName))].map((fileName) => joinURL(input.base, fileName));
|
|
2328
|
+
ssr[routeFile] = !routeHasSymbols && [...routeSourceFiles].some((file) => resolverSourceFiles.has(file)) ? [] : [...[...firstEventPath].filter((fileName) => ssrFileNames.has(fileName)), ...[...ssrFileNames].filter((fileName) => !firstEventPath.has(fileName))].map((fileName) => joinURL(input.base, fileName));
|
|
2161
2329
|
styles[routeFile] = routeStylesheetsForChunks(routeFileChunks, styleFileNames, chunksByFileName, input.base);
|
|
2162
2330
|
}
|
|
2163
2331
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markless/router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Markless router: client-side navigation with SSR streaming and build-time preload maps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -64,11 +64,11 @@
|
|
|
64
64
|
"pathe": "^2.0.3",
|
|
65
65
|
"satteri": "0.6.3",
|
|
66
66
|
"ufo": "^1.6.4",
|
|
67
|
-
"@markless/bundler": "0.
|
|
68
|
-
"@markless/web": "0.
|
|
67
|
+
"@markless/bundler": "0.6.0",
|
|
68
|
+
"@markless/web": "0.6.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
|
-
"@markless/analyzer": "0.
|
|
71
|
+
"@markless/analyzer": "0.6.0"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
74
|
"typescript": "^5.9.3",
|