@olane/o-core 0.8.3 → 0.8.5

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 (34) hide show
  1. package/README.md +101 -31
  2. package/dist/src/auth/file-token-store.d.ts +15 -0
  3. package/dist/src/auth/file-token-store.d.ts.map +1 -0
  4. package/dist/src/auth/file-token-store.js +55 -0
  5. package/dist/src/auth/index.d.ts +6 -0
  6. package/dist/src/auth/index.d.ts.map +1 -0
  7. package/dist/src/auth/index.js +5 -0
  8. package/dist/src/auth/o-refresh-token-provider.d.ts +31 -0
  9. package/dist/src/auth/o-refresh-token-provider.d.ts.map +1 -0
  10. package/dist/src/auth/o-refresh-token-provider.js +61 -0
  11. package/dist/src/auth/o-token-manager.d.ts +46 -0
  12. package/dist/src/auth/o-token-manager.d.ts.map +1 -0
  13. package/dist/src/auth/o-token-manager.js +211 -0
  14. package/dist/src/auth/o-token-provider.d.ts +16 -0
  15. package/dist/src/auth/o-token-provider.d.ts.map +1 -0
  16. package/dist/src/auth/o-token-provider.js +1 -0
  17. package/dist/src/auth/o-token-store.d.ts +17 -0
  18. package/dist/src/auth/o-token-store.d.ts.map +1 -0
  19. package/dist/src/auth/o-token-store.js +1 -0
  20. package/dist/src/context/index.d.ts +2 -0
  21. package/dist/src/context/index.d.ts.map +1 -0
  22. package/dist/src/context/index.js +1 -0
  23. package/dist/src/context/o-request-context.d.ts +22 -0
  24. package/dist/src/context/o-request-context.d.ts.map +1 -0
  25. package/dist/src/context/o-request-context.js +47 -0
  26. package/dist/src/core/interfaces/use-data.config.d.ts +7 -0
  27. package/dist/src/core/interfaces/use-data.config.d.ts.map +1 -1
  28. package/dist/src/core/o-core.d.ts +5 -0
  29. package/dist/src/core/o-core.d.ts.map +1 -1
  30. package/dist/src/core/o-core.js +28 -6
  31. package/dist/src/index.d.ts +2 -0
  32. package/dist/src/index.d.ts.map +1 -1
  33. package/dist/src/index.js +2 -0
  34. package/package.json +3 -3
package/README.md CHANGED
@@ -35,22 +35,24 @@ This is **NOT** a network framework or API library - it's the abstract operating
35
35
  ## Installation
36
36
 
37
37
  ```bash
38
- npm install @olane/o-core @olane/o-protocol
38
+ pnpm install @olane/o-core @olane/o-protocol
39
39
  ```
40
40
 
41
41
  ## Quick Start
42
42
 
43
43
  ### Creating Your First Tool Node
44
44
 
45
+ > **Note**: `oCore` is an abstract base class. For production use, extend higher-level packages like `oNodeTool` (from `@olane/o-node`), `oLaneTool` (from `@olane/o-lane`), or `McpTool` (from `@olane/o-mcp`). The example below demonstrates the core concepts.
46
+
45
47
  ```typescript
46
48
  import { oCore, oAddress, NodeType, NodeState } from '@olane/o-core';
47
49
  import { oRequest, oResponse } from '@olane/o-core';
48
50
 
49
51
  // Extend oCore to create your tool node
50
52
  class MyToolNode extends oCore {
51
- constructor(address: string) {
53
+ constructor(config: { address: oAddress }) {
52
54
  super({
53
- address: new oAddress(address),
55
+ address: config.address,
54
56
  type: NodeType.AGENT, // Type remains AGENT for now (legacy naming)
55
57
  description: 'My first tool node',
56
58
  methods: {
@@ -68,11 +70,11 @@ class MyToolNode extends oCore {
68
70
  // Implement required abstract methods
69
71
  async execute(request: oRequest): Promise<any> {
70
72
  const { method, params } = request;
71
-
73
+
72
74
  if (method === 'greet') {
73
75
  return { message: `Hello, ${params.name}!` };
74
76
  }
75
-
77
+
76
78
  throw new Error(`Unknown method: ${method}`);
77
79
  }
78
80
 
@@ -103,19 +105,30 @@ class MyToolNode extends oCore {
103
105
  }
104
106
 
105
107
  // Create and start your tool node
106
- const toolNode = new MyToolNode('o://company/customer-service');
108
+ // IMPORTANT: Use simple (non-nested) addresses in constructors.
109
+ // Nested addresses like 'o://company/customer-service' are created
110
+ // automatically at runtime during parent-child registration.
111
+ const toolNode = new MyToolNode({
112
+ address: new oAddress('o://customer-service')
113
+ });
107
114
  await toolNode.start();
108
115
 
109
116
  // AI agents can now use this tool node via its o:// address
110
117
  const response = await toolNode.use(
111
- new oAddress('o://company/customer-service'),
118
+ new oAddress('o://customer-service'),
112
119
  {
113
120
  method: 'greet',
114
121
  params: { name: 'Alice' }
115
122
  }
116
123
  );
117
124
 
118
- console.log(response.result); // { message: "Hello, Alice!" }
125
+ // Response follows the standard wrapping structure:
126
+ // response.result.success - boolean indicating success/failure
127
+ // response.result.data - the returned data on success
128
+ // response.result.error - error details on failure
129
+ if (response.result.success) {
130
+ console.log(response.result.data); // { message: "Hello, Alice!" }
131
+ }
119
132
 
120
133
  // Stop the tool node gracefully
121
134
  await toolNode.stop();
@@ -125,15 +138,16 @@ await toolNode.stop();
125
138
 
126
139
  ```typescript
127
140
  // Tool Node A can communicate with Tool Node B using o:// addresses
128
- const salesTool = new MyToolNode('o://company/sales');
129
- const analyticsTool = new MyToolNode('o://company/analytics');
141
+ // Use simple addresses in constructors; nested addresses are created at runtime
142
+ const salesTool = new MyToolNode({ address: new oAddress('o://sales') });
143
+ const analyticsTool = new MyToolNode({ address: new oAddress('o://analytics') });
130
144
 
131
145
  await salesTool.start();
132
146
  await analyticsTool.start();
133
147
 
134
148
  // Sales tool calls analytics tool (inter-process communication)
135
149
  const result = await salesTool.use(
136
- new oAddress('o://company/analytics'),
150
+ new oAddress('o://analytics'),
137
151
  {
138
152
  method: 'analyze',
139
153
  params: { data: salesData }
@@ -145,19 +159,25 @@ const result = await salesTool.use(
145
159
 
146
160
  ```typescript
147
161
  // Create a parent-child hierarchy of tool nodes
148
- const parent = new MyToolNode('o://company');
149
- const child1 = new MyToolNode('o://company/sales');
150
- const child2 = new MyToolNode('o://company/marketing');
162
+ // Use simple addresses in constructors - nested addresses are created at runtime
163
+ const parent = new MyToolNode({ address: new oAddress('o://company') });
164
+
165
+ // Children use simple addresses with a parent reference
166
+ // During registration, child addresses become nested (e.g., 'o://company/sales')
167
+ const child1 = new MyToolNode({ address: new oAddress('o://sales') });
168
+ const child2 = new MyToolNode({ address: new oAddress('o://marketing') });
151
169
 
152
170
  await parent.start();
153
171
  await child1.start();
154
172
  await child2.start();
155
173
 
156
- // Register children with parent
174
+ // Register children with parent - this creates the nested addresses
157
175
  parent.addChildNode(child1);
158
176
  parent.addChildNode(child2);
159
177
 
160
- // Child tool nodes automatically inherit context from parent
178
+ // After registration:
179
+ // child1.address -> 'o://company/sales'
180
+ // child2.address -> 'o://company/marketing'
161
181
  // Routing happens automatically through the hierarchy
162
182
  ```
163
183
 
@@ -185,7 +205,9 @@ console.log(toolNode.state); // NodeState.STOPPED
185
205
  Addresses in Olane OS follow a hierarchical filesystem-like pattern:
186
206
 
187
207
  ```typescript
188
- // Hierarchical addresses
208
+ // Hierarchical addresses exist at runtime after parent-child registration.
209
+ // They are created by the system, not by constructors directly.
210
+ // For example, after registration a child address may become:
189
211
  const address1 = new oAddress('o://company/finance/accounting');
190
212
  const address2 = new oAddress('o://users/alice/inbox');
191
213
 
@@ -197,6 +219,12 @@ console.log(address1.validate()); // true
197
219
  // Static vs dynamic addresses
198
220
  const staticAddr = address1.toStaticAddress();
199
221
  console.log(staticAddr.toString()); // "o://accounting"
222
+
223
+ // IMPORTANT: When creating nodes in constructors, always use simple
224
+ // (non-nested) addresses. Nested addresses are created automatically
225
+ // during parent-child registration at runtime.
226
+ // ✅ new oAddress('o://my-tool')
227
+ // ❌ new oAddress('o://parent/my-tool') -- violates validateNotNested()
200
228
  ```
201
229
 
202
230
  **📖 For complete details on address resolution, routing algorithms, and custom resolvers, see the [Router System documentation](./src/router/README.md).**
@@ -207,8 +235,9 @@ All inter-process communication (IPC) follows a request/response pattern using J
207
235
 
208
236
  ```typescript
209
237
  // Making a request from one tool node to another
238
+ // Full signature: use(address: oAddress, data?: { method: string, params: any, id?: string }, options?: UseOptions)
210
239
  const response: oResponse = await toolNode.use(
211
- new oAddress('o://target/toolnode'),
240
+ new oAddress('o://target-toolnode'),
212
241
  {
213
242
  method: 'processData',
214
243
  params: { key: 'value' },
@@ -216,19 +245,58 @@ const response: oResponse = await toolNode.use(
216
245
  }
217
246
  );
218
247
 
219
- // Handling errors
248
+ // Always check the response structure
249
+ if (response.result.success) {
250
+ console.log('Data:', response.result.data);
251
+ } else {
252
+ console.error('Error:', response.result.error);
253
+ }
254
+
255
+ // Transport-level errors throw exceptions
220
256
  try {
221
257
  const response = await toolNode.use(targetAddress, requestData);
222
- console.log(response.result);
258
+ // Check response.result.success for application-level errors
223
259
  } catch (error) {
224
260
  if (error instanceof oError) {
225
- console.error(`Error ${error.code}: ${error.message}`);
261
+ console.error(`Transport error ${error.code}: ${error.message}`);
226
262
  }
227
263
  }
228
264
  ```
229
265
 
230
266
  **📖 Learn more about JSON-RPC messaging, request states, and connection lifecycle in the [Connection System documentation](./src/connection/README.md).**
231
267
 
268
+ ### Response Structure
269
+
270
+ When you call `use()`, the response follows a standard wrapping structure created by the `ResponseBuilder`. In higher-level packages (`@olane/o-node`, `@olane/o-tool`, `@olane/o-lane`), responses are wrapped with `success`, `data`, and `error` fields:
271
+
272
+ ```typescript
273
+ const response = await toolNode.use(targetAddress, {
274
+ method: 'processData',
275
+ params: { key: 'value' }
276
+ });
277
+
278
+ // Standard response structure:
279
+ // {
280
+ // jsonrpc: "2.0",
281
+ // id: "request-id",
282
+ // result: {
283
+ // success: boolean, // Whether the operation succeeded
284
+ // data: any, // The returned data (on success)
285
+ // error?: string // Error details (on failure)
286
+ // }
287
+ // }
288
+
289
+ // Always check success before accessing data
290
+ if (response.result.success) {
291
+ const data = response.result.data;
292
+ console.log('Result:', data);
293
+ } else {
294
+ console.error('Error:', response.result.error);
295
+ }
296
+ ```
297
+
298
+ > **Important**: Access data via `response.result.data`, not `response.result` directly. The `result` object contains the wrapping fields (`success`, `data`, `error`), not the raw return value.
299
+
232
300
  ### Metrics and Observability
233
301
 
234
302
  Every tool node tracks metrics automatically:
@@ -252,7 +320,7 @@ toolNode.logger.error('Error message');
252
320
  `oCore` is an abstract base class that provides:
253
321
 
254
322
  - **Lifecycle Management**: `start()`, `stop()`, `initialize()`, `teardown()`
255
- - **Communication**: `use()`, `use()`, `connect()`
323
+ - **Communication**: `use()`, `useDirect()`, `connect()`
256
324
  - **Routing**: `router`, `initializeRouter()`
257
325
  - **Hierarchy**: `addChildNode()`, `removeChildNode()`, `hierarchyManager`
258
326
  - **State Management**: `state`, `NodeState` enum
@@ -401,7 +469,7 @@ async execute(request: oRequest): Promise<any> {
401
469
  ```typescript
402
470
  import { setupGracefulShutdown } from '@olane/o-core';
403
471
 
404
- const toolNode = new MyToolNode('o://my/toolnode');
472
+ const toolNode = new MyToolNode({ address: new oAddress('o://my-toolnode') });
405
473
  await toolNode.start();
406
474
 
407
475
  // Setup graceful shutdown handlers
@@ -430,7 +498,9 @@ Abstract base class for building tool nodes.
430
498
  #### Methods
431
499
  - `async start(): Promise<void>` - Start the tool node
432
500
  - `async stop(): Promise<void>` - Stop the tool node gracefully
433
- - `async use(address, data?): Promise<oResponse>` - Communicate with another tool node (IPC)
501
+ - `async use(address: oAddress, data?: UseDataConfig, options?: UseOptions): Promise<oResponse>` - Communicate with another tool node (IPC). The `options` parameter supports `noRouting`, `isStream`, `onChunk`, `readTimeoutMs`, `drainTimeoutMs`, and `abortSignal`.
502
+ - `async useDirect(address: oAddress, data?: UseDataConfig): Promise<oResponse>` - Send a request without routing (equivalent to `use()` with `{ noRouting: true }`)
503
+ - `async useStream(address: oAddress, data: UseDataConfig, options: UseStreamOptions): Promise<oResponse>` - Send a streaming request to another tool node
434
504
  - `async execute(request): Promise<any>` - Execute a request (abstract - you implement this)
435
505
  - `addChildNode(node): void` - Add a child tool node
436
506
  - `removeChildNode(node): void` - Remove a child tool node
@@ -460,29 +530,29 @@ new oError(code: oErrorCodes, message: string, data?: any)
460
530
 
461
531
  ```bash
462
532
  # Run tests
463
- npm test
533
+ pnpm test
464
534
 
465
535
  # Run tests in Node.js
466
- npm run test:node
536
+ pnpm run test:node
467
537
 
468
538
  # Run tests in browser
469
- npm run test:browser
539
+ pnpm run test:browser
470
540
  ```
471
541
 
472
542
  ## Development
473
543
 
474
544
  ```bash
475
545
  # Install dependencies
476
- npm install
546
+ pnpm install
477
547
 
478
548
  # Build the package
479
- npm run build
549
+ pnpm run build
480
550
 
481
551
  # Run in development mode
482
- npm run dev
552
+ pnpm run dev
483
553
 
484
554
  # Lint the code
485
- npm run lint
555
+ pnpm run lint
486
556
  ```
487
557
 
488
558
  ## Use Cases
@@ -0,0 +1,15 @@
1
+ import type { oTokenStore, oTokenStoreEntry } from './o-token-store.js';
2
+ export interface FileTokenStoreConfig {
3
+ directory: string;
4
+ }
5
+ export declare class FileTokenStore implements oTokenStore {
6
+ private directory;
7
+ private initialized;
8
+ constructor(config: FileTokenStoreConfig);
9
+ get(key: string): Promise<oTokenStoreEntry | null>;
10
+ set(key: string, entry: oTokenStoreEntry): Promise<void>;
11
+ delete(key: string): Promise<void>;
12
+ private keyToPath;
13
+ private ensureDirectory;
14
+ }
15
+ //# sourceMappingURL=file-token-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-token-store.d.ts","sourceRoot":"","sources":["../../../src/auth/file-token-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAExE,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAS;gBAEhB,MAAM,EAAE,oBAAoB;IAIlC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAqBlD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxC,OAAO,CAAC,SAAS;YAKH,eAAe;CAK9B"}
@@ -0,0 +1,55 @@
1
+ import { readFile, writeFile, rename, unlink, mkdir } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ export class FileTokenStore {
4
+ constructor(config) {
5
+ this.initialized = false;
6
+ this.directory = config.directory;
7
+ }
8
+ async get(key) {
9
+ await this.ensureDirectory();
10
+ const filePath = this.keyToPath(key);
11
+ let raw;
12
+ try {
13
+ raw = await readFile(filePath, 'utf-8');
14
+ }
15
+ catch (err) {
16
+ if (err.code === 'ENOENT')
17
+ return null;
18
+ throw err;
19
+ }
20
+ try {
21
+ return JSON.parse(raw);
22
+ }
23
+ catch {
24
+ // Corrupted file — remove it and return null
25
+ await unlink(filePath).catch(() => { });
26
+ return null;
27
+ }
28
+ }
29
+ async set(key, entry) {
30
+ await this.ensureDirectory();
31
+ const filePath = this.keyToPath(key);
32
+ const tmpPath = filePath + '.tmp';
33
+ const data = JSON.stringify(entry, null, 2);
34
+ // Atomic write: write to tmp, then rename
35
+ await writeFile(tmpPath, data, { encoding: 'utf-8', mode: 0o600 });
36
+ await rename(tmpPath, filePath);
37
+ }
38
+ async delete(key) {
39
+ const filePath = this.keyToPath(key);
40
+ await unlink(filePath).catch((err) => {
41
+ if (err.code !== 'ENOENT')
42
+ throw err;
43
+ });
44
+ }
45
+ keyToPath(key) {
46
+ const sanitized = key.replace(/[^a-zA-Z0-9_\-\.]/g, '_');
47
+ return join(this.directory, `${sanitized}.token.json`);
48
+ }
49
+ async ensureDirectory() {
50
+ if (this.initialized)
51
+ return;
52
+ await mkdir(this.directory, { recursive: true, mode: 0o700 });
53
+ this.initialized = true;
54
+ }
55
+ }
@@ -0,0 +1,6 @@
1
+ export * from './o-token-provider.js';
2
+ export * from './o-token-manager.js';
3
+ export * from './o-token-store.js';
4
+ export * from './o-refresh-token-provider.js';
5
+ export * from './file-token-store.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './o-token-provider.js';
2
+ export * from './o-token-manager.js';
3
+ export * from './o-token-store.js';
4
+ export * from './o-refresh-token-provider.js';
5
+ export * from './file-token-store.js';
@@ -0,0 +1,31 @@
1
+ import type { oTokenProvider, oTokenResult } from './o-token-provider.js';
2
+ export interface OAuth2TokenResponse {
3
+ access_token: string;
4
+ expires_in?: number;
5
+ refresh_token?: string;
6
+ token_type?: string;
7
+ [key: string]: any;
8
+ }
9
+ export interface RefreshTokenProviderConfig {
10
+ tokenEndpoint: string;
11
+ refreshToken: string;
12
+ clientId?: string;
13
+ clientSecret?: string;
14
+ headers?: Record<string, string>;
15
+ additionalParams?: Record<string, string>;
16
+ parseResponse?: (body: any) => oTokenResult;
17
+ }
18
+ export declare class RefreshTokenProvider implements oTokenProvider {
19
+ private tokenEndpoint;
20
+ private refreshToken;
21
+ private clientId?;
22
+ private clientSecret?;
23
+ private headers;
24
+ private additionalParams;
25
+ private parseResponse;
26
+ constructor(config: RefreshTokenProviderConfig);
27
+ acquireToken(): Promise<oTokenResult>;
28
+ updateRefreshToken(token: string): void;
29
+ static defaultParseResponse(body: OAuth2TokenResponse): oTokenResult;
30
+ }
31
+ //# sourceMappingURL=o-refresh-token-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-refresh-token-provider.d.ts","sourceRoot":"","sources":["../../../src/auth/o-refresh-token-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1E,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,YAAY,CAAC;CAC7C;AAED,qBAAa,oBAAqB,YAAW,cAAc;IACzD,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,CAAS;IAC1B,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,gBAAgB,CAAyB;IACjD,OAAO,CAAC,aAAa,CAA8B;gBAEvC,MAAM,EAAE,0BAA0B;IAUxC,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;IAyC3C,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIvC,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,mBAAmB,GAAG,YAAY;CAmBrE"}
@@ -0,0 +1,61 @@
1
+ export class RefreshTokenProvider {
2
+ constructor(config) {
3
+ this.tokenEndpoint = config.tokenEndpoint;
4
+ this.refreshToken = config.refreshToken;
5
+ this.clientId = config.clientId;
6
+ this.clientSecret = config.clientSecret;
7
+ this.headers = config.headers ?? {};
8
+ this.additionalParams = config.additionalParams ?? {};
9
+ this.parseResponse = config.parseResponse ?? RefreshTokenProvider.defaultParseResponse;
10
+ }
11
+ async acquireToken() {
12
+ const body = new URLSearchParams({
13
+ grant_type: 'refresh_token',
14
+ refresh_token: this.refreshToken,
15
+ ...this.additionalParams,
16
+ });
17
+ if (this.clientId) {
18
+ body.set('client_id', this.clientId);
19
+ }
20
+ if (this.clientSecret) {
21
+ body.set('client_secret', this.clientSecret);
22
+ }
23
+ const response = await fetch(this.tokenEndpoint, {
24
+ method: 'POST',
25
+ headers: {
26
+ 'Content-Type': 'application/x-www-form-urlencoded',
27
+ ...this.headers,
28
+ },
29
+ body: body.toString(),
30
+ });
31
+ if (!response.ok) {
32
+ const text = await response.text().catch(() => '');
33
+ throw new Error(`Token refresh failed: ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`);
34
+ }
35
+ const json = await response.json();
36
+ const result = this.parseResponse(json);
37
+ // Rotate stored refresh token if the provider returned a new one
38
+ if (result.refreshToken) {
39
+ this.refreshToken = result.refreshToken;
40
+ }
41
+ return result;
42
+ }
43
+ updateRefreshToken(token) {
44
+ this.refreshToken = token;
45
+ }
46
+ static defaultParseResponse(body) {
47
+ if (!body.access_token) {
48
+ throw new Error('Token response missing access_token');
49
+ }
50
+ const result = {
51
+ token: body.access_token,
52
+ };
53
+ if (body.expires_in != null) {
54
+ result.expiresAt = Math.floor(Date.now() / 1000) + body.expires_in;
55
+ }
56
+ if (body.refresh_token) {
57
+ result.refreshToken = body.refresh_token;
58
+ }
59
+ return result;
60
+ }
61
+ }
@@ -0,0 +1,46 @@
1
+ import type { oTokenProvider, oTokenResult } from './o-token-provider.js';
2
+ import type { oTokenStore } from './o-token-store.js';
3
+ import type { ORequestAuthContext } from '../context/o-request-context.js';
4
+ export interface oTokenManagerConfig {
5
+ provider: oTokenProvider;
6
+ autoRefresh?: boolean;
7
+ refreshBufferMs?: number;
8
+ defaultLifetimeMs?: number;
9
+ maxRefreshRetries?: number;
10
+ onRefreshFailure?: (error: Error) => void;
11
+ store?: oTokenStore;
12
+ storeKey?: string;
13
+ }
14
+ export declare class oTokenManager {
15
+ private provider;
16
+ private autoRefresh;
17
+ private refreshBufferMs;
18
+ private defaultLifetimeMs;
19
+ private maxRefreshRetries;
20
+ private onRefreshFailure?;
21
+ private store;
22
+ private storeKey;
23
+ private storeLoaded;
24
+ private currentResult;
25
+ private acquiredAt;
26
+ private refreshPromise;
27
+ private refreshTimer;
28
+ private destroyed;
29
+ constructor(config: oTokenManagerConfig);
30
+ getToken(forceRefresh?: boolean): Promise<string>;
31
+ getTokenResult(forceRefresh?: boolean): Promise<oTokenResult>;
32
+ refresh(): Promise<oTokenResult>;
33
+ isExpired(): boolean;
34
+ isCloseToExpiration(): boolean;
35
+ getTimeUntilExpiration(): number | null;
36
+ toAuthContext(): ORequestAuthContext | null;
37
+ destroy(): Promise<void>;
38
+ private loadFromStore;
39
+ private saveToStore;
40
+ private executeRefreshWithRetry;
41
+ private scheduleAutoRefresh;
42
+ private clearRefreshTimer;
43
+ private getExpiresAtMs;
44
+ private sleep;
45
+ }
46
+ //# sourceMappingURL=o-token-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-token-manager.d.ts","sourceRoot":"","sources":["../../../src/auth/o-token-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAoB,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAE3E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,cAAc,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC1C,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,gBAAgB,CAAC,CAAyB;IAElD,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,YAAY,CAA8C;IAClE,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,mBAAmB;IAWjC,QAAQ,CAAC,YAAY,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAK/C,cAAc,CAAC,YAAY,UAAQ,GAAG,OAAO,CAAC,YAAY,CAAC;IAoB3D,OAAO,IAAI,OAAO,CAAC,YAAY,CAAC;IAoBtC,SAAS,IAAI,OAAO;IAOpB,mBAAmB,IAAI,OAAO;IAO9B,sBAAsB,IAAI,MAAM,GAAG,IAAI;IAOvC,aAAa,IAAI,mBAAmB,GAAG,IAAI;IAarC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAgBhB,aAAa;YA4Bb,WAAW;YAiBX,uBAAuB;IA2BrC,OAAO,CAAC,mBAAmB;IAwB3B,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,KAAK;CAGd"}
@@ -0,0 +1,211 @@
1
+ export class oTokenManager {
2
+ constructor(config) {
3
+ this.storeLoaded = false;
4
+ this.currentResult = null;
5
+ this.acquiredAt = null;
6
+ this.refreshPromise = null;
7
+ this.refreshTimer = null;
8
+ this.destroyed = false;
9
+ this.provider = config.provider;
10
+ this.autoRefresh = config.autoRefresh ?? true;
11
+ this.refreshBufferMs = config.refreshBufferMs ?? 60000;
12
+ this.defaultLifetimeMs = config.defaultLifetimeMs ?? 3600000;
13
+ this.maxRefreshRetries = config.maxRefreshRetries ?? 3;
14
+ this.onRefreshFailure = config.onRefreshFailure;
15
+ this.store = config.store ?? null;
16
+ this.storeKey = config.storeKey ?? 'default';
17
+ }
18
+ async getToken(forceRefresh = false) {
19
+ const result = await this.getTokenResult(forceRefresh);
20
+ return result.token;
21
+ }
22
+ async getTokenResult(forceRefresh = false) {
23
+ if (this.destroyed) {
24
+ throw new Error('oTokenManager has been destroyed');
25
+ }
26
+ if (!forceRefresh && this.currentResult && !this.isExpired()) {
27
+ return this.currentResult;
28
+ }
29
+ // On first call, try to restore from persistent store
30
+ if (!forceRefresh && !this.currentResult && this.store && !this.storeLoaded) {
31
+ const restored = await this.loadFromStore();
32
+ if (restored && !this.isExpired()) {
33
+ return this.currentResult;
34
+ }
35
+ }
36
+ return this.refresh();
37
+ }
38
+ async refresh() {
39
+ if (this.destroyed) {
40
+ throw new Error('oTokenManager has been destroyed');
41
+ }
42
+ // Concurrent deduplication: share a single in-flight refresh
43
+ if (this.refreshPromise) {
44
+ return this.refreshPromise;
45
+ }
46
+ this.refreshPromise = this.executeRefreshWithRetry();
47
+ try {
48
+ const result = await this.refreshPromise;
49
+ return result;
50
+ }
51
+ finally {
52
+ this.refreshPromise = null;
53
+ }
54
+ }
55
+ isExpired() {
56
+ if (!this.currentResult)
57
+ return true;
58
+ const expiresAt = this.getExpiresAtMs();
59
+ if (expiresAt === null)
60
+ return false;
61
+ return Date.now() >= expiresAt;
62
+ }
63
+ isCloseToExpiration() {
64
+ if (!this.currentResult)
65
+ return true;
66
+ const expiresAt = this.getExpiresAtMs();
67
+ if (expiresAt === null)
68
+ return false;
69
+ return Date.now() >= expiresAt - this.refreshBufferMs;
70
+ }
71
+ getTimeUntilExpiration() {
72
+ if (!this.currentResult)
73
+ return null;
74
+ const expiresAt = this.getExpiresAtMs();
75
+ if (expiresAt === null)
76
+ return null;
77
+ return Math.max(0, expiresAt - Date.now());
78
+ }
79
+ toAuthContext() {
80
+ if (!this.currentResult)
81
+ return null;
82
+ return {
83
+ token: this.currentResult.token,
84
+ claims: {
85
+ sub: this.currentResult.claims?.sub,
86
+ iss: this.currentResult.claims?.iss,
87
+ ...this.currentResult.claims,
88
+ },
89
+ };
90
+ }
91
+ async destroy() {
92
+ this.destroyed = true;
93
+ this.clearRefreshTimer();
94
+ // Persist latest state before clearing memory
95
+ await this.saveToStore();
96
+ this.currentResult = null;
97
+ this.acquiredAt = null;
98
+ this.refreshPromise = null;
99
+ if (this.provider.destroy) {
100
+ await this.provider.destroy();
101
+ }
102
+ }
103
+ async loadFromStore() {
104
+ this.storeLoaded = true;
105
+ try {
106
+ const entry = await this.store.get(this.storeKey);
107
+ if (!entry)
108
+ return false;
109
+ this.currentResult = {
110
+ token: entry.token,
111
+ expiresAt: entry.expiresAt,
112
+ claims: entry.claims,
113
+ refreshToken: entry.refreshToken,
114
+ };
115
+ this.acquiredAt = entry.acquiredAt;
116
+ // Feed persisted refresh token back to provider
117
+ if (entry.refreshToken && this.provider.updateRefreshToken) {
118
+ this.provider.updateRefreshToken(entry.refreshToken);
119
+ }
120
+ this.scheduleAutoRefresh();
121
+ return true;
122
+ }
123
+ catch {
124
+ // Store failures are non-fatal — degrade to in-memory
125
+ return false;
126
+ }
127
+ }
128
+ async saveToStore() {
129
+ if (!this.store || !this.currentResult || this.acquiredAt === null)
130
+ return;
131
+ try {
132
+ const entry = {
133
+ token: this.currentResult.token,
134
+ expiresAt: this.currentResult.expiresAt,
135
+ claims: this.currentResult.claims,
136
+ refreshToken: this.currentResult.refreshToken,
137
+ acquiredAt: this.acquiredAt,
138
+ };
139
+ await this.store.set(this.storeKey, entry);
140
+ }
141
+ catch {
142
+ // Store failures are non-fatal
143
+ }
144
+ }
145
+ async executeRefreshWithRetry() {
146
+ let lastError = null;
147
+ for (let attempt = 0; attempt <= this.maxRefreshRetries; attempt++) {
148
+ try {
149
+ const result = await this.provider.acquireToken();
150
+ this.currentResult = result;
151
+ this.acquiredAt = Date.now();
152
+ this.scheduleAutoRefresh();
153
+ await this.saveToStore();
154
+ return result;
155
+ }
156
+ catch (err) {
157
+ lastError = err instanceof Error ? err : new Error(String(err));
158
+ if (attempt < this.maxRefreshRetries) {
159
+ // Exponential backoff: 1s, 2s, 4s, ...
160
+ const delayMs = Math.min(1000 * Math.pow(2, attempt), 30000);
161
+ await this.sleep(delayMs);
162
+ }
163
+ }
164
+ }
165
+ const error = lastError ?? new Error('Token refresh failed');
166
+ this.onRefreshFailure?.(error);
167
+ throw error;
168
+ }
169
+ scheduleAutoRefresh() {
170
+ this.clearRefreshTimer();
171
+ if (!this.autoRefresh || this.destroyed)
172
+ return;
173
+ const expiresAt = this.getExpiresAtMs();
174
+ if (expiresAt === null)
175
+ return;
176
+ const refreshAt = expiresAt - this.refreshBufferMs;
177
+ const delay = Math.max(0, refreshAt - Date.now());
178
+ this.refreshTimer = setTimeout(() => {
179
+ if (this.destroyed)
180
+ return;
181
+ this.refresh().catch((err) => {
182
+ // onRefreshFailure already called in executeRefreshWithRetry
183
+ });
184
+ }, delay);
185
+ // Don't block process exit
186
+ if (this.refreshTimer && typeof this.refreshTimer === 'object' && 'unref' in this.refreshTimer) {
187
+ this.refreshTimer.unref();
188
+ }
189
+ }
190
+ clearRefreshTimer() {
191
+ if (this.refreshTimer !== null) {
192
+ clearTimeout(this.refreshTimer);
193
+ this.refreshTimer = null;
194
+ }
195
+ }
196
+ getExpiresAtMs() {
197
+ if (!this.currentResult)
198
+ return null;
199
+ if (this.currentResult.expiresAt != null) {
200
+ return this.currentResult.expiresAt * 1000; // convert unix seconds to ms
201
+ }
202
+ // No expiry info — fall back to defaultLifetimeMs from acquisition time
203
+ if (this.acquiredAt != null) {
204
+ return this.acquiredAt + this.defaultLifetimeMs;
205
+ }
206
+ return null;
207
+ }
208
+ sleep(ms) {
209
+ return new Promise((resolve) => setTimeout(resolve, ms));
210
+ }
211
+ }
@@ -0,0 +1,16 @@
1
+ export interface oTokenResult {
2
+ token: string;
3
+ expiresAt?: number;
4
+ claims?: {
5
+ sub?: string;
6
+ iss?: string;
7
+ [key: string]: any;
8
+ };
9
+ refreshToken?: string;
10
+ }
11
+ export interface oTokenProvider {
12
+ acquireToken(): Promise<oTokenResult>;
13
+ destroy?(): Promise<void>;
14
+ updateRefreshToken?(token: string): void;
15
+ }
16
+ //# sourceMappingURL=o-token-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-token-provider.d.ts","sourceRoot":"","sources":["../../../src/auth/o-token-provider.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,kBAAkB,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1C"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,17 @@
1
+ export interface oTokenStoreEntry {
2
+ token: string;
3
+ expiresAt?: number;
4
+ claims?: {
5
+ sub?: string;
6
+ iss?: string;
7
+ [key: string]: any;
8
+ };
9
+ refreshToken?: string;
10
+ acquiredAt: number;
11
+ }
12
+ export interface oTokenStore {
13
+ get(key: string): Promise<oTokenStoreEntry | null>;
14
+ set(key: string, entry: oTokenStoreEntry): Promise<void>;
15
+ delete(key: string): Promise<void>;
16
+ }
17
+ //# sourceMappingURL=o-token-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-token-store.d.ts","sourceRoot":"","sources":["../../../src/auth/o-token-store.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACnD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './o-request-context.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/context/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1 @@
1
+ export * from './o-request-context.js';
@@ -0,0 +1,22 @@
1
+ import type { oTokenManager } from '../auth/o-token-manager.js';
2
+ export interface ORequestAuthContext {
3
+ token: string;
4
+ claims: {
5
+ sub?: string;
6
+ iss?: string;
7
+ aud?: string | string[];
8
+ exp?: number;
9
+ [key: string]: any;
10
+ };
11
+ }
12
+ export interface ORequestStore {
13
+ auth?: ORequestAuthContext;
14
+ tokenManager?: oTokenManager;
15
+ }
16
+ export declare const oRequestContext: {
17
+ run<T>(store: ORequestStore, fn: () => T): T;
18
+ getStore(): ORequestStore | undefined;
19
+ getAuth(): ORequestAuthContext | undefined;
20
+ getTokenManager(): oTokenManager | undefined;
21
+ };
22
+ //# sourceMappingURL=o-request-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-request-context.d.ts","sourceRoot":"","sources":["../../../src/context/o-request-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE;QACN,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QACxB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B;AAgBD,eAAO,MAAM,eAAe;QACtB,CAAC,SAAS,aAAa,MAAM,MAAM,CAAC,GAAG,CAAC;gBAoBhC,aAAa,GAAG,SAAS;eAO1B,mBAAmB,GAAG,SAAS;uBAIvB,aAAa,GAAG,SAAS;CAG7C,CAAC"}
@@ -0,0 +1,47 @@
1
+ // Runtime detection: use native AsyncLocalStorage if available (Node, Deno, Bun, CF Workers).
2
+ // Falls back to a simple variable for browsers/React Native where concurrent
3
+ // multi-user requests don't happen.
4
+ let nativeALS = null;
5
+ try {
6
+ const mod = await import('node:async_hooks');
7
+ nativeALS = new mod.AsyncLocalStorage();
8
+ }
9
+ catch {
10
+ // Not available — browser or React Native runtime
11
+ }
12
+ // Browser fallback state
13
+ let currentStore;
14
+ export const oRequestContext = {
15
+ run(store, fn) {
16
+ if (nativeALS) {
17
+ return nativeALS.run(store, fn);
18
+ }
19
+ // Browser fallback: simple variable swap (safe for single-user environments)
20
+ const prev = currentStore;
21
+ currentStore = store;
22
+ try {
23
+ const result = fn();
24
+ if (result instanceof Promise) {
25
+ return result.finally(() => { currentStore = prev; });
26
+ }
27
+ currentStore = prev;
28
+ return result;
29
+ }
30
+ catch (e) {
31
+ currentStore = prev;
32
+ throw e;
33
+ }
34
+ },
35
+ getStore() {
36
+ if (nativeALS) {
37
+ return nativeALS.getStore();
38
+ }
39
+ return currentStore;
40
+ },
41
+ getAuth() {
42
+ return oRequestContext.getStore()?.auth;
43
+ },
44
+ getTokenManager() {
45
+ return oRequestContext.getStore()?.tokenManager;
46
+ },
47
+ };
@@ -1,6 +1,13 @@
1
1
  export interface UseDataConfig {
2
2
  method: string;
3
3
  params?: {
4
+ _auth?: {
5
+ token: string;
6
+ claims: {
7
+ sub?: string;
8
+ [key: string]: any;
9
+ };
10
+ };
4
11
  [key: string]: any;
5
12
  };
6
13
  id?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"use-data.config.d.ts","sourceRoot":"","sources":["../../../../src/core/interfaces/use-data.config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;CACb"}
1
+ {"version":3,"file":"use-data.config.d.ts","sourceRoot":"","sources":["../../../../src/core/interfaces/use-data.config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE;gBAAE,GAAG,CAAC,EAAE,MAAM,CAAC;gBAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;aAAE,CAAA;SAAE,CAAC;QACxE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;IACF,EAAE,CAAC,EAAE,MAAM,CAAC;CACb"}
@@ -96,6 +96,11 @@ export declare abstract class oCore extends oObject {
96
96
  * @throws Error if node is not running
97
97
  */
98
98
  private validateRunning;
99
+ /**
100
+ * Injects _auth from AsyncLocalStorage into request params if not already present.
101
+ * This enables automatic auth propagation across node.use() calls.
102
+ */
103
+ private injectAuthContext;
99
104
  useSelf(data?: {
100
105
  method?: string;
101
106
  params?: {
@@ -1 +1 @@
1
- {"version":3,"file":"o-core.d.ts","sourceRoot":"","sources":["../../../src/core/o-core.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"o-core.d.ts","sourceRoot":"","sources":["../../../src/core/o-core.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ import { oObject } from './o-object.js';
6
6
  import { oMetrics } from './lib/o-metrics.js';
7
7
  import { oRequest } from '../connection/o-request.js';
8
8
  import { ResponseBuilder } from '../response/response-builder.js';
9
+ import { oRequestContext } from '../context/o-request-context.js';
9
10
  export class oCore extends oObject {
10
11
  constructor(config) {
11
12
  super((config.name ? `:${config.name}` : '') + ':' + config.address.toString());
@@ -99,10 +100,11 @@ export class oCore extends oObject {
99
100
  if (!this.requestManager) {
100
101
  throw new Error('Request manager is not initialized');
101
102
  }
103
+ const enriched = this.injectAuthContext(data);
102
104
  if (address?.toStaticAddress().equals(this.address.toStaticAddress())) {
103
- return this.useSelf(data);
105
+ return this.useSelf(enriched);
104
106
  }
105
- return this.requestManager.send(address, data, options, this);
107
+ return this.requestManager.send(address, enriched, options, this);
106
108
  }
107
109
  /**
108
110
  * Helper method to validate node is running
@@ -114,14 +116,33 @@ export class oCore extends oObject {
114
116
  throw new Error('Node is not running');
115
117
  }
116
118
  }
119
+ /**
120
+ * Injects _auth from AsyncLocalStorage into request params if not already present.
121
+ * This enables automatic auth propagation across node.use() calls.
122
+ */
123
+ injectAuthContext(data) {
124
+ if (!data)
125
+ return data;
126
+ const auth = oRequestContext.getAuth();
127
+ if (!auth || data.params?._auth)
128
+ return data;
129
+ return {
130
+ ...data,
131
+ params: {
132
+ ...data.params,
133
+ _auth: auth,
134
+ },
135
+ };
136
+ }
117
137
  async useSelf(data) {
118
138
  this.validateRunning();
139
+ const enriched = this.injectAuthContext(data);
119
140
  const request = new oRequest({
120
- method: data?.method,
141
+ method: enriched?.method,
121
142
  params: {
122
143
  _connectionId: 0,
123
- _requestMethod: data?.method,
124
- ...data?.params,
144
+ _requestMethod: enriched?.method,
145
+ ...enriched?.params,
125
146
  },
126
147
  id: 0,
127
148
  });
@@ -150,6 +171,7 @@ export class oCore extends oObject {
150
171
  if (!this.requestManager) {
151
172
  throw new Error('Request manager is not initialized');
152
173
  }
174
+ const enriched = this.injectAuthContext(data);
153
175
  // extract child address with transports
154
176
  if (!childAddress.transports) {
155
177
  const child = this.hierarchyManager.getChild(childAddress);
@@ -161,7 +183,7 @@ export class oCore extends oObject {
161
183
  childAddress.setTransports(child?.transports || []);
162
184
  }
163
185
  }
164
- return this.requestManager.send(childAddress, data, options, this);
186
+ return this.requestManager.send(childAddress, enriched, options, this);
165
187
  }
166
188
  // hierarchy
167
189
  addChildNode(node) {
@@ -1,4 +1,6 @@
1
+ export * from './auth/index.js';
1
2
  export * from './connection/index.js';
3
+ export * from './context/index.js';
2
4
  export * from './core/index.js';
3
5
  export * from './error/index.js';
4
6
  export * from './response/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
package/dist/src/index.js CHANGED
@@ -1,4 +1,6 @@
1
+ export * from './auth/index.js';
1
2
  export * from './connection/index.js';
3
+ export * from './context/index.js';
2
4
  export * from './core/index.js';
3
5
  export * from './error/index.js';
4
6
  export * from './response/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olane/o-core",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "type": "module",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -63,12 +63,12 @@
63
63
  "typescript": "^5.8.3"
64
64
  },
65
65
  "dependencies": {
66
- "@olane/o-protocol": "0.8.3",
66
+ "@olane/o-protocol": "0.8.5",
67
67
  "chalk": "^5.4.1",
68
68
  "debug": "^4.4.1",
69
69
  "dotenv": "^16.5.0",
70
70
  "multiformats": "^13.3.7",
71
71
  "stream-json": "^1.9.1"
72
72
  },
73
- "gitHead": "189c0cf7b6dd9d5d961f5424af21d37978092d9e"
73
+ "gitHead": "e88f1e55dcc92d9a410d28200e4220697116f82f"
74
74
  }