pixivflow 2.12.3 → 2.14.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.
Files changed (151) hide show
  1. package/README.md +30 -4
  2. package/README_EN.md +11 -3
  3. package/config/fly-two-bots.example.json +3 -1
  4. package/dist/commands/DoctorCommand.d.ts +20 -0
  5. package/dist/commands/DoctorCommand.d.ts.map +1 -0
  6. package/dist/commands/DoctorCommand.js +107 -0
  7. package/dist/commands/DoctorCommand.js.map +1 -0
  8. package/dist/commands/OutboxCommand.d.ts +17 -0
  9. package/dist/commands/OutboxCommand.d.ts.map +1 -0
  10. package/dist/commands/OutboxCommand.js +102 -0
  11. package/dist/commands/OutboxCommand.js.map +1 -0
  12. package/dist/commands/ReconcileCommand.d.ts +24 -0
  13. package/dist/commands/ReconcileCommand.d.ts.map +1 -0
  14. package/dist/commands/ReconcileCommand.js +70 -0
  15. package/dist/commands/ReconcileCommand.js.map +1 -0
  16. package/dist/commands/SchedulerCommand.d.ts.map +1 -1
  17. package/dist/commands/SchedulerCommand.js +5 -0
  18. package/dist/commands/SchedulerCommand.js.map +1 -1
  19. package/dist/commands/SchedulerRunOnceCommand.d.ts.map +1 -1
  20. package/dist/commands/SchedulerRunOnceCommand.js +6 -0
  21. package/dist/commands/SchedulerRunOnceCommand.js.map +1 -1
  22. package/dist/commands/index.d.ts +4 -1
  23. package/dist/commands/index.d.ts.map +1 -1
  24. package/dist/commands/index.js +10 -1
  25. package/dist/commands/index.js.map +1 -1
  26. package/dist/commands/scheduler-runtime.d.ts +10 -1
  27. package/dist/commands/scheduler-runtime.d.ts.map +1 -1
  28. package/dist/commands/scheduler-runtime.js +157 -47
  29. package/dist/commands/scheduler-runtime.js.map +1 -1
  30. package/dist/config/types.d.ts +14 -1
  31. package/dist/config/types.d.ts.map +1 -1
  32. package/dist/config/validation.d.ts.map +1 -1
  33. package/dist/config/validation.js +10 -0
  34. package/dist/config/validation.js.map +1 -1
  35. package/dist/delivery/DeliveryAck.d.ts +70 -0
  36. package/dist/delivery/DeliveryAck.d.ts.map +1 -0
  37. package/dist/delivery/DeliveryAck.js +72 -0
  38. package/dist/delivery/DeliveryAck.js.map +1 -0
  39. package/dist/delivery/DeliveryDispatcher.d.ts +1 -0
  40. package/dist/delivery/DeliveryDispatcher.d.ts.map +1 -1
  41. package/dist/delivery/DeliveryDispatcher.js +9 -1
  42. package/dist/delivery/DeliveryDispatcher.js.map +1 -1
  43. package/dist/delivery/DeliveryService.d.ts +74 -0
  44. package/dist/delivery/DeliveryService.d.ts.map +1 -0
  45. package/dist/delivery/DeliveryService.js +209 -0
  46. package/dist/delivery/DeliveryService.js.map +1 -0
  47. package/dist/delivery/HttpMultipartDelivery.d.ts +11 -1
  48. package/dist/delivery/HttpMultipartDelivery.d.ts.map +1 -1
  49. package/dist/delivery/HttpMultipartDelivery.js +70 -67
  50. package/dist/delivery/HttpMultipartDelivery.js.map +1 -1
  51. package/dist/delivery/LegacyOutboxMigration.d.ts +21 -0
  52. package/dist/delivery/LegacyOutboxMigration.d.ts.map +1 -0
  53. package/dist/delivery/LegacyOutboxMigration.js +125 -0
  54. package/dist/delivery/LegacyOutboxMigration.js.map +1 -0
  55. package/dist/delivery/OutboxWorker.d.ts +70 -0
  56. package/dist/delivery/OutboxWorker.d.ts.map +1 -0
  57. package/dist/delivery/OutboxWorker.js +211 -0
  58. package/dist/delivery/OutboxWorker.js.map +1 -0
  59. package/dist/delivery/types.d.ts +15 -0
  60. package/dist/delivery/types.d.ts.map +1 -1
  61. package/dist/download/DownloadManager.d.ts +17 -12
  62. package/dist/download/DownloadManager.d.ts.map +1 -1
  63. package/dist/download/DownloadManager.js +31 -53
  64. package/dist/download/DownloadManager.js.map +1 -1
  65. package/dist/download/IllustrationDownloader.d.ts +1 -0
  66. package/dist/download/IllustrationDownloader.d.ts.map +1 -1
  67. package/dist/download/IllustrationDownloader.js +19 -1
  68. package/dist/download/IllustrationDownloader.js.map +1 -1
  69. package/dist/download/NovelDownloader.d.ts +3 -1
  70. package/dist/download/NovelDownloader.d.ts.map +1 -1
  71. package/dist/download/NovelDownloader.js +30 -2
  72. package/dist/download/NovelDownloader.js.map +1 -1
  73. package/dist/download/handlers/IllustrationTargetHandler.d.ts +18 -8
  74. package/dist/download/handlers/IllustrationTargetHandler.d.ts.map +1 -1
  75. package/dist/download/handlers/IllustrationTargetHandler.js +101 -74
  76. package/dist/download/handlers/IllustrationTargetHandler.js.map +1 -1
  77. package/dist/download/handlers/NovelTargetHandler.d.ts +8 -8
  78. package/dist/download/handlers/NovelTargetHandler.d.ts.map +1 -1
  79. package/dist/download/handlers/NovelTargetHandler.js +64 -83
  80. package/dist/download/handlers/NovelTargetHandler.js.map +1 -1
  81. package/dist/download/plan/DownloadPlanner.d.ts +6 -1
  82. package/dist/download/plan/DownloadPlanner.d.ts.map +1 -1
  83. package/dist/download/plan/DownloadPlanner.js +28 -5
  84. package/dist/download/plan/DownloadPlanner.js.map +1 -1
  85. package/dist/index.js +1 -1
  86. package/dist/index.js.map +1 -1
  87. package/dist/notification/NotificationPolicy.d.ts +38 -0
  88. package/dist/notification/NotificationPolicy.d.ts.map +1 -0
  89. package/dist/notification/NotificationPolicy.js +89 -0
  90. package/dist/notification/NotificationPolicy.js.map +1 -0
  91. package/dist/package.json +1 -1
  92. package/dist/pixiv/PixivClient.d.ts +4 -0
  93. package/dist/pixiv/PixivClient.d.ts.map +1 -1
  94. package/dist/pixiv/PixivClient.js +15 -2
  95. package/dist/pixiv/PixivClient.js.map +1 -1
  96. package/dist/pixiv/RateLimitCoordinator.d.ts +30 -0
  97. package/dist/pixiv/RateLimitCoordinator.d.ts.map +1 -0
  98. package/dist/pixiv/RateLimitCoordinator.js +66 -0
  99. package/dist/pixiv/RateLimitCoordinator.js.map +1 -0
  100. package/dist/pixiv/client/PixivApiCore.d.ts +5 -0
  101. package/dist/pixiv/client/PixivApiCore.d.ts.map +1 -1
  102. package/dist/pixiv/client/PixivApiCore.js +31 -9
  103. package/dist/pixiv/client/PixivApiCore.js.map +1 -1
  104. package/dist/scheduler/ScheduleTriggerServer.d.ts +7 -0
  105. package/dist/scheduler/ScheduleTriggerServer.d.ts.map +1 -1
  106. package/dist/scheduler/ScheduleTriggerServer.js +17 -0
  107. package/dist/scheduler/ScheduleTriggerServer.js.map +1 -1
  108. package/dist/scheduler/SlotCoordinator.d.ts +15 -0
  109. package/dist/scheduler/SlotCoordinator.d.ts.map +1 -1
  110. package/dist/scheduler/SlotCoordinator.js +74 -0
  111. package/dist/scheduler/SlotCoordinator.js.map +1 -1
  112. package/dist/scheduler/SlotStateMachine.d.ts +32 -0
  113. package/dist/scheduler/SlotStateMachine.d.ts.map +1 -0
  114. package/dist/scheduler/SlotStateMachine.js +65 -0
  115. package/dist/scheduler/SlotStateMachine.js.map +1 -0
  116. package/dist/scheduler/TargetOutcome.d.ts +63 -0
  117. package/dist/scheduler/TargetOutcome.d.ts.map +1 -0
  118. package/dist/scheduler/TargetOutcome.js +28 -0
  119. package/dist/scheduler/TargetOutcome.js.map +1 -0
  120. package/dist/storage/Database.d.ts +16 -0
  121. package/dist/storage/Database.d.ts.map +1 -1
  122. package/dist/storage/Database.js +29 -0
  123. package/dist/storage/Database.js.map +1 -1
  124. package/dist/storage/DatabaseMigration.d.ts.map +1 -1
  125. package/dist/storage/DatabaseMigration.js +66 -0
  126. package/dist/storage/DatabaseMigration.js.map +1 -1
  127. package/dist/storage/repositories/DeliveryRepository.d.ts +73 -0
  128. package/dist/storage/repositories/DeliveryRepository.d.ts.map +1 -0
  129. package/dist/storage/repositories/DeliveryRepository.js +148 -0
  130. package/dist/storage/repositories/DeliveryRepository.js.map +1 -0
  131. package/dist/storage/repositories/MetadataRepository.d.ts +27 -0
  132. package/dist/storage/repositories/MetadataRepository.d.ts.map +1 -0
  133. package/dist/storage/repositories/MetadataRepository.js +58 -0
  134. package/dist/storage/repositories/MetadataRepository.js.map +1 -0
  135. package/dist/storage/repositories/OutboxRepository.d.ts +72 -0
  136. package/dist/storage/repositories/OutboxRepository.d.ts.map +1 -0
  137. package/dist/storage/repositories/OutboxRepository.js +200 -0
  138. package/dist/storage/repositories/OutboxRepository.js.map +1 -0
  139. package/dist/storage/repositories/SlotRepository.d.ts +26 -1
  140. package/dist/storage/repositories/SlotRepository.d.ts.map +1 -1
  141. package/dist/storage/repositories/SlotRepository.js +76 -2
  142. package/dist/storage/repositories/SlotRepository.js.map +1 -1
  143. package/dist/utils/config-validator-unified.d.ts.map +1 -1
  144. package/dist/utils/config-validator-unified.js +14 -0
  145. package/dist/utils/config-validator-unified.js.map +1 -1
  146. package/dist/webui/package.json +1 -1
  147. package/package.json +1 -1
  148. package/dist/delivery/DeliveryOutbox.d.ts +0 -43
  149. package/dist/delivery/DeliveryOutbox.d.ts.map +0 -1
  150. package/dist/delivery/DeliveryOutbox.js +0 -293
  151. package/dist/delivery/DeliveryOutbox.js.map +0 -1
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DeliveryRepository = void 0;
4
+ const BaseRepository_1 = require("./BaseRepository");
5
+ /**
6
+ * The delivery ledger. Answers "has this work actually been CONFIRMED delivered
7
+ * to this target?" — distinct from the downloads table ("was the file cached
8
+ * locally?"). downloaded != delivered.
9
+ *
10
+ * Dedup scope is (delivery_target, work_type, pixiv_id): bot1 having posted a
11
+ * work does not forbid bot2 posting it.
12
+ */
13
+ class DeliveryRepository extends BaseRepository_1.BaseRepository {
14
+ /** Insert a pending intent. No-op if the idempotency key already exists. */
15
+ insertIntent(input) {
16
+ const info = this.db
17
+ .prepare(`INSERT INTO deliveries
18
+ (id, delivery_target, work_type, pixiv_id, slot_id, target_id, idempotency_key, status)
19
+ VALUES
20
+ (@id, @deliveryTarget, @workType, @pixivId, @slotId, @targetId, @idempotencyKey, 'pending')
21
+ ON CONFLICT(idempotency_key) DO NOTHING`)
22
+ .run({
23
+ id: input.id,
24
+ deliveryTarget: input.deliveryTarget,
25
+ workType: input.workType,
26
+ pixivId: input.pixivId,
27
+ slotId: input.slotId ?? null,
28
+ targetId: input.targetId ?? null,
29
+ idempotencyKey: input.idempotencyKey,
30
+ });
31
+ const created = info.changes > 0;
32
+ return { row: created ? this.getById(input.id) : this.getByIdempotencyKey(input.idempotencyKey), created };
33
+ }
34
+ getById(id) {
35
+ const row = this.db.prepare(`SELECT * FROM deliveries WHERE id = ?`).get(id);
36
+ return row ? this.toRow(row) : null;
37
+ }
38
+ getByIdempotencyKey(key) {
39
+ const row = this.db.prepare(`SELECT * FROM deliveries WHERE idempotency_key = ?`).get(key);
40
+ return row ? this.toRow(row) : null;
41
+ }
42
+ /**
43
+ * True when this exact work is already CONFIRMED (delivered, or an attested
44
+ * historical duplicate) for this target. Pending/failed intents do not block
45
+ * selection — they are retried, not treated as a delivered fact.
46
+ */
47
+ isDelivered(deliveryTarget, workType, pixivId) {
48
+ const row = this.db
49
+ .prepare(`SELECT 1 FROM deliveries
50
+ WHERE delivery_target = ? AND work_type = ? AND pixiv_id = ?
51
+ AND status IN ('delivered','duplicate')
52
+ LIMIT 1`)
53
+ .get(deliveryTarget, workType, String(pixivId));
54
+ return Boolean(row);
55
+ }
56
+ /** Batch form for candidate-pipeline pre-lock dedupe. */
57
+ deliveredIds(deliveryTarget, workType, pixivIds) {
58
+ const out = new Set();
59
+ if (pixivIds.length === 0)
60
+ return out;
61
+ const CHUNK = 400;
62
+ for (let i = 0; i < pixivIds.length; i += CHUNK) {
63
+ const slice = pixivIds.slice(i, i + CHUNK);
64
+ const placeholders = slice.map(() => '?').join(',');
65
+ const rows = this.db
66
+ .prepare(`SELECT DISTINCT pixiv_id FROM deliveries
67
+ WHERE delivery_target = ? AND work_type = ? AND status IN ('delivered','duplicate')
68
+ AND pixiv_id IN (${placeholders})`)
69
+ .all(deliveryTarget, workType, ...slice);
70
+ for (const r of rows)
71
+ out.add(r.pixiv_id);
72
+ }
73
+ return out;
74
+ }
75
+ recordAck(id, ack) {
76
+ const terminal = ack.status === 'delivered' || ack.status === 'duplicate' || ack.status === 'failed';
77
+ const sets = [
78
+ 'status = @status',
79
+ 'remote_id = COALESCE(@remoteId, remote_id)',
80
+ 'remote_status = @remoteStatus',
81
+ 'reuse_reason = @reuseReason',
82
+ 'last_error = @error',
83
+ 'attempts = attempts + 1',
84
+ 'updated_at = CURRENT_TIMESTAMP',
85
+ ];
86
+ if (terminal)
87
+ sets.push(`delivered_at = COALESCE(delivered_at, CASE WHEN @status IN ('delivered','duplicate') THEN CURRENT_TIMESTAMP ELSE NULL END)`);
88
+ this.db
89
+ .prepare(`UPDATE deliveries SET ${sets.join(', ')} WHERE id = @id`)
90
+ .run({
91
+ id,
92
+ status: ack.status,
93
+ remoteId: ack.remoteId ?? null,
94
+ remoteStatus: ack.remoteStatus ?? null,
95
+ reuseReason: ack.reuseReason ?? null,
96
+ error: ack.error ?? null,
97
+ });
98
+ }
99
+ /** Backfill a delivery fact discovered during downstream reconciliation. */
100
+ backfill(input) {
101
+ const { row, created } = this.insertIntent(input);
102
+ if (created || row.status !== 'delivered') {
103
+ this.recordAck(input.id, {
104
+ status: 'delivered',
105
+ remoteId: input.remoteId,
106
+ remoteStatus: input.remoteStatus ?? 'reconciled',
107
+ });
108
+ }
109
+ return { row: this.getById(input.id), created };
110
+ }
111
+ pending(limit = 200) {
112
+ const rows = this.db
113
+ .prepare(`SELECT * FROM deliveries WHERE status = 'pending' ORDER BY created_at ASC LIMIT ?`)
114
+ .all(limit);
115
+ return rows.map((r) => this.toRow(r));
116
+ }
117
+ countByStatus() {
118
+ const rows = this.db
119
+ .prepare(`SELECT status, COUNT(*) AS n FROM deliveries GROUP BY status`)
120
+ .all();
121
+ const out = { pending: 0, delivered: 0, duplicate: 0, failed: 0 };
122
+ for (const r of rows)
123
+ out[r.status] = r.n;
124
+ return out;
125
+ }
126
+ toRow(row) {
127
+ return {
128
+ id: row.id,
129
+ deliveryTarget: row.delivery_target,
130
+ workType: row.work_type,
131
+ pixivId: row.pixiv_id,
132
+ slotId: row.slot_id,
133
+ targetId: row.target_id,
134
+ idempotencyKey: row.idempotency_key,
135
+ status: row.status,
136
+ remoteId: row.remote_id,
137
+ remoteStatus: row.remote_status,
138
+ reuseReason: row.reuse_reason,
139
+ attempts: row.attempts,
140
+ lastError: row.last_error,
141
+ createdAt: row.created_at,
142
+ updatedAt: row.updated_at,
143
+ deliveredAt: row.delivered_at,
144
+ };
145
+ }
146
+ }
147
+ exports.DeliveryRepository = DeliveryRepository;
148
+ //# sourceMappingURL=DeliveryRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeliveryRepository.js","sourceRoot":"","sources":["../../../src/storage/repositories/DeliveryRepository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { BaseRepository } from './BaseRepository';
2
+ export interface PixivMetadata {
3
+ pixivId: string;
4
+ workType: string;
5
+ language: string | null;
6
+ xRestrict: number | null;
7
+ publishedAt: string | null;
8
+ title: string | null;
9
+ checkedAt: number;
10
+ }
11
+ /**
12
+ * Lightweight SQLite metadata cache. Novel language filtering otherwise issues
13
+ * a full detail + full-text request for every candidate on every fallback run;
14
+ * caching the classified result bounds request volume and reduces 429 storms.
15
+ * Entries expire after a TTL so fresh classifications still happen eventually.
16
+ */
17
+ export declare class MetadataRepository extends BaseRepository {
18
+ get(pixivId: string, workType: string): PixivMetadata | null;
19
+ fresh(pixivId: string, workType: string, ttlMs: number, now?: number): PixivMetadata | null;
20
+ put(pixivId: string, workType: string, data: {
21
+ language?: string | null;
22
+ xRestrict?: number | null;
23
+ publishedAt?: string | null;
24
+ title?: string | null;
25
+ }, now?: number): void;
26
+ }
27
+ //# sourceMappingURL=MetadataRepository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetadataRepository.d.ts","sourceRoot":"","sources":["../../../src/storage/repositories/MetadataRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,cAAc;IACpD,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAgB5D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,aAAa,GAAG,IAAI;IAOvG,GAAG,CACD,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EACjH,GAAG,GAAE,MAAmB,GACvB,IAAI;CAsBR"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MetadataRepository = void 0;
4
+ const BaseRepository_1 = require("./BaseRepository");
5
+ /**
6
+ * Lightweight SQLite metadata cache. Novel language filtering otherwise issues
7
+ * a full detail + full-text request for every candidate on every fallback run;
8
+ * caching the classified result bounds request volume and reduces 429 storms.
9
+ * Entries expire after a TTL so fresh classifications still happen eventually.
10
+ */
11
+ class MetadataRepository extends BaseRepository_1.BaseRepository {
12
+ get(pixivId, workType) {
13
+ const row = this.db
14
+ .prepare(`SELECT * FROM pixiv_metadata WHERE pixiv_id = ? AND work_type = ?`)
15
+ .get(String(pixivId), workType);
16
+ if (!row)
17
+ return null;
18
+ return {
19
+ pixivId: row.pixiv_id,
20
+ workType: row.work_type,
21
+ language: row.language,
22
+ xRestrict: row.x_restrict,
23
+ publishedAt: row.published_at,
24
+ title: row.title,
25
+ checkedAt: row.checked_at,
26
+ };
27
+ }
28
+ fresh(pixivId, workType, ttlMs, now = Date.now()) {
29
+ const row = this.get(pixivId, workType);
30
+ if (!row)
31
+ return null;
32
+ if (now - row.checkedAt > ttlMs)
33
+ return null;
34
+ return row;
35
+ }
36
+ put(pixivId, workType, data, now = Date.now()) {
37
+ this.db
38
+ .prepare(`INSERT INTO pixiv_metadata (pixiv_id, work_type, language, x_restrict, published_at, title, checked_at)
39
+ VALUES (@pixivId, @workType, @language, @xRestrict, @publishedAt, @title, @now)
40
+ ON CONFLICT(pixiv_id, work_type) DO UPDATE SET
41
+ language=excluded.language,
42
+ x_restrict=excluded.x_restrict,
43
+ published_at=excluded.published_at,
44
+ title=excluded.title,
45
+ checked_at=excluded.checked_at`)
46
+ .run({
47
+ pixivId: String(pixivId),
48
+ workType,
49
+ language: data.language ?? null,
50
+ xRestrict: data.xRestrict ?? null,
51
+ publishedAt: data.publishedAt ?? null,
52
+ title: data.title ?? null,
53
+ now,
54
+ });
55
+ }
56
+ }
57
+ exports.MetadataRepository = MetadataRepository;
58
+ //# sourceMappingURL=MetadataRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetadataRepository.js","sourceRoot":"","sources":["../../../src/storage/repositories/MetadataRepository.ts"],"names":[],"mappings":";;;AAAA,qDAAkD;AAYlD;;;;;GAKG;AACH,MAAa,kBAAmB,SAAQ,+BAAc;IACpD,GAAG,CAAC,OAAe,EAAE,QAAgB;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;aAChB,OAAO,CAAC,mEAAmE,CAAC;aAC5E,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAQ,CAAC;QACzC,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,OAAO;YACL,OAAO,EAAE,GAAG,CAAC,QAAQ;YACrB,QAAQ,EAAE,GAAG,CAAC,SAAS;YACvB,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,SAAS,EAAE,GAAG,CAAC,UAAU;YACzB,WAAW,EAAE,GAAG,CAAC,YAAY;YAC7B,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,SAAS,EAAE,GAAG,CAAC,UAAU;SAC1B,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,QAAgB,EAAE,KAAa,EAAE,MAAc,IAAI,CAAC,GAAG,EAAE;QAC9E,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,IAAI,GAAG,GAAG,GAAG,CAAC,SAAS,GAAG,KAAK;YAAE,OAAO,IAAI,CAAC;QAC7C,OAAO,GAAG,CAAC;IACb,CAAC;IAED,GAAG,CACD,OAAe,EACf,QAAgB,EAChB,IAAiH,EACjH,MAAc,IAAI,CAAC,GAAG,EAAE;QAExB,IAAI,CAAC,EAAE;aACJ,OAAO,CACN;;;;;;;0CAOkC,CACnC;aACA,GAAG,CAAC;YACH,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC;YACxB,QAAQ;YACR,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI;YAC/B,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI;YACjC,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI;YACrC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI;YACzB,GAAG;SACJ,CAAC,CAAC;IACP,CAAC;CACF;AAnDD,gDAmDC"}
@@ -0,0 +1,72 @@
1
+ import { BaseRepository } from './BaseRepository';
2
+ export type OutboxKind = 'delivery' | 'notification';
3
+ export type OutboxStatus = 'pending' | 'processing' | 'retry_wait' | 'done' | 'dead' | 'cancelled';
4
+ export interface OutboxRow {
5
+ id: string;
6
+ kind: OutboxKind;
7
+ idempotencyKey: string | null;
8
+ deliveryId: string | null;
9
+ deliveryTarget: string;
10
+ payloadJson: string;
11
+ status: OutboxStatus;
12
+ attempts: number;
13
+ maxAttempts: number;
14
+ nextAttemptAt: number;
15
+ leaseOwner: string | null;
16
+ leaseUntil: number | null;
17
+ lastError: string | null;
18
+ createdAt: number;
19
+ updatedAt: number;
20
+ completedAt: number | null;
21
+ }
22
+ export interface NewOutboxItem {
23
+ kind: OutboxKind;
24
+ deliveryTarget: string;
25
+ idempotencyKey?: string | null;
26
+ deliveryId?: string | null;
27
+ payload: unknown;
28
+ /** Initial due time (epoch ms). Default now. */
29
+ dueAt?: number;
30
+ maxAttempts?: number;
31
+ }
32
+ /**
33
+ * SQLite transactional outbox. One durable row per intended external side
34
+ * effect (a content delivery or a notification). A single OutboxWorker claims
35
+ * due rows with a short lease, performs the effect, and marks them done. Rows
36
+ * survive process kill / machine stop; a restart simply resumes due rows.
37
+ */
38
+ export declare class OutboxRepository extends BaseRepository {
39
+ static owner(): string;
40
+ /** Insert an intent. Returns the row. Idempotent on (kind, idempotency_key). */
41
+ enqueue(input: NewOutboxItem, now?: number): OutboxRow;
42
+ get(id: string): OutboxRow | null;
43
+ getByKey(kind: OutboxKind, key: string): OutboxRow | null;
44
+ list(status?: OutboxStatus, limit?: number): OutboxRow[];
45
+ /**
46
+ * Claim up to `limit` due rows for `owner`. Due = pending/retry_wait whose
47
+ * next_attempt_at has passed, OR processing rows whose lease expired (a
48
+ * crashed prior worker). The claim is a compare-and-set inside one
49
+ * statement, so two workers/processes never grab the same row.
50
+ */
51
+ claimDue(owner: string, leaseMs: number, limit: number, now?: number): OutboxRow[];
52
+ markDone(id: string, now?: number): void;
53
+ /** Schedule a later retry, or flip to dead once attempts are exhausted. */
54
+ markRetry(id: string, nextAt: number, error: string, now?: number): OutboxStatus;
55
+ /** Release a processing row back to pending without counting a retry. */
56
+ release(id: string, now?: number): void;
57
+ /** Reopen a dead row for one more attempt (operator / reconcile action). */
58
+ requeue(id: string, dueAt?: number): void;
59
+ cancel(id: string, now?: number): boolean;
60
+ counts(now?: number): {
61
+ pending: number;
62
+ retryWait: number;
63
+ processing: number;
64
+ dead: number;
65
+ done24h: number;
66
+ oldestPendingMs: number | null;
67
+ };
68
+ /** Rows still non-terminal (used by reconcile/doctor). */
69
+ staleProcessing(now?: number): OutboxRow[];
70
+ private toRow;
71
+ }
72
+ //# sourceMappingURL=OutboxRepository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OutboxRepository.d.ts","sourceRoot":"","sources":["../../../src/storage/repositories/OutboxRepository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OutboxRepository = void 0;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const BaseRepository_1 = require("./BaseRepository");
6
+ /**
7
+ * SQLite transactional outbox. One durable row per intended external side
8
+ * effect (a content delivery or a notification). A single OutboxWorker claims
9
+ * due rows with a short lease, performs the effect, and marks them done. Rows
10
+ * survive process kill / machine stop; a restart simply resumes due rows.
11
+ */
12
+ class OutboxRepository extends BaseRepository_1.BaseRepository {
13
+ static owner() {
14
+ return `${process.pid}-${(0, node_crypto_1.randomUUID)().slice(0, 8)}`;
15
+ }
16
+ /** Insert an intent. Returns the row. Idempotent on (kind, idempotency_key). */
17
+ enqueue(input, now = Date.now()) {
18
+ const id = (0, node_crypto_1.randomUUID)();
19
+ const payloadJson = JSON.stringify(input.payload ?? {});
20
+ this.db
21
+ .prepare(`INSERT INTO outbox
22
+ (id, kind, idempotency_key, delivery_id, delivery_target, payload_json,
23
+ status, attempts, max_attempts, next_attempt_at, created_at, updated_at)
24
+ VALUES
25
+ (@id, @kind, @idempotencyKey, @deliveryId, @deliveryTarget, @payloadJson,
26
+ 'pending', 0, @maxAttempts, @dueAt, @now, @now)
27
+ ON CONFLICT(kind, idempotency_key) WHERE idempotency_key IS NOT NULL
28
+ DO UPDATE SET updated_at = @now`)
29
+ .run({
30
+ id,
31
+ kind: input.kind,
32
+ idempotencyKey: input.idempotencyKey ?? null,
33
+ deliveryId: input.deliveryId ?? null,
34
+ deliveryTarget: input.deliveryTarget,
35
+ payloadJson,
36
+ maxAttempts: input.maxAttempts ?? 12,
37
+ dueAt: input.dueAt ?? now,
38
+ now,
39
+ });
40
+ // On conflict the existing row is authoritative; fetch by the natural key.
41
+ if (input.idempotencyKey) {
42
+ return this.getByKey(input.kind, input.idempotencyKey);
43
+ }
44
+ return this.get(id);
45
+ }
46
+ get(id) {
47
+ const row = this.db.prepare(`SELECT * FROM outbox WHERE id = ?`).get(id);
48
+ return row ? this.toRow(row) : null;
49
+ }
50
+ getByKey(kind, key) {
51
+ const row = this.db
52
+ .prepare(`SELECT * FROM outbox WHERE kind = ? AND idempotency_key = ?`)
53
+ .get(kind, key);
54
+ return row ? this.toRow(row) : null;
55
+ }
56
+ list(status, limit = 100) {
57
+ const bounded = Math.max(1, Math.min(Math.trunc(limit), 500));
58
+ const rows = status
59
+ ? this.db.prepare(`SELECT * FROM outbox WHERE status=? ORDER BY created_at DESC LIMIT ?`).all(status, bounded)
60
+ : this.db.prepare(`SELECT * FROM outbox ORDER BY created_at DESC LIMIT ?`).all(bounded);
61
+ return rows.map((row) => this.toRow(row));
62
+ }
63
+ /**
64
+ * Claim up to `limit` due rows for `owner`. Due = pending/retry_wait whose
65
+ * next_attempt_at has passed, OR processing rows whose lease expired (a
66
+ * crashed prior worker). The claim is a compare-and-set inside one
67
+ * statement, so two workers/processes never grab the same row.
68
+ */
69
+ claimDue(owner, leaseMs, limit, now = Date.now()) {
70
+ const ids = this.db
71
+ .prepare(`SELECT id FROM outbox
72
+ WHERE status IN ('pending','retry_wait') AND next_attempt_at <= @now
73
+ OR (status = 'processing' AND lease_until IS NOT NULL AND lease_until <= @now)
74
+ ORDER BY next_attempt_at ASC
75
+ LIMIT @limit`)
76
+ .all({ now, limit }).map((r) => r.id);
77
+ if (ids.length === 0)
78
+ return [];
79
+ const claim = this.db.prepare(`UPDATE outbox
80
+ SET status = 'processing', lease_owner = @owner, lease_until = @until, updated_at = @now
81
+ WHERE id = @id
82
+ AND (status IN ('pending','retry_wait') AND next_attempt_at <= @now
83
+ OR (status = 'processing' AND lease_until IS NOT NULL AND lease_until <= @now))`);
84
+ const out = [];
85
+ const tx = this.db.transaction((rows) => {
86
+ for (const id of rows) {
87
+ const info = claim.run({ id, owner, until: now + leaseMs, now });
88
+ if (info.changes > 0) {
89
+ const row = this.get(id);
90
+ if (row)
91
+ out.push(row);
92
+ }
93
+ }
94
+ });
95
+ tx(ids);
96
+ return out;
97
+ }
98
+ markDone(id, now = Date.now()) {
99
+ this.db
100
+ .prepare(`UPDATE outbox
101
+ SET status='done', lease_owner=NULL, lease_until=NULL, last_error=NULL,
102
+ completed_at=@now, updated_at=@now
103
+ WHERE id=@id`)
104
+ .run({ id, now });
105
+ }
106
+ /** Schedule a later retry, or flip to dead once attempts are exhausted. */
107
+ markRetry(id, nextAt, error, now = Date.now()) {
108
+ const row = this.get(id);
109
+ if (!row)
110
+ return 'dead';
111
+ const attempts = row.attempts + 1;
112
+ const dead = attempts >= row.maxAttempts;
113
+ this.db
114
+ .prepare(`UPDATE outbox
115
+ SET attempts=@attempts,
116
+ status=@status,
117
+ next_attempt_at=@nextAt,
118
+ lease_owner=NULL, lease_until=NULL,
119
+ last_error=@error, updated_at=@now
120
+ WHERE id=@id`)
121
+ .run({
122
+ id,
123
+ attempts,
124
+ status: dead ? 'dead' : 'retry_wait',
125
+ nextAt: dead ? row.nextAttemptAt : nextAt,
126
+ error: error.slice(0, 1000),
127
+ now,
128
+ });
129
+ return dead ? 'dead' : 'retry_wait';
130
+ }
131
+ /** Release a processing row back to pending without counting a retry. */
132
+ release(id, now = Date.now()) {
133
+ this.db
134
+ .prepare(`UPDATE outbox SET status='pending', lease_owner=NULL, lease_until=NULL,
135
+ next_attempt_at=@now, updated_at=@now WHERE id=@id AND status='processing'`)
136
+ .run({ id, now });
137
+ }
138
+ /** Reopen a dead row for one more attempt (operator / reconcile action). */
139
+ requeue(id, dueAt = Date.now()) {
140
+ this.db
141
+ .prepare(`UPDATE outbox SET status='retry_wait', next_attempt_at=@dueAt, attempts=0,
142
+ last_error=NULL, lease_owner=NULL, lease_until=NULL,
143
+ completed_at=NULL, updated_at=@dueAt WHERE id=@id`)
144
+ .run({ id, dueAt });
145
+ }
146
+ cancel(id, now = Date.now()) {
147
+ const result = this.db.prepare(`UPDATE outbox SET status='cancelled', lease_owner=NULL, lease_until=NULL,
148
+ last_error='cancelled by operator', completed_at=@now, updated_at=@now
149
+ WHERE id=@id AND status IN ('pending','retry_wait','dead')`).run({ id, now });
150
+ return result.changes === 1;
151
+ }
152
+ counts(now = Date.now()) {
153
+ const one = (sql, ...params) => this.db.prepare(sql).get(...params).n;
154
+ const pending = one(`SELECT COUNT(*) n FROM outbox WHERE status IN ('pending','retry_wait')`);
155
+ const retryWait = one(`SELECT COUNT(*) n FROM outbox WHERE status='retry_wait'`);
156
+ const processing = one(`SELECT COUNT(*) n FROM outbox WHERE status='processing'`);
157
+ const dead = one(`SELECT COUNT(*) n FROM outbox WHERE status='dead'`);
158
+ const done24h = one(`SELECT COUNT(*) n FROM outbox WHERE status='done' AND completed_at >= ?`, now - 86_400_000);
159
+ const oldest = this.db
160
+ .prepare(`SELECT MIN(next_attempt_at) t FROM outbox WHERE status IN ('pending','retry_wait')`)
161
+ .get();
162
+ return {
163
+ pending,
164
+ retryWait,
165
+ processing,
166
+ dead,
167
+ done24h,
168
+ oldestPendingMs: oldest.t == null ? null : Math.max(0, now - oldest.t),
169
+ };
170
+ }
171
+ /** Rows still non-terminal (used by reconcile/doctor). */
172
+ staleProcessing(now = Date.now()) {
173
+ const rows = this.db
174
+ .prepare(`SELECT * FROM outbox WHERE status='processing' AND lease_until IS NOT NULL AND lease_until <= ?`)
175
+ .all(now);
176
+ return rows.map((r) => this.toRow(r));
177
+ }
178
+ toRow(row) {
179
+ return {
180
+ id: row.id,
181
+ kind: row.kind,
182
+ idempotencyKey: row.idempotency_key,
183
+ deliveryId: row.delivery_id,
184
+ deliveryTarget: row.delivery_target,
185
+ payloadJson: row.payload_json,
186
+ status: row.status,
187
+ attempts: row.attempts,
188
+ maxAttempts: row.max_attempts,
189
+ nextAttemptAt: row.next_attempt_at,
190
+ leaseOwner: row.lease_owner,
191
+ leaseUntil: row.lease_until,
192
+ lastError: row.last_error,
193
+ createdAt: row.created_at,
194
+ updatedAt: row.updated_at,
195
+ completedAt: row.completed_at,
196
+ };
197
+ }
198
+ }
199
+ exports.OutboxRepository = OutboxRepository;
200
+ //# sourceMappingURL=OutboxRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OutboxRepository.js","sourceRoot":"","sources":["../../../src/storage/repositories/OutboxRepository.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { BaseRepository } from './BaseRepository';
2
2
  export type SlotStatus = 'pending' | 'running' | 'success' | 'partial' | 'failed' | 'expired';
3
- export type CellStatus = 'pending' | 'selected' | 'submitted' | 'no_candidate' | 'failed';
3
+ export type CellStatus = 'pending' | 'selected' | 'artifact_ready' | 'delivery_pending' | 'submitted' | 'no_candidate' | 'duplicate' | 'failed';
4
4
  export interface SlotRecord {
5
5
  id: string;
6
6
  /** Schedule this occurrence belongs to (id is already schedule-scoped). */
@@ -22,6 +22,9 @@ export interface SlotRecord {
22
22
  startedAt: string | null;
23
23
  completedAt: string | null;
24
24
  lastError: string | null;
25
+ leaseOwner: string | null;
26
+ leaseUntil: number | null;
27
+ heartbeatAt: number | null;
25
28
  }
26
29
  export interface SlotItemRecord {
27
30
  id: number;
@@ -92,6 +95,28 @@ export declare class SlotRepository extends BaseRepository {
92
95
  /** Explicit operator action: forget the locked work so a re-run picks another candidate. */
93
96
  clearCellWork(slotId: string, targetId: string): void;
94
97
  setCellStatus(slotId: string, targetId: string, status: CellStatus, error?: string): void;
98
+ /**
99
+ * Transition a cell with FSM validation. Never downgrades a confirmed cell;
100
+ * an illegal transition throws rather than silently corrupting state.
101
+ */
102
+ transitionCell(slotId: string, targetId: string, next: CellStatus, error?: string): SlotItemRecord;
103
+ /**
104
+ * Claim execution ownership of a slot for `owner` until `leaseUntil`
105
+ * (epoch ms). Returns true when this caller now owns the lease. A second
106
+ * process/trigger sees an active lease and must converge (resume/observe),
107
+ * not start a parallel run. An expired lease is reclaimable.
108
+ */
109
+ claimSlotLease(slotId: string, owner: string, leaseUntil: number, now?: number): boolean;
110
+ heartbeatSlotLease(slotId: string, owner: string, leaseUntil: number, now?: number): void;
111
+ releaseSlotLease(slotId: string, owner: string): void;
112
+ getSlotLease(slotId: string): {
113
+ owner: string | null;
114
+ until: number | null;
115
+ };
116
+ /** Slots whose lease expired while still non-terminal (crashed workers). */
117
+ slotsWithStaleLease(now?: number): string[];
118
+ /** Record an error without changing terminality (retryable failure keeps the cell resumable). */
119
+ setCellError(slotId: string, targetId: string, error: string): void;
95
120
  /** Work ids already locked in THIS slot (to stop two cells taking the same work). */
96
121
  getLockedWorkIds(slotId: string): Set<string>;
97
122
  /** Roll up a slot's status from its cells. */
@@ -1 +1 @@
1
- {"version":3,"file":"SlotRepository.d.ts","sourceRoot":"","sources":["../../../src/storage/repositories/SlotRepository.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SlotRepository.d.ts","sourceRoot":"","sources":["../../../src/storage/repositories/SlotRepository.ts"],"names":[],"mappings":"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"}