@sekuire/sdk 0.1.22 → 0.1.24

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.
@@ -13,6 +13,10 @@ export interface A2AClientOptions {
13
13
  timeout?: number;
14
14
  /** Optional device fingerprint for API-key auth on task endpoints */
15
15
  deviceFingerprint?: string;
16
+ /** Optional runtime token resolver for per-request credential sync */
17
+ tokenResolver?: () => string | undefined;
18
+ /** Optional callback to refresh credentials after runtime-token 401 */
19
+ onUnauthorized?: () => Promise<void>;
16
20
  }
17
21
  /**
18
22
  * A2A Protocol Client
@@ -45,6 +49,8 @@ export declare class A2AClient {
45
49
  private runtimeToken;
46
50
  private timeout;
47
51
  private deviceFingerprint;
52
+ private tokenResolver?;
53
+ private onUnauthorized?;
48
54
  constructor(options: A2AClientOptions);
49
55
  setRuntimeToken(token: string): void;
50
56
  /**
@@ -110,6 +116,8 @@ export declare class A2AClient {
110
116
  private jsonRpc;
111
117
  private fetch;
112
118
  private fetchTask;
119
+ private doFetchTask;
120
+ private resolveRuntimeToken;
113
121
  private taskAuthHeaders;
114
122
  private isLikelyJwt;
115
123
  }
@@ -17,6 +17,8 @@ export interface DelegatorConfig {
17
17
  retryDelayMs?: number;
18
18
  retryBackoffMultiplier?: number;
19
19
  policyGateway?: PolicyGateway;
20
+ tokenResolver?: () => string | undefined;
21
+ onUnauthorized?: () => Promise<void>;
20
22
  }
21
23
  export interface DelegationRequest {
22
24
  skill: string;
package/dist/beacon.d.ts CHANGED
@@ -72,7 +72,7 @@ export interface InstallationCredentials {
72
72
  export interface BootstrapResponse {
73
73
  installation_id: string;
74
74
  runtime_token: string;
75
- refresh_token: string;
75
+ refresh_token?: string;
76
76
  expires_at: string;
77
77
  heartbeat_interval: number;
78
78
  }
package/dist/index.d.ts CHANGED
@@ -305,6 +305,8 @@ interface DelegatorConfig {
305
305
  retryDelayMs?: number;
306
306
  retryBackoffMultiplier?: number;
307
307
  policyGateway?: PolicyGateway;
308
+ tokenResolver?: () => string | undefined;
309
+ onUnauthorized?: () => Promise<void>;
308
310
  }
309
311
  interface DelegationRequest {
310
312
  skill: string;
@@ -366,12 +368,30 @@ interface RuntimeCredentials {
366
368
  refreshToken?: string;
367
369
  expiresAt?: string;
368
370
  }
371
+ interface BootstrapResponseData {
372
+ installation_id: string;
373
+ runtime_token: string;
374
+ refresh_token?: string;
375
+ expires_at: string;
376
+ }
377
+ interface BootstrapTarget {
378
+ installationId: string | null;
379
+ runtimeToken: string | null;
380
+ refreshToken: string | null;
381
+ credentialsStore?: RuntimeCredentialsStore | null;
382
+ }
383
+ declare function applyBootstrapResponse(target: BootstrapTarget, data: BootstrapResponseData): void;
369
384
  declare class RuntimeCredentialsStore {
370
385
  private installationId?;
371
386
  private runtimeToken?;
372
387
  private refreshToken?;
373
388
  private expiresAt?;
374
- constructor(initial?: RuntimeCredentials);
389
+ private apiBaseUrl?;
390
+ private inflightRefresh;
391
+ constructor(initial?: RuntimeCredentials & {
392
+ apiBaseUrl?: string;
393
+ });
394
+ setApiBaseUrl(url: string): void;
375
395
  update(partial: RuntimeCredentials): void;
376
396
  setRuntimeToken(runtimeToken: string, expiresAt?: string): void;
377
397
  setInstallationId(installationId: string): void;
@@ -383,6 +403,8 @@ declare class RuntimeCredentialsStore {
383
403
  getAll(): RuntimeCredentials;
384
404
  hasRecoveryCredentials(): boolean;
385
405
  hasRuntimeToken(): boolean;
406
+ refreshRuntimeToken(caller?: string): Promise<void>;
407
+ private doRefresh;
386
408
  }
387
409
 
388
410
  /**
@@ -458,7 +480,7 @@ interface InstallationCredentials {
458
480
  interface BootstrapResponse {
459
481
  installation_id: string;
460
482
  runtime_token: string;
461
- refresh_token: string;
483
+ refresh_token?: string;
462
484
  expires_at: string;
463
485
  heartbeat_interval: number;
464
486
  }
@@ -1059,6 +1081,9 @@ declare class SekuireSDK {
1059
1081
  createDelegator(options?: {
1060
1082
  timeout?: number;
1061
1083
  pollInterval?: number;
1084
+ maxRetries?: number;
1085
+ retryDelayMs?: number;
1086
+ retryBackoffMultiplier?: number;
1062
1087
  }): A2ATaskDelegator;
1063
1088
  /**
1064
1089
  * Get the agent ID.
@@ -3342,6 +3367,10 @@ interface A2AClientOptions {
3342
3367
  timeout?: number;
3343
3368
  /** Optional device fingerprint for API-key auth on task endpoints */
3344
3369
  deviceFingerprint?: string;
3370
+ /** Optional runtime token resolver for per-request credential sync */
3371
+ tokenResolver?: () => string | undefined;
3372
+ /** Optional callback to refresh credentials after runtime-token 401 */
3373
+ onUnauthorized?: () => Promise<void>;
3345
3374
  }
3346
3375
  /**
3347
3376
  * A2A Protocol Client
@@ -3374,6 +3403,8 @@ declare class A2AClient {
3374
3403
  private runtimeToken;
3375
3404
  private timeout;
3376
3405
  private deviceFingerprint;
3406
+ private tokenResolver?;
3407
+ private onUnauthorized?;
3377
3408
  constructor(options: A2AClientOptions);
3378
3409
  setRuntimeToken(token: string): void;
3379
3410
  /**
@@ -3439,6 +3470,8 @@ declare class A2AClient {
3439
3470
  private jsonRpc;
3440
3471
  private fetch;
3441
3472
  private fetchTask;
3473
+ private doFetchTask;
3474
+ private resolveRuntimeToken;
3442
3475
  private taskAuthHeaders;
3443
3476
  private isLikelyJwt;
3444
3477
  }
@@ -3534,5 +3567,5 @@ declare class A2AServer {
3534
3567
  private generateId;
3535
3568
  }
3536
3569
 
3537
- export { A2AClient, A2AError, A2AServer, A2ATaskDelegator, SekuireAgent as Agent, AgentIdentity, AnthropicProvider, BaseMemoryStorage, Beacon, CONVEX_FUNCTIONS_TEMPLATE, CONVEX_SCHEMA_TEMPLATE, CloudflareD1Storage, CloudflareKVStorage, ComplianceError, ComplianceMonitor, ContentPolicyError, ConvexStorage, CryptoError, DEFAULT_API_URL, DynamoDBStorage, FileAccessError, GoogleProvider, InMemoryStorage, NetworkComplianceError, NetworkError, OllamaProvider, OpenAIProvider, PolicyClient, PolicyEnforcer, PolicyGateway, PolicyViolationError, PostgresStorage, ProtocolError, RedisStorage, RuntimeCredentialsStore, SQLiteStorage, SekuireAgent$1 as SekuireAgent, SekuireAgentBuilder, SekuireClient, SekuireCrypto, SekuireError, SekuireLogger, SekuireRegistryClient, SekuireSDK, SekuireServer, SekuireSpanExporter, TaskWorker, Tool, ToolPatternParser, ToolRegistry, ToolUsageError, TursoStorage, UpstashStorage, builtInTools, calculateSekuireId, createAgent, createBeacon, createDefaultToolRegistry, createDelegationTool, createDelegator, createDiscoveryTool, createLLMProvider, createMemoryStorage, createRegistryClient, createSekuireClient, createSekuireExpressMiddleware, createSekuireFastifyPlugin, createWorker, detectDeploymentUrl, generateKeyPair, getAgent, getAgentConfig, getAgents, getTools$1 as getLegacyTools, getStorageInfo, getSystemPrompt, getTools, getTracer, hasStorage, initTelemetry, listStorageTypes, llm, loadConfig, loadSystemPrompt, loadTools, registerStorage, shutdownTelemetry, tool, tools };
3538
- export type { A2AArtifact, A2AClientOptions, A2AMessage, A2AMessagePart, A2ARouteRequest, A2ARouteResponse, A2AServerOptions, A2ATask, A2ATaskState, A2ATaskStatus, ActivePolicy, ActivePolicyResponse, AgentCapabilities, AgentCard, AgentConfig, AgentId, AgentInvokeOptions, AgentOptions, AgentProvider, AgentResponse$1 as AgentResponse, AgentSkill, BeaconConfig, BeaconStatus, BootstrapResponse, BuiltInMemoryType, ChatChunk, ChatOptions, ChatResponse, CloudflareD1Config, CloudflareKVConfig, ComplianceConfig, ComplianceViolation, ConditionOperator, ToolDefinition$1 as ConfigToolDefinition, ConvexConfig, CreateOrgRequest, CreateWorkspaceRequest, CustomRule, DelegationRequest, DelegationResult, DelegatorConfig, DisputeRequest, DisputeResponse, DynamoDBConfig, EventLog, EventType, ExporterType, HandshakeAuth, HandshakeHello, HandshakeResult, HandshakeWelcome, HexString, IdentityConfig, InstallationCredentials, InviteRequest, InviteResponse, JsonRpcError, JsonRpcRequest, JsonRpcResponse, KeyPair, LLMConfig, Message as LLMMessage, LLMProvider, LLMProviderConfig, ToolCallFunction as LLMToolCall, ToolDefinition as LLMToolDefinition, LeaderboardEntry, LoggerConfig$1 as LoggerConfig, Manifest, MemoryConfig, MemoryFactoryConfig, MemoryMessage, MemoryStorage, MemoryType, Message$1 as Message, OrgResponse, OrgSummary, PerAgentLimits, PolicyDecision, PolicyViolation, PostgresConfig, ProjectMetadata, PublishAgentOptions, PublishRequest, PublishResponse, RateLimitsConfig$1 as RateLimitsConfig, RedisConfig, RegistryClientConfig, ReputationLog, ReputationResponse, RuleCondition, RuntimeCredentials, SQLiteConfig, SearchAgentsOptions, SekuireAgentConfig, SekuireClientConfig, SekuireConfig, SekuireExporterConfig, SekuireSDKConfig, Severity, SkillContext, SkillHandler, StreamingSkillContext, StreamingSkillHandler, StreamingUpdate, SubmitReputationRequest, TaskCompletion, TaskContext, TaskEvent, TaskHandler, TaskState, TaskUpdateEvent, TasksCancelParams, TasksGetParams, TasksSendParams, TasksSendSubscribeParams, TelemetryConfig, ToolCall, ToolDefinition$2 as ToolDefinition, ToolInput, ToolMetadata, ToolParameter, ToolsSchema, TrustHeaders, TrustHeadersRequest, TursoConfig, UpdateAgentOptions, UpstashConfig, UserContextResponse, VerificationIssue, VerificationRequest, VerificationResult, VerificationStatus, VerifyAgentRequest, WorkerConfig, WorkspaceResponse, WorkspaceSummary };
3570
+ export { A2AClient, A2AError, A2AServer, A2ATaskDelegator, SekuireAgent as Agent, AgentIdentity, AnthropicProvider, BaseMemoryStorage, Beacon, CONVEX_FUNCTIONS_TEMPLATE, CONVEX_SCHEMA_TEMPLATE, CloudflareD1Storage, CloudflareKVStorage, ComplianceError, ComplianceMonitor, ContentPolicyError, ConvexStorage, CryptoError, DEFAULT_API_URL, DynamoDBStorage, FileAccessError, GoogleProvider, InMemoryStorage, NetworkComplianceError, NetworkError, OllamaProvider, OpenAIProvider, PolicyClient, PolicyEnforcer, PolicyGateway, PolicyViolationError, PostgresStorage, ProtocolError, RedisStorage, RuntimeCredentialsStore, SQLiteStorage, SekuireAgent$1 as SekuireAgent, SekuireAgentBuilder, SekuireClient, SekuireCrypto, SekuireError, SekuireLogger, SekuireRegistryClient, SekuireSDK, SekuireServer, SekuireSpanExporter, TaskWorker, Tool, ToolPatternParser, ToolRegistry, ToolUsageError, TursoStorage, UpstashStorage, applyBootstrapResponse, builtInTools, calculateSekuireId, createAgent, createBeacon, createDefaultToolRegistry, createDelegationTool, createDelegator, createDiscoveryTool, createLLMProvider, createMemoryStorage, createRegistryClient, createSekuireClient, createSekuireExpressMiddleware, createSekuireFastifyPlugin, createWorker, detectDeploymentUrl, generateKeyPair, getAgent, getAgentConfig, getAgents, getTools$1 as getLegacyTools, getStorageInfo, getSystemPrompt, getTools, getTracer, hasStorage, initTelemetry, listStorageTypes, llm, loadConfig, loadSystemPrompt, loadTools, registerStorage, shutdownTelemetry, tool, tools };
3571
+ export type { A2AArtifact, A2AClientOptions, A2AMessage, A2AMessagePart, A2ARouteRequest, A2ARouteResponse, A2AServerOptions, A2ATask, A2ATaskState, A2ATaskStatus, ActivePolicy, ActivePolicyResponse, AgentCapabilities, AgentCard, AgentConfig, AgentId, AgentInvokeOptions, AgentOptions, AgentProvider, AgentResponse$1 as AgentResponse, AgentSkill, BeaconConfig, BeaconStatus, BootstrapResponse, BootstrapResponseData, BootstrapTarget, BuiltInMemoryType, ChatChunk, ChatOptions, ChatResponse, CloudflareD1Config, CloudflareKVConfig, ComplianceConfig, ComplianceViolation, ConditionOperator, ToolDefinition$1 as ConfigToolDefinition, ConvexConfig, CreateOrgRequest, CreateWorkspaceRequest, CustomRule, DelegationRequest, DelegationResult, DelegatorConfig, DisputeRequest, DisputeResponse, DynamoDBConfig, EventLog, EventType, ExporterType, HandshakeAuth, HandshakeHello, HandshakeResult, HandshakeWelcome, HexString, IdentityConfig, InstallationCredentials, InviteRequest, InviteResponse, JsonRpcError, JsonRpcRequest, JsonRpcResponse, KeyPair, LLMConfig, Message as LLMMessage, LLMProvider, LLMProviderConfig, ToolCallFunction as LLMToolCall, ToolDefinition as LLMToolDefinition, LeaderboardEntry, LoggerConfig$1 as LoggerConfig, Manifest, MemoryConfig, MemoryFactoryConfig, MemoryMessage, MemoryStorage, MemoryType, Message$1 as Message, OrgResponse, OrgSummary, PerAgentLimits, PolicyDecision, PolicyViolation, PostgresConfig, ProjectMetadata, PublishAgentOptions, PublishRequest, PublishResponse, RateLimitsConfig$1 as RateLimitsConfig, RedisConfig, RegistryClientConfig, ReputationLog, ReputationResponse, RuleCondition, RuntimeCredentials, SQLiteConfig, SearchAgentsOptions, SekuireAgentConfig, SekuireClientConfig, SekuireConfig, SekuireExporterConfig, SekuireSDKConfig, Severity, SkillContext, SkillHandler, StreamingSkillContext, StreamingSkillHandler, StreamingUpdate, SubmitReputationRequest, TaskCompletion, TaskContext, TaskEvent, TaskHandler, TaskState, TaskUpdateEvent, TasksCancelParams, TasksGetParams, TasksSendParams, TasksSendSubscribeParams, TelemetryConfig, ToolCall, ToolDefinition$2 as ToolDefinition, ToolInput, ToolMetadata, ToolParameter, ToolsSchema, TrustHeaders, TrustHeadersRequest, TursoConfig, UpdateAgentOptions, UpstashConfig, UserContextResponse, VerificationIssue, VerificationRequest, VerificationResult, VerificationStatus, VerifyAgentRequest, WorkerConfig, WorkspaceResponse, WorkspaceSummary };
package/dist/index.esm.js CHANGED
@@ -69,6 +69,8 @@ class A2AClient {
69
69
  options.deviceFingerprint ||
70
70
  process.env.SEKUIRE_DEVICE_FINGERPRINT ||
71
71
  "sekuire-typescript-sdk";
72
+ this.tokenResolver = options.tokenResolver;
73
+ this.onUnauthorized = options.onUnauthorized;
72
74
  }
73
75
  setRuntimeToken(token) {
74
76
  this.runtimeToken = token;
@@ -78,7 +80,7 @@ class A2AClient {
78
80
  * The API will find an agent with the matching skill and forward the task.
79
81
  */
80
82
  async sendBySkill(request) {
81
- const response = await this.fetch("/a2a/route", {
83
+ const response = await this.fetchTask("/a2a/route", {
82
84
  method: "POST",
83
85
  body: JSON.stringify(request),
84
86
  });
@@ -291,19 +293,37 @@ class A2AClient {
291
293
  });
292
294
  }
293
295
  async fetchTask(path, init) {
296
+ const runtimeToken = this.resolveRuntimeToken();
297
+ const response = await this.doFetchTask(path, init, runtimeToken);
298
+ const usedRuntimeToken = !!runtimeToken && runtimeToken.startsWith("srt_");
299
+ if (response.status === 401 && usedRuntimeToken && this.onUnauthorized) {
300
+ try {
301
+ await this.onUnauthorized();
302
+ }
303
+ catch {
304
+ return response;
305
+ }
306
+ return this.doFetchTask(path, init, this.resolveRuntimeToken());
307
+ }
308
+ return response;
309
+ }
310
+ async doFetchTask(path, init, runtimeToken) {
294
311
  return fetch(`${this.baseUrl}${path}`, {
295
312
  ...init,
296
313
  headers: {
297
314
  "Content-Type": "application/json",
298
- ...this.taskAuthHeaders(),
315
+ ...this.taskAuthHeaders(runtimeToken),
299
316
  ...init.headers,
300
317
  },
301
318
  signal: AbortSignal.timeout(this.timeout),
302
319
  });
303
320
  }
304
- taskAuthHeaders() {
305
- if (this.runtimeToken) {
306
- return { Authorization: `Bearer ${this.runtimeToken}` };
321
+ resolveRuntimeToken() {
322
+ return this.tokenResolver?.() ?? this.runtimeToken;
323
+ }
324
+ taskAuthHeaders(runtimeToken) {
325
+ if (runtimeToken) {
326
+ return { Authorization: `Bearer ${runtimeToken}` };
307
327
  }
308
328
  if (this.isLikelyJwt(this.authToken)) {
309
329
  return { Authorization: `Bearer ${this.authToken}` };
@@ -396,6 +416,8 @@ class A2ATaskDelegator {
396
416
  baseUrl: config.apiUrl,
397
417
  authToken: config.authToken,
398
418
  timeout: this.config.timeout,
419
+ tokenResolver: config.tokenResolver,
420
+ onUnauthorized: config.onUnauthorized,
399
421
  });
400
422
  }
401
423
  setRuntimeToken(token) {
@@ -812,6 +834,121 @@ function detectDeploymentUrl() {
812
834
  return undefined;
813
835
  }
814
836
 
837
+ function applyBootstrapResponse(target, data) {
838
+ target.installationId = data.installation_id;
839
+ target.runtimeToken = data.runtime_token;
840
+ if (data.refresh_token) {
841
+ target.refreshToken = data.refresh_token;
842
+ }
843
+ target.credentialsStore?.update({
844
+ installationId: data.installation_id,
845
+ runtimeToken: data.runtime_token,
846
+ refreshToken: data.refresh_token,
847
+ expiresAt: data.expires_at,
848
+ });
849
+ }
850
+ class RuntimeCredentialsStore {
851
+ constructor(initial) {
852
+ this.inflightRefresh = null;
853
+ if (initial) {
854
+ this.update(initial);
855
+ }
856
+ if (initial?.apiBaseUrl) {
857
+ this.apiBaseUrl = initial.apiBaseUrl;
858
+ }
859
+ }
860
+ setApiBaseUrl(url) {
861
+ this.apiBaseUrl = url;
862
+ }
863
+ update(partial) {
864
+ if (partial.installationId) {
865
+ this.installationId = partial.installationId;
866
+ }
867
+ if (partial.runtimeToken) {
868
+ this.runtimeToken = partial.runtimeToken;
869
+ }
870
+ if (partial.refreshToken) {
871
+ this.refreshToken = partial.refreshToken;
872
+ }
873
+ if (partial.expiresAt !== undefined) {
874
+ this.expiresAt = partial.expiresAt;
875
+ }
876
+ }
877
+ setRuntimeToken(runtimeToken, expiresAt) {
878
+ this.runtimeToken = runtimeToken;
879
+ if (expiresAt !== undefined) {
880
+ this.expiresAt = expiresAt;
881
+ }
882
+ }
883
+ setInstallationId(installationId) {
884
+ this.installationId = installationId;
885
+ }
886
+ setRefreshToken(refreshToken) {
887
+ this.refreshToken = refreshToken;
888
+ }
889
+ getInstallationId() {
890
+ return this.installationId;
891
+ }
892
+ getRuntimeToken() {
893
+ return this.runtimeToken;
894
+ }
895
+ getRefreshToken() {
896
+ return this.refreshToken;
897
+ }
898
+ getExpiresAt() {
899
+ return this.expiresAt;
900
+ }
901
+ getAll() {
902
+ return {
903
+ installationId: this.installationId,
904
+ runtimeToken: this.runtimeToken,
905
+ refreshToken: this.refreshToken,
906
+ expiresAt: this.expiresAt,
907
+ };
908
+ }
909
+ hasRecoveryCredentials() {
910
+ return !!(this.installationId && this.refreshToken);
911
+ }
912
+ hasRuntimeToken() {
913
+ return !!this.runtimeToken;
914
+ }
915
+ async refreshRuntimeToken(caller) {
916
+ if (this.inflightRefresh) {
917
+ return this.inflightRefresh;
918
+ }
919
+ this.inflightRefresh = this.doRefresh(caller).finally(() => {
920
+ this.inflightRefresh = null;
921
+ });
922
+ return this.inflightRefresh;
923
+ }
924
+ async doRefresh(caller) {
925
+ const installationId = this.installationId;
926
+ const refreshToken = this.refreshToken;
927
+ const apiBaseUrl = this.apiBaseUrl;
928
+ if (!installationId || !refreshToken) {
929
+ throw new Error("Cannot refresh token - missing installation ID or refresh token");
930
+ }
931
+ if (!apiBaseUrl) {
932
+ throw new Error("Cannot refresh token - missing API base URL");
933
+ }
934
+ const response = await fetch(`${apiBaseUrl}/api/v1/installations/${installationId}/refresh`, {
935
+ method: "POST",
936
+ headers: { "Content-Type": "application/json" },
937
+ body: JSON.stringify({ refresh_token: refreshToken }),
938
+ });
939
+ if (!response.ok) {
940
+ const body = await response.text();
941
+ throw new Error(`Token refresh failed: ${response.status} - ${body}`);
942
+ }
943
+ const data = await response.json();
944
+ this.runtimeToken = data.runtime_token;
945
+ if (data.expires_at !== undefined) {
946
+ this.expiresAt = data.expires_at;
947
+ }
948
+ console.log(`[${caller || "CredentialsStore"}] Runtime token refreshed successfully`);
949
+ }
950
+ }
951
+
815
952
  /**
816
953
  * Sekuire Beacon - Deployment Registration & Heartbeat
817
954
  *
@@ -855,6 +992,7 @@ class Beacon {
855
992
  this.credentialsStore = config.credentialsStore;
856
993
  this.policyGateway = config.policyGateway;
857
994
  if (this.credentialsStore) {
995
+ this.credentialsStore.setApiBaseUrl(this.config.apiBaseUrl);
858
996
  this.credentialsStore.update({
859
997
  installationId: resolvedInstallationId,
860
998
  refreshToken: resolvedRefreshToken,
@@ -1042,6 +1180,16 @@ class Beacon {
1042
1180
  }
1043
1181
  // Refresh to get a new runtime token
1044
1182
  try {
1183
+ if (this.credentialsStore) {
1184
+ this.credentialsStore.update({ installationId, refreshToken });
1185
+ await this.credentialsStore.refreshRuntimeToken("Beacon");
1186
+ this.installationId = installationId;
1187
+ this.runtimeToken = this.credentialsStore.getRuntimeToken() ?? null;
1188
+ this.refreshToken = refreshToken;
1189
+ this.expiresAt = this.credentialsStore.getExpiresAt() ?? null;
1190
+ console.log('[Beacon] Credentials recovered via refresh token');
1191
+ return true;
1192
+ }
1045
1193
  const response = await fetch(`${this.config.apiBaseUrl}/api/v1/installations/${installationId}/refresh`, {
1046
1194
  method: 'POST',
1047
1195
  headers: {
@@ -1059,14 +1207,8 @@ class Beacon {
1059
1207
  const data = await response.json();
1060
1208
  this.installationId = installationId;
1061
1209
  this.runtimeToken = data.runtime_token;
1062
- this.refreshToken = refreshToken; // Refresh token is stable
1210
+ this.refreshToken = refreshToken;
1063
1211
  this.expiresAt = data.expires_at || null;
1064
- this.credentialsStore?.update({
1065
- installationId,
1066
- runtimeToken: data.runtime_token,
1067
- refreshToken,
1068
- expiresAt: data.expires_at,
1069
- });
1070
1212
  console.log('[Beacon] Credentials recovered via refresh token');
1071
1213
  return true;
1072
1214
  }
@@ -1176,9 +1318,7 @@ class Beacon {
1176
1318
  return false;
1177
1319
  }
1178
1320
  const data = await response.json();
1179
- this.installationId = data.installation_id;
1180
- this.runtimeToken = data.runtime_token;
1181
- this.refreshToken = data.refresh_token;
1321
+ applyBootstrapResponse(this, data);
1182
1322
  console.log(`[Beacon] Recovery bootstrap successful, installation ID: ${this.installationId}`);
1183
1323
  return true;
1184
1324
  }
@@ -1215,16 +1355,8 @@ class Beacon {
1215
1355
  throw new Error(`Bootstrap failed: ${response.status} ${response.statusText} - ${body}`);
1216
1356
  }
1217
1357
  const data = await response.json();
1218
- this.installationId = data.installation_id;
1219
- this.runtimeToken = data.runtime_token;
1220
- this.refreshToken = data.refresh_token;
1358
+ applyBootstrapResponse(this, data);
1221
1359
  this.expiresAt = data.expires_at || null;
1222
- this.credentialsStore?.update({
1223
- installationId: data.installation_id,
1224
- runtimeToken: data.runtime_token,
1225
- refreshToken: data.refresh_token,
1226
- expiresAt: data.expires_at,
1227
- });
1228
1360
  }
1229
1361
  /**
1230
1362
  * Send heartbeat (lease renewal) to Sekuire
@@ -1292,6 +1424,11 @@ class Beacon {
1292
1424
  * Refresh the runtime token using the refresh token
1293
1425
  */
1294
1426
  async refreshRuntimeToken() {
1427
+ if (this.credentialsStore) {
1428
+ await this.credentialsStore.refreshRuntimeToken("Beacon");
1429
+ this.runtimeToken = this.credentialsStore.getRuntimeToken() ?? null;
1430
+ return;
1431
+ }
1295
1432
  const installationId = this.getInstallationId();
1296
1433
  const refreshToken = this.getRefreshToken();
1297
1434
  if (!installationId || !refreshToken) {
@@ -1312,7 +1449,6 @@ class Beacon {
1312
1449
  }
1313
1450
  const data = await response.json();
1314
1451
  this.runtimeToken = data.runtime_token;
1315
- this.credentialsStore?.setRuntimeToken(data.runtime_token, data.expires_at);
1316
1452
  console.log('[Beacon] Runtime token refreshed successfully');
1317
1453
  }
1318
1454
  /**
@@ -2146,66 +2282,6 @@ class PolicyGateway {
2146
2282
  }
2147
2283
  }
2148
2284
 
2149
- class RuntimeCredentialsStore {
2150
- constructor(initial) {
2151
- if (initial) {
2152
- this.update(initial);
2153
- }
2154
- }
2155
- update(partial) {
2156
- if (partial.installationId) {
2157
- this.installationId = partial.installationId;
2158
- }
2159
- if (partial.runtimeToken) {
2160
- this.runtimeToken = partial.runtimeToken;
2161
- }
2162
- if (partial.refreshToken) {
2163
- this.refreshToken = partial.refreshToken;
2164
- }
2165
- if (partial.expiresAt !== undefined) {
2166
- this.expiresAt = partial.expiresAt;
2167
- }
2168
- }
2169
- setRuntimeToken(runtimeToken, expiresAt) {
2170
- this.runtimeToken = runtimeToken;
2171
- if (expiresAt !== undefined) {
2172
- this.expiresAt = expiresAt;
2173
- }
2174
- }
2175
- setInstallationId(installationId) {
2176
- this.installationId = installationId;
2177
- }
2178
- setRefreshToken(refreshToken) {
2179
- this.refreshToken = refreshToken;
2180
- }
2181
- getInstallationId() {
2182
- return this.installationId;
2183
- }
2184
- getRuntimeToken() {
2185
- return this.runtimeToken;
2186
- }
2187
- getRefreshToken() {
2188
- return this.refreshToken;
2189
- }
2190
- getExpiresAt() {
2191
- return this.expiresAt;
2192
- }
2193
- getAll() {
2194
- return {
2195
- installationId: this.installationId,
2196
- runtimeToken: this.runtimeToken,
2197
- refreshToken: this.refreshToken,
2198
- expiresAt: this.expiresAt,
2199
- };
2200
- }
2201
- hasRecoveryCredentials() {
2202
- return !!(this.installationId && this.refreshToken);
2203
- }
2204
- hasRuntimeToken() {
2205
- return !!this.runtimeToken;
2206
- }
2207
- }
2208
-
2209
2285
  function getDefaultExportFromCjs (x) {
2210
2286
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
2211
2287
  }
@@ -2758,6 +2834,7 @@ class TaskWorker {
2758
2834
  this.installationId = resolvedInstallationId || null;
2759
2835
  this.refreshToken = resolvedRefreshToken || null;
2760
2836
  if (this.credentialsStore) {
2837
+ this.credentialsStore.setApiBaseUrl(this.config.apiBaseUrl);
2761
2838
  this.credentialsStore.update({
2762
2839
  installationId: resolvedInstallationId,
2763
2840
  refreshToken: resolvedRefreshToken,
@@ -2830,6 +2907,17 @@ class TaskWorker {
2830
2907
  return false;
2831
2908
  }
2832
2909
  try {
2910
+ if (this.credentialsStore) {
2911
+ this.credentialsStore.update({ installationId, refreshToken });
2912
+ await this.credentialsStore.refreshRuntimeToken("Worker");
2913
+ this.installationId = installationId;
2914
+ this.runtimeToken = this.credentialsStore.getRuntimeToken() ?? null;
2915
+ this.refreshToken = refreshToken;
2916
+ const expiresAt = this.credentialsStore.getExpiresAt();
2917
+ this.expiresAt = expiresAt ? new Date(expiresAt).getTime() : null;
2918
+ console.log(`[Worker] Credentials recovered for installation: ${installationId}`);
2919
+ return true;
2920
+ }
2833
2921
  const response = await fetch(`${this.config.apiBaseUrl}/api/v1/installations/${installationId}/refresh`, {
2834
2922
  method: "POST",
2835
2923
  headers: {
@@ -2849,12 +2937,6 @@ class TaskWorker {
2849
2937
  this.runtimeToken = data.runtime_token;
2850
2938
  this.refreshToken = refreshToken;
2851
2939
  this.expiresAt = data.expires_at ? new Date(data.expires_at).getTime() : null;
2852
- this.credentialsStore?.update({
2853
- installationId,
2854
- runtimeToken: data.runtime_token,
2855
- refreshToken,
2856
- expiresAt: data.expires_at,
2857
- });
2858
2940
  console.log(`[Worker] Credentials recovered for installation: ${installationId}`);
2859
2941
  return true;
2860
2942
  }
@@ -3097,18 +3179,10 @@ class TaskWorker {
3097
3179
  throw new Error(`Bootstrap failed: ${response.status} - ${errorText}`);
3098
3180
  }
3099
3181
  const data = await response.json();
3100
- this.installationId = data.installation_id;
3101
- this.runtimeToken = data.runtime_token;
3102
- this.refreshToken = data.refresh_token;
3182
+ applyBootstrapResponse(this, data);
3103
3183
  this.expiresAt = data.expires_at
3104
3184
  ? new Date(data.expires_at).getTime()
3105
3185
  : null;
3106
- this.credentialsStore?.update({
3107
- installationId: data.installation_id,
3108
- runtimeToken: data.runtime_token,
3109
- refreshToken: data.refresh_token,
3110
- expiresAt: data.expires_at,
3111
- });
3112
3186
  console.log(`[Worker] Bootstrapped installation: ${this.installationId}`);
3113
3187
  }
3114
3188
  catch (e) {
@@ -3181,6 +3255,11 @@ class TaskWorker {
3181
3255
  * Refresh the runtime token using the refresh token
3182
3256
  */
3183
3257
  async refreshRuntimeToken() {
3258
+ if (this.credentialsStore) {
3259
+ await this.credentialsStore.refreshRuntimeToken("Worker");
3260
+ this.runtimeToken = this.credentialsStore.getRuntimeToken() ?? null;
3261
+ return;
3262
+ }
3184
3263
  const installationId = this.getInstallationId();
3185
3264
  const refreshToken = this.getRefreshToken();
3186
3265
  if (!installationId || !refreshToken) {
@@ -3201,7 +3280,6 @@ class TaskWorker {
3201
3280
  }
3202
3281
  const data = await response.json();
3203
3282
  this.runtimeToken = data.runtime_token;
3204
- this.credentialsStore?.setRuntimeToken(data.runtime_token, data.expires_at);
3205
3283
  console.log("[Worker] Runtime token refreshed successfully");
3206
3284
  }
3207
3285
  getInstallationId() {
@@ -3267,6 +3345,7 @@ class SekuireSDK {
3267
3345
  installationId: this.config.installationId,
3268
3346
  refreshToken: this.config.refreshToken,
3269
3347
  runtimeToken: this.config.runtimeToken,
3348
+ apiBaseUrl: this.config.apiUrl,
3270
3349
  });
3271
3350
  this.identity = new AgentIdentity(this.config.agentName, this.config.agentId, this.config.privateKey);
3272
3351
  const loggerConfig = {
@@ -3544,20 +3623,22 @@ class SekuireSDK {
3544
3623
  * task registration/completion can use runtime token if bootstrapped.
3545
3624
  */
3546
3625
  createDelegator(options) {
3547
- const credentials = this.getRuntimeCredentials();
3548
- const delegator = new A2ATaskDelegator({
3626
+ return new A2ATaskDelegator({
3549
3627
  apiUrl: this.config.apiUrl,
3550
3628
  authToken: this.config.apiKey || "",
3551
3629
  workspaceId: this.config.workspaceId,
3552
3630
  agentId: this.config.agentId,
3553
3631
  timeout: options?.timeout,
3554
3632
  pollInterval: options?.pollInterval,
3633
+ maxRetries: options?.maxRetries,
3634
+ retryDelayMs: options?.retryDelayMs,
3635
+ retryBackoffMultiplier: options?.retryBackoffMultiplier,
3555
3636
  policyGateway: this.policyGateway ?? undefined,
3637
+ tokenResolver: () => this.credentialsStore.getRuntimeToken(),
3638
+ onUnauthorized: async () => {
3639
+ await this.credentialsStore.refreshRuntimeToken("A2AClient");
3640
+ },
3556
3641
  });
3557
- if (credentials?.runtimeToken) {
3558
- delegator.setRuntimeToken(credentials.runtimeToken);
3559
- }
3560
- return delegator;
3561
3642
  }
3562
3643
  /**
3563
3644
  * Get the agent ID.
@@ -18350,4 +18431,4 @@ class A2AServer {
18350
18431
  }
18351
18432
  }
18352
18433
 
18353
- export { A2AClient, A2AError, A2AServer, A2ATaskDelegator, SekuireAgent as Agent, AgentIdentity, AnthropicProvider, BaseMemoryStorage, Beacon, CONVEX_FUNCTIONS_TEMPLATE, CONVEX_SCHEMA_TEMPLATE, CloudflareD1Storage, CloudflareKVStorage, ComplianceError, ComplianceMonitor, ContentPolicyError, ConvexStorage, CryptoError, DEFAULT_API_URL, DynamoDBStorage, FileAccessError, GoogleProvider, InMemoryStorage, NetworkComplianceError, NetworkError, OllamaProvider, OpenAIProvider, PolicyClient, PolicyEnforcer, PolicyGateway, PolicyViolationError, PostgresStorage, ProtocolError, RedisStorage, RuntimeCredentialsStore, SQLiteStorage, SekuireAgent$1 as SekuireAgent, SekuireAgentBuilder, SekuireClient, SekuireCrypto, SekuireError, SekuireLogger, SekuireRegistryClient, SekuireSDK, SekuireServer, SekuireSpanExporter, TaskWorker, ToolPatternParser, ToolRegistry, ToolUsageError, TursoStorage, UpstashStorage, builtInTools, calculateSekuireId, createAgent, createBeacon, createDefaultToolRegistry, createDelegationTool, createDelegator, createDiscoveryTool, createLLMProvider, createMemoryStorage, createRegistryClient, createSekuireClient, createSekuireExpressMiddleware, createSekuireFastifyPlugin, createWorker, detectDeploymentUrl, generateKeyPair, getAgent, getAgentConfig, getAgents, getTools$1 as getLegacyTools, getStorageInfo, getSystemPrompt, getTools, getTracer, hasStorage, initTelemetry, listStorageTypes, llm, loadConfig, loadSystemPrompt, loadTools, registerStorage, shutdownTelemetry, tool, tools };
18434
+ export { A2AClient, A2AError, A2AServer, A2ATaskDelegator, SekuireAgent as Agent, AgentIdentity, AnthropicProvider, BaseMemoryStorage, Beacon, CONVEX_FUNCTIONS_TEMPLATE, CONVEX_SCHEMA_TEMPLATE, CloudflareD1Storage, CloudflareKVStorage, ComplianceError, ComplianceMonitor, ContentPolicyError, ConvexStorage, CryptoError, DEFAULT_API_URL, DynamoDBStorage, FileAccessError, GoogleProvider, InMemoryStorage, NetworkComplianceError, NetworkError, OllamaProvider, OpenAIProvider, PolicyClient, PolicyEnforcer, PolicyGateway, PolicyViolationError, PostgresStorage, ProtocolError, RedisStorage, RuntimeCredentialsStore, SQLiteStorage, SekuireAgent$1 as SekuireAgent, SekuireAgentBuilder, SekuireClient, SekuireCrypto, SekuireError, SekuireLogger, SekuireRegistryClient, SekuireSDK, SekuireServer, SekuireSpanExporter, TaskWorker, ToolPatternParser, ToolRegistry, ToolUsageError, TursoStorage, UpstashStorage, applyBootstrapResponse, builtInTools, calculateSekuireId, createAgent, createBeacon, createDefaultToolRegistry, createDelegationTool, createDelegator, createDiscoveryTool, createLLMProvider, createMemoryStorage, createRegistryClient, createSekuireClient, createSekuireExpressMiddleware, createSekuireFastifyPlugin, createWorker, detectDeploymentUrl, generateKeyPair, getAgent, getAgentConfig, getAgents, getTools$1 as getLegacyTools, getStorageInfo, getSystemPrompt, getTools, getTracer, hasStorage, initTelemetry, listStorageTypes, llm, loadConfig, loadSystemPrompt, loadTools, registerStorage, shutdownTelemetry, tool, tools };
package/dist/index.js CHANGED
@@ -93,6 +93,8 @@ class A2AClient {
93
93
  options.deviceFingerprint ||
94
94
  process.env.SEKUIRE_DEVICE_FINGERPRINT ||
95
95
  "sekuire-typescript-sdk";
96
+ this.tokenResolver = options.tokenResolver;
97
+ this.onUnauthorized = options.onUnauthorized;
96
98
  }
97
99
  setRuntimeToken(token) {
98
100
  this.runtimeToken = token;
@@ -102,7 +104,7 @@ class A2AClient {
102
104
  * The API will find an agent with the matching skill and forward the task.
103
105
  */
104
106
  async sendBySkill(request) {
105
- const response = await this.fetch("/a2a/route", {
107
+ const response = await this.fetchTask("/a2a/route", {
106
108
  method: "POST",
107
109
  body: JSON.stringify(request),
108
110
  });
@@ -315,19 +317,37 @@ class A2AClient {
315
317
  });
316
318
  }
317
319
  async fetchTask(path, init) {
320
+ const runtimeToken = this.resolveRuntimeToken();
321
+ const response = await this.doFetchTask(path, init, runtimeToken);
322
+ const usedRuntimeToken = !!runtimeToken && runtimeToken.startsWith("srt_");
323
+ if (response.status === 401 && usedRuntimeToken && this.onUnauthorized) {
324
+ try {
325
+ await this.onUnauthorized();
326
+ }
327
+ catch {
328
+ return response;
329
+ }
330
+ return this.doFetchTask(path, init, this.resolveRuntimeToken());
331
+ }
332
+ return response;
333
+ }
334
+ async doFetchTask(path, init, runtimeToken) {
318
335
  return fetch(`${this.baseUrl}${path}`, {
319
336
  ...init,
320
337
  headers: {
321
338
  "Content-Type": "application/json",
322
- ...this.taskAuthHeaders(),
339
+ ...this.taskAuthHeaders(runtimeToken),
323
340
  ...init.headers,
324
341
  },
325
342
  signal: AbortSignal.timeout(this.timeout),
326
343
  });
327
344
  }
328
- taskAuthHeaders() {
329
- if (this.runtimeToken) {
330
- return { Authorization: `Bearer ${this.runtimeToken}` };
345
+ resolveRuntimeToken() {
346
+ return this.tokenResolver?.() ?? this.runtimeToken;
347
+ }
348
+ taskAuthHeaders(runtimeToken) {
349
+ if (runtimeToken) {
350
+ return { Authorization: `Bearer ${runtimeToken}` };
331
351
  }
332
352
  if (this.isLikelyJwt(this.authToken)) {
333
353
  return { Authorization: `Bearer ${this.authToken}` };
@@ -420,6 +440,8 @@ class A2ATaskDelegator {
420
440
  baseUrl: config.apiUrl,
421
441
  authToken: config.authToken,
422
442
  timeout: this.config.timeout,
443
+ tokenResolver: config.tokenResolver,
444
+ onUnauthorized: config.onUnauthorized,
423
445
  });
424
446
  }
425
447
  setRuntimeToken(token) {
@@ -836,6 +858,121 @@ function detectDeploymentUrl() {
836
858
  return undefined;
837
859
  }
838
860
 
861
+ function applyBootstrapResponse(target, data) {
862
+ target.installationId = data.installation_id;
863
+ target.runtimeToken = data.runtime_token;
864
+ if (data.refresh_token) {
865
+ target.refreshToken = data.refresh_token;
866
+ }
867
+ target.credentialsStore?.update({
868
+ installationId: data.installation_id,
869
+ runtimeToken: data.runtime_token,
870
+ refreshToken: data.refresh_token,
871
+ expiresAt: data.expires_at,
872
+ });
873
+ }
874
+ class RuntimeCredentialsStore {
875
+ constructor(initial) {
876
+ this.inflightRefresh = null;
877
+ if (initial) {
878
+ this.update(initial);
879
+ }
880
+ if (initial?.apiBaseUrl) {
881
+ this.apiBaseUrl = initial.apiBaseUrl;
882
+ }
883
+ }
884
+ setApiBaseUrl(url) {
885
+ this.apiBaseUrl = url;
886
+ }
887
+ update(partial) {
888
+ if (partial.installationId) {
889
+ this.installationId = partial.installationId;
890
+ }
891
+ if (partial.runtimeToken) {
892
+ this.runtimeToken = partial.runtimeToken;
893
+ }
894
+ if (partial.refreshToken) {
895
+ this.refreshToken = partial.refreshToken;
896
+ }
897
+ if (partial.expiresAt !== undefined) {
898
+ this.expiresAt = partial.expiresAt;
899
+ }
900
+ }
901
+ setRuntimeToken(runtimeToken, expiresAt) {
902
+ this.runtimeToken = runtimeToken;
903
+ if (expiresAt !== undefined) {
904
+ this.expiresAt = expiresAt;
905
+ }
906
+ }
907
+ setInstallationId(installationId) {
908
+ this.installationId = installationId;
909
+ }
910
+ setRefreshToken(refreshToken) {
911
+ this.refreshToken = refreshToken;
912
+ }
913
+ getInstallationId() {
914
+ return this.installationId;
915
+ }
916
+ getRuntimeToken() {
917
+ return this.runtimeToken;
918
+ }
919
+ getRefreshToken() {
920
+ return this.refreshToken;
921
+ }
922
+ getExpiresAt() {
923
+ return this.expiresAt;
924
+ }
925
+ getAll() {
926
+ return {
927
+ installationId: this.installationId,
928
+ runtimeToken: this.runtimeToken,
929
+ refreshToken: this.refreshToken,
930
+ expiresAt: this.expiresAt,
931
+ };
932
+ }
933
+ hasRecoveryCredentials() {
934
+ return !!(this.installationId && this.refreshToken);
935
+ }
936
+ hasRuntimeToken() {
937
+ return !!this.runtimeToken;
938
+ }
939
+ async refreshRuntimeToken(caller) {
940
+ if (this.inflightRefresh) {
941
+ return this.inflightRefresh;
942
+ }
943
+ this.inflightRefresh = this.doRefresh(caller).finally(() => {
944
+ this.inflightRefresh = null;
945
+ });
946
+ return this.inflightRefresh;
947
+ }
948
+ async doRefresh(caller) {
949
+ const installationId = this.installationId;
950
+ const refreshToken = this.refreshToken;
951
+ const apiBaseUrl = this.apiBaseUrl;
952
+ if (!installationId || !refreshToken) {
953
+ throw new Error("Cannot refresh token - missing installation ID or refresh token");
954
+ }
955
+ if (!apiBaseUrl) {
956
+ throw new Error("Cannot refresh token - missing API base URL");
957
+ }
958
+ const response = await fetch(`${apiBaseUrl}/api/v1/installations/${installationId}/refresh`, {
959
+ method: "POST",
960
+ headers: { "Content-Type": "application/json" },
961
+ body: JSON.stringify({ refresh_token: refreshToken }),
962
+ });
963
+ if (!response.ok) {
964
+ const body = await response.text();
965
+ throw new Error(`Token refresh failed: ${response.status} - ${body}`);
966
+ }
967
+ const data = await response.json();
968
+ this.runtimeToken = data.runtime_token;
969
+ if (data.expires_at !== undefined) {
970
+ this.expiresAt = data.expires_at;
971
+ }
972
+ console.log(`[${caller || "CredentialsStore"}] Runtime token refreshed successfully`);
973
+ }
974
+ }
975
+
839
976
  /**
840
977
  * Sekuire Beacon - Deployment Registration & Heartbeat
841
978
  *
@@ -879,6 +1016,7 @@ class Beacon {
879
1016
  this.credentialsStore = config.credentialsStore;
880
1017
  this.policyGateway = config.policyGateway;
881
1018
  if (this.credentialsStore) {
1019
+ this.credentialsStore.setApiBaseUrl(this.config.apiBaseUrl);
882
1020
  this.credentialsStore.update({
883
1021
  installationId: resolvedInstallationId,
884
1022
  refreshToken: resolvedRefreshToken,
@@ -1066,6 +1204,16 @@ class Beacon {
1066
1204
  }
1067
1205
  // Refresh to get a new runtime token
1068
1206
  try {
1207
+ if (this.credentialsStore) {
1208
+ this.credentialsStore.update({ installationId, refreshToken });
1209
+ await this.credentialsStore.refreshRuntimeToken("Beacon");
1210
+ this.installationId = installationId;
1211
+ this.runtimeToken = this.credentialsStore.getRuntimeToken() ?? null;
1212
+ this.refreshToken = refreshToken;
1213
+ this.expiresAt = this.credentialsStore.getExpiresAt() ?? null;
1214
+ console.log('[Beacon] Credentials recovered via refresh token');
1215
+ return true;
1216
+ }
1069
1217
  const response = await fetch(`${this.config.apiBaseUrl}/api/v1/installations/${installationId}/refresh`, {
1070
1218
  method: 'POST',
1071
1219
  headers: {
@@ -1083,14 +1231,8 @@ class Beacon {
1083
1231
  const data = await response.json();
1084
1232
  this.installationId = installationId;
1085
1233
  this.runtimeToken = data.runtime_token;
1086
- this.refreshToken = refreshToken; // Refresh token is stable
1234
+ this.refreshToken = refreshToken;
1087
1235
  this.expiresAt = data.expires_at || null;
1088
- this.credentialsStore?.update({
1089
- installationId,
1090
- runtimeToken: data.runtime_token,
1091
- refreshToken,
1092
- expiresAt: data.expires_at,
1093
- });
1094
1236
  console.log('[Beacon] Credentials recovered via refresh token');
1095
1237
  return true;
1096
1238
  }
@@ -1200,9 +1342,7 @@ class Beacon {
1200
1342
  return false;
1201
1343
  }
1202
1344
  const data = await response.json();
1203
- this.installationId = data.installation_id;
1204
- this.runtimeToken = data.runtime_token;
1205
- this.refreshToken = data.refresh_token;
1345
+ applyBootstrapResponse(this, data);
1206
1346
  console.log(`[Beacon] Recovery bootstrap successful, installation ID: ${this.installationId}`);
1207
1347
  return true;
1208
1348
  }
@@ -1239,16 +1379,8 @@ class Beacon {
1239
1379
  throw new Error(`Bootstrap failed: ${response.status} ${response.statusText} - ${body}`);
1240
1380
  }
1241
1381
  const data = await response.json();
1242
- this.installationId = data.installation_id;
1243
- this.runtimeToken = data.runtime_token;
1244
- this.refreshToken = data.refresh_token;
1382
+ applyBootstrapResponse(this, data);
1245
1383
  this.expiresAt = data.expires_at || null;
1246
- this.credentialsStore?.update({
1247
- installationId: data.installation_id,
1248
- runtimeToken: data.runtime_token,
1249
- refreshToken: data.refresh_token,
1250
- expiresAt: data.expires_at,
1251
- });
1252
1384
  }
1253
1385
  /**
1254
1386
  * Send heartbeat (lease renewal) to Sekuire
@@ -1316,6 +1448,11 @@ class Beacon {
1316
1448
  * Refresh the runtime token using the refresh token
1317
1449
  */
1318
1450
  async refreshRuntimeToken() {
1451
+ if (this.credentialsStore) {
1452
+ await this.credentialsStore.refreshRuntimeToken("Beacon");
1453
+ this.runtimeToken = this.credentialsStore.getRuntimeToken() ?? null;
1454
+ return;
1455
+ }
1319
1456
  const installationId = this.getInstallationId();
1320
1457
  const refreshToken = this.getRefreshToken();
1321
1458
  if (!installationId || !refreshToken) {
@@ -1336,7 +1473,6 @@ class Beacon {
1336
1473
  }
1337
1474
  const data = await response.json();
1338
1475
  this.runtimeToken = data.runtime_token;
1339
- this.credentialsStore?.setRuntimeToken(data.runtime_token, data.expires_at);
1340
1476
  console.log('[Beacon] Runtime token refreshed successfully');
1341
1477
  }
1342
1478
  /**
@@ -2170,66 +2306,6 @@ class PolicyGateway {
2170
2306
  }
2171
2307
  }
2172
2308
 
2173
- class RuntimeCredentialsStore {
2174
- constructor(initial) {
2175
- if (initial) {
2176
- this.update(initial);
2177
- }
2178
- }
2179
- update(partial) {
2180
- if (partial.installationId) {
2181
- this.installationId = partial.installationId;
2182
- }
2183
- if (partial.runtimeToken) {
2184
- this.runtimeToken = partial.runtimeToken;
2185
- }
2186
- if (partial.refreshToken) {
2187
- this.refreshToken = partial.refreshToken;
2188
- }
2189
- if (partial.expiresAt !== undefined) {
2190
- this.expiresAt = partial.expiresAt;
2191
- }
2192
- }
2193
- setRuntimeToken(runtimeToken, expiresAt) {
2194
- this.runtimeToken = runtimeToken;
2195
- if (expiresAt !== undefined) {
2196
- this.expiresAt = expiresAt;
2197
- }
2198
- }
2199
- setInstallationId(installationId) {
2200
- this.installationId = installationId;
2201
- }
2202
- setRefreshToken(refreshToken) {
2203
- this.refreshToken = refreshToken;
2204
- }
2205
- getInstallationId() {
2206
- return this.installationId;
2207
- }
2208
- getRuntimeToken() {
2209
- return this.runtimeToken;
2210
- }
2211
- getRefreshToken() {
2212
- return this.refreshToken;
2213
- }
2214
- getExpiresAt() {
2215
- return this.expiresAt;
2216
- }
2217
- getAll() {
2218
- return {
2219
- installationId: this.installationId,
2220
- runtimeToken: this.runtimeToken,
2221
- refreshToken: this.refreshToken,
2222
- expiresAt: this.expiresAt,
2223
- };
2224
- }
2225
- hasRecoveryCredentials() {
2226
- return !!(this.installationId && this.refreshToken);
2227
- }
2228
- hasRuntimeToken() {
2229
- return !!this.runtimeToken;
2230
- }
2231
- }
2232
-
2233
2309
  function getDefaultExportFromCjs (x) {
2234
2310
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
2235
2311
  }
@@ -2782,6 +2858,7 @@ class TaskWorker {
2782
2858
  this.installationId = resolvedInstallationId || null;
2783
2859
  this.refreshToken = resolvedRefreshToken || null;
2784
2860
  if (this.credentialsStore) {
2861
+ this.credentialsStore.setApiBaseUrl(this.config.apiBaseUrl);
2785
2862
  this.credentialsStore.update({
2786
2863
  installationId: resolvedInstallationId,
2787
2864
  refreshToken: resolvedRefreshToken,
@@ -2854,6 +2931,17 @@ class TaskWorker {
2854
2931
  return false;
2855
2932
  }
2856
2933
  try {
2934
+ if (this.credentialsStore) {
2935
+ this.credentialsStore.update({ installationId, refreshToken });
2936
+ await this.credentialsStore.refreshRuntimeToken("Worker");
2937
+ this.installationId = installationId;
2938
+ this.runtimeToken = this.credentialsStore.getRuntimeToken() ?? null;
2939
+ this.refreshToken = refreshToken;
2940
+ const expiresAt = this.credentialsStore.getExpiresAt();
2941
+ this.expiresAt = expiresAt ? new Date(expiresAt).getTime() : null;
2942
+ console.log(`[Worker] Credentials recovered for installation: ${installationId}`);
2943
+ return true;
2944
+ }
2857
2945
  const response = await fetch(`${this.config.apiBaseUrl}/api/v1/installations/${installationId}/refresh`, {
2858
2946
  method: "POST",
2859
2947
  headers: {
@@ -2873,12 +2961,6 @@ class TaskWorker {
2873
2961
  this.runtimeToken = data.runtime_token;
2874
2962
  this.refreshToken = refreshToken;
2875
2963
  this.expiresAt = data.expires_at ? new Date(data.expires_at).getTime() : null;
2876
- this.credentialsStore?.update({
2877
- installationId,
2878
- runtimeToken: data.runtime_token,
2879
- refreshToken,
2880
- expiresAt: data.expires_at,
2881
- });
2882
2964
  console.log(`[Worker] Credentials recovered for installation: ${installationId}`);
2883
2965
  return true;
2884
2966
  }
@@ -3121,18 +3203,10 @@ class TaskWorker {
3121
3203
  throw new Error(`Bootstrap failed: ${response.status} - ${errorText}`);
3122
3204
  }
3123
3205
  const data = await response.json();
3124
- this.installationId = data.installation_id;
3125
- this.runtimeToken = data.runtime_token;
3126
- this.refreshToken = data.refresh_token;
3206
+ applyBootstrapResponse(this, data);
3127
3207
  this.expiresAt = data.expires_at
3128
3208
  ? new Date(data.expires_at).getTime()
3129
3209
  : null;
3130
- this.credentialsStore?.update({
3131
- installationId: data.installation_id,
3132
- runtimeToken: data.runtime_token,
3133
- refreshToken: data.refresh_token,
3134
- expiresAt: data.expires_at,
3135
- });
3136
3210
  console.log(`[Worker] Bootstrapped installation: ${this.installationId}`);
3137
3211
  }
3138
3212
  catch (e) {
@@ -3205,6 +3279,11 @@ class TaskWorker {
3205
3279
  * Refresh the runtime token using the refresh token
3206
3280
  */
3207
3281
  async refreshRuntimeToken() {
3282
+ if (this.credentialsStore) {
3283
+ await this.credentialsStore.refreshRuntimeToken("Worker");
3284
+ this.runtimeToken = this.credentialsStore.getRuntimeToken() ?? null;
3285
+ return;
3286
+ }
3208
3287
  const installationId = this.getInstallationId();
3209
3288
  const refreshToken = this.getRefreshToken();
3210
3289
  if (!installationId || !refreshToken) {
@@ -3225,7 +3304,6 @@ class TaskWorker {
3225
3304
  }
3226
3305
  const data = await response.json();
3227
3306
  this.runtimeToken = data.runtime_token;
3228
- this.credentialsStore?.setRuntimeToken(data.runtime_token, data.expires_at);
3229
3307
  console.log("[Worker] Runtime token refreshed successfully");
3230
3308
  }
3231
3309
  getInstallationId() {
@@ -3291,6 +3369,7 @@ class SekuireSDK {
3291
3369
  installationId: this.config.installationId,
3292
3370
  refreshToken: this.config.refreshToken,
3293
3371
  runtimeToken: this.config.runtimeToken,
3372
+ apiBaseUrl: this.config.apiUrl,
3294
3373
  });
3295
3374
  this.identity = new AgentIdentity(this.config.agentName, this.config.agentId, this.config.privateKey);
3296
3375
  const loggerConfig = {
@@ -3568,20 +3647,22 @@ class SekuireSDK {
3568
3647
  * task registration/completion can use runtime token if bootstrapped.
3569
3648
  */
3570
3649
  createDelegator(options) {
3571
- const credentials = this.getRuntimeCredentials();
3572
- const delegator = new A2ATaskDelegator({
3650
+ return new A2ATaskDelegator({
3573
3651
  apiUrl: this.config.apiUrl,
3574
3652
  authToken: this.config.apiKey || "",
3575
3653
  workspaceId: this.config.workspaceId,
3576
3654
  agentId: this.config.agentId,
3577
3655
  timeout: options?.timeout,
3578
3656
  pollInterval: options?.pollInterval,
3657
+ maxRetries: options?.maxRetries,
3658
+ retryDelayMs: options?.retryDelayMs,
3659
+ retryBackoffMultiplier: options?.retryBackoffMultiplier,
3579
3660
  policyGateway: this.policyGateway ?? undefined,
3661
+ tokenResolver: () => this.credentialsStore.getRuntimeToken(),
3662
+ onUnauthorized: async () => {
3663
+ await this.credentialsStore.refreshRuntimeToken("A2AClient");
3664
+ },
3580
3665
  });
3581
- if (credentials?.runtimeToken) {
3582
- delegator.setRuntimeToken(credentials.runtimeToken);
3583
- }
3584
- return delegator;
3585
3666
  }
3586
3667
  /**
3587
3668
  * Get the agent ID.
@@ -18426,6 +18507,7 @@ exports.ToolRegistry = ToolRegistry;
18426
18507
  exports.ToolUsageError = ToolUsageError;
18427
18508
  exports.TursoStorage = TursoStorage;
18428
18509
  exports.UpstashStorage = UpstashStorage;
18510
+ exports.applyBootstrapResponse = applyBootstrapResponse;
18429
18511
  exports.builtInTools = builtInTools;
18430
18512
  exports.calculateSekuireId = calculateSekuireId;
18431
18513
  exports.createAgent = createAgent;
@@ -4,12 +4,30 @@ export interface RuntimeCredentials {
4
4
  refreshToken?: string;
5
5
  expiresAt?: string;
6
6
  }
7
+ export interface BootstrapResponseData {
8
+ installation_id: string;
9
+ runtime_token: string;
10
+ refresh_token?: string;
11
+ expires_at: string;
12
+ }
13
+ export interface BootstrapTarget {
14
+ installationId: string | null;
15
+ runtimeToken: string | null;
16
+ refreshToken: string | null;
17
+ credentialsStore?: RuntimeCredentialsStore | null;
18
+ }
19
+ export declare function applyBootstrapResponse(target: BootstrapTarget, data: BootstrapResponseData): void;
7
20
  export declare class RuntimeCredentialsStore {
8
21
  private installationId?;
9
22
  private runtimeToken?;
10
23
  private refreshToken?;
11
24
  private expiresAt?;
12
- constructor(initial?: RuntimeCredentials);
25
+ private apiBaseUrl?;
26
+ private inflightRefresh;
27
+ constructor(initial?: RuntimeCredentials & {
28
+ apiBaseUrl?: string;
29
+ });
30
+ setApiBaseUrl(url: string): void;
13
31
  update(partial: RuntimeCredentials): void;
14
32
  setRuntimeToken(runtimeToken: string, expiresAt?: string): void;
15
33
  setInstallationId(installationId: string): void;
@@ -21,4 +39,6 @@ export declare class RuntimeCredentialsStore {
21
39
  getAll(): RuntimeCredentials;
22
40
  hasRecoveryCredentials(): boolean;
23
41
  hasRuntimeToken(): boolean;
42
+ refreshRuntimeToken(caller?: string): Promise<void>;
43
+ private doRefresh;
24
44
  }
package/dist/sdk.d.ts CHANGED
@@ -205,6 +205,9 @@ export declare class SekuireSDK {
205
205
  createDelegator(options?: {
206
206
  timeout?: number;
207
207
  pollInterval?: number;
208
+ maxRetries?: number;
209
+ retryDelayMs?: number;
210
+ retryBackoffMultiplier?: number;
208
211
  }): A2ATaskDelegator;
209
212
  /**
210
213
  * Get the agent ID.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sekuire/sdk",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
4
4
  "description": "Sekuire Identity Protocol SDK for TypeScript/JavaScript",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",