@zaclinley/dsh-mailharbor 0.16.0 → 0.17.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/lib/index.js CHANGED
@@ -1209,6 +1209,18 @@ var MailDatabase = class {
1209
1209
  where.push("e.date >= ?");
1210
1210
  params.push(query.since);
1211
1211
  }
1212
+ if (typeof query.before === "string" && query.before !== "") {
1213
+ where.push("e.date < ?");
1214
+ params.push(query.before.length === 10 ? `${query.before} 23:59:59` : query.before);
1215
+ }
1216
+ if (typeof query.from === "string" && query.from.trim() !== "") {
1217
+ const needle = `%${query.from.trim().toLowerCase()}%`;
1218
+ where.push("(lower(e.from_addr) LIKE ? OR lower(e.from_name) LIKE ?)");
1219
+ params.push(needle, needle);
1220
+ }
1221
+ if (query.attachmentsOnly === true) {
1222
+ where.push("EXISTS (SELECT 1 FROM attachments a WHERE a.email_id = e.id)");
1223
+ }
1212
1224
  if (query.unread !== void 0) {
1213
1225
  const mids = query.unread.mids.slice(0, 500);
1214
1226
  const ids = query.unread.ids.slice(0, 500);
@@ -2768,7 +2780,7 @@ ${conversation.trim()}
2768
2780
  }
2769
2781
 
2770
2782
  // src/host/version.ts
2771
- var VERSION = "0.16.0";
2783
+ var VERSION = "0.17.0";
2772
2784
 
2773
2785
  // src/host/api.ts
2774
2786
  init_smtp();
@@ -2872,11 +2884,19 @@ function buildRouter(runtime) {
2872
2884
  return { ...items, offset, limit };
2873
2885
  }
2874
2886
  const unreadOnly = url.searchParams.get("unread") === "1";
2887
+ const from = url.searchParams.get("from") ?? "";
2888
+ const since = url.searchParams.get("since") ?? "";
2889
+ const before = url.searchParams.get("before") ?? "";
2890
+ const attachmentsOnly = url.searchParams.get("attachment") === "1";
2875
2891
  const page = runtime.database(account).list({
2876
2892
  mailbox: mailbox === "" ? "all" : mailbox,
2877
2893
  query,
2878
2894
  offset,
2879
2895
  limit,
2896
+ ...from.trim() === "" ? {} : { from },
2897
+ ...since === "" ? {} : { since },
2898
+ ...before === "" ? {} : { before },
2899
+ ...attachmentsOnly ? { attachmentsOnly: true } : {},
2880
2900
  ...unreadOnly ? { unread: unreadKeys(runtime, account) } : {}
2881
2901
  });
2882
2902
  return { ...page, items: page.items.map((item) => localSummary(runtime, account, item)) };
@@ -3107,14 +3127,26 @@ function buildRouter(runtime) {
3107
3127
  const part = Number(url.searchParams.get("part") ?? 0);
3108
3128
  const provider = runtime.provider(account);
3109
3129
  const file2 = await provider.attachment(mailbox, uid, part);
3110
- writeAttachment(res, file2.filename, file2.contentType, Buffer.from(file2.dataBase64, "base64"));
3130
+ writeAttachment(
3131
+ res,
3132
+ file2.filename,
3133
+ file2.contentType,
3134
+ Buffer.from(file2.dataBase64, "base64"),
3135
+ canPreviewInline(file2.contentType) && url.searchParams.get("inline") === "1"
3136
+ );
3111
3137
  return void 0;
3112
3138
  }
3113
3139
  const emailId = Number(url.searchParams.get("emailId") ?? 0);
3114
3140
  const attachmentId = Number(url.searchParams.get("attachmentId") ?? 0);
3115
3141
  const file = runtime.database(account).attachment(emailId, attachmentId);
3116
3142
  if (file === void 0) throw new HttpError(404, "\u9644\u4EF6\u4E0D\u5B58\u5728");
3117
- writeAttachment(res, file.filename, file.contentType, Buffer.from(file.data));
3143
+ writeAttachment(
3144
+ res,
3145
+ file.filename,
3146
+ file.contentType,
3147
+ Buffer.from(file.data),
3148
+ canPreviewInline(file.contentType) && url.searchParams.get("inline") === "1"
3149
+ );
3118
3150
  return void 0;
3119
3151
  });
3120
3152
  router.get("/drafts", ({ url }) => {
@@ -3998,13 +4030,24 @@ async function listServer(runtime, account, mailbox, query, limit, offset = 0) {
3998
4030
  );
3999
4031
  return { items, total: result.total };
4000
4032
  }
4001
- function writeAttachment(res, filename, contentType, data) {
4033
+ function canPreviewInline(contentType) {
4034
+ const type = contentType.toLowerCase();
4035
+ return type.startsWith("image/") && type !== "image/svg+xml" || type === "application/pdf" || type === "text/plain" || type === "text/csv" || type === "text/markdown" || type === "application/json";
4036
+ }
4037
+ function writeAttachment(res, filename, contentType, data, inline = false) {
4002
4038
  res.statusCode = 200;
4003
4039
  res.setHeader("content-type", contentType);
4004
4040
  res.setHeader("content-length", String(data.length));
4005
- res.setHeader("content-disposition", `attachment; filename*=UTF-8''${encodeURIComponent(filename)}`);
4041
+ res.setHeader(
4042
+ "content-disposition",
4043
+ `${inline ? "inline" : "attachment"}; filename*=UTF-8''${encodeURIComponent(filename)}`
4044
+ );
4006
4045
  res.setHeader("cache-control", "no-store");
4007
4046
  res.setHeader("x-content-type-options", "nosniff");
4047
+ res.setHeader(
4048
+ "content-security-policy",
4049
+ "sandbox; default-src 'none'; img-src 'self' data:; style-src 'unsafe-inline'"
4050
+ );
4008
4051
  res.end(data);
4009
4052
  }
4010
4053
  function asObject(value) {