@openruntime/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/README.md ADDED
@@ -0,0 +1 @@
1
+ readme
@@ -0,0 +1,12 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ export declare class BridgeHttpError extends Error {
3
+ readonly status: number;
4
+ readonly code: string;
5
+ constructor(status: number, code: string, message: string);
6
+ }
7
+ export declare function writeCorsHeaders(response: ServerResponse): void;
8
+ export declare function writeJson(response: ServerResponse, status: number, body: unknown): void;
9
+ export declare function writeError(response: ServerResponse, error: unknown): void;
10
+ export declare function readJson(request: IncomingMessage): Promise<unknown>;
11
+ export declare function getPathSegments(url: URL): string[];
12
+ //# sourceMappingURL=http-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-utils.d.ts","sourceRoot":"","sources":["../src/http-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjE,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1D;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAI/D;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAMvF;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAYzE;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,CAazE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,EAAE,CAElD"}
@@ -0,0 +1,51 @@
1
+ export class BridgeHttpError extends Error {
2
+ status;
3
+ code;
4
+ constructor(status, code, message) {
5
+ super(message);
6
+ this.status = status;
7
+ this.code = code;
8
+ }
9
+ }
10
+ export function writeCorsHeaders(response) {
11
+ response.setHeader("access-control-allow-origin", "*");
12
+ response.setHeader("access-control-allow-methods", "GET,POST,OPTIONS");
13
+ response.setHeader("access-control-allow-headers", "content-type");
14
+ }
15
+ export function writeJson(response, status, body) {
16
+ writeCorsHeaders(response);
17
+ response.writeHead(status, {
18
+ "content-type": "application/json; charset=utf-8"
19
+ });
20
+ response.end(`${JSON.stringify(body, null, 2)}\n`);
21
+ }
22
+ export function writeError(response, error) {
23
+ const httpError = error instanceof BridgeHttpError
24
+ ? error
25
+ : new BridgeHttpError(500, "internal_error", error instanceof Error ? error.message : String(error));
26
+ const body = {
27
+ error: {
28
+ message: httpError.message,
29
+ code: httpError.code
30
+ }
31
+ };
32
+ writeJson(response, httpError.status, body);
33
+ }
34
+ export async function readJson(request) {
35
+ const chunks = [];
36
+ for await (const chunk of request) {
37
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
38
+ }
39
+ if (chunks.length === 0)
40
+ return undefined;
41
+ try {
42
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
43
+ }
44
+ catch {
45
+ throw new BridgeHttpError(400, "invalid_json", "Request body must be valid JSON.");
46
+ }
47
+ }
48
+ export function getPathSegments(url) {
49
+ return url.pathname.split("/").filter(Boolean).map(decodeURIComponent);
50
+ }
51
+ //# sourceMappingURL=http-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-utils.js","sourceRoot":"","sources":["../src/http-utils.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,MAAM,CAAS;IACf,IAAI,CAAS;IAEtB,YAAY,MAAc,EAAE,IAAY,EAAE,OAAe;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,UAAU,gBAAgB,CAAC,QAAwB;IACvD,QAAQ,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;IACvD,QAAQ,CAAC,SAAS,CAAC,8BAA8B,EAAE,kBAAkB,CAAC,CAAC;IACvE,QAAQ,CAAC,SAAS,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAwB,EAAE,MAAc,EAAE,IAAa;IAC/E,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE;QACzB,cAAc,EAAE,iCAAiC;KAClD,CAAC,CAAC;IACH,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,QAAwB,EAAE,KAAc;IACjE,MAAM,SAAS,GAAG,KAAK,YAAY,eAAe;QAChD,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,IAAI,eAAe,CAAC,GAAG,EAAE,gBAAgB,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAEvG,MAAM,IAAI,GAAoB;QAC5B,KAAK,EAAE;YACL,OAAO,EAAE,SAAS,CAAC,OAAO;YAC1B,IAAI,EAAE,SAAS,CAAC,IAAI;SACrB;KACF,CAAC;IACF,SAAS,CAAC,QAAQ,EAAE,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAwB;IACrD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAE1C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,eAAe,CAAC,GAAG,EAAE,cAAc,EAAE,kCAAkC,CAAC,CAAC;IACrF,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAQ;IACtC,OAAO,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;AACzE,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const bridgePackageInfo: import("@openruntime/core").OpenRuntimePackageInfo;
2
+ export { createBridgeServer } from "./server.js";
3
+ export type { BridgeErrorBody, BridgeListenOptions, BridgeRuntimeInfo, BridgeRuntimeStatus, BridgeServer, BridgeServerAddress, CreateBridgeServerOptions } from "./types.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,oDAA0D,CAAC;AAEzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,mBAAmB,EACnB,yBAAyB,EAC1B,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import { createPackageInfo } from "@openruntime/core";
2
+ export const bridgePackageInfo = createPackageInfo("@openruntime/bridge", "page bridge");
3
+ export { createBridgeServer } from "./server.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,CAAC,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,qBAAqB,EAAE,aAAa,CAAC,CAAC;AAEzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { BridgeRuntimeCommandName, BridgeRuntimeQuery } from "@openruntime/core";
2
+ export declare function getCommandFromResource(resource: string): BridgeRuntimeCommandName | undefined;
3
+ export declare function parseRuntimeQuery(method: BridgeRuntimeCommandName, searchParams: URLSearchParams): BridgeRuntimeQuery | undefined;
4
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,kBAAkB,EAOnB,MAAM,mBAAmB,CAAC;AAE3B,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,wBAAwB,GAAG,SAAS,CAM7F;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,wBAAwB,EAChC,YAAY,EAAE,eAAe,GAC5B,kBAAkB,GAAG,SAAS,CAKhC"}
package/dist/query.js ADDED
@@ -0,0 +1,94 @@
1
+ export function getCommandFromResource(resource) {
2
+ if (resource === "targets")
3
+ return "getTargets";
4
+ if (resource === "snapshot")
5
+ return "getSnapshot";
6
+ if (resource === "events")
7
+ return "getEvents";
8
+ if (resource === "actions")
9
+ return "getActions";
10
+ return undefined;
11
+ }
12
+ export function parseRuntimeQuery(method, searchParams) {
13
+ if (method === "getTargets")
14
+ return parseTargetsQuery(searchParams);
15
+ if (method === "getSnapshot")
16
+ return parseSnapshotQuery(searchParams);
17
+ if (method === "getEvents")
18
+ return parseEventsQuery(searchParams);
19
+ return parseActionsQuery(searchParams);
20
+ }
21
+ function parseTargetsQuery(searchParams) {
22
+ const query = {};
23
+ setIfDefined(query, "id", getStringValues(searchParams, "id"));
24
+ setIfDefined(query, "type", getStringValues(searchParams, "type"));
25
+ setIfDefined(query, "source", getStringValues(searchParams, "source"));
26
+ setIfDefined(query, "status", getStringValues(searchParams, "status"));
27
+ setIfDefined(query, "query", getStringValue(searchParams, "query"));
28
+ return maybeQuery(query);
29
+ }
30
+ function parseSnapshotQuery(searchParams) {
31
+ const query = {};
32
+ setIfDefined(query, "id", getStringValues(searchParams, "id"));
33
+ setIfDefined(query, "type", getStringValues(searchParams, "type"));
34
+ setIfDefined(query, "source", getStringValues(searchParams, "source"));
35
+ setIfDefined(query, "status", getStringValues(searchParams, "status"));
36
+ setIfDefined(query, "query", getStringValue(searchParams, "query"));
37
+ return maybeQuery(query);
38
+ }
39
+ function parseEventsQuery(searchParams) {
40
+ const query = {};
41
+ setIfDefined(query, "since", getNumberValue(searchParams, "since"));
42
+ setIfDefined(query, "targetId", getStringValues(searchParams, "targetId") ?? getStringValues(searchParams, "target-id"));
43
+ setIfDefined(query, "actionName", getStringValues(searchParams, "actionName") ?? getStringValues(searchParams, "action"));
44
+ setIfDefined(query, "type", getStringValues(searchParams, "type"));
45
+ setIfDefined(query, "source", getStringValues(searchParams, "source"));
46
+ setIfDefined(query, "status", getStringValues(searchParams, "status"));
47
+ setIfDefined(query, "limit", getNumberValue(searchParams, "limit"));
48
+ setIfDefined(query, "query", getStringValue(searchParams, "query"));
49
+ return maybeQuery(query);
50
+ }
51
+ function parseActionsQuery(searchParams) {
52
+ const query = {};
53
+ setIfDefined(query, "name", getStringValues(searchParams, "name"));
54
+ setIfDefined(query, "source", getStringValues(searchParams, "source"));
55
+ setIfDefined(query, "risk", getStringValues(searchParams, "risk"));
56
+ setIfDefined(query, "enabled", getBooleanValue(searchParams, "enabled"));
57
+ setIfDefined(query, "query", getStringValue(searchParams, "query"));
58
+ return maybeQuery(query);
59
+ }
60
+ function getStringValue(searchParams, name) {
61
+ return searchParams.get(name) ?? undefined;
62
+ }
63
+ function getStringValues(searchParams, name) {
64
+ const values = searchParams.getAll(name);
65
+ if (values.length === 0)
66
+ return undefined;
67
+ return values.length === 1 ? values[0] : values;
68
+ }
69
+ function getNumberValue(searchParams, name) {
70
+ const value = searchParams.get(name);
71
+ if (value === null)
72
+ return undefined;
73
+ const number = Number(value);
74
+ return Number.isFinite(number) ? number : undefined;
75
+ }
76
+ function getBooleanValue(searchParams, name) {
77
+ const value = searchParams.get(name);
78
+ if (value === null)
79
+ return undefined;
80
+ if (value === "true")
81
+ return true;
82
+ if (value === "false")
83
+ return false;
84
+ return undefined;
85
+ }
86
+ function maybeQuery(query) {
87
+ return Object.keys(query).length === 0 ? undefined : query;
88
+ }
89
+ function setIfDefined(query, key, value) {
90
+ if (value !== undefined) {
91
+ query[key] = value;
92
+ }
93
+ }
94
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { BridgeRuntimeCommandName, BridgeServerRuntimeSyncPayload, BridgeRuntimeQuery, BridgeRuntimeRequest, BridgeRuntimeResponse } from "@openruntime/core";
2
+ import type { GetEventsResult, RuntimeActionDescriptor, RuntimeSnapshot, RuntimeTargetDescriptor } from "@openruntime/core";
3
+ import type { BridgeRuntimeInfo } from "./types.js";
4
+ export interface RuntimeStream {
5
+ send(event: string, data: unknown): void;
6
+ close(): void;
7
+ }
8
+ export declare class RuntimeConnectionStore {
9
+ #private;
10
+ constructor(options?: {
11
+ clock?: {
12
+ now(): number;
13
+ };
14
+ commandTimeout?: number;
15
+ idGenerator?: () => string;
16
+ });
17
+ connect(url: string, stream: RuntimeStream, options?: {
18
+ pageInstanceId?: string;
19
+ runtimeId?: string;
20
+ sessionId?: string;
21
+ renderId?: string;
22
+ }): BridgeRuntimeInfo;
23
+ syncServerRuntime(input: BridgeServerRuntimeSyncPayload): BridgeRuntimeInfo;
24
+ disconnect(runtimeId: string, stream: RuntimeStream): void;
25
+ disconnectAll(): void;
26
+ list(): BridgeRuntimeInfo[];
27
+ get(runtimeId: string): BridgeRuntimeInfo | undefined;
28
+ getCachedSnapshot(runtimeId: string): RuntimeSnapshot | undefined;
29
+ getCachedEvents(runtimeId: string, query?: BridgeRuntimeQuery): GetEventsResult | undefined;
30
+ getCachedTargets(runtimeId: string, query?: BridgeRuntimeQuery): RuntimeTargetDescriptor[] | undefined;
31
+ getCachedActions(runtimeId: string, query?: BridgeRuntimeQuery): RuntimeActionDescriptor[] | undefined;
32
+ hasCachedTarget(runtimeId: string, targetId: string): boolean;
33
+ cacheResult(runtimeId: string, method: BridgeRuntimeCommandName, result: unknown): void;
34
+ request(runtimeId: string, method: BridgeRuntimeCommandName, requestInput?: Omit<BridgeRuntimeRequest, "requestId" | "method">, timeout?: number): Promise<unknown>;
35
+ resolve(runtimeId: string, requestId: string, response: BridgeRuntimeResponse): boolean;
36
+ }
37
+ //# sourceMappingURL=runtime-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-store.d.ts","sourceRoot":"","sources":["../src/runtime-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,8BAA8B,EAC9B,kBAAkB,EAClB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAGV,eAAe,EAGf,uBAAuB,EACvB,eAAe,EACf,uBAAuB,EACxB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IACzC,KAAK,IAAI,IAAI,CAAC;CACf;AAuBD,qBAAa,sBAAsB;;gBAOrB,OAAO,GAAE;QACnB,KAAK,CAAC,EAAE;YAAE,GAAG,IAAI,MAAM,CAAA;SAAE,CAAC;QAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,MAAM,CAAC;KACvB;IAMN,OAAO,CACL,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE;QACP,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACd,GACL,iBAAiB;IAsCpB,iBAAiB,CAAC,KAAK,EAAE,8BAA8B,GAAG,iBAAiB;IA4C3E,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI;IAmB1D,aAAa,IAAI,IAAI;IAcrB,IAAI,IAAI,iBAAiB,EAAE;IAO3B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAKrD,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAIjE,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,kBAAkB,GAAG,eAAe,GAAG,SAAS;IAM3F,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,kBAAkB,GAAG,uBAAuB,EAAE,GAAG,SAAS;IAMtG,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,kBAAkB,GAAG,uBAAuB,EAAE,GAAG,SAAS;IAMtG,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAM7D,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,wBAAwB,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI;IAiBvF,OAAO,CACL,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,wBAAwB,EAChC,YAAY,GAAE,IAAI,CAAC,oBAAoB,EAAE,WAAW,GAAG,QAAQ,CAAM,EACrE,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC;IAgCnB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,qBAAqB,GAAG,OAAO;CA4BxF"}
@@ -0,0 +1,395 @@
1
+ import { BridgeHttpError } from "./http-utils.js";
2
+ export class RuntimeConnectionStore {
3
+ #runtimes = new Map();
4
+ #clock;
5
+ #commandTimeout;
6
+ #idGenerator;
7
+ #requestId = 0;
8
+ constructor(options = {}) {
9
+ this.#clock = options.clock ?? { now: () => Date.now() };
10
+ this.#commandTimeout = options.commandTimeout ?? 5000;
11
+ this.#idGenerator = options.idGenerator ?? (() => `runtime-${this.#clock.now().toString(36)}-${this.#runtimes.size + 1}`);
12
+ }
13
+ connect(url, stream, options = {}) {
14
+ const now = this.#clock.now();
15
+ const existing = options.runtimeId === undefined ? undefined : this.#runtimes.get(options.runtimeId);
16
+ if (existing !== undefined) {
17
+ const { disconnectedAt: _disconnectedAt, ...activeInfo } = existing.info;
18
+ existing.info = {
19
+ ...activeInfo,
20
+ url,
21
+ ...(options.sessionId === undefined ? {} : { sessionId: options.sessionId }),
22
+ ...(options.renderId === undefined ? {} : { renderId: options.renderId }),
23
+ ...(options.pageInstanceId === undefined ? {} : { pageInstanceId: options.pageInstanceId }),
24
+ status: "connected",
25
+ lastSeenAt: now
26
+ };
27
+ existing.stream = stream;
28
+ return { ...existing.info };
29
+ }
30
+ const info = {
31
+ runtimeId: options.runtimeId ?? this.#idGenerator(),
32
+ url,
33
+ ...(options.sessionId === undefined ? {} : { sessionId: options.sessionId }),
34
+ ...(options.renderId === undefined ? {} : { renderId: options.renderId }),
35
+ ...(options.pageInstanceId === undefined ? {} : { pageInstanceId: options.pageInstanceId }),
36
+ status: "connected",
37
+ connectedAt: now,
38
+ lastSeenAt: now
39
+ };
40
+ this.#runtimes.set(info.runtimeId, {
41
+ info,
42
+ stream,
43
+ pending: new Map()
44
+ });
45
+ return { ...info };
46
+ }
47
+ syncServerRuntime(input) {
48
+ const now = this.#clock.now();
49
+ const existing = this.#runtimes.get(input.runtimeId);
50
+ const existingInfo = existing?.info;
51
+ const { disconnectedAt: _disconnectedAt, ...activeInfo } = existingInfo ?? {
52
+ runtimeId: input.runtimeId,
53
+ connectedAt: now
54
+ };
55
+ const info = {
56
+ ...activeInfo,
57
+ url: input.url,
58
+ ...(input.sessionId === undefined ? {} : { sessionId: input.sessionId }),
59
+ ...(input.renderId === undefined ? {} : { renderId: input.renderId }),
60
+ ...(input.source === undefined ? {} : { source: input.source }),
61
+ status: existing?.stream === undefined ? "server" : "connected",
62
+ lastSeenAt: now
63
+ };
64
+ const record = existing ?? {
65
+ info,
66
+ pending: new Map()
67
+ };
68
+ record.info = info;
69
+ if (input.targets !== undefined) {
70
+ record.serverTargets = input.targets;
71
+ record.lastTargets = input.targets;
72
+ }
73
+ if (input.snapshot !== undefined) {
74
+ record.serverSnapshot = input.snapshot;
75
+ record.lastSnapshot = mergeSnapshots(input.snapshot, record.lastSnapshot) ?? input.snapshot;
76
+ }
77
+ if (input.events !== undefined) {
78
+ record.serverEvents = input.events;
79
+ record.lastEvents = mergeEvents(record.serverEvents, record.runtimeEvents) ?? input.events;
80
+ }
81
+ if (input.actions !== undefined) {
82
+ record.serverActions = input.actions;
83
+ record.lastActions = input.actions;
84
+ }
85
+ this.#runtimes.set(input.runtimeId, record);
86
+ return { ...record.info };
87
+ }
88
+ disconnect(runtimeId, stream) {
89
+ const runtime = this.#runtimes.get(runtimeId);
90
+ if (runtime === undefined || runtime.stream !== stream)
91
+ return;
92
+ delete runtime.stream;
93
+ runtime.info = {
94
+ ...runtime.info,
95
+ status: "disconnected",
96
+ disconnectedAt: this.#clock.now(),
97
+ lastSeenAt: this.#clock.now()
98
+ };
99
+ for (const [requestId, pending] of runtime.pending) {
100
+ clearTimeout(pending.timer);
101
+ pending.reject(createRuntimeDisconnectedError(`Runtime "${runtimeId}" disconnected before responding to request "${requestId}".`));
102
+ }
103
+ runtime.pending.clear();
104
+ }
105
+ disconnectAll() {
106
+ for (const runtime of this.#runtimes.values()) {
107
+ runtime.stream?.close();
108
+ delete runtime.stream;
109
+ runtime.info = {
110
+ ...runtime.info,
111
+ status: "disconnected",
112
+ disconnectedAt: this.#clock.now(),
113
+ lastSeenAt: this.#clock.now()
114
+ };
115
+ this.#rejectPending(runtime, createRuntimeDisconnectedError(`Runtime "${runtime.info.runtimeId}" disconnected.`));
116
+ }
117
+ }
118
+ list() {
119
+ return Array.from(this.#runtimes.values())
120
+ .filter((runtime) => runtime.info.status !== "disconnected")
121
+ .map((runtime) => ({ ...runtime.info }))
122
+ .sort((left, right) => right.lastSeenAt - left.lastSeenAt);
123
+ }
124
+ get(runtimeId) {
125
+ const runtime = this.#runtimes.get(runtimeId);
126
+ return runtime === undefined ? undefined : { ...runtime.info };
127
+ }
128
+ getCachedSnapshot(runtimeId) {
129
+ return this.#runtimes.get(runtimeId)?.lastSnapshot;
130
+ }
131
+ getCachedEvents(runtimeId, query) {
132
+ const events = this.#runtimes.get(runtimeId)?.lastEvents;
133
+ if (events === undefined)
134
+ return undefined;
135
+ return filterEvents(events, query);
136
+ }
137
+ getCachedTargets(runtimeId, query) {
138
+ const targets = this.#runtimes.get(runtimeId)?.lastTargets;
139
+ if (targets === undefined)
140
+ return undefined;
141
+ return filterTargets(targets, query);
142
+ }
143
+ getCachedActions(runtimeId, query) {
144
+ const actions = this.#runtimes.get(runtimeId)?.lastActions;
145
+ if (actions === undefined)
146
+ return undefined;
147
+ return filterActions(actions, query);
148
+ }
149
+ hasCachedTarget(runtimeId, targetId) {
150
+ const runtime = this.#runtimes.get(runtimeId);
151
+ return runtime?.lastSnapshot?.targets[targetId] !== undefined
152
+ || runtime?.lastTargets?.some((target) => target.id === targetId) === true;
153
+ }
154
+ cacheResult(runtimeId, method, result) {
155
+ const runtime = this.#runtimes.get(runtimeId);
156
+ if (runtime === undefined)
157
+ return;
158
+ if (method === "getSnapshot") {
159
+ const snapshot = result;
160
+ runtime.lastSnapshot = mergeSnapshots(runtime.serverSnapshot, snapshot) ?? snapshot;
161
+ }
162
+ else if (method === "getEvents") {
163
+ runtime.runtimeEvents = result;
164
+ runtime.lastEvents = mergeEvents(runtime.serverEvents, runtime.runtimeEvents) ?? runtime.runtimeEvents;
165
+ }
166
+ else if (method === "getTargets") {
167
+ runtime.lastTargets = mergeTargets(runtime.serverTargets, result);
168
+ }
169
+ else if (method === "getActions") {
170
+ runtime.lastActions = mergeActions(runtime.serverActions, result);
171
+ }
172
+ }
173
+ request(runtimeId, method, requestInput = {}, timeout) {
174
+ const runtime = this.#runtimes.get(runtimeId);
175
+ if (runtime === undefined) {
176
+ return Promise.reject(new Error(`Runtime "${runtimeId}" was not found.`));
177
+ }
178
+ if (runtime.stream === undefined || runtime.info.status !== "connected") {
179
+ return Promise.reject(new Error(`Runtime "${runtimeId}" is disconnected.`));
180
+ }
181
+ const requestId = `request-${this.#requestId += 1}`;
182
+ const request = {
183
+ requestId,
184
+ method,
185
+ ...requestInput
186
+ };
187
+ return new Promise((resolve, reject) => {
188
+ const timer = setTimeout(() => {
189
+ runtime.pending.delete(requestId);
190
+ reject(new Error(`Timed out waiting for runtime "${runtimeId}" to respond to "${method}".`));
191
+ }, timeout ?? this.#commandTimeout);
192
+ runtime.pending.set(requestId, {
193
+ resolve,
194
+ reject,
195
+ timer
196
+ });
197
+ runtime.stream?.send("request", request);
198
+ });
199
+ }
200
+ resolve(runtimeId, requestId, response) {
201
+ const runtime = this.#runtimes.get(runtimeId);
202
+ const pending = runtime?.pending.get(requestId);
203
+ if (runtime === undefined || pending === undefined)
204
+ return false;
205
+ clearTimeout(pending.timer);
206
+ runtime.pending.delete(requestId);
207
+ runtime.info = {
208
+ ...runtime.info,
209
+ lastSeenAt: this.#clock.now()
210
+ };
211
+ if (response.success) {
212
+ pending.resolve(response.result);
213
+ }
214
+ else {
215
+ pending.reject(new Error(response.error?.message ?? "Runtime request failed."));
216
+ }
217
+ return true;
218
+ }
219
+ #rejectPending(runtime, error) {
220
+ for (const pending of runtime.pending.values()) {
221
+ clearTimeout(pending.timer);
222
+ pending.reject(error);
223
+ }
224
+ runtime.pending.clear();
225
+ }
226
+ }
227
+ function createRuntimeDisconnectedError(message) {
228
+ return new BridgeHttpError(409, "runtime_disconnected", message);
229
+ }
230
+ function mergeSnapshots(serverSnapshot, runtimeSnapshot) {
231
+ if (serverSnapshot === undefined) {
232
+ return runtimeSnapshot;
233
+ }
234
+ if (runtimeSnapshot === undefined) {
235
+ return serverSnapshot;
236
+ }
237
+ return {
238
+ targets: {
239
+ ...serverSnapshot.targets,
240
+ ...runtimeSnapshot.targets
241
+ },
242
+ latestEventId: Math.max(serverSnapshot.latestEventId, runtimeSnapshot.latestEventId),
243
+ capturedAt: Math.max(serverSnapshot.capturedAt, runtimeSnapshot.capturedAt)
244
+ };
245
+ }
246
+ function mergeTargets(serverTargets, runtimeTargets) {
247
+ if (serverTargets === undefined || serverTargets.length === 0) {
248
+ return runtimeTargets;
249
+ }
250
+ const merged = new Map(serverTargets.map((target) => [target.id, target]));
251
+ for (const target of runtimeTargets) {
252
+ merged.set(target.id, target);
253
+ }
254
+ return [...merged.values()];
255
+ }
256
+ function mergeActions(serverActions, runtimeActions) {
257
+ if (serverActions === undefined || serverActions.length === 0) {
258
+ return runtimeActions;
259
+ }
260
+ const merged = new Map(serverActions.map((action) => [action.name, action]));
261
+ for (const action of runtimeActions) {
262
+ merged.set(action.name, action);
263
+ }
264
+ return [...merged.values()];
265
+ }
266
+ function mergeEvents(serverEvents, runtimeEvents) {
267
+ if (serverEvents === undefined) {
268
+ return runtimeEvents;
269
+ }
270
+ if (runtimeEvents === undefined) {
271
+ return serverEvents;
272
+ }
273
+ return {
274
+ events: mergeEventList(serverEvents.events, runtimeEvents.events),
275
+ latestEventId: Math.max(serverEvents.latestEventId, runtimeEvents.latestEventId),
276
+ truncated: serverEvents.truncated || runtimeEvents.truncated
277
+ };
278
+ }
279
+ function mergeEventList(serverEvents, runtimeEvents) {
280
+ const merged = new Map();
281
+ for (const event of [...serverEvents, ...runtimeEvents]) {
282
+ merged.set(getEventKey(event), event);
283
+ }
284
+ return [...merged.values()].sort((left, right) => {
285
+ if (left.timestamp !== right.timestamp)
286
+ return left.timestamp - right.timestamp;
287
+ return left.id - right.id;
288
+ });
289
+ }
290
+ function getEventKey(event) {
291
+ return [
292
+ event.source,
293
+ event.id,
294
+ event.timestamp,
295
+ event.type,
296
+ event.targetId ?? "",
297
+ event.actionName ?? "",
298
+ event.status ?? ""
299
+ ].join(":");
300
+ }
301
+ function filterTargets(targets, query) {
302
+ if (query === undefined)
303
+ return targets;
304
+ return targets.filter((target) => {
305
+ if (!matchesQueryValue(target.id, query.id))
306
+ return false;
307
+ if (!matchesQueryValue(target.type, query.type))
308
+ return false;
309
+ if (!matchesQueryValue(target.source, query.source))
310
+ return false;
311
+ if (query.query !== undefined && !target.id.includes(query.query) && !target.type.includes(query.query)) {
312
+ return false;
313
+ }
314
+ return true;
315
+ });
316
+ }
317
+ function filterActions(actions, query) {
318
+ if (query === undefined)
319
+ return actions;
320
+ return actions.filter((action) => {
321
+ if (!matchesQueryValue(action.source, query.source))
322
+ return false;
323
+ if (query.query !== undefined && !action.name.includes(query.query) && !action.description?.includes(query.query)) {
324
+ return false;
325
+ }
326
+ return true;
327
+ });
328
+ }
329
+ function filterEvents(result, query) {
330
+ if (query === undefined)
331
+ return result;
332
+ const filtered = result.events.filter((event) => matchesEvent(event, query));
333
+ const limit = normalizeLimit(query.limit);
334
+ const truncated = result.truncated || filtered.length > limit;
335
+ const events = truncated ? filtered.slice(filtered.length - limit) : filtered;
336
+ return {
337
+ events,
338
+ latestEventId: result.latestEventId,
339
+ truncated
340
+ };
341
+ }
342
+ function matchesEvent(event, query) {
343
+ if (query.since !== undefined && event.id <= query.since) {
344
+ return false;
345
+ }
346
+ return (matchesQueryValue(event.targetId, query.targetId) &&
347
+ matchesQueryValue(event.actionName, query.actionName) &&
348
+ matchesQueryValue(event.type, query.type) &&
349
+ matchesQueryValue(event.source, query.source) &&
350
+ matchesQueryValue(event.status, query.status) &&
351
+ matchesEventText(event, query.query));
352
+ }
353
+ function matchesEventText(event, query) {
354
+ if (query === undefined || query === "")
355
+ return true;
356
+ const normalizedQuery = query.toLowerCase();
357
+ return [
358
+ event.targetId,
359
+ event.actionName,
360
+ event.type,
361
+ event.source,
362
+ event.status,
363
+ event.error?.message,
364
+ event.error?.code,
365
+ event.error?.stack,
366
+ stringifySearchValue(event.error?.data),
367
+ stringifySearchValue(event.payload)
368
+ ].some((field) => field?.toLowerCase().includes(normalizedQuery) ?? false);
369
+ }
370
+ function stringifySearchValue(value) {
371
+ if (value === undefined)
372
+ return undefined;
373
+ if (typeof value === "string")
374
+ return value;
375
+ try {
376
+ return JSON.stringify(value);
377
+ }
378
+ catch {
379
+ return String(value);
380
+ }
381
+ }
382
+ function normalizeLimit(limit) {
383
+ if (limit === undefined || !Number.isFinite(limit) || limit < 1) {
384
+ return 100;
385
+ }
386
+ return Math.floor(limit);
387
+ }
388
+ function matchesQueryValue(value, expected) {
389
+ if (expected === undefined)
390
+ return true;
391
+ if (value === undefined)
392
+ return false;
393
+ return Array.isArray(expected) ? expected.includes(value) : value === expected;
394
+ }
395
+ //# sourceMappingURL=runtime-store.js.map