@blamejs/core 0.9.19 → 0.9.21

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/mail-store.js CHANGED
@@ -169,6 +169,12 @@ function create(opts) {
169
169
  var stmtSetFlag = db.prepare("INSERT OR IGNORE INTO " + qFlags + " (objectid, flag, set_at) VALUES (?, ?, ?)");
170
170
  var stmtUnsetFlag = db.prepare("DELETE FROM " + qFlags + " WHERE objectid = ? AND flag = ?");
171
171
  var stmtLegalHold = db.prepare("UPDATE " + qMsgs + " SET legal_hold = ? WHERE objectid = ?");
172
+ var stmtMoveByObjectId = db.prepare(
173
+ "UPDATE " + qMsgs + " SET folder_id = ?, modseq = ? WHERE objectid = ? AND folder_id = ?");
174
+ var stmtSizeByObjectId = db.prepare(
175
+ "SELECT size_bytes FROM " + qMsgs + " WHERE objectid = ? AND folder_id = ?");
176
+ var stmtDecrementQuota = db.prepare(
177
+ "UPDATE " + qQuota + " SET used_bytes = used_bytes - ?, used_count = used_count - ? WHERE folder_id = ?");
172
178
  var stmtThreadFor = db.prepare("SELECT objectid FROM " + qMsgs + " WHERE thread_root_id = ? ORDER BY received_at ASC");
173
179
  var stmtFindThreadByMsgId = db.prepare(
174
180
  "SELECT objectid, thread_root_id FROM " + qMsgs + " WHERE message_id_hash = ? LIMIT 1");
@@ -262,6 +268,18 @@ function create(opts) {
262
268
  if (!q) return { usedBytes: 0, usedCount: 0, capBytes: null, capCount: null };
263
269
  return { usedBytes: q.used_bytes, usedCount: q.used_count, capBytes: q.cap_bytes, capCount: q.cap_count };
264
270
  },
271
+ moveMessages: function (fromFolderName, toFolderName, objectids) {
272
+ return _moveMessages({
273
+ stmtGetFolderByName: stmtGetFolderByName,
274
+ stmtBumpFolderModseq: stmtBumpFolderModseq,
275
+ stmtMoveByObjectId: stmtMoveByObjectId,
276
+ stmtSizeByObjectId: stmtSizeByObjectId,
277
+ stmtDecrementQuota: stmtDecrementQuota,
278
+ stmtBumpQuota: stmtBumpQuota,
279
+ fromFolderName: fromFolderName, toFolderName: toFolderName,
280
+ objectids: objectids,
281
+ });
282
+ },
265
283
  setLegalHold: function (objectids, holdOpts) {
266
284
  var hold = (holdOpts && holdOpts.hold) ? 1 : 0; // allow:raw-byte-literal — boolean cast for sqlite INTEGER column
267
285
  objectids.forEach(function (oid) { stmtLegalHold.run(hold, oid); });
@@ -405,6 +423,55 @@ function _fetchByObjectId(args) {
405
423
  };
406
424
  }
407
425
 
426
+ // ---- Move -----------------------------------------------------------------
427
+
428
+ function _moveMessages(args) {
429
+ var fromFolder = args.stmtGetFolderByName.get(args.fromFolderName);
430
+ if (!fromFolder) {
431
+ throw new MailStoreError("mail-store/no-folder",
432
+ "moveMessages: from-folder '" + args.fromFolderName + "' not found");
433
+ }
434
+ var toFolder = args.stmtGetFolderByName.get(args.toFolderName);
435
+ if (!toFolder) {
436
+ throw new MailStoreError("mail-store/no-folder",
437
+ "moveMessages: to-folder '" + args.toFolderName + "' not found");
438
+ }
439
+ if (!Array.isArray(args.objectids)) {
440
+ throw new MailStoreError("mail-store/bad-input",
441
+ "moveMessages: objectids must be an array");
442
+ }
443
+ // Per RFC 7162 each folder owns its own modseq counter. The moved
444
+ // row joins the destination's sequence — it gets `dstModseq` (the
445
+ // destination folder's new max). Source still bumps its `modseq_max`
446
+ // to track the removal even though the row is gone; CONDSTORE
447
+ // clients polling the source for `since-modseq` see the change.
448
+ var srcModseq = (fromFolder.modseq_max || 0) + 1;
449
+ var dstModseq = (toFolder.modseq_max || 0) + 1;
450
+ var changed = 0;
451
+ var movedBytes = 0;
452
+ for (var i = 0; i < args.objectids.length; i += 1) {
453
+ // Capture size before the row's folder_id moves — the destination
454
+ // quota gets the delta and the source quota decrements by the same.
455
+ var size = args.stmtSizeByObjectId.get(args.objectids[i], fromFolder.id);
456
+ var bytes = size ? size.size_bytes : 0;
457
+ var r = args.stmtMoveByObjectId.run(toFolder.id, dstModseq, args.objectids[i], fromFolder.id);
458
+ if (r && r.changes) {
459
+ changed += r.changes;
460
+ movedBytes += bytes;
461
+ }
462
+ }
463
+ // Quota maintenance: decrement source by sum-of-sizes, increment
464
+ // destination. v0.9.19 substrate already maintains per-folder quota
465
+ // on append; move must keep both sides accurate.
466
+ if (changed > 0) {
467
+ args.stmtDecrementQuota.run(movedBytes, changed, fromFolder.id);
468
+ args.stmtBumpQuota.run(toFolder.id, movedBytes, changed);
469
+ }
470
+ args.stmtBumpFolderModseq.run(srcModseq, args.fromFolderName);
471
+ args.stmtBumpFolderModseq.run(dstModseq, args.toFolderName);
472
+ return { changed: changed, fromModseq: srcModseq, toModseq: dstModseq };
473
+ }
474
+
408
475
  // ---- Flags ----------------------------------------------------------------
409
476
 
410
477
  function _setFlags(args) {
package/lib/mail.js CHANGED
@@ -68,6 +68,7 @@ var dkim = require("./mail-dkim");
68
68
  var mailAuth = require("./mail-auth");
69
69
  var mailBimi = require("./mail-bimi");
70
70
  var mailUnsubscribe = require("./mail-unsubscribe");
71
+ var mailAgent = require("./mail-agent");
71
72
  var net = lazyRequire(function () { return require("node:net"); });
72
73
  var networkDns = lazyRequire(function () { return require("./network-dns"); });
73
74
  var nodeUrl = require("node:url");
@@ -1862,4 +1863,9 @@ module.exports = {
1862
1863
  http: httpTransport,
1863
1864
  resend: resendTransport,
1864
1865
  },
1866
+ // The mail-stack standardization contract (v0.9.20). JMAP / IMAP /
1867
+ // POP3 / ManageSieve / MX / submission all translate into
1868
+ // `agent.X(args)`; RBAC + posture + audit + dispatch owned here.
1869
+ // See lib/mail-agent.js for the full surface.
1870
+ agent: mailAgent,
1865
1871
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.9.19",
3
+ "version": "0.9.21",
4
4
  "description": "The Node framework that owns its stack.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "blamejs contributors",
package/sbom.cdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.6",
5
- "serialNumber": "urn:uuid:ed73363f-9191-4704-85db-94a6cd3c93e5",
5
+ "serialNumber": "urn:uuid:f8b30ec2-7478-4a7b-852d-09721ba89ab2",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-14T17:13:12.089Z",
8
+ "timestamp": "2026-05-14T20:33:49.367Z",
9
9
  "lifecycles": [
10
10
  {
11
11
  "phase": "build"
@@ -19,14 +19,14 @@
19
19
  }
20
20
  ],
21
21
  "component": {
22
- "bom-ref": "@blamejs/core@0.9.19",
22
+ "bom-ref": "@blamejs/core@0.9.21",
23
23
  "type": "library",
24
24
  "name": "blamejs",
25
- "version": "0.9.19",
25
+ "version": "0.9.21",
26
26
  "scope": "required",
27
27
  "author": "blamejs contributors",
28
28
  "description": "The Node framework that owns its stack.",
29
- "purl": "pkg:npm/%40blamejs/core@0.9.19",
29
+ "purl": "pkg:npm/%40blamejs/core@0.9.21",
30
30
  "properties": [],
31
31
  "externalReferences": [
32
32
  {
@@ -54,7 +54,7 @@
54
54
  "components": [],
55
55
  "dependencies": [
56
56
  {
57
- "ref": "@blamejs/core@0.9.19",
57
+ "ref": "@blamejs/core@0.9.21",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]