@oxyhq/contracts 0.10.0 → 0.12.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.
@@ -115,6 +115,14 @@ export interface AuthTokenBundle {
115
115
  refreshToken: string;
116
116
  expiresAt: string;
117
117
  user: UserResponse;
118
+ /**
119
+ * The device secret (phase 2c — zero-cookie transport). Present ONLY when
120
+ * the bundle is minted for a device that carries a `DeviceSession` doc; the
121
+ * client persists it first-party and later mints access tokens via
122
+ * `POST /session/device/token`. Optional and additive: cookie-lane bundles
123
+ * for a device with no doc omit it, so existing consumers are unaffected.
124
+ */
125
+ deviceSecret?: string;
118
126
  }
119
127
  export declare const authTokenBundleSchema: z.ZodType<AuthTokenBundle>;
120
128
  /**
@@ -213,6 +221,13 @@ export interface LoginSessionResult {
213
221
  expiresAt: string;
214
222
  accessToken?: string;
215
223
  refreshToken?: string;
224
+ /**
225
+ * The device secret (phase 2c — zero-cookie transport). Present ONLY when
226
+ * the sign-in resolved a device binding; the client persists it first-party
227
+ * and later mints access tokens via `POST /session/device/token`. Optional
228
+ * and additive — wired identically to `refreshToken`.
229
+ */
230
+ deviceSecret?: string;
216
231
  user: {
217
232
  id: string;
218
233
  username?: string;
@@ -245,7 +260,7 @@ export interface DeviceResolveAccount {
245
260
  /**
246
261
  * Wire shape of `POST /auth/device/resolve` — the device's active account id
247
262
  * (or `null` when signed out of all) plus every account signed in on the
248
- * device. Replaces the IdP's `/auth/refresh-all` chooser feed.
263
+ * device. Replaces the IdP's legacy cookie-based chooser feed.
249
264
  */
250
265
  export interface DeviceResolveResponse {
251
266
  activeAccountId: string | null;
@@ -163,3 +163,110 @@ export type SessionAccount = z.infer<typeof sessionAccountSchema>;
163
163
  export type DeviceSessionState = z.infer<typeof deviceSessionStateSchema>;
164
164
  export type ActiveToken = z.infer<typeof activeTokenSchema>;
165
165
  export type DeviceSessionSync = z.infer<typeof deviceSessionSyncSchema>;
166
+ /**
167
+ * Request body for `POST /session/device/token` — the client presents the
168
+ * `deviceId` it stored first-party plus the opaque `deviceSecret`. NO bearer:
169
+ * possession of the secret IS the proof of device ownership. The server matches
170
+ * `sha256(deviceSecret)` against the device's stored `secretHash` (constant-time)
171
+ * and mints a short access token for the device's active account.
172
+ */
173
+ export declare const deviceTokenMintRequestSchema: z.ZodObject<{
174
+ deviceId: z.ZodString;
175
+ deviceSecret: z.ZodString;
176
+ }, "strip", z.ZodTypeAny, {
177
+ deviceSecret: string;
178
+ deviceId: string;
179
+ }, {
180
+ deviceSecret: string;
181
+ deviceId: string;
182
+ }>;
183
+ /**
184
+ * Wire shape of a successful `POST /session/device/token`: the freshly-minted
185
+ * short access token for the active account, its expiry, the NEXT rotating
186
+ * device secret the client must persist (rotation-in-use — the presented secret
187
+ * stays valid for a short grace so multi-tab races don't lock out), and the
188
+ * projected device-session state.
189
+ */
190
+ export declare const deviceTokenMintResponseSchema: z.ZodObject<{
191
+ accessToken: z.ZodString;
192
+ expiresAt: z.ZodString;
193
+ nextDeviceSecret: z.ZodString;
194
+ state: z.ZodObject<{
195
+ deviceId: z.ZodString;
196
+ accounts: z.ZodArray<z.ZodObject<{
197
+ accountId: z.ZodString;
198
+ sessionId: z.ZodString;
199
+ authuser: z.ZodNumber;
200
+ operatedByUserId: z.ZodOptional<z.ZodString>;
201
+ }, "strip", z.ZodTypeAny, {
202
+ sessionId: string;
203
+ accountId: string;
204
+ authuser: number;
205
+ operatedByUserId?: string | undefined;
206
+ }, {
207
+ sessionId: string;
208
+ accountId: string;
209
+ authuser: number;
210
+ operatedByUserId?: string | undefined;
211
+ }>, "many">;
212
+ activeAccountId: z.ZodNullable<z.ZodString>;
213
+ revision: z.ZodNumber;
214
+ updatedAt: z.ZodNumber;
215
+ }, "strip", z.ZodTypeAny, {
216
+ updatedAt: number;
217
+ deviceId: string;
218
+ activeAccountId: string | null;
219
+ accounts: {
220
+ sessionId: string;
221
+ accountId: string;
222
+ authuser: number;
223
+ operatedByUserId?: string | undefined;
224
+ }[];
225
+ revision: number;
226
+ }, {
227
+ updatedAt: number;
228
+ deviceId: string;
229
+ activeAccountId: string | null;
230
+ accounts: {
231
+ sessionId: string;
232
+ accountId: string;
233
+ authuser: number;
234
+ operatedByUserId?: string | undefined;
235
+ }[];
236
+ revision: number;
237
+ }>;
238
+ }, "strip", z.ZodTypeAny, {
239
+ expiresAt: string;
240
+ state: {
241
+ updatedAt: number;
242
+ deviceId: string;
243
+ activeAccountId: string | null;
244
+ accounts: {
245
+ sessionId: string;
246
+ accountId: string;
247
+ authuser: number;
248
+ operatedByUserId?: string | undefined;
249
+ }[];
250
+ revision: number;
251
+ };
252
+ accessToken: string;
253
+ nextDeviceSecret: string;
254
+ }, {
255
+ expiresAt: string;
256
+ state: {
257
+ updatedAt: number;
258
+ deviceId: string;
259
+ activeAccountId: string | null;
260
+ accounts: {
261
+ sessionId: string;
262
+ accountId: string;
263
+ authuser: number;
264
+ operatedByUserId?: string | undefined;
265
+ }[];
266
+ revision: number;
267
+ };
268
+ accessToken: string;
269
+ nextDeviceSecret: string;
270
+ }>;
271
+ export type DeviceTokenMintRequest = z.infer<typeof deviceTokenMintRequestSchema>;
272
+ export type DeviceTokenMintResponse = z.infer<typeof deviceTokenMintResponseSchema>;
@@ -1,6 +1,16 @@
1
1
  /**
2
2
  * Canonical contract for the FedCM ID-token JWT payload.
3
3
  *
4
+ * DEAD SINCE THE WAVE-2 FEDCM DELETION (found during the comment sweep, not
5
+ * fixed here — this is a published `@oxyhq/contracts` export, so removing it
6
+ * is a breaking change/major-version decision, out of scope for a comment
7
+ * fix): `POST /fedcm/exchange`, `fedcm.service.exchangeIdToken`, and
8
+ * `packages/auth/server/index.ts`'s `mintSessionForClient` — every consumer
9
+ * and producer this file describes — are all deleted. No current code
10
+ * imports `fedcmTokenPayloadSchema` / `FedcmTokenPayload` outside this
11
+ * package. Flag for a follow-up major-version cleanup.
12
+ *
13
+ * Original doc (historical, describes the now-deleted system):
4
14
  * SINGLE SOURCE OF TRUTH for the decoded claims of the HS256 ID token the auth
5
15
  * IdP (`auth.oxy.so`) signs and `POST /fedcm/exchange` consumes. The API decodes
6
16
  * the JWT, verifies its signature, then validates the resulting claim object
@@ -9,8 +9,8 @@
9
9
  * Platform-agnostic — zod is the only runtime dependency. No react/react-native/
10
10
  * expo, no `require()` in the ESM build.
11
11
  */
12
- export { userNameSchema, userResponseSchema, userProfileUpdateSchema, currentUserResponseSchema, deviceSessionAccountSchema, deviceSessionsResponseSchema, resolveUserId, safeParseContract, } from './userResponse';
13
- export type { UserNameResponse, UserResponse, UserProfileUpdate, CurrentUserResponseContract, DeviceSessionAccountResponse, DeviceSessionsResponseContract, } from './userResponse';
12
+ export { userNameSchema, userResponseSchema, userProfileUpdateSchema, currentUserResponseSchema, deviceLinkedSessionSchema, deviceLinkedSessionsResponseSchema, resolveUserId, safeParseContract, } from './userResponse';
13
+ export type { UserNameResponse, UserResponse, UserProfileUpdate, CurrentUserResponseContract, DeviceLinkedSessionResponse, DeviceLinkedSessionsResponseContract, } from './userResponse';
14
14
  export { applicationTypeSchema, publicApplicationSchema, sessionStatusSchema, } from './sessionStatus';
15
15
  export type { ApplicationTypeContract, PublicApplicationResponse, SessionStatusResponse, } from './sessionStatus';
16
16
  export { fedcmTokenPayloadSchema, } from './fedcmToken';
@@ -27,7 +27,7 @@ export { publicCardSchema, signedPublicCardSchema, realLifeAttestationRecordSche
27
27
  export type { CardTrustTier, PersonhoodStatus, PublicCard, SignedPublicCard, RealLifeAttestationRecord, RealLifeAttestationResult, ValidationVerdict, ValidationRequestStatus, ValidationVerdictRecord, ValidationOpenRequest, ValidationOpenResult, ValidationRequestSummary, ValidationVoteResult, PersonhoodVouchRecord, PersonhoodBreakdown, PersonhoodStatusResult, VouchResult, CredentialStatus, CredentialRecord, VerifiableCredentialResponse, CredentialIssueResult, CredentialListResult, CredentialVerifyResult, } from './civic';
28
28
  export { linkPreviewSchema, linkPreviewBatchRequestSchema, linkPreviewBatchResponseSchema, linkPreviewResponseSchema, } from './links';
29
29
  export type { LinkPreviewStatus, LinkPreview, LinkPreviewBatchRequest, LinkPreviewBatchResponse, } from './links';
30
- export { sessionAccountSchema, deviceSessionStateSchema, activeTokenSchema, deviceSessionSyncSchema, } from './deviceSession';
31
- export type { SessionAccount, DeviceSessionState, ActiveToken, DeviceSessionSync, } from './deviceSession';
30
+ export { sessionAccountSchema, deviceSessionStateSchema, activeTokenSchema, deviceSessionSyncSchema, deviceTokenMintRequestSchema, deviceTokenMintResponseSchema, } from './deviceSession';
31
+ export type { SessionAccount, DeviceSessionState, ActiveToken, DeviceSessionSync, DeviceTokenMintRequest, DeviceTokenMintResponse, } from './deviceSession';
32
32
  export { deviceBootReasonSchema, deviceBootFragmentSchema, deviceExchangeRequestSchema, authTokenBundleSchema, webSessionResultSchema, tokenRefreshRequestSchema, tokenRefreshResponseSchema, deviceTokenIssueResponseSchema, loginResultSchema, deviceResolveRequestSchema, deviceResolveResponseSchema, } from './deviceBoot';
33
33
  export type { DeviceBootReason, DeviceBootFragment, DeviceExchangeRequest, AuthTokenBundle, WebSessionResult, WebSessionSession, WebSessionNoSession, TokenRefreshRequest, TokenRefreshResponse, DeviceTokenIssueResponse, LoginTwoFactorRequired, LoginSessionResult, LoginResult, DeviceResolveRequest, DeviceResolveAccount, DeviceResolveResponse, } from './deviceBoot';
@@ -19,9 +19,10 @@
19
19
  * Faithful to the producers:
20
20
  * - `packages/api/src/utils/serializeApplication.ts` `serializePublicApplication`
21
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.
22
+ * (`description`, `icon`, `websiteUrl`, `privacyPolicyUrl`, `termsUrl`,
23
+ * `developerName`) are OMITTED when absent (never serialized as `null`), so
24
+ * they are `.optional()` — NOT `.nullable()`. `type` is the `Application.type`
25
+ * enum.
25
26
  * - `packages/api/src/routes/auth.ts` `GET /session/status/:sessionToken` — the
26
27
  * inner object of the API's `{ data: ... }` success envelope. The handler
27
28
  * ALWAYS emits `status`, `authorized` (`status === 'authorized'`),
@@ -48,9 +49,10 @@ export type ApplicationTypeContract = z.infer<typeof applicationTypeSchema>;
48
49
  * `GET /auth/oauth/client/:clientId` (OAuth code flow).
49
50
  *
50
51
  * 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.
52
+ * `description` / `icon` / `websiteUrl` / `privacyPolicyUrl` / `termsUrl` /
53
+ * `developerName` when the underlying value is absent — it never writes `null`
54
+ * for them. `developerName` is only attached for non-official apps when a name
55
+ * could be resolved.
54
56
  */
55
57
  export declare const publicApplicationSchema: z.ZodObject<{
56
58
  id: z.ZodString;
@@ -58,6 +60,8 @@ export declare const publicApplicationSchema: z.ZodObject<{
58
60
  description: z.ZodOptional<z.ZodString>;
59
61
  icon: z.ZodOptional<z.ZodString>;
60
62
  websiteUrl: z.ZodOptional<z.ZodString>;
63
+ privacyPolicyUrl: z.ZodOptional<z.ZodString>;
64
+ termsUrl: z.ZodOptional<z.ZodString>;
61
65
  type: z.ZodEnum<["first_party", "third_party", "internal", "system"]>;
62
66
  isOfficial: z.ZodBoolean;
63
67
  isInternal: z.ZodBoolean;
@@ -73,6 +77,8 @@ export declare const publicApplicationSchema: z.ZodObject<{
73
77
  description?: string | undefined;
74
78
  icon?: string | undefined;
75
79
  websiteUrl?: string | undefined;
80
+ privacyPolicyUrl?: string | undefined;
81
+ termsUrl?: string | undefined;
76
82
  developerName?: string | undefined;
77
83
  }, {
78
84
  id: string;
@@ -84,6 +90,8 @@ export declare const publicApplicationSchema: z.ZodObject<{
84
90
  description?: string | undefined;
85
91
  icon?: string | undefined;
86
92
  websiteUrl?: string | undefined;
93
+ privacyPolicyUrl?: string | undefined;
94
+ termsUrl?: string | undefined;
87
95
  developerName?: string | undefined;
88
96
  }>;
89
97
  export type PublicApplicationResponse = z.infer<typeof publicApplicationSchema>;
@@ -116,6 +124,8 @@ export declare const sessionStatusSchema: z.ZodObject<{
116
124
  description: z.ZodOptional<z.ZodString>;
117
125
  icon: z.ZodOptional<z.ZodString>;
118
126
  websiteUrl: z.ZodOptional<z.ZodString>;
127
+ privacyPolicyUrl: z.ZodOptional<z.ZodString>;
128
+ termsUrl: z.ZodOptional<z.ZodString>;
119
129
  type: z.ZodEnum<["first_party", "third_party", "internal", "system"]>;
120
130
  isOfficial: z.ZodBoolean;
121
131
  isInternal: z.ZodBoolean;
@@ -131,6 +141,8 @@ export declare const sessionStatusSchema: z.ZodObject<{
131
141
  description?: string | undefined;
132
142
  icon?: string | undefined;
133
143
  websiteUrl?: string | undefined;
144
+ privacyPolicyUrl?: string | undefined;
145
+ termsUrl?: string | undefined;
134
146
  developerName?: string | undefined;
135
147
  }, {
136
148
  id: string;
@@ -142,6 +154,8 @@ export declare const sessionStatusSchema: z.ZodObject<{
142
154
  description?: string | undefined;
143
155
  icon?: string | undefined;
144
156
  websiteUrl?: string | undefined;
157
+ privacyPolicyUrl?: string | undefined;
158
+ termsUrl?: string | undefined;
145
159
  developerName?: string | undefined;
146
160
  }>>>;
147
161
  expiresAt: z.ZodOptional<z.ZodString>;
@@ -166,6 +180,8 @@ export declare const sessionStatusSchema: z.ZodObject<{
166
180
  description?: string | undefined;
167
181
  icon?: string | undefined;
168
182
  websiteUrl?: string | undefined;
183
+ privacyPolicyUrl?: string | undefined;
184
+ termsUrl?: string | undefined;
169
185
  developerName?: string | undefined;
170
186
  } | null | undefined;
171
187
  }, {
@@ -186,6 +202,8 @@ export declare const sessionStatusSchema: z.ZodObject<{
186
202
  description?: string | undefined;
187
203
  icon?: string | undefined;
188
204
  websiteUrl?: string | undefined;
205
+ privacyPolicyUrl?: string | undefined;
206
+ termsUrl?: string | undefined;
189
207
  developerName?: string | undefined;
190
208
  } | null | undefined;
191
209
  }>;
@@ -16,7 +16,8 @@
16
16
  *
17
17
  * Faithful to the producers:
18
18
  * - `packages/api/src/utils/userTransform.ts` `formatUserResponse` — the
19
- * canonical serialization used by `/auth/refresh-all`, device sessions, etc.
19
+ * canonical serialization used by the device-first bootstrap/exchange
20
+ * endpoints (`deviceAuth.ts`), login/signup, device sessions, etc.
20
21
  * Emits `id` (NOT `_id`), forwards `username` verbatim (may be absent), and
21
22
  * emits `name` as the structured `{ first, last, full, displayName }`
22
23
  * subdocument.
@@ -24,8 +25,6 @@
24
25
  * `''`; `full` and `displayName` are Mongoose VIRTUALS. Formatted API
25
26
  * responses compose both fields, while raw-document responses may omit the
26
27
  * virtuals if the query did not materialise them.
27
- * - The `/auth/refresh-all` handler in `packages/api/src/routes/auth.ts`, whose
28
- * per-slot `authuser` is the numeric `oxy_rt_${authuser}` cookie slot.
29
28
  *
30
29
  * Platform-agnostic — zod only, no react/react-native/expo. ESM-safe (no
31
30
  * `require()`).
@@ -457,7 +456,7 @@ export type CurrentUserResponseContract = z.infer<typeof currentUserResponseSche
457
456
  * session). Backs the multi-account chooser. The embedded user mirrors
458
457
  * `formatUserResponse`; it is nullable on slots that lost their user document.
459
458
  */
460
- export declare const deviceSessionAccountSchema: z.ZodObject<{
459
+ export declare const deviceLinkedSessionSchema: z.ZodObject<{
461
460
  sessionId: z.ZodString;
462
461
  isCurrent: z.ZodOptional<z.ZodBoolean>;
463
462
  user: z.ZodOptional<z.ZodNullable<z.ZodObject<{
@@ -615,9 +614,9 @@ export declare const deviceSessionAccountSchema: z.ZodObject<{
615
614
  verifiedDomains: z.ZodOptional<z.ZodArray<z.ZodType<import("./identity").VerifiedDomain, z.ZodTypeDef, import("./identity").VerifiedDomain>, "many">>;
616
615
  }, z.ZodTypeAny, "passthrough"> | null | undefined;
617
616
  }>;
618
- export type DeviceSessionAccountResponse = z.infer<typeof deviceSessionAccountSchema>;
617
+ export type DeviceLinkedSessionResponse = z.infer<typeof deviceLinkedSessionSchema>;
619
618
  /** Wire shape of `GET /session/device/sessions/:sessionId` (an array). */
620
- export declare const deviceSessionsResponseSchema: z.ZodArray<z.ZodObject<{
619
+ export declare const deviceLinkedSessionsResponseSchema: z.ZodArray<z.ZodObject<{
621
620
  sessionId: z.ZodString;
622
621
  isCurrent: z.ZodOptional<z.ZodBoolean>;
623
622
  user: z.ZodOptional<z.ZodNullable<z.ZodObject<{
@@ -775,7 +774,7 @@ export declare const deviceSessionsResponseSchema: z.ZodArray<z.ZodObject<{
775
774
  verifiedDomains: z.ZodOptional<z.ZodArray<z.ZodType<import("./identity").VerifiedDomain, z.ZodTypeDef, import("./identity").VerifiedDomain>, "many">>;
776
775
  }, z.ZodTypeAny, "passthrough"> | null | undefined;
777
776
  }>, "many">;
778
- export type DeviceSessionsResponseContract = z.infer<typeof deviceSessionsResponseSchema>;
777
+ export type DeviceLinkedSessionsResponseContract = z.infer<typeof deviceLinkedSessionsResponseSchema>;
779
778
  /**
780
779
  * Safely parse a value against a contract schema. Returns the parsed (typed)
781
780
  * value, or `null` when validation fails — the same ergonomics the auth app's
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/contracts",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "OxyHQ API contracts — single source of truth for request/response Zod schemas and inferred types, shared by the backend and the client SDKs",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",