@almadar/runtime 6.54.0 → 6.56.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-Cz5MiWKB.d.ts → OrbitalServerRuntime-Bh4fHBkb.d.ts} +26 -4
- package/dist/OrbitalServerRuntime.d.ts +2 -2
- package/dist/OrbitalServerRuntime.js +89 -5
- package/dist/ServerBridge.d.ts +1 -1
- package/dist/{chunk-DERIA6MO.js → chunk-XY5BLZKS.js} +43 -4
- package/dist/createOsHandlers.d.ts +1 -1
- package/dist/index.d.ts +19 -6
- package/dist/index.js +6 -3
- package/dist/{types-BcPORH_x.d.ts → types-BWENk-qT.d.ts} +12 -4
- package/package.json +4 -4
|
@@ -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-
|
|
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';
|
|
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;
|
|
@@ -1296,6 +1299,25 @@ declare class OrbitalServerRuntime {
|
|
|
1296
1299
|
* Clear the preprocessing cache.
|
|
1297
1300
|
*/
|
|
1298
1301
|
clearPreprocessCache(): void;
|
|
1302
|
+
/**
|
|
1303
|
+
* Resolve an entity definition by name across every registered orbital's
|
|
1304
|
+
* resolved primary entity. Used by relation-option injection to find the
|
|
1305
|
+
* relation TARGET entity (usually another orbital's primary).
|
|
1306
|
+
*/
|
|
1307
|
+
private findEntityDefByName;
|
|
1308
|
+
/**
|
|
1309
|
+
* Server-side relation-option injection — the interpreter's mirror of the
|
|
1310
|
+
* compiled path's build-time `relationsData` generation (orbital-rust
|
|
1311
|
+
* registry.rs). Walks a render-ui pattern tree; for every form pattern
|
|
1312
|
+
* (form / form-section / inline-edit-form / wizard-step) and detail-panel
|
|
1313
|
+
* whose linked entity declares relation-typed fields among the node's
|
|
1314
|
+
* `fields`, reads the relation TARGET entity's rows from the persistence
|
|
1315
|
+
* adapter and attaches `relationsData: { <field>: [{value, label}] }`.
|
|
1316
|
+
* Label contract identical to codegen: `name || title || id`. Options are
|
|
1317
|
+
* re-read on every render-ui, so they refresh with each re-render exactly
|
|
1318
|
+
* like any fetch. Authored `relationsData` is never overwritten.
|
|
1319
|
+
*/
|
|
1320
|
+
private injectRelationOptions;
|
|
1299
1321
|
/**
|
|
1300
1322
|
* Register a single orbital
|
|
1301
1323
|
*/
|
|
@@ -1471,4 +1493,4 @@ declare class OrbitalServerRuntime {
|
|
|
1471
1493
|
*/
|
|
1472
1494
|
declare function createOrbitalServerRuntime(config?: OrbitalServerRuntimeConfig): OrbitalServerRuntime;
|
|
1473
1495
|
|
|
1474
|
-
export { normalizeEventKey as A, parseNamespacedEvent as B, preprocessSchema as C, processEvent as D, type EntitySharingMap as E, type ClientEffectTuple as F, type
|
|
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
|
|
3
|
-
import './types-
|
|
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';
|
|
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-
|
|
2
|
-
export { InMemoryPersistence, collectDeclaredConfigDefaults } from './chunk-
|
|
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';
|
|
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';
|
|
@@ -10,6 +10,7 @@ import * as nodeModule from 'module';
|
|
|
10
10
|
import { evaluateListenPayloadExpr, evaluateGuard, evaluate } from '@almadar/evaluator';
|
|
11
11
|
import { DEFAULT_VIEWER, buildResolvedTraitConfigs, isInlineTrait, isEntityCall, applyListenPayloadMapping, personaFromIdentityRow, normalizeUserContext, isRuntimeEntity, isPageReference } from '@almadar/core';
|
|
12
12
|
import { ownerFieldsFromSchema, identityEntityName, entityAccessPolicies } from '@almadar/core/mock';
|
|
13
|
+
import { getPatternFieldsContract } from '@almadar/core/patterns';
|
|
13
14
|
|
|
14
15
|
// src/identity/routing.ts
|
|
15
16
|
function eventRouteKey(eventName, eventId) {
|
|
@@ -527,6 +528,81 @@ var OrbitalServerRuntime = class {
|
|
|
527
528
|
clearPreprocessCache() {
|
|
528
529
|
this.preprocessedCache.clear();
|
|
529
530
|
}
|
|
531
|
+
/**
|
|
532
|
+
* Resolve an entity definition by name across every registered orbital's
|
|
533
|
+
* resolved primary entity. Used by relation-option injection to find the
|
|
534
|
+
* relation TARGET entity (usually another orbital's primary).
|
|
535
|
+
*/
|
|
536
|
+
findEntityDefByName(name) {
|
|
537
|
+
for (const registered of this.orbitals.values()) {
|
|
538
|
+
if (registered.entity?.name === name) return registered.entity;
|
|
539
|
+
}
|
|
540
|
+
return void 0;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Server-side relation-option injection — the interpreter's mirror of the
|
|
544
|
+
* compiled path's build-time `relationsData` generation (orbital-rust
|
|
545
|
+
* registry.rs). Walks a render-ui pattern tree; for every form pattern
|
|
546
|
+
* (form / form-section / inline-edit-form / wizard-step) and detail-panel
|
|
547
|
+
* whose linked entity declares relation-typed fields among the node's
|
|
548
|
+
* `fields`, reads the relation TARGET entity's rows from the persistence
|
|
549
|
+
* adapter and attaches `relationsData: { <field>: [{value, label}] }`.
|
|
550
|
+
* Label contract identical to codegen: `name || title || id`. Options are
|
|
551
|
+
* re-read on every render-ui, so they refresh with each re-render exactly
|
|
552
|
+
* like any fetch. Authored `relationsData` is never overwritten.
|
|
553
|
+
*/
|
|
554
|
+
async injectRelationOptions(pattern, registered, traitName) {
|
|
555
|
+
if (pattern === null || typeof pattern !== "object") return;
|
|
556
|
+
const linkedEntityName = registered.traits.find((t) => t.name === traitName)?.linkedEntity ?? registered.entity?.name;
|
|
557
|
+
if (!linkedEntityName) return;
|
|
558
|
+
const entityDef = this.findEntityDefByName(linkedEntityName);
|
|
559
|
+
if (!entityDef?.fields) return;
|
|
560
|
+
const relationTargets = /* @__PURE__ */ new Map();
|
|
561
|
+
for (const field of entityDef.fields) {
|
|
562
|
+
if (field.type === "relation" && field.relation?.entity && field.name) {
|
|
563
|
+
relationTargets.set(field.name, field.relation.entity);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
if (relationTargets.size === 0) return;
|
|
567
|
+
const visit = async (node) => {
|
|
568
|
+
if (node === null || node === void 0 || typeof node !== "object") return;
|
|
569
|
+
if (Array.isArray(node)) {
|
|
570
|
+
for (const child of node) await visit(child);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
const record = node;
|
|
574
|
+
const nodeType = record["type"];
|
|
575
|
+
const fields = record["fields"];
|
|
576
|
+
if (typeof nodeType === "string" && // Which patterns consume entity-bound field lists is DECLARED per
|
|
577
|
+
// component via `@fieldsContract` and read from the pattern registry
|
|
578
|
+
// — never a hardcoded name list. Both contracts get relation options
|
|
579
|
+
// (form selects need choices; display fields need label resolution).
|
|
580
|
+
getPatternFieldsContract(nodeType) !== void 0 && Array.isArray(fields) && record["relationsData"] === void 0) {
|
|
581
|
+
const relationsData = {};
|
|
582
|
+
for (const fieldEntry of fields) {
|
|
583
|
+
const fieldName = typeof fieldEntry === "string" ? fieldEntry : fieldEntry !== null && typeof fieldEntry === "object" && !Array.isArray(fieldEntry) ? String(
|
|
584
|
+
fieldEntry["name"] ?? fieldEntry["key"] ?? ""
|
|
585
|
+
) : "";
|
|
586
|
+
const targetEntity = fieldName ? relationTargets.get(fieldName) : void 0;
|
|
587
|
+
if (!targetEntity) continue;
|
|
588
|
+
try {
|
|
589
|
+
const rows = await this.persistence.list(targetEntity);
|
|
590
|
+
relationsData[fieldName] = rows.map((r) => ({
|
|
591
|
+
value: String(r.id ?? ""),
|
|
592
|
+
label: String(r.name ?? r.title ?? r.id ?? "")
|
|
593
|
+
}));
|
|
594
|
+
} catch {
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
if (Object.keys(relationsData).length > 0) {
|
|
598
|
+
record["relationsData"] = relationsData;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
const children = record["children"];
|
|
602
|
+
if (children !== void 0) await visit(children);
|
|
603
|
+
};
|
|
604
|
+
await visit(pattern);
|
|
605
|
+
}
|
|
530
606
|
/**
|
|
531
607
|
* Register a single orbital
|
|
532
608
|
*/
|
|
@@ -1675,7 +1751,8 @@ var OrbitalServerRuntime = class {
|
|
|
1675
1751
|
}
|
|
1676
1752
|
},
|
|
1677
1753
|
// Client-side effects - collect for forwarding to client
|
|
1678
|
-
renderUI: (slot, pattern, props, priority) => {
|
|
1754
|
+
renderUI: async (slot, pattern, props, priority) => {
|
|
1755
|
+
await this.injectRelationOptions(pattern, registered, traitName);
|
|
1679
1756
|
const patternNode = pattern !== null && typeof pattern === "object" && !Array.isArray(pattern) ? pattern : null;
|
|
1680
1757
|
const patternEntity = patternNode?.entity;
|
|
1681
1758
|
const entityRow = patternEntity !== null && typeof patternEntity === "object" && !Array.isArray(patternEntity) ? patternEntity : null;
|
|
@@ -1689,8 +1766,15 @@ var OrbitalServerRuntime = class {
|
|
|
1689
1766
|
});
|
|
1690
1767
|
pushClientEffect(["render-ui", slot, pattern, props, priority]);
|
|
1691
1768
|
},
|
|
1692
|
-
navigate: (path, params) => {
|
|
1693
|
-
|
|
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"]);
|
|
1694
1778
|
},
|
|
1695
1779
|
notify: (message, type) => {
|
|
1696
1780
|
if (this.config.debug) {
|
package/dist/ServerBridge.d.ts
CHANGED
|
@@ -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,
|
|
@@ -1563,7 +1565,7 @@ var EffectExecutor = class _EffectExecutor {
|
|
|
1563
1565
|
const pattern = patternRaw === null ? null : patternRaw;
|
|
1564
1566
|
const props = args[2];
|
|
1565
1567
|
const priority = args[3];
|
|
1566
|
-
this.handlers.renderUI(slot, pattern, props, priority);
|
|
1568
|
+
await this.handlers.renderUI(slot, pattern, props, priority);
|
|
1567
1569
|
} else {
|
|
1568
1570
|
this.logUnsupported("render-ui");
|
|
1569
1571
|
}
|
|
@@ -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
|
-
|
|
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];
|
|
@@ -2101,7 +2117,7 @@ var mockLog = createLogger("almadar:runtime:mock");
|
|
|
2101
2117
|
var DEFAULT_MOCK_SEED = 42;
|
|
2102
2118
|
var SEED_REFERENCE_TIMESTAMP = "2024-01-01T00:00:00.000Z";
|
|
2103
2119
|
var MS_PER_DAY = 864e5;
|
|
2104
|
-
var MockPersistenceAdapter = class {
|
|
2120
|
+
var MockPersistenceAdapter = class _MockPersistenceAdapter {
|
|
2105
2121
|
stores = /* @__PURE__ */ new Map();
|
|
2106
2122
|
schemas = /* @__PURE__ */ new Map();
|
|
2107
2123
|
idCounters = /* @__PURE__ */ new Map();
|
|
@@ -2349,6 +2365,7 @@ var MockPersistenceAdapter = class {
|
|
|
2349
2365
|
// ============================================================================
|
|
2350
2366
|
async create(entityType, data) {
|
|
2351
2367
|
const store = this.getStore(entityType);
|
|
2368
|
+
this.assertFileValuesWithinCeiling(entityType, data);
|
|
2352
2369
|
const id = this.nextId(entityType);
|
|
2353
2370
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2354
2371
|
const withDefaults = this.applyFieldDefaults(entityType, data);
|
|
@@ -2361,6 +2378,27 @@ var MockPersistenceAdapter = class {
|
|
|
2361
2378
|
store.set(id, item);
|
|
2362
2379
|
return { id };
|
|
2363
2380
|
}
|
|
2381
|
+
/**
|
|
2382
|
+
* Mock-mode file storage ceiling: a `file`-typed value whose `url` is a
|
|
2383
|
+
* `data:` URI keeps the whole payload in this in-memory/localStorage
|
|
2384
|
+
* store. Above the ceiling the write is REJECTED with a clear error —
|
|
2385
|
+
* never silently truncated or corrupted. Real deployments store bytes in
|
|
2386
|
+
* object storage and keep only the URL, so the ceiling is mock-only.
|
|
2387
|
+
*/
|
|
2388
|
+
static FILE_DATA_URI_CEILING_BYTES = 2 * 1024 * 1024;
|
|
2389
|
+
assertFileValuesWithinCeiling(entityType, data) {
|
|
2390
|
+
for (const [fieldName, value] of Object.entries(data)) {
|
|
2391
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) continue;
|
|
2392
|
+
const candidate = value;
|
|
2393
|
+
if (typeof candidate.url !== "string" || !candidate.url.startsWith("data:")) continue;
|
|
2394
|
+
const bytes = typeof candidate.sizeBytes === "number" ? candidate.sizeBytes : candidate.url.length;
|
|
2395
|
+
if (bytes > _MockPersistenceAdapter.FILE_DATA_URI_CEILING_BYTES) {
|
|
2396
|
+
throw new Error(
|
|
2397
|
+
`${entityType}.${fieldName}: the playground mock store cannot persist files larger than ${_MockPersistenceAdapter.FILE_DATA_URI_CEILING_BYTES / (1024 * 1024)}MB (got ${(bytes / (1024 * 1024)).toFixed(1)}MB). Use a smaller file - production deployments store file bytes in object storage instead of the row.`
|
|
2398
|
+
);
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2364
2402
|
/**
|
|
2365
2403
|
* Fill in any entity-declared field defaults that the caller omitted.
|
|
2366
2404
|
* SAVE payloads coming from form-section only carry the fields the user
|
|
@@ -2382,6 +2420,7 @@ var MockPersistenceAdapter = class {
|
|
|
2382
2420
|
}
|
|
2383
2421
|
async update(entityType, id, data) {
|
|
2384
2422
|
const store = this.getStore(entityType);
|
|
2423
|
+
this.assertFileValuesWithinCeiling(entityType, data);
|
|
2385
2424
|
const existing = store.get(id);
|
|
2386
2425
|
if (!existing) {
|
|
2387
2426
|
throw new Error(`Entity ${entityType} with id ${id} not found`);
|
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-
|
|
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, 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-
|
|
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';
|
|
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
|
/**
|
|
@@ -686,6 +690,15 @@ declare class MockPersistenceAdapter implements PersistenceAdapter {
|
|
|
686
690
|
create(entityType: string, data: EntityRow): Promise<{
|
|
687
691
|
id: string;
|
|
688
692
|
}>;
|
|
693
|
+
/**
|
|
694
|
+
* Mock-mode file storage ceiling: a `file`-typed value whose `url` is a
|
|
695
|
+
* `data:` URI keeps the whole payload in this in-memory/localStorage
|
|
696
|
+
* store. Above the ceiling the write is REJECTED with a clear error —
|
|
697
|
+
* never silently truncated or corrupted. Real deployments store bytes in
|
|
698
|
+
* object storage and keep only the URL, so the ceiling is mock-only.
|
|
699
|
+
*/
|
|
700
|
+
private static readonly FILE_DATA_URI_CEILING_BYTES;
|
|
701
|
+
private assertFileValuesWithinCeiling;
|
|
689
702
|
/**
|
|
690
703
|
* Fill in any entity-declared field defaults that the caller omitted.
|
|
691
704
|
* SAVE payloads coming from form-section only carry the fields the user
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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-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';
|
|
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';
|
|
@@ -57,7 +57,7 @@ function sendServerEvent(orbital, event, payload) {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
function createClientEffectHandlers(options) {
|
|
60
|
-
const { eventBus, slotSetter, navigate, notify, sendServer, orbitalName = "" } = options;
|
|
60
|
+
const { eventBus, slotSetter, navigate, navigateBack, notify, sendServer, orbitalName = "" } = options;
|
|
61
61
|
return {
|
|
62
62
|
emit: (event, payload) => {
|
|
63
63
|
const prefixedEvent = event.startsWith("UI:") ? event : `UI:${event}`;
|
|
@@ -87,6 +87,9 @@ function createClientEffectHandlers(options) {
|
|
|
87
87
|
}
|
|
88
88
|
log.warn("navigate-no-handler", { path });
|
|
89
89
|
}),
|
|
90
|
+
navigateBack: navigateBack ?? (() => {
|
|
91
|
+
log.warn("navigate-back-no-handler");
|
|
92
|
+
}),
|
|
90
93
|
notify: notify ?? ((msg, type) => {
|
|
91
94
|
log.debug("notify", { type: type ?? null, message: msg });
|
|
92
95
|
}),
|
|
@@ -183,12 +183,20 @@ interface EffectHandlers {
|
|
|
183
183
|
sendServer?: (event: string, payload?: EventPayload) => void;
|
|
184
184
|
/** Render UI to a slot (client only). `pattern` is the post-interpolation
|
|
185
185
|
* `PatternConfig` from the trait's `(render-ui slot pattern)` SExpr, or
|
|
186
|
-
* `null` when the trait clears the slot (`render-ui slot null`).
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
* `null` when the trait clears the slot (`render-ui slot null`).
|
|
187
|
+
* May be async: the server runtime injects relation option data
|
|
188
|
+
* (relationsData) read from the persistence adapter before pushing —
|
|
189
|
+
* the interpreter's mirror of codegen's build-time relationsData. */
|
|
190
|
+
renderUI?: (slot: string, pattern: PatternConfig | null, props?: PatternProps, priority?: number) => void | Promise<void>;
|
|
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). */
|
|
189
194
|
navigate?: (path: string, params?: {
|
|
190
195
|
[key: string]: string;
|
|
191
|
-
}) => void;
|
|
196
|
+
}, crumb?: string) => void;
|
|
197
|
+
/** Pop the orbital-scoped navigation stack and return to the previous
|
|
198
|
+
* entry (client only). */
|
|
199
|
+
navigateBack?: () => void;
|
|
192
200
|
/** Show a notification (client: toast, server: log) */
|
|
193
201
|
notify?: (message: string, type: 'success' | 'error' | 'warning' | 'info') => void;
|
|
194
202
|
/** Log a message */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@almadar/runtime",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.56.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.
|
|
60
|
+
"@almadar/core": "^10.64.0",
|
|
61
61
|
"@almadar/evaluator": "^2.41.0",
|
|
62
62
|
"@almadar/logger": "^1.11.0",
|
|
63
|
-
"@almadar/server": "^2.
|
|
64
|
-
"@almadar/std": "^16.
|
|
63
|
+
"@almadar/server": "^2.35.0",
|
|
64
|
+
"@almadar/std": "^16.180.0"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"express": "^5.0.0"
|