scrapme-flow 0.0.0-stage → 0.2.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 (171) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +126 -2
  3. package/dist/src/commands/commands.models.d.ts +41 -0
  4. package/dist/src/commands/commands.models.js +2 -0
  5. package/dist/src/commands/commands.models.js.map +1 -0
  6. package/dist/src/commands/save-document.command.d.ts +9 -0
  7. package/dist/src/commands/save-document.command.js +33 -0
  8. package/dist/src/commands/save-document.command.js.map +1 -0
  9. package/dist/src/commands/scrape-page.command.d.ts +20 -0
  10. package/dist/src/commands/scrape-page.command.js +93 -0
  11. package/dist/src/commands/scrape-page.command.js.map +1 -0
  12. package/dist/src/commands/send-mail.command.d.ts +11 -0
  13. package/dist/src/commands/send-mail.command.js +39 -0
  14. package/dist/src/commands/send-mail.command.js.map +1 -0
  15. package/dist/src/config/config-builder.d.ts +24 -0
  16. package/dist/src/config/config-builder.js +129 -0
  17. package/dist/src/config/config-builder.js.map +1 -0
  18. package/dist/src/config/config-loader.d.ts +10 -0
  19. package/dist/src/config/config-loader.js +79 -0
  20. package/dist/src/config/config-loader.js.map +1 -0
  21. package/dist/src/config/config.models.d.ts +144 -0
  22. package/dist/src/config/config.models.js +2 -0
  23. package/dist/src/config/config.models.js.map +1 -0
  24. package/dist/src/config/config.schema.d.ts +75 -0
  25. package/dist/src/config/config.schema.js +87 -0
  26. package/dist/src/config/config.schema.js.map +1 -0
  27. package/dist/src/config/dsn-check.d.ts +5 -0
  28. package/dist/src/config/dsn-check.js +12 -0
  29. package/dist/src/config/dsn-check.js.map +1 -0
  30. package/dist/src/di/container.d.ts +13 -0
  31. package/dist/src/di/container.js +67 -0
  32. package/dist/src/di/container.js.map +1 -0
  33. package/dist/src/di/types.d.ts +27 -0
  34. package/dist/src/di/types.js +28 -0
  35. package/dist/src/di/types.js.map +1 -0
  36. package/dist/src/flow/command-executor.d.ts +18 -0
  37. package/dist/src/flow/command-executor.js +87 -0
  38. package/dist/src/flow/command-executor.js.map +1 -0
  39. package/dist/src/flow/command-resolver.d.ts +11 -0
  40. package/dist/src/flow/command-resolver.js +35 -0
  41. package/dist/src/flow/command-resolver.js.map +1 -0
  42. package/dist/src/flow/flow-catalog.d.ts +12 -0
  43. package/dist/src/flow/flow-catalog.js +31 -0
  44. package/dist/src/flow/flow-catalog.js.map +1 -0
  45. package/dist/src/flow/flow-errors.d.ts +66 -0
  46. package/dist/src/flow/flow-errors.js +119 -0
  47. package/dist/src/flow/flow-errors.js.map +1 -0
  48. package/dist/src/flow/flow-job-processor.d.ts +33 -0
  49. package/dist/src/flow/flow-job-processor.js +208 -0
  50. package/dist/src/flow/flow-job-processor.js.map +1 -0
  51. package/dist/src/flow/flow-params.d.ts +9 -0
  52. package/dist/src/flow/flow-params.js +52 -0
  53. package/dist/src/flow/flow-params.js.map +1 -0
  54. package/dist/src/flow/flow-runner.d.ts +36 -0
  55. package/dist/src/flow/flow-runner.js +209 -0
  56. package/dist/src/flow/flow-runner.js.map +1 -0
  57. package/dist/src/flow/flow-scheduler.d.ts +24 -0
  58. package/dist/src/flow/flow-scheduler.js +96 -0
  59. package/dist/src/flow/flow-scheduler.js.map +1 -0
  60. package/dist/src/flow/flow-validator.d.ts +29 -0
  61. package/dist/src/flow/flow-validator.js +141 -0
  62. package/dist/src/flow/flow-validator.js.map +1 -0
  63. package/dist/src/flow/flow.d.ts +32 -0
  64. package/dist/src/flow/flow.js +50 -0
  65. package/dist/src/flow/flow.js.map +1 -0
  66. package/dist/src/flow/flow.models.d.ts +288 -0
  67. package/dist/src/flow/flow.models.js +38 -0
  68. package/dist/src/flow/flow.models.js.map +1 -0
  69. package/dist/src/flow/retry-policy.d.ts +9 -0
  70. package/dist/src/flow/retry-policy.js +15 -0
  71. package/dist/src/flow/retry-policy.js.map +1 -0
  72. package/dist/src/flow/state-path.d.ts +21 -0
  73. package/dist/src/flow/state-path.js +37 -0
  74. package/dist/src/flow/state-path.js.map +1 -0
  75. package/dist/src/flow/step-input-builder.d.ts +15 -0
  76. package/dist/src/flow/step-input-builder.js +63 -0
  77. package/dist/src/flow/step-input-builder.js.map +1 -0
  78. package/dist/src/flows/scrape.flow.d.ts +6 -0
  79. package/dist/src/flows/scrape.flow.js +31 -0
  80. package/dist/src/flows/scrape.flow.js.map +1 -0
  81. package/dist/src/index.d.ts +57 -0
  82. package/dist/src/index.js +50 -0
  83. package/dist/src/index.js.map +1 -0
  84. package/dist/src/logging/logger.d.ts +17 -0
  85. package/dist/src/logging/logger.js +55 -0
  86. package/dist/src/logging/logger.js.map +1 -0
  87. package/dist/src/logging/logger.models.d.ts +25 -0
  88. package/dist/src/logging/logger.models.js +7 -0
  89. package/dist/src/logging/logger.models.js.map +1 -0
  90. package/dist/src/mail/mail.models.d.ts +15 -0
  91. package/dist/src/mail/mail.models.js +2 -0
  92. package/dist/src/mail/mail.models.js.map +1 -0
  93. package/dist/src/mail/smtp-mailer.d.ts +13 -0
  94. package/dist/src/mail/smtp-mailer.js +70 -0
  95. package/dist/src/mail/smtp-mailer.js.map +1 -0
  96. package/dist/src/mail/unconfigured-mailer.d.ts +6 -0
  97. package/dist/src/mail/unconfigured-mailer.js +20 -0
  98. package/dist/src/mail/unconfigured-mailer.js.map +1 -0
  99. package/dist/src/models.d.ts +11 -0
  100. package/dist/src/models.js +10 -0
  101. package/dist/src/models.js.map +1 -0
  102. package/dist/src/monitor/monitor-api.d.ts +18 -0
  103. package/dist/src/monitor/monitor-api.js +62 -0
  104. package/dist/src/monitor/monitor-api.js.map +1 -0
  105. package/dist/src/monitor/monitor-server.d.ts +33 -0
  106. package/dist/src/monitor/monitor-server.js +142 -0
  107. package/dist/src/monitor/monitor-server.js.map +1 -0
  108. package/dist/src/monitor/monitor.models.d.ts +27 -0
  109. package/dist/src/monitor/monitor.models.js +2 -0
  110. package/dist/src/monitor/monitor.models.js.map +1 -0
  111. package/dist/src/queue/pg-boss-flow-queue.d.ts +22 -0
  112. package/dist/src/queue/pg-boss-flow-queue.js +102 -0
  113. package/dist/src/queue/pg-boss-flow-queue.js.map +1 -0
  114. package/dist/src/queue/queue.models.d.ts +38 -0
  115. package/dist/src/queue/queue.models.js +2 -0
  116. package/dist/src/queue/queue.models.js.map +1 -0
  117. package/dist/src/reporting/lighty-error-reporter.d.ts +24 -0
  118. package/dist/src/reporting/lighty-error-reporter.js +96 -0
  119. package/dist/src/reporting/lighty-error-reporter.js.map +1 -0
  120. package/dist/src/reporting/log-error-reporter.d.ts +12 -0
  121. package/dist/src/reporting/log-error-reporter.js +35 -0
  122. package/dist/src/reporting/log-error-reporter.js.map +1 -0
  123. package/dist/src/reporting/reporting.models.d.ts +27 -0
  124. package/dist/src/reporting/reporting.models.js +2 -0
  125. package/dist/src/reporting/reporting.models.js.map +1 -0
  126. package/dist/src/scrapme.d.ts +61 -0
  127. package/dist/src/scrapme.js +133 -0
  128. package/dist/src/scrapme.js.map +1 -0
  129. package/dist/src/scrapme.models.d.ts +18 -0
  130. package/dist/src/scrapme.models.js +2 -0
  131. package/dist/src/scrapme.models.js.map +1 -0
  132. package/dist/src/storage/couch-connection.d.ts +19 -0
  133. package/dist/src/storage/couch-connection.js +67 -0
  134. package/dist/src/storage/couch-connection.js.map +1 -0
  135. package/dist/src/storage/couch-database.d.ts +44 -0
  136. package/dist/src/storage/couch-database.js +118 -0
  137. package/dist/src/storage/couch-database.js.map +1 -0
  138. package/dist/src/storage/couch-document-store.d.ts +14 -0
  139. package/dist/src/storage/couch-document-store.js +36 -0
  140. package/dist/src/storage/couch-document-store.js.map +1 -0
  141. package/dist/src/storage/couch-error.d.ts +12 -0
  142. package/dist/src/storage/couch-error.js +19 -0
  143. package/dist/src/storage/couch-error.js.map +1 -0
  144. package/dist/src/storage/couch-flow-run-store.d.ts +24 -0
  145. package/dist/src/storage/couch-flow-run-store.js +66 -0
  146. package/dist/src/storage/couch-flow-run-store.js.map +1 -0
  147. package/dist/src/storage/couch-run-store.d.ts +15 -0
  148. package/dist/src/storage/couch-run-store.js +52 -0
  149. package/dist/src/storage/couch-run-store.js.map +1 -0
  150. package/dist/src/storage/run-doc-ids.d.ts +9 -0
  151. package/dist/src/storage/run-doc-ids.js +15 -0
  152. package/dist/src/storage/run-doc-ids.js.map +1 -0
  153. package/dist/src/storage/storage.models.d.ts +95 -0
  154. package/dist/src/storage/storage.models.js +5 -0
  155. package/dist/src/storage/storage.models.js.map +1 -0
  156. package/dist/src/storage/unconfigured-document-store.d.ts +8 -0
  157. package/dist/src/storage/unconfigured-document-store.js +26 -0
  158. package/dist/src/storage/unconfigured-document-store.js.map +1 -0
  159. package/dist/src/util/preview.d.ts +10 -0
  160. package/dist/src/util/preview.js +44 -0
  161. package/dist/src/util/preview.js.map +1 -0
  162. package/dist/src/util/text.d.ts +8 -0
  163. package/dist/src/util/text.js +16 -0
  164. package/dist/src/util/text.js.map +1 -0
  165. package/dist/src/util/timing.d.ts +10 -0
  166. package/dist/src/util/timing.js +59 -0
  167. package/dist/src/util/timing.js.map +1 -0
  168. package/dist/src/util/url.d.ts +5 -0
  169. package/dist/src/util/url.js +11 -0
  170. package/dist/src/util/url.js.map +1 -0
  171. package/package.json +75 -4
@@ -0,0 +1,12 @@
1
+ /** A CouchDB request answered with an unexpected status. 5xx/409-on-update are worth retrying. */
2
+ export declare class CouchError extends Error {
3
+ readonly status: number;
4
+ readonly body: unknown;
5
+ private static readonly CONFLICT;
6
+ private static readonly SERVER_ERROR;
7
+ /** got's status when there was no response at all. */
8
+ private static readonly NO_RESPONSE;
9
+ private static readonly BODY_PREVIEW_CHARS;
10
+ readonly retryable: boolean;
11
+ constructor(operation: string, status: number, body: unknown);
12
+ }
@@ -0,0 +1,19 @@
1
+ /** A CouchDB request answered with an unexpected status. 5xx/409-on-update are worth retrying. */
2
+ export class CouchError extends Error {
3
+ status;
4
+ body;
5
+ static CONFLICT = 409;
6
+ static SERVER_ERROR = 500;
7
+ /** got's status when there was no response at all. */
8
+ static NO_RESPONSE = 0;
9
+ static BODY_PREVIEW_CHARS = 300;
10
+ retryable;
11
+ constructor(operation, status, body) {
12
+ super(`CouchDB ${operation} -> HTTP ${status}${body ? `: ${JSON.stringify(body).slice(0, CouchError.BODY_PREVIEW_CHARS)}` : ''}`);
13
+ this.status = status;
14
+ this.body = body;
15
+ this.name = 'CouchError';
16
+ this.retryable = status >= CouchError.SERVER_ERROR || status === CouchError.CONFLICT || status === CouchError.NO_RESPONSE;
17
+ }
18
+ }
19
+ //# sourceMappingURL=couch-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"couch-error.js","sourceRoot":"","sources":["../../../src/storage/couch-error.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,MAAM,OAAO,UAAW,SAAQ,KAAK;IAUjB;IACA;IAVV,MAAM,CAAU,QAAQ,GAAG,GAAG,CAAC;IAC/B,MAAM,CAAU,YAAY,GAAG,GAAG,CAAC;IAC3C,sDAAsD;IAC9C,MAAM,CAAU,WAAW,GAAG,CAAC,CAAC;IAChC,MAAM,CAAU,kBAAkB,GAAG,GAAG,CAAC;IACjC,SAAS,CAAU;IAEnC,YACE,SAAiB,EACD,MAAc,EACd,IAAa;QAE7B,KAAK,CAAC,WAAW,SAAS,YAAY,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAHlH,WAAM,GAAN,MAAM,CAAQ;QACd,SAAI,GAAJ,IAAI,CAAS;QAG7B,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,MAAM,IAAI,UAAU,CAAC,YAAY,IAAI,MAAM,KAAK,UAAU,CAAC,QAAQ,IAAI,MAAM,KAAK,UAAU,CAAC,WAAW,CAAC;IAC5H,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { ScrapmeConfig } from '../config/config.models.js';
2
+ import type { Logger } from '../logging/logger.js';
3
+ import type { CouchDatabases, FlowErrorDoc, FlowRunDoc, FlowRunStore } from './storage.models.js';
4
+ /**
5
+ * Runs and errors in COUCHDB_RUNS_DB. Storage problems are logged, never thrown: a CouchDB outage must not
6
+ * fail a flow that is otherwise fine (the error still goes to LightyErrors and the log).
7
+ */
8
+ export declare class CouchFlowRunStore implements FlowRunStore {
9
+ private readonly config;
10
+ private readonly couch;
11
+ private readonly logger;
12
+ constructor(config: ScrapmeConfig, couch: CouchDatabases, logger: Logger);
13
+ runStarted(doc: FlowRunDoc): Promise<void>;
14
+ runFinished(doc: FlowRunDoc): Promise<void>;
15
+ attemptFailed(doc: FlowErrorDoc): Promise<void>;
16
+ private db;
17
+ private safely;
18
+ }
19
+ /** FLOW_SAVE_RUNS=false. */
20
+ export declare class NoopFlowRunStore implements FlowRunStore {
21
+ runStarted(): Promise<void>;
22
+ runFinished(): Promise<void>;
23
+ attemptFailed(): Promise<void>;
24
+ }
@@ -0,0 +1,66 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
8
+ return function (target, key) { decorator(target, key, paramIndex); }
9
+ };
10
+ import { inject, injectable } from 'inversify';
11
+ import { TYPES } from '../di/types.js';
12
+ /**
13
+ * Runs and errors in COUCHDB_RUNS_DB. Storage problems are logged, never thrown: a CouchDB outage must not
14
+ * fail a flow that is otherwise fine (the error still goes to LightyErrors and the log).
15
+ */
16
+ let CouchFlowRunStore = class CouchFlowRunStore {
17
+ config;
18
+ couch;
19
+ logger;
20
+ constructor(config, couch, logger) {
21
+ this.config = config;
22
+ this.couch = couch;
23
+ this.logger = logger.child({ component: 'run-store' });
24
+ }
25
+ async runStarted(doc) {
26
+ await this.safely('save run', doc._id, () => this.db().upsert(doc));
27
+ }
28
+ async runFinished(doc) {
29
+ await this.safely('save run', doc._id, async () => {
30
+ await this.db().upsert(doc);
31
+ this.logger.info('run stored', { runId: doc.runId, status: doc.status, url: this.db().docUrl(doc._id) });
32
+ });
33
+ }
34
+ async attemptFailed(doc) {
35
+ await this.safely('save error', doc._id, () => this.db().create(doc));
36
+ }
37
+ db() {
38
+ return this.couch.database(this.config.couch.runsDb);
39
+ }
40
+ async safely(what, id, work) {
41
+ try {
42
+ await work();
43
+ }
44
+ catch (error) {
45
+ this.logger.warn(`could not ${what} in CouchDB (the flow goes on)`, { id, db: this.config.couch.runsDb, error });
46
+ }
47
+ }
48
+ };
49
+ CouchFlowRunStore = __decorate([
50
+ injectable(),
51
+ __param(0, inject(TYPES.Config)),
52
+ __param(1, inject(TYPES.CouchConnection)),
53
+ __param(2, inject(TYPES.Logger))
54
+ ], CouchFlowRunStore);
55
+ export { CouchFlowRunStore };
56
+ /** FLOW_SAVE_RUNS=false. */
57
+ let NoopFlowRunStore = class NoopFlowRunStore {
58
+ async runStarted() { }
59
+ async runFinished() { }
60
+ async attemptFailed() { }
61
+ };
62
+ NoopFlowRunStore = __decorate([
63
+ injectable()
64
+ ], NoopFlowRunStore);
65
+ export { NoopFlowRunStore };
66
+ //# sourceMappingURL=couch-flow-run-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"couch-flow-run-store.js","sourceRoot":"","sources":["../../../src/storage/couch-flow-run-store.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAIvC;;;GAGG;AAEI,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAIa;IACS;IAJjC,MAAM,CAAS;IAEhC,YACyC,MAAqB,EACZ,KAAqB,EAC/C,MAAc;QAFG,WAAM,GAAN,MAAM,CAAe;QACZ,UAAK,GAAL,KAAK,CAAgB;QAGrE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;IACzD,CAAC;IAEM,KAAK,CAAC,UAAU,CAAC,GAAe;QACrC,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACtE,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,GAAe;QACtC,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;YAChD,MAAM,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3G,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,aAAa,CAAC,GAAiB;QAC1C,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACxE,CAAC;IAEO,EAAE;QACR,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACvD,CAAC;IAEO,KAAK,CAAC,MAAM,CAAC,IAAY,EAAE,EAAU,EAAE,IAA4B;QACzE,IAAI,CAAC;YACH,MAAM,IAAI,EAAE,CAAC;QACf,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,IAAI,gCAAgC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACnH,CAAC;IACH,CAAC;CACF,CAAA;AArCY,iBAAiB;IAD7B,UAAU,EAAE;IAKR,WAAA,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IACpB,WAAA,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAA;IAC7B,WAAA,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;GANZ,iBAAiB,CAqC7B;;AAED,4BAA4B;AAErB,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IACpB,KAAK,CAAC,UAAU,KAAmB,CAAC;IACpC,KAAK,CAAC,WAAW,KAAmB,CAAC;IACrC,KAAK,CAAC,aAAa,KAAmB,CAAC;CAC/C,CAAA;AAJY,gBAAgB;IAD5B,UAAU,EAAE;GACA,gBAAgB,CAI5B"}
@@ -0,0 +1,15 @@
1
+ import type { CouchConfig } from '../config/config.models.js';
2
+ import type { CouchDatabases, FlowRunDoc, RunStore } from './storage.models.js';
3
+ /** RunStore in couch.runsDb: one `run:<id>` document per run. Errors are thrown. */
4
+ export declare class CouchRunStore implements RunStore {
5
+ private readonly config;
6
+ private readonly couch;
7
+ constructor(config: CouchConfig, couch: CouchDatabases);
8
+ create(doc: FlowRunDoc): Promise<void>;
9
+ /** null also for a document in another format (written by an older scrapme). */
10
+ get(runId: string): Promise<FlowRunDoc | null>;
11
+ update(runId: string, change: (doc: FlowRunDoc) => void): Promise<FlowRunDoc>;
12
+ /** Newest first; documents in another format (written by an older scrapme) are skipped. */
13
+ list(limit: number): Promise<FlowRunDoc[]>;
14
+ private db;
15
+ }
@@ -0,0 +1,52 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
8
+ return function (target, key) { decorator(target, key, paramIndex); }
9
+ };
10
+ import { inject, injectable } from 'inversify';
11
+ import { TYPES } from '../di/types.js';
12
+ import { RunDocIds } from './run-doc-ids.js';
13
+ /** RunStore in couch.runsDb: one `run:<id>` document per run. Errors are thrown. */
14
+ let CouchRunStore = class CouchRunStore {
15
+ config;
16
+ couch;
17
+ constructor(config, couch) {
18
+ this.config = config;
19
+ this.couch = couch;
20
+ }
21
+ async create(doc) {
22
+ await this.db().upsert(doc);
23
+ }
24
+ /** null also for a document in another format (written by an older scrapme). */
25
+ async get(runId) {
26
+ const doc = await this.db().get(RunDocIds.run(runId));
27
+ return RunDocIds.isRunDoc(doc) ? doc : null;
28
+ }
29
+ async update(runId, change) {
30
+ const updated = await this.db().update(RunDocIds.run(runId), (doc) => {
31
+ change(doc);
32
+ doc.updatedAt = new Date().toISOString();
33
+ });
34
+ if (!updated)
35
+ throw new Error(`run ${runId} not found in ${this.config.runsDb}`);
36
+ return updated;
37
+ }
38
+ /** Newest first; documents in another format (written by an older scrapme) are skipped. */
39
+ async list(limit) {
40
+ return (await this.db().byPrefix(RunDocIds.RUN_PREFIX, limit, true)).filter((d) => RunDocIds.isRunDoc(d));
41
+ }
42
+ db() {
43
+ return this.couch.database(this.config.runsDb);
44
+ }
45
+ };
46
+ CouchRunStore = __decorate([
47
+ injectable(),
48
+ __param(0, inject(TYPES.CouchConfig)),
49
+ __param(1, inject(TYPES.CouchConnection))
50
+ ], CouchRunStore);
51
+ export { CouchRunStore };
52
+ //# sourceMappingURL=couch-run-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"couch-run-store.js","sourceRoot":"","sources":["../../../src/storage/couch-run-store.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG7C,oFAAoF;AAE7E,IAAM,aAAa,GAAnB,MAAM,aAAa;IAEsB;IACI;IAFlD,YAC8C,MAAmB,EACf,KAAqB;QADzB,WAAM,GAAN,MAAM,CAAa;QACf,UAAK,GAAL,KAAK,CAAgB;IACpE,CAAC;IAEG,KAAK,CAAC,MAAM,CAAC,GAAe;QACjC,MAAM,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAED,gFAAgF;IACzE,KAAK,CAAC,GAAG,CAAC,KAAa;QAC5B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,CAAa,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QAClE,OAAO,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9C,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,MAAiC;QAClE,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAa,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE;YAC/E,MAAM,CAAC,GAAG,CAAC,CAAC;YACZ,GAAG,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC3C,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,iBAAiB,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACjF,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,2FAA2F;IACpF,KAAK,CAAC,IAAI,CAAC,KAAa;QAC7B,OAAO,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAa,SAAS,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACxH,CAAC;IAGO,EAAE;QACR,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC;CACF,CAAA;AAlCY,aAAa;IADzB,UAAU,EAAE;IAGR,WAAA,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IACzB,WAAA,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAA;GAHrB,aAAa,CAkCzB"}
@@ -0,0 +1,9 @@
1
+ import { type FlowRunDoc } from './storage.models.js';
2
+ /** Ids of the run documents in couch.runsDb. Run ids are UUIDv7 and sort by creation time, so do the run docs. */
3
+ export declare class RunDocIds {
4
+ static readonly RUN_PREFIX = "run:";
5
+ /** `run:<runId>` */
6
+ static run(runId: string): string;
7
+ /** A run document this version can read (older scrapme versions wrote run:<id> documents of another shape). */
8
+ static isRunDoc(doc: unknown): doc is FlowRunDoc;
9
+ }
@@ -0,0 +1,15 @@
1
+ import { DOC_TYPE } from './storage.models.js';
2
+ /** Ids of the run documents in couch.runsDb. Run ids are UUIDv7 and sort by creation time, so do the run docs. */
3
+ export class RunDocIds {
4
+ static RUN_PREFIX = 'run:';
5
+ /** `run:<runId>` */
6
+ static run(runId) {
7
+ return RunDocIds.RUN_PREFIX + runId;
8
+ }
9
+ /** A run document this version can read (older scrapme versions wrote run:<id> documents of another shape). */
10
+ static isRunDoc(doc) {
11
+ const d = doc;
12
+ return !!d && d.type === DOC_TYPE.FLOW_RUN && typeof d.runId === 'string' && Array.isArray(d.steps) && Array.isArray(d.flowAttempts) && d.steps.every((s) => Array.isArray(s?.attempts));
13
+ }
14
+ }
15
+ //# sourceMappingURL=run-doc-ids.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-doc-ids.js","sourceRoot":"","sources":["../../../src/storage/run-doc-ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAmB,MAAM,qBAAqB,CAAC;AAEhE,kHAAkH;AAClH,MAAM,OAAO,SAAS;IACb,MAAM,CAAU,UAAU,GAAG,MAAM,CAAC;IAE3C,oBAAoB;IACb,MAAM,CAAC,GAAG,CAAC,KAAa;QAC7B,OAAO,SAAS,CAAC,UAAU,GAAG,KAAK,CAAC;IACtC,CAAC;IAED,+GAA+G;IACxG,MAAM,CAAC,QAAQ,CAAC,GAAY;QACjC,MAAM,CAAC,GAAG,GAAiC,CAAC;QAC5C,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC3L,CAAC"}
@@ -0,0 +1,95 @@
1
+ import type { FlowAttemptReport, RunStatus, SerializedError, StepReport } from '../flow/flow.models.js';
2
+ /** `type` of the documents in couch.runsDb. */
3
+ export declare const DOC_TYPE: {
4
+ readonly FLOW_RUN: "flow-run";
5
+ };
6
+ export type DocType = (typeof DOC_TYPE)[keyof typeof DOC_TYPE];
7
+ export interface CouchDoc {
8
+ _id: string;
9
+ _rev?: string;
10
+ [key: string]: unknown;
11
+ }
12
+ export interface SavedDocument {
13
+ db: string;
14
+ id: string;
15
+ rev: string;
16
+ /** true = new document, false = a new revision of an existing one. */
17
+ created: boolean;
18
+ /** Fauxton (CouchDB web UI) link. */
19
+ url: string;
20
+ }
21
+ /** Results of flows (SaveDocumentCommand). Upserts whole documents. */
22
+ export interface DocumentStore {
23
+ save(id: string, document: Record<string, unknown>, options?: {
24
+ db?: string;
25
+ }): Promise<SavedDocument>;
26
+ get<T extends object>(id: string, options?: {
27
+ db?: string;
28
+ }): Promise<(T & CouchDoc) | null>;
29
+ }
30
+ /**
31
+ * One document per run in couch.runsDb: `run:<runId>`. Written when the run is scheduled and after every change
32
+ * (flow attempt started / ended, step started / succeeded / failed) — the monitor reads it.
33
+ */
34
+ export interface FlowRunDoc extends CouchDoc {
35
+ type: typeof DOC_TYPE.FLOW_RUN;
36
+ runId: string;
37
+ flow: string;
38
+ status: RunStatus;
39
+ tags: Record<string, string>;
40
+ /** The run input (params with defaults). */
41
+ input: Record<string, unknown>;
42
+ /** The steps of the current (last) flow attempt; `attempts` keeps the attempts of every flow attempt. */
43
+ steps: StepReport[];
44
+ /** Key of the step running now (or that failed last). */
45
+ currentStep: string | null;
46
+ flowAttempts: FlowAttemptReport[];
47
+ /** pg-boss: attempts = retries + 1. */
48
+ maxFlowAttempts: number;
49
+ createdAt: string;
50
+ updatedAt: string;
51
+ startedAt?: string;
52
+ finishedAt?: string;
53
+ durationMs?: number;
54
+ error?: SerializedError & {
55
+ step: string;
56
+ };
57
+ reportEventId?: string;
58
+ }
59
+ /** The run documents (CouchRunStore). Failures are thrown: a flow that can't record its progress fails its attempt. */
60
+ export interface RunStore {
61
+ create(doc: FlowRunDoc): Promise<void>;
62
+ get(runId: string): Promise<FlowRunDoc | null>;
63
+ /** Read-modify-write, retried on conflicts; returns the stored document. */
64
+ update(runId: string, change: (doc: FlowRunDoc) => void): Promise<FlowRunDoc>;
65
+ /** Newest first. */
66
+ list(limit: number): Promise<FlowRunDoc[]>;
67
+ }
68
+ /** One CouchDB database (CouchDatabase; in-memory in tests). */
69
+ export interface CouchDatabaseApi {
70
+ readonly name: string;
71
+ get<T extends CouchDoc>(id: string): Promise<T | null>;
72
+ /** Write a new document; EXISTS when the id is taken (never overwrites). */
73
+ create(doc: CouchDoc): Promise<CreateResult>;
74
+ /** Create or replace a document. */
75
+ upsert(doc: CouchDoc): Promise<{
76
+ rev: string;
77
+ created: boolean;
78
+ }>;
79
+ /** Read, change and write back, again on a conflict; null when the document doesn't exist. */
80
+ update<T extends CouchDoc>(id: string, change: (doc: T) => void): Promise<T | null>;
81
+ /** Documents whose id starts with `prefix`, in id order. */
82
+ byPrefix<T extends CouchDoc>(prefix: string, limit: number, descending?: boolean): Promise<T[]>;
83
+ /** Fauxton (web UI) link of a document. */
84
+ docUrl(id: string): string;
85
+ }
86
+ /** Hands out databases by name (CouchConnection). */
87
+ export interface CouchDatabases {
88
+ database(name: string): CouchDatabaseApi;
89
+ }
90
+ /** CouchDB answer to creating a document that may exist already. */
91
+ export declare const CREATE_RESULT: {
92
+ readonly CREATED: "created";
93
+ readonly EXISTS: "exists";
94
+ };
95
+ export type CreateResult = (typeof CREATE_RESULT)[keyof typeof CREATE_RESULT];
@@ -0,0 +1,5 @@
1
+ /** `type` of the documents in couch.runsDb. */
2
+ export const DOC_TYPE = { FLOW_RUN: 'flow-run' };
3
+ /** CouchDB answer to creating a document that may exist already. */
4
+ export const CREATE_RESULT = { CREATED: 'created', EXISTS: 'exists' };
5
+ //# sourceMappingURL=storage.models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.models.js","sourceRoot":"","sources":["../../../src/storage/storage.models.ts"],"names":[],"mappings":"AAEA,+CAA+C;AAC/C,MAAM,CAAC,MAAM,QAAQ,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAW,CAAC;AAoF1D,oEAAoE;AACpE,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAW,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { CouchDoc, DocumentStore, SavedDocument } from './storage.models.js';
2
+ /** Bound when Scrapme.create got no `couch`: SaveDocumentCommand fails at once with NOT_CONFIGURED. */
3
+ export declare class UnconfiguredDocumentStore implements DocumentStore {
4
+ private static readonly SERVICE;
5
+ private static readonly USER;
6
+ save(): Promise<SavedDocument>;
7
+ get<T extends object>(): Promise<(T & CouchDoc) | null>;
8
+ }
@@ -0,0 +1,26 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var UnconfiguredDocumentStore_1;
8
+ import { injectable } from 'inversify';
9
+ import { NotConfiguredError } from '../flow/flow-errors.js';
10
+ /** Bound when Scrapme.create got no `couch`: SaveDocumentCommand fails at once with NOT_CONFIGURED. */
11
+ let UnconfiguredDocumentStore = class UnconfiguredDocumentStore {
12
+ static { UnconfiguredDocumentStore_1 = this; }
13
+ static SERVICE = 'couch';
14
+ static USER = 'SaveDocumentCommand';
15
+ async save() {
16
+ throw new NotConfiguredError(UnconfiguredDocumentStore_1.SERVICE, UnconfiguredDocumentStore_1.USER);
17
+ }
18
+ async get() {
19
+ throw new NotConfiguredError(UnconfiguredDocumentStore_1.SERVICE, UnconfiguredDocumentStore_1.USER);
20
+ }
21
+ };
22
+ UnconfiguredDocumentStore = UnconfiguredDocumentStore_1 = __decorate([
23
+ injectable()
24
+ ], UnconfiguredDocumentStore);
25
+ export { UnconfiguredDocumentStore };
26
+ //# sourceMappingURL=unconfigured-document-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unconfigured-document-store.js","sourceRoot":"","sources":["../../../src/storage/unconfigured-document-store.ts"],"names":[],"mappings":";;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAG5D,uGAAuG;AAEhG,IAAM,yBAAyB,GAA/B,MAAM,yBAAyB;;IAC5B,MAAM,CAAU,OAAO,GAAG,OAAO,CAAC;IAClC,MAAM,CAAU,IAAI,GAAG,qBAAqB,CAAC;IAE9C,KAAK,CAAC,IAAI;QACf,MAAM,IAAI,kBAAkB,CAAC,2BAAyB,CAAC,OAAO,EAAE,2BAAyB,CAAC,IAAI,CAAC,CAAC;IAClG,CAAC;IAEM,KAAK,CAAC,GAAG;QACd,MAAM,IAAI,kBAAkB,CAAC,2BAAyB,CAAC,OAAO,EAAE,2BAAyB,CAAC,IAAI,CAAC,CAAC;IAClG,CAAC;;AAVU,yBAAyB;IADrC,UAAU,EAAE;GACA,yBAAyB,CAWrC"}
@@ -0,0 +1,10 @@
1
+ /** Values that are safe and small enough to store with a run. */
2
+ export declare class Preview {
3
+ private static readonly MAX_DEPTH;
4
+ private static readonly MAX_ITEMS;
5
+ /**
6
+ * A copy of a value that is safe and small enough to store with a run: long strings (HTML!) are cut, deep or
7
+ * huge structures are summarised, functions/symbols dropped, Dates as ISO strings.
8
+ */
9
+ static of(value: unknown, maxChars: number, depth?: number): unknown;
10
+ }
@@ -0,0 +1,44 @@
1
+ /** Values that are safe and small enough to store with a run. */
2
+ export class Preview {
3
+ static MAX_DEPTH = 6;
4
+ static MAX_ITEMS = 50;
5
+ /**
6
+ * A copy of a value that is safe and small enough to store with a run: long strings (HTML!) are cut, deep or
7
+ * huge structures are summarised, functions/symbols dropped, Dates as ISO strings.
8
+ */
9
+ static of(value, maxChars, depth = 0) {
10
+ if (value === null || value === undefined)
11
+ return value ?? null;
12
+ if (typeof value === 'string')
13
+ return value.length > maxChars ? `${value.slice(0, maxChars)}… (+${value.length - maxChars} chars)` : value;
14
+ if (typeof value === 'number' || typeof value === 'boolean')
15
+ return value;
16
+ if (typeof value === 'bigint')
17
+ return value.toString();
18
+ if (typeof value === 'function' || typeof value === 'symbol')
19
+ return undefined;
20
+ if (value instanceof Date)
21
+ return value.toISOString();
22
+ if (value instanceof Error)
23
+ return { name: value.name, message: value.message };
24
+ if (value instanceof Uint8Array)
25
+ return `<${value.byteLength} bytes>`;
26
+ if (depth >= Preview.MAX_DEPTH)
27
+ return Array.isArray(value) ? `[${value.length} items]` : '{…}';
28
+ if (Array.isArray(value)) {
29
+ const items = value.slice(0, Preview.MAX_ITEMS).map((v) => Preview.of(v, maxChars, depth + 1));
30
+ return value.length > Preview.MAX_ITEMS ? [...items, `… (+${value.length - Preview.MAX_ITEMS} items)`] : items;
31
+ }
32
+ const out = {};
33
+ const entries = Object.entries(value);
34
+ for (const [k, v] of entries.slice(0, Preview.MAX_ITEMS)) {
35
+ const p = Preview.of(v, maxChars, depth + 1);
36
+ if (p !== undefined)
37
+ out[k] = p;
38
+ }
39
+ if (entries.length > Preview.MAX_ITEMS)
40
+ out['…'] = `+${entries.length - Preview.MAX_ITEMS} keys`;
41
+ return out;
42
+ }
43
+ }
44
+ //# sourceMappingURL=preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.js","sourceRoot":"","sources":["../../../src/util/preview.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,OAAO,OAAO;IACV,MAAM,CAAU,SAAS,GAAG,CAAC,CAAC;IAC9B,MAAM,CAAU,SAAS,GAAG,EAAE,CAAC;IAEvC;;;OAGG;IACI,MAAM,CAAC,EAAE,CAAC,KAAc,EAAE,QAAgB,EAAE,KAAK,GAAG,CAAC;QAC1D,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,IAAI,IAAI,CAAC;QAChE,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,KAAK,CAAC,MAAM,GAAG,QAAQ,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;QAC3I,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QAC1E,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;QACvD,IAAI,OAAO,KAAK,KAAK,UAAU,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QAC/E,IAAI,KAAK,YAAY,IAAI;YAAE,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC;QACtD,IAAI,KAAK,YAAY,KAAK;YAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QAChF,IAAI,KAAK,YAAY,UAAU;YAAE,OAAO,IAAI,KAAK,CAAC,UAAU,SAAS,CAAC;QACtE,IAAI,KAAK,IAAI,OAAO,CAAC,SAAS;YAAE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;QAChG,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;YAC/F,OAAO,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,OAAO,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QACjH,CAAC;QACD,MAAM,GAAG,GAA4B,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,CAAC;QACjE,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACzD,MAAM,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YAC7C,IAAI,CAAC,KAAK,SAAS;gBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS;YAAE,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS,OAAO,CAAC;QACjG,OAAO,GAAG,CAAC;IACb,CAAC"}
@@ -0,0 +1,8 @@
1
+ /** Text helpers. */
2
+ export declare class Text {
3
+ /**
4
+ * Every run of whitespace (spaces, tabs, new lines, no-break spaces…) → one space, trimmed.
5
+ * " Przychody ze\n sprzedaży " → "Przychody ze sprzedaży". `String#trim` decides what is whitespace.
6
+ */
7
+ static normalizeSpace(text: string): string;
8
+ }
@@ -0,0 +1,16 @@
1
+ /** Text helpers. */
2
+ export class Text {
3
+ /**
4
+ * Every run of whitespace (spaces, tabs, new lines, no-break spaces…) → one space, trimmed.
5
+ * " Przychody ze\n sprzedaży " → "Przychody ze sprzedaży". `String#trim` decides what is whitespace.
6
+ */
7
+ static normalizeSpace(text) {
8
+ return [...text]
9
+ .map((ch) => (ch.trim() === '' ? ' ' : ch))
10
+ .join('')
11
+ .split(' ')
12
+ .filter(Boolean)
13
+ .join(' ');
14
+ }
15
+ }
16
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../../src/util/text.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB,MAAM,OAAO,IAAI;IACf;;;OAGG;IACI,MAAM,CAAC,cAAc,CAAC,IAAY;QACvC,OAAO,CAAC,GAAG,IAAI,CAAC;aACb,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;aAC1C,IAAI,CAAC,EAAE,CAAC;aACR,KAAK,CAAC,GAAG,CAAC;aACV,MAAM,CAAC,OAAO,CAAC;aACf,IAAI,CAAC,GAAG,CAAC,CAAC;IACf,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ /** Waiting with AbortSignals. */
2
+ export declare class Timing {
3
+ /** setTimeout as a promise; rejects with the signal's reason when aborted. */
4
+ static sleep(ms: number, signal?: AbortSignal): Promise<void>;
5
+ /**
6
+ * Run `work` with its own AbortSignal that aborts after `timeoutMs` (reason = onTimeout()) or when `parent`
7
+ * aborts. Rejects at that moment even if `work` ignores the signal — a hanging command can't hang the flow.
8
+ */
9
+ static withTimeout<T>(work: (signal: AbortSignal) => Promise<T>, timeoutMs: number, onTimeout: () => Error, parent?: AbortSignal): Promise<T>;
10
+ }
@@ -0,0 +1,59 @@
1
+ /** Waiting with AbortSignals. */
2
+ export class Timing {
3
+ /** setTimeout as a promise; rejects with the signal's reason when aborted. */
4
+ static sleep(ms, signal) {
5
+ return new Promise((resolve, reject) => {
6
+ if (signal?.aborted) {
7
+ reject(signal.reason);
8
+ return;
9
+ }
10
+ const onAbort = () => {
11
+ clearTimeout(timer);
12
+ reject(signal?.reason);
13
+ };
14
+ const timer = setTimeout(() => {
15
+ signal?.removeEventListener('abort', onAbort);
16
+ resolve();
17
+ }, ms);
18
+ signal?.addEventListener('abort', onAbort, { once: true });
19
+ });
20
+ }
21
+ /**
22
+ * Run `work` with its own AbortSignal that aborts after `timeoutMs` (reason = onTimeout()) or when `parent`
23
+ * aborts. Rejects at that moment even if `work` ignores the signal — a hanging command can't hang the flow.
24
+ */
25
+ static async withTimeout(work, timeoutMs, onTimeout, parent) {
26
+ const controller = new AbortController();
27
+ let timer;
28
+ let onParentAbort;
29
+ const stopped = new Promise((_, reject) => {
30
+ timer = setTimeout(() => {
31
+ const error = onTimeout();
32
+ controller.abort(error);
33
+ reject(error);
34
+ }, timeoutMs);
35
+ if (parent) {
36
+ onParentAbort = () => {
37
+ controller.abort(parent.reason);
38
+ reject(parent.reason);
39
+ };
40
+ if (parent.aborted)
41
+ onParentAbort();
42
+ else
43
+ parent.addEventListener('abort', onParentAbort, { once: true });
44
+ }
45
+ });
46
+ stopped.catch(() => undefined); // handled by the race below; avoid an unhandled rejection after work wins
47
+ try {
48
+ const running = work(controller.signal);
49
+ running.catch(() => undefined); // a timed-out command may still reject later; nobody waits for it any more
50
+ return await Promise.race([running, stopped]);
51
+ }
52
+ finally {
53
+ clearTimeout(timer);
54
+ if (parent && onParentAbort)
55
+ parent.removeEventListener('abort', onParentAbort);
56
+ }
57
+ }
58
+ }
59
+ //# sourceMappingURL=timing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timing.js","sourceRoot":"","sources":["../../../src/util/timing.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,MAAM,OAAO,MAAM;IACjB,8EAA8E;IACvE,MAAM,CAAC,KAAK,CAAC,EAAU,EAAE,MAAoB;QAClD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;gBACpB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACtB,OAAO;YACT,CAAC;YACD,MAAM,OAAO,GAAG,GAAS,EAAE;gBACzB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACzB,CAAC,CAAC;YACF,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBAC9C,OAAO,EAAE,CAAC;YACZ,CAAC,EAAE,EAAE,CAAC,CAAC;YACP,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,KAAK,CAAC,WAAW,CAC7B,IAAyC,EACzC,SAAiB,EACjB,SAAsB,EACtB,MAAoB;QAEpB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,IAAI,KAAgD,CAAC;QACrD,IAAI,aAAuC,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;YAC/C,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBACtB,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;gBAC1B,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACxB,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC,EAAE,SAAS,CAAC,CAAC;YACd,IAAI,MAAM,EAAE,CAAC;gBACX,aAAa,GAAG,GAAG,EAAE;oBACnB,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBAChC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACxB,CAAC,CAAC;gBACF,IAAI,MAAM,CAAC,OAAO;oBAAE,aAAa,EAAE,CAAC;;oBAC/B,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACvE,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,0EAA0E;QAC1G,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YACxC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,2EAA2E;YAC3G,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAChD,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,IAAI,MAAM,IAAI,aAAa;gBAAE,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QAClF,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ /** URL helpers. */
2
+ export declare class Urls {
3
+ /** "http://couch:5984//" → "http://couch:5984" (base URLs are joined with "/" later). */
4
+ static withoutTrailingSlash(url: string): string;
5
+ }
@@ -0,0 +1,11 @@
1
+ /** URL helpers. */
2
+ export class Urls {
3
+ /** "http://couch:5984//" → "http://couch:5984" (base URLs are joined with "/" later). */
4
+ static withoutTrailingSlash(url) {
5
+ let out = url;
6
+ while (out.endsWith('/'))
7
+ out = out.slice(0, -1);
8
+ return out;
9
+ }
10
+ }
11
+ //# sourceMappingURL=url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.js","sourceRoot":"","sources":["../../../src/util/url.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,MAAM,OAAO,IAAI;IACf,yFAAyF;IAClF,MAAM,CAAC,oBAAoB,CAAC,GAAW;QAC5C,IAAI,GAAG,GAAG,GAAG,CAAC;QACd,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACjD,OAAO,GAAG,CAAC;IACb,CAAC;CACF"}