@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.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 extname2 = __require("path").extname;
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 = extname2("x." + path8).toLowerCase().substr(1);
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 fs11 = __require("fs");
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
- fs11.stat(value.path, function(err, stat) {
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((resolve, reject) => {
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
- resolve({ outputDir: output });
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((resolve, reject) => {
10685
- logger.closeWinston(resolve);
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((resolve, reject) => {
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
- resolve();
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((resolve, reject) => {
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 resolve();
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((resolve, reject) => {
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", () => resolve(Math.max(0, newlines - 1))).on("error", reject);
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((resolve, reject) => {
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
- resolve();
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 logPrefix5 = "[CdnService]";
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(`${logPrefix5} Rate limited \u2014 waiting ${seconds}s (Retry-After header), attempt ${retryCount}/${MAX_RETRIES}`);
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(`${logPrefix5} Retrying in ${delay}ms (attempt ${retryCount}/${MAX_RETRIES}) for ${error.config?.method?.toUpperCase()} ${error.config?.url}`);
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(`${logPrefix5} HEAD not supported for ${url}, treating file as absent`);
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(`${logPrefix5} Uploading ${fileName} (${fileBuffer.length} bytes) to CDN ${cdnId}`);
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(`${logPrefix5} Successfully uploaded ${fileName} (status ${response.status})`);
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 fs6 from "fs-extra";
14082
+ import fs7 from "fs-extra";
13961
14083
  import path5 from "path";
13962
- var logPrefix6 = "[AssetTap]";
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(`${logPrefix6} Streams have mixed replication modes (${[...modes].join(", ")}). Manifest will report "FULL".`);
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(`${logPrefix6} [DRY_RUN] mode active \u2014 skipping CDN checks and uploads`);
13993
- await fs6.emptyDir(this.outputDir);
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(`${logPrefix6} [DRY_RUN] Limit: ${dryRunLimit} assets per stream`);
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(`${logPrefix6} DRY_RUN_LIMIT is set but DRY_RUN is not active \u2014 limit will be ignored`);
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 fs6.ensureDir(tmpDir2);
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(`${logPrefix6} Processing stream: ${stream.streamId} (mode=${stream.replicationMode}, concurrency=${this.concurrency})`);
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(`${logPrefix6} Processing entry: ${entry.sourcePath}`);
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(`${logPrefix6} Skipping ${entry.sourcePath} (up-to-date)`);
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 fs6.stat(uploadPath);
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 fs6.ensureDir(path5.dirname(inspectPath));
14056
- await fs6.copy(uploadPath, inspectPath);
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(`${logPrefix6} ${dryRun ? "[DRY_RUN] Processed" : "Uploaded"} ${entry.sourcePath} \u2192 ${entry.destinationPath}`);
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(`${logPrefix6} Failed to process ${entry.sourcePath}: ${message}`);
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 fs6.remove(downloadedPath).catch(() => void 0);
14213
+ await fs7.remove(downloadedPath).catch(() => void 0);
14085
14214
  if (uploadPath !== downloadedPath) {
14086
- await fs6.remove(uploadPath).catch(() => void 0);
14215
+ await fs7.remove(uploadPath).catch(() => void 0);
14087
14216
  }
14088
14217
  }
14089
14218
  if (dryRunLimit !== void 0 && streamAssetCount >= dryRunLimit) {
14090
- logger.info(`${logPrefix6} [DRY_RUN] Reached limit of ${dryRunLimit} for stream "${stream.streamId}", stopping.`);
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 fs6.ensureDir(this.outputDir);
14122
- await fs6.writeJson(path5.join(this.outputDir, "manifest.json"), manifest, { spaces: 2 });
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(`${logPrefix6} Sync complete. Uploaded=${totalSummary.uploaded} Skipped=${totalSummary.skipped} Errors=${totalSummary.errors}`);
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 basename = path6.basename(inputPath, path6.extname(inputPath));
14165
- const outputPath = path6.join(dir, `${basename}.webp`);
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 fs7 from "fs-extra";
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 fs7.stat(filePath);
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 logPrefix7 = "[DocumentTap]";
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(`${logPrefix7} No target set. Assign a WhalyDocumentTarget before calling sync().`);
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(`${logPrefix7} No stream set. Assign this.stream in init().`);
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(`${logPrefix7} [DRY_RUN] mode active \u2014 skipping API calls and uploads`);
14318
- await fs7.emptyDir(this.outputDir);
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(`${logPrefix7} [DRY_RUN] Limit: ${dryRunLimit} documents per stream`);
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(`${logPrefix7} DRY_RUN_LIMIT is set but DRY_RUN is not active \u2014 limit will be ignored`);
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 fs7.ensureDir(tmpDir2);
14455
+ await fs8.ensureDir(tmpDir2);
14327
14456
  try {
14328
14457
  const stream = this.stream;
14329
- logger.info(`${logPrefix7} Processing stream: ${stream.streamId}`);
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(`${logPrefix7} Stream ${stream.streamId} diff: create=${diff.toCreate.length} reupload=${diff.toReupload.length} updateMeta=${diff.toUpdateMetadata.length} delete=${diff.toDelete.length} skip=${diff.skipped.length}`);
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 fs7.ensureDir(this.outputDir);
14366
- await fs7.writeJson(path7.join(this.outputDir, "manifest.json"), manifest, { spaces: 2 });
14367
- logger.info(`${logPrefix7} Sync complete. Created=${streamSummary.created} Updated=${streamSummary.updated} Reuploaded=${streamSummary.reuploaded} Deleted=${streamSummary.deleted} Skipped=${streamSummary.skipped} Errors=${streamSummary.errors}`);
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 fs7.remove(tmpDir2).catch(() => void 0);
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 fs7.ensureDir(path7.dirname(inspectPath));
14430
- await fs7.copy(downloadPath, inspectPath);
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(`${logPrefix7} Skipped ${entry.externalId} (${entry.fileName}): ${err.message}`);
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(`${logPrefix7} Failed to create ${entry.externalId} (${entry.fileName}, ${sizeLabel}): ${message}`);
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 fs7.remove(downloadPath).catch(() => void 0);
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 fs7.ensureDir(path7.dirname(inspectPath));
14456
- await fs7.copy(downloadPath, inspectPath);
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(`${logPrefix7} Skipped ${entry.externalId} (${entry.fileName}): ${err.message}`);
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(`${logPrefix7} Failed to reupload ${entry.externalId} (${entry.fileName}, ${sizeLabel}): ${message}`);
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 fs7.remove(downloadPath).catch(() => void 0);
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(`${logPrefix7} Failed to update metadata for ${entry.externalId}: ${message}`);
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(`${logPrefix7} Failed to delete ${doc.external_id}: ${message}`);
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 fs9 from "fs-extra";
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 fs8 from "fs";
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 logPrefix8 = "[WhalyDocumentService]";
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(`${logPrefix8} Using direct GCS upload to bucket: ${gcsBucketName}`);
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(`${logPrefix8} Rate limited \u2014 waiting ${seconds}s, attempt ${retryCount}/${MAX_RETRIES2}`);
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(`${logPrefix8} Retrying in ${delay}ms (attempt ${retryCount}/${MAX_RETRIES2}) for ${error.config?.method?.toUpperCase()} ${error.config?.url}`);
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(`${logPrefix8} Fetched ${documents.length} existing documents from Whaly`);
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(`${logPrefix8} GCS upload retry ${attempt}/${MAX_RETRIES2} in ${delay}ms for ${destinationPath}`);
14611
- await new Promise((resolve) => setTimeout(resolve, delay));
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 fs8.promises.stat(localFilePath);
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", fs8.createReadStream(localFilePath), fileName);
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 logPrefix9 = "[WhalyDocumentTarget]";
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(`${logPrefix9} Uploading file for new document: ${entry.externalId}`);
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 fs9.stat(localFilePath);
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(`${logPrefix9} Created document: ${entry.externalId} (${entry.fileName})`);
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(`${logPrefix9} Re-uploading file for document: ${entry.externalId}`);
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 fs9.stat(localFilePath);
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(`${logPrefix9} Re-uploaded document: ${entry.externalId} (${entry.fileName})`);
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(`${logPrefix9} Updated metadata for document: ${entry.externalId} (${entry.fileName})`);
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(`${logPrefix9} Deleted document: ${externalId} (id=${docId})`);
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((resolve, reject) => setTimeout(resolve, 1e3 * retryCount));
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 fs10 from "fs-extra";
15318
- var logPrefix10 = "[CdnAssetTarget]";
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(`${logPrefix10} ${entry.destinationPath} not in CDN \u2192 will sync`);
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(`${logPrefix10} ${entry.destinationPath} source has no lastModified \u2192 will sync`);
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(`${logPrefix10} ${entry.destinationPath} CDN has no lastModified \u2192 will sync`);
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(`${logPrefix10} Skipping ${entry.destinationPath} (CDN is up-to-date)`);
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 fs10.readFile(asset.uploadPath);
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(`${logPrefix10} Uploaded ${asset.entry.destinationPath} (${fileBuffer.length} bytes)`);
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,