@whaly/connector-sdk 0.3.10 → 0.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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);
@@ -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((resolve, reject) => {
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
- resolve();
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((resolve, reject) => {
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 resolve();
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((resolve, reject) => {
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", () => resolve(Math.max(0, newlines - 1))).on("error", reject);
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((resolve, reject) => {
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
- resolve();
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 logPrefix5 = "[CdnService]";
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(`${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}`);
13871
13983
  return seconds * 1e3;
13872
13984
  }
13873
13985
  }
13874
13986
  const delay = axiosRetry2.exponentialDelay(retryCount);
13875
- 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}`);
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(`${logPrefix5} HEAD not supported for ${url}, treating file as absent`);
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(`${logPrefix5} Uploading ${fileName} (${fileBuffer.length} bytes) to CDN ${cdnId}`);
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(`${logPrefix5} Successfully uploaded ${fileName} (status ${response.status})`);
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 fs6 from "fs-extra";
14082
+ import fs7 from "fs-extra";
13971
14083
  import path5 from "path";
13972
- var logPrefix6 = "[AssetTap]";
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(`${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".`);
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(`${logPrefix6} [DRY_RUN] mode active \u2014 skipping CDN checks and uploads`);
14003
- 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);
14004
14116
  if (dryRunLimit !== void 0) {
14005
- logger.info(`${logPrefix6} [DRY_RUN] Limit: ${dryRunLimit} assets per stream`);
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(`${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`);
14009
14121
  }
14010
14122
  const tmpDir2 = path5.join(this.outputDir, "tmp");
14011
- await fs6.ensureDir(tmpDir2);
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(`${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})`);
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(`${logPrefix6} Processing entry: ${entry.sourcePath}`);
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(`${logPrefix6} Skipping ${entry.sourcePath} (up-to-date)`);
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 fs6.stat(uploadPath);
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 fs6.ensureDir(path5.dirname(inspectPath));
14066
- await fs6.copy(uploadPath, inspectPath);
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 fs6.ensureDir(path5.dirname(originalPath));
14072
- await fs6.copy(downloadedPath, originalPath);
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(`${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}`);
14086
14198
  } catch (err) {
14087
14199
  const message = err instanceof Error ? err.message : String(err);
14088
- logger.error(`${logPrefix6} Failed to process ${entry.sourcePath}: ${message}`);
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 fs6.remove(downloadedPath).catch(() => void 0);
14213
+ await fs7.remove(downloadedPath).catch(() => void 0);
14102
14214
  if (uploadPath !== downloadedPath) {
14103
- await fs6.remove(uploadPath).catch(() => void 0);
14215
+ await fs7.remove(uploadPath).catch(() => void 0);
14104
14216
  }
14105
14217
  }
14106
14218
  if (dryRunLimit !== void 0 && streamAssetCount >= dryRunLimit) {
14107
- 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.`);
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 fs6.ensureDir(this.outputDir);
14139
- 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 });
14140
14252
  if (!dryRun) {
14141
14253
  await this.target.complete();
14142
14254
  }
14143
- 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}`);
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 basename = path6.basename(inputPath, path6.extname(inputPath));
14182
- const outputPath = path6.join(dir, `${basename}.webp`);
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 fs7 from "fs-extra";
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 fs7.stat(filePath);
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 logPrefix7 = "[DocumentTap]";
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(`${logPrefix7} No target set. Assign a WhalyDocumentTarget before calling sync().`);
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(`${logPrefix7} No stream set. Assign this.stream in init().`);
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(`${logPrefix7} [DRY_RUN] mode active \u2014 skipping API calls and uploads`);
14335
- 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);
14336
14448
  if (dryRunLimit !== void 0) {
14337
- logger.info(`${logPrefix7} [DRY_RUN] Limit: ${dryRunLimit} documents per stream`);
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(`${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`);
14341
14453
  }
14342
14454
  const tmpDir2 = path7.join(this.outputDir, "tmp");
14343
- await fs7.ensureDir(tmpDir2);
14455
+ await fs8.ensureDir(tmpDir2);
14344
14456
  try {
14345
14457
  const stream = this.stream;
14346
- logger.info(`${logPrefix7} Processing stream: ${stream.streamId}`);
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(`${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}`);
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 fs7.ensureDir(this.outputDir);
14383
- await fs7.writeJson(path7.join(this.outputDir, "manifest.json"), manifest, { spaces: 2 });
14384
- 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}`);
14385
14497
  return manifest;
14386
14498
  } finally {
14387
- await fs7.remove(tmpDir2).catch(() => void 0);
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 fs7.ensureDir(path7.dirname(inspectPath));
14447
- await fs7.copy(downloadPath, inspectPath);
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(`${logPrefix7} Skipped ${entry.externalId} (${entry.fileName}): ${err.message}`);
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(`${logPrefix7} Failed to create ${entry.externalId} (${entry.fileName}, ${sizeLabel}): ${message}`);
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 fs7.remove(downloadPath).catch(() => void 0);
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 fs7.ensureDir(path7.dirname(inspectPath));
14473
- await fs7.copy(downloadPath, inspectPath);
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(`${logPrefix7} Skipped ${entry.externalId} (${entry.fileName}): ${err.message}`);
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(`${logPrefix7} Failed to reupload ${entry.externalId} (${entry.fileName}, ${sizeLabel}): ${message}`);
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 fs7.remove(downloadPath).catch(() => void 0);
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(`${logPrefix7} Failed to update metadata for ${entry.externalId}: ${message}`);
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(`${logPrefix7} Failed to delete ${doc.external_id}: ${message}`);
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 fs9 from "fs-extra";
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 fs8 from "fs";
14647
+ import fs9 from "fs";
14536
14648
  import { Storage as Storage2 } from "@google-cloud/storage";
14537
14649
  function enrichAxiosError(err) {
14538
14650
  if (!axios4.isAxiosError(err)) return err instanceof Error ? err : new Error(String(err));
@@ -14543,7 +14655,7 @@ function enrichAxiosError(err) {
14543
14655
  const detail = typeof body === "string" ? body : JSON.stringify(body ?? "");
14544
14656
  return new Error(`${method} ${url} failed with status ${status}: ${detail}`, { cause: err });
14545
14657
  }
14546
- var logPrefix8 = "[WhalyDocumentService]";
14658
+ var logPrefix9 = "[WhalyDocumentService]";
14547
14659
  var MAX_RETRIES2 = 10;
14548
14660
  var WhalyDocumentService = class {
14549
14661
  axiosClient;
@@ -14556,7 +14668,7 @@ var WhalyDocumentService = class {
14556
14668
  const gcsBucketName = process.env["WLY_GCS_BUCKET"];
14557
14669
  if (gcsBucketName) {
14558
14670
  this.gcsBucket = new Storage2().bucket(gcsBucketName);
14559
- logger.info(`${logPrefix8} Using direct GCS upload to bucket: ${gcsBucketName}`);
14671
+ logger.info(`${logPrefix9} Using direct GCS upload to bucket: ${gcsBucketName}`);
14560
14672
  }
14561
14673
  this.axiosClient = axios4.create({
14562
14674
  baseURL: resolvedEndpoint,
@@ -14577,12 +14689,12 @@ var WhalyDocumentService = class {
14577
14689
  if (retryAfter) {
14578
14690
  const seconds = Number(retryAfter);
14579
14691
  if (!isNaN(seconds) && seconds > 0) {
14580
- logger.info(`${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}`);
14581
14693
  return seconds * 1e3;
14582
14694
  }
14583
14695
  }
14584
14696
  const delay = axiosRetry3.exponentialDelay(retryCount);
14585
- 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}`);
14586
14698
  return delay;
14587
14699
  }
14588
14700
  });
@@ -14603,7 +14715,7 @@ var WhalyDocumentService = class {
14603
14715
  if (!nextAfter) break;
14604
14716
  after = nextAfter;
14605
14717
  }
14606
- logger.info(`${logPrefix8} Fetched ${documents.length} existing documents from Whaly`);
14718
+ logger.info(`${logPrefix9} Fetched ${documents.length} existing documents from Whaly`);
14607
14719
  return documents;
14608
14720
  }
14609
14721
  /** Upload a file to object storage. Returns storage path and size. */
@@ -14624,11 +14736,11 @@ var WhalyDocumentService = class {
14624
14736
  } catch (err) {
14625
14737
  if (attempt === maxAttempts) throw err;
14626
14738
  const delay = Math.min(1e3 * 2 ** (attempt - 1), 3e4);
14627
- logger.info(`${logPrefix8} GCS upload retry ${attempt}/${MAX_RETRIES2} in ${delay}ms for ${destinationPath}`);
14628
- 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));
14629
14741
  }
14630
14742
  }
14631
- const stat = await fs8.promises.stat(localFilePath);
14743
+ const stat = await fs9.promises.stat(localFilePath);
14632
14744
  return {
14633
14745
  storage: this.objectStorageId,
14634
14746
  filePath: destinationPath,
@@ -14637,7 +14749,7 @@ var WhalyDocumentService = class {
14637
14749
  }
14638
14750
  async uploadFileViaAPI(destinationPath, localFilePath, fileName) {
14639
14751
  const form = new import_form_data.default();
14640
- form.append("file", fs8.createReadStream(localFilePath), fileName);
14752
+ form.append("file", fs9.createReadStream(localFilePath), fileName);
14641
14753
  try {
14642
14754
  const response = await this.axiosClient.post(
14643
14755
  `/v1/object-storages/${this.objectStorageId}/upload`,
@@ -14681,7 +14793,7 @@ var WhalyDocumentService = class {
14681
14793
  };
14682
14794
 
14683
14795
  // src/sdk/models/document-target/whaly-document-target.ts
14684
- var logPrefix9 = "[WhalyDocumentTarget]";
14796
+ var logPrefix10 = "[WhalyDocumentTarget]";
14685
14797
  var WhalyDocumentTarget = class {
14686
14798
  config;
14687
14799
  service;
@@ -14700,9 +14812,9 @@ var WhalyDocumentTarget = class {
14700
14812
  async createDocument(streamId, entry, localFilePath) {
14701
14813
  const destinationPath = `${streamId}/${entry.externalId}.${entry.extension}`;
14702
14814
  const fileName = `${entry.externalId}.${entry.extension}`;
14703
- logger.info(`${logPrefix9} Uploading file for new document: ${entry.externalId}`);
14815
+ logger.info(`${logPrefix10} Uploading file for new document: ${entry.externalId}`);
14704
14816
  const uploadResult = await this.service.uploadFile(destinationPath, localFilePath, fileName);
14705
- const stat = await fs9.stat(localFilePath);
14817
+ const stat = await fs10.stat(localFilePath);
14706
14818
  await this.service.createDocument({
14707
14819
  file_name: entry.fileName,
14708
14820
  external_id: entry.externalId,
@@ -14717,7 +14829,7 @@ var WhalyDocumentTarget = class {
14717
14829
  storage: uploadResult.storage,
14718
14830
  metadata: entry.metadata ?? {}
14719
14831
  });
14720
- logger.info(`${logPrefix9} Created document: ${entry.externalId} (${entry.fileName})`);
14832
+ logger.info(`${logPrefix10} Created document: ${entry.externalId} (${entry.fileName})`);
14721
14833
  }
14722
14834
  /**
14723
14835
  * Re-upload the file and update the document record.
@@ -14725,9 +14837,9 @@ var WhalyDocumentTarget = class {
14725
14837
  async reuploadDocument(streamId, docId, entry, localFilePath) {
14726
14838
  const destinationPath = `${streamId}/${entry.externalId}.${entry.extension}`;
14727
14839
  const fileName = `${entry.externalId}.${entry.extension}`;
14728
- logger.info(`${logPrefix9} Re-uploading file for document: ${entry.externalId}`);
14840
+ logger.info(`${logPrefix10} Re-uploading file for document: ${entry.externalId}`);
14729
14841
  const uploadResult = await this.service.uploadFile(destinationPath, localFilePath, fileName);
14730
- const stat = await fs9.stat(localFilePath);
14842
+ const stat = await fs10.stat(localFilePath);
14731
14843
  await this.service.updateDocument(docId, {
14732
14844
  external_id: entry.externalId,
14733
14845
  file_name: entry.fileName,
@@ -14742,7 +14854,7 @@ var WhalyDocumentTarget = class {
14742
14854
  storage: uploadResult.storage,
14743
14855
  metadata: entry.metadata ?? {}
14744
14856
  });
14745
- logger.info(`${logPrefix9} Re-uploaded document: ${entry.externalId} (${entry.fileName})`);
14857
+ logger.info(`${logPrefix10} Re-uploaded document: ${entry.externalId} (${entry.fileName})`);
14746
14858
  }
14747
14859
  /** Update only the metadata fields (no file re-upload). */
14748
14860
  async updateDocumentMetadata(docId, entry, existingDoc) {
@@ -14760,12 +14872,12 @@ var WhalyDocumentTarget = class {
14760
14872
  storage: existingDoc.storage,
14761
14873
  metadata: entry.metadata ?? {}
14762
14874
  });
14763
- logger.info(`${logPrefix9} Updated metadata for document: ${entry.externalId} (${entry.fileName})`);
14875
+ logger.info(`${logPrefix10} Updated metadata for document: ${entry.externalId} (${entry.fileName})`);
14764
14876
  }
14765
14877
  /** Delete a document record. */
14766
14878
  async deleteDocument(docId, externalId) {
14767
14879
  await this.service.deleteDocument(docId);
14768
- logger.info(`${logPrefix9} Deleted document: ${externalId} (id=${docId})`);
14880
+ logger.info(`${logPrefix10} Deleted document: ${externalId} (id=${docId})`);
14769
14881
  }
14770
14882
  };
14771
14883
 
@@ -15104,7 +15216,7 @@ var BigQueryDBSync = class extends StreamWarehouseSyncService {
15104
15216
  gracefulExit(1);
15105
15217
  } else {
15106
15218
  logger.error(`StreamId: ${this.streamId} - Error when checking if dataset already exists. Retrying... ${err.message} - ${err.code}`);
15107
- await new Promise((resolve, reject) => setTimeout(resolve, 1e3 * retryCount));
15219
+ await new Promise((resolve2, reject) => setTimeout(resolve2, 1e3 * retryCount));
15108
15220
  await this.createDatabaseAndSchemaIfNotExists(retryCount + 1);
15109
15221
  }
15110
15222
  }
@@ -15331,8 +15443,8 @@ var BigQueryTarget = class extends ITarget {
15331
15443
  };
15332
15444
 
15333
15445
  // src/targets/cdn/main.ts
15334
- import fs10 from "fs-extra";
15335
- var logPrefix10 = "[CdnAssetTarget]";
15446
+ import fs11 from "fs-extra";
15447
+ var logPrefix11 = "[CdnAssetTarget]";
15336
15448
  var CdnAssetTarget = class extends AssetTarget {
15337
15449
  cdnService;
15338
15450
  constructor(config) {
@@ -15342,31 +15454,31 @@ var CdnAssetTarget = class extends AssetTarget {
15342
15454
  async shouldSync(entry) {
15343
15455
  const metadata = await this.cdnService.getFileMetadata(getCdnId(this.config.cdnId), entry.destinationPath);
15344
15456
  if (!metadata.exists) {
15345
- logger.debug(`${logPrefix10} ${entry.destinationPath} not in CDN \u2192 will sync`);
15457
+ logger.debug(`${logPrefix11} ${entry.destinationPath} not in CDN \u2192 will sync`);
15346
15458
  return true;
15347
15459
  }
15348
15460
  if (entry.lastModified === void 0) {
15349
- logger.debug(`${logPrefix10} ${entry.destinationPath} source has no lastModified \u2192 will sync`);
15461
+ logger.debug(`${logPrefix11} ${entry.destinationPath} source has no lastModified \u2192 will sync`);
15350
15462
  return true;
15351
15463
  }
15352
15464
  if (metadata.lastModified === null) {
15353
- logger.debug(`${logPrefix10} ${entry.destinationPath} CDN has no lastModified \u2192 will sync`);
15465
+ logger.debug(`${logPrefix11} ${entry.destinationPath} CDN has no lastModified \u2192 will sync`);
15354
15466
  return true;
15355
15467
  }
15356
15468
  const sourceIsNewer = entry.lastModified > metadata.lastModified;
15357
15469
  if (!sourceIsNewer) {
15358
- logger.debug(`${logPrefix10} Skipping ${entry.destinationPath} (CDN is up-to-date)`);
15470
+ logger.debug(`${logPrefix11} Skipping ${entry.destinationPath} (CDN is up-to-date)`);
15359
15471
  }
15360
15472
  return sourceIsNewer;
15361
15473
  }
15362
15474
  async uploadAsset(asset) {
15363
- const fileBuffer = await fs10.readFile(asset.uploadPath);
15475
+ const fileBuffer = await fs11.readFile(asset.uploadPath);
15364
15476
  await this.cdnService.uploadFile(
15365
15477
  getCdnId(this.config.cdnId),
15366
15478
  asset.entry.destinationPath,
15367
15479
  fileBuffer
15368
15480
  );
15369
- logger.info(`${logPrefix10} Uploaded ${asset.entry.destinationPath} (${fileBuffer.length} bytes)`);
15481
+ logger.info(`${logPrefix11} Uploaded ${asset.entry.destinationPath} (${fileBuffer.length} bytes)`);
15370
15482
  }
15371
15483
  };
15372
15484
 
@@ -15435,6 +15547,7 @@ export {
15435
15547
  GCSStateProvider,
15436
15548
  ITarget,
15437
15549
  ImageTransform,
15550
+ LocalStorageService,
15438
15551
  MIME_TYPES,
15439
15552
  MissingFieldInSchemaError,
15440
15553
  MissingSchemaError,