@nexus-code/remote-protocol 0.0.0-stage → 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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"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"}
package/dist/view.js ADDED
@@ -0,0 +1,260 @@
1
+ /**
2
+ * A chat as another device draws it: the conversation the serving device's
3
+ * app already made of its program's log, trimmed of what only that app
4
+ * uses. The shapes follow the desktop app's chat model, so its chat view can
5
+ * draw a remote one as it draws its own; Claude Code's and Codex's own
6
+ * formats stay on the serving device, which keeps up with their versions.
7
+ *
8
+ * An item or call of a kind this version does not know stays parseable
9
+ * (UnknownItemSchema): a newer device may send more, and an older one skips it.
10
+ */
11
+ import { z } from "zod";
12
+ /** An image a message or a tool result holds. Its bytes stay on the serving device in v1. */
13
+ export const ImageRefSchema = z.object({
14
+ mediaType: z.string(),
15
+ /** How many bytes the image takes. */
16
+ bytes: z.number().int().nonnegative(),
17
+ });
18
+ const at = z.number().optional();
19
+ export const UserItemSchema = z.object({
20
+ kind: z.literal("user"),
21
+ key: z.string(),
22
+ text: z.string(),
23
+ images: z.array(ImageRefSchema),
24
+ /** sent: written to the program; taken: the program read it. */
25
+ state: z.enum(["sent", "taken"]),
26
+ /** Written during a turn and not read yet: it waits above the composer. */
27
+ queued: z.boolean().optional(),
28
+ at,
29
+ });
30
+ export const AssistantBlockSchema = z.discriminatedUnion("type", [
31
+ z.object({ type: z.literal("text"), text: z.string() }),
32
+ z.object({ type: z.literal("thinking"), text: z.string() }),
33
+ z.object({ type: z.literal("tool"), toolUseId: z.string() }),
34
+ ]);
35
+ export const AssistantItemSchema = z.object({
36
+ kind: z.literal("assistant"),
37
+ key: z.string(),
38
+ messageId: z.string(),
39
+ blocks: z.array(AssistantBlockSchema),
40
+ at,
41
+ });
42
+ export const NoticeItemSchema = z.object({
43
+ kind: z.literal("notice"),
44
+ key: z.string(),
45
+ /** interrupted, exited, restarted, compacted, cleared, error…: a code the app names. */
46
+ code: z.string(),
47
+ detail: z.string().optional(),
48
+ at,
49
+ });
50
+ /**
51
+ * Where an agent that sent a message can be answered: its tab, on the
52
+ * device `deviceId` (absent: the device this chat runs on). `nexus chat
53
+ * send` takes it as it is.
54
+ */
55
+ export const ReplyAddressSchema = z.object({
56
+ deviceId: z.string().optional(),
57
+ workspaceId: z.string(),
58
+ tabId: z.string(),
59
+ });
60
+ /** A message the program took that the user did not write: another session's, a channel's. */
61
+ export const ReceivedItemSchema = z.object({
62
+ kind: z.literal("received"),
63
+ key: z.string(),
64
+ from: z.object({
65
+ kind: z.string(),
66
+ name: z.string().optional(),
67
+ agent: z.string().optional(),
68
+ /** Sent from another device of the account: which one, as it names itself. */
69
+ device: z.object({ id: z.string(), name: z.string() }).optional(),
70
+ /** Where the sender takes an answer. */
71
+ replyTo: ReplyAddressSchema.optional(),
72
+ }),
73
+ text: z.string(),
74
+ at,
75
+ });
76
+ export const TaskEndItemSchema = z.object({
77
+ kind: z.literal("task_end"),
78
+ key: z.string(),
79
+ taskId: z.string(),
80
+ status: z.string(),
81
+ description: z.string().optional(),
82
+ taskType: z.string().optional(),
83
+ summary: z.string().optional(),
84
+ toolUseId: z.string().optional(),
85
+ wakes: z.boolean().optional(),
86
+ at,
87
+ });
88
+ export const ShellItemSchema = z.object({
89
+ kind: z.literal("shell"),
90
+ key: z.string(),
91
+ command: z.string(),
92
+ stdout: z.string().optional(),
93
+ stderr: z.string().optional(),
94
+ at,
95
+ });
96
+ /** The item kinds this version knows. */
97
+ export const ITEM_KINDS = new Set([
98
+ "user",
99
+ "assistant",
100
+ "notice",
101
+ "received",
102
+ "task_end",
103
+ "shell",
104
+ ]);
105
+ /**
106
+ * An item of a kind this version does not know: kept so the list stays
107
+ * whole, and not drawn. A known kind that does not fit its shape is no such item.
108
+ */
109
+ export const UnknownItemSchema = z
110
+ .object({ kind: z.string().refine((kind) => !ITEM_KINDS.has(kind)), key: z.string() })
111
+ .passthrough();
112
+ export const ViewItemSchema = z.union([
113
+ UserItemSchema,
114
+ AssistantItemSchema,
115
+ NoticeItemSchema,
116
+ ReceivedItemSchema,
117
+ TaskEndItemSchema,
118
+ ShellItemSchema,
119
+ UnknownItemSchema,
120
+ ]);
121
+ /** Most characters of a tool's result text sent; the rest is cut (`truncated`). */
122
+ export const MAX_RESULT_TEXT = 64 * 1024;
123
+ export const ViewToolCallSchema = z.object({
124
+ id: z.string(),
125
+ name: z.string(),
126
+ displayName: z.string().optional(),
127
+ input: z.unknown(),
128
+ /** streaming, running, done, error, denied, stopped. */
129
+ status: z.string(),
130
+ result: z
131
+ .object({
132
+ text: z.string(),
133
+ isError: z.boolean(),
134
+ /** The program's structured result: a run's stdout, an edit's patch. */
135
+ structured: z.unknown().optional(),
136
+ images: z.array(ImageRefSchema),
137
+ /** The text was longer than MAX_RESULT_TEXT and is cut there. */
138
+ truncated: z.boolean().optional(),
139
+ })
140
+ .optional(),
141
+ /** The agent call it runs under; null on the main thread. */
142
+ parentToolUseId: z.string().nullable(),
143
+ });
144
+ /** A tool the program asks to run, which the user allows or denies. */
145
+ export const ViewPermissionSchema = z.object({
146
+ requestId: z.string(),
147
+ toolName: z.string(),
148
+ displayName: z.string().optional(),
149
+ input: z.record(z.unknown()),
150
+ description: z.string().optional(),
151
+ decisionReason: z.string().optional(),
152
+ toolUseId: z.string().optional(),
153
+ /** A subagent's request. */
154
+ agentId: z.string().optional(),
155
+ /** The call as the card previews it, when the input alone does not tell it. */
156
+ preview: ViewToolCallSchema.optional(),
157
+ /**
158
+ * What "always allow" would add, one choice each, in the serving
159
+ * device's words ("Allow Bash(npm test:*) in this folder"): chat.answer
160
+ * picks them by index.
161
+ */
162
+ suggestions: z.array(z.object({ label: z.string() })).optional(),
163
+ });
164
+ /** A task the program runs beside the turn: a background run, a subagent. */
165
+ export const ViewTaskSchema = z.object({
166
+ taskId: z.string(),
167
+ type: z.string(),
168
+ description: z.string(),
169
+ status: z.string(),
170
+ toolUseId: z.string().optional(),
171
+ startedAt: z.number().optional(),
172
+ endedAt: z.number().optional(),
173
+ summary: z.string().optional(),
174
+ activity: z.string().optional(),
175
+ });
176
+ /** The reply being written: what the program streamed of its next message so far. */
177
+ export const ViewStreamingSchema = z.object({
178
+ messageId: z.string(),
179
+ blocks: z.array(z.object({
180
+ type: z.enum(["text", "thinking", "tool_use"]),
181
+ text: z.string(),
182
+ toolUseId: z.string().optional(),
183
+ })),
184
+ });
185
+ /** Where a chat stands, apart from its messages. */
186
+ export const ChatStatusSchema = z.object({
187
+ agent: z.enum(["claude", "codex"]),
188
+ title: z.string(),
189
+ /** The model it runs, as its program names it. */
190
+ model: z.string().optional(),
191
+ effort: z.string().optional(),
192
+ permissionMode: z.string().optional(),
193
+ /** A turn is under way. */
194
+ running: z.boolean(),
195
+ process: z.enum(["none", "running", "exited"]),
196
+ turn: z
197
+ .object({
198
+ startedAt: z.number().optional(),
199
+ outputTokens: z.number(),
200
+ /** requesting, compacting… */
201
+ status: z.string().optional(),
202
+ })
203
+ .nullable(),
204
+ streaming: ViewStreamingSchema.nullable(),
205
+ permissions: z.array(ViewPermissionSchema),
206
+ });
207
+ /** One step of the agent's to-do list. */
208
+ export const ViewTodoSchema = z.object({
209
+ content: z.string(),
210
+ /** pending, in_progress or completed. */
211
+ status: z.string(),
212
+ });
213
+ /** A subagent the turn called (an Agent tool call). */
214
+ export const ViewAgentRowSchema = z.object({
215
+ toolUseId: z.string(),
216
+ description: z.string(),
217
+ /** running, completed, failed or stopped. */
218
+ status: z.string(),
219
+ startedAt: z.number().optional(),
220
+ endedAt: z.number().optional(),
221
+ });
222
+ /** A goal the chat works toward (/goal), and where it stands. */
223
+ export const ViewGoalSchema = z.object({
224
+ condition: z.string(),
225
+ /** active, paused, met or failed. */
226
+ status: z.string(),
227
+ setAt: z.number().optional(),
228
+ /** How many checks found it unmet so far. */
229
+ checks: z.number().int().nonnegative(),
230
+ /** Once it ended: why. */
231
+ reason: z.string().optional(),
232
+ });
233
+ /**
234
+ * What the chat's side panel shows beside the conversation: the to-do
235
+ * list, the tasks and subagents, the files it changed, the context it
236
+ * fills, what it cost, and its goal.
237
+ */
238
+ export const ChatPanelSchema = z.object({
239
+ todos: z.array(ViewTodoSchema),
240
+ /** Background runs and the like, by the program's task ids (chat.stopTask stops one). */
241
+ tasks: z.array(ViewTaskSchema),
242
+ agents: z.array(ViewAgentRowSchema),
243
+ changedFiles: z.array(z.object({
244
+ /** Absolute, on the serving device, as the chat's tool calls name it. */
245
+ path: z.string(),
246
+ added: z.number().int().nonnegative().optional(),
247
+ removed: z.number().int().nonnegative().optional(),
248
+ })),
249
+ /** The context window: tokens in it, and how many it takes; null before the program said. */
250
+ context: z
251
+ .object({
252
+ usedTokens: z.number().int().nonnegative(),
253
+ maxTokens: z.number().int().positive(),
254
+ })
255
+ .nullable(),
256
+ /** What the conversation cost so far, in US dollars, when the program tells it. */
257
+ costUsd: z.number().nonnegative().optional(),
258
+ goal: ViewGoalSchema.nullable(),
259
+ });
260
+ //# sourceMappingURL=view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * The voice socket: what a device says goes to the server as audio and
3
+ * comes back as text while it speaks (streaming speech to text).
4
+ *
5
+ * GET /voice?v=1&lang=<language> upgrades to a WebSocket, signed in as
6
+ * /relay is (a Bearer header, or ?ticket= from POST /relay/ticket). Then:
7
+ * - server: `ready`, naming the audio format and sample rate to send, and
8
+ * the most seconds this session may take;
9
+ * - client: binary frames of audio in that format, about 100 ms each, then
10
+ * `end` when the user stops;
11
+ * - server, as they come: `partial` (the words so far of the segment being
12
+ * spoken; each replaces the last) and `final` (a finished segment, to
13
+ * append; it clears the partial). Every partial and final after the
14
+ * session's first final starts with the space its language puts between
15
+ * segments (none for ja or zh): the text is the finals joined as they
16
+ * came, then the partial, with nothing trimmed or added between;
17
+ * - server: `limit` if the audio ran past what the session or the
18
+ * account's quota allows (audio past it is dropped; finals still come);
19
+ * - server: `done` with the seconds counted, once every final is out; then
20
+ * it closes (1000). An `error` ends the session; it closes after.
21
+ */
22
+ import { z } from "zod";
23
+ export declare const VOICE_VERSION = 1;
24
+ /** Most bytes in one audio frame (2 s of 16 kHz 16-bit mono); an even count. */
25
+ export declare const MAX_AUDIO_FRAME_BYTES: number;
26
+ /** The language to hear, BCP 47-ish: "ko", "en", "en-US", or "multi" to detect it. */
27
+ export declare const VoiceLanguageSchema: z.ZodString;
28
+ /** What a device sends besides audio: that the user stopped speaking. */
29
+ export declare const VoiceClientMessageSchema: z.ZodObject<{
30
+ t: z.ZodLiteral<"end">;
31
+ }, "strip", z.ZodTypeAny, {
32
+ t: "end";
33
+ }, {
34
+ t: "end";
35
+ }>;
36
+ export type VoiceClientMessage = z.infer<typeof VoiceClientMessageSchema>;
37
+ export declare const VoiceReadySchema: z.ZodObject<{
38
+ t: z.ZodLiteral<"ready">;
39
+ format: z.ZodLiteral<"pcm_s16le">;
40
+ /** The rate to send at; it may change with the provider, so it is not to be assumed. */
41
+ sampleRate: z.ZodNumber;
42
+ /** The fewer of the session's limit and what is left of the month's quota. */
43
+ maxSeconds: z.ZodNumber;
44
+ }, "strip", z.ZodTypeAny, {
45
+ t: "ready";
46
+ format: "pcm_s16le";
47
+ sampleRate: number;
48
+ maxSeconds: number;
49
+ }, {
50
+ t: "ready";
51
+ format: "pcm_s16le";
52
+ sampleRate: number;
53
+ maxSeconds: number;
54
+ }>;
55
+ export declare const VoiceServerMessageSchema: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
56
+ t: z.ZodLiteral<"ready">;
57
+ format: z.ZodLiteral<"pcm_s16le">;
58
+ /** The rate to send at; it may change with the provider, so it is not to be assumed. */
59
+ sampleRate: z.ZodNumber;
60
+ /** The fewer of the session's limit and what is left of the month's quota. */
61
+ maxSeconds: z.ZodNumber;
62
+ }, "strip", z.ZodTypeAny, {
63
+ t: "ready";
64
+ format: "pcm_s16le";
65
+ sampleRate: number;
66
+ maxSeconds: number;
67
+ }, {
68
+ t: "ready";
69
+ format: "pcm_s16le";
70
+ sampleRate: number;
71
+ maxSeconds: number;
72
+ }>, z.ZodObject<{
73
+ t: z.ZodLiteral<"partial">;
74
+ text: z.ZodString;
75
+ }, "strip", z.ZodTypeAny, {
76
+ t: "partial";
77
+ text: string;
78
+ }, {
79
+ t: "partial";
80
+ text: string;
81
+ }>, z.ZodObject<{
82
+ t: z.ZodLiteral<"final">;
83
+ text: z.ZodString;
84
+ }, "strip", z.ZodTypeAny, {
85
+ t: "final";
86
+ text: string;
87
+ }, {
88
+ t: "final";
89
+ text: string;
90
+ }>, z.ZodObject<{
91
+ t: z.ZodLiteral<"limit">;
92
+ reason: z.ZodEnum<["session", "quota"]>;
93
+ }, "strip", z.ZodTypeAny, {
94
+ t: "limit";
95
+ reason: "session" | "quota";
96
+ }, {
97
+ t: "limit";
98
+ reason: "session" | "quota";
99
+ }>, z.ZodObject<{
100
+ t: z.ZodLiteral<"done">;
101
+ seconds: z.ZodNumber;
102
+ }, "strip", z.ZodTypeAny, {
103
+ t: "done";
104
+ seconds: number;
105
+ }, {
106
+ t: "done";
107
+ seconds: number;
108
+ }>, z.ZodObject<{
109
+ t: z.ZodLiteral<"error">;
110
+ /** unauthorized: the device's sign-in ended (the socket closes 4001 after it). */
111
+ code: z.ZodEnum<["bad-frame", "provider-error", "unauthorized"]>;
112
+ message: z.ZodString;
113
+ }, "strip", z.ZodTypeAny, {
114
+ code: "bad-frame" | "unauthorized" | "provider-error";
115
+ message: string;
116
+ t: "error";
117
+ }, {
118
+ code: "bad-frame" | "unauthorized" | "provider-error";
119
+ message: string;
120
+ t: "error";
121
+ }>]>;
122
+ export type VoiceServerMessage = z.infer<typeof VoiceServerMessageSchema>;
123
+ /** GET /voice/usage: this month's seconds, used and allowed. */
124
+ export declare const VoiceUsageSchema: z.ZodObject<{
125
+ /** The month, as YYYY-MM. */
126
+ period: z.ZodString;
127
+ usedSeconds: z.ZodNumber;
128
+ limitSeconds: z.ZodNumber;
129
+ }, "strip", z.ZodTypeAny, {
130
+ period: string;
131
+ usedSeconds: number;
132
+ limitSeconds: number;
133
+ }, {
134
+ period: string;
135
+ usedSeconds: number;
136
+ limitSeconds: number;
137
+ }>;
138
+ export type VoiceUsage = z.infer<typeof VoiceUsageSchema>;
139
+ //# sourceMappingURL=voice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice.d.ts","sourceRoot":"","sources":["../src/voice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,aAAa,IAAI,CAAC;AAE/B,gFAAgF;AAChF,eAAO,MAAM,qBAAqB,QAAY,CAAC;AAE/C,sFAAsF;AACtF,eAAO,MAAM,mBAAmB,aAAuD,CAAC;AAExF,yEAAyE;AACzE,eAAO,MAAM,wBAAwB;;;;;;EAAoC,CAAC;AAC1E,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,gBAAgB;;;IAG3B,wFAAwF;;IAExF,8EAA8E;;;;;;;;;;;;EAE9E,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;IANnC,wFAAwF;;IAExF,8EAA8E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAY5E,kFAAkF;;;;;;;;;;;IAIpF,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,gEAAgE;AAChE,eAAO,MAAM,gBAAgB;IAC3B,6BAA6B;;;;;;;;;;;;EAI7B,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
package/dist/voice.js ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The voice socket: what a device says goes to the server as audio and
3
+ * comes back as text while it speaks (streaming speech to text).
4
+ *
5
+ * GET /voice?v=1&lang=<language> upgrades to a WebSocket, signed in as
6
+ * /relay is (a Bearer header, or ?ticket= from POST /relay/ticket). Then:
7
+ * - server: `ready`, naming the audio format and sample rate to send, and
8
+ * the most seconds this session may take;
9
+ * - client: binary frames of audio in that format, about 100 ms each, then
10
+ * `end` when the user stops;
11
+ * - server, as they come: `partial` (the words so far of the segment being
12
+ * spoken; each replaces the last) and `final` (a finished segment, to
13
+ * append; it clears the partial). Every partial and final after the
14
+ * session's first final starts with the space its language puts between
15
+ * segments (none for ja or zh): the text is the finals joined as they
16
+ * came, then the partial, with nothing trimmed or added between;
17
+ * - server: `limit` if the audio ran past what the session or the
18
+ * account's quota allows (audio past it is dropped; finals still come);
19
+ * - server: `done` with the seconds counted, once every final is out; then
20
+ * it closes (1000). An `error` ends the session; it closes after.
21
+ */
22
+ import { z } from "zod";
23
+ export const VOICE_VERSION = 1;
24
+ /** Most bytes in one audio frame (2 s of 16 kHz 16-bit mono); an even count. */
25
+ export const MAX_AUDIO_FRAME_BYTES = 64 * 1024;
26
+ /** The language to hear, BCP 47-ish: "ko", "en", "en-US", or "multi" to detect it. */
27
+ export const VoiceLanguageSchema = z.string().regex(/^([a-z]{2,3}(-[A-Z]{2})?|multi)$/);
28
+ /** What a device sends besides audio: that the user stopped speaking. */
29
+ export const VoiceClientMessageSchema = z.object({ t: z.literal("end") });
30
+ export const VoiceReadySchema = z.object({
31
+ t: z.literal("ready"),
32
+ format: z.literal("pcm_s16le"),
33
+ /** The rate to send at; it may change with the provider, so it is not to be assumed. */
34
+ sampleRate: z.number().int().positive(),
35
+ /** The fewer of the session's limit and what is left of the month's quota. */
36
+ maxSeconds: z.number().nonnegative(),
37
+ });
38
+ export const VoiceServerMessageSchema = z.discriminatedUnion("t", [
39
+ VoiceReadySchema,
40
+ z.object({ t: z.literal("partial"), text: z.string() }),
41
+ z.object({ t: z.literal("final"), text: z.string() }),
42
+ z.object({ t: z.literal("limit"), reason: z.enum(["session", "quota"]) }),
43
+ z.object({ t: z.literal("done"), seconds: z.number().nonnegative() }),
44
+ z.object({
45
+ t: z.literal("error"),
46
+ /** unauthorized: the device's sign-in ended (the socket closes 4001 after it). */
47
+ code: z.enum(["bad-frame", "provider-error", "unauthorized"]),
48
+ message: z.string(),
49
+ }),
50
+ ]);
51
+ /** GET /voice/usage: this month's seconds, used and allowed. */
52
+ export const VoiceUsageSchema = z.object({
53
+ /** The month, as YYYY-MM. */
54
+ period: z.string(),
55
+ usedSeconds: z.number().nonnegative(),
56
+ limitSeconds: z.number().nonnegative(),
57
+ });
58
+ //# sourceMappingURL=voice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice.js","sourceRoot":"","sources":["../src/voice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC;AAE/B,gFAAgF;AAChF,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,GAAG,IAAI,CAAC;AAE/C,sFAAsF;AACtF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;AAExF,yEAAyE;AACzE,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAG1E,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACrB,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;IAC9B,wFAAwF;IACxF,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACvC,8EAA8E;IAC9E,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE;CACrC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE;IAChE,gBAAgB;IAChB,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IACvD,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IACrD,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IACzE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;IACrE,CAAC,CAAC,MAAM,CAAC;QACP,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;QACrB,kFAAkF;QAClF,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,gBAAgB,EAAE,cAAc,CAAC,CAAC;QAC7D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;KACpB,CAAC;CACH,CAAC,CAAC;AAGH,gEAAgE;AAChE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,6BAA6B;IAC7B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE;IACrC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE;CACvC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,38 @@
1
1
  {
2
2
  "name": "@nexus-code/remote-protocol",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "NexusCode's remote protocol: the relay's frames and the end-to-end RPC between a user's devices",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/moreih29/nexus-code.git",
9
+ "directory": "packages/remote-protocol"
10
+ },
11
+ "type": "module",
12
+ "main": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ },
19
+ "./package.json": "./package.json"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "src",
24
+ "README.md",
25
+ "ACCOUNT_KEYS.md"
26
+ ],
27
+ "sideEffects": false,
28
+ "scripts": {
29
+ "build": "rm -rf dist && tsc -p tsconfig.build.json",
30
+ "prepublishOnly": "npm run build"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "peerDependencies": {
36
+ "zod": "^3.25.0"
37
+ }
38
+ }
package/src/account.ts ADDED
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The account key, locked with the account password: the server keeps the
3
+ * locked bundle and hands it to the account's devices, which open it on
4
+ * their own (see ../ACCOUNT_KEYS.md). The server never sees the password,
5
+ * the key, or anything made from them; it only checks the bundle's shape.
6
+ */
7
+ import { z } from "zod";
8
+ import { Base64UrlSchema } from "./relay.js";
9
+
10
+ /** The associated data the key is sealed with: the user's id and the key's version, so a bundle cannot pass for another's. */
11
+ export function bundleAadOf(userId: string, kid: number): string {
12
+ return `nexus-remote/account-key/v1|${userId}|${kid}`;
13
+ }
14
+
15
+ /** Argon2id's settings, as libsodium's crypto_pwhash takes them (ALG_ARGON2ID13). */
16
+ export const KdfSchema = z.object({
17
+ alg: z.literal("argon2id13"),
18
+ /** crypto_pwhash's opslimit. */
19
+ ops: z.number().int().min(1).max(10),
20
+ /** crypto_pwhash's memlimit, in bytes. */
21
+ mem: z
22
+ .number()
23
+ .int()
24
+ .min(16 * 1024 * 1024)
25
+ .max(1024 * 1024 * 1024),
26
+ /** 16 random bytes. */
27
+ salt: Base64UrlSchema,
28
+ });
29
+ export type Kdf = z.infer<typeof KdfSchema>;
30
+
31
+ /** The settings a new bundle is locked with; a bundle keeps its own, so these can grow. */
32
+ export const DEFAULT_KDF = { alg: "argon2id13", ops: 3, mem: 64 * 1024 * 1024 } as const;
33
+
34
+ /**
35
+ * The account key (32 bytes) sealed with XChaCha20-Poly1305 under the key
36
+ * the password makes with `kdf`, with bundleAadOf(userId, kid) as the
37
+ * associated data. `kid` is the account key's version, which sealed frames
38
+ * name; it goes up when the key is made anew.
39
+ */
40
+ export const KeyBundleSchema = z.object({
41
+ v: z.literal(1),
42
+ kid: z.number().int().positive(),
43
+ kdf: KdfSchema,
44
+ /** 24 random bytes. */
45
+ nonce: Base64UrlSchema,
46
+ box: Base64UrlSchema,
47
+ });
48
+ export type KeyBundle = z.infer<typeof KeyBundleSchema>;
49
+
50
+ /** GET /account/key-bundle: the bundle and its version on the server, or 404 before there is one. */
51
+ export const KeyBundleResponseSchema = z.object({
52
+ bundle: KeyBundleSchema,
53
+ /** Counts the bundle's writes, for the next PUT to say which one it replaces. */
54
+ version: z.number().int().positive(),
55
+ });
56
+ export type KeyBundleResponse = z.infer<typeof KeyBundleResponseSchema>;
57
+
58
+ /**
59
+ * PUT /account/key-bundle. `expected` is the version it replaces, or null
60
+ * for the first bundle; the server answers 409 when another write came
61
+ * first. A new password locks the same key (same kid); a reset puts a new
62
+ * key (kid + 1), which the account's other devices take once they are told
63
+ * the new password.
64
+ */
65
+ export const KeyBundlePutSchema = z.object({
66
+ bundle: KeyBundleSchema,
67
+ expected: z.number().int().positive().nullable(),
68
+ });
69
+ export type KeyBundlePut = z.infer<typeof KeyBundlePutSchema>;
package/src/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * NexusCode's remote protocol, in two layers, and the account key's bundle:
3
+ * - ./relay: the frames between a device and its account's room on the
4
+ * relay, which the relay reads and routes;
5
+ * - ./sealed, ./rpc, ./view: what a sealed frame carries between two
6
+ * devices of the account, which only they can open;
7
+ * - ./account: the account key, locked with the account password, as the
8
+ * server keeps it;
9
+ * - ./voice: the voice socket, speech to text while the user speaks;
10
+ * - ./info: what the server offers (GET /info).
11
+ */
12
+ export * from "./account.js";
13
+ export * from "./info.js";
14
+ export * from "./relay.js";
15
+ export * from "./rpc.js";
16
+ export * from "./sealed.js";
17
+ export * from "./view.js";
18
+ export * from "./voice.js";
package/src/info.ts ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * GET /info, signed in or not: what the server offers, so a device shows
3
+ * only what works there.
4
+ */
5
+ import { z } from "zod";
6
+
7
+ export const ServerInfoSchema = z.object({
8
+ /**
9
+ * The sign-ins the server has, each its own /auth/<name>/start: "google",
10
+ * "github", and "dev" only on a server at localhost. A device offers one
11
+ * button for each it knows.
12
+ */
13
+ signIn: z.array(z.string()),
14
+ relay: z.object({ version: z.number().int() }).nullable(),
15
+ /** Null where the server has no speech-to-text provider: no microphone then. */
16
+ voice: z.object({ version: z.number().int() }).nullable(),
17
+ });
18
+ export type ServerInfo = z.infer<typeof ServerInfoSchema>;