@bytebrand/export-cars 1.26.31 → 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 (56) hide show
  1. package/dist/configs/autouncle.config.d.ts +14 -0
  2. package/dist/configs/autouncle.config.js +36 -3
  3. package/dist/configs/autouncle.config.js.map +1 -1
  4. package/dist/configs/meinstadt.config.d.ts +15 -0
  5. package/dist/configs/meinstadt.config.js +42 -3
  6. package/dist/configs/meinstadt.config.js.map +1 -1
  7. package/dist/constants/autouncle.contants.d.ts +1 -3
  8. package/dist/constants/autouncle.contants.js +2 -4
  9. package/dist/constants/autouncle.contants.js.map +1 -1
  10. package/dist/exporters/autouncle.exporter.d.ts +3 -2
  11. package/dist/exporters/autouncle.exporter.js +45 -27
  12. package/dist/exporters/autouncle.exporter.js.map +1 -1
  13. package/dist/exporters/meinstadt.exporter.d.ts +3 -2
  14. package/dist/exporters/meinstadt.exporter.js +40 -23
  15. package/dist/exporters/meinstadt.exporter.js.map +1 -1
  16. package/dist/formats/autouncle-json.builder.js +1 -4
  17. package/dist/formats/autouncle-json.builder.js.map +1 -1
  18. package/dist/interfaces/export-item.interface.d.ts +8 -12
  19. package/dist/interfaces/params.interface.d.ts +6 -0
  20. package/dist/services/autouncle-feed-run.d.ts +66 -0
  21. package/dist/services/autouncle-feed-run.js +135 -0
  22. package/dist/services/autouncle-feed-run.js.map +1 -0
  23. package/dist/services/meinstadt-feed-run.d.ts +81 -0
  24. package/dist/services/meinstadt-feed-run.js +166 -0
  25. package/dist/services/meinstadt-feed-run.js.map +1 -0
  26. package/dist/transformers/autouncle.transformer.d.ts +38 -22
  27. package/dist/transformers/autouncle.transformer.js +156 -144
  28. package/dist/transformers/autouncle.transformer.js.map +1 -1
  29. package/dist/transformers/meinstadt.transformer.d.ts +17 -13
  30. package/dist/transformers/meinstadt.transformer.js +88 -61
  31. package/dist/transformers/meinstadt.transformer.js.map +1 -1
  32. package/dist/tsconfig.build.tsbuildinfo +1 -1
  33. package/docs/autouncle/AUDIT.md +97 -0
  34. package/docs/autouncle/PARTNER-QUESTIONS.md +53 -0
  35. package/docs/autouncle/RUNBOOK.md +64 -0
  36. package/docs/meinestadt/AUDIT.md +146 -0
  37. package/docs/meinestadt/PARTNER-QUESTIONS.md +54 -0
  38. package/docs/meinestadt/RUNBOOK.md +64 -0
  39. package/package.json +3 -2
  40. package/src/configs/autouncle.config.ts +51 -3
  41. package/src/configs/meinstadt.config.ts +57 -2
  42. package/src/constants/autouncle.contants.ts +2 -3
  43. package/src/exporters/autouncle.exporter.ts +59 -37
  44. package/src/exporters/meinstadt.exporter.ts +53 -32
  45. package/src/formats/autouncle-json.builder.ts +2 -4
  46. package/src/interfaces/export-item.interface.ts +15 -12
  47. package/src/interfaces/params.interface.ts +10 -0
  48. package/src/services/autouncle-feed-run.ts +197 -0
  49. package/src/services/meinstadt-feed-run.ts +240 -0
  50. package/src/transformers/autouncle.transformer.ts +217 -175
  51. package/src/transformers/meinstadt.transformer.ts +114 -68
  52. package/test/autouncle-feed-run.test.ts +256 -0
  53. package/test/autouncle-mapping.test.ts +225 -0
  54. package/test/fixtures/meinstadt.fixture.ts +87 -0
  55. package/test/meinstadt-feed-run.test.ts +288 -0
  56. package/test/meinstadt-mapping.test.ts +215 -0
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AutouncleFeedRun = void 0;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const autouncle_json_builder_1 = require("../formats/autouncle-json.builder");
7
+ const autouncle_transformer_1 = require("../transformers/autouncle.transformer");
8
+ const feed_guard_1 = require("./feed-guard");
9
+ const increment = (counter, key) => {
10
+ counter[key] = (counter[key] ?? 0) + 1;
11
+ };
12
+ class AutouncleFeedRun {
13
+ deps;
14
+ options;
15
+ constructor(deps, options) {
16
+ this.deps = deps;
17
+ this.options = options;
18
+ }
19
+ now() {
20
+ return this.options.now ? this.options.now() : new Date();
21
+ }
22
+ async run() {
23
+ const { guard } = this.deps;
24
+ const { jsonFile, runId, dryRun } = this.options;
25
+ const startedAt = this.now();
26
+ const lastGood = await guard.readLastGood();
27
+ const report = {
28
+ runId,
29
+ mode: dryRun ? 'dry-run' : 'live',
30
+ startedAt: startedAt.toISOString(),
31
+ status: 'failed',
32
+ jsonFile,
33
+ source: { files: 0, newestChunkAt: null, cars: 0 },
34
+ items: 0,
35
+ dealers: 0,
36
+ excluded: {},
37
+ imagesPerItem: { min: null, max: null, total: 0 },
38
+ images: {},
39
+ lastGood,
40
+ lastGoodAgeHours: guard.staleHours(lastGood, startedAt),
41
+ stale: guard.isStale(lastGood, startedAt),
42
+ };
43
+ await guard.acquireLock(runId ?? 'local', startedAt);
44
+ const tmpFile = `${jsonFile}.tmp`;
45
+ try {
46
+ const snapshot = await (0, feed_guard_1.inspectSourceSnapshot)(this.options.sourceDirectory, this.options.sourceBaseFileName);
47
+ report.source.files = snapshot.files;
48
+ report.source.newestChunkAt = snapshot.newestMtime?.toISOString() ?? null;
49
+ guard.checkSource(snapshot, startedAt);
50
+ await fs_1.promises.mkdir((0, path_1.dirname)(jsonFile), { recursive: true });
51
+ await fs_1.promises.rm(tmpFile, { force: true });
52
+ const builder = new autouncle_json_builder_1.AutouncleJsonBuilder(tmpFile);
53
+ await builder.buildStart();
54
+ const seen = new Set();
55
+ const dealers = new Set();
56
+ let first = true;
57
+ await this.deps.forEachChunk(async (cars) => {
58
+ for (const source of cars) {
59
+ report.source.cars += 1;
60
+ const id = String(source?.car?._id ?? '');
61
+ if (id && seen.has(id)) {
62
+ increment(report.excluded, autouncle_transformer_1.AutouncleExclusion.duplicateId);
63
+ continue;
64
+ }
65
+ seen.add(id);
66
+ if (!this.deps.filterCar(source)) {
67
+ increment(report.excluded, autouncle_transformer_1.AutouncleExclusion.filtered);
68
+ continue;
69
+ }
70
+ const excluded = (0, autouncle_transformer_1.getAutouncleExclusion)(source.car);
71
+ if (excluded) {
72
+ increment(report.excluded, excluded);
73
+ continue;
74
+ }
75
+ const ownerId = String(source.car.metaData.ownerId).trim();
76
+ const address = await this.deps.dealerAddress(ownerId);
77
+ if (!address) {
78
+ increment(report.excluded, autouncle_transformer_1.AutouncleExclusion.noDealer);
79
+ continue;
80
+ }
81
+ const images = await this.deps.resolveImages(source);
82
+ const mapped = (0, autouncle_transformer_1.mapAutouncleItem)(source.car, { domain: this.options.domain, address, images, translate: this.deps.translate });
83
+ if (mapped.ok === false) {
84
+ increment(report.excluded, mapped.reason);
85
+ continue;
86
+ }
87
+ await builder.addItem(mapped.item, first);
88
+ first = false;
89
+ dealers.add(ownerId);
90
+ this.count(report, mapped.item.images.length);
91
+ }
92
+ });
93
+ await builder.buildEnd();
94
+ report.dealers = dealers.size;
95
+ report.images = this.deps.imageStats();
96
+ const counts = { sourceItems: report.source.cars, publishedItems: report.items };
97
+ guard.checkCounts(counts, lastGood);
98
+ report.lastGood = await guard.publish(tmpFile, jsonFile, counts, this.now(), runId);
99
+ report.status = 'published';
100
+ report.lastGoodAgeHours = 0;
101
+ report.stale = false;
102
+ return report;
103
+ }
104
+ catch (error) {
105
+ if (error instanceof feed_guard_1.FeedGuardError) {
106
+ report.status = 'blocked';
107
+ report.guard = { code: error.code, message: error.message };
108
+ }
109
+ else {
110
+ report.error = error?.message ?? String(error);
111
+ }
112
+ await fs_1.promises.rename(tmpFile, `${jsonFile}.rejected`).catch(() => undefined);
113
+ throw error;
114
+ }
115
+ finally {
116
+ await this.writeReport(report);
117
+ await guard.releaseLock();
118
+ }
119
+ }
120
+ count(report, images) {
121
+ report.items += 1;
122
+ const stats = report.imagesPerItem;
123
+ stats.min = stats.min === null ? images : Math.min(stats.min, images);
124
+ stats.max = stats.max === null ? images : Math.max(stats.max, images);
125
+ stats.total += images;
126
+ }
127
+ async writeReport(report) {
128
+ report.finishedAt = this.now().toISOString();
129
+ await fs_1.promises.mkdir(this.options.stateDir, { recursive: true });
130
+ await fs_1.promises.writeFile((0, path_1.join)(this.options.stateDir, 'last-run-report.json'), JSON.stringify(report, null, 2), 'utf8');
131
+ console.log(`autouncle feed report: ${JSON.stringify(report)}`);
132
+ }
133
+ }
134
+ exports.AutouncleFeedRun = AutouncleFeedRun;
135
+ //# sourceMappingURL=autouncle-feed-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autouncle-feed-run.js","sourceRoot":"","sources":["../../src/services/autouncle-feed-run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ import { ImboImageResponseInterface } from '@bytebrand/chunkable';
2
+ import { DataSchemes } from '@bytebrand/car-schema';
3
+ import { FeedGuard, LastGood } from './feed-guard';
4
+ export interface MeinstadtSourceCar {
5
+ car: DataSchemes.Car;
6
+ images: ImboImageResponseInterface[];
7
+ }
8
+ export declare enum MeinstadtExclusion {
9
+ duplicateId = "duplicate_id",
10
+ filtered = "filtered",
11
+ noVehicleId = "no_vehicle_id",
12
+ noImage = "no_valid_image"
13
+ }
14
+ export declare class MeinstadtConfigError extends Error {
15
+ readonly code: string;
16
+ constructor(code: string, message: string);
17
+ }
18
+ export interface MeinstadtRunDeps {
19
+ forEachChunk: (fn: (cars: MeinstadtSourceCar[]) => Promise<void>) => Promise<unknown>;
20
+ filterCar: (source: MeinstadtSourceCar) => boolean;
21
+ resolveImages: (source: MeinstadtSourceCar) => Promise<string[]>;
22
+ imageStats: () => Record<string, number>;
23
+ equipment: (car: DataSchemes.Car) => Promise<string>;
24
+ zip: (jsonFile: string, zipFile: string) => Promise<void>;
25
+ guard: FeedGuard;
26
+ }
27
+ export interface MeinstadtRunOptions {
28
+ runId?: string;
29
+ dryRun: boolean;
30
+ cpc: string | null;
31
+ domain: string;
32
+ sourceDirectory: string;
33
+ sourceBaseFileName: string;
34
+ jsonFile: string;
35
+ zipFile: string;
36
+ stateDir: string;
37
+ translate?: (key: string) => string | undefined;
38
+ now?: () => Date;
39
+ }
40
+ export interface MeinstadtRunReport {
41
+ runId?: string;
42
+ mode: 'dry-run' | 'live';
43
+ startedAt: string;
44
+ finishedAt?: string;
45
+ status: 'published' | 'blocked' | 'failed';
46
+ guard?: {
47
+ code: string;
48
+ message: string;
49
+ };
50
+ error?: string;
51
+ cpc: string | null;
52
+ jsonFile: string;
53
+ zipFile: string;
54
+ source: {
55
+ files: number;
56
+ newestChunkAt: string | null;
57
+ cars: number;
58
+ };
59
+ items: number;
60
+ excluded: Record<string, number>;
61
+ accidentFree: Record<string, number>;
62
+ imagesPerItem: {
63
+ min: number | null;
64
+ max: number | null;
65
+ total: number;
66
+ };
67
+ images: Record<string, number>;
68
+ lastGood: LastGood | null;
69
+ lastGoodAgeHours: number | null;
70
+ stale: boolean;
71
+ }
72
+ export declare const zipSingleFile: (file: string, zipFile: string) => Promise<void>;
73
+ export declare class MeinstadtFeedRun {
74
+ private readonly deps;
75
+ private readonly options;
76
+ constructor(deps: MeinstadtRunDeps, options: MeinstadtRunOptions);
77
+ private now;
78
+ run(): Promise<MeinstadtRunReport>;
79
+ private count;
80
+ private writeReport;
81
+ }
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MeinstadtFeedRun = exports.zipSingleFile = exports.MeinstadtConfigError = exports.MeinstadtExclusion = void 0;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const meinstadt_json_builder_1 = require("../formats/meinstadt-json.builder");
7
+ const meinstadt_transformer_1 = require("../transformers/meinstadt.transformer");
8
+ const feed_guard_1 = require("./feed-guard");
9
+ var MeinstadtExclusion;
10
+ (function (MeinstadtExclusion) {
11
+ MeinstadtExclusion["duplicateId"] = "duplicate_id";
12
+ MeinstadtExclusion["filtered"] = "filtered";
13
+ MeinstadtExclusion["noVehicleId"] = "no_vehicle_id";
14
+ MeinstadtExclusion["noImage"] = "no_valid_image";
15
+ })(MeinstadtExclusion || (exports.MeinstadtExclusion = MeinstadtExclusion = {}));
16
+ class MeinstadtConfigError extends Error {
17
+ code;
18
+ constructor(code, message) {
19
+ super(`[meinstadt:${code}] ${message}`);
20
+ this.code = code;
21
+ }
22
+ }
23
+ exports.MeinstadtConfigError = MeinstadtConfigError;
24
+ const AdmZip = require('adm-zip');
25
+ const zipSingleFile = async (file, zipFile) => {
26
+ const archive = new AdmZip();
27
+ archive.addLocalFile(file);
28
+ archive.writeZip(zipFile);
29
+ };
30
+ exports.zipSingleFile = zipSingleFile;
31
+ const increment = (counter, key) => {
32
+ counter[key] = (counter[key] ?? 0) + 1;
33
+ };
34
+ class MeinstadtFeedRun {
35
+ deps;
36
+ options;
37
+ constructor(deps, options) {
38
+ this.deps = deps;
39
+ this.options = options;
40
+ }
41
+ now() {
42
+ return this.options.now ? this.options.now() : new Date();
43
+ }
44
+ async run() {
45
+ const { guard } = this.deps;
46
+ const { jsonFile, zipFile, stateDir, runId, dryRun, cpc } = this.options;
47
+ const startedAt = this.now();
48
+ const lastGood = await guard.readLastGood();
49
+ const report = {
50
+ runId,
51
+ mode: dryRun ? 'dry-run' : 'live',
52
+ startedAt: startedAt.toISOString(),
53
+ status: 'failed',
54
+ cpc,
55
+ jsonFile,
56
+ zipFile,
57
+ source: { files: 0, newestChunkAt: null, cars: 0 },
58
+ items: 0,
59
+ excluded: {},
60
+ accidentFree: {},
61
+ imagesPerItem: { min: null, max: null, total: 0 },
62
+ images: {},
63
+ lastGood,
64
+ lastGoodAgeHours: guard.staleHours(lastGood, startedAt),
65
+ stale: guard.isStale(lastGood, startedAt),
66
+ };
67
+ if (!dryRun && !cpc) {
68
+ report.error = 'cpc_missing';
69
+ await this.writeReport(report);
70
+ throw new MeinstadtConfigError('cpc_missing', 'live meinestadt feed needs a configured cpc (positive decimal, e.g. "0.99")');
71
+ }
72
+ await guard.acquireLock(runId ?? 'local', startedAt);
73
+ const tmpFile = `${jsonFile}.tmp`;
74
+ try {
75
+ const snapshot = await (0, feed_guard_1.inspectSourceSnapshot)(this.options.sourceDirectory, this.options.sourceBaseFileName);
76
+ report.source.files = snapshot.files;
77
+ report.source.newestChunkAt = snapshot.newestMtime?.toISOString() ?? null;
78
+ guard.checkSource(snapshot, startedAt);
79
+ await fs_1.promises.mkdir((0, path_1.dirname)(jsonFile), { recursive: true });
80
+ await fs_1.promises.rm(tmpFile, { force: true });
81
+ const builder = new meinstadt_json_builder_1.MeinstadtJsonBuilder(tmpFile);
82
+ await builder.buildStart();
83
+ const seen = new Set();
84
+ let first = true;
85
+ await this.deps.forEachChunk(async (cars) => {
86
+ for (const source of cars) {
87
+ report.source.cars += 1;
88
+ const id = String(source?.car?._id ?? '');
89
+ if (id && seen.has(id)) {
90
+ increment(report.excluded, MeinstadtExclusion.duplicateId);
91
+ continue;
92
+ }
93
+ seen.add(id);
94
+ if (!this.deps.filterCar(source)) {
95
+ increment(report.excluded, MeinstadtExclusion.filtered);
96
+ continue;
97
+ }
98
+ if (!source.car?.metaData?.vehicleId) {
99
+ increment(report.excluded, MeinstadtExclusion.noVehicleId);
100
+ continue;
101
+ }
102
+ const images = await this.deps.resolveImages(source);
103
+ if (!images.length) {
104
+ increment(report.excluded, MeinstadtExclusion.noImage);
105
+ continue;
106
+ }
107
+ const item = (0, meinstadt_transformer_1.mapMeinstadtItem)(source.car, {
108
+ domain: this.options.domain,
109
+ cpc,
110
+ equipment: await this.deps.equipment(source.car),
111
+ images,
112
+ translate: this.options.translate,
113
+ });
114
+ await builder.addItem(item, first);
115
+ first = false;
116
+ this.count(report, item);
117
+ }
118
+ });
119
+ await builder.buildEnd();
120
+ report.images = this.deps.imageStats();
121
+ const counts = { sourceItems: report.source.cars, publishedItems: report.items };
122
+ guard.checkCounts(counts, lastGood);
123
+ report.lastGood = await guard.publish(tmpFile, jsonFile, counts, this.now(), runId);
124
+ const zipTmp = zipFile.replace(/\.zip$/, '.tmp.zip');
125
+ await fs_1.promises.rm(zipTmp, { force: true });
126
+ await this.deps.zip(jsonFile, zipTmp);
127
+ await fs_1.promises.rename(zipTmp, zipFile);
128
+ report.status = 'published';
129
+ report.lastGoodAgeHours = 0;
130
+ report.stale = false;
131
+ return report;
132
+ }
133
+ catch (error) {
134
+ if (error instanceof feed_guard_1.FeedGuardError) {
135
+ report.status = 'blocked';
136
+ report.guard = { code: error.code, message: error.message };
137
+ }
138
+ else {
139
+ report.error = error?.message ?? String(error);
140
+ }
141
+ await fs_1.promises.rename(tmpFile, `${jsonFile}.rejected`).catch(() => undefined);
142
+ throw error;
143
+ }
144
+ finally {
145
+ await this.writeReport(report);
146
+ await guard.releaseLock();
147
+ }
148
+ }
149
+ count(report, item) {
150
+ report.items += 1;
151
+ increment(report.accidentFree, String(item.accidentFree));
152
+ const n = item.images.length;
153
+ const stats = report.imagesPerItem;
154
+ stats.min = stats.min === null ? n : Math.min(stats.min, n);
155
+ stats.max = stats.max === null ? n : Math.max(stats.max, n);
156
+ stats.total += n;
157
+ }
158
+ async writeReport(report) {
159
+ report.finishedAt = this.now().toISOString();
160
+ await fs_1.promises.mkdir(this.options.stateDir, { recursive: true });
161
+ await fs_1.promises.writeFile((0, path_1.join)(this.options.stateDir, 'last-run-report.json'), JSON.stringify(report, null, 2), 'utf8');
162
+ console.log(`meinestadt feed report: ${JSON.stringify(report)}`);
163
+ }
164
+ }
165
+ exports.MeinstadtFeedRun = MeinstadtFeedRun;
166
+ //# sourceMappingURL=meinstadt-feed-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meinstadt-feed-run.js","sourceRoot":"","sources":["../../src/services/meinstadt-feed-run.ts"],"names":[],"mappings":"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"}
@@ -1,31 +1,47 @@
1
1
  import { DataSchemes } from '@bytebrand/car-schema';
2
- import { ConfigService, ImagesService } from '../services';
3
2
  import { AutouncleJsonItem } from '../interfaces';
4
- import { ImboImageResponseInterface } from '@bytebrand/chunkable';
3
+ import { OpenAiImageSelection } from './openai-image-fields';
4
+ export declare enum AutouncleExclusion {
5
+ duplicateId = "duplicate_id",
6
+ filtered = "filtered",
7
+ noId = "no_id",
8
+ noDealer = "no_dealer",
9
+ notAvailable = "reserved_or_sold",
10
+ noPrice = "no_valid_price",
11
+ noImage = "no_valid_image"
12
+ }
13
+ export interface AutouncleAddress {
14
+ city: string;
15
+ addr1: string;
16
+ region: string;
17
+ postal_code: string;
18
+ }
19
+ export interface AutouncleMappingContext {
20
+ domain: string;
21
+ address: AutouncleAddress;
22
+ images: string[];
23
+ translate: (key: string) => string;
24
+ }
25
+ export type AutouncleMapResult = {
26
+ ok: true;
27
+ item: AutouncleJsonItem;
28
+ } | {
29
+ ok: false;
30
+ reason: AutouncleExclusion;
31
+ };
32
+ export declare const toAutouncleImages: (selection: OpenAiImageSelection, maxImages?: number) => string[];
33
+ export declare const getAutouncleYear: (firstRegistration: unknown, now?: Date) => string;
34
+ export declare const getAutouncleStatus: (firstRegistration: unknown) => 'Neuwagen' | 'Gebrauchtwagen';
35
+ export declare const getAutounclePrice: (value: unknown) => string | null;
36
+ export declare const getAutouncleExclusion: (car: DataSchemes.Car) => AutouncleExclusion | null;
37
+ export declare const mapAutouncleItem: (car: DataSchemes.Car, ctx: AutouncleMappingContext) => AutouncleMapResult;
5
38
  export declare class AutouncleTransformer {
6
- private configService;
7
- private imageService;
8
39
  private translator;
9
40
  private postalCodesService;
10
- constructor(configService: ConfigService, imageService: ImagesService);
11
- transform({ car, images, owner, }: {
12
- car: DataSchemes.Car;
13
- images: ImboImageResponseInterface[];
14
- metadata?: unknown;
15
- owner: unknown;
16
- }): Promise<AutouncleJsonItem>;
17
- private getStatus;
18
- private getYear;
19
- private mapBodyStyle;
20
- private mapFuel;
21
- private mapTransmission;
22
- private getPrice;
23
- private getAddress;
41
+ constructor();
42
+ translate(key: string): string;
43
+ getAddress(owner: unknown): Promise<AutouncleAddress>;
24
44
  private isEmptyLocation;
25
45
  private isEmptyAddress;
26
- private getCoords;
27
46
  private getLocationByInfo;
28
- private getExteriorColor;
29
- private getMileage;
30
- private has4WD;
31
47
  }