@whaly/connector-sdk 0.3.9 → 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 +84 -3
- package/dist/index.d.ts +84 -3
- package/dist/index.js +205 -72
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +234 -103
- 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);
|
|
@@ -10853,6 +10853,16 @@ function getMimeType(filePathOrExt) {
|
|
|
10853
10853
|
const ext = filePathOrExt.startsWith(".") ? filePathOrExt.toLowerCase() : path.extname(filePathOrExt).toLowerCase();
|
|
10854
10854
|
return MIME_TYPES[ext] ?? "application/octet-stream";
|
|
10855
10855
|
}
|
|
10856
|
+
var EXTENSION_BY_MIME = Object.entries(MIME_TYPES).reduce(
|
|
10857
|
+
(acc, [ext, mime]) => {
|
|
10858
|
+
if (!acc[mime]) acc[mime] = ext;
|
|
10859
|
+
return acc;
|
|
10860
|
+
},
|
|
10861
|
+
{}
|
|
10862
|
+
);
|
|
10863
|
+
function getExtension(mimeType) {
|
|
10864
|
+
return EXTENSION_BY_MIME[mimeType] ?? ".bin";
|
|
10865
|
+
}
|
|
10856
10866
|
|
|
10857
10867
|
// src/sdk/models/replication.ts
|
|
10858
10868
|
var ReplicationMethod = /* @__PURE__ */ ((ReplicationMethod2) => {
|
|
@@ -12442,13 +12452,13 @@ var ITarget = class _ITarget {
|
|
|
12442
12452
|
const dbSyncInstance = stream.getDbSync();
|
|
12443
12453
|
const recordWithrenamedColumns = dbSyncInstance.renameColumns(recordWithDecimal);
|
|
12444
12454
|
const serializedRecord = this.getSerializedRecord(streamId, recordWithrenamedColumns);
|
|
12445
|
-
return new Promise((
|
|
12455
|
+
return new Promise((resolve2, reject) => {
|
|
12446
12456
|
stream.getFileToLoad().stream.write(serializedRecord, (error) => {
|
|
12447
12457
|
if (error) {
|
|
12448
12458
|
reject(error);
|
|
12449
12459
|
}
|
|
12450
12460
|
stream.incrementBatchedRowCount();
|
|
12451
|
-
|
|
12461
|
+
resolve2();
|
|
12452
12462
|
});
|
|
12453
12463
|
});
|
|
12454
12464
|
} catch (err) {
|
|
@@ -12589,11 +12599,11 @@ var ITarget = class _ITarget {
|
|
|
12589
12599
|
const streamState = this.streams[streamId];
|
|
12590
12600
|
if (!streamState || streamState.getBatchedRowCount() === 0) continue;
|
|
12591
12601
|
const fileToLoad = streamState.getFileToLoad();
|
|
12592
|
-
await new Promise((
|
|
12602
|
+
await new Promise((resolve2, reject) => {
|
|
12593
12603
|
fileToLoad.stream.end(() => {
|
|
12594
12604
|
fileToLoad.stream.close((err) => {
|
|
12595
12605
|
if (err) reject(err);
|
|
12596
|
-
else
|
|
12606
|
+
else resolve2();
|
|
12597
12607
|
});
|
|
12598
12608
|
});
|
|
12599
12609
|
});
|
|
@@ -13124,18 +13134,18 @@ async function* rowGeneratorFromCsv(path8, fileConfig) {
|
|
|
13124
13134
|
}
|
|
13125
13135
|
}
|
|
13126
13136
|
async function countCsvLines(filePath) {
|
|
13127
|
-
return new Promise((
|
|
13137
|
+
return new Promise((resolve2, reject) => {
|
|
13128
13138
|
let newlines = 0;
|
|
13129
13139
|
createReadStream(filePath).on("data", (chunk2) => {
|
|
13130
13140
|
const buf = Buffer.isBuffer(chunk2) ? chunk2 : Buffer.from(chunk2);
|
|
13131
13141
|
for (let i = 0; i < buf.length; i++) {
|
|
13132
13142
|
if (buf[i] === 10) newlines++;
|
|
13133
13143
|
}
|
|
13134
|
-
}).on("end", () =>
|
|
13144
|
+
}).on("end", () => resolve2(Math.max(0, newlines - 1))).on("error", reject);
|
|
13135
13145
|
});
|
|
13136
13146
|
}
|
|
13137
13147
|
var checkCsvHeaderRow = async (path8, fileConfig) => {
|
|
13138
|
-
return new Promise((
|
|
13148
|
+
return new Promise((resolve2, reject) => {
|
|
13139
13149
|
const colsWithParsingConfig = Object.keys(fileConfig.fields).map((key) => key.trim());
|
|
13140
13150
|
console.debug(`${logPrefix} CSV Expected columns:`, colsWithParsingConfig.map((col) => {
|
|
13141
13151
|
const info = getStringHexInfo(col);
|
|
@@ -13210,7 +13220,7 @@ var checkCsvHeaderRow = async (path8, fileConfig) => {
|
|
|
13210
13220
|
reject(new Error(`Error processing CSV file: ${error.message}`));
|
|
13211
13221
|
});
|
|
13212
13222
|
initialReadStream.on("close", () => {
|
|
13213
|
-
|
|
13223
|
+
resolve2();
|
|
13214
13224
|
});
|
|
13215
13225
|
});
|
|
13216
13226
|
};
|
|
@@ -13791,6 +13801,16 @@ var CloudStorageService = class {
|
|
|
13791
13801
|
throw new Error(format6(`error writing GCS object gs://${this.bucket.name}/${objectPath}, err: %s`, err?.message));
|
|
13792
13802
|
}
|
|
13793
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
|
+
}
|
|
13794
13814
|
/**
|
|
13795
13815
|
* Uploads a local file to the bucket with a unique name based on prefix, streamId, and UUID.
|
|
13796
13816
|
* Files are stored under `<prefix>/<run-id>/` when the RUN_ID env var is set,
|
|
@@ -13819,6 +13839,108 @@ var CloudStorageService = class {
|
|
|
13819
13839
|
}
|
|
13820
13840
|
};
|
|
13821
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
|
+
|
|
13822
13944
|
// src/services/zip.ts
|
|
13823
13945
|
import * as fse from "fs-extra";
|
|
13824
13946
|
import decompress from "decompress";
|
|
@@ -13831,7 +13953,7 @@ var unzip = async (zipFilePath, extractedPath) => {
|
|
|
13831
13953
|
// src/services/cdn.ts
|
|
13832
13954
|
import axios3 from "axios";
|
|
13833
13955
|
import axiosRetry2 from "axios-retry";
|
|
13834
|
-
var
|
|
13956
|
+
var logPrefix6 = "[CdnService]";
|
|
13835
13957
|
var MAX_RETRIES = 10;
|
|
13836
13958
|
var CdnService = class {
|
|
13837
13959
|
axiosClient;
|
|
@@ -13857,12 +13979,12 @@ var CdnService = class {
|
|
|
13857
13979
|
if (retryAfter) {
|
|
13858
13980
|
const seconds = Number(retryAfter);
|
|
13859
13981
|
if (!isNaN(seconds) && seconds > 0) {
|
|
13860
|
-
logger.info(`${
|
|
13982
|
+
logger.info(`${logPrefix6} Rate limited \u2014 waiting ${seconds}s (Retry-After header), attempt ${retryCount}/${MAX_RETRIES}`);
|
|
13861
13983
|
return seconds * 1e3;
|
|
13862
13984
|
}
|
|
13863
13985
|
}
|
|
13864
13986
|
const delay = axiosRetry2.exponentialDelay(retryCount);
|
|
13865
|
-
logger.info(`${
|
|
13987
|
+
logger.info(`${logPrefix6} Retrying in ${delay}ms (attempt ${retryCount}/${MAX_RETRIES}) for ${error.config?.method?.toUpperCase()} ${error.config?.url}`);
|
|
13866
13988
|
return delay;
|
|
13867
13989
|
}
|
|
13868
13990
|
});
|
|
@@ -13888,7 +14010,7 @@ var CdnService = class {
|
|
|
13888
14010
|
const status = err.response?.status;
|
|
13889
14011
|
if (status === 404) return { exists: false, lastModified: null, contentType: null };
|
|
13890
14012
|
if (status === 405) {
|
|
13891
|
-
logger.warn(`${
|
|
14013
|
+
logger.warn(`${logPrefix6} HEAD not supported for ${url}, treating file as absent`);
|
|
13892
14014
|
return { exists: false, lastModified: null, contentType: null };
|
|
13893
14015
|
}
|
|
13894
14016
|
this.throwMeaningfulError(err);
|
|
@@ -13912,11 +14034,11 @@ var CdnService = class {
|
|
|
13912
14034
|
async uploadFile(cdnId, fileName, fileBuffer) {
|
|
13913
14035
|
const url = `/v1/cdn/${cdnId}/files/${encodeURIComponent(fileName)}`;
|
|
13914
14036
|
try {
|
|
13915
|
-
logger.info(`${
|
|
14037
|
+
logger.info(`${logPrefix6} Uploading ${fileName} (${fileBuffer.length} bytes) to CDN ${cdnId}`);
|
|
13916
14038
|
const form = new FormData();
|
|
13917
14039
|
form.append("file", new Blob([fileBuffer]), fileName);
|
|
13918
14040
|
const response = await this.axiosClient.put(url, form);
|
|
13919
|
-
logger.info(`${
|
|
14041
|
+
logger.info(`${logPrefix6} Successfully uploaded ${fileName} (status ${response.status})`);
|
|
13920
14042
|
return {
|
|
13921
14043
|
filePath: response.data?.filePath ?? `/org/${cdnId}/file/${fileName}`
|
|
13922
14044
|
};
|
|
@@ -13957,9 +14079,9 @@ var AssetStream = class {
|
|
|
13957
14079
|
};
|
|
13958
14080
|
|
|
13959
14081
|
// src/sdk/models/asset-tap/asset-tap.ts
|
|
13960
|
-
import
|
|
14082
|
+
import fs7 from "fs-extra";
|
|
13961
14083
|
import path5 from "path";
|
|
13962
|
-
var
|
|
14084
|
+
var logPrefix7 = "[AssetTap]";
|
|
13963
14085
|
function inferContentType(filePath, fallback) {
|
|
13964
14086
|
const mime = getMimeType(filePath);
|
|
13965
14087
|
return mime !== "application/octet-stream" ? mime : fallback;
|
|
@@ -13967,7 +14089,7 @@ function inferContentType(filePath, fallback) {
|
|
|
13967
14089
|
function deriveManifestMode(streams) {
|
|
13968
14090
|
const modes = new Set(streams.map((s) => s.replicationMode));
|
|
13969
14091
|
if (modes.size > 1) {
|
|
13970
|
-
logger.warn(`${
|
|
14092
|
+
logger.warn(`${logPrefix7} Streams have mixed replication modes (${[...modes].join(", ")}). Manifest will report "FULL".`);
|
|
13971
14093
|
return "FULL";
|
|
13972
14094
|
}
|
|
13973
14095
|
return streams[0]?.replicationMode ?? "INCREMENTAL";
|
|
@@ -13989,21 +14111,21 @@ var AssetTap = class {
|
|
|
13989
14111
|
const dryRun = isDryRun();
|
|
13990
14112
|
const dryRunLimit = dryRun ? getDryRunLimit() : void 0;
|
|
13991
14113
|
if (dryRun) {
|
|
13992
|
-
logger.info(`${
|
|
13993
|
-
await
|
|
14114
|
+
logger.info(`${logPrefix7} [DRY_RUN] mode active \u2014 skipping CDN checks and uploads`);
|
|
14115
|
+
await fs7.emptyDir(this.outputDir);
|
|
13994
14116
|
if (dryRunLimit !== void 0) {
|
|
13995
|
-
logger.info(`${
|
|
14117
|
+
logger.info(`${logPrefix7} [DRY_RUN] Limit: ${dryRunLimit} assets per stream`);
|
|
13996
14118
|
}
|
|
13997
14119
|
} else if (process.env["DRY_RUN_LIMIT"] !== void 0) {
|
|
13998
|
-
logger.warn(`${
|
|
14120
|
+
logger.warn(`${logPrefix7} DRY_RUN_LIMIT is set but DRY_RUN is not active \u2014 limit will be ignored`);
|
|
13999
14121
|
}
|
|
14000
14122
|
const tmpDir2 = path5.join(this.outputDir, "tmp");
|
|
14001
|
-
await
|
|
14123
|
+
await fs7.ensureDir(tmpDir2);
|
|
14002
14124
|
const streamManifests = [];
|
|
14003
14125
|
let entryIndex = 0;
|
|
14004
14126
|
let totalSummary = { total: 0, uploaded: 0, skipped: 0, errors: 0 };
|
|
14005
14127
|
for (const stream of this.streams) {
|
|
14006
|
-
logger.info(`${
|
|
14128
|
+
logger.info(`${logPrefix7} Processing stream: ${stream.streamId} (mode=${stream.replicationMode}, concurrency=${this.concurrency})`);
|
|
14007
14129
|
const assetEntries = [];
|
|
14008
14130
|
let streamAssetCount = 0;
|
|
14009
14131
|
await processFromAsyncIterable(
|
|
@@ -14012,11 +14134,11 @@ var AssetTap = class {
|
|
|
14012
14134
|
if (dryRunLimit !== void 0 && streamAssetCount >= dryRunLimit) {
|
|
14013
14135
|
return "stop";
|
|
14014
14136
|
}
|
|
14015
|
-
logger.debug(`${
|
|
14137
|
+
logger.debug(`${logPrefix7} Processing entry: ${entry.sourcePath}`);
|
|
14016
14138
|
if (stream.replicationMode === "INCREMENTAL" && !dryRun) {
|
|
14017
14139
|
const shouldSync = await this.target.shouldSync(entry);
|
|
14018
14140
|
if (!shouldSync) {
|
|
14019
|
-
logger.debug(`${
|
|
14141
|
+
logger.debug(`${logPrefix7} Skipping ${entry.sourcePath} (up-to-date)`);
|
|
14020
14142
|
assetEntries.push({
|
|
14021
14143
|
sourcePath: entry.sourcePath,
|
|
14022
14144
|
destinationPath: entry.destinationPath,
|
|
@@ -14039,7 +14161,7 @@ var AssetTap = class {
|
|
|
14039
14161
|
await stream.downloadEntry(entry, downloadedPath);
|
|
14040
14162
|
uploadPath = await stream.transformFile(downloadedPath, entry);
|
|
14041
14163
|
const wasTransformed = uploadPath !== downloadedPath;
|
|
14042
|
-
const stat = await
|
|
14164
|
+
const stat = await fs7.stat(uploadPath);
|
|
14043
14165
|
const processed = {
|
|
14044
14166
|
entry,
|
|
14045
14167
|
downloadedPath,
|
|
@@ -14052,8 +14174,15 @@ var AssetTap = class {
|
|
|
14052
14174
|
await this.target.uploadAsset(processed);
|
|
14053
14175
|
} else {
|
|
14054
14176
|
const inspectPath = path5.join(this.outputDir, stream.streamId, entry.destinationPath);
|
|
14055
|
-
await
|
|
14056
|
-
await
|
|
14177
|
+
await fs7.ensureDir(path5.dirname(inspectPath));
|
|
14178
|
+
await fs7.copy(uploadPath, inspectPath);
|
|
14179
|
+
if (wasTransformed) {
|
|
14180
|
+
const baseName = path5.basename(entry.destinationPath, path5.extname(entry.destinationPath));
|
|
14181
|
+
const origExt = getExtension(entry.contentType);
|
|
14182
|
+
const originalPath = path5.join(this.outputDir, "originals", `${baseName}${origExt}`);
|
|
14183
|
+
await fs7.ensureDir(path5.dirname(originalPath));
|
|
14184
|
+
await fs7.copy(downloadedPath, originalPath);
|
|
14185
|
+
}
|
|
14057
14186
|
}
|
|
14058
14187
|
assetEntries.push({
|
|
14059
14188
|
sourcePath: entry.sourcePath,
|
|
@@ -14065,10 +14194,10 @@ var AssetTap = class {
|
|
|
14065
14194
|
status: "uploaded",
|
|
14066
14195
|
transformed: wasTransformed
|
|
14067
14196
|
});
|
|
14068
|
-
logger.info(`${
|
|
14197
|
+
logger.info(`${logPrefix7} ${dryRun ? "[DRY_RUN] Processed" : "Uploaded"} ${entry.sourcePath} \u2192 ${entry.destinationPath}`);
|
|
14069
14198
|
} catch (err) {
|
|
14070
14199
|
const message = err instanceof Error ? err.message : String(err);
|
|
14071
|
-
logger.error(`${
|
|
14200
|
+
logger.error(`${logPrefix7} Failed to process ${entry.sourcePath}: ${message}`);
|
|
14072
14201
|
assetEntries.push({
|
|
14073
14202
|
sourcePath: entry.sourcePath,
|
|
14074
14203
|
destinationPath: entry.destinationPath,
|
|
@@ -14081,13 +14210,13 @@ var AssetTap = class {
|
|
|
14081
14210
|
error: message
|
|
14082
14211
|
});
|
|
14083
14212
|
} finally {
|
|
14084
|
-
await
|
|
14213
|
+
await fs7.remove(downloadedPath).catch(() => void 0);
|
|
14085
14214
|
if (uploadPath !== downloadedPath) {
|
|
14086
|
-
await
|
|
14215
|
+
await fs7.remove(uploadPath).catch(() => void 0);
|
|
14087
14216
|
}
|
|
14088
14217
|
}
|
|
14089
14218
|
if (dryRunLimit !== void 0 && streamAssetCount >= dryRunLimit) {
|
|
14090
|
-
logger.info(`${
|
|
14219
|
+
logger.info(`${logPrefix7} [DRY_RUN] Reached limit of ${dryRunLimit} for stream "${stream.streamId}", stopping.`);
|
|
14091
14220
|
return "stop";
|
|
14092
14221
|
}
|
|
14093
14222
|
return "continue";
|
|
@@ -14118,12 +14247,12 @@ var AssetTap = class {
|
|
|
14118
14247
|
streams: streamManifests,
|
|
14119
14248
|
summary: totalSummary
|
|
14120
14249
|
};
|
|
14121
|
-
await
|
|
14122
|
-
await
|
|
14250
|
+
await fs7.ensureDir(this.outputDir);
|
|
14251
|
+
await fs7.writeJson(path5.join(this.outputDir, "manifest.json"), manifest, { spaces: 2 });
|
|
14123
14252
|
if (!dryRun) {
|
|
14124
14253
|
await this.target.complete();
|
|
14125
14254
|
}
|
|
14126
|
-
logger.info(`${
|
|
14255
|
+
logger.info(`${logPrefix7} Sync complete. Uploaded=${totalSummary.uploaded} Skipped=${totalSummary.skipped} Errors=${totalSummary.errors}`);
|
|
14127
14256
|
return manifest;
|
|
14128
14257
|
}
|
|
14129
14258
|
};
|
|
@@ -14161,8 +14290,8 @@ var ImageTransform = class {
|
|
|
14161
14290
|
*/
|
|
14162
14291
|
static async toWebp(inputPath, options) {
|
|
14163
14292
|
const dir = path6.dirname(inputPath);
|
|
14164
|
-
const
|
|
14165
|
-
const outputPath = path6.join(dir, `${
|
|
14293
|
+
const basename2 = path6.basename(inputPath, path6.extname(inputPath));
|
|
14294
|
+
const outputPath = path6.join(dir, `${basename2}.webp`);
|
|
14166
14295
|
let pipeline = sharp(inputPath);
|
|
14167
14296
|
const hasSize = options.width !== void 0 && options.height !== void 0;
|
|
14168
14297
|
if (hasSize) {
|
|
@@ -14270,7 +14399,7 @@ var DocumentStream = class {
|
|
|
14270
14399
|
};
|
|
14271
14400
|
|
|
14272
14401
|
// src/sdk/models/document-tap/document-tap.ts
|
|
14273
|
-
import
|
|
14402
|
+
import fs8 from "fs-extra";
|
|
14274
14403
|
import path7 from "path";
|
|
14275
14404
|
var BYTES_PER_KB = 1024;
|
|
14276
14405
|
function formatFileSize(bytes) {
|
|
@@ -14280,13 +14409,13 @@ function formatFileSize(bytes) {
|
|
|
14280
14409
|
}
|
|
14281
14410
|
async function getFileSizeLabel(filePath) {
|
|
14282
14411
|
try {
|
|
14283
|
-
const stat = await
|
|
14412
|
+
const stat = await fs8.stat(filePath);
|
|
14284
14413
|
return formatFileSize(stat.size);
|
|
14285
14414
|
} catch {
|
|
14286
14415
|
return "unknown size";
|
|
14287
14416
|
}
|
|
14288
14417
|
}
|
|
14289
|
-
var
|
|
14418
|
+
var logPrefix8 = "[DocumentTap]";
|
|
14290
14419
|
var DocumentTap = class {
|
|
14291
14420
|
config;
|
|
14292
14421
|
outputDir;
|
|
@@ -14305,32 +14434,32 @@ var DocumentTap = class {
|
|
|
14305
14434
|
}
|
|
14306
14435
|
async sync() {
|
|
14307
14436
|
if (!this.target) {
|
|
14308
|
-
throw new Error(`${
|
|
14437
|
+
throw new Error(`${logPrefix8} No target set. Assign a WhalyDocumentTarget before calling sync().`);
|
|
14309
14438
|
}
|
|
14310
14439
|
await this.init();
|
|
14311
14440
|
if (!this.stream) {
|
|
14312
|
-
throw new Error(`${
|
|
14441
|
+
throw new Error(`${logPrefix8} No stream set. Assign this.stream in init().`);
|
|
14313
14442
|
}
|
|
14314
14443
|
const dryRun = isDryRun();
|
|
14315
14444
|
const dryRunLimit = dryRun ? getDryRunLimit() : void 0;
|
|
14316
14445
|
if (dryRun) {
|
|
14317
|
-
logger.info(`${
|
|
14318
|
-
await
|
|
14446
|
+
logger.info(`${logPrefix8} [DRY_RUN] mode active \u2014 skipping API calls and uploads`);
|
|
14447
|
+
await fs8.emptyDir(this.outputDir);
|
|
14319
14448
|
if (dryRunLimit !== void 0) {
|
|
14320
|
-
logger.info(`${
|
|
14449
|
+
logger.info(`${logPrefix8} [DRY_RUN] Limit: ${dryRunLimit} documents per stream`);
|
|
14321
14450
|
}
|
|
14322
14451
|
} else if (process.env["DRY_RUN_LIMIT"] !== void 0) {
|
|
14323
|
-
logger.warn(`${
|
|
14452
|
+
logger.warn(`${logPrefix8} DRY_RUN_LIMIT is set but DRY_RUN is not active \u2014 limit will be ignored`);
|
|
14324
14453
|
}
|
|
14325
14454
|
const tmpDir2 = path7.join(this.outputDir, "tmp");
|
|
14326
|
-
await
|
|
14455
|
+
await fs8.ensureDir(tmpDir2);
|
|
14327
14456
|
try {
|
|
14328
14457
|
const stream = this.stream;
|
|
14329
|
-
logger.info(`${
|
|
14458
|
+
logger.info(`${logPrefix8} Processing stream: ${stream.streamId}`);
|
|
14330
14459
|
const sourceEntries = await this.collectSourceEntries(stream, dryRunLimit);
|
|
14331
14460
|
const existingDocs = dryRun ? [] : await this.target.listExistingDocuments();
|
|
14332
14461
|
const diff = this.computeDiff(stream, sourceEntries, existingDocs);
|
|
14333
|
-
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}`);
|
|
14334
14463
|
const entries = [];
|
|
14335
14464
|
const createTasks = diff.toCreate.map((entry) => async () => {
|
|
14336
14465
|
return this.executeCreate(stream, entry, tmpDir2, dryRun);
|
|
@@ -14362,12 +14491,12 @@ var DocumentTap = class {
|
|
|
14362
14491
|
streams: [streamManifest],
|
|
14363
14492
|
summary: streamSummary
|
|
14364
14493
|
};
|
|
14365
|
-
await
|
|
14366
|
-
await
|
|
14367
|
-
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}`);
|
|
14368
14497
|
return manifest;
|
|
14369
14498
|
} finally {
|
|
14370
|
-
await
|
|
14499
|
+
await fs8.remove(tmpDir2).catch(() => void 0);
|
|
14371
14500
|
}
|
|
14372
14501
|
}
|
|
14373
14502
|
async collectSourceEntries(stream, limit) {
|
|
@@ -14426,21 +14555,21 @@ var DocumentTap = class {
|
|
|
14426
14555
|
await this.target.createDocument(stream.streamId, entry, downloadPath);
|
|
14427
14556
|
} else {
|
|
14428
14557
|
const inspectPath = path7.join(this.outputDir, stream.streamId, `${safeId}.${entry.extension}`);
|
|
14429
|
-
await
|
|
14430
|
-
await
|
|
14558
|
+
await fs8.ensureDir(path7.dirname(inspectPath));
|
|
14559
|
+
await fs8.copy(downloadPath, inspectPath);
|
|
14431
14560
|
}
|
|
14432
14561
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "created" };
|
|
14433
14562
|
} catch (err) {
|
|
14434
14563
|
if (err instanceof DocumentDownloadSkipError) {
|
|
14435
|
-
logger.warn(`${
|
|
14564
|
+
logger.warn(`${logPrefix8} Skipped ${entry.externalId} (${entry.fileName}): ${err.message}`);
|
|
14436
14565
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "skipped" };
|
|
14437
14566
|
}
|
|
14438
14567
|
const message = err instanceof Error ? err.message : String(err);
|
|
14439
14568
|
const sizeLabel = await getFileSizeLabel(downloadPath);
|
|
14440
|
-
logger.error(`${
|
|
14569
|
+
logger.error(`${logPrefix8} Failed to create ${entry.externalId} (${entry.fileName}, ${sizeLabel}): ${message}`);
|
|
14441
14570
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "error", error: message };
|
|
14442
14571
|
} finally {
|
|
14443
|
-
await
|
|
14572
|
+
await fs8.remove(downloadPath).catch(() => void 0);
|
|
14444
14573
|
}
|
|
14445
14574
|
}
|
|
14446
14575
|
async executeReupload(stream, entry, existingDoc, tmpDir2, dryRun) {
|
|
@@ -14452,21 +14581,21 @@ var DocumentTap = class {
|
|
|
14452
14581
|
await this.target.reuploadDocument(stream.streamId, existingDoc.id, entry, downloadPath);
|
|
14453
14582
|
} else {
|
|
14454
14583
|
const inspectPath = path7.join(this.outputDir, stream.streamId, `${safeId}.${entry.extension}`);
|
|
14455
|
-
await
|
|
14456
|
-
await
|
|
14584
|
+
await fs8.ensureDir(path7.dirname(inspectPath));
|
|
14585
|
+
await fs8.copy(downloadPath, inspectPath);
|
|
14457
14586
|
}
|
|
14458
14587
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "reuploaded" };
|
|
14459
14588
|
} catch (err) {
|
|
14460
14589
|
if (err instanceof DocumentDownloadSkipError) {
|
|
14461
|
-
logger.warn(`${
|
|
14590
|
+
logger.warn(`${logPrefix8} Skipped ${entry.externalId} (${entry.fileName}): ${err.message}`);
|
|
14462
14591
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "skipped" };
|
|
14463
14592
|
}
|
|
14464
14593
|
const message = err instanceof Error ? err.message : String(err);
|
|
14465
14594
|
const sizeLabel = await getFileSizeLabel(downloadPath);
|
|
14466
|
-
logger.error(`${
|
|
14595
|
+
logger.error(`${logPrefix8} Failed to reupload ${entry.externalId} (${entry.fileName}, ${sizeLabel}): ${message}`);
|
|
14467
14596
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "error", error: message };
|
|
14468
14597
|
} finally {
|
|
14469
|
-
await
|
|
14598
|
+
await fs8.remove(downloadPath).catch(() => void 0);
|
|
14470
14599
|
}
|
|
14471
14600
|
}
|
|
14472
14601
|
async executeMetadataUpdate(entry, existingDoc, dryRun) {
|
|
@@ -14477,7 +14606,7 @@ var DocumentTap = class {
|
|
|
14477
14606
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "updated" };
|
|
14478
14607
|
} catch (err) {
|
|
14479
14608
|
const message = err instanceof Error ? err.message : String(err);
|
|
14480
|
-
logger.error(`${
|
|
14609
|
+
logger.error(`${logPrefix8} Failed to update metadata for ${entry.externalId}: ${message}`);
|
|
14481
14610
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "error", error: message };
|
|
14482
14611
|
}
|
|
14483
14612
|
}
|
|
@@ -14489,7 +14618,7 @@ var DocumentTap = class {
|
|
|
14489
14618
|
return { externalId: doc.external_id, fileName: doc.file_name, status: "deleted" };
|
|
14490
14619
|
} catch (err) {
|
|
14491
14620
|
const message = err instanceof Error ? err.message : String(err);
|
|
14492
|
-
logger.error(`${
|
|
14621
|
+
logger.error(`${logPrefix8} Failed to delete ${doc.external_id}: ${message}`);
|
|
14493
14622
|
return { externalId: doc.external_id, fileName: doc.file_name, status: "error", error: message };
|
|
14494
14623
|
}
|
|
14495
14624
|
}
|
|
@@ -14509,13 +14638,13 @@ var DocumentTap = class {
|
|
|
14509
14638
|
};
|
|
14510
14639
|
|
|
14511
14640
|
// src/sdk/models/document-target/whaly-document-target.ts
|
|
14512
|
-
import
|
|
14641
|
+
import fs10 from "fs-extra";
|
|
14513
14642
|
|
|
14514
14643
|
// src/services/whaly-document.ts
|
|
14515
14644
|
var import_form_data = __toESM(require_form_data());
|
|
14516
14645
|
import axios4 from "axios";
|
|
14517
14646
|
import axiosRetry3 from "axios-retry";
|
|
14518
|
-
import
|
|
14647
|
+
import fs9 from "fs";
|
|
14519
14648
|
import { Storage as Storage2 } from "@google-cloud/storage";
|
|
14520
14649
|
function enrichAxiosError(err) {
|
|
14521
14650
|
if (!axios4.isAxiosError(err)) return err instanceof Error ? err : new Error(String(err));
|
|
@@ -14526,7 +14655,7 @@ function enrichAxiosError(err) {
|
|
|
14526
14655
|
const detail = typeof body === "string" ? body : JSON.stringify(body ?? "");
|
|
14527
14656
|
return new Error(`${method} ${url} failed with status ${status}: ${detail}`, { cause: err });
|
|
14528
14657
|
}
|
|
14529
|
-
var
|
|
14658
|
+
var logPrefix9 = "[WhalyDocumentService]";
|
|
14530
14659
|
var MAX_RETRIES2 = 10;
|
|
14531
14660
|
var WhalyDocumentService = class {
|
|
14532
14661
|
axiosClient;
|
|
@@ -14539,7 +14668,7 @@ var WhalyDocumentService = class {
|
|
|
14539
14668
|
const gcsBucketName = process.env["WLY_GCS_BUCKET"];
|
|
14540
14669
|
if (gcsBucketName) {
|
|
14541
14670
|
this.gcsBucket = new Storage2().bucket(gcsBucketName);
|
|
14542
|
-
logger.info(`${
|
|
14671
|
+
logger.info(`${logPrefix9} Using direct GCS upload to bucket: ${gcsBucketName}`);
|
|
14543
14672
|
}
|
|
14544
14673
|
this.axiosClient = axios4.create({
|
|
14545
14674
|
baseURL: resolvedEndpoint,
|
|
@@ -14560,12 +14689,12 @@ var WhalyDocumentService = class {
|
|
|
14560
14689
|
if (retryAfter) {
|
|
14561
14690
|
const seconds = Number(retryAfter);
|
|
14562
14691
|
if (!isNaN(seconds) && seconds > 0) {
|
|
14563
|
-
logger.info(`${
|
|
14692
|
+
logger.info(`${logPrefix9} Rate limited \u2014 waiting ${seconds}s, attempt ${retryCount}/${MAX_RETRIES2}`);
|
|
14564
14693
|
return seconds * 1e3;
|
|
14565
14694
|
}
|
|
14566
14695
|
}
|
|
14567
14696
|
const delay = axiosRetry3.exponentialDelay(retryCount);
|
|
14568
|
-
logger.info(`${
|
|
14697
|
+
logger.info(`${logPrefix9} Retrying in ${delay}ms (attempt ${retryCount}/${MAX_RETRIES2}) for ${error.config?.method?.toUpperCase()} ${error.config?.url}`);
|
|
14569
14698
|
return delay;
|
|
14570
14699
|
}
|
|
14571
14700
|
});
|
|
@@ -14586,7 +14715,7 @@ var WhalyDocumentService = class {
|
|
|
14586
14715
|
if (!nextAfter) break;
|
|
14587
14716
|
after = nextAfter;
|
|
14588
14717
|
}
|
|
14589
|
-
logger.info(`${
|
|
14718
|
+
logger.info(`${logPrefix9} Fetched ${documents.length} existing documents from Whaly`);
|
|
14590
14719
|
return documents;
|
|
14591
14720
|
}
|
|
14592
14721
|
/** Upload a file to object storage. Returns storage path and size. */
|
|
@@ -14607,11 +14736,11 @@ var WhalyDocumentService = class {
|
|
|
14607
14736
|
} catch (err) {
|
|
14608
14737
|
if (attempt === maxAttempts) throw err;
|
|
14609
14738
|
const delay = Math.min(1e3 * 2 ** (attempt - 1), 3e4);
|
|
14610
|
-
logger.info(`${
|
|
14611
|
-
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));
|
|
14612
14741
|
}
|
|
14613
14742
|
}
|
|
14614
|
-
const stat = await
|
|
14743
|
+
const stat = await fs9.promises.stat(localFilePath);
|
|
14615
14744
|
return {
|
|
14616
14745
|
storage: this.objectStorageId,
|
|
14617
14746
|
filePath: destinationPath,
|
|
@@ -14620,7 +14749,7 @@ var WhalyDocumentService = class {
|
|
|
14620
14749
|
}
|
|
14621
14750
|
async uploadFileViaAPI(destinationPath, localFilePath, fileName) {
|
|
14622
14751
|
const form = new import_form_data.default();
|
|
14623
|
-
form.append("file",
|
|
14752
|
+
form.append("file", fs9.createReadStream(localFilePath), fileName);
|
|
14624
14753
|
try {
|
|
14625
14754
|
const response = await this.axiosClient.post(
|
|
14626
14755
|
`/v1/object-storages/${this.objectStorageId}/upload`,
|
|
@@ -14664,7 +14793,7 @@ var WhalyDocumentService = class {
|
|
|
14664
14793
|
};
|
|
14665
14794
|
|
|
14666
14795
|
// src/sdk/models/document-target/whaly-document-target.ts
|
|
14667
|
-
var
|
|
14796
|
+
var logPrefix10 = "[WhalyDocumentTarget]";
|
|
14668
14797
|
var WhalyDocumentTarget = class {
|
|
14669
14798
|
config;
|
|
14670
14799
|
service;
|
|
@@ -14683,9 +14812,9 @@ var WhalyDocumentTarget = class {
|
|
|
14683
14812
|
async createDocument(streamId, entry, localFilePath) {
|
|
14684
14813
|
const destinationPath = `${streamId}/${entry.externalId}.${entry.extension}`;
|
|
14685
14814
|
const fileName = `${entry.externalId}.${entry.extension}`;
|
|
14686
|
-
logger.info(`${
|
|
14815
|
+
logger.info(`${logPrefix10} Uploading file for new document: ${entry.externalId}`);
|
|
14687
14816
|
const uploadResult = await this.service.uploadFile(destinationPath, localFilePath, fileName);
|
|
14688
|
-
const stat = await
|
|
14817
|
+
const stat = await fs10.stat(localFilePath);
|
|
14689
14818
|
await this.service.createDocument({
|
|
14690
14819
|
file_name: entry.fileName,
|
|
14691
14820
|
external_id: entry.externalId,
|
|
@@ -14700,7 +14829,7 @@ var WhalyDocumentTarget = class {
|
|
|
14700
14829
|
storage: uploadResult.storage,
|
|
14701
14830
|
metadata: entry.metadata ?? {}
|
|
14702
14831
|
});
|
|
14703
|
-
logger.info(`${
|
|
14832
|
+
logger.info(`${logPrefix10} Created document: ${entry.externalId} (${entry.fileName})`);
|
|
14704
14833
|
}
|
|
14705
14834
|
/**
|
|
14706
14835
|
* Re-upload the file and update the document record.
|
|
@@ -14708,9 +14837,9 @@ var WhalyDocumentTarget = class {
|
|
|
14708
14837
|
async reuploadDocument(streamId, docId, entry, localFilePath) {
|
|
14709
14838
|
const destinationPath = `${streamId}/${entry.externalId}.${entry.extension}`;
|
|
14710
14839
|
const fileName = `${entry.externalId}.${entry.extension}`;
|
|
14711
|
-
logger.info(`${
|
|
14840
|
+
logger.info(`${logPrefix10} Re-uploading file for document: ${entry.externalId}`);
|
|
14712
14841
|
const uploadResult = await this.service.uploadFile(destinationPath, localFilePath, fileName);
|
|
14713
|
-
const stat = await
|
|
14842
|
+
const stat = await fs10.stat(localFilePath);
|
|
14714
14843
|
await this.service.updateDocument(docId, {
|
|
14715
14844
|
external_id: entry.externalId,
|
|
14716
14845
|
file_name: entry.fileName,
|
|
@@ -14725,7 +14854,7 @@ var WhalyDocumentTarget = class {
|
|
|
14725
14854
|
storage: uploadResult.storage,
|
|
14726
14855
|
metadata: entry.metadata ?? {}
|
|
14727
14856
|
});
|
|
14728
|
-
logger.info(`${
|
|
14857
|
+
logger.info(`${logPrefix10} Re-uploaded document: ${entry.externalId} (${entry.fileName})`);
|
|
14729
14858
|
}
|
|
14730
14859
|
/** Update only the metadata fields (no file re-upload). */
|
|
14731
14860
|
async updateDocumentMetadata(docId, entry, existingDoc) {
|
|
@@ -14743,12 +14872,12 @@ var WhalyDocumentTarget = class {
|
|
|
14743
14872
|
storage: existingDoc.storage,
|
|
14744
14873
|
metadata: entry.metadata ?? {}
|
|
14745
14874
|
});
|
|
14746
|
-
logger.info(`${
|
|
14875
|
+
logger.info(`${logPrefix10} Updated metadata for document: ${entry.externalId} (${entry.fileName})`);
|
|
14747
14876
|
}
|
|
14748
14877
|
/** Delete a document record. */
|
|
14749
14878
|
async deleteDocument(docId, externalId) {
|
|
14750
14879
|
await this.service.deleteDocument(docId);
|
|
14751
|
-
logger.info(`${
|
|
14880
|
+
logger.info(`${logPrefix10} Deleted document: ${externalId} (id=${docId})`);
|
|
14752
14881
|
}
|
|
14753
14882
|
};
|
|
14754
14883
|
|
|
@@ -15087,7 +15216,7 @@ var BigQueryDBSync = class extends StreamWarehouseSyncService {
|
|
|
15087
15216
|
gracefulExit(1);
|
|
15088
15217
|
} else {
|
|
15089
15218
|
logger.error(`StreamId: ${this.streamId} - Error when checking if dataset already exists. Retrying... ${err.message} - ${err.code}`);
|
|
15090
|
-
await new Promise((
|
|
15219
|
+
await new Promise((resolve2, reject) => setTimeout(resolve2, 1e3 * retryCount));
|
|
15091
15220
|
await this.createDatabaseAndSchemaIfNotExists(retryCount + 1);
|
|
15092
15221
|
}
|
|
15093
15222
|
}
|
|
@@ -15314,8 +15443,8 @@ var BigQueryTarget = class extends ITarget {
|
|
|
15314
15443
|
};
|
|
15315
15444
|
|
|
15316
15445
|
// src/targets/cdn/main.ts
|
|
15317
|
-
import
|
|
15318
|
-
var
|
|
15446
|
+
import fs11 from "fs-extra";
|
|
15447
|
+
var logPrefix11 = "[CdnAssetTarget]";
|
|
15319
15448
|
var CdnAssetTarget = class extends AssetTarget {
|
|
15320
15449
|
cdnService;
|
|
15321
15450
|
constructor(config) {
|
|
@@ -15325,31 +15454,31 @@ var CdnAssetTarget = class extends AssetTarget {
|
|
|
15325
15454
|
async shouldSync(entry) {
|
|
15326
15455
|
const metadata = await this.cdnService.getFileMetadata(getCdnId(this.config.cdnId), entry.destinationPath);
|
|
15327
15456
|
if (!metadata.exists) {
|
|
15328
|
-
logger.debug(`${
|
|
15457
|
+
logger.debug(`${logPrefix11} ${entry.destinationPath} not in CDN \u2192 will sync`);
|
|
15329
15458
|
return true;
|
|
15330
15459
|
}
|
|
15331
15460
|
if (entry.lastModified === void 0) {
|
|
15332
|
-
logger.debug(`${
|
|
15461
|
+
logger.debug(`${logPrefix11} ${entry.destinationPath} source has no lastModified \u2192 will sync`);
|
|
15333
15462
|
return true;
|
|
15334
15463
|
}
|
|
15335
15464
|
if (metadata.lastModified === null) {
|
|
15336
|
-
logger.debug(`${
|
|
15465
|
+
logger.debug(`${logPrefix11} ${entry.destinationPath} CDN has no lastModified \u2192 will sync`);
|
|
15337
15466
|
return true;
|
|
15338
15467
|
}
|
|
15339
15468
|
const sourceIsNewer = entry.lastModified > metadata.lastModified;
|
|
15340
15469
|
if (!sourceIsNewer) {
|
|
15341
|
-
logger.debug(`${
|
|
15470
|
+
logger.debug(`${logPrefix11} Skipping ${entry.destinationPath} (CDN is up-to-date)`);
|
|
15342
15471
|
}
|
|
15343
15472
|
return sourceIsNewer;
|
|
15344
15473
|
}
|
|
15345
15474
|
async uploadAsset(asset) {
|
|
15346
|
-
const fileBuffer = await
|
|
15475
|
+
const fileBuffer = await fs11.readFile(asset.uploadPath);
|
|
15347
15476
|
await this.cdnService.uploadFile(
|
|
15348
15477
|
getCdnId(this.config.cdnId),
|
|
15349
15478
|
asset.entry.destinationPath,
|
|
15350
15479
|
fileBuffer
|
|
15351
15480
|
);
|
|
15352
|
-
logger.info(`${
|
|
15481
|
+
logger.info(`${logPrefix11} Uploaded ${asset.entry.destinationPath} (${fileBuffer.length} bytes)`);
|
|
15353
15482
|
}
|
|
15354
15483
|
};
|
|
15355
15484
|
|
|
@@ -15418,6 +15547,7 @@ export {
|
|
|
15418
15547
|
GCSStateProvider,
|
|
15419
15548
|
ITarget,
|
|
15420
15549
|
ImageTransform,
|
|
15550
|
+
LocalStorageService,
|
|
15421
15551
|
MIME_TYPES,
|
|
15422
15552
|
MissingFieldInSchemaError,
|
|
15423
15553
|
MissingSchemaError,
|
|
@@ -15473,6 +15603,7 @@ export {
|
|
|
15473
15603
|
getCounterMetrics,
|
|
15474
15604
|
getDownloadFileApiCall,
|
|
15475
15605
|
getDryRunLimit,
|
|
15606
|
+
getExtension,
|
|
15476
15607
|
getJSONApiCall,
|
|
15477
15608
|
getJSONApiCallWithFullResponse,
|
|
15478
15609
|
getMimeType,
|