@bytebrand/export-cars 1.26.30 → 1.26.32

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 (64) hide show
  1. package/README.md +12 -4
  2. package/dist/configs/autouncle.config.d.ts +14 -0
  3. package/dist/configs/autouncle.config.js +36 -3
  4. package/dist/configs/autouncle.config.js.map +1 -1
  5. package/dist/configs/meinstadt.config.d.ts +15 -0
  6. package/dist/configs/meinstadt.config.js +42 -3
  7. package/dist/configs/meinstadt.config.js.map +1 -1
  8. package/dist/constants/autouncle.contants.d.ts +1 -3
  9. package/dist/constants/autouncle.contants.js +2 -4
  10. package/dist/constants/autouncle.contants.js.map +1 -1
  11. package/dist/exporters/autouncle.exporter.d.ts +3 -2
  12. package/dist/exporters/autouncle.exporter.js +45 -27
  13. package/dist/exporters/autouncle.exporter.js.map +1 -1
  14. package/dist/exporters/meinstadt.exporter.d.ts +3 -2
  15. package/dist/exporters/meinstadt.exporter.js +40 -23
  16. package/dist/exporters/meinstadt.exporter.js.map +1 -1
  17. package/dist/formats/autouncle-json.builder.js +1 -4
  18. package/dist/formats/autouncle-json.builder.js.map +1 -1
  19. package/dist/interfaces/export-item.interface.d.ts +8 -12
  20. package/dist/interfaces/params.interface.d.ts +6 -0
  21. package/dist/services/autouncle-feed-run.d.ts +66 -0
  22. package/dist/services/autouncle-feed-run.js +135 -0
  23. package/dist/services/autouncle-feed-run.js.map +1 -0
  24. package/dist/services/images.service.d.ts +4 -0
  25. package/dist/services/images.service.js +9 -3
  26. package/dist/services/images.service.js.map +1 -1
  27. package/dist/services/meinstadt-feed-run.d.ts +81 -0
  28. package/dist/services/meinstadt-feed-run.js +166 -0
  29. package/dist/services/meinstadt-feed-run.js.map +1 -0
  30. package/dist/transformers/autouncle.transformer.d.ts +38 -22
  31. package/dist/transformers/autouncle.transformer.js +156 -144
  32. package/dist/transformers/autouncle.transformer.js.map +1 -1
  33. package/dist/transformers/meinstadt.transformer.d.ts +17 -13
  34. package/dist/transformers/meinstadt.transformer.js +88 -61
  35. package/dist/transformers/meinstadt.transformer.js.map +1 -1
  36. package/dist/tsconfig.build.tsbuildinfo +1 -1
  37. package/docs/autouncle/AUDIT.md +97 -0
  38. package/docs/autouncle/PARTNER-QUESTIONS.md +53 -0
  39. package/docs/autouncle/RUNBOOK.md +64 -0
  40. package/docs/meinestadt/AUDIT.md +146 -0
  41. package/docs/meinestadt/PARTNER-QUESTIONS.md +54 -0
  42. package/docs/meinestadt/RUNBOOK.md +64 -0
  43. package/docs/openai-ads/AUDIT.md +1 -0
  44. package/docs/openai-ads/RUNBOOK.md +19 -0
  45. package/package.json +3 -2
  46. package/src/configs/autouncle.config.ts +51 -3
  47. package/src/configs/meinstadt.config.ts +57 -2
  48. package/src/constants/autouncle.contants.ts +2 -3
  49. package/src/exporters/autouncle.exporter.ts +59 -37
  50. package/src/exporters/meinstadt.exporter.ts +53 -32
  51. package/src/formats/autouncle-json.builder.ts +2 -4
  52. package/src/interfaces/export-item.interface.ts +15 -12
  53. package/src/interfaces/params.interface.ts +10 -0
  54. package/src/services/autouncle-feed-run.ts +197 -0
  55. package/src/services/images.service.ts +15 -4
  56. package/src/services/meinstadt-feed-run.ts +240 -0
  57. package/src/transformers/autouncle.transformer.ts +217 -175
  58. package/src/transformers/meinstadt.transformer.ts +114 -68
  59. package/test/autouncle-feed-run.test.ts +256 -0
  60. package/test/autouncle-mapping.test.ts +225 -0
  61. package/test/clean-images.test.ts +26 -0
  62. package/test/fixtures/meinstadt.fixture.ts +87 -0
  63. package/test/meinstadt-feed-run.test.ts +288 -0
  64. package/test/meinstadt-mapping.test.ts +215 -0
package/README.md CHANGED
@@ -55,8 +55,11 @@ Library only. The OpenAI ExportType, transformer and version bump come with ADV-
55
55
  - Uses only the car's own Imbo photos (the loader's cleaned list), ordered deterministically:
56
56
  - the hero first: a 3/4 exterior, `ext_f_right`, else `ext_f_left`;
57
57
  - then the other exterior views, then the interior views (`IMAGES_SORT_ORDER`).
58
- - Drops `_feat_` close-ups, `conext_*`, codes unknown to `IMAGES_SORT_ORDER` (e.g. `simple_*`, `middle_console`,
59
- `ext_lr_main`) and repeated imageIdentifiers.
58
+ - `ext_lr_main` (a real side or rear-3/4 shot that most cars have) is not in the shared `IMAGES_SORT_ORDER`.
59
+ The clean profile alone accepts it through `CLEAN_EXTRA_IMAGE_SORT_ORDER`, after the other exterior views
60
+ and before the interior. It is never the hero. Other feeds still rank it 100.
61
+ - Drops `_feat_` close-ups, `conext_*`, codes neither order knows (e.g. `simple_*`, `middle_console`,
62
+ `int_spec_touch_screen`, `zoomedIn`) and repeated imageIdentifiers.
60
63
  - Returns `[]` when there is no 3/4 exterior shot: the car is skipped. A placeholder is never added.
61
64
  - Every URL is the explicit JPEG `https://images.auto.de/carimage/{carId}/{imageId}/large-cached.jpeg`. The
62
65
  extension-less `.../large` returns WebP or JPEG depending on the `Accept` header (no `Vary`), so the format
@@ -105,6 +108,8 @@ Library only. The OpenAI ExportType, transformer and version bump come with ADV-
105
108
  - `services/content-wordpress/wp/robots.txt` disallows `/search/` for `*`. OpenAI crawlers obey robots.txt,
106
109
  so a dedicated `OAI-AdsBot` group allows `/search/vehicle/` and repeats the `*` Disallow rules (a bot with
107
110
  its own group ignores `*`). Keep both groups in sync.
111
+ - The group is in `deploy_develop`, so it reaches the dev WordPress with the next content-wordpress deploy.
112
+ Prod is a separate decision: it is not rolled out to prod until that decision is made.
108
113
  - OAI-SearchBot stays under `*`.
109
114
  - Cloudflare: the custom rule "Allow Search Bots" (`cf.client.bot`, skip) runs before "captcha for search"
110
115
  (js_challenge on `www.auto.de/search`). A CF-verified OAI-AdsBot should pass. Unverified clients outside
@@ -130,8 +135,11 @@ Library only. The OpenAI ExportType, transformer and version bump come with ADV-
130
135
  expires. Mitigations:
131
136
  - send a full catalog upload on every image or description change (ADV-335);
132
137
  - re-validate on every run.
133
- - `ext_lr_main` (a real side or rear-3/4 exterior shot, present on most cars) is unknown to `IMAGES_SORT_ORDER`,
134
- so the clean profile drops it.
138
+ - An image that has dropped out of the cleaned Imbo list can still answer 200 from the image cache. The profile is
139
+ built from the current list, so such a car is skipped rather than shown with its old photo. Seen on 12.10:
140
+ car `3b92e5c7…`'s `ext_f_right` had left the list while its old URL still returned 200.
141
+ - robots.txt `OAI-AdsBot` group: on dev with the next content-wordpress deploy; prod rollout needs a separate
142
+ decision.
135
143
  - The CDP is a client-side SPA with no SSR (fe-main nginx serves `index.html` for `/search*`). A crawler that
136
144
  doesn't run JS sees an empty page, which is a risk for the OAI-AdsBot landing-page review.
137
145
  - Pre-existing: the `DEFAULT_IMAGES` placeholders (`carimage/noimage/...`) answer 404, yet default-type partner
@@ -1,5 +1,19 @@
1
1
  import { Params } from '../interfaces/params.interface';
2
+ import { FeedGuardOptions } from '../services/feed-guard';
2
3
  import { Config } from './config';
4
+ export declare const AUTOUNCLE_DEFAULTS: {
5
+ imageConcurrency: number;
6
+ minSourceItems: number;
7
+ minPublishedItems: number;
8
+ maxDropPercent: number;
9
+ maxSourceAgeHours: number;
10
+ maxStaleHours: number;
11
+ };
3
12
  export declare class AutouncleConfig extends Config {
13
+ dryRun: boolean;
14
+ imageConcurrency: number;
15
+ maxImages: number;
16
+ stateDir: string;
17
+ feedGuard: FeedGuardOptions;
4
18
  constructor(params: Params);
5
19
  }
@@ -1,13 +1,46 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AutouncleConfig = void 0;
3
+ exports.AutouncleConfig = exports.AUTOUNCLE_DEFAULTS = void 0;
4
+ const lodash_1 = require("lodash");
4
5
  const enums_1 = require("../enums");
5
6
  const config_1 = require("./config");
7
+ const text = (value) => (typeof value === 'string' ? value.trim() : '');
8
+ const positiveNumber = (value, fallback) => {
9
+ const parsed = (0, lodash_1.toNumber)(text(value));
10
+ return text(value) && Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
11
+ };
12
+ exports.AUTOUNCLE_DEFAULTS = {
13
+ imageConcurrency: 16,
14
+ minSourceItems: 1000,
15
+ minPublishedItems: 1,
16
+ maxDropPercent: 20,
17
+ maxSourceAgeHours: 26,
18
+ maxStaleHours: 48,
19
+ };
6
20
  class AutouncleConfig extends config_1.Config {
21
+ dryRun;
22
+ imageConcurrency;
23
+ maxImages;
24
+ stateDir;
25
+ feedGuard;
7
26
  constructor(params) {
8
27
  super(params);
9
- this.pathesConfig.localConvertedDirectory = `resources/${enums_1.ExportType.AUTOUNCLE}-export`;
10
- this.imageType = enums_1.ImageType.default;
28
+ this.dryRun = text(params.autouncleDryRun).toLowerCase() !== 'false';
29
+ const mode = this.dryRun ? 'dryrun' : 'export';
30
+ this.pathesConfig.localConvertedDirectory = `resources/${enums_1.ExportType.AUTOUNCLE}-${mode}`;
31
+ this.stateDir = `resources/${enums_1.ExportType.AUTOUNCLE}-state/${mode}`;
32
+ this.imageType = enums_1.ImageType.clean;
33
+ this.imageConcurrency = positiveNumber(params.autouncleImageConcurrency, exports.AUTOUNCLE_DEFAULTS.imageConcurrency);
34
+ this.maxImages = Math.floor(positiveNumber(params.autouncleMaxImages, 0));
35
+ this.feedGuard = {
36
+ stateDir: this.stateDir,
37
+ minSourceItems: positiveNumber(params.feedGuardMinSourceItems, exports.AUTOUNCLE_DEFAULTS.minSourceItems),
38
+ minPublishedItems: positiveNumber(params.feedGuardMinPublishedItems, exports.AUTOUNCLE_DEFAULTS.minPublishedItems),
39
+ maxDropPercent: positiveNumber(params.feedGuardMaxDropPercent, exports.AUTOUNCLE_DEFAULTS.maxDropPercent),
40
+ maxSourceAgeHours: positiveNumber(params.feedGuardMaxSourceAgeHours, exports.AUTOUNCLE_DEFAULTS.maxSourceAgeHours),
41
+ maxStaleHours: positiveNumber(params.feedGuardMaxStaleHours, exports.AUTOUNCLE_DEFAULTS.maxStaleHours),
42
+ acceptDrop: text(params.feedGuardAcceptDrop).toLowerCase() === 'true',
43
+ };
11
44
  this.outputFiles = [
12
45
  `${this.pathesConfig.localConvertedDirectory}/api_export_cars_${enums_1.ExportType.AUTOUNCLE}.${enums_1.FileType.JSON}`,
13
46
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"autouncle.config.js","sourceRoot":"","sources":["../../src/configs/autouncle.config.ts"],"names":[],"mappings":";;;AAAA,oCAA4D;AAE5D,qCAAkC;AAElC,MAAa,eAAgB,SAAQ,eAAM;IACzC,YAAY,MAAc;QACxB,KAAK,CAAC,MAAM,CAAC,CAAC;QACd,IAAI,CAAC,YAAY,CAAC,uBAAuB,GAAG,aAAa,kBAAU,CAAC,SAAS,SAAS,CAAC;QACvF,IAAI,CAAC,SAAS,GAAG,iBAAS,CAAC,OAAO,CAAC;QACnC,IAAI,CAAC,WAAW,GAAG;YACjB,GAAG,IAAI,CAAC,YAAY,CAAC,uBAAuB,oBAAoB,kBAAU,CAAC,SAAS,IAAI,gBAAQ,CAAC,IAAI,EAAE;SACxG,CAAC;IACJ,CAAC;CACF;AATD,0CASC"}
1
+ {"version":3,"file":"autouncle.config.js","sourceRoot":"","sources":["../../src/configs/autouncle.config.ts"],"names":[],"mappings":";;;AAAA,mCAAkC;AAElC,oCAA2D;AAG3D,qCAAkC;AAElC,MAAM,IAAI,GAAG,CAAC,KAAc,EAAU,EAAE,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAEzF,MAAM,cAAc,GAAG,CAAC,KAAc,EAAE,QAAgB,EAAU,EAAE;IAClE,MAAM,MAAM,GAAG,IAAA,iBAAQ,EAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACrC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClF,CAAC,CAAC;AAIW,QAAA,kBAAkB,GAAG;IAChC,gBAAgB,EAAE,EAAE;IACpB,cAAc,EAAE,IAAI;IACpB,iBAAiB,EAAE,CAAC;IACpB,cAAc,EAAE,EAAE;IAClB,iBAAiB,EAAE,EAAE;IACrB,aAAa,EAAE,EAAE;CAClB,CAAC;AAQF,MAAa,eAAgB,SAAQ,eAAM;IACzC,MAAM,CAAU;IAChB,gBAAgB,CAAS;IAEzB,SAAS,CAAS;IAClB,QAAQ,CAAS;IACjB,SAAS,CAAmB;IAE5B,YAAY,MAAc;QACxB,KAAK,CAAC,MAAM,CAAC,CAAC;QACd,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC;QACrE,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC/C,IAAI,CAAC,YAAY,CAAC,uBAAuB,GAAG,aAAa,kBAAU,CAAC,SAAS,IAAI,IAAI,EAAE,CAAC;QACxF,IAAI,CAAC,QAAQ,GAAG,aAAa,kBAAU,CAAC,SAAS,UAAU,IAAI,EAAE,CAAC;QAClE,IAAI,CAAC,SAAS,GAAG,iBAAS,CAAC,KAAK,CAAC;QACjC,IAAI,CAAC,gBAAgB,GAAG,cAAc,CAAC,MAAM,CAAC,yBAAyB,EAAE,0BAAkB,CAAC,gBAAgB,CAAC,CAAC;QAC9G,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1E,IAAI,CAAC,SAAS,GAAG;YACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,cAAc,EAAE,cAAc,CAAC,MAAM,CAAC,uBAAuB,EAAE,0BAAkB,CAAC,cAAc,CAAC;YACjG,iBAAiB,EAAE,cAAc,CAAC,MAAM,CAAC,0BAA0B,EAAE,0BAAkB,CAAC,iBAAiB,CAAC;YAC1G,cAAc,EAAE,cAAc,CAAC,MAAM,CAAC,uBAAuB,EAAE,0BAAkB,CAAC,cAAc,CAAC;YACjG,iBAAiB,EAAE,cAAc,CAAC,MAAM,CAAC,0BAA0B,EAAE,0BAAkB,CAAC,iBAAiB,CAAC;YAC1G,aAAa,EAAE,cAAc,CAAC,MAAM,CAAC,sBAAsB,EAAE,0BAAkB,CAAC,aAAa,CAAC;YAC9F,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM;SACtE,CAAC;QACF,IAAI,CAAC,WAAW,GAAG;YACjB,GAAG,IAAI,CAAC,YAAY,CAAC,uBAAuB,oBAAoB,kBAAU,CAAC,SAAS,IAAI,gBAAQ,CAAC,IAAI,EAAE;SACxG,CAAC;IACJ,CAAC;CACF;AA9BD,0CA8BC"}
@@ -1,5 +1,20 @@
1
1
  import { Params } from '../interfaces/params.interface';
2
+ import { FeedGuardOptions } from '../services/feed-guard';
2
3
  import { Config } from './config';
4
+ export declare const parseMeinstadtCpc: (value: unknown) => string | null;
5
+ export declare const MEINSTADT_DEFAULTS: {
6
+ imageConcurrency: number;
7
+ minSourceItems: number;
8
+ minPublishedItems: number;
9
+ maxDropPercent: number;
10
+ maxSourceAgeHours: number;
11
+ maxStaleHours: number;
12
+ };
3
13
  export declare class MeinstadtConfig extends Config {
14
+ dryRun: boolean;
15
+ imageConcurrency: number;
16
+ maxImages: number;
17
+ stateDir: string;
18
+ feedGuard: FeedGuardOptions;
4
19
  constructor(params: Params);
5
20
  }
@@ -1,13 +1,52 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MeinstadtConfig = void 0;
3
+ exports.MeinstadtConfig = exports.MEINSTADT_DEFAULTS = exports.parseMeinstadtCpc = void 0;
4
+ const lodash_1 = require("lodash");
4
5
  const config_1 = require("./config");
5
6
  const enums_1 = require("../enums");
7
+ const text = (value) => (typeof value === 'string' ? value.trim() : '');
8
+ const positiveNumber = (value, fallback) => {
9
+ const parsed = (0, lodash_1.toNumber)(text(value));
10
+ return text(value) && Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
11
+ };
12
+ const parseMeinstadtCpc = (value) => {
13
+ const raw = text(value);
14
+ return /^\d+(\.\d+)?$/.test(raw) && Number(raw) > 0 ? raw : null;
15
+ };
16
+ exports.parseMeinstadtCpc = parseMeinstadtCpc;
17
+ exports.MEINSTADT_DEFAULTS = {
18
+ imageConcurrency: 16,
19
+ minSourceItems: 1000,
20
+ minPublishedItems: 500,
21
+ maxDropPercent: 20,
22
+ maxSourceAgeHours: 26,
23
+ maxStaleHours: 48,
24
+ };
6
25
  class MeinstadtConfig extends config_1.Config {
26
+ dryRun;
27
+ imageConcurrency;
28
+ maxImages;
29
+ stateDir;
30
+ feedGuard;
7
31
  constructor(params) {
8
32
  super(params);
9
- this.pathesConfig.localConvertedDirectory = `resources/${enums_1.ExportType.MEINSTADT}-export`;
10
- this.imageType = enums_1.ImageType.default;
33
+ this.dryRun = text(params.meinstadtDryRun).toLowerCase() !== 'false';
34
+ const mode = this.dryRun ? 'dryrun' : 'export';
35
+ this.pathesConfig.localConvertedDirectory = `resources/${enums_1.ExportType.MEINSTADT}-${mode}`;
36
+ this.stateDir = `resources/${enums_1.ExportType.MEINSTADT}-state/${mode}`;
37
+ this.imageType = enums_1.ImageType.clean;
38
+ this.cpc = (0, exports.parseMeinstadtCpc)(params.cpc);
39
+ this.imageConcurrency = positiveNumber(params.meinstadtImageConcurrency, exports.MEINSTADT_DEFAULTS.imageConcurrency);
40
+ this.maxImages = Math.floor(positiveNumber(params.meinstadtMaxImages, 0));
41
+ this.feedGuard = {
42
+ stateDir: this.stateDir,
43
+ minSourceItems: positiveNumber(params.feedGuardMinSourceItems, exports.MEINSTADT_DEFAULTS.minSourceItems),
44
+ minPublishedItems: positiveNumber(params.feedGuardMinPublishedItems, exports.MEINSTADT_DEFAULTS.minPublishedItems),
45
+ maxDropPercent: positiveNumber(params.feedGuardMaxDropPercent, exports.MEINSTADT_DEFAULTS.maxDropPercent),
46
+ maxSourceAgeHours: positiveNumber(params.feedGuardMaxSourceAgeHours, exports.MEINSTADT_DEFAULTS.maxSourceAgeHours),
47
+ maxStaleHours: positiveNumber(params.feedGuardMaxStaleHours, exports.MEINSTADT_DEFAULTS.maxStaleHours),
48
+ acceptDrop: text(params.feedGuardAcceptDrop).toLowerCase() === 'true',
49
+ };
11
50
  this.outputFiles = [
12
51
  `${this.pathesConfig.localConvertedDirectory}/api_export_cars_${enums_1.ExportType.MEINSTADT}.${enums_1.FileType.JSON}`,
13
52
  `${this.pathesConfig.localConvertedDirectory}/api_export_cars_${enums_1.ExportType.MEINSTADT}.${enums_1.FileType.ZIP}`,
@@ -1 +1 @@
1
- {"version":3,"file":"meinstadt.config.js","sourceRoot":"","sources":["../../src/configs/meinstadt.config.ts"],"names":[],"mappings":";;;AACA,qCAAkC;AAClC,oCAA2D;AAE3D,MAAa,eAAgB,SAAQ,eAAM;IACzC,YAAY,MAAc;QACxB,KAAK,CAAC,MAAM,CAAC,CAAC;QACd,IAAI,CAAC,YAAY,CAAC,uBAAuB,GAAG,aAAa,kBAAU,CAAC,SAAS,SAAS,CAAC;QACvF,IAAI,CAAC,SAAS,GAAG,iBAAS,CAAC,OAAO,CAAC;QACnC,IAAI,CAAC,WAAW,GAAG;YACjB,GAAG,IAAI,CAAC,YAAY,CAAC,uBAAuB,oBAAoB,kBAAU,CAAC,SAAS,IAAI,gBAAQ,CAAC,IAAI,EAAE;YACvG,GAAG,IAAI,CAAC,YAAY,CAAC,uBAAuB,oBAAoB,kBAAU,CAAC,SAAS,IAAI,gBAAQ,CAAC,GAAG,EAAE;SACvG,CAAC;IACJ,CAAC;CACF;AAVD,0CAUC"}
1
+ {"version":3,"file":"meinstadt.config.js","sourceRoot":"","sources":["../../src/configs/meinstadt.config.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,2 @@
1
1
  export declare const MIN_MILEAGES = 0;
2
- export declare const DEFAULT_ZIP = "";
3
- export declare const DEFAULT_CITY = "";
4
- export declare const DEFAULT_ADDR1 = "";
2
+ export declare const DEFAULT_REGION = "Deutschland";
@@ -1,8 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_ADDR1 = exports.DEFAULT_CITY = exports.DEFAULT_ZIP = exports.MIN_MILEAGES = void 0;
3
+ exports.DEFAULT_REGION = exports.MIN_MILEAGES = void 0;
4
4
  exports.MIN_MILEAGES = 0;
5
- exports.DEFAULT_ZIP = '';
6
- exports.DEFAULT_CITY = '';
7
- exports.DEFAULT_ADDR1 = '';
5
+ exports.DEFAULT_REGION = 'Deutschland';
8
6
  //# sourceMappingURL=autouncle.contants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"autouncle.contants.js","sourceRoot":"","sources":["../../src/constants/autouncle.contants.ts"],"names":[],"mappings":";;;AAAa,QAAA,YAAY,GAAG,CAAC,CAAC;AACjB,QAAA,WAAW,GAAG,EAAE,CAAC;AACjB,QAAA,YAAY,GAAG,EAAE,CAAC;AAClB,QAAA,aAAa,GAAG,EAAE,CAAC"}
1
+ {"version":3,"file":"autouncle.contants.js","sourceRoot":"","sources":["../../src/constants/autouncle.contants.ts"],"names":[],"mappings":";;;AAAa,QAAA,YAAY,GAAG,CAAC,CAAC;AAEjB,QAAA,cAAc,GAAG,aAAa,CAAC"}
@@ -1,12 +1,13 @@
1
1
  import { ModuleRef } from '@nestjs/core';
2
- import { CarService, RulesService, LoaderService, ConfigService } from '../services';
2
+ import { CarService, RulesService, LoaderService, ConfigService, ImagesService } from '../services';
3
3
  import { Exporter } from '../interfaces/exporter.interface';
4
4
  export declare class AutouncleExporter implements Exporter {
5
5
  private carService;
6
6
  private configService;
7
7
  private loaderService;
8
8
  private rulesService;
9
+ private imagesService;
9
10
  private moduleRef;
10
- constructor(carService: CarService, configService: ConfigService, loaderService: LoaderService, rulesService: RulesService, moduleRef: ModuleRef);
11
+ constructor(carService: CarService, configService: ConfigService, loaderService: LoaderService, rulesService: RulesService, imagesService: ImagesService, moduleRef: ModuleRef);
11
12
  export(): Promise<void>;
12
13
  }
@@ -10,53 +10,70 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.AutouncleExporter = void 0;
13
- const lodash_1 = require("lodash");
14
13
  const common_1 = require("@nestjs/common");
15
14
  const core_1 = require("@nestjs/core");
16
15
  const cronicle_helper_1 = require("@bytebrand/cronicle-helper");
17
16
  const autouncle_transformer_1 = require("../transformers/autouncle.transformer");
18
- const autouncle_json_builder_1 = require("../formats/autouncle-json.builder");
17
+ const openai_image_fields_1 = require("../transformers/openai-image-fields");
19
18
  const services_1 = require("../services");
19
+ const image_url_validator_service_1 = require("../services/image-url-validator.service");
20
+ const feed_guard_1 = require("../services/feed-guard");
21
+ const autouncle_feed_run_1 = require("../services/autouncle-feed-run");
20
22
  let AutouncleExporter = class AutouncleExporter {
21
23
  carService;
22
24
  configService;
23
25
  loaderService;
24
26
  rulesService;
27
+ imagesService;
25
28
  moduleRef;
26
- constructor(carService, configService, loaderService, rulesService, moduleRef) {
29
+ constructor(carService, configService, loaderService, rulesService, imagesService, moduleRef) {
27
30
  this.carService = carService;
28
31
  this.configService = configService;
29
32
  this.loaderService = loaderService;
30
33
  this.rulesService = rulesService;
34
+ this.imagesService = imagesService;
31
35
  this.moduleRef = moduleRef;
32
36
  }
33
37
  async export() {
34
- const [fileName] = this.configService.config.outputFiles;
35
- await cronicle_helper_1.CronicleUtils.ensureDir(this.configService.config.pathesConfig.localConvertedDirectory);
36
- await cronicle_helper_1.CronicleUtils.emptyDir(this.configService.config.pathesConfig.localConvertedDirectory);
37
- const autouncleJsonBuilder = new autouncle_json_builder_1.AutouncleJsonBuilder(fileName);
38
- await autouncleJsonBuilder.buildStart();
39
- const autouncleTransformer = await this.moduleRef.create(autouncle_transformer_1.AutouncleTransformer);
40
- let firstCar = true;
41
- await this.loaderService.process(async (chunk) => {
42
- chunk.data = chunk.data.filter(e => this.carService.filterCar(e, this.rulesService.rules));
43
- for (const data of chunk.data) {
44
- const ownerId = (0, lodash_1.get)(data.car, 'metaData.ownerId');
45
- const owner = await this.carService.getOwner(ownerId).catch((error) => { console.error(error); return null; });
46
- if (!owner) {
47
- console.log(`Skip car because owner ${ownerId} is not a dealer`);
48
- continue;
38
+ const config = this.configService.config;
39
+ const [jsonFile] = config.outputFiles;
40
+ const validator = new image_url_validator_service_1.ImageUrlValidator({ concurrency: config.imageConcurrency });
41
+ const transformer = await this.moduleRef.create(autouncle_transformer_1.AutouncleTransformer);
42
+ const addresses = new Map();
43
+ const run = new autouncle_feed_run_1.AutouncleFeedRun({
44
+ forEachChunk: fn => this.loaderService.process((chunk) => fn(chunk.data)),
45
+ filterCar: source => this.carService.filterCar(source, this.rulesService.rules),
46
+ dealerAddress: (ownerId) => {
47
+ if (!addresses.has(ownerId)) {
48
+ addresses.set(ownerId, this.carService.getOwner(ownerId)
49
+ .then(owner => (owner ? transformer.getAddress(owner) : null))
50
+ .catch((error) => { console.error(error?.message ?? error); return null; }));
49
51
  }
50
- const car = await autouncleTransformer.transform({ owner, ...data });
51
- await autouncleJsonBuilder.addItem(car, firstCar);
52
- this.carService.counter.countCar(data.images);
53
- if (firstCar) {
54
- firstCar = false;
55
- }
56
- }
52
+ return addresses.get(ownerId);
53
+ },
54
+ resolveImages: async ({ car, images }) => (0, autouncle_transformer_1.toAutouncleImages)(await (0, openai_image_fields_1.resolveOpenAiImageFields)(this.imagesService.getCleanImages(car._id, images), validator), config.maxImages),
55
+ imageStats: () => validator.stats,
56
+ translate: key => transformer.translate(key),
57
+ guard: new feed_guard_1.FeedGuard(config.feedGuard),
58
+ }, {
59
+ runId: config.runId,
60
+ dryRun: config.dryRun,
61
+ domain: config.domain,
62
+ sourceDirectory: config.pathesConfig.localDirectory,
63
+ sourceBaseFileName: config.pathesConfig.baseFileName,
64
+ jsonFile,
65
+ stateDir: config.stateDir,
57
66
  });
58
- await autouncleJsonBuilder.buildEnd();
59
- console.log(this.carService.counter.getCountedCars());
67
+ try {
68
+ const report = await run.run();
69
+ if (report.stale) {
70
+ console.log(`autouncle feed STALE: last good file ${report.lastGoodAgeHours?.toFixed(1)} h old`);
71
+ }
72
+ }
73
+ catch (error) {
74
+ cronicle_helper_1.LoggerService.exitError(`autouncle feed not published: ${error?.message ?? error}`);
75
+ process.exit(1);
76
+ }
60
77
  }
61
78
  };
62
79
  exports.AutouncleExporter = AutouncleExporter;
@@ -66,6 +83,7 @@ exports.AutouncleExporter = AutouncleExporter = __decorate([
66
83
  services_1.ConfigService,
67
84
  services_1.LoaderService,
68
85
  services_1.RulesService,
86
+ services_1.ImagesService,
69
87
  core_1.ModuleRef])
70
88
  ], AutouncleExporter);
71
89
  //# sourceMappingURL=autouncle.exporter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"autouncle.exporter.js","sourceRoot":"","sources":["../../src/exporters/autouncle.exporter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"autouncle.exporter.js","sourceRoot":"","sources":["../../src/exporters/autouncle.exporter.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,13 @@
1
1
  import { ModuleRef } from '@nestjs/core';
2
- import { CarService, RulesService, LoaderService, ConfigService } from '../services';
2
+ import { CarService, RulesService, LoaderService, ConfigService, ImagesService } from '../services';
3
3
  import { Exporter } from '../interfaces/exporter.interface';
4
4
  export declare class MeinstadtExporter implements Exporter {
5
5
  private carService;
6
6
  private configService;
7
7
  private rulesService;
8
8
  private loaderService;
9
+ private imagesService;
9
10
  private moduleRef;
10
- constructor(carService: CarService, configService: ConfigService, rulesService: RulesService, loaderService: LoaderService, moduleRef: ModuleRef);
11
+ constructor(carService: CarService, configService: ConfigService, rulesService: RulesService, loaderService: LoaderService, imagesService: ImagesService, moduleRef: ModuleRef);
11
12
  export(): Promise<void>;
12
13
  }
@@ -13,45 +13,61 @@ exports.MeinstadtExporter = void 0;
13
13
  const common_1 = require("@nestjs/common");
14
14
  const core_1 = require("@nestjs/core");
15
15
  const cronicle_helper_1 = require("@bytebrand/cronicle-helper");
16
- const zipper_1 = require("@bytebrand/zipper");
17
16
  const services_1 = require("../services");
17
+ const image_url_validator_service_1 = require("../services/image-url-validator.service");
18
+ const feed_guard_1 = require("../services/feed-guard");
19
+ const meinstadt_feed_run_1 = require("../services/meinstadt-feed-run");
18
20
  const meinstadt_transformer_1 = require("../transformers/meinstadt.transformer");
19
- const meinstadt_json_builder_1 = require("../formats/meinstadt-json.builder");
21
+ const openai_image_fields_1 = require("../transformers/openai-image-fields");
20
22
  let MeinstadtExporter = class MeinstadtExporter {
21
23
  carService;
22
24
  configService;
23
25
  rulesService;
24
26
  loaderService;
27
+ imagesService;
25
28
  moduleRef;
26
- constructor(carService, configService, rulesService, loaderService, moduleRef) {
29
+ constructor(carService, configService, rulesService, loaderService, imagesService, moduleRef) {
27
30
  this.carService = carService;
28
31
  this.configService = configService;
29
32
  this.rulesService = rulesService;
30
33
  this.loaderService = loaderService;
34
+ this.imagesService = imagesService;
31
35
  this.moduleRef = moduleRef;
32
36
  }
33
37
  async export() {
34
- const [fileJson, fileGZ] = this.configService.config.outputFiles;
35
- await cronicle_helper_1.CronicleUtils.ensureDir(this.configService.config.pathesConfig.localConvertedDirectory);
36
- await cronicle_helper_1.CronicleUtils.emptyDir(this.configService.config.pathesConfig.localConvertedDirectory);
37
- const meinstadtJsonBuilder = new meinstadt_json_builder_1.MeinstadtJsonBuilder(fileJson);
38
- await meinstadtJsonBuilder.buildStart();
39
- const meinstadtTransformer = await this.moduleRef.create(meinstadt_transformer_1.MeinstadtTransformer);
40
- let firstCar = true;
41
- await this.loaderService.process(async (chunk) => {
42
- chunk.data = chunk.data.filter(e => this.carService.filterCar(e, this.rulesService.rules));
43
- for (const data of chunk.data) {
44
- const car = await meinstadtTransformer.transform(data);
45
- await meinstadtJsonBuilder.addItem(car, firstCar);
46
- this.carService.counter.countCar(data.images);
47
- if (firstCar) {
48
- firstCar = false;
49
- }
50
- }
38
+ const config = this.configService.config;
39
+ const [jsonFile, zipFile] = config.outputFiles;
40
+ const validator = new image_url_validator_service_1.ImageUrlValidator({ concurrency: config.imageConcurrency });
41
+ const transformer = await this.moduleRef.create(meinstadt_transformer_1.MeinstadtTransformer);
42
+ const run = new meinstadt_feed_run_1.MeinstadtFeedRun({
43
+ forEachChunk: fn => this.loaderService.process((chunk) => fn(chunk.data)),
44
+ filterCar: source => this.carService.filterCar(source, this.rulesService.rules),
45
+ resolveImages: async ({ car, images }) => (0, meinstadt_transformer_1.toMeinstadtImages)(await (0, openai_image_fields_1.resolveOpenAiImageFields)(this.imagesService.getCleanImages(car._id, images), validator), config.maxImages),
46
+ imageStats: () => validator.stats,
47
+ equipment: car => transformer.getDescription(car),
48
+ zip: meinstadt_feed_run_1.zipSingleFile,
49
+ guard: new feed_guard_1.FeedGuard(config.feedGuard),
50
+ }, {
51
+ runId: config.runId,
52
+ dryRun: config.dryRun,
53
+ cpc: config.cpc,
54
+ domain: config.domain,
55
+ sourceDirectory: config.pathesConfig.localDirectory,
56
+ sourceBaseFileName: config.pathesConfig.baseFileName,
57
+ jsonFile,
58
+ zipFile,
59
+ stateDir: config.stateDir,
51
60
  });
52
- await meinstadtJsonBuilder.buildEnd();
53
- await zipper_1.Zipper.zip({ dest: fileGZ, fileList: [fileJson] });
54
- console.log(this.carService.counter.getCountedCars());
61
+ try {
62
+ const report = await run.run();
63
+ if (report.stale) {
64
+ console.log(`meinestadt feed STALE: last good file ${report.lastGoodAgeHours?.toFixed(1)} h old`);
65
+ }
66
+ }
67
+ catch (error) {
68
+ cronicle_helper_1.LoggerService.exitError(`meinestadt feed not published: ${error?.message ?? error}`);
69
+ process.exit(1);
70
+ }
55
71
  }
56
72
  };
57
73
  exports.MeinstadtExporter = MeinstadtExporter;
@@ -61,6 +77,7 @@ exports.MeinstadtExporter = MeinstadtExporter = __decorate([
61
77
  services_1.ConfigService,
62
78
  services_1.RulesService,
63
79
  services_1.LoaderService,
80
+ services_1.ImagesService,
64
81
  core_1.ModuleRef])
65
82
  ], MeinstadtExporter);
66
83
  //# sourceMappingURL=meinstadt.exporter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"meinstadt.exporter.js","sourceRoot":"","sources":["../../src/exporters/meinstadt.exporter.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,uCAAyC;AAEzC,gEAA2D;AAE3D,8CAA2C;AAE3C,0CAAqF;AACrF,iFAA6E;AAC7E,8EAAyE;AAKlE,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAElB;IACA;IACA;IACA;IACA;IALV,YACU,UAAsB,EACtB,aAA4B,EAC5B,YAA0B,EAC1B,aAA4B,EAC5B,SAAoB;QAJpB,eAAU,GAAV,UAAU,CAAY;QACtB,kBAAa,GAAb,aAAa,CAAe;QAC5B,iBAAY,GAAZ,YAAY,CAAc;QAC1B,kBAAa,GAAb,aAAa,CAAe;QAC5B,cAAS,GAAT,SAAS,CAAW;IAC3B,CAAC;IAEJ,KAAK,CAAC,MAAM;QACV,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC;QACjE,MAAM,+BAAa,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC;QAC9F,MAAM,+BAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC;QAE7F,MAAM,oBAAoB,GAAG,IAAI,6CAAoB,CAAC,QAAQ,CAAC,CAAC;QAChE,MAAM,oBAAoB,CAAC,UAAU,EAAE,CAAC;QAExC,MAAM,oBAAoB,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,4CAAoB,CAAC,CAAC;QAE/E,IAAI,QAAQ,GAAG,IAAI,CAAC;QACpB,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,KAAuB,EAAE,EAAE;YACjE,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;YAE3F,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE;gBAE7B,MAAM,GAAG,GAAG,MAAM,oBAAoB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;gBAEvD,MAAM,oBAAoB,CAAC,OAAO,CAAC,GAAwB,EAAE,QAAQ,CAAC,CAAC;gBACvE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAE9C,IAAI,QAAQ,EAAE;oBACZ,QAAQ,GAAG,KAAK,CAAC;iBAClB;aACF;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,oBAAoB,CAAC,QAAQ,EAAE,CAAC;QACtC,MAAM,eAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IACxD,CAAC;CACF,CAAA;AAxCY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;qCAGW,qBAAU;QACP,wBAAa;QACd,uBAAY;QACX,wBAAa;QACjB,gBAAS;GANnB,iBAAiB,CAwC7B"}
1
+ {"version":3,"file":"meinstadt.exporter.js","sourceRoot":"","sources":["../../src/exporters/meinstadt.exporter.ts"],"names":[],"mappings":"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"}
@@ -7,10 +7,7 @@ class AutouncleJsonBuilder extends cronicle_helper_1.XMLBuilderBase {
7
7
  await this.write('{"ads":[');
8
8
  }
9
9
  async addItem(car, firstSym) {
10
- if (firstSym) {
11
- await this.write(`${JSON.stringify(car)}`);
12
- }
13
- await this.write(`,${JSON.stringify(car)}`);
10
+ await this.write(`${firstSym ? '' : ','}${JSON.stringify(car)}`);
14
11
  }
15
12
  async buildEnd() {
16
13
  await this.write(']}');
@@ -1 +1 @@
1
- {"version":3,"file":"autouncle-json.builder.js","sourceRoot":"","sources":["../../src/formats/autouncle-json.builder.ts"],"names":[],"mappings":";;;AAAA,gEAA4D;AAG5D,MAAa,oBAAqB,SAAQ,gCAAc;IACtD,KAAK,CAAC,UAAU;QACd,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAsB,EAAE,QAAkB;QACtD,IAAI,QAAQ,EAAE;YACZ,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;SAC5C;QACD,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACvB,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;IACnB,CAAC;CACF;AAhBD,oDAgBC"}
1
+ {"version":3,"file":"autouncle-json.builder.js","sourceRoot":"","sources":["../../src/formats/autouncle-json.builder.ts"],"names":[],"mappings":";;;AAAA,gEAA4D;AAG5D,MAAa,oBAAqB,SAAQ,gCAAc;IACtD,KAAK,CAAC,UAAU;QACd,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC/B,CAAC;IAGD,KAAK,CAAC,OAAO,CAAC,GAAsB,EAAE,QAAkB;QACtD,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACvB,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;IACnB,CAAC;CACF;AAdD,oDAcC"}
@@ -66,19 +66,18 @@ export interface MeinstadtJsonItem {
66
66
  id: string;
67
67
  make: string;
68
68
  model: string;
69
- cpc: string;
69
+ cpc: string | null;
70
70
  listingUrl: string;
71
71
  title: string;
72
- accidentFree: boolean;
72
+ accidentFree: boolean | null;
73
73
  mileage: number;
74
- initialRegistration: string;
75
- offerCreationDate: string;
74
+ initialRegistration: number | null;
75
+ offerCreationDate: number | null;
76
76
  numberOfDoors: number;
77
77
  numberOfSeats: number;
78
78
  numberOfPreviousOwners: number;
79
79
  price: number;
80
- powerPS: string;
81
- powerKS: string;
80
+ power: number;
82
81
  co2Emissions: number;
83
82
  fuelConsumptionCombined: number;
84
83
  equipment: string;
@@ -87,14 +86,11 @@ export interface MeinstadtJsonItem {
87
86
  emissionClass: string;
88
87
  emissionSticker: string;
89
88
  fuelType: string;
90
- transmissionType: string;
91
- sellerType: string;
92
- usageState: string;
93
- imagesCount: number;
94
- images: string;
95
- power: number;
96
89
  'transmissionType/transmission': string;
90
+ imagesCount: number;
97
91
  'customerType/sellerType': string;
92
+ usageState: string;
93
+ images: string[];
98
94
  }
99
95
  export interface AutouncleJsonItem {
100
96
  back_link: string;
@@ -28,6 +28,12 @@ export interface Params {
28
28
  feedGuardMaxSourceAgeHours?: string;
29
29
  feedGuardMaxStaleHours?: string;
30
30
  feedGuardAcceptDrop?: string;
31
+ meinstadtDryRun?: string;
32
+ meinstadtImageConcurrency?: string;
33
+ meinstadtMaxImages?: string;
34
+ autouncleDryRun?: string;
35
+ autouncleImageConcurrency?: string;
36
+ autouncleMaxImages?: string;
31
37
  }
32
38
  export interface FeedItemsBigQueryTarget {
33
39
  project: string;