@agentuity/core 2.0.0-beta.0 → 2.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 (94) hide show
  1. package/dist/deprecation.d.ts +20 -0
  2. package/dist/deprecation.d.ts.map +1 -0
  3. package/dist/deprecation.js +102 -0
  4. package/dist/deprecation.js.map +1 -0
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +2 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/services/api.d.ts.map +1 -1
  10. package/dist/services/api.js +13 -5
  11. package/dist/services/api.js.map +1 -1
  12. package/dist/services/oauth/flow.d.ts +82 -0
  13. package/dist/services/oauth/flow.d.ts.map +1 -0
  14. package/dist/services/oauth/flow.js +308 -0
  15. package/dist/services/oauth/flow.js.map +1 -0
  16. package/dist/services/oauth/index.d.ts +2 -0
  17. package/dist/services/oauth/index.d.ts.map +1 -1
  18. package/dist/services/oauth/index.js +2 -0
  19. package/dist/services/oauth/index.js.map +1 -1
  20. package/dist/services/oauth/token-storage.d.ts +109 -0
  21. package/dist/services/oauth/token-storage.d.ts.map +1 -0
  22. package/dist/services/oauth/token-storage.js +140 -0
  23. package/dist/services/oauth/token-storage.js.map +1 -0
  24. package/dist/services/oauth/types.d.ts +63 -0
  25. package/dist/services/oauth/types.d.ts.map +1 -1
  26. package/dist/services/oauth/types.js +74 -0
  27. package/dist/services/oauth/types.js.map +1 -1
  28. package/dist/services/project/get.d.ts +12 -0
  29. package/dist/services/project/get.d.ts.map +1 -1
  30. package/dist/services/project/get.js +9 -0
  31. package/dist/services/project/get.js.map +1 -1
  32. package/dist/services/sandbox/client.d.ts +201 -1
  33. package/dist/services/sandbox/client.d.ts.map +1 -1
  34. package/dist/services/sandbox/client.js +276 -15
  35. package/dist/services/sandbox/client.js.map +1 -1
  36. package/dist/services/sandbox/create.d.ts +5 -0
  37. package/dist/services/sandbox/create.d.ts.map +1 -1
  38. package/dist/services/sandbox/create.js +11 -0
  39. package/dist/services/sandbox/create.js.map +1 -1
  40. package/dist/services/sandbox/execute.d.ts.map +1 -1
  41. package/dist/services/sandbox/execute.js +22 -11
  42. package/dist/services/sandbox/execute.js.map +1 -1
  43. package/dist/services/sandbox/execution.d.ts +1 -0
  44. package/dist/services/sandbox/execution.d.ts.map +1 -1
  45. package/dist/services/sandbox/execution.js +4 -2
  46. package/dist/services/sandbox/execution.js.map +1 -1
  47. package/dist/services/sandbox/files.js +1 -1
  48. package/dist/services/sandbox/files.js.map +1 -1
  49. package/dist/services/sandbox/index.d.ts +3 -1
  50. package/dist/services/sandbox/index.d.ts.map +1 -1
  51. package/dist/services/sandbox/index.js +1 -0
  52. package/dist/services/sandbox/index.js.map +1 -1
  53. package/dist/services/sandbox/job.d.ts +227 -0
  54. package/dist/services/sandbox/job.d.ts.map +1 -0
  55. package/dist/services/sandbox/job.js +109 -0
  56. package/dist/services/sandbox/job.js.map +1 -0
  57. package/dist/services/sandbox/run.d.ts +1 -0
  58. package/dist/services/sandbox/run.d.ts.map +1 -1
  59. package/dist/services/sandbox/run.js +83 -30
  60. package/dist/services/sandbox/run.js.map +1 -1
  61. package/dist/services/sandbox/types.d.ts +45 -0
  62. package/dist/services/sandbox/types.d.ts.map +1 -1
  63. package/dist/services/sandbox/types.js +42 -0
  64. package/dist/services/sandbox/types.js.map +1 -1
  65. package/dist/services/sandbox/util.d.ts +1 -0
  66. package/dist/services/sandbox/util.d.ts.map +1 -1
  67. package/dist/services/sandbox/util.js +1 -0
  68. package/dist/services/sandbox/util.js.map +1 -1
  69. package/dist/services/schedule/service.d.ts +5 -0
  70. package/dist/services/schedule/service.d.ts.map +1 -1
  71. package/dist/services/schedule/service.js +16 -0
  72. package/dist/services/schedule/service.js.map +1 -1
  73. package/dist/services/schedule/types.d.ts +1 -0
  74. package/dist/services/schedule/types.d.ts.map +1 -1
  75. package/package.json +2 -2
  76. package/src/deprecation.ts +120 -0
  77. package/src/index.ts +3 -0
  78. package/src/services/api.ts +15 -5
  79. package/src/services/oauth/flow.ts +356 -0
  80. package/src/services/oauth/index.ts +2 -0
  81. package/src/services/oauth/token-storage.ts +220 -0
  82. package/src/services/oauth/types.ts +95 -0
  83. package/src/services/project/get.ts +9 -0
  84. package/src/services/sandbox/client.ts +446 -16
  85. package/src/services/sandbox/create.ts +13 -0
  86. package/src/services/sandbox/execute.ts +26 -12
  87. package/src/services/sandbox/execution.ts +5 -2
  88. package/src/services/sandbox/files.ts +1 -1
  89. package/src/services/sandbox/index.ts +20 -0
  90. package/src/services/sandbox/job.ts +161 -0
  91. package/src/services/sandbox/run.ts +129 -34
  92. package/src/services/sandbox/types.ts +50 -0
  93. package/src/services/sandbox/util.ts +1 -0
  94. package/src/services/schedule/service.ts +20 -0
@@ -0,0 +1,308 @@
1
+ import { getEnv } from "../env.js";
2
+ import { OAuthResponseError } from "./util.js";
3
+ import { OAuthTokenResponseSchema, OAuthUserInfoSchema } from "./types.js";
4
+ const DEFAULT_TIMEOUT_MS = 30_000;
5
+ /**
6
+ * Resolve OAuth configuration by merging explicit config with environment variables.
7
+ * Priority: explicit config > env vars > issuer-derived URLs > defaults.
8
+ */
9
+ function resolveConfig(config) {
10
+ const clientId = config?.clientId ?? getEnv('OAUTH_CLIENT_ID');
11
+ const clientSecret = config?.clientSecret ?? getEnv('OAUTH_CLIENT_SECRET');
12
+ const issuer = config?.issuer ?? getEnv('OAUTH_ISSUER');
13
+ const authorizeUrl = config?.authorizeUrl ??
14
+ getEnv('OAUTH_AUTHORIZE_URL') ??
15
+ (issuer ? `${issuer}/authorize` : undefined);
16
+ const tokenUrl = config?.tokenUrl ??
17
+ getEnv('OAUTH_TOKEN_URL') ??
18
+ (issuer ? `${issuer}/oauth/token` : undefined);
19
+ const userinfoUrl = config?.userinfoUrl ??
20
+ getEnv('OAUTH_USERINFO_URL') ??
21
+ (issuer ? `${issuer}/userinfo` : undefined);
22
+ const revokeUrl = config?.revokeUrl ?? getEnv('OAUTH_REVOKE_URL') ?? (issuer ? `${issuer}/revoke` : undefined);
23
+ const endSessionUrl = config?.endSessionUrl ??
24
+ getEnv('OAUTH_END_SESSION_URL') ??
25
+ (issuer ? `${issuer}/end_session` : undefined);
26
+ const scopes = config?.scopes ?? getEnv('OAUTH_SCOPES') ?? 'openid profile email';
27
+ const prompt = config?.prompt;
28
+ return {
29
+ clientId,
30
+ clientSecret,
31
+ issuer,
32
+ authorizeUrl,
33
+ tokenUrl,
34
+ userinfoUrl,
35
+ revokeUrl,
36
+ endSessionUrl,
37
+ scopes,
38
+ prompt,
39
+ };
40
+ }
41
+ /**
42
+ * Build an OAuth 2.0 authorization URL for redirecting the user to the OIDC provider.
43
+ *
44
+ * @param redirectUri - The callback URL the provider will redirect to after authentication
45
+ * @param config - Optional OAuth configuration. Falls back to environment variables.
46
+ * @returns The full authorization URL to redirect the user to
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * // Uses OAUTH_CLIENT_ID, OAUTH_AUTHORIZE_URL (or OAUTH_ISSUER) from env
51
+ * const url = buildAuthorizeUrl('http://localhost:3500/api/oauth/login');
52
+ *
53
+ * // Or with explicit config
54
+ * const url = buildAuthorizeUrl('http://localhost:3500/api/oauth/login', {
55
+ * issuer: 'https://auth.agentuity.cloud',
56
+ * clientId: 'my-client-id',
57
+ * });
58
+ * ```
59
+ */
60
+ export function buildAuthorizeUrl(redirectUri, config) {
61
+ const resolved = resolveConfig(config);
62
+ if (!resolved.authorizeUrl) {
63
+ throw new OAuthResponseError({
64
+ message: 'No authorize URL configured. Set OAUTH_AUTHORIZE_URL or OAUTH_ISSUER environment variable.',
65
+ });
66
+ }
67
+ if (!resolved.clientId) {
68
+ throw new OAuthResponseError({
69
+ message: 'No client ID configured. Set OAUTH_CLIENT_ID environment variable.',
70
+ });
71
+ }
72
+ const params = new URLSearchParams({
73
+ client_id: resolved.clientId,
74
+ redirect_uri: redirectUri,
75
+ response_type: 'code',
76
+ scope: resolved.scopes,
77
+ });
78
+ if (resolved.prompt) {
79
+ params.set('prompt', resolved.prompt);
80
+ }
81
+ return `${resolved.authorizeUrl}?${params.toString()}`;
82
+ }
83
+ /**
84
+ * Exchange an authorization code for an access token.
85
+ *
86
+ * @param code - The authorization code received from the OAuth callback
87
+ * @param redirectUri - The same redirect URI used in the authorization request
88
+ * @param config - Optional OAuth configuration. Falls back to environment variables.
89
+ * @returns The token response including access_token, and optionally refresh_token, id_token, etc.
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * const token = await exchangeToken(code, 'http://localhost:3500/api/oauth/login');
94
+ * console.log(token.access_token);
95
+ * ```
96
+ */
97
+ export async function exchangeToken(code, redirectUri, config) {
98
+ const resolved = resolveConfig(config);
99
+ if (!resolved.tokenUrl) {
100
+ throw new OAuthResponseError({
101
+ message: 'No token URL configured. Set OAUTH_TOKEN_URL or OAUTH_ISSUER environment variable.',
102
+ });
103
+ }
104
+ if (!resolved.clientId) {
105
+ throw new OAuthResponseError({
106
+ message: 'No client ID configured. Set OAUTH_CLIENT_ID environment variable.',
107
+ });
108
+ }
109
+ if (!resolved.clientSecret) {
110
+ throw new OAuthResponseError({
111
+ message: 'No client secret configured. Set OAUTH_CLIENT_SECRET environment variable.',
112
+ });
113
+ }
114
+ let response;
115
+ try {
116
+ response = await fetch(resolved.tokenUrl, {
117
+ method: 'POST',
118
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
119
+ body: new URLSearchParams({
120
+ grant_type: 'authorization_code',
121
+ code,
122
+ redirect_uri: redirectUri,
123
+ client_id: resolved.clientId,
124
+ client_secret: resolved.clientSecret,
125
+ }),
126
+ signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),
127
+ });
128
+ }
129
+ catch (err) {
130
+ if (err instanceof DOMException && err.name === 'TimeoutError') {
131
+ throw new OAuthResponseError({
132
+ message: `Token exchange timed out after ${DEFAULT_TIMEOUT_MS}ms`,
133
+ });
134
+ }
135
+ throw err;
136
+ }
137
+ if (!response.ok) {
138
+ const error = await response.text();
139
+ throw new OAuthResponseError({
140
+ message: `Token exchange failed (${response.status}): ${error}`,
141
+ });
142
+ }
143
+ const data = await response.json();
144
+ return OAuthTokenResponseSchema.parse(data);
145
+ }
146
+ /**
147
+ * Refresh an access token using a refresh token.
148
+ *
149
+ * @param refreshTokenValue - The refresh token obtained from a previous token exchange
150
+ * @param config - Optional OAuth configuration. Falls back to environment variables.
151
+ * @returns The token response including a new access_token, and optionally a new refresh_token
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * const newToken = await refreshToken(previousToken.refresh_token!);
156
+ * console.log(newToken.access_token);
157
+ * ```
158
+ */
159
+ export async function refreshToken(refreshTokenValue, config) {
160
+ const resolved = resolveConfig(config);
161
+ if (!resolved.tokenUrl) {
162
+ throw new OAuthResponseError({
163
+ message: 'No token URL configured. Set OAUTH_TOKEN_URL or OAUTH_ISSUER environment variable.',
164
+ });
165
+ }
166
+ if (!resolved.clientId) {
167
+ throw new OAuthResponseError({
168
+ message: 'No client ID configured. Set OAUTH_CLIENT_ID environment variable.',
169
+ });
170
+ }
171
+ const params = new URLSearchParams({
172
+ grant_type: 'refresh_token',
173
+ refresh_token: refreshTokenValue,
174
+ client_id: resolved.clientId,
175
+ });
176
+ if (resolved.clientSecret) {
177
+ params.set('client_secret', resolved.clientSecret);
178
+ }
179
+ let response;
180
+ try {
181
+ response = await fetch(resolved.tokenUrl, {
182
+ method: 'POST',
183
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
184
+ body: params,
185
+ signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),
186
+ });
187
+ }
188
+ catch (err) {
189
+ if (err instanceof DOMException && err.name === 'TimeoutError') {
190
+ throw new OAuthResponseError({
191
+ message: `Token refresh timed out after ${DEFAULT_TIMEOUT_MS}ms`,
192
+ });
193
+ }
194
+ throw err;
195
+ }
196
+ if (!response.ok) {
197
+ const error = await response.text();
198
+ throw new OAuthResponseError({
199
+ message: `Token refresh failed (${response.status}): ${error}`,
200
+ });
201
+ }
202
+ const data = await response.json();
203
+ return OAuthTokenResponseSchema.parse(data);
204
+ }
205
+ /**
206
+ * Revoke an OAuth token (access token or refresh token) to log the user out.
207
+ *
208
+ * Calls the token revocation endpoint (RFC 7009). The server will invalidate
209
+ * the token so it can no longer be used. Per the spec, the endpoint returns
210
+ * a success response even if the token was already invalid.
211
+ *
212
+ * @param token - The access token or refresh token to revoke
213
+ * @param config - Optional OAuth configuration. Falls back to environment variables.
214
+ *
215
+ * @example
216
+ * ```typescript
217
+ * // Revoke the refresh token to fully log out
218
+ * await logout(token.refresh_token!);
219
+ * ```
220
+ */
221
+ export async function logout(token, config) {
222
+ const resolved = resolveConfig(config);
223
+ if (!resolved.revokeUrl) {
224
+ throw new OAuthResponseError({
225
+ message: 'No revoke URL configured. Set OAUTH_REVOKE_URL or OAUTH_ISSUER environment variable.',
226
+ });
227
+ }
228
+ if (!resolved.clientId) {
229
+ throw new OAuthResponseError({
230
+ message: 'No client ID configured. Set OAUTH_CLIENT_ID environment variable.',
231
+ });
232
+ }
233
+ const params = new URLSearchParams({
234
+ token,
235
+ client_id: resolved.clientId,
236
+ });
237
+ if (resolved.clientSecret) {
238
+ params.set('client_secret', resolved.clientSecret);
239
+ }
240
+ let response;
241
+ try {
242
+ response = await fetch(resolved.revokeUrl, {
243
+ method: 'POST',
244
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
245
+ body: params,
246
+ signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),
247
+ });
248
+ }
249
+ catch (err) {
250
+ if (err instanceof DOMException && err.name === 'TimeoutError') {
251
+ throw new OAuthResponseError({
252
+ message: `Token revocation timed out after ${DEFAULT_TIMEOUT_MS}ms`,
253
+ });
254
+ }
255
+ throw err;
256
+ }
257
+ if (!response.ok) {
258
+ const error = await response.text();
259
+ throw new OAuthResponseError({
260
+ message: `Token revocation failed (${response.status}): ${error}`,
261
+ });
262
+ }
263
+ }
264
+ /**
265
+ * Fetch user information from the OIDC userinfo endpoint using an access token.
266
+ *
267
+ * @param accessToken - The access token obtained from the token exchange
268
+ * @param config - Optional OAuth configuration. Falls back to environment variables.
269
+ * @returns The user info including sub, name, email, and any additional claims
270
+ *
271
+ * @example
272
+ * ```typescript
273
+ * const user = await fetchUserInfo(token.access_token);
274
+ * console.log(user.name, user.email);
275
+ * ```
276
+ */
277
+ export async function fetchUserInfo(accessToken, config) {
278
+ const resolved = resolveConfig(config);
279
+ if (!resolved.userinfoUrl) {
280
+ throw new OAuthResponseError({
281
+ message: 'No userinfo URL configured. Set OAUTH_USERINFO_URL or OAUTH_ISSUER environment variable.',
282
+ });
283
+ }
284
+ let response;
285
+ try {
286
+ response = await fetch(resolved.userinfoUrl, {
287
+ headers: { Authorization: `Bearer ${accessToken}` },
288
+ signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),
289
+ });
290
+ }
291
+ catch (err) {
292
+ if (err instanceof DOMException && err.name === 'TimeoutError') {
293
+ throw new OAuthResponseError({
294
+ message: `Userinfo request timed out after ${DEFAULT_TIMEOUT_MS}ms`,
295
+ });
296
+ }
297
+ throw err;
298
+ }
299
+ if (!response.ok) {
300
+ const error = await response.text();
301
+ throw new OAuthResponseError({
302
+ message: `Failed to fetch user info (${response.status}): ${error}`,
303
+ });
304
+ }
305
+ const data = await response.json();
306
+ return OAuthUserInfoSchema.parse(data);
307
+ }
308
+ //# sourceMappingURL=flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow.js","sourceRoot":"","sources":["../../../src/services/oauth/flow.ts"],"names":[],"mappings":"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"}
@@ -6,4 +6,6 @@ export * from './scopes.ts';
6
6
  export * from './members.ts';
7
7
  export * from './keys.ts';
8
8
  export * from './util.ts';
9
+ export * from './flow.ts';
10
+ export * from './token-storage.ts';
9
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/oauth/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/oauth/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,oBAAoB,CAAC"}
@@ -6,4 +6,6 @@ export * from "./scopes.js";
6
6
  export * from "./members.js";
7
7
  export * from "./keys.js";
8
8
  export * from "./util.js";
9
+ export * from "./flow.js";
10
+ export * from "./token-storage.js";
9
11
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/oauth/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/oauth/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,109 @@
1
+ import type { KeyValueStorage } from '../keyvalue/service.ts';
2
+ import type { OAuthFlowConfig, OAuthTokenResponse, StoredToken } from './types.ts';
3
+ /**
4
+ * Check whether a stored token's access token has expired.
5
+ *
6
+ * @param token - The stored token to check
7
+ * @returns true if the token has an expires_at timestamp that is in the past
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const token = await storage.get('user:123');
12
+ * if (token && isTokenExpired(token)) {
13
+ * // Token is expired and auto-refresh wasn't available
14
+ * }
15
+ * ```
16
+ */
17
+ export declare function isTokenExpired(token: StoredToken): boolean;
18
+ /**
19
+ * Options for configuring a TokenStorage instance.
20
+ */
21
+ export interface TokenStorageOptions {
22
+ /**
23
+ * OAuth configuration for auto-refresh and token revocation.
24
+ * If not provided, auto-refresh on get() and server-side revocation on invalidate() are disabled.
25
+ */
26
+ config?: OAuthFlowConfig;
27
+ /**
28
+ * KV namespace for storing tokens. Defaults to 'oauth-tokens'.
29
+ */
30
+ namespace?: string;
31
+ /**
32
+ * Key prefix prepended to all storage keys.
33
+ * Useful for scoping tokens by application or tenant.
34
+ */
35
+ prefix?: string;
36
+ }
37
+ /**
38
+ * Interface for storing, retrieving, and invalidating OAuth tokens.
39
+ *
40
+ * Implementations handle persistence and may support automatic token refresh
41
+ * on retrieval and server-side revocation on invalidation.
42
+ */
43
+ export interface TokenStorage {
44
+ /**
45
+ * Retrieve a stored token by key.
46
+ *
47
+ * If the token is expired and a refresh_token is available (and config is provided),
48
+ * the token is automatically refreshed, stored, and the new token is returned.
49
+ * If auto-refresh fails, the expired token is returned so the caller can decide
50
+ * how to handle it (check with {@link isTokenExpired}).
51
+ *
52
+ * @param key - The storage key (e.g. a user ID or session ID)
53
+ * @returns The stored token, or null if no token exists for the key
54
+ */
55
+ get(key: string): Promise<StoredToken | null>;
56
+ /**
57
+ * Store a token response from a token exchange or refresh.
58
+ *
59
+ * Automatically computes `expires_at` from `expires_in` if present.
60
+ *
61
+ * @param key - The storage key (e.g. a user ID or session ID)
62
+ * @param token - The OAuth token response to store
63
+ */
64
+ set(key: string, token: OAuthTokenResponse): Promise<void>;
65
+ /**
66
+ * Invalidate a stored token: revoke it server-side and remove from storage.
67
+ *
68
+ * If config is provided, the refresh token (or access token as fallback)
69
+ * is revoked via the token revocation endpoint. Revocation is best-effort —
70
+ * the token is removed from storage regardless of whether revocation succeeds.
71
+ *
72
+ * @param key - The storage key to invalidate
73
+ * @returns The token that was removed, or null if no token existed
74
+ */
75
+ invalidate(key: string): Promise<StoredToken | null>;
76
+ }
77
+ /**
78
+ * Token storage backed by Agentuity's Key-Value storage service.
79
+ *
80
+ * Stores tokens as JSON in a KV namespace. Supports automatic token refresh
81
+ * on retrieval when tokens expire (if OAuth config is provided).
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * import { KeyValueTokenStorage } from '@agentuity/core/oauth';
86
+ *
87
+ * // Create storage with auto-refresh enabled
88
+ * const storage = new KeyValueTokenStorage(ctx.kv, {
89
+ * config: { issuer: 'https://auth.example.com' },
90
+ * });
91
+ *
92
+ * // Store a token after initial exchange
93
+ * await storage.set('user:123', tokenResponse);
94
+ *
95
+ * // Retrieve — auto-refreshes if expired
96
+ * const token = await storage.get('user:123');
97
+ *
98
+ * // Logout — revokes server-side and removes from storage
99
+ * await storage.invalidate('user:123');
100
+ * ```
101
+ */
102
+ export declare class KeyValueTokenStorage implements TokenStorage {
103
+ #private;
104
+ constructor(kv: KeyValueStorage, options?: TokenStorageOptions);
105
+ get(key: string): Promise<StoredToken | null>;
106
+ set(key: string, token: OAuthTokenResponse): Promise<void>;
107
+ invalidate(key: string): Promise<StoredToken | null>;
108
+ }
109
+ //# sourceMappingURL=token-storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-storage.d.ts","sourceRoot":"","sources":["../../../src/services/oauth/token-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAMnF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAG1D;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;OAGG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IAEzB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC5B;;;;;;;;;;OAUG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE9C;;;;;;;OAOG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3D;;;;;;;;;OASG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CACrD;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,oBAAqB,YAAW,YAAY;;gBAM5C,EAAE,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,mBAAmB;IAOxD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAyB7C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAK1D,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;CA8C1D"}
@@ -0,0 +1,140 @@
1
+ import { StoredTokenSchema } from "./types.js";
2
+ import { refreshToken, logout } from "./flow.js";
3
+ const DEFAULT_NAMESPACE = 'oauth-tokens';
4
+ /**
5
+ * Check whether a stored token's access token has expired.
6
+ *
7
+ * @param token - The stored token to check
8
+ * @returns true if the token has an expires_at timestamp that is in the past
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const token = await storage.get('user:123');
13
+ * if (token && isTokenExpired(token)) {
14
+ * // Token is expired and auto-refresh wasn't available
15
+ * }
16
+ * ```
17
+ */
18
+ export function isTokenExpired(token) {
19
+ if (!token.expires_at)
20
+ return false;
21
+ return Math.floor(Date.now() / 1000) >= token.expires_at;
22
+ }
23
+ /**
24
+ * Convert an OAuth token response to a StoredToken with computed expires_at.
25
+ */
26
+ function toStoredToken(token) {
27
+ return {
28
+ access_token: token.access_token,
29
+ token_type: token.token_type,
30
+ refresh_token: token.refresh_token,
31
+ scope: token.scope,
32
+ id_token: token.id_token,
33
+ expires_at: token.expires_in ? Math.floor(Date.now() / 1000) + token.expires_in : undefined,
34
+ };
35
+ }
36
+ /**
37
+ * Token storage backed by Agentuity's Key-Value storage service.
38
+ *
39
+ * Stores tokens as JSON in a KV namespace. Supports automatic token refresh
40
+ * on retrieval when tokens expire (if OAuth config is provided).
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * import { KeyValueTokenStorage } from '@agentuity/core/oauth';
45
+ *
46
+ * // Create storage with auto-refresh enabled
47
+ * const storage = new KeyValueTokenStorage(ctx.kv, {
48
+ * config: { issuer: 'https://auth.example.com' },
49
+ * });
50
+ *
51
+ * // Store a token after initial exchange
52
+ * await storage.set('user:123', tokenResponse);
53
+ *
54
+ * // Retrieve — auto-refreshes if expired
55
+ * const token = await storage.get('user:123');
56
+ *
57
+ * // Logout — revokes server-side and removes from storage
58
+ * await storage.invalidate('user:123');
59
+ * ```
60
+ */
61
+ export class KeyValueTokenStorage {
62
+ #kv;
63
+ #namespace;
64
+ #prefix;
65
+ #config;
66
+ constructor(kv, options) {
67
+ this.#kv = kv;
68
+ this.#namespace = options?.namespace ?? DEFAULT_NAMESPACE;
69
+ this.#prefix = options?.prefix ?? '';
70
+ this.#config = options?.config;
71
+ }
72
+ async get(key) {
73
+ const result = await this.#kv.get(this.#namespace, this.#resolveKey(key));
74
+ if (!result.exists)
75
+ return null;
76
+ const parsed = StoredTokenSchema.safeParse(result.data);
77
+ if (!parsed.success)
78
+ return null;
79
+ const token = parsed.data;
80
+ // Auto-refresh if expired and refresh_token + config are available
81
+ if (isTokenExpired(token) && token.refresh_token && this.#config) {
82
+ try {
83
+ const newTokenResponse = await refreshToken(token.refresh_token, this.#config);
84
+ const newStored = toStoredToken(newTokenResponse);
85
+ await this.#store(key, newStored);
86
+ return newStored;
87
+ }
88
+ catch {
89
+ // Refresh failed — return the expired token, caller can check isTokenExpired()
90
+ return token;
91
+ }
92
+ }
93
+ return token;
94
+ }
95
+ async set(key, token) {
96
+ const stored = toStoredToken(token);
97
+ await this.#store(key, stored);
98
+ }
99
+ async invalidate(key) {
100
+ const resolvedKey = this.#resolveKey(key);
101
+ const result = await this.#kv.get(this.#namespace, resolvedKey);
102
+ if (!result.exists)
103
+ return null;
104
+ const parsed = StoredTokenSchema.safeParse(result.data);
105
+ const token = parsed.success ? parsed.data : null;
106
+ // Revoke server-side (best effort)
107
+ if (token && this.#config) {
108
+ const tokenToRevoke = token.refresh_token ?? token.access_token;
109
+ try {
110
+ await logout(tokenToRevoke, this.#config);
111
+ }
112
+ catch {
113
+ // Best effort — continue with storage cleanup
114
+ }
115
+ }
116
+ // Remove from storage regardless of revocation result
117
+ await this.#kv.delete(this.#namespace, resolvedKey);
118
+ return token;
119
+ }
120
+ async #store(key, token) {
121
+ // Only set explicit TTL for tokens without a refresh_token.
122
+ // Tokens with refresh capability persist until explicitly invalidated
123
+ // (auto-refresh on get() will keep them fresh).
124
+ let ttl;
125
+ if (!token.refresh_token && token.expires_at) {
126
+ const remaining = token.expires_at - Math.floor(Date.now() / 1000);
127
+ if (remaining > 0) {
128
+ ttl = Math.max(remaining, 60); // KV minimum is 60 seconds
129
+ }
130
+ }
131
+ await this.#kv.set(this.#namespace, this.#resolveKey(key), token, {
132
+ ttl,
133
+ contentType: 'application/json',
134
+ });
135
+ }
136
+ #resolveKey(key) {
137
+ return this.#prefix ? `${this.#prefix}${key}` : key;
138
+ }
139
+ }
140
+ //# sourceMappingURL=token-storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-storage.js","sourceRoot":"","sources":["../../../src/services/oauth/token-storage.ts"],"names":[],"mappings":"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"}