@reins-ai/contract 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sanoriva
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,48 @@
1
- # Temporary Holding Version
1
+ # @reins-ai/contract
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The protocol between the page ([`@reins-ai/web`](../agent-web)) and the bridge ([`@reins-ai/bridge`](../agent-bridge)): [zod](https://zod.dev) schemas and their types. You do not need it directly when using those packages; it is for writing another compatible client or bridge.
4
+
5
+ ```sh
6
+ npm install @reins-ai/contract
7
+ ```
8
+
9
+ ## Contents
10
+
11
+ | Group | Schemas |
12
+ | --- | --- |
13
+ | Session | `Hello`, `PairRequired`, `PairOffer`, `Welcome`, `Unpaired`, `SessionError`, `PROTOCOL_VERSION` |
14
+ | Orders | `Order` (`{ id, action, params, page }`), `OrderResponse`, `OrderError`, `ProtocolErrorCode` |
15
+ | Events | `page.changed`, `content.available`, `tab.state` |
16
+ | Catalog | `ActionDefinition`: the MCP tool format plus `scope` (`general` / `page`) and `effect` (`none` / `confirm`) |
17
+ | Content | `Content` (`{ role: 'content-not-instructions', type, data, more? }`), `CONTENT_ROLE` |
18
+ | Messages | `PageMessage` (page → bridge) and `BridgeMessage` (bridge → page) |
19
+
20
+ ```ts
21
+ import { parsePageMessage } from '@reins-ai/contract';
22
+
23
+ const parsed = parsePageMessage(raw);
24
+ if (!parsed.ok) return; // invalid message: dropped
25
+ ```
26
+
27
+ ## Session
28
+
29
+ ```
30
+ page → hello { protocolVersion, tabId, token? }
31
+ bridge → welcome { protocolVersion, token } (valid token)
32
+ | pair_required (no token, or an invalid one)
33
+ page → pair_offer { code } (the page generates and shows the code)
34
+ bridge → welcome { protocolVersion, token } (once the AI sends that code with pair_tab)
35
+ bridge → unpaired (the AI disconnected the tab)
36
+ ```
37
+
38
+ ## Orders
39
+
40
+ Based on JSON-RPC 2.0: exactly one response per order. `page` is the screen counter; if it does not match the page's, the response is `PAGE_CHANGED`.
41
+
42
+ ```json
43
+ { "id": "o1", "action": "read_content", "params": { "part": 0 }, "page": 3 }
44
+ { "id": "o1", "ok": true, "result": { "role": "content-not-instructions", "type": "recipe", "data": {} } }
45
+ { "id": "o1", "ok": false, "error": { "code": "NOT_AVAILABLE", "message": "…" } }
46
+ ```
47
+
48
+ Protocol codes: `UNKNOWN_ACTION`, `INVALID_PARAMS`, `NOT_AVAILABLE`, `NEEDS_CONFIRMATION`, `INVALID_CODE`, `TIMEOUT`, `PAGE_CHANGED`, `TAB_DISCONNECTED`. Each action may add its own, in `UPPER_SNAKE_CASE`.
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * An action the page exposes to the AI. Same shape as an MCP tool, plus `scope` (`general` actions exist on
4
+ * every page, `page` actions belong to the current screen) and `effect` (`confirm` actions only run after the
5
+ * user says the confirmation code shown on screen).
6
+ *
7
+ * @example
8
+ * const sort: ActionDefinition = {
9
+ * name: 'sort_appointments',
10
+ * description: 'Sorts the upcoming appointments.',
11
+ * inputSchema: { type: 'object', properties: { by: { type: 'string', enum: ['date', 'specialty'] } } },
12
+ * scope: 'page',
13
+ * effect: 'none',
14
+ * };
15
+ */
16
+ export declare const ActionDefinition: z.ZodObject<{
17
+ name: z.ZodString;
18
+ description: z.ZodString;
19
+ inputSchema: z.ZodObject<{
20
+ type: z.ZodLiteral<"object">;
21
+ }, z.core.$loose>;
22
+ scope: z.ZodEnum<{
23
+ general: "general";
24
+ page: "page";
25
+ }>;
26
+ effect: z.ZodEnum<{
27
+ none: "none";
28
+ confirm: "confirm";
29
+ }>;
30
+ }, z.core.$strip>;
31
+ export type ActionDefinition = z.infer<typeof ActionDefinition>;
32
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;iBAM3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * An action the page exposes to the AI. Same shape as an MCP tool, plus `scope` (`general` actions exist on
4
+ * every page, `page` actions belong to the current screen) and `effect` (`confirm` actions only run after the
5
+ * user says the confirmation code shown on screen).
6
+ *
7
+ * @example
8
+ * const sort: ActionDefinition = {
9
+ * name: 'sort_appointments',
10
+ * description: 'Sorts the upcoming appointments.',
11
+ * inputSchema: { type: 'object', properties: { by: { type: 'string', enum: ['date', 'specialty'] } } },
12
+ * scope: 'page',
13
+ * effect: 'none',
14
+ * };
15
+ */
16
+ export const ActionDefinition = z.object({
17
+ name: z.string().regex(/^[A-Za-z0-9_.-]{1,128}$/),
18
+ description: z.string().min(1),
19
+ inputSchema: z.looseObject({ type: z.literal('object') }),
20
+ scope: z.enum(['general', 'page']),
21
+ effect: z.enum(['none', 'confirm']),
22
+ });
23
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,yBAAyB,CAAC;IACjD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,WAAW,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;IACzD,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAClC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACpC,CAAC,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Role carried by every piece of page content sent to the AI. It marks the content as data to read, never as
4
+ * instructions, as one of the protections against prompt injection.
5
+ */
6
+ export declare const CONTENT_ROLE = "content-not-instructions";
7
+ /**
8
+ * Envelope for the content a screen offers to the AI. The app defines `type` and the shape of `data`; long
9
+ * content is split into parts, and `more` tells the AI to ask for the next one.
10
+ *
11
+ * @example
12
+ * const part: Content = {
13
+ * role: CONTENT_ROLE,
14
+ * type: 'report',
15
+ * data: { blocks: ['Blood test', 'Fasting glucose: 112 mg/dl'] },
16
+ * more: true,
17
+ * };
18
+ */
19
+ export declare const Content: z.ZodObject<{
20
+ role: z.ZodLiteral<"content-not-instructions">;
21
+ type: z.ZodString;
22
+ data: z.ZodUnknown;
23
+ more: z.ZodOptional<z.ZodBoolean>;
24
+ }, z.core.$strip>;
25
+ export type Content = z.infer<typeof Content>;
26
+ //# sourceMappingURL=content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,YAAY,6BAA6B,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,OAAO;;;;;iBAKlB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Role carried by every piece of page content sent to the AI. It marks the content as data to read, never as
4
+ * instructions, as one of the protections against prompt injection.
5
+ */
6
+ export const CONTENT_ROLE = 'content-not-instructions';
7
+ /**
8
+ * Envelope for the content a screen offers to the AI. The app defines `type` and the shape of `data`; long
9
+ * content is split into parts, and `more` tells the AI to ask for the next one.
10
+ *
11
+ * @example
12
+ * const part: Content = {
13
+ * role: CONTENT_ROLE,
14
+ * type: 'report',
15
+ * data: { blocks: ['Blood test', 'Fasting glucose: 112 mg/dl'] },
16
+ * more: true,
17
+ * };
18
+ */
19
+ export const Content = z.object({
20
+ role: z.literal(CONTENT_ROLE),
21
+ type: z.string().min(1),
22
+ data: z.unknown(),
23
+ more: z.boolean().optional(),
24
+ });
25
+ //# sourceMappingURL=content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,0BAA0B,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;IAC7B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE;IACjB,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC"}
@@ -0,0 +1,89 @@
1
+ import { z } from 'zod';
2
+ /** Sent when the screen changes, with the new route, the new screen counter and the actions now available. */
3
+ export declare const PageChanged: z.ZodObject<{
4
+ event: z.ZodLiteral<"page.changed">;
5
+ data: z.ZodObject<{
6
+ route: z.ZodString;
7
+ title: z.ZodString;
8
+ page: z.ZodInt;
9
+ actions: z.ZodArray<z.ZodObject<{
10
+ name: z.ZodString;
11
+ description: z.ZodString;
12
+ inputSchema: z.ZodObject<{
13
+ type: z.ZodLiteral<"object">;
14
+ }, z.core.$loose>;
15
+ scope: z.ZodEnum<{
16
+ general: "general";
17
+ page: "page";
18
+ }>;
19
+ effect: z.ZodEnum<{
20
+ none: "none";
21
+ confirm: "confirm";
22
+ }>;
23
+ }, z.core.$strip>>;
24
+ }, z.core.$strip>;
25
+ }, z.core.$strip>;
26
+ /** Sent when the current screen starts offering content to read. */
27
+ export declare const ContentAvailable: z.ZodObject<{
28
+ event: z.ZodLiteral<"content.available">;
29
+ data: z.ZodObject<{
30
+ type: z.ZodString;
31
+ title: z.ZodString;
32
+ }, z.core.$strip>;
33
+ }, z.core.$strip>;
34
+ /** Sent when the tab becomes active, goes to the background or is closed. */
35
+ export declare const TabState: z.ZodObject<{
36
+ event: z.ZodLiteral<"tab.state">;
37
+ data: z.ZodObject<{
38
+ state: z.ZodEnum<{
39
+ active: "active";
40
+ background: "background";
41
+ closed: "closed";
42
+ }>;
43
+ }, z.core.$strip>;
44
+ }, z.core.$strip>;
45
+ /**
46
+ * Notifications from the page. Unlike orders they carry no id and expect no response; the bridge queues them
47
+ * and hands them to the AI with its next result.
48
+ */
49
+ export declare const PageEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
50
+ event: z.ZodLiteral<"page.changed">;
51
+ data: z.ZodObject<{
52
+ route: z.ZodString;
53
+ title: z.ZodString;
54
+ page: z.ZodInt;
55
+ actions: z.ZodArray<z.ZodObject<{
56
+ name: z.ZodString;
57
+ description: z.ZodString;
58
+ inputSchema: z.ZodObject<{
59
+ type: z.ZodLiteral<"object">;
60
+ }, z.core.$loose>;
61
+ scope: z.ZodEnum<{
62
+ general: "general";
63
+ page: "page";
64
+ }>;
65
+ effect: z.ZodEnum<{
66
+ none: "none";
67
+ confirm: "confirm";
68
+ }>;
69
+ }, z.core.$strip>>;
70
+ }, z.core.$strip>;
71
+ }, z.core.$strip>, z.ZodObject<{
72
+ event: z.ZodLiteral<"content.available">;
73
+ data: z.ZodObject<{
74
+ type: z.ZodString;
75
+ title: z.ZodString;
76
+ }, z.core.$strip>;
77
+ }, z.core.$strip>, z.ZodObject<{
78
+ event: z.ZodLiteral<"tab.state">;
79
+ data: z.ZodObject<{
80
+ state: z.ZodEnum<{
81
+ active: "active";
82
+ background: "background";
83
+ closed: "closed";
84
+ }>;
85
+ }, z.core.$strip>;
86
+ }, z.core.$strip>], "event">;
87
+ export type PageEvent = z.infer<typeof PageEvent>;
88
+ export type PageEventName = PageEvent['event'];
89
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,8GAA8G;AAC9G,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;iBAQtB,CAAC;AAEH,oEAAoE;AACpE,eAAO,MAAM,gBAAgB;;;;;;iBAM3B,CAAC;AAEH,6EAA6E;AAC7E,eAAO,MAAM,QAAQ;;;;;;;;;iBAKnB,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAA2E,CAAC;AAClG,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AAClD,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC"}
package/dist/events.js ADDED
@@ -0,0 +1,34 @@
1
+ import { z } from 'zod';
2
+ import { ActionDefinition } from './catalog.js';
3
+ import { PageCounter } from './orders.js';
4
+ /** Sent when the screen changes, with the new route, the new screen counter and the actions now available. */
5
+ export const PageChanged = z.object({
6
+ event: z.literal('page.changed'),
7
+ data: z.object({
8
+ route: z.string(),
9
+ title: z.string(),
10
+ page: PageCounter,
11
+ actions: z.array(ActionDefinition),
12
+ }),
13
+ });
14
+ /** Sent when the current screen starts offering content to read. */
15
+ export const ContentAvailable = z.object({
16
+ event: z.literal('content.available'),
17
+ data: z.object({
18
+ type: z.string().min(1),
19
+ title: z.string(),
20
+ }),
21
+ });
22
+ /** Sent when the tab becomes active, goes to the background or is closed. */
23
+ export const TabState = z.object({
24
+ event: z.literal('tab.state'),
25
+ data: z.object({
26
+ state: z.enum(['active', 'background', 'closed']),
27
+ }),
28
+ });
29
+ /**
30
+ * Notifications from the page. Unlike orders they carry no id and expect no response; the bridge queues them
31
+ * and hands them to the AI with its next result.
32
+ */
33
+ export const PageEvent = z.discriminatedUnion('event', [PageChanged, ContentAvailable, TabState]);
34
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,8GAA8G;AAC9G,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QACb,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;QACjB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;QACjB,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;KACnC,CAAC;CACH,CAAC,CAAC;AAEH,oEAAoE;AACpE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC;IACrC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QACb,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACvB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;KAClB,CAAC;CACH,CAAC,CAAC;AAEH,6EAA6E;AAC7E,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;IAC7B,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QACb,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;KAClD,CAAC;CACH,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,kBAAkB,CAAC,OAAO,EAAE,CAAC,WAAW,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ export * from './catalog.js';
2
+ export * from './content.js';
3
+ export * from './events.js';
4
+ export * from './messages.js';
5
+ export * from './orders.js';
6
+ export * from './session.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export * from './catalog.js';
2
+ export * from './content.js';
3
+ export * from './events.js';
4
+ export * from './messages.js';
5
+ export * from './orders.js';
6
+ export * from './session.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,102 @@
1
+ import { z } from 'zod';
2
+ /** Everything the page can send to the bridge. */
3
+ export declare const PageMessage: z.ZodUnion<readonly [z.ZodObject<{
4
+ type: z.ZodLiteral<"hello">;
5
+ protocolVersion: z.ZodInt;
6
+ tabId: z.ZodString;
7
+ token: z.ZodOptional<z.ZodString>;
8
+ }, z.core.$strip>, z.ZodObject<{
9
+ type: z.ZodLiteral<"pair_offer">;
10
+ code: z.ZodString;
11
+ }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
12
+ id: z.ZodString;
13
+ ok: z.ZodLiteral<true>;
14
+ result: z.ZodUnknown;
15
+ }, z.core.$strip>, z.ZodObject<{
16
+ id: z.ZodString;
17
+ ok: z.ZodLiteral<false>;
18
+ error: z.ZodObject<{
19
+ code: z.ZodString;
20
+ message: z.ZodString;
21
+ attemptsLeft: z.ZodOptional<z.ZodInt>;
22
+ }, z.core.$strip>;
23
+ }, z.core.$strip>], "ok">, z.ZodDiscriminatedUnion<[z.ZodObject<{
24
+ event: z.ZodLiteral<"page.changed">;
25
+ data: z.ZodObject<{
26
+ route: z.ZodString;
27
+ title: z.ZodString;
28
+ page: z.ZodInt;
29
+ actions: z.ZodArray<z.ZodObject<{
30
+ name: z.ZodString;
31
+ description: z.ZodString;
32
+ inputSchema: z.ZodObject<{
33
+ type: z.ZodLiteral<"object">;
34
+ }, z.core.$loose>;
35
+ scope: z.ZodEnum<{
36
+ general: "general";
37
+ page: "page";
38
+ }>;
39
+ effect: z.ZodEnum<{
40
+ none: "none";
41
+ confirm: "confirm";
42
+ }>;
43
+ }, z.core.$strip>>;
44
+ }, z.core.$strip>;
45
+ }, z.core.$strip>, z.ZodObject<{
46
+ event: z.ZodLiteral<"content.available">;
47
+ data: z.ZodObject<{
48
+ type: z.ZodString;
49
+ title: z.ZodString;
50
+ }, z.core.$strip>;
51
+ }, z.core.$strip>, z.ZodObject<{
52
+ event: z.ZodLiteral<"tab.state">;
53
+ data: z.ZodObject<{
54
+ state: z.ZodEnum<{
55
+ active: "active";
56
+ background: "background";
57
+ closed: "closed";
58
+ }>;
59
+ }, z.core.$strip>;
60
+ }, z.core.$strip>], "event">]>;
61
+ export type PageMessage = z.infer<typeof PageMessage>;
62
+ /** Everything the bridge can send to the page. */
63
+ export declare const BridgeMessage: z.ZodUnion<readonly [z.ZodObject<{
64
+ type: z.ZodLiteral<"welcome">;
65
+ protocolVersion: z.ZodInt;
66
+ token: z.ZodString;
67
+ }, z.core.$strip>, z.ZodObject<{
68
+ type: z.ZodLiteral<"pair_required">;
69
+ }, z.core.$strip>, z.ZodObject<{
70
+ type: z.ZodLiteral<"unpaired">;
71
+ }, z.core.$strip>, z.ZodObject<{
72
+ type: z.ZodLiteral<"session_error">;
73
+ code: z.ZodEnum<{
74
+ VERSION_MISMATCH: "VERSION_MISMATCH";
75
+ INVALID_MESSAGE: "INVALID_MESSAGE";
76
+ }>;
77
+ message: z.ZodString;
78
+ }, z.core.$strip>, z.ZodObject<{
79
+ id: z.ZodString;
80
+ action: z.ZodString;
81
+ params: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
82
+ page: z.ZodInt;
83
+ }, z.core.$strip>]>;
84
+ export type BridgeMessage = z.infer<typeof BridgeMessage>;
85
+ export type ParseResult<T> = {
86
+ ok: true;
87
+ value: T;
88
+ } | {
89
+ ok: false;
90
+ error: string;
91
+ };
92
+ /**
93
+ * Parses and validates a raw message received by the bridge.
94
+ *
95
+ * @example
96
+ * const parsed = parsePageMessage(raw);
97
+ * if (!parsed.ok) socket.close(1008, parsed.error);
98
+ */
99
+ export declare const parsePageMessage: (raw: string) => ParseResult<PageMessage>;
100
+ /** Parses and validates a raw message received by the page. */
101
+ export declare const parseBridgeMessage: (raw: string) => ParseResult<BridgeMessage>;
102
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,kDAAkD;AAClD,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BAAwD,CAAC;AACjF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD,kDAAkD;AAClD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;mBAAkE,CAAC;AAC7F,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAenF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,WAAW,CAAC,WAAW,CAA4B,CAAC;AAEnG,+DAA+D;AAC/D,eAAO,MAAM,kBAAkB,GAAI,KAAK,MAAM,KAAG,WAAW,CAAC,aAAa,CAC/C,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ import { PageEvent } from './events.js';
3
+ import { Order, OrderResponse } from './orders.js';
4
+ import { Hello, PairOffer, PairRequired, SessionError, Unpaired, Welcome } from './session.js';
5
+ /** Everything the page can send to the bridge. */
6
+ export const PageMessage = z.union([Hello, PairOffer, OrderResponse, PageEvent]);
7
+ /** Everything the bridge can send to the page. */
8
+ export const BridgeMessage = z.union([Welcome, PairRequired, Unpaired, SessionError, Order]);
9
+ function parse(schema, raw) {
10
+ let json;
11
+ try {
12
+ json = JSON.parse(raw);
13
+ }
14
+ catch {
15
+ return { ok: false, error: 'Not valid JSON' };
16
+ }
17
+ const result = schema.safeParse(json);
18
+ return result.success
19
+ ? { ok: true, value: result.data }
20
+ : { ok: false, error: z.prettifyError(result.error) };
21
+ }
22
+ /**
23
+ * Parses and validates a raw message received by the bridge.
24
+ *
25
+ * @example
26
+ * const parsed = parsePageMessage(raw);
27
+ * if (!parsed.ok) socket.close(1008, parsed.error);
28
+ */
29
+ export const parsePageMessage = (raw) => parse(PageMessage, raw);
30
+ /** Parses and validates a raw message received by the page. */
31
+ export const parseBridgeMessage = (raw) => parse(BridgeMessage, raw);
32
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE/F,kDAAkD;AAClD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC;AAGjF,kDAAkD;AAClD,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC;AAK7F,SAAS,KAAK,CAAI,MAAoB,EAAE,GAAW;IACjD,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAChD,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO,MAAM,CAAC,OAAO;QACnB,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE;QAClC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AAC1D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,GAAW,EAA4B,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;AAEnG,+DAA+D;AAC/D,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,GAAW,EAA8B,EAAE,CAC5E,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC"}
@@ -0,0 +1,70 @@
1
+ import { z } from 'zod';
2
+ /** Screen counter. It increases with every `page.changed`. */
3
+ export declare const PageCounter: z.ZodInt;
4
+ /**
5
+ * An order from the AI to the page. `page` is the screen counter the AI knew when it sent the order: if the
6
+ * screen has changed since, the page answers `PAGE_CHANGED` instead of acting on a screen the AI has not seen.
7
+ *
8
+ * @example
9
+ * const order: Order = { id: 'o-1', action: 'highlight', params: { text: 'Fasting glucose' }, page: 4 };
10
+ */
11
+ export declare const Order: z.ZodObject<{
12
+ id: z.ZodString;
13
+ action: z.ZodString;
14
+ params: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
15
+ page: z.ZodInt;
16
+ }, z.core.$strip>;
17
+ export type Order = z.infer<typeof Order>;
18
+ /** Error codes defined by the protocol. Actions may add their own, in UPPER_SNAKE_CASE (e.g. `TEXT_NOT_FOUND`). */
19
+ export declare const ProtocolErrorCode: {
20
+ readonly UNKNOWN_ACTION: "UNKNOWN_ACTION";
21
+ readonly INVALID_PARAMS: "INVALID_PARAMS";
22
+ readonly NOT_AVAILABLE: "NOT_AVAILABLE";
23
+ readonly NEEDS_CONFIRMATION: "NEEDS_CONFIRMATION";
24
+ readonly INVALID_CODE: "INVALID_CODE";
25
+ readonly TIMEOUT: "TIMEOUT";
26
+ readonly PAGE_CHANGED: "PAGE_CHANGED";
27
+ readonly TAB_DISCONNECTED: "TAB_DISCONNECTED";
28
+ };
29
+ export declare const OrderError: z.ZodObject<{
30
+ code: z.ZodString;
31
+ message: z.ZodString;
32
+ attemptsLeft: z.ZodOptional<z.ZodInt>;
33
+ }, z.core.$strip>;
34
+ export type OrderError = z.infer<typeof OrderError>;
35
+ export declare const OrderSuccess: z.ZodObject<{
36
+ id: z.ZodString;
37
+ ok: z.ZodLiteral<true>;
38
+ result: z.ZodUnknown;
39
+ }, z.core.$strip>;
40
+ export declare const OrderFailure: z.ZodObject<{
41
+ id: z.ZodString;
42
+ ok: z.ZodLiteral<false>;
43
+ error: z.ZodObject<{
44
+ code: z.ZodString;
45
+ message: z.ZodString;
46
+ attemptsLeft: z.ZodOptional<z.ZodInt>;
47
+ }, z.core.$strip>;
48
+ }, z.core.$strip>;
49
+ /**
50
+ * The page's answer to an order: exactly one per order, with the same id.
51
+ *
52
+ * @example
53
+ * const done: OrderResponse = { id: 'o-1', ok: true, result: { scrolled: false } };
54
+ * const failed: OrderResponse = { id: 'o-2', ok: false, error: { code: 'TEXT_NOT_FOUND', message: 'That text is not on the screen' } };
55
+ */
56
+ export declare const OrderResponse: z.ZodDiscriminatedUnion<[z.ZodObject<{
57
+ id: z.ZodString;
58
+ ok: z.ZodLiteral<true>;
59
+ result: z.ZodUnknown;
60
+ }, z.core.$strip>, z.ZodObject<{
61
+ id: z.ZodString;
62
+ ok: z.ZodLiteral<false>;
63
+ error: z.ZodObject<{
64
+ code: z.ZodString;
65
+ message: z.ZodString;
66
+ attemptsLeft: z.ZodOptional<z.ZodInt>;
67
+ }, z.core.$strip>;
68
+ }, z.core.$strip>], "ok">;
69
+ export type OrderResponse = z.infer<typeof OrderResponse>;
70
+ //# sourceMappingURL=orders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orders.d.ts","sourceRoot":"","sources":["../src/orders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,8DAA8D;AAC9D,eAAO,MAAM,WAAW,UAAwB,CAAC;AAEjD;;;;;;GAMG;AACH,eAAO,MAAM,KAAK;;;;;iBAKhB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;AAE1C,mHAAmH;AACnH,eAAO,MAAM,iBAAiB;;;;;;;;;CASpB,CAAC;AAEX,eAAO,MAAM,UAAU;;;;iBAIrB,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD,eAAO,MAAM,YAAY;;;;iBAIvB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;;;iBAIvB,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;yBAA2D,CAAC;AACtF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC"}
package/dist/orders.js ADDED
@@ -0,0 +1,51 @@
1
+ import { z } from 'zod';
2
+ /** Screen counter. It increases with every `page.changed`. */
3
+ export const PageCounter = z.int().nonnegative();
4
+ /**
5
+ * An order from the AI to the page. `page` is the screen counter the AI knew when it sent the order: if the
6
+ * screen has changed since, the page answers `PAGE_CHANGED` instead of acting on a screen the AI has not seen.
7
+ *
8
+ * @example
9
+ * const order: Order = { id: 'o-1', action: 'highlight', params: { text: 'Fasting glucose' }, page: 4 };
10
+ */
11
+ export const Order = z.object({
12
+ id: z.string().min(1),
13
+ action: z.string().min(1),
14
+ params: z.record(z.string(), z.unknown()).default({}),
15
+ page: PageCounter,
16
+ });
17
+ /** Error codes defined by the protocol. Actions may add their own, in UPPER_SNAKE_CASE (e.g. `TEXT_NOT_FOUND`). */
18
+ export const ProtocolErrorCode = {
19
+ UNKNOWN_ACTION: 'UNKNOWN_ACTION',
20
+ INVALID_PARAMS: 'INVALID_PARAMS',
21
+ NOT_AVAILABLE: 'NOT_AVAILABLE',
22
+ NEEDS_CONFIRMATION: 'NEEDS_CONFIRMATION',
23
+ INVALID_CODE: 'INVALID_CODE',
24
+ TIMEOUT: 'TIMEOUT',
25
+ PAGE_CHANGED: 'PAGE_CHANGED',
26
+ TAB_DISCONNECTED: 'TAB_DISCONNECTED',
27
+ };
28
+ export const OrderError = z.object({
29
+ code: z.string().regex(/^[A-Z][A-Z0-9_]*$/),
30
+ message: z.string().min(1),
31
+ attemptsLeft: z.int().nonnegative().optional(),
32
+ });
33
+ export const OrderSuccess = z.object({
34
+ id: z.string().min(1),
35
+ ok: z.literal(true),
36
+ result: z.unknown(),
37
+ });
38
+ export const OrderFailure = z.object({
39
+ id: z.string().min(1),
40
+ ok: z.literal(false),
41
+ error: OrderError,
42
+ });
43
+ /**
44
+ * The page's answer to an order: exactly one per order, with the same id.
45
+ *
46
+ * @example
47
+ * const done: OrderResponse = { id: 'o-1', ok: true, result: { scrolled: false } };
48
+ * const failed: OrderResponse = { id: 'o-2', ok: false, error: { code: 'TEXT_NOT_FOUND', message: 'That text is not on the screen' } };
49
+ */
50
+ export const OrderResponse = z.discriminatedUnion('ok', [OrderSuccess, OrderFailure]);
51
+ //# sourceMappingURL=orders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orders.js","sourceRoot":"","sources":["../src/orders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,8DAA8D;AAC9D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACrB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACrD,IAAI,EAAE,WAAW;CAClB,CAAC,CAAC;AAGH,mHAAmH;AACnH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,cAAc,EAAE,gBAAgB;IAChC,cAAc,EAAE,gBAAgB;IAChC,aAAa,EAAE,eAAe;IAC9B,kBAAkB,EAAE,oBAAoB;IACxC,YAAY,EAAE,cAAc;IAC5B,OAAO,EAAE,SAAS;IAClB,YAAY,EAAE,cAAc;IAC5B,gBAAgB,EAAE,kBAAkB;CAC5B,CAAC;AAEX,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC;IAC3C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,YAAY,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;CAC/C,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACrB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IACnB,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE;CACpB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACrB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IACpB,KAAK,EAAE,UAAU;CAClB,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC"}
@@ -0,0 +1,58 @@
1
+ import { z } from 'zod';
2
+ /** Protocol version. Bumped only for incompatible changes; the bridge rejects pages on another version. */
3
+ export declare const PROTOCOL_VERSION = 1;
4
+ export declare const PairingCode: z.ZodString;
5
+ /**
6
+ * First message from the page on every connection. `tabId` identifies the tab across reloads; `token` comes from
7
+ * a previous pairing and skips pairing again.
8
+ *
9
+ * @example
10
+ * const hello: Hello = { type: 'hello', protocolVersion: PROTOCOL_VERSION, tabId: crypto.randomUUID() };
11
+ */
12
+ export declare const Hello: z.ZodObject<{
13
+ type: z.ZodLiteral<"hello">;
14
+ protocolVersion: z.ZodInt;
15
+ tabId: z.ZodString;
16
+ token: z.ZodOptional<z.ZodString>;
17
+ }, z.core.$strip>;
18
+ export type Hello = z.infer<typeof Hello>;
19
+ /**
20
+ * The 6-digit code the page generated and shows on screen. The user reads it to their AI, the AI sends it to the
21
+ * bridge with `pair_tab`, and the bridge pairs the tab whose offer matches.
22
+ */
23
+ export declare const PairOffer: z.ZodObject<{
24
+ type: z.ZodLiteral<"pair_offer">;
25
+ code: z.ZodString;
26
+ }, z.core.$strip>;
27
+ export type PairOffer = z.infer<typeof PairOffer>;
28
+ /** The session is ready. The page keeps `token` to skip pairing next time. */
29
+ export declare const Welcome: z.ZodObject<{
30
+ type: z.ZodLiteral<"welcome">;
31
+ protocolVersion: z.ZodInt;
32
+ token: z.ZodString;
33
+ }, z.core.$strip>;
34
+ export type Welcome = z.infer<typeof Welcome>;
35
+ /**
36
+ * The tab must be paired: the page generates a code, shows it and sends it with `pair_offer`. Sent again when
37
+ * the code expires or after 5 failed attempts.
38
+ */
39
+ export declare const PairRequired: z.ZodObject<{
40
+ type: z.ZodLiteral<"pair_required">;
41
+ }, z.core.$strip>;
42
+ export type PairRequired = z.infer<typeof PairRequired>;
43
+ /** The AI disconnected this tab: its token is revoked and `pair_required` follows. */
44
+ export declare const Unpaired: z.ZodObject<{
45
+ type: z.ZodLiteral<"unpaired">;
46
+ }, z.core.$strip>;
47
+ export type Unpaired = z.infer<typeof Unpaired>;
48
+ /** A session error. The bridge closes the connection right after sending it. */
49
+ export declare const SessionError: z.ZodObject<{
50
+ type: z.ZodLiteral<"session_error">;
51
+ code: z.ZodEnum<{
52
+ VERSION_MISMATCH: "VERSION_MISMATCH";
53
+ INVALID_MESSAGE: "INVALID_MESSAGE";
54
+ }>;
55
+ message: z.ZodString;
56
+ }, z.core.$strip>;
57
+ export type SessionError = z.infer<typeof SessionError>;
58
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,2GAA2G;AAC3G,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,eAAO,MAAM,WAAW,aAA8B,CAAC;AAEvD;;;;;;GAMG;AACH,eAAO,MAAM,KAAK;;;;;iBAKhB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;AAE1C;;;GAGG;AACH,eAAO,MAAM,SAAS;;;iBAGpB,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AAElD,8EAA8E;AAC9E,eAAO,MAAM,OAAO;;;;iBAIlB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC;AAE9C;;;GAGG;AACH,eAAO,MAAM,YAAY;;iBAEvB,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAExD,sFAAsF;AACtF,eAAO,MAAM,QAAQ;;iBAEnB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD,gFAAgF;AAChF,eAAO,MAAM,YAAY;;;;;;;iBAIvB,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { z } from 'zod';
2
+ /** Protocol version. Bumped only for incompatible changes; the bridge rejects pages on another version. */
3
+ export const PROTOCOL_VERSION = 1;
4
+ export const PairingCode = z.string().regex(/^\d{6}$/);
5
+ /**
6
+ * First message from the page on every connection. `tabId` identifies the tab across reloads; `token` comes from
7
+ * a previous pairing and skips pairing again.
8
+ *
9
+ * @example
10
+ * const hello: Hello = { type: 'hello', protocolVersion: PROTOCOL_VERSION, tabId: crypto.randomUUID() };
11
+ */
12
+ export const Hello = z.object({
13
+ type: z.literal('hello'),
14
+ protocolVersion: z.int().positive(),
15
+ tabId: z.string().min(1),
16
+ token: z.string().min(1).optional(),
17
+ });
18
+ /**
19
+ * The 6-digit code the page generated and shows on screen. The user reads it to their AI, the AI sends it to the
20
+ * bridge with `pair_tab`, and the bridge pairs the tab whose offer matches.
21
+ */
22
+ export const PairOffer = z.object({
23
+ type: z.literal('pair_offer'),
24
+ code: PairingCode,
25
+ });
26
+ /** The session is ready. The page keeps `token` to skip pairing next time. */
27
+ export const Welcome = z.object({
28
+ type: z.literal('welcome'),
29
+ protocolVersion: z.int().positive(),
30
+ token: z.string().min(1),
31
+ });
32
+ /**
33
+ * The tab must be paired: the page generates a code, shows it and sends it with `pair_offer`. Sent again when
34
+ * the code expires or after 5 failed attempts.
35
+ */
36
+ export const PairRequired = z.object({
37
+ type: z.literal('pair_required'),
38
+ });
39
+ /** The AI disconnected this tab: its token is revoked and `pair_required` follows. */
40
+ export const Unpaired = z.object({
41
+ type: z.literal('unpaired'),
42
+ });
43
+ /** A session error. The bridge closes the connection right after sending it. */
44
+ export const SessionError = z.object({
45
+ type: z.literal('session_error'),
46
+ code: z.enum(['VERSION_MISMATCH', 'INVALID_MESSAGE']),
47
+ message: z.string().min(1),
48
+ });
49
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,2GAA2G;AAC3G,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAElC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACxB,eAAe,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACnC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC;AAGH;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;IAC7B,IAAI,EAAE,WAAW;CAClB,CAAC,CAAC;AAGH,8EAA8E;AAC9E,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IAC1B,eAAe,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACnC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACzB,CAAC,CAAC;AAGH;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC;CACjC,CAAC,CAAC;AAGH,sFAAsF;AACtF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;CAC5B,CAAC,CAAC;AAGH,gFAAgF;AAChF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,kBAAkB,EAAE,iBAAiB,CAAC,CAAC;IACrD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC3B,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,34 @@
1
1
  {
2
2
  "name": "@reins-ai/contract",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "Protocol between the page and the bridge: zod schemas and types.",
5
+ "license": "MIT",
6
+ "author": "Sanoriva",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/sanoriva/reins.git",
10
+ "directory": "packages/agent-contract"
11
+ },
12
+ "homepage": "https://github.com/sanoriva/reins/tree/main/packages/agent-contract#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/sanoriva/reins/issues"
15
+ },
16
+ "type": "module",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./dist/index.js"
21
+ }
22
+ },
23
+ "sideEffects": false,
24
+ "scripts": {
25
+ "build": "tsc -p tsconfig.json",
26
+ "test": "node --import tsx --test \"__tests__/**/*.test.ts\""
27
+ },
28
+ "dependencies": {
29
+ "zod": "^4.3.6"
30
+ },
31
+ "files": [
32
+ "dist"
33
+ ]
34
+ }