@almadar/runtime 6.56.0 → 6.58.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-BWENk-qT.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-TwQ8Dybu.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
  /**
@@ -1,4 +1,4 @@
1
1
  import 'express';
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-Bh4fHBkb.js';
3
- import './types-BWENk-qT.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-Dn9dIwJk.js';
3
+ import './types-TwQ8Dybu.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-XY5BLZKS.js';
2
- export { InMemoryPersistence, collectDeclaredConfigDefaults } from './chunk-XY5BLZKS.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';
@@ -1522,7 +1522,8 @@ var OrbitalServerRuntime = class {
1522
1522
  result = await this.config.effectHandlers.callService(
1523
1523
  service,
1524
1524
  action,
1525
- params
1525
+ params,
1526
+ user ? { principal: user.id, role: user.role } : void 0
1526
1527
  );
1527
1528
  } else if (this.config.mode === "mock") {
1528
1529
  const mockId = `mock_${service}_${action}_${Math.random().toString(36).slice(2, 10)}`;
@@ -1820,6 +1821,24 @@ var OrbitalServerRuntime = class {
1820
1821
  ...callSiteOverride ?? {}
1821
1822
  };
1822
1823
  }
1824
+ if (bindings.config) {
1825
+ const USER_FORWARD = /^@user(?:\.[\w]+)+$/;
1826
+ let changed = false;
1827
+ const resolved = {};
1828
+ for (const [key, value] of Object.entries(bindings.config)) {
1829
+ if (typeof value === "string" && USER_FORWARD.test(value)) {
1830
+ let cur = user;
1831
+ for (const seg of value.slice("@user.".length).split(".")) {
1832
+ cur = cur !== null && typeof cur === "object" ? cur[seg] : void 0;
1833
+ }
1834
+ resolved[key] = typeof cur === "string" || typeof cur === "number" || typeof cur === "boolean" ? cur : "";
1835
+ changed = true;
1836
+ } else {
1837
+ resolved[key] = value;
1838
+ }
1839
+ }
1840
+ if (changed) bindings.config = resolved;
1841
+ }
1823
1842
  const sigilPages = [];
1824
1843
  const seenPaths = /* @__PURE__ */ new Set();
1825
1844
  for (const reg of this.orbitals.values()) {
@@ -1,4 +1,4 @@
1
- import { I as IEventBus } from './types-BWENk-qT.js';
1
+ import { I as IEventBus } from './types-TwQ8Dybu.js';
2
2
  import { EventPayload } from '@almadar/core';
3
3
 
4
4
  /**
@@ -1935,6 +1935,17 @@ var EffectExecutor = class _EffectExecutor {
1935
1935
  }, emitCfg);
1936
1936
  break;
1937
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
+ }
1938
1949
  default: {
1939
1950
  if (operator.includes("/")) {
1940
1951
  const [positional, emitCfg] = this.splitSubstrateEmit(args);
@@ -1,4 +1,4 @@
1
- import { E as EffectHandlers } from './types-BWENk-qT.js';
1
+ import { E as EffectHandlers } from './types-TwQ8Dybu.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-BWENk-qT.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-BWENk-qT.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-Bh4fHBkb.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-Bh4fHBkb.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, S as ServiceCallContext, T as TraitDefinition } from './types-TwQ8Dybu.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-TwQ8Dybu.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-Dn9dIwJk.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-Dn9dIwJk.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';
@@ -803,7 +803,7 @@ interface CreateServerEffectHandlersOptions {
803
803
  trait?: string;
804
804
  };
805
805
  /** Consumer-supplied `call-service` handler. When absent, calls warn and return null. */
806
- callService?: (service: string, action: string, params?: ServiceParams) => Promise<EventPayload | null>;
806
+ callService?: (service: string, action: string, params?: ServiceParams, context?: ServiceCallContext) => Promise<EventPayload | null>;
807
807
  /**
808
808
  * The declared `@read`/`@create`/`@update`/`@delete` directives, keyed by
809
809
  * entity name. Build it with `entityAccessTable(schema)` from `@almadar/core`.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { EffectExecutor } from './chunk-XY5BLZKS.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-XY5BLZKS.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",
@@ -130,6 +141,29 @@ function createClientEffectHandlers(options) {
130
141
  await navigator.clipboard.writeText(text);
131
142
  return { text };
132
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
+ },
133
167
  browserGeolocationCurrent: async (options2) => {
134
168
  if (typeof navigator === "undefined" || !navigator.geolocation) {
135
169
  throw new Error("Geolocation API is not available in this environment");
@@ -401,7 +435,13 @@ function createServerEffectHandlers(opts) {
401
435
  try {
402
436
  let result = null;
403
437
  if (consumerCallService) {
404
- result = await consumerCallService(service, action, params);
438
+ const viewer = bindings?.user;
439
+ result = await consumerCallService(
440
+ service,
441
+ action,
442
+ params,
443
+ viewer ? { principal: viewer.id, role: viewer.role } : void 0
444
+ );
405
445
  } else {
406
446
  const mockId = `mock_${service}_${action}_${Math.random().toString(36).slice(2, 10)}`;
407
447
  const paramsEcho = {};
@@ -121,6 +121,16 @@ interface TraitDefinition {
121
121
  * Client: React hooks, DOM, router
122
122
  * Server: Express, database, integrators
123
123
  */
124
+ /**
125
+ * Caller identity forwarded with a call-service dispatch (I-25) — the id and
126
+ * roster role of the SAME normalized viewer entity ACL enforces against.
127
+ * Absent when no viewer is bound (ticks, anonymous); role-gated services
128
+ * fail closed on absence.
129
+ */
130
+ interface ServiceCallContext {
131
+ principal?: string;
132
+ role?: string;
133
+ }
124
134
  interface EffectHandlers {
125
135
  /**
126
136
  * Emit an event to the event bus.
@@ -143,8 +153,10 @@ interface EffectHandlers {
143
153
  persist: (action: 'create' | 'update' | 'delete' | 'batch', entityType: string, data?: EntityRow) => Promise<void>;
144
154
  /** Set a field value on an entity */
145
155
  set: (entityId: string, field: string, value: FieldValue) => void;
146
- /** Call an external service */
147
- callService: (service: string, action: string, params?: ServiceParams) => Promise<EventPayload | null>;
156
+ /** Call an external service. `context` carries the caller's identity
157
+ * (the same viewer entity ACL enforces against) so role-gated services
158
+ * can enforce server-side; hosts forward it to the integration factory. */
159
+ callService: (service: string, action: string, params?: ServiceParams, context?: ServiceCallContext) => Promise<EventPayload | null>;
148
160
  /** Fetch entity data (server only) - returns data for client-side rendering.
149
161
  *
150
162
  * Always returns a `FetchResult` (`{rows, total}`) on success. `total`
@@ -271,6 +283,12 @@ interface EffectHandlers {
271
283
  }>;
272
284
  /** browser/geolocation-current — resolves with the position inside `result` */
273
285
  browserGeolocationCurrent?: (options?: BrowserGeolocationOptions) => Promise<BrowserGeolocationPosition>;
286
+ /** browser/push-subscribe — resolves with the flat Web Push subscription credentials inside `result` */
287
+ browserPushSubscribe?: () => Promise<{
288
+ endpoint: string;
289
+ p256dh: string;
290
+ auth: string;
291
+ }>;
274
292
  /** compose/compose-all — compose multiple orbitals into one schema */
275
293
  substrateComposeAll?: (config: {
276
294
  appName: string;
@@ -483,4 +501,4 @@ interface TransitionObserver {
483
501
  */
484
502
  declare const HANDLER_MANIFEST: Record<ExecutionEnvironment, string[]>;
485
503
 
486
- export { type BindingContext as B, type ConfigContext as C, type EffectHandlers as E, HANDLER_MANIFEST as H, type IEventBus as I, type PatternProps as P, type RuntimeEvent as R, type TraitDefinition as T, type Unsubscribe as U, type EventListener as a, type RuntimeConfig as b, type TransitionObserver as c, type TraitState as d, type TransitionResult as e, type EvaluationContextExtensions as f, type RuntimePatternValue as g, type EffectContext as h, type ExecutionEnvironment as i, type EffectResult as j, type BrowserFileMeta as k, type BrowserFilePickerOptions as l, type BrowserGeolocationOptions as m, type BrowserGeolocationPosition as n, type Effect as o };
504
+ export { type BindingContext as B, type ConfigContext as C, type EffectHandlers as E, HANDLER_MANIFEST as H, type IEventBus as I, type PatternProps as P, type RuntimeEvent as R, type ServiceCallContext as S, type TraitDefinition as T, type Unsubscribe as U, type EventListener as a, type RuntimeConfig as b, type TransitionObserver as c, type TraitState as d, type TransitionResult as e, type EvaluationContextExtensions as f, type RuntimePatternValue as g, type EffectContext as h, type ExecutionEnvironment as i, type EffectResult as j, type BrowserFileMeta as k, type BrowserFilePickerOptions as l, type BrowserGeolocationOptions as m, type BrowserGeolocationPosition as n, type Effect as o };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/runtime",
3
- "version": "6.56.0",
3
+ "version": "6.58.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.64.0",
60
+ "@almadar/core": "^10.67.0",
61
61
  "@almadar/evaluator": "^2.41.0",
62
62
  "@almadar/logger": "^1.11.0",
63
- "@almadar/server": "^2.35.0",
64
- "@almadar/std": "^16.180.0"
63
+ "@almadar/server": "^2.37.0",
64
+ "@almadar/std": "^16.183.0"
65
65
  },
66
66
  "peerDependencies": {
67
67
  "express": "^5.0.0"