@bayoudhi/moose-lib-serverless 0.7.2 → 0.7.4

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.js CHANGED
@@ -5,7 +5,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __commonJS = (cb, mod) => function __require() {
8
+ var __commonJS = (cb, mod) => function __require2() {
9
9
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
10
  };
11
11
  var __export = (target, all) => {
@@ -191,9 +191,11 @@ var index_exports = {};
191
191
  __export(index_exports, {
192
192
  ACKs: () => ACKs,
193
193
  Api: () => Api,
194
+ ApiHelpers: () => ApiHelpers,
194
195
  CSV_DELIMITERS: () => CSV_DELIMITERS,
195
196
  ClickHouseEngines: () => ClickHouseEngines,
196
197
  ConsumptionApi: () => ConsumptionApi,
198
+ ConsumptionHelpers: () => ConsumptionHelpers,
197
199
  DEFAULT_CSV_CONFIG: () => DEFAULT_CSV_CONFIG,
198
200
  DEFAULT_JSON_CONFIG: () => DEFAULT_JSON_CONFIG,
199
201
  DataSource: () => DataSource,
@@ -207,7 +209,10 @@ __export(index_exports, {
207
209
  MAX_RETRY_TIME_MS: () => MAX_RETRY_TIME_MS,
208
210
  MOOSE_RUNTIME_ENV_PREFIX: () => MOOSE_RUNTIME_ENV_PREFIX,
209
211
  MaterializedView: () => MaterializedView,
212
+ MooseCache: () => MooseCache,
213
+ MooseClient: () => MooseClient,
210
214
  OlapTable: () => OlapTable,
215
+ QueryClient: () => QueryClient,
211
216
  RETRY_FACTOR_PRODUCER: () => RETRY_FACTOR_PRODUCER,
212
217
  RETRY_INITIAL_TIME_MS: () => RETRY_INITIAL_TIME_MS,
213
218
  Sql: () => Sql,
@@ -217,24 +222,35 @@ __export(index_exports, {
217
222
  View: () => View,
218
223
  WebApp: () => WebApp,
219
224
  Workflow: () => Workflow,
225
+ WorkflowClient: () => WorkflowClient,
220
226
  antiCachePath: () => antiCachePath,
221
227
  cliLog: () => cliLog,
222
228
  compilerLog: () => compilerLog,
223
229
  configureClickHouse: () => configureClickHouse,
224
230
  createClickhouseParameter: () => createClickhouseParameter,
231
+ createProducerConfig: () => createProducerConfig,
232
+ expressMiddleware: () => expressMiddleware,
225
233
  getApi: () => getApi,
226
234
  getApis: () => getApis,
235
+ getClickhouseClient: () => getClickhouseClient,
227
236
  getFileName: () => getFileName,
228
237
  getIngestApi: () => getIngestApi,
229
238
  getIngestApis: () => getIngestApis,
239
+ getKafkaClient: () => getKafkaClient,
240
+ getKafkaProducer: () => getKafkaProducer,
241
+ getLegacyMooseUtils: () => getLegacyMooseUtils,
230
242
  getMaterializedView: () => getMaterializedView,
231
243
  getMaterializedViews: () => getMaterializedViews,
244
+ getMooseClients: () => getMooseClients,
245
+ getMooseUtils: () => getMooseUtils,
246
+ getMooseUtilsFromRequest: () => getMooseUtilsFromRequest,
232
247
  getSqlResource: () => getSqlResource,
233
248
  getSqlResources: () => getSqlResources,
234
249
  getStream: () => getStream,
235
250
  getStreams: () => getStreams,
236
251
  getTable: () => getTable,
237
252
  getTables: () => getTables,
253
+ getTemporalClient: () => getTemporalClient,
238
254
  getValueFromParameter: () => getValueFromParameter,
239
255
  getView: () => getView,
240
256
  getViews: () => getViews,
@@ -243,6 +259,7 @@ __export(index_exports, {
243
259
  getWorkflow: () => getWorkflow,
244
260
  getWorkflows: () => getWorkflows2,
245
261
  isValidCSVDelimiter: () => isValidCSVDelimiter,
262
+ joinQueries: () => joinQueries,
246
263
  logError: () => logError,
247
264
  mapToClickHouseType: () => mapToClickHouseType,
248
265
  mapTstoJs: () => mapTstoJs,
@@ -252,6 +269,7 @@ __export(index_exports, {
252
269
  parseJSON: () => parseJSON,
253
270
  parseJSONWithDates: () => parseJSONWithDates,
254
271
  quoteIdentifier: () => quoteIdentifier,
272
+ rewriteImportExtensions: () => rewriteImportExtensions,
255
273
  sql: () => sql,
256
274
  toQuery: () => toQuery,
257
275
  toQueryPreview: () => toQueryPreview,
@@ -259,7 +277,7 @@ __export(index_exports, {
259
277
  });
260
278
  module.exports = __toCommonJS(index_exports);
261
279
 
262
- // ../ts-moose-lib/dist/serverless.mjs
280
+ // ../../node_modules/.pnpm/@514labs+moose-lib@0.6.417_@swc+helpers@0.5.17_esbuild@0.25.12_ts-patch@3.3.0_tsconfig-paths@_suczegg7f7vmuhhhtfsuwrbhmu/node_modules/@514labs/moose-lib/dist/index.mjs
263
281
  var import_fs = require("fs");
264
282
  var import_path = __toESM(require("path"), 1);
265
283
  var import_client = require("@clickhouse/client");
@@ -267,14 +285,26 @@ var import_kafka_javascript = __toESM(require_kafka_javascript(), 1);
267
285
  var import_path2 = __toESM(require("path"), 1);
268
286
  var toml = __toESM(require("toml"), 1);
269
287
  var import_process = __toESM(require("process"), 1);
270
- var import_client2 = __toESM(require_client(), 1);
271
- var import_redis = __toESM(require_redis(), 1);
272
- var import_csv_parse = require("csv-parse");
288
+ var path2 = __toESM(require("path"), 1);
289
+ var import_fs2 = require("fs");
290
+ var import_path3 = __toESM(require("path"), 1);
273
291
  var import_stream = require("stream");
274
292
  var import_crypto = require("crypto");
275
293
  var import_crypto2 = require("crypto");
294
+ var import_client2 = __toESM(require_client(), 1);
295
+ var import_crypto3 = require("crypto");
296
+ var import_perf_hooks = require("perf_hooks");
297
+ var fs = __toESM(require("fs"), 1);
298
+ var import_redis = __toESM(require_redis(), 1);
299
+ var import_csv_parse = require("csv-parse");
276
300
  var __defProp2 = Object.defineProperty;
277
301
  var __getOwnPropNames2 = Object.getOwnPropertyNames;
302
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
303
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
304
+ }) : x)(function(x) {
305
+ if (typeof require !== "undefined") return require.apply(this, arguments);
306
+ throw Error('Dynamic require of "' + x + '" is not supported');
307
+ });
278
308
  var __esm = (fn, res) => function __init() {
279
309
  return fn && (res = (0, fn[__getOwnPropNames2(fn)[0]])(fn = 0)), res;
280
310
  };
@@ -342,11 +372,11 @@ function walkDirectory(dir, extensions) {
342
372
  }
343
373
  return results;
344
374
  }
345
- function addJsExtensionToImports(content, fileDir) {
375
+ function addJsExtensionToImports(content2, fileDir) {
346
376
  const fromPattern = /(from\s+['"])(\.\.?\/[^'"]*?)(['"])/g;
347
377
  const bareImportPattern = /(import\s+['"])(\.\.?\/[^'"]*?)(['"])/g;
348
378
  const dynamicPattern = /(import\s*\(\s*['"])(\.\.?\/[^'"]*?)(['"])/g;
349
- let result = content;
379
+ let result = content2;
350
380
  result = result.replace(fromPattern, (match, prefix, importPath, quote) => {
351
381
  return rewriteImportPath(match, prefix, importPath, quote, fileDir);
352
382
  });
@@ -397,10 +427,10 @@ function rewriteImportPath(match, prefix, importPath, quote, fileDir) {
397
427
  function rewriteImportExtensions(outDir) {
398
428
  const files = walkDirectory(outDir, [".js", ".mjs"]);
399
429
  for (const filePath of files) {
400
- const content = (0, import_fs.readFileSync)(filePath, "utf-8");
430
+ const content2 = (0, import_fs.readFileSync)(filePath, "utf-8");
401
431
  const fileDir = import_path.default.dirname(filePath);
402
- const rewritten = addJsExtensionToImports(content, fileDir);
403
- if (content !== rewritten) {
432
+ const rewritten = addJsExtensionToImports(content2, fileDir);
433
+ if (content2 !== rewritten) {
404
434
  (0, import_fs.writeFileSync)(filePath, rewritten, "utf-8");
405
435
  }
406
436
  }
@@ -452,7 +482,7 @@ var init_commons = __esm({
452
482
  console.log(message);
453
483
  }
454
484
  };
455
- antiCachePath = (path2) => `${path2}?num=${Math.random().toString()}&time=${Date.now()}`;
485
+ antiCachePath = (path4) => `${path4}?num=${Math.random().toString()}&time=${Date.now()}`;
456
486
  getFileName = (filePath) => {
457
487
  const regex = /\/([^\/]+)\.ts/;
458
488
  const matches = filePath.match(regex);
@@ -550,11 +580,11 @@ var init_commons = __esm({
550
580
  }
551
581
  });
552
582
  async function findConfigFile(startDir = process.cwd()) {
553
- const fs = await import("fs");
583
+ const fs2 = await import("fs");
554
584
  let currentDir = import_path2.default.resolve(startDir);
555
585
  while (true) {
556
586
  const configPath = import_path2.default.join(currentDir, "moose.config.toml");
557
- if (fs.existsSync(configPath)) {
587
+ if (fs2.existsSync(configPath)) {
558
588
  return configPath;
559
589
  }
560
590
  const parentDir = import_path2.default.dirname(currentDir);
@@ -566,7 +596,7 @@ async function findConfigFile(startDir = process.cwd()) {
566
596
  return null;
567
597
  }
568
598
  async function readProjectConfig() {
569
- const fs = await import("fs");
599
+ const fs2 = await import("fs");
570
600
  const configPath = await findConfigFile();
571
601
  if (!configPath) {
572
602
  throw new ConfigError(
@@ -574,7 +604,7 @@ async function readProjectConfig() {
574
604
  );
575
605
  }
576
606
  try {
577
- const configContent = fs.readFileSync(configPath, "utf-8");
607
+ const configContent = fs2.readFileSync(configPath, "utf-8");
578
608
  const config = toml.parse(configContent);
579
609
  return config;
580
610
  } catch (error) {
@@ -865,6 +895,7 @@ var ClickHouseEngines = /* @__PURE__ */ ((ClickHouseEngines2) => {
865
895
  ClickHouseEngines2["Distributed"] = "Distributed";
866
896
  ClickHouseEngines2["IcebergS3"] = "IcebergS3";
867
897
  ClickHouseEngines2["Kafka"] = "Kafka";
898
+ ClickHouseEngines2["Merge"] = "Merge";
868
899
  ClickHouseEngines2["ReplicatedMergeTree"] = "ReplicatedMergeTree";
869
900
  ClickHouseEngines2["ReplicatedReplacingMergeTree"] = "ReplicatedReplacingMergeTree";
870
901
  ClickHouseEngines2["ReplicatedAggregatingMergeTree"] = "ReplicatedAggregatingMergeTree";
@@ -874,50 +905,292 @@ var ClickHouseEngines = /* @__PURE__ */ ((ClickHouseEngines2) => {
874
905
  return ClickHouseEngines2;
875
906
  })(ClickHouseEngines || {});
876
907
  init_commons();
877
- var MOOSE_RUNTIME_ENV_PREFIX = "__MOOSE_RUNTIME_ENV__:";
878
- var mooseRuntimeEnv = {
879
- /**
880
- * Gets a value from an environment variable, with behavior depending on context.
881
- *
882
- * When IS_LOADING_INFRA_MAP=true (infrastructure loading):
883
- * Returns a marker string that Moose CLI will resolve later
884
- *
885
- * When IS_LOADING_INFRA_MAP is unset (function/workflow runtime):
886
- * Returns the actual value from the environment variable
887
- *
888
- * @param envVarName - Name of the environment variable to resolve
889
- * @returns Either a marker string or the actual environment variable value
890
- * @throws {Error} If the environment variable name is empty
891
- * @throws {Error} If the environment variable is not set (runtime mode only)
892
- *
893
- * @example
894
- * ```typescript
895
- * // Instead of this (evaluated at build time):
896
- * awsAccessKeyId: process.env.AWS_ACCESS_KEY_ID
897
- *
898
- * // Use this (evaluated at runtime):
899
- * awsAccessKeyId: mooseRuntimeEnv.get("AWS_ACCESS_KEY_ID")
900
- * ```
901
- */
902
- get(envVarName) {
903
- if (!envVarName || envVarName.trim() === "") {
904
- throw new Error("Environment variable name cannot be empty");
908
+ var MOOSE_COMPILER_PLUGINS = [
909
+ {
910
+ transform: "./node_modules/@514labs/moose-lib/dist/compilerPlugin.js"
911
+ // No longer using transformProgram - direct typia integration eliminates
912
+ // the need for program replacement and the associated incremental compilation issues
913
+ },
914
+ {
915
+ // Keep typia plugin for users who use typia directly (not through Moose resources)
916
+ transform: "typia/lib/transform"
917
+ }
918
+ ];
919
+ var MOOSE_COMPILER_OPTIONS = {
920
+ experimentalDecorators: true,
921
+ esModuleInterop: true,
922
+ // Disable strict module syntax checking to avoid dual-package type conflicts
923
+ // This prevents errors where the same type imported with different resolution
924
+ // modes (CJS vs ESM) is treated as incompatible
925
+ verbatimModuleSyntax: false
926
+ };
927
+ var MOOSE_MODULE_OPTIONS = {
928
+ module: "NodeNext",
929
+ moduleResolution: "NodeNext"
930
+ };
931
+ function getSourceDir() {
932
+ return process.env.MOOSE_SOURCE_DIR || "app";
933
+ }
934
+ var DEFAULT_OUT_DIR = ".moose/compiled";
935
+ function readUserOutDir(projectRoot = process.cwd()) {
936
+ try {
937
+ let content = (0, import_fs2.readFileSync)(
938
+ import_path3.default.join(projectRoot, "tsconfig.json"),
939
+ "utf-8"
940
+ );
941
+ if (content.charCodeAt(0) === 65279) {
942
+ content = content.slice(1);
905
943
  }
906
- const isLoadingInfraMap = process.env.IS_LOADING_INFRA_MAP === "true";
907
- if (isLoadingInfraMap) {
908
- return `${MOOSE_RUNTIME_ENV_PREFIX}${envVarName}`;
944
+ const tsconfig = eval(`(${content})`);
945
+ return tsconfig.compilerOptions?.outDir || null;
946
+ } catch {
947
+ return null;
948
+ }
949
+ }
950
+ function getOutDir(projectRoot2 = process.cwd()) {
951
+ const userOutDir = readUserOutDir(projectRoot2);
952
+ return userOutDir || DEFAULT_OUT_DIR;
953
+ }
954
+ function getCompiledIndexPath(projectRoot2 = process.cwd()) {
955
+ const outDir = getOutDir(projectRoot2);
956
+ const sourceDir = getSourceDir();
957
+ return import_path3.default.resolve(projectRoot2, outDir, sourceDir, "index.js");
958
+ }
959
+ function hasCompiledArtifacts(projectRoot2 = process.cwd()) {
960
+ return (0, import_fs2.existsSync)(getCompiledIndexPath(projectRoot2));
961
+ }
962
+ function detectModuleSystem(projectRoot2 = process.cwd()) {
963
+ const pkgPath = import_path3.default.join(projectRoot2, "package.json");
964
+ if ((0, import_fs2.existsSync)(pkgPath)) {
965
+ try {
966
+ const pkgContent = (0, import_fs2.readFileSync)(pkgPath, "utf-8");
967
+ const pkg = JSON.parse(pkgContent);
968
+ if (pkg.type === "module") {
969
+ return "esm";
970
+ }
971
+ } catch (e) {
972
+ console.debug(
973
+ `[moose] Failed to parse package.json at ${pkgPath}, defaulting to CJS:`,
974
+ e
975
+ );
976
+ }
977
+ }
978
+ return "cjs";
979
+ }
980
+ function getModuleOptions(moduleSystem) {
981
+ if (moduleSystem === "esm") {
982
+ return {
983
+ module: "ES2022",
984
+ moduleResolution: "bundler"
985
+ };
986
+ }
987
+ return {
988
+ module: "CommonJS",
989
+ moduleResolution: "Node"
990
+ };
991
+ }
992
+ async function loadModule(modulePath, projectRoot2 = process.cwd()) {
993
+ const moduleSystem = detectModuleSystem(projectRoot2);
994
+ if (moduleSystem === "esm") {
995
+ const { pathToFileURL } = await import("url");
996
+ const fileUrl = pathToFileURL(modulePath).href;
997
+ return await import(fileUrl);
998
+ }
999
+ return __require(modulePath);
1000
+ }
1001
+ var isClientOnlyMode = () => import_process.default.env.MOOSE_CLIENT_ONLY === "true";
1002
+ var moose_internal = {
1003
+ tables: /* @__PURE__ */ new Map(),
1004
+ streams: /* @__PURE__ */ new Map(),
1005
+ ingestApis: /* @__PURE__ */ new Map(),
1006
+ apis: /* @__PURE__ */ new Map(),
1007
+ sqlResources: /* @__PURE__ */ new Map(),
1008
+ workflows: /* @__PURE__ */ new Map(),
1009
+ webApps: /* @__PURE__ */ new Map(),
1010
+ materializedViews: /* @__PURE__ */ new Map(),
1011
+ views: /* @__PURE__ */ new Map()
1012
+ };
1013
+ var defaultRetentionPeriod = 60 * 60 * 24 * 7;
1014
+ var getMooseInternal = () => globalThis.moose_internal;
1015
+ if (getMooseInternal() === void 0) {
1016
+ globalThis.moose_internal = moose_internal;
1017
+ }
1018
+ var loadIndex = async () => {
1019
+ if (!hasCompiledArtifacts()) {
1020
+ const outDir2 = getOutDir();
1021
+ const sourceDir = getSourceDir();
1022
+ throw new Error(
1023
+ `Compiled artifacts not found at ${outDir2}/${sourceDir}/index.js. Run 'npx moose-tspc' to compile your TypeScript first.`
1024
+ );
1025
+ }
1026
+ const registry = getMooseInternal();
1027
+ registry.tables.clear();
1028
+ registry.streams.clear();
1029
+ registry.ingestApis.clear();
1030
+ registry.apis.clear();
1031
+ registry.sqlResources.clear();
1032
+ registry.workflows.clear();
1033
+ registry.webApps.clear();
1034
+ registry.materializedViews.clear();
1035
+ registry.views.clear();
1036
+ const outDir = getOutDir();
1037
+ const compiledDir = path2.isAbsolute(outDir) ? outDir : path2.join(import_process.default.cwd(), outDir);
1038
+ Object.keys(__require.cache).forEach((key) => {
1039
+ if (key.startsWith(compiledDir)) {
1040
+ delete __require.cache[key];
1041
+ }
1042
+ });
1043
+ try {
1044
+ const indexPath = getCompiledIndexPath();
1045
+ await loadModule(indexPath);
1046
+ } catch (error) {
1047
+ let hint;
1048
+ let includeDetails = true;
1049
+ const details = error instanceof Error ? error.message : String(error);
1050
+ if (details.includes("no transform has been configured") || details.includes("NoTransformConfigurationError")) {
1051
+ hint = "\u{1F534} Typia Transformation Error\n\nThis is likely a bug in Moose. The Typia type transformer failed to process your code.\n\nPlease report this issue:\n \u2022 Moose Slack: https://join.slack.com/t/moose-community/shared_invite/zt-2fjh5n3wz-cnOmM9Xe9DYAgQrNu8xKxg\n \u2022 Include the stack trace below and the file being processed\n\n";
1052
+ includeDetails = false;
1053
+ } else if (details.includes("ERR_REQUIRE_ESM") || details.includes("ES Module")) {
1054
+ hint = "The file or its dependencies are ESM-only. Switch to packages that dual-support CJS & ESM, or upgrade to Node 22.12+. If you must use Node 20, you may try Node 20.19\n\n";
1055
+ }
1056
+ if (hint === void 0) {
1057
+ throw error;
909
1058
  } else {
910
- const value = process.env[envVarName];
911
- if (value === void 0) {
912
- throw new Error(
913
- `Environment variable '${envVarName}' is not set. This is required for runtime execution of functions/workflows.`
914
- );
1059
+ const errorMsg = includeDetails ? `${hint}${details}` : hint;
1060
+ const cause = error instanceof Error ? error : void 0;
1061
+ throw new Error(errorMsg, { cause });
1062
+ }
1063
+ }
1064
+ };
1065
+ var dlqSchema = {
1066
+ version: "3.1",
1067
+ components: {
1068
+ schemas: {
1069
+ DeadLetterModel: {
1070
+ type: "object",
1071
+ properties: {
1072
+ originalRecord: {
1073
+ $ref: "#/components/schemas/Recordstringany"
1074
+ },
1075
+ errorMessage: {
1076
+ type: "string"
1077
+ },
1078
+ errorType: {
1079
+ type: "string"
1080
+ },
1081
+ failedAt: {
1082
+ type: "string",
1083
+ format: "date-time"
1084
+ },
1085
+ source: {
1086
+ oneOf: [
1087
+ {
1088
+ const: "api"
1089
+ },
1090
+ {
1091
+ const: "transform"
1092
+ },
1093
+ {
1094
+ const: "table"
1095
+ }
1096
+ ]
1097
+ }
1098
+ },
1099
+ required: [
1100
+ "originalRecord",
1101
+ "errorMessage",
1102
+ "errorType",
1103
+ "failedAt",
1104
+ "source"
1105
+ ]
1106
+ },
1107
+ Recordstringany: {
1108
+ type: "object",
1109
+ properties: {},
1110
+ required: [],
1111
+ description: "Construct a type with a set of properties K of type T",
1112
+ additionalProperties: {}
915
1113
  }
916
- return value;
917
1114
  }
1115
+ },
1116
+ schemas: [
1117
+ {
1118
+ $ref: "#/components/schemas/DeadLetterModel"
1119
+ }
1120
+ ]
1121
+ };
1122
+ var dlqColumns = [
1123
+ {
1124
+ name: "originalRecord",
1125
+ data_type: "Json",
1126
+ primary_key: false,
1127
+ required: true,
1128
+ unique: false,
1129
+ default: null,
1130
+ annotations: [],
1131
+ ttl: null,
1132
+ codec: null,
1133
+ materialized: null,
1134
+ comment: null
1135
+ },
1136
+ {
1137
+ name: "errorMessage",
1138
+ data_type: "String",
1139
+ primary_key: false,
1140
+ required: true,
1141
+ unique: false,
1142
+ default: null,
1143
+ annotations: [],
1144
+ ttl: null,
1145
+ codec: null,
1146
+ materialized: null,
1147
+ comment: null
1148
+ },
1149
+ {
1150
+ name: "errorType",
1151
+ data_type: "String",
1152
+ primary_key: false,
1153
+ required: true,
1154
+ unique: false,
1155
+ default: null,
1156
+ annotations: [],
1157
+ ttl: null,
1158
+ codec: null,
1159
+ materialized: null,
1160
+ comment: null
1161
+ },
1162
+ {
1163
+ name: "failedAt",
1164
+ data_type: "DateTime",
1165
+ primary_key: false,
1166
+ required: true,
1167
+ unique: false,
1168
+ default: null,
1169
+ annotations: [],
1170
+ ttl: null,
1171
+ codec: null,
1172
+ materialized: null,
1173
+ comment: null
1174
+ },
1175
+ {
1176
+ name: "source",
1177
+ data_type: "String",
1178
+ primary_key: false,
1179
+ required: true,
1180
+ unique: false,
1181
+ default: null,
1182
+ annotations: [],
1183
+ ttl: null,
1184
+ codec: null,
1185
+ materialized: null,
1186
+ comment: null
918
1187
  }
1188
+ ];
1189
+ var getWorkflows = async () => {
1190
+ await loadIndex();
1191
+ const registry = getMooseInternal();
1192
+ return registry.workflows;
919
1193
  };
920
- var mooseEnvSecrets = mooseRuntimeEnv;
921
1194
  var quoteIdentifier = (name) => {
922
1195
  return name.startsWith("`") && name.endsWith("`") ? name : `\`${name}\``;
923
1196
  };
@@ -1088,216 +1361,6 @@ var mapToClickHouseType = (value) => {
1088
1361
  function emptyIfUndefined(value) {
1089
1362
  return value === void 0 ? "" : value;
1090
1363
  }
1091
- init_commons();
1092
- function jsonDateReviver(key, value) {
1093
- const iso8601Format = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)$/;
1094
- if (typeof value === "string" && iso8601Format.test(value)) {
1095
- return new Date(value);
1096
- }
1097
- return value;
1098
- }
1099
- function parseCSV(content, config) {
1100
- return new Promise((resolve, reject) => {
1101
- const results = [];
1102
- (0, import_csv_parse.parse)(content, {
1103
- delimiter: config.delimiter,
1104
- columns: config.columns ?? true,
1105
- skip_empty_lines: config.skipEmptyLines ?? true,
1106
- trim: config.trim ?? true
1107
- }).on("data", (row) => {
1108
- results.push(row);
1109
- }).on("end", () => {
1110
- resolve(results);
1111
- }).on("error", (error) => {
1112
- reject(error);
1113
- });
1114
- });
1115
- }
1116
- function parseJSON(content, config = {}) {
1117
- try {
1118
- const parsed = JSON.parse(content, config.reviver);
1119
- if (Array.isArray(parsed)) {
1120
- return parsed;
1121
- } else {
1122
- return [parsed];
1123
- }
1124
- } catch (error) {
1125
- throw new Error(
1126
- `Failed to parse JSON: ${error instanceof Error ? error.message : "Unknown error"}`
1127
- );
1128
- }
1129
- }
1130
- function parseJSONWithDates(content) {
1131
- return parseJSON(content, { reviver: jsonDateReviver });
1132
- }
1133
- function isValidCSVDelimiter(delimiter) {
1134
- return delimiter.length === 1 && !/\s/.test(delimiter);
1135
- }
1136
- var CSV_DELIMITERS = {
1137
- COMMA: ",",
1138
- TAB: " ",
1139
- SEMICOLON: ";",
1140
- PIPE: "|"
1141
- };
1142
- var DEFAULT_CSV_CONFIG = {
1143
- delimiter: CSV_DELIMITERS.COMMA,
1144
- columns: true,
1145
- skipEmptyLines: true,
1146
- trim: true
1147
- };
1148
- var DEFAULT_JSON_CONFIG = {
1149
- reviver: jsonDateReviver
1150
- };
1151
- var DataSource = class {
1152
- name;
1153
- supportsIncremental;
1154
- constructor(config) {
1155
- this.name = config.name;
1156
- this.supportsIncremental = config.supportsIncremental ?? false;
1157
- }
1158
- };
1159
- init_commons();
1160
- var isClientOnlyMode = () => import_process.default.env.MOOSE_CLIENT_ONLY === "true";
1161
- var moose_internal = {
1162
- tables: /* @__PURE__ */ new Map(),
1163
- streams: /* @__PURE__ */ new Map(),
1164
- ingestApis: /* @__PURE__ */ new Map(),
1165
- apis: /* @__PURE__ */ new Map(),
1166
- sqlResources: /* @__PURE__ */ new Map(),
1167
- workflows: /* @__PURE__ */ new Map(),
1168
- webApps: /* @__PURE__ */ new Map(),
1169
- materializedViews: /* @__PURE__ */ new Map(),
1170
- views: /* @__PURE__ */ new Map()
1171
- };
1172
- var defaultRetentionPeriod = 60 * 60 * 24 * 7;
1173
- var getMooseInternal = () => globalThis.moose_internal;
1174
- if (getMooseInternal() === void 0) {
1175
- globalThis.moose_internal = moose_internal;
1176
- }
1177
- var dlqSchema = {
1178
- version: "3.1",
1179
- components: {
1180
- schemas: {
1181
- DeadLetterModel: {
1182
- type: "object",
1183
- properties: {
1184
- originalRecord: {
1185
- $ref: "#/components/schemas/Recordstringany"
1186
- },
1187
- errorMessage: {
1188
- type: "string"
1189
- },
1190
- errorType: {
1191
- type: "string"
1192
- },
1193
- failedAt: {
1194
- type: "string",
1195
- format: "date-time"
1196
- },
1197
- source: {
1198
- oneOf: [
1199
- {
1200
- const: "api"
1201
- },
1202
- {
1203
- const: "transform"
1204
- },
1205
- {
1206
- const: "table"
1207
- }
1208
- ]
1209
- }
1210
- },
1211
- required: [
1212
- "originalRecord",
1213
- "errorMessage",
1214
- "errorType",
1215
- "failedAt",
1216
- "source"
1217
- ]
1218
- },
1219
- Recordstringany: {
1220
- type: "object",
1221
- properties: {},
1222
- required: [],
1223
- description: "Construct a type with a set of properties K of type T",
1224
- additionalProperties: {}
1225
- }
1226
- }
1227
- },
1228
- schemas: [
1229
- {
1230
- $ref: "#/components/schemas/DeadLetterModel"
1231
- }
1232
- ]
1233
- };
1234
- var dlqColumns = [
1235
- {
1236
- name: "originalRecord",
1237
- data_type: "Json",
1238
- primary_key: false,
1239
- required: true,
1240
- unique: false,
1241
- default: null,
1242
- annotations: [],
1243
- ttl: null,
1244
- codec: null,
1245
- materialized: null,
1246
- comment: null
1247
- },
1248
- {
1249
- name: "errorMessage",
1250
- data_type: "String",
1251
- primary_key: false,
1252
- required: true,
1253
- unique: false,
1254
- default: null,
1255
- annotations: [],
1256
- ttl: null,
1257
- codec: null,
1258
- materialized: null,
1259
- comment: null
1260
- },
1261
- {
1262
- name: "errorType",
1263
- data_type: "String",
1264
- primary_key: false,
1265
- required: true,
1266
- unique: false,
1267
- default: null,
1268
- annotations: [],
1269
- ttl: null,
1270
- codec: null,
1271
- materialized: null,
1272
- comment: null
1273
- },
1274
- {
1275
- name: "failedAt",
1276
- data_type: "DateTime",
1277
- primary_key: false,
1278
- required: true,
1279
- unique: false,
1280
- default: null,
1281
- annotations: [],
1282
- ttl: null,
1283
- codec: null,
1284
- materialized: null,
1285
- comment: null
1286
- },
1287
- {
1288
- name: "source",
1289
- data_type: "String",
1290
- primary_key: false,
1291
- required: true,
1292
- unique: false,
1293
- default: null,
1294
- annotations: [],
1295
- ttl: null,
1296
- codec: null,
1297
- materialized: null,
1298
- comment: null
1299
- }
1300
- ];
1301
1364
  var OlapTable = class extends TypedBase {
1302
1365
  name;
1303
1366
  /** @internal */
@@ -2500,22 +2563,22 @@ var Api = class extends TypedBase {
2500
2563
  return this._handler;
2501
2564
  };
2502
2565
  async call(baseUrl, queryParams) {
2503
- let path2;
2566
+ let path4;
2504
2567
  if (this.config?.path) {
2505
2568
  if (this.config.version) {
2506
2569
  const pathEndsWithVersion = this.config.path.endsWith(`/${this.config.version}`) || this.config.path === this.config.version || this.config.path.endsWith(this.config.version) && this.config.path.length > this.config.version.length && this.config.path[this.config.path.length - this.config.version.length - 1] === "/";
2507
2570
  if (pathEndsWithVersion) {
2508
- path2 = this.config.path;
2571
+ path4 = this.config.path;
2509
2572
  } else {
2510
- path2 = `${this.config.path.replace(/\/$/, "")}/${this.config.version}`;
2573
+ path4 = `${this.config.path.replace(/\/$/, "")}/${this.config.version}`;
2511
2574
  }
2512
2575
  } else {
2513
- path2 = this.config.path;
2576
+ path4 = this.config.path;
2514
2577
  }
2515
2578
  } else {
2516
- path2 = this.config?.version ? `${this.name}/${this.config.version}` : this.name;
2579
+ path4 = this.config?.version ? `${this.name}/${this.config.version}` : this.name;
2517
2580
  }
2518
- const url = new URL(`${baseUrl.replace(/\/$/, "")}/api/${path2}`);
2581
+ const url = new URL(`${baseUrl.replace(/\/$/, "")}/api/${path4}`);
2519
2582
  const searchParams = url.searchParams;
2520
2583
  for (const [key, value] of Object.entries(queryParams)) {
2521
2584
  if (Array.isArray(value)) {
@@ -2574,6 +2637,11 @@ var IngestPipeline = class extends TypedBase {
2574
2637
  }
2575
2638
  }
2576
2639
  if (config.table) {
2640
+ if (typeof config.table === "object" && "engine" in config.table && config.table.engine === "Merge") {
2641
+ throw new Error(
2642
+ `IngestPipeline "${name}": Merge engine is read-only and cannot be used as a table destination.`
2643
+ );
2644
+ }
2577
2645
  const tableConfig = typeof config.table === "object" ? {
2578
2646
  ...config.table,
2579
2647
  lifeCycle: config.table.lifeCycle ?? config.lifeCycle,
@@ -2817,6 +2885,8 @@ var MaterializedView = class {
2817
2885
  sourceTables;
2818
2886
  /** Optional metadata for the materialized view */
2819
2887
  metadata;
2888
+ /** Optional lifecycle management policy for the materialized view */
2889
+ lifeCycle;
2820
2890
  constructor(options, targetSchema, targetColumns) {
2821
2891
  let selectStatement = options.selectStatement;
2822
2892
  if (typeof selectStatement !== "string") {
@@ -2850,6 +2920,7 @@ var MaterializedView = class {
2850
2920
  this.sourceTables = options.selectTables.map(
2851
2921
  (t) => formatTableReference(t)
2852
2922
  );
2923
+ this.lifeCycle = options.lifeCycle;
2853
2924
  this.metadata = options.metadata ? { ...options.metadata } : {};
2854
2925
  if (!this.metadata.source) {
2855
2926
  const stack = new Error().stack;
@@ -3158,6 +3229,675 @@ function getView(name) {
3158
3229
  return getMooseInternal().views.get(name);
3159
3230
  }
3160
3231
  init_commons();
3232
+ var MOOSE_RUNTIME_ENV_PREFIX = "__MOOSE_RUNTIME_ENV__:";
3233
+ var mooseRuntimeEnv = {
3234
+ /**
3235
+ * Gets a value from an environment variable, with behavior depending on context.
3236
+ *
3237
+ * When IS_LOADING_INFRA_MAP=true (infrastructure loading):
3238
+ * Returns a marker string that Moose CLI will resolve later
3239
+ *
3240
+ * When IS_LOADING_INFRA_MAP is unset (function/workflow runtime):
3241
+ * Returns the actual value from the environment variable
3242
+ *
3243
+ * @param envVarName - Name of the environment variable to resolve
3244
+ * @returns Either a marker string or the actual environment variable value
3245
+ * @throws {Error} If the environment variable name is empty
3246
+ * @throws {Error} If the environment variable is not set (runtime mode only)
3247
+ *
3248
+ * @example
3249
+ * ```typescript
3250
+ * // Instead of this (evaluated at build time):
3251
+ * awsAccessKeyId: process.env.AWS_ACCESS_KEY_ID
3252
+ *
3253
+ * // Use this (evaluated at runtime):
3254
+ * awsAccessKeyId: mooseRuntimeEnv.get("AWS_ACCESS_KEY_ID")
3255
+ * ```
3256
+ */
3257
+ get(envVarName) {
3258
+ if (!envVarName || envVarName.trim() === "") {
3259
+ throw new Error("Environment variable name cannot be empty");
3260
+ }
3261
+ const isLoadingInfraMap = process.env.IS_LOADING_INFRA_MAP === "true";
3262
+ if (isLoadingInfraMap) {
3263
+ return `${MOOSE_RUNTIME_ENV_PREFIX}${envVarName}`;
3264
+ } else {
3265
+ const value = process.env[envVarName];
3266
+ if (value === void 0) {
3267
+ throw new Error(
3268
+ `Environment variable '${envVarName}' is not set. This is required for runtime execution of functions/workflows.`
3269
+ );
3270
+ }
3271
+ return value;
3272
+ }
3273
+ }
3274
+ };
3275
+ var mooseEnvSecrets = mooseRuntimeEnv;
3276
+ function formatElapsedTime(ms) {
3277
+ if (ms < 1e3) {
3278
+ return `${Math.round(ms)} ms`;
3279
+ }
3280
+ const seconds = ms / 1e3;
3281
+ if (seconds < 60) {
3282
+ return `${seconds.toFixed(2)} seconds`;
3283
+ }
3284
+ const minutes = Math.floor(seconds / 60);
3285
+ const remainingSeconds = seconds % 60;
3286
+ return `${minutes} minutes and ${remainingSeconds.toFixed(2)} seconds`;
3287
+ }
3288
+ var MooseClient = class {
3289
+ query;
3290
+ workflow;
3291
+ constructor(queryClient, temporalClient) {
3292
+ this.query = queryClient;
3293
+ this.workflow = new WorkflowClient(temporalClient);
3294
+ }
3295
+ };
3296
+ var QueryClient = class {
3297
+ client;
3298
+ query_id_prefix;
3299
+ constructor(client, query_id_prefix) {
3300
+ this.client = client;
3301
+ this.query_id_prefix = query_id_prefix;
3302
+ }
3303
+ async execute(sql3) {
3304
+ const [query, query_params] = toQuery(sql3);
3305
+ console.log(`[QueryClient] | Query: ${toQueryPreview(sql3)}`);
3306
+ const start = import_perf_hooks.performance.now();
3307
+ const result = await this.client.query({
3308
+ query,
3309
+ query_params,
3310
+ format: "JSONEachRow",
3311
+ query_id: this.query_id_prefix + (0, import_crypto3.randomUUID)()
3312
+ // Note: wait_end_of_query deliberately NOT set here as this is used for SELECT queries
3313
+ // where response buffering would harm streaming performance and concurrency
3314
+ });
3315
+ const elapsedMs = import_perf_hooks.performance.now() - start;
3316
+ console.log(
3317
+ `[QueryClient] | Query completed: ${formatElapsedTime(elapsedMs)}`
3318
+ );
3319
+ return result;
3320
+ }
3321
+ async command(sql3) {
3322
+ const [query, query_params] = toQuery(sql3);
3323
+ console.log(`[QueryClient] | Command: ${toQueryPreview(sql3)}`);
3324
+ const start = import_perf_hooks.performance.now();
3325
+ const result = await this.client.command({
3326
+ query,
3327
+ query_params,
3328
+ query_id: this.query_id_prefix + (0, import_crypto3.randomUUID)()
3329
+ });
3330
+ const elapsedMs = import_perf_hooks.performance.now() - start;
3331
+ console.log(
3332
+ `[QueryClient] | Command completed: ${formatElapsedTime(elapsedMs)}`
3333
+ );
3334
+ return result;
3335
+ }
3336
+ };
3337
+ var WorkflowClient = class {
3338
+ client;
3339
+ constructor(temporalClient) {
3340
+ this.client = temporalClient;
3341
+ }
3342
+ async execute(name, input_data) {
3343
+ try {
3344
+ if (!this.client) {
3345
+ return {
3346
+ status: 404,
3347
+ body: `Temporal client not found. Is the feature flag enabled?`
3348
+ };
3349
+ }
3350
+ const config = await this.getWorkflowConfig(name);
3351
+ const [processedInput, workflowId] = this.processInputData(
3352
+ name,
3353
+ input_data
3354
+ );
3355
+ console.log(
3356
+ `WorkflowClient - starting workflow: ${name} with config ${JSON.stringify(config)} and input_data ${JSON.stringify(processedInput)}`
3357
+ );
3358
+ const handle = await this.client.workflow.start("ScriptWorkflow", {
3359
+ args: [
3360
+ { workflow_name: name, execution_mode: "start" },
3361
+ processedInput
3362
+ ],
3363
+ taskQueue: "typescript-script-queue",
3364
+ workflowId,
3365
+ workflowIdConflictPolicy: "FAIL",
3366
+ workflowIdReusePolicy: "ALLOW_DUPLICATE",
3367
+ retry: {
3368
+ // Temporal's maximumAttempts = total attempts (initial + retries)
3369
+ maximumAttempts: config.retries + 1
3370
+ },
3371
+ workflowRunTimeout: config.timeout
3372
+ });
3373
+ return {
3374
+ status: 200,
3375
+ body: `Workflow started: ${name}. View it in the Temporal dashboard: http://localhost:8080/namespaces/default/workflows/${workflowId}/${handle.firstExecutionRunId}/history`
3376
+ };
3377
+ } catch (error) {
3378
+ return {
3379
+ status: 400,
3380
+ body: `Error starting workflow: ${error}`
3381
+ };
3382
+ }
3383
+ }
3384
+ async terminate(workflowId) {
3385
+ try {
3386
+ if (!this.client) {
3387
+ return {
3388
+ status: 404,
3389
+ body: `Temporal client not found. Is the feature flag enabled?`
3390
+ };
3391
+ }
3392
+ const handle = this.client.workflow.getHandle(workflowId);
3393
+ await handle.terminate();
3394
+ return {
3395
+ status: 200,
3396
+ body: `Workflow terminated: ${workflowId}`
3397
+ };
3398
+ } catch (error) {
3399
+ return {
3400
+ status: 400,
3401
+ body: `Error terminating workflow: ${error}`
3402
+ };
3403
+ }
3404
+ }
3405
+ async getWorkflowConfig(name) {
3406
+ const workflows = await getWorkflows();
3407
+ const workflow = workflows.get(name);
3408
+ if (workflow) {
3409
+ return {
3410
+ retries: workflow.config.retries || 3,
3411
+ timeout: workflow.config.timeout || "1h"
3412
+ };
3413
+ }
3414
+ throw new Error(`Workflow config not found for ${name}`);
3415
+ }
3416
+ processInputData(name, input_data) {
3417
+ let workflowId = name;
3418
+ if (input_data) {
3419
+ const hash = (0, import_crypto3.createHash)("sha256").update(JSON.stringify(input_data)).digest("hex").slice(0, 16);
3420
+ workflowId = `${name}-${hash}`;
3421
+ }
3422
+ return [input_data, workflowId];
3423
+ }
3424
+ };
3425
+ async function getTemporalClient(temporalUrl, namespace, clientCert, clientKey, apiKey) {
3426
+ try {
3427
+ console.info(
3428
+ `<api> Using temporal_url: ${temporalUrl} and namespace: ${namespace}`
3429
+ );
3430
+ let connectionOptions = {
3431
+ address: temporalUrl,
3432
+ connectTimeout: "3s"
3433
+ };
3434
+ if (clientCert && clientKey) {
3435
+ console.log("Using TLS for secure Temporal");
3436
+ const cert = await fs.readFileSync(clientCert);
3437
+ const key = await fs.readFileSync(clientKey);
3438
+ connectionOptions.tls = {
3439
+ clientCertPair: { crt: cert, key }
3440
+ };
3441
+ } else if (apiKey) {
3442
+ console.log("Using API key for secure Temporal");
3443
+ connectionOptions.address = "us-west1.gcp.api.temporal.io:7233";
3444
+ connectionOptions.apiKey = apiKey;
3445
+ connectionOptions.tls = {};
3446
+ connectionOptions.metadata = {
3447
+ "temporal-namespace": namespace
3448
+ };
3449
+ }
3450
+ console.log(`<api> Connecting to Temporal at ${connectionOptions.address}`);
3451
+ const connection = await import_client2.Connection.connect(connectionOptions);
3452
+ const client = new import_client2.Client({ connection, namespace });
3453
+ console.log("<api> Connected to Temporal server");
3454
+ return client;
3455
+ } catch (error) {
3456
+ console.warn(`Failed to connect to Temporal. Is the feature flag enabled?`);
3457
+ console.warn(error);
3458
+ return void 0;
3459
+ }
3460
+ }
3461
+ var ApiHelpers = {
3462
+ column: (value) => ["Identifier", value],
3463
+ table: (value) => ["Identifier", value]
3464
+ };
3465
+ var ConsumptionHelpers = ApiHelpers;
3466
+ function joinQueries({
3467
+ values,
3468
+ separator = ",",
3469
+ prefix = "",
3470
+ suffix = ""
3471
+ }) {
3472
+ if (values.length === 0) {
3473
+ throw new TypeError(
3474
+ "Expected `join([])` to be called with an array of multiple elements, but got an empty array"
3475
+ );
3476
+ }
3477
+ return new Sql(
3478
+ [prefix, ...Array(values.length - 1).fill(separator), suffix],
3479
+ values
3480
+ );
3481
+ }
3482
+ function getMooseUtilsFromRequest(req) {
3483
+ console.warn(
3484
+ "[DEPRECATED] getMooseUtilsFromRequest() is deprecated. Import getMooseUtils from '@514labs/moose-lib' and call it without parameters: const { client, sql } = await getMooseUtils();"
3485
+ );
3486
+ return req.moose;
3487
+ }
3488
+ var getLegacyMooseUtils = getMooseUtilsFromRequest;
3489
+ function expressMiddleware() {
3490
+ console.warn(
3491
+ "[DEPRECATED] expressMiddleware() is deprecated. Use getMooseUtils() directly or rely on injectMooseUtils config."
3492
+ );
3493
+ return (req, res, next) => {
3494
+ if (!req.moose && req.raw && req.raw.moose) {
3495
+ req.moose = req.raw.moose;
3496
+ }
3497
+ next();
3498
+ };
3499
+ }
3500
+ var instance = null;
3501
+ var initPromise = null;
3502
+ var MooseCache = class _MooseCache {
3503
+ client;
3504
+ isConnected = false;
3505
+ keyPrefix;
3506
+ disconnectTimer = null;
3507
+ idleTimeout;
3508
+ connectPromise = null;
3509
+ constructor() {
3510
+ const redisUrl = process.env.MOOSE_REDIS_CONFIG__URL || "redis://127.0.0.1:6379";
3511
+ const prefix = process.env.MOOSE_REDIS_CONFIG__KEY_PREFIX || "MS";
3512
+ this.idleTimeout = parseInt(process.env.MOOSE_REDIS_CONFIG__IDLE_TIMEOUT || "30", 10) * 1e3;
3513
+ this.keyPrefix = `${prefix}::moosecache::`;
3514
+ this.client = (0, import_redis.createClient)({
3515
+ url: redisUrl
3516
+ });
3517
+ process.on("SIGTERM", this.gracefulShutdown);
3518
+ process.on("SIGINT", this.gracefulShutdown);
3519
+ this.client.on("error", async (err) => {
3520
+ console.error("TS Redis client error:", err);
3521
+ await this.disconnect();
3522
+ });
3523
+ this.client.on("connect", () => {
3524
+ this.isConnected = true;
3525
+ console.log("TS Redis client connected");
3526
+ });
3527
+ this.client.on("end", () => {
3528
+ this.isConnected = false;
3529
+ console.log("TS Redis client disconnected");
3530
+ this.clearDisconnectTimer();
3531
+ });
3532
+ }
3533
+ clearDisconnectTimer() {
3534
+ if (this.disconnectTimer) {
3535
+ clearTimeout(this.disconnectTimer);
3536
+ this.disconnectTimer = null;
3537
+ }
3538
+ }
3539
+ resetDisconnectTimer() {
3540
+ this.clearDisconnectTimer();
3541
+ this.disconnectTimer = setTimeout(async () => {
3542
+ if (this.isConnected) {
3543
+ console.log("TS Redis client disconnecting due to inactivity");
3544
+ await this.disconnect();
3545
+ }
3546
+ }, this.idleTimeout);
3547
+ }
3548
+ async ensureConnected() {
3549
+ if (!this.isConnected) {
3550
+ await this.connect();
3551
+ }
3552
+ this.resetDisconnectTimer();
3553
+ }
3554
+ async connect() {
3555
+ if (this.isConnected) {
3556
+ return;
3557
+ }
3558
+ if (this.connectPromise) {
3559
+ return this.connectPromise;
3560
+ }
3561
+ this.connectPromise = (async () => {
3562
+ try {
3563
+ await this.client.connect();
3564
+ this.resetDisconnectTimer();
3565
+ } catch (error) {
3566
+ this.connectPromise = null;
3567
+ throw error;
3568
+ }
3569
+ })();
3570
+ return this.connectPromise;
3571
+ }
3572
+ async gracefulShutdown() {
3573
+ if (this.isConnected) {
3574
+ await this.disconnect();
3575
+ }
3576
+ process.exit(0);
3577
+ }
3578
+ getPrefixedKey(key) {
3579
+ return `${this.keyPrefix}${key}`;
3580
+ }
3581
+ /**
3582
+ * Gets the singleton instance of MooseCache. Creates a new instance if one doesn't exist.
3583
+ * The client will automatically connect to Redis and handle reconnection if needed.
3584
+ *
3585
+ * @returns Promise<MooseCache> The singleton instance of MooseCache
3586
+ * @example
3587
+ * const cache = await MooseCache.get();
3588
+ */
3589
+ static async get() {
3590
+ if (instance) {
3591
+ return instance;
3592
+ }
3593
+ if (initPromise) {
3594
+ return initPromise;
3595
+ }
3596
+ initPromise = (async () => {
3597
+ try {
3598
+ const newInstance = new _MooseCache();
3599
+ await newInstance.connect();
3600
+ instance = newInstance;
3601
+ return newInstance;
3602
+ } catch (error) {
3603
+ initPromise = null;
3604
+ throw error;
3605
+ }
3606
+ })();
3607
+ return initPromise;
3608
+ }
3609
+ /**
3610
+ * Sets a value in the cache. Objects are automatically JSON stringified.
3611
+ *
3612
+ * @param key - The key to store the value under
3613
+ * @param value - The value to store. Can be a string or any object (will be JSON stringified)
3614
+ * @param ttlSeconds - Optional time-to-live in seconds. If not provided, defaults to 1 hour (3600 seconds).
3615
+ * Must be a non-negative number. If 0, the key will expire immediately.
3616
+ * @example
3617
+ * // Store a string
3618
+ * await cache.set("foo", "bar");
3619
+ *
3620
+ * // Store an object with custom TTL
3621
+ * await cache.set("foo:config", { baz: 123, qux: true }, 60); // expires in 1 minute
3622
+ *
3623
+ * // This is essentially a get-set, which returns the previous value if it exists.
3624
+ * // You can create logic to only do work for the first time.
3625
+ * const value = await cache.set("testSessionId", "true");
3626
+ * if (value) {
3627
+ * // Cache was set before, return
3628
+ * } else {
3629
+ * // Cache was set for first time, do work
3630
+ * }
3631
+ */
3632
+ async set(key, value, ttlSeconds) {
3633
+ try {
3634
+ if (ttlSeconds !== void 0 && ttlSeconds < 0) {
3635
+ throw new Error("ttlSeconds must be a non-negative number");
3636
+ }
3637
+ await this.ensureConnected();
3638
+ const prefixedKey = this.getPrefixedKey(key);
3639
+ const stringValue = typeof value === "object" ? JSON.stringify(value) : value;
3640
+ const ttl = ttlSeconds ?? 3600;
3641
+ return await this.client.set(prefixedKey, stringValue, {
3642
+ EX: ttl,
3643
+ GET: true
3644
+ });
3645
+ } catch (error) {
3646
+ console.error(`Error setting cache key ${key}:`, error);
3647
+ throw error;
3648
+ }
3649
+ }
3650
+ /**
3651
+ * Retrieves a value from the cache. Attempts to parse the value as JSON if possible.
3652
+ *
3653
+ * @param key - The key to retrieve
3654
+ * @returns Promise<T | null> The value, parsed as type T if it was JSON, or as string if not. Returns null if key doesn't exist
3655
+ * @example
3656
+ * // Get a string
3657
+ * const value = await cache.get("foo");
3658
+ *
3659
+ * // Get and parse an object with type safety
3660
+ * interface Config { baz: number; qux: boolean; }
3661
+ * const config = await cache.get<Config>("foo:config");
3662
+ */
3663
+ async get(key) {
3664
+ try {
3665
+ await this.ensureConnected();
3666
+ const prefixedKey = this.getPrefixedKey(key);
3667
+ const value = await this.client.get(prefixedKey);
3668
+ if (value === null) return null;
3669
+ try {
3670
+ const parsed = JSON.parse(value);
3671
+ if (typeof parsed === "object" && parsed !== null) {
3672
+ return parsed;
3673
+ }
3674
+ return value;
3675
+ } catch {
3676
+ return value;
3677
+ }
3678
+ } catch (error) {
3679
+ console.error(`Error getting cache key ${key}:`, error);
3680
+ throw error;
3681
+ }
3682
+ }
3683
+ /**
3684
+ * Deletes a specific key from the cache.
3685
+ *
3686
+ * @param key - The key to delete
3687
+ * @example
3688
+ * await cache.delete("foo");
3689
+ */
3690
+ async delete(key) {
3691
+ try {
3692
+ await this.ensureConnected();
3693
+ const prefixedKey = this.getPrefixedKey(key);
3694
+ await this.client.del(prefixedKey);
3695
+ } catch (error) {
3696
+ console.error(`Error deleting cache key ${key}:`, error);
3697
+ throw error;
3698
+ }
3699
+ }
3700
+ /**
3701
+ * Deletes all keys that start with the given prefix.
3702
+ *
3703
+ * @param keyPrefix - The prefix of keys to delete
3704
+ * @example
3705
+ * // Delete all keys starting with "foo"
3706
+ * await cache.clearKeys("foo");
3707
+ */
3708
+ async clearKeys(keyPrefix) {
3709
+ try {
3710
+ await this.ensureConnected();
3711
+ const prefixedKey = this.getPrefixedKey(keyPrefix);
3712
+ const keys = await this.client.keys(`${prefixedKey}*`);
3713
+ if (keys.length > 0) {
3714
+ await this.client.del(keys);
3715
+ }
3716
+ } catch (error) {
3717
+ console.error(
3718
+ `Error clearing cache keys with prefix ${keyPrefix}:`,
3719
+ error
3720
+ );
3721
+ throw error;
3722
+ }
3723
+ }
3724
+ /**
3725
+ * Deletes all keys in the cache
3726
+ *
3727
+ * @example
3728
+ * await cache.clear();
3729
+ */
3730
+ async clear() {
3731
+ try {
3732
+ await this.ensureConnected();
3733
+ const keys = await this.client.keys(`${this.keyPrefix}*`);
3734
+ if (keys.length > 0) {
3735
+ await this.client.del(keys);
3736
+ }
3737
+ } catch (error) {
3738
+ console.error("Error clearing cache:", error);
3739
+ throw error;
3740
+ }
3741
+ }
3742
+ /**
3743
+ * Manually disconnects the Redis client. The client will automatically reconnect
3744
+ * when the next operation is performed.
3745
+ *
3746
+ * @example
3747
+ * await cache.disconnect();
3748
+ */
3749
+ async disconnect() {
3750
+ this.clearDisconnectTimer();
3751
+ this.connectPromise = null;
3752
+ if (this.isConnected) {
3753
+ await this.client.quit();
3754
+ }
3755
+ }
3756
+ };
3757
+ init_commons();
3758
+ var standaloneUtils = null;
3759
+ var initPromise2 = null;
3760
+ var toClientConfig = (config) => ({
3761
+ ...config,
3762
+ useSSL: config.useSSL ? "true" : "false"
3763
+ });
3764
+ async function getMooseUtils(req) {
3765
+ if (req !== void 0) {
3766
+ console.warn(
3767
+ "[DEPRECATED] getMooseUtils(req) no longer requires a request parameter. Use getMooseUtils() instead."
3768
+ );
3769
+ }
3770
+ const runtimeContext = globalThis._mooseRuntimeContext;
3771
+ if (runtimeContext) {
3772
+ return {
3773
+ client: runtimeContext.client,
3774
+ sql,
3775
+ jwt: runtimeContext.jwt
3776
+ };
3777
+ }
3778
+ if (standaloneUtils) {
3779
+ return standaloneUtils;
3780
+ }
3781
+ if (initPromise2) {
3782
+ return initPromise2;
3783
+ }
3784
+ initPromise2 = (async () => {
3785
+ await Promise.resolve().then(() => (init_runtime(), runtime_exports));
3786
+ const configRegistry = globalThis._mooseConfigRegistry;
3787
+ if (!configRegistry) {
3788
+ throw new Error(
3789
+ "Moose not initialized. Ensure you're running within a Moose app or have proper configuration set up."
3790
+ );
3791
+ }
3792
+ const clickhouseConfig = await configRegistry.getStandaloneClickhouseConfig();
3793
+ const clickhouseClient = getClickhouseClient(
3794
+ toClientConfig(clickhouseConfig)
3795
+ );
3796
+ const queryClient = new QueryClient(clickhouseClient, "standalone");
3797
+ const mooseClient = new MooseClient(queryClient);
3798
+ standaloneUtils = {
3799
+ client: mooseClient,
3800
+ sql,
3801
+ jwt: void 0
3802
+ };
3803
+ return standaloneUtils;
3804
+ })();
3805
+ try {
3806
+ return await initPromise2;
3807
+ } finally {
3808
+ initPromise2 = null;
3809
+ }
3810
+ }
3811
+ async function getMooseClients(config) {
3812
+ console.warn(
3813
+ "[DEPRECATED] getMooseClients() is deprecated. Use getMooseUtils() instead."
3814
+ );
3815
+ if (config && Object.keys(config).length > 0) {
3816
+ await Promise.resolve().then(() => (init_runtime(), runtime_exports));
3817
+ const configRegistry = globalThis._mooseConfigRegistry;
3818
+ if (!configRegistry) {
3819
+ throw new Error(
3820
+ "Configuration registry not initialized. Ensure the Moose framework is properly set up."
3821
+ );
3822
+ }
3823
+ const clickhouseConfig = await configRegistry.getStandaloneClickhouseConfig(config);
3824
+ const clickhouseClient = getClickhouseClient(
3825
+ toClientConfig(clickhouseConfig)
3826
+ );
3827
+ const queryClient = new QueryClient(clickhouseClient, "standalone");
3828
+ const mooseClient = new MooseClient(queryClient);
3829
+ return { client: mooseClient };
3830
+ }
3831
+ const utils = await getMooseUtils();
3832
+ return { client: utils.client };
3833
+ }
3834
+ function jsonDateReviver(key, value) {
3835
+ const iso8601Format = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)$/;
3836
+ if (typeof value === "string" && iso8601Format.test(value)) {
3837
+ return new Date(value);
3838
+ }
3839
+ return value;
3840
+ }
3841
+ function parseCSV(content2, config) {
3842
+ return new Promise((resolve2, reject) => {
3843
+ const results = [];
3844
+ (0, import_csv_parse.parse)(content2, {
3845
+ delimiter: config.delimiter,
3846
+ columns: config.columns ?? true,
3847
+ skip_empty_lines: config.skipEmptyLines ?? true,
3848
+ trim: config.trim ?? true
3849
+ }).on("data", (row) => {
3850
+ results.push(row);
3851
+ }).on("end", () => {
3852
+ resolve2(results);
3853
+ }).on("error", (error) => {
3854
+ reject(error);
3855
+ });
3856
+ });
3857
+ }
3858
+ function parseJSON(content2, config = {}) {
3859
+ try {
3860
+ const parsed = JSON.parse(content2, config.reviver);
3861
+ if (Array.isArray(parsed)) {
3862
+ return parsed;
3863
+ } else {
3864
+ return [parsed];
3865
+ }
3866
+ } catch (error) {
3867
+ throw new Error(
3868
+ `Failed to parse JSON: ${error instanceof Error ? error.message : "Unknown error"}`
3869
+ );
3870
+ }
3871
+ }
3872
+ function parseJSONWithDates(content2) {
3873
+ return parseJSON(content2, { reviver: jsonDateReviver });
3874
+ }
3875
+ function isValidCSVDelimiter(delimiter) {
3876
+ return delimiter.length === 1 && !/\s/.test(delimiter);
3877
+ }
3878
+ var CSV_DELIMITERS = {
3879
+ COMMA: ",",
3880
+ TAB: " ",
3881
+ SEMICOLON: ";",
3882
+ PIPE: "|"
3883
+ };
3884
+ var DEFAULT_CSV_CONFIG = {
3885
+ delimiter: CSV_DELIMITERS.COMMA,
3886
+ columns: true,
3887
+ skipEmptyLines: true,
3888
+ trim: true
3889
+ };
3890
+ var DEFAULT_JSON_CONFIG = {
3891
+ reviver: jsonDateReviver
3892
+ };
3893
+ var DataSource = class {
3894
+ name;
3895
+ supportsIncremental;
3896
+ constructor(config) {
3897
+ this.name = config.name;
3898
+ this.supportsIncremental = config.supportsIncremental ?? false;
3899
+ }
3900
+ };
3161
3901
 
3162
3902
  // src/index.ts
3163
3903
  var _pendingClickHouseConfig = null;
@@ -3195,9 +3935,11 @@ function configureClickHouse(config) {
3195
3935
  0 && (module.exports = {
3196
3936
  ACKs,
3197
3937
  Api,
3938
+ ApiHelpers,
3198
3939
  CSV_DELIMITERS,
3199
3940
  ClickHouseEngines,
3200
3941
  ConsumptionApi,
3942
+ ConsumptionHelpers,
3201
3943
  DEFAULT_CSV_CONFIG,
3202
3944
  DEFAULT_JSON_CONFIG,
3203
3945
  DataSource,
@@ -3211,7 +3953,10 @@ function configureClickHouse(config) {
3211
3953
  MAX_RETRY_TIME_MS,
3212
3954
  MOOSE_RUNTIME_ENV_PREFIX,
3213
3955
  MaterializedView,
3956
+ MooseCache,
3957
+ MooseClient,
3214
3958
  OlapTable,
3959
+ QueryClient,
3215
3960
  RETRY_FACTOR_PRODUCER,
3216
3961
  RETRY_INITIAL_TIME_MS,
3217
3962
  Sql,
@@ -3221,24 +3966,35 @@ function configureClickHouse(config) {
3221
3966
  View,
3222
3967
  WebApp,
3223
3968
  Workflow,
3969
+ WorkflowClient,
3224
3970
  antiCachePath,
3225
3971
  cliLog,
3226
3972
  compilerLog,
3227
3973
  configureClickHouse,
3228
3974
  createClickhouseParameter,
3975
+ createProducerConfig,
3976
+ expressMiddleware,
3229
3977
  getApi,
3230
3978
  getApis,
3979
+ getClickhouseClient,
3231
3980
  getFileName,
3232
3981
  getIngestApi,
3233
3982
  getIngestApis,
3983
+ getKafkaClient,
3984
+ getKafkaProducer,
3985
+ getLegacyMooseUtils,
3234
3986
  getMaterializedView,
3235
3987
  getMaterializedViews,
3988
+ getMooseClients,
3989
+ getMooseUtils,
3990
+ getMooseUtilsFromRequest,
3236
3991
  getSqlResource,
3237
3992
  getSqlResources,
3238
3993
  getStream,
3239
3994
  getStreams,
3240
3995
  getTable,
3241
3996
  getTables,
3997
+ getTemporalClient,
3242
3998
  getValueFromParameter,
3243
3999
  getView,
3244
4000
  getViews,
@@ -3247,6 +4003,7 @@ function configureClickHouse(config) {
3247
4003
  getWorkflow,
3248
4004
  getWorkflows,
3249
4005
  isValidCSVDelimiter,
4006
+ joinQueries,
3250
4007
  logError,
3251
4008
  mapToClickHouseType,
3252
4009
  mapTstoJs,
@@ -3256,6 +4013,7 @@ function configureClickHouse(config) {
3256
4013
  parseJSON,
3257
4014
  parseJSONWithDates,
3258
4015
  quoteIdentifier,
4016
+ rewriteImportExtensions,
3259
4017
  sql,
3260
4018
  toQuery,
3261
4019
  toQueryPreview,