@phtngyn/cms 0.1.0-beta.5 → 0.2.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +114 -41
  3. package/package.json +13 -1
  4. package/src/ApplicationTypes.d.ts +84 -0
  5. package/src/ApplicationTypes.js +1 -0
  6. package/src/{Configuration-CDMYfTre.js → Configuration-BU-UyGoH.js} +4 -4
  7. package/src/{Configuration-CDMYfTre.js.map → Configuration-BU-UyGoH.js.map} +1 -1
  8. package/src/Configuration.d.ts +43 -21
  9. package/src/Configuration.js.map +1 -1
  10. package/src/Content.d.ts +67 -0
  11. package/src/Content.js +291 -0
  12. package/src/Content.js.map +1 -0
  13. package/src/{ContentTransfer-C3Av9sWz.js → ContentTransfer-BhF9G56s.js} +8 -4
  14. package/src/ContentTransfer-BhF9G56s.js.map +1 -0
  15. package/src/ContentTransfer-CRQet3QJ.d.ts +48 -0
  16. package/src/{DocumentEngine-J7g-emdf.js → DocumentEngine-ClhFXW9M.js} +4 -4
  17. package/src/{DocumentEngine-J7g-emdf.js.map → DocumentEngine-ClhFXW9M.js.map} +1 -1
  18. package/src/DocumentModel.d.ts +14 -2
  19. package/src/DocumentModel.js +32 -4
  20. package/src/DocumentModel.js.map +1 -1
  21. package/src/{Forms-CfcI3tPU.js → Forms-BbkE7QfC.js} +47 -16
  22. package/src/Forms-BbkE7QfC.js.map +1 -0
  23. package/src/{Forms-Dj6NuW66.js → Forms-DoB56hfe.js} +24 -7
  24. package/src/Forms-DoB56hfe.js.map +1 -0
  25. package/src/{Forms-BsJMev5_.d.ts → Forms-R0HoTR-o.d.ts} +31 -13
  26. package/src/Forms.d.ts +23 -11
  27. package/src/Forms.js.map +1 -1
  28. package/src/I18n-zbqpWxki.d.ts +29 -0
  29. package/src/I18n.d.ts +2 -20
  30. package/src/Module.js +18 -7
  31. package/src/Module.js.map +1 -1
  32. package/src/{S3MediaObjects-CpPSzJto.js → S3MediaObjects-D5Ns4FM6.js} +61 -40
  33. package/src/S3MediaObjects-D5Ns4FM6.js.map +1 -0
  34. package/src/cli/content.js +63 -221
  35. package/src/cli/content.js.map +1 -1
  36. package/src/cli.js +120 -5
  37. package/src/cli.js.map +1 -1
  38. package/src/{connection-CBAy2qGy.js → connection-D5S9Iph-.js} +2 -2
  39. package/src/{connection-CBAy2qGy.js.map → connection-D5S9Iph-.js.map} +1 -1
  40. package/src/dev-lifecycle-CZ7iCzG9.js +515 -0
  41. package/src/dev-lifecycle-CZ7iCzG9.js.map +1 -0
  42. package/src/{installation-CNfIriVm.js → installation-BNuoRDOz.js} +601 -468
  43. package/src/installation-BNuoRDOz.js.map +1 -0
  44. package/src/internal/application-types.js +43 -0
  45. package/src/internal/application-types.js.map +1 -0
  46. package/src/internal/authoring-catalog.js +9 -4
  47. package/src/internal/authoring-catalog.js.map +1 -1
  48. package/src/internal/authoring-metadata.js +1 -1
  49. package/src/internal/configuration.js +149 -46
  50. package/src/internal/configuration.js.map +1 -1
  51. package/src/internal/dev-lifecycle.js +3 -0
  52. package/src/internal/diagnostics.js +47 -0
  53. package/src/internal/diagnostics.js.map +1 -0
  54. package/src/internal/document-model.js +2 -2
  55. package/src/internal/document-model.js.map +1 -1
  56. package/src/internal/form-capabilities.js +1 -1
  57. package/src/internal/i18n.js +27 -1
  58. package/src/internal/i18n.js.map +1 -1
  59. package/src/{location-BTqdfIzX.js → location-CPX7oj0o.js} +2 -2
  60. package/src/{location-BTqdfIzX.js.map → location-CPX7oj0o.js.map} +1 -1
  61. package/src/{models-B4IoTmp7.js → models-C9kF9JlQ.js} +2 -2
  62. package/src/{models-B4IoTmp7.js.map → models-C9kF9JlQ.js.map} +1 -1
  63. package/src/{models-Bah5B3bT.js → models-ChRxBChy.js} +9 -2
  64. package/src/models-ChRxBChy.js.map +1 -0
  65. package/src/runtime/delivery/context.js +1 -1
  66. package/src/runtime/delivery/plugin.js +28 -5
  67. package/src/runtime/delivery/plugin.js.map +1 -1
  68. package/src/runtime/delivery/preview.d.ts +1 -1
  69. package/src/runtime/delivery/types.d.ts +2 -85
  70. package/src/runtime/delivery/useCmsDocumentSeo.d.ts +8 -1
  71. package/src/runtime/delivery/useCmsDocumentSeo.js +19 -7
  72. package/src/runtime/delivery/useCmsDocumentSeo.js.map +1 -1
  73. package/src/runtime/delivery/useDocument.d.ts +2 -2
  74. package/src/runtime/delivery/useDocument.js.map +1 -1
  75. package/src/runtime/delivery/useDocumentQuery.d.ts +3 -3
  76. package/src/runtime/delivery/useDocumentQuery.js.map +1 -1
  77. package/src/runtime/forms/document.js +1 -1
  78. package/src/runtime/forms/useCmsForm.js +89 -45
  79. package/src/runtime/forms/useCmsForm.js.map +1 -1
  80. package/src/runtime/i18n/useCmsI18n.d.ts +9 -7
  81. package/src/runtime/i18n/useCmsI18n.js +5 -4
  82. package/src/runtime/i18n/useCmsI18n.js.map +1 -1
  83. package/src/runtime/installation.js +2 -2
  84. package/src/runtime/plugin.js +12 -4
  85. package/src/runtime/plugin.js.map +1 -1
  86. package/src/runtime/preview/connection.js +1 -1
  87. package/src/runtime/preview/controller.js +2 -2
  88. package/src/runtime/preview/plugin.client.js +3 -3
  89. package/src/runtime/preview/store.js +1 -1
  90. package/src/runtime/sitemap.js +1 -1
  91. package/src/scalars-CA6kyipS.d.ts +7 -0
  92. package/src/{store-b2CSXgMt.js → store-B49J21NA.js} +3 -3
  93. package/src/{store-b2CSXgMt.js.map → store-B49J21NA.js.map} +1 -1
  94. package/src/types-DutFRtaG.d.ts +90 -0
  95. package/studio/{CreateDocumentDialog-GGey1uBc.js → CreateDocumentDialog-DJ8c0WZb.js} +3 -3
  96. package/studio/{documentPlanning-DRErYmBU.js → documentPlanning-CDb31mnl.js} +5935 -5869
  97. package/studio/host.css +1 -1
  98. package/studio/host.js +7608 -7250
  99. package/src/ContentTransfer-C3Av9sWz.js.map +0 -1
  100. package/src/Forms-CfcI3tPU.js.map +0 -1
  101. package/src/Forms-Dj6NuW66.js.map +0 -1
  102. package/src/S3MediaObjects-CpPSzJto.js.map +0 -1
  103. package/src/installation-CNfIriVm.js.map +0 -1
  104. package/src/models-Bah5B3bT.js.map +0 -1
@@ -1,12 +1,12 @@
1
1
  import { c as RevisionId, d as SourcePath, f as nonNegativeInt, i as DocumentVersion, n as DocumentHistoryCursor, o as PublicPath, r as DocumentId, s as RelativeDocumentPath, t as DocumentGeneration, u as Slug } from "./scalars-B2lgGUnj.js";
2
- import { i as FormResult, o as FormSubmission } from "./Forms-CfcI3tPU.js";
3
- import { a as encodeCmsEditorComponentAttributes, d as createCmsComarkRenderData, m as toComarkDocument, p as mutableJsonObject, s as projectCmsEditorComponentAttributes } from "./Forms-Dj6NuW66.js";
4
- import { $ as StudioActor, B as SeoMediaUnavailable, C as PublishedDocumentLookup, D as RemoveDocumentInput, E as PublishedDocumentSurroundQuery, Et as RequestId, F as SaveSeoInput, G as SeoUrl, I as SeoCanonicalOrigin, J as AccessDenied, K as SeoVersionConflict, L as SeoCapabilities, N as GlobalSeoSettings, O as RestoreDocumentInput, P as PublishSeoInput, Q as Role, R as SeoConfiguration, S as PublishDocumentInput, T as PublishedDocumentQuery, U as SeoSnapshot, V as SeoMutationResult, W as SeoState, X as DOCUMENT_ACTIONS, Y as AuthenticationRequired, Z as MEDIA_ACTIONS, _ as DocumentSurround, _t as MediaReference, at as MediaCleanupReport, bt as MediaTooLarge, c as DocumentIssue, ct as MediaFolder, d as DocumentNavigationQuery, dt as MediaInvalid, et as StudioEntryDenied, f as DocumentQueryScalar, g as DocumentSummary, gt as MediaQuery, ht as MediaPage, i as CreateDocumentInput, it as MediaByteSize, j as UpdateDocumentInput, k as UndeleteDocumentInput, l as DocumentMutationResult, lt as MediaId, m as DocumentSource, mt as MediaObjectKey, n as CmsMarkdownDocument, nt as ImageMimeType, o as DeletedDocument, ot as MediaConflict, p as DocumentRevisionAction, pt as MediaNotFound, q as SitemapEntry, r as CompiledDocument, rt as MediaAsset, s as DocumentBrowseQuery, u as DocumentNavigationItem, ut as MediaIntegrityReport, v as DocumentValidationResult, vt as MediaReferenced, w as PublishedDocumentPage, x as MoveDocumentInput, xt as MediaUpload, y as DuplicateDocumentInput, z as SeoConfirmationRequired } from "./models-Bah5B3bT.js";
2
+ import { $ as StudioActor, B as SeoMediaUnavailable, C as PublishedDocumentLookup, D as RemoveDocumentInput, E as PublishedDocumentSurroundQuery, Et as RequestId, F as SaveSeoInput, G as SeoUrl, I as SeoCanonicalOrigin, J as AccessDenied, K as SeoVersionConflict, L as SeoCapabilities, N as GlobalSeoSettings, O as RestoreDocumentInput, P as PublishSeoInput, Q as Role, R as SeoConfiguration, S as PublishDocumentInput, T as PublishedDocumentQuery, U as SeoSnapshot, V as SeoMutationResult, W as SeoState, X as DOCUMENT_ACTIONS, Y as AuthenticationRequired, Z as MEDIA_ACTIONS, _ as DocumentSurround, _t as MediaReference, at as MediaCleanupReport, bt as MediaTooLarge, c as DocumentIssue, ct as MediaFolder, d as DocumentNavigationQuery, dt as MediaInvalid, et as StudioEntryDenied, f as DocumentQueryScalar, g as DocumentSummary, gt as MediaQuery, ht as MediaPage, i as CreateDocumentInput, it as MediaByteSize, j as UpdateDocumentInput, k as UndeleteDocumentInput, l as DocumentMutationResult, lt as MediaId, m as DocumentSource, mt as MediaObjectKey, n as CmsMarkdownDocument, nt as ImageMimeType, o as DeletedDocument, ot as MediaConflict, p as DocumentRevisionAction, pt as MediaNotFound, q as SitemapEntry, r as CompiledDocument, rt as MediaAsset, s as DocumentBrowseQuery, u as DocumentNavigationItem, ut as MediaIntegrityReport, v as DocumentValidationResult, vt as MediaReferenced, w as PublishedDocumentPage, x as MoveDocumentInput, xt as MediaUpload, y as DuplicateDocumentInput, z as SeoConfirmationRequired } from "./models-ChRxBChy.js";
3
+ import { i as ContentSnapshot, n as ContentApplyResult, o as ContentTransferConflict, r as ContentPlan, s as ContentTransferInput, t as ContentApplyInput } from "./ContentTransfer-BhF9G56s.js";
5
4
  import { u as STUDIO_API_PATH } from "./HttpPaths-c9nLZ9H2.js";
5
+ import { c as FormSubmission, o as FormResult } from "./Forms-BbkE7QfC.js";
6
+ import { a as encodeCmsEditorComponentAttributes, d as createCmsComarkRenderData, m as toComarkDocument, p as mutableJsonObject, s as projectCmsEditorComponentAttributes } from "./Forms-DoB56hfe.js";
6
7
  import { i as withoutEditorMetadata } from "./metadata-BEZPWh-3.js";
7
- import { d as EditorRenderFailed, i as MediaConfiguration, r as DocumentConfiguration } from "./Configuration-CDMYfTre.js";
8
- import { i as ContentSnapshot, n as ContentApplyResult, o as ContentTransferConflict, r as ContentPlan, s as ContentTransferInput, t as ContentApplyInput } from "./ContentTransfer-C3Av9sWz.js";
9
- import { a as normalizeDocumentRelativePath, c as resolveDocumentAddress, i as localizeDocumentPath, n as referenceTarget, o as normalizePublicPath, r as DocumentCompilationFailed, s as parseDocumentAddress, t as createDocumentEngine } from "./DocumentEngine-J7g-emdf.js";
8
+ import { d as EditorRenderFailed, i as MediaConfiguration, r as DocumentConfiguration } from "./Configuration-BU-UyGoH.js";
9
+ import { a as normalizeDocumentRelativePath, c as resolveDocumentAddress, i as localizeDocumentPath, n as referenceTarget, o as normalizePublicPath, r as DocumentCompilationFailed, s as parseDocumentAddress, t as createDocumentEngine } from "./DocumentEngine-ClhFXW9M.js";
10
10
  import { Context, Crypto, Data, DateTime, Effect, Encoding, Layer, Option, Predicate, PubSub, Redacted, Ref, Result, Schedule, Schema, Semaphore, Stream, flow } from "effect";
11
11
  import { NodeStream } from "@effect/platform-node-shared";
12
12
  import { Multipart } from "effect/unstable/http";
@@ -559,7 +559,8 @@ const StudioDocumentsApi = HttpApiGroup.make("documents").add(HttpApiEndpoint.ge
559
559
  params: { documentId: DocumentId },
560
560
  payload: Schema.Struct({
561
561
  ...MoveDocumentPayload.fields,
562
- includeChildren: DuplicateDocumentInput.fields.includeChildren
562
+ includeChildren: DuplicateDocumentInput.fields.includeChildren,
563
+ locale: DuplicateDocumentInput.fields.locale
563
564
  }),
564
565
  success: DocumentMutationResult,
565
566
  error: MutationErrors
@@ -1244,7 +1245,7 @@ const prepareTreeMutation = Effect.fn("Documents.prepareTreeMutation")(function*
1244
1245
  sourcePath: root.sourcePath
1245
1246
  }) ?? "";
1246
1247
  const nextRelative = destination.kind === "home" ? "" : [destination.parent, destination.slug].filter(Boolean).join("/");
1247
- if (rootRelative && (nextRelative === rootRelative || nextRelative.startsWith(`${rootRelative}/`))) return yield* invalid("Choose a destination outside this page and its subpages.");
1248
+ if (!(command.action === "document.duplicate" && command.input.locale !== void 0 && command.input.locale !== parent.locale) && rootRelative && (nextRelative === rootRelative || nextRelative.startsWith(`${rootRelative}/`))) return yield* invalid("Choose a destination outside this page and its subpages.");
1248
1249
  const relative = documentRelativePath(collection, {
1249
1250
  document: page,
1250
1251
  sourcePath: source.sourcePath
@@ -1255,8 +1256,9 @@ const prepareTreeMutation = Effect.fn("Documents.prepareTreeMutation")(function*
1255
1256
  kind: "entry",
1256
1257
  slug: yield* decodeSlug(slug)
1257
1258
  }, segments.length ? { parent: yield* decodeParent(segments.join("/")) } : void 0) : { kind: "home" };
1258
- const sourcePath = yield* Effect.fromResult(planDocumentMove(configuration, page, location));
1259
- const markdown = yield* relocateDocumentMarkdown(configuration, page, location, source.markdown).pipe(Effect.mapError(() => invalid("The page could not be copied to its new URL.")));
1259
+ const destinationPage = command.action === "document.duplicate" && command.input.locale ? Object.assign({}, page, { locale: command.input.locale }) : page;
1260
+ const sourcePath = yield* Effect.fromResult(planDocumentMove(configuration, destinationPage, location));
1261
+ const markdown = yield* relocateDocumentMarkdown(configuration, destinationPage, location, source.markdown).pipe(Effect.mapError(() => invalid("The page could not be copied to its new URL.")));
1260
1262
  if (command.action === "document.duplicate") {
1261
1263
  const documentId = yield* command.nextDocumentId;
1262
1264
  plans.push({
@@ -1694,7 +1696,7 @@ const commitDocumentMutation = Effect.fn("Documents.commitMutation")(function* (
1694
1696
  resource: {
1695
1697
  kind: "collection",
1696
1698
  collection: source.collection,
1697
- locale: source.locale
1699
+ locale: command.input.locale ?? source.locale
1698
1700
  }
1699
1701
  });
1700
1702
  }
@@ -2191,6 +2193,7 @@ const makeDocuments = Effect.fn("Documents.make")(function* (configuration, opti
2191
2193
  return ContentSnapshot.make({
2192
2194
  version: 1,
2193
2195
  sources: current.snapshot.active.map((source) => ({
2196
+ documentId: source.documentId,
2194
2197
  sourcePath: source.sourcePath,
2195
2198
  markdown: source.markdown,
2196
2199
  published: source.publishedVersion === source.version
@@ -2431,17 +2434,30 @@ const seoDeliveryLayer = Layer.effect(SeoDelivery, Effect.gen(function* () {
2431
2434
  const previews = yield* PreviewSeo;
2432
2435
  const published = yield* PublishedSeo;
2433
2436
  const documents = yield* PublishedDocuments;
2434
- const resolveWith = (document, snapshot) => CompiledDocument.make(Object.assign({}, document, { resolvedSeo: resolveDocumentSeo({
2435
- capabilities: snapshot.capabilities,
2436
- document,
2437
- global: snapshot.revision.settings
2438
- }) }));
2439
- const publishedDocument = Effect.fn("SeoDelivery.publishedDocument")((document) => published.read.pipe(Effect.map((snapshot) => resolveWith(document, snapshot))));
2440
- const previewDocument = Effect.fn("SeoDelivery.previewDocument")((document) => previews.read.pipe(Effect.map((snapshot) => resolveWith(document, snapshot))));
2437
+ const alternatives = (document) => documents.snapshot.pipe(Effect.map((snapshot) => snapshot.flatMap((candidate) => candidate.key === document.key && candidate.locale !== void 0 ? [{
2438
+ locale: candidate.locale,
2439
+ path: candidate.path
2440
+ }] : [])));
2441
+ const resolveWith = (document, snapshot, localized) => CompiledDocument.make(Object.assign({}, document, {
2442
+ alternatives: localized,
2443
+ resolvedSeo: resolveDocumentSeo({
2444
+ capabilities: snapshot.capabilities,
2445
+ document,
2446
+ global: snapshot.revision.settings
2447
+ })
2448
+ }));
2449
+ const publishedDocument = Effect.fn("SeoDelivery.publishedDocument")((document) => Effect.all({
2450
+ snapshot: published.read,
2451
+ alternatives: alternatives(document)
2452
+ }).pipe(Effect.map(({ alternatives, snapshot }) => resolveWith(document, snapshot, alternatives))));
2453
+ const previewDocument = Effect.fn("SeoDelivery.previewDocument")((document) => Effect.all({
2454
+ snapshot: previews.read,
2455
+ alternatives: alternatives(document)
2456
+ }).pipe(Effect.map(({ alternatives, snapshot }) => resolveWith(document, snapshot, alternatives))));
2441
2457
  const sitemap = Effect.gen(function* () {
2442
2458
  const snapshot = yield* published.read;
2443
2459
  const resolved = (yield* documents.snapshot).flatMap((document) => {
2444
- const resolvedDocument = resolveWith(document, snapshot);
2460
+ const resolvedDocument = resolveWith(document, snapshot, []);
2445
2461
  return resolvedDocument.resolvedSeo?.index === true && resolvedDocument.source.publishedAt !== void 0 ? [resolvedDocument] : [];
2446
2462
  });
2447
2463
  const localesByKey = /* @__PURE__ */ new Map();
@@ -2600,30 +2616,30 @@ function s3MediaObjectStoreLayer(options) {
2600
2616
  }
2601
2617
  function makeStore(options, client) {
2602
2618
  return {
2603
- list: listObjects(options.bucket, client),
2604
- promote: (input) => promoteObject(options.bucket, input, client),
2605
- put: (input) => putObject(options.bucket, input, client),
2619
+ list: listObjects(options.bucket, options.prefix, client),
2620
+ promote: (input) => promoteObject(options.bucket, options.prefix, input, client),
2621
+ put: (input) => putObject(options.bucket, options.prefix, input, client),
2606
2622
  remove: (objectKey) => providerRequest("MediaObjectStore.S3.remove", client.deleteObject({
2607
2623
  bucket: options.bucket,
2608
- key: objectKey
2624
+ key: physicalKey(options.prefix, objectKey)
2609
2625
  })),
2610
- stat: (objectKey) => statObject(options.bucket, objectKey, client)
2626
+ stat: (objectKey) => statObject(options.bucket, options.prefix, objectKey, client)
2611
2627
  };
2612
2628
  }
2613
- function promoteObject(bucket, input, client) {
2629
+ function promoteObject(bucket, prefix, input, client) {
2614
2630
  if (input.byteSize > 5e9) return Effect.fail(storageError("MediaObjectStore.S3.promote", "The object exceeds the S3 single-copy size limit."));
2615
- return statObject(bucket, input.sourceObjectKey, client).pipe(Effect.flatMap((source) => Option.isSome(source) && source.value.byteSize === input.byteSize && source.value.mimeType === input.mimeType ? Effect.void : Effect.fail(storageError("MediaObjectStore.S3.promote.source", "The staged object metadata does not match its intent."))), Effect.flatMap(() => providerRequest("MediaObjectStore.S3.promote.copy", client.copyObject({
2631
+ return statObject(bucket, prefix, input.sourceObjectKey, client).pipe(Effect.flatMap((source) => Option.isSome(source) && source.value.byteSize === input.byteSize && source.value.mimeType === input.mimeType ? Effect.void : Effect.fail(storageError("MediaObjectStore.S3.promote.source", "The staged object metadata does not match its intent."))), Effect.flatMap(() => providerRequest("MediaObjectStore.S3.promote.copy", client.copyObject({
2616
2632
  bucket,
2617
2633
  cacheControl: replaceableMediaCacheControl,
2618
2634
  contentType: input.mimeType,
2619
- copySource: copySource(bucket, input.sourceObjectKey),
2620
- key: input.destinationObjectKey
2621
- }))), Effect.flatMap(() => statObject(bucket, input.destinationObjectKey, client)), Effect.flatMap((destination) => Option.isSome(destination) && destination.value.byteSize === input.byteSize && destination.value.mimeType === input.mimeType ? Effect.succeed(destination.value) : Effect.fail(storageError("MediaObjectStore.S3.promote.verify", "The promoted object metadata does not match its intent."))));
2635
+ copySource: copySource(bucket, physicalKey(prefix, input.sourceObjectKey)),
2636
+ key: physicalKey(prefix, input.destinationObjectKey)
2637
+ }))), Effect.flatMap(() => statObject(bucket, prefix, input.destinationObjectKey, client)), Effect.flatMap((destination) => Option.isSome(destination) && destination.value.byteSize === input.byteSize && destination.value.mimeType === input.mimeType ? Effect.succeed(destination.value) : Effect.fail(storageError("MediaObjectStore.S3.promote.verify", "The promoted object metadata does not match its intent."))));
2622
2638
  }
2623
2639
  function copySource(bucket, objectKey) {
2624
2640
  return `/${encodeURIComponent(bucket)}/${objectKey.split("/").map(encodeURIComponent).join("/")}`;
2625
2641
  }
2626
- function putObject(bucket, input, client) {
2642
+ function putObject(bucket, prefix, input, client) {
2627
2643
  return Effect.gen(function* () {
2628
2644
  const body = yield* validatedWriteBody(input);
2629
2645
  yield* client.putObject({
@@ -2632,7 +2648,7 @@ function putObject(bucket, input, client) {
2632
2648
  cacheControl: replaceableMediaCacheControl,
2633
2649
  contentLength: input.byteSize,
2634
2650
  contentType: input.mimeType,
2635
- key: input.objectKey
2651
+ key: physicalKey(prefix, input.objectKey)
2636
2652
  }).pipe(Effect.catch((failure) => isWriteBodyError(failure.cause) ? Effect.fail(failure.cause) : Effect.fail(providerError("MediaObjectStore.S3.put", failure))));
2637
2653
  return {
2638
2654
  byteSize: input.byteSize,
@@ -2648,27 +2664,27 @@ const validatedWriteBody = Effect.fn("MediaObjectStore.S3.validateWriteBody")(fu
2648
2664
  return chunk;
2649
2665
  })), Stream.concat(Stream.fromEffect(Ref.get(byteLength).pipe(Effect.flatMap((actual) => actual === input.byteSize ? Effect.void : Effect.fail(storageError("MediaObjectStore.S3.put.body", "The object body does not match its declared byte size."))))).pipe(Stream.drain)));
2650
2666
  });
2651
- function statObject(bucket, objectKey, client) {
2667
+ function statObject(bucket, prefix, objectKey, client) {
2652
2668
  return client.headObject({
2653
2669
  bucket,
2654
- key: objectKey
2670
+ key: physicalKey(prefix, objectKey)
2655
2671
  }).pipe(Effect.matchEffect({
2656
2672
  onFailure: (failure) => isMissingObject(failure.cause) ? Effect.succeed(Option.none()) : Effect.fail(providerError("MediaObjectStore.S3.stat", failure)),
2657
2673
  onSuccess: (output) => decodeStoredObject("MediaObjectStore.S3.stat", objectKey, output.contentLength, output.contentType).pipe(Effect.asSome)
2658
2674
  }));
2659
2675
  }
2660
- function listObjects(bucket, client) {
2676
+ function listObjects(bucket, prefix, client) {
2661
2677
  return Stream.paginate({ seenTokens: /* @__PURE__ */ new Set() }, (state) => providerRequest("MediaObjectStore.S3.list", client.listObjects({
2662
2678
  bucket,
2663
2679
  continuationToken: state.continuationToken,
2664
- prefix: mediaObjectPrefix
2680
+ prefix: `${prefix}${mediaObjectPrefix}`
2665
2681
  })).pipe(Effect.flatMap((page) => Effect.gen(function* () {
2666
- return [yield* Effect.forEach(page.objects, decodeListedObject), yield* nextListState(state, page)];
2682
+ return [yield* Effect.forEach(page.objects, (object) => decodeListedObject(object, prefix)), yield* nextListState(state, page)];
2667
2683
  }))));
2668
2684
  }
2669
- function decodeListedObject(object) {
2685
+ function decodeListedObject(object, prefix) {
2670
2686
  if (object.key === void 0) return Effect.fail(storageError("MediaObjectStore.S3.list", "The provider returned object metadata without a key."));
2671
- return decodeStoredObject("MediaObjectStore.S3.list", object.key, object.size);
2687
+ return decodeStoredObject("MediaObjectStore.S3.list", object.key.slice(prefix.length), object.size);
2672
2688
  }
2673
2689
  function nextListState(state, page) {
2674
2690
  if (!page.isTruncated) return Effect.succeedNone;
@@ -2742,7 +2758,8 @@ function resolveOptions(options) {
2742
2758
  const bucket = options.bucket.trim();
2743
2759
  const region = options.region.trim();
2744
2760
  const endpoint = options.endpoint?.trim();
2745
- if (!bucket || !region || options.endpoint !== void 0 && !endpoint) return Effect.fail(storageError("MediaObjectStore.S3.configure", "The bucket, region, and configured endpoint must be non-empty."));
2761
+ const prefix = options.prefix.trim();
2762
+ if (!bucket || !region || options.endpoint !== void 0 && !endpoint || !prefix || prefix.startsWith("/") || !prefix.endsWith("/") || prefix.includes("..")) return Effect.fail(storageError("MediaObjectStore.S3.configure", "The bucket, region, configured endpoint, and relative object prefix must be valid."));
2746
2763
  if (options.credentials) {
2747
2764
  const secretAccessKey = Redacted.value(options.credentials.secretAccessKey);
2748
2765
  const sessionToken = options.credentials.sessionToken && Redacted.value(options.credentials.sessionToken);
@@ -2757,10 +2774,14 @@ function resolveOptions(options) {
2757
2774
  } : void 0,
2758
2775
  endpoint,
2759
2776
  forcePathStyle: options.forcePathStyle ?? false,
2777
+ prefix,
2760
2778
  provisionBucket: options.provisionBucket ?? false,
2761
2779
  region
2762
2780
  });
2763
2781
  }
2782
+ function physicalKey(prefix, objectKey) {
2783
+ return `${prefix}${objectKey}`;
2784
+ }
2764
2785
  function storageError(operation, message) {
2765
2786
  return new MediaStorageError({
2766
2787
  cause: new Error(message),
@@ -2774,4 +2795,4 @@ const maxS3SingleCopyBytes = 5e9;
2774
2795
 
2775
2796
  //#endregion
2776
2797
  export { DocumentRevision as $, StudioBadRequest as A, User as B, DocumentStore as C, CurrentStudioRequest as D, defaultAccessControlLayer as E, studioInternalError as F, UserSelfRemovalDenied as G, UserAlreadyExists as H, InitializationAlreadyCompleted as I, CollaborationServerMessage as J, UserSelfRoleChangeDenied as K, InitializationProofInvalid as L, StudioRequestConflict as M, StudioSchemaError as N, StudioApi as O, StudioInternalError as P, DocumentHistoryInvalidCursor as Q, InitializationState as R, DocumentPersistenceError as S, AccessControl as T, UserNotFound as U, UserAdministrationDenied as V, UserPage as W, StateVector as X, CollaborationTicket as Y, DocumentHistoryComparisonTooLarge as Z, Documents as _, mediaObjectPrefix as a, ActivityEntry as at, cursorCodec as b, Seo as c, ActivityPage as ct, seoDeliveryLayer as d, DocumentMediaUnavailable as dt, ACTIVITY_ACTIONS as et, seoLayer as f, DocumentNotFound as ft, DocumentPreviews as g, PublishedDocumentNotFound as gt, DocumentMaintenance as h, DocumentVersionConflict as ht, MediaObjectStore as i, ActivityCursorInvalid as it, StudioBootstrap as j, StudioAuthentication as k, SeoDelivery as l, ActivityTarget as lt, SeoStore as m, DocumentValidationFailed as mt, s3MediaObjectStoreLayer as n, ActivityContext as nt, PreviewSeo as o, ActivityEntryDraft as ot, SeoPersistenceError as p, DocumentPathConflict as pt, CollaborationClientMessage as q, MediaPersistenceError as r, ActivityCursor as rt, PublishedSeo as s, ActivityId as st, maxS3SingleCopyBytes as t, ActivityAction as tt, makeDefaultSeoOptions as u, ActivityTargetKind as ut, PublishedDocuments as v, renderEditorMarkdown as w, DocumentGenerationConflict as x, documentsLayer as y, CreateUserInput as z };
2777
- //# sourceMappingURL=S3MediaObjects-CpPSzJto.js.map
2798
+ //# sourceMappingURL=S3MediaObjects-D5Ns4FM6.js.map