@cipherstash/stack 0.15.1 → 0.15.3

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.
@@ -113,8 +113,305 @@ function buildEncryptConfig(...protectTables) {
113
113
  return config;
114
114
  }
115
115
 
116
+ // ../../node_modules/.pnpm/evlog@1.9.0/node_modules/evlog/dist/utils.mjs
117
+ function formatDuration(ms) {
118
+ if (ms < 1e3) return `${Math.round(ms)}ms`;
119
+ return `${(ms / 1e3).toFixed(2)}s`;
120
+ }
121
+ function isDev() {
122
+ if (typeof process !== "undefined") return process.env.NODE_ENV !== "production";
123
+ if (typeof window !== "undefined") return true;
124
+ return false;
125
+ }
126
+ function detectEnvironment() {
127
+ const env = typeof process !== "undefined" ? process.env : {};
128
+ const defaultEnvironment = isDev() ? "development" : "production";
129
+ return {
130
+ environment: env.NODE_ENV || defaultEnvironment,
131
+ service: env.SERVICE_NAME || "app",
132
+ version: env.APP_VERSION,
133
+ commitHash: env.COMMIT_SHA || env.GITHUB_SHA || env.VERCEL_GIT_COMMIT_SHA || env.CF_PAGES_COMMIT_SHA,
134
+ region: env.VERCEL_REGION || env.AWS_REGION || env.FLY_REGION || env.CF_REGION
135
+ };
136
+ }
137
+ function getConsoleMethod(level) {
138
+ return level;
139
+ }
140
+ var colors = {
141
+ reset: "\x1B[0m",
142
+ bold: "\x1B[1m",
143
+ dim: "\x1B[2m",
144
+ red: "\x1B[31m",
145
+ green: "\x1B[32m",
146
+ yellow: "\x1B[33m",
147
+ blue: "\x1B[34m",
148
+ magenta: "\x1B[35m",
149
+ cyan: "\x1B[36m",
150
+ white: "\x1B[37m",
151
+ gray: "\x1B[90m"
152
+ };
153
+ function getLevelColor(level) {
154
+ switch (level) {
155
+ case "error":
156
+ return colors.red;
157
+ case "warn":
158
+ return colors.yellow;
159
+ case "info":
160
+ return colors.cyan;
161
+ case "debug":
162
+ return colors.gray;
163
+ default:
164
+ return colors.white;
165
+ }
166
+ }
167
+ function matchesPattern(path, pattern) {
168
+ const regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/{{GLOBSTAR}}/g, ".*").replace(/\?/g, "[^/]");
169
+ return new RegExp(`^${regexPattern}$`).test(path);
170
+ }
171
+
172
+ // ../../node_modules/.pnpm/evlog@1.9.0/node_modules/evlog/dist/logger.mjs
173
+ function isPlainObject(val) {
174
+ return val !== null && typeof val === "object" && !Array.isArray(val);
175
+ }
176
+ function deepDefaults(base, defaults) {
177
+ const result = { ...base };
178
+ for (const key in defaults) {
179
+ const baseVal = result[key];
180
+ const defaultVal = defaults[key];
181
+ if (baseVal === void 0 || baseVal === null) result[key] = defaultVal;
182
+ else if (isPlainObject(baseVal) && isPlainObject(defaultVal)) result[key] = deepDefaults(baseVal, defaultVal);
183
+ }
184
+ return result;
185
+ }
186
+ var globalEnv = {
187
+ service: "app",
188
+ environment: "development"
189
+ };
190
+ var globalPretty = isDev();
191
+ var globalSampling = {};
192
+ var globalStringify = true;
193
+ var globalDrain;
194
+ var globalEnabled = true;
195
+ function initLogger(config = {}) {
196
+ globalEnabled = config.enabled ?? true;
197
+ const detected = detectEnvironment();
198
+ globalEnv = {
199
+ service: config.env?.service ?? detected.service ?? "app",
200
+ environment: config.env?.environment ?? detected.environment ?? "development",
201
+ version: config.env?.version ?? detected.version,
202
+ commitHash: config.env?.commitHash ?? detected.commitHash,
203
+ region: config.env?.region ?? detected.region
204
+ };
205
+ globalPretty = config.pretty ?? isDev();
206
+ globalSampling = config.sampling ?? {};
207
+ globalStringify = config.stringify ?? true;
208
+ globalDrain = config.drain;
209
+ }
210
+ function shouldSample(level) {
211
+ const { rates } = globalSampling;
212
+ if (!rates) return true;
213
+ const percentage = level === "error" && rates.error === void 0 ? 100 : rates[level] ?? 100;
214
+ if (percentage <= 0) return false;
215
+ if (percentage >= 100) return true;
216
+ return Math.random() * 100 < percentage;
217
+ }
218
+ function shouldKeep(ctx) {
219
+ const { keep } = globalSampling;
220
+ if (!keep?.length) return false;
221
+ return keep.some((condition) => {
222
+ if (condition.status !== void 0 && ctx.status !== void 0 && ctx.status >= condition.status) return true;
223
+ if (condition.duration !== void 0 && ctx.duration !== void 0 && ctx.duration >= condition.duration) return true;
224
+ if (condition.path && ctx.path && matchesPattern(ctx.path, condition.path)) return true;
225
+ return false;
226
+ });
227
+ }
228
+ function emitWideEvent(level, event, skipSamplingCheck = false) {
229
+ if (!globalEnabled) return null;
230
+ if (!skipSamplingCheck && !shouldSample(level)) return null;
231
+ const formatted = {
232
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
233
+ level,
234
+ ...globalEnv,
235
+ ...event
236
+ };
237
+ if (globalPretty) prettyPrintWideEvent(formatted);
238
+ else if (globalStringify) console[getConsoleMethod(level)](JSON.stringify(formatted));
239
+ else console[getConsoleMethod(level)](formatted);
240
+ if (globalDrain) Promise.resolve(globalDrain({ event: formatted })).catch((err) => {
241
+ console.error("[evlog] drain failed:", err);
242
+ });
243
+ return formatted;
244
+ }
245
+ function emitTaggedLog(level, tag, message) {
246
+ if (!globalEnabled) return;
247
+ if (globalPretty) {
248
+ if (!shouldSample(level)) return;
249
+ const color = getLevelColor(level);
250
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
251
+ console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`);
252
+ return;
253
+ }
254
+ emitWideEvent(level, {
255
+ tag,
256
+ message
257
+ });
258
+ }
259
+ function formatValue(value) {
260
+ if (value === null || value === void 0) return String(value);
261
+ if (typeof value === "object") {
262
+ const pairs = [];
263
+ for (const [k, v] of Object.entries(value)) if (v !== void 0 && v !== null) if (typeof v === "object") pairs.push(`${k}=${JSON.stringify(v)}`);
264
+ else pairs.push(`${k}=${v}`);
265
+ return pairs.join(" ");
266
+ }
267
+ return String(value);
268
+ }
269
+ function prettyPrintWideEvent(event) {
270
+ const { timestamp, level, service, environment, version, ...rest } = event;
271
+ const levelColor = getLevelColor(level);
272
+ const ts = timestamp.slice(11, 23);
273
+ let header = `${colors.dim}${ts}${colors.reset} ${levelColor}${level.toUpperCase()}${colors.reset}`;
274
+ header += ` ${colors.cyan}[${service}]${colors.reset}`;
275
+ if (rest.method && rest.path) {
276
+ header += ` ${rest.method} ${rest.path}`;
277
+ delete rest.method;
278
+ delete rest.path;
279
+ }
280
+ if (rest.status) {
281
+ const statusColor = rest.status >= 400 ? colors.red : colors.green;
282
+ header += ` ${statusColor}${rest.status}${colors.reset}`;
283
+ delete rest.status;
284
+ }
285
+ if (rest.duration) {
286
+ header += ` ${colors.dim}in ${rest.duration}${colors.reset}`;
287
+ delete rest.duration;
288
+ }
289
+ console.log(header);
290
+ const entries = Object.entries(rest).filter(([_, v]) => v !== void 0);
291
+ const lastIndex = entries.length - 1;
292
+ entries.forEach(([key, value], index) => {
293
+ const prefix = index === lastIndex ? "\u2514\u2500" : "\u251C\u2500";
294
+ const formatted = formatValue(value);
295
+ console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${formatted}`);
296
+ });
297
+ }
298
+ function createLogMethod(level) {
299
+ return function logMethod(tagOrEvent, message) {
300
+ if (typeof tagOrEvent === "string" && message !== void 0) emitTaggedLog(level, tagOrEvent, message);
301
+ else if (typeof tagOrEvent === "object") emitWideEvent(level, tagOrEvent);
302
+ else emitTaggedLog(level, "log", String(tagOrEvent));
303
+ };
304
+ }
305
+ var _log = {
306
+ info: createLogMethod("info"),
307
+ error: createLogMethod("error"),
308
+ warn: createLogMethod("warn"),
309
+ debug: createLogMethod("debug")
310
+ };
311
+ var noopLogger = {
312
+ set() {
313
+ },
314
+ error() {
315
+ },
316
+ info() {
317
+ },
318
+ warn() {
319
+ },
320
+ emit() {
321
+ return null;
322
+ },
323
+ getContext() {
324
+ return {};
325
+ }
326
+ };
327
+ function createRequestLogger(options = {}) {
328
+ if (!globalEnabled) return noopLogger;
329
+ const startTime = Date.now();
330
+ let context = {
331
+ method: options.method,
332
+ path: options.path,
333
+ requestId: options.requestId
334
+ };
335
+ let hasError = false;
336
+ let hasWarn = false;
337
+ function addRequestLog(level, message) {
338
+ const entry = {
339
+ level,
340
+ message,
341
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
342
+ };
343
+ const requestLogs = Array.isArray(context.requestLogs) ? [...context.requestLogs, entry] : [entry];
344
+ context = {
345
+ ...context,
346
+ requestLogs
347
+ };
348
+ }
349
+ return {
350
+ set(data) {
351
+ context = deepDefaults(data, context);
352
+ },
353
+ error(error, errorContext) {
354
+ hasError = true;
355
+ const err = typeof error === "string" ? new Error(error) : error;
356
+ context = deepDefaults({
357
+ ...errorContext,
358
+ error: {
359
+ name: err.name,
360
+ message: err.message,
361
+ stack: err.stack,
362
+ ..."status" in err && { status: err.status },
363
+ ..."statusText" in err && { statusText: err.statusText },
364
+ ..."statusCode" in err && { statusCode: err.statusCode },
365
+ ..."statusMessage" in err && { statusMessage: err.statusMessage },
366
+ ..."data" in err && { data: err.data },
367
+ ..."cause" in err && { cause: err.cause }
368
+ }
369
+ }, context);
370
+ },
371
+ info(message, infoContext) {
372
+ addRequestLog("info", message);
373
+ if (infoContext) {
374
+ const { requestLogs: _, ...rest } = infoContext;
375
+ context = deepDefaults(rest, context);
376
+ }
377
+ },
378
+ warn(message, warnContext) {
379
+ hasWarn = true;
380
+ addRequestLog("warn", message);
381
+ if (warnContext) {
382
+ const { requestLogs: _, ...rest } = warnContext;
383
+ context = deepDefaults(rest, context);
384
+ }
385
+ },
386
+ emit(overrides) {
387
+ const durationMs = Date.now() - startTime;
388
+ const duration = formatDuration(durationMs);
389
+ const level = hasError ? "error" : hasWarn ? "warn" : "info";
390
+ const { _forceKeep, ...restOverrides } = overrides ?? {};
391
+ const tailCtx = {
392
+ status: context.status ?? restOverrides.status,
393
+ duration: durationMs,
394
+ path: context.path,
395
+ method: context.method,
396
+ context: {
397
+ ...context,
398
+ ...restOverrides
399
+ }
400
+ };
401
+ if (!(_forceKeep || shouldKeep(tailCtx)) && !shouldSample(level)) return null;
402
+ return emitWideEvent(level, {
403
+ ...context,
404
+ ...restOverrides,
405
+ duration
406
+ }, true);
407
+ },
408
+ getContext() {
409
+ return { ...context };
410
+ }
411
+ };
412
+ }
413
+
116
414
  // src/utils/logger/index.ts
117
- var import_evlog = require("evlog");
118
415
  var validLevels = ["debug", "info", "error"];
119
416
  function levelFromEnv() {
120
417
  const env = process.env.STASH_STACK_LOG;
@@ -138,7 +435,7 @@ function initStackLogger() {
138
435
  initialized = true;
139
436
  const level = levelFromEnv();
140
437
  const rates = samplingRatesForLevel(level);
141
- (0, import_evlog.initLogger)({
438
+ initLogger({
142
439
  env: { service: "@cipherstash/stack" },
143
440
  enabled: true,
144
441
  sampling: { rates }
@@ -150,7 +447,7 @@ function safeMessage(args) {
150
447
  }
151
448
  var logger = {
152
449
  debug(...args) {
153
- const log = (0, import_evlog.createRequestLogger)();
450
+ const log = createRequestLogger();
154
451
  log.set({
155
452
  level: "debug",
156
453
  source: "@cipherstash/stack",
@@ -159,18 +456,18 @@ var logger = {
159
456
  log.emit();
160
457
  },
161
458
  info(...args) {
162
- const log = (0, import_evlog.createRequestLogger)();
459
+ const log = createRequestLogger();
163
460
  log.set({ source: "@cipherstash/stack" });
164
461
  log.info(safeMessage(args));
165
462
  log.emit();
166
463
  },
167
464
  warn(...args) {
168
- const log = (0, import_evlog.createRequestLogger)();
465
+ const log = createRequestLogger();
169
466
  log.warn(safeMessage(args));
170
467
  log.emit();
171
468
  },
172
469
  error(...args) {
173
- const log = (0, import_evlog.createRequestLogger)();
470
+ const log = createRequestLogger();
174
471
  log.error(safeMessage(args));
175
472
  log.emit();
176
473
  }
@@ -408,7 +705,7 @@ var BatchEncryptQueryOperation = class extends EncryptionOperation {
408
705
  );
409
706
  }
410
707
  async execute() {
411
- const log = (0, import_evlog.createRequestLogger)();
708
+ const log = createRequestLogger();
412
709
  log.set({
413
710
  op: "batchEncryptQuery",
414
711
  count: this.terms.length,
@@ -453,7 +750,7 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
453
750
  this.auditMetadata = auditMetadata;
454
751
  }
455
752
  async execute() {
456
- const log = (0, import_evlog.createRequestLogger)();
753
+ const log = createRequestLogger();
457
754
  log.set({
458
755
  op: "batchEncryptQuery",
459
756
  count: this.terms.length,
@@ -533,7 +830,7 @@ var BulkDecryptOperation = class extends EncryptionOperation {
533
830
  return new BulkDecryptOperationWithLockContext(this, lockContext);
534
831
  }
535
832
  async execute() {
536
- const log = (0, import_evlog.createRequestLogger)();
833
+ const log = createRequestLogger();
537
834
  log.set({
538
835
  op: "bulkDecrypt",
539
836
  count: this.encryptedPayloads?.length ?? 0,
@@ -585,7 +882,7 @@ var BulkDecryptOperationWithLockContext = class extends EncryptionOperation {
585
882
  }
586
883
  async execute() {
587
884
  const { client, encryptedPayloads } = this.operation.getOperation();
588
- const log = (0, import_evlog.createRequestLogger)();
885
+ const log = createRequestLogger();
589
886
  log.set({
590
887
  op: "bulkDecrypt",
591
888
  count: encryptedPayloads?.length ?? 0,
@@ -1156,7 +1453,7 @@ var BulkDecryptModelsOperation = class extends EncryptionOperation {
1156
1453
  return new BulkDecryptModelsOperationWithLockContext(this, lockContext);
1157
1454
  }
1158
1455
  async execute() {
1159
- const log = (0, import_evlog.createRequestLogger)();
1456
+ const log = createRequestLogger();
1160
1457
  log.set({
1161
1458
  op: "bulkDecryptModels",
1162
1459
  count: this.models.length,
@@ -1203,7 +1500,7 @@ var BulkDecryptModelsOperationWithLockContext = class extends EncryptionOperatio
1203
1500
  }
1204
1501
  async execute() {
1205
1502
  const { client, models } = this.operation.getOperation();
1206
- const log = (0, import_evlog.createRequestLogger)();
1503
+ const log = createRequestLogger();
1207
1504
  log.set({
1208
1505
  op: "bulkDecryptModels",
1209
1506
  count: models.length,
@@ -1268,7 +1565,7 @@ var BulkEncryptOperation = class extends EncryptionOperation {
1268
1565
  return new BulkEncryptOperationWithLockContext(this, lockContext);
1269
1566
  }
1270
1567
  async execute() {
1271
- const log = (0, import_evlog.createRequestLogger)();
1568
+ const log = createRequestLogger();
1272
1569
  log.set({
1273
1570
  op: "bulkEncrypt",
1274
1571
  table: this.table.tableName,
@@ -1334,7 +1631,7 @@ var BulkEncryptOperationWithLockContext = class extends EncryptionOperation {
1334
1631
  }
1335
1632
  async execute() {
1336
1633
  const { client, plaintexts, column, table } = this.operation.getOperation();
1337
- const log = (0, import_evlog.createRequestLogger)();
1634
+ const log = createRequestLogger();
1338
1635
  log.set({
1339
1636
  op: "bulkEncrypt",
1340
1637
  table: table.tableName,
@@ -1401,7 +1698,7 @@ var BulkEncryptModelsOperation = class extends EncryptionOperation {
1401
1698
  return new BulkEncryptModelsOperationWithLockContext(this, lockContext);
1402
1699
  }
1403
1700
  async execute() {
1404
- const log = (0, import_evlog.createRequestLogger)();
1701
+ const log = createRequestLogger();
1405
1702
  log.set({
1406
1703
  op: "bulkEncryptModels",
1407
1704
  table: this.table.tableName,
@@ -1455,7 +1752,7 @@ var BulkEncryptModelsOperationWithLockContext = class extends EncryptionOperatio
1455
1752
  }
1456
1753
  async execute() {
1457
1754
  const { client, models, table } = this.operation.getOperation();
1458
- const log = (0, import_evlog.createRequestLogger)();
1755
+ const log = createRequestLogger();
1459
1756
  log.set({
1460
1757
  op: "bulkEncryptModels",
1461
1758
  table: table.tableName,
@@ -1509,7 +1806,7 @@ var DecryptOperation = class extends EncryptionOperation {
1509
1806
  return new DecryptOperationWithLockContext(this, lockContext);
1510
1807
  }
1511
1808
  async execute() {
1512
- const log = (0, import_evlog.createRequestLogger)();
1809
+ const log = createRequestLogger();
1513
1810
  log.set({
1514
1811
  op: "decrypt",
1515
1812
  lockContext: false
@@ -1558,7 +1855,7 @@ var DecryptOperationWithLockContext = class extends EncryptionOperation {
1558
1855
  }
1559
1856
  }
1560
1857
  async execute() {
1561
- const log = (0, import_evlog.createRequestLogger)();
1858
+ const log = createRequestLogger();
1562
1859
  log.set({
1563
1860
  op: "decrypt",
1564
1861
  lockContext: true
@@ -1609,7 +1906,7 @@ var DecryptModelOperation = class extends EncryptionOperation {
1609
1906
  return new DecryptModelOperationWithLockContext(this, lockContext);
1610
1907
  }
1611
1908
  async execute() {
1612
- const log = (0, import_evlog.createRequestLogger)();
1909
+ const log = createRequestLogger();
1613
1910
  log.set({
1614
1911
  op: "decryptModel",
1615
1912
  lockContext: false
@@ -1654,7 +1951,7 @@ var DecryptModelOperationWithLockContext = class extends EncryptionOperation {
1654
1951
  }
1655
1952
  }
1656
1953
  async execute() {
1657
- const log = (0, import_evlog.createRequestLogger)();
1954
+ const log = createRequestLogger();
1658
1955
  log.set({
1659
1956
  op: "decryptModel",
1660
1957
  lockContext: true
@@ -1710,7 +2007,7 @@ var EncryptOperation = class extends EncryptionOperation {
1710
2007
  return new EncryptOperationWithLockContext(this, lockContext);
1711
2008
  }
1712
2009
  async execute() {
1713
- const log = (0, import_evlog.createRequestLogger)();
2010
+ const log = createRequestLogger();
1714
2011
  log.set({
1715
2012
  op: "encrypt",
1716
2013
  table: this.table.tableName,
@@ -1771,7 +2068,7 @@ var EncryptOperationWithLockContext = class extends EncryptionOperation {
1771
2068
  }
1772
2069
  async execute() {
1773
2070
  const { client, plaintext, column, table } = this.operation.getOperation();
1774
- const log = (0, import_evlog.createRequestLogger)();
2071
+ const log = createRequestLogger();
1775
2072
  log.set({
1776
2073
  op: "encrypt",
1777
2074
  table: table.tableName,
@@ -1827,7 +2124,7 @@ var EncryptModelOperation = class extends EncryptionOperation {
1827
2124
  return new EncryptModelOperationWithLockContext(this, lockContext);
1828
2125
  }
1829
2126
  async execute() {
1830
- const log = (0, import_evlog.createRequestLogger)();
2127
+ const log = createRequestLogger();
1831
2128
  log.set({
1832
2129
  op: "encryptModel",
1833
2130
  table: this.table.tableName,
@@ -1880,7 +2177,7 @@ var EncryptModelOperationWithLockContext = class extends EncryptionOperation {
1880
2177
  }
1881
2178
  async execute() {
1882
2179
  const { client, model, table } = this.operation.getOperation();
1883
- const log = (0, import_evlog.createRequestLogger)();
2180
+ const log = createRequestLogger();
1884
2181
  log.set({
1885
2182
  op: "encryptModel",
1886
2183
  table: table.tableName,
@@ -1938,7 +2235,7 @@ var EncryptQueryOperation = class extends EncryptionOperation {
1938
2235
  );
1939
2236
  }
1940
2237
  async execute() {
1941
- const log = (0, import_evlog.createRequestLogger)();
2238
+ const log = createRequestLogger();
1942
2239
  log.set({
1943
2240
  op: "encryptQuery",
1944
2241
  table: this.opts.table.tableName,
@@ -2001,7 +2298,7 @@ var EncryptQueryOperationWithLockContext = class extends EncryptionOperation {
2001
2298
  this.auditMetadata = auditMetadata;
2002
2299
  }
2003
2300
  async execute() {
2004
- const log = (0, import_evlog.createRequestLogger)();
2301
+ const log = createRequestLogger();
2005
2302
  log.set({
2006
2303
  op: "encryptQuery",
2007
2304
  table: this.opts.table.tableName,