scrapme-flow 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +123 -2
- package/dashboard/dist/assets/index-D-otDb0Z.css +1 -0
- package/dashboard/dist/assets/index-F0JnDwTs.js +2 -0
- package/dashboard/dist/index.html +14 -0
- package/dist/src/commands/commands.models.d.ts +41 -0
- package/dist/src/commands/commands.models.js +2 -0
- package/dist/src/commands/commands.models.js.map +1 -0
- package/dist/src/commands/save-document.command.d.ts +9 -0
- package/dist/src/commands/save-document.command.js +33 -0
- package/dist/src/commands/save-document.command.js.map +1 -0
- package/dist/src/commands/scrape-page.command.d.ts +20 -0
- package/dist/src/commands/scrape-page.command.js +93 -0
- package/dist/src/commands/scrape-page.command.js.map +1 -0
- package/dist/src/commands/send-mail.command.d.ts +11 -0
- package/dist/src/commands/send-mail.command.js +39 -0
- package/dist/src/commands/send-mail.command.js.map +1 -0
- package/dist/src/config/config-builder.d.ts +24 -0
- package/dist/src/config/config-builder.js +131 -0
- package/dist/src/config/config-builder.js.map +1 -0
- package/dist/src/config/config-loader.d.ts +10 -0
- package/dist/src/config/config-loader.js +79 -0
- package/dist/src/config/config-loader.js.map +1 -0
- package/dist/src/config/config.models.d.ts +154 -0
- package/dist/src/config/config.models.js +2 -0
- package/dist/src/config/config.models.js.map +1 -0
- package/dist/src/config/config.schema.d.ts +75 -0
- package/dist/src/config/config.schema.js +87 -0
- package/dist/src/config/config.schema.js.map +1 -0
- package/dist/src/config/dsn-check.d.ts +5 -0
- package/dist/src/config/dsn-check.js +12 -0
- package/dist/src/config/dsn-check.js.map +1 -0
- package/dist/src/di/container.d.ts +13 -0
- package/dist/src/di/container.js +74 -0
- package/dist/src/di/container.js.map +1 -0
- package/dist/src/di/types.d.ts +30 -0
- package/dist/src/di/types.js +31 -0
- package/dist/src/di/types.js.map +1 -0
- package/dist/src/flow/command-executor.d.ts +18 -0
- package/dist/src/flow/command-executor.js +87 -0
- package/dist/src/flow/command-executor.js.map +1 -0
- package/dist/src/flow/command-resolver.d.ts +11 -0
- package/dist/src/flow/command-resolver.js +35 -0
- package/dist/src/flow/command-resolver.js.map +1 -0
- package/dist/src/flow/flow-catalog.d.ts +12 -0
- package/dist/src/flow/flow-catalog.js +31 -0
- package/dist/src/flow/flow-catalog.js.map +1 -0
- package/dist/src/flow/flow-errors.d.ts +66 -0
- package/dist/src/flow/flow-errors.js +119 -0
- package/dist/src/flow/flow-errors.js.map +1 -0
- package/dist/src/flow/flow-job-processor.d.ts +33 -0
- package/dist/src/flow/flow-job-processor.js +208 -0
- package/dist/src/flow/flow-job-processor.js.map +1 -0
- package/dist/src/flow/flow-params.d.ts +9 -0
- package/dist/src/flow/flow-params.js +52 -0
- package/dist/src/flow/flow-params.js.map +1 -0
- package/dist/src/flow/flow-runner.d.ts +36 -0
- package/dist/src/flow/flow-runner.js +209 -0
- package/dist/src/flow/flow-runner.js.map +1 -0
- package/dist/src/flow/flow-scheduler.d.ts +24 -0
- package/dist/src/flow/flow-scheduler.js +96 -0
- package/dist/src/flow/flow-scheduler.js.map +1 -0
- package/dist/src/flow/flow-validator.d.ts +29 -0
- package/dist/src/flow/flow-validator.js +141 -0
- package/dist/src/flow/flow-validator.js.map +1 -0
- package/dist/src/flow/flow.d.ts +32 -0
- package/dist/src/flow/flow.js +50 -0
- package/dist/src/flow/flow.js.map +1 -0
- package/dist/src/flow/flow.models.d.ts +288 -0
- package/dist/src/flow/flow.models.js +38 -0
- package/dist/src/flow/flow.models.js.map +1 -0
- package/dist/src/flow/retry-policy.d.ts +9 -0
- package/dist/src/flow/retry-policy.js +15 -0
- package/dist/src/flow/retry-policy.js.map +1 -0
- package/dist/src/flow/state-path.d.ts +21 -0
- package/dist/src/flow/state-path.js +37 -0
- package/dist/src/flow/state-path.js.map +1 -0
- package/dist/src/flow/step-input-builder.d.ts +15 -0
- package/dist/src/flow/step-input-builder.js +63 -0
- package/dist/src/flow/step-input-builder.js.map +1 -0
- package/dist/src/flows/scrape.flow.d.ts +6 -0
- package/dist/src/flows/scrape.flow.js +31 -0
- package/dist/src/flows/scrape.flow.js.map +1 -0
- package/dist/src/index.d.ts +60 -0
- package/dist/src/index.js +52 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/logging/logger.d.ts +17 -0
- package/dist/src/logging/logger.js +55 -0
- package/dist/src/logging/logger.js.map +1 -0
- package/dist/src/logging/logger.models.d.ts +25 -0
- package/dist/src/logging/logger.models.js +7 -0
- package/dist/src/logging/logger.models.js.map +1 -0
- package/dist/src/mail/mail.models.d.ts +15 -0
- package/dist/src/mail/mail.models.js +2 -0
- package/dist/src/mail/mail.models.js.map +1 -0
- package/dist/src/mail/smtp-mailer.d.ts +13 -0
- package/dist/src/mail/smtp-mailer.js +70 -0
- package/dist/src/mail/smtp-mailer.js.map +1 -0
- package/dist/src/mail/unconfigured-mailer.d.ts +6 -0
- package/dist/src/mail/unconfigured-mailer.js +20 -0
- package/dist/src/mail/unconfigured-mailer.js.map +1 -0
- package/dist/src/monitor/monitor-api.d.ts +18 -0
- package/dist/src/monitor/monitor-api.js +62 -0
- package/dist/src/monitor/monitor-api.js.map +1 -0
- package/dist/src/monitor/monitor-server.d.ts +33 -0
- package/dist/src/monitor/monitor-server.js +142 -0
- package/dist/src/monitor/monitor-server.js.map +1 -0
- package/dist/src/monitor/monitor.models.d.ts +27 -0
- package/dist/src/monitor/monitor.models.js +2 -0
- package/dist/src/monitor/monitor.models.js.map +1 -0
- package/dist/src/queue/pg-boss-flow-queue.d.ts +22 -0
- package/dist/src/queue/pg-boss-flow-queue.js +102 -0
- package/dist/src/queue/pg-boss-flow-queue.js.map +1 -0
- package/dist/src/queue/queue.models.d.ts +38 -0
- package/dist/src/queue/queue.models.js +2 -0
- package/dist/src/queue/queue.models.js.map +1 -0
- package/dist/src/reporting/lighty-error-reporter.d.ts +24 -0
- package/dist/src/reporting/lighty-error-reporter.js +96 -0
- package/dist/src/reporting/lighty-error-reporter.js.map +1 -0
- package/dist/src/reporting/log-error-reporter.d.ts +12 -0
- package/dist/src/reporting/log-error-reporter.js +35 -0
- package/dist/src/reporting/log-error-reporter.js.map +1 -0
- package/dist/src/reporting/reporting.models.d.ts +27 -0
- package/dist/src/reporting/reporting.models.js +2 -0
- package/dist/src/reporting/reporting.models.js.map +1 -0
- package/dist/src/scrapme.d.ts +62 -0
- package/dist/src/scrapme.js +140 -0
- package/dist/src/scrapme.js.map +1 -0
- package/dist/src/scrapme.models.d.ts +18 -0
- package/dist/src/scrapme.models.js +2 -0
- package/dist/src/scrapme.models.js.map +1 -0
- package/dist/src/storage/couch-connection.d.ts +19 -0
- package/dist/src/storage/couch-connection.js +67 -0
- package/dist/src/storage/couch-connection.js.map +1 -0
- package/dist/src/storage/couch-database.d.ts +44 -0
- package/dist/src/storage/couch-database.js +118 -0
- package/dist/src/storage/couch-database.js.map +1 -0
- package/dist/src/storage/couch-document-store.d.ts +14 -0
- package/dist/src/storage/couch-document-store.js +36 -0
- package/dist/src/storage/couch-document-store.js.map +1 -0
- package/dist/src/storage/couch-error.d.ts +12 -0
- package/dist/src/storage/couch-error.js +19 -0
- package/dist/src/storage/couch-error.js.map +1 -0
- package/dist/src/storage/couch-flow-run-store.d.ts +24 -0
- package/dist/src/storage/couch-flow-run-store.js +66 -0
- package/dist/src/storage/couch-flow-run-store.js.map +1 -0
- package/dist/src/storage/couch-run-store.d.ts +17 -0
- package/dist/src/storage/couch-run-store.js +58 -0
- package/dist/src/storage/couch-run-store.js.map +1 -0
- package/dist/src/storage/run-doc-ids.d.ts +6 -0
- package/dist/src/storage/run-doc-ids.js +9 -0
- package/dist/src/storage/run-doc-ids.js.map +1 -0
- package/dist/src/storage/storage.models.d.ts +95 -0
- package/dist/src/storage/storage.models.js +5 -0
- package/dist/src/storage/storage.models.js.map +1 -0
- package/dist/src/storage/unconfigured-document-store.d.ts +8 -0
- package/dist/src/storage/unconfigured-document-store.js +26 -0
- package/dist/src/storage/unconfigured-document-store.js.map +1 -0
- package/dist/src/util/preview.d.ts +10 -0
- package/dist/src/util/preview.js +44 -0
- package/dist/src/util/preview.js.map +1 -0
- package/dist/src/util/text.d.ts +8 -0
- package/dist/src/util/text.js +16 -0
- package/dist/src/util/text.js.map +1 -0
- package/dist/src/util/timing.d.ts +10 -0
- package/dist/src/util/timing.js +59 -0
- package/dist/src/util/timing.js.map +1 -0
- package/dist/src/util/url.d.ts +5 -0
- package/dist/src/util/url.js +11 -0
- package/dist/src/util/url.js.map +1 -0
- package/package.json +77 -4
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { LOG_LEVEL, LOG_LEVELS } from '../logging/logger.models.js';
|
|
3
|
+
import { Urls } from '../util/url.js';
|
|
4
|
+
import { DsnCheck } from './dsn-check.js';
|
|
5
|
+
/** The services given to Scrapme.create are invalid (thrown by Scrapme.create). */
|
|
6
|
+
export class ConfigError extends Error {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = 'ConfigError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/** Checks the services an app gives to Scrapme.create (zod), fills in defaults and freezes the result. */
|
|
13
|
+
export class ConfigBuilder {
|
|
14
|
+
/**
|
|
15
|
+
* CouchDB's own rule for database names (docs.couchdb.org, "PUT /{db}"). It is a rule about characters, so a
|
|
16
|
+
* regex is the clearest way to state it.
|
|
17
|
+
*/
|
|
18
|
+
static COUCH_DB_NAME = /^[a-z][a-z0-9_$()+/-]*$/;
|
|
19
|
+
static STEP_TIMEOUT_MARGIN_MS = 60_000;
|
|
20
|
+
static SMTP_PORT = 587;
|
|
21
|
+
static SMTPS_PORT = 465;
|
|
22
|
+
/** pg-boss schema names go into SQL as identifiers. */
|
|
23
|
+
static SQL_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
24
|
+
static QUEUE_PREFIX = 'scrapme_';
|
|
25
|
+
static ms = (min = 0) => z.number().int().min(min);
|
|
26
|
+
static dbName = z.string().regex(ConfigBuilder.COUCH_DB_NAME, 'CouchDB names: lowercase letters, digits and _$()+/-, starting with a letter');
|
|
27
|
+
static schema = z.strictObject({
|
|
28
|
+
logLevel: z.enum(LOG_LEVELS).default(LOG_LEVEL.INFO),
|
|
29
|
+
defaults: z
|
|
30
|
+
.strictObject({
|
|
31
|
+
retries: ConfigBuilder.ms().default(3),
|
|
32
|
+
timeoutMs: ConfigBuilder.ms(1).default(60_000),
|
|
33
|
+
retryDelayMs: ConfigBuilder.ms().default(1_000),
|
|
34
|
+
maxRetryDelayMs: ConfigBuilder.ms().default(30_000),
|
|
35
|
+
maxStoredChars: ConfigBuilder.ms(100).default(2_000),
|
|
36
|
+
})
|
|
37
|
+
.default({ retries: 3, timeoutMs: 60_000, retryDelayMs: 1_000, maxRetryDelayMs: 30_000, maxStoredChars: 2_000 })
|
|
38
|
+
.refine((d) => d.maxRetryDelayMs >= d.retryDelayMs, { message: 'maxRetryDelayMs must be >= retryDelayMs' }),
|
|
39
|
+
postgres: z.strictObject({
|
|
40
|
+
connectionString: z.string().refine((v) => URL.canParse(v), 'must be a postgres:// URL'),
|
|
41
|
+
schema: z.string().regex(ConfigBuilder.SQL_IDENTIFIER, 'letters, digits and _ only').default('scrapme'),
|
|
42
|
+
}),
|
|
43
|
+
queue: z
|
|
44
|
+
.strictObject({
|
|
45
|
+
prefix: z.string().regex(ConfigBuilder.SQL_IDENTIFIER, 'letters, digits and _ only').default(ConfigBuilder.QUEUE_PREFIX),
|
|
46
|
+
retries: ConfigBuilder.ms().default(3),
|
|
47
|
+
retryDelaySeconds: ConfigBuilder.ms().default(30),
|
|
48
|
+
retryBackoff: z.boolean().default(true),
|
|
49
|
+
timeoutSeconds: ConfigBuilder.ms(1).default(3_600),
|
|
50
|
+
concurrency: ConfigBuilder.ms(1).default(1),
|
|
51
|
+
// pg-boss: at least 0.5 s
|
|
52
|
+
pollingIntervalSeconds: z.number().min(0.5).default(2),
|
|
53
|
+
retentionDays: ConfigBuilder.ms(1).default(7),
|
|
54
|
+
shutdownTimeoutMs: ConfigBuilder.ms(0).default(30_000),
|
|
55
|
+
})
|
|
56
|
+
.default({ prefix: ConfigBuilder.QUEUE_PREFIX, retries: 3, retryDelaySeconds: 30, retryBackoff: true, timeoutSeconds: 3_600, concurrency: 1, pollingIntervalSeconds: 2, retentionDays: 7, shutdownTimeoutMs: 30_000 }),
|
|
57
|
+
monitor: z.strictObject({ port: ConfigBuilder.ms(0).max(65_535), host: z.string().default('127.0.0.1') }).optional(),
|
|
58
|
+
scrapAnything: z
|
|
59
|
+
.strictObject({
|
|
60
|
+
url: z.url(),
|
|
61
|
+
apiSecret: z.string().min(1, 'apiSecret is required (API_SECRET of scrap-anything)'),
|
|
62
|
+
requestTimeoutMs: ConfigBuilder.ms(1).default(30_000),
|
|
63
|
+
pollIntervalMs: ConfigBuilder.ms(1).default(2_000),
|
|
64
|
+
waitTimeoutMs: ConfigBuilder.ms(1).default(600_000),
|
|
65
|
+
stepTimeoutMs: ConfigBuilder.ms(1).optional(),
|
|
66
|
+
stepRetries: ConfigBuilder.ms().default(1),
|
|
67
|
+
})
|
|
68
|
+
.transform((s) => ({ ...s, url: Urls.withoutTrailingSlash(s.url), stepTimeoutMs: s.stepTimeoutMs ?? s.waitTimeoutMs + ConfigBuilder.STEP_TIMEOUT_MARGIN_MS }))
|
|
69
|
+
.refine((s) => s.stepTimeoutMs > s.waitTimeoutMs, { message: 'stepTimeoutMs must be greater than waitTimeoutMs (the step waits for the server job)' })
|
|
70
|
+
.optional(),
|
|
71
|
+
couch: z
|
|
72
|
+
.strictObject({
|
|
73
|
+
url: z.url(),
|
|
74
|
+
user: z.string(),
|
|
75
|
+
password: z.string(),
|
|
76
|
+
db: ConfigBuilder.dbName.default('scrapme'),
|
|
77
|
+
runsDb: ConfigBuilder.dbName.default('scrapme_runs'),
|
|
78
|
+
publicUrl: z.url().optional(),
|
|
79
|
+
timeoutMs: ConfigBuilder.ms(1).default(15_000),
|
|
80
|
+
retryLimit: ConfigBuilder.ms().default(2),
|
|
81
|
+
})
|
|
82
|
+
.transform((c) => ({ ...c, url: Urls.withoutTrailingSlash(c.url), publicUrl: Urls.withoutTrailingSlash(c.publicUrl ?? c.url) })),
|
|
83
|
+
mail: z
|
|
84
|
+
.strictObject({
|
|
85
|
+
host: z.string().min(1),
|
|
86
|
+
port: ConfigBuilder.ms(1).optional(),
|
|
87
|
+
secure: z.boolean().default(false),
|
|
88
|
+
user: z.string().optional(),
|
|
89
|
+
password: z.string().optional(),
|
|
90
|
+
timeoutMs: ConfigBuilder.ms(1).default(10_000),
|
|
91
|
+
from: z.string().min(1),
|
|
92
|
+
to: z.array(z.string().min(1)).default([]),
|
|
93
|
+
})
|
|
94
|
+
.transform((m) => ({ ...m, port: m.port ?? (m.secure ? ConfigBuilder.SMTPS_PORT : ConfigBuilder.SMTP_PORT), user: m.user ?? null, password: m.password ?? null }))
|
|
95
|
+
.optional(),
|
|
96
|
+
lighty: z
|
|
97
|
+
.strictObject({
|
|
98
|
+
dsn: z.string().refine((dsn) => DsnCheck.isValid(dsn), 'must look like https://<project-key>@<host>/<project>'),
|
|
99
|
+
environment: z.string().default('production'),
|
|
100
|
+
release: z.string().default('scrapme'),
|
|
101
|
+
flushTimeoutMs: ConfigBuilder.ms(1).default(5_000),
|
|
102
|
+
})
|
|
103
|
+
.optional(),
|
|
104
|
+
});
|
|
105
|
+
static build(options) {
|
|
106
|
+
const parsed = ConfigBuilder.schema.safeParse(options);
|
|
107
|
+
if (!parsed.success)
|
|
108
|
+
throw new ConfigError(`Invalid scrapme options:\n${z.prettifyError(parsed.error)}`);
|
|
109
|
+
const o = parsed.data;
|
|
110
|
+
return ConfigBuilder.deepFreeze({
|
|
111
|
+
logLevel: o.logLevel,
|
|
112
|
+
flow: o.defaults,
|
|
113
|
+
postgres: o.postgres,
|
|
114
|
+
queue: o.queue,
|
|
115
|
+
monitor: o.monitor ?? null,
|
|
116
|
+
scrapAnything: o.scrapAnything ?? null,
|
|
117
|
+
couch: o.couch,
|
|
118
|
+
mail: o.mail ?? null,
|
|
119
|
+
lighty: o.lighty ?? null,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
static deepFreeze(value) {
|
|
123
|
+
if (value && typeof value === 'object') {
|
|
124
|
+
for (const v of Object.values(value))
|
|
125
|
+
ConfigBuilder.deepFreeze(v);
|
|
126
|
+
Object.freeze(value);
|
|
127
|
+
}
|
|
128
|
+
return value;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=config-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-builder.js","sourceRoot":"","sources":["../../../src/config/config-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ScrapmeConfig } from './config.models.js';
|
|
2
|
+
export declare class ConfigError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
/** The only place that reads environment variables. Empty strings count as "not set" (default applies). */
|
|
6
|
+
export declare class ConfigLoader {
|
|
7
|
+
static load(env?: Record<string, string | undefined>): ScrapmeConfig;
|
|
8
|
+
private static toConfig;
|
|
9
|
+
private static deepFreeze;
|
|
10
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ConfigSchema } from './config.schema.js';
|
|
3
|
+
import { Urls } from '../util/url.js';
|
|
4
|
+
export class ConfigError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'ConfigError';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/** The only place that reads environment variables. Empty strings count as "not set" (default applies). */
|
|
11
|
+
export class ConfigLoader {
|
|
12
|
+
static load(env = process.env) {
|
|
13
|
+
const cleaned = {};
|
|
14
|
+
for (const key of Object.keys(ConfigSchema.env.shape)) {
|
|
15
|
+
const value = env[key];
|
|
16
|
+
if (value !== undefined && value.trim() !== '')
|
|
17
|
+
cleaned[key] = value;
|
|
18
|
+
}
|
|
19
|
+
const parsed = ConfigSchema.env.safeParse(cleaned);
|
|
20
|
+
if (!parsed.success)
|
|
21
|
+
throw new ConfigError(`Invalid scrapme configuration:\n${z.prettifyError(parsed.error)}`);
|
|
22
|
+
return ConfigLoader.deepFreeze(ConfigLoader.toConfig(parsed.data));
|
|
23
|
+
}
|
|
24
|
+
static toConfig(e) {
|
|
25
|
+
return {
|
|
26
|
+
logLevel: e.LOG_LEVEL,
|
|
27
|
+
scrapAnything: {
|
|
28
|
+
url: e.SCRAP_ANYTHING_URL,
|
|
29
|
+
secret: e.SCRAP_ANYTHING_SECRET,
|
|
30
|
+
requestTimeoutMs: e.SCRAP_ANYTHING_REQUEST_TIMEOUT_MS,
|
|
31
|
+
pollIntervalMs: e.SCRAP_ANYTHING_POLL_INTERVAL_MS,
|
|
32
|
+
waitTimeoutMs: e.SCRAP_ANYTHING_WAIT_TIMEOUT_MS,
|
|
33
|
+
},
|
|
34
|
+
scrape: { stepTimeoutMs: e.SCRAPE_STEP_TIMEOUT_MS, stepRetries: e.SCRAPE_STEP_RETRIES },
|
|
35
|
+
couch: {
|
|
36
|
+
url: Urls.withoutTrailingSlash(e.COUCHDB_URL),
|
|
37
|
+
publicUrl: Urls.withoutTrailingSlash(e.COUCHDB_PUBLIC_URL || e.COUCHDB_URL),
|
|
38
|
+
user: e.COUCHDB_USER,
|
|
39
|
+
password: e.COUCHDB_PASSWORD,
|
|
40
|
+
db: e.COUCHDB_DB,
|
|
41
|
+
runsDb: e.COUCHDB_RUNS_DB,
|
|
42
|
+
timeoutMs: e.COUCHDB_TIMEOUT_MS,
|
|
43
|
+
retryLimit: e.COUCHDB_RETRY_LIMIT,
|
|
44
|
+
},
|
|
45
|
+
smtp: {
|
|
46
|
+
host: e.SMTP_HOST,
|
|
47
|
+
port: e.SMTP_PORT,
|
|
48
|
+
secure: e.SMTP_SECURE,
|
|
49
|
+
user: e.SMTP_USER,
|
|
50
|
+
password: e.SMTP_PASSWORD,
|
|
51
|
+
timeoutMs: e.SMTP_TIMEOUT_MS,
|
|
52
|
+
},
|
|
53
|
+
mail: { from: e.MAIL_FROM, to: e.MAIL_TO, uiUrl: e.MAIL_UI_URL },
|
|
54
|
+
lighty: {
|
|
55
|
+
dsn: e.LIGHTY_DSN,
|
|
56
|
+
environment: e.LIGHTY_ENVIRONMENT,
|
|
57
|
+
release: e.LIGHTY_RELEASE,
|
|
58
|
+
flushTimeoutMs: e.LIGHTY_FLUSH_TIMEOUT_MS,
|
|
59
|
+
},
|
|
60
|
+
flow: {
|
|
61
|
+
retries: e.FLOW_RETRIES,
|
|
62
|
+
timeoutMs: e.FLOW_TIMEOUT_MS,
|
|
63
|
+
retryDelayMs: e.FLOW_RETRY_DELAY_MS,
|
|
64
|
+
maxRetryDelayMs: e.FLOW_RETRY_MAX_DELAY_MS,
|
|
65
|
+
saveRuns: e.FLOW_SAVE_RUNS,
|
|
66
|
+
maxStoredChars: e.FLOW_MAX_STORED_CHARS,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
static deepFreeze(value) {
|
|
71
|
+
if (value && typeof value === 'object') {
|
|
72
|
+
for (const v of Object.values(value))
|
|
73
|
+
ConfigLoader.deepFreeze(v);
|
|
74
|
+
Object.freeze(value);
|
|
75
|
+
}
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=config-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../../src/config/config-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import type { LogLevel } from '../logging/logger.models.js';
|
|
2
|
+
/** Postgres for the pg-boss flow queue (required). */
|
|
3
|
+
export interface PostgresOptions {
|
|
4
|
+
/** e.g. postgres://user:password@localhost:5434/scrapme */
|
|
5
|
+
connectionString: string;
|
|
6
|
+
/** pg-boss tables live in this schema. Default "scrapme". */
|
|
7
|
+
schema?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The pg-boss queues and their workers: one queue per flow (prefix + flow name), created when the flow is first
|
|
11
|
+
* scheduled. Each flow can override retries / delay / timeout (FlowConfig).
|
|
12
|
+
*/
|
|
13
|
+
export interface QueueOptions {
|
|
14
|
+
/** Queue names are prefix + flow name. Default "scrapme_". */
|
|
15
|
+
prefix?: string;
|
|
16
|
+
/** Flow attempts after the first one (each attempt runs the flow from its first step). Default 3. */
|
|
17
|
+
retries?: number;
|
|
18
|
+
/** Default 30. */
|
|
19
|
+
retryDelaySeconds?: number;
|
|
20
|
+
/** Default true. */
|
|
21
|
+
retryBackoff?: boolean;
|
|
22
|
+
/** One flow attempt may run this long (pg-boss expireInSeconds). Default 3 600. */
|
|
23
|
+
timeoutSeconds?: number;
|
|
24
|
+
/** Runs of one flow at the same time in this process. Default 1. */
|
|
25
|
+
concurrency?: number;
|
|
26
|
+
/** How often idle workers look for jobs, in seconds (min 0.5). Default 2. */
|
|
27
|
+
pollingIntervalSeconds?: number;
|
|
28
|
+
/** Finished jobs are removed from Postgres after this (the runs stay in CouchDB). Default 7. */
|
|
29
|
+
retentionDays?: number;
|
|
30
|
+
/** stop() waits this long for running flows. Default 30 000. */
|
|
31
|
+
shutdownTimeoutMs?: number;
|
|
32
|
+
}
|
|
33
|
+
/** The monitoring dashboard (Svelte UI + JSON API on /api). */
|
|
34
|
+
export interface MonitorOptions {
|
|
35
|
+
/** e.g. 3100; 0 = any free port. */
|
|
36
|
+
port: number;
|
|
37
|
+
/** Default "127.0.0.1" (only this machine); "0.0.0.0" to open it to the network. */
|
|
38
|
+
host?: string;
|
|
39
|
+
}
|
|
40
|
+
/** scrap-anything — needed by ScrapePageCommand. */
|
|
41
|
+
export interface ScrapAnythingOptions {
|
|
42
|
+
/** e.g. http://localhost:3000 */
|
|
43
|
+
url: string;
|
|
44
|
+
/** API_SECRET of scrap-anything (Bearer for POST /jobs). */
|
|
45
|
+
apiSecret: string;
|
|
46
|
+
/** One HTTP request to the API. Default 30 000. */
|
|
47
|
+
requestTimeoutMs?: number;
|
|
48
|
+
/** How often a waiting step asks for the job status. Default 2 000. */
|
|
49
|
+
pollIntervalMs?: number;
|
|
50
|
+
/** How long one ScrapePage attempt waits for its job (the server retries for up to ~7 min). Default 600 000. */
|
|
51
|
+
waitTimeoutMs?: number;
|
|
52
|
+
/** Timeout of one ScrapePage attempt; must be > waitTimeoutMs. Default waitTimeoutMs + 60 000. */
|
|
53
|
+
stepTimeoutMs?: number;
|
|
54
|
+
/** New server jobs after a failed one (the server already retried). Default 1. */
|
|
55
|
+
stepRetries?: number;
|
|
56
|
+
}
|
|
57
|
+
/** CouchDB — the run documents and the results of SaveDocumentCommand (required). */
|
|
58
|
+
export interface CouchOptions {
|
|
59
|
+
/** e.g. http://localhost:5984 */
|
|
60
|
+
url: string;
|
|
61
|
+
user: string;
|
|
62
|
+
password: string;
|
|
63
|
+
/** Database of SaveDocumentCommand. Default "scrapme". */
|
|
64
|
+
db?: string;
|
|
65
|
+
/** Database of runs and failed attempts. Default "scrapme_runs". */
|
|
66
|
+
runsDb?: string;
|
|
67
|
+
/** CouchDB as seen from a browser (Fauxton links). Default url. */
|
|
68
|
+
publicUrl?: string;
|
|
69
|
+
/** Default 15 000. */
|
|
70
|
+
timeoutMs?: number;
|
|
71
|
+
/** Default 2. */
|
|
72
|
+
retryLimit?: number;
|
|
73
|
+
}
|
|
74
|
+
/** SMTP — needed by SendMailCommand. */
|
|
75
|
+
export interface MailOptions {
|
|
76
|
+
host: string;
|
|
77
|
+
/** Default 587 with secure=false, 465 with secure=true. */
|
|
78
|
+
port?: number;
|
|
79
|
+
/** Default false. */
|
|
80
|
+
secure?: boolean;
|
|
81
|
+
user?: string;
|
|
82
|
+
password?: string;
|
|
83
|
+
/** Default 10 000. */
|
|
84
|
+
timeoutMs?: number;
|
|
85
|
+
/** e.g. "scrapme <scrapme@example.com>" */
|
|
86
|
+
from: string;
|
|
87
|
+
/** Default recipients of SendMailCommand. */
|
|
88
|
+
to?: string[];
|
|
89
|
+
}
|
|
90
|
+
/** LightyErrors (sentry-clone): a step that finally fails is reported there. */
|
|
91
|
+
export interface LightyOptions {
|
|
92
|
+
/** http(s)://<project-key>@<host>/<project> */
|
|
93
|
+
dsn: string;
|
|
94
|
+
/** Default "production". */
|
|
95
|
+
environment?: string;
|
|
96
|
+
/** Default "scrapme". */
|
|
97
|
+
release?: string;
|
|
98
|
+
/** Default 5 000. */
|
|
99
|
+
flushTimeoutMs?: number;
|
|
100
|
+
}
|
|
101
|
+
/** Defaults of every step (a step or the command itself can override them). Command retries run inside a flow attempt. */
|
|
102
|
+
export interface StepDefaults {
|
|
103
|
+
/** Attempts = retries + 1. Default 3. */
|
|
104
|
+
retries?: number;
|
|
105
|
+
/** One attempt. Default 60 000. */
|
|
106
|
+
timeoutMs?: number;
|
|
107
|
+
/** First retry delay, doubled per retry, with jitter. Default 1 000. */
|
|
108
|
+
retryDelayMs?: number;
|
|
109
|
+
/** Default 30 000. */
|
|
110
|
+
maxRetryDelayMs?: number;
|
|
111
|
+
/** Longer strings (HTML!) are cut in stored inputs/outputs. Default 2 000. */
|
|
112
|
+
maxStoredChars?: number;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Everything scrapme connects to, given by the app (scrapme reads no environment variables). `postgres` and `couch`
|
|
116
|
+
* are required: flows run on a pg-boss queue and their progress is kept in CouchDB. The rest is needed only by the
|
|
117
|
+
* commands that use it: no `scrapAnything` = ScrapePageCommand fails, no `mail` = SendMailCommand fails (both with
|
|
118
|
+
* NOT_CONFIGURED); no `lighty` = final errors are only logged.
|
|
119
|
+
*/
|
|
120
|
+
export interface ServiceOptions {
|
|
121
|
+
postgres: PostgresOptions;
|
|
122
|
+
couch: CouchOptions;
|
|
123
|
+
queue?: QueueOptions;
|
|
124
|
+
monitor?: MonitorOptions;
|
|
125
|
+
scrapAnything?: ScrapAnythingOptions;
|
|
126
|
+
mail?: MailOptions;
|
|
127
|
+
lighty?: LightyOptions;
|
|
128
|
+
defaults?: StepDefaults;
|
|
129
|
+
/** Default "info"; "silent" turns logging off. */
|
|
130
|
+
logLevel?: LogLevel;
|
|
131
|
+
}
|
|
132
|
+
export type ScrapAnythingConfig = Required<ScrapAnythingOptions>;
|
|
133
|
+
export type CouchConfig = Required<CouchOptions>;
|
|
134
|
+
export type MailConfig = Required<Omit<MailOptions, 'user' | 'password'>> & {
|
|
135
|
+
user: string | null;
|
|
136
|
+
password: string | null;
|
|
137
|
+
};
|
|
138
|
+
export type LightyConfig = Required<LightyOptions>;
|
|
139
|
+
export type StepDefaultsConfig = Required<StepDefaults>;
|
|
140
|
+
export type PostgresConfig = Required<PostgresOptions>;
|
|
141
|
+
export type QueueConfig = Required<QueueOptions>;
|
|
142
|
+
export type MonitorConfig = Required<MonitorOptions>;
|
|
143
|
+
/** Validated, frozen configuration (ConfigBuilder). A missing optional service is null. */
|
|
144
|
+
export interface ScrapmeConfig {
|
|
145
|
+
logLevel: LogLevel;
|
|
146
|
+
flow: StepDefaultsConfig;
|
|
147
|
+
postgres: PostgresConfig;
|
|
148
|
+
queue: QueueConfig;
|
|
149
|
+
monitor: MonitorConfig | null;
|
|
150
|
+
scrapAnything: ScrapAnythingConfig | null;
|
|
151
|
+
couch: CouchConfig;
|
|
152
|
+
mail: MailConfig | null;
|
|
153
|
+
lighty: LightyConfig | null;
|
|
154
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.models.js","sourceRoot":"","sources":["../../../src/config/config.models.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** The zod schema of every setting, with its default. Documented in .env.example. */
|
|
3
|
+
export declare class ConfigSchema {
|
|
4
|
+
/**
|
|
5
|
+
* CouchDB's own rule for database names (docs.couchdb.org, "PUT /{db}"). It is a rule about characters, so a
|
|
6
|
+
* regex is the clearest way to state it.
|
|
7
|
+
*/
|
|
8
|
+
private static readonly COUCH_DB_NAME;
|
|
9
|
+
private static readonly TRUE_VALUES;
|
|
10
|
+
private static readonly FALSE_VALUES;
|
|
11
|
+
private static readonly LIST_SEPARATOR;
|
|
12
|
+
private static int;
|
|
13
|
+
private static str;
|
|
14
|
+
private static bool;
|
|
15
|
+
private static couchDbName;
|
|
16
|
+
private static list;
|
|
17
|
+
static readonly env: z.ZodObject<{
|
|
18
|
+
LOG_LEVEL: z.ZodDefault<z.ZodEnum<{
|
|
19
|
+
debug: "debug";
|
|
20
|
+
info: "info";
|
|
21
|
+
warn: "warn";
|
|
22
|
+
error: "error";
|
|
23
|
+
silent: "silent";
|
|
24
|
+
}>>;
|
|
25
|
+
SCRAP_ANYTHING_URL: z.ZodDefault<z.ZodURL>;
|
|
26
|
+
SCRAP_ANYTHING_SECRET: z.ZodDefault<z.ZodString>;
|
|
27
|
+
SCRAP_ANYTHING_REQUEST_TIMEOUT_MS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
28
|
+
SCRAP_ANYTHING_POLL_INTERVAL_MS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
29
|
+
SCRAP_ANYTHING_WAIT_TIMEOUT_MS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
30
|
+
SCRAPE_STEP_TIMEOUT_MS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
31
|
+
SCRAPE_STEP_RETRIES: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
32
|
+
COUCHDB_URL: z.ZodDefault<z.ZodURL>;
|
|
33
|
+
COUCHDB_PUBLIC_URL: z.ZodDefault<z.ZodString>;
|
|
34
|
+
COUCHDB_USER: z.ZodDefault<z.ZodString>;
|
|
35
|
+
COUCHDB_PASSWORD: z.ZodDefault<z.ZodString>;
|
|
36
|
+
COUCHDB_DB: z.ZodDefault<z.ZodString>;
|
|
37
|
+
COUCHDB_RUNS_DB: z.ZodDefault<z.ZodString>;
|
|
38
|
+
COUCHDB_TIMEOUT_MS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
39
|
+
COUCHDB_RETRY_LIMIT: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
40
|
+
SMTP_HOST: z.ZodDefault<z.ZodString>;
|
|
41
|
+
SMTP_PORT: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
42
|
+
SMTP_SECURE: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
|
|
43
|
+
0: "0";
|
|
44
|
+
1: "1";
|
|
45
|
+
true: "true";
|
|
46
|
+
yes: "yes";
|
|
47
|
+
false: "false";
|
|
48
|
+
no: "no";
|
|
49
|
+
}>>, z.ZodTransform<boolean, "0" | "1" | "true" | "yes" | "false" | "no">>;
|
|
50
|
+
SMTP_USER: z.ZodDefault<z.ZodString>;
|
|
51
|
+
SMTP_PASSWORD: z.ZodDefault<z.ZodString>;
|
|
52
|
+
SMTP_TIMEOUT_MS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
53
|
+
MAIL_FROM: z.ZodDefault<z.ZodString>;
|
|
54
|
+
MAIL_TO: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<string[], string>>;
|
|
55
|
+
MAIL_UI_URL: z.ZodDefault<z.ZodString>;
|
|
56
|
+
LIGHTY_DSN: z.ZodDefault<z.ZodString>;
|
|
57
|
+
LIGHTY_ENVIRONMENT: z.ZodDefault<z.ZodString>;
|
|
58
|
+
LIGHTY_RELEASE: z.ZodDefault<z.ZodString>;
|
|
59
|
+
LIGHTY_FLUSH_TIMEOUT_MS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
60
|
+
FLOW_RETRIES: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
61
|
+
FLOW_TIMEOUT_MS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
62
|
+
FLOW_RETRY_DELAY_MS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
63
|
+
FLOW_RETRY_MAX_DELAY_MS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
64
|
+
FLOW_SAVE_RUNS: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
|
|
65
|
+
0: "0";
|
|
66
|
+
1: "1";
|
|
67
|
+
true: "true";
|
|
68
|
+
yes: "yes";
|
|
69
|
+
false: "false";
|
|
70
|
+
no: "no";
|
|
71
|
+
}>>, z.ZodTransform<boolean, "0" | "1" | "true" | "yes" | "false" | "no">>;
|
|
72
|
+
FLOW_MAX_STORED_CHARS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
73
|
+
}, z.core.$strip>;
|
|
74
|
+
}
|
|
75
|
+
export type ParsedEnv = z.infer<typeof ConfigSchema.env>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { LOG_LEVEL, LOG_LEVELS } from '../logging/logger.models.js';
|
|
3
|
+
import { DsnCheck } from './dsn-check.js';
|
|
4
|
+
/** The zod schema of every setting, with its default. Documented in .env.example. */
|
|
5
|
+
export class ConfigSchema {
|
|
6
|
+
/**
|
|
7
|
+
* CouchDB's own rule for database names (docs.couchdb.org, "PUT /{db}"). It is a rule about characters, so a
|
|
8
|
+
* regex is the clearest way to state it.
|
|
9
|
+
*/
|
|
10
|
+
static COUCH_DB_NAME = /^[a-z][a-z0-9_$()+/-]*$/;
|
|
11
|
+
static TRUE_VALUES = ['true', '1', 'yes'];
|
|
12
|
+
static FALSE_VALUES = ['false', '0', 'no'];
|
|
13
|
+
static LIST_SEPARATOR = ',';
|
|
14
|
+
static int(def, min = 0) {
|
|
15
|
+
return z.coerce.number().int().min(min).default(def);
|
|
16
|
+
}
|
|
17
|
+
static str(def) {
|
|
18
|
+
return z.string().trim().default(def);
|
|
19
|
+
}
|
|
20
|
+
static bool(def) {
|
|
21
|
+
const C = ConfigSchema;
|
|
22
|
+
return z
|
|
23
|
+
.enum([...C.TRUE_VALUES, ...C.FALSE_VALUES])
|
|
24
|
+
.default(def ? C.TRUE_VALUES[0] : C.FALSE_VALUES[0])
|
|
25
|
+
.transform((v) => C.TRUE_VALUES.includes(v));
|
|
26
|
+
}
|
|
27
|
+
static couchDbName(def) {
|
|
28
|
+
return z.string().regex(ConfigSchema.COUCH_DB_NAME, 'CouchDB names: lowercase letters, digits and _$()+/-, starting with a letter').default(def);
|
|
29
|
+
}
|
|
30
|
+
static list(def) {
|
|
31
|
+
return z
|
|
32
|
+
.string()
|
|
33
|
+
.default(def)
|
|
34
|
+
.transform((v) => v.split(ConfigSchema.LIST_SEPARATOR).map((s) => s.trim()).filter(Boolean));
|
|
35
|
+
}
|
|
36
|
+
static env = z
|
|
37
|
+
.object({
|
|
38
|
+
LOG_LEVEL: z.enum(LOG_LEVELS).default(LOG_LEVEL.INFO),
|
|
39
|
+
SCRAP_ANYTHING_URL: z.url().default('http://localhost:3000'),
|
|
40
|
+
SCRAP_ANYTHING_SECRET: ConfigSchema.str(''),
|
|
41
|
+
SCRAP_ANYTHING_REQUEST_TIMEOUT_MS: ConfigSchema.int(30_000, 1),
|
|
42
|
+
SCRAP_ANYTHING_POLL_INTERVAL_MS: ConfigSchema.int(2_000, 1),
|
|
43
|
+
SCRAP_ANYTHING_WAIT_TIMEOUT_MS: ConfigSchema.int(600_000, 1),
|
|
44
|
+
SCRAPE_STEP_TIMEOUT_MS: ConfigSchema.int(660_000, 1),
|
|
45
|
+
SCRAPE_STEP_RETRIES: ConfigSchema.int(1),
|
|
46
|
+
COUCHDB_URL: z.url().default('http://localhost:5984'),
|
|
47
|
+
COUCHDB_PUBLIC_URL: ConfigSchema.str(''),
|
|
48
|
+
COUCHDB_USER: ConfigSchema.str('admin'),
|
|
49
|
+
COUCHDB_PASSWORD: ConfigSchema.str('admin'),
|
|
50
|
+
COUCHDB_DB: ConfigSchema.couchDbName('scrapme'),
|
|
51
|
+
COUCHDB_RUNS_DB: ConfigSchema.couchDbName('scrapme_runs'),
|
|
52
|
+
COUCHDB_TIMEOUT_MS: ConfigSchema.int(15_000, 1),
|
|
53
|
+
COUCHDB_RETRY_LIMIT: ConfigSchema.int(2),
|
|
54
|
+
SMTP_HOST: ConfigSchema.str('localhost'),
|
|
55
|
+
SMTP_PORT: ConfigSchema.int(1025, 1),
|
|
56
|
+
SMTP_SECURE: ConfigSchema.bool(false),
|
|
57
|
+
SMTP_USER: ConfigSchema.str(''),
|
|
58
|
+
SMTP_PASSWORD: ConfigSchema.str(''),
|
|
59
|
+
SMTP_TIMEOUT_MS: ConfigSchema.int(10_000, 1),
|
|
60
|
+
MAIL_FROM: ConfigSchema.str('scrapme <scrapme@localhost>'),
|
|
61
|
+
MAIL_TO: ConfigSchema.list('owner@localhost'),
|
|
62
|
+
MAIL_UI_URL: ConfigSchema.str('http://localhost:8025'),
|
|
63
|
+
LIGHTY_DSN: ConfigSchema.str(''),
|
|
64
|
+
LIGHTY_ENVIRONMENT: ConfigSchema.str('development'),
|
|
65
|
+
LIGHTY_RELEASE: ConfigSchema.str('scrapme@0.1.0'),
|
|
66
|
+
LIGHTY_FLUSH_TIMEOUT_MS: ConfigSchema.int(5_000, 1),
|
|
67
|
+
FLOW_RETRIES: ConfigSchema.int(2),
|
|
68
|
+
FLOW_TIMEOUT_MS: ConfigSchema.int(60_000, 1),
|
|
69
|
+
FLOW_RETRY_DELAY_MS: ConfigSchema.int(1_000),
|
|
70
|
+
FLOW_RETRY_MAX_DELAY_MS: ConfigSchema.int(30_000),
|
|
71
|
+
FLOW_SAVE_RUNS: ConfigSchema.bool(true),
|
|
72
|
+
FLOW_MAX_STORED_CHARS: ConfigSchema.int(2_000, 100),
|
|
73
|
+
})
|
|
74
|
+
.refine((e) => e.SCRAPE_STEP_TIMEOUT_MS > e.SCRAP_ANYTHING_WAIT_TIMEOUT_MS, {
|
|
75
|
+
message: 'SCRAPE_STEP_TIMEOUT_MS must be greater than SCRAP_ANYTHING_WAIT_TIMEOUT_MS (the step waits for the server job)',
|
|
76
|
+
path: ['SCRAPE_STEP_TIMEOUT_MS'],
|
|
77
|
+
})
|
|
78
|
+
.refine((e) => e.FLOW_RETRY_MAX_DELAY_MS >= e.FLOW_RETRY_DELAY_MS, {
|
|
79
|
+
message: 'FLOW_RETRY_MAX_DELAY_MS must be >= FLOW_RETRY_DELAY_MS',
|
|
80
|
+
path: ['FLOW_RETRY_MAX_DELAY_MS'],
|
|
81
|
+
})
|
|
82
|
+
.refine((e) => !e.LIGHTY_DSN || DsnCheck.isValid(e.LIGHTY_DSN), {
|
|
83
|
+
message: 'LIGHTY_DSN must look like https://<project-key>@<host>/<project>',
|
|
84
|
+
path: ['LIGHTY_DSN'],
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=config.schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.schema.js","sourceRoot":"","sources":["../../../src/config/config.schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** LightyErrors DSN: `http(s)://<project-key>@<host>[:port]/<project>` — checked with URL, not a pattern. */
|
|
2
|
+
export class DsnCheck {
|
|
3
|
+
static PROTOCOLS = new Set(['http:', 'https:']);
|
|
4
|
+
static isValid(dsn) {
|
|
5
|
+
if (!URL.canParse(dsn))
|
|
6
|
+
return false;
|
|
7
|
+
const url = new URL(dsn);
|
|
8
|
+
const project = url.pathname.split('/').filter(Boolean);
|
|
9
|
+
return DsnCheck.PROTOCOLS.has(url.protocol) && url.username !== '' && url.password === '' && project.length > 0;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=dsn-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dsn-check.js","sourceRoot":"","sources":["../../../src/config/dsn-check.ts"],"names":[],"mappings":"AAAA,6GAA6G;AAC7G,MAAM,OAAO,QAAQ;IACX,MAAM,CAAU,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE1D,MAAM,CAAC,OAAO,CAAC,GAAW;QAC/B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACxD,OAAO,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAClH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Container } from 'inversify';
|
|
2
|
+
import type { ScrapmeConfig } from '../config/config.models.js';
|
|
3
|
+
/**
|
|
4
|
+
* Composition root of scrapme's own services (singletons). The container's parent is the app's container (when
|
|
5
|
+
* given): `autobind` resolves any `@injectable()` command class by its class, and its `@inject(...)`s find the
|
|
6
|
+
* app's services through the parent — commands need no bindings. A missing optional service (mail, scrapAnything)
|
|
7
|
+
* gets an "unconfigured" stand-in, so only the command that needs it fails (NOT_CONFIGURED). Replace a scrapme
|
|
8
|
+
* service with `scrapme.container.rebindSync(TYPES.X)` before start() (tests use this for the queue and stores).
|
|
9
|
+
*/
|
|
10
|
+
export declare class ContainerBuilder {
|
|
11
|
+
private static readonly APP;
|
|
12
|
+
static build(config: ScrapmeConfig, parent?: Container): Container;
|
|
13
|
+
}
|