pixivflow 2.19.2 → 2.19.4
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/dist/commands/scheduler-runtime.js +16 -17
- package/dist/delivery/DeliveryAck.d.ts +14 -0
- package/dist/delivery/DeliveryAck.js +18 -0
- package/dist/delivery/DeliveryLedgerPort.d.ts +14 -0
- package/dist/delivery/DeliveryLedgerPort.js +43 -0
- package/dist/delivery/OutboxWorker.js +13 -0
- package/dist/delivery/settleDeliveryTerminal.d.ts +25 -0
- package/dist/delivery/settleDeliveryTerminal.js +40 -0
- package/dist/download/DownloadManager.d.ts +5 -0
- package/dist/download/DownloadManager.js +12 -2
- package/dist/download/handlers/IllustrationTargetHandler.d.ts +27 -1
- package/dist/download/handlers/IllustrationTargetHandler.js +105 -7
- package/dist/download/handlers/NovelTargetHandler.d.ts +27 -1
- package/dist/download/handlers/NovelTargetHandler.js +107 -3
- package/dist/package.json +1 -1
- package/dist/pixiv-client/TargetSearchRunner.js +24 -8
- package/dist/scheduler/SlotCoordinator.d.ts +74 -1
- package/dist/scheduler/SlotCoordinator.js +108 -1
- package/dist/scheduler/WorkIdentity.d.ts +49 -0
- package/dist/scheduler/WorkIdentity.js +31 -0
- package/dist/storage/repositories/DeliveryRepository.d.ts +9 -0
- package/dist/storage/repositories/DeliveryRepository.js +16 -0
- package/dist/storage/repositories/OutboxRepository.d.ts +9 -0
- package/dist/storage/repositories/OutboxRepository.js +17 -0
- package/dist/storage/repositories/SlotRepository.d.ts +27 -0
- package/dist/storage/repositories/SlotRepository.js +45 -0
- package/dist/topic/TopicPipeline.js +4 -0
- package/dist/utils/errors.d.ts +9 -0
- package/dist/utils/errors.js +14 -1
- package/dist/version.js +1 -1
- package/dist/webui/package.json +1 -1
- package/package.json +1 -1
|
@@ -92,6 +92,33 @@ export declare class SlotRepository extends BaseRepository {
|
|
|
92
92
|
* candidate replacement is a separate explicit operator action (clearCellWork).
|
|
93
93
|
*/
|
|
94
94
|
lockCellWork(slotId: string, targetId: string, workId: string, workType: string): SlotItemRecord;
|
|
95
|
+
/**
|
|
96
|
+
* Compare-and-set the cell's work binding, with real concurrency semantics.
|
|
97
|
+
*
|
|
98
|
+
* `lockCellWork` above only stops *this* process from overwriting an existing
|
|
99
|
+
* id (COALESCE); it cannot elect a winner between two callers that both read
|
|
100
|
+
* "no binding". This one can: the write is guarded by `work_id IS NULL OR
|
|
101
|
+
* work_id = @workId`, so if two workers select A and B at the same instant
|
|
102
|
+
* exactly one UPDATE lands. The returned record is authoritative — a losing
|
|
103
|
+
* caller MUST continue with `cell.workId`, never with its own candidate, or
|
|
104
|
+
* the cell would process a work it does not own.
|
|
105
|
+
*/
|
|
106
|
+
tryLockCellWork(slotId: string, targetId: string, workId: string, workType: string): {
|
|
107
|
+
cell: SlotItemRecord;
|
|
108
|
+
won: boolean;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Roll back a PROVISIONAL binding taken for a work that produced no local
|
|
112
|
+
* artifact (a candidate that failed while the cell was still unbound).
|
|
113
|
+
*
|
|
114
|
+
* Deliberately narrow: it only clears the row while it still holds exactly
|
|
115
|
+
* `workId` AND is still `selected`. Once the cell moved on (an artifact was
|
|
116
|
+
* persisted -> delivery_pending/submitted/..., or another writer rebound it)
|
|
117
|
+
* the release is refused, so it can never erase a committed work identity.
|
|
118
|
+
* Re-selecting is only ever allowed while nothing was committed — that is what
|
|
119
|
+
* keeps (slotId,targetId) -> workId stable.
|
|
120
|
+
*/
|
|
121
|
+
releaseCellWork(slotId: string, targetId: string, workId: string): boolean;
|
|
95
122
|
/** Explicit operator action: forget the locked work so a re-run picks another candidate. */
|
|
96
123
|
clearCellWork(slotId: string, targetId: string): void;
|
|
97
124
|
setCellStatus(slotId: string, targetId: string, status: CellStatus, error?: string): void;
|
|
@@ -137,6 +137,51 @@ class SlotRepository extends BaseRepository_1.BaseRepository {
|
|
|
137
137
|
.run({ slotId, targetId, workId, workType });
|
|
138
138
|
return this.getCell(slotId, targetId);
|
|
139
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* Compare-and-set the cell's work binding, with real concurrency semantics.
|
|
142
|
+
*
|
|
143
|
+
* `lockCellWork` above only stops *this* process from overwriting an existing
|
|
144
|
+
* id (COALESCE); it cannot elect a winner between two callers that both read
|
|
145
|
+
* "no binding". This one can: the write is guarded by `work_id IS NULL OR
|
|
146
|
+
* work_id = @workId`, so if two workers select A and B at the same instant
|
|
147
|
+
* exactly one UPDATE lands. The returned record is authoritative — a losing
|
|
148
|
+
* caller MUST continue with `cell.workId`, never with its own candidate, or
|
|
149
|
+
* the cell would process a work it does not own.
|
|
150
|
+
*/
|
|
151
|
+
tryLockCellWork(slotId, targetId, workId, workType) {
|
|
152
|
+
this.db
|
|
153
|
+
.prepare(`UPDATE schedule_slot_items
|
|
154
|
+
SET work_id = @workId,
|
|
155
|
+
work_type = CASE WHEN work_id IS NULL THEN @workType ELSE work_type END,
|
|
156
|
+
status = CASE WHEN status = 'pending' THEN 'selected' ELSE status END,
|
|
157
|
+
attempt_count = CASE WHEN work_id IS NULL THEN attempt_count + 1 ELSE attempt_count END,
|
|
158
|
+
updated_at = CURRENT_TIMESTAMP
|
|
159
|
+
WHERE slot_id = @slotId AND target_id = @targetId
|
|
160
|
+
AND (work_id IS NULL OR work_id = @workId)`)
|
|
161
|
+
.run({ slotId, targetId, workId, workType });
|
|
162
|
+
const cell = this.getCell(slotId, targetId);
|
|
163
|
+
return { cell, won: cell.workId === workId };
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Roll back a PROVISIONAL binding taken for a work that produced no local
|
|
167
|
+
* artifact (a candidate that failed while the cell was still unbound).
|
|
168
|
+
*
|
|
169
|
+
* Deliberately narrow: it only clears the row while it still holds exactly
|
|
170
|
+
* `workId` AND is still `selected`. Once the cell moved on (an artifact was
|
|
171
|
+
* persisted -> delivery_pending/submitted/..., or another writer rebound it)
|
|
172
|
+
* the release is refused, so it can never erase a committed work identity.
|
|
173
|
+
* Re-selecting is only ever allowed while nothing was committed — that is what
|
|
174
|
+
* keeps (slotId,targetId) -> workId stable.
|
|
175
|
+
*/
|
|
176
|
+
releaseCellWork(slotId, targetId, workId) {
|
|
177
|
+
const info = this.db
|
|
178
|
+
.prepare(`UPDATE schedule_slot_items
|
|
179
|
+
SET work_id = NULL, status = 'pending', updated_at = CURRENT_TIMESTAMP
|
|
180
|
+
WHERE slot_id = @slotId AND target_id = @targetId
|
|
181
|
+
AND work_id = @workId AND status = 'selected'`)
|
|
182
|
+
.run({ slotId, targetId, workId });
|
|
183
|
+
return info.changes > 0;
|
|
184
|
+
}
|
|
140
185
|
/** Explicit operator action: forget the locked work so a re-run picks another candidate. */
|
|
141
186
|
clearCellWork(slotId, targetId) {
|
|
142
187
|
this.db
|
|
@@ -123,6 +123,10 @@ class TopicPipeline {
|
|
|
123
123
|
// A cancellation must not be degraded into "no results for this tag": that
|
|
124
124
|
// would silently continue the cancelled run across the remaining tags.
|
|
125
125
|
(0, errors_1.rethrowIfCancelled)(error, this.signal);
|
|
126
|
+
// A broken pager contract must not degrade either: reporting "no works
|
|
127
|
+
// today" would hide the failure and let the run claim success.
|
|
128
|
+
if (error instanceof errors_1.PaginationError)
|
|
129
|
+
throw error;
|
|
126
130
|
logger_1.logger.warn('[TopicCollector] search failed tag=' + tag + ' type=' + contentType + ': ' + (error instanceof Error ? error.message : String(error)));
|
|
127
131
|
return [];
|
|
128
132
|
}
|
package/dist/utils/errors.d.ts
CHANGED
|
@@ -33,6 +33,15 @@ export declare class NetworkError extends PixivFlowError {
|
|
|
33
33
|
waitTime?: number;
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* The pagination adapter returned a cursor it had already handed back (the same
|
|
38
|
+
* `next` twice, or a cycle). Re-requesting would repeat the previous page
|
|
39
|
+
* forever, which is exactly the Attempt 2 fallback-day failure, so the pager
|
|
40
|
+
* fails deterministically instead of spinning.
|
|
41
|
+
*/
|
|
42
|
+
export declare class PaginationError extends PixivFlowError {
|
|
43
|
+
constructor(message: string, cause?: Error);
|
|
44
|
+
}
|
|
36
45
|
export declare class DownloadError extends PixivFlowError {
|
|
37
46
|
readonly itemId?: number | undefined;
|
|
38
47
|
readonly itemType?: "illustration" | "novel" | undefined;
|
package/dist/utils/errors.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Provides consistent error types and handling patterns across the application
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.ErrorRecoveryStrategy = exports.HelpRequest = exports.VersionRequest = exports.OperationCancelledError = exports.DatabaseError = exports.PendingDeliveryError = exports.DownloadError = exports.NetworkError = exports.AuthenticationError = exports.ConfigError = exports.PixivFlowError = exports.PixivTimeoutError = exports.PixivRateLimitError = exports.PixivNotFoundError = exports.PixivNetworkError = exports.PixivHttpError = exports.PixivError = void 0;
|
|
7
|
+
exports.ErrorRecoveryStrategy = exports.HelpRequest = exports.VersionRequest = exports.OperationCancelledError = exports.DatabaseError = exports.PendingDeliveryError = exports.DownloadError = exports.PaginationError = exports.NetworkError = exports.AuthenticationError = exports.ConfigError = exports.PixivFlowError = exports.PixivTimeoutError = exports.PixivRateLimitError = exports.PixivNotFoundError = exports.PixivNetworkError = exports.PixivHttpError = exports.PixivError = void 0;
|
|
8
8
|
exports.isPixivKitError = isPixivKitError;
|
|
9
9
|
exports.toNetworkError = toNetworkError;
|
|
10
10
|
exports.isOperationCancelled = isOperationCancelled;
|
|
@@ -92,6 +92,19 @@ class NetworkError extends PixivFlowError {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
exports.NetworkError = NetworkError;
|
|
95
|
+
/**
|
|
96
|
+
* The pagination adapter returned a cursor it had already handed back (the same
|
|
97
|
+
* `next` twice, or a cycle). Re-requesting would repeat the previous page
|
|
98
|
+
* forever, which is exactly the Attempt 2 fallback-day failure, so the pager
|
|
99
|
+
* fails deterministically instead of spinning.
|
|
100
|
+
*/
|
|
101
|
+
class PaginationError extends PixivFlowError {
|
|
102
|
+
constructor(message, cause) {
|
|
103
|
+
super(message, 'PAGINATION_ERROR', undefined, cause);
|
|
104
|
+
this.name = 'PaginationError';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
exports.PaginationError = PaginationError;
|
|
95
108
|
class DownloadError extends PixivFlowError {
|
|
96
109
|
itemId;
|
|
97
110
|
itemType;
|
package/dist/version.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BUILD = void 0;
|
|
4
4
|
// GENERATED by scripts/write-version.js — do not edit manually.
|
|
5
|
-
exports.BUILD = { version: '2.19.
|
|
5
|
+
exports.BUILD = { version: '2.19.4', commit: 'f331cd4bb164' };
|
|
6
6
|
//# sourceMappingURL=version.js.map
|
package/dist/webui/package.json
CHANGED
package/package.json
CHANGED