@cipherstash/stack 0.15.1 → 0.15.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +19 -19
- package/dist/{chunk-YPAPL3IC.js → chunk-46S3YFRK.js} +2 -2
- package/dist/chunk-6FD7OBGM.js +365 -0
- package/dist/chunk-6FD7OBGM.js.map +1 -0
- package/dist/dynamodb/index.cjs +303 -6
- package/dist/dynamodb/index.cjs.map +1 -1
- package/dist/dynamodb/index.js +1 -1
- package/dist/encryption/index.cjs +323 -26
- package/dist/encryption/index.cjs.map +1 -1
- package/dist/encryption/index.js +2 -2
- package/dist/identity/index.cjs +303 -6
- package/dist/identity/index.cjs.map +1 -1
- package/dist/identity/index.js +1 -1
- package/dist/index.cjs +323 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/supabase/index.cjs +303 -6
- package/dist/supabase/index.cjs.map +1 -1
- package/dist/supabase/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-Q5FTQLYG.js +0 -68
- package/dist/chunk-Q5FTQLYG.js.map +0 -1
- /package/dist/{chunk-YPAPL3IC.js.map → chunk-46S3YFRK.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @cipherstash/stack
|
|
2
2
|
|
|
3
|
+
## 0.15.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- afe6810: Bump protect-ffi version
|
|
8
|
+
|
|
9
|
+
## 0.15.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 510c485: Bundle `evlog` into the CJS output. `evlog` is pure ESM (no `require` condition in its `exports` map), so CJS consumers of `@cipherstash/stack` (e.g. webpack bundles) were failing with `ERR_PACKAGE_PATH_NOT_EXPORTED` when the stack's `index.cjs` tried to `require("evlog")`. `evlog` is now inlined at build time and no longer resolved at runtime.
|
|
14
|
+
|
|
3
15
|
## 0.15.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ pnpm add @cipherstash/stack
|
|
|
47
47
|
### 1. Initialize and authenticate your project
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
|
-
npx
|
|
50
|
+
npx stash init
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
The wizard will authenticate you, walk you through choosing a database connection method, build an encryption schema, and install the required dependencies.
|
|
@@ -438,25 +438,25 @@ await secrets.delete("DATABASE_URL")
|
|
|
438
438
|
|
|
439
439
|
## CLI Reference
|
|
440
440
|
|
|
441
|
-
The CLI is available via `npx
|
|
441
|
+
The CLI is available via `npx stash` after install.
|
|
442
442
|
|
|
443
|
-
### `npx
|
|
443
|
+
### `npx stash auth`
|
|
444
444
|
|
|
445
445
|
Authenticate with CipherStash.
|
|
446
446
|
|
|
447
447
|
```bash
|
|
448
|
-
npx
|
|
448
|
+
npx stash auth login
|
|
449
449
|
```
|
|
450
450
|
|
|
451
451
|
This runs the device code flow: it opens your browser, you confirm the code, and a token is saved to `~/.cipherstash/auth.json`. No environment variables or credentials files are needed for local development.
|
|
452
452
|
|
|
453
|
-
### `npx
|
|
453
|
+
### `npx stash init`
|
|
454
454
|
|
|
455
455
|
Initialize CipherStash for your project with an interactive wizard.
|
|
456
456
|
|
|
457
457
|
```bash
|
|
458
|
-
npx
|
|
459
|
-
npx
|
|
458
|
+
npx stash init
|
|
459
|
+
npx stash init --supabase
|
|
460
460
|
```
|
|
461
461
|
|
|
462
462
|
The wizard will:
|
|
@@ -464,31 +464,31 @@ The wizard will:
|
|
|
464
464
|
2. Bind your device to the default Keyset
|
|
465
465
|
3. Choose your database connection method (Drizzle ORM, Supabase JS, Prisma, or Raw SQL)
|
|
466
466
|
4. Build an encryption schema interactively or use a placeholder, then generate the encryption client file
|
|
467
|
-
5. Install
|
|
467
|
+
5. Install `stash` as a dev dependency for database tooling
|
|
468
468
|
|
|
469
|
-
After init, run `npx
|
|
469
|
+
After init, run `npx stash db setup` to configure your database.
|
|
470
470
|
|
|
471
471
|
| Flag | Description |
|
|
472
472
|
|------|-------------|
|
|
473
473
|
| `--supabase` | Use Supabase-specific setup flow |
|
|
474
474
|
|
|
475
|
-
### `npx
|
|
475
|
+
### `npx stash secrets`
|
|
476
476
|
|
|
477
477
|
Manage encrypted secrets from the terminal.
|
|
478
478
|
|
|
479
479
|
```bash
|
|
480
|
-
npx
|
|
481
|
-
npx
|
|
482
|
-
npx
|
|
483
|
-
npx
|
|
480
|
+
npx stash secrets set -name DATABASE_URL -value "postgres://..." -environment production
|
|
481
|
+
npx stash secrets get -name DATABASE_URL -environment production
|
|
482
|
+
npx stash secrets list -environment production
|
|
483
|
+
npx stash secrets delete -name DATABASE_URL -environment production
|
|
484
484
|
```
|
|
485
485
|
|
|
486
486
|
| Command | Flags | Aliases | Description |
|
|
487
487
|
|-----|----|-----|-------|
|
|
488
|
-
| `npx
|
|
489
|
-
| `npx
|
|
490
|
-
| `npx
|
|
491
|
-
| `npx
|
|
488
|
+
| `npx stash secrets set` | `-name`, `-value`, `-environment` | `-n`, `-V`, `-e` | Encrypt and store a secret |
|
|
489
|
+
| `npx stash secrets get` | `-name`, `-environment` | `-n`, `-e` | Retrieve and decrypt a secret |
|
|
490
|
+
| `npx stash secrets list` | `-environment` | `-e` | List all secret names in an environment |
|
|
491
|
+
| `npx stash secrets delete` | `-name`, `-environment`, `-yes` | `-n`, `-e`, `-y` | Delete a secret (prompts for confirmation unless `-yes`) |
|
|
492
492
|
|
|
493
493
|
## Configuration
|
|
494
494
|
|
|
@@ -676,7 +676,7 @@ If you are migrating from `@cipherstash/protect`, the following table maps the o
|
|
|
676
676
|
| `csColumn(name)` | `encryptedColumn(name)` | `@cipherstash/stack/schema` |
|
|
677
677
|
| `import { LockContext } from "@cipherstash/protect/identify"` | `import { LockContext } from "@cipherstash/stack/identity"` | `@cipherstash/stack/identity` |
|
|
678
678
|
| N/A | `Secrets` class | `@cipherstash/stack/secrets` |
|
|
679
|
-
| N/A | CLI | `npx
|
|
679
|
+
| N/A | CLI | `npx stash` |
|
|
680
680
|
|
|
681
681
|
All method signatures on the encryption client (`encrypt`, `decrypt`, `encryptModel`, etc.) remain the same. The `Result` pattern (`data` / `failure`) is unchanged.
|
|
682
682
|
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
import {
|
|
15
15
|
createRequestLogger,
|
|
16
16
|
logger
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-6FD7OBGM.js";
|
|
18
18
|
import {
|
|
19
19
|
EncryptionErrorTypes
|
|
20
20
|
} from "./chunk-LBMC4D6D.js";
|
|
@@ -2325,4 +2325,4 @@ export {
|
|
|
2325
2325
|
EncryptionClient,
|
|
2326
2326
|
Encryption
|
|
2327
2327
|
};
|
|
2328
|
-
//# sourceMappingURL=chunk-
|
|
2328
|
+
//# sourceMappingURL=chunk-46S3YFRK.js.map
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
// ../../node_modules/.pnpm/evlog@1.9.0/node_modules/evlog/dist/utils.mjs
|
|
2
|
+
function formatDuration(ms) {
|
|
3
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
4
|
+
return `${(ms / 1e3).toFixed(2)}s`;
|
|
5
|
+
}
|
|
6
|
+
function isDev() {
|
|
7
|
+
if (typeof process !== "undefined") return process.env.NODE_ENV !== "production";
|
|
8
|
+
if (typeof window !== "undefined") return true;
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
function detectEnvironment() {
|
|
12
|
+
const env = typeof process !== "undefined" ? process.env : {};
|
|
13
|
+
const defaultEnvironment = isDev() ? "development" : "production";
|
|
14
|
+
return {
|
|
15
|
+
environment: env.NODE_ENV || defaultEnvironment,
|
|
16
|
+
service: env.SERVICE_NAME || "app",
|
|
17
|
+
version: env.APP_VERSION,
|
|
18
|
+
commitHash: env.COMMIT_SHA || env.GITHUB_SHA || env.VERCEL_GIT_COMMIT_SHA || env.CF_PAGES_COMMIT_SHA,
|
|
19
|
+
region: env.VERCEL_REGION || env.AWS_REGION || env.FLY_REGION || env.CF_REGION
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function getConsoleMethod(level) {
|
|
23
|
+
return level;
|
|
24
|
+
}
|
|
25
|
+
var colors = {
|
|
26
|
+
reset: "\x1B[0m",
|
|
27
|
+
bold: "\x1B[1m",
|
|
28
|
+
dim: "\x1B[2m",
|
|
29
|
+
red: "\x1B[31m",
|
|
30
|
+
green: "\x1B[32m",
|
|
31
|
+
yellow: "\x1B[33m",
|
|
32
|
+
blue: "\x1B[34m",
|
|
33
|
+
magenta: "\x1B[35m",
|
|
34
|
+
cyan: "\x1B[36m",
|
|
35
|
+
white: "\x1B[37m",
|
|
36
|
+
gray: "\x1B[90m"
|
|
37
|
+
};
|
|
38
|
+
function getLevelColor(level) {
|
|
39
|
+
switch (level) {
|
|
40
|
+
case "error":
|
|
41
|
+
return colors.red;
|
|
42
|
+
case "warn":
|
|
43
|
+
return colors.yellow;
|
|
44
|
+
case "info":
|
|
45
|
+
return colors.cyan;
|
|
46
|
+
case "debug":
|
|
47
|
+
return colors.gray;
|
|
48
|
+
default:
|
|
49
|
+
return colors.white;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function matchesPattern(path, pattern) {
|
|
53
|
+
const regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/{{GLOBSTAR}}/g, ".*").replace(/\?/g, "[^/]");
|
|
54
|
+
return new RegExp(`^${regexPattern}$`).test(path);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ../../node_modules/.pnpm/evlog@1.9.0/node_modules/evlog/dist/logger.mjs
|
|
58
|
+
function isPlainObject(val) {
|
|
59
|
+
return val !== null && typeof val === "object" && !Array.isArray(val);
|
|
60
|
+
}
|
|
61
|
+
function deepDefaults(base, defaults) {
|
|
62
|
+
const result = { ...base };
|
|
63
|
+
for (const key in defaults) {
|
|
64
|
+
const baseVal = result[key];
|
|
65
|
+
const defaultVal = defaults[key];
|
|
66
|
+
if (baseVal === void 0 || baseVal === null) result[key] = defaultVal;
|
|
67
|
+
else if (isPlainObject(baseVal) && isPlainObject(defaultVal)) result[key] = deepDefaults(baseVal, defaultVal);
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
var globalEnv = {
|
|
72
|
+
service: "app",
|
|
73
|
+
environment: "development"
|
|
74
|
+
};
|
|
75
|
+
var globalPretty = isDev();
|
|
76
|
+
var globalSampling = {};
|
|
77
|
+
var globalStringify = true;
|
|
78
|
+
var globalDrain;
|
|
79
|
+
var globalEnabled = true;
|
|
80
|
+
function initLogger(config = {}) {
|
|
81
|
+
globalEnabled = config.enabled ?? true;
|
|
82
|
+
const detected = detectEnvironment();
|
|
83
|
+
globalEnv = {
|
|
84
|
+
service: config.env?.service ?? detected.service ?? "app",
|
|
85
|
+
environment: config.env?.environment ?? detected.environment ?? "development",
|
|
86
|
+
version: config.env?.version ?? detected.version,
|
|
87
|
+
commitHash: config.env?.commitHash ?? detected.commitHash,
|
|
88
|
+
region: config.env?.region ?? detected.region
|
|
89
|
+
};
|
|
90
|
+
globalPretty = config.pretty ?? isDev();
|
|
91
|
+
globalSampling = config.sampling ?? {};
|
|
92
|
+
globalStringify = config.stringify ?? true;
|
|
93
|
+
globalDrain = config.drain;
|
|
94
|
+
}
|
|
95
|
+
function shouldSample(level) {
|
|
96
|
+
const { rates } = globalSampling;
|
|
97
|
+
if (!rates) return true;
|
|
98
|
+
const percentage = level === "error" && rates.error === void 0 ? 100 : rates[level] ?? 100;
|
|
99
|
+
if (percentage <= 0) return false;
|
|
100
|
+
if (percentage >= 100) return true;
|
|
101
|
+
return Math.random() * 100 < percentage;
|
|
102
|
+
}
|
|
103
|
+
function shouldKeep(ctx) {
|
|
104
|
+
const { keep } = globalSampling;
|
|
105
|
+
if (!keep?.length) return false;
|
|
106
|
+
return keep.some((condition) => {
|
|
107
|
+
if (condition.status !== void 0 && ctx.status !== void 0 && ctx.status >= condition.status) return true;
|
|
108
|
+
if (condition.duration !== void 0 && ctx.duration !== void 0 && ctx.duration >= condition.duration) return true;
|
|
109
|
+
if (condition.path && ctx.path && matchesPattern(ctx.path, condition.path)) return true;
|
|
110
|
+
return false;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function emitWideEvent(level, event, skipSamplingCheck = false) {
|
|
114
|
+
if (!globalEnabled) return null;
|
|
115
|
+
if (!skipSamplingCheck && !shouldSample(level)) return null;
|
|
116
|
+
const formatted = {
|
|
117
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
118
|
+
level,
|
|
119
|
+
...globalEnv,
|
|
120
|
+
...event
|
|
121
|
+
};
|
|
122
|
+
if (globalPretty) prettyPrintWideEvent(formatted);
|
|
123
|
+
else if (globalStringify) console[getConsoleMethod(level)](JSON.stringify(formatted));
|
|
124
|
+
else console[getConsoleMethod(level)](formatted);
|
|
125
|
+
if (globalDrain) Promise.resolve(globalDrain({ event: formatted })).catch((err) => {
|
|
126
|
+
console.error("[evlog] drain failed:", err);
|
|
127
|
+
});
|
|
128
|
+
return formatted;
|
|
129
|
+
}
|
|
130
|
+
function emitTaggedLog(level, tag, message) {
|
|
131
|
+
if (!globalEnabled) return;
|
|
132
|
+
if (globalPretty) {
|
|
133
|
+
if (!shouldSample(level)) return;
|
|
134
|
+
const color = getLevelColor(level);
|
|
135
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
136
|
+
console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
emitWideEvent(level, {
|
|
140
|
+
tag,
|
|
141
|
+
message
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function formatValue(value) {
|
|
145
|
+
if (value === null || value === void 0) return String(value);
|
|
146
|
+
if (typeof value === "object") {
|
|
147
|
+
const pairs = [];
|
|
148
|
+
for (const [k, v] of Object.entries(value)) if (v !== void 0 && v !== null) if (typeof v === "object") pairs.push(`${k}=${JSON.stringify(v)}`);
|
|
149
|
+
else pairs.push(`${k}=${v}`);
|
|
150
|
+
return pairs.join(" ");
|
|
151
|
+
}
|
|
152
|
+
return String(value);
|
|
153
|
+
}
|
|
154
|
+
function prettyPrintWideEvent(event) {
|
|
155
|
+
const { timestamp, level, service, environment, version, ...rest } = event;
|
|
156
|
+
const levelColor = getLevelColor(level);
|
|
157
|
+
const ts = timestamp.slice(11, 23);
|
|
158
|
+
let header = `${colors.dim}${ts}${colors.reset} ${levelColor}${level.toUpperCase()}${colors.reset}`;
|
|
159
|
+
header += ` ${colors.cyan}[${service}]${colors.reset}`;
|
|
160
|
+
if (rest.method && rest.path) {
|
|
161
|
+
header += ` ${rest.method} ${rest.path}`;
|
|
162
|
+
delete rest.method;
|
|
163
|
+
delete rest.path;
|
|
164
|
+
}
|
|
165
|
+
if (rest.status) {
|
|
166
|
+
const statusColor = rest.status >= 400 ? colors.red : colors.green;
|
|
167
|
+
header += ` ${statusColor}${rest.status}${colors.reset}`;
|
|
168
|
+
delete rest.status;
|
|
169
|
+
}
|
|
170
|
+
if (rest.duration) {
|
|
171
|
+
header += ` ${colors.dim}in ${rest.duration}${colors.reset}`;
|
|
172
|
+
delete rest.duration;
|
|
173
|
+
}
|
|
174
|
+
console.log(header);
|
|
175
|
+
const entries = Object.entries(rest).filter(([_, v]) => v !== void 0);
|
|
176
|
+
const lastIndex = entries.length - 1;
|
|
177
|
+
entries.forEach(([key, value], index) => {
|
|
178
|
+
const prefix = index === lastIndex ? "\u2514\u2500" : "\u251C\u2500";
|
|
179
|
+
const formatted = formatValue(value);
|
|
180
|
+
console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${formatted}`);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
function createLogMethod(level) {
|
|
184
|
+
return function logMethod(tagOrEvent, message) {
|
|
185
|
+
if (typeof tagOrEvent === "string" && message !== void 0) emitTaggedLog(level, tagOrEvent, message);
|
|
186
|
+
else if (typeof tagOrEvent === "object") emitWideEvent(level, tagOrEvent);
|
|
187
|
+
else emitTaggedLog(level, "log", String(tagOrEvent));
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
var _log = {
|
|
191
|
+
info: createLogMethod("info"),
|
|
192
|
+
error: createLogMethod("error"),
|
|
193
|
+
warn: createLogMethod("warn"),
|
|
194
|
+
debug: createLogMethod("debug")
|
|
195
|
+
};
|
|
196
|
+
var noopLogger = {
|
|
197
|
+
set() {
|
|
198
|
+
},
|
|
199
|
+
error() {
|
|
200
|
+
},
|
|
201
|
+
info() {
|
|
202
|
+
},
|
|
203
|
+
warn() {
|
|
204
|
+
},
|
|
205
|
+
emit() {
|
|
206
|
+
return null;
|
|
207
|
+
},
|
|
208
|
+
getContext() {
|
|
209
|
+
return {};
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
function createRequestLogger(options = {}) {
|
|
213
|
+
if (!globalEnabled) return noopLogger;
|
|
214
|
+
const startTime = Date.now();
|
|
215
|
+
let context = {
|
|
216
|
+
method: options.method,
|
|
217
|
+
path: options.path,
|
|
218
|
+
requestId: options.requestId
|
|
219
|
+
};
|
|
220
|
+
let hasError = false;
|
|
221
|
+
let hasWarn = false;
|
|
222
|
+
function addRequestLog(level, message) {
|
|
223
|
+
const entry = {
|
|
224
|
+
level,
|
|
225
|
+
message,
|
|
226
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
227
|
+
};
|
|
228
|
+
const requestLogs = Array.isArray(context.requestLogs) ? [...context.requestLogs, entry] : [entry];
|
|
229
|
+
context = {
|
|
230
|
+
...context,
|
|
231
|
+
requestLogs
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
set(data) {
|
|
236
|
+
context = deepDefaults(data, context);
|
|
237
|
+
},
|
|
238
|
+
error(error, errorContext) {
|
|
239
|
+
hasError = true;
|
|
240
|
+
const err = typeof error === "string" ? new Error(error) : error;
|
|
241
|
+
context = deepDefaults({
|
|
242
|
+
...errorContext,
|
|
243
|
+
error: {
|
|
244
|
+
name: err.name,
|
|
245
|
+
message: err.message,
|
|
246
|
+
stack: err.stack,
|
|
247
|
+
..."status" in err && { status: err.status },
|
|
248
|
+
..."statusText" in err && { statusText: err.statusText },
|
|
249
|
+
..."statusCode" in err && { statusCode: err.statusCode },
|
|
250
|
+
..."statusMessage" in err && { statusMessage: err.statusMessage },
|
|
251
|
+
..."data" in err && { data: err.data },
|
|
252
|
+
..."cause" in err && { cause: err.cause }
|
|
253
|
+
}
|
|
254
|
+
}, context);
|
|
255
|
+
},
|
|
256
|
+
info(message, infoContext) {
|
|
257
|
+
addRequestLog("info", message);
|
|
258
|
+
if (infoContext) {
|
|
259
|
+
const { requestLogs: _, ...rest } = infoContext;
|
|
260
|
+
context = deepDefaults(rest, context);
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
warn(message, warnContext) {
|
|
264
|
+
hasWarn = true;
|
|
265
|
+
addRequestLog("warn", message);
|
|
266
|
+
if (warnContext) {
|
|
267
|
+
const { requestLogs: _, ...rest } = warnContext;
|
|
268
|
+
context = deepDefaults(rest, context);
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
emit(overrides) {
|
|
272
|
+
const durationMs = Date.now() - startTime;
|
|
273
|
+
const duration = formatDuration(durationMs);
|
|
274
|
+
const level = hasError ? "error" : hasWarn ? "warn" : "info";
|
|
275
|
+
const { _forceKeep, ...restOverrides } = overrides ?? {};
|
|
276
|
+
const tailCtx = {
|
|
277
|
+
status: context.status ?? restOverrides.status,
|
|
278
|
+
duration: durationMs,
|
|
279
|
+
path: context.path,
|
|
280
|
+
method: context.method,
|
|
281
|
+
context: {
|
|
282
|
+
...context,
|
|
283
|
+
...restOverrides
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
if (!(_forceKeep || shouldKeep(tailCtx)) && !shouldSample(level)) return null;
|
|
287
|
+
return emitWideEvent(level, {
|
|
288
|
+
...context,
|
|
289
|
+
...restOverrides,
|
|
290
|
+
duration
|
|
291
|
+
}, true);
|
|
292
|
+
},
|
|
293
|
+
getContext() {
|
|
294
|
+
return { ...context };
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// src/utils/logger/index.ts
|
|
300
|
+
var validLevels = ["debug", "info", "error"];
|
|
301
|
+
function levelFromEnv() {
|
|
302
|
+
const env = process.env.STASH_STACK_LOG;
|
|
303
|
+
if (env && validLevels.includes(env)) return env;
|
|
304
|
+
return "error";
|
|
305
|
+
}
|
|
306
|
+
function samplingRatesForLevel(level) {
|
|
307
|
+
switch (level) {
|
|
308
|
+
case "debug":
|
|
309
|
+
return { debug: 100, info: 100, warn: 100, error: 100 };
|
|
310
|
+
case "info":
|
|
311
|
+
return { debug: 0, info: 100, warn: 100, error: 100 };
|
|
312
|
+
case "error":
|
|
313
|
+
default:
|
|
314
|
+
return { debug: 0, info: 0, warn: 0, error: 100 };
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
var initialized = false;
|
|
318
|
+
function initStackLogger() {
|
|
319
|
+
if (initialized) return;
|
|
320
|
+
initialized = true;
|
|
321
|
+
const level = levelFromEnv();
|
|
322
|
+
const rates = samplingRatesForLevel(level);
|
|
323
|
+
initLogger({
|
|
324
|
+
env: { service: "@cipherstash/stack" },
|
|
325
|
+
enabled: true,
|
|
326
|
+
sampling: { rates }
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
initStackLogger();
|
|
330
|
+
function safeMessage(args) {
|
|
331
|
+
return typeof args[0] === "string" ? args[0] : "";
|
|
332
|
+
}
|
|
333
|
+
var logger = {
|
|
334
|
+
debug(...args) {
|
|
335
|
+
const log = createRequestLogger();
|
|
336
|
+
log.set({
|
|
337
|
+
level: "debug",
|
|
338
|
+
source: "@cipherstash/stack",
|
|
339
|
+
message: safeMessage(args)
|
|
340
|
+
});
|
|
341
|
+
log.emit();
|
|
342
|
+
},
|
|
343
|
+
info(...args) {
|
|
344
|
+
const log = createRequestLogger();
|
|
345
|
+
log.set({ source: "@cipherstash/stack" });
|
|
346
|
+
log.info(safeMessage(args));
|
|
347
|
+
log.emit();
|
|
348
|
+
},
|
|
349
|
+
warn(...args) {
|
|
350
|
+
const log = createRequestLogger();
|
|
351
|
+
log.warn(safeMessage(args));
|
|
352
|
+
log.emit();
|
|
353
|
+
},
|
|
354
|
+
error(...args) {
|
|
355
|
+
const log = createRequestLogger();
|
|
356
|
+
log.error(safeMessage(args));
|
|
357
|
+
log.emit();
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
export {
|
|
362
|
+
createRequestLogger,
|
|
363
|
+
logger
|
|
364
|
+
};
|
|
365
|
+
//# sourceMappingURL=chunk-6FD7OBGM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../node_modules/.pnpm/evlog@1.9.0/node_modules/evlog/src/utils.ts","../../../node_modules/.pnpm/evlog@1.9.0/node_modules/evlog/src/logger.ts","../src/utils/logger/index.ts"],"sourcesContent":["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"],"mappings":"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","names":[]}
|