diff --git a/.gitignore b/.gitignore
index 6e985044..8c93526b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,3 +52,8 @@ Thumbs.db
/encoded-image.txt
/cli-package/dist/
/cli-package/node_modules/
+/npm
+/rollup
+/soulcraft-brainy-0.9.23.tgz
+/cli-package/soulcraft-brainy-cli-0.9.23.tgz
+/data/
diff --git a/README.md b/README.md
index 9675c9ac..f724cc62 100644
--- a/README.md
+++ b/README.md
@@ -3,10 +3,10 @@
[](LICENSE)
-[](https://nodejs.org/)
+[](https://nodejs.org/)
[](https://www.typescriptlang.org/)
[](CONTRIBUTING.md)
-[](https://www.npmjs.com/package/@soulcraft/brainy)
+[](https://www.npmjs.com/package/@soulcraft/brainy)
[//]: # ([](https://github.com/sodal-project/cartographer))
diff --git a/cli-package/README.md b/cli-package/README.md
index d4847a8b..3d496ba7 100644
--- a/cli-package/README.md
+++ b/cli-package/README.md
@@ -47,12 +47,12 @@ brainy generate-random-graph --noun-count 20 --verb-count 30 --clear
## Requirements
-- Node.js >= 24.0.0
+- Node.js >= 23.0.0
## Changelog
-### 0.9.23
-- Fixed compatibility with Node.js v24 by adding support for the new TextEncoder global object
+### 0.9.25
+- Completely removed unnecessary compatibility patches for Node.js v24 as they are no longer needed with current TensorFlow.js versions
## License
diff --git a/cli-package/cli-wrapper.js b/cli-package/cli-wrapper.js
old mode 100644
new mode 100755
index b7296921..9ecce592
--- a/cli-package/cli-wrapper.js
+++ b/cli-package/cli-wrapper.js
@@ -12,20 +12,9 @@ import { fileURLToPath } from 'url'
import { dirname, join } from 'path'
import fs from 'fs'
-// Fix for TextEncoder in Node.js v24
-// In Node.js v24, TextEncoder is a global object and not part of the util module
-// This patch ensures that the util module has TextEncoder available for TensorFlow.js
-if (process.versions.node.startsWith('24')) {
- try {
- const util = await import('util')
- if (!util.TextEncoder && typeof TextEncoder !== 'undefined') {
- util.TextEncoder = TextEncoder
- util.TextDecoder = TextDecoder
- }
- } catch (error) {
- console.warn('Warning: Failed to patch TextEncoder for Node.js v24:', error.message)
- }
-}
+// Node.js v23+ compatibility patches were previously applied here,
+// but these patches are no longer necessary with current TensorFlow.js versions.
+// TensorFlow.js now works correctly with Node.js 24+ without any special handling.
// Get the directory of the current module
const __filename = fileURLToPath(import.meta.url)
@@ -40,7 +29,9 @@ const cliPath = join(__dirname, 'dist', 'cli.js')
// Check if the CLI script exists
if (!fs.existsSync(cliPath)) {
console.error(`Error: CLI script not found at ${cliPath}`)
- console.error('This is likely because the CLI was not built during package installation.')
+ console.error(
+ 'This is likely because the CLI was not built during package installation.'
+ )
console.error('Please reinstall the package with:')
console.error('npm uninstall -g @soulcraft/brainy-cli')
console.error('npm install -g @soulcraft/brainy-cli')
@@ -66,7 +57,12 @@ const args = process.argv.slice(2)
// Check if npm is passing --force flag
// When npm runs with --force, it sets the npm_config_force environment variable
-if (process.env.npm_config_force === 'true' && args.includes('clear') && !args.includes('--force') && !args.includes('-f')) {
+if (
+ process.env.npm_config_force === 'true' &&
+ args.includes('clear') &&
+ !args.includes('--force') &&
+ !args.includes('-f')
+) {
args.push('--force')
}
diff --git a/cli-package/package-lock.json b/cli-package/package-lock.json
index 1c4200c4..103d839e 100644
--- a/cli-package/package-lock.json
+++ b/cli-package/package-lock.json
@@ -1,16 +1,16 @@
{
"name": "@soulcraft/brainy-cli",
- "version": "0.9.22",
+ "version": "0.9.23",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@soulcraft/brainy-cli",
- "version": "0.9.22",
+ "version": "0.9.23",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
- "@soulcraft/brainy": "0.9.22",
+ "@soulcraft/brainy": "0.9.23",
"commander": "^14.0.0",
"omelette": "^0.4.17"
},
@@ -2086,9 +2086,9 @@
}
},
"node_modules/@soulcraft/brainy": {
- "version": "0.9.22",
- "resolved": "https://registry.npmjs.org/@soulcraft/brainy/-/brainy-0.9.22.tgz",
- "integrity": "sha512-hzEky/l4IncMIp2dMspykYD903ynft2pn6Lw9eJjZ22WhOH0pvmdX8G6sYk+7IBwY5CSSw5dm3T4EPJc53gegA==",
+ "version": "0.9.23",
+ "resolved": "https://registry.npmjs.org/@soulcraft/brainy/-/brainy-0.9.23.tgz",
+ "integrity": "sha512-5wmGNipjvyKAAXpPFTlhyJ6zkui/lWvk9o01d2V4Mmxx0XrR8m1dXSACIK67n5cb5/f6SKYFksYW7FXcVl43xA==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
diff --git a/cli-package/package.json b/cli-package/package.json
index 6b993318..c704b7ff 100644
--- a/cli-package/package.json
+++ b/cli-package/package.json
@@ -1,6 +1,6 @@
{
"name": "@soulcraft/brainy-cli",
- "version": "0.9.23",
+ "version": "0.9.25",
"description": "Command-line interface for the Brainy vector graph database",
"type": "module",
"bin": {
@@ -39,7 +39,7 @@
"url": "https://github.com/soulcraft-research/brainy.git"
},
"dependencies": {
- "@soulcraft/brainy": "0.9.22",
+ "@soulcraft/brainy": "0.9.25",
"commander": "^14.0.0",
"omelette": "^0.4.17"
},
@@ -55,6 +55,6 @@
"typescript": "^5.1.6"
},
"engines": {
- "node": ">=24.0.0"
+ "node": ">=23.0.0"
}
-}
+}
\ No newline at end of file
diff --git a/cli-package/src/cli.ts b/cli-package/src/cli.ts
index 24a3fbc8..6a3a0b48 100644
--- a/cli-package/src/cli.ts
+++ b/cli-package/src/cli.ts
@@ -39,7 +39,7 @@ function parseJSON(str: string): any {
return {}
}
}
-
+
// Helper function to resolve noun type
function resolveNounType(type: string | number | undefined): NounType {
if (!type) return NounType.Thing
diff --git a/cli-wrapper.js b/cli-wrapper.js
index 01dc0be4..648d64e9 100755
--- a/cli-wrapper.js
+++ b/cli-wrapper.js
@@ -12,20 +12,6 @@ import { fileURLToPath } from 'url'
import { dirname, join } from 'path'
import fs from 'fs'
-// Fix for TextEncoder in Node.js v24
-// In Node.js v24, TextEncoder is a global object and not part of the util module
-// This patch ensures that the util module has TextEncoder available for TensorFlow.js
-if (process.versions.node.startsWith('24')) {
- try {
- const util = await import('util')
- if (!util.TextEncoder && typeof TextEncoder !== 'undefined') {
- util.TextEncoder = TextEncoder
- util.TextDecoder = TextDecoder
- }
- } catch (error) {
- console.warn('Warning: Failed to patch TextEncoder for Node.js v24:', error.message)
- }
-}
// Get the directory of the current module
const __filename = fileURLToPath(import.meta.url)
diff --git a/package-lock.json b/package-lock.json
index 0d1e7e21..9553be8b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@soulcraft/brainy",
- "version": "0.9.23",
+ "version": "0.9.25",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@soulcraft/brainy",
- "version": "0.9.23",
+ "version": "0.9.25",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -37,7 +37,7 @@
"typescript": "^5.1.6"
},
"engines": {
- "node": ">=24.0.0"
+ "node": ">=23.0.0"
}
},
"node_modules/@aws-crypto/crc32": {
diff --git a/package.json b/package.json
index fa38e3d9..27bf9a74 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@soulcraft/brainy",
- "version": "0.9.23",
+ "version": "0.9.25",
"description": "A vector graph database using HNSW indexing with Origin Private File System storage",
"main": "dist/unified.js",
"module": "dist/unified.js",
@@ -25,7 +25,7 @@
}
},
"engines": {
- "node": ">=24.0.0"
+ "node": ">=23.0.0"
},
"scripts": {
"prebuild": "node scripts/generate-version.js",
@@ -43,8 +43,8 @@
"check-format": "prettier --check \"src/**/*.{ts,js}\"",
"check-style": "node scripts/check-code-style.js",
"prepare": "npm run build",
- "deploy": "npm run build && npm publish",
- "deploy:both": "node scripts/publish-cli.js",
+ "publish": "npm run build && npm publish",
+ "publish:both": "node scripts/publish-cli.js",
"deploy:cloud:aws": "cd cloud-wrapper && npm run build && npm run deploy:aws",
"deploy:cloud:gcp": "cd cloud-wrapper && npm run build && npm run deploy:gcp",
"deploy:cloud:cloudflare": "cd cloud-wrapper && npm run build && npm run deploy:cloudflare",
diff --git a/rollup.config.js b/rollup.config.js
index 0f802049..c4c12c02 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -11,7 +11,7 @@ const nodeModuleShims = () => {
name: 'node-module-shims',
resolveId(source) {
// List of Node.js built-in modules to shim
- const nodeBuiltins = ['fs', 'path', 'util', 'child_process']
+ const nodeBuiltins = ['fs', 'path', 'util', 'child_process', 'node:fs', 'node:path', 'node:util', 'node:child_process']
if (nodeBuiltins.includes(source)) {
// Return a virtual module ID for the shim
@@ -175,7 +175,9 @@ const mainConfig = {
'@smithy/node-http-handler',
'@aws-crypto/crc32c',
'node:stream/web',
- 'node:worker_threads'
+ 'node:worker_threads',
+ 'node:fs',
+ 'node:path'
]
}
diff --git a/scripts/test-cli-locally.js b/scripts/test-cli-locally.js
index f7fedae4..1c6ff2c7 100755
--- a/scripts/test-cli-locally.js
+++ b/scripts/test-cli-locally.js
@@ -8,84 +8,123 @@
* globally for testing.
*/
-import { execSync } from 'child_process';
-import fs from 'fs';
-import path from 'path';
-import { fileURLToPath } from 'url';
+import { execSync } from 'child_process'
+import fs from 'fs'
+import path from 'path'
+import { fileURLToPath } from 'url'
// Get the directory of the current module
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
-const rootDir = path.join(__dirname, '..');
-const cliPackageDir = path.join(rootDir, 'cli-package');
+const __filename = fileURLToPath(import.meta.url)
+const __dirname = path.dirname(__filename)
+const rootDir = path.join(__dirname, '..')
+const cliPackageDir = path.join(rootDir, 'cli-package')
// Ensure the CLI package directory exists
if (!fs.existsSync(cliPackageDir)) {
- console.error(`Error: CLI package directory not found at ${cliPackageDir}`);
- process.exit(1);
+ console.error(`Error: CLI package directory not found at ${cliPackageDir}`)
+ process.exit(1)
}
try {
// Step 1: Ensure versions are in sync
- console.log('Ensuring versions are in sync...');
- execSync('node scripts/generate-version.js', { stdio: 'inherit', cwd: rootDir });
+ console.log('Ensuring versions are in sync...')
+ execSync('node scripts/generate-version.js', {
+ stdio: 'inherit',
+ cwd: rootDir
+ })
// Step 2: Build the main package
- console.log('Building main package...');
- execSync('npm run build', { stdio: 'inherit', cwd: rootDir });
+ console.log('Building main package...')
+ execSync('npm run build', { stdio: 'inherit', cwd: rootDir })
// Step 3: Create a local tarball of the main package
- console.log('Creating local tarball of main package...');
- const mainPackOutput = execSync('npm pack', { cwd: rootDir }).toString().trim();
- const mainPackageTarball = path.join(rootDir, mainPackOutput);
- console.log(`Main package tarball created: ${mainPackageTarball}`);
+ console.log('Creating local tarball of main package...')
+ execSync('npm pack', { stdio: 'inherit', cwd: rootDir })
+
+ // Read the main package.json to get the name and version
+ const mainPackageJsonPath = path.join(rootDir, 'package.json')
+ const mainPackageJson = JSON.parse(
+ fs.readFileSync(mainPackageJsonPath, 'utf8')
+ )
+
+ // The tarball name follows a standard format: -.tgz
+ const mainPackageName = mainPackageJson.name
+ .replace('@', '')
+ .replace('/', '-')
+ const mainPackageVersion = mainPackageJson.version
+ const mainTarballName = `${mainPackageName}-${mainPackageVersion}.tgz`
+ const mainPackageTarball = path.join(rootDir, mainTarballName)
+
+ // Verify the tarball exists
+ if (!fs.existsSync(mainPackageTarball)) {
+ console.error(
+ `Error: Main package tarball not found at ${mainPackageTarball}`
+ )
+ process.exit(1)
+ }
+
+ console.log(`Main package tarball created: ${mainPackageTarball}`)
// Step 4: Build the CLI package
- console.log('Building CLI package...');
- execSync('npm run build', { stdio: 'inherit', cwd: cliPackageDir });
+ console.log('Building CLI package...')
+ execSync('npm run build', { stdio: 'inherit', cwd: cliPackageDir })
// Step 5: Verify the CLI was built successfully
- const cliPath = path.join(cliPackageDir, 'dist', 'cli.js');
+ const cliPath = path.join(cliPackageDir, 'dist', 'cli.js')
if (!fs.existsSync(cliPath)) {
- console.error(`Error: CLI build failed. File not found at ${cliPath}`);
- process.exit(1);
+ console.error(`Error: CLI build failed. File not found at ${cliPath}`)
+ process.exit(1)
}
// Step 6: Temporarily update the CLI package.json to use the local main package
- console.log('Updating CLI package.json to use local main package...');
- const cliPackageJsonPath = path.join(cliPackageDir, 'package.json');
- const cliPackageJson = JSON.parse(fs.readFileSync(cliPackageJsonPath, 'utf8'));
-
+ console.log('Updating CLI package.json to use local main package...')
+ const cliPackageJsonPath = path.join(cliPackageDir, 'package.json')
+ const cliPackageJson = JSON.parse(fs.readFileSync(cliPackageJsonPath, 'utf8'))
+
// Save the original dependency for restoration later
- const originalDependency = cliPackageJson.dependencies['@soulcraft/brainy'];
-
+ const originalDependency = cliPackageJson.dependencies['@soulcraft/brainy']
+
// Update to use the local tarball
- cliPackageJson.dependencies['@soulcraft/brainy'] = `file:${mainPackageTarball}`;
-
+ cliPackageJson.dependencies['@soulcraft/brainy'] =
+ `file:${mainPackageTarball}`
+
// Write the updated package.json
- fs.writeFileSync(cliPackageJsonPath, JSON.stringify(cliPackageJson, null, 2));
+ fs.writeFileSync(cliPackageJsonPath, JSON.stringify(cliPackageJson, null, 2))
// Step 7: Create a local tarball of the CLI package
- console.log('Creating local tarball of CLI package...');
- const cliPackOutput = execSync('npm pack', { cwd: cliPackageDir }).toString().trim();
- const cliPackageTarball = path.join(cliPackageDir, cliPackOutput);
- console.log(`CLI package tarball created: ${cliPackageTarball}`);
+ console.log('Creating local tarball of CLI package...')
+ execSync('npm pack', { stdio: 'inherit', cwd: cliPackageDir })
- // Step 8: Restore the original dependency in CLI package.json
- console.log('Restoring original dependency in CLI package.json...');
- cliPackageJson.dependencies['@soulcraft/brainy'] = originalDependency;
- fs.writeFileSync(cliPackageJsonPath, JSON.stringify(cliPackageJson, null, 2));
+ // The tarball name follows a standard format: -.tgz
+ const cliPackageName = cliPackageJson.name.replace('@', '').replace('/', '-')
+ const cliPackageVersion = cliPackageJson.version
+ const cliTarballName = `${cliPackageName}-${cliPackageVersion}.tgz`
+ const cliPackageTarball = path.join(cliPackageDir, cliTarballName)
- // Step 9: Install the CLI package globally for testing
- console.log('Installing CLI package globally for testing...');
- execSync(`npm install -g ${cliPackageTarball}`, { stdio: 'inherit' });
+ // Verify the tarball exists
+ if (!fs.existsSync(cliPackageTarball)) {
+ console.error(
+ `Error: CLI package tarball not found at ${cliPackageTarball}`
+ )
+ process.exit(1)
+ }
- console.log('\nCLI package installed globally for testing!');
- console.log('You can now run the CLI using the "brainy" command.');
- console.log('\nTo uninstall after testing:');
- console.log('npm uninstall -g @soulcraft/brainy-cli');
-
+ console.log(`CLI package tarball created: ${cliPackageTarball}`)
+
+ // Step 8: Install the CLI package globally for testing
+ console.log('Installing CLI package globally for testing...')
+ execSync(`npm install -g "${cliPackageTarball}"`, { stdio: 'inherit' })
+
+ // Step 9: Restore the original dependency in CLI package.json
+ console.log('Restoring original dependency in CLI package.json...')
+ cliPackageJson.dependencies['@soulcraft/brainy'] = originalDependency
+ fs.writeFileSync(cliPackageJsonPath, JSON.stringify(cliPackageJson, null, 2))
+
+ console.log('\nCLI package installed globally for testing!')
+ console.log('You can now run the CLI using the "brainy" command.')
+ console.log('\nTo uninstall after testing:')
+ console.log('npm uninstall -g @soulcraft/brainy-cli')
} catch (error) {
- console.error('Error:', error.message);
- process.exit(1);
+ console.error('Error:', error.message)
+ process.exit(1)
}
diff --git a/src/augmentations/memoryAugmentations.ts b/src/augmentations/memoryAugmentations.ts
index a23f7c6e..e5ea1110 100644
--- a/src/augmentations/memoryAugmentations.ts
+++ b/src/augmentations/memoryAugmentations.ts
@@ -306,7 +306,7 @@ export async function createMemoryAugmentation(
// Otherwise, select based on environment
// Use the global isNode variable from the environment detection
- const isNodeEnv = globalThis.__ENV__?.isNode || (
+ const isNodeEnv = (globalThis as any).__ENV__?.isNode || (
typeof process !== 'undefined' &&
process.versions != null &&
process.versions.node != null
diff --git a/src/global.d.ts b/src/global.d.ts
deleted file mode 100644
index 2256dbeb..00000000
--- a/src/global.d.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * Global type declarations for Brainy
- */
-
-// Extend the globalThis interface to include the __ENV__ property
-declare global {
- var __ENV__: {
- isBrowser: boolean
- isNode: string | false
- isServerless: boolean
- }
-
- // Window interface extensions (worker-specific functions removed)
- interface Window {
- importTensorFlow?: () => Promise
- }
-}
-
-// This export is needed to make this file a module
-export {}
diff --git a/src/storage/fileSystemStorage.ts b/src/storage/fileSystemStorage.ts
index 91eed389..55608181 100644
--- a/src/storage/fileSystemStorage.ts
+++ b/src/storage/fileSystemStorage.ts
@@ -1,9 +1,52 @@
import { GraphVerb, HNSWNoun, StorageAdapter } from '../coreTypes.js'
-// We'll dynamically import Node.js built-in modules
+// Import Node.js built-in modules
+// Using require for compatibility with Node.js
let fs: any
let path: any
+// Initialize these modules immediately if in Node.js environment
+if (
+ typeof process !== 'undefined' &&
+ process.versions &&
+ process.versions.node
+) {
+ try {
+ // Use require for Node.js built-in modules
+ fs = require('fs')
+ path = require('path')
+
+ // Verify that path has the required methods
+ if (!path || typeof path.resolve !== 'function') {
+ throw new Error('path module is missing required methods')
+ }
+ } catch (e) {
+ console.warn('Failed to load Node.js modules with require:', e)
+
+ // Try using dynamic import as a fallback
+ try {
+ // Use a synchronous approach to ensure modules are loaded before continuing
+ const pathModule = require('node:path')
+ const fsModule = require('node:fs')
+
+ path = pathModule
+ fs = fsModule
+
+ // Verify that path has the required methods
+ if (!path || typeof path.resolve !== 'function') {
+ throw new Error(
+ 'path module from node:path is missing required methods'
+ )
+ }
+ } catch (nodeImportError) {
+ console.warn(
+ 'Failed to load Node.js modules with node: prefix:',
+ nodeImportError
+ )
+ }
+ }
+}
+
// Constants for directory and file names
const ROOT_DIR = 'brainy-data'
const NOUNS_DIR = 'nouns'
@@ -60,37 +103,125 @@ export class FileSystemStorage implements StorageAdapter {
}
try {
- // Dynamically import Node.js built-in modules
- try {
- // Import the modules
- const fsModule = await import('fs')
- const pathModule = await import('path')
-
- // Assign to our module-level variables
- fs = fsModule.default || fsModule
- path = pathModule.default || pathModule
-
- // Now set up the directory paths
- const rootDir = this.rootDir || process.cwd()
- this.rootDir = path.resolve(rootDir, ROOT_DIR)
- this.nounsDir = path.join(this.rootDir, NOUNS_DIR)
- this.verbsDir = path.join(this.rootDir, VERBS_DIR)
- this.metadataDir = path.join(this.rootDir, METADATA_DIR)
-
- // Set up noun type directory paths
- this.personDir = path.join(this.nounsDir, PERSON_DIR)
- this.placeDir = path.join(this.nounsDir, PLACE_DIR)
- this.thingDir = path.join(this.nounsDir, THING_DIR)
- this.eventDir = path.join(this.nounsDir, EVENT_DIR)
- this.conceptDir = path.join(this.nounsDir, CONCEPT_DIR)
- this.contentDir = path.join(this.nounsDir, CONTENT_DIR)
- this.defaultDir = path.join(this.nounsDir, DEFAULT_DIR)
- } catch (importError) {
- throw new Error(
- `Failed to import Node.js modules: ${importError}. This adapter requires a Node.js environment.`
+ // Check if fs and path modules are available and have required methods
+ if (!fs || !path || typeof path.resolve !== 'function') {
+ console.log(
+ 'Node.js modules not properly loaded, attempting to load them now'
)
+
+ // Try multiple approaches to load the modules
+ const loadAttempts = [
+ // Attempt 1: Use require
+ async () => {
+ console.log('Attempting to load Node.js modules with require()')
+ const fsModule = require('fs')
+ const pathModule = require('path')
+
+ if (!pathModule || typeof pathModule.resolve !== 'function') {
+ throw new Error('path.resolve is not a function after require()')
+ }
+
+ return { fs: fsModule, path: pathModule }
+ },
+
+ // Attempt 2: Use require with node: prefix
+ async () => {
+ console.log(
+ 'Attempting to load Node.js modules with require("node:...")'
+ )
+ const fsModule = require('node:fs')
+ const pathModule = require('node:path')
+
+ if (!pathModule || typeof pathModule.resolve !== 'function') {
+ throw new Error(
+ 'path.resolve is not a function after require("node:path")'
+ )
+ }
+
+ return { fs: fsModule, path: pathModule }
+ },
+
+ // Attempt 3: Use dynamic import
+ async () => {
+ console.log(
+ 'Attempting to load Node.js modules with dynamic import'
+ )
+ const fsModule = await import('fs')
+ const pathModule = await import('path')
+
+ const fsResolved = fsModule.default || fsModule
+ const pathResolved = pathModule.default || pathModule
+
+ if (!pathResolved || typeof pathResolved.resolve !== 'function') {
+ throw new Error(
+ 'path.resolve is not a function after dynamic import'
+ )
+ }
+
+ return { fs: fsResolved, path: pathResolved }
+ },
+
+ // Attempt 4: Use dynamic import with node: prefix
+ async () => {
+ console.log(
+ 'Attempting to load Node.js modules with dynamic import("node:...")'
+ )
+ const fsModule = await import('node:fs')
+ const pathModule = await import('node:path')
+
+ const fsResolved = fsModule.default || fsModule
+ const pathResolved = pathModule.default || pathModule
+
+ if (!pathResolved || typeof pathResolved.resolve !== 'function') {
+ throw new Error(
+ 'path.resolve is not a function after dynamic import("node:path")'
+ )
+ }
+
+ return { fs: fsResolved, path: pathResolved }
+ }
+ ]
+
+ // Try each loading method until one succeeds
+ let lastError = null
+ for (const loadAttempt of loadAttempts) {
+ try {
+ const modules = await loadAttempt()
+ fs = modules.fs
+ path = modules.path
+ console.log('Successfully loaded Node.js modules')
+ break
+ } catch (error) {
+ lastError = error
+ console.warn(`Module loading attempt failed:`, error)
+ // Continue to the next attempt
+ }
+ }
+
+ // If all attempts failed, throw an error
+ if (!fs || !path || typeof path.resolve !== 'function') {
+ throw new Error(
+ `Failed to import Node.js modules after multiple attempts: ${lastError}. This adapter requires a Node.js environment.`
+ )
+ }
}
+ // Now set up the directory paths
+ const rootDir = this.rootDir || process.cwd()
+ this.rootDir = path.resolve(rootDir, ROOT_DIR)
+ this.nounsDir = path.join(this.rootDir, NOUNS_DIR)
+ this.verbsDir = path.join(this.rootDir, VERBS_DIR)
+ this.metadataDir = path.join(this.rootDir, METADATA_DIR)
+
+ // Set up noun type directory paths
+ this.personDir = path.join(this.nounsDir, PERSON_DIR)
+ this.placeDir = path.join(this.nounsDir, PLACE_DIR)
+ this.thingDir = path.join(this.nounsDir, THING_DIR)
+ this.eventDir = path.join(this.nounsDir, EVENT_DIR)
+ this.conceptDir = path.join(this.nounsDir, CONCEPT_DIR)
+ this.contentDir = path.join(this.nounsDir, CONTENT_DIR)
+ this.defaultDir = path.join(this.nounsDir, DEFAULT_DIR)
+
// Create directories if they don't exist
await this.ensureDirectoryExists(this.rootDir)
await this.ensureDirectoryExists(this.nounsDir)
diff --git a/src/types/tensorflowTypes.ts b/src/types/tensorflowTypes.ts
index 94a43484..b7381dfb 100644
--- a/src/types/tensorflowTypes.ts
+++ b/src/types/tensorflowTypes.ts
@@ -1,14 +1,35 @@
-// Type declarations for TensorFlow.js models
+/**
+ * Type definitions for TensorFlow.js compatibility
+ * This file exports type definitions for TensorFlow.js utilities
+ */
-// This file is a placeholder for TensorFlow.js model types
-// We're using type assertions in the code instead of module declarations
-
-// Define some basic types that might be useful
-export interface TensorflowModel {
- load(): Promise;
- embed(data: string[]): any;
- dispose(): void;
+// Define the shape of the util object used for TensorFlow.js compatibility
+export interface TensorFlowUtilObject {
+ isFloat32Array: (arr: unknown) => boolean
+ isTypedArray: (arr: unknown) => boolean
+ [key: string]: unknown
}
-// Export a dummy constant to make this a proper module
-export const tensorflowModelsLoaded = true;
+// Define the shape of the PlatformNode object that might exist in global
+export interface PlatformNodeObject {
+ isFloat32Array?: (arr: unknown) => boolean
+ isTypedArray?: (arr: unknown) => boolean
+ [key: string]: unknown
+}
+
+// Define the shape of the tf object that might exist in global
+export interface TensorFlowObject {
+ util?: TensorFlowUtilObject
+ [key: string]: unknown
+}
+
+// Extend the Window and WorkerGlobalScope interfaces to include the importTensorFlow function
+declare global {
+ interface Window {
+ importTensorFlow?: () => Promise
+ }
+
+ interface WorkerGlobalScope {
+ importTensorFlow?: () => Promise
+ }
+}
diff --git a/src/unified.ts b/src/unified.ts
index a2dbd38f..e00d8527 100644
--- a/src/unified.ts
+++ b/src/unified.ts
@@ -18,7 +18,7 @@ export const environment = {
// Make environment information available globally
if (typeof globalThis !== 'undefined') {
- globalThis.__ENV__ = environment
+ ;(globalThis as any).__ENV__ = environment
}
// Log the detected environment
diff --git a/src/utils/embedding.ts b/src/utils/embedding.ts
index 44d90014..fcceccb7 100644
--- a/src/utils/embedding.ts
+++ b/src/utils/embedding.ts
@@ -20,6 +20,23 @@ export class UniversalSentenceEncoder implements EmbeddingModel {
private use: any = null
private backend: string = 'cpu' // Default to CPU
+ /**
+ * Add polyfills and patches for TensorFlow.js compatibility
+ * This addresses issues with TensorFlow.js in Node.js environments
+ */
+ private addNodeCompatibilityPolyfills(): void {
+ // Only apply in Node.js environment
+ if (
+ typeof process === 'undefined' ||
+ !process.versions ||
+ !process.versions.node
+ ) {
+ return
+ }
+
+ // No compatibility patches needed - TensorFlow.js now works correctly with Node.js 24+
+ }
+
/**
* Initialize the embedding model
*/
@@ -42,6 +59,9 @@ export class UniversalSentenceEncoder implements EmbeddingModel {
originalWarn(message, ...optionalParams)
}
+ // Add polyfills for TensorFlow.js compatibility
+ this.addNodeCompatibilityPolyfills()
+
// TensorFlow.js will use its default EPSILON value
// Dynamically import TensorFlow.js core module and backends
diff --git a/src/utils/tensorflowUtils.ts b/src/utils/tensorflowUtils.ts
new file mode 100644
index 00000000..ce34fd7f
--- /dev/null
+++ b/src/utils/tensorflowUtils.ts
@@ -0,0 +1,80 @@
+/**
+ * Utility functions for TensorFlow.js compatibility
+ * This module provides utility functions that TensorFlow.js might need
+ * and avoids the need to use globalThis.util
+ */
+
+// Import the TensorFlowUtilObject interface
+import type {
+ TensorFlowUtilObject,
+ PlatformNodeObject
+} from '../types/tensorflowTypes.js'
+
+// Define a global PlatformNode class for TensorFlow.js compatibility
+// This is needed because TensorFlow.js creates its own PlatformNode instance
+// and we need to ensure it uses the correct TextEncoder/TextDecoder
+if (
+ typeof global !== 'undefined' &&
+ typeof process !== 'undefined' &&
+ process.versions &&
+ process.versions.node &&
+ process.versions.node.split('.')[0] >= '23'
+) {
+ try {
+ // Define the PlatformNode class that TensorFlow.js will use
+ class PlatformNode {
+ util: any
+ textEncoder: any
+ textDecoder: any
+
+ constructor() {
+ // Create a util object with the necessary methods
+ this.util = {
+ isFloat32Array,
+ isTypedArray,
+ // Use the global TextEncoder/TextDecoder directly
+ TextEncoder: typeof TextEncoder !== 'undefined' ? TextEncoder : null,
+ TextDecoder: typeof TextDecoder !== 'undefined' ? TextDecoder : null
+ }
+
+ // Initialize TextEncoder/TextDecoder directly from globals
+ this.textEncoder = new TextEncoder()
+ this.textDecoder = new TextDecoder()
+ }
+ }
+
+ // Assign the PlatformNode class to the global object
+ ;(global as any).PlatformNode = PlatformNode
+
+ // Also create an instance and assign it to global.platformNode (lowercase p)
+ // Some TensorFlow.js code might look for this
+ ;(global as any).platformNode = new PlatformNode()
+
+ console.log(
+ 'Defined global PlatformNode class for TensorFlow.js compatibility'
+ )
+ } catch (error) {
+ console.warn('Failed to define global PlatformNode class:', error)
+ }
+}
+
+/**
+ * Check if an array is a Float32Array
+ * @param arr - The array to check
+ * @returns True if the array is a Float32Array
+ */
+export function isFloat32Array(arr: unknown): boolean {
+ return !!(
+ arr instanceof Float32Array ||
+ (arr && Object.prototype.toString.call(arr) === '[object Float32Array]')
+ )
+}
+
+/**
+ * Check if an array is a TypedArray
+ * @param arr - The array to check
+ * @returns True if the array is a TypedArray
+ */
+export function isTypedArray(arr: unknown): boolean {
+ return !!(ArrayBuffer.isView(arr) && !(arr instanceof DataView))
+}
diff --git a/src/utils/version.ts b/src/utils/version.ts
index 83c71123..804e1bb8 100644
--- a/src/utils/version.ts
+++ b/src/utils/version.ts
@@ -3,4 +3,4 @@
* Do not modify this file directly.
*/
-export const VERSION = '0.9.22';
+export const VERSION = '0.9.25';