@iteraai/inspector-protocol 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 +137 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.js +40 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/origins.d.ts +4 -0
- package/dist/origins.js +20 -0
- package/dist/origins.js.map +1 -0
- package/dist/securityEvents.d.ts +8 -0
- package/dist/types.d.ts +159 -0
- package/dist/types.js +39 -0
- package/dist/types.js.map +1 -0
- package/dist/validators.d.ts +22 -0
- package/dist/validators.js +188 -0
- package/dist/validators.js.map +1 -0
- package/package.json +72 -0
package/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# `@iteraai/inspector-protocol`
|
|
2
|
+
|
|
3
|
+
Protocol constants, message builders, validators, origin helpers, and security event constants for the Itera component inspector SDK.
|
|
4
|
+
|
|
5
|
+
Use this package anywhere you need to speak the hosted editor protocol without pulling in the React runtime package: host/editor integrations, embedded message handlers, smoke fixtures, and protocol-aware tests.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @iteraai/inspector-protocol
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Before the first npm publish, use the workspace package or a packed tarball. The package name and import paths below are the supported public contract.
|
|
14
|
+
|
|
15
|
+
## Public Surface
|
|
16
|
+
|
|
17
|
+
| Import path | Purpose |
|
|
18
|
+
| ---------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
19
|
+
| `@iteraai/inspector-protocol` | Root constants, protocol/security event constants, message builders, validators, and origin helpers. |
|
|
20
|
+
| `@iteraai/inspector-protocol/types` | Message envelope, payload, tree, props, and placeholder types. |
|
|
21
|
+
| `@iteraai/inspector-protocol/errors` | Protocol error codes and error construction helpers. |
|
|
22
|
+
| `@iteraai/inspector-protocol/validators` | `buildMessage`, `parseMessage`, and `isInspectorMessage`. |
|
|
23
|
+
| `@iteraai/inspector-protocol/origins` | Origin normalization and iframe target-origin helpers. |
|
|
24
|
+
|
|
25
|
+
The root entrypoint also exports the current security event constants used by the React bridge runtime.
|
|
26
|
+
|
|
27
|
+
## Current Protocol Contract
|
|
28
|
+
|
|
29
|
+
Protocol constants:
|
|
30
|
+
|
|
31
|
+
- `INSPECTOR_CHANNEL` is `itera-component-inspector`
|
|
32
|
+
- `INSPECTOR_PROTOCOL_VERSION` is `1`
|
|
33
|
+
- Serializable placeholders use the `__iteraType` discriminator
|
|
34
|
+
|
|
35
|
+
Host-to-embedded message types:
|
|
36
|
+
|
|
37
|
+
- `HELLO`
|
|
38
|
+
- `REQUEST_TREE`
|
|
39
|
+
- `REQUEST_NODE_PROPS`
|
|
40
|
+
- `REQUEST_SNAPSHOT`
|
|
41
|
+
- `HIGHLIGHT_NODE`
|
|
42
|
+
- `CLEAR_HIGHLIGHT`
|
|
43
|
+
- `PING`
|
|
44
|
+
|
|
45
|
+
Embedded-to-host message types:
|
|
46
|
+
|
|
47
|
+
- `READY`
|
|
48
|
+
- `TREE_SNAPSHOT`
|
|
49
|
+
- `TREE_DELTA`
|
|
50
|
+
- `NODE_PROPS`
|
|
51
|
+
- `SNAPSHOT`
|
|
52
|
+
- `NODE_SELECTED`
|
|
53
|
+
- `PONG`
|
|
54
|
+
- `ERROR`
|
|
55
|
+
|
|
56
|
+
The branded channel name and placeholder discriminator are preserved intentionally for compatibility with the current `Web` integration.
|
|
57
|
+
|
|
58
|
+
## Quick Start
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import {
|
|
62
|
+
buildMessage,
|
|
63
|
+
parseMessage,
|
|
64
|
+
type InspectorMessage,
|
|
65
|
+
} from "@iteraai/inspector-protocol";
|
|
66
|
+
|
|
67
|
+
const helloMessage: InspectorMessage<"HELLO"> = buildMessage(
|
|
68
|
+
"HELLO",
|
|
69
|
+
{
|
|
70
|
+
capabilities: ["tree", "props", "highlight"],
|
|
71
|
+
auth: {
|
|
72
|
+
sessionToken: "signed-session-token",
|
|
73
|
+
metadata: {
|
|
74
|
+
expiresAt: Math.floor(Date.now() / 1000) + 300,
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
requestId: "request-1",
|
|
80
|
+
sessionId: "session-1",
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const iframe = document.querySelector("iframe");
|
|
85
|
+
|
|
86
|
+
iframe?.contentWindow?.postMessage(
|
|
87
|
+
helloMessage,
|
|
88
|
+
"https://preview.customer-app.example",
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
window.addEventListener("message", (event) => {
|
|
92
|
+
const parsed = parseMessage(event.data, {
|
|
93
|
+
sourceOrigin: event.origin,
|
|
94
|
+
trustedOrigins: ["https://preview.customer-app.example"],
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
if (!parsed.ok) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (parsed.message.type === "READY") {
|
|
102
|
+
console.log("Inspector handshake complete.");
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`requestId` and `sessionId` are envelope fields, not payload fields. The embedded bridge echoes them back in responses so the host can correlate request/response pairs.
|
|
108
|
+
|
|
109
|
+
## Origin Requirements
|
|
110
|
+
|
|
111
|
+
The protocol package does not decide which origins are trusted for your app, but it gives you the helpers needed to enforce that contract consistently.
|
|
112
|
+
|
|
113
|
+
- Pass `sourceOrigin` and `trustedOrigins` to `parseMessage` when validating inbound messages from `postMessage`.
|
|
114
|
+
- Trusted origins must match exact URL origins, including scheme and port.
|
|
115
|
+
- Use `normalizeOrigin` when you start from a full URL and need the origin only.
|
|
116
|
+
- Use `deriveTargetOriginFromIframeSrc` and `canHostSendToTargetOrigin` when the host needs to derive or verify the `postMessage` target origin for an iframe.
|
|
117
|
+
|
|
118
|
+
If origin validation fails, `parseMessage` returns `ERR_INVALID_ORIGIN`.
|
|
119
|
+
|
|
120
|
+
## Session Token Contract
|
|
121
|
+
|
|
122
|
+
The protocol shape for secure handshakes is carried in `HELLO.payload.auth`.
|
|
123
|
+
|
|
124
|
+
- `auth.sessionToken` is the required field used by secure embedded bridge integrations.
|
|
125
|
+
- The current embedded bridge expects that token to be a non-empty string.
|
|
126
|
+
- If `auth.metadata.expiresAt` is present and already expired, secure embedded bridges reject the handshake.
|
|
127
|
+
- `metadata` fields such as `tokenType`, `issuer`, `audience`, `issuedAt`, `expiresAt`, and `nonce` are part of the public protocol shape.
|
|
128
|
+
|
|
129
|
+
If you only need protocol parsing and message construction, this package does not enforce the token itself. Token validation happens in `@iteraai/react-component-inspector` when bridge security is enabled.
|
|
130
|
+
|
|
131
|
+
## Placeholder And Error Behavior
|
|
132
|
+
|
|
133
|
+
Customer-visible placeholder and error details are part of the protocol contract:
|
|
134
|
+
|
|
135
|
+
- `serializablePlaceholderTypes` includes `redacted`, `dom-node`, `date`, `error`, `map`, `set`, and other non-JSON-native value markers.
|
|
136
|
+
- `inspectorErrorCodes` includes origin, version, authorization, oversize-message, node-not-found, invalid-payload, and unknown-message-type failures.
|
|
137
|
+
- `INSPECTOR_SECURITY_EVENT_NAME_MESSAGE_REJECTED` and related root exports document the current security event naming contract used by the bridge runtime.
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const inspectorErrorCodes: readonly ["ERR_INVALID_ORIGIN", "ERR_UNSUPPORTED_VERSION", "ERR_UNAUTHORIZED_SESSION", "ERR_SECURITY_POLICY_REJECTED", "ERR_OVERSIZE_MESSAGE", "ERR_NODE_NOT_FOUND", "ERR_INVALID_MESSAGE", "ERR_INVALID_PAYLOAD", "ERR_UNKNOWN_MESSAGE_TYPE"];
|
|
2
|
+
export type InspectorErrorCode = (typeof inspectorErrorCodes)[number];
|
|
3
|
+
export declare const inspectorOversizeRejectionReasons: readonly ["host-inbound-message-too-large", "embedded-inbound-message-too-large"];
|
|
4
|
+
export type InspectorOversizeRejectionReason = (typeof inspectorOversizeRejectionReasons)[number];
|
|
5
|
+
export type InspectorProtocolError = {
|
|
6
|
+
code: InspectorErrorCode;
|
|
7
|
+
message: string;
|
|
8
|
+
details?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare const createInspectorProtocolError: (code: InspectorErrorCode, details?: string) => InspectorProtocolError;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const R = [
|
|
2
|
+
"ERR_INVALID_ORIGIN",
|
|
3
|
+
"ERR_UNSUPPORTED_VERSION",
|
|
4
|
+
"ERR_UNAUTHORIZED_SESSION",
|
|
5
|
+
"ERR_SECURITY_POLICY_REJECTED",
|
|
6
|
+
"ERR_OVERSIZE_MESSAGE",
|
|
7
|
+
"ERR_NODE_NOT_FOUND",
|
|
8
|
+
"ERR_INVALID_MESSAGE",
|
|
9
|
+
"ERR_INVALID_PAYLOAD",
|
|
10
|
+
"ERR_UNKNOWN_MESSAGE_TYPE"
|
|
11
|
+
], t = [
|
|
12
|
+
"host-inbound-message-too-large",
|
|
13
|
+
"embedded-inbound-message-too-large"
|
|
14
|
+
], E = {
|
|
15
|
+
ERR_INVALID_ORIGIN: "Message origin is not trusted.",
|
|
16
|
+
ERR_UNSUPPORTED_VERSION: "Protocol version is not supported.",
|
|
17
|
+
ERR_UNAUTHORIZED_SESSION: "Inspector session is not authorized.",
|
|
18
|
+
ERR_SECURITY_POLICY_REJECTED: "Message was rejected by inspector security policy.",
|
|
19
|
+
ERR_OVERSIZE_MESSAGE: "Message exceeds the allowed inspector size limit.",
|
|
20
|
+
ERR_NODE_NOT_FOUND: "Requested node was not found.",
|
|
21
|
+
ERR_INVALID_MESSAGE: "Message does not match protocol envelope.",
|
|
22
|
+
ERR_INVALID_PAYLOAD: "Message payload does not match type contract.",
|
|
23
|
+
ERR_UNKNOWN_MESSAGE_TYPE: "Message type is not recognized by protocol v1."
|
|
24
|
+
}, _ = (e, o) => {
|
|
25
|
+
const s = E[e];
|
|
26
|
+
return o === void 0 ? {
|
|
27
|
+
code: e,
|
|
28
|
+
message: s
|
|
29
|
+
} : {
|
|
30
|
+
code: e,
|
|
31
|
+
message: `${s} ${o}`,
|
|
32
|
+
details: o
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
export {
|
|
36
|
+
_ as createInspectorProtocolError,
|
|
37
|
+
R as inspectorErrorCodes,
|
|
38
|
+
t as inspectorOversizeRejectionReasons
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sources":["../src/errors.ts"],"sourcesContent":["export const inspectorErrorCodes = [\n 'ERR_INVALID_ORIGIN',\n 'ERR_UNSUPPORTED_VERSION',\n 'ERR_UNAUTHORIZED_SESSION',\n 'ERR_SECURITY_POLICY_REJECTED',\n 'ERR_OVERSIZE_MESSAGE',\n 'ERR_NODE_NOT_FOUND',\n 'ERR_INVALID_MESSAGE',\n 'ERR_INVALID_PAYLOAD',\n 'ERR_UNKNOWN_MESSAGE_TYPE',\n] as const;\n\nexport type InspectorErrorCode = (typeof inspectorErrorCodes)[number];\n\nexport const inspectorOversizeRejectionReasons = [\n 'host-inbound-message-too-large',\n 'embedded-inbound-message-too-large',\n] as const;\n\nexport type InspectorOversizeRejectionReason =\n (typeof inspectorOversizeRejectionReasons)[number];\n\nexport type InspectorProtocolError = {\n code: InspectorErrorCode;\n message: string;\n details?: string;\n};\n\nconst inspectorErrorMessages: Record<InspectorErrorCode, string> = {\n ERR_INVALID_ORIGIN: 'Message origin is not trusted.',\n ERR_UNSUPPORTED_VERSION: 'Protocol version is not supported.',\n ERR_UNAUTHORIZED_SESSION: 'Inspector session is not authorized.',\n ERR_SECURITY_POLICY_REJECTED:\n 'Message was rejected by inspector security policy.',\n ERR_OVERSIZE_MESSAGE: 'Message exceeds the allowed inspector size limit.',\n ERR_NODE_NOT_FOUND: 'Requested node was not found.',\n ERR_INVALID_MESSAGE: 'Message does not match protocol envelope.',\n ERR_INVALID_PAYLOAD: 'Message payload does not match type contract.',\n ERR_UNKNOWN_MESSAGE_TYPE: 'Message type is not recognized by protocol v1.',\n};\n\nexport const createInspectorProtocolError = (\n code: InspectorErrorCode,\n details?: string,\n): InspectorProtocolError => {\n const baseMessage = inspectorErrorMessages[code];\n\n if (details === undefined) {\n return {\n code,\n message: baseMessage,\n };\n }\n\n return {\n code,\n message: `${baseMessage} ${details}`,\n details,\n };\n};\n"],"names":["inspectorErrorCodes","inspectorOversizeRejectionReasons","inspectorErrorMessages","createInspectorProtocolError","code","details","baseMessage"],"mappings":"AAAO,MAAMA,IAAsB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAIaC,IAAoC;AAAA,EAC/C;AAAA,EACA;AACF,GAWMC,IAA6D;AAAA,EACjE,oBAAoB;AAAA,EACpB,yBAAyB;AAAA,EACzB,0BAA0B;AAAA,EAC1B,8BACE;AAAA,EACF,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,0BAA0B;AAC5B,GAEaC,IAA+B,CAC1CC,GACAC,MAC2B;AAC3B,QAAMC,IAAcJ,EAAuBE,CAAI;AAE/C,SAAIC,MAAY,SACP;AAAA,IACL,MAAAD;AAAA,IACA,SAASE;AAAA,EAAA,IAIN;AAAA,IACL,MAAAF;AAAA,IACA,SAAS,GAAGE,CAAW,IAAID,CAAO;AAAA,IAClC,SAAAA;AAAA,EAAA;AAEJ;"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createInspectorProtocolError as c, inspectorErrorCodes as E, inspectorOversizeRejectionReasons as d } from "./errors.js";
|
|
2
|
+
import { canHostSendToTargetOrigin as p, deriveTargetOriginFromIframeSrc as u, isOriginTrusted as R, normalizeOrigin as S } from "./origins.js";
|
|
3
|
+
import { INSPECTOR_CHANNEL as m, INSPECTOR_PROTOCOL_VERSION as O, embeddedToHostMessageTypes as _, hostToEmbeddedMessageTypes as C, serializablePlaceholderTypes as N } from "./types.js";
|
|
4
|
+
import { buildMessage as l, isInspectorMessage as y, parseMessage as z } from "./validators.js";
|
|
5
|
+
const o = 1, e = "itera.inspector.security.message_rejected", s = [
|
|
6
|
+
e
|
|
7
|
+
], i = [
|
|
8
|
+
"inbound-message-oversize",
|
|
9
|
+
"unauthorized-missing-auth",
|
|
10
|
+
"unauthorized-invalid-token",
|
|
11
|
+
"unauthorized-expired-token",
|
|
12
|
+
"security-policy-rejected",
|
|
13
|
+
"unknown-rejection-reason"
|
|
14
|
+
], n = (r) => "inbound-message-oversize";
|
|
15
|
+
export {
|
|
16
|
+
m as INSPECTOR_CHANNEL,
|
|
17
|
+
O as INSPECTOR_PROTOCOL_VERSION,
|
|
18
|
+
e as INSPECTOR_SECURITY_EVENT_NAME_MESSAGE_REJECTED,
|
|
19
|
+
o as INSPECTOR_SECURITY_EVENT_SCHEMA_VERSION,
|
|
20
|
+
l as buildMessage,
|
|
21
|
+
p as canHostSendToTargetOrigin,
|
|
22
|
+
c as createInspectorProtocolError,
|
|
23
|
+
u as deriveTargetOriginFromIframeSrc,
|
|
24
|
+
_ as embeddedToHostMessageTypes,
|
|
25
|
+
C as hostToEmbeddedMessageTypes,
|
|
26
|
+
E as inspectorErrorCodes,
|
|
27
|
+
d as inspectorOversizeRejectionReasons,
|
|
28
|
+
s as inspectorSecurityEventNames,
|
|
29
|
+
i as inspectorSecurityReasonCodes,
|
|
30
|
+
y as isInspectorMessage,
|
|
31
|
+
R as isOriginTrusted,
|
|
32
|
+
n as mapOversizeRejectionReasonToSecurityReasonCode,
|
|
33
|
+
S as normalizeOrigin,
|
|
34
|
+
z as parseMessage,
|
|
35
|
+
N as serializablePlaceholderTypes
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/securityEvents.ts"],"sourcesContent":["import type { InspectorOversizeRejectionReason } from './errors';\n\nexport const INSPECTOR_SECURITY_EVENT_SCHEMA_VERSION = 1 as const;\n\nexport const INSPECTOR_SECURITY_EVENT_NAME_MESSAGE_REJECTED =\n 'itera.inspector.security.message_rejected';\n\nexport const inspectorSecurityEventNames = [\n INSPECTOR_SECURITY_EVENT_NAME_MESSAGE_REJECTED,\n] as const;\n\nexport type InspectorSecurityEventName =\n (typeof inspectorSecurityEventNames)[number];\n\nexport const inspectorSecurityReasonCodes = [\n 'inbound-message-oversize',\n 'unauthorized-missing-auth',\n 'unauthorized-invalid-token',\n 'unauthorized-expired-token',\n 'security-policy-rejected',\n 'unknown-rejection-reason',\n] as const;\n\nexport type InspectorSecurityReasonCode =\n (typeof inspectorSecurityReasonCodes)[number];\n\nexport const mapOversizeRejectionReasonToSecurityReasonCode = (\n _reason: InspectorOversizeRejectionReason,\n): InspectorSecurityReasonCode => {\n return 'inbound-message-oversize';\n};\n"],"names":["INSPECTOR_SECURITY_EVENT_SCHEMA_VERSION","INSPECTOR_SECURITY_EVENT_NAME_MESSAGE_REJECTED","inspectorSecurityEventNames","inspectorSecurityReasonCodes","mapOversizeRejectionReasonToSecurityReasonCode","_reason"],"mappings":";;;;AAEO,MAAMA,IAA0C,GAE1CC,IACX,6CAEWC,IAA8B;AAAA,EACzCD;AACF,GAKaE,IAA+B;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKaC,IAAiD,CAC5DC,MAEO;"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const normalizeOrigin: (originOrUrl: string) => string | undefined;
|
|
2
|
+
export declare const deriveTargetOriginFromIframeSrc: (iframeSrc: string) => string | undefined;
|
|
3
|
+
export declare const isOriginTrusted: (origin: string, allowlist: readonly string[]) => boolean;
|
|
4
|
+
export declare const canHostSendToTargetOrigin: (iframeSrc: string, targetOrigin: string) => boolean;
|
package/dist/origins.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const i = (r) => {
|
|
2
|
+
try {
|
|
3
|
+
return new URL(r).origin;
|
|
4
|
+
} catch {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
}, c = (r) => i(r), o = (r) => i(r), s = (r, e) => {
|
|
8
|
+
const n = i(r);
|
|
9
|
+
return n === void 0 ? !1 : e.map((t) => i(t)).filter((t) => t !== void 0).includes(n);
|
|
10
|
+
}, a = (r, e) => {
|
|
11
|
+
const n = o(r);
|
|
12
|
+
return n === void 0 ? !1 : n === i(e);
|
|
13
|
+
};
|
|
14
|
+
export {
|
|
15
|
+
a as canHostSendToTargetOrigin,
|
|
16
|
+
o as deriveTargetOriginFromIframeSrc,
|
|
17
|
+
s as isOriginTrusted,
|
|
18
|
+
c as normalizeOrigin
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=origins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"origins.js","sources":["../src/origins.ts"],"sourcesContent":["const toOrigin = (rawOrigin: string): string | undefined => {\n try {\n return new URL(rawOrigin).origin;\n } catch {\n return undefined;\n }\n};\n\nexport const normalizeOrigin = (originOrUrl: string): string | undefined => {\n return toOrigin(originOrUrl);\n};\n\nexport const deriveTargetOriginFromIframeSrc = (\n iframeSrc: string,\n): string | undefined => {\n return toOrigin(iframeSrc);\n};\n\nexport const isOriginTrusted = (\n origin: string,\n allowlist: readonly string[],\n): boolean => {\n const normalizedOrigin = toOrigin(origin);\n\n if (normalizedOrigin === undefined) {\n return false;\n }\n\n return allowlist\n .map((item) => toOrigin(item))\n .filter((item): item is string => item !== undefined)\n .includes(normalizedOrigin);\n};\n\nexport const canHostSendToTargetOrigin = (\n iframeSrc: string,\n targetOrigin: string,\n): boolean => {\n const expectedTargetOrigin = deriveTargetOriginFromIframeSrc(iframeSrc);\n\n if (expectedTargetOrigin === undefined) {\n return false;\n }\n\n return expectedTargetOrigin === toOrigin(targetOrigin);\n};\n"],"names":["toOrigin","rawOrigin","normalizeOrigin","originOrUrl","deriveTargetOriginFromIframeSrc","iframeSrc","isOriginTrusted","origin","allowlist","normalizedOrigin","item","canHostSendToTargetOrigin","targetOrigin","expectedTargetOrigin"],"mappings":"AAAA,MAAMA,IAAW,CAACC,MAA0C;AAC1D,MAAI;AACF,WAAO,IAAI,IAAIA,CAAS,EAAE;AAAA,EAC5B,QAAQ;AACN;AAAA,EACF;AACF,GAEaC,IAAkB,CAACC,MACvBH,EAASG,CAAW,GAGhBC,IAAkC,CAC7CC,MAEOL,EAASK,CAAS,GAGdC,IAAkB,CAC7BC,GACAC,MACY;AACZ,QAAMC,IAAmBT,EAASO,CAAM;AAExC,SAAIE,MAAqB,SAChB,KAGFD,EACJ,IAAI,CAACE,MAASV,EAASU,CAAI,CAAC,EAC5B,OAAO,CAACA,MAAyBA,MAAS,MAAS,EACnD,SAASD,CAAgB;AAC9B,GAEaE,IAA4B,CACvCN,GACAO,MACY;AACZ,QAAMC,IAAuBT,EAAgCC,CAAS;AAEtE,SAAIQ,MAAyB,SACpB,KAGFA,MAAyBb,EAASY,CAAY;AACvD;"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { InspectorOversizeRejectionReason } from './errors';
|
|
2
|
+
export declare const INSPECTOR_SECURITY_EVENT_SCHEMA_VERSION: 1;
|
|
3
|
+
export declare const INSPECTOR_SECURITY_EVENT_NAME_MESSAGE_REJECTED = "itera.inspector.security.message_rejected";
|
|
4
|
+
export declare const inspectorSecurityEventNames: readonly ["itera.inspector.security.message_rejected"];
|
|
5
|
+
export type InspectorSecurityEventName = (typeof inspectorSecurityEventNames)[number];
|
|
6
|
+
export declare const inspectorSecurityReasonCodes: readonly ["inbound-message-oversize", "unauthorized-missing-auth", "unauthorized-invalid-token", "unauthorized-expired-token", "security-policy-rejected", "unknown-rejection-reason"];
|
|
7
|
+
export type InspectorSecurityReasonCode = (typeof inspectorSecurityReasonCodes)[number];
|
|
8
|
+
export declare const mapOversizeRejectionReasonToSecurityReasonCode: (_reason: InspectorOversizeRejectionReason) => InspectorSecurityReasonCode;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { InspectorErrorCode } from './errors';
|
|
2
|
+
export declare const INSPECTOR_CHANNEL = "itera-component-inspector";
|
|
3
|
+
export declare const INSPECTOR_PROTOCOL_VERSION = 1;
|
|
4
|
+
export type InspectorChannel = typeof INSPECTOR_CHANNEL;
|
|
5
|
+
export type InspectorProtocolVersion = typeof INSPECTOR_PROTOCOL_VERSION;
|
|
6
|
+
export declare const hostToEmbeddedMessageTypes: readonly ["HELLO", "REQUEST_TREE", "REQUEST_NODE_PROPS", "REQUEST_SNAPSHOT", "HIGHLIGHT_NODE", "CLEAR_HIGHLIGHT", "PING"];
|
|
7
|
+
export type HostToEmbeddedMessageType = (typeof hostToEmbeddedMessageTypes)[number];
|
|
8
|
+
export declare const embeddedToHostMessageTypes: readonly ["READY", "TREE_SNAPSHOT", "TREE_DELTA", "NODE_PROPS", "SNAPSHOT", "NODE_SELECTED", "PONG", "ERROR"];
|
|
9
|
+
export type EmbeddedToHostMessageType = (typeof embeddedToHostMessageTypes)[number];
|
|
10
|
+
export type InspectorMessageType = HostToEmbeddedMessageType | EmbeddedToHostMessageType;
|
|
11
|
+
export type TreeNodeSource = {
|
|
12
|
+
file: string;
|
|
13
|
+
line: number;
|
|
14
|
+
column?: number;
|
|
15
|
+
};
|
|
16
|
+
export type TreeNode = {
|
|
17
|
+
id: string;
|
|
18
|
+
displayName: string;
|
|
19
|
+
parentId: string | null;
|
|
20
|
+
childrenIds: string[];
|
|
21
|
+
source?: TreeNodeSource;
|
|
22
|
+
key?: string;
|
|
23
|
+
tags?: string[];
|
|
24
|
+
};
|
|
25
|
+
export declare const serializablePlaceholderTypes: readonly ["undefined", "function", "symbol", "bigint", "date", "regexp", "map", "set", "error", "dom-node", "redacted", "unserializable"];
|
|
26
|
+
export type SerializablePlaceholderType = (typeof serializablePlaceholderTypes)[number];
|
|
27
|
+
export type SerializablePlaceholder = {
|
|
28
|
+
__iteraType: SerializablePlaceholderType;
|
|
29
|
+
preview?: string;
|
|
30
|
+
};
|
|
31
|
+
export type SerializableScalar = string | number | boolean | null;
|
|
32
|
+
export type SerializableObject = {
|
|
33
|
+
[key: string]: SerializableValue;
|
|
34
|
+
};
|
|
35
|
+
export type SerializableValue = SerializableScalar | SerializableValue[] | SerializableObject | SerializablePlaceholder;
|
|
36
|
+
export type NodePropsMeta = {
|
|
37
|
+
truncated?: boolean;
|
|
38
|
+
droppedKeys?: string[];
|
|
39
|
+
redactedCount?: number;
|
|
40
|
+
redactedPaths?: string[];
|
|
41
|
+
};
|
|
42
|
+
export type NodeProps = {
|
|
43
|
+
nodeId: string;
|
|
44
|
+
props: Record<string, SerializableValue>;
|
|
45
|
+
meta: NodePropsMeta;
|
|
46
|
+
};
|
|
47
|
+
export type HelloPayload = {
|
|
48
|
+
capabilities?: string[];
|
|
49
|
+
auth?: HelloAuthPayload;
|
|
50
|
+
};
|
|
51
|
+
export type HelloAuthPayload = {
|
|
52
|
+
sessionToken: string;
|
|
53
|
+
metadata?: HelloAuthMetadata;
|
|
54
|
+
};
|
|
55
|
+
export type HelloAuthMetadata = {
|
|
56
|
+
tokenType?: string;
|
|
57
|
+
issuer?: string;
|
|
58
|
+
audience?: string | string[];
|
|
59
|
+
issuedAt?: number;
|
|
60
|
+
expiresAt?: number;
|
|
61
|
+
nonce?: string;
|
|
62
|
+
};
|
|
63
|
+
export type RequestTreePayload = {
|
|
64
|
+
includeSource?: boolean;
|
|
65
|
+
};
|
|
66
|
+
export type RequestNodePropsPayload = {
|
|
67
|
+
nodeId: string;
|
|
68
|
+
};
|
|
69
|
+
export type RequestSnapshotPayload = {
|
|
70
|
+
includeTree?: boolean;
|
|
71
|
+
includeHtml?: boolean;
|
|
72
|
+
};
|
|
73
|
+
export type HighlightNodePayload = {
|
|
74
|
+
nodeId: string;
|
|
75
|
+
};
|
|
76
|
+
export type PingPayload = {
|
|
77
|
+
sentAt?: number;
|
|
78
|
+
};
|
|
79
|
+
export type ReadyPayload = {
|
|
80
|
+
capabilities?: string[];
|
|
81
|
+
};
|
|
82
|
+
export type TreeSnapshotPayload = {
|
|
83
|
+
nodes: TreeNode[];
|
|
84
|
+
rootIds: string[];
|
|
85
|
+
meta?: TreeSnapshotMeta;
|
|
86
|
+
};
|
|
87
|
+
export type TreeSnapshotMeta = {
|
|
88
|
+
truncated?: boolean;
|
|
89
|
+
totalNodeCount?: number;
|
|
90
|
+
includedNodeCount?: number;
|
|
91
|
+
truncatedNodeCount?: number;
|
|
92
|
+
};
|
|
93
|
+
export type TreeDeltaPayload = {
|
|
94
|
+
addedNodes: TreeNode[];
|
|
95
|
+
updatedNodes: TreeNode[];
|
|
96
|
+
removedNodeIds: string[];
|
|
97
|
+
};
|
|
98
|
+
export type NodeSelectedPayload = {
|
|
99
|
+
nodeId: string;
|
|
100
|
+
};
|
|
101
|
+
export type SnapshotPayload = {
|
|
102
|
+
capture: Blob;
|
|
103
|
+
captureMimeType: string;
|
|
104
|
+
width: number;
|
|
105
|
+
height: number;
|
|
106
|
+
capturedAt: number;
|
|
107
|
+
treeSnapshot: TreeSnapshotPayload;
|
|
108
|
+
html?: string;
|
|
109
|
+
htmlTruncated?: boolean;
|
|
110
|
+
};
|
|
111
|
+
export type PongPayload = {
|
|
112
|
+
sentAt?: number;
|
|
113
|
+
};
|
|
114
|
+
export type ErrorPayload = {
|
|
115
|
+
code: InspectorErrorCode;
|
|
116
|
+
message: string;
|
|
117
|
+
details?: Record<string, SerializableValue>;
|
|
118
|
+
};
|
|
119
|
+
export type HostToEmbeddedPayloadByType = {
|
|
120
|
+
HELLO: HelloPayload;
|
|
121
|
+
REQUEST_TREE: RequestTreePayload;
|
|
122
|
+
REQUEST_NODE_PROPS: RequestNodePropsPayload;
|
|
123
|
+
REQUEST_SNAPSHOT: RequestSnapshotPayload;
|
|
124
|
+
HIGHLIGHT_NODE: HighlightNodePayload;
|
|
125
|
+
CLEAR_HIGHLIGHT: undefined;
|
|
126
|
+
PING: PingPayload;
|
|
127
|
+
};
|
|
128
|
+
export type EmbeddedToHostPayloadByType = {
|
|
129
|
+
READY: ReadyPayload;
|
|
130
|
+
TREE_SNAPSHOT: TreeSnapshotPayload;
|
|
131
|
+
TREE_DELTA: TreeDeltaPayload;
|
|
132
|
+
NODE_PROPS: NodeProps;
|
|
133
|
+
SNAPSHOT: SnapshotPayload;
|
|
134
|
+
NODE_SELECTED: NodeSelectedPayload;
|
|
135
|
+
PONG: PongPayload;
|
|
136
|
+
ERROR: ErrorPayload;
|
|
137
|
+
};
|
|
138
|
+
export type InspectorPayloadByType = HostToEmbeddedPayloadByType & EmbeddedToHostPayloadByType;
|
|
139
|
+
export type InspectorMessageEnvelope<TType extends InspectorMessageType, TPayload> = {
|
|
140
|
+
channel: InspectorChannel;
|
|
141
|
+
version: InspectorProtocolVersion;
|
|
142
|
+
type: TType;
|
|
143
|
+
requestId?: string;
|
|
144
|
+
sessionId?: string;
|
|
145
|
+
} & (TPayload extends undefined ? {
|
|
146
|
+
payload?: undefined;
|
|
147
|
+
} : {
|
|
148
|
+
payload: TPayload;
|
|
149
|
+
});
|
|
150
|
+
export type InspectorMessage<TType extends InspectorMessageType> = InspectorMessageEnvelope<TType, InspectorPayloadByType[TType]>;
|
|
151
|
+
export type AnyInspectorMessage = {
|
|
152
|
+
[Type in InspectorMessageType]: InspectorMessage<Type>;
|
|
153
|
+
}[InspectorMessageType];
|
|
154
|
+
export type HostToEmbeddedMessage = {
|
|
155
|
+
[Type in HostToEmbeddedMessageType]: InspectorMessage<Type>;
|
|
156
|
+
}[HostToEmbeddedMessageType];
|
|
157
|
+
export type EmbeddedToHostMessage = {
|
|
158
|
+
[Type in EmbeddedToHostMessageType]: InspectorMessage<Type>;
|
|
159
|
+
}[EmbeddedToHostMessageType];
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const e = "itera-component-inspector", E = 1, T = [
|
|
2
|
+
"HELLO",
|
|
3
|
+
"REQUEST_TREE",
|
|
4
|
+
"REQUEST_NODE_PROPS",
|
|
5
|
+
"REQUEST_SNAPSHOT",
|
|
6
|
+
"HIGHLIGHT_NODE",
|
|
7
|
+
"CLEAR_HIGHLIGHT",
|
|
8
|
+
"PING"
|
|
9
|
+
], o = [
|
|
10
|
+
"READY",
|
|
11
|
+
"TREE_SNAPSHOT",
|
|
12
|
+
"TREE_DELTA",
|
|
13
|
+
"NODE_PROPS",
|
|
14
|
+
"SNAPSHOT",
|
|
15
|
+
"NODE_SELECTED",
|
|
16
|
+
"PONG",
|
|
17
|
+
"ERROR"
|
|
18
|
+
], s = [
|
|
19
|
+
"undefined",
|
|
20
|
+
"function",
|
|
21
|
+
"symbol",
|
|
22
|
+
"bigint",
|
|
23
|
+
"date",
|
|
24
|
+
"regexp",
|
|
25
|
+
"map",
|
|
26
|
+
"set",
|
|
27
|
+
"error",
|
|
28
|
+
"dom-node",
|
|
29
|
+
"redacted",
|
|
30
|
+
"unserializable"
|
|
31
|
+
];
|
|
32
|
+
export {
|
|
33
|
+
e as INSPECTOR_CHANNEL,
|
|
34
|
+
E as INSPECTOR_PROTOCOL_VERSION,
|
|
35
|
+
o as embeddedToHostMessageTypes,
|
|
36
|
+
T as hostToEmbeddedMessageTypes,
|
|
37
|
+
s as serializablePlaceholderTypes
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sources":["../src/types.ts"],"sourcesContent":["import type { InspectorErrorCode } from './errors';\n\nexport const INSPECTOR_CHANNEL = 'itera-component-inspector';\nexport const INSPECTOR_PROTOCOL_VERSION = 1;\n\nexport type InspectorChannel = typeof INSPECTOR_CHANNEL;\nexport type InspectorProtocolVersion = typeof INSPECTOR_PROTOCOL_VERSION;\n\nexport const hostToEmbeddedMessageTypes = [\n 'HELLO',\n 'REQUEST_TREE',\n 'REQUEST_NODE_PROPS',\n 'REQUEST_SNAPSHOT',\n 'HIGHLIGHT_NODE',\n 'CLEAR_HIGHLIGHT',\n 'PING',\n] as const;\n\nexport type HostToEmbeddedMessageType =\n (typeof hostToEmbeddedMessageTypes)[number];\n\nexport const embeddedToHostMessageTypes = [\n 'READY',\n 'TREE_SNAPSHOT',\n 'TREE_DELTA',\n 'NODE_PROPS',\n 'SNAPSHOT',\n 'NODE_SELECTED',\n 'PONG',\n 'ERROR',\n] as const;\n\nexport type EmbeddedToHostMessageType =\n (typeof embeddedToHostMessageTypes)[number];\n\nexport type InspectorMessageType =\n | HostToEmbeddedMessageType\n | EmbeddedToHostMessageType;\n\nexport type TreeNodeSource = {\n file: string;\n line: number;\n column?: number;\n};\n\nexport type TreeNode = {\n id: string;\n displayName: string;\n parentId: string | null;\n childrenIds: string[];\n source?: TreeNodeSource;\n key?: string;\n tags?: string[];\n};\n\nexport const serializablePlaceholderTypes = [\n 'undefined',\n 'function',\n 'symbol',\n 'bigint',\n 'date',\n 'regexp',\n 'map',\n 'set',\n 'error',\n 'dom-node',\n 'redacted',\n 'unserializable',\n] as const;\n\nexport type SerializablePlaceholderType =\n (typeof serializablePlaceholderTypes)[number];\n\nexport type SerializablePlaceholder = {\n __iteraType: SerializablePlaceholderType;\n preview?: string;\n};\n\nexport type SerializableScalar = string | number | boolean | null;\n\nexport type SerializableObject = {\n [key: string]: SerializableValue;\n};\n\nexport type SerializableValue =\n | SerializableScalar\n | SerializableValue[]\n | SerializableObject\n | SerializablePlaceholder;\n\nexport type NodePropsMeta = {\n truncated?: boolean;\n droppedKeys?: string[];\n redactedCount?: number;\n redactedPaths?: string[];\n};\n\nexport type NodeProps = {\n nodeId: string;\n props: Record<string, SerializableValue>;\n meta: NodePropsMeta;\n};\n\nexport type HelloPayload = {\n capabilities?: string[];\n auth?: HelloAuthPayload;\n};\n\nexport type HelloAuthPayload = {\n sessionToken: string;\n metadata?: HelloAuthMetadata;\n};\n\nexport type HelloAuthMetadata = {\n tokenType?: string;\n issuer?: string;\n audience?: string | string[];\n issuedAt?: number;\n expiresAt?: number;\n nonce?: string;\n};\n\nexport type RequestTreePayload = {\n includeSource?: boolean;\n};\n\nexport type RequestNodePropsPayload = {\n nodeId: string;\n};\n\nexport type RequestSnapshotPayload = {\n includeTree?: boolean;\n includeHtml?: boolean;\n};\n\nexport type HighlightNodePayload = {\n nodeId: string;\n};\n\nexport type PingPayload = {\n sentAt?: number;\n};\n\nexport type ReadyPayload = {\n capabilities?: string[];\n};\n\nexport type TreeSnapshotPayload = {\n nodes: TreeNode[];\n rootIds: string[];\n meta?: TreeSnapshotMeta;\n};\n\nexport type TreeSnapshotMeta = {\n truncated?: boolean;\n totalNodeCount?: number;\n includedNodeCount?: number;\n truncatedNodeCount?: number;\n};\n\nexport type TreeDeltaPayload = {\n addedNodes: TreeNode[];\n updatedNodes: TreeNode[];\n removedNodeIds: string[];\n};\n\nexport type NodeSelectedPayload = {\n nodeId: string;\n};\n\nexport type SnapshotPayload = {\n capture: Blob;\n captureMimeType: string;\n width: number;\n height: number;\n capturedAt: number;\n treeSnapshot: TreeSnapshotPayload;\n html?: string;\n htmlTruncated?: boolean;\n};\n\nexport type PongPayload = {\n sentAt?: number;\n};\n\nexport type ErrorPayload = {\n code: InspectorErrorCode;\n message: string;\n details?: Record<string, SerializableValue>;\n};\n\nexport type HostToEmbeddedPayloadByType = {\n HELLO: HelloPayload;\n REQUEST_TREE: RequestTreePayload;\n REQUEST_NODE_PROPS: RequestNodePropsPayload;\n REQUEST_SNAPSHOT: RequestSnapshotPayload;\n HIGHLIGHT_NODE: HighlightNodePayload;\n CLEAR_HIGHLIGHT: undefined;\n PING: PingPayload;\n};\n\nexport type EmbeddedToHostPayloadByType = {\n READY: ReadyPayload;\n TREE_SNAPSHOT: TreeSnapshotPayload;\n TREE_DELTA: TreeDeltaPayload;\n NODE_PROPS: NodeProps;\n SNAPSHOT: SnapshotPayload;\n NODE_SELECTED: NodeSelectedPayload;\n PONG: PongPayload;\n ERROR: ErrorPayload;\n};\n\nexport type InspectorPayloadByType =\n HostToEmbeddedPayloadByType & EmbeddedToHostPayloadByType;\n\nexport type InspectorMessageEnvelope<\n TType extends InspectorMessageType,\n TPayload,\n> = {\n channel: InspectorChannel;\n version: InspectorProtocolVersion;\n type: TType;\n requestId?: string;\n sessionId?: string;\n} & (TPayload extends undefined ? { payload?: undefined } : { payload: TPayload });\n\nexport type InspectorMessage<TType extends InspectorMessageType> =\n InspectorMessageEnvelope<TType, InspectorPayloadByType[TType]>;\n\nexport type AnyInspectorMessage = {\n [Type in InspectorMessageType]: InspectorMessage<Type>;\n}[InspectorMessageType];\n\nexport type HostToEmbeddedMessage = {\n [Type in HostToEmbeddedMessageType]: InspectorMessage<Type>;\n}[HostToEmbeddedMessageType];\n\nexport type EmbeddedToHostMessage = {\n [Type in EmbeddedToHostMessageType]: InspectorMessage<Type>;\n}[EmbeddedToHostMessageType];\n"],"names":["INSPECTOR_CHANNEL","INSPECTOR_PROTOCOL_VERSION","hostToEmbeddedMessageTypes","embeddedToHostMessageTypes","serializablePlaceholderTypes"],"mappings":"AAEO,MAAMA,IAAoB,6BACpBC,IAA6B,GAK7BC,IAA6B;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKaC,IAA6B;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAyBaC,IAA+B;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { InspectorProtocolError } from './errors';
|
|
2
|
+
import { AnyInspectorMessage, InspectorMessage, InspectorMessageType, InspectorPayloadByType } from './types';
|
|
3
|
+
export type BuildMessageOptions = {
|
|
4
|
+
requestId?: string;
|
|
5
|
+
sessionId?: string;
|
|
6
|
+
};
|
|
7
|
+
export type ParseMessageOptions = {
|
|
8
|
+
sourceOrigin?: string;
|
|
9
|
+
trustedOrigins?: readonly string[];
|
|
10
|
+
expectedOrigin?: string;
|
|
11
|
+
supportedVersion?: number;
|
|
12
|
+
};
|
|
13
|
+
export type ParseMessageResult = {
|
|
14
|
+
ok: true;
|
|
15
|
+
message: AnyInspectorMessage;
|
|
16
|
+
} | {
|
|
17
|
+
ok: false;
|
|
18
|
+
error: InspectorProtocolError;
|
|
19
|
+
};
|
|
20
|
+
export declare const buildMessage: <Type extends InspectorMessageType>(type: Type, payload: InspectorPayloadByType[Type], options?: BuildMessageOptions) => InspectorMessage<Type>;
|
|
21
|
+
export declare const parseMessage: (raw: unknown, options?: ParseMessageOptions) => ParseMessageResult;
|
|
22
|
+
export declare const isInspectorMessage: (raw: unknown) => raw is AnyInspectorMessage;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { createInspectorProtocolError as n, inspectorErrorCodes as a } from "./errors.js";
|
|
2
|
+
import { normalizeOrigin as I, isOriginTrusted as p } from "./origins.js";
|
|
3
|
+
import { INSPECTOR_PROTOCOL_VERSION as A, INSPECTOR_CHANNEL as R, hostToEmbeddedMessageTypes as b, embeddedToHostMessageTypes as O, serializablePlaceholderTypes as S } from "./types.js";
|
|
4
|
+
const _ = /* @__PURE__ */ new Set([
|
|
5
|
+
...b,
|
|
6
|
+
...O
|
|
7
|
+
]), i = (e) => typeof e == "object" && e !== null && !Array.isArray(e), s = (e) => Array.isArray(e) && e.every((r) => typeof r == "string"), y = (e) => typeof e == "string" || s(e), d = (e) => typeof e == "number" && Number.isInteger(e) && e >= 0, m = (e) => typeof e == "number" && Number.isInteger(e) && e > 0, T = (e) => typeof e == "number" && Number.isFinite(e), h = (e) => !(!i(e) || e.tokenType !== void 0 && typeof e.tokenType != "string" || e.issuer !== void 0 && typeof e.issuer != "string" || e.audience !== void 0 && !y(e.audience) || e.issuedAt !== void 0 && typeof e.issuedAt != "number" || e.expiresAt !== void 0 && typeof e.expiresAt != "number" || e.nonce !== void 0 && typeof e.nonce != "string"), P = (e) => !(!i(e) || typeof e.sessionToken != "string" || e.metadata !== void 0 && !h(e.metadata)), L = (e) => !(typeof e.__iteraType != "string" || !S.includes(
|
|
8
|
+
e.__iteraType
|
|
9
|
+
) || e.preview !== void 0 && typeof e.preview != "string"), u = (e, r = 0) => r > 12 ? !1 : e === null || ["string", "number", "boolean"].includes(typeof e) ? !0 : Array.isArray(e) ? e.every((t) => u(t, r + 1)) : i(e) ? L(e) ? !0 : Object.values(e).every(
|
|
10
|
+
(t) => u(t, r + 1)
|
|
11
|
+
) : !1, c = (e) => !(!i(e) || typeof e.id != "string" || typeof e.displayName != "string" || !Array.isArray(e.childrenIds) || !e.childrenIds.every((r) => typeof r == "string") || e.parentId !== null && typeof e.parentId != "string" || e.source !== void 0 && (!i(e.source) || typeof e.source.file != "string" || typeof e.source.line != "number" || e.source.column !== void 0 && typeof e.source.column != "number") || e.key !== void 0 && typeof e.key != "string" || e.tags !== void 0 && !s(e.tags)), D = (e) => !(!i(e) || typeof e.nodeId != "string" || !i(e.props) || !Object.values(e.props).every((r) => u(r)) || !i(e.meta) || e.meta.truncated !== void 0 && typeof e.meta.truncated != "boolean" || e.meta.droppedKeys !== void 0 && !s(e.meta.droppedKeys) || e.meta.redactedCount !== void 0 && !d(e.meta.redactedCount) || e.meta.redactedPaths !== void 0 && !s(e.meta.redactedPaths)), M = (e) => !(!i(e) || e.truncated !== void 0 && typeof e.truncated != "boolean" || e.totalNodeCount !== void 0 && !d(e.totalNodeCount) || e.includedNodeCount !== void 0 && !d(e.includedNodeCount) || e.truncatedNodeCount !== void 0 && !d(e.truncatedNodeCount)), N = (e) => i(e) && Array.isArray(e.nodes) && e.nodes.every((r) => c(r)) && s(e.rootIds) && (e.meta === void 0 || M(e.meta)), G = (e) => typeof Blob < "u" && e instanceof Blob, H = (e) => e === "CLEAR_HIGHLIGHT", k = (e, r) => {
|
|
12
|
+
switch (e) {
|
|
13
|
+
case "HELLO":
|
|
14
|
+
return r === void 0 ? !0 : i(r) && (r.capabilities === void 0 || s(r.capabilities)) && (r.auth === void 0 || P(r.auth));
|
|
15
|
+
case "READY":
|
|
16
|
+
return r === void 0 ? !0 : i(r) && (r.capabilities === void 0 || s(r.capabilities));
|
|
17
|
+
case "REQUEST_TREE":
|
|
18
|
+
return r === void 0 ? !0 : i(r) && (r.includeSource === void 0 || typeof r.includeSource == "boolean");
|
|
19
|
+
case "REQUEST_SNAPSHOT":
|
|
20
|
+
return r === void 0 ? !0 : i(r) && (r.includeTree === void 0 || typeof r.includeTree == "boolean") && (r.includeHtml === void 0 || typeof r.includeHtml == "boolean");
|
|
21
|
+
case "REQUEST_NODE_PROPS":
|
|
22
|
+
case "HIGHLIGHT_NODE":
|
|
23
|
+
case "NODE_SELECTED":
|
|
24
|
+
return i(r) && typeof r.nodeId == "string";
|
|
25
|
+
case "CLEAR_HIGHLIGHT":
|
|
26
|
+
return r === void 0;
|
|
27
|
+
case "PING":
|
|
28
|
+
case "PONG":
|
|
29
|
+
return r === void 0 ? !0 : i(r) && (r.sentAt === void 0 || typeof r.sentAt == "number");
|
|
30
|
+
case "TREE_SNAPSHOT":
|
|
31
|
+
return N(r);
|
|
32
|
+
case "TREE_DELTA":
|
|
33
|
+
return i(r) && Array.isArray(r.addedNodes) && r.addedNodes.every((t) => c(t)) && Array.isArray(r.updatedNodes) && r.updatedNodes.every((t) => c(t)) && s(r.removedNodeIds);
|
|
34
|
+
case "NODE_PROPS":
|
|
35
|
+
return D(r);
|
|
36
|
+
case "SNAPSHOT":
|
|
37
|
+
return i(r) && G(r.capture) && typeof r.captureMimeType == "string" && m(r.width) && m(r.height) && T(r.capturedAt) && r.capturedAt >= 0 && N(r.treeSnapshot) && (r.html === void 0 || typeof r.html == "string") && (r.htmlTruncated === void 0 || typeof r.htmlTruncated == "boolean");
|
|
38
|
+
case "ERROR":
|
|
39
|
+
return i(r) && typeof r.code == "string" && a.includes(r.code) && typeof r.message == "string" && (r.details === void 0 || i(r.details) && Object.values(r.details).every(
|
|
40
|
+
(t) => u(t)
|
|
41
|
+
));
|
|
42
|
+
}
|
|
43
|
+
}, V = (e) => {
|
|
44
|
+
if (typeof e == "string")
|
|
45
|
+
try {
|
|
46
|
+
const r = JSON.parse(e);
|
|
47
|
+
return i(r) ? r : void 0;
|
|
48
|
+
} catch {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (i(e))
|
|
52
|
+
return e;
|
|
53
|
+
}, l = (e) => {
|
|
54
|
+
if (e.sourceOrigin === void 0)
|
|
55
|
+
return;
|
|
56
|
+
const r = I(e.sourceOrigin);
|
|
57
|
+
if (r === void 0)
|
|
58
|
+
return n(
|
|
59
|
+
"ERR_INVALID_ORIGIN",
|
|
60
|
+
`Source origin ${e.sourceOrigin} is not a valid URL origin.`
|
|
61
|
+
);
|
|
62
|
+
if (e.expectedOrigin !== void 0) {
|
|
63
|
+
const t = I(e.expectedOrigin);
|
|
64
|
+
if (t === void 0)
|
|
65
|
+
return n(
|
|
66
|
+
"ERR_INVALID_ORIGIN",
|
|
67
|
+
`Expected origin ${e.expectedOrigin} is not a valid URL origin.`
|
|
68
|
+
);
|
|
69
|
+
if (r !== t)
|
|
70
|
+
return n(
|
|
71
|
+
"ERR_INVALID_ORIGIN",
|
|
72
|
+
`Expected ${t} but received ${r}.`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (e.trustedOrigins !== void 0 && !p(r, e.trustedOrigins))
|
|
76
|
+
return n(
|
|
77
|
+
"ERR_INVALID_ORIGIN",
|
|
78
|
+
`Origin ${r} is not in host allowlist.`
|
|
79
|
+
);
|
|
80
|
+
}, U = (e, r, t = {}) => {
|
|
81
|
+
const o = {
|
|
82
|
+
channel: R,
|
|
83
|
+
version: A,
|
|
84
|
+
type: e,
|
|
85
|
+
requestId: t.requestId,
|
|
86
|
+
sessionId: t.sessionId
|
|
87
|
+
};
|
|
88
|
+
return r === void 0 ? o : {
|
|
89
|
+
...o,
|
|
90
|
+
payload: r
|
|
91
|
+
};
|
|
92
|
+
}, C = (e, r = {}) => {
|
|
93
|
+
const t = V(e);
|
|
94
|
+
if (t === void 0)
|
|
95
|
+
return {
|
|
96
|
+
ok: !1,
|
|
97
|
+
error: n(
|
|
98
|
+
"ERR_INVALID_MESSAGE",
|
|
99
|
+
"Incoming message must be an object or JSON string object."
|
|
100
|
+
)
|
|
101
|
+
};
|
|
102
|
+
const o = l(r);
|
|
103
|
+
if (o !== void 0)
|
|
104
|
+
return {
|
|
105
|
+
ok: !1,
|
|
106
|
+
error: o
|
|
107
|
+
};
|
|
108
|
+
if (t.channel !== R)
|
|
109
|
+
return {
|
|
110
|
+
ok: !1,
|
|
111
|
+
error: n(
|
|
112
|
+
"ERR_INVALID_MESSAGE",
|
|
113
|
+
`Invalid channel ${String(t.channel)}.`
|
|
114
|
+
)
|
|
115
|
+
};
|
|
116
|
+
if (typeof t.version != "number")
|
|
117
|
+
return {
|
|
118
|
+
ok: !1,
|
|
119
|
+
error: n(
|
|
120
|
+
"ERR_INVALID_MESSAGE",
|
|
121
|
+
"Message version must be a number."
|
|
122
|
+
)
|
|
123
|
+
};
|
|
124
|
+
const g = r.supportedVersion ?? A;
|
|
125
|
+
if (t.version !== g)
|
|
126
|
+
return {
|
|
127
|
+
ok: !1,
|
|
128
|
+
error: n(
|
|
129
|
+
"ERR_UNSUPPORTED_VERSION",
|
|
130
|
+
`Expected version ${g} but received ${t.version}.`
|
|
131
|
+
)
|
|
132
|
+
};
|
|
133
|
+
if (typeof t.type != "string")
|
|
134
|
+
return {
|
|
135
|
+
ok: !1,
|
|
136
|
+
error: n(
|
|
137
|
+
"ERR_INVALID_MESSAGE",
|
|
138
|
+
"Message type must be a string."
|
|
139
|
+
)
|
|
140
|
+
};
|
|
141
|
+
if (!_.has(t.type))
|
|
142
|
+
return {
|
|
143
|
+
ok: !1,
|
|
144
|
+
error: n(
|
|
145
|
+
"ERR_UNKNOWN_MESSAGE_TYPE",
|
|
146
|
+
`Message type ${t.type} is not part of protocol v1.`
|
|
147
|
+
)
|
|
148
|
+
};
|
|
149
|
+
if (t.requestId !== void 0 && typeof t.requestId != "string")
|
|
150
|
+
return {
|
|
151
|
+
ok: !1,
|
|
152
|
+
error: n(
|
|
153
|
+
"ERR_INVALID_MESSAGE",
|
|
154
|
+
"requestId must be a string when provided."
|
|
155
|
+
)
|
|
156
|
+
};
|
|
157
|
+
if (t.sessionId !== void 0 && typeof t.sessionId != "string")
|
|
158
|
+
return {
|
|
159
|
+
ok: !1,
|
|
160
|
+
error: n(
|
|
161
|
+
"ERR_INVALID_MESSAGE",
|
|
162
|
+
"sessionId must be a string when provided."
|
|
163
|
+
)
|
|
164
|
+
};
|
|
165
|
+
const f = t.type, E = t.payload;
|
|
166
|
+
return H(f) && E !== void 0 ? {
|
|
167
|
+
ok: !1,
|
|
168
|
+
error: n(
|
|
169
|
+
"ERR_INVALID_PAYLOAD",
|
|
170
|
+
`${f} does not accept a payload.`
|
|
171
|
+
)
|
|
172
|
+
} : k(f, E) ? {
|
|
173
|
+
ok: !0,
|
|
174
|
+
message: t
|
|
175
|
+
} : {
|
|
176
|
+
ok: !1,
|
|
177
|
+
error: n(
|
|
178
|
+
"ERR_INVALID_PAYLOAD",
|
|
179
|
+
`Payload does not satisfy ${f} contract.`
|
|
180
|
+
)
|
|
181
|
+
};
|
|
182
|
+
}, j = (e) => C(e).ok;
|
|
183
|
+
export {
|
|
184
|
+
U as buildMessage,
|
|
185
|
+
j as isInspectorMessage,
|
|
186
|
+
C as parseMessage
|
|
187
|
+
};
|
|
188
|
+
//# sourceMappingURL=validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.js","sources":["../src/validators.ts"],"sourcesContent":["import {\n createInspectorProtocolError,\n type InspectorProtocolError,\n inspectorErrorCodes,\n} from './errors';\nimport { isOriginTrusted, normalizeOrigin } from './origins';\nimport {\n embeddedToHostMessageTypes,\n hostToEmbeddedMessageTypes,\n INSPECTOR_CHANNEL,\n INSPECTOR_PROTOCOL_VERSION,\n serializablePlaceholderTypes,\n type AnyInspectorMessage,\n type InspectorMessage,\n type InspectorMessageType,\n type InspectorPayloadByType,\n type HelloAuthPayload,\n type NodeProps,\n type SerializablePlaceholder,\n type SerializableValue,\n type TreeNode,\n} from './types';\n\ntype RawMessage = Record<string, unknown>;\n\nexport type BuildMessageOptions = {\n requestId?: string;\n sessionId?: string;\n};\n\nexport type ParseMessageOptions = {\n sourceOrigin?: string;\n trustedOrigins?: readonly string[];\n expectedOrigin?: string;\n supportedVersion?: number;\n};\n\nexport type ParseMessageResult =\n | {\n ok: true;\n message: AnyInspectorMessage;\n }\n | {\n ok: false;\n error: InspectorProtocolError;\n };\n\nconst validMessageTypes = new Set<string>([\n ...hostToEmbeddedMessageTypes,\n ...embeddedToHostMessageTypes,\n]);\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n};\n\nconst isStringArray = (value: unknown): value is string[] => {\n return Array.isArray(value) && value.every((item) => typeof item === 'string');\n};\n\nconst isStringOrStringArray = (\n value: unknown,\n): value is string | string[] => {\n return typeof value === 'string' || isStringArray(value);\n};\n\nconst isNonNegativeInteger = (value: unknown): value is number => {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n};\n\nconst isPositiveInteger = (value: unknown): value is number => {\n return typeof value === 'number' && Number.isInteger(value) && value > 0;\n};\n\nconst isFiniteNumber = (value: unknown): value is number => {\n return typeof value === 'number' && Number.isFinite(value);\n};\n\nconst isHelloAuthMetadata = (value: unknown): boolean => {\n if (!isRecord(value)) {\n return false;\n }\n\n if (\n value.tokenType !== undefined &&\n typeof value.tokenType !== 'string'\n ) {\n return false;\n }\n\n if (\n value.issuer !== undefined &&\n typeof value.issuer !== 'string'\n ) {\n return false;\n }\n\n if (\n value.audience !== undefined &&\n !isStringOrStringArray(value.audience)\n ) {\n return false;\n }\n\n if (\n value.issuedAt !== undefined &&\n typeof value.issuedAt !== 'number'\n ) {\n return false;\n }\n\n if (\n value.expiresAt !== undefined &&\n typeof value.expiresAt !== 'number'\n ) {\n return false;\n }\n\n if (\n value.nonce !== undefined &&\n typeof value.nonce !== 'string'\n ) {\n return false;\n }\n\n return true;\n};\n\nconst isHelloAuthPayload = (value: unknown): value is HelloAuthPayload => {\n if (!isRecord(value)) {\n return false;\n }\n\n if (typeof value.sessionToken !== 'string') {\n return false;\n }\n\n if (\n value.metadata !== undefined &&\n !isHelloAuthMetadata(value.metadata)\n ) {\n return false;\n }\n\n return true;\n};\n\nconst isSerializablePlaceholder = (\n value: Record<string, unknown>,\n): value is SerializablePlaceholder => {\n if (typeof value.__iteraType !== 'string') {\n return false;\n }\n\n if (\n !(serializablePlaceholderTypes as readonly string[]).includes(\n value.__iteraType,\n )\n ) {\n return false;\n }\n\n if (\n value.preview !== undefined &&\n typeof value.preview !== 'string'\n ) {\n return false;\n }\n\n return true;\n};\n\nconst isSerializableValue = (\n value: unknown,\n depth = 0,\n): value is SerializableValue => {\n if (depth > 12) {\n return false;\n }\n\n if (value === null) {\n return true;\n }\n\n if (['string', 'number', 'boolean'].includes(typeof value)) {\n return true;\n }\n\n if (Array.isArray(value)) {\n return value.every((entry) => isSerializableValue(entry, depth + 1));\n }\n\n if (!isRecord(value)) {\n return false;\n }\n\n if (isSerializablePlaceholder(value)) {\n return true;\n }\n\n return Object.values(value).every((entry) =>\n isSerializableValue(entry, depth + 1),\n );\n};\n\nconst isTreeNode = (value: unknown): value is TreeNode => {\n if (!isRecord(value)) {\n return false;\n }\n\n if (\n typeof value.id !== 'string' ||\n typeof value.displayName !== 'string' ||\n !Array.isArray(value.childrenIds) ||\n !value.childrenIds.every((item) => typeof item === 'string')\n ) {\n return false;\n }\n\n if (value.parentId !== null && typeof value.parentId !== 'string') {\n return false;\n }\n\n if (value.source !== undefined) {\n if (!isRecord(value.source)) {\n return false;\n }\n\n if (\n typeof value.source.file !== 'string' ||\n typeof value.source.line !== 'number'\n ) {\n return false;\n }\n\n if (\n value.source.column !== undefined &&\n typeof value.source.column !== 'number'\n ) {\n return false;\n }\n }\n\n if (value.key !== undefined && typeof value.key !== 'string') {\n return false;\n }\n\n if (value.tags !== undefined && !isStringArray(value.tags)) {\n return false;\n }\n\n return true;\n};\n\nconst isNodeProps = (value: unknown): value is NodeProps => {\n if (!isRecord(value)) {\n return false;\n }\n\n if (typeof value.nodeId !== 'string') {\n return false;\n }\n\n if (!isRecord(value.props)) {\n return false;\n }\n\n if (!Object.values(value.props).every((entry) => isSerializableValue(entry))) {\n return false;\n }\n\n if (!isRecord(value.meta)) {\n return false;\n }\n\n if (\n value.meta.truncated !== undefined &&\n typeof value.meta.truncated !== 'boolean'\n ) {\n return false;\n }\n\n if (value.meta.droppedKeys !== undefined && !isStringArray(value.meta.droppedKeys)) {\n return false;\n }\n\n if (\n value.meta.redactedCount !== undefined &&\n !isNonNegativeInteger(value.meta.redactedCount)\n ) {\n return false;\n }\n\n if (\n value.meta.redactedPaths !== undefined &&\n !isStringArray(value.meta.redactedPaths)\n ) {\n return false;\n }\n\n return true;\n};\n\nconst isTreeSnapshotMeta = (value: unknown): boolean => {\n if (!isRecord(value)) {\n return false;\n }\n\n if (\n value.truncated !== undefined &&\n typeof value.truncated !== 'boolean'\n ) {\n return false;\n }\n\n if (\n value.totalNodeCount !== undefined &&\n !isNonNegativeInteger(value.totalNodeCount)\n ) {\n return false;\n }\n\n if (\n value.includedNodeCount !== undefined &&\n !isNonNegativeInteger(value.includedNodeCount)\n ) {\n return false;\n }\n\n if (\n value.truncatedNodeCount !== undefined &&\n !isNonNegativeInteger(value.truncatedNodeCount)\n ) {\n return false;\n }\n\n return true;\n};\n\nconst isTreeSnapshotPayload = (value: unknown): boolean => {\n return (\n isRecord(value) &&\n Array.isArray(value.nodes) &&\n value.nodes.every((node) => isTreeNode(node)) &&\n isStringArray(value.rootIds) &&\n (value.meta === undefined || isTreeSnapshotMeta(value.meta))\n );\n};\n\nconst isBlobValue = (value: unknown): value is Blob => {\n return typeof Blob !== 'undefined' && value instanceof Blob;\n};\n\nconst expectsNoPayload = (type: InspectorMessageType): boolean => {\n return type === 'CLEAR_HIGHLIGHT';\n};\n\nconst validatePayloadByType = (\n type: InspectorMessageType,\n payload: unknown,\n): boolean => {\n switch (type) {\n case 'HELLO': {\n if (payload === undefined) {\n return true;\n }\n\n return (\n isRecord(payload) &&\n (payload.capabilities === undefined ||\n isStringArray(payload.capabilities)) &&\n (payload.auth === undefined || isHelloAuthPayload(payload.auth))\n );\n }\n\n case 'READY': {\n if (payload === undefined) {\n return true;\n }\n\n return isRecord(payload) &&\n (payload.capabilities === undefined || isStringArray(payload.capabilities));\n }\n\n case 'REQUEST_TREE': {\n if (payload === undefined) {\n return true;\n }\n\n return (\n isRecord(payload) &&\n (payload.includeSource === undefined ||\n typeof payload.includeSource === 'boolean')\n );\n }\n\n case 'REQUEST_SNAPSHOT': {\n if (payload === undefined) {\n return true;\n }\n\n return (\n isRecord(payload) &&\n (payload.includeTree === undefined ||\n typeof payload.includeTree === 'boolean') &&\n (payload.includeHtml === undefined ||\n typeof payload.includeHtml === 'boolean')\n );\n }\n\n case 'REQUEST_NODE_PROPS':\n case 'HIGHLIGHT_NODE':\n case 'NODE_SELECTED': {\n return isRecord(payload) && typeof payload.nodeId === 'string';\n }\n\n case 'CLEAR_HIGHLIGHT': {\n return payload === undefined;\n }\n\n case 'PING':\n case 'PONG': {\n if (payload === undefined) {\n return true;\n }\n\n return isRecord(payload) &&\n (payload.sentAt === undefined || typeof payload.sentAt === 'number');\n }\n\n case 'TREE_SNAPSHOT': {\n return isTreeSnapshotPayload(payload);\n }\n\n case 'TREE_DELTA': {\n return (\n isRecord(payload) &&\n Array.isArray(payload.addedNodes) &&\n payload.addedNodes.every((node) => isTreeNode(node)) &&\n Array.isArray(payload.updatedNodes) &&\n payload.updatedNodes.every((node) => isTreeNode(node)) &&\n isStringArray(payload.removedNodeIds)\n );\n }\n\n case 'NODE_PROPS': {\n return isNodeProps(payload);\n }\n\n case 'SNAPSHOT': {\n return (\n isRecord(payload) &&\n isBlobValue(payload.capture) &&\n typeof payload.captureMimeType === 'string' &&\n isPositiveInteger(payload.width) &&\n isPositiveInteger(payload.height) &&\n isFiniteNumber(payload.capturedAt) &&\n payload.capturedAt >= 0 &&\n isTreeSnapshotPayload(payload.treeSnapshot) &&\n (payload.html === undefined || typeof payload.html === 'string') &&\n (payload.htmlTruncated === undefined ||\n typeof payload.htmlTruncated === 'boolean')\n );\n }\n\n case 'ERROR': {\n return (\n isRecord(payload) &&\n typeof payload.code === 'string' &&\n (inspectorErrorCodes as readonly string[]).includes(payload.code) &&\n typeof payload.message === 'string' &&\n (payload.details === undefined ||\n (isRecord(payload.details) &&\n Object.values(payload.details).every((value) =>\n isSerializableValue(value),\n )))\n );\n }\n }\n};\n\nconst toRawMessage = (raw: unknown): RawMessage | undefined => {\n if (typeof raw === 'string') {\n try {\n const parsed = JSON.parse(raw) as unknown;\n\n if (!isRecord(parsed)) {\n return undefined;\n }\n\n return parsed;\n } catch {\n return undefined;\n }\n }\n\n if (!isRecord(raw)) {\n return undefined;\n }\n\n return raw;\n};\n\nconst validateOrigin = (\n options: ParseMessageOptions,\n): InspectorProtocolError | undefined => {\n if (options.sourceOrigin === undefined) {\n return undefined;\n }\n\n const normalizedSourceOrigin = normalizeOrigin(options.sourceOrigin);\n\n if (normalizedSourceOrigin === undefined) {\n return createInspectorProtocolError(\n 'ERR_INVALID_ORIGIN',\n `Source origin ${options.sourceOrigin} is not a valid URL origin.`,\n );\n }\n\n if (\n options.expectedOrigin !== undefined\n ) {\n const normalizedExpectedOrigin = normalizeOrigin(options.expectedOrigin);\n\n if (normalizedExpectedOrigin === undefined) {\n return createInspectorProtocolError(\n 'ERR_INVALID_ORIGIN',\n `Expected origin ${options.expectedOrigin} is not a valid URL origin.`,\n );\n }\n\n if (normalizedSourceOrigin !== normalizedExpectedOrigin) {\n return createInspectorProtocolError(\n 'ERR_INVALID_ORIGIN',\n `Expected ${normalizedExpectedOrigin} but received ${normalizedSourceOrigin}.`,\n );\n }\n }\n\n if (\n options.trustedOrigins !== undefined &&\n !isOriginTrusted(normalizedSourceOrigin, options.trustedOrigins)\n ) {\n return createInspectorProtocolError(\n 'ERR_INVALID_ORIGIN',\n `Origin ${normalizedSourceOrigin} is not in host allowlist.`,\n );\n }\n\n return undefined;\n};\n\nexport const buildMessage = <Type extends InspectorMessageType>(\n type: Type,\n payload: InspectorPayloadByType[Type],\n options: BuildMessageOptions = {},\n): InspectorMessage<Type> => {\n const baseEnvelope = {\n channel: INSPECTOR_CHANNEL,\n version: INSPECTOR_PROTOCOL_VERSION,\n type,\n requestId: options.requestId,\n sessionId: options.sessionId,\n };\n\n if (payload === undefined) {\n return baseEnvelope as unknown as InspectorMessage<Type>;\n }\n\n return {\n ...baseEnvelope,\n payload,\n } as unknown as InspectorMessage<Type>;\n};\n\nexport const parseMessage = (\n raw: unknown,\n options: ParseMessageOptions = {},\n): ParseMessageResult => {\n const parsedMessage = toRawMessage(raw);\n\n if (parsedMessage === undefined) {\n return {\n ok: false,\n error: createInspectorProtocolError(\n 'ERR_INVALID_MESSAGE',\n 'Incoming message must be an object or JSON string object.',\n ),\n };\n }\n\n const originError = validateOrigin(options);\n\n if (originError !== undefined) {\n return {\n ok: false,\n error: originError,\n };\n }\n\n if (parsedMessage.channel !== INSPECTOR_CHANNEL) {\n return {\n ok: false,\n error: createInspectorProtocolError(\n 'ERR_INVALID_MESSAGE',\n `Invalid channel ${String(parsedMessage.channel)}.`,\n ),\n };\n }\n\n if (typeof parsedMessage.version !== 'number') {\n return {\n ok: false,\n error: createInspectorProtocolError(\n 'ERR_INVALID_MESSAGE',\n 'Message version must be a number.',\n ),\n };\n }\n\n const supportedVersion =\n options.supportedVersion ?? INSPECTOR_PROTOCOL_VERSION;\n\n if (parsedMessage.version !== supportedVersion) {\n return {\n ok: false,\n error: createInspectorProtocolError(\n 'ERR_UNSUPPORTED_VERSION',\n `Expected version ${supportedVersion} but received ${parsedMessage.version}.`,\n ),\n };\n }\n\n if (typeof parsedMessage.type !== 'string') {\n return {\n ok: false,\n error: createInspectorProtocolError(\n 'ERR_INVALID_MESSAGE',\n 'Message type must be a string.',\n ),\n };\n }\n\n if (!validMessageTypes.has(parsedMessage.type)) {\n return {\n ok: false,\n error: createInspectorProtocolError(\n 'ERR_UNKNOWN_MESSAGE_TYPE',\n `Message type ${parsedMessage.type} is not part of protocol v1.`,\n ),\n };\n }\n\n if (\n parsedMessage.requestId !== undefined &&\n typeof parsedMessage.requestId !== 'string'\n ) {\n return {\n ok: false,\n error: createInspectorProtocolError(\n 'ERR_INVALID_MESSAGE',\n 'requestId must be a string when provided.',\n ),\n };\n }\n\n if (\n parsedMessage.sessionId !== undefined &&\n typeof parsedMessage.sessionId !== 'string'\n ) {\n return {\n ok: false,\n error: createInspectorProtocolError(\n 'ERR_INVALID_MESSAGE',\n 'sessionId must be a string when provided.',\n ),\n };\n }\n\n const messageType = parsedMessage.type as InspectorMessageType;\n const payload = parsedMessage.payload;\n\n if (expectsNoPayload(messageType) && payload !== undefined) {\n return {\n ok: false,\n error: createInspectorProtocolError(\n 'ERR_INVALID_PAYLOAD',\n `${messageType} does not accept a payload.`,\n ),\n };\n }\n\n if (!validatePayloadByType(messageType, payload)) {\n return {\n ok: false,\n error: createInspectorProtocolError(\n 'ERR_INVALID_PAYLOAD',\n `Payload does not satisfy ${messageType} contract.`,\n ),\n };\n }\n\n return {\n ok: true,\n message: parsedMessage as AnyInspectorMessage,\n };\n};\n\nexport const isInspectorMessage = (raw: unknown): raw is AnyInspectorMessage => {\n return parseMessage(raw).ok;\n};\n"],"names":["validMessageTypes","hostToEmbeddedMessageTypes","embeddedToHostMessageTypes","isRecord","value","isStringArray","item","isStringOrStringArray","isNonNegativeInteger","isPositiveInteger","isFiniteNumber","isHelloAuthMetadata","isHelloAuthPayload","isSerializablePlaceholder","serializablePlaceholderTypes","isSerializableValue","depth","entry","isTreeNode","isNodeProps","isTreeSnapshotMeta","isTreeSnapshotPayload","node","isBlobValue","expectsNoPayload","type","validatePayloadByType","payload","inspectorErrorCodes","toRawMessage","raw","parsed","validateOrigin","options","normalizedSourceOrigin","normalizeOrigin","createInspectorProtocolError","normalizedExpectedOrigin","isOriginTrusted","buildMessage","baseEnvelope","INSPECTOR_CHANNEL","INSPECTOR_PROTOCOL_VERSION","parseMessage","parsedMessage","originError","supportedVersion","messageType","isInspectorMessage"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@iteraai/inspector-protocol",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Protocol constants, message builders, and validators for the Itera component inspector SDK.",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"sideEffects": false,
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./types": {
|
|
21
|
+
"types": "./dist/types.d.ts",
|
|
22
|
+
"import": "./dist/types.js"
|
|
23
|
+
},
|
|
24
|
+
"./errors": {
|
|
25
|
+
"types": "./dist/errors.d.ts",
|
|
26
|
+
"import": "./dist/errors.js"
|
|
27
|
+
},
|
|
28
|
+
"./validators": {
|
|
29
|
+
"types": "./dist/validators.d.ts",
|
|
30
|
+
"import": "./dist/validators.js"
|
|
31
|
+
},
|
|
32
|
+
"./origins": {
|
|
33
|
+
"types": "./dist/origins.d.ts",
|
|
34
|
+
"import": "./dist/origins.js"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/iteraai/component-inspector.git",
|
|
40
|
+
"directory": "packages/inspector-protocol"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/iteraai/component-inspector/issues"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/iteraai/component-inspector/tree/main/packages/inspector-protocol#readme",
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "vite build",
|
|
51
|
+
"prepack": "npm run build",
|
|
52
|
+
"type-check": "tsc --noEmit",
|
|
53
|
+
"test": "vitest run",
|
|
54
|
+
"test:watch": "vitest watch",
|
|
55
|
+
"lint": "eslint . --fix",
|
|
56
|
+
"lint:ci": "eslint . --max-warnings=0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@eslint/js": "^9.19.0",
|
|
60
|
+
"@stylistic/eslint-plugin-ts": "^4.2.0",
|
|
61
|
+
"@types/node": "^22.13.1",
|
|
62
|
+
"eslint": "^9.20.1",
|
|
63
|
+
"eslint-config-prettier": "^10.0.1",
|
|
64
|
+
"eslint-plugin-unicorn": "^58.0.0",
|
|
65
|
+
"globals": "^15.14.0",
|
|
66
|
+
"typescript": "~5.6.2",
|
|
67
|
+
"typescript-eslint": "^8.23.0",
|
|
68
|
+
"vite": "^6.0.5",
|
|
69
|
+
"vite-plugin-dts": "^4.5.4",
|
|
70
|
+
"vitest": "^3.0.8"
|
|
71
|
+
}
|
|
72
|
+
}
|