@oxyhq/contracts 0.25.0 → 0.26.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,856 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * The browser DeviceSession hub at `auth.oxy.so` (issue #937, Phase 5, ADR 0003).
4
+ *
5
+ * Two wire surfaces live in this file and they are deliberately different
6
+ * shapes, because they answer to different callers:
7
+ *
8
+ * - The `browserHub*` schemas below the first divider are the API's
9
+ * (`api.oxy.so/session/browser-hub/*`), spoken ONLY by the IdP's own
10
+ * server/edge layer. They carry the raw handle and a bearer, so nothing that
11
+ * speaks them may run in a browser.
12
+ * - The `hub*` schemas below the second divider are the EDGE's
13
+ * (`auth.oxy.so/hub/*`), spoken by the IdP SPA. They carry neither: the
14
+ * handle stays in an `HttpOnly` cookie the script cannot read, and the
15
+ * device-wide bearer stays at the edge.
16
+ *
17
+ * That split is the whole point of the phase. A single schema covering both
18
+ * would let a refactor move a credential across the boundary without any type
19
+ * changing shape.
20
+ *
21
+ * ## What is NOT reopened here
22
+ *
23
+ * Relying-party origins remain zero-cookie: they keep `{deviceId,
24
+ * deviceSecret}` + `POST /session/device/token` and set no cookie of any kind.
25
+ * `auth.oxy.so` alone holds a handle, first-party only. There is no
26
+ * refresh-token family and no bootstrap hop.
27
+ */
28
+ /**
29
+ * The one cookie name, `__Host-` prefixed.
30
+ *
31
+ * The prefix is not decoration: a browser refuses to store a `__Host-` cookie
32
+ * that carries a `Domain` attribute or a `Path` other than `/`, or that arrives
33
+ * without `Secure`. So the name itself is what makes "bound to `auth.oxy.so`
34
+ * alone, readable by no other `oxy.so` host" enforced by the client rather than
35
+ * merely intended by the server — including against a compromised sibling
36
+ * subdomain, which is the specific attack `Domain=.oxy.so` would have opened.
37
+ */
38
+ export declare const BROWSER_HUB_COOKIE_NAME = "__Host-oxy-device";
39
+ /**
40
+ * The exact attribute set the edge sets, in the order it writes them.
41
+ *
42
+ * Held as data rather than as a template string so a test can assert the set
43
+ * rather than a rendered line, and so removing one attribute is a diff to a
44
+ * named constant instead of an edit inside a string literal.
45
+ *
46
+ * `Max-Age` is deliberately NOT in this list — see
47
+ * {@link BROWSER_HUB_HANDLE_TTL_MS}, which the edge appends. Everything here is
48
+ * a SECURITY attribute and none of them is ever conditional.
49
+ */
50
+ export declare const BROWSER_HUB_COOKIE_ATTRIBUTES: readonly ["Secure", "HttpOnly", "SameSite=Lax", "Path=/"];
51
+ /**
52
+ * How long a hub handle lives, server-side and in the cookie alike.
53
+ *
54
+ * Thirty days. The cookie's `Max-Age` is derived from this same constant so the
55
+ * two cannot disagree: a cookie outliving its credential produces a browser that
56
+ * believes it is signed in and is refused on every call, and a credential
57
+ * outliving its cookie leaves an un-addressable row alive on the server.
58
+ *
59
+ * A hub handle is NOT a session cookie (one with no `Max-Age`, discarded when
60
+ * the browser closes). It cannot be: the thing it identifies is the browser
61
+ * PROFILE's device session, and a device session that evaporates when the user
62
+ * quits their browser would send them back to a QR scan every morning — the
63
+ * exact failure ADR 0003 exists to remove.
64
+ */
65
+ export declare const BROWSER_HUB_HANDLE_TTL_MS: number;
66
+ /**
67
+ * The raw handle, as it travels between the edge and the API.
68
+ *
69
+ * An opaque base64url random value and NOTHING else — no token, no user id, no
70
+ * device id, no account id, no serialized state. The server stores only
71
+ * `sha256(handle)`, so a dump of the column cannot address a browser.
72
+ *
73
+ * The minimum length is a floor against an empty or truncated value reaching a
74
+ * hash comparison, not a statement about the entropy: that is fixed by the
75
+ * issuer (`BROWSER_HUB_HANDLE_BYTES` in the API), and a handle is the only
76
+ * credential in this flow, so it is 256 bits.
77
+ */
78
+ export declare const browserHubHandleSchema: z.ZodString;
79
+ /** Request body of every handle-presenting API endpoint. */
80
+ export declare const browserHubHandleRequestSchema: z.ZodObject<{
81
+ handle: z.ZodString;
82
+ }, "strip", z.ZodTypeAny, {
83
+ handle: string;
84
+ }, {
85
+ handle: string;
86
+ }>;
87
+ /**
88
+ * Response of `POST /session/browser-hub/establish` and `.../rotate`.
89
+ *
90
+ * The raw handle is returned exactly ONCE, to the edge, which puts it straight
91
+ * into the cookie and keeps no copy. It is never logged, never re-readable, and
92
+ * never reaches the browser's script context.
93
+ */
94
+ export declare const browserHubHandleResponseSchema: z.ZodObject<{
95
+ handle: z.ZodString;
96
+ expiresAt: z.ZodString;
97
+ }, "strip", z.ZodTypeAny, {
98
+ expiresAt: string;
99
+ handle: string;
100
+ }, {
101
+ expiresAt: string;
102
+ handle: string;
103
+ }>;
104
+ /**
105
+ * Response of `POST /session/browser-hub/resolve` — the browser's device
106
+ * session, resolved from the handle alone.
107
+ *
108
+ * Carries a bearer because the edge needs one to run the authorize lane on the
109
+ * browser's behalf. It is the ordinary short-lived access token of the device's
110
+ * active context, and it stops at the edge.
111
+ */
112
+ export declare const browserHubResolveResponseSchema: z.ZodObject<{
113
+ accessToken: z.ZodString;
114
+ expiresAt: z.ZodString;
115
+ directory: z.ZodObject<{
116
+ deviceId: z.ZodString;
117
+ revision: z.ZodNumber;
118
+ activeContextId: z.ZodNullable<z.ZodString>;
119
+ principals: z.ZodArray<z.ZodObject<{
120
+ id: z.ZodString;
121
+ userId: z.ZodString;
122
+ authuser: z.ZodNumber;
123
+ user: z.ZodObject<{
124
+ id: z.ZodString;
125
+ username: z.ZodString;
126
+ name: z.ZodOptional<z.ZodType<import("./userResponse").UserNameResponse, z.ZodTypeDef, import("./userResponse").UserNameResponse>>;
127
+ avatar: z.ZodOptional<z.ZodNullable<z.ZodString>>;
128
+ color: z.ZodOptional<z.ZodNullable<z.ZodString>>;
129
+ }, "strip", z.ZodTypeAny, {
130
+ username: string;
131
+ id: string;
132
+ name?: import("./userResponse").UserNameResponse | undefined;
133
+ avatar?: string | null | undefined;
134
+ color?: string | null | undefined;
135
+ }, {
136
+ username: string;
137
+ id: string;
138
+ name?: import("./userResponse").UserNameResponse | undefined;
139
+ avatar?: string | null | undefined;
140
+ color?: string | null | undefined;
141
+ }>;
142
+ contexts: z.ZodArray<z.ZodObject<{
143
+ id: z.ZodString;
144
+ accountId: z.ZodString;
145
+ kind: z.ZodEnum<["personal", "organization", "project", "bot", "channel"]>;
146
+ relationship: z.ZodEnum<["self", "owner", "member"]>;
147
+ account: z.ZodObject<{
148
+ id: z.ZodString;
149
+ username: z.ZodString;
150
+ name: z.ZodOptional<z.ZodType<import("./userResponse").UserNameResponse, z.ZodTypeDef, import("./userResponse").UserNameResponse>>;
151
+ avatar: z.ZodOptional<z.ZodNullable<z.ZodString>>;
152
+ color: z.ZodOptional<z.ZodNullable<z.ZodString>>;
153
+ }, "strip", z.ZodTypeAny, {
154
+ username: string;
155
+ id: string;
156
+ name?: import("./userResponse").UserNameResponse | undefined;
157
+ avatar?: string | null | undefined;
158
+ color?: string | null | undefined;
159
+ }, {
160
+ username: string;
161
+ id: string;
162
+ name?: import("./userResponse").UserNameResponse | undefined;
163
+ avatar?: string | null | undefined;
164
+ color?: string | null | undefined;
165
+ }>;
166
+ onDevice: z.ZodBoolean;
167
+ available: z.ZodBoolean;
168
+ active: z.ZodBoolean;
169
+ lastUsedAt: z.ZodNullable<z.ZodNumber>;
170
+ }, "strip", z.ZodTypeAny, {
171
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
172
+ accountId: string;
173
+ id: string;
174
+ relationship: "self" | "owner" | "member";
175
+ account: {
176
+ username: string;
177
+ id: string;
178
+ name?: import("./userResponse").UserNameResponse | undefined;
179
+ avatar?: string | null | undefined;
180
+ color?: string | null | undefined;
181
+ };
182
+ onDevice: boolean;
183
+ available: boolean;
184
+ active: boolean;
185
+ lastUsedAt: number | null;
186
+ }, {
187
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
188
+ accountId: string;
189
+ id: string;
190
+ relationship: "self" | "owner" | "member";
191
+ account: {
192
+ username: string;
193
+ id: string;
194
+ name?: import("./userResponse").UserNameResponse | undefined;
195
+ avatar?: string | null | undefined;
196
+ color?: string | null | undefined;
197
+ };
198
+ onDevice: boolean;
199
+ available: boolean;
200
+ active: boolean;
201
+ lastUsedAt: number | null;
202
+ }>, "many">;
203
+ }, "strip", z.ZodTypeAny, {
204
+ authuser: number;
205
+ userId: string;
206
+ id: string;
207
+ user: {
208
+ username: string;
209
+ id: string;
210
+ name?: import("./userResponse").UserNameResponse | undefined;
211
+ avatar?: string | null | undefined;
212
+ color?: string | null | undefined;
213
+ };
214
+ contexts: {
215
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
216
+ accountId: string;
217
+ id: string;
218
+ relationship: "self" | "owner" | "member";
219
+ account: {
220
+ username: string;
221
+ id: string;
222
+ name?: import("./userResponse").UserNameResponse | undefined;
223
+ avatar?: string | null | undefined;
224
+ color?: string | null | undefined;
225
+ };
226
+ onDevice: boolean;
227
+ available: boolean;
228
+ active: boolean;
229
+ lastUsedAt: number | null;
230
+ }[];
231
+ }, {
232
+ authuser: number;
233
+ userId: string;
234
+ id: string;
235
+ user: {
236
+ username: string;
237
+ id: string;
238
+ name?: import("./userResponse").UserNameResponse | undefined;
239
+ avatar?: string | null | undefined;
240
+ color?: string | null | undefined;
241
+ };
242
+ contexts: {
243
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
244
+ accountId: string;
245
+ id: string;
246
+ relationship: "self" | "owner" | "member";
247
+ account: {
248
+ username: string;
249
+ id: string;
250
+ name?: import("./userResponse").UserNameResponse | undefined;
251
+ avatar?: string | null | undefined;
252
+ color?: string | null | undefined;
253
+ };
254
+ onDevice: boolean;
255
+ available: boolean;
256
+ active: boolean;
257
+ lastUsedAt: number | null;
258
+ }[];
259
+ }>, "many">;
260
+ updatedAt: z.ZodNumber;
261
+ }, "strip", z.ZodTypeAny, {
262
+ deviceId: string;
263
+ revision: number;
264
+ updatedAt: number;
265
+ activeContextId: string | null;
266
+ principals: {
267
+ authuser: number;
268
+ userId: string;
269
+ id: string;
270
+ user: {
271
+ username: string;
272
+ id: string;
273
+ name?: import("./userResponse").UserNameResponse | undefined;
274
+ avatar?: string | null | undefined;
275
+ color?: string | null | undefined;
276
+ };
277
+ contexts: {
278
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
279
+ accountId: string;
280
+ id: string;
281
+ relationship: "self" | "owner" | "member";
282
+ account: {
283
+ username: string;
284
+ id: string;
285
+ name?: import("./userResponse").UserNameResponse | undefined;
286
+ avatar?: string | null | undefined;
287
+ color?: string | null | undefined;
288
+ };
289
+ onDevice: boolean;
290
+ available: boolean;
291
+ active: boolean;
292
+ lastUsedAt: number | null;
293
+ }[];
294
+ }[];
295
+ }, {
296
+ deviceId: string;
297
+ revision: number;
298
+ updatedAt: number;
299
+ activeContextId: string | null;
300
+ principals: {
301
+ authuser: number;
302
+ userId: string;
303
+ id: string;
304
+ user: {
305
+ username: string;
306
+ id: string;
307
+ name?: import("./userResponse").UserNameResponse | undefined;
308
+ avatar?: string | null | undefined;
309
+ color?: string | null | undefined;
310
+ };
311
+ contexts: {
312
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
313
+ accountId: string;
314
+ id: string;
315
+ relationship: "self" | "owner" | "member";
316
+ account: {
317
+ username: string;
318
+ id: string;
319
+ name?: import("./userResponse").UserNameResponse | undefined;
320
+ avatar?: string | null | undefined;
321
+ color?: string | null | undefined;
322
+ };
323
+ onDevice: boolean;
324
+ available: boolean;
325
+ active: boolean;
326
+ lastUsedAt: number | null;
327
+ }[];
328
+ }[];
329
+ }>;
330
+ }, "strip", z.ZodTypeAny, {
331
+ accessToken: string;
332
+ expiresAt: string;
333
+ directory: {
334
+ deviceId: string;
335
+ revision: number;
336
+ updatedAt: number;
337
+ activeContextId: string | null;
338
+ principals: {
339
+ authuser: number;
340
+ userId: string;
341
+ id: string;
342
+ user: {
343
+ username: string;
344
+ id: string;
345
+ name?: import("./userResponse").UserNameResponse | undefined;
346
+ avatar?: string | null | undefined;
347
+ color?: string | null | undefined;
348
+ };
349
+ contexts: {
350
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
351
+ accountId: string;
352
+ id: string;
353
+ relationship: "self" | "owner" | "member";
354
+ account: {
355
+ username: string;
356
+ id: string;
357
+ name?: import("./userResponse").UserNameResponse | undefined;
358
+ avatar?: string | null | undefined;
359
+ color?: string | null | undefined;
360
+ };
361
+ onDevice: boolean;
362
+ available: boolean;
363
+ active: boolean;
364
+ lastUsedAt: number | null;
365
+ }[];
366
+ }[];
367
+ };
368
+ }, {
369
+ accessToken: string;
370
+ expiresAt: string;
371
+ directory: {
372
+ deviceId: string;
373
+ revision: number;
374
+ updatedAt: number;
375
+ activeContextId: string | null;
376
+ principals: {
377
+ authuser: number;
378
+ userId: string;
379
+ id: string;
380
+ user: {
381
+ username: string;
382
+ id: string;
383
+ name?: import("./userResponse").UserNameResponse | undefined;
384
+ avatar?: string | null | undefined;
385
+ color?: string | null | undefined;
386
+ };
387
+ contexts: {
388
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
389
+ accountId: string;
390
+ id: string;
391
+ relationship: "self" | "owner" | "member";
392
+ account: {
393
+ username: string;
394
+ id: string;
395
+ name?: import("./userResponse").UserNameResponse | undefined;
396
+ avatar?: string | null | undefined;
397
+ color?: string | null | undefined;
398
+ };
399
+ onDevice: boolean;
400
+ available: boolean;
401
+ active: boolean;
402
+ lastUsedAt: number | null;
403
+ }[];
404
+ }[];
405
+ };
406
+ }>;
407
+ /**
408
+ * Why a handle did not resolve. A CLOSED set, and deliberately coarse.
409
+ *
410
+ * - `invalid_handle` — unknown, expired, or revoked. One code for all
411
+ * three: distinguishing them would tell a caller
412
+ * holding a guessed value whether it ever existed.
413
+ * - `no_active_session` — the handle is good and the device has nothing live
414
+ * to mint for. The credential is NOT revoked; the
415
+ * browser re-authenticates and keeps its cookie.
416
+ */
417
+ export declare const browserHubErrorSchema: z.ZodEnum<["invalid_handle", "no_active_session"]>;
418
+ /** Response of `POST /session/browser-hub/revoke`. Idempotent by construction. */
419
+ export declare const browserHubRevokeResponseSchema: z.ZodObject<{
420
+ revoked: z.ZodBoolean;
421
+ }, "strip", z.ZodTypeAny, {
422
+ revoked: boolean;
423
+ }, {
424
+ revoked: boolean;
425
+ }>;
426
+ /**
427
+ * What the SPA is allowed to know about the hub session.
428
+ *
429
+ * `signed_out` covers "no cookie", "cookie present but the handle no longer
430
+ * resolves" and "resolved, but the device has nothing live" — from the script's
431
+ * side those are one state, and collapsing them here is what stops a UI from
432
+ * branching on a distinction it must not act on.
433
+ *
434
+ * `active` carries the DIRECTORY and no credential. A switcher renders from it;
435
+ * nothing in it can be spent against the API. The bearer that produced it never
436
+ * left the edge.
437
+ */
438
+ export declare const hubSessionSchema: z.ZodDiscriminatedUnion<"status", [z.ZodObject<{
439
+ status: z.ZodLiteral<"signed_out">;
440
+ }, "strip", z.ZodTypeAny, {
441
+ status: "signed_out";
442
+ }, {
443
+ status: "signed_out";
444
+ }>, z.ZodObject<{
445
+ status: z.ZodLiteral<"active">;
446
+ directory: z.ZodObject<{
447
+ deviceId: z.ZodString;
448
+ revision: z.ZodNumber;
449
+ activeContextId: z.ZodNullable<z.ZodString>;
450
+ principals: z.ZodArray<z.ZodObject<{
451
+ id: z.ZodString;
452
+ userId: z.ZodString;
453
+ authuser: z.ZodNumber;
454
+ user: z.ZodObject<{
455
+ id: z.ZodString;
456
+ username: z.ZodString;
457
+ name: z.ZodOptional<z.ZodType<import("./userResponse").UserNameResponse, z.ZodTypeDef, import("./userResponse").UserNameResponse>>;
458
+ avatar: z.ZodOptional<z.ZodNullable<z.ZodString>>;
459
+ color: z.ZodOptional<z.ZodNullable<z.ZodString>>;
460
+ }, "strip", z.ZodTypeAny, {
461
+ username: string;
462
+ id: string;
463
+ name?: import("./userResponse").UserNameResponse | undefined;
464
+ avatar?: string | null | undefined;
465
+ color?: string | null | undefined;
466
+ }, {
467
+ username: string;
468
+ id: string;
469
+ name?: import("./userResponse").UserNameResponse | undefined;
470
+ avatar?: string | null | undefined;
471
+ color?: string | null | undefined;
472
+ }>;
473
+ contexts: z.ZodArray<z.ZodObject<{
474
+ id: z.ZodString;
475
+ accountId: z.ZodString;
476
+ kind: z.ZodEnum<["personal", "organization", "project", "bot", "channel"]>;
477
+ relationship: z.ZodEnum<["self", "owner", "member"]>;
478
+ account: z.ZodObject<{
479
+ id: z.ZodString;
480
+ username: z.ZodString;
481
+ name: z.ZodOptional<z.ZodType<import("./userResponse").UserNameResponse, z.ZodTypeDef, import("./userResponse").UserNameResponse>>;
482
+ avatar: z.ZodOptional<z.ZodNullable<z.ZodString>>;
483
+ color: z.ZodOptional<z.ZodNullable<z.ZodString>>;
484
+ }, "strip", z.ZodTypeAny, {
485
+ username: string;
486
+ id: string;
487
+ name?: import("./userResponse").UserNameResponse | undefined;
488
+ avatar?: string | null | undefined;
489
+ color?: string | null | undefined;
490
+ }, {
491
+ username: string;
492
+ id: string;
493
+ name?: import("./userResponse").UserNameResponse | undefined;
494
+ avatar?: string | null | undefined;
495
+ color?: string | null | undefined;
496
+ }>;
497
+ onDevice: z.ZodBoolean;
498
+ available: z.ZodBoolean;
499
+ active: z.ZodBoolean;
500
+ lastUsedAt: z.ZodNullable<z.ZodNumber>;
501
+ }, "strip", z.ZodTypeAny, {
502
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
503
+ accountId: string;
504
+ id: string;
505
+ relationship: "self" | "owner" | "member";
506
+ account: {
507
+ username: string;
508
+ id: string;
509
+ name?: import("./userResponse").UserNameResponse | undefined;
510
+ avatar?: string | null | undefined;
511
+ color?: string | null | undefined;
512
+ };
513
+ onDevice: boolean;
514
+ available: boolean;
515
+ active: boolean;
516
+ lastUsedAt: number | null;
517
+ }, {
518
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
519
+ accountId: string;
520
+ id: string;
521
+ relationship: "self" | "owner" | "member";
522
+ account: {
523
+ username: string;
524
+ id: string;
525
+ name?: import("./userResponse").UserNameResponse | undefined;
526
+ avatar?: string | null | undefined;
527
+ color?: string | null | undefined;
528
+ };
529
+ onDevice: boolean;
530
+ available: boolean;
531
+ active: boolean;
532
+ lastUsedAt: number | null;
533
+ }>, "many">;
534
+ }, "strip", z.ZodTypeAny, {
535
+ authuser: number;
536
+ userId: string;
537
+ id: string;
538
+ user: {
539
+ username: string;
540
+ id: string;
541
+ name?: import("./userResponse").UserNameResponse | undefined;
542
+ avatar?: string | null | undefined;
543
+ color?: string | null | undefined;
544
+ };
545
+ contexts: {
546
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
547
+ accountId: string;
548
+ id: string;
549
+ relationship: "self" | "owner" | "member";
550
+ account: {
551
+ username: string;
552
+ id: string;
553
+ name?: import("./userResponse").UserNameResponse | undefined;
554
+ avatar?: string | null | undefined;
555
+ color?: string | null | undefined;
556
+ };
557
+ onDevice: boolean;
558
+ available: boolean;
559
+ active: boolean;
560
+ lastUsedAt: number | null;
561
+ }[];
562
+ }, {
563
+ authuser: number;
564
+ userId: string;
565
+ id: string;
566
+ user: {
567
+ username: string;
568
+ id: string;
569
+ name?: import("./userResponse").UserNameResponse | undefined;
570
+ avatar?: string | null | undefined;
571
+ color?: string | null | undefined;
572
+ };
573
+ contexts: {
574
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
575
+ accountId: string;
576
+ id: string;
577
+ relationship: "self" | "owner" | "member";
578
+ account: {
579
+ username: string;
580
+ id: string;
581
+ name?: import("./userResponse").UserNameResponse | undefined;
582
+ avatar?: string | null | undefined;
583
+ color?: string | null | undefined;
584
+ };
585
+ onDevice: boolean;
586
+ available: boolean;
587
+ active: boolean;
588
+ lastUsedAt: number | null;
589
+ }[];
590
+ }>, "many">;
591
+ updatedAt: z.ZodNumber;
592
+ }, "strip", z.ZodTypeAny, {
593
+ deviceId: string;
594
+ revision: number;
595
+ updatedAt: number;
596
+ activeContextId: string | null;
597
+ principals: {
598
+ authuser: number;
599
+ userId: string;
600
+ id: string;
601
+ user: {
602
+ username: string;
603
+ id: string;
604
+ name?: import("./userResponse").UserNameResponse | undefined;
605
+ avatar?: string | null | undefined;
606
+ color?: string | null | undefined;
607
+ };
608
+ contexts: {
609
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
610
+ accountId: string;
611
+ id: string;
612
+ relationship: "self" | "owner" | "member";
613
+ account: {
614
+ username: string;
615
+ id: string;
616
+ name?: import("./userResponse").UserNameResponse | undefined;
617
+ avatar?: string | null | undefined;
618
+ color?: string | null | undefined;
619
+ };
620
+ onDevice: boolean;
621
+ available: boolean;
622
+ active: boolean;
623
+ lastUsedAt: number | null;
624
+ }[];
625
+ }[];
626
+ }, {
627
+ deviceId: string;
628
+ revision: number;
629
+ updatedAt: number;
630
+ activeContextId: string | null;
631
+ principals: {
632
+ authuser: number;
633
+ userId: string;
634
+ id: string;
635
+ user: {
636
+ username: string;
637
+ id: string;
638
+ name?: import("./userResponse").UserNameResponse | undefined;
639
+ avatar?: string | null | undefined;
640
+ color?: string | null | undefined;
641
+ };
642
+ contexts: {
643
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
644
+ accountId: string;
645
+ id: string;
646
+ relationship: "self" | "owner" | "member";
647
+ account: {
648
+ username: string;
649
+ id: string;
650
+ name?: import("./userResponse").UserNameResponse | undefined;
651
+ avatar?: string | null | undefined;
652
+ color?: string | null | undefined;
653
+ };
654
+ onDevice: boolean;
655
+ available: boolean;
656
+ active: boolean;
657
+ lastUsedAt: number | null;
658
+ }[];
659
+ }[];
660
+ }>;
661
+ }, "strip", z.ZodTypeAny, {
662
+ status: "active";
663
+ directory: {
664
+ deviceId: string;
665
+ revision: number;
666
+ updatedAt: number;
667
+ activeContextId: string | null;
668
+ principals: {
669
+ authuser: number;
670
+ userId: string;
671
+ id: string;
672
+ user: {
673
+ username: string;
674
+ id: string;
675
+ name?: import("./userResponse").UserNameResponse | undefined;
676
+ avatar?: string | null | undefined;
677
+ color?: string | null | undefined;
678
+ };
679
+ contexts: {
680
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
681
+ accountId: string;
682
+ id: string;
683
+ relationship: "self" | "owner" | "member";
684
+ account: {
685
+ username: string;
686
+ id: string;
687
+ name?: import("./userResponse").UserNameResponse | undefined;
688
+ avatar?: string | null | undefined;
689
+ color?: string | null | undefined;
690
+ };
691
+ onDevice: boolean;
692
+ available: boolean;
693
+ active: boolean;
694
+ lastUsedAt: number | null;
695
+ }[];
696
+ }[];
697
+ };
698
+ }, {
699
+ status: "active";
700
+ directory: {
701
+ deviceId: string;
702
+ revision: number;
703
+ updatedAt: number;
704
+ activeContextId: string | null;
705
+ principals: {
706
+ authuser: number;
707
+ userId: string;
708
+ id: string;
709
+ user: {
710
+ username: string;
711
+ id: string;
712
+ name?: import("./userResponse").UserNameResponse | undefined;
713
+ avatar?: string | null | undefined;
714
+ color?: string | null | undefined;
715
+ };
716
+ contexts: {
717
+ kind: "personal" | "organization" | "project" | "bot" | "channel";
718
+ accountId: string;
719
+ id: string;
720
+ relationship: "self" | "owner" | "member";
721
+ account: {
722
+ username: string;
723
+ id: string;
724
+ name?: import("./userResponse").UserNameResponse | undefined;
725
+ avatar?: string | null | undefined;
726
+ color?: string | null | undefined;
727
+ };
728
+ onDevice: boolean;
729
+ available: boolean;
730
+ active: boolean;
731
+ lastUsedAt: number | null;
732
+ }[];
733
+ }[];
734
+ };
735
+ }>]>;
736
+ /** Request body of `POST /hub/claim` — the Commons approval lane's handoff. */
737
+ export declare const hubClaimRequestSchema: z.ZodObject<{
738
+ /**
739
+ * The secret `sessionToken` of an approved `AuthSession`, held only by the
740
+ * page that created it. The edge spends it server-side: the access token and
741
+ * device secret the claim yields are consumed to establish the hub and are
742
+ * then discarded, so neither is ever returned to the script.
743
+ */
744
+ sessionToken: z.ZodString;
745
+ }, "strip", z.ZodTypeAny, {
746
+ sessionToken: string;
747
+ }, {
748
+ sessionToken: string;
749
+ }>;
750
+ /** Request body of `POST /hub/activate` — pick the globally active context. */
751
+ export declare const hubActivateRequestSchema: z.ZodObject<{
752
+ contextId: z.ZodString;
753
+ }, "strip", z.ZodTypeAny, {
754
+ contextId: string;
755
+ }, {
756
+ contextId: string;
757
+ }>;
758
+ /**
759
+ * Request body of `POST /hub/authorize` — a later official origin joining.
760
+ *
761
+ * There is no `prompt` field, and that is not an omission. `'none'` is absent
762
+ * from `buildOAuthAuthorizeUrl`'s union in `@oxyhq/core` precisely so a silent
763
+ * loop cannot be rebuilt in one line, and this endpoint would be the second
764
+ * place to rebuild it. A caller that needs a login or consent prompt gets one
765
+ * by not passing `approve`.
766
+ */
767
+ export declare const hubAuthorizeRequestSchema: z.ZodObject<{
768
+ clientId: z.ZodString;
769
+ redirectUri: z.ZodString;
770
+ state: z.ZodOptional<z.ZodString>;
771
+ codeChallenge: z.ZodString;
772
+ /** S256 only. `plain` is refused before the request leaves the edge. */
773
+ codeChallengeMethod: z.ZodLiteral<"S256">;
774
+ scope: z.ZodOptional<z.ZodString>;
775
+ /**
776
+ * The user's explicit answer on the consent screen.
777
+ *
778
+ * Absent or `false` means "tell me whether consent is needed"; the edge then
779
+ * returns `consent_required` and mints nothing. Only `true` may mint, and only
780
+ * the consent screen's own button sends it — which is why the decision of
781
+ * WHETHER consent is required is re-read from the server on both passes rather
782
+ * than remembered from the first.
783
+ */
784
+ approve: z.ZodOptional<z.ZodBoolean>;
785
+ }, "strip", z.ZodTypeAny, {
786
+ clientId: string;
787
+ redirectUri: string;
788
+ codeChallenge: string;
789
+ codeChallengeMethod: "S256";
790
+ state?: string | undefined;
791
+ scope?: string | undefined;
792
+ approve?: boolean | undefined;
793
+ }, {
794
+ clientId: string;
795
+ redirectUri: string;
796
+ codeChallenge: string;
797
+ codeChallengeMethod: "S256";
798
+ state?: string | undefined;
799
+ scope?: string | undefined;
800
+ approve?: boolean | undefined;
801
+ }>;
802
+ /**
803
+ * Result of `POST /hub/authorize`.
804
+ *
805
+ * `signed_out` is the honest answer for a browser with no hub session: the SPA
806
+ * runs the ordinary Commons-first authentication and tries again. It is never a
807
+ * redirect the edge performs on the browser's behalf — no automatic chain
808
+ * across Oxy origins, and nothing here can be hidden inside an iframe.
809
+ */
810
+ export declare const hubAuthorizeResultSchema: z.ZodDiscriminatedUnion<"status", [z.ZodObject<{
811
+ status: z.ZodLiteral<"signed_out">;
812
+ }, "strip", z.ZodTypeAny, {
813
+ status: "signed_out";
814
+ }, {
815
+ status: "signed_out";
816
+ }>, z.ZodObject<{
817
+ status: z.ZodLiteral<"consent_required">;
818
+ reason: z.ZodEnum<["new", "scope_changed"]>;
819
+ userConsentScopes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
820
+ }, "strip", z.ZodTypeAny, {
821
+ status: "consent_required";
822
+ reason: "new" | "scope_changed";
823
+ userConsentScopes?: string[] | undefined;
824
+ }, {
825
+ status: "consent_required";
826
+ reason: "new" | "scope_changed";
827
+ userConsentScopes?: string[] | undefined;
828
+ }>, z.ZodObject<{
829
+ status: z.ZodLiteral<"code">;
830
+ code: z.ZodString;
831
+ state: z.ZodNullable<z.ZodString>;
832
+ redirectUri: z.ZodString;
833
+ expiresIn: z.ZodNumber;
834
+ }, "strip", z.ZodTypeAny, {
835
+ code: string;
836
+ status: "code";
837
+ state: string | null;
838
+ redirectUri: string;
839
+ expiresIn: number;
840
+ }, {
841
+ code: string;
842
+ status: "code";
843
+ state: string | null;
844
+ redirectUri: string;
845
+ expiresIn: number;
846
+ }>]>;
847
+ export type BrowserHubHandleRequest = z.infer<typeof browserHubHandleRequestSchema>;
848
+ export type BrowserHubHandleResponse = z.infer<typeof browserHubHandleResponseSchema>;
849
+ export type BrowserHubResolveResponse = z.infer<typeof browserHubResolveResponseSchema>;
850
+ export type BrowserHubError = z.infer<typeof browserHubErrorSchema>;
851
+ export type BrowserHubRevokeResponse = z.infer<typeof browserHubRevokeResponseSchema>;
852
+ export type HubSession = z.infer<typeof hubSessionSchema>;
853
+ export type HubClaimRequest = z.infer<typeof hubClaimRequestSchema>;
854
+ export type HubActivateRequest = z.infer<typeof hubActivateRequestSchema>;
855
+ export type HubAuthorizeRequest = z.infer<typeof hubAuthorizeRequestSchema>;
856
+ export type HubAuthorizeResult = z.infer<typeof hubAuthorizeResultSchema>;