@triggery/devtools-bridge 0.1.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/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +43 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/package.json +72 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @triggery/devtools-bridge
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
First public preview release.
|
|
6
|
+
|
|
7
|
+
Page-side bridge for Triggery devtools — broadcasts runtime events over window.postMessage for the Chrome extension / standalone panel to consume
|
|
8
|
+
|
|
9
|
+
See the [repository-level CHANGELOG](../../CHANGELOG.md#010--2026-05-16) for the full set of packages and the umbrella feature list. Future entries on this file are appended automatically by changesets.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aleksey Skhomenko
|
|
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,43 @@
|
|
|
1
|
+
# @triggery/devtools-bridge
|
|
2
|
+
|
|
3
|
+
Page-side bridge that makes a Triggery runtime observable to external tools — the [Chrome extension](../../extensions/chrome-devtools), a future standalone web panel, custom inspectors, etc.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @triggery/devtools-bridge
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Use
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { createRuntime } from '@triggery/core';
|
|
15
|
+
import { installDevtoolsBridge } from '@triggery/devtools-bridge';
|
|
16
|
+
|
|
17
|
+
const runtime = createRuntime();
|
|
18
|
+
|
|
19
|
+
if (import.meta.env.DEV) {
|
|
20
|
+
installDevtoolsBridge(runtime);
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
That's it. The bridge:
|
|
25
|
+
|
|
26
|
+
1. Exposes a discovery handle on `window.__triggery_devtools__` so tools can detect the runtime.
|
|
27
|
+
2. Broadcasts a `triggery:hello` `postMessage` with the current `graph()` + inspector buffer.
|
|
28
|
+
3. Subscribes to the runtime and broadcasts a `triggery:snapshot` for every new run.
|
|
29
|
+
4. On `dispose()`, removes the discovery handle and broadcasts a `triggery:bye`.
|
|
30
|
+
|
|
31
|
+
In Node / SSR `installDevtoolsBridge` returns a no-op disposer.
|
|
32
|
+
|
|
33
|
+
## Wire format
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
{ source: 'triggery-devtools', type: 'triggery:hello', runtimeId, graph, buffer, at }
|
|
37
|
+
{ source: 'triggery-devtools', type: 'triggery:snapshot', runtimeId, snapshot, at }
|
|
38
|
+
{ source: 'triggery-devtools', type: 'triggery:bye', runtimeId, at }
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## License
|
|
42
|
+
|
|
43
|
+
MIT © Aleksey Skhomenko
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { RuntimeGraph, TriggerInspectSnapshot, Runtime } from '@triggery/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @triggery/devtools-bridge — make a runtime observable to external tools.
|
|
5
|
+
*
|
|
6
|
+
* Install once per runtime in DEV builds. The bridge:
|
|
7
|
+
* 1. Stamps a discovery object onto `window[globalKey]` so tools can
|
|
8
|
+
* detect that the page has Triggery running and read the runtime id.
|
|
9
|
+
* 2. Broadcasts an initial `triggery:hello` message with the current
|
|
10
|
+
* graph + inspector buffer (so a panel opened mid-session has data).
|
|
11
|
+
* 3. Subscribes to the runtime and broadcasts every new inspector
|
|
12
|
+
* snapshot as `triggery:snapshot`.
|
|
13
|
+
*
|
|
14
|
+
* Messages are sent via `window.postMessage(..., '*')` with a stable
|
|
15
|
+
* `source` field, which the Chrome extension's content script listens
|
|
16
|
+
* for. Same wire format works for a standalone WebSocket-backed panel
|
|
17
|
+
* (planned for V2).
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { createRuntime } from '@triggery/core';
|
|
22
|
+
* import { installDevtoolsBridge } from '@triggery/devtools-bridge';
|
|
23
|
+
*
|
|
24
|
+
* const runtime = createRuntime();
|
|
25
|
+
* if (import.meta.env.DEV) installDevtoolsBridge(runtime);
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** Default `source` used in the postMessage envelope. */
|
|
30
|
+
declare const DEVTOOLS_SOURCE = "triggery-devtools";
|
|
31
|
+
/** Default key on `window` for runtime discovery. */
|
|
32
|
+
declare const DEVTOOLS_GLOBAL_KEY = "__triggery_devtools__";
|
|
33
|
+
type DevtoolsBridgeOptions = {
|
|
34
|
+
/** Custom discovery key — only override if you need multiple bridges. */
|
|
35
|
+
readonly globalKey?: string;
|
|
36
|
+
/** Custom envelope `source` — must match what the consumer (extension) filters on. */
|
|
37
|
+
readonly source?: string;
|
|
38
|
+
};
|
|
39
|
+
/** Type of every message we publish. The extension content script switches on this. */
|
|
40
|
+
type DevtoolsMessage = {
|
|
41
|
+
readonly source: string;
|
|
42
|
+
readonly type: 'triggery:hello';
|
|
43
|
+
readonly runtimeId: string;
|
|
44
|
+
readonly graph: RuntimeGraph;
|
|
45
|
+
readonly buffer: readonly TriggerInspectSnapshot[];
|
|
46
|
+
readonly at: number;
|
|
47
|
+
} | {
|
|
48
|
+
readonly source: string;
|
|
49
|
+
readonly type: 'triggery:snapshot';
|
|
50
|
+
readonly runtimeId: string;
|
|
51
|
+
readonly snapshot: TriggerInspectSnapshot;
|
|
52
|
+
readonly at: number;
|
|
53
|
+
} | {
|
|
54
|
+
readonly source: string;
|
|
55
|
+
readonly type: 'triggery:bye';
|
|
56
|
+
readonly runtimeId: string;
|
|
57
|
+
readonly at: number;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Install the bridge. Returns a `dispose` function that unsubscribes and
|
|
61
|
+
* removes the discovery key — call it when the runtime itself goes away.
|
|
62
|
+
*
|
|
63
|
+
* Calling `installDevtoolsBridge` on a non-browser environment (Node, SSR)
|
|
64
|
+
* is safe — it returns a no-op disposer.
|
|
65
|
+
*/
|
|
66
|
+
declare function installDevtoolsBridge(runtime: Runtime, options?: DevtoolsBridgeOptions): () => void;
|
|
67
|
+
|
|
68
|
+
export { DEVTOOLS_GLOBAL_KEY, DEVTOOLS_SOURCE, type DevtoolsBridgeOptions, type DevtoolsMessage, installDevtoolsBridge };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var DEVTOOLS_SOURCE = "triggery-devtools";
|
|
3
|
+
var DEVTOOLS_GLOBAL_KEY = "__triggery_devtools__";
|
|
4
|
+
var getWindow = () => {
|
|
5
|
+
const g = globalThis;
|
|
6
|
+
return g.window;
|
|
7
|
+
};
|
|
8
|
+
function installDevtoolsBridge(runtime, options = {}) {
|
|
9
|
+
const win = getWindow();
|
|
10
|
+
if (!win) return () => {
|
|
11
|
+
};
|
|
12
|
+
const globalKey = options.globalKey ?? DEVTOOLS_GLOBAL_KEY;
|
|
13
|
+
const source = options.source ?? DEVTOOLS_SOURCE;
|
|
14
|
+
globalThis[globalKey] = {
|
|
15
|
+
runtime,
|
|
16
|
+
runtimeId: runtime.id,
|
|
17
|
+
source,
|
|
18
|
+
version: 1
|
|
19
|
+
};
|
|
20
|
+
win.postMessage(
|
|
21
|
+
{
|
|
22
|
+
source,
|
|
23
|
+
type: "triggery:hello",
|
|
24
|
+
runtimeId: runtime.id,
|
|
25
|
+
graph: runtime.graph(),
|
|
26
|
+
buffer: runtime.getInspectorBuffer(),
|
|
27
|
+
at: Date.now()
|
|
28
|
+
},
|
|
29
|
+
"*"
|
|
30
|
+
);
|
|
31
|
+
const token = runtime.subscribe((snapshot) => {
|
|
32
|
+
win.postMessage(
|
|
33
|
+
{
|
|
34
|
+
source,
|
|
35
|
+
type: "triggery:snapshot",
|
|
36
|
+
runtimeId: runtime.id,
|
|
37
|
+
snapshot,
|
|
38
|
+
at: Date.now()
|
|
39
|
+
},
|
|
40
|
+
"*"
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
let disposed = false;
|
|
44
|
+
return () => {
|
|
45
|
+
if (disposed) return;
|
|
46
|
+
disposed = true;
|
|
47
|
+
token.unregister();
|
|
48
|
+
delete globalThis[globalKey];
|
|
49
|
+
win.postMessage(
|
|
50
|
+
{
|
|
51
|
+
source,
|
|
52
|
+
type: "triggery:bye",
|
|
53
|
+
runtimeId: runtime.id,
|
|
54
|
+
at: Date.now()
|
|
55
|
+
},
|
|
56
|
+
"*"
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { DEVTOOLS_GLOBAL_KEY, DEVTOOLS_SOURCE, installDevtoolsBridge };
|
|
62
|
+
//# sourceMappingURL=index.js.map
|
|
63
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";AA6BO,IAAM,eAAA,GAAkB;AAExB,IAAM,mBAAA,GAAsB;AA0CnC,IAAM,YAAY,MAA8B;AAC9C,EAAA,MAAM,CAAA,GAAI,UAAA;AACV,EAAA,OAAO,CAAA,CAAE,MAAA;AACX,CAAA;AASO,SAAS,qBAAA,CACd,OAAA,EACA,OAAA,GAAiC,EAAC,EACtB;AACZ,EAAA,MAAM,MAAM,SAAA,EAAU;AACtB,EAAA,IAAI,CAAC,GAAA,EAAK,OAAO,MAAM;AAAA,EAAC,CAAA;AAExB,EAAA,MAAM,SAAA,GAAY,QAAQ,SAAA,IAAa,mBAAA;AACvC,EAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,IAAU,eAAA;AAKjC,EAAC,UAAA,CAA0B,SAAS,CAAA,GAAI;AAAA,IACtC,OAAA;AAAA,IACA,WAAW,OAAA,CAAQ,EAAA;AAAA,IACnB,MAAA;AAAA,IACA,OAAA,EAAS;AAAA,GACX;AAIA,EAAA,GAAA,CAAI,WAAA;AAAA,IACF;AAAA,MACE,MAAA;AAAA,MACA,IAAA,EAAM,gBAAA;AAAA,MACN,WAAW,OAAA,CAAQ,EAAA;AAAA,MACnB,KAAA,EAAO,QAAQ,KAAA,EAAM;AAAA,MACrB,MAAA,EAAQ,QAAQ,kBAAA,EAAmB;AAAA,MACnC,EAAA,EAAI,KAAK,GAAA;AAAI,KACf;AAAA,IACA;AAAA,GACF;AAGA,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,SAAA,CAAU,CAAC,QAAA,KAAa;AAC5C,IAAA,GAAA,CAAI,WAAA;AAAA,MACF;AAAA,QACE,MAAA;AAAA,QACA,IAAA,EAAM,mBAAA;AAAA,QACN,WAAW,OAAA,CAAQ,EAAA;AAAA,QACnB,QAAA;AAAA,QACA,EAAA,EAAI,KAAK,GAAA;AAAI,OACf;AAAA,MACA;AAAA,KACF;AAAA,EACF,CAAC,CAAA;AAED,EAAA,IAAI,QAAA,GAAW,KAAA;AACf,EAAA,OAAO,MAAM;AACX,IAAA,IAAI,QAAA,EAAU;AACd,IAAA,QAAA,GAAW,IAAA;AACX,IAAA,KAAA,CAAM,UAAA,EAAW;AACjB,IAAA,OAAQ,WAA0B,SAAS,CAAA;AAC3C,IAAA,GAAA,CAAI,WAAA;AAAA,MACF;AAAA,QACE,MAAA;AAAA,QACA,IAAA,EAAM,cAAA;AAAA,QACN,WAAW,OAAA,CAAQ,EAAA;AAAA,QACnB,EAAA,EAAI,KAAK,GAAA;AAAI,OACf;AAAA,MACA;AAAA,KACF;AAAA,EACF,CAAA;AACF","file":"index.js","sourcesContent":["/**\n * @triggery/devtools-bridge — make a runtime observable to external tools.\n *\n * Install once per runtime in DEV builds. The bridge:\n * 1. Stamps a discovery object onto `window[globalKey]` so tools can\n * detect that the page has Triggery running and read the runtime id.\n * 2. Broadcasts an initial `triggery:hello` message with the current\n * graph + inspector buffer (so a panel opened mid-session has data).\n * 3. Subscribes to the runtime and broadcasts every new inspector\n * snapshot as `triggery:snapshot`.\n *\n * Messages are sent via `window.postMessage(..., '*')` with a stable\n * `source` field, which the Chrome extension's content script listens\n * for. Same wire format works for a standalone WebSocket-backed panel\n * (planned for V2).\n *\n * @example\n * ```ts\n * import { createRuntime } from '@triggery/core';\n * import { installDevtoolsBridge } from '@triggery/devtools-bridge';\n *\n * const runtime = createRuntime();\n * if (import.meta.env.DEV) installDevtoolsBridge(runtime);\n * ```\n */\n\nimport type { Runtime, RuntimeGraph, TriggerInspectSnapshot } from '@triggery/core';\n\n/** Default `source` used in the postMessage envelope. */\nexport const DEVTOOLS_SOURCE = 'triggery-devtools';\n/** Default key on `window` for runtime discovery. */\nexport const DEVTOOLS_GLOBAL_KEY = '__triggery_devtools__';\n\nexport type DevtoolsBridgeOptions = {\n /** Custom discovery key — only override if you need multiple bridges. */\n readonly globalKey?: string;\n /** Custom envelope `source` — must match what the consumer (extension) filters on. */\n readonly source?: string;\n};\n\n/** Type of every message we publish. The extension content script switches on this. */\nexport type DevtoolsMessage =\n | {\n readonly source: string;\n readonly type: 'triggery:hello';\n readonly runtimeId: string;\n readonly graph: RuntimeGraph;\n readonly buffer: readonly TriggerInspectSnapshot[];\n readonly at: number;\n }\n | {\n readonly source: string;\n readonly type: 'triggery:snapshot';\n readonly runtimeId: string;\n readonly snapshot: TriggerInspectSnapshot;\n readonly at: number;\n }\n | {\n readonly source: string;\n readonly type: 'triggery:bye';\n readonly runtimeId: string;\n readonly at: number;\n };\n\ntype WindowLike = {\n postMessage(data: unknown, targetOrigin: string): void;\n};\n\ntype GlobalLike = {\n [key: string]: unknown;\n window?: WindowLike;\n};\n\nconst getWindow = (): WindowLike | undefined => {\n const g = globalThis as GlobalLike;\n return g.window;\n};\n\n/**\n * Install the bridge. Returns a `dispose` function that unsubscribes and\n * removes the discovery key — call it when the runtime itself goes away.\n *\n * Calling `installDevtoolsBridge` on a non-browser environment (Node, SSR)\n * is safe — it returns a no-op disposer.\n */\nexport function installDevtoolsBridge(\n runtime: Runtime,\n options: DevtoolsBridgeOptions = {},\n): () => void {\n const win = getWindow();\n if (!win) return () => {};\n\n const globalKey = options.globalKey ?? DEVTOOLS_GLOBAL_KEY;\n const source = options.source ?? DEVTOOLS_SOURCE;\n\n // Discovery handle for extension content scripts. Holds a reference to the\n // live runtime so tools that can reach the main world (e.g. injected\n // scripts) can subscribe directly without postMessage round-trips.\n (globalThis as GlobalLike)[globalKey] = {\n runtime,\n runtimeId: runtime.id,\n source,\n version: 1,\n };\n\n // Initial hello with the current graph + buffer so a panel opened mid-session\n // sees state immediately.\n win.postMessage(\n {\n source,\n type: 'triggery:hello',\n runtimeId: runtime.id,\n graph: runtime.graph(),\n buffer: runtime.getInspectorBuffer(),\n at: Date.now(),\n } satisfies DevtoolsMessage,\n '*',\n );\n\n // Per-event stream.\n const token = runtime.subscribe((snapshot) => {\n win.postMessage(\n {\n source,\n type: 'triggery:snapshot',\n runtimeId: runtime.id,\n snapshot,\n at: Date.now(),\n } satisfies DevtoolsMessage,\n '*',\n );\n });\n\n let disposed = false;\n return () => {\n if (disposed) return;\n disposed = true;\n token.unregister();\n delete (globalThis as GlobalLike)[globalKey];\n win.postMessage(\n {\n source,\n type: 'triggery:bye',\n runtimeId: runtime.id,\n at: Date.now(),\n } satisfies DevtoolsMessage,\n '*',\n );\n };\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@triggery/devtools-bridge",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Page-side bridge for Triggery devtools — broadcasts runtime events over window.postMessage for the Chrome extension / standalone panel to consume",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Aleksey Skhomenko",
|
|
7
|
+
"homepage": "https://triggeryjs.github.io/triggery",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/triggeryjs/triggery.git",
|
|
11
|
+
"directory": "packages/devtools-bridge"
|
|
12
|
+
},
|
|
13
|
+
"bugs": "https://github.com/triggeryjs/triggery/issues",
|
|
14
|
+
"funding": [
|
|
15
|
+
{
|
|
16
|
+
"type": "patreon",
|
|
17
|
+
"url": "https://www.patreon.com/triggery"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"type": "boosty",
|
|
21
|
+
"url": "https://boosty.to/triggery"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"keywords": [
|
|
25
|
+
"triggery",
|
|
26
|
+
"devtools",
|
|
27
|
+
"chrome-extension",
|
|
28
|
+
"bridge",
|
|
29
|
+
"inspector"
|
|
30
|
+
],
|
|
31
|
+
"type": "module",
|
|
32
|
+
"main": "./dist/index.js",
|
|
33
|
+
"module": "./dist/index.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"source": "./src/index.ts",
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"import": "./dist/index.js",
|
|
40
|
+
"default": "./dist/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./package.json": "./package.json"
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"dist",
|
|
46
|
+
"README.md",
|
|
47
|
+
"LICENSE",
|
|
48
|
+
"CHANGELOG.md"
|
|
49
|
+
],
|
|
50
|
+
"sideEffects": false,
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@triggery/core": "0.1.0"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"happy-dom": "^20.9.0",
|
|
59
|
+
"tsup": "^8.5.1",
|
|
60
|
+
"typescript": "^6.0.3",
|
|
61
|
+
"vitest": "^4.1.6",
|
|
62
|
+
"@triggery/core": "0.1.0"
|
|
63
|
+
},
|
|
64
|
+
"scripts": {
|
|
65
|
+
"build": "tsup",
|
|
66
|
+
"dev": "tsup --watch",
|
|
67
|
+
"test": "vitest run --passWithNoTests",
|
|
68
|
+
"test:watch": "vitest --passWithNoTests",
|
|
69
|
+
"test:coverage": "vitest run --coverage --passWithNoTests",
|
|
70
|
+
"clean": "rm -rf dist *.tsbuildinfo"
|
|
71
|
+
}
|
|
72
|
+
}
|