@se-studio/contentful-cms 3.9.4 → 3.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +3 -3
  3. package/dist/commands/asset.d.ts.map +1 -1
  4. package/dist/commands/asset.js +20 -5
  5. package/dist/commands/asset.js.map +1 -1
  6. package/dist/commands/host-scaffold.js +1 -1
  7. package/dist/commands/media.d.ts.map +1 -1
  8. package/dist/commands/media.js +10 -5
  9. package/dist/commands/media.js.map +1 -1
  10. package/dist/contentful/assets.d.ts +4 -0
  11. package/dist/contentful/assets.d.ts.map +1 -1
  12. package/dist/contentful/assets.js +9 -0
  13. package/dist/contentful/assets.js.map +1 -1
  14. package/dist/contentful/cma-user-agent.d.ts +1 -1
  15. package/dist/contentful/cma-user-agent.d.ts.map +1 -1
  16. package/dist/contentful/hosted-asset-upload.d.ts +1 -1
  17. package/dist/contentful/hosted-asset-upload.d.ts.map +1 -1
  18. package/dist/contentful/hosted-asset-upload.js +1 -1
  19. package/dist/contentful/hosted-asset-upload.js.map +1 -1
  20. package/dist/contentful/pipeline-encode-gate.d.ts +27 -0
  21. package/dist/contentful/pipeline-encode-gate.d.ts.map +1 -0
  22. package/dist/contentful/pipeline-encode-gate.js +102 -0
  23. package/dist/contentful/pipeline-encode-gate.js.map +1 -0
  24. package/dist/editor-pack/generate.js +1 -1
  25. package/dist/editor-pack/generate.js.map +1 -1
  26. package/dist/generated/hosted-guide.d.ts +1 -1
  27. package/dist/generated/hosted-guide.d.ts.map +1 -1
  28. package/dist/generated/hosted-guide.js +1 -1
  29. package/dist/generated/hosted-guide.js.map +1 -1
  30. package/dist/generated/version.d.ts +1 -1
  31. package/dist/generated/version.d.ts.map +1 -1
  32. package/dist/generated/version.js +1 -1
  33. package/dist/generated/version.js.map +1 -1
  34. package/dist/hosted/next/routes/staged-upload.d.ts +1 -0
  35. package/dist/hosted/next/routes/staged-upload.d.ts.map +1 -1
  36. package/dist/hosted/next/routes/staged-upload.js +38 -1
  37. package/dist/hosted/next/routes/staged-upload.js.map +1 -1
  38. package/dist/mcp/prompts/onboarding.d.ts.map +1 -1
  39. package/dist/mcp/prompts/onboarding.js +5 -5
  40. package/dist/mcp/prompts/onboarding.js.map +1 -1
  41. package/dist/mcp/tools/cms-edit.d.ts +1 -1
  42. package/dist/mcp/tools/cms-edit.d.ts.map +1 -1
  43. package/dist/mcp/tools/cms-edit.js +3 -2
  44. package/dist/mcp/tools/cms-edit.js.map +1 -1
  45. package/dist/mcp/tools/media.d.ts.map +1 -1
  46. package/dist/mcp/tools/media.js +18 -11
  47. package/dist/mcp/tools/media.js.map +1 -1
  48. package/dist/mcp/tools/staged-upload.d.ts.map +1 -1
  49. package/dist/mcp/tools/staged-upload.js +6 -4
  50. package/dist/mcp/tools/staged-upload.js.map +1 -1
  51. package/dist/media-pipeline/actions.d.ts +6 -8
  52. package/dist/media-pipeline/actions.d.ts.map +1 -1
  53. package/dist/media-pipeline/actions.js +10 -8
  54. package/dist/media-pipeline/actions.js.map +1 -1
  55. package/dist/media-pipeline/client.d.ts +11 -3
  56. package/dist/media-pipeline/client.d.ts.map +1 -1
  57. package/dist/media-pipeline/client.js +1 -4
  58. package/dist/media-pipeline/client.js.map +1 -1
  59. package/dist/media-pipeline/import-alt.d.ts +8 -0
  60. package/dist/media-pipeline/import-alt.d.ts.map +1 -0
  61. package/dist/media-pipeline/import-alt.js +23 -0
  62. package/dist/media-pipeline/import-alt.js.map +1 -0
  63. package/dist/media-pipeline/import.d.ts.map +1 -1
  64. package/dist/media-pipeline/import.js +45 -0
  65. package/dist/media-pipeline/import.js.map +1 -1
  66. package/dist/media-pipeline/limits.d.ts +2 -2
  67. package/dist/media-pipeline/limits.d.ts.map +1 -1
  68. package/dist/media-pipeline/limits.js +2 -2
  69. package/dist/media-pipeline/limits.js.map +1 -1
  70. package/dist/media-pipeline/prepare-source.d.ts +32 -0
  71. package/dist/media-pipeline/prepare-source.d.ts.map +1 -0
  72. package/dist/media-pipeline/prepare-source.js +132 -0
  73. package/dist/media-pipeline/prepare-source.js.map +1 -0
  74. package/dist/staged-upload/hmac.d.ts +4 -0
  75. package/dist/staged-upload/hmac.d.ts.map +1 -1
  76. package/dist/staged-upload/hmac.js +35 -0
  77. package/dist/staged-upload/hmac.js.map +1 -1
  78. package/dist/staged-upload/request.d.ts.map +1 -1
  79. package/dist/staged-upload/request.js +14 -11
  80. package/dist/staged-upload/request.js.map +1 -1
  81. package/dist/staged-upload/store.d.ts +2 -0
  82. package/dist/staged-upload/store.d.ts.map +1 -1
  83. package/dist/staged-upload/store.js +18 -0
  84. package/dist/staged-upload/store.js.map +1 -1
  85. package/docs/editor-tasks/media-pipeline-prepare.md +29 -18
  86. package/docs/editor-tasks/media-reuse-and-upload.md +23 -20
  87. package/docs/mcp/hosted-guide.md +9 -8
  88. package/package.json +1 -1
  89. package/skills/core/SKILL.md +4 -8
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare-source.d.ts","sourceRoot":"","sources":["../../src/media-pipeline/prepare-source.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGvD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzF,MAAM,WAAW,kBAAkB;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AAmD5F,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,oBAAoB,EACzB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CACR;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAC7F,CA6FA"}
@@ -0,0 +1,132 @@
1
+ import { getPublicOrigin } from '../hosted/oauth/config.js';
2
+ import { getRuntimeContext } from '../runtime/context.js';
3
+ import { buildStagedDownloadUrl, getUploadHmacSecret } from '../staged-upload/hmac.js';
4
+ import { STAGED_UPLOAD_TTL_SECONDS } from '../staged-upload/limits.js';
5
+ import { parseDriveFolderUrl } from './validate.js';
6
+ function sanitizeIds(ids) {
7
+ const out = [];
8
+ const seen = new Set();
9
+ for (const raw of ids ?? []) {
10
+ const t = typeof raw === 'string' ? raw.trim() : '';
11
+ if (!t || seen.has(t)) {
12
+ continue;
13
+ }
14
+ seen.add(t);
15
+ out.push(t);
16
+ }
17
+ return out;
18
+ }
19
+ function normalizeHttpsUrls(urls) {
20
+ const files = [];
21
+ const seen = new Set();
22
+ for (const raw of urls ?? []) {
23
+ const url = typeof raw === 'string' ? raw.trim() : raw.url?.trim();
24
+ if (!url || seen.has(url)) {
25
+ continue;
26
+ }
27
+ seen.add(url);
28
+ let sourceName;
29
+ if (typeof raw !== 'string' && raw.sourceName?.trim()) {
30
+ sourceName = raw.sourceName.trim();
31
+ }
32
+ else {
33
+ try {
34
+ const base = decodeURIComponent(new URL(url).pathname.split('/').pop() ?? '');
35
+ sourceName = base || `file-${String(files.length + 1)}`;
36
+ }
37
+ catch {
38
+ sourceName = `file-${String(files.length + 1)}`;
39
+ }
40
+ }
41
+ const mime = typeof raw === 'string' ? undefined : raw.mime?.trim() || undefined;
42
+ files.push(mime ? { sourceName, url, mime } : { sourceName, url });
43
+ }
44
+ return files;
45
+ }
46
+ function remainingTtlSeconds(createdAt) {
47
+ const elapsed = Math.floor((Date.now() - createdAt) / 1000);
48
+ return Math.max(60, STAGED_UPLOAD_TTL_SECONDS - elapsed);
49
+ }
50
+ export async function resolvePrepareSource(ctx, params) {
51
+ const driveUrl = params.driveFolderUrl?.trim();
52
+ const stagedIds = sanitizeIds(params.stagedUploadIds);
53
+ const httpsFiles = normalizeHttpsUrls(params.httpsUrls);
54
+ const hasDrive = Boolean(driveUrl);
55
+ const hasStaged = stagedIds.length > 0;
56
+ const hasHttps = httpsFiles.length > 0;
57
+ if (hasDrive && (hasStaged || hasHttps)) {
58
+ return {
59
+ ok: false,
60
+ error: 'Provide either driveFolderUrl or stagedUploadIds/httpsUrls, not both. Raster/video intake uses staged or HTTPS files in one prepare job.',
61
+ };
62
+ }
63
+ if (!hasDrive && !hasStaged && !hasHttps) {
64
+ return {
65
+ ok: false,
66
+ error: 'prepare requires driveFolderUrl, stagedUploadIds, or httpsUrls. Raster and video must go through the media pipeline — do not use asset upload --staged/--url/--base64.',
67
+ };
68
+ }
69
+ if (hasDrive && driveUrl) {
70
+ const folder = parseDriveFolderUrl(driveUrl);
71
+ if (!folder.ok) {
72
+ return { ok: false, error: folder.error };
73
+ }
74
+ return {
75
+ ok: true,
76
+ source: { type: 'google_drive_folder', url: folder.url },
77
+ folderId: folder.folderId,
78
+ };
79
+ }
80
+ const files = [...httpsFiles];
81
+ if (hasStaged) {
82
+ const store = ctx.stagedUploadStore ?? getRuntimeContext()?.stagedUploadStore ?? null;
83
+ if (!store) {
84
+ return {
85
+ ok: false,
86
+ error: 'stagedUploadIds require hosted Redis staged upload store.',
87
+ };
88
+ }
89
+ let origin;
90
+ let secret;
91
+ try {
92
+ origin = ctx.publicOrigin ?? getPublicOrigin();
93
+ secret = getUploadHmacSecret();
94
+ }
95
+ catch (err) {
96
+ return {
97
+ ok: false,
98
+ error: err instanceof Error ? err.message : String(err),
99
+ };
100
+ }
101
+ for (const uploadId of stagedIds) {
102
+ try {
103
+ const peeked = await store.peekFile(ctx.userId, uploadId);
104
+ const record = await store.getRecord(ctx.userId, uploadId);
105
+ const exp = Math.floor(Date.now() / 1000) + remainingTtlSeconds(record?.createdAt ?? Date.now());
106
+ const url = buildStagedDownloadUrl(origin, uploadId, ctx.userId, exp, secret);
107
+ files.push({
108
+ sourceName: peeked.fileName,
109
+ url,
110
+ mime: peeked.mimeType,
111
+ });
112
+ }
113
+ catch (err) {
114
+ return {
115
+ ok: false,
116
+ error: err instanceof Error
117
+ ? `Staged upload ${uploadId}: ${err.message}`
118
+ : `Staged upload ${uploadId} is not ready.`,
119
+ };
120
+ }
121
+ }
122
+ }
123
+ if (files.length === 0) {
124
+ return { ok: false, error: 'No files to prepare.' };
125
+ }
126
+ return {
127
+ ok: true,
128
+ source: { type: 'https_urls', files },
129
+ folderId: hasStaged ? `staged:${String(stagedIds.length)}` : 'https',
130
+ };
131
+ }
132
+ //# sourceMappingURL=prepare-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare-source.js","sourceRoot":"","sources":["../../src/media-pipeline/prepare-source.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,10 @@
1
1
  export declare function getUploadHmacSecret(): string;
2
2
  export declare function buildUploadSignaturePayload(uploadId: string, userId: string, exp: number): string;
3
+ export declare function buildDownloadSignaturePayload(uploadId: string, userId: string, exp: number): string;
3
4
  export declare function signUploadUrl(uploadId: string, userId: string, exp: number, secret: string): string;
4
5
  export declare function verifyUploadSignature(uploadId: string, userId: string, exp: number, sig: string, secret: string): boolean;
5
6
  export declare function buildStagedUploadUrl(origin: string, uploadId: string, userId: string, exp: number, secret: string): string;
7
+ export declare function signDownloadUrl(uploadId: string, userId: string, exp: number, secret: string): string;
8
+ export declare function verifyDownloadSignature(uploadId: string, userId: string, exp: number, sig: string, secret: string): boolean;
9
+ export declare function buildStagedDownloadUrl(origin: string, uploadId: string, userId: string, exp: number, secret: string): string;
6
10
  //# sourceMappingURL=hmac.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hmac.d.ts","sourceRoot":"","sources":["../../src/staged-upload/hmac.ts"],"names":[],"mappings":"AAEA,wBAAgB,mBAAmB,IAAI,MAAM,CAM5C;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjG;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,MAAM,CAGR;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAeT;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,MAAM,CASR"}
1
+ {"version":3,"file":"hmac.d.ts","sourceRoot":"","sources":["../../src/staged-upload/hmac.ts"],"names":[],"mappings":"AAEA,wBAAgB,mBAAmB,IAAI,MAAM,CAM5C;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjG;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GACV,MAAM,CAER;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,MAAM,CAGR;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAeT;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,MAAM,CASR;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,MAAM,CAGR;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAeT;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,MAAM,CAUR"}
@@ -9,6 +9,9 @@ export function getUploadHmacSecret() {
9
9
  export function buildUploadSignaturePayload(uploadId, userId, exp) {
10
10
  return `${uploadId}:${userId}:${String(exp)}`;
11
11
  }
12
+ export function buildDownloadSignaturePayload(uploadId, userId, exp) {
13
+ return `get:${uploadId}:${userId}:${String(exp)}`;
14
+ }
12
15
  export function signUploadUrl(uploadId, userId, exp, secret) {
13
16
  const payload = buildUploadSignaturePayload(uploadId, userId, exp);
14
17
  return crypto.createHmac('sha256', secret).update(payload).digest('hex');
@@ -40,4 +43,36 @@ export function buildStagedUploadUrl(origin, uploadId, userId, exp, secret) {
40
43
  });
41
44
  return `${origin.replace(/\/$/, '')}/api/staged-upload?${params.toString()}`;
42
45
  }
46
+ export function signDownloadUrl(uploadId, userId, exp, secret) {
47
+ const payload = buildDownloadSignaturePayload(uploadId, userId, exp);
48
+ return crypto.createHmac('sha256', secret).update(payload).digest('hex');
49
+ }
50
+ export function verifyDownloadSignature(uploadId, userId, exp, sig, secret) {
51
+ if (!sig || !uploadId || !userId) {
52
+ return false;
53
+ }
54
+ const expected = signDownloadUrl(uploadId, userId, exp, secret);
55
+ try {
56
+ const expectedBuf = Buffer.from(expected, 'hex');
57
+ const actualBuf = Buffer.from(sig, 'hex');
58
+ if (expectedBuf.length !== actualBuf.length) {
59
+ return false;
60
+ }
61
+ return crypto.timingSafeEqual(expectedBuf, actualBuf);
62
+ }
63
+ catch {
64
+ return false;
65
+ }
66
+ }
67
+ export function buildStagedDownloadUrl(origin, uploadId, userId, exp, secret) {
68
+ const sig = signDownloadUrl(uploadId, userId, exp, secret);
69
+ const params = new URLSearchParams({
70
+ id: uploadId,
71
+ uid: userId,
72
+ exp: String(exp),
73
+ sig,
74
+ op: 'get',
75
+ });
76
+ return `${origin.replace(/\/$/, '')}/api/staged-upload?${params.toString()}`;
77
+ }
43
78
  //# sourceMappingURL=hmac.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hmac.js","sourceRoot":"","sources":["../../src/staged-upload/hmac.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,MAAM,UAAU,mBAAmB;IACjC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,EAAE,IAAI,EAAE,CAAC;IACjE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,QAAgB,EAAE,MAAc,EAAE,GAAW;IACvF,OAAO,GAAG,QAAQ,IAAI,MAAM,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,QAAgB,EAChB,MAAc,EACd,GAAW,EACX,MAAc;IAEd,MAAM,OAAO,GAAG,2BAA2B,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;IACnE,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,QAAgB,EAChB,MAAc,EACd,GAAW,EACX,GAAW,EACX,MAAc;IAEd,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAC9D,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACjD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC1C,IAAI,WAAW,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;YAC5C,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,MAAM,CAAC,eAAe,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,MAAc,EACd,QAAgB,EAChB,MAAc,EACd,GAAW,EACX,MAAc;IAEd,MAAM,GAAG,GAAG,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,EAAE,EAAE,QAAQ;QACZ,GAAG,EAAE,MAAM;QACX,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC;QAChB,GAAG;KACJ,CAAC,CAAC;IACH,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,sBAAsB,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;AAC/E,CAAC"}
1
+ {"version":3,"file":"hmac.js","sourceRoot":"","sources":["../../src/staged-upload/hmac.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/staged-upload/request.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE5D,MAAM,WAAW,+BAA+B;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE,+BAA+B,GACtC,OAAO,CAAC,yBAAyB,CAAC,CAoCpC"}
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/staged-upload/request.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE5D,MAAM,WAAW,+BAA+B;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE,+BAA+B,GACtC,OAAO,CAAC,yBAAyB,CAAC,CAsCpC"}
@@ -1,3 +1,4 @@
1
+ import { requiresPipelineEncode } from '../contentful/pipeline-encode-gate.js';
1
2
  import { getPublicOrigin } from '../hosted/oauth/config.js';
2
3
  import { buildStagedUploadUrl, getUploadHmacSecret } from './hmac.js';
3
4
  import { hostedStagedMaxBytes, STAGED_UPLOAD_TTL_SECONDS } from './limits.js';
@@ -15,17 +16,19 @@ export async function createStagedUploadRequest(store, params) {
15
16
  const origin = getPublicOrigin();
16
17
  const exp = Math.floor(Date.now() / 1000) + STAGED_UPLOAD_TTL_SECONDS;
17
18
  const uploadUrl = buildStagedUploadUrl(origin, uploadId, params.userId, exp, secret);
18
- const consumeArgs = [
19
- 'asset',
20
- 'upload',
21
- '--staged',
22
- uploadId,
23
- '--mime',
24
- params.mimeType,
25
- '--file-name',
26
- params.fileName,
27
- ...(params.title ? ['--title', params.title] : []),
28
- ];
19
+ const consumeArgs = requiresPipelineEncode(params.mimeType, params.fileName)
20
+ ? ['media', 'prepare', '--staged-ids', uploadId]
21
+ : [
22
+ 'asset',
23
+ 'upload',
24
+ '--staged',
25
+ uploadId,
26
+ '--mime',
27
+ params.mimeType,
28
+ '--file-name',
29
+ params.fileName,
30
+ ...(params.title ? ['--title', params.title] : []),
31
+ ];
29
32
  const curlCommand = `curl -f -X POST -F ${shellQuote(`file=@/path/to/${params.fileName}`)} ${shellQuote(uploadUrl)}`;
30
33
  return {
31
34
  uploadId,
@@ -1 +1 @@
1
- {"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/staged-upload/request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAY9E,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,KAAwB,EACxB,MAAuC;IAEvC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,aAAa,CAAC;QACzC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,MAAM,CAAC,UAAU;KAC9B,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,mBAAmB,EAAE,CAAC;IACrC,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,yBAAyB,CAAC;IACtE,MAAM,SAAS,GAAG,oBAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAErF,MAAM,WAAW,GAAG;QAClB,OAAO;QACP,QAAQ;QACR,UAAU;QACV,QAAQ;QACR,QAAQ;QACR,MAAM,CAAC,QAAQ;QACf,aAAa;QACb,MAAM,CAAC,QAAQ;QACf,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KACnD,CAAC;IAEF,MAAM,WAAW,GAAG,sBAAsB,UAAU,CAAC,kBAAkB,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;IAErH,OAAO;QACL,QAAQ;QACR,SAAS;QACT,SAAS,EAAE,yBAAyB;QACpC,SAAS,EAAE,GAAG;QACd,QAAQ,EAAE,oBAAoB,EAAE;QAChC,WAAW;QACX,WAAW;KACZ,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/staged-upload/request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAY9E,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,KAAwB,EACxB,MAAuC;IAEvC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,aAAa,CAAC;QACzC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,MAAM,CAAC,UAAU;KAC9B,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,mBAAmB,EAAE,CAAC;IACrC,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,yBAAyB,CAAC;IACtE,MAAM,SAAS,GAAG,oBAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAErF,MAAM,WAAW,GAAG,sBAAsB,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;QAC1E,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,CAAC;QAChD,CAAC,CAAC;YACE,OAAO;YACP,QAAQ;YACR,UAAU;YACV,QAAQ;YACR,QAAQ;YACR,MAAM,CAAC,QAAQ;YACf,aAAa;YACb,MAAM,CAAC,QAAQ;YACf,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACnD,CAAC;IAEN,MAAM,WAAW,GAAG,sBAAsB,UAAU,CAAC,kBAAkB,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;IAErH,OAAO;QACL,QAAQ;QACR,SAAS;QACT,SAAS,EAAE,yBAAyB;QACpC,SAAS,EAAE,GAAG;QACd,QAAQ,EAAE,oBAAoB,EAAE;QAChC,WAAW;QACX,WAAW;KACZ,CAAC;AACJ,CAAC"}
@@ -14,6 +14,8 @@ export declare class StagedUploadStore {
14
14
  }): Promise<string>;
15
15
  storeFile(userId: string, uploadId: string, buffer: Buffer, mimeType: string): Promise<StagedUploadRecord>;
16
16
  consume(userId: string, uploadId: string): Promise<StagedUploadConsumeResult>;
17
+ /** Read staged bytes without deleting (pipeline fetch). */
18
+ peekFile(userId: string, uploadId: string): Promise<StagedUploadConsumeResult>;
17
19
  getRecord(userId: string, uploadId: string): Promise<StagedUploadRecord | null>;
18
20
  }
19
21
  //# sourceMappingURL=store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/staged-upload/store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAO/D,OAAO,KAAK,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA0BhF,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAF5B,YACmB,KAAK,EAAE,WAAW,EAClB,SAAS,SAAa,EACrC;IAEJ,OAAO,CAAC,OAAO;IAIT,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYnD;IAEK,aAAa,CAAC,MAAM,EAAE;QAC1B,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmClB;IAEK,SAAS,CACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,CAAC,CA8B7B;IAEK,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAqBlF;IAEK,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAEpF;CACF"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/staged-upload/store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAO/D,OAAO,KAAK,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA0BhF,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAF5B,YACmB,KAAK,EAAE,WAAW,EAClB,SAAS,SAAa,EACrC;IAEJ,OAAO,CAAC,OAAO;IAIT,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYnD;IAEK,aAAa,CAAC,MAAM,EAAE;QAC1B,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmClB;IAEK,SAAS,CACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,CAAC,CA8B7B;IAEK,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAqBlF;IAED,2DAA2D;IACrD,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAgBnF;IAEK,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAEpF;CACF"}
@@ -117,6 +117,24 @@ export class StagedUploadStore {
117
117
  byteLength: buffer.length,
118
118
  };
119
119
  }
120
+ /** Read staged bytes without deleting (pipeline fetch). */
121
+ async peekFile(userId, uploadId) {
122
+ const existing = parseRecord(await this.redis.get(this.fullKey(userId, uploadId)));
123
+ if (!existing || existing.userId !== userId || existing.uploadId !== uploadId) {
124
+ throw new Error('Staged upload not found or expired.');
125
+ }
126
+ if (existing.status !== 'ready' || !existing.dataBase64) {
127
+ throw new Error('Staged upload has no file data yet. POST the file to uploadUrl first.');
128
+ }
129
+ const buffer = Buffer.from(existing.dataBase64, 'base64');
130
+ assertUploadBufferSize(buffer);
131
+ return {
132
+ buffer,
133
+ fileName: existing.fileName,
134
+ mimeType: existing.mimeType,
135
+ byteLength: buffer.length,
136
+ };
137
+ }
120
138
  async getRecord(userId, uploadId) {
121
139
  return parseRecord(await this.redis.get(this.fullKey(userId, uploadId)));
122
140
  }
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/staged-upload/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/staged-upload/store.ts"],"names":[],"mappings":"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"}
@@ -33,10 +33,13 @@ Normalize a **folder of designer masters** into short-lived **public HTTPS URLs*
33
33
 
34
34
  | Situation | Action |
35
35
  |-----------|--------|
36
- | Drive/Figma package with large JPEGs/videos | **This task first**, then structure build |
37
- | Single small image already in library | `task-media-reuse-and-upload` only |
38
- | Masters already under limits and catalogued | Reuse search only |
39
- | Prior prepare already reached `succeeded` + catalog | **Reuse that jobId** — do not re-prepare the whole folder |
36
+ | Drive folder of masters | This task with `driveFolderUrl` |
37
+ | Staged files (curl after `cms_edit_request_staged_upload`) | This task with `stagedUploadIds` — one prepare for the batch |
38
+ | Public HTTPS on allowed hosts | This task with `httpsUrls` |
39
+ | Single SVG/PDF/Lottie | `task-media-reuse-and-upload` asset upload --staged |
40
+ | Prior prepare already reached `succeeded` + catalog | **Reuse that jobId** — do not re-prepare |
41
+
42
+ Do **not** use `asset upload --staged/--base64` for jpeg/png/webp/gif/mp4. **Video** must use **import** (not `asset upload --url`, even on a Blob ready host). Raster `--url` is allowed only for pipeline ready image hosts.
40
43
 
41
44
  ## Steps (agent — single auth)
42
45
 
@@ -44,6 +47,8 @@ Normalize a **folder of designer masters** into short-lived **public HTTPS URLs*
44
47
 
45
48
  Call MCP tool **`cms_edit_media`**:
46
49
 
50
+ Drive:
51
+
47
52
  ```json
48
53
  {
49
54
  "action": "prepare",
@@ -51,23 +56,27 @@ Call MCP tool **`cms_edit_media`**:
51
56
  "profile": "case-study-v1",
52
57
  "sourceNames": [
53
58
  "BusinessCards copy.jpg",
54
- "ArcticDB x3 Screens Tablet-1920.mp4",
55
- "ADB_Macbook_HomeLoop.mp4"
59
+ "ArcticDB x3 Screens Tablet-1920.mp4"
56
60
  ]
57
61
  }
58
62
  ```
59
63
 
60
- | Param | On prepare |
61
- |-------|------------|
62
- | omit `sourceNames` | Encode **entire** folder (slow for large case-study packs) |
63
- | non-empty `sourceNames` | **Allowlist** — only exact Drive file names are downloaded/encoded |
64
- | `excludeSourceNames` | Skip these names (always) |
64
+ Staged (after curl PUT/POST to each `uploadUrl`):
65
+
66
+ ```json
67
+ {
68
+ "action": "prepare",
69
+ "stagedUploadIds": ["<uploadId1>", "<uploadId2>"]
70
+ }
71
+ ```
65
72
 
66
73
  CLI:
67
74
 
68
75
  ```bash
69
76
  cms-edit media prepare --drive-folder "https://drive.google.com/drive/folders/…" \
70
77
  --source-names "BusinessCards copy.jpg,ADB_Macbook_HomeLoop.mp4"
78
+
79
+ cms-edit media prepare --staged-ids "id1,id2"
71
80
  ```
72
81
 
73
82
  Expect `{ ok: true, jobId, status: "queued", pollHint }`.
@@ -103,7 +112,7 @@ or
103
112
 
104
113
  - Do **not** invent assets for gaps.
105
114
  - Do **not** wait 5–10+ minutes on `provisioning`.
106
- - Do **not** thrash prepares (rate limit + concurrent max typically **2** per user).
115
+ - Do **not** thrash prepares (rate limit **100**/hour, concurrent max typically **4** per user).
107
116
  - On `429` / too many concurrent: call `status` once on any stuck old `jobId` (to free slots if past grace), then prepare again **once**.
108
117
  - Prefer **reusing** a job that already reached `succeeded` + catalog over preparing again for the same Drive folder.
109
118
 
@@ -117,9 +126,10 @@ Each asset includes:
117
126
 
118
127
  | Field | Use |
119
128
  |-------|-----|
120
- | `readyUrl` | `asset upload --url` into Contentful |
129
+ | `readyUrl` | Import via `cms_edit_media` import only (CMA gate: pipeline ready hosts) |
121
130
  | `previewUrl` / `posterUrl` | Agent vision for **title / fileName / alt** (when present) |
122
- | `altDraft` / `titleDraft` | Filename seeds only — improve before save |
131
+ | `altDraft` / `titleDraft` | Filename seeds only — improve before import |
132
+ | `role` `gif-converted` | Animated GIF became MP4 — Media mute-loop, not `featuredImage` |
123
133
 
124
134
  ### 4. Import into Contentful (reuse-first)
125
135
 
@@ -146,9 +156,10 @@ After drafting titles/alts from **previewUrl** / **posterUrl**:
146
156
  }
147
157
  ```
148
158
 
149
- 1. Always **`dryRun: true` first** — check `existing: true/false` per asset (reuse is by **fileName**).
150
- 2. When you need **new** assets instead of reusing prior runs, set `overrides[].fileName` to unique names.
151
- 3. Then import without `dryRun`.
159
+ 1. Always **`dryRun: true` first** — check `existing: true/false` per asset (reuse is by **fileName**). Missing alt on new files is reported as `altFailures` / per-row `alt_required`; dryRun still returns `ok: true`.
160
+ 2. New uploads **fail** without review-quality `overrides[].alt` when you import for real (not empty, not the filename).
161
+ 3. When you need **new** assets instead of reusing prior runs, set `overrides[].fileName` to unique names.
162
+ 4. Then import without `dryRun`.
152
163
 
153
164
  CLI:
154
165
  `cms-edit media import --job <id> [--dry-run] [--with-media] [--only-with-overrides] [--source-names a.jpg,b.jpg] [--exclude-source-names x.jpg] [--overrides-json '[…]']`
@@ -164,7 +175,7 @@ Import:
164
175
  `cms_edit ["set", "@cN", "visual", "<mediaId>", "--link"]`
165
176
  — **never** `add … --target visual` (`add` only supports content **arrays**).
166
177
 
167
- Manual `asset upload --url` remains available for one-offs.
178
+ Manual `asset upload --url` is allowed only for **pipeline-ready images** (Vercel Blob / `MEDIA_PIPELINE_READY_HOSTS`, https in production). **Video** must use **import**. Always prefer import for new masters.
168
179
 
169
180
  ### Hardening notes (for agents)
170
181
 
@@ -32,30 +32,39 @@
32
32
 
33
33
  ## Upload only when no match
34
34
 
35
- ### Oversized masters / whole Drive folders
35
+ ### Raster images and video (required)
36
36
 
37
- If files are near or over **4 MB** (hosted staged) or **10 MB** (URL/local), or the user shared a **Drive folder of masters**, do **not** improvise compression in chat.
37
+ Encode via **`task-media-pipeline-prepare`**. Intake can be:
38
38
 
39
- 1. Run **`task-media-pipeline-prepare`** (Drive folder → ready public URLs under limits)
40
- 2. Return here and import with **`--url`** + reuse-first filename search
39
+ 1. A **Drive folder**, or
40
+ 2. **Staged upload** (4 MB): `cms_edit_request_staged_upload` → curl → `cms_edit_media` prepare with `stagedUploadIds` (see returned `consumeArgs`), or
41
+ 3. **httpsUrls** on pipeline-allowed hosts
41
42
 
42
- ### Hosted MCP (default)
43
+ Then wait → catalog → **import** with `overrides[].alt`. Do **not** `asset upload --staged/--base64` for jpeg/png/webp/gif/mp4. Do **not** `asset upload --url` for **video** (import only). Raster `--url` only for pipeline ready image hosts.
43
44
 
44
- **Always use staged upload** for ad-hoc small binaries. Do not pass base64 in `cms_edit` args — hosted MCP rejects `asset upload --base64`.
45
+ Animated GIFs become **MP4** (`gif-converted`) — attach as mute-loop Media / video visual, not `featuredImage`.
46
+
47
+ ### SVG, PDF, Lottie
48
+
49
+ These may skip the pipeline. On hosted MCP use staged upload then `asset upload --staged`.
50
+
51
+ ### Hosted MCP (SVG/PDF/Lottie only)
52
+
53
+ **Always use staged upload** for ad-hoc binaries. Do not pass base64 in `cms_edit` args — hosted MCP rejects `asset upload --base64`.
45
54
 
46
55
  1. `cms_edit_request_staged_upload` with `fileName`, `mimeType`, optional `byteLength`, optional `title`
47
56
  2. Run the returned `curlCommand` in a shell (POST file to `uploadUrl`)
48
- 3. `cms_edit` with the returned `consumeArgs` (e.g. `["asset","upload","--staged","<uploadId>",…]`)
57
+ 3. Follow `consumeArgs`: **media prepare** for photos/video; **asset upload --staged** for SVG/PDF/Lottie
49
58
 
50
59
  Rules:
51
60
 
52
- - Staged upload keeps binary **out of MCP args** — only a short `uploadId` is passed to Contentful
53
- - Hosted limit: **4 MB** per file; **1000 upload URLs per user per hour**; TTL **60 minutes**; single-use
54
- - **PNG** when the source has transparency (portraits on brand-colour cards); JPEG flattens alpha
55
- - Upload alone does **not** attach the asset — follow with **link + save** (below)
61
+ - Staged upload keeps binary **out of MCP args**
62
+ - Hosted limit: **4 MB** per file; **1000 upload URLs per user per hour**; TTL **60 minutes**
63
+ - Raster/video staged files stay in Redis until pipeline fetches them (GET); they are not written to CMA
64
+ - Upload/import alone does **not** attach the asset — follow with **link + save** (below)
56
65
  - Use `--if-exists-by-filename` (with `--file-name`) to avoid duplicate assets when re-running
57
66
 
58
- After staged upload, create a Media wrapper **only when none exists** for that asset:
67
+ After import, create a Media wrapper **only when none exists** for that asset:
59
68
 
60
69
  ```
61
70
  cms_edit ["list", "--type", "media", "--asset-id", "<newPortraitAssetId>"]
@@ -68,17 +77,11 @@ To rename an existing Media wrapper: `cms_edit ["batch", "set", "<media-entry-id
68
77
 
69
78
  Avoid `asset upload --with-media` when multiple entries will share the same image (e.g. news composites) — it creates duplicate Media entries. Upload the asset only, then one shared `create media`, then link the media ID on each entry.
70
79
 
71
- **Prefer `--url`** when the file is already on **public HTTPS** under size limits — especially **media-pipeline ready pack URLs**:
72
-
73
- ```
74
- cms_edit ["asset", "upload", "--url", "https://<public-https-url>/file.png", "--mime", "image/png", "--file-name", "headshot-name-1200.png", "--title", "…", "--if-exists-by-filename"]
75
- ```
76
-
77
- The URL must be fetchable by the hosted MCP server. Do not use local-only URLs.
80
+ **Prefer pipeline import** for encoded masters. **Video** must use import. `asset upload --url` is only for **pipeline ready images** (or SVG/PDF/Lottie). A random PNG or Contentful CDN master is rejected.
78
81
 
79
82
  ### Local CLI (only when user approves)
80
83
 
81
- Hosted MCP uses `cms_edit_request_staged_upload` then `asset upload --staged`. Do not use the local `cms-edit` CLI for uploads.
84
+ Hosted MCP uses `cms_edit_request_staged_upload` then **media prepare** for raster/video (or `asset upload --staged` for SVG/PDF/Lottie). Do not use the local `cms-edit` CLI for uploads.
82
85
 
83
86
  ## Link uploaded asset to an entry
84
87
 
@@ -20,7 +20,7 @@ All `save` operations create **drafts only**. A human must review and publish in
20
20
  | Tool | Purpose |
21
21
  |------|---------|
22
22
  | `cms_edit` | Run any cms-edit command via an `args` array |
23
- | `cms_edit_request_staged_upload` | Get a presigned upload URL for binary files (then `curl` + `asset upload --staged`) |
23
+ | `cms_edit_request_staged_upload` | Presigned URL for binaries. Raster/video: then `cms_edit_media` prepare. SVG/PDF/Lottie: then `asset upload --staged` |
24
24
  | `cms_edit_version` | Check the installed cms-edit version (no session required) |
25
25
  | `cms_edit_help` | Guide topics (`overview`, `workflow`, `commands`, `troubleshooting`, `hosted`) **or** playbooks (`create-from-json`, `fields-component`, …) |
26
26
 
@@ -130,7 +130,7 @@ Always run `diff` before `save`. To abandon changes: `["discard"]`.
130
130
  | Task | Where |
131
131
  |------|-------|
132
132
  | Edit copy, add sections, create pages/articles | **Agent + cms-edit** (drafts) |
133
- | Upload new images and files | **Agent + cms-edit** (`asset upload`) — search/reuse first |
133
+ | Upload new images and files | **Agent + cms-edit** — search/reuse first; raster/video via `cms_edit_media` import |
134
134
  | Publish approved drafts | **Contentful UI** |
135
135
  | Edit copy directly in Contentful | **Avoid** — use cms-edit instead |
136
136
 
@@ -138,12 +138,13 @@ cms-edit saves **drafts only**. A colleague must **publish in Contentful** for c
138
138
 
139
139
  ## Asset upload (hosted MCP)
140
140
 
141
- Hosted connectors have **no server filesystem** and **reject `asset upload --base64`**. Use staged upload for all images and binary files.
141
+ Hosted connectors have **no server filesystem** and **reject `asset upload --base64`**. Raster/video: staged intake then **media pipeline**. SVG/PDF/Lottie: staged then `asset upload --staged`.
142
142
 
143
143
  | Source | When | Example |
144
144
  |--------|------|---------|
145
- | **Staged upload** (required for binary) | All images and files on hosted MCP | See **Staged upload** below |
146
- | **`--url`** (last resort) | File already on public HTTPS fetchable by the host | `["asset", "upload", "--url", "https://…/photo.png", "--mime", "image/png", "--file-name", "photo.png"]` |
145
+ | **Staged + pipeline** | jpeg/png/webp/gif/mp4 | `cms_edit_media` prepare `stagedUploadIds` → import (required for video) |
146
+ | **`--url`** | Pipeline-ready **images** only, or SVG/PDF | `["asset", "upload", "--url", "https://….blob.vercel-storage.com/ready.jpg"]` |
147
+ | **Staged consume** | SVG/PDF/Lottie | `asset upload --staged` |
147
148
 
148
149
  **After upload:** note the returned asset `id`, attach to the entry (`asset set @root media <id>` for person portraits), then `diff` → `save`. Upload alone does not update entries.
149
150
 
@@ -168,10 +169,10 @@ Keeps binary **out of MCP tool args**. The agent uploads via `curl`, then passes
168
169
 
169
170
  1. `cms_edit_request_staged_upload` with `fileName`, `mimeType`, optional `byteLength`, optional `title`
170
171
  2. Run the returned `curlCommand` in a shell (POST multipart to `uploadUrl`)
171
- 3. `cms_edit` with the returned `consumeArgs` (includes `asset upload --staged <uploadId>`)
172
- 4. Link and save as usual
172
+ 3. Follow `consumeArgs`: **media prepare** (`cms_edit_media` / `media prepare --staged-ids`) for jpeg/png/webp/gif/mp4; **asset upload --staged** for SVG/PDF/Lottie
173
+ 4. For pipeline jobs: wait → catalog → **import** (required for video). Then link and save
173
174
 
174
- Hosted limit: **4 MB** per staged file (Vercel body limit). Rate limit: **1000 upload URLs per user per hour**. TTL: **60 minutes**, single-use.
175
+ Hosted limit: **4 MB** per staged file (Vercel body limit). Rate limit: **1000 upload URLs per user per hour**. TTL: **60 minutes**. Raster/video staged files are intake (GET by the pipeline); they are not consumed into CMA.
175
176
 
176
177
  ## Featured images (articles)
177
178
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@se-studio/contentful-cms",
3
- "version": "3.9.4",
3
+ "version": "3.10.0",
4
4
  "description": "CLI tool for AI agents to read and edit Contentful draft content without publish permissions",
5
5
  "repository": {
6
6
  "type": "git",
@@ -31,7 +31,8 @@ Use this skill when you need to read or edit content in Contentful using **hoste
31
31
  All `save` operations create **draft** versions. A human must review and publish in Contentful.
32
32
 
33
33
  **Assets:** Upload **is** supported (`asset upload`). Default workflow: **search and reuse** existing assets first (`index sync` → `asset search`). When uploading:
34
- - **Hosted MCP:** always `cms_edit_request_staged_upload` → curl → `asset upload --staged` (never `--base64`)
34
+ - **Raster/video:** `cms_edit_request_staged_upload` → curl → `cms_edit_media` prepare (`stagedUploadIds`) → wait → catalog → import with real alt. Never `asset upload --staged/--url/--base64` for jpeg/png/webp/gif/mp4.
35
+ - **SVG/PDF/Lottie:** `cms_edit_request_staged_upload` → curl → `asset upload --staged` (never `--base64`)
35
36
  - Use a **sensible fileName** and **descriptive title** (and alt text where the site uses it)
36
37
  - Avoid oversized images — width over **2000px** is usually wasteful for web (exact limits vary by project; check `asset audit` / media review guidance)
37
38
  - Prefer `--if-exists-by-filename` to avoid duplicates
@@ -371,13 +372,8 @@ cms-edit asset search "hero background"
371
372
  cms-edit asset search --filename istockphoto-123.jpg
372
373
  cms-edit asset search --filename-match 'istockphoto-.*'
373
374
 
374
- # Local CLI — URL or base64 (hosted MCP rejects --base64)
375
- cms-edit asset upload --url https://example.com/image.jpg --if-exists-by-filename
376
- cms-edit asset upload --base64 "$B64" --mime image/png --file-name poster.png
377
-
378
- # Hosted MCP — always staged upload for binary files
379
- # cms_edit_request_staged_upload → curl uploadUrl → consumeArgs
380
- # cms_edit ["asset", "upload", "--staged", "<uploadId>", "--mime", "image/png", "--file-name", "photo.png"]
375
+ # Raster/video: cms_edit_media prepare → wait → catalog → import (video: import only).
376
+ # SVG/PDF/Lottie: cms_edit_request_staged_upload → curl → asset upload --staged
381
377
 
382
378
  # Upload and create a Media wrapper in one step (--media-name defaults to asset title)
383
379
  cms-edit asset upload ./figure.png --with-media --media-position Middle