@jini-ai/cms 0.3.4 → 0.3.6

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 (104) hide show
  1. package/README.md +22 -17
  2. package/dist/content-types/agent-tools.d.ts.map +1 -1
  3. package/dist/content-types/agent-tools.js +1 -1
  4. package/dist/content-types/agent-tools.js.map +1 -1
  5. package/dist/content-types/errors.d.ts +19 -1
  6. package/dist/content-types/errors.d.ts.map +1 -1
  7. package/dist/content-types/errors.js +22 -1
  8. package/dist/content-types/errors.js.map +1 -1
  9. package/dist/content-types/index-provisioning.d.ts +56 -10
  10. package/dist/content-types/index-provisioning.d.ts.map +1 -1
  11. package/dist/content-types/index-provisioning.js +86 -13
  12. package/dist/content-types/index-provisioning.js.map +1 -1
  13. package/dist/content-types/index.d.ts +15 -3
  14. package/dist/content-types/index.d.ts.map +1 -1
  15. package/dist/content-types/index.js +14 -2
  16. package/dist/content-types/index.js.map +1 -1
  17. package/dist/content-types/lifecycle.js +3 -3
  18. package/dist/content-types/lifecycle.js.map +1 -1
  19. package/dist/content-types/types.d.ts +64 -3
  20. package/dist/content-types/types.d.ts.map +1 -1
  21. package/dist/content-types/types.js +67 -3
  22. package/dist/content-types/types.js.map +1 -1
  23. package/dist/content-types/write-service.d.ts +18 -3
  24. package/dist/content-types/write-service.d.ts.map +1 -1
  25. package/dist/content-types/write-service.js +28 -2
  26. package/dist/content-types/write-service.js.map +1 -1
  27. package/dist/core/ports.d.ts +12 -2
  28. package/dist/core/ports.d.ts.map +1 -1
  29. package/dist/entries/field-validation.d.ts.map +1 -1
  30. package/dist/entries/field-validation.js +96 -1
  31. package/dist/entries/field-validation.js.map +1 -1
  32. package/dist/entries/write-service.d.ts +14 -0
  33. package/dist/entries/write-service.d.ts.map +1 -1
  34. package/dist/entries/write-service.js +2 -2
  35. package/dist/entries/write-service.js.map +1 -1
  36. package/dist/identity/admin-crud-service.d.ts +28 -0
  37. package/dist/identity/admin-crud-service.d.ts.map +1 -1
  38. package/dist/identity/admin-crud-service.js +30 -0
  39. package/dist/identity/admin-crud-service.js.map +1 -1
  40. package/dist/identity/auth-service.d.ts +32 -1
  41. package/dist/identity/auth-service.d.ts.map +1 -1
  42. package/dist/identity/auth-service.js +44 -15
  43. package/dist/identity/auth-service.js.map +1 -1
  44. package/dist/identity/index.d.ts +4 -1
  45. package/dist/identity/index.d.ts.map +1 -1
  46. package/dist/identity/index.js +4 -1
  47. package/dist/identity/index.js.map +1 -1
  48. package/dist/identity/seed.d.ts +14 -2
  49. package/dist/identity/seed.d.ts.map +1 -1
  50. package/dist/identity/seed.js +197 -45
  51. package/dist/identity/seed.js.map +1 -1
  52. package/dist/media/blob-store.fs.d.ts +7 -0
  53. package/dist/media/blob-store.fs.d.ts.map +1 -1
  54. package/dist/media/blob-store.fs.js +12 -2
  55. package/dist/media/blob-store.fs.js.map +1 -1
  56. package/dist/media/content-type-sniffer.d.ts +1 -1
  57. package/dist/media/content-type-sniffer.d.ts.map +1 -1
  58. package/dist/media/content-type-sniffer.js +52 -4
  59. package/dist/media/content-type-sniffer.js.map +1 -1
  60. package/dist/media/html-attributes.d.ts +90 -0
  61. package/dist/media/html-attributes.d.ts.map +1 -0
  62. package/dist/media/html-attributes.js +161 -0
  63. package/dist/media/html-attributes.js.map +1 -0
  64. package/dist/media/image-transformer.sharp.d.ts +35 -1
  65. package/dist/media/image-transformer.sharp.d.ts.map +1 -1
  66. package/dist/media/image-transformer.sharp.js +44 -2
  67. package/dist/media/image-transformer.sharp.js.map +1 -1
  68. package/dist/media/index.d.ts +2 -1
  69. package/dist/media/index.d.ts.map +1 -1
  70. package/dist/media/index.js +2 -1
  71. package/dist/media/index.js.map +1 -1
  72. package/dist/media/media-service.d.ts +93 -1
  73. package/dist/media/media-service.d.ts.map +1 -1
  74. package/dist/media/media-service.js +254 -7
  75. package/dist/media/media-service.js.map +1 -1
  76. package/dist/media/ports.d.ts +8 -1
  77. package/dist/media/ports.d.ts.map +1 -1
  78. package/dist/media/rendition-service.d.ts +7 -1
  79. package/dist/media/rendition-service.d.ts.map +1 -1
  80. package/dist/media/rendition-service.js +10 -4
  81. package/dist/media/rendition-service.js.map +1 -1
  82. package/dist/media/repo.memory.d.ts +4 -0
  83. package/dist/media/repo.memory.d.ts.map +1 -1
  84. package/dist/media/repo.memory.js +3 -0
  85. package/dist/media/repo.memory.js.map +1 -1
  86. package/dist/media/tool-registrations.d.ts +6 -2
  87. package/dist/media/tool-registrations.d.ts.map +1 -1
  88. package/dist/media/tool-registrations.js +19 -2
  89. package/dist/media/tool-registrations.js.map +1 -1
  90. package/dist/media/types.d.ts +26 -0
  91. package/dist/media/types.d.ts.map +1 -1
  92. package/dist/media/types.js.map +1 -1
  93. package/dist/navigation/agent-tools.d.ts.map +1 -1
  94. package/dist/navigation/agent-tools.js +8 -1
  95. package/dist/navigation/agent-tools.js.map +1 -1
  96. package/dist/navigation/index.d.ts +10 -1
  97. package/dist/navigation/index.d.ts.map +1 -1
  98. package/dist/navigation/index.js +10 -1
  99. package/dist/navigation/index.js.map +1 -1
  100. package/dist/navigation/menu-service.d.ts +60 -4
  101. package/dist/navigation/menu-service.d.ts.map +1 -1
  102. package/dist/navigation/menu-service.js +106 -8
  103. package/dist/navigation/menu-service.js.map +1 -1
  104. package/package.json +1 -1
@@ -0,0 +1,161 @@
1
+ /**
2
+ * @file Server-side allowlist for `MediaRecord.htmlAttributes` (2026-09-07) — the enforcement half
3
+ * of a validator that ALSO has a browser-side copy in Tovu's admin
4
+ * (`apps/admin/src/features/media/rules.ts`, `parseMediaHtmlAttributes` and friends).
5
+ *
6
+ * Deliberately duplicated, not shared via one imported module, for the same reason this codebase
7
+ * already hand-copies `DEFAULT_ALLOWED_MIME_TYPES` into Tovu's `FILE_HANDLER_ALLOWED_MIME_TYPES`/
8
+ * `IMPORTABLE_CONTENT_TYPES`: `@jini-ai/cms/media`'s barrel (`index.ts`) re-exports files that
9
+ * import real Node built-ins (`node:crypto` in `media-service.ts`, `node:fs` in
10
+ * `blob-store.fs.ts`, native `sharp` bindings in `image-transformer.sharp.ts`) — importing this
11
+ * subpath from a browser-bundled Vite app (Tovu's `apps/admin`) risks pulling those into the admin
12
+ * SPA's bundle even if only this one pure function is actually used, and this admin's own copy
13
+ * already exists, tested, with no such risk. This file is the copy every Node-side consumer
14
+ * (`media-service.ts`'s own `updateMediaMetadata`, and Tovu's `apps/website` render path, both pure
15
+ * backend code) can safely import from `@jini-ai/cms/media` instead of re-deriving the rules a
16
+ * third time.
17
+ *
18
+ * THE RULES THEMSELVES ARE NOT REDESIGNED HERE — this is a verbatim port of the admin copy's logic
19
+ * (allowlist membership, `on*`/`javascript:` precedence, the tokenizer, the four rejection reasons).
20
+ * Extend `MEDIA_HTML_ATTRIBUTE_ALLOWED_NAMES` in BOTH copies together if a new attribute is ever
21
+ * needed — that is the one piece of drift risk this duplication accepts, the same risk every other
22
+ * hand-copied list in this codebase already accepts.
23
+ *
24
+ * This is a SECURITY boundary, not a syntax convenience: media metadata is authored in Tovu's admin
25
+ * but rendered on the public site, so a free-text HTML-attribute passthrough is a stored-XSS vector
26
+ * (`onerror`, `onclick`, `style`, `href="javascript:"`, any `on*` handler) the moment it reaches a
27
+ * public page. A client-side-only check is not a control, since the API accepts whatever a caller
28
+ * sends — this file is what makes the write path (`updateMediaMetadata`) and the render path (a
29
+ * host's own tag-building code) actually enforce it, not just the admin form.
30
+ */
31
+ /**
32
+ * Exact-match attribute names the allowlist accepts beyond the open-ended `data-`/`aria-` prefix
33
+ * families (checked separately in {@link isAllowedMediaHtmlAttributeName}). Picked for the owner's
34
+ * stated near-term uses (animations, custom WebMCP hooks) plus the standard `<img>`/`<video>`
35
+ * attributes those uses actually need; extend this list, not the parser, when a new one is needed —
36
+ * and keep it in sync with the identical constant in Tovu's admin copy (see this file's header).
37
+ */
38
+ export const MEDIA_HTML_ATTRIBUTE_ALLOWED_NAMES = [
39
+ "loading",
40
+ "decoding",
41
+ "playsinline",
42
+ "muted",
43
+ "loop",
44
+ "autoplay",
45
+ "poster",
46
+ ];
47
+ /**
48
+ * The shape EVERY accepted attribute name must have, checked before allowlist membership
49
+ * (2026-09-07 stored-XSS fix; keep identical in the admin copy).
50
+ *
51
+ * The `data-`/`aria-` families below are open-ended by design — no fixed suffix list — so the
52
+ * prefix check alone accepted whatever characters {@link HTML_ATTRIBUTE_TOKEN}'s name class
53
+ * (`[^\s="']+`, which excludes only whitespace, `=` and quotes) let through. `<`, `>` and `/` are
54
+ * all legal in that class, and a renderer templating a name into ` name="value"` escapes only the
55
+ * VALUE — so a stored `data-x><svg/onload=alert(1)` closed the `<img>` and opened a live
56
+ * `<svg onload>` on the public page. Constraining the NAME to the characters a real HTML attribute
57
+ * name can contain is what makes "the value is escaped" sufficient: no accepted name can carry a
58
+ * character that terminates a tag or starts an attribute.
59
+ *
60
+ * Deliberately narrower than the HTML spec's own name production (which permits far more): this
61
+ * field exists for `data-*`/`aria-*` hooks and a short list of standard `<img>`/`<video>`
62
+ * attributes, every one of which fits `[a-z][a-z0-9-]*`. Widening this is a deliberate decision,
63
+ * not something a new allowlist entry should need.
64
+ */
65
+ const MEDIA_HTML_ATTRIBUTE_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
66
+ /** Whether `name` is on the allowlist — a well-formed attribute name
67
+ * ({@link MEDIA_HTML_ATTRIBUTE_NAME_PATTERN}) that is either an exact match against
68
+ * {@link MEDIA_HTML_ATTRIBUTE_ALLOWED_NAMES} or carries a `data-`/`aria-` prefix (both open-ended
69
+ * families with no fixed suffix list). Case-insensitive: HTML attribute names are themselves
70
+ * case-insensitive, and an operator typing `DATA-FOO` should not slip past a lowercase-only check.
71
+ *
72
+ * @complexity O(n) in the name's length (one anchored regex test), then O(1) — one prefix check,
73
+ * one fixed-length array lookup.
74
+ */
75
+ export function isAllowedMediaHtmlAttributeName(name) {
76
+ const lower = name.toLowerCase();
77
+ if (!MEDIA_HTML_ATTRIBUTE_NAME_PATTERN.test(lower))
78
+ return false;
79
+ if (lower.startsWith("data-") || lower.startsWith("aria-"))
80
+ return true;
81
+ return MEDIA_HTML_ATTRIBUTE_ALLOWED_NAMES.includes(lower);
82
+ }
83
+ /** Matches one `name`, or one `name="value"`/`name='value'`/`name=value` pair — the same loose
84
+ * shape real HTML attribute syntax allows, since that is the syntax an operator typing this field
85
+ * would naturally reach for. */
86
+ const HTML_ATTRIBUTE_TOKEN = /([^\s="']+)(?:=(?:"([^"]*)"|'([^']*)'|([^\s"']+)))?/g;
87
+ /** Classifies one already-tokenized `name`/`value` pair. Split out of {@link parseMediaHtmlAttributes}
88
+ * so each rejection reason is its own directly testable branch.
89
+ *
90
+ * Order matters: `on*`/`javascript:` are checked BEFORE allowlist membership, so a rejected
91
+ * `onerror="..."` always reports as `event-handler` (the more specific, more actionable reason)
92
+ * rather than the generic `disallowed-name`.
93
+ *
94
+ * @complexity O(1) — three fixed checks against one already-extracted token.
95
+ */
96
+ function classifyMediaHtmlAttributeToken(name, value) {
97
+ if (name.startsWith("on"))
98
+ return { reason: "event-handler", attribute: name };
99
+ if (value.trim().toLowerCase().startsWith("javascript:"))
100
+ return { reason: "javascript-url", attribute: name };
101
+ if (!isAllowedMediaHtmlAttributeName(name))
102
+ return { reason: "disallowed-name", attribute: name };
103
+ return null;
104
+ }
105
+ /**
106
+ * Parses the `htmlAttributes` field's free text (`name="value" name2="value2"`, or a bare boolean
107
+ * `name`) into a validated attribute map, rejecting anything not on the allowlist. Nothing here
108
+ * tries to sanitize or escape an otherwise-disallowed name into something safe — it is rejected
109
+ * outright, and the caller must show the reason (not silently drop it) so an operator can tell a
110
+ * typo from a hard "no".
111
+ *
112
+ * @complexity Time O(n) in `text`'s length (one regex pass over it), space O(k) for k parsed
113
+ * attributes.
114
+ */
115
+ export function parseMediaHtmlAttributes(text) {
116
+ const trimmed = text.trim();
117
+ if (trimmed === "")
118
+ return { attributes: {}, error: null };
119
+ const attributes = {};
120
+ HTML_ATTRIBUTE_TOKEN.lastIndex = 0;
121
+ let consumed = 0;
122
+ let match;
123
+ while ((match = HTML_ATTRIBUTE_TOKEN.exec(trimmed)) !== null) {
124
+ // Non-whitespace text between the previous match and this one is a fragment the token pattern
125
+ // could not parse as a name (e.g. a stray quote) — reported once, at the first gap, rather
126
+ // than silently skipped.
127
+ const skipped = trimmed.slice(consumed, match.index);
128
+ if (skipped.trim() !== "")
129
+ return { attributes: {}, error: { reason: "malformed", attribute: skipped.trim() } };
130
+ consumed = match.index + match[0].length;
131
+ const name = match[1].toLowerCase();
132
+ const value = match[2] ?? match[3] ?? match[4] ?? "";
133
+ const rejection = classifyMediaHtmlAttributeToken(name, value);
134
+ if (rejection)
135
+ return { attributes: {}, error: rejection };
136
+ attributes[name] = value;
137
+ }
138
+ const trailing = trimmed.slice(consumed);
139
+ if (trailing.trim() !== "")
140
+ return { attributes: {}, error: { reason: "malformed", attribute: trailing.trim() } };
141
+ return { attributes, error: null };
142
+ }
143
+ /** Formats a {@link MediaHtmlAttributeError} into a plain-English message naming the rejected
144
+ * attribute (owner requirement) — the server-side, non-localized counterpart to the admin's own
145
+ * `describeMediaHtmlAttributeError` (which additionally runs the message through `MEDIA_DICT` for
146
+ * the operator's locale). Domain errors elsewhere in this file (`MediaValidationError`'s other
147
+ * messages) are likewise always plain English, so this matches that existing convention rather
148
+ * than inventing a localized-error contract this service has never had.
149
+ *
150
+ * @complexity O(1).
151
+ */
152
+ export function describeMediaHtmlAttributeError(error) {
153
+ if (error.reason === "event-handler")
154
+ return `event handler attributes like '${error.attribute}' are not allowed`;
155
+ if (error.reason === "javascript-url")
156
+ return `'${error.attribute}' cannot use a javascript: value`;
157
+ if (error.reason === "malformed")
158
+ return `could not parse HTML attributes near '${error.attribute}'`;
159
+ return `'${error.attribute}' is not an allowed HTML attribute`;
160
+ }
161
+ //# sourceMappingURL=html-attributes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-attributes.js","sourceRoot":"","sources":["../../src/media/html-attributes.ts"],"names":[],"mappings":"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"}
@@ -24,8 +24,42 @@ export declare class ImageSourceCorruptError extends Error {
24
24
  * `params.format` (via `sharp().toFormat(...)`, always — re-encode is
25
25
  * unconditional).
26
26
  *
27
+ * Animated sources (multi-frame GIF/WebP/APNG): loaded with `{ animated: true }` whenever the
28
+ * target format can carry animation (`ANIMATION_CAPABLE_FORMATS`), so `.resize()` and `.toFormat()`
29
+ * operate on every frame instead of silently decoding only frame 0. This is safe to request
30
+ * unconditionally for a genuinely single-frame source too — verified empirically against this
31
+ * package's pinned `sharp@0.35.3`: a static image loaded with `{ animated: true }` produces
32
+ * byte-identical dimensions/output to loading it without the option (sharp resolves `nPages` to 1
33
+ * from the format's own page count, there is no multi-page metadata to read all of).
34
+ *
35
+ * When the target format CANNOT carry animation (jpeg/png), `{ animated: true }` is deliberately
36
+ * NOT passed — verified empirically that doing so anyway is worse than a plain flatten: sharp
37
+ * writes the whole multi-frame "toilet roll" (all frames stacked vertically) out as one tall,
38
+ * visibly-corrupted static image rather than either a clean single frame or a real animated
39
+ * output. Loading without the option keeps sharp's default single-page decode, which already
40
+ * yields a normal frame-0 still — a deliberate, now-documented flatten instead of an accident.
41
+ *
42
+ * Multi-frame resize correctness: `sharp`'s native pipeline is already page-height-aware — the
43
+ * `width`/`height` passed to `.resize()` are resolved against the PER-FRAME `pageHeight`, not the
44
+ * full multi-frame canvas, and the crop/scale math is applied identically per frame (verified with
45
+ * a 4-frame fixture and an aggressive mismatched-aspect crop — each frame's content stayed inside
46
+ * its own frame boundary). No special-cased width-only or manual `pageHeight` recomputation is
47
+ * needed here; adding one would be redundant with (and could conflict with) sharp's own handling.
48
+ *
49
+ * Resource bounds: sharp's default `limitInputPixels` (~268M px, unconditional, not raised by
50
+ * `{ animated: true }`) is checked against the FULL decoded canvas — for a multi-page load that
51
+ * means `width * (pageHeight * pages)`, i.e. total pixels across all frames combined, not per
52
+ * frame. Turning on `{ animated: true }` therefore does not remove or widen that ceiling. It does
53
+ * mean legitimate large animated files now do proportionally more decode/re-encode work than the
54
+ * previous (buggy) frame-0-only path — expected, since fully processing an animated file is the
55
+ * point of this fix — bounded on the input side by `DEFAULT_MAX_UPLOAD_BYTES` (10 MiB compressed)
56
+ * before any of these bytes ever reach this transformer.
57
+ *
27
58
  * @complexity O(pixels) — dominated by `sharp`'s native resize/encode work,
28
- * outside this function's control. Runs IN-PROCESS in this build (the
59
+ * outside this function's control. For an animated source this now scales with total pixels across
60
+ * ALL frames combined (previously just frame 0) — see "Resource bounds" above for why this widened
61
+ * cost is bounded by the same pre-existing `limitInputPixels`/upload-size caps rather than being an
62
+ * unbounded new surface. Runs IN-PROCESS in this build (the
29
63
  * out-of-process worker the original design calls for to protect the host from
30
64
  * `sharp` OOMing is explicitly out of scope for this task — see
31
65
  * `rendition-service.ts`'s file header).
@@ -1 +1 @@
1
- {"version":3,"file":"image-transformer.sharp.d.ts","sourceRoot":"","sources":["../../src/media/image-transformer.sharp.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAK9G,mGAAmG;AACnG,qBAAa,8BAA+B,SAAQ,KAAK;CAAG;AAE5D;;;;;;;;;;;;;GAaG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;CAAG;AAoCrD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,qBAAsB,YAAW,oBAAoB;IAC1D,SAAS,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAgC3E"}
1
+ {"version":3,"file":"image-transformer.sharp.d.ts","sourceRoot":"","sources":["../../src/media/image-transformer.sharp.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAM9G,mGAAmG;AACnG,qBAAa,8BAA+B,SAAQ,KAAK;CAAG;AAE5D;;;;;;;;;;;;;GAaG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;CAAG;AA4CrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,qBAAa,qBAAsB,YAAW,oBAAoB;IAC1D,SAAS,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAoC3E"}
@@ -49,6 +49,13 @@ export class ImageTransformUnavailableError extends Error {
49
49
  */
50
50
  export class ImageSourceCorruptError extends Error {
51
51
  }
52
+ /**
53
+ * {@link TransformFormat} values that can actually carry multiple frames on output. GIF and WebP
54
+ * both support animated re-encoding; JPEG and PNG do not (this build's plain libvips PNG writer
55
+ * does not emit APNG). Gates the `{ animated: true }` load option below — see that call site's
56
+ * comment for why loading animated but encoding to a non-animated format must NOT happen.
57
+ */
58
+ const ANIMATION_CAPABLE_FORMATS = new Set(["webp", "gif"]);
52
59
  /**
53
60
  * Lazily resolves the `sharp` module. See file header for why this is a
54
61
  * deferred, untyped `require()` (via `createRequire`) rather than a
@@ -75,8 +82,42 @@ function loadSharpFactory() {
75
82
  * `params.format` (via `sharp().toFormat(...)`, always — re-encode is
76
83
  * unconditional).
77
84
  *
85
+ * Animated sources (multi-frame GIF/WebP/APNG): loaded with `{ animated: true }` whenever the
86
+ * target format can carry animation (`ANIMATION_CAPABLE_FORMATS`), so `.resize()` and `.toFormat()`
87
+ * operate on every frame instead of silently decoding only frame 0. This is safe to request
88
+ * unconditionally for a genuinely single-frame source too — verified empirically against this
89
+ * package's pinned `sharp@0.35.3`: a static image loaded with `{ animated: true }` produces
90
+ * byte-identical dimensions/output to loading it without the option (sharp resolves `nPages` to 1
91
+ * from the format's own page count, there is no multi-page metadata to read all of).
92
+ *
93
+ * When the target format CANNOT carry animation (jpeg/png), `{ animated: true }` is deliberately
94
+ * NOT passed — verified empirically that doing so anyway is worse than a plain flatten: sharp
95
+ * writes the whole multi-frame "toilet roll" (all frames stacked vertically) out as one tall,
96
+ * visibly-corrupted static image rather than either a clean single frame or a real animated
97
+ * output. Loading without the option keeps sharp's default single-page decode, which already
98
+ * yields a normal frame-0 still — a deliberate, now-documented flatten instead of an accident.
99
+ *
100
+ * Multi-frame resize correctness: `sharp`'s native pipeline is already page-height-aware — the
101
+ * `width`/`height` passed to `.resize()` are resolved against the PER-FRAME `pageHeight`, not the
102
+ * full multi-frame canvas, and the crop/scale math is applied identically per frame (verified with
103
+ * a 4-frame fixture and an aggressive mismatched-aspect crop — each frame's content stayed inside
104
+ * its own frame boundary). No special-cased width-only or manual `pageHeight` recomputation is
105
+ * needed here; adding one would be redundant with (and could conflict with) sharp's own handling.
106
+ *
107
+ * Resource bounds: sharp's default `limitInputPixels` (~268M px, unconditional, not raised by
108
+ * `{ animated: true }`) is checked against the FULL decoded canvas — for a multi-page load that
109
+ * means `width * (pageHeight * pages)`, i.e. total pixels across all frames combined, not per
110
+ * frame. Turning on `{ animated: true }` therefore does not remove or widen that ceiling. It does
111
+ * mean legitimate large animated files now do proportionally more decode/re-encode work than the
112
+ * previous (buggy) frame-0-only path — expected, since fully processing an animated file is the
113
+ * point of this fix — bounded on the input side by `DEFAULT_MAX_UPLOAD_BYTES` (10 MiB compressed)
114
+ * before any of these bytes ever reach this transformer.
115
+ *
78
116
  * @complexity O(pixels) — dominated by `sharp`'s native resize/encode work,
79
- * outside this function's control. Runs IN-PROCESS in this build (the
117
+ * outside this function's control. For an animated source this now scales with total pixels across
118
+ * ALL frames combined (previously just frame 0) — see "Resource bounds" above for why this widened
119
+ * cost is bounded by the same pre-existing `limitInputPixels`/upload-size caps rather than being an
120
+ * unbounded new surface. Runs IN-PROCESS in this build (the
80
121
  * out-of-process worker the original design calls for to protect the host from
81
122
  * `sharp` OOMing is explicitly out of scope for this task — see
82
123
  * `rendition-service.ts`'s file header).
@@ -90,6 +131,7 @@ function loadSharpFactory() {
90
131
  export class SharpImageTransformer {
91
132
  async transform(input) {
92
133
  const sharpFactory = loadSharpFactory();
134
+ const preserveAnimation = ANIMATION_CAPABLE_FORMATS.has(input.params.format);
93
135
  // Pipeline construction through `toBuffer()` all live in one try/catch: any of these steps can
94
136
  // reject on bad SOURCE bytes (`sharp`'s decode is lazy — a malformed file often only surfaces
95
137
  // once a downstream operation like `toBuffer()` actually reads it), and every such rejection
@@ -97,7 +139,7 @@ export class SharpImageTransformer {
97
139
  // call in the chain actually threw. See {@link ImageSourceCorruptError}'s own doc for why this is
98
140
  // named/rethrown rather than left as an undifferentiated `sharp` error.
99
141
  try {
100
- let pipeline = sharpFactory(Buffer.from(input.bytes));
142
+ let pipeline = sharpFactory(Buffer.from(input.bytes), preserveAnimation ? { animated: true } : undefined);
101
143
  if (input.params.width !== undefined || input.params.height !== undefined) {
102
144
  pipeline = pipeline.resize(input.params.width, input.params.height, {
103
145
  fit: input.params.fit ?? "cover",
@@ -1 +1 @@
1
- {"version":3,"file":"image-transformer.sharp.js","sourceRoot":"","sources":["../../src/media/image-transformer.sharp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C,mGAAmG;AACnG,MAAM,OAAO,8BAA+B,SAAQ,KAAK;CAAG;AAE5D;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,uBAAwB,SAAQ,KAAK;CAAG;AAcrD;;;;;;;;GAQG;AACH,SAAS,gBAAgB;IACvB,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,OAAO,CAAiB,CAAC;IAC1C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,8BAA8B,CACtC,2FAA2F;YACzF,oFAAoF;YACpF,0FAA0F;YAC1F,qBAAqB,CACxB,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,qBAAqB;IAChC,KAAK,CAAC,SAAS,CAAC,KAA0B;QACxC,MAAM,YAAY,GAAG,gBAAgB,EAAE,CAAC;QAExC,+FAA+F;QAC/F,8FAA8F;QAC9F,6FAA6F;QAC7F,gGAAgG;QAChG,kGAAkG;QAClG,wEAAwE;QACxE,IAAI,CAAC;YACH,IAAI,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;YAEtD,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC1E,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE;oBAClE,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,OAAO;iBACjC,CAAC,CAAC;YACL,CAAC;YAED,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAClD,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAC;YAE5C,OAAO;gBACL,KAAK,EAAE,IAAI,UAAU,CAAC,SAAS,CAAC;gBAChC,WAAW,EAAE,sBAAsB,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;aACzD,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAChE,MAAM,IAAI,uBAAuB,CAC/B,oEAAoE,KAAK,CAAC,MAAM,CAAC,MAAM,OAAO,MAAM,EAAE,CACvG,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"image-transformer.sharp.js","sourceRoot":"","sources":["../../src/media/image-transformer.sharp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAI5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C,mGAAmG;AACnG,MAAM,OAAO,8BAA+B,SAAQ,KAAK;CAAG;AAE5D;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,uBAAwB,SAAQ,KAAK;CAAG;AAcrD;;;;;GAKG;AACH,MAAM,yBAAyB,GAAiC,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AAEzF;;;;;;;;GAQG;AACH,SAAS,gBAAgB;IACvB,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,OAAO,CAAiB,CAAC;IAC1C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,8BAA8B,CACtC,2FAA2F;YACzF,oFAAoF;YACpF,0FAA0F;YAC1F,qBAAqB,CACxB,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,MAAM,OAAO,qBAAqB;IAChC,KAAK,CAAC,SAAS,CAAC,KAA0B;QACxC,MAAM,YAAY,GAAG,gBAAgB,EAAE,CAAC;QACxC,MAAM,iBAAiB,GAAG,yBAAyB,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAE7E,+FAA+F;QAC/F,8FAA8F;QAC9F,6FAA6F;QAC7F,gGAAgG;QAChG,kGAAkG;QAClG,wEAAwE;QACxE,IAAI,CAAC;YACH,IAAI,QAAQ,GAAG,YAAY,CACzB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EACxB,iBAAiB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CACnD,CAAC;YAEF,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC1E,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE;oBAClE,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,OAAO;iBACjC,CAAC,CAAC;YACL,CAAC;YAED,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAClD,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAC;YAE5C,OAAO;gBACL,KAAK,EAAE,IAAI,UAAU,CAAC,SAAS,CAAC;gBAChC,WAAW,EAAE,sBAAsB,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;aACzD,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAChE,MAAM,IAAI,uBAAuB,CAC/B,oEAAoE,KAAK,CAAC,MAAM,CAAC,MAAM,OAAO,MAAM,EAAE,CACvG,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
@@ -15,12 +15,13 @@ export type { MediaStatus, MediaSource, MediaRecord, AssetBlobStatus, AssetBlobR
15
15
  export { MediaNotFoundError, MediaValidationError, MediaConflictError, MediaSourceImmutableError, MediaStillReferencedError, } from "./types.js";
16
16
  export type { MediaRepoPort, AssetBlobRepoPort, AssetRenditionRepoPort, BlobStorePort, BlobGcJournalRepoPort, PutBlobInput, TransformDefinitionRepoPort, } from "./ports.js";
17
17
  export { computeBlobStorageKey } from "./blob-key.js";
18
+ export { MEDIA_HTML_ATTRIBUTE_ALLOWED_NAMES, isAllowedMediaHtmlAttributeName, parseMediaHtmlAttributes, describeMediaHtmlAttributeError, type MediaHtmlAttributeRejectionReason, type MediaHtmlAttributeError, type ParsedMediaHtmlAttributes, } from "./html-attributes.js";
18
19
  export { InMemoryMediaRepo, InMemoryAssetBlobRepo, InMemoryAssetRenditionRepo, InMemoryBlobGcJournalRepo, InMemoryTransformDefinitionRepo, } from "./repo.memory.js";
19
20
  export { withSha256Lock } from "./blob-gc-lock.js";
20
21
  export { DEFAULT_GC_GRACE_MS, resolveGcGraceMs, isBlobUnreferenced, tombstoneBlobIfUnreferenced, runBlobGcDeletePass, runBlobGcUnlinkPass, runBlobGcCycle, runMonthlyOrphanSweepStub, } from "./blob-gc.js";
21
22
  export { InMemoryBlobStore } from "./blob-store.memory.js";
22
23
  export { LocalFsBlobStore, type LocalFsBlobStoreDeps } from "./blob-store.fs.js";
23
- export { DEFAULT_MAX_UPLOAD_BYTES, DEFAULT_ALLOWED_MIME_TYPES, resolveWriteOnceSource, uploadMedia, listMedia, getMediaById, updateMediaMetadata, trashMedia, purgeMedia, type UploadMediaInput, type UploadMediaDeps, type UpdateMediaMetadataInput, } from "./media-service.js";
24
+ export { DEFAULT_MAX_UPLOAD_BYTES, DEFAULT_ALLOWED_MIME_TYPES, resolveWriteOnceSource, uploadMedia, listMedia, getMediaById, findMediaByIdOrSlug, updateMediaMetadata, trashMedia, purgeMedia, type UploadMediaInput, type UploadMediaDeps, type UpdateMediaMetadataInput, type FindMediaByIdOrSlugRequired, } from "./media-service.js";
24
25
  export type { TransformFit, TransformFormat, TransformParams, TransformDefinitionRecord, } from "./transform-types.js";
25
26
  export { TransformValidationError, mimeForTransformFormat, MAX_TRANSFORM_DIMENSION_PX } from "./transform-types.js";
26
27
  export { withRenditionLock, withTransformRegistryLock } from "./transform-lock.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/media/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,YAAY,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,sBAAsB,EACtB,aAAa,EACb,qBAAqB,EACrB,YAAY,EACZ,2BAA2B,GAC5B,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,+BAA+B,GAChC,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,2BAA2B,EAC3B,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAEjF,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,WAAW,EACX,SAAS,EACT,YAAY,EACZ,mBAAmB,EACnB,UAAU,EACV,UAAU,EACV,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,wBAAwB,GAC9B,MAAM,oBAAoB,CAAC;AAS5B,YAAY,EACV,YAAY,EACZ,eAAe,EACf,eAAe,EACf,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAEpH,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAEnF,OAAO,EACL,iBAAiB,EACjB,4BAA4B,EAC5B,wBAAwB,EACxB,8BAA8B,EAC9B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,GAC3B,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,qBAAqB,EACrB,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,GACjC,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9G,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAElE,OAAO,EAAE,qBAAqB,EAAE,8BAA8B,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAO9H,OAAO,EAAE,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEtF,sGAAsG;AACtG,OAAO,EACL,qBAAqB,EACrB,KAAK,mBAAmB,IAAI,wBAAwB,EACpD,KAAK,mBAAmB,IAAI,wBAAwB,EACpD,KAAK,uBAAuB,IAAI,4BAA4B,GAC7D,MAAM,kBAAkB,CAAC;AAE1B;;;;;;GAMG;AACH,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,KAAK,aAAa,GACnB,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/media/index.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,12 @@
1
1
  export { MediaNotFoundError, MediaValidationError, MediaConflictError, MediaSourceImmutableError, MediaStillReferencedError, } from "./types.js";
2
2
  export { computeBlobStorageKey } from "./blob-key.js";
3
+ export { MEDIA_HTML_ATTRIBUTE_ALLOWED_NAMES, isAllowedMediaHtmlAttributeName, parseMediaHtmlAttributes, describeMediaHtmlAttributeError, } from "./html-attributes.js";
3
4
  export { InMemoryMediaRepo, InMemoryAssetBlobRepo, InMemoryAssetRenditionRepo, InMemoryBlobGcJournalRepo, InMemoryTransformDefinitionRepo, } from "./repo.memory.js";
4
5
  export { withSha256Lock } from "./blob-gc-lock.js";
5
6
  export { DEFAULT_GC_GRACE_MS, resolveGcGraceMs, isBlobUnreferenced, tombstoneBlobIfUnreferenced, runBlobGcDeletePass, runBlobGcUnlinkPass, runBlobGcCycle, runMonthlyOrphanSweepStub, } from "./blob-gc.js";
6
7
  export { InMemoryBlobStore } from "./blob-store.memory.js";
7
8
  export { LocalFsBlobStore } from "./blob-store.fs.js";
8
- export { DEFAULT_MAX_UPLOAD_BYTES, DEFAULT_ALLOWED_MIME_TYPES, resolveWriteOnceSource, uploadMedia, listMedia, getMediaById, updateMediaMetadata, trashMedia, purgeMedia, } from "./media-service.js";
9
+ export { DEFAULT_MAX_UPLOAD_BYTES, DEFAULT_ALLOWED_MIME_TYPES, resolveWriteOnceSource, uploadMedia, listMedia, getMediaById, findMediaByIdOrSlug, updateMediaMetadata, trashMedia, purgeMedia, } from "./media-service.js";
9
10
  export { TransformValidationError, mimeForTransformFormat, MAX_TRANSFORM_DIMENSION_PX } from "./transform-types.js";
10
11
  export { withRenditionLock, withTransformRegistryLock } from "./transform-lock.js";
11
12
  export { registerTransform, getLatestTransformDefinition, isLatestTransformVersion, isReferencedByPublishedContent, } from "./transform-registry.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/media/index.ts"],"names":[],"mappings":"AAuBA,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,YAAY,CAAC;AAYpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,+BAA+B,GAChC,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,2BAA2B,EAC3B,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAA6B,MAAM,oBAAoB,CAAC;AAEjF,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,WAAW,EACX,SAAS,EACT,YAAY,EACZ,mBAAmB,EACnB,UAAU,EACV,UAAU,GAIX,MAAM,oBAAoB,CAAC;AAe5B,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAEpH,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAEnF,OAAO,EACL,iBAAiB,EACjB,4BAA4B,EAC5B,wBAAwB,EACxB,8BAA8B,GAG/B,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,qBAAqB,GAItB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAElE,OAAO,EAAE,qBAAqB,EAAE,8BAA8B,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAE9H,gFAAgF;AAChF,8EAA8E;AAC9E,8EAA8E;AAC9E,uBAAuB;AACvB,gFAAgF;AAChF,OAAO,EAAE,gBAAgB,EAA2B,MAAM,2BAA2B,CAAC;AAEtF,sGAAsG;AACtG,OAAO,EACL,qBAAqB,GAItB,MAAM,kBAAkB,CAAC;AAE1B;;;;;;GAMG;AACH,OAAO,EACL,uBAAuB,EACvB,gBAAgB,GAEjB,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/media/index.ts"],"names":[],"mappings":"AAuBA,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,YAAY,CAAC;AAYpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EACL,kCAAkC,EAClC,+BAA+B,EAC/B,wBAAwB,EACxB,+BAA+B,GAIhC,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,+BAA+B,GAChC,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,2BAA2B,EAC3B,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAA6B,MAAM,oBAAoB,CAAC;AAEjF,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,WAAW,EACX,SAAS,EACT,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,UAAU,EACV,UAAU,GAKX,MAAM,oBAAoB,CAAC;AAe5B,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAEpH,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAEnF,OAAO,EACL,iBAAiB,EACjB,4BAA4B,EAC5B,wBAAwB,EACxB,8BAA8B,GAG/B,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,qBAAqB,GAItB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAElE,OAAO,EAAE,qBAAqB,EAAE,8BAA8B,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAE9H,gFAAgF;AAChF,8EAA8E;AAC9E,8EAA8E;AAC9E,uBAAuB;AACvB,gFAAgF;AAChF,OAAO,EAAE,gBAAgB,EAA2B,MAAM,2BAA2B,CAAC;AAEtF,sGAAsG;AACtG,OAAO,EACL,qBAAqB,GAItB,MAAM,kBAAkB,CAAC;AAE1B;;;;;;GAMG;AACH,OAAO,EACL,uBAAuB,EACvB,gBAAgB,GAEjB,MAAM,yBAAyB,CAAC"}
@@ -10,6 +10,14 @@ export declare const DEFAULT_MAX_UPLOAD_BYTES: number;
10
10
  * that sanitizer is not built in this pass, so SVG upload is rejected rather
11
11
  * than accepted unsanitized.
12
12
  *
13
+ * `image/avif` (owner-directed, 2026-09-06): a fifth still-image type, on the
14
+ * same footing as the four above — `content-type-sniffer.ts` identifies it by
15
+ * ISO-BMFF brand and the installed `sharp`/libvips build decodes it, so it
16
+ * flows through the ordinary transform/rendition pipeline and is re-encoded
17
+ * like any other image. Adding it required a matching sniffer fix, not just
18
+ * this line: AVIF shares MP4's `ftyp` container tag, so before that fix an
19
+ * AVIF was sniffed as `video/mp4` and served as an unplayable video.
20
+ *
13
21
  * `video/mp4`/`video/webm` (owner-directed, 2026-08-24): the two formats
14
22
  * `content-type-sniffer.ts` already recognizes by magic bytes. Unlike the four
15
23
  * image types above, an accepted video is never re-encoded — there is no
@@ -86,7 +94,8 @@ export interface UploadMediaOptional {
86
94
  *
87
95
  * @complexity O(1) — one hash, one blob lookup, at most one blob write, one
88
96
  * media write, one rendition write (the lock itself adds O(1) scheduling
89
- * overhead, not a scan).
97
+ * overhead, not a scan) — plus {@link deriveUniqueMediaSlug}'s own O(n) in the number of prior
98
+ * same-base-slug collisions (see that function's doc).
90
99
  * @overallScore 100
91
100
  */
92
101
  export declare function uploadMedia(required: UploadMediaRequired, optional?: UploadMediaOptional): Promise<{
@@ -131,6 +140,39 @@ export interface GetMediaByIdRequired {
131
140
  export declare function getMediaById(required: GetMediaByIdRequired, _optional?: Record<string, never>): Promise<{
132
141
  media: MediaRecord;
133
142
  }>;
143
+ export interface FindMediaByIdOrSlugRequired {
144
+ deps: {
145
+ mediaRepo: MediaRepoPort;
146
+ };
147
+ input: {
148
+ workspaceId: UUID;
149
+ idOrSlug: string;
150
+ };
151
+ }
152
+ /**
153
+ * Resolves a media asset by either its id or its slug — ID FIRST, slug second. The slug is the
154
+ * handle a human typed into an embed marker or a hand-authored `<img>`/`<video>` tag; the id is the
155
+ * opaque UUID every existing reference already uses, and every URL a host's renderer emits.
156
+ *
157
+ * THE ORDER IS A SECURITY PROPERTY, not a preference (2026-09-07). This resolved slug-first, on the
158
+ * documented assumption that "an id never collides with a slug in practice since slugs pass through
159
+ * {@link isValidMediaSlugFormat}". That assumption was false: a lowercase UUID matched the old slug
160
+ * pattern `[a-z0-9-]+` exactly, so setting asset B's slug to asset A's id made every `/m/{A.id}/…`
161
+ * URL — the ones a renderer emitted for A, already live in published pages — resolve to B instead.
162
+ * An id is minted by the system and is never a value a human chooses, so it must always win; the
163
+ * write path additionally refuses UUID-shaped slugs now (see
164
+ * {@link MEDIA_SLUG_UUID_SHAPE_PATTERN}), but ordering is what protects rows written before that
165
+ * rule existed. Id-first costs nothing on the slug path: a real slug simply misses the id lookup and
166
+ * falls through.
167
+ *
168
+ * Never throws (unlike {@link getMediaById}): every call site that needs this (an embed resolver, a
169
+ * public rendition route) already has its own REQ-27-style non-throwing-miss contract, so this
170
+ * returns `null` on failure and lets the caller apply its own not-found handling rather than forcing
171
+ * one shape on every caller.
172
+ *
173
+ * @complexity O(1) — at most two indexed repo lookups, short-circuited on the first hit.
174
+ */
175
+ export declare function findMediaByIdOrSlug(required: FindMediaByIdOrSlugRequired, _optional?: Record<string, never>): Promise<MediaRecord | null>;
134
176
  export interface UpdateMediaMetadataInput {
135
177
  workspaceId: UUID;
136
178
  id: UUID;
@@ -152,6 +194,23 @@ export interface UpdateMediaMetadataInput {
152
194
  * a string that trims to empty is stored as `null` (equivalent to clearing it), matching the
153
195
  * "empty means unset" convention `title`/`alt`/etc. already follow via `.trim()`. */
154
196
  cssClass?: string | null | undefined;
197
+ /**
198
+ * Explicit slug edit (2026-09-07). `undefined` (key omitted) leaves the stored slug unchanged —
199
+ * in particular, changing `title` on the SAME call never touches `slug`; they are independent
200
+ * fields by design (see `MediaRecord.slug`'s doc). Unlike `title`/`cssClass`, `slug` has no
201
+ * "empty means unset" fallback: a media asset's slug is never null once assigned, so a caller
202
+ * cannot clear it back to absent, only replace it with a different valid slug.
203
+ */
204
+ slug?: string | undefined;
205
+ /**
206
+ * Same undefined/null/value contract as `cssClass` above (2026-09-07). A provided non-empty string
207
+ * is validated against `html-attributes.ts`'s allowlist BEFORE it is trimmed and stored — an `on*`
208
+ * handler, a `javascript:` value, or any disallowed name throws `MediaValidationError` naming the
209
+ * exact rejected attribute, and NOTHING is written (this field included) when that happens. A
210
+ * string that validates but trims to empty is stored as `null`, matching `cssClass`'s identical
211
+ * "empty means unset" convention.
212
+ */
213
+ htmlAttributes?: string | null | undefined;
155
214
  }
156
215
  export interface UpdateMediaMetadataDeps {
157
216
  clock: ClockPort;
@@ -241,4 +300,37 @@ export interface PurgeMediaRequired {
241
300
  export declare function purgeMedia(required: PurgeMediaRequired, _optional?: Record<string, never>): Promise<{
242
301
  purged: true;
243
302
  }>;
303
+ /** Deps shared by both callers of {@link removeMediaRowsAndTombstoneBlob} — the subset of
304
+ * `PurgeMediaDeps` that cleanup actually needs (no `blobStore`: neither caller deletes bytes
305
+ * directly, only tombstones the row via `tombstoneBlobIfUnreferenced`). */
306
+ export interface MediaRowCleanupDeps {
307
+ mediaRepo: MediaRepoPort;
308
+ blobRepo: AssetBlobRepoPort;
309
+ renditionRepo: AssetRenditionRepoPort;
310
+ /** Optional — see `PurgeMediaDeps.clock`'s identical doc. */
311
+ clock?: ClockPort | undefined;
312
+ }
313
+ export interface RollbackUploadedMediaRequired {
314
+ deps: MediaRowCleanupDeps;
315
+ input: {
316
+ workspaceId: UUID;
317
+ media: MediaRecord;
318
+ };
319
+ }
320
+ /**
321
+ * Compensating rollback for {@link uploadMedia}: removes the rendition + media rows it just wrote
322
+ * and tombstones the blob if no other active media row in the workspace still references its
323
+ * sha256 (delegates to {@link removeMediaRowsAndTombstoneBlob}, `purgeMedia`'s own cleanup step).
324
+ *
325
+ * For a caller-side step that runs AFTER `uploadMedia()` has already committed and then fails
326
+ * (e.g. `tool-registrations.ts`'s optional `recordUploadContentType` hook) — without this, the
327
+ * rows `uploadMedia()` wrote survive as orphans (bytes and/or rows nothing points at) even though
328
+ * the caller sees the whole upload as failed. Unlike `purgeMedia`, this performs no trashed-status
329
+ * guard: it is an internal compensating action for a partially-failed operation, not a user-facing
330
+ * delete.
331
+ *
332
+ * @complexity O(n) in the workspace's media row count, inherited from
333
+ * {@link removeMediaRowsAndTombstoneBlob}.
334
+ */
335
+ export declare function rollbackUploadedMedia(required: RollbackUploadedMediaRequired, _optional?: Record<string, never>): Promise<void>;
244
336
  //# sourceMappingURL=media-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"media-service.d.ts","sourceRoot":"","sources":["../../src/media/media-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"media-service.d.ts","sourceRoot":"","sources":["../../src/media/media-service.ts"],"names":[],"mappings":"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"}