@payloadcms/figma 0.0.1-alpha.3 → 0.0.1-alpha.31

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 (229) hide show
  1. package/dist/api/control-plane.d.ts +22 -1
  2. package/dist/api/control-plane.d.ts.map +1 -1
  3. package/dist/api/control-plane.js +54 -15
  4. package/dist/api/control-plane.js.map +1 -1
  5. package/dist/api/figma-api.d.ts.map +1 -1
  6. package/dist/api/figma-api.js +42 -12
  7. package/dist/api/figma-api.js.map +1 -1
  8. package/dist/auth/callback-server.d.ts.map +1 -1
  9. package/dist/auth/callback-server.js +2 -1
  10. package/dist/auth/callback-server.js.map +1 -1
  11. package/dist/auth/crypto-utils.d.ts.map +1 -1
  12. package/dist/auth/crypto-utils.js +5 -5
  13. package/dist/auth/crypto-utils.js.map +1 -1
  14. package/dist/auth/oauth-flow.d.ts +1 -1
  15. package/dist/auth/oauth-flow.d.ts.map +1 -1
  16. package/dist/auth/oauth-flow.js +5 -5
  17. package/dist/auth/oauth-flow.js.map +1 -1
  18. package/dist/auth/project-token.d.ts.map +1 -1
  19. package/dist/auth/project-token.js +9 -4
  20. package/dist/auth/project-token.js.map +1 -1
  21. package/dist/auth/token-store.d.ts +10 -0
  22. package/dist/auth/token-store.d.ts.map +1 -1
  23. package/dist/auth/token-store.js +20 -0
  24. package/dist/auth/token-store.js.map +1 -1
  25. package/dist/cli.js +3 -0
  26. package/dist/cli.js.map +1 -1
  27. package/dist/commands/deploy.d.ts +4 -0
  28. package/dist/commands/deploy.d.ts.map +1 -1
  29. package/dist/commands/deploy.js +68 -126
  30. package/dist/commands/deploy.js.map +1 -1
  31. package/dist/commands/init.d.ts +1 -5
  32. package/dist/commands/init.d.ts.map +1 -1
  33. package/dist/commands/init.js +90 -85
  34. package/dist/commands/init.js.map +1 -1
  35. package/dist/commands/list-tokens.js +2 -2
  36. package/dist/commands/list-tokens.js.map +1 -1
  37. package/dist/commands/login.d.ts +8 -1
  38. package/dist/commands/login.d.ts.map +1 -1
  39. package/dist/commands/login.js +12 -6
  40. package/dist/commands/login.js.map +1 -1
  41. package/dist/commands/logout.js +2 -2
  42. package/dist/commands/logout.js.map +1 -1
  43. package/dist/config/oauth.d.ts +5 -0
  44. package/dist/config/oauth.d.ts.map +1 -1
  45. package/dist/config/oauth.js +9 -4
  46. package/dist/config/oauth.js.map +1 -1
  47. package/dist/db-content-api/README.md +108 -0
  48. package/dist/db-content-api/generated/content-api-types.d.ts +3702 -0
  49. package/dist/db-content-api/generated/content-api-types.d.ts.map +1 -0
  50. package/dist/db-content-api/generated/content-api-types.js +7 -0
  51. package/dist/db-content-api/generated/content-api-types.js.map +1 -0
  52. package/dist/db-content-api/index.d.ts +18 -0
  53. package/dist/db-content-api/index.d.ts.map +1 -0
  54. package/dist/db-content-api/index.js +572 -0
  55. package/dist/db-content-api/index.js.map +1 -0
  56. package/dist/db-content-api/temp-utilities/pagination.d.ts +13 -0
  57. package/dist/db-content-api/temp-utilities/pagination.d.ts.map +1 -0
  58. package/dist/db-content-api/temp-utilities/pagination.js +45 -0
  59. package/dist/db-content-api/temp-utilities/pagination.js.map +1 -0
  60. package/dist/db-content-api/temp-utilities/slug.d.ts +2 -0
  61. package/dist/db-content-api/temp-utilities/slug.d.ts.map +1 -0
  62. package/dist/db-content-api/temp-utilities/slug.js +3 -0
  63. package/dist/db-content-api/temp-utilities/slug.js.map +1 -0
  64. package/dist/db-content-api/temp-utilities/sorting.d.ts +7 -0
  65. package/dist/db-content-api/temp-utilities/sorting.d.ts.map +1 -0
  66. package/dist/db-content-api/temp-utilities/sorting.js +71 -0
  67. package/dist/db-content-api/temp-utilities/sorting.js.map +1 -0
  68. package/dist/db-content-api/temp-utilities/unwrapDocument.d.ts +4 -0
  69. package/dist/db-content-api/temp-utilities/unwrapDocument.d.ts.map +1 -0
  70. package/dist/db-content-api/temp-utilities/unwrapDocument.js +53 -0
  71. package/dist/db-content-api/temp-utilities/unwrapDocument.js.map +1 -0
  72. package/dist/db-content-api/utilities/auth.d.ts +30 -0
  73. package/dist/db-content-api/utilities/auth.d.ts.map +1 -0
  74. package/dist/db-content-api/utilities/auth.js +81 -0
  75. package/dist/db-content-api/utilities/auth.js.map +1 -0
  76. package/dist/db-content-api/utilities/data/applyDefaults.d.ts +7 -0
  77. package/dist/db-content-api/utilities/data/applyDefaults.d.ts.map +1 -0
  78. package/dist/db-content-api/utilities/data/applyDefaults.js +59 -0
  79. package/dist/db-content-api/utilities/data/applyDefaults.js.map +1 -0
  80. package/dist/db-content-api/utilities/data/castFieldValue.d.ts +11 -0
  81. package/dist/db-content-api/utilities/data/castFieldValue.d.ts.map +1 -0
  82. package/dist/db-content-api/utilities/data/castFieldValue.js +66 -0
  83. package/dist/db-content-api/utilities/data/castFieldValue.js.map +1 -0
  84. package/dist/db-content-api/utilities/data/index.d.ts +28 -0
  85. package/dist/db-content-api/utilities/data/index.d.ts.map +1 -0
  86. package/dist/db-content-api/utilities/data/index.js +166 -0
  87. package/dist/db-content-api/utilities/data/index.js.map +1 -0
  88. package/dist/db-content-api/utilities/data/stripFields.d.ts +48 -0
  89. package/dist/db-content-api/utilities/data/stripFields.d.ts.map +1 -0
  90. package/dist/db-content-api/utilities/data/stripFields.js +195 -0
  91. package/dist/db-content-api/utilities/data/stripFields.js.map +1 -0
  92. package/dist/db-content-api/utilities/joins.d.ts +55 -0
  93. package/dist/db-content-api/utilities/joins.d.ts.map +1 -0
  94. package/dist/db-content-api/utilities/joins.js +130 -0
  95. package/dist/db-content-api/utilities/joins.js.map +1 -0
  96. package/dist/db-content-api/utilities/where.d.ts +12 -0
  97. package/dist/db-content-api/utilities/where.d.ts.map +1 -0
  98. package/dist/db-content-api/utilities/where.js +107 -0
  99. package/dist/db-content-api/utilities/where.js.map +1 -0
  100. package/dist/endpoints/health.d.ts +3 -0
  101. package/dist/endpoints/health.d.ts.map +1 -0
  102. package/dist/endpoints/health.js +11 -0
  103. package/dist/endpoints/health.js.map +1 -0
  104. package/dist/exports/client.d.ts +4 -0
  105. package/dist/exports/client.d.ts.map +1 -0
  106. package/dist/exports/client.js +5 -0
  107. package/dist/exports/client.js.map +1 -0
  108. package/dist/index.d.ts +2 -1
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +3 -1
  111. package/dist/index.js.map +1 -1
  112. package/dist/oauth/components/LoginButton/index.d.ts.map +1 -1
  113. package/dist/oauth/components/LoginButton/index.js +50 -6
  114. package/dist/oauth/components/LoginButton/index.js.map +1 -1
  115. package/dist/oauth/components/LoginButton/index.scss +50 -3
  116. package/dist/oauth/components/LogoutButton/index.d.ts.map +1 -1
  117. package/dist/oauth/components/LogoutButton/index.js +0 -1
  118. package/dist/oauth/components/LogoutButton/index.js.map +1 -1
  119. package/dist/oauth/defaults.d.ts.map +1 -1
  120. package/dist/oauth/defaults.js +29 -5
  121. package/dist/oauth/defaults.js.map +1 -1
  122. package/dist/oauth/endpoints/getLoginEndpoint.d.ts.map +1 -1
  123. package/dist/oauth/endpoints/getLoginEndpoint.js +1 -1
  124. package/dist/oauth/endpoints/getLoginEndpoint.js.map +1 -1
  125. package/dist/oauth/index.d.ts.map +1 -1
  126. package/dist/oauth/index.js +42 -6
  127. package/dist/oauth/index.js.map +1 -1
  128. package/dist/oauth/strategy/index.d.ts.map +1 -1
  129. package/dist/oauth/strategy/index.js +6 -2
  130. package/dist/oauth/strategy/index.js.map +1 -1
  131. package/dist/oauth/types.d.ts +6 -6
  132. package/dist/oauth/types.d.ts.map +1 -1
  133. package/dist/oauth/types.js.map +1 -1
  134. package/dist/oauth/utilities/createCookieOptions.d.ts.map +1 -1
  135. package/dist/oauth/utilities/createCookieOptions.js.map +1 -1
  136. package/dist/oauth/utilities/isDuplicateKeyError.d.ts +7 -0
  137. package/dist/oauth/utilities/isDuplicateKeyError.d.ts.map +1 -0
  138. package/dist/oauth/utilities/isDuplicateKeyError.js +14 -0
  139. package/dist/oauth/utilities/isDuplicateKeyError.js.map +1 -0
  140. package/dist/oauth/utilities/refreshTokens.d.ts.map +1 -1
  141. package/dist/oauth/utilities/refreshTokens.js +1 -1
  142. package/dist/oauth/utilities/refreshTokens.js.map +1 -1
  143. package/dist/plugin/build-config.d.ts +21 -4
  144. package/dist/plugin/build-config.d.ts.map +1 -1
  145. package/dist/plugin/build-config.js +103 -9
  146. package/dist/plugin/build-config.js.map +1 -1
  147. package/dist/storage-content-api/api-types.d.ts +161 -0
  148. package/dist/storage-content-api/api-types.d.ts.map +1 -0
  149. package/dist/storage-content-api/api-types.js +6 -0
  150. package/dist/storage-content-api/api-types.js.map +1 -0
  151. package/dist/storage-content-api/client-uploads/ClientUploadHandler.d.ts +9 -0
  152. package/dist/storage-content-api/client-uploads/ClientUploadHandler.d.ts.map +1 -0
  153. package/dist/storage-content-api/client-uploads/ClientUploadHandler.js +42 -0
  154. package/dist/storage-content-api/client-uploads/ClientUploadHandler.js.map +1 -0
  155. package/dist/storage-content-api/client-uploads/generateSignedURL.d.ts +13 -0
  156. package/dist/storage-content-api/client-uploads/generateSignedURL.d.ts.map +1 -0
  157. package/dist/storage-content-api/client-uploads/generateSignedURL.js +31 -0
  158. package/dist/storage-content-api/client-uploads/generateSignedURL.js.map +1 -0
  159. package/dist/storage-content-api/client.d.ts +6 -0
  160. package/dist/storage-content-api/client.d.ts.map +1 -0
  161. package/dist/storage-content-api/client.js +36 -0
  162. package/dist/storage-content-api/client.js.map +1 -0
  163. package/dist/storage-content-api/generateURL.d.ts +7 -0
  164. package/dist/storage-content-api/generateURL.d.ts.map +1 -0
  165. package/dist/storage-content-api/generateURL.js +7 -0
  166. package/dist/storage-content-api/generateURL.js.map +1 -0
  167. package/dist/storage-content-api/handleDelete.d.ts +8 -0
  168. package/dist/storage-content-api/handleDelete.d.ts.map +1 -0
  169. package/dist/storage-content-api/handleDelete.js +15 -0
  170. package/dist/storage-content-api/handleDelete.js.map +1 -0
  171. package/dist/storage-content-api/handleUpload.d.ts +11 -0
  172. package/dist/storage-content-api/handleUpload.d.ts.map +1 -0
  173. package/dist/storage-content-api/handleUpload.js +136 -0
  174. package/dist/storage-content-api/handleUpload.js.map +1 -0
  175. package/dist/storage-content-api/index.d.ts +5 -0
  176. package/dist/storage-content-api/index.d.ts.map +1 -0
  177. package/dist/storage-content-api/index.js +31 -0
  178. package/dist/storage-content-api/index.js.map +1 -0
  179. package/dist/storage-content-api/staticHandler.d.ts +10 -0
  180. package/dist/storage-content-api/staticHandler.d.ts.map +1 -0
  181. package/dist/storage-content-api/staticHandler.js +55 -0
  182. package/dist/storage-content-api/staticHandler.js.map +1 -0
  183. package/dist/storage-content-api/types.d.ts +10 -0
  184. package/dist/storage-content-api/types.d.ts.map +1 -0
  185. package/dist/storage-content-api/types.js +3 -0
  186. package/dist/storage-content-api/types.js.map +1 -0
  187. package/dist/templates/README.md +19 -0
  188. package/dist/utils/env-management.d.ts +9 -8
  189. package/dist/utils/env-management.d.ts.map +1 -1
  190. package/dist/utils/env-management.js +73 -74
  191. package/dist/utils/env-management.js.map +1 -1
  192. package/dist/utils/formatter.d.ts.map +1 -1
  193. package/dist/utils/formatter.js +1 -7
  194. package/dist/utils/formatter.js.map +1 -1
  195. package/dist/utils/lambda-config.d.ts.map +1 -1
  196. package/dist/utils/lambda-config.js +1 -0
  197. package/dist/utils/lambda-config.js.map +1 -1
  198. package/dist/utils/messages.d.ts.map +1 -1
  199. package/dist/utils/messages.js +5 -7
  200. package/dist/utils/messages.js.map +1 -1
  201. package/dist/utils/payload-config-ast.d.ts +22 -3
  202. package/dist/utils/payload-config-ast.d.ts.map +1 -1
  203. package/dist/utils/payload-config-ast.js +89 -31
  204. package/dist/utils/payload-config-ast.js.map +1 -1
  205. package/dist/utils/payload-config-finder.d.ts +2 -2
  206. package/dist/utils/payload-config-finder.d.ts.map +1 -1
  207. package/dist/utils/payload-config-finder.js +48 -9
  208. package/dist/utils/payload-config-finder.js.map +1 -1
  209. package/dist/utils/payload-config-modifier.d.ts.map +1 -1
  210. package/dist/utils/payload-config-modifier.js +33 -4
  211. package/dist/utils/payload-config-modifier.js.map +1 -1
  212. package/dist/utils/payload-package-check.d.ts +5 -0
  213. package/dist/utils/payload-package-check.d.ts.map +1 -1
  214. package/dist/utils/payload-package-check.js +48 -4
  215. package/dist/utils/payload-package-check.js.map +1 -1
  216. package/dist/utils/project.d.ts.map +1 -1
  217. package/dist/utils/project.js +8 -6
  218. package/dist/utils/project.js.map +1 -1
  219. package/dist/utils/s3-upload.d.ts +0 -1
  220. package/dist/utils/s3-upload.d.ts.map +1 -1
  221. package/dist/utils/s3-upload.js +10 -3
  222. package/dist/utils/s3-upload.js.map +1 -1
  223. package/dist/utils/token-display.d.ts.map +1 -1
  224. package/dist/utils/token-display.js +11 -5
  225. package/dist/utils/token-display.js.map +1 -1
  226. package/dist/utils/typescript-validator.d.ts.map +1 -1
  227. package/dist/utils/typescript-validator.js +1 -6
  228. package/dist/utils/typescript-validator.js.map +1 -1
  229. package/package.json +24 -7
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handleDelete.d.ts","sourceRoot":"","sources":["../../src/storage-content-api/handleDelete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAA;AAI1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,aAAa,CAAA;CACtB,CAAA;AAED,eAAO,MAAM,eAAe,eAAgB,IAAI,KAAG,YAOlD,CAAA"}
@@ -0,0 +1,15 @@
1
+ import path from 'path';
2
+ export const getHandleDelete = ({ client })=>{
3
+ return async ({ doc: { prefix = '' }, filename })=>{
4
+ const fileKey = path.posix.join(prefix, filename);
5
+ await client.DELETE('/api/v0/uploads/{filename}', {
6
+ params: {
7
+ path: {
8
+ filename: fileKey
9
+ }
10
+ }
11
+ });
12
+ };
13
+ };
14
+
15
+ //# sourceMappingURL=handleDelete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/storage-content-api/handleDelete.ts"],"sourcesContent":["import type { HandleDelete } from '@payloadcms/plugin-cloud-storage/types'\n\nimport path from 'path'\n\nimport type { StorageClient } from './client.js'\n\ntype Args = {\n client: StorageClient\n}\n\nexport const getHandleDelete = ({ client }: Args): HandleDelete => {\n return async ({ doc: { prefix = '' }, filename }) => {\n const fileKey = path.posix.join(prefix, filename)\n await client.DELETE('/api/v0/uploads/{filename}', {\n params: { path: { filename: fileKey } },\n })\n }\n}\n"],"names":["path","getHandleDelete","client","doc","prefix","filename","fileKey","posix","join","DELETE","params"],"mappings":"AAEA,OAAOA,UAAU,OAAM;AAQvB,OAAO,MAAMC,kBAAkB,CAAC,EAAEC,MAAM,EAAQ;IAC9C,OAAO,OAAO,EAAEC,KAAK,EAAEC,SAAS,EAAE,EAAE,EAAEC,QAAQ,EAAE;QAC9C,MAAMC,UAAUN,KAAKO,KAAK,CAACC,IAAI,CAACJ,QAAQC;QACxC,MAAMH,OAAOO,MAAM,CAAC,8BAA8B;YAChDC,QAAQ;gBAAEV,MAAM;oBAAEK,UAAUC;gBAAQ;YAAE;QACxC;IACF;AACF,EAAC"}
@@ -0,0 +1,11 @@
1
+ import type { HandleUpload } from '@payloadcms/plugin-cloud-storage/types';
2
+ import type { CollectionConfig } from 'payload';
3
+ import type { StorageClient } from './client.js';
4
+ type Args = {
5
+ client: StorageClient;
6
+ collection: CollectionConfig;
7
+ prefix?: string;
8
+ };
9
+ export declare const getHandleUpload: ({ client, prefix }: Args) => HandleUpload;
10
+ export {};
11
+ //# sourceMappingURL=handleUpload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handleUpload.d.ts","sourceRoot":"","sources":["../../src/storage-content-api/handleUpload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAA;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAK/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,aAAa,CAAA;IACrB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAKD,eAAO,MAAM,eAAe,uBAA6B,IAAI,KAAG,YAmC/D,CAAA"}
@@ -0,0 +1,136 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ const PART_SIZE = 64 * 1024 * 1024 // 64MB per part
4
+ ;
5
+ const MAX_FILE_SIZE_BEFORE_MULTIPART = 100 * 1024 * 1024 // 100MB
6
+ ;
7
+ export const getHandleUpload = ({ client, prefix = '' })=>{
8
+ return async ({ clientUploadContext, data, file })=>{
9
+ // Skip if client already uploaded THIS SPECIFIC file
10
+ // clientUploadContext.filename contains the original filename that was client-uploaded
11
+ // Resized versions (different filename) should still be uploaded
12
+ const clientUploadedFilename = clientUploadContext && typeof clientUploadContext === 'object' && 'filename' in clientUploadContext ? clientUploadContext.filename : undefined;
13
+ const isOriginalClientUploaded = clientUploadContext && typeof clientUploadContext === 'object' && 'clientUploaded' in clientUploadContext && clientUploadContext.clientUploaded && file.filename === clientUploadedFilename;
14
+ if (isOriginalClientUploaded) {
15
+ return data;
16
+ }
17
+ const fileKey = path.posix.join(data.prefix || prefix, file.filename);
18
+ const fileData = file.tempFilePath ? fs.readFileSync(file.tempFilePath) : file.buffer;
19
+ const fileSize = file.filesize || fileData.length;
20
+ if (fileSize > MAX_FILE_SIZE_BEFORE_MULTIPART) {
21
+ await uploadMultipart({
22
+ client,
23
+ fileData,
24
+ fileKey,
25
+ mimeType: file.mimeType
26
+ });
27
+ } else {
28
+ await uploadSingleFile({
29
+ client,
30
+ fileData,
31
+ fileKey,
32
+ mimeType: file.mimeType
33
+ });
34
+ }
35
+ return data;
36
+ };
37
+ };
38
+ async function uploadSingleFile({ client, fileData, fileKey, mimeType }) {
39
+ const { data, error } = await client.POST('/api/v0/uploads/sign', {
40
+ body: {
41
+ contentType: mimeType,
42
+ expiresIn: 3600,
43
+ filename: fileKey
44
+ }
45
+ });
46
+ if (error || !data) {
47
+ throw new Error(`Failed to get presigned upload URL: ${JSON.stringify(error)}`);
48
+ }
49
+ const uploadResponse = await fetch(data.url, {
50
+ body: fileData,
51
+ headers: {
52
+ 'Content-Type': mimeType
53
+ },
54
+ method: 'PUT'
55
+ });
56
+ if (!uploadResponse.ok) {
57
+ throw new Error(`Failed to upload to S3: ${uploadResponse.status} ${uploadResponse.statusText}`);
58
+ }
59
+ }
60
+ async function uploadMultipart({ client, fileData, fileKey, mimeType }) {
61
+ const { data: initiateData, error: initiateError } = await client.POST('/api/v0/uploads/multipart/initiate', {
62
+ body: {
63
+ contentType: mimeType,
64
+ filename: fileKey
65
+ }
66
+ });
67
+ if (initiateError || !initiateData) {
68
+ throw new Error(`Failed to initiate multipart upload: ${JSON.stringify(initiateError)}`);
69
+ }
70
+ const { uploadId } = initiateData;
71
+ try {
72
+ const numParts = Math.ceil(fileData.length / PART_SIZE);
73
+ const partNumbers = Array.from({
74
+ length: numParts
75
+ }, (_, i)=>i + 1);
76
+ const { data: partsData, error: partsError } = await client.POST('/api/v0/uploads/multipart/parts', {
77
+ body: {
78
+ expiresIn: 3600,
79
+ filename: fileKey,
80
+ partNumbers,
81
+ uploadId
82
+ }
83
+ });
84
+ if (partsError || !partsData) {
85
+ throw new Error(`Failed to get part URLs: ${JSON.stringify(partsError)}`);
86
+ }
87
+ const { parts } = partsData;
88
+ if (!parts || !Array.isArray(parts)) {
89
+ throw new Error('Invalid response from part URLs endpoint: parts is not an array');
90
+ }
91
+ const uploadedParts = await Promise.all(parts.map(async ({ partNumber, url })=>{
92
+ const start = (partNumber - 1) * PART_SIZE;
93
+ const end = Math.min(start + PART_SIZE, fileData.length);
94
+ const partData = fileData.slice(start, end);
95
+ const uploadResponse = await fetch(url, {
96
+ body: partData,
97
+ headers: {
98
+ 'Content-Type': mimeType
99
+ },
100
+ method: 'PUT'
101
+ });
102
+ const etag = uploadResponse.headers.get('ETag');
103
+ if (!etag) {
104
+ throw new Error(`No ETag returned for part ${partNumber}`);
105
+ }
106
+ return {
107
+ ETag: etag,
108
+ PartNumber: partNumber
109
+ };
110
+ }));
111
+ const { error: completeError } = await client.POST('/api/v0/uploads/multipart/complete', {
112
+ body: {
113
+ filename: fileKey,
114
+ parts: uploadedParts,
115
+ uploadId
116
+ }
117
+ });
118
+ if (completeError) {
119
+ throw new Error(`Failed to complete multipart upload: ${JSON.stringify(completeError)}`);
120
+ }
121
+ } catch (error) {
122
+ try {
123
+ await client.POST('/api/v0/uploads/multipart/abort', {
124
+ body: {
125
+ filename: fileKey,
126
+ uploadId
127
+ }
128
+ });
129
+ } catch {
130
+ // Ignore abort errors
131
+ }
132
+ throw error;
133
+ }
134
+ }
135
+
136
+ //# sourceMappingURL=handleUpload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/storage-content-api/handleUpload.ts"],"sourcesContent":["import type { HandleUpload } from '@payloadcms/plugin-cloud-storage/types'\nimport type { CollectionConfig } from 'payload'\n\nimport fs from 'fs'\nimport path from 'path'\n\nimport type { StorageClient } from './client.js'\n\ntype Args = {\n client: StorageClient\n collection: CollectionConfig\n prefix?: string\n}\n\nconst PART_SIZE = 64 * 1024 * 1024 // 64MB per part\nconst MAX_FILE_SIZE_BEFORE_MULTIPART = 100 * 1024 * 1024 // 100MB\n\nexport const getHandleUpload = ({ client, prefix = '' }: Args): HandleUpload => {\n return async ({ clientUploadContext, data, file }) => {\n // Skip if client already uploaded THIS SPECIFIC file\n // clientUploadContext.filename contains the original filename that was client-uploaded\n // Resized versions (different filename) should still be uploaded\n const clientUploadedFilename =\n clientUploadContext &&\n typeof clientUploadContext === 'object' &&\n 'filename' in clientUploadContext\n ? clientUploadContext.filename\n : undefined\n\n const isOriginalClientUploaded =\n clientUploadContext &&\n typeof clientUploadContext === 'object' &&\n 'clientUploaded' in clientUploadContext &&\n clientUploadContext.clientUploaded &&\n file.filename === clientUploadedFilename\n\n if (isOriginalClientUploaded) {\n return data\n }\n\n const fileKey = path.posix.join(data.prefix || prefix, file.filename)\n const fileData = file.tempFilePath ? fs.readFileSync(file.tempFilePath) : file.buffer\n const fileSize = file.filesize || fileData.length\n\n if (fileSize > MAX_FILE_SIZE_BEFORE_MULTIPART) {\n await uploadMultipart({ client, fileData, fileKey, mimeType: file.mimeType })\n } else {\n await uploadSingleFile({ client, fileData, fileKey, mimeType: file.mimeType })\n }\n\n return data\n }\n}\n\nasync function uploadSingleFile({\n client,\n fileData,\n fileKey,\n mimeType,\n}: {\n client: StorageClient\n fileData: Buffer\n fileKey: string\n mimeType: string\n}): Promise<void> {\n const { data, error } = await client.POST('/api/v0/uploads/sign', {\n body: { contentType: mimeType, expiresIn: 3600, filename: fileKey },\n })\n\n if (error || !data) {\n throw new Error(`Failed to get presigned upload URL: ${JSON.stringify(error)}`)\n }\n\n const uploadResponse = await fetch(data.url, {\n body: fileData,\n headers: { 'Content-Type': mimeType },\n method: 'PUT',\n })\n\n if (!uploadResponse.ok) {\n throw new Error(`Failed to upload to S3: ${uploadResponse.status} ${uploadResponse.statusText}`)\n }\n}\n\nasync function uploadMultipart({\n client,\n fileData,\n fileKey,\n mimeType,\n}: {\n client: StorageClient\n fileData: Buffer\n fileKey: string\n mimeType: string\n}): Promise<void> {\n const { data: initiateData, error: initiateError } = await client.POST(\n '/api/v0/uploads/multipart/initiate',\n {\n body: { contentType: mimeType, filename: fileKey },\n },\n )\n\n if (initiateError || !initiateData) {\n throw new Error(`Failed to initiate multipart upload: ${JSON.stringify(initiateError)}`)\n }\n\n const { uploadId } = initiateData\n\n try {\n const numParts = Math.ceil(fileData.length / PART_SIZE)\n const partNumbers = Array.from({ length: numParts }, (_, i) => i + 1)\n\n const { data: partsData, error: partsError } = await client.POST(\n '/api/v0/uploads/multipart/parts',\n {\n body: { expiresIn: 3600, filename: fileKey, partNumbers, uploadId },\n },\n )\n\n if (partsError || !partsData) {\n throw new Error(`Failed to get part URLs: ${JSON.stringify(partsError)}`)\n }\n\n const { parts } = partsData\n\n if (!parts || !Array.isArray(parts)) {\n throw new Error('Invalid response from part URLs endpoint: parts is not an array')\n }\n\n const uploadedParts = await Promise.all(\n parts.map(async ({ partNumber, url }) => {\n const start = (partNumber - 1) * PART_SIZE\n const end = Math.min(start + PART_SIZE, fileData.length)\n const partData = fileData.slice(start, end)\n\n const uploadResponse = await fetch(url, {\n body: partData,\n headers: { 'Content-Type': mimeType },\n method: 'PUT',\n })\n\n const etag = uploadResponse.headers.get('ETag')\n if (!etag) {\n throw new Error(`No ETag returned for part ${partNumber}`)\n }\n\n return { ETag: etag, PartNumber: partNumber }\n }),\n )\n\n const { error: completeError } = await client.POST('/api/v0/uploads/multipart/complete', {\n body: { filename: fileKey, parts: uploadedParts, uploadId },\n })\n\n if (completeError) {\n throw new Error(`Failed to complete multipart upload: ${JSON.stringify(completeError)}`)\n }\n } catch (error) {\n try {\n await client.POST('/api/v0/uploads/multipart/abort', {\n body: { filename: fileKey, uploadId },\n })\n } catch {\n // Ignore abort errors\n }\n throw error\n }\n}\n"],"names":["fs","path","PART_SIZE","MAX_FILE_SIZE_BEFORE_MULTIPART","getHandleUpload","client","prefix","clientUploadContext","data","file","clientUploadedFilename","filename","undefined","isOriginalClientUploaded","clientUploaded","fileKey","posix","join","fileData","tempFilePath","readFileSync","buffer","fileSize","filesize","length","uploadMultipart","mimeType","uploadSingleFile","error","POST","body","contentType","expiresIn","Error","JSON","stringify","uploadResponse","fetch","url","headers","method","ok","status","statusText","initiateData","initiateError","uploadId","numParts","Math","ceil","partNumbers","Array","from","_","i","partsData","partsError","parts","isArray","uploadedParts","Promise","all","map","partNumber","start","end","min","partData","slice","etag","get","ETag","PartNumber","completeError"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Adapter } from '@payloadcms/plugin-cloud-storage/types';
2
+ import type { StorageClientConfig } from './types.js';
3
+ export type { StorageClientConfig } from './types.js';
4
+ export declare function contentApiStorageAdapter(config: StorageClientConfig): Adapter;
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage-content-api/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAoB,MAAM,wCAAwC,CAAA;AAEvF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAQrD,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAErD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAa7E"}
@@ -0,0 +1,31 @@
1
+ import { createStorageClient } from './client.js';
2
+ import { getGenerateURL } from './generateURL.js';
3
+ import { getHandleDelete } from './handleDelete.js';
4
+ import { getHandleUpload } from './handleUpload.js';
5
+ import { getHandler } from './staticHandler.js';
6
+ export function contentApiStorageAdapter(config) {
7
+ return ({ collection, prefix })=>{
8
+ const client = createStorageClient(config);
9
+ const baseUrl = config.baseUrl;
10
+ return {
11
+ name: 'content-api',
12
+ generateURL: getGenerateURL({
13
+ baseUrl
14
+ }),
15
+ handleDelete: getHandleDelete({
16
+ client
17
+ }),
18
+ handleUpload: getHandleUpload({
19
+ client,
20
+ collection,
21
+ prefix
22
+ }),
23
+ staticHandler: getHandler({
24
+ client,
25
+ collection
26
+ })
27
+ };
28
+ };
29
+ }
30
+
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/storage-content-api/index.ts"],"sourcesContent":["import type { Adapter, GeneratedAdapter } from '@payloadcms/plugin-cloud-storage/types'\n\nimport type { StorageClientConfig } from './types.js'\n\nimport { createStorageClient } from './client.js'\nimport { getGenerateURL } from './generateURL.js'\nimport { getHandleDelete } from './handleDelete.js'\nimport { getHandleUpload } from './handleUpload.js'\nimport { getHandler } from './staticHandler.js'\n\nexport type { StorageClientConfig } from './types.js'\n\nexport function contentApiStorageAdapter(config: StorageClientConfig): Adapter {\n return ({ collection, prefix }): GeneratedAdapter => {\n const client = createStorageClient(config)\n const baseUrl = config.baseUrl\n\n return {\n name: 'content-api',\n generateURL: getGenerateURL({ baseUrl }),\n handleDelete: getHandleDelete({ client }),\n handleUpload: getHandleUpload({ client, collection, prefix }),\n staticHandler: getHandler({ client, collection }),\n }\n }\n}\n"],"names":["createStorageClient","getGenerateURL","getHandleDelete","getHandleUpload","getHandler","contentApiStorageAdapter","config","collection","prefix","client","baseUrl","name","generateURL","handleDelete","handleUpload","staticHandler"],"mappings":"AAIA,SAASA,mBAAmB,QAAQ,cAAa;AACjD,SAASC,cAAc,QAAQ,mBAAkB;AACjD,SAASC,eAAe,QAAQ,oBAAmB;AACnD,SAASC,eAAe,QAAQ,oBAAmB;AACnD,SAASC,UAAU,QAAQ,qBAAoB;AAI/C,OAAO,SAASC,yBAAyBC,MAA2B;IAClE,OAAO,CAAC,EAAEC,UAAU,EAAEC,MAAM,EAAE;QAC5B,MAAMC,SAAST,oBAAoBM;QACnC,MAAMI,UAAUJ,OAAOI,OAAO;QAE9B,OAAO;YACLC,MAAM;YACNC,aAAaX,eAAe;gBAAES;YAAQ;YACtCG,cAAcX,gBAAgB;gBAAEO;YAAO;YACvCK,cAAcX,gBAAgB;gBAAEM;gBAAQF;gBAAYC;YAAO;YAC3DO,eAAeX,WAAW;gBAAEK;gBAAQF;YAAW;QACjD;IACF;AACF"}
@@ -0,0 +1,10 @@
1
+ import type { StaticHandler } from '@payloadcms/plugin-cloud-storage/types';
2
+ import type { CollectionConfig } from 'payload';
3
+ import type { StorageClient } from './client.js';
4
+ type Args = {
5
+ client: StorageClient;
6
+ collection: CollectionConfig;
7
+ };
8
+ export declare const getHandler: ({ client, collection }: Args) => StaticHandler;
9
+ export {};
10
+ //# sourceMappingURL=staticHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staticHandler.d.ts","sourceRoot":"","sources":["../../src/storage-content-api/staticHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAK/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,aAAa,CAAA;IACrB,UAAU,EAAE,gBAAgB,CAAA;CAC7B,CAAA;AAED,eAAO,MAAM,UAAU,2BAA4B,IAAI,KAAG,aAuCzD,CAAA"}
@@ -0,0 +1,55 @@
1
+ import { getFilePrefix } from '@payloadcms/plugin-cloud-storage/utilities';
2
+ import path from 'path';
3
+ export const getHandler = ({ client, collection })=>{
4
+ return async (req, { params: { clientUploadContext, filename } })=>{
5
+ try {
6
+ const prefix = await getFilePrefix({
7
+ clientUploadContext,
8
+ collection,
9
+ filename,
10
+ req
11
+ });
12
+ const key = path.posix.join(prefix, filename);
13
+ const { data, error } = await client.POST('/api/v0/uploads/download/sign', {
14
+ body: {
15
+ expiresIn: 7200,
16
+ filename: key
17
+ }
18
+ });
19
+ if (error || !data) {
20
+ req.payload.logger.error(`Failed to get signed download URL: ${JSON.stringify(error)}`);
21
+ return new Response('Internal Server Error', {
22
+ status: 500
23
+ });
24
+ }
25
+ // Fetch file bytes from S3 (required for Payload's image processing)
26
+ const fileResponse = await fetch(data.url);
27
+ if (!fileResponse.ok) {
28
+ req.payload.logger.error(`S3 fetch failed: ${fileResponse.status} ${fileResponse.statusText}`);
29
+ return new Response('Failed to fetch file from storage', {
30
+ status: 502
31
+ });
32
+ }
33
+ const contentType = fileResponse.headers.get('content-type') || 'application/octet-stream';
34
+ const contentLength = fileResponse.headers.get('content-length');
35
+ return new Response(fileResponse.body, {
36
+ headers: {
37
+ 'Content-Type': contentType,
38
+ ...contentLength && {
39
+ 'Content-Length': contentLength
40
+ }
41
+ }
42
+ });
43
+ } catch (err) {
44
+ req.payload.logger.error({
45
+ err,
46
+ msg: 'Error in staticHandler'
47
+ });
48
+ return new Response('Internal Server Error', {
49
+ status: 500
50
+ });
51
+ }
52
+ };
53
+ };
54
+
55
+ //# sourceMappingURL=staticHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/storage-content-api/staticHandler.ts"],"sourcesContent":["import type { StaticHandler } from '@payloadcms/plugin-cloud-storage/types'\nimport type { CollectionConfig } from 'payload'\n\nimport { getFilePrefix } from '@payloadcms/plugin-cloud-storage/utilities'\nimport path from 'path'\n\nimport type { StorageClient } from './client.js'\n\ntype Args = {\n client: StorageClient\n collection: CollectionConfig\n}\n\nexport const getHandler = ({ client, collection }: Args): StaticHandler => {\n return async (req, { params: { clientUploadContext, filename } }) => {\n try {\n const prefix = await getFilePrefix({ clientUploadContext, collection, filename, req })\n const key = path.posix.join(prefix, filename)\n\n const { data, error } = await client.POST('/api/v0/uploads/download/sign', {\n body: { expiresIn: 7200, filename: key },\n })\n\n if (error || !data) {\n req.payload.logger.error(`Failed to get signed download URL: ${JSON.stringify(error)}`)\n return new Response('Internal Server Error', { status: 500 })\n }\n\n // Fetch file bytes from S3 (required for Payload's image processing)\n const fileResponse = await fetch(data.url)\n\n if (!fileResponse.ok) {\n req.payload.logger.error(\n `S3 fetch failed: ${fileResponse.status} ${fileResponse.statusText}`,\n )\n return new Response('Failed to fetch file from storage', { status: 502 })\n }\n\n const contentType = fileResponse.headers.get('content-type') || 'application/octet-stream'\n const contentLength = fileResponse.headers.get('content-length')\n\n return new Response(fileResponse.body, {\n headers: {\n 'Content-Type': contentType,\n ...(contentLength && { 'Content-Length': contentLength }),\n },\n })\n } catch (err) {\n req.payload.logger.error({ err, msg: 'Error in staticHandler' })\n return new Response('Internal Server Error', { status: 500 })\n }\n }\n}\n"],"names":["getFilePrefix","path","getHandler","client","collection","req","params","clientUploadContext","filename","prefix","key","posix","join","data","error","POST","body","expiresIn","payload","logger","JSON","stringify","Response","status","fileResponse","fetch","url","ok","statusText","contentType","headers","get","contentLength","err","msg"],"mappings":"AAGA,SAASA,aAAa,QAAQ,6CAA4C;AAC1E,OAAOC,UAAU,OAAM;AASvB,OAAO,MAAMC,aAAa,CAAC,EAAEC,MAAM,EAAEC,UAAU,EAAQ;IACrD,OAAO,OAAOC,KAAK,EAAEC,QAAQ,EAAEC,mBAAmB,EAAEC,QAAQ,EAAE,EAAE;QAC9D,IAAI;YACF,MAAMC,SAAS,MAAMT,cAAc;gBAAEO;gBAAqBH;gBAAYI;gBAAUH;YAAI;YACpF,MAAMK,MAAMT,KAAKU,KAAK,CAACC,IAAI,CAACH,QAAQD;YAEpC,MAAM,EAAEK,IAAI,EAAEC,KAAK,EAAE,GAAG,MAAMX,OAAOY,IAAI,CAAC,iCAAiC;gBACzEC,MAAM;oBAAEC,WAAW;oBAAMT,UAAUE;gBAAI;YACzC;YAEA,IAAII,SAAS,CAACD,MAAM;gBAClBR,IAAIa,OAAO,CAACC,MAAM,CAACL,KAAK,CAAC,CAAC,mCAAmC,EAAEM,KAAKC,SAAS,CAACP,QAAQ;gBACtF,OAAO,IAAIQ,SAAS,yBAAyB;oBAAEC,QAAQ;gBAAI;YAC7D;YAEA,qEAAqE;YACrE,MAAMC,eAAe,MAAMC,MAAMZ,KAAKa,GAAG;YAEzC,IAAI,CAACF,aAAaG,EAAE,EAAE;gBACpBtB,IAAIa,OAAO,CAACC,MAAM,CAACL,KAAK,CACtB,CAAC,iBAAiB,EAAEU,aAAaD,MAAM,CAAC,CAAC,EAAEC,aAAaI,UAAU,EAAE;gBAEtE,OAAO,IAAIN,SAAS,qCAAqC;oBAAEC,QAAQ;gBAAI;YACzE;YAEA,MAAMM,cAAcL,aAAaM,OAAO,CAACC,GAAG,CAAC,mBAAmB;YAChE,MAAMC,gBAAgBR,aAAaM,OAAO,CAACC,GAAG,CAAC;YAE/C,OAAO,IAAIT,SAASE,aAAaR,IAAI,EAAE;gBACrCc,SAAS;oBACP,gBAAgBD;oBAChB,GAAIG,iBAAiB;wBAAE,kBAAkBA;oBAAc,CAAC;gBAC1D;YACF;QACF,EAAE,OAAOC,KAAK;YACZ5B,IAAIa,OAAO,CAACC,MAAM,CAACL,KAAK,CAAC;gBAAEmB;gBAAKC,KAAK;YAAyB;YAC9D,OAAO,IAAIZ,SAAS,yBAAyB;gBAAEC,QAAQ;YAAI;QAC7D;IACF;AACF,EAAC"}
@@ -0,0 +1,10 @@
1
+ import type { AuthMode } from '../db-content-api/utilities/auth.js';
2
+ export type StorageClientConfig = {
3
+ auth: AuthMode;
4
+ baseUrl: string;
5
+ contentSystemId: string;
6
+ } | {
7
+ baseUrl: string;
8
+ contentApiKey: string;
9
+ };
10
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/storage-content-api/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAA;AAEnE,MAAM,MAAM,mBAAmB,GAC3B;IACE,IAAI,EAAE,QAAQ,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,EAAE,MAAM,CAAA;CACxB,GACD;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/storage-content-api/types.ts"],"sourcesContent":["import type { AuthMode } from '../db-content-api/utilities/auth.js'\n\nexport type StorageClientConfig =\n | {\n auth: AuthMode\n baseUrl: string\n contentSystemId: string\n }\n | { baseUrl: string; contentApiKey: string }\n"],"names":[],"mappings":"AAEA,WAM8C"}
@@ -0,0 +1,19 @@
1
+ # {{PROJECT_NAME}}
2
+
3
+ A Payload project configured for running on Figma infrastructure.
4
+
5
+ ## Getting Started
6
+
7
+ pnpm dev
8
+
9
+ Open http://localhost:3000/admin to access the admin panel.
10
+
11
+ ## Deployment
12
+
13
+ npx @payloadcms/figma deploy
14
+
15
+ Deploys to Figma infrastructure.
16
+
17
+ ## Resources
18
+
19
+ - [Payload Docs](https://payloadcms.com/docs)
@@ -1,16 +1,17 @@
1
1
  /**
2
- * Generate a cryptographically secure secret for PAYLOAD_SECRET
2
+ * Get an environment variable value from .env file
3
3
  *
4
- * @returns 24-character hexadecimal string
4
+ * @param projectPath - Path to project directory
5
+ * @param key - Environment variable name to retrieve
6
+ * @returns The value if found, null otherwise
5
7
  */
6
- export declare function generateSecret(): string;
8
+ export declare function getEnvVar(projectPath: string, key: string): Promise<null | string>;
7
9
  /**
8
- * Manage environment files for a new project
9
- *
10
- * Creates .env from .env.example (if exists) and populates PAYLOAD_SECRET
10
+ * Add or update an environment variable in .env file
11
11
  *
12
12
  * @param projectPath - Path to project directory
13
- * @returns The generated payload secret
13
+ * @param key - Environment variable name
14
+ * @param value - Environment variable value
14
15
  */
15
- export declare function manageEnvFiles(projectPath: string): Promise<string>;
16
+ export declare function addOrUpdateEnvVar(projectPath: string, key: string, value: string): Promise<void>;
16
17
  //# sourceMappingURL=env-management.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"env-management.d.ts","sourceRoot":"","sources":["../../src/utils/env-management.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAoDD;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA8CzE"}
1
+ {"version":3,"file":"env-management.d.ts","sourceRoot":"","sources":["../../src/utils/env-management.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,wBAAsB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CA+BxF;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAmEf"}
@@ -1,97 +1,96 @@
1
- import { randomBytes } from 'crypto';
2
1
  import fs from 'fs/promises';
3
2
  import path from 'path';
4
3
  /**
5
- * Generate a cryptographically secure secret for PAYLOAD_SECRET
4
+ * Get an environment variable value from .env file
6
5
  *
7
- * @returns 24-character hexadecimal string
8
- */ export function generateSecret() {
9
- return randomBytes(32).toString('hex').slice(0, 24);
10
- }
11
- /**
12
- * Sanitize and process environment file contents
13
- *
14
- * @param contents - Raw .env file contents
15
- * @param payloadSecret - Secret to use for PAYLOAD_SECRET
16
- * @returns Processed .env contents
17
- */ function sanitizeEnv(contents, payloadSecret) {
18
- const lines = contents.split('\n');
19
- const seenKeys = new Set();
20
- const processedLines = [];
21
- for (const line of lines){
22
- // Skip empty lines and comments
23
- if (!line.trim() || line.trim().startsWith('#')) {
24
- processedLines.push(line);
25
- continue;
26
- }
27
- // Skip lines without =
28
- if (!line.includes('=')) {
29
- processedLines.push(line);
30
- continue;
31
- }
32
- const [key] = line.split('=');
33
- const trimmedKey = key.trim();
34
- // Skip duplicate keys
35
- if (seenKeys.has(trimmedKey)) {
36
- continue;
37
- }
38
- seenKeys.add(trimmedKey);
39
- // Replace PAYLOAD_SECRET with actual value
40
- if (trimmedKey === 'PAYLOAD_SECRET' || trimmedKey === 'PAYLOAD_SECRET_KEY') {
41
- processedLines.push(`PAYLOAD_SECRET=${payloadSecret}`);
42
- } else {
43
- processedLines.push(line);
6
+ * @param projectPath - Path to project directory
7
+ * @param key - Environment variable name to retrieve
8
+ * @returns The value if found, null otherwise
9
+ */ export async function getEnvVar(projectPath, key) {
10
+ const envPath = path.join(projectPath, '.env');
11
+ try {
12
+ const contents = await fs.readFile(envPath, 'utf-8');
13
+ const lines = contents.split('\n');
14
+ for (const line of lines){
15
+ // Skip empty lines and comments
16
+ if (!line.trim() || line.trim().startsWith('#')) {
17
+ continue;
18
+ }
19
+ // Skip lines without =
20
+ if (!line.includes('=')) {
21
+ continue;
22
+ }
23
+ const equalsIndex = line.indexOf('=');
24
+ const lineKey = line.substring(0, equalsIndex).trim();
25
+ if (lineKey === key) {
26
+ return line.substring(equalsIndex + 1);
27
+ }
44
28
  }
29
+ return null;
30
+ } catch {
31
+ // File doesn't exist or can't be read
32
+ return null;
45
33
  }
46
- // Add PAYLOAD_SECRET if not present
47
- if (!seenKeys.has('PAYLOAD_SECRET') && !seenKeys.has('PAYLOAD_SECRET_KEY')) {
48
- processedLines.push(`PAYLOAD_SECRET=${payloadSecret}`);
49
- }
50
- return processedLines.join('\n');
51
34
  }
52
35
  /**
53
- * Manage environment files for a new project
54
- *
55
- * Creates .env from .env.example (if exists) and populates PAYLOAD_SECRET
36
+ * Add or update an environment variable in .env file
56
37
  *
57
38
  * @param projectPath - Path to project directory
58
- * @returns The generated payload secret
59
- */ export async function manageEnvFiles(projectPath) {
60
- const payloadSecret = generateSecret();
61
- const envExamplePath = path.join(projectPath, '.env.example');
39
+ * @param key - Environment variable name
40
+ * @param value - Environment variable value
41
+ */ export async function addOrUpdateEnvVar(projectPath, key, value) {
62
42
  const envPath = path.join(projectPath, '.env');
63
43
  try {
64
- // Check if .env.example exists
65
- let envExampleContents = '';
66
- try {
67
- envExampleContents = await fs.readFile(envExamplePath, 'utf-8');
68
- } catch {
69
- // No .env.example, create minimal .env
70
- envExampleContents = '';
71
- }
72
- // Check if .env already exists
44
+ let contents = '';
73
45
  let envExists = false;
46
+ // Try to read existing .env file
74
47
  try {
75
- await fs.access(envPath);
48
+ contents = await fs.readFile(envPath, 'utf-8');
76
49
  envExists = true;
77
50
  } catch {
78
- // .env doesn't exist
51
+ // .env doesn't exist, will create it
79
52
  }
80
- if (!envExists) {
81
- // Create .env from .env.example
82
- const sanitized = sanitizeEnv(envExampleContents, payloadSecret);
83
- await fs.writeFile(envPath, sanitized, 'utf-8');
84
- } else {
85
- // Update existing .env if it doesn't have PAYLOAD_SECRET
86
- const existingContents = await fs.readFile(envPath, 'utf-8');
87
- if (!existingContents.includes('PAYLOAD_SECRET=') && !existingContents.includes('PAYLOAD_SECRET_KEY=')) {
88
- const sanitized = sanitizeEnv(existingContents, payloadSecret);
89
- await fs.writeFile(envPath, sanitized, 'utf-8');
53
+ const lines = contents.split('\n');
54
+ const seenKeys = new Set();
55
+ const processedLines = [];
56
+ let keyUpdated = false;
57
+ for (const line of lines){
58
+ // Skip empty lines at start if file didn't exist
59
+ if (!envExists && !line.trim()) {
60
+ continue;
90
61
  }
62
+ // Preserve empty lines and comments
63
+ if (!line.trim() || line.trim().startsWith('#')) {
64
+ processedLines.push(line);
65
+ continue;
66
+ }
67
+ // Skip lines without =
68
+ if (!line.includes('=')) {
69
+ processedLines.push(line);
70
+ continue;
71
+ }
72
+ const [lineKey] = line.split('=');
73
+ const trimmedKey = lineKey.trim();
74
+ // Skip duplicate keys (keep first occurrence)
75
+ if (seenKeys.has(trimmedKey)) {
76
+ continue;
77
+ }
78
+ seenKeys.add(trimmedKey);
79
+ // Update or keep the line
80
+ if (trimmedKey === key) {
81
+ processedLines.push(`${key}=${value}`);
82
+ keyUpdated = true;
83
+ } else {
84
+ processedLines.push(line);
85
+ }
86
+ }
87
+ // Add key if not present
88
+ if (!keyUpdated) {
89
+ processedLines.push(`${key}=${value}`);
91
90
  }
92
- return payloadSecret;
91
+ await fs.writeFile(envPath, processedLines.join('\n'), 'utf-8');
93
92
  } catch (error) {
94
- throw new Error(`Failed to manage environment files: ${error instanceof Error ? error.message : 'Unknown error'}`);
93
+ throw new Error(`Failed to update .env file: ${error instanceof Error ? error.message : 'Unknown error'}`);
95
94
  }
96
95
  }
97
96