@ai-matrx/media 0.7.16 → 0.9.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 (191) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/files/engine/api/assets.d.ts +223 -0
  3. package/dist/files/engine/api/assets.js +124 -0
  4. package/dist/files/engine/api/assets.js.map +1 -0
  5. package/dist/files/engine/api/direct.d.ts +43 -0
  6. package/dist/files/engine/api/direct.js +73 -0
  7. package/dist/files/engine/api/direct.js.map +1 -0
  8. package/dist/files/engine/api/fileOrganization.d.ts +34 -0
  9. package/dist/files/engine/api/fileOrganization.js +38 -0
  10. package/dist/files/engine/api/fileOrganization.js.map +1 -0
  11. package/dist/files/engine/api/files.d.ts +249 -0
  12. package/dist/files/engine/api/files.js +231 -0
  13. package/dist/files/engine/api/files.js.map +1 -0
  14. package/dist/files/engine/api/folders.d.ts +63 -0
  15. package/dist/files/engine/api/folders.js +56 -0
  16. package/dist/files/engine/api/folders.js.map +1 -0
  17. package/dist/files/engine/api/office.d.ts +27 -0
  18. package/dist/files/engine/api/office.js +19 -0
  19. package/dist/files/engine/api/office.js.map +1 -0
  20. package/dist/files/engine/api/permissions.d.ts +37 -0
  21. package/dist/files/engine/api/permissions.js +109 -0
  22. package/dist/files/engine/api/permissions.js.map +1 -0
  23. package/dist/files/engine/api/versions.d.ts +26 -0
  24. package/dist/files/engine/api/versions.js +37 -0
  25. package/dist/files/engine/api/versions.js.map +1 -0
  26. package/dist/files/engine/cache/idb-store.d.ts +95 -0
  27. package/dist/files/engine/cache/idb-store.js +172 -0
  28. package/dist/files/engine/cache/idb-store.js.map +1 -0
  29. package/dist/files/engine/cache/policy.d.ts +14 -0
  30. package/dist/files/engine/cache/policy.js +40 -0
  31. package/dist/files/engine/cache/policy.js.map +1 -0
  32. package/dist/files/engine/cache/register-service-worker.d.ts +57 -0
  33. package/dist/files/engine/cache/register-service-worker.js +80 -0
  34. package/dist/files/engine/cache/register-service-worker.js.map +1 -0
  35. package/dist/files/engine/db-types.d.ts +48865 -0
  36. package/dist/files/engine/db-types.js +1 -0
  37. package/dist/files/engine/db-types.js.map +1 -0
  38. package/dist/files/engine/filesDb.d.ts +1913 -0
  39. package/dist/files/engine/filesDb.js +28 -0
  40. package/dist/files/engine/filesDb.js.map +1 -0
  41. package/dist/files/engine/handler/handler.d.ts +82 -0
  42. package/dist/files/engine/handler/handler.js +124 -0
  43. package/dist/files/engine/handler/handler.js.map +1 -0
  44. package/dist/files/engine/handler/hooks/useFile.d.ts +17 -0
  45. package/dist/files/engine/handler/hooks/useFile.js +75 -0
  46. package/dist/files/engine/handler/hooks/useFile.js.map +1 -0
  47. package/dist/files/engine/handler/hooks/useFileUpload.d.ts +76 -0
  48. package/dist/files/engine/handler/hooks/useFileUpload.js +67 -0
  49. package/dist/files/engine/handler/hooks/useFileUpload.js.map +1 -0
  50. package/dist/files/engine/handler/input/normalize.d.ts +14 -0
  51. package/dist/files/engine/handler/input/normalize.js +365 -0
  52. package/dist/files/engine/handler/input/normalize.js.map +1 -0
  53. package/dist/files/engine/handler/intelligence/access.d.ts +35 -0
  54. package/dist/files/engine/handler/intelligence/access.js +85 -0
  55. package/dist/files/engine/handler/intelligence/access.js.map +1 -0
  56. package/dist/files/engine/handler/intelligence/magic-bytes.d.ts +21 -0
  57. package/dist/files/engine/handler/intelligence/magic-bytes.js +67 -0
  58. package/dist/files/engine/handler/intelligence/magic-bytes.js.map +1 -0
  59. package/dist/files/engine/handler/output/target.d.ts +19 -0
  60. package/dist/files/engine/handler/output/target.js +222 -0
  61. package/dist/files/engine/handler/output/target.js.map +1 -0
  62. package/dist/files/engine/handler/resolver.d.ts +34 -0
  63. package/dist/files/engine/handler/resolver.js +133 -0
  64. package/dist/files/engine/handler/resolver.js.map +1 -0
  65. package/dist/files/engine/handler/types.d.ts +367 -0
  66. package/dist/files/engine/handler/types.js +1 -0
  67. package/dist/files/engine/handler/types.js.map +1 -0
  68. package/dist/files/engine/handler/upload.d.ts +32 -0
  69. package/dist/files/engine/handler/upload.js +295 -0
  70. package/dist/files/engine/handler/upload.js.map +1 -0
  71. package/dist/files/engine/handler/utils/classify.d.ts +14 -0
  72. package/dist/files/engine/handler/utils/classify.js +27 -0
  73. package/dist/files/engine/handler/utils/classify.js.map +1 -0
  74. package/dist/files/engine/handler/utils/prefer-locator.d.ts +32 -0
  75. package/dist/files/engine/handler/utils/prefer-locator.js +34 -0
  76. package/dist/files/engine/handler/utils/prefer-locator.js.map +1 -0
  77. package/dist/files/engine/handler/utils/python-base.d.ts +129 -0
  78. package/dist/files/engine/handler/utils/python-base.js +60 -0
  79. package/dist/files/engine/handler/utils/python-base.js.map +1 -0
  80. package/dist/files/engine/hooks/blob-cache.d.ts +130 -0
  81. package/dist/files/engine/hooks/blob-cache.js +162 -0
  82. package/dist/files/engine/hooks/blob-cache.js.map +1 -0
  83. package/dist/files/engine/hooks/office-extraction-cache.d.ts +28 -0
  84. package/dist/files/engine/hooks/office-extraction-cache.js +67 -0
  85. package/dist/files/engine/hooks/office-extraction-cache.js.map +1 -0
  86. package/dist/files/engine/host/configure.d.ts +166 -0
  87. package/dist/files/engine/host/configure.js +30 -0
  88. package/dist/files/engine/host/configure.js.map +1 -0
  89. package/dist/files/engine/host/org.d.ts +8 -0
  90. package/dist/files/engine/host/org.js +16 -0
  91. package/dist/files/engine/host/org.js.map +1 -0
  92. package/dist/files/engine/host/python-client.d.ts +60 -0
  93. package/dist/files/engine/host/python-client.js +46 -0
  94. package/dist/files/engine/host/python-client.js.map +1 -0
  95. package/dist/files/engine/host/share-links.d.ts +20 -0
  96. package/dist/files/engine/host/share-links.js +32 -0
  97. package/dist/files/engine/host/share-links.js.map +1 -0
  98. package/dist/files/engine/host/store.d.ts +24 -0
  99. package/dist/files/engine/host/store.js +23 -0
  100. package/dist/files/engine/host/store.js.map +1 -0
  101. package/dist/files/engine/host/supabase.d.ts +3808 -0
  102. package/dist/files/engine/host/supabase.js +33 -0
  103. package/dist/files/engine/host/supabase.js.map +1 -0
  104. package/dist/files/engine/host/toast.d.ts +14 -0
  105. package/dist/files/engine/host/toast.js +20 -0
  106. package/dist/files/engine/host/toast.js.map +1 -0
  107. package/dist/files/engine/host/typed-client.d.ts +136 -0
  108. package/dist/files/engine/host/typed-client.js +66 -0
  109. package/dist/files/engine/host/typed-client.js.map +1 -0
  110. package/dist/files/engine/index.d.ts +22 -0
  111. package/dist/files/engine/index.js +49 -0
  112. package/dist/files/engine/index.js.map +1 -0
  113. package/dist/files/engine/media/our-file-sources.d.ts +39 -0
  114. package/dist/files/engine/media/our-file-sources.js +83 -0
  115. package/dist/files/engine/media/our-file-sources.js.map +1 -0
  116. package/dist/files/engine/media/signed-url.d.ts +1 -0
  117. package/dist/files/engine/media/signed-url.js +6 -0
  118. package/dist/files/engine/media/signed-url.js.map +1 -0
  119. package/dist/files/engine/redux/converters.d.ts +73 -0
  120. package/dist/files/engine/redux/converters.js +286 -0
  121. package/dist/files/engine/redux/converters.js.map +1 -0
  122. package/dist/files/engine/redux/file-hydration.d.ts +15 -0
  123. package/dist/files/engine/redux/file-hydration.js +46 -0
  124. package/dist/files/engine/redux/file-hydration.js.map +1 -0
  125. package/dist/files/engine/redux/file-tree-auth-boundary.d.ts +5 -0
  126. package/dist/files/engine/redux/file-tree-auth-boundary.js +28 -0
  127. package/dist/files/engine/redux/file-tree-auth-boundary.js.map +1 -0
  128. package/dist/files/engine/redux/file-tree-timeout.d.ts +32 -0
  129. package/dist/files/engine/redux/file-tree-timeout.js +73 -0
  130. package/dist/files/engine/redux/file-tree-timeout.js.map +1 -0
  131. package/dist/files/engine/redux/mutation-toast-middleware.d.ts +27 -0
  132. package/dist/files/engine/redux/mutation-toast-middleware.js +103 -0
  133. package/dist/files/engine/redux/mutation-toast-middleware.js.map +1 -0
  134. package/dist/files/engine/redux/realtime-middleware.d.ts +61 -0
  135. package/dist/files/engine/redux/realtime-middleware.js +431 -0
  136. package/dist/files/engine/redux/realtime-middleware.js.map +1 -0
  137. package/dist/files/engine/redux/request-ledger.d.ts +68 -0
  138. package/dist/files/engine/redux/request-ledger.js +66 -0
  139. package/dist/files/engine/redux/request-ledger.js.map +1 -0
  140. package/dist/files/engine/redux/selectors.d.ts +3254 -0
  141. package/dist/files/engine/redux/selectors.js +428 -0
  142. package/dist/files/engine/redux/selectors.js.map +1 -0
  143. package/dist/files/engine/redux/slice.d.ts +157 -0
  144. package/dist/files/engine/redux/slice.js +836 -0
  145. package/dist/files/engine/redux/slice.js.map +1 -0
  146. package/dist/files/engine/redux/thunks.d.ts +449 -0
  147. package/dist/files/engine/redux/thunks.js +1684 -0
  148. package/dist/files/engine/redux/thunks.js.map +1 -0
  149. package/dist/files/engine/redux/tree-utils.d.ts +90 -0
  150. package/dist/files/engine/redux/tree-utils.js +200 -0
  151. package/dist/files/engine/redux/tree-utils.js.map +1 -0
  152. package/dist/files/engine/support/claimsUser.d.ts +77 -0
  153. package/dist/files/engine/support/claimsUser.js +48 -0
  154. package/dist/files/engine/support/claimsUser.js.map +1 -0
  155. package/dist/files/engine/support/datetime.d.ts +6 -0
  156. package/dist/files/engine/support/datetime.js +15 -0
  157. package/dist/files/engine/support/datetime.js.map +1 -0
  158. package/dist/files/engine/support/document-visibility.d.ts +14 -0
  159. package/dist/files/engine/support/document-visibility.js +28 -0
  160. package/dist/files/engine/support/document-visibility.js.map +1 -0
  161. package/dist/files/engine/support/logger.d.ts +28 -0
  162. package/dist/files/engine/support/logger.js +36 -0
  163. package/dist/files/engine/support/logger.js.map +1 -0
  164. package/dist/files/engine/types.d.ts +1081 -0
  165. package/dist/files/engine/types.js +30 -0
  166. package/dist/files/engine/types.js.map +1 -0
  167. package/dist/files/engine/upload/cloudUpload.d.ts +182 -0
  168. package/dist/files/engine/upload/cloudUpload.js +418 -0
  169. package/dist/files/engine/upload/cloudUpload.js.map +1 -0
  170. package/dist/files/engine/upload/tusUpload.d.ts +100 -0
  171. package/dist/files/engine/upload/tusUpload.js +258 -0
  172. package/dist/files/engine/upload/tusUpload.js.map +1 -0
  173. package/dist/files/engine/upload/uploadDedupGuard.d.ts +58 -0
  174. package/dist/files/engine/upload/uploadDedupGuard.js +41 -0
  175. package/dist/files/engine/upload/uploadDedupGuard.js.map +1 -0
  176. package/dist/files/engine/upload/uploadGuardOpeners.d.ts +70 -0
  177. package/dist/files/engine/upload/uploadGuardOpeners.js +54 -0
  178. package/dist/files/engine/upload/uploadGuardOpeners.js.map +1 -0
  179. package/dist/files/engine/utils/file-types.d.ts +243 -0
  180. package/dist/files/engine/utils/file-types.js +1722 -0
  181. package/dist/files/engine/utils/file-types.js.map +1 -0
  182. package/dist/files/engine/utils/user-visible.d.ts +133 -0
  183. package/dist/files/engine/utils/user-visible.js +115 -0
  184. package/dist/files/engine/utils/user-visible.js.map +1 -0
  185. package/dist/files.cjs +1298 -0
  186. package/dist/files.cjs.map +1 -0
  187. package/dist/files.d.cts +1171 -0
  188. package/dist/files.d.ts +1171 -0
  189. package/dist/files.js +1275 -0
  190. package/dist/files.js.map +1 -0
  191. package/package.json +404 -9
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/files.ts","../src/files/ref-types.ts","../src/files/blocks/types.ts","../src/files/blocks/guards.ts","../src/files/blocks/image/guards.ts","../src/files/blocks/adapters/from-cx-av-part.ts","../src/files/blocks/adapters/from-media-block.ts","../src/files/blocks/adapters/from-media-ref.ts","../src/files/blocks/image/helpers/extract-file-id-from-url.ts","../src/files/blocks/image/helpers/parse-filename-from-url.ts","../src/files/blocks/image/adapters/from-image-output-data.ts","../src/files/blocks/image/adapters/from-cx-media-part.ts","../src/files/blocks/image/adapters/from-partial-image-data.ts","../src/files/blocks/image/adapters/from-render-block.ts","../src/files/blocks/image/adapters/to-cx-media-part.ts","../src/files/blocks/image/helpers/derive-viewer-url.ts","../src/react/cn.ts","../src/files/media/video-date.ts","../src/files/blocks/video/VideoPublishDate.tsx","../src/files/handler/errors.ts","../src/files/utils/folder-conventions.ts","../src/files/handler/utils/upload-folder-path.ts","../src/files/media/object-url-registry.ts"],"sourcesContent":["/**\n * `@ai-matrx/media/files` — the Matrx file vocabulary every client shares (P16f):\n * the wire `MediaRef` and file visibility, the platform media-block union with its\n * guards and wire adapters (cx parts, image output, render blocks, media blocks),\n * the canonical folder conventions, upload errors, the video publish date, and the\n * object-URL registry. Pure data and one hook-free component; no store, no transport.\n * Moved verbatim from matrx-frontend `features/files` + `lib/media`.\n */\n\nexport * from \"./files/ref-types\";\nexport * from \"./files/blocks/types\";\nexport * from \"./files/blocks/guards\";\nexport type { UnifiedImageBlock } from \"./files/blocks/image/types\";\nexport { isUnifiedImageBlock } from \"./files/blocks/image/guards\";\nexport * from \"./files/blocks/adapters/from-cx-av-part\";\nexport * from \"./files/blocks/adapters/from-media-block\";\nexport * from \"./files/blocks/adapters/from-media-ref\";\nexport * from \"./files/blocks/image/adapters/from-cx-media-part\";\nexport * from \"./files/blocks/image/adapters/from-image-output-data\";\nexport * from \"./files/blocks/image/adapters/from-partial-image-data\";\nexport * from \"./files/blocks/image/adapters/from-render-block\";\nexport * from \"./files/blocks/image/adapters/to-cx-media-part\";\nexport * from \"./files/blocks/image/helpers/derive-viewer-url\";\nexport * from \"./files/blocks/image/helpers/extract-file-id-from-url\";\nexport * from \"./files/blocks/image/helpers/parse-filename-from-url\";\nexport * from \"./files/blocks/video/VideoPublishDate\";\nexport * from \"./files/handler/errors\";\nexport * from \"./files/handler/utils/upload-folder-path\";\nexport * from \"./files/utils/folder-conventions\";\nexport * from \"./files/media/video-date\";\nexport * from \"./files/media/object-url-registry\";\n","/**\n * files/ref-types — the Matrx file reference vocabulary shared by every client:\n * visibility, permission level, the wire `MediaRef`, and the identity hint a caller\n * may already know. Moved from matrx-frontend `features/files/types.ts` (P16f).\n */\n\nexport type Visibility = \"personal\" | \"internal\" | \"link\" | \"public\";\nexport type PermissionLevel = \"read\" | \"write\" | \"admin\";\n\n\n// ---------------------------------------------------------------------------\n// 1b. MediaRef — canonical reference shape for AI API content blocks\n// ---------------------------------------------------------------------------\n//\n// Mirrors the Python backend's `MediaRef` schema verbatim. Every outbound\n// `image` / `audio` / `video` / `document` content block on the AI APIs\n// (`/ai/agents/{id}`, `/ai/conversations/{id}`, `/ai/chat`, `/ai/manual`,\n// etc.) carries one of these as the file identifier.\n//\n// Backend Pydantic:\n// class MediaRef(BaseModel):\n// file_id: str | None = None # cld_files UUID — preferred\n// url: str | None = None # any URL we issued OR external https://\n// mime_type: str | None = None\n// metadata: dict[str, Any] = Field(default_factory=dict)\n//\n// Exactly ONE of `file_id` / `url` SHOULD be set, in that preference order.\n// Sending both is allowed but the backend resolves them in the same\n// priority — `file_id` wins, then `url`. Native storage locations\n// (`s3://...`) are server-only and never appear on the client.\n//\n// Use the builders below (and the app's `cloudFileToMediaRef` for a stored file):\n// - `fileIdToMediaRef(id, mime?)` — when only the id is known\n// - `urlToMediaRef(url, mime?)` — for external public URLs\n//\n// **Don't hand-build MediaRefs at callsites.** The builders make sure we\n// never accidentally drift from this contract.\nexport interface MediaRef {\n /** cld_files UUID — preferred form for any file we own. */\n file_id?: string;\n /** Any URL we issued (durable download route, share link) OR external https://. */\n url?: string;\n /** Optional client hint; backend overrides with `cld_files.mime_type` for owned files. */\n mime_type?: string;\n /** Free-form per-call metadata. Keep small — this rides on every request. */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Metadata a caller may already know when all it has is a durable file id.\n * These values seed the canonical Redux record before field hydration runs;\n * omitted keys remain genuinely unloaded and are fetched on demand.\n */\nexport interface FileIdentityHint {\n fileName?: string;\n mimeType?: string | null;\n fileSize?: number | null;\n visibility?: Visibility;\n /** Permanent public delivery only. Never place a signed URL here. */\n publicUrl?: string | null;\n /** Permanent public CDN delivery only. Never place a signed URL here. */\n cdnUrl?: string | null;\n}\n\n\n/** Reads a stored visibility; anything unknown is the private default. */\nexport function toVisibility(raw: string | null | undefined): Visibility {\n if (raw === \"public\") return \"public\";\n if (raw === \"link\") return \"link\";\n if (raw === \"internal\") return \"internal\";\n return \"personal\";\n}\n\n/**\n * Build a MediaRef from just a `file_id` (e.g. when an upload completes\n * and the caller has the id but not the full record yet).\n */\nexport function fileIdToMediaRef(\n fileId: string,\n mimeType?: string | null,\n): MediaRef {\n const ref: MediaRef = { file_id: fileId };\n if (mimeType) ref.mime_type = mimeType;\n return ref;\n}\n\n/**\n * Build a MediaRef from an external URL (public website image, signed URL\n * we don't own, etc.). Use this ONLY when you don't have a `file_id` —\n * otherwise the backend has to follow the URL to resolve the file.\n */\nexport function urlToMediaRef(url: string, mimeType?: string | null): MediaRef {\n const ref: MediaRef = { url };\n if (mimeType) ref.mime_type = mimeType;\n return ref;\n}\n","/**\n * features/files/blocks/types.ts\n *\n * THE canonical TypeScript shape for every piece of media (image / video /\n * audio / document / youtube) in the app — the FE mirror of Python's\n * `UnifiedMediaBlock` Pydantic union. See:\n * - docs/PYTHON_UPDATES.md — Phase 0/1/2 wire contract & migration plan\n * - features/files/blocks/image/UNIFIED_IMAGE_BLOCK.md — backstory\n * - packages/matrx-connect/matrx_connect/context/media_block.py (backend)\n *\n * Naming convention:\n * - This file uses **camelCase** (TS domain shape).\n * - The wire shape (`MediaBlockData.block` in stream events,\n * `cld_files.metadata.generation` on assets) uses **snake_case**.\n * - The adapter `./adapters/from-media-block.ts` converts the wire shape\n * to this shape at the boundary. Components only ever see camelCase.\n *\n * Two discriminators:\n * - `kind` : \"image\" | \"video\" | \"audio\" | \"document\" | \"youtube\"\n * Narrow on this first to access kind-specific fields\n * (e.g. `width`/`height` on image, `durationMs` on audio).\n * - `origin` : \"matrx\" | \"external\"\n * Narrow on this second to access ownership-specific fields\n * (`fileId` on matrx, `externalUrl` on external).\n *\n * Invariants (enforced at adapter boundary):\n * 1. `origin === \"matrx\"` → `fileId` non-null when `status === \"complete\"`.\n * 2. `origin === \"external\"` → `externalUrl` non-null OR `base64` non-null.\n * 3. `status === \"streaming\"` → `base64` non-null (in-flight bytes).\n * 4. `status === \"error\"` → `errorMessage` non-null.\n */\n\n// ─── Discriminator alphabets ────────────────────────────────────────────────\n\nexport type MediaKind = \"image\" | \"video\" | \"audio\" | \"document\" | \"youtube\";\nexport type MediaOrigin = \"matrx\" | \"external\";\nexport type MediaStatus = \"complete\" | \"streaming\" | \"error\";\n/**\n * THE canonical `platform.visibility` enum — identical to\n * `features/files/types.ts#Visibility`, the DB, and the server. This used to\n * be its own dialect (`public | personal | shared`), which is how `internal`\n * and `link` rows got mis-bucketed on the way to URL resolution.\n */\nexport type MediaVisibility = \"personal\" | \"internal\" | \"link\" | \"public\";\n\n// ─── Cross-cutting base (every block carries these) ─────────────────────────\n\ninterface MediaBlockBase {\n /**\n * \"complete\" — final media; all configured URLs are valid as of emission\n * \"streaming\" — generating; `base64` (partial preview) is the only render source\n * \"error\" — generation failed; `errorMessage` carries the reason\n */\n status: MediaStatus;\n /** 0–1 progress. Meaningful only when status === \"streaming\". */\n progress: number | null;\n /** Populated when status === \"error\". null otherwise. */\n errorMessage: string | null;\n\n // ── Bytes-level metadata ─────────────────────────────────────────────────\n /** Canonical MIME `type/subtype`. */\n mimeType: string | null;\n /** Display name (often AI-generated for ai-produced media). */\n fileName: string | null;\n /**\n * File size in bytes (renamed from `file_size` in Phase 0 — see\n * docs/PYTHON_UPDATES.md §3). null when unknown (typical for streaming\n * partials and pre-finalize states).\n */\n sizeBytes: number | null;\n /**\n * Inline base64 bytes. Used for streaming partials and tiny inline assets.\n * Cleared once `status === \"complete\"` and a URL is available.\n */\n base64: string | null;\n\n /**\n * Free-form. Phase 2 stamps `metadata.generation` (typed as\n * `MediaGenerationMetadata` below) for any AI-generated asset.\n * Existing top-level keys (`model`, `provider`, `prompt`, `cost`) are\n * preserved for back-compat — new code should read `metadata.generation`.\n */\n metadata: Record<string, unknown> | null;\n\n /**\n * The reference role this media played as an INPUT (subject, style,\n * first_frame, extend, …) and its `@name`, carried from the persisted\n * part so a reload redisplays it. Absent for generated output.\n */\n referenceRole?: string | null;\n referenceName?: string | null;\n}\n\n// ─── Origin halves (cross-cut every kind) ───────────────────────────────────\n\n/**\n * Fields present on every matrx-owned (cld_files-backed) media block.\n * `fileId` is the permanent identity the URL resolver re-mints from on\n * expiry (via fileHandler). Native storage locations are server-only and\n * never appear on the client.\n */\ninterface MatrxOriginFields {\n origin: \"matrx\";\n\n /** cld_files.id — the permanent identity. */\n fileId: string;\n /**\n * cld_files.visibility — drives URL resolution:\n * \"public\" — prefer cdnUrl; permanent URL, no auth required\n * everything else (\"personal\" / \"internal\" / \"link\") — render through\n * the durable authenticated URL (`fileUrls(fileId).inline`), which the\n * browser authenticates via the `mx_files_session` cookie\n */\n visibility: MediaVisibility;\n\n // ── URL flavors. Resolver picks the best at render time. ─────────────────\n /** Permanent CDN URL — no expiry, no auth required. */\n cdnUrl: string | null;\n /** Durable attachment-disposition variant. Used for the download action. */\n downloadUrl: string | null;\n\n // ── Lineage hints ────────────────────────────────────────────────────────\n /** cld_files.parent_file_id — derivation lineage. */\n parentFileId: string | null;\n /**\n * cld_files.derivation_kind — how this was produced from `parentFileId`.\n * E.g. \"manual_upload\", \"extracted_pages\", \"cropped\", \"rendered_page_image\".\n */\n derivationKind: string | null;\n\n // ── Thumbnails ───────────────────────────────────────────────────────────\n // Phase 1b removed `thumbnail_url` + `thumbnail_uri` from the wire shape.\n // The canonical source is now `Asset.variants[\"thumbnail_url\"].url` via\n // `GET /assets/{file_id}`. See docs/PYTHON_UPDATES.md \"Phase 1b\".\n //\n // For TOP-LEVEL listings, `FileRecord.thumbnail_url` (one field on the\n // REST response) is still populated by the backend resolver and lifts\n // onto `CloudFile.thumbnailUrl` for grid / picker components. That field\n // lives on `CloudFile`, not on the media block — a block represents an\n // image you're rendering, not a generic file listing.\n}\n\n/**\n * Fields present on every external (third-party / user-pasted) media block.\n * We never refresh these and never try to mint fresh URLs.\n */\ninterface ExternalOriginFields {\n origin: \"external\";\n /** The external URL. Always present — empty string fallback means broken. */\n externalUrl: string;\n /** Optional provenance label — e.g. \"Wikimedia\", \"Tool: web_search\". */\n sourceLabel: string | null;\n}\n\n// ─── Kind-specific fields ───────────────────────────────────────────────────\n\ninterface ImageKindFields {\n kind: \"image\";\n /** Pixel width. Null when unknown / pre-finalize. */\n width: number | null;\n /** Pixel height. Null when unknown / pre-finalize. */\n height: number | null;\n /**\n * Optional content-class hint from vision models — e.g. \"photograph\",\n * \"diagram\", \"ui-screenshot\". Free-form; consumers should treat as a UI\n * hint only.\n */\n visionClass: string | null;\n}\n\ninterface VideoKindFields {\n kind: \"video\";\n width: number | null;\n height: number | null;\n /** Duration in milliseconds. */\n durationMs: number | null;\n /**\n * Poster/cover frame URL (extracted at ~10% of timeline). Phase 1\n * populates this for matrx-owned videos via `Asset.variants[\"poster_url\"]`.\n */\n posterUrl: string | null;\n}\n\ninterface AudioKindFields {\n kind: \"audio\";\n /** Duration in milliseconds. */\n durationMs: number | null;\n /**\n * Inline transcript text when present. Long-form transcripts go in a\n * separate processed_documents row; this carries the short-form summary\n * or null.\n */\n transcript: string | null;\n}\n\ninterface DocumentKindFields {\n kind: \"document\";\n /** Page count for paginated documents (PDF, DOCX, …). null otherwise. */\n pageCount: number | null;\n /**\n * Page-1 preview rendered to image. Phase 1 populates this for PDFs.\n * Useful when displaying an inline document chip.\n */\n page1Url: string | null;\n}\n\ninterface YouTubeKindFields {\n kind: \"youtube\";\n /** Extracted YouTube video id (the `?v=` token). */\n videoId: string | null;\n}\n\n// ─── Cross-product variants (kind × origin) ─────────────────────────────────\n// Each kind has matrx + external variants so consumers can narrow on either\n// discriminator. YouTube is always external (no FE upload path).\n\nexport type MatrxImageBlock = MediaBlockBase &\n MatrxOriginFields &\n ImageKindFields;\nexport type ExternalImageBlock = MediaBlockBase &\n ExternalOriginFields &\n ImageKindFields;\nexport type ImageBlock = MatrxImageBlock | ExternalImageBlock;\n\nexport type MatrxVideoBlock = MediaBlockBase &\n MatrxOriginFields &\n VideoKindFields;\nexport type ExternalVideoBlock = MediaBlockBase &\n ExternalOriginFields &\n VideoKindFields;\nexport type VideoBlock = MatrxVideoBlock | ExternalVideoBlock;\n\nexport type MatrxAudioBlock = MediaBlockBase &\n MatrxOriginFields &\n AudioKindFields;\nexport type ExternalAudioBlock = MediaBlockBase &\n ExternalOriginFields &\n AudioKindFields;\nexport type AudioBlock = MatrxAudioBlock | ExternalAudioBlock;\n\nexport type MatrxDocumentBlock = MediaBlockBase &\n MatrxOriginFields &\n DocumentKindFields;\nexport type ExternalDocumentBlock = MediaBlockBase &\n ExternalOriginFields &\n DocumentKindFields;\nexport type DocumentBlock = MatrxDocumentBlock | ExternalDocumentBlock;\n\n/** YouTube is always external per the Python contract. */\nexport type YouTubeBlock = MediaBlockBase &\n ExternalOriginFields &\n YouTubeKindFields;\n\n/**\n * The unified discriminated union for every media reference in the app.\n *\n * Narrowing recipe:\n * if (block.kind === \"image\") {\n * if (block.origin === \"matrx\") {\n * // block.fileId, block.visibility, block.cdnUrl, ...\n * } else {\n * // block.externalUrl, block.sourceLabel\n * }\n * // block.width, block.height (image-specific)\n * }\n */\nexport type UnifiedMediaBlock =\n | ImageBlock\n | VideoBlock\n | AudioBlock\n | DocumentBlock\n | YouTubeBlock;\n\n// ─── Generation metadata (Phase 2 contract) ─────────────────────────────────\n//\n// Provider-agnostic shape stamped onto `metadata.generation` for every\n// AI-generated media file. Read directly from `block.metadata?.generation`.\n//\n// Field names are camelCase here (domain shape); the wire shape uses\n// snake_case. See `MediaGenerationMetadataWire` below for the raw wire\n// shape and the FE convenience converter `parseGenerationMetadata`.\n\nexport type MediaGenerationKind =\n | \"image\"\n | \"video\"\n | \"audio\"\n | \"speech\"\n | \"music\";\n\nexport interface MediaGenerationMetadata {\n // ── Identity ────────────────────────────────────────────────────────────\n kind: MediaGenerationKind;\n provider: string;\n model: string;\n\n // ── Request ─────────────────────────────────────────────────────────────\n prompt: string;\n negativePrompt: string | null;\n /**\n * Provider's rewrite of the user's prompt (OpenAI's `revised_prompt`).\n * Surface to the user — improves transparency and trust.\n */\n revisedPrompt: string | null;\n\n // ── Output shape (normalized across providers) ──────────────────────────\n width: number | null;\n height: number | null;\n /** Free-form, e.g. \"16:9\", \"1:1\", \"9:16\". */\n aspectRatio: string | null;\n durationSeconds: number | null;\n\n // ── Generation knobs (provider support varies) ──────────────────────────\n quality: string | null;\n style: string | null;\n seed: number | null;\n steps: number | null;\n cfgScale: number | null;\n nRequested: number;\n nReturned: number;\n\n // ── Operational ─────────────────────────────────────────────────────────\n responseId: string | null;\n durationMs: number | null;\n costUsd: number | null;\n /** E.g. \"completed\", \"content_filter\", \"error\". */\n finishReason: string | null;\n safetyFlagged: boolean;\n\n /** Catch-all for provider-native fields we haven't canonicalized yet. */\n providerExtras: Record<string, unknown>;\n}\n\n/**\n * Wire shape (snake_case) as Python emits it. Adapters read this; consumers\n * generally don't.\n */\nexport interface MediaGenerationMetadataWire {\n kind: MediaGenerationKind;\n provider: string;\n model: string;\n prompt: string;\n negative_prompt?: string | null;\n revised_prompt?: string | null;\n width?: number | null;\n height?: number | null;\n aspect_ratio?: string | null;\n duration_seconds?: number | null;\n quality?: string | null;\n style?: string | null;\n seed?: number | null;\n steps?: number | null;\n cfg_scale?: number | null;\n n_requested?: number;\n n_returned?: number;\n response_id?: string | null;\n duration_ms?: number | null;\n cost_usd?: number | null;\n finish_reason?: string | null;\n safety_flagged?: boolean;\n provider_extras?: Record<string, unknown>;\n}\n\n/**\n * Pull the typed `MediaGenerationMetadata` out of a block's free-form\n * metadata bag. Returns null when no `generation` key is present.\n *\n * Usage:\n * const gen = parseGenerationMetadata(block.metadata);\n * if (gen?.revisedPrompt) { renderRevisedPromptBanner(gen.revisedPrompt); }\n */\nexport function parseGenerationMetadata(\n metadata: Record<string, unknown> | null | undefined,\n): MediaGenerationMetadata | null {\n if (!metadata) return null;\n const raw = metadata.generation;\n if (!raw || typeof raw !== \"object\") return null;\n const w = raw as MediaGenerationMetadataWire;\n if (typeof w.kind !== \"string\") return null;\n if (typeof w.provider !== \"string\") return null;\n if (typeof w.model !== \"string\") return null;\n if (typeof w.prompt !== \"string\") return null;\n return {\n kind: w.kind,\n provider: w.provider,\n model: w.model,\n prompt: w.prompt,\n negativePrompt: w.negative_prompt ?? null,\n revisedPrompt: w.revised_prompt ?? null,\n width: w.width ?? null,\n height: w.height ?? null,\n aspectRatio: w.aspect_ratio ?? null,\n durationSeconds: w.duration_seconds ?? null,\n quality: w.quality ?? null,\n style: w.style ?? null,\n seed: w.seed ?? null,\n steps: w.steps ?? null,\n cfgScale: w.cfg_scale ?? null,\n nRequested: w.n_requested ?? 1,\n nReturned: w.n_returned ?? 1,\n responseId: w.response_id ?? null,\n durationMs: w.duration_ms ?? null,\n costUsd: w.cost_usd ?? null,\n finishReason: w.finish_reason ?? null,\n safetyFlagged: w.safety_flagged ?? false,\n providerExtras: w.provider_extras ?? {},\n };\n}\n","/**\n * features/files/blocks/guards.ts\n *\n * Runtime type guards for `UnifiedMediaBlock` and its variants. Used at\n * trust boundaries (Redux reads, adapter inputs) to prove the shape\n * rather than force-cast.\n *\n * All guards accept `unknown` so they're safe to use against raw\n * `Record<string, unknown>` data (e.g. `block.data` on a render-block\n * envelope, `block.metadata` on a free-form bag).\n */\n\nimport type {\n AudioBlock,\n DocumentBlock,\n ExternalImageBlock,\n ImageBlock,\n MatrxImageBlock,\n UnifiedMediaBlock,\n VideoBlock,\n YouTubeBlock,\n} from \"./types\";\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\";\n}\n\n// ─── Discriminator probes ───────────────────────────────────────────────────\n\nfunction hasMediaShape(value: unknown): value is Record<string, unknown> {\n if (!isObject(value)) return false;\n if (typeof value.kind !== \"string\") return false;\n if (value.origin !== \"matrx\" && value.origin !== \"external\") return false;\n return true;\n}\n\n// ─── Origin guards (kind-agnostic) ──────────────────────────────────────────\n\nexport function isMatrxMediaBlock(\n value: unknown,\n): value is Extract<UnifiedMediaBlock, { origin: \"matrx\" }> {\n if (!hasMediaShape(value)) return false;\n if (value.origin !== \"matrx\") return false;\n return typeof value.fileId === \"string\";\n}\n\nexport function isExternalMediaBlock(\n value: unknown,\n): value is Extract<UnifiedMediaBlock, { origin: \"external\" }> {\n if (!hasMediaShape(value)) return false;\n if (value.origin !== \"external\") return false;\n return typeof value.externalUrl === \"string\";\n}\n\nexport function isUnifiedMediaBlock(\n value: unknown,\n): value is UnifiedMediaBlock {\n return isMatrxMediaBlock(value) || isExternalMediaBlock(value);\n}\n\n// ─── Kind guards ────────────────────────────────────────────────────────────\n\nexport function isImageBlock(value: unknown): value is ImageBlock {\n return isUnifiedMediaBlock(value) && value.kind === \"image\";\n}\n\nexport function isVideoBlock(value: unknown): value is VideoBlock {\n return isUnifiedMediaBlock(value) && value.kind === \"video\";\n}\n\nexport function isAudioBlock(value: unknown): value is AudioBlock {\n return isUnifiedMediaBlock(value) && value.kind === \"audio\";\n}\n\nexport function isDocumentBlock(value: unknown): value is DocumentBlock {\n return isUnifiedMediaBlock(value) && value.kind === \"document\";\n}\n\nexport function isYouTubeBlock(value: unknown): value is YouTubeBlock {\n return isUnifiedMediaBlock(value) && value.kind === \"youtube\";\n}\n\n// ─── Cross-product guards for ergonomic narrowing ───────────────────────────\n\nexport function isMatrxImageBlock(value: unknown): value is MatrxImageBlock {\n return isImageBlock(value) && value.origin === \"matrx\";\n}\n\nexport function isExternalImageBlock(\n value: unknown,\n): value is ExternalImageBlock {\n return isImageBlock(value) && value.origin === \"external\";\n}\n","/**\n * features/files/blocks/image/guards.ts\n *\n * Image-specific runtime guards. Re-exported from the canonical guards in\n * `../guards.ts`. New code should prefer importing from there directly.\n *\n * Usage:\n *\n * if (!isUnifiedImageBlock(block.data)) return null;\n * // block.data is now narrowed to ImageBlock (kind: \"image\")\n * // by TypeScript.\n *\n * These guards check BOTH `kind === \"image\"` and the origin discriminator,\n * so a stray video/audio/document block will NOT pass through them.\n */\n\nexport { isMatrxImageBlock, isExternalImageBlock } from \"../guards\";\n\nimport { isImageBlock } from \"../guards\";\nimport type { UnifiedImageBlock } from \"./types\";\n\n/**\n * Back-compat alias for `isImageBlock` — narrows to `UnifiedImageBlock`\n * (a.k.a. the `kind: \"image\"` variant of `UnifiedMediaBlock`).\n */\nexport function isUnifiedImageBlock(\n value: unknown,\n): value is UnifiedImageBlock {\n return isImageBlock(value);\n}\n","/**\n * features/files/blocks/adapters/from-cx-av-part.ts\n *\n * Convert a DB-stored `cx_message.content[]` media part (kind: \"audio\" |\n * \"video\") into the `AudioOutputData` / `VideoOutputData` render-block payload\n * the chat media renderers consume.\n *\n * This is the audio/video twin of the image adapter\n * (`../image/adapters/from-cx-media-part.ts`) and exists for the same reason:\n * **media identity is the `file_id`, never a URL.** The stored `url` is\n * whatever happened to be visible at save time (legacy rows: a long-dead\n * signed S3 URL). `file_id` is what lets `buildMediaSource` → `useFileSrc`\n * resolve the durable URL on every render.\n *\n * `file_id` lives at the TOP LEVEL of the stored media part (and is sometimes\n * mirrored into `metadata`); the URL flavors are dumped into `metadata`. Both\n * are lifted back out here so the round-trip is lossless.\n */\n\nimport type {\n AudioMediaPart,\n AudioOutputData,\n VideoMediaPart,\n VideoOutputData,\n} from \"@ai-matrx/agents/generated/stream-events\";\n\nfunction str(v: unknown): string | null {\n return typeof v === \"string\" && v.length > 0 ? v : null;\n}\n\ninterface LiftedUrls {\n url: string;\n file_id: string | null;\n cdn_url: string | null;\n download_url: string | null;\n}\n\nfunction liftUrls(part: AudioMediaPart | VideoMediaPart): LiftedUrls {\n const metadata = (part.metadata ?? null) as Record<string, unknown> | null;\n const cdn = str(metadata?.cdn_url);\n const download = str(metadata?.download_url);\n return {\n // The on-disk `url` is a save-time snapshot; forward it as the fallback\n // the handler only uses when no identity is available.\n url: str(part.url) ?? cdn ?? \"\",\n file_id: str(part.file_id) ?? str(metadata?.file_id),\n cdn_url: cdn,\n download_url: download,\n };\n}\n\nexport function fromCxAudioPart(part: AudioMediaPart): AudioOutputData & {\n transcription_result: string | null;\n} {\n return {\n type: \"audio_output\",\n ...liftUrls(part),\n mime_type: part.mime_type ?? \"audio/*\",\n transcription_result: part.transcription_result ?? null,\n };\n}\n\nexport function fromCxVideoPart(part: VideoMediaPart): VideoOutputData & {\n reference_role: string | null;\n reference_name: string | null;\n} {\n return {\n type: \"video_output\",\n ...liftUrls(part),\n mime_type: part.mime_type ?? \"video/*\",\n // A video reference's role (extend / restyle) and its `@name` — carried so\n // a reload redisplays them (see ReferenceRoleCaption).\n reference_role: part.role ?? null,\n reference_name: part.name ?? null,\n };\n}\n","/**\n * features/files/blocks/adapters/from-media-block.ts\n *\n * THE primary inbound adapter for the new `data.type === \"media_block\"`\n * stream event (Phase 0 of Python's unified-media rollout — see\n * docs/PYTHON_UPDATES.md).\n *\n * The wire shape (Python's `UnifiedMediaBlock` Pydantic union) is\n * snake_case and nearly identical to our domain shape. This adapter does\n * exactly two things:\n * 1. Rename fields snake_case → camelCase.\n * 2. Enforce invariants:\n * - matrx → fileId non-null\n * - external → externalUrl non-null\n * Anything that doesn't satisfy these falls through to an external\n * \"broken\" block; the renderer shows an error state.\n *\n * Anything kind-specific (image's `vision_class`, video's `duration_ms`,\n * etc.) is just propagated — no per-kind logic here.\n *\n * Note: Python `main` hasn't deployed yet (as of 2026-05-16). The shape\n * below is what we'll receive once it does. Until then this adapter is\n * cold-path; the existing `image_output` / `partial_image` legacy\n * adapters carry traffic.\n */\n\nimport { toVisibility } from \"../../ref-types\";\nimport type {\n AudioBlock,\n DocumentBlock,\n ExternalAudioBlock,\n ExternalDocumentBlock,\n ExternalImageBlock,\n ExternalVideoBlock,\n ImageBlock,\n MatrxAudioBlock,\n MatrxDocumentBlock,\n MatrxImageBlock,\n MatrxVideoBlock,\n MediaStatus,\n MediaVisibility,\n UnifiedMediaBlock,\n VideoBlock,\n YouTubeBlock,\n} from \"../types\";\n\n// ─── Wire shape (snake_case mirror of Python's UnifiedMediaBlock) ───────────\n//\n// Hand-typed because the Python-generated `stream-events.ts` doesn't yet\n// emit these — the new types will appear after the backend redeploys.\n// This file owns the source-of-truth shape until then.\n\ninterface WireMediaBlockBase {\n origin: \"matrx\" | \"external\";\n status?: MediaStatus | null;\n progress?: number | null;\n error_message?: string | null;\n mime_type?: string | null;\n file_name?: string | null;\n size_bytes?: number | null;\n base64?: string | null;\n metadata?: Record<string, unknown> | null;\n\n // Matrx-only\n file_id?: string | null;\n visibility?: MediaVisibility | null;\n cdn_url?: string | null;\n download_url?: string | null;\n parent_file_id?: string | null;\n derivation_kind?: string | null;\n // Phase 1b: `thumbnail_url` + `thumbnail_uri` removed from the wire.\n // The canonical source is `Asset.variants[\"thumbnail_url\"].url`.\n\n // External-only\n external_url?: string | null;\n source_label?: string | null;\n}\n\ninterface WireImageBlock extends WireMediaBlockBase {\n kind: \"image\";\n width?: number | null;\n height?: number | null;\n vision_class?: string | null;\n}\n\ninterface WireVideoBlock extends WireMediaBlockBase {\n kind: \"video\";\n width?: number | null;\n height?: number | null;\n duration_ms?: number | null;\n poster_url?: string | null;\n}\n\ninterface WireAudioBlock extends WireMediaBlockBase {\n kind: \"audio\";\n duration_ms?: number | null;\n transcript?: string | null;\n}\n\ninterface WireDocumentBlock extends WireMediaBlockBase {\n kind: \"document\";\n page_count?: number | null;\n page1_url?: string | null;\n}\n\ninterface WireYouTubeBlock extends WireMediaBlockBase {\n kind: \"youtube\";\n video_id?: string | null;\n}\n\nexport type WireMediaBlock =\n | WireImageBlock\n | WireVideoBlock\n | WireAudioBlock\n | WireDocumentBlock\n | WireYouTubeBlock;\n\n/**\n * Wire shape for the `media_block` stream event envelope. Always has\n * `type: \"media_block\"` and a `block: WireMediaBlock` payload.\n */\nexport interface WireMediaBlockData {\n type: \"media_block\";\n block: WireMediaBlock;\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\nfunction pickStatus(s?: MediaStatus | null): MediaStatus {\n return s === \"streaming\" || s === \"error\" ? s : \"complete\";\n}\n\n// The WIRE speaks the DB enum `platform.visibility`\n// (personal < internal < link < public). The block domain speaks\n// `public | personal | shared` — see `toVisibility` in redux/converters.ts for\n// the same translation at the cld_files read boundary. Accept BOTH here: the\n// server sends canonical labels, but persisted `cx_message.content[]` items\n// written before the 2026-07-21 enum canonicalization can still carry the\n// retired `shared` / `private` spellings.\ntype WireVisibility =\n | \"personal\"\n | \"internal\"\n | \"link\"\n | \"public\"\n | \"shared\"\n | \"private\";\n\nfunction pickVisibility(v?: WireVisibility | null): MediaVisibility {\n // The ONE legacy normalizer: the retired spellings both reconcile to\n // `personal`, exactly as the server does (matrx_utils LEGACY_VISIBILITY_MAP),\n // and unknown/null lands there too so a block with a missing visibility is\n // never promoted to public — a private file must resolve through the durable\n // authenticated route, never a bare CDN guess.\n return toVisibility(v);\n}\n\n/**\n * Pull the fields shared by every kind, regardless of origin.\n */\nfunction commonFields(wire: WireMediaBlockBase) {\n return {\n status: pickStatus(wire.status),\n progress: wire.progress ?? null,\n errorMessage: wire.error_message ?? null,\n mimeType: wire.mime_type ?? null,\n fileName: wire.file_name ?? null,\n sizeBytes: wire.size_bytes ?? null,\n base64: wire.base64 ?? null,\n metadata: wire.metadata ?? null,\n };\n}\n\n/**\n * Pull every matrx-origin field. Returns null when the wire block isn't\n * a complete matrx record (fileId missing).\n */\nfunction matrxFields(wire: WireMediaBlockBase): {\n origin: \"matrx\";\n fileId: string;\n visibility: MediaVisibility;\n cdnUrl: string | null;\n downloadUrl: string | null;\n parentFileId: string | null;\n derivationKind: string | null;\n} | null {\n if (wire.origin !== \"matrx\") return null;\n if (!wire.file_id) return null;\n return {\n origin: \"matrx\",\n fileId: wire.file_id,\n visibility: pickVisibility(wire.visibility),\n cdnUrl: wire.cdn_url ?? null,\n downloadUrl: wire.download_url ?? null,\n parentFileId: wire.parent_file_id ?? null,\n derivationKind: wire.derivation_kind ?? null,\n };\n}\n\nfunction externalFields(wire: WireMediaBlockBase): {\n origin: \"external\";\n externalUrl: string;\n sourceLabel: string | null;\n} {\n return {\n origin: \"external\",\n externalUrl: wire.external_url ?? \"\",\n sourceLabel: wire.source_label ?? null,\n };\n}\n\n// ─── Kind-specific lifting ──────────────────────────────────────────────────\n\nfunction liftImage(wire: WireImageBlock): ImageBlock {\n const common = commonFields(wire);\n const matrx = matrxFields(wire);\n const imageBits = {\n kind: \"image\" as const,\n width: wire.width ?? null,\n height: wire.height ?? null,\n visionClass: wire.vision_class ?? null,\n };\n if (matrx) {\n const block: MatrxImageBlock = { ...common, ...matrx, ...imageBits };\n return block;\n }\n const block: ExternalImageBlock = {\n ...common,\n ...externalFields(wire),\n ...imageBits,\n };\n return block;\n}\n\nfunction liftVideo(wire: WireVideoBlock): VideoBlock {\n const common = commonFields(wire);\n const matrx = matrxFields(wire);\n const videoBits = {\n kind: \"video\" as const,\n width: wire.width ?? null,\n height: wire.height ?? null,\n durationMs: wire.duration_ms ?? null,\n posterUrl: wire.poster_url ?? null,\n };\n if (matrx) {\n const block: MatrxVideoBlock = { ...common, ...matrx, ...videoBits };\n return block;\n }\n const block: ExternalVideoBlock = {\n ...common,\n ...externalFields(wire),\n ...videoBits,\n };\n return block;\n}\n\nfunction liftAudio(wire: WireAudioBlock): AudioBlock {\n const common = commonFields(wire);\n const matrx = matrxFields(wire);\n const audioBits = {\n kind: \"audio\" as const,\n durationMs: wire.duration_ms ?? null,\n transcript: wire.transcript ?? null,\n };\n if (matrx) {\n const block: MatrxAudioBlock = { ...common, ...matrx, ...audioBits };\n return block;\n }\n const block: ExternalAudioBlock = {\n ...common,\n ...externalFields(wire),\n ...audioBits,\n };\n return block;\n}\n\nfunction liftDocument(wire: WireDocumentBlock): DocumentBlock {\n const common = commonFields(wire);\n const matrx = matrxFields(wire);\n const docBits = {\n kind: \"document\" as const,\n pageCount: wire.page_count ?? null,\n page1Url: wire.page1_url ?? null,\n };\n if (matrx) {\n const block: MatrxDocumentBlock = { ...common, ...matrx, ...docBits };\n return block;\n }\n const block: ExternalDocumentBlock = {\n ...common,\n ...externalFields(wire),\n ...docBits,\n };\n return block;\n}\n\nfunction liftYouTube(wire: WireYouTubeBlock): YouTubeBlock {\n // YouTube is always external per the Python contract.\n const common = commonFields(wire);\n const block: YouTubeBlock = {\n ...common,\n ...externalFields(wire),\n kind: \"youtube\",\n videoId: wire.video_id ?? null,\n };\n return block;\n}\n\n// ─── Public entry point ─────────────────────────────────────────────────────\n\n/**\n * Lift a wire-shape `UnifiedMediaBlock` (as emitted by Python's new\n * `media_block` data event) into our domain `UnifiedMediaBlock` shape.\n *\n * Discriminates on `kind` and delegates to the kind-specific lifter.\n * Each lifter handles the matrx-vs-external origin split internally.\n */\nexport function fromMediaBlock(wire: WireMediaBlock): UnifiedMediaBlock {\n switch (wire.kind) {\n case \"image\":\n return liftImage(wire);\n case \"video\":\n return liftVideo(wire);\n case \"audio\":\n return liftAudio(wire);\n case \"document\":\n return liftDocument(wire);\n case \"youtube\":\n return liftYouTube(wire);\n default: {\n // Defensive fallback — Python adds a new kind we don't know yet.\n // Surface it as an external image with the original metadata so\n // nothing is dropped silently.\n const base = wire as WireMediaBlockBase;\n const unknownKind = (wire as { kind: string }).kind;\n const fallback: ExternalImageBlock = {\n ...commonFields(base),\n ...externalFields(base),\n kind: \"image\",\n width: null,\n height: null,\n visionClass: null,\n metadata: {\n ...(base.metadata ?? {}),\n _unknown_media_kind: unknownKind,\n },\n errorMessage: `Unsupported media kind: ${unknownKind}`,\n status: \"error\",\n };\n return fallback;\n }\n }\n}\n\n/**\n * Predicate for narrowing a raw `data` payload (typed as\n * `Record<string, unknown>` in Redux) down to a `media_block` event.\n *\n * Use at the stream-event boundary:\n * if (isMediaBlockData(d)) { upsert(fromMediaBlock(d.block)); }\n */\nexport function isMediaBlockData(value: unknown): value is WireMediaBlockData {\n if (value === null || typeof value !== \"object\") return false;\n const v = value as Record<string, unknown>;\n if (v.type !== \"media_block\") return false;\n if (!v.block || typeof v.block !== \"object\") return false;\n const b = v.block as Record<string, unknown>;\n return typeof b.kind === \"string\" && typeof b.origin === \"string\";\n}\n","/**\n * features/files/blocks/adapters/from-media-ref.ts\n *\n * Generic platform primitive: turn a bare `MediaRef` (or file_id / URL)\n * into a minimal `UnifiedMediaBlock` so it can be fed to the canonical\n * renderers (`UnifiedImageBlockRenderer`, `UnifiedVideoBlockRenderer`)\n * which consume a `block`, not a `MediaRef`.\n *\n * Why this exists: many callsites only ever have a durable reference to a\n * file — a `{file_id}` (we own it) or a `{url}` (external / already-public)\n * — yet they want the full rich-media affordances (expand → fullscreen,\n * the \"…\" menu, mobile long-press, share, download). Those affordances\n * live ONLY on the canonical block renderers. This adapter bridges the\n * gap without forcing every caller to hand-build a block literal (which\n * the CLAUDE.md file-handling rules forbid).\n *\n * Mapping (consistent with the invariants in `../types.ts`):\n * - `{ file_id }` ref → an `origin: \"matrx\"` block. `fileId` is set;\n * `visibility` is \"personal\" (unknown) and `cdnUrl` is null, so\n * `useBlockMediaSource` resolves the durable URL via the injected\n * `MediaClient`.\n * - `{ url }` ref → an `origin: \"external\"` block. `externalUrl` is set;\n * the renderer uses it as-is.\n * - A ref that resolves to neither → an `external` \"broken\" block with a\n * null/empty `externalUrl`; the renderer shows its error state.\n *\n * `status` is always \"complete\" — these refs point at finished media. For\n * streaming partials, use the streaming adapters in `from-media-block.ts`.\n */\n\nimport type { MediaRef } from \"../../ref-types\";\nimport type {\n ExternalImageBlock,\n ExternalVideoBlock,\n ImageBlock,\n MatrxImageBlock,\n MatrxVideoBlock,\n VideoBlock,\n} from \"../types\";\n\n/** The kinds this generic adapter can synthesize a block for. */\nexport type MediaBlockKindArg = \"image\" | \"video\";\n\nfunction commonBase(ref: MediaRef) {\n return {\n status: \"complete\" as const,\n progress: null,\n errorMessage: null,\n mimeType: ref.mime_type ?? null,\n fileName: null,\n sizeBytes: null,\n base64: null,\n metadata: null,\n };\n}\n\nfunction matrxBase(fileId: string) {\n return {\n origin: \"matrx\" as const,\n fileId,\n visibility: \"personal\" as const,\n cdnUrl: null,\n downloadUrl: null,\n parentFileId: null,\n derivationKind: null,\n };\n}\n\nfunction externalBase(url: string) {\n return {\n origin: \"external\" as const,\n externalUrl: url,\n sourceLabel: null,\n };\n}\n\n/**\n * Build a minimal `ImageBlock` from a durable reference.\n */\nexport function imageBlockFromMediaRef(ref: MediaRef | null): ImageBlock | null {\n if (!ref) return null;\n const common = commonBase(ref);\n const imageBits = {\n kind: \"image\" as const,\n width: null,\n height: null,\n visionClass: null,\n };\n if (ref.file_id) {\n const block: MatrxImageBlock = {\n ...common,\n ...matrxBase(ref.file_id),\n ...imageBits,\n };\n return block;\n }\n const block: ExternalImageBlock = {\n ...common,\n ...externalBase(ref.url ?? \"\"),\n ...imageBits,\n };\n return block;\n}\n\n/**\n * Build a minimal `VideoBlock` from a durable reference.\n */\nexport function videoBlockFromMediaRef(ref: MediaRef | null): VideoBlock | null {\n if (!ref) return null;\n const common = commonBase(ref);\n const videoBits = {\n kind: \"video\" as const,\n width: null,\n height: null,\n durationMs: null,\n posterUrl: null,\n };\n if (ref.file_id) {\n const block: MatrxVideoBlock = {\n ...common,\n ...matrxBase(ref.file_id),\n ...videoBits,\n };\n return block;\n }\n const block: ExternalVideoBlock = {\n ...common,\n ...externalBase(ref.url ?? \"\"),\n ...videoBits,\n };\n return block;\n}\n\n/**\n * Kind-dispatching convenience: build an image or video block from a ref.\n * Returns `null` when `ref` is null.\n */\nexport function blockFromMediaRef(\n ref: MediaRef | null,\n kind: MediaBlockKindArg,\n): ImageBlock | VideoBlock | null {\n return kind === \"video\"\n ? videoBlockFromMediaRef(ref)\n : imageBlockFromMediaRef(ref);\n}\n","import { isUuidShape } from \"@ai-matrx/kit/uuid\";\n\n/**\n * features/files/blocks/image/helpers/extract-file-id-from-url.ts\n *\n * Best-effort extraction of a cld_files UUID from a storage / CDN URL.\n *\n * Canonical S3 key scheme: `/{owner_id}/{file_id}` (no subfolder, no extension).\n * Legacy fallback: `/{owner_id}/{folder}/{file_id}.{ext}`.\n *\n * Used by adapters as a last-resort when Python's payload doesn't carry an\n * explicit `file_id` field — e.g. legacy stream events. Once Python emits\n * `file_id` consistently, this becomes dead code.\n */\n\nexport function extractFileIdFromUrl(\n url: string | null | undefined,\n): string | null {\n if (!url) return null;\n try {\n const parts = new URL(url).pathname.split(\"/\").filter(Boolean);\n // Canonical scheme: /{owner}/{file_id}\n if (parts.length >= 2) {\n const candidate = parts[1];\n if (isUuidShape(candidate)) return candidate;\n }\n // Legacy fallback: last segment may be {uuid}.{ext}\n const last = parts[parts.length - 1] ?? \"\";\n const stripped = last.replace(/\\.[^.]+$/, \"\");\n if (isUuidShape(stripped)) return stripped;\n return null;\n } catch {\n return null;\n }\n}\n","/**\n * features/files/blocks/image/helpers/parse-filename-from-url.ts\n *\n * S3 signed URLs the backend mints for AI-generated images carry the\n * intended filename in `response-content-disposition`, e.g.:\n *\n * ?response-content-disposition=inline%3B%20filename%3D%22kitten.png%22\n *\n * Python's AI-naming step (`features/ai/...`) writes a meaningful name\n * there based on the prompt, so the browser shows it on download. But\n * when we use `<a download=\"...\">` we override that — we need the name\n * in `block.fileName` to pass it back.\n *\n * This helper extracts the filename from the query param if present.\n * Returns null on anything malformed so callers always get a string or\n * null (never an empty string).\n *\n * Handles both RFC 5987 forms:\n * - `filename=\"kitten.png\"` (quoted, ASCII)\n * - `filename*=UTF-8''ki%CC%88tten.png` (extended, percent-encoded)\n */\n\nconst FILENAME_QUERY_KEYS = [\n \"response-content-disposition\",\n \"content-disposition\",\n];\n\nexport function parseFilenameFromUrl(\n url: string | null | undefined,\n): string | null {\n if (!url) return null;\n\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return null;\n }\n\n for (const key of FILENAME_QUERY_KEYS) {\n const disposition = parsed.searchParams.get(key);\n if (disposition) {\n const name = parseContentDisposition(disposition);\n if (name) return name;\n }\n }\n\n return null;\n}\n\n/**\n * Parse a Content-Disposition header value and return the filename.\n * RFC 6266 / 5987 — handles both `filename=` and `filename*=` forms.\n */\nfunction parseContentDisposition(value: string): string | null {\n // RFC 5987 extended form: filename*=UTF-8''<percent-encoded>\n // Prefer this over the ASCII form when present (it can carry unicode).\n const extMatch =\n /filename\\*\\s*=\\s*([A-Za-z0-9_-]+)'(?:[A-Za-z0-9_-]*)'([^;]+)/i.exec(value);\n if (extMatch) {\n const charset = extMatch[1]!;\n const encoded = extMatch[2]!.trim();\n try {\n const decoded = decodeURIComponent(encoded);\n if (charset.toLowerCase() === \"utf-8\") return safeName(decoded);\n return safeName(decoded);\n } catch {\n // fall through to the basic form\n }\n }\n\n // Basic form: filename=\"kitten.png\" OR filename=kitten.png\n const basicMatch = /filename\\s*=\\s*(?:\"([^\"]+)\"|([^;]+))/i.exec(value);\n if (basicMatch) {\n const raw = (basicMatch[1] ?? basicMatch[2] ?? \"\").trim();\n if (raw) return safeName(raw);\n }\n\n return null;\n}\n\n/**\n * Strip path traversal characters from a filename — defense-in-depth in\n * case the URL was crafted to inject a path. Result is just the leaf.\n */\nfunction safeName(name: string): string | null {\n // Take only the leaf (no directory separators).\n const leaf = name.split(/[/\\\\]/).pop()?.trim();\n if (!leaf) return null;\n // Reject control characters and obviously broken values.\n if (/[\\x00-\\x1f]/.test(leaf)) return null;\n return leaf;\n}\n","/**\n * features/files/blocks/image/adapters/from-image-output-data.ts\n *\n * Convert a Python `image_output` data event into a UnifiedImageBlock.\n *\n * Today's Python wire shape (ImageOutputData):\n * { type: \"image_output\", url, mime_type, file_id?, cdn_url?, download_url? }\n *\n * What this adapter does:\n * - Lifts `file_id` to identify a matrx-owned file (most common case).\n * - Tries to extract `file_id` from `url` if Python didn't supply one\n * (legacy fallback — eventually deletable).\n * - Promotes additional fields from `metadata` if Python included them\n * there as a transitional shim:\n * visibility, thumbnail_url, parent_file_id, derivation_kind,\n * file_name, width, height, size_bytes.\n * - When no `file_id` is recoverable, falls back to an external block\n * using whichever URL is most likely permanent.\n *\n * Delete when Python emits UnifiedImageBlock directly (Phase 2).\n */\n\nimport type { ImageOutputData } from \"@ai-matrx/agents/generated/stream-events\";\nimport type {\n UnifiedImageBlock,\n MatrxImageBlock,\n ExternalImageBlock,\n} from \"../types\";\nimport type { MediaVisibility } from \"../../types\";\nimport { extractFileIdFromUrl } from \"../helpers/extract-file-id-from-url\";\nimport { parseFilenameFromUrl } from \"../helpers/parse-filename-from-url\";\nimport { isSignedUrl } from \"@ai-matrx/data/files\";\n\n/**\n * Read a string from a metadata bag, returning null when missing / wrong type.\n */\nfunction metaString(\n metadata: Record<string, unknown> | null | undefined,\n key: string,\n): string | null {\n if (!metadata) return null;\n const value = metadata[key];\n return typeof value === \"string\" ? value : null;\n}\n\nfunction metaNumber(\n metadata: Record<string, unknown> | null | undefined,\n key: string,\n): number | null {\n if (!metadata) return null;\n const value = metadata[key];\n return typeof value === \"number\" && Number.isFinite(value) ? value : null;\n}\n\nfunction metaVisibility(\n metadata: Record<string, unknown> | null | undefined,\n): MediaVisibility {\n const value = metaString(metadata, \"visibility\");\n if (\n value === \"public\" ||\n value === \"personal\" ||\n value === \"internal\" ||\n value === \"link\"\n )\n return value;\n // `metadata` is an untyped passthrough of the cld_files row, so it carries\n // RAW `platform.visibility` labels (personal < internal < link < public), not\n // the block domain's vocabulary. Translate them the same way the other read\n // boundaries do (redux/converters.ts::toVisibility) — before this, `internal`\n // (the column DEFAULT and the most common value in files.files) fell through\n // to the `public` default below, which tells the UI the image has a permanent\n // CDN URL and suppresses signed-URL refresh: the image dies at expiry.\n if (value === \"shared\" || value === \"private\") return \"personal\";\n // Unknown is NEVER \"public\". The old \"public\" default told\n // useBlockMediaSource the block's URL was a permanent CDN URL and bound the\n // authenticated durable inline-download endpoint for the file straight to\n // an <img> — the third-party-cookie lane — for a `personal` row: \"Image\n // unavailable\" forever in any browser that blocks third-party cookies\n // (Arman's Chrome, 2026-09-16). \"personal\" is the row default in\n // files.files and the safe assumption: the client resolves by file_id and\n // upgrades to the permanent CDN URL itself once the row is hydrated. The\n // server now stamps `metadata.visibility` on every generated block, so this\n // branch is the exception, not the rule.\n return \"personal\";\n}\n\nexport function fromImageOutputData(\n data: ImageOutputData,\n carriedMetadata?: Record<string, unknown> | null,\n): UnifiedImageBlock {\n // `metadata` may live either on the top-level event envelope or inside the\n // payload itself depending on Python's emit point. Caller passes whichever\n // is most relevant; we read both as fallbacks.\n const metadata = carriedMetadata ?? null;\n\n // ── URL flavors ────────────────────────────────────────────────────────\n const cdnUrl = data.cdn_url ?? null;\n const downloadUrl = data.download_url ?? null;\n\n // `url` is the durable always-renderable URL per the platform contract. A\n // LEGACY row/event can still carry a signed URL here — classify it so we\n // never file an expiring URL into the permanent-CDN slot (that\n // misclassification is the bug that made owned images go dark forever).\n const fallbackUrl = data.url;\n const fallbackLooksSigned = isSignedUrl(fallbackUrl);\n const finalCdnUrl =\n cdnUrl ?? (fallbackLooksSigned ? null : (fallbackUrl ?? null));\n\n // ── Identity ───────────────────────────────────────────────────────────\n const explicitFileId = data.file_id ?? null;\n const inferredFileId =\n explicitFileId ??\n extractFileIdFromUrl(finalCdnUrl) ??\n extractFileIdFromUrl(fallbackUrl) ??\n null;\n\n // ── Common fields (every variant, regardless of origin) ────────────────\n const common = {\n kind: \"image\" as const,\n base64: null,\n mimeType: data.mime_type ?? null,\n // Filename priority:\n // 1. Explicit `file_name` in the event metadata (Python's intent).\n // 2. The filename baked into the signed URL's\n // `response-content-disposition` query param — Python sets this\n // to the AI-chosen name on every signed-URL mint, and it's the\n // ground truth for \"what should the user see on download\".\n // 3. null — fall back to a generic `image.<ext>` at the callsite.\n fileName:\n metaString(metadata, \"file_name\") ??\n parseFilenameFromUrl(downloadUrl) ??\n parseFilenameFromUrl(finalCdnUrl) ??\n null,\n width: metaNumber(metadata, \"width\"),\n height: metaNumber(metadata, \"height\"),\n // Phase 0 wire rename: prefer `size_bytes`, accept legacy `file_size`\n // from in-flight services that haven't redeployed yet.\n sizeBytes:\n metaNumber(metadata, \"size_bytes\") ?? metaNumber(metadata, \"file_size\"),\n visionClass: metaString(metadata, \"vision_class\"),\n status: \"complete\" as const,\n progress: null,\n errorMessage: null,\n metadata: metadata ?? null,\n };\n\n // ── Variant selection ──────────────────────────────────────────────────\n // A fileId proves matrx identity; anything without one collapses to\n // external.\n if (inferredFileId) {\n const matrx: MatrxImageBlock = {\n ...common,\n origin: \"matrx\",\n fileId: inferredFileId,\n visibility: metaVisibility(metadata),\n cdnUrl: finalCdnUrl,\n downloadUrl,\n // Phase 1b: thumbnails removed from MatrxImageBlock — the canonical\n // source is `Asset.variants[\"thumbnail_url\"].url` via GET /assets/{id}.\n // For top-level listings, `CloudFile.thumbnailUrl` (lifted from\n // `FileRecord.thumbnail_url`) is the FE-side cache of that resolved URL.\n parentFileId: metaString(metadata, \"parent_file_id\"),\n derivationKind: metaString(metadata, \"derivation_kind\"),\n };\n return matrx;\n }\n\n // Truly external — synthesize an externalUrl from whatever we have.\n // External blocks no longer carry the matrx-only URL flavors at the\n // type level (see features/files/blocks/types.ts) — those URLs are\n // dropped here when we can't prove a matrx identity.\n const externalUrl = fallbackUrl ?? finalCdnUrl ?? \"\";\n if (!externalUrl) {\n const broken: ExternalImageBlock = {\n ...common,\n origin: \"external\",\n externalUrl: \"\",\n sourceLabel: metaString(metadata, \"source_label\"),\n };\n return broken;\n }\n const external: ExternalImageBlock = {\n ...common,\n origin: \"external\",\n externalUrl,\n sourceLabel: metaString(metadata, \"source_label\"),\n };\n return external;\n}\n","/**\n * features/files/blocks/image/adapters/from-cx-media-part.ts\n *\n * Convert a DB-stored `cx_message.content[]` media part (kind: \"image\") into\n * a UnifiedImageBlock.\n *\n * Today's storage shape (CxMediaContent → ImageMediaPart):\n * { type: \"media\", kind: \"image\", url?, mime_type?, base64_data?,\n * metadata? }\n *\n * Everything else (file_id, cdn_url, visibility, thumbnails,\n * dimensions, file_name, prompt, model, etc.) gets dumped into `metadata`\n * today by `assembleMessageParts`. This adapter pulls them BACK out so the\n * round-trip is lossless.\n *\n * Delete when `cx_message.content[]` storage shape switches to\n * UnifiedImageBlock natively (Phase 3).\n */\n\nimport type { ImageMediaPart } from \"@ai-matrx/agents/generated/stream-events\";\nimport type { UnifiedImageBlock } from \"../types\";\nimport { fromImageOutputData } from \"./from-image-output-data\";\n\nexport function fromCxMediaPart(part: ImageMediaPart): UnifiedImageBlock {\n const metadata = (part.metadata ?? null) as Record<string, unknown> | null;\n // Pull URL flavors and file_id from metadata if present (where\n // assembleMessageParts dumped them).\n const cdnFromMeta =\n typeof metadata?.cdn_url === \"string\" ? metadata.cdn_url : null;\n const downloadFromMeta =\n typeof metadata?.download_url === \"string\" ? metadata.download_url : null;\n // `file_id` is stored at the TOP LEVEL of the media part by the backend\n // (and only sometimes mirrored into metadata). Prefer the top-level value —\n // losing it forces the block to recover the id from an expiring URL, and if\n // that fails the block collapses to `external` and can never re-mint. An\n // owned file must ALWAYS keep its file_id.\n const fileId =\n (typeof part.file_id === \"string\" ? part.file_id : null) ??\n (typeof metadata?.file_id === \"string\" ? metadata.file_id : null);\n\n // The on-disk `url` field is whatever was visible at save time — could be\n // CDN, could be a legacy signed URL (long-expired). Forward as the\n // fallback; the adapter classifies signed URLs and never treats them as\n // permanent.\n const fallbackUrl = part.url ?? cdnFromMeta ?? \"\";\n\n const block = fromImageOutputData(\n {\n type: \"image_output\",\n url: fallbackUrl,\n mime_type: part.mime_type ?? \"image/*\",\n file_id: fileId,\n cdn_url: cdnFromMeta,\n download_url: downloadFromMeta,\n },\n {\n // Pass through all metadata so the extension fields (visibility,\n // thumbnail, dimensions, etc.) get lifted by the rich adapter.\n // Stored parts from before the storage-location eradication may\n ...(metadata ?? {}),\n },\n );\n\n // The reference role + `@name` the person gave this image as an input.\n // Top-level fields on the part (never in metadata); dropping them here was\n // why a role set in the builder never showed again after reload.\n const withRole: UnifiedImageBlock = {\n ...block,\n referenceRole: part.role ?? null,\n referenceName: part.name ?? null,\n };\n\n // Base64 inline payload (rare but allowed by the on-disk shape).\n if (typeof metadata?.base64_data === \"string\") {\n return { ...withRole, base64: metadata.base64_data };\n }\n return withRole;\n}\n","/**\n * features/files/blocks/image/adapters/from-partial-image-data.ts\n *\n * Convert a Python `partial_image` event into an in-flight UnifiedImageBlock.\n *\n * Partial images are base64 frames Python emits during image generation.\n * They arrive BEFORE the final `image_output` event lands, so there's no\n * fileId yet. We model them as an external block in \"streaming\" status\n * whose `base64` carries the latest frame.\n *\n * When the final `image_output` arrives, the stream-ingest layer should\n * upsert by `blockId` so a single block transitions from streaming\n * (base64-only) → complete (matrx variant with URLs). This means partial\n * and final SHARE the same blockId in Redux.\n *\n * Delete when Python emits UnifiedImageBlock directly with status: \"streaming\"\n * (Phase 2).\n */\n\nimport type { PartialImageData } from \"@ai-matrx/agents/generated/stream-events\";\nimport type { UnifiedImageBlock } from \"../types\";\n\nexport function fromPartialImageData(\n data: PartialImageData,\n carriedMetadata?: Record<string, unknown> | null,\n): UnifiedImageBlock {\n // Partials are visually external — they're inline base64 with no identity\n // until the final event lands. The renderer treats them as \"best available\n // preview\" while waiting for the upsert.\n return {\n kind: \"image\",\n origin: \"external\",\n base64: data.b64_json,\n mimeType: data.mime_type ?? \"image/png\",\n fileName: null,\n width: null,\n height: null,\n sizeBytes: null,\n visionClass: null,\n status: \"streaming\",\n progress: data.progress ?? null,\n errorMessage: null,\n metadata: carriedMetadata ?? null,\n externalUrl: \"\",\n sourceLabel: \"Generating\",\n };\n}\n","/**\n * features/files/blocks/image/adapters/from-render-block.ts\n *\n * Convert a markdown-parsed image render_block (e.g. from a text chunk that\n * contained `![alt](url)`) into a UnifiedImageBlock.\n *\n * Today's wire shape is minimal — `{ src, alt }`. We treat these as external\n * unless the URL pattern matches our canonical S3 key scheme, in which case\n * we promote to matrx via `extractFileIdFromUrl` (inside `fromImageOutputData`).\n *\n * Input type is `RenderBlockPayload` (not `ImageRenderBlock`) so callers can\n * pass the redux-stored loose shape without a force-cast. We validate the\n * payload structure internally; an empty src yields an external block with an\n * empty URL — the renderer's error state covers it.\n *\n * Delete when render_block:image emits UnifiedImageBlock in its `data` field\n * (Phase 2).\n */\n\nimport type { RenderBlockPayload } from \"@ai-matrx/agents/generated/stream-events\";\nimport { fromImageOutputData } from \"./from-image-output-data\";\nimport type { UnifiedImageBlock } from \"../types\";\n\nexport function fromRenderBlock(block: RenderBlockPayload): UnifiedImageBlock {\n // Pull `src` defensively — the loose `Record<string, unknown>` data\n // shape gives no compile-time guarantee. Adapters at boundaries must\n // tolerate Python sending field names that drift slightly over time.\n const data = (block.data ?? {}) as Record<string, unknown>;\n const src = typeof data.src === \"string\" ? data.src : \"\";\n const mimeType =\n typeof data.mime_type === \"string\" ? data.mime_type : \"image/*\";\n\n // Forward into the rich adapter so the same heuristics (file_id extraction,\n // signed-url detection, expiry parsing) apply.\n return fromImageOutputData(\n {\n type: \"image_output\",\n url: src,\n mime_type: mimeType,\n },\n block.metadata ?? null,\n );\n}\n","/**\n * features/files/blocks/image/adapters/to-cx-media-part.ts\n *\n * Convert a `UnifiedImageBlock` into the generated DB on-disk\n * `ImageMediaPart` shape.\n *\n * On-disk shape today (`ImageMediaPart`):\n * { type: \"media\", kind: \"image\", file_id? | url?, origin?,\n * mime_type?, size_bytes?, width?, height?, metadata? }\n *\n * Strategy:\n * - Keep generated top-level identity fields populated so\n * legacy readers that haven't migrated keep working.\n * - Pack EVERY canonical field (origin, fileId, cdnUrl, downloadUrl,\n * visibility, thumbnails, dimensions, etc.) into\n * `metadata` under stable keys so `fromCxMediaPart` can re-lift them\n * losslessly when the message is reloaded.\n *\n * Delete when `cx_message.content[]` storage switches to UnifiedImageBlock\n * natively (Phase 3).\n */\n\nimport type { ImageMediaPart } from \"@ai-matrx/agents/generated/stream-events\";\nimport type { UnifiedImageBlock } from \"../types\";\n\nexport function toCxMediaPart(block: UnifiedImageBlock): ImageMediaPart {\n // The visible `url` field: prefer the most permanent option so reload\n // works even when metadata isn't read.\n const visibleUrl =\n block.origin === \"matrx\"\n ? (block.cdnUrl ?? undefined)\n : block.externalUrl || undefined;\n\n // Pack the canonical fields into metadata under explicit keys. We do NOT\n // drop the caller's free-form `metadata` — we merge it in first so any\n // adapter-promoted keys overwrite stale ones.\n const callerMetadata = block.metadata ?? {};\n const packed: Record<string, unknown> = {\n ...callerMetadata,\n kind: block.kind,\n origin: block.origin,\n mime_type: block.mimeType,\n file_name: block.fileName,\n width: block.width,\n height: block.height,\n size_bytes: block.sizeBytes,\n vision_class: block.visionClass,\n status: block.status,\n progress: block.progress,\n error_message: block.errorMessage,\n };\n // NEVER persist expiring locators into cx_message media parts — a stored\n // signed URL is a guaranteed future 403. Old blocks can still carry them\n // in free-form metadata; strip them at the write boundary.\n delete packed.signed_url;\n delete packed.signed_url_expires_at;\n\n if (block.origin === \"matrx\") {\n packed.cdn_url = block.cdnUrl;\n packed.download_url = block.downloadUrl;\n packed.file_id = block.fileId;\n packed.visibility = block.visibility;\n // Phase 1b: `thumbnail_url` / `thumbnail_uri` removed from the block\n // shape; thumbnails are now sourced from `Asset.variants[\"thumbnail_url\"]`.\n packed.parent_file_id = block.parentFileId;\n packed.derivation_kind = block.derivationKind;\n } else {\n packed.external_url = block.externalUrl;\n packed.source_label = block.sourceLabel;\n }\n\n // Base64 is transient render data, not a top-level ImageMediaPart field.\n // Preserve it inside extensible metadata for the live Redux round-trip;\n // emitting `base64_data` beside `type`/`kind` violates the generated\n // chat.message.content contract and crashes the strict read boundary.\n if (block.base64) {\n packed.base64_data = block.base64;\n }\n\n const common = {\n type: \"media\",\n kind: \"image\",\n ...(block.mimeType !== null ? { mime_type: block.mimeType } : {}),\n ...(block.sizeBytes !== null ? { size_bytes: block.sizeBytes } : {}),\n ...(block.width !== null ? { width: block.width } : {}),\n ...(block.height !== null ? { height: block.height } : {}),\n metadata: packed,\n } as const;\n\n if (block.origin === \"matrx\") {\n return {\n ...common,\n origin: \"matrx\",\n file_id: block.fileId,\n ...(visibleUrl ? { url: visibleUrl } : {}),\n };\n }\n\n const externalUrl =\n visibleUrl ??\n (block.base64\n ? `data:${block.mimeType ?? \"image/*\"};base64,${block.base64}`\n : null);\n if (!externalUrl) {\n throw new TypeError(\n \"Cannot project external image into chat.message.content: missing URL and base64 locator\",\n );\n }\n\n return {\n ...common,\n origin: \"external\",\n url: externalUrl,\n };\n}\n","/**\n * features/files/blocks/image/helpers/derive-viewer-url.ts\n *\n * Derive the internal viewer route for a matrx-owned image. The route\n * `/files/f/{fileId}` is the canonical \"deep link\" for any cld_files row.\n *\n * External blocks do not have a viewer URL — return null.\n */\n\nimport type { UnifiedImageBlock } from \"../types\";\n\nexport function deriveViewerUrl(block: UnifiedImageBlock): string | null {\n if (block.origin === \"external\") return null;\n return `/files/f/${block.fileId}`;\n}\n","/**\n * src/react/cn.ts — conditional class join with last-wins Tailwind conflict\n * merging. The originals used the app's `cn` (clsx + tailwind-merge); public\n * `className` overrides depend on last-wins class-conflict merging, so a\n * naive join would be a behavior divergence (the kit `./confirm` precedent —\n * this is why `tailwind-merge` is a sanctioned runtime dep of `/react`).\n */\n\nimport { twMerge } from \"tailwind-merge\";\n\nexport type ClassValue = string | false | null | undefined | 0;\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(inputs.filter(Boolean).join(\" \"));\n}\n","const COMPACT_VIDEO_DATE = new Intl.DateTimeFormat(\"en-US\", {\n month: \"2-digit\",\n day: \"2-digit\",\n year: \"2-digit\",\n timeZone: \"UTC\",\n});\n\nconst FULL_VIDEO_DATE = new Intl.DateTimeFormat(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n timeZone: \"UTC\",\n});\n\nfunction parseVideoDate(value: string | null | undefined): Date | null {\n if (!value) return null;\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n}\n\n/** Stable, narrow video publish-date text for cards, rows, and embeds. */\nexport function formatVideoPublishDate(\n value: string | null | undefined,\n): string {\n const date = parseVideoDate(value);\n return date ? COMPACT_VIDEO_DATE.format(date) : \"No Date\";\n}\n\n/** Accessible detail for the compact video publish-date treatment. */\nexport function formatVideoPublishDateTitle(\n value: string | null | undefined,\n): string {\n const date = parseVideoDate(value);\n return date\n ? `Published ${FULL_VIDEO_DATE.format(date)}`\n : \"Publish date unavailable\";\n}\n\nconst VIDEO_DATE_KEYS = [\n \"published_at\",\n \"publishedAt\",\n \"publish_date\",\n \"publishDate\",\n \"uploadDate\",\n \"datePublished\",\n] as const;\n\nconst VIDEO_METADATA_CONTAINERS = [\n \"video_metadata\",\n \"schema_org\",\n \"metadata\",\n] as const;\n\n/**\n * Read a provider/schema publish date from the common metadata envelopes used\n * by research media, crawled site videos, and brand-library assets.\n */\nexport function videoPublishDateFromMetadata(value: unknown): string | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const record = value as Record<string, unknown>;\n for (const key of VIDEO_DATE_KEYS) {\n const candidate = record[key];\n if (typeof candidate === \"string\" && parseVideoDate(candidate)) {\n return candidate;\n }\n }\n for (const key of VIDEO_METADATA_CONTAINERS) {\n const nested = videoPublishDateFromMetadata(record[key]);\n if (nested) return nested;\n }\n return null;\n}\n","import { cn } from \"../../../react/cn\";\nimport {\n formatVideoPublishDate,\n formatVideoPublishDateTitle,\n} from \"../../media/video-date\";\n\n/** One compact publish-date treatment shared by every video surface. */\nexport function VideoPublishDate({\n publishedAt,\n className,\n}: {\n publishedAt?: string | null;\n className?: string;\n}) {\n const dateTime =\n publishedAt && !Number.isNaN(new Date(publishedAt).getTime())\n ? publishedAt\n : undefined;\n const content = formatVideoPublishDate(publishedAt);\n const sharedProps = {\n className: cn(\n \"shrink-0 whitespace-nowrap text-[10px] tabular-nums text-muted-foreground\",\n className,\n ),\n title: formatVideoPublishDateTitle(publishedAt),\n \"aria-label\": formatVideoPublishDateTitle(publishedAt),\n };\n\n return dateTime ? (\n <time {...sharedProps} dateTime={dateTime}>\n {content}\n </time>\n ) : (\n <span {...sharedProps}>{content}</span>\n );\n}\n","/**\n * features/files/handler/errors.ts\n *\n * Error taxonomy for the universal file handler. Every failure inside the\n * handler maps to ONE of these classes — callers `instanceof`-check to\n * decide whether to retry, refresh, surface a UI, or reject.\n *\n * The crucial distinction the handler exists to enforce:\n *\n * - FileAccessDeniedError → user does NOT have access. Reject. Never retry.\n * - a transient auth failure on a durable URL → refresh the file session\n * (see ../session.ts) and retry the SAME URL; never a terminal error.\n */\n\nexport type FileHandlerErrorCode =\n | \"access_denied\"\n | \"not_found\"\n | \"deleted\"\n | \"share_link_invalid\"\n | \"external_fetch_failed\"\n | \"cors_blocked\"\n | \"mime_unknown\"\n | \"upload_failed\"\n | \"upload_cancelled\"\n | \"quota_exceeded\"\n | \"in_flight\"\n | \"internal\";\n\nexport class FileHandlerError extends Error {\n readonly code: FileHandlerErrorCode;\n readonly fileId?: string | undefined;\n override readonly cause?: unknown;\n\n constructor(\n code: FileHandlerErrorCode,\n message: string,\n opts?: { fileId?: string; cause?: unknown },\n ) {\n super(message);\n this.name = \"FileHandlerError\";\n this.code = code;\n this.fileId = opts?.fileId;\n this.cause = opts?.cause;\n }\n}\n\nexport class FileAccessDeniedError extends FileHandlerError {\n constructor(\n // Thrown ONLY on a real 403 from our own file server (resolver.ts) —\n // a proven refusal, not a guess. The sentence\n // stays plain so a surface that renders it verbatim never implies more\n // than the server actually said; a surface that can do better should\n // render `<AccessGate token=\"file\" id={fileId}/>`, which names the owner\n // and offers a request.\n message = \"This file isn't available to you.\",\n opts?: { fileId?: string },\n ) {\n super(\"access_denied\", message, opts);\n this.name = \"FileAccessDeniedError\";\n }\n}\n\nexport class FileNotFoundError extends FileHandlerError {\n // A 404 from the file server. It proves the server could not retrieve the\n // file — NOT that the file was deleted (that is `FileDeletedError`, which\n // has a `deleted_at` to point at) and not that it never existed.\n constructor(message = \"We couldn't retrieve this file.\", opts?: { fileId?: string }) {\n super(\"not_found\", message, opts);\n this.name = \"FileNotFoundError\";\n }\n}\n\nexport class FileDeletedError extends FileHandlerError {\n constructor(message = \"File is in trash\", opts?: { fileId?: string }) {\n super(\"deleted\", message, opts);\n this.name = \"FileDeletedError\";\n }\n}\n\nexport class ShareLinkInvalidError extends FileHandlerError {\n constructor(message = \"Share link is invalid, expired, or revoked\") {\n super(\"share_link_invalid\", message);\n this.name = \"ShareLinkInvalidError\";\n }\n}\n\nexport class ExternalFetchError extends FileHandlerError {\n constructor(message = \"Failed to fetch external URL\", opts?: { cause?: unknown }) {\n super(\"external_fetch_failed\", message, opts);\n this.name = \"ExternalFetchError\";\n }\n}\n\nexport class FileUploadError extends FileHandlerError {\n constructor(message: string, opts?: { cause?: unknown }) {\n super(\"upload_failed\", message, opts);\n this.name = \"FileUploadError\";\n }\n}\n\n/**\n * The person was asked which workspace an upload belongs to and declined.\n *\n * Deliberately a distinct class, not a `FileUploadError` with a flag: nothing\n * failed. No bytes moved, no row was written, and there is nothing to retry or\n * report. Every catch site must swallow it silently — cancelling has to return\n * the person exactly where they were, which a red toast does not.\n */\nexport class UploadCancelledError extends FileHandlerError {\n constructor(message = \"Upload cancelled — no workspace was selected.\") {\n super(\"upload_cancelled\", message);\n this.name = \"UploadCancelledError\";\n }\n}\n\nexport function isUploadCancelledError(error: unknown): boolean {\n return error instanceof Error && error.name === \"UploadCancelledError\";\n}\n","/**\n * features/files/utils/folder-conventions.ts\n *\n * Canonical folder paths for every feature that uploads on behalf of the\n * user. The rule is simple: **organize files the way a user would expect to\n * find them.** When a user opens `/files`, they should be able to\n * point at a folder and say \"that's where X goes\" without us explaining it.\n *\n * Two buckets:\n *\n * 1. Visible folders — real, user-facing. Files go here when the user\n * produced them, uploaded them, or attached them to something. Names are\n * human-readable (Title Case) because they're shown in the tree.\n *\n * 2. Hidden folders (leading `.`) — ephemeral / infrastructure files the\n * user doesn't need to see or manage. Auto-collapsed in the UI. These\n * should be rare; only use them for true transients (short-lived URL\n * staging, drafts) and prefer deletion on completion.\n *\n * Every consumer migration should pick its folder from this file or add a\n * new constant here — do NOT hand-roll folder paths at call sites.\n *\n * This file is also the source of truth for the **default visibility** of\n * every folder — see `resolveDefaultVisibility` near the bottom. Callers\n * should pick visibility based on render context, not user role: anything\n * rendered on a public page (org logo, podcast cover, agent-app icon)\n * defaults to `\"public\"` so it gets a CDN URL; anything user-scoped\n * (chat attachment, task attachment, ephemeral temp) stays `\"private\"`.\n */\n\nimport type { Visibility } from \"../ref-types\";\n\n// ---------------------------------------------------------------------------\n// Static (feature-level) folders\n// ---------------------------------------------------------------------------\n\nexport const CloudFolders = {\n // ── Visible / user-managed ────────────────────────────────────────────\n\n /** Top-level \"Images\" drawer. */\n IMAGES: \"Images\",\n /** Images pasted/attached inside a chat. */\n IMAGES_CHAT: \"Images/Chat\",\n /** Screenshots dragged or pasted into the app. */\n IMAGES_SCREENSHOTS: \"Images/Screenshots\",\n /** User avatars / profile images. */\n IMAGES_AVATARS: \"Images/Avatars\",\n /** Images generated by AI tools. */\n IMAGES_GENERATED: \"Images/Generated\",\n /** Screenshots and images flattened with user-authored markup. */\n IMAGES_ANNOTATED: \"Images/Annotated\",\n\n /** Top-level \"Audio\" drawer. */\n AUDIO: \"Audio\",\n /** User-initiated audio recordings (voice-to-text, voice pad, etc.). */\n AUDIO_RECORDINGS: \"Audio/Recordings\",\n /** Podcast asset uploads. */\n AUDIO_PODCASTS: \"Audio/Podcasts\",\n\n /** Top-level \"Captures\" drawer — everything the in-browser media-capture\n * system saves (features/media-capture). User-produced, so visible. */\n CAPTURES: \"Captures\",\n /** Photos taken with the in-app camera (Capture Studio / device fallback). */\n CAPTURES_PHOTOS: \"Captures/Photos\",\n /** Videos recorded with the in-app camera (media-capture Phase 7). */\n CAPTURES_VIDEOS: \"Captures/Videos\",\n /** Audio recorded through the Capture Studio (media-capture Phase 7). */\n CAPTURES_AUDIO: \"Captures/Audio\",\n\n /** Product-capture staging (features/product-capture) — per-item folders of\n * photos/videos/voice notes shot ahead of listing creation. Org-namespaced\n * via `folderForProductCaptureItem` (same server one-path-one-org rule as\n * Captures). User-produced, so visible. */\n PRODUCT_CAPTURES: \"Product Captures\",\n\n /** Commerce intake (W4 capture app): per-asset media filed under\n * `Commerce Intake/<orgId>/<batchId>/<asset-leaf>` via\n * `folderForIntakeAsset` (same server one-path-one-org rule as Captures).\n * User-produced, so visible. */\n COMMERCE_INTAKE: \"Commerce Intake\",\n\n /**\n * Static app assets (sounds, hero images, model-card thumbnails, demo\n * data) owned by an admin service account and rendered globally.\n * Always public — CDN URL is the goal. Source of truth for the\n * static-asset migration (see scripts/migrate-public-assets-to-cdn.ts).\n */\n APP_ASSETS: \"App Assets\",\n\n /** Top-level documents (PDF, DOCX, etc.). */\n DOCUMENTS: \"Documents\",\n /** PDF-specific drawer. */\n DOCUMENTS_PDFS: \"Documents/PDFs\",\n\n /** Top-level code files (scripts, snippets). */\n CODE: \"Code\",\n /** Code saved via the code-editor window. */\n CODE_EDITOR: \"Code/Editor\",\n\n /** Generic AI-generated outputs. */\n GENERATED: \"Generated\",\n\n /** Files attached to agent apps, keyed by app id at runtime. */\n AGENT_APPS: \"Agent Apps\",\n\n /** Files attached to tasks, keyed by task id at runtime. */\n TASK_ATTACHMENTS: \"Task Attachments\",\n\n /** Files attached to War Room tiles, keyed by tile id at runtime. */\n WAR_ROOM: \"War Room\",\n\n /** Files dropped into a chat composer (pre-send or history). */\n CHAT_ATTACHMENTS: \"Chat Attachments\",\n\n /** Slack-imported files. */\n SLACK_IMPORTS: \"Slack Imports\",\n\n /** Web-scrape captures (HTML snapshots, exported markdown). */\n SCRAPED_CONTENT: \"Scraped Content\",\n\n // ── Shared assets / org-scoped public surfaces ─────────────────────────\n\n /**\n * Org-scoped shared assets — logos, hero images, anything an\n * organization renders on a public surface. Keyed by org id at\n * runtime (e.g. `Shared Assets/orgs/<org-id>`). Always public —\n * the CDN URL is the rendering target.\n */\n SHARED_ASSETS_ORGS: \"Shared Assets/orgs\",\n\n /** Public screenshot attachments submitted through the feedback window. */\n FEEDBACK_IMAGES: \"Shared Assets/feedback-images\",\n\n /**\n * OG / social-preview covers for HTML pages the user publishes.\n * Lives under Shared Assets so all org/public-surface previews\n * share one CDN-backed bucket.\n */\n HTML_PAGES_OG: \"Shared Assets/html-pages\",\n\n // ── App-asset subfolders ───────────────────────────────────────────────\n\n /**\n * Favicons rendered by prompt-app / agent-app standalone pages.\n * Always public — favicon requests are anonymous.\n */\n PROMPT_APPS_FAVICONS: \"App Assets/prompt-apps/favicons\",\n\n /**\n * Per-block assets attached to agent blocks (icons, illustrations,\n * inline media). Keyed by block id at runtime via\n * `folderForAgentBlock(blockId)`.\n */\n AGENT_BLOCKS: \"Agent Apps/blocks\",\n\n // ── Canvas / image-editor ──────────────────────────────────────────────\n\n /**\n * Cover images rendered on canvas social/share surfaces. Public so\n * the share-card OG image is a stable CDN URL.\n */\n CANVAS_COVERS: \"Images/Canvas/Covers\",\n\n /**\n * Source images the user is editing in the image studio. Private —\n * these are the user's working files, NOT public render targets.\n * Outputs that the user explicitly publishes land elsewhere.\n */\n IMAGES_EDITED_SOURCES: \"Images/Edited/Sources\",\n\n // ── Hidden / ephemeral ─────────────────────────────────────────────────\n // All hidden roots live under \".matrx-tmp/\" so the tree has a single\n // ignorable folder rather than many. Callers that use these MUST delete\n // the file when done.\n\n /** Root for all ephemeral cloud-files work. Hidden in the tree. */\n TMP: \".matrx-tmp\",\n /** Short-lived audio files staged for URL-based transcription. */\n TMP_TRANSCRIPTS: \".matrx-tmp/transcripts\",\n /** Upload-in-progress staging (future use). */\n TMP_UPLOADS: \".matrx-tmp/uploads\",\n\n // ── System / infrastructure ────────────────────────────────────────────\n // Owned and populated by the Python backend (not the user). These rows\n // exist in `cld_files` / `cld_folders` so they have asset IDs, but they\n // must NEVER appear in the user-facing tree.\n //\n // The Phase 1b/1c \"SOCIAL_BASELINE\" backfill (2026-05-16) created\n // `cld_files` rows under `system-files/variants/<file_id>/<og|thumb|tiny|page1_url>.jpg`\n // — three to four rows per source file. The cascade was cleaned up\n // server-side on 2026-05-16 (migrations 012/013); the tree RPCs now\n // exclude `parent_file_id IS NOT NULL` and `file_path LIKE\n // 'system-files/%'`. The FE keeps `isSystemPath` as a defensive guard\n // at every tree boundary (loadUserFileTree, loadFolderContents,\n // realtime middleware). See common-docs systems/files/file-service/WIRE_CONTRACT.md.\n\n /** Root for backend-owned infrastructure files (variants, posters, etc.). */\n SYSTEM_FILES: \"system-files\",\n /** SOCIAL_BASELINE variant storage: og.jpg / thumb.jpg / tiny.jpg / page1_url.jpg. */\n SYSTEM_VARIANTS: \"system-files/variants\",\n /**\n * Backend \"generations\" registry root — every AI generation (image,\n * video, audio/TTS) the server materializes lands under\n * `generations/<images|video|audio>/...`. Backend-owned; mirrors the\n * server's `is_system_path()` (which treats `system-files` AND\n * `generations` as system). Never shown in the user tree.\n */\n GENERATIONS: \"generations\",\n\n /**\n * Recorded audio captured by the Transcripts / voice features. As of\n * 2026-06-14 the backend relocates every `origin: \"transcripts\"` upload\n * here, UNDER the hidden `system-files/` root — one\n * `recording_<iso>_<rand>.webm` per capture (80+ for an active user).\n * Because it's under `system-files/`, `isSystemPath` already hides it\n * from the tree, folder views, AND Recents — no separate predicate\n * needed. Managed exclusively via the Transcripts UI (by `cld_files.id`).\n * See docs/files/transcript-recordings-system-relocation.md.\n */\n TRANSCRIPT_RECORDINGS: \"system-files/transcripts/Recordings\",\n\n /**\n * LEGACY user-namespace location for transcript recordings, before the\n * 2026-06-14 backend relocation to `system-files/transcripts/...`. Kept\n * ONLY as a defensive Recents guard: the backend relocates every\n * `origin: \"transcripts\"` upload, but the presigned/TUS (chunked + large\n * file) relocation path was genuinely missing and is committed but NOT yet\n * in prod as of 2026-06-15.\n *\n * DO NOT DROP THIS GUARD until that backend fix has DEPLOYED to prod —\n * dropping it earlier would let a chunked/large recording slip through\n * unhidden. Sequence: backend deploys → then remove this constant from\n * `isSystemManagedContentPath` (and delete it). See the FE-response /\n * \"open items\" in docs/files/transcript-recordings-system-relocation.md.\n */\n TRANSCRIPT_RECORDINGS_LEGACY: \"Transcripts/Recordings\",\n\n // ── System-managed user content (browsable, but NOT in Recents) ─────────\n // Lives under USER roots (so it stays visible in the Files browser), but\n // is machine-named, high-volume, and background-produced — so it must\n // never pollute the Recents stream (your \"entire reality\" on open).\n\n /**\n * Per-tool generated image variants — `tool-images/<id>/v/<name>.jpg`,\n * multiple sizes per source. Machine-produced output, excluded from\n * Recents (see `isSystemManagedContentPath`).\n */\n TOOL_IMAGES: \"tool-images\",\n\n /**\n * FastFire voice-drill recordings — full-session + per-card response clips.\n * Live under the hidden `system-files/fastfire/...` root (same class as\n * transcript recordings). Managed via Education / FastFire UI only.\n */\n SYSTEM_FASTFIRE: \"system-files/fastfire\",\n SYSTEM_FASTFIRE_SESSIONS: \"system-files/fastfire/sessions\",\n SYSTEM_FASTFIRE_RESPONSES: \"system-files/fastfire/responses\",\n\n /**\n * Spoken Practice (oral exam / interview / debate) recordings — full-session\n * clips + per-prompt spoken-answer clips. Same hidden `system-files/` class as\n * FastFire (so `isSystemPath` keeps them out of the Files browser + Recents).\n */\n SYSTEM_SPOKEN_PRACTICE: \"system-files/spoken-practice\",\n SYSTEM_SPOKEN_PRACTICE_SESSIONS: \"system-files/spoken-practice/sessions\",\n SYSTEM_SPOKEN_PRACTICE_RESPONSES: \"system-files/spoken-practice/responses\",\n\n /**\n * Handwritten / image-answer grading — photos of worked problems a learner\n * submits to the vision grader (assessment written-item photo answers +\n * the standalone \"Grade my handwritten work\" surface). Same hidden\n * `system-files/` class (kept out of the Files browser + Recents).\n */\n SYSTEM_IMAGE_GRADE: \"system-files/image-grade\",\n SYSTEM_IMAGE_GRADE_RESPONSES: \"system-files/image-grade/responses\",\n\n /**\n * LEGACY user-namespace FastFire paths (pre-2026-07 relocation). Kept as a\n * defensive tree + Recents guard until every row is backfilled under\n * `system-files/fastfire/`.\n */\n FASTFIRE_SESSIONS: \"FastFire/sessions\",\n FASTFIRE_RESPONSES: \"FastFire/responses\",\n} as const;\n\n// ---------------------------------------------------------------------------\n// Dynamic folder builders — for entity-scoped subfolders.\n// ---------------------------------------------------------------------------\n\n/**\n * Files attached to a specific task.\n * folderForTask(\"abc-123\") → \"Task Attachments/abc-123\"\n */\nexport function folderForTask(taskId: string): string {\n return `${CloudFolders.TASK_ATTACHMENTS}/${taskId}`;\n}\n\n/**\n * Files attached to a specific War Room tile.\n * folderForWarRoomThread(\"abc-123\") → \"War Room/abc-123\"\n */\nexport function folderForWarRoomThread(threadId: string): string {\n return `${CloudFolders.WAR_ROOM}/${threadId}`;\n}\n\n/**\n * Files attached to a specific chat / conversation.\n * folderForConversation(\"xyz\") → \"Chat Attachments/xyz\"\n */\nexport function folderForConversation(conversationId: string): string {\n return `${CloudFolders.CHAT_ATTACHMENTS}/${conversationId}`;\n}\n\n/**\n * Assets for a specific agent app (favicon, icons, etc.).\n * folderForAgentApp(\"abc\") → \"Agent Apps/abc\"\n */\nexport function folderForAgentApp(appId: string): string {\n return `${CloudFolders.AGENT_APPS}/${appId}`;\n}\n\n/**\n * Per-podcast episode assets.\n */\nexport function folderForPodcast(podcastId: string): string {\n return `${CloudFolders.AUDIO_PODCASTS}/${podcastId}`;\n}\n\n/**\n * Per-org shared assets.\n * folderForOrg(\"org-abc\") → \"Shared Assets/orgs/org-abc\"\n */\nexport function folderForOrg(orgId: string): string {\n return `${CloudFolders.SHARED_ASSETS_ORGS}/${orgId}`;\n}\n\n/**\n * Per-agent-block assets (icons, illustrations, attached media).\n * folderForAgentBlock(\"blk_123\") → \"Agent Apps/blocks/blk_123\"\n */\nexport function folderForAgentBlock(blockId: string): string {\n return `${CloudFolders.AGENT_BLOCKS}/${blockId}`;\n}\n\n/** Per-org capture subtree. Org id in the path keeps each workspace's\n * captures a DISTINCT global folder path (the server allows one folder\n * path per user, pinned to one org — a flat `Captures/Videos` cannot exist\n * under two orgs). Falls back to the flat path when there is no active org\n * (personal context).\n *\n * Nested output still resolves to `personal` visibility: the\n * `resolveDefaultVisibility` rule keys on the `Captures` prefix (a\n * longest-prefix match), so `Captures/<org>/Videos` matches the same rule as\n * the flat `Captures/Videos`. The org id in the path is filing, not access —\n * personal-visibility files stay owner-gated regardless of org. */\nexport function folderForCaptures(\n kind: \"photo\" | \"video\" | \"audio\",\n orgId?: string | null,\n): string {\n const leaf = kind === \"photo\" ? \"Photos\" : kind === \"video\" ? \"Videos\" : \"Audio\";\n const trimmed = typeof orgId === \"string\" ? orgId.trim() : \"\";\n if (trimmed) {\n return `${CloudFolders.CAPTURES}/${trimmed}/${leaf}`;\n }\n // No active org (personal context) — the flat/legacy path.\n return kind === \"photo\"\n ? CloudFolders.CAPTURES_PHOTOS\n : kind === \"video\"\n ? CloudFolders.CAPTURES_VIDEOS\n : CloudFolders.CAPTURES_AUDIO;\n}\n\n/** Per-item product-capture folder: `Product Captures/<orgId>/<leaf>`.\n * `leaf` is the item's sanitized code (the QR value / SKU) when known at\n * creation, else the item id — set ONCE at item creation and never renamed.\n * Org id in the path for the same one-path-one-org server rule as\n * `folderForCaptures`. Files here upload with explicit `visibility:\n * \"internal\"` (org-wide access is the point of the surface), so the\n * `resolveDefaultVisibility` prefix rules are deliberately not consulted. */\nexport function folderForProductCaptureItem(orgId: string, leaf: string): string {\n // Folder path segments: a scanned QR can carry separators/reserved chars --\n // collapse anything unsafe to single dashes. Callers pass the item id when\n // the code sanitizes to nothing.\n const safe = leaf\n .replace(/[^A-Za-z0-9._@-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return `${CloudFolders.PRODUCT_CAPTURES}/${orgId.trim()}/${safe}`;\n}\n\n/**\n * Commerce-intake artifact folder for one asset (or the batch-level stream in\n * untracked mode — pass the batch id as `leaf`). Fixed at creation, NEVER\n * renamed — a QR/serial that arrives later lives on identifier rows only\n * (PROTOTYPE-CONCEPTS P13: the cloud path is never renamed).\n */\nexport function folderForIntakeAsset(\n orgId: string,\n batchId: string,\n leaf: string,\n): string {\n const safe = leaf.replace(/[^A-Za-z0-9._@-]+/g, \"-\").replace(/^-+|-+$/g, \"\");\n return `${CloudFolders.COMMERCE_INTAKE}/${orgId.trim()}/${batchId.trim()}/${safe || batchId.trim()}`;\n}\n\n// ---------------------------------------------------------------------------\n// Predicates\n// ---------------------------------------------------------------------------\n\n/** True if the folder is under `.matrx-tmp/` (user-hidden). */\nexport function isHiddenFolder(folderPath: string): boolean {\n return (\n folderPath === CloudFolders.TMP || folderPath.startsWith(\".matrx-tmp/\")\n );\n}\n\n/**\n * True if `path` (a `cld_files.file_path` or `cld_folders.folder_path`)\n * points at a backend-owned system / infrastructure row that must NEVER\n * surface in the user's tree.\n *\n * Today this covers:\n * - `system-files` / `system-files/...` — backfilled SOCIAL_BASELINE\n * variant rows (og/thumb/tiny/page1_url) and their per-source-file\n * folders. ~3–4 rows per uploaded image, ~10k+ for active accounts.\n * - `generations` / `generations/...` — the backend AI-generation\n * registry root (image/video/audio output). Mirrors the server's\n * `is_system_path()`, which treats BOTH `system-files` and\n * `generations` as system; the tree RPC already drops these, this is\n * the FE-side parity guard at every other tree boundary.\n * - `.matrx-tmp` / `.matrx-tmp/...` — ephemeral staging the user\n * shouldn't see or manage.\n *\n * The predicate is intentionally path-based (not `derivation_kind` or\n * `parent_file_id`) because the Python backfill didn't populate those\n * fields on variant rows. Once they do, we'll add data-shape signals\n * here and drop the path heuristic.\n *\n * Pass either a file path or a folder path — both follow the same\n * convention (system paths are prefix-rooted).\n */\nexport function isSystemPath(path: string | null | undefined): boolean {\n if (!path) return false;\n return (\n path === CloudFolders.SYSTEM_FILES ||\n path.startsWith(`${CloudFolders.SYSTEM_FILES}/`) ||\n path === CloudFolders.GENERATIONS ||\n path.startsWith(`${CloudFolders.GENERATIONS}/`) ||\n path === CloudFolders.TMP ||\n path.startsWith(`${CloudFolders.TMP}/`)\n );\n}\n\n/**\n * THE VISIBILITY RULE IS THE DATABASE'S, NOT THIS FILE'S.\n *\n * `isHiddenFromUserTree()` and `isFastFirePath()` used to live here and were a\n * SECOND copy of the server's rule — the browser hid top-level `FastFire/**`\n * that the server called user-visible, so the sync daemon wrote those bytes to\n * disk while the browser refused to show them (folder-sync DECISIONS D16,\n * SPEC-SERVER §1.4 consumer 2). They are deleted.\n *\n * Rows that arrive through `get_user_file_tree` are already filtered by\n * `files.is_user_visible_path` — never filter them again. Realtime payloads,\n * which bypass the RPC, use the parity-tested mirror in\n * `features/files/utils/user-visible.ts`.\n */\n\n/**\n * RECENTS IS THE DATABASE'S RULE TOO. `isExcludedFromRecents`,\n * `isGeneratedContentPath` and `isSystemManagedContentPath` lived here as a\n * client-only Recents rule; they are deleted (2026-09-24). Their roots moved\n * into the one declaration (`files.is_recent_activity*`, aidream\n * matrx_files/user_visible.py RECENT_EXCLUDED_ROOTS) and the browser applies\n * its parity-guarded mirror, `isRecentActivityFile` / `isRecentActivityPath`\n * in `features/files/utils/user-visible.ts`. Rule + registry: common-docs\n * systems/files/file-service/USER_FILES_VS_MACHINE_FILES.md.\n */\n\n/**\n * True if the folder path matches one of our canonical conventions (either\n * visible or hidden). Useful for UI that wants to show a pretty icon next\n * to known folders.\n */\nexport function isConventionalFolder(folderPath: string): boolean {\n const all = Object.values(CloudFolders) as string[];\n return all.includes(folderPath);\n}\n\n// ---------------------------------------------------------------------------\n// Reverse-lookup helpers — used by e.g. FileIcon to render a special badge\n// for well-known folders.\n// ---------------------------------------------------------------------------\n\n/**\n * Maps a CloudFolders constant → human-friendly description for tooltips /\n * empty states. Extend as needed.\n */\nexport const CloudFolderDescriptions: Record<string, string> = {\n [CloudFolders.IMAGES]: \"All your images, organized.\",\n [CloudFolders.IMAGES_CHAT]: \"Images shared in chat.\",\n [CloudFolders.IMAGES_SCREENSHOTS]: \"Screenshots you pasted or dragged in.\",\n [CloudFolders.IMAGES_AVATARS]: \"Profile pictures and avatars.\",\n [CloudFolders.IMAGES_GENERATED]: \"AI-generated images.\",\n [CloudFolders.AUDIO]: \"Audio files.\",\n [CloudFolders.AUDIO_RECORDINGS]: \"Voice recordings.\",\n [CloudFolders.AUDIO_PODCASTS]: \"Podcast assets.\",\n [CloudFolders.CAPTURES]: \"Photos, videos, and audio captured in the app.\",\n [CloudFolders.CAPTURES_PHOTOS]: \"Photos taken with the in-app camera.\",\n [CloudFolders.CAPTURES_VIDEOS]: \"Videos recorded with the in-app camera.\",\n [CloudFolders.CAPTURES_AUDIO]: \"Audio recorded in the Capture Studio.\",\n [CloudFolders.APP_ASSETS]: \"Static app assets shared across the platform.\",\n [CloudFolders.DOCUMENTS]: \"Documents and reports.\",\n [CloudFolders.DOCUMENTS_PDFS]: \"PDFs.\",\n [CloudFolders.CODE]: \"Code files.\",\n [CloudFolders.GENERATED]: \"Files produced by AI tools.\",\n [CloudFolders.AGENT_APPS]: \"Assets attached to your agent apps.\",\n [CloudFolders.TASK_ATTACHMENTS]: \"Files attached to tasks.\",\n [CloudFolders.CHAT_ATTACHMENTS]: \"Files shared in conversations.\",\n [CloudFolders.SLACK_IMPORTS]: \"Files imported from Slack.\",\n [CloudFolders.SCRAPED_CONTENT]: \"Captures from the web scraper.\",\n [CloudFolders.SHARED_ASSETS_ORGS]: \"Organization-scoped shared assets.\",\n [CloudFolders.HTML_PAGES_OG]: \"OG covers for HTML pages.\",\n [CloudFolders.PROMPT_APPS_FAVICONS]: \"Favicons for prompt-app pages.\",\n [CloudFolders.AGENT_BLOCKS]: \"Per-block agent app assets.\",\n [CloudFolders.CANVAS_COVERS]: \"Canvas social cover images.\",\n [CloudFolders.IMAGES_EDITED_SOURCES]: \"Source images for the image studio.\",\n [CloudFolders.TMP]: \"Internal temporary workspace (hidden).\",\n};\n\n// ---------------------------------------------------------------------------\n// Default visibility per folder\n//\n// Source of truth for \"what visibility should this upload land with?\" when\n// the caller hasn't picked one explicitly. Order matters — we longest-prefix\n// match against `folderPath` so e.g. `Shared Assets/feedback-images` wins\n// over a generic `Shared Assets/` rule.\n//\n// Public defaults are for content rendered on public pages or shared\n// surfaces (logos, podcasts, app icons, feedback screenshots that admin\n// reviews). Private defaults are for user-scoped content (chat, task,\n// ephemeral). When in doubt, default to private and let the caller opt in.\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_VISIBILITY_RULES: ReadonlyArray<{\n prefix: string;\n visibility: Visibility;\n}> = [\n // Most-specific rules first — longest-prefix wins.\n { prefix: \"Shared Assets/feedback-images\", visibility: \"public\" },\n { prefix: CloudFolders.SHARED_ASSETS_ORGS, visibility: \"public\" },\n { prefix: CloudFolders.HTML_PAGES_OG, visibility: \"public\" },\n { prefix: CloudFolders.PROMPT_APPS_FAVICONS, visibility: \"public\" },\n { prefix: CloudFolders.AGENT_BLOCKS, visibility: \"public\" },\n { prefix: CloudFolders.CANVAS_COVERS, visibility: \"public\" },\n { prefix: CloudFolders.APP_ASSETS, visibility: \"public\" },\n { prefix: CloudFolders.IMAGES_AVATARS, visibility: \"public\" },\n { prefix: CloudFolders.AUDIO_PODCASTS, visibility: \"public\" },\n { prefix: CloudFolders.AGENT_APPS, visibility: \"public\" },\n { prefix: \"Shared Assets\", visibility: \"public\" },\n\n // IMAGES_EDITED_SOURCES is private — these are the user's working\n // source files for the image studio, not public render targets.\n // Captures are the user's own camera/mic output — never public render\n // targets. Explicit rule (not just the fallback) so the intent is recorded.\n { prefix: CloudFolders.CAPTURES, visibility: \"personal\" },\n { prefix: CloudFolders.IMAGES_EDITED_SOURCES, visibility: \"personal\" },\n { prefix: CloudFolders.IMAGES_GENERATED, visibility: \"personal\" },\n { prefix: CloudFolders.CHAT_ATTACHMENTS, visibility: \"personal\" },\n { prefix: CloudFolders.TASK_ATTACHMENTS, visibility: \"personal\" },\n { prefix: CloudFolders.WAR_ROOM, visibility: \"personal\" },\n { prefix: CloudFolders.SLACK_IMPORTS, visibility: \"personal\" },\n { prefix: CloudFolders.SCRAPED_CONTENT, visibility: \"personal\" },\n { prefix: \"Private Assets\", visibility: \"personal\" },\n { prefix: CloudFolders.TMP, visibility: \"personal\" },\n];\n\n/**\n * Resolve the default visibility for a given folder path. Longest-prefix\n * match against `DEFAULT_VISIBILITY_RULES`; falls back to `\"personal\"` for\n * any folder not in the table. Use at upload sites that don't have an\n * obvious context-driven choice.\n */\nexport function resolveDefaultVisibility(folderPath: string): Visibility {\n const normalized = folderPath.replace(/^\\/+|\\/+$/g, \"\");\n let best: { prefix: string; visibility: Visibility } | null = null;\n for (const rule of DEFAULT_VISIBILITY_RULES) {\n if (\n normalized === rule.prefix ||\n normalized.startsWith(`${rule.prefix}/`)\n ) {\n if (!best || rule.prefix.length > best.prefix.length) {\n best = rule;\n }\n }\n }\n return best?.visibility ?? \"personal\";\n}\n","import { CloudFolders } from \"../../utils/folder-conventions\";\n\nconst TOP_LEVEL_FOLDERS: Readonly<Record<string, string>> = {\n userContent: \"My Files\",\n images: CloudFolders.IMAGES,\n Images: CloudFolders.IMAGES,\n audio: CloudFolders.AUDIO,\n Audio: CloudFolders.AUDIO,\n \"audio-recordings\": CloudFolders.AUDIO_RECORDINGS,\n documents: CloudFolders.DOCUMENTS,\n Documents: CloudFolders.DOCUMENTS,\n code: CloudFolders.CODE,\n Code: CloudFolders.CODE,\n \"any-file\": \"Uploads\",\n attachments: CloudFolders.CHAT_ATTACHMENTS,\n};\n\n/** Compose a canonical Files folder path from an optional logical root. */\nexport function composeUploadFolderPath(\n root: string = \"Uploads\",\n path?: string,\n): string {\n const top = (TOP_LEVEL_FOLDERS[root] ?? root).replace(/^\\/+|\\/+$/g, \"\");\n const sub = (path ?? \"\").replace(/^\\/+|\\/+$/g, \"\");\n return sub ? `${top}/${sub}` : top;\n}\n","/**\n * Shared bounded registry for ephemeral `URL.createObjectURL` blobs.\n *\n * Consumers that create local blob URLs use this primitive so previews cannot\n * leak memory without bound. Explicit cleanup remains preferred; the global\n * ceiling is a final safety net for callers that no longer own their URL.\n */\n\nconst MAX_LIVE = 256;\nconst live = new Map<string, true>();\n\n/** Create a tracked object URL; evicts the oldest if over the cap. */\nexport function createTrackedObjectUrl(blob: Blob): string {\n const url = URL.createObjectURL(blob);\n live.set(url, true);\n while (live.size > MAX_LIVE) {\n const oldest = live.keys().next().value as string | undefined;\n if (!oldest) break;\n live.delete(oldest);\n try {\n URL.revokeObjectURL(oldest);\n } catch {\n // The browser may already have revoked an invalid URL.\n }\n }\n return url;\n}\n\n/** Explicitly revoke a tracked URL when a consumer knows it is finished. */\nexport function revokeTrackedObjectUrl(url: string | undefined | null): void {\n if (!url || !live.has(url)) return;\n live.delete(url);\n try {\n URL.revokeObjectURL(url);\n } catch {\n // The browser may already have revoked an invalid URL.\n }\n}\n"],"mappings":"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","names":["block","block"]}