@ccmsg/protocol 1.20.0 → 1.22.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 +2 -2
- package/package.json +1 -1
- package/src/attributes.ts +77 -52
- package/src/common/auth.ts +28 -28
- package/src/common/hello.ts +72 -34
- package/src/common/ping.ts +2 -2
- package/src/common/shutdown.ts +4 -4
- package/src/common/topics.ts +24 -19
- package/src/control/dump.ts +73 -66
- package/src/control/files.ts +24 -24
- package/src/control/kv.ts +6 -6
- package/src/control/launcher.ts +4 -4
- package/src/control/llm.ts +8 -8
- package/src/control/sandbox.ts +4 -4
- package/src/control/session-errors.ts +3 -3
- package/src/control/session-status.ts +2 -2
- package/src/control/session.ts +36 -35
- package/src/control/transcript.ts +6 -6
- package/src/control/translate.ts +2 -2
- package/src/envelope.ts +2 -2
- package/src/errors.ts +1 -1
- package/src/fixtures/common.ts +45 -32
- package/src/fixtures/control.ts +67 -67
- package/src/fixtures/index.ts +77 -63
- package/src/fixtures/messaging.ts +9 -9
- package/src/fixtures/topics.ts +9 -9
- package/src/identifiers.ts +8 -6
- package/src/messaging/message.ts +3 -3
- package/src/messaging/notify.ts +3 -3
- package/src/messaging/say.ts +9 -9
- package/src/schemas.ts +79 -67
- package/src/session-meta.ts +2 -1
package/README.md
CHANGED
|
@@ -20,8 +20,8 @@ bun add @ccmsg/protocol
|
|
|
20
20
|
import { isValid, MessageSendRequest, OP_ATTRIBUTES, opErrors } from "@ccmsg/protocol";
|
|
21
21
|
|
|
22
22
|
isValid(MessageSendRequest, incoming); // validating the wire is the contract's job
|
|
23
|
-
OP_ATTRIBUTES.
|
|
24
|
-
opErrors("
|
|
23
|
+
OP_ATTRIBUTES["message.send"].roles; // authorization reads the table, not a branch
|
|
24
|
+
opErrors("session.rename"); // the codes this op may answer with
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
## Documentation
|
package/package.json
CHANGED
package/src/attributes.ts
CHANGED
|
@@ -17,7 +17,14 @@ export interface OpAttributes {
|
|
|
17
17
|
readonly plane: Plane;
|
|
18
18
|
/** Roles allowed to call the op. A role outside this set gets `forbidden`. */
|
|
19
19
|
readonly roles: readonly Role[];
|
|
20
|
-
/** Whether the op requires an identity settled by
|
|
20
|
+
/** Whether the op requires an identity settled by a greeting.
|
|
21
|
+
*
|
|
22
|
+
* On a WebSocket connection the only ops that may arrive before one are the
|
|
23
|
+
* three greetings: a caller that will not say who it is has nothing to be
|
|
24
|
+
* answered, and whether the instance is there is already known once the
|
|
25
|
+
* connection was made. The ops carried over HTTP answer before any connection exists, which is
|
|
26
|
+
* what `carrier` says; `needs_hello` is false on them because there is no
|
|
27
|
+
* greeting to have sent, not because they are open on a settled one. */
|
|
21
28
|
readonly needs_hello: boolean;
|
|
22
29
|
/** The capability the op needs, when it needs one. */
|
|
23
30
|
readonly capability?: Capability;
|
|
@@ -51,32 +58,50 @@ const INSTANCE_ONLY = ["instance"] as const;
|
|
|
51
58
|
* facts live: authorization, capability gating and forwarding all read it
|
|
52
59
|
* rather than each carrying their own copy. */
|
|
53
60
|
export const OP_ATTRIBUTES = {
|
|
54
|
-
// --- common: connect, declare the end, and subscribe (
|
|
55
|
-
//
|
|
61
|
+
// --- common: connect, declare the end, and subscribe (15) ---
|
|
62
|
+
// A greeting settles what the connection is, and there is one per role: what
|
|
63
|
+
// each must carry is then the op's own schema rather than a rule read off a
|
|
64
|
+
// field, and a connection cannot be settled as something neither side meant.
|
|
65
|
+
//
|
|
66
|
+
// The greetings and `instance.ping` address the instance the caller reached, so
|
|
56
67
|
// there is nothing to forward and no unreachable instance to report — which
|
|
57
68
|
// is why they are `cluster` despite answering about one instance.
|
|
58
|
-
hello: {
|
|
69
|
+
"hello.session": {
|
|
70
|
+
plane: "common",
|
|
71
|
+
roles: ALL_ROLES,
|
|
72
|
+
needs_hello: false,
|
|
73
|
+
locality: "cluster",
|
|
74
|
+
errors: [],
|
|
75
|
+
},
|
|
76
|
+
"hello.user": {
|
|
59
77
|
plane: "common",
|
|
60
78
|
roles: ALL_ROLES,
|
|
61
79
|
needs_hello: false,
|
|
62
80
|
locality: "cluster",
|
|
63
81
|
errors: [],
|
|
64
82
|
},
|
|
65
|
-
|
|
83
|
+
"hello.instance": {
|
|
66
84
|
plane: "common",
|
|
67
85
|
roles: ALL_ROLES,
|
|
68
86
|
needs_hello: false,
|
|
69
87
|
locality: "cluster",
|
|
70
88
|
errors: [],
|
|
71
89
|
},
|
|
72
|
-
|
|
90
|
+
"instance.ping": {
|
|
91
|
+
plane: "common",
|
|
92
|
+
roles: ALL_ROLES,
|
|
93
|
+
needs_hello: true,
|
|
94
|
+
locality: "cluster",
|
|
95
|
+
errors: [],
|
|
96
|
+
},
|
|
97
|
+
"instance.shutdown": {
|
|
73
98
|
plane: "common",
|
|
74
99
|
roles: USER_ONLY,
|
|
75
100
|
needs_hello: true,
|
|
76
101
|
locality: "instance-local",
|
|
77
102
|
errors: [],
|
|
78
103
|
},
|
|
79
|
-
|
|
104
|
+
"session.stopping": {
|
|
80
105
|
plane: "common",
|
|
81
106
|
roles: SESSION_ONLY,
|
|
82
107
|
needs_hello: true,
|
|
@@ -86,14 +111,14 @@ export const OP_ATTRIBUTES = {
|
|
|
86
111
|
// Open to every role, with which role may have which topic left to the topic
|
|
87
112
|
// table: an instance subscribes as itself to what only instances may hold,
|
|
88
113
|
// and a person is refused there by that table rather than here.
|
|
89
|
-
|
|
114
|
+
"topic.subscribe": {
|
|
90
115
|
plane: "common",
|
|
91
116
|
roles: ALL_ROLES,
|
|
92
117
|
needs_hello: true,
|
|
93
118
|
locality: "cluster",
|
|
94
119
|
errors: ["topic_unknown"],
|
|
95
120
|
},
|
|
96
|
-
|
|
121
|
+
"topic.unsubscribe": {
|
|
97
122
|
plane: "common",
|
|
98
123
|
roles: ALL_ROLES,
|
|
99
124
|
needs_hello: true,
|
|
@@ -102,12 +127,12 @@ export const OP_ATTRIBUTES = {
|
|
|
102
127
|
},
|
|
103
128
|
|
|
104
129
|
// The four ops that authenticate a person are open to every role for the
|
|
105
|
-
// same reason
|
|
106
|
-
// what they answer is what settles one. They are `cluster` because whichever
|
|
130
|
+
// same reason the greetings are: they run before there is an identity to
|
|
131
|
+
// check, and what they answer is what settles one. They are `cluster` because whichever
|
|
107
132
|
// instance is reached answers — behind a load balancer that is not a choice
|
|
108
133
|
// the caller makes — and each asks the issuing instance itself for the parts
|
|
109
134
|
// only it holds.
|
|
110
|
-
|
|
135
|
+
"auth.challenge": {
|
|
111
136
|
plane: "common",
|
|
112
137
|
roles: ALL_ROLES,
|
|
113
138
|
needs_hello: false,
|
|
@@ -115,7 +140,7 @@ export const OP_ATTRIBUTES = {
|
|
|
115
140
|
carrier: "http",
|
|
116
141
|
errors: [],
|
|
117
142
|
},
|
|
118
|
-
|
|
143
|
+
"auth.register": {
|
|
119
144
|
plane: "common",
|
|
120
145
|
roles: ALL_ROLES,
|
|
121
146
|
needs_hello: false,
|
|
@@ -123,7 +148,7 @@ export const OP_ATTRIBUTES = {
|
|
|
123
148
|
carrier: "http",
|
|
124
149
|
errors: ["auth_invalid", "auth_expired", "auth_unknown_issuer"],
|
|
125
150
|
},
|
|
126
|
-
|
|
151
|
+
"auth.assert": {
|
|
127
152
|
plane: "common",
|
|
128
153
|
roles: ALL_ROLES,
|
|
129
154
|
needs_hello: false,
|
|
@@ -131,7 +156,7 @@ export const OP_ATTRIBUTES = {
|
|
|
131
156
|
carrier: "http",
|
|
132
157
|
errors: ["auth_invalid", "auth_expired", "auth_unknown_issuer"],
|
|
133
158
|
},
|
|
134
|
-
|
|
159
|
+
"auth.token.refresh": {
|
|
135
160
|
plane: "common",
|
|
136
161
|
roles: ALL_ROLES,
|
|
137
162
|
needs_hello: false,
|
|
@@ -140,8 +165,8 @@ export const OP_ATTRIBUTES = {
|
|
|
140
165
|
errors: ["auth_invalid", "auth_expired", "auth_unknown_issuer"],
|
|
141
166
|
},
|
|
142
167
|
// Addresses the connection it arrives on, which is on the instance that
|
|
143
|
-
// received it: nothing to forward, as with
|
|
144
|
-
|
|
168
|
+
// received it: nothing to forward, as with a greeting.
|
|
169
|
+
"auth.extend": {
|
|
145
170
|
plane: "common",
|
|
146
171
|
roles: USER_ONLY,
|
|
147
172
|
needs_hello: true,
|
|
@@ -151,14 +176,14 @@ export const OP_ATTRIBUTES = {
|
|
|
151
176
|
// Between instances: what an issuer alone can answer. Instance-local by the
|
|
152
177
|
// usual rule — the subject belongs to one instance, and it is reached by
|
|
153
178
|
// `to_instance` being that instance's id.
|
|
154
|
-
|
|
179
|
+
"auth.resolve": {
|
|
155
180
|
plane: "common",
|
|
156
181
|
roles: INSTANCE_ONLY,
|
|
157
182
|
needs_hello: true,
|
|
158
183
|
locality: "instance-local",
|
|
159
184
|
errors: ["auth_invalid", "auth_expired"],
|
|
160
185
|
},
|
|
161
|
-
|
|
186
|
+
"auth.rotate": {
|
|
162
187
|
plane: "common",
|
|
163
188
|
roles: INSTANCE_ONLY,
|
|
164
189
|
needs_hello: true,
|
|
@@ -167,28 +192,28 @@ export const OP_ATTRIBUTES = {
|
|
|
167
192
|
},
|
|
168
193
|
|
|
169
194
|
// --- messaging: one-to-one delivery (4) ---
|
|
170
|
-
|
|
195
|
+
"message.send": {
|
|
171
196
|
plane: "messaging",
|
|
172
197
|
roles: AGENT_AND_USER,
|
|
173
198
|
needs_hello: true,
|
|
174
199
|
locality: "cluster",
|
|
175
200
|
errors: ["session_not_found"],
|
|
176
201
|
},
|
|
177
|
-
|
|
202
|
+
"say.post": {
|
|
178
203
|
plane: "messaging",
|
|
179
204
|
roles: SESSION_ONLY,
|
|
180
205
|
needs_hello: true,
|
|
181
206
|
locality: "cluster",
|
|
182
207
|
errors: ["rate_limited"],
|
|
183
208
|
},
|
|
184
|
-
|
|
209
|
+
"say.unread.clear": {
|
|
185
210
|
plane: "messaging",
|
|
186
211
|
roles: USER_ONLY,
|
|
187
212
|
needs_hello: true,
|
|
188
213
|
locality: "cluster",
|
|
189
214
|
errors: [],
|
|
190
215
|
},
|
|
191
|
-
|
|
216
|
+
"notify.send": {
|
|
192
217
|
plane: "messaging",
|
|
193
218
|
roles: AGENT_AND_USER,
|
|
194
219
|
needs_hello: true,
|
|
@@ -197,14 +222,14 @@ export const OP_ATTRIBUTES = {
|
|
|
197
222
|
},
|
|
198
223
|
|
|
199
224
|
// --- control: session observation and operation (10) ---
|
|
200
|
-
|
|
225
|
+
"session.kill": {
|
|
201
226
|
plane: "control",
|
|
202
227
|
roles: USER_ONLY,
|
|
203
228
|
needs_hello: true,
|
|
204
229
|
locality: "instance-local",
|
|
205
230
|
errors: ["session_not_found"],
|
|
206
231
|
},
|
|
207
|
-
|
|
232
|
+
"session.rename": {
|
|
208
233
|
plane: "control",
|
|
209
234
|
roles: USER_ONLY,
|
|
210
235
|
needs_hello: true,
|
|
@@ -212,35 +237,35 @@ export const OP_ATTRIBUTES = {
|
|
|
212
237
|
locality: "instance-local",
|
|
213
238
|
errors: ["session_not_found"],
|
|
214
239
|
},
|
|
215
|
-
|
|
240
|
+
"session.env.read": {
|
|
216
241
|
plane: "control",
|
|
217
242
|
roles: USER_ONLY,
|
|
218
243
|
needs_hello: true,
|
|
219
244
|
locality: "instance-local",
|
|
220
245
|
errors: ["session_not_found"],
|
|
221
246
|
},
|
|
222
|
-
|
|
247
|
+
"session.search": {
|
|
223
248
|
plane: "control",
|
|
224
249
|
roles: USER_ONLY,
|
|
225
250
|
needs_hello: true,
|
|
226
251
|
locality: "instance-local",
|
|
227
252
|
errors: [],
|
|
228
253
|
},
|
|
229
|
-
|
|
254
|
+
"session.dump.write": {
|
|
230
255
|
plane: "control",
|
|
231
256
|
roles: USER_ONLY,
|
|
232
257
|
needs_hello: true,
|
|
233
258
|
locality: "instance-local",
|
|
234
259
|
errors: ["not_found"],
|
|
235
260
|
},
|
|
236
|
-
|
|
261
|
+
"dump.presets.read": {
|
|
237
262
|
plane: "control",
|
|
238
263
|
roles: AGENT_AND_USER,
|
|
239
264
|
needs_hello: true,
|
|
240
265
|
locality: "instance-local",
|
|
241
266
|
errors: [],
|
|
242
267
|
},
|
|
243
|
-
|
|
268
|
+
"transcript.read": {
|
|
244
269
|
plane: "control",
|
|
245
270
|
roles: AGENT_AND_USER,
|
|
246
271
|
needs_hello: true,
|
|
@@ -248,7 +273,7 @@ export const OP_ATTRIBUTES = {
|
|
|
248
273
|
scope: "role",
|
|
249
274
|
errors: ["not_found"],
|
|
250
275
|
},
|
|
251
|
-
|
|
276
|
+
"transcript.items.read": {
|
|
252
277
|
plane: "control",
|
|
253
278
|
roles: AGENT_AND_USER,
|
|
254
279
|
needs_hello: true,
|
|
@@ -256,7 +281,7 @@ export const OP_ATTRIBUTES = {
|
|
|
256
281
|
scope: "role",
|
|
257
282
|
errors: ["not_found"],
|
|
258
283
|
},
|
|
259
|
-
|
|
284
|
+
"session.fork.origin.read": {
|
|
260
285
|
plane: "control",
|
|
261
286
|
roles: USER_ONLY,
|
|
262
287
|
needs_hello: true,
|
|
@@ -264,7 +289,7 @@ export const OP_ATTRIBUTES = {
|
|
|
264
289
|
locality: "instance-local",
|
|
265
290
|
errors: ["not_found"],
|
|
266
291
|
},
|
|
267
|
-
|
|
292
|
+
"session.forget": {
|
|
268
293
|
plane: "control",
|
|
269
294
|
roles: USER_ONLY,
|
|
270
295
|
needs_hello: true,
|
|
@@ -273,7 +298,7 @@ export const OP_ATTRIBUTES = {
|
|
|
273
298
|
},
|
|
274
299
|
|
|
275
300
|
// --- control: file access (9) ---
|
|
276
|
-
|
|
301
|
+
"dir.list": {
|
|
277
302
|
plane: "control",
|
|
278
303
|
roles: AGENT_AND_USER,
|
|
279
304
|
needs_hello: true,
|
|
@@ -281,7 +306,7 @@ export const OP_ATTRIBUTES = {
|
|
|
281
306
|
scope: "role",
|
|
282
307
|
errors: ["path_forbidden", "not_found"],
|
|
283
308
|
},
|
|
284
|
-
|
|
309
|
+
"file.read": {
|
|
285
310
|
plane: "control",
|
|
286
311
|
roles: AGENT_AND_USER,
|
|
287
312
|
needs_hello: true,
|
|
@@ -289,49 +314,49 @@ export const OP_ATTRIBUTES = {
|
|
|
289
314
|
scope: "role",
|
|
290
315
|
errors: ["path_forbidden", "not_found"],
|
|
291
316
|
},
|
|
292
|
-
|
|
317
|
+
"file.write": {
|
|
293
318
|
plane: "control",
|
|
294
319
|
roles: USER_ONLY,
|
|
295
320
|
needs_hello: true,
|
|
296
321
|
locality: "instance-local",
|
|
297
322
|
errors: ["path_not_writable", "file_exists"],
|
|
298
323
|
},
|
|
299
|
-
|
|
324
|
+
"file.create": {
|
|
300
325
|
plane: "control",
|
|
301
326
|
roles: USER_ONLY,
|
|
302
327
|
needs_hello: true,
|
|
303
328
|
locality: "instance-local",
|
|
304
329
|
errors: ["file_exists", "path_forbidden"],
|
|
305
330
|
},
|
|
306
|
-
|
|
331
|
+
"file.edit": {
|
|
307
332
|
plane: "control",
|
|
308
333
|
roles: USER_ONLY,
|
|
309
334
|
needs_hello: true,
|
|
310
335
|
locality: "instance-local",
|
|
311
336
|
errors: ["file_conflict", "not_a_text_file"],
|
|
312
337
|
},
|
|
313
|
-
|
|
338
|
+
"file.delete": {
|
|
314
339
|
plane: "control",
|
|
315
340
|
roles: USER_ONLY,
|
|
316
341
|
needs_hello: true,
|
|
317
342
|
locality: "instance-local",
|
|
318
343
|
errors: ["path_forbidden", "not_found"],
|
|
319
344
|
},
|
|
320
|
-
|
|
345
|
+
"file.find": {
|
|
321
346
|
plane: "control",
|
|
322
347
|
roles: USER_ONLY,
|
|
323
348
|
needs_hello: true,
|
|
324
349
|
locality: "instance-local",
|
|
325
350
|
errors: ["path_forbidden"],
|
|
326
351
|
},
|
|
327
|
-
|
|
352
|
+
"file.stat": {
|
|
328
353
|
plane: "control",
|
|
329
354
|
roles: USER_ONLY,
|
|
330
355
|
needs_hello: true,
|
|
331
356
|
locality: "instance-local",
|
|
332
357
|
errors: [],
|
|
333
358
|
},
|
|
334
|
-
|
|
359
|
+
"dir.tree": {
|
|
335
360
|
plane: "control",
|
|
336
361
|
roles: USER_ONLY,
|
|
337
362
|
needs_hello: true,
|
|
@@ -341,7 +366,7 @@ export const OP_ATTRIBUTES = {
|
|
|
341
366
|
},
|
|
342
367
|
|
|
343
368
|
// --- control: launcher / sandbox / translate / llm (7) ---
|
|
344
|
-
|
|
369
|
+
"launcher.config.read": {
|
|
345
370
|
plane: "control",
|
|
346
371
|
roles: USER_ONLY,
|
|
347
372
|
needs_hello: true,
|
|
@@ -349,7 +374,7 @@ export const OP_ATTRIBUTES = {
|
|
|
349
374
|
locality: "instance-local",
|
|
350
375
|
errors: [],
|
|
351
376
|
},
|
|
352
|
-
|
|
377
|
+
"launcher.run": {
|
|
353
378
|
plane: "control",
|
|
354
379
|
roles: USER_ONLY,
|
|
355
380
|
needs_hello: true,
|
|
@@ -357,7 +382,7 @@ export const OP_ATTRIBUTES = {
|
|
|
357
382
|
locality: "instance-local",
|
|
358
383
|
errors: [],
|
|
359
384
|
},
|
|
360
|
-
|
|
385
|
+
"sandbox.grant": {
|
|
361
386
|
plane: "control",
|
|
362
387
|
roles: USER_ONLY,
|
|
363
388
|
needs_hello: true,
|
|
@@ -365,7 +390,7 @@ export const OP_ATTRIBUTES = {
|
|
|
365
390
|
locality: "instance-local",
|
|
366
391
|
errors: ["path_forbidden"],
|
|
367
392
|
},
|
|
368
|
-
|
|
393
|
+
"sandbox.revoke": {
|
|
369
394
|
plane: "control",
|
|
370
395
|
roles: USER_ONLY,
|
|
371
396
|
needs_hello: true,
|
|
@@ -373,7 +398,7 @@ export const OP_ATTRIBUTES = {
|
|
|
373
398
|
locality: "instance-local",
|
|
374
399
|
errors: [],
|
|
375
400
|
},
|
|
376
|
-
|
|
401
|
+
"translate.run": {
|
|
377
402
|
plane: "control",
|
|
378
403
|
roles: USER_ONLY,
|
|
379
404
|
needs_hello: true,
|
|
@@ -381,7 +406,7 @@ export const OP_ATTRIBUTES = {
|
|
|
381
406
|
locality: "instance-local",
|
|
382
407
|
errors: ["translate_helper_failed"],
|
|
383
408
|
},
|
|
384
|
-
|
|
409
|
+
"llm.usage.read": {
|
|
385
410
|
plane: "control",
|
|
386
411
|
roles: USER_ONLY,
|
|
387
412
|
needs_hello: true,
|
|
@@ -389,7 +414,7 @@ export const OP_ATTRIBUTES = {
|
|
|
389
414
|
locality: "instance-local",
|
|
390
415
|
errors: [],
|
|
391
416
|
},
|
|
392
|
-
|
|
417
|
+
"llm.stats.read": {
|
|
393
418
|
plane: "control",
|
|
394
419
|
roles: USER_ONLY,
|
|
395
420
|
needs_hello: true,
|
|
@@ -401,21 +426,21 @@ export const OP_ATTRIBUTES = {
|
|
|
401
426
|
// --- control: the shared key-value store (3) ---
|
|
402
427
|
// The only control ops that are not instance-local: a value is held by every
|
|
403
428
|
// instance rather than by one, so whichever is asked can answer.
|
|
404
|
-
|
|
429
|
+
"kv.read": {
|
|
405
430
|
plane: "control",
|
|
406
431
|
roles: USER_ONLY,
|
|
407
432
|
needs_hello: true,
|
|
408
433
|
locality: "cluster",
|
|
409
434
|
errors: ["not_found"],
|
|
410
435
|
},
|
|
411
|
-
|
|
436
|
+
"kv.write": {
|
|
412
437
|
plane: "control",
|
|
413
438
|
roles: USER_ONLY,
|
|
414
439
|
needs_hello: true,
|
|
415
440
|
locality: "cluster",
|
|
416
441
|
errors: [],
|
|
417
442
|
},
|
|
418
|
-
|
|
443
|
+
"kv.delete": {
|
|
419
444
|
plane: "control",
|
|
420
445
|
roles: USER_ONLY,
|
|
421
446
|
needs_hello: true,
|
package/src/common/auth.ts
CHANGED
|
@@ -45,7 +45,7 @@ export type AuthChallengeArgs = Static<typeof AuthChallengeArgs>;
|
|
|
45
45
|
* The issuer travels beside the value rather than inside it because the
|
|
46
46
|
* instance that receives the answer is not necessarily the one that issued it:
|
|
47
47
|
* behind a load balancer either may be reached, so the receiver reads the
|
|
48
|
-
* issuer, asks it to consume the challenge (`
|
|
48
|
+
* issuer, asks it to consume the challenge (`auth.resolve`), and verifies the
|
|
49
49
|
* assertion itself. An issuer a caller made up names an instance that knows no
|
|
50
50
|
* such challenge, which is a refusal and not a way in. */
|
|
51
51
|
export const AuthChallenge = Type.Object(
|
|
@@ -63,14 +63,14 @@ export type AuthChallenge = Static<typeof AuthChallenge>;
|
|
|
63
63
|
export const AuthChallengeResult = AuthChallenge;
|
|
64
64
|
export type AuthChallengeResult = Static<typeof AuthChallengeResult>;
|
|
65
65
|
|
|
66
|
-
export const AuthChallengeRequest = request("
|
|
67
|
-
export const AuthChallengeResponse = response("
|
|
66
|
+
export const AuthChallengeRequest = request("auth.challenge", AuthChallengeArgs);
|
|
67
|
+
export const AuthChallengeResponse = response("auth.challenge", AuthChallengeResult);
|
|
68
68
|
|
|
69
69
|
// --- registration ----------------------------------------------------------
|
|
70
70
|
|
|
71
71
|
/** What the registration URL carries, as the instance that issued it reads it
|
|
72
72
|
* back. On the wire between a browser and an instance the whole of it is one
|
|
73
|
-
* opaque string; this shape is what `
|
|
73
|
+
* opaque string; this shape is what `auth.resolve` answers with, so the two
|
|
74
74
|
* instances involved agree on what was authorized.
|
|
75
75
|
*
|
|
76
76
|
* Its integrity rests on a secret made for this one registration and held only
|
|
@@ -175,8 +175,8 @@ export type AuthSession = Static<typeof AuthSession>;
|
|
|
175
175
|
export const AuthRegisterResult = AuthSession;
|
|
176
176
|
export type AuthRegisterResult = Static<typeof AuthRegisterResult>;
|
|
177
177
|
|
|
178
|
-
export const AuthRegisterRequest = request("
|
|
179
|
-
export const AuthRegisterResponse = response("
|
|
178
|
+
export const AuthRegisterRequest = request("auth.register", AuthRegisterArgs);
|
|
179
|
+
export const AuthRegisterResponse = response("auth.register", AuthRegisterResult);
|
|
180
180
|
|
|
181
181
|
// --- assertion -------------------------------------------------------------
|
|
182
182
|
|
|
@@ -207,8 +207,8 @@ export type AuthAssertArgs = Static<typeof AuthAssertArgs>;
|
|
|
207
207
|
export const AuthAssertResult = AuthSession;
|
|
208
208
|
export type AuthAssertResult = Static<typeof AuthAssertResult>;
|
|
209
209
|
|
|
210
|
-
export const AuthAssertRequest = request("
|
|
211
|
-
export const AuthAssertResponse = response("
|
|
210
|
+
export const AuthAssertRequest = request("auth.assert", AuthAssertArgs);
|
|
211
|
+
export const AuthAssertResponse = response("auth.assert", AuthAssertResult);
|
|
212
212
|
|
|
213
213
|
// --- refreshing a token pair ----------------------------------------------
|
|
214
214
|
|
|
@@ -224,7 +224,7 @@ export type AuthRefreshReason = Static<typeof AuthRefreshReason>;
|
|
|
224
224
|
/** The refresh token is not among the arguments: it is a cookie the carrier
|
|
225
225
|
* already holds, and a caller that could state it is a caller that could read
|
|
226
226
|
* it. What is left is why the caller is asking, which nothing is decided by. */
|
|
227
|
-
export const
|
|
227
|
+
export const AuthTokenRefreshArgs = Type.Object({
|
|
228
228
|
/** What prompted this refresh, as the client knows it: the page was loaded
|
|
229
229
|
* again, the access token was about to expire, or a dropped connection is
|
|
230
230
|
* being remade. A hint kept on the family (`last_refresh`) for a person
|
|
@@ -234,31 +234,31 @@ export const AuthRefreshTokenArgs = Type.Object({
|
|
|
234
234
|
* refresh as any. */
|
|
235
235
|
reason: Type.Optional(AuthRefreshReason),
|
|
236
236
|
});
|
|
237
|
-
export type
|
|
237
|
+
export type AuthTokenRefreshArgs = Static<typeof AuthTokenRefreshArgs>;
|
|
238
238
|
|
|
239
|
-
export const
|
|
240
|
-
export type
|
|
239
|
+
export const AuthTokenRefreshResult = AuthSession;
|
|
240
|
+
export type AuthTokenRefreshResult = Static<typeof AuthTokenRefreshResult>;
|
|
241
241
|
|
|
242
|
-
export const
|
|
243
|
-
export const
|
|
242
|
+
export const AuthTokenRefreshRequest = request("auth.token.refresh", AuthTokenRefreshArgs);
|
|
243
|
+
export const AuthTokenRefreshResponse = response("auth.token.refresh", AuthTokenRefreshResult);
|
|
244
244
|
|
|
245
245
|
// --- extending a live connection ------------------------------------------
|
|
246
246
|
|
|
247
|
-
/** Carries a token got from `
|
|
247
|
+
/** Carries a token got from `auth.token.refresh`, on the connection whose life
|
|
248
248
|
* it extends. Apart from that op because they answer different questions: one
|
|
249
249
|
* mints, this one moves a live connection's deadline, and a client that had to
|
|
250
250
|
* reconnect to use a fresh token would blink every few hours for no reason. */
|
|
251
|
-
export const
|
|
252
|
-
export type
|
|
251
|
+
export const AuthExtendArgs = Type.Object({ access_token: Base64Url });
|
|
252
|
+
export type AuthExtendArgs = Static<typeof AuthExtendArgs>;
|
|
253
253
|
|
|
254
|
-
export const
|
|
255
|
-
/** The connection's new deadline, as
|
|
254
|
+
export const AuthExtendResult = Type.Object({
|
|
255
|
+
/** The connection's new deadline, as the greeting first stated it. */
|
|
256
256
|
auth_expires_at: Timestamp,
|
|
257
257
|
});
|
|
258
|
-
export type
|
|
258
|
+
export type AuthExtendResult = Static<typeof AuthExtendResult>;
|
|
259
259
|
|
|
260
|
-
export const
|
|
261
|
-
export const
|
|
260
|
+
export const AuthExtendRequest = request("auth.extend", AuthExtendArgs);
|
|
261
|
+
export const AuthExtendResponse = response("auth.extend", AuthExtendResult);
|
|
262
262
|
|
|
263
263
|
// --- between instances -----------------------------------------------------
|
|
264
264
|
|
|
@@ -297,8 +297,8 @@ export const AuthResolveResult = Type.Union(
|
|
|
297
297
|
);
|
|
298
298
|
export type AuthResolveResult = Static<typeof AuthResolveResult>;
|
|
299
299
|
|
|
300
|
-
export const AuthResolveRequest = request("
|
|
301
|
-
export const AuthResolveResponse = response("
|
|
300
|
+
export const AuthResolveRequest = request("auth.resolve", AuthResolveArgs);
|
|
301
|
+
export const AuthResolveResponse = response("auth.resolve", AuthResolveResult);
|
|
302
302
|
|
|
303
303
|
/** Rotates a token family at the one instance allowed to write it.
|
|
304
304
|
*
|
|
@@ -332,8 +332,8 @@ export const AuthRotateResult = Type.Object({
|
|
|
332
332
|
});
|
|
333
333
|
export type AuthRotateResult = Static<typeof AuthRotateResult>;
|
|
334
334
|
|
|
335
|
-
export const AuthRotateRequest = request("
|
|
336
|
-
export const AuthRotateResponse = response("
|
|
335
|
+
export const AuthRotateRequest = request("auth.rotate", AuthRotateArgs);
|
|
336
|
+
export const AuthRotateResponse = response("auth.rotate", AuthRotateResult);
|
|
337
337
|
|
|
338
338
|
// --- the replicated records ------------------------------------------------
|
|
339
339
|
|
|
@@ -513,7 +513,7 @@ export const AuthRecord = Type.Object(
|
|
|
513
513
|
);
|
|
514
514
|
export type AuthRecord = Static<typeof AuthRecord>;
|
|
515
515
|
|
|
516
|
-
/** The `
|
|
516
|
+
/** The `auth.records` topic: how credentials and token families reach every
|
|
517
517
|
* instance.
|
|
518
518
|
*
|
|
519
519
|
* Apart from the store because of who may read it. The store is the person's to
|
|
@@ -522,6 +522,6 @@ export type AuthRecord = Static<typeof AuthRecord>;
|
|
|
522
522
|
* it would be a new way in. Only instances subscribe, and a relay carries the
|
|
523
523
|
* frames as the instance it is rather than on a person's behalf. */
|
|
524
524
|
export const AuthRecordsFrame = topicFrame(
|
|
525
|
-
"
|
|
525
|
+
"auth.records",
|
|
526
526
|
Type.Object({ records: Type.Array(AuthRecord) }),
|
|
527
527
|
);
|