apprun 3.37.3 → 3.38.1

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.
Files changed (65) hide show
  1. package/.claude/settings.local.json +18 -0
  2. package/.docs/done/2026/07/13/explicit-pretty-links.md +32 -0
  3. package/.docs/done/2026/07/13/first-render-dom-attributes.md +18 -0
  4. package/.docs/plans/2026/07/13/plan-explicit-pretty-links.md +119 -0
  5. package/.docs/plans/2026/07/13/plan-first-render-dom-attributes.md +66 -0
  6. package/.docs/plans/2026/07/13/plan-play-typescript-runtime.md +77 -0
  7. package/.docs/plans/2026/07/13/plan-release-3-38-1-docs.md +74 -0
  8. package/.docs/reqs/2026/07/13/req-explicit-pretty-links.md +46 -0
  9. package/.docs/reqs/2026/07/13/req-first-render-dom-attributes.md +31 -0
  10. package/.docs/reqs/2026/07/13/req-play-typescript-runtime.md +29 -0
  11. package/.docs/reqs/2026/07/13/req-release-3-38-1-docs.md +34 -0
  12. package/.playwright-mcp/console-2026-06-24T18-37-47-881Z.log +17 -0
  13. package/CHANGELOG.md +14 -1
  14. package/README.md +3 -2
  15. package/WHATSNEW.md +32 -6
  16. package/ai/apprun.prompt.md +545 -109
  17. package/apprun.d.ts +21 -6
  18. package/cli/app.js +7 -0
  19. package/dist/apprun-code.js +1 -1
  20. package/dist/apprun-code.js.map +1 -1
  21. package/dist/apprun-dev-tools.js +1 -1
  22. package/dist/apprun-dev-tools.js.map +1 -1
  23. package/dist/apprun-html.esm.js +7 -7
  24. package/dist/apprun-html.esm.js.map +1 -1
  25. package/dist/apprun-html.js +1 -1
  26. package/dist/apprun-html.js.map +1 -1
  27. package/dist/apprun-play-html.esm.js +7 -7
  28. package/dist/apprun-play-html.esm.js.map +1 -1
  29. package/dist/apprun-play.js +1 -1
  30. package/dist/apprun-play.js.map +1 -1
  31. package/dist/apprun.esm.js +1 -1
  32. package/dist/apprun.esm.js.map +1 -1
  33. package/dist/apprun.js +1 -1
  34. package/dist/apprun.js.map +1 -1
  35. package/dist/createState.js.map +1 -1
  36. package/esm/apprun-code.js +15 -3
  37. package/esm/apprun-code.js.map +1 -1
  38. package/esm/apprun-play.js +8 -2
  39. package/esm/apprun-play.js.map +1 -1
  40. package/esm/apprun.js +16 -8
  41. package/esm/apprun.js.map +1 -1
  42. package/esm/directive.js +129 -8
  43. package/esm/directive.js.map +1 -1
  44. package/esm/router.js +3 -2
  45. package/esm/router.js.map +1 -1
  46. package/esm/types.js +1 -0
  47. package/esm/types.js.map +1 -1
  48. package/esm/vdom-my-prop-attr.js +5 -11
  49. package/esm/vdom-my-prop-attr.js.map +1 -1
  50. package/esm/version.js +1 -1
  51. package/jsx-runtime.js +1 -1
  52. package/jsx-runtime.js.map +1 -1
  53. package/package.json +1 -1
  54. package/src/apprun-code.tsx +15 -3
  55. package/src/apprun-play.tsx +9 -3
  56. package/src/apprun.ts +18 -10
  57. package/src/component.ts +1 -1
  58. package/src/createState.ts +1 -1
  59. package/src/directive.ts +132 -7
  60. package/src/global.d.ts +2 -2
  61. package/src/router.ts +3 -2
  62. package/src/types.ts +6 -3
  63. package/src/vdom-my-prop-attr.ts +5 -11
  64. package/src/version.ts +1 -1
  65. package/error.log +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apprun",
3
- "version": "3.37.3",
3
+ "version": "3.38.1",
4
4
  "description": "JavaScript library that has Elm inspired architecture, event pub-sub and components",
5
5
  "main": "dist/apprun.js",
6
6
  "module": "esm/apprun.js",
@@ -1,3 +1,15 @@
1
+ /**
2
+ * AppRun playground custom element.
3
+ *
4
+ * Generates an isolated preview document, compiles JSX/TypeScript in the
5
+ * browser, and renders the result with AppRun. The TypeScript CDN dependency
6
+ * uses an explicit version and browser bundle path so the `ts` global is
7
+ * available before preview compilation begins.
8
+ *
9
+ * Recent Changes:
10
+ * - Executes compiled script-style examples synchronously before the preview
11
+ * document finishes DOMContentLoaded, preserving startup configuration.
12
+ */
1
13
  import { app, Component } from './apprun';
2
14
 
3
15
  declare var CodeMirror;
@@ -45,7 +57,7 @@ const code_html = code => `<!DOCTYPE html>
45
57
  margin: 2em;
46
58
  }
47
59
  </style>
48
- <script src="https://cdn.jsdelivr.net/npm/typescript@latest"></script>
60
+ <script src="https://cdn.jsdelivr.net/npm/typescript@5.8.3/lib/typescript.js"></script>
49
61
  <script src="dist/apprun-html.js"></script>
50
62
  </head>
51
63
  <body>
@@ -58,7 +70,7 @@ const compiled = ts.transpileModule(code, {
58
70
  "jsxFactory": "app.h",
59
71
  "jsxFragmentFactory": "app.Fragment",
60
72
  "target": "es2020",
61
- "module": "esnext",
73
+ "module": "none",
62
74
  },
63
75
  reportDiagnostics: true,
64
76
  });
@@ -82,7 +94,7 @@ if (compiled.diagnostics && compiled.diagnostics.length) {
82
94
  document.body.appendChild(pre);
83
95
  };
84
96
  const script = document.createElement('script');
85
- script.type = 'module';
97
+ script.type = 'text/javascript';
86
98
  script.text = compiled.outputText;
87
99
  document.body.appendChild(script);
88
100
  }
@@ -1,3 +1,9 @@
1
+ /**
2
+ * AppRun documentation playground custom element.
3
+ *
4
+ * Compiles browser-global TypeScript/JSX examples into synchronous scripts so
5
+ * startup configuration runs before the preview document's DOMContentLoaded.
6
+ */
1
7
  import { app, Component } from './apprun';
2
8
 
3
9
  const popup_div = `<div id="play-popup" class="overlay">
@@ -126,7 +132,7 @@ const compiled = ts.transpileModule(code, {
126
132
  "jsxFactory": "app.h",
127
133
  "jsxFragmentFactory": "app.Fragment",
128
134
  "target": "es2020",
129
- "module": "esnext",
135
+ "module": "none",
130
136
  },
131
137
  reportDiagnostics: true,
132
138
  });
@@ -150,7 +156,7 @@ if (compiled.diagnostics && compiled.diagnostics.length) {
150
156
  document.body.appendChild(pre);
151
157
  };
152
158
  const script = document.createElement('script');
153
- script.type = 'module';
159
+ script.type = 'text/javascript';
154
160
  script.text = compiled.outputText;
155
161
  document.body.appendChild(script);
156
162
  }
@@ -194,7 +200,7 @@ const setup_editor = (textarea, iframe, code, hide_src) => {
194
200
  }
195
201
  }
196
202
 
197
- class Play extends Component {
203
+ class Play extends Component<any> {
198
204
  view = (state) => {
199
205
  const code_id = state['code-element-id'];
200
206
  const element = this.element;
package/src/apprun.ts CHANGED
@@ -24,6 +24,7 @@
24
24
  * - Virtual DOM rendering with multiple renderer support
25
25
  * - Component lifecycle management
26
26
  * - Client-side routing with hash/path support
27
+ * - Explicit pretty-link path routing through app.use_prettyLink()
27
28
  * - Web Components integration
28
29
  * - React compatibility layer
29
30
  * - TypeScript support with strong typing
@@ -37,6 +38,7 @@
37
38
  * - Safer element access with proper type assertions
38
39
  *
39
40
  * Recent Changes:
41
+ * - Restored hash routing and normal browser navigation as the default; pretty-link interception is opt-in
40
42
  * - Modified addComponents to accept (element, components) where components is a key-value object with routes as keys and components as values
41
43
  * - Simplified component mounting API for better usability
42
44
  *
@@ -54,6 +56,8 @@
54
56
  * }
55
57
  *
56
58
  * // Mount multiple components
59
+ * // Required only when browser /path links should use SPA navigation.
60
+ * app.use_prettyLink();
57
61
  * app.addComponents(document.body, {
58
62
  * '/home': MyComponent,
59
63
  * '/about': AnotherComponent
@@ -73,7 +77,7 @@ import { APPRUN_VERSION } from './version';
73
77
 
74
78
  export type StatelessComponent<T = {}> = (args: T) => string | VNode | void;
75
79
  type OnDecorator = {
76
- <T = any>(options?: any): (constructor: Function) => void;
80
+ <T = unknown>(options?: any): (constructor: Function) => void;
77
81
  <E = string>(events?: E, options?: any): (target: any, key: string) => void;
78
82
  };
79
83
 
@@ -109,7 +113,7 @@ if (!app.start) {
109
113
  app.webComponent = webComponent;
110
114
  app.safeHTML = safeHTML;
111
115
 
112
- app.start = <T, E = any>(element?: Element | string, state?: State<T>, view?: View<T>, update?: Update<T, E>,
116
+ app.start = <T, E = unknown>(element?: Element | string, state?: State<T>, view?: View<T>, update?: Update<T, E>,
113
117
  options?: AppStartOptions<T>): Component<T, E> => {
114
118
  const opts = { render: true, global_event: true, ...options };
115
119
  const component = new Component<T, E>(state, view, update);
@@ -124,24 +128,25 @@ if (!app.start) {
124
128
 
125
129
  const NOOP = _ => {/* Intentionally empty */ }
126
130
  app.on('/', NOOP);
131
+ app.on('#', NOOP);
127
132
  app.on('debug', _ => NOOP);
128
133
  app.on(ROUTER_EVENT, NOOP);
129
134
  app.on(ROUTER_404_EVENT, NOOP);
130
135
  app.route = route;
131
136
  app.on('route', url => app['route'] && app['route'](url));
132
137
 
138
+ let prettyLinks = false;
139
+ /** Select SPA path-link routing before DOMContentLoaded; hash routing is the default. */
140
+ app.use_prettyLink = (enabled = true) => {
141
+ prettyLinks = enabled;
142
+ };
143
+
133
144
  if (typeof document === 'object') {
134
145
  document.addEventListener("DOMContentLoaded", () => {
135
146
  const no_init_route = document.body.hasAttribute('apprun-no-init') || app['no-init-route'] || false;
136
- const use_hash = app.find('#') || app.find('#/') || false;
137
147
 
138
- // console.log(`AppRun ${app.version} started with ${use_hash ? 'hash' : 'path'} routing. Initial load: ${init_load ? 'disabled' : 'enabled'}.`);
139
- window.addEventListener('hashchange', () => route(location.hash));
140
- window.addEventListener('popstate', () => route(location.pathname));
141
-
142
- if (use_hash) {
143
- !no_init_route && route(location.hash);
144
- } else {
148
+ if (prettyLinks) {
149
+ window.addEventListener('popstate', () => route(location.pathname));
145
150
  !no_init_route && (() => {
146
151
  const basePath = app.basePath || '';
147
152
  let initialPath = location.pathname;
@@ -172,6 +177,9 @@ if (!app.start) {
172
177
  route(menu.pathname); // Route with relative path (without base path)
173
178
  }
174
179
  });
180
+ } else {
181
+ window.addEventListener('hashchange', () => route(location.hash));
182
+ !no_init_route && route(location.hash);
175
183
  }
176
184
  });
177
185
  }
package/src/component.ts CHANGED
@@ -66,7 +66,7 @@ export const REFRESH = state => state;
66
66
 
67
67
  const app = _app as unknown as IApp;
68
68
 
69
- export class Component<T = any, E = any> {
69
+ export class Component<T = unknown, E = unknown> {
70
70
  static __isAppRunComponent = true;
71
71
  private _app = new App();
72
72
  private _actions = [];
@@ -1,6 +1,6 @@
1
1
  import { produce, Draft } from 'immer';
2
2
 
3
- export function createState<T = any>(
3
+ export function createState<T = unknown>(
4
4
  fn: (draft: Draft<T>, ...args: any[]) => void
5
5
  ): (state: T, ...args: any[]) => T {
6
6
  return (state: T, ...args: any[]): T => {
package/src/directive.ts CHANGED
@@ -34,16 +34,36 @@
34
34
  * - Enhanced error handling for invalid event targets
35
35
  * - Safer DOM element property access
36
36
  *
37
+ * Nested State Binding Support (v3.37.4):
38
+ * - Enhanced $bind directive to support nested object and array paths
39
+ * - Supports dot notation: 'user.name', 'user.profile.settings.theme'
40
+ * - Supports bracket notation: 'items[0]', 'users[1].name'
41
+ * - Supports mixed notation: 'users[0].settings.theme', 'data["key"].value'
42
+ * - Safe traversal with automatic intermediate object/array creation
43
+ * - Maintains backward compatibility with simple property binding
44
+ *
37
45
  * Usage:
38
46
  * ```tsx
39
47
  * // Event binding
40
48
  * <button $onclick="event-name">Click</button>
41
49
  * <input $oninput={e => setState(e.target.value)} />
42
50
  *
43
- * // Two-way binding
51
+ * // Simple two-way binding
44
52
  * <input $bind="state.property" />
45
53
  * <select $bind="selected">...</select>
46
54
  *
55
+ * // Nested object binding
56
+ * <input $bind="user.profile.name" />
57
+ * <input $bind="user.settings.theme" />
58
+ *
59
+ * // Array element binding
60
+ * <input $bind="items[0]" />
61
+ * <input $bind="todos[1].title" />
62
+ *
63
+ * // Mixed nested binding
64
+ * <input $bind="users[0].profile.settings.notifications.email" />
65
+ * <select $bind="config.display.mode">...</select>
66
+ *
47
67
  * // Array handlers
48
68
  * <button $onclick={['handler', param1, param2]}>Click</button>
49
69
  * ```
@@ -52,18 +72,123 @@
52
72
  import app from './app';
53
73
  import { safeEventTarget } from './type-utils';
54
74
 
75
+ /**
76
+ * Parse a path string into an array of keys and indices
77
+ * Supports paths like: 'a.b', 'a[0]', 'a[0].b', 'a["key"]'
78
+ */
79
+ const parsePath = (path: string): Array<string | number> => {
80
+ if (!path) return [];
81
+
82
+ const keys: Array<string | number> = [];
83
+ let current = '';
84
+ let inBracket = false;
85
+ let quoteChar = '';
86
+
87
+ for (let i = 0; i < path.length; i++) {
88
+ const char = path[i];
89
+
90
+ if (char === '[' && !inBracket) {
91
+ if (current) {
92
+ keys.push(current);
93
+ current = '';
94
+ }
95
+ inBracket = true;
96
+ } else if (char === ']' && inBracket) {
97
+ if (quoteChar) {
98
+ // Remove quotes from string keys
99
+ current = current.slice(1, -1);
100
+ } else if (/^\d+$/.test(current)) {
101
+ // Convert numeric strings to numbers
102
+ current = parseInt(current, 10) as any;
103
+ }
104
+ keys.push(current);
105
+ current = '';
106
+ inBracket = false;
107
+ quoteChar = '';
108
+ } else if ((char === '"' || char === "'") && inBracket) {
109
+ if (!quoteChar) {
110
+ quoteChar = char;
111
+ } else if (char === quoteChar) {
112
+ quoteChar = '';
113
+ }
114
+ current += char;
115
+ } else if (char === '.' && !inBracket) {
116
+ if (current) {
117
+ keys.push(current);
118
+ current = '';
119
+ }
120
+ } else {
121
+ current += char;
122
+ }
123
+ }
124
+
125
+ if (current) {
126
+ keys.push(current);
127
+ }
128
+
129
+ return keys;
130
+ };
131
+
132
+ /**
133
+ * Safely get a nested value from an object using a path
134
+ */
135
+ const getNestedValue = (obj: any, path: Array<string | number>): any => {
136
+ let current = obj;
137
+ for (const key of path) {
138
+ if (current == null) return undefined;
139
+ current = current[key];
140
+ }
141
+ return current;
142
+ };
143
+
144
+ /**
145
+ * Safely set a nested value in an object using a path
146
+ * Creates intermediate objects/arrays as needed
147
+ */
148
+ const setNestedValue = (obj: any, path: Array<string | number>, value: any): any => {
149
+ if (path.length === 0) return value;
150
+
151
+ const result = { ...obj };
152
+ let current = result;
153
+
154
+ for (let i = 0; i < path.length - 1; i++) {
155
+ const key = path[i];
156
+ const nextKey = path[i + 1];
157
+
158
+ if (current[key] == null) {
159
+ // Create array if next key is numeric, object otherwise
160
+ current[key] = typeof nextKey === 'number' ? [] : {};
161
+ } else if (Array.isArray(current[key])) {
162
+ current[key] = [...current[key]];
163
+ } else if (typeof current[key] === 'object') {
164
+ current[key] = { ...current[key] };
165
+ }
166
+
167
+ current = current[key];
168
+ }
169
+
170
+ current[path[path.length - 1]] = value;
171
+ return result;
172
+ };
173
+
55
174
  const getStateValue = (component, name) => {
56
- return (name ? component['state'][name] : component['state']) || '';
175
+ if (!name) return component['state'] || '';
176
+
177
+ const path = parsePath(name);
178
+ const value = getNestedValue(component['state'], path);
179
+ return value !== undefined ? value : '';
57
180
  }
58
181
 
59
182
  const setStateValue = (component, name, value) => {
60
- if (name) {
61
- const state = component['state'] || {};
62
- state[name] = value;
63
- component.setState(state);
64
- } else {
183
+ if (!name) {
65
184
  component.setState(value);
185
+ return;
66
186
  }
187
+
188
+ const path = parsePath(name);
189
+ const currentState = component['state'] || {};
190
+ const newState = setNestedValue(currentState, path, value);
191
+ component.setState(newState);
67
192
  }
68
193
 
69
194
  const apply_directive = (key: string, props: {}, tag, component) => {
package/src/global.d.ts CHANGED
@@ -8,12 +8,12 @@ declare global {
8
8
  app: App;
9
9
  _AppRunVersions: string;
10
10
  Component: typeof Component & {
11
- <T = any>(options?: any): (constructor: Function) => void;
11
+ <T = unknown>(options?: any): (constructor: Function) => void;
12
12
  };
13
13
  _React: any;
14
14
  React: App;
15
15
  on: {
16
- <T = any>(options?: any): (constructor: Function) => void;
16
+ <T = unknown>(options?: any): (constructor: Function) => void;
17
17
  <E = string>(events?: E, options?: any): (target: any, key: string) => void;
18
18
  };
19
19
  customElement: (name: string) => (constructor: Function) => void;
package/src/router.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  * 2. Path-based routing (/path)
10
10
  * - Works with browser history API
11
11
  * - Requires server configuration for SPA routing
12
- * - Handles popstate events automatically
12
+ * - Handles browser links and popstate after app.use_prettyLink() opts in before initialization
13
13
  * 3. Event-based navigation
14
14
  * - Routes trigger corresponding component events
15
15
  * - Automatic route parameter extraction
@@ -38,7 +38,7 @@
38
38
  *
39
39
  * // Navigate programmatically
40
40
  * app.run('route', '#/home');
41
- * route('/users/123'); // Direct routing
41
+ * route('/users/123'); // Direct routing does not require pretty-link mode
42
42
  *
43
43
  * // Hierarchical matching examples
44
44
  * app.on('/api', (operation, id) => // Handle /api/users/123);
@@ -50,6 +50,7 @@
50
50
  * // If handler found at /api, it receives: ('v1', 'users', '123')
51
51
  *
52
52
  * // Base Path Support (NEW):
53
+ * app.use_prettyLink(); // Enable automatic browser path navigation before initialization
53
54
  * app.basePath = '/myapp'; // For sub-directory deployments
54
55
  * // Links: <a href="/users/123"> (relative paths)
55
56
  * // Navigation: /myapp/users/123 (full path)
package/src/types.ts CHANGED
@@ -19,6 +19,7 @@
19
19
  * - ActionOptions: Action behavior options (render, history, global, callback)
20
20
  * - MountOptions: Component mounting options (global events, routing, transitions)
21
21
  * - AppStartOptions: Application startup configuration with lifecycle hooks
22
+ * - IApp.use_prettyLink: Explicit startup selection for path-link routing
22
23
  *
23
24
  * Features:
24
25
  * - Strong typing for component lifecycle
@@ -66,7 +67,7 @@ export type VDOM = false | string | VNode | Array<VNode | string> | TemplateResu
66
67
  export type View<T> = (state: T) => VDOM | void;
67
68
  export type Action<T> = (state: T, ...p: any[]) => T | Promise<T> | void | AsyncGenerator<T> | Generator<T>;
68
69
  export type ActionDef<T, E> = (readonly [E, Action<T>, {}?]);
69
- export type Update<T, E = any> = ActionDef<T, E>[] | { [name: string]: Action<T> | {}[] } | (E | Action<T> | {})[];
70
+ export type Update<T, E = unknown> = ActionDef<T, E>[] | { [name: string]: Action<T> | {}[] } | (E | Action<T> | {})[];
70
71
  export type ActionOptions = {
71
72
  render?: boolean, history?, global?: boolean;
72
73
  callback?: (state: any) => void;
@@ -111,7 +112,7 @@ export interface IApp {
111
112
  /** @deprecated Use runAsync() instead */
112
113
  query(name: string, ...args: any[]): Promise<any[]>;
113
114
 
114
- start<T, E = any>(element?: Element | string, model?: T, view?: View<T>, update?: Update<T, E>,
115
+ start<T, E = unknown>(element?: Element | string, model?: T, view?: View<T>, update?: Update<T, E>,
115
116
  options?: AppStartOptions<T>): any;
116
117
 
117
118
  h(tag: string | Function, props?: any, ...children: any[]): VNode | VNode[];
@@ -123,6 +124,8 @@ export interface IApp {
123
124
  safeHTML(html: string): any[];
124
125
  use_render(render: any, mode?: 0 | 1): void;
125
126
  use_react(React: any, ReactDOM: any): void;
127
+ /** Select SPA path-link routing before DOMContentLoaded; hash routing is the default. */
128
+ use_prettyLink(enabled?: boolean): void;
126
129
  version: string;
127
130
  basePath?: string;
128
131
  addComponents: (element: Element | string, components: ComponentRoute) => void;
@@ -134,7 +137,7 @@ interface ComponentLike {
134
137
  }
135
138
 
136
139
  // Define component constructor type
137
- type ComponentConstructor<T = any> = new (
140
+ type ComponentConstructor<T = unknown> = new (
138
141
  state?: T,
139
142
  view?: any,
140
143
  update?: any,
@@ -3,7 +3,7 @@
3
3
  * Standards-compliant property/attribute handling with caching and special element support
4
4
  * Features: Skip logic for preserving user interactions during VDOM reconciliation
5
5
  * Exports: updateProps - Main function for DOM element property updates
6
- * Updated: 2025-01-14 - Skip logic for focus-sensitive (selection), scroll, and media properties
6
+ * Updated: 2026-07-13 - Restore stale class cleanup when first-render VDOM props are null
7
7
  */
8
8
 
9
9
  import { find, html, svg } from 'property-information';
@@ -13,17 +13,11 @@ const propertyInfoCache = new Map<string, any>();
13
13
 
14
14
  // Merge old and new props, handling className -> class conversion and null cleanup
15
15
  function mergeProps(oldProps: { [key: string]: any }, newProps: { [key: string]: any }): { [key: string]: any } {
16
- if (newProps) {
17
- newProps['class'] = newProps['class'] || newProps['className'];
18
- delete newProps['className'];
19
- }
16
+ newProps = newProps || {};
17
+ newProps['class'] = newProps['class'] || newProps['className'];
18
+ delete newProps['className'];
20
19
 
21
- if (!oldProps || Object.keys(oldProps).length === 0) return newProps || {};
22
- if (!newProps || Object.keys(newProps).length === 0) {
23
- const props: { [key: string]: any } = {};
24
- Object.keys(oldProps).forEach(p => props[p] = null);
25
- return props;
26
- }
20
+ if (!oldProps || Object.keys(oldProps).length === 0) return newProps;
27
21
 
28
22
  const props: { [key: string]: any } = {};
29
23
  Object.keys(oldProps).forEach(p => {
package/src/version.ts CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  // Import version from package.json to maintain single source of truth
12
12
  // This version string is used across the framework
13
- export const APPRUN_VERSION = '3.37.2';
13
+ export const APPRUN_VERSION = '3.38.0';
14
14
 
15
15
  // Version string with prefix for global tracking
16
16
  export const APPRUN_VERSION_GLOBAL = `AppRun-${APPRUN_VERSION}`;
package/error.log DELETED
File without changes