@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.js
CHANGED
|
@@ -8830,7 +8830,7 @@ var require_mime_types = __commonJS({
|
|
|
8830
8830
|
"node_modules/mime-types/index.js"(exports2) {
|
|
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
|
exports2.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;
|
|
@@ -10342,6 +10342,7 @@ __export(index_exports, {
|
|
|
10342
10342
|
GCSStateProvider: () => GCSStateProvider,
|
|
10343
10343
|
ITarget: () => ITarget,
|
|
10344
10344
|
ImageTransform: () => ImageTransform,
|
|
10345
|
+
LocalStorageService: () => LocalStorageService,
|
|
10345
10346
|
MIME_TYPES: () => MIME_TYPES,
|
|
10346
10347
|
MissingFieldInSchemaError: () => MissingFieldInSchemaError,
|
|
10347
10348
|
MissingSchemaError: () => MissingSchemaError,
|
|
@@ -10397,6 +10398,7 @@ __export(index_exports, {
|
|
|
10397
10398
|
getCounterMetrics: () => getCounterMetrics,
|
|
10398
10399
|
getDownloadFileApiCall: () => getDownloadFileApiCall,
|
|
10399
10400
|
getDryRunLimit: () => getDryRunLimit,
|
|
10401
|
+
getExtension: () => getExtension,
|
|
10400
10402
|
getJSONApiCall: () => getJSONApiCall,
|
|
10401
10403
|
getJSONApiCallWithFullResponse: () => getJSONApiCallWithFullResponse,
|
|
10402
10404
|
getMimeType: () => getMimeType,
|
|
@@ -10640,7 +10642,7 @@ var getDownloadFileApiCall = async (endpoint, config, output, privateLogging) =>
|
|
|
10640
10642
|
...config.headers ? { headers: config.headers } : {},
|
|
10641
10643
|
paramsSerializer: { serialize: (params) => qs.stringify(params, { arrayFormat: "repeat" }) }
|
|
10642
10644
|
}).then((response) => {
|
|
10643
|
-
return new Promise((
|
|
10645
|
+
return new Promise((resolve2, reject) => {
|
|
10644
10646
|
response.data.pipe(writer);
|
|
10645
10647
|
let error = null;
|
|
10646
10648
|
writer.on("error", (err) => {
|
|
@@ -10650,7 +10652,7 @@ var getDownloadFileApiCall = async (endpoint, config, output, privateLogging) =>
|
|
|
10650
10652
|
});
|
|
10651
10653
|
writer.on("close", () => {
|
|
10652
10654
|
if (!error) {
|
|
10653
|
-
|
|
10655
|
+
resolve2({ outputDir: output });
|
|
10654
10656
|
}
|
|
10655
10657
|
});
|
|
10656
10658
|
});
|
|
@@ -10801,8 +10803,8 @@ var printMemoryFootprint = (prefix) => {
|
|
|
10801
10803
|
|
|
10802
10804
|
// src/sdk/service/exit.ts
|
|
10803
10805
|
async function gracefulExit(exitCode) {
|
|
10804
|
-
const loggerFinish = new Promise((
|
|
10805
|
-
logger.closeWinston(
|
|
10806
|
+
const loggerFinish = new Promise((resolve2, reject) => {
|
|
10807
|
+
logger.closeWinston(resolve2);
|
|
10806
10808
|
});
|
|
10807
10809
|
await loggerFinish;
|
|
10808
10810
|
process.exit(exitCode);
|
|
@@ -10973,6 +10975,16 @@ function getMimeType(filePathOrExt) {
|
|
|
10973
10975
|
const ext = filePathOrExt.startsWith(".") ? filePathOrExt.toLowerCase() : import_node_path.default.extname(filePathOrExt).toLowerCase();
|
|
10974
10976
|
return MIME_TYPES[ext] ?? "application/octet-stream";
|
|
10975
10977
|
}
|
|
10978
|
+
var EXTENSION_BY_MIME = Object.entries(MIME_TYPES).reduce(
|
|
10979
|
+
(acc, [ext, mime]) => {
|
|
10980
|
+
if (!acc[mime]) acc[mime] = ext;
|
|
10981
|
+
return acc;
|
|
10982
|
+
},
|
|
10983
|
+
{}
|
|
10984
|
+
);
|
|
10985
|
+
function getExtension(mimeType) {
|
|
10986
|
+
return EXTENSION_BY_MIME[mimeType] ?? ".bin";
|
|
10987
|
+
}
|
|
10976
10988
|
|
|
10977
10989
|
// src/sdk/models/replication.ts
|
|
10978
10990
|
var ReplicationMethod = /* @__PURE__ */ ((ReplicationMethod2) => {
|
|
@@ -12562,13 +12574,13 @@ var ITarget = class _ITarget {
|
|
|
12562
12574
|
const dbSyncInstance = stream.getDbSync();
|
|
12563
12575
|
const recordWithrenamedColumns = dbSyncInstance.renameColumns(recordWithDecimal);
|
|
12564
12576
|
const serializedRecord = this.getSerializedRecord(streamId, recordWithrenamedColumns);
|
|
12565
|
-
return new Promise((
|
|
12577
|
+
return new Promise((resolve2, reject) => {
|
|
12566
12578
|
stream.getFileToLoad().stream.write(serializedRecord, (error) => {
|
|
12567
12579
|
if (error) {
|
|
12568
12580
|
reject(error);
|
|
12569
12581
|
}
|
|
12570
12582
|
stream.incrementBatchedRowCount();
|
|
12571
|
-
|
|
12583
|
+
resolve2();
|
|
12572
12584
|
});
|
|
12573
12585
|
});
|
|
12574
12586
|
} catch (err) {
|
|
@@ -12709,11 +12721,11 @@ var ITarget = class _ITarget {
|
|
|
12709
12721
|
const streamState = this.streams[streamId];
|
|
12710
12722
|
if (!streamState || streamState.getBatchedRowCount() === 0) continue;
|
|
12711
12723
|
const fileToLoad = streamState.getFileToLoad();
|
|
12712
|
-
await new Promise((
|
|
12724
|
+
await new Promise((resolve2, reject) => {
|
|
12713
12725
|
fileToLoad.stream.end(() => {
|
|
12714
12726
|
fileToLoad.stream.close((err) => {
|
|
12715
12727
|
if (err) reject(err);
|
|
12716
|
-
else
|
|
12728
|
+
else resolve2();
|
|
12717
12729
|
});
|
|
12718
12730
|
});
|
|
12719
12731
|
});
|
|
@@ -13244,18 +13256,18 @@ async function* rowGeneratorFromCsv(path8, fileConfig) {
|
|
|
13244
13256
|
}
|
|
13245
13257
|
}
|
|
13246
13258
|
async function countCsvLines(filePath) {
|
|
13247
|
-
return new Promise((
|
|
13259
|
+
return new Promise((resolve2, reject) => {
|
|
13248
13260
|
let newlines = 0;
|
|
13249
13261
|
(0, import_fs2.createReadStream)(filePath).on("data", (chunk2) => {
|
|
13250
13262
|
const buf = Buffer.isBuffer(chunk2) ? chunk2 : Buffer.from(chunk2);
|
|
13251
13263
|
for (let i = 0; i < buf.length; i++) {
|
|
13252
13264
|
if (buf[i] === 10) newlines++;
|
|
13253
13265
|
}
|
|
13254
|
-
}).on("end", () =>
|
|
13266
|
+
}).on("end", () => resolve2(Math.max(0, newlines - 1))).on("error", reject);
|
|
13255
13267
|
});
|
|
13256
13268
|
}
|
|
13257
13269
|
var checkCsvHeaderRow = async (path8, fileConfig) => {
|
|
13258
|
-
return new Promise((
|
|
13270
|
+
return new Promise((resolve2, reject) => {
|
|
13259
13271
|
const colsWithParsingConfig = Object.keys(fileConfig.fields).map((key) => key.trim());
|
|
13260
13272
|
console.debug(`${logPrefix} CSV Expected columns:`, colsWithParsingConfig.map((col) => {
|
|
13261
13273
|
const info = getStringHexInfo(col);
|
|
@@ -13330,7 +13342,7 @@ var checkCsvHeaderRow = async (path8, fileConfig) => {
|
|
|
13330
13342
|
reject(new Error(`Error processing CSV file: ${error.message}`));
|
|
13331
13343
|
});
|
|
13332
13344
|
initialReadStream.on("close", () => {
|
|
13333
|
-
|
|
13345
|
+
resolve2();
|
|
13334
13346
|
});
|
|
13335
13347
|
});
|
|
13336
13348
|
};
|
|
@@ -13911,6 +13923,16 @@ var CloudStorageService = class {
|
|
|
13911
13923
|
throw new Error((0, import_util5.format)(`error writing GCS object gs://${this.bucket.name}/${objectPath}, err: %s`, err?.message));
|
|
13912
13924
|
}
|
|
13913
13925
|
}
|
|
13926
|
+
/**
|
|
13927
|
+
* Resolves a file URI to a local file path by downloading it from the configured GCS bucket.
|
|
13928
|
+
*
|
|
13929
|
+
* @example
|
|
13930
|
+
* const storage = new CloudStorageService("my-bucket", "my-folder");
|
|
13931
|
+
* const localPath = await storage.resolveFileUri("folder/file.xlsx");
|
|
13932
|
+
*/
|
|
13933
|
+
async resolveFileUri(fileUri) {
|
|
13934
|
+
return this.downloadFile(fileUri, pathModule.basename(fileUri));
|
|
13935
|
+
}
|
|
13914
13936
|
/**
|
|
13915
13937
|
* Uploads a local file to the bucket with a unique name based on prefix, streamId, and UUID.
|
|
13916
13938
|
* Files are stored under `<prefix>/<run-id>/` when the RUN_ID env var is set,
|
|
@@ -13939,6 +13961,108 @@ var CloudStorageService = class {
|
|
|
13939
13961
|
}
|
|
13940
13962
|
};
|
|
13941
13963
|
|
|
13964
|
+
// src/services/local-storage.ts
|
|
13965
|
+
var pathModule2 = __toESM(require("path"));
|
|
13966
|
+
var fs6 = __toESM(require("fs"));
|
|
13967
|
+
var import_crypto2 = require("crypto");
|
|
13968
|
+
var logPrefix5 = "[LocalStorageService]";
|
|
13969
|
+
var LocalStorageService = class {
|
|
13970
|
+
basePath;
|
|
13971
|
+
processedSuffix;
|
|
13972
|
+
supportedExtensions;
|
|
13973
|
+
constructor(basePath, opts) {
|
|
13974
|
+
this.basePath = pathModule2.resolve(basePath);
|
|
13975
|
+
this.processedSuffix = opts?.processedSuffix ?? ".processed";
|
|
13976
|
+
this.supportedExtensions = opts?.supportedExtensions ?? [];
|
|
13977
|
+
}
|
|
13978
|
+
async listFiles(prefix) {
|
|
13979
|
+
const dir = prefix ? pathModule2.resolve(this.basePath, prefix) : this.basePath;
|
|
13980
|
+
if (!fs6.existsSync(dir)) {
|
|
13981
|
+
return [];
|
|
13982
|
+
}
|
|
13983
|
+
const entries = fs6.readdirSync(dir, { recursive: true });
|
|
13984
|
+
const files = [];
|
|
13985
|
+
for (const entry of entries) {
|
|
13986
|
+
const rel = typeof entry === "string" ? entry : entry.toString();
|
|
13987
|
+
const full = pathModule2.join(dir, rel);
|
|
13988
|
+
if (fs6.statSync(full).isFile()) {
|
|
13989
|
+
files.push(pathModule2.relative(this.basePath, full));
|
|
13990
|
+
}
|
|
13991
|
+
}
|
|
13992
|
+
return files;
|
|
13993
|
+
}
|
|
13994
|
+
async getUnprocessedFiles() {
|
|
13995
|
+
const allFiles = await this.listFiles();
|
|
13996
|
+
const markerFiles = new Set(
|
|
13997
|
+
allFiles.filter((f) => f.endsWith(this.processedSuffix)).map((f) => f.replace(this.processedSuffix, ""))
|
|
13998
|
+
);
|
|
13999
|
+
return allFiles.filter((f) => {
|
|
14000
|
+
if (f.endsWith(this.processedSuffix)) return false;
|
|
14001
|
+
if (this.supportedExtensions.length > 0) {
|
|
14002
|
+
const ext = pathModule2.extname(f).toLowerCase();
|
|
14003
|
+
if (!this.supportedExtensions.includes(ext)) return false;
|
|
14004
|
+
}
|
|
14005
|
+
return !markerFiles.has(f);
|
|
14006
|
+
});
|
|
14007
|
+
}
|
|
14008
|
+
async createMarkerFile(fileName) {
|
|
14009
|
+
const markerPath = pathModule2.join(this.basePath, `${fileName}${this.processedSuffix}`);
|
|
14010
|
+
const dir = pathModule2.dirname(markerPath);
|
|
14011
|
+
if (!fs6.existsSync(dir)) {
|
|
14012
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
14013
|
+
}
|
|
14014
|
+
fs6.writeFileSync(markerPath, `Marked file ${fileName} as processed`);
|
|
14015
|
+
logger.info(`${logPrefix5} Marker file ${markerPath} created successfully.`);
|
|
14016
|
+
}
|
|
14017
|
+
async downloadFile(filePath, _fileName) {
|
|
14018
|
+
const resolved = pathModule2.resolve(this.basePath, filePath);
|
|
14019
|
+
if (!fs6.existsSync(resolved)) {
|
|
14020
|
+
throw new Error(`Local file not found: ${resolved}`);
|
|
14021
|
+
}
|
|
14022
|
+
logger.info(`${logPrefix5} Resolved local file: ${resolved}`);
|
|
14023
|
+
return resolved;
|
|
14024
|
+
}
|
|
14025
|
+
async resolveFileUri(fileUri) {
|
|
14026
|
+
const resolved = pathModule2.resolve(fileUri);
|
|
14027
|
+
if (!fs6.existsSync(resolved)) {
|
|
14028
|
+
throw new Error(`Local file not found: ${resolved}`);
|
|
14029
|
+
}
|
|
14030
|
+
logger.info(`${logPrefix5} File URI resolved to local path: ${resolved}`);
|
|
14031
|
+
return resolved;
|
|
14032
|
+
}
|
|
14033
|
+
async uploadFile(localPath, destPath) {
|
|
14034
|
+
const dest = pathModule2.resolve(this.basePath, destPath);
|
|
14035
|
+
const dir = pathModule2.dirname(dest);
|
|
14036
|
+
if (!fs6.existsSync(dir)) {
|
|
14037
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
14038
|
+
}
|
|
14039
|
+
fs6.copyFileSync(localPath, dest);
|
|
14040
|
+
logger.info(`${logPrefix5} Copied '%s' to '%s'`, localPath, dest);
|
|
14041
|
+
return { name: destPath };
|
|
14042
|
+
}
|
|
14043
|
+
async readObjectAsString(objectPath) {
|
|
14044
|
+
const fullPath = pathModule2.resolve(this.basePath, objectPath);
|
|
14045
|
+
if (!fs6.existsSync(fullPath)) {
|
|
14046
|
+
throw new Error(`Local file not found: ${fullPath}`);
|
|
14047
|
+
}
|
|
14048
|
+
return fs6.readFileSync(fullPath, "utf8");
|
|
14049
|
+
}
|
|
14050
|
+
async writeStringObject(objectPath, contents) {
|
|
14051
|
+
const fullPath = pathModule2.resolve(this.basePath, objectPath);
|
|
14052
|
+
const dir = pathModule2.dirname(fullPath);
|
|
14053
|
+
if (!fs6.existsSync(dir)) {
|
|
14054
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
14055
|
+
}
|
|
14056
|
+
fs6.writeFileSync(fullPath, contents, "utf8");
|
|
14057
|
+
logger.info(`${logPrefix5} Wrote object to ${fullPath}`);
|
|
14058
|
+
}
|
|
14059
|
+
async uploadFileWithUniqueName(filePath, prefix, streamId) {
|
|
14060
|
+
const runFolder = process.env.RUN_ID ?? "default";
|
|
14061
|
+
const destName = `${prefix}/${runFolder}/${streamId}-${(0, import_crypto2.randomUUID)()}.jsonnl`;
|
|
14062
|
+
return this.uploadFile(filePath, destName);
|
|
14063
|
+
}
|
|
14064
|
+
};
|
|
14065
|
+
|
|
13942
14066
|
// src/services/zip.ts
|
|
13943
14067
|
var fse = __toESM(require("fs-extra"));
|
|
13944
14068
|
var import_decompress = __toESM(require("decompress"));
|
|
@@ -13951,7 +14075,7 @@ var unzip = async (zipFilePath, extractedPath) => {
|
|
|
13951
14075
|
// src/services/cdn.ts
|
|
13952
14076
|
var import_axios3 = __toESM(require("axios"));
|
|
13953
14077
|
var import_axios_retry2 = __toESM(require("axios-retry"));
|
|
13954
|
-
var
|
|
14078
|
+
var logPrefix6 = "[CdnService]";
|
|
13955
14079
|
var MAX_RETRIES = 10;
|
|
13956
14080
|
var CdnService = class {
|
|
13957
14081
|
axiosClient;
|
|
@@ -13977,12 +14101,12 @@ var CdnService = class {
|
|
|
13977
14101
|
if (retryAfter) {
|
|
13978
14102
|
const seconds = Number(retryAfter);
|
|
13979
14103
|
if (!isNaN(seconds) && seconds > 0) {
|
|
13980
|
-
logger.info(`${
|
|
14104
|
+
logger.info(`${logPrefix6} Rate limited \u2014 waiting ${seconds}s (Retry-After header), attempt ${retryCount}/${MAX_RETRIES}`);
|
|
13981
14105
|
return seconds * 1e3;
|
|
13982
14106
|
}
|
|
13983
14107
|
}
|
|
13984
14108
|
const delay = import_axios_retry2.default.exponentialDelay(retryCount);
|
|
13985
|
-
logger.info(`${
|
|
14109
|
+
logger.info(`${logPrefix6} Retrying in ${delay}ms (attempt ${retryCount}/${MAX_RETRIES}) for ${error.config?.method?.toUpperCase()} ${error.config?.url}`);
|
|
13986
14110
|
return delay;
|
|
13987
14111
|
}
|
|
13988
14112
|
});
|
|
@@ -14008,7 +14132,7 @@ var CdnService = class {
|
|
|
14008
14132
|
const status = err.response?.status;
|
|
14009
14133
|
if (status === 404) return { exists: false, lastModified: null, contentType: null };
|
|
14010
14134
|
if (status === 405) {
|
|
14011
|
-
logger.warn(`${
|
|
14135
|
+
logger.warn(`${logPrefix6} HEAD not supported for ${url}, treating file as absent`);
|
|
14012
14136
|
return { exists: false, lastModified: null, contentType: null };
|
|
14013
14137
|
}
|
|
14014
14138
|
this.throwMeaningfulError(err);
|
|
@@ -14032,11 +14156,11 @@ var CdnService = class {
|
|
|
14032
14156
|
async uploadFile(cdnId, fileName, fileBuffer) {
|
|
14033
14157
|
const url = `/v1/cdn/${cdnId}/files/${encodeURIComponent(fileName)}`;
|
|
14034
14158
|
try {
|
|
14035
|
-
logger.info(`${
|
|
14159
|
+
logger.info(`${logPrefix6} Uploading ${fileName} (${fileBuffer.length} bytes) to CDN ${cdnId}`);
|
|
14036
14160
|
const form = new FormData();
|
|
14037
14161
|
form.append("file", new Blob([fileBuffer]), fileName);
|
|
14038
14162
|
const response = await this.axiosClient.put(url, form);
|
|
14039
|
-
logger.info(`${
|
|
14163
|
+
logger.info(`${logPrefix6} Successfully uploaded ${fileName} (status ${response.status})`);
|
|
14040
14164
|
return {
|
|
14041
14165
|
filePath: response.data?.filePath ?? `/org/${cdnId}/file/${fileName}`
|
|
14042
14166
|
};
|
|
@@ -14079,7 +14203,7 @@ var AssetStream = class {
|
|
|
14079
14203
|
// src/sdk/models/asset-tap/asset-tap.ts
|
|
14080
14204
|
var import_fs_extra4 = __toESM(require("fs-extra"));
|
|
14081
14205
|
var import_node_path4 = __toESM(require("path"));
|
|
14082
|
-
var
|
|
14206
|
+
var logPrefix7 = "[AssetTap]";
|
|
14083
14207
|
function inferContentType(filePath, fallback) {
|
|
14084
14208
|
const mime = getMimeType(filePath);
|
|
14085
14209
|
return mime !== "application/octet-stream" ? mime : fallback;
|
|
@@ -14087,7 +14211,7 @@ function inferContentType(filePath, fallback) {
|
|
|
14087
14211
|
function deriveManifestMode(streams) {
|
|
14088
14212
|
const modes = new Set(streams.map((s) => s.replicationMode));
|
|
14089
14213
|
if (modes.size > 1) {
|
|
14090
|
-
logger.warn(`${
|
|
14214
|
+
logger.warn(`${logPrefix7} Streams have mixed replication modes (${[...modes].join(", ")}). Manifest will report "FULL".`);
|
|
14091
14215
|
return "FULL";
|
|
14092
14216
|
}
|
|
14093
14217
|
return streams[0]?.replicationMode ?? "INCREMENTAL";
|
|
@@ -14109,13 +14233,13 @@ var AssetTap = class {
|
|
|
14109
14233
|
const dryRun = isDryRun();
|
|
14110
14234
|
const dryRunLimit = dryRun ? getDryRunLimit() : void 0;
|
|
14111
14235
|
if (dryRun) {
|
|
14112
|
-
logger.info(`${
|
|
14236
|
+
logger.info(`${logPrefix7} [DRY_RUN] mode active \u2014 skipping CDN checks and uploads`);
|
|
14113
14237
|
await import_fs_extra4.default.emptyDir(this.outputDir);
|
|
14114
14238
|
if (dryRunLimit !== void 0) {
|
|
14115
|
-
logger.info(`${
|
|
14239
|
+
logger.info(`${logPrefix7} [DRY_RUN] Limit: ${dryRunLimit} assets per stream`);
|
|
14116
14240
|
}
|
|
14117
14241
|
} else if (process.env["DRY_RUN_LIMIT"] !== void 0) {
|
|
14118
|
-
logger.warn(`${
|
|
14242
|
+
logger.warn(`${logPrefix7} DRY_RUN_LIMIT is set but DRY_RUN is not active \u2014 limit will be ignored`);
|
|
14119
14243
|
}
|
|
14120
14244
|
const tmpDir2 = import_node_path4.default.join(this.outputDir, "tmp");
|
|
14121
14245
|
await import_fs_extra4.default.ensureDir(tmpDir2);
|
|
@@ -14123,7 +14247,7 @@ var AssetTap = class {
|
|
|
14123
14247
|
let entryIndex = 0;
|
|
14124
14248
|
let totalSummary = { total: 0, uploaded: 0, skipped: 0, errors: 0 };
|
|
14125
14249
|
for (const stream of this.streams) {
|
|
14126
|
-
logger.info(`${
|
|
14250
|
+
logger.info(`${logPrefix7} Processing stream: ${stream.streamId} (mode=${stream.replicationMode}, concurrency=${this.concurrency})`);
|
|
14127
14251
|
const assetEntries = [];
|
|
14128
14252
|
let streamAssetCount = 0;
|
|
14129
14253
|
await processFromAsyncIterable(
|
|
@@ -14132,11 +14256,11 @@ var AssetTap = class {
|
|
|
14132
14256
|
if (dryRunLimit !== void 0 && streamAssetCount >= dryRunLimit) {
|
|
14133
14257
|
return "stop";
|
|
14134
14258
|
}
|
|
14135
|
-
logger.debug(`${
|
|
14259
|
+
logger.debug(`${logPrefix7} Processing entry: ${entry.sourcePath}`);
|
|
14136
14260
|
if (stream.replicationMode === "INCREMENTAL" && !dryRun) {
|
|
14137
14261
|
const shouldSync = await this.target.shouldSync(entry);
|
|
14138
14262
|
if (!shouldSync) {
|
|
14139
|
-
logger.debug(`${
|
|
14263
|
+
logger.debug(`${logPrefix7} Skipping ${entry.sourcePath} (up-to-date)`);
|
|
14140
14264
|
assetEntries.push({
|
|
14141
14265
|
sourcePath: entry.sourcePath,
|
|
14142
14266
|
destinationPath: entry.destinationPath,
|
|
@@ -14174,6 +14298,13 @@ var AssetTap = class {
|
|
|
14174
14298
|
const inspectPath = import_node_path4.default.join(this.outputDir, stream.streamId, entry.destinationPath);
|
|
14175
14299
|
await import_fs_extra4.default.ensureDir(import_node_path4.default.dirname(inspectPath));
|
|
14176
14300
|
await import_fs_extra4.default.copy(uploadPath, inspectPath);
|
|
14301
|
+
if (wasTransformed) {
|
|
14302
|
+
const baseName = import_node_path4.default.basename(entry.destinationPath, import_node_path4.default.extname(entry.destinationPath));
|
|
14303
|
+
const origExt = getExtension(entry.contentType);
|
|
14304
|
+
const originalPath = import_node_path4.default.join(this.outputDir, "originals", `${baseName}${origExt}`);
|
|
14305
|
+
await import_fs_extra4.default.ensureDir(import_node_path4.default.dirname(originalPath));
|
|
14306
|
+
await import_fs_extra4.default.copy(downloadedPath, originalPath);
|
|
14307
|
+
}
|
|
14177
14308
|
}
|
|
14178
14309
|
assetEntries.push({
|
|
14179
14310
|
sourcePath: entry.sourcePath,
|
|
@@ -14185,10 +14316,10 @@ var AssetTap = class {
|
|
|
14185
14316
|
status: "uploaded",
|
|
14186
14317
|
transformed: wasTransformed
|
|
14187
14318
|
});
|
|
14188
|
-
logger.info(`${
|
|
14319
|
+
logger.info(`${logPrefix7} ${dryRun ? "[DRY_RUN] Processed" : "Uploaded"} ${entry.sourcePath} \u2192 ${entry.destinationPath}`);
|
|
14189
14320
|
} catch (err) {
|
|
14190
14321
|
const message = err instanceof Error ? err.message : String(err);
|
|
14191
|
-
logger.error(`${
|
|
14322
|
+
logger.error(`${logPrefix7} Failed to process ${entry.sourcePath}: ${message}`);
|
|
14192
14323
|
assetEntries.push({
|
|
14193
14324
|
sourcePath: entry.sourcePath,
|
|
14194
14325
|
destinationPath: entry.destinationPath,
|
|
@@ -14207,7 +14338,7 @@ var AssetTap = class {
|
|
|
14207
14338
|
}
|
|
14208
14339
|
}
|
|
14209
14340
|
if (dryRunLimit !== void 0 && streamAssetCount >= dryRunLimit) {
|
|
14210
|
-
logger.info(`${
|
|
14341
|
+
logger.info(`${logPrefix7} [DRY_RUN] Reached limit of ${dryRunLimit} for stream "${stream.streamId}", stopping.`);
|
|
14211
14342
|
return "stop";
|
|
14212
14343
|
}
|
|
14213
14344
|
return "continue";
|
|
@@ -14243,7 +14374,7 @@ var AssetTap = class {
|
|
|
14243
14374
|
if (!dryRun) {
|
|
14244
14375
|
await this.target.complete();
|
|
14245
14376
|
}
|
|
14246
|
-
logger.info(`${
|
|
14377
|
+
logger.info(`${logPrefix7} Sync complete. Uploaded=${totalSummary.uploaded} Skipped=${totalSummary.skipped} Errors=${totalSummary.errors}`);
|
|
14247
14378
|
return manifest;
|
|
14248
14379
|
}
|
|
14249
14380
|
};
|
|
@@ -14281,8 +14412,8 @@ var ImageTransform = class {
|
|
|
14281
14412
|
*/
|
|
14282
14413
|
static async toWebp(inputPath, options) {
|
|
14283
14414
|
const dir = import_node_path5.default.dirname(inputPath);
|
|
14284
|
-
const
|
|
14285
|
-
const outputPath = import_node_path5.default.join(dir, `${
|
|
14415
|
+
const basename2 = import_node_path5.default.basename(inputPath, import_node_path5.default.extname(inputPath));
|
|
14416
|
+
const outputPath = import_node_path5.default.join(dir, `${basename2}.webp`);
|
|
14286
14417
|
let pipeline = (0, import_sharp.default)(inputPath);
|
|
14287
14418
|
const hasSize = options.width !== void 0 && options.height !== void 0;
|
|
14288
14419
|
if (hasSize) {
|
|
@@ -14406,7 +14537,7 @@ async function getFileSizeLabel(filePath) {
|
|
|
14406
14537
|
return "unknown size";
|
|
14407
14538
|
}
|
|
14408
14539
|
}
|
|
14409
|
-
var
|
|
14540
|
+
var logPrefix8 = "[DocumentTap]";
|
|
14410
14541
|
var DocumentTap = class {
|
|
14411
14542
|
config;
|
|
14412
14543
|
outputDir;
|
|
@@ -14425,32 +14556,32 @@ var DocumentTap = class {
|
|
|
14425
14556
|
}
|
|
14426
14557
|
async sync() {
|
|
14427
14558
|
if (!this.target) {
|
|
14428
|
-
throw new Error(`${
|
|
14559
|
+
throw new Error(`${logPrefix8} No target set. Assign a WhalyDocumentTarget before calling sync().`);
|
|
14429
14560
|
}
|
|
14430
14561
|
await this.init();
|
|
14431
14562
|
if (!this.stream) {
|
|
14432
|
-
throw new Error(`${
|
|
14563
|
+
throw new Error(`${logPrefix8} No stream set. Assign this.stream in init().`);
|
|
14433
14564
|
}
|
|
14434
14565
|
const dryRun = isDryRun();
|
|
14435
14566
|
const dryRunLimit = dryRun ? getDryRunLimit() : void 0;
|
|
14436
14567
|
if (dryRun) {
|
|
14437
|
-
logger.info(`${
|
|
14568
|
+
logger.info(`${logPrefix8} [DRY_RUN] mode active \u2014 skipping API calls and uploads`);
|
|
14438
14569
|
await import_fs_extra5.default.emptyDir(this.outputDir);
|
|
14439
14570
|
if (dryRunLimit !== void 0) {
|
|
14440
|
-
logger.info(`${
|
|
14571
|
+
logger.info(`${logPrefix8} [DRY_RUN] Limit: ${dryRunLimit} documents per stream`);
|
|
14441
14572
|
}
|
|
14442
14573
|
} else if (process.env["DRY_RUN_LIMIT"] !== void 0) {
|
|
14443
|
-
logger.warn(`${
|
|
14574
|
+
logger.warn(`${logPrefix8} DRY_RUN_LIMIT is set but DRY_RUN is not active \u2014 limit will be ignored`);
|
|
14444
14575
|
}
|
|
14445
14576
|
const tmpDir2 = import_node_path6.default.join(this.outputDir, "tmp");
|
|
14446
14577
|
await import_fs_extra5.default.ensureDir(tmpDir2);
|
|
14447
14578
|
try {
|
|
14448
14579
|
const stream = this.stream;
|
|
14449
|
-
logger.info(`${
|
|
14580
|
+
logger.info(`${logPrefix8} Processing stream: ${stream.streamId}`);
|
|
14450
14581
|
const sourceEntries = await this.collectSourceEntries(stream, dryRunLimit);
|
|
14451
14582
|
const existingDocs = dryRun ? [] : await this.target.listExistingDocuments();
|
|
14452
14583
|
const diff = this.computeDiff(stream, sourceEntries, existingDocs);
|
|
14453
|
-
logger.info(`${
|
|
14584
|
+
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}`);
|
|
14454
14585
|
const entries = [];
|
|
14455
14586
|
const createTasks = diff.toCreate.map((entry) => async () => {
|
|
14456
14587
|
return this.executeCreate(stream, entry, tmpDir2, dryRun);
|
|
@@ -14484,7 +14615,7 @@ var DocumentTap = class {
|
|
|
14484
14615
|
};
|
|
14485
14616
|
await import_fs_extra5.default.ensureDir(this.outputDir);
|
|
14486
14617
|
await import_fs_extra5.default.writeJson(import_node_path6.default.join(this.outputDir, "manifest.json"), manifest, { spaces: 2 });
|
|
14487
|
-
logger.info(`${
|
|
14618
|
+
logger.info(`${logPrefix8} Sync complete. Created=${streamSummary.created} Updated=${streamSummary.updated} Reuploaded=${streamSummary.reuploaded} Deleted=${streamSummary.deleted} Skipped=${streamSummary.skipped} Errors=${streamSummary.errors}`);
|
|
14488
14619
|
return manifest;
|
|
14489
14620
|
} finally {
|
|
14490
14621
|
await import_fs_extra5.default.remove(tmpDir2).catch(() => void 0);
|
|
@@ -14552,12 +14683,12 @@ var DocumentTap = class {
|
|
|
14552
14683
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "created" };
|
|
14553
14684
|
} catch (err) {
|
|
14554
14685
|
if (err instanceof DocumentDownloadSkipError) {
|
|
14555
|
-
logger.warn(`${
|
|
14686
|
+
logger.warn(`${logPrefix8} Skipped ${entry.externalId} (${entry.fileName}): ${err.message}`);
|
|
14556
14687
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "skipped" };
|
|
14557
14688
|
}
|
|
14558
14689
|
const message = err instanceof Error ? err.message : String(err);
|
|
14559
14690
|
const sizeLabel = await getFileSizeLabel(downloadPath);
|
|
14560
|
-
logger.error(`${
|
|
14691
|
+
logger.error(`${logPrefix8} Failed to create ${entry.externalId} (${entry.fileName}, ${sizeLabel}): ${message}`);
|
|
14561
14692
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "error", error: message };
|
|
14562
14693
|
} finally {
|
|
14563
14694
|
await import_fs_extra5.default.remove(downloadPath).catch(() => void 0);
|
|
@@ -14578,12 +14709,12 @@ var DocumentTap = class {
|
|
|
14578
14709
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "reuploaded" };
|
|
14579
14710
|
} catch (err) {
|
|
14580
14711
|
if (err instanceof DocumentDownloadSkipError) {
|
|
14581
|
-
logger.warn(`${
|
|
14712
|
+
logger.warn(`${logPrefix8} Skipped ${entry.externalId} (${entry.fileName}): ${err.message}`);
|
|
14582
14713
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "skipped" };
|
|
14583
14714
|
}
|
|
14584
14715
|
const message = err instanceof Error ? err.message : String(err);
|
|
14585
14716
|
const sizeLabel = await getFileSizeLabel(downloadPath);
|
|
14586
|
-
logger.error(`${
|
|
14717
|
+
logger.error(`${logPrefix8} Failed to reupload ${entry.externalId} (${entry.fileName}, ${sizeLabel}): ${message}`);
|
|
14587
14718
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "error", error: message };
|
|
14588
14719
|
} finally {
|
|
14589
14720
|
await import_fs_extra5.default.remove(downloadPath).catch(() => void 0);
|
|
@@ -14597,7 +14728,7 @@ var DocumentTap = class {
|
|
|
14597
14728
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "updated" };
|
|
14598
14729
|
} catch (err) {
|
|
14599
14730
|
const message = err instanceof Error ? err.message : String(err);
|
|
14600
|
-
logger.error(`${
|
|
14731
|
+
logger.error(`${logPrefix8} Failed to update metadata for ${entry.externalId}: ${message}`);
|
|
14601
14732
|
return { externalId: entry.externalId, fileName: entry.fileName, status: "error", error: message };
|
|
14602
14733
|
}
|
|
14603
14734
|
}
|
|
@@ -14609,7 +14740,7 @@ var DocumentTap = class {
|
|
|
14609
14740
|
return { externalId: doc.external_id, fileName: doc.file_name, status: "deleted" };
|
|
14610
14741
|
} catch (err) {
|
|
14611
14742
|
const message = err instanceof Error ? err.message : String(err);
|
|
14612
|
-
logger.error(`${
|
|
14743
|
+
logger.error(`${logPrefix8} Failed to delete ${doc.external_id}: ${message}`);
|
|
14613
14744
|
return { externalId: doc.external_id, fileName: doc.file_name, status: "error", error: message };
|
|
14614
14745
|
}
|
|
14615
14746
|
}
|
|
@@ -14646,7 +14777,7 @@ function enrichAxiosError(err) {
|
|
|
14646
14777
|
const detail = typeof body === "string" ? body : JSON.stringify(body ?? "");
|
|
14647
14778
|
return new Error(`${method} ${url} failed with status ${status}: ${detail}`, { cause: err });
|
|
14648
14779
|
}
|
|
14649
|
-
var
|
|
14780
|
+
var logPrefix9 = "[WhalyDocumentService]";
|
|
14650
14781
|
var MAX_RETRIES2 = 10;
|
|
14651
14782
|
var WhalyDocumentService = class {
|
|
14652
14783
|
axiosClient;
|
|
@@ -14659,7 +14790,7 @@ var WhalyDocumentService = class {
|
|
|
14659
14790
|
const gcsBucketName = process.env["WLY_GCS_BUCKET"];
|
|
14660
14791
|
if (gcsBucketName) {
|
|
14661
14792
|
this.gcsBucket = new import_storage2.Storage().bucket(gcsBucketName);
|
|
14662
|
-
logger.info(`${
|
|
14793
|
+
logger.info(`${logPrefix9} Using direct GCS upload to bucket: ${gcsBucketName}`);
|
|
14663
14794
|
}
|
|
14664
14795
|
this.axiosClient = import_axios4.default.create({
|
|
14665
14796
|
baseURL: resolvedEndpoint,
|
|
@@ -14680,12 +14811,12 @@ var WhalyDocumentService = class {
|
|
|
14680
14811
|
if (retryAfter) {
|
|
14681
14812
|
const seconds = Number(retryAfter);
|
|
14682
14813
|
if (!isNaN(seconds) && seconds > 0) {
|
|
14683
|
-
logger.info(`${
|
|
14814
|
+
logger.info(`${logPrefix9} Rate limited \u2014 waiting ${seconds}s, attempt ${retryCount}/${MAX_RETRIES2}`);
|
|
14684
14815
|
return seconds * 1e3;
|
|
14685
14816
|
}
|
|
14686
14817
|
}
|
|
14687
14818
|
const delay = import_axios_retry3.default.exponentialDelay(retryCount);
|
|
14688
|
-
logger.info(`${
|
|
14819
|
+
logger.info(`${logPrefix9} Retrying in ${delay}ms (attempt ${retryCount}/${MAX_RETRIES2}) for ${error.config?.method?.toUpperCase()} ${error.config?.url}`);
|
|
14689
14820
|
return delay;
|
|
14690
14821
|
}
|
|
14691
14822
|
});
|
|
@@ -14706,7 +14837,7 @@ var WhalyDocumentService = class {
|
|
|
14706
14837
|
if (!nextAfter) break;
|
|
14707
14838
|
after = nextAfter;
|
|
14708
14839
|
}
|
|
14709
|
-
logger.info(`${
|
|
14840
|
+
logger.info(`${logPrefix9} Fetched ${documents.length} existing documents from Whaly`);
|
|
14710
14841
|
return documents;
|
|
14711
14842
|
}
|
|
14712
14843
|
/** Upload a file to object storage. Returns storage path and size. */
|
|
@@ -14727,8 +14858,8 @@ var WhalyDocumentService = class {
|
|
|
14727
14858
|
} catch (err) {
|
|
14728
14859
|
if (attempt === maxAttempts) throw err;
|
|
14729
14860
|
const delay = Math.min(1e3 * 2 ** (attempt - 1), 3e4);
|
|
14730
|
-
logger.info(`${
|
|
14731
|
-
await new Promise((
|
|
14861
|
+
logger.info(`${logPrefix9} GCS upload retry ${attempt}/${MAX_RETRIES2} in ${delay}ms for ${destinationPath}`);
|
|
14862
|
+
await new Promise((resolve2) => setTimeout(resolve2, delay));
|
|
14732
14863
|
}
|
|
14733
14864
|
}
|
|
14734
14865
|
const stat = await import_node_fs.default.promises.stat(localFilePath);
|
|
@@ -14784,7 +14915,7 @@ var WhalyDocumentService = class {
|
|
|
14784
14915
|
};
|
|
14785
14916
|
|
|
14786
14917
|
// src/sdk/models/document-target/whaly-document-target.ts
|
|
14787
|
-
var
|
|
14918
|
+
var logPrefix10 = "[WhalyDocumentTarget]";
|
|
14788
14919
|
var WhalyDocumentTarget = class {
|
|
14789
14920
|
config;
|
|
14790
14921
|
service;
|
|
@@ -14803,7 +14934,7 @@ var WhalyDocumentTarget = class {
|
|
|
14803
14934
|
async createDocument(streamId, entry, localFilePath) {
|
|
14804
14935
|
const destinationPath = `${streamId}/${entry.externalId}.${entry.extension}`;
|
|
14805
14936
|
const fileName = `${entry.externalId}.${entry.extension}`;
|
|
14806
|
-
logger.info(`${
|
|
14937
|
+
logger.info(`${logPrefix10} Uploading file for new document: ${entry.externalId}`);
|
|
14807
14938
|
const uploadResult = await this.service.uploadFile(destinationPath, localFilePath, fileName);
|
|
14808
14939
|
const stat = await import_fs_extra6.default.stat(localFilePath);
|
|
14809
14940
|
await this.service.createDocument({
|
|
@@ -14820,7 +14951,7 @@ var WhalyDocumentTarget = class {
|
|
|
14820
14951
|
storage: uploadResult.storage,
|
|
14821
14952
|
metadata: entry.metadata ?? {}
|
|
14822
14953
|
});
|
|
14823
|
-
logger.info(`${
|
|
14954
|
+
logger.info(`${logPrefix10} Created document: ${entry.externalId} (${entry.fileName})`);
|
|
14824
14955
|
}
|
|
14825
14956
|
/**
|
|
14826
14957
|
* Re-upload the file and update the document record.
|
|
@@ -14828,7 +14959,7 @@ var WhalyDocumentTarget = class {
|
|
|
14828
14959
|
async reuploadDocument(streamId, docId, entry, localFilePath) {
|
|
14829
14960
|
const destinationPath = `${streamId}/${entry.externalId}.${entry.extension}`;
|
|
14830
14961
|
const fileName = `${entry.externalId}.${entry.extension}`;
|
|
14831
|
-
logger.info(`${
|
|
14962
|
+
logger.info(`${logPrefix10} Re-uploading file for document: ${entry.externalId}`);
|
|
14832
14963
|
const uploadResult = await this.service.uploadFile(destinationPath, localFilePath, fileName);
|
|
14833
14964
|
const stat = await import_fs_extra6.default.stat(localFilePath);
|
|
14834
14965
|
await this.service.updateDocument(docId, {
|
|
@@ -14845,7 +14976,7 @@ var WhalyDocumentTarget = class {
|
|
|
14845
14976
|
storage: uploadResult.storage,
|
|
14846
14977
|
metadata: entry.metadata ?? {}
|
|
14847
14978
|
});
|
|
14848
|
-
logger.info(`${
|
|
14979
|
+
logger.info(`${logPrefix10} Re-uploaded document: ${entry.externalId} (${entry.fileName})`);
|
|
14849
14980
|
}
|
|
14850
14981
|
/** Update only the metadata fields (no file re-upload). */
|
|
14851
14982
|
async updateDocumentMetadata(docId, entry, existingDoc) {
|
|
@@ -14863,12 +14994,12 @@ var WhalyDocumentTarget = class {
|
|
|
14863
14994
|
storage: existingDoc.storage,
|
|
14864
14995
|
metadata: entry.metadata ?? {}
|
|
14865
14996
|
});
|
|
14866
|
-
logger.info(`${
|
|
14997
|
+
logger.info(`${logPrefix10} Updated metadata for document: ${entry.externalId} (${entry.fileName})`);
|
|
14867
14998
|
}
|
|
14868
14999
|
/** Delete a document record. */
|
|
14869
15000
|
async deleteDocument(docId, externalId) {
|
|
14870
15001
|
await this.service.deleteDocument(docId);
|
|
14871
|
-
logger.info(`${
|
|
15002
|
+
logger.info(`${logPrefix10} Deleted document: ${externalId} (id=${docId})`);
|
|
14872
15003
|
}
|
|
14873
15004
|
};
|
|
14874
15005
|
|
|
@@ -15207,7 +15338,7 @@ var BigQueryDBSync = class extends StreamWarehouseSyncService {
|
|
|
15207
15338
|
gracefulExit(1);
|
|
15208
15339
|
} else {
|
|
15209
15340
|
logger.error(`StreamId: ${this.streamId} - Error when checking if dataset already exists. Retrying... ${err.message} - ${err.code}`);
|
|
15210
|
-
await new Promise((
|
|
15341
|
+
await new Promise((resolve2, reject) => setTimeout(resolve2, 1e3 * retryCount));
|
|
15211
15342
|
await this.createDatabaseAndSchemaIfNotExists(retryCount + 1);
|
|
15212
15343
|
}
|
|
15213
15344
|
}
|
|
@@ -15435,7 +15566,7 @@ var BigQueryTarget = class extends ITarget {
|
|
|
15435
15566
|
|
|
15436
15567
|
// src/targets/cdn/main.ts
|
|
15437
15568
|
var import_fs_extra7 = __toESM(require("fs-extra"));
|
|
15438
|
-
var
|
|
15569
|
+
var logPrefix11 = "[CdnAssetTarget]";
|
|
15439
15570
|
var CdnAssetTarget = class extends AssetTarget {
|
|
15440
15571
|
cdnService;
|
|
15441
15572
|
constructor(config) {
|
|
@@ -15445,20 +15576,20 @@ var CdnAssetTarget = class extends AssetTarget {
|
|
|
15445
15576
|
async shouldSync(entry) {
|
|
15446
15577
|
const metadata = await this.cdnService.getFileMetadata(getCdnId(this.config.cdnId), entry.destinationPath);
|
|
15447
15578
|
if (!metadata.exists) {
|
|
15448
|
-
logger.debug(`${
|
|
15579
|
+
logger.debug(`${logPrefix11} ${entry.destinationPath} not in CDN \u2192 will sync`);
|
|
15449
15580
|
return true;
|
|
15450
15581
|
}
|
|
15451
15582
|
if (entry.lastModified === void 0) {
|
|
15452
|
-
logger.debug(`${
|
|
15583
|
+
logger.debug(`${logPrefix11} ${entry.destinationPath} source has no lastModified \u2192 will sync`);
|
|
15453
15584
|
return true;
|
|
15454
15585
|
}
|
|
15455
15586
|
if (metadata.lastModified === null) {
|
|
15456
|
-
logger.debug(`${
|
|
15587
|
+
logger.debug(`${logPrefix11} ${entry.destinationPath} CDN has no lastModified \u2192 will sync`);
|
|
15457
15588
|
return true;
|
|
15458
15589
|
}
|
|
15459
15590
|
const sourceIsNewer = entry.lastModified > metadata.lastModified;
|
|
15460
15591
|
if (!sourceIsNewer) {
|
|
15461
|
-
logger.debug(`${
|
|
15592
|
+
logger.debug(`${logPrefix11} Skipping ${entry.destinationPath} (CDN is up-to-date)`);
|
|
15462
15593
|
}
|
|
15463
15594
|
return sourceIsNewer;
|
|
15464
15595
|
}
|
|
@@ -15469,7 +15600,7 @@ var CdnAssetTarget = class extends AssetTarget {
|
|
|
15469
15600
|
asset.entry.destinationPath,
|
|
15470
15601
|
fileBuffer
|
|
15471
15602
|
);
|
|
15472
|
-
logger.info(`${
|
|
15603
|
+
logger.info(`${logPrefix11} Uploaded ${asset.entry.destinationPath} (${fileBuffer.length} bytes)`);
|
|
15473
15604
|
}
|
|
15474
15605
|
};
|
|
15475
15606
|
|
|
@@ -15539,6 +15670,7 @@ var GCSStateProvider = class {
|
|
|
15539
15670
|
GCSStateProvider,
|
|
15540
15671
|
ITarget,
|
|
15541
15672
|
ImageTransform,
|
|
15673
|
+
LocalStorageService,
|
|
15542
15674
|
MIME_TYPES,
|
|
15543
15675
|
MissingFieldInSchemaError,
|
|
15544
15676
|
MissingSchemaError,
|
|
@@ -15594,6 +15726,7 @@ var GCSStateProvider = class {
|
|
|
15594
15726
|
getCounterMetrics,
|
|
15595
15727
|
getDownloadFileApiCall,
|
|
15596
15728
|
getDryRunLimit,
|
|
15729
|
+
getExtension,
|
|
15597
15730
|
getJSONApiCall,
|
|
15598
15731
|
getJSONApiCallWithFullResponse,
|
|
15599
15732
|
getMimeType,
|