@modelprofile.com/authswitch 8.1.0 → 9.0.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_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/authority-contract.d.ts +73 -0
- package/dist_ts/authority-contract.js +55 -2
- package/dist_ts/authority-import-contract.d.ts +8 -4
- package/dist_ts/authority-import-contract.js +12 -13
- package/dist_ts/authority-paths.d.ts +37 -0
- package/dist_ts/authority-paths.js +46 -0
- package/dist_ts/authority-runtime-contract.d.ts +11 -1
- package/dist_ts/classes.authoritybroker.d.ts +9 -0
- package/dist_ts/classes.authoritybroker.js +72 -11
- package/dist_ts/classes.authorityclient.d.ts +17 -11
- package/dist_ts/classes.authorityclient.js +47 -22
- package/dist_ts/classes.authoritydaemon.d.ts +22 -3
- package/dist_ts/classes.authoritydaemon.js +106 -59
- package/dist_ts/classes.authoritydatabase.d.ts +9 -1
- package/dist_ts/classes.authoritydatabase.js +39 -13
- package/dist_ts/classes.authorityimport.d.ts +33 -6
- package/dist_ts/classes.authorityimport.js +102 -25
- package/dist_ts/classes.authoritymodels.d.ts +4 -1
- package/dist_ts/classes.authoritymodels.js +15 -3
- package/dist_ts/classes.authoritypreuse.js +8 -3
- package/dist_ts/classes.authorityservice.d.ts +20 -11
- package/dist_ts/classes.authorityservice.js +37 -23
- package/dist_ts/classes.claudeauthority.js +19 -11
- package/dist_ts/classes.claudenative.d.ts +63 -3
- package/dist_ts/classes.claudenative.js +68 -8
- package/dist_ts/classes.cli.d.ts +10 -2
- package/dist_ts/classes.cli.js +12 -4
- package/dist_ts/classes.codexmanaged.d.ts +8 -0
- package/dist_ts/classes.codexmanaged.js +19 -12
- package/dist_ts/classes.legacyfence.d.ts +53 -0
- package/dist_ts/classes.legacyfence.js +189 -0
- package/dist_ts/classes.operations.d.ts +15 -3
- package/dist_ts/classes.operations.js +22 -4
- package/dist_ts/classes.service.d.ts +21 -2
- package/dist_ts/classes.service.js +35 -8
- package/dist_ts/classes.tui.d.ts +2 -1
- package/dist_ts/classes.tui.js +3 -2
- package/dist_ts/ts_migration/0003_claude_handoff_proof.d.ts +13 -0
- package/dist_ts/ts_migration/0003_claude_handoff_proof.js +20 -0
- package/dist_ts/ts_migration/index.js +3 -1
- package/dist_ts/ts_migration/legacysources/authswitchstores.js +5 -2
- package/dist_ts/ts_migration/legacysources/nativestores.js +15 -8
- package/dist_ts/ts_migration/legacysources/shared.d.ts +3 -2
- package/dist_ts/ts_migration/legacysources/shared.js +3 -5
- package/package.json +11 -7
- package/readme.md +188 -13
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/authority-contract.ts +125 -0
- package/ts/authority-import-contract.ts +12 -11
- package/ts/authority-paths.ts +69 -0
- package/ts/authority-runtime-contract.ts +11 -1
- package/ts/classes.authoritybroker.ts +70 -11
- package/ts/classes.authorityclient.ts +59 -21
- package/ts/classes.authoritydaemon.ts +116 -60
- package/ts/classes.authoritydatabase.ts +39 -12
- package/ts/classes.authorityimport.ts +131 -26
- package/ts/classes.authoritymodels.ts +11 -2
- package/ts/classes.authoritypreuse.ts +7 -1
- package/ts/classes.authorityservice.ts +42 -30
- package/ts/classes.claudeauthority.ts +22 -10
- package/ts/classes.claudenative.ts +104 -10
- package/ts/classes.cli.ts +14 -3
- package/ts/classes.codexmanaged.ts +18 -7
- package/ts/classes.legacyfence.ts +219 -0
- package/ts/classes.operations.ts +22 -3
- package/ts/classes.service.ts +45 -8
- package/ts/classes.tui.ts +3 -1
- package/ts/ts_migration/0003_claude_handoff_proof.ts +19 -0
- package/ts/ts_migration/index.ts +2 -0
- package/ts/ts_migration/legacysources/authswitchstores.ts +4 -1
- package/ts/ts_migration/legacysources/nativestores.ts +15 -7
- package/ts/ts_migration/legacysources/shared.ts +4 -6
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as plugins from './plugins.js';
|
|
2
2
|
import type { IAuthSwitchAccount, IAuthSwitchAccountEvent, IAuthSwitchBinding, IAuthSwitchLogin,
|
|
3
|
-
IAuthSwitchOperation, IAuthSwitchSnapshot } from './authority-contract.js';
|
|
3
|
+
IAuthSwitchOperation, IAuthSwitchSnapshot, TAuthSwitchLoginOwnerTool } from './authority-contract.js';
|
|
4
|
+
import { AuthSwitchRefusal } from './authority-contract.js';
|
|
4
5
|
import { AuthSwitchAuthorityDatabase } from './classes.authoritydatabase.js';
|
|
5
6
|
import type { IStoredAuthorityAccount, IStoredAuthorityBinding, IStoredAuthorityGrant,
|
|
6
7
|
IStoredAuthorityDeviceOperation } from './classes.authoritymodels.js';
|
|
@@ -50,14 +51,57 @@ const tokenExpiry = (credential: TOpenAiCredential): string | null => {
|
|
|
50
51
|
catch { return null; }
|
|
51
52
|
};
|
|
52
53
|
const openAiGrantId = (accountId: string): string => idHash('authswitch-grant-v1', accountId, 'openai_managed', 'chatgpt');
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* What a caller is told when the answer is decided. Each states the repair and names no id, path or host.
|
|
57
|
+
*
|
|
58
|
+
* They are written once because several sites answer the same question: an operation id this authority does
|
|
59
|
+
* not hold is the same answer whether a read, a cancel or a start met it, and a client that branches on the
|
|
60
|
+
* code must not have to tell those apart.
|
|
61
|
+
*/
|
|
62
|
+
const unknownOperation = 'This authority knows no device sign-in by that operation ID. '
|
|
63
|
+
+ 'Start a new sign-in and follow that one.';
|
|
64
|
+
const loginNotBindable = 'This login cannot back a runtime binding. The authority must hold the login '
|
|
65
|
+
+ 'itself, it must be the account\'s selected OpenAI login, and it must be ready. Reauthenticate the '
|
|
66
|
+
+ 'account or choose another one.';
|
|
67
|
+
const bindingUnauthorized = 'This runtime binding is not authorized. Bind the account again to obtain a '
|
|
68
|
+
+ 'capability for it.';
|
|
69
|
+
const bindingMoved = 'This runtime binding changed while its credential was being resolved. Bind the '
|
|
70
|
+
+ 'account again.';
|
|
71
|
+
const bindingNeedsReauth = 'The account no longer holds the login this binding was authorized for. '
|
|
72
|
+
+ 'Reauthenticate the account, then bind it again.';
|
|
53
73
|
const publicAccount = (account: IStoredAuthorityAccount): IAuthSwitchAccount => ({
|
|
54
74
|
id: account.id, providerId: account.providerId, label: account.label, email: account.email,
|
|
55
75
|
plan: account.plan, removed: account.removed, revision: account.revision,
|
|
56
76
|
statusObservedAt: account.statusObservedAt,
|
|
57
77
|
});
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Which native tool refreshes a grant, decided here because this is the one place that publishes a login.
|
|
81
|
+
*
|
|
82
|
+
* `owner` and `purpose` are what the authority stores; the tool is their meaning, and naming it here keeps
|
|
83
|
+
* every consumer from re-deriving it -- the derivation that is wrong as soon as two purposes share a tool,
|
|
84
|
+
* or one tool gains a second purpose. `daemon` and `none` have no native refresher at all, which is a value
|
|
85
|
+
* of its own rather than a missing one.
|
|
86
|
+
*/
|
|
87
|
+
const loginOwnerTool = (grant: IStoredAuthorityGrant): TAuthSwitchLoginOwnerTool | null => {
|
|
88
|
+
if (grant.owner === 'claude_native') return 'claude_code';
|
|
89
|
+
if (grant.owner !== 'legacy_native') return null;
|
|
90
|
+
switch (grant.purpose) {
|
|
91
|
+
case 'opencode_native': return 'opencode';
|
|
92
|
+
case 'openai_managed': return 'codex';
|
|
93
|
+
case 'claude_host_native': return 'claude_code';
|
|
94
|
+
// A container setup token is held for a container, not refreshed by a tool on this host.
|
|
95
|
+
case 'claude_container_setup': return null;
|
|
96
|
+
// A purpose added without deciding its tool fails the type check here rather than publishing `null`,
|
|
97
|
+
// which would claim the authority refreshes a login some tool actually holds.
|
|
98
|
+
default: { const unhandledPurpose: never = grant.purpose; return unhandledPurpose; }
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
58
102
|
const publicLogin = (grant: IStoredAuthorityGrant): IAuthSwitchLogin => ({
|
|
59
103
|
id: grant.id, accountId: grant.accountId, providerId: grant.providerId, purpose: grant.purpose,
|
|
60
|
-
owner: grant.owner,
|
|
104
|
+
owner: grant.owner, ownerTool: loginOwnerTool(grant),
|
|
61
105
|
health: grant.state === 'exchange_may_have_been_sent' ? 'refreshing'
|
|
62
106
|
: grant.state === 'native' ? 'unverified'
|
|
63
107
|
: grant.state === 'legacy_native_pending' || grant.state === 'handoff_pending' ? 'pending_handoff' : grant.state,
|
|
@@ -340,7 +384,7 @@ export class AuthSwitchAuthorityBroker {
|
|
|
340
384
|
private async finishStartingOperation(operationId: string, state: 'failed' | 'interrupted',
|
|
341
385
|
error: string): Promise<IStoredAuthorityDeviceOperation> {
|
|
342
386
|
const current = await this.database.readOperation(operationId);
|
|
343
|
-
if (!current || current.kind === 'preuse_openai') throw new
|
|
387
|
+
if (!current || current.kind === 'preuse_openai') throw new AuthSwitchRefusal('not_found', unknownOperation);
|
|
344
388
|
if (deviceOperationTerminal(current)) return current;
|
|
345
389
|
if (current.state !== 'starting') throw new Error('Account operation already started its provider login.');
|
|
346
390
|
const updateId = plugins.crypto.randomUUID();
|
|
@@ -406,7 +450,7 @@ export class AuthSwitchAuthorityBroker {
|
|
|
406
450
|
let current: IStoredAuthorityDeviceOperation;
|
|
407
451
|
try {
|
|
408
452
|
const stored = await this.database.readOperation(id);
|
|
409
|
-
if (!stored || stored.kind === 'preuse_openai') throw new
|
|
453
|
+
if (!stored || stored.kind === 'preuse_openai') throw new AuthSwitchRefusal('not_found', unknownOperation);
|
|
410
454
|
current = stored;
|
|
411
455
|
} catch (error) {
|
|
412
456
|
await Promise.allSettled([handle.cancel(), handle.close()]);
|
|
@@ -513,7 +557,7 @@ export class AuthSwitchAuthorityBroker {
|
|
|
513
557
|
public async getOperation(operationId: string): Promise<IAuthSwitchOperation> {
|
|
514
558
|
if (!isUuid(operationId)) throw new Error('Invalid operation ID.');
|
|
515
559
|
const operation = await this.database.readOperation(operationId);
|
|
516
|
-
if (!operation || operation.kind === 'preuse_openai') throw new
|
|
560
|
+
if (!operation || operation.kind === 'preuse_openai') throw new AuthSwitchRefusal('not_found', unknownOperation);
|
|
517
561
|
return publicOperation(operation);
|
|
518
562
|
}
|
|
519
563
|
|
|
@@ -537,7 +581,7 @@ export class AuthSwitchAuthorityBroker {
|
|
|
537
581
|
public async cancelOperation(operationId: string): Promise<IAuthSwitchOperation> {
|
|
538
582
|
if (!isUuid(operationId)) throw new Error('Invalid operation ID.');
|
|
539
583
|
const current = await this.database.readOperation(operationId);
|
|
540
|
-
if (!current || current.kind === 'preuse_openai') throw new
|
|
584
|
+
if (!current || current.kind === 'preuse_openai') throw new AuthSwitchRefusal('not_found', unknownOperation);
|
|
541
585
|
if (current.state === 'committing') throw new Error('Login is completing; check its operation status.');
|
|
542
586
|
if (current.state !== 'starting' && current.state !== 'pending') return publicOperation(current);
|
|
543
587
|
const updateId = plugins.crypto.randomUUID();
|
|
@@ -554,7 +598,7 @@ export class AuthSwitchAuthorityBroker {
|
|
|
554
598
|
if (!isId(accountId) || !validRevision(expectedRevision) || !safeLabel(label)) throw new Error('Invalid account change.');
|
|
555
599
|
const updateId = plugins.crypto.randomUUID();
|
|
556
600
|
const updated = await this.database.changeAccount(updateId, accountId, account => {
|
|
557
|
-
if (!account || account.removed || account.revision !== expectedRevision) throw new
|
|
601
|
+
if (!account || account.removed || account.revision !== expectedRevision) throw new AuthSwitchRefusal('account_changed', 'Account changed; refresh before editing.');
|
|
558
602
|
return { ...account, label, revision: account.revision + 1, updateId,
|
|
559
603
|
statusObservedAt: new Date(this.now()).toISOString() };
|
|
560
604
|
});
|
|
@@ -585,7 +629,7 @@ export class AuthSwitchAuthorityBroker {
|
|
|
585
629
|
|| grant.owner !== 'daemon'
|
|
586
630
|
|| grant.purpose !== input.purpose || account.providerId !== 'openai'
|
|
587
631
|
|| input.runtime === 'claude') {
|
|
588
|
-
throw new
|
|
632
|
+
throw new AuthSwitchRefusal('login_unavailable', loginNotBindable);
|
|
589
633
|
}
|
|
590
634
|
return { id, accountId: input.accountId, grantId: grant.id, runtime: input.runtime, scopeId: input.scopeId,
|
|
591
635
|
incarnationId: input.incarnationId, revision: (existing?.revision ?? 0) + 1,
|
|
@@ -623,21 +667,27 @@ export class AuthSwitchAuthorityBroker {
|
|
|
623
667
|
const current = await this.database.readBindingContext(bindingId);
|
|
624
668
|
const binding = current.binding;
|
|
625
669
|
const expected = Buffer.from(binding?.capabilityHash ?? '0'.repeat(64), 'hex');
|
|
670
|
+
// A missing binding and a wrong capability are compared against the same zero hash on purpose, so
|
|
671
|
+
// nothing here tells a caller which it was. One code preserves exactly that, and it is truthful for
|
|
672
|
+
// both: this capability does not authorize anything, and binding again is the only repair.
|
|
626
673
|
if (!binding || !plugins.crypto.timingSafeEqual(supplied, expected)) {
|
|
627
|
-
throw new
|
|
674
|
+
throw new AuthSwitchRefusal('binding_unauthorized', bindingUnauthorized);
|
|
628
675
|
}
|
|
629
676
|
if (originalBinding && (binding.id !== originalBinding.id
|
|
630
677
|
|| binding.capabilityHash !== originalBinding.capabilityHash
|
|
631
678
|
|| binding.accountId !== originalBinding.accountId || binding.grantId !== originalBinding.grantId
|
|
632
679
|
|| binding.incarnationId !== originalBinding.incarnationId
|
|
633
680
|
|| binding.grantAuthorizationGeneration !== originalBinding.grantAuthorizationGeneration)) {
|
|
634
|
-
|
|
681
|
+
// The capability still matched, so what moved is the binding itself: another incarnation took the
|
|
682
|
+
// scope, or the account was reauthorized under it. The caller's repair is the one above -- bind
|
|
683
|
+
// again -- so it is the same code; a second one would name a difference no runtime can act on.
|
|
684
|
+
throw new AuthSwitchRefusal('binding_unauthorized', bindingMoved);
|
|
635
685
|
}
|
|
636
686
|
originalBinding ??= binding;
|
|
637
687
|
if (!current.account || current.account.removed || !current.grant
|
|
638
688
|
|| current.grant.id !== binding.grantId
|
|
639
689
|
|| current.grant.authorizationGeneration !== binding.grantAuthorizationGeneration) {
|
|
640
|
-
throw new
|
|
690
|
+
throw new AuthSwitchRefusal('login_unavailable', bindingNeedsReauth);
|
|
641
691
|
}
|
|
642
692
|
return { account: current.account, grant: current.grant };
|
|
643
693
|
}, minValidityMs, rejectedGrantGeneration);
|
|
@@ -659,6 +709,15 @@ export class AuthSwitchAuthorityBroker {
|
|
|
659
709
|
}, minValidityMs, rejectedGrantGeneration);
|
|
660
710
|
}
|
|
661
711
|
|
|
712
|
+
/**
|
|
713
|
+
* The shared managed-access loop, whose refusals are deliberately still unmarked faults.
|
|
714
|
+
*
|
|
715
|
+
* Its two callers repair differently: a runtime holding a binding binds again, while the usage reader has
|
|
716
|
+
* no binding at all and collapses everything into one usage problem. Naming a code here would either say
|
|
717
|
+
* "binding" to a caller that has none, or invent a second meaning for one that does, so the decision waits
|
|
718
|
+
* for the slice that gives the usage answer its own vocabulary. What a bound runtime can act on is decided
|
|
719
|
+
* before this point, in the view `resolveAccess` supplies.
|
|
720
|
+
*/
|
|
662
721
|
private async resolveManagedAccess(readView: () => Promise<{
|
|
663
722
|
account: IStoredAuthorityAccount; grant: IStoredAuthorityGrant;
|
|
664
723
|
}>, minValidityMs: number, rejectedGrantGeneration?: number): Promise<IAuthSwitchResolvedAccess> {
|
|
@@ -68,7 +68,13 @@ export interface IAuthSwitchSubscriptionOptions {
|
|
|
68
68
|
heartbeatMs?: number;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* Node-only client for the per-user daemon. Each request has its own bounded Unix connection.
|
|
73
|
+
*
|
|
74
|
+
* Every method takes an optional `AbortSignal`. A referenced socket with a 35 second timeout outlives a
|
|
75
|
+
* consumer's own stop unless that consumer can cancel the read, so the signal is what releases it; it
|
|
76
|
+
* detaches this request only and never cancels work the daemon already owns.
|
|
77
|
+
*/
|
|
72
78
|
export class AuthSwitchClient {
|
|
73
79
|
private readonly target: plugins.typedrequest.TypedTarget;
|
|
74
80
|
private readonly runtimeTarget: plugins.typedrequest.TypedTarget;
|
|
@@ -119,9 +125,10 @@ export class AuthSwitchClient {
|
|
|
119
125
|
{ submission, callerQuiescent: true, acknowledgeRunOrder: true }, 120_000, true, signal)).result;
|
|
120
126
|
}
|
|
121
127
|
|
|
122
|
-
public async getUsage(accountId: string, loginId: string, force = false
|
|
128
|
+
public async getUsage(accountId: string, loginId: string, force = false,
|
|
129
|
+
signal?: AbortSignal): Promise<IReq_AuthSwitchUsage['response']['usage']> {
|
|
123
130
|
return (await this.request<IReq_AuthSwitchUsage>('authswitch.authority.usage',
|
|
124
|
-
{ accountId, loginId, force })).usage;
|
|
131
|
+
{ accountId, loginId, force }, 35_000, false, signal)).usage;
|
|
125
132
|
}
|
|
126
133
|
|
|
127
134
|
/** Assemble a consistent view from bounded database pages; restart if a writer changes the revision. */
|
|
@@ -167,8 +174,24 @@ export class AuthSwitchClient {
|
|
|
167
174
|
if (!Number.isSafeInteger(heartbeatMs) || heartbeatMs < 50 || heartbeatMs > 30_000) {
|
|
168
175
|
throw new Error('Authswitch subscription heartbeat must be 50–30000 ms.');
|
|
169
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* The pause between reconnection attempts, which never keeps its consumer's process alive.
|
|
179
|
+
*
|
|
180
|
+
* A subscription that cannot reach the daemon re-arms this timer for as long as that lasts, and during
|
|
181
|
+
* each pause it is the only handle this client holds -- the failed request already destroyed its socket.
|
|
182
|
+
* Referenced, that chain of 250 ms waits would hold an otherwise finished process open indefinitely,
|
|
183
|
+
* and it has nothing to finish: the wait itself does no work, and an abort clears it.
|
|
184
|
+
*
|
|
185
|
+
* An abort that already happened is checked before the timer is armed, because a signal fires once: a
|
|
186
|
+
* consumer that stops from inside its own disconnect callback aborts between this loop's last check and
|
|
187
|
+
* this call, and a listener added afterwards would never run. The pause would then be waited out in
|
|
188
|
+
* full, and since it holds nothing, a process whose only remaining handle it is can exit inside it --
|
|
189
|
+
* dropping the closing status this loop owes its consumer.
|
|
190
|
+
*/
|
|
170
191
|
const retry = () => new Promise<void>(resolve => {
|
|
192
|
+
if (signal.aborted) { resolve(); return; }
|
|
171
193
|
const timer = setTimeout(() => { signal.removeEventListener('abort', aborted); resolve(); }, 250);
|
|
194
|
+
timer.unref();
|
|
172
195
|
const aborted = () => { clearTimeout(timer); resolve(); };
|
|
173
196
|
signal.addEventListener('abort', aborted, { once: true });
|
|
174
197
|
});
|
|
@@ -258,8 +281,10 @@ export class AuthSwitchClient {
|
|
|
258
281
|
return (await this.request<IReq_AuthSwitchBeginReauth>('authswitch.authority.reauth',
|
|
259
282
|
{ operationId, accountId, loginId, purpose, flow: 'device' }, 35_000, false, signal)).operation;
|
|
260
283
|
}
|
|
261
|
-
public listOperations(after?: string, limit?: number
|
|
262
|
-
|
|
284
|
+
public listOperations(after?: string, limit?: number,
|
|
285
|
+
signal?: AbortSignal): Promise<IReq_AuthSwitchListOperations['response']> {
|
|
286
|
+
return this.request<IReq_AuthSwitchListOperations>('authswitch.authority.operations',
|
|
287
|
+
{ after, limit }, 35_000, false, signal);
|
|
263
288
|
}
|
|
264
289
|
public async getOperation(operationId: string, signal?: AbortSignal): Promise<IReq_AuthSwitchGetOperation['response']['operation']> {
|
|
265
290
|
return (await this.request<IReq_AuthSwitchGetOperation>('authswitch.authority.operation',
|
|
@@ -284,27 +309,39 @@ export class AuthSwitchClient {
|
|
|
284
309
|
return (await this.request<IReq_AuthSwitchCancelPreuse>(
|
|
285
310
|
'authswitch.authority.preuse.cancel', { operationId }, 35_000, false, signal)).operation;
|
|
286
311
|
}
|
|
287
|
-
public async renameAccount(accountId: string, expectedRevision: number, label: string
|
|
288
|
-
|
|
312
|
+
public async renameAccount(accountId: string, expectedRevision: number, label: string,
|
|
313
|
+
signal?: AbortSignal): Promise<IReq_AuthSwitchRenameAccount['response']['account']> {
|
|
314
|
+
return (await this.request<IReq_AuthSwitchRenameAccount>('authswitch.authority.rename',
|
|
315
|
+
{ accountId, expectedRevision, label }, 35_000, false, signal)).account;
|
|
289
316
|
}
|
|
290
|
-
public async removeAccount(accountId: string, expectedRevision: number
|
|
291
|
-
|
|
317
|
+
public async removeAccount(accountId: string, expectedRevision: number,
|
|
318
|
+
signal?: AbortSignal): Promise<IReq_AuthSwitchRemoveAccount['response']['account']> {
|
|
319
|
+
return (await this.request<IReq_AuthSwitchRemoveAccount>('authswitch.authority.remove',
|
|
320
|
+
{ accountId, expectedRevision }, 35_000, false, signal)).account;
|
|
292
321
|
}
|
|
293
|
-
public async switchClaudeNative(accountId: string, loginId: string
|
|
322
|
+
public async switchClaudeNative(accountId: string, loginId: string,
|
|
323
|
+
signal?: AbortSignal): Promise<IReq_AuthSwitchSwitchClaudeNative['response']['handoff']> {
|
|
294
324
|
return (await this.request<IReq_AuthSwitchSwitchClaudeNative>('authswitch.authority.claude.switch',
|
|
295
|
-
{ accountId, loginId, purpose: 'claude_host_native' })).handoff;
|
|
325
|
+
{ accountId, loginId, purpose: 'claude_host_native' }, 35_000, false, signal)).handoff;
|
|
296
326
|
}
|
|
297
|
-
public async getClaudeNativeHandoff(operationId: string
|
|
298
|
-
|
|
327
|
+
public async getClaudeNativeHandoff(operationId: string,
|
|
328
|
+
signal?: AbortSignal): Promise<IReq_AuthSwitchClaudeNativeHandoff['response']['handoff']> {
|
|
329
|
+
return (await this.request<IReq_AuthSwitchClaudeNativeHandoff>('authswitch.authority.claude.handoff',
|
|
330
|
+
{ operationId }, 35_000, false, signal)).handoff;
|
|
299
331
|
}
|
|
300
|
-
public listClaudeNativeHandoffs(after?: string, limit?: number
|
|
301
|
-
|
|
332
|
+
public listClaudeNativeHandoffs(after?: string, limit?: number,
|
|
333
|
+
signal?: AbortSignal): Promise<IReq_AuthSwitchClaudeNativeHandoffs['response']> {
|
|
334
|
+
return this.request<IReq_AuthSwitchClaudeNativeHandoffs>('authswitch.authority.claude.handoffs',
|
|
335
|
+
{ after, limit }, 35_000, false, signal);
|
|
302
336
|
}
|
|
303
|
-
public bindAccount(input: IReq_AuthSwitchBindAccount['request']
|
|
304
|
-
|
|
337
|
+
public bindAccount(input: IReq_AuthSwitchBindAccount['request'],
|
|
338
|
+
signal?: AbortSignal): Promise<IReq_AuthSwitchBindAccount['response']> {
|
|
339
|
+
return this.request<IReq_AuthSwitchBindAccount>('authswitch.authority.bind', input, 35_000, false, signal);
|
|
305
340
|
}
|
|
306
|
-
public resolveAccess(input: IReq_AuthSwitchResolveAccess['request']
|
|
307
|
-
|
|
341
|
+
public resolveAccess(input: IReq_AuthSwitchResolveAccess['request'],
|
|
342
|
+
signal?: AbortSignal): Promise<IReq_AuthSwitchResolveAccess['response']> {
|
|
343
|
+
return this.request<IReq_AuthSwitchResolveAccess>('authswitch.authority.resolveAccess',
|
|
344
|
+
input, 35_000, true, signal);
|
|
308
345
|
}
|
|
309
346
|
public releaseBinding(input: IReq_AuthSwitchReleaseBinding['request'], signal?: AbortSignal): Promise<IReq_AuthSwitchReleaseBinding['response']> {
|
|
310
347
|
return this.request<IReq_AuthSwitchReleaseBinding>('authswitch.authority.release', input, 35_000, true, signal);
|
|
@@ -320,9 +357,10 @@ export class AuthSwitchRuntimeClient {
|
|
|
320
357
|
postMethod: (payload, options) => post(runtimeSocketPath, payload, options?.signal),
|
|
321
358
|
});
|
|
322
359
|
}
|
|
323
|
-
public resolveAccess(input: IReq_AuthSwitchResolveAccess['request']
|
|
360
|
+
public resolveAccess(input: IReq_AuthSwitchResolveAccess['request'],
|
|
361
|
+
signal?: AbortSignal): Promise<IReq_AuthSwitchResolveAccess['response']> {
|
|
324
362
|
return new plugins.typedrequest.TypedRequest<IReq_AuthSwitchResolveAccess>(this.target,
|
|
325
|
-
'authswitch.authority.resolveAccess').fire(input, { timeoutMs: 35_000, maxRetries: 0 });
|
|
363
|
+
'authswitch.authority.resolveAccess').fire(input, { timeoutMs: 35_000, maxRetries: 0, abortSignal: signal });
|
|
326
364
|
}
|
|
327
365
|
public releaseBinding(input: IReq_AuthSwitchReleaseBinding['request'], signal?: AbortSignal): Promise<IReq_AuthSwitchReleaseBinding['response']> {
|
|
328
366
|
return new plugins.typedrequest.TypedRequest<IReq_AuthSwitchReleaseBinding>(this.target,
|