@ai-matrx/media 0.11.0 → 0.13.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.
- package/CHANGELOG.md +22 -0
- package/dist/files/engine/db-types.d.ts +3 -50128
- package/dist/files/engine/filesDb.d.ts +168 -168
- package/dist/files/engine/handler/utils/python-base.d.ts +2 -13
- package/dist/files/engine/handler/utils/python-base.js +2 -2
- package/dist/files/engine/handler/utils/python-base.js.map +1 -1
- package/dist/files/engine/host/supabase.d.ts +231 -214
- package/dist/files/engine/upload/tusUpload.d.ts +9 -54
- package/dist/files/engine/upload/tusUpload.js +29 -221
- package/dist/files/engine/upload/tusUpload.js.map +1 -1
- package/dist/files/engine/upload/uploadDedupGuard.d.ts +1 -58
- package/dist/files/engine/upload/uploadDedupGuard.js +5 -35
- package/dist/files/engine/upload/uploadDedupGuard.js.map +1 -1
- package/package.json +5 -6
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
* `createShareLink` in `@/utils/permissions/shareLinks` — the landing page is
|
|
23
23
|
* `/s/{token}` and the clean byte endpoint is Python's `/share/{token}`.
|
|
24
24
|
*/
|
|
25
|
+
import { type FileUrls } from "@ai-matrx/data/files";
|
|
26
|
+
export type { FileUrls };
|
|
25
27
|
export declare function pythonBaseUrl(): string;
|
|
26
28
|
export interface ShareUrls {
|
|
27
29
|
/**
|
|
@@ -72,19 +74,6 @@ export declare function shareChildFileUrls(token: string, fileId: string, opts?:
|
|
|
72
74
|
* single canonical embeddable URL.
|
|
73
75
|
*/
|
|
74
76
|
export declare function pythonShareUrl(token: string): string;
|
|
75
|
-
export interface FileUrls {
|
|
76
|
-
/**
|
|
77
|
-
* Authenticated direct-download endpoint. CORS-safe for `fetch()`.
|
|
78
|
-
* Returns bytes with `Content-Disposition: attachment` so a `<a>`
|
|
79
|
-
* click triggers a download.
|
|
80
|
-
*/
|
|
81
|
-
download: string;
|
|
82
|
-
/**
|
|
83
|
-
* Authenticated inline endpoint — same bytes, `Content-Disposition:
|
|
84
|
-
* inline` so the URL works as `<img src>`, `<video src>`, etc.
|
|
85
|
-
*/
|
|
86
|
-
inline: string;
|
|
87
|
-
}
|
|
88
77
|
/**
|
|
89
78
|
* Build every URL variant for a cld_files file id in one call. Cheap —
|
|
90
79
|
* just string concatenation. These are DURABLE URLs: they never expire and
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildFileUrls, shareUrl as packageShareUrl } from "@ai-matrx/data/files";
|
|
2
2
|
import { resolveFilesBaseUrl } from "../../host/python-client.js";
|
|
3
3
|
import { shareLinkUrl } from "../../host/share-links.js";
|
|
4
4
|
function pythonBaseUrl() {
|
|
@@ -22,7 +22,7 @@ function pythonShareUrl(token) {
|
|
|
22
22
|
return shareUrls(token).public;
|
|
23
23
|
}
|
|
24
24
|
function fileUrls(fileId) {
|
|
25
|
-
return
|
|
25
|
+
return buildFileUrls(pythonBaseUrl(), fileId);
|
|
26
26
|
}
|
|
27
27
|
const AUTHENTICATED_FILE_BYTES_RE = /\/files\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\/download(?:[?#]|$)/i;
|
|
28
28
|
function isAuthenticatedFileBytesUrl(url) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/files/engine/handler/utils/python-base.ts"],"sourcesContent":["/**\n * features/files/handler/utils/python-base.ts\n *\n * Resolve Python backend URLs for direct browser → Python file traffic.\n * The handler emits URLs that point at Python, never at Next.js — there\n * is no server-side file handler in this app and no `/app/api/*` proxy\n * involvement.\n *\n * Design note — \"all variants in one object\":\n * Python exposes the same bytes via slightly-different URLs (inline vs\n * attachment) and the FE has a share landing page. Rather than add a new\n * function for every future tweak, the canonical builders here\n * (`shareUrls`, `fileUrls`) return ALL the variants up front and let the\n * caller pick. Single spelling for \"everything you can do with a\n * token / file id.\"\n *\n * Single-string helpers (`pythonShareUrl`, `pythonFileDownloadUrl`,\n * `pythonFileInlineUrl`) are kept as thin wrappers so existing callers\n * don't churn. Prefer the object form in new code.\n *\n * Tokens are CANONICAL share-link tokens (`platform.share_links`), minted via\n * `createShareLink` in `@/utils/permissions/shareLinks` — the landing page is\n * `/s/{token}` and the clean byte endpoint is Python's `/share/{token}`.\n */\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../../src/files/engine/handler/utils/python-base.ts"],"sourcesContent":["/**\n * features/files/handler/utils/python-base.ts\n *\n * Resolve Python backend URLs for direct browser → Python file traffic.\n * The handler emits URLs that point at Python, never at Next.js — there\n * is no server-side file handler in this app and no `/app/api/*` proxy\n * involvement.\n *\n * Design note — \"all variants in one object\":\n * Python exposes the same bytes via slightly-different URLs (inline vs\n * attachment) and the FE has a share landing page. Rather than add a new\n * function for every future tweak, the canonical builders here\n * (`shareUrls`, `fileUrls`) return ALL the variants up front and let the\n * caller pick. Single spelling for \"everything you can do with a\n * token / file id.\"\n *\n * Single-string helpers (`pythonShareUrl`, `pythonFileDownloadUrl`,\n * `pythonFileInlineUrl`) are kept as thin wrappers so existing callers\n * don't churn. Prefer the object form in new code.\n *\n * Tokens are CANONICAL share-link tokens (`platform.share_links`), minted via\n * `createShareLink` in `@/utils/permissions/shareLinks` — the landing page is\n * `/s/{token}` and the clean byte endpoint is Python's `/share/{token}`.\n */\n\nimport { buildFileUrls, shareUrl as packageShareUrl, type FileUrls } from \"@ai-matrx/data/files\";\n\nexport type { FileUrls };\nimport { resolveFilesBaseUrl } from \"../../host/python-client\";\nimport { shareLinkUrl } from \"../../host/share-links\";\n\nexport function pythonBaseUrl(): string {\n return resolveFilesBaseUrl();\n}\n\n// ---------------------------------------------------------------------------\n// Share-link URLs (token-based, public, no auth)\n// ---------------------------------------------------------------------------\n\nexport interface ShareUrls {\n /**\n * Canonical clean public URL with `inline` Content-Disposition (the default).\n * Works as `<img src>`, `<video src>`, `<audio src>`, PDF preview, or a\n * normal browser link a recipient can paste anywhere.\n *\n * Image / video / audio / PDF render inline. Dangerous types\n * (HTML, SVG, JS) are forced to `attachment` server-side.\n */\n public: string;\n /**\n * Explicit download endpoint with `?inline=false` — forces\n * `Content-Disposition: attachment` so the browser triggers a\n * download dialog instead of rendering inline. Use for \"Save As…\"\n * style affordances on images / PDFs.\n */\n attachment: string;\n /**\n * The canonical share landing page on the FE — `/s/{token}` (metadata via\n * the `resolve_share_token` RPC + preview + download button). Useful as a\n * clickable link in chat / email / docs; NOT a media src.\n */\n page: string;\n}\n\n/**\n * Build every URL variant for a share token in one call. Cheap —\n * just string concatenation, no I/O.\n */\nexport function shareUrls(\n token: string,\n opts?: { appOrigin?: string },\n): ShareUrls {\n const t = encodeURIComponent(token);\n // The URL grammar is @ai-matrx/data/files'; the host only binds the base.\n const base = packageShareUrl(pythonBaseUrl(), token);\n return {\n public: base,\n attachment: `${base}/download?inline=false`,\n page: opts?.appOrigin\n ? `${opts.appOrigin.replace(/\\/$/, \"\")}/s/${t}`\n : shareLinkUrl(t),\n };\n}\n\n/**\n * Byte URLs for ONE child file of a shared record — a shared chat's\n * attachment — reached with the parent's share token (access ladder T-19b).\n * The files service answers `/share/{token}/files/{fileId}` only when the file\n * is a child of the record that token shares; nothing else is reachable.\n */\nexport function shareChildFileUrls(\n token: string,\n fileId: string,\n opts?: { baseUrl?: string },\n): { inline: string; attachment: string } {\n const backend = (opts?.baseUrl ?? pythonBaseUrl()).replace(/\\/$/, \"\");\n const base = `${backend}/share/${encodeURIComponent(token)}/files/${encodeURIComponent(fileId)}`;\n return { inline: base, attachment: `${base}?inline=false` };\n}\n\n/**\n * Python's clean public byte-streaming share endpoint. Convenience wrapper\n * around `shareUrls(token).public` for callers that just want the\n * single canonical embeddable URL.\n */\nexport function pythonShareUrl(token: string): string {\n return shareUrls(token).public;\n}\n\n// ---------------------------------------------------------------------------\n// Authenticated file URLs (file-id, owner / shared-permission required)\n// ---------------------------------------------------------------------------\n\n\n/**\n * Build every URL variant for a cld_files file id in one call. Cheap —\n * just string concatenation. These are DURABLE URLs: they never expire and\n * carry only the file id. Auth is either an Authorization header on\n * `fetch()` (the python-client attaches it) or the `mx_files_session`\n * cookie for plain `<img>`/`<video>` bindings (see `../session.ts`).\n * `?inline=1` matches the exact spelling the backend emits on\n * `FileRecord.url`, keeping cache keys identical either way.\n */\nexport function fileUrls(fileId: string): FileUrls {\n // The URL grammar is @ai-matrx/data/files'; the host only binds the base.\n return buildFileUrls(pythonBaseUrl(), fileId);\n}\n\nconst AUTHENTICATED_FILE_BYTES_RE =\n /\\/files\\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\/download(?:[?#]|$)/i;\n\n/**\n * True for a durable `/files/{id}/download` URL (either host, either\n * spelling) — bytes that answer 401 unless the request carries the person's\n * Authorization header or the `mx_files_session` cookie. A consumer that\n * loads bytes with its own fetch (PDF.js) must never send one bare.\n */\nexport function isAuthenticatedFileBytesUrl(url: string | null | undefined): boolean {\n return !!url && AUTHENTICATED_FILE_BYTES_RE.test(url);\n}\n\n/** Single-URL convenience wrapper around `fileUrls(fileId).download`. */\nexport function pythonFileDownloadUrl(fileId: string): string {\n return fileUrls(fileId).download;\n}\n\n/** Single-URL convenience wrapper around `fileUrls(fileId).inline`. */\nexport function pythonFileInlineUrl(fileId: string): string {\n return fileUrls(fileId).inline;\n}\n\n// ---------------------------------------------------------------------------\n// URL classification + viewer-page derivation\n// ---------------------------------------------------------------------------\n\n/**\n * Match anything that ends in `/share/{token}` or `/share/{token}/download`\n * (with optional query string / hash) where `{token}` is a hex-ish string of\n * at least 8 chars (covers both UUIDs and shorter custom tokens). Used to\n * recognize URLs that we ourselves emitted via `shareUrls()` so we can\n * round-trip them back into a viewer URL.\n */\nconst SHARE_TOKEN_RE = /\\/share\\/([0-9a-f-]{8,})(?:\\/download)?(?:[/?#]|$)/i;\n\n/**\n * Extract the share token from any URL we recognize. Returns `null` for\n * URLs that aren't ours (opaque external and third-party URLs).\n */\nexport function tokenFromShareUrl(url: string): string | null {\n if (!url) return null;\n const match = url.match(SHARE_TOKEN_RE);\n return match ? match[1] : null;\n}\n\n/**\n * \"Best-effort viewer URL\" for any image / file URL we might have stored\n * in the database. The intent is what the user clicks when they want to\n * SEE the file (not download it):\n *\n * - Our bare `/share/{token}` (or legacy `/share/{token}/download`) URLs → the\n * canonical FE landing page at `${origin}/s/{token}` (metadata + preview\n * + download button). This is what an admin wants when they click a\n * screenshot in the feedback dialog.\n * - Anything else (external URLs) →\n * returned unchanged. Browsers render image bytes inline regardless,\n * and we have no viewer page for them anyway.\n */\nexport function imageViewUrl(\n url: string,\n opts?: { appOrigin?: string },\n): string {\n const token = tokenFromShareUrl(url);\n if (!token) return url;\n return shareUrls(token, opts).page;\n}\n"],"mappings":"AAyBA,SAAS,eAAe,YAAY,uBAAsC;AAG1E,SAAS,2BAA2B;AACpC,SAAS,oBAAoB;AAEtB,SAAS,gBAAwB;AACtC,SAAO,oBAAoB;AAC7B;AAmCO,SAAS,UACd,OACA,MACW;AACX,QAAM,IAAI,mBAAmB,KAAK;AAElC,QAAM,OAAO,gBAAgB,cAAc,GAAG,KAAK;AACnD,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,YAAY,GAAG,IAAI;AAAA,IACnB,MAAM,MAAM,YACR,GAAG,KAAK,UAAU,QAAQ,OAAO,EAAE,CAAC,MAAM,CAAC,KAC3C,aAAa,CAAC;AAAA,EACpB;AACF;AAQO,SAAS,mBACd,OACA,QACA,MACwC;AACxC,QAAM,WAAW,MAAM,WAAW,cAAc,GAAG,QAAQ,OAAO,EAAE;AACpE,QAAM,OAAO,GAAG,OAAO,UAAU,mBAAmB,KAAK,CAAC,UAAU,mBAAmB,MAAM,CAAC;AAC9F,SAAO,EAAE,QAAQ,MAAM,YAAY,GAAG,IAAI,gBAAgB;AAC5D;AAOO,SAAS,eAAe,OAAuB;AACpD,SAAO,UAAU,KAAK,EAAE;AAC1B;AAgBO,SAAS,SAAS,QAA0B;AAEjD,SAAO,cAAc,cAAc,GAAG,MAAM;AAC9C;AAEA,MAAM,8BACJ;AAQK,SAAS,4BAA4B,KAAyC;AACnF,SAAO,CAAC,CAAC,OAAO,4BAA4B,KAAK,GAAG;AACtD;AAGO,SAAS,sBAAsB,QAAwB;AAC5D,SAAO,SAAS,MAAM,EAAE;AAC1B;AAGO,SAAS,oBAAoB,QAAwB;AAC1D,SAAO,SAAS,MAAM,EAAE;AAC1B;AAaA,MAAM,iBAAiB;AAMhB,SAAS,kBAAkB,KAA4B;AAC5D,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,QAAQ,IAAI,MAAM,cAAc;AACtC,SAAO,QAAQ,MAAM,CAAC,IAAI;AAC5B;AAeO,SAAS,aACd,KACA,MACQ;AACR,QAAM,QAAQ,kBAAkB,GAAG;AACnC,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,UAAU,OAAO,IAAI,EAAE;AAChC;","names":[]}
|