pixivflow 2.5.0 → 2.7.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 (97) hide show
  1. package/README.md +72 -0
  2. package/README_EN.md +55 -0
  3. package/config/fly-two-bots.example.json +240 -0
  4. package/dist/commands/SchedulerCommand.d.ts +1 -0
  5. package/dist/commands/SchedulerCommand.d.ts.map +1 -1
  6. package/dist/commands/SchedulerCommand.js +78 -22
  7. package/dist/commands/SchedulerCommand.js.map +1 -1
  8. package/dist/config/defaults.d.ts +5 -0
  9. package/dist/config/defaults.d.ts.map +1 -1
  10. package/dist/config/defaults.js +6 -0
  11. package/dist/config/defaults.js.map +1 -1
  12. package/dist/config/loader.d.ts +1 -1
  13. package/dist/config/loader.d.ts.map +1 -1
  14. package/dist/config/loader.js +4 -2
  15. package/dist/config/loader.js.map +1 -1
  16. package/dist/config/path-resolution.d.ts.map +1 -1
  17. package/dist/config/path-resolution.js +4 -0
  18. package/dist/config/path-resolution.js.map +1 -1
  19. package/dist/config/types.d.ts +91 -3
  20. package/dist/config/types.d.ts.map +1 -1
  21. package/dist/config/validation.d.ts.map +1 -1
  22. package/dist/config/validation.js +92 -0
  23. package/dist/config/validation.js.map +1 -1
  24. package/dist/config.d.ts +1 -1
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js.map +1 -1
  27. package/dist/delivery/DeliveryDispatcher.d.ts +11 -0
  28. package/dist/delivery/DeliveryDispatcher.d.ts.map +1 -0
  29. package/dist/delivery/DeliveryDispatcher.js +31 -0
  30. package/dist/delivery/DeliveryDispatcher.js.map +1 -0
  31. package/dist/delivery/DeliveryOutbox.d.ts +23 -0
  32. package/dist/delivery/DeliveryOutbox.d.ts.map +1 -0
  33. package/dist/delivery/DeliveryOutbox.js +172 -0
  34. package/dist/delivery/DeliveryOutbox.js.map +1 -0
  35. package/dist/delivery/HttpMultipartDelivery.d.ts +18 -0
  36. package/dist/delivery/HttpMultipartDelivery.d.ts.map +1 -0
  37. package/dist/delivery/HttpMultipartDelivery.js +217 -0
  38. package/dist/delivery/HttpMultipartDelivery.js.map +1 -0
  39. package/dist/delivery/types.d.ts +31 -0
  40. package/dist/delivery/types.d.ts.map +1 -0
  41. package/dist/delivery/types.js +3 -0
  42. package/dist/delivery/types.js.map +1 -0
  43. package/dist/download/DownloadManager.d.ts +2 -0
  44. package/dist/download/DownloadManager.d.ts.map +1 -1
  45. package/dist/download/DownloadManager.js +30 -2
  46. package/dist/download/DownloadManager.js.map +1 -1
  47. package/dist/download/IllustrationDownloader.d.ts +2 -1
  48. package/dist/download/IllustrationDownloader.d.ts.map +1 -1
  49. package/dist/download/IllustrationDownloader.js +29 -4
  50. package/dist/download/IllustrationDownloader.js.map +1 -1
  51. package/dist/download/NovelDownloader.d.ts +2 -1
  52. package/dist/download/NovelDownloader.d.ts.map +1 -1
  53. package/dist/download/NovelDownloader.js +9 -1
  54. package/dist/download/NovelDownloader.js.map +1 -1
  55. package/dist/download/handlers/IllustrationTargetHandler.d.ts +4 -1
  56. package/dist/download/handlers/IllustrationTargetHandler.d.ts.map +1 -1
  57. package/dist/download/handlers/IllustrationTargetHandler.js +27 -10
  58. package/dist/download/handlers/IllustrationTargetHandler.js.map +1 -1
  59. package/dist/download/handlers/NovelTargetHandler.d.ts +4 -1
  60. package/dist/download/handlers/NovelTargetHandler.d.ts.map +1 -1
  61. package/dist/download/handlers/NovelTargetHandler.js +26 -11
  62. package/dist/download/handlers/NovelTargetHandler.js.map +1 -1
  63. package/dist/index.js +4 -1
  64. package/dist/index.js.map +1 -1
  65. package/dist/package.json +1 -1
  66. package/dist/scheduler/MultiScheduleManager.d.ts +39 -0
  67. package/dist/scheduler/MultiScheduleManager.d.ts.map +1 -0
  68. package/dist/scheduler/MultiScheduleManager.js +182 -0
  69. package/dist/scheduler/MultiScheduleManager.js.map +1 -0
  70. package/dist/scheduler/Scheduler.d.ts +13 -1
  71. package/dist/scheduler/Scheduler.d.ts.map +1 -1
  72. package/dist/scheduler/Scheduler.js +31 -7
  73. package/dist/scheduler/Scheduler.js.map +1 -1
  74. package/dist/scheduler/schedules.d.ts +8 -0
  75. package/dist/scheduler/schedules.d.ts.map +1 -0
  76. package/dist/scheduler/schedules.js +32 -0
  77. package/dist/scheduler/schedules.js.map +1 -0
  78. package/dist/storage/Database.d.ts +5 -4
  79. package/dist/storage/Database.d.ts.map +1 -1
  80. package/dist/storage/Database.js +13 -9
  81. package/dist/storage/Database.js.map +1 -1
  82. package/dist/storage/DatabaseMigration.d.ts.map +1 -1
  83. package/dist/storage/DatabaseMigration.js +11 -0
  84. package/dist/storage/DatabaseMigration.js.map +1 -1
  85. package/dist/storage/repositories/SchedulerRepository.d.ts +4 -4
  86. package/dist/storage/repositories/SchedulerRepository.d.ts.map +1 -1
  87. package/dist/storage/repositories/SchedulerRepository.js +18 -12
  88. package/dist/storage/repositories/SchedulerRepository.js.map +1 -1
  89. package/dist/utils/config-validator-unified.d.ts.map +1 -1
  90. package/dist/utils/config-validator-unified.js +117 -0
  91. package/dist/utils/config-validator-unified.js.map +1 -1
  92. package/dist/utils/errors.d.ts +8 -0
  93. package/dist/utils/errors.d.ts.map +1 -1
  94. package/dist/utils/errors.js +16 -1
  95. package/dist/utils/errors.js.map +1 -1
  96. package/dist/webui/package.json +1 -1
  97. package/package.json +2 -1
package/README.md CHANGED
@@ -54,6 +54,33 @@ pixivflow download
54
54
  pixivflow scheduler # 按 cron 配置长期挂机自动收集
55
55
  ```
56
56
 
57
+ ### 单进程多计划与配置热重载
58
+
59
+ `schedules[]` 可以为不同 target 组设置各自的 Cron。所有计划由一个 Node
60
+ 进程托管,共享 Pixiv 客户端、SQLite 与文件服务;执行阶段使用有界串行队列,
61
+ 适合 512 MiB 小内存机器。配置文件默认被监听,SSH/同步工具替换文件后会先完整
62
+ 校验,再一次性替换全部调度项;无效 JSON、错误 Cron 或未知 target id 不会破坏
63
+ 当前运行中的计划。正在执行的任务继续使用旧快照,下一次任务使用新快照。
64
+
65
+ ```json
66
+ {
67
+ "scheduler": { "enabled": false, "cron": "0 3 * * *" },
68
+ "schedules": [
69
+ { "id": "bot1", "enabled": true, "cron": "10 5 * * *", "targetIds": ["bot1-art", "bot1-novel"] },
70
+ { "id": "bot2", "enabled": true, "cron": "30 5 * * *", "targetIds": ["bot2-art", "bot2-novel"] }
71
+ ],
72
+ "targets": [
73
+ { "id": "bot1-art", "type": "illustration", "mode": "ranking", "rankingDate": "YESTERDAY" },
74
+ { "id": "bot1-novel", "type": "novel", "mode": "ranking", "rankingDate": "YESTERDAY" }
75
+ ]
76
+ }
77
+ ```
78
+
79
+ 旧的单 `scheduler` 配置继续兼容。`pixiv`、`network`、`storage` 涉及长生命周期
80
+ 连接或路径,修改后需要重启;`schedules`、`targets`、`delivery`、`download` 可以
81
+ 热重载。完整双 Bot 缓存投递模板见
82
+ [`config/fly-two-bots.example.json`](config/fly-two-bots.example.json)。
83
+
57
84
  ## 下载目标
58
85
 
59
86
  在配置文件的 `targets` 中定义要收集的内容,多个条件可以组合:
@@ -69,6 +96,51 @@ pixivflow scheduler # 按 cron 配置长期挂机自动收集
69
96
  已下载的作品由 SQLite 数据库记录并自动跳过;文件存在但缺少记录时会自动补齐,
70
97
  两者互不冲突。
71
98
 
99
+ ### 本地留存与缓存交付
100
+
101
+ 每个 target 可选择 `storageMode: "persistent"`(默认,本地永久留存)或
102
+ `storageMode: "cache"`(下载后交给命名 delivery target,成功才删除本地文件)。
103
+ 交付层不绑定具体服务;下面只是把一个 HTTP multipart 投稿接口翻译成配置:
104
+
105
+ ```json
106
+ {
107
+ "delivery": {
108
+ "targets": {
109
+ "tg-example": {
110
+ "type": "httpMultipart",
111
+ "url": "https://telesubmit-multi-bot.fly.dev/api/bot1/v1/submissions",
112
+ "headers": { "Authorization": "Bearer ${TG_SUBMIT_TOKEN}" },
113
+ "fileField": "files",
114
+ "fields": { "title": "{{title}}" },
115
+ "success": { "statuses": [201], "jsonPath": "ok", "equals": true },
116
+ "arrayFormat": "comma",
117
+ "maxAttempts": 3,
118
+ "retryDelayMs": 2000
119
+ }
120
+ },
121
+ "deleteAfterDelivery": true
122
+ },
123
+ "targets": [
124
+ { "type": "illustration", "tag": "收藏", "storageMode": "persistent" },
125
+ {
126
+ "type": "illustration",
127
+ "tag": "更新",
128
+ "storageMode": "cache",
129
+ "delivery": {
130
+ "target": "tg-example",
131
+ "fields": { "tags": ["公告", "更新"], "anonymous": false }
132
+ }
133
+ }
134
+ ]
135
+ }
136
+ ```
137
+
138
+ headers 和 URL 支持任意 `${ENV_NAME}` 环境变量插值。交付失败时文件和
139
+ outbox 清单保留在 SQLite 数据库同级的 `delivery-outbox/`;下一次运行会先
140
+ 自动重试,成功后再清理。
141
+ 对上面的 TG 示例,可把 `/gen_token` 得到的 `tp_...` 放入
142
+ `TG_SUBMIT_TOKEN` 环境变量;这只是示例服务自己的认证流程。
143
+
72
144
  交互式配置向导:`pixivflow setup`。
73
145
 
74
146
  ## 常用命令
package/README_EN.md CHANGED
@@ -56,6 +56,21 @@ pixivflow download
56
56
  pixivflow scheduler # long-running cron collection
57
57
  ```
58
58
 
59
+ ### Multiple schedules and atomic hot reload
60
+
61
+ `schedules[]` hosts independently timed target groups in one Node process.
62
+ Plans share Pixiv authentication, SQLite, and file services, while a bounded
63
+ serial queue prevents overlapping downloads from producing memory spikes.
64
+ The active config is watched by default: replace it over SSH and PixivFlow
65
+ fully validates the new snapshot before swapping the entire cron table. An
66
+ invalid edit leaves the previous schedules running. In-flight work finishes
67
+ on its old snapshot; the next run sees the new one.
68
+
69
+ Legacy single-`scheduler` configs remain supported. `schedules`, `targets`,
70
+ `delivery`, and `download` are hot-reloadable; changes to `pixiv`, `network`,
71
+ or `storage` require a process restart. See the ready-to-edit
72
+ [`config/fly-two-bots.example.json`](config/fly-two-bots.example.json) template.
73
+
59
74
  ## Download targets
60
75
 
61
76
  Define what to collect in the `targets` section of your config. Conditions
@@ -73,6 +88,46 @@ Downloaded items are tracked in a SQLite database and skipped automatically;
73
88
  files that exist without a database record are reconciled, so the two never
74
89
  conflict.
75
90
 
91
+ ### Persistent and cache delivery modes
92
+
93
+ Each target can use `storageMode: "persistent"` (the default, keep files) or
94
+ `storageMode: "cache"` (send files to a named delivery target and delete them
95
+ only after success). The delivery layer is service-independent; this example
96
+ merely translates an HTTP multipart submission API into configuration:
97
+
98
+ ```json
99
+ {
100
+ "delivery": {
101
+ "targets": {
102
+ "sharing-api": {
103
+ "type": "httpMultipart",
104
+ "url": "https://example.test/submissions",
105
+ "headers": { "Authorization": "Bearer ${SHARING_TOKEN}" },
106
+ "fileField": "files",
107
+ "fields": { "title": "{{title}}" },
108
+ "success": { "statuses": [201], "jsonPath": "ok", "equals": true }
109
+ }
110
+ }
111
+ },
112
+ "targets": [
113
+ { "type": "illustration", "tag": "archive", "storageMode": "persistent" },
114
+ {
115
+ "type": "illustration",
116
+ "tag": "updates",
117
+ "storageMode": "cache",
118
+ "delivery": {
119
+ "target": "sharing-api",
120
+ "fields": { "tags": ["announcement", "update"], "anonymous": false }
121
+ }
122
+ }
123
+ ]
124
+ }
125
+ ```
126
+
127
+ Headers and URLs accept arbitrary `${ENV_NAME}` interpolation. Failed delivery
128
+ keeps both files and the durable outbox manifest beside the SQLite database;
129
+ the next run retries them before processing new targets.
130
+
76
131
  Interactive configuration wizard: `pixivflow setup`.
77
132
 
78
133
  ## Common commands
@@ -0,0 +1,240 @@
1
+ {
2
+ "logLevel": "info",
3
+ "pixiv": {
4
+ "clientId": "MOBrBDS8blbauoSck0ZfDbtuzpyT",
5
+ "clientSecret": "lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj",
6
+ "deviceToken": "pixiv",
7
+ "refreshToken": "YOUR_REFRESH_TOKEN",
8
+ "userAgent": "PixivAndroidApp/5.0.234 (Android 11; Pixel 6)"
9
+ },
10
+ "network": {
11
+ "timeoutMs": 30000,
12
+ "retries": 3,
13
+ "retryDelay": 2000
14
+ },
15
+ "storage": {
16
+ "databasePath": "./pixivflow.db",
17
+ "downloadDirectory": "./cache",
18
+ "illustrationDirectory": "./cache/illustrations",
19
+ "novelDirectory": "./cache/novels"
20
+ },
21
+ "scheduler": {
22
+ "enabled": false,
23
+ "cron": "0 3 * * *",
24
+ "timezone": "Asia/Shanghai"
25
+ },
26
+ "schedules": [
27
+ {
28
+ "id": "bot1-daily",
29
+ "name": "Bot 1 daily ranking",
30
+ "enabled": false,
31
+ "cron": "10 5 * * *",
32
+ "timezone": "Asia/Shanghai",
33
+ "targetIds": [
34
+ "bot1-illust-tag-a",
35
+ "bot1-novel-tag-a",
36
+ "bot1-illust-tag-b",
37
+ "bot1-novel-tag-b"
38
+ ],
39
+ "timeout": 1200000,
40
+ "maxConsecutiveFailures": 5,
41
+ "failureRetryDelay": 30000
42
+ },
43
+ {
44
+ "id": "bot2-daily",
45
+ "name": "Bot 2 daily ranking",
46
+ "enabled": false,
47
+ "cron": "30 5 * * *",
48
+ "timezone": "Asia/Shanghai",
49
+ "targetIds": [
50
+ "bot2-illust-tag-c",
51
+ "bot2-novel-tag-c",
52
+ "bot2-illust-tag-d",
53
+ "bot2-novel-tag-d"
54
+ ],
55
+ "timeout": 1200000,
56
+ "maxConsecutiveFailures": 5,
57
+ "failureRetryDelay": 30000
58
+ }
59
+ ],
60
+ "schedulerRuntime": {
61
+ "watchConfig": true,
62
+ "reloadDebounceMs": 500,
63
+ "queueLimit": 2
64
+ },
65
+ "download": {
66
+ "concurrency": 1,
67
+ "requestDelay": 1000,
68
+ "dynamicConcurrency": false,
69
+ "minConcurrency": 1,
70
+ "maxRetries": 3,
71
+ "retryDelay": 3000,
72
+ "timeout": 90000
73
+ },
74
+ "delivery": {
75
+ "targets": {
76
+ "telepost-bot1": {
77
+ "type": "httpMultipart",
78
+ "url": "http://127.0.0.1:8080/api/bot1/v1/submissions",
79
+ "headers": {
80
+ "Authorization": "Bearer ${TELEPOST_BOT1_SUBMIT_TOKEN}"
81
+ },
82
+ "fileField": "files",
83
+ "fields": {
84
+ "title": "{{title}}",
85
+ "tags": [
86
+ "Pixiv",
87
+ "{{tag}}"
88
+ ],
89
+ "note": "Pixiv ID: {{pixivId}}",
90
+ "anonymous": true,
91
+ "idempotency_key": "pixiv:bot1:{{type}}:{{pixivId}}"
92
+ },
93
+ "success": {
94
+ "statuses": [
95
+ 201
96
+ ],
97
+ "jsonPath": "ok",
98
+ "equals": true
99
+ },
100
+ "maxAttempts": 3,
101
+ "retryDelayMs": 3000
102
+ },
103
+ "telepost-bot2": {
104
+ "type": "httpMultipart",
105
+ "url": "http://127.0.0.1:8080/api/bot2/v1/submissions",
106
+ "headers": {
107
+ "Authorization": "Bearer ${TELEPOST_BOT2_SUBMIT_TOKEN}"
108
+ },
109
+ "fileField": "files",
110
+ "fields": {
111
+ "title": "{{title}}",
112
+ "tags": [
113
+ "Pixiv",
114
+ "{{tag}}"
115
+ ],
116
+ "note": "Pixiv ID: {{pixivId}}",
117
+ "anonymous": true,
118
+ "idempotency_key": "pixiv:bot2:{{type}}:{{pixivId}}"
119
+ },
120
+ "success": {
121
+ "statuses": [
122
+ 201
123
+ ],
124
+ "jsonPath": "ok",
125
+ "equals": true
126
+ },
127
+ "maxAttempts": 3,
128
+ "retryDelayMs": 3000
129
+ }
130
+ },
131
+ "deleteAfterDelivery": true
132
+ },
133
+ "targets": [
134
+ {
135
+ "id": "bot1-illust-tag-a",
136
+ "type": "illustration",
137
+ "mode": "ranking",
138
+ "rankingMode": "day",
139
+ "rankingDate": "YESTERDAY",
140
+ "filterTag": "TAG_A",
141
+ "limit": 1,
142
+ "storageMode": "cache",
143
+ "delivery": {
144
+ "target": "telepost-bot1"
145
+ }
146
+ },
147
+ {
148
+ "id": "bot1-novel-tag-a",
149
+ "type": "novel",
150
+ "mode": "ranking",
151
+ "rankingMode": "day",
152
+ "rankingDate": "YESTERDAY",
153
+ "filterTag": "TAG_A",
154
+ "limit": 1,
155
+ "storageMode": "cache",
156
+ "delivery": {
157
+ "target": "telepost-bot1"
158
+ }
159
+ },
160
+ {
161
+ "id": "bot1-illust-tag-b",
162
+ "type": "illustration",
163
+ "mode": "ranking",
164
+ "rankingMode": "day",
165
+ "rankingDate": "YESTERDAY",
166
+ "filterTag": "TAG_B",
167
+ "limit": 1,
168
+ "storageMode": "cache",
169
+ "delivery": {
170
+ "target": "telepost-bot1"
171
+ }
172
+ },
173
+ {
174
+ "id": "bot1-novel-tag-b",
175
+ "type": "novel",
176
+ "mode": "ranking",
177
+ "rankingMode": "day",
178
+ "rankingDate": "YESTERDAY",
179
+ "filterTag": "TAG_B",
180
+ "limit": 1,
181
+ "storageMode": "cache",
182
+ "delivery": {
183
+ "target": "telepost-bot1"
184
+ }
185
+ },
186
+ {
187
+ "id": "bot2-illust-tag-c",
188
+ "type": "illustration",
189
+ "mode": "ranking",
190
+ "rankingMode": "day",
191
+ "rankingDate": "YESTERDAY",
192
+ "filterTag": "TAG_C",
193
+ "limit": 1,
194
+ "storageMode": "cache",
195
+ "delivery": {
196
+ "target": "telepost-bot2"
197
+ }
198
+ },
199
+ {
200
+ "id": "bot2-novel-tag-c",
201
+ "type": "novel",
202
+ "mode": "ranking",
203
+ "rankingMode": "day",
204
+ "rankingDate": "YESTERDAY",
205
+ "filterTag": "TAG_C",
206
+ "limit": 1,
207
+ "storageMode": "cache",
208
+ "delivery": {
209
+ "target": "telepost-bot2"
210
+ }
211
+ },
212
+ {
213
+ "id": "bot2-illust-tag-d",
214
+ "type": "illustration",
215
+ "mode": "ranking",
216
+ "rankingMode": "day",
217
+ "rankingDate": "YESTERDAY",
218
+ "filterTag": "TAG_D",
219
+ "limit": 1,
220
+ "storageMode": "cache",
221
+ "delivery": {
222
+ "target": "telepost-bot2"
223
+ }
224
+ },
225
+ {
226
+ "id": "bot2-novel-tag-d",
227
+ "type": "novel",
228
+ "mode": "ranking",
229
+ "rankingMode": "day",
230
+ "rankingDate": "YESTERDAY",
231
+ "filterTag": "TAG_D",
232
+ "limit": 1,
233
+ "storageMode": "cache",
234
+ "delivery": {
235
+ "target": "telepost-bot2"
236
+ }
237
+ }
238
+ ],
239
+ "initialDelay": 0
240
+ }
@@ -17,6 +17,7 @@ export declare class SchedulerCommand extends BaseCommand {
17
17
  longRunning: boolean;
18
18
  };
19
19
  execute(context: CommandContext, args: CommandArgs): Promise<CommandResult>;
20
+ private getImmutableFingerprint;
20
21
  getUsage(): string;
21
22
  }
22
23
  //# sourceMappingURL=SchedulerCommand.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SchedulerCommand.d.ts","sourceRoot":"","sources":["../../src/commands/SchedulerCommand.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAUrE;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,WAAW;IAC/C,QAAQ,CAAC,IAAI,eAAe;IAC5B,QAAQ,CAAC,WAAW,oDAAoD;IACxE,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAgB;IAC1C,QAAQ,CAAC,QAAQ;;;;MAIf;IAEI,OAAO,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC;IAkFjF,QAAQ,IAAI,MAAM;CAYnB"}
1
+ {"version":3,"file":"SchedulerCommand.d.ts","sourceRoot":"","sources":["../../src/commands/SchedulerCommand.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAYrE;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,WAAW;IAC/C,QAAQ,CAAC,IAAI,eAAe;IAC5B,QAAQ,CAAC,WAAW,oDAAoD;IACxE,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAgB;IAC1C,QAAQ,CAAC,QAAQ;;;;MAIf;IAEI,OAAO,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC;IAmIjF,OAAO,CAAC,uBAAuB;IAQ/B,QAAQ,IAAI,MAAM;CAYnB"}
@@ -12,8 +12,10 @@ const AuthClient_1 = require("../pixiv/AuthClient");
12
12
  const PixivClient_1 = require("../pixiv/PixivClient");
13
13
  const FileService_1 = require("../download/FileService");
14
14
  const DownloadManager_1 = require("../download/DownloadManager");
15
- const Scheduler_1 = require("../scheduler/Scheduler");
16
15
  const token_maintenance_1 = require("../utils/token-maintenance");
16
+ const MultiScheduleManager_1 = require("../scheduler/MultiScheduleManager");
17
+ const schedules_1 = require("../scheduler/schedules");
18
+ const placeholders_1 = require("../config/placeholders");
17
19
  /**
18
20
  * Scheduler command - Start scheduler (default if enabled in config)
19
21
  */
@@ -28,45 +30,87 @@ class SchedulerCommand extends Command_1.BaseCommand {
28
30
  };
29
31
  async execute(context, args) {
30
32
  try {
31
- const configPath = (0, config_1.getConfigPath)();
32
- const config = (0, config_1.loadConfig)(configPath);
33
+ const configPath = (0, config_1.getConfigPath)(args.options.config);
34
+ // Keep TODAY/YESTERDAY placeholders intact. They are resolved afresh for
35
+ // every plan execution, not frozen at daemon startup.
36
+ const config = (0, config_1.loadConfig)(configPath, false, false);
33
37
  const database = new Database_1.Database(config.storage.databasePath);
34
38
  database.migrate();
35
39
  const auth = new AuthClient_1.PixivAuth(config.pixiv, config.network, database, configPath);
36
40
  const pixivClient = new PixivClient_1.PixivClient(auth, config);
37
41
  const fileService = new FileService_1.FileService(config.storage);
38
- const downloadManager = new DownloadManager_1.DownloadManager(config, pixivClient, database, fileService);
39
- await downloadManager.initialise();
42
+ await fileService.initialise();
40
43
  // Start token maintenance service for automatic token refresh
41
44
  const tokenMaintenance = (0, token_maintenance_1.createTokenMaintenanceService)(auth, config.pixiv, config.network, config);
42
45
  if (tokenMaintenance) {
43
46
  tokenMaintenance.start();
44
47
  }
45
- const runJob = async () => {
48
+ let activeDownloadManager = null;
49
+ const immutableFingerprint = this.getImmutableFingerprint(config);
50
+ const runJob = async (snapshot, schedule) => {
51
+ const runtimeConfig = (0, placeholders_1.processConfigPlaceholders)(snapshot);
52
+ const targets = (0, schedules_1.selectScheduleTargets)(runtimeConfig.targets, schedule);
53
+ const scopedConfig = { ...runtimeConfig, targets };
54
+ if (targets.length === 0) {
55
+ context.logger.warn('Scheduled plan has no selected targets; skipping', {
56
+ scheduleId: schedule.id,
57
+ targetIds: schedule.targetIds,
58
+ });
59
+ return;
60
+ }
61
+ const downloadManager = new DownloadManager_1.DownloadManager(scopedConfig, pixivClient, database, fileService);
62
+ activeDownloadManager = downloadManager;
63
+ await downloadManager.initialise();
46
64
  // Apply initial delay if configured
47
- if (config.initialDelay && config.initialDelay > 0) {
48
- context.logger.info(`Waiting ${config.initialDelay}ms before starting download...`);
49
- await new Promise(resolve => setTimeout(resolve, config.initialDelay));
65
+ if (runtimeConfig.initialDelay && runtimeConfig.initialDelay > 0) {
66
+ context.logger.info(`Waiting ${runtimeConfig.initialDelay}ms before starting download...`, {
67
+ scheduleId: schedule.id,
68
+ });
69
+ await new Promise(resolve => setTimeout(resolve, runtimeConfig.initialDelay));
50
70
  }
51
71
  context.logger.info('='.repeat(60));
52
- context.logger.info('Starting scheduled Pixiv download job');
72
+ context.logger.info('Starting scheduled Pixiv download plan', {
73
+ scheduleId: schedule.id,
74
+ targets: targets.map(target => target.id ?? target.tag ?? target.filterTag ?? target.type),
75
+ });
53
76
  context.logger.info('='.repeat(60));
54
77
  const startTime = Date.now();
55
- await downloadManager.runAllTargets();
78
+ try {
79
+ await downloadManager.runAllTargets();
80
+ }
81
+ finally {
82
+ if (activeDownloadManager === downloadManager)
83
+ activeDownloadManager = null;
84
+ }
56
85
  const duration = Math.round((Date.now() - startTime) / 1000);
57
86
  context.logger.info('='.repeat(60));
58
- context.logger.info(`Scheduled download job finished (took ${duration}s)`);
87
+ context.logger.info(`Scheduled download plan finished (took ${duration}s)`, {
88
+ scheduleId: schedule.id,
89
+ });
59
90
  context.logger.info('='.repeat(60));
60
91
  };
61
- const scheduler = new Scheduler_1.Scheduler(config.scheduler, database, {
62
- beginRun: () => database.getOverviewStats().totalDownloads,
63
- endRun: (baseline) => Promise.resolve(database.getOverviewStats().totalDownloads - baseline),
64
- requestCancel: (reason) => downloadManager.cancel(reason),
92
+ const manager = new MultiScheduleManager_1.MultiScheduleManager({
93
+ configPath,
94
+ loadConfig: () => {
95
+ const next = (0, config_1.loadConfig)(configPath, false, false);
96
+ if (this.getImmutableFingerprint(next) !== immutableFingerprint) {
97
+ throw new Error('pixiv/network/storage changes require a process restart; schedules, targets, delivery and download settings can be hot-reloaded');
98
+ }
99
+ return next;
100
+ },
101
+ execute: runJob,
102
+ database,
103
+ telemetry: {
104
+ beginRun: () => database.getOverviewStats().totalDownloads,
105
+ endRun: () => database.getOverviewStats().totalDownloads,
106
+ requestCancel: (reason) => activeDownloadManager?.cancel(reason),
107
+ },
65
108
  });
66
- scheduler.start(runJob);
109
+ const status = manager.start(config);
67
110
  const cleanup = () => {
68
111
  context.logger.info('Shutting down PixivFlow');
69
- scheduler.stop();
112
+ manager.stop();
113
+ activeDownloadManager?.cancel('process shutdown');
70
114
  if (tokenMaintenance) {
71
115
  tokenMaintenance.stop();
72
116
  }
@@ -75,9 +119,14 @@ class SchedulerCommand extends Command_1.BaseCommand {
75
119
  };
76
120
  process.on('SIGINT', cleanup);
77
121
  process.on('SIGTERM', cleanup);
122
+ process.on('SIGHUP', () => {
123
+ context.logger.info('Received SIGHUP; reloading scheduler configuration');
124
+ manager.reload();
125
+ });
78
126
  // Keep process alive
79
127
  return this.success('Scheduler started', {
80
- message: 'Scheduler is running. Press Ctrl+C to stop.'
128
+ message: 'Multi-plan scheduler is running with atomic config hot reload. Press Ctrl+C to stop.',
129
+ schedules: status.schedules,
81
130
  });
82
131
  }
83
132
  catch (error) {
@@ -87,14 +136,21 @@ class SchedulerCommand extends Command_1.BaseCommand {
87
136
  return this.failure(error instanceof Error ? error.message : String(error), { error });
88
137
  }
89
138
  }
139
+ getImmutableFingerprint(config) {
140
+ return JSON.stringify({
141
+ pixiv: config.pixiv,
142
+ network: config.network,
143
+ storage: config.storage,
144
+ });
145
+ }
90
146
  getUsage() {
91
147
  return `scheduler
92
148
 
93
149
  Start the scheduler to run download jobs periodically according to config.
94
150
 
95
- The scheduler will run download jobs based on the cron expression configured
96
- in the config file. If scheduler is not enabled in config, this command will
97
- still start but may not execute jobs.
151
+ The scheduler hosts all enabled schedules in one process. Valid changes to
152
+ schedules, targets, delivery and download settings are loaded automatically.
153
+ Pixiv credentials, network and storage changes require a restart.
98
154
 
99
155
  Examples:
100
156
  pixivflow scheduler # Start scheduler`;
@@ -1 +1 @@
1
- {"version":3,"file":"SchedulerCommand.js","sourceRoot":"","sources":["../../src/commands/SchedulerCommand.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,uCAAwC;AACxC,yCAA6C;AAE7C,sCAAsD;AACtD,kDAA+C;AAC/C,oDAAgD;AAChD,sDAAmD;AACnD,yDAAsD;AACtD,iEAA8D;AAC9D,sDAAmD;AACnD,kEAA2E;AAE3E;;GAEG;AACH,MAAa,gBAAiB,SAAQ,qBAAW;IACtC,IAAI,GAAG,WAAW,CAAC;IACnB,WAAW,GAAG,gDAAgD,CAAC;IAC/D,OAAO,GAAa,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACjC,QAAQ,GAAG;QAClB,QAAQ,EAAE,0BAAe,CAAC,QAAQ;QAClC,YAAY,EAAE,IAAI;QAClB,WAAW,EAAE,IAAI;KAClB,CAAC;IAEF,KAAK,CAAC,OAAO,CAAC,OAAuB,EAAE,IAAiB;QACtD,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAA,sBAAa,GAAE,CAAC;YACnC,MAAM,MAAM,GAAG,IAAA,mBAAU,EAAC,UAAU,CAAC,CAAC;YAEtC,MAAM,QAAQ,GAAG,IAAI,mBAAQ,CAAC,MAAM,CAAC,OAAQ,CAAC,YAAa,CAAC,CAAC;YAC7D,QAAQ,CAAC,OAAO,EAAE,CAAC;YAEnB,MAAM,IAAI,GAAG,IAAI,sBAAS,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,OAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;YAChF,MAAM,WAAW,GAAG,IAAI,yBAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAClD,MAAM,WAAW,GAAG,IAAI,yBAAW,CAAC,MAAM,CAAC,OAAQ,CAAC,CAAC;YACrD,MAAM,eAAe,GAAG,IAAI,iCAAe,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;YAExF,MAAM,eAAe,CAAC,UAAU,EAAE,CAAC;YAEnC,8DAA8D;YAC9D,MAAM,gBAAgB,GAAG,IAAA,iDAA6B,EACpD,IAAI,EACJ,MAAM,CAAC,KAAK,EACZ,MAAM,CAAC,OAAQ,EACf,MAAM,CACP,CAAC;YACF,IAAI,gBAAgB,EAAE,CAAC;gBACrB,gBAAgB,CAAC,KAAK,EAAE,CAAC;YAC3B,CAAC;YAED,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;gBACxB,oCAAoC;gBACpC,IAAI,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;oBACnD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,YAAY,gCAAgC,CAAC,CAAC;oBACpF,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,YAAa,CAAC,CAAC,CAAC;gBAC1E,CAAC;gBAED,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;gBACpC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;gBAC7D,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;gBAEpC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAC7B,MAAM,eAAe,CAAC,aAAa,EAAE,CAAC;gBACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;gBAE7D,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;gBACpC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,yCAAyC,QAAQ,IAAI,CAAC,CAAC;gBAC3E,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;YACtC,CAAC,CAAC;YAEF,MAAM,SAAS,GAAG,IAAI,qBAAS,CAAC,MAAM,CAAC,SAAU,EAAE,QAAQ,EAAE;gBAC3D,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC,cAAc;gBAC1D,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CACnB,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC,cAAc,GAAG,QAAQ,CAAC;gBACxE,aAAa,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC;aAC1D,CAAC,CAAC;YACH,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAExB,MAAM,OAAO,GAAG,GAAG,EAAE;gBACnB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;gBAC/C,SAAS,CAAC,IAAI,EAAE,CAAC;gBACjB,IAAI,gBAAgB,EAAE,CAAC;oBACrB,gBAAgB,CAAC,IAAI,EAAE,CAAC;gBAC1B,CAAC;gBACD,QAAQ,CAAC,KAAK,EAAE,CAAC;gBACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC,CAAC;YAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC9B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAE/B,qBAAqB;YACrB,OAAO,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE;gBACvC,OAAO,EAAE,6CAA6C;aACvD,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,EAAE;gBAC3D,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;aAC7E,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,OAAO,CACjB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACtD,EAAE,KAAK,EAAE,CACV,CAAC;QACJ,CAAC;IACH,CAAC;IAED,QAAQ;QACN,OAAO;;;;;;;;;iEASsD,CAAC;IAChE,CAAC;CACF;AAxGD,4CAwGC"}
1
+ {"version":3,"file":"SchedulerCommand.js","sourceRoot":"","sources":["../../src/commands/SchedulerCommand.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,11 @@ export declare const DEFAULT_CONFIG: {
18
18
  readonly cron: "0 3 * * *";
19
19
  readonly timezone: "Asia/Shanghai";
20
20
  };
21
+ readonly schedulerRuntime: {
22
+ readonly watchConfig: true;
23
+ readonly reloadDebounceMs: 500;
24
+ readonly queueLimit: 8;
25
+ };
21
26
  readonly download: {
22
27
  readonly concurrency: 3;
23
28
  readonly requestDelay: 500;
@@ -1 +1 @@
1
- {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE3C,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BjB,CAAC;AAEX;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,gBAAgB,CAwBxD"}
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE3C,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BjB,CAAC;AAEX;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,gBAAgB,CAyBxD"}
@@ -21,6 +21,11 @@ exports.DEFAULT_CONFIG = {
21
21
  cron: '0 3 * * *',
22
22
  timezone: 'Asia/Shanghai',
23
23
  },
24
+ schedulerRuntime: {
25
+ watchConfig: true,
26
+ reloadDebounceMs: 500,
27
+ queueLimit: 8,
28
+ },
24
29
  download: {
25
30
  concurrency: 3,
26
31
  requestDelay: 500,
@@ -48,6 +53,7 @@ function generateDefaultConfig() {
48
53
  network: exports.DEFAULT_CONFIG.network,
49
54
  storage: exports.DEFAULT_CONFIG.storage,
50
55
  scheduler: exports.DEFAULT_CONFIG.scheduler,
56
+ schedulerRuntime: exports.DEFAULT_CONFIG.schedulerRuntime,
51
57
  download: exports.DEFAULT_CONFIG.download,
52
58
  targets: [
53
59
  {
@@ -1 +1 @@
1
- {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAmCH,sDAwBC;AAvDY,QAAA,cAAc,GAAG;IAC5B,QAAQ,EAAE,MAAe;IACzB,OAAO,EAAE;QACP,SAAS,EAAE,KAAK;QAChB,OAAO,EAAE,CAAC;QACV,UAAU,EAAE,IAAI;KACjB;IACD,OAAO,EAAE;QACP,YAAY,EAAE,4BAA4B;QAC1C,iBAAiB,EAAE,aAAa;KACjC;IACD,SAAS,EAAE;QACT,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,WAAW;QACjB,QAAQ,EAAE,eAAe;KAC1B;IACD,QAAQ,EAAE;QACR,WAAW,EAAE,CAAC;QACd,YAAY,EAAE,GAAG;QACjB,kBAAkB,EAAE,IAAI;QACxB,cAAc,EAAE,CAAC;QACjB,UAAU,EAAE,CAAC;QACb,UAAU,EAAE,IAAI;QAChB,OAAO,EAAE,KAAK;KACf;IACD,YAAY,EAAE,CAAC;CACP,CAAC;AAEX;;GAEG;AACH,SAAgB,qBAAqB;IACnC,OAAO;QACL,QAAQ,EAAE,sBAAc,CAAC,QAAQ;QACjC,KAAK,EAAE;YACL,QAAQ,EAAE,8BAA8B;YACxC,YAAY,EAAE,0CAA0C;YACxD,WAAW,EAAE,OAAO;YACpB,YAAY,EAAE,oBAAoB;YAClC,SAAS,EAAE,+CAA+C;SAC3D;QACD,OAAO,EAAE,sBAAc,CAAC,OAAO;QAC/B,OAAO,EAAE,sBAAc,CAAC,OAAO;QAC/B,SAAS,EAAE,sBAAc,CAAC,SAAS;QACnC,QAAQ,EAAE,sBAAc,CAAC,QAAQ;QACjC,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,cAAc;gBACpB,GAAG,EAAE,MAAM;gBACX,KAAK,EAAE,EAAE;gBACT,YAAY,EAAE,wBAAwB;aACvC;SACF;QACD,YAAY,EAAE,sBAAc,CAAC,YAAY;KAC1C,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAwCH,sDAyBC;AA7DY,QAAA,cAAc,GAAG;IAC5B,QAAQ,EAAE,MAAe;IACzB,OAAO,EAAE;QACP,SAAS,EAAE,KAAK;QAChB,OAAO,EAAE,CAAC;QACV,UAAU,EAAE,IAAI;KACjB;IACD,OAAO,EAAE;QACP,YAAY,EAAE,4BAA4B;QAC1C,iBAAiB,EAAE,aAAa;KACjC;IACD,SAAS,EAAE;QACT,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,WAAW;QACjB,QAAQ,EAAE,eAAe;KAC1B;IACD,gBAAgB,EAAE;QAChB,WAAW,EAAE,IAAI;QACjB,gBAAgB,EAAE,GAAG;QACrB,UAAU,EAAE,CAAC;KACd;IACD,QAAQ,EAAE;QACR,WAAW,EAAE,CAAC;QACd,YAAY,EAAE,GAAG;QACjB,kBAAkB,EAAE,IAAI;QACxB,cAAc,EAAE,CAAC;QACjB,UAAU,EAAE,CAAC;QACb,UAAU,EAAE,IAAI;QAChB,OAAO,EAAE,KAAK;KACf;IACD,YAAY,EAAE,CAAC;CACP,CAAC;AAEX;;GAEG;AACH,SAAgB,qBAAqB;IACnC,OAAO;QACL,QAAQ,EAAE,sBAAc,CAAC,QAAQ;QACjC,KAAK,EAAE;YACL,QAAQ,EAAE,8BAA8B;YACxC,YAAY,EAAE,0CAA0C;YACxD,WAAW,EAAE,OAAO;YACpB,YAAY,EAAE,oBAAoB;YAClC,SAAS,EAAE,+CAA+C;SAC3D;QACD,OAAO,EAAE,sBAAc,CAAC,OAAO;QAC/B,OAAO,EAAE,sBAAc,CAAC,OAAO;QAC/B,SAAS,EAAE,sBAAc,CAAC,SAAS;QACnC,gBAAgB,EAAE,sBAAc,CAAC,gBAAgB;QACjD,QAAQ,EAAE,sBAAc,CAAC,QAAQ;QACjC,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,cAAc;gBACpB,GAAG,EAAE,MAAM;gBACX,KAAK,EAAE,EAAE;gBACT,YAAY,EAAE,wBAAwB;aACvC;SACF;QACD,YAAY,EAAE,sBAAc,CAAC,YAAY;KAC1C,CAAC;AACJ,CAAC"}
@@ -13,5 +13,5 @@ export declare function getConfigPath(configPath?: string): string;
13
13
  * @param configPath - Path to config file
14
14
  * @param skipValidation - If true, skip configuration validation (useful for login commands)
15
15
  */
16
- export declare function loadConfig(configPath?: string, skipValidation?: boolean): StandaloneConfig;
16
+ export declare function loadConfig(configPath?: string, skipValidation?: boolean, resolveDynamicPlaceholders?: boolean): StandaloneConfig;
17
17
  //# sourceMappingURL=loader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAO3C;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAwBzD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,cAAc,GAAE,OAAe,GAAG,gBAAgB,CAoLjG"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAO3C;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAwBzD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,UAAU,CAAC,EAAE,MAAM,EACnB,cAAc,GAAE,OAAe,EAC/B,0BAA0B,GAAE,OAAc,GACzC,gBAAgB,CAsLlB"}