@nexusts/view 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,843 @@
1
+ // @bun
2
+ var __require = import.meta.require;
3
+
4
+ // packages/view/src/rendu.ts
5
+ import { compileTemplate } from "rendu";
6
+
7
+ class RenduAdapter {
8
+ name = "rendu";
9
+ cache = new Map;
10
+ render(template, data, context, options) {
11
+ const safe = {};
12
+ for (const [k, v] of Object.entries(data)) {
13
+ safe[k] = typeof v === "string" ? v : v == null ? "" : String(v);
14
+ }
15
+ const merged = this.mergeData(safe, context, options);
16
+ return this.getCompiled(template, options)(merged);
17
+ }
18
+ compile(template, options) {
19
+ const compiled = this.getCompiled(template, options);
20
+ return (data) => compiled(data);
21
+ }
22
+ getCompiled(template, options) {
23
+ const cacheKey = options ? `${options.stream ? "s" : ""}` : "";
24
+ let compiled = this.cache.get(cacheKey);
25
+ if (!compiled) {
26
+ compiled = compileTemplate(template, {
27
+ stream: options?.stream ?? false
28
+ });
29
+ this.cache.set(cacheKey, compiled);
30
+ }
31
+ return compiled;
32
+ }
33
+ mergeData(data, context, options) {
34
+ const merged = { ...data };
35
+ if (context) {
36
+ if (context.request)
37
+ merged.$REQUEST = context.request;
38
+ if (context.response)
39
+ merged.$RESPONSE = context.response;
40
+ if (context.globals)
41
+ Object.assign(merged, context.globals);
42
+ }
43
+ if (options?.layout)
44
+ merged.$LAYOUT = options.layout;
45
+ return merged;
46
+ }
47
+ }
48
+ // packages/view/src/edge.ts
49
+ class EdgeAdapter {
50
+ edge;
51
+ name = "edge";
52
+ constructor(edge) {
53
+ this.edge = edge;
54
+ }
55
+ async render(template, data, context, options) {
56
+ if (!this.edge) {
57
+ throw new Error("EdgeAdapter requires an Edge instance. " + "Install `edge.js` and pass it to `new EdgeAdapter(edge)`, " + "or use the default RenduAdapter instead.");
58
+ }
59
+ const fn = this.edge.renderRaw ?? this.edge.renderString;
60
+ if (!fn) {
61
+ throw new Error("Provided Edge instance does not implement renderRaw/renderString.");
62
+ }
63
+ return fn.call(this.edge, template, { ...data, $OPTIONS: options });
64
+ }
65
+ }
66
+ // packages/view/src/eta.ts
67
+ class EtaAdapter {
68
+ name = "eta";
69
+ cache = new Map;
70
+ async render(template, data, _context, _options) {
71
+ const compiled = this.getCompiled(template);
72
+ return compiled(data);
73
+ }
74
+ compile(template, _options) {
75
+ const compiled = this.getCompiled(template);
76
+ return (data) => Promise.resolve(compiled(data));
77
+ }
78
+ getCompiled(template) {
79
+ let fn = this.cache.get(template);
80
+ if (!fn) {
81
+ let Eta;
82
+ try {
83
+ Eta = __require("eta").Eta;
84
+ } catch (e) {
85
+ throw new Error(`[nexus] EtaAdapter: the "eta" package is not installed. ` + `Run \`bun add eta\` (or \`npm install eta\`) to use .eta templates.`);
86
+ }
87
+ const eta = new Eta;
88
+ fn = (data) => eta.renderString(template, data);
89
+ this.cache.set(template, fn);
90
+ }
91
+ return fn;
92
+ }
93
+ }
94
+ // packages/view/src/inertia/inertia-adapter.ts
95
+ import"reflect-metadata";
96
+
97
+ // packages/view/src/inertia/helpers.ts
98
+ class DeferredProp {
99
+ callback;
100
+ group;
101
+ __inertiaKind = "deferred";
102
+ constructor(callback, group = "default") {
103
+ this.callback = callback;
104
+ this.group = group;
105
+ }
106
+ resolve() {
107
+ return this.callback();
108
+ }
109
+ }
110
+ function defer(callback, group = "default") {
111
+ return new DeferredProp(callback, group);
112
+ }
113
+
114
+ class AlwaysProp {
115
+ callback;
116
+ __inertiaKind = "always";
117
+ constructor(callback) {
118
+ this.callback = callback;
119
+ }
120
+ resolve() {
121
+ return this.callback();
122
+ }
123
+ }
124
+ function always(callback) {
125
+ return new AlwaysProp(callback);
126
+ }
127
+
128
+ class OptionalProp {
129
+ callback;
130
+ threshold;
131
+ __inertiaKind = "optional";
132
+ constructor(callback, threshold = 0) {
133
+ this.callback = callback;
134
+ this.threshold = threshold;
135
+ }
136
+ resolve() {
137
+ return this.callback();
138
+ }
139
+ }
140
+ function optional(callback, threshold = 0) {
141
+ return new OptionalProp(callback, threshold);
142
+ }
143
+
144
+ class MergeProp {
145
+ __inertiaKind = "merge";
146
+ matchPropsOn;
147
+ constructor(callback, matchPropsOn = []) {
148
+ this.matchPropsOn = matchPropsOn;
149
+ this.callback = callback;
150
+ }
151
+ callback;
152
+ resolve() {
153
+ return this.callback();
154
+ }
155
+ }
156
+ function merge(callback, matchPropsOn = []) {
157
+ return new MergeProp(callback, matchPropsOn);
158
+ }
159
+
160
+ class DeepMergeProp {
161
+ callback;
162
+ __inertiaKind = "deepMerge";
163
+ constructor(callback) {
164
+ this.callback = callback;
165
+ }
166
+ resolve() {
167
+ return this.callback();
168
+ }
169
+ }
170
+ function deepMerge(callback) {
171
+ return new DeepMergeProp(callback);
172
+ }
173
+
174
+ class OnceProp {
175
+ callback;
176
+ __inertiaKind = "once";
177
+ constructor(callback) {
178
+ this.callback = callback;
179
+ }
180
+ resolve() {
181
+ return this.callback();
182
+ }
183
+ }
184
+ function once(callback) {
185
+ return new OnceProp(callback);
186
+ }
187
+ function isInertiaHelper(value) {
188
+ return value !== null && typeof value === "object" && typeof value.__inertiaKind === "string" && typeof value.resolve === "function";
189
+ }
190
+
191
+ // packages/view/src/inertia/default-ssr.ts
192
+ async function renderDefaultRoot(adapter, ssr, component, page, c) {
193
+ const title = adapter.title();
194
+ const headTags = [];
195
+ let bodyHtml = "";
196
+ if (ssr) {
197
+ try {
198
+ const result = await ssr.render(component, page.props);
199
+ bodyHtml = result.html ?? "";
200
+ if (result.head)
201
+ headTags.push(...result.head);
202
+ if (result.data) {
203
+ Object.assign(page, result.data);
204
+ }
205
+ } catch (err) {
206
+ console.error(`[inertia] SSR render failed for "${component}":`, err);
207
+ }
208
+ }
209
+ if (ssr?.head) {
210
+ try {
211
+ const extra = await ssr.head();
212
+ headTags.push(...extra);
213
+ } catch {}
214
+ }
215
+ const html = `<!DOCTYPE html>
216
+ <html lang="en">
217
+ <head>
218
+ <meta charset="utf-8">
219
+ <meta name="viewport" content="width=device-width, initial-scale=1">
220
+ <title>${escapeHtml(title)}</title>
221
+ ${headTags.join(`
222
+ `)}
223
+ </head>
224
+ <body>
225
+ <div id="app" data-page="${escapeAttr(JSON.stringify(page))}">${bodyHtml}</div>
226
+ </body>
227
+ </html>`;
228
+ return c.html(html, 200, {
229
+ Vary: "X-Inertia"
230
+ });
231
+ }
232
+ function escapeHtml(s) {
233
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
234
+ }
235
+ function escapeAttr(s) {
236
+ return escapeHtml(s).replace(/'/g, "&#39;");
237
+ }
238
+
239
+ // packages/view/src/inertia/inertia-response.ts
240
+ var INERTIA_RESPONSE_TAG = "__nexus_inertia_response__";
241
+
242
+ class InertiaResponse {
243
+ adapter;
244
+ component;
245
+ props;
246
+ [INERTIA_RESPONSE_TAG] = true;
247
+ options = {};
248
+ lazyCache = new Map;
249
+ constructor(adapter, component, props) {
250
+ this.adapter = adapter;
251
+ this.component = component;
252
+ this.props = props;
253
+ }
254
+ withEncryptHistory(encrypt = true) {
255
+ this.options.encryptHistory = encrypt;
256
+ return this;
257
+ }
258
+ withClearHistory(clear = true) {
259
+ this.options.clearHistory = clear;
260
+ return this;
261
+ }
262
+ async toResponse(c) {
263
+ const url = c.req.url;
264
+ const info = this.parseInertiaRequest(c);
265
+ if (info.isInertia && info.clientVersion !== undefined) {
266
+ const serverVersion = await this.adapter.resolveVersion();
267
+ if (serverVersion !== undefined && info.clientVersion !== serverVersion) {
268
+ return this.assetVersionMismatch(c.req.url);
269
+ }
270
+ }
271
+ const page = await this.buildPage(url, info, c);
272
+ if (info.isInertia) {
273
+ return this.jsonResponse(page);
274
+ }
275
+ return this.htmlResponse(c, page);
276
+ }
277
+ async buildPage(url, info, c) {
278
+ const shared = await this.adapter.getSharedFor(c);
279
+ const allProps = { ...shared, ...this.props };
280
+ const resolved = {};
281
+ const deferredProps = {};
282
+ const mergeProps = [];
283
+ const deepMergeProps = [];
284
+ const matchPropsOn = [];
285
+ for (const [key, value] of Object.entries(allProps)) {
286
+ if (isInertiaHelper(value)) {
287
+ const helper = value;
288
+ switch (helper.__inertiaKind) {
289
+ case "deferred": {
290
+ const d = helper;
291
+ const group = d.group ?? "default";
292
+ (deferredProps[group] ??= []).push(key);
293
+ resolved[key] = null;
294
+ break;
295
+ }
296
+ case "always": {
297
+ resolved[key] = await Promise.resolve(helper.resolve());
298
+ break;
299
+ }
300
+ case "optional": {
301
+ const v = await Promise.resolve(helper.resolve());
302
+ const o = helper;
303
+ const threshold = o.threshold ?? 0;
304
+ if (Array.isArray(v) && v.length <= threshold) {
305
+ if (this.isPartialReload(info)) {
306
+ continue;
307
+ }
308
+ }
309
+ resolved[key] = v;
310
+ break;
311
+ }
312
+ case "merge": {
313
+ const v = await Promise.resolve(helper.resolve());
314
+ mergeProps.push(key);
315
+ const m = helper;
316
+ if (m.matchPropsOn && m.matchPropsOn.length > 0) {
317
+ deepMergeProps.push(key);
318
+ matchPropsOn.push(m.matchPropsOn);
319
+ }
320
+ resolved[key] = v;
321
+ break;
322
+ }
323
+ case "deepMerge": {
324
+ resolved[key] = await Promise.resolve(helper.resolve());
325
+ mergeProps.push(key);
326
+ deepMergeProps.push(key);
327
+ break;
328
+ }
329
+ case "once": {
330
+ if (info.isInertia) {
331
+ continue;
332
+ }
333
+ resolved[key] = await Promise.resolve(helper.resolve());
334
+ break;
335
+ }
336
+ case "lazy": {
337
+ const lz = helper;
338
+ const tag = lz.tag;
339
+ if (this.lazyCache.has(tag)) {
340
+ resolved[key] = this.lazyCache.get(tag);
341
+ } else {
342
+ const v = await Promise.resolve(helper.resolve());
343
+ this.lazyCache.set(tag, v);
344
+ resolved[key] = v;
345
+ }
346
+ break;
347
+ }
348
+ default: {
349
+ resolved[key] = await Promise.resolve(helper.resolve());
350
+ }
351
+ }
352
+ } else {
353
+ resolved[key] = value;
354
+ }
355
+ }
356
+ const sharedKeys = new Set(Object.keys(shared));
357
+ this.applyPartialFilter(resolved, info, sharedKeys);
358
+ const version = await this.adapter.resolveVersion();
359
+ return {
360
+ component: this.component,
361
+ props: resolved,
362
+ url,
363
+ version: version ?? "",
364
+ encryptHistory: this.options.encryptHistory ?? this.adapter.encryptHistory(),
365
+ clearHistory: this.options.clearHistory ?? false,
366
+ deferredProps: Object.keys(deferredProps).length > 0 ? deferredProps : undefined,
367
+ mergeProps: mergeProps.length > 0 ? mergeProps : undefined,
368
+ deepMergeProps: deepMergeProps.length > 0 ? deepMergeProps : undefined,
369
+ matchPropsOn: matchPropsOn.length > 0 ? matchPropsOn : undefined,
370
+ scrollRegions: {}
371
+ };
372
+ }
373
+ applyPartialFilter(resolved, info, sharedKeys) {
374
+ if (!this.isPartialReload(info))
375
+ return;
376
+ if (info.partialOnly) {
377
+ for (const key of Object.keys(resolved)) {
378
+ const isAlways = sharedKeys.has(key);
379
+ if (!info.partialOnly.includes(key) && !isAlways) {
380
+ delete resolved[key];
381
+ }
382
+ }
383
+ }
384
+ if (info.partialExcept) {
385
+ for (const key of Object.keys(resolved)) {
386
+ const isAlways = sharedKeys.has(key);
387
+ if (info.partialExcept.includes(key) && !isAlways) {
388
+ delete resolved[key];
389
+ }
390
+ }
391
+ }
392
+ }
393
+ isPartialReload(info) {
394
+ return info.isInertia && (!!info.partialOnly || !!info.partialExcept);
395
+ }
396
+ parseInertiaRequest(c) {
397
+ const isInertia = c.req.header("x-inertia") === "true";
398
+ const partialOnlyHeader = c.req.header("x-inertia-partial-data");
399
+ const partialExceptHeader = c.req.header("x-inertia-partial-except");
400
+ const resetHeader = c.req.header("x-inertia-reset");
401
+ return {
402
+ isInertia,
403
+ clientVersion: c.req.header("x-inertia-version") ?? undefined,
404
+ partialComponent: c.req.header("x-inertia-partial-component") ?? undefined,
405
+ partialOnly: this.csv(partialOnlyHeader),
406
+ partialExcept: this.csv(partialExceptHeader),
407
+ reset: this.csv(resetHeader),
408
+ isHardReload: c.req.header("x-inertia-hard-reload") === "true"
409
+ };
410
+ }
411
+ csv(value) {
412
+ if (!value)
413
+ return;
414
+ const parts = value.split(",").map((s) => s.trim()).filter(Boolean);
415
+ return parts.length > 0 ? parts : undefined;
416
+ }
417
+ jsonResponse(page) {
418
+ return new Response(JSON.stringify(page), {
419
+ status: 200,
420
+ headers: {
421
+ "Content-Type": "application/json",
422
+ Vary: "X-Inertia",
423
+ "X-Inertia": "true"
424
+ }
425
+ });
426
+ }
427
+ htmlResponse(c, page) {
428
+ const ssr = this.adapter.ssr();
429
+ return renderDefaultRoot(this.adapter, ssr ?? null, this.component, page, c);
430
+ }
431
+ assetVersionMismatch(url) {
432
+ return new Response(null, {
433
+ status: 409,
434
+ headers: {
435
+ "X-Inertia-Location": url
436
+ }
437
+ });
438
+ }
439
+ }
440
+
441
+ // packages/view/src/inertia/form-helper.ts
442
+ class InertiaFormBuilder {
443
+ adapter;
444
+ component;
445
+ props;
446
+ errorMap = {};
447
+ errorBagName;
448
+ constructor(adapter, component, initialProps = {}) {
449
+ this.adapter = adapter;
450
+ this.component = component;
451
+ this.props = { ...initialProps };
452
+ }
453
+ withProps(extra) {
454
+ Object.assign(this.props, extra);
455
+ return this;
456
+ }
457
+ with(key, value) {
458
+ this.props[key] = value;
459
+ return this;
460
+ }
461
+ withErrors(errors) {
462
+ for (const [field, message] of Object.entries(errors)) {
463
+ const list = Array.isArray(message) ? message : [message];
464
+ this.errorMap[field] = [...this.errorMap[field] ?? [], ...list];
465
+ }
466
+ return this;
467
+ }
468
+ withError(field, message) {
469
+ (this.errorMap[field] ??= []).push(message);
470
+ return this;
471
+ }
472
+ withErrorBag(name) {
473
+ this.errorBagName = name;
474
+ return this;
475
+ }
476
+ withValues(values) {
477
+ this.props.values = values;
478
+ return this;
479
+ }
480
+ render() {
481
+ if (Object.keys(this.errorMap).length > 0) {
482
+ this.props.errors = { ...this.errorMap };
483
+ }
484
+ if (this.errorBagName) {
485
+ this.props.errorBag = this.errorBagName;
486
+ }
487
+ return this.adapter.render(this.component, this.props);
488
+ }
489
+ redirect(url) {
490
+ return new Response(null, {
491
+ status: 303,
492
+ headers: { Location: url }
493
+ });
494
+ }
495
+ back(to) {
496
+ return new Response(null, {
497
+ status: 303,
498
+ headers: { Location: to ?? "back" }
499
+ });
500
+ }
501
+ getErrors() {
502
+ return { ...this.errorMap };
503
+ }
504
+ getProps() {
505
+ return { ...this.props };
506
+ }
507
+ }
508
+
509
+ // packages/view/src/inertia/inertia-adapter.ts
510
+ var INERTIA_TOKEN = Symbol.for("nexus:Inertia");
511
+
512
+ class Inertia {
513
+ config;
514
+ shared = {};
515
+ constructor(config = {}) {
516
+ this.config = {
517
+ encryptHistory: false,
518
+ ...config
519
+ };
520
+ }
521
+ render(component, propsOrDeferred, maybeProps) {
522
+ const { component: comp, props } = this.normalizeRenderArgs(component, propsOrDeferred, maybeProps);
523
+ return new InertiaResponse(this, comp, props);
524
+ }
525
+ location(url) {
526
+ return new Response(null, {
527
+ status: 409,
528
+ headers: {
529
+ "X-Inertia-Location": url
530
+ }
531
+ });
532
+ }
533
+ redirect(url, status = 302) {
534
+ return new Response(null, {
535
+ status,
536
+ headers: { Location: url }
537
+ });
538
+ }
539
+ back() {
540
+ return new Response(null, {
541
+ status: 302,
542
+ headers: { Location: "back" }
543
+ });
544
+ }
545
+ form(component, initialProps = {}) {
546
+ return new InertiaFormBuilder(this, component, initialProps);
547
+ }
548
+ setVersion(version) {
549
+ this.config.version = version;
550
+ return this;
551
+ }
552
+ setSsrAdapter(adapter) {
553
+ this.config.ssr = adapter ?? undefined;
554
+ return this;
555
+ }
556
+ setTitle(title) {
557
+ this.config.title = title;
558
+ return this;
559
+ }
560
+ setEncryptHistory(encrypt = true) {
561
+ this.config.encryptHistory = encrypt;
562
+ return this;
563
+ }
564
+ setSharedProps(shared) {
565
+ this.config.sharedProps = shared;
566
+ return this;
567
+ }
568
+ share(key, value) {
569
+ if (typeof key === "string") {
570
+ this.shared[key] = value;
571
+ } else if (key && typeof key === "object") {
572
+ Object.assign(this.shared, key);
573
+ }
574
+ }
575
+ unshare(key) {
576
+ delete this.shared[key];
577
+ }
578
+ getShared() {
579
+ return { ...this.shared };
580
+ }
581
+ title() {
582
+ return this.config.title ?? "Nexus";
583
+ }
584
+ encryptHistory() {
585
+ return this.config.encryptHistory ?? false;
586
+ }
587
+ ssr() {
588
+ return this.config.ssr ?? null;
589
+ }
590
+ async resolveVersion() {
591
+ const v = this.config.version;
592
+ if (typeof v === "function")
593
+ return await v();
594
+ return v;
595
+ }
596
+ async getSharedFor(_c) {
597
+ const static_ = this.getShared();
598
+ const configured = this.config.sharedProps;
599
+ if (typeof configured === "function") {
600
+ const dyn = await configured();
601
+ return { ...static_, ...dyn };
602
+ }
603
+ return { ...static_, ...configured ?? {} };
604
+ }
605
+ static TOKEN = INERTIA_TOKEN;
606
+ normalizeRenderArgs(component, propsOrDeferred, maybeProps) {
607
+ if (maybeProps !== undefined) {
608
+ const deferred = {};
609
+ for (const [k, v] of Object.entries(propsOrDeferred)) {
610
+ if (v instanceof DeferredProp)
611
+ deferred[k] = v;
612
+ else
613
+ throw new Error(`Inertia.render: 3-arg form expects the second argument to be a map of deferred props. ` + `Got non-deferred value at key "${k}".`);
614
+ }
615
+ return { component, props: { ...deferred, ...maybeProps } };
616
+ }
617
+ return { component, props: propsOrDeferred ?? {} };
618
+ }
619
+ }
620
+ // packages/view/src/inertia/form-middleware.ts
621
+ var FORM_METHODS = new Set(["POST", "PUT", "PATCH", "DELETE"]);
622
+ function inertiaFormMiddleware(options = {}) {
623
+ const csrfHeader = (options.csrfHeader ?? "X-CSRF-Token").toLowerCase();
624
+ const csrfField = options.csrfField ?? "_token";
625
+ const csrfSharedKey = options.csrfSharedKey ?? "csrfToken";
626
+ const csrfStatus = options.csrfFailureStatus ?? 419;
627
+ return async (c, next) => {
628
+ const method = c.req.method;
629
+ if (!FORM_METHODS.has(method)) {
630
+ await next();
631
+ return;
632
+ }
633
+ if (options.validateCsrf) {
634
+ const expected = options.getCsrfToken ? options.getCsrfToken(c) : c.get("nexusjs")?.shared?.[csrfSharedKey];
635
+ if (typeof expected === "string" && expected.length > 0) {
636
+ const submittedHeader = c.req.header(csrfHeader);
637
+ const submittedField = await readFieldFromBody(c, csrfField);
638
+ const submitted = submittedHeader ?? submittedField;
639
+ if (submitted !== expected) {
640
+ return c.json({ message: "CSRF token mismatch" }, csrfStatus);
641
+ }
642
+ }
643
+ }
644
+ const contentType = c.req.header("content-type") ?? "";
645
+ if (contentType.includes("application/x-www-form-urlencoded") || contentType.includes("multipart/form-data")) {
646
+ try {
647
+ const parsed = await c.req.parseBody();
648
+ c.set("formBody", parsed);
649
+ } catch {}
650
+ }
651
+ await next();
652
+ return;
653
+ };
654
+ }
655
+ async function readFieldFromBody(c, field) {
656
+ const cached = c.get("formBody");
657
+ if (cached && Object.hasOwn(cached, field)) {
658
+ const v = cached[field];
659
+ return Array.isArray(v) ? v[0] : v;
660
+ }
661
+ try {
662
+ const body = await c.req.parseBody();
663
+ if (body && Object.hasOwn(body, field)) {
664
+ const v = body[field];
665
+ return Array.isArray(v) ? v[0] : v;
666
+ }
667
+ } catch {}
668
+ return;
669
+ }
670
+ // packages/view/src/inertia/ssr/registry.ts
671
+ class ComponentRegistry {
672
+ map = new Map;
673
+ register(name, component) {
674
+ this.map.set(name, component);
675
+ return this;
676
+ }
677
+ registerAll(components) {
678
+ for (const [name, component] of Object.entries(components)) {
679
+ this.map.set(name, component);
680
+ }
681
+ return this;
682
+ }
683
+ resolve(name) {
684
+ return this.map.get(name);
685
+ }
686
+ has(name) {
687
+ return this.map.has(name);
688
+ }
689
+ unregister(name) {
690
+ return this.map.delete(name);
691
+ }
692
+ names() {
693
+ return [...this.map.keys()];
694
+ }
695
+ get size() {
696
+ return this.map.size;
697
+ }
698
+ }
699
+ function createRegistry(initial) {
700
+ const reg = new ComponentRegistry;
701
+ if (initial)
702
+ reg.registerAll(initial);
703
+ return reg;
704
+ }
705
+ function asRegistry(input) {
706
+ return input instanceof ComponentRegistry ? input : createRegistry(input);
707
+ }
708
+
709
+ // packages/view/src/inertia/ssr/react-adapter.ts
710
+ function createReactAdapter(options) {
711
+ const registry = asRegistry(options.components);
712
+ return {
713
+ name: "react",
714
+ async render(component, props) {
715
+ const [{ renderToString }, React] = await Promise.all([
716
+ import("react-dom/server"),
717
+ import("react")
718
+ ]);
719
+ const Component = registry.resolve(component);
720
+ if (!Component) {
721
+ throw new Error(`[inertia/react] Component "${component}" is not registered. ` + `Use createReactAdapter({ components: { ${component}: ... } }) ` + `or registry.register('${component}', Component).`);
722
+ }
723
+ const element = React.createElement(Component, props);
724
+ const html = renderToString(element);
725
+ return { html, head: [] };
726
+ }
727
+ };
728
+ }
729
+ // packages/view/src/inertia/ssr/vue-adapter.ts
730
+ function createVueAdapter(options) {
731
+ const registry = asRegistry(options.components);
732
+ return {
733
+ name: "vue",
734
+ async render(component, props) {
735
+ const [{ renderToString }, { createSSRApp, h }] = await Promise.all([
736
+ import("vue/server-renderer"),
737
+ import("vue")
738
+ ]);
739
+ const Component = registry.resolve(component);
740
+ if (!Component) {
741
+ throw new Error(`[inertia/vue] Component "${component}" is not registered. ` + `Use createVueAdapter({ components: { ${component}: ... } }) ` + `or registry.register('${component}', Component).`);
742
+ }
743
+ const app = createSSRApp({
744
+ render() {
745
+ return h(Component, props);
746
+ }
747
+ });
748
+ const html = await renderToString(app);
749
+ return { html, head: [] };
750
+ }
751
+ };
752
+ }
753
+ // packages/view/src/view-engine.ts
754
+ var viewPath = "";
755
+ function setViewPaths(path) {
756
+ viewPath = path ? path.endsWith("/") || path.endsWith("\\") ? path : `${path}/` : "";
757
+ }
758
+ function getViewPaths() {
759
+ return viewPath;
760
+ }
761
+ var VIEW_FILE_EXTS = [".html", ".edge", ".rendu", ".eta"];
762
+ function isViewFilePath(name) {
763
+ const lower = name.toLowerCase();
764
+ return VIEW_FILE_EXTS.some((ext) => lower.endsWith(ext));
765
+ }
766
+ function selectAdapter(template) {
767
+ const lower = template.toLowerCase();
768
+ if (lower.endsWith(".edge"))
769
+ return new EdgeAdapter;
770
+ if (lower.endsWith(".eta"))
771
+ return new EtaAdapter;
772
+ return new RenduAdapter;
773
+ }
774
+ async function renderView(template, data, context) {
775
+ let source = template;
776
+ if (isViewFilePath(template) && viewPath.length > 0) {
777
+ const loaded = await loadTemplate(viewPath, template);
778
+ if (loaded === null) {
779
+ throw new Error(`[nexus] View file not found: "${template}" (searched: ${viewPath})`);
780
+ }
781
+ source = loaded;
782
+ }
783
+ const adapter = selectAdapter(source);
784
+ return adapter.render(source, data, context);
785
+ }
786
+ async function loadTemplate(dir, name) {
787
+ if (!dir)
788
+ return null;
789
+ const full = joinPath(dir, name);
790
+ try {
791
+ const file = await readFile(full);
792
+ if (file !== null)
793
+ return file;
794
+ } catch {}
795
+ return null;
796
+ }
797
+ function joinPath(dir, name) {
798
+ if (!dir.endsWith("/") && !dir.endsWith("\\"))
799
+ return `${dir}/${name}`;
800
+ return `${dir}${name}`;
801
+ }
802
+ async function readFile(path) {
803
+ if (typeof globalThis.Bun !== "undefined") {
804
+ try {
805
+ const file = globalThis.Bun.file(path);
806
+ if (await file.exists())
807
+ return file.text();
808
+ } catch {}
809
+ }
810
+ try {
811
+ const fs = await import("fs/promises");
812
+ return await fs.readFile(path, "utf8");
813
+ } catch {
814
+ return null;
815
+ }
816
+ }
817
+ export {
818
+ setViewPaths,
819
+ renderView,
820
+ renderDefaultRoot,
821
+ optional,
822
+ once,
823
+ merge,
824
+ loadTemplate,
825
+ inertiaFormMiddleware,
826
+ getViewPaths,
827
+ defer,
828
+ deepMerge,
829
+ createVueAdapter,
830
+ createRegistry,
831
+ createReactAdapter,
832
+ asRegistry,
833
+ always,
834
+ RenduAdapter,
835
+ InertiaFormBuilder,
836
+ Inertia,
837
+ EtaAdapter,
838
+ EdgeAdapter,
839
+ ComponentRegistry
840
+ };
841
+
842
+ //# debugId=7E50D43C00788D4B64756E2164756E21
843
+ //# sourceMappingURL=index.js.map