@aotter/mantle-runtime 0.0.11-alpha.13 → 0.0.11-alpha.14

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 (68) hide show
  1. package/dist/domain/port/MediaAssetRepository.d.ts +34 -0
  2. package/dist/domain/port/MediaAssetRepository.d.ts.map +1 -0
  3. package/dist/domain/port/MediaAssetRepository.js +2 -0
  4. package/dist/domain/port/MediaAssetRepository.js.map +1 -0
  5. package/dist/domain/port/MediaStorage.d.ts +118 -44
  6. package/dist/domain/port/MediaStorage.d.ts.map +1 -1
  7. package/dist/domain/port/MediaStorage.js +12 -1
  8. package/dist/domain/port/MediaStorage.js.map +1 -1
  9. package/dist/domain/port/SiteConfigRepository.d.ts +2 -2
  10. package/dist/domain/port/SiteConfigRepository.d.ts.map +1 -1
  11. package/dist/domain/port/index.d.ts +3 -1
  12. package/dist/domain/port/index.d.ts.map +1 -1
  13. package/dist/domain/port/index.js +1 -0
  14. package/dist/domain/port/index.js.map +1 -1
  15. package/dist/index.d.ts +3 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +1 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/infrastructure/boot/canonicalMigrations.d.ts.map +1 -1
  20. package/dist/infrastructure/boot/canonicalMigrations.js +17 -0
  21. package/dist/infrastructure/boot/canonicalMigrations.js.map +1 -1
  22. package/dist/infrastructure/mcp/McpJsonRpcDispatcher.d.ts +6 -3
  23. package/dist/infrastructure/mcp/McpJsonRpcDispatcher.d.ts.map +1 -1
  24. package/dist/infrastructure/mcp/McpJsonRpcDispatcher.js +26 -11
  25. package/dist/infrastructure/mcp/McpJsonRpcDispatcher.js.map +1 -1
  26. package/dist/infrastructure/mcp/McpToolCatalog.d.ts +7 -4
  27. package/dist/infrastructure/mcp/McpToolCatalog.d.ts.map +1 -1
  28. package/dist/infrastructure/mcp/McpToolCatalog.js +62 -26
  29. package/dist/infrastructure/mcp/McpToolCatalog.js.map +1 -1
  30. package/dist/infrastructure/persistence/DatabaseMediaAssetRepository.d.ts +27 -0
  31. package/dist/infrastructure/persistence/DatabaseMediaAssetRepository.d.ts.map +1 -0
  32. package/dist/infrastructure/persistence/DatabaseMediaAssetRepository.js +80 -0
  33. package/dist/infrastructure/persistence/DatabaseMediaAssetRepository.js.map +1 -0
  34. package/dist/infrastructure/persistence/DatabaseSiteConfigRepository.d.ts +2 -2
  35. package/dist/infrastructure/persistence/DatabaseSiteConfigRepository.d.ts.map +1 -1
  36. package/dist/infrastructure/persistence/DatabaseSiteConfigRepository.js +24 -3
  37. package/dist/infrastructure/persistence/DatabaseSiteConfigRepository.js.map +1 -1
  38. package/dist/infrastructure/persistence/index.d.ts +1 -0
  39. package/dist/infrastructure/persistence/index.d.ts.map +1 -1
  40. package/dist/infrastructure/persistence/index.js +1 -0
  41. package/dist/infrastructure/persistence/index.js.map +1 -1
  42. package/dist/runtime.d.ts +10 -3
  43. package/dist/runtime.d.ts.map +1 -1
  44. package/dist/runtime.js +6 -2
  45. package/dist/runtime.js.map +1 -1
  46. package/dist/usecase/dto/media/index.d.ts +31 -15
  47. package/dist/usecase/dto/media/index.d.ts.map +1 -1
  48. package/dist/usecase/dto/media/index.js +10 -3
  49. package/dist/usecase/dto/media/index.js.map +1 -1
  50. package/dist/usecase/media/CommitMediaUploadUseCase.d.ts +14 -4
  51. package/dist/usecase/media/CommitMediaUploadUseCase.d.ts.map +1 -1
  52. package/dist/usecase/media/CommitMediaUploadUseCase.js +30 -19
  53. package/dist/usecase/media/CommitMediaUploadUseCase.js.map +1 -1
  54. package/dist/usecase/media/CreateMediaUploadUseCase.d.ts +34 -2
  55. package/dist/usecase/media/CreateMediaUploadUseCase.d.ts.map +1 -1
  56. package/dist/usecase/media/CreateMediaUploadUseCase.js +165 -40
  57. package/dist/usecase/media/CreateMediaUploadUseCase.js.map +1 -1
  58. package/dist/usecase/media/PendingUploadRecord.d.ts +29 -10
  59. package/dist/usecase/media/PendingUploadRecord.d.ts.map +1 -1
  60. package/dist/usecase/media/diagnostics.d.ts +19 -2
  61. package/dist/usecase/media/diagnostics.d.ts.map +1 -1
  62. package/dist/usecase/media/diagnostics.js +66 -7
  63. package/dist/usecase/media/diagnostics.js.map +1 -1
  64. package/dist/usecase/media/mediaAllowlist.d.ts +1 -1
  65. package/dist/usecase/media/mediaAllowlist.d.ts.map +1 -1
  66. package/dist/usecase/media/mediaAllowlist.js +3 -0
  67. package/dist/usecase/media/mediaAllowlist.js.map +1 -1
  68. package/package.json +2 -2
@@ -1,8 +1,15 @@
1
1
  /**
2
2
  * Media use-case DTOs. Distinct from `MediaStorage` port request types:
3
- * the use case receives caller-supplied fields, derives the rest
4
- * (storageKey via the adapter, expiresAt via the clock, maxBytes via
5
- * adapter config), and forwards a port-shaped request internally.
3
+ * the use case receives caller-supplied variant declarations, derives
4
+ * the rest (uploadGroupId via IdGenerator, storage keys via the
5
+ * adapter, expiresAt via the clock, per-mime maxBytes via site
6
+ * config), and forwards port-shaped requests internally.
7
+ *
8
+ * The shape is multi-variant from the start (#272): one
9
+ * `create_media_upload` call yields N presigned URLs (one per
10
+ * format), and one `commit_media_upload` finalises the whole
11
+ * bundle. Optimization runs agent-side via
12
+ * `@aotter/mantle-media-tools` — the runtime never transforms bytes.
6
13
  */
7
14
  export {};
8
15
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/usecase/dto/media/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/usecase/dto/media/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
@@ -1,15 +1,25 @@
1
1
  import type { Clock } from "../../domain/port/Clock.js";
2
2
  import type { KvCache } from "../../domain/port/KvCache.js";
3
+ import type { MediaAssetRepository } from "../../domain/port/MediaAssetRepository.js";
3
4
  import type { MediaAsset, MediaStorage } from "../../domain/port/MediaStorage.js";
4
5
  import type { CommitMediaUploadRequest } from "../dto/media/index.js";
6
+ /**
7
+ * Finalise the variant bundle issued by `create_media_upload`. Reads
8
+ * the `PendingUploadRecord` from KV (each variant's expected
9
+ * mime + size + storageKey), asks the adapter to verify every
10
+ * uploaded object (HEAD + bytes), and on success persists the
11
+ * resulting `MediaAsset` to the `media_assets` table.
12
+ *
13
+ * All-or-nothing: any variant failing HEAD-verify rejects the whole
14
+ * commit. The orphan sweeper (#254) cleans up partially-uploaded
15
+ * bundles whose pending record expired.
16
+ */
5
17
  export declare class CommitMediaUploadUseCase {
6
18
  private readonly storage;
7
19
  private readonly kv;
8
20
  private readonly clock;
9
- private readonly opts;
10
- constructor(storage: MediaStorage, kv: KvCache, clock: Clock, opts?: {
11
- readonly maxBytes?: number;
12
- });
21
+ private readonly assets;
22
+ constructor(storage: MediaStorage, kv: KvCache, clock: Clock, assets: MediaAssetRepository);
13
23
  execute(request: CommitMediaUploadRequest): Promise<MediaAsset>;
14
24
  }
15
25
  //# sourceMappingURL=CommitMediaUploadUseCase.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CommitMediaUploadUseCase.d.ts","sourceRoot":"","sources":["../../../src/usecase/media/CommitMediaUploadUseCase.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAClF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAUtE,qBAAa,wBAAwB;IAEjC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAHJ,OAAO,EAAE,YAAY,EACrB,EAAE,EAAE,OAAO,EACX,KAAK,EAAE,KAAK,EACZ,IAAI,GAAE;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO;IAGtD,OAAO,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,UAAU,CAAC;CA8BtE"}
1
+ {"version":3,"file":"CommitMediaUploadUseCase.d.ts","sourceRoot":"","sources":["../../../src/usecase/media/CommitMediaUploadUseCase.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,KAAK,EAEV,UAAU,EACV,YAAY,EACb,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAKtE;;;;;;;;;;GAUG;AACH,qBAAa,wBAAwB;IAEjC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAHN,OAAO,EAAE,YAAY,EACrB,EAAE,EAAE,OAAO,EACX,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,oBAAoB;IAGzC,OAAO,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,UAAU,CAAC;CAkCtE"}
@@ -1,40 +1,51 @@
1
1
  import { DiagnosticError } from "@aotter/mantle-spec";
2
- import { mediaUploadExpiredDiagnostic, } from "./diagnostics.js";
3
- import { DEFAULT_MAX_BYTES, PENDING_UPLOAD_KV_PREFIX, } from "./mediaAllowlist.js";
2
+ import { mediaUploadExpiredDiagnostic } from "./diagnostics.js";
3
+ import { PENDING_UPLOAD_KV_PREFIX } from "./mediaAllowlist.js";
4
+ /**
5
+ * Finalise the variant bundle issued by `create_media_upload`. Reads
6
+ * the `PendingUploadRecord` from KV (each variant's expected
7
+ * mime + size + storageKey), asks the adapter to verify every
8
+ * uploaded object (HEAD + bytes), and on success persists the
9
+ * resulting `MediaAsset` to the `media_assets` table.
10
+ *
11
+ * All-or-nothing: any variant failing HEAD-verify rejects the whole
12
+ * commit. The orphan sweeper (#254) cleans up partially-uploaded
13
+ * bundles whose pending record expired.
14
+ */
4
15
  export class CommitMediaUploadUseCase {
5
16
  storage;
6
17
  kv;
7
18
  clock;
8
- opts;
9
- constructor(storage, kv, clock, opts = {}) {
19
+ assets;
20
+ constructor(storage, kv, clock, assets) {
10
21
  this.storage = storage;
11
22
  this.kv = kv;
12
23
  this.clock = clock;
13
- this.opts = opts;
24
+ this.assets = assets;
14
25
  }
15
26
  async execute(request) {
16
27
  const opPath = "usecase/CommitMediaUpload";
17
- const kvKey = `${PENDING_UPLOAD_KV_PREFIX}${request.uploadId}`;
28
+ const kvKey = `${PENDING_UPLOAD_KV_PREFIX}${request.uploadGroupId}`;
18
29
  const raw = await this.kv.get(kvKey);
19
30
  if (!raw) {
20
- throw new DiagnosticError(mediaUploadExpiredDiagnostic(opPath, request.uploadId));
31
+ throw new DiagnosticError(mediaUploadExpiredDiagnostic(opPath, request.uploadGroupId));
21
32
  }
22
33
  const record = JSON.parse(raw);
23
- const adapterCap = this.opts.maxBytes ?? DEFAULT_MAX_BYTES;
24
- // Per-upload ceiling: tighter of (caller-declared at create) vs
25
- // (adapter-wide cap). Defends against an adapter that accepted a
26
- // larger PUT than the use case minted the URL for.
27
- const maxBytes = Math.min(adapterCap, record.expectedSize);
34
+ const variantSpecs = record.variants.map((v) => ({
35
+ mimeType: v.mimeType,
36
+ role: v.role,
37
+ storageKey: v.storageKey,
38
+ maxBytes: Math.min(v.maxBytes, v.expectedSize),
39
+ }));
28
40
  const asset = await this.storage.commitUpload({
29
- uploadId: request.uploadId,
30
- storageKey: record.storageKey,
31
- expectedMimeType: record.expectedMimeType,
32
- maxBytes,
33
- alt: request.alt,
34
- caption: request.caption,
35
- checksum: request.checksum,
41
+ uploadGroupId: request.uploadGroupId,
42
+ filename: record.filename,
43
+ variants: variantSpecs,
44
+ alt: request.alt ?? record.alt,
45
+ caption: request.caption ?? record.caption,
36
46
  now: this.clock.now(),
37
47
  });
48
+ await this.assets.save(asset);
38
49
  // Best-effort cleanup. KV TTL covers us if delete fails.
39
50
  await this.kv.delete(kvKey).catch(() => undefined);
40
51
  return asset;
@@ -1 +1 @@
1
- {"version":3,"file":"CommitMediaUploadUseCase.js","sourceRoot":"","sources":["../../../src/usecase/media/CommitMediaUploadUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAKtD,OAAO,EACL,4BAA4B,GAC7B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAG7B,MAAM,OAAO,wBAAwB;IAEhB;IACA;IACA;IACA;IAJnB,YACmB,OAAqB,EACrB,EAAW,EACX,KAAY,EACZ,OAAuC,EAAE;QAHzC,YAAO,GAAP,OAAO,CAAc;QACrB,OAAE,GAAF,EAAE,CAAS;QACX,UAAK,GAAL,KAAK,CAAO;QACZ,SAAI,GAAJ,IAAI,CAAqC;IACzD,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,OAAiC;QAC7C,MAAM,MAAM,GAAG,2BAA2B,CAAC;QAC3C,MAAM,KAAK,GAAG,GAAG,wBAAwB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;QAC/D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,eAAe,CAAC,4BAA4B,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;QACpF,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAwB,CAAC;QACtD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,iBAAiB,CAAC;QAC3D,gEAAgE;QAChE,iEAAiE;QACjE,mDAAmD;QACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;QAE3D,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;YAC5C,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;YACzC,QAAQ;YACR,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;SACtB,CAAC,CAAC;QAEH,yDAAyD;QACzD,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAEnD,OAAO,KAAK,CAAC;IACf,CAAC;CACF"}
1
+ {"version":3,"file":"CommitMediaUploadUseCase.js","sourceRoot":"","sources":["../../../src/usecase/media/CommitMediaUploadUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAUtD,OAAO,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAG/D;;;;;;;;;;GAUG;AACH,MAAM,OAAO,wBAAwB;IAEhB;IACA;IACA;IACA;IAJnB,YACmB,OAAqB,EACrB,EAAW,EACX,KAAY,EACZ,MAA4B;QAH5B,YAAO,GAAP,OAAO,CAAc;QACrB,OAAE,GAAF,EAAE,CAAS;QACX,UAAK,GAAL,KAAK,CAAO;QACZ,WAAM,GAAN,MAAM,CAAsB;IAC5C,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,OAAiC;QAC7C,MAAM,MAAM,GAAG,2BAA2B,CAAC;QAC3C,MAAM,KAAK,GAAG,GAAG,wBAAwB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;QACpE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,eAAe,CACvB,4BAA4B,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,CAC5D,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAwB,CAAC;QAEtD,MAAM,YAAY,GAA2C,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvF,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,YAAY,CAAC;SAC/C,CAAC,CAAC,CAAC;QAEJ,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;YAC5C,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,QAAQ,EAAE,YAAY;YACtB,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG;YAC9B,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO;YAC1C,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;SACtB,CAAC,CAAC;QAEH,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE9B,yDAAyD;QACzD,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAEnD,OAAO,KAAK,CAAC;IACf,CAAC;CACF"}
@@ -1,18 +1,50 @@
1
1
  import type { Clock } from "../../domain/port/Clock.js";
2
+ import type { IdGenerator } from "../../domain/port/IdGenerator.js";
2
3
  import type { KvCache } from "../../domain/port/KvCache.js";
3
4
  import type { MediaStorage } from "../../domain/port/MediaStorage.js";
4
5
  import type { SiteConfigRepository } from "../../domain/port/SiteConfigRepository.js";
5
6
  import type { CreateMediaUploadRequest, CreateMediaUploadResponse } from "../dto/media/index.js";
7
+ /**
8
+ * Issue presigned upload capabilities for every variant the agent
9
+ * declares for one logical media asset (#272). The asset's `id` is
10
+ * minted here and surfaces as `uploadGroupId` in the response — the
11
+ * caller passes it back to `commit_media_upload`.
12
+ *
13
+ * Optimization runs agent-side via `@aotter/mantle-media-tools`. This
14
+ * use case enforces policy only — never transforms bytes:
15
+ * - purpose must be declared in `siteDefaults.media.purposes`
16
+ * - variants must cover every required mime for that purpose
17
+ * - each variant's byteSize ≤ `policy.maxBytes[mime]`
18
+ * - mime allowlist (still gates per variant; SVG opt-in via ctor)
19
+ * - "suspicious shape" heuristic: modern formats (avif / webp) MUST
20
+ * NOT be larger than the fallback (jpeg) — uploader skipped
21
+ * optimization → hard fail rather than emit a `<picture>` slower
22
+ * than the bare `<img>`.
23
+ */
6
24
  export declare class CreateMediaUploadUseCase {
7
25
  private readonly storage;
8
26
  private readonly kv;
9
27
  private readonly clock;
28
+ private readonly idgen;
10
29
  private readonly siteConfig;
11
30
  private readonly opts;
12
- constructor(storage: MediaStorage, kv: KvCache, clock: Clock, siteConfig: SiteConfigRepository, opts?: {
31
+ constructor(storage: MediaStorage, kv: KvCache, clock: Clock, idgen: IdGenerator, siteConfig: SiteConfigRepository, opts?: {
13
32
  readonly allowSvg: boolean;
14
- readonly maxBytes?: number;
15
33
  });
16
34
  execute(request: CreateMediaUploadRequest): Promise<CreateMediaUploadResponse>;
35
+ private assertVariantsCoverPolicy;
36
+ /** Enforce per-mime byte caps from the purpose policy BEFORE the
37
+ * adapter signs presigned PUT URLs. Mantle docs / ADR-0017
38
+ * promise this gate at create time — without it, oversized
39
+ * variants only fail after R2 has accepted the bytes (wasted
40
+ * upload + potential bill).
41
+ *
42
+ * Also gates on positive-integer byteSize. JSON-RPC and HTTP
43
+ * validation only narrow to `typeof === "number"`, so 0, -1, or
44
+ * 0.5 can reach here and produce signed URLs against a maxBytes
45
+ * comparison that accepts them. */
46
+ private assertVariantSizesUnderCap;
47
+ private assertEachVariantAccepted;
48
+ private assertNoSuspiciousSizing;
17
49
  }
18
50
  //# sourceMappingURL=CreateMediaUploadUseCase.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CreateMediaUploadUseCase.d.ts","sourceRoot":"","sources":["../../../src/usecase/media/CreateMediaUploadUseCase.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,uBAAuB,CAAC;AAiB/B,qBAAa,wBAAwB;IAEjC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAJJ,OAAO,EAAE,YAAY,EACrB,EAAE,EAAE,OAAO,EACX,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,oBAAoB,EAChC,IAAI,GAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAE9E;IAGG,OAAO,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;CAkErF"}
1
+ {"version":3,"file":"CreateMediaUploadUseCase.d.ts","sourceRoot":"","sources":["../../../src/usecase/media/CreateMediaUploadUseCase.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,KAAK,EAEV,YAAY,EACb,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EAE1B,MAAM,uBAAuB,CAAC;AAqB/B;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,wBAAwB;IAEjC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI;gBALJ,OAAO,EAAE,YAAY,EACrB,EAAE,EAAE,OAAO,EACX,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,oBAAoB,EAChC,IAAI,GAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;KAAwB;IAGvE,OAAO,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IA0EpF,OAAO,CAAC,yBAAyB;IA8CjC;;;;;;;;;wCASoC;IACpC,OAAO,CAAC,0BAA0B;IA4BlC,OAAO,CAAC,yBAAyB;IAcjC,OAAO,CAAC,wBAAwB;CAmBjC"}
@@ -1,71 +1,196 @@
1
1
  import { DiagnosticError } from "@aotter/mantle-spec";
2
- import { mediaMimeRejectedDiagnostic, mediaPurposeRejectedDiagnostic, mediaSizeExceededDiagnostic, mediaSvgRejectedDiagnostic, } from "./diagnostics.js";
3
- import { DEFAULT_MAX_BYTES, MEDIA_SVG_MIME, PENDING_UPLOAD_KV_PREFIX, PENDING_UPLOAD_KV_TTL_SECONDS, UPLOAD_URL_TTL_SECONDS, isAllowedMime, } from "./mediaAllowlist.js";
2
+ import { mediaMimeRejectedDiagnostic, mediaPurposeRejectedDiagnostic, mediaSvgRejectedDiagnostic, mediaVariantSizeExceededDiagnostic, mediaVariantsIncompleteDiagnostic, mediaVariantsSuspiciousSizeDiagnostic, } from "./diagnostics.js";
3
+ import { MEDIA_SVG_MIME, PENDING_UPLOAD_KV_PREFIX, PENDING_UPLOAD_KV_TTL_SECONDS, UPLOAD_URL_TTL_SECONDS, isAllowedMime, } from "./mediaAllowlist.js";
4
+ /**
5
+ * Issue presigned upload capabilities for every variant the agent
6
+ * declares for one logical media asset (#272). The asset's `id` is
7
+ * minted here and surfaces as `uploadGroupId` in the response — the
8
+ * caller passes it back to `commit_media_upload`.
9
+ *
10
+ * Optimization runs agent-side via `@aotter/mantle-media-tools`. This
11
+ * use case enforces policy only — never transforms bytes:
12
+ * - purpose must be declared in `siteDefaults.media.purposes`
13
+ * - variants must cover every required mime for that purpose
14
+ * - each variant's byteSize ≤ `policy.maxBytes[mime]`
15
+ * - mime allowlist (still gates per variant; SVG opt-in via ctor)
16
+ * - "suspicious shape" heuristic: modern formats (avif / webp) MUST
17
+ * NOT be larger than the fallback (jpeg) — uploader skipped
18
+ * optimization → hard fail rather than emit a `<picture>` slower
19
+ * than the bare `<img>`.
20
+ */
4
21
  export class CreateMediaUploadUseCase {
5
22
  storage;
6
23
  kv;
7
24
  clock;
25
+ idgen;
8
26
  siteConfig;
9
27
  opts;
10
- constructor(storage, kv, clock, siteConfig, opts = {
11
- allowSvg: false,
12
- }) {
28
+ constructor(storage, kv, clock, idgen, siteConfig, opts = { allowSvg: false }) {
13
29
  this.storage = storage;
14
30
  this.kv = kv;
15
31
  this.clock = clock;
32
+ this.idgen = idgen;
16
33
  this.siteConfig = siteConfig;
17
34
  this.opts = opts;
18
35
  }
19
36
  async execute(request) {
20
37
  const opPath = "usecase/CreateMediaUpload";
21
- const maxBytes = this.opts.maxBytes ?? DEFAULT_MAX_BYTES;
22
- // Fail-closed purpose enforcement (#262). Empty `media.purposes` —
23
- // either undeclared or operator-cleared — disables uploads entirely
24
- // at this layer; the MCP tool catalog + admin endpoint also gate on
25
- // the same condition for cleaner UX. Reading per request rather
26
- // than snapshotting at boot lets operator edits via the admin
27
- // Settings page take effect without a redeploy.
28
38
  const declared = await this.siteConfig.readMediaPurposes();
29
- if (declared.length === 0 || !request.purpose || !declared.includes(request.purpose)) {
30
- throw new DiagnosticError(mediaPurposeRejectedDiagnostic(opPath, request.purpose, declared));
31
- }
32
- if (request.mimeType === MEDIA_SVG_MIME && !this.opts.allowSvg) {
33
- throw new DiagnosticError(mediaSvgRejectedDiagnostic(opPath));
34
- }
35
- if (!isAllowedMime(request.mimeType, this.opts.allowSvg)) {
36
- throw new DiagnosticError(mediaMimeRejectedDiagnostic(opPath, request.mimeType));
37
- }
38
- // Enforce the ceiling before minting a presigned URL — see
39
- // CreateMediaUploadRequest.byteSize for the WHY.
40
- if (request.byteSize > maxBytes) {
41
- throw new DiagnosticError(mediaSizeExceededDiagnostic(opPath, request.byteSize, maxBytes));
39
+ const declaredNames = declared.map((p) => p.name);
40
+ const policy = declared.find((p) => p.name === request.purpose);
41
+ if (!policy) {
42
+ throw new DiagnosticError(mediaPurposeRejectedDiagnostic(opPath, request.purpose, declaredNames));
42
43
  }
44
+ this.assertVariantsCoverPolicy(opPath, request, policy);
45
+ this.assertEachVariantAccepted(opPath, request);
46
+ this.assertVariantSizesUnderCap(opPath, request, policy);
47
+ this.assertNoSuspiciousSizing(opPath, request);
43
48
  const now = this.clock.now();
44
49
  const expiresAt = now + UPLOAD_URL_TTL_SECONDS * 1000;
45
- const capability = await this.storage.createUpload({
46
- filename: request.filename,
47
- mimeType: request.mimeType,
48
- byteSize: request.byteSize,
49
- maxBytes,
50
+ const uploadGroupId = this.idgen.next();
51
+ const variantSpecs = request.variants.map((v) => ({
52
+ mimeType: v.mimeType,
53
+ byteSize: v.byteSize,
54
+ maxBytes: policy.maxBytes[v.mimeType] ?? Number.MAX_SAFE_INTEGER,
55
+ role: v.role,
56
+ }));
57
+ const result = await this.storage.createUpload({
58
+ uploadGroupId,
50
59
  purpose: request.purpose,
60
+ filename: request.filename,
61
+ variants: variantSpecs,
51
62
  now,
52
63
  expiresAt,
53
64
  });
65
+ const pendingVariants = result.capabilities.map((cap, i) => ({
66
+ mimeType: cap.mimeType,
67
+ role: cap.role,
68
+ storageKey: cap.storageKey,
69
+ expectedSize: variantSpecs[i].byteSize,
70
+ maxBytes: variantSpecs[i].maxBytes,
71
+ }));
54
72
  const record = {
55
- storageKey: capability.storageKey,
56
- expectedMimeType: request.mimeType,
57
- expectedSize: request.byteSize,
58
- expiresAt: capability.expiresAt,
73
+ purpose: request.purpose,
74
+ filename: request.filename,
75
+ variants: pendingVariants,
76
+ alt: request.alt,
77
+ caption: request.caption,
78
+ expiresAt: result.expiresAt,
59
79
  createdAt: now,
60
80
  };
61
- await this.kv.put(`${PENDING_UPLOAD_KV_PREFIX}${capability.uploadId}`, JSON.stringify(record), { expirationTtl: PENDING_UPLOAD_KV_TTL_SECONDS });
81
+ await this.kv.put(`${PENDING_UPLOAD_KV_PREFIX}${result.uploadGroupId}`, JSON.stringify(record), { expirationTtl: PENDING_UPLOAD_KV_TTL_SECONDS });
62
82
  return {
63
- uploadId: capability.uploadId,
64
- uploadUrl: capability.uploadUrl,
65
- method: capability.method,
66
- requiredHeaders: capability.requiredHeaders,
67
- expiresAt: capability.expiresAt,
83
+ uploadGroupId: result.uploadGroupId,
84
+ capabilities: result.capabilities.map((cap) => ({
85
+ mimeType: cap.mimeType,
86
+ role: cap.role,
87
+ method: cap.method,
88
+ uploadUrl: cap.uploadUrl,
89
+ requiredHeaders: cap.requiredHeaders,
90
+ })),
91
+ expiresAt: result.expiresAt,
68
92
  };
69
93
  }
94
+ assertVariantsCoverPolicy(opPath, request, policy) {
95
+ const supplied = request.variants.map((v) => v.mimeType);
96
+ const missing = policy.required.filter((m) => !supplied.includes(m));
97
+ if (missing.length > 0) {
98
+ throw new DiagnosticError(mediaVariantsIncompleteDiagnostic(opPath, policy.name, policy.required, supplied));
99
+ }
100
+ // Closed set: the policy declares which mimes belong to this
101
+ // purpose. Extras (e.g. an `image/png` alongside the declared
102
+ // avif/webp/jpeg trio) would land without a per-mime byte cap
103
+ // and bypass the size gate entirely. Reject any supplied mime
104
+ // outside `policy.required`.
105
+ const allowed = new Set(policy.required);
106
+ const extras = request.variants.filter((v) => !allowed.has(v.mimeType));
107
+ if (extras.length > 0) {
108
+ throw new DiagnosticError(mediaVariantsIncompleteDiagnostic(opPath, policy.name, policy.required, supplied));
109
+ }
110
+ // Exactly one primary. Storage key layout is `<group>/<role>.<ext>`,
111
+ // so two primaries collide on the same R2 key + ambiguate which
112
+ // variant `<img>` falls back to. Same for any duplicated (mime, role)
113
+ // pair — two `image/jpeg` alternates would also collide on key.
114
+ const primaries = request.variants.filter((v) => v.role === "primary");
115
+ if (primaries.length !== 1) {
116
+ throw new DiagnosticError(mediaVariantsIncompleteDiagnostic(opPath, policy.name, policy.required, supplied));
117
+ }
118
+ const seen = new Set();
119
+ for (const v of request.variants) {
120
+ const key = `${v.mimeType}/${v.role}`;
121
+ if (seen.has(key)) {
122
+ throw new DiagnosticError(mediaVariantsIncompleteDiagnostic(opPath, policy.name, policy.required, supplied));
123
+ }
124
+ seen.add(key);
125
+ }
126
+ }
127
+ /** Enforce per-mime byte caps from the purpose policy BEFORE the
128
+ * adapter signs presigned PUT URLs. Mantle docs / ADR-0017
129
+ * promise this gate at create time — without it, oversized
130
+ * variants only fail after R2 has accepted the bytes (wasted
131
+ * upload + potential bill).
132
+ *
133
+ * Also gates on positive-integer byteSize. JSON-RPC and HTTP
134
+ * validation only narrow to `typeof === "number"`, so 0, -1, or
135
+ * 0.5 can reach here and produce signed URLs against a maxBytes
136
+ * comparison that accepts them. */
137
+ assertVariantSizesUnderCap(opPath, request, policy) {
138
+ for (const v of request.variants) {
139
+ if (!Number.isSafeInteger(v.byteSize) || v.byteSize <= 0) {
140
+ throw new DiagnosticError(mediaVariantSizeExceededDiagnostic(opPath, v.mimeType, v.byteSize, 0));
141
+ }
142
+ const cap = policy.maxBytes[v.mimeType];
143
+ // mime outside policy.required was already rejected in
144
+ // assertVariantsCoverPolicy; defensive check so a future
145
+ // refactor doesn't silently uncap.
146
+ if (cap === undefined) {
147
+ throw new DiagnosticError(mediaVariantSizeExceededDiagnostic(opPath, v.mimeType, v.byteSize, 0));
148
+ }
149
+ if (v.byteSize > cap) {
150
+ throw new DiagnosticError(mediaVariantSizeExceededDiagnostic(opPath, v.mimeType, v.byteSize, cap));
151
+ }
152
+ }
153
+ }
154
+ assertEachVariantAccepted(opPath, request) {
155
+ for (const v of request.variants) {
156
+ if (v.mimeType === MEDIA_SVG_MIME && !this.opts.allowSvg) {
157
+ throw new DiagnosticError(mediaSvgRejectedDiagnostic(opPath));
158
+ }
159
+ if (!isAllowedMime(v.mimeType, this.opts.allowSvg)) {
160
+ throw new DiagnosticError(mediaMimeRejectedDiagnostic(opPath, v.mimeType));
161
+ }
162
+ }
163
+ }
164
+ assertNoSuspiciousSizing(opPath, request) {
165
+ const fallback = pickFallbackForSizing(request.variants);
166
+ if (!fallback)
167
+ return;
168
+ for (const v of request.variants) {
169
+ if (v === fallback)
170
+ continue;
171
+ if (!MODERN_FORMATS.has(v.mimeType))
172
+ continue;
173
+ if (v.byteSize > fallback.byteSize) {
174
+ throw new DiagnosticError(mediaVariantsSuspiciousSizeDiagnostic(opPath, `${v.mimeType} (${v.byteSize}B) > ${fallback.mimeType} (${fallback.byteSize}B)`));
175
+ }
176
+ }
177
+ }
178
+ }
179
+ /** Modern formats that, by convention, should be smaller than the
180
+ * universal fallback (jpeg / png). Used by the "suspicious sizing"
181
+ * heuristic — if any of these weigh more than the fallback, the
182
+ * uploader almost certainly skipped optimization. */
183
+ const MODERN_FORMATS = new Set(["image/avif", "image/webp"]);
184
+ /** Pick the variant to compare modern formats against — preferred
185
+ * order: jpeg → png → gif. Returns undefined when none of the
186
+ * classic-format variants are present (e.g. an avif-only upload),
187
+ * in which case the heuristic skips. */
188
+ function pickFallbackForSizing(variants) {
189
+ for (const mime of ["image/jpeg", "image/png", "image/gif"]) {
190
+ const found = variants.find((v) => v.mimeType === mime);
191
+ if (found)
192
+ return found;
193
+ }
194
+ return undefined;
70
195
  }
71
196
  //# sourceMappingURL=CreateMediaUploadUseCase.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CreateMediaUploadUseCase.js","sourceRoot":"","sources":["../../../src/usecase/media/CreateMediaUploadUseCase.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CreateMediaUploadUseCase.js","sourceRoot":"","sources":["../../../src/usecase/media/CreateMediaUploadUseCase.ts"],"names":[],"mappings":"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"}
@@ -1,17 +1,36 @@
1
+ import type { MediaVariantRole } from "../../domain/port/MediaStorage.js";
1
2
  /** KV record persisted by `CreateMediaUploadUseCase` and read by
2
3
  * `CommitMediaUploadUseCase`. Stored under
3
- * `${PENDING_UPLOAD_KV_PREFIX}${uploadId}` with a TTL set to
4
- * `PENDING_UPLOAD_KV_TTL_SECONDS`. */
4
+ * `${PENDING_UPLOAD_KV_PREFIX}${uploadGroupId}` with a TTL set to
5
+ * `PENDING_UPLOAD_KV_TTL_SECONDS`.
6
+ *
7
+ * Multi-variant from the start (#272): one record tracks every
8
+ * variant the agent declared, so commit can HEAD all N R2 objects
9
+ * in one atomic shot.
10
+ */
5
11
  export interface PendingUploadRecord {
6
- readonly storageKey: string;
7
- readonly expectedMimeType: string;
8
- /** Caller-declared byte size, persisted at create time so commit can
9
- * enforce a tight per-upload ceiling instead of just the adapter-
10
- * wide `maxBytes`. Adapter ultimately verifies actual stored bytes
11
- * ≤ commit-supplied maxBytes — `CommitMediaUploadUseCase` passes
12
- * `min(adapterCap, record.expectedSize)`. */
13
- readonly expectedSize: number;
12
+ readonly purpose: string;
13
+ /** Original filename — forwarded by commit into R2 customMetadata
14
+ * on every variant. Preserved here so the commit path sees it
15
+ * without a second hop. */
16
+ readonly filename: string;
17
+ readonly variants: ReadonlyArray<PendingUploadVariant>;
18
+ readonly alt?: string;
19
+ readonly caption?: string;
14
20
  readonly expiresAt: number;
15
21
  readonly createdAt: number;
16
22
  }
23
+ export interface PendingUploadVariant {
24
+ readonly mimeType: string;
25
+ readonly role: MediaVariantRole;
26
+ readonly storageKey: string;
27
+ /** Caller-declared byte size, persisted at create time so commit
28
+ * can enforce a tight per-variant ceiling rather than just the
29
+ * per-purpose `maxBytes`. The adapter ultimately verifies actual
30
+ * stored bytes ≤ this. */
31
+ readonly expectedSize: number;
32
+ /** Per-purpose `maxBytes[mimeType]`. Forwarded to the adapter so
33
+ * HEAD-verify rejects oversized PUTs with the right cap message. */
34
+ readonly maxBytes: number;
35
+ }
17
36
  //# sourceMappingURL=PendingUploadRecord.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PendingUploadRecord.d.ts","sourceRoot":"","sources":["../../../src/usecase/media/PendingUploadRecord.ts"],"names":[],"mappings":"AAAA;;;uCAGuC;AACvC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC;;;;kDAI8C;IAC9C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B"}
1
+ {"version":3,"file":"PendingUploadRecord.d.ts","sourceRoot":"","sources":["../../../src/usecase/media/PendingUploadRecord.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAE1E;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;gCAE4B;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAC;IACvD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;+BAG2B;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;yEACqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B"}
@@ -3,8 +3,8 @@ export declare function mediaNotConfiguredDiagnostic(opPath: string): Diagnostic
3
3
  export declare function mediaMimeRejectedDiagnostic(opPath: string, mime: string): Diagnostic;
4
4
  export declare function mediaSvgRejectedDiagnostic(opPath: string): Diagnostic;
5
5
  export declare function mediaSizeExceededDiagnostic(opPath: string, byteSize: number, maxBytes: number): Diagnostic;
6
- export declare function mediaUploadExpiredDiagnostic(opPath: string, uploadId: string): Diagnostic;
7
- export declare function mediaObjectNotFoundDiagnostic(opPath: string, uploadId: string): Diagnostic;
6
+ export declare function mediaUploadExpiredDiagnostic(opPath: string, uploadGroupId: string): Diagnostic;
7
+ export declare function mediaObjectNotFoundDiagnostic(opPath: string, uploadGroupId: string): Diagnostic;
8
8
  /** Caller supplied a `purpose` that this deployment did not declare in
9
9
  * `siteDefaults.media.purposes`. Fail-closed per #262: alpha has no
10
10
  * production consumers, so there is no warn-and-allow compatibility
@@ -12,4 +12,21 @@ export declare function mediaObjectNotFoundDiagnostic(opPath: string, uploadId:
12
12
  * field carries the declared set so agents can self-correct without
13
13
  * another round trip. */
14
14
  export declare function mediaPurposeRejectedDiagnostic(opPath: string, purpose: string | undefined, declared: readonly string[]): Diagnostic;
15
+ /** Caller's variants manifest is missing one or more mimes the
16
+ * purpose policy declares as required. The expected field carries
17
+ * the declared required set + the supplied set so the agent script
18
+ * can self-correct without another round trip. */
19
+ export declare function mediaVariantsIncompleteDiagnostic(opPath: string, purpose: string, required: readonly string[], supplied: readonly string[]): Diagnostic;
20
+ export declare function mediaVariantSizeExceededDiagnostic(opPath: string, mime: string, byteSize: number, maxBytes: number): Diagnostic;
21
+ /**
22
+ * Variant byte sizes don't match the format hierarchy the uploader
23
+ * promised — typically avif > webp > jpeg (each modern format
24
+ * smaller). When the upload manifest claims a modern format that's
25
+ * larger than the universal-fallback (e.g. `avif` weighing more than
26
+ * `jpeg`), the uploader almost certainly skipped optimization for
27
+ * that variant. Fail hard rather than emit a `<picture>` that's
28
+ * slower than the bare `<img>` fallback.
29
+ */
30
+ export declare function mediaVariantsSuspiciousSizeDiagnostic(opPath: string, detail: string): Diagnostic;
31
+ export declare function mediaAssetNotFoundDiagnostic(opPath: string, id: string): Diagnostic;
15
32
  //# sourceMappingURL=diagnostics.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../../src/usecase/media/diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAItE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAUvE;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,CASpF;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAUrE;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,UAAU,CASZ;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAUzF;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAU1F;AAED;;;;;0BAK0B;AAC1B,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,UAAU,CAiBZ"}
1
+ {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../../src/usecase/media/diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAItE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAUvE;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,CASpF;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAUrE;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,UAAU,CASZ;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,UAAU,CAU9F;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,UAAU,CAU/F;AAED;;;;;0BAK0B;AAC1B,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,UAAU,CAiBZ;AAED;;;mDAGmD;AACnD,wBAAgB,iCAAiC,CAC/C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,UAAU,CAaZ;AAED,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,UAAU,CAWZ;AAED;;;;;;;;GAQG;AACH,wBAAgB,qCAAqC,CACnD,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,UAAU,CAYZ;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,CAWnF"}