@nexushub/client 0.4.3 → 0.4.4
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/dist/chunk-NOIMIIA5.js +53 -0
- package/dist/chunk-VFVPDENW.cjs +53 -0
- package/dist/cli.cjs +460 -99
- package/dist/content/binary-compiler.cjs +135 -0
- package/dist/content/binary-compiler.d.cts +28 -0
- package/dist/content/binary-compiler.d.ts +28 -0
- package/dist/content/binary-compiler.js +100 -0
- package/dist/content/local-cache-server.cjs +184 -52
- package/dist/content/local-cache-server.d.cts +9 -4
- package/dist/content/local-cache-server.d.ts +9 -4
- package/dist/content/local-cache-server.js +184 -52
- package/dist/index.cjs +221 -99
- package/dist/index.js +221 -99
- package/dist/local-cache-server-BNLLL4NR.js +224 -0
- package/dist/local-cache-server-SF5SXE7H.cjs +224 -0
- package/dist/react.cjs +399 -78
- package/dist/react.d.cts +140 -1
- package/dist/react.d.ts +140 -1
- package/dist/react.js +370 -49
- package/package.json +2 -1
- package/dist/local-cache-server-6DXQJFCQ.cjs +0 -114
- package/dist/local-cache-server-DBJWR7HD.js +0 -114
package/dist/index.js
CHANGED
|
@@ -8,6 +8,164 @@ var __export = (target, all) => {
|
|
|
8
8
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
// src/config.ts
|
|
12
|
+
var DEFAULT_API_URL, DEFAULT_ANALYTICS_URL, LOCAL_NEST_URL, LOCAL_RUST_URL, getEnvConfig, mergeConfigs, getFullConfig, validateConfig;
|
|
13
|
+
var init_config = __esm({
|
|
14
|
+
"src/config.ts"() {
|
|
15
|
+
"use strict";
|
|
16
|
+
DEFAULT_API_URL = "https://endpoints.gnexus.co.tz";
|
|
17
|
+
DEFAULT_ANALYTICS_URL = "https://sentry.gnexus.co.tz";
|
|
18
|
+
LOCAL_NEST_URL = "https://endpoints.gnexus.co.tz";
|
|
19
|
+
LOCAL_RUST_URL = "https://sentry.gnexus.co.tz";
|
|
20
|
+
getEnvConfig = () => {
|
|
21
|
+
const NEXT_PUBLIC_ID = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_NEXUS_ID : void 0;
|
|
22
|
+
const NEXT_PUBLIC_KEY = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_NEXUS_KEY : void 0;
|
|
23
|
+
const NEXT_PUBLIC_URL = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_NEXUS_API_URL : void 0;
|
|
24
|
+
const NODE_ID = typeof process !== "undefined" ? process.env.NEXUS_PROJECT_ID : void 0;
|
|
25
|
+
const NODE_KEY = typeof process !== "undefined" ? process.env.NEXUS_API_KEY : void 0;
|
|
26
|
+
const NODE_URL = typeof process !== "undefined" ? process.env.NEXUS_API_URL : void 0;
|
|
27
|
+
const NODE_ENV = typeof process !== "undefined" ? process.env.NODE_ENV : "production";
|
|
28
|
+
const isDev = NODE_ENV === "development" || typeof window !== "undefined" && window.location.hostname === "localhost";
|
|
29
|
+
const projectId = NEXT_PUBLIC_ID ?? NODE_ID;
|
|
30
|
+
const apiKey = NEXT_PUBLIC_KEY ?? NODE_KEY;
|
|
31
|
+
const apiUrl = NEXT_PUBLIC_URL ?? NODE_URL ?? (isDev ? LOCAL_NEST_URL : DEFAULT_API_URL);
|
|
32
|
+
const analyticsUrl = apiUrl.includes("localhost") ? LOCAL_RUST_URL : DEFAULT_ANALYTICS_URL;
|
|
33
|
+
return {
|
|
34
|
+
projectId,
|
|
35
|
+
apiKey,
|
|
36
|
+
apiUrl,
|
|
37
|
+
analyticsUrl
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
mergeConfigs = (base, override) => {
|
|
41
|
+
const mergedApiUrl = override.apiUrl || base.apiUrl || DEFAULT_API_URL;
|
|
42
|
+
const mergedAnalyticsUrl = override.analyticsUrl || base.analyticsUrl || (mergedApiUrl.includes("localhost") ? LOCAL_RUST_URL : DEFAULT_ANALYTICS_URL);
|
|
43
|
+
return {
|
|
44
|
+
...base,
|
|
45
|
+
...override,
|
|
46
|
+
apiUrl: mergedApiUrl,
|
|
47
|
+
analyticsUrl: mergedAnalyticsUrl,
|
|
48
|
+
projectId: override.projectId || base.projectId,
|
|
49
|
+
apiKey: override.apiKey || base.apiKey
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
getFullConfig = (partialConfig) => {
|
|
53
|
+
const envConfig = getEnvConfig();
|
|
54
|
+
return mergeConfigs(envConfig, partialConfig || {});
|
|
55
|
+
};
|
|
56
|
+
validateConfig = (config) => {
|
|
57
|
+
const errors = [];
|
|
58
|
+
if (!config.projectId) errors.push("Missing projectId");
|
|
59
|
+
if (!config.apiUrl) errors.push("Missing apiUrl");
|
|
60
|
+
return errors;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// src/content/binary-compiler.ts
|
|
66
|
+
import * as crypto2 from "crypto";
|
|
67
|
+
var BinaryCompiler;
|
|
68
|
+
var init_binary_compiler = __esm({
|
|
69
|
+
"src/content/binary-compiler.ts"() {
|
|
70
|
+
"use strict";
|
|
71
|
+
BinaryCompiler = class {
|
|
72
|
+
/**
|
|
73
|
+
* Generates a secure, deterministic cryptographic key from the project's API key.
|
|
74
|
+
*/
|
|
75
|
+
static deriveKeys(apiKey) {
|
|
76
|
+
const hash = crypto2.createHash("sha256").update(apiKey).digest();
|
|
77
|
+
const encryptionKey = hash;
|
|
78
|
+
const hmacKey = crypto2.createHmac("sha256", apiKey).update("nexus-integrity-key").digest();
|
|
79
|
+
return { encryptionKey, hmacKey };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Compiles JSON content data into a secure, signed, and encrypted .nx binary buffer.
|
|
83
|
+
*/
|
|
84
|
+
static compile(data, apiKey, projectId, metadataOverrides = {}) {
|
|
85
|
+
const { encryptionKey, hmacKey } = this.deriveKeys(apiKey);
|
|
86
|
+
const metadata = {
|
|
87
|
+
version: "2.0.0",
|
|
88
|
+
compiledAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
89
|
+
projectId,
|
|
90
|
+
...metadataOverrides
|
|
91
|
+
};
|
|
92
|
+
const metadataStr = JSON.stringify(metadata);
|
|
93
|
+
const metadataBuffer = Buffer.from(metadataStr, "utf-8");
|
|
94
|
+
const iv = crypto2.randomBytes(16);
|
|
95
|
+
const cipher = crypto2.createCipheriv(this.ALGORITHM, encryptionKey, iv);
|
|
96
|
+
const plainTextPayload = JSON.stringify(data);
|
|
97
|
+
let encryptedPayload = cipher.update(plainTextPayload, "utf8");
|
|
98
|
+
encryptedPayload = Buffer.concat([encryptedPayload, cipher.final()]);
|
|
99
|
+
const payloadBuffer = Buffer.concat([iv, encryptedPayload]);
|
|
100
|
+
const headerBuffer = Buffer.from(this.MAGIC_HEADER, "ascii");
|
|
101
|
+
const metaLengthBuffer = Buffer.alloc(4);
|
|
102
|
+
metaLengthBuffer.writeUInt32BE(metadataBuffer.length, 0);
|
|
103
|
+
const payloadLengthBuffer = Buffer.alloc(4);
|
|
104
|
+
payloadLengthBuffer.writeUInt32BE(payloadBuffer.length, 0);
|
|
105
|
+
const prefixBlock = Buffer.concat([
|
|
106
|
+
headerBuffer,
|
|
107
|
+
metaLengthBuffer,
|
|
108
|
+
metadataBuffer,
|
|
109
|
+
payloadLengthBuffer,
|
|
110
|
+
payloadBuffer
|
|
111
|
+
]);
|
|
112
|
+
const hmac = crypto2.createHmac("sha256", hmacKey);
|
|
113
|
+
hmac.update(prefixBlock);
|
|
114
|
+
const signature = hmac.digest();
|
|
115
|
+
return Buffer.concat([prefixBlock, signature]);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Verifies, decrypts, and decompiles a .nx binary buffer back into clean, type-safe JSON.
|
|
119
|
+
* Throws structured errors on integrity verification failures or file corruption.
|
|
120
|
+
*/
|
|
121
|
+
static decompile(buffer, apiKey) {
|
|
122
|
+
if (buffer.length < 44) {
|
|
123
|
+
throw new Error(
|
|
124
|
+
"Corrupted File: Binary payload is too short to be a valid Nexus node."
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
const { encryptionKey, hmacKey } = this.deriveKeys(apiKey);
|
|
128
|
+
const prefixBlockLength = buffer.length - 32;
|
|
129
|
+
const prefixBlock = buffer.subarray(0, prefixBlockLength);
|
|
130
|
+
const expectedSignature = buffer.subarray(prefixBlockLength);
|
|
131
|
+
const hmac = crypto2.createHmac("sha256", hmacKey);
|
|
132
|
+
hmac.update(prefixBlock);
|
|
133
|
+
const actualSignature = hmac.digest();
|
|
134
|
+
if (!crypto2.timingSafeEqual(expectedSignature, actualSignature)) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
"DATA_INTEGRITY_VIOLATION: Cryptographic signature mismatch. This local node has been modified externally or tampered with."
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
const magicHeader = prefixBlock.subarray(0, 4).toString("ascii");
|
|
140
|
+
if (magicHeader !== this.MAGIC_HEADER) {
|
|
141
|
+
throw new Error(
|
|
142
|
+
"Invalid Format: File lacks the correct Nexus binary magic header."
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
const metaLength = prefixBlock.readUInt32BE(4);
|
|
146
|
+
const metaStart = 8;
|
|
147
|
+
const metaEnd = metaStart + metaLength;
|
|
148
|
+
const metadataStr = prefixBlock.subarray(metaStart, metaEnd).toString("utf-8");
|
|
149
|
+
const metadata = JSON.parse(metadataStr);
|
|
150
|
+
const payloadLength = prefixBlock.readUInt32BE(metaEnd);
|
|
151
|
+
const payloadStart = metaEnd + 4;
|
|
152
|
+
const payloadEnd = payloadStart + payloadLength;
|
|
153
|
+
const payloadBuffer = prefixBlock.subarray(payloadStart, payloadEnd);
|
|
154
|
+
const iv = payloadBuffer.subarray(0, 16);
|
|
155
|
+
const cipherText = payloadBuffer.subarray(16);
|
|
156
|
+
const decipher = crypto2.createDecipheriv(this.ALGORITHM, encryptionKey, iv);
|
|
157
|
+
let decrypted = decipher.update(cipherText);
|
|
158
|
+
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
|
159
|
+
const data = JSON.parse(decrypted.toString("utf8"));
|
|
160
|
+
return { data, metadata };
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
BinaryCompiler.MAGIC_HEADER = "NEXS";
|
|
164
|
+
// 4-byte ASCII magic identifier
|
|
165
|
+
BinaryCompiler.ALGORITHM = "aes-256-cbc";
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
11
169
|
// src/content/local-cache-server.ts
|
|
12
170
|
var local_cache_server_exports = {};
|
|
13
171
|
__export(local_cache_server_exports, {
|
|
@@ -19,84 +177,92 @@ var LocalCache;
|
|
|
19
177
|
var init_local_cache_server = __esm({
|
|
20
178
|
"src/content/local-cache-server.ts"() {
|
|
21
179
|
"use strict";
|
|
180
|
+
init_config();
|
|
181
|
+
init_binary_compiler();
|
|
22
182
|
LocalCache = class {
|
|
23
183
|
constructor(customPath) {
|
|
184
|
+
this.apiKey = "";
|
|
24
185
|
this.baseDir = customPath || ".nexus/local";
|
|
186
|
+
const config = getEnvConfig();
|
|
187
|
+
this.apiKey = config.apiKey || "";
|
|
25
188
|
}
|
|
26
189
|
isLoaded() {
|
|
27
190
|
return fs.existsSync(path.resolve(process.cwd(), this.baseDir));
|
|
28
191
|
}
|
|
29
192
|
/**
|
|
30
|
-
*
|
|
193
|
+
* Helper to decrypt and decompile `.nx` files on-the-fly.
|
|
31
194
|
*/
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
`${slug}.json`
|
|
39
|
-
);
|
|
40
|
-
if (fs.existsSync(filePath)) {
|
|
41
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
42
|
-
const pageData = JSON.parse(fileContent);
|
|
43
|
-
return pageData.data !== void 0 ? pageData.data : pageData;
|
|
195
|
+
decompileFile(filePath) {
|
|
196
|
+
if (!this.apiKey) {
|
|
197
|
+
if (process.env.NODE_ENV === "development") {
|
|
198
|
+
console.warn(
|
|
199
|
+
"\u26A0\uFE0F NexusHub: Missing NEXUS_API_KEY. Local decryption bypassed."
|
|
200
|
+
);
|
|
44
201
|
}
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
try {
|
|
205
|
+
const encryptedBuffer = fs.readFileSync(filePath);
|
|
206
|
+
const decompiled = BinaryCompiler.decompile(encryptedBuffer, this.apiKey);
|
|
207
|
+
return decompiled.data;
|
|
45
208
|
} catch (error) {
|
|
46
209
|
if (process.env.NODE_ENV === "development") {
|
|
47
|
-
console.
|
|
48
|
-
|
|
49
|
-
|
|
210
|
+
console.error(
|
|
211
|
+
`
|
|
212
|
+
\u{1F6A8} NexusHub Security Alert: Data Integrity Violation in file:
|
|
213
|
+
${filePath}
|
|
214
|
+
Error: ${error.message}
|
|
215
|
+
This file has been disabled until regenerated via npx nexus pull.
|
|
216
|
+
`
|
|
50
217
|
);
|
|
51
218
|
}
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Retrieve a specific page directly from its .nx file.
|
|
224
|
+
*/
|
|
225
|
+
async getPage(slug) {
|
|
226
|
+
const filePath = path.resolve(
|
|
227
|
+
process.cwd(),
|
|
228
|
+
this.baseDir,
|
|
229
|
+
"pages",
|
|
230
|
+
`${slug}.nx`
|
|
231
|
+
);
|
|
232
|
+
if (fs.existsSync(filePath)) {
|
|
233
|
+
const pageData = this.decompileFile(filePath);
|
|
234
|
+
if (!pageData) return null;
|
|
235
|
+
return pageData.data !== void 0 ? pageData.data : pageData;
|
|
52
236
|
}
|
|
53
237
|
return null;
|
|
54
238
|
}
|
|
55
239
|
/**
|
|
56
|
-
* Retrieve an entire collection from its specific
|
|
240
|
+
* Retrieve an entire collection from its specific .nx file.
|
|
57
241
|
*/
|
|
58
242
|
async getCollection(collectionId) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
68
|
-
return JSON.parse(fileContent);
|
|
69
|
-
}
|
|
70
|
-
} catch (error) {
|
|
71
|
-
if (process.env.NODE_ENV === "development") {
|
|
72
|
-
console.warn(
|
|
73
|
-
`\u26A0\uFE0F NexusHub: Failed to load local collection '${collectionId}':`,
|
|
74
|
-
error
|
|
75
|
-
);
|
|
76
|
-
}
|
|
243
|
+
const filePath = path.resolve(
|
|
244
|
+
process.cwd(),
|
|
245
|
+
this.baseDir,
|
|
246
|
+
"collections",
|
|
247
|
+
`${collectionId}.nx`
|
|
248
|
+
);
|
|
249
|
+
if (fs.existsSync(filePath)) {
|
|
250
|
+
return this.decompileFile(filePath);
|
|
77
251
|
}
|
|
78
252
|
return null;
|
|
79
253
|
}
|
|
80
254
|
/**
|
|
81
|
-
* Retrieve global settings from its file.
|
|
255
|
+
* Retrieve global settings from its .nx file.
|
|
82
256
|
*/
|
|
83
257
|
async getGlobals() {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
this.baseDir,
|
|
88
|
-
"globals.json"
|
|
89
|
-
);
|
|
90
|
-
if (fs.existsSync(filePath)) {
|
|
91
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
92
|
-
return JSON.parse(fileContent);
|
|
93
|
-
}
|
|
94
|
-
} catch {
|
|
258
|
+
const filePath = path.resolve(process.cwd(), this.baseDir, "globals.nx");
|
|
259
|
+
if (fs.existsSync(filePath)) {
|
|
260
|
+
return this.decompileFile(filePath);
|
|
95
261
|
}
|
|
96
262
|
return null;
|
|
97
263
|
}
|
|
98
264
|
/**
|
|
99
|
-
* Returns a merged JSON of the entire workspace structure
|
|
265
|
+
* Returns a merged JSON of the entire workspace structure.
|
|
100
266
|
*/
|
|
101
267
|
async getAllData() {
|
|
102
268
|
const pages = {};
|
|
@@ -106,8 +272,8 @@ var init_local_cache_server = __esm({
|
|
|
106
272
|
const pagesDir = path.resolve(process.cwd(), this.baseDir, "pages");
|
|
107
273
|
if (fs.existsSync(pagesDir)) {
|
|
108
274
|
for (const file of fs.readdirSync(pagesDir)) {
|
|
109
|
-
if (file.endsWith(".
|
|
110
|
-
const slug = path.basename(file, ".
|
|
275
|
+
if (file.endsWith(".nx")) {
|
|
276
|
+
const slug = path.basename(file, ".nx");
|
|
111
277
|
pages[slug] = await this.getPage(slug);
|
|
112
278
|
}
|
|
113
279
|
}
|
|
@@ -115,8 +281,8 @@ var init_local_cache_server = __esm({
|
|
|
115
281
|
const colsDir = path.resolve(process.cwd(), this.baseDir, "collections");
|
|
116
282
|
if (fs.existsSync(colsDir)) {
|
|
117
283
|
for (const file of fs.readdirSync(colsDir)) {
|
|
118
|
-
if (file.endsWith(".
|
|
119
|
-
const id = path.basename(file, ".
|
|
284
|
+
if (file.endsWith(".nx")) {
|
|
285
|
+
const id = path.basename(file, ".nx");
|
|
120
286
|
collections[id] = await this.getCollection(id) || [];
|
|
121
287
|
}
|
|
122
288
|
}
|
|
@@ -197,53 +363,8 @@ var init_local_cache_client = __esm({
|
|
|
197
363
|
}
|
|
198
364
|
});
|
|
199
365
|
|
|
200
|
-
// src/
|
|
201
|
-
|
|
202
|
-
var DEFAULT_ANALYTICS_URL = "https://sentry.gnexus.co.tz";
|
|
203
|
-
var LOCAL_NEST_URL = "https://endpoints.gnexus.co.tz";
|
|
204
|
-
var LOCAL_RUST_URL = "https://sentry.gnexus.co.tz";
|
|
205
|
-
var getEnvConfig = () => {
|
|
206
|
-
const NEXT_PUBLIC_ID = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_NEXUS_ID : void 0;
|
|
207
|
-
const NEXT_PUBLIC_KEY = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_NEXUS_KEY : void 0;
|
|
208
|
-
const NEXT_PUBLIC_URL = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_NEXUS_API_URL : void 0;
|
|
209
|
-
const NODE_ID = typeof process !== "undefined" ? process.env.NEXUS_PROJECT_ID : void 0;
|
|
210
|
-
const NODE_KEY = typeof process !== "undefined" ? process.env.NEXUS_API_KEY : void 0;
|
|
211
|
-
const NODE_URL = typeof process !== "undefined" ? process.env.NEXUS_API_URL : void 0;
|
|
212
|
-
const NODE_ENV = typeof process !== "undefined" ? process.env.NODE_ENV : "production";
|
|
213
|
-
const isDev = NODE_ENV === "development" || typeof window !== "undefined" && window.location.hostname === "localhost";
|
|
214
|
-
const projectId = NEXT_PUBLIC_ID ?? NODE_ID;
|
|
215
|
-
const apiKey = NEXT_PUBLIC_KEY ?? NODE_KEY;
|
|
216
|
-
const apiUrl = NEXT_PUBLIC_URL ?? NODE_URL ?? (isDev ? LOCAL_NEST_URL : DEFAULT_API_URL);
|
|
217
|
-
const analyticsUrl = apiUrl.includes("localhost") ? LOCAL_RUST_URL : DEFAULT_ANALYTICS_URL;
|
|
218
|
-
return {
|
|
219
|
-
projectId,
|
|
220
|
-
apiKey,
|
|
221
|
-
apiUrl,
|
|
222
|
-
analyticsUrl
|
|
223
|
-
};
|
|
224
|
-
};
|
|
225
|
-
var mergeConfigs = (base, override) => {
|
|
226
|
-
const mergedApiUrl = override.apiUrl || base.apiUrl || DEFAULT_API_URL;
|
|
227
|
-
const mergedAnalyticsUrl = override.analyticsUrl || base.analyticsUrl || (mergedApiUrl.includes("localhost") ? LOCAL_RUST_URL : DEFAULT_ANALYTICS_URL);
|
|
228
|
-
return {
|
|
229
|
-
...base,
|
|
230
|
-
...override,
|
|
231
|
-
apiUrl: mergedApiUrl,
|
|
232
|
-
analyticsUrl: mergedAnalyticsUrl,
|
|
233
|
-
projectId: override.projectId || base.projectId,
|
|
234
|
-
apiKey: override.apiKey || base.apiKey
|
|
235
|
-
};
|
|
236
|
-
};
|
|
237
|
-
var getFullConfig = (partialConfig) => {
|
|
238
|
-
const envConfig = getEnvConfig();
|
|
239
|
-
return mergeConfigs(envConfig, partialConfig || {});
|
|
240
|
-
};
|
|
241
|
-
var validateConfig = (config) => {
|
|
242
|
-
const errors = [];
|
|
243
|
-
if (!config.projectId) errors.push("Missing projectId");
|
|
244
|
-
if (!config.apiUrl) errors.push("Missing apiUrl");
|
|
245
|
-
return errors;
|
|
246
|
-
};
|
|
366
|
+
// src/client.ts
|
|
367
|
+
init_config();
|
|
247
368
|
|
|
248
369
|
// src/content/cache-implementations.ts
|
|
249
370
|
var CacheTags = {
|
|
@@ -2457,6 +2578,7 @@ var nexus = new NexusClient();
|
|
|
2457
2578
|
var createNexusClient = (config) => new NexusClient(config);
|
|
2458
2579
|
|
|
2459
2580
|
// src/index.ts
|
|
2581
|
+
init_config();
|
|
2460
2582
|
var VERSION = "0.0.1";
|
|
2461
2583
|
export {
|
|
2462
2584
|
AnalyticsEngine,
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getEnvConfig
|
|
3
|
+
} from "./chunk-NOIMIIA5.js";
|
|
4
|
+
|
|
5
|
+
// src/content/local-cache-server.ts
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import path from "path";
|
|
8
|
+
|
|
9
|
+
// src/content/binary-compiler.ts
|
|
10
|
+
import * as crypto from "crypto";
|
|
11
|
+
var BinaryCompiler = class {
|
|
12
|
+
/**
|
|
13
|
+
* Generates a secure, deterministic cryptographic key from the project's API key.
|
|
14
|
+
*/
|
|
15
|
+
static deriveKeys(apiKey) {
|
|
16
|
+
const hash = crypto.createHash("sha256").update(apiKey).digest();
|
|
17
|
+
const encryptionKey = hash;
|
|
18
|
+
const hmacKey = crypto.createHmac("sha256", apiKey).update("nexus-integrity-key").digest();
|
|
19
|
+
return { encryptionKey, hmacKey };
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Compiles JSON content data into a secure, signed, and encrypted .nx binary buffer.
|
|
23
|
+
*/
|
|
24
|
+
static compile(data, apiKey, projectId, metadataOverrides = {}) {
|
|
25
|
+
const { encryptionKey, hmacKey } = this.deriveKeys(apiKey);
|
|
26
|
+
const metadata = {
|
|
27
|
+
version: "2.0.0",
|
|
28
|
+
compiledAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29
|
+
projectId,
|
|
30
|
+
...metadataOverrides
|
|
31
|
+
};
|
|
32
|
+
const metadataStr = JSON.stringify(metadata);
|
|
33
|
+
const metadataBuffer = Buffer.from(metadataStr, "utf-8");
|
|
34
|
+
const iv = crypto.randomBytes(16);
|
|
35
|
+
const cipher = crypto.createCipheriv(this.ALGORITHM, encryptionKey, iv);
|
|
36
|
+
const plainTextPayload = JSON.stringify(data);
|
|
37
|
+
let encryptedPayload = cipher.update(plainTextPayload, "utf8");
|
|
38
|
+
encryptedPayload = Buffer.concat([encryptedPayload, cipher.final()]);
|
|
39
|
+
const payloadBuffer = Buffer.concat([iv, encryptedPayload]);
|
|
40
|
+
const headerBuffer = Buffer.from(this.MAGIC_HEADER, "ascii");
|
|
41
|
+
const metaLengthBuffer = Buffer.alloc(4);
|
|
42
|
+
metaLengthBuffer.writeUInt32BE(metadataBuffer.length, 0);
|
|
43
|
+
const payloadLengthBuffer = Buffer.alloc(4);
|
|
44
|
+
payloadLengthBuffer.writeUInt32BE(payloadBuffer.length, 0);
|
|
45
|
+
const prefixBlock = Buffer.concat([
|
|
46
|
+
headerBuffer,
|
|
47
|
+
metaLengthBuffer,
|
|
48
|
+
metadataBuffer,
|
|
49
|
+
payloadLengthBuffer,
|
|
50
|
+
payloadBuffer
|
|
51
|
+
]);
|
|
52
|
+
const hmac = crypto.createHmac("sha256", hmacKey);
|
|
53
|
+
hmac.update(prefixBlock);
|
|
54
|
+
const signature = hmac.digest();
|
|
55
|
+
return Buffer.concat([prefixBlock, signature]);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Verifies, decrypts, and decompiles a .nx binary buffer back into clean, type-safe JSON.
|
|
59
|
+
* Throws structured errors on integrity verification failures or file corruption.
|
|
60
|
+
*/
|
|
61
|
+
static decompile(buffer, apiKey) {
|
|
62
|
+
if (buffer.length < 44) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
"Corrupted File: Binary payload is too short to be a valid Nexus node."
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
const { encryptionKey, hmacKey } = this.deriveKeys(apiKey);
|
|
68
|
+
const prefixBlockLength = buffer.length - 32;
|
|
69
|
+
const prefixBlock = buffer.subarray(0, prefixBlockLength);
|
|
70
|
+
const expectedSignature = buffer.subarray(prefixBlockLength);
|
|
71
|
+
const hmac = crypto.createHmac("sha256", hmacKey);
|
|
72
|
+
hmac.update(prefixBlock);
|
|
73
|
+
const actualSignature = hmac.digest();
|
|
74
|
+
if (!crypto.timingSafeEqual(expectedSignature, actualSignature)) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
"DATA_INTEGRITY_VIOLATION: Cryptographic signature mismatch. This local node has been modified externally or tampered with."
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
const magicHeader = prefixBlock.subarray(0, 4).toString("ascii");
|
|
80
|
+
if (magicHeader !== this.MAGIC_HEADER) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
"Invalid Format: File lacks the correct Nexus binary magic header."
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
const metaLength = prefixBlock.readUInt32BE(4);
|
|
86
|
+
const metaStart = 8;
|
|
87
|
+
const metaEnd = metaStart + metaLength;
|
|
88
|
+
const metadataStr = prefixBlock.subarray(metaStart, metaEnd).toString("utf-8");
|
|
89
|
+
const metadata = JSON.parse(metadataStr);
|
|
90
|
+
const payloadLength = prefixBlock.readUInt32BE(metaEnd);
|
|
91
|
+
const payloadStart = metaEnd + 4;
|
|
92
|
+
const payloadEnd = payloadStart + payloadLength;
|
|
93
|
+
const payloadBuffer = prefixBlock.subarray(payloadStart, payloadEnd);
|
|
94
|
+
const iv = payloadBuffer.subarray(0, 16);
|
|
95
|
+
const cipherText = payloadBuffer.subarray(16);
|
|
96
|
+
const decipher = crypto.createDecipheriv(this.ALGORITHM, encryptionKey, iv);
|
|
97
|
+
let decrypted = decipher.update(cipherText);
|
|
98
|
+
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
|
99
|
+
const data = JSON.parse(decrypted.toString("utf8"));
|
|
100
|
+
return { data, metadata };
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
BinaryCompiler.MAGIC_HEADER = "NEXS";
|
|
104
|
+
// 4-byte ASCII magic identifier
|
|
105
|
+
BinaryCompiler.ALGORITHM = "aes-256-cbc";
|
|
106
|
+
|
|
107
|
+
// src/content/local-cache-server.ts
|
|
108
|
+
var LocalCache = class {
|
|
109
|
+
constructor(customPath) {
|
|
110
|
+
this.apiKey = "";
|
|
111
|
+
this.baseDir = customPath || ".nexus/local";
|
|
112
|
+
const config = getEnvConfig();
|
|
113
|
+
this.apiKey = config.apiKey || "";
|
|
114
|
+
}
|
|
115
|
+
isLoaded() {
|
|
116
|
+
return fs.existsSync(path.resolve(process.cwd(), this.baseDir));
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Helper to decrypt and decompile `.nx` files on-the-fly.
|
|
120
|
+
*/
|
|
121
|
+
decompileFile(filePath) {
|
|
122
|
+
if (!this.apiKey) {
|
|
123
|
+
if (process.env.NODE_ENV === "development") {
|
|
124
|
+
console.warn(
|
|
125
|
+
"\u26A0\uFE0F NexusHub: Missing NEXUS_API_KEY. Local decryption bypassed."
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const encryptedBuffer = fs.readFileSync(filePath);
|
|
132
|
+
const decompiled = BinaryCompiler.decompile(encryptedBuffer, this.apiKey);
|
|
133
|
+
return decompiled.data;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
if (process.env.NODE_ENV === "development") {
|
|
136
|
+
console.error(
|
|
137
|
+
`
|
|
138
|
+
\u{1F6A8} NexusHub Security Alert: Data Integrity Violation in file:
|
|
139
|
+
${filePath}
|
|
140
|
+
Error: ${error.message}
|
|
141
|
+
This file has been disabled until regenerated via npx nexus pull.
|
|
142
|
+
`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Retrieve a specific page directly from its .nx file.
|
|
150
|
+
*/
|
|
151
|
+
async getPage(slug) {
|
|
152
|
+
const filePath = path.resolve(
|
|
153
|
+
process.cwd(),
|
|
154
|
+
this.baseDir,
|
|
155
|
+
"pages",
|
|
156
|
+
`${slug}.nx`
|
|
157
|
+
);
|
|
158
|
+
if (fs.existsSync(filePath)) {
|
|
159
|
+
const pageData = this.decompileFile(filePath);
|
|
160
|
+
if (!pageData) return null;
|
|
161
|
+
return pageData.data !== void 0 ? pageData.data : pageData;
|
|
162
|
+
}
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Retrieve an entire collection from its specific .nx file.
|
|
167
|
+
*/
|
|
168
|
+
async getCollection(collectionId) {
|
|
169
|
+
const filePath = path.resolve(
|
|
170
|
+
process.cwd(),
|
|
171
|
+
this.baseDir,
|
|
172
|
+
"collections",
|
|
173
|
+
`${collectionId}.nx`
|
|
174
|
+
);
|
|
175
|
+
if (fs.existsSync(filePath)) {
|
|
176
|
+
return this.decompileFile(filePath);
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Retrieve global settings from its .nx file.
|
|
182
|
+
*/
|
|
183
|
+
async getGlobals() {
|
|
184
|
+
const filePath = path.resolve(process.cwd(), this.baseDir, "globals.nx");
|
|
185
|
+
if (fs.existsSync(filePath)) {
|
|
186
|
+
return this.decompileFile(filePath);
|
|
187
|
+
}
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Returns a merged JSON of the entire workspace structure.
|
|
192
|
+
*/
|
|
193
|
+
async getAllData() {
|
|
194
|
+
const pages = {};
|
|
195
|
+
const collections = {};
|
|
196
|
+
let globals = {};
|
|
197
|
+
try {
|
|
198
|
+
const pagesDir = path.resolve(process.cwd(), this.baseDir, "pages");
|
|
199
|
+
if (fs.existsSync(pagesDir)) {
|
|
200
|
+
for (const file of fs.readdirSync(pagesDir)) {
|
|
201
|
+
if (file.endsWith(".nx")) {
|
|
202
|
+
const slug = path.basename(file, ".nx");
|
|
203
|
+
pages[slug] = await this.getPage(slug);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const colsDir = path.resolve(process.cwd(), this.baseDir, "collections");
|
|
208
|
+
if (fs.existsSync(colsDir)) {
|
|
209
|
+
for (const file of fs.readdirSync(colsDir)) {
|
|
210
|
+
if (file.endsWith(".nx")) {
|
|
211
|
+
const id = path.basename(file, ".nx");
|
|
212
|
+
collections[id] = await this.getCollection(id) || [];
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
globals = await this.getGlobals() || {};
|
|
217
|
+
} catch {
|
|
218
|
+
}
|
|
219
|
+
return { pages, collections, globals };
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
export {
|
|
223
|
+
LocalCache
|
|
224
|
+
};
|