@cipherstash/stack 0.18.0 → 1.0.0-rc.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.
- package/CHANGELOG.md +704 -0
- package/README.md +97 -79
- package/dist/adapter-kit.cjs +923 -0
- package/dist/adapter-kit.cjs.map +1 -0
- package/dist/adapter-kit.d.cts +82 -0
- package/dist/adapter-kit.d.ts +82 -0
- package/dist/adapter-kit.js +47 -0
- package/dist/adapter-kit.js.map +1 -0
- package/dist/base-operation-AOAIvsSB.d.cts +32 -0
- package/dist/base-operation-FXEzUXIq.d.ts +32 -0
- package/dist/{chunk-VPOTNP4K.js → chunk-3B5ZX3IS.js} +3 -1
- package/dist/chunk-3B5ZX3IS.js.map +1 -0
- package/dist/chunk-7333ZC6L.js +48 -0
- package/dist/chunk-7333ZC6L.js.map +1 -0
- package/dist/{chunk-XWPGAHBZ.js → chunk-BNO32ZMV.js} +1 -1
- package/dist/chunk-BNO32ZMV.js.map +1 -0
- package/dist/chunk-CLM7E4I6.js +4439 -0
- package/dist/chunk-CLM7E4I6.js.map +1 -0
- package/dist/{chunk-LLCCNKDL.js → chunk-HQANMV7R.js} +3 -3
- package/dist/{chunk-LLCCNKDL.js.map → chunk-HQANMV7R.js.map} +1 -1
- package/dist/chunk-JSG2AMDI.js +17 -0
- package/dist/chunk-JSG2AMDI.js.map +1 -0
- package/dist/chunk-OFQ555AX.js +191 -0
- package/dist/chunk-OFQ555AX.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-V2Q3NYIH.js +494 -0
- package/dist/chunk-V2Q3NYIH.js.map +1 -0
- package/dist/chunk-X3JRXEIB.js +98 -0
- package/dist/chunk-X3JRXEIB.js.map +1 -0
- package/dist/{chunk-ZYOZHZMJ.js → chunk-ZTP5QJ27.js} +193 -169
- package/dist/chunk-ZTP5QJ27.js.map +1 -0
- package/dist/client.cjs +4124 -49
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +6 -5
- package/dist/client.d.ts +6 -5
- package/dist/client.js +3 -1
- package/dist/columns-D2_YzrCX.d.cts +622 -0
- package/dist/columns-rZc7fQHI.d.ts +622 -0
- package/dist/dynamodb/index.cjs +19 -12
- package/dist/dynamodb/index.cjs.map +1 -1
- package/dist/dynamodb/index.d.cts +3 -2
- package/dist/dynamodb/index.d.ts +3 -2
- package/dist/dynamodb/index.js +8 -10
- package/dist/dynamodb/index.js.map +1 -1
- package/dist/encryption/index.cjs +4496 -222
- package/dist/encryption/index.cjs.map +1 -1
- package/dist/encryption/index.d.cts +807 -6
- package/dist/encryption/index.d.ts +807 -6
- package/dist/encryption/index.js +15 -7
- package/dist/encryption/v3.cjs +7896 -0
- package/dist/encryption/v3.cjs.map +1 -0
- package/dist/encryption/v3.d.cts +103 -0
- package/dist/encryption/v3.d.ts +103 -0
- package/dist/encryption/v3.js +189 -0
- package/dist/encryption/v3.js.map +1 -0
- package/dist/eql/v3/index.cjs +663 -0
- package/dist/eql/v3/index.cjs.map +1 -0
- package/dist/eql/v3/index.d.cts +173 -0
- package/dist/eql/v3/index.d.ts +173 -0
- package/dist/eql/v3/index.js +99 -0
- package/dist/eql/v3/index.js.map +1 -0
- package/dist/errors/index.js +1 -0
- package/dist/identity/index.cjs +55 -35
- package/dist/identity/index.cjs.map +1 -1
- package/dist/identity/index.d.cts +54 -30
- package/dist/identity/index.d.ts +54 -30
- package/dist/identity/index.js +9 -177
- package/dist/identity/index.js.map +1 -1
- package/dist/index-BquA71_Y.d.ts +24 -0
- package/dist/index-fhWTOV0K.d.cts +24 -0
- package/dist/index.cjs +4547 -243
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -19
- package/dist/index.d.ts +18 -19
- package/dist/index.js +20 -5
- package/dist/index.js.map +1 -1
- package/dist/schema/index.cjs +4128 -49
- package/dist/schema/index.cjs.map +1 -1
- package/dist/schema/index.d.cts +1 -1
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema/index.js +3 -1
- package/dist/{types-public-BTxqjmtv.d.cts → types-public-QMjYNfQO.d.cts} +448 -251
- package/dist/{types-public-BTxqjmtv.d.ts → types-public-QMjYNfQO.d.ts} +448 -251
- package/dist/types-public.cjs.map +1 -1
- package/dist/types-public.d.cts +2 -2
- package/dist/types-public.d.ts +2 -2
- package/dist/types-public.js +2 -1
- package/dist/wasm-inline.d.ts +1643 -0
- package/dist/wasm-inline.js +4901 -0
- package/dist/wasm-inline.js.map +1 -0
- package/package.json +74 -52
- package/dist/chunk-VPOTNP4K.js.map +0 -1
- package/dist/chunk-XWPGAHBZ.js.map +0 -1
- package/dist/chunk-YWQXTZ5M.js +0 -383
- package/dist/chunk-YWQXTZ5M.js.map +0 -1
- package/dist/chunk-ZYOZHZMJ.js.map +0 -1
- package/dist/client-CIsfZ2zg.d.ts +0 -692
- package/dist/client-Dt98Rugc.d.cts +0 -692
- package/dist/drizzle/index.cjs +0 -1558
- package/dist/drizzle/index.cjs.map +0 -1
- package/dist/drizzle/index.d.cts +0 -358
- package/dist/drizzle/index.d.ts +0 -358
- package/dist/drizzle/index.js +0 -1215
- package/dist/drizzle/index.js.map +0 -1
- package/dist/supabase/index.cjs +0 -1526
- package/dist/supabase/index.cjs.map +0 -1
- package/dist/supabase/index.d.cts +0 -144
- package/dist/supabase/index.d.ts +0 -144
- package/dist/supabase/index.js +0 -899
- package/dist/supabase/index.js.map +0 -1
package/dist/dynamodb/index.cjs
CHANGED
|
@@ -28,7 +28,20 @@ __export(dynamodb_exports, {
|
|
|
28
28
|
});
|
|
29
29
|
module.exports = __toCommonJS(dynamodb_exports);
|
|
30
30
|
|
|
31
|
-
// ../../node_modules/.pnpm
|
|
31
|
+
// ../../node_modules/.pnpm/@byteslice+result@0.2.0/node_modules/@byteslice/result/dist/result.mjs
|
|
32
|
+
function ensureError(ex) {
|
|
33
|
+
return ex instanceof Error ? ex : new Error("Something went wrong");
|
|
34
|
+
}
|
|
35
|
+
async function withResult(operation, onError, hooks) {
|
|
36
|
+
try {
|
|
37
|
+
return { data: await operation() };
|
|
38
|
+
} catch (ex) {
|
|
39
|
+
const error = hooks?.onException?.(ex) ?? ensureError(ex);
|
|
40
|
+
return { failure: onError(error) };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ../../node_modules/.pnpm/evlog@1.11.0_next@15.5.18_react-dom@19.2.3_react@19.2.3__react@19.2.3__react@19.2.3/node_modules/evlog/dist/utils.mjs
|
|
32
45
|
function formatDuration(ms) {
|
|
33
46
|
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
34
47
|
return `${(ms / 1e3).toFixed(2)}s`;
|
|
@@ -84,7 +97,7 @@ function matchesPattern(path, pattern) {
|
|
|
84
97
|
return new RegExp(`^${regexPattern}$`).test(path);
|
|
85
98
|
}
|
|
86
99
|
|
|
87
|
-
// ../../node_modules/.pnpm/evlog@1.11.0_next@15.5.
|
|
100
|
+
// ../../node_modules/.pnpm/evlog@1.11.0_next@15.5.18_react-dom@19.2.3_react@19.2.3__react@19.2.3__react@19.2.3/node_modules/evlog/dist/logger.mjs
|
|
88
101
|
function isPlainObject(val) {
|
|
89
102
|
return val !== null && typeof val === "object" && !Array.isArray(val);
|
|
90
103
|
}
|
|
@@ -388,9 +401,6 @@ var logger = {
|
|
|
388
401
|
}
|
|
389
402
|
};
|
|
390
403
|
|
|
391
|
-
// src/dynamodb/operations/bulk-decrypt-models.ts
|
|
392
|
-
var import_result = require("@byteslice/result");
|
|
393
|
-
|
|
394
404
|
// src/dynamodb/helpers.ts
|
|
395
405
|
var import_protect_ffi = require("@cipherstash/protect-ffi");
|
|
396
406
|
var ciphertextAttrSuffix = "__source";
|
|
@@ -581,7 +591,7 @@ var BulkDecryptModelsOperation = class extends DynamoDBOperation {
|
|
|
581
591
|
}
|
|
582
592
|
async execute() {
|
|
583
593
|
logger.debug(`DynamoDB: bulk decrypting ${this.items.length} models.`);
|
|
584
|
-
return await
|
|
594
|
+
return await withResult(
|
|
585
595
|
async () => {
|
|
586
596
|
const itemsWithEqlPayloads = this.items.map(
|
|
587
597
|
(item) => toItemWithEqlPayloads(item, this.table)
|
|
@@ -603,7 +613,6 @@ var BulkDecryptModelsOperation = class extends DynamoDBOperation {
|
|
|
603
613
|
};
|
|
604
614
|
|
|
605
615
|
// src/dynamodb/operations/bulk-encrypt-models.ts
|
|
606
|
-
var import_result2 = require("@byteslice/result");
|
|
607
616
|
var BulkEncryptModelsOperation = class extends DynamoDBOperation {
|
|
608
617
|
encryptionClient;
|
|
609
618
|
items;
|
|
@@ -616,7 +625,7 @@ var BulkEncryptModelsOperation = class extends DynamoDBOperation {
|
|
|
616
625
|
}
|
|
617
626
|
async execute() {
|
|
618
627
|
logger.debug(`DynamoDB: bulk encrypting ${this.items.length} models.`);
|
|
619
|
-
return await
|
|
628
|
+
return await withResult(
|
|
620
629
|
async () => {
|
|
621
630
|
const encryptResult = await this.encryptionClient.bulkEncryptModels(
|
|
622
631
|
this.items.map((item) => deepClone(item)),
|
|
@@ -642,7 +651,6 @@ var BulkEncryptModelsOperation = class extends DynamoDBOperation {
|
|
|
642
651
|
};
|
|
643
652
|
|
|
644
653
|
// src/dynamodb/operations/decrypt-model.ts
|
|
645
|
-
var import_result3 = require("@byteslice/result");
|
|
646
654
|
var DecryptModelOperation = class extends DynamoDBOperation {
|
|
647
655
|
encryptionClient;
|
|
648
656
|
item;
|
|
@@ -655,7 +663,7 @@ var DecryptModelOperation = class extends DynamoDBOperation {
|
|
|
655
663
|
}
|
|
656
664
|
async execute() {
|
|
657
665
|
logger.debug("DynamoDB: decrypting model.");
|
|
658
|
-
return await
|
|
666
|
+
return await withResult(
|
|
659
667
|
async () => {
|
|
660
668
|
const withEqlPayloads = toItemWithEqlPayloads(this.item, this.table);
|
|
661
669
|
const decryptResult = await this.encryptionClient.decryptModel(withEqlPayloads).audit(this.getAuditData());
|
|
@@ -675,7 +683,6 @@ var DecryptModelOperation = class extends DynamoDBOperation {
|
|
|
675
683
|
};
|
|
676
684
|
|
|
677
685
|
// src/dynamodb/operations/encrypt-model.ts
|
|
678
|
-
var import_result4 = require("@byteslice/result");
|
|
679
686
|
var EncryptModelOperation = class extends DynamoDBOperation {
|
|
680
687
|
encryptionClient;
|
|
681
688
|
item;
|
|
@@ -688,7 +695,7 @@ var EncryptModelOperation = class extends DynamoDBOperation {
|
|
|
688
695
|
}
|
|
689
696
|
async execute() {
|
|
690
697
|
logger.debug("DynamoDB: encrypting model.");
|
|
691
|
-
return await
|
|
698
|
+
return await withResult(
|
|
692
699
|
async () => {
|
|
693
700
|
const encryptResult = await this.encryptionClient.encryptModel(deepClone(this.item), this.table).audit(this.getAuditData());
|
|
694
701
|
if (encryptResult.failure) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/dynamodb/index.ts","../../../../node_modules/.pnpm/evlog@1.11.0_next@15.5.10_react-dom@19.2.3_react@19.2.3__react@19.2.3__react@19.2.3/node_modules/evlog/src/utils.ts","../../../../node_modules/.pnpm/evlog@1.11.0_next@15.5.10_react-dom@19.2.3_react@19.2.3__react@19.2.3__react@19.2.3/node_modules/evlog/src/logger.ts","../../src/utils/logger/index.ts","../../src/dynamodb/operations/bulk-decrypt-models.ts","../../src/dynamodb/helpers.ts","../../src/dynamodb/operations/base-operation.ts","../../src/dynamodb/operations/bulk-encrypt-models.ts","../../src/dynamodb/operations/decrypt-model.ts","../../src/dynamodb/operations/encrypt-model.ts"],"sourcesContent":["import type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { EncryptedValue } from '@/types'\nimport { BulkDecryptModelsOperation } from './operations/bulk-decrypt-models'\nimport { BulkEncryptModelsOperation } from './operations/bulk-encrypt-models'\nimport { DecryptModelOperation } from './operations/decrypt-model'\nimport { EncryptModelOperation } from './operations/encrypt-model'\nimport type {\n EncryptedDynamoDBConfig,\n EncryptedDynamoDBInstance,\n} from './types'\n\n/**\n * Create an encrypted DynamoDB helper bound to an `EncryptionClient`.\n *\n * Returns an object with `encryptModel`, `decryptModel`, `bulkEncryptModels`,\n * and `bulkDecryptModels` methods that transparently encrypt/decrypt DynamoDB\n * items according to the provided table schema.\n *\n * @param config - Configuration containing the `encryptionClient` and optional\n * logging / error-handling callbacks.\n * @returns An {@link EncryptedDynamoDBInstance} with encrypt/decrypt operations.\n *\n * @example\n * ```typescript\n * import { Encryption } from \"@cipherstash/stack\"\n * import { encryptedDynamoDB } from \"@cipherstash/stack/dynamodb\"\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * const client = await Encryption({ schemas: [users] })\n * const dynamo = encryptedDynamoDB({ encryptionClient: client })\n *\n * const encrypted = await dynamo.encryptModel({ email: \"a@b.com\" }, users)\n * ```\n */\nexport function encryptedDynamoDB(\n config: EncryptedDynamoDBConfig,\n): EncryptedDynamoDBInstance {\n const { encryptionClient, options } = config\n\n return {\n encryptModel<T extends Record<string, unknown>>(\n item: T,\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new EncryptModelOperation<T>(\n encryptionClient,\n item,\n table,\n options,\n )\n },\n\n bulkEncryptModels<T extends Record<string, unknown>>(\n items: T[],\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new BulkEncryptModelsOperation<T>(\n encryptionClient,\n items,\n table,\n options,\n )\n },\n\n decryptModel<T extends Record<string, unknown>>(\n item: Record<string, EncryptedValue | unknown>,\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new DecryptModelOperation<T>(\n encryptionClient,\n item,\n table,\n options,\n )\n },\n\n bulkDecryptModels<T extends Record<string, unknown>>(\n items: Record<string, EncryptedValue | unknown>[],\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new BulkDecryptModelsOperation<T>(\n encryptionClient,\n items,\n table,\n options,\n )\n },\n }\n}\n\nexport type {\n EncryptedDynamoDBConfig,\n EncryptedDynamoDBError,\n EncryptedDynamoDBInstance,\n} from './types'\n\n// Re-export the operation classes returned by the DynamoDB instance methods so\n// they are part of the public API and appear in the generated reference.\nexport {\n EncryptModelOperation,\n DecryptModelOperation,\n BulkEncryptModelsOperation,\n BulkDecryptModelsOperation,\n}\n","import type { EnvironmentContext, LogLevel } from './types'\n\nexport function formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${Math.round(ms)}ms`\n }\n return `${(ms / 1000).toFixed(2)}s`\n}\n\nexport function isServer(): boolean {\n return typeof window === 'undefined'\n}\n\nexport function isClient(): boolean {\n return typeof window !== 'undefined'\n}\n\nexport function isDev(): boolean {\n if (typeof process !== 'undefined') {\n return process.env.NODE_ENV !== 'production'\n }\n if (typeof window !== 'undefined') {\n return true\n }\n return false\n}\n\nexport function detectEnvironment(): Partial<EnvironmentContext> {\n const env = typeof process !== 'undefined' ? process.env : {}\n const defaultEnvironment = isDev() ? 'development' : 'production'\n\n return {\n environment: env.NODE_ENV || defaultEnvironment,\n service: env.SERVICE_NAME || 'app',\n version: env.APP_VERSION,\n commitHash: env.COMMIT_SHA\n || env.GITHUB_SHA\n || env.VERCEL_GIT_COMMIT_SHA\n || env.CF_PAGES_COMMIT_SHA,\n region: env.VERCEL_REGION\n || env.AWS_REGION\n || env.FLY_REGION\n || env.CF_REGION,\n }\n}\n\nexport function getConsoleMethod(level: LogLevel): LogLevel {\n return level\n}\n\nexport const colors = {\n reset: '\\x1B[0m',\n bold: '\\x1B[1m',\n dim: '\\x1B[2m',\n red: '\\x1B[31m',\n green: '\\x1B[32m',\n yellow: '\\x1B[33m',\n blue: '\\x1B[34m',\n magenta: '\\x1B[35m',\n cyan: '\\x1B[36m',\n white: '\\x1B[37m',\n gray: '\\x1B[90m',\n} as const\n\nexport function getLevelColor(level: string): string {\n switch (level) {\n case 'error':\n return colors.red\n case 'warn':\n return colors.yellow\n case 'info':\n return colors.cyan\n case 'debug':\n return colors.gray\n default:\n return colors.white\n }\n}\n\n/** Headers that should never be passed to hooks for security */\nexport const SENSITIVE_HEADERS = [\n 'authorization',\n 'cookie',\n 'set-cookie',\n 'x-api-key',\n 'x-auth-token',\n 'proxy-authorization',\n]\n\nexport function filterSafeHeaders(headers: Record<string, string>): Record<string, string> {\n const safeHeaders: Record<string, string> = {}\n\n for (const [key, value] of Object.entries(headers)) {\n if (!SENSITIVE_HEADERS.includes(key.toLowerCase())) {\n safeHeaders[key] = value\n }\n }\n\n return safeHeaders\n}\n\n/**\n * Match a path against a glob pattern.\n * Supports * (any chars except /) and ** (any chars including /).\n */\nexport function matchesPattern(path: string, pattern: string): boolean {\n const regexPattern = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&') // Escape special regex chars except * and ?\n .replace(/\\*\\*/g, '{{GLOBSTAR}}') // Temp placeholder for **\n .replace(/\\*/g, '[^/]*') // * matches anything except /\n .replace(/{{GLOBSTAR}}/g, '.*') // ** matches anything including /\n .replace(/\\?/g, '[^/]') // ? matches single char except /\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(path)\n}\n","import type { DrainContext, EnvironmentContext, FieldContext, Log, LogLevel, LoggerConfig, RequestLogger, RequestLoggerOptions, SamplingConfig, TailSamplingContext, WideEvent } from './types'\nimport { colors, detectEnvironment, formatDuration, getConsoleMethod, getLevelColor, isDev, matchesPattern } from './utils'\n\nfunction isPlainObject(val: unknown): val is Record<string, unknown> {\n return val !== null && typeof val === 'object' && !Array.isArray(val)\n}\n\nfunction deepDefaults(base: Record<string, unknown>, defaults: Record<string, unknown>): Record<string, unknown> {\n const result = { ...base }\n for (const key in defaults) {\n const baseVal = result[key]\n const defaultVal = defaults[key]\n if (baseVal === undefined || baseVal === null) {\n result[key] = defaultVal\n } else if (isPlainObject(baseVal) && isPlainObject(defaultVal)) {\n result[key] = deepDefaults(baseVal, defaultVal)\n }\n }\n return result\n}\n\nlet globalEnv: EnvironmentContext = {\n service: 'app',\n environment: 'development',\n}\n\nlet globalPretty = isDev()\nlet globalSampling: SamplingConfig = {}\nlet globalStringify = true\nlet globalDrain: ((ctx: DrainContext) => void | Promise<void>) | undefined\nlet globalEnabled = true\n\n/**\n * Initialize the logger with configuration.\n * Call this once at application startup.\n */\nexport function initLogger(config: LoggerConfig = {}): void {\n globalEnabled = config.enabled ?? true\n const detected = detectEnvironment()\n\n globalEnv = {\n service: config.env?.service ?? detected.service ?? 'app',\n environment: config.env?.environment ?? detected.environment ?? 'development',\n version: config.env?.version ?? detected.version,\n commitHash: config.env?.commitHash ?? detected.commitHash,\n region: config.env?.region ?? detected.region,\n }\n\n globalPretty = config.pretty ?? isDev()\n globalSampling = config.sampling ?? {}\n globalStringify = config.stringify ?? true\n globalDrain = config.drain\n}\n\n/**\n * Check if logging is globally enabled.\n */\nexport function isEnabled(): boolean {\n return globalEnabled\n}\n\n/**\n * Determine if a log at the given level should be emitted based on sampling config.\n * Error level defaults to 100% (always logged) unless explicitly configured otherwise.\n */\nfunction shouldSample(level: LogLevel): boolean {\n const { rates } = globalSampling\n if (!rates) {\n return true // No sampling configured, log everything\n }\n\n // Error defaults to 100% unless explicitly set\n const percentage = level === 'error' && rates.error === undefined\n ? 100\n : rates[level] ?? 100\n\n // 0% = never log, 100% = always log\n if (percentage <= 0) return false\n if (percentage >= 100) return true\n\n return Math.random() * 100 < percentage\n}\n\n/**\n * Evaluate tail sampling conditions to determine if a log should be force-kept.\n * Returns true if ANY condition matches (OR logic).\n */\nexport function shouldKeep(ctx: TailSamplingContext): boolean {\n const { keep } = globalSampling\n if (!keep?.length) return false\n\n return keep.some((condition) => {\n if (condition.status !== undefined && ctx.status !== undefined && ctx.status >= condition.status) {\n return true\n }\n if (condition.duration !== undefined && ctx.duration !== undefined && ctx.duration >= condition.duration) {\n return true\n }\n if (condition.path && ctx.path && matchesPattern(ctx.path, condition.path)) {\n return true\n }\n return false\n })\n}\n\nfunction emitWideEvent(level: LogLevel, event: Record<string, unknown>, skipSamplingCheck = false): WideEvent | null {\n if (!globalEnabled) return null\n\n if (!skipSamplingCheck && !shouldSample(level)) {\n return null\n }\n\n const formatted: WideEvent = {\n timestamp: new Date().toISOString(),\n level,\n ...globalEnv,\n ...event,\n }\n\n if (globalPretty) {\n prettyPrintWideEvent(formatted)\n } else if (globalStringify) {\n console[getConsoleMethod(level)](JSON.stringify(formatted))\n } else {\n console[getConsoleMethod(level)](formatted)\n }\n\n if (globalDrain) {\n Promise.resolve(globalDrain({ event: formatted })).catch((err) => {\n console.error('[evlog] drain failed:', err)\n })\n }\n\n return formatted\n}\n\nfunction emitTaggedLog(level: LogLevel, tag: string, message: string): void {\n if (!globalEnabled) return\n\n if (globalPretty) {\n if (!shouldSample(level)) {\n return\n }\n const color = getLevelColor(level)\n const timestamp = new Date().toISOString().slice(11, 23)\n console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`)\n return\n }\n emitWideEvent(level, { tag, message })\n}\n\nfunction formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return String(value)\n }\n if (typeof value === 'object') {\n // Flatten object to key=value pairs\n const pairs: string[] = []\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (v !== undefined && v !== null) {\n if (typeof v === 'object') {\n // For nested objects, show as JSON\n pairs.push(`${k}=${JSON.stringify(v)}`)\n } else {\n pairs.push(`${k}=${v}`)\n }\n }\n }\n return pairs.join(' ')\n }\n return String(value)\n}\n\nfunction prettyPrintWideEvent(event: Record<string, unknown>): void {\n const { timestamp, level, service, environment, version, ...rest } = event\n const levelColor = getLevelColor(level as string)\n const ts = (timestamp as string).slice(11, 23)\n\n let header = `${colors.dim}${ts}${colors.reset} ${levelColor}${(level as string).toUpperCase()}${colors.reset}`\n header += ` ${colors.cyan}[${service}]${colors.reset}`\n\n if (rest.method && rest.path) {\n header += ` ${rest.method} ${rest.path}`\n delete rest.method\n delete rest.path\n }\n\n if (rest.status) {\n const statusColor = (rest.status as number) >= 400 ? colors.red : colors.green\n header += ` ${statusColor}${rest.status}${colors.reset}`\n delete rest.status\n }\n\n if (rest.duration) {\n header += ` ${colors.dim}in ${rest.duration}${colors.reset}`\n delete rest.duration\n }\n\n console.log(header)\n\n const entries = Object.entries(rest).filter(([_, v]) => v !== undefined)\n const lastIndex = entries.length - 1\n\n entries.forEach(([key, value], index) => {\n const isLast = index === lastIndex\n const prefix = isLast ? '└─' : '├─'\n const formatted = formatValue(value)\n console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${formatted}`)\n })\n}\n\nfunction createLogMethod(level: LogLevel) {\n return function logMethod(tagOrEvent: string | Record<string, unknown>, message?: string): void {\n if (typeof tagOrEvent === 'string' && message !== undefined) {\n emitTaggedLog(level, tagOrEvent, message)\n } else if (typeof tagOrEvent === 'object') {\n emitWideEvent(level, tagOrEvent)\n } else {\n emitTaggedLog(level, 'log', String(tagOrEvent))\n }\n }\n}\n\n/**\n * Simple logging API - as easy as console.log\n *\n * @example\n * ```ts\n * log.info('auth', 'User logged in')\n * log.error({ action: 'payment', error: 'failed' })\n * ```\n */\nconst _log: Log = {\n info: createLogMethod('info'),\n error: createLogMethod('error'),\n warn: createLogMethod('warn'),\n debug: createLogMethod('debug'),\n}\n\nexport { _log as log }\n\nconst noopLogger: RequestLogger = {\n set() {},\n error() {},\n info() {},\n warn() {},\n emit() {\n return null\n },\n getContext() {\n return {}\n },\n}\n\n/**\n * Create a request-scoped logger for building wide events.\n *\n * @example\n * ```ts\n * const log = createRequestLogger({ method: 'POST', path: '/checkout' })\n * log.set({ user: { id: '123' } })\n * log.set({ cart: { items: 3 } })\n * log.emit()\n * ```\n */\nexport function createRequestLogger<T extends object = Record<string, unknown>>(options: RequestLoggerOptions = {}): RequestLogger<T> {\n if (!globalEnabled) return noopLogger as RequestLogger<T>\n\n const startTime = Date.now()\n let context: Record<string, unknown> = {\n method: options.method,\n path: options.path,\n requestId: options.requestId,\n }\n let hasError = false\n let hasWarn = false\n\n function addRequestLog(level: 'info' | 'warn', message: string): void {\n const entry = {\n level,\n message,\n timestamp: new Date().toISOString(),\n }\n\n const requestLogs = Array.isArray(context.requestLogs)\n ? [...context.requestLogs, entry]\n : [entry]\n\n context = {\n ...context,\n requestLogs,\n }\n }\n\n return {\n set(data: FieldContext<T>): void {\n context = deepDefaults(data as Record<string, unknown>, context) as Record<string, unknown>\n },\n\n error(error: Error | string, errorContext?: FieldContext<T>): void {\n hasError = true\n const err = typeof error === 'string' ? new Error(error) : error\n\n const errorData = {\n ...(errorContext as Record<string, unknown>),\n error: {\n name: err.name,\n message: err.message,\n stack: err.stack,\n ...('status' in err && { status: (err as Record<string, unknown>).status }),\n ...('statusText' in err && { statusText: (err as Record<string, unknown>).statusText }),\n ...('statusCode' in err && { statusCode: (err as Record<string, unknown>).statusCode }),\n ...('statusMessage' in err && { statusMessage: (err as Record<string, unknown>).statusMessage }),\n ...('data' in err && { data: (err as Record<string, unknown>).data }),\n ...('cause' in err && { cause: (err as unknown as Record<string, unknown>).cause }),\n },\n }\n context = deepDefaults(errorData, context) as Record<string, unknown>\n },\n\n info(message: string, infoContext?: FieldContext<T>): void {\n addRequestLog('info', message)\n if (infoContext) {\n const { requestLogs: _, ...rest } = infoContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n warn(message: string, warnContext?: FieldContext<T>): void {\n hasWarn = true\n addRequestLog('warn', message)\n if (warnContext) {\n const { requestLogs: _, ...rest } = warnContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n emit(overrides?: FieldContext<T> & { _forceKeep?: boolean }): WideEvent | null {\n const durationMs = Date.now() - startTime\n const duration = formatDuration(durationMs)\n const level: LogLevel = hasError ? 'error' : hasWarn ? 'warn' : 'info'\n\n // Extract _forceKeep from overrides (set by evlog:emit:keep hook)\n const { _forceKeep, ...restOverrides } = (overrides ?? {}) as Record<string, unknown> & { _forceKeep?: boolean }\n\n // Build tail sampling context\n const tailCtx: TailSamplingContext = {\n status: (context.status ?? restOverrides.status) as number | undefined,\n duration: durationMs,\n path: context.path as string | undefined,\n method: context.method as string | undefined,\n context: { ...context, ...restOverrides },\n }\n\n // Tail sampling: force keep if hook or built-in conditions match\n const forceKeep = _forceKeep || shouldKeep(tailCtx)\n\n // Apply head sampling only if not force-kept\n if (!forceKeep && !shouldSample(level)) {\n return null\n }\n\n return emitWideEvent(level, {\n ...context,\n ...restOverrides,\n duration,\n }, true)\n },\n\n getContext(): FieldContext<T> & Record<string, unknown> {\n return { ...context }\n },\n }\n}\n\n/**\n * Get the current environment context.\n */\nexport function getEnvironment(): EnvironmentContext {\n return { ...globalEnv }\n}\n","import { createRequestLogger, initLogger } from 'evlog'\n\n/**\n * Log level for the Stack logger.\n *\n * Configured via the `STASH_STACK_LOG` environment variable.\n *\n * - `'error'` — Only errors (default when `STASH_STACK_LOG` is not set).\n * - `'info'` — Info and errors.\n * - `'debug'` — Debug, info, and errors.\n */\nexport type LogLevel = 'debug' | 'info' | 'error'\n\nconst validLevels: readonly LogLevel[] = ['debug', 'info', 'error'] as const\n\nfunction levelFromEnv(): LogLevel {\n const env = process.env.STASH_STACK_LOG\n if (env && validLevels.includes(env as LogLevel)) return env as LogLevel\n return 'error'\n}\n\nfunction samplingRatesForLevel(level: LogLevel): Record<string, number> {\n // evlog uses sampling rates: 100 = always emit, 0 = never emit\n switch (level) {\n case 'debug':\n return { debug: 100, info: 100, warn: 100, error: 100 }\n case 'info':\n return { debug: 0, info: 100, warn: 100, error: 100 }\n case 'error':\n default:\n return { debug: 0, info: 0, warn: 0, error: 100 }\n }\n}\n\nlet initialized = false\n\n/**\n * Initialize the Stack logger.\n *\n * The log level is read from the `STASH_STACK_LOG` environment variable.\n * When the variable is not set, the default is `'error'` (errors only).\n *\n * @internal\n */\nexport function initStackLogger(): void {\n if (initialized) return\n initialized = true\n\n const level = levelFromEnv()\n const rates = samplingRatesForLevel(level)\n\n initLogger({\n env: { service: '@cipherstash/stack' },\n enabled: true,\n sampling: { rates },\n })\n}\n\n// Auto-init with defaults on first import\ninitStackLogger()\n\nexport { createRequestLogger }\n\n// Stringify only the first arg (the message string); drop subsequent args\n// which may contain sensitive objects (e.g. encryptConfig, plaintext).\nfunction safeMessage(args: unknown[]): string {\n return typeof args[0] === 'string' ? args[0] : ''\n}\n\n// Logger for simple one-off logs used across Stack interfaces.\nexport const logger = {\n debug(...args: unknown[]) {\n const log = createRequestLogger()\n log.set({\n level: 'debug',\n source: '@cipherstash/stack',\n message: safeMessage(args),\n })\n log.emit()\n },\n info(...args: unknown[]) {\n const log = createRequestLogger()\n log.set({ source: '@cipherstash/stack' })\n log.info(safeMessage(args))\n log.emit()\n },\n warn(...args: unknown[]) {\n const log = createRequestLogger()\n log.warn(safeMessage(args))\n log.emit()\n },\n error(...args: unknown[]) {\n const log = createRequestLogger()\n log.error(safeMessage(args))\n log.emit()\n },\n}\n","import type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { Decrypted, EncryptedValue } from '@/types'\nimport { logger } from '@/utils/logger'\nimport { type Result, withResult } from '@byteslice/result'\nimport { handleError, toItemWithEqlPayloads } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class BulkDecryptModelsOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<Decrypted<T>[]> {\n private encryptionClient: EncryptionClient\n private items: Record<string, EncryptedValue | unknown>[]\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n items: Record<string, EncryptedValue | unknown>[],\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.items = items\n this.table = table\n }\n\n public async execute(): Promise<\n Result<Decrypted<T>[], EncryptedDynamoDBError>\n > {\n logger.debug(`DynamoDB: bulk decrypting ${this.items.length} models.`)\n return await withResult(\n async () => {\n const itemsWithEqlPayloads = this.items.map((item) =>\n toItemWithEqlPayloads(item, this.table),\n )\n\n const decryptResult = await this.encryptionClient\n .bulkDecryptModels<T>(itemsWithEqlPayloads as T[])\n .audit(this.getAuditData())\n\n if (decryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(decryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = decryptResult.failure.code\n throw error\n }\n\n return decryptResult.data\n },\n (error) =>\n handleError(error, 'bulkDecryptModels', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n","import type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { EncryptedValue } from '@/types'\nimport { logger } from '@/utils/logger'\nimport type { ProtectErrorCode } from '@cipherstash/protect-ffi'\nimport { ProtectError as FfiProtectError } from '@cipherstash/protect-ffi'\nimport type { EncryptedDynamoDBError } from './types'\n\nexport const ciphertextAttrSuffix = '__source'\nexport const searchTermAttrSuffix = '__hmac'\n\nexport class EncryptedDynamoDBErrorImpl\n extends Error\n implements EncryptedDynamoDBError\n{\n constructor(\n message: string,\n public code: ProtectErrorCode | 'DYNAMODB_ENCRYPTION_ERROR',\n public details?: Record<string, unknown>,\n ) {\n super(message)\n this.name = 'EncryptedDynamoDBError'\n }\n}\n\nexport function handleError(\n error: unknown,\n context: string,\n options?: {\n logger?: {\n error: (message: string, error: Error) => void\n }\n errorHandler?: (error: EncryptedDynamoDBError) => void\n },\n): EncryptedDynamoDBError {\n // Preserve FFI error code if available, otherwise use generic DynamoDB error code\n // Check for FfiProtectError instance or plain error objects with code property\n const errorObj = error as Record<string, unknown>\n const errorCode =\n error instanceof FfiProtectError\n ? error.code\n : errorObj &&\n typeof errorObj === 'object' &&\n 'code' in errorObj &&\n typeof errorObj.code === 'string'\n ? (errorObj.code as ProtectErrorCode)\n : 'DYNAMODB_ENCRYPTION_ERROR'\n\n const errorMessage =\n error instanceof Error\n ? error.message\n : errorObj && typeof errorObj.message === 'string'\n ? errorObj.message\n : String(error)\n\n const dynamoError = new EncryptedDynamoDBErrorImpl(errorMessage, errorCode, {\n context,\n })\n\n logger.error(`DynamoDB error in ${context}: ${errorMessage}`)\n\n if (options?.errorHandler) {\n options.errorHandler(dynamoError)\n }\n\n if (options?.logger) {\n options.logger.error(`Error in ${context}`, dynamoError)\n }\n\n return dynamoError\n}\n\nexport function deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== 'object') {\n return obj\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => deepClone(item)) as unknown as T\n }\n\n return Object.entries(obj as Record<string, unknown>).reduce(\n (acc, [key, value]) => ({\n // biome-ignore lint/performance/noAccumulatingSpread: TODO later\n ...acc,\n [key]: deepClone(value),\n }),\n {} as T,\n )\n}\n\nexport function toEncryptedDynamoItem(\n encrypted: Record<string, unknown>,\n encryptedAttrs: string[],\n): Record<string, unknown> {\n function processValue(\n attrName: string,\n attrValue: unknown,\n isNested: boolean,\n ): Record<string, unknown> {\n if (attrValue === null || attrValue === undefined) {\n return { [attrName]: attrValue }\n }\n\n // Handle encrypted payload\n if (\n encryptedAttrs.includes(attrName) ||\n (isNested &&\n typeof attrValue === 'object' &&\n 'c' in (attrValue as object))\n ) {\n const encryptPayload = attrValue as EncryptedValue\n if (encryptPayload?.k === 'ct' && encryptPayload.c) {\n const result: Record<string, unknown> = {}\n if (encryptPayload.hm) {\n result[`${attrName}${searchTermAttrSuffix}`] = encryptPayload.hm\n }\n result[`${attrName}${ciphertextAttrSuffix}`] = encryptPayload.c\n return result\n }\n\n if (encryptPayload?.k === 'sv' && encryptPayload.sv) {\n const result: Record<string, unknown> = {}\n result[`${attrName}${ciphertextAttrSuffix}`] = encryptPayload.sv\n return result\n }\n }\n\n // Handle nested objects recursively\n if (typeof attrValue === 'object' && !Array.isArray(attrValue)) {\n const nestedResult = Object.entries(\n attrValue as Record<string, unknown>,\n ).reduce(\n (acc, [key, val]) => {\n const processed = processValue(key, val, true)\n return Object.assign({}, acc, processed)\n },\n {} as Record<string, unknown>,\n )\n return { [attrName]: nestedResult }\n }\n\n // Handle non-encrypted values\n return { [attrName]: attrValue }\n }\n\n return Object.entries(encrypted).reduce(\n (putItem, [attrName, attrValue]) => {\n const processed = processValue(attrName, attrValue, false)\n return Object.assign({}, putItem, processed)\n },\n {} as Record<string, unknown>,\n )\n}\n\nexport function toItemWithEqlPayloads(\n decrypted: Record<string, EncryptedValue | unknown>,\n encryptionSchema: EncryptedTable<EncryptedTableColumn>,\n): Record<string, unknown> {\n function processValue(\n attrName: string,\n attrValue: unknown,\n isNested: boolean,\n ): Record<string, unknown> {\n if (attrValue === null || attrValue === undefined) {\n return { [attrName]: attrValue }\n }\n\n // Skip HMAC fields\n if (attrName.endsWith(searchTermAttrSuffix)) {\n return {}\n }\n\n const encryptConfig = encryptionSchema.build()\n const encryptedAttrs = Object.keys(encryptConfig.columns)\n const columnName = attrName.slice(0, -ciphertextAttrSuffix.length)\n\n // Handle encrypted payload\n if (\n attrName.endsWith(ciphertextAttrSuffix) &&\n (encryptedAttrs.includes(columnName) || isNested)\n ) {\n const i = { c: columnName, t: encryptConfig.tableName }\n const v = 2\n\n // Nested values are not searchable, so we can just return the standard EQL payload.\n // Worth noting, that encryptConfig.columns[columnName] will be undefined if isNested is true.\n if (\n !isNested &&\n encryptConfig.columns[columnName].cast_as === 'json' &&\n encryptConfig.columns[columnName].indexes.ste_vec\n ) {\n return {\n [columnName]: {\n i,\n v,\n k: 'sv',\n sv: attrValue,\n },\n }\n }\n\n return {\n [columnName]: {\n i,\n v,\n k: 'ct',\n c: attrValue,\n },\n }\n }\n\n // Handle nested objects recursively\n if (typeof attrValue === 'object' && !Array.isArray(attrValue)) {\n const nestedResult = Object.entries(\n attrValue as Record<string, unknown>,\n ).reduce(\n (acc, [key, val]) => {\n const processed = processValue(key, val, true)\n return Object.assign({}, acc, processed)\n },\n {} as Record<string, unknown>,\n )\n return { [attrName]: nestedResult }\n }\n\n // Handle non-encrypted values\n return { [attrName]: attrValue }\n }\n\n return Object.entries(decrypted).reduce(\n (formattedItem, [attrName, attrValue]) => {\n const processed = processValue(attrName, attrValue, false)\n return Object.assign({}, formattedItem, processed)\n },\n {} as Record<string, unknown>,\n )\n}\n","import type { Result } from '@byteslice/result'\nimport type { EncryptedDynamoDBError } from '../types'\n\nexport type AuditConfig = {\n metadata?: Record<string, unknown>\n}\n\nexport type AuditData = {\n metadata?: Record<string, unknown>\n}\n\nexport type DynamoDBOperationOptions = {\n logger?: {\n error: (message: string, error: Error) => void\n }\n errorHandler?: (error: EncryptedDynamoDBError) => void\n}\n\nexport abstract class DynamoDBOperation<T> {\n protected auditMetadata?: Record<string, unknown>\n protected logger?: DynamoDBOperationOptions['logger']\n protected errorHandler?: DynamoDBOperationOptions['errorHandler']\n\n constructor(options?: DynamoDBOperationOptions) {\n this.logger = options?.logger\n this.errorHandler = options?.errorHandler\n }\n\n /**\n * Attach audit metadata to this operation. Can be chained.\n */\n audit(config: AuditConfig): this {\n this.auditMetadata = config.metadata\n return this\n }\n\n /**\n * Get the audit metadata for this operation.\n */\n protected getAuditData(): AuditData {\n return {\n metadata: this.auditMetadata,\n }\n }\n\n /**\n * Execute the operation and return a Result\n */\n abstract execute(): Promise<Result<T, EncryptedDynamoDBError>>\n\n /**\n * Make the operation thenable\n */\n public then<TResult1 = Result<T, EncryptedDynamoDBError>, TResult2 = never>(\n onfulfilled?:\n | ((\n value: Result<T, EncryptedDynamoDBError>,\n ) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.execute().then(onfulfilled, onrejected)\n }\n}\n","import type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport { logger } from '@/utils/logger'\nimport { type Result, withResult } from '@byteslice/result'\nimport { deepClone, handleError, toEncryptedDynamoItem } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class BulkEncryptModelsOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<T[]> {\n private encryptionClient: EncryptionClient\n private items: T[]\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n items: T[],\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.items = items\n this.table = table\n }\n\n public async execute(): Promise<Result<T[], EncryptedDynamoDBError>> {\n logger.debug(`DynamoDB: bulk encrypting ${this.items.length} models.`)\n return await withResult(\n async () => {\n const encryptResult = await this.encryptionClient\n .bulkEncryptModels(\n this.items.map((item) => deepClone(item)),\n this.table,\n )\n .audit(this.getAuditData())\n\n if (encryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(encryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = encryptResult.failure.code\n throw error\n }\n\n const data = encryptResult.data.map((item) => deepClone(item))\n const encryptedAttrs = Object.keys(this.table.build().columns)\n\n return data.map(\n (encrypted) => toEncryptedDynamoItem(encrypted, encryptedAttrs) as T,\n )\n },\n (error) =>\n handleError(error, 'bulkEncryptModels', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n","import type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { Decrypted, EncryptedValue } from '@/types'\nimport { logger } from '@/utils/logger'\nimport { type Result, withResult } from '@byteslice/result'\nimport { handleError, toItemWithEqlPayloads } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class DecryptModelOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<Decrypted<T>> {\n private encryptionClient: EncryptionClient\n private item: Record<string, EncryptedValue | unknown>\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n item: Record<string, EncryptedValue | unknown>,\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.item = item\n this.table = table\n }\n\n public async execute(): Promise<\n Result<Decrypted<T>, EncryptedDynamoDBError>\n > {\n logger.debug('DynamoDB: decrypting model.')\n return await withResult(\n async () => {\n const withEqlPayloads = toItemWithEqlPayloads(this.item, this.table)\n\n const decryptResult = await this.encryptionClient\n .decryptModel<T>(withEqlPayloads as T)\n .audit(this.getAuditData())\n\n if (decryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(decryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = decryptResult.failure.code\n throw error\n }\n\n return decryptResult.data\n },\n (error) =>\n handleError(error, 'decryptModel', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n","import type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport { logger } from '@/utils/logger'\nimport { type Result, withResult } from '@byteslice/result'\nimport { deepClone, handleError, toEncryptedDynamoItem } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class EncryptModelOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<T> {\n private encryptionClient: EncryptionClient\n private item: T\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n item: T,\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.item = item\n this.table = table\n }\n\n public async execute(): Promise<Result<T, EncryptedDynamoDBError>> {\n logger.debug('DynamoDB: encrypting model.')\n return await withResult(\n async () => {\n const encryptResult = await this.encryptionClient\n .encryptModel(deepClone(this.item), this.table)\n .audit(this.getAuditData())\n\n if (encryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(encryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = encryptResult.failure.code\n throw error\n }\n\n const data = deepClone(encryptResult.data)\n const encryptedAttrs = Object.keys(this.table.build().columns)\n\n return toEncryptedDynamoItem(data, encryptedAttrs) as T\n },\n (error) =>\n handleError(error, 'encryptModel', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n"],"mappings":"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","names":["FfiProtectError","import_result","import_result","import_result"]}
|
|
1
|
+
{"version":3,"sources":["../../src/dynamodb/index.ts","../../../../node_modules/.pnpm/@byteslice+result@0.2.0/node_modules/@byteslice/result/dist/result.mjs","../../../../node_modules/.pnpm/evlog@1.11.0_next@15.5.18_react-dom@19.2.3_react@19.2.3__react@19.2.3__react@19.2.3/node_modules/evlog/src/utils.ts","../../../../node_modules/.pnpm/evlog@1.11.0_next@15.5.18_react-dom@19.2.3_react@19.2.3__react@19.2.3__react@19.2.3/node_modules/evlog/src/logger.ts","../../src/utils/logger/index.ts","../../src/dynamodb/helpers.ts","../../src/dynamodb/operations/base-operation.ts","../../src/dynamodb/operations/bulk-decrypt-models.ts","../../src/dynamodb/operations/bulk-encrypt-models.ts","../../src/dynamodb/operations/decrypt-model.ts","../../src/dynamodb/operations/encrypt-model.ts"],"sourcesContent":["import type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { EncryptedValue } from '@/types'\nimport { BulkDecryptModelsOperation } from './operations/bulk-decrypt-models'\nimport { BulkEncryptModelsOperation } from './operations/bulk-encrypt-models'\nimport { DecryptModelOperation } from './operations/decrypt-model'\nimport { EncryptModelOperation } from './operations/encrypt-model'\nimport type {\n EncryptedDynamoDBConfig,\n EncryptedDynamoDBInstance,\n} from './types'\n\n/**\n * Create an encrypted DynamoDB helper bound to an `EncryptionClient`.\n *\n * Returns an object with `encryptModel`, `decryptModel`, `bulkEncryptModels`,\n * and `bulkDecryptModels` methods that transparently encrypt/decrypt DynamoDB\n * items according to the provided table schema.\n *\n * @param config - Configuration containing the `encryptionClient` and optional\n * logging / error-handling callbacks.\n * @returns An {@link EncryptedDynamoDBInstance} with encrypt/decrypt operations.\n *\n * @example\n * ```typescript\n * import { Encryption } from \"@cipherstash/stack\"\n * import { encryptedDynamoDB } from \"@cipherstash/stack/dynamodb\"\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * const client = await Encryption({ schemas: [users] })\n * const dynamo = encryptedDynamoDB({ encryptionClient: client })\n *\n * const encrypted = await dynamo.encryptModel({ email: \"a@b.com\" }, users)\n * ```\n */\nexport function encryptedDynamoDB(\n config: EncryptedDynamoDBConfig,\n): EncryptedDynamoDBInstance {\n const { encryptionClient, options } = config\n\n return {\n encryptModel<T extends Record<string, unknown>>(\n item: T,\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new EncryptModelOperation<T>(\n encryptionClient,\n item,\n table,\n options,\n )\n },\n\n bulkEncryptModels<T extends Record<string, unknown>>(\n items: T[],\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new BulkEncryptModelsOperation<T>(\n encryptionClient,\n items,\n table,\n options,\n )\n },\n\n decryptModel<T extends Record<string, unknown>>(\n item: Record<string, EncryptedValue | unknown>,\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new DecryptModelOperation<T>(\n encryptionClient,\n item,\n table,\n options,\n )\n },\n\n bulkDecryptModels<T extends Record<string, unknown>>(\n items: Record<string, EncryptedValue | unknown>[],\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new BulkDecryptModelsOperation<T>(\n encryptionClient,\n items,\n table,\n options,\n )\n },\n }\n}\n\nexport type {\n EncryptedDynamoDBConfig,\n EncryptedDynamoDBError,\n EncryptedDynamoDBInstance,\n} from './types'\n\n// Re-export the operation classes returned by the DynamoDB instance methods so\n// they are part of the public API and appear in the generated reference.\nexport {\n BulkDecryptModelsOperation,\n BulkEncryptModelsOperation,\n DecryptModelOperation,\n EncryptModelOperation,\n}\n","// src/result.ts\nfunction ensureError(ex) {\n return ex instanceof Error ? ex : new Error(\"Something went wrong\");\n}\nasync function withResult(operation, onError, hooks) {\n try {\n return { data: await operation() };\n } catch (ex) {\n const error = hooks?.onException?.(ex) ?? ensureError(ex);\n return { failure: onError(error) };\n }\n}\nexport {\n withResult\n};\n","import type { EnvironmentContext, LogLevel } from './types'\n\nexport function formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${Math.round(ms)}ms`\n }\n return `${(ms / 1000).toFixed(2)}s`\n}\n\nexport function isServer(): boolean {\n return typeof window === 'undefined'\n}\n\nexport function isClient(): boolean {\n return typeof window !== 'undefined'\n}\n\nexport function isDev(): boolean {\n if (typeof process !== 'undefined') {\n return process.env.NODE_ENV !== 'production'\n }\n if (typeof window !== 'undefined') {\n return true\n }\n return false\n}\n\nexport function detectEnvironment(): Partial<EnvironmentContext> {\n const env = typeof process !== 'undefined' ? process.env : {}\n const defaultEnvironment = isDev() ? 'development' : 'production'\n\n return {\n environment: env.NODE_ENV || defaultEnvironment,\n service: env.SERVICE_NAME || 'app',\n version: env.APP_VERSION,\n commitHash: env.COMMIT_SHA\n || env.GITHUB_SHA\n || env.VERCEL_GIT_COMMIT_SHA\n || env.CF_PAGES_COMMIT_SHA,\n region: env.VERCEL_REGION\n || env.AWS_REGION\n || env.FLY_REGION\n || env.CF_REGION,\n }\n}\n\nexport function getConsoleMethod(level: LogLevel): LogLevel {\n return level\n}\n\nexport const colors = {\n reset: '\\x1B[0m',\n bold: '\\x1B[1m',\n dim: '\\x1B[2m',\n red: '\\x1B[31m',\n green: '\\x1B[32m',\n yellow: '\\x1B[33m',\n blue: '\\x1B[34m',\n magenta: '\\x1B[35m',\n cyan: '\\x1B[36m',\n white: '\\x1B[37m',\n gray: '\\x1B[90m',\n} as const\n\nexport function getLevelColor(level: string): string {\n switch (level) {\n case 'error':\n return colors.red\n case 'warn':\n return colors.yellow\n case 'info':\n return colors.cyan\n case 'debug':\n return colors.gray\n default:\n return colors.white\n }\n}\n\n/** Headers that should never be passed to hooks for security */\nexport const SENSITIVE_HEADERS = [\n 'authorization',\n 'cookie',\n 'set-cookie',\n 'x-api-key',\n 'x-auth-token',\n 'proxy-authorization',\n]\n\nexport function filterSafeHeaders(headers: Record<string, string>): Record<string, string> {\n const safeHeaders: Record<string, string> = {}\n\n for (const [key, value] of Object.entries(headers)) {\n if (!SENSITIVE_HEADERS.includes(key.toLowerCase())) {\n safeHeaders[key] = value\n }\n }\n\n return safeHeaders\n}\n\n/**\n * Match a path against a glob pattern.\n * Supports * (any chars except /) and ** (any chars including /).\n */\nexport function matchesPattern(path: string, pattern: string): boolean {\n const regexPattern = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&') // Escape special regex chars except * and ?\n .replace(/\\*\\*/g, '{{GLOBSTAR}}') // Temp placeholder for **\n .replace(/\\*/g, '[^/]*') // * matches anything except /\n .replace(/{{GLOBSTAR}}/g, '.*') // ** matches anything including /\n .replace(/\\?/g, '[^/]') // ? matches single char except /\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(path)\n}\n","import type { DrainContext, EnvironmentContext, FieldContext, Log, LogLevel, LoggerConfig, RequestLogger, RequestLoggerOptions, SamplingConfig, TailSamplingContext, WideEvent } from './types'\nimport { colors, detectEnvironment, formatDuration, getConsoleMethod, getLevelColor, isDev, matchesPattern } from './utils'\n\nfunction isPlainObject(val: unknown): val is Record<string, unknown> {\n return val !== null && typeof val === 'object' && !Array.isArray(val)\n}\n\nfunction deepDefaults(base: Record<string, unknown>, defaults: Record<string, unknown>): Record<string, unknown> {\n const result = { ...base }\n for (const key in defaults) {\n const baseVal = result[key]\n const defaultVal = defaults[key]\n if (baseVal === undefined || baseVal === null) {\n result[key] = defaultVal\n } else if (isPlainObject(baseVal) && isPlainObject(defaultVal)) {\n result[key] = deepDefaults(baseVal, defaultVal)\n }\n }\n return result\n}\n\nlet globalEnv: EnvironmentContext = {\n service: 'app',\n environment: 'development',\n}\n\nlet globalPretty = isDev()\nlet globalSampling: SamplingConfig = {}\nlet globalStringify = true\nlet globalDrain: ((ctx: DrainContext) => void | Promise<void>) | undefined\nlet globalEnabled = true\n\n/**\n * Initialize the logger with configuration.\n * Call this once at application startup.\n */\nexport function initLogger(config: LoggerConfig = {}): void {\n globalEnabled = config.enabled ?? true\n const detected = detectEnvironment()\n\n globalEnv = {\n service: config.env?.service ?? detected.service ?? 'app',\n environment: config.env?.environment ?? detected.environment ?? 'development',\n version: config.env?.version ?? detected.version,\n commitHash: config.env?.commitHash ?? detected.commitHash,\n region: config.env?.region ?? detected.region,\n }\n\n globalPretty = config.pretty ?? isDev()\n globalSampling = config.sampling ?? {}\n globalStringify = config.stringify ?? true\n globalDrain = config.drain\n}\n\n/**\n * Check if logging is globally enabled.\n */\nexport function isEnabled(): boolean {\n return globalEnabled\n}\n\n/**\n * Determine if a log at the given level should be emitted based on sampling config.\n * Error level defaults to 100% (always logged) unless explicitly configured otherwise.\n */\nfunction shouldSample(level: LogLevel): boolean {\n const { rates } = globalSampling\n if (!rates) {\n return true // No sampling configured, log everything\n }\n\n // Error defaults to 100% unless explicitly set\n const percentage = level === 'error' && rates.error === undefined\n ? 100\n : rates[level] ?? 100\n\n // 0% = never log, 100% = always log\n if (percentage <= 0) return false\n if (percentage >= 100) return true\n\n return Math.random() * 100 < percentage\n}\n\n/**\n * Evaluate tail sampling conditions to determine if a log should be force-kept.\n * Returns true if ANY condition matches (OR logic).\n */\nexport function shouldKeep(ctx: TailSamplingContext): boolean {\n const { keep } = globalSampling\n if (!keep?.length) return false\n\n return keep.some((condition) => {\n if (condition.status !== undefined && ctx.status !== undefined && ctx.status >= condition.status) {\n return true\n }\n if (condition.duration !== undefined && ctx.duration !== undefined && ctx.duration >= condition.duration) {\n return true\n }\n if (condition.path && ctx.path && matchesPattern(ctx.path, condition.path)) {\n return true\n }\n return false\n })\n}\n\nfunction emitWideEvent(level: LogLevel, event: Record<string, unknown>, skipSamplingCheck = false): WideEvent | null {\n if (!globalEnabled) return null\n\n if (!skipSamplingCheck && !shouldSample(level)) {\n return null\n }\n\n const formatted: WideEvent = {\n timestamp: new Date().toISOString(),\n level,\n ...globalEnv,\n ...event,\n }\n\n if (globalPretty) {\n prettyPrintWideEvent(formatted)\n } else if (globalStringify) {\n console[getConsoleMethod(level)](JSON.stringify(formatted))\n } else {\n console[getConsoleMethod(level)](formatted)\n }\n\n if (globalDrain) {\n Promise.resolve(globalDrain({ event: formatted })).catch((err) => {\n console.error('[evlog] drain failed:', err)\n })\n }\n\n return formatted\n}\n\nfunction emitTaggedLog(level: LogLevel, tag: string, message: string): void {\n if (!globalEnabled) return\n\n if (globalPretty) {\n if (!shouldSample(level)) {\n return\n }\n const color = getLevelColor(level)\n const timestamp = new Date().toISOString().slice(11, 23)\n console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`)\n return\n }\n emitWideEvent(level, { tag, message })\n}\n\nfunction formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return String(value)\n }\n if (typeof value === 'object') {\n // Flatten object to key=value pairs\n const pairs: string[] = []\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (v !== undefined && v !== null) {\n if (typeof v === 'object') {\n // For nested objects, show as JSON\n pairs.push(`${k}=${JSON.stringify(v)}`)\n } else {\n pairs.push(`${k}=${v}`)\n }\n }\n }\n return pairs.join(' ')\n }\n return String(value)\n}\n\nfunction prettyPrintWideEvent(event: Record<string, unknown>): void {\n const { timestamp, level, service, environment, version, ...rest } = event\n const levelColor = getLevelColor(level as string)\n const ts = (timestamp as string).slice(11, 23)\n\n let header = `${colors.dim}${ts}${colors.reset} ${levelColor}${(level as string).toUpperCase()}${colors.reset}`\n header += ` ${colors.cyan}[${service}]${colors.reset}`\n\n if (rest.method && rest.path) {\n header += ` ${rest.method} ${rest.path}`\n delete rest.method\n delete rest.path\n }\n\n if (rest.status) {\n const statusColor = (rest.status as number) >= 400 ? colors.red : colors.green\n header += ` ${statusColor}${rest.status}${colors.reset}`\n delete rest.status\n }\n\n if (rest.duration) {\n header += ` ${colors.dim}in ${rest.duration}${colors.reset}`\n delete rest.duration\n }\n\n console.log(header)\n\n const entries = Object.entries(rest).filter(([_, v]) => v !== undefined)\n const lastIndex = entries.length - 1\n\n entries.forEach(([key, value], index) => {\n const isLast = index === lastIndex\n const prefix = isLast ? '└─' : '├─'\n const formatted = formatValue(value)\n console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${formatted}`)\n })\n}\n\nfunction createLogMethod(level: LogLevel) {\n return function logMethod(tagOrEvent: string | Record<string, unknown>, message?: string): void {\n if (typeof tagOrEvent === 'string' && message !== undefined) {\n emitTaggedLog(level, tagOrEvent, message)\n } else if (typeof tagOrEvent === 'object') {\n emitWideEvent(level, tagOrEvent)\n } else {\n emitTaggedLog(level, 'log', String(tagOrEvent))\n }\n }\n}\n\n/**\n * Simple logging API - as easy as console.log\n *\n * @example\n * ```ts\n * log.info('auth', 'User logged in')\n * log.error({ action: 'payment', error: 'failed' })\n * ```\n */\nconst _log: Log = {\n info: createLogMethod('info'),\n error: createLogMethod('error'),\n warn: createLogMethod('warn'),\n debug: createLogMethod('debug'),\n}\n\nexport { _log as log }\n\nconst noopLogger: RequestLogger = {\n set() {},\n error() {},\n info() {},\n warn() {},\n emit() {\n return null\n },\n getContext() {\n return {}\n },\n}\n\n/**\n * Create a request-scoped logger for building wide events.\n *\n * @example\n * ```ts\n * const log = createRequestLogger({ method: 'POST', path: '/checkout' })\n * log.set({ user: { id: '123' } })\n * log.set({ cart: { items: 3 } })\n * log.emit()\n * ```\n */\nexport function createRequestLogger<T extends object = Record<string, unknown>>(options: RequestLoggerOptions = {}): RequestLogger<T> {\n if (!globalEnabled) return noopLogger as RequestLogger<T>\n\n const startTime = Date.now()\n let context: Record<string, unknown> = {\n method: options.method,\n path: options.path,\n requestId: options.requestId,\n }\n let hasError = false\n let hasWarn = false\n\n function addRequestLog(level: 'info' | 'warn', message: string): void {\n const entry = {\n level,\n message,\n timestamp: new Date().toISOString(),\n }\n\n const requestLogs = Array.isArray(context.requestLogs)\n ? [...context.requestLogs, entry]\n : [entry]\n\n context = {\n ...context,\n requestLogs,\n }\n }\n\n return {\n set(data: FieldContext<T>): void {\n context = deepDefaults(data as Record<string, unknown>, context) as Record<string, unknown>\n },\n\n error(error: Error | string, errorContext?: FieldContext<T>): void {\n hasError = true\n const err = typeof error === 'string' ? new Error(error) : error\n\n const errorData = {\n ...(errorContext as Record<string, unknown>),\n error: {\n name: err.name,\n message: err.message,\n stack: err.stack,\n ...('status' in err && { status: (err as Record<string, unknown>).status }),\n ...('statusText' in err && { statusText: (err as Record<string, unknown>).statusText }),\n ...('statusCode' in err && { statusCode: (err as Record<string, unknown>).statusCode }),\n ...('statusMessage' in err && { statusMessage: (err as Record<string, unknown>).statusMessage }),\n ...('data' in err && { data: (err as Record<string, unknown>).data }),\n ...('cause' in err && { cause: (err as unknown as Record<string, unknown>).cause }),\n },\n }\n context = deepDefaults(errorData, context) as Record<string, unknown>\n },\n\n info(message: string, infoContext?: FieldContext<T>): void {\n addRequestLog('info', message)\n if (infoContext) {\n const { requestLogs: _, ...rest } = infoContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n warn(message: string, warnContext?: FieldContext<T>): void {\n hasWarn = true\n addRequestLog('warn', message)\n if (warnContext) {\n const { requestLogs: _, ...rest } = warnContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n emit(overrides?: FieldContext<T> & { _forceKeep?: boolean }): WideEvent | null {\n const durationMs = Date.now() - startTime\n const duration = formatDuration(durationMs)\n const level: LogLevel = hasError ? 'error' : hasWarn ? 'warn' : 'info'\n\n // Extract _forceKeep from overrides (set by evlog:emit:keep hook)\n const { _forceKeep, ...restOverrides } = (overrides ?? {}) as Record<string, unknown> & { _forceKeep?: boolean }\n\n // Build tail sampling context\n const tailCtx: TailSamplingContext = {\n status: (context.status ?? restOverrides.status) as number | undefined,\n duration: durationMs,\n path: context.path as string | undefined,\n method: context.method as string | undefined,\n context: { ...context, ...restOverrides },\n }\n\n // Tail sampling: force keep if hook or built-in conditions match\n const forceKeep = _forceKeep || shouldKeep(tailCtx)\n\n // Apply head sampling only if not force-kept\n if (!forceKeep && !shouldSample(level)) {\n return null\n }\n\n return emitWideEvent(level, {\n ...context,\n ...restOverrides,\n duration,\n }, true)\n },\n\n getContext(): FieldContext<T> & Record<string, unknown> {\n return { ...context }\n },\n }\n}\n\n/**\n * Get the current environment context.\n */\nexport function getEnvironment(): EnvironmentContext {\n return { ...globalEnv }\n}\n","import { createRequestLogger, initLogger } from 'evlog'\n\n/**\n * Log level for the Stack logger.\n *\n * Configured via the `STASH_STACK_LOG` environment variable.\n *\n * - `'error'` — Only errors (default when `STASH_STACK_LOG` is not set).\n * - `'info'` — Info and errors.\n * - `'debug'` — Debug, info, and errors.\n */\nexport type LogLevel = 'debug' | 'info' | 'error'\n\nconst validLevels: readonly LogLevel[] = ['debug', 'info', 'error'] as const\n\nfunction levelFromEnv(): LogLevel {\n const env = process.env.STASH_STACK_LOG\n if (env && validLevels.includes(env as LogLevel)) return env as LogLevel\n return 'error'\n}\n\nfunction samplingRatesForLevel(level: LogLevel): Record<string, number> {\n // evlog uses sampling rates: 100 = always emit, 0 = never emit\n switch (level) {\n case 'debug':\n return { debug: 100, info: 100, warn: 100, error: 100 }\n case 'info':\n return { debug: 0, info: 100, warn: 100, error: 100 }\n case 'error':\n default:\n return { debug: 0, info: 0, warn: 0, error: 100 }\n }\n}\n\nlet initialized = false\n\n/**\n * Initialize the Stack logger.\n *\n * The log level is read from the `STASH_STACK_LOG` environment variable.\n * When the variable is not set, the default is `'error'` (errors only).\n *\n * @internal\n */\nexport function initStackLogger(): void {\n if (initialized) return\n initialized = true\n\n const level = levelFromEnv()\n const rates = samplingRatesForLevel(level)\n\n initLogger({\n env: { service: '@cipherstash/stack' },\n enabled: true,\n sampling: { rates },\n })\n}\n\n// Auto-init with defaults on first import\ninitStackLogger()\n\nexport { createRequestLogger }\n\n// Stringify only the first arg (the message string); drop subsequent args\n// which may contain sensitive objects (e.g. encryptConfig, plaintext).\nfunction safeMessage(args: unknown[]): string {\n return typeof args[0] === 'string' ? args[0] : ''\n}\n\n// Logger for simple one-off logs used across Stack interfaces.\nexport const logger = {\n debug(...args: unknown[]) {\n const log = createRequestLogger()\n log.set({\n level: 'debug',\n source: '@cipherstash/stack',\n message: safeMessage(args),\n })\n log.emit()\n },\n info(...args: unknown[]) {\n const log = createRequestLogger()\n log.set({ source: '@cipherstash/stack' })\n log.info(safeMessage(args))\n log.emit()\n },\n warn(...args: unknown[]) {\n const log = createRequestLogger()\n log.warn(safeMessage(args))\n log.emit()\n },\n error(...args: unknown[]) {\n const log = createRequestLogger()\n log.error(safeMessage(args))\n log.emit()\n },\n}\n","import type { ProtectErrorCode } from '@cipherstash/protect-ffi'\nimport { ProtectError as FfiProtectError } from '@cipherstash/protect-ffi'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { EncryptedValue } from '@/types'\nimport { logger } from '@/utils/logger'\nimport type { EncryptedDynamoDBError } from './types'\n\nexport const ciphertextAttrSuffix = '__source'\nexport const searchTermAttrSuffix = '__hmac'\n\nexport class EncryptedDynamoDBErrorImpl\n extends Error\n implements EncryptedDynamoDBError\n{\n constructor(\n message: string,\n public code: ProtectErrorCode | 'DYNAMODB_ENCRYPTION_ERROR',\n public details?: Record<string, unknown>,\n ) {\n super(message)\n this.name = 'EncryptedDynamoDBError'\n }\n}\n\nexport function handleError(\n error: unknown,\n context: string,\n options?: {\n logger?: {\n error: (message: string, error: Error) => void\n }\n errorHandler?: (error: EncryptedDynamoDBError) => void\n },\n): EncryptedDynamoDBError {\n // Preserve FFI error code if available, otherwise use generic DynamoDB error code\n // Check for FfiProtectError instance or plain error objects with code property\n const errorObj = error as Record<string, unknown>\n const errorCode =\n error instanceof FfiProtectError\n ? error.code\n : errorObj &&\n typeof errorObj === 'object' &&\n 'code' in errorObj &&\n typeof errorObj.code === 'string'\n ? (errorObj.code as ProtectErrorCode)\n : 'DYNAMODB_ENCRYPTION_ERROR'\n\n const errorMessage =\n error instanceof Error\n ? error.message\n : errorObj && typeof errorObj.message === 'string'\n ? errorObj.message\n : String(error)\n\n const dynamoError = new EncryptedDynamoDBErrorImpl(errorMessage, errorCode, {\n context,\n })\n\n logger.error(`DynamoDB error in ${context}: ${errorMessage}`)\n\n if (options?.errorHandler) {\n options.errorHandler(dynamoError)\n }\n\n if (options?.logger) {\n options.logger.error(`Error in ${context}`, dynamoError)\n }\n\n return dynamoError\n}\n\nexport function deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== 'object') {\n return obj\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => deepClone(item)) as unknown as T\n }\n\n return Object.entries(obj as Record<string, unknown>).reduce(\n (acc, [key, value]) => ({\n // biome-ignore lint/performance/noAccumulatingSpread: TODO later\n ...acc,\n [key]: deepClone(value),\n }),\n {} as T,\n )\n}\n\nexport function toEncryptedDynamoItem(\n encrypted: Record<string, unknown>,\n encryptedAttrs: string[],\n): Record<string, unknown> {\n function processValue(\n attrName: string,\n attrValue: unknown,\n isNested: boolean,\n ): Record<string, unknown> {\n if (attrValue === null || attrValue === undefined) {\n return { [attrName]: attrValue }\n }\n\n // Handle encrypted payload\n if (\n encryptedAttrs.includes(attrName) ||\n (isNested &&\n typeof attrValue === 'object' &&\n 'c' in (attrValue as object))\n ) {\n const encryptPayload = attrValue as EncryptedValue\n if (encryptPayload?.k === 'ct' && encryptPayload.c) {\n const result: Record<string, unknown> = {}\n if (encryptPayload.hm) {\n result[`${attrName}${searchTermAttrSuffix}`] = encryptPayload.hm\n }\n result[`${attrName}${ciphertextAttrSuffix}`] = encryptPayload.c\n return result\n }\n\n if (encryptPayload?.k === 'sv' && encryptPayload.sv) {\n const result: Record<string, unknown> = {}\n result[`${attrName}${ciphertextAttrSuffix}`] = encryptPayload.sv\n return result\n }\n }\n\n // Handle nested objects recursively\n if (typeof attrValue === 'object' && !Array.isArray(attrValue)) {\n const nestedResult = Object.entries(\n attrValue as Record<string, unknown>,\n ).reduce(\n (acc, [key, val]) => {\n const processed = processValue(key, val, true)\n return Object.assign({}, acc, processed)\n },\n {} as Record<string, unknown>,\n )\n return { [attrName]: nestedResult }\n }\n\n // Handle non-encrypted values\n return { [attrName]: attrValue }\n }\n\n return Object.entries(encrypted).reduce(\n (putItem, [attrName, attrValue]) => {\n const processed = processValue(attrName, attrValue, false)\n return Object.assign({}, putItem, processed)\n },\n {} as Record<string, unknown>,\n )\n}\n\nexport function toItemWithEqlPayloads(\n decrypted: Record<string, EncryptedValue | unknown>,\n encryptionSchema: EncryptedTable<EncryptedTableColumn>,\n): Record<string, unknown> {\n function processValue(\n attrName: string,\n attrValue: unknown,\n isNested: boolean,\n ): Record<string, unknown> {\n if (attrValue === null || attrValue === undefined) {\n return { [attrName]: attrValue }\n }\n\n // Skip HMAC fields\n if (attrName.endsWith(searchTermAttrSuffix)) {\n return {}\n }\n\n const encryptConfig = encryptionSchema.build()\n const encryptedAttrs = Object.keys(encryptConfig.columns)\n const columnName = attrName.slice(0, -ciphertextAttrSuffix.length)\n\n // Handle encrypted payload\n if (\n attrName.endsWith(ciphertextAttrSuffix) &&\n (encryptedAttrs.includes(columnName) || isNested)\n ) {\n const i = { c: columnName, t: encryptConfig.tableName }\n const v = 2\n\n // Nested values are not searchable, so we can just return the standard EQL payload.\n // Worth noting, that encryptConfig.columns[columnName] will be undefined if isNested is true.\n if (\n !isNested &&\n encryptConfig.columns[columnName].cast_as === 'json' &&\n encryptConfig.columns[columnName].indexes.ste_vec\n ) {\n return {\n [columnName]: {\n i,\n v,\n k: 'sv',\n sv: attrValue,\n },\n }\n }\n\n return {\n [columnName]: {\n i,\n v,\n k: 'ct',\n c: attrValue,\n },\n }\n }\n\n // Handle nested objects recursively\n if (typeof attrValue === 'object' && !Array.isArray(attrValue)) {\n const nestedResult = Object.entries(\n attrValue as Record<string, unknown>,\n ).reduce(\n (acc, [key, val]) => {\n const processed = processValue(key, val, true)\n return Object.assign({}, acc, processed)\n },\n {} as Record<string, unknown>,\n )\n return { [attrName]: nestedResult }\n }\n\n // Handle non-encrypted values\n return { [attrName]: attrValue }\n }\n\n return Object.entries(decrypted).reduce(\n (formattedItem, [attrName, attrValue]) => {\n const processed = processValue(attrName, attrValue, false)\n return Object.assign({}, formattedItem, processed)\n },\n {} as Record<string, unknown>,\n )\n}\n","import type { Result } from '@byteslice/result'\nimport type { EncryptedDynamoDBError } from '../types'\n\nexport type AuditConfig = {\n metadata?: Record<string, unknown>\n}\n\nexport type AuditData = {\n metadata?: Record<string, unknown>\n}\n\nexport type DynamoDBOperationOptions = {\n logger?: {\n error: (message: string, error: Error) => void\n }\n errorHandler?: (error: EncryptedDynamoDBError) => void\n}\n\nexport abstract class DynamoDBOperation<T> {\n protected auditMetadata?: Record<string, unknown>\n protected logger?: DynamoDBOperationOptions['logger']\n protected errorHandler?: DynamoDBOperationOptions['errorHandler']\n\n constructor(options?: DynamoDBOperationOptions) {\n this.logger = options?.logger\n this.errorHandler = options?.errorHandler\n }\n\n /**\n * Attach audit metadata to this operation. Can be chained.\n */\n audit(config: AuditConfig): this {\n this.auditMetadata = config.metadata\n return this\n }\n\n /**\n * Get the audit metadata for this operation.\n */\n protected getAuditData(): AuditData {\n return {\n metadata: this.auditMetadata,\n }\n }\n\n /**\n * Execute the operation and return a Result\n */\n abstract execute(): Promise<Result<T, EncryptedDynamoDBError>>\n\n /**\n * Make the operation thenable\n */\n public then<TResult1 = Result<T, EncryptedDynamoDBError>, TResult2 = never>(\n onfulfilled?:\n | ((\n value: Result<T, EncryptedDynamoDBError>,\n ) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.execute().then(onfulfilled, onrejected)\n }\n}\n","import { type Result, withResult } from '@byteslice/result'\nimport type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { Decrypted, EncryptedValue } from '@/types'\nimport { logger } from '@/utils/logger'\nimport { handleError, toItemWithEqlPayloads } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class BulkDecryptModelsOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<Decrypted<T>[]> {\n private encryptionClient: EncryptionClient\n private items: Record<string, EncryptedValue | unknown>[]\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n items: Record<string, EncryptedValue | unknown>[],\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.items = items\n this.table = table\n }\n\n public async execute(): Promise<\n Result<Decrypted<T>[], EncryptedDynamoDBError>\n > {\n logger.debug(`DynamoDB: bulk decrypting ${this.items.length} models.`)\n return await withResult(\n async () => {\n const itemsWithEqlPayloads = this.items.map((item) =>\n toItemWithEqlPayloads(item, this.table),\n )\n\n const decryptResult = await this.encryptionClient\n .bulkDecryptModels<T>(itemsWithEqlPayloads as T[])\n .audit(this.getAuditData())\n\n if (decryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(decryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = decryptResult.failure.code\n throw error\n }\n\n return decryptResult.data\n },\n (error) =>\n handleError(error, 'bulkDecryptModels', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n","import { type Result, withResult } from '@byteslice/result'\nimport type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport { logger } from '@/utils/logger'\nimport { deepClone, handleError, toEncryptedDynamoItem } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class BulkEncryptModelsOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<T[]> {\n private encryptionClient: EncryptionClient\n private items: T[]\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n items: T[],\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.items = items\n this.table = table\n }\n\n public async execute(): Promise<Result<T[], EncryptedDynamoDBError>> {\n logger.debug(`DynamoDB: bulk encrypting ${this.items.length} models.`)\n return await withResult(\n async () => {\n const encryptResult = await this.encryptionClient\n .bulkEncryptModels(\n this.items.map((item) => deepClone(item)),\n this.table,\n )\n .audit(this.getAuditData())\n\n if (encryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(encryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = encryptResult.failure.code\n throw error\n }\n\n const data = encryptResult.data.map((item) => deepClone(item))\n const encryptedAttrs = Object.keys(this.table.build().columns)\n\n return data.map(\n (encrypted) => toEncryptedDynamoItem(encrypted, encryptedAttrs) as T,\n )\n },\n (error) =>\n handleError(error, 'bulkEncryptModels', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n","import { type Result, withResult } from '@byteslice/result'\nimport type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { Decrypted, EncryptedValue } from '@/types'\nimport { logger } from '@/utils/logger'\nimport { handleError, toItemWithEqlPayloads } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class DecryptModelOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<Decrypted<T>> {\n private encryptionClient: EncryptionClient\n private item: Record<string, EncryptedValue | unknown>\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n item: Record<string, EncryptedValue | unknown>,\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.item = item\n this.table = table\n }\n\n public async execute(): Promise<\n Result<Decrypted<T>, EncryptedDynamoDBError>\n > {\n logger.debug('DynamoDB: decrypting model.')\n return await withResult(\n async () => {\n const withEqlPayloads = toItemWithEqlPayloads(this.item, this.table)\n\n const decryptResult = await this.encryptionClient\n .decryptModel<T>(withEqlPayloads as T)\n .audit(this.getAuditData())\n\n if (decryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(decryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = decryptResult.failure.code\n throw error\n }\n\n return decryptResult.data\n },\n (error) =>\n handleError(error, 'decryptModel', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n","import { type Result, withResult } from '@byteslice/result'\nimport type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport { logger } from '@/utils/logger'\nimport { deepClone, handleError, toEncryptedDynamoItem } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class EncryptModelOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<T> {\n private encryptionClient: EncryptionClient\n private item: T\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n item: T,\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.item = item\n this.table = table\n }\n\n public async execute(): Promise<Result<T, EncryptedDynamoDBError>> {\n logger.debug('DynamoDB: encrypting model.')\n return await withResult(\n async () => {\n const encryptResult = await this.encryptionClient\n .encryptModel(deepClone(this.item), this.table)\n .audit(this.getAuditData())\n\n if (encryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(encryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = encryptResult.failure.code\n throw error\n }\n\n const data = deepClone(encryptResult.data)\n const encryptedAttrs = Object.keys(this.table.build().columns)\n\n return toEncryptedDynamoItem(data, encryptedAttrs) as T\n },\n (error) =>\n handleError(error, 'encryptModel', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n"],"mappings":"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","names":["FfiProtectError"]}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { a as EncryptionClient } from '../client-Dt98Rugc.cjs';
|
|
2
|
-
import { c as EncryptedTable, d as EncryptedTableColumn, D as Decrypted, g as EncryptedValue } from '../types-public-BTxqjmtv.cjs';
|
|
3
1
|
import { Result } from '@byteslice/result';
|
|
2
|
+
import { EncryptionClient } from '../encryption/index.cjs';
|
|
3
|
+
import { z as EncryptedTable, A as EncryptedTableColumn, D as Decrypted, F as EncryptedValue } from '../types-public-QMjYNfQO.cjs';
|
|
4
4
|
import { ProtectErrorCode } from '@cipherstash/protect-ffi';
|
|
5
5
|
import '../errors/index.cjs';
|
|
6
6
|
import '../identity/index.cjs';
|
|
7
|
+
import '../base-operation-AOAIvsSB.cjs';
|
|
7
8
|
import 'zod';
|
|
8
9
|
|
|
9
10
|
type AuditConfig = {
|
package/dist/dynamodb/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { a as EncryptionClient } from '../client-CIsfZ2zg.js';
|
|
2
|
-
import { c as EncryptedTable, d as EncryptedTableColumn, D as Decrypted, g as EncryptedValue } from '../types-public-BTxqjmtv.js';
|
|
3
1
|
import { Result } from '@byteslice/result';
|
|
2
|
+
import { EncryptionClient } from '../encryption/index.js';
|
|
3
|
+
import { z as EncryptedTable, A as EncryptedTableColumn, D as Decrypted, F as EncryptedValue } from '../types-public-QMjYNfQO.js';
|
|
4
4
|
import { ProtectErrorCode } from '@cipherstash/protect-ffi';
|
|
5
5
|
import '../errors/index.js';
|
|
6
6
|
import '../identity/index.js';
|
|
7
|
+
import '../base-operation-FXEzUXIq.js';
|
|
7
8
|
import 'zod';
|
|
8
9
|
|
|
9
10
|
type AuditConfig = {
|
package/dist/dynamodb/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
withResult
|
|
3
|
+
} from "../chunk-JSG2AMDI.js";
|
|
1
4
|
import {
|
|
2
5
|
logger
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
|
|
5
|
-
// src/dynamodb/operations/bulk-decrypt-models.ts
|
|
6
|
-
import { withResult } from "@byteslice/result";
|
|
6
|
+
} from "../chunk-HQANMV7R.js";
|
|
7
|
+
import "../chunk-PZ5AY32C.js";
|
|
7
8
|
|
|
8
9
|
// src/dynamodb/helpers.ts
|
|
9
10
|
import { ProtectError as FfiProtectError } from "@cipherstash/protect-ffi";
|
|
@@ -217,7 +218,6 @@ var BulkDecryptModelsOperation = class extends DynamoDBOperation {
|
|
|
217
218
|
};
|
|
218
219
|
|
|
219
220
|
// src/dynamodb/operations/bulk-encrypt-models.ts
|
|
220
|
-
import { withResult as withResult2 } from "@byteslice/result";
|
|
221
221
|
var BulkEncryptModelsOperation = class extends DynamoDBOperation {
|
|
222
222
|
encryptionClient;
|
|
223
223
|
items;
|
|
@@ -230,7 +230,7 @@ var BulkEncryptModelsOperation = class extends DynamoDBOperation {
|
|
|
230
230
|
}
|
|
231
231
|
async execute() {
|
|
232
232
|
logger.debug(`DynamoDB: bulk encrypting ${this.items.length} models.`);
|
|
233
|
-
return await
|
|
233
|
+
return await withResult(
|
|
234
234
|
async () => {
|
|
235
235
|
const encryptResult = await this.encryptionClient.bulkEncryptModels(
|
|
236
236
|
this.items.map((item) => deepClone(item)),
|
|
@@ -256,7 +256,6 @@ var BulkEncryptModelsOperation = class extends DynamoDBOperation {
|
|
|
256
256
|
};
|
|
257
257
|
|
|
258
258
|
// src/dynamodb/operations/decrypt-model.ts
|
|
259
|
-
import { withResult as withResult3 } from "@byteslice/result";
|
|
260
259
|
var DecryptModelOperation = class extends DynamoDBOperation {
|
|
261
260
|
encryptionClient;
|
|
262
261
|
item;
|
|
@@ -269,7 +268,7 @@ var DecryptModelOperation = class extends DynamoDBOperation {
|
|
|
269
268
|
}
|
|
270
269
|
async execute() {
|
|
271
270
|
logger.debug("DynamoDB: decrypting model.");
|
|
272
|
-
return await
|
|
271
|
+
return await withResult(
|
|
273
272
|
async () => {
|
|
274
273
|
const withEqlPayloads = toItemWithEqlPayloads(this.item, this.table);
|
|
275
274
|
const decryptResult = await this.encryptionClient.decryptModel(withEqlPayloads).audit(this.getAuditData());
|
|
@@ -289,7 +288,6 @@ var DecryptModelOperation = class extends DynamoDBOperation {
|
|
|
289
288
|
};
|
|
290
289
|
|
|
291
290
|
// src/dynamodb/operations/encrypt-model.ts
|
|
292
|
-
import { withResult as withResult4 } from "@byteslice/result";
|
|
293
291
|
var EncryptModelOperation = class extends DynamoDBOperation {
|
|
294
292
|
encryptionClient;
|
|
295
293
|
item;
|
|
@@ -302,7 +300,7 @@ var EncryptModelOperation = class extends DynamoDBOperation {
|
|
|
302
300
|
}
|
|
303
301
|
async execute() {
|
|
304
302
|
logger.debug("DynamoDB: encrypting model.");
|
|
305
|
-
return await
|
|
303
|
+
return await withResult(
|
|
306
304
|
async () => {
|
|
307
305
|
const encryptResult = await this.encryptionClient.encryptModel(deepClone(this.item), this.table).audit(this.getAuditData());
|
|
308
306
|
if (encryptResult.failure) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/dynamodb/operations/bulk-decrypt-models.ts","../../src/dynamodb/helpers.ts","../../src/dynamodb/operations/base-operation.ts","../../src/dynamodb/operations/bulk-encrypt-models.ts","../../src/dynamodb/operations/decrypt-model.ts","../../src/dynamodb/operations/encrypt-model.ts","../../src/dynamodb/index.ts"],"sourcesContent":["import type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { Decrypted, EncryptedValue } from '@/types'\nimport { logger } from '@/utils/logger'\nimport { type Result, withResult } from '@byteslice/result'\nimport { handleError, toItemWithEqlPayloads } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class BulkDecryptModelsOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<Decrypted<T>[]> {\n private encryptionClient: EncryptionClient\n private items: Record<string, EncryptedValue | unknown>[]\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n items: Record<string, EncryptedValue | unknown>[],\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.items = items\n this.table = table\n }\n\n public async execute(): Promise<\n Result<Decrypted<T>[], EncryptedDynamoDBError>\n > {\n logger.debug(`DynamoDB: bulk decrypting ${this.items.length} models.`)\n return await withResult(\n async () => {\n const itemsWithEqlPayloads = this.items.map((item) =>\n toItemWithEqlPayloads(item, this.table),\n )\n\n const decryptResult = await this.encryptionClient\n .bulkDecryptModels<T>(itemsWithEqlPayloads as T[])\n .audit(this.getAuditData())\n\n if (decryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(decryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = decryptResult.failure.code\n throw error\n }\n\n return decryptResult.data\n },\n (error) =>\n handleError(error, 'bulkDecryptModels', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n","import type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { EncryptedValue } from '@/types'\nimport { logger } from '@/utils/logger'\nimport type { ProtectErrorCode } from '@cipherstash/protect-ffi'\nimport { ProtectError as FfiProtectError } from '@cipherstash/protect-ffi'\nimport type { EncryptedDynamoDBError } from './types'\n\nexport const ciphertextAttrSuffix = '__source'\nexport const searchTermAttrSuffix = '__hmac'\n\nexport class EncryptedDynamoDBErrorImpl\n extends Error\n implements EncryptedDynamoDBError\n{\n constructor(\n message: string,\n public code: ProtectErrorCode | 'DYNAMODB_ENCRYPTION_ERROR',\n public details?: Record<string, unknown>,\n ) {\n super(message)\n this.name = 'EncryptedDynamoDBError'\n }\n}\n\nexport function handleError(\n error: unknown,\n context: string,\n options?: {\n logger?: {\n error: (message: string, error: Error) => void\n }\n errorHandler?: (error: EncryptedDynamoDBError) => void\n },\n): EncryptedDynamoDBError {\n // Preserve FFI error code if available, otherwise use generic DynamoDB error code\n // Check for FfiProtectError instance or plain error objects with code property\n const errorObj = error as Record<string, unknown>\n const errorCode =\n error instanceof FfiProtectError\n ? error.code\n : errorObj &&\n typeof errorObj === 'object' &&\n 'code' in errorObj &&\n typeof errorObj.code === 'string'\n ? (errorObj.code as ProtectErrorCode)\n : 'DYNAMODB_ENCRYPTION_ERROR'\n\n const errorMessage =\n error instanceof Error\n ? error.message\n : errorObj && typeof errorObj.message === 'string'\n ? errorObj.message\n : String(error)\n\n const dynamoError = new EncryptedDynamoDBErrorImpl(errorMessage, errorCode, {\n context,\n })\n\n logger.error(`DynamoDB error in ${context}: ${errorMessage}`)\n\n if (options?.errorHandler) {\n options.errorHandler(dynamoError)\n }\n\n if (options?.logger) {\n options.logger.error(`Error in ${context}`, dynamoError)\n }\n\n return dynamoError\n}\n\nexport function deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== 'object') {\n return obj\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => deepClone(item)) as unknown as T\n }\n\n return Object.entries(obj as Record<string, unknown>).reduce(\n (acc, [key, value]) => ({\n // biome-ignore lint/performance/noAccumulatingSpread: TODO later\n ...acc,\n [key]: deepClone(value),\n }),\n {} as T,\n )\n}\n\nexport function toEncryptedDynamoItem(\n encrypted: Record<string, unknown>,\n encryptedAttrs: string[],\n): Record<string, unknown> {\n function processValue(\n attrName: string,\n attrValue: unknown,\n isNested: boolean,\n ): Record<string, unknown> {\n if (attrValue === null || attrValue === undefined) {\n return { [attrName]: attrValue }\n }\n\n // Handle encrypted payload\n if (\n encryptedAttrs.includes(attrName) ||\n (isNested &&\n typeof attrValue === 'object' &&\n 'c' in (attrValue as object))\n ) {\n const encryptPayload = attrValue as EncryptedValue\n if (encryptPayload?.k === 'ct' && encryptPayload.c) {\n const result: Record<string, unknown> = {}\n if (encryptPayload.hm) {\n result[`${attrName}${searchTermAttrSuffix}`] = encryptPayload.hm\n }\n result[`${attrName}${ciphertextAttrSuffix}`] = encryptPayload.c\n return result\n }\n\n if (encryptPayload?.k === 'sv' && encryptPayload.sv) {\n const result: Record<string, unknown> = {}\n result[`${attrName}${ciphertextAttrSuffix}`] = encryptPayload.sv\n return result\n }\n }\n\n // Handle nested objects recursively\n if (typeof attrValue === 'object' && !Array.isArray(attrValue)) {\n const nestedResult = Object.entries(\n attrValue as Record<string, unknown>,\n ).reduce(\n (acc, [key, val]) => {\n const processed = processValue(key, val, true)\n return Object.assign({}, acc, processed)\n },\n {} as Record<string, unknown>,\n )\n return { [attrName]: nestedResult }\n }\n\n // Handle non-encrypted values\n return { [attrName]: attrValue }\n }\n\n return Object.entries(encrypted).reduce(\n (putItem, [attrName, attrValue]) => {\n const processed = processValue(attrName, attrValue, false)\n return Object.assign({}, putItem, processed)\n },\n {} as Record<string, unknown>,\n )\n}\n\nexport function toItemWithEqlPayloads(\n decrypted: Record<string, EncryptedValue | unknown>,\n encryptionSchema: EncryptedTable<EncryptedTableColumn>,\n): Record<string, unknown> {\n function processValue(\n attrName: string,\n attrValue: unknown,\n isNested: boolean,\n ): Record<string, unknown> {\n if (attrValue === null || attrValue === undefined) {\n return { [attrName]: attrValue }\n }\n\n // Skip HMAC fields\n if (attrName.endsWith(searchTermAttrSuffix)) {\n return {}\n }\n\n const encryptConfig = encryptionSchema.build()\n const encryptedAttrs = Object.keys(encryptConfig.columns)\n const columnName = attrName.slice(0, -ciphertextAttrSuffix.length)\n\n // Handle encrypted payload\n if (\n attrName.endsWith(ciphertextAttrSuffix) &&\n (encryptedAttrs.includes(columnName) || isNested)\n ) {\n const i = { c: columnName, t: encryptConfig.tableName }\n const v = 2\n\n // Nested values are not searchable, so we can just return the standard EQL payload.\n // Worth noting, that encryptConfig.columns[columnName] will be undefined if isNested is true.\n if (\n !isNested &&\n encryptConfig.columns[columnName].cast_as === 'json' &&\n encryptConfig.columns[columnName].indexes.ste_vec\n ) {\n return {\n [columnName]: {\n i,\n v,\n k: 'sv',\n sv: attrValue,\n },\n }\n }\n\n return {\n [columnName]: {\n i,\n v,\n k: 'ct',\n c: attrValue,\n },\n }\n }\n\n // Handle nested objects recursively\n if (typeof attrValue === 'object' && !Array.isArray(attrValue)) {\n const nestedResult = Object.entries(\n attrValue as Record<string, unknown>,\n ).reduce(\n (acc, [key, val]) => {\n const processed = processValue(key, val, true)\n return Object.assign({}, acc, processed)\n },\n {} as Record<string, unknown>,\n )\n return { [attrName]: nestedResult }\n }\n\n // Handle non-encrypted values\n return { [attrName]: attrValue }\n }\n\n return Object.entries(decrypted).reduce(\n (formattedItem, [attrName, attrValue]) => {\n const processed = processValue(attrName, attrValue, false)\n return Object.assign({}, formattedItem, processed)\n },\n {} as Record<string, unknown>,\n )\n}\n","import type { Result } from '@byteslice/result'\nimport type { EncryptedDynamoDBError } from '../types'\n\nexport type AuditConfig = {\n metadata?: Record<string, unknown>\n}\n\nexport type AuditData = {\n metadata?: Record<string, unknown>\n}\n\nexport type DynamoDBOperationOptions = {\n logger?: {\n error: (message: string, error: Error) => void\n }\n errorHandler?: (error: EncryptedDynamoDBError) => void\n}\n\nexport abstract class DynamoDBOperation<T> {\n protected auditMetadata?: Record<string, unknown>\n protected logger?: DynamoDBOperationOptions['logger']\n protected errorHandler?: DynamoDBOperationOptions['errorHandler']\n\n constructor(options?: DynamoDBOperationOptions) {\n this.logger = options?.logger\n this.errorHandler = options?.errorHandler\n }\n\n /**\n * Attach audit metadata to this operation. Can be chained.\n */\n audit(config: AuditConfig): this {\n this.auditMetadata = config.metadata\n return this\n }\n\n /**\n * Get the audit metadata for this operation.\n */\n protected getAuditData(): AuditData {\n return {\n metadata: this.auditMetadata,\n }\n }\n\n /**\n * Execute the operation and return a Result\n */\n abstract execute(): Promise<Result<T, EncryptedDynamoDBError>>\n\n /**\n * Make the operation thenable\n */\n public then<TResult1 = Result<T, EncryptedDynamoDBError>, TResult2 = never>(\n onfulfilled?:\n | ((\n value: Result<T, EncryptedDynamoDBError>,\n ) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.execute().then(onfulfilled, onrejected)\n }\n}\n","import type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport { logger } from '@/utils/logger'\nimport { type Result, withResult } from '@byteslice/result'\nimport { deepClone, handleError, toEncryptedDynamoItem } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class BulkEncryptModelsOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<T[]> {\n private encryptionClient: EncryptionClient\n private items: T[]\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n items: T[],\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.items = items\n this.table = table\n }\n\n public async execute(): Promise<Result<T[], EncryptedDynamoDBError>> {\n logger.debug(`DynamoDB: bulk encrypting ${this.items.length} models.`)\n return await withResult(\n async () => {\n const encryptResult = await this.encryptionClient\n .bulkEncryptModels(\n this.items.map((item) => deepClone(item)),\n this.table,\n )\n .audit(this.getAuditData())\n\n if (encryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(encryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = encryptResult.failure.code\n throw error\n }\n\n const data = encryptResult.data.map((item) => deepClone(item))\n const encryptedAttrs = Object.keys(this.table.build().columns)\n\n return data.map(\n (encrypted) => toEncryptedDynamoItem(encrypted, encryptedAttrs) as T,\n )\n },\n (error) =>\n handleError(error, 'bulkEncryptModels', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n","import type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { Decrypted, EncryptedValue } from '@/types'\nimport { logger } from '@/utils/logger'\nimport { type Result, withResult } from '@byteslice/result'\nimport { handleError, toItemWithEqlPayloads } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class DecryptModelOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<Decrypted<T>> {\n private encryptionClient: EncryptionClient\n private item: Record<string, EncryptedValue | unknown>\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n item: Record<string, EncryptedValue | unknown>,\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.item = item\n this.table = table\n }\n\n public async execute(): Promise<\n Result<Decrypted<T>, EncryptedDynamoDBError>\n > {\n logger.debug('DynamoDB: decrypting model.')\n return await withResult(\n async () => {\n const withEqlPayloads = toItemWithEqlPayloads(this.item, this.table)\n\n const decryptResult = await this.encryptionClient\n .decryptModel<T>(withEqlPayloads as T)\n .audit(this.getAuditData())\n\n if (decryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(decryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = decryptResult.failure.code\n throw error\n }\n\n return decryptResult.data\n },\n (error) =>\n handleError(error, 'decryptModel', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n","import type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport { logger } from '@/utils/logger'\nimport { type Result, withResult } from '@byteslice/result'\nimport { deepClone, handleError, toEncryptedDynamoItem } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class EncryptModelOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<T> {\n private encryptionClient: EncryptionClient\n private item: T\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n item: T,\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.item = item\n this.table = table\n }\n\n public async execute(): Promise<Result<T, EncryptedDynamoDBError>> {\n logger.debug('DynamoDB: encrypting model.')\n return await withResult(\n async () => {\n const encryptResult = await this.encryptionClient\n .encryptModel(deepClone(this.item), this.table)\n .audit(this.getAuditData())\n\n if (encryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(encryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = encryptResult.failure.code\n throw error\n }\n\n const data = deepClone(encryptResult.data)\n const encryptedAttrs = Object.keys(this.table.build().columns)\n\n return toEncryptedDynamoItem(data, encryptedAttrs) as T\n },\n (error) =>\n handleError(error, 'encryptModel', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n","import type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { EncryptedValue } from '@/types'\nimport { BulkDecryptModelsOperation } from './operations/bulk-decrypt-models'\nimport { BulkEncryptModelsOperation } from './operations/bulk-encrypt-models'\nimport { DecryptModelOperation } from './operations/decrypt-model'\nimport { EncryptModelOperation } from './operations/encrypt-model'\nimport type {\n EncryptedDynamoDBConfig,\n EncryptedDynamoDBInstance,\n} from './types'\n\n/**\n * Create an encrypted DynamoDB helper bound to an `EncryptionClient`.\n *\n * Returns an object with `encryptModel`, `decryptModel`, `bulkEncryptModels`,\n * and `bulkDecryptModels` methods that transparently encrypt/decrypt DynamoDB\n * items according to the provided table schema.\n *\n * @param config - Configuration containing the `encryptionClient` and optional\n * logging / error-handling callbacks.\n * @returns An {@link EncryptedDynamoDBInstance} with encrypt/decrypt operations.\n *\n * @example\n * ```typescript\n * import { Encryption } from \"@cipherstash/stack\"\n * import { encryptedDynamoDB } from \"@cipherstash/stack/dynamodb\"\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * const client = await Encryption({ schemas: [users] })\n * const dynamo = encryptedDynamoDB({ encryptionClient: client })\n *\n * const encrypted = await dynamo.encryptModel({ email: \"a@b.com\" }, users)\n * ```\n */\nexport function encryptedDynamoDB(\n config: EncryptedDynamoDBConfig,\n): EncryptedDynamoDBInstance {\n const { encryptionClient, options } = config\n\n return {\n encryptModel<T extends Record<string, unknown>>(\n item: T,\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new EncryptModelOperation<T>(\n encryptionClient,\n item,\n table,\n options,\n )\n },\n\n bulkEncryptModels<T extends Record<string, unknown>>(\n items: T[],\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new BulkEncryptModelsOperation<T>(\n encryptionClient,\n items,\n table,\n options,\n )\n },\n\n decryptModel<T extends Record<string, unknown>>(\n item: Record<string, EncryptedValue | unknown>,\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new DecryptModelOperation<T>(\n encryptionClient,\n item,\n table,\n options,\n )\n },\n\n bulkDecryptModels<T extends Record<string, unknown>>(\n items: Record<string, EncryptedValue | unknown>[],\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new BulkDecryptModelsOperation<T>(\n encryptionClient,\n items,\n table,\n options,\n )\n },\n }\n}\n\nexport type {\n EncryptedDynamoDBConfig,\n EncryptedDynamoDBError,\n EncryptedDynamoDBInstance,\n} from './types'\n\n// Re-export the operation classes returned by the DynamoDB instance methods so\n// they are part of the public API and appear in the generated reference.\nexport {\n EncryptModelOperation,\n DecryptModelOperation,\n BulkEncryptModelsOperation,\n BulkDecryptModelsOperation,\n}\n"],"mappings":"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","names":["withResult","withResult","withResult","withResult","withResult","withResult"]}
|
|
1
|
+
{"version":3,"sources":["../../src/dynamodb/helpers.ts","../../src/dynamodb/operations/base-operation.ts","../../src/dynamodb/operations/bulk-decrypt-models.ts","../../src/dynamodb/operations/bulk-encrypt-models.ts","../../src/dynamodb/operations/decrypt-model.ts","../../src/dynamodb/operations/encrypt-model.ts","../../src/dynamodb/index.ts"],"sourcesContent":["import type { ProtectErrorCode } from '@cipherstash/protect-ffi'\nimport { ProtectError as FfiProtectError } from '@cipherstash/protect-ffi'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { EncryptedValue } from '@/types'\nimport { logger } from '@/utils/logger'\nimport type { EncryptedDynamoDBError } from './types'\n\nexport const ciphertextAttrSuffix = '__source'\nexport const searchTermAttrSuffix = '__hmac'\n\nexport class EncryptedDynamoDBErrorImpl\n extends Error\n implements EncryptedDynamoDBError\n{\n constructor(\n message: string,\n public code: ProtectErrorCode | 'DYNAMODB_ENCRYPTION_ERROR',\n public details?: Record<string, unknown>,\n ) {\n super(message)\n this.name = 'EncryptedDynamoDBError'\n }\n}\n\nexport function handleError(\n error: unknown,\n context: string,\n options?: {\n logger?: {\n error: (message: string, error: Error) => void\n }\n errorHandler?: (error: EncryptedDynamoDBError) => void\n },\n): EncryptedDynamoDBError {\n // Preserve FFI error code if available, otherwise use generic DynamoDB error code\n // Check for FfiProtectError instance or plain error objects with code property\n const errorObj = error as Record<string, unknown>\n const errorCode =\n error instanceof FfiProtectError\n ? error.code\n : errorObj &&\n typeof errorObj === 'object' &&\n 'code' in errorObj &&\n typeof errorObj.code === 'string'\n ? (errorObj.code as ProtectErrorCode)\n : 'DYNAMODB_ENCRYPTION_ERROR'\n\n const errorMessage =\n error instanceof Error\n ? error.message\n : errorObj && typeof errorObj.message === 'string'\n ? errorObj.message\n : String(error)\n\n const dynamoError = new EncryptedDynamoDBErrorImpl(errorMessage, errorCode, {\n context,\n })\n\n logger.error(`DynamoDB error in ${context}: ${errorMessage}`)\n\n if (options?.errorHandler) {\n options.errorHandler(dynamoError)\n }\n\n if (options?.logger) {\n options.logger.error(`Error in ${context}`, dynamoError)\n }\n\n return dynamoError\n}\n\nexport function deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== 'object') {\n return obj\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => deepClone(item)) as unknown as T\n }\n\n return Object.entries(obj as Record<string, unknown>).reduce(\n (acc, [key, value]) => ({\n // biome-ignore lint/performance/noAccumulatingSpread: TODO later\n ...acc,\n [key]: deepClone(value),\n }),\n {} as T,\n )\n}\n\nexport function toEncryptedDynamoItem(\n encrypted: Record<string, unknown>,\n encryptedAttrs: string[],\n): Record<string, unknown> {\n function processValue(\n attrName: string,\n attrValue: unknown,\n isNested: boolean,\n ): Record<string, unknown> {\n if (attrValue === null || attrValue === undefined) {\n return { [attrName]: attrValue }\n }\n\n // Handle encrypted payload\n if (\n encryptedAttrs.includes(attrName) ||\n (isNested &&\n typeof attrValue === 'object' &&\n 'c' in (attrValue as object))\n ) {\n const encryptPayload = attrValue as EncryptedValue\n if (encryptPayload?.k === 'ct' && encryptPayload.c) {\n const result: Record<string, unknown> = {}\n if (encryptPayload.hm) {\n result[`${attrName}${searchTermAttrSuffix}`] = encryptPayload.hm\n }\n result[`${attrName}${ciphertextAttrSuffix}`] = encryptPayload.c\n return result\n }\n\n if (encryptPayload?.k === 'sv' && encryptPayload.sv) {\n const result: Record<string, unknown> = {}\n result[`${attrName}${ciphertextAttrSuffix}`] = encryptPayload.sv\n return result\n }\n }\n\n // Handle nested objects recursively\n if (typeof attrValue === 'object' && !Array.isArray(attrValue)) {\n const nestedResult = Object.entries(\n attrValue as Record<string, unknown>,\n ).reduce(\n (acc, [key, val]) => {\n const processed = processValue(key, val, true)\n return Object.assign({}, acc, processed)\n },\n {} as Record<string, unknown>,\n )\n return { [attrName]: nestedResult }\n }\n\n // Handle non-encrypted values\n return { [attrName]: attrValue }\n }\n\n return Object.entries(encrypted).reduce(\n (putItem, [attrName, attrValue]) => {\n const processed = processValue(attrName, attrValue, false)\n return Object.assign({}, putItem, processed)\n },\n {} as Record<string, unknown>,\n )\n}\n\nexport function toItemWithEqlPayloads(\n decrypted: Record<string, EncryptedValue | unknown>,\n encryptionSchema: EncryptedTable<EncryptedTableColumn>,\n): Record<string, unknown> {\n function processValue(\n attrName: string,\n attrValue: unknown,\n isNested: boolean,\n ): Record<string, unknown> {\n if (attrValue === null || attrValue === undefined) {\n return { [attrName]: attrValue }\n }\n\n // Skip HMAC fields\n if (attrName.endsWith(searchTermAttrSuffix)) {\n return {}\n }\n\n const encryptConfig = encryptionSchema.build()\n const encryptedAttrs = Object.keys(encryptConfig.columns)\n const columnName = attrName.slice(0, -ciphertextAttrSuffix.length)\n\n // Handle encrypted payload\n if (\n attrName.endsWith(ciphertextAttrSuffix) &&\n (encryptedAttrs.includes(columnName) || isNested)\n ) {\n const i = { c: columnName, t: encryptConfig.tableName }\n const v = 2\n\n // Nested values are not searchable, so we can just return the standard EQL payload.\n // Worth noting, that encryptConfig.columns[columnName] will be undefined if isNested is true.\n if (\n !isNested &&\n encryptConfig.columns[columnName].cast_as === 'json' &&\n encryptConfig.columns[columnName].indexes.ste_vec\n ) {\n return {\n [columnName]: {\n i,\n v,\n k: 'sv',\n sv: attrValue,\n },\n }\n }\n\n return {\n [columnName]: {\n i,\n v,\n k: 'ct',\n c: attrValue,\n },\n }\n }\n\n // Handle nested objects recursively\n if (typeof attrValue === 'object' && !Array.isArray(attrValue)) {\n const nestedResult = Object.entries(\n attrValue as Record<string, unknown>,\n ).reduce(\n (acc, [key, val]) => {\n const processed = processValue(key, val, true)\n return Object.assign({}, acc, processed)\n },\n {} as Record<string, unknown>,\n )\n return { [attrName]: nestedResult }\n }\n\n // Handle non-encrypted values\n return { [attrName]: attrValue }\n }\n\n return Object.entries(decrypted).reduce(\n (formattedItem, [attrName, attrValue]) => {\n const processed = processValue(attrName, attrValue, false)\n return Object.assign({}, formattedItem, processed)\n },\n {} as Record<string, unknown>,\n )\n}\n","import type { Result } from '@byteslice/result'\nimport type { EncryptedDynamoDBError } from '../types'\n\nexport type AuditConfig = {\n metadata?: Record<string, unknown>\n}\n\nexport type AuditData = {\n metadata?: Record<string, unknown>\n}\n\nexport type DynamoDBOperationOptions = {\n logger?: {\n error: (message: string, error: Error) => void\n }\n errorHandler?: (error: EncryptedDynamoDBError) => void\n}\n\nexport abstract class DynamoDBOperation<T> {\n protected auditMetadata?: Record<string, unknown>\n protected logger?: DynamoDBOperationOptions['logger']\n protected errorHandler?: DynamoDBOperationOptions['errorHandler']\n\n constructor(options?: DynamoDBOperationOptions) {\n this.logger = options?.logger\n this.errorHandler = options?.errorHandler\n }\n\n /**\n * Attach audit metadata to this operation. Can be chained.\n */\n audit(config: AuditConfig): this {\n this.auditMetadata = config.metadata\n return this\n }\n\n /**\n * Get the audit metadata for this operation.\n */\n protected getAuditData(): AuditData {\n return {\n metadata: this.auditMetadata,\n }\n }\n\n /**\n * Execute the operation and return a Result\n */\n abstract execute(): Promise<Result<T, EncryptedDynamoDBError>>\n\n /**\n * Make the operation thenable\n */\n public then<TResult1 = Result<T, EncryptedDynamoDBError>, TResult2 = never>(\n onfulfilled?:\n | ((\n value: Result<T, EncryptedDynamoDBError>,\n ) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.execute().then(onfulfilled, onrejected)\n }\n}\n","import { type Result, withResult } from '@byteslice/result'\nimport type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { Decrypted, EncryptedValue } from '@/types'\nimport { logger } from '@/utils/logger'\nimport { handleError, toItemWithEqlPayloads } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class BulkDecryptModelsOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<Decrypted<T>[]> {\n private encryptionClient: EncryptionClient\n private items: Record<string, EncryptedValue | unknown>[]\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n items: Record<string, EncryptedValue | unknown>[],\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.items = items\n this.table = table\n }\n\n public async execute(): Promise<\n Result<Decrypted<T>[], EncryptedDynamoDBError>\n > {\n logger.debug(`DynamoDB: bulk decrypting ${this.items.length} models.`)\n return await withResult(\n async () => {\n const itemsWithEqlPayloads = this.items.map((item) =>\n toItemWithEqlPayloads(item, this.table),\n )\n\n const decryptResult = await this.encryptionClient\n .bulkDecryptModels<T>(itemsWithEqlPayloads as T[])\n .audit(this.getAuditData())\n\n if (decryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(decryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = decryptResult.failure.code\n throw error\n }\n\n return decryptResult.data\n },\n (error) =>\n handleError(error, 'bulkDecryptModels', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n","import { type Result, withResult } from '@byteslice/result'\nimport type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport { logger } from '@/utils/logger'\nimport { deepClone, handleError, toEncryptedDynamoItem } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class BulkEncryptModelsOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<T[]> {\n private encryptionClient: EncryptionClient\n private items: T[]\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n items: T[],\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.items = items\n this.table = table\n }\n\n public async execute(): Promise<Result<T[], EncryptedDynamoDBError>> {\n logger.debug(`DynamoDB: bulk encrypting ${this.items.length} models.`)\n return await withResult(\n async () => {\n const encryptResult = await this.encryptionClient\n .bulkEncryptModels(\n this.items.map((item) => deepClone(item)),\n this.table,\n )\n .audit(this.getAuditData())\n\n if (encryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(encryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = encryptResult.failure.code\n throw error\n }\n\n const data = encryptResult.data.map((item) => deepClone(item))\n const encryptedAttrs = Object.keys(this.table.build().columns)\n\n return data.map(\n (encrypted) => toEncryptedDynamoItem(encrypted, encryptedAttrs) as T,\n )\n },\n (error) =>\n handleError(error, 'bulkEncryptModels', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n","import { type Result, withResult } from '@byteslice/result'\nimport type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { Decrypted, EncryptedValue } from '@/types'\nimport { logger } from '@/utils/logger'\nimport { handleError, toItemWithEqlPayloads } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class DecryptModelOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<Decrypted<T>> {\n private encryptionClient: EncryptionClient\n private item: Record<string, EncryptedValue | unknown>\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n item: Record<string, EncryptedValue | unknown>,\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.item = item\n this.table = table\n }\n\n public async execute(): Promise<\n Result<Decrypted<T>, EncryptedDynamoDBError>\n > {\n logger.debug('DynamoDB: decrypting model.')\n return await withResult(\n async () => {\n const withEqlPayloads = toItemWithEqlPayloads(this.item, this.table)\n\n const decryptResult = await this.encryptionClient\n .decryptModel<T>(withEqlPayloads as T)\n .audit(this.getAuditData())\n\n if (decryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(decryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = decryptResult.failure.code\n throw error\n }\n\n return decryptResult.data\n },\n (error) =>\n handleError(error, 'decryptModel', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n","import { type Result, withResult } from '@byteslice/result'\nimport type { EncryptionClient } from '@/encryption'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport { logger } from '@/utils/logger'\nimport { deepClone, handleError, toEncryptedDynamoItem } from '../helpers'\nimport type { EncryptedDynamoDBError } from '../types'\nimport {\n DynamoDBOperation,\n type DynamoDBOperationOptions,\n} from './base-operation'\n\nexport class EncryptModelOperation<\n T extends Record<string, unknown>,\n> extends DynamoDBOperation<T> {\n private encryptionClient: EncryptionClient\n private item: T\n private table: EncryptedTable<EncryptedTableColumn>\n\n constructor(\n encryptionClient: EncryptionClient,\n item: T,\n table: EncryptedTable<EncryptedTableColumn>,\n options?: DynamoDBOperationOptions,\n ) {\n super(options)\n this.encryptionClient = encryptionClient\n this.item = item\n this.table = table\n }\n\n public async execute(): Promise<Result<T, EncryptedDynamoDBError>> {\n logger.debug('DynamoDB: encrypting model.')\n return await withResult(\n async () => {\n const encryptResult = await this.encryptionClient\n .encryptModel(deepClone(this.item), this.table)\n .audit(this.getAuditData())\n\n if (encryptResult.failure) {\n // Create an Error object that preserves the FFI error code\n // This is necessary because withResult's ensureError wraps non-Error objects\n const error = new Error(encryptResult.failure.message) as Error & {\n code?: string\n }\n error.code = encryptResult.failure.code\n throw error\n }\n\n const data = deepClone(encryptResult.data)\n const encryptedAttrs = Object.keys(this.table.build().columns)\n\n return toEncryptedDynamoItem(data, encryptedAttrs) as T\n },\n (error) =>\n handleError(error, 'encryptModel', {\n logger: this.logger,\n errorHandler: this.errorHandler,\n }),\n )\n }\n}\n","import type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { EncryptedValue } from '@/types'\nimport { BulkDecryptModelsOperation } from './operations/bulk-decrypt-models'\nimport { BulkEncryptModelsOperation } from './operations/bulk-encrypt-models'\nimport { DecryptModelOperation } from './operations/decrypt-model'\nimport { EncryptModelOperation } from './operations/encrypt-model'\nimport type {\n EncryptedDynamoDBConfig,\n EncryptedDynamoDBInstance,\n} from './types'\n\n/**\n * Create an encrypted DynamoDB helper bound to an `EncryptionClient`.\n *\n * Returns an object with `encryptModel`, `decryptModel`, `bulkEncryptModels`,\n * and `bulkDecryptModels` methods that transparently encrypt/decrypt DynamoDB\n * items according to the provided table schema.\n *\n * @param config - Configuration containing the `encryptionClient` and optional\n * logging / error-handling callbacks.\n * @returns An {@link EncryptedDynamoDBInstance} with encrypt/decrypt operations.\n *\n * @example\n * ```typescript\n * import { Encryption } from \"@cipherstash/stack\"\n * import { encryptedDynamoDB } from \"@cipherstash/stack/dynamodb\"\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * const client = await Encryption({ schemas: [users] })\n * const dynamo = encryptedDynamoDB({ encryptionClient: client })\n *\n * const encrypted = await dynamo.encryptModel({ email: \"a@b.com\" }, users)\n * ```\n */\nexport function encryptedDynamoDB(\n config: EncryptedDynamoDBConfig,\n): EncryptedDynamoDBInstance {\n const { encryptionClient, options } = config\n\n return {\n encryptModel<T extends Record<string, unknown>>(\n item: T,\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new EncryptModelOperation<T>(\n encryptionClient,\n item,\n table,\n options,\n )\n },\n\n bulkEncryptModels<T extends Record<string, unknown>>(\n items: T[],\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new BulkEncryptModelsOperation<T>(\n encryptionClient,\n items,\n table,\n options,\n )\n },\n\n decryptModel<T extends Record<string, unknown>>(\n item: Record<string, EncryptedValue | unknown>,\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new DecryptModelOperation<T>(\n encryptionClient,\n item,\n table,\n options,\n )\n },\n\n bulkDecryptModels<T extends Record<string, unknown>>(\n items: Record<string, EncryptedValue | unknown>[],\n table: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new BulkDecryptModelsOperation<T>(\n encryptionClient,\n items,\n table,\n options,\n )\n },\n }\n}\n\nexport type {\n EncryptedDynamoDBConfig,\n EncryptedDynamoDBError,\n EncryptedDynamoDBInstance,\n} from './types'\n\n// Re-export the operation classes returned by the DynamoDB instance methods so\n// they are part of the public API and appear in the generated reference.\nexport {\n BulkDecryptModelsOperation,\n BulkEncryptModelsOperation,\n DecryptModelOperation,\n EncryptModelOperation,\n}\n"],"mappings":"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","names":[]}
|