streetui 1.9.0 → 2.0.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/bin.cjs +1 -1
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/bin.js.map +1 -1
- package/dist/create-bin.cjs +1 -1
- package/dist/create-bin.cjs.map +1 -1
- package/dist/create-bin.js +1 -1
- package/dist/create-bin.js.map +1 -1
- package/dist/{compile-DqsMQVJk.d.cts → hydration-diagnostics-CFYDXBlm.d.cts} +353 -3
- package/dist/{compile-DqsMQVJk.d.ts → hydration-diagnostics-CFYDXBlm.d.ts} +353 -3
- package/dist/index.cjs +865 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +355 -147
- package/dist/index.d.ts +355 -147
- package/dist/index.js +851 -8
- package/dist/index.js.map +1 -1
- package/dist/renderer-interface-BUhHV7ja.d.cts +26 -0
- package/dist/renderer-interface-B_-hWnKk.d.ts +26 -0
- package/dist/{server-BYnmb_hR.d.ts → server-C0PvFBzD.d.ts} +181 -2
- package/dist/{server-DnwqBTfE.d.cts → server-DnAOFpMP.d.cts} +181 -2
- package/dist/server.cjs +217 -3
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +216 -3
- package/dist/server.js.map +1 -1
- package/dist/testing.cjs +368 -6
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +3 -3
- package/dist/testing.d.ts +3 -3
- package/dist/testing.js +368 -6
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
- package/dist/hydration-diagnostics-4pwt6v7b.d.cts +0 -89
- package/dist/hydration-diagnostics-B2FmY05M.d.ts +0 -89
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/version.ts
|
|
2
|
-
var VERSION = "
|
|
2
|
+
var VERSION = "2.0.0";
|
|
3
3
|
|
|
4
4
|
// ../state/src/signal.ts
|
|
5
5
|
var _activeConsumer = null;
|
|
@@ -339,6 +339,198 @@ function resource(loader, options = {}) {
|
|
|
339
339
|
};
|
|
340
340
|
}
|
|
341
341
|
|
|
342
|
+
// ../state/src/mutation.ts
|
|
343
|
+
function mutation(mutator, options = {}) {
|
|
344
|
+
const status = signal("idle");
|
|
345
|
+
const data = signal(void 0);
|
|
346
|
+
const error = signal(void 0);
|
|
347
|
+
const pending = derived(() => status.get() === "loading");
|
|
348
|
+
let disposed = false;
|
|
349
|
+
let runId = 0;
|
|
350
|
+
const mutate = async (args) => {
|
|
351
|
+
if (disposed) {
|
|
352
|
+
return await mutator(args);
|
|
353
|
+
}
|
|
354
|
+
const myRun = ++runId;
|
|
355
|
+
batch(() => {
|
|
356
|
+
error.set(void 0);
|
|
357
|
+
status.set("loading");
|
|
358
|
+
});
|
|
359
|
+
try {
|
|
360
|
+
const result = await mutator(args);
|
|
361
|
+
if (!disposed && myRun === runId) {
|
|
362
|
+
batch(() => {
|
|
363
|
+
data.set(result);
|
|
364
|
+
error.set(void 0);
|
|
365
|
+
status.set("success");
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
if (!disposed && myRun === runId) {
|
|
369
|
+
await options.onSuccess?.(result, args);
|
|
370
|
+
await options.onSettled?.(args);
|
|
371
|
+
}
|
|
372
|
+
return result;
|
|
373
|
+
} catch (err) {
|
|
374
|
+
if (!disposed && myRun === runId) {
|
|
375
|
+
batch(() => {
|
|
376
|
+
error.set(err);
|
|
377
|
+
status.set("error");
|
|
378
|
+
});
|
|
379
|
+
await options.onError?.(err, args);
|
|
380
|
+
await options.onSettled?.(args);
|
|
381
|
+
}
|
|
382
|
+
throw err;
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
const reset = () => {
|
|
386
|
+
batch(() => {
|
|
387
|
+
status.set("idle");
|
|
388
|
+
data.set(void 0);
|
|
389
|
+
error.set(void 0);
|
|
390
|
+
});
|
|
391
|
+
};
|
|
392
|
+
const dispose = () => {
|
|
393
|
+
disposed = true;
|
|
394
|
+
};
|
|
395
|
+
if (options.onCleanup !== void 0) options.onCleanup(dispose);
|
|
396
|
+
return { status, data, error, pending, mutate, reset, dispose };
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// ../state/src/client.ts
|
|
400
|
+
var HttpError = class extends Error {
|
|
401
|
+
status;
|
|
402
|
+
statusText;
|
|
403
|
+
url;
|
|
404
|
+
body;
|
|
405
|
+
constructor(status, statusText, url, body) {
|
|
406
|
+
super(`HTTP ${status} ${statusText} for ${url}`);
|
|
407
|
+
this.name = "HttpError";
|
|
408
|
+
this.status = status;
|
|
409
|
+
this.statusText = statusText;
|
|
410
|
+
this.url = url;
|
|
411
|
+
this.body = body;
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
function joinUrl(baseUrl, path) {
|
|
415
|
+
if (baseUrl === void 0 || baseUrl === "") return path;
|
|
416
|
+
const b = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
417
|
+
const p = path.startsWith("/") ? path : `/${path}`;
|
|
418
|
+
return `${b}${p}`;
|
|
419
|
+
}
|
|
420
|
+
function withQuery(url, query) {
|
|
421
|
+
if (query === void 0) return url;
|
|
422
|
+
const params = new URLSearchParams();
|
|
423
|
+
for (const [k, v] of Object.entries(query)) params.set(k, String(v));
|
|
424
|
+
const qs = params.toString();
|
|
425
|
+
if (qs === "") return url;
|
|
426
|
+
return url.includes("?") ? `${url}&${qs}` : `${url}?${qs}`;
|
|
427
|
+
}
|
|
428
|
+
function createClient(config = {}) {
|
|
429
|
+
const doFetch = config.fetch ?? ((input, init) => {
|
|
430
|
+
if (typeof fetch === "undefined") {
|
|
431
|
+
throw new Error("createClient: no global fetch; pass { fetch } explicitly");
|
|
432
|
+
}
|
|
433
|
+
return fetch(input, init);
|
|
434
|
+
});
|
|
435
|
+
async function request(method, path, body, reqConfig = {}) {
|
|
436
|
+
const url = withQuery(joinUrl(config.baseUrl, path), reqConfig.query);
|
|
437
|
+
const headers = { ...config.headers, ...reqConfig.headers };
|
|
438
|
+
const init = { method, headers };
|
|
439
|
+
if (reqConfig.signal !== void 0) init.signal = reqConfig.signal;
|
|
440
|
+
if (body !== void 0) {
|
|
441
|
+
if (headers["Content-Type"] === void 0) headers["Content-Type"] = "application/json";
|
|
442
|
+
init.body = JSON.stringify(body);
|
|
443
|
+
}
|
|
444
|
+
const response = await doFetch(url, init);
|
|
445
|
+
const parsed = await parseBody(response);
|
|
446
|
+
if (!response.ok) {
|
|
447
|
+
throw new HttpError(response.status, response.statusText, url, parsed);
|
|
448
|
+
}
|
|
449
|
+
return parsed;
|
|
450
|
+
}
|
|
451
|
+
return {
|
|
452
|
+
request,
|
|
453
|
+
get: (path, c) => request("GET", path, void 0, c),
|
|
454
|
+
post: (path, b, c) => request("POST", path, b, c),
|
|
455
|
+
put: (path, b, c) => request("PUT", path, b, c),
|
|
456
|
+
patch: (path, b, c) => request("PATCH", path, b, c),
|
|
457
|
+
del: (path, c) => request("DELETE", path, void 0, c),
|
|
458
|
+
resource: (path, options = {}) => {
|
|
459
|
+
const { query, ...resourceOptions } = options;
|
|
460
|
+
return resource(
|
|
461
|
+
(ctx) => request("GET", path, void 0, { signal: ctx.signal, ...query !== void 0 ? { query } : {} }),
|
|
462
|
+
resourceOptions
|
|
463
|
+
);
|
|
464
|
+
},
|
|
465
|
+
mutation: (method, path, options) => mutation((args) => request(method, path, args), options ?? {})
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
async function parseBody(response) {
|
|
469
|
+
const text = await response.text();
|
|
470
|
+
if (text === "") return void 0;
|
|
471
|
+
const type = response.headers.get("content-type") ?? "";
|
|
472
|
+
if (type.includes("application/json")) {
|
|
473
|
+
try {
|
|
474
|
+
return JSON.parse(text);
|
|
475
|
+
} catch {
|
|
476
|
+
return text;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return text;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// ../state/src/auth.ts
|
|
483
|
+
function createAuthSession(config) {
|
|
484
|
+
const session = resource(
|
|
485
|
+
(ctx) => config.loadUser(ctx),
|
|
486
|
+
{
|
|
487
|
+
...config.immediate !== void 0 ? { immediate: config.immediate } : {},
|
|
488
|
+
...config.onCleanup !== void 0 ? { onCleanup: config.onCleanup } : {}
|
|
489
|
+
}
|
|
490
|
+
);
|
|
491
|
+
const status = derived(() => {
|
|
492
|
+
const s = session.status.get();
|
|
493
|
+
const d = session.data.get();
|
|
494
|
+
if (s === "error") return "error";
|
|
495
|
+
if (s === "idle" || s === "loading" && d === void 0) return "loading";
|
|
496
|
+
return d === null || d === void 0 ? "unauthenticated" : "authenticated";
|
|
497
|
+
});
|
|
498
|
+
const user = derived(() => {
|
|
499
|
+
const d = session.data.get();
|
|
500
|
+
return d === null ? void 0 : d;
|
|
501
|
+
});
|
|
502
|
+
const authenticated = derived(() => status.get() === "authenticated");
|
|
503
|
+
const unauthenticated = derived(() => status.get() === "unauthenticated");
|
|
504
|
+
const loading = derived(() => status.get() === "loading");
|
|
505
|
+
const logoutMutation = mutation(
|
|
506
|
+
async () => {
|
|
507
|
+
await config.logout?.();
|
|
508
|
+
},
|
|
509
|
+
{ onSuccess: () => session.refetch() }
|
|
510
|
+
);
|
|
511
|
+
const dispose = () => {
|
|
512
|
+
session.dispose();
|
|
513
|
+
status.dispose();
|
|
514
|
+
user.dispose();
|
|
515
|
+
authenticated.dispose();
|
|
516
|
+
unauthenticated.dispose();
|
|
517
|
+
loading.dispose();
|
|
518
|
+
logoutMutation.dispose();
|
|
519
|
+
};
|
|
520
|
+
return {
|
|
521
|
+
status,
|
|
522
|
+
user,
|
|
523
|
+
error: session.error,
|
|
524
|
+
authenticated,
|
|
525
|
+
unauthenticated,
|
|
526
|
+
loading,
|
|
527
|
+
loggingOut: logoutMutation.pending,
|
|
528
|
+
refresh: () => session.refetch(),
|
|
529
|
+
logout: () => logoutMutation.mutate(void 0),
|
|
530
|
+
dispose
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
|
|
342
534
|
// ../core/src/a11y-ids.ts
|
|
343
535
|
var UNSAFE = /[^A-Za-z0-9_-]+/g;
|
|
344
536
|
function toIdToken(base) {
|
|
@@ -605,9 +797,13 @@ function formatDiagnosticContext(context) {
|
|
|
605
797
|
const parts = [];
|
|
606
798
|
if (context.package !== void 0) parts.push(`package=${context.package}`);
|
|
607
799
|
if (context.operation !== void 0) parts.push(`operation=${context.operation}`);
|
|
800
|
+
if (context.component !== void 0) parts.push(`component=${context.component}`);
|
|
801
|
+
if (context.phase !== void 0) parts.push(`phase=${context.phase}`);
|
|
608
802
|
if (context.nodeId !== void 0) parts.push(`node=${context.nodeId}`);
|
|
803
|
+
if (context.element !== void 0) parts.push(`element=${context.element}`);
|
|
609
804
|
if (context.route !== void 0) parts.push(`route=${context.route}`);
|
|
610
805
|
if (context.resource !== void 0) parts.push(`resource=${context.resource}`);
|
|
806
|
+
if (context.signal !== void 0) parts.push(`signal=${context.signal}`);
|
|
611
807
|
return parts.length > 0 ? ` [${parts.join(", ")}]` : "";
|
|
612
808
|
}
|
|
613
809
|
var StreetFrameworkError = class extends Error {
|
|
@@ -638,6 +834,42 @@ function consoleDiagnosticSink(logger = console) {
|
|
|
638
834
|
error: (m, c) => logger.error?.(`${m}${formatDiagnosticContext(c)}`)
|
|
639
835
|
};
|
|
640
836
|
}
|
|
837
|
+
function describeErrorAt(error, context, options, depth) {
|
|
838
|
+
const isError = error instanceof Error;
|
|
839
|
+
const name = isError ? error.name : "Error";
|
|
840
|
+
const message = isError ? error.message : safeStringify(error);
|
|
841
|
+
const report = { name, message, isError };
|
|
842
|
+
if (context !== void 0) report.context = context;
|
|
843
|
+
if (options.includeStack === true && isError && typeof error.stack === "string") {
|
|
844
|
+
report.stack = error.stack;
|
|
845
|
+
}
|
|
846
|
+
if (options.includeCause === true && isError && depth < 4) {
|
|
847
|
+
const cause = error.cause;
|
|
848
|
+
if (cause !== void 0 && cause !== null) {
|
|
849
|
+
report.cause = describeErrorAt(cause, void 0, options, depth + 1);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
return report;
|
|
853
|
+
}
|
|
854
|
+
function safeStringify(value) {
|
|
855
|
+
if (typeof value === "string") return value;
|
|
856
|
+
if (value === null) return "null";
|
|
857
|
+
if (value === void 0) return "undefined";
|
|
858
|
+
const t = typeof value;
|
|
859
|
+
if (t === "number" || t === "boolean" || t === "bigint" || t === "symbol") {
|
|
860
|
+
return String(value);
|
|
861
|
+
}
|
|
862
|
+
const ctor = t === "object" && value !== null ? value.constructor?.name ?? "Object" : t;
|
|
863
|
+
return `[non-Error ${ctor}]`;
|
|
864
|
+
}
|
|
865
|
+
function describeError(error, context, options = {}) {
|
|
866
|
+
return describeErrorAt(error, context, options, 0);
|
|
867
|
+
}
|
|
868
|
+
function reportError(sink, error, context, options = {}) {
|
|
869
|
+
const report = describeError(error, context, options);
|
|
870
|
+
reportDiagnostic(sink, "error", report.message, report.context);
|
|
871
|
+
return report;
|
|
872
|
+
}
|
|
641
873
|
|
|
642
874
|
// ../graph/src/graph-node.ts
|
|
643
875
|
var GraphNode = class _GraphNode {
|
|
@@ -808,6 +1040,7 @@ var ApplicationGraph = class {
|
|
|
808
1040
|
this.handlers.delete(`__overlay__${node.id}`);
|
|
809
1041
|
this.handlers.delete(`__component__${node.id}`);
|
|
810
1042
|
this.handlers.delete(`__transition__${node.id}`);
|
|
1043
|
+
this.handlers.delete(`__head__${node.id}`);
|
|
811
1044
|
}
|
|
812
1045
|
// ── Handler registry ──────────────────────────────────────────────────────
|
|
813
1046
|
registerHandler(key, fn) {
|
|
@@ -937,6 +1170,121 @@ function isTransitionConfig(value) {
|
|
|
937
1170
|
return typeof o["name"] === "string" || typeof o["enter"] === "string" || typeof o["enterActive"] === "string" || typeof o["enterFrom"] === "string" || typeof o["leave"] === "string" || typeof o["leaveActive"] === "string" || typeof o["leaveFrom"] === "string";
|
|
938
1171
|
}
|
|
939
1172
|
|
|
1173
|
+
// ../dsl/src/head.ts
|
|
1174
|
+
function metaDedupKey(m) {
|
|
1175
|
+
if (m.charset !== void 0) return "meta:charset";
|
|
1176
|
+
if (m.name !== void 0) return `meta:name=${m.name}`;
|
|
1177
|
+
if (m.property !== void 0) return `meta:property=${m.property}`;
|
|
1178
|
+
if (m.httpEquiv !== void 0) return `meta:http-equiv=${m.httpEquiv}`;
|
|
1179
|
+
return void 0;
|
|
1180
|
+
}
|
|
1181
|
+
function metaAttrs(m) {
|
|
1182
|
+
const attrs = {};
|
|
1183
|
+
if (m.charset !== void 0) attrs["charset"] = m.charset;
|
|
1184
|
+
if (m.name !== void 0) attrs["name"] = m.name;
|
|
1185
|
+
if (m.property !== void 0) attrs["property"] = m.property;
|
|
1186
|
+
if (m.httpEquiv !== void 0) attrs["http-equiv"] = m.httpEquiv;
|
|
1187
|
+
if (m.content !== void 0) attrs["content"] = m.content;
|
|
1188
|
+
return attrs;
|
|
1189
|
+
}
|
|
1190
|
+
function linkAttrs(l) {
|
|
1191
|
+
const attrs = { rel: l.rel, href: l.href };
|
|
1192
|
+
if (l.sizes !== void 0) attrs["sizes"] = l.sizes;
|
|
1193
|
+
if (l.type !== void 0) attrs["type"] = l.type;
|
|
1194
|
+
if (l.media !== void 0) attrs["media"] = l.media;
|
|
1195
|
+
if (l.as !== void 0) attrs["as"] = l.as;
|
|
1196
|
+
if (l.crossorigin !== void 0) attrs["crossorigin"] = l.crossorigin;
|
|
1197
|
+
if (l.hreflang !== void 0) attrs["hreflang"] = l.hreflang;
|
|
1198
|
+
return attrs;
|
|
1199
|
+
}
|
|
1200
|
+
function resolveHead(config) {
|
|
1201
|
+
const entries = [];
|
|
1202
|
+
if (config.charset !== void 0) {
|
|
1203
|
+
entries.push({ tag: "meta", dedupKey: "meta:charset", attrs: { charset: config.charset } });
|
|
1204
|
+
}
|
|
1205
|
+
if (config.base !== void 0) {
|
|
1206
|
+
entries.push({ tag: "base", dedupKey: "base", attrs: { href: config.base } });
|
|
1207
|
+
}
|
|
1208
|
+
if (config.title !== void 0) {
|
|
1209
|
+
entries.push({ tag: "title", dedupKey: "title", attrs: {}, text: config.title });
|
|
1210
|
+
}
|
|
1211
|
+
if (config.description !== void 0) {
|
|
1212
|
+
entries.push({
|
|
1213
|
+
tag: "meta",
|
|
1214
|
+
dedupKey: "meta:name=description",
|
|
1215
|
+
attrs: { name: "description", content: config.description }
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
if (config.canonical !== void 0) {
|
|
1219
|
+
entries.push({
|
|
1220
|
+
tag: "link",
|
|
1221
|
+
dedupKey: "link:rel=canonical",
|
|
1222
|
+
attrs: { rel: "canonical", href: config.canonical }
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
if (config.robots !== void 0) {
|
|
1226
|
+
entries.push({
|
|
1227
|
+
tag: "meta",
|
|
1228
|
+
dedupKey: "meta:name=robots",
|
|
1229
|
+
attrs: { name: "robots", content: config.robots }
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
if (config.themeColor !== void 0) {
|
|
1233
|
+
entries.push({
|
|
1234
|
+
tag: "meta",
|
|
1235
|
+
dedupKey: "meta:name=theme-color",
|
|
1236
|
+
attrs: { name: "theme-color", content: config.themeColor }
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
if (config.viewport !== void 0) {
|
|
1240
|
+
entries.push({
|
|
1241
|
+
tag: "meta",
|
|
1242
|
+
dedupKey: "meta:name=viewport",
|
|
1243
|
+
attrs: { name: "viewport", content: config.viewport }
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
if (config.favicon !== void 0) {
|
|
1247
|
+
const l = typeof config.favicon === "string" ? { rel: "icon", href: config.favicon } : config.favicon;
|
|
1248
|
+
entries.push({ tag: "link", dedupKey: `link:rel=${l.rel}`, attrs: linkAttrs(l) });
|
|
1249
|
+
}
|
|
1250
|
+
if (config.openGraph !== void 0) {
|
|
1251
|
+
for (const key of Object.keys(config.openGraph)) {
|
|
1252
|
+
const property = `og:${key}`;
|
|
1253
|
+
entries.push({
|
|
1254
|
+
tag: "meta",
|
|
1255
|
+
dedupKey: `meta:property=${property}`,
|
|
1256
|
+
attrs: { property, content: config.openGraph[key] }
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
if (config.twitter !== void 0) {
|
|
1261
|
+
for (const key of Object.keys(config.twitter)) {
|
|
1262
|
+
const name = `twitter:${key}`;
|
|
1263
|
+
entries.push({
|
|
1264
|
+
tag: "meta",
|
|
1265
|
+
dedupKey: `meta:name=${name}`,
|
|
1266
|
+
attrs: { name, content: config.twitter[key] }
|
|
1267
|
+
});
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
if (config.meta !== void 0) {
|
|
1271
|
+
for (const m of config.meta) {
|
|
1272
|
+
const key = metaDedupKey(m);
|
|
1273
|
+
if (key === void 0) continue;
|
|
1274
|
+
entries.push({ tag: "meta", dedupKey: key, attrs: metaAttrs(m) });
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
if (config.link !== void 0) {
|
|
1278
|
+
for (const l of config.link) {
|
|
1279
|
+
entries.push({ tag: "link", dedupKey: `link:rel=${l.rel}:href=${l.href}`, attrs: linkAttrs(l) });
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
return { entries };
|
|
1283
|
+
}
|
|
1284
|
+
function isHeadContribution(value) {
|
|
1285
|
+
return value !== null && typeof value === "object" && Array.isArray(value["entries"]);
|
|
1286
|
+
}
|
|
1287
|
+
|
|
940
1288
|
// ../dsl/src/builders.ts
|
|
941
1289
|
function isSignal(v) {
|
|
942
1290
|
return v !== null && typeof v === "object" && typeof v["get"] === "function" && typeof v["subscribe"] === "function";
|
|
@@ -1318,8 +1666,14 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
1318
1666
|
this.container(id, (c) => {
|
|
1319
1667
|
c.when(
|
|
1320
1668
|
hasError,
|
|
1321
|
-
// Error state → fallback.
|
|
1322
|
-
|
|
1669
|
+
// Error state → fallback. The fallback branch mounts exactly when the
|
|
1670
|
+
// boundary enters its error state, so this is also where the optional
|
|
1671
|
+
// `onError` reporting hook fires (observe-only; §6/§7).
|
|
1672
|
+
(fb) => {
|
|
1673
|
+
const currentError = readError();
|
|
1674
|
+
options.onError?.(currentError);
|
|
1675
|
+
options.fallback(fb, currentError, retry);
|
|
1676
|
+
},
|
|
1323
1677
|
// Healthy state → body, guarded against synchronous build throws.
|
|
1324
1678
|
(body) => {
|
|
1325
1679
|
try {
|
|
@@ -1331,6 +1685,24 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
1331
1685
|
);
|
|
1332
1686
|
}, { id });
|
|
1333
1687
|
}
|
|
1688
|
+
asyncBoundary(key, res, branches) {
|
|
1689
|
+
const isError = derived(() => res.status.get() === "error");
|
|
1690
|
+
const showSuccess = derived(
|
|
1691
|
+
() => res.status.get() !== "error" && res.data.get() !== void 0
|
|
1692
|
+
);
|
|
1693
|
+
const showLoading = derived(
|
|
1694
|
+
() => res.status.get() !== "error" && res.data.get() === void 0
|
|
1695
|
+
);
|
|
1696
|
+
const dataSignal = derived(() => res.data.get());
|
|
1697
|
+
const retry = () => {
|
|
1698
|
+
void res.refetch();
|
|
1699
|
+
};
|
|
1700
|
+
this.container(key, (c) => {
|
|
1701
|
+
c.when(isError, (fb) => branches.error?.(fb, res.error.peek(), retry));
|
|
1702
|
+
c.when(showSuccess, (sb) => branches.success(sb, dataSignal));
|
|
1703
|
+
c.when(showLoading, (lb) => branches.loading?.(lb));
|
|
1704
|
+
}, { key });
|
|
1705
|
+
}
|
|
1334
1706
|
// ── Portals & overlays ──────────────────────────────────────────────────────
|
|
1335
1707
|
portal(key, builder, options = {}) {
|
|
1336
1708
|
const node = this._graph.createNode("portal", {
|
|
@@ -1340,6 +1712,31 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
1340
1712
|
});
|
|
1341
1713
|
builder(new ContainerBuilderImpl(node, this._graph));
|
|
1342
1714
|
}
|
|
1715
|
+
/**
|
|
1716
|
+
* Declare document metadata (2.0 §1–§3). Creates a `'head'` node — a neutral,
|
|
1717
|
+
* empty inline anchor at this position (one node / one element, so positional
|
|
1718
|
+
* hydration is preserved) — and registers a `__head__<id>` descriptor holding
|
|
1719
|
+
* this call's normalized, dedup-keyed {@link resolveHead} contribution. The
|
|
1720
|
+
* renderer applies it to `document.head` on the browser (adopting server tags
|
|
1721
|
+
* on hydration, cleaning up on unmount / route change) and emits the active
|
|
1722
|
+
* graph's merged metadata as a string on the server (`renderHead`).
|
|
1723
|
+
*
|
|
1724
|
+
* Multiple `head()` nodes may be live at once (app default + route + component)
|
|
1725
|
+
* — the renderer merges them and, per dedup key, the last in document order
|
|
1726
|
+
* wins (see head.ts). No new render path: this reuses the same graph-node +
|
|
1727
|
+
* handler-registry convention as overlays/transitions/components.
|
|
1728
|
+
*/
|
|
1729
|
+
head(metadata) {
|
|
1730
|
+
const node = this._graph.createNode("head", {
|
|
1731
|
+
parent: this._node,
|
|
1732
|
+
props: { "data-streetui-head-anchor": "" }
|
|
1733
|
+
});
|
|
1734
|
+
const contribution = resolveHead(metadata);
|
|
1735
|
+
this._graph.registerHandler(
|
|
1736
|
+
`__head__${node.id}`,
|
|
1737
|
+
() => contribution
|
|
1738
|
+
);
|
|
1739
|
+
}
|
|
1343
1740
|
/**
|
|
1344
1741
|
* Shared assembly for every overlay kind: a `portal` node whose single child
|
|
1345
1742
|
* is a `when(open, panel)` conditional. The panel container carries the
|
|
@@ -1711,8 +2108,8 @@ var RuntimeNodeInstance = class {
|
|
|
1711
2108
|
this.children.push(instance);
|
|
1712
2109
|
}
|
|
1713
2110
|
/** Subscribe to a signal and register the unsubscribe for cleanup. */
|
|
1714
|
-
trackSignal(
|
|
1715
|
-
const unsub =
|
|
2111
|
+
trackSignal(signal3, handler) {
|
|
2112
|
+
const unsub = signal3.subscribe(handler);
|
|
1716
2113
|
this.cleanup.add(unsub);
|
|
1717
2114
|
}
|
|
1718
2115
|
/** Register an arbitrary cleanup function (e.g. DOM event removal). */
|
|
@@ -2083,6 +2480,9 @@ var BrowserDOMAdapter = class {
|
|
|
2083
2480
|
body() {
|
|
2084
2481
|
return document.body ?? null;
|
|
2085
2482
|
}
|
|
2483
|
+
head() {
|
|
2484
|
+
return document.head ?? null;
|
|
2485
|
+
}
|
|
2086
2486
|
activeElement() {
|
|
2087
2487
|
return document.activeElement ?? null;
|
|
2088
2488
|
}
|
|
@@ -2462,6 +2862,9 @@ var ServerDOMAdapter = class {
|
|
|
2462
2862
|
body() {
|
|
2463
2863
|
return null;
|
|
2464
2864
|
}
|
|
2865
|
+
head() {
|
|
2866
|
+
return null;
|
|
2867
|
+
}
|
|
2465
2868
|
activeElement() {
|
|
2466
2869
|
return null;
|
|
2467
2870
|
}
|
|
@@ -2844,7 +3247,13 @@ var TAG_MAP = {
|
|
|
2844
3247
|
// its children are relocated to a document.body container on the browser
|
|
2845
3248
|
// (see the portal branch in mount.ts). On the server (no body) it renders
|
|
2846
3249
|
// inline, so the anchor tag is what SSR/hydration positionally match on.
|
|
2847
|
-
portal: "div"
|
|
3250
|
+
portal: "div",
|
|
3251
|
+
// A `head()` node renders as a neutral, empty inline anchor <div> at its
|
|
3252
|
+
// declaration site (like a portal anchor). Its actual contribution — title/
|
|
3253
|
+
// meta/link/etc. — is applied to `document.head` by `wireHeadBehavior` on the
|
|
3254
|
+
// browser, and emitted separately by `renderHead()` on the server. Keeping a
|
|
3255
|
+
// one-node/one-element anchor preserves positional hydration.
|
|
3256
|
+
head: "div"
|
|
2848
3257
|
};
|
|
2849
3258
|
function resolveTag(type) {
|
|
2850
3259
|
return TAG_MAP[type] ?? "div";
|
|
@@ -3300,6 +3709,184 @@ var TransitionController = class {
|
|
|
3300
3709
|
}
|
|
3301
3710
|
};
|
|
3302
3711
|
|
|
3712
|
+
// ../renderer/src/head.ts
|
|
3713
|
+
var HEAD_MARKER = "data-streetui-head";
|
|
3714
|
+
var HEAD_KEY = "data-streetui-head-key";
|
|
3715
|
+
function isSignalLike(v) {
|
|
3716
|
+
return v !== null && typeof v === "object" && typeof v["subscribe"] === "function" && typeof v["peek"] === "function";
|
|
3717
|
+
}
|
|
3718
|
+
function readValue(v) {
|
|
3719
|
+
if (isSignalLike(v)) return String(v.peek() ?? "");
|
|
3720
|
+
return String(v ?? "");
|
|
3721
|
+
}
|
|
3722
|
+
function resolveEntry(entry) {
|
|
3723
|
+
const attrs = {};
|
|
3724
|
+
for (const key of Object.keys(entry.attrs)) {
|
|
3725
|
+
attrs[key] = readValue(entry.attrs[key]);
|
|
3726
|
+
}
|
|
3727
|
+
const resolved = { tag: entry.tag, attrs };
|
|
3728
|
+
if (entry.tag === "title") {
|
|
3729
|
+
return { ...resolved, text: readValue(entry.text) };
|
|
3730
|
+
}
|
|
3731
|
+
return resolved;
|
|
3732
|
+
}
|
|
3733
|
+
var HeadManager = class {
|
|
3734
|
+
_dom;
|
|
3735
|
+
_head;
|
|
3736
|
+
_contributions = /* @__PURE__ */ new Map();
|
|
3737
|
+
_applied = /* @__PURE__ */ new Map();
|
|
3738
|
+
_order = 0;
|
|
3739
|
+
_adopted = false;
|
|
3740
|
+
constructor(dom, head) {
|
|
3741
|
+
this._dom = dom;
|
|
3742
|
+
this._head = head;
|
|
3743
|
+
}
|
|
3744
|
+
/** Register (or replace) a node's contribution and re-apply the merged result. */
|
|
3745
|
+
register(nodeId, entries) {
|
|
3746
|
+
this._contributions.set(nodeId, { order: this._order++, entries });
|
|
3747
|
+
this.apply();
|
|
3748
|
+
}
|
|
3749
|
+
/** Withdraw a node's contribution (unmount / route change) and re-apply. */
|
|
3750
|
+
unregister(nodeId) {
|
|
3751
|
+
if (this._contributions.delete(nodeId)) this.apply();
|
|
3752
|
+
}
|
|
3753
|
+
/** Recompute the merged head and patch `document.head` to match. */
|
|
3754
|
+
apply() {
|
|
3755
|
+
if (!this._adopted) {
|
|
3756
|
+
this._adoptServerTags();
|
|
3757
|
+
this._adopted = true;
|
|
3758
|
+
}
|
|
3759
|
+
const ordered = [...this._contributions.values()].sort((a, b) => a.order - b.order);
|
|
3760
|
+
const merged = /* @__PURE__ */ new Map();
|
|
3761
|
+
for (const contribution of ordered) {
|
|
3762
|
+
for (const entry of contribution.entries) {
|
|
3763
|
+
merged.set(entry.dedupKey, resolveEntry(entry));
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
for (const [key, desired] of merged) {
|
|
3767
|
+
const existing = this._applied.get(key);
|
|
3768
|
+
if (existing !== void 0 && existing.tag === desired.tag) {
|
|
3769
|
+
this._reconcileAttrs(existing, desired);
|
|
3770
|
+
} else {
|
|
3771
|
+
if (existing !== void 0) {
|
|
3772
|
+
this._dom.removeChild(this._head, existing.el);
|
|
3773
|
+
this._applied.delete(key);
|
|
3774
|
+
}
|
|
3775
|
+
const el = this._createTag(key, desired);
|
|
3776
|
+
this._dom.appendChild(this._head, el);
|
|
3777
|
+
this._applied.set(key, { el, attrKeys: new Set(Object.keys(desired.attrs)), tag: desired.tag });
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
for (const [key, record] of [...this._applied]) {
|
|
3781
|
+
if (!merged.has(key)) {
|
|
3782
|
+
this._dom.removeChild(this._head, record.el);
|
|
3783
|
+
this._applied.delete(key);
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
_createTag(key, desired) {
|
|
3788
|
+
const el = this._dom.createElement(desired.tag);
|
|
3789
|
+
this._dom.setAttribute(el, HEAD_MARKER, "");
|
|
3790
|
+
this._dom.setAttribute(el, HEAD_KEY, key);
|
|
3791
|
+
for (const attr of Object.keys(desired.attrs)) {
|
|
3792
|
+
this._dom.setAttribute(el, attr, desired.attrs[attr]);
|
|
3793
|
+
}
|
|
3794
|
+
if (desired.tag === "title") this._dom.setTextContent(el, desired.text ?? "");
|
|
3795
|
+
return el;
|
|
3796
|
+
}
|
|
3797
|
+
_reconcileAttrs(record, desired) {
|
|
3798
|
+
const nextKeys = new Set(Object.keys(desired.attrs));
|
|
3799
|
+
for (const attr of record.attrKeys) {
|
|
3800
|
+
if (!nextKeys.has(attr)) this._dom.removeAttribute(record.el, attr);
|
|
3801
|
+
}
|
|
3802
|
+
for (const attr of nextKeys) {
|
|
3803
|
+
this._dom.setAttribute(record.el, attr, desired.attrs[attr]);
|
|
3804
|
+
}
|
|
3805
|
+
if (desired.tag === "title") this._dom.setTextContent(record.el, desired.text ?? "");
|
|
3806
|
+
record.attrKeys = nextKeys;
|
|
3807
|
+
}
|
|
3808
|
+
/**
|
|
3809
|
+
* Seed `_applied` from server-emitted `[data-streetui-head-key]` tags already
|
|
3810
|
+
* in `document.head`. The subsequent diff reuses these elements when the
|
|
3811
|
+
* client desires the same key (no duplicate), rewrites them if the value
|
|
3812
|
+
* changed, or removes them if the client graph no longer wants them.
|
|
3813
|
+
*/
|
|
3814
|
+
_adoptServerTags() {
|
|
3815
|
+
for (const child of this._dom.childNodes(this._head)) {
|
|
3816
|
+
if (!this._dom.isElement(child)) continue;
|
|
3817
|
+
const el = child;
|
|
3818
|
+
const key = this._dom.getAttribute(el, HEAD_KEY);
|
|
3819
|
+
if (key === null) continue;
|
|
3820
|
+
this._applied.set(key, {
|
|
3821
|
+
el,
|
|
3822
|
+
attrKeys: new Set(this._attrNames(el)),
|
|
3823
|
+
tag: this._dom.tagName(el)
|
|
3824
|
+
});
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
/** The framework-managed attribute names currently on a server tag. */
|
|
3828
|
+
_attrNames(el) {
|
|
3829
|
+
const names = [];
|
|
3830
|
+
if (this._dom.getAttribute(el, HEAD_MARKER) !== null) names.push(HEAD_MARKER);
|
|
3831
|
+
if (this._dom.getAttribute(el, HEAD_KEY) !== null) names.push(HEAD_KEY);
|
|
3832
|
+
return names;
|
|
3833
|
+
}
|
|
3834
|
+
};
|
|
3835
|
+
function getHeadManager(ctx) {
|
|
3836
|
+
const head = ctx.dom.head();
|
|
3837
|
+
if (head === null) return null;
|
|
3838
|
+
const mutable = ctx;
|
|
3839
|
+
if (mutable.head === void 0) mutable.head = new HeadManager(ctx.dom, head);
|
|
3840
|
+
return mutable.head;
|
|
3841
|
+
}
|
|
3842
|
+
function wireHeadBehavior(ctx, graphNode, instance) {
|
|
3843
|
+
const manager = getHeadManager(ctx);
|
|
3844
|
+
if (manager === null) return;
|
|
3845
|
+
const descFn = ctx.graph.getHandler(`__head__${graphNode.id}`);
|
|
3846
|
+
if (descFn === void 0) return;
|
|
3847
|
+
const contribution = descFn();
|
|
3848
|
+
const nodeId = graphNode.id;
|
|
3849
|
+
manager.register(nodeId, contribution.entries);
|
|
3850
|
+
for (const entry of contribution.entries) {
|
|
3851
|
+
for (const attrKey of Object.keys(entry.attrs)) {
|
|
3852
|
+
const v = entry.attrs[attrKey];
|
|
3853
|
+
if (isSignalLike(v)) {
|
|
3854
|
+
instance.trackCleanup(v.subscribe(() => manager.apply()));
|
|
3855
|
+
}
|
|
3856
|
+
}
|
|
3857
|
+
if (isSignalLike(entry.text)) {
|
|
3858
|
+
instance.trackCleanup(entry.text.subscribe(() => manager.apply()));
|
|
3859
|
+
}
|
|
3860
|
+
}
|
|
3861
|
+
instance.trackCleanup(() => manager.unregister(nodeId));
|
|
3862
|
+
}
|
|
3863
|
+
function renderHead(compiled) {
|
|
3864
|
+
const graph = compiled.graph;
|
|
3865
|
+
const merged = /* @__PURE__ */ new Map();
|
|
3866
|
+
graph.walk((node) => {
|
|
3867
|
+
if (node.type !== "head") return;
|
|
3868
|
+
const descFn = graph.getHandler(`__head__${node.id}`);
|
|
3869
|
+
if (descFn === void 0) return;
|
|
3870
|
+
for (const entry of descFn().entries) {
|
|
3871
|
+
merged.set(entry.dedupKey, resolveEntry(entry));
|
|
3872
|
+
}
|
|
3873
|
+
});
|
|
3874
|
+
if (merged.size === 0) return "";
|
|
3875
|
+
const dom = new ServerDOMAdapter();
|
|
3876
|
+
let out = "";
|
|
3877
|
+
for (const [key, desired] of merged) {
|
|
3878
|
+
const el = dom.createElement(desired.tag);
|
|
3879
|
+
dom.setAttribute(el, HEAD_MARKER, "");
|
|
3880
|
+
dom.setAttribute(el, HEAD_KEY, key);
|
|
3881
|
+
for (const attr of Object.keys(desired.attrs)) {
|
|
3882
|
+
dom.setAttribute(el, attr, desired.attrs[attr]);
|
|
3883
|
+
}
|
|
3884
|
+
if (desired.tag === "title") dom.setTextContent(el, desired.text ?? "");
|
|
3885
|
+
out += dom.serializeOuter(el);
|
|
3886
|
+
}
|
|
3887
|
+
return out;
|
|
3888
|
+
}
|
|
3889
|
+
|
|
3303
3890
|
// ../renderer/src/mount.ts
|
|
3304
3891
|
var SKIP_PROP_KEYS = /* @__PURE__ */ new Set([
|
|
3305
3892
|
"text",
|
|
@@ -3422,6 +4009,9 @@ function mountNode(ctx, graphNode, parentDom) {
|
|
|
3422
4009
|
const instance2 = new NodeInstance(graphNode, el2);
|
|
3423
4010
|
ctx.instances.set(graphNode.id, instance2);
|
|
3424
4011
|
wireEvents(dom, graph, graphNode, el2, instance2);
|
|
4012
|
+
if (graphNode.stateRefs.length !== 0) {
|
|
4013
|
+
wireSignalBindings(ctx, graphNode, instance2, linkUpdate(dom, el2));
|
|
4014
|
+
}
|
|
3425
4015
|
dom.appendChild(parentDom, el2);
|
|
3426
4016
|
return instance2;
|
|
3427
4017
|
}
|
|
@@ -3477,6 +4067,16 @@ function mountNode(ctx, graphNode, parentDom) {
|
|
|
3477
4067
|
wireOverlayBehavior(ctx, graphNode, instance2, target);
|
|
3478
4068
|
return instance2;
|
|
3479
4069
|
}
|
|
4070
|
+
if (graphNode.type === "head") {
|
|
4071
|
+
const anchor = dom.createElement(resolveTag("head"));
|
|
4072
|
+
dom.setAttribute(anchor, "data-streetui-head-anchor", "");
|
|
4073
|
+
applyNodeProps(ctx, graphNode, anchor);
|
|
4074
|
+
const instance2 = new NodeInstance(graphNode, anchor);
|
|
4075
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
4076
|
+
dom.appendChild(parentDom, anchor);
|
|
4077
|
+
wireHeadBehavior(ctx, graphNode, instance2);
|
|
4078
|
+
return instance2;
|
|
4079
|
+
}
|
|
3480
4080
|
const tag = resolveTag(graphNode.type);
|
|
3481
4081
|
const el = dom.createElement(tag);
|
|
3482
4082
|
applyNodeProps(ctx, graphNode, el);
|
|
@@ -3541,6 +4141,17 @@ function buttonUpdate(dom, el) {
|
|
|
3541
4141
|
}
|
|
3542
4142
|
};
|
|
3543
4143
|
}
|
|
4144
|
+
function linkUpdate(dom, el) {
|
|
4145
|
+
return (propKey, value) => {
|
|
4146
|
+
if (propKey === "label") {
|
|
4147
|
+
dom.setTextContent(el, String(value ?? ""));
|
|
4148
|
+
} else if (propKey === "href") {
|
|
4149
|
+
dom.setAttribute(el, "href", String(value ?? ""));
|
|
4150
|
+
} else {
|
|
4151
|
+
applyProp(dom, el, propKey, value);
|
|
4152
|
+
}
|
|
4153
|
+
};
|
|
4154
|
+
}
|
|
3544
4155
|
function applyNodeProps(ctx, graphNode, el) {
|
|
3545
4156
|
const props = graphNode.props;
|
|
3546
4157
|
for (const key in props) {
|
|
@@ -3775,7 +4386,12 @@ function hydrateNode(ctx, graphNode, domNode, path) {
|
|
|
3775
4386
|
case "link": {
|
|
3776
4387
|
const instance = new NodeInstance(graphNode, domNode);
|
|
3777
4388
|
ctx.instances.set(graphNode.id, instance);
|
|
3778
|
-
if (graphNode.type === "link")
|
|
4389
|
+
if (graphNode.type === "link") {
|
|
4390
|
+
wireEvents(dom, graph, graphNode, domNode, instance);
|
|
4391
|
+
if (graphNode.stateRefs.length !== 0) {
|
|
4392
|
+
wireSignalBindings(ctx, graphNode, instance, linkUpdate(dom, domNode));
|
|
4393
|
+
}
|
|
4394
|
+
}
|
|
3779
4395
|
return instance;
|
|
3780
4396
|
}
|
|
3781
4397
|
case "reactive-list":
|
|
@@ -3805,6 +4421,12 @@ function hydrateNode(ctx, graphNode, domNode, path) {
|
|
|
3805
4421
|
wireOverlayBehavior(ctx, graphNode, instance, target);
|
|
3806
4422
|
return instance;
|
|
3807
4423
|
}
|
|
4424
|
+
case "head": {
|
|
4425
|
+
const instance = new NodeInstance(graphNode, domNode);
|
|
4426
|
+
ctx.instances.set(graphNode.id, instance);
|
|
4427
|
+
wireHeadBehavior(ctx, graphNode, instance);
|
|
4428
|
+
return instance;
|
|
4429
|
+
}
|
|
3808
4430
|
default: {
|
|
3809
4431
|
const instance = new NodeInstance(graphNode, domNode);
|
|
3810
4432
|
ctx.instances.set(graphNode.id, instance);
|
|
@@ -4051,7 +4673,8 @@ function analyzeGraph(graph) {
|
|
|
4051
4673
|
const isConditional = node.type === "conditional";
|
|
4052
4674
|
const isPortal = node.type === "portal";
|
|
4053
4675
|
const isComponent = node.type === "component";
|
|
4054
|
-
const
|
|
4676
|
+
const isHead = node.type === "head";
|
|
4677
|
+
const isStatic = node.stateRefs.length === 0 && !hasEvents && !isList && !isConditional && !isPortal && !isComponent && !isHead;
|
|
4055
4678
|
const isStaticSubtree = isStatic && allChildrenStatic;
|
|
4056
4679
|
nodes.set(node.id, {
|
|
4057
4680
|
isStatic,
|
|
@@ -5113,11 +5736,22 @@ function capture(compiled, sources, options) {
|
|
|
5113
5736
|
snapshot: app.perf,
|
|
5114
5737
|
diagnostics: diagnosePerformance(compiled, options.perfThresholds)
|
|
5115
5738
|
};
|
|
5739
|
+
const components = inspectComponents(compiled.graph);
|
|
5740
|
+
const interactions = inspectInteractions(compiled.graph);
|
|
5741
|
+
const diagnostics = {
|
|
5742
|
+
errors: app.diagnostics.errors,
|
|
5743
|
+
warnings: app.diagnostics.warnings,
|
|
5744
|
+
messages: app.diagnostics.messages
|
|
5745
|
+
};
|
|
5116
5746
|
const snapshot = {
|
|
5117
5747
|
application,
|
|
5118
5748
|
graph: app.graph,
|
|
5119
5749
|
signals,
|
|
5120
5750
|
performance,
|
|
5751
|
+
components,
|
|
5752
|
+
overlays: interactions.overlays,
|
|
5753
|
+
transitions: interactions.transitions,
|
|
5754
|
+
diagnostics,
|
|
5121
5755
|
...sources.router !== void 0 ? { router: inspectRouter(sources.router) } : {},
|
|
5122
5756
|
...sources.resources !== void 0 ? { resources: mapInspect(sources.resources, (r) => inspectResource(r)) } : {},
|
|
5123
5757
|
...sources.forms !== void 0 ? { forms: mapInspect(sources.forms, (f) => inspectForm(f)) } : {},
|
|
@@ -5158,6 +5792,25 @@ function formatSnapshot(s) {
|
|
|
5158
5792
|
for (const [label, sig] of Object.entries(s.signals.live)) {
|
|
5159
5793
|
lines.push(` ${label} [${sig.kind}] = ${format(sig.value)} \xB7 observers ${sig.observerCount ?? "?"}`);
|
|
5160
5794
|
}
|
|
5795
|
+
if (s.components.length > 0) {
|
|
5796
|
+
lines.push(`Components: ${s.components.length}`);
|
|
5797
|
+
for (const c of s.components) {
|
|
5798
|
+
lines.push(` ${" ".repeat(c.depth)}${c.name}${c.key !== void 0 ? ` (#${c.key})` : ""} \xB7 children ${c.childCount}`);
|
|
5799
|
+
}
|
|
5800
|
+
}
|
|
5801
|
+
if (s.overlays.length > 0) {
|
|
5802
|
+
lines.push(`Overlays: ${s.overlays.length}`);
|
|
5803
|
+
for (const o of s.overlays) {
|
|
5804
|
+
const kind = o.modal ? "modal" : o.menu ? "menu" : o.takesFocus ? "focusable" : "non-modal";
|
|
5805
|
+
lines.push(` ${o.key ?? o.id} [${kind}] ${o.open ? "open" : "closed"}`);
|
|
5806
|
+
}
|
|
5807
|
+
}
|
|
5808
|
+
if (s.transitions.length > 0) {
|
|
5809
|
+
lines.push(`Transitions: ${s.transitions.length}`);
|
|
5810
|
+
for (const t of s.transitions) {
|
|
5811
|
+
lines.push(` ${t.key ?? t.id} on <${t.nodeType}> \xB7 ${t.duration}ms${t.appear ? " \xB7 appear" : ""}`);
|
|
5812
|
+
}
|
|
5813
|
+
}
|
|
5161
5814
|
if (s.router !== void 0) {
|
|
5162
5815
|
lines.push(`Router: ${s.router.path} (${s.router.pattern})${s.router.isFallback ? " [fallback]" : ""}`);
|
|
5163
5816
|
}
|
|
@@ -5191,6 +5844,12 @@ function formatSnapshot(s) {
|
|
|
5191
5844
|
for (const d of s.performance.diagnostics) {
|
|
5192
5845
|
lines.push(` ${d.code}: ${d.message}`);
|
|
5193
5846
|
}
|
|
5847
|
+
lines.push(
|
|
5848
|
+
`Diagnostics: ${s.diagnostics.errors} error(s), ${s.diagnostics.warnings} warning(s)`
|
|
5849
|
+
);
|
|
5850
|
+
for (const m of s.diagnostics.messages) {
|
|
5851
|
+
lines.push(` ${m}`);
|
|
5852
|
+
}
|
|
5194
5853
|
return lines.join("\n");
|
|
5195
5854
|
}
|
|
5196
5855
|
function format(value) {
|
|
@@ -5206,6 +5865,176 @@ function format(value) {
|
|
|
5206
5865
|
return String(value);
|
|
5207
5866
|
}
|
|
5208
5867
|
|
|
5868
|
+
// ../devtools/src/view.ts
|
|
5869
|
+
function escapeHtml(value) {
|
|
5870
|
+
const s = typeof value === "string" ? value : stringifyValue(value);
|
|
5871
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
5872
|
+
}
|
|
5873
|
+
function stringifyValue(value) {
|
|
5874
|
+
if (value === null || value === void 0) return String(value);
|
|
5875
|
+
if (typeof value === "object") {
|
|
5876
|
+
try {
|
|
5877
|
+
return JSON.stringify(value);
|
|
5878
|
+
} catch {
|
|
5879
|
+
return "[object]";
|
|
5880
|
+
}
|
|
5881
|
+
}
|
|
5882
|
+
return String(value);
|
|
5883
|
+
}
|
|
5884
|
+
function section(title, count, body) {
|
|
5885
|
+
const badge = count === void 0 ? "" : ` <span class="st-count">${count}</span>`;
|
|
5886
|
+
return `<section class="st-panel"><h2>${escapeHtml(title)}${badge}</h2>${body}</section>`;
|
|
5887
|
+
}
|
|
5888
|
+
function ul(items) {
|
|
5889
|
+
if (items.length === 0) return '<p class="st-empty">(none)</p>';
|
|
5890
|
+
return `<ul>${items.map((i) => `<li>${i}</li>`).join("")}</ul>`;
|
|
5891
|
+
}
|
|
5892
|
+
function renderDevToolsHTML(s) {
|
|
5893
|
+
const app = s.application;
|
|
5894
|
+
const parts = [];
|
|
5895
|
+
parts.push(
|
|
5896
|
+
section(
|
|
5897
|
+
"Application",
|
|
5898
|
+
void 0,
|
|
5899
|
+
`<p>${escapeHtml(app.identity.name)} <span class="st-dim">v${escapeHtml(app.identity.version)}</span></p><p class="st-dim">${app.nodeCount} nodes \xB7 depth ${app.maxDepth} \xB7 ${app.pages.length} page(s) \xB7 ${app.signalCount} signals \xB7 ${app.eventHandlers} handlers \xB7 ${app.stateBindings} bindings</p>`
|
|
5900
|
+
)
|
|
5901
|
+
);
|
|
5902
|
+
parts.push(
|
|
5903
|
+
section(
|
|
5904
|
+
"Components",
|
|
5905
|
+
s.components.length,
|
|
5906
|
+
ul(
|
|
5907
|
+
s.components.map(
|
|
5908
|
+
(c) => `<span class="st-depth" style="--d:${c.depth}"></span><code>${escapeHtml(c.name)}</code>` + (c.key !== void 0 ? ` <span class="st-key">#${escapeHtml(c.key)}</span>` : "") + ` <span class="st-dim">${c.childCount} child(ren)</span>`
|
|
5909
|
+
)
|
|
5910
|
+
)
|
|
5911
|
+
)
|
|
5912
|
+
);
|
|
5913
|
+
parts.push(section("Graph", void 0, `<pre class="st-tree">${escapeHtml(renderNodeTree(s.graph))}</pre>`));
|
|
5914
|
+
parts.push(
|
|
5915
|
+
section(
|
|
5916
|
+
"Signals",
|
|
5917
|
+
s.signals.boundSignalIds.length,
|
|
5918
|
+
`<p class="st-dim">${s.signals.boundSignalIds.length} bound in graph \xB7 effects shown as observer counts (no global effect registry)</p>` + ul(
|
|
5919
|
+
Object.entries(s.signals.live).map(
|
|
5920
|
+
([label, sig]) => `<code>${escapeHtml(label)}</code> <span class="st-key">[${escapeHtml(sig.kind)}]</span> = <code>${escapeHtml(sig.value)}</code> <span class="st-dim">observers ${escapeHtml(sig.observerCount ?? "?")}</span>`
|
|
5921
|
+
)
|
|
5922
|
+
)
|
|
5923
|
+
)
|
|
5924
|
+
);
|
|
5925
|
+
if (s.router !== void 0) {
|
|
5926
|
+
parts.push(
|
|
5927
|
+
section(
|
|
5928
|
+
"Router",
|
|
5929
|
+
void 0,
|
|
5930
|
+
`<p><code>${escapeHtml(s.router.path)}</code> <span class="st-dim">(${escapeHtml(s.router.pattern)})${s.router.isFallback ? " \xB7 fallback" : ""}</span></p>`
|
|
5931
|
+
)
|
|
5932
|
+
);
|
|
5933
|
+
}
|
|
5934
|
+
if (s.resources !== void 0) {
|
|
5935
|
+
parts.push(
|
|
5936
|
+
section(
|
|
5937
|
+
"Resources",
|
|
5938
|
+
Object.keys(s.resources).length,
|
|
5939
|
+
ul(
|
|
5940
|
+
Object.entries(s.resources).map(
|
|
5941
|
+
([label, r]) => `<code>${escapeHtml(label)}</code>: ${escapeHtml(r.status)}` + (r.loading ? ' <span class="st-dim">(loading)</span>' : "") + (r.hasError ? ` <span class="st-err">!${escapeHtml(r.errorName)}</span>` : "")
|
|
5942
|
+
)
|
|
5943
|
+
)
|
|
5944
|
+
)
|
|
5945
|
+
);
|
|
5946
|
+
}
|
|
5947
|
+
parts.push(
|
|
5948
|
+
section(
|
|
5949
|
+
"Overlays",
|
|
5950
|
+
s.overlays.length,
|
|
5951
|
+
ul(
|
|
5952
|
+
s.overlays.map((o) => {
|
|
5953
|
+
const kind = o.modal ? "modal" : o.menu ? "menu" : o.takesFocus ? "focusable" : "non-modal";
|
|
5954
|
+
return `<code>${escapeHtml(o.key ?? o.id)}</code> <span class="st-key">[${kind}]</span> <span class="st-dim">${o.open ? "open" : "closed"}${o.closeOnEscape ? " \xB7 esc" : ""}${o.restoreFocus ? " \xB7 restore" : ""}</span>`;
|
|
5955
|
+
})
|
|
5956
|
+
)
|
|
5957
|
+
)
|
|
5958
|
+
);
|
|
5959
|
+
parts.push(
|
|
5960
|
+
section(
|
|
5961
|
+
"Transitions",
|
|
5962
|
+
s.transitions.length,
|
|
5963
|
+
ul(
|
|
5964
|
+
s.transitions.map(
|
|
5965
|
+
(t) => `<code>${escapeHtml(t.key ?? t.id)}</code> on <code><${escapeHtml(t.nodeType)}></code> <span class="st-dim">${t.duration}ms${t.appear ? " \xB7 appear" : ""}</span>`
|
|
5966
|
+
)
|
|
5967
|
+
)
|
|
5968
|
+
)
|
|
5969
|
+
);
|
|
5970
|
+
if (s.forms !== void 0) {
|
|
5971
|
+
parts.push(
|
|
5972
|
+
section(
|
|
5973
|
+
"Forms",
|
|
5974
|
+
Object.keys(s.forms).length,
|
|
5975
|
+
ul(
|
|
5976
|
+
Object.entries(s.forms).map(
|
|
5977
|
+
([label, f]) => `<code>${escapeHtml(label)}</code>: ${f.valid ? "valid" : "invalid"} \xB7 ${escapeHtml(f.status)} \xB7 ${f.fields.length} field(s)`
|
|
5978
|
+
)
|
|
5979
|
+
)
|
|
5980
|
+
)
|
|
5981
|
+
);
|
|
5982
|
+
}
|
|
5983
|
+
if (s.i18n !== void 0) {
|
|
5984
|
+
const missing = s.i18n.missingKeys;
|
|
5985
|
+
parts.push(
|
|
5986
|
+
section(
|
|
5987
|
+
"i18n",
|
|
5988
|
+
void 0,
|
|
5989
|
+
`<p><code>${escapeHtml(s.i18n.locale)}</code> of [${s.i18n.locales.map(escapeHtml).join(", ")}]${missing !== void 0 ? ` <span class="st-dim">\xB7 missing ${missing.length}</span>` : ""}</p>`
|
|
5990
|
+
)
|
|
5991
|
+
);
|
|
5992
|
+
}
|
|
5993
|
+
parts.push(
|
|
5994
|
+
section(
|
|
5995
|
+
"Performance",
|
|
5996
|
+
s.performance.diagnostics.length,
|
|
5997
|
+
`<p class="st-dim">Structural counts, not runtime timings \u2014 not a production profiler.</p>` + ul(s.performance.diagnostics.map((d) => `<code>${escapeHtml(d.code)}</code>: ${escapeHtml(d.message)}`))
|
|
5998
|
+
)
|
|
5999
|
+
);
|
|
6000
|
+
parts.push(
|
|
6001
|
+
section(
|
|
6002
|
+
"Diagnostics",
|
|
6003
|
+
s.diagnostics.errors + s.diagnostics.warnings,
|
|
6004
|
+
`<p class="st-dim">${s.diagnostics.errors} error(s) \xB7 ${s.diagnostics.warnings} warning(s)</p>` + ul(s.diagnostics.messages.map((m) => escapeHtml(m)))
|
|
6005
|
+
)
|
|
6006
|
+
);
|
|
6007
|
+
const title = `StreetUI DevTools \u2014 ${escapeHtml(app.identity.name)}`;
|
|
6008
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><title>${title}</title><style>${DEVTOOLS_CSS}</style></head><body class="st-devtools"><header class="st-header"><h1>${title} <span class="st-dim">v${escapeHtml(app.identity.version)}</span></h1></header><main>${parts.join("")}</main></body></html>`;
|
|
6009
|
+
}
|
|
6010
|
+
function renderNodeTree(node) {
|
|
6011
|
+
const lines = [];
|
|
6012
|
+
const walk = (n) => {
|
|
6013
|
+
const indent = " ".repeat(n.depth);
|
|
6014
|
+
const key = n.key !== void 0 ? ` #${n.key}` : "";
|
|
6015
|
+
lines.push(`${indent}<${n.type}${key}> ${n.id}`);
|
|
6016
|
+
for (const c of n.children) walk(c);
|
|
6017
|
+
};
|
|
6018
|
+
walk(node);
|
|
6019
|
+
return lines.join("\n");
|
|
6020
|
+
}
|
|
6021
|
+
var DEVTOOLS_CSS = [
|
|
6022
|
+
".st-devtools{font:13px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;margin:0;color:#e6e6e6;background:#1e1e28}",
|
|
6023
|
+
".st-header{padding:12px 16px;border-bottom:1px solid #333;background:#15151c}",
|
|
6024
|
+
".st-header h1{font-size:14px;margin:0}",
|
|
6025
|
+
"main{padding:8px 16px}",
|
|
6026
|
+
".st-panel{margin:12px 0;border:1px solid #2c2c38;border-radius:6px;overflow:hidden}",
|
|
6027
|
+
".st-panel h2{font-size:12px;text-transform:uppercase;letter-spacing:.04em;margin:0;padding:6px 10px;background:#23232e}",
|
|
6028
|
+
".st-panel ul{list-style:none;margin:0;padding:6px 10px}",
|
|
6029
|
+
".st-panel li{padding:1px 0}",
|
|
6030
|
+
".st-panel p{margin:6px 10px}",
|
|
6031
|
+
".st-count{background:#3a3a4a;border-radius:10px;padding:0 7px;font-size:11px;float:right}",
|
|
6032
|
+
".st-dim{color:#8a8a9a}.st-key{color:#7db4ff}.st-err{color:#ff8a8a}.st-empty{color:#6a6a7a}",
|
|
6033
|
+
".st-tree{margin:6px 10px;white-space:pre;overflow:auto;color:#c8c8d4}",
|
|
6034
|
+
".st-depth{display:inline-block}.st-depth{width:calc(var(--d,0)*12px)}",
|
|
6035
|
+
"code{color:#d7d7e0}"
|
|
6036
|
+
].join("");
|
|
6037
|
+
|
|
5209
6038
|
// src/config.ts
|
|
5210
6039
|
function defineConfig(config) {
|
|
5211
6040
|
return config;
|
|
@@ -5228,6 +6057,8 @@ export {
|
|
|
5228
6057
|
FOCUSABLE_SELECTOR,
|
|
5229
6058
|
FormBuilderImpl,
|
|
5230
6059
|
GraphNode,
|
|
6060
|
+
HeadManager,
|
|
6061
|
+
HttpError,
|
|
5231
6062
|
Lifecycle,
|
|
5232
6063
|
ListBuilderImpl,
|
|
5233
6064
|
NodeInstance,
|
|
@@ -5268,7 +6099,9 @@ export {
|
|
|
5268
6099
|
containFocus,
|
|
5269
6100
|
createAnnouncer,
|
|
5270
6101
|
createApplication,
|
|
6102
|
+
createAuthSession,
|
|
5271
6103
|
createBrowserHistory,
|
|
6104
|
+
createClient,
|
|
5272
6105
|
createContext,
|
|
5273
6106
|
createDevTools,
|
|
5274
6107
|
createForm,
|
|
@@ -5284,10 +6117,12 @@ export {
|
|
|
5284
6117
|
createStreetEvent,
|
|
5285
6118
|
defineConfig,
|
|
5286
6119
|
derived,
|
|
6120
|
+
describeError,
|
|
5287
6121
|
diagnosePerformance,
|
|
5288
6122
|
effect,
|
|
5289
6123
|
email,
|
|
5290
6124
|
environment,
|
|
6125
|
+
escapeHtml,
|
|
5291
6126
|
escapeHtmlAttr,
|
|
5292
6127
|
escapeHtmlText,
|
|
5293
6128
|
flushSync,
|
|
@@ -5319,7 +6154,9 @@ export {
|
|
|
5319
6154
|
interpolate,
|
|
5320
6155
|
isBatching,
|
|
5321
6156
|
isComponentDefinition,
|
|
6157
|
+
isHeadContribution,
|
|
5322
6158
|
isTransitionConfig,
|
|
6159
|
+
linkUpdate,
|
|
5323
6160
|
matchPattern,
|
|
5324
6161
|
matchRoutes,
|
|
5325
6162
|
maxLength,
|
|
@@ -5327,6 +6164,7 @@ export {
|
|
|
5327
6164
|
mountGraph,
|
|
5328
6165
|
mountNode,
|
|
5329
6166
|
mountRouter,
|
|
6167
|
+
mutation,
|
|
5330
6168
|
nextId,
|
|
5331
6169
|
nodeIdPrefix,
|
|
5332
6170
|
nodeTypeStats,
|
|
@@ -5343,10 +6181,14 @@ export {
|
|
|
5343
6181
|
readState,
|
|
5344
6182
|
reconcileChildren,
|
|
5345
6183
|
reconcileChildrenByPlan,
|
|
6184
|
+
renderDevToolsHTML,
|
|
6185
|
+
renderHead,
|
|
5346
6186
|
renderToString,
|
|
5347
6187
|
reportDiagnostic,
|
|
6188
|
+
reportError,
|
|
5348
6189
|
required,
|
|
5349
6190
|
resetIdCounter,
|
|
6191
|
+
resolveHead,
|
|
5350
6192
|
resolveTag,
|
|
5351
6193
|
resolveTransition,
|
|
5352
6194
|
resource,
|
|
@@ -5374,6 +6216,7 @@ export {
|
|
|
5374
6216
|
validateGraph,
|
|
5375
6217
|
wireComponentBehavior,
|
|
5376
6218
|
wireEvents,
|
|
6219
|
+
wireHeadBehavior,
|
|
5377
6220
|
wireOverlayBehavior,
|
|
5378
6221
|
wireReactiveList,
|
|
5379
6222
|
wireSignalBindings
|