@constela/runtime 0.8.0 → 0.9.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/index.d.ts CHANGED
@@ -56,6 +56,7 @@ interface EvaluationContext {
56
56
  path: string;
57
57
  };
58
58
  imports?: Record<string, unknown>;
59
+ refs?: Record<string, Element>;
59
60
  }
60
61
  declare function evaluate(expr: CompiledExpression, ctx: EvaluationContext): unknown;
61
62
 
@@ -76,6 +77,8 @@ interface ActionContext {
76
77
  actions: Record<string, CompiledAction>;
77
78
  locals: Record<string, unknown>;
78
79
  eventPayload?: unknown;
80
+ refs?: Record<string, Element>;
81
+ subscriptions?: (() => void)[];
79
82
  }
80
83
  declare function executeAction(action: CompiledAction, ctx: ActionContext): Promise<void>;
81
84
 
package/dist/index.js CHANGED
@@ -193,6 +193,8 @@ function evaluate(expr, ctx) {
193
193
  }
194
194
  return importData;
195
195
  }
196
+ case "ref":
197
+ return ctx.refs?.[expr.name] ?? null;
196
198
  default: {
197
199
  const _exhaustiveCheck = expr;
198
200
  throw new Error(`Unknown expression type: ${JSON.stringify(_exhaustiveCheck)}`);
@@ -418,6 +420,18 @@ async function executeStep(step, ctx) {
418
420
  case "navigate":
419
421
  await executeNavigateStep(step, ctx);
420
422
  break;
423
+ case "import":
424
+ await executeImportStep(step, ctx);
425
+ break;
426
+ case "call":
427
+ await executeCallStep(step, ctx);
428
+ break;
429
+ case "subscribe":
430
+ await executeSubscribeStep(step, ctx);
431
+ break;
432
+ case "dispose":
433
+ await executeDisposeStep(step, ctx);
434
+ break;
421
435
  }
422
436
  }
423
437
  async function executeSetStep(target, value, ctx) {
@@ -534,13 +548,21 @@ async function executeFetchStep(step, ctx) {
534
548
  }
535
549
  }
536
550
  } else {
551
+ ctx.locals["error"] = {
552
+ message: `HTTP error: ${response.status} ${response.statusText}`,
553
+ name: "HTTPError"
554
+ };
537
555
  if (step.onError) {
538
556
  for (const errorStep of step.onError) {
539
557
  await executeStep(errorStep, ctx);
540
558
  }
541
559
  }
542
560
  }
543
- } catch (_error) {
561
+ } catch (err) {
562
+ ctx.locals["error"] = {
563
+ message: err instanceof Error ? err.message : String(err),
564
+ name: err instanceof Error ? err.name : "Error"
565
+ };
544
566
  if (step.onError) {
545
567
  for (const errorStep of step.onError) {
546
568
  await executeStep(errorStep, ctx);
@@ -581,7 +603,11 @@ async function executeStorageStep(step, ctx) {
581
603
  await executeStep(successStep, ctx);
582
604
  }
583
605
  }
584
- } catch (_error) {
606
+ } catch (err) {
607
+ ctx.locals["error"] = {
608
+ message: err instanceof Error ? err.message : String(err),
609
+ name: err instanceof Error ? err.name : "Error"
610
+ };
585
611
  if (step.onError) {
586
612
  for (const errorStep of step.onError) {
587
613
  await executeStep(errorStep, ctx);
@@ -612,7 +638,11 @@ async function executeClipboardStep(step, ctx) {
612
638
  await executeStep(successStep, ctx);
613
639
  }
614
640
  }
615
- } catch (_error) {
641
+ } catch (err) {
642
+ ctx.locals["error"] = {
643
+ message: err instanceof Error ? err.message : String(err),
644
+ name: err instanceof Error ? err.name : "Error"
645
+ };
616
646
  if (step.onError) {
617
647
  for (const errorStep of step.onError) {
618
648
  await executeStep(errorStep, ctx);
@@ -632,6 +662,98 @@ async function executeNavigateStep(step, ctx) {
632
662
  window.location.assign(url);
633
663
  }
634
664
  }
665
+ async function executeImportStep(step, ctx) {
666
+ try {
667
+ const module = await import(
668
+ /* @vite-ignore */
669
+ step.module
670
+ );
671
+ ctx.locals[step.result] = module;
672
+ if (step.onSuccess) {
673
+ for (const successStep of step.onSuccess) {
674
+ await executeStep(successStep, ctx);
675
+ }
676
+ }
677
+ } catch (err) {
678
+ ctx.locals["error"] = {
679
+ message: err instanceof Error ? err.message : String(err),
680
+ name: err instanceof Error ? err.name : "Error"
681
+ };
682
+ if (step.onError) {
683
+ for (const errorStep of step.onError) {
684
+ await executeStep(errorStep, ctx);
685
+ }
686
+ }
687
+ }
688
+ }
689
+ async function executeCallStep(step, ctx) {
690
+ const evalCtx = { state: ctx.state, locals: ctx.locals, ...ctx.refs && { refs: ctx.refs } };
691
+ try {
692
+ const target = evaluate(step.target, evalCtx);
693
+ const args = step.args?.map((arg) => evaluate(arg, evalCtx)) ?? [];
694
+ if (typeof target === "function") {
695
+ const result = await target(...args);
696
+ if (step.result) {
697
+ ctx.locals[step.result] = result;
698
+ }
699
+ } else {
700
+ throw new Error(`Target is not callable: received ${typeof target}`);
701
+ }
702
+ if (step.onSuccess) {
703
+ for (const successStep of step.onSuccess) {
704
+ await executeStep(successStep, ctx);
705
+ }
706
+ }
707
+ } catch (err) {
708
+ ctx.locals["error"] = {
709
+ message: err instanceof Error ? err.message : String(err),
710
+ name: err instanceof Error ? err.name : "Error"
711
+ };
712
+ if (step.onError) {
713
+ for (const errorStep of step.onError) {
714
+ await executeStep(errorStep, ctx);
715
+ }
716
+ }
717
+ }
718
+ }
719
+ async function executeSubscribeStep(step, ctx) {
720
+ const evalCtx = { state: ctx.state, locals: ctx.locals, ...ctx.refs && { refs: ctx.refs } };
721
+ const target = evaluate(step.target, evalCtx);
722
+ if (target && typeof target === "object" && step.event in target) {
723
+ const eventMethod = target[step.event];
724
+ if (typeof eventMethod === "function") {
725
+ const disposable = eventMethod.call(target, async (eventData) => {
726
+ const action = ctx.actions[step.action];
727
+ if (action) {
728
+ const subscriptionCtx = {
729
+ ...ctx,
730
+ locals: { ...ctx.locals, event: eventData }
731
+ };
732
+ await executeAction(action, subscriptionCtx);
733
+ }
734
+ });
735
+ if (ctx.subscriptions) {
736
+ if (disposable && typeof disposable === "object" && "dispose" in disposable && typeof disposable.dispose === "function") {
737
+ ctx.subscriptions.push(() => disposable.dispose());
738
+ } else if (typeof disposable === "function") {
739
+ ctx.subscriptions.push(disposable);
740
+ }
741
+ }
742
+ }
743
+ }
744
+ }
745
+ async function executeDisposeStep(step, ctx) {
746
+ const evalCtx = { state: ctx.state, locals: ctx.locals, ...ctx.refs && { refs: ctx.refs } };
747
+ const target = evaluate(step.target, evalCtx);
748
+ if (target && typeof target === "object") {
749
+ const obj = target;
750
+ if (typeof obj["dispose"] === "function") {
751
+ obj["dispose"]();
752
+ } else if (typeof obj["destroy"] === "function") {
753
+ obj["destroy"]();
754
+ }
755
+ }
756
+ }
635
757
 
636
758
  // src/renderer/markdown.ts
637
759
  import { marked } from "marked";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constela/runtime",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Runtime DOM renderer for Constela UI framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,8 +18,8 @@
18
18
  "dompurify": "^3.3.1",
19
19
  "marked": "^17.0.1",
20
20
  "shiki": "^3.20.0",
21
- "@constela/compiler": "0.5.0",
22
- "@constela/core": "0.5.0"
21
+ "@constela/compiler": "0.6.0",
22
+ "@constela/core": "0.6.0"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/dompurify": "^3.2.0",
@@ -29,7 +29,7 @@
29
29
  "tsup": "^8.0.0",
30
30
  "typescript": "^5.3.0",
31
31
  "vitest": "^2.0.0",
32
- "@constela/server": "1.0.0"
32
+ "@constela/server": "2.0.0"
33
33
  },
34
34
  "engines": {
35
35
  "node": ">=20.0.0"