@whaly/connector-sdk 0.3.10 → 0.3.12
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 +104 -7
- package/dist/index.d.ts +104 -7
- package/dist/index.js +205 -78
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +237 -111
- 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,20 +14655,22 @@ 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;
|
|
14550
14662
|
objectStorageId;
|
|
14663
|
+
documentSourceId;
|
|
14551
14664
|
gcsBucket;
|
|
14552
14665
|
constructor(config) {
|
|
14553
14666
|
const resolvedKey = getServiceAccountKey(config.serviceAccountKey);
|
|
14554
14667
|
const resolvedEndpoint = getApiEndpoint(config.apiEndpoint);
|
|
14555
14668
|
this.objectStorageId = config.objectStorageId;
|
|
14669
|
+
this.documentSourceId = config.documentSourceId;
|
|
14556
14670
|
const gcsBucketName = process.env["WLY_GCS_BUCKET"];
|
|
14557
14671
|
if (gcsBucketName) {
|
|
14558
14672
|
this.gcsBucket = new Storage2().bucket(gcsBucketName);
|
|
14559
|
-
logger.info(`${
|
|
14673
|
+
logger.info(`${logPrefix9} Using direct GCS upload to bucket: ${gcsBucketName}`);
|
|
14560
14674
|
}
|
|
14561
14675
|
this.axiosClient = axios4.create({
|
|
14562
14676
|
baseURL: resolvedEndpoint,
|
|
@@ -14577,22 +14691,26 @@ var WhalyDocumentService = class {
|
|
|
14577
14691
|
if (retryAfter) {
|
|
14578
14692
|
const seconds = Number(retryAfter);
|
|
14579
14693
|
if (!isNaN(seconds) && seconds > 0) {
|
|
14580
|
-
logger.info(`${
|
|
14694
|
+
logger.info(`${logPrefix9} Rate limited \u2014 waiting ${seconds}s, attempt ${retryCount}/${MAX_RETRIES2}`);
|
|
14581
14695
|
return seconds * 1e3;
|
|
14582
14696
|
}
|
|
14583
14697
|
}
|
|
14584
14698
|
const delay = axiosRetry3.exponentialDelay(retryCount);
|
|
14585
|
-
logger.info(`${
|
|
14699
|
+
logger.info(`${logPrefix9} Retrying in ${delay}ms (attempt ${retryCount}/${MAX_RETRIES2}) for ${error.config?.method?.toUpperCase()} ${error.config?.url}`);
|
|
14586
14700
|
return delay;
|
|
14587
14701
|
}
|
|
14588
14702
|
});
|
|
14589
14703
|
}
|
|
14590
|
-
/**
|
|
14704
|
+
/**
|
|
14705
|
+
* Fetch all documents belonging to the configured document source,
|
|
14706
|
+
* handling cursor-based pagination. The `document_source_id` server-side
|
|
14707
|
+
* filter scopes the result to this connector's source only.
|
|
14708
|
+
*/
|
|
14591
14709
|
async listAllDocuments() {
|
|
14592
14710
|
const documents = [];
|
|
14593
14711
|
let after;
|
|
14594
14712
|
while (true) {
|
|
14595
|
-
const params = {};
|
|
14713
|
+
const params = { document_source_id: this.documentSourceId };
|
|
14596
14714
|
if (after) params["after"] = after;
|
|
14597
14715
|
const response = await this.axiosClient.get(
|
|
14598
14716
|
"/v1/documents",
|
|
@@ -14603,7 +14721,7 @@ var WhalyDocumentService = class {
|
|
|
14603
14721
|
if (!nextAfter) break;
|
|
14604
14722
|
after = nextAfter;
|
|
14605
14723
|
}
|
|
14606
|
-
logger.info(`${
|
|
14724
|
+
logger.info(`${logPrefix9} Fetched ${documents.length} existing documents from Whaly`);
|
|
14607
14725
|
return documents;
|
|
14608
14726
|
}
|
|
14609
14727
|
/** Upload a file to object storage. Returns storage path and size. */
|
|
@@ -14624,11 +14742,11 @@ var WhalyDocumentService = class {
|
|
|
14624
14742
|
} catch (err) {
|
|
14625
14743
|
if (attempt === maxAttempts) throw err;
|
|
14626
14744
|
const delay = Math.min(1e3 * 2 ** (attempt - 1), 3e4);
|
|
14627
|
-
logger.info(`${
|
|
14628
|
-
await new Promise((
|
|
14745
|
+
logger.info(`${logPrefix9} GCS upload retry ${attempt}/${MAX_RETRIES2} in ${delay}ms for ${destinationPath}`);
|
|
14746
|
+
await new Promise((resolve2) => setTimeout(resolve2, delay));
|
|
14629
14747
|
}
|
|
14630
14748
|
}
|
|
14631
|
-
const stat = await
|
|
14749
|
+
const stat = await fs9.promises.stat(localFilePath);
|
|
14632
14750
|
return {
|
|
14633
14751
|
storage: this.objectStorageId,
|
|
14634
14752
|
filePath: destinationPath,
|
|
@@ -14637,7 +14755,7 @@ var WhalyDocumentService = class {
|
|
|
14637
14755
|
}
|
|
14638
14756
|
async uploadFileViaAPI(destinationPath, localFilePath, fileName) {
|
|
14639
14757
|
const form = new import_form_data.default();
|
|
14640
|
-
form.append("file",
|
|
14758
|
+
form.append("file", fs9.createReadStream(localFilePath), fileName);
|
|
14641
14759
|
try {
|
|
14642
14760
|
const response = await this.axiosClient.post(
|
|
14643
14761
|
`/v1/object-storages/${this.objectStorageId}/upload`,
|
|
@@ -14652,19 +14770,26 @@ var WhalyDocumentService = class {
|
|
|
14652
14770
|
throw enrichAxiosError(err);
|
|
14653
14771
|
}
|
|
14654
14772
|
}
|
|
14655
|
-
/** Create a new document record. */
|
|
14773
|
+
/** Create a new document record, attached to the configured document source. */
|
|
14656
14774
|
async createDocument(payload) {
|
|
14657
14775
|
try {
|
|
14658
|
-
const response = await this.axiosClient.post("/v1/documents",
|
|
14776
|
+
const response = await this.axiosClient.post("/v1/documents", {
|
|
14777
|
+
...payload,
|
|
14778
|
+
document_source_id: this.documentSourceId
|
|
14779
|
+
});
|
|
14659
14780
|
return response.data.data ?? response.data;
|
|
14660
14781
|
} catch (err) {
|
|
14661
14782
|
throw enrichAxiosError(err);
|
|
14662
14783
|
}
|
|
14663
14784
|
}
|
|
14664
|
-
/** Update an existing document record. */
|
|
14785
|
+
/** Update an existing document record, keeping it in the configured document source. */
|
|
14665
14786
|
async updateDocument(id, payload) {
|
|
14666
14787
|
try {
|
|
14667
|
-
const response = await this.axiosClient.put(`/v1/documents/${id}`, {
|
|
14788
|
+
const response = await this.axiosClient.put(`/v1/documents/${id}`, {
|
|
14789
|
+
id,
|
|
14790
|
+
...payload,
|
|
14791
|
+
document_source_id: this.documentSourceId
|
|
14792
|
+
});
|
|
14668
14793
|
return response.data.data ?? response.data;
|
|
14669
14794
|
} catch (err) {
|
|
14670
14795
|
throw enrichAxiosError(err);
|
|
@@ -14681,7 +14806,7 @@ var WhalyDocumentService = class {
|
|
|
14681
14806
|
};
|
|
14682
14807
|
|
|
14683
14808
|
// src/sdk/models/document-target/whaly-document-target.ts
|
|
14684
|
-
var
|
|
14809
|
+
var logPrefix10 = "[WhalyDocumentTarget]";
|
|
14685
14810
|
var WhalyDocumentTarget = class {
|
|
14686
14811
|
config;
|
|
14687
14812
|
service;
|
|
@@ -14700,9 +14825,9 @@ var WhalyDocumentTarget = class {
|
|
|
14700
14825
|
async createDocument(streamId, entry, localFilePath) {
|
|
14701
14826
|
const destinationPath = `${streamId}/${entry.externalId}.${entry.extension}`;
|
|
14702
14827
|
const fileName = `${entry.externalId}.${entry.extension}`;
|
|
14703
|
-
logger.info(`${
|
|
14828
|
+
logger.info(`${logPrefix10} Uploading file for new document: ${entry.externalId}`);
|
|
14704
14829
|
const uploadResult = await this.service.uploadFile(destinationPath, localFilePath, fileName);
|
|
14705
|
-
const stat = await
|
|
14830
|
+
const stat = await fs10.stat(localFilePath);
|
|
14706
14831
|
await this.service.createDocument({
|
|
14707
14832
|
file_name: entry.fileName,
|
|
14708
14833
|
external_id: entry.externalId,
|
|
@@ -14717,7 +14842,7 @@ var WhalyDocumentTarget = class {
|
|
|
14717
14842
|
storage: uploadResult.storage,
|
|
14718
14843
|
metadata: entry.metadata ?? {}
|
|
14719
14844
|
});
|
|
14720
|
-
logger.info(`${
|
|
14845
|
+
logger.info(`${logPrefix10} Created document: ${entry.externalId} (${entry.fileName})`);
|
|
14721
14846
|
}
|
|
14722
14847
|
/**
|
|
14723
14848
|
* Re-upload the file and update the document record.
|
|
@@ -14725,9 +14850,9 @@ var WhalyDocumentTarget = class {
|
|
|
14725
14850
|
async reuploadDocument(streamId, docId, entry, localFilePath) {
|
|
14726
14851
|
const destinationPath = `${streamId}/${entry.externalId}.${entry.extension}`;
|
|
14727
14852
|
const fileName = `${entry.externalId}.${entry.extension}`;
|
|
14728
|
-
logger.info(`${
|
|
14853
|
+
logger.info(`${logPrefix10} Re-uploading file for document: ${entry.externalId}`);
|
|
14729
14854
|
const uploadResult = await this.service.uploadFile(destinationPath, localFilePath, fileName);
|
|
14730
|
-
const stat = await
|
|
14855
|
+
const stat = await fs10.stat(localFilePath);
|
|
14731
14856
|
await this.service.updateDocument(docId, {
|
|
14732
14857
|
external_id: entry.externalId,
|
|
14733
14858
|
file_name: entry.fileName,
|
|
@@ -14742,7 +14867,7 @@ var WhalyDocumentTarget = class {
|
|
|
14742
14867
|
storage: uploadResult.storage,
|
|
14743
14868
|
metadata: entry.metadata ?? {}
|
|
14744
14869
|
});
|
|
14745
|
-
logger.info(`${
|
|
14870
|
+
logger.info(`${logPrefix10} Re-uploaded document: ${entry.externalId} (${entry.fileName})`);
|
|
14746
14871
|
}
|
|
14747
14872
|
/** Update only the metadata fields (no file re-upload). */
|
|
14748
14873
|
async updateDocumentMetadata(docId, entry, existingDoc) {
|
|
@@ -14760,12 +14885,12 @@ var WhalyDocumentTarget = class {
|
|
|
14760
14885
|
storage: existingDoc.storage,
|
|
14761
14886
|
metadata: entry.metadata ?? {}
|
|
14762
14887
|
});
|
|
14763
|
-
logger.info(`${
|
|
14888
|
+
logger.info(`${logPrefix10} Updated metadata for document: ${entry.externalId} (${entry.fileName})`);
|
|
14764
14889
|
}
|
|
14765
14890
|
/** Delete a document record. */
|
|
14766
14891
|
async deleteDocument(docId, externalId) {
|
|
14767
14892
|
await this.service.deleteDocument(docId);
|
|
14768
|
-
logger.info(`${
|
|
14893
|
+
logger.info(`${logPrefix10} Deleted document: ${externalId} (id=${docId})`);
|
|
14769
14894
|
}
|
|
14770
14895
|
};
|
|
14771
14896
|
|
|
@@ -15104,7 +15229,7 @@ var BigQueryDBSync = class extends StreamWarehouseSyncService {
|
|
|
15104
15229
|
gracefulExit(1);
|
|
15105
15230
|
} else {
|
|
15106
15231
|
logger.error(`StreamId: ${this.streamId} - Error when checking if dataset already exists. Retrying... ${err.message} - ${err.code}`);
|
|
15107
|
-
await new Promise((
|
|
15232
|
+
await new Promise((resolve2, reject) => setTimeout(resolve2, 1e3 * retryCount));
|
|
15108
15233
|
await this.createDatabaseAndSchemaIfNotExists(retryCount + 1);
|
|
15109
15234
|
}
|
|
15110
15235
|
}
|
|
@@ -15331,8 +15456,8 @@ var BigQueryTarget = class extends ITarget {
|
|
|
15331
15456
|
};
|
|
15332
15457
|
|
|
15333
15458
|
// src/targets/cdn/main.ts
|
|
15334
|
-
import
|
|
15335
|
-
var
|
|
15459
|
+
import fs11 from "fs-extra";
|
|
15460
|
+
var logPrefix11 = "[CdnAssetTarget]";
|
|
15336
15461
|
var CdnAssetTarget = class extends AssetTarget {
|
|
15337
15462
|
cdnService;
|
|
15338
15463
|
constructor(config) {
|
|
@@ -15342,31 +15467,31 @@ var CdnAssetTarget = class extends AssetTarget {
|
|
|
15342
15467
|
async shouldSync(entry) {
|
|
15343
15468
|
const metadata = await this.cdnService.getFileMetadata(getCdnId(this.config.cdnId), entry.destinationPath);
|
|
15344
15469
|
if (!metadata.exists) {
|
|
15345
|
-
logger.debug(`${
|
|
15470
|
+
logger.debug(`${logPrefix11} ${entry.destinationPath} not in CDN \u2192 will sync`);
|
|
15346
15471
|
return true;
|
|
15347
15472
|
}
|
|
15348
15473
|
if (entry.lastModified === void 0) {
|
|
15349
|
-
logger.debug(`${
|
|
15474
|
+
logger.debug(`${logPrefix11} ${entry.destinationPath} source has no lastModified \u2192 will sync`);
|
|
15350
15475
|
return true;
|
|
15351
15476
|
}
|
|
15352
15477
|
if (metadata.lastModified === null) {
|
|
15353
|
-
logger.debug(`${
|
|
15478
|
+
logger.debug(`${logPrefix11} ${entry.destinationPath} CDN has no lastModified \u2192 will sync`);
|
|
15354
15479
|
return true;
|
|
15355
15480
|
}
|
|
15356
15481
|
const sourceIsNewer = entry.lastModified > metadata.lastModified;
|
|
15357
15482
|
if (!sourceIsNewer) {
|
|
15358
|
-
logger.debug(`${
|
|
15483
|
+
logger.debug(`${logPrefix11} Skipping ${entry.destinationPath} (CDN is up-to-date)`);
|
|
15359
15484
|
}
|
|
15360
15485
|
return sourceIsNewer;
|
|
15361
15486
|
}
|
|
15362
15487
|
async uploadAsset(asset) {
|
|
15363
|
-
const fileBuffer = await
|
|
15488
|
+
const fileBuffer = await fs11.readFile(asset.uploadPath);
|
|
15364
15489
|
await this.cdnService.uploadFile(
|
|
15365
15490
|
getCdnId(this.config.cdnId),
|
|
15366
15491
|
asset.entry.destinationPath,
|
|
15367
15492
|
fileBuffer
|
|
15368
15493
|
);
|
|
15369
|
-
logger.info(`${
|
|
15494
|
+
logger.info(`${logPrefix11} Uploaded ${asset.entry.destinationPath} (${fileBuffer.length} bytes)`);
|
|
15370
15495
|
}
|
|
15371
15496
|
};
|
|
15372
15497
|
|
|
@@ -15435,6 +15560,7 @@ export {
|
|
|
15435
15560
|
GCSStateProvider,
|
|
15436
15561
|
ITarget,
|
|
15437
15562
|
ImageTransform,
|
|
15563
|
+
LocalStorageService,
|
|
15438
15564
|
MIME_TYPES,
|
|
15439
15565
|
MissingFieldInSchemaError,
|
|
15440
15566
|
MissingSchemaError,
|