@aitty/protocol 0.1.1 → 0.2.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 +49 -0
- package/dist/index.d.ts +69 -2
- package/dist/index.js +66 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# @aitty/protocol
|
|
2
|
+
|
|
3
|
+
Shared protocol types and helpers for aitty browser-terminal sessions.
|
|
4
|
+
|
|
5
|
+
This package has no Node runtime dependency. Use it when a host, browser
|
|
6
|
+
adapter, or integration needs to share status, control-frame, theme, or portless
|
|
7
|
+
session-path semantics without depending on the full server or browser runtime.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm i @aitty/protocol
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import {
|
|
19
|
+
createAittyPortlessIdentity,
|
|
20
|
+
createHelloControlFrame,
|
|
21
|
+
parseAittyControlFrame
|
|
22
|
+
} from "@aitty/protocol";
|
|
23
|
+
|
|
24
|
+
const identity = createAittyPortlessIdentity({
|
|
25
|
+
project: "my-app",
|
|
26
|
+
label: "codex",
|
|
27
|
+
token: "local-session-token"
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
console.log(identity.path);
|
|
31
|
+
|
|
32
|
+
const frame = parseAittyControlFrame(createHelloControlFrame({
|
|
33
|
+
cols: 120,
|
|
34
|
+
rows: 32,
|
|
35
|
+
replay: ""
|
|
36
|
+
}));
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Main Exports
|
|
40
|
+
|
|
41
|
+
- Portless helpers: `createAittyPortlessIdentity()`, `normalizePortlessSegment()`, `normalizeAittyPortlessPathname()`.
|
|
42
|
+
- Control frames: `createHelloControlFrame()`, `createResizeControlFrame()`, `createExitControlFrame()`, `createThemeControlFrame()`, `parseAittyControlFrame()`.
|
|
43
|
+
- Status types: `AittyTerminalStatusSnapshot`, connection states, output states, and session presentation states.
|
|
44
|
+
- Theme helpers: `normalizeTheme()`, `readThemeSource()`, `subscribeThemeSource()`.
|
|
45
|
+
- Session metadata helpers: `createSessionInfoBody()` and `AittySessionInfo`.
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
Apache-2.0
|
package/dist/index.d.ts
CHANGED
|
@@ -36,6 +36,7 @@ type AittyTerminalStatusSnapshot = {
|
|
|
36
36
|
output: AittyTerminalOutputState;
|
|
37
37
|
sessionState: AittyTerminalSessionPresentationState;
|
|
38
38
|
};
|
|
39
|
+
type AittyClientRole = "controller" | "viewer";
|
|
39
40
|
type AittyHelloControlFrame = {
|
|
40
41
|
cols: number;
|
|
41
42
|
replay: string;
|
|
@@ -62,7 +63,44 @@ type AittyThemeControlFrame = {
|
|
|
62
63
|
theme: AittyTheme | null;
|
|
63
64
|
type: "theme";
|
|
64
65
|
};
|
|
65
|
-
type
|
|
66
|
+
type AittyRoleControlFrame = {
|
|
67
|
+
clientId: string;
|
|
68
|
+
role: AittyClientRole;
|
|
69
|
+
type: "role";
|
|
70
|
+
};
|
|
71
|
+
type AittyTakeoverRequestControlFrame = {
|
|
72
|
+
requestId?: string;
|
|
73
|
+
requesterId?: string;
|
|
74
|
+
type: "takeover-request";
|
|
75
|
+
};
|
|
76
|
+
type AittyTakeoverResponseControlFrame = {
|
|
77
|
+
approved: boolean;
|
|
78
|
+
requestId: string;
|
|
79
|
+
type: "takeover-response";
|
|
80
|
+
};
|
|
81
|
+
type AittyTakeoverResultControlFrame = {
|
|
82
|
+
approved: boolean;
|
|
83
|
+
reason?: string;
|
|
84
|
+
type: "takeover-result";
|
|
85
|
+
};
|
|
86
|
+
type AittyPushSubscriptionPayload = {
|
|
87
|
+
endpoint: string;
|
|
88
|
+
expirationTime?: null | number;
|
|
89
|
+
keys: {
|
|
90
|
+
auth: string;
|
|
91
|
+
p256dh: string;
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
type AittyPushSubscribeControlFrame = {
|
|
95
|
+
subscription: AittyPushSubscriptionPayload;
|
|
96
|
+
type: "push-subscribe";
|
|
97
|
+
url?: string;
|
|
98
|
+
};
|
|
99
|
+
type AittyPushUnsubscribeControlFrame = {
|
|
100
|
+
endpoint?: string;
|
|
101
|
+
type: "push-unsubscribe";
|
|
102
|
+
};
|
|
103
|
+
type AittyControlFrame = AittyExitControlFrame | AittyHelloControlFrame | AittyPingControlFrame | AittyPongControlFrame | AittyPushSubscribeControlFrame | AittyPushUnsubscribeControlFrame | AittyRoleControlFrame | AittyResizeControlFrame | AittyTakeoverRequestControlFrame | AittyTakeoverResponseControlFrame | AittyTakeoverResultControlFrame | AittyThemeControlFrame;
|
|
66
104
|
declare function createAittyPortlessIdentity(options: {
|
|
67
105
|
label?: string;
|
|
68
106
|
labelFallback?: string;
|
|
@@ -87,8 +125,37 @@ declare function createExitControlFrame(options: {
|
|
|
87
125
|
code: number | null;
|
|
88
126
|
signal?: string | null;
|
|
89
127
|
}): string;
|
|
128
|
+
declare function createRoleControlFrame(options: {
|
|
129
|
+
clientId: string;
|
|
130
|
+
role: AittyClientRole;
|
|
131
|
+
}): string;
|
|
132
|
+
declare function createTakeoverRequestControlFrame(options?: {
|
|
133
|
+
requestId?: string;
|
|
134
|
+
requesterId?: string;
|
|
135
|
+
}): string;
|
|
136
|
+
declare function createTakeoverResponseControlFrame(options: {
|
|
137
|
+
approved: boolean;
|
|
138
|
+
requestId: string;
|
|
139
|
+
}): string;
|
|
140
|
+
declare function createTakeoverResultControlFrame(options: {
|
|
141
|
+
approved: boolean;
|
|
142
|
+
reason?: string;
|
|
143
|
+
}): string;
|
|
144
|
+
declare function createPushSubscribeControlFrame(options: {
|
|
145
|
+
subscription: AittyPushSubscriptionPayload;
|
|
146
|
+
url?: string;
|
|
147
|
+
}): string;
|
|
148
|
+
declare function createPushUnsubscribeControlFrame(options?: {
|
|
149
|
+
endpoint?: string;
|
|
150
|
+
}): string;
|
|
90
151
|
declare function parseAittyControlFrame(data: string): AittyControlFrame | null;
|
|
152
|
+
declare function isAittyRoleControlFrame(frame: AittyControlFrame): frame is AittyRoleControlFrame;
|
|
91
153
|
declare function isAittyResizeControlFrame(frame: AittyControlFrame): frame is AittyResizeControlFrame;
|
|
154
|
+
declare function isAittyTakeoverRequestControlFrame(frame: AittyControlFrame): frame is AittyTakeoverRequestControlFrame;
|
|
155
|
+
declare function isAittyTakeoverResponseControlFrame(frame: AittyControlFrame): frame is AittyTakeoverResponseControlFrame;
|
|
156
|
+
declare function isAittyTakeoverResultControlFrame(frame: AittyControlFrame): frame is AittyTakeoverResultControlFrame;
|
|
157
|
+
declare function isAittyPushSubscribeControlFrame(frame: AittyControlFrame): frame is AittyPushSubscribeControlFrame;
|
|
158
|
+
declare function isAittyPushUnsubscribeControlFrame(frame: AittyControlFrame): frame is AittyPushUnsubscribeControlFrame;
|
|
92
159
|
declare function isValidAittyResizeDimension(value: unknown): value is number;
|
|
93
160
|
declare function normalizeTheme(theme: AittyTheme | undefined): AittyTheme | undefined;
|
|
94
161
|
declare function readThemeSource(source: AittyThemeSource | undefined): Promise<AittyTheme | undefined>;
|
|
@@ -96,4 +163,4 @@ declare function subscribeThemeSource(source: AittyThemeSource | undefined, list
|
|
|
96
163
|
dispose(): void;
|
|
97
164
|
};
|
|
98
165
|
//#endregion
|
|
99
|
-
export { AITTY_SESSION_PATH_PREFIX, AittyControlFrame, AittyExitControlFrame, AittyHelloControlFrame, AittyPingControlFrame, AittyPongControlFrame, AittyPortlessIdentity, AittyPortlessOptions, AittyResizeControlFrame, AittyRuntimeKind, AittySessionInfo, AittyTerminalConnectionState, AittyTerminalLoadingPresentation, AittyTerminalOutputState, AittyTerminalSessionPresentationState, AittyTerminalStatusSnapshot, AittyTheme, AittyThemeControlFrame, AittyThemeSource, AittyThemeSubscription, createAittyPortlessIdentity, createExitControlFrame, createHelloControlFrame, createPingControlFrame, createPongControlFrame, createResizeControlFrame, createSessionInfoBody, createThemeControlFrame, isAittyResizeControlFrame, isValidAittyResizeDimension, normalizeAittyPortlessPathname, normalizePortlessSegment, normalizeTheme, parseAittyControlFrame, readThemeSource, subscribeThemeSource };
|
|
166
|
+
export { AITTY_SESSION_PATH_PREFIX, AittyClientRole, AittyControlFrame, AittyExitControlFrame, AittyHelloControlFrame, AittyPingControlFrame, AittyPongControlFrame, AittyPortlessIdentity, AittyPortlessOptions, AittyPushSubscribeControlFrame, AittyPushSubscriptionPayload, AittyPushUnsubscribeControlFrame, AittyResizeControlFrame, AittyRoleControlFrame, AittyRuntimeKind, AittySessionInfo, AittyTakeoverRequestControlFrame, AittyTakeoverResponseControlFrame, AittyTakeoverResultControlFrame, AittyTerminalConnectionState, AittyTerminalLoadingPresentation, AittyTerminalOutputState, AittyTerminalSessionPresentationState, AittyTerminalStatusSnapshot, AittyTheme, AittyThemeControlFrame, AittyThemeSource, AittyThemeSubscription, createAittyPortlessIdentity, createExitControlFrame, createHelloControlFrame, createPingControlFrame, createPongControlFrame, createPushSubscribeControlFrame, createPushUnsubscribeControlFrame, createResizeControlFrame, createRoleControlFrame, createSessionInfoBody, createTakeoverRequestControlFrame, createTakeoverResponseControlFrame, createTakeoverResultControlFrame, createThemeControlFrame, isAittyPushSubscribeControlFrame, isAittyPushUnsubscribeControlFrame, isAittyResizeControlFrame, isAittyRoleControlFrame, isAittyTakeoverRequestControlFrame, isAittyTakeoverResponseControlFrame, isAittyTakeoverResultControlFrame, isValidAittyResizeDimension, normalizeAittyPortlessPathname, normalizePortlessSegment, normalizeTheme, parseAittyControlFrame, readThemeSource, subscribeThemeSource };
|
package/dist/index.js
CHANGED
|
@@ -58,6 +58,47 @@ function createExitControlFrame(options) {
|
|
|
58
58
|
type: "exit"
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
|
+
function createRoleControlFrame(options) {
|
|
62
|
+
return JSON.stringify({
|
|
63
|
+
clientId: options.clientId,
|
|
64
|
+
role: options.role,
|
|
65
|
+
type: "role"
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function createTakeoverRequestControlFrame(options = {}) {
|
|
69
|
+
return JSON.stringify({
|
|
70
|
+
...options.requestId ? { requestId: options.requestId } : {},
|
|
71
|
+
...options.requesterId ? { requesterId: options.requesterId } : {},
|
|
72
|
+
type: "takeover-request"
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function createTakeoverResponseControlFrame(options) {
|
|
76
|
+
return JSON.stringify({
|
|
77
|
+
approved: options.approved,
|
|
78
|
+
requestId: options.requestId,
|
|
79
|
+
type: "takeover-response"
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function createTakeoverResultControlFrame(options) {
|
|
83
|
+
return JSON.stringify({
|
|
84
|
+
approved: options.approved,
|
|
85
|
+
...options.reason ? { reason: options.reason } : {},
|
|
86
|
+
type: "takeover-result"
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function createPushSubscribeControlFrame(options) {
|
|
90
|
+
return JSON.stringify({
|
|
91
|
+
subscription: options.subscription,
|
|
92
|
+
...options.url ? { url: options.url } : {},
|
|
93
|
+
type: "push-subscribe"
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function createPushUnsubscribeControlFrame(options = {}) {
|
|
97
|
+
return JSON.stringify({
|
|
98
|
+
...options.endpoint ? { endpoint: options.endpoint } : {},
|
|
99
|
+
type: "push-unsubscribe"
|
|
100
|
+
});
|
|
101
|
+
}
|
|
61
102
|
function parseAittyControlFrame(data) {
|
|
62
103
|
try {
|
|
63
104
|
const parsed = JSON.parse(data);
|
|
@@ -68,12 +109,36 @@ function parseAittyControlFrame(data) {
|
|
|
68
109
|
return null;
|
|
69
110
|
}
|
|
70
111
|
}
|
|
112
|
+
function isAittyRoleControlFrame(frame) {
|
|
113
|
+
return frame.type === "role" && (frame.role === "controller" || frame.role === "viewer") && typeof frame.clientId === "string" && frame.clientId.length > 0;
|
|
114
|
+
}
|
|
71
115
|
function isAittyResizeControlFrame(frame) {
|
|
72
116
|
return frame.type === "resize" && isValidAittyResizeDimension(frame.cols) && isValidAittyResizeDimension(frame.rows);
|
|
73
117
|
}
|
|
118
|
+
function isAittyTakeoverRequestControlFrame(frame) {
|
|
119
|
+
return frame.type === "takeover-request";
|
|
120
|
+
}
|
|
121
|
+
function isAittyTakeoverResponseControlFrame(frame) {
|
|
122
|
+
return frame.type === "takeover-response" && typeof frame.requestId === "string" && frame.requestId.length > 0 && typeof frame.approved === "boolean";
|
|
123
|
+
}
|
|
124
|
+
function isAittyTakeoverResultControlFrame(frame) {
|
|
125
|
+
return frame.type === "takeover-result" && typeof frame.approved === "boolean";
|
|
126
|
+
}
|
|
127
|
+
function isAittyPushSubscribeControlFrame(frame) {
|
|
128
|
+
return frame.type === "push-subscribe" && isAittyPushSubscriptionPayload(frame.subscription) && (frame.url === void 0 || typeof frame.url === "string");
|
|
129
|
+
}
|
|
130
|
+
function isAittyPushUnsubscribeControlFrame(frame) {
|
|
131
|
+
return frame.type === "push-unsubscribe" && (frame.endpoint === void 0 || typeof frame.endpoint === "string");
|
|
132
|
+
}
|
|
74
133
|
function isValidAittyResizeDimension(value) {
|
|
75
134
|
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
76
135
|
}
|
|
136
|
+
function isAittyPushSubscriptionPayload(value) {
|
|
137
|
+
if (!value || typeof value !== "object") return false;
|
|
138
|
+
const subscription = value;
|
|
139
|
+
const keys = subscription.keys;
|
|
140
|
+
return typeof subscription.endpoint === "string" && subscription.endpoint.length > 0 && (subscription.expirationTime === void 0 || subscription.expirationTime === null || typeof subscription.expirationTime === "number") && Boolean(keys) && typeof keys?.auth === "string" && keys.auth.length > 0 && typeof keys.p256dh === "string" && keys.p256dh.length > 0;
|
|
141
|
+
}
|
|
77
142
|
function normalizeTheme(theme) {
|
|
78
143
|
if (typeof theme !== "string") return;
|
|
79
144
|
const normalized = theme.trim();
|
|
@@ -91,4 +156,4 @@ function subscribeThemeSource(source, listener) {
|
|
|
91
156
|
return { dispose() {} };
|
|
92
157
|
}
|
|
93
158
|
//#endregion
|
|
94
|
-
export { AITTY_SESSION_PATH_PREFIX, createAittyPortlessIdentity, createExitControlFrame, createHelloControlFrame, createPingControlFrame, createPongControlFrame, createResizeControlFrame, createSessionInfoBody, createThemeControlFrame, isAittyResizeControlFrame, isValidAittyResizeDimension, normalizeAittyPortlessPathname, normalizePortlessSegment, normalizeTheme, parseAittyControlFrame, readThemeSource, subscribeThemeSource };
|
|
159
|
+
export { AITTY_SESSION_PATH_PREFIX, createAittyPortlessIdentity, createExitControlFrame, createHelloControlFrame, createPingControlFrame, createPongControlFrame, createPushSubscribeControlFrame, createPushUnsubscribeControlFrame, createResizeControlFrame, createRoleControlFrame, createSessionInfoBody, createTakeoverRequestControlFrame, createTakeoverResponseControlFrame, createTakeoverResultControlFrame, createThemeControlFrame, isAittyPushSubscribeControlFrame, isAittyPushUnsubscribeControlFrame, isAittyResizeControlFrame, isAittyRoleControlFrame, isAittyTakeoverRequestControlFrame, isAittyTakeoverResponseControlFrame, isAittyTakeoverResultControlFrame, isValidAittyResizeDimension, normalizeAittyPortlessPathname, normalizePortlessSegment, normalizeTheme, parseAittyControlFrame, readThemeSource, subscribeThemeSource };
|