@ekrooh/bare 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -195
- package/dist/{index-DjulYFJL.d.mts → index-BkwUzwVt.d.mts} +94 -20
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +1 -512
- package/dist/messages-BbpF3wNH.mjs +849 -0
- package/dist/{plugins-1KweEBct.mjs → plugins-DZu_NWVp.mjs} +46 -18
- package/dist/plugins-discovery-events.d.mts +5 -8
- package/dist/plugins-discovery-events.mjs +2 -3
- package/dist/plugins-health-events.d.mts +4 -7
- package/dist/plugins-health-events.mjs +2 -3
- package/dist/plugins-logs-events.d.mts +34 -0
- package/dist/plugins-logs-events.mjs +25 -0
- package/dist/plugins-media-events.d.mts +6 -11
- package/dist/plugins-media-events.mjs +2 -3
- package/dist/plugins-permissions-events.d.mts +7 -10
- package/dist/plugins-permissions-events.mjs +2 -3
- package/dist/plugins.d.mts +9 -11
- package/dist/plugins.mjs +1 -2
- package/dist/runtime.d.mts +42 -22
- package/dist/runtime.mjs +853 -138
- package/dist/{static-file-server-DY9EKEVf.d.mts → static-file-server-C8pIX1JD.d.mts} +44 -17
- package/dist/store-DTg1jN5E.mjs +49 -0
- package/dist/transports.d.mts +14 -11
- package/dist/transports.mjs +170 -82
- package/package.json +12 -7
package/dist/index.mjs
CHANGED
|
@@ -1,512 +1 @@
|
|
|
1
|
-
|
|
2
|
-
//#region core/messages/constants.ts
|
|
3
|
-
const VERSION = 1;
|
|
4
|
-
const MessageType = { ENVELOPE: 1 };
|
|
5
|
-
/** Canonical error codes. Everything the framework throws uses these; peers
|
|
6
|
-
* may carry arbitrary codes over the wire, and consumers may return app-scoped
|
|
7
|
-
* codes (e.g. `app.photos/not-found`) which are preserved verbatim. Keep
|
|
8
|
-
* `android/src/main/.../ErrorCodes.kt` in sync with the canonical union. */
|
|
9
|
-
const ErrorCode = {
|
|
10
|
-
UNSUPPORTED_CAPABILITY: "UNSUPPORTED_CAPABILITY",
|
|
11
|
-
UNSUPPORTED_EVENT: "UNSUPPORTED_EVENT",
|
|
12
|
-
HOST_ERROR: "HOST_ERROR",
|
|
13
|
-
TRANSPORT_ERROR: "TRANSPORT_ERROR",
|
|
14
|
-
PLUGIN_ERROR: "PLUGIN_ERROR",
|
|
15
|
-
INVALID_RESPONSE: "INVALID_RESPONSE",
|
|
16
|
-
FRAME_TOO_LARGE: "FRAME_TOO_LARGE",
|
|
17
|
-
FRAME_INVALID: "FRAME_INVALID",
|
|
18
|
-
TIMEOUT: "TIMEOUT"
|
|
19
|
-
};
|
|
20
|
-
/** A JSON header must fit a 16-bit big-endian length field. */
|
|
21
|
-
const MAX_HEADER_BYTES = 65535;
|
|
22
|
-
/** Upper bound on one encoded frame. Large binary transfers are a plugin-level
|
|
23
|
-
* concern (out-of-band handles), not an in-band payload. */
|
|
24
|
-
const MAX_FRAME_BYTES = 16777216;
|
|
25
|
-
//#endregion
|
|
26
|
-
//#region core/messages/types.ts
|
|
27
|
-
var CoreError = class extends Error {
|
|
28
|
-
code;
|
|
29
|
-
constructor(code, message) {
|
|
30
|
-
super(message);
|
|
31
|
-
this.name = "CoreError";
|
|
32
|
-
this.code = code;
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
//#endregion
|
|
36
|
-
//#region core/messages/errors.ts
|
|
37
|
-
/** Success half of an `Either` tuple. */
|
|
38
|
-
function ok(result) {
|
|
39
|
-
return [null, result];
|
|
40
|
-
}
|
|
41
|
-
/** Failure half of an `Either` tuple. Accepts a canonical error code or any
|
|
42
|
-
* app-scoped code (`app.photos/not-found`) — the code is preserved verbatim. */
|
|
43
|
-
function err(code, message) {
|
|
44
|
-
return [new CoreError(code, message), null];
|
|
45
|
-
}
|
|
46
|
-
/** Convenience for constructing a `CoreError` from a possibly-non-canonical
|
|
47
|
-
* wire code: preserves known codes, maps anything else to `PLUGIN_ERROR`.
|
|
48
|
-
* Framework callers that want app codes preserved construct the error
|
|
49
|
-
* directly instead. */
|
|
50
|
-
function coerceErrorCode(code) {
|
|
51
|
-
if (code && code in ErrorCode) return code;
|
|
52
|
-
return ErrorCode.PLUGIN_ERROR;
|
|
53
|
-
}
|
|
54
|
-
//#endregion
|
|
55
|
-
//#region core/messages/plugin-kernel.ts
|
|
56
|
-
function createPluginRegistry() {
|
|
57
|
-
const plugins = /* @__PURE__ */ new Map();
|
|
58
|
-
return {
|
|
59
|
-
register(plugin) {
|
|
60
|
-
if (!plugin.id.includes(".")) throw new Error(`plugin id must be namespaced (example: "vendor.plugin"), got "${plugin.id}"`);
|
|
61
|
-
if (plugins.has(plugin.id)) throw new Error(`plugin id "${plugin.id}" is already registered`);
|
|
62
|
-
plugins.set(plugin.id, plugin);
|
|
63
|
-
},
|
|
64
|
-
resolve(pluginId, runtime) {
|
|
65
|
-
return plugins.get(pluginId)?.runtimes[runtime];
|
|
66
|
-
},
|
|
67
|
-
get(pluginId) {
|
|
68
|
-
return plugins.get(pluginId);
|
|
69
|
-
},
|
|
70
|
-
listCapabilities(runtime) {
|
|
71
|
-
const rows = [];
|
|
72
|
-
for (const plugin of plugins.values()) {
|
|
73
|
-
const runtimes = Object.keys(plugin.runtimes);
|
|
74
|
-
if (runtime && !runtimes.includes(runtime)) continue;
|
|
75
|
-
rows.push({
|
|
76
|
-
pluginId: plugin.id,
|
|
77
|
-
capabilities: plugin.capabilities ?? [],
|
|
78
|
-
events: plugin.events ?? [],
|
|
79
|
-
runtimes
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
return rows;
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
/** Whether the router may synthesize an UNSUPPORTED_EVENT response. Events are
|
|
87
|
-
* only gated when the manifest declares them; undeclared plugins opt out of
|
|
88
|
-
* validation for backward compatibility. */
|
|
89
|
-
function declaresEvent(plugin, event) {
|
|
90
|
-
return plugin?.events ? plugin.events.includes(event) : true;
|
|
91
|
-
}
|
|
92
|
-
function createPluginRouter(registry, runtime, options) {
|
|
93
|
-
const logger = options?.logger ?? console;
|
|
94
|
-
return { async route(header, payload) {
|
|
95
|
-
const plugin = isPluginEnvelopeHeader(header) ? registry.get(header.pluginId) : void 0;
|
|
96
|
-
if (isPluginEnvelopeHeader(header)) {
|
|
97
|
-
if (!declaresEvent(plugin, header.event)) {
|
|
98
|
-
const error = new CoreError(ErrorCode.UNSUPPORTED_EVENT, `Unsupported event ${header.pluginId}.${header.event} on ${runtime}`);
|
|
99
|
-
if (isPluginDispatchHeader(header)) logger.warn(error.message);
|
|
100
|
-
return invokeErrorResponse(header, error);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
if (isPluginDispatchHeader(header)) {
|
|
104
|
-
const runtimeAdapter = registry.resolve(header.pluginId, runtime);
|
|
105
|
-
if (!runtimeAdapter?.dispatch) {
|
|
106
|
-
const error = new CoreError(ErrorCode.UNSUPPORTED_CAPABILITY, `Unsupported capability ${header.pluginId}.${header.event} on ${runtime}`);
|
|
107
|
-
logger.warn(error.message);
|
|
108
|
-
return invokeErrorResponse(header, error);
|
|
109
|
-
}
|
|
110
|
-
try {
|
|
111
|
-
await runtimeAdapter.dispatch(header.event, header.args, {
|
|
112
|
-
runtime,
|
|
113
|
-
payload
|
|
114
|
-
});
|
|
115
|
-
return null;
|
|
116
|
-
} catch (e) {
|
|
117
|
-
const error = new CoreError(ErrorCode.PLUGIN_ERROR, e instanceof Error ? e.message : String(e));
|
|
118
|
-
logger.error(`dispatch ${header.pluginId}.${header.event} failed: ${error.message}`);
|
|
119
|
-
return invokeErrorResponse(header, error);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
if (isPluginInvokeRequestHeader(header)) {
|
|
123
|
-
const runtimeAdapter = registry.resolve(header.pluginId, runtime);
|
|
124
|
-
if (runtimeAdapter?.invoke) try {
|
|
125
|
-
const [error, okResult] = await runtimeAdapter.invoke(header.event, header.args, {
|
|
126
|
-
runtime,
|
|
127
|
-
payload
|
|
128
|
-
});
|
|
129
|
-
return {
|
|
130
|
-
type: "INVOKE_RESPONSE",
|
|
131
|
-
pluginId: header.pluginId,
|
|
132
|
-
event: header.event,
|
|
133
|
-
requestId: header.requestId,
|
|
134
|
-
result: okResult ?? void 0,
|
|
135
|
-
error: error ? {
|
|
136
|
-
code: error.code,
|
|
137
|
-
message: error.message
|
|
138
|
-
} : void 0
|
|
139
|
-
};
|
|
140
|
-
} catch (e) {
|
|
141
|
-
const error = new CoreError(ErrorCode.PLUGIN_ERROR, e instanceof Error ? e.message : String(e));
|
|
142
|
-
logger.error(`invoke ${header.pluginId}.${header.event} failed: ${error.message}`);
|
|
143
|
-
return invokeErrorResponse(header, error);
|
|
144
|
-
}
|
|
145
|
-
if (header.requestId && options?.delegateToHost) try {
|
|
146
|
-
const delegated = await options.delegateToHost(header, payload);
|
|
147
|
-
if (delegated) return delegated;
|
|
148
|
-
} catch (e) {
|
|
149
|
-
return invokeErrorResponse(header, new CoreError(ErrorCode.HOST_ERROR, e instanceof Error ? e.message : String(e)));
|
|
150
|
-
}
|
|
151
|
-
return invokeErrorResponse(header, new CoreError(ErrorCode.UNSUPPORTED_CAPABILITY, `Unsupported capability ${header.pluginId}.${header.event} on ${runtime}`));
|
|
152
|
-
}
|
|
153
|
-
return null;
|
|
154
|
-
} };
|
|
155
|
-
}
|
|
156
|
-
function createPluginBus(messenger) {
|
|
157
|
-
return {
|
|
158
|
-
dispatch(envelope) {
|
|
159
|
-
return messenger.dispatch({
|
|
160
|
-
type: "DISPATCH",
|
|
161
|
-
pluginId: envelope.pluginId,
|
|
162
|
-
event: envelope.event,
|
|
163
|
-
args: envelope.args
|
|
164
|
-
});
|
|
165
|
-
},
|
|
166
|
-
async invoke(envelope) {
|
|
167
|
-
const response = await messenger.invoke({
|
|
168
|
-
type: "INVOKE_REQUEST",
|
|
169
|
-
pluginId: envelope.pluginId,
|
|
170
|
-
event: envelope.event,
|
|
171
|
-
args: envelope.args
|
|
172
|
-
}, envelope.payload ?? null, envelope.timeoutMs);
|
|
173
|
-
if (isPluginInvokeResponseHeader(response)) {
|
|
174
|
-
if (response.error) return [new CoreError(response.error.code, String(response.error.message ?? "Plugin invoke failed")), null];
|
|
175
|
-
return [null, response.result];
|
|
176
|
-
}
|
|
177
|
-
return [new CoreError(ErrorCode.INVALID_RESPONSE, `Unexpected response type ${response.type}`), null];
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
function invokeErrorResponse(header, error) {
|
|
182
|
-
return {
|
|
183
|
-
type: "INVOKE_RESPONSE",
|
|
184
|
-
pluginId: header.pluginId,
|
|
185
|
-
event: header.event,
|
|
186
|
-
requestId: header.requestId,
|
|
187
|
-
error: {
|
|
188
|
-
code: error.code,
|
|
189
|
-
message: error.message
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
function isPluginDispatchHeader(header) {
|
|
194
|
-
return header.type === "DISPATCH" && typeof header.pluginId === "string" && typeof header.event === "string";
|
|
195
|
-
}
|
|
196
|
-
function isPluginEnvelopeHeader(header) {
|
|
197
|
-
return isPluginDispatchHeader(header) || isPluginInvokeRequestHeader(header);
|
|
198
|
-
}
|
|
199
|
-
function isPluginInvokeRequestHeader(header) {
|
|
200
|
-
return header.type === "INVOKE_REQUEST" && typeof header.pluginId === "string" && typeof header.event === "string";
|
|
201
|
-
}
|
|
202
|
-
function isPluginInvokeResponseHeader(header) {
|
|
203
|
-
return header.type === "INVOKE_RESPONSE" && typeof header.pluginId === "string" && typeof header.event === "string";
|
|
204
|
-
}
|
|
205
|
-
//#endregion
|
|
206
|
-
//#region core/messages/rpc-messenger.ts
|
|
207
|
-
function createProtocolMessenger(send) {
|
|
208
|
-
const pending = /* @__PURE__ */ new Map();
|
|
209
|
-
return {
|
|
210
|
-
dispatch(request, payload) {
|
|
211
|
-
const requestWithId = withRequestId(request);
|
|
212
|
-
send(requestWithId, payload);
|
|
213
|
-
return requestWithId.requestId;
|
|
214
|
-
},
|
|
215
|
-
invoke(request, payload, timeoutMs = 5e3) {
|
|
216
|
-
const requestWithId = withRequestId(request);
|
|
217
|
-
const { requestId } = requestWithId;
|
|
218
|
-
return new Promise((resolvePromise, rejectPromise) => {
|
|
219
|
-
const timer = setTimeout(() => {
|
|
220
|
-
pending.delete(requestId);
|
|
221
|
-
rejectPromise(/* @__PURE__ */ new Error(`invoke timeout for ${request.type} (${requestId})`));
|
|
222
|
-
}, timeoutMs);
|
|
223
|
-
pending.set(requestId, {
|
|
224
|
-
resolve: resolvePromise,
|
|
225
|
-
reject: rejectPromise,
|
|
226
|
-
timer
|
|
227
|
-
});
|
|
228
|
-
send(requestWithId, payload);
|
|
229
|
-
});
|
|
230
|
-
},
|
|
231
|
-
handleIncoming(header) {
|
|
232
|
-
if (!header.requestId) return;
|
|
233
|
-
const pendingCall = pending.get(header.requestId);
|
|
234
|
-
if (!pendingCall) return;
|
|
235
|
-
clearTimeout(pendingCall.timer);
|
|
236
|
-
pending.delete(header.requestId);
|
|
237
|
-
pendingCall.resolve(header);
|
|
238
|
-
}
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
function createRequestId() {
|
|
242
|
-
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
243
|
-
}
|
|
244
|
-
function withRequestId(request) {
|
|
245
|
-
return {
|
|
246
|
-
...request,
|
|
247
|
-
requestId: createRequestId()
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
//#endregion
|
|
251
|
-
//#region core/messages/wire-codec.ts
|
|
252
|
-
var MessageProtocol = class {
|
|
253
|
-
encodeStr;
|
|
254
|
-
decodeStr;
|
|
255
|
-
allowUnknownTypes;
|
|
256
|
-
maxFrameBytes;
|
|
257
|
-
constructor(options) {
|
|
258
|
-
this.encodeStr = options?.encode || ((str) => new TextEncoder().encode(str));
|
|
259
|
-
this.decodeStr = options?.decode || ((bytes) => new TextDecoder().decode(bytes));
|
|
260
|
-
this.allowUnknownTypes = options?.allowUnknownTypes ?? false;
|
|
261
|
-
this.maxFrameBytes = options?.maxFrameBytes ?? 16777216;
|
|
262
|
-
}
|
|
263
|
-
encode(type, header, payload) {
|
|
264
|
-
const headerJson = JSON.stringify(header);
|
|
265
|
-
const headerBytes = this.encodeStr(headerJson);
|
|
266
|
-
if (headerBytes.byteLength > 65535) throw new Error(`Header too large: ${headerBytes.byteLength} bytes, maximum is ${MAX_HEADER_BYTES}`);
|
|
267
|
-
let payloadBytes;
|
|
268
|
-
if (payload == null) payloadBytes = /* @__PURE__ */ new Uint8Array(0);
|
|
269
|
-
else if (typeof payload === "string") payloadBytes = this.encodeStr(payload);
|
|
270
|
-
else if (payload instanceof ArrayBuffer) payloadBytes = new Uint8Array(payload);
|
|
271
|
-
else payloadBytes = payload;
|
|
272
|
-
const hLen = headerBytes.byteLength;
|
|
273
|
-
const pLen = payloadBytes.byteLength;
|
|
274
|
-
const totalLength = 4 + hLen + pLen;
|
|
275
|
-
if (totalLength > this.maxFrameBytes) throw new Error(`Frame too large: ${totalLength} bytes, maximum is ${this.maxFrameBytes}`);
|
|
276
|
-
let buffer;
|
|
277
|
-
if (typeof Buffer !== "undefined" && typeof Buffer.allocUnsafe === "function") buffer = Buffer.allocUnsafe(totalLength);
|
|
278
|
-
else buffer = new Uint8Array(totalLength);
|
|
279
|
-
buffer[0] = 1;
|
|
280
|
-
buffer[1] = type;
|
|
281
|
-
buffer[2] = hLen >> 8 & 255;
|
|
282
|
-
buffer[3] = hLen & 255;
|
|
283
|
-
buffer.set(headerBytes, 4);
|
|
284
|
-
if (pLen > 0) buffer.set(payloadBytes, 4 + hLen);
|
|
285
|
-
return buffer;
|
|
286
|
-
}
|
|
287
|
-
decode(data) {
|
|
288
|
-
const view = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
289
|
-
const byteLength = view.byteLength;
|
|
290
|
-
if (byteLength < 4) throw new Error(`Message too short: ${byteLength} bytes`);
|
|
291
|
-
if (byteLength > this.maxFrameBytes) throw new Error(`Frame too large: ${byteLength} bytes, maximum is ${this.maxFrameBytes}`);
|
|
292
|
-
const version = view[0];
|
|
293
|
-
if (version !== 1) throw new Error(`Unsupported version: ${version}. Expected 1`);
|
|
294
|
-
const type = view[1];
|
|
295
|
-
if (!this.allowUnknownTypes && !isKnownMessageType(type)) throw new Error(`Unsupported message type: ${type}`);
|
|
296
|
-
const headerLen = view[2] << 8 | view[3];
|
|
297
|
-
if (byteLength < 4 + headerLen) throw new Error(`Message too short for header: ${byteLength} bytes, expected at least ${4 + headerLen}`);
|
|
298
|
-
return {
|
|
299
|
-
type,
|
|
300
|
-
header: parseAndValidateHeader(this.decodeStr(view.subarray(4, 4 + headerLen))),
|
|
301
|
-
payload: view.subarray(4 + headerLen)
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
};
|
|
305
|
-
function isKnownMessageType(type) {
|
|
306
|
-
return Object.values(MessageType).includes(type);
|
|
307
|
-
}
|
|
308
|
-
function parseAndValidateHeader(headerJson) {
|
|
309
|
-
const parsed = JSON.parse(headerJson);
|
|
310
|
-
if (!parsed || typeof parsed !== "object") throw new Error("Invalid header: expected object");
|
|
311
|
-
const header = parsed;
|
|
312
|
-
switch (header.type) {
|
|
313
|
-
case "DISPATCH":
|
|
314
|
-
if (isValidPluginHeaderFields(header)) return mergeHeader(header, {
|
|
315
|
-
type: "DISPATCH",
|
|
316
|
-
pluginId: header.pluginId,
|
|
317
|
-
event: header.event,
|
|
318
|
-
requestId: asOptionalString(header.requestId),
|
|
319
|
-
args: asOptionalRecord(header.args)
|
|
320
|
-
});
|
|
321
|
-
break;
|
|
322
|
-
case "INVOKE_REQUEST":
|
|
323
|
-
if (isValidPluginHeaderFields(header)) return mergeHeader(header, {
|
|
324
|
-
type: "INVOKE_REQUEST",
|
|
325
|
-
pluginId: header.pluginId,
|
|
326
|
-
event: header.event,
|
|
327
|
-
requestId: asOptionalString(header.requestId),
|
|
328
|
-
args: asOptionalRecord(header.args)
|
|
329
|
-
});
|
|
330
|
-
break;
|
|
331
|
-
case "INVOKE_RESPONSE":
|
|
332
|
-
if (isValidPluginHeaderFields(header)) return mergeHeader(header, {
|
|
333
|
-
type: "INVOKE_RESPONSE",
|
|
334
|
-
pluginId: header.pluginId,
|
|
335
|
-
event: header.event,
|
|
336
|
-
requestId: asOptionalString(header.requestId),
|
|
337
|
-
result: header.result,
|
|
338
|
-
error: parseCoreErrorWire(header.error)
|
|
339
|
-
});
|
|
340
|
-
break;
|
|
341
|
-
case "HOST_CAPABILITIES_QUERY":
|
|
342
|
-
if (typeof header.requestId === "string") return mergeHeader(header, {
|
|
343
|
-
type: "HOST_CAPABILITIES_QUERY",
|
|
344
|
-
requestId: header.requestId
|
|
345
|
-
});
|
|
346
|
-
break;
|
|
347
|
-
case "HOST_CAPABILITIES_RESPONSE":
|
|
348
|
-
if (typeof header.requestId === "string") return mergeHeader(header, {
|
|
349
|
-
type: "HOST_CAPABILITIES_RESPONSE",
|
|
350
|
-
requestId: header.requestId,
|
|
351
|
-
capabilities: parseCapabilityDescriptors(header.capabilities)
|
|
352
|
-
});
|
|
353
|
-
break;
|
|
354
|
-
case "HOST_INVOKE_REQUEST":
|
|
355
|
-
if (typeof header.requestId === "string" && typeof header.pluginId === "string" && typeof header.event === "string") return mergeHeader(header, {
|
|
356
|
-
type: "HOST_INVOKE_REQUEST",
|
|
357
|
-
requestId: header.requestId,
|
|
358
|
-
pluginId: header.pluginId,
|
|
359
|
-
event: header.event,
|
|
360
|
-
args: asOptionalRecord(header.args)
|
|
361
|
-
});
|
|
362
|
-
break;
|
|
363
|
-
case "HOST_INVOKE_RESPONSE": if (typeof header.requestId === "string" && typeof header.pluginId === "string" && typeof header.event === "string") return mergeHeader(header, {
|
|
364
|
-
type: "HOST_INVOKE_RESPONSE",
|
|
365
|
-
requestId: header.requestId,
|
|
366
|
-
pluginId: header.pluginId,
|
|
367
|
-
event: header.event,
|
|
368
|
-
result: header.result,
|
|
369
|
-
error: parseCoreErrorWire(header.error)
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
throw new Error(`Unsupported header type: ${String(header.type)}`);
|
|
373
|
-
}
|
|
374
|
-
/** Validated known fields win, unknown fields pass through untouched so
|
|
375
|
-
* forward-compatible peers can relay envelopes without losing data. */
|
|
376
|
-
function mergeHeader(parsed, known) {
|
|
377
|
-
return {
|
|
378
|
-
...parsed,
|
|
379
|
-
...known
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
function isValidPluginHeaderFields(header) {
|
|
383
|
-
return typeof header.pluginId === "string" && typeof header.event === "string";
|
|
384
|
-
}
|
|
385
|
-
function asOptionalString(value) {
|
|
386
|
-
return typeof value === "string" ? value : void 0;
|
|
387
|
-
}
|
|
388
|
-
function asOptionalRecord(value) {
|
|
389
|
-
return value && typeof value === "object" ? value : void 0;
|
|
390
|
-
}
|
|
391
|
-
function parseCoreErrorWire(value) {
|
|
392
|
-
if (!value || typeof value !== "object") return void 0;
|
|
393
|
-
const candidate = value;
|
|
394
|
-
if (typeof candidate.code !== "string" || typeof candidate.message !== "string") return void 0;
|
|
395
|
-
return {
|
|
396
|
-
code: candidate.code,
|
|
397
|
-
message: candidate.message
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
const RUNTIME_TARGETS = /* @__PURE__ */ new Set([
|
|
401
|
-
"web",
|
|
402
|
-
"android",
|
|
403
|
-
"ios",
|
|
404
|
-
"bare"
|
|
405
|
-
]);
|
|
406
|
-
function parseRuntimeTarget(value) {
|
|
407
|
-
if (typeof value !== "string") return null;
|
|
408
|
-
return RUNTIME_TARGETS.has(value) ? value : null;
|
|
409
|
-
}
|
|
410
|
-
function parseCapabilityDescriptors(value) {
|
|
411
|
-
if (!Array.isArray(value)) return [];
|
|
412
|
-
const out = [];
|
|
413
|
-
for (const row of value) {
|
|
414
|
-
if (!row || typeof row !== "object") continue;
|
|
415
|
-
const r = row;
|
|
416
|
-
if (typeof r.pluginId !== "string") continue;
|
|
417
|
-
const events = Array.isArray(r.events) ? r.events.filter((e) => typeof e === "string") : [];
|
|
418
|
-
const caps = Array.isArray(r.capabilities) ? r.capabilities.filter((c) => typeof c === "string") : [];
|
|
419
|
-
const runtimes = [];
|
|
420
|
-
if (Array.isArray(r.runtimes)) for (const rt of r.runtimes) {
|
|
421
|
-
const parsed = parseRuntimeTarget(rt);
|
|
422
|
-
if (parsed) runtimes.push(parsed);
|
|
423
|
-
}
|
|
424
|
-
out.push({
|
|
425
|
-
pluginId: r.pluginId,
|
|
426
|
-
capabilities: caps,
|
|
427
|
-
events,
|
|
428
|
-
runtimes
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
return out;
|
|
432
|
-
}
|
|
433
|
-
//#endregion
|
|
434
|
-
//#region core/messages/define-plugin.ts
|
|
435
|
-
/**
|
|
436
|
-
* Builds a {@link PluginManifest} from an event spec table. The `events` list
|
|
437
|
-
* is derived from the specs and handlers are dispatched by event name — no
|
|
438
|
-
* hand-written if-chains. Handlers receive typed args. Plugins with no local
|
|
439
|
-
* handlers (host-delegated, e.g. `core.permissions`) pass no `invoke`/`dispatch`.
|
|
440
|
-
*/
|
|
441
|
-
function definePlugin(id, specs, options = {}) {
|
|
442
|
-
const invokeByEvent = /* @__PURE__ */ new Map();
|
|
443
|
-
const dispatchByEvent = /* @__PURE__ */ new Map();
|
|
444
|
-
const events = [];
|
|
445
|
-
for (const key of Object.keys(specs)) {
|
|
446
|
-
const spec = specs[key];
|
|
447
|
-
if (spec.pluginId !== id) throw new Error(`event spec ${spec.name} belongs to ${spec.pluginId}, not ${id}`);
|
|
448
|
-
events.push(spec.name);
|
|
449
|
-
const invoker = options.invoke?.[key];
|
|
450
|
-
if (invoker) invokeByEvent.set(spec.name, invoker);
|
|
451
|
-
const dispatcher = options.dispatch?.[key];
|
|
452
|
-
if (dispatcher) dispatchByEvent.set(spec.name, dispatcher);
|
|
453
|
-
}
|
|
454
|
-
const adapter = {};
|
|
455
|
-
if (invokeByEvent.size > 0) adapter.invoke = (event, args, context) => {
|
|
456
|
-
const handler = invokeByEvent.get(event);
|
|
457
|
-
if (!handler) throw new Error(`Unhandled invoke event ${event}`);
|
|
458
|
-
return handler(args, context);
|
|
459
|
-
};
|
|
460
|
-
if (dispatchByEvent.size > 0) adapter.dispatch = (event, args, context) => {
|
|
461
|
-
const handler = dispatchByEvent.get(event);
|
|
462
|
-
if (!handler) throw new Error(`Unhandled dispatch event ${event}`);
|
|
463
|
-
return handler(args, context);
|
|
464
|
-
};
|
|
465
|
-
const runtimes = {};
|
|
466
|
-
if (invokeByEvent.size > 0 || dispatchByEvent.size > 0) runtimes.bare = adapter;
|
|
467
|
-
return {
|
|
468
|
-
id,
|
|
469
|
-
capabilities: options.capabilities,
|
|
470
|
-
events,
|
|
471
|
-
runtimes
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
/** Typed builder: an invoke envelope for a spec's event. */
|
|
475
|
-
function invokeEvent(spec, args, payload, timeoutMs) {
|
|
476
|
-
return {
|
|
477
|
-
kind: "invoke",
|
|
478
|
-
pluginId: spec.pluginId,
|
|
479
|
-
event: spec.name,
|
|
480
|
-
args,
|
|
481
|
-
payload,
|
|
482
|
-
timeoutMs
|
|
483
|
-
};
|
|
484
|
-
}
|
|
485
|
-
/** Typed builder: a dispatch envelope for a spec's event. */
|
|
486
|
-
function dispatchEvent(spec, args, payload) {
|
|
487
|
-
return {
|
|
488
|
-
kind: "dispatch",
|
|
489
|
-
pluginId: spec.pluginId,
|
|
490
|
-
event: spec.name,
|
|
491
|
-
args,
|
|
492
|
-
payload
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
//#endregion
|
|
496
|
-
//#region core/messages/create-bare-runtime-context.ts
|
|
497
|
-
function createBareRuntimeContext(plugins = [], routerOptions) {
|
|
498
|
-
const runtime = "bare";
|
|
499
|
-
const protocol = new MessageProtocol({
|
|
500
|
-
encode: (str) => new TextEncoder$1().encode(str),
|
|
501
|
-
decode: (bytes) => new TextDecoder$1().decode(bytes)
|
|
502
|
-
});
|
|
503
|
-
const pluginRegistry = createPluginRegistry();
|
|
504
|
-
for (const plugin of plugins) pluginRegistry.register(plugin);
|
|
505
|
-
return {
|
|
506
|
-
protocol,
|
|
507
|
-
pluginRegistry,
|
|
508
|
-
pluginRouter: createPluginRouter(pluginRegistry, runtime, routerOptions)
|
|
509
|
-
};
|
|
510
|
-
}
|
|
511
|
-
//#endregion
|
|
512
|
-
export { CoreError, ErrorCode, MAX_FRAME_BYTES, MAX_HEADER_BYTES, MessageProtocol, MessageType, VERSION, coerceErrorCode, createBareRuntimeContext, createPluginBus, createPluginRegistry, createPluginRouter, createProtocolMessenger, definePlugin, dispatchEvent, err, invokeEvent, ok };
|
|
1
|
+
export { h as CoreError, g as ErrorCode, _ as MAX_FRAME_BYTES, v as MAX_HEADER_BYTES, o as MessageProtocol, y as MessageType, b as VERSION, f as coerceErrorCode, n as createBareRuntimeContext, l as createPluginBus, u as createPluginRegistry, d as createPluginRouter, s as createProtocolMessenger, r as definePlugin, i as dispatchEvent, p as err, t as installWebConsoleCapture, a as invokeEvent, m as ok } from "./messages-BbpF3wNH.mjs";
|