@kiwa-test/nextjs 1.1.0 → 1.2.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/index.js ADDED
@@ -0,0 +1,800 @@
1
+ // src/invoke-server-action.ts
2
+ var REDIRECT_SYMBOL = /* @__PURE__ */ Symbol.for("kiwa.next.redirect");
3
+ function createCookieJar(initial) {
4
+ const store = new Map(Object.entries(initial));
5
+ return {
6
+ get(name) {
7
+ return store.get(name);
8
+ },
9
+ set(name, value) {
10
+ store.set(name, value);
11
+ },
12
+ delete(name) {
13
+ store.delete(name);
14
+ },
15
+ entries() {
16
+ return Array.from(store.entries());
17
+ }
18
+ };
19
+ }
20
+ function isRedirectSignal(value) {
21
+ return typeof value === "object" && value !== null && value[REDIRECT_SYMBOL] === true;
22
+ }
23
+ async function invokeServerAction(opts) {
24
+ const headers = /* @__PURE__ */ new Map();
25
+ for (const [name, value] of Object.entries(opts.headers ?? {})) {
26
+ headers.set(name.toLowerCase(), value);
27
+ }
28
+ const env = {
29
+ cookies: createCookieJar(opts.cookies ?? {}),
30
+ headers,
31
+ revalidated: { paths: [], tags: [] },
32
+ redirect: null
33
+ };
34
+ const callArgs = [opts.formData ?? new FormData(), ...opts.args ?? []];
35
+ let result;
36
+ let error;
37
+ try {
38
+ result = await opts.action(...callArgs);
39
+ } catch (caught) {
40
+ if (isRedirectSignal(caught)) {
41
+ env.redirect = caught;
42
+ } else {
43
+ error = caught;
44
+ }
45
+ }
46
+ return { result, error, env };
47
+ }
48
+
49
+ // src/invoke-middleware.ts
50
+ var MIDDLEWARE_ACTION_SYMBOL = /* @__PURE__ */ Symbol.for("kiwa.next.middleware.action");
51
+ function buildRequest(opts) {
52
+ const url = new URL(opts.url);
53
+ const headers = /* @__PURE__ */ new Map();
54
+ for (const [name, value] of Object.entries(opts.headers ?? {})) {
55
+ headers.set(name.toLowerCase(), value);
56
+ }
57
+ const cookies = new Map(Object.entries(opts.cookies ?? {}));
58
+ return {
59
+ url: opts.url,
60
+ method: opts.method ?? "GET",
61
+ headers,
62
+ cookies,
63
+ nextUrl: {
64
+ pathname: url.pathname,
65
+ search: url.search,
66
+ searchParams: url.searchParams
67
+ },
68
+ geo: opts.geo ?? {}
69
+ };
70
+ }
71
+ var middlewareActions = {
72
+ next() {
73
+ return { [MIDDLEWARE_ACTION_SYMBOL]: true, kind: "next" };
74
+ },
75
+ redirect(url, status = 307) {
76
+ return { [MIDDLEWARE_ACTION_SYMBOL]: true, kind: "redirect", url, status };
77
+ },
78
+ rewrite(url) {
79
+ return { [MIDDLEWARE_ACTION_SYMBOL]: true, kind: "rewrite", url };
80
+ },
81
+ json(body, status = 200) {
82
+ return { [MIDDLEWARE_ACTION_SYMBOL]: true, kind: "json", body, status };
83
+ }
84
+ };
85
+ async function invokeMiddleware(opts) {
86
+ const req = buildRequest(opts);
87
+ const responseHeaders = /* @__PURE__ */ new Map();
88
+ const responseCookies = /* @__PURE__ */ new Map();
89
+ const seam = {
90
+ setHeader(name, value) {
91
+ responseHeaders.set(name.toLowerCase(), value);
92
+ },
93
+ setCookie(name, value) {
94
+ responseCookies.set(name, value);
95
+ }
96
+ };
97
+ let action = middlewareActions.next();
98
+ let error;
99
+ try {
100
+ const result = await opts.middleware(req, seam);
101
+ action = result;
102
+ } catch (caught) {
103
+ error = caught;
104
+ action = { [MIDDLEWARE_ACTION_SYMBOL]: true, kind: "noop" };
105
+ }
106
+ return {
107
+ env: {
108
+ responseHeaders,
109
+ responseCookies,
110
+ action
111
+ },
112
+ error
113
+ };
114
+ }
115
+
116
+ // src/render-server-component.ts
117
+ var NOT_FOUND_SYMBOL = /* @__PURE__ */ Symbol.for("kiwa.next.rsc.notFound");
118
+ var FORBIDDEN_SYMBOL = /* @__PURE__ */ Symbol.for("kiwa.next.rsc.forbidden");
119
+ var RSC_REDIRECT_SYMBOL = /* @__PURE__ */ Symbol.for("kiwa.next.rsc.redirect");
120
+ function isRscElement(node) {
121
+ if (typeof node !== "object" || node === null) return false;
122
+ const candidate = node;
123
+ return typeof candidate.type !== "undefined" && typeof candidate.props === "object" && candidate.props !== null;
124
+ }
125
+ function isNotFound(value) {
126
+ return typeof value === "object" && value !== null && value[NOT_FOUND_SYMBOL] === true;
127
+ }
128
+ function isForbidden(value) {
129
+ return typeof value === "object" && value !== null && value[FORBIDDEN_SYMBOL] === true;
130
+ }
131
+ function isRscRedirect(value) {
132
+ return typeof value === "object" && value !== null && value[RSC_REDIRECT_SYMBOL] === true;
133
+ }
134
+ function findAll(tree, predicate) {
135
+ const out = [];
136
+ function visit(node) {
137
+ if (Array.isArray(node)) {
138
+ node.forEach(visit);
139
+ return;
140
+ }
141
+ if (!isRscElement(node)) return;
142
+ if (predicate(node)) out.push(node);
143
+ const children = node.props.children;
144
+ if (typeof children !== "undefined") {
145
+ visit(children);
146
+ }
147
+ }
148
+ visit(tree);
149
+ return out;
150
+ }
151
+ function textContent(tree) {
152
+ const parts = [];
153
+ function visit(node) {
154
+ if (Array.isArray(node)) {
155
+ node.forEach(visit);
156
+ return;
157
+ }
158
+ if (typeof node === "string" || typeof node === "number") {
159
+ parts.push(String(node));
160
+ return;
161
+ }
162
+ if (isRscElement(node)) {
163
+ const children = node.props.children;
164
+ if (typeof children !== "undefined") visit(children);
165
+ }
166
+ }
167
+ visit(tree);
168
+ return parts.filter((p) => p.length > 0).join(" ");
169
+ }
170
+ async function renderServerComponent(opts) {
171
+ let tree = null;
172
+ let signal = null;
173
+ let error;
174
+ const props = opts.props ?? {};
175
+ try {
176
+ const result = await opts.component(props);
177
+ tree = result;
178
+ } catch (caught) {
179
+ if (isNotFound(caught) || isForbidden(caught) || isRscRedirect(caught)) {
180
+ signal = caught;
181
+ } else {
182
+ error = caught;
183
+ }
184
+ }
185
+ return { tree, signal, error };
186
+ }
187
+
188
+ // src/invoke-parallel-routes.ts
189
+ var PARALLEL_INTERCEPTION_SYMBOL = /* @__PURE__ */ Symbol.for("kiwa.next.parallel.interception");
190
+ async function renderSlot(input) {
191
+ let tree = null;
192
+ let usedDefault = false;
193
+ let error;
194
+ const interception = input.intercepting ? {
195
+ [PARALLEL_INTERCEPTION_SYMBOL]: true,
196
+ slot: input.slot,
197
+ variant: input.intercepting.variant,
198
+ url: input.intercepting.url,
199
+ distance: input.intercepting.distance ?? "sibling"
200
+ } : null;
201
+ const useDefault = input.component === null || interception?.variant === "default";
202
+ try {
203
+ if (useDefault) {
204
+ if (typeof input.defaultFallback !== "function") {
205
+ throw new Error(`slot ${input.slot}: no default.tsx fallback supplied`);
206
+ }
207
+ tree = await input.defaultFallback();
208
+ usedDefault = true;
209
+ } else if (input.component !== null) {
210
+ tree = await input.component(input.props ?? {});
211
+ }
212
+ } catch (caught) {
213
+ error = caught;
214
+ }
215
+ return { slot: input.slot, tree, usedDefault, interception, error };
216
+ }
217
+ async function invokeParallelRoutes(opts) {
218
+ let childrenTree = null;
219
+ let childrenError;
220
+ let layoutError;
221
+ try {
222
+ childrenTree = await opts.children(opts.childrenProps ?? {});
223
+ } catch (caught) {
224
+ childrenError = caught;
225
+ }
226
+ const slotResults = await Promise.all(opts.slots.map((input) => renderSlot(input)));
227
+ const slotMap = {};
228
+ for (const result of slotResults) {
229
+ slotMap[result.slot] = result.tree;
230
+ }
231
+ let tree = null;
232
+ try {
233
+ const props = {
234
+ ...opts.layoutProps ?? {},
235
+ children: childrenTree,
236
+ slots: slotMap
237
+ };
238
+ tree = await opts.layout(props);
239
+ } catch (caught) {
240
+ layoutError = caught;
241
+ }
242
+ return { tree, slotResults, childrenError, layoutError };
243
+ }
244
+
245
+ // src/setup-next-rsc-env.ts
246
+ var RSC_ERROR_BOUNDARY_SYMBOL = /* @__PURE__ */ Symbol.for("kiwa.next.rsc.errorBoundary");
247
+ var DEFAULT_STREAMING_TIMEOUT_MS = 5e3;
248
+ function buildErrorBoundary(error) {
249
+ return { [RSC_ERROR_BOUNDARY_SYMBOL]: true, error };
250
+ }
251
+ async function runWithTimeout(promise, timeoutMs) {
252
+ let timer;
253
+ const timeout = new Promise((resolve) => {
254
+ timer = setTimeout(() => resolve({ value: null, timedOut: true }), timeoutMs);
255
+ });
256
+ try {
257
+ const value = await Promise.race([
258
+ promise.then((v) => ({ value: v, timedOut: false })),
259
+ timeout
260
+ ]);
261
+ return value;
262
+ } finally {
263
+ if (timer) clearTimeout(timer);
264
+ }
265
+ }
266
+ async function collectStream(source, fallback) {
267
+ const chunks = [];
268
+ if (typeof fallback !== "undefined" && fallback !== null) {
269
+ chunks.push(fallback);
270
+ }
271
+ try {
272
+ for await (const chunk of source) {
273
+ chunks.push(chunk);
274
+ }
275
+ } catch (err) {
276
+ return { chunks, resolved: null, thrown: err };
277
+ }
278
+ const resolved = chunks.length > 0 ? chunks[chunks.length - 1] ?? null : null;
279
+ const fallbackOnly = chunks.length === 1 && fallback !== null && Object.is(chunks[0], fallback);
280
+ return { chunks, resolved: fallbackOnly ? null : resolved, thrown: void 0 };
281
+ }
282
+ async function* singleChunkSource(component, props) {
283
+ const result = await component(props);
284
+ yield result;
285
+ }
286
+ async function setupNextRscEnv(opts = {}) {
287
+ const timeoutMs = opts.streamingTimeout ?? DEFAULT_STREAMING_TIMEOUT_MS;
288
+ const fallback = opts.suspenseFallback ?? null;
289
+ if (timeoutMs <= 0 && (opts.dataSource || opts.component)) {
290
+ return {
291
+ chunks: fallback !== null ? [fallback] : [],
292
+ fallback,
293
+ resolved: null,
294
+ errorBoundary: null,
295
+ timedOut: true
296
+ };
297
+ }
298
+ if (typeof opts.injectError !== "undefined") {
299
+ return {
300
+ chunks: fallback !== null ? [fallback] : [],
301
+ fallback,
302
+ resolved: null,
303
+ errorBoundary: buildErrorBoundary(opts.injectError),
304
+ timedOut: false
305
+ };
306
+ }
307
+ if (!opts.dataSource && !opts.component) {
308
+ return {
309
+ chunks: fallback !== null ? [fallback] : [],
310
+ fallback,
311
+ resolved: null,
312
+ errorBoundary: null,
313
+ timedOut: false
314
+ };
315
+ }
316
+ const source = opts.dataSource ? opts.dataSource : singleChunkSource(opts.component, opts.props ?? {});
317
+ const { value, timedOut } = await runWithTimeout(collectStream(source, fallback), timeoutMs);
318
+ if (timedOut || value === null) {
319
+ return {
320
+ chunks: fallback !== null ? [fallback] : [],
321
+ fallback,
322
+ resolved: null,
323
+ errorBoundary: null,
324
+ timedOut: true
325
+ };
326
+ }
327
+ const { chunks, resolved, thrown } = value;
328
+ if (typeof thrown !== "undefined") {
329
+ return {
330
+ chunks,
331
+ fallback,
332
+ resolved: null,
333
+ errorBoundary: buildErrorBoundary(thrown),
334
+ timedOut: false
335
+ };
336
+ }
337
+ return {
338
+ chunks,
339
+ fallback,
340
+ resolved,
341
+ errorBoundary: null,
342
+ timedOut: false
343
+ };
344
+ }
345
+
346
+ // src/semantics/types.ts
347
+ var dialect = {
348
+ "app-router": {
349
+ "action.form_submitted": "app.server-action.form.submit",
350
+ "action.revalidate_path": "app.cache.revalidatePath",
351
+ "action.revalidate_tag": "app.cache.revalidateTag",
352
+ "action.redirected": "app.navigation.redirect",
353
+ "ppr.static_shell_rendered": "app.ppr.static-shell",
354
+ "ppr.dynamic_hole_opened": "app.ppr.dynamic-hole",
355
+ "ppr.streaming_boundary_flushed": "app.ppr.stream-boundary",
356
+ "ppr.completed": "app.ppr.complete",
357
+ "intercept.current_segment": "app.intercept.current",
358
+ "intercept.parent_segment": "app.intercept.parent",
359
+ "intercept.root_catchall": "app.intercept.root",
360
+ "intercept.modal_opened": "app.intercept.modal",
361
+ "parallel.default_rendered": "app.parallel.default",
362
+ "parallel.loading_rendered": "app.parallel.loading",
363
+ "parallel.error_boundary_captured": "app.parallel.error",
364
+ "parallel.slot_navigated": "app.parallel.navigate"
365
+ },
366
+ "pages-router": {
367
+ "action.form_submitted": "pages.api.form.submit",
368
+ "action.revalidate_path": "pages.isr.revalidate",
369
+ "action.revalidate_tag": "pages.cache.tag.noop",
370
+ "action.redirected": "pages.router.redirect",
371
+ "ppr.static_shell_rendered": "pages.ssg.shell",
372
+ "ppr.dynamic_hole_opened": "pages.ssr.dynamic-hole",
373
+ "ppr.streaming_boundary_flushed": "pages.stream.boundary",
374
+ "ppr.completed": "pages.render.complete",
375
+ "intercept.current_segment": "pages.intercept.current",
376
+ "intercept.parent_segment": "pages.intercept.parent",
377
+ "intercept.root_catchall": "pages.intercept.root",
378
+ "intercept.modal_opened": "pages.modal.open",
379
+ "parallel.default_rendered": "pages.slot.default",
380
+ "parallel.loading_rendered": "pages.slot.loading",
381
+ "parallel.error_boundary_captured": "pages.slot.error",
382
+ "parallel.slot_navigated": "pages.slot.navigate"
383
+ },
384
+ "edge-runtime": {
385
+ "action.form_submitted": "edge.action.form.submit",
386
+ "action.revalidate_path": "edge.cache.revalidatePath",
387
+ "action.revalidate_tag": "edge.cache.revalidateTag",
388
+ "action.redirected": "edge.response.redirect",
389
+ "ppr.static_shell_rendered": "edge.ppr.static-shell",
390
+ "ppr.dynamic_hole_opened": "edge.ppr.dynamic-hole",
391
+ "ppr.streaming_boundary_flushed": "edge.stream.boundary",
392
+ "ppr.completed": "edge.ppr.complete",
393
+ "intercept.current_segment": "edge.intercept.current",
394
+ "intercept.parent_segment": "edge.intercept.parent",
395
+ "intercept.root_catchall": "edge.intercept.root",
396
+ "intercept.modal_opened": "edge.modal.open",
397
+ "parallel.default_rendered": "edge.parallel.default",
398
+ "parallel.loading_rendered": "edge.parallel.loading",
399
+ "parallel.error_boundary_captured": "edge.parallel.error",
400
+ "parallel.slot_navigated": "edge.parallel.navigate"
401
+ }
402
+ };
403
+ function providerEventName(target, neutral) {
404
+ return dialect[target][neutral] ?? neutral;
405
+ }
406
+
407
+ // src/semantics/server-action-advanced.ts
408
+ function startServerActionAdvanced(input) {
409
+ if (input.actionId.length === 0) {
410
+ throw new Error("startServerActionAdvanced: actionId must not be empty");
411
+ }
412
+ return {
413
+ target: input.target,
414
+ actionId: input.actionId,
415
+ state: "idle",
416
+ form: {},
417
+ revalidatedPaths: [],
418
+ revalidatedTags: [],
419
+ redirectUrl: null,
420
+ history: []
421
+ };
422
+ }
423
+ function submitFormAction(session, form) {
424
+ if (session.state !== "idle") {
425
+ throw new Error(`submitFormAction: session is ${session.state}, not idle`);
426
+ }
427
+ session.state = "submitted";
428
+ session.form = { ...form };
429
+ return emit(session, "action.form_submitted", {
430
+ fields: Object.keys(form).join(","),
431
+ fieldCount: Object.keys(form).length
432
+ });
433
+ }
434
+ function revalidateActionPath(session, path) {
435
+ if (session.state === "idle") {
436
+ throw new Error("revalidateActionPath: form action was not submitted");
437
+ }
438
+ if (!path.startsWith("/")) {
439
+ throw new Error("revalidateActionPath: path must start with /");
440
+ }
441
+ session.state = "path-revalidated";
442
+ session.revalidatedPaths.push(path);
443
+ return emit(session, "action.revalidate_path", { path, count: session.revalidatedPaths.length });
444
+ }
445
+ function revalidateActionTag(session, tag) {
446
+ if (session.state === "idle") {
447
+ throw new Error("revalidateActionTag: form action was not submitted");
448
+ }
449
+ if (tag.length === 0) {
450
+ throw new Error("revalidateActionTag: tag must not be empty");
451
+ }
452
+ session.state = "tag-revalidated";
453
+ session.revalidatedTags.push(tag);
454
+ return emit(session, "action.revalidate_tag", { tag, count: session.revalidatedTags.length });
455
+ }
456
+ function redirectAction(session, url) {
457
+ if (session.state === "idle") {
458
+ throw new Error("redirectAction: form action was not submitted");
459
+ }
460
+ if (url.length === 0) {
461
+ throw new Error("redirectAction: url must not be empty");
462
+ }
463
+ session.state = "redirected";
464
+ session.redirectUrl = url;
465
+ return emit(session, "action.redirected", { url });
466
+ }
467
+ function emit(session, neutralEvent, metadata) {
468
+ const step = {
469
+ neutralEvent,
470
+ providerEvent: providerEventName(session.target, neutralEvent),
471
+ state: session.state,
472
+ amountCents: 0,
473
+ metadata: { target: session.target, actionId: session.actionId, ...metadata }
474
+ };
475
+ session.history.push(step);
476
+ return step;
477
+ }
478
+
479
+ // src/semantics/partial-prerendering.ts
480
+ function startPartialPrerendering(input) {
481
+ if (input.routeId.length === 0) {
482
+ throw new Error("startPartialPrerendering: routeId must not be empty");
483
+ }
484
+ return {
485
+ target: input.target,
486
+ routeId: input.routeId,
487
+ state: "idle",
488
+ shellHtml: null,
489
+ dynamicHoles: /* @__PURE__ */ new Map(),
490
+ streamedBoundaries: [],
491
+ history: []
492
+ };
493
+ }
494
+ function renderStaticShell(session, html) {
495
+ if (session.state !== "idle") {
496
+ throw new Error(`renderStaticShell: session is ${session.state}, not idle`);
497
+ }
498
+ if (html.length === 0) {
499
+ throw new Error("renderStaticShell: html must not be empty");
500
+ }
501
+ session.state = "static-shell";
502
+ session.shellHtml = html;
503
+ return emit2(session, "ppr.static_shell_rendered", { bytes: html.length });
504
+ }
505
+ function openDynamicHole(session, input) {
506
+ if (session.shellHtml === null) {
507
+ throw new Error("openDynamicHole: static shell must be rendered first");
508
+ }
509
+ if (input.holeId.length === 0) {
510
+ throw new Error("openDynamicHole: holeId must not be empty");
511
+ }
512
+ session.state = "dynamic-hole";
513
+ session.dynamicHoles.set(input.holeId, input.fallback);
514
+ return emit2(session, "ppr.dynamic_hole_opened", {
515
+ holeId: input.holeId,
516
+ fallback: input.fallback,
517
+ holeCount: session.dynamicHoles.size
518
+ });
519
+ }
520
+ function flushStreamingBoundary(session, input) {
521
+ if (!session.dynamicHoles.has(input.holeId)) {
522
+ throw new Error(`flushStreamingBoundary: ${input.holeId} is not an open dynamic hole`);
523
+ }
524
+ if (input.html.length === 0) {
525
+ throw new Error("flushStreamingBoundary: html must not be empty");
526
+ }
527
+ session.state = "streaming";
528
+ session.streamedBoundaries.push(input.holeId);
529
+ session.dynamicHoles.set(input.holeId, input.html);
530
+ return emit2(session, "ppr.streaming_boundary_flushed", {
531
+ holeId: input.holeId,
532
+ bytes: input.html.length
533
+ });
534
+ }
535
+ function completePartialPrerendering(session) {
536
+ if (session.shellHtml === null) {
537
+ throw new Error("completePartialPrerendering: static shell was not rendered");
538
+ }
539
+ session.state = "completed";
540
+ return emit2(session, "ppr.completed", {
541
+ holeCount: session.dynamicHoles.size,
542
+ streamedCount: session.streamedBoundaries.length
543
+ });
544
+ }
545
+ function emit2(session, neutralEvent, metadata) {
546
+ const step = {
547
+ neutralEvent,
548
+ providerEvent: providerEventName(session.target, neutralEvent),
549
+ state: session.state,
550
+ amountCents: 0,
551
+ metadata: { target: session.target, routeId: session.routeId, ...metadata }
552
+ };
553
+ session.history.push(step);
554
+ return step;
555
+ }
556
+
557
+ // src/semantics/interception-routes.ts
558
+ function startInterceptionRoutes(input) {
559
+ if (input.routeId.length === 0) {
560
+ throw new Error("startInterceptionRoutes: routeId must not be empty");
561
+ }
562
+ return {
563
+ target: input.target,
564
+ routeId: input.routeId,
565
+ state: "idle",
566
+ matches: [],
567
+ modalRoute: null,
568
+ history: []
569
+ };
570
+ }
571
+ function interceptCurrentSegment(session, from, to) {
572
+ return intercept(session, "(.)", "current", "intercept.current_segment", from, to);
573
+ }
574
+ function interceptParentSegment(session, from, to) {
575
+ return intercept(session, "(..)", "parent", "intercept.parent_segment", from, to);
576
+ }
577
+ function interceptRootCatchall(session, from, to) {
578
+ return intercept(session, "(...)", "root", "intercept.root_catchall", from, to);
579
+ }
580
+ function openInterceptedModal(session, modalRoute) {
581
+ if (modalRoute.length === 0) {
582
+ throw new Error("openInterceptedModal: modalRoute must not be empty");
583
+ }
584
+ if (session.matches.length === 0) {
585
+ throw new Error("openInterceptedModal: an interception match is required first");
586
+ }
587
+ session.state = "modal-open";
588
+ session.modalRoute = modalRoute;
589
+ return emit3(session, "intercept.modal_opened", {
590
+ modalRoute,
591
+ matchCount: session.matches.length
592
+ });
593
+ }
594
+ function intercept(session, matcher, state, neutralEvent, from, to) {
595
+ if (!from.startsWith("/") || !to.startsWith("/")) {
596
+ throw new Error("intercept: from and to must start with /");
597
+ }
598
+ session.state = state;
599
+ session.matches.push({ matcher, from, to });
600
+ return emit3(session, neutralEvent, { matcher, from, to });
601
+ }
602
+ function emit3(session, neutralEvent, metadata) {
603
+ const step = {
604
+ neutralEvent,
605
+ providerEvent: providerEventName(session.target, neutralEvent),
606
+ state: session.state,
607
+ amountCents: 0,
608
+ metadata: { target: session.target, routeId: session.routeId, ...metadata }
609
+ };
610
+ session.history.push(step);
611
+ return step;
612
+ }
613
+
614
+ // src/semantics/parallel-routes-advanced.ts
615
+ function startParallelRoutesAdvanced(input) {
616
+ if (input.layoutId.length === 0) {
617
+ throw new Error("startParallelRoutesAdvanced: layoutId must not be empty");
618
+ }
619
+ return {
620
+ target: input.target,
621
+ layoutId: input.layoutId,
622
+ state: "idle",
623
+ slots: /* @__PURE__ */ new Map(),
624
+ loadingSlots: /* @__PURE__ */ new Set(),
625
+ errors: [],
626
+ history: []
627
+ };
628
+ }
629
+ function renderDefaultSlot(session, slot, html) {
630
+ assertSlot(slot);
631
+ session.state = "default-rendered";
632
+ session.slots.set(slot, html);
633
+ return emit4(session, "parallel.default_rendered", { slot, html });
634
+ }
635
+ function renderLoadingState(session, slot) {
636
+ assertSlot(slot);
637
+ session.state = "loading-rendered";
638
+ session.loadingSlots.add(slot);
639
+ return emit4(session, "parallel.loading_rendered", {
640
+ slot,
641
+ loadingCount: session.loadingSlots.size
642
+ });
643
+ }
644
+ function captureParallelError(session, input) {
645
+ assertSlot(input.slot);
646
+ const message = typeof input.error === "string" ? input.error : input.error.message;
647
+ session.state = "error-captured";
648
+ session.errors.push({ slot: input.slot, message });
649
+ return emit4(session, "parallel.error_boundary_captured", {
650
+ slot: input.slot,
651
+ message,
652
+ errorCount: session.errors.length
653
+ });
654
+ }
655
+ function navigateSlot(session, input) {
656
+ assertSlot(input.slot);
657
+ if (!input.from.startsWith("/") || !input.to.startsWith("/")) {
658
+ throw new Error("navigateSlot: from and to must start with /");
659
+ }
660
+ session.state = "slot-navigated";
661
+ session.loadingSlots.delete(input.slot);
662
+ return emit4(session, "parallel.slot_navigated", input);
663
+ }
664
+ function assertSlot(slot) {
665
+ if (slot.length === 0) {
666
+ throw new Error("slot must not be empty");
667
+ }
668
+ }
669
+ function emit4(session, neutralEvent, metadata) {
670
+ const step = {
671
+ neutralEvent,
672
+ providerEvent: providerEventName(session.target, neutralEvent),
673
+ state: session.state,
674
+ amountCents: 0,
675
+ metadata: { target: session.target, layoutId: session.layoutId, ...metadata }
676
+ };
677
+ session.history.push(step);
678
+ return step;
679
+ }
680
+
681
+ // src/semantics/fidelity.ts
682
+ var NEXT_AXIS_TO_EVENTS = {
683
+ "server-action-advanced": [
684
+ "action.form_submitted",
685
+ "action.revalidate_path",
686
+ "action.revalidate_tag",
687
+ "action.redirected"
688
+ ],
689
+ "partial-prerendering": [
690
+ "ppr.static_shell_rendered",
691
+ "ppr.dynamic_hole_opened",
692
+ "ppr.streaming_boundary_flushed",
693
+ "ppr.completed"
694
+ ],
695
+ "interception-routes": [
696
+ "intercept.current_segment",
697
+ "intercept.parent_segment",
698
+ "intercept.root_catchall",
699
+ "intercept.modal_opened"
700
+ ],
701
+ "parallel-routes-advanced": [
702
+ "parallel.default_rendered",
703
+ "parallel.loading_rendered",
704
+ "parallel.error_boundary_captured",
705
+ "parallel.slot_navigated"
706
+ ]
707
+ };
708
+ function collectFidelityCoverage(providers = ["app-router", "pages-router", "edge-runtime"]) {
709
+ const axes = Object.keys(NEXT_AXIS_TO_EVENTS);
710
+ const rows = [];
711
+ for (const provider of providers) {
712
+ for (const axis of axes) {
713
+ const neutralEvents = NEXT_AXIS_TO_EVENTS[axis];
714
+ rows.push({
715
+ provider,
716
+ axis,
717
+ neutralEvents,
718
+ providerEvents: neutralEvents.map((event) => providerEventName(provider, event))
719
+ });
720
+ }
721
+ }
722
+ return { providers, axes, rows };
723
+ }
724
+
725
+ // src/real-driver.ts
726
+ var TARGET_KEY_ENV = {
727
+ "app-router": "NEXT_APP_URL",
728
+ "pages-router": "NEXT_PAGES_URL",
729
+ "edge-runtime": "EDGE_RUNTIME_URL"
730
+ };
731
+ function resolveMode(provider, env = process.env) {
732
+ const rawMode = env.KIWA_MODE?.toLowerCase();
733
+ if (rawMode !== void 0 && rawMode !== "real" && rawMode !== "mock") {
734
+ return { provider, mode: "mock", reason: "invalid-mode" };
735
+ }
736
+ if (rawMode !== "real") {
737
+ return { provider, mode: "mock", reason: "default-mock" };
738
+ }
739
+ const keyValue = env[TARGET_KEY_ENV[provider]];
740
+ if (typeof keyValue !== "string" || keyValue.length === 0) {
741
+ return { provider, mode: "mock", reason: "missing-key" };
742
+ }
743
+ return { provider, mode: "real", reason: "kiwa-mode-real" };
744
+ }
745
+ function resolveAllModes(env = process.env) {
746
+ const providers = ["app-router", "pages-router", "edge-runtime"];
747
+ return providers.map((provider) => resolveMode(provider, env));
748
+ }
749
+ function assertMode(provider, expected, env = process.env) {
750
+ const resolved = resolveMode(provider, env);
751
+ if (resolved.mode !== expected) {
752
+ throw new Error(
753
+ `expected ${provider} in ${expected} mode but resolved ${resolved.mode} (${resolved.reason})`
754
+ );
755
+ }
756
+ }
757
+ export {
758
+ FORBIDDEN_SYMBOL,
759
+ MIDDLEWARE_ACTION_SYMBOL,
760
+ NEXT_AXIS_TO_EVENTS,
761
+ NOT_FOUND_SYMBOL,
762
+ PARALLEL_INTERCEPTION_SYMBOL,
763
+ REDIRECT_SYMBOL,
764
+ RSC_ERROR_BOUNDARY_SYMBOL,
765
+ RSC_REDIRECT_SYMBOL,
766
+ assertMode,
767
+ captureParallelError,
768
+ collectFidelityCoverage,
769
+ completePartialPrerendering,
770
+ findAll,
771
+ flushStreamingBoundary,
772
+ interceptCurrentSegment,
773
+ interceptParentSegment,
774
+ interceptRootCatchall,
775
+ invokeMiddleware,
776
+ invokeParallelRoutes,
777
+ invokeServerAction,
778
+ middlewareActions,
779
+ navigateSlot,
780
+ openDynamicHole,
781
+ openInterceptedModal,
782
+ providerEventName,
783
+ redirectAction,
784
+ renderDefaultSlot,
785
+ renderLoadingState,
786
+ renderServerComponent,
787
+ renderStaticShell,
788
+ resolveAllModes,
789
+ resolveMode,
790
+ revalidateActionPath,
791
+ revalidateActionTag,
792
+ setupNextRscEnv,
793
+ startInterceptionRoutes,
794
+ startParallelRoutesAdvanced,
795
+ startPartialPrerendering,
796
+ startServerActionAdvanced,
797
+ submitFormAction,
798
+ textContent
799
+ };
800
+ //# sourceMappingURL=index.js.map