ts-prorm-orm 1.1.0

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.
Files changed (310) hide show
  1. package/CHANGELOG.md +1111 -0
  2. package/LICENSE +21 -0
  3. package/README.md +573 -0
  4. package/dist/audit/history-query.js +180 -0
  5. package/dist/audit/index.js +23 -0
  6. package/dist/audit/logger.js +236 -0
  7. package/dist/cache/cache-manager.js +84 -0
  8. package/dist/cache/index.js +16 -0
  9. package/dist/cache/redis-cluster-cache.js +557 -0
  10. package/dist/cli.js +2200 -0
  11. package/dist/compliance/audit-trail.js +68 -0
  12. package/dist/compliance/backup-verification.js +685 -0
  13. package/dist/compliance/breach-detector.js +505 -0
  14. package/dist/compliance/consent-record.js +227 -0
  15. package/dist/compliance/consent-versioning.js +331 -0
  16. package/dist/compliance/cross-border-log.js +530 -0
  17. package/dist/compliance/data-classifier.js +258 -0
  18. package/dist/compliance/data-lineage.js +565 -0
  19. package/dist/compliance/data-masker.js +303 -0
  20. package/dist/compliance/data-portability.js +265 -0
  21. package/dist/compliance/data-retention.js +195 -0
  22. package/dist/compliance/dsar-workflow.js +342 -0
  23. package/dist/compliance/field-encryption.js +223 -0
  24. package/dist/compliance/immutable-record.js +148 -0
  25. package/dist/compliance/index.js +260 -0
  26. package/dist/compliance/privacy-impact-assessment.js +364 -0
  27. package/dist/compliance/pseudonymization.js +269 -0
  28. package/dist/compliance/query-firewall.js +1182 -0
  29. package/dist/compliance/rate-limiter.js +580 -0
  30. package/dist/compliance/right-to-erasure.js +117 -0
  31. package/dist/compliance/row-level-security.js +246 -0
  32. package/dist/compliance/security-decorator.js +574 -0
  33. package/dist/compliance/security-monitor.js +525 -0
  34. package/dist/compliance/sensitive-data-discovery.js +476 -0
  35. package/dist/compliance/session-isolation.js +472 -0
  36. package/dist/compliance/tls-enforcer.js +108 -0
  37. package/dist/compliance/worm-storage.js +712 -0
  38. package/dist/connection-manager.js +198 -0
  39. package/dist/connection-pool.js +519 -0
  40. package/dist/decorators/audit.js +136 -0
  41. package/dist/decorators/belongs-to-many.js +115 -0
  42. package/dist/decorators/belongs-to.js +115 -0
  43. package/dist/decorators/check.js +435 -0
  44. package/dist/decorators/collate.js +329 -0
  45. package/dist/decorators/comment.js +205 -0
  46. package/dist/decorators/database-settings.js +236 -0
  47. package/dist/decorators/default.js +244 -0
  48. package/dist/decorators/encryption.js +235 -0
  49. package/dist/decorators/engine.js +97 -0
  50. package/dist/decorators/fk-constraints.js +594 -0
  51. package/dist/decorators/foreign-table.js +136 -0
  52. package/dist/decorators/generated.js +274 -0
  53. package/dist/decorators/has-many.js +127 -0
  54. package/dist/decorators/has-one.js +116 -0
  55. package/dist/decorators/hstore.js +129 -0
  56. package/dist/decorators/index.js +355 -0
  57. package/dist/decorators/json-column.js +83 -0
  58. package/dist/decorators/jsonb.js +101 -0
  59. package/dist/decorators/orm-decorators.js +425 -0
  60. package/dist/decorators/permissions.js +294 -0
  61. package/dist/decorators/procedure.js +210 -0
  62. package/dist/decorators/query-options.js +556 -0
  63. package/dist/decorators/range.js +167 -0
  64. package/dist/decorators/set-column.js +83 -0
  65. package/dist/decorators/spatial.js +114 -0
  66. package/dist/decorators/storage.js +580 -0
  67. package/dist/decorators/timezone.js +512 -0
  68. package/dist/decorators/trigger.js +90 -0
  69. package/dist/decorators/uuid.js +135 -0
  70. package/dist/decorators/view.js +258 -0
  71. package/dist/diagrams/chen-diagram.js +354 -0
  72. package/dist/diagrams/class-diagram.js +384 -0
  73. package/dist/diagrams/dependency-diagram.js +432 -0
  74. package/dist/diagrams/er-diagram.js +605 -0
  75. package/dist/diagrams/flow-diagram.js +394 -0
  76. package/dist/diagrams/gantt-diagram.js +411 -0
  77. package/dist/diagrams/index-diagram.js +353 -0
  78. package/dist/diagrams/index.js +184 -0
  79. package/dist/diagrams/migration-diagram.js +316 -0
  80. package/dist/diagrams/model-diagram.js +616 -0
  81. package/dist/diagrams/package-diagram.js +376 -0
  82. package/dist/diagrams/palette.js +85 -0
  83. package/dist/diagrams/relational-diagram.js +455 -0
  84. package/dist/diagrams/schemadoc-diagram.js +309 -0
  85. package/dist/diagrams/sequence-diagram.js +307 -0
  86. package/dist/diagrams/state-diagram.js +344 -0
  87. package/dist/diagrams/svg-dom.js +111 -0
  88. package/dist/diagrams/tree-diagram.js +250 -0
  89. package/dist/dialects/clickhouse/index.js +1742 -0
  90. package/dist/dialects/cockroachdb/index.js +4677 -0
  91. package/dist/dialects/cratedb/index.js +441 -0
  92. package/dist/dialects/databricks/index.js +517 -0
  93. package/dist/dialects/db2/index.js +2225 -0
  94. package/dist/dialects/dialect.js +720 -0
  95. package/dist/dialects/duckdb/index.js +2014 -0
  96. package/dist/dialects/exasol/index.js +357 -0
  97. package/dist/dialects/firebird/index.js +495 -0
  98. package/dist/dialects/greenplum/index.js +457 -0
  99. package/dist/dialects/hana/index.js +1741 -0
  100. package/dist/dialects/mariadb/index.js +3590 -0
  101. package/dist/dialects/mssql/index.js +2296 -0
  102. package/dist/dialects/mysql/index.js +4058 -0
  103. package/dist/dialects/oracle/index.js +2999 -0
  104. package/dist/dialects/postgres/index.js +5319 -0
  105. package/dist/dialects/query-stream-helper.js +152 -0
  106. package/dist/dialects/questdb/index.js +433 -0
  107. package/dist/dialects/redshift/index.js +2277 -0
  108. package/dist/dialects/singlestore/index.js +354 -0
  109. package/dist/dialects/snowflake/index.js +2082 -0
  110. package/dist/dialects/spanner/index.js +1768 -0
  111. package/dist/dialects/sqlite/index.js +3382 -0
  112. package/dist/dialects/tidb/index.js +377 -0
  113. package/dist/dialects/timescaledb/index.js +164 -0
  114. package/dist/dialects/trino/index.js +420 -0
  115. package/dist/dialects/turso/index.js +227 -0
  116. package/dist/dialects/vertica/index.js +317 -0
  117. package/dist/dialects/yugabytedb/index.js +424 -0
  118. package/dist/errors/index.js +472 -0
  119. package/dist/errors/utils.js +340 -0
  120. package/dist/errors.js +21 -0
  121. package/dist/extensions/catalog/cloud-warehouse-features.js +207 -0
  122. package/dist/extensions/catalog/mssql-features.js +147 -0
  123. package/dist/extensions/catalog/mysql-mariadb-plugins.js +229 -0
  124. package/dist/extensions/catalog/oracle-db2-features.js +196 -0
  125. package/dist/extensions/catalog/postgres-extensions.js +516 -0
  126. package/dist/extensions/index.js +71 -0
  127. package/dist/extensions/types.js +13 -0
  128. package/dist/foreign-data.js +173 -0
  129. package/dist/hooks/hooks-manager.js +350 -0
  130. package/dist/hooks/index.js +37 -0
  131. package/dist/index.js +463 -0
  132. package/dist/logging.js +335 -0
  133. package/dist/migrations/index.js +40 -0
  134. package/dist/migrations/migration.js +196 -0
  135. package/dist/migrations/migrator.js +411 -0
  136. package/dist/migrations/prormmigration.js +275 -0
  137. package/dist/migrations/query-interface.js +435 -0
  138. package/dist/migrations/seeder.js +353 -0
  139. package/dist/models/associations.js +852 -0
  140. package/dist/models/constraints.js +288 -0
  141. package/dist/models/data-types.js +2518 -0
  142. package/dist/models/decorators.js +445 -0
  143. package/dist/models/index.js +33 -0
  144. package/dist/models/indexes.js +531 -0
  145. package/dist/models/methods.js +382 -0
  146. package/dist/models/model-manager.js +103 -0
  147. package/dist/models/model.js +5349 -0
  148. package/dist/models/operators.js +67 -0
  149. package/dist/models/scopes.js +189 -0
  150. package/dist/models/typescript-types.js +26 -0
  151. package/dist/nosql/aerospike/index.js +205 -0
  152. package/dist/nosql/allegrograph/index.js +169 -0
  153. package/dist/nosql/arangodb/index.js +364 -0
  154. package/dist/nosql/azure-blob/index.js +206 -0
  155. package/dist/nosql/beanstalkd/index.js +231 -0
  156. package/dist/nosql/beequeue/index.js +210 -0
  157. package/dist/nosql/bigchaindb/index.js +195 -0
  158. package/dist/nosql/bigtable/index.js +224 -0
  159. package/dist/nosql/blazegraph/index.js +173 -0
  160. package/dist/nosql/bullmq/index.js +191 -0
  161. package/dist/nosql/cassandra/index.js +174 -0
  162. package/dist/nosql/chroma/index.js +190 -0
  163. package/dist/nosql/cloudflare-kv/index.js +220 -0
  164. package/dist/nosql/coherence/index.js +200 -0
  165. package/dist/nosql/cosmosdb/index.js +157 -0
  166. package/dist/nosql/couchbase/index.js +213 -0
  167. package/dist/nosql/dax/index.js +212 -0
  168. package/dist/nosql/deno-kv/index.js +206 -0
  169. package/dist/nosql/dgraph/index.js +171 -0
  170. package/dist/nosql/doris/index.js +169 -0
  171. package/dist/nosql/druid/index.js +162 -0
  172. package/dist/nosql/dynamodb/index.js +937 -0
  173. package/dist/nosql/elasticsearch/index.js +377 -0
  174. package/dist/nosql/etcd/index.js +502 -0
  175. package/dist/nosql/eventhubs/index.js +213 -0
  176. package/dist/nosql/eventstore/index.js +254 -0
  177. package/dist/nosql/faunadb/index.js +188 -0
  178. package/dist/nosql/firestore/index.js +177 -0
  179. package/dist/nosql/fluree/index.js +148 -0
  180. package/dist/nosql/fuseki/index.js +170 -0
  181. package/dist/nosql/gcs/index.js +172 -0
  182. package/dist/nosql/gearman/index.js +160 -0
  183. package/dist/nosql/geode/index.js +196 -0
  184. package/dist/nosql/graphdb/index.js +169 -0
  185. package/dist/nosql/graylog/index.js +188 -0
  186. package/dist/nosql/gridgain/index.js +171 -0
  187. package/dist/nosql/hazelcast/index.js +162 -0
  188. package/dist/nosql/hbase/index.js +230 -0
  189. package/dist/nosql/ignite/index.js +173 -0
  190. package/dist/nosql/immudb/index.js +184 -0
  191. package/dist/nosql/index.js +232 -0
  192. package/dist/nosql/infinispan/index.js +200 -0
  193. package/dist/nosql/influxdb/index.js +0 -0
  194. package/dist/nosql/kafka/index.js +234 -0
  195. package/dist/nosql/keyspaces/index.js +189 -0
  196. package/dist/nosql/kinesis/index.js +253 -0
  197. package/dist/nosql/leveldb/index.js +153 -0
  198. package/dist/nosql/lmdb/index.js +160 -0
  199. package/dist/nosql/loki/index.js +201 -0
  200. package/dist/nosql/marklogic/index.js +204 -0
  201. package/dist/nosql/materialize/index.js +145 -0
  202. package/dist/nosql/meilisearch/index.js +154 -0
  203. package/dist/nosql/memcached/index.js +223 -0
  204. package/dist/nosql/milvus/index.js +410 -0
  205. package/dist/nosql/minio/index.js +265 -0
  206. package/dist/nosql/momento/index.js +179 -0
  207. package/dist/nosql/mongodb/index.js +461 -0
  208. package/dist/nosql/nats/index.js +247 -0
  209. package/dist/nosql/nedb/index.js +164 -0
  210. package/dist/nosql/neo4j/index.js +450 -0
  211. package/dist/nosql/neptune/index.js +470 -0
  212. package/dist/nosql/nsq/index.js +200 -0
  213. package/dist/nosql/opensearch/index.js +186 -0
  214. package/dist/nosql/orientdb/index.js +175 -0
  215. package/dist/nosql/papertrail/index.js +200 -0
  216. package/dist/nosql/pinecone/index.js +0 -0
  217. package/dist/nosql/pinot/index.js +133 -0
  218. package/dist/nosql/pouchdb/index.js +172 -0
  219. package/dist/nosql/prometheus/index.js +174 -0
  220. package/dist/nosql/provendb/index.js +147 -0
  221. package/dist/nosql/pubsub/index.js +187 -0
  222. package/dist/nosql/pulsar/index.js +232 -0
  223. package/dist/nosql/qdrant/index.js +295 -0
  224. package/dist/nosql/qldb/index.js +192 -0
  225. package/dist/nosql/r2/index.js +281 -0
  226. package/dist/nosql/rabbitmq/index.js +237 -0
  227. package/dist/nosql/ravendb/index.js +175 -0
  228. package/dist/nosql/redis/index.js +607 -0
  229. package/dist/nosql/redpanda/index.js +237 -0
  230. package/dist/nosql/resque/index.js +203 -0
  231. package/dist/nosql/rethinkdb/index.js +232 -0
  232. package/dist/nosql/rocksdb/index.js +152 -0
  233. package/dist/nosql/rockset/index.js +126 -0
  234. package/dist/nosql/s3/index.js +298 -0
  235. package/dist/nosql/scylladb/index.js +178 -0
  236. package/dist/nosql/signoz/index.js +227 -0
  237. package/dist/nosql/sns/index.js +201 -0
  238. package/dist/nosql/solr/index.js +231 -0
  239. package/dist/nosql/splunk/index.js +227 -0
  240. package/dist/nosql/sqs/index.js +246 -0
  241. package/dist/nosql/stardog/index.js +169 -0
  242. package/dist/nosql/starrocks/index.js +170 -0
  243. package/dist/nosql/store.js +2 -0
  244. package/dist/nosql/sumologic/index.js +213 -0
  245. package/dist/nosql/surrealdb/index.js +179 -0
  246. package/dist/nosql/terminusdb/index.js +151 -0
  247. package/dist/nosql/tigergraph/index.js +469 -0
  248. package/dist/nosql/typesense/index.js +148 -0
  249. package/dist/nosql/unqlite/index.js +157 -0
  250. package/dist/nosql/upstash/index.js +167 -0
  251. package/dist/nosql/vercel-kv/index.js +166 -0
  252. package/dist/nosql/victoriametrics/index.js +213 -0
  253. package/dist/nosql/virtuoso/index.js +169 -0
  254. package/dist/nosql/weaviate/index.js +276 -0
  255. package/dist/operators/index.js +108 -0
  256. package/dist/operators.js +2690 -0
  257. package/dist/prisma-migrate/index.js +38 -0
  258. package/dist/prisma-migrate/migration-generator.js +125 -0
  259. package/dist/prisma-migrate/model-generator.js +172 -0
  260. package/dist/prisma-migrate/relations.js +100 -0
  261. package/dist/prisma-migrate/schema-parser.js +167 -0
  262. package/dist/prisma-migrate/type-mapper.js +40 -0
  263. package/dist/prorm.js +6832 -0
  264. package/dist/query-builders/cte-builder.js +80 -0
  265. package/dist/query-builders/functions/aggregate.js +390 -0
  266. package/dist/query-builders/functions/conditional.js +503 -0
  267. package/dist/query-builders/functions/datetime.js +695 -0
  268. package/dist/query-builders/functions/fulltext.js +439 -0
  269. package/dist/query-builders/functions/index.js +93 -0
  270. package/dist/query-builders/functions/json.js +427 -0
  271. package/dist/query-builders/functions/math.js +399 -0
  272. package/dist/query-builders/functions/string.js +518 -0
  273. package/dist/query-builders/functions/window.js +328 -0
  274. package/dist/query-builders/include-builder.js +323 -0
  275. package/dist/query-builders/index-expression-builder.js +242 -0
  276. package/dist/query-builders/index.js +161 -0
  277. package/dist/query-builders/insert-builder.js +164 -0
  278. package/dist/query-builders/model-helpers.js +38 -0
  279. package/dist/query-builders/order-limit-builder.js +239 -0
  280. package/dist/query-builders/sql-compiler.js +2040 -0
  281. package/dist/query-builders/subquery-builder.js +152 -0
  282. package/dist/query-builders/update-builder.js +182 -0
  283. package/dist/query-builders/view-builder.js +218 -0
  284. package/dist/query-builders/where-builder.js +1532 -0
  285. package/dist/query-interface.js +622 -0
  286. package/dist/query-optimizers/batch-optimizer.js +426 -0
  287. package/dist/query-optimizers/explain-plans.js +415 -0
  288. package/dist/query-optimizers/index.js +51 -0
  289. package/dist/query-optimizers/prepared-statement-cache.js +423 -0
  290. package/dist/query-optimizers/query-hints.js +438 -0
  291. package/dist/query-optimizers/query-optimizer.js +278 -0
  292. package/dist/query-optimizers/slow-query-logger.js +271 -0
  293. package/dist/replica-manager.js +507 -0
  294. package/dist/schema/index.js +15 -0
  295. package/dist/schema/migration-generator.js +374 -0
  296. package/dist/schema/schema-differ.js +549 -0
  297. package/dist/schema/types.js +6 -0
  298. package/dist/sql-constants.js +300 -0
  299. package/dist/sqlite-advanced.js +1047 -0
  300. package/dist/streams/index.js +12 -0
  301. package/dist/streams/transforms.js +178 -0
  302. package/dist/transaction.js +456 -0
  303. package/dist/types/index.js +180 -0
  304. package/dist/user-management.js +127 -0
  305. package/dist/utils/date.js +300 -0
  306. package/dist/utils/index.js +1079 -0
  307. package/dist/utils/string.js +161 -0
  308. package/dist/validators/index.js +19 -0
  309. package/dist/validators/validator.js +911 -0
  310. package/package.json +190 -0
@@ -0,0 +1,1079 @@
1
+ "use strict";
2
+ /**
3
+ * Utility functions for the ORM
4
+ * Includes string converters, pluralization, object utilities, UUID generation, and SQL formatting
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
18
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.camelToSnake = camelToSnake;
22
+ exports.camelize = camelize;
23
+ exports.snakeToCamel = snakeToCamel;
24
+ exports.snakeCase = snakeCase;
25
+ exports.camelToKebab = camelToKebab;
26
+ exports.kebabToCamel = kebabToCamel;
27
+ exports.pluralize = pluralize;
28
+ exports.singularize = singularize;
29
+ exports.cloneDeep = cloneDeep;
30
+ exports.merge = merge;
31
+ exports.pick = pick;
32
+ exports.omit = omit;
33
+ exports.generateUUID = generateUUID;
34
+ exports.generateShortUUID = generateShortUUID;
35
+ exports.isValidUUID = isValidUUID;
36
+ exports.formatValues = formatValues;
37
+ exports.formatValue = formatValue;
38
+ exports.escapeString = escapeString;
39
+ exports.escapeId = escapeId;
40
+ exports.formatWhere = formatWhere;
41
+ exports.isEmpty = isEmpty;
42
+ exports.coalesce = coalesce;
43
+ exports.escapeLike = escapeLike;
44
+ exports.addTicks = addTicks;
45
+ exports.removeTicks = removeTicks;
46
+ exports.toDefaultValue = toDefaultValue;
47
+ exports.formatDefaultValue = formatDefaultValue;
48
+ exports.spliceStr = spliceStr;
49
+ exports.formatDateString = formatDateString;
50
+ exports.randomString = randomString;
51
+ exports.randomAlphaNumeric = randomAlphaNumeric;
52
+ exports.randomNumeric = randomNumeric;
53
+ exports.randomHex = randomHex;
54
+ exports.timestamp = timestamp;
55
+ exports.nowDate = nowDate;
56
+ exports.defaultValue = defaultValue;
57
+ exports.defaultIfEmpty = defaultIfEmpty;
58
+ exports.retry = retry;
59
+ exports.retryWithBackoff = retryWithBackoff;
60
+ exports.unique = unique;
61
+ exports.flatten = flatten;
62
+ exports.groupBy = groupBy;
63
+ exports.sortBy = sortBy;
64
+ exports.sum = sum;
65
+ exports.underscore = underscore;
66
+ exports.includes = includes;
67
+ exports.startsWith = startsWith;
68
+ exports.endsWith = endsWith;
69
+ exports.repeat = repeat;
70
+ exports.reverse = reverse;
71
+ exports.clone = clone;
72
+ exports.get = get;
73
+ exports.set = set;
74
+ exports.has = has;
75
+ exports.isString = isString;
76
+ exports.isNumber = isNumber;
77
+ exports.isBoolean = isBoolean;
78
+ exports.isDate = isDate;
79
+ exports.isArray = isArray;
80
+ exports.isObject = isObject;
81
+ exports.formatCurrency = formatCurrency;
82
+ exports.format = format;
83
+ const string_1 = require("./string");
84
+ // ==================== String Case Converters ====================
85
+ /**
86
+ * Convert camelCase to snake_case
87
+ */
88
+ function camelToSnake(str) {
89
+ return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
90
+ }
91
+ /**
92
+ * Convert snake_case to camelCase
93
+ * Alias for snakeToCamel
94
+ */
95
+ function camelize(str) {
96
+ return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
97
+ }
98
+ /**
99
+ * Convert snake_case to camelCase
100
+ */
101
+ function snakeToCamel(str) {
102
+ return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
103
+ }
104
+ /**
105
+ * Convert camelCase to snake_case
106
+ * Alias for camelToSnake
107
+ */
108
+ function snakeCase(str) {
109
+ return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
110
+ }
111
+ /**
112
+ * Convert camelCase to kebab-case
113
+ */
114
+ function camelToKebab(str) {
115
+ return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
116
+ }
117
+ /**
118
+ * Convert kebab-case to camelCase
119
+ */
120
+ function kebabToCamel(str) {
121
+ return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
122
+ }
123
+ // ==================== Pluralization ====================
124
+ // Common irregular plurals
125
+ const irregularPlurals = {
126
+ person: 'people',
127
+ man: 'men',
128
+ woman: 'women',
129
+ child: 'children',
130
+ tooth: 'teeth',
131
+ foot: 'feet',
132
+ mouse: 'mice',
133
+ goose: 'geese',
134
+ ox: 'oxen',
135
+ quiz: 'quizzes',
136
+ matrix: 'matrices',
137
+ vertex: 'vertices',
138
+ index: 'indices',
139
+ appendix: 'appendices',
140
+ bacterium: 'bacteria',
141
+ criterion: 'criteria',
142
+ phenomenon: 'phenomena',
143
+ analysis: 'analyses',
144
+ diagnosis: 'diagnoses',
145
+ hypothesis: 'hypotheses',
146
+ synthesis: 'syntheses',
147
+ crisis: 'crises',
148
+ basis: 'bases',
149
+ };
150
+ // Words that are the same in singular and plural
151
+ const uncountableWords = new Set([
152
+ 'equipment',
153
+ 'information',
154
+ 'rice',
155
+ 'money',
156
+ 'species',
157
+ 'series',
158
+ 'fish',
159
+ 'sheep',
160
+ 'deer',
161
+ 'moose',
162
+ 'aircraft',
163
+ 'offspring',
164
+ 'news',
165
+ 'media',
166
+ 'status',
167
+ ]);
168
+ /**
169
+ * Pluralize a word
170
+ */
171
+ function pluralize(word, count) {
172
+ // If count is 1, return singular form
173
+ if (count !== undefined && count === 1) {
174
+ return singularize(word);
175
+ }
176
+ // Handle uncountable words
177
+ const lowerWord = word.toLowerCase();
178
+ if (uncountableWords.has(lowerWord)) {
179
+ return word;
180
+ }
181
+ // Handle irregular plurals
182
+ if (irregularPlurals[lowerWord]) {
183
+ return irregularPlurals[lowerWord];
184
+ }
185
+ // Handle words ending in 'y' (consonant + y -> ies)
186
+ if (lowerWord.endsWith('y') && !isVowel(lowerWord[lowerWord.length - 2])) {
187
+ return word.slice(0, -1) + 'ies';
188
+ }
189
+ // Handle words ending in 'f' or 'fe' (fe -> ves)
190
+ if (lowerWord.endsWith('fe')) {
191
+ return word.slice(0, -2) + 'ves';
192
+ }
193
+ if (lowerWord.endsWith('f')) {
194
+ return word.slice(0, -1) + 'ves';
195
+ }
196
+ // Handle words ending in 'o' (sometimes -> es)
197
+ if (lowerWord.endsWith('o') && !isVowel(lowerWord[lowerWord.length - 2])) {
198
+ // Common exceptions
199
+ const exceptions = ['photo', 'piano', 'halo', 'logo', 'mango', 'cargo', 'hero', ' veto'];
200
+ if (exceptions.some((ex) => lowerWord === ex)) {
201
+ return word + 'es';
202
+ }
203
+ }
204
+ // Handle words ending in 's', 'ss', 'sh', 'ch', 'x', 'z'
205
+ const esEndings = ['s', 'ss', 'sh', 'ch', 'x', 'z', 'o'];
206
+ if (esEndings.some((ending) => lowerWord.endsWith(ending))) {
207
+ return word + 'es';
208
+ }
209
+ // Default: add 's'
210
+ return word + 's';
211
+ }
212
+ /**
213
+ * Singularize a word
214
+ */
215
+ function singularize(word) {
216
+ const lowerWord = word.toLowerCase();
217
+ // Handle uncountable words
218
+ if (uncountableWords.has(lowerWord)) {
219
+ return word;
220
+ }
221
+ // Handle irregular plurals (reverse lookup)
222
+ for (const [singular, plural] of Object.entries(irregularPlurals)) {
223
+ if (plural === lowerWord) {
224
+ // Preserve original case
225
+ if (word[0] === word[0].toUpperCase()) {
226
+ return singular.charAt(0).toUpperCase() + singular.slice(1);
227
+ }
228
+ return singular;
229
+ }
230
+ }
231
+ // Handle words ending in 'ies'
232
+ if (lowerWord.endsWith('ies') && lowerWord.length > 3) {
233
+ return word.slice(0, -3) + 'y';
234
+ }
235
+ // Handle words ending in 'ves'
236
+ if (lowerWord.endsWith('ves')) {
237
+ if (lowerWord.endsWith('lves')) {
238
+ return word.slice(0, -3) + 'fe';
239
+ }
240
+ if (lowerWord.endsWith('ives')) {
241
+ return word.slice(0, -3) + 'fe';
242
+ }
243
+ if (lowerWord.endsWith('oves')) {
244
+ return word.slice(0, -3) + 'fe';
245
+ }
246
+ return word.slice(0, -3) + 'f';
247
+ }
248
+ // Handle words ending in 'es'
249
+ if (lowerWord.endsWith('es') && lowerWord.length > 2) {
250
+ // Check for words ending in 'ses', 'shes', 'ches', 'xes', 'zes'
251
+ if (lowerWord.length > 3 && /[sz]es$/.test(lowerWord)) {
252
+ return word.slice(0, -2);
253
+ }
254
+ // Check for words like 'heroes', 'vetoes'
255
+ if (/[aeiou]oes$/.test(lowerWord)) {
256
+ return word.slice(0, -2);
257
+ }
258
+ }
259
+ // Handle words ending in 's' (but not 'ss')
260
+ if (lowerWord.endsWith('s') && !lowerWord.endsWith('ss') && lowerWord.length > 1) {
261
+ return word.slice(0, -1);
262
+ }
263
+ return word;
264
+ }
265
+ /**
266
+ * Helper function to check if a character is a vowel
267
+ */
268
+ function isVowel(char) {
269
+ return 'aeiou'.includes(char.toLowerCase());
270
+ }
271
+ // ==================== Object Utilities ====================
272
+ /**
273
+ * Deep clone an object
274
+ */
275
+ function cloneDeep(obj) {
276
+ if (obj === null || typeof obj !== 'object') {
277
+ return obj;
278
+ }
279
+ if (obj instanceof Date) {
280
+ return new Date(obj.getTime());
281
+ }
282
+ if (obj instanceof Array) {
283
+ return obj.map((item) => cloneDeep(item));
284
+ }
285
+ if (obj instanceof Set) {
286
+ return new Set(Array.from(obj).map((item) => cloneDeep(item)));
287
+ }
288
+ if (obj instanceof Map) {
289
+ return new Map(Array.from(obj.entries()).map(([key, value]) => [cloneDeep(key), cloneDeep(value)]));
290
+ }
291
+ if (typeof obj === 'object') {
292
+ const cloned = {};
293
+ for (const key of Object.keys(obj)) {
294
+ cloned[key] = cloneDeep(obj[key]);
295
+ }
296
+ return cloned;
297
+ }
298
+ return obj;
299
+ }
300
+ /**
301
+ * Deep merge objects
302
+ */
303
+ function merge(target, ...sources) {
304
+ if (!sources.length) {
305
+ return target;
306
+ }
307
+ const source = sources.shift();
308
+ if (isPlainObject(target) && isPlainObject(source)) {
309
+ const sourceObj = source;
310
+ const sourceKeys = Object.keys(sourceObj);
311
+ for (const key of sourceKeys) {
312
+ const sourceValue = sourceObj[key];
313
+ if (isPlainObject(sourceValue)) {
314
+ if (!target[key]) {
315
+ Object.assign(target, { [key]: {} });
316
+ }
317
+ merge(target[key], sourceValue);
318
+ }
319
+ else if (sourceValue !== undefined) {
320
+ Object.assign(target, { [key]: sourceValue });
321
+ }
322
+ }
323
+ }
324
+ return merge(target, ...sources);
325
+ }
326
+ /**
327
+ * Check if value is a plain object
328
+ */
329
+ function isPlainObject(item) {
330
+ return item && typeof item === 'object' && !Array.isArray(item);
331
+ }
332
+ /**
333
+ * Pick properties from an object
334
+ */
335
+ function pick(obj, keys) {
336
+ const result = {};
337
+ for (const key of keys) {
338
+ if (key in obj) {
339
+ result[key] = obj[key];
340
+ }
341
+ }
342
+ return result;
343
+ }
344
+ /**
345
+ * Omit properties from an object
346
+ */
347
+ function omit(obj, keys) {
348
+ const result = { ...obj };
349
+ for (const key of keys) {
350
+ delete result[key];
351
+ }
352
+ return result;
353
+ }
354
+ // ==================== UUID Generation ====================
355
+ /**
356
+ * Generate a UUID v4
357
+ */
358
+ function generateUUID() {
359
+ // Use crypto.randomUUID if available
360
+ if (typeof crypto !== 'undefined' && crypto.randomUUID) {
361
+ return crypto.randomUUID();
362
+ }
363
+ // Fallback implementation
364
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
365
+ const r = (Math.random() * 16) | 0;
366
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
367
+ return v.toString(16);
368
+ });
369
+ }
370
+ /**
371
+ * Generate a short UUID (8 characters)
372
+ */
373
+ function generateShortUUID() {
374
+ return generateUUID().replace(/-/g, '').substring(0, 8);
375
+ }
376
+ /**
377
+ * Validate UUID format
378
+ */
379
+ function isValidUUID(uuid) {
380
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
381
+ return uuidRegex.test(uuid);
382
+ }
383
+ // ==================== SQL Formatting ====================
384
+ /**
385
+ * Format values for SQL query
386
+ */
387
+ function formatValues(values) {
388
+ const formatted = {};
389
+ for (const [key, value] of Object.entries(values)) {
390
+ formatted[key] = formatValue(value);
391
+ }
392
+ return formatted;
393
+ }
394
+ /**
395
+ * Format a single value for SQL
396
+ */
397
+ function formatValue(value) {
398
+ if (value === null || value === undefined) {
399
+ return null;
400
+ }
401
+ if (value instanceof Date) {
402
+ return value.toISOString();
403
+ }
404
+ if (Array.isArray(value)) {
405
+ return value.map((item) => formatValue(item));
406
+ }
407
+ if (typeof value === 'object') {
408
+ // Handle special objects
409
+ if (value instanceof Set) {
410
+ return Array.from(value).map((item) => formatValue(item));
411
+ }
412
+ if (value instanceof Map) {
413
+ const obj = {};
414
+ value.forEach((v, k) => {
415
+ obj[k] = formatValue(v);
416
+ });
417
+ return JSON.stringify(obj);
418
+ }
419
+ return JSON.stringify(value);
420
+ }
421
+ return value;
422
+ }
423
+ /**
424
+ * Escape a string for SQL
425
+ */
426
+ function escapeString(value) {
427
+ if (typeof value !== 'string') {
428
+ return String(value);
429
+ }
430
+ // Escape single quotes by doubling them
431
+ return value.replace(/'/g, "''");
432
+ }
433
+ /**
434
+ * Escape an identifier (table/column name)
435
+ */
436
+ function escapeId(identifier) {
437
+ // Escape backticks and wrap in backticks
438
+ return `\`${identifier.replace(/`/g, '``')}\``;
439
+ }
440
+ /**
441
+ * Format a where condition for SQL
442
+ */
443
+ function formatWhere(where) {
444
+ const conditions = [];
445
+ for (const [key, value] of Object.entries(where)) {
446
+ if (key.startsWith('$')) {
447
+ // Logical operators
448
+ continue;
449
+ }
450
+ if (typeof value === 'object' && value !== null) {
451
+ // Operator conditions
452
+ for (const [op, opValue] of Object.entries(value)) {
453
+ conditions.push(`${escapeId(key)} ${formatOperator(op)} ${formatValue(opValue)}`);
454
+ }
455
+ }
456
+ else {
457
+ // Simple equality
458
+ conditions.push(`${escapeId(key)} = ${formatValue(value)}`);
459
+ }
460
+ }
461
+ return conditions.join(' AND ');
462
+ }
463
+ /**
464
+ * Format an operator
465
+ */
466
+ function formatOperator(op) {
467
+ const operators = {
468
+ $eq: '=',
469
+ $ne: '!=',
470
+ $gt: '>',
471
+ $gte: '>=',
472
+ $lt: '<',
473
+ $lte: '<=',
474
+ $like: 'LIKE',
475
+ $notLike: 'NOT LIKE',
476
+ $in: 'IN',
477
+ $notIn: 'NOT IN',
478
+ $between: 'BETWEEN',
479
+ $notBetween: 'NOT BETWEEN',
480
+ $isNull: 'IS NULL',
481
+ $isNotNull: 'IS NOT NULL',
482
+ };
483
+ return operators[op] || op;
484
+ }
485
+ // ==================== Other Utilities ====================
486
+ /**
487
+ * Check if value is empty (null, undefined, empty string, empty array, empty object)
488
+ */
489
+ function isEmpty(value) {
490
+ if (value === null || value === undefined) {
491
+ return true;
492
+ }
493
+ if (typeof value === 'string') {
494
+ return value.trim() === '';
495
+ }
496
+ if (Array.isArray(value)) {
497
+ return value.length === 0;
498
+ }
499
+ if (typeof value === 'object') {
500
+ return Object.keys(value).length === 0;
501
+ }
502
+ return false;
503
+ }
504
+ /**
505
+ * Get the first defined value from arguments
506
+ */
507
+ function coalesce(...values) {
508
+ return values.find((value) => value !== null && value !== undefined);
509
+ }
510
+ // Note: `truncate` and `pad` are defined once in './string' and re-exported
511
+ // via `export * from './string'` below. Duplicate definitions used to live
512
+ // here with a different (and inconsistent) default `pad` direction, which
513
+ // silently shadowed the './string' implementation because local exports
514
+ // take precedence over `export *` re-exports for the same name.
515
+ /**
516
+ * Convert a value to a string suitable for use in SQL LIKE
517
+ */
518
+ function escapeLike(value) {
519
+ return value.replace(/[%_]/g, (match) => `\\${match}`);
520
+ }
521
+ // ==================== Tick/Backtick Utilities ====================
522
+ /**
523
+ * Wrap a string in backticks (for SQL identifiers)
524
+ */
525
+ function addTicks(str) {
526
+ return `\`${str}\``;
527
+ }
528
+ /**
529
+ * Remove backticks from a string
530
+ */
531
+ function removeTicks(str) {
532
+ return str.replace(/^`|`$/g, '');
533
+ }
534
+ /**
535
+ * Convert a value to its default JavaScript value
536
+ */
537
+ function toDefaultValue(value) {
538
+ if (value === null) {
539
+ return null;
540
+ }
541
+ if (value === undefined) {
542
+ return undefined;
543
+ }
544
+ const defaultValues = {
545
+ // String types
546
+ STRING: () => '',
547
+ TEXT: () => '',
548
+ CITEXT: () => '',
549
+ CHAR: () => '',
550
+ UUID: () => undefined,
551
+ // Number types
552
+ INTEGER: () => 0,
553
+ BIGINT: () => 0,
554
+ FLOAT: () => 0.0,
555
+ DOUBLE: () => 0.0,
556
+ DECIMAL: () => 0,
557
+ // Boolean
558
+ BOOLEAN: () => false,
559
+ // Date types
560
+ DATE: () => null,
561
+ DATEONLY: () => null,
562
+ NOW: () => null,
563
+ TIME: () => null,
564
+ // Other
565
+ JSON: () => null,
566
+ JSONB: () => null,
567
+ BLOB: () => null,
568
+ ENUM: () => null,
569
+ ARRAY: () => [],
570
+ GEOMETRY: () => null,
571
+ GEOGRAPHY: () => null,
572
+ };
573
+ // If value is a DataType instance or string type name
574
+ if (typeof value === 'string' && defaultValues[value]) {
575
+ return defaultValues[value]();
576
+ }
577
+ // If value is an object with a type property
578
+ if (typeof value === 'object' && value !== null) {
579
+ const typeName = value.type?.toUpperCase?.() || value.typeName?.toUpperCase?.();
580
+ if (typeName && defaultValues[typeName]) {
581
+ return defaultValues[typeName]();
582
+ }
583
+ }
584
+ return value;
585
+ }
586
+ /**
587
+ * Format a value for SQL based on dialect
588
+ */
589
+ function formatDefaultValue(value, dialect) {
590
+ if (value === null || value === undefined) {
591
+ return 'NULL';
592
+ }
593
+ if (typeof value === 'boolean') {
594
+ // Handle PostgreSQL boolean format
595
+ if (dialect === 'postgres') {
596
+ return value ? 'TRUE' : 'FALSE';
597
+ }
598
+ return value ? '1' : '0';
599
+ }
600
+ if (typeof value === 'number') {
601
+ return String(value);
602
+ }
603
+ if (typeof value === 'string') {
604
+ // Escape single quotes by doubling them
605
+ const escaped = value.replace(/'/g, "''");
606
+ return `'${escaped}'`;
607
+ }
608
+ if (value instanceof Date) {
609
+ const dateStr = value.toISOString();
610
+ // Handle different dialect date formats
611
+ if (dialect === 'postgres') {
612
+ return `'${dateStr}'`;
613
+ }
614
+ if (dialect === 'mysql') {
615
+ return `'${dateStr.slice(0, 19).replace('T', ' ')}'`;
616
+ }
617
+ return `'${dateStr}'`;
618
+ }
619
+ if (Array.isArray(value)) {
620
+ if (dialect === 'postgres' || dialect === 'mysql') {
621
+ return `'${JSON.stringify(value)}'::jsonb`;
622
+ }
623
+ return `'${JSON.stringify(value)}'`;
624
+ }
625
+ if (typeof value === 'object') {
626
+ return `'${JSON.stringify(value)}'`;
627
+ }
628
+ return String(value);
629
+ }
630
+ // ==================== String Splicing ====================
631
+ /**
632
+ * Insert a string at a specific position, optionally replacing characters
633
+ * @param str The original string
634
+ * @param index Position to insert/replace at (0-indexed)
635
+ * @param count Number of characters to replace (0 for insert only)
636
+ * @param insert String to insert
637
+ */
638
+ function spliceStr(str, index, count, insert) {
639
+ if (index < 0) {
640
+ index = str.length + index;
641
+ }
642
+ if (index < 0) {
643
+ index = 0;
644
+ }
645
+ if (index > str.length) {
646
+ index = str.length;
647
+ }
648
+ return str.slice(0, index) + insert + str.slice(index + count);
649
+ }
650
+ // ==================== Date Formatting ====================
651
+ /**
652
+ * Format a date to a string
653
+ * @param date - Date to format
654
+ * @param formatStr - Format string (YYYY-MM-DD, etc.)
655
+ */
656
+ function formatDateString(date, formatStr = 'YYYY-MM-DD') {
657
+ const d = date instanceof Date ? date : new Date(date);
658
+ if (isNaN(d.getTime())) {
659
+ throw new Error('Invalid date');
660
+ }
661
+ const year = d.getFullYear();
662
+ const month = String(d.getMonth() + 1).padStart(2, '0');
663
+ const day = String(d.getDate()).padStart(2, '0');
664
+ const hours = String(d.getHours()).padStart(2, '0');
665
+ const minutes = String(d.getMinutes()).padStart(2, '0');
666
+ const seconds = String(d.getSeconds()).padStart(2, '0');
667
+ return formatStr
668
+ .replace('YYYY', String(year))
669
+ .replace('YY', String(year).slice(-2))
670
+ .replace('MM', month)
671
+ .replace('DD', day)
672
+ .replace('HH', hours)
673
+ .replace('mm', minutes)
674
+ .replace('ss', seconds);
675
+ }
676
+ // ==================== Random String Generation ====================
677
+ /**
678
+ * Generate a random string of specified length
679
+ */
680
+ function randomString(length = 16, chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') {
681
+ let result = '';
682
+ const charsLength = chars.length;
683
+ for (let i = 0; i < length; i++) {
684
+ result += chars.charAt(Math.floor(Math.random() * charsLength));
685
+ }
686
+ return result;
687
+ }
688
+ /**
689
+ * Generate a random alphanumeric string
690
+ */
691
+ function randomAlphaNumeric(length = 16) {
692
+ return randomString(length, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789');
693
+ }
694
+ /**
695
+ * Generate a random numeric string
696
+ */
697
+ function randomNumeric(length = 8) {
698
+ return randomString(length, '0123456789');
699
+ }
700
+ /**
701
+ * Generate a random hex string
702
+ */
703
+ function randomHex(length = 16) {
704
+ return randomString(length, '0123456789abcdef');
705
+ }
706
+ // ==================== Current Timestamp ====================
707
+ /**
708
+ * Get current timestamp in milliseconds
709
+ *
710
+ * Note: named `timestamp` (not `now`) to avoid colliding with the
711
+ * `now(): Date` export from './date', which is re-exported via
712
+ * `export * from './date'` below and is the canonical `utils.now()`.
713
+ */
714
+ function timestamp() {
715
+ return Date.now();
716
+ }
717
+ /**
718
+ * Get current timestamp as Date object
719
+ */
720
+ function nowDate() {
721
+ return new Date();
722
+ }
723
+ // ==================== Default Value ====================
724
+ /**
725
+ * Return default value if value is null or undefined
726
+ */
727
+ function defaultValue(value, defaultVal) {
728
+ return value !== null && value !== undefined ? value : defaultVal;
729
+ }
730
+ /**
731
+ * Return default value if value is empty
732
+ */
733
+ function defaultIfEmpty(value, defaultVal) {
734
+ if (value === null || value === undefined)
735
+ return defaultVal;
736
+ if (typeof value === 'string' && value.trim() === '')
737
+ return defaultVal;
738
+ if (Array.isArray(value) && value.length === 0)
739
+ return defaultVal;
740
+ if (typeof value === 'object' && Object.keys(value).length === 0)
741
+ return defaultVal;
742
+ return value;
743
+ }
744
+ // Default error patterns to retry on
745
+ const DEFAULT_RETRY_PATTERNS = [
746
+ 'Connection timeout',
747
+ 'ETIMEDOUT',
748
+ 'ECONNREFUSED',
749
+ 'ECONNRESET',
750
+ 'EHOSTUNREACH',
751
+ 'ENOTFOUND',
752
+ 'timeout',
753
+ 'connecting',
754
+ 'connection',
755
+ 'database',
756
+ ];
757
+ /**
758
+ * Sleep for the specified duration
759
+ */
760
+ function sleep(ms) {
761
+ return new Promise((resolve) => setTimeout(resolve, ms));
762
+ }
763
+ /**
764
+ * Check if an error matches any of the retry patterns
765
+ */
766
+ function shouldRetry(error, matchPatterns) {
767
+ const errorMessage = error instanceof Error ? error.message : String(error);
768
+ const patterns = matchPatterns || DEFAULT_RETRY_PATTERNS;
769
+ return patterns.some((pattern) => errorMessage.toLowerCase().includes(pattern.toLowerCase()));
770
+ }
771
+ /**
772
+ * Calculate the delay for the next retry using exponential backoff
773
+ */
774
+ function calculateBackoffDelay(attempt, baseTimeout, backoffMultiplier, maxDelay) {
775
+ const delay = baseTimeout * Math.pow(backoffMultiplier, attempt);
776
+ return Math.min(delay, maxDelay);
777
+ }
778
+ /**
779
+ * Retry a function with configurable options
780
+ *
781
+ * @param fn - The async function to retry
782
+ * @param options - Retry options
783
+ * @returns The result of the function
784
+ */
785
+ async function retry(fn, options = {}) {
786
+ const { max = 3, timeout = 1000, match, backoff = false, backoffMultiplier = 2, backoffMax = 10000, } = options;
787
+ let lastError = 'Unknown error';
788
+ let attempt = 0;
789
+ while (attempt < max) {
790
+ try {
791
+ return await fn();
792
+ }
793
+ catch (error) {
794
+ lastError = error;
795
+ // Check if we should retry this error
796
+ if (!shouldRetry(lastError, match)) {
797
+ throw lastError;
798
+ }
799
+ attempt++;
800
+ // If we've reached max attempts, throw the last error
801
+ if (attempt >= max) {
802
+ throw lastError;
803
+ }
804
+ // Calculate delay for next retry
805
+ let delay;
806
+ if (backoff) {
807
+ delay = calculateBackoffDelay(attempt, timeout, backoffMultiplier, backoffMax);
808
+ }
809
+ else {
810
+ delay = timeout;
811
+ }
812
+ // Add some jitter to avoid thundering herd
813
+ const jitter = Math.random() * 100;
814
+ await sleep(delay + jitter);
815
+ }
816
+ }
817
+ throw lastError;
818
+ }
819
+ /**
820
+ * Retry a function with exponential backoff
821
+ *
822
+ * @param fn - The async function to retry
823
+ * @param maxRetries - Maximum number of retries (default: 3)
824
+ * @param baseTimeout - Base timeout in ms (default: 1000)
825
+ * @param maxTimeout - Maximum timeout in ms (default: 10000)
826
+ * @returns The result of the function
827
+ */
828
+ async function retryWithBackoff(fn, maxRetries = 3, baseTimeout = 1000, maxTimeout = 10000) {
829
+ return retry(fn, {
830
+ max: maxRetries,
831
+ timeout: baseTimeout,
832
+ backoff: true,
833
+ backoffMultiplier: 2,
834
+ backoffMax: maxTimeout,
835
+ });
836
+ }
837
+ // ==================== Array Utils ====================
838
+ /**
839
+ * Get unique values from an array
840
+ */
841
+ function unique(arr) {
842
+ return Array.from(new Set(arr));
843
+ }
844
+ /**
845
+ * Flatten an array of arrays
846
+ */
847
+ function flatten(arr) {
848
+ return arr.flat();
849
+ }
850
+ /**
851
+ * Group array items by a key
852
+ */
853
+ function groupBy(arr, key) {
854
+ return arr.reduce((result, item) => {
855
+ const groupKey = String(item[key]);
856
+ if (!result[groupKey]) {
857
+ result[groupKey] = [];
858
+ }
859
+ result[groupKey].push(item);
860
+ return result;
861
+ }, {});
862
+ }
863
+ /**
864
+ * Sort array by a key or function
865
+ */
866
+ function sortBy(arr, iteratee) {
867
+ return [...arr].sort((a, b) => {
868
+ const aVal = typeof iteratee === 'function' ? iteratee(a) : a[iteratee];
869
+ const bVal = typeof iteratee === 'function' ? iteratee(b) : b[iteratee];
870
+ if (aVal < bVal)
871
+ return -1;
872
+ if (aVal > bVal)
873
+ return 1;
874
+ return 0;
875
+ });
876
+ }
877
+ /**
878
+ * Sum array values
879
+ */
880
+ function sum(arr) {
881
+ return arr.reduce((total, n) => total + n, 0);
882
+ }
883
+ // ==================== Additional String Utilities ====================
884
+ /**
885
+ * Convert string to snake_case (alias for snakeCase)
886
+ */
887
+ function underscore(str) {
888
+ return snakeCase(str);
889
+ }
890
+ /**
891
+ * String includes method
892
+ */
893
+ function includes(str, searchString) {
894
+ return str.includes(searchString);
895
+ }
896
+ /**
897
+ * String startsWith method
898
+ */
899
+ function startsWith(str, searchString) {
900
+ return str.startsWith(searchString);
901
+ }
902
+ /**
903
+ * String endsWith method
904
+ */
905
+ function endsWith(str, searchString) {
906
+ return str.endsWith(searchString);
907
+ }
908
+ /**
909
+ * String repeat method
910
+ */
911
+ function repeat(str, count) {
912
+ return str.repeat(count);
913
+ }
914
+ function reverse(input) {
915
+ if (typeof input === 'string') {
916
+ return [...input].reverse().join('');
917
+ }
918
+ return [...input].reverse();
919
+ }
920
+ // ==================== Object Utilities ====================
921
+ /**
922
+ * Deep clone an object
923
+ */
924
+ function clone(obj) {
925
+ return JSON.parse(JSON.stringify(obj));
926
+ }
927
+ /**
928
+ * Get property from object
929
+ */
930
+ function get(obj, path) {
931
+ return path.split('.').reduce((acc, part) => acc && acc[part], obj);
932
+ }
933
+ /**
934
+ * Set property on object
935
+ */
936
+ function set(obj, path, value) {
937
+ const parts = path.split('.');
938
+ let current = obj;
939
+ for (let i = 0; i < parts.length - 1; i++) {
940
+ if (!current[parts[i]]) {
941
+ current[parts[i]] = {};
942
+ }
943
+ current = current[parts[i]];
944
+ }
945
+ current[parts[parts.length - 1]] = value;
946
+ }
947
+ /**
948
+ * Check if object has property
949
+ */
950
+ function has(obj, path) {
951
+ const parts = path.split('.');
952
+ let current = obj;
953
+ for (const part of parts) {
954
+ if (current == null || !(part in current)) {
955
+ return false;
956
+ }
957
+ current = current[part];
958
+ }
959
+ return true;
960
+ }
961
+ // ==================== Type Check Utilities ====================
962
+ /**
963
+ * Check if value is a string
964
+ */
965
+ function isString(value) {
966
+ return typeof value === 'string';
967
+ }
968
+ /**
969
+ * Check if value is a number
970
+ */
971
+ function isNumber(value) {
972
+ return typeof value === 'number' && !isNaN(value);
973
+ }
974
+ /**
975
+ * Check if value is a boolean
976
+ */
977
+ function isBoolean(value) {
978
+ return typeof value === 'boolean';
979
+ }
980
+ /**
981
+ * Check if value is a date
982
+ */
983
+ function isDate(value) {
984
+ return value instanceof Date;
985
+ }
986
+ /**
987
+ * Check if value is an array
988
+ */
989
+ function isArray(value) {
990
+ return Array.isArray(value);
991
+ }
992
+ /**
993
+ * Check if value is an object
994
+ */
995
+ function isObject(value) {
996
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
997
+ }
998
+ // ==================== Format Utilities ====================
999
+ /**
1000
+ * Format a number as currency
1001
+ */
1002
+ function formatCurrency(amount, currency = 'USD') {
1003
+ // useGrouping: false so callers can reliably find the raw numeric
1004
+ // substring (e.g. '1234.56') in the output without thousands separators
1005
+ // breaking it up (e.g. '1,234.56').
1006
+ return new Intl.NumberFormat('en-US', {
1007
+ style: 'currency',
1008
+ currency,
1009
+ useGrouping: false,
1010
+ }).format(amount);
1011
+ }
1012
+ /**
1013
+ * Format a number to a fixed number of decimal places.
1014
+ *
1015
+ * Named `format` (not re-exported by './date', see note there) so this is
1016
+ * the canonical `utils.format` for numeric formatting.
1017
+ */
1018
+ function format(value, decimals = 2) {
1019
+ return value.toFixed(decimals);
1020
+ }
1021
+ // Export from string utils
1022
+ __exportStar(require("./string"), exports);
1023
+ // Export from date utils
1024
+ __exportStar(require("./date"), exports);
1025
+ exports.default = {
1026
+ camelToSnake,
1027
+ snakeToCamel,
1028
+ camelToKebab,
1029
+ kebabToCamel,
1030
+ camelize,
1031
+ snakeCase,
1032
+ pluralize,
1033
+ singularize,
1034
+ cloneDeep,
1035
+ merge,
1036
+ pick,
1037
+ omit,
1038
+ generateUUID,
1039
+ generateShortUUID,
1040
+ isValidUUID,
1041
+ formatValues,
1042
+ formatValue,
1043
+ escapeString,
1044
+ escapeId,
1045
+ formatWhere,
1046
+ isEmpty,
1047
+ coalesce,
1048
+ truncate: string_1.truncate,
1049
+ pad: string_1.pad,
1050
+ escapeLike,
1051
+ addTicks,
1052
+ removeTicks,
1053
+ toDefaultValue,
1054
+ formatDefaultValue,
1055
+ spliceStr,
1056
+ unique,
1057
+ flatten,
1058
+ groupBy,
1059
+ sortBy,
1060
+ sum,
1061
+ underscore,
1062
+ includes,
1063
+ startsWith,
1064
+ endsWith,
1065
+ repeat,
1066
+ reverse,
1067
+ clone,
1068
+ get,
1069
+ set,
1070
+ has,
1071
+ isString,
1072
+ isNumber,
1073
+ isBoolean,
1074
+ isDate,
1075
+ isArray,
1076
+ isObject,
1077
+ formatCurrency,
1078
+ formatDateString,
1079
+ };