@oxyhq/contracts 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/.tsbuildinfo +1 -0
- package/dist/cjs/fedcmToken.js +49 -0
- package/dist/cjs/index.js +22 -1
- package/dist/cjs/recommendations.js +125 -0
- package/dist/cjs/sessionStatus.js +102 -0
- package/dist/cjs/userResponse.js +58 -31
- package/dist/esm/.tsbuildinfo +1 -0
- package/dist/esm/fedcmToken.js +46 -0
- package/dist/esm/index.js +10 -1
- package/dist/esm/recommendations.js +122 -0
- package/dist/esm/sessionStatus.js +99 -0
- package/dist/esm/userResponse.js +57 -30
- package/dist/types/.tsbuildinfo +1 -0
- package/dist/types/fedcmToken.d.ts +59 -0
- package/dist/types/index.d.ts +8 -2
- package/dist/types/recommendations.d.ts +535 -0
- package/dist/types/sessionStatus.d.ts +192 -0
- package/dist/types/userResponse.d.ts +340 -170
- package/package.json +1 -1
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical contract for `GET /auth/session/status/:sessionToken`.
|
|
3
|
+
*
|
|
4
|
+
* SINGLE SOURCE OF TRUTH for the wire shape of the cross-app device-flow
|
|
5
|
+
* session-status payload and the sanitized public application identity it
|
|
6
|
+
* embeds. The API validates its OUTPUT against these schemas; the auth app
|
|
7
|
+
* (consent UI) validates its INPUT against the same schemas. Because there is
|
|
8
|
+
* exactly one definition, the producer and the consumer cannot drift.
|
|
9
|
+
*
|
|
10
|
+
* The class of bug that motivated moving this into `@oxyhq/contracts`: the auth
|
|
11
|
+
* app's LOCAL `sessionStatusSchema` typed `sessionId` as a non-nullable
|
|
12
|
+
* `z.string().optional()`. The producer emits `sessionId: authorizedSessionId ||
|
|
13
|
+
* null`, so a PENDING session (not yet authorized) carries `sessionId: null` —
|
|
14
|
+
* `.optional()` permits `undefined`/missing but REJECTS `null`, so `safeParse`
|
|
15
|
+
* failed, the whole response collapsed to `null`, and the consent screen showed
|
|
16
|
+
* "Unable to identify the requesting application". Pinning the nullability in one
|
|
17
|
+
* shared place makes that drift impossible.
|
|
18
|
+
*
|
|
19
|
+
* Faithful to the producers:
|
|
20
|
+
* - `packages/api/src/utils/serializeApplication.ts` `serializePublicApplication`
|
|
21
|
+
* — the ONLY shape returned to an unauthenticated consent UI. Optional fields
|
|
22
|
+
* (`description`, `icon`, `websiteUrl`, `developerName`) are OMITTED when
|
|
23
|
+
* absent (never serialized as `null`), so they are `.optional()` — NOT
|
|
24
|
+
* `.nullable()`. `type` is the `Application.type` enum.
|
|
25
|
+
* - `packages/api/src/routes/auth.ts` `GET /session/status/:sessionToken` — the
|
|
26
|
+
* inner object of the API's `{ data: ... }` success envelope. The handler
|
|
27
|
+
* ALWAYS emits `status`, `authorized` (`status === 'authorized'`),
|
|
28
|
+
* `sessionToken`, `expiresAt` (ISO string), and `application` (resolved object
|
|
29
|
+
* OR `null`). It ALWAYS emits `sessionId` / `publicKey` / `userId`, each as a
|
|
30
|
+
* string value OR `null` (`authorizedSessionId || null`, `authorizedBy ||
|
|
31
|
+
* null`, `authorizedUserId?.toString() || null`).
|
|
32
|
+
*
|
|
33
|
+
* Platform-agnostic — zod only, no react/react-native/expo. ESM-safe (no
|
|
34
|
+
* `require()`).
|
|
35
|
+
*/
|
|
36
|
+
import { z } from 'zod';
|
|
37
|
+
/**
|
|
38
|
+
* Application `type` enum. Mirrors `APPLICATION_TYPES` in
|
|
39
|
+
* `packages/api/src/models/Application.ts` (`first_party` | `third_party` |
|
|
40
|
+
* `internal` | `system`).
|
|
41
|
+
*/
|
|
42
|
+
export declare const applicationTypeSchema: z.ZodEnum<["first_party", "third_party", "internal", "system"]>;
|
|
43
|
+
export type ApplicationTypeContract = z.infer<typeof applicationTypeSchema>;
|
|
44
|
+
/**
|
|
45
|
+
* The display-safe public identity of a requesting application, exactly as
|
|
46
|
+
* `serializePublicApplication` emits it. Returned by the API inside
|
|
47
|
+
* `GET /auth/session/status/:sessionToken` (device flow) and
|
|
48
|
+
* `GET /auth/oauth/client/:clientId` (OAuth code flow).
|
|
49
|
+
*
|
|
50
|
+
* Optional fields are `.optional()` (NOT `.nullable()`): the serializer OMITS
|
|
51
|
+
* `description` / `icon` / `websiteUrl` / `developerName` when the underlying
|
|
52
|
+
* value is absent — it never writes `null` for them. `developerName` is only
|
|
53
|
+
* attached for non-official apps when a name could be resolved.
|
|
54
|
+
*/
|
|
55
|
+
export declare const publicApplicationSchema: z.ZodObject<{
|
|
56
|
+
id: z.ZodString;
|
|
57
|
+
name: z.ZodString;
|
|
58
|
+
description: z.ZodOptional<z.ZodString>;
|
|
59
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
60
|
+
websiteUrl: z.ZodOptional<z.ZodString>;
|
|
61
|
+
type: z.ZodEnum<["first_party", "third_party", "internal", "system"]>;
|
|
62
|
+
isOfficial: z.ZodBoolean;
|
|
63
|
+
isInternal: z.ZodBoolean;
|
|
64
|
+
scopes: z.ZodArray<z.ZodString, "many">;
|
|
65
|
+
developerName: z.ZodOptional<z.ZodString>;
|
|
66
|
+
}, "strip", z.ZodTypeAny, {
|
|
67
|
+
type: "first_party" | "third_party" | "internal" | "system";
|
|
68
|
+
id: string;
|
|
69
|
+
name: string;
|
|
70
|
+
isOfficial: boolean;
|
|
71
|
+
isInternal: boolean;
|
|
72
|
+
scopes: string[];
|
|
73
|
+
description?: string | undefined;
|
|
74
|
+
icon?: string | undefined;
|
|
75
|
+
websiteUrl?: string | undefined;
|
|
76
|
+
developerName?: string | undefined;
|
|
77
|
+
}, {
|
|
78
|
+
type: "first_party" | "third_party" | "internal" | "system";
|
|
79
|
+
id: string;
|
|
80
|
+
name: string;
|
|
81
|
+
isOfficial: boolean;
|
|
82
|
+
isInternal: boolean;
|
|
83
|
+
scopes: string[];
|
|
84
|
+
description?: string | undefined;
|
|
85
|
+
icon?: string | undefined;
|
|
86
|
+
websiteUrl?: string | undefined;
|
|
87
|
+
developerName?: string | undefined;
|
|
88
|
+
}>;
|
|
89
|
+
export type PublicApplicationResponse = z.infer<typeof publicApplicationSchema>;
|
|
90
|
+
/**
|
|
91
|
+
* The inner object of `GET /auth/session/status/:sessionToken` (inside the API's
|
|
92
|
+
* `{ data: ... }` envelope).
|
|
93
|
+
*
|
|
94
|
+
* `application` is the resolved {@link publicApplicationSchema} identity of the
|
|
95
|
+
* requesting application, or `null` when the bound app was hard-deleted / is no
|
|
96
|
+
* longer `active` (defensive — normally always present).
|
|
97
|
+
*
|
|
98
|
+
* `sessionId` / `publicKey` / `userId` are `.nullable().optional()`: the producer
|
|
99
|
+
* ALWAYS emits the key, with a string for an AUTHORIZED session or `null` for a
|
|
100
|
+
* PENDING one. `.nullable()` accepts the PENDING `null`; `.optional()` is belt-
|
|
101
|
+
* and-braces so a consumer is never broken by a future projection that drops the
|
|
102
|
+
* key. (`.optional()` alone would REJECT the PENDING `null` — that was the bug.)
|
|
103
|
+
*
|
|
104
|
+
* `authorized` / `sessionToken` / `expiresAt` are emitted unconditionally by the
|
|
105
|
+
* current producer and are never `null`, but stay `.optional()` so the contract
|
|
106
|
+
* tolerates leaner shapes from other producers of this same payload without a
|
|
107
|
+
* coordinated bump.
|
|
108
|
+
*/
|
|
109
|
+
export declare const sessionStatusSchema: z.ZodObject<{
|
|
110
|
+
status: z.ZodString;
|
|
111
|
+
authorized: z.ZodOptional<z.ZodBoolean>;
|
|
112
|
+
sessionToken: z.ZodOptional<z.ZodString>;
|
|
113
|
+
application: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
114
|
+
id: z.ZodString;
|
|
115
|
+
name: z.ZodString;
|
|
116
|
+
description: z.ZodOptional<z.ZodString>;
|
|
117
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
118
|
+
websiteUrl: z.ZodOptional<z.ZodString>;
|
|
119
|
+
type: z.ZodEnum<["first_party", "third_party", "internal", "system"]>;
|
|
120
|
+
isOfficial: z.ZodBoolean;
|
|
121
|
+
isInternal: z.ZodBoolean;
|
|
122
|
+
scopes: z.ZodArray<z.ZodString, "many">;
|
|
123
|
+
developerName: z.ZodOptional<z.ZodString>;
|
|
124
|
+
}, "strip", z.ZodTypeAny, {
|
|
125
|
+
type: "first_party" | "third_party" | "internal" | "system";
|
|
126
|
+
id: string;
|
|
127
|
+
name: string;
|
|
128
|
+
isOfficial: boolean;
|
|
129
|
+
isInternal: boolean;
|
|
130
|
+
scopes: string[];
|
|
131
|
+
description?: string | undefined;
|
|
132
|
+
icon?: string | undefined;
|
|
133
|
+
websiteUrl?: string | undefined;
|
|
134
|
+
developerName?: string | undefined;
|
|
135
|
+
}, {
|
|
136
|
+
type: "first_party" | "third_party" | "internal" | "system";
|
|
137
|
+
id: string;
|
|
138
|
+
name: string;
|
|
139
|
+
isOfficial: boolean;
|
|
140
|
+
isInternal: boolean;
|
|
141
|
+
scopes: string[];
|
|
142
|
+
description?: string | undefined;
|
|
143
|
+
icon?: string | undefined;
|
|
144
|
+
websiteUrl?: string | undefined;
|
|
145
|
+
developerName?: string | undefined;
|
|
146
|
+
}>>>;
|
|
147
|
+
expiresAt: z.ZodOptional<z.ZodString>;
|
|
148
|
+
sessionId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
149
|
+
publicKey: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
150
|
+
userId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
151
|
+
}, "strip", z.ZodTypeAny, {
|
|
152
|
+
status: string;
|
|
153
|
+
publicKey?: string | null | undefined;
|
|
154
|
+
expiresAt?: string | undefined;
|
|
155
|
+
sessionId?: string | null | undefined;
|
|
156
|
+
authorized?: boolean | undefined;
|
|
157
|
+
sessionToken?: string | undefined;
|
|
158
|
+
application?: {
|
|
159
|
+
type: "first_party" | "third_party" | "internal" | "system";
|
|
160
|
+
id: string;
|
|
161
|
+
name: string;
|
|
162
|
+
isOfficial: boolean;
|
|
163
|
+
isInternal: boolean;
|
|
164
|
+
scopes: string[];
|
|
165
|
+
description?: string | undefined;
|
|
166
|
+
icon?: string | undefined;
|
|
167
|
+
websiteUrl?: string | undefined;
|
|
168
|
+
developerName?: string | undefined;
|
|
169
|
+
} | null | undefined;
|
|
170
|
+
userId?: string | null | undefined;
|
|
171
|
+
}, {
|
|
172
|
+
status: string;
|
|
173
|
+
publicKey?: string | null | undefined;
|
|
174
|
+
expiresAt?: string | undefined;
|
|
175
|
+
sessionId?: string | null | undefined;
|
|
176
|
+
authorized?: boolean | undefined;
|
|
177
|
+
sessionToken?: string | undefined;
|
|
178
|
+
application?: {
|
|
179
|
+
type: "first_party" | "third_party" | "internal" | "system";
|
|
180
|
+
id: string;
|
|
181
|
+
name: string;
|
|
182
|
+
isOfficial: boolean;
|
|
183
|
+
isInternal: boolean;
|
|
184
|
+
scopes: string[];
|
|
185
|
+
description?: string | undefined;
|
|
186
|
+
icon?: string | undefined;
|
|
187
|
+
websiteUrl?: string | undefined;
|
|
188
|
+
developerName?: string | undefined;
|
|
189
|
+
} | null | undefined;
|
|
190
|
+
userId?: string | null | undefined;
|
|
191
|
+
}>;
|
|
192
|
+
export type SessionStatusResponse = z.infer<typeof sessionStatusSchema>;
|