@parsrun/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -0
- package/dist/decimal.d.ts +190 -0
- package/dist/decimal.js +347 -0
- package/dist/decimal.js.map +1 -0
- package/dist/env.d.ts +101 -0
- package/dist/env.js +172 -0
- package/dist/env.js.map +1 -0
- package/dist/error-codes.d.ts +257 -0
- package/dist/error-codes.js +261 -0
- package/dist/error-codes.js.map +1 -0
- package/dist/errors.d.ts +81 -0
- package/dist/errors.js +161 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +116 -0
- package/dist/index.js +1987 -0
- package/dist/index.js.map +1 -0
- package/dist/logger-aEibH9Mv.d.ts +262 -0
- package/dist/logger.d.ts +1 -0
- package/dist/logger.js +327 -0
- package/dist/logger.js.map +1 -0
- package/dist/runtime.d.ts +62 -0
- package/dist/runtime.js +88 -0
- package/dist/runtime.js.map +1 -0
- package/dist/transports/index.d.ts +347 -0
- package/dist/transports/index.js +657 -0
- package/dist/transports/index.js.map +1 -0
- package/dist/types.d.ts +116 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/package.json +68 -0
package/dist/logger.js
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
// src/runtime.ts
|
|
2
|
+
function detectRuntime() {
|
|
3
|
+
if (typeof globalThis !== "undefined" && "Bun" in globalThis) {
|
|
4
|
+
return "bun";
|
|
5
|
+
}
|
|
6
|
+
if (typeof globalThis !== "undefined" && "Deno" in globalThis) {
|
|
7
|
+
return "deno";
|
|
8
|
+
}
|
|
9
|
+
if (typeof globalThis !== "undefined" && typeof globalThis.caches !== "undefined" && typeof globalThis.process === "undefined") {
|
|
10
|
+
return "cloudflare";
|
|
11
|
+
}
|
|
12
|
+
if (typeof globalThis !== "undefined" && typeof globalThis.EdgeRuntime !== "undefined") {
|
|
13
|
+
return "edge";
|
|
14
|
+
}
|
|
15
|
+
if (typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined" && typeof globalThis.document !== "undefined") {
|
|
16
|
+
return "browser";
|
|
17
|
+
}
|
|
18
|
+
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
19
|
+
return "node";
|
|
20
|
+
}
|
|
21
|
+
return "unknown";
|
|
22
|
+
}
|
|
23
|
+
var runtime = detectRuntime();
|
|
24
|
+
var runtimeInfo = {
|
|
25
|
+
runtime,
|
|
26
|
+
isNode: runtime === "node",
|
|
27
|
+
isDeno: runtime === "deno",
|
|
28
|
+
isBun: runtime === "bun",
|
|
29
|
+
isCloudflare: runtime === "cloudflare",
|
|
30
|
+
isEdge: runtime === "cloudflare" || runtime === "edge" || runtime === "deno",
|
|
31
|
+
isBrowser: runtime === "browser",
|
|
32
|
+
isServer: runtime !== "browser",
|
|
33
|
+
supportsWebCrypto: typeof globalThis.crypto?.subtle !== "undefined",
|
|
34
|
+
supportsStreams: typeof globalThis.ReadableStream !== "undefined"
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// src/env.ts
|
|
38
|
+
var edgeEnvStore = {};
|
|
39
|
+
function getEnv(key, defaultValue) {
|
|
40
|
+
if (runtime === "cloudflare" || runtime === "edge") {
|
|
41
|
+
return edgeEnvStore[key] ?? defaultValue;
|
|
42
|
+
}
|
|
43
|
+
if (runtime === "deno") {
|
|
44
|
+
try {
|
|
45
|
+
return globalThis.Deno.env.get(key) ?? defaultValue;
|
|
46
|
+
} catch {
|
|
47
|
+
return defaultValue;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (typeof process !== "undefined" && process.env) {
|
|
51
|
+
return process.env[key] ?? defaultValue;
|
|
52
|
+
}
|
|
53
|
+
if (runtime === "browser" && typeof globalThis.__ENV__ !== "undefined") {
|
|
54
|
+
return globalThis.__ENV__[key] ?? defaultValue;
|
|
55
|
+
}
|
|
56
|
+
return defaultValue;
|
|
57
|
+
}
|
|
58
|
+
function isDevelopment() {
|
|
59
|
+
const env = getEnv("NODE_ENV");
|
|
60
|
+
return env === "development" || env === void 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/transports/console.ts
|
|
64
|
+
var ConsoleTransport = class {
|
|
65
|
+
name = "console";
|
|
66
|
+
pretty;
|
|
67
|
+
colors;
|
|
68
|
+
constructor(options = {}) {
|
|
69
|
+
this.pretty = options.pretty ?? isDevelopment();
|
|
70
|
+
this.colors = options.colors ?? (runtime === "node" || runtime === "bun");
|
|
71
|
+
}
|
|
72
|
+
log(entry) {
|
|
73
|
+
if (this.pretty) {
|
|
74
|
+
this.logPretty(entry);
|
|
75
|
+
} else {
|
|
76
|
+
this.logJson(entry);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
logJson(entry) {
|
|
80
|
+
const { level, message, timestamp, context, error } = entry;
|
|
81
|
+
const output = {
|
|
82
|
+
level,
|
|
83
|
+
time: timestamp,
|
|
84
|
+
msg: message
|
|
85
|
+
};
|
|
86
|
+
if (context && Object.keys(context).length > 0) {
|
|
87
|
+
Object.assign(output, context);
|
|
88
|
+
}
|
|
89
|
+
if (error) {
|
|
90
|
+
output["err"] = error;
|
|
91
|
+
}
|
|
92
|
+
console.log(JSON.stringify(output));
|
|
93
|
+
}
|
|
94
|
+
logPretty(entry) {
|
|
95
|
+
const { level, message, timestamp, context, error } = entry;
|
|
96
|
+
const levelColors = {
|
|
97
|
+
TRACE: "\x1B[90m",
|
|
98
|
+
// Gray
|
|
99
|
+
DEBUG: "\x1B[36m",
|
|
100
|
+
// Cyan
|
|
101
|
+
INFO: "\x1B[32m",
|
|
102
|
+
// Green
|
|
103
|
+
WARN: "\x1B[33m",
|
|
104
|
+
// Yellow
|
|
105
|
+
ERROR: "\x1B[31m",
|
|
106
|
+
// Red
|
|
107
|
+
FATAL: "\x1B[35m",
|
|
108
|
+
// Magenta
|
|
109
|
+
SILENT: ""
|
|
110
|
+
};
|
|
111
|
+
const reset = "\x1B[0m";
|
|
112
|
+
const color = this.colors ? levelColors[level] : "";
|
|
113
|
+
const resetCode = this.colors ? reset : "";
|
|
114
|
+
const timePart = timestamp.split("T")[1];
|
|
115
|
+
const time = timePart ? timePart.slice(0, 8) : timestamp;
|
|
116
|
+
let output = `${color}[${time}] ${level.padEnd(5)}${resetCode} ${message}`;
|
|
117
|
+
if (context && Object.keys(context).length > 0) {
|
|
118
|
+
output += ` ${JSON.stringify(context)}`;
|
|
119
|
+
}
|
|
120
|
+
if (level === "ERROR" || level === "FATAL") {
|
|
121
|
+
console.error(output);
|
|
122
|
+
if (error?.stack) {
|
|
123
|
+
console.error(error.stack);
|
|
124
|
+
}
|
|
125
|
+
} else if (level === "WARN") {
|
|
126
|
+
console.warn(output);
|
|
127
|
+
} else if (level === "DEBUG" || level === "TRACE") {
|
|
128
|
+
console.debug(output);
|
|
129
|
+
} else {
|
|
130
|
+
console.log(output);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// src/logger.ts
|
|
136
|
+
var LogLevel = {
|
|
137
|
+
TRACE: 10,
|
|
138
|
+
DEBUG: 20,
|
|
139
|
+
INFO: 30,
|
|
140
|
+
WARN: 40,
|
|
141
|
+
ERROR: 50,
|
|
142
|
+
FATAL: 60,
|
|
143
|
+
SILENT: 100
|
|
144
|
+
};
|
|
145
|
+
function redactFields(obj, fields) {
|
|
146
|
+
const result = { ...obj };
|
|
147
|
+
for (const field of fields) {
|
|
148
|
+
if (field in result) {
|
|
149
|
+
result[field] = "[REDACTED]";
|
|
150
|
+
}
|
|
151
|
+
const parts = field.split(".");
|
|
152
|
+
if (parts.length > 1) {
|
|
153
|
+
let current = result;
|
|
154
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
155
|
+
const part = parts[i];
|
|
156
|
+
if (part && current && typeof current === "object" && part in current) {
|
|
157
|
+
const val = current[part];
|
|
158
|
+
if (val && typeof val === "object") {
|
|
159
|
+
current = val;
|
|
160
|
+
} else {
|
|
161
|
+
current = void 0;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
current = void 0;
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const lastPart = parts[parts.length - 1];
|
|
170
|
+
if (lastPart && current && typeof current === "object" && lastPart in current) {
|
|
171
|
+
current[lastPart] = "[REDACTED]";
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
var DEFAULT_REDACT_FIELDS = [
|
|
178
|
+
"password",
|
|
179
|
+
"secret",
|
|
180
|
+
"token",
|
|
181
|
+
"accessToken",
|
|
182
|
+
"refreshToken",
|
|
183
|
+
"apiKey",
|
|
184
|
+
"authorization",
|
|
185
|
+
"cookie",
|
|
186
|
+
"creditCard",
|
|
187
|
+
"ssn"
|
|
188
|
+
];
|
|
189
|
+
var Logger = class _Logger {
|
|
190
|
+
level;
|
|
191
|
+
name;
|
|
192
|
+
context;
|
|
193
|
+
transports;
|
|
194
|
+
redactFields;
|
|
195
|
+
timestampFn;
|
|
196
|
+
constructor(config = {}) {
|
|
197
|
+
const levelName = config.level ?? getEnv("LOG_LEVEL") ?? "INFO";
|
|
198
|
+
this.level = LogLevel[levelName] ?? LogLevel.INFO;
|
|
199
|
+
this.name = config.name;
|
|
200
|
+
this.context = config.context ?? {};
|
|
201
|
+
this.transports = config.transports ?? [
|
|
202
|
+
new ConsoleTransport(
|
|
203
|
+
config.pretty !== void 0 ? { pretty: config.pretty } : {}
|
|
204
|
+
)
|
|
205
|
+
];
|
|
206
|
+
this.redactFields = [...DEFAULT_REDACT_FIELDS, ...config.redact ?? []];
|
|
207
|
+
if (config.timestamp === false) {
|
|
208
|
+
this.timestampFn = () => "";
|
|
209
|
+
} else if (typeof config.timestamp === "function") {
|
|
210
|
+
this.timestampFn = config.timestamp;
|
|
211
|
+
} else {
|
|
212
|
+
this.timestampFn = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Create a child logger with additional context
|
|
217
|
+
*/
|
|
218
|
+
child(context) {
|
|
219
|
+
const levelEntry = Object.entries(LogLevel).find(([_, v]) => v === this.level);
|
|
220
|
+
const levelName = levelEntry ? levelEntry[0] : "INFO";
|
|
221
|
+
const child = new _Logger({
|
|
222
|
+
level: levelName,
|
|
223
|
+
name: this.name,
|
|
224
|
+
context: { ...this.context, ...context },
|
|
225
|
+
transports: this.transports,
|
|
226
|
+
redact: this.redactFields
|
|
227
|
+
});
|
|
228
|
+
return child;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Log a message
|
|
232
|
+
*/
|
|
233
|
+
log(level, message, context, error) {
|
|
234
|
+
const levelValue = LogLevel[level];
|
|
235
|
+
if (levelValue < this.level) return;
|
|
236
|
+
let finalContext = { ...this.context };
|
|
237
|
+
if (this.name) {
|
|
238
|
+
finalContext["module"] = this.name;
|
|
239
|
+
}
|
|
240
|
+
if (context) {
|
|
241
|
+
finalContext = { ...finalContext, ...context };
|
|
242
|
+
}
|
|
243
|
+
finalContext = redactFields(finalContext, this.redactFields);
|
|
244
|
+
const entry = {
|
|
245
|
+
level,
|
|
246
|
+
levelValue,
|
|
247
|
+
message,
|
|
248
|
+
timestamp: this.timestampFn(),
|
|
249
|
+
context: Object.keys(finalContext).length > 0 ? finalContext : void 0,
|
|
250
|
+
error: error ? {
|
|
251
|
+
name: error.name,
|
|
252
|
+
message: error.message,
|
|
253
|
+
stack: error.stack
|
|
254
|
+
} : void 0
|
|
255
|
+
};
|
|
256
|
+
for (const transport of this.transports) {
|
|
257
|
+
transport.log(entry);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
trace(message, context) {
|
|
261
|
+
this.log("TRACE", message, context);
|
|
262
|
+
}
|
|
263
|
+
debug(message, context) {
|
|
264
|
+
this.log("DEBUG", message, context);
|
|
265
|
+
}
|
|
266
|
+
info(message, context) {
|
|
267
|
+
this.log("INFO", message, context);
|
|
268
|
+
}
|
|
269
|
+
warn(message, context) {
|
|
270
|
+
this.log("WARN", message, context);
|
|
271
|
+
}
|
|
272
|
+
error(message, error, context) {
|
|
273
|
+
const err = error instanceof Error ? error : void 0;
|
|
274
|
+
const ctx = error instanceof Error ? context : error;
|
|
275
|
+
this.log("ERROR", message, ctx, err);
|
|
276
|
+
}
|
|
277
|
+
fatal(message, error, context) {
|
|
278
|
+
const err = error instanceof Error ? error : void 0;
|
|
279
|
+
const ctx = error instanceof Error ? context : error;
|
|
280
|
+
this.log("FATAL", message, ctx, err);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
function createLogger(config) {
|
|
284
|
+
return new Logger(config);
|
|
285
|
+
}
|
|
286
|
+
var logger = createLogger();
|
|
287
|
+
function logError(log, error, message, context) {
|
|
288
|
+
if (error instanceof Error) {
|
|
289
|
+
log.error(message, error, context);
|
|
290
|
+
} else {
|
|
291
|
+
log.error(message, { error: String(error), ...context });
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
async function measureTime(log, operation, fn) {
|
|
295
|
+
const start = Date.now();
|
|
296
|
+
try {
|
|
297
|
+
const result = await fn();
|
|
298
|
+
const duration = Date.now() - start;
|
|
299
|
+
log.info(`${operation} completed`, { operation, durationMs: duration });
|
|
300
|
+
return result;
|
|
301
|
+
} catch (error) {
|
|
302
|
+
const duration = Date.now() - start;
|
|
303
|
+
logError(log, error, `${operation} failed`, { operation, durationMs: duration });
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
function createRequestLogger(baseLogger, request) {
|
|
308
|
+
const pathname = request.url ? new URL(request.url).pathname : void 0;
|
|
309
|
+
return baseLogger.child({
|
|
310
|
+
requestId: request.requestId,
|
|
311
|
+
method: request.method,
|
|
312
|
+
path: pathname,
|
|
313
|
+
userId: request.userId,
|
|
314
|
+
tenantId: request.tenantId
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
export {
|
|
318
|
+
ConsoleTransport,
|
|
319
|
+
LogLevel,
|
|
320
|
+
Logger,
|
|
321
|
+
createLogger,
|
|
322
|
+
createRequestLogger,
|
|
323
|
+
logError,
|
|
324
|
+
logger,
|
|
325
|
+
measureTime
|
|
326
|
+
};
|
|
327
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime.ts","../src/env.ts","../src/transports/console.ts","../src/logger.ts"],"sourcesContent":["/**\n * @parsrun/core - Runtime Detection\n * Edge-compatible runtime detection for Node.js, Deno, Bun, and Cloudflare Workers\n */\n\nexport type Runtime = \"node\" | \"deno\" | \"bun\" | \"cloudflare\" | \"edge\" | \"browser\" | \"unknown\";\n\n/**\n * Detect the current JavaScript runtime\n */\nexport function detectRuntime(): Runtime {\n // Bun check (must be before Node since Bun also has process)\n if (typeof globalThis !== \"undefined\" && \"Bun\" in globalThis) {\n return \"bun\";\n }\n\n // Deno check\n if (typeof globalThis !== \"undefined\" && \"Deno\" in globalThis) {\n return \"deno\";\n }\n\n // Cloudflare Workers check (has caches but no process)\n if (\n typeof globalThis !== \"undefined\" &&\n typeof (globalThis as any).caches !== \"undefined\" &&\n typeof (globalThis as any).process === \"undefined\"\n ) {\n return \"cloudflare\";\n }\n\n // Generic Edge runtime check (Vercel Edge, etc.)\n if (\n typeof globalThis !== \"undefined\" &&\n typeof (globalThis as any).EdgeRuntime !== \"undefined\"\n ) {\n return \"edge\";\n }\n\n // Browser check\n if (\n typeof globalThis !== \"undefined\" &&\n typeof (globalThis as any).window !== \"undefined\" &&\n typeof (globalThis as any).document !== \"undefined\"\n ) {\n return \"browser\";\n }\n\n // Node.js check\n if (\n typeof process !== \"undefined\" &&\n process.versions &&\n process.versions.node\n ) {\n return \"node\";\n }\n\n return \"unknown\";\n}\n\n/**\n * Current runtime (cached)\n */\nexport const runtime = detectRuntime();\n\n/**\n * Runtime information helpers\n */\nexport const runtimeInfo = {\n runtime,\n isNode: runtime === \"node\",\n isDeno: runtime === \"deno\",\n isBun: runtime === \"bun\",\n isCloudflare: runtime === \"cloudflare\",\n isEdge: runtime === \"cloudflare\" || runtime === \"edge\" || runtime === \"deno\",\n isBrowser: runtime === \"browser\",\n isServer: runtime !== \"browser\",\n supportsWebCrypto: typeof globalThis.crypto?.subtle !== \"undefined\",\n supportsStreams: typeof globalThis.ReadableStream !== \"undefined\",\n} as const;\n\n/**\n * Check if running in Node.js\n */\nexport function isNode(): boolean {\n return runtime === \"node\";\n}\n\n/**\n * Check if running in Deno\n */\nexport function isDeno(): boolean {\n return runtime === \"deno\";\n}\n\n/**\n * Check if running in Bun\n */\nexport function isBun(): boolean {\n return runtime === \"bun\";\n}\n\n/**\n * Check if running in Cloudflare Workers\n */\nexport function isCloudflare(): boolean {\n return runtime === \"cloudflare\";\n}\n\n/**\n * Check if running in any edge environment\n */\nexport function isEdge(): boolean {\n return runtimeInfo.isEdge;\n}\n\n/**\n * Check if running in browser\n */\nexport function isBrowser(): boolean {\n return runtime === \"browser\";\n}\n\n/**\n * Check if running on server (not browser)\n */\nexport function isServer(): boolean {\n return runtimeInfo.isServer;\n}\n\n/**\n * Get runtime version string\n */\nexport function getRuntimeVersion(): string {\n switch (runtime) {\n case \"node\":\n return `Node.js ${process.versions.node}`;\n case \"bun\":\n return `Bun ${(globalThis as any).Bun.version}`;\n case \"deno\":\n return `Deno ${(globalThis as any).Deno.version.deno}`;\n case \"cloudflare\":\n return \"Cloudflare Workers\";\n case \"edge\":\n return \"Edge Runtime\";\n case \"browser\":\n return typeof navigator !== \"undefined\" ? navigator.userAgent : \"Browser\";\n default:\n return \"Unknown\";\n }\n}\n","/**\n * @parsrun/core - Environment Variables\n * Runtime-agnostic environment variable access\n * Works in Node.js, Deno, Bun, and Cloudflare Workers\n */\n\nimport { runtime } from \"./runtime.js\";\n\n/**\n * Environment variable store for edge runtimes\n * Must be set from the request handler's env parameter\n */\nlet edgeEnvStore: Record<string, string | undefined> = {};\n\n/**\n * Set environment variables for edge runtimes (Cloudflare Workers, etc.)\n * Call this from your worker's fetch handler with the env parameter\n *\n * @example\n * ```typescript\n * export default {\n * async fetch(request, env) {\n * setEdgeEnv(env);\n * // ... rest of handler\n * }\n * }\n * ```\n */\nexport function setEdgeEnv(env: Record<string, string | undefined>): void {\n edgeEnvStore = { ...edgeEnvStore, ...env };\n}\n\n/**\n * Clear edge environment store\n */\nexport function clearEdgeEnv(): void {\n edgeEnvStore = {};\n}\n\n/**\n * Get an environment variable value\n * Works across all runtimes\n */\nexport function getEnv(key: string, defaultValue?: string): string | undefined {\n // Edge runtimes (Cloudflare Workers, etc.)\n if (runtime === \"cloudflare\" || runtime === \"edge\") {\n return edgeEnvStore[key] ?? defaultValue;\n }\n\n // Deno\n if (runtime === \"deno\") {\n try {\n return (globalThis as any).Deno.env.get(key) ?? defaultValue;\n } catch {\n return defaultValue;\n }\n }\n\n // Node.js / Bun (both use process.env)\n if (typeof process !== \"undefined\" && process.env) {\n return process.env[key] ?? defaultValue;\n }\n\n // Browser - check for injected env\n if (runtime === \"browser\" && typeof (globalThis as any).__ENV__ !== \"undefined\") {\n return (globalThis as any).__ENV__[key] ?? defaultValue;\n }\n\n return defaultValue;\n}\n\n/**\n * Get an environment variable, throwing if not found\n */\nexport function requireEnv(key: string): string {\n const value = getEnv(key);\n if (value === undefined || value === \"\") {\n throw new Error(`Required environment variable \"${key}\" is not set`);\n }\n return value;\n}\n\n/**\n * Get an environment variable as a number\n */\nexport function getEnvNumber(key: string, defaultValue?: number): number | undefined {\n const value = getEnv(key);\n if (value === undefined || value === \"\") {\n return defaultValue;\n }\n const parsed = parseInt(value, 10);\n return isNaN(parsed) ? defaultValue : parsed;\n}\n\n/**\n * Get an environment variable as a float\n */\nexport function getEnvFloat(key: string, defaultValue?: number): number | undefined {\n const value = getEnv(key);\n if (value === undefined || value === \"\") {\n return defaultValue;\n }\n const parsed = parseFloat(value);\n return isNaN(parsed) ? defaultValue : parsed;\n}\n\n/**\n * Get an environment variable as a boolean\n */\nexport function getEnvBoolean(key: string, defaultValue: boolean = false): boolean {\n const value = getEnv(key);\n if (value === undefined || value === \"\") {\n return defaultValue;\n }\n return value === \"true\" || value === \"1\" || value === \"yes\";\n}\n\n/**\n * Get an environment variable as an array (comma-separated)\n */\nexport function getEnvArray(key: string, defaultValue: string[] = []): string[] {\n const value = getEnv(key);\n if (value === undefined || value === \"\") {\n return defaultValue;\n }\n return value.split(\",\").map((s) => s.trim()).filter(Boolean);\n}\n\n/**\n * Get an environment variable as JSON\n */\nexport function getEnvJson<T>(key: string, defaultValue?: T): T | undefined {\n const value = getEnv(key);\n if (value === undefined || value === \"\") {\n return defaultValue;\n }\n try {\n return JSON.parse(value) as T;\n } catch {\n return defaultValue;\n }\n}\n\n/**\n * Check if running in development mode\n */\nexport function isDevelopment(): boolean {\n const env = getEnv(\"NODE_ENV\");\n return env === \"development\" || env === undefined;\n}\n\n/**\n * Check if running in production mode\n */\nexport function isProduction(): boolean {\n return getEnv(\"NODE_ENV\") === \"production\";\n}\n\n/**\n * Check if running in test mode\n */\nexport function isTest(): boolean {\n return getEnv(\"NODE_ENV\") === \"test\";\n}\n\n/**\n * Environment mode\n */\nexport type EnvMode = \"development\" | \"production\" | \"test\";\n\n/**\n * Get current environment mode\n */\nexport function getEnvMode(): EnvMode {\n const env = getEnv(\"NODE_ENV\");\n if (env === \"production\") return \"production\";\n if (env === \"test\") return \"test\";\n return \"development\";\n}\n\n/**\n * Create a typed environment configuration object\n *\n * @example\n * ```typescript\n * const env = createEnvConfig({\n * DATABASE_URL: { required: true },\n * PORT: { type: 'number', default: 3000 },\n * DEBUG: { type: 'boolean', default: false },\n * });\n *\n * env.DATABASE_URL // string\n * env.PORT // number\n * env.DEBUG // boolean\n * ```\n */\nexport function createEnvConfig<T extends EnvSchema>(schema: T): EnvResult<T> {\n const result: Record<string, unknown> = {};\n\n for (const [key, config] of Object.entries(schema)) {\n const envConfig = config as EnvConfigItem;\n let value: unknown;\n\n switch (envConfig.type) {\n case \"number\":\n value = getEnvNumber(key, envConfig.default as number | undefined);\n break;\n case \"boolean\":\n value = getEnvBoolean(key, envConfig.default as boolean | undefined);\n break;\n case \"array\":\n value = getEnvArray(key, envConfig.default as string[] | undefined);\n break;\n case \"json\":\n value = getEnvJson(key, envConfig.default);\n break;\n default:\n value = getEnv(key, envConfig.default as string | undefined);\n }\n\n if (envConfig.required && (value === undefined || value === \"\")) {\n throw new Error(`Required environment variable \"${key}\" is not set`);\n }\n\n result[key] = value;\n }\n\n return result as EnvResult<T>;\n}\n\n// Type helpers for createEnvConfig\ntype EnvConfigItem = {\n type?: \"string\" | \"number\" | \"boolean\" | \"array\" | \"json\";\n required?: boolean;\n default?: unknown;\n};\n\ntype EnvSchema = Record<string, EnvConfigItem>;\n\ntype EnvResult<T extends EnvSchema> = {\n [K in keyof T]: T[K][\"type\"] extends \"number\"\n ? number\n : T[K][\"type\"] extends \"boolean\"\n ? boolean\n : T[K][\"type\"] extends \"array\"\n ? string[]\n : T[K][\"type\"] extends \"json\"\n ? unknown\n : string;\n};\n","/**\n * @parsrun/core - Console Transport\n * Default transport that outputs to console\n */\n\nimport { runtime } from \"../runtime.js\";\nimport { isDevelopment } from \"../env.js\";\nimport type { LogEntry, LogLevelName } from \"../logger.js\";\nimport type { LogTransport } from \"./types.js\";\n\n/**\n * Console transport options\n */\nexport interface ConsoleTransportOptions {\n /** Enable pretty printing (default: true in development) */\n pretty?: boolean;\n /** Enable ANSI colors (default: true in Node/Bun) */\n colors?: boolean;\n}\n\n/**\n * Console transport\n * Outputs logs to console with optional pretty printing and colors\n */\nexport class ConsoleTransport implements LogTransport {\n readonly name = \"console\";\n\n private pretty: boolean;\n private colors: boolean;\n\n constructor(options: ConsoleTransportOptions = {}) {\n this.pretty = options.pretty ?? isDevelopment();\n this.colors = options.colors ?? (runtime === \"node\" || runtime === \"bun\");\n }\n\n log(entry: LogEntry): void {\n if (this.pretty) {\n this.logPretty(entry);\n } else {\n this.logJson(entry);\n }\n }\n\n private logJson(entry: LogEntry): void {\n const { level, message, timestamp, context, error } = entry;\n\n const output: Record<string, unknown> = {\n level,\n time: timestamp,\n msg: message,\n };\n\n if (context && Object.keys(context).length > 0) {\n Object.assign(output, context);\n }\n\n if (error) {\n output[\"err\"] = error;\n }\n\n console.log(JSON.stringify(output));\n }\n\n private logPretty(entry: LogEntry): void {\n const { level, message, timestamp, context, error } = entry;\n\n const levelColors: Record<LogLevelName, string> = {\n TRACE: \"\\x1b[90m\", // Gray\n DEBUG: \"\\x1b[36m\", // Cyan\n INFO: \"\\x1b[32m\", // Green\n WARN: \"\\x1b[33m\", // Yellow\n ERROR: \"\\x1b[31m\", // Red\n FATAL: \"\\x1b[35m\", // Magenta\n SILENT: \"\",\n };\n\n const reset = \"\\x1b[0m\";\n const color = this.colors ? levelColors[level] : \"\";\n const resetCode = this.colors ? reset : \"\";\n\n // Extract time part from ISO timestamp\n const timePart = timestamp.split(\"T\")[1];\n const time = timePart ? timePart.slice(0, 8) : timestamp;\n\n let output = `${color}[${time}] ${level.padEnd(5)}${resetCode} ${message}`;\n\n if (context && Object.keys(context).length > 0) {\n output += ` ${JSON.stringify(context)}`;\n }\n\n // Route to appropriate console method\n if (level === \"ERROR\" || level === \"FATAL\") {\n console.error(output);\n if (error?.stack) {\n console.error(error.stack);\n }\n } else if (level === \"WARN\") {\n console.warn(output);\n } else if (level === \"DEBUG\" || level === \"TRACE\") {\n console.debug(output);\n } else {\n console.log(output);\n }\n }\n}\n","/**\n * @parsrun/core - Logger\n * Lightweight, edge-compatible structured logging\n * Can be used standalone or as abstraction over pino/winston in Node.js\n */\n\nimport { getEnv } from \"./env.js\";\nimport { ConsoleTransport } from \"./transports/console.js\";\nimport type { LogTransport } from \"./transports/types.js\";\n\n// Re-export ConsoleTransport for backward compatibility\nexport { ConsoleTransport, type ConsoleTransportOptions } from \"./transports/console.js\";\n\n// Re-export transport types\nexport type { LogTransport } from \"./transports/types.js\";\n\n/**\n * Log levels\n */\nexport const LogLevel = {\n TRACE: 10,\n DEBUG: 20,\n INFO: 30,\n WARN: 40,\n ERROR: 50,\n FATAL: 60,\n SILENT: 100,\n} as const;\n\nexport type LogLevelName = keyof typeof LogLevel;\nexport type LogLevelValue = (typeof LogLevel)[LogLevelName];\n\n/**\n * Error info structure\n */\nexport interface ErrorInfo {\n name: string;\n message: string;\n stack: string | undefined;\n}\n\n/**\n * Log entry structure\n */\nexport interface LogEntry {\n level: LogLevelName;\n levelValue: LogLevelValue;\n message: string;\n timestamp: string;\n context: Record<string, unknown> | undefined;\n error: ErrorInfo | undefined;\n}\n\n\n/**\n * Logger configuration\n */\nexport interface LoggerConfig {\n /** Minimum log level */\n level: LogLevelName | undefined;\n /** Logger name/module */\n name: string | undefined;\n /** Base context added to all logs */\n context: Record<string, unknown> | undefined;\n /** Custom transports */\n transports: LogTransport[] | undefined;\n /** Pretty print in development */\n pretty: boolean | undefined;\n /** Redact sensitive fields */\n redact: string[] | undefined;\n /** Timestamp format */\n timestamp: boolean | (() => string) | undefined;\n}\n\n\n/**\n * Redact sensitive fields from context\n */\nfunction redactFields(\n obj: Record<string, unknown>,\n fields: string[]\n): Record<string, unknown> {\n const result = { ...obj };\n for (const field of fields) {\n if (field in result) {\n result[field] = \"[REDACTED]\";\n }\n // Handle nested fields like \"user.password\"\n const parts = field.split(\".\");\n if (parts.length > 1) {\n let current: Record<string, unknown> | undefined = result;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (part && current && typeof current === \"object\" && part in current) {\n const val = current[part];\n if (val && typeof val === \"object\") {\n current = val as Record<string, unknown>;\n } else {\n current = undefined;\n break;\n }\n } else {\n current = undefined;\n break;\n }\n }\n const lastPart = parts[parts.length - 1];\n if (lastPart && current && typeof current === \"object\" && lastPart in current) {\n current[lastPart] = \"[REDACTED]\";\n }\n }\n }\n return result;\n}\n\n/**\n * Default redact fields\n */\nconst DEFAULT_REDACT_FIELDS = [\n \"password\",\n \"secret\",\n \"token\",\n \"accessToken\",\n \"refreshToken\",\n \"apiKey\",\n \"authorization\",\n \"cookie\",\n \"creditCard\",\n \"ssn\",\n];\n\n/**\n * Logger class\n */\nexport class Logger {\n private level: LogLevelValue;\n private name: string | undefined;\n private context: Record<string, unknown>;\n private transports: LogTransport[];\n private redactFields: string[];\n private timestampFn: () => string;\n\n constructor(config: Partial<LoggerConfig> = {}) {\n const levelName = config.level ?? (getEnv(\"LOG_LEVEL\") as LogLevelName | undefined) ?? \"INFO\";\n this.level = LogLevel[levelName] ?? LogLevel.INFO;\n this.name = config.name;\n this.context = config.context ?? {};\n this.transports = config.transports ?? [\n new ConsoleTransport(\n config.pretty !== undefined ? { pretty: config.pretty } : {}\n ),\n ];\n this.redactFields = [...DEFAULT_REDACT_FIELDS, ...(config.redact ?? [])];\n\n if (config.timestamp === false) {\n this.timestampFn = () => \"\";\n } else if (typeof config.timestamp === \"function\") {\n this.timestampFn = config.timestamp;\n } else {\n this.timestampFn = () => new Date().toISOString();\n }\n }\n\n /**\n * Create a child logger with additional context\n */\n child(context: Record<string, unknown>): Logger {\n const levelEntry = Object.entries(LogLevel).find(([_, v]) => v === this.level);\n const levelName = levelEntry ? (levelEntry[0] as LogLevelName) : \"INFO\";\n\n const child = new Logger({\n level: levelName,\n name: this.name,\n context: { ...this.context, ...context },\n transports: this.transports,\n redact: this.redactFields,\n });\n return child;\n }\n\n /**\n * Log a message\n */\n private log(\n level: LogLevelName,\n message: string,\n context?: Record<string, unknown>,\n error?: Error\n ): void {\n const levelValue = LogLevel[level];\n if (levelValue < this.level) return;\n\n let finalContext = { ...this.context };\n if (this.name) {\n finalContext[\"module\"] = this.name;\n }\n if (context) {\n finalContext = { ...finalContext, ...context };\n }\n\n // Redact sensitive fields\n finalContext = redactFields(finalContext, this.redactFields);\n\n const entry: LogEntry = {\n level,\n levelValue,\n message,\n timestamp: this.timestampFn(),\n context: Object.keys(finalContext).length > 0 ? finalContext : undefined,\n error: error\n ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n }\n : undefined,\n };\n\n for (const transport of this.transports) {\n transport.log(entry);\n }\n }\n\n trace(message: string, context?: Record<string, unknown>): void {\n this.log(\"TRACE\", message, context);\n }\n\n debug(message: string, context?: Record<string, unknown>): void {\n this.log(\"DEBUG\", message, context);\n }\n\n info(message: string, context?: Record<string, unknown>): void {\n this.log(\"INFO\", message, context);\n }\n\n warn(message: string, context?: Record<string, unknown>): void {\n this.log(\"WARN\", message, context);\n }\n\n error(message: string, error?: Error | unknown, context?: Record<string, unknown>): void {\n const err = error instanceof Error ? error : undefined;\n const ctx = error instanceof Error ? context : (error as Record<string, unknown> | undefined);\n this.log(\"ERROR\", message, ctx, err);\n }\n\n fatal(message: string, error?: Error | unknown, context?: Record<string, unknown>): void {\n const err = error instanceof Error ? error : undefined;\n const ctx = error instanceof Error ? context : (error as Record<string, unknown> | undefined);\n this.log(\"FATAL\", message, ctx, err);\n }\n}\n\n/**\n * Create a logger instance\n */\nexport function createLogger(config?: Partial<LoggerConfig>): Logger {\n return new Logger(config);\n}\n\n/**\n * Default logger instance\n */\nexport const logger = createLogger();\n\n/**\n * Utility: Log error with proper formatting\n */\nexport function logError(\n log: Logger,\n error: unknown,\n message: string,\n context?: Record<string, unknown>\n): void {\n if (error instanceof Error) {\n log.error(message, error, context);\n } else {\n log.error(message, { error: String(error), ...context });\n }\n}\n\n/**\n * Utility: Measure execution time\n */\nexport async function measureTime<T>(\n log: Logger,\n operation: string,\n fn: () => Promise<T>\n): Promise<T> {\n const start = Date.now();\n try {\n const result = await fn();\n const duration = Date.now() - start;\n log.info(`${operation} completed`, { operation, durationMs: duration });\n return result;\n } catch (error) {\n const duration = Date.now() - start;\n logError(log, error, `${operation} failed`, { operation, durationMs: duration });\n throw error;\n }\n}\n\n/**\n * Utility: Create request logger middleware context\n */\nexport function createRequestLogger(\n baseLogger: Logger,\n request: {\n method?: string;\n url?: string;\n requestId?: string;\n userId?: string;\n tenantId?: string;\n }\n): Logger {\n const pathname = request.url ? new URL(request.url).pathname : undefined;\n return baseLogger.child({\n requestId: request.requestId,\n method: request.method,\n path: pathname,\n userId: request.userId,\n tenantId: request.tenantId,\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @parsrun/core - Runtime Detection
|
|
3
|
+
* Edge-compatible runtime detection for Node.js, Deno, Bun, and Cloudflare Workers
|
|
4
|
+
*/
|
|
5
|
+
type Runtime = "node" | "deno" | "bun" | "cloudflare" | "edge" | "browser" | "unknown";
|
|
6
|
+
/**
|
|
7
|
+
* Detect the current JavaScript runtime
|
|
8
|
+
*/
|
|
9
|
+
declare function detectRuntime(): Runtime;
|
|
10
|
+
/**
|
|
11
|
+
* Current runtime (cached)
|
|
12
|
+
*/
|
|
13
|
+
declare const runtime: Runtime;
|
|
14
|
+
/**
|
|
15
|
+
* Runtime information helpers
|
|
16
|
+
*/
|
|
17
|
+
declare const runtimeInfo: {
|
|
18
|
+
readonly runtime: Runtime;
|
|
19
|
+
readonly isNode: boolean;
|
|
20
|
+
readonly isDeno: boolean;
|
|
21
|
+
readonly isBun: boolean;
|
|
22
|
+
readonly isCloudflare: boolean;
|
|
23
|
+
readonly isEdge: boolean;
|
|
24
|
+
readonly isBrowser: boolean;
|
|
25
|
+
readonly isServer: boolean;
|
|
26
|
+
readonly supportsWebCrypto: boolean;
|
|
27
|
+
readonly supportsStreams: boolean;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Check if running in Node.js
|
|
31
|
+
*/
|
|
32
|
+
declare function isNode(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Check if running in Deno
|
|
35
|
+
*/
|
|
36
|
+
declare function isDeno(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Check if running in Bun
|
|
39
|
+
*/
|
|
40
|
+
declare function isBun(): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Check if running in Cloudflare Workers
|
|
43
|
+
*/
|
|
44
|
+
declare function isCloudflare(): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Check if running in any edge environment
|
|
47
|
+
*/
|
|
48
|
+
declare function isEdge(): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Check if running in browser
|
|
51
|
+
*/
|
|
52
|
+
declare function isBrowser(): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Check if running on server (not browser)
|
|
55
|
+
*/
|
|
56
|
+
declare function isServer(): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Get runtime version string
|
|
59
|
+
*/
|
|
60
|
+
declare function getRuntimeVersion(): string;
|
|
61
|
+
|
|
62
|
+
export { type Runtime, detectRuntime, getRuntimeVersion, isBrowser, isBun, isCloudflare, isDeno, isEdge, isNode, isServer, runtime, runtimeInfo };
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// src/runtime.ts
|
|
2
|
+
function detectRuntime() {
|
|
3
|
+
if (typeof globalThis !== "undefined" && "Bun" in globalThis) {
|
|
4
|
+
return "bun";
|
|
5
|
+
}
|
|
6
|
+
if (typeof globalThis !== "undefined" && "Deno" in globalThis) {
|
|
7
|
+
return "deno";
|
|
8
|
+
}
|
|
9
|
+
if (typeof globalThis !== "undefined" && typeof globalThis.caches !== "undefined" && typeof globalThis.process === "undefined") {
|
|
10
|
+
return "cloudflare";
|
|
11
|
+
}
|
|
12
|
+
if (typeof globalThis !== "undefined" && typeof globalThis.EdgeRuntime !== "undefined") {
|
|
13
|
+
return "edge";
|
|
14
|
+
}
|
|
15
|
+
if (typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined" && typeof globalThis.document !== "undefined") {
|
|
16
|
+
return "browser";
|
|
17
|
+
}
|
|
18
|
+
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
19
|
+
return "node";
|
|
20
|
+
}
|
|
21
|
+
return "unknown";
|
|
22
|
+
}
|
|
23
|
+
var runtime = detectRuntime();
|
|
24
|
+
var runtimeInfo = {
|
|
25
|
+
runtime,
|
|
26
|
+
isNode: runtime === "node",
|
|
27
|
+
isDeno: runtime === "deno",
|
|
28
|
+
isBun: runtime === "bun",
|
|
29
|
+
isCloudflare: runtime === "cloudflare",
|
|
30
|
+
isEdge: runtime === "cloudflare" || runtime === "edge" || runtime === "deno",
|
|
31
|
+
isBrowser: runtime === "browser",
|
|
32
|
+
isServer: runtime !== "browser",
|
|
33
|
+
supportsWebCrypto: typeof globalThis.crypto?.subtle !== "undefined",
|
|
34
|
+
supportsStreams: typeof globalThis.ReadableStream !== "undefined"
|
|
35
|
+
};
|
|
36
|
+
function isNode() {
|
|
37
|
+
return runtime === "node";
|
|
38
|
+
}
|
|
39
|
+
function isDeno() {
|
|
40
|
+
return runtime === "deno";
|
|
41
|
+
}
|
|
42
|
+
function isBun() {
|
|
43
|
+
return runtime === "bun";
|
|
44
|
+
}
|
|
45
|
+
function isCloudflare() {
|
|
46
|
+
return runtime === "cloudflare";
|
|
47
|
+
}
|
|
48
|
+
function isEdge() {
|
|
49
|
+
return runtimeInfo.isEdge;
|
|
50
|
+
}
|
|
51
|
+
function isBrowser() {
|
|
52
|
+
return runtime === "browser";
|
|
53
|
+
}
|
|
54
|
+
function isServer() {
|
|
55
|
+
return runtimeInfo.isServer;
|
|
56
|
+
}
|
|
57
|
+
function getRuntimeVersion() {
|
|
58
|
+
switch (runtime) {
|
|
59
|
+
case "node":
|
|
60
|
+
return `Node.js ${process.versions.node}`;
|
|
61
|
+
case "bun":
|
|
62
|
+
return `Bun ${globalThis.Bun.version}`;
|
|
63
|
+
case "deno":
|
|
64
|
+
return `Deno ${globalThis.Deno.version.deno}`;
|
|
65
|
+
case "cloudflare":
|
|
66
|
+
return "Cloudflare Workers";
|
|
67
|
+
case "edge":
|
|
68
|
+
return "Edge Runtime";
|
|
69
|
+
case "browser":
|
|
70
|
+
return typeof navigator !== "undefined" ? navigator.userAgent : "Browser";
|
|
71
|
+
default:
|
|
72
|
+
return "Unknown";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export {
|
|
76
|
+
detectRuntime,
|
|
77
|
+
getRuntimeVersion,
|
|
78
|
+
isBrowser,
|
|
79
|
+
isBun,
|
|
80
|
+
isCloudflare,
|
|
81
|
+
isDeno,
|
|
82
|
+
isEdge,
|
|
83
|
+
isNode,
|
|
84
|
+
isServer,
|
|
85
|
+
runtime,
|
|
86
|
+
runtimeInfo
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime.ts"],"sourcesContent":["/**\n * @parsrun/core - Runtime Detection\n * Edge-compatible runtime detection for Node.js, Deno, Bun, and Cloudflare Workers\n */\n\nexport type Runtime = \"node\" | \"deno\" | \"bun\" | \"cloudflare\" | \"edge\" | \"browser\" | \"unknown\";\n\n/**\n * Detect the current JavaScript runtime\n */\nexport function detectRuntime(): Runtime {\n // Bun check (must be before Node since Bun also has process)\n if (typeof globalThis !== \"undefined\" && \"Bun\" in globalThis) {\n return \"bun\";\n }\n\n // Deno check\n if (typeof globalThis !== \"undefined\" && \"Deno\" in globalThis) {\n return \"deno\";\n }\n\n // Cloudflare Workers check (has caches but no process)\n if (\n typeof globalThis !== \"undefined\" &&\n typeof (globalThis as any).caches !== \"undefined\" &&\n typeof (globalThis as any).process === \"undefined\"\n ) {\n return \"cloudflare\";\n }\n\n // Generic Edge runtime check (Vercel Edge, etc.)\n if (\n typeof globalThis !== \"undefined\" &&\n typeof (globalThis as any).EdgeRuntime !== \"undefined\"\n ) {\n return \"edge\";\n }\n\n // Browser check\n if (\n typeof globalThis !== \"undefined\" &&\n typeof (globalThis as any).window !== \"undefined\" &&\n typeof (globalThis as any).document !== \"undefined\"\n ) {\n return \"browser\";\n }\n\n // Node.js check\n if (\n typeof process !== \"undefined\" &&\n process.versions &&\n process.versions.node\n ) {\n return \"node\";\n }\n\n return \"unknown\";\n}\n\n/**\n * Current runtime (cached)\n */\nexport const runtime = detectRuntime();\n\n/**\n * Runtime information helpers\n */\nexport const runtimeInfo = {\n runtime,\n isNode: runtime === \"node\",\n isDeno: runtime === \"deno\",\n isBun: runtime === \"bun\",\n isCloudflare: runtime === \"cloudflare\",\n isEdge: runtime === \"cloudflare\" || runtime === \"edge\" || runtime === \"deno\",\n isBrowser: runtime === \"browser\",\n isServer: runtime !== \"browser\",\n supportsWebCrypto: typeof globalThis.crypto?.subtle !== \"undefined\",\n supportsStreams: typeof globalThis.ReadableStream !== \"undefined\",\n} as const;\n\n/**\n * Check if running in Node.js\n */\nexport function isNode(): boolean {\n return runtime === \"node\";\n}\n\n/**\n * Check if running in Deno\n */\nexport function isDeno(): boolean {\n return runtime === \"deno\";\n}\n\n/**\n * Check if running in Bun\n */\nexport function isBun(): boolean {\n return runtime === \"bun\";\n}\n\n/**\n * Check if running in Cloudflare Workers\n */\nexport function isCloudflare(): boolean {\n return runtime === \"cloudflare\";\n}\n\n/**\n * Check if running in any edge environment\n */\nexport function isEdge(): boolean {\n return runtimeInfo.isEdge;\n}\n\n/**\n * Check if running in browser\n */\nexport function isBrowser(): boolean {\n return runtime === \"browser\";\n}\n\n/**\n * Check if running on server (not browser)\n */\nexport function isServer(): boolean {\n return runtimeInfo.isServer;\n}\n\n/**\n * Get runtime version string\n */\nexport function getRuntimeVersion(): string {\n switch (runtime) {\n case \"node\":\n return `Node.js ${process.versions.node}`;\n case \"bun\":\n return `Bun ${(globalThis as any).Bun.version}`;\n case \"deno\":\n return `Deno ${(globalThis as any).Deno.version.deno}`;\n case \"cloudflare\":\n return \"Cloudflare Workers\";\n case \"edge\":\n return \"Edge Runtime\";\n case \"browser\":\n return typeof navigator !== \"undefined\" ? navigator.userAgent : \"Browser\";\n default:\n return \"Unknown\";\n }\n}\n"],"mappings":";AAUO,SAAS,gBAAyB;AAEvC,MAAI,OAAO,eAAe,eAAe,SAAS,YAAY;AAC5D,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,eAAe,eAAe,UAAU,YAAY;AAC7D,WAAO;AAAA,EACT;AAGA,MACE,OAAO,eAAe,eACtB,OAAQ,WAAmB,WAAW,eACtC,OAAQ,WAAmB,YAAY,aACvC;AACA,WAAO;AAAA,EACT;AAGA,MACE,OAAO,eAAe,eACtB,OAAQ,WAAmB,gBAAgB,aAC3C;AACA,WAAO;AAAA,EACT;AAGA,MACE,OAAO,eAAe,eACtB,OAAQ,WAAmB,WAAW,eACtC,OAAQ,WAAmB,aAAa,aACxC;AACA,WAAO;AAAA,EACT;AAGA,MACE,OAAO,YAAY,eACnB,QAAQ,YACR,QAAQ,SAAS,MACjB;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKO,IAAM,UAAU,cAAc;AAK9B,IAAM,cAAc;AAAA,EACzB;AAAA,EACA,QAAQ,YAAY;AAAA,EACpB,QAAQ,YAAY;AAAA,EACpB,OAAO,YAAY;AAAA,EACnB,cAAc,YAAY;AAAA,EAC1B,QAAQ,YAAY,gBAAgB,YAAY,UAAU,YAAY;AAAA,EACtE,WAAW,YAAY;AAAA,EACvB,UAAU,YAAY;AAAA,EACtB,mBAAmB,OAAO,WAAW,QAAQ,WAAW;AAAA,EACxD,iBAAiB,OAAO,WAAW,mBAAmB;AACxD;AAKO,SAAS,SAAkB;AAChC,SAAO,YAAY;AACrB;AAKO,SAAS,SAAkB;AAChC,SAAO,YAAY;AACrB;AAKO,SAAS,QAAiB;AAC/B,SAAO,YAAY;AACrB;AAKO,SAAS,eAAwB;AACtC,SAAO,YAAY;AACrB;AAKO,SAAS,SAAkB;AAChC,SAAO,YAAY;AACrB;AAKO,SAAS,YAAqB;AACnC,SAAO,YAAY;AACrB;AAKO,SAAS,WAAoB;AAClC,SAAO,YAAY;AACrB;AAKO,SAAS,oBAA4B;AAC1C,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,aAAO,WAAW,QAAQ,SAAS,IAAI;AAAA,IACzC,KAAK;AACH,aAAO,OAAQ,WAAmB,IAAI,OAAO;AAAA,IAC/C,KAAK;AACH,aAAO,QAAS,WAAmB,KAAK,QAAQ,IAAI;AAAA,IACtD,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,OAAO,cAAc,cAAc,UAAU,YAAY;AAAA,IAClE;AACE,aAAO;AAAA,EACX;AACF;","names":[]}
|