@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,128 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { isDebug } from './is-debug.js';
|
|
4
|
+
/**
|
|
5
|
+
* Retry configuration
|
|
6
|
+
*/ const MAX_RETRIES = 3;
|
|
7
|
+
const INITIAL_RETRY_DELAY = 1000 // 1 second
|
|
8
|
+
;
|
|
9
|
+
/**
|
|
10
|
+
* Sleep for specified milliseconds
|
|
11
|
+
*/ function sleep(ms) {
|
|
12
|
+
return new Promise((resolve)=>setTimeout(resolve, ms));
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Check if a signed URL is a mock URL
|
|
16
|
+
*/ function isMockUrl(signedUrl) {
|
|
17
|
+
return signedUrl.includes('X-Amz-Signature=mock');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Upload a file to S3 using a signed URL
|
|
21
|
+
*
|
|
22
|
+
* Retries up to 3 times with exponential backoff
|
|
23
|
+
*
|
|
24
|
+
* @param filePath - Absolute path to file to upload
|
|
25
|
+
* @param signedUrl - Signed S3 upload URL
|
|
26
|
+
* @param contentType - MIME type (optional)
|
|
27
|
+
* @throws Error if upload fails after retries
|
|
28
|
+
*/ export async function uploadFile(filePath, signedUrl, contentType) {
|
|
29
|
+
// Skip actual upload for mock URLs
|
|
30
|
+
if (isMockUrl(signedUrl)) {
|
|
31
|
+
if (isDebug()) {
|
|
32
|
+
console.log(`Mock upload: ${path.basename(filePath)}`);
|
|
33
|
+
}
|
|
34
|
+
// Verify file exists
|
|
35
|
+
const stats = await fs.stat(filePath);
|
|
36
|
+
// Simulate upload latency based on file size
|
|
37
|
+
// lambda.zip: ~1-2 seconds, small files: 50-150ms
|
|
38
|
+
const isLargeFile = stats.size > 1024 * 1024 // > 1MB
|
|
39
|
+
;
|
|
40
|
+
const latency = isLargeFile ? 1000 + Math.random() * 1000 // 1-2 seconds for large files
|
|
41
|
+
: 50 + Math.random() * 100 // 50-150ms for small files
|
|
42
|
+
;
|
|
43
|
+
await sleep(latency);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const fileBuffer = await fs.readFile(filePath);
|
|
47
|
+
let lastError = null;
|
|
48
|
+
for(let attempt = 0; attempt < MAX_RETRIES; attempt++){
|
|
49
|
+
try {
|
|
50
|
+
const response = await fetch(signedUrl, {
|
|
51
|
+
body: fileBuffer,
|
|
52
|
+
headers: contentType ? {
|
|
53
|
+
'Content-Type': contentType
|
|
54
|
+
} : {},
|
|
55
|
+
method: 'PUT'
|
|
56
|
+
});
|
|
57
|
+
if (response.ok) {
|
|
58
|
+
return; // Success
|
|
59
|
+
}
|
|
60
|
+
lastError = new Error(`Upload failed: ${response.status} ${response.statusText}`);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
lastError = error instanceof Error ? error : new Error('Unknown error');
|
|
63
|
+
}
|
|
64
|
+
// Wait before retry (exponential backoff)
|
|
65
|
+
if (attempt < MAX_RETRIES - 1) {
|
|
66
|
+
await sleep(INITIAL_RETRY_DELAY * Math.pow(2, attempt));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
throw lastError || new Error('Upload failed after retries');
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Upload Lambda code zip to S3
|
|
73
|
+
*
|
|
74
|
+
* @param zipPath - Path to lambda.zip
|
|
75
|
+
* @param signedUrl - Signed S3 upload URL
|
|
76
|
+
*/ export async function uploadLambdaZip(zipPath, signedUrl) {
|
|
77
|
+
await uploadFile(zipPath, signedUrl, 'application/zip');
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Upload static assets to S3 in parallel
|
|
81
|
+
*
|
|
82
|
+
* Uploads up to 5 files concurrently
|
|
83
|
+
*
|
|
84
|
+
* @param projectPath - Path to project root
|
|
85
|
+
* @param assetUrls - Map of asset paths to signed URLs
|
|
86
|
+
* @param onProgress - Optional callback for progress updates (uploaded, total)
|
|
87
|
+
* @returns Upload results with counts
|
|
88
|
+
*/ export async function uploadStaticAssets(projectPath, assetUrls, onProgress) {
|
|
89
|
+
const results = {
|
|
90
|
+
assetsFailed: 0,
|
|
91
|
+
assetsUploaded: 0,
|
|
92
|
+
lambdaUploaded: false,
|
|
93
|
+
totalBytesUploaded: 0
|
|
94
|
+
};
|
|
95
|
+
const assetPaths = Object.keys(assetUrls);
|
|
96
|
+
if (assetPaths.length === 0) {
|
|
97
|
+
return results;
|
|
98
|
+
}
|
|
99
|
+
// Upload assets with limited concurrency
|
|
100
|
+
const CONCURRENCY = 5;
|
|
101
|
+
for(let i = 0; i < assetPaths.length; i += CONCURRENCY){
|
|
102
|
+
const batch = assetPaths.slice(i, i + CONCURRENCY);
|
|
103
|
+
await Promise.all(batch.map(async (assetPath)=>{
|
|
104
|
+
try {
|
|
105
|
+
// Convert _next back to .next for file system
|
|
106
|
+
const fsPath = assetPath.replace(/^_next\//, '.next/');
|
|
107
|
+
const fullPath = path.join(projectPath, fsPath);
|
|
108
|
+
const signedUrl = assetUrls[assetPath];
|
|
109
|
+
await uploadFile(fullPath, signedUrl);
|
|
110
|
+
results.assetsUploaded++;
|
|
111
|
+
// Track bytes uploaded
|
|
112
|
+
const stats = await fs.stat(fullPath);
|
|
113
|
+
results.totalBytesUploaded += stats.size;
|
|
114
|
+
// Report progress
|
|
115
|
+
onProgress?.(results.assetsUploaded, assetPaths.length);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
results.assetsFailed++;
|
|
118
|
+
if (isDebug()) {
|
|
119
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
120
|
+
console.error(`Failed to upload ${assetPath}: ${message}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
return results;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
//# sourceMappingURL=s3-upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/s3-upload.ts"],"sourcesContent":["import fs from 'fs/promises'\nimport path from 'path'\n\nimport { isDebug } from './is-debug.js'\n\n/**\n * Results from uploading assets\n */\nexport interface UploadResults {\n /** Number of static assets that failed to upload */\n assetsFailed: number\n /** Number of static assets successfully uploaded */\n assetsUploaded: number\n /** Whether Lambda code was uploaded */\n lambdaUploaded: boolean\n /** Total bytes uploaded */\n totalBytesUploaded: number\n}\n\n/**\n * Retry configuration\n */\nconst MAX_RETRIES = 3\nconst INITIAL_RETRY_DELAY = 1000 // 1 second\n\n/**\n * Sleep for specified milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n/**\n * Check if a signed URL is a mock URL\n */\nfunction isMockUrl(signedUrl: string): boolean {\n return signedUrl.includes('X-Amz-Signature=mock')\n}\n\n/**\n * Upload a file to S3 using a signed URL\n *\n * Retries up to 3 times with exponential backoff\n *\n * @param filePath - Absolute path to file to upload\n * @param signedUrl - Signed S3 upload URL\n * @param contentType - MIME type (optional)\n * @throws Error if upload fails after retries\n */\nexport async function uploadFile(\n filePath: string,\n signedUrl: string,\n contentType?: string,\n): Promise<void> {\n // Skip actual upload for mock URLs\n if (isMockUrl(signedUrl)) {\n if (isDebug()) {\n console.log(`Mock upload: ${path.basename(filePath)}`)\n }\n // Verify file exists\n const stats = await fs.stat(filePath)\n\n // Simulate upload latency based on file size\n // lambda.zip: ~1-2 seconds, small files: 50-150ms\n const isLargeFile = stats.size > 1024 * 1024 // > 1MB\n const latency = isLargeFile\n ? 1000 + Math.random() * 1000 // 1-2 seconds for large files\n : 50 + Math.random() * 100 // 50-150ms for small files\n await sleep(latency)\n return\n }\n\n const fileBuffer = await fs.readFile(filePath)\n\n let lastError: Error | null = null\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n const response = await fetch(signedUrl, {\n body: fileBuffer,\n headers: contentType ? { 'Content-Type': contentType } : {},\n method: 'PUT',\n })\n\n if (response.ok) {\n return // Success\n }\n\n lastError = new Error(`Upload failed: ${response.status} ${response.statusText}`)\n } catch (error) {\n lastError = error instanceof Error ? error : new Error('Unknown error')\n }\n\n // Wait before retry (exponential backoff)\n if (attempt < MAX_RETRIES - 1) {\n await sleep(INITIAL_RETRY_DELAY * Math.pow(2, attempt))\n }\n }\n\n throw lastError || new Error('Upload failed after retries')\n}\n\n/**\n * Upload Lambda code zip to S3\n *\n * @param zipPath - Path to lambda.zip\n * @param signedUrl - Signed S3 upload URL\n */\nexport async function uploadLambdaZip(zipPath: string, signedUrl: string): Promise<void> {\n await uploadFile(zipPath, signedUrl, 'application/zip')\n}\n\n/**\n * Upload static assets to S3 in parallel\n *\n * Uploads up to 5 files concurrently\n *\n * @param projectPath - Path to project root\n * @param assetUrls - Map of asset paths to signed URLs\n * @param onProgress - Optional callback for progress updates (uploaded, total)\n * @returns Upload results with counts\n */\nexport async function uploadStaticAssets(\n projectPath: string,\n assetUrls: Record<string, string>,\n onProgress?: (uploaded: number, total: number) => void,\n): Promise<UploadResults> {\n const results: UploadResults = {\n assetsFailed: 0,\n assetsUploaded: 0,\n lambdaUploaded: false,\n totalBytesUploaded: 0,\n }\n\n const assetPaths = Object.keys(assetUrls)\n\n if (assetPaths.length === 0) {\n return results\n }\n\n // Upload assets with limited concurrency\n const CONCURRENCY = 5\n for (let i = 0; i < assetPaths.length; i += CONCURRENCY) {\n const batch = assetPaths.slice(i, i + CONCURRENCY)\n\n await Promise.all(\n batch.map(async (assetPath) => {\n try {\n // Convert _next back to .next for file system\n const fsPath = assetPath.replace(/^_next\\//, '.next/')\n const fullPath = path.join(projectPath, fsPath)\n const signedUrl = assetUrls[assetPath]\n\n await uploadFile(fullPath, signedUrl)\n\n results.assetsUploaded++\n\n // Track bytes uploaded\n const stats = await fs.stat(fullPath)\n results.totalBytesUploaded += stats.size\n\n // Report progress\n onProgress?.(results.assetsUploaded, assetPaths.length)\n } catch (error) {\n results.assetsFailed++\n if (isDebug()) {\n const message = error instanceof Error ? error.message : 'Unknown error'\n console.error(`Failed to upload ${assetPath}: ${message}`)\n }\n }\n }),\n )\n }\n\n return results\n}\n"],"names":["fs","path","isDebug","MAX_RETRIES","INITIAL_RETRY_DELAY","sleep","ms","Promise","resolve","setTimeout","isMockUrl","signedUrl","includes","uploadFile","filePath","contentType","console","log","basename","stats","stat","isLargeFile","size","latency","Math","random","fileBuffer","readFile","lastError","attempt","response","fetch","body","headers","method","ok","Error","status","statusText","error","pow","uploadLambdaZip","zipPath","uploadStaticAssets","projectPath","assetUrls","onProgress","results","assetsFailed","assetsUploaded","lambdaUploaded","totalBytesUploaded","assetPaths","Object","keys","length","CONCURRENCY","i","batch","slice","all","map","assetPath","fsPath","replace","fullPath","join","message"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-upload.spec.d.ts","sourceRoot":"","sources":["../../src/utils/s3-upload.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { uploadFile, uploadLambdaZip, uploadStaticAssets } from './s3-upload.js';
|
|
5
|
+
describe('s3-upload', ()=>{
|
|
6
|
+
const testDir = path.join(process.cwd(), 'test-fixtures', 's3-upload');
|
|
7
|
+
beforeEach(async ()=>{
|
|
8
|
+
await fs.mkdir(testDir, {
|
|
9
|
+
recursive: true
|
|
10
|
+
});
|
|
11
|
+
vi.clearAllMocks();
|
|
12
|
+
});
|
|
13
|
+
afterEach(async ()=>{
|
|
14
|
+
await fs.rm(testDir, {
|
|
15
|
+
force: true,
|
|
16
|
+
recursive: true
|
|
17
|
+
});
|
|
18
|
+
vi.restoreAllMocks();
|
|
19
|
+
});
|
|
20
|
+
describe('uploadFile', ()=>{
|
|
21
|
+
it('should upload file to signed URL', async ()=>{
|
|
22
|
+
const testFile = path.join(testDir, 'test.txt');
|
|
23
|
+
await fs.writeFile(testFile, 'test content');
|
|
24
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
25
|
+
ok: true,
|
|
26
|
+
status: 200
|
|
27
|
+
});
|
|
28
|
+
global.fetch = mockFetch;
|
|
29
|
+
await uploadFile(testFile, 'https://s3.example.com/upload?signature=abc');
|
|
30
|
+
expect(mockFetch).toHaveBeenCalledWith('https://s3.example.com/upload?signature=abc', expect.objectContaining({
|
|
31
|
+
body: expect.any(Buffer),
|
|
32
|
+
method: 'PUT'
|
|
33
|
+
}));
|
|
34
|
+
});
|
|
35
|
+
it('should retry on failure', async ()=>{
|
|
36
|
+
const testFile = path.join(testDir, 'test.txt');
|
|
37
|
+
await fs.writeFile(testFile, 'test');
|
|
38
|
+
const mockFetch = vi.fn().mockResolvedValueOnce({
|
|
39
|
+
ok: false,
|
|
40
|
+
status: 500
|
|
41
|
+
}).mockResolvedValueOnce({
|
|
42
|
+
ok: false,
|
|
43
|
+
status: 500
|
|
44
|
+
}).mockResolvedValueOnce({
|
|
45
|
+
ok: true,
|
|
46
|
+
status: 200
|
|
47
|
+
});
|
|
48
|
+
global.fetch = mockFetch;
|
|
49
|
+
await uploadFile(testFile, 'https://s3.example.com/upload');
|
|
50
|
+
expect(mockFetch).toHaveBeenCalledTimes(3);
|
|
51
|
+
});
|
|
52
|
+
it('should throw after max retries', async ()=>{
|
|
53
|
+
const testFile = path.join(testDir, 'test.txt');
|
|
54
|
+
await fs.writeFile(testFile, 'test');
|
|
55
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
56
|
+
ok: false,
|
|
57
|
+
status: 500
|
|
58
|
+
});
|
|
59
|
+
global.fetch = mockFetch;
|
|
60
|
+
await expect(uploadFile(testFile, 'https://s3.example.com/upload')).rejects.toThrow();
|
|
61
|
+
});
|
|
62
|
+
it('should throw error for non-existent file', async ()=>{
|
|
63
|
+
global.fetch = vi.fn().mockResolvedValue({
|
|
64
|
+
ok: true
|
|
65
|
+
});
|
|
66
|
+
await expect(uploadFile(path.join(testDir, 'missing.txt'), 'https://s3.example.com')).rejects.toThrow();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe('uploadLambdaZip', ()=>{
|
|
70
|
+
it('should upload zip file', async ()=>{
|
|
71
|
+
const zipPath = path.join(testDir, 'lambda.zip');
|
|
72
|
+
await fs.writeFile(zipPath, 'mock zip content');
|
|
73
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
74
|
+
ok: true,
|
|
75
|
+
status: 200
|
|
76
|
+
});
|
|
77
|
+
global.fetch = mockFetch;
|
|
78
|
+
await uploadLambdaZip(zipPath, 'https://s3.example.com/lambda.zip');
|
|
79
|
+
expect(mockFetch).toHaveBeenCalledWith('https://s3.example.com/lambda.zip', expect.objectContaining({
|
|
80
|
+
headers: expect.objectContaining({
|
|
81
|
+
'Content-Type': 'application/zip'
|
|
82
|
+
}),
|
|
83
|
+
method: 'PUT'
|
|
84
|
+
}));
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
describe('uploadStaticAssets', ()=>{
|
|
88
|
+
it('should upload multiple assets', async ()=>{
|
|
89
|
+
// Files are on disk at .next/static (filesystem structure)
|
|
90
|
+
const staticDir = path.join(testDir, '.next', 'static');
|
|
91
|
+
await fs.mkdir(staticDir, {
|
|
92
|
+
recursive: true
|
|
93
|
+
});
|
|
94
|
+
await fs.writeFile(path.join(staticDir, 'file1.js'), 'code1');
|
|
95
|
+
await fs.writeFile(path.join(staticDir, 'file2.css'), 'styles');
|
|
96
|
+
// Asset paths use _next prefix (S3 convention)
|
|
97
|
+
const assetUrls = {
|
|
98
|
+
'_next/static/file1.js': 'https://s3.example.com/file1.js',
|
|
99
|
+
'_next/static/file2.css': 'https://s3.example.com/file2.css'
|
|
100
|
+
};
|
|
101
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
102
|
+
ok: true,
|
|
103
|
+
status: 200
|
|
104
|
+
});
|
|
105
|
+
global.fetch = mockFetch;
|
|
106
|
+
const result = await uploadStaticAssets(testDir, assetUrls);
|
|
107
|
+
expect(result.lambdaUploaded).toBe(false);
|
|
108
|
+
expect(result.assetsUploaded).toBe(2);
|
|
109
|
+
expect(result.assetsFailed).toBe(0);
|
|
110
|
+
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
111
|
+
});
|
|
112
|
+
it('should track failed uploads', async ()=>{
|
|
113
|
+
// Files on disk at .next/static
|
|
114
|
+
const staticDir = path.join(testDir, '.next', 'static');
|
|
115
|
+
await fs.mkdir(staticDir, {
|
|
116
|
+
recursive: true
|
|
117
|
+
});
|
|
118
|
+
await fs.writeFile(path.join(staticDir, 'file1.js'), 'code');
|
|
119
|
+
// Asset paths use _next prefix
|
|
120
|
+
const assetUrls = {
|
|
121
|
+
'_next/static/file1.js': 'https://s3.example.com/file1.js'
|
|
122
|
+
};
|
|
123
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
124
|
+
ok: false,
|
|
125
|
+
status: 500
|
|
126
|
+
});
|
|
127
|
+
global.fetch = mockFetch;
|
|
128
|
+
const result = await uploadStaticAssets(testDir, assetUrls);
|
|
129
|
+
expect(result.assetsUploaded).toBe(0);
|
|
130
|
+
expect(result.assetsFailed).toBe(1);
|
|
131
|
+
});
|
|
132
|
+
it('should handle empty asset list', async ()=>{
|
|
133
|
+
const result = await uploadStaticAssets(testDir, {});
|
|
134
|
+
expect(result.assetsUploaded).toBe(0);
|
|
135
|
+
expect(result.assetsFailed).toBe(0);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
//# sourceMappingURL=s3-upload.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/s3-upload.spec.ts"],"sourcesContent":["import fs from 'fs/promises'\nimport path from 'path'\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'\n\nimport { uploadFile, uploadLambdaZip, uploadStaticAssets } from './s3-upload.js'\n\ndescribe('s3-upload', () => {\n const testDir = path.join(process.cwd(), 'test-fixtures', 's3-upload')\n\n beforeEach(async () => {\n await fs.mkdir(testDir, { recursive: true })\n vi.clearAllMocks()\n })\n\n afterEach(async () => {\n await fs.rm(testDir, { force: true, recursive: true })\n vi.restoreAllMocks()\n })\n\n describe('uploadFile', () => {\n it('should upload file to signed URL', async () => {\n const testFile = path.join(testDir, 'test.txt')\n await fs.writeFile(testFile, 'test content')\n\n const mockFetch = vi.fn().mockResolvedValue({\n ok: true,\n status: 200,\n })\n global.fetch = mockFetch\n\n await uploadFile(testFile, 'https://s3.example.com/upload?signature=abc')\n\n expect(mockFetch).toHaveBeenCalledWith(\n 'https://s3.example.com/upload?signature=abc',\n expect.objectContaining({\n body: expect.any(Buffer),\n method: 'PUT',\n }),\n )\n })\n\n it('should retry on failure', async () => {\n const testFile = path.join(testDir, 'test.txt')\n await fs.writeFile(testFile, 'test')\n\n const mockFetch = vi\n .fn()\n .mockResolvedValueOnce({ ok: false, status: 500 })\n .mockResolvedValueOnce({ ok: false, status: 500 })\n .mockResolvedValueOnce({ ok: true, status: 200 })\n\n global.fetch = mockFetch\n\n await uploadFile(testFile, 'https://s3.example.com/upload')\n\n expect(mockFetch).toHaveBeenCalledTimes(3)\n })\n\n it('should throw after max retries', async () => {\n const testFile = path.join(testDir, 'test.txt')\n await fs.writeFile(testFile, 'test')\n\n const mockFetch = vi.fn().mockResolvedValue({ ok: false, status: 500 })\n global.fetch = mockFetch\n\n await expect(uploadFile(testFile, 'https://s3.example.com/upload')).rejects.toThrow()\n })\n\n it('should throw error for non-existent file', async () => {\n global.fetch = vi.fn().mockResolvedValue({ ok: true })\n\n await expect(\n uploadFile(path.join(testDir, 'missing.txt'), 'https://s3.example.com'),\n ).rejects.toThrow()\n })\n })\n\n describe('uploadLambdaZip', () => {\n it('should upload zip file', async () => {\n const zipPath = path.join(testDir, 'lambda.zip')\n await fs.writeFile(zipPath, 'mock zip content')\n\n const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200 })\n global.fetch = mockFetch\n\n await uploadLambdaZip(zipPath, 'https://s3.example.com/lambda.zip')\n\n expect(mockFetch).toHaveBeenCalledWith(\n 'https://s3.example.com/lambda.zip',\n expect.objectContaining({\n headers: expect.objectContaining({\n 'Content-Type': 'application/zip',\n }),\n method: 'PUT',\n }),\n )\n })\n })\n\n describe('uploadStaticAssets', () => {\n it('should upload multiple assets', async () => {\n // Files are on disk at .next/static (filesystem structure)\n const staticDir = path.join(testDir, '.next', 'static')\n await fs.mkdir(staticDir, { recursive: true })\n await fs.writeFile(path.join(staticDir, 'file1.js'), 'code1')\n await fs.writeFile(path.join(staticDir, 'file2.css'), 'styles')\n\n // Asset paths use _next prefix (S3 convention)\n const assetUrls = {\n '_next/static/file1.js': 'https://s3.example.com/file1.js',\n '_next/static/file2.css': 'https://s3.example.com/file2.css',\n }\n\n const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200 })\n global.fetch = mockFetch\n\n const result = await uploadStaticAssets(testDir, assetUrls)\n\n expect(result.lambdaUploaded).toBe(false)\n expect(result.assetsUploaded).toBe(2)\n expect(result.assetsFailed).toBe(0)\n expect(mockFetch).toHaveBeenCalledTimes(2)\n })\n\n it('should track failed uploads', async () => {\n // Files on disk at .next/static\n const staticDir = path.join(testDir, '.next', 'static')\n await fs.mkdir(staticDir, { recursive: true })\n await fs.writeFile(path.join(staticDir, 'file1.js'), 'code')\n\n // Asset paths use _next prefix\n const assetUrls = {\n '_next/static/file1.js': 'https://s3.example.com/file1.js',\n }\n\n const mockFetch = vi.fn().mockResolvedValue({ ok: false, status: 500 })\n global.fetch = mockFetch\n\n const result = await uploadStaticAssets(testDir, assetUrls)\n\n expect(result.assetsUploaded).toBe(0)\n expect(result.assetsFailed).toBe(1)\n })\n\n it('should handle empty asset list', async () => {\n const result = await uploadStaticAssets(testDir, {})\n\n expect(result.assetsUploaded).toBe(0)\n expect(result.assetsFailed).toBe(0)\n })\n })\n})\n"],"names":["fs","path","afterEach","beforeEach","describe","expect","it","vi","uploadFile","uploadLambdaZip","uploadStaticAssets","testDir","join","process","cwd","mkdir","recursive","clearAllMocks","rm","force","restoreAllMocks","testFile","writeFile","mockFetch","fn","mockResolvedValue","ok","status","global","fetch","toHaveBeenCalledWith","objectContaining","body","any","Buffer","method","mockResolvedValueOnce","toHaveBeenCalledTimes","rejects","toThrow","zipPath","headers","staticDir","assetUrls","result","lambdaUploaded","toBe","assetsUploaded","assetsFailed"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TokenStore } from '../auth/token-store.js';
|
|
2
|
+
/**
|
|
3
|
+
* Mask token for display (show first 4 and last 4 characters)
|
|
4
|
+
*/
|
|
5
|
+
export declare function maskToken(token: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Format timestamp as human-readable string with color coding
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatTimestamp(timestamp: number): string;
|
|
10
|
+
/**
|
|
11
|
+
* Show all stored project tokens
|
|
12
|
+
*/
|
|
13
|
+
export declare function showProjectTokens(tokenStore: TokenStore): void;
|
|
14
|
+
//# sourceMappingURL=token-display.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-display.d.ts","sourceRoot":"","sources":["../../src/utils/token-display.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAExD;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAsBzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAgC9D"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
/**
|
|
4
|
+
* Mask token for display (show first 4 and last 4 characters)
|
|
5
|
+
*/ export function maskToken(token) {
|
|
6
|
+
if (token.length <= 8) {
|
|
7
|
+
return '***';
|
|
8
|
+
}
|
|
9
|
+
return `${token.slice(0, 4)}${'*'.repeat(Math.min(token.length - 8, 32))}${token.slice(-4)}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Format timestamp as human-readable string with color coding
|
|
13
|
+
*/ export function formatTimestamp(timestamp) {
|
|
14
|
+
const now = Date.now();
|
|
15
|
+
const diff = timestamp - now;
|
|
16
|
+
if (diff < 0) {
|
|
17
|
+
return pc.red('Expired');
|
|
18
|
+
}
|
|
19
|
+
const minutes = Math.floor(diff / 60000);
|
|
20
|
+
const hours = Math.floor(minutes / 60);
|
|
21
|
+
const days = Math.floor(hours / 24);
|
|
22
|
+
if (days > 0) {
|
|
23
|
+
return pc.green(`${days}d ${hours % 24}h`);
|
|
24
|
+
}
|
|
25
|
+
if (hours > 0) {
|
|
26
|
+
return pc.green(`${hours}h ${minutes % 60}m`);
|
|
27
|
+
}
|
|
28
|
+
if (minutes > 5) {
|
|
29
|
+
return pc.yellow(`${minutes}m`);
|
|
30
|
+
}
|
|
31
|
+
return pc.red(`${minutes}m`);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Show all stored project tokens
|
|
35
|
+
*/ export function showProjectTokens(tokenStore) {
|
|
36
|
+
// Get all tenant IDs that have project tokens
|
|
37
|
+
const tenantIds = tokenStore.getAllProjectTokenTenantIds();
|
|
38
|
+
if (tenantIds.length === 0) {
|
|
39
|
+
p.log.step(pc.dim('No project tokens stored.'));
|
|
40
|
+
p.note(`Run ${pc.cyan('payloadcms-figma init')} to create a CMS instance`, 'Tip');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const projectTokenLines = [];
|
|
44
|
+
tenantIds.forEach((tenantId, index)=>{
|
|
45
|
+
const projectToken = tokenStore.getProjectToken(tenantId);
|
|
46
|
+
if (!projectToken) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const isValid = tokenStore.hasValidProjectToken(tenantId);
|
|
50
|
+
const status = isValid ? pc.green('✓ Valid') : pc.red('✗ Expired');
|
|
51
|
+
if (index > 0) {
|
|
52
|
+
projectTokenLines.push(''); // Blank line between tokens
|
|
53
|
+
}
|
|
54
|
+
projectTokenLines.push(`Tenant ID: ${tenantId}`);
|
|
55
|
+
projectTokenLines.push(`Status: ${status}`);
|
|
56
|
+
projectTokenLines.push(`Token: ${maskToken(projectToken.token)}`);
|
|
57
|
+
projectTokenLines.push(`Expires: ${formatTimestamp(projectToken.expiresAt)}`);
|
|
58
|
+
});
|
|
59
|
+
p.note(projectTokenLines.join('\n'), `Project Tokens (${tenantIds.length})`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
//# sourceMappingURL=token-display.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/token-display.ts"],"sourcesContent":["import * as p from '@clack/prompts'\nimport pc from 'picocolors'\n\nimport type { TokenStore } from '../auth/token-store.js'\n\n/**\n * Mask token for display (show first 4 and last 4 characters)\n */\nexport function maskToken(token: string): string {\n if (token.length <= 8) {\n return '***'\n }\n return `${token.slice(0, 4)}${'*'.repeat(Math.min(token.length - 8, 32))}${token.slice(-4)}`\n}\n\n/**\n * Format timestamp as human-readable string with color coding\n */\nexport function formatTimestamp(timestamp: number): string {\n const now = Date.now()\n const diff = timestamp - now\n\n if (diff < 0) {\n return pc.red('Expired')\n }\n\n const minutes = Math.floor(diff / 60000)\n const hours = Math.floor(minutes / 60)\n const days = Math.floor(hours / 24)\n\n if (days > 0) {\n return pc.green(`${days}d ${hours % 24}h`)\n }\n if (hours > 0) {\n return pc.green(`${hours}h ${minutes % 60}m`)\n }\n if (minutes > 5) {\n return pc.yellow(`${minutes}m`)\n }\n return pc.red(`${minutes}m`)\n}\n\n/**\n * Show all stored project tokens\n */\nexport function showProjectTokens(tokenStore: TokenStore): void {\n // Get all tenant IDs that have project tokens\n const tenantIds = tokenStore.getAllProjectTokenTenantIds()\n\n if (tenantIds.length === 0) {\n p.log.step(pc.dim('No project tokens stored.'))\n p.note(`Run ${pc.cyan('payloadcms-figma init')} to create a CMS instance`, 'Tip')\n return\n }\n const projectTokenLines: string[] = []\n\n tenantIds.forEach((tenantId, index) => {\n const projectToken = tokenStore.getProjectToken(tenantId)\n\n if (!projectToken) {\n return\n }\n\n const isValid = tokenStore.hasValidProjectToken(tenantId)\n const status = isValid ? pc.green('✓ Valid') : pc.red('✗ Expired')\n\n if (index > 0) {\n projectTokenLines.push('') // Blank line between tokens\n }\n\n projectTokenLines.push(`Tenant ID: ${tenantId}`)\n projectTokenLines.push(`Status: ${status}`)\n projectTokenLines.push(`Token: ${maskToken(projectToken.token)}`)\n projectTokenLines.push(`Expires: ${formatTimestamp(projectToken.expiresAt)}`)\n })\n\n p.note(projectTokenLines.join('\\n'), `Project Tokens (${tenantIds.length})`)\n}\n"],"names":["p","pc","maskToken","token","length","slice","repeat","Math","min","formatTimestamp","timestamp","now","Date","diff","red","minutes","floor","hours","days","green","yellow","showProjectTokens","tokenStore","tenantIds","getAllProjectTokenTenantIds","log","step","dim","note","cyan","projectTokenLines","forEach","tenantId","index","projectToken","getProjectToken","isValid","hasValidProjectToken","status","push","expiresAt","join"],"mappings":"AAAA,YAAYA,OAAO,iBAAgB;AACnC,OAAOC,QAAQ,aAAY;AAI3B;;CAEC,GACD,OAAO,SAASC,UAAUC,KAAa;IACrC,IAAIA,MAAMC,MAAM,IAAI,GAAG;QACrB,OAAO;IACT;IACA,OAAO,GAAGD,MAAME,KAAK,CAAC,GAAG,KAAK,IAAIC,MAAM,CAACC,KAAKC,GAAG,CAACL,MAAMC,MAAM,GAAG,GAAG,OAAOD,MAAME,KAAK,CAAC,CAAC,IAAI;AAC9F;AAEA;;CAEC,GACD,OAAO,SAASI,gBAAgBC,SAAiB;IAC/C,MAAMC,MAAMC,KAAKD,GAAG;IACpB,MAAME,OAAOH,YAAYC;IAEzB,IAAIE,OAAO,GAAG;QACZ,OAAOZ,GAAGa,GAAG,CAAC;IAChB;IAEA,MAAMC,UAAUR,KAAKS,KAAK,CAACH,OAAO;IAClC,MAAMI,QAAQV,KAAKS,KAAK,CAACD,UAAU;IACnC,MAAMG,OAAOX,KAAKS,KAAK,CAACC,QAAQ;IAEhC,IAAIC,OAAO,GAAG;QACZ,OAAOjB,GAAGkB,KAAK,CAAC,GAAGD,KAAK,EAAE,EAAED,QAAQ,GAAG,CAAC,CAAC;IAC3C;IACA,IAAIA,QAAQ,GAAG;QACb,OAAOhB,GAAGkB,KAAK,CAAC,GAAGF,MAAM,EAAE,EAAEF,UAAU,GAAG,CAAC,CAAC;IAC9C;IACA,IAAIA,UAAU,GAAG;QACf,OAAOd,GAAGmB,MAAM,CAAC,GAAGL,QAAQ,CAAC,CAAC;IAChC;IACA,OAAOd,GAAGa,GAAG,CAAC,GAAGC,QAAQ,CAAC,CAAC;AAC7B;AAEA;;CAEC,GACD,OAAO,SAASM,kBAAkBC,UAAsB;IACtD,8CAA8C;IAC9C,MAAMC,YAAYD,WAAWE,2BAA2B;IAExD,IAAID,UAAUnB,MAAM,KAAK,GAAG;QAC1BJ,EAAEyB,GAAG,CAACC,IAAI,CAACzB,GAAG0B,GAAG,CAAC;QAClB3B,EAAE4B,IAAI,CAAC,CAAC,IAAI,EAAE3B,GAAG4B,IAAI,CAAC,yBAAyB,yBAAyB,CAAC,EAAE;QAC3E;IACF;IACA,MAAMC,oBAA8B,EAAE;IAEtCP,UAAUQ,OAAO,CAAC,CAACC,UAAUC;QAC3B,MAAMC,eAAeZ,WAAWa,eAAe,CAACH;QAEhD,IAAI,CAACE,cAAc;YACjB;QACF;QAEA,MAAME,UAAUd,WAAWe,oBAAoB,CAACL;QAChD,MAAMM,SAASF,UAAUnC,GAAGkB,KAAK,CAAC,aAAalB,GAAGa,GAAG,CAAC;QAEtD,IAAImB,QAAQ,GAAG;YACbH,kBAAkBS,IAAI,CAAC,KAAI,4BAA4B;QACzD;QAEAT,kBAAkBS,IAAI,CAAC,CAAC,gBAAgB,EAAEP,UAAU;QACpDF,kBAAkBS,IAAI,CAAC,CAAC,gBAAgB,EAAED,QAAQ;QAClDR,kBAAkBS,IAAI,CAAC,CAAC,gBAAgB,EAAErC,UAAUgC,aAAa/B,KAAK,GAAG;QACzE2B,kBAAkBS,IAAI,CAAC,CAAC,gBAAgB,EAAE9B,gBAAgByB,aAAaM,SAAS,GAAG;IACrF;IAEAxC,EAAE4B,IAAI,CAACE,kBAAkBW,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAElB,UAAUnB,MAAM,CAAC,CAAC,CAAC;AAC7E"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PackageManager } from './package-manager.js';
|
|
2
|
+
export type TypeScriptCheckResult = {
|
|
3
|
+
errors: string[];
|
|
4
|
+
success: boolean;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Run TypeScript type checking (tsc --noEmit)
|
|
8
|
+
* Skips silently if TypeScript not available
|
|
9
|
+
*/
|
|
10
|
+
export declare function runTypeScriptCheck(projectPath: string, packageManager: PackageManager): Promise<TypeScriptCheckResult>;
|
|
11
|
+
//# sourceMappingURL=typescript-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typescript-validator.d.ts","sourceRoot":"","sources":["../../src/utils/typescript-validator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,qBAAqB,CAAC,CAmChC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Run TypeScript type checking (tsc --noEmit)
|
|
4
|
+
* Skips silently if TypeScript not available
|
|
5
|
+
*/ export async function runTypeScriptCheck(projectPath, packageManager) {
|
|
6
|
+
return new Promise((resolve)=>{
|
|
7
|
+
try {
|
|
8
|
+
const args = [
|
|
9
|
+
'exec',
|
|
10
|
+
'tsc',
|
|
11
|
+
'--noEmit'
|
|
12
|
+
];
|
|
13
|
+
const child = spawn(packageManager, args, {
|
|
14
|
+
cwd: projectPath,
|
|
15
|
+
shell: true,
|
|
16
|
+
stdio: 'pipe'
|
|
17
|
+
});
|
|
18
|
+
let output = '';
|
|
19
|
+
child.stdout?.on('data', (data)=>{
|
|
20
|
+
output += data.toString();
|
|
21
|
+
});
|
|
22
|
+
child.on('close', (code)=>{
|
|
23
|
+
if (code === 0) {
|
|
24
|
+
resolve({
|
|
25
|
+
errors: [],
|
|
26
|
+
success: true
|
|
27
|
+
});
|
|
28
|
+
} else {
|
|
29
|
+
const errors = parseTypeScriptErrors(output);
|
|
30
|
+
resolve({
|
|
31
|
+
errors,
|
|
32
|
+
success: false
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
child.on('error', ()=>{
|
|
37
|
+
// tsc not available - skip validation
|
|
38
|
+
resolve({
|
|
39
|
+
errors: [],
|
|
40
|
+
success: true
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
} catch {
|
|
44
|
+
// Skip validation if error
|
|
45
|
+
resolve({
|
|
46
|
+
errors: [],
|
|
47
|
+
success: true
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Parse TypeScript error output
|
|
54
|
+
*/ function parseTypeScriptErrors(output) {
|
|
55
|
+
return output.split('\n').filter((line)=>line.includes('error TS')).map((line)=>line.trim());
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=typescript-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/typescript-validator.ts"],"sourcesContent":["import { spawn } from 'child_process'\n\nimport type { PackageManager } from './package-manager.js'\n\nexport type TypeScriptCheckResult = {\n errors: string[]\n success: boolean\n}\n\n/**\n * Run TypeScript type checking (tsc --noEmit)\n * Skips silently if TypeScript not available\n */\nexport async function runTypeScriptCheck(\n projectPath: string,\n packageManager: PackageManager,\n): Promise<TypeScriptCheckResult> {\n return new Promise((resolve) => {\n try {\n const args = ['exec', 'tsc', '--noEmit']\n\n const child = spawn(packageManager, args, {\n cwd: projectPath,\n shell: true,\n stdio: 'pipe',\n })\n\n let output = ''\n\n child.stdout?.on('data', (data) => {\n output += data.toString()\n })\n\n child.on('close', (code) => {\n if (code === 0) {\n resolve({ errors: [], success: true })\n } else {\n const errors = parseTypeScriptErrors(output)\n resolve({ errors, success: false })\n }\n })\n\n child.on('error', () => {\n // tsc not available - skip validation\n resolve({ errors: [], success: true })\n })\n } catch {\n // Skip validation if error\n resolve({ errors: [], success: true })\n }\n })\n}\n\n/**\n * Parse TypeScript error output\n */\nfunction parseTypeScriptErrors(output: string): string[] {\n return output\n .split('\\n')\n .filter((line) => line.includes('error TS'))\n .map((line) => line.trim())\n}\n"],"names":["spawn","runTypeScriptCheck","projectPath","packageManager","Promise","resolve","args","child","cwd","shell","stdio","output","stdout","on","data","toString","code","errors","success","parseTypeScriptErrors","split","filter","line","includes","map","trim"],"mappings":"AAAA,SAASA,KAAK,QAAQ,gBAAe;AASrC;;;CAGC,GACD,OAAO,eAAeC,mBACpBC,WAAmB,EACnBC,cAA8B;IAE9B,OAAO,IAAIC,QAAQ,CAACC;QAClB,IAAI;YACF,MAAMC,OAAO;gBAAC;gBAAQ;gBAAO;aAAW;YAExC,MAAMC,QAAQP,MAAMG,gBAAgBG,MAAM;gBACxCE,KAAKN;gBACLO,OAAO;gBACPC,OAAO;YACT;YAEA,IAAIC,SAAS;YAEbJ,MAAMK,MAAM,EAAEC,GAAG,QAAQ,CAACC;gBACxBH,UAAUG,KAAKC,QAAQ;YACzB;YAEAR,MAAMM,EAAE,CAAC,SAAS,CAACG;gBACjB,IAAIA,SAAS,GAAG;oBACdX,QAAQ;wBAAEY,QAAQ,EAAE;wBAAEC,SAAS;oBAAK;gBACtC,OAAO;oBACL,MAAMD,SAASE,sBAAsBR;oBACrCN,QAAQ;wBAAEY;wBAAQC,SAAS;oBAAM;gBACnC;YACF;YAEAX,MAAMM,EAAE,CAAC,SAAS;gBAChB,sCAAsC;gBACtCR,QAAQ;oBAAEY,QAAQ,EAAE;oBAAEC,SAAS;gBAAK;YACtC;QACF,EAAE,OAAM;YACN,2BAA2B;YAC3Bb,QAAQ;gBAAEY,QAAQ,EAAE;gBAAEC,SAAS;YAAK;QACtC;IACF;AACF;AAEA;;CAEC,GACD,SAASC,sBAAsBR,MAAc;IAC3C,OAAOA,OACJS,KAAK,CAAC,MACNC,MAAM,CAAC,CAACC,OAASA,KAAKC,QAAQ,CAAC,aAC/BC,GAAG,CAAC,CAACF,OAASA,KAAKG,IAAI;AAC5B"}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@payloadcms/figma",
|
|
3
|
+
"version": "0.0.1-alpha.0",
|
|
4
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"bin": {
|
|
16
|
+
"payloadcms-figma": "bin/cli.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"package.json",
|
|
20
|
+
"dist",
|
|
21
|
+
"bin"
|
|
22
|
+
],
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@clack/prompts": "^0.11.0",
|
|
25
|
+
"@figma/rest-api-spec": "^0.34.0",
|
|
26
|
+
"@payloadcms/richtext-lexical": "3.54.0",
|
|
27
|
+
"@sindresorhus/slugify": "^3.0.0",
|
|
28
|
+
"arg": "^5.0.2",
|
|
29
|
+
"conf": "^13.0.1",
|
|
30
|
+
"esprima-next": "^6.0.2",
|
|
31
|
+
"figures": "^6.1.0",
|
|
32
|
+
"jose": "6.0.12",
|
|
33
|
+
"open": "^10.1.0",
|
|
34
|
+
"payload": "3.54.0",
|
|
35
|
+
"picocolors": "1.1.1",
|
|
36
|
+
"tar": "^7.4.3",
|
|
37
|
+
"terminal-link": "^5.0.0",
|
|
38
|
+
"ts-morph": "^21.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "22.12.0",
|
|
42
|
+
"tsx": "4.20.6",
|
|
43
|
+
"typescript": "5.9.3",
|
|
44
|
+
"vitest": "3.2.4"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"registry": "https://registry.npmjs.org/"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "pnpm build:swc && pnpm build:types && pnpm copyfiles",
|
|
51
|
+
"build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
|
|
52
|
+
"build:types": "tsc",
|
|
53
|
+
"clean": "rimraf -g \"{dist,*.tsbuildinfo,package}\"",
|
|
54
|
+
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png}\" dist/",
|
|
55
|
+
"debug:clear-tokens": "tsx scripts/clear-tokens.ts",
|
|
56
|
+
"debug:expire-token": "tsx scripts/expire-token.ts",
|
|
57
|
+
"debug:jwks": "tsx scripts/test-jwks-validation.ts",
|
|
58
|
+
"debug:refresh-token": "tsx scripts/refresh-token.ts",
|
|
59
|
+
"debug:tokens": "tsx scripts/debug-tokens.ts",
|
|
60
|
+
"debug:write-token": "tsx scripts/write-token.ts",
|
|
61
|
+
"lint": "eslint src",
|
|
62
|
+
"lint:fix": "eslint . --fix",
|
|
63
|
+
"start": "pnpm build && node ./bin/cli.js",
|
|
64
|
+
"test": "TEST_UNIT=true vitest run",
|
|
65
|
+
"test:int": "TEST_INT=true vitest run --config vitest.config.int.ts",
|
|
66
|
+
"test:int:watch": "TEST_INT=true vitest --config vitest.config.int.ts",
|
|
67
|
+
"test:watch": "TEST_UNIT=true vitest"
|
|
68
|
+
}
|
|
69
|
+
}
|