@sealant/api-contracts-next 0.39.0-next.754 → 0.40.0-next.756

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,5 @@
1
+ /**
2
+ * The account selector that resolves to the owner's chosen default for a provider. Its own
3
+ * dependency-free entry so the bundled CLI can import it without the HttpApi contract.
4
+ */
5
+ export declare const DEFAULT_ACCOUNT_SELECTOR = "default";
@@ -0,0 +1,5 @@
1
+ /**
2
+ * The account selector that resolves to the owner's chosen default for a provider. Its own
3
+ * dependency-free entry so the bundled CLI can import it without the HttpApi contract.
4
+ */
5
+ export const DEFAULT_ACCOUNT_SELECTOR = "default";
@@ -44,12 +44,30 @@ export declare const connectedAccountSummarySchema: Schema.Struct<{
44
44
  /** What that attempt did: `refreshed`, `fresh` (nothing to do), or `failed`. */
45
45
  readonly lastRefreshOutcome: Schema.NullOr<Schema.Literals<readonly ["refreshed", "fresh", "failed"]>>;
46
46
  }>;
47
+ /** Whether this is the owner's default for its provider. Absent from older control planes. */
48
+ readonly isDefault: Schema.optional<Schema.Boolean>;
49
+ /**
50
+ * Which credential the account holds: starts at 1 and moves on whenever a reconnect or refresh
51
+ * stores different bytes. Absent from older control planes.
52
+ */
53
+ readonly credentialRevision: Schema.optional<Schema.Int>;
47
54
  }>;
48
55
  export type ConnectedAccountSummary = typeof connectedAccountSummarySchema.Type;
49
56
  export declare const createConnectedAccountRequestSchema: Schema.Struct<{
50
57
  readonly ownerUserId: Schema.String;
51
58
  readonly provider: Schema.Literals<readonly ["claude", "codex", "github"]>;
59
+ /**
60
+ * The account to connect or replace by name; a new name is a new account, and `default` names
61
+ * the owner's chosen default. The owner's first account for the provider is named `default`
62
+ * whatever this says. With neither `name` nor `accountId` (or `default` while none is chosen),
63
+ * the owner's only account is replaced, and with several the connect is refused (`409`,
64
+ * `connected-account-ambiguous`, with `candidateAccountIds`).
65
+ */
52
66
  readonly name: Schema.optional<Schema.String>;
67
+ /** Replace this account (the owner's, of `provider`). Not with `name`. */
68
+ readonly accountId: Schema.optional<Schema.String>;
69
+ /** Make the connected account the owner's default for the provider, in the same write. */
70
+ readonly makeDefault: Schema.optional<Schema.Boolean>;
53
71
  readonly secret: Schema.String;
54
72
  }>;
55
73
  export type CreateConnectedAccountRequest = typeof createConnectedAccountRequestSchema.Type;
@@ -81,13 +99,64 @@ export declare const listConnectedAccountsResponseSchema: Schema.Struct<{
81
99
  /** What that attempt did: `refreshed`, `fresh` (nothing to do), or `failed`. */
82
100
  readonly lastRefreshOutcome: Schema.NullOr<Schema.Literals<readonly ["refreshed", "fresh", "failed"]>>;
83
101
  }>;
102
+ /** Whether this is the owner's default for its provider. Absent from older control planes. */
103
+ readonly isDefault: Schema.optional<Schema.Boolean>;
104
+ /**
105
+ * Which credential the account holds: starts at 1 and moves on whenever a reconnect or refresh
106
+ * stores different bytes. Absent from older control planes.
107
+ */
108
+ readonly credentialRevision: Schema.optional<Schema.Int>;
84
109
  }>>;
85
110
  }>;
86
111
  export type ListConnectedAccountsResponse = typeof listConnectedAccountsResponseSchema.Type;
87
112
  export declare const markConnectedAccountInvalidRequestSchema: Schema.Struct<{
88
113
  readonly ownerUserId: Schema.String;
114
+ /**
115
+ * The `credentialRevision` the refusal was observed on. When the stored credential has moved on
116
+ * since, nothing is marked and the answer's `outcome` is `superseded`.
117
+ */
118
+ readonly revision: Schema.optional<Schema.Int>;
89
119
  }>;
90
120
  export type MarkConnectedAccountInvalidRequest = typeof markConnectedAccountInvalidRequestSchema.Type;
121
+ export declare const markConnectedAccountInvalidResponseSchema: Schema.Struct<{
122
+ readonly connectedAccountId: Schema.String;
123
+ readonly ownerUserId: Schema.String;
124
+ readonly provider: Schema.Literals<readonly ["claude", "codex", "github"]>;
125
+ readonly name: Schema.String;
126
+ readonly kind: Schema.String;
127
+ readonly status: Schema.Literals<readonly ["active", "invalid", "archived"]>;
128
+ readonly metadata: Schema.$Record<Schema.String, Schema.Unknown>;
129
+ readonly connectedAt: Schema.String;
130
+ readonly updatedAt: Schema.String;
131
+ readonly lastUsedAt: Schema.NullOr<Schema.String>;
132
+ readonly lastSyncedAt: Schema.NullOr<Schema.String>;
133
+ /** Freshness as the control plane observed it; see the schema above for what null means. */
134
+ readonly credential: Schema.Struct<{
135
+ /** When the access token expires. Hours, for a Claude session credential. */
136
+ readonly accessExpiresAt: Schema.NullOr<Schema.String>;
137
+ /** When the grant itself expires, after which reconnecting is the only way back. */
138
+ readonly refreshExpiresAt: Schema.NullOr<Schema.String>;
139
+ /** When the platform last rotated or checked this credential. */
140
+ readonly lastRefreshAt: Schema.NullOr<Schema.String>;
141
+ /** What that attempt did: `refreshed`, `fresh` (nothing to do), or `failed`. */
142
+ readonly lastRefreshOutcome: Schema.NullOr<Schema.Literals<readonly ["refreshed", "fresh", "failed"]>>;
143
+ }>;
144
+ /** Whether this is the owner's default for its provider. Absent from older control planes. */
145
+ readonly isDefault: Schema.optional<Schema.Boolean>;
146
+ /**
147
+ * Which credential the account holds: starts at 1 and moves on whenever a reconnect or refresh
148
+ * stores different bytes. Absent from older control planes.
149
+ */
150
+ readonly credentialRevision: Schema.optional<Schema.Int>;
151
+ /** `marked`: the account is now invalid. `superseded`: a newer credential, left as it was. */
152
+ readonly outcome: Schema.optional<Schema.Literals<readonly ["marked", "superseded"]>>;
153
+ }>;
154
+ export type MarkConnectedAccountInvalidResponse = typeof markConnectedAccountInvalidResponseSchema.Type;
155
+ export declare const setConnectedAccountDefaultRequestSchema: Schema.Struct<{
156
+ readonly ownerUserId: Schema.String;
157
+ readonly connectedAccountId: Schema.String;
158
+ }>;
159
+ export type SetConnectedAccountDefaultRequest = typeof setConnectedAccountDefaultRequestSchema.Type;
91
160
  declare const ConnectedAccountBadRequestError_base: Schema.Class<ConnectedAccountBadRequestError, Schema.TaggedStruct<"ConnectedAccountBadRequestError", {
92
161
  readonly message: Schema.String;
93
162
  }>, import("effect/Cause").YieldableError>;
@@ -100,6 +169,14 @@ export declare class ConnectedAccountNotFoundError extends ConnectedAccountNotFo
100
169
  }
101
170
  declare const ConnectedAccountConflictError_base: Schema.Class<ConnectedAccountConflictError, Schema.TaggedStruct<"ConnectedAccountConflictError", {
102
171
  readonly message: Schema.String;
172
+ /**
173
+ * A stable reason, where one applies: `connected-account-ambiguous` (a connect without a target
174
+ * while the owner has several accounts for the provider), `connected-account-invalid` (a default
175
+ * chosen while its credential is invalid).
176
+ */
177
+ readonly code: Schema.optional<Schema.Literals<readonly ["connected-account-ambiguous", "connected-account-invalid"]>>;
178
+ /** The accounts a `connected-account-ambiguous` connect could have meant. */
179
+ readonly candidateAccountIds: Schema.optional<Schema.$Array<Schema.String>>;
103
180
  }>, import("effect/Cause").YieldableError>;
104
181
  export declare class ConnectedAccountConflictError extends ConnectedAccountConflictError_base {
105
182
  }
@@ -140,10 +217,28 @@ export declare const ConnectedAccountsGroup: HttpApiGroup.HttpApiGroup<"connecte
140
217
  /** What that attempt did: `refreshed`, `fresh` (nothing to do), or `failed`. */
141
218
  readonly lastRefreshOutcome: Schema.NullOr<Schema.Literals<readonly ["refreshed", "fresh", "failed"]>>;
142
219
  }>;
220
+ /** Whether this is the owner's default for its provider. Absent from older control planes. */
221
+ readonly isDefault: Schema.optional<Schema.Boolean>;
222
+ /**
223
+ * Which credential the account holds: starts at 1 and moves on whenever a reconnect or refresh
224
+ * stores different bytes. Absent from older control planes.
225
+ */
226
+ readonly credentialRevision: Schema.optional<Schema.Int>;
143
227
  }>>, Schema.toCodecJson<typeof ConnectedAccountNotFoundError | typeof ConnectedAccountInternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"createConnectedAccount", "POST", "/", never, never, Schema.toCodecJson<Schema.Struct<{
144
228
  readonly ownerUserId: Schema.String;
145
229
  readonly provider: Schema.Literals<readonly ["claude", "codex", "github"]>;
230
+ /**
231
+ * The account to connect or replace by name; a new name is a new account, and `default` names
232
+ * the owner's chosen default. The owner's first account for the provider is named `default`
233
+ * whatever this says. With neither `name` nor `accountId` (or `default` while none is chosen),
234
+ * the owner's only account is replaced, and with several the connect is refused (`409`,
235
+ * `connected-account-ambiguous`, with `candidateAccountIds`).
236
+ */
146
237
  readonly name: Schema.optional<Schema.String>;
238
+ /** Replace this account (the owner's, of `provider`). Not with `name`. */
239
+ readonly accountId: Schema.optional<Schema.String>;
240
+ /** Make the connected account the owner's default for the provider, in the same write. */
241
+ readonly makeDefault: Schema.optional<Schema.Boolean>;
147
242
  readonly secret: Schema.String;
148
243
  }>>, never, Schema.toCodecJson<Schema.Struct<{
149
244
  readonly connectedAccountId: Schema.String;
@@ -168,6 +263,13 @@ export declare const ConnectedAccountsGroup: HttpApiGroup.HttpApiGroup<"connecte
168
263
  /** What that attempt did: `refreshed`, `fresh` (nothing to do), or `failed`. */
169
264
  readonly lastRefreshOutcome: Schema.NullOr<Schema.Literals<readonly ["refreshed", "fresh", "failed"]>>;
170
265
  }>;
266
+ /** Whether this is the owner's default for its provider. Absent from older control planes. */
267
+ readonly isDefault: Schema.optional<Schema.Boolean>;
268
+ /**
269
+ * Which credential the account holds: starts at 1 and moves on whenever a reconnect or refresh
270
+ * stores different bytes. Absent from older control planes.
271
+ */
272
+ readonly credentialRevision: Schema.optional<Schema.Int>;
171
273
  }>>, Schema.toCodecJson<typeof ConnectedAccountBadRequestError | typeof ConnectedAccountNotFoundError | typeof ConnectedAccountConflictError | typeof ConnectedAccountServiceUnavailableError | typeof ConnectedAccountInternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"listConnectedAccounts", "GET", "/", never, Schema.toCodecStringTree<Schema.Struct<{
172
274
  readonly ownerUserId: Schema.String;
173
275
  }>>, never, never, Schema.toCodecJson<Schema.Struct<{
@@ -194,11 +296,60 @@ export declare const ConnectedAccountsGroup: HttpApiGroup.HttpApiGroup<"connecte
194
296
  /** What that attempt did: `refreshed`, `fresh` (nothing to do), or `failed`. */
195
297
  readonly lastRefreshOutcome: Schema.NullOr<Schema.Literals<readonly ["refreshed", "fresh", "failed"]>>;
196
298
  }>;
299
+ /** Whether this is the owner's default for its provider. Absent from older control planes. */
300
+ readonly isDefault: Schema.optional<Schema.Boolean>;
301
+ /**
302
+ * Which credential the account holds: starts at 1 and moves on whenever a reconnect or refresh
303
+ * stores different bytes. Absent from older control planes.
304
+ */
305
+ readonly credentialRevision: Schema.optional<Schema.Int>;
197
306
  }>>;
198
307
  }>>, Schema.toCodecJson<typeof ConnectedAccountInternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"markConnectedAccountInvalid", "POST", "/:connectedAccountId/mark-invalid", Schema.toCodecStringTree<Schema.Struct<{
199
308
  readonly connectedAccountId: Schema.String;
200
309
  }>>, never, Schema.toCodecJson<Schema.Struct<{
201
310
  readonly ownerUserId: Schema.String;
311
+ /**
312
+ * The `credentialRevision` the refusal was observed on. When the stored credential has moved on
313
+ * since, nothing is marked and the answer's `outcome` is `superseded`.
314
+ */
315
+ readonly revision: Schema.optional<Schema.Int>;
316
+ }>>, never, Schema.toCodecJson<Schema.Struct<{
317
+ readonly connectedAccountId: Schema.String;
318
+ readonly ownerUserId: Schema.String;
319
+ readonly provider: Schema.Literals<readonly ["claude", "codex", "github"]>;
320
+ readonly name: Schema.String;
321
+ readonly kind: Schema.String;
322
+ readonly status: Schema.Literals<readonly ["active", "invalid", "archived"]>;
323
+ readonly metadata: Schema.$Record<Schema.String, Schema.Unknown>;
324
+ readonly connectedAt: Schema.String;
325
+ readonly updatedAt: Schema.String;
326
+ readonly lastUsedAt: Schema.NullOr<Schema.String>;
327
+ readonly lastSyncedAt: Schema.NullOr<Schema.String>;
328
+ /** Freshness as the control plane observed it; see the schema above for what null means. */
329
+ readonly credential: Schema.Struct<{
330
+ /** When the access token expires. Hours, for a Claude session credential. */
331
+ readonly accessExpiresAt: Schema.NullOr<Schema.String>;
332
+ /** When the grant itself expires, after which reconnecting is the only way back. */
333
+ readonly refreshExpiresAt: Schema.NullOr<Schema.String>;
334
+ /** When the platform last rotated or checked this credential. */
335
+ readonly lastRefreshAt: Schema.NullOr<Schema.String>;
336
+ /** What that attempt did: `refreshed`, `fresh` (nothing to do), or `failed`. */
337
+ readonly lastRefreshOutcome: Schema.NullOr<Schema.Literals<readonly ["refreshed", "fresh", "failed"]>>;
338
+ }>;
339
+ /** Whether this is the owner's default for its provider. Absent from older control planes. */
340
+ readonly isDefault: Schema.optional<Schema.Boolean>;
341
+ /**
342
+ * Which credential the account holds: starts at 1 and moves on whenever a reconnect or refresh
343
+ * stores different bytes. Absent from older control planes.
344
+ */
345
+ readonly credentialRevision: Schema.optional<Schema.Int>;
346
+ /** `marked`: the account is now invalid. `superseded`: a newer credential, left as it was. */
347
+ readonly outcome: Schema.optional<Schema.Literals<readonly ["marked", "superseded"]>>;
348
+ }>>, Schema.toCodecJson<typeof ConnectedAccountNotFoundError | typeof ConnectedAccountInternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"setConnectedAccountDefault", "PUT", "/defaults/:provider", Schema.toCodecStringTree<Schema.Struct<{
349
+ readonly provider: Schema.Literals<readonly ["claude", "codex", "github"]>;
350
+ }>>, never, Schema.toCodecJson<Schema.Struct<{
351
+ readonly ownerUserId: Schema.String;
352
+ readonly connectedAccountId: Schema.String;
202
353
  }>>, never, Schema.toCodecJson<Schema.Struct<{
203
354
  readonly connectedAccountId: Schema.String;
204
355
  readonly ownerUserId: Schema.String;
@@ -222,5 +373,12 @@ export declare const ConnectedAccountsGroup: HttpApiGroup.HttpApiGroup<"connecte
222
373
  /** What that attempt did: `refreshed`, `fresh` (nothing to do), or `failed`. */
223
374
  readonly lastRefreshOutcome: Schema.NullOr<Schema.Literals<readonly ["refreshed", "fresh", "failed"]>>;
224
375
  }>;
225
- }>>, Schema.toCodecJson<typeof ConnectedAccountNotFoundError | typeof ConnectedAccountInternalServerError>, never, never>, false>;
376
+ /** Whether this is the owner's default for its provider. Absent from older control planes. */
377
+ readonly isDefault: Schema.optional<Schema.Boolean>;
378
+ /**
379
+ * Which credential the account holds: starts at 1 and moves on whenever a reconnect or refresh
380
+ * stores different bytes. Absent from older control planes.
381
+ */
382
+ readonly credentialRevision: Schema.optional<Schema.Int>;
383
+ }>>, Schema.toCodecJson<typeof ConnectedAccountNotFoundError | typeof ConnectedAccountConflictError | typeof ConnectedAccountInternalServerError>, never, never>, false>;
226
384
  export {};
@@ -12,6 +12,11 @@ provider-shaped plaintext INTO the API, where it is validated, encrypted (AES-25
12
12
  expose only non-secret metadata (token suffix, codex account id/email, github login+scopes).
13
13
  `markConnectedAccountInvalid` is the internal 401-feedback hook (worker/sync-back observed the
14
14
  provider rejecting the credential).
15
+
16
+ Each person has at most one default account per provider, the one the selector `default` (the
17
+ SDK's `true`) means. Connecting a person's first account for a provider makes it the default;
18
+ after that only `makeDefault` on a connect, or `setConnectedAccountDefault`, changes it.
19
+ Disconnecting the default leaves the person without one: no other account is chosen for them.
15
20
  */
16
21
  export const connectedAccountProviderSchema = Schema.Literals(["claude", "codex", "github"]);
17
22
  export const connectedAccountStatusSchema = Schema.Literals(["active", "invalid", "archived"]);
@@ -47,12 +52,29 @@ export const connectedAccountSummarySchema = Schema.Struct({
47
52
  lastSyncedAt: Schema.NullOr(Schema.String),
48
53
  /** Freshness as the control plane observed it; see the schema above for what null means. */
49
54
  credential: connectedAccountCredentialSchema,
55
+ /** Whether this is the owner's default for its provider. Absent from older control planes. */
56
+ isDefault: Schema.optional(Schema.Boolean),
57
+ /**
58
+ * Which credential the account holds: starts at 1 and moves on whenever a reconnect or refresh
59
+ * stores different bytes. Absent from older control planes.
60
+ */
61
+ credentialRevision: Schema.optional(Schema.Int),
50
62
  });
51
63
  export const createConnectedAccountRequestSchema = Schema.Struct({
52
64
  ownerUserId: NonEmptyString,
53
65
  provider: connectedAccountProviderSchema,
54
- // Multiple accounts per provider are allowed; defaults to "default".
66
+ /**
67
+ * The account to connect or replace by name; a new name is a new account, and `default` names
68
+ * the owner's chosen default. The owner's first account for the provider is named `default`
69
+ * whatever this says. With neither `name` nor `accountId` (or `default` while none is chosen),
70
+ * the owner's only account is replaced, and with several the connect is refused (`409`,
71
+ * `connected-account-ambiguous`, with `candidateAccountIds`).
72
+ */
55
73
  name: Schema.optional(NonEmptyString),
74
+ /** Replace this account (the owner's, of `provider`). Not with `name`. */
75
+ accountId: Schema.optional(NonEmptyString),
76
+ /** Make the connected account the owner's default for the provider, in the same write. */
77
+ makeDefault: Schema.optional(Schema.Boolean),
56
78
  // Provider-shaped plaintext: claude setup-token or verbatim .credentials.json contents /
57
79
  // verbatim codex auth.json contents / github token. Encrypted server-side; never stored or
58
80
  // echoed back as-is. Not trimmed here — pasted credential files are stored verbatim.
@@ -66,6 +88,20 @@ export const listConnectedAccountsResponseSchema = Schema.Struct({
66
88
  });
67
89
  export const markConnectedAccountInvalidRequestSchema = Schema.Struct({
68
90
  ownerUserId: NonEmptyString,
91
+ /**
92
+ * The `credentialRevision` the refusal was observed on. When the stored credential has moved on
93
+ * since, nothing is marked and the answer's `outcome` is `superseded`.
94
+ */
95
+ revision: Schema.optional(Schema.Int),
96
+ });
97
+ export const markConnectedAccountInvalidResponseSchema = Schema.Struct({
98
+ ...connectedAccountSummarySchema.fields,
99
+ /** `marked`: the account is now invalid. `superseded`: a newer credential, left as it was. */
100
+ outcome: Schema.optional(Schema.Literals(["marked", "superseded"])),
101
+ });
102
+ export const setConnectedAccountDefaultRequestSchema = Schema.Struct({
103
+ ownerUserId: NonEmptyString,
104
+ connectedAccountId: NonEmptyString,
69
105
  });
70
106
  export class ConnectedAccountBadRequestError extends Schema.TaggedError()("ConnectedAccountBadRequestError", {
71
107
  message: Schema.String,
@@ -77,6 +113,14 @@ export class ConnectedAccountNotFoundError extends Schema.TaggedError()("Connect
77
113
  }
78
114
  export class ConnectedAccountConflictError extends Schema.TaggedError()("ConnectedAccountConflictError", {
79
115
  message: Schema.String,
116
+ /**
117
+ * A stable reason, where one applies: `connected-account-ambiguous` (a connect without a target
118
+ * while the owner has several accounts for the provider), `connected-account-invalid` (a default
119
+ * chosen while its credential is invalid).
120
+ */
121
+ code: Schema.optional(Schema.Literals(["connected-account-ambiguous", "connected-account-invalid"])),
122
+ /** The accounts a `connected-account-ambiguous` connect could have meant. */
123
+ candidateAccountIds: Schema.optional(Schema.Array(NonEmptyString)),
80
124
  }, { httpApiStatus: 409 }) {
81
125
  }
82
126
  export class ConnectedAccountServiceUnavailableError extends Schema.TaggedError()("ConnectedAccountServiceUnavailableError", {
@@ -88,11 +132,9 @@ export class ConnectedAccountInternalServerError extends Schema.TaggedError()("C
88
132
  }, { httpApiStatus: 500 }) {
89
133
  }
90
134
  const connectedAccountIdParams = Schema.Struct({ connectedAccountId: NonEmptyString });
135
+ const connectedAccountProviderParams = Schema.Struct({ provider: connectedAccountProviderSchema });
91
136
  export const ConnectedAccountsGroup = HttpApiGroup.make("connectedAccounts")
92
- .add(
93
- // Connect/replace: upserts on (owner, provider, name), so reconnecting swaps the sealed
94
- // payload in place instead of erroring.
95
- HttpApiEndpoint.post("createConnectedAccount", "/", {
137
+ .add(HttpApiEndpoint.post("createConnectedAccount", "/", {
96
138
  payload: createConnectedAccountRequestSchema,
97
139
  success: connectedAccountSummarySchema.pipe(HttpApiSchema.status(201)),
98
140
  error: [
@@ -122,7 +164,17 @@ HttpApiEndpoint.delete("archiveConnectedAccount", "/:connectedAccountId", {
122
164
  HttpApiEndpoint.post("markConnectedAccountInvalid", "/:connectedAccountId/mark-invalid", {
123
165
  params: connectedAccountIdParams,
124
166
  payload: markConnectedAccountInvalidRequestSchema,
125
- success: connectedAccountSummarySchema,
167
+ success: markConnectedAccountInvalidResponseSchema,
126
168
  error: [ConnectedAccountNotFoundError, ConnectedAccountInternalServerError],
169
+ }))
170
+ .add(HttpApiEndpoint.put("setConnectedAccountDefault", "/defaults/:provider", {
171
+ params: connectedAccountProviderParams,
172
+ payload: setConnectedAccountDefaultRequestSchema,
173
+ success: connectedAccountSummarySchema,
174
+ error: [
175
+ ConnectedAccountNotFoundError,
176
+ ConnectedAccountConflictError,
177
+ ConnectedAccountInternalServerError,
178
+ ],
127
179
  }))
128
180
  .annotate(OpenApi.Description, "Connected provider accounts (Claude / Codex / GitHub credentials). Secret material is never returned by any endpoint.");