@vryzel/file-next 0.4.4 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -45,7 +45,7 @@ export const actions = createServerActions({
45
45
  fs,
46
46
  writeThrough: createWriteThrough(fs, store),
47
47
  getAuth: () => ({
48
- tenantId: asTenantId("acme"),
48
+ tenantId: asTenantId("demo"),
49
49
  userId: asUserId("user-1"),
50
50
  }),
51
51
  });
@@ -140,8 +140,8 @@ Missing config throws `FileSystemError` (not retryable).
140
140
  ### 6. Multi-tenant keys
141
141
 
142
142
  ```ts
143
- const scoped = fs.forTenant("acme");
144
- // object keys are prefixed t/acme/{nodeId} unless prefixTenantKeys: false
143
+ const scoped = fs.forTenant("demo");
144
+ // object keys are prefixed t/demo/{nodeId} unless prefixTenantKeys: false
145
145
  ```
146
146
 
147
147
  Every store method also takes `tenantId`. Do not take tenant from the request body.
@@ -210,6 +210,12 @@ interface PresignedUploadInput {
210
210
  interface PresignedDownloadInput {
211
211
  key: S3Key;
212
212
  expiresIn?: number;
213
+ /**
214
+ * Default `attachment`. `inline` is honored only for non-executing preview types.
215
+ * Pass `contentType` or the signer keeps `attachment`.
216
+ */
217
+ disposition?: "attachment" | "inline";
218
+ contentType?: string;
213
219
  }
214
220
  interface GetPublicUrlInput {
215
221
  key: S3Key;
@@ -210,6 +210,12 @@ interface PresignedUploadInput {
210
210
  interface PresignedDownloadInput {
211
211
  key: S3Key;
212
212
  expiresIn?: number;
213
+ /**
214
+ * Default `attachment`. `inline` is honored only for non-executing preview types.
215
+ * Pass `contentType` or the signer keeps `attachment`.
216
+ */
217
+ disposition?: "attachment" | "inline";
218
+ contentType?: string;
213
219
  }
214
220
  interface GetPublicUrlInput {
215
221
  key: S3Key;
package/dist/index.cjs CHANGED
@@ -3061,6 +3061,20 @@ var setMetadata = async (client, config, input) => {
3061
3061
  return err(fromAws(e));
3062
3062
  }
3063
3063
  };
3064
+
3065
+ // src/storage/content-disposition.ts
3066
+ var NEVER_INLINE = /* @__PURE__ */ new Set(["text/html", "application/xhtml+xml", "image/svg+xml"]);
3067
+ function signedContentDisposition(requested, contentType) {
3068
+ if (requested !== "inline") return "attachment";
3069
+ const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase() ?? "";
3070
+ if (!mime || NEVER_INLINE.has(mime)) return "attachment";
3071
+ if (mime === "application/pdf" || mime === "text/plain" || mime === "text/csv" || mime === "text/markdown" || mime.startsWith("image/") || mime.startsWith("video/") || mime.startsWith("audio/")) {
3072
+ return "inline";
3073
+ }
3074
+ return "attachment";
3075
+ }
3076
+
3077
+ // src/storage/s3-adapter/presigned.ts
3064
3078
  var createPresignedUploadUrl = async (client, config, input) => {
3065
3079
  try {
3066
3080
  const cmd = new clientS3.PutObjectCommand({
@@ -3078,7 +3092,8 @@ var createPresignedDownloadUrl = async (client, config, input) => {
3078
3092
  try {
3079
3093
  const cmd = new clientS3.GetObjectCommand({
3080
3094
  Bucket: config.bucket,
3081
- Key: input.key
3095
+ Key: input.key,
3096
+ ResponseContentDisposition: signedContentDisposition(input.disposition, input.contentType)
3082
3097
  });
3083
3098
  const url = await s3RequestPresigner.getSignedUrl(client, cmd, { expiresIn: input.expiresIn ?? 900 });
3084
3099
  return ok({ url });