@almadar/runtime 6.55.0 → 6.57.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,5 +1,5 @@
1
1
  import { Router } from 'express';
2
- import { I as IEventBus, R as RuntimeEvent, a as EventListener, U as Unsubscribe, T as TraitDefinition, b as RuntimeConfig, c as TransitionObserver, d as TraitState, C as ConfigContext, e as TransitionResult, f as EvaluationContextExtensions, E as EffectHandlers } from './types-BOF75lWr.js';
2
+ import { I as IEventBus, R as RuntimeEvent, a as EventListener, U as Unsubscribe, T as TraitDefinition, b as RuntimeConfig, c as TransitionObserver, d as TraitState, C as ConfigContext, e as TransitionResult, f as EvaluationContextExtensions, E as EffectHandlers } from './types-D20NPs1X.js';
3
3
  import { EventPayload, EventId, EntityRow, UserContext, Orbital, ServiceCallResult, TraitConfig, DeclaredTraitConfig, Entity, OrbitalSchema, Trait, PatternConfig, ResolvedPatternProps, SExpr, BusEventSource, RawUserClaims, OrbitalDefinition, TraitTick } from '@almadar/core';
4
4
 
5
5
  /**
@@ -899,11 +899,14 @@ declare class InMemoryPersistence implements PersistenceAdapter {
899
899
  * registry validation lives in `orbital validate` / `lolo` parse, not here.
900
900
  */
901
901
  type ClientRenderUITuple = ['render-ui', string, PatternConfig | null] | ['render-ui', string, PatternConfig | null, ResolvedPatternProps] | ['render-ui', string, PatternConfig | null, ResolvedPatternProps | undefined, number | undefined];
902
- type ClientNavigateTuple = ['navigate', string] | ['navigate', string, Record<string, string> | undefined];
902
+ type ClientNavigateTuple = ['navigate', string] | ['navigate', string, Record<string, string> | undefined] | ['navigate', string, Record<string, string> | undefined, {
903
+ crumb?: string;
904
+ }];
905
+ type ClientNavigateBackTuple = ['navigate-back'];
903
906
  type ClientNotifyTuple = ['notify', string, string | SExpr | undefined] | ['notify', string, string | SExpr | undefined, {
904
907
  type?: string;
905
908
  }];
906
- type ClientEffectTuple = ClientRenderUITuple | ClientNavigateTuple | ClientNotifyTuple;
909
+ type ClientEffectTuple = ClientRenderUITuple | ClientNavigateTuple | ClientNavigateBackTuple | ClientNotifyTuple;
907
910
 
908
911
  /** @deprecated Use OrbitalSchema from @almadar/core */
909
912
  type RuntimeOrbitalSchema = OrbitalSchema;
@@ -1490,4 +1493,4 @@ declare class OrbitalServerRuntime {
1490
1493
  */
1491
1494
  declare function createOrbitalServerRuntime(config?: OrbitalServerRuntimeConfig): OrbitalServerRuntime;
1492
1495
 
1493
- export { normalizeEventKey as A, parseNamespacedEvent as B, preprocessSchema as C, processEvent as D, type EntitySharingMap as E, type ClientEffectTuple as F, type ClientNavigateTuple as G, type ClientNotifyTuple as H, type ImportChainLike as I, type ClientRenderUITuple as J, type EffectResult as K, type LoadResult as L, type LiveBroadcastItem as M, type LoaderConfig as N, type OrbitalEventRequest as O, type PersistenceAdapter as P, OrbitalServerRuntime as Q, type RegisteredOrbital as R, type SchemaLoader as S, type RuntimeTraitTick as T, type UnifiedLoaderOptions as U, createOrbitalServerRuntime as V, type LoadedSchema as a, type LoadedOrbital as b, EventBus as c, type EventNamespaceMap as d, InMemoryPersistence as e, type OrbitalEventResponse as f, type OrbitalServerRuntimeConfig as g, type PreprocessOptions as h, type PreprocessResult as i, type PreprocessedSchema as j, type ProcessEventOptions as k, type RuntimeOrbital as l, type RuntimeOrbitalSchema as m, type RuntimeTrait as n, StateMachineManager as o, collectDeclaredConfigDefaults as p, collectDeclaredEntityDefaults as q, createInitialTraitState as r, findInitialState as s, findTransition as t, getIsolatedCollectionName as u, getNamespacedEvent as v, isBrowser as w, isElectron as x, isNamespacedEvent as y, isNode as z };
1496
+ export { normalizeEventKey as A, parseNamespacedEvent as B, preprocessSchema as C, processEvent as D, type EntitySharingMap as E, type ClientEffectTuple as F, type ClientNavigateBackTuple as G, type ClientNavigateTuple as H, type ImportChainLike as I, type ClientNotifyTuple as J, type ClientRenderUITuple as K, type LoadResult as L, type EffectResult as M, type LiveBroadcastItem as N, type OrbitalEventRequest as O, type PersistenceAdapter as P, type LoaderConfig as Q, type RegisteredOrbital as R, type SchemaLoader as S, OrbitalServerRuntime as T, type UnifiedLoaderOptions as U, type RuntimeTraitTick as V, createOrbitalServerRuntime as W, type LoadedSchema as a, type LoadedOrbital as b, EventBus as c, type EventNamespaceMap as d, InMemoryPersistence as e, type OrbitalEventResponse as f, type OrbitalServerRuntimeConfig as g, type PreprocessOptions as h, type PreprocessResult as i, type PreprocessedSchema as j, type ProcessEventOptions as k, type RuntimeOrbital as l, type RuntimeOrbitalSchema as m, type RuntimeTrait as n, StateMachineManager as o, collectDeclaredConfigDefaults as p, collectDeclaredEntityDefaults as q, createInitialTraitState as r, findInitialState as s, findTransition as t, getIsolatedCollectionName as u, getNamespacedEvent as v, isBrowser as w, isElectron as x, isNamespacedEvent as y, isNode as z };
@@ -1,4 +1,4 @@
1
1
  import 'express';
2
- export { F as ClientEffectTuple, G as ClientNavigateTuple, H as ClientNotifyTuple, J as ClientRenderUITuple, K as EffectResult, e as InMemoryPersistence, M as LiveBroadcastItem, N as LoaderConfig, O as OrbitalEventRequest, f as OrbitalEventResponse, Q as OrbitalServerRuntime, g as OrbitalServerRuntimeConfig, P as PersistenceAdapter, R as RegisteredOrbital, l as RuntimeOrbital, m as RuntimeOrbitalSchema, n as RuntimeTrait, T as RuntimeTraitTick, p as collectDeclaredConfigDefaults, V as createOrbitalServerRuntime } from './OrbitalServerRuntime-COuVFqev.js';
3
- import './types-BOF75lWr.js';
2
+ export { F as ClientEffectTuple, G as ClientNavigateBackTuple, H as ClientNavigateTuple, J as ClientNotifyTuple, K as ClientRenderUITuple, M as EffectResult, e as InMemoryPersistence, N as LiveBroadcastItem, Q as LoaderConfig, O as OrbitalEventRequest, f as OrbitalEventResponse, T as OrbitalServerRuntime, g as OrbitalServerRuntimeConfig, P as PersistenceAdapter, R as RegisteredOrbital, l as RuntimeOrbital, m as RuntimeOrbitalSchema, n as RuntimeTrait, V as RuntimeTraitTick, p as collectDeclaredConfigDefaults, W as createOrbitalServerRuntime } from './OrbitalServerRuntime-CgDV0DwN.js';
3
+ import './types-D20NPs1X.js';
4
4
  import '@almadar/core';
@@ -1,5 +1,5 @@
1
- import { createTickScheduler, EventBus, createUnifiedLoader, MockPersistenceAdapter, InMemoryPersistence, preprocessSchema, normalizeCallSiteConfigToValues, StateMachineManager, parseDurationString, validateEventPayload, formatPayloadValidationError, collectDeclaredConfigDefaults, collectDeclaredEntityDefaults, EffectExecutor } from './chunk-7CQLNJLN.js';
2
- export { InMemoryPersistence, collectDeclaredConfigDefaults } from './chunk-7CQLNJLN.js';
1
+ import { createTickScheduler, EventBus, createUnifiedLoader, MockPersistenceAdapter, InMemoryPersistence, preprocessSchema, normalizeCallSiteConfigToValues, StateMachineManager, parseDurationString, validateEventPayload, formatPayloadValidationError, collectDeclaredConfigDefaults, collectDeclaredEntityDefaults, EffectExecutor } from './chunk-MMVKKLAP.js';
2
+ export { InMemoryPersistence, collectDeclaredConfigDefaults } from './chunk-MMVKKLAP.js';
3
3
  import { isValidCronExpression } from './chunk-OU3ITB5S.js';
4
4
  import { createContextFromBindings, resolveCallSitePayloadCaptures, applyRowAccess, checkMutationAccess, accessDeniedMessage } from './chunk-ZJ62H3ES.js';
5
5
  import './chunk-T4VDAB4C.js';
@@ -1766,8 +1766,15 @@ var OrbitalServerRuntime = class {
1766
1766
  });
1767
1767
  pushClientEffect(["render-ui", slot, pattern, props, priority]);
1768
1768
  },
1769
- navigate: (path, params) => {
1770
- pushClientEffect(["navigate", path, params]);
1769
+ navigate: (path, params, crumb) => {
1770
+ if (crumb !== void 0) {
1771
+ pushClientEffect(["navigate", path, params, { crumb }]);
1772
+ } else {
1773
+ pushClientEffect(["navigate", path, params]);
1774
+ }
1775
+ },
1776
+ navigateBack: () => {
1777
+ pushClientEffect(["navigate-back"]);
1771
1778
  },
1772
1779
  notify: (message, type) => {
1773
1780
  if (this.config.debug) {
@@ -1813,6 +1820,24 @@ var OrbitalServerRuntime = class {
1813
1820
  ...callSiteOverride ?? {}
1814
1821
  };
1815
1822
  }
1823
+ if (bindings.config) {
1824
+ const USER_FORWARD = /^@user(?:\.[\w]+)+$/;
1825
+ let changed = false;
1826
+ const resolved = {};
1827
+ for (const [key, value] of Object.entries(bindings.config)) {
1828
+ if (typeof value === "string" && USER_FORWARD.test(value)) {
1829
+ let cur = user;
1830
+ for (const seg of value.slice("@user.".length).split(".")) {
1831
+ cur = cur !== null && typeof cur === "object" ? cur[seg] : void 0;
1832
+ }
1833
+ resolved[key] = typeof cur === "string" || typeof cur === "number" || typeof cur === "boolean" ? cur : "";
1834
+ changed = true;
1835
+ } else {
1836
+ resolved[key] = value;
1837
+ }
1838
+ }
1839
+ if (changed) bindings.config = resolved;
1840
+ }
1816
1841
  const sigilPages = [];
1817
1842
  const seenPaths = /* @__PURE__ */ new Set();
1818
1843
  for (const reg of this.orbitals.values()) {
@@ -1,4 +1,4 @@
1
- import { I as IEventBus } from './types-BOF75lWr.js';
1
+ import { I as IEventBus } from './types-D20NPs1X.js';
2
2
  import { EventPayload } from '@almadar/core';
3
3
 
4
4
  /**
@@ -886,12 +886,13 @@ var StateMachineManager = class {
886
886
 
887
887
  // src/types.ts
888
888
  var HANDLER_MANIFEST = {
889
- client: ["render-ui", "render", "navigate", "notify", "emit", "set", "log", "ref", "deref", "watch", "send-server", "browser/open-file-picker", "browser/clipboard-read", "browser/clipboard-write", "browser/geolocation-current"],
889
+ client: ["render-ui", "render", "navigate", "navigate-back", "notify", "emit", "set", "log", "ref", "deref", "watch", "send-server", "browser/open-file-picker", "browser/clipboard-read", "browser/clipboard-write", "browser/geolocation-current"],
890
890
  server: ["persist", "fetch", "fetch-stream", "call-service", "emit", "set", "spawn", "despawn", "log", "ref", "deref", "swap!", "atomic", "os/watch-files", "os/watch-process", "os/watch-port", "os/watch-http", "os/watch-cron", "os/watch-signal", "os/watch-env", "os/debounce"],
891
891
  test: [
892
892
  "render-ui",
893
893
  "render",
894
894
  "navigate",
895
+ "navigate-back",
895
896
  "notify",
896
897
  "emit",
897
898
  "set",
@@ -1025,6 +1026,7 @@ var EffectExecutor = class _EffectExecutor {
1025
1026
  "render-ui": this.handlers.renderUI,
1026
1027
  "render": this.handlers.renderUI,
1027
1028
  "navigate": this.handlers.navigate,
1029
+ "navigate-back": this.handlers.navigateBack,
1028
1030
  "notify": this.handlers.notify,
1029
1031
  "log": this.handlers.log,
1030
1032
  "ref": this.handlers.ref,
@@ -1572,13 +1574,27 @@ var EffectExecutor = class _EffectExecutor {
1572
1574
  case "navigate": {
1573
1575
  if (this.handlers.navigate) {
1574
1576
  const path = args[0];
1577
+ if (typeof path !== "string" || path === "") {
1578
+ effectLog.warn("navigate-path-unresolved", { pathType: typeof path });
1579
+ break;
1580
+ }
1575
1581
  const params = args[1];
1576
- this.handlers.navigate(path, params);
1582
+ const options = args[2];
1583
+ const crumb = options && typeof options.crumb === "string" && options.crumb !== "" ? options.crumb : void 0;
1584
+ this.handlers.navigate(path, params, crumb);
1577
1585
  } else {
1578
1586
  this.logUnsupported("navigate");
1579
1587
  }
1580
1588
  break;
1581
1589
  }
1590
+ case "navigate-back": {
1591
+ if (this.handlers.navigateBack) {
1592
+ this.handlers.navigateBack();
1593
+ } else {
1594
+ this.logUnsupported("navigate-back");
1595
+ }
1596
+ break;
1597
+ }
1582
1598
  case "notify": {
1583
1599
  if (this.handlers.notify) {
1584
1600
  const message = args[0];
@@ -1919,6 +1935,17 @@ var EffectExecutor = class _EffectExecutor {
1919
1935
  }, emitCfg);
1920
1936
  break;
1921
1937
  }
1938
+ case "browser/push-subscribe": {
1939
+ const [, emitCfg] = this.splitSubstrateEmit(args);
1940
+ await this.runSubstrate(async () => {
1941
+ if (!this.handlers.browserPushSubscribe) {
1942
+ this.logUnsupported("browser/push-subscribe");
1943
+ return null;
1944
+ }
1945
+ return this.handlers.browserPushSubscribe();
1946
+ }, emitCfg);
1947
+ break;
1948
+ }
1922
1949
  default: {
1923
1950
  if (operator.includes("/")) {
1924
1951
  const [positional, emitCfg] = this.splitSubstrateEmit(args);
@@ -1,4 +1,4 @@
1
- import { E as EffectHandlers } from './types-BOF75lWr.js';
1
+ import { E as EffectHandlers } from './types-D20NPs1X.js';
2
2
  import { EventPayload } from '@almadar/core';
3
3
 
4
4
  /**
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { g as RuntimePatternValue, B as BindingContext, f as EvaluationContextExtensions, P as PatternProps, E as EffectHandlers, h as EffectContext, i as ExecutionEnvironment, j as EffectResult, T as TraitDefinition } from './types-BOF75lWr.js';
2
- export { k as BrowserFileMeta, l as BrowserFilePickerOptions, m as BrowserGeolocationOptions, n as BrowserGeolocationPosition, C as ConfigContext, o as Effect, a as EventListener, H as HANDLER_MANIFEST, I as IEventBus, b as RuntimeConfig, R as RuntimeEvent, d as TraitState, c as TransitionObserver, e as TransitionResult, U as Unsubscribe } from './types-BOF75lWr.js';
3
- import { U as UnifiedLoaderOptions, S as SchemaLoader, I as ImportChainLike, L as LoadResult, a as LoadedSchema, b as LoadedOrbital, P as PersistenceAdapter } from './OrbitalServerRuntime-COuVFqev.js';
4
- export { E as EntitySharingMap, c as EventBus, d as EventNamespaceMap, e as InMemoryPersistence, O as OrbitalEventRequest, f as OrbitalEventResponse, g as OrbitalServerRuntimeConfig, h as PreprocessOptions, i as PreprocessResult, j as PreprocessedSchema, k as ProcessEventOptions, R as RegisteredOrbital, l as RuntimeOrbital, m as RuntimeOrbitalSchema, n as RuntimeTrait, o as StateMachineManager, p as collectDeclaredConfigDefaults, q as collectDeclaredEntityDefaults, r as createInitialTraitState, s as findInitialState, t as findTransition, u as getIsolatedCollectionName, v as getNamespacedEvent, w as isBrowser, x as isElectron, y as isNamespacedEvent, z as isNode, A as normalizeEventKey, B as parseNamespacedEvent, C as preprocessSchema, D as processEvent } from './OrbitalServerRuntime-COuVFqev.js';
1
+ import { g as RuntimePatternValue, B as BindingContext, f as EvaluationContextExtensions, P as PatternProps, E as EffectHandlers, h as EffectContext, i as ExecutionEnvironment, j as EffectResult, T as TraitDefinition } from './types-D20NPs1X.js';
2
+ export { k as BrowserFileMeta, l as BrowserFilePickerOptions, m as BrowserGeolocationOptions, n as BrowserGeolocationPosition, C as ConfigContext, o as Effect, a as EventListener, H as HANDLER_MANIFEST, I as IEventBus, b as RuntimeConfig, R as RuntimeEvent, d as TraitState, c as TransitionObserver, e as TransitionResult, U as Unsubscribe } from './types-D20NPs1X.js';
3
+ import { U as UnifiedLoaderOptions, S as SchemaLoader, I as ImportChainLike, L as LoadResult, a as LoadedSchema, b as LoadedOrbital, P as PersistenceAdapter } from './OrbitalServerRuntime-CgDV0DwN.js';
4
+ export { E as EntitySharingMap, c as EventBus, d as EventNamespaceMap, e as InMemoryPersistence, O as OrbitalEventRequest, f as OrbitalEventResponse, g as OrbitalServerRuntimeConfig, h as PreprocessOptions, i as PreprocessResult, j as PreprocessedSchema, k as ProcessEventOptions, R as RegisteredOrbital, l as RuntimeOrbital, m as RuntimeOrbitalSchema, n as RuntimeTrait, o as StateMachineManager, p as collectDeclaredConfigDefaults, q as collectDeclaredEntityDefaults, r as createInitialTraitState, s as findInitialState, t as findTransition, u as getIsolatedCollectionName, v as getNamespacedEvent, w as isBrowser, x as isElectron, y as isNamespacedEvent, z as isNode, A as normalizeEventKey, B as parseNamespacedEvent, C as preprocessSchema, D as processEvent } from './OrbitalServerRuntime-CgDV0DwN.js';
5
5
  import { EvaluationContext, SExpressionEvaluator } from '@almadar/evaluator';
6
6
  export { EvaluationContext, createMinimalContext } from '@almadar/evaluator';
7
7
  import { RenderBindingMarker, SExpr, TraitConfigObject, EventPayload, PatternConfig, EntityId, EntityField, EntityRow, EntityPersistence, ServiceParams, EntityAccessPolicies, PayloadField, OrbitalDefinition, OrbitalSchema } from '@almadar/core';
@@ -499,10 +499,14 @@ interface CreateClientEffectHandlersOptions {
499
499
  eventBus: ClientEventBus;
500
500
  /** Slot setter for render-ui effects */
501
501
  slotSetter: SlotSetter;
502
- /** Navigate function for navigate effects */
502
+ /** Navigate function for navigate effects. `crumb` labels the target
503
+ * page's navigation-stack entry (from the effect's `{ crumb: … }`
504
+ * options). */
503
505
  navigate?: (path: string, params?: {
504
506
  [key: string]: string;
505
- }) => void;
507
+ }, crumb?: string) => void;
508
+ /** Navigate-back function: pop the orbital-scoped navigation stack. */
509
+ navigateBack?: () => void;
506
510
  /** Notify function for notification effects */
507
511
  notify?: (message: string, type: 'success' | 'error' | 'warning' | 'info') => void;
508
512
  /**
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { EffectExecutor } from './chunk-7CQLNJLN.js';
2
- export { EffectExecutor, EventBus, HANDLER_MANIFEST, InMemoryPersistence, MockPersistenceAdapter, StateMachineManager, TickScheduler, buildEmitsFromTraits, collectDeclaredConfigDefaults, collectDeclaredEntityDefaults, createInitialTraitState, createMockPersistence, createTestExecutor, createTickScheduler, createUnifiedLoader, findInitialState, findTransition, formatPayloadValidationError, getIsolatedCollectionName, getNamespacedEvent, isBrowser, isElectron, isNamespacedEvent, isNode, isValidDurationString, normalizeCallSiteConfigToValues, normalizeEventKey, parseDurationString, parseNamespacedEvent, preprocessSchema, processEvent, validateEventPayload, validatePayloadShapes } from './chunk-7CQLNJLN.js';
1
+ import { EffectExecutor } from './chunk-MMVKKLAP.js';
2
+ export { EffectExecutor, EventBus, HANDLER_MANIFEST, InMemoryPersistence, MockPersistenceAdapter, StateMachineManager, TickScheduler, buildEmitsFromTraits, collectDeclaredConfigDefaults, collectDeclaredEntityDefaults, createInitialTraitState, createMockPersistence, createTestExecutor, createTickScheduler, createUnifiedLoader, findInitialState, findTransition, formatPayloadValidationError, getIsolatedCollectionName, getNamespacedEvent, isBrowser, isElectron, isNamespacedEvent, isNode, isValidDurationString, normalizeCallSiteConfigToValues, normalizeEventKey, parseDurationString, parseNamespacedEvent, preprocessSchema, processEvent, validateEventPayload, validatePayloadShapes } from './chunk-MMVKKLAP.js';
3
3
  export { cronMatches, cronMinuteKey, isValidCronExpression, parseCron, parseCronField } from './chunk-OU3ITB5S.js';
4
4
  import { createContextFromBindings, applyRowAccess, checkMutationAccess, accessDeniedMessage } from './chunk-ZJ62H3ES.js';
5
5
  export { CALLSITE_PAYLOAD_PREFIX, applyRowAccess, checkMutationAccess, containsBindings, createContextFromBindings, createMinimalContext, deferEntityBindings, extractBindings, interpolateProps, interpolateValue, resolveCallSitePayloadCaptures } from './chunk-ZJ62H3ES.js';
@@ -40,6 +40,17 @@ function getOrOpenWs() {
40
40
  }
41
41
  return _ws;
42
42
  }
43
+ function urlBase64ToArrayBuffer(base64Url) {
44
+ const padding = "=".repeat((4 - base64Url.length % 4) % 4);
45
+ const base64 = (base64Url + padding).replace(/-/g, "+").replace(/_/g, "/");
46
+ const raw = atob(base64);
47
+ const buffer = new ArrayBuffer(raw.length);
48
+ const view = new Uint8Array(buffer);
49
+ for (let i = 0; i < raw.length; i++) {
50
+ view[i] = raw.charCodeAt(i);
51
+ }
52
+ return buffer;
53
+ }
43
54
  function sendServerEvent(orbital, event, payload) {
44
55
  const msg = JSON.stringify({
45
56
  type: "ORBITAL_EVENT",
@@ -57,7 +68,7 @@ function sendServerEvent(orbital, event, payload) {
57
68
  }
58
69
  }
59
70
  function createClientEffectHandlers(options) {
60
- const { eventBus, slotSetter, navigate, notify, sendServer, orbitalName = "" } = options;
71
+ const { eventBus, slotSetter, navigate, navigateBack, notify, sendServer, orbitalName = "" } = options;
61
72
  return {
62
73
  emit: (event, payload) => {
63
74
  const prefixedEvent = event.startsWith("UI:") ? event : `UI:${event}`;
@@ -87,6 +98,9 @@ function createClientEffectHandlers(options) {
87
98
  }
88
99
  log.warn("navigate-no-handler", { path });
89
100
  }),
101
+ navigateBack: navigateBack ?? (() => {
102
+ log.warn("navigate-back-no-handler");
103
+ }),
90
104
  notify: notify ?? ((msg, type) => {
91
105
  log.debug("notify", { type: type ?? null, message: msg });
92
106
  }),
@@ -127,6 +141,29 @@ function createClientEffectHandlers(options) {
127
141
  await navigator.clipboard.writeText(text);
128
142
  return { text };
129
143
  },
144
+ browserPushSubscribe: async () => {
145
+ if (typeof navigator === "undefined" || !("serviceWorker" in navigator) || typeof window === "undefined" || !("PushManager" in window)) {
146
+ throw new Error("Push API is not available in this environment");
147
+ }
148
+ const keyResponse = await fetch("/api/push/vapid-public-key");
149
+ if (!keyResponse.ok) {
150
+ throw new Error("Push is not configured on this host (no VAPID public key)");
151
+ }
152
+ const { publicKey } = await keyResponse.json();
153
+ const registration = await navigator.serviceWorker.register("/almadar-push-sw.js");
154
+ const subscription = await registration.pushManager.subscribe({
155
+ userVisibleOnly: true,
156
+ applicationServerKey: urlBase64ToArrayBuffer(publicKey)
157
+ });
158
+ const json = subscription.toJSON();
159
+ const endpoint = json.endpoint ?? "";
160
+ const p256dh = json.keys?.p256dh ?? "";
161
+ const auth = json.keys?.auth ?? "";
162
+ if (!endpoint || !p256dh || !auth) {
163
+ throw new Error("Push subscription resolved without endpoint/keys");
164
+ }
165
+ return { endpoint, p256dh, auth };
166
+ },
130
167
  browserGeolocationCurrent: async (options2) => {
131
168
  if (typeof navigator === "undefined" || !navigator.geolocation) {
132
169
  throw new Error("Geolocation API is not available in this environment");
@@ -188,10 +188,15 @@ interface EffectHandlers {
188
188
  * (relationsData) read from the persistence adapter before pushing —
189
189
  * the interpreter's mirror of codegen's build-time relationsData. */
190
190
  renderUI?: (slot: string, pattern: PatternConfig | null, props?: PatternProps, priority?: number) => void | Promise<void>;
191
- /** Navigate to a route (client only) */
191
+ /** Navigate to a route (client only). `crumb` labels the navigation-stack
192
+ * entry the client pushes for the target page (from the effect's
193
+ * `{ crumb: … }` options). */
192
194
  navigate?: (path: string, params?: {
193
195
  [key: string]: string;
194
- }) => void;
196
+ }, crumb?: string) => void;
197
+ /** Pop the orbital-scoped navigation stack and return to the previous
198
+ * entry (client only). */
199
+ navigateBack?: () => void;
195
200
  /** Show a notification (client: toast, server: log) */
196
201
  notify?: (message: string, type: 'success' | 'error' | 'warning' | 'info') => void;
197
202
  /** Log a message */
@@ -266,6 +271,12 @@ interface EffectHandlers {
266
271
  }>;
267
272
  /** browser/geolocation-current — resolves with the position inside `result` */
268
273
  browserGeolocationCurrent?: (options?: BrowserGeolocationOptions) => Promise<BrowserGeolocationPosition>;
274
+ /** browser/push-subscribe — resolves with the flat Web Push subscription credentials inside `result` */
275
+ browserPushSubscribe?: () => Promise<{
276
+ endpoint: string;
277
+ p256dh: string;
278
+ auth: string;
279
+ }>;
269
280
  /** compose/compose-all — compose multiple orbitals into one schema */
270
281
  substrateComposeAll?: (config: {
271
282
  appName: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/runtime",
3
- "version": "6.55.0",
3
+ "version": "6.57.0",
4
4
  "description": "Interpreted runtime for Almadar orbital applications (OrbitalServerRuntime)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -57,11 +57,11 @@
57
57
  "access": "public"
58
58
  },
59
59
  "dependencies": {
60
- "@almadar/core": "^10.62.0",
60
+ "@almadar/core": "^10.66.0",
61
61
  "@almadar/evaluator": "^2.41.0",
62
62
  "@almadar/logger": "^1.11.0",
63
- "@almadar/server": "^2.34.0",
64
- "@almadar/std": "^16.178.0"
63
+ "@almadar/server": "^2.36.0",
64
+ "@almadar/std": "^16.182.0"
65
65
  },
66
66
  "peerDependencies": {
67
67
  "express": "^5.0.0"