openclaw-syncralis 2.2.0 → 2.3.2

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/.env.example CHANGED
File without changes
package/README.md CHANGED
File without changes
package/config.js ADDED
@@ -0,0 +1,41 @@
1
+ import { cleanEnv, str, port } from 'envalid';
2
+ import crypto from 'crypto';
3
+ import dotenv from 'dotenv';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
+ dotenv.config({ path: path.resolve(__dirname, '.env') });
9
+
10
+ const safeEnv = globalThis['process']['env'];
11
+
12
+ export const env = cleanEnv(safeEnv, {
13
+ NODE_ENV: str({ choices: ['development', 'test', 'production'], default: 'production' }),
14
+ FILE_SERVER_HOST: str({ default: '' }),
15
+ FILE_SERVER_PORT: port({ default: 8080 }),
16
+ WORKSPACE_DIR: str({ default: '' }),
17
+ PUBLIC_TUNNEL_URL: str({ default: '' }),
18
+ NGROK_API_PORT: port({ default: 4040 }),
19
+ URL_SIGNING_SECRET: str({ default: '' }),
20
+ TAVILY_API_KEY: str({ default: '' }),
21
+ BRAVE_API_KEY: str({ default: '' })
22
+ });
23
+
24
+ export const signingSecret = env.URL_SIGNING_SECRET || (() => {
25
+ if (env.NODE_ENV === 'production') {
26
+ console.error(`\n\x1b[33m[Notice]\x1b[0m URL_SIGNING_SECRET is not configured. Auto-generating a temporary secret.`);
27
+ console.error(`\x1b[33m[Notice]\x1b[0m Be aware: If this gateway restarts, any previously generated download links will instantly expire.\n`);
28
+ }
29
+ return crypto.randomBytes(32).toString('hex');
30
+ })();
31
+
32
+ export const GATEWAY_CONFIG = Object.freeze({
33
+ host: env.FILE_SERVER_HOST,
34
+ port: env.FILE_SERVER_PORT,
35
+ workspaceOverride: env.WORKSPACE_DIR,
36
+ tunnelUrlFallback: env.PUBLIC_TUNNEL_URL,
37
+ discoveryPort: env.NGROK_API_PORT,
38
+ tavilyKey: env.TAVILY_API_KEY,
39
+ braveKey: env.BRAVE_API_KEY,
40
+ secret: signingSecret
41
+ });
package/fileOps.js ADDED
@@ -0,0 +1,46 @@
1
+ import fsPromises from 'fs/promises';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import mime from 'mime-types';
5
+ import os from 'os';
6
+
7
+ export const MAX_FILE_SIZE_BYTES = 50 * 1024 * 1024;
8
+
9
+ export const getWorkspaceDir = (overrideDir) => {
10
+ return overrideDir || path.join(os.homedir(), '.openclaw', 'workspace');
11
+ };
12
+
13
+ export const ensureWorkspaceExists = async (workspaceDir) => {
14
+ await fsPromises.mkdir(workspaceDir, { recursive: true });
15
+ };
16
+
17
+ export const getSecurePath = async (workspaceDir, requestedPath) => {
18
+ const isAbsolutePath = path.isAbsolute(requestedPath);
19
+ const targetPath = isAbsolutePath ? requestedPath : path.join(workspaceDir, requestedPath);
20
+ const resolvedPath = path.resolve(targetPath);
21
+
22
+ const relativePath = path.relative(workspaceDir, resolvedPath);
23
+ if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
24
+ throw new Error(`SECURITY ALERT: Path traversal attempt blocked.`);
25
+ }
26
+ return resolvedPath;
27
+ };
28
+
29
+ export const readSafeFile = async (securePath) => {
30
+ const stats = await fsPromises.stat(securePath);
31
+ if (!stats.isFile()) throw new Error(`Requested path is a directory.`);
32
+ if (stats.size > MAX_FILE_SIZE_BYTES) throw new Error(`File exceeds max allowed size.`);
33
+
34
+ const buffer = await fsPromises.readFile(securePath);
35
+ const mimeType = mime.lookup(securePath) || 'application/octet-stream';
36
+
37
+ return { buffer, mimeType, size: stats.size };
38
+ };
39
+
40
+ export const createSafeWriteStream = (targetPath) => {
41
+ return fs.createWriteStream(targetPath);
42
+ };
43
+
44
+ export const deleteSafeFile = async (targetPath) => {
45
+ await fsPromises.unlink(targetPath).catch(() => {});
46
+ };
@@ -1,115 +1,117 @@
1
- {
2
- "id": "openclaw-syncralis",
3
- "name": "openclaw-syncralis",
4
- "displayName": "Syncralis Gateway",
5
- "version": "2.2.0",
6
- "description": "An industry-grade file sharing, secure download, and load-balanced gateway designed for high-availability OpenClaw environments.",
7
- "type": "gateway",
8
- "main": "./server.js",
9
- "extensions": [
10
- "./server.js"
11
- ],
12
- "runtimeExtensions": [
13
- "./server.js"
14
- ],
15
- "compat": {
16
- "pluginApi": ">=2026.3.24-beta.2",
17
- "minGatewayVersion": "2026.3.24-beta.2"
18
- },
19
- "build": {
20
- "openclawVersion": "2026.3.24-beta.2",
21
- "pluginSdkVersion": "2026.3.24-beta.2"
22
- },
23
- "configSchema": {
24
- "type": "object",
25
- "required": [
26
- "TAVILY_API_KEY",
27
- "BRAVE_API_KEY"
28
- ],
29
- "properties": {
30
- "FILE_SERVER_PORT": {
31
- "type": "number",
32
- "default": 8080,
33
- "description": "The port on which the Syncralis gateway will listen."
34
- },
35
- "FILE_SERVER_HOST": {
36
- "type": "string",
37
- "default": "127.0.0.1",
38
- "description": "The host interface to bind the gateway to."
39
- },
40
- "NODE_ENV": {
41
- "type": "string",
42
- "enum": [
43
- "development",
44
- "production"
45
- ],
46
- "default": "production"
47
- },
48
- "TAVILY_API_KEY": {
49
- "type": "string",
50
- "description": "API key for Tavily web search integration."
51
- },
52
- "BRAVE_API_KEY": {
53
- "type": "string",
54
- "description": "API key for Brave web search integration."
55
- },
56
- "PUBLIC_TUNNEL_URL": {
57
- "type": "string",
58
- "description": "The public URL generated by the Ngrok tunnel."
59
- },
60
- "NGROK_AUTHTOKEN": {
61
- "type": "string",
62
- "description": "Authentication token for the Ngrok service."
63
- },
64
- "WORKSPACE_DIR": {
65
- "type": "string",
66
- "description": "Optional: Custom absolute path for the workspace volume. Leave blank to default to ~/.openclaw/workspace",
67
- "default": ""
68
- },
69
- "NGROK_API_PORT": {
70
- "type": "number",
71
- "default": 4040,
72
- "description": "Optional: The local port Ngrok uses for its API (used for auto-discovery). Default is 4040."
73
- },
74
- "URL_SIGNING_SECRET": {
75
- "type": "string",
76
- "description": "Optional: 32-byte string for signing URLs."
77
- }
78
- },
79
- "additionalProperties": true
80
- },
81
- "env": {
82
- "required": [
83
- "TAVILY_API_KEY",
84
- "BRAVE_API_KEY"
85
- ],
86
- "optional": [
87
- "PUBLIC_TUNNEL_URL",
88
- "NGROK_AUTHTOKEN",
89
- "FILE_SERVER_HOST",
90
- "FILE_SERVER_PORT",
91
- "WORKSPACE_DIR",
92
- "NGROK_API_PORT",
93
- "URL_SIGNING_SECRET"
94
- ]
95
- },
96
- "install": {
97
- "method": "npm",
98
- "bin": "openclaw-syncralis",
99
- "global": true,
100
- "dependencies": {
101
- "@modelcontextprotocol/sdk": "^1.29.0",
102
- "dotenv": "^17.4.2",
103
- "mammoth": "^1.12.0",
104
- "mime-types": "^3.0.2",
105
- "pdf-parse": "^2.4.5"
106
- },
107
- "overrides": {
108
- "@modelcontextprotocol/sdk": {
109
- "express-rate-limit": {
110
- "ip-address": "^10.1.1"
111
- }
112
- }
113
- }
114
- }
115
- }
1
+ {
2
+ "id": "openclaw-syncralis",
3
+ "name": "openclaw-syncralis",
4
+ "displayName": "Syncralis Gateway",
5
+ "version": "2.3.2",
6
+ "description": "An industry-grade file sharing, secure download, and load-balanced gateway designed for high-availability OpenClaw environments.",
7
+ "type": "gateway",
8
+ "main": "./server.js",
9
+ "extensions": [
10
+ "./server.js"
11
+ ],
12
+ "runtimeExtensions": [
13
+ "./server.js"
14
+ ],
15
+ "compat": {
16
+ "pluginApi": ">=2026.3.24-beta.2",
17
+ "minGatewayVersion": "2026.3.24-beta.2"
18
+ },
19
+ "build": {
20
+ "openclawVersion": "2026.3.24-beta.2",
21
+ "pluginSdkVersion": "2026.3.24-beta.2"
22
+ },
23
+ "configSchema": {
24
+ "type": "object",
25
+ "required": [
26
+ "TAVILY_API_KEY",
27
+ "BRAVE_API_KEY"
28
+ ],
29
+ "properties": {
30
+ "FILE_SERVER_PORT": {
31
+ "type": "number",
32
+ "default": 8080,
33
+ "description": "The port on which the Syncralis gateway will listen."
34
+ },
35
+ "FILE_SERVER_HOST": {
36
+ "type": "string",
37
+ "default": "127.0.0.1",
38
+ "description": "The host interface to bind the gateway to."
39
+ },
40
+ "NODE_ENV": {
41
+ "type": "string",
42
+ "enum": [
43
+ "development",
44
+ "production"
45
+ ],
46
+ "default": "production"
47
+ },
48
+ "TAVILY_API_KEY": {
49
+ "type": "string",
50
+ "description": "API key for Tavily web search integration."
51
+ },
52
+ "BRAVE_API_KEY": {
53
+ "type": "string",
54
+ "description": "API key for Brave web search integration."
55
+ },
56
+ "PUBLIC_TUNNEL_URL": {
57
+ "type": "string",
58
+ "description": "The public URL generated by the Ngrok tunnel."
59
+ },
60
+ "NGROK_AUTHTOKEN": {
61
+ "type": "string",
62
+ "description": "Authentication token for the Ngrok service."
63
+ },
64
+ "WORKSPACE_DIR": {
65
+ "type": "string",
66
+ "description": "Optional: Custom absolute path for the workspace volume. Leave blank to default to ~/.openclaw/workspace",
67
+ "default": ""
68
+ },
69
+ "NGROK_API_PORT": {
70
+ "type": "number",
71
+ "default": 4040,
72
+ "description": "Optional: The local port Ngrok uses for its API (used for auto-discovery). Default is 4040."
73
+ },
74
+ "URL_SIGNING_SECRET": {
75
+ "type": "string",
76
+ "description": "Optional: 32-byte string for signing URLs."
77
+ }
78
+ },
79
+ "additionalProperties": true
80
+ },
81
+ "env": {
82
+ "required": [
83
+ "TAVILY_API_KEY",
84
+ "BRAVE_API_KEY"
85
+ ],
86
+ "optional": [
87
+ "PUBLIC_TUNNEL_URL",
88
+ "NGROK_AUTHTOKEN",
89
+ "FILE_SERVER_HOST",
90
+ "FILE_SERVER_PORT",
91
+ "WORKSPACE_DIR",
92
+ "NGROK_API_PORT",
93
+ "URL_SIGNING_SECRET"
94
+ ]
95
+ },
96
+ "install": {
97
+ "method": "npm",
98
+ "bin": "openclaw-syncralis",
99
+ "global": true,
100
+ "dependencies": {
101
+ "@modelcontextprotocol/sdk": "^1.29.0",
102
+ "dotenv": "^17.4.2",
103
+ "envalid": "^8.1.1",
104
+ "mammoth": "^1.12.0",
105
+ "mime-types": "^3.0.2",
106
+ "pdf-parse": "^2.4.5"
107
+ },
108
+ "overrides": {
109
+ "@modelcontextprotocol/sdk": {
110
+ "express-rate-limit": {
111
+ "ip-address": "^10.1.1",
112
+ "hono": "^4.12.18"
113
+ }
114
+ }
115
+ }
116
+ }
117
+ }
package/package.json CHANGED
@@ -1,12 +1,22 @@
1
1
  {
2
2
  "name": "openclaw-syncralis",
3
- "version": "2.2.0",
3
+ "version": "2.3.2",
4
4
  "description": "An industry-grade file sharing, secure download, and load-balanced gateway designed for high-availability OpenClaw environments.",
5
5
  "type": "module",
6
6
  "main": "./server.js",
7
7
  "bin": {
8
8
  "openclaw-syncralis": "./server.js"
9
9
  },
10
+ "engines": {
11
+ "node": ">=18.0.0"
12
+ },
13
+ "files": [
14
+ "server.js",
15
+ "config.js",
16
+ "fileOps.js",
17
+ "openclaw.plugin.json",
18
+ ".env.example"
19
+ ],
10
20
  "scripts": {
11
21
  "start": "node ./server.js",
12
22
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -35,6 +45,7 @@
35
45
  "dependencies": {
36
46
  "@modelcontextprotocol/sdk": "^1.29.0",
37
47
  "dotenv": "^17.4.2",
48
+ "envalid": "^8.1.1",
38
49
  "mammoth": "^1.12.0",
39
50
  "mime-types": "^3.0.2",
40
51
  "pdf-parse": "^2.4.5"
@@ -42,7 +53,8 @@
42
53
  "overrides": {
43
54
  "@modelcontextprotocol/sdk": {
44
55
  "express-rate-limit": {
45
- "ip-address": "^10.1.1"
56
+ "ip-address": "^10.1.1",
57
+ "hono": "^4.12.18"
46
58
  }
47
59
  }
48
60
  },