@bridgething/extension 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Joey Eamigh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # @bridgething/extension
2
+
3
+ The client a [bridgething](https://github.com/JoeyEamigh/bridgething) extension
4
+ uses to talk to its host. An extension is a Deno process the bridgething
5
+ desktop app runs beside a webapp.
6
+
7
+ ```sh
8
+ bun add @bridgething/extension
9
+ ```
10
+
11
+ ```ts
12
+ import { asJson, defineExtension, json } from '@bridgething/extension';
13
+
14
+ defineExtension({
15
+ start(ctx) {
16
+ ctx.on('device', e => ctx.log.info(e.type, e.device.name));
17
+ ctx.on('message', (device, message) =>
18
+ device.send(json({ echo: asJson(message) })),
19
+ );
20
+ },
21
+ });
22
+ ```
23
+
24
+ Register listeners synchronously in `start`; the host replays connected devices
25
+ as soon as `start` runs. The host protocol owns stdin and stdout, so
26
+ `console.log` corrupts it. Log with `ctx.log`.
27
+
28
+ Scaffold a webapp with an extension:
29
+
30
+ ```sh
31
+ bun create bridgething my-app --extension
32
+ ```
33
+
34
+ - Docs: <https://bridgething.com/docs/extensions>
35
+ - Source: <https://github.com/JoeyEamigh/bridgething>
@@ -0,0 +1,100 @@
1
+ import type { ForwardMessage, SendableMessage } from './message.js';
2
+ import type { ExtensionWebapp, LogLevel } from './protocol.js';
3
+ /** Drops a listener registered with `ctx.on`. Safe to call more than once. */
4
+ export type Unsubscribe = () => void;
5
+ export type DeviceRef = string | {
6
+ id: string;
7
+ };
8
+ /**
9
+ * One Car Thing the host has announced to this extension. A handle stays valid for the life of the process.
10
+ * A disconnected device keeps its last known `name` and `config`, with `connected` false.
11
+ */
12
+ export interface Device {
13
+ /** The device serial. Stable across reconnects and across host restarts. */
14
+ readonly id: string;
15
+ readonly name: string;
16
+ /** True while this extension's webapp is the active webapp on this device. */
17
+ readonly active: boolean;
18
+ readonly connected: boolean;
19
+ /** The webapp's settings for this device, keyed by config key from `manifest.json`. */
20
+ readonly config: Readonly<Record<string, string>>;
21
+ /**
22
+ * Sends a message to this device's webapp. The host delivers it while the webapp is active,
23
+ * and drops it otherwise.
24
+ */
25
+ send(message: SendableMessage): void;
26
+ }
27
+ /** Connect, disconnect, and active-webapp changes, in one stream. */
28
+ export type DeviceEvent = {
29
+ type: 'connected' | 'disconnected' | 'active';
30
+ device: Device;
31
+ };
32
+ export type DeviceListener = (event: DeviceEvent) => void;
33
+ export type MessageListener = (device: Device, message: ForwardMessage) => void;
34
+ /** `value` is null when the settings page clears the key, which removes it from `device.config`. */
35
+ export type ConfigListener = (device: Device, key: string, value: string | null) => void;
36
+ /**
37
+ * Persistent JSON store for this extension, held in a file under `ctx.dataDir`.
38
+ * Every method rejects once shutdown starts, so write as state changes.
39
+ */
40
+ export interface KvStore {
41
+ get<T = unknown>(key: string): Promise<T | undefined>;
42
+ set(key: string, value: unknown): Promise<void>;
43
+ delete(key: string): Promise<void>;
44
+ list(): Promise<string[]>;
45
+ }
46
+ export interface AuthBridge {
47
+ /**
48
+ * Opens `url` in the user's browser. Resolves with the callback URL the host captured,
49
+ * including its query string. Rejects if the user cancels.
50
+ */
51
+ authorize(url: string): Promise<string>;
52
+ }
53
+ /** Writes to the desktop app's log, prefixed with the webapp name. */
54
+ export interface ExtensionLog {
55
+ debug(...args: unknown[]): void;
56
+ info(...args: unknown[]): void;
57
+ warn(...args: unknown[]): void;
58
+ error(...args: unknown[]): void;
59
+ log(level: LogLevel, ...args: unknown[]): void;
60
+ }
61
+ /** Everything an extension can reach. `start` receives it. */
62
+ export interface ExtensionContext {
63
+ /** The host protocol revision. */
64
+ readonly api: number;
65
+ readonly webapp: ExtensionWebapp;
66
+ /** Directory this extension may write to. The kv store file lives here. */
67
+ readonly dataDir: string;
68
+ /** The connected devices, recomputed on every read. */
69
+ readonly devices: readonly Device[];
70
+ /** Returns a handle for any device id, connected or not. */
71
+ device(id: string): Device;
72
+ /** Sends a message to every connected device where this webapp is active. */
73
+ broadcast(message: SendableMessage): void;
74
+ /** Returns the settings for a device. An id the host has not announced returns an empty object. */
75
+ config(device: DeviceRef): Readonly<Record<string, string>>;
76
+ /**
77
+ * Registers a listener. Call `on` synchronously at the top of `start`. The host replays
78
+ * connected devices right after `start` begins, so a listener registered after an `await`
79
+ * can miss them.
80
+ */
81
+ on(event: 'device', listener: DeviceListener): Unsubscribe;
82
+ on(event: 'message', listener: MessageListener): Unsubscribe;
83
+ on(event: 'config', listener: ConfigListener): Unsubscribe;
84
+ readonly kv: KvStore;
85
+ readonly auth: AuthBridge;
86
+ readonly log: ExtensionLog;
87
+ }
88
+ export type ExtensionSpec = {
89
+ /**
90
+ * Runs once, after the host connects. Register listeners synchronously, then do the rest of
91
+ * your setup. The desktop app shows this extension as starting until the returned promise settles.
92
+ */
93
+ start(ctx: ExtensionContext): void | Promise<void>;
94
+ /**
95
+ * Runs before the process exits, on host shutdown or disconnect. Release timers, sockets, and
96
+ * child processes here. `ctx.kv` and `ctx.auth` reject from this hook, so persist state as it changes.
97
+ */
98
+ stop?(): void | Promise<void>;
99
+ };
100
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":""}
package/dist/deno.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { type ExtensionHost } from './host.js';
2
+ /** The host protocol over `Deno.stdin` and `Deno.stdout`. `defineExtension` uses this transport by default. */
3
+ export declare function denoHost(): ExtensionHost;
4
+ //# sourceMappingURL=deno.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deno.d.ts","sourceRoot":"","sources":["../src/deno.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAQ/D,+GAA+G;AAC/G,wBAAgB,QAAQ,IAAI,aAAa,CAUxC"}
package/dist/deno.js ADDED
@@ -0,0 +1,14 @@
1
+ import { ExtensionError } from './host.js';
2
+ /** The host protocol over `Deno.stdin` and `Deno.stdout`. `defineExtension` uses this transport by default. */
3
+ export function denoHost() {
4
+ const runtime = globalThis.Deno;
5
+ if (!runtime) {
6
+ throw new ExtensionError('extensions run under deno; no Deno global in this process', 'no-runtime');
7
+ }
8
+ return {
9
+ readable: runtime.stdin.readable,
10
+ writable: runtime.stdout.writable,
11
+ exit: code => runtime.exit(code),
12
+ };
13
+ }
14
+ //# sourceMappingURL=deno.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deno.js","sourceRoot":"","sources":["../src/deno.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAsB,MAAM,WAAW,CAAC;AAQ/D,+GAA+G;AAC/G,MAAM,UAAU,QAAQ;IACtB,MAAM,OAAO,GAAI,UAAgD,CAAC,IAAI,CAAC;IACvE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,cAAc,CAAC,2DAA2D,EAAE,YAAY,CAAC,CAAC;IACtG,CAAC;IACD,OAAO;QACL,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,QAAQ;QAChC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ;QACjC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;KACjC,CAAC;AACJ,CAAC"}
package/dist/host.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ import type { ExtensionMessage } from './protocol.js';
2
+ /**
3
+ * The transport an extension runs over. The two byte streams carry the newline-delimited host
4
+ * protocol, and `exit` ends the process. Pass in-memory streams to drive a runtime from a test.
5
+ */
6
+ export type ExtensionHost = {
7
+ readable: ReadableStream<Uint8Array>;
8
+ writable: WritableStream<Uint8Array>;
9
+ exit(code: number): void;
10
+ };
11
+ /** Every failure this package raises. Branch on `kind`. */
12
+ export declare class ExtensionError extends Error {
13
+ readonly kind: 'host-error' | 'disconnected' | 'write-failed' | 'no-runtime';
14
+ constructor(message: string, kind: 'host-error' | 'disconnected' | 'write-failed' | 'no-runtime');
15
+ }
16
+ export declare function readLines(reader: ReadableStreamDefaultReader<Uint8Array>): AsyncGenerator<string>;
17
+ export declare class LineWriter {
18
+ private readonly writer;
19
+ private readonly encoder;
20
+ private tail;
21
+ constructor(writable: WritableStream<Uint8Array>);
22
+ write(message: ExtensionMessage): Promise<void>;
23
+ close(): Promise<void>;
24
+ }
25
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACrC,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF,2DAA2D;AAC3D,qBAAa,cAAe,SAAQ,KAAK;aAGrB,IAAI,EAAE,YAAY,GAAG,cAAc,GAAG,cAAc,GAAG,YAAY;gBADnF,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,YAAY,GAAG,cAAc,GAAG,cAAc,GAAG,YAAY;CAKtF;AAED,wBAAuB,SAAS,CAAC,MAAM,EAAE,2BAA2B,CAAC,UAAU,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAmBxG;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,IAAI,CAAoC;gBAEpC,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC;IAIhD,KAAK,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOzC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ7B"}
package/dist/host.js ADDED
@@ -0,0 +1,57 @@
1
+ /** Every failure this package raises. Branch on `kind`. */
2
+ export class ExtensionError extends Error {
3
+ kind;
4
+ constructor(message, kind) {
5
+ super(message);
6
+ this.kind = kind;
7
+ this.name = 'ExtensionError';
8
+ }
9
+ }
10
+ export async function* readLines(reader) {
11
+ const decoder = new TextDecoder();
12
+ let buffered = '';
13
+ try {
14
+ for (;;) {
15
+ const { done, value } = await reader.read();
16
+ if (done)
17
+ break;
18
+ buffered += decoder.decode(value, { stream: true });
19
+ for (let cut = buffered.indexOf('\n'); cut >= 0; cut = buffered.indexOf('\n')) {
20
+ const line = buffered.slice(0, cut);
21
+ buffered = buffered.slice(cut + 1);
22
+ if (line.trim().length > 0)
23
+ yield line;
24
+ }
25
+ }
26
+ buffered += decoder.decode();
27
+ if (buffered.trim().length > 0)
28
+ yield buffered;
29
+ }
30
+ finally {
31
+ reader.releaseLock();
32
+ }
33
+ }
34
+ export class LineWriter {
35
+ writer;
36
+ encoder = new TextEncoder();
37
+ tail = Promise.resolve();
38
+ constructor(writable) {
39
+ this.writer = writable.getWriter();
40
+ }
41
+ write(message) {
42
+ const chunk = this.encoder.encode(`${JSON.stringify(message)}\n`);
43
+ const written = this.tail.then(() => this.writer.write(chunk));
44
+ this.tail = written.catch(() => undefined);
45
+ return written;
46
+ }
47
+ async close() {
48
+ await this.tail;
49
+ try {
50
+ await this.writer.close();
51
+ }
52
+ catch {
53
+ this.writer.releaseLock();
54
+ }
55
+ }
56
+ }
57
+ //# sourceMappingURL=host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAYA,2DAA2D;AAC3D,MAAM,OAAO,cAAe,SAAQ,KAAK;IAGrB;IAFlB,YACE,OAAe,EACC,IAAmE;QAEnF,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,SAAI,GAAJ,IAAI,CAA+D;QAGnF,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,SAAS,CAAC,MAA+C;IAC9E,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,CAAC;QACH,SAAS,CAAC;YACR,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI;gBAAE,MAAM;YAChB,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,KAAK,IAAI,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9E,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;gBACpC,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;gBACnC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;oBAAE,MAAM,IAAI,CAAC;YACzC,CAAC;QACH,CAAC;QACD,QAAQ,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QAC7B,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,QAAQ,CAAC;IACjD,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;AACH,CAAC;AAED,MAAM,OAAO,UAAU;IACJ,MAAM,CAA0C;IAChD,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IACrC,IAAI,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;IAEhD,YAAY,QAAoC;QAC9C,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,OAAyB;QAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAClE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/D,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC3C,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,IAAI,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QAC5B,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,25 @@
1
+ import type { ExtensionSpec } from './context.js';
2
+ import type { ExtensionHost } from './host.js';
3
+ export type { AuthBridge, ConfigListener, Device, DeviceEvent, DeviceListener, DeviceRef, ExtensionContext, ExtensionLog, ExtensionSpec, KvStore, MessageListener, Unsubscribe, } from './context.js';
4
+ export { denoHost } from './deno.js';
5
+ export { ExtensionError, type ExtensionHost } from './host.js';
6
+ export { asBinary, asJson, asText, binary, json, text, type ForwardMessage, type SendableMessage } from './message.js';
7
+ export { EXTENSION_API_VERSION, type ExtensionMessage, type ExtensionWebapp, type HostMessage, type LogLevel, type WireForwardMessage, } from './protocol.js';
8
+ /**
9
+ * Runs an extension. Call it once at the top level of the entry module.
10
+ *
11
+ * The host protocol owns stdin and stdout, so `console.log` corrupts it. Log with `ctx.log`.
12
+ *
13
+ * ```ts
14
+ * defineExtension({
15
+ * start(ctx) {
16
+ * ctx.on('message', (device, message) => device.send(asJson(message) ?? 'pong'));
17
+ * },
18
+ * });
19
+ * ```
20
+ *
21
+ * The returned promise settles after `stop()` runs, once the host sends `stop` or closes stdin.
22
+ * Pass `host` to run the same runtime over streams you own.
23
+ */
24
+ export declare function defineExtension(spec: ExtensionSpec, host?: ExtensionHost): Promise<void>;
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG/C,YAAY,EACV,UAAU,EACV,cAAc,EACd,MAAM,EACN,WAAW,EACX,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,OAAO,EACP,eAAe,EACf,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACvH,OAAO,EACL,qBAAqB,EACrB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,kBAAkB,GACxB,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,GAAE,aAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpG"}
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ import { denoHost } from './deno.js';
2
+ import { ExtensionRuntime } from './runtime.js';
3
+ export { denoHost } from './deno.js';
4
+ export { ExtensionError } from './host.js';
5
+ export { asBinary, asJson, asText, binary, json, text } from './message.js';
6
+ export { EXTENSION_API_VERSION, } from './protocol.js';
7
+ /**
8
+ * Runs an extension. Call it once at the top level of the entry module.
9
+ *
10
+ * The host protocol owns stdin and stdout, so `console.log` corrupts it. Log with `ctx.log`.
11
+ *
12
+ * ```ts
13
+ * defineExtension({
14
+ * start(ctx) {
15
+ * ctx.on('message', (device, message) => device.send(asJson(message) ?? 'pong'));
16
+ * },
17
+ * });
18
+ * ```
19
+ *
20
+ * The returned promise settles after `stop()` runs, once the host sends `stop` or closes stdin.
21
+ * Pass `host` to run the same runtime over streams you own.
22
+ */
23
+ export function defineExtension(spec, host = denoHost()) {
24
+ return new ExtensionRuntime(spec, host).run();
25
+ }
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAgBhD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,cAAc,EAAsB,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAA6C,MAAM,cAAc,CAAC;AACvH,OAAO,EACL,qBAAqB,GAMtB,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,IAAmB,EAAE,OAAsB,QAAQ,EAAE;IACnF,OAAO,IAAI,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;AAChD,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { ForwardMessage } from '@bridgething/lib/shared';
2
+ import type { WireForwardMessage } from './protocol.js';
3
+ export type { ForwardMessage };
4
+ /**
5
+ * Anything `send` and `broadcast` accept. The runtime sends a string as `text` and a `Uint8Array`
6
+ * as `binary`. Wrap any other value with {@link json}.
7
+ */
8
+ export type SendableMessage = ForwardMessage | string | Uint8Array;
9
+ /** Builds a `text` forward message. */
10
+ export declare function text(data: string): ForwardMessage;
11
+ /** Builds a `json` forward message from a JSON-serializable value. */
12
+ export declare function json(data: unknown): ForwardMessage;
13
+ /** Builds a `binary` forward message. */
14
+ export declare function binary(data: Uint8Array): ForwardMessage;
15
+ /** The payload if this message is `text`, otherwise `undefined`. */
16
+ export declare function asText(message: ForwardMessage): string | undefined;
17
+ /** The payload if this message is `json`, otherwise `undefined`. `T` is an unchecked cast. */
18
+ export declare function asJson<T = unknown>(message: ForwardMessage): T | undefined;
19
+ /** The payload if this message is `binary`, otherwise `undefined`. */
20
+ export declare function asBinary(message: ForwardMessage): Uint8Array | undefined;
21
+ export declare function intoWire(message: SendableMessage): WireForwardMessage;
22
+ export declare function fromWire(message: WireForwardMessage): ForwardMessage;
23
+ //# sourceMappingURL=message.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../src/message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,YAAY,EAAE,cAAc,EAAE,CAAC;AAE/B;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,MAAM,GAAG,UAAU,CAAC;AAEnE,uCAAuC;AACvC,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAEjD;AAED,sEAAsE;AACtE,wBAAgB,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAElD;AAED,yCAAyC;AACzC,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,cAAc,CAEvD;AAED,oEAAoE;AACpE,wBAAgB,MAAM,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,GAAG,SAAS,CAElE;AAED,8FAA8F;AAC9F,wBAAgB,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,cAAc,GAAG,CAAC,GAAG,SAAS,CAE1E;AAED,sEAAsE;AACtE,wBAAgB,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,UAAU,GAAG,SAAS,CAExE;AAmBD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,kBAAkB,CAKrE;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,kBAAkB,GAAG,cAAc,CAGpE"}
@@ -0,0 +1,54 @@
1
+ /** Builds a `text` forward message. */
2
+ export function text(data) {
3
+ return { encoding: 'text', data };
4
+ }
5
+ /** Builds a `json` forward message from a JSON-serializable value. */
6
+ export function json(data) {
7
+ return { encoding: 'json', data };
8
+ }
9
+ /** Builds a `binary` forward message. */
10
+ export function binary(data) {
11
+ return { encoding: 'binary', data };
12
+ }
13
+ /** The payload if this message is `text`, otherwise `undefined`. */
14
+ export function asText(message) {
15
+ return message.encoding === 'text' ? message.data : undefined;
16
+ }
17
+ /** The payload if this message is `json`, otherwise `undefined`. `T` is an unchecked cast. */
18
+ export function asJson(message) {
19
+ return message.encoding === 'json' ? message.data : undefined;
20
+ }
21
+ /** The payload if this message is `binary`, otherwise `undefined`. */
22
+ export function asBinary(message) {
23
+ return message.encoding === 'binary' ? message.data : undefined;
24
+ }
25
+ const CHUNK = 0x8000;
26
+ function toBase64(bytes) {
27
+ let latin1 = '';
28
+ for (let i = 0; i < bytes.length; i += CHUNK) {
29
+ latin1 += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
30
+ }
31
+ return btoa(latin1);
32
+ }
33
+ function fromBase64(data) {
34
+ const latin1 = atob(data);
35
+ const bytes = new Uint8Array(latin1.length);
36
+ for (let i = 0; i < latin1.length; i++)
37
+ bytes[i] = latin1.charCodeAt(i);
38
+ return bytes;
39
+ }
40
+ export function intoWire(message) {
41
+ if (typeof message === 'string')
42
+ return { encoding: 'text', data: message };
43
+ if (message instanceof Uint8Array)
44
+ return { encoding: 'binary', data: toBase64(message) };
45
+ if (message.encoding === 'binary')
46
+ return { encoding: 'binary', data: toBase64(message.data) };
47
+ return message;
48
+ }
49
+ export function fromWire(message) {
50
+ if (message.encoding === 'binary')
51
+ return { encoding: 'binary', data: fromBase64(message.data) };
52
+ return message;
53
+ }
54
+ //# sourceMappingURL=message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.js","sourceRoot":"","sources":["../src/message.ts"],"names":[],"mappings":"AAWA,uCAAuC;AACvC,MAAM,UAAU,IAAI,CAAC,IAAY;IAC/B,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACpC,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,IAAI,CAAC,IAAa;IAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACpC,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,MAAM,CAAC,IAAgB;IACrC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,MAAM,CAAC,OAAuB;IAC5C,OAAO,OAAO,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAChE,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,MAAM,CAAc,OAAuB;IACzD,OAAO,OAAO,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAE,OAAO,CAAC,IAAU,CAAC,CAAC,CAAC,SAAS,CAAC;AACvE,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,QAAQ,CAAC,OAAuB;IAC9C,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAClE,CAAC;AAED,MAAM,KAAK,GAAG,MAAM,CAAC;AAErB,SAAS,QAAQ,CAAC,KAAiB;IACjC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC;QAC7C,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACxE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,OAAwB;IAC/C,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC5E,IAAI,OAAO,YAAY,UAAU;QAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;IAC1F,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;IAC/F,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,OAA2B;IAClD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;IACjG,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,115 @@
1
+ /** Host protocol revision this package speaks. The host refuses a mismatch. */
2
+ export declare const EXTENSION_API_VERSION = 1;
3
+ /** Severity accepted by `ctx.log`. */
4
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
5
+ /** Identity of the webapp this extension ships inside, as the host reports it. */
6
+ export type ExtensionWebapp = {
7
+ id: string;
8
+ name: string;
9
+ version: string;
10
+ };
11
+ /**
12
+ * `ForwardMessage` as it appears on stdio. The transport is JSON lines, so `binary` payloads
13
+ * are base64.
14
+ */
15
+ export type WireForwardMessage = {
16
+ encoding: 'text';
17
+ data: string;
18
+ } | {
19
+ encoding: 'json';
20
+ data: unknown;
21
+ } | {
22
+ encoding: 'binary';
23
+ data: string;
24
+ };
25
+ type NoFields = Record<never, never>;
26
+ /** Every `t` the host writes. `HostMessage` derives its arms from this list. */
27
+ export declare const HOST_MESSAGE_TYPES: readonly ["hello", "device.connected", "device.disconnected", "device.active", "device.message", "config.changed", "reply", "stop"];
28
+ export type HostMessageType = (typeof HOST_MESSAGE_TYPES)[number];
29
+ type HostPayloads = {
30
+ hello: {
31
+ api: number;
32
+ webapp: ExtensionWebapp;
33
+ dataDir: string;
34
+ };
35
+ 'device.connected': {
36
+ device: string;
37
+ name: string;
38
+ config: Record<string, string>;
39
+ active: boolean;
40
+ };
41
+ 'device.disconnected': {
42
+ device: string;
43
+ };
44
+ 'device.active': {
45
+ device: string;
46
+ active: boolean;
47
+ };
48
+ 'device.message': {
49
+ device: string;
50
+ message: WireForwardMessage;
51
+ };
52
+ 'config.changed': {
53
+ device: string;
54
+ key: string;
55
+ value: string | null;
56
+ };
57
+ reply: {
58
+ id: string;
59
+ ok: true;
60
+ value?: unknown;
61
+ } | {
62
+ id: string;
63
+ ok: false;
64
+ error: string;
65
+ };
66
+ stop: NoFields;
67
+ };
68
+ /** A line the host writes to the extension's stdin. */
69
+ export type HostMessage = {
70
+ [K in HostMessageType]: {
71
+ t: K;
72
+ } & HostPayloads[K];
73
+ }[HostMessageType];
74
+ /** Every `t` the extension writes. `ExtensionMessage` derives its arms from this list. */
75
+ export declare const EXTENSION_MESSAGE_TYPES: readonly ["device.send", "kv.get", "kv.set", "kv.delete", "kv.list", "auth.authorize", "log", "ready"];
76
+ export type ExtensionMessageType = (typeof EXTENSION_MESSAGE_TYPES)[number];
77
+ type ExtensionPayloads = {
78
+ 'device.send': {
79
+ device?: string;
80
+ message: WireForwardMessage;
81
+ };
82
+ 'kv.get': {
83
+ id: string;
84
+ key: string;
85
+ };
86
+ 'kv.set': {
87
+ id: string;
88
+ key: string;
89
+ value: unknown;
90
+ };
91
+ 'kv.delete': {
92
+ id: string;
93
+ key: string;
94
+ };
95
+ 'kv.list': {
96
+ id: string;
97
+ };
98
+ 'auth.authorize': {
99
+ id: string;
100
+ url: string;
101
+ };
102
+ log: {
103
+ level: LogLevel;
104
+ message: string;
105
+ };
106
+ ready: NoFields;
107
+ };
108
+ /** A line the extension writes to its stdout. */
109
+ export type ExtensionMessage = {
110
+ [K in ExtensionMessageType]: {
111
+ t: K;
112
+ } & ExtensionPayloads[K];
113
+ }[ExtensionMessageType];
114
+ export {};
115
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /** Host protocol revision this package speaks. The host refuses a mismatch. */
2
+ export const EXTENSION_API_VERSION = 1;
3
+ /** Every `t` the host writes. `HostMessage` derives its arms from this list. */
4
+ export const HOST_MESSAGE_TYPES = [
5
+ 'hello',
6
+ 'device.connected',
7
+ 'device.disconnected',
8
+ 'device.active',
9
+ 'device.message',
10
+ 'config.changed',
11
+ 'reply',
12
+ 'stop',
13
+ ];
14
+ /** Every `t` the extension writes. `ExtensionMessage` derives its arms from this list. */
15
+ export const EXTENSION_MESSAGE_TYPES = [
16
+ 'device.send',
17
+ 'kv.get',
18
+ 'kv.set',
19
+ 'kv.delete',
20
+ 'kv.list',
21
+ 'auth.authorize',
22
+ 'log',
23
+ 'ready',
24
+ ];
25
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAuBvC,gFAAgF;AAChF,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,OAAO;IACP,kBAAkB;IAClB,qBAAqB;IACrB,eAAe;IACf,gBAAgB;IAChB,gBAAgB;IAChB,OAAO;IACP,MAAM;CACE,CAAC;AAkBX,0FAA0F;AAC1F,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,aAAa;IACb,QAAQ;IACR,QAAQ;IACR,WAAW;IACX,SAAS;IACT,gBAAgB;IAChB,KAAK;IACL,OAAO;CACC,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { AuthBridge, ConfigListener, Device, DeviceListener, DeviceRef, ExtensionContext, ExtensionLog, ExtensionSpec, KvStore, MessageListener, Unsubscribe } from './context.js';
2
+ import { type ExtensionHost } from './host.js';
3
+ import { type SendableMessage } from './message.js';
4
+ import { type ExtensionWebapp } from './protocol.js';
5
+ export declare class ExtensionRuntime implements ExtensionContext {
6
+ private readonly spec;
7
+ private readonly host;
8
+ private readonly writer;
9
+ private readonly devices_;
10
+ private readonly pending;
11
+ private readonly onDevice;
12
+ private readonly onMessage;
13
+ private readonly onConfig;
14
+ private nextRequestId;
15
+ private started;
16
+ private finishing;
17
+ private settled;
18
+ private helloApi;
19
+ private helloWebapp;
20
+ private helloDataDir;
21
+ private reader;
22
+ constructor(spec: ExtensionSpec, host: ExtensionHost);
23
+ get api(): number;
24
+ get webapp(): ExtensionWebapp;
25
+ get dataDir(): string;
26
+ get devices(): readonly Device[];
27
+ device(id: string): Device;
28
+ broadcast(message: SendableMessage): void;
29
+ config(device: DeviceRef): Readonly<Record<string, string>>;
30
+ on(event: 'device', listener: DeviceListener): Unsubscribe;
31
+ on(event: 'message', listener: MessageListener): Unsubscribe;
32
+ on(event: 'config', listener: ConfigListener): Unsubscribe;
33
+ readonly kv: KvStore;
34
+ readonly auth: AuthBridge;
35
+ readonly log: ExtensionLog;
36
+ forward(device: string | undefined, message: SendableMessage): void;
37
+ run(): Promise<void>;
38
+ private ensure;
39
+ private parse;
40
+ private dispatch;
41
+ private begin;
42
+ private abortStart;
43
+ private announce;
44
+ private guard;
45
+ private emit;
46
+ private request;
47
+ private finish;
48
+ private shutdown;
49
+ }
50
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EACd,MAAM,EAEN,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,OAAO,EACP,eAAe,EACf,WAAW,EACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAyC,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AACtF,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAGL,KAAK,eAAe,EAGrB,MAAM,eAAe,CAAC;AAiCvB,qBAAa,gBAAiB,YAAW,gBAAgB;IAiBrD,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAjBvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiC;IAC1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IACtD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8B;IACxD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IACtD,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,WAAW,CAAsD;IACzE,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,MAAM,CAAsD;gBAGjD,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,aAAa;IAKtC,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED,IAAI,MAAM,IAAI,eAAe,CAE5B;IAED,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,OAAO,IAAI,SAAS,MAAM,EAAE,CAE/B;IAED,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAI1B,SAAS,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAIzC,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAK3D,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,GAAG,WAAW;IAC1D,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,GAAG,WAAW;IAC5D,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,GAAG,WAAW;IAiB1D,QAAQ,CAAC,EAAE,EAAE,OAAO,CAOlB;IAEF,QAAQ,CAAC,IAAI,EAAE,UAAU,CAGvB;IAEF,QAAQ,CAAC,GAAG,EAAE,YAAY,CAQxB;IAEF,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAK7D,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB1B,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,KAAK;IASb,OAAO,CAAC,QAAQ;IA6DhB,OAAO,CAAC,KAAK;IAgBb,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,KAAK;IASb,OAAO,CAAC,IAAI;IAMZ,OAAO,CAAC,OAAO;IAef,OAAO,CAAC,MAAM;YAKA,QAAQ;CAoBvB"}
@@ -0,0 +1,291 @@
1
+ import { ExtensionError, LineWriter, readLines } from './host.js';
2
+ import { fromWire, intoWire } from './message.js';
3
+ import { EXTENSION_API_VERSION, } from './protocol.js';
4
+ function describe(value) {
5
+ if (typeof value === 'string')
6
+ return value;
7
+ if (value instanceof Error)
8
+ return value.stack ?? `${value.name}: ${value.message}`;
9
+ try {
10
+ return JSON.stringify(value) ?? String(value);
11
+ }
12
+ catch {
13
+ return String(value);
14
+ }
15
+ }
16
+ class DeviceImpl {
17
+ id;
18
+ runtime;
19
+ name = '';
20
+ active = false;
21
+ connected = false;
22
+ config = {};
23
+ constructor(id, runtime) {
24
+ this.id = id;
25
+ this.runtime = runtime;
26
+ }
27
+ send(message) {
28
+ this.runtime.forward(this.id, message);
29
+ }
30
+ }
31
+ export class ExtensionRuntime {
32
+ spec;
33
+ host;
34
+ writer;
35
+ devices_ = new Map();
36
+ pending = new Map();
37
+ onDevice = new Set();
38
+ onMessage = new Set();
39
+ onConfig = new Set();
40
+ nextRequestId = 1;
41
+ started = false;
42
+ finishing;
43
+ settled;
44
+ helloApi = EXTENSION_API_VERSION;
45
+ helloWebapp = { id: '', name: '', version: '' };
46
+ helloDataDir = '';
47
+ reader;
48
+ constructor(spec, host) {
49
+ this.spec = spec;
50
+ this.host = host;
51
+ this.writer = new LineWriter(host.writable);
52
+ }
53
+ get api() {
54
+ return this.helloApi;
55
+ }
56
+ get webapp() {
57
+ return this.helloWebapp;
58
+ }
59
+ get dataDir() {
60
+ return this.helloDataDir;
61
+ }
62
+ get devices() {
63
+ return [...this.devices_.values()].filter(device => device.connected);
64
+ }
65
+ device(id) {
66
+ return this.ensure(id);
67
+ }
68
+ broadcast(message) {
69
+ this.forward(undefined, message);
70
+ }
71
+ config(device) {
72
+ const id = typeof device === 'string' ? device : device.id;
73
+ return this.devices_.get(id)?.config ?? {};
74
+ }
75
+ on(event, listener) {
76
+ if (event === 'device') {
77
+ const fn = listener;
78
+ this.onDevice.add(fn);
79
+ return () => this.onDevice.delete(fn);
80
+ }
81
+ if (event === 'message') {
82
+ const fn = listener;
83
+ this.onMessage.add(fn);
84
+ return () => this.onMessage.delete(fn);
85
+ }
86
+ const fn = listener;
87
+ this.onConfig.add(fn);
88
+ return () => this.onConfig.delete(fn);
89
+ }
90
+ kv = {
91
+ get: (key) => this.request(id => ({ t: 'kv.get', id, key })).then(value => (value === null ? undefined : value)),
92
+ set: (key, value) => this.request(id => ({ t: 'kv.set', id, key, value })).then(() => undefined),
93
+ delete: (key) => this.request(id => ({ t: 'kv.delete', id, key })).then(() => undefined),
94
+ list: () => this.request(id => ({ t: 'kv.list', id })).then(value => (value ?? [])),
95
+ };
96
+ auth = {
97
+ authorize: (url) => this.request(id => ({ t: 'auth.authorize', id, url })).then(value => String(value)),
98
+ };
99
+ log = {
100
+ debug: (...args) => this.log.log('debug', ...args),
101
+ info: (...args) => this.log.log('info', ...args),
102
+ warn: (...args) => this.log.log('warn', ...args),
103
+ error: (...args) => this.log.log('error', ...args),
104
+ log: (level, ...args) => {
105
+ this.emit({ t: 'log', level, message: args.map(describe).join(' ') });
106
+ },
107
+ };
108
+ forward(device, message) {
109
+ const wire = intoWire(message);
110
+ this.emit(device === undefined ? { t: 'device.send', message: wire } : { t: 'device.send', device, message: wire });
111
+ }
112
+ async run() {
113
+ this.reader = this.host.readable.getReader();
114
+ try {
115
+ for await (const line of readLines(this.reader)) {
116
+ const message = this.parse(line);
117
+ if (!message)
118
+ continue;
119
+ if (message.t === 'stop') {
120
+ await this.finish(0);
121
+ return;
122
+ }
123
+ this.dispatch(message);
124
+ }
125
+ }
126
+ catch (err) {
127
+ await this.finish(1, new ExtensionError(`stdin read failed: ${describe(err)}`, 'disconnected'));
128
+ return;
129
+ }
130
+ await this.finish(0);
131
+ }
132
+ ensure(id) {
133
+ const existing = this.devices_.get(id);
134
+ if (existing)
135
+ return existing;
136
+ const fresh = new DeviceImpl(id, this);
137
+ this.devices_.set(id, fresh);
138
+ return fresh;
139
+ }
140
+ parse(line) {
141
+ try {
142
+ return JSON.parse(line);
143
+ }
144
+ catch (err) {
145
+ this.log.error(`unparseable line from host: ${describe(err)}`);
146
+ return undefined;
147
+ }
148
+ }
149
+ dispatch(message) {
150
+ switch (message.t) {
151
+ case 'hello': {
152
+ this.helloApi = message.api;
153
+ this.helloWebapp = message.webapp;
154
+ this.helloDataDir = message.dataDir;
155
+ this.begin();
156
+ return;
157
+ }
158
+ case 'device.connected': {
159
+ const device = this.ensure(message.device);
160
+ device.name = message.name;
161
+ device.config = { ...message.config };
162
+ device.active = message.active;
163
+ device.connected = true;
164
+ this.announce({ type: 'connected', device });
165
+ return;
166
+ }
167
+ case 'device.disconnected': {
168
+ const device = this.devices_.get(message.device);
169
+ if (!device)
170
+ return;
171
+ device.connected = false;
172
+ device.active = false;
173
+ this.announce({ type: 'disconnected', device });
174
+ return;
175
+ }
176
+ case 'device.active': {
177
+ const device = this.ensure(message.device);
178
+ device.active = message.active;
179
+ this.announce({ type: 'active', device });
180
+ return;
181
+ }
182
+ case 'device.message': {
183
+ const device = this.ensure(message.device);
184
+ const forwarded = this.guard(() => fromWire(message.message));
185
+ if (!forwarded)
186
+ return;
187
+ for (const listener of [...this.onMessage])
188
+ this.guard(() => listener(device, forwarded));
189
+ return;
190
+ }
191
+ case 'config.changed': {
192
+ const device = this.ensure(message.device);
193
+ const next = { ...device.config };
194
+ if (message.value === null)
195
+ delete next[message.key];
196
+ else
197
+ next[message.key] = message.value;
198
+ device.config = next;
199
+ for (const listener of [...this.onConfig]) {
200
+ this.guard(() => listener(device, message.key, message.value));
201
+ }
202
+ return;
203
+ }
204
+ case 'reply': {
205
+ const waiting = this.pending.get(message.id);
206
+ if (!waiting)
207
+ return;
208
+ this.pending.delete(message.id);
209
+ if (message.ok)
210
+ waiting.resolve(message.value);
211
+ else
212
+ waiting.reject(new ExtensionError(message.error, 'host-error'));
213
+ return;
214
+ }
215
+ }
216
+ }
217
+ begin() {
218
+ if (this.started)
219
+ return;
220
+ this.started = true;
221
+ let starting;
222
+ try {
223
+ starting = this.spec.start(this);
224
+ }
225
+ catch (err) {
226
+ this.abortStart(err);
227
+ return;
228
+ }
229
+ void Promise.resolve(starting).then(() => this.emit({ t: 'ready' }), (err) => this.abortStart(err));
230
+ }
231
+ abortStart(err) {
232
+ this.log.error(`start failed: ${describe(err)}`);
233
+ void this.finish(1, new ExtensionError(describe(err), 'host-error'));
234
+ }
235
+ announce(event) {
236
+ for (const listener of [...this.onDevice])
237
+ this.guard(() => listener(event));
238
+ }
239
+ guard(run) {
240
+ try {
241
+ return run();
242
+ }
243
+ catch (err) {
244
+ this.log.error(describe(err));
245
+ return undefined;
246
+ }
247
+ }
248
+ emit(message) {
249
+ this.writer.write(message).catch((err) => {
250
+ void this.finish(1, new ExtensionError(`stdout write failed: ${describe(err)}`, 'write-failed'));
251
+ });
252
+ }
253
+ request(build) {
254
+ if (this.settled) {
255
+ const advice = 'kv and auth cannot be reached once shutdown has begun, so persist eagerly rather than from stop';
256
+ return Promise.reject(new ExtensionError(`${this.settled.message}; ${advice}`, this.settled.kind));
257
+ }
258
+ const id = String(this.nextRequestId++);
259
+ return new Promise((resolve, reject) => {
260
+ this.pending.set(id, { resolve, reject });
261
+ this.writer.write(build(id)).catch((err) => {
262
+ if (!this.pending.delete(id))
263
+ return;
264
+ reject(new ExtensionError(`stdout write failed: ${describe(err)}`, 'write-failed'));
265
+ });
266
+ });
267
+ }
268
+ finish(code, reason) {
269
+ this.finishing ??= this.shutdown(code, reason);
270
+ return this.finishing;
271
+ }
272
+ async shutdown(code, reason) {
273
+ const failure = reason ?? new ExtensionError('the host closed the connection', 'disconnected');
274
+ this.settled = failure;
275
+ await this.reader?.cancel().catch(() => undefined);
276
+ for (const waiting of [...this.pending.values()])
277
+ waiting.reject(failure);
278
+ this.pending.clear();
279
+ try {
280
+ await this.spec.stop?.();
281
+ }
282
+ catch (err) {
283
+ await this.writer
284
+ .write({ t: 'log', level: 'error', message: `stop failed: ${describe(err)}` })
285
+ .catch(() => undefined);
286
+ }
287
+ await this.writer.close();
288
+ this.host.exit(code);
289
+ }
290
+ }
291
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@bridgething/extension",
3
+ "version": "0.0.1",
4
+ "description": "The client a bridgething extension uses to reach Car Things, settings, storage, and the user's browser from its Deno process.",
5
+ "license": "MIT",
6
+ "author": "Joey Eamigh <55670930+JoeyEamigh@users.noreply.github.com> (https://github.com/JoeyEamigh)",
7
+ "homepage": "https://bridgething.com",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/JoeyEamigh/bridgething.git",
11
+ "directory": "packages/extension-ts"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/JoeyEamigh/bridgething/issues"
15
+ },
16
+ "keywords": ["bridgething", "spotify", "car-thing", "superbird", "extension", "deno"],
17
+ "publishConfig": {
18
+ "access": "public",
19
+ "registry": "https://registry.npmjs.org/"
20
+ },
21
+ "type": "module",
22
+ "types": "./dist/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "default": "./dist/index.js"
27
+ }
28
+ },
29
+ "files": ["dist"],
30
+ "scripts": {
31
+ "prebuild": "rm -rf dist",
32
+ "build": "tsc -p tsconfig.build.json",
33
+ "dev": "tsc -p tsconfig.build.json --watch",
34
+ "typecheck": "tsc --noEmit && deno check --no-config --sloppy-imports --import-map=import_map.json src/index.ts",
35
+ "test": "bun test",
36
+ "lint": "eslint ."
37
+ },
38
+ "dependencies": {
39
+ "@bridgething/lib": "0.11.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/bun": "^1.4.0"
43
+ },
44
+ "peerDependencies": {
45
+ "typescript": "^6.0.3"
46
+ }
47
+ }