BREAKING CHANGE(Smartenv): Add Deno and Bun runtime detection, introduce getSafeModuleFor API, update docs and tests, and make isNode semantics Node-only (breaking change)
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* autocreated commitinfo by @pushrocks/commitinfo
|
||||
* autocreated commitinfo by @push.rocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@push.rocks/smartenv',
|
||||
version: '5.0.12',
|
||||
description: 'store things about your environment and let them travel across modules'
|
||||
version: '6.0.0',
|
||||
description: 'A module for storing and accessing environment details across different platforms.'
|
||||
}
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
export let defaultme = null;
|
||||
|
||||
/**
|
||||
* Runtime type representing the detected JavaScript runtime environment
|
||||
*/
|
||||
export type TRuntimeType = 'node' | 'deno' | 'bun' | 'browser';
|
||||
|
||||
/**
|
||||
* Runtime target for module loading - can be a specific runtime or 'server' for all server-side runtimes
|
||||
*/
|
||||
export type TRuntimeTarget = TRuntimeType | 'server';
|
||||
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface Global {
|
||||
|
||||
@@ -31,8 +31,8 @@ export class Smartenv {
|
||||
}
|
||||
|
||||
public async getSafeNodeModule<T = any>(moduleNameArg: string, runAfterFunc?: (moduleArg: T) => Promise<any>): Promise<T> {
|
||||
if (!this.isNode) {
|
||||
console.error(`You tried to load a node module in a wrong context: ${moduleNameArg}. This does not throw.`);
|
||||
if (!this.isNode && !this.isDeno && !this.isBun) {
|
||||
console.error(`You tried to load a server module in a wrong context: ${moduleNameArg}. This does not throw.`);
|
||||
return;
|
||||
}
|
||||
// tslint:disable-next-line: function-constructor
|
||||
@@ -72,16 +72,49 @@ export class Smartenv {
|
||||
return getFunctionArg();
|
||||
}
|
||||
|
||||
public get runtimeEnv() {
|
||||
if (typeof process !== 'undefined') {
|
||||
public get runtimeEnv(): interfaces.TRuntimeType {
|
||||
// Check Deno first (most distinctive)
|
||||
if (typeof globalThis.Deno !== 'undefined' &&
|
||||
typeof (globalThis as any).Deno?.version !== 'undefined') {
|
||||
return 'deno';
|
||||
}
|
||||
|
||||
// Check Bun second (most distinctive)
|
||||
if (typeof globalThis.Bun !== 'undefined' &&
|
||||
typeof (globalThis as any).Bun?.version !== 'undefined') {
|
||||
return 'bun';
|
||||
}
|
||||
|
||||
// Check Node.js (be explicit about versions to avoid Deno/Bun false positives)
|
||||
if (typeof globalThis.process !== 'undefined' &&
|
||||
typeof (globalThis as any).process?.versions?.node !== 'undefined') {
|
||||
return 'node';
|
||||
} else {
|
||||
}
|
||||
|
||||
// Check Browser (default fallback)
|
||||
if (typeof globalThis.window !== 'undefined' &&
|
||||
typeof (globalThis as any).document !== 'undefined') {
|
||||
return 'browser';
|
||||
}
|
||||
|
||||
// Safe fallback
|
||||
return 'browser';
|
||||
}
|
||||
|
||||
public get isBrowser(): boolean {
|
||||
return !this.isNode;
|
||||
return this.runtimeEnv === 'browser';
|
||||
}
|
||||
|
||||
public get isNode(): boolean {
|
||||
return this.runtimeEnv === 'node';
|
||||
}
|
||||
|
||||
public get isDeno(): boolean {
|
||||
return this.runtimeEnv === 'deno';
|
||||
}
|
||||
|
||||
public get isBun(): boolean {
|
||||
return this.runtimeEnv === 'bun';
|
||||
}
|
||||
|
||||
public get userAgent(): string {
|
||||
@@ -93,12 +126,77 @@ export class Smartenv {
|
||||
}
|
||||
}
|
||||
|
||||
public get isNode(): boolean {
|
||||
return this.runtimeEnv === 'node';
|
||||
public get nodeVersion(): string {
|
||||
if (this.isNode) {
|
||||
return process.version;
|
||||
}
|
||||
return 'undefined';
|
||||
}
|
||||
|
||||
public get nodeVersion(): string {
|
||||
return process.version;
|
||||
public get denoVersion(): string {
|
||||
if (this.isDeno) {
|
||||
return (globalThis as any).Deno.version.deno;
|
||||
}
|
||||
return 'undefined';
|
||||
}
|
||||
|
||||
public get bunVersion(): string {
|
||||
if (this.isBun) {
|
||||
return (globalThis as any).Bun.version;
|
||||
}
|
||||
return 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a module only if the current runtime matches the target runtime(s)
|
||||
* @param target - Single runtime, array of runtimes, or 'server' for all server-side runtimes
|
||||
* @param moduleNameOrUrl - Module name (for Node/Deno/Bun) or URL (for browser)
|
||||
* @param getFunction - Optional function to retrieve the module in browser context
|
||||
* @returns The loaded module or undefined if runtime doesn't match
|
||||
*/
|
||||
public async getSafeModuleFor<T = any>(
|
||||
target: interfaces.TRuntimeTarget | interfaces.TRuntimeTarget[],
|
||||
moduleNameOrUrl: string,
|
||||
getFunction?: () => any
|
||||
): Promise<T | undefined> {
|
||||
// Normalize target to array
|
||||
let targetRuntimes: interfaces.TRuntimeType[];
|
||||
|
||||
if (Array.isArray(target)) {
|
||||
// Expand 'server' if present in array
|
||||
targetRuntimes = target.flatMap(t =>
|
||||
t === 'server' ? ['node', 'deno', 'bun'] as interfaces.TRuntimeType[] : [t as interfaces.TRuntimeType]
|
||||
);
|
||||
} else if (target === 'server') {
|
||||
targetRuntimes = ['node', 'deno', 'bun'];
|
||||
} else {
|
||||
targetRuntimes = [target];
|
||||
}
|
||||
|
||||
// Check if current runtime matches any target
|
||||
if (!targetRuntimes.includes(this.runtimeEnv)) {
|
||||
console.warn(
|
||||
`Module "${moduleNameOrUrl}" requested for runtime(s) [${targetRuntimes.join(', ')}] ` +
|
||||
`but current runtime is "${this.runtimeEnv}". Skipping load.`
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Load based on current runtime
|
||||
if (this.isNode || this.isDeno || this.isBun) {
|
||||
// Server-side runtimes use dynamic import
|
||||
const moduleResult = await this.getSafeNodeModule<T>(moduleNameOrUrl);
|
||||
return moduleResult;
|
||||
} else if (this.isBrowser) {
|
||||
if (!getFunction) {
|
||||
console.error(`Browser module load requires getFunction parameter for "${moduleNameOrUrl}"`);
|
||||
return undefined;
|
||||
}
|
||||
const moduleResult = await this.getSafeWebModule(moduleNameOrUrl, getFunction);
|
||||
return moduleResult as T;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public get isCI(): boolean {
|
||||
@@ -147,6 +245,12 @@ export class Smartenv {
|
||||
if (this.isNode) {
|
||||
console.log('running on NODE');
|
||||
console.log('node version is ' + this.nodeVersion);
|
||||
} else if (this.isDeno) {
|
||||
console.log('running on DENO');
|
||||
console.log('deno version is ' + this.denoVersion);
|
||||
} else if (this.isBun) {
|
||||
console.log('running on BUN');
|
||||
console.log('bun version is ' + this.bunVersion);
|
||||
} else {
|
||||
console.log('running on BROWSER');
|
||||
console.log('browser is ' + this.userAgent);
|
||||
|
||||
Reference in New Issue
Block a user