@se-studio/contentful-cms 3.10.3 → 3.11.1

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 (133) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -1
  3. package/dist/cli/hosted-inline-limit.d.ts +4 -0
  4. package/dist/cli/hosted-inline-limit.d.ts.map +1 -0
  5. package/dist/cli/hosted-inline-limit.js +15 -0
  6. package/dist/cli/hosted-inline-limit.js.map +1 -0
  7. package/dist/cli/read-json-input.d.ts +16 -1
  8. package/dist/cli/read-json-input.d.ts.map +1 -1
  9. package/dist/cli/read-json-input.js +100 -12
  10. package/dist/cli/read-json-input.js.map +1 -1
  11. package/dist/commands/apply-from-json.d.ts.map +1 -1
  12. package/dist/commands/apply-from-json.js +10 -3
  13. package/dist/commands/apply-from-json.js.map +1 -1
  14. package/dist/commands/article-tags-from-json.d.ts.map +1 -1
  15. package/dist/commands/article-tags-from-json.js +12 -3
  16. package/dist/commands/article-tags-from-json.js.map +1 -1
  17. package/dist/commands/asset.d.ts.map +1 -1
  18. package/dist/commands/asset.js +2 -0
  19. package/dist/commands/asset.js.map +1 -1
  20. package/dist/commands/create-from-json.d.ts.map +1 -1
  21. package/dist/commands/create-from-json.js +16 -4
  22. package/dist/commands/create-from-json.js.map +1 -1
  23. package/dist/commands/create-person-from-json.d.ts.map +1 -1
  24. package/dist/commands/create-person-from-json.js +12 -3
  25. package/dist/commands/create-person-from-json.js.map +1 -1
  26. package/dist/commands/create-person.d.ts.map +1 -1
  27. package/dist/commands/create-person.js +20 -5
  28. package/dist/commands/create-person.js.map +1 -1
  29. package/dist/commands/create-taxonomy-from-json.d.ts.map +1 -1
  30. package/dist/commands/create-taxonomy-from-json.js +12 -3
  31. package/dist/commands/create-taxonomy-from-json.js.map +1 -1
  32. package/dist/commands/create-taxonomy.d.ts.map +1 -1
  33. package/dist/commands/create-taxonomy.js +28 -8
  34. package/dist/commands/create-taxonomy.js.map +1 -1
  35. package/dist/commands/host-scaffold.d.ts +1 -0
  36. package/dist/commands/host-scaffold.d.ts.map +1 -1
  37. package/dist/commands/host-scaffold.js +4 -2
  38. package/dist/commands/host-scaffold.js.map +1 -1
  39. package/dist/commands/open.d.ts.map +1 -1
  40. package/dist/commands/open.js +9 -3
  41. package/dist/commands/open.js.map +1 -1
  42. package/dist/commands/project.d.ts.map +1 -1
  43. package/dist/commands/project.js +2 -0
  44. package/dist/commands/project.js.map +1 -1
  45. package/dist/commands/read.d.ts.map +1 -1
  46. package/dist/commands/read.js +3 -0
  47. package/dist/commands/read.js.map +1 -1
  48. package/dist/commands/rtf.d.ts.map +1 -1
  49. package/dist/commands/rtf.js +20 -8
  50. package/dist/commands/rtf.js.map +1 -1
  51. package/dist/commands/run.d.ts.map +1 -1
  52. package/dist/commands/run.js +12 -3
  53. package/dist/commands/run.js.map +1 -1
  54. package/dist/commands/session-diff.d.ts.map +1 -1
  55. package/dist/commands/session-diff.js +13 -0
  56. package/dist/commands/session-diff.js.map +1 -1
  57. package/dist/commands/set.d.ts.map +1 -1
  58. package/dist/commands/set.js +78 -38
  59. package/dist/commands/set.js.map +1 -1
  60. package/dist/commands/staged-upload.d.ts.map +1 -1
  61. package/dist/commands/staged-upload.js +2 -0
  62. package/dist/commands/staged-upload.js.map +1 -1
  63. package/dist/contentful/cma-user-agent.d.ts +1 -1
  64. package/dist/diff/long-text.d.ts +24 -0
  65. package/dist/diff/long-text.d.ts.map +1 -0
  66. package/dist/diff/long-text.js +65 -0
  67. package/dist/diff/long-text.js.map +1 -0
  68. package/dist/generated/help-topics.d.ts.map +1 -1
  69. package/dist/generated/help-topics.js +1 -1
  70. package/dist/generated/help-topics.js.map +1 -1
  71. package/dist/generated/hosted-guide.d.ts +1 -1
  72. package/dist/generated/hosted-guide.d.ts.map +1 -1
  73. package/dist/generated/hosted-guide.js +1 -1
  74. package/dist/generated/hosted-guide.js.map +1 -1
  75. package/dist/generated/version.d.ts +1 -1
  76. package/dist/generated/version.js +1 -1
  77. package/dist/mcp/tools/cms-edit.d.ts +1 -1
  78. package/dist/mcp/tools/cms-edit.d.ts.map +1 -1
  79. package/dist/mcp/tools/cms-edit.js +18 -10
  80. package/dist/mcp/tools/cms-edit.js.map +1 -1
  81. package/dist/mcp/tools/staged-upload.d.ts.map +1 -1
  82. package/dist/mcp/tools/staged-upload.js +27 -10
  83. package/dist/mcp/tools/staged-upload.js.map +1 -1
  84. package/dist/media-pipeline/prepare-source.d.ts.map +1 -1
  85. package/dist/media-pipeline/prepare-source.js +2 -0
  86. package/dist/media-pipeline/prepare-source.js.map +1 -1
  87. package/dist/preview/entry-urls.d.ts.map +1 -1
  88. package/dist/preview/entry-urls.js +8 -6
  89. package/dist/preview/entry-urls.js.map +1 -1
  90. package/dist/project/doctor.d.ts.map +1 -1
  91. package/dist/project/doctor.js +11 -0
  92. package/dist/project/doctor.js.map +1 -1
  93. package/dist/project/validate-staged-upload-route.d.ts +6 -0
  94. package/dist/project/validate-staged-upload-route.d.ts.map +1 -0
  95. package/dist/project/validate-staged-upload-route.js +47 -0
  96. package/dist/project/validate-staged-upload-route.js.map +1 -0
  97. package/dist/rtf/resolveRtfInput.d.ts +7 -2
  98. package/dist/rtf/resolveRtfInput.d.ts.map +1 -1
  99. package/dist/rtf/resolveRtfInput.js +49 -7
  100. package/dist/rtf/resolveRtfInput.js.map +1 -1
  101. package/dist/session/dirty.js +3 -3
  102. package/dist/session/dirty.js.map +1 -1
  103. package/dist/snapshot/fields.d.ts +1 -0
  104. package/dist/snapshot/fields.d.ts.map +1 -1
  105. package/dist/snapshot/fields.js +23 -0
  106. package/dist/snapshot/fields.js.map +1 -1
  107. package/dist/staged-upload/consume-text.d.ts +11 -0
  108. package/dist/staged-upload/consume-text.d.ts.map +1 -0
  109. package/dist/staged-upload/consume-text.js +55 -0
  110. package/dist/staged-upload/consume-text.js.map +1 -0
  111. package/dist/staged-upload/mime.d.ts +9 -1
  112. package/dist/staged-upload/mime.d.ts.map +1 -1
  113. package/dist/staged-upload/mime.js +52 -3
  114. package/dist/staged-upload/mime.js.map +1 -1
  115. package/dist/staged-upload/request.d.ts +2 -0
  116. package/dist/staged-upload/request.d.ts.map +1 -1
  117. package/dist/staged-upload/request.js +24 -12
  118. package/dist/staged-upload/request.js.map +1 -1
  119. package/dist/staged-upload/store.d.ts +2 -0
  120. package/dist/staged-upload/store.d.ts.map +1 -1
  121. package/dist/staged-upload/store.js +13 -7
  122. package/dist/staged-upload/store.js.map +1 -1
  123. package/dist/staged-upload/types.d.ts +4 -0
  124. package/dist/staged-upload/types.d.ts.map +1 -1
  125. package/docs/editor-tasks/create-html-component.md +15 -5
  126. package/docs/editor-tasks/preview-verify.md +6 -5
  127. package/docs/help/create-from-json.md +7 -4
  128. package/docs/help/fields-html-component.md +11 -1
  129. package/docs/help/index.md +1 -1
  130. package/docs/help/workflow.md +1 -1
  131. package/docs/mcp/hosted-guide.md +13 -11
  132. package/package.json +1 -1
  133. package/skills/core/SKILL.md +4 -3
@@ -1 +1 @@
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"}
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;AAC9E,OAAO,EAAE,qBAAqB,EAAyB,MAAM,WAAW,CAAC;AAazE,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC7C,CAAC;AAED,SAAS,gBAAgB,CACvB,IAAsB,EACtB,QAAgB,EAChB,MAAuC;IAEvC,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;IACvC,CAAC;IACD,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,sBAAsB,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;QAC7D,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;AACR,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,KAAwB,EACxB,MAAuC;IAEvC,MAAM,IAAI,GAAG,qBAAqB,CAAC,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAE9F,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,IAAI;QACJ,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,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAE7D,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,4 +1,5 @@
1
1
  import type { RedisClient } from '../session/session-store.js';
2
+ import { type StagedUploadKind } from './mime.js';
2
3
  import type { StagedUploadConsumeResult, StagedUploadRecord } from './types.js';
3
4
  export declare class StagedUploadStore {
4
5
  private readonly redis;
@@ -10,6 +11,7 @@ export declare class StagedUploadStore {
10
11
  userId: string;
11
12
  fileName: string;
12
13
  mimeType: string;
14
+ kind?: StagedUploadKind;
13
15
  byteLength?: number;
14
16
  }): Promise<string>;
15
17
  storeFile(userId: string, uploadId: string, buffer: Buffer, mimeType: string): Promise<StagedUploadRecord>;
@@ -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;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"}
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;AAM/D,OAAO,EAGL,KAAK,gBAAgB,EAEtB,MAAM,WAAW,CAAC;AACnB,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,IAAI,CAAC,EAAE,gBAAgB,CAAC;QACxB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqClB;IAEK,SAAS,CACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,CAAC,CAgC7B;IAEK,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAsBlF;IAED,2DAA2D;IACrD,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAiBnF;IAEK,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAEpF;CACF"}
@@ -1,7 +1,7 @@
1
1
  import * as crypto from 'node:crypto';
2
2
  import { assertUploadBufferSize } from '../contentful/upload-limits.js';
3
3
  import { hostedStagedMaxBytes, STAGED_UPLOAD_RATE_LIMIT_PER_HOUR, STAGED_UPLOAD_TTL_SECONDS, } from './limits.js';
4
- import { isAllowedStagedMimeType } from './mime.js';
4
+ import { effectiveStagedMimeType, isAllowedStagedMimeType, stagedKindOrAsset, } from './mime.js';
5
5
  const KEY_PREFIX = 'cms-edit:staged:';
6
6
  const RATE_PREFIX = 'cms-edit:staged-rate:';
7
7
  function rateKey(userId, hourBucket) {
@@ -46,8 +46,9 @@ export class StagedUploadStore {
46
46
  }
47
47
  }
48
48
  async createPending(params) {
49
- if (!isAllowedStagedMimeType(params.mimeType)) {
50
- throw new Error(`MIME type not allowed for staged upload: ${params.mimeType}`);
49
+ const kind = params.kind ?? 'asset';
50
+ if (!isAllowedStagedMimeType(params.mimeType, kind)) {
51
+ throw new Error(`MIME type not allowed for staged upload (${kind}): ${params.mimeType}`);
51
52
  }
52
53
  if (params.byteLength !== undefined && params.byteLength > hostedStagedMaxBytes()) {
53
54
  throw new Error(`Declared byteLength exceeds hosted staged upload limit (${String(hostedStagedMaxBytes())} bytes).`);
@@ -59,6 +60,7 @@ export class StagedUploadStore {
59
60
  userId: params.userId,
60
61
  fileName: params.fileName,
61
62
  mimeType: params.mimeType,
63
+ kind,
62
64
  byteLength: params.byteLength,
63
65
  status: 'pending',
64
66
  createdAt: Date.now(),
@@ -77,9 +79,6 @@ export class StagedUploadStore {
77
79
  if (buffer.length > hostedStagedMaxBytes()) {
78
80
  throw new Error(`File exceeds hosted staged upload limit (${String(hostedStagedMaxBytes())} bytes).`);
79
81
  }
80
- if (!isAllowedStagedMimeType(mimeType)) {
81
- throw new Error(`MIME type not allowed for staged upload: ${mimeType}`);
82
- }
83
82
  const key = this.fullKey(userId, uploadId);
84
83
  const existing = parseRecord(await this.redis.get(key));
85
84
  if (!existing || existing.userId !== userId || existing.uploadId !== uploadId) {
@@ -88,10 +87,15 @@ export class StagedUploadStore {
88
87
  if (existing.status === 'ready') {
89
88
  throw new Error('Staged upload already received.');
90
89
  }
90
+ const kind = existing.kind ?? 'asset';
91
+ const resolvedMime = effectiveStagedMimeType(mimeType, existing.mimeType, kind);
92
+ if (!isAllowedStagedMimeType(resolvedMime, kind)) {
93
+ throw new Error(`MIME type not allowed for staged upload (${kind}): ${resolvedMime}`);
94
+ }
91
95
  const record = {
92
96
  ...existing,
93
97
  status: 'ready',
94
- mimeType,
98
+ mimeType: resolvedMime,
95
99
  byteLength: buffer.length,
96
100
  dataBase64: buffer.toString('base64'),
97
101
  };
@@ -115,6 +119,7 @@ export class StagedUploadStore {
115
119
  fileName: existing.fileName,
116
120
  mimeType: existing.mimeType,
117
121
  byteLength: buffer.length,
122
+ kind: stagedKindOrAsset(existing.kind),
118
123
  };
119
124
  }
120
125
  /** Read staged bytes without deleting (pipeline fetch). */
@@ -133,6 +138,7 @@ export class StagedUploadStore {
133
138
  fileName: existing.fileName,
134
139
  mimeType: existing.mimeType,
135
140
  byteLength: buffer.length,
141
+ kind: stagedKindOrAsset(existing.kind),
136
142
  };
137
143
  }
138
144
  async getRecord(userId, uploadId) {
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/staged-upload/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAExE,OAAO,EACL,oBAAoB,EACpB,iCAAiC,EACjC,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAGpD,MAAM,UAAU,GAAG,kBAAkB,CAAC;AACtC,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAE5C,SAAS,OAAO,CAAC,MAAc,EAAE,UAAkB;IACjD,OAAO,GAAG,WAAW,GAAG,MAAM,IAAI,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;AACzD,CAAC;AAED,SAAS,WAAW,CAAC,GAAY;IAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAuB,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAyB,CAAC;IACnC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,OAAO,iBAAiB;IAET,KAAK;IACL,SAAS;IAF5B,YACmB,KAAkB,EAClB,SAAS,GAAG,UAAU;qBADtB,KAAK;yBACL,SAAS;IACzB,CAAC;IAEI,OAAO,CAAC,MAAc,EAAE,QAAgB;QAC9C,OAAO,GAAG,IAAI,CAAC,SAAS,GAAG,MAAM,IAAI,QAAQ,EAAE,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,MAAc;QAClC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;QAC7D,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,KAAK,GAAG,iCAAiC,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CACb,sCAAsC,MAAM,CAAC,iCAAiC,CAAC,aAAa,CAC7F,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,MAKnB;QACC,IAAI,CAAC,uBAAuB,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,4CAA4C,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACjF,CAAC;QACD,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,IAAI,MAAM,CAAC,UAAU,GAAG,oBAAoB,EAAE,EAAE,CAAC;YAClF,MAAM,IAAI,KAAK,CACb,2DAA2D,MAAM,CAAC,oBAAoB,EAAE,CAAC,UAAU,CACpG,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAE1C,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvD,MAAM,MAAM,GAAuB;YACjC,QAAQ;YACR,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,MAAM,EAAE,SAAS;YACjB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QAEF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAC9B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EACrC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EACtB;YACE,EAAE,EAAE,yBAAyB;YAC7B,EAAE,EAAE,IAAI;SACT,CACF,CAAC;QACF,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC3D,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,SAAS,CACb,MAAc,EACd,QAAgB,EAChB,MAAc,EACd,QAAgB;QAEhB,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,MAAM,CAAC,MAAM,GAAG,oBAAoB,EAAE,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CACb,4CAA4C,MAAM,CAAC,oBAAoB,EAAE,CAAC,UAAU,CACrF,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,uBAAuB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,4CAA4C,QAAQ,EAAE,CAAC,CAAC;QAC1E,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACxD,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC9E,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,MAAM,GAAuB;YACjC,GAAG,QAAQ;YACX,MAAM,EAAE,OAAO;YACf,QAAQ;YACR,UAAU,EAAE,MAAM,CAAC,MAAM;YACzB,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;SACtC,CAAC;QAEF,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,yBAAyB,EAAE,CAAC,CAAC;QACrF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,QAAgB;QAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACxD,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC9E,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,KAAK,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;QAC3F,CAAC;QAED,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAE1B,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC1D,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAE/B,OAAO;YACL,MAAM;YACN,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,UAAU,EAAE,MAAM,CAAC,MAAM;SAC1B,CAAC;IACJ,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,QAAQ,CAAC,MAAc,EAAE,QAAgB;QAC7C,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;QACnF,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC9E,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,KAAK,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;QAC3F,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC1D,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAC/B,OAAO;YACL,MAAM;YACN,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,UAAU,EAAE,MAAM,CAAC,MAAM;SAC1B,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,MAAc,EAAE,QAAgB;QAC9C,OAAO,WAAW,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC;CACF"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/staged-upload/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAExE,OAAO,EACL,oBAAoB,EACpB,iCAAiC,EACjC,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EAEvB,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAGnB,MAAM,UAAU,GAAG,kBAAkB,CAAC;AACtC,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAE5C,SAAS,OAAO,CAAC,MAAc,EAAE,UAAkB;IACjD,OAAO,GAAG,WAAW,GAAG,MAAM,IAAI,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;AACzD,CAAC;AAED,SAAS,WAAW,CAAC,GAAY;IAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAuB,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAyB,CAAC;IACnC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,OAAO,iBAAiB;IAET,KAAK;IACL,SAAS;IAF5B,YACmB,KAAkB,EAClB,SAAS,GAAG,UAAU;qBADtB,KAAK;yBACL,SAAS;IACzB,CAAC;IAEI,OAAO,CAAC,MAAc,EAAE,QAAgB;QAC9C,OAAO,GAAG,IAAI,CAAC,SAAS,GAAG,MAAM,IAAI,QAAQ,EAAE,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,MAAc;QAClC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;QAC7D,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,KAAK,GAAG,iCAAiC,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CACb,sCAAsC,MAAM,CAAC,iCAAiC,CAAC,aAAa,CAC7F,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,MAMnB;QACC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC;QACpC,IAAI,CAAC,uBAAuB,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC3F,CAAC;QACD,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,IAAI,MAAM,CAAC,UAAU,GAAG,oBAAoB,EAAE,EAAE,CAAC;YAClF,MAAM,IAAI,KAAK,CACb,2DAA2D,MAAM,CAAC,oBAAoB,EAAE,CAAC,UAAU,CACpG,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAE1C,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvD,MAAM,MAAM,GAAuB;YACjC,QAAQ;YACR,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,IAAI;YACJ,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,MAAM,EAAE,SAAS;YACjB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QAEF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAC9B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EACrC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EACtB;YACE,EAAE,EAAE,yBAAyB;YAC7B,EAAE,EAAE,IAAI;SACT,CACF,CAAC;QACF,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC3D,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,SAAS,CACb,MAAc,EACd,QAAgB,EAChB,MAAc,EACd,QAAgB;QAEhB,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,MAAM,CAAC,MAAM,GAAG,oBAAoB,EAAE,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CACb,4CAA4C,MAAM,CAAC,oBAAoB,EAAE,CAAC,UAAU,CACrF,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACxD,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC9E,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,IAAI,OAAO,CAAC;QACtC,MAAM,YAAY,GAAG,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAChF,IAAI,CAAC,uBAAuB,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,MAAM,YAAY,EAAE,CAAC,CAAC;QACxF,CAAC;QAED,MAAM,MAAM,GAAuB;YACjC,GAAG,QAAQ;YACX,MAAM,EAAE,OAAO;YACf,QAAQ,EAAE,YAAY;YACtB,UAAU,EAAE,MAAM,CAAC,MAAM;YACzB,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;SACtC,CAAC;QAEF,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,yBAAyB,EAAE,CAAC,CAAC;QACrF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,QAAgB;QAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACxD,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC9E,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,KAAK,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;QAC3F,CAAC;QAED,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAE1B,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC1D,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAE/B,OAAO;YACL,MAAM;YACN,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,UAAU,EAAE,MAAM,CAAC,MAAM;YACzB,IAAI,EAAE,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC;SACvC,CAAC;IACJ,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,QAAQ,CAAC,MAAc,EAAE,QAAgB;QAC7C,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;QACnF,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC9E,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,KAAK,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;QAC3F,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC1D,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAC/B,OAAO;YACL,MAAM;YACN,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,UAAU,EAAE,MAAM,CAAC,MAAM;YACzB,IAAI,EAAE,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC;SACvC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,MAAc,EAAE,QAAgB;QAC9C,OAAO,WAAW,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC;CACF"}
@@ -1,9 +1,12 @@
1
+ import type { StagedUploadKind } from './mime.js';
1
2
  export type StagedUploadStatus = 'pending' | 'ready';
2
3
  export interface StagedUploadRecord {
3
4
  uploadId: string;
4
5
  userId: string;
5
6
  fileName: string;
6
7
  mimeType: string;
8
+ /** Default asset for records created before kind existed. */
9
+ kind?: StagedUploadKind;
7
10
  byteLength?: number;
8
11
  status: StagedUploadStatus;
9
12
  dataBase64?: string;
@@ -23,5 +26,6 @@ export interface StagedUploadConsumeResult {
23
26
  fileName: string;
24
27
  mimeType: string;
25
28
  byteLength: number;
29
+ kind: StagedUploadKind;
26
30
  }
27
31
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/staged-upload/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/staged-upload/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAElD,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,gBAAgB,CAAC;CACxB"}
@@ -17,7 +17,7 @@
17
17
  ## Prerequisites
18
18
 
19
19
  - Read `cms-edit://customer/pages` (or `articles`) and `cms-edit://customer/components-index`
20
- - `cms_edit ["schema", "htmlComponent"]` — use this space’s field IDs (`rawHtml` vs `htmlContent`, `customJs` vs `jsContent`). **`externalScripts` is the same field id on every space.**
20
+ - `cms_edit ["schema", "htmlComponent"]` — use this space’s field IDs (`rawHtml` vs `htmlContent`, `customJs` vs `jsContent`). **`externalScripts` is the same field id on every space.** If `schema` does **not** list `externalScripts`, **stop** and ask for Contentful migration 28 — do not stuff vendor/long JS into `customJs` (Contentful Text is ~50k characters).
21
21
  - Designer HTML / prototype available (file, paste, or Drive). **Do not** paste a multi-megabyte dump with `data:` URIs into Contentful.
22
22
  - For ordinary Google Doc / Figma-to-registered-stack briefs with no custom CSS/JS, use `task-create-from-document` instead.
23
23
 
@@ -77,7 +77,17 @@ cms_edit ["set", "@cN", "externalScripts", "--json", "[\"/html-components/featur
77
77
 
78
78
  On `create from-json`, put the same array under `fields.externalScripts`. Run `schema htmlComponent` first — unknown keys fail (`html` vs `htmlContent`).
79
79
 
80
- Then set HTML/CSS/JS with `--content` / `--content-base64` on `rawHtml`/`customCss`/`customJs` (or this space’s dual-write ids).
80
+ Then set HTML/CSS/JS. Hosted MCP **rejects** `--content` / `--content-base64` / `--json` over **8192 bytes**. Do not stub-create then patch. Write files on disk, then:
81
+
82
+ ```
83
+ cms_edit_request_staged_upload kind=text mimeType=text/html|text/css|text/javascript
84
+ # run curlCommand
85
+ cms_edit ["set", "@cN", "rawHtml", "--staged", "<id>"]
86
+ ```
87
+
88
+ Contentful Text fields themselves cap around **50k characters**. Put vendor/long JS in `externalScripts` (`/html-components/….js` in the site repo), not `customJs`.
89
+
90
+ `diff` prints bytes + sha256 + a 20-line head for long Text — not the full body. Confirm integrity with `["read", "@cN", "--hash"]` (full body only on `read` without `--hash`).
81
91
 
82
92
  ## Media first (mandatory)
83
93
 
@@ -101,9 +111,9 @@ Then set HTML/CSS/JS with `--content` / `--content-base64` on `rawHtml`/`customC
101
111
  3. Post a soft-proof (ordered stack + `externalScripts` URLs) and get a light human **yes**.
102
112
  4. Media pipeline: extract, upload, rewrite URLs.
103
113
  5. Create or open the page/article. Add registered components where decided.
104
- 6. For each HtmlComponent: `add htmlComponent` (or `create from-json --dry-run --strict` with this space’s field keys).
105
- 7. Set `externalScripts` with `--json`. Set HTML/CSS/JS. Set `cmsLabel`.
106
- 8. `diff` → `save` (draft).
114
+ 6. For each HtmlComponent: `add htmlComponent` (or `create from-json --staged` / `--dry-run --strict` with this space’s field keys). Do not put HTML/CSS/JS over 8k in `--json`.
115
+ 7. Set `externalScripts` with `--json`. Set HTML/CSS/JS via `--staged` when over 8k. Set `cmsLabel`.
116
+ 8. `diff` → `read --hash` → `save` (draft).
107
117
  9. `cms_edit ["preview", "urls", "<slug>"]` — follow `task-preview-verify`. Confirm libraries load (no `createElement('script')`, no dropped-URL warnings).
108
118
 
109
119
  ## Confirmation gates
@@ -23,9 +23,9 @@ After saving a draft, agents should return **all applicable URLs** and explain w
23
23
 
24
24
  | Target | Label | When to use |
25
25
  |--------|-------|-------------|
26
- | **contentfulLivePreview** | Live preview (publish here) | **Primary for editors when `url` is present.** Opens `app.contentful.com/.../entries/.../preview/...` — in-app preview with inspector. User clicks the green **Publish** button at the top to go live. If `url` is `null`, read `unavailableReason` / `notes` — do not invent a Live Preview link; use **staging** + **contentfulEntry** instead. |
27
- | **staging** | Preview (staging site) | Full-page check on staging, e.g. `{devBaseUrl}/resources/news/{tag}/{slug}/` (includes Vercel bypass params when configured). Always valid for draft visibility when staging is configured. |
28
- | **siteLivePreview** | Preview redirect | `{devBaseUrl}/preview?id={entryId}` — entry-aware redirect to the staging path. |
26
+ | **contentfulLivePreview** | Live preview (publish here) | **Primary for editors when `url` is present.** If `url` is `null` (often CMA 404), read `unavailableReason` — **not a failed save**. Do not invent a Live Preview link. |
27
+ | **staging** | Preview (staging site) | Full-page check on staging. **`showsDrafts` is false** unless that deployment is `DRAFT_ONLY`. Do not use this as the only check for draft-only pages. |
28
+ | **siteLivePreview** | Preview redirect | `{devBaseUrl}/preview?id={entryId}` — **`showsDrafts: true`**. Use this for draft-only pages. |
29
29
  | **production** | Production site | Published content only — compare after publish. |
30
30
  | **contentfulEntry** | Contentful entry editor | Classic entry form. Prefer **Live preview** when available; otherwise this is the publish path. |
31
31
 
@@ -43,8 +43,9 @@ After saving a draft, agents should return **all applicable URLs** and explain w
43
43
 
44
44
  2. **Hand off to the editor:**
45
45
  - **Live preview** — when `url` is non-null: reviewing the draft and publishing (green Publish button in Contentful).
46
- - **Preview (staging site)** — full-screen check on the staging deployment (always offer when available).
47
- - If Live Preview is unavailable, say so briefly using `unavailableReason` and point at staging + classic entry editor.
46
+ - **siteLivePreview** (`/preview?id=`) — **draft-only pages**.
47
+ - **Preview (staging site)** — full-screen check when `showsDrafts` is acceptable (published or `DRAFT_ONLY` host).
48
+ - If Live Preview is unavailable, say so briefly using `unavailableReason`; do not treat 404 as a failed job.
48
49
 
49
50
  3. Summarize what to check before publish handoff — use the checklist below (add multi-block items when relevant).
50
51
 
@@ -1,15 +1,17 @@
1
1
  # cms-edit create from-json — Complete Guide
2
2
 
3
- `create from-json` creates a complete new page or article — including all components, collections, and CTA links — from `--json` or `--json-base64`. It is the recommended way to create new pages on hosted MCP.
3
+ `create from-json` creates a complete new page or article — including all components, collections, and CTA links — from `--json`, `--json-base64`, or **`--staged`** (hosted). It is the recommended way to create new pages on hosted MCP.
4
4
 
5
- **Agents:** do not use a local `cms-edit` binary, `--file`, or stdin. Filesystem clients encode the file as `--json-base64`. Desktop clients pass `--json` in the `cms_edit` args array.
5
+ **Agents:** do not use a local `cms-edit` binary, `--file`, or stdin. **Fields over ~8k must not go through `--json` / `--json-base64` / `--content`.** Hosted MCP rejects those over 8192 bytes. Write the JSON on disk → `cms_edit_request_staged_upload` with `kind=json` → curl → `create from-json --staged <id> --dry-run --strict`. Dry-run peeks without consuming the slot.
6
6
 
7
- Also: `export from-json` (open session → same JSON with `existingId` / `version`) and `apply from-json` (validate, then update/create).
7
+ Also: `export from-json` (open session → same JSON with `existingId` / `version`) and `apply from-json` (`--staged` supported).
8
8
 
9
9
  ```
10
10
  cms_edit ["help", "create-from-json"]
11
11
  cms_edit_help { "topic": "create-from-json" }
12
12
  cms_edit ["create", "from-json", "--json", "{...}", "--dry-run", "--strict"]
13
+ # or, when the payload is over 8k:
14
+ cms_edit ["create", "from-json", "--staged", "<id>", "--dry-run", "--strict"]
13
15
  ```
14
16
 
15
17
  ## Validation traps (fail before CMA)
@@ -43,7 +45,8 @@ Run `cms-edit index sync` before using any `*AssetFilename` shorthand (index-bac
43
45
  // "page" (default) or "article". Auto-detected as "article" if articleTypeId is present.
44
46
  "type": "page",
45
47
 
46
- // Required. The URL slug. Leading slash is stripped automatically. Trailing slash triggers a warning.
48
+ // Required. The URL slug. A single leading slash is stripped silently (`/home` → `home`).
49
+ // Trailing or extra slashes still warn. Store CMS slugs without a leading slash.
47
50
  "slug": "/solutions/hepatology",
48
51
 
49
52
  // Required. The page title (also used as cmsLabel if cmsLabel is omitted).
@@ -40,12 +40,22 @@ Do **not** put libraries in HTML `<script>` tags or `createElement('script')` in
40
40
 
41
41
  ## Setting fields
42
42
 
43
- HTML/CSS/JS (long text):
43
+ HTML/CSS/JS (long text). Hosted MCP max **8192 bytes** inline — over that, staged upload:
44
+
45
+ ```
46
+ cms_edit_request_staged_upload { "fileName": "hero.js", "mimeType": "text/javascript", "kind": "text" }
47
+ # curlCommand
48
+ cms_edit ["set", "@cN", "customJs", "--staged", "<uploadId>"]
49
+ ```
50
+
51
+ Tiny snippets only:
44
52
 
45
53
  ```
46
54
  cms_edit ["set", "@cN", "rawHtml", "--content-base64", "<b64>"]
47
55
  ```
48
56
 
57
+ Contentful Text is ~**50k characters**. Confirm with `["read", "@cN", "--hash"]`. `diff` summarizes long fields (bytes, sha256, head).
58
+
49
59
  `externalScripts` is an array — **not** a scalar string. Scalar `set` is rejected.
50
60
 
51
61
  ```
@@ -86,7 +86,7 @@ cms-edit batch run --json '[...]'
86
86
  |---|---|
87
87
  | `open --page-slug <slug>` | Load a page into the session (see `help lookup`) |
88
88
  | `open --resume` | Re-print active session; **keeps** staged edits (no refetch) |
89
- | `open --overwrite …` | Replace session even if dirty (discards staged field edits) |
89
+ | `open --overwrite --confirm-discard …` | Replace session even if dirty (discards staged field edits) |
90
90
  | `set <ref\|id> <field> <value>` | Set field; bare entry IDs allowed mid-session |
91
91
  | `set <id>:field=value …` | Scalar multi-set by entry ID (stays on current session) |
92
92
  | `open --id <id>` | Load by Contentful entry ID |
@@ -35,7 +35,7 @@ cms-edit open --include-chrome --page-slug /solutions/hepatology
35
35
  | Situation | Command |
36
36
  |-----------|---------|
37
37
  | Session has unsaved changes, need tree again | `cms-edit open --resume` (no refetch; keeps staged edits) |
38
- | Intentionally abandon staged work and load another entry | `cms-edit open --overwrite --id <id>` (or `discard` then `open`) |
38
+ | Intentionally abandon staged work and load another entry | `cms-edit open --overwrite --confirm-discard --id <id>` (or `discard` then `open`) |
39
39
  | Plain `open` while dirty | **Hard fail** with remediation steps |
40
40
 
41
41
  ```bash
@@ -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` | Presigned URL for binaries. Raster/video: then `cms_edit_media` prepare. SVG/PDF/Lottie: then `asset upload --staged` |
23
+ | `cms_edit_request_staged_upload` | Presigned URL. `kind=asset` (default): binaries. `kind=text`: HtmlComponent fields then `set --staged`. `kind=json`: `create from-json --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-html-component`, `fields-component`, …) |
26
26
 
@@ -160,19 +160,22 @@ Full workflow: `cms-edit://customer/task-media-reuse-and-upload`.
160
160
  | Shared Drive folder has extra files | Import with `sourceNames` or `onlyWithOverrides` after catalog |
161
161
  | Prepare says no media / empty folder | Share folder **Viewer** with `media-pipeline-reader@se-media-pipeline.iam.gserviceaccount.com`, then re-prepare once |
162
162
  | MCP tool times out ~180s | `read` / `diff` / re-`catalog` before retrying the same write — server may already have saved |
163
- | `preview urls` has no Live Preview URL | Use staging + classic entry editor; row includes `unavailableReason` when CMA preview fails |
163
+ | `preview urls` has no Live Preview URL | Not a failed save. For **draft-only** pages use **siteLivePreview** (`/preview?id=`). Staging `showsDrafts` is false unless `DRAFT_ONLY`. |
164
164
  | Reuse-first import matches old fileNames | dry-run first; set `overrides[].fileName` for unique names when duplication is required |
165
165
 
166
166
  ### Staged upload
167
167
 
168
- Keeps binary **out of MCP tool args**. The agent uploads via `curl`, then passes only a short `uploadId`.
168
+ Keeps binary **and large text/JSON** out of MCP tool args. The agent uploads via `curl`, then passes only a short `uploadId`.
169
169
 
170
- 1. `cms_edit_request_staged_upload` with `fileName`, `mimeType`, optional `byteLength`, optional `title`
170
+ 1. `cms_edit_request_staged_upload` with `fileName`, `mimeType`, optional `kind` (`asset` \| `text` \| `json`), optional `byteLength`, optional `title`
171
171
  2. Run the returned `curlCommand` in a shell (POST multipart to `uploadUrl`)
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
172
+ 3. Follow `consumeArgs`:
173
+ - **asset:** media prepare for jpeg/png/webp/gif/mp4; **asset upload --staged** for SVG/PDF/Lottie
174
+ - **text:** `set @ref field --staged <id>` (insert ref and field id)
175
+ - **json:** `create from-json --staged <id>` (add `--dry-run --strict` first). Dry-run does not consume the slot.
173
176
  4. For pipeline jobs: wait → catalog → **import** (required for video). Then link and save
174
177
 
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.
178
+ Hosted **inline** `--json` / `--content` / `--*-base64` is capped at **8192 bytes**. Staged files: **4 MB**. Rate limit: **1000 upload URLs per user per hour**. TTL: **60 minutes**.
176
179
 
177
180
  ## Featured images (articles)
178
181
 
@@ -186,12 +189,11 @@ Run `["index", "sync"]` before resolving assets by filename.
186
189
 
187
190
  ## JSON payloads (filesystem vs no filesystem)
188
191
 
189
- Hosted MCP cannot see your disk. Same commands either way:
192
+ Hosted MCP cannot see your disk. **Do not** put 10–50k strings in `cms_edit` args.
190
193
 
191
- - **Filesystem client:** write `page.json`, then `cms_edit ["create", "from-json", "--json-base64", "<base64 of file>", "--dry-run", "--strict"]`
192
- - **No filesystem (Desktop):** put the JSON in `--json` on the tool call
193
-
194
- Never use a local `cms-edit` binary, `--file`, or stdin for content.
194
+ - **Over 8k:** write the file, `kind=json` or `kind=text`, curl, `--staged`
195
+ - **Tiny JSON only:** `--json` on the tool call
196
+ - Never `--file` or stdin for content
195
197
 
196
198
  ## Create content
197
199
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@se-studio/contentful-cms",
3
- "version": "3.10.3",
3
+ "version": "3.11.1",
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",
@@ -15,11 +15,11 @@ Use this skill when you need to read or edit content in Contentful using **hoste
15
15
 
16
16
  `cms-edit` lets you read and edit Contentful draft content without publishing.
17
17
 
18
- **New page/article:** `schema` for this space → `create from-json --dry-run --strict` → `create from-json` (`--json` or `--json-base64`). Nested tree key is `components`; discriminator is `type`.
18
+ **New page/article:** `schema` for this space → if the payload is over 8k, staged `kind=json` then `create from-json --staged --dry-run --strict` → create. Tiny JSON may use `--json`. Nested tree key is `components`; discriminator is `type`.
19
19
 
20
- **Edit a tree:** `open` → `export from-json` → edit JSON → `apply from-json`. Tiny patches: `set` / `rtf` / `add` then `diff` → `save`.
20
+ **Edit a tree:** `open` → `export from-json` → edit JSON → `apply from-json` (`--staged` when over 8k). Tiny patches: `set` / `rtf` / `add` then `diff` → `save`. Long HtmlComponent fields: `kind=text` then `set --staged`.
21
21
 
22
- **Never publish.** Hosted MCP cannot see your disk — send JSON in the tool call.
22
+ **Never publish.** Hosted MCP cannot see your disk — send JSON in the tool call **only if under 8192 bytes**.
23
23
 
24
24
  ## Safety Rules
25
25
 
@@ -33,6 +33,7 @@ All `save` operations create **draft** versions. A human must review and publish
33
33
  **Assets:** Upload **is** supported (`asset upload`). Default workflow: **search and reuse** existing assets first (`index sync` → `asset search`). When uploading:
34
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
35
  - **SVG/PDF/Lottie:** `cms_edit_request_staged_upload` → curl → `asset upload --staged` (never `--base64`)
36
+ - **HtmlComponent / large JSON:** `cms_edit_request_staged_upload` with `kind=text` or `kind=json` → curl → `set --staged`, `rtf --staged`, `create from-json --staged`, or `apply from-json --staged`. Hosted MCP rejects inline `--json`/`--content` over 8192 bytes.
36
37
  - Use a **sensible fileName** and **descriptive title** (and alt text where the site uses it)
37
38
  - Avoid oversized images — width over **2000px** is usually wasteful for web (exact limits vary by project; check `asset audit` / media review guidance)
38
39
  - Prefer `--if-exists-by-filename` to avoid duplicates