@almadar/runtime 6.71.0 → 6.73.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/{OrbitalServerRuntime-DnDJhpLS.d.ts → OrbitalServerRuntime-BiEntWd-.d.ts} +258 -86
- package/dist/OrbitalServerRuntime.d.ts +2 -2
- package/dist/OrbitalServerRuntime.js +171 -16
- package/dist/ServerBridge.d.ts +1 -1
- package/dist/{chunk-PAEMYGKV.js → chunk-H7HQQVQJ.js} +3071 -299
- package/dist/{chunk-ZJ62H3ES.js → chunk-ZWAOJT6R.js} +5 -29
- package/dist/createOsHandlers.d.ts +1 -1
- package/dist/entityAccess.js +1 -1
- package/dist/{external-loader-YUUADLAP.js → external-loader-CISUEINQ.js} +1 -0
- package/dist/index.d.ts +14 -132
- package/dist/index.js +28 -10
- package/dist/{types-BaD_ox7e.d.ts → types-CWaIuEQn.d.ts} +34 -4
- package/package.json +7 -7
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveBinding, evaluate, createMinimalContext } from '@almadar/evaluator';
|
|
2
2
|
export { createMinimalContext } from '@almadar/evaluator';
|
|
3
3
|
import { isKnownStdOperator } from '@almadar/std/registry';
|
|
4
4
|
import { containsEntityBinding, containsPayloadBinding, RENDER_BINDING_MARKER } from '@almadar/core';
|
|
@@ -10,33 +10,6 @@ setNamespaceLevel("almadar:runtime:bindings", "WARN");
|
|
|
10
10
|
var deferLog = createLogger("almadar:runtime:defer");
|
|
11
11
|
var renderLog = createLogger("almadar:runtime:render-ui");
|
|
12
12
|
var CLIENT_ONLY_BINDING_ROOTS = /* @__PURE__ */ new Set(["trait"]);
|
|
13
|
-
var CALLSITE_PAYLOAD_PREFIX = "@callsitePayload.";
|
|
14
|
-
function payloadValueToConfigValue(v) {
|
|
15
|
-
if (v === null || v === void 0) return null;
|
|
16
|
-
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") return v;
|
|
17
|
-
if (v instanceof Date) return v.toISOString();
|
|
18
|
-
if (Array.isArray(v)) return v.map(payloadValueToConfigValue);
|
|
19
|
-
if (typeof v === "object") {
|
|
20
|
-
const obj = {};
|
|
21
|
-
for (const [k, val] of Object.entries(v)) obj[k] = payloadValueToConfigValue(val);
|
|
22
|
-
return obj;
|
|
23
|
-
}
|
|
24
|
-
return String(v);
|
|
25
|
-
}
|
|
26
|
-
function resolveCallSitePayloadCaptures(config, payload) {
|
|
27
|
-
let ctx;
|
|
28
|
-
const out = {};
|
|
29
|
-
for (const [key, value] of Object.entries(config)) {
|
|
30
|
-
if (typeof value === "string" && value.startsWith(CALLSITE_PAYLOAD_PREFIX)) {
|
|
31
|
-
const field = value.slice(CALLSITE_PAYLOAD_PREFIX.length);
|
|
32
|
-
if (!ctx) ctx = createMinimalContext({}, payload ?? {}, "idle");
|
|
33
|
-
out[key] = payloadValueToConfigValue(resolveBinding(`@payload.${field}`, ctx));
|
|
34
|
-
} else {
|
|
35
|
-
out[key] = value;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return out;
|
|
39
|
-
}
|
|
40
13
|
function isClientOnlyBinding(value) {
|
|
41
14
|
if (!value.startsWith("@")) return false;
|
|
42
15
|
const afterAt = value.slice(1);
|
|
@@ -330,6 +303,9 @@ function createContextFromBindings(bindings, strictBindings, contextExtensions)
|
|
|
330
303
|
if (bindings.currentTheme) {
|
|
331
304
|
ctx.currentTheme = bindings.currentTheme;
|
|
332
305
|
}
|
|
306
|
+
if (bindings.callsitePayload) {
|
|
307
|
+
ctx.callsitePayload = bindings.callsitePayload;
|
|
308
|
+
}
|
|
333
309
|
if (bindings.locals) {
|
|
334
310
|
ctx.locals = bindings.locals;
|
|
335
311
|
}
|
|
@@ -379,4 +355,4 @@ function checkMutationAccess(row, policy, bindings) {
|
|
|
379
355
|
}
|
|
380
356
|
}
|
|
381
357
|
|
|
382
|
-
export {
|
|
358
|
+
export { accessDeniedMessage, applyRowAccess, checkMutationAccess, containsBindings, createContextFromBindings, deferEntityBindings, extractBindings, interpolateProps, interpolateValue };
|
package/dist/entityAccess.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { accessDeniedMessage, applyRowAccess, checkMutationAccess } from './chunk-
|
|
1
|
+
export { accessDeniedMessage, applyRowAccess, checkMutationAccess } from './chunk-ZWAOJT6R.js';
|
|
2
2
|
import './chunk-MLKGABMK.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
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-
|
|
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-
|
|
4
|
-
export { E as EntitySharingMap, c as EventBus, d as EventNamespaceMap, e as InMemoryPersistence, O as OrbitalEventRequest,
|
|
1
|
+
import { h as RuntimePatternValue, B as BindingContext, f as EvaluationContextExtensions, P as PatternProps, E as EffectHandlers, g as EffectContext, i as ExecutionEnvironment, j as EffectResult, T as TraitDefinition } from './types-CWaIuEQn.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-CWaIuEQn.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-BiEntWd-.js';
|
|
4
|
+
export { C as CreateServerEffectHandlersOptions, E as EntitySharingMap, c as EventBus, d as EventNamespaceMap, e as InMemoryPersistence, f as LIFECYCLE_EVENTS, O as OrbitalEventRequest, g as OrbitalEventResponse, h as OrbitalServerRuntimeConfig, i as PreprocessOptions, j as PreprocessResult, k as PreprocessedSchema, l as ProcessEventOptions, R as RegisteredOrbital, m as RuntimeOrbital, n as RuntimeOrbitalSchema, o as RuntimeTrait, p as ServerEffectResult, q as StateMachineManager, r as collectDeclaredConfigDefaults, s as collectDeclaredEntityDefaults, t as createInitialTraitState, u as createServerEffectHandlers, v as findInitialState, w as findTransition, x as getIsolatedCollectionName, y as getNamespacedEvent, z as isBrowser, A as isElectron, B as isNamespacedEvent, D as isNode, F as normalizeEventKey, G as parseNamespacedEvent, H as preprocessSchema, J as processEvent } from './OrbitalServerRuntime-BiEntWd-.js';
|
|
5
5
|
import { EvaluationContext, SExpressionEvaluator } from '@almadar/evaluator';
|
|
6
6
|
export { EvaluationContext, createMinimalContext } from '@almadar/evaluator';
|
|
7
|
-
import { RenderBindingMarker, SExpr, RuntimeValue,
|
|
7
|
+
import { RenderBindingMarker, SExpr, RuntimeValue, EventPayload, PatternConfig, EntityId, EntityField, EntityRow, EntityPersistence, PayloadField, OrbitalDefinition, OrbitalSchema } from '@almadar/core';
|
|
8
8
|
export { EntityField, normalizeCallSiteConfigToValues } from '@almadar/core';
|
|
9
9
|
export { AccessBindings, applyRowAccess, checkMutationAccess } from './entityAccess.js';
|
|
10
10
|
export { ServerBridgeConfig, ServerBridgeState } from './ServerBridge.js';
|
|
@@ -268,23 +268,6 @@ declare function isValidDurationString(interval: string): boolean;
|
|
|
268
268
|
* @packageDocumentation
|
|
269
269
|
*/
|
|
270
270
|
|
|
271
|
-
/**
|
|
272
|
-
* Call-site payload capture grammar. Mirrors the Rust orbital-core
|
|
273
|
-
* `CALLSITE_PAYLOAD_PREFIX` (`@callsitePayload.`). A composed trait's call-site
|
|
274
|
-
* config value of this form is a snapshot of the COMPOSING effect's triggering
|
|
275
|
-
* event payload, captured at the call site — deliberately distinct from
|
|
276
|
-
* `@payload.` so it is never evaluated in the child's own INIT scope.
|
|
277
|
-
*/
|
|
278
|
-
declare const CALLSITE_PAYLOAD_PREFIX = "@callsitePayload.";
|
|
279
|
-
/**
|
|
280
|
-
* Resolve call-site payload captures in a child trait's call-site config
|
|
281
|
-
* against the COMPOSING effect's triggering event payload. Each value of the
|
|
282
|
-
* form `@callsitePayload.<field>` becomes the literal read from `payload`
|
|
283
|
-
* (snapshot semantics — the child sees a plain value, never a payload ref).
|
|
284
|
-
* Non-capture entries pass through untouched. Returns a new object; the input
|
|
285
|
-
* is not mutated.
|
|
286
|
-
*/
|
|
287
|
-
declare function resolveCallSitePayloadCaptures(config: TraitConfigObject, payload: EventPayload | undefined): TraitConfigObject;
|
|
288
271
|
/**
|
|
289
272
|
* Interpolate binding references in props.
|
|
290
273
|
*
|
|
@@ -481,6 +464,14 @@ declare class EffectExecutor {
|
|
|
481
464
|
* substrate-op args. Returns `[positionalArgs, emitConfig]`.
|
|
482
465
|
*/
|
|
483
466
|
private splitSubstrateEmit;
|
|
467
|
+
/**
|
|
468
|
+
* Dispatches one effect. Returns `void` for the ordinary case (the
|
|
469
|
+
* caller only cares whether it threw). A `persist` that resolves
|
|
470
|
+
* without throwing — the store DENIED the write, signalled by return
|
|
471
|
+
* value rather than an exception, per the "close the circuit" doctrine
|
|
472
|
+
* — reports that outcome here so `executeWithResults` can record it as
|
|
473
|
+
* `status: 'failed'` instead of the default `'executed'`.
|
|
474
|
+
*/
|
|
484
475
|
private dispatch;
|
|
485
476
|
private logUnsupported;
|
|
486
477
|
}
|
|
@@ -839,115 +830,6 @@ declare class MockPersistenceAdapter implements PersistenceAdapter {
|
|
|
839
830
|
*/
|
|
840
831
|
declare function createMockPersistence(config?: MockPersistenceConfig): MockPersistenceAdapter;
|
|
841
832
|
|
|
842
|
-
/**
|
|
843
|
-
* ServerEffectHandlers — reusable factory for the server-side effect layer.
|
|
844
|
-
*
|
|
845
|
-
* Mirrors the handlers built inline in
|
|
846
|
-
* `OrbitalServerRuntime.executeEffects` so both the real server runtime
|
|
847
|
-
* AND the in-browser mock runtime (`@almadar/ui` OrbPreview autoMock) can
|
|
848
|
-
* share the same `fetch` / `persist` / `set` / `ref` / `deref` / `swap!` /
|
|
849
|
-
* `atomic` / `callService` semantics against a `PersistenceAdapter`.
|
|
850
|
-
*
|
|
851
|
-
* Browser-safe: only imports core + this package's browser-safe modules.
|
|
852
|
-
* Does NOT import express/Node, so it is reachable from `@almadar/ui`.
|
|
853
|
-
*
|
|
854
|
-
* @packageDocumentation
|
|
855
|
-
*/
|
|
856
|
-
|
|
857
|
-
/**
|
|
858
|
-
* Minimal event-bus contract the server handlers need. Narrower than the
|
|
859
|
-
* full `IEventBus` so clients with a React-context bus (only `emit` is
|
|
860
|
-
* relevant for effect dispatch) can hand it in without adapter code.
|
|
861
|
-
*/
|
|
862
|
-
interface ServerEffectEventBus {
|
|
863
|
-
emit(event: string, payload?: EventPayload, source?: {
|
|
864
|
-
orbital?: string;
|
|
865
|
-
trait?: string;
|
|
866
|
-
}): void;
|
|
867
|
-
}
|
|
868
|
-
/**
|
|
869
|
-
* Result entry recorded for each effect invocation. Mirrors the server
|
|
870
|
-
* runtime's `EffectResult`. Callers who want telemetry pass an array that
|
|
871
|
-
* the factory appends to; otherwise it's unused.
|
|
872
|
-
*/
|
|
873
|
-
interface ServerEffectResult {
|
|
874
|
-
effect: "set" | "persist" | "call-service" | "fetch" | "ref" | "deref" | "swap" | "atomic";
|
|
875
|
-
action?: string;
|
|
876
|
-
entityType?: string;
|
|
877
|
-
data?: unknown;
|
|
878
|
-
success: boolean;
|
|
879
|
-
error?: string;
|
|
880
|
-
}
|
|
881
|
-
interface CreateServerEffectHandlersOptions {
|
|
882
|
-
/** Persistent store backing `fetch` / `persist` / `ref` / `deref` / `swap`. */
|
|
883
|
-
persistence: PersistenceAdapter;
|
|
884
|
-
/** Event bus that `emit` delegates to. Only `.emit()` is required. */
|
|
885
|
-
eventBus: ServerEffectEventBus;
|
|
886
|
-
/** The trait's linked entity type (used as the default for persist/set). */
|
|
887
|
-
entityType: string;
|
|
888
|
-
/** Current entity row id (used by `set`, `persist update/delete` fallback). */
|
|
889
|
-
entityId?: string;
|
|
890
|
-
/**
|
|
891
|
-
* Binding object passed to inner `atomic` evaluator. When absent, atomic
|
|
892
|
-
* effects still run but have no access to `@entity` / `@payload` bindings.
|
|
893
|
-
*/
|
|
894
|
-
bindings?: BindingContext;
|
|
895
|
-
/** Effect context passed to the inner `atomic` executor. */
|
|
896
|
-
context?: EffectContext;
|
|
897
|
-
/** Per-event result sink. Optional — telemetry only. */
|
|
898
|
-
effectResults?: ServerEffectResult[];
|
|
899
|
-
/**
|
|
900
|
-
* Per-event fetched-data cache. `fetch` writes here so downstream UI
|
|
901
|
-
* renderers can resolve `@entity` bindings from the latest load without
|
|
902
|
-
* a separate round-trip.
|
|
903
|
-
*/
|
|
904
|
-
fetchedData?: Record<string, EntityRow[]>;
|
|
905
|
-
/** Per-event emit log. Optional — telemetry only. */
|
|
906
|
-
emittedEvents?: Array<{
|
|
907
|
-
event: string;
|
|
908
|
-
payload?: EventPayload;
|
|
909
|
-
}>;
|
|
910
|
-
/** Source stamp applied to all emits. */
|
|
911
|
-
source?: {
|
|
912
|
-
orbital?: string;
|
|
913
|
-
trait?: string;
|
|
914
|
-
};
|
|
915
|
-
/** Consumer-supplied `call-service` handler. When absent, calls warn and return null. */
|
|
916
|
-
callService?: (service: string, action: string, params?: ServiceParams, context?: ServiceCallContext) => Promise<EventPayload | null>;
|
|
917
|
-
/**
|
|
918
|
-
* The declared `@read`/`@create`/`@update`/`@delete` directives, keyed by
|
|
919
|
-
* entity name. Build it with `entityAccessTable(schema)` from `@almadar/core`.
|
|
920
|
-
*
|
|
921
|
-
* Optional: a caller that holds no schema (the client offline-preview path)
|
|
922
|
-
* passes nothing and gets today's unrestricted behavior. A preview is not a
|
|
923
|
-
* security boundary — the generated server is, and that one always has the
|
|
924
|
-
* policies compiled in.
|
|
925
|
-
*/
|
|
926
|
-
entityAccess?: ReadonlyMap<string, EntityAccessPolicies>;
|
|
927
|
-
/** Verbose logging. */
|
|
928
|
-
debug?: boolean;
|
|
929
|
-
}
|
|
930
|
-
/**
|
|
931
|
-
* Build the full server-side effect handler set bound to a persistence
|
|
932
|
-
* adapter. The returned object satisfies `EffectHandlers` and can be
|
|
933
|
-
* handed directly to `EffectExecutor`.
|
|
934
|
-
*
|
|
935
|
-
* Scope: one handler object per transition — capture `entityId`,
|
|
936
|
-
* `bindings`, `context`, and the sink arrays at build time. For a new
|
|
937
|
-
* transition, call this factory again.
|
|
938
|
-
*
|
|
939
|
-
* Intentionally does NOT implement:
|
|
940
|
-
* - `renderUI` / `notify` / `navigate` — these are client-side, provided
|
|
941
|
-
* by `createClientEffectHandlers`. A mock runtime merges both handler
|
|
942
|
-
* sets.
|
|
943
|
-
* - `os/watch-*` observers — these are a no-op outside the server.
|
|
944
|
-
* - Schema-aware relation cardinality / on-delete cascades — those live
|
|
945
|
-
* in `OrbitalServerRuntime` and depend on the full registered schema.
|
|
946
|
-
* Clients that need them can wrap the persist handler with their own
|
|
947
|
-
* validation.
|
|
948
|
-
*/
|
|
949
|
-
declare function createServerEffectHandlers(opts: CreateServerEffectHandlersOptions): EffectHandlers;
|
|
950
|
-
|
|
951
833
|
/**
|
|
952
834
|
* PayloadValidator - Cross-Trait Payload Shape Validation (RCG-10)
|
|
953
835
|
*
|
|
@@ -1222,4 +1104,4 @@ declare namespace index {
|
|
|
1222
1104
|
export { type index_ComposeBehaviorsInput as ComposeBehaviorsInput, type index_ComposeBehaviorsResult as ComposeBehaviorsResult, type index_EventWiringEntry as EventWiringEntry, type index_LayoutStrategy as LayoutStrategy, type index_PipeStep as PipeStep, index_applyEventWiring as applyEventWiring, index_composeBehaviors as composeBehaviors, index_detectLayoutStrategy as detectLayoutStrategy, index_pipeBehaviors as pipeBehaviors };
|
|
1223
1105
|
}
|
|
1224
1106
|
|
|
1225
|
-
export { BindingContext,
|
|
1107
|
+
export { BindingContext, type ClientEventBus, type ComposeBehaviorsInput, type ComposeBehaviorsResult, type CreateClientEffectHandlersOptions, type CronFields, type DeferredPatternValue, EffectContext, EffectExecutor, type EffectExecutorOptions, EffectHandlers, EffectResult, type EntitySchema, type EventWiringEntry, ExecutionEnvironment, ImportChainLike, type LayoutStrategy, LoadResult, LoadedOrbital, LoadedSchema, MockPersistenceAdapter, type MockPersistenceConfig, type PayloadMismatch, type PayloadValidationFailure, PersistenceAdapter, type PipeStep, SchemaLoader, type SlotSetter, type TickHandle, TickScheduler, TraitDefinition, UnifiedLoaderOptions, applyEventWiring, buildEmitsFromTraits, composeBehaviors, index as composition, containsBindings, createClientEffectHandlers, createContextFromBindings, createMockPersistence, createTestExecutor, createTickScheduler, createUnifiedLoader, cronMatches, cronMinuteKey, deferEntityBindings, detectLayoutStrategy, extractBindings, formatPayloadValidationError, interpolateProps, interpolateValue, isValidCronExpression, isValidDurationString, parseCron, parseCronField, parseDurationString, pipeBehaviors, validateEventPayload, validatePayloadShapes };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { EffectExecutor } from './chunk-
|
|
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-
|
|
1
|
+
import { EffectExecutor } from './chunk-H7HQQVQJ.js';
|
|
2
|
+
export { EffectExecutor, EventBus, HANDLER_MANIFEST, InMemoryPersistence, LIFECYCLE_EVENTS, 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-H7HQQVQJ.js';
|
|
3
3
|
export { cronMatches, cronMinuteKey, isValidCronExpression, parseCron, parseCronField } from './chunk-OU3ITB5S.js';
|
|
4
|
-
import { createContextFromBindings, applyRowAccess, checkMutationAccess, accessDeniedMessage } from './chunk-
|
|
5
|
-
export {
|
|
4
|
+
import { createContextFromBindings, applyRowAccess, checkMutationAccess, accessDeniedMessage } from './chunk-ZWAOJT6R.js';
|
|
5
|
+
export { applyRowAccess, checkMutationAccess, containsBindings, createContextFromBindings, createMinimalContext, deferEntityBindings, extractBindings, interpolateProps, interpolateValue } from './chunk-ZWAOJT6R.js';
|
|
6
6
|
import './chunk-T4VDAB4C.js';
|
|
7
7
|
export { PERF_NAMESPACE, RendererContractViolationError, adjustSchemaForMockData, aggregateSlotContent, assertIsMultiSourceSlotManager, assertIsSlotManager, bindEventBus, bindTraitStateGetter, buildMockData, buildOrbitalsByTrait, clearPerf, createSlotSetter, ensureVerificationApi, getOrbitalVerification, perfEnd, perfGauge, perfStart, perfStore, perfTime, perfTimeAsync, prepareSchemaForPreview, pushPerfEntry, validateSlotContent, wrapCallbackForEvent } from './chunk-F5W3YZGJ.js';
|
|
8
8
|
export { collectEmbeddedTraits, collectTraitRefsFromResolvedTrait } from './chunk-SCRAHWOC.js';
|
|
@@ -283,10 +283,10 @@ function createServerEffectHandlers(opts) {
|
|
|
283
283
|
createData
|
|
284
284
|
);
|
|
285
285
|
batchResults.push({
|
|
286
|
+
...createData,
|
|
286
287
|
action: "create",
|
|
287
288
|
entityType: opEntityType,
|
|
288
|
-
id: newId
|
|
289
|
-
...createData
|
|
289
|
+
id: newId
|
|
290
290
|
});
|
|
291
291
|
completed.push({
|
|
292
292
|
action: "create",
|
|
@@ -301,10 +301,10 @@ function createServerEffectHandlers(opts) {
|
|
|
301
301
|
await persistence.update(opEntityType, updateId, updateData);
|
|
302
302
|
const updated = await persistence.getById(opEntityType, updateId);
|
|
303
303
|
batchResults.push({
|
|
304
|
+
...updated || updateData,
|
|
304
305
|
action: "update",
|
|
305
306
|
entityType: opEntityType,
|
|
306
|
-
id: updateId
|
|
307
|
-
...updated || updateData
|
|
307
|
+
id: updateId
|
|
308
308
|
});
|
|
309
309
|
completed.push({
|
|
310
310
|
action: "update",
|
|
@@ -358,15 +358,17 @@ function createServerEffectHandlers(opts) {
|
|
|
358
358
|
const type = targetEntityType || entityType;
|
|
359
359
|
let resultData;
|
|
360
360
|
const sizeBefore = (await persistence.list(type)).length;
|
|
361
|
+
let deniedReason;
|
|
361
362
|
try {
|
|
362
363
|
const mutationPolicy = entityAccess?.get(type)?.[action];
|
|
363
364
|
switch (action) {
|
|
364
365
|
case "create": {
|
|
365
366
|
if (!checkMutationAccess(data ?? {}, mutationPolicy, accessBindings(type))) {
|
|
367
|
+
deniedReason = "access-denied";
|
|
366
368
|
throw new Error(accessDeniedMessage("create", type));
|
|
367
369
|
}
|
|
368
370
|
const { id } = await persistence.create(type, data ?? {});
|
|
369
|
-
resultData = {
|
|
371
|
+
resultData = { ...data ?? {}, id };
|
|
370
372
|
break;
|
|
371
373
|
}
|
|
372
374
|
case "update": {
|
|
@@ -376,15 +378,17 @@ function createServerEffectHandlers(opts) {
|
|
|
376
378
|
if (mutationPolicy !== void 0) {
|
|
377
379
|
const existing = await persistence.getById(type, idOrFallback);
|
|
378
380
|
if (!existing || !checkMutationAccess(existing, mutationPolicy, accessBindings(type))) {
|
|
381
|
+
deniedReason = "access-denied";
|
|
379
382
|
throw new Error(accessDeniedMessage("update", type));
|
|
380
383
|
}
|
|
381
384
|
}
|
|
382
385
|
await persistence.update(type, idOrFallback, row);
|
|
383
386
|
const updated = await persistence.getById(type, idOrFallback);
|
|
384
|
-
resultData = updated ?? { id: idOrFallback
|
|
387
|
+
resultData = updated ?? { ...row, id: idOrFallback };
|
|
385
388
|
} else {
|
|
386
389
|
effectLog.error("persist:no-row-key", { action, entityType: type });
|
|
387
390
|
if (NO_ROW_KEY_IS_FATAL) {
|
|
391
|
+
deniedReason = "no-row-key";
|
|
388
392
|
throw new Error(
|
|
389
393
|
`persist ${action} ${type} resolved no row key \u2014 the id was neither on the row being written nor on the request. Bind it before the write, e.g. (set @entity.id ?row.id) on the transition that selects it.`
|
|
390
394
|
);
|
|
@@ -400,6 +404,7 @@ function createServerEffectHandlers(opts) {
|
|
|
400
404
|
if (mutationPolicy !== void 0) {
|
|
401
405
|
const existing = await persistence.getById(type, deleteId);
|
|
402
406
|
if (!existing || !checkMutationAccess(existing, mutationPolicy, accessBindings(type))) {
|
|
407
|
+
deniedReason = "access-denied";
|
|
403
408
|
throw new Error(accessDeniedMessage("delete", type));
|
|
404
409
|
}
|
|
405
410
|
}
|
|
@@ -408,6 +413,7 @@ function createServerEffectHandlers(opts) {
|
|
|
408
413
|
} else {
|
|
409
414
|
effectLog.error("persist:no-row-key", { action, entityType: type });
|
|
410
415
|
if (NO_ROW_KEY_IS_FATAL) {
|
|
416
|
+
deniedReason = "no-row-key";
|
|
411
417
|
throw new Error(
|
|
412
418
|
`persist ${action} ${type} resolved no row key \u2014 the id was neither on the row being written nor on the request. Bind it before the write, e.g. (set @entity.id ?row.id) on the transition that selects it.`
|
|
413
419
|
);
|
|
@@ -416,6 +422,17 @@ function createServerEffectHandlers(opts) {
|
|
|
416
422
|
break;
|
|
417
423
|
}
|
|
418
424
|
}
|
|
425
|
+
if (resultData === void 0 && (action === "update" || action === "delete")) {
|
|
426
|
+
record({
|
|
427
|
+
effect: "persist",
|
|
428
|
+
action,
|
|
429
|
+
entityType: type,
|
|
430
|
+
success: false,
|
|
431
|
+
denied: true,
|
|
432
|
+
error: `persist ${action} ${type} resolved no row key`
|
|
433
|
+
});
|
|
434
|
+
return void 0;
|
|
435
|
+
}
|
|
419
436
|
const sizeAfter = (await persistence.list(type)).length;
|
|
420
437
|
effectLog.debug("persist:store-mutate", {
|
|
421
438
|
action,
|
|
@@ -443,6 +460,7 @@ function createServerEffectHandlers(opts) {
|
|
|
443
460
|
effect: "persist",
|
|
444
461
|
action,
|
|
445
462
|
entityType: type,
|
|
463
|
+
...deniedReason !== void 0 ? { denied: true } : {},
|
|
446
464
|
success: false,
|
|
447
465
|
error: err instanceof Error ? err.message : String(err)
|
|
448
466
|
});
|
|
@@ -157,11 +157,31 @@ interface EffectHandlers {
|
|
|
157
157
|
* envelope carries. Without it a `*_CREATED` listener sees no id (the
|
|
158
158
|
* compiled path emits the created row), so anything routing on the new
|
|
159
159
|
* row's identity — navigating to the page just created — worked in one
|
|
160
|
-
* execution path only.
|
|
161
|
-
*
|
|
162
|
-
*
|
|
160
|
+
* execution path only.
|
|
161
|
+
*
|
|
162
|
+
* `create`/`update`/`delete` (batch is separate — see `PersistBatchSummary`)
|
|
163
|
+
* return `undefined` ONLY to signal the write was DENIED or otherwise
|
|
164
|
+
* failed (a policy rejection, a missing row key, a no-op stub) — never
|
|
165
|
+
* a genuine success with nothing to report, since every real success
|
|
166
|
+
* branch sets a row. The caller (`EffectExecutor`'s `persist` case)
|
|
167
|
+
* treats `undefined` as a failure: it skips the declared `success`
|
|
168
|
+
* emit entirely rather than falling back to the submitted data, which
|
|
169
|
+
* previously made a denied delete indistinguishable from a completed
|
|
170
|
+
* one.
|
|
163
171
|
*/
|
|
164
172
|
persist: (action: 'create' | 'update' | 'delete' | 'batch', entityType: string, data?: EntityRow) => Promise<EntityRow | undefined>;
|
|
173
|
+
/**
|
|
174
|
+
* Bridge mode: the SERVER executes every persist of this dispatch and
|
|
175
|
+
* returns the real outcome in its response (`effectResults`), so the
|
|
176
|
+
* client's `persist` member is a placeholder that must never be read as
|
|
177
|
+
* a denial. When `true`, `EffectExecutor` skips the persist locally —
|
|
178
|
+
* no `persist:denied` error, no client-side `failure` emit (which fired
|
|
179
|
+
* the declared failure event in the browser while the server had
|
|
180
|
+
* succeeded), no `success` emit either (the server's cascade carries it).
|
|
181
|
+
* Set by `@almadar/ui`'s `createClientEffectHandlers` when no live
|
|
182
|
+
* client entity is supplied; absent everywhere a handler really writes.
|
|
183
|
+
*/
|
|
184
|
+
persistDelegated?: true;
|
|
165
185
|
/** Set a field value on an entity */
|
|
166
186
|
set: (entityId: string, field: string, value: FieldValue) => void;
|
|
167
187
|
/** Call an external service. `context` carries the caller's identity
|
|
@@ -383,6 +403,16 @@ interface BindingContext {
|
|
|
383
403
|
* `let`-bound locals.
|
|
384
404
|
*/
|
|
385
405
|
locals?: Map<string, RuntimeValue>;
|
|
406
|
+
/**
|
|
407
|
+
* The composing effect's triggering payload, for a trait embedded via
|
|
408
|
+
* `@trait.X` inline into a parent's render-ui. Set when re-running an
|
|
409
|
+
* embedded child's lifecycle transition under its embedder's payload
|
|
410
|
+
* (see `OrbitalServerRuntime.executeEffects` / the client's
|
|
411
|
+
* `useTraitStateMachine`), so `@callsitePayload.<field>` resolves on the
|
|
412
|
+
* child's evaluation context — mirrors the compiled path's
|
|
413
|
+
* `CALLSITE_PAYLOAD_PREFIX` capture.
|
|
414
|
+
*/
|
|
415
|
+
callsitePayload?: EventPayload;
|
|
386
416
|
/** Additional custom bindings */
|
|
387
417
|
[key: string]: unknown;
|
|
388
418
|
}
|
|
@@ -512,4 +542,4 @@ interface TransitionObserver {
|
|
|
512
542
|
*/
|
|
513
543
|
declare const HANDLER_MANIFEST: Record<ExecutionEnvironment, string[]>;
|
|
514
544
|
|
|
515
|
-
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
|
|
545
|
+
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 EffectContext as g, type RuntimePatternValue 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.
|
|
3
|
+
"version": "6.73.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.
|
|
61
|
-
"@almadar/evaluator": "^2.
|
|
60
|
+
"@almadar/core": "^10.88.0",
|
|
61
|
+
"@almadar/evaluator": "^2.45.0",
|
|
62
62
|
"@almadar/logger": "^1.12.0",
|
|
63
|
-
"@almadar/server": "^2.
|
|
64
|
-
"@almadar/std": "^16.
|
|
63
|
+
"@almadar/server": "^2.40.0",
|
|
64
|
+
"@almadar/std": "^16.209.0"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"express": "^5.0.0"
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
-
"@almadar/eslint-plugin": "^2.
|
|
75
|
+
"@almadar/eslint-plugin": "^2.18.0",
|
|
76
76
|
"@types/express": "^5.0.0",
|
|
77
77
|
"@types/node": "^20.0.0",
|
|
78
78
|
"@typescript-eslint/parser": "8.65.0",
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"build": "tsup",
|
|
103
103
|
"build:watch": "tsup --watch",
|
|
104
104
|
"lint": "eslint src/",
|
|
105
|
-
"typecheck": "tsc --noEmit",
|
|
105
|
+
"typecheck": "tsc --noEmit -p tsconfig.typecheck.json",
|
|
106
106
|
"test": "vitest --run"
|
|
107
107
|
}
|
|
108
108
|
}
|