@get-bb/plugin-sdk 0.4.45 → 0.4.48
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/bundled-types/bb-plugin-sdk-app.d.ts +48 -1
- package/bundled-types/bb-plugin-sdk-internal-plugin-app-collector.d.ts +34 -3
- package/bundled-types/bb-plugin-sdk-testing-app.d.ts +18 -1
- package/bundled-types/bb-plugin-sdk-testing.d.ts +20 -1
- package/bundled-types/bb-plugin-sdk.d.ts +484 -1
- package/dist/internal/host-policy.js +1 -0
- package/dist/internal/plugin-app-collector.js +142 -5
- package/dist/provider-bridge-acp.js +10 -8
- package/dist/provider-bridge-testing.js +2 -11
- package/dist/provider-bridge.js +10 -8
- package/dist/testing/app.js +136 -4
- package/dist/testing/index.js +151 -0
- package/package.json +1 -1
package/dist/testing/index.js
CHANGED
|
@@ -36,6 +36,7 @@ function parseNamespacedGlyph(glyph) {
|
|
|
36
36
|
|
|
37
37
|
// ../domain/src/plugin-cli.ts
|
|
38
38
|
var RESERVED_BB_CLI_COMMANDS = [
|
|
39
|
+
"browser",
|
|
39
40
|
"environment",
|
|
40
41
|
"file",
|
|
41
42
|
"guide",
|
|
@@ -2311,6 +2312,8 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
2311
2312
|
}
|
|
2312
2313
|
};
|
|
2313
2314
|
const httpRoutes = [];
|
|
2315
|
+
const websocketRoutes = [];
|
|
2316
|
+
const websocketSessions = /* @__PURE__ */ new Set();
|
|
2314
2317
|
const http = {
|
|
2315
2318
|
route(method, path, handler, opts) {
|
|
2316
2319
|
assertLive();
|
|
@@ -2344,6 +2347,29 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
2344
2347
|
);
|
|
2345
2348
|
}
|
|
2346
2349
|
httpRoutes.push({ method: normalizedMethod, path, auth, handler });
|
|
2350
|
+
},
|
|
2351
|
+
experimental_websocket(path, handler, opts) {
|
|
2352
|
+
assertLive();
|
|
2353
|
+
if (typeof path !== "string" || !path.startsWith("/")) {
|
|
2354
|
+
throw new Error(
|
|
2355
|
+
`websocket route path must be a string starting with "/", got ${JSON.stringify(path)}`
|
|
2356
|
+
);
|
|
2357
|
+
}
|
|
2358
|
+
if (typeof handler !== "function") {
|
|
2359
|
+
throw new Error(
|
|
2360
|
+
`websocket route handler for ${path} must be a function`
|
|
2361
|
+
);
|
|
2362
|
+
}
|
|
2363
|
+
const auth = opts?.auth ?? "local";
|
|
2364
|
+
if (auth !== "local" && auth !== "token" && auth !== "none") {
|
|
2365
|
+
throw new Error(
|
|
2366
|
+
`invalid auth mode "${String(auth)}" for websocket ${path} \u2014 use "local", "token", or "none"`
|
|
2367
|
+
);
|
|
2368
|
+
}
|
|
2369
|
+
if (websocketRoutes.some((route) => route.path === path)) {
|
|
2370
|
+
throw new Error(`websocket route ${path} is already registered`);
|
|
2371
|
+
}
|
|
2372
|
+
websocketRoutes.push({ path, auth, handler });
|
|
2347
2373
|
}
|
|
2348
2374
|
};
|
|
2349
2375
|
const rpcHandlers = /* @__PURE__ */ new Map();
|
|
@@ -3059,6 +3085,9 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
3059
3085
|
pendingInteractions.delete(id);
|
|
3060
3086
|
pending.resolve({ outcome: "cancelled", reason: "plugin-disposed" });
|
|
3061
3087
|
}
|
|
3088
|
+
for (const session of [...websocketSessions]) {
|
|
3089
|
+
await session.closeForReload();
|
|
3090
|
+
}
|
|
3062
3091
|
for (const controller of serviceControllers) controller.abort();
|
|
3063
3092
|
for (const hook of [...disposeHooks].reverse()) {
|
|
3064
3093
|
try {
|
|
@@ -3104,6 +3133,7 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
3104
3133
|
registrations: {
|
|
3105
3134
|
settingsDescriptors,
|
|
3106
3135
|
httpRoutes,
|
|
3136
|
+
websocketRoutes,
|
|
3107
3137
|
get rpcMethods() {
|
|
3108
3138
|
return [...rpcHandlers.keys()];
|
|
3109
3139
|
},
|
|
@@ -3321,6 +3351,127 @@ function createFakePluginHostInternal(options, sharedState) {
|
|
|
3321
3351
|
});
|
|
3322
3352
|
return app.request(path, { ...init, method: normalizedMethod });
|
|
3323
3353
|
},
|
|
3354
|
+
async experimental_openWebSocket(path, init) {
|
|
3355
|
+
assertLive();
|
|
3356
|
+
const url = new URL(path, "http://plugin.test");
|
|
3357
|
+
const route = websocketRoutes.find(
|
|
3358
|
+
(candidate) => candidate.path === url.pathname
|
|
3359
|
+
);
|
|
3360
|
+
if (!route) {
|
|
3361
|
+
throw new Error(
|
|
3362
|
+
`no websocket route ${url.pathname} is registered \u2014 registered: ${websocketRoutes.map((candidate) => candidate.path).join(", ") || "(none)"}`
|
|
3363
|
+
);
|
|
3364
|
+
}
|
|
3365
|
+
const request = new Request(url, { ...init, method: "GET" });
|
|
3366
|
+
let handlers;
|
|
3367
|
+
try {
|
|
3368
|
+
handlers = route.handler({
|
|
3369
|
+
request,
|
|
3370
|
+
url,
|
|
3371
|
+
headers: request.headers
|
|
3372
|
+
});
|
|
3373
|
+
if (typeof handlers !== "object" || handlers === null || Array.isArray(handlers)) {
|
|
3374
|
+
throw new Error("websocket route handler must return an object");
|
|
3375
|
+
}
|
|
3376
|
+
for (const name of [
|
|
3377
|
+
"onOpen",
|
|
3378
|
+
"onMessage",
|
|
3379
|
+
"onClose",
|
|
3380
|
+
"onError"
|
|
3381
|
+
]) {
|
|
3382
|
+
const callback = handlers[name];
|
|
3383
|
+
if (callback !== void 0 && typeof callback !== "function") {
|
|
3384
|
+
throw new Error(
|
|
3385
|
+
`websocket route handler ${name} must be a function`
|
|
3386
|
+
);
|
|
3387
|
+
}
|
|
3388
|
+
}
|
|
3389
|
+
} catch (error) {
|
|
3390
|
+
emitLog(
|
|
3391
|
+
"warn",
|
|
3392
|
+
`websocket ${route.path} connect failed: ${errorMessage(error)}`
|
|
3393
|
+
);
|
|
3394
|
+
throw error;
|
|
3395
|
+
}
|
|
3396
|
+
const sent = [];
|
|
3397
|
+
const closeCalls = [];
|
|
3398
|
+
let readyState = 0;
|
|
3399
|
+
let closeNotified = false;
|
|
3400
|
+
let eventQueue = Promise.resolve();
|
|
3401
|
+
const invoke = async (event, run) => {
|
|
3402
|
+
eventQueue = eventQueue.then(async () => {
|
|
3403
|
+
try {
|
|
3404
|
+
await run();
|
|
3405
|
+
} catch (error) {
|
|
3406
|
+
emitLog(
|
|
3407
|
+
"warn",
|
|
3408
|
+
`websocket ${route.path} ${event} failed: ${errorMessage(error)}`
|
|
3409
|
+
);
|
|
3410
|
+
}
|
|
3411
|
+
});
|
|
3412
|
+
await eventQueue;
|
|
3413
|
+
};
|
|
3414
|
+
const socket = {
|
|
3415
|
+
send(data) {
|
|
3416
|
+
sent.push(typeof data === "string" ? data : new Uint8Array(data));
|
|
3417
|
+
},
|
|
3418
|
+
close(code, reason) {
|
|
3419
|
+
closeCalls.push({ code: code ?? null, reason: reason ?? null });
|
|
3420
|
+
if (readyState < 2) readyState = 2;
|
|
3421
|
+
},
|
|
3422
|
+
get readyState() {
|
|
3423
|
+
return readyState;
|
|
3424
|
+
}
|
|
3425
|
+
};
|
|
3426
|
+
const notifyClose = async (code, reason) => {
|
|
3427
|
+
if (closeNotified) return;
|
|
3428
|
+
closeNotified = true;
|
|
3429
|
+
readyState = 3;
|
|
3430
|
+
websocketSessions.delete(session);
|
|
3431
|
+
if (handlers.onClose !== void 0) {
|
|
3432
|
+
await invoke(
|
|
3433
|
+
"close",
|
|
3434
|
+
() => handlers.onClose?.(socket, { code, reason })
|
|
3435
|
+
);
|
|
3436
|
+
}
|
|
3437
|
+
};
|
|
3438
|
+
const session = {
|
|
3439
|
+
sent,
|
|
3440
|
+
closeCalls,
|
|
3441
|
+
get readyState() {
|
|
3442
|
+
return readyState;
|
|
3443
|
+
},
|
|
3444
|
+
async receive(data) {
|
|
3445
|
+
if (readyState !== 1) {
|
|
3446
|
+
throw new Error(
|
|
3447
|
+
"cannot receive a websocket message while not open"
|
|
3448
|
+
);
|
|
3449
|
+
}
|
|
3450
|
+
if (handlers.onMessage !== void 0) {
|
|
3451
|
+
await invoke("message", () => handlers.onMessage?.(socket, data));
|
|
3452
|
+
}
|
|
3453
|
+
},
|
|
3454
|
+
async close(code = 1e3, reason = "") {
|
|
3455
|
+
if (readyState < 2) socket.close(code, reason);
|
|
3456
|
+
await notifyClose(code, reason);
|
|
3457
|
+
},
|
|
3458
|
+
async error(error) {
|
|
3459
|
+
if (handlers.onError !== void 0) {
|
|
3460
|
+
await invoke("error", () => handlers.onError?.(socket, error));
|
|
3461
|
+
}
|
|
3462
|
+
},
|
|
3463
|
+
async closeForReload() {
|
|
3464
|
+
socket.close(1012, "Plugin reloaded or disabled");
|
|
3465
|
+
await notifyClose(1012, "Plugin reloaded or disabled");
|
|
3466
|
+
}
|
|
3467
|
+
};
|
|
3468
|
+
websocketSessions.add(session);
|
|
3469
|
+
readyState = 1;
|
|
3470
|
+
if (handlers.onOpen !== void 0) {
|
|
3471
|
+
await invoke("open", () => handlers.onOpen?.(socket));
|
|
3472
|
+
}
|
|
3473
|
+
return session;
|
|
3474
|
+
},
|
|
3324
3475
|
runService(name) {
|
|
3325
3476
|
const service = services.find((record) => record.name === name);
|
|
3326
3477
|
if (!service) {
|