@gajae-code/ai 0.15.5 → 0.15.6
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/CHANGELOG.md +15 -0
- package/dist/types/auth-broker/client.d.ts +6 -2
- package/dist/types/auth-broker/remote-store.d.ts +14 -2
- package/dist/types/auth-broker/types.d.ts +6 -0
- package/dist/types/auth-broker/wire-schemas.d.ts +19 -0
- package/dist/types/auth-gateway/server.d.ts +39 -5
- package/dist/types/auth-gateway/types.d.ts +16 -2
- package/dist/types/auth-storage.d.ts +92 -24
- package/dist/types/provider-models/openai-compat.d.ts +1 -0
- package/dist/types/providers/register-builtins.d.ts +12 -12
- package/dist/types/stream.d.ts +2 -1
- package/dist/types/types.d.ts +22 -2
- package/dist/types/utils/oauth/api-key-login.d.ts +4 -1
- package/dist/types/utils/oauth/api-key-validation.d.ts +12 -6
- package/dist/types/utils/oauth/commandcode.d.ts +1 -0
- package/dist/types/utils/oauth/types.d.ts +1 -1
- package/dist/types/utils/retry.d.ts +2 -0
- package/package.json +3 -3
- package/src/auth-broker/client.ts +41 -13
- package/src/auth-broker/redact.ts +25 -1
- package/src/auth-broker/remote-store.ts +374 -115
- package/src/auth-broker/server.ts +131 -91
- package/src/auth-broker/types.ts +6 -0
- package/src/auth-broker/wire-schemas.ts +6 -0
- package/src/auth-gateway/server.ts +447 -79
- package/src/auth-gateway/types.ts +28 -2
- package/src/auth-storage.ts +658 -154
- package/src/cli.ts +1 -0
- package/src/models.json +1023 -0
- package/src/provider-models/descriptors.ts +3 -1
- package/src/provider-models/openai-compat.ts +41 -1
- package/src/providers/anthropic.ts +7 -1
- package/src/providers/azure-openai-responses.ts +4 -1
- package/src/providers/cursor.ts +256 -101
- package/src/providers/gitlab-duo.ts +18 -1
- package/src/providers/google-gemini-cli.ts +3 -0
- package/src/providers/google-shared.ts +3 -0
- package/src/providers/kiro-codewhisperer.ts +24 -8
- package/src/providers/ollama.ts +3 -0
- package/src/providers/openai-codex-responses.ts +20 -6
- package/src/providers/openai-completions.ts +11 -1
- package/src/providers/openai-responses.ts +10 -1
- package/src/providers/pi-native-client.ts +1 -0
- package/src/providers/pi-native-server.ts +24 -0
- package/src/providers/register-builtins.d.ts +12 -12
- package/src/providers/register-builtins.ts +16 -3
- package/src/stream.d.ts +2 -1
- package/src/stream.ts +175 -67
- package/src/types.d.ts +22 -2
- package/src/types.ts +27 -1
- package/src/utils/oauth/api-key-login.ts +13 -2
- package/src/utils/oauth/api-key-validation.ts +242 -41
- package/src/utils/oauth/commandcode.ts +17 -0
- package/src/utils/oauth/index.ts +20 -5
- package/src/utils/oauth/types.d.ts +1 -1
- package/src/utils/oauth/types.ts +1 -0
- package/src/utils/retry.d.ts +2 -0
- package/src/utils/retry.ts +15 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.15.6] - 2026-08-30
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `AuthGatewayServerOptions` now requires `providerScope`; `AuthGatewayBootOptions` requires the provider-filtered `listModels` callback and an exact-catalog-object `resolveModel`. Direct `@gajae-code/ai` callers must construct one gateway instance per provider and pass a provider-filtered source catalog. This matches the mandatory `--provider=<id>` CLI migration and prevents cross-provider model and credential ambiguity.
|
|
10
|
+
- `AuthGatewayBootOptions` now requires live authority callbacks (`hasProviderCredential`, `reloadProviderCredentials`, and `validateProviderCredential`). Gateway dispatch holds the authority lease through `streamSimple()` admission and rejects credentials revoked during asynchronous selection instead of sending a stale key.
|
|
11
|
+
- `auth-broker serve` now requires an `AuthCredentialStore` with atomic `allocateMonotonicSequence` support for durable broker incarnation epochs; unsupported custom stores fail closed before binding and must migrate to the durable cache-backed contract.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Cursor HTTP/2 streams now drain admitted exec responses before normal teardown and centralize terminal failures, preventing delayed handlers and retained shell callbacks from writing after the request has ended.
|
|
16
|
+
- Auth-gateway boot and dispatch are now provider-scoped: model catalogs reject cross-provider id ambiguity, Codex rows retain `openai-codex-responses`, and requests cannot borrow credentials from another provider.
|
|
17
|
+
- Broker-backed gateway dispatch leases now remain held until the provider's transport-admission boundary, preventing lazy stream construction from releasing authority before outbound dispatch.
|
|
18
|
+
- Kiro (Amazon Q Developer / CodeWhisperer) OAuth is now fully wired end-to-end: `AuthStorage.login("kiro", ...)` previously had no dispatch case despite `kiro` being advertised in `getOAuthProviders()`, so every advertised login path (`gjc auth-broker login kiro`, the interactive `/login` provider picker, direct `@gajae-code/ai` CLI `login kiro`) failed with `Unknown OAuth provider: kiro`. `mapOptionsForApi()` also had no case for `kiro-codewhisperer-stream`, so any chat call on a Kiro model threw `Unhandled API in mapOptionsForApi` regardless of auth method. The bundled model catalog had no `kiro` entries at all, leaving OAuth-only users with an empty model list; the provider descriptor's default model id also did not match any catalog entry. The OAuth CodeWhisperer request now also carries `modelId` in every wire message, matching the sibling API-key transport's request shape (issue #5064).
|
|
19
|
+
|
|
5
20
|
## [0.15.5] - 2026-08-29
|
|
6
21
|
|
|
7
22
|
### Added
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { AuthCredential } from "../auth-storage";
|
|
2
|
+
import type { Provider } from "../types";
|
|
2
3
|
import type { CredentialDisableResponse, CredentialIfAbsentUploadResponse, CredentialMetadataResponse, CredentialRefreshRequest, CredentialRefreshResponse, CredentialUploadResponse, HealthzResponse, SnapshotResponse, SnapshotStreamEvent, UsageResponse } from "./types";
|
|
4
|
+
export declare const AUTH_BROKER_EPOCH_HEADER = "X-GJC-Auth-Broker-Epoch";
|
|
3
5
|
export interface AuthBrokerClientOptions {
|
|
4
6
|
/** Base URL (e.g. `https://broker.tailnet:8765`). Trailing slashes are trimmed. */
|
|
5
7
|
url: string;
|
|
@@ -35,6 +37,7 @@ export declare class AuthBrokerCredentialMetadataUnsupportedError extends AuthBr
|
|
|
35
37
|
}
|
|
36
38
|
export interface FetchSnapshotOptions {
|
|
37
39
|
ifGenerationGt?: number;
|
|
40
|
+
ifEpoch?: string;
|
|
38
41
|
waitMs?: number;
|
|
39
42
|
signal?: AbortSignal;
|
|
40
43
|
}
|
|
@@ -45,6 +48,7 @@ export type FetchSnapshotResult = {
|
|
|
45
48
|
} | {
|
|
46
49
|
status: 304;
|
|
47
50
|
generation: number;
|
|
51
|
+
epoch?: string;
|
|
48
52
|
};
|
|
49
53
|
export declare class AuthBrokerClient {
|
|
50
54
|
#private;
|
|
@@ -67,10 +71,10 @@ export declare class AuthBrokerClient {
|
|
|
67
71
|
openSnapshotStream(opts?: {
|
|
68
72
|
signal?: AbortSignal;
|
|
69
73
|
}): AsyncGenerator<SnapshotStreamEvent>;
|
|
70
|
-
fetchUsage(signal?: AbortSignal): Promise<UsageResponse>;
|
|
74
|
+
fetchUsage(signal?: AbortSignal, provider?: Provider): Promise<UsageResponse>;
|
|
71
75
|
refreshCredential(id: number, signal?: AbortSignal): Promise<CredentialRefreshResponse>;
|
|
72
76
|
refreshMCPCredential(id: number, body: CredentialRefreshRequest, signal?: AbortSignal): Promise<CredentialRefreshResponse>;
|
|
73
|
-
disableCredential(id: number, cause: string, signal?: AbortSignal): Promise<CredentialDisableResponse>;
|
|
77
|
+
disableCredential(id: number, cause: string, signal?: AbortSignal, expectedRevision?: number): Promise<CredentialDisableResponse>;
|
|
74
78
|
uploadCredential(provider: string, credential: AuthCredential, signal?: AbortSignal): Promise<CredentialUploadResponse>;
|
|
75
79
|
uploadCredentialIfAbsent(provider: string, credential: AuthCredential, signal?: AbortSignal): Promise<CredentialIfAbsentUploadResponse>;
|
|
76
80
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* usage reports cache TTL is 5 minutes per credential, so durability across
|
|
8
8
|
* runs isn't required.
|
|
9
9
|
*/
|
|
10
|
-
import { type AuthCredential, type AuthCredentialIfAbsentResult, type AuthCredentialStore, type CachedCredentialHealth, type CachedUsagePresentation, type CredentialInventoryRecord, type MCPOAuthRefreshClient, type OAuthCredential, type SafeUsageReport, type StoredAuthCredential } from "../auth-storage";
|
|
10
|
+
import { type AuthCredential, type AuthCredentialIfAbsentResult, type AuthCredentialStore, type CachedCredentialHealth, type CachedUsagePresentation, type CredentialDispatchTicket, type CredentialInventoryRecord, type MCPOAuthRefreshClient, type OAuthCredential, type SafeUsageReport, type StoredAuthCredential } from "../auth-storage";
|
|
11
11
|
import type { Provider } from "../types";
|
|
12
12
|
import type { UsageReport } from "../usage";
|
|
13
13
|
import type { OAuthCredentials } from "../utils/oauth/types";
|
|
@@ -50,6 +50,14 @@ export declare class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
50
50
|
flushPresentationPersistence(): Promise<void>;
|
|
51
51
|
get snapshot(): SnapshotResponse;
|
|
52
52
|
getInventoryMetadataState(): Readonly<CredentialInventoryMetadataState>;
|
|
53
|
+
onSnapshotChanged(listener: () => void): () => void;
|
|
54
|
+
/**
|
|
55
|
+
* Queue a provider-admission ticket behind all currently pending snapshot
|
|
56
|
+
* authority work. Snapshot applications that arrive after this ticket wait
|
|
57
|
+
* for its release, so a revocation is ordered either before admission or
|
|
58
|
+
* after it — never in the middle of the dispatch boundary.
|
|
59
|
+
*/
|
|
60
|
+
acquireCredentialDispatchTicket(_provider: Provider, signal?: AbortSignal): Promise<CredentialDispatchTicket>;
|
|
53
61
|
syncInventoryMetadata(): Promise<Readonly<CredentialInventoryMetadataState>>;
|
|
54
62
|
/**
|
|
55
63
|
* Payload-free inventory view. This method never performs network I/O; metadata
|
|
@@ -58,7 +66,7 @@ export declare class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
58
66
|
*/
|
|
59
67
|
listCredentialInventory(provider?: string): CredentialInventoryRecord[];
|
|
60
68
|
/** Re-hydrate the in-memory snapshot from the broker. */
|
|
61
|
-
refreshSnapshot(): Promise<SnapshotResponse>;
|
|
69
|
+
refreshSnapshot(signal?: AbortSignal): Promise<SnapshotResponse>;
|
|
62
70
|
listAuthCredentials(provider?: string): StoredAuthCredential[];
|
|
63
71
|
/**
|
|
64
72
|
* In-memory update from a successful refresh through the broker. AuthStorage
|
|
@@ -67,7 +75,10 @@ export declare class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
67
75
|
*/
|
|
68
76
|
updateAuthCredential(id: number, credential: AuthCredential): void;
|
|
69
77
|
deleteAuthCredential(_id: number, _disabledCause: string): void;
|
|
78
|
+
allocateMonotonicSequence(_key: string, _expiresAtSec: number): number;
|
|
70
79
|
tryDisableAuthCredentialIfMatches(_id: number, _expectedData: string, _disabledCause: string): boolean;
|
|
80
|
+
/** Disable one credential through the authenticated broker mutation endpoint. */
|
|
81
|
+
disableAuthCredentialRemote(credentialId: number, disabledCause: string, signal?: AbortSignal, expectedRevision?: number): Promise<boolean>;
|
|
71
82
|
waitForFreshSnapshot(maxWaitMs: number, opts?: {
|
|
72
83
|
signal?: AbortSignal;
|
|
73
84
|
}): Promise<boolean>;
|
|
@@ -117,6 +128,7 @@ export declare class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
117
128
|
* residential laptop is, so all credentials surface every cycle.
|
|
118
129
|
*/
|
|
119
130
|
fetchUsageReports(signal?: AbortSignal): Promise<UsageReport[] | null>;
|
|
131
|
+
fetchUsageReportsForProvider(provider: Provider, signal?: AbortSignal): Promise<UsageReport[] | null>;
|
|
120
132
|
/** Synchronous, zero-network usage presentation read. */
|
|
121
133
|
peekCachedUsagePresentation(provider: Provider, credentialId: number): CachedUsagePresentation | undefined;
|
|
122
134
|
/** Synchronous, zero-network health presentation read backed by the redacted sidecar. */
|
|
@@ -17,6 +17,7 @@ export interface CredentialMetadataRecord {
|
|
|
17
17
|
}
|
|
18
18
|
/** GET /v1/credentials/metadata response body. */
|
|
19
19
|
export interface CredentialMetadataResponse {
|
|
20
|
+
epoch?: string;
|
|
20
21
|
generation: number;
|
|
21
22
|
generatedAt: number;
|
|
22
23
|
credentials: CredentialMetadataRecord[];
|
|
@@ -37,6 +38,8 @@ export type SnapshotEntry = AuthCredentialSnapshotEntry & {
|
|
|
37
38
|
};
|
|
38
39
|
/** GET /v1/snapshot response body. */
|
|
39
40
|
export interface SnapshotResponse extends Omit<AuthCredentialSnapshot, "credentials"> {
|
|
41
|
+
/** Stable for one broker process; changes when the broker restarts. */
|
|
42
|
+
epoch?: string;
|
|
40
43
|
serverNowMs: number;
|
|
41
44
|
refresher: RefresherSchedule;
|
|
42
45
|
credentials: SnapshotEntry[];
|
|
@@ -55,6 +58,7 @@ export type CredentialRefreshRequest = MCPOAuthRefreshClient;
|
|
|
55
58
|
/** POST /v1/credential/:id/disable request body. */
|
|
56
59
|
export interface CredentialDisableRequest {
|
|
57
60
|
cause: string;
|
|
61
|
+
expectedRevision?: number;
|
|
58
62
|
}
|
|
59
63
|
/** POST /v1/credential/:id/disable response body. */
|
|
60
64
|
export interface CredentialDisableResponse {
|
|
@@ -91,6 +95,7 @@ export interface SnapshotStreamSnapshotEvent extends SnapshotResponse {
|
|
|
91
95
|
/** Single credential added/changed (upsert or refresh). */
|
|
92
96
|
export interface SnapshotStreamEntryEvent {
|
|
93
97
|
kind: "entry";
|
|
98
|
+
epoch?: string;
|
|
94
99
|
generation: number;
|
|
95
100
|
serverNowMs: number;
|
|
96
101
|
refresher: RefresherSchedule;
|
|
@@ -99,6 +104,7 @@ export interface SnapshotStreamEntryEvent {
|
|
|
99
104
|
/** Single credential disabled/deleted. */
|
|
100
105
|
export interface SnapshotStreamRemovedEvent {
|
|
101
106
|
kind: "removed";
|
|
107
|
+
epoch?: string;
|
|
102
108
|
generation: number;
|
|
103
109
|
serverNowMs: number;
|
|
104
110
|
refresher: RefresherSchedule;
|
|
@@ -106,6 +106,7 @@ export declare const credentialSnapshotEntrySchema: z.ZodObject<{
|
|
|
106
106
|
key: z.ZodString;
|
|
107
107
|
}, z.core.$strict>], "type">;
|
|
108
108
|
identityKey: z.ZodNullable<z.ZodString>;
|
|
109
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
109
110
|
}, z.core.$strict>;
|
|
110
111
|
export declare const snapshotEntrySchema: z.ZodObject<{
|
|
111
112
|
id: z.ZodNumber;
|
|
@@ -128,6 +129,7 @@ export declare const snapshotEntrySchema: z.ZodObject<{
|
|
|
128
129
|
key: z.ZodString;
|
|
129
130
|
}, z.core.$strict>], "type">;
|
|
130
131
|
identityKey: z.ZodNullable<z.ZodString>;
|
|
132
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
131
133
|
rotatesInMs: z.ZodNullable<z.ZodNumber>;
|
|
132
134
|
}, z.core.$strict>;
|
|
133
135
|
export declare const refresherScheduleSchema: z.ZodObject<{
|
|
@@ -137,6 +139,7 @@ export declare const refresherScheduleSchema: z.ZodObject<{
|
|
|
137
139
|
nextSweepInMs: z.ZodNumber;
|
|
138
140
|
}, z.core.$strict>;
|
|
139
141
|
export declare const snapshotResponseSchema: z.ZodObject<{
|
|
142
|
+
epoch: z.ZodOptional<z.ZodString>;
|
|
140
143
|
generation: z.ZodNumber;
|
|
141
144
|
generatedAt: z.ZodNumber;
|
|
142
145
|
serverNowMs: z.ZodNumber;
|
|
@@ -167,6 +170,7 @@ export declare const snapshotResponseSchema: z.ZodObject<{
|
|
|
167
170
|
key: z.ZodString;
|
|
168
171
|
}, z.core.$strict>], "type">;
|
|
169
172
|
identityKey: z.ZodNullable<z.ZodString>;
|
|
173
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
170
174
|
rotatesInMs: z.ZodNullable<z.ZodNumber>;
|
|
171
175
|
}, z.core.$strict>>;
|
|
172
176
|
}, z.core.$strict>;
|
|
@@ -182,6 +186,7 @@ export declare const credentialMetadataRecordSchema: z.ZodObject<{
|
|
|
182
186
|
disabledCause: z.ZodNullable<z.ZodString>;
|
|
183
187
|
}, z.core.$strict>;
|
|
184
188
|
export declare const credentialMetadataResponseSchema: z.ZodObject<{
|
|
189
|
+
epoch: z.ZodOptional<z.ZodString>;
|
|
185
190
|
generation: z.ZodNumber;
|
|
186
191
|
generatedAt: z.ZodNumber;
|
|
187
192
|
credentials: z.ZodArray<z.ZodObject<{
|
|
@@ -197,6 +202,7 @@ export declare const credentialMetadataResponseSchema: z.ZodObject<{
|
|
|
197
202
|
}, z.core.$strict>;
|
|
198
203
|
/** First frame on connect — full snapshot embedded inline with a `kind` tag. */
|
|
199
204
|
export declare const snapshotStreamSnapshotEventSchema: z.ZodObject<{
|
|
205
|
+
epoch: z.ZodOptional<z.ZodString>;
|
|
200
206
|
generation: z.ZodNumber;
|
|
201
207
|
generatedAt: z.ZodNumber;
|
|
202
208
|
serverNowMs: z.ZodNumber;
|
|
@@ -227,6 +233,7 @@ export declare const snapshotStreamSnapshotEventSchema: z.ZodObject<{
|
|
|
227
233
|
key: z.ZodString;
|
|
228
234
|
}, z.core.$strict>], "type">;
|
|
229
235
|
identityKey: z.ZodNullable<z.ZodString>;
|
|
236
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
230
237
|
rotatesInMs: z.ZodNullable<z.ZodNumber>;
|
|
231
238
|
}, z.core.$strict>>;
|
|
232
239
|
kind: z.ZodLiteral<"snapshot">;
|
|
@@ -234,6 +241,7 @@ export declare const snapshotStreamSnapshotEventSchema: z.ZodObject<{
|
|
|
234
241
|
/** Per-credential upsert/refresh delta. */
|
|
235
242
|
export declare const snapshotStreamEntryEventSchema: z.ZodObject<{
|
|
236
243
|
kind: z.ZodLiteral<"entry">;
|
|
244
|
+
epoch: z.ZodOptional<z.ZodString>;
|
|
237
245
|
generation: z.ZodNumber;
|
|
238
246
|
serverNowMs: z.ZodNumber;
|
|
239
247
|
refresher: z.ZodObject<{
|
|
@@ -263,12 +271,14 @@ export declare const snapshotStreamEntryEventSchema: z.ZodObject<{
|
|
|
263
271
|
key: z.ZodString;
|
|
264
272
|
}, z.core.$strict>], "type">;
|
|
265
273
|
identityKey: z.ZodNullable<z.ZodString>;
|
|
274
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
266
275
|
rotatesInMs: z.ZodNullable<z.ZodNumber>;
|
|
267
276
|
}, z.core.$strict>;
|
|
268
277
|
}, z.core.$strict>;
|
|
269
278
|
/** Per-credential delete delta. */
|
|
270
279
|
export declare const snapshotStreamRemovedEventSchema: z.ZodObject<{
|
|
271
280
|
kind: z.ZodLiteral<"removed">;
|
|
281
|
+
epoch: z.ZodOptional<z.ZodString>;
|
|
272
282
|
generation: z.ZodNumber;
|
|
273
283
|
serverNowMs: z.ZodNumber;
|
|
274
284
|
refresher: z.ZodObject<{
|
|
@@ -281,6 +291,7 @@ export declare const snapshotStreamRemovedEventSchema: z.ZodObject<{
|
|
|
281
291
|
}, z.core.$strict>;
|
|
282
292
|
/** Discriminated union over every event frame the snapshot stream emits. */
|
|
283
293
|
export declare const snapshotStreamEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
294
|
+
epoch: z.ZodOptional<z.ZodString>;
|
|
284
295
|
generation: z.ZodNumber;
|
|
285
296
|
generatedAt: z.ZodNumber;
|
|
286
297
|
serverNowMs: z.ZodNumber;
|
|
@@ -311,11 +322,13 @@ export declare const snapshotStreamEventSchema: z.ZodDiscriminatedUnion<[z.ZodOb
|
|
|
311
322
|
key: z.ZodString;
|
|
312
323
|
}, z.core.$strict>], "type">;
|
|
313
324
|
identityKey: z.ZodNullable<z.ZodString>;
|
|
325
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
314
326
|
rotatesInMs: z.ZodNullable<z.ZodNumber>;
|
|
315
327
|
}, z.core.$strict>>;
|
|
316
328
|
kind: z.ZodLiteral<"snapshot">;
|
|
317
329
|
}, z.core.$strict>, z.ZodObject<{
|
|
318
330
|
kind: z.ZodLiteral<"entry">;
|
|
331
|
+
epoch: z.ZodOptional<z.ZodString>;
|
|
319
332
|
generation: z.ZodNumber;
|
|
320
333
|
serverNowMs: z.ZodNumber;
|
|
321
334
|
refresher: z.ZodObject<{
|
|
@@ -345,10 +358,12 @@ export declare const snapshotStreamEventSchema: z.ZodDiscriminatedUnion<[z.ZodOb
|
|
|
345
358
|
key: z.ZodString;
|
|
346
359
|
}, z.core.$strict>], "type">;
|
|
347
360
|
identityKey: z.ZodNullable<z.ZodString>;
|
|
361
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
348
362
|
rotatesInMs: z.ZodNullable<z.ZodNumber>;
|
|
349
363
|
}, z.core.$strict>;
|
|
350
364
|
}, z.core.$strict>, z.ZodObject<{
|
|
351
365
|
kind: z.ZodLiteral<"removed">;
|
|
366
|
+
epoch: z.ZodOptional<z.ZodString>;
|
|
352
367
|
generation: z.ZodNumber;
|
|
353
368
|
serverNowMs: z.ZodNumber;
|
|
354
369
|
refresher: z.ZodObject<{
|
|
@@ -447,10 +462,12 @@ export declare const credentialRefreshResponseSchema: z.ZodObject<{
|
|
|
447
462
|
key: z.ZodString;
|
|
448
463
|
}, z.core.$strict>], "type">;
|
|
449
464
|
identityKey: z.ZodNullable<z.ZodString>;
|
|
465
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
450
466
|
}, z.core.$strict>;
|
|
451
467
|
}, z.core.$strict>;
|
|
452
468
|
export declare const credentialDisableRequestSchema: z.ZodObject<{
|
|
453
469
|
cause: z.ZodOptional<z.ZodString>;
|
|
470
|
+
expectedRevision: z.ZodOptional<z.ZodNumber>;
|
|
454
471
|
}, z.core.$strict>;
|
|
455
472
|
export declare const credentialDisableResponseSchema: z.ZodObject<{
|
|
456
473
|
ok: z.ZodBoolean;
|
|
@@ -497,6 +514,7 @@ export declare const credentialUploadResponseSchema: z.ZodObject<{
|
|
|
497
514
|
key: z.ZodString;
|
|
498
515
|
}, z.core.$strict>], "type">;
|
|
499
516
|
identityKey: z.ZodNullable<z.ZodString>;
|
|
517
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
500
518
|
}, z.core.$strict>>;
|
|
501
519
|
}, z.core.$strict>;
|
|
502
520
|
export declare const credentialIfAbsentUploadResponseSchema: z.ZodObject<{
|
|
@@ -532,5 +550,6 @@ export declare const credentialIfAbsentUploadResponseSchema: z.ZodObject<{
|
|
|
532
550
|
key: z.ZodString;
|
|
533
551
|
}, z.core.$strict>], "type">;
|
|
534
552
|
identityKey: z.ZodNullable<z.ZodString>;
|
|
553
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
535
554
|
}, z.core.$strict>>;
|
|
536
555
|
}, z.core.$strict>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* gjc auth-gateway HTTP server.
|
|
3
3
|
*
|
|
4
|
-
* Accepts
|
|
4
|
+
* Accepts a provider-scoped provider-format request (OpenAI chat-completions, Anthropic
|
|
5
5
|
* messages, OpenAI Responses) and dispatches through pi-ai's `streamSimple()`
|
|
6
6
|
* — which handles credential injection, anthropic-beta headers, OpenAI code backend
|
|
7
7
|
* websocket transport, and all the per-provider intricacies. The gateway is
|
|
@@ -12,25 +12,59 @@
|
|
|
12
12
|
* GET /healthz → unauth; ok + version
|
|
13
13
|
* GET /v1/usage → aggregated provider usage (5-min per-credential cache via AuthStorage)
|
|
14
14
|
* GET /v1/credentials/check → per-credential auth probe (diagnose 401s in a multi-account pool)
|
|
15
|
-
* GET /v1/models → list
|
|
15
|
+
* GET /v1/models → list models from the selected provider scope
|
|
16
16
|
* POST /v1/chat/completions → OpenAI chat-completions in/out
|
|
17
17
|
* POST /v1/messages → Anthropic messages in/out
|
|
18
18
|
* POST /v1/responses → OpenAI Responses in/out
|
|
19
19
|
*/
|
|
20
20
|
import type { AuthStorage } from "../auth-storage";
|
|
21
|
-
import type { Api, Model } from "../types";
|
|
21
|
+
import type { Api, AssistantMessageEventStream, Model, Provider } from "../types";
|
|
22
22
|
import type { AuthGatewayServerHandle, AuthGatewayServerOptions } from "./types";
|
|
23
23
|
export type ModelResolver = (modelId: string) => Model<Api> | undefined;
|
|
24
24
|
export interface AuthGatewayBootOptions extends AuthGatewayServerOptions {
|
|
25
25
|
/** Source of credentials. Caller wires this to a broker-backed AuthStorage. */
|
|
26
26
|
storage: AuthStorage;
|
|
27
|
+
/**
|
|
28
|
+
* Current broker-backed scope authority. When supplied, this is checked on
|
|
29
|
+
* every request so a live broker snapshot removal immediately fails closed.
|
|
30
|
+
*/
|
|
31
|
+
hasProviderCredential: () => boolean;
|
|
32
|
+
/** Refresh the dispatch cache from the current broker snapshot before use. */
|
|
33
|
+
reloadProviderCredentials: (signal?: AbortSignal) => Promise<void>;
|
|
34
|
+
/** Confirm that the selected key is still present in the current authority snapshot. */
|
|
35
|
+
validateProviderCredential: (provider: string, apiKey: string) => boolean;
|
|
27
36
|
/**
|
|
28
37
|
* Resolve a client-requested model id to a pi-ai Model. Caller supplies
|
|
29
38
|
* this from a ModelRegistry (lives in `coding-agent` to avoid an inverse
|
|
30
39
|
* dependency in `pi-ai`).
|
|
31
40
|
*/
|
|
32
41
|
resolveModel: ModelResolver;
|
|
33
|
-
/**
|
|
34
|
-
listModels
|
|
42
|
+
/** Supplier for the source-backed model catalog used by `/v1/models`. */
|
|
43
|
+
listModels: () => Iterable<Model<Api>>;
|
|
44
|
+
}
|
|
45
|
+
export interface AuthGatewayModelCatalog {
|
|
46
|
+
readonly models: readonly Model<Api>[];
|
|
47
|
+
resolve(modelId: string): Model<Api> | undefined;
|
|
35
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Whether a model can be served through the broker-backed auth gateway.
|
|
51
|
+
*
|
|
52
|
+
* Bedrock's credential chain is process-local AWS authority, not a broker
|
|
53
|
+
* credential. Advertising a native Bedrock model from this gateway would let
|
|
54
|
+
* direct callers bypass the broker boundary (and make readiness lie about a
|
|
55
|
+
* model the gateway cannot authenticate). Keep this predicate shared with the
|
|
56
|
+
* CLI readiness checks so every entry point applies the same fence.
|
|
57
|
+
*/
|
|
58
|
+
export declare function isAuthGatewayModelBrokerConsumable(model: Pick<Model<Api>, "api" | "transport">): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Build an unambiguous, provider-scoped catalog.
|
|
61
|
+
*
|
|
62
|
+
* Models from other providers are intentionally ignored rather than allowed
|
|
63
|
+
* to compete for the same id. Duplicate ids within the selected provider are
|
|
64
|
+
* rejected because choosing either one would make request dispatch
|
|
65
|
+
* order-dependent.
|
|
66
|
+
*/
|
|
67
|
+
export declare function createAuthGatewayModelCatalog(provider: Provider, models: Iterable<Model<Api>>): AuthGatewayModelCatalog;
|
|
68
|
+
export declare function releaseGatewayCredentialLeaseOnAdmission(events: Pick<AssistantMessageEventStream, "result">, release: () => void, signal?: AbortSignal): void;
|
|
36
69
|
export declare function startAuthGateway(opts: AuthGatewayBootOptions): AuthGatewayServerHandle;
|
|
70
|
+
export declare function isSafeProviderScope(provider: unknown): provider is string;
|
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
import type { Effort } from "../model-thinking";
|
|
2
|
-
import type { AssistantMessage, AssistantMessageEventStream, CacheRetention, Context, ServiceTier } from "../types";
|
|
2
|
+
import type { Api, AssistantMessage, AssistantMessageEventStream, CacheRetention, Context, Provider, ServiceTier } from "../types";
|
|
3
3
|
/**
|
|
4
4
|
* Wire types for the gjc auth-gateway.
|
|
5
5
|
*
|
|
6
6
|
* The gateway sits between unauthenticated clients (containerized gjc,
|
|
7
7
|
* llm-git, …) and the broker. It accepts provider-format HTTP requests
|
|
8
|
-
* (OpenAI chat-completions / Anthropic messages / OpenAI Responses)
|
|
8
|
+
* (OpenAI chat-completions / Anthropic messages / OpenAI Responses) within
|
|
9
|
+
* one explicit provider scope,
|
|
9
10
|
* dispatches them through pi-ai's `streamSimple()`, and translates the
|
|
10
11
|
* canonical event stream back to the matching wire format. The gateway
|
|
11
12
|
* injects `Authorization` server-side so clients never see access tokens.
|
|
12
13
|
*/
|
|
13
14
|
/** Default bind. Loopback-only — front with reverse proxy for remote access. */
|
|
14
15
|
export declare const DEFAULT_AUTH_GATEWAY_BIND = "127.0.0.1:4000";
|
|
16
|
+
/**
|
|
17
|
+
* Provider APIs whose gateway identity is part of the provider contract.
|
|
18
|
+
*
|
|
19
|
+
* OpenAI Codex is backed by the Codex OAuth authority and must never be
|
|
20
|
+
* projected as a generic OpenAI Responses model. Other providers may expose
|
|
21
|
+
* more than one API and therefore remain catalog-defined.
|
|
22
|
+
*/
|
|
23
|
+
export declare const AUTH_GATEWAY_PROVIDER_APIS: Readonly<Record<string, Api>>;
|
|
24
|
+
export interface AuthGatewayProviderScope {
|
|
25
|
+
provider: Provider;
|
|
26
|
+
}
|
|
15
27
|
export type AuthGatewayToolChoice = "auto" | "none" | "required" | {
|
|
16
28
|
name: string;
|
|
17
29
|
};
|
|
@@ -102,6 +114,8 @@ export interface AuthGatewayFormatModule {
|
|
|
102
114
|
export interface AuthGatewayServerOptions {
|
|
103
115
|
/** Listen address. Default `127.0.0.1:4000`. */
|
|
104
116
|
bind?: string;
|
|
117
|
+
/** Required provider scope. An unscoped gateway is not supported. */
|
|
118
|
+
providerScope: AuthGatewayProviderScope;
|
|
105
119
|
/** Accept any of these bearer tokens. Empty allows unauthenticated calls. */
|
|
106
120
|
bearerTokens: string[];
|
|
107
121
|
/** Version surfaced on `/healthz`. */
|