@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.
Files changed (73) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/authority-contract.d.ts +73 -0
  3. package/dist_ts/authority-contract.js +55 -2
  4. package/dist_ts/authority-import-contract.d.ts +8 -4
  5. package/dist_ts/authority-import-contract.js +12 -13
  6. package/dist_ts/authority-paths.d.ts +37 -0
  7. package/dist_ts/authority-paths.js +46 -0
  8. package/dist_ts/authority-runtime-contract.d.ts +11 -1
  9. package/dist_ts/classes.authoritybroker.d.ts +9 -0
  10. package/dist_ts/classes.authoritybroker.js +72 -11
  11. package/dist_ts/classes.authorityclient.d.ts +17 -11
  12. package/dist_ts/classes.authorityclient.js +47 -22
  13. package/dist_ts/classes.authoritydaemon.d.ts +22 -3
  14. package/dist_ts/classes.authoritydaemon.js +106 -59
  15. package/dist_ts/classes.authoritydatabase.d.ts +9 -1
  16. package/dist_ts/classes.authoritydatabase.js +39 -13
  17. package/dist_ts/classes.authorityimport.d.ts +33 -6
  18. package/dist_ts/classes.authorityimport.js +102 -25
  19. package/dist_ts/classes.authoritymodels.d.ts +4 -1
  20. package/dist_ts/classes.authoritymodels.js +15 -3
  21. package/dist_ts/classes.authoritypreuse.js +8 -3
  22. package/dist_ts/classes.authorityservice.d.ts +20 -11
  23. package/dist_ts/classes.authorityservice.js +37 -23
  24. package/dist_ts/classes.claudeauthority.js +19 -11
  25. package/dist_ts/classes.claudenative.d.ts +63 -3
  26. package/dist_ts/classes.claudenative.js +68 -8
  27. package/dist_ts/classes.cli.d.ts +10 -2
  28. package/dist_ts/classes.cli.js +12 -4
  29. package/dist_ts/classes.codexmanaged.d.ts +8 -0
  30. package/dist_ts/classes.codexmanaged.js +19 -12
  31. package/dist_ts/classes.legacyfence.d.ts +53 -0
  32. package/dist_ts/classes.legacyfence.js +189 -0
  33. package/dist_ts/classes.operations.d.ts +15 -3
  34. package/dist_ts/classes.operations.js +22 -4
  35. package/dist_ts/classes.service.d.ts +21 -2
  36. package/dist_ts/classes.service.js +35 -8
  37. package/dist_ts/classes.tui.d.ts +2 -1
  38. package/dist_ts/classes.tui.js +3 -2
  39. package/dist_ts/ts_migration/0003_claude_handoff_proof.d.ts +13 -0
  40. package/dist_ts/ts_migration/0003_claude_handoff_proof.js +20 -0
  41. package/dist_ts/ts_migration/index.js +3 -1
  42. package/dist_ts/ts_migration/legacysources/authswitchstores.js +5 -2
  43. package/dist_ts/ts_migration/legacysources/nativestores.js +15 -8
  44. package/dist_ts/ts_migration/legacysources/shared.d.ts +3 -2
  45. package/dist_ts/ts_migration/legacysources/shared.js +3 -5
  46. package/package.json +11 -7
  47. package/readme.md +188 -13
  48. package/ts/00_commitinfo_data.ts +1 -1
  49. package/ts/authority-contract.ts +125 -0
  50. package/ts/authority-import-contract.ts +12 -11
  51. package/ts/authority-paths.ts +69 -0
  52. package/ts/authority-runtime-contract.ts +11 -1
  53. package/ts/classes.authoritybroker.ts +70 -11
  54. package/ts/classes.authorityclient.ts +59 -21
  55. package/ts/classes.authoritydaemon.ts +116 -60
  56. package/ts/classes.authoritydatabase.ts +39 -12
  57. package/ts/classes.authorityimport.ts +131 -26
  58. package/ts/classes.authoritymodels.ts +11 -2
  59. package/ts/classes.authoritypreuse.ts +7 -1
  60. package/ts/classes.authorityservice.ts +42 -30
  61. package/ts/classes.claudeauthority.ts +22 -10
  62. package/ts/classes.claudenative.ts +104 -10
  63. package/ts/classes.cli.ts +14 -3
  64. package/ts/classes.codexmanaged.ts +18 -7
  65. package/ts/classes.legacyfence.ts +219 -0
  66. package/ts/classes.operations.ts +22 -3
  67. package/ts/classes.service.ts +45 -8
  68. package/ts/classes.tui.ts +3 -1
  69. package/ts/ts_migration/0003_claude_handoff_proof.ts +19 -0
  70. package/ts/ts_migration/index.ts +2 -0
  71. package/ts/ts_migration/legacysources/authswitchstores.ts +4 -1
  72. package/ts/ts_migration/legacysources/nativestores.ts +15 -7
  73. 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 Error('Account operation was not found.');
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 Error('Account operation was not found.');
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 Error('Account operation was not found.');
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 Error('Account operation was not found.');
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 Error('Account changed; refresh before editing.');
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 Error('Account is not available for this runtime.');
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 Error('Runtime binding is not authorized.');
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
- throw new Error('Account binding changed during credential resolution.');
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 Error('Account needs reauthentication.');
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
- /** Node-only client for the per-user daemon. Each request has its own bounded Unix connection. */
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): Promise<IReq_AuthSwitchUsage['response']['usage']> {
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): Promise<IReq_AuthSwitchListOperations['response']> {
262
- return this.request<IReq_AuthSwitchListOperations>('authswitch.authority.operations', { after, limit });
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): Promise<IReq_AuthSwitchRenameAccount['response']['account']> {
288
- return (await this.request<IReq_AuthSwitchRenameAccount>('authswitch.authority.rename', { accountId, expectedRevision, label })).account;
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): Promise<IReq_AuthSwitchRemoveAccount['response']['account']> {
291
- return (await this.request<IReq_AuthSwitchRemoveAccount>('authswitch.authority.remove', { accountId, expectedRevision })).account;
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): Promise<IReq_AuthSwitchSwitchClaudeNative['response']['handoff']> {
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): Promise<IReq_AuthSwitchClaudeNativeHandoff['response']['handoff']> {
298
- return (await this.request<IReq_AuthSwitchClaudeNativeHandoff>('authswitch.authority.claude.handoff', { operationId })).handoff;
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): Promise<IReq_AuthSwitchClaudeNativeHandoffs['response']> {
301
- return this.request<IReq_AuthSwitchClaudeNativeHandoffs>('authswitch.authority.claude.handoffs', { after, limit });
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']): Promise<IReq_AuthSwitchBindAccount['response']> {
304
- return this.request<IReq_AuthSwitchBindAccount>('authswitch.authority.bind', input);
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']): Promise<IReq_AuthSwitchResolveAccess['response']> {
307
- return this.request<IReq_AuthSwitchResolveAccess>('authswitch.authority.resolveAccess', input, 35_000, true);
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']): Promise<IReq_AuthSwitchResolveAccess['response']> {
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,