@payloadcms/figma 0.0.1-alpha.64 → 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.
Files changed (40) hide show
  1. package/dist/auth/callback-server.d.ts +19 -7
  2. package/dist/auth/callback-server.js +72 -31
  3. package/dist/auth/crypto-utils.d.ts +11 -0
  4. package/dist/auth/crypto-utils.js +22 -1
  5. package/dist/auth/oauth-flow.d.ts +3 -1
  6. package/dist/auth/oauth-flow.js +13 -6
  7. package/dist/auth/token-store.d.ts +2 -0
  8. package/dist/auth/token-store.js +41 -1
  9. package/dist/auth/types.d.ts +7 -0
  10. package/dist/cli.js +6 -1
  11. package/dist/commands/init.d.ts +4 -0
  12. package/dist/commands/init.js +44 -2
  13. package/dist/config/oauth.d.ts +2 -1
  14. package/dist/config/oauth.js +7 -1
  15. package/dist/db-content-api/generated/content-api-types.d.ts +6 -0
  16. package/dist/db-content-api/index.d.ts +2 -0
  17. package/dist/db-content-api/index.js +9 -1
  18. package/dist/lib/download-skill.d.ts +13 -0
  19. package/dist/lib/download-skill.js +79 -0
  20. package/dist/oauth/endpoints/getLoginEndpoint.js +26 -107
  21. package/dist/oauth/endpoints/getTokenLoginEndpoint.d.ts +17 -0
  22. package/dist/oauth/endpoints/getTokenLoginEndpoint.js +105 -0
  23. package/dist/oauth/index.js +8 -0
  24. package/dist/oauth/utilities/establishSession.d.ts +23 -0
  25. package/dist/oauth/utilities/establishSession.js +82 -0
  26. package/dist/oauth/utilities/exchangeCodeForAccessToken.d.ts +24 -0
  27. package/dist/oauth/utilities/exchangeCodeForAccessToken.js +28 -0
  28. package/dist/oauth/utilities/isAbsoluteURL.d.ts +2 -0
  29. package/dist/oauth/utilities/isAbsoluteURL.js +3 -0
  30. package/dist/plugin/build-config.js +3 -0
  31. package/dist/types.d.ts +2 -0
  32. package/dist/utils/download-template.d.ts +9 -1
  33. package/dist/utils/download-template.js +24 -19
  34. package/dist/utils/messages.js +2 -0
  35. package/dist/utils/parse-template-spec.d.ts +12 -0
  36. package/dist/utils/parse-template-spec.js +62 -0
  37. package/dist/utils/project.d.ts +2 -1
  38. package/dist/utils/project.js +2 -2
  39. package/package.json +9 -1
  40. package/dist/db-content-api/README.md +0 -98
@@ -220,6 +220,7 @@ export async function buildFigmaConfig(config) {
220
220
  mode: 'apiKey'
221
221
  },
222
222
  contentSystemId,
223
+ environmentName: process.env.FIGMA_ENVIRONMENT_NAME,
223
224
  url
224
225
  });
225
226
  } else if (process.env.FIGMA_DEV_JWT === 'true') {
@@ -228,6 +229,7 @@ export async function buildFigmaConfig(config) {
228
229
  mode: 'devJwt'
229
230
  },
230
231
  contentSystemId,
232
+ environmentName: process.env.FIGMA_ENVIRONMENT_NAME,
231
233
  url
232
234
  });
233
235
  } else {
@@ -237,6 +239,7 @@ export async function buildFigmaConfig(config) {
237
239
  tokenStore: getTokenStore()
238
240
  },
239
241
  contentSystemId,
242
+ environmentName: process.env.FIGMA_ENVIRONMENT_NAME,
240
243
  url
241
244
  });
242
245
  }
package/dist/types.d.ts CHANGED
@@ -11,11 +11,13 @@ export interface Args extends arg.Spec {
11
11
  '--list': BooleanConstructor;
12
12
  '--logout': BooleanConstructor;
13
13
  '--name': StringConstructor;
14
+ '--template': StringConstructor;
14
15
  '--yes': BooleanConstructor;
15
16
  '-e': string;
16
17
  '-f': string;
17
18
  '-h': string;
18
19
  '-n': string;
20
+ '-t': string;
19
21
  '-y': string;
20
22
  }
21
23
  export type CliArgs = arg.Result<Args>;
@@ -5,11 +5,19 @@ export declare class TemplateDownloadError extends Error {
5
5
  cause?: Error | undefined;
6
6
  constructor(message: string, cause?: Error | undefined);
7
7
  }
8
+ export type TemplateSource = {
9
+ owner: string;
10
+ ref: string;
11
+ repo: string;
12
+ templatePath: string;
13
+ };
14
+ export declare const DEFAULT_TEMPLATE_SOURCE: TemplateSource;
8
15
  /**
9
16
  * Download Payload template from GitHub with retry logic
10
17
  *
11
18
  * @param projectDir - Directory to extract template into
19
+ * @param source - Optional override of repo / ref / template path
12
20
  * @throws TemplateDownloadError if download fails
13
21
  */
14
- export declare function downloadTemplateFromGitHub(projectDir: string): Promise<void>;
22
+ export declare function downloadTemplateFromGitHub(projectDir: string, source?: Partial<TemplateSource>): Promise<void>;
15
23
  //# sourceMappingURL=download-template.d.ts.map
@@ -11,23 +11,30 @@ import { x } from 'tar';
11
11
  this.name = 'TemplateDownloadError';
12
12
  }
13
13
  }
14
- const BRANCH_OR_TAG = 'v3.79.1';
15
- /** GitHub strips the 'v' prefix in tarball directory names */ const TARBALL_PREFIX = `payload-${BRANCH_OR_TAG.replace(/^v/, '')}`;
16
- const TEMPLATE_NAME = 'blank';
14
+ export const DEFAULT_TEMPLATE_SOURCE = {
15
+ owner: 'payloadcms',
16
+ ref: 'v3.84.1',
17
+ repo: 'payload',
18
+ templatePath: 'blank'
19
+ };
17
20
  const MAX_RETRIES = 3;
18
- const INITIAL_RETRY_DELAY = 1000 // 1 second
19
- ;
21
+ const INITIAL_RETRY_DELAY = 1000;
20
22
  /**
21
23
  * Download Payload template from GitHub with retry logic
22
24
  *
23
25
  * @param projectDir - Directory to extract template into
26
+ * @param source - Optional override of repo / ref / template path
24
27
  * @throws TemplateDownloadError if download fails
25
- */ export async function downloadTemplateFromGitHub(projectDir) {
28
+ */ export async function downloadTemplateFromGitHub(projectDir, source) {
29
+ const resolved = {
30
+ ...DEFAULT_TEMPLATE_SOURCE,
31
+ ...source
32
+ };
26
33
  let lastError;
27
34
  for(let attempt = 1; attempt <= MAX_RETRIES; attempt++){
28
35
  try {
29
- await downloadTemplateAttempt(projectDir);
30
- return; // Success
36
+ await downloadTemplateAttempt(projectDir, resolved);
37
+ return;
31
38
  } catch (error) {
32
39
  lastError = error instanceof Error ? error : new Error('Unknown error');
33
40
  if (attempt < MAX_RETRIES) {
@@ -37,31 +44,29 @@ const INITIAL_RETRY_DELAY = 1000 // 1 second
37
44
  }
38
45
  }
39
46
  }
40
- // All retries failed
41
47
  throw new TemplateDownloadError(`Failed to download template after ${MAX_RETRIES} attempts`, lastError);
42
48
  }
43
- /**
44
- * Single attempt to download template (extracted for retry logic)
45
- */ async function downloadTemplateAttempt(projectDir) {
46
- const url = `https://codeload.github.com/payloadcms/payload/tar.gz/${BRANCH_OR_TAG}`;
47
- const filter = `${TARBALL_PREFIX}/templates/${TEMPLATE_NAME}/`;
49
+ async function downloadTemplateAttempt(projectDir, source) {
50
+ const url = `https://codeload.github.com/${source.owner}/${source.repo}/tar.gz/${source.ref}`;
51
+ // GitHub strips the leading 'v' and replaces '/' with '-' when naming the tarball root dir
52
+ const refSlug = source.ref.replace(/^v/, '').replace(/\//g, '-');
53
+ const tarballPrefix = `${source.repo}-${refSlug}`;
54
+ const filter = `${tarballPrefix}/templates/${source.templatePath}/`;
55
+ const strip = 2 + source.templatePath.split('/').length;
48
56
  try {
49
- // Ensure target directory exists
50
57
  await fs.mkdir(projectDir, {
51
58
  recursive: true
52
59
  });
53
60
  await pipeline(await downloadTarStream(url), x({
54
61
  cwd: projectDir,
55
62
  filter: (p)=>p.includes(filter),
56
- strip: 2 + TEMPLATE_NAME.split('/').length
63
+ strip
57
64
  }));
58
65
  } catch (error) {
59
66
  throw new TemplateDownloadError('Failed to download template from GitHub', error instanceof Error ? error : undefined);
60
67
  }
61
68
  }
62
- /**
63
- * Download tar stream from URL
64
- */ async function downloadTarStream(url) {
69
+ async function downloadTarStream(url) {
65
70
  const res = await fetch(url);
66
71
  if (!res.ok) {
67
72
  throw new Error(`HTTP ${res.status}: ${res.statusText}`);
@@ -39,6 +39,8 @@ export function helpMessage() {
39
39
  ${pc.cyan('@payloadcms/figma init --id <id> --env staging')} Initialize for specific environment
40
40
  ${pc.dim('--name, -n <name>')} Set project directory name (skips prompt)
41
41
  ${pc.dim('--force')} Force reconfiguration of existing project
42
+ ${pc.dim('--no-skill')} Skip installing the Payload skill into .claude/skills/payload/
43
+ ${pc.dim('--template, -t <spec>')} Override scaffold template (e.g. v3.80.0:website, owner/repo#ref:path)
42
44
 
43
45
  ${pc.bold('BOOTSTRAP COMMAND')}
44
46
 
@@ -0,0 +1,12 @@
1
+ import type { TemplateSource } from './download-template.js';
2
+ export declare class TemplateSpecParseError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ /**
6
+ * Parse a --template spec string into a partial TemplateSource override.
7
+ *
8
+ * Format: [<owner>/<repo>#]<ref>:<template-path>
9
+ * Shorthand: a bare token with no `#` and no `:` is treated as the template path.
10
+ */
11
+ export declare function parseTemplateSpec(spec: string): Partial<TemplateSource>;
12
+ //# sourceMappingURL=parse-template-spec.d.ts.map
@@ -0,0 +1,62 @@
1
+ export class TemplateSpecParseError extends Error {
2
+ constructor(message){
3
+ super(message);
4
+ this.name = 'TemplateSpecParseError';
5
+ }
6
+ }
7
+ /**
8
+ * Parse a --template spec string into a partial TemplateSource override.
9
+ *
10
+ * Format: [<owner>/<repo>#]<ref>:<template-path>
11
+ * Shorthand: a bare token with no `#` and no `:` is treated as the template path.
12
+ */ export function parseTemplateSpec(spec) {
13
+ const trimmed = spec.trim();
14
+ if (!trimmed) {
15
+ throw new TemplateSpecParseError('Template spec is empty');
16
+ }
17
+ let rest = trimmed;
18
+ const result = {};
19
+ const hashIndex = rest.indexOf('#');
20
+ if (hashIndex !== -1) {
21
+ const repoPart = rest.slice(0, hashIndex);
22
+ rest = rest.slice(hashIndex + 1);
23
+ const slashCount = (repoPart.match(/\//g) ?? []).length;
24
+ if (slashCount !== 1) {
25
+ throw new TemplateSpecParseError(`Expected "<owner>/<repo>" before "#", got "${repoPart}"`);
26
+ }
27
+ const [owner, repo] = repoPart.split('/');
28
+ if (!owner || !repo) {
29
+ throw new TemplateSpecParseError(`Invalid owner/repo: "${repoPart}"`);
30
+ }
31
+ result.owner = owner;
32
+ result.repo = repo;
33
+ } else {
34
+ // Check for slash only in the portion before the first colon (the ref part).
35
+ // Slashes after the colon are valid multi-segment template paths.
36
+ const beforeColon = rest.includes(':') ? rest.slice(0, rest.indexOf(':')) : rest;
37
+ if (beforeColon.includes('/')) {
38
+ throw new TemplateSpecParseError(`"<owner>/<repo>" must be followed by "#<ref>" (got "${trimmed}")`);
39
+ }
40
+ }
41
+ const colonIndex = rest.indexOf(':');
42
+ if (colonIndex !== -1) {
43
+ const ref = rest.slice(0, colonIndex);
44
+ const templatePath = rest.slice(colonIndex + 1);
45
+ if (!ref) {
46
+ throw new TemplateSpecParseError('Ref before ":" is empty');
47
+ }
48
+ if (!templatePath) {
49
+ throw new TemplateSpecParseError('Template path after ":" is empty');
50
+ }
51
+ result.ref = ref;
52
+ result.templatePath = templatePath;
53
+ return result;
54
+ }
55
+ if (hashIndex !== -1) {
56
+ throw new TemplateSpecParseError('Spec with "<owner>/<repo>#<ref>" must include ":<template-path>"');
57
+ }
58
+ result.templatePath = rest;
59
+ return result;
60
+ }
61
+
62
+ //# sourceMappingURL=parse-template-spec.js.map
@@ -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
  *
@@ -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.64",
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.