@almadar/ui 5.158.0 → 5.159.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.
@@ -1,8 +1,8 @@
1
- import { createContext, useCallback, useState, useEffect, useMemo, useContext, useRef, useSyncExternalStore } from 'react';
1
+ import React, { createContext, useCallback, useState, useEffect, useMemo, useContext, useRef, useSyncExternalStore } from 'react';
2
2
  import { createLogger } from '@almadar/logger';
3
3
  import { EventBusContext, useTraitScopeChain } from '@almadar/ui/providers';
4
4
  export { useNavStack } from '@almadar/ui/providers';
5
- import { mergeEntityFrame } from '@almadar/core';
5
+ import { mergeEntityFrame, isRenderBindingMarker } from '@almadar/core';
6
6
  import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
7
7
 
8
8
  var log = createLogger("almadar:ui:orbital-history");
@@ -1018,6 +1018,88 @@ function useEmitEvent() {
1018
1018
  [eventBus]
1019
1019
  );
1020
1020
  }
1021
+ function expressionEqual(a, b) {
1022
+ if (Object.is(a, b)) return true;
1023
+ if (Array.isArray(a) && Array.isArray(b)) {
1024
+ if (a.length !== b.length) return false;
1025
+ for (let i = 0; i < a.length; i++) {
1026
+ if (!expressionEqual(a[i], b[i])) return false;
1027
+ }
1028
+ return true;
1029
+ }
1030
+ if (a !== null && b !== null && typeof a === "object" && typeof b === "object" && !Array.isArray(a) && !Array.isArray(b) && !(a instanceof Date) && !(b instanceof Date)) {
1031
+ const aKeys = Object.keys(a);
1032
+ const bKeys = Object.keys(b);
1033
+ if (aKeys.length !== bKeys.length) return false;
1034
+ for (const key of aKeys) {
1035
+ if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
1036
+ if (!expressionEqual(
1037
+ a[key],
1038
+ b[key]
1039
+ )) return false;
1040
+ }
1041
+ return true;
1042
+ }
1043
+ return false;
1044
+ }
1045
+ function isPlainSlotObject(value) {
1046
+ if (value === null || value === void 0 || typeof value !== "object") return false;
1047
+ if (Array.isArray(value)) return false;
1048
+ if (React.isValidElement(value)) return false;
1049
+ if (value instanceof Date) return false;
1050
+ if (isRenderBindingMarker(value)) return false;
1051
+ return true;
1052
+ }
1053
+ function shareValue(prev, next) {
1054
+ if (Object.is(prev, next)) return { value: prev, equal: true };
1055
+ const prevMarker = isRenderBindingMarker(prev) ? prev : void 0;
1056
+ const nextMarker = isRenderBindingMarker(next) ? next : void 0;
1057
+ if (prevMarker !== void 0 || nextMarker !== void 0) {
1058
+ if (prevMarker !== void 0 && nextMarker !== void 0 && expressionEqual(prevMarker.expression, nextMarker.expression)) {
1059
+ return { value: prev, equal: true };
1060
+ }
1061
+ return { value: next, equal: false };
1062
+ }
1063
+ if (prev instanceof Date || next instanceof Date) {
1064
+ return prev instanceof Date && next instanceof Date && prev.getTime() === next.getTime() ? { value: prev, equal: true } : { value: next, equal: false };
1065
+ }
1066
+ if (typeof prev === "function" || typeof next === "function") return { value: next, equal: false };
1067
+ if (React.isValidElement(prev) || React.isValidElement(next)) return { value: next, equal: false };
1068
+ if (Array.isArray(prev) && Array.isArray(next)) {
1069
+ let equal = prev.length === next.length;
1070
+ const out = new Array(next.length);
1071
+ for (let i = 0; i < next.length; i++) {
1072
+ const child = shareValue(prev[i], next[i]);
1073
+ out[i] = child.value;
1074
+ if (!child.equal) equal = false;
1075
+ }
1076
+ return equal ? { value: prev, equal: true } : { value: out, equal: false };
1077
+ }
1078
+ if (isPlainSlotObject(prev) && isPlainSlotObject(next)) {
1079
+ const prevKeys = Object.keys(prev);
1080
+ const nextKeys = Object.keys(next);
1081
+ let equal = prevKeys.length === nextKeys.length;
1082
+ const out = {};
1083
+ for (const key of nextKeys) {
1084
+ if (!Object.prototype.hasOwnProperty.call(prev, key)) {
1085
+ equal = false;
1086
+ out[key] = next[key];
1087
+ continue;
1088
+ }
1089
+ const child = shareValue(prev[key], next[key]);
1090
+ out[key] = child.value;
1091
+ if (!child.equal) equal = false;
1092
+ }
1093
+ return equal ? { value: prev, equal: true } : { value: out, equal: false };
1094
+ }
1095
+ return { value: next, equal: false };
1096
+ }
1097
+ function reconcileSlotProps(prev, next) {
1098
+ const result = shareValue(prev, next);
1099
+ return { value: result.value, equal: result.equal };
1100
+ }
1101
+
1102
+ // hooks/useUISlots.ts
1021
1103
  var log11 = createLogger("almadar:ui:ui-slots");
1022
1104
  var DEFAULT_SOURCE_KEY = "__default__";
1023
1105
  var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
@@ -1172,6 +1254,14 @@ function useUISlotManager() {
1172
1254
  });
1173
1255
  return prev;
1174
1256
  }
1257
+ if (existing && existing.priority === content.priority && existing.pattern === content.pattern && existing.animation === content.animation && existing.transitionEvent === content.transitionEvent && existing.fromState === content.fromState && existing.entity === content.entity && existing.nodeId === content.nodeId && existing.autoDismissAt === void 0 && content.autoDismissAt === void 0 && existing.onDismiss === void 0 === (content.onDismiss === void 0)) {
1258
+ const reconciled = reconcileSlotProps(existing.props, content.props);
1259
+ if (reconciled.equal) {
1260
+ log11.debug("slot:flush-bail", { slot: config.target, sourceKey, pattern: content.pattern });
1261
+ return prev;
1262
+ }
1263
+ content.props = reconciled.value;
1264
+ }
1175
1265
  const nextSources = {
1176
1266
  ...slotSources,
1177
1267
  [sourceKey]: content
@@ -1579,6 +1669,7 @@ var en_default = {
1579
1669
  "common.confirm": "Are you sure?",
1580
1670
  "common.create": "Create",
1581
1671
  "common.edit": "Edit",
1672
+ "common.title": "Title",
1582
1673
  "common.view": "View",
1583
1674
  "common.add": "Add",
1584
1675
  "common.remove": "Remove",
@@ -3,6 +3,8 @@
3
3
  var clsx = require('clsx');
4
4
  var tailwindMerge = require('tailwind-merge');
5
5
  var logger = require('@almadar/logger');
6
+ var react = require('react');
7
+ var ui = require('@almadar/runtime/ui');
6
8
  var core = require('@almadar/core');
7
9
 
8
10
  var __defProp = Object.defineProperty;
@@ -446,6 +448,64 @@ function clearTraits() {
446
448
  traits.clear();
447
449
  notifyListeners4();
448
450
  }
451
+
452
+ // lib/command-send-pump.ts
453
+ function createCommandSendPump() {
454
+ let tail = Promise.resolve();
455
+ return {
456
+ enqueue(job) {
457
+ const result = tail.then(job);
458
+ tail = result.then(
459
+ () => void 0,
460
+ () => void 0
461
+ );
462
+ return result;
463
+ }
464
+ };
465
+ }
466
+
467
+ // lib/tick-send-relay.ts
468
+ function createTickSendRelay(send) {
469
+ const lanes = /* @__PURE__ */ new Map();
470
+ const flush = (key, lane) => {
471
+ const next = lane.pending;
472
+ lane.pending = void 0;
473
+ if (next === void 0) {
474
+ lane.inFlight = false;
475
+ return;
476
+ }
477
+ lane.inFlight = true;
478
+ void send(key, next).catch(() => void 0).then(() => flush(key, lane));
479
+ };
480
+ return {
481
+ send(key, value) {
482
+ const lane = lanes.get(key) ?? { inFlight: false };
483
+ lanes.set(key, lane);
484
+ if (lane.inFlight) {
485
+ lane.pending = value;
486
+ return;
487
+ }
488
+ lane.pending = value;
489
+ flush(key, lane);
490
+ },
491
+ clear() {
492
+ for (const lane of lanes.values()) {
493
+ lane.pending = void 0;
494
+ }
495
+ }
496
+ };
497
+ }
498
+ function usePerfBuffer() {
499
+ return react.useSyncExternalStore(ui.perfStore.subscribe, ui.perfStore.getSnapshot, ui.perfStore.getSnapshot);
500
+ }
501
+ var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
502
+ ui.pushPerfEntry({
503
+ name: `profiler:${id}:${phase}`,
504
+ durationMs: actualDuration,
505
+ ts: commitTime,
506
+ detail: { baseDuration }
507
+ });
508
+ };
449
509
  var log2 = logger.createLogger("almadar:bridge");
450
510
  var MAX_TRANSITIONS = 500;
451
511
  function getState() {
@@ -2034,6 +2094,34 @@ var JAZARI_COLORS = {
2034
2094
  darkBg: "#1a1a2e"
2035
2095
  };
2036
2096
 
2097
+ Object.defineProperty(exports, "PERF_NAMESPACE", {
2098
+ enumerable: true,
2099
+ get: function () { return ui.PERF_NAMESPACE; }
2100
+ });
2101
+ Object.defineProperty(exports, "clearPerf", {
2102
+ enumerable: true,
2103
+ get: function () { return ui.clearPerf; }
2104
+ });
2105
+ Object.defineProperty(exports, "perfEnd", {
2106
+ enumerable: true,
2107
+ get: function () { return ui.perfEnd; }
2108
+ });
2109
+ Object.defineProperty(exports, "perfGauge", {
2110
+ enumerable: true,
2111
+ get: function () { return ui.perfGauge; }
2112
+ });
2113
+ Object.defineProperty(exports, "perfStart", {
2114
+ enumerable: true,
2115
+ get: function () { return ui.perfStart; }
2116
+ });
2117
+ Object.defineProperty(exports, "perfTime", {
2118
+ enumerable: true,
2119
+ get: function () { return ui.perfTime; }
2120
+ });
2121
+ Object.defineProperty(exports, "perfTimeAsync", {
2122
+ enumerable: true,
2123
+ get: function () { return ui.perfTimeAsync; }
2124
+ });
2037
2125
  exports.ApiError = ApiError;
2038
2126
  exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
2039
2127
  exports.JAZARI_COLORS = JAZARI_COLORS;
@@ -2053,6 +2141,8 @@ exports.clearVerification = clearVerification;
2053
2141
  exports.cn = cn;
2054
2142
  exports.compareCellValues = compareCellValues;
2055
2143
  exports.computeJazariLayout = computeJazariLayout;
2144
+ exports.createCommandSendPump = createCommandSendPump;
2145
+ exports.createTickSendRelay = createTickSendRelay;
2056
2146
  exports.debug = debug;
2057
2147
  exports.debugCollision = debugCollision;
2058
2148
  exports.debugError = debugError;
@@ -2115,6 +2205,7 @@ exports.parseContentSegments = parseContentSegments;
2115
2205
  exports.parseLessonSegments = parseLessonSegments;
2116
2206
  exports.parseMarkdownWithCodeBlocks = parseMarkdownWithCodeBlocks;
2117
2207
  exports.pipeIconPath = pipeIconPath;
2208
+ exports.profilerOnRender = profilerOnRender;
2118
2209
  exports.recordGuardEvaluation = recordGuardEvaluation;
2119
2210
  exports.recordServerResponse = recordServerResponse;
2120
2211
  exports.recordTransition = recordTransition;
@@ -2143,4 +2234,5 @@ exports.updateCheck = updateCheck;
2143
2234
  exports.updateGuardResult = updateGuardResult;
2144
2235
  exports.updateTickExecution = updateTickExecution;
2145
2236
  exports.updateTraitState = updateTraitState;
2237
+ exports.usePerfBuffer = usePerfBuffer;
2146
2238
  exports.waitForTransition = waitForTransition;
@@ -1,6 +1,8 @@
1
1
  export { C as ContentSegment, D as DEFAULT_CONFIG, a as DomEntityBox, b as DomLayoutData, c as DomOutputsBox, d as DomStateNode, e as DomTransitionLabel, f as DomTransitionPath, E as EntityDefinition, L as LessonSegment, R as RenderOptions, S as StateDefinition, g as StateMachineDefinition, T as TraitSnapshotGetter, h as TransitionDefinition, V as VisualizerConfig, i as bindCanvasCapture, j as bindEventBus, k as bindLastDrawables, l as bindTraitStateGetter, m as clearVerification, n as cn, o as extractOutputsFromTransitions, p as extractStateMachine, q as formatGuard, r as getAllChecks, s as getBridgeHealth, t as getEffectSummary, u as getSnapshot, v as getSummary, w as getTraitSnapshots, x as getTransitions, y as getTransitionsForTrait, z as parseContentSegments, A as parseLessonSegments, B as parseMarkdownWithCodeBlocks, F as recordServerResponse, G as recordTransition, H as registerCheck, I as registerTraitSnapshot, J as renderStateMachineToDomData, K as renderStateMachineToSvg, M as subscribeToVerification, N as updateAssetStatus, O as updateBridgeHealth, P as updateCheck, Q as waitForTransition } from '../cn-TH-RHihd.cjs';
2
2
  import { FieldValue, EntityRow, EventPayload } from '@almadar/core';
3
3
  export { AssetLoadStatus, BridgeHealth, CheckStatus, EffectTrace, EventLogEntry, OrbitalVerificationAPI, ServerResponseTrace, TraitStateSnapshot, TransitionTrace, VerificationCheck, VerificationSnapshot, VerificationSummary } from '@almadar/core';
4
+ export { p as profilerOnRender, u as usePerfBuffer } from '../perf-DaVdsbU0.cjs';
5
+ export { PERF_NAMESPACE, PerfEntry, clearPerf, perfEnd, perfGauge, perfStart, perfTime, perfTimeAsync } from '@almadar/runtime/ui';
4
6
  import 'react';
5
7
  import '../paintDispatch-DgBctxIq.cjs';
6
8
  import '../types-B3nHgnMG.cjs';
@@ -285,6 +287,61 @@ declare function onDebugToggle(listener: DebugToggleListener): () => void;
285
287
  */
286
288
  declare function initDebugShortcut(): () => void;
287
289
 
290
+ /**
291
+ * Command send pump (T7, docs/Almadar_Tick_Loop.md §3a item 2).
292
+ *
293
+ * Command-class events are a lossless ordered stream: two OW_DAMAGE hits must
294
+ * land twice, and the server must apply them in the exact order the client
295
+ * executed them. Pre-T7 the actor-queue drain `await`ed the server round trip
296
+ * per entry, so network latency sat on the input path — a keyup's local
297
+ * transition didn't run until every queued command ahead of it had completed
298
+ * its round trip (R-COMMAND-DRAIN-AWAIT-INPUT-LAG: 400-900ms typical, 1.6s
299
+ * peak under rapid platformer input).
300
+ *
301
+ * The pump restores ordering without the stall: jobs run strictly one at a
302
+ * time in enqueue order (request N+1 leaves only after response N arrived, so
303
+ * the server sees ordered commands and responses arrive in order — no seq
304
+ * numbers, no server machinery), while the caller's continuation runs when
305
+ * its own job settles and the drain moves on immediately. Tick-class traffic
306
+ * never passes through here — it is lossy and goes through
307
+ * `tick-send-relay.ts` instead.
308
+ *
309
+ * @packageDocumentation
310
+ */
311
+ interface CommandSendPump {
312
+ /** Run `job` after every previously enqueued job settles, in FIFO order. */
313
+ enqueue: <T>(job: () => Promise<T>) => Promise<T>;
314
+ }
315
+ declare function createCommandSendPump(): CommandSendPump;
316
+
317
+ /**
318
+ * Tick send relay (client→server leg of the tick doctrine, T8).
319
+ *
320
+ * A tick emission is a latest-state broadcast, not a command stream: it is
321
+ * coalesced newest-wins at every hop — client queue (`event-queue-coalesce`),
322
+ * client→server transport (this module), server relay
323
+ * (`OrbitalServerRuntime.queueTickRelay`). Pre-T8 this leg was missing: every
324
+ * tick firing issued one fire-and-forget HTTP POST, and when aggregate RTT ×
325
+ * rate exceeded the browser's per-origin connection pool, command fetches
326
+ * (keyup STOP) queued behind a never-ending tick stream — input lag that grew
327
+ * with play time (R-CLIENT-TICK-POST-BACKLOG).
328
+ *
329
+ * Backpressure by construction: at most one send in flight per key. Firings
330
+ * during flight replace the pending snapshot (newest-wins); on settle the
331
+ * newest pending goes out (trailing edge). Rate self-limits to 1/RTT — a fast
332
+ * server sees every tick, a slow one drops stale intermediates instead of
333
+ * growing a backlog. Commands never pass through here.
334
+ *
335
+ * @packageDocumentation
336
+ */
337
+ interface TickSendRelay<T> {
338
+ /** Dispatch a snapshot; coalesces onto the in-flight key's lane if busy. */
339
+ send: (key: string, value: T) => void;
340
+ /** Drop all pending snapshots (unmount / transport swap). */
341
+ clear: () => void;
342
+ }
343
+ declare function createTickSendRelay<T>(send: (key: string, value: T) => Promise<void>): TickSendRelay<T>;
344
+
288
345
  /**
289
346
  * Shared field-name + value formatting — the single owner of the humanize and
290
347
  * format vocabulary previously duplicated across DataTable, DataGrid, CardGrid,
@@ -558,4 +615,4 @@ declare function eightPointedStarPath(cx: number, cy: number, outerR: number, in
558
615
  */
559
616
  declare function arrowheadPath(size: number): string;
560
617
 
561
- export { ApiError, type DebugEvent, type DebugEventType, type EntitySnapshot, type EntityState, type GuardContext, type GuardEvaluation, JAZARI_COLORS, type JazariArmLayout, type JazariEffectInfo, type JazariGearLayout, type JazariGuardInfo, type JazariLayout, type LayoutInput, type LayoutState, type LayoutTransition, type PersistentEntityInfo, type RuntimeEntity, type SortDirection, type TickExecution, type TraitDebugInfo, type TraitGuard, type TraitTransition, type ValueFormat, apiClient, arrowheadPath, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, compareCellValues, computeJazariLayout, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, formatDate, formatDateTime, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllTicks, getAllTraits, getDebugEvents, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getTick, getTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, pipeIconPath, recordGuardEvaluation, registerTick, registerTrait, resolveImageUrl, setDebugEnabled, setEntityProvider, setTickActive, sortRows, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, toggleDebug, unregisterTick, unregisterTrait, updateGuardResult, updateTickExecution, updateTraitState };
618
+ export { ApiError, type CommandSendPump, type DebugEvent, type DebugEventType, type EntitySnapshot, type EntityState, type GuardContext, type GuardEvaluation, JAZARI_COLORS, type JazariArmLayout, type JazariEffectInfo, type JazariGearLayout, type JazariGuardInfo, type JazariLayout, type LayoutInput, type LayoutState, type LayoutTransition, type PersistentEntityInfo, type RuntimeEntity, type SortDirection, type TickExecution, type TickSendRelay, type TraitDebugInfo, type TraitGuard, type TraitTransition, type ValueFormat, apiClient, arrowheadPath, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, compareCellValues, computeJazariLayout, createCommandSendPump, createTickSendRelay, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, formatDate, formatDateTime, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllTicks, getAllTraits, getDebugEvents, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getTick, getTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, pipeIconPath, recordGuardEvaluation, registerTick, registerTrait, resolveImageUrl, setDebugEnabled, setEntityProvider, setTickActive, sortRows, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, toggleDebug, unregisterTick, unregisterTrait, updateGuardResult, updateTickExecution, updateTraitState };
@@ -1,6 +1,8 @@
1
1
  export { C as ContentSegment, D as DEFAULT_CONFIG, a as DomEntityBox, b as DomLayoutData, c as DomOutputsBox, d as DomStateNode, e as DomTransitionLabel, f as DomTransitionPath, E as EntityDefinition, L as LessonSegment, R as RenderOptions, S as StateDefinition, g as StateMachineDefinition, T as TraitSnapshotGetter, h as TransitionDefinition, V as VisualizerConfig, i as bindCanvasCapture, j as bindEventBus, k as bindLastDrawables, l as bindTraitStateGetter, m as clearVerification, n as cn, o as extractOutputsFromTransitions, p as extractStateMachine, q as formatGuard, r as getAllChecks, s as getBridgeHealth, t as getEffectSummary, u as getSnapshot, v as getSummary, w as getTraitSnapshots, x as getTransitions, y as getTransitionsForTrait, z as parseContentSegments, A as parseLessonSegments, B as parseMarkdownWithCodeBlocks, F as recordServerResponse, G as recordTransition, H as registerCheck, I as registerTraitSnapshot, J as renderStateMachineToDomData, K as renderStateMachineToSvg, M as subscribeToVerification, N as updateAssetStatus, O as updateBridgeHealth, P as updateCheck, Q as waitForTransition } from '../cn-CFurBb2q.js';
2
2
  import { FieldValue, EntityRow, EventPayload } from '@almadar/core';
3
3
  export { AssetLoadStatus, BridgeHealth, CheckStatus, EffectTrace, EventLogEntry, OrbitalVerificationAPI, ServerResponseTrace, TraitStateSnapshot, TransitionTrace, VerificationCheck, VerificationSnapshot, VerificationSummary } from '@almadar/core';
4
+ export { p as profilerOnRender, u as usePerfBuffer } from '../perf-DaVdsbU0.js';
5
+ export { PERF_NAMESPACE, PerfEntry, clearPerf, perfEnd, perfGauge, perfStart, perfTime, perfTimeAsync } from '@almadar/runtime/ui';
4
6
  import 'react';
5
7
  import '../paintDispatch-B5n2DTB-.js';
6
8
  import '../types-B3nHgnMG.js';
@@ -285,6 +287,61 @@ declare function onDebugToggle(listener: DebugToggleListener): () => void;
285
287
  */
286
288
  declare function initDebugShortcut(): () => void;
287
289
 
290
+ /**
291
+ * Command send pump (T7, docs/Almadar_Tick_Loop.md §3a item 2).
292
+ *
293
+ * Command-class events are a lossless ordered stream: two OW_DAMAGE hits must
294
+ * land twice, and the server must apply them in the exact order the client
295
+ * executed them. Pre-T7 the actor-queue drain `await`ed the server round trip
296
+ * per entry, so network latency sat on the input path — a keyup's local
297
+ * transition didn't run until every queued command ahead of it had completed
298
+ * its round trip (R-COMMAND-DRAIN-AWAIT-INPUT-LAG: 400-900ms typical, 1.6s
299
+ * peak under rapid platformer input).
300
+ *
301
+ * The pump restores ordering without the stall: jobs run strictly one at a
302
+ * time in enqueue order (request N+1 leaves only after response N arrived, so
303
+ * the server sees ordered commands and responses arrive in order — no seq
304
+ * numbers, no server machinery), while the caller's continuation runs when
305
+ * its own job settles and the drain moves on immediately. Tick-class traffic
306
+ * never passes through here — it is lossy and goes through
307
+ * `tick-send-relay.ts` instead.
308
+ *
309
+ * @packageDocumentation
310
+ */
311
+ interface CommandSendPump {
312
+ /** Run `job` after every previously enqueued job settles, in FIFO order. */
313
+ enqueue: <T>(job: () => Promise<T>) => Promise<T>;
314
+ }
315
+ declare function createCommandSendPump(): CommandSendPump;
316
+
317
+ /**
318
+ * Tick send relay (client→server leg of the tick doctrine, T8).
319
+ *
320
+ * A tick emission is a latest-state broadcast, not a command stream: it is
321
+ * coalesced newest-wins at every hop — client queue (`event-queue-coalesce`),
322
+ * client→server transport (this module), server relay
323
+ * (`OrbitalServerRuntime.queueTickRelay`). Pre-T8 this leg was missing: every
324
+ * tick firing issued one fire-and-forget HTTP POST, and when aggregate RTT ×
325
+ * rate exceeded the browser's per-origin connection pool, command fetches
326
+ * (keyup STOP) queued behind a never-ending tick stream — input lag that grew
327
+ * with play time (R-CLIENT-TICK-POST-BACKLOG).
328
+ *
329
+ * Backpressure by construction: at most one send in flight per key. Firings
330
+ * during flight replace the pending snapshot (newest-wins); on settle the
331
+ * newest pending goes out (trailing edge). Rate self-limits to 1/RTT — a fast
332
+ * server sees every tick, a slow one drops stale intermediates instead of
333
+ * growing a backlog. Commands never pass through here.
334
+ *
335
+ * @packageDocumentation
336
+ */
337
+ interface TickSendRelay<T> {
338
+ /** Dispatch a snapshot; coalesces onto the in-flight key's lane if busy. */
339
+ send: (key: string, value: T) => void;
340
+ /** Drop all pending snapshots (unmount / transport swap). */
341
+ clear: () => void;
342
+ }
343
+ declare function createTickSendRelay<T>(send: (key: string, value: T) => Promise<void>): TickSendRelay<T>;
344
+
288
345
  /**
289
346
  * Shared field-name + value formatting — the single owner of the humanize and
290
347
  * format vocabulary previously duplicated across DataTable, DataGrid, CardGrid,
@@ -558,4 +615,4 @@ declare function eightPointedStarPath(cx: number, cy: number, outerR: number, in
558
615
  */
559
616
  declare function arrowheadPath(size: number): string;
560
617
 
561
- export { ApiError, type DebugEvent, type DebugEventType, type EntitySnapshot, type EntityState, type GuardContext, type GuardEvaluation, JAZARI_COLORS, type JazariArmLayout, type JazariEffectInfo, type JazariGearLayout, type JazariGuardInfo, type JazariLayout, type LayoutInput, type LayoutState, type LayoutTransition, type PersistentEntityInfo, type RuntimeEntity, type SortDirection, type TickExecution, type TraitDebugInfo, type TraitGuard, type TraitTransition, type ValueFormat, apiClient, arrowheadPath, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, compareCellValues, computeJazariLayout, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, formatDate, formatDateTime, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllTicks, getAllTraits, getDebugEvents, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getTick, getTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, pipeIconPath, recordGuardEvaluation, registerTick, registerTrait, resolveImageUrl, setDebugEnabled, setEntityProvider, setTickActive, sortRows, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, toggleDebug, unregisterTick, unregisterTrait, updateGuardResult, updateTickExecution, updateTraitState };
618
+ export { ApiError, type CommandSendPump, type DebugEvent, type DebugEventType, type EntitySnapshot, type EntityState, type GuardContext, type GuardEvaluation, JAZARI_COLORS, type JazariArmLayout, type JazariEffectInfo, type JazariGearLayout, type JazariGuardInfo, type JazariLayout, type LayoutInput, type LayoutState, type LayoutTransition, type PersistentEntityInfo, type RuntimeEntity, type SortDirection, type TickExecution, type TickSendRelay, type TraitDebugInfo, type TraitGuard, type TraitTransition, type ValueFormat, apiClient, arrowheadPath, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, compareCellValues, computeJazariLayout, createCommandSendPump, createTickSendRelay, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, formatDate, formatDateTime, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllTicks, getAllTraits, getDebugEvents, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getTick, getTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, pipeIconPath, recordGuardEvaluation, registerTick, registerTrait, resolveImageUrl, setDebugEnabled, setEntityProvider, setTickActive, sortRows, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, toggleDebug, unregisterTick, unregisterTrait, updateGuardResult, updateTickExecution, updateTraitState };
package/dist/lib/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  import { clsx } from 'clsx';
2
2
  import { twMerge } from 'tailwind-merge';
3
3
  import { createLogger, isLogLevelEnabled } from '@almadar/logger';
4
+ import { useSyncExternalStore } from 'react';
5
+ import { perfStore, pushPerfEntry } from '@almadar/runtime/ui';
6
+ export { PERF_NAMESPACE, clearPerf, perfEnd, perfGauge, perfStart, perfTime, perfTimeAsync } from '@almadar/runtime/ui';
4
7
  import { isFileValue } from '@almadar/core';
5
8
 
6
9
  var __defProp = Object.defineProperty;
@@ -444,6 +447,64 @@ function clearTraits() {
444
447
  traits.clear();
445
448
  notifyListeners4();
446
449
  }
450
+
451
+ // lib/command-send-pump.ts
452
+ function createCommandSendPump() {
453
+ let tail = Promise.resolve();
454
+ return {
455
+ enqueue(job) {
456
+ const result = tail.then(job);
457
+ tail = result.then(
458
+ () => void 0,
459
+ () => void 0
460
+ );
461
+ return result;
462
+ }
463
+ };
464
+ }
465
+
466
+ // lib/tick-send-relay.ts
467
+ function createTickSendRelay(send) {
468
+ const lanes = /* @__PURE__ */ new Map();
469
+ const flush = (key, lane) => {
470
+ const next = lane.pending;
471
+ lane.pending = void 0;
472
+ if (next === void 0) {
473
+ lane.inFlight = false;
474
+ return;
475
+ }
476
+ lane.inFlight = true;
477
+ void send(key, next).catch(() => void 0).then(() => flush(key, lane));
478
+ };
479
+ return {
480
+ send(key, value) {
481
+ const lane = lanes.get(key) ?? { inFlight: false };
482
+ lanes.set(key, lane);
483
+ if (lane.inFlight) {
484
+ lane.pending = value;
485
+ return;
486
+ }
487
+ lane.pending = value;
488
+ flush(key, lane);
489
+ },
490
+ clear() {
491
+ for (const lane of lanes.values()) {
492
+ lane.pending = void 0;
493
+ }
494
+ }
495
+ };
496
+ }
497
+ function usePerfBuffer() {
498
+ return useSyncExternalStore(perfStore.subscribe, perfStore.getSnapshot, perfStore.getSnapshot);
499
+ }
500
+ var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
501
+ pushPerfEntry({
502
+ name: `profiler:${id}:${phase}`,
503
+ durationMs: actualDuration,
504
+ ts: commitTime,
505
+ detail: { baseDuration }
506
+ });
507
+ };
447
508
  var log2 = createLogger("almadar:bridge");
448
509
  var MAX_TRANSITIONS = 500;
449
510
  function getState() {
@@ -2032,4 +2093,4 @@ var JAZARI_COLORS = {
2032
2093
  darkBg: "#1a1a2e"
2033
2094
  };
2034
2095
 
2035
- export { ApiError, DEFAULT_CONFIG, JAZARI_COLORS, apiClient, arrowheadPath, bindCanvasCapture, bindEventBus, bindLastDrawables, bindTraitStateGetter, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, clearVerification, cn, compareCellValues, computeJazariLayout, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, extractOutputsFromTransitions, extractStateMachine, formatDate, formatDateTime, formatGuard, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllChecks, getAllTicks, getAllTraits, getBridgeHealth, getDebugEvents, getEffectSummary, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getSnapshot, getSummary, getTick, getTrait, getTraitSnapshots, getTransitions, getTransitionsForTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, parseContentSegments, parseLessonSegments, parseMarkdownWithCodeBlocks, pipeIconPath, recordGuardEvaluation, recordServerResponse, recordTransition, registerCheck, registerTick, registerTrait, registerTraitSnapshot, renderStateMachineToDomData, renderStateMachineToSvg, resolveImageUrl, setDebugEnabled, setEntityProvider, setTickActive, sortRows, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, subscribeToVerification, toggleDebug, unregisterTick, unregisterTrait, updateAssetStatus, updateBridgeHealth, updateCheck, updateGuardResult, updateTickExecution, updateTraitState, waitForTransition };
2096
+ export { ApiError, DEFAULT_CONFIG, JAZARI_COLORS, apiClient, arrowheadPath, bindCanvasCapture, bindEventBus, bindLastDrawables, bindTraitStateGetter, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, clearVerification, cn, compareCellValues, computeJazariLayout, createCommandSendPump, createTickSendRelay, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, extractOutputsFromTransitions, extractStateMachine, formatDate, formatDateTime, formatGuard, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllChecks, getAllTicks, getAllTraits, getBridgeHealth, getDebugEvents, getEffectSummary, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getSnapshot, getSummary, getTick, getTrait, getTraitSnapshots, getTransitions, getTransitionsForTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, parseContentSegments, parseLessonSegments, parseMarkdownWithCodeBlocks, pipeIconPath, profilerOnRender, recordGuardEvaluation, recordServerResponse, recordTransition, registerCheck, registerTick, registerTrait, registerTraitSnapshot, renderStateMachineToDomData, renderStateMachineToSvg, resolveImageUrl, setDebugEnabled, setEntityProvider, setTickActive, sortRows, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, subscribeToVerification, toggleDebug, unregisterTick, unregisterTrait, updateAssetStatus, updateBridgeHealth, updateCheck, updateGuardResult, updateTickExecution, updateTraitState, usePerfBuffer, waitForTransition };
@@ -13,6 +13,7 @@ var en_default = {
13
13
  "common.confirm": "Are you sure?",
14
14
  "common.create": "Create",
15
15
  "common.edit": "Edit",
16
+ "common.title": "Title",
16
17
  "common.view": "View",
17
18
  "common.add": "Add",
18
19
  "common.remove": "Remove",
@@ -590,6 +591,7 @@ var ar_default = {
590
591
  "common.confirm": "\u0647\u0644 \u0623\u0646\u062A \u0645\u062A\u0623\u0643\u062F\u061F",
591
592
  "common.create": "\u0625\u0646\u0634\u0627\u0621",
592
593
  "common.edit": "\u062A\u0639\u062F\u064A\u0644",
594
+ "common.title": "\u0627\u0644\u0639\u0646\u0648\u0627\u0646",
593
595
  "common.view": "\u0639\u0631\u0636",
594
596
  "common.add": "\u0625\u0636\u0627\u0641\u0629",
595
597
  "common.remove": "\u0625\u0632\u0627\u0644\u0629",
@@ -1167,6 +1169,7 @@ var sl_default = {
1167
1169
  "common.confirm": "Ali ste prepri\u010Dani?",
1168
1170
  "common.create": "Ustvari",
1169
1171
  "common.edit": "Uredi",
1172
+ "common.title": "Naslov",
1170
1173
  "common.view": "Prika\u017Ei",
1171
1174
  "common.add": "Dodaj",
1172
1175
  "common.remove": "Odstrani",
@@ -11,6 +11,7 @@ var en_default = {
11
11
  "common.confirm": "Are you sure?",
12
12
  "common.create": "Create",
13
13
  "common.edit": "Edit",
14
+ "common.title": "Title",
14
15
  "common.view": "View",
15
16
  "common.add": "Add",
16
17
  "common.remove": "Remove",
@@ -588,6 +589,7 @@ var ar_default = {
588
589
  "common.confirm": "\u0647\u0644 \u0623\u0646\u062A \u0645\u062A\u0623\u0643\u062F\u061F",
589
590
  "common.create": "\u0625\u0646\u0634\u0627\u0621",
590
591
  "common.edit": "\u062A\u0639\u062F\u064A\u0644",
592
+ "common.title": "\u0627\u0644\u0639\u0646\u0648\u0627\u0646",
591
593
  "common.view": "\u0639\u0631\u0636",
592
594
  "common.add": "\u0625\u0636\u0627\u0641\u0629",
593
595
  "common.remove": "\u0625\u0632\u0627\u0644\u0629",
@@ -1165,6 +1167,7 @@ var sl_default = {
1165
1167
  "common.confirm": "Ali ste prepri\u010Dani?",
1166
1168
  "common.create": "Ustvari",
1167
1169
  "common.edit": "Uredi",
1170
+ "common.title": "Naslov",
1168
1171
  "common.view": "Prika\u017Ei",
1169
1172
  "common.add": "Dodaj",
1170
1173
  "common.remove": "Odstrani",
@@ -0,0 +1,21 @@
1
+ import { ProfilerOnRenderCallback } from 'react';
2
+ import { PerfEntry } from '@almadar/runtime/ui';
3
+
4
+ /**
5
+ * @almadar/ui/runtime — perf instrumentation
6
+ *
7
+ * React-specific consumption layer on top of the renderer-agnostic perf ring
8
+ * now living in `@almadar/runtime/ui/perf`. Re-exports the framework-free
9
+ * timing primitives and adds `useSyncExternalStore` / `React.Profiler` hooks.
10
+ */
11
+
12
+ /**
13
+ * React hook: returns the current perf ring snapshot, re-renders on push.
14
+ */
15
+ declare function usePerfBuffer(): readonly PerfEntry[];
16
+ /**
17
+ * React.Profiler `onRender` callback. Records `actualDuration` per commit.
18
+ */
19
+ declare const profilerOnRender: ProfilerOnRenderCallback;
20
+
21
+ export { profilerOnRender as p, usePerfBuffer as u };
@@ -0,0 +1,21 @@
1
+ import { ProfilerOnRenderCallback } from 'react';
2
+ import { PerfEntry } from '@almadar/runtime/ui';
3
+
4
+ /**
5
+ * @almadar/ui/runtime — perf instrumentation
6
+ *
7
+ * React-specific consumption layer on top of the renderer-agnostic perf ring
8
+ * now living in `@almadar/runtime/ui/perf`. Re-exports the framework-free
9
+ * timing primitives and adds `useSyncExternalStore` / `React.Profiler` hooks.
10
+ */
11
+
12
+ /**
13
+ * React hook: returns the current perf ring snapshot, re-renders on push.
14
+ */
15
+ declare function usePerfBuffer(): readonly PerfEntry[];
16
+ /**
17
+ * React.Profiler `onRender` callback. Records `actualDuration` per commit.
18
+ */
19
+ declare const profilerOnRender: ProfilerOnRenderCallback;
20
+
21
+ export { profilerOnRender as p, usePerfBuffer as u };