frameio 3.2.2 → 4.1.1
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/README.md +159 -4
- package/dist/cjs/BaseClient.d.ts +4 -0
- package/dist/cjs/BaseClient.js +4 -2
- package/dist/cjs/api/resources/accountPermissions/client/Client.js +6 -6
- package/dist/cjs/api/resources/accounts/client/Client.js +13 -13
- package/dist/cjs/api/resources/comments/client/Client.js +48 -48
- package/dist/cjs/api/resources/files/client/Client.js +77 -77
- package/dist/cjs/api/resources/folders/client/Client.js +56 -56
- package/dist/cjs/api/resources/metadata/client/Client.d.ts +4 -4
- package/dist/cjs/api/resources/metadata/client/Client.js +18 -18
- package/dist/cjs/api/resources/metadata/client/requests/BulkUpdateMetadataParams.d.ts +4 -4
- package/dist/cjs/api/resources/metadataFields/client/Client.js +28 -28
- package/dist/cjs/api/resources/projectPermissions/client/Client.js +20 -20
- package/dist/cjs/api/resources/projects/client/Client.js +34 -34
- package/dist/cjs/api/resources/shares/client/Client.d.ts +4 -4
- package/dist/cjs/api/resources/shares/client/Client.js +72 -72
- package/dist/cjs/api/resources/shares/client/requests/AddAssetParams.d.ts +1 -1
- package/dist/cjs/api/resources/shares/client/requests/CreateShareParams.d.ts +2 -2
- package/dist/cjs/api/resources/shares/client/requests/UpdateShareParams.d.ts +1 -1
- package/dist/cjs/api/resources/users/client/Client.js +7 -7
- package/dist/cjs/api/resources/versionStacks/client/Client.d.ts +6 -2
- package/dist/cjs/api/resources/versionStacks/client/Client.js +48 -44
- package/dist/cjs/api/resources/versionStacks/client/requests/VersionStackCreateParams.d.ts +1 -1
- package/dist/cjs/api/resources/webhooks/client/Client.js +34 -34
- package/dist/cjs/api/resources/workspacePermissions/client/Client.js +20 -20
- package/dist/cjs/api/resources/workspaces/client/Client.js +34 -34
- package/dist/cjs/api/types/Account.d.ts +0 -2
- package/dist/cjs/api/types/AuditLogwithIncludes.d.ts +4 -0
- package/dist/cjs/api/types/AuditLogwithIncludes.js +4 -0
- package/dist/cjs/api/types/Filters.d.ts +4 -0
- package/dist/cjs/api/types/Filters.js +4 -0
- package/dist/cjs/index.d.ts +4 -0
- package/dist/cjs/index.js +21 -1
- package/dist/cjs/oauth/BaseAuth.d.ts +66 -0
- package/dist/cjs/oauth/BaseAuth.js +113 -0
- package/dist/cjs/oauth/NativeAppAuth.d.ts +32 -0
- package/dist/cjs/oauth/NativeAppAuth.js +35 -0
- package/dist/cjs/oauth/SPAAuth.d.ts +38 -0
- package/dist/cjs/oauth/SPAAuth.js +96 -0
- package/dist/cjs/oauth/ServerToServerAuth.d.ts +17 -0
- package/dist/cjs/oauth/ServerToServerAuth.js +49 -0
- package/dist/cjs/oauth/TokenManager.d.ts +83 -0
- package/dist/cjs/oauth/TokenManager.js +174 -0
- package/dist/cjs/oauth/WebAppAuth.d.ts +29 -0
- package/dist/cjs/oauth/WebAppAuth.js +88 -0
- package/dist/cjs/oauth/errors.d.ts +41 -0
- package/dist/cjs/oauth/errors.js +83 -0
- package/dist/cjs/oauth/http.d.ts +70 -0
- package/dist/cjs/oauth/http.js +280 -0
- package/dist/cjs/oauth/index.d.ts +34 -0
- package/dist/cjs/oauth/index.js +47 -0
- package/dist/cjs/oauth/logger.d.ts +17 -0
- package/dist/cjs/oauth/logger.js +18 -0
- package/dist/cjs/oauth/pkce.d.ts +30 -0
- package/dist/cjs/oauth/pkce.js +102 -0
- package/dist/cjs/oauth/validation.d.ts +17 -0
- package/dist/cjs/oauth/validation.js +55 -0
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/BaseClient.d.mts +4 -0
- package/dist/esm/BaseClient.mjs +4 -2
- package/dist/esm/api/resources/accountPermissions/client/Client.mjs +7 -7
- package/dist/esm/api/resources/accounts/client/Client.mjs +13 -13
- package/dist/esm/api/resources/comments/client/Client.mjs +49 -49
- package/dist/esm/api/resources/files/client/Client.mjs +78 -78
- package/dist/esm/api/resources/folders/client/Client.mjs +57 -57
- package/dist/esm/api/resources/metadata/client/Client.d.mts +4 -4
- package/dist/esm/api/resources/metadata/client/Client.mjs +19 -19
- package/dist/esm/api/resources/metadata/client/requests/BulkUpdateMetadataParams.d.mts +4 -4
- package/dist/esm/api/resources/metadataFields/client/Client.mjs +29 -29
- package/dist/esm/api/resources/projectPermissions/client/Client.mjs +21 -21
- package/dist/esm/api/resources/projects/client/Client.mjs +35 -35
- package/dist/esm/api/resources/shares/client/Client.d.mts +4 -4
- package/dist/esm/api/resources/shares/client/Client.mjs +73 -73
- package/dist/esm/api/resources/shares/client/requests/AddAssetParams.d.mts +1 -1
- package/dist/esm/api/resources/shares/client/requests/CreateShareParams.d.mts +2 -2
- package/dist/esm/api/resources/shares/client/requests/UpdateShareParams.d.mts +1 -1
- package/dist/esm/api/resources/users/client/Client.mjs +8 -8
- package/dist/esm/api/resources/versionStacks/client/Client.d.mts +6 -2
- package/dist/esm/api/resources/versionStacks/client/Client.mjs +49 -45
- package/dist/esm/api/resources/versionStacks/client/requests/VersionStackCreateParams.d.mts +1 -1
- package/dist/esm/api/resources/webhooks/client/Client.mjs +35 -35
- package/dist/esm/api/resources/workspacePermissions/client/Client.mjs +21 -21
- package/dist/esm/api/resources/workspaces/client/Client.mjs +35 -35
- package/dist/esm/api/types/Account.d.mts +0 -2
- package/dist/esm/api/types/AuditLogwithIncludes.d.mts +4 -0
- package/dist/esm/api/types/AuditLogwithIncludes.mjs +4 -0
- package/dist/esm/api/types/Filters.d.mts +4 -0
- package/dist/esm/api/types/Filters.mjs +4 -0
- package/dist/esm/index.d.mts +4 -0
- package/dist/esm/index.mjs +6 -0
- package/dist/esm/oauth/BaseAuth.d.mts +66 -0
- package/dist/esm/oauth/BaseAuth.mjs +109 -0
- package/dist/esm/oauth/NativeAppAuth.d.mts +32 -0
- package/dist/esm/oauth/NativeAppAuth.mjs +31 -0
- package/dist/esm/oauth/SPAAuth.d.mts +38 -0
- package/dist/esm/oauth/SPAAuth.mjs +92 -0
- package/dist/esm/oauth/ServerToServerAuth.d.mts +17 -0
- package/dist/esm/oauth/ServerToServerAuth.mjs +45 -0
- package/dist/esm/oauth/TokenManager.d.mts +83 -0
- package/dist/esm/oauth/TokenManager.mjs +170 -0
- package/dist/esm/oauth/WebAppAuth.d.mts +29 -0
- package/dist/esm/oauth/WebAppAuth.mjs +84 -0
- package/dist/esm/oauth/errors.d.mts +41 -0
- package/dist/esm/oauth/errors.mjs +72 -0
- package/dist/esm/oauth/http.d.mts +70 -0
- package/dist/esm/oauth/http.mjs +274 -0
- package/dist/esm/oauth/index.d.mts +34 -0
- package/dist/esm/oauth/index.mjs +30 -0
- package/dist/esm/oauth/logger.d.mts +17 -0
- package/dist/esm/oauth/logger.mjs +15 -0
- package/dist/esm/oauth/pkce.d.mts +30 -0
- package/dist/esm/oauth/pkce.mjs +98 -0
- package/dist/esm/oauth/validation.d.mts +17 -0
- package/dist/esm/oauth/validation.mjs +51 -0
- package/dist/esm/version.d.mts +1 -1
- package/dist/esm/version.mjs +1 -1
- package/package.json +1 -1
- package/reference.md +14 -10
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Single Page App authentication (authorization_code + PKCE).
|
|
4
|
+
*
|
|
5
|
+
* Use for browser-based apps that cannot store a client secret.
|
|
6
|
+
*/
|
|
7
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
10
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
11
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
12
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
13
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.SPAAuth = void 0;
|
|
18
|
+
const BaseAuth_1 = require("./BaseAuth");
|
|
19
|
+
const errors_1 = require("./errors");
|
|
20
|
+
const http_1 = require("./http");
|
|
21
|
+
const pkce_1 = require("./pkce");
|
|
22
|
+
const validation_1 = require("./validation");
|
|
23
|
+
class SPAAuth extends BaseAuth_1.BaseAuth {
|
|
24
|
+
constructor(options) {
|
|
25
|
+
var _a;
|
|
26
|
+
if (!options.redirectUri) {
|
|
27
|
+
throw new errors_1.ConfigurationError("redirectUri is required");
|
|
28
|
+
}
|
|
29
|
+
(0, validation_1.validateRedirectUriScheme)(options.redirectUri);
|
|
30
|
+
super(options);
|
|
31
|
+
this._redirectUri = options.redirectUri;
|
|
32
|
+
this._scopes = (_a = options.scopes) !== null && _a !== void 0 ? _a : http_1.DEFAULT_SCOPES;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build the Adobe IMS authorization URL with PKCE challenge.
|
|
36
|
+
*
|
|
37
|
+
* @returns Object with `url` and `codeVerifier` (store the verifier for exchange).
|
|
38
|
+
*/
|
|
39
|
+
getAuthorizationUrl(options) {
|
|
40
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
const codeVerifier = (0, pkce_1.generateCodeVerifier)();
|
|
42
|
+
const codeChallenge = yield (0, pkce_1.generateCodeChallenge)(codeVerifier);
|
|
43
|
+
const params = new URLSearchParams({
|
|
44
|
+
client_id: this._clientId,
|
|
45
|
+
redirect_uri: this._redirectUri,
|
|
46
|
+
scope: this._scopes,
|
|
47
|
+
response_type: "code",
|
|
48
|
+
state: options.state,
|
|
49
|
+
code_challenge: codeChallenge,
|
|
50
|
+
code_challenge_method: "S256",
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
url: `${this._authorizeUrl}?${params.toString()}`,
|
|
54
|
+
codeVerifier,
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Exchange an authorization code + PKCE verifier for tokens.
|
|
60
|
+
*/
|
|
61
|
+
exchangeCode(options) {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
const result = yield this._tokenRequest({
|
|
64
|
+
grant_type: "authorization_code",
|
|
65
|
+
client_id: this._clientId,
|
|
66
|
+
code: options.code,
|
|
67
|
+
redirect_uri: this._redirectUri,
|
|
68
|
+
code_verifier: options.codeVerifier,
|
|
69
|
+
});
|
|
70
|
+
this._storeTokens(result);
|
|
71
|
+
return result;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/** Manually trigger a token refresh. */
|
|
75
|
+
refresh() {
|
|
76
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
77
|
+
const result = yield this._refresh();
|
|
78
|
+
this._storeTokens(result);
|
|
79
|
+
return result;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
_refresh() {
|
|
83
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
84
|
+
const refreshTok = this._tokenManager.refreshTokenValue;
|
|
85
|
+
if (!refreshTok) {
|
|
86
|
+
throw new errors_1.ConfigurationError("No refresh token available. Call exchangeCode() first.");
|
|
87
|
+
}
|
|
88
|
+
return this._tokenRequest({
|
|
89
|
+
grant_type: "refresh_token",
|
|
90
|
+
client_id: this._clientId,
|
|
91
|
+
refresh_token: refreshTok,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.SPAAuth = SPAAuth;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-to-Server authentication (client_credentials grant).
|
|
3
|
+
*
|
|
4
|
+
* Use for backend services and scripts with no user interaction.
|
|
5
|
+
*/
|
|
6
|
+
import { BaseAuth, type BaseAuthOptions } from "./BaseAuth";
|
|
7
|
+
import type { TokenResponse } from "./TokenManager";
|
|
8
|
+
export interface ServerToServerAuthOptions extends BaseAuthOptions {
|
|
9
|
+
clientSecret: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class ServerToServerAuth extends BaseAuth {
|
|
12
|
+
private readonly _scopes;
|
|
13
|
+
constructor(options: ServerToServerAuthOptions);
|
|
14
|
+
/** Explicitly fetch a new access token. */
|
|
15
|
+
authenticate(): Promise<TokenResponse>;
|
|
16
|
+
protected _refresh(): Promise<TokenResponse>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Server-to-Server authentication (client_credentials grant).
|
|
4
|
+
*
|
|
5
|
+
* Use for backend services and scripts with no user interaction.
|
|
6
|
+
*/
|
|
7
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
10
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
11
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
12
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
13
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.ServerToServerAuth = void 0;
|
|
18
|
+
const BaseAuth_1 = require("./BaseAuth");
|
|
19
|
+
const errors_1 = require("./errors");
|
|
20
|
+
const http_1 = require("./http");
|
|
21
|
+
class ServerToServerAuth extends BaseAuth_1.BaseAuth {
|
|
22
|
+
constructor(options) {
|
|
23
|
+
var _a;
|
|
24
|
+
if (!options.clientSecret) {
|
|
25
|
+
throw new errors_1.ConfigurationError("clientSecret is required");
|
|
26
|
+
}
|
|
27
|
+
super(options, options.clientSecret);
|
|
28
|
+
this._scopes = (_a = options.scopes) !== null && _a !== void 0 ? _a : http_1.S2S_SCOPES;
|
|
29
|
+
}
|
|
30
|
+
/** Explicitly fetch a new access token. */
|
|
31
|
+
authenticate() {
|
|
32
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
33
|
+
const result = yield this._refresh();
|
|
34
|
+
this._storeTokens(result);
|
|
35
|
+
return result;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
_refresh() {
|
|
39
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
40
|
+
return this._tokenRequest({
|
|
41
|
+
grant_type: "client_credentials",
|
|
42
|
+
client_id: this._clientId,
|
|
43
|
+
client_secret: this._clientSecret,
|
|
44
|
+
scope: this._scopes,
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.ServerToServerAuth = ServerToServerAuth;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token lifecycle manager — the core of frameio-auth-sdk.
|
|
3
|
+
*
|
|
4
|
+
* Stores access/refresh tokens, checks expiry with a configurable buffer,
|
|
5
|
+
* and coordinates async-safe automatic refresh.
|
|
6
|
+
*/
|
|
7
|
+
import type { Logger } from "./logger";
|
|
8
|
+
/** Shape returned by refresh functions and token endpoints. */
|
|
9
|
+
export interface TokenResponse {
|
|
10
|
+
access_token: string;
|
|
11
|
+
expires_in: number;
|
|
12
|
+
refresh_token?: string;
|
|
13
|
+
token_type?: string;
|
|
14
|
+
scope?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Serialised token state for persistence. */
|
|
17
|
+
export interface ExportedTokens {
|
|
18
|
+
access_token: string | null;
|
|
19
|
+
refresh_token: string | null;
|
|
20
|
+
expires_at: number;
|
|
21
|
+
}
|
|
22
|
+
/** A function that performs the actual token refresh / fetch. */
|
|
23
|
+
export type RefreshFunction = () => Promise<TokenResponse>;
|
|
24
|
+
/** Optional callback fired after every successful token refresh. */
|
|
25
|
+
export type OnTokenRefreshed = (tokens: ExportedTokens) => void;
|
|
26
|
+
export interface TokenManagerOptions {
|
|
27
|
+
refreshFunc: RefreshFunction;
|
|
28
|
+
/** Seconds before actual expiry to trigger proactive refresh. Default: 60. */
|
|
29
|
+
refreshBuffer?: number;
|
|
30
|
+
/** Called after every successful refresh. */
|
|
31
|
+
onTokenRefreshed?: OnTokenRefreshed;
|
|
32
|
+
/** Logger instance for diagnostic output. */
|
|
33
|
+
logger?: Logger;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Manages token storage, expiry detection, and auto-refresh.
|
|
37
|
+
*
|
|
38
|
+
* Pass `manager.getToken` (bound) to the Frame.io SDK:
|
|
39
|
+
* ```ts
|
|
40
|
+
* const client = new FrameioClient({ token: () => auth.getToken() });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare class TokenManager {
|
|
44
|
+
private _refreshFunc;
|
|
45
|
+
private _refreshBuffer;
|
|
46
|
+
private _onTokenRefreshed?;
|
|
47
|
+
private _logger;
|
|
48
|
+
private _accessToken;
|
|
49
|
+
private _refreshToken;
|
|
50
|
+
private _expiresAt;
|
|
51
|
+
/** In-flight refresh promise for deduplication. */
|
|
52
|
+
private _refreshPromise;
|
|
53
|
+
/** Set by clear() to prevent an in-flight refresh from restoring tokens. */
|
|
54
|
+
private _revoked;
|
|
55
|
+
constructor(options: TokenManagerOptions);
|
|
56
|
+
/**
|
|
57
|
+
* Return a valid access token, refreshing if necessary.
|
|
58
|
+
*
|
|
59
|
+
* Safe to call concurrently — only one refresh request will fire.
|
|
60
|
+
*/
|
|
61
|
+
getToken(): Promise<string>;
|
|
62
|
+
get accessToken(): string | null;
|
|
63
|
+
get refreshTokenValue(): string | null;
|
|
64
|
+
get expiresAt(): number;
|
|
65
|
+
get isExpired(): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Manually set token data (e.g. after initial code exchange).
|
|
68
|
+
*/
|
|
69
|
+
setTokens(accessToken: string, expiresIn: number, refreshToken?: string): void;
|
|
70
|
+
/** Export current token state for persistence. */
|
|
71
|
+
exportTokens(): ExportedTokens;
|
|
72
|
+
/** Restore token state from a previously exported object. */
|
|
73
|
+
importTokens(data: ExportedTokens): void;
|
|
74
|
+
/** Clear all stored tokens and cancel any in-flight refresh. */
|
|
75
|
+
clear(): void;
|
|
76
|
+
private _isTokenValid;
|
|
77
|
+
/**
|
|
78
|
+
* Async-safe refresh: if a refresh is already in flight, await the
|
|
79
|
+
* existing promise instead of firing a second request.
|
|
80
|
+
*/
|
|
81
|
+
private _doRefresh;
|
|
82
|
+
private _executeRefresh;
|
|
83
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Token lifecycle manager — the core of frameio-auth-sdk.
|
|
4
|
+
*
|
|
5
|
+
* Stores access/refresh tokens, checks expiry with a configurable buffer,
|
|
6
|
+
* and coordinates async-safe automatic refresh.
|
|
7
|
+
*/
|
|
8
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
9
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
10
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
11
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
12
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
13
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
14
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.TokenManager = void 0;
|
|
19
|
+
const errors_1 = require("./errors");
|
|
20
|
+
const logger_1 = require("./logger");
|
|
21
|
+
const validation_1 = require("./validation");
|
|
22
|
+
/**
|
|
23
|
+
* Manages token storage, expiry detection, and auto-refresh.
|
|
24
|
+
*
|
|
25
|
+
* Pass `manager.getToken` (bound) to the Frame.io SDK:
|
|
26
|
+
* ```ts
|
|
27
|
+
* const client = new FrameioClient({ token: () => auth.getToken() });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
class TokenManager {
|
|
31
|
+
constructor(options) {
|
|
32
|
+
var _a, _b;
|
|
33
|
+
this._accessToken = null;
|
|
34
|
+
this._refreshToken = null;
|
|
35
|
+
this._expiresAt = 0;
|
|
36
|
+
/** In-flight refresh promise for deduplication. */
|
|
37
|
+
this._refreshPromise = null;
|
|
38
|
+
/** Set by clear() to prevent an in-flight refresh from restoring tokens. */
|
|
39
|
+
this._revoked = false;
|
|
40
|
+
this._refreshFunc = options.refreshFunc;
|
|
41
|
+
this._refreshBuffer = (_a = options.refreshBuffer) !== null && _a !== void 0 ? _a : 60;
|
|
42
|
+
this._onTokenRefreshed = options.onTokenRefreshed;
|
|
43
|
+
this._logger = (_b = options.logger) !== null && _b !== void 0 ? _b : logger_1.noopLogger;
|
|
44
|
+
}
|
|
45
|
+
// ------------------------------------------------------------------
|
|
46
|
+
// Public API
|
|
47
|
+
// ------------------------------------------------------------------
|
|
48
|
+
/**
|
|
49
|
+
* Return a valid access token, refreshing if necessary.
|
|
50
|
+
*
|
|
51
|
+
* Safe to call concurrently — only one refresh request will fire.
|
|
52
|
+
*/
|
|
53
|
+
getToken() {
|
|
54
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
55
|
+
if (this._isTokenValid()) {
|
|
56
|
+
return this._accessToken;
|
|
57
|
+
}
|
|
58
|
+
return this._doRefresh();
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
get accessToken() {
|
|
62
|
+
return this._accessToken;
|
|
63
|
+
}
|
|
64
|
+
get refreshTokenValue() {
|
|
65
|
+
return this._refreshToken;
|
|
66
|
+
}
|
|
67
|
+
get expiresAt() {
|
|
68
|
+
return this._expiresAt;
|
|
69
|
+
}
|
|
70
|
+
get isExpired() {
|
|
71
|
+
return !this._isTokenValid();
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Manually set token data (e.g. after initial code exchange).
|
|
75
|
+
*/
|
|
76
|
+
setTokens(accessToken, expiresIn, refreshToken) {
|
|
77
|
+
this._revoked = false;
|
|
78
|
+
this._accessToken = accessToken;
|
|
79
|
+
this._expiresAt = Date.now() / 1000 + expiresIn;
|
|
80
|
+
if (refreshToken !== undefined) {
|
|
81
|
+
this._refreshToken = refreshToken;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** Export current token state for persistence. */
|
|
85
|
+
exportTokens() {
|
|
86
|
+
return {
|
|
87
|
+
access_token: this._accessToken,
|
|
88
|
+
refresh_token: this._refreshToken,
|
|
89
|
+
expires_at: this._expiresAt,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/** Restore token state from a previously exported object. */
|
|
93
|
+
importTokens(data) {
|
|
94
|
+
var _a;
|
|
95
|
+
(0, validation_1.validateTokenImport)(data);
|
|
96
|
+
this._revoked = false;
|
|
97
|
+
this._accessToken = data.access_token;
|
|
98
|
+
this._refreshToken = data.refresh_token;
|
|
99
|
+
this._expiresAt = (_a = data.expires_at) !== null && _a !== void 0 ? _a : 0;
|
|
100
|
+
}
|
|
101
|
+
/** Clear all stored tokens and cancel any in-flight refresh. */
|
|
102
|
+
clear() {
|
|
103
|
+
this._accessToken = null;
|
|
104
|
+
this._refreshToken = null;
|
|
105
|
+
this._expiresAt = 0;
|
|
106
|
+
this._refreshPromise = null;
|
|
107
|
+
this._revoked = true;
|
|
108
|
+
}
|
|
109
|
+
// ------------------------------------------------------------------
|
|
110
|
+
// Internals
|
|
111
|
+
// ------------------------------------------------------------------
|
|
112
|
+
_isTokenValid() {
|
|
113
|
+
return this._accessToken !== null && Date.now() / 1000 < this._expiresAt - this._refreshBuffer;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Async-safe refresh: if a refresh is already in flight, await the
|
|
117
|
+
* existing promise instead of firing a second request.
|
|
118
|
+
*/
|
|
119
|
+
_doRefresh() {
|
|
120
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
121
|
+
if (this._refreshPromise) {
|
|
122
|
+
return this._refreshPromise;
|
|
123
|
+
}
|
|
124
|
+
this._refreshPromise = this._executeRefresh();
|
|
125
|
+
try {
|
|
126
|
+
return yield this._refreshPromise;
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
this._refreshPromise = null;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
_executeRefresh() {
|
|
134
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
135
|
+
var _a;
|
|
136
|
+
let result;
|
|
137
|
+
this._logger.debug("Token refresh triggered.");
|
|
138
|
+
try {
|
|
139
|
+
result = yield this._refreshFunc();
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
if (err instanceof errors_1.AuthenticationError ||
|
|
143
|
+
err instanceof errors_1.TokenExpiredError ||
|
|
144
|
+
err instanceof errors_1.NetworkError ||
|
|
145
|
+
err instanceof errors_1.RateLimitError) {
|
|
146
|
+
throw err;
|
|
147
|
+
}
|
|
148
|
+
throw new errors_1.AuthenticationError("refresh_failed", (0, errors_1.sanitizeMessage)(`Token refresh failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
149
|
+
}
|
|
150
|
+
// If clear() was called while the refresh was in flight (e.g. via
|
|
151
|
+
// revoke()), do not overwrite the cleared state with new tokens.
|
|
152
|
+
if (this._revoked) {
|
|
153
|
+
throw new errors_1.AuthenticationError("revoked", "Tokens were revoked during refresh.");
|
|
154
|
+
}
|
|
155
|
+
const token = result.access_token;
|
|
156
|
+
this._accessToken = token;
|
|
157
|
+
this._expiresAt = Date.now() / 1000 + ((_a = result.expires_in) !== null && _a !== void 0 ? _a : 86400);
|
|
158
|
+
if (result.refresh_token) {
|
|
159
|
+
this._refreshToken = result.refresh_token;
|
|
160
|
+
}
|
|
161
|
+
this._logger.info(`Token refreshed (length=${token.length}).`);
|
|
162
|
+
if (this._onTokenRefreshed) {
|
|
163
|
+
try {
|
|
164
|
+
this._onTokenRefreshed(this.exportTokens());
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
this._logger.warn(`onTokenRefreshed callback raised: ${err}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return token;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
exports.TokenManager = TokenManager;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web App authentication (authorization_code grant).
|
|
3
|
+
*
|
|
4
|
+
* Use for server-side applications that can securely store a client secret.
|
|
5
|
+
*/
|
|
6
|
+
import { BaseAuth, type BaseAuthOptions } from "./BaseAuth";
|
|
7
|
+
import type { TokenResponse } from "./TokenManager";
|
|
8
|
+
export interface WebAppAuthOptions extends BaseAuthOptions {
|
|
9
|
+
clientSecret: string;
|
|
10
|
+
redirectUri: string;
|
|
11
|
+
}
|
|
12
|
+
export declare class WebAppAuth extends BaseAuth {
|
|
13
|
+
private readonly _redirectUri;
|
|
14
|
+
private readonly _scopes;
|
|
15
|
+
constructor(options: WebAppAuthOptions);
|
|
16
|
+
/**
|
|
17
|
+
* Build the Adobe IMS authorization URL.
|
|
18
|
+
*
|
|
19
|
+
* @param options.state - An opaque CSRF/state value.
|
|
20
|
+
*/
|
|
21
|
+
getAuthorizationUrl(options: {
|
|
22
|
+
state: string;
|
|
23
|
+
}): string;
|
|
24
|
+
/** Exchange an authorization code for access and refresh tokens. */
|
|
25
|
+
exchangeCode(code: string): Promise<TokenResponse>;
|
|
26
|
+
/** Manually trigger a token refresh. */
|
|
27
|
+
refresh(): Promise<TokenResponse>;
|
|
28
|
+
protected _refresh(): Promise<TokenResponse>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Web App authentication (authorization_code grant).
|
|
4
|
+
*
|
|
5
|
+
* Use for server-side applications that can securely store a client secret.
|
|
6
|
+
*/
|
|
7
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
10
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
11
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
12
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
13
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.WebAppAuth = void 0;
|
|
18
|
+
const BaseAuth_1 = require("./BaseAuth");
|
|
19
|
+
const errors_1 = require("./errors");
|
|
20
|
+
const http_1 = require("./http");
|
|
21
|
+
const validation_1 = require("./validation");
|
|
22
|
+
class WebAppAuth extends BaseAuth_1.BaseAuth {
|
|
23
|
+
constructor(options) {
|
|
24
|
+
var _a;
|
|
25
|
+
if (!options.clientSecret) {
|
|
26
|
+
throw new errors_1.ConfigurationError("clientSecret is required");
|
|
27
|
+
}
|
|
28
|
+
if (!options.redirectUri) {
|
|
29
|
+
throw new errors_1.ConfigurationError("redirectUri is required");
|
|
30
|
+
}
|
|
31
|
+
(0, validation_1.validateRedirectUriScheme)(options.redirectUri);
|
|
32
|
+
super(options, options.clientSecret);
|
|
33
|
+
this._redirectUri = options.redirectUri;
|
|
34
|
+
this._scopes = (_a = options.scopes) !== null && _a !== void 0 ? _a : http_1.DEFAULT_SCOPES;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build the Adobe IMS authorization URL.
|
|
38
|
+
*
|
|
39
|
+
* @param options.state - An opaque CSRF/state value.
|
|
40
|
+
*/
|
|
41
|
+
getAuthorizationUrl(options) {
|
|
42
|
+
const params = new URLSearchParams({
|
|
43
|
+
client_id: this._clientId,
|
|
44
|
+
redirect_uri: this._redirectUri,
|
|
45
|
+
scope: this._scopes,
|
|
46
|
+
response_type: "code",
|
|
47
|
+
state: options.state,
|
|
48
|
+
});
|
|
49
|
+
return `${this._authorizeUrl}?${params.toString()}`;
|
|
50
|
+
}
|
|
51
|
+
/** Exchange an authorization code for access and refresh tokens. */
|
|
52
|
+
exchangeCode(code) {
|
|
53
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
54
|
+
const result = yield this._tokenRequest({
|
|
55
|
+
grant_type: "authorization_code",
|
|
56
|
+
client_id: this._clientId,
|
|
57
|
+
client_secret: this._clientSecret,
|
|
58
|
+
code,
|
|
59
|
+
redirect_uri: this._redirectUri,
|
|
60
|
+
});
|
|
61
|
+
this._storeTokens(result);
|
|
62
|
+
return result;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/** Manually trigger a token refresh. */
|
|
66
|
+
refresh() {
|
|
67
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
68
|
+
const result = yield this._refresh();
|
|
69
|
+
this._storeTokens(result);
|
|
70
|
+
return result;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
_refresh() {
|
|
74
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
const refreshTok = this._tokenManager.refreshTokenValue;
|
|
76
|
+
if (!refreshTok) {
|
|
77
|
+
throw new errors_1.ConfigurationError("No refresh token available. Call exchangeCode() first.");
|
|
78
|
+
}
|
|
79
|
+
return this._tokenRequest({
|
|
80
|
+
grant_type: "refresh_token",
|
|
81
|
+
client_id: this._clientId,
|
|
82
|
+
client_secret: this._clientSecret,
|
|
83
|
+
refresh_token: refreshTok,
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.WebAppAuth = WebAppAuth;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error types for frameio-auth-sdk.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Strip JWT-like tokens from error messages to prevent token leakage.
|
|
6
|
+
*
|
|
7
|
+
* Redacts strings matching the JWT prefix pattern (eyJ followed by 10+
|
|
8
|
+
* base64url characters). This covers Adobe IMS access and refresh tokens.
|
|
9
|
+
*/
|
|
10
|
+
export declare function sanitizeMessage(msg: string): string;
|
|
11
|
+
/** Base error for all frameio-auth-sdk errors. */
|
|
12
|
+
export declare class FrameioAuthError extends Error {
|
|
13
|
+
constructor(message: string);
|
|
14
|
+
}
|
|
15
|
+
/** Raised when token exchange or refresh fails. */
|
|
16
|
+
export declare class AuthenticationError extends FrameioAuthError {
|
|
17
|
+
readonly errorCode: string;
|
|
18
|
+
readonly errorDescription?: string;
|
|
19
|
+
constructor(errorCode: string, errorDescription?: string);
|
|
20
|
+
}
|
|
21
|
+
/** Raised when the refresh token is expired and re-authentication is required. */
|
|
22
|
+
export declare class TokenExpiredError extends FrameioAuthError {
|
|
23
|
+
constructor(message?: string);
|
|
24
|
+
}
|
|
25
|
+
/** Raised when a network request fails (timeout, connection error, etc.). */
|
|
26
|
+
export declare class NetworkError extends FrameioAuthError {
|
|
27
|
+
constructor(message?: string);
|
|
28
|
+
}
|
|
29
|
+
/** Raised when the API returns 429 Too Many Requests and retries are exhausted. */
|
|
30
|
+
export declare class RateLimitError extends FrameioAuthError {
|
|
31
|
+
readonly retryAfter: number | undefined;
|
|
32
|
+
constructor(retryAfter?: number);
|
|
33
|
+
}
|
|
34
|
+
/** Raised when PKCE verification fails. */
|
|
35
|
+
export declare class PKCEError extends FrameioAuthError {
|
|
36
|
+
constructor(message?: string);
|
|
37
|
+
}
|
|
38
|
+
/** Raised when required configuration is missing or invalid. */
|
|
39
|
+
export declare class ConfigurationError extends FrameioAuthError {
|
|
40
|
+
constructor(message: string);
|
|
41
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Custom error types for frameio-auth-sdk.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ConfigurationError = exports.PKCEError = exports.RateLimitError = exports.NetworkError = exports.TokenExpiredError = exports.AuthenticationError = exports.FrameioAuthError = void 0;
|
|
7
|
+
exports.sanitizeMessage = sanitizeMessage;
|
|
8
|
+
/** Pattern to detect JWT-like tokens (eyJ...) in error messages. */
|
|
9
|
+
const JWT_PATTERN = /eyJ[A-Za-z0-9_-]{10,}/g;
|
|
10
|
+
/**
|
|
11
|
+
* Strip JWT-like tokens from error messages to prevent token leakage.
|
|
12
|
+
*
|
|
13
|
+
* Redacts strings matching the JWT prefix pattern (eyJ followed by 10+
|
|
14
|
+
* base64url characters). This covers Adobe IMS access and refresh tokens.
|
|
15
|
+
*/
|
|
16
|
+
function sanitizeMessage(msg) {
|
|
17
|
+
return msg.replace(JWT_PATTERN, "[REDACTED]");
|
|
18
|
+
}
|
|
19
|
+
/** Base error for all frameio-auth-sdk errors. */
|
|
20
|
+
class FrameioAuthError extends Error {
|
|
21
|
+
constructor(message) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = "FrameioAuthError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.FrameioAuthError = FrameioAuthError;
|
|
27
|
+
/** Raised when token exchange or refresh fails. */
|
|
28
|
+
class AuthenticationError extends FrameioAuthError {
|
|
29
|
+
constructor(errorCode, errorDescription) {
|
|
30
|
+
const desc = errorDescription ? sanitizeMessage(errorDescription) : undefined;
|
|
31
|
+
const msg = desc ? `${errorCode} — ${desc}` : errorCode;
|
|
32
|
+
super(msg);
|
|
33
|
+
this.name = "AuthenticationError";
|
|
34
|
+
this.errorCode = errorCode;
|
|
35
|
+
this.errorDescription = desc;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.AuthenticationError = AuthenticationError;
|
|
39
|
+
/** Raised when the refresh token is expired and re-authentication is required. */
|
|
40
|
+
class TokenExpiredError extends FrameioAuthError {
|
|
41
|
+
constructor(message = "Refresh token expired. Re-authentication required.") {
|
|
42
|
+
super(sanitizeMessage(message));
|
|
43
|
+
this.name = "TokenExpiredError";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.TokenExpiredError = TokenExpiredError;
|
|
47
|
+
/** Raised when a network request fails (timeout, connection error, etc.). */
|
|
48
|
+
class NetworkError extends FrameioAuthError {
|
|
49
|
+
constructor(message = "Network request failed.") {
|
|
50
|
+
super(message);
|
|
51
|
+
this.name = "NetworkError";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.NetworkError = NetworkError;
|
|
55
|
+
/** Raised when the API returns 429 Too Many Requests and retries are exhausted. */
|
|
56
|
+
class RateLimitError extends FrameioAuthError {
|
|
57
|
+
constructor(retryAfter) {
|
|
58
|
+
let msg = "Rate limited by Adobe IMS.";
|
|
59
|
+
if (retryAfter !== undefined) {
|
|
60
|
+
msg += ` Retry after ${Math.round(retryAfter)}s.`;
|
|
61
|
+
}
|
|
62
|
+
super(msg);
|
|
63
|
+
this.name = "RateLimitError";
|
|
64
|
+
this.retryAfter = retryAfter;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.RateLimitError = RateLimitError;
|
|
68
|
+
/** Raised when PKCE verification fails. */
|
|
69
|
+
class PKCEError extends FrameioAuthError {
|
|
70
|
+
constructor(message = "PKCE verification failed.") {
|
|
71
|
+
super(message);
|
|
72
|
+
this.name = "PKCEError";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.PKCEError = PKCEError;
|
|
76
|
+
/** Raised when required configuration is missing or invalid. */
|
|
77
|
+
class ConfigurationError extends FrameioAuthError {
|
|
78
|
+
constructor(message) {
|
|
79
|
+
super(message);
|
|
80
|
+
this.name = "ConfigurationError";
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.ConfigurationError = ConfigurationError;
|