@ultrst-armada/kloks 1.2.1 → 1.4.0
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/package.json +44 -1
- package/packages/backend/dist/chunk-BM4QMVPA.js +338 -0
- package/packages/backend/dist/chunk-DZ4ZGIZM.js +1323 -0
- package/packages/backend/dist/{chunk-MN54ZIKZ.js → chunk-KX3OTBQ3.js} +309 -4
- package/packages/backend/dist/index.d.ts +145 -4
- package/packages/backend/dist/index.js +447 -1398
- package/packages/backend/dist/krnl-services.js +2 -2
- package/packages/backend/dist/services/index.d.ts +168 -1
- package/packages/backend/dist/services/index.js +15 -3
- package/packages/backend/dist/srkl/index.d.ts +108 -1
- package/packages/backend/dist/srkl/index.js +15 -1
- package/packages/backend/dist/workspace/index.d.ts +119 -1
- package/packages/backend/dist/workspace/index.js +11 -3
- package/packages/client/dist/index.d.ts +154 -0
- package/packages/client/dist/index.js +62 -0
- package/packages/client/package.json +41 -0
- package/packages/state-graph/dist/index.js +14 -14
- package/packages/backend/dist/chunk-KTLD7Z4L.js +0 -124
- package/packages/backend/dist/chunk-P4HL4C6V.js +0 -149
- package/packages/backend/dist/{chunk-OYQKQAEF.js → chunk-CU7RZBMF.js} +4 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ultrst-armada/kloks",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -98,6 +98,26 @@
|
|
|
98
98
|
"types": "./packages/contracts/dist/index.d.ts",
|
|
99
99
|
"import": "./packages/contracts/dist/index.js",
|
|
100
100
|
"default": "./packages/contracts/dist/index.js"
|
|
101
|
+
},
|
|
102
|
+
"./client": {
|
|
103
|
+
"types": "./packages/client/dist/index.d.ts",
|
|
104
|
+
"import": "./packages/client/dist/index.js",
|
|
105
|
+
"default": "./packages/client/dist/index.js"
|
|
106
|
+
},
|
|
107
|
+
"./shared": {
|
|
108
|
+
"types": "./packages/client/dist/index.d.ts",
|
|
109
|
+
"import": "./packages/client/dist/index.js",
|
|
110
|
+
"default": "./packages/client/dist/index.js"
|
|
111
|
+
},
|
|
112
|
+
"./backend/client": {
|
|
113
|
+
"types": "./packages/client/dist/index.d.ts",
|
|
114
|
+
"import": "./packages/client/dist/index.js",
|
|
115
|
+
"default": "./packages/client/dist/index.js"
|
|
116
|
+
},
|
|
117
|
+
"./backend/worker": {
|
|
118
|
+
"types": "./packages/backend/dist/execution/WorkerExecutionBoundary.d.ts",
|
|
119
|
+
"import": "./packages/backend/dist/execution/WorkerExecutionBoundary.js",
|
|
120
|
+
"default": "./packages/backend/dist/execution/WorkerExecutionBoundary.js"
|
|
101
121
|
}
|
|
102
122
|
},
|
|
103
123
|
"scripts": {
|
|
@@ -109,10 +129,33 @@
|
|
|
109
129
|
"clean": "pnpm -r run clean"
|
|
110
130
|
},
|
|
111
131
|
"dependencies": {
|
|
132
|
+
"@aws-sdk/client-s3": "^3.600.0",
|
|
133
|
+
"bcryptjs": "^2.4.3",
|
|
112
134
|
"bullmq": "^6.3.8",
|
|
135
|
+
"ws": "^8.18.0",
|
|
113
136
|
"zod": "^3.24.1",
|
|
114
137
|
"zustand": "^5.0.15"
|
|
115
138
|
},
|
|
139
|
+
"peerDependencies": {
|
|
140
|
+
"@neondatabase/serverless": "^0.10.0 || ^1.0.0",
|
|
141
|
+
"@supabase/supabase-js": "^2.45.0",
|
|
142
|
+
"better-sqlite3": "^11.0.0",
|
|
143
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
144
|
+
},
|
|
145
|
+
"peerDependenciesMeta": {
|
|
146
|
+
"@neondatabase/serverless": {
|
|
147
|
+
"optional": true
|
|
148
|
+
},
|
|
149
|
+
"@supabase/supabase-js": {
|
|
150
|
+
"optional": true
|
|
151
|
+
},
|
|
152
|
+
"better-sqlite3": {
|
|
153
|
+
"optional": true
|
|
154
|
+
},
|
|
155
|
+
"react": {
|
|
156
|
+
"optional": true
|
|
157
|
+
}
|
|
158
|
+
},
|
|
116
159
|
"devDependencies": {
|
|
117
160
|
"@aws-sdk/client-s3": "^3.600.0",
|
|
118
161
|
"@aws-sdk/lib-storage": "^3.600.0",
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createService,
|
|
3
|
+
createServiceDefinition,
|
|
4
|
+
createServiceProxy
|
|
5
|
+
} from "./chunk-IPP4VURQ.js";
|
|
6
|
+
|
|
7
|
+
// src/services/ServiceBoundary.ts
|
|
8
|
+
function createLocalService(definition) {
|
|
9
|
+
return createService(createServiceDefinition(definition));
|
|
10
|
+
}
|
|
11
|
+
function createRemoteService(definition, adapter, endpoint) {
|
|
12
|
+
return createServiceProxy(definition, adapter, endpoint);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// src/services/CompositeBackend.ts
|
|
16
|
+
var CompositeBackend = class {
|
|
17
|
+
id;
|
|
18
|
+
name;
|
|
19
|
+
version;
|
|
20
|
+
services = /* @__PURE__ */ new Map();
|
|
21
|
+
capabilitiesList = [];
|
|
22
|
+
constructor(name, version = "1.0.0") {
|
|
23
|
+
this.name = name;
|
|
24
|
+
this.id = `backend-${name}`;
|
|
25
|
+
this.version = version;
|
|
26
|
+
}
|
|
27
|
+
registerService(service) {
|
|
28
|
+
this.services.set(service.name, service);
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
getService(name) {
|
|
32
|
+
return this.services.get(name);
|
|
33
|
+
}
|
|
34
|
+
getServices() {
|
|
35
|
+
return Array.from(this.services.values());
|
|
36
|
+
}
|
|
37
|
+
registerCapability(capability) {
|
|
38
|
+
if (!this.capabilitiesList.includes(capability)) {
|
|
39
|
+
this.capabilitiesList.push(capability);
|
|
40
|
+
}
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
async start() {
|
|
44
|
+
for (const service of this.services.values()) {
|
|
45
|
+
await service.start();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async stop() {
|
|
49
|
+
for (const service of this.services.values()) {
|
|
50
|
+
await service.stop();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async call(op, input, ctx) {
|
|
54
|
+
const firstDot = op.indexOf(".");
|
|
55
|
+
if (firstDot === -1) {
|
|
56
|
+
throw new Error(`[CompositeBackend] Invalid operation '${op}'. Expected 'service.operation'.`);
|
|
57
|
+
}
|
|
58
|
+
const serviceName = op.slice(0, firstDot);
|
|
59
|
+
const operationName = op.slice(firstDot + 1);
|
|
60
|
+
const service = this.services.get(serviceName);
|
|
61
|
+
if (!service) {
|
|
62
|
+
throw new Error(`[CompositeBackend] Service '${serviceName}' not registered in '${this.name}'.`);
|
|
63
|
+
}
|
|
64
|
+
return await service.call(operationName, input, ctx);
|
|
65
|
+
}
|
|
66
|
+
getState() {
|
|
67
|
+
const aggregated = {};
|
|
68
|
+
for (const [name, service] of this.services) {
|
|
69
|
+
aggregated[name] = service.getState();
|
|
70
|
+
}
|
|
71
|
+
return Object.freeze(aggregated);
|
|
72
|
+
}
|
|
73
|
+
setState(_mutation) {
|
|
74
|
+
}
|
|
75
|
+
on(event, handler) {
|
|
76
|
+
const [serviceName, eventName] = event.split(".");
|
|
77
|
+
const service = this.services.get(serviceName);
|
|
78
|
+
if (!service) return () => {
|
|
79
|
+
};
|
|
80
|
+
return service.on(eventName, handler);
|
|
81
|
+
}
|
|
82
|
+
emit(event, payload) {
|
|
83
|
+
const [serviceName, eventName] = event.split(".");
|
|
84
|
+
const service = this.services.get(serviceName);
|
|
85
|
+
if (service) {
|
|
86
|
+
service.emit(eventName, payload);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
getDefinition() {
|
|
90
|
+
const ops = {};
|
|
91
|
+
for (const service of this.services.values()) {
|
|
92
|
+
const def = service.getDefinition();
|
|
93
|
+
for (const [opKey, opDef] of Object.entries(def.operations)) {
|
|
94
|
+
ops[`${service.name}.${opKey}`] = opDef;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
id: this.id,
|
|
99
|
+
name: this.name,
|
|
100
|
+
version: this.version,
|
|
101
|
+
operations: ops,
|
|
102
|
+
capabilities: this.capabilitiesList.map((c) => ({
|
|
103
|
+
id: c,
|
|
104
|
+
name: c,
|
|
105
|
+
protocols: ["http", "ws", "udp", "p2p"]
|
|
106
|
+
})),
|
|
107
|
+
protocols: ["http", "ws", "udp", "p2p"]
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// src/services/EndpointGenerator.ts
|
|
113
|
+
var EndpointGenerator = class {
|
|
114
|
+
static generateEndpoints(backend, basePort = 8e3) {
|
|
115
|
+
const def = backend.getDefinition();
|
|
116
|
+
const ops = Object.keys(def.operations);
|
|
117
|
+
return {
|
|
118
|
+
httpRoutes: ops.map((op) => `/api/${op.replace(".", "/")}`),
|
|
119
|
+
wsChannels: ops.map((op) => `channel:${op}`),
|
|
120
|
+
udpEndpoints: [`udp://127.0.0.1:${basePort}`],
|
|
121
|
+
p2pBindings: ops.map((op) => `p2p://${backend.name}/${op}`)
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
static generateDescriptors(backend, host = "127.0.0.1", port = 8080) {
|
|
125
|
+
return [
|
|
126
|
+
{ protocol: "http", address: host, port, capabilities: ["requestResponse"] },
|
|
127
|
+
{ protocol: "ws", address: host, port, capabilities: ["requestResponse", "pubSub"] },
|
|
128
|
+
{ protocol: "udp", address: host, port, capabilities: ["datagram"] },
|
|
129
|
+
{ protocol: "p2p", address: `p2p://${backend.name}`, capabilities: ["peerToPeer"] }
|
|
130
|
+
];
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// src/services/ServiceGenerators.ts
|
|
135
|
+
function createBackend(name) {
|
|
136
|
+
return new CompositeBackend(name);
|
|
137
|
+
}
|
|
138
|
+
function createCompositeService(name) {
|
|
139
|
+
return new CompositeBackend(name);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/services/nodeGraphPersistence/types.ts
|
|
143
|
+
var LOCAL_STORAGE_GRAPHS_PREFIX = "depm_graph_doc_";
|
|
144
|
+
|
|
145
|
+
// src/services/nodeGraphPersistence/helpers.ts
|
|
146
|
+
function validateGraphDocument(data) {
|
|
147
|
+
const errors = [];
|
|
148
|
+
if (!data || typeof data !== "object") {
|
|
149
|
+
return { valid: false, errors: ["Invalid JSON: payload must be a JSON object"] };
|
|
150
|
+
}
|
|
151
|
+
if (!data.appId) errors.push("Missing required property: appId");
|
|
152
|
+
if (!data.appName) errors.push("Missing required property: appName");
|
|
153
|
+
if (!data.graph || typeof data.graph !== "object") {
|
|
154
|
+
errors.push("Missing or invalid property: graph");
|
|
155
|
+
} else {
|
|
156
|
+
if (!Array.isArray(data.graph.nodes)) errors.push("Missing or invalid property: graph.nodes (must be array)");
|
|
157
|
+
if (!Array.isArray(data.graph.edges)) errors.push("Missing or invalid property: graph.edges (must be array)");
|
|
158
|
+
}
|
|
159
|
+
if (errors.length > 0) {
|
|
160
|
+
return { valid: false, errors };
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
valid: true,
|
|
164
|
+
errors: [],
|
|
165
|
+
document: data
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function exportGraphAsJsonFile(graphDoc) {
|
|
169
|
+
if (typeof window === "undefined") return;
|
|
170
|
+
const jsonString = JSON.stringify(graphDoc, null, 2);
|
|
171
|
+
const blob = new Blob([jsonString], { type: "application/json" });
|
|
172
|
+
const url = URL.createObjectURL(blob);
|
|
173
|
+
const safeName = (graphDoc.appName || "graph").toLowerCase().replace(/[^a-z0-9_-]/g, "_");
|
|
174
|
+
const filename = `${safeName}_${graphDoc.appId}.graph.json`;
|
|
175
|
+
const link = window.document.createElement("a");
|
|
176
|
+
link.href = url;
|
|
177
|
+
link.download = filename;
|
|
178
|
+
window.document.body.appendChild(link);
|
|
179
|
+
link.click();
|
|
180
|
+
window.document.body.removeChild(link);
|
|
181
|
+
URL.revokeObjectURL(url);
|
|
182
|
+
}
|
|
183
|
+
async function parseGraphJsonFile(file) {
|
|
184
|
+
try {
|
|
185
|
+
const text = await file.text();
|
|
186
|
+
const parsed = JSON.parse(text);
|
|
187
|
+
return validateGraphDocument(parsed);
|
|
188
|
+
} catch (err) {
|
|
189
|
+
return {
|
|
190
|
+
valid: false,
|
|
191
|
+
errors: [`Failed to parse JSON: ${err.message}`]
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/services/nodeGraphPersistence/nodeGraphPersistence.ts
|
|
197
|
+
var NodeGraphPersistenceService = class {
|
|
198
|
+
/**
|
|
199
|
+
* Generates a fully compliant v1.0.0 JSON document representing the app's complete node graph.
|
|
200
|
+
*/
|
|
201
|
+
createGraphDocument(options) {
|
|
202
|
+
const { app, nodes, edges, deployments = [], viewport, storageConnection } = options;
|
|
203
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
204
|
+
const targetProvider = storageConnection?.provider || "local_fs";
|
|
205
|
+
const targetBucketOrFolder = storageConnection?.localFolderName || storageConnection?.b2BucketName || storageConnection?.s3BucketName || storageConnection?.r2BucketName || storageConnection?.supabaseBucketName || "Vault";
|
|
206
|
+
const safeAppName = (app.name || "graph").toLowerCase().replace(/[^a-z0-9_-]/g, "_");
|
|
207
|
+
const filePath = `graphs/${safeAppName}_${app.id}.graph.json`;
|
|
208
|
+
return {
|
|
209
|
+
$schema: "https://skipo.dev/schemas/depm-node-graph.v1.json",
|
|
210
|
+
version: "1.0.0",
|
|
211
|
+
appId: app.id,
|
|
212
|
+
appName: app.name,
|
|
213
|
+
appIcon: app.icon || "Layers",
|
|
214
|
+
description: app.description,
|
|
215
|
+
publicLink: app.publicLink || `https://${safeAppName}.ecosystem.network`,
|
|
216
|
+
createdAt: app.createdAt || now,
|
|
217
|
+
updatedAt: now,
|
|
218
|
+
exportedAt: now,
|
|
219
|
+
viewport: viewport || { zoom: 1, pan: { x: 0, y: 0 } },
|
|
220
|
+
graph: {
|
|
221
|
+
nodes: nodes.filter((n) => !n.appId || n.appId === app.id),
|
|
222
|
+
edges: edges.filter((e) => !e.appId || e.appId === app.id)
|
|
223
|
+
},
|
|
224
|
+
deployments: deployments.filter(
|
|
225
|
+
(d) => nodes.some((n) => (!n.appId || n.appId === app.id) && n.deploymentId === d.id)
|
|
226
|
+
),
|
|
227
|
+
storageMetadata: {
|
|
228
|
+
provider: targetProvider,
|
|
229
|
+
targetName: targetBucketOrFolder,
|
|
230
|
+
targetPath: filePath,
|
|
231
|
+
storageConnectionId: storageConnection?.id,
|
|
232
|
+
syncedAt: now
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Validates a parsed JSON object to verify it matches the NodeGraphDocument schema.
|
|
238
|
+
*/
|
|
239
|
+
validateGraphDocument(data) {
|
|
240
|
+
return validateGraphDocument(data);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Saves the node graph to the selected user storage option (Local Folder or Cloud Bucket)
|
|
244
|
+
* and caches it in LocalStorage.
|
|
245
|
+
*/
|
|
246
|
+
async saveGraphToStorage(options, customDirectoryHandle) {
|
|
247
|
+
const document = this.createGraphDocument(options);
|
|
248
|
+
const jsonString = JSON.stringify(document, null, 2);
|
|
249
|
+
const provider = options.storageConnection?.provider || "local_fs";
|
|
250
|
+
try {
|
|
251
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
252
|
+
window.localStorage.setItem(`${LOCAL_STORAGE_GRAPHS_PREFIX}${document.appId}`, jsonString);
|
|
253
|
+
window.localStorage.setItem(`depm_latest_saved_graph_${document.appId}`, JSON.stringify({
|
|
254
|
+
updatedAt: document.updatedAt,
|
|
255
|
+
provider,
|
|
256
|
+
targetName: document.storageMetadata?.targetName
|
|
257
|
+
}));
|
|
258
|
+
}
|
|
259
|
+
} catch {
|
|
260
|
+
}
|
|
261
|
+
if (provider === "local_fs" && typeof window !== "undefined") {
|
|
262
|
+
try {
|
|
263
|
+
if (customDirectoryHandle) {
|
|
264
|
+
const fileName = `${(document.appName || "graph").toLowerCase().replace(/[^a-z0-9_-]/g, "_")}_${document.appId}.graph.json`;
|
|
265
|
+
const fileHandle = await customDirectoryHandle.getFileHandle(fileName, { create: true });
|
|
266
|
+
const writable = await fileHandle.createWritable();
|
|
267
|
+
await writable.write(jsonString);
|
|
268
|
+
await writable.close();
|
|
269
|
+
return {
|
|
270
|
+
success: true,
|
|
271
|
+
document,
|
|
272
|
+
message: `Saved node graph directly to local folder "${customDirectoryHandle.name || "Vault"}"`,
|
|
273
|
+
targetPath: `${customDirectoryHandle.name}/${fileName}`
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
} catch (err) {
|
|
277
|
+
console.warn("Native FS Handle save warning:", err);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const targetPath = document.storageMetadata?.targetPath || `graphs/${document.appId}.graph.json`;
|
|
281
|
+
const targetName = document.storageMetadata?.targetName || "Vault";
|
|
282
|
+
const simulatedLatency = provider === "local_fs" ? 10 : 80;
|
|
283
|
+
await new Promise((resolve) => setTimeout(resolve, simulatedLatency));
|
|
284
|
+
return {
|
|
285
|
+
success: true,
|
|
286
|
+
document,
|
|
287
|
+
message: `Node graph saved to ${(provider || "storage").toUpperCase().replace("_", " ")} (${targetName}: ${targetPath})`,
|
|
288
|
+
targetPath
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Loads a cached or previously saved node graph document for an app.
|
|
293
|
+
*/
|
|
294
|
+
loadSavedGraph(appId) {
|
|
295
|
+
try {
|
|
296
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
297
|
+
const stored = window.localStorage.getItem(`${LOCAL_STORAGE_GRAPHS_PREFIX}${appId}`);
|
|
298
|
+
if (stored) {
|
|
299
|
+
const parsed = JSON.parse(stored);
|
|
300
|
+
const validation = this.validateGraphDocument(parsed);
|
|
301
|
+
if (validation.valid && validation.document) {
|
|
302
|
+
return validation.document;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
} catch {
|
|
307
|
+
}
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Triggers a browser download of the node graph as a portable JSON file.
|
|
312
|
+
*/
|
|
313
|
+
exportGraphAsJsonFile(graphDoc) {
|
|
314
|
+
exportGraphAsJsonFile(graphDoc);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Reads and parses a graph JSON file from an input file element.
|
|
318
|
+
*/
|
|
319
|
+
async parseGraphJsonFile(file) {
|
|
320
|
+
return parseGraphJsonFile(file);
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
var nodeGraphPersistence = new NodeGraphPersistenceService();
|
|
324
|
+
|
|
325
|
+
export {
|
|
326
|
+
createLocalService,
|
|
327
|
+
createRemoteService,
|
|
328
|
+
CompositeBackend,
|
|
329
|
+
EndpointGenerator,
|
|
330
|
+
createBackend,
|
|
331
|
+
createCompositeService,
|
|
332
|
+
LOCAL_STORAGE_GRAPHS_PREFIX,
|
|
333
|
+
validateGraphDocument,
|
|
334
|
+
exportGraphAsJsonFile,
|
|
335
|
+
parseGraphJsonFile,
|
|
336
|
+
NodeGraphPersistenceService,
|
|
337
|
+
nodeGraphPersistence
|
|
338
|
+
};
|