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

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 (103) hide show
  1. package/dist/domain/model/TemplateRegistry.d.ts +3 -0
  2. package/dist/domain/model/TemplateRegistry.d.ts.map +1 -1
  3. package/dist/domain/model/TemplateRegistry.js.map +1 -1
  4. package/dist/domain/port/MediaAssetRepository.d.ts +34 -0
  5. package/dist/domain/port/MediaAssetRepository.d.ts.map +1 -0
  6. package/dist/domain/port/MediaAssetRepository.js +2 -0
  7. package/dist/domain/port/MediaAssetRepository.js.map +1 -0
  8. package/dist/domain/port/MediaStorage.d.ts +159 -44
  9. package/dist/domain/port/MediaStorage.d.ts.map +1 -1
  10. package/dist/domain/port/MediaStorage.js +12 -1
  11. package/dist/domain/port/MediaStorage.js.map +1 -1
  12. package/dist/domain/port/SiteConfigRepository.d.ts +2 -2
  13. package/dist/domain/port/SiteConfigRepository.d.ts.map +1 -1
  14. package/dist/domain/port/index.d.ts +3 -1
  15. package/dist/domain/port/index.d.ts.map +1 -1
  16. package/dist/domain/port/index.js +1 -0
  17. package/dist/domain/port/index.js.map +1 -1
  18. package/dist/domain/service/HtmlRenderer.d.ts +3 -0
  19. package/dist/domain/service/HtmlRenderer.d.ts.map +1 -1
  20. package/dist/domain/service/HtmlRenderer.js +7 -1
  21. package/dist/domain/service/HtmlRenderer.js.map +1 -1
  22. package/dist/domain/service/io/MediaAssetReferences.d.ts +13 -0
  23. package/dist/domain/service/io/MediaAssetReferences.d.ts.map +1 -0
  24. package/dist/domain/service/io/MediaAssetReferences.js +48 -0
  25. package/dist/domain/service/io/MediaAssetReferences.js.map +1 -0
  26. package/dist/index.d.ts +3 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1 -0
  29. package/dist/index.js.map +1 -1
  30. package/dist/infrastructure/boot/canonicalMigrations.d.ts.map +1 -1
  31. package/dist/infrastructure/boot/canonicalMigrations.js +17 -0
  32. package/dist/infrastructure/boot/canonicalMigrations.js.map +1 -1
  33. package/dist/infrastructure/mcp/McpJsonRpcDispatcher.d.ts +9 -5
  34. package/dist/infrastructure/mcp/McpJsonRpcDispatcher.d.ts.map +1 -1
  35. package/dist/infrastructure/mcp/McpJsonRpcDispatcher.js +84 -11
  36. package/dist/infrastructure/mcp/McpJsonRpcDispatcher.js.map +1 -1
  37. package/dist/infrastructure/mcp/McpToolCatalog.d.ts +8 -4
  38. package/dist/infrastructure/mcp/McpToolCatalog.d.ts.map +1 -1
  39. package/dist/infrastructure/mcp/McpToolCatalog.js +108 -24
  40. package/dist/infrastructure/mcp/McpToolCatalog.js.map +1 -1
  41. package/dist/infrastructure/persistence/DatabaseMediaAssetRepository.d.ts +27 -0
  42. package/dist/infrastructure/persistence/DatabaseMediaAssetRepository.d.ts.map +1 -0
  43. package/dist/infrastructure/persistence/DatabaseMediaAssetRepository.js +80 -0
  44. package/dist/infrastructure/persistence/DatabaseMediaAssetRepository.js.map +1 -0
  45. package/dist/infrastructure/persistence/DatabaseSiteConfigRepository.d.ts +2 -2
  46. package/dist/infrastructure/persistence/DatabaseSiteConfigRepository.d.ts.map +1 -1
  47. package/dist/infrastructure/persistence/DatabaseSiteConfigRepository.js +24 -3
  48. package/dist/infrastructure/persistence/DatabaseSiteConfigRepository.js.map +1 -1
  49. package/dist/infrastructure/persistence/index.d.ts +1 -0
  50. package/dist/infrastructure/persistence/index.d.ts.map +1 -1
  51. package/dist/infrastructure/persistence/index.js +1 -0
  52. package/dist/infrastructure/persistence/index.js.map +1 -1
  53. package/dist/infrastructure/render/HtmlPublishOrchestrator.d.ts +3 -1
  54. package/dist/infrastructure/render/HtmlPublishOrchestrator.d.ts.map +1 -1
  55. package/dist/infrastructure/render/HtmlPublishOrchestrator.js +8 -2
  56. package/dist/infrastructure/render/HtmlPublishOrchestrator.js.map +1 -1
  57. package/dist/runtime.d.ts +12 -4
  58. package/dist/runtime.d.ts.map +1 -1
  59. package/dist/runtime.js +12 -7
  60. package/dist/runtime.js.map +1 -1
  61. package/dist/usecase/dto/media/index.d.ts +42 -15
  62. package/dist/usecase/dto/media/index.d.ts.map +1 -1
  63. package/dist/usecase/dto/media/index.js +10 -3
  64. package/dist/usecase/dto/media/index.js.map +1 -1
  65. package/dist/usecase/media/CommitMediaUploadUseCase.d.ts +14 -4
  66. package/dist/usecase/media/CommitMediaUploadUseCase.d.ts.map +1 -1
  67. package/dist/usecase/media/CommitMediaUploadUseCase.js +30 -19
  68. package/dist/usecase/media/CommitMediaUploadUseCase.js.map +1 -1
  69. package/dist/usecase/media/CreateMediaUploadUseCase.d.ts +34 -2
  70. package/dist/usecase/media/CreateMediaUploadUseCase.d.ts.map +1 -1
  71. package/dist/usecase/media/CreateMediaUploadUseCase.js +184 -41
  72. package/dist/usecase/media/CreateMediaUploadUseCase.js.map +1 -1
  73. package/dist/usecase/media/PendingUploadRecord.d.ts +29 -10
  74. package/dist/usecase/media/PendingUploadRecord.d.ts.map +1 -1
  75. package/dist/usecase/media/UploadMediaVariantUseCase.d.ts +35 -0
  76. package/dist/usecase/media/UploadMediaVariantUseCase.d.ts.map +1 -0
  77. package/dist/usecase/media/UploadMediaVariantUseCase.js +75 -0
  78. package/dist/usecase/media/UploadMediaVariantUseCase.js.map +1 -0
  79. package/dist/usecase/media/diagnostics.d.ts +19 -2
  80. package/dist/usecase/media/diagnostics.d.ts.map +1 -1
  81. package/dist/usecase/media/diagnostics.js +66 -7
  82. package/dist/usecase/media/diagnostics.js.map +1 -1
  83. package/dist/usecase/media/index.d.ts +1 -0
  84. package/dist/usecase/media/index.d.ts.map +1 -1
  85. package/dist/usecase/media/index.js +1 -0
  86. package/dist/usecase/media/index.js.map +1 -1
  87. package/dist/usecase/media/mediaAllowlist.d.ts +1 -1
  88. package/dist/usecase/media/mediaAllowlist.d.ts.map +1 -1
  89. package/dist/usecase/media/mediaAllowlist.js +3 -0
  90. package/dist/usecase/media/mediaAllowlist.js.map +1 -1
  91. package/dist/usecase/render/PreviewEntryUseCase.d.ts +3 -1
  92. package/dist/usecase/render/PreviewEntryUseCase.d.ts.map +1 -1
  93. package/dist/usecase/render/PreviewEntryUseCase.js +6 -1
  94. package/dist/usecase/render/PreviewEntryUseCase.js.map +1 -1
  95. package/dist/usecase/render/RenderEntryLiveUseCase.d.ts +3 -1
  96. package/dist/usecase/render/RenderEntryLiveUseCase.d.ts.map +1 -1
  97. package/dist/usecase/render/RenderEntryLiveUseCase.js +6 -1
  98. package/dist/usecase/render/RenderEntryLiveUseCase.js.map +1 -1
  99. package/dist/usecase/render/RenderListLiveUseCase.d.ts +3 -1
  100. package/dist/usecase/render/RenderListLiveUseCase.d.ts.map +1 -1
  101. package/dist/usecase/render/RenderListLiveUseCase.js +6 -1
  102. package/dist/usecase/render/RenderListLiveUseCase.js.map +1 -1
  103. package/package.json +4 -4
@@ -1,5 +1,6 @@
1
1
  import type { Entry, SiteConfig } from "@aotter/mantle-spec";
2
2
  import type { SeoMeta } from "./SeoMeta.js";
3
+ import type { MediaAsset } from "../port/MediaStorage.js";
3
4
  /**
4
5
  * Render-pipeline types + consumer-supplied template registry.
5
6
  *
@@ -25,6 +26,7 @@ import type { SeoMeta } from "./SeoMeta.js";
25
26
  export interface EntryContext {
26
27
  readonly entry: Entry;
27
28
  readonly site: SiteConfig;
29
+ readonly mediaAssets?: ReadonlyMap<string, MediaAsset>;
28
30
  readonly seo?: SeoMeta;
29
31
  }
30
32
  export interface ListContext {
@@ -32,6 +34,7 @@ export interface ListContext {
32
34
  readonly locale: string;
33
35
  readonly entries: readonly Entry[];
34
36
  readonly site: SiteConfig;
37
+ readonly mediaAssets?: ReadonlyMap<string, MediaAsset>;
35
38
  readonly seo?: SeoMeta;
36
39
  }
37
40
  export type EntryTemplate = (ctx: EntryContext) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"TemplateRegistry.d.ts","sourceRoot":"","sources":["../../../src/domain/model/TemplateRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,YAAY,KAAK,MAAM,CAAC;AAC1D,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,MAAM,CAAC;AAExD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAC5D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmC;IAEzD,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,aAAa,GAAG,IAAI;IAIjE,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,YAAY,GAAG,IAAI;IAI/D,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI/D,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;CAG9D"}
1
+ {"version":3,"file":"TemplateRegistry.d.ts","sourceRoot":"","sources":["../../../src/domain/model/TemplateRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACvD,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACvD,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,YAAY,KAAK,MAAM,CAAC;AAC1D,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,MAAM,CAAC;AAExD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAC5D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmC;IAEzD,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,aAAa,GAAG,IAAI;IAIjE,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,YAAY,GAAG,IAAI;IAI/D,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI/D,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;CAG9D"}
@@ -1 +1 @@
1
- {"version":3,"file":"TemplateRegistry.js","sourceRoot":"","sources":["../../../src/domain/model/TemplateRegistry.ts"],"names":[],"mappings":"AA0CA,MAAM,OAAO,gBAAgB;IACV,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC3C,KAAK,GAAG,IAAI,GAAG,EAAwB,CAAC;IAEzD,qBAAqB,CAAC,UAAkB,EAAE,CAAgB;QACxD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,oBAAoB,CAAC,UAAkB,EAAE,CAAe;QACtD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAChC,CAAC;IAED,gBAAgB,CAAC,UAAkB;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACtC,CAAC;IAED,eAAe,CAAC,UAAkB;QAChC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACpC,CAAC;CACF"}
1
+ {"version":3,"file":"TemplateRegistry.js","sourceRoot":"","sources":["../../../src/domain/model/TemplateRegistry.ts"],"names":[],"mappings":"AA6CA,MAAM,OAAO,gBAAgB;IACV,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC3C,KAAK,GAAG,IAAI,GAAG,EAAwB,CAAC;IAEzD,qBAAqB,CAAC,UAAkB,EAAE,CAAgB;QACxD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,oBAAoB,CAAC,UAAkB,EAAE,CAAe;QACtD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAChC,CAAC;IAED,gBAAgB,CAAC,UAAkB;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACtC,CAAC;IAED,eAAe,CAAC,UAAkB;QAChC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACpC,CAAC;CACF"}
@@ -0,0 +1,34 @@
1
+ import type { MediaAsset } from "./MediaStorage.js";
2
+ /**
3
+ * Persistent store for committed `MediaAsset` rows — the
4
+ * `media_assets` table on the SDK-canonical schema. Owned by the
5
+ * commit-media use case (which `save`s on successful commit) and the
6
+ * render path (which calls `findById` / `findManyByIds` via
7
+ * `runtime.media.resolve`).
8
+ *
9
+ * The table is the single source of truth for the variants set of an
10
+ * already-uploaded asset; entry data carries only `MediaAsset.id`
11
+ * (`x-mantle-ref: media_assets`) and the renderer resolves at render
12
+ * time. Persisting the full asset row (not just storage keys) keeps
13
+ * resolution to one indexed read and lets the orphan sweeper (#254)
14
+ * identify uncommitted-but-unreferenced R2 objects by comparing
15
+ * bucket listings against the table.
16
+ *
17
+ * `findManyByIds` is mandatory (not a `findById`-fan-out helper)
18
+ * because entry-list rendering pulls N posts → N coverAssetId lookups;
19
+ * the renderer's DataLoader-style batcher relies on a single DB round
20
+ * trip per page.
21
+ *
22
+ * `delete` removes the row only — the R2 objects are deleted by
23
+ * the use case that owns the asset deletion lifecycle, which calls
24
+ * `MediaStorage.deleteObject` once per variant before this. Splitting
25
+ * the two lets either side fail without leaving the other in a
26
+ * half-deleted state the sweeper can clean up.
27
+ */
28
+ export interface MediaAssetRepository {
29
+ findById(id: string): Promise<MediaAsset | null>;
30
+ findManyByIds(ids: readonly string[]): Promise<ReadonlyMap<string, MediaAsset>>;
31
+ save(asset: MediaAsset): Promise<void>;
32
+ delete(id: string): Promise<void>;
33
+ }
34
+ //# sourceMappingURL=MediaAssetRepository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaAssetRepository.d.ts","sourceRoot":"","sources":["../../../src/domain/port/MediaAssetRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACjD,aAAa,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IAChF,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=MediaAssetRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaAssetRepository.js","sourceRoot":"","sources":["../../../src/domain/port/MediaAssetRepository.ts"],"names":[],"mappings":""}
@@ -3,17 +3,26 @@
3
3
  * part of the required v0.1.0 provisioning path: starters must keep
4
4
  * working without an implementation.
5
5
  *
6
- * The port is intentionally object-storage-shaped. Cloudflare R2, S3,
7
- * filesystem, or a future hosted service can implement it without
8
- * leaking adapter types into runtime use cases.
6
+ * # Multi-variant by default (#272)
7
+ *
8
+ * Every committed `MediaAsset` carries one or more `variants` — at
9
+ * minimum the format `<img>` falls back to (`role: "primary"`), and
10
+ * typically additional formats (`webp`, `avif`) the renderer prefers
11
+ * via `<picture>`. Variant *bytes* are produced agent-side by
12
+ * `@aotter/mantle-media-tools` (sharp / libvips); the Worker only
13
+ * receives already-processed uploads and enforces policy. workerd
14
+ * has no usable image-processing stack — pushing optimization onto
15
+ * the agent sidesteps that entirely.
9
16
  *
10
17
  * # Scope: public bucket only
11
18
  *
12
19
  * `getPublicUrl()` returns an unconditional public URL; reads bypass
13
- * the Worker (`MEDIA_PUBLIC_URL_BASE` → CDN → R2). `MediaAsset.publicUrl`
14
- * is frozen at commit time and embedded directly into entry data
15
- * (e.g. `posts.coverUrl`). For public assets the URL is permanent and
16
- * the read path stays cheap.
20
+ * the Worker (`MEDIA_PUBLIC_URL_BASE` → CDN → R2). Each variant's
21
+ * `publicUrl` is frozen at commit time. The asset is persisted to the
22
+ * `media_assets` table by the commit use case; entries reference it
23
+ * by `MediaAsset.id` (`x-mantle-ref: media_assets`) and the renderer
24
+ * calls `runtime.media.resolve(id)` to materialise the full variants
25
+ * set at render time.
17
26
  *
18
27
  * **Private content (subscription-gated, fan-club, signed-GET, etc.)
19
28
  * is a separate port + separate R2 bucket in v0.2** — see ADR-0011
@@ -27,76 +36,182 @@
27
36
  * `usecase/dto/media/`.
28
37
  */
29
38
  export interface MediaStorage {
30
- /** Create a short-lived direct-upload capability for a single object. */
39
+ /** Issue presigned direct-upload capabilities for every declared
40
+ * variant of one logical asset. The adapter mints storage keys
41
+ * (typically under a shared `<uploadGroupId>/` prefix) and signs a
42
+ * PUT URL per variant. */
31
43
  createUpload(args: CreateUploadArgs): Promise<CreateUploadResult>;
32
- /** Commit a previously-uploaded object after adapter metadata checks. */
44
+ /** Commit a previously-PUT variant bundle. The adapter HEADs every
45
+ * storageKey, verifies actual mime + bytes, and returns a fully
46
+ * populated `MediaAsset` — the use case then persists it to the
47
+ * `media_assets` table via `MediaAssetRepository.save`. All-or-
48
+ * nothing: any variant failing verification rejects the whole
49
+ * commit. */
33
50
  commitUpload(args: CommitUploadArgs): Promise<MediaAsset>;
34
- /** Resolve the stable public URL for an already committed asset. */
51
+ /** Resolve the stable public URL for a single stored object by
52
+ * storageKey. Used by adapter internals and the orphan sweeper
53
+ * (#254); render paths read URLs straight off `MediaAsset.variants`
54
+ * rather than calling this per request. */
35
55
  getPublicUrl(args: GetPublicUrlArgs): Promise<string>;
36
- deleteAsset(args: DeleteAssetArgs): Promise<void>;
56
+ /** Delete a single stored object. The use-case-level deletion path
57
+ * orchestrates "lookup by asset id → delete every variant object →
58
+ * delete media_assets row" by calling this once per variant. */
59
+ deleteObject(args: DeleteObjectArgs): Promise<void>;
60
+ /** Server-side variant byte write — the sandboxed-agent alternative
61
+ * to the presigned-PUT path produced by `createUpload`. Used by
62
+ * the `upload_media_variant` MCP tool when the caller cannot reach
63
+ * the storage backend directly (e.g. Claude Cowork agents — the
64
+ * outbound proxy doesn't allowlist R2 hosts). The adapter writes
65
+ * via its privileged binding (R2 binding for Cloudflare; AWS SDK
66
+ * PUT for a future S3 adapter; etc.) with no signed URL involved.
67
+ *
68
+ * The storage-key layout matches what `createUpload` would have
69
+ * produced for the same `(uploadGroupId, purpose, role, mimeType)`
70
+ * so `commitUpload`'s HEAD-verify still resolves the right object
71
+ * regardless of which path the bytes arrived on.
72
+ *
73
+ * Every adapter MUST implement this method (the interface is
74
+ * required-shaped, not optional). Adapters without a privileged
75
+ * write path implement it as a thrower — typically raising
76
+ * `DiagnosticError(MEDIA_NOT_CONFIGURED)` so the use case surfaces
77
+ * the failure with the expected diagnostic shape. */
78
+ putVariantBytes(args: PutVariantBytesArgs): Promise<PutVariantBytesResult>;
79
+ }
80
+ export interface PutVariantBytesArgs {
81
+ /** Logical asset id — matches the same group's `createUpload`. */
82
+ readonly uploadGroupId: string;
83
+ /** Drives the storage-key prefix. Must match the pending upload's
84
+ * declared purpose. */
85
+ readonly purpose: string;
86
+ readonly role: MediaVariantRole;
87
+ readonly mimeType: string;
88
+ /** Original filename — preserved on the stored object's metadata
89
+ * alongside the variant role + group id, matching createUpload's
90
+ * customMetadata shape so commit's HEAD-verify reads the same
91
+ * fields whether the bytes arrived via presigned PUT or via this
92
+ * server-side path. */
93
+ readonly filename: string;
94
+ readonly bytes: Uint8Array;
95
+ }
96
+ export interface PutVariantBytesResult {
97
+ /** Adapter-minted storage key. Use-case persists this back into the
98
+ * matching `PendingUploadVariant` so commit verifies the right
99
+ * object. */
100
+ readonly storageKey: string;
37
101
  }
102
+ /** Variant role within a logical asset.
103
+ *
104
+ * - `primary` — the `<img>` / fallback rendering. Every asset has
105
+ * exactly one. Conventionally jpeg / png (universal browser support).
106
+ * - `alternate` — additional format candidates the renderer prefers
107
+ * via `<picture><source>`. Modern formats (avif, webp).
108
+ * - `fallback` — reserved for future use (e.g. very-small thumbnail
109
+ * for above-the-fold inlining). Not currently emitted by the
110
+ * `media-tools` agent script.
111
+ */
112
+ export type MediaVariantRole = "primary" | "alternate" | "fallback";
38
113
  export interface CreateUploadArgs {
114
+ /** Logical asset id — also the future `MediaAsset.id`. Minted by
115
+ * the use case via `IdGenerator`; the adapter uses it as the
116
+ * storage-key prefix so every variant of one asset lives under a
117
+ * common path. */
118
+ readonly uploadGroupId: string;
119
+ readonly purpose: string;
120
+ /** Original filename — stamped into each variant's customMetadata
121
+ * at commit time. Storage keys remain server-generated; the
122
+ * filename is purely for operator visibility in R2 / S3 dashboards
123
+ * and for renderers that want to recover a download name. */
39
124
  readonly filename: string;
40
- readonly mimeType: string;
41
- /** Already checked against `maxBytes` by the use case. Adapters may
42
- * forward it as a `Content-Length` constraint when the backend
43
- * supports it. */
44
- readonly byteSize: number;
45
- readonly maxBytes: number;
46
- readonly purpose?: string;
125
+ readonly variants: ReadonlyArray<CreateUploadVariantSpec>;
47
126
  readonly now: number;
48
127
  readonly expiresAt: number;
128
+ /** Optional opaque metadata the adapter may stamp onto the stored
129
+ * objects (e.g. customer tag, deployment env). Not interpreted. */
49
130
  readonly metadata?: Readonly<Record<string, string>>;
50
131
  }
132
+ export interface CreateUploadVariantSpec {
133
+ readonly mimeType: string;
134
+ /** Caller-declared payload size. The use case already verified it
135
+ * satisfies `maxBytes`; passed through so the adapter can forward
136
+ * it as a Content-Length hint where the backend supports one. */
137
+ readonly byteSize: number;
138
+ /** Per-mime cap, sourced from `siteDefaults.media.purposes[name].maxBytes`. */
139
+ readonly maxBytes: number;
140
+ readonly role: MediaVariantRole;
141
+ }
51
142
  export interface CreateUploadResult {
52
- readonly uploadId: string;
143
+ readonly uploadGroupId: string;
144
+ readonly capabilities: ReadonlyArray<UploadCapability>;
145
+ readonly expiresAt: number;
146
+ }
147
+ export interface UploadCapability {
148
+ readonly mimeType: string;
149
+ readonly role: MediaVariantRole;
53
150
  readonly method: "PUT";
54
151
  readonly uploadUrl: string;
55
152
  readonly storageKey: string;
56
- readonly expiresAt: number;
153
+ readonly publicUrl: string;
57
154
  readonly requiredHeaders?: Readonly<Record<string, string>>;
58
- /** Optional preview of the eventual public URL. Commit remains authoritative. */
59
- readonly publicUrl?: string;
60
155
  }
61
156
  /**
62
- * Adapter contract: before returning `MediaAsset`, verify the stored
63
- * object's actual content-type against `expectedMimeType` and actual
64
- * byte size against `maxBytes`. The use case only validates caller-
65
- * declared MIME, not the bytes that landed in storage — without
66
- * adapter-side verification, a caller can declare `image/png` and PUT
67
- * a PDF. Mismatch throw `DiagnosticError(MEDIA_MIME_REJECTED)` or
68
- * `MEDIA_SIZE_EXCEEDED`. (Use whichever metadata primitive the
69
- * backend exposes: R2 / S3 `head()`, filesystem `stat()`.)
157
+ * Adapter contract: for each variant, before populating the returned
158
+ * `MediaAsset`, verify the stored object's actual content-type
159
+ * matches `mimeType` and actual byte size `maxBytes`. Any failure
160
+ * rejects the whole bundle with `DiagnosticError(MEDIA_MIME_REJECTED)`
161
+ * or `MEDIA_VARIANT_SIZE_EXCEEDED`. Without adapter-side verification,
162
+ * a caller can declare `image/png` and PUT a PDF.
70
163
  */
71
164
  export interface CommitUploadArgs {
72
- readonly uploadId: string;
73
- readonly storageKey: string;
74
- /** Adapter must verify stored object's actual content-type matches. */
75
- readonly expectedMimeType: string;
76
- /** Adapter must verify stored object's actual byte size ≤ this. */
77
- readonly maxBytes: number;
165
+ readonly uploadGroupId: string;
166
+ /** Original filename forwarded from the create-time call; adapter
167
+ * stamps it into each variant's customMetadata so operator
168
+ * dashboards see the human-meaningful name alongside the
169
+ * server-generated storage key. */
170
+ readonly filename: string;
171
+ readonly variants: ReadonlyArray<CommitUploadVariantSpec>;
78
172
  readonly alt?: string;
79
173
  readonly caption?: string;
80
- readonly checksum?: string;
81
174
  readonly now: number;
82
175
  }
176
+ export interface CommitUploadVariantSpec {
177
+ readonly mimeType: string;
178
+ readonly role: MediaVariantRole;
179
+ readonly storageKey: string;
180
+ readonly maxBytes: number;
181
+ }
83
182
  export interface GetPublicUrlArgs {
84
- readonly assetId: string;
85
183
  readonly storageKey: string;
86
184
  }
87
- export interface DeleteAssetArgs {
88
- readonly assetId: string;
185
+ export interface DeleteObjectArgs {
89
186
  readonly storageKey: string;
90
187
  }
188
+ /**
189
+ * Committed asset — what `commitUpload` returns and what the
190
+ * `media_assets` table persists. Renderers consume `variants`
191
+ * directly; `<picture>` emits one `<source>` per non-primary
192
+ * variant with `<img>` falling back to the primary one. There is
193
+ * no top-level `publicUrl` — that single-URL world is what
194
+ * #272 replaces.
195
+ */
91
196
  export interface MediaAsset {
92
197
  readonly id: string;
93
- readonly storageKey: string;
94
- readonly publicUrl: string;
95
- readonly mimeType: string;
96
- readonly byteSize: number;
198
+ readonly variants: ReadonlyArray<MediaVariant>;
97
199
  readonly alt?: string;
98
200
  readonly caption?: string;
99
201
  readonly createdAt: number;
100
202
  readonly metadata?: Readonly<Record<string, string>>;
101
203
  }
204
+ export interface MediaVariant {
205
+ readonly mimeType: string;
206
+ readonly publicUrl: string;
207
+ readonly storageKey: string;
208
+ readonly byteSize: number;
209
+ readonly role: MediaVariantRole;
210
+ }
211
+ /** Pick the primary variant (the one `<img>` falls back to). Helper
212
+ * for renderers / SSR that want one URL when they don't care about
213
+ * the full `<picture>` form. Throws if the asset has no primary —
214
+ * the use case rejects commits in that shape, so a runtime-reachable
215
+ * asset always has one. */
216
+ export declare function pickPrimaryVariant(asset: MediaAsset): MediaVariant;
102
217
  //# sourceMappingURL=MediaStorage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MediaStorage.d.ts","sourceRoot":"","sources":["../../../src/domain/port/MediaStorage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MediaStorage.d.ts","sourceRoot":"","sources":["../../../src/domain/port/MediaStorage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,WAAW,YAAY;IAC3B;;;+BAG2B;IAC3B,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAElE;;;;;kBAKc;IACd,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAE1D;;;gDAG4C;IAC5C,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEtD;;qEAEiE;IACjE,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpD;;;;;;;;;;;;;;;;;0DAiBsD;IACtD,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CAC5E;AAED,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;4BACwB;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;4BAIwB;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC;;kBAEc;IACd,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;AAEpE,MAAM,WAAW,gBAAgB;IAC/B;;;uBAGmB;IACnB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;kEAG8D;IAC9D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAC;IAC1D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;wEACoE;IACpE,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;sEAEkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;CACjC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACvD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC7D;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;;;wCAGoC;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAC;IAC1D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IAC/C,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,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;CACjC;AAED;;;;4BAI4B;AAC5B,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,YAAY,CAQlE"}
@@ -1,2 +1,13 @@
1
- export {};
1
+ /** Pick the primary variant (the one `<img>` falls back to). Helper
2
+ * for renderers / SSR that want one URL when they don't care about
3
+ * the full `<picture>` form. Throws if the asset has no primary —
4
+ * the use case rejects commits in that shape, so a runtime-reachable
5
+ * asset always has one. */
6
+ export function pickPrimaryVariant(asset) {
7
+ const primary = asset.variants.find((v) => v.role === "primary");
8
+ if (!primary) {
9
+ throw new Error(`MediaAsset ${asset.id} has no primary variant — commit invariant violated`);
10
+ }
11
+ return primary;
12
+ }
2
13
  //# sourceMappingURL=MediaStorage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MediaStorage.js","sourceRoot":"","sources":["../../../src/domain/port/MediaStorage.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"MediaStorage.js","sourceRoot":"","sources":["../../../src/domain/port/MediaStorage.ts"],"names":[],"mappings":"AAoOA;;;;4BAI4B;AAC5B,MAAM,UAAU,kBAAkB,CAAC,KAAiB;IAClD,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IACjE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,cAAc,KAAK,CAAC,EAAE,qDAAqD,CAC5E,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { SiteConfig, SiteDefaults } from "@aotter/mantle-spec";
1
+ import type { MediaPurposePolicy, SiteConfig, SiteDefaults } from "@aotter/mantle-spec";
2
2
  /**
3
3
  * `SiteConfigRepository` — the `site_config` row read/write surface
4
4
  * the runtime exposes to render paths and `bootInit`.
@@ -22,6 +22,6 @@ export interface SiteConfigRepository {
22
22
  * Empty array when the deployment didn't declare any — symmetric
23
23
  * with "no `MediaStorage` configured" and used by the MCP tool
24
24
  * catalog to gate `create_media_upload` / `commit_media_upload`. */
25
- readMediaPurposes(): Promise<readonly string[]>;
25
+ readMediaPurposes(): Promise<readonly MediaPurposePolicy[]>;
26
26
  }
27
27
  //# sourceMappingURL=SiteConfigRepository.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SiteConfigRepository.d.ts","sourceRoot":"","sources":["../../../src/domain/port/SiteConfigRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEpE;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5B,WAAW,IAAI,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IAC1C;;;yEAGqE;IACrE,iBAAiB,IAAI,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;CACjD"}
1
+ {"version":3,"file":"SiteConfigRepository.d.ts","sourceRoot":"","sources":["../../../src/domain/port/SiteConfigRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExF;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5B,WAAW,IAAI,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IAC1C;;;yEAGqE;IACrE,iBAAiB,IAAI,OAAO,CAAC,SAAS,kBAAkB,EAAE,CAAC,CAAC;CAC7D"}
@@ -19,7 +19,9 @@ export type { AssetServer } from "./AssetServer.js";
19
19
  export type { EntryRepository, CreateEntryArgs, UpdateEntryArgs, DeleteEntryArgs, ArchiveEntryArgs, TransitionStatusArgs, ListEntriesArgs, ListEntriesResult, FindEntryByDataFieldArgs, FindEntryByDataFieldsArgs, MutationHookFields, } from "./EntryRepository.js";
20
20
  export type { SiteConfigRepository } from "./SiteConfigRepository.js";
21
21
  export type { PublishOrchestrator, PublishEntryRequest, } from "./PublishOrchestrator.js";
22
- export type { MediaStorage, CreateUploadArgs, CreateUploadResult, CommitUploadArgs, GetPublicUrlArgs, DeleteAssetArgs, MediaAsset, } from "./MediaStorage.js";
22
+ export type { MediaStorage, CreateUploadArgs, CreateUploadVariantSpec, CreateUploadResult, UploadCapability, CommitUploadArgs, CommitUploadVariantSpec, GetPublicUrlArgs, DeleteObjectArgs, MediaAsset, MediaVariant, MediaVariantRole, } from "./MediaStorage.js";
23
+ export { pickPrimaryVariant } from "./MediaStorage.js";
24
+ export type { MediaAssetRepository } from "./MediaAssetRepository.js";
23
25
  export type { EmailSender, EmailSendArgs, } from "./EmailSender.js";
24
26
  export type { LifecycleHookRunner, RunLifecycleHookRequest, } from "./LifecycleHookRunner.js";
25
27
  export type { DeferredHookDispatcher, DeferredHookEnvelope, CtxSnapshot, } from "./DeferredHookDispatcher.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/domain/port/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,eAAe,EACf,SAAS,GACV,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACxE,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EACV,eAAe,EACf,eAAe,EACf,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,YAAY,EACV,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,WAAW,EACX,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,sBAAsB,EACtB,oBAAoB,EACpB,WAAW,GACZ,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,KAAK,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,KAAK,WAAW,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EACL,KAAK,eAAe,EACpB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/domain/port/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,eAAe,EACf,SAAS,GACV,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACxE,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EACV,eAAe,EACf,eAAe,EACf,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,YAAY,EACV,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,YAAY,EACV,WAAW,EACX,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,sBAAsB,EACtB,oBAAoB,EACpB,WAAW,GACZ,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,KAAK,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,KAAK,WAAW,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EACL,KAAK,eAAe,EACpB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC"}
@@ -1,3 +1,4 @@
1
+ export { pickPrimaryVariant } from "./MediaStorage.js";
1
2
  export { ctxSnapshotFrom } from "./DeferredHookDispatcher.js";
2
3
  export { SystemClock } from "./Clock.js";
3
4
  export { RandomUuidGenerator } from "./IdGenerator.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/domain/port/index.ts"],"names":[],"mappings":"AAiEA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAc,WAAW,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAoB,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAEL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/domain/port/index.ts"],"names":[],"mappings":"AAyDA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAevD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAc,WAAW,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAoB,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAEL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import type { Entry, SiteConfig } from "@aotter/mantle-spec";
2
2
  import type { TemplateRegistry } from "../model/TemplateRegistry.js";
3
3
  import type { SeoMeta } from "../model/SeoMeta.js";
4
+ import type { MediaAsset } from "../port/MediaStorage.js";
4
5
  export interface RenderEntryArgs {
5
6
  readonly entry: Entry;
6
7
  readonly site: SiteConfig;
@@ -8,6 +9,7 @@ export interface RenderEntryArgs {
8
9
  /** Defaults to `<!doctype html>`. Pipelines that want the
9
10
  * upper-case `<!DOCTYPE html>\n` shape pass it explicitly. */
10
11
  readonly doctype?: string;
12
+ readonly mediaAssets?: ReadonlyMap<string, MediaAsset>;
11
13
  /** Optional pre-composed SEO/AEO block. Threaded into the
12
14
  * `EntryContext.seo` field so templates can emit `<SeoTags
13
15
  * seo={seo}/>` inside `<head>`. Renderers that skip composition
@@ -24,6 +26,7 @@ export interface RenderListArgs {
24
26
  readonly site: SiteConfig;
25
27
  readonly templates: TemplateRegistry;
26
28
  readonly doctype?: string;
29
+ readonly mediaAssets?: ReadonlyMap<string, MediaAsset>;
27
30
  readonly seo?: SeoMeta;
28
31
  }
29
32
  /** Returns the full HTML doc or `null` if no list template is
@@ -1 +1 @@
1
- {"version":3,"file":"HtmlRenderer.d.ts","sourceRoot":"","sources":["../../../src/domain/service/HtmlRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAGV,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAgBnD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC;mEAC+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B;;;+DAG2D;IAC3D,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;qDACqD;AACrD,wBAAgB,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CASpE;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;mCACmC;AACnC,wBAAgB,cAAc,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAalE"}
1
+ {"version":3,"file":"HtmlRenderer.d.ts","sourceRoot":"","sources":["../../../src/domain/service/HtmlRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAGV,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAgB1D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC;mEAC+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACvD;;;+DAG2D;IAC3D,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;qDACqD;AACrD,wBAAgB,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAcpE;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACvD,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;mCACmC;AACnC,wBAAgB,cAAc,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAclE"}
@@ -18,7 +18,12 @@ export function renderEntryHtml(args) {
18
18
  if (!tpl)
19
19
  return null;
20
20
  return ((args.doctype ?? DEFAULT_DOCTYPE) +
21
- tpl({ entry: args.entry, site: args.site, seo: args.seo }));
21
+ tpl({
22
+ entry: args.entry,
23
+ site: args.site,
24
+ mediaAssets: args.mediaAssets,
25
+ seo: args.seo,
26
+ }));
22
27
  }
23
28
  /** Returns the full HTML doc or `null` if no list template is
24
29
  * registered for `collection`. */
@@ -32,6 +37,7 @@ export function renderListHtml(args) {
32
37
  locale: args.locale,
33
38
  entries: args.entries,
34
39
  site: args.site,
40
+ mediaAssets: args.mediaAssets,
35
41
  seo: args.seo,
36
42
  }));
37
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"HtmlRenderer.js","sourceRoot":"","sources":["../../../src/domain/service/HtmlRenderer.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;GAWG;AACH,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAgB1C;qDACqD;AACrD,MAAM,UAAU,eAAe,CAAC,IAAqB;IACnD,MAAM,GAAG,GAA8B,IAAI,CAAC,SAAS,CAAC,gBAAgB,CACpE,IAAI,CAAC,KAAK,CAAC,UAAU,CACtB,CAAC;IACF,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,OAAO,CACL,CAAC,IAAI,CAAC,OAAO,IAAI,eAAe,CAAC;QACjC,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAC3D,CAAC;AACJ,CAAC;AAYD;mCACmC;AACnC,MAAM,UAAU,cAAc,CAAC,IAAoB;IACjD,MAAM,GAAG,GAA6B,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACtF,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,OAAO,CACL,CAAC,IAAI,CAAC,OAAO,IAAI,eAAe,CAAC;QACjC,GAAG,CAAC;YACF,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,CAAC,CACH,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"HtmlRenderer.js","sourceRoot":"","sources":["../../../src/domain/service/HtmlRenderer.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;GAWG;AACH,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAiB1C;qDACqD;AACrD,MAAM,UAAU,eAAe,CAAC,IAAqB;IACnD,MAAM,GAAG,GAA8B,IAAI,CAAC,SAAS,CAAC,gBAAgB,CACpE,IAAI,CAAC,KAAK,CAAC,UAAU,CACtB,CAAC;IACF,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,OAAO,CACL,CAAC,IAAI,CAAC,OAAO,IAAI,eAAe,CAAC;QACjC,GAAG,CAAC;YACF,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,CAAC,CACH,CAAC;AACJ,CAAC;AAaD;mCACmC;AACnC,MAAM,UAAU,cAAc,CAAC,IAAoB;IACjD,MAAM,GAAG,GAA6B,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACtF,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,OAAO,CACL,CAAC,IAAI,CAAC,OAAO,IAAI,eAAe,CAAC;QACjC,GAAG,CAAC;YACF,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { Entry } from "@aotter/mantle-spec";
2
+ import type { MediaAssetRepository } from "../../port/MediaAssetRepository.js";
3
+ import type { MediaAsset } from "../../port/MediaStorage.js";
4
+ /**
5
+ * Extract media asset references from entry data by convention.
6
+ * Starters use `coverAssetId`, `imageAssetId`, nested `{ assetId }`, etc.
7
+ * The schema-level source of truth remains `x-mantle-ref: media_assets`;
8
+ * this convention keeps the render path schema-agnostic until the
9
+ * manifest compiler exposes field metadata at runtime.
10
+ */
11
+ export declare function collectMediaAssetIds(value: unknown): readonly string[];
12
+ export declare function resolveMediaAssetsForEntries(repo: MediaAssetRepository | null, entries: readonly Entry[]): Promise<ReadonlyMap<string, MediaAsset> | undefined>;
13
+ //# sourceMappingURL=MediaAssetReferences.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaAssetReferences.d.ts","sourceRoot":"","sources":["../../../../src/domain/service/io/MediaAssetReferences.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE7D;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAItE;AAED,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,oBAAoB,GAAG,IAAI,EACjC,OAAO,EAAE,SAAS,KAAK,EAAE,GACxB,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,SAAS,CAAC,CAKtD"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Extract media asset references from entry data by convention.
3
+ * Starters use `coverAssetId`, `imageAssetId`, nested `{ assetId }`, etc.
4
+ * The schema-level source of truth remains `x-mantle-ref: media_assets`;
5
+ * this convention keeps the render path schema-agnostic until the
6
+ * manifest compiler exposes field metadata at runtime.
7
+ */
8
+ export function collectMediaAssetIds(value) {
9
+ const out = [];
10
+ collect(value, out);
11
+ return [...new Set(out)];
12
+ }
13
+ export async function resolveMediaAssetsForEntries(repo, entries) {
14
+ if (!repo)
15
+ return undefined;
16
+ const ids = collectMediaAssetIds(entries.map((entry) => entry.data));
17
+ if (ids.length === 0)
18
+ return undefined;
19
+ return repo.findManyByIds(ids);
20
+ }
21
+ function collect(value, out) {
22
+ if (value == null)
23
+ return;
24
+ if (Array.isArray(value)) {
25
+ for (const item of value)
26
+ collect(item, out);
27
+ return;
28
+ }
29
+ if (typeof value !== "object")
30
+ return;
31
+ for (const [key, child] of Object.entries(value)) {
32
+ if (typeof child === "string" &&
33
+ (key === "assetId" || key.endsWith("AssetId")) &&
34
+ child.length > 0) {
35
+ out.push(child);
36
+ continue;
37
+ }
38
+ if (Array.isArray(child) && key.endsWith("AssetIds")) {
39
+ for (const item of child) {
40
+ if (typeof item === "string" && item.length > 0)
41
+ out.push(item);
42
+ }
43
+ continue;
44
+ }
45
+ collect(child, out);
46
+ }
47
+ }
48
+ //# sourceMappingURL=MediaAssetReferences.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaAssetReferences.js","sourceRoot":"","sources":["../../../../src/domain/service/io/MediaAssetReferences.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACpB,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,IAAiC,EACjC,OAAyB;IAEzB,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACrE,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACvC,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,OAAO,CAAC,KAAc,EAAE,GAAa;IAC5C,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO;IAC1B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,MAAM,IAAI,IAAI,KAAK;YAAE,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO;IACtC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;QAC5E,IACE,OAAO,KAAK,KAAK,QAAQ;YACzB,CAAC,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YAC9C,KAAK,CAAC,MAAM,GAAG,CAAC,EAChB,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChB,SAAS;QACX,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACrD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;oBAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClE,CAAC;YACD,SAAS;QACX,CAAC;QACD,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACtB,CAAC;AACH,CAAC"}
package/dist/index.d.ts CHANGED
@@ -18,7 +18,9 @@ export { createCmsRuntime, type CreateCmsRuntimeArgs, type CmsRuntime, } from ".
18
18
  export type { DatabaseDriver, PreparedStatement, RunResult, BatchResult, MigrationRunner, Migration, } from "./domain/port/DatabaseDriver.js";
19
19
  export type { KvCache, KvPutOptions, KvListResult } from "./domain/port/KvCache.js";
20
20
  export type { AssetServer } from "./domain/port/AssetServer.js";
21
- export type { MediaStorage, CreateUploadArgs, CreateUploadResult, CommitUploadArgs, GetPublicUrlArgs, DeleteAssetArgs, MediaAsset, } from "./domain/port/MediaStorage.js";
21
+ export type { MediaStorage, CreateUploadArgs, CreateUploadVariantSpec, CreateUploadResult, UploadCapability, CommitUploadArgs, CommitUploadVariantSpec, GetPublicUrlArgs, DeleteObjectArgs, MediaAsset, MediaVariant, MediaVariantRole, PutVariantBytesArgs, PutVariantBytesResult, } from "./domain/port/MediaStorage.js";
22
+ export { pickPrimaryVariant } from "./domain/port/MediaStorage.js";
23
+ export type { MediaAssetRepository } from "./domain/port/MediaAssetRepository.js";
22
24
  export type { EmailSender, EmailSendArgs, } from "./domain/port/EmailSender.js";
23
25
  export { extensionForMime } from "./usecase/media/mediaAllowlist.js";
24
26
  export type { DeferredHookDispatcher, DeferredHookEnvelope, CtxSnapshot, } from "./domain/port/DeferredHookDispatcher.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EACL,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,UAAU,GAChB,MAAM,cAAc,CAAC;AAKtB,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,eAAe,EACf,SAAS,GACV,MAAM,iCAAiC,CAAC;AACzC,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACpF,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,UAAU,GACX,MAAM,+BAA+B,CAAC;AACvC,YAAY,EACV,WAAW,EACX,aAAa,GACd,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,YAAY,EACV,sBAAsB,EACtB,oBAAoB,EACpB,WAAW,GACZ,MAAM,yCAAyC,CAAC;AAKjD,OAAO,EAAE,KAAK,WAAW,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAGrF,YAAY,EACV,UAAU,EACV,cAAc,GACf,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EACL,gBAAgB,EAChB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,GACrB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,GACxB,MAAM,qCAAqC,CAAC;AAI7C,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,yBAAyB,EACzB,WAAW,EACX,UAAU,GACX,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC1E,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,sBAAsB,EACtB,WAAW,GACZ,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAC7E,OAAO,EACL,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,sCAAsC,CAAC;AAI9C,OAAO,EACL,oBAAoB,EACpB,KAAK,cAAc,EACnB,KAAK,WAAW,GACjB,MAAM,8CAA8C,CAAC;AAItD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AAIpF,OAAO,EAAE,aAAa,EAAE,MAAM,+CAA+C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EACL,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,UAAU,GAChB,MAAM,cAAc,CAAC;AAKtB,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,eAAe,EACf,SAAS,GACV,MAAM,iCAAiC,CAAC;AACzC,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACpF,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAClF,YAAY,EACV,WAAW,EACX,aAAa,GACd,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,YAAY,EACV,sBAAsB,EACtB,oBAAoB,EACpB,WAAW,GACZ,MAAM,yCAAyC,CAAC;AAKjD,OAAO,EAAE,KAAK,WAAW,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAGrF,YAAY,EACV,UAAU,EACV,cAAc,GACf,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EACL,gBAAgB,EAChB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,GACrB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,GACxB,MAAM,qCAAqC,CAAC;AAI7C,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,yBAAyB,EACzB,WAAW,EACX,UAAU,GACX,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC1E,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,sBAAsB,EACtB,WAAW,GACZ,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAC7E,OAAO,EACL,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,sCAAsC,CAAC;AAI9C,OAAO,EACL,oBAAoB,EACpB,KAAK,cAAc,EACnB,KAAK,WAAW,GACjB,MAAM,8CAA8C,CAAC;AAItD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AAIpF,OAAO,EAAE,aAAa,EAAE,MAAM,+CAA+C,CAAC"}
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@
16
16
  */
17
17
  // Assembly root.
18
18
  export { createCmsRuntime, } from "./runtime.js";
19
+ export { pickPrimaryVariant } from "./domain/port/MediaStorage.js";
19
20
  export { extensionForMime } from "./usecase/media/mediaAllowlist.js";
20
21
  // ID source — adapters wire this into binding-side helpers that need
21
22
  // random IDs. Default `RandomUuidGenerator` (`crypto.randomUUID()`)
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,iBAAiB;AACjB,OAAO,EACL,gBAAgB,GAGjB,MAAM,cAAc,CAAC;AA4BtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAOrE,qEAAqE;AACrE,oEAAoE;AACpE,wDAAwD;AACxD,OAAO,EAAoB,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAQrF,OAAO,EACL,gBAAgB,GAKjB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,wBAAwB,GAIzB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,mBAAmB,EACnB,iBAAiB,GAGlB,MAAM,qCAAqC,CAAC;AAE7C,kEAAkE;AAClE,oEAAoE;AACpE,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,yBAAyB,EACzB,WAAW,EACX,UAAU,GACX,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC1E,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,sBAAsB,EACtB,WAAW,GACZ,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAC7E,OAAO,EACL,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,sCAAsC,CAAC;AAE9C,iEAAiE;AACjE,4DAA4D;AAC5D,OAAO,EACL,oBAAoB,GAGrB,MAAM,8CAA8C,CAAC;AAEtD,6DAA6D;AAC7D,4DAA4D;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AAEpF,qEAAqE;AACrE,gCAAgC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,+CAA+C,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,iBAAiB;AACjB,OAAO,EACL,gBAAgB,GAGjB,MAAM,cAAc,CAAC;AA+BtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAMnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAOrE,qEAAqE;AACrE,oEAAoE;AACpE,wDAAwD;AACxD,OAAO,EAAoB,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAQrF,OAAO,EACL,gBAAgB,GAKjB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,wBAAwB,GAIzB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,mBAAmB,EACnB,iBAAiB,GAGlB,MAAM,qCAAqC,CAAC;AAE7C,kEAAkE;AAClE,oEAAoE;AACpE,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,yBAAyB,EACzB,WAAW,EACX,UAAU,GACX,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC1E,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,sBAAsB,EACtB,WAAW,GACZ,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAC7E,OAAO,EACL,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,sCAAsC,CAAC;AAE9C,iEAAiE;AACjE,4DAA4D;AAC5D,OAAO,EACL,oBAAoB,GAGrB,MAAM,8CAA8C,CAAC;AAEtD,6DAA6D;AAC7D,4DAA4D;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AAEpF,qEAAqE;AACrE,gCAAgC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,+CAA+C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"canonicalMigrations.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/boot/canonicalMigrations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAErE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,SAAS,EA2JpD,CAAC"}
1
+ {"version":3,"file":"canonicalMigrations.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/boot/canonicalMigrations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAErE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,SAAS,EA6KpD,CAAC"}