@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.
- package/README.md +5 -8
- package/dist/app.js +13 -1168
- package/dist/app.js.map +3 -9
- package/dist/chunk-00zt3w6e.js +58 -0
- package/dist/chunk-00zt3w6e.js.map +10 -0
- package/dist/chunk-3zvyth50.js +87 -0
- package/dist/chunk-3zvyth50.js.map +10 -0
- package/dist/chunk-5gtx3pza.js +11 -0
- package/dist/chunk-5gtx3pza.js.map +9 -0
- package/dist/chunk-7222131a.js +191 -0
- package/dist/chunk-7222131a.js.map +10 -0
- package/dist/chunk-avchpwhf.js +200 -0
- package/dist/chunk-avchpwhf.js.map +10 -0
- package/dist/chunk-ec0tgy9a.js +154 -0
- package/dist/chunk-ec0tgy9a.js.map +10 -0
- package/dist/chunk-fnss4dm2.js +479 -0
- package/dist/chunk-fnss4dm2.js.map +10 -0
- package/dist/chunk-g2gz9pgg.js +133 -0
- package/dist/chunk-g2gz9pgg.js.map +10 -0
- package/dist/chunk-g72v6mmf.js +341 -0
- package/dist/chunk-g72v6mmf.js.map +10 -0
- package/dist/chunk-g7g3jxty.js +351 -0
- package/dist/chunk-g7g3jxty.js.map +10 -0
- package/dist/chunk-g830re2c.js +50 -0
- package/dist/chunk-g830re2c.js.map +10 -0
- package/dist/chunk-gtwh1sg7.js +127 -0
- package/dist/chunk-gtwh1sg7.js.map +10 -0
- package/dist/chunk-k12cwfst.js +72 -0
- package/dist/chunk-k12cwfst.js.map +10 -0
- package/dist/chunk-mbqqsz6r.js +128 -0
- package/dist/chunk-mbqqsz6r.js.map +10 -0
- package/dist/chunk-ne632swm.js +209 -0
- package/dist/chunk-ne632swm.js.map +10 -0
- package/dist/chunk-p3pj1bax.js +206 -0
- package/dist/chunk-p3pj1bax.js.map +10 -0
- package/dist/chunk-vshdk2pw.js +56 -0
- package/dist/chunk-vshdk2pw.js.map +10 -0
- package/dist/chunk-wp2ebn2m.js +51 -0
- package/dist/chunk-wp2ebn2m.js.map +10 -0
- package/dist/chunk-x4qv4jm9.js +88 -0
- package/dist/chunk-x4qv4jm9.js.map +10 -0
- package/dist/chunk-ycxp4drd.js +211 -0
- package/dist/chunk-ycxp4drd.js.map +10 -0
- package/dist/components/builtin.js +14 -1246
- package/dist/components/builtin.js.map +3 -10
- package/dist/context.js +7 -362
- package/dist/context.js.map +3 -6
- package/dist/datasource.js +5 -76
- package/dist/datasource.js.map +3 -4
- package/dist/disposable.js +20 -367
- package/dist/disposable.js.map +3 -5
- package/dist/engine-base.d.ts +38 -2
- package/dist/engine-base.js +45 -412
- package/dist/engine-base.js.map +4 -6
- package/dist/events.js +7 -285
- package/dist/events.js.map +3 -5
- package/dist/hypen.js +8 -71
- package/dist/hypen.js.map +3 -4
- package/dist/index.browser.js +58 -2152
- package/dist/index.browser.js.map +3 -16
- package/dist/index.d.ts +2 -0
- package/dist/index.js +132 -3058
- package/dist/index.js.map +4 -22
- package/dist/logger.js +16 -220
- package/dist/logger.js.map +3 -4
- package/dist/managed-router.js +12 -1367
- package/dist/managed-router.js.map +3 -10
- package/dist/portable.js +6 -70
- package/dist/portable.js.map +3 -4
- package/dist/remote/client.js +9 -1010
- package/dist/remote/client.js.map +3 -8
- package/dist/remote/index.d.ts +2 -0
- package/dist/remote/index.js +511 -1066
- package/dist/remote/index.js.map +4 -9
- package/dist/remote/remote-session.d.ts +245 -0
- package/dist/remote/session.js +5 -147
- package/dist/remote/session.js.map +3 -4
- package/dist/renderer.js +7 -271
- package/dist/renderer.js.map +3 -5
- package/dist/resolver.js +5 -484
- package/dist/resolver.js.map +3 -5
- package/dist/result.js +25 -211
- package/dist/result.js.map +3 -4
- package/dist/retry.js +10 -336
- package/dist/retry.js.map +3 -5
- package/dist/router.js +9 -807
- package/dist/router.js.map +3 -8
- package/dist/state.js +10 -274
- package/dist/state.js.map +3 -5
- package/dist/validate.d.ts +19 -0
- package/package.json +13 -1
- package/src/engine-base.ts +87 -4
- package/src/index.ts +5 -0
- package/src/remote/index.ts +16 -0
- package/src/remote/remote-session.ts +998 -0
- package/src/validate.ts +37 -0
package/src/engine-base.ts
CHANGED
|
@@ -46,6 +46,35 @@ import type {
|
|
|
46
46
|
|
|
47
47
|
const log = frameworkLoggers.engine;
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Recursively convert wasm-bindgen `Map` values into plain objects.
|
|
51
|
+
*
|
|
52
|
+
* The web-target WASM returns action payloads (and nested values) as `Map`
|
|
53
|
+
* instances; user handlers expect plain objects. Only plain objects
|
|
54
|
+
* (`constructor === Object`), arrays, and Maps are descended into — class
|
|
55
|
+
* instances, `Date`, etc. are passed through untouched.
|
|
56
|
+
*/
|
|
57
|
+
function mapToPlainObject(value: any): any {
|
|
58
|
+
if (value instanceof Map) {
|
|
59
|
+
const obj: Record<string, any> = {};
|
|
60
|
+
for (const [key, val] of value.entries()) {
|
|
61
|
+
obj[key] = mapToPlainObject(val);
|
|
62
|
+
}
|
|
63
|
+
return obj;
|
|
64
|
+
}
|
|
65
|
+
if (Array.isArray(value)) {
|
|
66
|
+
return value.map(mapToPlainObject);
|
|
67
|
+
}
|
|
68
|
+
if (value && typeof value === "object" && value.constructor === Object) {
|
|
69
|
+
const obj: Record<string, any> = {};
|
|
70
|
+
for (const [key, val] of Object.entries(value)) {
|
|
71
|
+
obj[key] = mapToPlainObject(val);
|
|
72
|
+
}
|
|
73
|
+
return obj;
|
|
74
|
+
}
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
|
|
49
78
|
/**
|
|
50
79
|
* Shared base wrapping a wasm-bindgen `WasmEngine`. `any` here is load-
|
|
51
80
|
* bearing: the concrete type is `WasmEngine` from either the `wasm-node`
|
|
@@ -57,6 +86,16 @@ export abstract class BaseEngine {
|
|
|
57
86
|
protected wasmEngine: any = null;
|
|
58
87
|
protected initialized = false;
|
|
59
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Component names the resolver was asked for and returned `null` on — i.e.
|
|
91
|
+
* names that are neither a registered primitive (the engine checks those
|
|
92
|
+
* first and never consults the resolver for them) nor resolvable to a
|
|
93
|
+
* template. Each such name produces an opaque `Create` patch the renderer
|
|
94
|
+
* drops. Tracked so a miss is warned about once and can be asserted on in
|
|
95
|
+
* tests. See `getUnresolvedComponents`.
|
|
96
|
+
*/
|
|
97
|
+
private unresolvedComponents = new Set<string>();
|
|
98
|
+
|
|
60
99
|
/**
|
|
61
100
|
* Initialize the WASM module. Platform-specific.
|
|
62
101
|
*
|
|
@@ -98,16 +137,47 @@ export abstract class BaseEngine {
|
|
|
98
137
|
|
|
99
138
|
/**
|
|
100
139
|
* Set the component resolver for dynamic component composition.
|
|
140
|
+
*
|
|
141
|
+
* The resolver is wrapped to detect "resolver misses": the engine only
|
|
142
|
+
* consults the resolver for element types that are NOT registered
|
|
143
|
+
* primitives, so a `null` return means the name resolves to nothing and
|
|
144
|
+
* the engine will emit an opaque `Create` the renderer silently drops
|
|
145
|
+
* (e.g. an anonymous component that never got registered). The first miss
|
|
146
|
+
* for each unique name is logged with actionable guidance; every miss is
|
|
147
|
+
* recorded for `getUnresolvedComponents()` / test assertions.
|
|
101
148
|
*/
|
|
102
149
|
setComponentResolver(resolver: ComponentResolver): void {
|
|
103
150
|
const engine = this.ensureInitialized();
|
|
104
151
|
engine.setComponentResolver(
|
|
105
152
|
(componentName: string, contextPath: string | null) => {
|
|
106
|
-
|
|
153
|
+
const resolved = resolver(componentName, contextPath);
|
|
154
|
+
if (resolved == null) {
|
|
155
|
+
if (!this.unresolvedComponents.has(componentName)) {
|
|
156
|
+
this.unresolvedComponents.add(componentName);
|
|
157
|
+
log.warn(
|
|
158
|
+
`Component "${componentName}" did not resolve: it is not a ` +
|
|
159
|
+
`registered primitive and the component resolver returned null. ` +
|
|
160
|
+
`The engine will emit an opaque Create for it and the renderer ` +
|
|
161
|
+
`will drop it. Did you forget to register/.module(...) the ` +
|
|
162
|
+
`component, or is its name misspelled in the template?`,
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return resolved;
|
|
107
167
|
},
|
|
108
168
|
);
|
|
109
169
|
}
|
|
110
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Names the component resolver has been asked for and failed to resolve
|
|
173
|
+
* this session (see `setComponentResolver`). Useful as a CI / smoke-test
|
|
174
|
+
* assertion — an empty array means every referenced component resolved to
|
|
175
|
+
* a primitive or a template.
|
|
176
|
+
*/
|
|
177
|
+
getUnresolvedComponents(): string[] {
|
|
178
|
+
return [...this.unresolvedComponents];
|
|
179
|
+
}
|
|
180
|
+
|
|
111
181
|
/**
|
|
112
182
|
* Parse and render Hypen DSL source code.
|
|
113
183
|
* @throws {ParseError} if the source fails to parse
|
|
@@ -220,11 +290,24 @@ export abstract class BaseEngine {
|
|
|
220
290
|
|
|
221
291
|
/**
|
|
222
292
|
* Platform hook: normalize an incoming action before the user handler
|
|
223
|
-
* sees it.
|
|
224
|
-
*
|
|
293
|
+
* sees it.
|
|
294
|
+
*
|
|
295
|
+
* The default converts any `Map` instances in the payload into plain
|
|
296
|
+
* objects (deeply). This is the landmine the wasm-bindgen **web** target
|
|
297
|
+
* sets: it returns structured action payloads as JS `Map`s, so a handler
|
|
298
|
+
* reading `payload.to` gets `undefined` and `@router.push, to: "/x"`
|
|
299
|
+
* silently no-ops. Every consumer of the web-target WASM — the browser
|
|
300
|
+
* engine, a Cloudflare `CFEngine`, any future runtime — inherits the fix
|
|
301
|
+
* here instead of rediscovering it.
|
|
302
|
+
*
|
|
303
|
+
* The wasm-bindgen **bundler** (node) target already returns plain
|
|
304
|
+
* objects, so for it this is a harmless deep walk. Subclasses on that
|
|
305
|
+
* target may override with an identity to skip the walk (see
|
|
306
|
+
* `@hypen-space/server`).
|
|
225
307
|
*/
|
|
226
308
|
protected normalizeAction(action: Action): Action {
|
|
227
|
-
return action;
|
|
309
|
+
if (!action.payload) return action;
|
|
310
|
+
return { ...action, payload: mapToPlainObject(action.payload) };
|
|
228
311
|
}
|
|
229
312
|
|
|
230
313
|
/**
|
package/src/index.ts
CHANGED
|
@@ -326,3 +326,8 @@ export {
|
|
|
326
326
|
isDebugMode,
|
|
327
327
|
} from "./logger.js";
|
|
328
328
|
export type { LogLevel, LoggerConfig, LogHandler } from "./logger.js";
|
|
329
|
+
|
|
330
|
+
// Patch-stream validation — catch silent resolver misses (opaque component
|
|
331
|
+
// elementTypes) in CI / smoke tests off the wire.
|
|
332
|
+
export { validatePatches } from "./validate.js";
|
|
333
|
+
export type { PatchValidationResult } from "./validate.js";
|
package/src/remote/index.ts
CHANGED
|
@@ -44,3 +44,19 @@ export type {
|
|
|
44
44
|
|
|
45
45
|
// Re-export Patch type
|
|
46
46
|
export type { Patch } from "../types.js";
|
|
47
|
+
|
|
48
|
+
// Transport-agnostic remote session. The engine is injected via
|
|
49
|
+
// `SessionHost.createEngine`, so any runtime (Node/Bun, Cloudflare Durable
|
|
50
|
+
// Objects, etc.) can reuse the Hypen remote protocol envelope.
|
|
51
|
+
// `@hypen-space/server` re-exports these for back-compat.
|
|
52
|
+
export {
|
|
53
|
+
RemoteSession,
|
|
54
|
+
AsyncQueueTransport,
|
|
55
|
+
createBunWebSocketTransport,
|
|
56
|
+
} from "./remote-session.js";
|
|
57
|
+
export type {
|
|
58
|
+
SessionTransport,
|
|
59
|
+
SessionHost,
|
|
60
|
+
RemoteSessionOptions,
|
|
61
|
+
OutgoingMessage,
|
|
62
|
+
} from "./remote-session.js";
|