@hypen-space/core 0.4.980 → 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/dist/context.js
CHANGED
|
@@ -1,366 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
// src/logger.ts
|
|
25
|
-
var LOG_LEVEL_ORDER = {
|
|
26
|
-
debug: 0,
|
|
27
|
-
info: 1,
|
|
28
|
-
warn: 2,
|
|
29
|
-
error: 3,
|
|
30
|
-
none: 4
|
|
31
|
-
};
|
|
32
|
-
var LOG_LEVEL_COLORS = {
|
|
33
|
-
debug: "\x1B[36m",
|
|
34
|
-
info: "\x1B[32m",
|
|
35
|
-
warn: "\x1B[33m",
|
|
36
|
-
error: "\x1B[31m"
|
|
37
|
-
};
|
|
38
|
-
var RESET_COLOR = "\x1B[0m";
|
|
39
|
-
function isProduction() {
|
|
40
|
-
if (typeof process !== "undefined" && process.env) {
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
var config = {
|
|
46
|
-
level: isProduction() ? "error" : "info",
|
|
47
|
-
colors: true,
|
|
48
|
-
timestamps: false
|
|
49
|
-
};
|
|
50
|
-
function setLogLevel(level) {
|
|
51
|
-
config.level = level;
|
|
52
|
-
}
|
|
53
|
-
function getLogLevel() {
|
|
54
|
-
return config.level;
|
|
55
|
-
}
|
|
56
|
-
function configureLogger(options) {
|
|
57
|
-
config = { ...config, ...options };
|
|
58
|
-
}
|
|
59
|
-
function enableLogging() {
|
|
60
|
-
config.level = "debug";
|
|
61
|
-
}
|
|
62
|
-
function disableLogging() {
|
|
63
|
-
config.level = "none";
|
|
64
|
-
}
|
|
65
|
-
function setDebugMode(enabled) {
|
|
66
|
-
config.level = enabled ? "debug" : "error";
|
|
67
|
-
}
|
|
68
|
-
function isDebugMode() {
|
|
69
|
-
return config.level === "debug";
|
|
70
|
-
}
|
|
71
|
-
function shouldLog(level) {
|
|
72
|
-
return LOG_LEVEL_ORDER[level] >= LOG_LEVEL_ORDER[config.level];
|
|
73
|
-
}
|
|
74
|
-
function formatTag(tag, level) {
|
|
75
|
-
const timestamp = config.timestamps ? `${new Date().toISOString()} ` : "";
|
|
76
|
-
if (config.colors && level !== "none") {
|
|
77
|
-
const color = LOG_LEVEL_COLORS[level];
|
|
78
|
-
return `${timestamp}${color}[${tag}]${RESET_COLOR}`;
|
|
79
|
-
}
|
|
80
|
-
return `${timestamp}[${tag}]`;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
class Logger {
|
|
84
|
-
tag;
|
|
85
|
-
constructor(tag) {
|
|
86
|
-
this.tag = tag;
|
|
87
|
-
}
|
|
88
|
-
debug(...args) {
|
|
89
|
-
if (!shouldLog("debug"))
|
|
90
|
-
return;
|
|
91
|
-
if (config.handler) {
|
|
92
|
-
config.handler.debug(this.tag, ...args);
|
|
93
|
-
} else {
|
|
94
|
-
console.log(formatTag(this.tag, "debug"), ...args);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
info(...args) {
|
|
98
|
-
if (!shouldLog("info"))
|
|
99
|
-
return;
|
|
100
|
-
if (config.handler) {
|
|
101
|
-
config.handler.info(this.tag, ...args);
|
|
102
|
-
} else {
|
|
103
|
-
console.info(formatTag(this.tag, "info"), ...args);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
warn(...args) {
|
|
107
|
-
if (!shouldLog("warn"))
|
|
108
|
-
return;
|
|
109
|
-
if (config.handler) {
|
|
110
|
-
config.handler.warn(this.tag, ...args);
|
|
111
|
-
} else {
|
|
112
|
-
console.warn(formatTag(this.tag, "warn"), ...args);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
error(...args) {
|
|
116
|
-
if (!shouldLog("error"))
|
|
117
|
-
return;
|
|
118
|
-
if (config.handler) {
|
|
119
|
-
config.handler.error(this.tag, ...args);
|
|
120
|
-
} else {
|
|
121
|
-
console.error(formatTag(this.tag, "error"), ...args);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
time(label, fn) {
|
|
125
|
-
if (!shouldLog("debug")) {
|
|
126
|
-
return fn();
|
|
127
|
-
}
|
|
128
|
-
const start = performance.now();
|
|
129
|
-
try {
|
|
130
|
-
return fn();
|
|
131
|
-
} finally {
|
|
132
|
-
const duration = performance.now() - start;
|
|
133
|
-
this.debug(`${label}: ${duration.toFixed(2)}ms`);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
async timeAsync(label, fn) {
|
|
137
|
-
if (!shouldLog("debug")) {
|
|
138
|
-
return fn();
|
|
139
|
-
}
|
|
140
|
-
const start = performance.now();
|
|
141
|
-
try {
|
|
142
|
-
return await fn();
|
|
143
|
-
} finally {
|
|
144
|
-
const duration = performance.now() - start;
|
|
145
|
-
this.debug(`${label}: ${duration.toFixed(2)}ms`);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
child(subTag) {
|
|
149
|
-
return new Logger(`${this.tag}:${subTag}`);
|
|
150
|
-
}
|
|
151
|
-
debugIf(condition, ...args) {
|
|
152
|
-
if (condition)
|
|
153
|
-
this.debug(...args);
|
|
154
|
-
}
|
|
155
|
-
warnIf(condition, ...args) {
|
|
156
|
-
if (condition)
|
|
157
|
-
this.warn(...args);
|
|
158
|
-
}
|
|
159
|
-
errorIf(condition, ...args) {
|
|
160
|
-
if (condition)
|
|
161
|
-
this.error(...args);
|
|
162
|
-
}
|
|
163
|
-
loggedOnce = new Set;
|
|
164
|
-
warnOnce(key, ...args) {
|
|
165
|
-
if (this.loggedOnce.has(key))
|
|
166
|
-
return;
|
|
167
|
-
this.loggedOnce.add(key);
|
|
168
|
-
this.warn(...args);
|
|
169
|
-
}
|
|
170
|
-
debugOnce(key, ...args) {
|
|
171
|
-
if (this.loggedOnce.has(key))
|
|
172
|
-
return;
|
|
173
|
-
this.loggedOnce.add(key);
|
|
174
|
-
this.debug(...args);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
function createLogger(tag) {
|
|
178
|
-
return new Logger(tag);
|
|
179
|
-
}
|
|
180
|
-
var logger = createLogger("Hypen");
|
|
181
|
-
var log = {
|
|
182
|
-
debug: (tag, ...args) => {
|
|
183
|
-
if (!shouldLog("debug"))
|
|
184
|
-
return;
|
|
185
|
-
console.log(formatTag(tag, "debug"), ...args);
|
|
186
|
-
},
|
|
187
|
-
info: (tag, ...args) => {
|
|
188
|
-
if (!shouldLog("info"))
|
|
189
|
-
return;
|
|
190
|
-
console.info(formatTag(tag, "info"), ...args);
|
|
191
|
-
},
|
|
192
|
-
warn: (tag, ...args) => {
|
|
193
|
-
if (!shouldLog("warn"))
|
|
194
|
-
return;
|
|
195
|
-
console.warn(formatTag(tag, "warn"), ...args);
|
|
196
|
-
},
|
|
197
|
-
error: (tag, ...args) => {
|
|
198
|
-
if (!shouldLog("error"))
|
|
199
|
-
return;
|
|
200
|
-
console.error(formatTag(tag, "error"), ...args);
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
var frameworkLoggers = {
|
|
204
|
-
hypen: createLogger("Hypen"),
|
|
205
|
-
engine: createLogger("Engine"),
|
|
206
|
-
router: createLogger("Router"),
|
|
207
|
-
state: createLogger("State"),
|
|
208
|
-
events: createLogger("Events"),
|
|
209
|
-
remote: createLogger("Remote"),
|
|
210
|
-
renderer: createLogger("Renderer"),
|
|
211
|
-
module: createLogger("Module"),
|
|
212
|
-
lifecycle: createLogger("Lifecycle"),
|
|
213
|
-
loader: createLogger("Loader"),
|
|
214
|
-
context: createLogger("Context"),
|
|
215
|
-
discovery: createLogger("Discovery"),
|
|
216
|
-
plugin: createLogger("Plugin"),
|
|
217
|
-
canvas: createLogger("Canvas"),
|
|
218
|
-
debug: createLogger("Debug")
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
// src/events.ts
|
|
222
|
-
var log2 = frameworkLoggers.events;
|
|
223
|
-
|
|
224
|
-
class TypedEventEmitter {
|
|
225
|
-
eventBus = new Map;
|
|
226
|
-
emit(event, payload) {
|
|
227
|
-
const handlers = this.eventBus.get(event);
|
|
228
|
-
if (!handlers || handlers.size === 0) {
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
handlers.forEach((handler) => {
|
|
232
|
-
try {
|
|
233
|
-
handler(payload);
|
|
234
|
-
} catch (error) {
|
|
235
|
-
log2.error(`Error in event handler for "${String(event)}":`, error);
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
on(event, handler) {
|
|
240
|
-
if (!this.eventBus.has(event)) {
|
|
241
|
-
this.eventBus.set(event, new Set);
|
|
242
|
-
}
|
|
243
|
-
const handlers = this.eventBus.get(event);
|
|
244
|
-
handlers.add(handler);
|
|
245
|
-
return () => {
|
|
246
|
-
handlers.delete(handler);
|
|
247
|
-
if (handlers.size === 0) {
|
|
248
|
-
this.eventBus.delete(event);
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
once(event, handler) {
|
|
253
|
-
const wrappedHandler = (payload) => {
|
|
254
|
-
handler(payload);
|
|
255
|
-
unsubscribe();
|
|
256
|
-
};
|
|
257
|
-
const unsubscribe = this.on(event, wrappedHandler);
|
|
258
|
-
return unsubscribe;
|
|
259
|
-
}
|
|
260
|
-
off(event, handler) {
|
|
261
|
-
const handlers = this.eventBus.get(event);
|
|
262
|
-
if (handlers) {
|
|
263
|
-
handlers.delete(handler);
|
|
264
|
-
if (handlers.size === 0) {
|
|
265
|
-
this.eventBus.delete(event);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
removeAllListeners(event) {
|
|
270
|
-
this.eventBus.delete(event);
|
|
271
|
-
}
|
|
272
|
-
clearAll() {
|
|
273
|
-
this.eventBus.clear();
|
|
274
|
-
}
|
|
275
|
-
listenerCount(event) {
|
|
276
|
-
return this.eventBus.get(event)?.size ?? 0;
|
|
277
|
-
}
|
|
278
|
-
eventNames() {
|
|
279
|
-
return Array.from(this.eventBus.keys());
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
function createEventEmitter() {
|
|
283
|
-
return new TypedEventEmitter;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// src/context.ts
|
|
287
|
-
var log3 = frameworkLoggers.context;
|
|
288
|
-
|
|
289
|
-
class HypenGlobalContext {
|
|
290
|
-
modules = new Map;
|
|
291
|
-
typedEvents;
|
|
292
|
-
constructor() {
|
|
293
|
-
this.typedEvents = new TypedEventEmitter;
|
|
294
|
-
}
|
|
295
|
-
get events() {
|
|
296
|
-
return this.typedEvents;
|
|
297
|
-
}
|
|
298
|
-
registerModule(id, instance) {
|
|
299
|
-
if (this.modules.has(id)) {
|
|
300
|
-
log3.warn(`Module "${id}" is already registered. Overwriting.`);
|
|
301
|
-
}
|
|
302
|
-
this.modules.set(id, instance);
|
|
303
|
-
log3.debug(`Registered module: ${id}`);
|
|
304
|
-
}
|
|
305
|
-
unregisterModule(id) {
|
|
306
|
-
this.modules.delete(id);
|
|
307
|
-
log3.debug(`Unregistered module: ${id}`);
|
|
308
|
-
}
|
|
309
|
-
getModule(id) {
|
|
310
|
-
const module = this.modules.get(id);
|
|
311
|
-
if (!module) {
|
|
312
|
-
throw new Error(`Module "${id}" not found. Available modules: ${Array.from(this.modules.keys()).join(", ")}`);
|
|
313
|
-
}
|
|
314
|
-
return {
|
|
315
|
-
state: module.getLiveState(),
|
|
316
|
-
setState: (patch) => module.updateState(patch),
|
|
317
|
-
getState: () => module.getState()
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
hasModule(id) {
|
|
321
|
-
return this.modules.has(id);
|
|
322
|
-
}
|
|
323
|
-
getModuleIds() {
|
|
324
|
-
return Array.from(this.modules.keys());
|
|
325
|
-
}
|
|
326
|
-
getGlobalState() {
|
|
327
|
-
const state = {};
|
|
328
|
-
this.modules.forEach((module, id) => {
|
|
329
|
-
state[id] = module.getState();
|
|
330
|
-
});
|
|
331
|
-
return state;
|
|
332
|
-
}
|
|
333
|
-
emit(event, payload) {
|
|
334
|
-
if (this.typedEvents.listenerCount(event) === 0) {
|
|
335
|
-
log3.debug(`Event "${event}" emitted but no listeners`);
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
log3.debug(`Emitting event: ${event}`, payload);
|
|
339
|
-
this.typedEvents.emit(event, payload);
|
|
340
|
-
}
|
|
341
|
-
on(event, handler) {
|
|
342
|
-
log3.debug(`Listening to event: ${event}`);
|
|
343
|
-
return this.typedEvents.on(event, handler);
|
|
344
|
-
}
|
|
345
|
-
off(event, handler) {
|
|
346
|
-
this.typedEvents.off(event, handler);
|
|
347
|
-
}
|
|
348
|
-
clearEvent(event) {
|
|
349
|
-
this.typedEvents.removeAllListeners(event);
|
|
350
|
-
}
|
|
351
|
-
clearAllEvents() {
|
|
352
|
-
this.typedEvents.clearAll();
|
|
353
|
-
}
|
|
354
|
-
debug() {
|
|
355
|
-
return {
|
|
356
|
-
modules: this.getModuleIds(),
|
|
357
|
-
events: this.typedEvents.eventNames(),
|
|
358
|
-
state: this.getGlobalState()
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
HypenGlobalContext
|
|
3
|
+
} from "./chunk-3zvyth50.js";
|
|
4
|
+
import"./chunk-k12cwfst.js";
|
|
5
|
+
import"./chunk-avchpwhf.js";
|
|
6
|
+
import"./chunk-5gtx3pza.js";
|
|
362
7
|
export {
|
|
363
8
|
HypenGlobalContext
|
|
364
9
|
};
|
|
365
10
|
|
|
366
|
-
//# debugId=
|
|
11
|
+
//# debugId=5DAF4163ED0E772564756E2164756E21
|
package/dist/context.js.map
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": [
|
|
3
|
+
"sources": [],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Configurable Debug Logger\n *\n * Provides environment-aware logging that can be disabled in production.\n * Supports log levels, tagged output, and performance timing.\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"none\";\n\nexport interface LoggerConfig {\n /** Minimum log level (default: \"debug\" in dev, \"error\" in prod) */\n level: LogLevel;\n /** Enable colored output (default: true) */\n colors: boolean;\n /** Include timestamps (default: false) */\n timestamps: boolean;\n /** Custom log handler (default: console) */\n handler?: LogHandler;\n}\n\nexport interface LogHandler {\n debug(tag: string, ...args: unknown[]): void;\n info(tag: string, ...args: unknown[]): void;\n warn(tag: string, ...args: unknown[]): void;\n error(tag: string, ...args: unknown[]): void;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst LOG_LEVEL_ORDER: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n none: 4,\n};\n\nconst LOG_LEVEL_COLORS: Record<Exclude<LogLevel, \"none\">, string> = {\n debug: \"\\x1b[36m\", // Cyan\n info: \"\\x1b[32m\", // Green\n warn: \"\\x1b[33m\", // Yellow\n error: \"\\x1b[31m\", // Red\n};\n\nconst RESET_COLOR = \"\\x1b[0m\";\n\n// ============================================================================\n// Global Configuration\n// ============================================================================\n\n/**\n * Detect if running in production environment\n */\nfunction isProduction(): boolean {\n if (typeof process !== \"undefined\" && process.env) {\n return process.env.NODE_ENV === \"production\";\n }\n return false;\n}\n\n/**\n * Default configuration\n */\nlet config: LoggerConfig = {\n level: isProduction() ? \"error\" : \"info\",\n colors: true,\n timestamps: false,\n};\n\n// ============================================================================\n// Configuration API\n// ============================================================================\n\n/**\n * Set the global log level\n */\nexport function setLogLevel(level: LogLevel): void {\n config.level = level;\n}\n\n/**\n * Get the current log level\n */\nexport function getLogLevel(): LogLevel {\n return config.level;\n}\n\n/**\n * Configure the logger\n */\nexport function configureLogger(options: Partial<LoggerConfig>): void {\n config = { ...config, ...options };\n}\n\n/**\n * Enable all logging (sets level to \"debug\")\n */\nexport function enableLogging(): void {\n config.level = \"debug\";\n}\n\n/**\n * Disable all logging (sets level to \"none\")\n */\nexport function disableLogging(): void {\n config.level = \"none\";\n}\n\n/**\n * Enable debug mode - alias for enableLogging()\n * Call this at app startup to see all debug logs\n *\n * @example\n * ```typescript\n * import { setDebugMode } from \"@hypen-space/core\";\n * setDebugMode(true);\n * ```\n */\nexport function setDebugMode(enabled: boolean): void {\n config.level = enabled ? \"debug\" : \"error\";\n}\n\n/**\n * Check if debug mode is enabled\n */\nexport function isDebugMode(): boolean {\n return config.level === \"debug\";\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\nfunction shouldLog(level: LogLevel): boolean {\n return LOG_LEVEL_ORDER[level] >= LOG_LEVEL_ORDER[config.level];\n}\n\nfunction formatTag(tag: string, level: LogLevel): string {\n const timestamp = config.timestamps ? `${new Date().toISOString()} ` : \"\";\n\n if (config.colors && level !== \"none\") {\n const color = LOG_LEVEL_COLORS[level as Exclude<LogLevel, \"none\">];\n return `${timestamp}${color}[${tag}]${RESET_COLOR}`;\n }\n\n return `${timestamp}[${tag}]`;\n}\n\n// ============================================================================\n// Logger Class\n// ============================================================================\n\n/**\n * Tagged logger instance\n *\n * @example\n * ```typescript\n * const log = createLogger(\"MyComponent\");\n * log.debug(\"initialized with\", { props });\n * log.error(\"failed to load\", error);\n * ```\n */\nexport class Logger {\n private readonly tag: string;\n\n constructor(tag: string) {\n this.tag = tag;\n }\n\n debug(...args: unknown[]): void {\n if (!shouldLog(\"debug\")) return;\n\n if (config.handler) {\n config.handler.debug(this.tag, ...args);\n } else {\n console.log(formatTag(this.tag, \"debug\"), ...args);\n }\n }\n\n info(...args: unknown[]): void {\n if (!shouldLog(\"info\")) return;\n\n if (config.handler) {\n config.handler.info(this.tag, ...args);\n } else {\n console.info(formatTag(this.tag, \"info\"), ...args);\n }\n }\n\n warn(...args: unknown[]): void {\n if (!shouldLog(\"warn\")) return;\n\n if (config.handler) {\n config.handler.warn(this.tag, ...args);\n } else {\n console.warn(formatTag(this.tag, \"warn\"), ...args);\n }\n }\n\n error(...args: unknown[]): void {\n if (!shouldLog(\"error\")) return;\n\n if (config.handler) {\n config.handler.error(this.tag, ...args);\n } else {\n console.error(formatTag(this.tag, \"error\"), ...args);\n }\n }\n\n /**\n * Time a function execution\n */\n time<T>(label: string, fn: () => T): T {\n if (!shouldLog(\"debug\")) {\n return fn();\n }\n\n const start = performance.now();\n try {\n return fn();\n } finally {\n const duration = performance.now() - start;\n this.debug(`${label}: ${duration.toFixed(2)}ms`);\n }\n }\n\n /**\n * Time an async function execution\n */\n async timeAsync<T>(label: string, fn: () => Promise<T>): Promise<T> {\n if (!shouldLog(\"debug\")) {\n return fn();\n }\n\n const start = performance.now();\n try {\n return await fn();\n } finally {\n const duration = performance.now() - start;\n this.debug(`${label}: ${duration.toFixed(2)}ms`);\n }\n }\n\n /**\n * Create a child logger with additional context\n */\n child(subTag: string): Logger {\n return new Logger(`${this.tag}:${subTag}`);\n }\n\n /**\n * Conditionally log based on a condition\n */\n debugIf(condition: boolean, ...args: unknown[]): void {\n if (condition) this.debug(...args);\n }\n\n warnIf(condition: boolean, ...args: unknown[]): void {\n if (condition) this.warn(...args);\n }\n\n errorIf(condition: boolean, ...args: unknown[]): void {\n if (condition) this.error(...args);\n }\n\n /**\n * Log once (useful for deprecation warnings)\n */\n private loggedOnce = new Set<string>();\n\n warnOnce(key: string, ...args: unknown[]): void {\n if (this.loggedOnce.has(key)) return;\n this.loggedOnce.add(key);\n this.warn(...args);\n }\n\n debugOnce(key: string, ...args: unknown[]): void {\n if (this.loggedOnce.has(key)) return;\n this.loggedOnce.add(key);\n this.debug(...args);\n }\n}\n\n// ============================================================================\n// Factory Functions\n// ============================================================================\n\n/**\n * Create a tagged logger\n *\n * @example\n * ```typescript\n * const log = createLogger(\"Router\");\n * log.info(\"navigating to\", path);\n * ```\n */\nexport function createLogger(tag: string): Logger {\n return new Logger(tag);\n}\n\n// ============================================================================\n// Default Logger Instance\n// ============================================================================\n\n/**\n * Default logger for general use\n */\nexport const logger = createLogger(\"Hypen\");\n\n// ============================================================================\n// Shorthand Functions (untagged)\n// ============================================================================\n\n/**\n * Shorthand logging functions for quick use\n * Prefer createLogger() for component-specific logging\n */\nexport const log = {\n debug: (tag: string, ...args: unknown[]): void => {\n if (!shouldLog(\"debug\")) return;\n console.log(formatTag(tag, \"debug\"), ...args);\n },\n\n info: (tag: string, ...args: unknown[]): void => {\n if (!shouldLog(\"info\")) return;\n console.info(formatTag(tag, \"info\"), ...args);\n },\n\n warn: (tag: string, ...args: unknown[]): void => {\n if (!shouldLog(\"warn\")) return;\n console.warn(formatTag(tag, \"warn\"), ...args);\n },\n\n error: (tag: string, ...args: unknown[]): void => {\n if (!shouldLog(\"error\")) return;\n console.error(formatTag(tag, \"error\"), ...args);\n },\n};\n\n// ============================================================================\n// Predefined Loggers for Framework Components\n// ============================================================================\n\nexport const frameworkLoggers = {\n hypen: createLogger(\"Hypen\"),\n engine: createLogger(\"Engine\"),\n router: createLogger(\"Router\"),\n state: createLogger(\"State\"),\n events: createLogger(\"Events\"),\n remote: createLogger(\"Remote\"),\n renderer: createLogger(\"Renderer\"),\n module: createLogger(\"Module\"),\n lifecycle: createLogger(\"Lifecycle\"),\n loader: createLogger(\"Loader\"),\n context: createLogger(\"Context\"),\n discovery: createLogger(\"Discovery\"),\n plugin: createLogger(\"Plugin\"),\n canvas: createLogger(\"Canvas\"),\n debug: createLogger(\"Debug\"),\n};\n",
|
|
6
|
-
"/**\n * Type-safe Event System\n *\n * Provides strongly-typed event emission and subscription with autocomplete support.\n */\n\nimport { frameworkLoggers } from \"./logger.js\";\n\nconst log = frameworkLoggers.events;\n\nexport type EventHandler<T = unknown> = (payload: T) => void;\n\n/**\n * Type-safe event emitter with generics\n */\nexport class TypedEventEmitter<TEvents extends Record<string, unknown> = Record<string, unknown>> {\n private eventBus = new Map<keyof TEvents, Set<EventHandler<any>>>();\n\n /**\n * Emit an event with type-safe payload\n */\n emit<K extends keyof TEvents>(event: K, payload: TEvents[K]): void {\n const handlers = this.eventBus.get(event);\n if (!handlers || handlers.size === 0) {\n return;\n }\n\n handlers.forEach((handler) => {\n try {\n handler(payload);\n } catch (error) {\n log.error(`Error in event handler for \"${String(event)}\":`, error);\n }\n });\n }\n\n /**\n * Subscribe to an event with type-safe payload\n * Returns an unsubscribe function\n */\n on<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): () => void {\n if (!this.eventBus.has(event)) {\n this.eventBus.set(event, new Set());\n }\n\n const handlers = this.eventBus.get(event)!;\n handlers.add(handler);\n\n // Return unsubscribe function\n return () => {\n handlers.delete(handler);\n if (handlers.size === 0) {\n this.eventBus.delete(event);\n }\n };\n }\n\n /**\n * Subscribe to an event once (auto-unsubscribe after first emit)\n */\n once<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): () => void {\n const wrappedHandler = (payload: TEvents[K]) => {\n handler(payload);\n unsubscribe();\n };\n\n const unsubscribe = this.on(event, wrappedHandler);\n return unsubscribe;\n }\n\n /**\n * Unsubscribe a specific handler from an event\n */\n off<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): void {\n const handlers = this.eventBus.get(event);\n if (handlers) {\n handlers.delete(handler);\n if (handlers.size === 0) {\n this.eventBus.delete(event);\n }\n }\n }\n\n /**\n * Remove all listeners for a specific event\n */\n removeAllListeners<K extends keyof TEvents>(event: K): void {\n this.eventBus.delete(event);\n }\n\n /**\n * Remove all listeners for all events\n */\n clearAll(): void {\n this.eventBus.clear();\n }\n\n /**\n * Get the number of listeners for an event\n */\n listenerCount<K extends keyof TEvents>(event: K): number {\n return this.eventBus.get(event)?.size ?? 0;\n }\n\n /**\n * Get all registered event names\n */\n eventNames(): Array<keyof TEvents> {\n return Array.from(this.eventBus.keys());\n }\n}\n\n/**\n * Default events for Hypen framework (can be extended by users)\n */\nexport type HypenFrameworkEvents = {\n 'module:created': { moduleId: string };\n 'module:destroyed': { moduleId: string };\n 'route:changed': { from: string | null; to: string };\n 'state:updated': { moduleId: string; paths: string[] };\n 'action:dispatched': { moduleId: string; actionName: string; payload?: unknown };\n 'error': { message: string; error?: Error; context?: string };\n};\n\n/**\n * Create a typed event emitter with custom event map\n */\nexport function createEventEmitter<TEvents extends Record<string, unknown> = HypenFrameworkEvents>(): TypedEventEmitter<TEvents> {\n return new TypedEventEmitter<TEvents>();\n}\n",
|
|
7
|
-
"/**\n * Global Context - Cross-module communication and state access\n */\n\nimport type { HypenModuleInstance } from \"./app.js\";\nimport { getStateSnapshot } from \"./state.js\";\nimport { TypedEventEmitter, type HypenFrameworkEvents } from \"./events.js\";\nimport { frameworkLoggers } from \"./logger.js\";\n\nconst log = frameworkLoggers.context;\n\nexport type ModuleReference<T = unknown> = {\n /**\n * Live proxy state - mutations are tracked and trigger re-renders.\n * Use `getState()` for a snapshot if you only need to read values.\n */\n state: T;\n setState: (patch: Partial<T>) => void;\n /**\n * Returns a deep-cloned snapshot of the current state.\n * Unlike `state`, mutations to the returned object are NOT tracked.\n */\n getState: () => T;\n};\n\nexport type EventHandler = (payload?: unknown) => void;\n\n/**\n * Global Context - Provides access to all modules and cross-module communication\n *\n * @template TEvents - Custom event map (extends HypenFrameworkEvents)\n */\nexport class HypenGlobalContext<TEvents extends Record<string, unknown> = HypenFrameworkEvents> {\n private modules = new Map<string, HypenModuleInstance>();\n private typedEvents: TypedEventEmitter<TEvents & Record<string, unknown>>;\n\n constructor() {\n this.typedEvents = new TypedEventEmitter<TEvents & Record<string, unknown>>();\n }\n\n /**\n * Get the typed event emitter for type-safe event handling\n */\n get events(): TypedEventEmitter<TEvents & Record<string, unknown>> {\n return this.typedEvents;\n }\n\n /**\n * Register a module instance with an ID\n */\n registerModule(id: string, instance: HypenModuleInstance) {\n if (this.modules.has(id)) {\n log.warn(`Module \"${id}\" is already registered. Overwriting.`);\n }\n this.modules.set(id, instance);\n log.debug(`Registered module: ${id}`);\n }\n\n /**\n * Unregister a module\n */\n unregisterModule(id: string) {\n this.modules.delete(id);\n log.debug(`Unregistered module: ${id}`);\n }\n\n /**\n * Get a module by ID with type safety\n */\n getModule<T = unknown>(id: string): ModuleReference<T> {\n const module = this.modules.get(id);\n if (!module) {\n throw new Error(\n `Module \"${id}\" not found. Available modules: ${Array.from(this.modules.keys()).join(\", \")}`\n );\n }\n\n return {\n state: module.getLiveState() as T,\n setState: (patch: Partial<T>) => module.updateState(patch),\n getState: () => module.getState() as T,\n };\n }\n\n /**\n * Check if a module exists\n */\n hasModule(id: string): boolean {\n return this.modules.has(id);\n }\n\n /**\n * Get all registered module IDs\n */\n getModuleIds(): string[] {\n return Array.from(this.modules.keys());\n }\n\n /**\n * Get the entire app state tree (snapshot)\n */\n getGlobalState(): Record<string, unknown> {\n const state: Record<string, unknown> = {};\n this.modules.forEach((module, id) => {\n state[id] = module.getState();\n });\n return state;\n }\n\n /**\n * Emit an event. Delegates to the TypedEventEmitter.\n */\n emit(event: string, payload?: unknown): void {\n if (this.typedEvents.listenerCount(event) === 0) {\n log.debug(`Event \"${event}\" emitted but no listeners`);\n return;\n }\n log.debug(`Emitting event: ${event}`, payload);\n this.typedEvents.emit(event, payload as TEvents[string]);\n }\n\n /**\n * Subscribe to an event. Delegates to the TypedEventEmitter.\n * Returns an unsubscribe function.\n */\n on(event: string, handler: EventHandler): () => void {\n log.debug(`Listening to event: ${event}`);\n return this.typedEvents.on(event, handler);\n }\n\n /**\n * Unsubscribe a specific handler from an event.\n * Delegates to the TypedEventEmitter.\n */\n off(event: string, handler: EventHandler): void {\n this.typedEvents.off(event, handler);\n }\n\n /**\n * Remove all listeners for a specific event.\n * Delegates to the TypedEventEmitter.\n */\n clearEvent(event: string): void {\n this.typedEvents.removeAllListeners(event);\n }\n\n /**\n * Remove all listeners for all events.\n * Delegates to the TypedEventEmitter.\n */\n clearAllEvents(): void {\n this.typedEvents.clearAll();\n }\n\n /**\n * Get debug info about the context\n */\n debug(): {\n modules: string[];\n events: Array<keyof TEvents | string>;\n state: Record<string, unknown>;\n } {\n return {\n modules: this.getModuleIds(),\n events: this.typedEvents.eventNames() as Array<keyof TEvents | string>,\n state: this.getGlobalState(),\n };\n }\n}\n"
|
|
8
5
|
],
|
|
9
|
-
"mappings": "
|
|
10
|
-
"debugId": "
|
|
6
|
+
"mappings": "",
|
|
7
|
+
"debugId": "5DAF4163ED0E772564756E2164756E21",
|
|
11
8
|
"names": []
|
|
12
9
|
}
|
package/dist/datasource.js
CHANGED
|
@@ -1,80 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
// src/datasource.ts
|
|
25
|
-
class DataSourceManager {
|
|
26
|
-
plugins = new Map;
|
|
27
|
-
configs = new Map;
|
|
28
|
-
state = new Map;
|
|
29
|
-
engine;
|
|
30
|
-
constructor(engine) {
|
|
31
|
-
this.engine = engine;
|
|
32
|
-
}
|
|
33
|
-
async use(plugin, config) {
|
|
34
|
-
const { name } = plugin;
|
|
35
|
-
this.state.set(name, {});
|
|
36
|
-
this.plugins.set(name, plugin);
|
|
37
|
-
this.configs.set(name, config);
|
|
38
|
-
await plugin.connect(config, (change) => {
|
|
39
|
-
const current = this.state.get(name) ?? {};
|
|
40
|
-
for (const path of change.paths) {
|
|
41
|
-
if (path in change.values) {
|
|
42
|
-
current[path] = change.values[path];
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
this.state.set(name, current);
|
|
46
|
-
this.engine.setContext(name, current);
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
get(name) {
|
|
50
|
-
return this.plugins.get(name);
|
|
51
|
-
}
|
|
52
|
-
has(name) {
|
|
53
|
-
return this.plugins.has(name);
|
|
54
|
-
}
|
|
55
|
-
getNames() {
|
|
56
|
-
return Array.from(this.plugins.keys());
|
|
57
|
-
}
|
|
58
|
-
getStatus(name) {
|
|
59
|
-
return this.plugins.get(name)?.status;
|
|
60
|
-
}
|
|
61
|
-
async remove(name) {
|
|
62
|
-
const plugin = this.plugins.get(name);
|
|
63
|
-
if (plugin) {
|
|
64
|
-
await plugin.disconnect();
|
|
65
|
-
this.plugins.delete(name);
|
|
66
|
-
this.configs.delete(name);
|
|
67
|
-
this.state.delete(name);
|
|
68
|
-
this.engine.removeContext(name);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
async disconnectAll() {
|
|
72
|
-
const names = Array.from(this.plugins.keys());
|
|
73
|
-
await Promise.all(names.map((name) => this.remove(name)));
|
|
74
|
-
}
|
|
75
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
DataSourceManager
|
|
3
|
+
} from "./chunk-vshdk2pw.js";
|
|
4
|
+
import"./chunk-5gtx3pza.js";
|
|
76
5
|
export {
|
|
77
6
|
DataSourceManager
|
|
78
7
|
};
|
|
79
8
|
|
|
80
|
-
//# debugId=
|
|
9
|
+
//# debugId=75477AE7A7B3A5BA64756E2164756E21
|
package/dist/datasource.js.map
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": [
|
|
3
|
+
"sources": [],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Data Source Plugin System for Hypen\n *\n * Enables live subscription databases (SpacetimeDB, Firebase, Convex, Electric SQL)\n * to push data into the Hypen reactive engine via a unified plugin interface.\n *\n * UI bindings use the `@provider.path` syntax:\n * - `@spacetime.messages` → SpacetimeDB messages table\n * - `@firebase.user.profile` → Firebase user profile\n * - `@convex.tasks` → Convex tasks table\n *\n * @module\n */\n\n// ---------------------------------------------------------------------------\n// Core Types\n// ---------------------------------------------------------------------------\n\n/** Connection status for a data source provider */\nexport type DataSourceStatus =\n | \"disconnected\"\n | \"connecting\"\n | \"connected\"\n | \"reconnecting\"\n | \"error\";\n\n/** Describes a subscription to a table or query */\nexport interface DataSourceQuery {\n /** Table or collection name (e.g., \"messages\", \"users\") */\n table: string;\n /** Optional filter criteria */\n filter?: Record<string, unknown>;\n /** Optional raw query string (e.g., SQL for SpacetimeDB) */\n sql?: string;\n}\n\n/** Handle returned by subscribe() — call unsubscribe() to stop receiving updates */\nexport interface DataSourceSubscription {\n /** Stop receiving updates for this subscription */\n unsubscribe(): void;\n /** Current subscription status */\n status: \"pending\" | \"applied\" | \"error\";\n /** Error details if status is \"error\" */\n error?: Error;\n}\n\n/** Describes a batch of changes pushed by a plugin */\nexport interface DataSourceChange {\n /** Changed paths relative to the provider root (e.g., [\"messages\", \"users\"]) */\n paths: string[];\n /** New values at those paths */\n values: Record<string, unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Plugin Interface\n// ---------------------------------------------------------------------------\n\n/**\n * Interface that all data source plugins must implement.\n *\n * A plugin manages the connection lifecycle and translates database-specific\n * events (row inserts, updates, deletes) into `DataSourceChange` objects that\n * the Hypen engine can consume.\n *\n * @typeParam TConfig - Plugin-specific configuration type\n *\n * @example\n * ```typescript\n * class SpacetimeDBPlugin implements DataSourcePlugin<SpacetimeDBConfig> {\n * readonly name = \"spacetime\";\n * status: DataSourceStatus = \"disconnected\";\n *\n * async connect(config: SpacetimeDBConfig, onChange: (change: DataSourceChange) => void) {\n * // Connect to SpacetimeDB, subscribe to tables, push changes via onChange\n * }\n * // ...\n * }\n * ```\n */\nexport interface DataSourcePlugin<TConfig = unknown> {\n /** Unique provider name (e.g., \"spacetime\", \"firebase\", \"convex\") */\n readonly name: string;\n\n /** Current connection status */\n status: DataSourceStatus;\n\n /**\n * Connect to the data source and begin pushing changes.\n *\n * @param config - Plugin-specific configuration\n * @param onChange - Callback to push data changes into the engine.\n * The plugin MUST call this whenever subscribed data changes.\n */\n connect(config: TConfig, onChange: (change: DataSourceChange) => void): Promise<void>;\n\n /**\n * Subscribe to a specific table or query.\n * Returns a handle to unsubscribe later.\n */\n subscribe(query: DataSourceQuery): DataSourceSubscription;\n\n /**\n * Call a remote procedure / reducer / mutation.\n *\n * @param method - Method name (e.g., \"sendMessage\" for SpacetimeDB reducer)\n * @param args - Arguments to pass\n * @returns The result from the remote call\n */\n call(method: string, ...args: unknown[]): Promise<unknown>;\n\n /**\n * Disconnect from the data source and clean up all subscriptions.\n */\n disconnect(): Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Data Source Manager\n// ---------------------------------------------------------------------------\n\n/** Interface for the engine's data source operations (maps to WASM setContext/removeContext) */\nexport interface IDataSourceEngine {\n /**\n * Set (or replace) a named data source context.\n * Registers the provider, stores the data, and re-renders bound nodes.\n * Sparse merging should happen at the SDK layer before calling this.\n */\n setContext(name: string, data: Record<string, unknown>): void;\n /**\n * Remove a data source context entirely.\n * Drops the provider's state and re-renders bound nodes (they resolve to null).\n */\n removeContext(name: string): void;\n}\n\n/**\n * Manages data source plugin lifecycles and bridges them to the Hypen engine.\n *\n * The manager:\n * 1. Registers plugins with the engine (creates state slots)\n * 2. Connects plugins and wires their onChange callbacks to engine updates\n * 3. Manages subscription lifecycles\n * 4. Handles cleanup on disconnect\n *\n * @example\n * ```typescript\n * const manager = new DataSourceManager(engine);\n *\n * // Register and connect a SpacetimeDB plugin\n * await manager.use(new SpacetimeDBPlugin(), {\n * uri: \"ws://localhost:3000\",\n * moduleName: \"chat\",\n * tables: [\"user\", \"message\"],\n * });\n *\n * // Access plugin for mutations\n * await manager.get(\"spacetime\").call(\"sendMessage\", \"Hello!\");\n *\n * // Clean up\n * await manager.disconnectAll();\n * ```\n */\nexport class DataSourceManager {\n private plugins = new Map<string, DataSourcePlugin>();\n private configs = new Map<string, unknown>();\n /** Accumulated state per provider — sparse merging happens here before setContext */\n private state = new Map<string, Record<string, unknown>>();\n private engine: IDataSourceEngine;\n\n constructor(engine: IDataSourceEngine) {\n this.engine = engine;\n }\n\n /**\n * Register, connect, and start a data source plugin.\n *\n * @param plugin - The plugin instance\n * @param config - Plugin-specific configuration\n */\n async use<C>(plugin: DataSourcePlugin<C>, config: C): Promise<void> {\n const { name } = plugin;\n\n // Initialize state slot\n this.state.set(name, {});\n\n // Store references\n this.plugins.set(name, plugin as DataSourcePlugin);\n this.configs.set(name, config);\n\n // Connect the plugin with an onChange callback that merges sparse data\n // and pushes the full state via setContext\n await plugin.connect(config, (change: DataSourceChange) => {\n // Merge changed paths into the accumulated state\n const current = this.state.get(name) ?? {};\n for (const path of change.paths) {\n if (path in change.values) {\n current[path] = change.values[path];\n }\n }\n this.state.set(name, current);\n\n // Push the full merged state to the engine\n this.engine.setContext(name, current);\n });\n }\n\n /**\n * Get a registered plugin by name.\n * Useful for calling mutations: `manager.get(\"spacetime\").call(\"sendMessage\", text)`\n */\n get<T extends DataSourcePlugin = DataSourcePlugin>(name: string): T | undefined {\n return this.plugins.get(name) as T | undefined;\n }\n\n /** Check if a plugin is registered */\n has(name: string): boolean {\n return this.plugins.has(name);\n }\n\n /** Get all registered provider names */\n getNames(): string[] {\n return Array.from(this.plugins.keys());\n }\n\n /** Get the status of a specific plugin */\n getStatus(name: string): DataSourceStatus | undefined {\n return this.plugins.get(name)?.status;\n }\n\n /**\n * Disconnect and remove a specific plugin.\n */\n async remove(name: string): Promise<void> {\n const plugin = this.plugins.get(name);\n if (plugin) {\n await plugin.disconnect();\n this.plugins.delete(name);\n this.configs.delete(name);\n this.state.delete(name);\n this.engine.removeContext(name);\n }\n }\n\n /**\n * Disconnect all plugins and clean up.\n */\n async disconnectAll(): Promise<void> {\n const names = Array.from(this.plugins.keys());\n await Promise.all(names.map((name) => this.remove(name)));\n }\n}\n"
|
|
6
5
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
6
|
+
"mappings": "",
|
|
7
|
+
"debugId": "75477AE7A7B3A5BA64756E2164756E21",
|
|
9
8
|
"names": []
|
|
10
9
|
}
|