@payloadcms/figma 0.0.1-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +11 -0
- package/bin/cli.js +4 -0
- package/dist/api/control-plane.d.ts +124 -0
- package/dist/api/control-plane.d.ts.map +1 -0
- package/dist/api/control-plane.js +245 -0
- package/dist/api/control-plane.js.map +1 -0
- package/dist/api/control-plane.spec.d.ts +2 -0
- package/dist/api/control-plane.spec.d.ts.map +1 -0
- package/dist/api/control-plane.spec.js +296 -0
- package/dist/api/control-plane.spec.js.map +1 -0
- package/dist/api/figma-api.d.ts +31 -0
- package/dist/api/figma-api.d.ts.map +1 -0
- package/dist/api/figma-api.js +169 -0
- package/dist/api/figma-api.js.map +1 -0
- package/dist/api/figma-api.spec.d.ts +14 -0
- package/dist/api/figma-api.spec.d.ts.map +1 -0
- package/dist/api/figma-api.spec.js +201 -0
- package/dist/api/figma-api.spec.js.map +1 -0
- package/dist/auth/__tests__/fixtures.d.ts +26 -0
- package/dist/auth/__tests__/fixtures.d.ts.map +1 -0
- package/dist/auth/__tests__/fixtures.js +67 -0
- package/dist/auth/__tests__/fixtures.js.map +1 -0
- package/dist/auth/__tests__/mocks.d.ts +33 -0
- package/dist/auth/__tests__/mocks.d.ts.map +1 -0
- package/dist/auth/__tests__/mocks.js +63 -0
- package/dist/auth/__tests__/mocks.js.map +1 -0
- package/dist/auth/browser.d.ts +31 -0
- package/dist/auth/browser.d.ts.map +1 -0
- package/dist/auth/browser.js +41 -0
- package/dist/auth/browser.js.map +1 -0
- package/dist/auth/callback-server.d.ts +61 -0
- package/dist/auth/callback-server.d.ts.map +1 -0
- package/dist/auth/callback-server.js +168 -0
- package/dist/auth/callback-server.js.map +1 -0
- package/dist/auth/callback-server.spec.d.ts +2 -0
- package/dist/auth/callback-server.spec.d.ts.map +1 -0
- package/dist/auth/callback-server.spec.js +85 -0
- package/dist/auth/callback-server.spec.js.map +1 -0
- package/dist/auth/crypto-utils.d.ts +33 -0
- package/dist/auth/crypto-utils.d.ts.map +1 -0
- package/dist/auth/crypto-utils.js +96 -0
- package/dist/auth/crypto-utils.js.map +1 -0
- package/dist/auth/crypto-utils.spec.d.ts +2 -0
- package/dist/auth/crypto-utils.spec.d.ts.map +1 -0
- package/dist/auth/crypto-utils.spec.js +36 -0
- package/dist/auth/crypto-utils.spec.js.map +1 -0
- package/dist/auth/jwt-validator.d.ts +41 -0
- package/dist/auth/jwt-validator.d.ts.map +1 -0
- package/dist/auth/jwt-validator.js +113 -0
- package/dist/auth/jwt-validator.js.map +1 -0
- package/dist/auth/jwt-validator.spec.d.ts +10 -0
- package/dist/auth/jwt-validator.spec.d.ts.map +1 -0
- package/dist/auth/jwt-validator.spec.js +236 -0
- package/dist/auth/jwt-validator.spec.js.map +1 -0
- package/dist/auth/oauth-flow.d.ts +62 -0
- package/dist/auth/oauth-flow.d.ts.map +1 -0
- package/dist/auth/oauth-flow.js +172 -0
- package/dist/auth/oauth-flow.js.map +1 -0
- package/dist/auth/oauth-flow.spec.d.ts +2 -0
- package/dist/auth/oauth-flow.spec.d.ts.map +1 -0
- package/dist/auth/oauth-flow.spec.js +134 -0
- package/dist/auth/oauth-flow.spec.js.map +1 -0
- package/dist/auth/pages/error.html +85 -0
- package/dist/auth/pages/success.html +74 -0
- package/dist/auth/pkce.d.ts +51 -0
- package/dist/auth/pkce.d.ts.map +1 -0
- package/dist/auth/pkce.js +71 -0
- package/dist/auth/pkce.js.map +1 -0
- package/dist/auth/pkce.spec.d.ts +2 -0
- package/dist/auth/pkce.spec.d.ts.map +1 -0
- package/dist/auth/pkce.spec.js +32 -0
- package/dist/auth/pkce.spec.js.map +1 -0
- package/dist/auth/project-token.d.ts +47 -0
- package/dist/auth/project-token.d.ts.map +1 -0
- package/dist/auth/project-token.js +134 -0
- package/dist/auth/project-token.js.map +1 -0
- package/dist/auth/project-token.spec.d.ts +2 -0
- package/dist/auth/project-token.spec.d.ts.map +1 -0
- package/dist/auth/project-token.spec.js +332 -0
- package/dist/auth/project-token.spec.js.map +1 -0
- package/dist/auth/refresh.d.ts +35 -0
- package/dist/auth/refresh.d.ts.map +1 -0
- package/dist/auth/refresh.js +149 -0
- package/dist/auth/refresh.js.map +1 -0
- package/dist/auth/refresh.spec.d.ts +2 -0
- package/dist/auth/refresh.spec.d.ts.map +1 -0
- package/dist/auth/refresh.spec.js +105 -0
- package/dist/auth/refresh.spec.js.map +1 -0
- package/dist/auth/token-store.d.ts +110 -0
- package/dist/auth/token-store.d.ts.map +1 -0
- package/dist/auth/token-store.js +188 -0
- package/dist/auth/token-store.js.map +1 -0
- package/dist/auth/token-store.spec.d.ts +2 -0
- package/dist/auth/token-store.spec.d.ts.map +1 -0
- package/dist/auth/token-store.spec.js +276 -0
- package/dist/auth/token-store.spec.js.map +1 -0
- package/dist/auth/types.d.ts +197 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +6 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +108 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/__tests__/test-utils.d.ts +28 -0
- package/dist/commands/__tests__/test-utils.d.ts.map +1 -0
- package/dist/commands/__tests__/test-utils.js +34 -0
- package/dist/commands/__tests__/test-utils.js.map +1 -0
- package/dist/commands/deploy.d.ts +16 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +297 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/deploy.spec.d.ts +2 -0
- package/dist/commands/deploy.spec.d.ts.map +1 -0
- package/dist/commands/deploy.spec.js +18 -0
- package/dist/commands/deploy.spec.js.map +1 -0
- package/dist/commands/init.d.ts +30 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +410 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/init.spec.d.ts +2 -0
- package/dist/commands/init.spec.d.ts.map +1 -0
- package/dist/commands/init.spec.js +283 -0
- package/dist/commands/init.spec.js.map +1 -0
- package/dist/commands/list-tokens.d.ts +16 -0
- package/dist/commands/list-tokens.d.ts.map +1 -0
- package/dist/commands/list-tokens.js +44 -0
- package/dist/commands/list-tokens.js.map +1 -0
- package/dist/commands/login.d.ts +17 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +69 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +16 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +43 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/config/oauth.d.ts +19 -0
- package/dist/config/oauth.d.ts.map +1 -0
- package/dist/config/oauth.js +43 -0
- package/dist/config/oauth.js.map +1 -0
- package/dist/constants.d.ts +27 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +27 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin/adapter.d.ts +5 -0
- package/dist/plugin/adapter.d.ts.map +1 -0
- package/dist/plugin/adapter.js +139 -0
- package/dist/plugin/adapter.js.map +1 -0
- package/dist/plugin/build-config.d.ts +37 -0
- package/dist/plugin/build-config.d.ts.map +1 -0
- package/dist/plugin/build-config.js +25 -0
- package/dist/plugin/build-config.js.map +1 -0
- package/dist/plugin/build-config.spec.d.ts +2 -0
- package/dist/plugin/build-config.spec.d.ts.map +1 -0
- package/dist/plugin/build-config.spec.js +72 -0
- package/dist/plugin/build-config.spec.js.map +1 -0
- package/dist/types/config.d.ts +45 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +9 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/asset-collection.d.ts +30 -0
- package/dist/utils/asset-collection.d.ts.map +1 -0
- package/dist/utils/asset-collection.js +117 -0
- package/dist/utils/asset-collection.js.map +1 -0
- package/dist/utils/asset-collection.spec.d.ts +2 -0
- package/dist/utils/asset-collection.spec.d.ts.map +1 -0
- package/dist/utils/asset-collection.spec.js +155 -0
- package/dist/utils/asset-collection.spec.js.map +1 -0
- package/dist/utils/build-detection.d.ts +32 -0
- package/dist/utils/build-detection.d.ts.map +1 -0
- package/dist/utils/build-detection.js +55 -0
- package/dist/utils/build-detection.js.map +1 -0
- package/dist/utils/build-detection.spec.d.ts +2 -0
- package/dist/utils/build-detection.spec.d.ts.map +1 -0
- package/dist/utils/build-detection.spec.js +110 -0
- package/dist/utils/build-detection.spec.js.map +1 -0
- package/dist/utils/config.d.ts +33 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +78 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/config.spec.d.ts +2 -0
- package/dist/utils/config.spec.d.ts.map +1 -0
- package/dist/utils/config.spec.js +167 -0
- package/dist/utils/config.spec.js.map +1 -0
- package/dist/utils/download-template.d.ts +15 -0
- package/dist/utils/download-template.d.ts.map +1 -0
- package/dist/utils/download-template.js +74 -0
- package/dist/utils/download-template.js.map +1 -0
- package/dist/utils/download-template.spec.d.ts +2 -0
- package/dist/utils/download-template.spec.d.ts.map +1 -0
- package/dist/utils/download-template.spec.js +76 -0
- package/dist/utils/download-template.spec.js.map +1 -0
- package/dist/utils/env-management.d.ts +16 -0
- package/dist/utils/env-management.d.ts.map +1 -0
- package/dist/utils/env-management.js +98 -0
- package/dist/utils/env-management.js.map +1 -0
- package/dist/utils/env-management.spec.d.ts +2 -0
- package/dist/utils/env-management.spec.d.ts.map +1 -0
- package/dist/utils/env-management.spec.js +123 -0
- package/dist/utils/env-management.spec.js.map +1 -0
- package/dist/utils/format.d.ts +23 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +49 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/formatter.d.ts +11 -0
- package/dist/utils/formatter.d.ts.map +1 -0
- package/dist/utils/formatter.js +47 -0
- package/dist/utils/formatter.js.map +1 -0
- package/dist/utils/git.d.ts +15 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +92 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/git.spec.d.ts +2 -0
- package/dist/utils/git.spec.d.ts.map +1 -0
- package/dist/utils/git.spec.js +99 -0
- package/dist/utils/git.spec.js.map +1 -0
- package/dist/utils/is-debug.d.ts +6 -0
- package/dist/utils/is-debug.d.ts.map +1 -0
- package/dist/utils/is-debug.js +8 -0
- package/dist/utils/is-debug.js.map +1 -0
- package/dist/utils/lambda-config.d.ts +7 -0
- package/dist/utils/lambda-config.d.ts.map +1 -0
- package/dist/utils/lambda-config.js +144 -0
- package/dist/utils/lambda-config.js.map +1 -0
- package/dist/utils/lambda-config.spec.d.ts +2 -0
- package/dist/utils/lambda-config.spec.d.ts.map +1 -0
- package/dist/utils/lambda-config.spec.js +141 -0
- package/dist/utils/lambda-config.spec.js.map +1 -0
- package/dist/utils/log.d.ts +6 -0
- package/dist/utils/log.d.ts.map +1 -0
- package/dist/utils/log.js +22 -0
- package/dist/utils/log.js.map +1 -0
- package/dist/utils/messages.d.ts +10 -0
- package/dist/utils/messages.d.ts.map +1 -0
- package/dist/utils/messages.js +96 -0
- package/dist/utils/messages.js.map +1 -0
- package/dist/utils/package-manager.d.ts +12 -0
- package/dist/utils/package-manager.d.ts.map +1 -0
- package/dist/utils/package-manager.js +37 -0
- package/dist/utils/package-manager.js.map +1 -0
- package/dist/utils/payload-config-ast.d.ts +30 -0
- package/dist/utils/payload-config-ast.d.ts.map +1 -0
- package/dist/utils/payload-config-ast.js +259 -0
- package/dist/utils/payload-config-ast.js.map +1 -0
- package/dist/utils/payload-config-ast.spec.d.ts +2 -0
- package/dist/utils/payload-config-ast.spec.d.ts.map +1 -0
- package/dist/utils/payload-config-ast.spec.js +303 -0
- package/dist/utils/payload-config-ast.spec.js.map +1 -0
- package/dist/utils/payload-config-finder.d.ts +9 -0
- package/dist/utils/payload-config-finder.d.ts.map +1 -0
- package/dist/utils/payload-config-finder.js +26 -0
- package/dist/utils/payload-config-finder.js.map +1 -0
- package/dist/utils/payload-config-modifier.d.ts +18 -0
- package/dist/utils/payload-config-modifier.d.ts.map +1 -0
- package/dist/utils/payload-config-modifier.int.spec.d.ts +2 -0
- package/dist/utils/payload-config-modifier.int.spec.d.ts.map +1 -0
- package/dist/utils/payload-config-modifier.int.spec.js +116 -0
- package/dist/utils/payload-config-modifier.int.spec.js.map +1 -0
- package/dist/utils/payload-config-modifier.js +232 -0
- package/dist/utils/payload-config-modifier.js.map +1 -0
- package/dist/utils/payload-config-modifier.spec.d.ts +2 -0
- package/dist/utils/payload-config-modifier.spec.d.ts.map +1 -0
- package/dist/utils/payload-config-modifier.spec.js +162 -0
- package/dist/utils/payload-config-modifier.spec.js.map +1 -0
- package/dist/utils/payload-package-check.d.ts +15 -0
- package/dist/utils/payload-package-check.d.ts.map +1 -0
- package/dist/utils/payload-package-check.js +116 -0
- package/dist/utils/payload-package-check.js.map +1 -0
- package/dist/utils/payload-package-check.spec.d.ts +2 -0
- package/dist/utils/payload-package-check.spec.d.ts.map +1 -0
- package/dist/utils/payload-package-check.spec.js +148 -0
- package/dist/utils/payload-package-check.spec.js.map +1 -0
- package/dist/utils/project.d.ts +58 -0
- package/dist/utils/project.d.ts.map +1 -0
- package/dist/utils/project.js +252 -0
- package/dist/utils/project.js.map +1 -0
- package/dist/utils/project.spec.d.ts +2 -0
- package/dist/utils/project.spec.d.ts.map +1 -0
- package/dist/utils/project.spec.js +222 -0
- package/dist/utils/project.spec.js.map +1 -0
- package/dist/utils/s3-upload.d.ts +43 -0
- package/dist/utils/s3-upload.d.ts.map +1 -0
- package/dist/utils/s3-upload.js +128 -0
- package/dist/utils/s3-upload.js.map +1 -0
- package/dist/utils/s3-upload.spec.d.ts +2 -0
- package/dist/utils/s3-upload.spec.d.ts.map +1 -0
- package/dist/utils/s3-upload.spec.js +140 -0
- package/dist/utils/s3-upload.spec.js.map +1 -0
- package/dist/utils/token-display.d.ts +14 -0
- package/dist/utils/token-display.d.ts.map +1 -0
- package/dist/utils/token-display.js +62 -0
- package/dist/utils/token-display.js.map +1 -0
- package/dist/utils/typescript-validator.d.ts +11 -0
- package/dist/utils/typescript-validator.d.ts.map +1 -0
- package/dist/utils/typescript-validator.js +58 -0
- package/dist/utils/typescript-validator.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { mockExpiredTokens, mockFigmaTokens, mockFreshTokens, mockTokensExpiringSoon } from './__tests__/fixtures.js';
|
|
3
|
+
import { TokenStore } from './token-store.js';
|
|
4
|
+
describe('TokenStore', ()=>{
|
|
5
|
+
let store;
|
|
6
|
+
beforeEach(()=>{
|
|
7
|
+
// Create a new store with a unique config name for each test
|
|
8
|
+
store = new TokenStore({
|
|
9
|
+
configName: `payloadcms-figma-test-${Date.now()}`
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
afterEach(()=>{
|
|
13
|
+
// Clean up after each test
|
|
14
|
+
store.clearTokens();
|
|
15
|
+
});
|
|
16
|
+
describe('setTokens and getTokens', ()=>{
|
|
17
|
+
it('should store and retrieve tokens', ()=>{
|
|
18
|
+
const tokens = mockFigmaTokens();
|
|
19
|
+
store.setTokens(tokens);
|
|
20
|
+
const retrieved = store.getTokens();
|
|
21
|
+
expect(retrieved).toEqual(tokens);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe('clearTokens', ()=>{
|
|
25
|
+
it('should remove stored tokens', ()=>{
|
|
26
|
+
const tokens = mockFigmaTokens();
|
|
27
|
+
store.setTokens(tokens);
|
|
28
|
+
store.clearTokens();
|
|
29
|
+
const retrieved = store.getTokens();
|
|
30
|
+
expect(retrieved).toBeNull();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe('hasValidTokens', ()=>{
|
|
34
|
+
it('should return true when valid tokens exist', ()=>{
|
|
35
|
+
const tokens = mockFreshTokens();
|
|
36
|
+
store.setTokens(tokens);
|
|
37
|
+
expect(store.hasValidTokens()).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
it('should return false when tokens are expired', ()=>{
|
|
40
|
+
const tokens = mockExpiredTokens();
|
|
41
|
+
store.setTokens(tokens);
|
|
42
|
+
expect(store.hasValidTokens()).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
it('should return false when tokens are expiring soon (within buffer)', ()=>{
|
|
45
|
+
const tokens = mockTokensExpiringSoon();
|
|
46
|
+
store.setTokens(tokens);
|
|
47
|
+
expect(store.hasValidTokens()).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe('getAccessToken', ()=>{
|
|
51
|
+
it('should return null when tokens are expired', ()=>{
|
|
52
|
+
const tokens = mockExpiredTokens();
|
|
53
|
+
store.setTokens(tokens);
|
|
54
|
+
const accessToken = store.getAccessToken();
|
|
55
|
+
expect(accessToken).toBeNull();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe('getRefreshToken', ()=>{
|
|
59
|
+
it('should return refresh token even if access token is expired', ()=>{
|
|
60
|
+
const tokens = mockExpiredTokens();
|
|
61
|
+
store.setTokens(tokens);
|
|
62
|
+
const refreshToken = store.getRefreshToken();
|
|
63
|
+
expect(refreshToken).toBe(tokens.refreshToken);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('updateAccessToken', ()=>{
|
|
67
|
+
it('should update access token and expiration time', ()=>{
|
|
68
|
+
const originalTokens = mockFigmaTokens();
|
|
69
|
+
store.setTokens(originalTokens);
|
|
70
|
+
const newAccessToken = 'figt_new_access_token';
|
|
71
|
+
const expiresIn = 7200 // 2 hours
|
|
72
|
+
;
|
|
73
|
+
store.updateAccessToken(newAccessToken, expiresIn);
|
|
74
|
+
const updatedTokens = store.getTokens();
|
|
75
|
+
expect(updatedTokens?.accessToken).toBe(newAccessToken);
|
|
76
|
+
expect(updatedTokens?.refreshToken).toBe(originalTokens.refreshToken);
|
|
77
|
+
expect(updatedTokens?.expiresAt).toBeGreaterThan(Date.now());
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe('Project Token Methods', ()=>{
|
|
81
|
+
const tenantId1 = 'tenant-123';
|
|
82
|
+
const tenantId2 = 'tenant-456';
|
|
83
|
+
const createProjectToken = (tenantId, expiresInMinutes)=>({
|
|
84
|
+
claims: {
|
|
85
|
+
aud: tenantId,
|
|
86
|
+
email: 'test@example.com',
|
|
87
|
+
exp: Math.floor(Date.now() / 1000) + expiresInMinutes * 60,
|
|
88
|
+
iat: Math.floor(Date.now() / 1000),
|
|
89
|
+
seat_type: 'full'
|
|
90
|
+
},
|
|
91
|
+
expiresAt: Date.now() + expiresInMinutes * 60 * 1000,
|
|
92
|
+
tenantId,
|
|
93
|
+
token: `jwt_token_${tenantId}`
|
|
94
|
+
});
|
|
95
|
+
describe('getProjectToken and setProjectToken', ()=>{
|
|
96
|
+
it('should store and retrieve a project token', ()=>{
|
|
97
|
+
const projectToken = createProjectToken(tenantId1, 30);
|
|
98
|
+
store.setProjectToken(tenantId1, projectToken);
|
|
99
|
+
const retrieved = store.getProjectToken(tenantId1);
|
|
100
|
+
expect(retrieved).toEqual(projectToken);
|
|
101
|
+
});
|
|
102
|
+
it('should return null for non-existent tenant', ()=>{
|
|
103
|
+
const retrieved = store.getProjectToken('non-existent');
|
|
104
|
+
expect(retrieved).toBeNull();
|
|
105
|
+
});
|
|
106
|
+
it('should store multiple project tokens independently', ()=>{
|
|
107
|
+
const token1 = createProjectToken(tenantId1, 30);
|
|
108
|
+
const token2 = createProjectToken(tenantId2, 45);
|
|
109
|
+
store.setProjectToken(tenantId1, token1);
|
|
110
|
+
store.setProjectToken(tenantId2, token2);
|
|
111
|
+
expect(store.getProjectToken(tenantId1)).toEqual(token1);
|
|
112
|
+
expect(store.getProjectToken(tenantId2)).toEqual(token2);
|
|
113
|
+
});
|
|
114
|
+
it('should overwrite existing token for same tenant', ()=>{
|
|
115
|
+
const oldToken = createProjectToken(tenantId1, 30);
|
|
116
|
+
const newToken = createProjectToken(tenantId1, 60);
|
|
117
|
+
store.setProjectToken(tenantId1, oldToken);
|
|
118
|
+
store.setProjectToken(tenantId1, newToken);
|
|
119
|
+
const retrieved = store.getProjectToken(tenantId1);
|
|
120
|
+
expect(retrieved).toEqual(newToken);
|
|
121
|
+
expect(retrieved?.token).toBe(newToken.token);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
describe('isProjectTokenExpired', ()=>{
|
|
125
|
+
it('should return false for valid token (30 minutes remaining)', ()=>{
|
|
126
|
+
const validToken = createProjectToken(tenantId1, 30);
|
|
127
|
+
expect(store.isProjectTokenExpired(validToken)).toBe(false);
|
|
128
|
+
});
|
|
129
|
+
it('should return true for expired token (past expiresAt)', ()=>{
|
|
130
|
+
const expiredToken = createProjectToken(tenantId1, -10) // 10 minutes ago
|
|
131
|
+
;
|
|
132
|
+
expect(store.isProjectTokenExpired(expiredToken)).toBe(true);
|
|
133
|
+
});
|
|
134
|
+
it('should return true for token within buffer window (4 minutes remaining)', ()=>{
|
|
135
|
+
// TOKEN_EXPIRY_BUFFER_SECONDS is 5 minutes (300 seconds)
|
|
136
|
+
// Token expires in 4 minutes = within buffer
|
|
137
|
+
const expiringToken = createProjectToken(tenantId1, 4);
|
|
138
|
+
expect(store.isProjectTokenExpired(expiringToken)).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
it('should return false for token just outside buffer window (6 minutes remaining)', ()=>{
|
|
141
|
+
// 6 minutes > 5 minute buffer
|
|
142
|
+
const validToken = createProjectToken(tenantId1, 6);
|
|
143
|
+
expect(store.isProjectTokenExpired(validToken)).toBe(false);
|
|
144
|
+
});
|
|
145
|
+
it('should handle token expiring exactly at buffer boundary', ()=>{
|
|
146
|
+
// Exactly 5 minutes = at buffer boundary
|
|
147
|
+
const boundaryToken = createProjectToken(tenantId1, 5);
|
|
148
|
+
// Should be considered expired (>= check in implementation)
|
|
149
|
+
expect(store.isProjectTokenExpired(boundaryToken)).toBe(true);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
describe('hasValidProjectToken', ()=>{
|
|
153
|
+
it('should return true for valid token', ()=>{
|
|
154
|
+
const validToken = createProjectToken(tenantId1, 30);
|
|
155
|
+
store.setProjectToken(tenantId1, validToken);
|
|
156
|
+
expect(store.hasValidProjectToken(tenantId1)).toBe(true);
|
|
157
|
+
});
|
|
158
|
+
it('should return false for expired token', ()=>{
|
|
159
|
+
const expiredToken = createProjectToken(tenantId1, -10);
|
|
160
|
+
store.setProjectToken(tenantId1, expiredToken);
|
|
161
|
+
expect(store.hasValidProjectToken(tenantId1)).toBe(false);
|
|
162
|
+
});
|
|
163
|
+
it('should return false for missing token', ()=>{
|
|
164
|
+
expect(store.hasValidProjectToken('non-existent')).toBe(false);
|
|
165
|
+
});
|
|
166
|
+
it('should return false for token within buffer window', ()=>{
|
|
167
|
+
const expiringToken = createProjectToken(tenantId1, 4) // Within 5-min buffer
|
|
168
|
+
;
|
|
169
|
+
store.setProjectToken(tenantId1, expiringToken);
|
|
170
|
+
expect(store.hasValidProjectToken(tenantId1)).toBe(false);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
describe('clearProjectToken', ()=>{
|
|
174
|
+
it('should remove specific tenant token', ()=>{
|
|
175
|
+
const token1 = createProjectToken(tenantId1, 30);
|
|
176
|
+
const token2 = createProjectToken(tenantId2, 30);
|
|
177
|
+
store.setProjectToken(tenantId1, token1);
|
|
178
|
+
store.setProjectToken(tenantId2, token2);
|
|
179
|
+
store.clearProjectToken(tenantId1);
|
|
180
|
+
expect(store.getProjectToken(tenantId1)).toBeNull();
|
|
181
|
+
expect(store.getProjectToken(tenantId2)).toEqual(token2);
|
|
182
|
+
});
|
|
183
|
+
it('should handle clearing non-existent token gracefully', ()=>{
|
|
184
|
+
expect(()=>store.clearProjectToken('non-existent')).not.toThrow();
|
|
185
|
+
expect(store.getProjectToken('non-existent')).toBeNull();
|
|
186
|
+
});
|
|
187
|
+
it('should not affect OAuth tokens', ()=>{
|
|
188
|
+
const oauthTokens = mockFigmaTokens();
|
|
189
|
+
const projectToken = createProjectToken(tenantId1, 30);
|
|
190
|
+
store.setTokens(oauthTokens);
|
|
191
|
+
store.setProjectToken(tenantId1, projectToken);
|
|
192
|
+
store.clearProjectToken(tenantId1);
|
|
193
|
+
expect(store.getTokens()).toEqual(oauthTokens);
|
|
194
|
+
expect(store.getProjectToken(tenantId1)).toBeNull();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
describe('clearAllProjectTokens', ()=>{
|
|
198
|
+
it('should remove all project tokens', ()=>{
|
|
199
|
+
const token1 = createProjectToken(tenantId1, 30);
|
|
200
|
+
const token2 = createProjectToken(tenantId2, 30);
|
|
201
|
+
store.setProjectToken(tenantId1, token1);
|
|
202
|
+
store.setProjectToken(tenantId2, token2);
|
|
203
|
+
store.clearAllProjectTokens();
|
|
204
|
+
expect(store.getProjectToken(tenantId1)).toBeNull();
|
|
205
|
+
expect(store.getProjectToken(tenantId2)).toBeNull();
|
|
206
|
+
expect(store.getAllProjectTokenTenantIds()).toEqual([]);
|
|
207
|
+
});
|
|
208
|
+
it('should not affect OAuth tokens', ()=>{
|
|
209
|
+
const oauthTokens = mockFigmaTokens();
|
|
210
|
+
const projectToken = createProjectToken(tenantId1, 30);
|
|
211
|
+
store.setTokens(oauthTokens);
|
|
212
|
+
store.setProjectToken(tenantId1, projectToken);
|
|
213
|
+
store.clearAllProjectTokens();
|
|
214
|
+
expect(store.getTokens()).toEqual(oauthTokens);
|
|
215
|
+
expect(store.getProjectToken(tenantId1)).toBeNull();
|
|
216
|
+
});
|
|
217
|
+
it('should handle clearing when no project tokens exist', ()=>{
|
|
218
|
+
expect(()=>store.clearAllProjectTokens()).not.toThrow();
|
|
219
|
+
expect(store.getAllProjectTokenTenantIds()).toEqual([]);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
describe('getAllProjectTokenTenantIds', ()=>{
|
|
223
|
+
it('should return all tenant IDs with stored tokens', ()=>{
|
|
224
|
+
const token1 = createProjectToken(tenantId1, 30);
|
|
225
|
+
const token2 = createProjectToken(tenantId2, 30);
|
|
226
|
+
store.setProjectToken(tenantId1, token1);
|
|
227
|
+
store.setProjectToken(tenantId2, token2);
|
|
228
|
+
const tenantIds = store.getAllProjectTokenTenantIds();
|
|
229
|
+
expect(tenantIds).toHaveLength(2);
|
|
230
|
+
expect(tenantIds).toContain(tenantId1);
|
|
231
|
+
expect(tenantIds).toContain(tenantId2);
|
|
232
|
+
});
|
|
233
|
+
it('should return empty array when no tokens stored', ()=>{
|
|
234
|
+
const tenantIds = store.getAllProjectTokenTenantIds();
|
|
235
|
+
expect(tenantIds).toEqual([]);
|
|
236
|
+
});
|
|
237
|
+
it('should return correct IDs after removing a token', ()=>{
|
|
238
|
+
const token1 = createProjectToken(tenantId1, 30);
|
|
239
|
+
const token2 = createProjectToken(tenantId2, 30);
|
|
240
|
+
store.setProjectToken(tenantId1, token1);
|
|
241
|
+
store.setProjectToken(tenantId2, token2);
|
|
242
|
+
store.clearProjectToken(tenantId1);
|
|
243
|
+
const tenantIds = store.getAllProjectTokenTenantIds();
|
|
244
|
+
expect(tenantIds).toEqual([
|
|
245
|
+
tenantId2
|
|
246
|
+
]);
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
describe('getProjectTokenClaims', ()=>{
|
|
250
|
+
it('should return claims for valid token', ()=>{
|
|
251
|
+
const projectToken = createProjectToken(tenantId1, 30);
|
|
252
|
+
store.setProjectToken(tenantId1, projectToken);
|
|
253
|
+
const claims = store.getProjectTokenClaims(tenantId1);
|
|
254
|
+
expect(claims).toEqual(projectToken.claims);
|
|
255
|
+
expect(claims?.aud).toBe(tenantId1);
|
|
256
|
+
expect(claims?.email).toBe('test@example.com');
|
|
257
|
+
});
|
|
258
|
+
it('should return null for non-existent token', ()=>{
|
|
259
|
+
const claims = store.getProjectTokenClaims('non-existent');
|
|
260
|
+
expect(claims).toBeNull();
|
|
261
|
+
});
|
|
262
|
+
it('should return null for token without claims', ()=>{
|
|
263
|
+
const tokenWithoutClaims = {
|
|
264
|
+
expiresAt: Date.now() + 30 * 60 * 1000,
|
|
265
|
+
tenantId: tenantId1,
|
|
266
|
+
token: 'jwt_token'
|
|
267
|
+
};
|
|
268
|
+
store.setProjectToken(tenantId1, tokenWithoutClaims);
|
|
269
|
+
const claims = store.getProjectTokenClaims(tenantId1);
|
|
270
|
+
expect(claims).toBeNull();
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
//# sourceMappingURL=token-store.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/auth/token-store.spec.ts"],"sourcesContent":["import { afterEach, beforeEach, describe, expect, it } from 'vitest'\n\nimport {\n mockExpiredTokens,\n mockFigmaTokens,\n mockFreshTokens,\n mockTokensExpiringSoon,\n} from './__tests__/fixtures.js'\nimport { TokenStore } from './token-store.js'\n\ndescribe('TokenStore', () => {\n let store: TokenStore\n\n beforeEach(() => {\n // Create a new store with a unique config name for each test\n store = new TokenStore({ configName: `payloadcms-figma-test-${Date.now()}` })\n })\n\n afterEach(() => {\n // Clean up after each test\n store.clearTokens()\n })\n\n describe('setTokens and getTokens', () => {\n it('should store and retrieve tokens', () => {\n const tokens = mockFigmaTokens()\n store.setTokens(tokens)\n\n const retrieved = store.getTokens()\n expect(retrieved).toEqual(tokens)\n })\n })\n\n describe('clearTokens', () => {\n it('should remove stored tokens', () => {\n const tokens = mockFigmaTokens()\n store.setTokens(tokens)\n\n store.clearTokens()\n\n const retrieved = store.getTokens()\n expect(retrieved).toBeNull()\n })\n })\n\n describe('hasValidTokens', () => {\n it('should return true when valid tokens exist', () => {\n const tokens = mockFreshTokens()\n store.setTokens(tokens)\n\n expect(store.hasValidTokens()).toBe(true)\n })\n\n it('should return false when tokens are expired', () => {\n const tokens = mockExpiredTokens()\n store.setTokens(tokens)\n\n expect(store.hasValidTokens()).toBe(false)\n })\n\n it('should return false when tokens are expiring soon (within buffer)', () => {\n const tokens = mockTokensExpiringSoon()\n store.setTokens(tokens)\n\n expect(store.hasValidTokens()).toBe(false)\n })\n })\n\n describe('getAccessToken', () => {\n it('should return null when tokens are expired', () => {\n const tokens = mockExpiredTokens()\n store.setTokens(tokens)\n\n const accessToken = store.getAccessToken()\n expect(accessToken).toBeNull()\n })\n })\n\n describe('getRefreshToken', () => {\n it('should return refresh token even if access token is expired', () => {\n const tokens = mockExpiredTokens()\n store.setTokens(tokens)\n\n const refreshToken = store.getRefreshToken()\n expect(refreshToken).toBe(tokens.refreshToken)\n })\n })\n\n describe('updateAccessToken', () => {\n it('should update access token and expiration time', () => {\n const originalTokens = mockFigmaTokens()\n store.setTokens(originalTokens)\n\n const newAccessToken = 'figt_new_access_token'\n const expiresIn = 7200 // 2 hours\n\n store.updateAccessToken(newAccessToken, expiresIn)\n\n const updatedTokens = store.getTokens()\n expect(updatedTokens?.accessToken).toBe(newAccessToken)\n expect(updatedTokens?.refreshToken).toBe(originalTokens.refreshToken)\n expect(updatedTokens?.expiresAt).toBeGreaterThan(Date.now())\n })\n })\n\n describe('Project Token Methods', () => {\n const tenantId1 = 'tenant-123'\n const tenantId2 = 'tenant-456'\n\n const createProjectToken = (tenantId: string, expiresInMinutes: number) => ({\n claims: {\n aud: tenantId, // Audience claim contains the CMS ID\n email: 'test@example.com',\n exp: Math.floor(Date.now() / 1000) + expiresInMinutes * 60,\n iat: Math.floor(Date.now() / 1000),\n seat_type: 'full',\n },\n expiresAt: Date.now() + expiresInMinutes * 60 * 1000,\n tenantId,\n token: `jwt_token_${tenantId}`,\n })\n\n describe('getProjectToken and setProjectToken', () => {\n it('should store and retrieve a project token', () => {\n const projectToken = createProjectToken(tenantId1, 30)\n store.setProjectToken(tenantId1, projectToken)\n\n const retrieved = store.getProjectToken(tenantId1)\n expect(retrieved).toEqual(projectToken)\n })\n\n it('should return null for non-existent tenant', () => {\n const retrieved = store.getProjectToken('non-existent')\n expect(retrieved).toBeNull()\n })\n\n it('should store multiple project tokens independently', () => {\n const token1 = createProjectToken(tenantId1, 30)\n const token2 = createProjectToken(tenantId2, 45)\n\n store.setProjectToken(tenantId1, token1)\n store.setProjectToken(tenantId2, token2)\n\n expect(store.getProjectToken(tenantId1)).toEqual(token1)\n expect(store.getProjectToken(tenantId2)).toEqual(token2)\n })\n\n it('should overwrite existing token for same tenant', () => {\n const oldToken = createProjectToken(tenantId1, 30)\n const newToken = createProjectToken(tenantId1, 60)\n\n store.setProjectToken(tenantId1, oldToken)\n store.setProjectToken(tenantId1, newToken)\n\n const retrieved = store.getProjectToken(tenantId1)\n expect(retrieved).toEqual(newToken)\n expect(retrieved?.token).toBe(newToken.token)\n })\n })\n\n describe('isProjectTokenExpired', () => {\n it('should return false for valid token (30 minutes remaining)', () => {\n const validToken = createProjectToken(tenantId1, 30)\n expect(store.isProjectTokenExpired(validToken)).toBe(false)\n })\n\n it('should return true for expired token (past expiresAt)', () => {\n const expiredToken = createProjectToken(tenantId1, -10) // 10 minutes ago\n expect(store.isProjectTokenExpired(expiredToken)).toBe(true)\n })\n\n it('should return true for token within buffer window (4 minutes remaining)', () => {\n // TOKEN_EXPIRY_BUFFER_SECONDS is 5 minutes (300 seconds)\n // Token expires in 4 minutes = within buffer\n const expiringToken = createProjectToken(tenantId1, 4)\n expect(store.isProjectTokenExpired(expiringToken)).toBe(true)\n })\n\n it('should return false for token just outside buffer window (6 minutes remaining)', () => {\n // 6 minutes > 5 minute buffer\n const validToken = createProjectToken(tenantId1, 6)\n expect(store.isProjectTokenExpired(validToken)).toBe(false)\n })\n\n it('should handle token expiring exactly at buffer boundary', () => {\n // Exactly 5 minutes = at buffer boundary\n const boundaryToken = createProjectToken(tenantId1, 5)\n // Should be considered expired (>= check in implementation)\n expect(store.isProjectTokenExpired(boundaryToken)).toBe(true)\n })\n })\n\n describe('hasValidProjectToken', () => {\n it('should return true for valid token', () => {\n const validToken = createProjectToken(tenantId1, 30)\n store.setProjectToken(tenantId1, validToken)\n\n expect(store.hasValidProjectToken(tenantId1)).toBe(true)\n })\n\n it('should return false for expired token', () => {\n const expiredToken = createProjectToken(tenantId1, -10)\n store.setProjectToken(tenantId1, expiredToken)\n\n expect(store.hasValidProjectToken(tenantId1)).toBe(false)\n })\n\n it('should return false for missing token', () => {\n expect(store.hasValidProjectToken('non-existent')).toBe(false)\n })\n\n it('should return false for token within buffer window', () => {\n const expiringToken = createProjectToken(tenantId1, 4) // Within 5-min buffer\n store.setProjectToken(tenantId1, expiringToken)\n\n expect(store.hasValidProjectToken(tenantId1)).toBe(false)\n })\n })\n\n describe('clearProjectToken', () => {\n it('should remove specific tenant token', () => {\n const token1 = createProjectToken(tenantId1, 30)\n const token2 = createProjectToken(tenantId2, 30)\n\n store.setProjectToken(tenantId1, token1)\n store.setProjectToken(tenantId2, token2)\n\n store.clearProjectToken(tenantId1)\n\n expect(store.getProjectToken(tenantId1)).toBeNull()\n expect(store.getProjectToken(tenantId2)).toEqual(token2)\n })\n\n it('should handle clearing non-existent token gracefully', () => {\n expect(() => store.clearProjectToken('non-existent')).not.toThrow()\n expect(store.getProjectToken('non-existent')).toBeNull()\n })\n\n it('should not affect OAuth tokens', () => {\n const oauthTokens = mockFigmaTokens()\n const projectToken = createProjectToken(tenantId1, 30)\n\n store.setTokens(oauthTokens)\n store.setProjectToken(tenantId1, projectToken)\n\n store.clearProjectToken(tenantId1)\n\n expect(store.getTokens()).toEqual(oauthTokens)\n expect(store.getProjectToken(tenantId1)).toBeNull()\n })\n })\n\n describe('clearAllProjectTokens', () => {\n it('should remove all project tokens', () => {\n const token1 = createProjectToken(tenantId1, 30)\n const token2 = createProjectToken(tenantId2, 30)\n\n store.setProjectToken(tenantId1, token1)\n store.setProjectToken(tenantId2, token2)\n\n store.clearAllProjectTokens()\n\n expect(store.getProjectToken(tenantId1)).toBeNull()\n expect(store.getProjectToken(tenantId2)).toBeNull()\n expect(store.getAllProjectTokenTenantIds()).toEqual([])\n })\n\n it('should not affect OAuth tokens', () => {\n const oauthTokens = mockFigmaTokens()\n const projectToken = createProjectToken(tenantId1, 30)\n\n store.setTokens(oauthTokens)\n store.setProjectToken(tenantId1, projectToken)\n\n store.clearAllProjectTokens()\n\n expect(store.getTokens()).toEqual(oauthTokens)\n expect(store.getProjectToken(tenantId1)).toBeNull()\n })\n\n it('should handle clearing when no project tokens exist', () => {\n expect(() => store.clearAllProjectTokens()).not.toThrow()\n expect(store.getAllProjectTokenTenantIds()).toEqual([])\n })\n })\n\n describe('getAllProjectTokenTenantIds', () => {\n it('should return all tenant IDs with stored tokens', () => {\n const token1 = createProjectToken(tenantId1, 30)\n const token2 = createProjectToken(tenantId2, 30)\n\n store.setProjectToken(tenantId1, token1)\n store.setProjectToken(tenantId2, token2)\n\n const tenantIds = store.getAllProjectTokenTenantIds()\n expect(tenantIds).toHaveLength(2)\n expect(tenantIds).toContain(tenantId1)\n expect(tenantIds).toContain(tenantId2)\n })\n\n it('should return empty array when no tokens stored', () => {\n const tenantIds = store.getAllProjectTokenTenantIds()\n expect(tenantIds).toEqual([])\n })\n\n it('should return correct IDs after removing a token', () => {\n const token1 = createProjectToken(tenantId1, 30)\n const token2 = createProjectToken(tenantId2, 30)\n\n store.setProjectToken(tenantId1, token1)\n store.setProjectToken(tenantId2, token2)\n store.clearProjectToken(tenantId1)\n\n const tenantIds = store.getAllProjectTokenTenantIds()\n expect(tenantIds).toEqual([tenantId2])\n })\n })\n\n describe('getProjectTokenClaims', () => {\n it('should return claims for valid token', () => {\n const projectToken = createProjectToken(tenantId1, 30)\n store.setProjectToken(tenantId1, projectToken)\n\n const claims = store.getProjectTokenClaims(tenantId1)\n expect(claims).toEqual(projectToken.claims)\n expect(claims?.aud).toBe(tenantId1)\n expect(claims?.email).toBe('test@example.com')\n })\n\n it('should return null for non-existent token', () => {\n const claims = store.getProjectTokenClaims('non-existent')\n expect(claims).toBeNull()\n })\n\n it('should return null for token without claims', () => {\n const tokenWithoutClaims = {\n expiresAt: Date.now() + 30 * 60 * 1000,\n tenantId: tenantId1,\n token: 'jwt_token',\n }\n store.setProjectToken(tenantId1, tokenWithoutClaims)\n\n const claims = store.getProjectTokenClaims(tenantId1)\n expect(claims).toBeNull()\n })\n })\n })\n})\n"],"names":["afterEach","beforeEach","describe","expect","it","mockExpiredTokens","mockFigmaTokens","mockFreshTokens","mockTokensExpiringSoon","TokenStore","store","configName","Date","now","clearTokens","tokens","setTokens","retrieved","getTokens","toEqual","toBeNull","hasValidTokens","toBe","accessToken","getAccessToken","refreshToken","getRefreshToken","originalTokens","newAccessToken","expiresIn","updateAccessToken","updatedTokens","expiresAt","toBeGreaterThan","tenantId1","tenantId2","createProjectToken","tenantId","expiresInMinutes","claims","aud","email","exp","Math","floor","iat","seat_type","token","projectToken","setProjectToken","getProjectToken","token1","token2","oldToken","newToken","validToken","isProjectTokenExpired","expiredToken","expiringToken","boundaryToken","hasValidProjectToken","clearProjectToken","not","toThrow","oauthTokens","clearAllProjectTokens","getAllProjectTokenTenantIds","tenantIds","toHaveLength","toContain","getProjectTokenClaims","tokenWithoutClaims"],"mappings":"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"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import type { ErrorResponsePayloadWithErrMessage, ErrorResponsePayloadWithErrorBoolean, User } from '@figma/rest-api-spec';
|
|
2
|
+
import type { JWTPayload as JoseJWTPayload } from 'jose';
|
|
3
|
+
/**
|
|
4
|
+
* Standard OAuth2 scopes for user-level permissions
|
|
5
|
+
* @see https://www.figma.com/developers/api#oauth2
|
|
6
|
+
*/
|
|
7
|
+
export type FigmaOAuthScope = 'current_user:read' | 'file_comments:read' | 'file_comments:write' | 'file_content:read' | 'file_dev_resources:read' | 'file_dev_resources:write' | 'file_metadata:read' | 'file_variables:read' | 'file_variables:write' | 'file_versions:read' | 'files:read' | 'library_analytics:read' | 'library_assets:read' | 'library_content:read' | 'projects:read' | 'team_library_content:read' | 'webhooks:read' | 'webhooks:write';
|
|
8
|
+
/**
|
|
9
|
+
* Organization-level OAuth2 scopes
|
|
10
|
+
* Requires organization admin permissions
|
|
11
|
+
*/
|
|
12
|
+
export type FigmaOrgOAuthScope = 'org:activity_log_read';
|
|
13
|
+
/**
|
|
14
|
+
* All valid Figma OAuth scopes
|
|
15
|
+
*/
|
|
16
|
+
export type FigmaScope = FigmaOAuthScope | FigmaOrgOAuthScope;
|
|
17
|
+
/**
|
|
18
|
+
* OAuth tokens returned from Figma API (internal format)
|
|
19
|
+
*/
|
|
20
|
+
export interface FigmaTokens {
|
|
21
|
+
/** OAuth2 access token for making authenticated API requests */
|
|
22
|
+
accessToken: string;
|
|
23
|
+
/** Unix timestamp (milliseconds) when the access token expires */
|
|
24
|
+
expiresAt: number;
|
|
25
|
+
/** OAuth2 refresh token for obtaining new access tokens */
|
|
26
|
+
refreshToken: string;
|
|
27
|
+
/** OAuth scopes granted to this token */
|
|
28
|
+
scopes?: FigmaOAuthScope[];
|
|
29
|
+
/** Token type (typically "Bearer") */
|
|
30
|
+
tokenType?: string;
|
|
31
|
+
/** Figma user ID string */
|
|
32
|
+
userId?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Raw token response from Figma OAuth2 token endpoint
|
|
36
|
+
* Response from POST https://api.figma.com/v1/oauth/token
|
|
37
|
+
*/
|
|
38
|
+
export interface FigmaTokenResponse {
|
|
39
|
+
/** OAuth2 access token */
|
|
40
|
+
access_token: string;
|
|
41
|
+
/** Token expiration time in seconds */
|
|
42
|
+
expires_in: number;
|
|
43
|
+
/** OAuth2 refresh token */
|
|
44
|
+
refresh_token: string;
|
|
45
|
+
/** Space-separated list of granted scopes */
|
|
46
|
+
scope?: string;
|
|
47
|
+
/** Token type (typically "Bearer") */
|
|
48
|
+
token_type?: string;
|
|
49
|
+
/** Figma user ID string */
|
|
50
|
+
user_id_string?: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* OAuth2 error response
|
|
54
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
|
|
55
|
+
*/
|
|
56
|
+
export interface OAuthErrorResponse {
|
|
57
|
+
/** Error code */
|
|
58
|
+
error: 'invalid_client' | 'invalid_grant' | 'invalid_request' | 'invalid_scope' | 'unauthorized_client' | 'unsupported_grant_type';
|
|
59
|
+
/** Human-readable error description */
|
|
60
|
+
error_description?: string;
|
|
61
|
+
/** URI with error information */
|
|
62
|
+
error_uri?: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Parameters for OAuth2 authorization URL
|
|
66
|
+
*/
|
|
67
|
+
export interface OAuthAuthorizationParams {
|
|
68
|
+
/** OAuth2 client ID */
|
|
69
|
+
client_id: string;
|
|
70
|
+
/** PKCE code challenge (optional but recommended) */
|
|
71
|
+
code_challenge?: string;
|
|
72
|
+
/** PKCE code challenge method (must be S256 if using PKCE) */
|
|
73
|
+
code_challenge_method?: 'S256';
|
|
74
|
+
/** Redirect URI for callback */
|
|
75
|
+
redirect_uri: string;
|
|
76
|
+
/** Response type (always "code" for authorization code flow) */
|
|
77
|
+
response_type: 'code';
|
|
78
|
+
/** Requested scopes (space-separated) */
|
|
79
|
+
scope: string;
|
|
80
|
+
/** State parameter for CSRF protection */
|
|
81
|
+
state: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Parameters for OAuth2 token exchange
|
|
85
|
+
*/
|
|
86
|
+
export interface OAuthTokenExchangeParams {
|
|
87
|
+
/** Authorization code from callback */
|
|
88
|
+
code: string;
|
|
89
|
+
/** PKCE code verifier (if PKCE was used) */
|
|
90
|
+
code_verifier?: string;
|
|
91
|
+
/** Grant type (always "authorization_code") */
|
|
92
|
+
grant_type: 'authorization_code';
|
|
93
|
+
/** Redirect URI (must match authorization request) */
|
|
94
|
+
redirect_uri: string;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Parameters for OAuth2 token refresh
|
|
98
|
+
*/
|
|
99
|
+
export interface OAuthTokenRefreshParams {
|
|
100
|
+
/** Grant type (always "refresh_token") */
|
|
101
|
+
grant_type: 'refresh_token';
|
|
102
|
+
/** Refresh token */
|
|
103
|
+
refresh_token: string;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Configuration for token storage
|
|
107
|
+
*/
|
|
108
|
+
export interface TokenStoreConfig {
|
|
109
|
+
/** Custom config name (defaults to 'payloadcms-figma') */
|
|
110
|
+
configName?: string;
|
|
111
|
+
/** Enable encryption (defaults to true) */
|
|
112
|
+
encryptionKey?: string;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* PKCE (Proof Key for Code Exchange) pair for OAuth2 public clients
|
|
116
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7636
|
|
117
|
+
*/
|
|
118
|
+
export interface PKCEPair {
|
|
119
|
+
/** Code challenge derived from code verifier */
|
|
120
|
+
codeChallenge: string;
|
|
121
|
+
/** Code challenge method (always S256) */
|
|
122
|
+
codeChallengeMethod: 'S256';
|
|
123
|
+
/** Code verifier - random string used to generate challenge */
|
|
124
|
+
codeVerifier: string;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* OAuth configuration for Figma API (public client with PKCE)
|
|
128
|
+
*
|
|
129
|
+
* This configuration is for a PUBLIC OAuth client that uses PKCE
|
|
130
|
+
* (Proof Key for Code Exchange) instead of a client secret.
|
|
131
|
+
* Public clients (like CLIs) cannot securely store client secrets.
|
|
132
|
+
*/
|
|
133
|
+
export interface OAuthConfig {
|
|
134
|
+
/** Figma OAuth authorization URL */
|
|
135
|
+
authorizationUrl: string;
|
|
136
|
+
/** OAuth2 client ID (public client) */
|
|
137
|
+
clientId: string;
|
|
138
|
+
/** OAuth2 redirect URI for callback */
|
|
139
|
+
redirectUri: string;
|
|
140
|
+
/** Figma OAuth token refresh URL */
|
|
141
|
+
refreshUrl: string;
|
|
142
|
+
/** OAuth2 scopes to request */
|
|
143
|
+
scopes: FigmaOAuthScope[];
|
|
144
|
+
/** Figma OAuth token exchange URL */
|
|
145
|
+
tokenUrl: string;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Re-export Figma's official types for convenience
|
|
149
|
+
*/
|
|
150
|
+
export type { ErrorResponsePayloadWithErrMessage, ErrorResponsePayloadWithErrorBoolean, User };
|
|
151
|
+
/**
|
|
152
|
+
* Type alias for Figma API error responses
|
|
153
|
+
* Combines both error response formats from Figma's REST API
|
|
154
|
+
*/
|
|
155
|
+
export type FigmaErrorResponse = ErrorResponsePayloadWithErrMessage | ErrorResponsePayloadWithErrorBoolean;
|
|
156
|
+
/**
|
|
157
|
+
* Figma user information
|
|
158
|
+
* Re-exported from @figma/rest-api-spec
|
|
159
|
+
*/
|
|
160
|
+
export type FigmaUser = User;
|
|
161
|
+
/**
|
|
162
|
+
* JWT payload structure from Figma project tokens
|
|
163
|
+
* Extends jose's standard JWTPayload with Figma-specific claims
|
|
164
|
+
*/
|
|
165
|
+
export interface JWTPayload extends JoseJWTPayload {
|
|
166
|
+
[key: string]: unknown;
|
|
167
|
+
/** User email address */
|
|
168
|
+
email?: string;
|
|
169
|
+
/** Tenant/CMS ID this token is scoped to */
|
|
170
|
+
tenant_id?: string;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Project token (JWT) for authenticating to Content API
|
|
174
|
+
* Used by local Payload instances to make authenticated requests
|
|
175
|
+
*/
|
|
176
|
+
export interface ProjectToken {
|
|
177
|
+
/** Validated JWT claims (populated after validation) */
|
|
178
|
+
claims?: JWTPayload;
|
|
179
|
+
/** Unix timestamp (milliseconds) when the token expires (from validated exp claim) */
|
|
180
|
+
expiresAt: number;
|
|
181
|
+
/** Tenant/CMS ID this token is scoped to */
|
|
182
|
+
tenantId: string;
|
|
183
|
+
/** JWT token string signed by Figma API */
|
|
184
|
+
token: string;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Raw project token response from Figma API
|
|
188
|
+
* Response from GET https://api.figma.com/v1/cms/:id/token/
|
|
189
|
+
*/
|
|
190
|
+
export interface ProjectTokenResponse {
|
|
191
|
+
/** Response metadata containing the JWT token */
|
|
192
|
+
meta: {
|
|
193
|
+
/** JWT token string */
|
|
194
|
+
token: string;
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/auth/types.ts"],"sourcesContent":["import type {\n ErrorResponsePayloadWithErrMessage,\n ErrorResponsePayloadWithErrorBoolean,\n User,\n} from '@figma/rest-api-spec'\nimport type { JWTPayload as JoseJWTPayload } from 'jose'\n\n/**\n * Standard OAuth2 scopes for user-level permissions\n * @see https://www.figma.com/developers/api#oauth2\n */\nexport type FigmaOAuthScope =\n | 'current_user:read' // Read user name, email, profile image\n | 'file_comments:read' // Read file comments\n | 'file_comments:write' // Post/delete comments and reactions\n | 'file_content:read' // Read file contents (nodes, editor type)\n | 'file_dev_resources:read' // Read dev resources\n | 'file_dev_resources:write' // Write dev resources\n | 'file_metadata:read' // Read file metadata\n | 'file_variables:read' // Read variables (Enterprise only)\n | 'file_variables:write' // Write variables (Enterprise only)\n | 'file_versions:read' // Read version history\n | 'files:read' // @deprecated Read files, projects, users\n | 'library_analytics:read' // Read library analytics\n | 'library_assets:read' // Read published components/styles data\n | 'library_content:read' // Read published components/styles\n | 'projects:read' // List projects and files\n | 'team_library_content:read' // Read team published content\n | 'webhooks:read' // Read webhook metadata\n | 'webhooks:write' // Create/manage webhooks\n\n/**\n * Organization-level OAuth2 scopes\n * Requires organization admin permissions\n */\nexport type FigmaOrgOAuthScope = 'org:activity_log_read' // Read organization activity logs\n\n/**\n * All valid Figma OAuth scopes\n */\nexport type FigmaScope = FigmaOAuthScope | FigmaOrgOAuthScope\n\n/**\n * OAuth tokens returned from Figma API (internal format)\n */\nexport interface FigmaTokens {\n /** OAuth2 access token for making authenticated API requests */\n accessToken: string\n /** Unix timestamp (milliseconds) when the access token expires */\n expiresAt: number\n /** OAuth2 refresh token for obtaining new access tokens */\n refreshToken: string\n /** OAuth scopes granted to this token */\n scopes?: FigmaOAuthScope[]\n /** Token type (typically \"Bearer\") */\n tokenType?: string\n /** Figma user ID string */\n userId?: string\n}\n\n/**\n * Raw token response from Figma OAuth2 token endpoint\n * Response from POST https://api.figma.com/v1/oauth/token\n */\nexport interface FigmaTokenResponse {\n /** OAuth2 access token */\n access_token: string\n /** Token expiration time in seconds */\n expires_in: number\n /** OAuth2 refresh token */\n refresh_token: string\n /** Space-separated list of granted scopes */\n scope?: string\n /** Token type (typically \"Bearer\") */\n token_type?: string\n /** Figma user ID string */\n user_id_string?: string\n}\n\n/**\n * OAuth2 error response\n * @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.2\n */\nexport interface OAuthErrorResponse {\n /** Error code */\n error:\n | 'invalid_client'\n | 'invalid_grant'\n | 'invalid_request'\n | 'invalid_scope'\n | 'unauthorized_client'\n | 'unsupported_grant_type'\n /** Human-readable error description */\n error_description?: string\n /** URI with error information */\n error_uri?: string\n}\n\n/**\n * Parameters for OAuth2 authorization URL\n */\nexport interface OAuthAuthorizationParams {\n /** OAuth2 client ID */\n client_id: string\n /** PKCE code challenge (optional but recommended) */\n code_challenge?: string\n /** PKCE code challenge method (must be S256 if using PKCE) */\n code_challenge_method?: 'S256'\n /** Redirect URI for callback */\n redirect_uri: string\n /** Response type (always \"code\" for authorization code flow) */\n response_type: 'code'\n /** Requested scopes (space-separated) */\n scope: string\n /** State parameter for CSRF protection */\n state: string\n}\n\n/**\n * Parameters for OAuth2 token exchange\n */\nexport interface OAuthTokenExchangeParams {\n /** Authorization code from callback */\n code: string\n /** PKCE code verifier (if PKCE was used) */\n code_verifier?: string\n /** Grant type (always \"authorization_code\") */\n grant_type: 'authorization_code'\n /** Redirect URI (must match authorization request) */\n redirect_uri: string\n}\n\n/**\n * Parameters for OAuth2 token refresh\n */\nexport interface OAuthTokenRefreshParams {\n /** Grant type (always \"refresh_token\") */\n grant_type: 'refresh_token'\n /** Refresh token */\n refresh_token: string\n}\n\n/**\n * Configuration for token storage\n */\nexport interface TokenStoreConfig {\n /** Custom config name (defaults to 'payloadcms-figma') */\n configName?: string\n /** Enable encryption (defaults to true) */\n encryptionKey?: string\n}\n\n/**\n * PKCE (Proof Key for Code Exchange) pair for OAuth2 public clients\n * @see https://datatracker.ietf.org/doc/html/rfc7636\n */\nexport interface PKCEPair {\n /** Code challenge derived from code verifier */\n codeChallenge: string\n /** Code challenge method (always S256) */\n codeChallengeMethod: 'S256'\n /** Code verifier - random string used to generate challenge */\n codeVerifier: string\n}\n\n/**\n * OAuth configuration for Figma API (public client with PKCE)\n *\n * This configuration is for a PUBLIC OAuth client that uses PKCE\n * (Proof Key for Code Exchange) instead of a client secret.\n * Public clients (like CLIs) cannot securely store client secrets.\n */\nexport interface OAuthConfig {\n /** Figma OAuth authorization URL */\n authorizationUrl: string\n /** OAuth2 client ID (public client) */\n clientId: string\n /** OAuth2 redirect URI for callback */\n redirectUri: string\n /** Figma OAuth token refresh URL */\n refreshUrl: string\n /** OAuth2 scopes to request */\n scopes: FigmaOAuthScope[]\n /** Figma OAuth token exchange URL */\n tokenUrl: string\n}\n\n/**\n * Re-export Figma's official types for convenience\n */\nexport type { ErrorResponsePayloadWithErrMessage, ErrorResponsePayloadWithErrorBoolean, User }\n\n/**\n * Type alias for Figma API error responses\n * Combines both error response formats from Figma's REST API\n */\nexport type FigmaErrorResponse =\n | ErrorResponsePayloadWithErrMessage\n | ErrorResponsePayloadWithErrorBoolean\n\n/**\n * Figma user information\n * Re-exported from @figma/rest-api-spec\n */\nexport type FigmaUser = User\n\n/**\n * JWT payload structure from Figma project tokens\n * Extends jose's standard JWTPayload with Figma-specific claims\n */\nexport interface JWTPayload extends JoseJWTPayload {\n [key: string]: unknown\n /** User email address */\n email?: string\n /** Tenant/CMS ID this token is scoped to */\n tenant_id?: string\n}\n\n/**\n * Project token (JWT) for authenticating to Content API\n * Used by local Payload instances to make authenticated requests\n */\nexport interface ProjectToken {\n /** Validated JWT claims (populated after validation) */\n claims?: JWTPayload\n /** Unix timestamp (milliseconds) when the token expires (from validated exp claim) */\n expiresAt: number\n /** Tenant/CMS ID this token is scoped to */\n tenantId: string\n /** JWT token string signed by Figma API */\n token: string\n}\n\n/**\n * Raw project token response from Figma API\n * Response from GET https://api.figma.com/v1/cms/:id/token/\n */\nexport interface ProjectTokenResponse {\n /** Response metadata containing the JWT token */\n meta: {\n /** JWT token string */\n token: string\n }\n}\n"],"names":[],"mappings":"AAyOA;;;CAGC,GACD,WAMC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAaA;;GAEG;AACH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAS1C"}
|