@markless/bundler 0.4.0 → 0.5.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/vite.js CHANGED
@@ -1,21 +1,48 @@
1
- import { MARKLESS_DEV_ERROR_CLEAR_EVENT, MARKLESS_DEV_ERROR_CLIENT_ID, MARKLESS_DEV_ERROR_EVENT, normalizeMarklessDevError, renderMarklessDevErrorDocument } from "./dev-error.js";
2
- import { _ as executionLogActivationInjection } from "./source-module-DI20i0ZG.js";
3
- import { c as createPreloadGraphAdder, l as preflightTsrxModuleDiagnostics, p as outputDefaults, t as createMarklessRolldownPlugin } from "./rolldown-CB2Xpf-E.js";
1
+ import { c as renderMarklessDevErrorDocument, n as MARKLESS_DEV_ERROR_CLIENT_ID, r as MARKLESS_DEV_ERROR_EVENT, s as normalizeMarklessDevError, t as MARKLESS_DEV_ERROR_CLEAR_EVENT } from "./dev-error-DRvO28Fd.js";
2
+ import { Et as executionLogActivationInjection, I as sharedReachedRenderDataRequest, at as STORAGE_FREE_RESUME_ENTRY_SPECIFIER, it as RESUME_ENTRY_SPECIFIER, j as pathname, nt as outputDefaults, t as MARKLESS_DEFERRED_PACK } from "./route-pack-groups-BpefyjrE.js";
3
+ import { n as includeOptimizedDeps, t as excludeSourceShippedDeps } from "./optimized-deps-BfzxSm6C.js";
4
+ import { A as inlineDeferSource, E as preflightTsrxModuleDiagnostics, O as INLINE_DEFER_LOADER_SOURCE, T as prefetchChunkParses, _ as createPreloadGraphAdder, a as collapseInitFacadeImports, d as nativePackingEnabled, f as nativePackingPlugins, h as withUndemandedReExportDoors, k as createInlineDeferTriggerSource, l as marklessRuntimeSpecifierId, m as undemandedRuntimeModules, o as unwrapAsyncImportWrappers, p as isReExportDoor, t as createMarklessRolldownPlugin, u as DEPRECATED_NATIVE_PACKING_WARNING, v as runtimeModuleIdFromOrigin } from "./rolldown-BciZw5hZ.js";
5
+ import { n as marklessRosterPositions, r as marklessRosterRenderContext, t as marklessRosterPositionSeeds } from "./shared-seed-slot-ihIVCD2S.js";
4
6
  import { joinURL, parsePath, withQuery } from "ufo";
5
- import { ASYNC_PROTOCOL_VERSION, STORAGE_SLOT_SYMBOL_KEY, serializeRuntimeAsyncSnapshots, serializeRuntimeStateCells, storageAttributeName } from "@markless/serializer";
6
- import { join, resolve } from "pathe";
7
+ import { ASYNC_PROTOCOL_VERSION, STORAGE_SLOT_SYMBOL_KEY, escapeScriptJson, serializeRuntimeAsyncSnapshots, serializeRuntimeStateCells, storageAttributeName, storageCookieName, storageSlotEntryKeyFromGraphNodeId } from "@markless/serializer";
8
+ import { isAbsolute, join, resolve } from "pathe";
9
+ import { DEBUGGING_PLAYBOOK_HINT } from "@markless/compiler";
10
+ import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
7
11
  import { isAbsolute as isAbsolute$1 } from "node:path";
8
12
  import { pathToFileURL } from "node:url";
9
- import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
13
+ import { createServerModuleRunner, isRunnableDevEnvironment } from "vite";
10
14
  import { tmpdir } from "node:os";
11
- import { PROTOCOL_EVENT_ACTION_KIND as PROTOCOL_EVENT_ACTION_KIND$1, protocolEventDispatchesMarkless } from "@markless/serializer/protocol";
15
+ import { PROTOCOL_EVENT_ACTION_KIND as PROTOCOL_EVENT_ACTION_KIND$1, PROTOCOL_IDLE_EVENT_NAME as PROTOCOL_IDLE_EVENT_NAME$1, PROTOCOL_LOCATOR_PATHS_ATTRIBUTE, PROTOCOL_VISIBLE_EVENT_NAME, protocolEventDispatchesMarkless } from "@markless/serializer/protocol";
12
16
  import "@markless/serializer/resume-record-delta";
13
- import { deserializeGraphValueForClient } from "@markless/serializer/decode-client";
14
- import { createServerModuleRunner, isRunnableDevEnvironment } from "vite";
17
+ //#region ../web/src/inline/served-census.ts
18
+ /**
19
+ * Pins the container's elements in DOM order as its census and returns them.
20
+ * When the count differs from the one the server measured, a script outside
21
+ * Markless changed the page first: the root is flagged for the resume module
22
+ * to renumber the census, and no elements are returned, so nothing is matched
23
+ * by a shifted index.
24
+ */
25
+ function marklessServedCensus(root, attribute) {
26
+ const live = [root];
27
+ const walker = document.createTreeWalker(root, 1);
28
+ for (let next = walker.nextNode(); next; next = walker.nextNode()) live.push(next);
29
+ root.__marklessCensus ||= live;
30
+ const value = root.getAttribute?.(attribute);
31
+ return value && parseInt(value) !== live.length ? (root.__marklessShifted = 1, []) : live;
32
+ }
33
+ //#endregion
15
34
  //#region ../web/src/inline/resumer.ts
16
35
  PROTOCOL_EVENT_ACTION_KIND$1.event, PROTOCOL_EVENT_ACTION_KIND$1.externalDelegate;
36
+ const INLINE_MODULE_LOADER_SOURCE = INLINE_DEFER_LOADER_SOURCE;
17
37
  function createInlineResumerSelfWakeSource(resumeModuleUrl) {
18
- return `;(${runInlineResumerSelfWake.toString()})(${JSON.stringify(resumeModuleUrl)});`;
38
+ return `;(${runInlineResumerSelfWake.toString()})(${JSON.stringify(resumeModuleUrl)},${INLINE_MODULE_LOADER_SOURCE},${inlineDeferSource()});`;
39
+ }
40
+ function createInlineResumerStorageWakeSource(resumeModuleUrl, slotSymbolKey, renderedJson) {
41
+ return `;(${runInlineResumerStorageWake.toString()})(${JSON.stringify(slotSymbolKey)},${renderedJson},()=>(${runInlineResumerSelfWake.toString()})(${JSON.stringify(resumeModuleUrl)},${INLINE_MODULE_LOADER_SOURCE},${inlineDeferSource()}));`;
42
+ }
43
+ function runInlineResumerStorageWake(slotSymbolKey, rendered, wake) {
44
+ const slot = globalThis[Symbol.for(slotSymbolKey)];
45
+ if (slot && rendered.some(([key, value]) => Object.hasOwn(slot, key) && slot[key] !== value)) wake();
19
46
  }
20
47
  /**
21
48
  * The Escape primer, appended only to a page whose served HTML carries an
@@ -27,14 +54,14 @@ function createInlineResumerSelfWakeSource(resumeModuleUrl) {
27
54
  * with no mark ships a byte-identical resumer.
28
55
  */
29
56
  function createInlineResumerOverlayPrimerSource(resumeModuleUrl) {
30
- return `;(${runInlineResumerOverlayPrimer.toString()})(${JSON.stringify(resumeModuleUrl)},(url) => import(/* @vite-ignore */ url));`;
57
+ return `;(${runInlineResumerOverlayPrimer.toString()})(${JSON.stringify(resumeModuleUrl)},${INLINE_MODULE_LOADER_SOURCE});`;
31
58
  }
32
59
  const PRERENDER_INLINE_EVENT_NAMES_TOKEN = "__MARKLESS_PRERENDER_EVENT_NAMES__";
33
60
  function renderPrerenderInlineResumerSource(compiled, eventNames) {
34
61
  return compiled.replace(PRERENDER_INLINE_EVENT_NAMES_TOKEN, JSON.stringify(eventNames));
35
62
  }
36
63
  function createPrerenderInlineResumerSource(eventNames, resumeModuleUrl, options) {
37
- const plain = `(${runPrerenderInlineResumer.toString()})(${JSON.stringify(eventNames)},${JSON.stringify(resumeModuleUrl)},u=>import(u));`;
64
+ const plain = `(${runPrerenderInlineResumer.toString()})(${JSON.stringify(eventNames)},${JSON.stringify(resumeModuleUrl)},u=>import(u),${marklessServedCensus.toString()},${JSON.stringify(PROTOCOL_LOCATOR_PATHS_ATTRIBUTE)});`;
38
65
  const logging = options?.executionLog !== void 0 && options.executionLog !== "never";
39
66
  if (!options?.debug && !logging) return plain;
40
67
  return `{
@@ -121,73 +148,60 @@ function runPrerenderInlineResumerDebugSetup(eventNames) {
121
148
  controls?.activate();
122
149
  } catch {}
123
150
  }
124
- function runPrerenderInlineResumer(eventNames, fallbackResumeModuleUrl, loadModule) {
151
+ function runPrerenderInlineResumer(eventNames, fallbackResumeModuleUrl, loadModule, census, pathsAttribute) {
125
152
  const currentScript = document.currentScript;
126
153
  const root = currentScript?.closest("[data-async-container]");
127
154
  const resumeModuleUrl = currentScript?.getAttribute?.("data-markless-resume-module") ?? fallbackResumeModuleUrl;
128
155
  if (!root || !resumeModuleUrl) return;
129
156
  let loaded;
130
- for (const eventName of eventNames) root.addEventListener(eventName, (event) => {
157
+ const dispatch = (event) => {
131
158
  root.__marklessDelegatedDispatch = true;
159
+ if (!root.__marklessCensus) census(root, pathsAttribute);
132
160
  return (loaded ||= loadModule(resumeModuleUrl)).then((module) => module.resumeContainerEvent({
133
161
  root,
134
162
  event,
135
163
  element: event.target,
136
164
  eventRecord: null
137
165
  }));
138
- }, true);
166
+ };
167
+ eventNames.map(root.__marklessListen = (eventName) => root.addEventListener(eventName, dispatch, true));
139
168
  }
140
- function runInlineResumerSelfWake(fallbackResumeModuleUrl) {
169
+ function runInlineResumerSelfWake(fallbackResumeModuleUrl, loadModule, defer) {
141
170
  const currentScript = document.currentScript;
142
171
  const root = currentScript?.closest("[data-async-container]");
143
172
  const resumeModuleUrl = currentScript?.getAttribute?.("data-markless-resume-module") ?? fallbackResumeModuleUrl;
144
173
  if (!root || !resumeModuleUrl) return;
145
- const wake = () => requestAnimationFrame(() => {
146
- queueMicrotask(async () => {
147
- if (!root.__asyncResumeRuntimeStarted) {
148
- root.__marklessDelegatedDispatch = true;
149
- await (await import(
150
- /* @vite-ignore */
151
- resumeModuleUrl
152
- )).resumeContainerEvent({
153
- root,
154
- event: 0
155
- });
156
- }
174
+ defer.idle(root, async () => {
175
+ if (root.__asyncResumeRuntimeStarted) return;
176
+ root.__marklessDelegatedDispatch = true;
177
+ await (await loadModule(resumeModuleUrl)).resumeContainerEvent({
178
+ root,
179
+ event: 0
157
180
  });
158
181
  });
159
- if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", wake, { once: true });
160
- else wake();
161
182
  }
162
- /**
163
- * One window-level listen, from first paint, on a page that elevates something.
164
- *
165
- * Two facts make it necessary. A page served with an open overlay is on the
166
- * stack the moment the behaviour installs, but nothing installs until the
167
- * runtime wakes; and Escape is the one gesture with no route into the page -
168
- * every other one reaches an authored handler through the container's own
169
- * listener, while a dismissal is reported by a document listener that does not
170
- * exist yet. So the first Escape on such a page would be spent waking and
171
- * dismiss nothing. This listens above the container, leaves the reason where the
172
- * behaviour's installer takes it, and lets the wake finish the job.
173
- *
174
- * Deliberately one-shot, and deliberately not the waker of first resort. The
175
- * container's own capture listener runs after this one and wakes the runtime for
176
- * any event the page has a record for; waking here as well would start a second
177
- * runtime for one gesture. Deciding a task later is what tells the two apart.
178
- */
179
183
  function runInlineResumerOverlayPrimer(fallbackResumeModuleUrl, loadModule) {
180
184
  const currentScript = document.currentScript;
181
185
  const root = currentScript?.closest("[data-async-container]");
182
186
  const resumeModuleUrl = currentScript?.getAttribute?.("data-markless-resume-module") ?? fallbackResumeModuleUrl;
183
187
  if (!root || !resumeModuleUrl) return;
184
188
  const prime = (event) => {
185
- removeEventListener("keydown", prime, true);
186
- removeEventListener("pointerdown", prime, true);
187
- if (root.__marklessDelegatedDispatch) return;
188
- if (event.key === "Escape") globalThis.__marklessOverlayPrimedDismissal = "escape";
189
+ if (root.__marklessOverlayInstalled) {
190
+ removeEventListener("keydown", prime, true);
191
+ removeEventListener("pointerdown", prime, true);
192
+ return;
193
+ }
194
+ if (!root.querySelector("[overlay]:not([hidden])")) return;
195
+ if (event.key === "Escape") root.__marklessOverlayPrimedDismissal = "escape";
196
+ if (root.__marklessDelegatedDispatch === true) return;
197
+ if (!root.__marklessCensus) {
198
+ const census = [root];
199
+ const all = root.getElementsByTagName?.("*") ?? [];
200
+ for (let index = 0; index < all.length; index++) census.push(all[index]);
201
+ root.__marklessCensus = census;
202
+ }
189
203
  setTimeout(() => {
190
- if (root.__marklessDelegatedDispatch) return;
204
+ if (root.__marklessDelegatedDispatch === true) return;
191
205
  root.__marklessDelegatedDispatch = true;
192
206
  loadModule(resumeModuleUrl).then((module) => module.resumeContainerEvent({
193
207
  root,
@@ -199,75 +213,6 @@ function runInlineResumerOverlayPrimer(fallbackResumeModuleUrl, loadModule) {
199
213
  addEventListener("pointerdown", prime, true);
200
214
  }
201
215
  //#endregion
202
- //#region ../web/src/repeat-runtime.ts
203
- var KeyedRepeatRuntimeError = class extends Error {
204
- code = "MARKLESS_REPEAT_KEY_DUPLICATE";
205
- severity = "error";
206
- phase = "runtime";
207
- repeatId;
208
- keyPath;
209
- collidingValue;
210
- docsUrl;
211
- constructor(diagnostic) {
212
- super(diagnostic.message);
213
- Object.defineProperty(this, "message", {
214
- value: diagnostic.message,
215
- enumerable: true,
216
- configurable: true
217
- });
218
- this.name = "KeyedRepeatRuntimeError";
219
- this.repeatId = diagnostic.repeatId;
220
- this.keyPath = diagnostic.keyPath;
221
- this.collidingValue = diagnostic.collidingValue;
222
- this.docsUrl = diagnostic.docsUrl;
223
- }
224
- };
225
- function validateKeyedRepeatGraphKeys(graph, view) {
226
- for (const repeat of view.keyedRepeats ?? []) assertUniqueRepeatKeys(repeat, readKeyedRepeatCollection(graph, repeat));
227
- }
228
- async function validateKeyedRepeatPayloadKeys(input) {
229
- const entries = await Promise.all(input.state.cells.map(async (cell) => [cell.graphNodeId, cell.value === void 0 ? void 0 : await deserializeGraphValueForClient(cell.value)]));
230
- const cells = new Map(entries);
231
- validateKeyedRepeatGraphKeys({ read(graphNodeId, path = []) {
232
- return readPath(cells.get(graphNodeId), path);
233
- } }, input.view);
234
- }
235
- function readKeyedRepeatCollection(graph, repeat) {
236
- if (!repeat.collectionGraphNodeId) return [];
237
- const value = graph.read(repeat.collectionGraphNodeId, repeat.collectionPath);
238
- if (Array.isArray(value)) return value;
239
- return Array.from(value ?? []);
240
- }
241
- function repeatItemKey(item, repeat) {
242
- return readPath(item, repeat.keyPath);
243
- }
244
- function assertUniqueRepeatKeys(repeat, items) {
245
- const seen = /* @__PURE__ */ new Map();
246
- for (const item of items) {
247
- const key = repeatItemKey(item, repeat);
248
- if (seen.has(key)) throw duplicateRepeatKeyError(repeat, key);
249
- seen.set(key, true);
250
- }
251
- }
252
- function duplicateRepeatKeyError(repeat, key) {
253
- const source = `${repeat.itemName}.${repeat.keyPath.join(".")}`;
254
- return new KeyedRepeatRuntimeError({
255
- message: `MARKLESS_REPEAT_KEY_DUPLICATE: Duplicate @for key ${JSON.stringify(key)} from ${source}.`,
256
- repeatId: repeat.id,
257
- keyPath: repeat.keyPath,
258
- collidingValue: key,
259
- docsUrl: "https://markless.dev/errors/MARKLESS_REPEAT_KEY_DUPLICATE"
260
- });
261
- }
262
- function readPath(value, path) {
263
- let cursor = value;
264
- for (const key of path) {
265
- if (cursor == null) return void 0;
266
- cursor = cursor[key];
267
- }
268
- return cursor;
269
- }
270
- //#endregion
271
216
  //#region ../web/src/prerender/records.ts
272
217
  async function prepareSsrResumeRecords(output) {
273
218
  const rawState = output.state ?? emptyStatePayload();
@@ -277,7 +222,7 @@ async function prepareSsrResumeRecords(output) {
277
222
  computed: serializeRuntimeAsyncSnapshots(rawState.computed ?? [])
278
223
  };
279
224
  const view = containerScopedView(output.view ?? emptyViewPayload());
280
- await validateKeyedRepeatPayloadKeys({
225
+ if (view.keyedRepeats?.length) await (await import("./repeat-runtime-BDnaUYXM.js")).validateKeyedRepeatPayloadKeys({
281
226
  state,
282
227
  view
283
228
  });
@@ -314,6 +259,34 @@ function emptyViewPayload() {
314
259
  };
315
260
  }
316
261
  //#endregion
262
+ //#region ../web/src/fns/roster-position.ts
263
+ /**
264
+ * The server render context with the roster channels on it. One counter per
265
+ * render, held by the closure rather than by a module, so two page renders in
266
+ * one process never share a count.
267
+ */
268
+ function marklessSsrRosterPositionContext(renderContext) {
269
+ const context = renderContext ?? {};
270
+ if (typeof context.rosterPosition === "function") return renderContext;
271
+ const sharedSeeds = marklessRosterPositionSeeds(context.sharedSeeds);
272
+ return {
273
+ ...context,
274
+ sharedSeeds,
275
+ ...marklessRosterRenderContext(marklessRosterPositions(sharedSeeds), void 0)
276
+ };
277
+ }
278
+ /**
279
+ * The counts this render minted, answered from the page it produced. A count is
280
+ * asked before the members it counts have rendered, so this is where it becomes
281
+ * a number — after composition, off the served view's own roster.
282
+ */
283
+ async function marklessSsrRosterCounted(renderContext, surface) {
284
+ if (!marklessRosterPositions((renderContext ?? {}).sharedSeeds)?.counted) return surface;
285
+ const roster = await globalThis.__marklessRosterResume?.();
286
+ if (!roster) throw new Error("MARKLESS_ROSTER_COUNT_UNRESOLVED");
287
+ return roster.marklessResolveRosterCounts(surface);
288
+ }
289
+ //#endregion
317
290
  //#region ../web/src/prerender/evaluator.ts
318
291
  async function evaluateBuiltPageClosure(page, props) {
319
292
  const renderContext = { prerender: true };
@@ -322,7 +295,192 @@ async function evaluateBuiltPageClosure(page, props) {
322
295
  throw new TypeError("Prerender resume requires a compiled TSRX artifact.");
323
296
  }
324
297
  //#endregion
298
+ //#region ../web/src/resume-anchor-census.ts
299
+ function isArmBranchAnchorComment(comment) {
300
+ const text = comment.data ?? comment.textContent ?? "";
301
+ return text.startsWith("markless:arm-branch:") || text.startsWith("/markless:arm-branch:");
302
+ }
303
+ //#endregion
304
+ //#region ../serializer/src/protocol-locator-paths-format.ts
305
+ /**
306
+ * The value of PROTOCOL_LOCATOR_PATHS_ATTRIBUTE: the served element count in decimal, the tag
307
+ * table joined by `,`, `|`, then for every located element and each of its ancestors, in tree
308
+ * order, four numbers: how many levels to step up from the previous entry to reach its parent (the
309
+ * container is 0), its DOM-order index as a delta from the previous entry, its place among the
310
+ * parent's element children, and its tag's place in the table; then `|` and each parent's served
311
+ * element-child count, in the order entries first name that parent. Numbers are written low five
312
+ * bits first: a digit from the first 32 here ends a number, one from the last 32 carries.
313
+ */
314
+ const PROTOCOL_LOCATOR_PATHS_DIGITS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-";
315
+ //#endregion
316
+ //#region ../web/src/locator-paths.ts
317
+ const VOID_TAGS = /* @__PURE__ */ new Set([
318
+ "area",
319
+ "base",
320
+ "br",
321
+ "col",
322
+ "embed",
323
+ "hr",
324
+ "img",
325
+ "input",
326
+ "link",
327
+ "meta",
328
+ "source",
329
+ "track",
330
+ "wbr"
331
+ ]);
332
+ const RAW_TEXT_TAGS = /* @__PURE__ */ new Set([
333
+ "script",
334
+ "style",
335
+ "textarea",
336
+ "title",
337
+ "xmp",
338
+ "iframe",
339
+ "noembed",
340
+ "noframes",
341
+ "noscript"
342
+ ]);
343
+ const FOREIGN_ROOTS = /* @__PURE__ */ new Set(["svg", "math"]);
344
+ function servedElementTree(html) {
345
+ const elements = [{
346
+ tag: "",
347
+ parent: -1,
348
+ child: 0
349
+ }];
350
+ const childCounts = [0];
351
+ const commentElementIndexes = [];
352
+ const nameEnds = [0];
353
+ const stack = [];
354
+ let templateDepth = 0;
355
+ let foreignDepth = 0;
356
+ let at = 0;
357
+ let lowerHtml;
358
+ while (at < html.length) {
359
+ const open = html.indexOf("<", at);
360
+ if (open < 0) break;
361
+ if (html.startsWith("<!--", open)) {
362
+ const end = html.indexOf("-->", open + 4);
363
+ at = end < 0 ? html.length : end + 3;
364
+ const data = html.slice(open + 4, end < 0 ? html.length : end);
365
+ if (templateDepth === 0 && !isArmBranchAnchorComment({
366
+ nodeType: 8,
367
+ data
368
+ })) commentElementIndexes.push(elements.length);
369
+ continue;
370
+ }
371
+ const next = html[open + 1] ?? "";
372
+ if (next === "!" || next === "?") {
373
+ const end = html.indexOf(">", open);
374
+ at = end < 0 ? html.length : end + 1;
375
+ continue;
376
+ }
377
+ const closing = next === "/";
378
+ const nameStart = closing ? open + 2 : open + 1;
379
+ const nameMatch = /^[a-zA-Z][^\s/>]*/.exec(html.slice(nameStart, nameStart + 64));
380
+ if (!nameMatch) {
381
+ at = open + 1;
382
+ continue;
383
+ }
384
+ const name = nameMatch[0];
385
+ const lower = name.toLowerCase();
386
+ const tag = foreignDepth > 0 ? name : lower;
387
+ const tagEnd = endOfTag(html, nameStart + nameMatch[0].length);
388
+ at = tagEnd + 1;
389
+ if (closing) {
390
+ const match = stack.findLastIndex((entry) => entry.tag.toLowerCase() === lower);
391
+ if (match < 0) continue;
392
+ for (const popped of stack.splice(match)) {
393
+ if (popped.tag.toLowerCase() === "template") templateDepth--;
394
+ if (FOREIGN_ROOTS.has(popped.tag.toLowerCase())) foreignDepth--;
395
+ }
396
+ continue;
397
+ }
398
+ const selfClosing = foreignDepth > 0 && html[tagEnd - 1] === "/";
399
+ const parent = stack.length ? stack[stack.length - 1].index : 0;
400
+ let index = parent;
401
+ if (templateDepth === 0) {
402
+ index = elements.push({
403
+ tag,
404
+ parent,
405
+ child: childCounts[parent]++
406
+ }) - 1;
407
+ childCounts.push(0);
408
+ nameEnds.push(nameStart + name.length);
409
+ }
410
+ if (VOID_TAGS.has(lower) || selfClosing) continue;
411
+ if (RAW_TEXT_TAGS.has(lower)) {
412
+ const close = (lowerHtml ??= html.toLowerCase()).indexOf(`</${lower}`, at);
413
+ at = close < 0 ? html.length : endOfTag(html, close + 2 + lower.length) + 1;
414
+ continue;
415
+ }
416
+ if (lower === "template") templateDepth++;
417
+ if (FOREIGN_ROOTS.has(lower)) foreignDepth++;
418
+ stack.push({
419
+ tag,
420
+ index
421
+ });
422
+ }
423
+ return {
424
+ elements,
425
+ childCounts,
426
+ commentElementIndexes,
427
+ nameEnds
428
+ };
429
+ }
430
+ function endOfTag(html, from) {
431
+ let quote = "";
432
+ for (let at = from; at < html.length; at++) {
433
+ const char = html[at];
434
+ if (quote) {
435
+ if (char === quote) quote = "";
436
+ } else if (char === "\"" || char === "'") quote = char;
437
+ else if (char === ">") return at;
438
+ }
439
+ return html.length - 1;
440
+ }
441
+ /**
442
+ * The attribute value for a container whose inner html is `containerHtml`, or
443
+ * undefined when the html holds fewer elements than the locators name.
444
+ * One entry per located element and each of its ancestors, so every entry is
445
+ * one step from its parent; the format is documented on PROTOCOL_LOCATOR_PATHS_DIGITS.
446
+ */
447
+ function servedLocatorPaths(containerHtml, locators) {
448
+ if (locators.length === 0) return void 0;
449
+ const { elements, childCounts } = servedElementTree(containerHtml);
450
+ const chain = /* @__PURE__ */ new Set();
451
+ for (const { index } of locators) {
452
+ if (index >= elements.length) return void 0;
453
+ for (let at = index; at > 0 && !chain.has(at); at = elements[at].parent) chain.add(at);
454
+ }
455
+ if (chain.size === 0) return void 0;
456
+ const tags = [];
457
+ const parents = [];
458
+ const stack = [0];
459
+ let entries = "";
460
+ let previous = 0;
461
+ for (const index of [...chain].sort((left, right) => left - right)) {
462
+ const { tag, parent, child } = elements[index];
463
+ let up = 0;
464
+ while (stack[stack.length - 1] !== parent) {
465
+ stack.pop();
466
+ up++;
467
+ }
468
+ if (!tags.includes(tag)) tags.push(tag);
469
+ if (!parents.includes(parent)) parents.push(parent);
470
+ entries += pathNumber(up) + pathNumber(index - previous) + pathNumber(child) + pathNumber(tags.indexOf(tag));
471
+ stack.push(index);
472
+ previous = index;
473
+ }
474
+ return `${elements.length}${tags.join(",")}|${entries}|${parents.map((parent) => pathNumber(childCounts[parent])).join("")}`;
475
+ }
476
+ function pathNumber(value) {
477
+ let digits = "";
478
+ for (; value >= 32; value = Math.floor(value / 32)) digits += PROTOCOL_LOCATOR_PATHS_DIGITS[32 + value % 32];
479
+ return digits + PROTOCOL_LOCATOR_PATHS_DIGITS[value];
480
+ }
481
+ //#endregion
325
482
  //#region ../web/src/render-to-string.ts
483
+ const MARKLESS_COMPONENT_PART_BRAND = "marklessComponentPart";
326
484
  async function assemblePrerenderPageParts(component, output, options) {
327
485
  const { state, view } = await prepareSsrResumeRecords(output);
328
486
  const browserTriggers = hasBrowserTriggers(view, state);
@@ -332,27 +490,57 @@ async function assemblePrerenderPageParts(component, output, options) {
332
490
  const selfWake = hasUnsettledAsyncBoundaryRunner(view, state);
333
491
  const boot = artifactPrerenderBoot(component);
334
492
  const settle = options.armEmission && selfWake ? boot?.settle : void 0;
335
- const resumerScript = browserTriggers && resumeModuleUrl ? renderInlineResumerScript(settle ? renderPrerenderInlineResumerSource(settle.boot, eventNames) : boot ? renderPrerenderInlineResumerSource(selfWake ? boot.prerenderSelfWake : boot.prerender, eventNames) : createPrerenderInlineResumerSource(eventNames, resumeModuleUrl), options.nonce, resumeModuleUrl, selfWake && !settle, settle?.moduleUrl, !boot) : "";
493
+ const resumerScript = browserTriggers && resumeModuleUrl ? renderInlineResumerScript(settle ? renderPrerenderInlineResumerSource(settle.boot, eventNames) : boot ? renderPrerenderInlineResumerSource(selfWake ? boot.prerenderSelfWake : boot.prerender, eventNames) : createPrerenderInlineResumerSource(eventNames, resumeModuleUrl), options.nonce, resumeModuleUrl, selfWake && !settle, settle?.moduleUrl, !boot, false, deferredTriggerSource(view) + (selfWake ? "" : storageWakeSource(state, resumeModuleUrl)), artifactInlineResumerSources(component)?.defer) : "";
336
494
  return {
337
495
  head: [
338
496
  renderStorageSeedScript(artifactStorageSeeds(component), options.nonce),
339
497
  renderHeadInjections(artifactHeadInjections(component), options.nonce),
340
498
  renderModulePreloadLinks(modulePreloads, options.nonce)
341
499
  ].filter(Boolean).join(""),
342
- container: [
343
- `<div${renderContainerAttributes(options.containerId)}>`,
500
+ container: renderContainer(options.containerId, [
344
501
  output.html,
345
- options.armEmission ?? "",
346
- resumerScript,
347
- "</div>"
348
- ].filter(Boolean).join("")
502
+ options.armEmission,
503
+ resumerScript
504
+ ], resumerScript ? view.locators : [])
349
505
  };
350
506
  }
351
507
  async function renderSsrOutput(component, props, renderContext) {
352
- if (typeof component === "function") return component(props, renderContext);
353
- if (component && typeof component.renderSsr === "function") return component.renderSsr(props, renderContext);
508
+ assertPageRenderable(component);
509
+ globalThis.__marklessRosterResume ??= () => import("./roster-resume-CpphsFl_.js");
510
+ const context = marklessSsrRosterPositionContext(renderContext);
511
+ if (typeof component === "function") return marklessSsrRosterCounted(context, await marklessSsrDeferredCounted(context, await component(props, context)));
512
+ if (component && typeof component.renderSsr === "function") return marklessSsrRosterCounted(context, await marklessSsrDeferredCounted(context, await component.renderSsr(props, context)));
354
513
  throw new TypeError("renderToString(App) requires a compiled TSRX artifact.");
355
514
  }
515
+ /**
516
+ * The count-spending expressions this render handed over unevaluated. They are
517
+ * answered first: the placeholder resolver that runs after them only has plain
518
+ * count reads left to replace.
519
+ */
520
+ async function marklessSsrDeferredCounted(renderContext, surface) {
521
+ const seeds = renderContext?.sharedSeeds;
522
+ const deferred = marklessRosterPositions(seeds)?.deferred;
523
+ if (!deferred || deferred.length === 0) return surface;
524
+ const roster = await globalThis.__marklessRosterResume?.();
525
+ if (!roster) throw new Error("MARKLESS_ROSTER_COUNT_UNRESOLVED");
526
+ return roster.marklessResolveDeferredCounts(surface, deferred);
527
+ }
528
+ /**
529
+ * Refuses a bare component part used AS A PAGE. `renderSsrOutput` is the one
530
+ * place a surface becomes a served page - composition reaches a part through
531
+ * `marklessSsrComponentPart` and never comes here - so the refusal costs
532
+ * composition nothing while a part-as-page can no longer be served inert.
533
+ */
534
+ function assertPageRenderable(component) {
535
+ const partName = componentPartName(component);
536
+ if (partName === void 0) return;
537
+ throw new Error(`MARKLESS_COMPONENT_PART_AS_PAGE: "${partName}" is published as a bare render part, not a page. A non-root export carries none of its module's page wiring (no resume module, no preloads, no head injections), so a page rendered from it is served complete and inert: no client runtime is ever fetched and no gesture can dispatch. Render "${partName}" inside a page, or make it the module's root export - the root is published merged with the module surface.`);
538
+ }
539
+ function componentPartName(component) {
540
+ if (typeof component !== "object" || component === null) return void 0;
541
+ const name = component[MARKLESS_COMPONENT_PART_BRAND];
542
+ return typeof name === "string" ? name : void 0;
543
+ }
356
544
  function artifactResumeModuleUrl(component) {
357
545
  return typeof component === "object" ? component.resumeModuleUrl : void 0;
358
546
  }
@@ -371,18 +559,37 @@ function artifactHeadInjections(component) {
371
559
  function artifactStorageSeeds(component) {
372
560
  return typeof component === "object" ? component.storageSeeds : void 0;
373
561
  }
562
+ function artifactInlineResumerSources(component) {
563
+ return typeof component === "object" ? component.inlineResumerSources : void 0;
564
+ }
374
565
  function renderHeadInjections(injections, nonce) {
375
566
  if (!injections?.length) return "";
376
567
  return injections.filter((injection) => injection.location === "head").map((injection) => renderHeadInjection(injection, nonce)).join("");
377
568
  }
378
569
  function renderStorageSeedScript(seeds, nonce) {
379
570
  if (!seeds?.length) return "";
380
- return `<script${nonce ? ` nonce="${escapeAttribute(nonce)}"` : ""}>${escapeInlineScript(`(()=>{const s=globalThis[Symbol.for(${JSON.stringify(STORAGE_SLOT_SYMBOL_KEY)})]||={};for(const[k,d,a,f]of ${JSON.stringify(seeds.map((seed) => [
571
+ return `<script${nonce ? ` nonce="${escapeAttribute(nonce)}"` : ""}>${escapeInlineScript(`(()=>{const s=globalThis[Symbol.for(${JSON.stringify(STORAGE_SLOT_SYMBOL_KEY)})]||={},c=document.cookie.split('; ');for(const[k,d,a,f,n]of ${escapeScriptJson(JSON.stringify(seeds.map((seed) => [
381
572
  seed.slotKey,
382
573
  seed.driverKey,
383
574
  storageAttributeName(seed.driverKey),
384
- seed.fallback
385
- ]))}){let v=f;try{v=localStorage.getItem(d)??f}catch{}s[k]=v;document.documentElement.setAttribute(a,v)}})()`)}<\/script>`;
575
+ seed.fallback,
576
+ storageCookieName(seed.driverKey)
577
+ ])))}){let v=f;try{const e=c.find(e=>e.startsWith(n+'='));v=e?decodeURIComponent(e.slice(n.length+1)):localStorage.getItem(d)??f}catch{}s[k]=v;document.documentElement.setAttribute(a,v)}})()`)}<\/script>`;
578
+ }
579
+ function storageWakeSource(state, resumeModuleUrl) {
580
+ const rendered = (state.storage ?? []).flatMap((record) => {
581
+ const value = renderedCellValue(state.cells.find((cell) => cell.graphNodeId === record.graphNodeId));
582
+ return value === void 0 ? [] : [[storageSlotEntryKeyFromGraphNodeId(record.graphNodeId), value]];
583
+ });
584
+ if (rendered.length === 0) return "";
585
+ return createInlineResumerStorageWakeSource(resumeModuleUrl, STORAGE_SLOT_SYMBOL_KEY, escapeScriptJson(JSON.stringify(rendered)));
586
+ }
587
+ function renderedCellValue(cell) {
588
+ if (typeof cell?.directValue === "string") return cell.directValue;
589
+ const value = cell?.value;
590
+ if (typeof value === "string") return value;
591
+ const root = value?.root;
592
+ return typeof root === "string" ? root : void 0;
386
593
  }
387
594
  function renderHeadInjection(injection, nonce) {
388
595
  const attributes = { ...injection.attributes };
@@ -411,7 +618,7 @@ function renderModulePreloadLinks(preloads, nonce) {
411
618
  return links.join("");
412
619
  }
413
620
  function hasBrowserTriggers(view, state) {
414
- return (state.storage?.length ?? 0) > 0 || view.events.some(protocolEventDispatchesMarkless) || state.computed.some((computed) => computed.async === false && typeof computed.deriveSymbolId === "string") || view.behaviors.some((behavior) => !!behavior.symbolId) || Object.keys(view.asyncRunners ?? {}).length > 0 || view.asyncBoundaries.some((boundary) => boundary.asyncReads.some((read) => !!read.runnerSymbolId)) || (view.keyedRepeats ?? []).some((repeat) => repeat.rowEvents.length > 0) || (view.branches ?? []).some((branch) => (branch.armRecords ?? []).some((arm) => arm.events.some(protocolEventDispatchesMarkless))) || view.asyncBoundaries.some((boundary) => boundaryArmEventNames(boundary).length > 0);
621
+ return (state.storage?.length ?? 0) > 0 || view.events.some(protocolEventDispatchesMarkless) || state.computed.some((computed) => computed.async === false && typeof computed.deriveSymbolId === "string") || view.behaviors.some((behavior) => !!behavior.symbolId) || Object.keys(view.asyncRunners ?? {}).length > 0 || view.asyncBoundaries.some((boundary) => boundary.asyncReads.some((read) => !!read.runnerSymbolId)) || (view.keyedRepeats ?? []).some((repeat) => repeat.rowEvents.length > 0) || (view.branches ?? []).some((branch) => (branch.armRecords ?? []).some((arm) => arm.events.some(protocolEventDispatchesMarkless)) || branchServedArmEventNames(branch).length > 0) || view.asyncBoundaries.some((boundary) => boundaryArmEventNames(boundary).length > 0);
415
622
  }
416
623
  function hasUnsettledAsyncBoundaryRunner(view, state) {
417
624
  const runners = { ...view.asyncRunners };
@@ -437,25 +644,46 @@ function boundaryArmEventNames(boundary) {
437
644
  if (!armRecords || Array.isArray(armRecords)) return [];
438
645
  return [...(armRecords.events ?? []).filter(protocolEventDispatchesMarkless).map((event) => event.eventName), ...(armRecords.keyedRepeats ?? []).flatMap((repeat) => repeat.rowEvents.map((event) => event.eventName))];
439
646
  }
647
+ function branchServedArmEventNames(branch) {
648
+ const armRecords = branch.servedArmRecords;
649
+ if (!armRecords) return [];
650
+ return [...armRecords.events.filter(protocolEventDispatchesMarkless).map((event) => event.eventName), ...(armRecords.keyedRepeats ?? []).flatMap((repeat) => repeat.rowEvents.map((event) => event.eventName))];
651
+ }
652
+ function eventHostIndexes(view, eventName) {
653
+ const hosts = new Set(view.events.filter((event) => event.eventName === eventName).map((event) => event.hostNodeId));
654
+ return view.locators.filter((locator) => hosts.has(locator.hostNodeId)).map((locator) => locator.index);
655
+ }
656
+ function deferredTriggerSource(view) {
657
+ const visible = eventHostIndexes(view, PROTOCOL_VISIBLE_EVENT_NAME);
658
+ const idle = eventHostIndexes(view, PROTOCOL_IDLE_EVENT_NAME$1);
659
+ if (browserEventNames({
660
+ ...view,
661
+ events: []
662
+ }).includes(PROTOCOL_IDLE_EVENT_NAME$1)) idle.push(0);
663
+ return (visible.length > 0 ? createInlineDeferTriggerSource("visible", visible) : "") + (idle.length > 0 ? createInlineDeferTriggerSource("idle", idle) : "");
664
+ }
440
665
  function browserEventNames(view) {
441
- return [...new Set([
666
+ return [.../* @__PURE__ */ new Set([
442
667
  ...view.events.filter(protocolEventDispatchesMarkless).map((event) => event.eventName),
443
668
  ...(view.keyedRepeats ?? []).flatMap((repeat) => repeat.rowEvents.map((event) => event.eventName)),
444
- ...(view.branches ?? []).flatMap((branch) => (branch.armRecords ?? []).flatMap((arm) => arm.events.filter(protocolEventDispatchesMarkless).map((event) => event.eventName))),
669
+ ...(view.branches ?? []).flatMap((branch) => [...(branch.armRecords ?? []).flatMap((arm) => arm.events.filter(protocolEventDispatchesMarkless).map((event) => event.eventName)), ...branchServedArmEventNames(branch)]),
445
670
  ...view.asyncBoundaries.flatMap(boundaryArmEventNames)
446
- ])].filter((eventName) => eventName !== "visible");
671
+ ])].filter((eventName) => eventName !== PROTOCOL_VISIBLE_EVENT_NAME);
447
672
  }
448
- function renderContainerAttributes(containerId) {
449
- return containerId ? ` data-async-container="${escapeAttribute(containerId)}"` : " data-async-container";
673
+ function renderContainer(containerId, parts, locators) {
674
+ const inner = parts.filter(Boolean).join("");
675
+ const paths = servedLocatorPaths(inner, locators);
676
+ return `<div data-async-container${containerId ? `="${escapeAttribute(containerId)}"` : ""}${paths ? ` ${PROTOCOL_LOCATOR_PATHS_ATTRIBUTE}="${paths}"` : ""}>${inner}</div>`;
450
677
  }
451
- function renderInlineResumerScript(source, nonce, resumeModuleUrl, selfWake, settleModuleUrl, appendSelfWakeSource = true, overlayPrimer = false) {
678
+ function renderInlineResumerScript(source, nonce, resumeModuleUrl, selfWake, settleModuleUrl, appendSelfWakeSource = true, overlayPrimer = false, appendedSource = "", deferFactory) {
452
679
  const nonceAttribute = nonce ? ` nonce="${escapeAttribute(nonce)}"` : "";
453
680
  const resumeModuleAttribute = resumeModuleUrl ? ` data-markless-resume-module="${escapeAttribute(resumeModuleUrl)}"` : "";
454
681
  const settleModuleAttribute = settleModuleUrl ? ` data-markless-settle-module="${escapeAttribute(settleModuleUrl)}"` : "";
455
682
  const selfWakeAttribute = selfWake ? " data-markless-self-wake" : "";
456
683
  const selfWakeSource = selfWake && appendSelfWakeSource ? createInlineResumerSelfWakeSource(resumeModuleUrl) : "";
457
684
  const overlayPrimerSource = overlayPrimer ? createInlineResumerOverlayPrimerSource(resumeModuleUrl) : "";
458
- return `<script data-async-resumer${nonceAttribute}${resumeModuleAttribute}${settleModuleAttribute}${selfWakeAttribute}>${escapeInlineScript(source + selfWakeSource + overlayPrimerSource)}<\/script>`;
685
+ const [first, ...rest] = (source + selfWakeSource + overlayPrimerSource + appendedSource).split(inlineDeferSource());
686
+ return `<script data-async-resumer${nonceAttribute}${resumeModuleAttribute}${settleModuleAttribute}${selfWakeAttribute}>${escapeInlineScript(rest.length ? `${first}${inlineDeferSource(deferFactory)}${rest.join("globalThis.__mDefer")}` : first)}<\/script>`;
459
687
  }
460
688
  function escapeAttribute(value) {
461
689
  return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
@@ -485,7 +713,8 @@ async function emitPrerenderedPage(input) {
485
713
  const html = await readFile(htmlFile, "utf8");
486
714
  const placeholder = "<div id=\"app\"></div>";
487
715
  if (!html.includes(placeholder)) throw new Error("MARKLESS_PRERENDER_CONTAINER_MISSING: expected exact #app build placeholder");
488
- await writeFile(htmlFile, (page.head ? html.replace("</head>", `${page.head}</head>`) : html).replace(placeholder, page.container));
716
+ const withHead = page.head ? html.replace("</head>", `${page.head}</head>`) : html;
717
+ await writeFile(htmlFile, withHead.replace(placeholder, page.container));
489
718
  }
490
719
  const SENTINEL_OPEN = "";
491
720
  const SENTINEL_CLOSE = "";
@@ -969,6 +1198,101 @@ async function withBuiltPrerenderPage(input, read) {
969
1198
  }
970
1199
  }
971
1200
  //#endregion
1201
+ //#region src/build/deferred-runtime.ts
1202
+ /**
1203
+ * Deferred packs for runtime no compiled demand names: each such dynamic-import target, plus what
1204
+ * only such targets reach. Modules reached from the same targets share one pack, so each target
1205
+ * stays its own chunk. A target other code imports statically still gets a pack: that importer
1206
+ * loads it through its static edge, while no preload plan follows a dynamic edge into it.
1207
+ */
1208
+ function deferredRuntimePacks(input) {
1209
+ const packs = /* @__PURE__ */ new Map();
1210
+ if (input.undemanded.size === 0) return packs;
1211
+ const undemanded = withUndemandedReExportDoors(input.modules, input.undemanded);
1212
+ const reach = (roots, skipUndemanded) => {
1213
+ const reached = /* @__PURE__ */ new Set();
1214
+ const pending = [...roots];
1215
+ while (pending.length) {
1216
+ const id = pending.pop();
1217
+ if (reached.has(id)) continue;
1218
+ reached.add(id);
1219
+ const module = input.modules.get(id);
1220
+ if (!module) continue;
1221
+ pending.push(...module.dependencies);
1222
+ for (const target of module.dynamicDependencies) if (!skipUndemanded || !undemanded.has(target)) pending.push(target);
1223
+ }
1224
+ return reached;
1225
+ };
1226
+ const lazy = reach(undemanded, false);
1227
+ const kept = reach([...input.modules.keys()].filter((id) => !lazy.has(id)), true);
1228
+ const dynamicTargets = /* @__PURE__ */ new Set();
1229
+ const behindUndemanded = /* @__PURE__ */ new Set();
1230
+ for (const [id, module] of input.modules) {
1231
+ for (const target of module.dynamicDependencies) dynamicTargets.add(target);
1232
+ if (undemanded.has(id)) for (const dependency of module.dependencies) behindUndemanded.add(dependency);
1233
+ }
1234
+ const reachedBy = /* @__PURE__ */ new Map();
1235
+ for (const target of [...undemanded].sort()) {
1236
+ if (behindUndemanded.has(target) && !dynamicTargets.has(target)) continue;
1237
+ const label = runtimeModuleIdFromOrigin(target.split("?")[0]) ?? "runtime";
1238
+ for (const id of reach([target], false)) {
1239
+ if (!input.modules.has(id) || kept.has(id) && !undemanded.has(id)) continue;
1240
+ const labels = reachedBy.get(id) ?? [];
1241
+ if (!labels.includes(label)) labels.push(label);
1242
+ reachedBy.set(id, labels);
1243
+ }
1244
+ }
1245
+ for (const [id, labels] of reachedBy) packs.set(id, `${MARKLESS_DEFERRED_PACK}-${labels.join("+").replace(/[^\w+-]/g, "-")}`);
1246
+ return packs;
1247
+ }
1248
+ function deferredRuntimePlugin(demandMaps) {
1249
+ let packs = /* @__PURE__ */ new Map();
1250
+ return {
1251
+ name: "markless:deferred-runtime",
1252
+ options(input) {
1253
+ return input.preserveEntrySignatures === false ? null : {
1254
+ ...input,
1255
+ preserveEntrySignatures: "allow-extension"
1256
+ };
1257
+ },
1258
+ buildEnd(error) {
1259
+ packs = /* @__PURE__ */ new Map();
1260
+ if (error) return;
1261
+ const modules = /* @__PURE__ */ new Map();
1262
+ for (const id of this.getModuleIds()) {
1263
+ const info = this.getModuleInfo(id);
1264
+ if (!info || "isExternal" in info && info.isExternal) continue;
1265
+ modules.set(id, {
1266
+ dependencies: info.importedIds,
1267
+ dynamicDependencies: info.dynamicallyImportedIds,
1268
+ reExportsOnly: isReExportDoor(info)
1269
+ });
1270
+ }
1271
+ packs = deferredRuntimePacks({
1272
+ modules,
1273
+ undemanded: undemandedRuntimeModules({
1274
+ demandMaps: demandMaps(),
1275
+ moduleIds: modules.keys()
1276
+ })
1277
+ });
1278
+ },
1279
+ outputOptions(output) {
1280
+ if (typeof output.codeSplitting !== "object") return null;
1281
+ return {
1282
+ ...output,
1283
+ codeSplitting: {
1284
+ ...output.codeSplitting,
1285
+ groups: [{
1286
+ name: (id) => packs.get(id) ?? null,
1287
+ priority: 1e3,
1288
+ includeDependenciesRecursively: false
1289
+ }, ...output.codeSplitting.groups ?? []]
1290
+ }
1291
+ };
1292
+ }
1293
+ };
1294
+ }
1295
+ //#endregion
972
1296
  //#region src/vite/dev-tags.ts
973
1297
  function createDevTags() {
974
1298
  const tags = [];
@@ -1080,7 +1404,7 @@ if (window.__MARKLESS_DEV_ERROR__) show(window.__MARKLESS_DEV_ERROR__);
1080
1404
  }
1081
1405
  //#endregion
1082
1406
  //#region src/vite/environment.ts
1083
- const UNMANAGED_VITE_ENVIRONMENTS = new Set(["nitro"]);
1407
+ const UNMANAGED_VITE_ENVIRONMENTS = /* @__PURE__ */ new Set(["nitro"]);
1084
1408
  function viteEnvironmentName(environment, options = {}) {
1085
1409
  if (environment === "client") return options.clientEnvironment ?? "client";
1086
1410
  if (environment === "server") return options.serverEnvironment ?? "ssr";
@@ -1106,6 +1430,19 @@ function isUnmanagedViteEnvironment(environment) {
1106
1430
  function transformMarklessRequest(server, url, environment, options) {
1107
1431
  return server.environments[viteEnvironmentName(environment, options)]?.transformRequest(url);
1108
1432
  }
1433
+ const serverModuleRunners = /* @__PURE__ */ new WeakMap();
1434
+ function serverModuleRunner(server, environmentName) {
1435
+ const environment = server.environments[environmentName];
1436
+ if (!environment || !isRunnableDevEnvironment(environment)) throw new Error(`MARKLESS_DEV_MODULE_RUNNER_UNAVAILABLE: ${environmentName}`);
1437
+ const byName = serverModuleRunners.get(server) ?? /* @__PURE__ */ new Map();
1438
+ serverModuleRunners.set(server, byName);
1439
+ const existing = byName.get(environmentName);
1440
+ if (existing) return existing;
1441
+ const runner = createServerModuleRunner(environment);
1442
+ byName.set(environmentName, runner);
1443
+ server.httpServer?.once("close", () => void runner.close());
1444
+ return runner;
1445
+ }
1109
1446
  function hasInProcessModuleRunner(environment) {
1110
1447
  return !!environment && isRunnableDevEnvironment(environment);
1111
1448
  }
@@ -1320,11 +1657,13 @@ function createViteHmr(options) {
1320
1657
  reloadModuleRunner();
1321
1658
  return [];
1322
1659
  }
1323
- const files = changedFiles(ctx.modules ?? []);
1660
+ const modules = new Set(ctx.modules ?? []);
1661
+ if (ctx.file) for (const target of targets.keys()) for (const module of target.moduleGraph?.getModulesByFile?.(ctx.file) ?? []) modules.add(module);
1662
+ const files = changedFiles([...modules]);
1324
1663
  const root = server?.config?.root;
1325
1664
  if (ctx.file && SOURCE_FILE_EXTENSION.test(ctx.file)) {
1326
1665
  const prefix = root && `${root}/`;
1327
- files.add(prefix && ctx.file.startsWith(prefix) ? `/${ctx.file.slice(prefix.length)}` : ctx.file);
1666
+ files.set(parsePath(ctx.file).pathname, prefix && ctx.file.startsWith(prefix) ? `/${ctx.file.slice(prefix.length)}` : ctx.file);
1328
1667
  }
1329
1668
  if (!files.size) return;
1330
1669
  let sendMessages = true;
@@ -1360,8 +1699,8 @@ function createViteHmr(options) {
1360
1699
  const invalidationEnvironments = [...targets.keys()];
1361
1700
  const invalidationScopes = generatedModuleScopes(targets);
1362
1701
  const invalidatedGeneratedIds = /* @__PURE__ */ new Set();
1363
- for (const file of files) {
1364
- const candidates = editedSource !== void 0 && ctx.file ? [ctx.file] : hmrCandidates(file, ctx.file);
1702
+ for (const [sourceId] of files) {
1703
+ const candidates = editedSource !== void 0 && ctx.file ? [ctx.file] : hmrCandidates(sourceId, ctx.file && SOURCE_FILE_EXTENSION.test(ctx.file) ? ctx.file : void 0);
1365
1704
  for (const candidate of candidates) for (const scope of invalidationScopes) {
1366
1705
  const invalidatedIds = await options.invalidateGeneratedModules?.(candidate, scope, candidate === ctx.file ? editedSource : void 0);
1367
1706
  for (const id of invalidatedIds ?? []) {
@@ -1431,7 +1770,7 @@ function clientHot(server, options, environment) {
1431
1770
  return environment.hot;
1432
1771
  }
1433
1772
  function invalidationTargets(server, options, environment, env) {
1434
- const targets = new Map([[environment, env]]);
1773
+ const targets = /* @__PURE__ */ new Map([[environment, env]]);
1435
1774
  const clientEnvironment = server?.environments?.[options.clientEnvironment];
1436
1775
  if (clientEnvironment) targets.set(clientEnvironment, "client");
1437
1776
  for (const [name, candidate] of Object.entries(server?.environments ?? {})) {
@@ -1454,10 +1793,10 @@ function moduleRunnerHots(targets, clientChannel) {
1454
1793
  return [...hots];
1455
1794
  }
1456
1795
  function changedFiles(modules) {
1457
- const files = /* @__PURE__ */ new Set();
1796
+ const files = /* @__PURE__ */ new Map();
1458
1797
  for (const module of modules) for (const item of [module, ...module.importers ?? []]) {
1459
1798
  const url = sourceUrl(item);
1460
- if (url) files.add(url);
1799
+ if (url) files.set(parsePath(item.id ?? item.file ?? url).pathname, url);
1461
1800
  }
1462
1801
  return files;
1463
1802
  }
@@ -1467,12 +1806,12 @@ function sourceUrl(module) {
1467
1806
  return null;
1468
1807
  }
1469
1808
  function hmrCandidates(file, absoluteFile) {
1470
- const candidates = new Set([file]);
1809
+ const candidates = /* @__PURE__ */ new Set([file]);
1471
1810
  if (absoluteFile) candidates.add(absoluteFile);
1472
1811
  return candidates;
1473
1812
  }
1474
1813
  function firstChangedFile(files) {
1475
- for (const file of files) return file;
1814
+ for (const file of files.values()) return file;
1476
1815
  }
1477
1816
  //#endregion
1478
1817
  //#region src/vite/dev-prerender.ts
@@ -1533,7 +1872,8 @@ function createDevPrerender(input) {
1533
1872
  } catch (error) {
1534
1873
  const environment = server?.environments[input.serverEnvironment];
1535
1874
  input.reportError(environment, error);
1536
- return injectDevClients(renderMarklessDevErrorDocument(normalizeMarklessDevError(error, { id: input.entry }), { base: input.base }), input.base);
1875
+ const payload = normalizeMarklessDevError(error, { id: input.entry });
1876
+ return injectDevClients(renderMarklessDevErrorDocument(payload, { base: input.base }), input.base);
1537
1877
  }
1538
1878
  },
1539
1879
  configureServer(nextServer) {
@@ -1544,6 +1884,49 @@ function createDevPrerender(input) {
1544
1884
  };
1545
1885
  }
1546
1886
  //#endregion
1887
+ //#region src/vite/dev-server-externals.ts
1888
+ function withDevServerExternals(context) {
1889
+ const config = context.environment?.config;
1890
+ if (config?.consumer !== "server") return context;
1891
+ const noExternal = config.resolve?.noExternal;
1892
+ const resolve = async (source, importer, options) => {
1893
+ const resolved = await context.resolve(source, importer, options);
1894
+ if (!isBareSpecifier(source) || matchesNoExternal(noExternal, source)) return resolved;
1895
+ const id = typeof resolved === "string" ? resolved : resolved?.id;
1896
+ if (!id || !isBuiltDependency(pathname(String(id)))) return resolved;
1897
+ return {
1898
+ ...typeof resolved === "object" ? resolved : {},
1899
+ id: String(id),
1900
+ external: true
1901
+ };
1902
+ };
1903
+ return new Proxy(context, { get(target, property) {
1904
+ if (property === "resolve") return resolve;
1905
+ const value = Reflect.get(target, property, target);
1906
+ return typeof value === "function" ? value.bind(target) : value;
1907
+ } });
1908
+ }
1909
+ function isBareSpecifier(source) {
1910
+ return !source.startsWith(".") && !isAbsolute(source) && !source.startsWith("\0") && !source.startsWith("virtual:");
1911
+ }
1912
+ function isBuiltDependency(id) {
1913
+ return id.includes("/node_modules/") && /\.[cm]?js$/.test(id);
1914
+ }
1915
+ function matchesNoExternal(noExternal, source) {
1916
+ if (noExternal === true) return true;
1917
+ if (noExternal === void 0) return false;
1918
+ return (typeof noExternal === "string" || noExternal instanceof RegExp ? [noExternal] : noExternal).some((pattern) => typeof pattern === "string" ? source === pattern || source.startsWith(`${pattern}/`) : pattern.test(source));
1919
+ }
1920
+ //#endregion
1921
+ //#region src/vite/dev-runtime-imports.ts
1922
+ function installDevRuntimeImportResolution(server, clientEnvironment) {
1923
+ for (const [name, environment] of Object.entries(server.environments ?? {})) {
1924
+ if (name === clientEnvironment || typeof environment.fetchModule !== "function") continue;
1925
+ const fetchModule = environment.fetchModule.bind(environment);
1926
+ environment.fetchModule = (id, importer, options) => fetchModule(marklessRuntimeSpecifierId(id) ?? id, importer, options);
1927
+ }
1928
+ }
1929
+ //#endregion
1547
1930
  //#region src/vite/index.ts
1548
1931
  const MARKLESS_SKIP_DUPLICATE_BUILDS = Symbol("markless-skip-duplicate-builds");
1549
1932
  const TSRX_INPUT_FILE = /\.tsrx(?:[?#].*)?$/;
@@ -1552,7 +1935,12 @@ function markless(options = {}) {
1552
1935
  const bundleGraphAdders = /* @__PURE__ */ new Set();
1553
1936
  const transformedTsrxSources = /* @__PURE__ */ new Map();
1554
1937
  const prerenderRecordsBySource = /* @__PURE__ */ new Map();
1555
- const rolldownOptions = { ...options };
1938
+ const { experimentalNativePacking: _deprecatedPacking, ...rest } = options;
1939
+ const rolldownOptions = {
1940
+ ...rest,
1941
+ packing: nativePackingEnabled(options),
1942
+ chunkImportMap: options.experimentalNativePacking === true
1943
+ };
1556
1944
  const prerender = process.env.MARKLESS_PRERENDER === "1";
1557
1945
  const explicitPrerenderWake = process.env.MARKLESS_PRERENDER_WAKE;
1558
1946
  rolldownOptions.prerender = false;
@@ -1609,12 +1997,17 @@ function markless(options = {}) {
1609
1997
  __MARKLESS_DEV_ENABLED__: devDefine
1610
1998
  };
1611
1999
  configDefaults(config, options, rolldownOptions);
2000
+ if (devEnabled) {
2001
+ includeOptimizedDeps(config, [RESUME_ENTRY_SPECIFIER, STORAGE_FREE_RESUME_ENTRY_SPECIFIER]);
2002
+ excludeSourceShippedDeps(config);
2003
+ }
1612
2004
  if (prerender || stagePrerenderWake) {
1613
2005
  prerenderEntry = ssrTsrxInput(config, options);
1614
2006
  rolldownOptions.prerender = prerender && prerenderEntry !== null;
1615
2007
  }
1616
2008
  },
1617
2009
  configResolved(resolvedConfig) {
2010
+ if (options.experimentalNativePacking !== void 0) resolvedConfig.logger.warn(DEPRECATED_NATIVE_PACKING_WARNING);
1618
2011
  resolvedRoot = resolvedConfig.root;
1619
2012
  clientOutDir = resolvedConfig.build?.outDir ?? "dist";
1620
2013
  const serve = resolvedConfig.command === "serve";
@@ -1694,9 +2087,10 @@ function markless(options = {}) {
1694
2087
  }
1695
2088
  },
1696
2089
  configureServer(server) {
1697
- server.config.logger?.info("markless diagnostics available - window.__MARKLESS_DEBUG__ records containers, lifecycles, and event routing; markless debugging playbook: run pnpm doctor, or read agent/markless.md in the installed @markless/core package.");
2090
+ server.config.logger?.info(`markless diagnostics available - window.__MARKLESS_DEBUG__ records containers, lifecycles, and event routing; ${DEBUGGING_PLAYBOOK_HINT}.`);
1698
2091
  rolldownOptions.devServer = {
1699
2092
  transformRequest: (url, environment) => transformMarklessRequest(server, url, environment, options),
2093
+ importModule: (source) => serverModuleRunner(server, viteEnvironmentName("server", options)).import(source),
1700
2094
  invalidateModule: (id, environment) => {
1701
2095
  const target = server.environments[viteEnvironmentName(environment, options)];
1702
2096
  const module = target?.moduleGraph?.getModuleById?.(id);
@@ -1706,6 +2100,7 @@ function markless(options = {}) {
1706
2100
  }
1707
2101
  };
1708
2102
  hmr.configureServer(server);
2103
+ installDevRuntimeImportResolution(server, viteEnvironmentName("client", options));
1709
2104
  devPrerender?.configureServer(server);
1710
2105
  },
1711
2106
  transformIndexHtml(html) {
@@ -1737,7 +2132,8 @@ function markless(options = {}) {
1737
2132
  transform: { async handler(code, id, transformOptions) {
1738
2133
  if (rolldownOptions.dev === true && TSRX_INPUT_FILE.test(id)) transformedTsrxSources.set(parsePath(id).pathname, code);
1739
2134
  try {
1740
- return await runHook(basePlugin.transform, this, code, id, transformOptions);
2135
+ const context = rolldownOptions.dev === true ? withDevServerExternals(this) : this;
2136
+ return await runHook(basePlugin.transform, context, code, id, transformOptions);
1741
2137
  } catch (error) {
1742
2138
  if (rolldownOptions.dev === true && TSRX_INPUT_FILE.test(id)) {
1743
2139
  const environment = this.environment;
@@ -1751,7 +2147,52 @@ function markless(options = {}) {
1751
2147
  return hmr.hotUpdate(this.environment, ctx);
1752
2148
  }
1753
2149
  };
1754
- return [marklessPlugin];
2150
+ return [
2151
+ marklessPlugin,
2152
+ {
2153
+ name: "markless:shared-render-data-reach",
2154
+ enforce: "pre",
2155
+ resolveId: {
2156
+ filter: { id: /[?&]markless-reached-from=/ },
2157
+ async handler(source, importer) {
2158
+ const shared = sharedReachedRenderDataRequest(source);
2159
+ return shared ? await this.resolve(shared, importer, { skipSelf: true }) : null;
2160
+ }
2161
+ }
2162
+ },
2163
+ {
2164
+ name: "markless:init-facade-imports",
2165
+ apply: "build",
2166
+ enforce: "pre",
2167
+ applyToEnvironment(environment) {
2168
+ return environment.config.consumer === "client";
2169
+ },
2170
+ generateBundle: {
2171
+ order: "post",
2172
+ async handler(_options, bundle) {
2173
+ await prefetchChunkParses(Object.values(bundle).filter((output) => output.type === "chunk" && output.code.includes("import(")));
2174
+ collapseInitFacadeImports(bundle);
2175
+ unwrapAsyncImportWrappers(bundle);
2176
+ }
2177
+ }
2178
+ },
2179
+ ...nativePackingEnabled(options) ? nativePackingPlugins(() => resolvedRoot, () => basePlugin.api.runtimeDemandMaps(), () => basePlugin.api.runtimeDemandSources()).map((plugin) => ({
2180
+ ...plugin,
2181
+ apply: "build",
2182
+ enforce: "post",
2183
+ sharedDuringBuild: true,
2184
+ applyToEnvironment(environment) {
2185
+ return environment.config.consumer === "client";
2186
+ }
2187
+ })) : [{
2188
+ ...deferredRuntimePlugin(() => basePlugin.api.runtimeDemandMaps()),
2189
+ apply: "build",
2190
+ enforce: "post",
2191
+ applyToEnvironment(environment) {
2192
+ return environment.config.consumer === "client";
2193
+ }
2194
+ }]
2195
+ ];
1755
2196
  }
1756
2197
  async function buildMarklessEnvironments(builder, options) {
1757
2198
  const environments = buildEnvironments(builder, options);