@olane/o-core 0.8.4 → 0.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/auth/file-token-store.d.ts +15 -0
- package/dist/src/auth/file-token-store.d.ts.map +1 -0
- package/dist/src/auth/file-token-store.js +55 -0
- package/dist/src/auth/index.d.ts +6 -0
- package/dist/src/auth/index.d.ts.map +1 -0
- package/dist/src/auth/index.js +5 -0
- package/dist/src/auth/o-refresh-token-provider.d.ts +31 -0
- package/dist/src/auth/o-refresh-token-provider.d.ts.map +1 -0
- package/dist/src/auth/o-refresh-token-provider.js +61 -0
- package/dist/src/auth/o-token-manager.d.ts +46 -0
- package/dist/src/auth/o-token-manager.d.ts.map +1 -0
- package/dist/src/auth/o-token-manager.js +211 -0
- package/dist/src/auth/o-token-provider.d.ts +16 -0
- package/dist/src/auth/o-token-provider.d.ts.map +1 -0
- package/dist/src/auth/o-token-provider.js +1 -0
- package/dist/src/auth/o-token-store.d.ts +17 -0
- package/dist/src/auth/o-token-store.d.ts.map +1 -0
- package/dist/src/auth/o-token-store.js +1 -0
- package/dist/src/context/index.d.ts +2 -0
- package/dist/src/context/index.d.ts.map +1 -0
- package/dist/src/context/index.js +1 -0
- package/dist/src/context/o-request-context.d.ts +22 -0
- package/dist/src/context/o-request-context.d.ts.map +1 -0
- package/dist/src/context/o-request-context.js +47 -0
- package/dist/src/core/interfaces/o-core.config.d.ts +2 -0
- package/dist/src/core/interfaces/o-core.config.d.ts.map +1 -1
- package/dist/src/core/interfaces/use-data.config.d.ts +7 -0
- package/dist/src/core/interfaces/use-data.config.d.ts.map +1 -1
- package/dist/src/core/o-core.d.ts +14 -0
- package/dist/src/core/o-core.d.ts.map +1 -1
- package/dist/src/core/o-core.js +52 -6
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -0
- package/package.json +3 -3
|
@@ -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 @@
|
|
|
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,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 @@
|
|
|
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
|
+
};
|
|
@@ -2,6 +2,7 @@ import { Libp2pConfig } from '@olane/o-config';
|
|
|
2
2
|
import { oAddress } from '../../router/o-address.js';
|
|
3
3
|
import { NodeType } from './node-type.enum.js';
|
|
4
4
|
import { oDependency, oMethod } from '@olane/o-protocol';
|
|
5
|
+
import type { oTokenManager } from '../../auth/o-token-manager.js';
|
|
5
6
|
export interface oCoreConfig {
|
|
6
7
|
address: oAddress;
|
|
7
8
|
leader: oAddress | null;
|
|
@@ -19,6 +20,7 @@ export interface oCoreConfig {
|
|
|
19
20
|
cwd?: string;
|
|
20
21
|
systemName?: string;
|
|
21
22
|
joinToken?: string;
|
|
23
|
+
tokenManager?: oTokenManager;
|
|
22
24
|
/**
|
|
23
25
|
* Internal flag - bypasses nested address validation.
|
|
24
26
|
* Should only be used by framework internals or tests.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-core.config.d.ts","sourceRoot":"","sources":["../../../../src/core/interfaces/o-core.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"o-core.config.d.ts","sourceRoot":"","sources":["../../../../src/core/interfaces/o-core.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAEnE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,QAAQ,CAAC;IAClB,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,OAAO,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,aAAa,CAAC;IAE7B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B"}
|
|
@@ -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;
|
|
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"}
|
|
@@ -18,6 +18,7 @@ import { oNotificationEvent, EventFilter, NotificationHandler, Subscription } fr
|
|
|
18
18
|
import { UseOptions } from './interfaces/use-options.interface.js';
|
|
19
19
|
import { UseStreamOptions } from './interfaces/use-stream-options.interface.js';
|
|
20
20
|
import { UseDataConfig } from './interfaces/use-data.config.js';
|
|
21
|
+
import { oTokenManager } from '../auth/o-token-manager.js';
|
|
21
22
|
export declare abstract class oCore extends oObject {
|
|
22
23
|
readonly config: oCoreConfig;
|
|
23
24
|
address: oAddress;
|
|
@@ -29,6 +30,7 @@ export declare abstract class oCore extends oObject {
|
|
|
29
30
|
requestManager?: oRequestManager;
|
|
30
31
|
router: oRouter;
|
|
31
32
|
notificationManager: oNotificationManager;
|
|
33
|
+
tokenManager?: oTokenManager;
|
|
32
34
|
private heartbeatInterval?;
|
|
33
35
|
constructor(config: oCoreConfig);
|
|
34
36
|
get isLeader(): boolean;
|
|
@@ -96,6 +98,18 @@ export declare abstract class oCore extends oObject {
|
|
|
96
98
|
* @throws Error if node is not running
|
|
97
99
|
*/
|
|
98
100
|
private validateRunning;
|
|
101
|
+
/**
|
|
102
|
+
* Injects _auth into request params if not already present.
|
|
103
|
+
*
|
|
104
|
+
* Resolution order:
|
|
105
|
+
* 1. AsyncLocalStorage context (propagated auth from an incoming request)
|
|
106
|
+
* 2. Node-level tokenManager (the node's own identity)
|
|
107
|
+
*
|
|
108
|
+
* This ensures every outbound request carries auth — whether it originates
|
|
109
|
+
* from within a request chain or from a node-initiated call (registration,
|
|
110
|
+
* heartbeat, etc.).
|
|
111
|
+
*/
|
|
112
|
+
private injectAuthContext;
|
|
99
113
|
useSelf(data?: {
|
|
100
114
|
method?: string;
|
|
101
115
|
params?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-core.d.ts","sourceRoot":"","sources":["../../../src/core/o-core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAEtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,mBAAmB,EACnB,YAAY,EACb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAEhE,8BAAsB,KAAM,SAAQ,OAAO;
|
|
1
|
+
{"version":3,"file":"o-core.d.ts","sourceRoot":"","sources":["../../../src/core/o-core.ts"],"names":[],"mappings":"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"}
|
package/dist/src/core/o-core.js
CHANGED
|
@@ -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());
|
|
@@ -19,6 +20,9 @@ export class oCore extends oObject {
|
|
|
19
20
|
config.address.validateNotNested();
|
|
20
21
|
}
|
|
21
22
|
this.address = config.address || new oAddress('o://node');
|
|
23
|
+
if (config.tokenManager) {
|
|
24
|
+
this.tokenManager = config.tokenManager;
|
|
25
|
+
}
|
|
22
26
|
}
|
|
23
27
|
get isLeader() {
|
|
24
28
|
return this.config.type === NodeType.LEADER;
|
|
@@ -99,10 +103,11 @@ export class oCore extends oObject {
|
|
|
99
103
|
if (!this.requestManager) {
|
|
100
104
|
throw new Error('Request manager is not initialized');
|
|
101
105
|
}
|
|
106
|
+
const enriched = await this.injectAuthContext(data);
|
|
102
107
|
if (address?.toStaticAddress().equals(this.address.toStaticAddress())) {
|
|
103
|
-
return this.useSelf(
|
|
108
|
+
return this.useSelf(enriched);
|
|
104
109
|
}
|
|
105
|
-
return this.requestManager.send(address,
|
|
110
|
+
return this.requestManager.send(address, enriched, options, this);
|
|
106
111
|
}
|
|
107
112
|
/**
|
|
108
113
|
* Helper method to validate node is running
|
|
@@ -114,14 +119,54 @@ export class oCore extends oObject {
|
|
|
114
119
|
throw new Error('Node is not running');
|
|
115
120
|
}
|
|
116
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Injects _auth into request params if not already present.
|
|
124
|
+
*
|
|
125
|
+
* Resolution order:
|
|
126
|
+
* 1. AsyncLocalStorage context (propagated auth from an incoming request)
|
|
127
|
+
* 2. Node-level tokenManager (the node's own identity)
|
|
128
|
+
*
|
|
129
|
+
* This ensures every outbound request carries auth — whether it originates
|
|
130
|
+
* from within a request chain or from a node-initiated call (registration,
|
|
131
|
+
* heartbeat, etc.).
|
|
132
|
+
*/
|
|
133
|
+
async injectAuthContext(data) {
|
|
134
|
+
if (!data)
|
|
135
|
+
return data;
|
|
136
|
+
// Already has explicit _auth — don't overwrite
|
|
137
|
+
if (data.params?._auth)
|
|
138
|
+
return data;
|
|
139
|
+
// 1. Propagated auth from incoming request context
|
|
140
|
+
let auth = oRequestContext.getAuth();
|
|
141
|
+
// 2. Fallback: node's own identity via tokenManager
|
|
142
|
+
if (!auth && this.tokenManager) {
|
|
143
|
+
try {
|
|
144
|
+
await this.tokenManager.getTokenResult();
|
|
145
|
+
auth = this.tokenManager.toAuthContext() ?? undefined;
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
this.logger.debug('Failed to get token from tokenManager:', error);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (!auth)
|
|
152
|
+
return data;
|
|
153
|
+
return {
|
|
154
|
+
...data,
|
|
155
|
+
params: {
|
|
156
|
+
...data.params,
|
|
157
|
+
_auth: auth,
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
117
161
|
async useSelf(data) {
|
|
118
162
|
this.validateRunning();
|
|
163
|
+
const enriched = await this.injectAuthContext(data);
|
|
119
164
|
const request = new oRequest({
|
|
120
|
-
method:
|
|
165
|
+
method: enriched?.method,
|
|
121
166
|
params: {
|
|
122
167
|
_connectionId: 0,
|
|
123
|
-
_requestMethod:
|
|
124
|
-
...
|
|
168
|
+
_requestMethod: enriched?.method,
|
|
169
|
+
...enriched?.params,
|
|
125
170
|
},
|
|
126
171
|
id: 0,
|
|
127
172
|
});
|
|
@@ -150,6 +195,7 @@ export class oCore extends oObject {
|
|
|
150
195
|
if (!this.requestManager) {
|
|
151
196
|
throw new Error('Request manager is not initialized');
|
|
152
197
|
}
|
|
198
|
+
const enriched = await this.injectAuthContext(data);
|
|
153
199
|
// extract child address with transports
|
|
154
200
|
if (!childAddress.transports) {
|
|
155
201
|
const child = this.hierarchyManager.getChild(childAddress);
|
|
@@ -161,7 +207,7 @@ export class oCore extends oObject {
|
|
|
161
207
|
childAddress.setTransports(child?.transports || []);
|
|
162
208
|
}
|
|
163
209
|
}
|
|
164
|
-
return this.requestManager.send(childAddress,
|
|
210
|
+
return this.requestManager.send(childAddress, enriched, options, this);
|
|
165
211
|
}
|
|
166
212
|
// hierarchy
|
|
167
213
|
addChildNode(node) {
|
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.d.ts.map
CHANGED
|
@@ -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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olane/o-core",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6",
|
|
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.
|
|
66
|
+
"@olane/o-protocol": "0.8.6",
|
|
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": "
|
|
73
|
+
"gitHead": "530f7e3c8576d9427f4181b91bdfb6ae1843cffa"
|
|
74
74
|
}
|