UNPKG

@maximai/maxim-js

Version:

Maxim AI JS SDK. Visit https://getmaxim.ai for more info.

225 lines 6.85 kB
"use strict"; /* * React Native platform adapter. Avoids Node built-ins and provides safe * fallbacks. File IO and CSV are disabled by default. Randomness prefers * expo-crypto when available, falling back to Math.random-based polyfill. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.reactNativeAdapter = void 0; // Lazy import for expo-crypto if present let expoCryptoRandomBytes = null; let expoCryptoAvailable = false; try { // eslint-disable-next-line @typescript-eslint/no-var-requires const expoCrypto = require("expo-crypto"); if (expoCrypto && typeof expoCrypto.getRandomBytesAsync === "function") { // Store sync wrapper for expo-crypto async function expoCryptoRandomBytes = (size) => { // For sync usage, we'll need to implement a cache or use different approach // For now, throw error indicating async version should be used throw new Error("expo-crypto requires async usage. Use platform.crypto.randomBytesAsync() instead."); }; expoCryptoAvailable = true; } } catch { // expo-crypto not available } const timers = { setInterval: (handler, ms) => setInterval(handler, ms), clearInterval: (handle) => clearInterval(handle), maybeUnref: (_handle) => { // No-op on RN; handle is a number }, }; const rnFs = { hasAccessToFilesystem() { // Assume /tmp-like access is not standard in RN; disable return false; }, existsSync(_p) { return false; }, mkdirpSync(_p) { // no-op }, async readFile(_p) { return { data: new Uint8Array() }; }, readFileSync(_p) { return new Uint8Array(); }, async writeFile(_p, _data) { // no-op }, readdirSync(_p) { return []; }, rmSync(_p) { // no-op }, statSync(_p) { return { size: 0 }; }, }; const rnPath = { basename: (filePath) => filePath.split("/").pop() || filePath, extname: (filePath) => { const idx = filePath.lastIndexOf("."); return idx >= 0 ? filePath.slice(idx) : ""; }, join: (...parts) => parts.join("/").replace(/\/+/, "/"), }; const rnMime = { lookup: (filePath) => { const ext = (filePath.split(".").pop() || "").toLowerCase(); const map = { jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif", pdf: "application/pdf", txt: "text/plain", json: "application/json", html: "text/html", css: "text/css", js: "application/javascript", zip: "application/zip", csv: "text/csv", }; return map[ext] || false; }, }; const net = { httpAgent: (_options) => { // Axios uses native stack on RN; no agents needed return undefined; }, httpsAgent: (_options) => { return undefined; }, }; function insecureRandomBytes(size) { const bytes = new Uint8Array(size); for (let i = 0; i < size; i++) bytes[i] = Math.floor(Math.random() * 256); return bytes; } function toUtf8Bytes(input) { if (typeof input !== "string") return input; if (typeof TextEncoder !== "undefined") return new TextEncoder().encode(input); // Fallback: naive UTF-8 encode const utf8 = []; for (let i = 0; i < input.length; i++) { const c = input.charCodeAt(i); if (c < 0x80) utf8.push(c); else if (c < 0x800) utf8.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f)); else utf8.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f)); } return new Uint8Array(utf8); } function simpleHashHex(input) { // 32-bit FNV-1a repeated to produce 128-bit hex (non-crypto) const bytes = toUtf8Bytes(input); const fnv = (seed) => { let h = seed >>> 0; for (let i = 0; i < bytes.length; i++) { h ^= bytes[i]; h = Math.imul(h, 0x01000193); } return (h >>> 0).toString(16).padStart(8, "0"); }; return fnv(0x811c9dc5) + fnv(0x811c9dc5 ^ 0xdeadbeef) + fnv(0x811c9dc5 ^ 0xa5a5a5a5) + fnv(0x811c9dc5 ^ 0x12345678); } async function secureRandomBytesAsync(size) { if (expoCryptoAvailable) { try { // eslint-disable-next-line @typescript-eslint/no-var-requires const expoCrypto = require("expo-crypto"); const result = await expoCrypto.getRandomBytesAsync(size); return new Uint8Array(result); } catch (error) { console.warn("[Maxim-SDK] expo-crypto failed, falling back to insecure random:", error); } } return insecureRandomBytes(size); } const rnCrypto = { randomBytes: (size) => { // Synchronous version - falls back to insecure for compatibility // Recommend using randomBytesAsync for better security on RN if (expoCryptoAvailable) { console.warn("[Maxim-SDK] Using insecure randomBytes. Consider using platform.crypto.randomBytesAsync() for better security."); } return insecureRandomBytes(size); }, randomBytesAsync: secureRandomBytesAsync, createHash: (_algorithm) => ({ update: (data) => ({ digest: (_encoding) => simpleHashHex(data), }), }), hostname: () => "react-native-device", isSecureRandomAvailable: expoCryptoAvailable, }; const stream = { Transform: class Transform { constructor(options) { this.options = options; this._transform = options.transform; this._flush = options.flush; this._destroyed = false; } transform(chunk, encoding, callback) { if (this._destroyed) return; try { this._transform(chunk, encoding, callback); } catch (err) { callback(err); } } flush(callback) { if (this._destroyed) return; try { this._flush(callback); } catch (err) { callback(err); } } destroy() { this._destroyed = true; } pipe(destination) { // Simple pipe implementation for React Native return destination; } }, }; const features = { csvSupported: false, fileIoSupported: false, }; exports.reactNativeAdapter = { name: "react-native", fs: rnFs, path: rnPath, mime: rnMime, timers, net, crypto: rnCrypto, stream, tmpdir: () => "/tmp", features, }; exports.default = exports.reactNativeAdapter; //# sourceMappingURL=reactNative.js.map