@hypen-space/core 0.4.956 → 0.5.2

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 (96) hide show
  1. package/README.md +5 -8
  2. package/dist/app.js +13 -1168
  3. package/dist/app.js.map +3 -9
  4. package/dist/chunk-00zt3w6e.js +58 -0
  5. package/dist/chunk-00zt3w6e.js.map +10 -0
  6. package/dist/chunk-3zvyth50.js +87 -0
  7. package/dist/chunk-3zvyth50.js.map +10 -0
  8. package/dist/chunk-5gtx3pza.js +11 -0
  9. package/dist/chunk-5gtx3pza.js.map +9 -0
  10. package/dist/chunk-7222131a.js +191 -0
  11. package/dist/chunk-7222131a.js.map +10 -0
  12. package/dist/chunk-avchpwhf.js +200 -0
  13. package/dist/chunk-avchpwhf.js.map +10 -0
  14. package/dist/chunk-ec0tgy9a.js +154 -0
  15. package/dist/chunk-ec0tgy9a.js.map +10 -0
  16. package/dist/chunk-fnss4dm2.js +479 -0
  17. package/dist/chunk-fnss4dm2.js.map +10 -0
  18. package/dist/chunk-g2gz9pgg.js +133 -0
  19. package/dist/chunk-g2gz9pgg.js.map +10 -0
  20. package/dist/chunk-g72v6mmf.js +341 -0
  21. package/dist/chunk-g72v6mmf.js.map +10 -0
  22. package/dist/chunk-g7g3jxty.js +351 -0
  23. package/dist/chunk-g7g3jxty.js.map +10 -0
  24. package/dist/chunk-g830re2c.js +50 -0
  25. package/dist/chunk-g830re2c.js.map +10 -0
  26. package/dist/chunk-gtwh1sg7.js +127 -0
  27. package/dist/chunk-gtwh1sg7.js.map +10 -0
  28. package/dist/chunk-k12cwfst.js +72 -0
  29. package/dist/chunk-k12cwfst.js.map +10 -0
  30. package/dist/chunk-mbqqsz6r.js +128 -0
  31. package/dist/chunk-mbqqsz6r.js.map +10 -0
  32. package/dist/chunk-ne632swm.js +209 -0
  33. package/dist/chunk-ne632swm.js.map +10 -0
  34. package/dist/chunk-p3pj1bax.js +206 -0
  35. package/dist/chunk-p3pj1bax.js.map +10 -0
  36. package/dist/chunk-vshdk2pw.js +56 -0
  37. package/dist/chunk-vshdk2pw.js.map +10 -0
  38. package/dist/chunk-wp2ebn2m.js +51 -0
  39. package/dist/chunk-wp2ebn2m.js.map +10 -0
  40. package/dist/chunk-x4qv4jm9.js +88 -0
  41. package/dist/chunk-x4qv4jm9.js.map +10 -0
  42. package/dist/chunk-ycxp4drd.js +211 -0
  43. package/dist/chunk-ycxp4drd.js.map +10 -0
  44. package/dist/components/builtin.js +14 -1246
  45. package/dist/components/builtin.js.map +3 -10
  46. package/dist/context.js +7 -362
  47. package/dist/context.js.map +3 -6
  48. package/dist/datasource.js +5 -76
  49. package/dist/datasource.js.map +3 -4
  50. package/dist/disposable.js +20 -367
  51. package/dist/disposable.js.map +3 -5
  52. package/dist/engine-base.d.ts +38 -2
  53. package/dist/engine-base.js +45 -412
  54. package/dist/engine-base.js.map +4 -6
  55. package/dist/events.js +7 -285
  56. package/dist/events.js.map +3 -5
  57. package/dist/hypen.js +8 -71
  58. package/dist/hypen.js.map +3 -4
  59. package/dist/index.browser.js +58 -2152
  60. package/dist/index.browser.js.map +3 -16
  61. package/dist/index.d.ts +2 -0
  62. package/dist/index.js +132 -3058
  63. package/dist/index.js.map +4 -22
  64. package/dist/logger.js +16 -220
  65. package/dist/logger.js.map +3 -4
  66. package/dist/managed-router.js +12 -1367
  67. package/dist/managed-router.js.map +3 -10
  68. package/dist/portable.js +6 -70
  69. package/dist/portable.js.map +3 -4
  70. package/dist/remote/client.js +9 -1010
  71. package/dist/remote/client.js.map +3 -8
  72. package/dist/remote/index.d.ts +2 -0
  73. package/dist/remote/index.js +511 -1066
  74. package/dist/remote/index.js.map +4 -9
  75. package/dist/remote/remote-session.d.ts +245 -0
  76. package/dist/remote/session.js +5 -147
  77. package/dist/remote/session.js.map +3 -4
  78. package/dist/renderer.js +7 -271
  79. package/dist/renderer.js.map +3 -5
  80. package/dist/resolver.js +5 -484
  81. package/dist/resolver.js.map +3 -5
  82. package/dist/result.js +25 -211
  83. package/dist/result.js.map +3 -4
  84. package/dist/retry.js +10 -336
  85. package/dist/retry.js.map +3 -5
  86. package/dist/router.js +9 -807
  87. package/dist/router.js.map +3 -8
  88. package/dist/state.js +10 -274
  89. package/dist/state.js.map +3 -5
  90. package/dist/validate.d.ts +19 -0
  91. package/package.json +13 -1
  92. package/src/engine-base.ts +87 -4
  93. package/src/index.ts +5 -0
  94. package/src/remote/index.ts +16 -0
  95. package/src/remote/remote-session.ts +998 -0
  96. package/src/validate.ts +37 -0
package/dist/index.js CHANGED
@@ -1,3066 +1,140 @@
1
- var __defProp = Object.defineProperty;
2
- var __returnValue = (v) => v;
3
- function __exportSetter(name, newValue) {
4
- this[name] = __returnValue.bind(null, newValue);
5
- }
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, {
9
- get: all[name],
10
- enumerable: true,
11
- configurable: true,
12
- set: __exportSetter.bind(all, name)
13
- });
14
- };
15
- var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
16
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
17
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
18
- }) : x)(function(x) {
19
- if (typeof require !== "undefined")
20
- return require.apply(this, arguments);
21
- throw Error('Dynamic require of "' + x + '" is not supported');
22
- });
23
-
24
- // node:path
25
- var exports_path = {};
26
- __export(exports_path, {
27
- sep: () => sep,
28
- resolve: () => resolve,
29
- relative: () => relative,
30
- posix: () => posix,
31
- parse: () => parse,
32
- normalize: () => normalize,
33
- join: () => join,
34
- isAbsolute: () => isAbsolute,
35
- format: () => format,
36
- extname: () => extname,
37
- dirname: () => dirname,
38
- delimiter: () => delimiter,
39
- default: () => path_default,
40
- basename: () => basename,
41
- _makeLong: () => _makeLong
42
- });
43
- function assertPath(path) {
44
- if (typeof path !== "string")
45
- throw TypeError("Path must be a string. Received " + JSON.stringify(path));
46
- }
47
- function normalizeStringPosix(path, allowAboveRoot) {
48
- var res = "", lastSegmentLength = 0, lastSlash = -1, dots = 0, code;
49
- for (var i = 0;i <= path.length; ++i) {
50
- if (i < path.length)
51
- code = path.charCodeAt(i);
52
- else if (code === 47)
53
- break;
54
- else
55
- code = 47;
56
- if (code === 47) {
57
- if (lastSlash === i - 1 || dots === 1)
58
- ;
59
- else if (lastSlash !== i - 1 && dots === 2) {
60
- if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== 46 || res.charCodeAt(res.length - 2) !== 46) {
61
- if (res.length > 2) {
62
- var lastSlashIndex = res.lastIndexOf("/");
63
- if (lastSlashIndex !== res.length - 1) {
64
- if (lastSlashIndex === -1)
65
- res = "", lastSegmentLength = 0;
66
- else
67
- res = res.slice(0, lastSlashIndex), lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
68
- lastSlash = i, dots = 0;
69
- continue;
70
- }
71
- } else if (res.length === 2 || res.length === 1) {
72
- res = "", lastSegmentLength = 0, lastSlash = i, dots = 0;
73
- continue;
74
- }
75
- }
76
- if (allowAboveRoot) {
77
- if (res.length > 0)
78
- res += "/..";
79
- else
80
- res = "..";
81
- lastSegmentLength = 2;
82
- }
83
- } else {
84
- if (res.length > 0)
85
- res += "/" + path.slice(lastSlash + 1, i);
86
- else
87
- res = path.slice(lastSlash + 1, i);
88
- lastSegmentLength = i - lastSlash - 1;
89
- }
90
- lastSlash = i, dots = 0;
91
- } else if (code === 46 && dots !== -1)
92
- ++dots;
93
- else
94
- dots = -1;
95
- }
96
- return res;
97
- }
98
- function _format(sep, pathObject) {
99
- var dir = pathObject.dir || pathObject.root, base = pathObject.base || (pathObject.name || "") + (pathObject.ext || "");
100
- if (!dir)
101
- return base;
102
- if (dir === pathObject.root)
103
- return dir + base;
104
- return dir + sep + base;
105
- }
106
- function resolve() {
107
- var resolvedPath = "", resolvedAbsolute = false, cwd;
108
- for (var i = arguments.length - 1;i >= -1 && !resolvedAbsolute; i--) {
109
- var path;
110
- if (i >= 0)
111
- path = arguments[i];
112
- else {
113
- if (cwd === undefined)
114
- cwd = process.cwd();
115
- path = cwd;
116
- }
117
- if (assertPath(path), path.length === 0)
118
- continue;
119
- resolvedPath = path + "/" + resolvedPath, resolvedAbsolute = path.charCodeAt(0) === 47;
120
- }
121
- if (resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute), resolvedAbsolute)
122
- if (resolvedPath.length > 0)
123
- return "/" + resolvedPath;
124
- else
125
- return "/";
126
- else if (resolvedPath.length > 0)
127
- return resolvedPath;
128
- else
129
- return ".";
130
- }
131
- function normalize(path) {
132
- if (assertPath(path), path.length === 0)
133
- return ".";
134
- var isAbsolute = path.charCodeAt(0) === 47, trailingSeparator = path.charCodeAt(path.length - 1) === 47;
135
- if (path = normalizeStringPosix(path, !isAbsolute), path.length === 0 && !isAbsolute)
136
- path = ".";
137
- if (path.length > 0 && trailingSeparator)
138
- path += "/";
139
- if (isAbsolute)
140
- return "/" + path;
141
- return path;
142
- }
143
- function isAbsolute(path) {
144
- return assertPath(path), path.length > 0 && path.charCodeAt(0) === 47;
145
- }
146
- function join() {
147
- if (arguments.length === 0)
148
- return ".";
149
- var joined;
150
- for (var i = 0;i < arguments.length; ++i) {
151
- var arg = arguments[i];
152
- if (assertPath(arg), arg.length > 0)
153
- if (joined === undefined)
154
- joined = arg;
155
- else
156
- joined += "/" + arg;
157
- }
158
- if (joined === undefined)
159
- return ".";
160
- return normalize(joined);
161
- }
162
- function relative(from, to) {
163
- if (assertPath(from), assertPath(to), from === to)
164
- return "";
165
- if (from = resolve(from), to = resolve(to), from === to)
166
- return "";
167
- var fromStart = 1;
168
- for (;fromStart < from.length; ++fromStart)
169
- if (from.charCodeAt(fromStart) !== 47)
170
- break;
171
- var fromEnd = from.length, fromLen = fromEnd - fromStart, toStart = 1;
172
- for (;toStart < to.length; ++toStart)
173
- if (to.charCodeAt(toStart) !== 47)
174
- break;
175
- var toEnd = to.length, toLen = toEnd - toStart, length = fromLen < toLen ? fromLen : toLen, lastCommonSep = -1, i = 0;
176
- for (;i <= length; ++i) {
177
- if (i === length) {
178
- if (toLen > length) {
179
- if (to.charCodeAt(toStart + i) === 47)
180
- return to.slice(toStart + i + 1);
181
- else if (i === 0)
182
- return to.slice(toStart + i);
183
- } else if (fromLen > length) {
184
- if (from.charCodeAt(fromStart + i) === 47)
185
- lastCommonSep = i;
186
- else if (i === 0)
187
- lastCommonSep = 0;
188
- }
189
- break;
190
- }
191
- var fromCode = from.charCodeAt(fromStart + i), toCode = to.charCodeAt(toStart + i);
192
- if (fromCode !== toCode)
193
- break;
194
- else if (fromCode === 47)
195
- lastCommonSep = i;
196
- }
197
- var out = "";
198
- for (i = fromStart + lastCommonSep + 1;i <= fromEnd; ++i)
199
- if (i === fromEnd || from.charCodeAt(i) === 47)
200
- if (out.length === 0)
201
- out += "..";
202
- else
203
- out += "/..";
204
- if (out.length > 0)
205
- return out + to.slice(toStart + lastCommonSep);
206
- else {
207
- if (toStart += lastCommonSep, to.charCodeAt(toStart) === 47)
208
- ++toStart;
209
- return to.slice(toStart);
210
- }
211
- }
212
- function _makeLong(path) {
213
- return path;
214
- }
215
- function dirname(path) {
216
- if (assertPath(path), path.length === 0)
217
- return ".";
218
- var code = path.charCodeAt(0), hasRoot = code === 47, end = -1, matchedSlash = true;
219
- for (var i = path.length - 1;i >= 1; --i)
220
- if (code = path.charCodeAt(i), code === 47) {
221
- if (!matchedSlash) {
222
- end = i;
223
- break;
224
- }
225
- } else
226
- matchedSlash = false;
227
- if (end === -1)
228
- return hasRoot ? "/" : ".";
229
- if (hasRoot && end === 1)
230
- return "//";
231
- return path.slice(0, end);
232
- }
233
- function basename(path, ext) {
234
- if (ext !== undefined && typeof ext !== "string")
235
- throw TypeError('"ext" argument must be a string');
236
- assertPath(path);
237
- var start = 0, end = -1, matchedSlash = true, i;
238
- if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {
239
- if (ext.length === path.length && ext === path)
240
- return "";
241
- var extIdx = ext.length - 1, firstNonSlashEnd = -1;
242
- for (i = path.length - 1;i >= 0; --i) {
243
- var code = path.charCodeAt(i);
244
- if (code === 47) {
245
- if (!matchedSlash) {
246
- start = i + 1;
247
- break;
248
- }
249
- } else {
250
- if (firstNonSlashEnd === -1)
251
- matchedSlash = false, firstNonSlashEnd = i + 1;
252
- if (extIdx >= 0)
253
- if (code === ext.charCodeAt(extIdx)) {
254
- if (--extIdx === -1)
255
- end = i;
256
- } else
257
- extIdx = -1, end = firstNonSlashEnd;
258
- }
259
- }
260
- if (start === end)
261
- end = firstNonSlashEnd;
262
- else if (end === -1)
263
- end = path.length;
264
- return path.slice(start, end);
265
- } else {
266
- for (i = path.length - 1;i >= 0; --i)
267
- if (path.charCodeAt(i) === 47) {
268
- if (!matchedSlash) {
269
- start = i + 1;
270
- break;
271
- }
272
- } else if (end === -1)
273
- matchedSlash = false, end = i + 1;
274
- if (end === -1)
275
- return "";
276
- return path.slice(start, end);
277
- }
278
- }
279
- function extname(path) {
280
- assertPath(path);
281
- var startDot = -1, startPart = 0, end = -1, matchedSlash = true, preDotState = 0;
282
- for (var i = path.length - 1;i >= 0; --i) {
283
- var code = path.charCodeAt(i);
284
- if (code === 47) {
285
- if (!matchedSlash) {
286
- startPart = i + 1;
287
- break;
288
- }
1
+ import {
2
+ ComponentResolver
3
+ } from "./chunk-mbqqsz6r.js";
4
+ import {
5
+ Link,
6
+ Route,
7
+ Router
8
+ } from "./chunk-x4qv4jm9.js";
9
+ import {
10
+ SessionManager
11
+ } from "./chunk-gtwh1sg7.js";
12
+ import {
13
+ HypenGlobalContext
14
+ } from "./chunk-3zvyth50.js";
15
+ import {
16
+ TypedEventEmitter,
17
+ createEventEmitter
18
+ } from "./chunk-k12cwfst.js";
19
+ import {
20
+ RemoteEngine
21
+ } from "./chunk-g7g3jxty.js";
22
+ import {
23
+ RetryConditions,
24
+ RetryPresets,
25
+ retry,
26
+ retryResult,
27
+ withRetry
28
+ } from "./chunk-g2gz9pgg.js";
29
+ import {
30
+ hypen,
31
+ index,
32
+ item,
33
+ state
34
+ } from "./chunk-wp2ebn2m.js";
35
+ import {
36
+ BaseRenderer,
37
+ ConsoleRenderer
38
+ } from "./chunk-00zt3w6e.js";
39
+ import {
40
+ HypenRouter
41
+ } from "./chunk-p3pj1bax.js";
42
+ import {
43
+ DisposableMixin,
44
+ DisposableStack,
45
+ compositeDisposable,
46
+ disposableAbortController,
47
+ disposableInterval,
48
+ disposableListener,
49
+ disposableSubscription,
50
+ disposableTimeout,
51
+ disposableWebSocket,
52
+ disposeElement,
53
+ getElementDisposables,
54
+ hasElementDisposables,
55
+ isDisposable,
56
+ using,
57
+ usingSync
58
+ } from "./chunk-ec0tgy9a.js";
59
+ import {
60
+ ManagedRouter
61
+ } from "./chunk-ne632swm.js";
62
+ import {
63
+ HypenApp,
64
+ HypenAppBuilder,
65
+ HypenModuleInstance,
66
+ app
67
+ } from "./chunk-fnss4dm2.js";
68
+ import {
69
+ DataSourceManager
70
+ } from "./chunk-vshdk2pw.js";
71
+ import {
72
+ ActionError,
73
+ ConnectionError,
74
+ Err,
75
+ HypenError,
76
+ Ok,
77
+ ParseError,
78
+ RenderError,
79
+ StateError,
80
+ all,
81
+ classifyEngineError,
82
+ flatMap,
83
+ fromPromise,
84
+ fromTry,
85
+ isErr,
86
+ isOk,
87
+ map,
88
+ mapErr,
89
+ match,
90
+ unwrap,
91
+ unwrapOr,
92
+ unwrapOrElse
93
+ } from "./chunk-7222131a.js";
94
+ import {
95
+ batchStateUpdates,
96
+ createObservableState,
97
+ getStateSnapshot,
98
+ isStateProxy,
99
+ unwrapProxy
100
+ } from "./chunk-ycxp4drd.js";
101
+ import {
102
+ portable,
103
+ setPortableImpl
104
+ } from "./chunk-g830re2c.js";
105
+ import {
106
+ Logger,
107
+ configureLogger,
108
+ createLogger,
109
+ disableLogging,
110
+ enableLogging,
111
+ frameworkLoggers,
112
+ getLogLevel,
113
+ isDebugMode,
114
+ log,
115
+ logger,
116
+ setDebugMode,
117
+ setLogLevel
118
+ } from "./chunk-avchpwhf.js";
119
+ import"./chunk-5gtx3pza.js";
120
+ // src/validate.ts
121
+ function validatePatches(patches, knownTypes) {
122
+ const known = knownTypes instanceof Set ? knownTypes : new Set(knownTypes);
123
+ const unknown = new Set;
124
+ for (const patch of patches) {
125
+ if (patch.type !== "create")
289
126
  continue;
290
- }
291
- if (end === -1)
292
- matchedSlash = false, end = i + 1;
293
- if (code === 46) {
294
- if (startDot === -1)
295
- startDot = i;
296
- else if (preDotState !== 1)
297
- preDotState = 1;
298
- } else if (startDot !== -1)
299
- preDotState = -1;
300
- }
301
- if (startDot === -1 || end === -1 || preDotState === 0 || preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)
302
- return "";
303
- return path.slice(startDot, end);
304
- }
305
- function format(pathObject) {
306
- if (pathObject === null || typeof pathObject !== "object")
307
- throw TypeError('The "pathObject" argument must be of type Object. Received type ' + typeof pathObject);
308
- return _format("/", pathObject);
309
- }
310
- function parse(path) {
311
- assertPath(path);
312
- var ret = { root: "", dir: "", base: "", ext: "", name: "" };
313
- if (path.length === 0)
314
- return ret;
315
- var code = path.charCodeAt(0), isAbsolute2 = code === 47, start;
316
- if (isAbsolute2)
317
- ret.root = "/", start = 1;
318
- else
319
- start = 0;
320
- var startDot = -1, startPart = 0, end = -1, matchedSlash = true, i = path.length - 1, preDotState = 0;
321
- for (;i >= start; --i) {
322
- if (code = path.charCodeAt(i), code === 47) {
323
- if (!matchedSlash) {
324
- startPart = i + 1;
325
- break;
326
- }
127
+ const elementType = patch.elementType;
128
+ if (typeof elementType !== "string")
327
129
  continue;
328
- }
329
- if (end === -1)
330
- matchedSlash = false, end = i + 1;
331
- if (code === 46) {
332
- if (startDot === -1)
333
- startDot = i;
334
- else if (preDotState !== 1)
335
- preDotState = 1;
336
- } else if (startDot !== -1)
337
- preDotState = -1;
338
- }
339
- if (startDot === -1 || end === -1 || preDotState === 0 || preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
340
- if (end !== -1)
341
- if (startPart === 0 && isAbsolute2)
342
- ret.base = ret.name = path.slice(1, end);
343
- else
344
- ret.base = ret.name = path.slice(startPart, end);
345
- } else {
346
- if (startPart === 0 && isAbsolute2)
347
- ret.name = path.slice(1, startDot), ret.base = path.slice(1, end);
348
- else
349
- ret.name = path.slice(startPart, startDot), ret.base = path.slice(startPart, end);
350
- ret.ext = path.slice(startDot, end);
351
- }
352
- if (startPart > 0)
353
- ret.dir = path.slice(0, startPart - 1);
354
- else if (isAbsolute2)
355
- ret.dir = "/";
356
- return ret;
357
- }
358
- var sep = "/", delimiter = ":", posix, path_default;
359
- var init_path = __esm(() => {
360
- posix = ((p) => (p.posix = p, p))({ resolve, normalize, isAbsolute, join, relative, _makeLong, dirname, basename, extname, format, parse, sep, delimiter, win32: null, posix: null });
361
- path_default = posix;
362
- });
363
-
364
- // src/result.ts
365
- function Ok(value) {
366
- return { ok: true, value };
367
- }
368
- function Err(error) {
369
- return { ok: false, error };
370
- }
371
- function isOk(result) {
372
- return result.ok;
373
- }
374
- function isErr(result) {
375
- return !result.ok;
376
- }
377
- async function fromPromise(promise, mapError) {
378
- try {
379
- const value = await promise;
380
- return Ok(value);
381
- } catch (e) {
382
- if (mapError) {
383
- return Err(mapError(e));
384
- }
385
- return Err(e);
386
- }
387
- }
388
- function fromTry(fn, mapError) {
389
- try {
390
- return Ok(fn());
391
- } catch (e) {
392
- if (mapError) {
393
- return Err(mapError(e));
394
- }
395
- return Err(e);
396
- }
397
- }
398
- function map(result, fn) {
399
- if (result.ok) {
400
- return Ok(fn(result.value));
401
- }
402
- return result;
403
- }
404
- function mapErr(result, fn) {
405
- if (!result.ok) {
406
- return Err(fn(result.error));
407
- }
408
- return result;
409
- }
410
- function flatMap(result, fn) {
411
- if (result.ok) {
412
- return fn(result.value);
413
- }
414
- return result;
415
- }
416
- function unwrap(result) {
417
- if (result.ok) {
418
- return result.value;
419
- }
420
- throw result.error;
421
- }
422
- function unwrapOr(result, defaultValue) {
423
- if (result.ok) {
424
- return result.value;
425
- }
426
- return defaultValue;
427
- }
428
- function unwrapOrElse(result, fn) {
429
- if (result.ok) {
430
- return result.value;
431
- }
432
- return fn(result.error);
433
- }
434
- function match(result, handlers) {
435
- if (result.ok) {
436
- return handlers.ok(result.value);
437
- }
438
- return handlers.err(result.error);
439
- }
440
- function all(results) {
441
- const values = [];
442
- for (const result of results) {
443
- if (!result.ok) {
444
- return result;
445
- }
446
- values.push(result.value);
447
- }
448
- return Ok(values);
449
- }
450
-
451
- class HypenError extends Error {
452
- code;
453
- context;
454
- cause;
455
- constructor(code, message, options) {
456
- super(message);
457
- this.name = "HypenError";
458
- this.code = code;
459
- this.context = options?.context;
460
- this.cause = options?.cause;
461
- Object.setPrototypeOf(this, new.target.prototype);
462
- }
463
- }
464
-
465
- class ActionError extends HypenError {
466
- actionName;
467
- constructor(actionName, cause) {
468
- super("ACTION_ERROR", `Action handler "${actionName}" failed: ${cause instanceof Error ? cause.message : String(cause)}`, {
469
- context: { actionName },
470
- cause: cause instanceof Error ? cause : undefined
471
- });
472
- this.name = "ActionError";
473
- this.actionName = actionName;
474
- }
475
- }
476
-
477
- class ConnectionError extends HypenError {
478
- url;
479
- attempt;
480
- constructor(url, cause, attempt) {
481
- super("CONNECTION_ERROR", `Connection to "${url}" failed${attempt ? ` (attempt ${attempt})` : ""}: ${cause instanceof Error ? cause.message : String(cause)}`, {
482
- context: { url, attempt },
483
- cause: cause instanceof Error ? cause : undefined
484
- });
485
- this.name = "ConnectionError";
486
- this.url = url;
487
- this.attempt = attempt;
488
- }
489
- }
490
-
491
- class StateError extends HypenError {
492
- path;
493
- constructor(message, path, cause) {
494
- super("STATE_ERROR", message, {
495
- context: { path },
496
- cause: cause instanceof Error ? cause : undefined
497
- });
498
- this.name = "StateError";
499
- this.path = path;
500
- }
501
- }
502
-
503
- class ParseError extends HypenError {
504
- source;
505
- constructor(message, source, cause) {
506
- super("PARSE_ERROR", message, {
507
- context: { source },
508
- cause: cause instanceof Error ? cause : undefined
509
- });
510
- this.name = "ParseError";
511
- this.source = source;
512
- }
513
- }
514
-
515
- class RenderError extends HypenError {
516
- constructor(message, cause) {
517
- super("RENDER_ERROR", message, {
518
- cause: cause instanceof Error ? cause : undefined
519
- });
520
- this.name = "RenderError";
521
- }
522
- }
523
- function classifyEngineError(err) {
524
- if (err && typeof err === "object" && "message" in err && "type" in err) {
525
- const structured = err;
526
- switch (structured.type) {
527
- case "parseError":
528
- return new ParseError(structured.message);
529
- case "stateError":
530
- return new StateError(structured.message);
531
- case "renderError":
532
- return new RenderError(structured.message);
533
- case "actionError":
534
- return new HypenError("ACTION_ERROR", structured.message);
535
- default:
536
- return new HypenError("UNKNOWN_ERROR", structured.message);
537
- }
538
- }
539
- const message = err instanceof Error ? err.message : String(err);
540
- if (message.startsWith("Parse error:")) {
541
- return new ParseError(message);
542
- }
543
- if (message.startsWith("Invalid state:") || message.startsWith("Invalid state patch:")) {
544
- return new StateError(message);
545
- }
546
- if (message.startsWith("Parent node not found:")) {
547
- return new RenderError(message);
548
- }
549
- return new RenderError(message);
550
- }
551
-
552
- // src/datasource.ts
553
- class DataSourceManager {
554
- plugins = new Map;
555
- configs = new Map;
556
- state = new Map;
557
- engine;
558
- constructor(engine) {
559
- this.engine = engine;
560
- }
561
- async use(plugin, config) {
562
- const { name } = plugin;
563
- this.state.set(name, {});
564
- this.plugins.set(name, plugin);
565
- this.configs.set(name, config);
566
- await plugin.connect(config, (change) => {
567
- const current = this.state.get(name) ?? {};
568
- for (const path of change.paths) {
569
- if (path in change.values) {
570
- current[path] = change.values[path];
571
- }
572
- }
573
- this.state.set(name, current);
574
- this.engine.setContext(name, current);
575
- });
576
- }
577
- get(name) {
578
- return this.plugins.get(name);
579
- }
580
- has(name) {
581
- return this.plugins.has(name);
582
- }
583
- getNames() {
584
- return Array.from(this.plugins.keys());
585
- }
586
- getStatus(name) {
587
- return this.plugins.get(name)?.status;
588
- }
589
- async remove(name) {
590
- const plugin = this.plugins.get(name);
591
- if (plugin) {
592
- await plugin.disconnect();
593
- this.plugins.delete(name);
594
- this.configs.delete(name);
595
- this.state.delete(name);
596
- this.engine.removeContext(name);
597
- }
598
- }
599
- async disconnectAll() {
600
- const names = Array.from(this.plugins.keys());
601
- await Promise.all(names.map((name) => this.remove(name)));
602
- }
603
- }
604
-
605
- // src/portable.ts
606
- function notInstalled(name) {
607
- throw new Error(`[@hypen-space/core] Portable helper "${name}" called before the engine was installed. ` + `Import @hypen-space/server, @hypen-space/web-engine, or call setPortableImpl() before use.`);
608
- }
609
- var current = {
610
- diffState: () => notInstalled("diffState"),
611
- matchPath: () => notInstalled("matchPath"),
612
- pathGet: () => notInstalled("pathGet"),
613
- pathHas: () => notInstalled("pathHas"),
614
- pathSet: () => notInstalled("pathSet"),
615
- pathDelete: () => notInstalled("pathDelete"),
616
- encodeUriComponent: () => notInstalled("encodeUriComponent"),
617
- decodeUriComponent: () => notInstalled("decodeUriComponent"),
618
- parseQuery: () => notInstalled("parseQuery"),
619
- buildUrl: () => notInstalled("buildUrl")
620
- };
621
- function setPortableImpl(impl) {
622
- if (impl === null) {
623
- current = {
624
- diffState: () => notInstalled("diffState"),
625
- matchPath: () => notInstalled("matchPath"),
626
- pathGet: () => notInstalled("pathGet"),
627
- pathHas: () => notInstalled("pathHas"),
628
- pathSet: () => notInstalled("pathSet"),
629
- pathDelete: () => notInstalled("pathDelete"),
630
- encodeUriComponent: () => notInstalled("encodeUriComponent"),
631
- decodeUriComponent: () => notInstalled("decodeUriComponent"),
632
- parseQuery: () => notInstalled("parseQuery"),
633
- buildUrl: () => notInstalled("buildUrl")
634
- };
635
- return;
636
- }
637
- current = impl;
638
- }
639
- var portable = {
640
- diffState: (o, n, b) => current.diffState(o, n, b),
641
- matchPath: (p, path) => current.matchPath(p, path),
642
- pathGet: (v, p) => current.pathGet(v, p),
643
- pathHas: (v, p) => current.pathHas(v, p),
644
- pathSet: (v, p, nv) => current.pathSet(v, p, nv),
645
- pathDelete: (v, p) => current.pathDelete(v, p),
646
- encodeUriComponent: (s) => current.encodeUriComponent(s),
647
- decodeUriComponent: (s) => current.decodeUriComponent(s),
648
- parseQuery: (f) => current.parseQuery(f),
649
- buildUrl: (p, q) => current.buildUrl(p, q)
650
- };
651
-
652
- // src/state.ts
653
- var IS_PROXY = Symbol.for("hypen.isProxy");
654
- var RAW_TARGET = Symbol.for("hypen.rawTarget");
655
- function deepClone(obj) {
656
- if (obj === null || typeof obj !== "object") {
657
- return obj;
658
- }
659
- if (typeof obj === "function") {
660
- return obj;
661
- }
662
- if (typeof obj.__getSnapshot === "function") {
663
- return obj.__getSnapshot();
664
- }
665
- if (obj instanceof WeakMap || obj instanceof WeakSet) {
666
- return obj;
667
- }
668
- const visited = new WeakMap;
669
- function cloneInternal(value) {
670
- if (value === null || typeof value !== "object") {
671
- return value;
672
- }
673
- if (typeof value === "function") {
674
- return value;
675
- }
676
- if (visited.has(value)) {
677
- return visited.get(value);
678
- }
679
- if (value instanceof WeakMap || value instanceof WeakSet) {
680
- return value;
681
- }
682
- if (value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
683
- try {
684
- return structuredClone(value);
685
- } catch {}
686
- }
687
- if (Array.isArray(value)) {
688
- const arrClone = [];
689
- visited.set(value, arrClone);
690
- for (let i = 0;i < value.length; i++) {
691
- arrClone[i] = cloneInternal(value[i]);
692
- }
693
- return arrClone;
694
- }
695
- const objClone = {};
696
- visited.set(value, objClone);
697
- for (const key in value) {
698
- if (Object.prototype.hasOwnProperty.call(value, key)) {
699
- objClone[key] = cloneInternal(value[key]);
700
- }
701
- }
702
- const symbolKeys = Object.getOwnPropertySymbols(value);
703
- for (const sym of symbolKeys) {
704
- objClone[sym] = cloneInternal(value[sym]);
705
- }
706
- return objClone;
707
- }
708
- return cloneInternal(obj);
709
- }
710
- function diffState(oldState, newState, basePath = "") {
711
- return portable.diffState(oldState, newState, basePath);
712
- }
713
- function createObservableState(initialState, options) {
714
- const opts = options || { onChange: () => {} };
715
- if (initialState === null || initialState === undefined) {
716
- initialState = {};
717
- }
718
- if (initialState instanceof Number || initialState instanceof String || initialState instanceof Boolean) {
719
- throw new TypeError("Cannot create observable state from primitive wrapper objects (Number, String, Boolean). " + "Use plain primitives or regular objects instead.");
720
- }
721
- initialState = deepClone(initialState);
722
- let lastSnapshot = deepClone(initialState);
723
- const pathPrefix = opts.pathPrefix || "";
724
- let batchDepth = 0;
725
- let pendingChange = null;
726
- function notifyChange() {
727
- if (batchDepth > 0)
728
- return;
729
- const change = diffState(lastSnapshot, state, pathPrefix);
730
- if (change.paths.length > 0) {
731
- lastSnapshot = deepClone(state);
732
- if (pendingChange) {
733
- change.paths.push(...pendingChange.paths);
734
- Object.assign(change.newValues, pendingChange.newValues);
735
- pendingChange = null;
736
- }
737
- opts.onChange(change);
738
- }
739
- }
740
- let notificationPending = false;
741
- function scheduleBatch() {
742
- if (batchDepth === 0) {
743
- if (!notificationPending) {
744
- notificationPending = true;
745
- queueMicrotask(() => {
746
- notificationPending = false;
747
- if (batchDepth === 0) {
748
- notifyChange();
749
- } else {}
750
- });
751
- }
752
- } else {
753
- pendingChange = pendingChange || { paths: [], newValues: {} };
754
- }
755
- }
756
- const proxyCache = new WeakMap;
757
- function createProxy(target, basePath) {
758
- const cached = proxyCache.get(target);
759
- if (cached)
760
- return cached;
761
- const proxy = new Proxy(target, {
762
- get(obj, prop) {
763
- if (prop === IS_PROXY)
764
- return true;
765
- if (prop === RAW_TARGET)
766
- return obj;
767
- if (prop === "__beginBatch") {
768
- return () => {
769
- batchDepth++;
770
- };
771
- }
772
- if (prop === "__endBatch") {
773
- return () => {
774
- batchDepth--;
775
- if (batchDepth === 0) {
776
- notifyChange();
777
- }
778
- };
779
- }
780
- if (prop === "__getSnapshot") {
781
- return () => deepClone(obj);
782
- }
783
- const value = obj[prop];
784
- if (value && typeof value === "object") {
785
- if (value[IS_PROXY]) {
786
- return value;
787
- }
788
- if (value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || value instanceof WeakMap || value instanceof WeakSet) {
789
- return value;
790
- }
791
- const cachedNested = proxyCache.get(value);
792
- if (cachedNested) {
793
- return cachedNested;
794
- }
795
- const nestedProxy = createProxy(value, basePath ? `${basePath}.${String(prop)}` : String(prop));
796
- return nestedProxy;
797
- }
798
- return value;
799
- },
800
- set(obj, prop, value) {
801
- const oldValue = obj[prop];
802
- if (value && typeof value === "object" && value[IS_PROXY]) {
803
- value = value[RAW_TARGET];
804
- }
805
- obj[prop] = value;
806
- if (oldValue !== value) {
807
- scheduleBatch();
808
- }
809
- return true;
810
- },
811
- deleteProperty(obj, prop) {
812
- const existed = Object.prototype.hasOwnProperty.call(obj, prop);
813
- const result = delete obj[prop];
814
- if (existed) {
815
- scheduleBatch();
816
- }
817
- return result;
818
- }
819
- });
820
- proxyCache.set(target, proxy);
821
- return proxy;
822
- }
823
- const state = createProxy(initialState, pathPrefix);
824
- return state;
825
- }
826
- function batchStateUpdates(state, fn) {
827
- const s = state;
828
- if (s.__beginBatch && s.__endBatch) {
829
- s.__beginBatch();
830
- try {
831
- fn();
832
- } finally {
833
- s.__endBatch();
834
- }
835
- } else {
836
- fn();
837
- }
838
- }
839
- function getStateSnapshot(state) {
840
- const s = state;
841
- if (s.__getSnapshot) {
842
- return s.__getSnapshot();
843
- }
844
- return deepClone(state);
845
- }
846
- function isStateProxy(value) {
847
- return value !== null && typeof value === "object" && value[IS_PROXY] === true;
848
- }
849
- function unwrapProxy(value) {
850
- if (value !== null && typeof value === "object" && value[IS_PROXY]) {
851
- return value[RAW_TARGET];
852
- }
853
- return value;
854
- }
855
-
856
- // src/logger.ts
857
- var LOG_LEVEL_ORDER = {
858
- debug: 0,
859
- info: 1,
860
- warn: 2,
861
- error: 3,
862
- none: 4
863
- };
864
- var LOG_LEVEL_COLORS = {
865
- debug: "\x1B[36m",
866
- info: "\x1B[32m",
867
- warn: "\x1B[33m",
868
- error: "\x1B[31m"
869
- };
870
- var RESET_COLOR = "\x1B[0m";
871
- function isProduction() {
872
- if (typeof process !== "undefined" && process.env) {
873
- return false;
874
- }
875
- return false;
876
- }
877
- var config = {
878
- level: isProduction() ? "error" : "info",
879
- colors: true,
880
- timestamps: false
881
- };
882
- function setLogLevel(level) {
883
- config.level = level;
884
- }
885
- function getLogLevel() {
886
- return config.level;
887
- }
888
- function configureLogger(options) {
889
- config = { ...config, ...options };
890
- }
891
- function enableLogging() {
892
- config.level = "debug";
893
- }
894
- function disableLogging() {
895
- config.level = "none";
896
- }
897
- function setDebugMode(enabled) {
898
- config.level = enabled ? "debug" : "error";
899
- }
900
- function isDebugMode() {
901
- return config.level === "debug";
902
- }
903
- function shouldLog(level) {
904
- return LOG_LEVEL_ORDER[level] >= LOG_LEVEL_ORDER[config.level];
905
- }
906
- function formatTag(tag, level) {
907
- const timestamp = config.timestamps ? `${new Date().toISOString()} ` : "";
908
- if (config.colors && level !== "none") {
909
- const color = LOG_LEVEL_COLORS[level];
910
- return `${timestamp}${color}[${tag}]${RESET_COLOR}`;
911
- }
912
- return `${timestamp}[${tag}]`;
913
- }
914
-
915
- class Logger {
916
- tag;
917
- constructor(tag) {
918
- this.tag = tag;
919
- }
920
- debug(...args) {
921
- if (!shouldLog("debug"))
922
- return;
923
- if (config.handler) {
924
- config.handler.debug(this.tag, ...args);
925
- } else {
926
- console.log(formatTag(this.tag, "debug"), ...args);
927
- }
928
- }
929
- info(...args) {
930
- if (!shouldLog("info"))
931
- return;
932
- if (config.handler) {
933
- config.handler.info(this.tag, ...args);
934
- } else {
935
- console.info(formatTag(this.tag, "info"), ...args);
936
- }
937
- }
938
- warn(...args) {
939
- if (!shouldLog("warn"))
940
- return;
941
- if (config.handler) {
942
- config.handler.warn(this.tag, ...args);
943
- } else {
944
- console.warn(formatTag(this.tag, "warn"), ...args);
945
- }
946
- }
947
- error(...args) {
948
- if (!shouldLog("error"))
949
- return;
950
- if (config.handler) {
951
- config.handler.error(this.tag, ...args);
952
- } else {
953
- console.error(formatTag(this.tag, "error"), ...args);
954
- }
955
- }
956
- time(label, fn) {
957
- if (!shouldLog("debug")) {
958
- return fn();
959
- }
960
- const start = performance.now();
961
- try {
962
- return fn();
963
- } finally {
964
- const duration = performance.now() - start;
965
- this.debug(`${label}: ${duration.toFixed(2)}ms`);
966
- }
967
- }
968
- async timeAsync(label, fn) {
969
- if (!shouldLog("debug")) {
970
- return fn();
971
- }
972
- const start = performance.now();
973
- try {
974
- return await fn();
975
- } finally {
976
- const duration = performance.now() - start;
977
- this.debug(`${label}: ${duration.toFixed(2)}ms`);
978
- }
979
- }
980
- child(subTag) {
981
- return new Logger(`${this.tag}:${subTag}`);
982
- }
983
- debugIf(condition, ...args) {
984
- if (condition)
985
- this.debug(...args);
986
- }
987
- warnIf(condition, ...args) {
988
- if (condition)
989
- this.warn(...args);
990
- }
991
- errorIf(condition, ...args) {
992
- if (condition)
993
- this.error(...args);
994
- }
995
- loggedOnce = new Set;
996
- warnOnce(key, ...args) {
997
- if (this.loggedOnce.has(key))
998
- return;
999
- this.loggedOnce.add(key);
1000
- this.warn(...args);
1001
- }
1002
- debugOnce(key, ...args) {
1003
- if (this.loggedOnce.has(key))
1004
- return;
1005
- this.loggedOnce.add(key);
1006
- this.debug(...args);
1007
- }
1008
- }
1009
- function createLogger(tag) {
1010
- return new Logger(tag);
1011
- }
1012
- var logger = createLogger("Hypen");
1013
- var log = {
1014
- debug: (tag, ...args) => {
1015
- if (!shouldLog("debug"))
1016
- return;
1017
- console.log(formatTag(tag, "debug"), ...args);
1018
- },
1019
- info: (tag, ...args) => {
1020
- if (!shouldLog("info"))
1021
- return;
1022
- console.info(formatTag(tag, "info"), ...args);
1023
- },
1024
- warn: (tag, ...args) => {
1025
- if (!shouldLog("warn"))
1026
- return;
1027
- console.warn(formatTag(tag, "warn"), ...args);
1028
- },
1029
- error: (tag, ...args) => {
1030
- if (!shouldLog("error"))
1031
- return;
1032
- console.error(formatTag(tag, "error"), ...args);
1033
- }
1034
- };
1035
- var frameworkLoggers = {
1036
- hypen: createLogger("Hypen"),
1037
- engine: createLogger("Engine"),
1038
- router: createLogger("Router"),
1039
- state: createLogger("State"),
1040
- events: createLogger("Events"),
1041
- remote: createLogger("Remote"),
1042
- renderer: createLogger("Renderer"),
1043
- module: createLogger("Module"),
1044
- lifecycle: createLogger("Lifecycle"),
1045
- loader: createLogger("Loader"),
1046
- context: createLogger("Context"),
1047
- discovery: createLogger("Discovery"),
1048
- plugin: createLogger("Plugin"),
1049
- canvas: createLogger("Canvas"),
1050
- debug: createLogger("Debug")
1051
- };
1052
-
1053
- // src/app.ts
1054
- var log2 = createLogger("ModuleInstance");
1055
-
1056
- class HypenAppBuilder {
1057
- initialState;
1058
- options;
1059
- createdHandler;
1060
- activatedHandler;
1061
- deactivatedHandler;
1062
- actionHandlers = new Map;
1063
- destroyedHandler;
1064
- disconnectHandler;
1065
- reconnectHandler;
1066
- expireHandler;
1067
- errorHandler;
1068
- template;
1069
- _registry;
1070
- dataSourceEntries = [];
1071
- _stateStore;
1072
- constructor(initialState, options, registry) {
1073
- this.initialState = initialState;
1074
- this.options = options || {};
1075
- this._registry = registry;
1076
- }
1077
- onCreated(fn) {
1078
- this.createdHandler = fn;
1079
- return this;
1080
- }
1081
- onAction(name, fn) {
1082
- this.actionHandlers.set(name, fn);
1083
- return this;
1084
- }
1085
- onActivated(fn) {
1086
- this.activatedHandler = fn;
1087
- return this;
1088
- }
1089
- onDeactivated(fn) {
1090
- this.deactivatedHandler = fn;
1091
- return this;
1092
- }
1093
- onDestroyed(fn) {
1094
- this.destroyedHandler = fn;
1095
- return this;
1096
- }
1097
- onDisconnect(fn) {
1098
- this.disconnectHandler = fn;
1099
- return this;
1100
- }
1101
- onReconnect(fn) {
1102
- this.reconnectHandler = fn;
1103
- return this;
1104
- }
1105
- onExpire(fn) {
1106
- this.expireHandler = fn;
1107
- return this;
1108
- }
1109
- onError(fn) {
1110
- this.errorHandler = fn;
1111
- return this;
1112
- }
1113
- persist(store) {
1114
- this._stateStore = store;
1115
- return this;
1116
- }
1117
- useDataSource(plugin, config2) {
1118
- this.dataSourceEntries.push({ plugin, config: config2 });
1119
- return this;
1120
- }
1121
- ui(template) {
1122
- this.template = template;
1123
- return this.build();
1124
- }
1125
- uiFile(path) {
1126
- const fs = (() => ({}));
1127
- this.template = fs.readFileSync(path, "utf-8").trim();
1128
- return this.build();
130
+ if (!known.has(elementType))
131
+ unknown.add(elementType);
1129
132
  }
1130
- build() {
1131
- const stateKeys = this.initialState !== null && typeof this.initialState === "object" ? Object.keys(this.initialState) : [];
1132
- const definition = {
1133
- name: this.options.name,
1134
- actions: Array.from(this.actionHandlers.keys()),
1135
- stateKeys,
1136
- persist: this.options.persist,
1137
- version: this.options.version,
1138
- initialState: this.initialState,
1139
- template: this.template,
1140
- dataSources: this.dataSourceEntries.length > 0 ? this.dataSourceEntries : undefined,
1141
- stateStore: this._stateStore,
1142
- handlers: {
1143
- onCreated: this.createdHandler,
1144
- onActivated: this.activatedHandler,
1145
- onDeactivated: this.deactivatedHandler,
1146
- onAction: this.actionHandlers,
1147
- onDestroyed: this.destroyedHandler,
1148
- onDisconnect: this.disconnectHandler,
1149
- onReconnect: this.reconnectHandler,
1150
- onExpire: this.expireHandler,
1151
- onError: this.errorHandler
1152
- }
1153
- };
1154
- if (this.options.name && this._registry) {
1155
- this._registry.set(this.options.name, definition);
1156
- }
1157
- return definition;
1158
- }
1159
- }
1160
-
1161
- class HypenApp {
1162
- _registry = new Map;
1163
- defineState(initial, options) {
1164
- return new HypenAppBuilder(initial, options, this._registry);
1165
- }
1166
- module(name) {
1167
- const registry = this._registry;
1168
- return {
1169
- defineState: (initial, options) => {
1170
- return new HypenAppBuilder(initial, { ...options, name }, registry);
1171
- }
1172
- };
1173
- }
1174
- get(name) {
1175
- return this._registry.get(name);
1176
- }
1177
- has(name) {
1178
- return this._registry.has(name);
1179
- }
1180
- get components() {
1181
- return this._registry;
1182
- }
1183
- getNames() {
1184
- return Array.from(this._registry.keys());
1185
- }
1186
- get size() {
1187
- return this._registry.size;
1188
- }
1189
- unregister(name) {
1190
- this._registry.delete(name);
1191
- }
1192
- clear() {
1193
- this._registry.clear();
1194
- }
1195
- }
1196
- var app = new HypenApp;
1197
-
1198
- class HypenModuleInstance {
1199
- engine;
1200
- definition;
1201
- state;
1202
- isDestroyed = false;
1203
- isActive = false;
1204
- router;
1205
- globalContext;
1206
- stateChangeCallbacks = [];
1207
- dataSourceManager;
1208
- dataSourceAccessor = {};
1209
- stateStore;
1210
- currentPersistKey = null;
1211
- persistDebounceTimer;
1212
- sessionId;
1213
- moduleKey = "";
1214
- constructor(engine, definition, router, globalContext, sessionId) {
1215
- this.engine = engine;
1216
- this.definition = definition;
1217
- this.router = router ?? null;
1218
- this.globalContext = globalContext;
1219
- this.sessionId = sessionId ?? crypto.randomUUID();
1220
- this.stateStore = definition.stateStore;
1221
- const moduleKey = (definition.name || "").toLowerCase();
1222
- this.moduleKey = moduleKey;
1223
- this.state = createObservableState(definition.initialState, {
1224
- onChange: (change) => {
1225
- this.engine.updateStateSparse(moduleKey || null, change.paths, change.newValues);
1226
- this.stateChangeCallbacks.forEach((cb) => cb());
1227
- this.persistIfNeeded();
1228
- }
1229
- });
1230
- const snapshot = getStateSnapshot(this.state);
1231
- if (moduleKey) {
1232
- this.engine.registerModule(moduleKey, definition.actions, definition.stateKeys, snapshot);
1233
- } else {
1234
- this.engine.setModule("AnonymousModule", definition.actions, definition.stateKeys, snapshot);
1235
- }
1236
- for (const [actionName, handler] of definition.handlers.onAction) {
1237
- log2.debug(`Registering action handler: ${actionName} for module ${definition.name}`);
1238
- this.engine.onAction(actionName, async (action) => {
1239
- log2.debug(`Action handler fired: ${actionName}`, action);
1240
- const actionCtx = {
1241
- name: action.name,
1242
- payload: action.payload,
1243
- sender: action.sender
1244
- };
1245
- const context = this.globalContext ? this.createGlobalContextAPI() : undefined;
1246
- const result = await this.executeAction(actionName, handler, {
1247
- action: actionCtx,
1248
- state: this.state,
1249
- context,
1250
- dataSources: this.dataSourceAccessor
1251
- });
1252
- if (!result.ok) {
1253
- const shouldRethrow = await this.handleError(result.error, { actionName });
1254
- if (shouldRethrow) {
1255
- throw result.error;
1256
- }
1257
- } else {
1258
- log2.debug(`Action handler completed: ${actionName}`);
1259
- }
1260
- });
1261
- }
1262
- this.engine.onAction("__hypen_bind", (action) => {
1263
- const payload = action.payload;
1264
- if (!payload?.path)
1265
- return;
1266
- const segments = payload.path.split(".");
1267
- let target = this.state;
1268
- for (let i = 0;i < segments.length - 1; i++) {
1269
- const seg = segments[i];
1270
- target = target?.[seg];
1271
- if (target == null)
1272
- return;
1273
- }
1274
- const lastSeg = segments[segments.length - 1];
1275
- target[lastSeg] = payload.value;
1276
- });
1277
- this._readyPromise = this.callCreatedHandler();
1278
- }
1279
- _readyPromise = Promise.resolve();
1280
- async waitForReady() {
1281
- await this._readyPromise;
1282
- }
1283
- async activate() {
1284
- if (this.isDestroyed || this.isActive)
1285
- return;
1286
- await this._readyPromise;
1287
- if (this.isDestroyed || this.isActive)
1288
- return;
1289
- this.isActive = true;
1290
- if (this.definition.handlers.onActivated) {
1291
- const context = this.globalContext ? this.createGlobalContextAPI() : undefined;
1292
- try {
1293
- await this.definition.handlers.onActivated(this.state, context);
1294
- } catch (e) {
1295
- const error = e instanceof HypenError ? e : new ActionError("onActivated", e);
1296
- const shouldRethrow = await this.handleError(error, { lifecycle: "activated" });
1297
- if (shouldRethrow) {
1298
- throw error;
1299
- }
1300
- }
1301
- }
1302
- }
1303
- async deactivate() {
1304
- if (this.isDestroyed || !this.isActive)
1305
- return;
1306
- this.isActive = false;
1307
- if (this.definition.handlers.onDeactivated) {
1308
- const context = this.globalContext ? this.createGlobalContextAPI() : undefined;
1309
- try {
1310
- await this.definition.handlers.onDeactivated(this.state, context);
1311
- } catch (e) {
1312
- const error = e instanceof HypenError ? e : new ActionError("onDeactivated", e);
1313
- const shouldRethrow = await this.handleError(error, { lifecycle: "deactivated" });
1314
- if (shouldRethrow) {
1315
- throw error;
1316
- }
1317
- }
1318
- }
1319
- }
1320
- createGlobalContextAPI() {
1321
- if (!this.globalContext) {
1322
- throw new Error("Global context not available");
1323
- }
1324
- const ctx = this.globalContext;
1325
- const api = {
1326
- getModule: (id) => ctx.getModule(id),
1327
- hasModule: (id) => ctx.hasModule(id),
1328
- getModuleIds: () => ctx.getModuleIds(),
1329
- getGlobalState: () => ctx.getGlobalState(),
1330
- emit: (event, payload) => ctx.emit(event, payload),
1331
- on: (event, handler) => ctx.on(event, handler),
1332
- router: this.router
1333
- };
1334
- const ctxRecord = ctx;
1335
- if (ctxRecord.__hypenEngine) {
1336
- api.__hypenEngine = ctxRecord.__hypenEngine;
1337
- }
1338
- return api;
1339
- }
1340
- async executeAction(actionName, handler, ctx) {
1341
- try {
1342
- const result = handler(ctx);
1343
- await result;
1344
- return Ok(undefined);
1345
- } catch (e) {
1346
- return Err(new ActionError(actionName, e));
1347
- }
1348
- }
1349
- async handleError(error, context) {
1350
- const errorCtx = {
1351
- error,
1352
- state: this.state,
1353
- actionName: context.actionName,
1354
- lifecycle: context.lifecycle
1355
- };
1356
- if (this.definition.handlers.onError) {
1357
- try {
1358
- const result = await this.definition.handlers.onError(errorCtx);
1359
- if (result && typeof result === "object") {
1360
- if ("handled" in result && result.handled) {
1361
- return false;
1362
- }
1363
- if ("rethrow" in result && result.rethrow) {
1364
- return true;
1365
- }
1366
- }
1367
- } catch (handlerError) {
1368
- log2.error("Error in onError handler:", handlerError);
1369
- }
1370
- }
1371
- if (this.globalContext) {
1372
- const eventContext = context.actionName ? `action:${context.actionName}` : context.lifecycle ? `lifecycle:${context.lifecycle}` : "unknown";
1373
- this.globalContext.emit("error", {
1374
- message: error.message,
1375
- error,
1376
- context: eventContext
1377
- });
1378
- }
1379
- log2.error(`${context.actionName ? `Action "${context.actionName}"` : `Lifecycle "${context.lifecycle}"`} error:`, error);
1380
- return false;
1381
- }
1382
- persistIfNeeded() {
1383
- if (!this.stateStore)
1384
- return;
1385
- const store = this.stateStore;
1386
- const newKey = store.resolveKey(this.state, this.definition.name || "AnonymousModule", this.sessionId);
1387
- if (newKey && !this.currentPersistKey) {
1388
- this.activatePersistence(newKey);
1389
- return;
1390
- }
1391
- if (!newKey && this.currentPersistKey) {
1392
- this.currentPersistKey = null;
1393
- return;
1394
- }
1395
- if (newKey && newKey !== this.currentPersistKey) {
1396
- this.activatePersistence(newKey);
1397
- return;
1398
- }
1399
- if (!this.currentPersistKey)
1400
- return;
1401
- clearTimeout(this.persistDebounceTimer);
1402
- this.persistDebounceTimer = setTimeout(() => {
1403
- const snapshot = getStateSnapshot(this.state);
1404
- store.save(this.currentPersistKey, snapshot);
1405
- }, 50);
1406
- }
1407
- async activatePersistence(key) {
1408
- this.currentPersistKey = key;
1409
- const stored = await this.stateStore.load(key);
1410
- if (stored) {
1411
- const merged = { ...this.definition.initialState, ...stored };
1412
- Object.assign(this.state, merged);
1413
- } else {
1414
- const snapshot = getStateSnapshot(this.state);
1415
- await this.stateStore.save(key, snapshot);
1416
- }
1417
- }
1418
- async callCreatedHandler() {
1419
- if (this.stateStore) {
1420
- const key = this.stateStore.resolveKey(this.state, this.definition.name || "AnonymousModule", this.sessionId);
1421
- if (key) {
1422
- this.currentPersistKey = key;
1423
- const stored = await this.stateStore.load(key);
1424
- if (stored) {
1425
- const merged = { ...this.definition.initialState, ...stored };
1426
- Object.assign(this.state, merged);
1427
- }
1428
- }
1429
- }
1430
- if (this.definition.dataSources?.length) {
1431
- const dsEngine = this.engine;
1432
- this.dataSourceManager = new DataSourceManager(dsEngine);
1433
- for (const { plugin, config: config2 } of this.definition.dataSources) {
1434
- try {
1435
- await this.dataSourceManager.use(plugin, config2);
1436
- this.dataSourceAccessor[plugin.name] = new Proxy(plugin, {
1437
- get(target, prop) {
1438
- if (typeof prop === "string" && !(prop in target)) {
1439
- return (...args) => target.call(prop, ...args);
1440
- }
1441
- return target[prop];
1442
- }
1443
- });
1444
- } catch (e) {
1445
- log2.error(`Failed to connect data source "${plugin.name}":`, e);
1446
- }
1447
- }
1448
- }
1449
- if (this.definition.handlers.onCreated) {
1450
- const context = this.globalContext ? this.createGlobalContextAPI() : undefined;
1451
- try {
1452
- await this.definition.handlers.onCreated(this.state, context);
1453
- } catch (e) {
1454
- const error = e instanceof HypenError ? e : new ActionError("onCreated", e);
1455
- const shouldRethrow = await this.handleError(error, { lifecycle: "created" });
1456
- if (shouldRethrow) {
1457
- throw error;
1458
- }
1459
- }
1460
- }
1461
- }
1462
- onStateChange(callback) {
1463
- this.stateChangeCallbacks.push(callback);
1464
- }
1465
- async destroy() {
1466
- if (this.isDestroyed)
1467
- return;
1468
- if (this.isActive) {
1469
- await this.deactivate();
1470
- }
1471
- if (this.currentPersistKey && this.stateStore) {
1472
- clearTimeout(this.persistDebounceTimer);
1473
- const snapshot = getStateSnapshot(this.state);
1474
- await this.stateStore.save(this.currentPersistKey, snapshot);
1475
- }
1476
- if (this.dataSourceManager) {
1477
- try {
1478
- await this.dataSourceManager.disconnectAll();
1479
- } catch (e) {
1480
- log2.error("Error disconnecting data sources:", e);
1481
- }
1482
- this.dataSourceManager = undefined;
1483
- this.dataSourceAccessor = {};
1484
- }
1485
- if (this.definition.handlers.onDestroyed) {
1486
- try {
1487
- await this.definition.handlers.onDestroyed(this.state);
1488
- } catch (e) {
1489
- const error = e instanceof HypenError ? e : new ActionError("onDestroyed", e);
1490
- const shouldRethrow = await this.handleError(error, { lifecycle: "destroyed" });
1491
- if (shouldRethrow) {
1492
- throw error;
1493
- }
1494
- }
1495
- }
1496
- this.isDestroyed = true;
1497
- }
1498
- getState() {
1499
- return getStateSnapshot(this.state);
1500
- }
1501
- getLiveState() {
1502
- return this.state;
1503
- }
1504
- updateState(patch) {
1505
- Object.assign(this.state, patch);
1506
- }
1507
- }
1508
-
1509
- // src/hypen.ts
1510
- function createBindingProxy(root) {
1511
- const handler = {
1512
- get(_, prop) {
1513
- if (prop === Symbol.toPrimitive || prop === "toString" || prop === "valueOf") {
1514
- return () => `@{${root}}`;
1515
- }
1516
- if (typeof prop === "symbol") {
1517
- return;
1518
- }
1519
- if (prop === "toJSON") {
1520
- return () => `@{${root}}`;
1521
- }
1522
- return createBindingProxy(`${root}.${prop}`);
1523
- },
1524
- has() {
1525
- return true;
1526
- },
1527
- ownKeys() {
1528
- return [];
1529
- },
1530
- getOwnPropertyDescriptor() {
1531
- return {
1532
- configurable: true,
1533
- enumerable: true
1534
- };
1535
- }
1536
- };
1537
- return new Proxy({}, handler);
1538
- }
1539
- var state = createBindingProxy("state");
1540
- var item = createBindingProxy("item");
1541
- var index = {
1542
- [Symbol.toPrimitive]: () => "@{index}",
1543
- toString: () => "@{index}",
1544
- valueOf: () => "@{index}",
1545
- toJSON: () => "@{index}"
1546
- };
1547
- function hypen(strings, ...expressions) {
1548
- let result = strings[0];
1549
- for (let i = 0;i < expressions.length; i++) {
1550
- const expr = expressions[i];
1551
- result += String(expr);
1552
- result += strings[i + 1];
1553
- }
1554
- return result.trim();
1555
- }
1556
-
1557
- // src/renderer.ts
1558
- var log3 = frameworkLoggers.renderer;
1559
-
1560
- class BaseRenderer {
1561
- nodes = new Map;
1562
- getNode(id) {
1563
- return this.nodes.get(id);
1564
- }
1565
- clear() {
1566
- this.nodes.clear();
1567
- }
1568
- applyPatch(patch) {
1569
- switch (patch.type) {
1570
- case "create":
1571
- this.onCreate(patch.id, patch.elementType, patch.props || {});
1572
- break;
1573
- case "setProp":
1574
- this.onSetProp(patch.id, patch.name, patch.value);
1575
- break;
1576
- case "setText":
1577
- this.onSetText(patch.id, patch.text);
1578
- break;
1579
- case "insert":
1580
- this.onInsert(patch.parentId, patch.id, patch.beforeId);
1581
- break;
1582
- case "move":
1583
- this.onMove(patch.parentId, patch.id, patch.beforeId);
1584
- break;
1585
- case "remove":
1586
- this.onRemove(patch.id);
1587
- break;
1588
- case "attachEvent":
1589
- this.onAttachEvent(patch.id, patch.eventName);
1590
- break;
1591
- case "detachEvent":
1592
- this.onDetachEvent(patch.id, patch.eventName);
1593
- break;
1594
- }
1595
- }
1596
- }
1597
-
1598
- class ConsoleRenderer {
1599
- applyPatches(patches) {
1600
- console.group("Hypen Patches");
1601
- for (const patch of patches) {
1602
- console.log(patch);
1603
- }
1604
- console.groupEnd();
1605
- }
1606
- }
1607
-
1608
- // src/disposable.ts
1609
- var log4 = frameworkLoggers.lifecycle;
1610
- function isDisposable(obj) {
1611
- return obj !== null && typeof obj === "object" && "dispose" in obj && typeof obj.dispose === "function";
1612
- }
1613
-
1614
- class DisposableStack {
1615
- stack = [];
1616
- disposed = false;
1617
- add(disposable) {
1618
- if (this.disposed) {
1619
- disposable.dispose();
1620
- return disposable;
1621
- }
1622
- this.stack.push(disposable);
1623
- return disposable;
1624
- }
1625
- addCallback(callback) {
1626
- this.add({ dispose: callback });
1627
- }
1628
- addValue(value, dispose) {
1629
- this.add({ dispose: () => dispose(value) });
1630
- return value;
1631
- }
1632
- dispose() {
1633
- if (this.disposed)
1634
- return;
1635
- this.disposed = true;
1636
- while (this.stack.length > 0) {
1637
- const item2 = this.stack.pop();
1638
- try {
1639
- item2.dispose();
1640
- } catch (error) {
1641
- log4.error("Error during dispose:", error);
1642
- }
1643
- }
1644
- }
1645
- get isDisposed() {
1646
- return this.disposed;
1647
- }
1648
- get size() {
1649
- return this.stack.length;
1650
- }
1651
- }
1652
- function disposableListener(target, event, handler, options) {
1653
- target.addEventListener(event, handler, options);
1654
- return {
1655
- dispose: () => target.removeEventListener(event, handler, options)
1656
- };
1657
- }
1658
- function disposableTimeout(callback, ms) {
1659
- const id = setTimeout(callback, ms);
1660
- return {
1661
- id,
1662
- dispose: () => clearTimeout(id)
1663
- };
1664
- }
1665
- function disposableInterval(callback, ms) {
1666
- const id = setInterval(callback, ms);
1667
- return {
1668
- id,
1669
- dispose: () => clearInterval(id)
1670
- };
1671
- }
1672
- function disposableWebSocket(ws) {
1673
- return {
1674
- dispose: () => {
1675
- if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
1676
- ws.close();
1677
- }
1678
- }
1679
- };
133
+ return { unknownTypes: [...unknown] };
1680
134
  }
1681
- function disposableAbortController() {
1682
- const controller = new AbortController;
1683
- return {
1684
- controller,
1685
- signal: controller.signal,
1686
- dispose: () => controller.abort()
1687
- };
1688
- }
1689
- function disposableSubscription(unsubscribe) {
1690
- return { dispose: unsubscribe };
1691
- }
1692
- var ELEMENT_DISPOSABLES = Symbol("hypen.disposables");
1693
- function getElementDisposables(element) {
1694
- const existing = element[ELEMENT_DISPOSABLES];
1695
- if (existing instanceof DisposableStack) {
1696
- return existing;
1697
- }
1698
- const stack = new DisposableStack;
1699
- element[ELEMENT_DISPOSABLES] = stack;
1700
- return stack;
1701
- }
1702
- function disposeElement(element) {
1703
- const stack = element[ELEMENT_DISPOSABLES];
1704
- if (stack instanceof DisposableStack) {
1705
- stack.dispose();
1706
- delete element[ELEMENT_DISPOSABLES];
1707
- }
1708
- }
1709
- function hasElementDisposables(element) {
1710
- return element[ELEMENT_DISPOSABLES] instanceof DisposableStack;
1711
- }
1712
-
1713
- class DisposableMixin {
1714
- disposables = new DisposableStack;
1715
- track(disposable) {
1716
- return this.disposables.add(disposable);
1717
- }
1718
- onDispose(callback) {
1719
- this.disposables.addCallback(callback);
1720
- }
1721
- dispose() {
1722
- this.disposables.dispose();
1723
- }
1724
- }
1725
- function compositeDisposable(...disposables) {
1726
- return {
1727
- dispose: () => {
1728
- for (const d of disposables) {
1729
- try {
1730
- d.dispose();
1731
- } catch (error) {
1732
- log4.error("Error during dispose:", error);
1733
- }
1734
- }
1735
- }
1736
- };
1737
- }
1738
- async function using(resource, fn) {
1739
- const r = typeof resource === "function" ? resource() : resource;
1740
- try {
1741
- return await fn(r);
1742
- } finally {
1743
- r.dispose();
1744
- }
1745
- }
1746
- function usingSync(resource, fn) {
1747
- const r = typeof resource === "function" ? resource() : resource;
1748
- try {
1749
- return fn(r);
1750
- } finally {
1751
- r.dispose();
1752
- }
1753
- }
1754
-
1755
- // src/router.ts
1756
- var log5 = frameworkLoggers.router;
1757
-
1758
- class HypenRouter {
1759
- state;
1760
- subscribers = new Set;
1761
- isInitialized = false;
1762
- isUpdating = false;
1763
- browserListeners = [];
1764
- constructor() {
1765
- this.state = createObservableState({
1766
- currentPath: "/",
1767
- params: {},
1768
- query: {},
1769
- previousPath: null
1770
- }, {
1771
- onChange: () => {
1772
- this.notifySubscribers();
1773
- }
1774
- });
1775
- if (typeof window !== "undefined") {
1776
- this.initializeBrowserSync();
1777
- }
1778
- }
1779
- initializeBrowserSync() {
1780
- const initialPath = this.getPathFromBrowser();
1781
- this.state.currentPath = initialPath;
1782
- this.state.params = {};
1783
- this.state.query = this.parseQuery();
1784
- this.browserListeners.push(disposableListener(window, "popstate", () => {
1785
- const newPath = this.getPathFromBrowser();
1786
- this.updatePath(newPath, false);
1787
- }));
1788
- this.browserListeners.push(disposableListener(window, "hashchange", () => {
1789
- if (this.isUpdating)
1790
- return;
1791
- const newPath = this.getPathFromBrowser();
1792
- this.updatePath(newPath, false);
1793
- }));
1794
- this.isInitialized = true;
1795
- log5.debug("Router initialized at:", initialPath);
1796
- }
1797
- getPathFromBrowser() {
1798
- if (typeof window === "undefined")
1799
- return "/";
1800
- const hash = window.location.hash.slice(1);
1801
- if (hash)
1802
- return hash;
1803
- return window.location.pathname;
1804
- }
1805
- parseQuery() {
1806
- if (typeof window === "undefined")
1807
- return {};
1808
- const query = {};
1809
- const searchParams = new URLSearchParams(window.location.search);
1810
- searchParams.forEach((value, key) => {
1811
- query[key] = value;
1812
- });
1813
- return query;
1814
- }
1815
- push(path) {
1816
- log5.debug("push:", path);
1817
- this.updatePath(path, true);
1818
- }
1819
- replace(path) {
1820
- log5.debug("replace:", path);
1821
- this.updatePath(path, true, true);
1822
- }
1823
- back() {
1824
- log5.debug("back");
1825
- if (typeof window !== "undefined") {
1826
- window.history.back();
1827
- }
1828
- }
1829
- forward() {
1830
- log5.debug("forward");
1831
- if (typeof window !== "undefined") {
1832
- window.history.forward();
1833
- }
1834
- }
1835
- updatePath(path, updateBrowser, replace = false) {
1836
- if (this.isUpdating)
1837
- return;
1838
- this.isUpdating = true;
1839
- try {
1840
- const oldPath = this.state.currentPath;
1841
- this.state.previousPath = oldPath;
1842
- this.state.currentPath = path;
1843
- this.state.query = this.parseQuery();
1844
- this.notifySubscribers();
1845
- if (updateBrowser && typeof window !== "undefined") {
1846
- const url = "#" + path;
1847
- if (replace) {
1848
- window.history.replaceState(null, "", url);
1849
- } else {
1850
- window.history.pushState(null, "", url);
1851
- }
1852
- try {
1853
- const hashChangeEvent = new HashChangeEvent("hashchange", {
1854
- oldURL: window.location.href.replace(window.location.hash, "#" + oldPath),
1855
- newURL: window.location.href
1856
- });
1857
- window.dispatchEvent(hashChangeEvent);
1858
- } catch {}
1859
- }
1860
- } finally {
1861
- this.isUpdating = false;
1862
- }
1863
- }
1864
- getCurrentPath() {
1865
- return this.state.currentPath;
1866
- }
1867
- getParams() {
1868
- return { ...this.state.params };
1869
- }
1870
- getQuery() {
1871
- return { ...this.state.query };
1872
- }
1873
- getState() {
1874
- return getStateSnapshot(this.state);
1875
- }
1876
- matchPath(pattern, path) {
1877
- if (!pattern || typeof pattern !== "string")
1878
- return null;
1879
- if (!path || typeof path !== "string")
1880
- return null;
1881
- const cleanPath = path.split("?")[0] ?? path;
1882
- const result = portable.matchPath(pattern, cleanPath);
1883
- if (!result)
1884
- return null;
1885
- const params = {};
1886
- for (const [name, raw] of Object.entries(result.params)) {
1887
- try {
1888
- params[name] = decodeURIComponent(raw);
1889
- } catch {
1890
- params[name] = raw;
1891
- }
1892
- }
1893
- return {
1894
- params,
1895
- query: this.state.query,
1896
- path
1897
- };
1898
- }
1899
- onNavigate(callback) {
1900
- this.subscribers.add(callback);
1901
- try {
1902
- callback(this.getState());
1903
- } catch (error) {
1904
- log5.error("Error in route subscriber:", error);
1905
- }
1906
- return () => {
1907
- this.subscribers.delete(callback);
1908
- };
1909
- }
1910
- notifySubscribers() {
1911
- const routeState = this.getState();
1912
- this.subscribers.forEach((callback) => {
1913
- try {
1914
- callback(routeState);
1915
- } catch (error) {
1916
- log5.error("Error in route subscriber:", error);
1917
- }
1918
- });
1919
- }
1920
- isActive(pattern) {
1921
- return this.matchPath(pattern, this.state.currentPath) !== null;
1922
- }
1923
- buildUrl(path, query) {
1924
- if (!query || Object.keys(query).length === 0) {
1925
- return path;
1926
- }
1927
- const queryString = new URLSearchParams(query).toString();
1928
- return `${path}?${queryString}`;
1929
- }
1930
- dispose() {
1931
- for (const listener of this.browserListeners) {
1932
- listener.dispose();
1933
- }
1934
- this.browserListeners = [];
1935
- this.subscribers.clear();
1936
- this.isInitialized = false;
1937
- log5.debug("Router disposed");
1938
- }
1939
- [Symbol.dispose]() {
1940
- this.dispose();
1941
- }
1942
- }
1943
-
1944
- // src/managed-router.ts
1945
- var log6 = createLogger("ManagedRouter");
1946
- var DEFAULT_MAX_PERSISTED_MODULES = 10;
1947
-
1948
- class ManagedRouter {
1949
- router;
1950
- engine;
1951
- registry;
1952
- globalContext;
1953
- routes = [];
1954
- activeModule = null;
1955
- activeRoute = null;
1956
- unsubscribe = null;
1957
- persistedModules = new Map;
1958
- maxPersistedModules;
1959
- navPromise = Promise.resolve();
1960
- constructor(router, engine, registry, globalContext, options = {}) {
1961
- this.router = router;
1962
- this.engine = engine;
1963
- this.registry = registry;
1964
- this.globalContext = globalContext;
1965
- const cap = options.maxPersistedModules ?? DEFAULT_MAX_PERSISTED_MODULES;
1966
- this.maxPersistedModules = cap > 0 ? cap : DEFAULT_MAX_PERSISTED_MODULES;
1967
- }
1968
- addRoute(route) {
1969
- this.routes.push(route);
1970
- return this;
1971
- }
1972
- start() {
1973
- this.unsubscribe = this.router.onNavigate((routeState) => {
1974
- this.handleRouteChange(routeState);
1975
- });
1976
- this.installRouterActions();
1977
- }
1978
- installRouterActions() {
1979
- const router = this.router;
1980
- const defer = (fn) => queueMicrotask(fn);
1981
- const readTo = (action) => {
1982
- const payload = action?.payload;
1983
- const to = payload?.to;
1984
- return typeof to === "string" && to.length > 0 ? to : null;
1985
- };
1986
- this.engine.onAction("router.push", (action) => {
1987
- const to = readTo(action);
1988
- if (to)
1989
- defer(() => router.push(to));
1990
- });
1991
- this.engine.onAction("router.replace", (action) => {
1992
- const to = readTo(action);
1993
- if (to)
1994
- defer(() => router.replace(to));
1995
- });
1996
- this.engine.onAction("router.back", () => {
1997
- defer(() => router.back());
1998
- });
1999
- this.engine.onAction("router.forward", () => {
2000
- defer(() => router.forward());
2001
- });
2002
- }
2003
- async stop() {
2004
- if (this.unsubscribe) {
2005
- this.unsubscribe();
2006
- this.unsubscribe = null;
2007
- }
2008
- const cleanup = this.navPromise.catch(() => {}).then(async () => {
2009
- await this.unmountActive();
2010
- for (const [moduleId, instance] of this.persistedModules) {
2011
- log6.debug(`Destroying persisted module on stop: ${moduleId}`);
2012
- try {
2013
- await instance.destroy();
2014
- } catch (e) {
2015
- log6.error(`Error destroying persisted module ${moduleId}:`, e);
2016
- }
2017
- this.globalContext.unregisterModule(moduleId);
2018
- }
2019
- this.persistedModules.clear();
2020
- });
2021
- this.navPromise = cleanup;
2022
- await cleanup;
2023
- this.router.dispose();
2024
- }
2025
- async waitForNavigation() {
2026
- try {
2027
- await this.navPromise;
2028
- } catch {}
2029
- }
2030
- getActiveModule() {
2031
- return this.activeModule;
2032
- }
2033
- getActiveRoute() {
2034
- return this.activeRoute;
2035
- }
2036
- handleRouteChange(routeState) {
2037
- this.navPromise = this.navPromise.catch((e) => {
2038
- log6.error("Previous navigation failed:", e);
2039
- }).then(() => this.processRouteChange(routeState));
2040
- }
2041
- async processRouteChange(routeState) {
2042
- const path = routeState.currentPath;
2043
- const matched = this.matchRoute(path);
2044
- if (!matched) {
2045
- log6.debug(`No route matched for path: ${path}`);
2046
- await this.unmountActive();
2047
- return;
2048
- }
2049
- if (this.activeRoute && this.activeRoute.path === matched.path) {
2050
- return;
2051
- }
2052
- await this.unmountActive();
2053
- await this.mount(matched);
2054
- }
2055
- matchRoute(path) {
2056
- for (const route of this.routes) {
2057
- if (this.router.matchPath(route.path, path) !== null) {
2058
- return route;
2059
- }
2060
- }
2061
- return null;
2062
- }
2063
- async mount(route) {
2064
- const definition = route.module || this.registry.get(route.component);
2065
- if (!definition) {
2066
- log6.debug(`No module definition found for component: ${route.component}`);
2067
- this.activeRoute = route;
2068
- return;
2069
- }
2070
- const namedDef = {
2071
- ...definition,
2072
- name: definition.name || route.component.toLowerCase()
2073
- };
2074
- const moduleId = namedDef.name.toLowerCase();
2075
- const persisted = this.persistedModules.get(moduleId);
2076
- if (persisted) {
2077
- log6.debug(`Restoring persisted module: ${moduleId} for route: ${route.path}`);
2078
- this.activeModule = persisted;
2079
- this.activeRoute = route;
2080
- this.persistedModules.delete(moduleId);
2081
- await persisted.activate();
2082
- return;
2083
- }
2084
- log6.debug(`Mounting module: ${namedDef.name} for route: ${route.path}`);
2085
- const instance = new HypenModuleInstance(this.engine, namedDef, this.router, this.globalContext);
2086
- this.globalContext.registerModule(moduleId, instance);
2087
- this.activeModule = instance;
2088
- this.activeRoute = route;
2089
- await instance.activate();
2090
- }
2091
- async unmountActive() {
2092
- if (!this.activeModule || !this.activeRoute) {
2093
- this.activeModule = null;
2094
- this.activeRoute = null;
2095
- return;
2096
- }
2097
- const active = this.activeModule;
2098
- const route = this.activeRoute;
2099
- const definition = route.module || this.registry.get(route.component);
2100
- const moduleId = (definition?.name || route.component).toLowerCase();
2101
- const persist = definition != null && definition.persist !== false;
2102
- this.activeModule = null;
2103
- this.activeRoute = null;
2104
- try {
2105
- await active.deactivate();
2106
- } catch (e) {
2107
- log6.error(`Error deactivating module ${moduleId}:`, e);
2108
- }
2109
- if (persist) {
2110
- log6.debug(`Persisting module: ${moduleId}`);
2111
- this.persistedModules.delete(moduleId);
2112
- this.persistedModules.set(moduleId, active);
2113
- await this.evictPersistedOverflow();
2114
- } else {
2115
- log6.debug(`Unmounting module: ${moduleId}`);
2116
- try {
2117
- await active.destroy();
2118
- } catch (e) {
2119
- log6.error(`Error destroying module ${moduleId}:`, e);
2120
- }
2121
- this.globalContext.unregisterModule(moduleId);
2122
- }
2123
- }
2124
- async evictPersistedOverflow() {
2125
- while (this.persistedModules.size > this.maxPersistedModules) {
2126
- const oldest = this.persistedModules.keys().next();
2127
- if (oldest.done)
2128
- break;
2129
- const oldestId = oldest.value;
2130
- const evicted = this.persistedModules.get(oldestId);
2131
- this.persistedModules.delete(oldestId);
2132
- log6.debug(`Evicting persisted module (LRU): ${oldestId}`);
2133
- try {
2134
- await evicted.destroy();
2135
- } catch (e) {
2136
- log6.error(`Error destroying evicted module ${oldestId}:`, e);
2137
- }
2138
- this.globalContext.unregisterModule(oldestId);
2139
- }
2140
- }
2141
- }
2142
-
2143
- // src/events.ts
2144
- var log7 = frameworkLoggers.events;
2145
-
2146
- class TypedEventEmitter {
2147
- eventBus = new Map;
2148
- emit(event, payload) {
2149
- const handlers = this.eventBus.get(event);
2150
- if (!handlers || handlers.size === 0) {
2151
- return;
2152
- }
2153
- handlers.forEach((handler) => {
2154
- try {
2155
- handler(payload);
2156
- } catch (error) {
2157
- log7.error(`Error in event handler for "${String(event)}":`, error);
2158
- }
2159
- });
2160
- }
2161
- on(event, handler) {
2162
- if (!this.eventBus.has(event)) {
2163
- this.eventBus.set(event, new Set);
2164
- }
2165
- const handlers = this.eventBus.get(event);
2166
- handlers.add(handler);
2167
- return () => {
2168
- handlers.delete(handler);
2169
- if (handlers.size === 0) {
2170
- this.eventBus.delete(event);
2171
- }
2172
- };
2173
- }
2174
- once(event, handler) {
2175
- const wrappedHandler = (payload) => {
2176
- handler(payload);
2177
- unsubscribe();
2178
- };
2179
- const unsubscribe = this.on(event, wrappedHandler);
2180
- return unsubscribe;
2181
- }
2182
- off(event, handler) {
2183
- const handlers = this.eventBus.get(event);
2184
- if (handlers) {
2185
- handlers.delete(handler);
2186
- if (handlers.size === 0) {
2187
- this.eventBus.delete(event);
2188
- }
2189
- }
2190
- }
2191
- removeAllListeners(event) {
2192
- this.eventBus.delete(event);
2193
- }
2194
- clearAll() {
2195
- this.eventBus.clear();
2196
- }
2197
- listenerCount(event) {
2198
- return this.eventBus.get(event)?.size ?? 0;
2199
- }
2200
- eventNames() {
2201
- return Array.from(this.eventBus.keys());
2202
- }
2203
- }
2204
- function createEventEmitter() {
2205
- return new TypedEventEmitter;
2206
- }
2207
-
2208
- // src/context.ts
2209
- var log8 = frameworkLoggers.context;
2210
-
2211
- class HypenGlobalContext {
2212
- modules = new Map;
2213
- typedEvents;
2214
- constructor() {
2215
- this.typedEvents = new TypedEventEmitter;
2216
- }
2217
- get events() {
2218
- return this.typedEvents;
2219
- }
2220
- registerModule(id, instance) {
2221
- if (this.modules.has(id)) {
2222
- log8.warn(`Module "${id}" is already registered. Overwriting.`);
2223
- }
2224
- this.modules.set(id, instance);
2225
- log8.debug(`Registered module: ${id}`);
2226
- }
2227
- unregisterModule(id) {
2228
- this.modules.delete(id);
2229
- log8.debug(`Unregistered module: ${id}`);
2230
- }
2231
- getModule(id) {
2232
- const module = this.modules.get(id);
2233
- if (!module) {
2234
- throw new Error(`Module "${id}" not found. Available modules: ${Array.from(this.modules.keys()).join(", ")}`);
2235
- }
2236
- return {
2237
- state: module.getLiveState(),
2238
- setState: (patch) => module.updateState(patch),
2239
- getState: () => module.getState()
2240
- };
2241
- }
2242
- hasModule(id) {
2243
- return this.modules.has(id);
2244
- }
2245
- getModuleIds() {
2246
- return Array.from(this.modules.keys());
2247
- }
2248
- getGlobalState() {
2249
- const state2 = {};
2250
- this.modules.forEach((module, id) => {
2251
- state2[id] = module.getState();
2252
- });
2253
- return state2;
2254
- }
2255
- emit(event, payload) {
2256
- if (this.typedEvents.listenerCount(event) === 0) {
2257
- log8.debug(`Event "${event}" emitted but no listeners`);
2258
- return;
2259
- }
2260
- log8.debug(`Emitting event: ${event}`, payload);
2261
- this.typedEvents.emit(event, payload);
2262
- }
2263
- on(event, handler) {
2264
- log8.debug(`Listening to event: ${event}`);
2265
- return this.typedEvents.on(event, handler);
2266
- }
2267
- off(event, handler) {
2268
- this.typedEvents.off(event, handler);
2269
- }
2270
- clearEvent(event) {
2271
- this.typedEvents.removeAllListeners(event);
2272
- }
2273
- clearAllEvents() {
2274
- this.typedEvents.clearAll();
2275
- }
2276
- debug() {
2277
- return {
2278
- modules: this.getModuleIds(),
2279
- events: this.typedEvents.eventNames(),
2280
- state: this.getGlobalState()
2281
- };
2282
- }
2283
- }
2284
-
2285
- // src/retry.ts
2286
- var DEFAULT_OPTIONS = {
2287
- maxAttempts: 3,
2288
- delayMs: 1000,
2289
- backoff: "exponential",
2290
- maxDelayMs: 30000,
2291
- jitter: 0.1
2292
- };
2293
- function calculateDelay(attempt, options) {
2294
- let delay;
2295
- switch (options.backoff) {
2296
- case "exponential":
2297
- delay = options.delayMs * Math.pow(2, attempt - 1);
2298
- break;
2299
- case "linear":
2300
- delay = options.delayMs * attempt;
2301
- break;
2302
- case "none":
2303
- delay = options.delayMs;
2304
- break;
2305
- }
2306
- if (options.jitter > 0) {
2307
- const jitterRange = delay * options.jitter;
2308
- delay += (Math.random() * 2 - 1) * jitterRange;
2309
- }
2310
- return Math.min(delay, options.maxDelayMs);
2311
- }
2312
- function sleep(ms, signal) {
2313
- return new Promise((resolve, reject) => {
2314
- if (signal?.aborted) {
2315
- reject(new Error("Retry aborted"));
2316
- return;
2317
- }
2318
- const timeoutId = setTimeout(resolve, ms);
2319
- signal?.addEventListener("abort", () => {
2320
- clearTimeout(timeoutId);
2321
- reject(new Error("Retry aborted"));
2322
- });
2323
- });
2324
- }
2325
- async function retry(fn, options = {}) {
2326
- const opts = { ...DEFAULT_OPTIONS, ...options };
2327
- let lastError = new Error("No attempts made");
2328
- for (let attempt = 1;attempt <= opts.maxAttempts; attempt++) {
2329
- try {
2330
- if (opts.signal?.aborted) {
2331
- throw new Error("Retry aborted");
2332
- }
2333
- return await fn();
2334
- } catch (e) {
2335
- lastError = e instanceof Error ? e : new Error(String(e));
2336
- if (opts.shouldRetry && !opts.shouldRetry(lastError)) {
2337
- throw lastError;
2338
- }
2339
- if (attempt === opts.maxAttempts) {
2340
- break;
2341
- }
2342
- const delayMs = calculateDelay(attempt, opts);
2343
- opts.onRetry?.(attempt, lastError, delayMs);
2344
- await sleep(delayMs, opts.signal);
2345
- }
2346
- }
2347
- throw lastError;
2348
- }
2349
- async function retryResult(fn, options = {}) {
2350
- try {
2351
- const value = await retry(fn, options);
2352
- return Ok(value);
2353
- } catch (e) {
2354
- return Err(e instanceof Error ? e : new Error(String(e)));
2355
- }
2356
- }
2357
- function withRetry(fn, options = {}) {
2358
- return (...args) => retry(() => fn(...args), options);
2359
- }
2360
- var RetryConditions = {
2361
- networkErrors: (error) => {
2362
- const message = error.message.toLowerCase();
2363
- return message.includes("network") || message.includes("fetch") || message.includes("timeout") || message.includes("econnrefused") || message.includes("econnreset") || message.includes("socket");
2364
- },
2365
- httpRetryable: (error) => {
2366
- const status = error.status;
2367
- if (!status)
2368
- return false;
2369
- return [408, 429, 500, 502, 503, 504].includes(status);
2370
- },
2371
- websocketErrors: (error) => {
2372
- const message = error.message.toLowerCase();
2373
- return message.includes("websocket") || message.includes("connection") || message.includes("close");
2374
- },
2375
- any: (...conditions) => (error) => conditions.some((c) => c(error)),
2376
- all: (...conditions) => (error) => conditions.every((c) => c(error))
2377
- };
2378
- var RetryPresets = {
2379
- aggressive: {
2380
- maxAttempts: 10,
2381
- delayMs: 500,
2382
- backoff: "exponential",
2383
- maxDelayMs: 60000,
2384
- jitter: 0.2
2385
- },
2386
- conservative: {
2387
- maxAttempts: 3,
2388
- delayMs: 2000,
2389
- backoff: "linear",
2390
- maxDelayMs: 1e4,
2391
- jitter: 0.1
2392
- },
2393
- fast: {
2394
- maxAttempts: 5,
2395
- delayMs: 100,
2396
- backoff: "exponential",
2397
- maxDelayMs: 2000,
2398
- jitter: 0
2399
- },
2400
- websocket: {
2401
- maxAttempts: 10,
2402
- delayMs: 1000,
2403
- backoff: "exponential",
2404
- maxDelayMs: 30000,
2405
- jitter: 0.1,
2406
- shouldRetry: RetryConditions.websocketErrors
2407
- }
2408
- };
2409
-
2410
- // src/remote/client.ts
2411
- var log9 = frameworkLoggers.remote;
2412
-
2413
- class RemoteEngine {
2414
- ws = null;
2415
- url;
2416
- state = "disconnected";
2417
- options;
2418
- reconnectAttempts = 0;
2419
- disposables = new DisposableStack;
2420
- reconnectDisposable = null;
2421
- currentSessionId = null;
2422
- sessionOptions;
2423
- patchCallbacks = [];
2424
- stateCallbacks = [];
2425
- connectionCallbacks = [];
2426
- disconnectionCallbacks = [];
2427
- errorCallbacks = [];
2428
- sessionEstablishedCallbacks = [];
2429
- sessionExpiredCallbacks = [];
2430
- currentState = null;
2431
- currentRevision = 0;
2432
- moduleName = "";
2433
- navigationDisposable = null;
2434
- lastViewValue = null;
2435
- handlingPopState = false;
2436
- constructor(url, options = {}) {
2437
- this.url = url;
2438
- const navOpt = options.navigation;
2439
- const navigation = navOpt ? {
2440
- backAction: (typeof navOpt === "object" ? navOpt.backAction : undefined) ?? "navigateBack",
2441
- viewStateKey: (typeof navOpt === "object" ? navOpt.viewStateKey : undefined) ?? "currentView"
2442
- } : undefined;
2443
- this.options = {
2444
- autoReconnect: options.autoReconnect ?? true,
2445
- reconnectInterval: options.reconnectInterval ?? 3000,
2446
- maxReconnectAttempts: options.maxReconnectAttempts ?? 10,
2447
- session: options.session,
2448
- navigation
2449
- };
2450
- this.sessionOptions = options.session;
2451
- if (options.session?.id) {
2452
- this.currentSessionId = options.session.id;
2453
- }
2454
- }
2455
- async connect() {
2456
- if (this.state === "connected" || this.state === "connecting") {
2457
- return Ok(undefined);
2458
- }
2459
- this.state = "connecting";
2460
- return new Promise((resolve) => {
2461
- try {
2462
- this.ws = new WebSocket(this.url);
2463
- this.disposables.add(disposableWebSocket(this.ws));
2464
- const messageHandler = (event) => {
2465
- this.handleMessage(event.data);
2466
- };
2467
- this.disposables.add(disposableListener(this.ws, "message", messageHandler));
2468
- const errorHandler = () => {
2469
- this.state = "error";
2470
- const error = new ConnectionError(this.url, new Error("WebSocket error"));
2471
- this.errorCallbacks.forEach((cb) => cb(error));
2472
- resolve(Err(error));
2473
- };
2474
- this.disposables.add(disposableListener(this.ws, "error", errorHandler));
2475
- const closeHandler = () => {
2476
- this.state = "disconnected";
2477
- this.disconnectionCallbacks.forEach((cb) => cb());
2478
- this.attemptReconnect();
2479
- };
2480
- this.disposables.add(disposableListener(this.ws, "close", closeHandler));
2481
- this.ws.onopen = () => {
2482
- this.state = "connected";
2483
- this.reconnectAttempts = 0;
2484
- if (this.reconnectDisposable) {
2485
- this.reconnectDisposable.dispose();
2486
- this.reconnectDisposable = null;
2487
- }
2488
- this.sendHello();
2489
- this.connectionCallbacks.forEach((cb) => cb());
2490
- resolve(Ok(undefined));
2491
- };
2492
- } catch (e) {
2493
- this.state = "error";
2494
- const error = new ConnectionError(this.url, e);
2495
- resolve(Err(error));
2496
- }
2497
- });
2498
- }
2499
- sendHello() {
2500
- if (!this.ws || this.ws.readyState !== WebSocket.OPEN)
2501
- return;
2502
- const hello = {
2503
- type: "hello",
2504
- sessionId: this.currentSessionId ?? this.sessionOptions?.id,
2505
- props: this.sessionOptions?.props,
2506
- persistKey: this.sessionOptions?.persistKey
2507
- };
2508
- this.ws.send(JSON.stringify(hello));
2509
- }
2510
- disconnect() {
2511
- if (this.reconnectDisposable) {
2512
- this.reconnectDisposable.dispose();
2513
- this.reconnectDisposable = null;
2514
- }
2515
- if (this.ws) {
2516
- if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {
2517
- this.ws.close();
2518
- }
2519
- this.ws = null;
2520
- }
2521
- this.state = "disconnected";
2522
- }
2523
- dispose() {
2524
- this.disconnect();
2525
- if (this.navigationDisposable) {
2526
- this.navigationDisposable.dispose();
2527
- this.navigationDisposable = null;
2528
- }
2529
- this.disposables.dispose();
2530
- }
2531
- setupNavigation() {
2532
- const nav = this.options.navigation;
2533
- if (!nav || typeof window === "undefined")
2534
- return;
2535
- if (this.navigationDisposable)
2536
- return;
2537
- this.navigationDisposable = disposableListener(window, "popstate", () => {
2538
- if (this.handlingPopState)
2539
- return;
2540
- log9.debug("Back navigation detected, dispatching:", nav.backAction);
2541
- this.handlingPopState = true;
2542
- this.dispatchAction(nav.backAction);
2543
- });
2544
- }
2545
- trackViewChange(state2) {
2546
- const nav = this.options.navigation;
2547
- if (!nav || typeof window === "undefined")
2548
- return;
2549
- const viewValue = this.resolveStateKey(state2, nav.viewStateKey);
2550
- if (viewValue === undefined || viewValue === this.lastViewValue)
2551
- return;
2552
- if (this.handlingPopState) {
2553
- this.handlingPopState = false;
2554
- this.lastViewValue = viewValue;
2555
- return;
2556
- }
2557
- if (this.lastViewValue !== null) {
2558
- window.history.pushState({ view: viewValue }, "", "");
2559
- }
2560
- this.lastViewValue = viewValue;
2561
- }
2562
- resolveStateKey(state2, key) {
2563
- if (!state2 || typeof state2 !== "object")
2564
- return;
2565
- const parts = key.split(".");
2566
- let current2 = state2;
2567
- for (const part of parts) {
2568
- if (current2 == null || typeof current2 !== "object")
2569
- return;
2570
- current2 = current2[part];
2571
- }
2572
- return typeof current2 === "string" ? current2 : undefined;
2573
- }
2574
- dispatchAction(action, payload) {
2575
- if (this.state !== "connected" || !this.ws) {
2576
- log9.warn("Cannot dispatch action: not connected");
2577
- return;
2578
- }
2579
- const message = {
2580
- type: "dispatchAction",
2581
- module: this.moduleName,
2582
- action,
2583
- payload
2584
- };
2585
- this.ws.send(JSON.stringify(message));
2586
- }
2587
- subscribeState() {
2588
- if (this.state !== "connected" || !this.ws) {
2589
- log9.warn("Cannot subscribe to state: not connected");
2590
- return;
2591
- }
2592
- const message = { type: "subscribeState" };
2593
- this.ws.send(JSON.stringify(message));
2594
- }
2595
- updateState(state2) {
2596
- if (this.state !== "connected" || !this.ws) {
2597
- log9.warn("Cannot update state: not connected");
2598
- return;
2599
- }
2600
- const message = {
2601
- type: "updateState",
2602
- module: this.moduleName,
2603
- state: state2
2604
- };
2605
- this.ws.send(JSON.stringify(message));
2606
- }
2607
- onPatches(callback) {
2608
- this.patchCallbacks.push(callback);
2609
- return this;
2610
- }
2611
- onStateUpdate(callback) {
2612
- this.stateCallbacks.push(callback);
2613
- return this;
2614
- }
2615
- onConnect(callback) {
2616
- this.connectionCallbacks.push(callback);
2617
- return this;
2618
- }
2619
- onDisconnect(callback) {
2620
- this.disconnectionCallbacks.push(callback);
2621
- return this;
2622
- }
2623
- onError(callback) {
2624
- this.errorCallbacks.push(callback);
2625
- return this;
2626
- }
2627
- onSessionEstablished(callback) {
2628
- this.sessionEstablishedCallbacks.push(callback);
2629
- return this;
2630
- }
2631
- onSessionExpired(callback) {
2632
- this.sessionExpiredCallbacks.push(callback);
2633
- return this;
2634
- }
2635
- getConnectionState() {
2636
- return this.state;
2637
- }
2638
- getCurrentState() {
2639
- return this.currentState;
2640
- }
2641
- getRevision() {
2642
- return this.currentRevision;
2643
- }
2644
- getSessionId() {
2645
- return this.currentSessionId;
2646
- }
2647
- handleMessage(data) {
2648
- try {
2649
- const message = JSON.parse(data);
2650
- switch (message.type) {
2651
- case "sessionAck":
2652
- this.handleSessionAck(message);
2653
- break;
2654
- case "sessionExpired":
2655
- this.handleSessionExpired(message);
2656
- break;
2657
- case "initialTree":
2658
- this.handleInitialTree(message);
2659
- break;
2660
- case "patch":
2661
- this.handlePatch(message);
2662
- break;
2663
- case "stateUpdate":
2664
- this.currentState = message.state;
2665
- this.trackViewChange(this.currentState);
2666
- this.stateCallbacks.forEach((cb) => cb(this.currentState));
2667
- break;
2668
- }
2669
- } catch (e) {
2670
- log9.error("Error handling remote message:", e);
2671
- const error = e instanceof Error ? e : new Error(String(e));
2672
- this.errorCallbacks.forEach((cb) => cb(error));
2673
- }
2674
- }
2675
- handleSessionAck(message) {
2676
- this.currentSessionId = message.sessionId;
2677
- const info = {
2678
- sessionId: message.sessionId,
2679
- isNew: message.isNew,
2680
- isRestored: message.isRestored
2681
- };
2682
- this.sessionEstablishedCallbacks.forEach((cb) => cb(info));
2683
- }
2684
- handleSessionExpired(message) {
2685
- this.currentSessionId = null;
2686
- this.sessionExpiredCallbacks.forEach((cb) => cb(message.reason));
2687
- }
2688
- handleInitialTree(message) {
2689
- this.moduleName = message.module;
2690
- this.currentState = message.state;
2691
- this.currentRevision = message.revision;
2692
- if (message.patches.length > 0) {
2693
- this.patchCallbacks.forEach((cb) => cb(message.patches));
2694
- }
2695
- this.trackViewChange(message.state);
2696
- this.setupNavigation();
2697
- if (this.options.navigation) {
2698
- this.subscribeState();
2699
- }
2700
- this.stateCallbacks.forEach((cb) => cb(message.state));
2701
- }
2702
- handlePatch(message) {
2703
- if (message.revision <= this.currentRevision) {
2704
- log9.warn(`Out of order patch: expected > ${this.currentRevision}, got ${message.revision}`);
2705
- return;
2706
- }
2707
- this.currentRevision = message.revision;
2708
- if (message.patches.length > 0) {
2709
- this.patchCallbacks.forEach((cb) => cb(message.patches));
2710
- }
2711
- }
2712
- attemptReconnect() {
2713
- if (!this.options.autoReconnect) {
2714
- return;
2715
- }
2716
- this.reconnectDisposable = disposableTimeout(() => {
2717
- this.reconnectDisposable = null;
2718
- retry(async () => {
2719
- const result = await this.connect();
2720
- if (!result.ok) {
2721
- throw result.error;
2722
- }
2723
- }, {
2724
- maxAttempts: this.options.maxReconnectAttempts,
2725
- delayMs: this.options.reconnectInterval,
2726
- backoff: "exponential",
2727
- maxDelayMs: 30000,
2728
- jitter: 0.1,
2729
- onRetry: (attempt, error) => {
2730
- log9.debug(`Reconnection attempt ${attempt}/${this.options.maxReconnectAttempts} failed: ${error.message}`);
2731
- }
2732
- }).catch((error) => {
2733
- log9.error("Max reconnection attempts reached:", error.message);
2734
- this.errorCallbacks.forEach((cb) => cb(new ConnectionError(this.url, error, this.options.maxReconnectAttempts)));
2735
- });
2736
- }, this.options.reconnectInterval);
2737
- }
2738
- }
2739
-
2740
- // src/remote/session.ts
2741
- class SessionManager {
2742
- activeSessions = new Map;
2743
- pendingSessions = new Map;
2744
- sessionConnections = new Map;
2745
- config;
2746
- constructor(config2 = {}) {
2747
- this.config = {
2748
- ttl: config2.ttl ?? 3600,
2749
- concurrent: config2.concurrent ?? "kick-old",
2750
- generateId: config2.generateId ?? (() => crypto.randomUUID())
2751
- };
2752
- }
2753
- getTtl() {
2754
- return this.config.ttl;
2755
- }
2756
- getConcurrentPolicy() {
2757
- return this.config.concurrent;
2758
- }
2759
- createSession(props) {
2760
- const now = new Date;
2761
- const session = {
2762
- id: this.config.generateId(),
2763
- ttl: this.config.ttl,
2764
- createdAt: now,
2765
- lastConnectedAt: now,
2766
- props
2767
- };
2768
- this.activeSessions.set(session.id, session);
2769
- return session;
2770
- }
2771
- getActiveSession(id) {
2772
- return this.activeSessions.get(id) ?? null;
2773
- }
2774
- getPendingSession(id) {
2775
- return this.pendingSessions.get(id) ?? null;
2776
- }
2777
- hasSession(id) {
2778
- return this.activeSessions.has(id) || this.pendingSessions.has(id);
2779
- }
2780
- suspendSession(sessionId, savedState, onExpire) {
2781
- const session = this.activeSessions.get(sessionId);
2782
- if (!session)
2783
- return;
2784
- this.activeSessions.delete(sessionId);
2785
- const expiryTimer = setTimeout(async () => {
2786
- const pending = this.pendingSessions.get(sessionId);
2787
- if (pending) {
2788
- this.pendingSessions.delete(sessionId);
2789
- await onExpire(pending.session);
2790
- }
2791
- }, session.ttl * 1000);
2792
- this.pendingSessions.set(sessionId, {
2793
- session,
2794
- savedState,
2795
- expiryTimer
2796
- });
2797
- }
2798
- resumeSession(sessionId) {
2799
- const pending = this.pendingSessions.get(sessionId);
2800
- if (!pending)
2801
- return null;
2802
- clearTimeout(pending.expiryTimer);
2803
- this.pendingSessions.delete(sessionId);
2804
- pending.session.lastConnectedAt = new Date;
2805
- this.activeSessions.set(sessionId, pending.session);
2806
- return {
2807
- session: pending.session,
2808
- savedState: pending.savedState
2809
- };
2810
- }
2811
- destroySession(sessionId) {
2812
- this.activeSessions.delete(sessionId);
2813
- const pending = this.pendingSessions.get(sessionId);
2814
- if (pending) {
2815
- clearTimeout(pending.expiryTimer);
2816
- this.pendingSessions.delete(sessionId);
2817
- }
2818
- this.sessionConnections.delete(sessionId);
2819
- }
2820
- trackConnection(sessionId, ws) {
2821
- let connections = this.sessionConnections.get(sessionId);
2822
- if (!connections) {
2823
- connections = new Set;
2824
- this.sessionConnections.set(sessionId, connections);
2825
- }
2826
- connections.add(ws);
2827
- }
2828
- untrackConnection(sessionId, ws) {
2829
- const connections = this.sessionConnections.get(sessionId);
2830
- if (connections) {
2831
- connections.delete(ws);
2832
- if (connections.size === 0) {
2833
- this.sessionConnections.delete(sessionId);
2834
- }
2835
- }
2836
- }
2837
- getConnections(sessionId) {
2838
- return this.sessionConnections.get(sessionId);
2839
- }
2840
- getConnectionCount(sessionId) {
2841
- return this.sessionConnections.get(sessionId)?.size ?? 0;
2842
- }
2843
- getStats() {
2844
- let totalConnections = 0;
2845
- for (const connections of this.sessionConnections.values()) {
2846
- totalConnections += connections.size;
2847
- }
2848
- return {
2849
- activeSessions: this.activeSessions.size,
2850
- pendingSessions: this.pendingSessions.size,
2851
- totalConnections
2852
- };
2853
- }
2854
- destroy() {
2855
- for (const pending of this.pendingSessions.values()) {
2856
- clearTimeout(pending.expiryTimer);
2857
- }
2858
- this.activeSessions.clear();
2859
- this.pendingSessions.clear();
2860
- this.sessionConnections.clear();
2861
- }
2862
- }
2863
-
2864
- // src/resolver.ts
2865
- class ComponentResolver {
2866
- cache = new Map;
2867
- options;
2868
- moduleRegistry;
2869
- constructor(options = {}) {
2870
- this.options = {
2871
- baseDir: options.baseDir || process.cwd(),
2872
- cache: options.cache ?? true,
2873
- customFetch: options.customFetch || this.defaultFetch.bind(this),
2874
- moduleRegistry: options.moduleRegistry
2875
- };
2876
- this.moduleRegistry = options.moduleRegistry;
2877
- }
2878
- async resolve(importStmt) {
2879
- if (this.moduleRegistry) {
2880
- const names = importStmt.clause.type === "named" ? importStmt.clause.names : [importStmt.clause.name];
2881
- const allFound = names.every((name) => this.moduleRegistry.has(name));
2882
- if (allFound) {
2883
- const result = {};
2884
- for (const name of names) {
2885
- const def = this.moduleRegistry.get(name);
2886
- result[name] = {
2887
- module: def,
2888
- template: def?.template || ""
2889
- };
2890
- }
2891
- return result;
2892
- }
2893
- }
2894
- const sourcePath = this.getSourcePath(importStmt.source);
2895
- if (this.options.cache && this.cache.has(sourcePath)) {
2896
- const cached = this.cache.get(sourcePath);
2897
- return this.extractComponents(importStmt.clause, cached);
2898
- }
2899
- let component;
2900
- if (importStmt.source.type === "local") {
2901
- component = await this.resolveLocal(importStmt.source.path);
2902
- } else {
2903
- component = await this.resolveUrl(importStmt.source.url);
2904
- }
2905
- if (this.options.cache) {
2906
- this.cache.set(sourcePath, component);
2907
- }
2908
- return this.extractComponents(importStmt.clause, component);
2909
- }
2910
- async resolveLocal(path) {
2911
- const { resolve: resolve2, join: join2 } = await Promise.resolve().then(() => (init_path(), exports_path));
2912
- const { readFile } = await import("fs/promises");
2913
- const basePath = resolve2(this.options.baseDir, path);
2914
- const hypenPath = basePath.endsWith(".hypen") ? basePath : `${basePath}.hypen`;
2915
- const template = await readFile(hypenPath, "utf-8");
2916
- const modulePath = hypenPath.replace(/\.hypen$/, ".ts");
2917
- let module = {};
2918
- try {
2919
- module = await import(modulePath);
2920
- } catch {}
2921
- return { module, template };
2922
- }
2923
- async resolveUrl(url) {
2924
- try {
2925
- const response = await this.options.customFetch(url);
2926
- const data = JSON.parse(response);
2927
- if (!data.module || !data.template) {
2928
- throw new Error(`Invalid component format from ${url}. Expected { module, template }`);
2929
- }
2930
- return data;
2931
- } catch (error) {
2932
- throw new Error(`Failed to resolve component from ${url}: ${error instanceof Error ? error.message : String(error)}`);
2933
- }
2934
- }
2935
- async defaultFetch(url) {
2936
- const response = await fetch(url);
2937
- if (!response.ok) {
2938
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
2939
- }
2940
- return response.text();
2941
- }
2942
- extractComponents(clause, component) {
2943
- if (clause.type === "default") {
2944
- return {
2945
- [clause.name]: component
2946
- };
2947
- } else {
2948
- const result = {};
2949
- for (const name of clause.names) {
2950
- result[name] = component;
2951
- }
2952
- return result;
2953
- }
2954
- }
2955
- getSourcePath(source) {
2956
- return source.type === "local" ? source.path : source.url;
2957
- }
2958
- clearCache() {
2959
- this.cache.clear();
2960
- }
2961
- static parseImports(text) {
2962
- const imports = [];
2963
- const importRegex = /import\s+(?:(\{[^}]*\})|(\w+))\s+from\s+["']([^"']+)["']/g;
2964
- let match2;
2965
- while ((match2 = importRegex.exec(text)) !== null) {
2966
- const [, namedImports, defaultImport, source] = match2;
2967
- if (!source)
2968
- continue;
2969
- let clause;
2970
- if (namedImports) {
2971
- const names = namedImports.slice(1, -1).split(",").map((n) => n.trim()).filter((n) => n.length > 0);
2972
- clause = { type: "named", names };
2973
- } else if (defaultImport) {
2974
- clause = { type: "default", name: defaultImport };
2975
- } else {
2976
- continue;
2977
- }
2978
- const sourceObj = source.startsWith("http://") || source.startsWith("https://") ? { type: "url", url: source } : { type: "local", path: source };
2979
- imports.push({ clause, source: sourceObj });
2980
- }
2981
- return imports;
2982
- }
2983
- }
2984
-
2985
- // src/components/builtin.ts
2986
- var log10 = frameworkLoggers.router;
2987
- async function updateRouteVisibility(currentPath, engine, doc) {
2988
- const targetDoc = doc ?? document;
2989
- const routeElements = targetDoc.querySelectorAll('[data-hypen-type="route"]');
2990
- let matchFound = false;
2991
- for (let index2 = 0;index2 < routeElements.length; index2++) {
2992
- const routeEl = routeElements[index2];
2993
- const htmlEl = routeEl;
2994
- const routePath = htmlEl.dataset.routePath || "/";
2995
- const isMatch = routePath === currentPath;
2996
- htmlEl.style.display = isMatch ? "flex" : "none";
2997
- if (isMatch) {
2998
- matchFound = true;
2999
- const componentName = htmlEl.dataset.routeComponent;
3000
- const isLazy = htmlEl.dataset.routeLazy === "true";
3001
- const hasContent = htmlEl.children.length > 0;
3002
- const shouldRender = componentName && engine && (isLazy || !hasContent);
3003
- if (shouldRender) {
3004
- try {
3005
- await engine.renderLazyRoute(routePath, componentName, htmlEl);
3006
- } catch (err) {
3007
- log10.error(`Failed to render route ${routePath}:`, err);
3008
- }
3009
- }
3010
- }
3011
- }
3012
- if (!matchFound) {
3013
- log10.warn(`No route matched path: ${currentPath}. Available routes:`, Array.from(routeElements).map((el) => el.dataset.routePath));
3014
- }
3015
- }
3016
- var Router = app.defineState({
3017
- currentPath: "/",
3018
- matchedRoute: null,
3019
- routeParams: {}
3020
- }, { name: "__Router" }).onCreated((state2, context) => {
3021
- if (!context) {
3022
- log10.error("Requires global context");
3023
- return;
3024
- }
3025
- const router = context.router;
3026
- if (!router) {
3027
- log10.error("Router not found in context");
3028
- return;
3029
- }
3030
- const hypenEngine = context.__hypenEngine;
3031
- setTimeout(() => {
3032
- updateRouteVisibility(state2.currentPath, hypenEngine);
3033
- }, 100);
3034
- router.onNavigate((routeState) => {
3035
- state2.currentPath = routeState.currentPath;
3036
- state2.routeParams = routeState.params;
3037
- updateRouteVisibility(routeState.currentPath, hypenEngine);
3038
- });
3039
- }).build();
3040
- var Route = app.defineState({}, { name: "__Route" }).build();
3041
- var Link = app.defineState({
3042
- to: "/",
3043
- isActive: false
3044
- }, { name: "__Link" }).onAction("navigate", ({ state: state2, context }) => {
3045
- const router = context?.router;
3046
- if (!router) {
3047
- log10.error("Link requires router context");
3048
- return;
3049
- }
3050
- const targetPath = state2.to;
3051
- router.push(targetPath);
3052
- }).onCreated((state2, context) => {
3053
- if (!context)
3054
- return;
3055
- const router = context.router;
3056
- if (router) {
3057
- router.onNavigate((routeState) => {
3058
- state2.isActive = routeState.currentPath === state2.to;
3059
- });
3060
- }
3061
- }).build();
3062
135
  export {
3063
136
  withRetry,
137
+ validatePatches,
3064
138
  usingSync,
3065
139
  using,
3066
140
  unwrapProxy,
@@ -3144,4 +218,4 @@ export {
3144
218
  ActionError
3145
219
  };
3146
220
 
3147
- //# debugId=6ED7F94267EF229064756E2164756E21
221
+ //# debugId=14404B08846A6FEF64756E2164756E21