@whaly/connector-sdk 0.3.10 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +79 -3
- package/dist/index.d.ts +79 -3
- package/dist/index.js +186 -72
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +218 -105
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -8830,7 +8830,7 @@ var require_mime_types = __commonJS({
|
|
|
8830
8830
|
"node_modules/mime-types/index.js"(exports) {
|
|
8831
8831
|
"use strict";
|
|
8832
8832
|
var db = require_mime_db();
|
|
8833
|
-
var
|
|
8833
|
+
var extname3 = __require("path").extname;
|
|
8834
8834
|
var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/;
|
|
8835
8835
|
var TEXT_TYPE_REGEXP = /^text\//i;
|
|
8836
8836
|
exports.charset = charset;
|
|
@@ -8884,7 +8884,7 @@ var require_mime_types = __commonJS({
|
|
|
8884
8884
|
if (!path8 || typeof path8 !== "string") {
|
|
8885
8885
|
return false;
|
|
8886
8886
|
}
|
|
8887
|
-
var extension2 =
|
|
8887
|
+
var extension2 = extname3("x." + path8).toLowerCase().substr(1);
|
|
8888
8888
|
if (!extension2) {
|
|
8889
8889
|
return false;
|
|
8890
8890
|
}
|
|
@@ -10003,7 +10003,7 @@ var require_form_data = __commonJS({
|
|
|
10003
10003
|
var http = __require("http");
|
|
10004
10004
|
var https = __require("https");
|
|
10005
10005
|
var parseUrl = __require("url").parse;
|
|
10006
|
-
var
|
|
10006
|
+
var fs12 = __require("fs");
|
|
10007
10007
|
var Stream2 = __require("stream").Stream;
|
|
10008
10008
|
var crypto = __require("crypto");
|
|
10009
10009
|
var mime = require_mime_types();
|
|
@@ -10070,7 +10070,7 @@ var require_form_data = __commonJS({
|
|
|
10070
10070
|
if (value.end != void 0 && value.end != Infinity && value.start != void 0) {
|
|
10071
10071
|
callback(null, value.end + 1 - (value.start ? value.start : 0));
|
|
10072
10072
|
} else {
|
|
10073
|
-
|
|
10073
|
+
fs12.stat(value.path, function(err, stat) {
|
|
10074
10074
|
if (err) {
|
|
10075
10075
|
callback(err);
|
|
10076
10076
|
return;
|
|
@@ -10520,7 +10520,7 @@ var getDownloadFileApiCall = async (endpoint, config, output, privateLogging) =>
|
|
|
10520
10520
|
...config.headers ? { headers: config.headers } : {},
|
|
10521
10521
|
paramsSerializer: { serialize: (params) => qs.stringify(params, { arrayFormat: "repeat" }) }
|
|
10522
10522
|
}).then((response) => {
|
|
10523
|
-
return new Promise((
|
|
10523
|
+
return new Promise((resolve2, reject) => {
|
|
10524
10524
|
response.data.pipe(writer);
|
|
10525
10525
|
let error = null;
|
|
10526
10526
|
writer.on("error", (err) => {
|
|
@@ -10530,7 +10530,7 @@ var getDownloadFileApiCall = async (endpoint, config, output, privateLogging) =>
|
|
|
10530
10530
|
});
|
|
10531
10531
|
writer.on("close", () => {
|
|
10532
10532
|
if (!error) {
|
|
10533
|
-
|
|
10533
|
+
resolve2({ outputDir: output });
|
|
10534
10534
|
}
|
|
10535
10535
|
});
|
|
10536
10536
|
});
|
|
@@ -10681,8 +10681,8 @@ var printMemoryFootprint = (prefix) => {
|
|
|
10681
10681
|
|
|
10682
10682
|
// src/sdk/service/exit.ts
|
|
10683
10683
|
async function gracefulExit(exitCode) {
|
|
10684
|
-
const loggerFinish = new Promise((
|
|
10685
|
-
logger.closeWinston(
|
|
10684
|
+
const loggerFinish = new Promise((resolve2, reject) => {
|
|
10685
|
+
logger.closeWinston(resolve2);
|
|
10686
10686
|
});
|
|
10687
10687
|
await loggerFinish;
|
|
10688
10688
|
process.exit(exitCode);
|
|
@@ -12452,13 +12452,13 @@ var ITarget = class _ITarget {
|
|
|
12452
12452
|
const dbSyncInstance = stream.getDbSync();
|
|
12453
12453
|
const recordWithrenamedColumns = dbSyncInstance.renameColumns(recordWithDecimal);
|
|
12454
12454
|
const serializedRecord = this.getSerializedRecord(streamId, recordWithrenamedColumns);
|
|
12455
|
-
return new Promise((
|
|
12455
|
+
return new Promise((resolve2, reject) => {
|
|
12456
12456
|
stream.getFileToLoad().stream.write(serializedRecord, (error) => {
|
|
12457
12457
|
if (error) {
|
|
12458
12458
|
reject(error);
|
|
12459
12459
|
}
|
|
12460
12460
|
stream.incrementBatchedRowCount();
|
|
12461
|
-
|
|
12461
|
+
resolve2();
|
|
12462
12462
|
});
|
|
12463
12463
|
});
|
|
12464
12464
|
} catch (err) {
|
|
@@ -12599,11 +12599,11 @@ var ITarget = class _ITarget {
|
|
|
12599
12599
|
const streamState = this.streams[streamId];
|
|
12600
12600
|
if (!streamState || streamState.getBatchedRowCount() === 0) continue;
|
|
12601
12601
|
const fileToLoad = streamState.getFileToLoad();
|
|
12602
|
-
await new Promise((
|
|
12602
|
+
await new Promise((resolve2, reject) => {
|
|
12603
12603
|
fileToLoad.stream.end(() => {
|
|
12604
12604
|
fileToLoad.stream.close((err) => {
|
|
12605
12605
|
if (err) reject(err);
|
|
12606
|
-
else
|
|
12606
|
+
else resolve2();
|
|
12607
12607
|
});
|
|
12608
12608
|
});
|
|
12609
12609
|
});
|
|
@@ -13134,18 +13134,18 @@ async function* rowGeneratorFromCsv(path8, fileConfig) {
|
|
|
13134
13134
|
}
|
|
13135
13135
|
}
|
|
13136
13136
|
async function countCsvLines(filePath) {
|
|
13137
|
-
return new Promise((
|
|
13137
|
+
return new Promise((resolve2, reject) => {
|
|
13138
13138
|
let newlines = 0;
|
|
13139
13139
|
createReadStream(filePath).on("data", (chunk2) => {
|
|
13140
13140
|
const buf = Buffer.isBuffer(chunk2) ? chunk2 : Buffer.from(chunk2);
|
|
13141
13141
|
for (let i = 0; i < buf.length; i++) {
|
|
13142
13142
|
if (buf[i] === 10) newlines++;
|
|
13143
13143
|
}
|
|
13144
|
-
}).on("end", () =>
|
|
13144
|
+
}).on("end", () => resolve2(Math.max(0, newlines - 1))).on("error", reject);
|
|
13145
13145
|
});
|
|
13146
13146
|
}
|
|
13147
13147
|
var checkCsvHeaderRow = async (path8, fileConfig) => {
|
|
13148
|
-
return new Promise((
|
|
13148
|
+
return new Promise((resolve2, reject) => {
|
|
13149
13149
|
const colsWithParsingConfig = Object.keys(fileConfig.fields).map((key) => key.trim());
|
|
13150
13150
|
console.debug(`${logPrefix} CSV Expected columns:`, colsWithParsingConfig.map((col) => {
|
|
13151
13151
|
const info = getStringHexInfo(col);
|
|
@@ -13220,7 +13220,7 @@ var checkCsvHeaderRow = async (path8, fileConfig) => {
|
|
|
13220
13220
|
reject(new Error(`Error processing CSV file: ${error.message}`));
|
|
13221
13221
|
});
|
|
13222
13222
|
initialReadStream.on("close", () => {
|
|
13223
|
-
|
|
13223
|
+
resolve2();
|
|
13224
13224
|
});
|
|
13225
13225
|
});
|
|
13226
13226
|
};
|
|
@@ -13801,6 +13801,16 @@ var CloudStorageService = class {
|
|
|
13801
13801
|
throw new Error(format6(`error writing GCS object gs://${this.bucket.name}/${objectPath}, err: %s`, err?.message));
|
|
13802
13802
|
}
|
|
13803
13803
|
}
|
|
13804
|
+
/**
|
|
13805
|
+
* Resolves a file URI to a local file path by downloading it from the configured GCS bucket.
|
|
13806
|
+
*
|
|
13807
|
+
* @example
|
|
13808
|
+
* const storage = new CloudStorageService("my-bucket", "my-folder");
|
|
13809
|
+
* const localPath = await storage.resolveFileUri("folder/file.xlsx");
|
|
13810
|
+
*/
|
|
13811
|
+
async resolveFileUri(fileUri) {
|
|
13812
|
+
return this.downloadFile(fileUri, pathModule.basename(fileUri));
|
|
13813
|
+
}
|
|
13804
13814
|
/**
|
|
13805
13815
|
* Uploads a local file to the bucket with a unique name based on prefix, streamId, and UUID.
|
|
13806
13816
|
* Files are stored under `<prefix>/<run-id>/` when the RUN_ID env var is set,
|
|
@@ -13829,6 +13839,108 @@ var CloudStorageService = class {
|
|
|
13829
13839
|
}
|
|
13830
13840
|
};
|
|
13831
13841
|
|
|
13842
|
+
// src/services/local-storage.ts
|
|
13843
|
+
import * as pathModule2 from "path";
|
|
13844
|
+
import * as fs6 from "fs";
|
|
13845
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
13846
|
+
var logPrefix5 = "[LocalStorageService]";
|
|
13847
|
+
var LocalStorageService = class {
|
|
13848
|
+
basePath;
|
|
13849
|
+
processedSuffix;
|
|
13850
|
+
supportedExtensions;
|
|
13851
|
+
constructor(basePath, opts) {
|
|
13852
|
+
this.basePath = pathModule2.resolve(basePath);
|
|
13853
|
+
this.processedSuffix = opts?.processedSuffix ?? ".processed";
|
|
13854
|
+
this.supportedExtensions = opts?.supportedExtensions ?? [];
|
|
13855
|
+
}
|
|
13856
|
+
async listFiles(prefix) {
|
|
13857
|
+
const dir = prefix ? pathModule2.resolve(this.basePath, prefix) : this.basePath;
|
|
13858
|
+
if (!fs6.existsSync(dir)) {
|
|
13859
|
+
return [];
|
|
13860
|
+
}
|
|
13861
|
+
const entries = fs6.readdirSync(dir, { recursive: true });
|
|
13862
|
+
const files = [];
|
|
13863
|
+
for (const entry of entries) {
|
|
13864
|
+
const rel = typeof entry === "string" ? entry : entry.toString();
|
|
13865
|
+
const full = pathModule2.join(dir, rel);
|
|
13866
|
+
if (fs6.statSync(full).isFile()) {
|
|
13867
|
+
files.push(pathModule2.relative(this.basePath, full));
|
|
13868
|
+
}
|
|
13869
|
+
}
|
|
13870
|
+
return files;
|
|
13871
|
+
}
|
|
13872
|
+
async getUnprocessedFiles() {
|
|
13873
|
+
const allFiles = await this.listFiles();
|
|
13874
|
+
const markerFiles = new Set(
|
|
13875
|
+
allFiles.filter((f) => f.endsWith(this.processedSuffix)).map((f) => f.replace(this.processedSuffix, ""))
|
|
13876
|
+
);
|
|
13877
|
+
return allFiles.filter((f) => {
|
|
13878
|
+
if (f.endsWith(this.processedSuffix)) return false;
|
|
13879
|
+
if (this.supportedExtensions.length > 0) {
|
|
13880
|
+
const ext = pathModule2.extname(f).toLowerCase();
|
|
13881
|
+
if (!this.supportedExtensions.includes(ext)) return false;
|
|
13882
|
+
}
|
|
13883
|
+
return !markerFiles.has(f);
|
|
13884
|
+
});
|
|
13885
|
+
}
|
|
13886
|
+
async createMarkerFile(fileName) {
|
|
13887
|
+
const markerPath = pathModule2.join(this.basePath, `${fileName}${this.processedSuffix}`);
|
|
13888
|
+
const dir = pathModule2.dirname(markerPath);
|
|
13889
|
+
if (!fs6.existsSync(dir)) {
|
|
13890
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
13891
|
+
}
|
|
13892
|
+
fs6.writeFileSync(markerPath, `Marked file ${fileName} as processed`);
|
|
13893
|
+
logger.info(`${logPrefix5} Marker file ${markerPath} created successfully.`);
|
|
13894
|
+
}
|
|
13895
|
+
async downloadFile(filePath, _fileName) {
|
|
13896
|
+
const resolved = pathModule2.resolve(this.basePath, filePath);
|
|
13897
|
+
if (!fs6.existsSync(resolved)) {
|
|
13898
|
+
throw new Error(`Local file not found: ${resolved}`);
|
|
13899
|
+
}
|
|
13900
|
+
logger.info(`${logPrefix5} Resolved local file: ${resolved}`);
|
|
13901
|
+
return resolved;
|
|
13902
|
+
}
|
|
13903
|
+
async resolveFileUri(fileUri) {
|
|
13904
|
+
const resolved = pathModule2.resolve(fileUri);
|
|
13905
|
+
if (!fs6.existsSync(resolved)) {
|
|
13906
|
+
throw new Error(`Local file not found: ${resolved}`);
|
|
13907
|
+
}
|
|
13908
|
+
logger.info(`${logPrefix5} File URI resolved to local path: ${resolved}`);
|
|
13909
|
+
return resolved;
|
|
13910
|
+
}
|
|
13911
|
+
async uploadFile(localPath, destPath) {
|
|
13912
|
+
const dest = pathModule2.resolve(this.basePath, destPath);
|
|
13913
|
+
const dir = pathModule2.dirname(dest);
|
|
13914
|
+
if (!fs6.existsSync(dir)) {
|
|
13915
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
13916
|
+
}
|
|
13917
|
+
fs6.copyFileSync(localPath, dest);
|
|
13918
|
+
logger.info(`${logPrefix5} Copied '%s' to '%s'`, localPath, dest);
|
|
13919
|
+
return { name: destPath };
|
|
13920
|
+
}
|
|
13921
|
+
async readObjectAsString(objectPath) {
|
|
13922
|
+
const fullPath = pathModule2.resolve(this.basePath, objectPath);
|
|
13923
|
+
if (!fs6.existsSync(fullPath)) {
|
|
13924
|
+
throw new Error(`Local file not found: ${fullPath}`);
|
|
13925
|
+
}
|
|
13926
|
+
return fs6.readFileSync(fullPath, "utf8");
|
|
13927
|
+
}
|
|
13928
|
+
async writeStringObject(objectPath, contents) {
|
|
13929
|
+
const fullPath = pathModule2.resolve(this.basePath, objectPath);
|
|
13930
|
+
const dir = pathModule2.dirname(fullPath);
|
|
13931
|
+
if (!fs6.existsSync(dir)) {
|
|
13932
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
13933
|
+
}
|
|
13934
|
+
fs6.writeFileSync(fullPath, contents, "utf8");
|
|
13935
|
+
logger.info(`${logPrefix5} Wrote object to ${fullPath}`);
|
|
13936
|
+
}
|
|
13937
|
+
async uploadFileWithUniqueName(filePath, prefix, streamId) {
|
|
13938
|
+
const runFolder = process.env.RUN_ID ?? "default";
|
|
13939
|
+
const destName = `${prefix}/${runFolder}/${streamId}-${randomUUID2()}.jsonnl`;
|
|
13940
|
+
return this.uploadFile(filePath, destName);
|
|
13941
|
+
}
|
|
13942
|
+
};
|
|
13943
|
+
|
|
13832
13944
|
// src/services/zip.ts
|
|
13833
13945
|
import * as fse from "fs-extra";
|
|
13834
13946
|
import decompress from "decompress";
|
|
@@ -13841,7 +13953,7 @@ var unzip = async (zipFilePath, extractedPath) => {
|
|
|
13841
13953
|
// src/services/cdn.ts
|
|
13842
13954
|
import axios3 from "axios";
|
|
13843
13955
|
import axiosRetry2 from "axios-retry";
|
|
13844
|
-
var
|
|
13956
|
+
var logPrefix6 = "[CdnService]";
|
|
13845
13957
|
var MAX_RETRIES = 10;
|
|
13846
13958
|
var CdnService = class {
|
|
13847
13959
|
axiosClient;
|
|
@@ -13867,12 +13979,12 @@ var CdnService = class {
|
|
|
13867
13979
|
if (retryAfter) {
|
|
13868
13980
|
const seconds = Number(retryAfter);
|
|
13869
13981
|
if (!isNaN(seconds) && seconds > 0) {
|
|
13870
|
-
logger.info(`${
|
|
13982
|
+
logger.info(`${logPrefix6} Rate limited \u2014 waiting ${seconds}s (Retry-After header), attempt ${retryCount}/${MAX_RETRIES}`);
|
|
13871
13983
|
return seconds * 1e3;
|
|
13872
13984
|
}
|
|
13873
13985
|
}
|
|
13874
13986
|
const delay = axiosRetry2.exponentialDelay(retryCount);
|
|
13875
|
-
logger.info(`${
|
|
13987
|
+
logger.info(`${logPrefix6} Retrying in ${delay}ms (attempt ${retryCount}/${MAX_RETRIES}) for ${error.config?.method?.toUpperCase()} ${error.config?.url}`);
|
|
13876
13988
|
return delay;
|
|
13877
13989
|
}
|
|
13878
13990
|
});
|
|
@@ -13898,7 +14010,7 @@ var CdnService = class {
|
|
|
13898
14010
|
const status = err.response?.status;
|
|
13899
14011
|
if (status === 404) return { exists: false, lastModified: null, contentType: null };
|
|
13900
14012
|
if (status === 405) {
|
|
13901
|
-
logger.warn(`${
|
|
14013
|
+
logger.warn(`${logPrefix6} HEAD not supported for ${url}, treating file as absent`);
|
|
13902
14014
|
return { exists: false, lastModified: null, contentType: null };
|
|
13903
14015
|
}
|
|
13904
14016
|
this.throwMeaningfulError(err);
|
|
@@ -13922,11 +14034,11 @@ var CdnService = class {
|
|
|
13922
14034
|
async uploadFile(cdnId, fileName, fileBuffer) {
|
|
13923
14035
|
const url = `/v1/cdn/${cdnId}/files/${encodeURIComponent(fileName)}`;
|
|
13924
14036
|
try {
|
|
13925
|
-
logger.info(`${
|
|
14037
|
+
logger.info(`${logPrefix6} Uploading ${fileName} (${fileBuffer.length} bytes) to CDN ${cdnId}`);
|
|
13926
14038
|
const form = new FormData();
|
|
13927
14039
|
form.append("file", new Blob([fileBuffer]), fileName);
|
|
13928
14040
|
const response = await this.axiosClient.put(url, form);
|
|
13929
|
-
logger.info(`${
|
|
14041
|
+
logger.info(`${logPrefix6} Successfully uploaded ${fileName} (status ${response.status})`);
|
|
13930
14042
|
return {
|
|
13931
14043
|
filePath: response.data?.filePath ?? `/org/${cdnId}/file/${fileName}`
|
|
13932
14044
|
};
|
|
@@ -13967,9 +14079,9 @@ var AssetStream = class {
|
|
|
13967
14079
|
};
|
|
13968
14080
|
|
|
13969
14081
|
// src/sdk/models/asset-tap/asset-tap.ts
|
|
13970
|
-
import
|
|
14082
|
+
import fs7 from "fs-extra";
|
|
13971
14083
|
import path5 from "path";
|
|
13972
|
-
var
|
|
14084
|
+
var logPrefix7 = "[AssetTap]";
|
|
13973
14085
|
function inferContentType(filePath, fallback) {
|
|
13974
14086
|
const mime = getMimeType(filePath);
|
|
13975
14087
|
return mime !== "application/octet-stream" ? mime : fallback;
|
|
@@ -13977,7 +14089,7 @@ function inferContentType(filePath, fallback) {
|
|
|
13977
14089
|
function deriveManifestMode(streams) {
|
|
13978
14090
|
const modes = new Set(streams.map((s) => s.replicationMode));
|
|
13979
14091
|
if (modes.size > 1) {
|
|
13980
|
-
logger.warn(`${
|
|
14092
|
+
logger.warn(`${logPrefix7} Streams have mixed replication modes (${[...modes].join(", ")}). Manifest will report "FULL".`);
|
|
13981
14093
|
return "FULL";
|
|
13982
14094
|
}
|
|
13983
14095
|
return streams[0]?.replicationMode ?? "INCREMENTAL";
|
|
@@ -13999,21 +14111,21 @@ var AssetTap = class {
|
|
|
13999
14111
|
const dryRun = isDryRun();
|
|
14000
14112
|
const dryRunLimit = dryRun ? getDryRunLimit() : void 0;
|
|
14001
14113
|
if (dryRun) {
|
|
14002
|
-
logger.info(`${
|
|
14003
|
-
await
|
|
14114
|
+
logger.info(`${logPrefix7} [DRY_RUN] mode active \u2014 skipping CDN checks and uploads`);
|
|
14115
|
+
await fs7.emptyDir(this.outputDir);
|
|
14004
14116
|
if (dryRunLimit !== void 0) {
|
|
14005
|
-
logger.info(`${
|
|
14117
|
+
logger.info(`${logPrefix7} [DRY_RUN] Limit: ${dryRunLimit} assets per stream`);
|
|
14006
14118
|
}
|
|
14007
14119
|
} else if (process.env["DRY_RUN_LIMIT"] !== void 0) {
|
|
14008
|
-
logger.warn(`${
|
|
14120
|
+
logger.warn(`${logPrefix7} DRY_RUN_LIMIT is set but DRY_RUN is not active \u2014 limit will be ignored`);
|
|
14009
14121
|
}
|
|
14010
14122
|
const tmpDir2 = path5.join(this.outputDir, "tmp");
|
|
14011
|
-
await
|
|
14123
|
+
await fs7.ensureDir(tmpDir2);
|
|
14012
14124
|
const streamManifests = [];
|
|
14013
14125
|
let entryIndex = 0;
|
|
14014
14126
|
let totalSummary = { total: 0, uploaded: 0, skipped: 0, errors: 0 };
|
|
14015
14127
|
for (const stream of this.streams) {
|
|
14016
|
-
logger.info(`${
|
|
14128
|
+
logger.info(`${logPrefix7} Processing stream: ${stream.streamId} (mode=${stream.replicationMode}, concurrency=${this.concurrency})`);
|
|
14017
14129
|
const assetEntries = [];
|
|
14018
14130
|
let streamAssetCount = 0;
|
|
14019
14131
|
await processFromAsyncIterable(
|
|
@@ -14022,11 +14134,11 @@ var AssetTap = class {
|
|
|
14022
14134
|
if (dryRunLimit !== void 0 && streamAssetCount >= dryRunLimit) {
|
|
14023
14135
|
return "stop";
|
|
14024
14136
|
}
|
|
14025
|
-
logger.debug(`${
|
|
14137
|
+
logger.debug(`${logPrefix7} Processing entry: ${entry.sourcePath}`);
|
|
14026
14138
|
if (stream.replicationMode === "INCREMENTAL" && !dryRun) {
|
|
14027
14139
|
const shouldSync = await this.target.shouldSync(entry);
|
|
14028
14140
|
if (!shouldSync) {
|
|
14029
|
-
logger.debug(`${
|
|
14141
|
+
logger.debug(`${logPrefix7} Skipping ${entry.sourcePath} (up-to-date)`);
|
|
14030
14142
|
assetEntries.push({
|
|
14031
14143
|
sourcePath: entry.sourcePath,
|
|
14032
14144
|
destinationPath: entry.destinationPath,
|
|
@@ -14049,7 +14161,7 @@ var AssetTap = class {
|
|
|
14049
14161
|
await stream.downloadEntry(entry, downloadedPath);
|
|
14050
14162
|
uploadPath = await stream.transformFile(downloadedPath, entry);
|
|
14051
14163
|
const wasTransformed = uploadPath !== downloadedPath;
|
|
14052
|
-
const stat = await
|
|
14164
|
+
const stat = await fs7.stat(uploadPath);
|
|
14053
14165
|
const processed = {
|
|
14054
14166
|
entry,
|
|
14055
14167
|
downloadedPath,
|
|
@@ -14062,14 +14174,14 @@ var AssetTap = class {
|
|
|
14062
14174
|
await this.target.uploadAsset(processed);
|
|
14063
14175
|
} else {
|
|
14064
14176
|
const inspectPath = path5.join(this.outputDir, stream.streamId, entry.destinationPath);
|
|
14065
|
-
await
|
|
14066
|
-
await
|
|
14177
|
+
await fs7.ensureDir(path5.dirname(inspectPath));
|
|
14178
|
+
await fs7.copy(uploadPath, inspectPath);
|
|
14067
14179
|
if (wasTransformed) {
|
|
14068
14180
|
const baseName = path5.basename(entry.destinationPath, path5.extname(entry.destinationPath));
|
|
14069
14181
|
const origExt = getExtension(entry.contentType);
|
|
14070
14182
|
const originalPath = path5.join(this.outputDir, "originals", `${baseName}${origExt}`);
|
|
14071
|
-
await
|
|
14072
|
-
await
|
|
14183
|
+
await fs7.ensureDir(path5.dirname(originalPath));
|
|
14184
|
+
await fs7.copy(downloadedPath, originalPath);
|
|
14073
14185
|
}
|
|
14074
14186
|
}
|
|
14075
14187
|
assetEntries.push({
|
|
@@ -14082,10 +14194,10 @@ var AssetTap = class {
|
|
|
14082
14194
|
status: "uploaded",
|
|
14083
14195
|
transformed: wasTransformed
|
|
14084
14196
|
});
|
|
14085
|
-
logger.info(`${
|
|
14197
|
+
logger.info(`${logPrefix7} ${dryRun ? "[DRY_RUN] Processed" : "Uploaded"} ${entry.sourcePath} \u2192 ${entry.destinationPath}`);
|
|
14086
14198
|
} catch (err) {
|
|
14087
14199
|
const message = err instanceof Error ? err.message : String(err);
|
|
14088
|
-
logger.error(`${
|
|
14200
|
+
logger.error(`${logPrefix7} Failed to process ${entry.sourcePath}: ${message}`);
|
|
14089
14201
|
assetEntries.push({
|
|
14090
14202
|
sourcePath: entry.sourcePath,
|
|
14091
14203
|
destinationPath: entry.destinationPath,
|
|
@@ -14098,13 +14210,13 @@ var AssetTap = class {
|
|
|
14098
14210
|
error: message
|
|
14099
14211
|
});
|
|
14100
14212
|
} finally {
|
|
14101
|
-
await
|
|
14213
|
+
await fs7.remove(downloadedPath).catch(() => void 0);
|
|
14102
14214
|
if (uploadPath !== downloadedPath) {
|
|
14103
|
-
await
|
|
14215
|
+
await fs7.remove(uploadPath).catch(() => void 0);
|
|
14104
14216
|
}
|
|
14105
14217
|
}
|
|
14106
14218
|
if (dryRunLimit !== void 0 && streamAssetCount >= dryRunLimit) {
|
|
14107
|
-
logger.info(`${
|
|
14219
|
+
logger.info(`${logPrefix7} [DRY_RUN] Reached limit of ${dryRunLimit} for stream "${stream.streamId}", stopping.`);
|
|
14108
14220
|
return "stop";
|
|
14109
14221
|
}
|
|
14110
14222
|
return "continue";
|
|
@@ -14135,12 +14247,12 @@ var AssetTap = class {
|
|
|
14135
14247
|
streams: streamManifests,
|
|
14136
14248
|
summary: totalSummary
|
|
14137
14249
|
};
|
|
14138
|
-
await
|
|
14139
|
-
await
|
|
14250
|
+
await fs7.ensureDir(this.outputDir);
|
|
14251
|
+
await fs7.writeJson(path5.join(this.outputDir, "manifest.json"), manifest, { spaces: 2 });
|
|
14140
14252
|
if (!dryRun) {
|
|
14141
14253
|
await this.target.complete();
|
|
14142
14254
|
}
|
|
14143
|
-
logger.info(`${
|
|
14255
|
+
logger.info(`${logPrefix7} Sync complete. Uploaded=${totalSummary.uploaded} Skipped=${totalSummary.skipped} Errors=${totalSummary.errors}`);
|
|
14144
14256
|
return manifest;
|
|
14145
14257
|
}
|
|
14146
14258
|
};
|
|
@@ -14178,8 +14290,8 @@ var ImageTransform = class {
|
|
|
14178
14290
|
*/
|
|
14179
14291
|
static async toWebp(inputPath, options) {
|
|
14180
14292
|
const dir = path6.dirname(inputPath);
|
|
14181
|
-
const
|
|
14182
|
-
const outputPath = path6.join(dir, `${
|
|
14293
|
+
const basename2 = path6.basename(inputPath, path6.extname(inputPath));
|
|
14294
|
+
const outputPath = path6.join(dir, `${basename2}.webp`);
|
|
14183
14295
|
let pipeline = sharp(inputPath);
|
|
14184
14296
|
const hasSize = options.width !== void 0 && options.height !== void 0;
|
|
14185
14297
|
if (hasSize) {
|
|
@@ -14287,7 +14399,7 @@ var DocumentStream = class {
|
|
|
14287
14399
|
};
|
|
14288
14400
|
|
|
14289
14401
|
// src/sdk/models/document-tap/document-tap.ts
|
|
14290
|
-
import
|
|
14402
|
+
import fs8 from "fs-extra";
|
|
14291
14403
|
import path7 from "path";
|
|
14292
14404
|
var BYTES_PER_KB = 1024;
|
|
14293
14405
|
function formatFileSize(bytes) {
|
|
@@ -14297,13 +14409,13 @@ function formatFileSize(bytes) {
|
|
|
14297
14409
|
}
|
|
14298
14410
|
async function getFileSizeLabel(filePath) {
|
|
14299
14411
|
try {
|
|
14300
|
-
const stat = await
|
|
14412
|
+
const stat = await fs8.stat(filePath);
|
|
14301
14413
|
return formatFileSize(stat.size);
|
|
14302
14414
|
} catch {
|
|
14303
14415
|
return "unknown size";
|
|
14304
14416
|
}
|
|
14305
14417
|
}
|
|
14306
|
-
var
|
|
14418
|
+
var logPrefix8 = "[DocumentTap]";
|
|
14307
14419
|
var DocumentTap = class {
|
|
14308
14420
|
config;
|
|
14309
14421
|
outputDir;
|
|
@@ -14322,32 +14434,32 @@ var DocumentTap = class {
|
|
|
14322
14434
|
}
|
|
14323
14435
|
async sync() {
|
|
14324
14436
|
if (!this.target) {
|
|
14325
|
-
throw new Error(`${
|
|
14437
|
+
throw new Error(`${logPrefix8} No target set. Assign a WhalyDocumentTarget before calling sync().`);
|
|
14326
14438
|
}
|
|
14327
14439
|
await this.init();
|
|
14328
14440
|
if (!this.stream) {
|
|
14329
|
-
throw new Error(`${
|
|
14441
|
+
throw new Error(`${logPrefix8} No stream set. Assign this.stream in init().`);
|
|
14330
14442
|
}
|
|
14331
14443
|
const dryRun = isDryRun();
|
|
14332
14444
|
const dryRunLimit = dryRun ? getDryRunLimit() : void 0;
|
|
14333
14445
|
if (dryRun) {
|
|
14334
|
-
logger.info(`${
|
|
14335
|
-
await
|
|
14446
|
+
logger.info(`${logPrefix8} [DRY_RUN] mode active \u2014 skipping API calls and uploads`);
|
|
14447
|
+
await fs8.emptyDir(this.outputDir);
|
|
14336
14448
|
if (dryRunLimit !== void 0) {
|
|
14337
|
-
logger.info(`${
|
|
14449
|
+
logger.info(`${logPrefix8} [DRY_RUN] Limit: ${dryRunLimit} documents per stream`);
|
|
14338
14450
|
}
|
|
14339
14451
|
} else if (process.env["DRY_RUN_LIMIT"] !== void 0) {
|
|
14340
|
-
logger.warn(`${
|
|
14452
|
+
logger.warn(`${logPrefix8} DRY_RUN_LIMIT is set but DRY_RUN is not active \u2014 limit will be ignored`);
|
|
14341
14453
|
}
|
|
14342
14454
|
const tmpDir2 = path7.join(this.outputDir, "tmp");
|
|
14343
|
-
await
|
|
14455
|
+
await fs8.ensureDir(tmpDir2);
|
|
14344
14456
|
try {
|
|
14345
14457
|
const stream = this.stream;
|
|
14346
|
-
logger.info(`${
|
|
14458
|
+
logger.info(`${logPrefix8} Processing stream: ${stream.streamId}`);
|
|
14347
14459
|
const sourceEntries = await this.collectSourceEntries(stream, dryRunLimit);
|
|
14348
14460
|
const existingDocs = dryRun ? [] : await this.target.listExistingDocuments();
|
|
14349
14461
|
const diff = this.computeDiff(stream, sourceEntries, existingDocs);
|
|
14350
|
-
logger.info(`${
|
|
14462
|
+
logger.info(`${logPrefix8} Stream ${stream.streamId} diff: create=${diff.toCreate.length} reupload=${diff.toReupload.length} updateMeta=${diff.toUpdateMetadata.length} delete=${diff.toDelete.length} skip=${diff.skipped.length}`);
|
|
14351
14463
|
const entries = [];
|
|
14352
14464
|
const createTasks = diff.toCreate.map((entry) => async () => {
|
|
14353
14465
|
return this.executeCreate(stream, entry, tmpDir2, dryRun);
|
|
@@ -14379,12 +14491,12 @@ var DocumentTap = class {
|
|
|
14379
14491
|
streams: [streamManifest],
|
|
14380
14492
|
summary: streamSummary
|
|
14381
14493
|
};
|
|
14382
|
-
await
|
|
14383
|
-
await
|
|
14384
|
-
logger.info(`${
|
|
14494
|
+
await fs8.ensureDir(this.outputDir);
|
|
14495
|
+
await fs8.writeJson(path7.join(this.outputDir, "manifest.json"), manifest, { spaces: 2 });
|
|
14496
|
+
logger.info(`${logPrefix8} Sync complete. Created=${streamSummary.created} Updated=${streamSummary.updated} Reuploaded=${streamSummary.reuploaded} Deleted=${streamSummary.deleted} Skipped=${streamSummary.skipped} Errors=${streamSummary.errors}`);
|
|
14385
14497
|
return manifest;
|
|
14386
14498
|
} finally {
|
|
14387
|
-
await
|
|
14499
|
+
await fs8.remove(tmpDir2).catch(() => void 0);
|
|
14388
14500
|
}
|
|
14389
14501
|
}
|
|
14390
14502
|
async collectSourceEntries(stream, limit) {
|
|
@@ -14443,21 +14555,21 @@ var DocumentTap = class {
|
|
|
14443
14555
|
await this.target.createDocument(stream.streamId, entry, downloadPath);
|
|
14444
14556
|
} else {
|
|
14445
14557
|
const inspectPath = path7.join(this.outputDir, stream.streamId, `${safeId}.${entry.extension}`);
|
|
14446
|
-
await
|
|
14447
|
-
await
|
|
14558
|
+
await fs8.ensureDir(path7.dirname(inspectPath));
|
|
14559
|
+
await fs8.copy(downloadPath, inspectPath);
|
|
14448
14560
|
}
|
|
14449
14561
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "created" };
|
|
14450
14562
|
} catch (err) {
|
|
14451
14563
|
if (err instanceof DocumentDownloadSkipError) {
|
|
14452
|
-
logger.warn(`${
|
|
14564
|
+
logger.warn(`${logPrefix8} Skipped ${entry.externalId} (${entry.fileName}): ${err.message}`);
|
|
14453
14565
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "skipped" };
|
|
14454
14566
|
}
|
|
14455
14567
|
const message = err instanceof Error ? err.message : String(err);
|
|
14456
14568
|
const sizeLabel = await getFileSizeLabel(downloadPath);
|
|
14457
|
-
logger.error(`${
|
|
14569
|
+
logger.error(`${logPrefix8} Failed to create ${entry.externalId} (${entry.fileName}, ${sizeLabel}): ${message}`);
|
|
14458
14570
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "error", error: message };
|
|
14459
14571
|
} finally {
|
|
14460
|
-
await
|
|
14572
|
+
await fs8.remove(downloadPath).catch(() => void 0);
|
|
14461
14573
|
}
|
|
14462
14574
|
}
|
|
14463
14575
|
async executeReupload(stream, entry, existingDoc, tmpDir2, dryRun) {
|
|
@@ -14469,21 +14581,21 @@ var DocumentTap = class {
|
|
|
14469
14581
|
await this.target.reuploadDocument(stream.streamId, existingDoc.id, entry, downloadPath);
|
|
14470
14582
|
} else {
|
|
14471
14583
|
const inspectPath = path7.join(this.outputDir, stream.streamId, `${safeId}.${entry.extension}`);
|
|
14472
|
-
await
|
|
14473
|
-
await
|
|
14584
|
+
await fs8.ensureDir(path7.dirname(inspectPath));
|
|
14585
|
+
await fs8.copy(downloadPath, inspectPath);
|
|
14474
14586
|
}
|
|
14475
14587
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "reuploaded" };
|
|
14476
14588
|
} catch (err) {
|
|
14477
14589
|
if (err instanceof DocumentDownloadSkipError) {
|
|
14478
|
-
logger.warn(`${
|
|
14590
|
+
logger.warn(`${logPrefix8} Skipped ${entry.externalId} (${entry.fileName}): ${err.message}`);
|
|
14479
14591
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "skipped" };
|
|
14480
14592
|
}
|
|
14481
14593
|
const message = err instanceof Error ? err.message : String(err);
|
|
14482
14594
|
const sizeLabel = await getFileSizeLabel(downloadPath);
|
|
14483
|
-
logger.error(`${
|
|
14595
|
+
logger.error(`${logPrefix8} Failed to reupload ${entry.externalId} (${entry.fileName}, ${sizeLabel}): ${message}`);
|
|
14484
14596
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "error", error: message };
|
|
14485
14597
|
} finally {
|
|
14486
|
-
await
|
|
14598
|
+
await fs8.remove(downloadPath).catch(() => void 0);
|
|
14487
14599
|
}
|
|
14488
14600
|
}
|
|
14489
14601
|
async executeMetadataUpdate(entry, existingDoc, dryRun) {
|
|
@@ -14494,7 +14606,7 @@ var DocumentTap = class {
|
|
|
14494
14606
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "updated" };
|
|
14495
14607
|
} catch (err) {
|
|
14496
14608
|
const message = err instanceof Error ? err.message : String(err);
|
|
14497
|
-
logger.error(`${
|
|
14609
|
+
logger.error(`${logPrefix8} Failed to update metadata for ${entry.externalId}: ${message}`);
|
|
14498
14610
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "error", error: message };
|
|
14499
14611
|
}
|
|
14500
14612
|
}
|
|
@@ -14506,7 +14618,7 @@ var DocumentTap = class {
|
|
|
14506
14618
|
return { externalId: doc.external_id, fileName: doc.file_name, status: "deleted" };
|
|
14507
14619
|
} catch (err) {
|
|
14508
14620
|
const message = err instanceof Error ? err.message : String(err);
|
|
14509
|
-
logger.error(`${
|
|
14621
|
+
logger.error(`${logPrefix8} Failed to delete ${doc.external_id}: ${message}`);
|
|
14510
14622
|
return { externalId: doc.external_id, fileName: doc.file_name, status: "error", error: message };
|
|
14511
14623
|
}
|
|
14512
14624
|
}
|
|
@@ -14526,13 +14638,13 @@ var DocumentTap = class {
|
|
|
14526
14638
|
};
|
|
14527
14639
|
|
|
14528
14640
|
// src/sdk/models/document-target/whaly-document-target.ts
|
|
14529
|
-
import
|
|
14641
|
+
import fs10 from "fs-extra";
|
|
14530
14642
|
|
|
14531
14643
|
// src/services/whaly-document.ts
|
|
14532
14644
|
var import_form_data = __toESM(require_form_data());
|
|
14533
14645
|
import axios4 from "axios";
|
|
14534
14646
|
import axiosRetry3 from "axios-retry";
|
|
14535
|
-
import
|
|
14647
|
+
import fs9 from "fs";
|
|
14536
14648
|
import { Storage as Storage2 } from "@google-cloud/storage";
|
|
14537
14649
|
function enrichAxiosError(err) {
|
|
14538
14650
|
if (!axios4.isAxiosError(err)) return err instanceof Error ? err : new Error(String(err));
|
|
@@ -14543,7 +14655,7 @@ function enrichAxiosError(err) {
|
|
|
14543
14655
|
const detail = typeof body === "string" ? body : JSON.stringify(body ?? "");
|
|
14544
14656
|
return new Error(`${method} ${url} failed with status ${status}: ${detail}`, { cause: err });
|
|
14545
14657
|
}
|
|
14546
|
-
var
|
|
14658
|
+
var logPrefix9 = "[WhalyDocumentService]";
|
|
14547
14659
|
var MAX_RETRIES2 = 10;
|
|
14548
14660
|
var WhalyDocumentService = class {
|
|
14549
14661
|
axiosClient;
|
|
@@ -14556,7 +14668,7 @@ var WhalyDocumentService = class {
|
|
|
14556
14668
|
const gcsBucketName = process.env["WLY_GCS_BUCKET"];
|
|
14557
14669
|
if (gcsBucketName) {
|
|
14558
14670
|
this.gcsBucket = new Storage2().bucket(gcsBucketName);
|
|
14559
|
-
logger.info(`${
|
|
14671
|
+
logger.info(`${logPrefix9} Using direct GCS upload to bucket: ${gcsBucketName}`);
|
|
14560
14672
|
}
|
|
14561
14673
|
this.axiosClient = axios4.create({
|
|
14562
14674
|
baseURL: resolvedEndpoint,
|
|
@@ -14577,12 +14689,12 @@ var WhalyDocumentService = class {
|
|
|
14577
14689
|
if (retryAfter) {
|
|
14578
14690
|
const seconds = Number(retryAfter);
|
|
14579
14691
|
if (!isNaN(seconds) && seconds > 0) {
|
|
14580
|
-
logger.info(`${
|
|
14692
|
+
logger.info(`${logPrefix9} Rate limited \u2014 waiting ${seconds}s, attempt ${retryCount}/${MAX_RETRIES2}`);
|
|
14581
14693
|
return seconds * 1e3;
|
|
14582
14694
|
}
|
|
14583
14695
|
}
|
|
14584
14696
|
const delay = axiosRetry3.exponentialDelay(retryCount);
|
|
14585
|
-
logger.info(`${
|
|
14697
|
+
logger.info(`${logPrefix9} Retrying in ${delay}ms (attempt ${retryCount}/${MAX_RETRIES2}) for ${error.config?.method?.toUpperCase()} ${error.config?.url}`);
|
|
14586
14698
|
return delay;
|
|
14587
14699
|
}
|
|
14588
14700
|
});
|
|
@@ -14603,7 +14715,7 @@ var WhalyDocumentService = class {
|
|
|
14603
14715
|
if (!nextAfter) break;
|
|
14604
14716
|
after = nextAfter;
|
|
14605
14717
|
}
|
|
14606
|
-
logger.info(`${
|
|
14718
|
+
logger.info(`${logPrefix9} Fetched ${documents.length} existing documents from Whaly`);
|
|
14607
14719
|
return documents;
|
|
14608
14720
|
}
|
|
14609
14721
|
/** Upload a file to object storage. Returns storage path and size. */
|
|
@@ -14624,11 +14736,11 @@ var WhalyDocumentService = class {
|
|
|
14624
14736
|
} catch (err) {
|
|
14625
14737
|
if (attempt === maxAttempts) throw err;
|
|
14626
14738
|
const delay = Math.min(1e3 * 2 ** (attempt - 1), 3e4);
|
|
14627
|
-
logger.info(`${
|
|
14628
|
-
await new Promise((
|
|
14739
|
+
logger.info(`${logPrefix9} GCS upload retry ${attempt}/${MAX_RETRIES2} in ${delay}ms for ${destinationPath}`);
|
|
14740
|
+
await new Promise((resolve2) => setTimeout(resolve2, delay));
|
|
14629
14741
|
}
|
|
14630
14742
|
}
|
|
14631
|
-
const stat = await
|
|
14743
|
+
const stat = await fs9.promises.stat(localFilePath);
|
|
14632
14744
|
return {
|
|
14633
14745
|
storage: this.objectStorageId,
|
|
14634
14746
|
filePath: destinationPath,
|
|
@@ -14637,7 +14749,7 @@ var WhalyDocumentService = class {
|
|
|
14637
14749
|
}
|
|
14638
14750
|
async uploadFileViaAPI(destinationPath, localFilePath, fileName) {
|
|
14639
14751
|
const form = new import_form_data.default();
|
|
14640
|
-
form.append("file",
|
|
14752
|
+
form.append("file", fs9.createReadStream(localFilePath), fileName);
|
|
14641
14753
|
try {
|
|
14642
14754
|
const response = await this.axiosClient.post(
|
|
14643
14755
|
`/v1/object-storages/${this.objectStorageId}/upload`,
|
|
@@ -14681,7 +14793,7 @@ var WhalyDocumentService = class {
|
|
|
14681
14793
|
};
|
|
14682
14794
|
|
|
14683
14795
|
// src/sdk/models/document-target/whaly-document-target.ts
|
|
14684
|
-
var
|
|
14796
|
+
var logPrefix10 = "[WhalyDocumentTarget]";
|
|
14685
14797
|
var WhalyDocumentTarget = class {
|
|
14686
14798
|
config;
|
|
14687
14799
|
service;
|
|
@@ -14700,9 +14812,9 @@ var WhalyDocumentTarget = class {
|
|
|
14700
14812
|
async createDocument(streamId, entry, localFilePath) {
|
|
14701
14813
|
const destinationPath = `${streamId}/${entry.externalId}.${entry.extension}`;
|
|
14702
14814
|
const fileName = `${entry.externalId}.${entry.extension}`;
|
|
14703
|
-
logger.info(`${
|
|
14815
|
+
logger.info(`${logPrefix10} Uploading file for new document: ${entry.externalId}`);
|
|
14704
14816
|
const uploadResult = await this.service.uploadFile(destinationPath, localFilePath, fileName);
|
|
14705
|
-
const stat = await
|
|
14817
|
+
const stat = await fs10.stat(localFilePath);
|
|
14706
14818
|
await this.service.createDocument({
|
|
14707
14819
|
file_name: entry.fileName,
|
|
14708
14820
|
external_id: entry.externalId,
|
|
@@ -14717,7 +14829,7 @@ var WhalyDocumentTarget = class {
|
|
|
14717
14829
|
storage: uploadResult.storage,
|
|
14718
14830
|
metadata: entry.metadata ?? {}
|
|
14719
14831
|
});
|
|
14720
|
-
logger.info(`${
|
|
14832
|
+
logger.info(`${logPrefix10} Created document: ${entry.externalId} (${entry.fileName})`);
|
|
14721
14833
|
}
|
|
14722
14834
|
/**
|
|
14723
14835
|
* Re-upload the file and update the document record.
|
|
@@ -14725,9 +14837,9 @@ var WhalyDocumentTarget = class {
|
|
|
14725
14837
|
async reuploadDocument(streamId, docId, entry, localFilePath) {
|
|
14726
14838
|
const destinationPath = `${streamId}/${entry.externalId}.${entry.extension}`;
|
|
14727
14839
|
const fileName = `${entry.externalId}.${entry.extension}`;
|
|
14728
|
-
logger.info(`${
|
|
14840
|
+
logger.info(`${logPrefix10} Re-uploading file for document: ${entry.externalId}`);
|
|
14729
14841
|
const uploadResult = await this.service.uploadFile(destinationPath, localFilePath, fileName);
|
|
14730
|
-
const stat = await
|
|
14842
|
+
const stat = await fs10.stat(localFilePath);
|
|
14731
14843
|
await this.service.updateDocument(docId, {
|
|
14732
14844
|
external_id: entry.externalId,
|
|
14733
14845
|
file_name: entry.fileName,
|
|
@@ -14742,7 +14854,7 @@ var WhalyDocumentTarget = class {
|
|
|
14742
14854
|
storage: uploadResult.storage,
|
|
14743
14855
|
metadata: entry.metadata ?? {}
|
|
14744
14856
|
});
|
|
14745
|
-
logger.info(`${
|
|
14857
|
+
logger.info(`${logPrefix10} Re-uploaded document: ${entry.externalId} (${entry.fileName})`);
|
|
14746
14858
|
}
|
|
14747
14859
|
/** Update only the metadata fields (no file re-upload). */
|
|
14748
14860
|
async updateDocumentMetadata(docId, entry, existingDoc) {
|
|
@@ -14760,12 +14872,12 @@ var WhalyDocumentTarget = class {
|
|
|
14760
14872
|
storage: existingDoc.storage,
|
|
14761
14873
|
metadata: entry.metadata ?? {}
|
|
14762
14874
|
});
|
|
14763
|
-
logger.info(`${
|
|
14875
|
+
logger.info(`${logPrefix10} Updated metadata for document: ${entry.externalId} (${entry.fileName})`);
|
|
14764
14876
|
}
|
|
14765
14877
|
/** Delete a document record. */
|
|
14766
14878
|
async deleteDocument(docId, externalId) {
|
|
14767
14879
|
await this.service.deleteDocument(docId);
|
|
14768
|
-
logger.info(`${
|
|
14880
|
+
logger.info(`${logPrefix10} Deleted document: ${externalId} (id=${docId})`);
|
|
14769
14881
|
}
|
|
14770
14882
|
};
|
|
14771
14883
|
|
|
@@ -15104,7 +15216,7 @@ var BigQueryDBSync = class extends StreamWarehouseSyncService {
|
|
|
15104
15216
|
gracefulExit(1);
|
|
15105
15217
|
} else {
|
|
15106
15218
|
logger.error(`StreamId: ${this.streamId} - Error when checking if dataset already exists. Retrying... ${err.message} - ${err.code}`);
|
|
15107
|
-
await new Promise((
|
|
15219
|
+
await new Promise((resolve2, reject) => setTimeout(resolve2, 1e3 * retryCount));
|
|
15108
15220
|
await this.createDatabaseAndSchemaIfNotExists(retryCount + 1);
|
|
15109
15221
|
}
|
|
15110
15222
|
}
|
|
@@ -15331,8 +15443,8 @@ var BigQueryTarget = class extends ITarget {
|
|
|
15331
15443
|
};
|
|
15332
15444
|
|
|
15333
15445
|
// src/targets/cdn/main.ts
|
|
15334
|
-
import
|
|
15335
|
-
var
|
|
15446
|
+
import fs11 from "fs-extra";
|
|
15447
|
+
var logPrefix11 = "[CdnAssetTarget]";
|
|
15336
15448
|
var CdnAssetTarget = class extends AssetTarget {
|
|
15337
15449
|
cdnService;
|
|
15338
15450
|
constructor(config) {
|
|
@@ -15342,31 +15454,31 @@ var CdnAssetTarget = class extends AssetTarget {
|
|
|
15342
15454
|
async shouldSync(entry) {
|
|
15343
15455
|
const metadata = await this.cdnService.getFileMetadata(getCdnId(this.config.cdnId), entry.destinationPath);
|
|
15344
15456
|
if (!metadata.exists) {
|
|
15345
|
-
logger.debug(`${
|
|
15457
|
+
logger.debug(`${logPrefix11} ${entry.destinationPath} not in CDN \u2192 will sync`);
|
|
15346
15458
|
return true;
|
|
15347
15459
|
}
|
|
15348
15460
|
if (entry.lastModified === void 0) {
|
|
15349
|
-
logger.debug(`${
|
|
15461
|
+
logger.debug(`${logPrefix11} ${entry.destinationPath} source has no lastModified \u2192 will sync`);
|
|
15350
15462
|
return true;
|
|
15351
15463
|
}
|
|
15352
15464
|
if (metadata.lastModified === null) {
|
|
15353
|
-
logger.debug(`${
|
|
15465
|
+
logger.debug(`${logPrefix11} ${entry.destinationPath} CDN has no lastModified \u2192 will sync`);
|
|
15354
15466
|
return true;
|
|
15355
15467
|
}
|
|
15356
15468
|
const sourceIsNewer = entry.lastModified > metadata.lastModified;
|
|
15357
15469
|
if (!sourceIsNewer) {
|
|
15358
|
-
logger.debug(`${
|
|
15470
|
+
logger.debug(`${logPrefix11} Skipping ${entry.destinationPath} (CDN is up-to-date)`);
|
|
15359
15471
|
}
|
|
15360
15472
|
return sourceIsNewer;
|
|
15361
15473
|
}
|
|
15362
15474
|
async uploadAsset(asset) {
|
|
15363
|
-
const fileBuffer = await
|
|
15475
|
+
const fileBuffer = await fs11.readFile(asset.uploadPath);
|
|
15364
15476
|
await this.cdnService.uploadFile(
|
|
15365
15477
|
getCdnId(this.config.cdnId),
|
|
15366
15478
|
asset.entry.destinationPath,
|
|
15367
15479
|
fileBuffer
|
|
15368
15480
|
);
|
|
15369
|
-
logger.info(`${
|
|
15481
|
+
logger.info(`${logPrefix11} Uploaded ${asset.entry.destinationPath} (${fileBuffer.length} bytes)`);
|
|
15370
15482
|
}
|
|
15371
15483
|
};
|
|
15372
15484
|
|
|
@@ -15435,6 +15547,7 @@ export {
|
|
|
15435
15547
|
GCSStateProvider,
|
|
15436
15548
|
ITarget,
|
|
15437
15549
|
ImageTransform,
|
|
15550
|
+
LocalStorageService,
|
|
15438
15551
|
MIME_TYPES,
|
|
15439
15552
|
MissingFieldInSchemaError,
|
|
15440
15553
|
MissingSchemaError,
|