@payloadcms/figma 0.0.1-alpha.63 → 0.0.1-alpha.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/callback-server.d.ts +19 -7
- package/dist/auth/callback-server.js +72 -31
- package/dist/auth/crypto-utils.d.ts +11 -0
- package/dist/auth/crypto-utils.js +22 -1
- package/dist/auth/oauth-flow.d.ts +3 -1
- package/dist/auth/oauth-flow.js +14 -6
- package/dist/auth/project-token.d.ts +15 -10
- package/dist/auth/project-token.js +147 -64
- package/dist/auth/token-store-migration.js +2 -2
- package/dist/auth/token-store.d.ts +2 -0
- package/dist/auth/token-store.js +43 -3
- package/dist/auth/types.d.ts +11 -0
- package/dist/cli.js +15 -1
- package/dist/commands/bootstrap.d.ts +18 -0
- package/dist/commands/bootstrap.js +90 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +76 -4
- package/dist/config/oauth.d.ts +2 -1
- package/dist/config/oauth.js +7 -1
- package/dist/db-content-api/generated/content-api-types.d.ts +6 -0
- package/dist/db-content-api/index.d.ts +2 -0
- package/dist/db-content-api/index.js +36 -74
- package/dist/lib/download-skill.d.ts +13 -0
- package/dist/lib/download-skill.js +79 -0
- package/dist/oauth/endpoints/getLoginEndpoint.js +26 -107
- package/dist/oauth/endpoints/getTokenLoginEndpoint.d.ts +17 -0
- package/dist/oauth/endpoints/getTokenLoginEndpoint.js +105 -0
- package/dist/oauth/index.js +8 -0
- package/dist/oauth/utilities/establishSession.d.ts +23 -0
- package/dist/oauth/utilities/establishSession.js +82 -0
- package/dist/oauth/utilities/exchangeCodeForAccessToken.d.ts +24 -0
- package/dist/oauth/utilities/exchangeCodeForAccessToken.js +28 -0
- package/dist/oauth/utilities/isAbsoluteURL.d.ts +2 -0
- package/dist/oauth/utilities/isAbsoluteURL.js +3 -0
- package/dist/plugin/build-config.js +65 -46
- package/dist/types.d.ts +2 -0
- package/dist/utils/download-template.d.ts +9 -1
- package/dist/utils/download-template.js +24 -19
- package/dist/utils/messages.js +9 -0
- package/dist/utils/parse-template-spec.d.ts +12 -0
- package/dist/utils/parse-template-spec.js +62 -0
- package/dist/utils/payload-config-modifier.js +96 -107
- package/dist/utils/payload-package-check.d.ts +21 -1
- package/dist/utils/payload-package-check.js +66 -26
- package/dist/utils/project.d.ts +2 -1
- package/dist/utils/project.js +2 -2
- package/package.json +9 -1
- package/dist/db-content-api/README.md +0 -98
|
@@ -5,7 +5,7 @@ import * as log from './log.js';
|
|
|
5
5
|
import { getAddCommand, getRunCommand } from './package-manager.js';
|
|
6
6
|
import { addFigmaProperty, applyModifications, detectRequiredChanges } from './payload-config-ast.js';
|
|
7
7
|
import { findPayloadConfig } from './payload-config-finder.js';
|
|
8
|
-
import { checkPackageInstalled, getPayloadVersion,
|
|
8
|
+
import { checkPackageInstalled, getPayloadVersion, installPackages, uninstallPackages } from './payload-package-check.js';
|
|
9
9
|
import { runTypeScriptCheck } from './typescript-validator.js';
|
|
10
10
|
import { getOwnVersion } from './version-check.js';
|
|
11
11
|
/**
|
|
@@ -14,10 +14,9 @@ import { getOwnVersion } from './version-check.js';
|
|
|
14
14
|
*/ export async function ensurePayloadFigmaConfig(projectPath, packageManager, figmaConfig) {
|
|
15
15
|
const changes = [];
|
|
16
16
|
const warnings = [];
|
|
17
|
-
let
|
|
17
|
+
let astModified = false;
|
|
18
18
|
try {
|
|
19
19
|
log.debug(`Starting payload config modification for: ${projectPath}`);
|
|
20
|
-
// 1. Find config file
|
|
21
20
|
const configPath = await findPayloadConfig(projectPath);
|
|
22
21
|
if (!configPath) {
|
|
23
22
|
log.debug(`Config file not found in: ${projectPath}`);
|
|
@@ -29,32 +28,10 @@ import { getOwnVersion } from './version-check.js';
|
|
|
29
28
|
};
|
|
30
29
|
}
|
|
31
30
|
log.debug(`Found config file: ${configPath}`);
|
|
32
|
-
//
|
|
31
|
+
// Pin @payloadcms/* packages to the project's payload version when possible.
|
|
33
32
|
const payloadVersion = await getPayloadVersion(projectPath);
|
|
34
33
|
log.debug(`Detected payload version: ${payloadVersion || 'unknown'}`);
|
|
35
|
-
//
|
|
36
|
-
const isInstalled = await checkPackageInstalled(projectPath, '@payloadcms/figma');
|
|
37
|
-
if (!isInstalled) {
|
|
38
|
-
log.debug('@payloadcms/figma not installed, attempting installation...');
|
|
39
|
-
try {
|
|
40
|
-
const figmaVersion = await getOwnVersion();
|
|
41
|
-
await installPackage(projectPath, '@payloadcms/figma', packageManager, figmaVersion);
|
|
42
|
-
changes.push('Installed @payloadcms/figma');
|
|
43
|
-
modified = true;
|
|
44
|
-
log.debug('@payloadcms/figma installed successfully');
|
|
45
|
-
} catch (error) {
|
|
46
|
-
log.debug(`Failed to install @payloadcms/figma: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
47
|
-
return {
|
|
48
|
-
changes: [],
|
|
49
|
-
error: 'Failed to install @payloadcms/figma',
|
|
50
|
-
modified: false,
|
|
51
|
-
success: false
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
} else {
|
|
55
|
-
log.debug('@payloadcms/figma already installed');
|
|
56
|
-
}
|
|
57
|
-
// 3. Parse config with ts-morph
|
|
34
|
+
// Parse first so a malformed config fails fast before we touch node_modules.
|
|
58
35
|
log.debug('Parsing config file with ts-morph...');
|
|
59
36
|
const project = new Project({
|
|
60
37
|
manipulationSettings: {
|
|
@@ -64,17 +41,15 @@ import { getOwnVersion } from './version-check.js';
|
|
|
64
41
|
skipAddingFilesFromTsConfig: true
|
|
65
42
|
});
|
|
66
43
|
const sourceFile = project.addSourceFileAtPath(configPath);
|
|
67
|
-
// 4. Detect required changes
|
|
68
44
|
log.debug('Detecting required changes...');
|
|
69
45
|
const detection = detectRequiredChanges(sourceFile);
|
|
70
46
|
log.debug(`Detection results: needsImportChange=${detection.needsImportChange}, hasAlias=${detection.hasAlias}, hasBuildConfig=${detection.hasBuildConfig}`);
|
|
71
|
-
// Handle failure modes
|
|
72
47
|
if (detection.hasAlias) {
|
|
73
48
|
log.debug('Config uses import alias (e.g., buildConfig as X)');
|
|
74
49
|
return {
|
|
75
50
|
changes,
|
|
76
51
|
error: 'Config uses import alias - manual modification required',
|
|
77
|
-
modified,
|
|
52
|
+
modified: false,
|
|
78
53
|
success: false
|
|
79
54
|
};
|
|
80
55
|
}
|
|
@@ -83,25 +58,95 @@ import { getOwnVersion } from './version-check.js';
|
|
|
83
58
|
return {
|
|
84
59
|
changes,
|
|
85
60
|
error: 'Config structure not recognized (no buildConfig call found)',
|
|
86
|
-
modified,
|
|
61
|
+
modified: false,
|
|
87
62
|
success: false
|
|
88
63
|
};
|
|
89
64
|
}
|
|
90
|
-
//
|
|
65
|
+
// Compute the full install/uninstall diff up front so each can run as a
|
|
66
|
+
// single package-manager call. npm leaves node_modules transient between
|
|
67
|
+
// back-to-back calls, which causes generate:importmap to silently miss
|
|
68
|
+
// subpath components — batching avoids that intermediate state.
|
|
69
|
+
const packagesToInstall = [];
|
|
70
|
+
const packagesToUninstall = [];
|
|
71
|
+
const figmaInstalled = await checkPackageInstalled(projectPath, '@payloadcms/figma');
|
|
72
|
+
if (!figmaInstalled) {
|
|
73
|
+
const figmaVersion = await getOwnVersion();
|
|
74
|
+
packagesToInstall.push({
|
|
75
|
+
name: '@payloadcms/figma',
|
|
76
|
+
changeMessage: 'Installed @payloadcms/figma',
|
|
77
|
+
version: figmaVersion
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const editorIsDefault = !detection.editorProperty || detection.editorProperty.isDefault;
|
|
81
|
+
if (editorIsDefault) {
|
|
82
|
+
const hasLexical = await checkPackageInstalled(projectPath, '@payloadcms/richtext-lexical');
|
|
83
|
+
if (!hasLexical) {
|
|
84
|
+
packagesToInstall.push({
|
|
85
|
+
name: '@payloadcms/richtext-lexical',
|
|
86
|
+
changeMessage: 'Installed @payloadcms/richtext-lexical (default editor)',
|
|
87
|
+
version: payloadVersion
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
log.debug(`Custom editor detected (${detection.editorProperty?.importSource}) - skipping lexical installation`);
|
|
92
|
+
}
|
|
93
|
+
const hasCloudStorage = await checkPackageInstalled(projectPath, '@payloadcms/plugin-cloud-storage');
|
|
94
|
+
if (!hasCloudStorage) {
|
|
95
|
+
packagesToInstall.push({
|
|
96
|
+
name: '@payloadcms/plugin-cloud-storage',
|
|
97
|
+
changeMessage: 'Installed @payloadcms/plugin-cloud-storage',
|
|
98
|
+
version: payloadVersion
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (detection.dbProperty) {
|
|
102
|
+
packagesToUninstall.push(detection.dbProperty.importSource);
|
|
103
|
+
}
|
|
104
|
+
if (detection.sharpProperty) {
|
|
105
|
+
packagesToUninstall.push('sharp');
|
|
106
|
+
}
|
|
107
|
+
if (packagesToInstall.length > 0) {
|
|
108
|
+
log.debug(`Installing ${packagesToInstall.length} packages in a single operation: ${packagesToInstall.map((p)=>p.name).join(', ')}`);
|
|
109
|
+
try {
|
|
110
|
+
await installPackages(projectPath, packagesToInstall.map(({ name, version })=>({
|
|
111
|
+
name,
|
|
112
|
+
version
|
|
113
|
+
})), packageManager);
|
|
114
|
+
for (const { changeMessage } of packagesToInstall){
|
|
115
|
+
changes.push(changeMessage);
|
|
116
|
+
}
|
|
117
|
+
} catch (error) {
|
|
118
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
119
|
+
log.debug(`Batched install failed: ${errorMessage}`);
|
|
120
|
+
const figmaInBatch = packagesToInstall.some((p)=>p.name === '@payloadcms/figma');
|
|
121
|
+
if (figmaInBatch) {
|
|
122
|
+
// Without @payloadcms/figma the rewritten config would import a
|
|
123
|
+
// missing package, so abort before touching the file.
|
|
124
|
+
return {
|
|
125
|
+
changes: [],
|
|
126
|
+
error: 'Failed to install @payloadcms/figma',
|
|
127
|
+
modified: false,
|
|
128
|
+
success: false
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
// Lexical and cloud-storage are non-fatal — payload still loads without
|
|
132
|
+
// them, so warn (with package names) and continue.
|
|
133
|
+
const failedNames = packagesToInstall.map((p)=>p.name).join(', ');
|
|
134
|
+
warnings.push(`Could not install dependencies (${failedNames}) — install them manually. Details: ${errorMessage}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
91
137
|
log.debug('Applying modifications...');
|
|
92
138
|
const modResult = applyModifications(sourceFile, detection);
|
|
93
139
|
if (modResult.modified) {
|
|
94
140
|
changes.push(...modResult.changes);
|
|
95
|
-
|
|
141
|
+
astModified = true;
|
|
96
142
|
log.debug(`Applied ${modResult.changes.length} modifications`);
|
|
97
143
|
}
|
|
98
|
-
// 6. Add figma property if config provided and doesn't exist
|
|
99
144
|
if (figmaConfig && !detection.figmaObjectExists) {
|
|
100
145
|
log.debug('Adding figma property to buildConfig...');
|
|
101
146
|
const figmaResult = addFigmaProperty(sourceFile, figmaConfig);
|
|
102
147
|
if (figmaResult.modified) {
|
|
103
148
|
changes.push(...figmaResult.changes);
|
|
104
|
-
|
|
149
|
+
astModified = true;
|
|
105
150
|
log.debug(`Added figma property`);
|
|
106
151
|
} else {
|
|
107
152
|
log.debug('Figma property not added (may already exist)');
|
|
@@ -109,95 +154,39 @@ import { getOwnVersion } from './version-check.js';
|
|
|
109
154
|
} else if (detection.figmaObjectExists) {
|
|
110
155
|
log.debug('Figma property already exists, skipping');
|
|
111
156
|
}
|
|
112
|
-
|
|
113
|
-
if (modified) {
|
|
157
|
+
if (astModified) {
|
|
114
158
|
sourceFile.formatText({
|
|
115
159
|
indentSize: 2,
|
|
116
160
|
tabSize: 2
|
|
117
161
|
});
|
|
118
162
|
await sourceFile.save();
|
|
119
163
|
log.debug('Config file saved');
|
|
120
|
-
// 7. Handle package management
|
|
121
|
-
const packagesToUninstall = [];
|
|
122
|
-
// Uninstall db adapter (buildFigmaConfig provides its own)
|
|
123
|
-
if (detection.dbProperty) {
|
|
124
|
-
packagesToUninstall.push(detection.dbProperty.importSource);
|
|
125
|
-
}
|
|
126
|
-
// Uninstall sharp (Figma infrastructure handles image processing)
|
|
127
|
-
if (detection.sharpProperty) {
|
|
128
|
-
packagesToUninstall.push('sharp');
|
|
129
|
-
}
|
|
130
|
-
// Ensure lexical is installed if user doesn't have a custom editor
|
|
131
|
-
// (buildFigmaConfig uses lexicalEditor() as default)
|
|
132
|
-
if (!detection.editorProperty) {
|
|
133
|
-
log.debug('No editor property detected - will ensure lexical is installed for default editor');
|
|
134
|
-
} else if (detection.editorProperty.isDefault) {
|
|
135
|
-
log.debug('Default lexicalEditor() detected - will ensure lexical is installed');
|
|
136
|
-
} else {
|
|
137
|
-
log.debug(`Custom editor detected (${detection.editorProperty.importSource}) - skipping lexical installation`);
|
|
138
|
-
}
|
|
139
|
-
if (!detection.editorProperty || detection.editorProperty.isDefault) {
|
|
140
|
-
log.debug('Checking if @payloadcms/richtext-lexical is installed...');
|
|
141
|
-
const hasLexical = await checkPackageInstalled(projectPath, '@payloadcms/richtext-lexical');
|
|
142
|
-
if (!hasLexical) {
|
|
143
|
-
log.debug('@payloadcms/richtext-lexical not found, installing...');
|
|
144
|
-
try {
|
|
145
|
-
await installPackage(projectPath, '@payloadcms/richtext-lexical', packageManager, payloadVersion);
|
|
146
|
-
changes.push('Installed @payloadcms/richtext-lexical (default editor)');
|
|
147
|
-
log.debug('Successfully installed @payloadcms/richtext-lexical');
|
|
148
|
-
} catch (error) {
|
|
149
|
-
log.debug(`Failed to install @payloadcms/richtext-lexical: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
150
|
-
// Don't fail on install error - user can install manually if needed
|
|
151
|
-
warnings.push('Could not install @payloadcms/richtext-lexical - you may need to install it manually');
|
|
152
|
-
}
|
|
153
|
-
} else {
|
|
154
|
-
log.debug('@payloadcms/richtext-lexical already installed, skipping');
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
// Ensure cloud-storage is installed (required peer dependency for buildFigmaConfig)
|
|
158
|
-
log.debug('Checking if @payloadcms/plugin-cloud-storage is installed...');
|
|
159
|
-
const hasCloudStorage = await checkPackageInstalled(projectPath, '@payloadcms/plugin-cloud-storage');
|
|
160
|
-
if (!hasCloudStorage) {
|
|
161
|
-
log.debug('@payloadcms/plugin-cloud-storage not found, installing...');
|
|
162
|
-
try {
|
|
163
|
-
await installPackage(projectPath, '@payloadcms/plugin-cloud-storage', packageManager, payloadVersion);
|
|
164
|
-
changes.push('Installed @payloadcms/plugin-cloud-storage');
|
|
165
|
-
log.debug('Successfully installed @payloadcms/plugin-cloud-storage');
|
|
166
|
-
} catch (error) {
|
|
167
|
-
log.debug(`Failed to install @payloadcms/plugin-cloud-storage: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
168
|
-
warnings.push('Could not install @payloadcms/plugin-cloud-storage - you may need to install it manually');
|
|
169
|
-
}
|
|
170
|
-
} else {
|
|
171
|
-
log.debug('@payloadcms/plugin-cloud-storage already installed, skipping');
|
|
172
|
-
}
|
|
173
|
-
if (packagesToUninstall.length > 0) {
|
|
174
|
-
log.debug(`Uninstalling ${packagesToUninstall.length} orphaned packages...`);
|
|
175
|
-
}
|
|
176
|
-
for (const pkg of packagesToUninstall){
|
|
177
|
-
try {
|
|
178
|
-
await uninstallPackage(projectPath, pkg, packageManager);
|
|
179
|
-
changes.push(`Uninstalled ${pkg}`);
|
|
180
|
-
log.debug(`Uninstalled ${pkg}`);
|
|
181
|
-
} catch (error) {
|
|
182
|
-
log.debug(`Failed to uninstall ${pkg}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
183
|
-
// Don't fail on uninstall errors - orphaned package is better than broken config
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
// 8. Format file
|
|
187
164
|
log.debug('Formatting config file...');
|
|
188
165
|
const formatResult = await formatFile(configPath, packageManager);
|
|
189
166
|
if (!formatResult.success && formatResult.warning) {
|
|
190
167
|
warnings.push(formatResult.warning);
|
|
191
168
|
log.debug(`Formatting warning: ${formatResult.warning}`);
|
|
192
169
|
}
|
|
193
|
-
// 9. Run TypeScript validation
|
|
194
170
|
log.debug('Running TypeScript validation...');
|
|
195
171
|
const tsResult = await runTypeScriptCheck(projectPath, packageManager);
|
|
196
172
|
if (!tsResult.success && tsResult.errors.length > 0) {
|
|
197
173
|
warnings.push(`TypeScript validation found issues - run '${getRunCommand(packageManager)} build' for details`);
|
|
198
174
|
log.debug(`TypeScript validation found ${tsResult.errors.length} issues`);
|
|
199
175
|
}
|
|
200
|
-
}
|
|
176
|
+
}
|
|
177
|
+
if (packagesToUninstall.length > 0) {
|
|
178
|
+
log.debug(`Uninstalling ${packagesToUninstall.length} orphaned packages: ${packagesToUninstall.join(', ')}`);
|
|
179
|
+
const uninstallResult = await uninstallPackages(projectPath, packagesToUninstall, packageManager);
|
|
180
|
+
if (uninstallResult.success) {
|
|
181
|
+
for (const pkg of packagesToUninstall){
|
|
182
|
+
changes.push(`Uninstalled ${pkg}`);
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
warnings.push(`Could not uninstall ${uninstallResult.failedPackages.join(', ')} — they may remain as orphaned dependencies in package.json`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const modified = astModified || changes.length > 0;
|
|
189
|
+
if (!modified) {
|
|
201
190
|
log.debug('No modifications needed - config already correct');
|
|
202
191
|
}
|
|
203
192
|
log.debug('Payload config modification completed successfully');
|
|
@@ -215,7 +204,7 @@ import { getOwnVersion } from './version-check.js';
|
|
|
215
204
|
return {
|
|
216
205
|
changes,
|
|
217
206
|
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
218
|
-
modified,
|
|
207
|
+
modified: astModified,
|
|
219
208
|
success: false
|
|
220
209
|
};
|
|
221
210
|
}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { PackageManager } from './package-manager.js';
|
|
2
|
+
export type PackageSpec = {
|
|
3
|
+
name: string;
|
|
4
|
+
version?: string;
|
|
5
|
+
};
|
|
6
|
+
export type UninstallResult = {
|
|
7
|
+
failedPackages: string[];
|
|
8
|
+
success: boolean;
|
|
9
|
+
};
|
|
2
10
|
/**
|
|
3
11
|
* Check if a package is installed in dependencies (not devDependencies)
|
|
4
12
|
*/
|
|
@@ -13,11 +21,23 @@ export declare function getPayloadVersion(projectPath: string): Promise<string |
|
|
|
13
21
|
* @param version - Version to install (without caret). Defaults to 'latest'.
|
|
14
22
|
*/
|
|
15
23
|
export declare function installPackage(projectPath: string, packageName: string, packageManager: PackageManager, version?: string): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Install multiple packages as production dependencies in a single package-manager call.
|
|
26
|
+
* No-op when packages is empty. Throws on failure with exit code and truncated stderr.
|
|
27
|
+
*/
|
|
28
|
+
export declare function installPackages(projectPath: string, packages: PackageSpec[], packageManager: PackageManager): Promise<void>;
|
|
16
29
|
/**
|
|
17
30
|
* Uninstall a package
|
|
18
31
|
* Does not throw on failure - orphaned package is better than broken config
|
|
19
32
|
*/
|
|
20
|
-
export declare function uninstallPackage(projectPath: string, packageName: string, packageManager: PackageManager): Promise<
|
|
33
|
+
export declare function uninstallPackage(projectPath: string, packageName: string, packageManager: PackageManager): Promise<UninstallResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Uninstall multiple packages in a single package-manager call.
|
|
36
|
+
* No-op when packageNames is empty. Does not throw — orphaned packages are
|
|
37
|
+
* preferable to a crash mid-config-rewrite. Returns a success flag so callers
|
|
38
|
+
* can avoid claiming "Uninstalled X" when the package manager actually failed.
|
|
39
|
+
*/
|
|
40
|
+
export declare function uninstallPackages(projectPath: string, packageNames: string[], packageManager: PackageManager): Promise<UninstallResult>;
|
|
21
41
|
/**
|
|
22
42
|
* Run an npm script from package.json
|
|
23
43
|
* Does not throw on failure - logs warning and continues
|
|
@@ -40,24 +40,33 @@ import * as log from './log.js';
|
|
|
40
40
|
* Install a package as a production dependency
|
|
41
41
|
* @param version - Version to install (without caret). Defaults to 'latest'.
|
|
42
42
|
*/ export async function installPackage(projectPath, packageName, packageManager, version = 'latest') {
|
|
43
|
+
return installPackages(projectPath, [
|
|
44
|
+
{
|
|
45
|
+
name: packageName,
|
|
46
|
+
version
|
|
47
|
+
}
|
|
48
|
+
], packageManager);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Install multiple packages as production dependencies in a single package-manager call.
|
|
52
|
+
* No-op when packages is empty. Throws on failure with exit code and truncated stderr.
|
|
53
|
+
*/ export async function installPackages(projectPath, packages, packageManager) {
|
|
54
|
+
if (packages.length === 0) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
43
57
|
return new Promise((resolve, reject)=>{
|
|
44
58
|
const command = packageManager;
|
|
45
|
-
const
|
|
59
|
+
const packageSpecs = packages.map(({ name, version })=>name.endsWith('.tgz') ? name : `${name}@${version ?? 'latest'}`);
|
|
46
60
|
const args = [
|
|
47
|
-
'add',
|
|
48
|
-
|
|
61
|
+
packageManager === 'npm' ? 'install' : 'add',
|
|
62
|
+
...packageSpecs
|
|
49
63
|
];
|
|
50
|
-
// npm uses 'install' instead of 'add'
|
|
51
|
-
if (packageManager === 'npm') {
|
|
52
|
-
args[0] = 'install';
|
|
53
|
-
}
|
|
54
64
|
log.debug(`Running: ${command} ${args.join(' ')} in ${projectPath}`);
|
|
55
65
|
let stderr = '';
|
|
56
66
|
const child = spawn(command, args, {
|
|
57
67
|
cwd: projectPath,
|
|
58
68
|
stdio: 'pipe'
|
|
59
69
|
});
|
|
60
|
-
// Capture stderr for debug logging
|
|
61
70
|
if (child.stderr) {
|
|
62
71
|
child.stderr.on('data', (data)=>{
|
|
63
72
|
stderr += data.toString();
|
|
@@ -69,15 +78,17 @@ import * as log from './log.js';
|
|
|
69
78
|
});
|
|
70
79
|
child.on('close', (code)=>{
|
|
71
80
|
if (code === 0) {
|
|
72
|
-
log.debug(`Successfully installed ${
|
|
81
|
+
log.debug(`Successfully installed ${packageSpecs.join(', ')}`);
|
|
73
82
|
resolve();
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
reject(new Error(`Failed to install ${packageName}`));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
log.debug(`Batched install failed (exit code: ${code})`);
|
|
86
|
+
if (stderr) {
|
|
87
|
+
log.debug(`stderr: ${stderr}`);
|
|
80
88
|
}
|
|
89
|
+
const truncatedStderr = stderr.trim().slice(-500);
|
|
90
|
+
const detail = truncatedStderr ? `\n${truncatedStderr}` : '';
|
|
91
|
+
reject(new Error(`Failed to install: ${packageSpecs.join(', ')} (exit code ${code})${detail}`));
|
|
81
92
|
});
|
|
82
93
|
});
|
|
83
94
|
}
|
|
@@ -85,29 +96,58 @@ import * as log from './log.js';
|
|
|
85
96
|
* Uninstall a package
|
|
86
97
|
* Does not throw on failure - orphaned package is better than broken config
|
|
87
98
|
*/ export async function uninstallPackage(projectPath, packageName, packageManager) {
|
|
99
|
+
return uninstallPackages(projectPath, [
|
|
100
|
+
packageName
|
|
101
|
+
], packageManager);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Uninstall multiple packages in a single package-manager call.
|
|
105
|
+
* No-op when packageNames is empty. Does not throw — orphaned packages are
|
|
106
|
+
* preferable to a crash mid-config-rewrite. Returns a success flag so callers
|
|
107
|
+
* can avoid claiming "Uninstalled X" when the package manager actually failed.
|
|
108
|
+
*/ export async function uninstallPackages(projectPath, packageNames, packageManager) {
|
|
109
|
+
if (packageNames.length === 0) {
|
|
110
|
+
return {
|
|
111
|
+
failedPackages: [],
|
|
112
|
+
success: true
|
|
113
|
+
};
|
|
114
|
+
}
|
|
88
115
|
return new Promise((resolve)=>{
|
|
89
116
|
const command = packageManager;
|
|
90
117
|
const args = [
|
|
91
|
-
'remove',
|
|
92
|
-
|
|
118
|
+
packageManager === 'npm' ? 'uninstall' : 'remove',
|
|
119
|
+
...packageNames
|
|
93
120
|
];
|
|
94
|
-
// npm uses 'uninstall' instead of 'remove'
|
|
95
|
-
if (packageManager === 'npm') {
|
|
96
|
-
args[0] = 'uninstall';
|
|
97
|
-
}
|
|
98
121
|
log.debug(`Running: ${command} ${args.join(' ')} in ${projectPath}`);
|
|
99
122
|
const child = spawn(command, args, {
|
|
100
123
|
cwd: projectPath,
|
|
101
124
|
stdio: 'pipe'
|
|
102
125
|
});
|
|
126
|
+
child.on('error', (error)=>{
|
|
127
|
+
log.debug(`Spawn error for ${command}: ${error.message}`);
|
|
128
|
+
resolve({
|
|
129
|
+
failedPackages: [
|
|
130
|
+
...packageNames
|
|
131
|
+
],
|
|
132
|
+
success: false
|
|
133
|
+
});
|
|
134
|
+
});
|
|
103
135
|
child.on('close', (code)=>{
|
|
104
136
|
if (code === 0) {
|
|
105
|
-
log.debug(`Successfully uninstalled ${
|
|
106
|
-
|
|
107
|
-
|
|
137
|
+
log.debug(`Successfully uninstalled ${packageNames.join(', ')}`);
|
|
138
|
+
resolve({
|
|
139
|
+
failedPackages: [],
|
|
140
|
+
success: true
|
|
141
|
+
});
|
|
142
|
+
return;
|
|
108
143
|
}
|
|
109
|
-
|
|
110
|
-
resolve(
|
|
144
|
+
log.debug(`Batched uninstall failed (exit code: ${code}), continuing anyway`);
|
|
145
|
+
resolve({
|
|
146
|
+
failedPackages: [
|
|
147
|
+
...packageNames
|
|
148
|
+
],
|
|
149
|
+
success: false
|
|
150
|
+
});
|
|
111
151
|
});
|
|
112
152
|
});
|
|
113
153
|
}
|
package/dist/utils/project.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Project detection and scaffolding utilities
|
|
3
3
|
*/
|
|
4
4
|
import type { ProjectInfo } from '../types/config.js';
|
|
5
|
+
import type { TemplateSource } from './download-template.js';
|
|
5
6
|
import type { PackageManager } from './package-manager.js';
|
|
6
7
|
/**
|
|
7
8
|
* Detect if current directory has a Payload project
|
|
@@ -23,7 +24,7 @@ export declare function validatePayloadVersion(version: string): boolean;
|
|
|
23
24
|
* @param projectPath - Path where to create the project
|
|
24
25
|
* @param projectName - Name for the project
|
|
25
26
|
*/
|
|
26
|
-
export declare function scaffoldProject(projectPath: string, projectName: string, packageManager?: PackageManager): Promise<void>;
|
|
27
|
+
export declare function scaffoldProject(projectPath: string, projectName: string, packageManager?: PackageManager, templateSource?: Partial<TemplateSource>): Promise<void>;
|
|
27
28
|
/**
|
|
28
29
|
* Initialize git repository after all setup is complete
|
|
29
30
|
*
|
package/dist/utils/project.js
CHANGED
|
@@ -120,13 +120,13 @@ import { getOwnVersion } from './version-check.js';
|
|
|
120
120
|
*
|
|
121
121
|
* @param projectPath - Path where to create the project
|
|
122
122
|
* @param projectName - Name for the project
|
|
123
|
-
*/ export async function scaffoldProject(projectPath, projectName, packageManager = 'npm') {
|
|
123
|
+
*/ export async function scaffoldProject(projectPath, projectName, packageManager = 'npm', templateSource) {
|
|
124
124
|
// Create project directory if it doesn't exist
|
|
125
125
|
await fs.mkdir(projectPath, {
|
|
126
126
|
recursive: true
|
|
127
127
|
});
|
|
128
128
|
// Download template from GitHub
|
|
129
|
-
await downloadTemplateFromGitHub(projectPath);
|
|
129
|
+
await downloadTemplateFromGitHub(projectPath, templateSource);
|
|
130
130
|
// Apply Lambda modifications BEFORE updating package.json
|
|
131
131
|
// This ensures we don't overwrite version replacements
|
|
132
132
|
await applyLambdaModifications(projectPath, packageManager);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payloadcms/figma",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.65",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -47,10 +47,18 @@
|
|
|
47
47
|
"uuid": "^10.0.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
+
"@payloadcms/eslint-config": "3.28.0",
|
|
51
|
+
"@payloadcms/eslint-plugin": "3.28.0",
|
|
52
|
+
"@swc/cli": "0.7.7",
|
|
50
53
|
"@types/archiver": "7.0.0",
|
|
51
54
|
"@types/cross-spawn": "6.0.6",
|
|
55
|
+
"@types/jsonwebtoken": "^9.0.10",
|
|
52
56
|
"@types/node": "22.12.0",
|
|
57
|
+
"@types/uuid": "^8.3.4",
|
|
58
|
+
"copyfiles": "^2.4.1",
|
|
59
|
+
"eslint": "9.22.0",
|
|
53
60
|
"openapi-typescript": "^7.13.0",
|
|
61
|
+
"rimraf": "^6.1.3",
|
|
54
62
|
"tsx": "4.20.6",
|
|
55
63
|
"typescript": "5.7.3",
|
|
56
64
|
"vitest": "4.0.15"
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# Content API Database Adapter Parity
|
|
2
|
-
|
|
3
|
-
This document explains how the Content API database adapter differs from Payload today and how it will behave once alignment is complete.
|
|
4
|
-
|
|
5
|
-
The Content API is an internal service built exclusively for Payload. Because of that, the adapter should match Payload by default and only diverge when there is a strong technical reason.
|
|
6
|
-
|
|
7
|
-
## Where
|
|
8
|
-
|
|
9
|
-
Now
|
|
10
|
-
`{ path: "slug", operator: "equals", value: "hello", type: "text" }`
|
|
11
|
-
|
|
12
|
-
Future
|
|
13
|
-
`{ path: "slug", operator: "equals", value: "hello", type: "text" }`
|
|
14
|
-
|
|
15
|
-
The format stays different. This allows the Content API to evolve its filter schema, for example to support composite types like Point, which are not lexicographically sortable. Semantics must remain identical to Payload.
|
|
16
|
-
|
|
17
|
-
## Pagination
|
|
18
|
-
|
|
19
|
-
~~Now~~
|
|
20
|
-
~~`{ limit: 10, offset: 20 }`~~
|
|
21
|
-
|
|
22
|
-
✅ Partially Implemented
|
|
23
|
-
`{ limit: 10, page: 3 }`
|
|
24
|
-
|
|
25
|
-
**Status:**
|
|
26
|
-
|
|
27
|
-
- ✅ Content API main endpoints use `page` (matches Payload)
|
|
28
|
-
|
|
29
|
-
- ⚠️ **Issue #1 (Joins):** `JoinClause` still uses `offset` instead of `page`
|
|
30
|
-
- Payload `JoinQuery`: `{ page?: number, limit?: number }`
|
|
31
|
-
- Content API `JoinClause`: `{ offset?: number, limit?: number }`
|
|
32
|
-
- **Inconsistent** with main endpoints which use `page`
|
|
33
|
-
|
|
34
|
-
**Current workaround for joins:** The adapter converts `page` to `offset`:
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
// Payload join query
|
|
38
|
-
{ page: 2, limit: 5 }
|
|
39
|
-
// Adapter converts to offset for Content API
|
|
40
|
-
{ offset: 5, limit: 5 }
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
**Future:**
|
|
44
|
-
|
|
45
|
-
1. Content API should support `skip` parameter for main endpoints
|
|
46
|
-
2. Content API `JoinClause` should use `page` instead of `offset` (consistent with main endpoints)
|
|
47
|
-
3. Content API pagination response should match Payload's flat structure
|
|
48
|
-
|
|
49
|
-
### Pagination Response Structure
|
|
50
|
-
|
|
51
|
-
**Payload format (flat):**
|
|
52
|
-
|
|
53
|
-
```typescript
|
|
54
|
-
{
|
|
55
|
-
docs: [...],
|
|
56
|
-
hasNextPage: boolean,
|
|
57
|
-
hasPrevPage: boolean,
|
|
58
|
-
limit: number,
|
|
59
|
-
nextPage: number | null,
|
|
60
|
-
page: number,
|
|
61
|
-
pagingCounter: number,
|
|
62
|
-
prevPage: number | null,
|
|
63
|
-
totalDocs: number,
|
|
64
|
-
totalPages: number
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
**Content API format (nested):**
|
|
69
|
-
|
|
70
|
-
```typescript
|
|
71
|
-
{
|
|
72
|
-
data: [...],
|
|
73
|
-
pagination: {
|
|
74
|
-
total: number,
|
|
75
|
-
current: { limit: number, page: number },
|
|
76
|
-
next?: { limit: number, page: number },
|
|
77
|
-
prev?: { limit: number, page: number }
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
**Current workaround:** The adapter transforms Content API's nested structure to Payload's flat structure using `getPaginationData()` utility.
|
|
83
|
-
|
|
84
|
-
## Slugs
|
|
85
|
-
|
|
86
|
-
Now
|
|
87
|
-
`{ collection: { key: "posts" } }`
|
|
88
|
-
|
|
89
|
-
Future
|
|
90
|
-
`{ collection: { slug: "posts" } }`
|
|
91
|
-
|
|
92
|
-
Collection identifiers will match Payload. Consumers should not be aware of internal collection IDs.
|
|
93
|
-
|
|
94
|
-
## Temporary Conversions
|
|
95
|
-
|
|
96
|
-
Helpers that translate Payload queries into the current Content API format are temporary and placed in the `temp-utilities` folder.
|
|
97
|
-
|
|
98
|
-
They live in the `temp-utilities` folder until the Content API is fully aligned with Payload.
|