@payloadcms/figma 0.1.0-alpha.1 → 0.1.0-alpha.2

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.
@@ -18,6 +18,7 @@ import * as log from '../utils/log.js';
18
18
  import { logMissingCliAuth } from './auth-preflight.js';
19
19
  import { logMissingContentSystemId } from './bootstrap-preflight.js';
20
20
  import { getDevCookieNames } from './dev-cookie-names.js';
21
+ import { createSandboxUploadFetchPlugin } from './sandbox-upload-fetch.js';
21
22
  /**
22
23
  * Worker-trusted marker injected by Figma's sites-worker after it validates the
23
24
  * X-Figma-Job-Queues-Auth-Bypass secret on a Payload jobs endpoint. The default
@@ -392,7 +393,12 @@ export async function buildFigmaConfig(config) {
392
393
  debug: !!process.env.DEBUG,
393
394
  disabled: false
394
395
  }),
395
- scheduleExtractPlugin()
396
+ scheduleExtractPlugin(),
397
+ // Not folded into createStoragePlugin, which is skipped when
398
+ // figma.storage is false and would break remote uploads for those apps.
399
+ createSandboxUploadFetchPlugin({
400
+ userCollections: config.collections
401
+ })
396
402
  ]
397
403
  };
398
404
  // Inject figma fields into users collection
@@ -0,0 +1,32 @@
1
+ import type { Config } from 'payload';
2
+ /**
3
+ * True inside the Make sandbox. agentplat injects `FIGMA=1`, absent locally and
4
+ * in the deployed Lambda; `FIGMA=true` matches the app template's vite config.
5
+ *
6
+ * KEEP_IN_SYNC(services/agentplat/scriptrun/script_runner.go): EnvFigma
7
+ */
8
+ export declare function isMakeSandbox(): boolean;
9
+ type SandboxUploadFetchOptions = {
10
+ /**
11
+ * The app's collections before any plugin runs. `plugin-cloud-storage` later
12
+ * rewrites `skipSafeFetch`, erasing whether the app set `false` or nothing, so
13
+ * intent must be read here.
14
+ */
15
+ userCollections: Config['collections'];
16
+ };
17
+ /**
18
+ * Defaults upload collections to skip `safeFetch` in the Make sandbox, where DNS
19
+ * maps external hostnames to unique-local IPv6 addresses (`fc00::/7`) that
20
+ * `safeFetch` rejects as non-unicast. A no-op elsewhere.
21
+ *
22
+ * Only a default: a collection that set `skipSafeFetch` itself keeps its value.
23
+ * `externalFileHeaderFilter` is left unset on purpose, since it would replace
24
+ * the cookie logic that forwards credentials for relative URLs.
25
+ *
26
+ * SSRF risks, bounded by the routes' auth gate and sandbox network limits:
27
+ * `getExternalFile` re-validates redirects only against `pasteURL.allowList`,
28
+ * any session can GET an arbitrary URL and read the body, and request cookies
29
+ * reach the target.
30
+ */
31
+ export declare function createSandboxUploadFetchPlugin({ userCollections }: SandboxUploadFetchOptions): (config: Config) => Config;
32
+ export {};
@@ -0,0 +1,53 @@
1
+ import * as log from '../utils/log.js';
2
+ /**
3
+ * True inside the Make sandbox. agentplat injects `FIGMA=1`, absent locally and
4
+ * in the deployed Lambda; `FIGMA=true` matches the app template's vite config.
5
+ *
6
+ * KEEP_IN_SYNC(services/agentplat/scriptrun/script_runner.go): EnvFigma
7
+ */ export function isMakeSandbox() {
8
+ return process.env.FIGMA === '1' || process.env.FIGMA === 'true';
9
+ }
10
+ /**
11
+ * Defaults upload collections to skip `safeFetch` in the Make sandbox, where DNS
12
+ * maps external hostnames to unique-local IPv6 addresses (`fc00::/7`) that
13
+ * `safeFetch` rejects as non-unicast. A no-op elsewhere.
14
+ *
15
+ * Only a default: a collection that set `skipSafeFetch` itself keeps its value.
16
+ * `externalFileHeaderFilter` is left unset on purpose, since it would replace
17
+ * the cookie logic that forwards credentials for relative URLs.
18
+ *
19
+ * SSRF risks, bounded by the routes' auth gate and sandbox network limits:
20
+ * `getExternalFile` re-validates redirects only against `pasteURL.allowList`,
21
+ * any session can GET an arbitrary URL and read the body, and request cookies
22
+ * reach the target.
23
+ */ export function createSandboxUploadFetchPlugin({ userCollections }) {
24
+ const appOwnedSlugs = new Set((userCollections ?? []).filter((collection)=>typeof collection.upload === 'object' && 'skipSafeFetch' in collection.upload).map((collection)=>collection.slug));
25
+ return (config)=>{
26
+ if (!isMakeSandbox()) {
27
+ return config;
28
+ }
29
+ const modifiedSlugs = [];
30
+ const collections = (config.collections ?? []).map((collection)=>{
31
+ if (!collection.upload || appOwnedSlugs.has(collection.slug)) {
32
+ return collection;
33
+ }
34
+ modifiedSlugs.push(collection.slug);
35
+ const upload = collection.upload === true ? {} : collection.upload;
36
+ return {
37
+ ...collection,
38
+ upload: {
39
+ ...upload,
40
+ skipSafeFetch: true
41
+ }
42
+ };
43
+ });
44
+ if (modifiedSlugs.length === 0) {
45
+ return config;
46
+ }
47
+ log.debug(`Make sandbox detected: upload collections skip safeFetch (${modifiedSlugs.join(', ')})`);
48
+ return {
49
+ ...config,
50
+ collections
51
+ };
52
+ };
53
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/figma",
3
- "version": "0.1.0-alpha.1",
3
+ "version": "0.1.0-alpha.2",
4
4
  "license": "SEE LICENSE IN LICENSE.md",
5
5
  "type": "module",
6
6
  "exports": {
@@ -97,6 +97,7 @@
97
97
  "generate:types": "tsx scripts/generate-types.ts",
98
98
  "lint": "eslint .",
99
99
  "lint:fix": "eslint . --fix",
100
+ "payload:cli": "tsx scripts/payload-cli.ts",
100
101
  "start": "pnpm build && node ./bin/cli.js",
101
102
  "test": "TEST_UNIT=true vitest run",
102
103
  "test:int": "TEST_INT=true vitest run --config vitest.config.int.ts",