@exulu/backend 1.4.1 → 1.5.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/CHANGELOG.md +3 -3
- package/dist/index.cjs +1295 -1294
- package/dist/index.d.cts +1 -7
- package/dist/index.d.ts +1 -7
- package/dist/index.js +1295 -1293
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -37,7 +37,6 @@ __export(index_exports, {
|
|
|
37
37
|
ExuluAuthentication: () => authentication,
|
|
38
38
|
ExuluChunkers: () => ExuluChunkers,
|
|
39
39
|
ExuluContext: () => ExuluContext,
|
|
40
|
-
ExuluDatabase: () => ExuluDatabase,
|
|
41
40
|
ExuluEmbedder: () => ExuluEmbedder,
|
|
42
41
|
ExuluEval: () => ExuluEval,
|
|
43
42
|
ExuluJobs: () => ExuluJobs,
|
|
@@ -112,6 +111,32 @@ var validateJob = (job) => {
|
|
|
112
111
|
return job;
|
|
113
112
|
};
|
|
114
113
|
|
|
114
|
+
// src/registry/classes.ts
|
|
115
|
+
var import_zod = require("zod");
|
|
116
|
+
var import_bullmq2 = require("bullmq");
|
|
117
|
+
var import_zod2 = require("zod");
|
|
118
|
+
var fs = __toESM(require("fs"), 1);
|
|
119
|
+
var path = __toESM(require("path"), 1);
|
|
120
|
+
var import_ai = require("ai");
|
|
121
|
+
|
|
122
|
+
// types/enums/statistics.ts
|
|
123
|
+
var STATISTICS_TYPE_ENUM = {
|
|
124
|
+
CONTEXT_RETRIEVE: "context.retrieve",
|
|
125
|
+
SOURCE_UPDATE: "source.update",
|
|
126
|
+
EMBEDDER_UPSERT: "embedder.upsert",
|
|
127
|
+
EMBEDDER_GENERATE: "embedder.generate",
|
|
128
|
+
EMBEDDER_DELETE: "embedder.delete",
|
|
129
|
+
WORKFLOW_RUN: "workflow.run",
|
|
130
|
+
CONTEXT_UPSERT: "context.upsert",
|
|
131
|
+
TOOL_CALL: "tool.call",
|
|
132
|
+
AGENT_RUN: "agent.run"
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// types/enums/eval-types.ts
|
|
136
|
+
var EVAL_TYPES_ENUM = {
|
|
137
|
+
llm_as_judge: "llm_as_judge"
|
|
138
|
+
};
|
|
139
|
+
|
|
115
140
|
// src/postgres/client.ts
|
|
116
141
|
var import_knex = __toESM(require("knex"), 1);
|
|
117
142
|
var import_knex2 = require("knex");
|
|
@@ -149,745 +174,142 @@ async function postgresClient() {
|
|
|
149
174
|
};
|
|
150
175
|
}
|
|
151
176
|
|
|
152
|
-
// src/
|
|
153
|
-
var
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
{
|
|
180
|
-
name: "agent",
|
|
181
|
-
type: "uuid"
|
|
182
|
-
},
|
|
177
|
+
// src/registry/classes.ts
|
|
178
|
+
var import_knex4 = __toESM(require("pgvector/knex"), 1);
|
|
179
|
+
|
|
180
|
+
// src/registry/decoraters/bullmq.ts
|
|
181
|
+
var import_bullmq = require("bullmq");
|
|
182
|
+
var import_uuid = require("uuid");
|
|
183
|
+
var bullmqDecorator = async ({
|
|
184
|
+
label,
|
|
185
|
+
type,
|
|
186
|
+
workflow,
|
|
187
|
+
embedder,
|
|
188
|
+
inputs,
|
|
189
|
+
queue,
|
|
190
|
+
user,
|
|
191
|
+
agent,
|
|
192
|
+
session,
|
|
193
|
+
configuration,
|
|
194
|
+
updater,
|
|
195
|
+
context,
|
|
196
|
+
steps,
|
|
197
|
+
source,
|
|
198
|
+
documents,
|
|
199
|
+
trigger,
|
|
200
|
+
item
|
|
201
|
+
}) => {
|
|
202
|
+
const redisId = (0, import_uuid.v4)();
|
|
203
|
+
const job = await queue.add(
|
|
204
|
+
`${embedder || workflow}`,
|
|
183
205
|
{
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
206
|
+
type: `${type}`,
|
|
207
|
+
...embedder && { embedder },
|
|
208
|
+
...workflow && { workflow },
|
|
209
|
+
...configuration && { configuration },
|
|
210
|
+
...updater && { updater },
|
|
211
|
+
...context && { context },
|
|
212
|
+
...source && { source },
|
|
213
|
+
...documents && { documents },
|
|
214
|
+
...steps && { steps },
|
|
215
|
+
...trigger && { trigger },
|
|
216
|
+
...item && { item },
|
|
217
|
+
agent,
|
|
218
|
+
user,
|
|
219
|
+
inputs,
|
|
220
|
+
label,
|
|
221
|
+
session
|
|
187
222
|
},
|
|
188
223
|
{
|
|
189
|
-
|
|
190
|
-
type: "text"
|
|
224
|
+
jobId: redisId
|
|
191
225
|
}
|
|
192
|
-
|
|
226
|
+
);
|
|
227
|
+
const { db: db2 } = await postgresClient();
|
|
228
|
+
const now = /* @__PURE__ */ new Date();
|
|
229
|
+
console.log("[EXULU] scheduling new job", inputs);
|
|
230
|
+
const insertData = {
|
|
231
|
+
name: `${label}`,
|
|
232
|
+
redis: job.id,
|
|
233
|
+
status: "waiting",
|
|
234
|
+
type,
|
|
235
|
+
inputs,
|
|
236
|
+
agent,
|
|
237
|
+
item,
|
|
238
|
+
createdAt: now,
|
|
239
|
+
updatedAt: now,
|
|
240
|
+
user,
|
|
241
|
+
session,
|
|
242
|
+
...embedder && { embedder },
|
|
243
|
+
...workflow && { workflow },
|
|
244
|
+
...configuration && { configuration },
|
|
245
|
+
...steps && { steps },
|
|
246
|
+
...updater && { updater },
|
|
247
|
+
...context && { context },
|
|
248
|
+
...source && { source },
|
|
249
|
+
...documents && { documents: documents.map((doc2) => doc2.id) },
|
|
250
|
+
...trigger && { trigger }
|
|
251
|
+
};
|
|
252
|
+
await db2("jobs").insert(insertData).onConflict("redis").merge({
|
|
253
|
+
...insertData,
|
|
254
|
+
updatedAt: now
|
|
255
|
+
// Only updatedAt changes on updates
|
|
256
|
+
});
|
|
257
|
+
const doc = await db2.from("jobs").where({ redis: job.id }).first();
|
|
258
|
+
if (!doc?.id) {
|
|
259
|
+
throw new Error("Failed to get job ID after insert/update");
|
|
260
|
+
}
|
|
261
|
+
console.log("[EXULU] created job", doc?.id);
|
|
262
|
+
return {
|
|
263
|
+
...job,
|
|
264
|
+
id: doc?.id,
|
|
265
|
+
redis: job.id
|
|
266
|
+
};
|
|
193
267
|
};
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
},
|
|
235
|
-
{
|
|
236
|
-
name: "status",
|
|
237
|
-
type: "text"
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
name: "emailVerified",
|
|
241
|
-
type: "text"
|
|
242
|
-
},
|
|
243
|
-
{
|
|
244
|
-
name: "apikey",
|
|
245
|
-
type: "text"
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
name: "last_used",
|
|
249
|
-
type: "date"
|
|
250
|
-
},
|
|
251
|
-
{
|
|
252
|
-
name: "anthropic_token",
|
|
253
|
-
type: "text"
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
name: "role",
|
|
257
|
-
type: "uuid"
|
|
258
|
-
}
|
|
259
|
-
]
|
|
268
|
+
|
|
269
|
+
// src/registry/utils/map-types.ts
|
|
270
|
+
var mapType = (t, type, name, defaultValue) => {
|
|
271
|
+
if (type === "text") {
|
|
272
|
+
t.text(name);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (type === "longText") {
|
|
276
|
+
t.text(name);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (type === "shortText") {
|
|
280
|
+
t.string(name, 100);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
if (type === "number") {
|
|
284
|
+
t.float(name);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
if (type === "boolean") {
|
|
288
|
+
t.boolean(name).defaultTo(defaultValue || false);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if (type === "code") {
|
|
292
|
+
t.text(name);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (type === "json") {
|
|
296
|
+
t.jsonb(name);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (type === "date") {
|
|
300
|
+
t.timestamp(name);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (type === "uuid") {
|
|
304
|
+
t.uuid(name);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
throw new Error("Invalid type: " + type);
|
|
260
308
|
};
|
|
261
|
-
var rolesSchema = {
|
|
262
|
-
name: {
|
|
263
|
-
plural: "roles",
|
|
264
|
-
singular: "role"
|
|
265
|
-
},
|
|
266
|
-
fields: [
|
|
267
|
-
{
|
|
268
|
-
name: "name",
|
|
269
|
-
type: "text"
|
|
270
|
-
},
|
|
271
|
-
{
|
|
272
|
-
name: "is_admin",
|
|
273
|
-
type: "boolean",
|
|
274
|
-
default: false
|
|
275
|
-
},
|
|
276
|
-
{
|
|
277
|
-
name: "agents",
|
|
278
|
-
type: "json"
|
|
279
|
-
}
|
|
280
|
-
]
|
|
281
|
-
};
|
|
282
|
-
var statisticsSchema = {
|
|
283
|
-
name: {
|
|
284
|
-
plural: "statistics",
|
|
285
|
-
singular: "statistic"
|
|
286
|
-
},
|
|
287
|
-
fields: [
|
|
288
|
-
{
|
|
289
|
-
name: "name",
|
|
290
|
-
type: "text"
|
|
291
|
-
},
|
|
292
|
-
{
|
|
293
|
-
name: "label",
|
|
294
|
-
type: "text"
|
|
295
|
-
},
|
|
296
|
-
{
|
|
297
|
-
name: "type",
|
|
298
|
-
type: "text"
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
name: "total",
|
|
302
|
-
type: "number"
|
|
303
|
-
}
|
|
304
|
-
]
|
|
305
|
-
};
|
|
306
|
-
var workflowSchema = {
|
|
307
|
-
name: {
|
|
308
|
-
plural: "workflows",
|
|
309
|
-
singular: "workflow"
|
|
310
|
-
},
|
|
311
|
-
fields: [
|
|
312
|
-
{
|
|
313
|
-
name: "workflow_name",
|
|
314
|
-
type: "text"
|
|
315
|
-
},
|
|
316
|
-
{
|
|
317
|
-
name: "run_id",
|
|
318
|
-
type: "text"
|
|
319
|
-
},
|
|
320
|
-
{
|
|
321
|
-
name: "snapshot",
|
|
322
|
-
type: "text"
|
|
323
|
-
}
|
|
324
|
-
]
|
|
325
|
-
};
|
|
326
|
-
var evalResultsSchema = {
|
|
327
|
-
name: {
|
|
328
|
-
plural: "eval_results",
|
|
329
|
-
singular: "eval_result"
|
|
330
|
-
},
|
|
331
|
-
fields: [
|
|
332
|
-
{
|
|
333
|
-
name: "input",
|
|
334
|
-
type: "longText"
|
|
335
|
-
},
|
|
336
|
-
{
|
|
337
|
-
name: "output",
|
|
338
|
-
type: "longText"
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
name: "duration",
|
|
342
|
-
type: "number"
|
|
343
|
-
},
|
|
344
|
-
{
|
|
345
|
-
name: "category",
|
|
346
|
-
type: "text"
|
|
347
|
-
},
|
|
348
|
-
{
|
|
349
|
-
name: "metadata",
|
|
350
|
-
type: "json"
|
|
351
|
-
},
|
|
352
|
-
{
|
|
353
|
-
name: "result",
|
|
354
|
-
type: "number"
|
|
355
|
-
},
|
|
356
|
-
{
|
|
357
|
-
name: "agent_id",
|
|
358
|
-
type: "uuid"
|
|
359
|
-
},
|
|
360
|
-
{
|
|
361
|
-
name: "workflow_id",
|
|
362
|
-
type: "uuid"
|
|
363
|
-
},
|
|
364
|
-
{
|
|
365
|
-
name: "eval_type",
|
|
366
|
-
type: "text"
|
|
367
|
-
},
|
|
368
|
-
{
|
|
369
|
-
name: "eval_name",
|
|
370
|
-
type: "text"
|
|
371
|
-
},
|
|
372
|
-
{
|
|
373
|
-
name: "comment",
|
|
374
|
-
type: "longText"
|
|
375
|
-
}
|
|
376
|
-
]
|
|
377
|
-
};
|
|
378
|
-
var jobsSchema = {
|
|
379
|
-
name: {
|
|
380
|
-
plural: "jobs",
|
|
381
|
-
singular: "job"
|
|
382
|
-
},
|
|
383
|
-
fields: [
|
|
384
|
-
{
|
|
385
|
-
name: "redis",
|
|
386
|
-
type: "text"
|
|
387
|
-
},
|
|
388
|
-
{
|
|
389
|
-
name: "session",
|
|
390
|
-
type: "text"
|
|
391
|
-
},
|
|
392
|
-
{
|
|
393
|
-
name: "status",
|
|
394
|
-
type: "text"
|
|
395
|
-
},
|
|
396
|
-
{
|
|
397
|
-
name: "type",
|
|
398
|
-
type: "text"
|
|
399
|
-
},
|
|
400
|
-
{
|
|
401
|
-
name: "result",
|
|
402
|
-
type: "longText"
|
|
403
|
-
},
|
|
404
|
-
{
|
|
405
|
-
name: "name",
|
|
406
|
-
type: "text"
|
|
407
|
-
},
|
|
408
|
-
{
|
|
409
|
-
name: "agent",
|
|
410
|
-
type: "uuid"
|
|
411
|
-
},
|
|
412
|
-
{
|
|
413
|
-
name: "workflow",
|
|
414
|
-
type: "uuid"
|
|
415
|
-
},
|
|
416
|
-
{
|
|
417
|
-
name: "user",
|
|
418
|
-
// next auth stores users with id type SERIAL, so we need to use number
|
|
419
|
-
type: "number"
|
|
420
|
-
},
|
|
421
|
-
{
|
|
422
|
-
name: "item",
|
|
423
|
-
type: "uuid"
|
|
424
|
-
},
|
|
425
|
-
{
|
|
426
|
-
name: "steps",
|
|
427
|
-
type: "number"
|
|
428
|
-
},
|
|
429
|
-
{
|
|
430
|
-
name: "inputs",
|
|
431
|
-
type: "json"
|
|
432
|
-
},
|
|
433
|
-
{
|
|
434
|
-
name: "finished_at",
|
|
435
|
-
type: "date"
|
|
436
|
-
},
|
|
437
|
-
{
|
|
438
|
-
name: "duration",
|
|
439
|
-
type: "number"
|
|
440
|
-
}
|
|
441
|
-
]
|
|
442
|
-
};
|
|
443
|
-
var agentsSchema = {
|
|
444
|
-
name: {
|
|
445
|
-
plural: "agents",
|
|
446
|
-
singular: "agent"
|
|
447
|
-
},
|
|
448
|
-
fields: [
|
|
449
|
-
{
|
|
450
|
-
name: "name",
|
|
451
|
-
type: "text"
|
|
452
|
-
},
|
|
453
|
-
{
|
|
454
|
-
name: "description",
|
|
455
|
-
type: "text"
|
|
456
|
-
},
|
|
457
|
-
{
|
|
458
|
-
name: "extensions",
|
|
459
|
-
type: "json"
|
|
460
|
-
},
|
|
461
|
-
{
|
|
462
|
-
name: "backend",
|
|
463
|
-
type: "text"
|
|
464
|
-
},
|
|
465
|
-
{
|
|
466
|
-
name: "type",
|
|
467
|
-
type: "text"
|
|
468
|
-
},
|
|
469
|
-
{
|
|
470
|
-
name: "active",
|
|
471
|
-
type: "boolean",
|
|
472
|
-
default: false
|
|
473
|
-
},
|
|
474
|
-
{
|
|
475
|
-
name: "public",
|
|
476
|
-
type: "boolean",
|
|
477
|
-
default: false
|
|
478
|
-
},
|
|
479
|
-
{
|
|
480
|
-
name: "tools",
|
|
481
|
-
type: "json"
|
|
482
|
-
}
|
|
483
|
-
]
|
|
484
|
-
};
|
|
485
|
-
|
|
486
|
-
// src/registry/utils/map-types.ts
|
|
487
|
-
var mapType = (t, type, name, defaultValue) => {
|
|
488
|
-
if (type === "text") {
|
|
489
|
-
t.text(name);
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
492
|
-
if (type === "longText") {
|
|
493
|
-
t.text(name);
|
|
494
|
-
return;
|
|
495
|
-
}
|
|
496
|
-
if (type === "shortText") {
|
|
497
|
-
t.string(name, 100);
|
|
498
|
-
return;
|
|
499
|
-
}
|
|
500
|
-
if (type === "number") {
|
|
501
|
-
t.float(name);
|
|
502
|
-
return;
|
|
503
|
-
}
|
|
504
|
-
if (type === "boolean") {
|
|
505
|
-
t.boolean(name).defaultTo(defaultValue || false);
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
if (type === "code") {
|
|
509
|
-
t.text(name);
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
512
|
-
if (type === "json") {
|
|
513
|
-
t.jsonb(name);
|
|
514
|
-
return;
|
|
515
|
-
}
|
|
516
|
-
if (type === "date") {
|
|
517
|
-
t.timestamp(name);
|
|
518
|
-
return;
|
|
519
|
-
}
|
|
520
|
-
if (type === "uuid") {
|
|
521
|
-
t.uuid(name);
|
|
522
|
-
return;
|
|
523
|
-
}
|
|
524
|
-
throw new Error("Invalid type: " + type);
|
|
525
|
-
};
|
|
526
|
-
|
|
527
|
-
// src/registry/utils/sanitize-name.ts
|
|
528
|
-
var sanitizeName = (name) => {
|
|
529
|
-
return name.toLowerCase().replace(/ /g, "_");
|
|
530
|
-
};
|
|
531
|
-
|
|
532
|
-
// src/auth/generate-key.ts
|
|
533
|
-
var import_bcryptjs = __toESM(require("bcryptjs"), 1);
|
|
534
|
-
var SALT_ROUNDS = 12;
|
|
535
|
-
async function encryptString(string) {
|
|
536
|
-
const hash = await import_bcryptjs.default.hash(string, SALT_ROUNDS);
|
|
537
|
-
return hash;
|
|
538
|
-
}
|
|
539
|
-
var generateApiKey = async (name, email) => {
|
|
540
|
-
const { db: db2 } = await postgresClient();
|
|
541
|
-
console.log("[EXULU] Inserting default user and admin role.");
|
|
542
|
-
const existingRole = await db2.from("roles").where({ name: "admin" }).first();
|
|
543
|
-
let roleId;
|
|
544
|
-
if (!existingRole) {
|
|
545
|
-
console.log("[EXULU] Creating default admin role.");
|
|
546
|
-
const role = await db2.from("roles").insert({
|
|
547
|
-
name: "admin",
|
|
548
|
-
is_admin: true,
|
|
549
|
-
agents: []
|
|
550
|
-
}).returning("id");
|
|
551
|
-
roleId = role[0].id;
|
|
552
|
-
} else {
|
|
553
|
-
roleId = existingRole.id;
|
|
554
|
-
}
|
|
555
|
-
const newKeyName = name;
|
|
556
|
-
const plainKey = `sk_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
|
|
557
|
-
const postFix = `/${newKeyName.toLowerCase().trim().replaceAll(" ", "_")}`;
|
|
558
|
-
const encryptedKey = await encryptString(plainKey);
|
|
559
|
-
const existingApiUser = await db2.from("users").where({ email }).first();
|
|
560
|
-
if (!existingApiUser) {
|
|
561
|
-
console.log("[EXULU] Creating default api user.");
|
|
562
|
-
await db2.from("users").insert({
|
|
563
|
-
name,
|
|
564
|
-
email,
|
|
565
|
-
super_admin: true,
|
|
566
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
567
|
-
updatedAt: /* @__PURE__ */ new Date(),
|
|
568
|
-
type: "api",
|
|
569
|
-
emailVerified: /* @__PURE__ */ new Date(),
|
|
570
|
-
apikey: `${encryptedKey}${postFix}`,
|
|
571
|
-
// password: "admin", todo add this again when we implement password auth / encryption as alternative to OTP
|
|
572
|
-
role: roleId
|
|
573
|
-
});
|
|
574
|
-
console.log("[EXULU] Default api user created. Key: ", `${plainKey}${postFix}`);
|
|
575
|
-
} else {
|
|
576
|
-
console.log("[EXULU] API user with that name already exists.");
|
|
577
|
-
}
|
|
578
|
-
console.log("[EXULU] Key generated, copy and use the plain key from here, you will not be able to access it again.");
|
|
579
|
-
console.log("[EXULU] Key: ", `${plainKey}${postFix}`);
|
|
580
|
-
return {
|
|
581
|
-
key: `${plainKey}${postFix}`
|
|
582
|
-
};
|
|
583
|
-
};
|
|
584
|
-
|
|
585
|
-
// src/postgres/init-db.ts
|
|
586
|
-
var up = async function(knex) {
|
|
587
|
-
if (!await knex.schema.hasTable("agent_sessions")) {
|
|
588
|
-
await knex.schema.createTable("agent_sessions", (table) => {
|
|
589
|
-
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
590
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
591
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
592
|
-
for (const field of agentSessionsSchema.fields) {
|
|
593
|
-
const { type, name, default: defaultValue } = field;
|
|
594
|
-
if (!type || !name) {
|
|
595
|
-
continue;
|
|
596
|
-
}
|
|
597
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
598
|
-
}
|
|
599
|
-
});
|
|
600
|
-
}
|
|
601
|
-
if (!await knex.schema.hasTable("agent_messages")) {
|
|
602
|
-
await knex.schema.createTable("agent_messages", (table) => {
|
|
603
|
-
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
604
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
605
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
606
|
-
for (const field of agentMessagesSchema.fields) {
|
|
607
|
-
const { type, name, default: defaultValue } = field;
|
|
608
|
-
if (!type || !name) {
|
|
609
|
-
continue;
|
|
610
|
-
}
|
|
611
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
612
|
-
}
|
|
613
|
-
});
|
|
614
|
-
}
|
|
615
|
-
if (!await knex.schema.hasTable("roles")) {
|
|
616
|
-
await knex.schema.createTable("roles", (table) => {
|
|
617
|
-
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
618
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
619
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
620
|
-
for (const field of rolesSchema.fields) {
|
|
621
|
-
const { type, name, default: defaultValue } = field;
|
|
622
|
-
if (!type || !name) {
|
|
623
|
-
continue;
|
|
624
|
-
}
|
|
625
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
626
|
-
}
|
|
627
|
-
});
|
|
628
|
-
}
|
|
629
|
-
if (!await knex.schema.hasTable("eval_results")) {
|
|
630
|
-
await knex.schema.createTable("eval_results", (table) => {
|
|
631
|
-
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
632
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
633
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
634
|
-
for (const field of evalResultsSchema.fields) {
|
|
635
|
-
const { type, name, default: defaultValue } = field;
|
|
636
|
-
if (!type || !name) {
|
|
637
|
-
continue;
|
|
638
|
-
}
|
|
639
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
640
|
-
}
|
|
641
|
-
});
|
|
642
|
-
}
|
|
643
|
-
if (!await knex.schema.hasTable("statistics")) {
|
|
644
|
-
await knex.schema.createTable("statistics", (table) => {
|
|
645
|
-
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
646
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
647
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
648
|
-
for (const field of statisticsSchema.fields) {
|
|
649
|
-
const { type, name, default: defaultValue } = field;
|
|
650
|
-
if (!type || !name) {
|
|
651
|
-
continue;
|
|
652
|
-
}
|
|
653
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
654
|
-
}
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
if (!await knex.schema.hasTable("jobs")) {
|
|
658
|
-
await knex.schema.createTable("jobs", (table) => {
|
|
659
|
-
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
660
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
661
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
662
|
-
for (const field of jobsSchema.fields) {
|
|
663
|
-
const { type, name, default: defaultValue } = field;
|
|
664
|
-
if (!type || !name) {
|
|
665
|
-
continue;
|
|
666
|
-
}
|
|
667
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
668
|
-
}
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
if (!await knex.schema.hasTable("agents")) {
|
|
672
|
-
await knex.schema.createTable("agents", (table) => {
|
|
673
|
-
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
674
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
675
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
676
|
-
for (const field of agentsSchema.fields) {
|
|
677
|
-
const { type, name, default: defaultValue } = field;
|
|
678
|
-
if (!type || !name) {
|
|
679
|
-
continue;
|
|
680
|
-
}
|
|
681
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
682
|
-
}
|
|
683
|
-
});
|
|
684
|
-
}
|
|
685
|
-
if (!await knex.schema.hasTable("verification_token")) {
|
|
686
|
-
await knex.schema.createTable("verification_token", (table) => {
|
|
687
|
-
table.text("identifier").notNullable();
|
|
688
|
-
table.timestamp("expires", { useTz: true }).notNullable();
|
|
689
|
-
table.text("token").notNullable();
|
|
690
|
-
table.primary(["identifier", "token"]);
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
if (!await knex.schema.hasTable("users")) {
|
|
694
|
-
await knex.schema.createTable("users", (table) => {
|
|
695
|
-
table.increments("id").primary();
|
|
696
|
-
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
697
|
-
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
698
|
-
table.string("name", 255);
|
|
699
|
-
table.string("password", 255);
|
|
700
|
-
table.string("email", 255);
|
|
701
|
-
table.timestamp("emailVerified", { useTz: true });
|
|
702
|
-
table.text("image");
|
|
703
|
-
for (const field of usersSchema.fields) {
|
|
704
|
-
console.log("[EXULU] field", field);
|
|
705
|
-
const { type, name, default: defaultValue } = field;
|
|
706
|
-
if (name === "id" || name === "name" || name === "email" || name === "emailVerified" || name === "image") {
|
|
707
|
-
continue;
|
|
708
|
-
}
|
|
709
|
-
if (!type || !name) {
|
|
710
|
-
continue;
|
|
711
|
-
}
|
|
712
|
-
mapType(table, type, sanitizeName(name), defaultValue);
|
|
713
|
-
}
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
if (!await knex.schema.hasTable("accounts")) {
|
|
717
|
-
await knex.schema.createTable("accounts", (table) => {
|
|
718
|
-
table.increments("id").primary();
|
|
719
|
-
table.integer("userId").notNullable();
|
|
720
|
-
table.string("type", 255).notNullable();
|
|
721
|
-
table.string("provider", 255).notNullable();
|
|
722
|
-
table.string("providerAccountId", 255).notNullable();
|
|
723
|
-
table.text("refresh_token");
|
|
724
|
-
table.text("access_token");
|
|
725
|
-
table.bigInteger("expires_at");
|
|
726
|
-
table.text("id_token");
|
|
727
|
-
table.text("scope");
|
|
728
|
-
table.text("session_state");
|
|
729
|
-
table.text("token_type");
|
|
730
|
-
});
|
|
731
|
-
}
|
|
732
|
-
};
|
|
733
|
-
var execute = async () => {
|
|
734
|
-
console.log("[EXULU] Initializing Exulu IMP database.");
|
|
735
|
-
const { db: db2 } = await postgresClient();
|
|
736
|
-
await up(db2);
|
|
737
|
-
console.log("[EXULU] Inserting default user and admin role.");
|
|
738
|
-
const existingRole = await db2.from("roles").where({ name: "admin" }).first();
|
|
739
|
-
let roleId;
|
|
740
|
-
if (!existingRole) {
|
|
741
|
-
console.log("[EXULU] Creating default admin role.");
|
|
742
|
-
const role = await db2.from("roles").insert({
|
|
743
|
-
name: "admin",
|
|
744
|
-
is_admin: true,
|
|
745
|
-
agents: JSON.stringify([])
|
|
746
|
-
}).returning("id");
|
|
747
|
-
roleId = role[0].id;
|
|
748
|
-
} else {
|
|
749
|
-
roleId = existingRole.id;
|
|
750
|
-
}
|
|
751
|
-
const existingUser = await db2.from("users").where({ email: "admin@exulu.com" }).first();
|
|
752
|
-
if (!existingUser) {
|
|
753
|
-
const password = await encryptString("admin");
|
|
754
|
-
console.log("[EXULU] Creating default admin user.");
|
|
755
|
-
await db2.from("users").insert({
|
|
756
|
-
name: "exulu",
|
|
757
|
-
email: "admin@exulu.com",
|
|
758
|
-
super_admin: true,
|
|
759
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
760
|
-
emailVerified: /* @__PURE__ */ new Date(),
|
|
761
|
-
updatedAt: /* @__PURE__ */ new Date(),
|
|
762
|
-
password,
|
|
763
|
-
type: "user",
|
|
764
|
-
role: roleId
|
|
765
|
-
});
|
|
766
|
-
}
|
|
767
|
-
const { key } = await generateApiKey("exulu", "api@exulu.com");
|
|
768
|
-
console.log("[EXULU] Database initialized.");
|
|
769
|
-
console.log("[EXULU] Default api key: ", `${key}`);
|
|
770
|
-
console.log("[EXULU] Default password if using password auth: ", `admin`);
|
|
771
|
-
console.log("[EXULU] Default email if using password auth: ", `admin@exulu.com`);
|
|
772
|
-
return;
|
|
773
|
-
};
|
|
774
|
-
|
|
775
|
-
// src/registry/classes.ts
|
|
776
|
-
var import_zod = require("zod");
|
|
777
|
-
var import_bullmq2 = require("bullmq");
|
|
778
|
-
var import_zod2 = require("zod");
|
|
779
|
-
var fs = __toESM(require("fs"), 1);
|
|
780
|
-
var path = __toESM(require("path"), 1);
|
|
781
|
-
var import_ai = require("ai");
|
|
782
|
-
|
|
783
|
-
// types/enums/statistics.ts
|
|
784
|
-
var STATISTICS_TYPE_ENUM = {
|
|
785
|
-
CONTEXT_RETRIEVE: "context.retrieve",
|
|
786
|
-
SOURCE_UPDATE: "source.update",
|
|
787
|
-
EMBEDDER_UPSERT: "embedder.upsert",
|
|
788
|
-
EMBEDDER_GENERATE: "embedder.generate",
|
|
789
|
-
EMBEDDER_DELETE: "embedder.delete",
|
|
790
|
-
WORKFLOW_RUN: "workflow.run",
|
|
791
|
-
CONTEXT_UPSERT: "context.upsert",
|
|
792
|
-
TOOL_CALL: "tool.call",
|
|
793
|
-
AGENT_RUN: "agent.run"
|
|
794
|
-
};
|
|
795
|
-
|
|
796
|
-
// types/enums/eval-types.ts
|
|
797
|
-
var EVAL_TYPES_ENUM = {
|
|
798
|
-
llm_as_judge: "llm_as_judge"
|
|
799
|
-
};
|
|
800
|
-
|
|
801
|
-
// src/registry/classes.ts
|
|
802
|
-
var import_knex4 = __toESM(require("pgvector/knex"), 1);
|
|
803
309
|
|
|
804
|
-
// src/registry/
|
|
805
|
-
var
|
|
806
|
-
|
|
807
|
-
var bullmqDecorator = async ({
|
|
808
|
-
label,
|
|
809
|
-
type,
|
|
810
|
-
workflow,
|
|
811
|
-
embedder,
|
|
812
|
-
inputs,
|
|
813
|
-
queue,
|
|
814
|
-
user,
|
|
815
|
-
agent,
|
|
816
|
-
session,
|
|
817
|
-
configuration,
|
|
818
|
-
updater,
|
|
819
|
-
context,
|
|
820
|
-
steps,
|
|
821
|
-
source,
|
|
822
|
-
documents,
|
|
823
|
-
trigger,
|
|
824
|
-
item
|
|
825
|
-
}) => {
|
|
826
|
-
const redisId = (0, import_uuid.v4)();
|
|
827
|
-
const job = await queue.add(
|
|
828
|
-
`${embedder || workflow}`,
|
|
829
|
-
{
|
|
830
|
-
type: `${type}`,
|
|
831
|
-
...embedder && { embedder },
|
|
832
|
-
...workflow && { workflow },
|
|
833
|
-
...configuration && { configuration },
|
|
834
|
-
...updater && { updater },
|
|
835
|
-
...context && { context },
|
|
836
|
-
...source && { source },
|
|
837
|
-
...documents && { documents },
|
|
838
|
-
...steps && { steps },
|
|
839
|
-
...trigger && { trigger },
|
|
840
|
-
...item && { item },
|
|
841
|
-
agent,
|
|
842
|
-
user,
|
|
843
|
-
inputs,
|
|
844
|
-
label,
|
|
845
|
-
session
|
|
846
|
-
},
|
|
847
|
-
{
|
|
848
|
-
jobId: redisId
|
|
849
|
-
}
|
|
850
|
-
);
|
|
851
|
-
const { db: db2 } = await postgresClient();
|
|
852
|
-
const now = /* @__PURE__ */ new Date();
|
|
853
|
-
console.log("[EXULU] scheduling new job", inputs);
|
|
854
|
-
const insertData = {
|
|
855
|
-
name: `${label}`,
|
|
856
|
-
redis: job.id,
|
|
857
|
-
status: "waiting",
|
|
858
|
-
type,
|
|
859
|
-
inputs,
|
|
860
|
-
agent,
|
|
861
|
-
item,
|
|
862
|
-
createdAt: now,
|
|
863
|
-
updatedAt: now,
|
|
864
|
-
user,
|
|
865
|
-
session,
|
|
866
|
-
...embedder && { embedder },
|
|
867
|
-
...workflow && { workflow },
|
|
868
|
-
...configuration && { configuration },
|
|
869
|
-
...steps && { steps },
|
|
870
|
-
...updater && { updater },
|
|
871
|
-
...context && { context },
|
|
872
|
-
...source && { source },
|
|
873
|
-
...documents && { documents: documents.map((doc2) => doc2.id) },
|
|
874
|
-
...trigger && { trigger }
|
|
875
|
-
};
|
|
876
|
-
await db2("jobs").insert(insertData).onConflict("redis").merge({
|
|
877
|
-
...insertData,
|
|
878
|
-
updatedAt: now
|
|
879
|
-
// Only updatedAt changes on updates
|
|
880
|
-
});
|
|
881
|
-
const doc = await db2.from("jobs").where({ redis: job.id }).first();
|
|
882
|
-
if (!doc?.id) {
|
|
883
|
-
throw new Error("Failed to get job ID after insert/update");
|
|
884
|
-
}
|
|
885
|
-
console.log("[EXULU] created job", doc?.id);
|
|
886
|
-
return {
|
|
887
|
-
...job,
|
|
888
|
-
id: doc?.id,
|
|
889
|
-
redis: job.id
|
|
890
|
-
};
|
|
310
|
+
// src/registry/utils/sanitize-name.ts
|
|
311
|
+
var sanitizeName = (name) => {
|
|
312
|
+
return name.toLowerCase().replace(/ /g, "_");
|
|
891
313
|
};
|
|
892
314
|
|
|
893
315
|
// types/enums/jobs.ts
|
|
@@ -2068,7 +1490,7 @@ var getToken = async (authHeader) => {
|
|
|
2068
1490
|
};
|
|
2069
1491
|
|
|
2070
1492
|
// src/auth/auth.ts
|
|
2071
|
-
var
|
|
1493
|
+
var import_bcryptjs = __toESM(require("bcryptjs"), 1);
|
|
2072
1494
|
var authentication = async ({
|
|
2073
1495
|
apikey,
|
|
2074
1496
|
authtoken,
|
|
@@ -2163,7 +1585,7 @@ var authentication = async ({
|
|
|
2163
1585
|
for (const user of filtered) {
|
|
2164
1586
|
const user_key_last_slash_index = user.apikey.lastIndexOf("/");
|
|
2165
1587
|
const user_key_compare_value = user.apikey.substring(0, user_key_last_slash_index);
|
|
2166
|
-
const isMatch = await
|
|
1588
|
+
const isMatch = await import_bcryptjs.default.compare(request_key_compare_value, user_key_compare_value);
|
|
2167
1589
|
if (isMatch) {
|
|
2168
1590
|
await db2.from("users").where({ id: user.id }).update({
|
|
2169
1591
|
last_used: /* @__PURE__ */ new Date()
|
|
@@ -2220,595 +1642,929 @@ var requestValidators = {
|
|
|
2220
1642
|
message: "Missing body."
|
|
2221
1643
|
};
|
|
2222
1644
|
}
|
|
2223
|
-
if (!req.body.agent) {
|
|
2224
|
-
return {
|
|
2225
|
-
error: true,
|
|
2226
|
-
code: 400,
|
|
2227
|
-
message: "Missing agent in body."
|
|
2228
|
-
};
|
|
1645
|
+
if (!req.body.agent) {
|
|
1646
|
+
return {
|
|
1647
|
+
error: true,
|
|
1648
|
+
code: 400,
|
|
1649
|
+
message: "Missing agent in body."
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1652
|
+
if (!req.body.session) {
|
|
1653
|
+
return {
|
|
1654
|
+
error: true,
|
|
1655
|
+
code: 400,
|
|
1656
|
+
message: "Missing session in body."
|
|
1657
|
+
};
|
|
1658
|
+
}
|
|
1659
|
+
if (!req.body.inputs) {
|
|
1660
|
+
return {
|
|
1661
|
+
error: true,
|
|
1662
|
+
code: 400,
|
|
1663
|
+
message: "Missing inputs in body."
|
|
1664
|
+
};
|
|
1665
|
+
}
|
|
1666
|
+
if (!req.body.label) {
|
|
1667
|
+
return {
|
|
1668
|
+
error: true,
|
|
1669
|
+
code: 400,
|
|
1670
|
+
message: "Missing label for job in body."
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1673
|
+
return {
|
|
1674
|
+
error: false
|
|
1675
|
+
};
|
|
1676
|
+
},
|
|
1677
|
+
embedders: (req, configuration) => {
|
|
1678
|
+
const contentType = req.headers["content-type"] || "";
|
|
1679
|
+
if (!contentType.includes("application/json")) {
|
|
1680
|
+
return {
|
|
1681
|
+
error: true,
|
|
1682
|
+
code: 400,
|
|
1683
|
+
message: "Unsupported content type."
|
|
1684
|
+
};
|
|
1685
|
+
}
|
|
1686
|
+
if (!req.body) {
|
|
1687
|
+
return {
|
|
1688
|
+
error: true,
|
|
1689
|
+
code: 400,
|
|
1690
|
+
message: "Missing body."
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
if (!req.body.inputs) {
|
|
1694
|
+
return {
|
|
1695
|
+
error: true,
|
|
1696
|
+
code: 400,
|
|
1697
|
+
message: "Missing inputs."
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
if (!req.body.label) {
|
|
1701
|
+
return {
|
|
1702
|
+
error: true,
|
|
1703
|
+
code: 400,
|
|
1704
|
+
message: "Missing label for job in body."
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
if (configuration) {
|
|
1708
|
+
for (const key in configuration) {
|
|
1709
|
+
if (!req.body.configuration[key]) {
|
|
1710
|
+
return {
|
|
1711
|
+
error: true,
|
|
1712
|
+
code: 400,
|
|
1713
|
+
message: `Missing ${key} in body.configuration.`
|
|
1714
|
+
};
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
return {
|
|
1719
|
+
error: false
|
|
1720
|
+
};
|
|
1721
|
+
},
|
|
1722
|
+
agents: (req) => {
|
|
1723
|
+
const contentType = req.headers["content-type"] || "";
|
|
1724
|
+
if (!contentType.includes("application/json")) {
|
|
1725
|
+
return {
|
|
1726
|
+
error: true,
|
|
1727
|
+
code: 400,
|
|
1728
|
+
message: "Unsupported content type."
|
|
1729
|
+
};
|
|
1730
|
+
}
|
|
1731
|
+
if (!req.body) {
|
|
1732
|
+
return {
|
|
1733
|
+
error: true,
|
|
1734
|
+
code: 400,
|
|
1735
|
+
message: "Missing body."
|
|
1736
|
+
};
|
|
1737
|
+
}
|
|
1738
|
+
if (!req.body.threadId) {
|
|
1739
|
+
return {
|
|
1740
|
+
error: true,
|
|
1741
|
+
code: 400,
|
|
1742
|
+
message: "Missing threadId in body."
|
|
1743
|
+
};
|
|
1744
|
+
}
|
|
1745
|
+
if (!req.body.resourceId) {
|
|
1746
|
+
return {
|
|
1747
|
+
error: true,
|
|
1748
|
+
code: 400,
|
|
1749
|
+
message: "Missing resourceId in body."
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
if (!req.body.messages) {
|
|
1753
|
+
return {
|
|
1754
|
+
error: true,
|
|
1755
|
+
code: 400,
|
|
1756
|
+
message: 'Missing "messages" property in body.'
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1759
|
+
return {
|
|
1760
|
+
error: false
|
|
1761
|
+
};
|
|
1762
|
+
}
|
|
1763
|
+
};
|
|
1764
|
+
|
|
1765
|
+
// src/registry/routes.ts
|
|
1766
|
+
var import_zodex = require("zodex");
|
|
1767
|
+
|
|
1768
|
+
// src/bullmq/queues.ts
|
|
1769
|
+
var import_bullmq4 = require("bullmq");
|
|
1770
|
+
var ExuluQueues = class {
|
|
1771
|
+
queues;
|
|
1772
|
+
constructor() {
|
|
1773
|
+
this.queues = [];
|
|
1774
|
+
}
|
|
1775
|
+
queue(name) {
|
|
1776
|
+
return this.queues.find((x) => x.name === name);
|
|
1777
|
+
}
|
|
1778
|
+
use(name) {
|
|
1779
|
+
const existing = this.queues.find((x) => x.name === name);
|
|
1780
|
+
if (existing) {
|
|
1781
|
+
return existing;
|
|
1782
|
+
}
|
|
1783
|
+
if (!redisServer.host?.length || !redisServer.port?.length) {
|
|
1784
|
+
console.error(`[EXULU] no redis server configured, but you are trying to use a queue ( ${name}), likely in an agent or workflow (look for ExuluQueues.use() ).`);
|
|
1785
|
+
throw new Error(`[EXULU] no redis server configured.`);
|
|
1786
|
+
}
|
|
1787
|
+
const newQueue = new import_bullmq4.Queue(`${name}`, { connection: redisServer });
|
|
1788
|
+
this.queues.push(newQueue);
|
|
1789
|
+
return newQueue;
|
|
1790
|
+
}
|
|
1791
|
+
};
|
|
1792
|
+
var queues = new ExuluQueues();
|
|
1793
|
+
|
|
1794
|
+
// types/models/vector-methods.ts
|
|
1795
|
+
var VectorMethodEnum = {
|
|
1796
|
+
"cosineDistance": "cosineDistance",
|
|
1797
|
+
"l1Distance": "l1Distance",
|
|
1798
|
+
"l2Distance": "l2Distance",
|
|
1799
|
+
"hammingDistance": "hammingDistance",
|
|
1800
|
+
"jaccardDistance": "jaccardDistance",
|
|
1801
|
+
"maxInnerProduct": "maxInnerProduct"
|
|
1802
|
+
};
|
|
1803
|
+
|
|
1804
|
+
// src/registry/routes.ts
|
|
1805
|
+
var import_express3 = __toESM(require("express"), 1);
|
|
1806
|
+
var import_server3 = require("@apollo/server");
|
|
1807
|
+
var Papa = __toESM(require("papaparse"), 1);
|
|
1808
|
+
var import_cors = __toESM(require("cors"), 1);
|
|
1809
|
+
var import_reflect_metadata = require("reflect-metadata");
|
|
1810
|
+
|
|
1811
|
+
// src/registry/utils/graphql.ts
|
|
1812
|
+
var import_schema = require("@graphql-tools/schema");
|
|
1813
|
+
var import_graphql_type_json = __toESM(require("graphql-type-json"), 1);
|
|
1814
|
+
var import_graphql = require("graphql");
|
|
1815
|
+
var import_crypto_js = __toESM(require("crypto-js"), 1);
|
|
1816
|
+
var GraphQLDate = new import_graphql.GraphQLScalarType({
|
|
1817
|
+
name: "Date",
|
|
1818
|
+
description: "Date custom scalar type",
|
|
1819
|
+
serialize(value) {
|
|
1820
|
+
if (value instanceof Date) {
|
|
1821
|
+
return value.toISOString();
|
|
1822
|
+
}
|
|
1823
|
+
if (typeof value === "number") {
|
|
1824
|
+
return new Date(value).toISOString();
|
|
2229
1825
|
}
|
|
2230
|
-
if (
|
|
2231
|
-
return
|
|
2232
|
-
error: true,
|
|
2233
|
-
code: 400,
|
|
2234
|
-
message: "Missing session in body."
|
|
2235
|
-
};
|
|
1826
|
+
if (typeof value === "string") {
|
|
1827
|
+
return new Date(value).toISOString();
|
|
2236
1828
|
}
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
};
|
|
1829
|
+
return value;
|
|
1830
|
+
},
|
|
1831
|
+
parseValue(value) {
|
|
1832
|
+
if (typeof value === "string") {
|
|
1833
|
+
return new Date(value);
|
|
2243
1834
|
}
|
|
2244
|
-
if (
|
|
2245
|
-
return
|
|
2246
|
-
error: true,
|
|
2247
|
-
code: 400,
|
|
2248
|
-
message: "Missing label for job in body."
|
|
2249
|
-
};
|
|
1835
|
+
if (typeof value === "number") {
|
|
1836
|
+
return new Date(value);
|
|
2250
1837
|
}
|
|
2251
|
-
return
|
|
2252
|
-
error: false
|
|
2253
|
-
};
|
|
1838
|
+
return value;
|
|
2254
1839
|
},
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
return {
|
|
2259
|
-
error: true,
|
|
2260
|
-
code: 400,
|
|
2261
|
-
message: "Unsupported content type."
|
|
2262
|
-
};
|
|
1840
|
+
parseLiteral(ast) {
|
|
1841
|
+
if (ast.kind === import_graphql.Kind.STRING) {
|
|
1842
|
+
return new Date(ast.value);
|
|
2263
1843
|
}
|
|
2264
|
-
if (
|
|
2265
|
-
return
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
1844
|
+
if (ast.kind === import_graphql.Kind.INT) {
|
|
1845
|
+
return new Date(parseInt(ast.value, 10));
|
|
1846
|
+
}
|
|
1847
|
+
return null;
|
|
1848
|
+
}
|
|
1849
|
+
});
|
|
1850
|
+
var map = (field) => {
|
|
1851
|
+
let type;
|
|
1852
|
+
switch (field.type) {
|
|
1853
|
+
case "text":
|
|
1854
|
+
case "shortText":
|
|
1855
|
+
case "longText":
|
|
1856
|
+
case "code":
|
|
1857
|
+
type = "String";
|
|
1858
|
+
break;
|
|
1859
|
+
case "number":
|
|
1860
|
+
type = "Float";
|
|
1861
|
+
break;
|
|
1862
|
+
case "boolean":
|
|
1863
|
+
type = "Boolean";
|
|
1864
|
+
break;
|
|
1865
|
+
case "json":
|
|
1866
|
+
type = "JSON";
|
|
1867
|
+
break;
|
|
1868
|
+
case "date":
|
|
1869
|
+
type = "Date";
|
|
1870
|
+
break;
|
|
1871
|
+
default:
|
|
1872
|
+
type = "String";
|
|
1873
|
+
}
|
|
1874
|
+
return type;
|
|
1875
|
+
};
|
|
1876
|
+
function createTypeDefs(table) {
|
|
1877
|
+
const fields = table.fields.map((field) => {
|
|
1878
|
+
let type;
|
|
1879
|
+
type = map(field);
|
|
1880
|
+
const required = field.required ? "!" : "";
|
|
1881
|
+
return ` ${field.name}: ${type}${required}`;
|
|
1882
|
+
});
|
|
1883
|
+
const typeDef = `
|
|
1884
|
+
type ${table.name.singular} {
|
|
1885
|
+
${fields.join("\n")}
|
|
1886
|
+
id: ID!
|
|
1887
|
+
createdAt: Date!
|
|
1888
|
+
updatedAt: Date!
|
|
1889
|
+
}
|
|
1890
|
+
`;
|
|
1891
|
+
const inputDef = `
|
|
1892
|
+
input ${table.name.singular}Input {
|
|
1893
|
+
${table.fields.map((f) => ` ${f.name}: ${map(f)}`).join("\n")}
|
|
1894
|
+
}
|
|
1895
|
+
`;
|
|
1896
|
+
return typeDef + inputDef;
|
|
1897
|
+
}
|
|
1898
|
+
function createFilterTypeDefs(table) {
|
|
1899
|
+
const fieldFilters = table.fields.map((field) => {
|
|
1900
|
+
let type;
|
|
1901
|
+
type = map(field);
|
|
1902
|
+
return `
|
|
1903
|
+
${field.name}: FilterOperator${type}`;
|
|
1904
|
+
});
|
|
1905
|
+
const tableNameSingularUpperCaseFirst = table.name.singular.charAt(0).toUpperCase() + table.name.singular.slice(1);
|
|
1906
|
+
const operatorTypes = `
|
|
1907
|
+
input FilterOperatorString {
|
|
1908
|
+
eq: String
|
|
1909
|
+
ne: String
|
|
1910
|
+
in: [String]
|
|
1911
|
+
contains: String
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
input FilterOperatorDate {
|
|
1915
|
+
lte: Date
|
|
1916
|
+
gte: Date
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
input FilterOperatorFloat {
|
|
1920
|
+
eq: Float
|
|
1921
|
+
ne: Float
|
|
1922
|
+
in: [Float]
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
input FilterOperatorBoolean {
|
|
1926
|
+
eq: Boolean
|
|
1927
|
+
ne: Boolean
|
|
1928
|
+
in: [Boolean]
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
input FilterOperatorJSON {
|
|
1932
|
+
eq: JSON
|
|
1933
|
+
ne: JSON
|
|
1934
|
+
in: [JSON]
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
input SortBy {
|
|
1938
|
+
field: String!
|
|
1939
|
+
direction: SortDirection!
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
enum SortDirection {
|
|
1943
|
+
ASC
|
|
1944
|
+
DESC
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
input Filter${tableNameSingularUpperCaseFirst} {
|
|
1948
|
+
${fieldFilters.join("\n")}
|
|
1949
|
+
}`;
|
|
1950
|
+
return operatorTypes;
|
|
1951
|
+
}
|
|
1952
|
+
var getRequestedFields = (info) => {
|
|
1953
|
+
const selections = info.operation.selectionSet.selections[0].selectionSet.selections;
|
|
1954
|
+
const itemsSelection = selections.find((s) => s.name.value === "items");
|
|
1955
|
+
const fields = itemsSelection ? Object.keys(itemsSelection.selectionSet.selections.reduce((acc, field) => {
|
|
1956
|
+
acc[field.name.value] = true;
|
|
1957
|
+
return acc;
|
|
1958
|
+
}, {})) : Object.keys(selections.reduce((acc, field) => {
|
|
1959
|
+
acc[field.name.value] = true;
|
|
1960
|
+
return acc;
|
|
1961
|
+
}, {}));
|
|
1962
|
+
return fields.filter((field) => field !== "pageInfo" && field !== "items");
|
|
1963
|
+
};
|
|
1964
|
+
function createMutations(table) {
|
|
1965
|
+
const tableNamePlural = table.name.plural.toLowerCase();
|
|
1966
|
+
const tableNameSingular = table.name.singular.toLowerCase();
|
|
1967
|
+
return {
|
|
1968
|
+
[`${tableNamePlural}CreateOne`]: async (_, args, context, info) => {
|
|
1969
|
+
const { db: db2 } = context;
|
|
1970
|
+
const requestedFields = getRequestedFields(info);
|
|
1971
|
+
let { input } = args;
|
|
1972
|
+
input = encryptSensitiveFields(input);
|
|
1973
|
+
const results = await db2(tableNamePlural).insert({
|
|
1974
|
+
...input,
|
|
1975
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1976
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1977
|
+
}).returning(requestedFields);
|
|
1978
|
+
return results[0];
|
|
1979
|
+
},
|
|
1980
|
+
[`${tableNamePlural}UpdateOne`]: async (_, args, context, info) => {
|
|
1981
|
+
const { db: db2 } = context;
|
|
1982
|
+
let { where, input } = args;
|
|
1983
|
+
input = encryptSensitiveFields(input);
|
|
1984
|
+
await db2(tableNamePlural).where(where).update({
|
|
1985
|
+
...input,
|
|
1986
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1987
|
+
});
|
|
1988
|
+
const requestedFields = getRequestedFields(info);
|
|
1989
|
+
const result = await db2.from(tableNamePlural).select(requestedFields).where(where).first();
|
|
1990
|
+
return result;
|
|
1991
|
+
},
|
|
1992
|
+
[`${tableNamePlural}UpdateOneById`]: async (_, args, context, info) => {
|
|
1993
|
+
let { id, input } = args;
|
|
1994
|
+
input = encryptSensitiveFields(input);
|
|
1995
|
+
const { db: db2 } = context;
|
|
1996
|
+
await db2(tableNamePlural).where({ id }).update({
|
|
1997
|
+
...input,
|
|
1998
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1999
|
+
});
|
|
2000
|
+
const requestedFields = getRequestedFields(info);
|
|
2001
|
+
const result = await db2.from(tableNamePlural).select(requestedFields).where({ id }).first();
|
|
2002
|
+
return result;
|
|
2003
|
+
},
|
|
2004
|
+
[`${tableNamePlural}RemoveOne`]: async (_, args, context, info) => {
|
|
2005
|
+
const { db: db2 } = context;
|
|
2006
|
+
const { where } = args;
|
|
2007
|
+
const requestedFields = getRequestedFields(info);
|
|
2008
|
+
const result = await db2.from(tableNamePlural).select(requestedFields).where(where).first();
|
|
2009
|
+
await db2(tableNamePlural).where(where).del();
|
|
2010
|
+
return result;
|
|
2011
|
+
},
|
|
2012
|
+
[`${tableNamePlural}RemoveOneById`]: async (_, args, context, info) => {
|
|
2013
|
+
const { id } = args;
|
|
2014
|
+
const { db: db2 } = context;
|
|
2015
|
+
const requestedFields = getRequestedFields(info);
|
|
2016
|
+
const result = await db2.from(tableNamePlural).select(requestedFields).where({ id }).first();
|
|
2017
|
+
await db2(tableNamePlural).where({ id }).del();
|
|
2018
|
+
return result;
|
|
2270
2019
|
}
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2020
|
+
};
|
|
2021
|
+
}
|
|
2022
|
+
function createQueries(table) {
|
|
2023
|
+
const tableNamePlural = table.name.plural.toLowerCase();
|
|
2024
|
+
const tableNameSingular = table.name.singular.toLowerCase();
|
|
2025
|
+
const applyFilters = (query, filters) => {
|
|
2026
|
+
filters.forEach((filter) => {
|
|
2027
|
+
Object.entries(filter).forEach(([fieldName, operators]) => {
|
|
2028
|
+
if (operators) {
|
|
2029
|
+
if (operators.eq !== void 0) {
|
|
2030
|
+
query = query.where(fieldName, operators.eq);
|
|
2031
|
+
}
|
|
2032
|
+
if (operators.ne !== void 0) {
|
|
2033
|
+
query = query.whereRaw(`?? IS DISTINCT FROM ?`, [fieldName, operators.ne]);
|
|
2034
|
+
}
|
|
2035
|
+
if (operators.in !== void 0) {
|
|
2036
|
+
query = query.whereIn(fieldName, operators.in);
|
|
2037
|
+
}
|
|
2038
|
+
if (operators.contains !== void 0) {
|
|
2039
|
+
query = query.where(fieldName, "like", `%${operators.contains}%`);
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
});
|
|
2043
|
+
});
|
|
2044
|
+
return query;
|
|
2045
|
+
};
|
|
2046
|
+
const applySorting = (query, sort) => {
|
|
2047
|
+
if (sort) {
|
|
2048
|
+
query = query.orderBy(sort.field, sort.direction.toLowerCase());
|
|
2277
2049
|
}
|
|
2278
|
-
|
|
2050
|
+
return query;
|
|
2051
|
+
};
|
|
2052
|
+
return {
|
|
2053
|
+
[`${tableNameSingular}ById`]: async (_, args, context, info) => {
|
|
2054
|
+
const { db: db2 } = context;
|
|
2055
|
+
const requestedFields = getRequestedFields(info);
|
|
2056
|
+
const result = await db2.from(tableNamePlural).select(requestedFields).where({ id: args.id }).first();
|
|
2057
|
+
return result;
|
|
2058
|
+
},
|
|
2059
|
+
[`${tableNameSingular}One`]: async (_, args, context, info) => {
|
|
2060
|
+
const { filters = [], sort } = args;
|
|
2061
|
+
const { db: db2 } = context;
|
|
2062
|
+
const requestedFields = getRequestedFields(info);
|
|
2063
|
+
let query = db2.from(tableNamePlural).select(requestedFields);
|
|
2064
|
+
query = applyFilters(query, filters);
|
|
2065
|
+
query = applySorting(query, sort);
|
|
2066
|
+
const result = await query.first();
|
|
2067
|
+
return result;
|
|
2068
|
+
},
|
|
2069
|
+
[`${tableNamePlural}Pagination`]: async (_, args, context, info) => {
|
|
2070
|
+
const { limit = 10, page = 0, filters = [], sort } = args;
|
|
2071
|
+
const { db: db2 } = context;
|
|
2072
|
+
let baseQuery = db2(tableNamePlural);
|
|
2073
|
+
baseQuery = applyFilters(baseQuery, filters);
|
|
2074
|
+
const [{ count }] = await baseQuery.clone().count("* as count");
|
|
2075
|
+
const itemCount = Number(count);
|
|
2076
|
+
const pageCount = Math.ceil(itemCount / limit);
|
|
2077
|
+
const currentPage = page;
|
|
2078
|
+
const hasPreviousPage = currentPage > 1;
|
|
2079
|
+
const hasNextPage = currentPage < pageCount - 1;
|
|
2080
|
+
let dataQuery = baseQuery.clone();
|
|
2081
|
+
const requestedFields = getRequestedFields(info);
|
|
2082
|
+
dataQuery = applySorting(dataQuery, sort);
|
|
2083
|
+
if (page > 1) {
|
|
2084
|
+
dataQuery = dataQuery.offset((page - 1) * limit);
|
|
2085
|
+
}
|
|
2086
|
+
const items = await dataQuery.select(requestedFields).limit(limit);
|
|
2279
2087
|
return {
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2088
|
+
pageInfo: {
|
|
2089
|
+
pageCount,
|
|
2090
|
+
itemCount,
|
|
2091
|
+
currentPage,
|
|
2092
|
+
hasPreviousPage,
|
|
2093
|
+
hasNextPage
|
|
2094
|
+
},
|
|
2095
|
+
items
|
|
2283
2096
|
};
|
|
2284
|
-
}
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2097
|
+
},
|
|
2098
|
+
// Add jobStatistics query for jobs table
|
|
2099
|
+
...tableNamePlural === "jobs" ? {
|
|
2100
|
+
jobStatistics: async (_, args, context, info) => {
|
|
2101
|
+
const { user, agent, from, to } = args;
|
|
2102
|
+
const { db: db2 } = context;
|
|
2103
|
+
let query = db2("jobs");
|
|
2104
|
+
if (user) {
|
|
2105
|
+
query = query.where("user", user);
|
|
2106
|
+
}
|
|
2107
|
+
if (agent) {
|
|
2108
|
+
query = query.where("agent", agent);
|
|
2109
|
+
}
|
|
2110
|
+
if (from) {
|
|
2111
|
+
query = query.where("createdAt", ">=", from);
|
|
2112
|
+
}
|
|
2113
|
+
if (to) {
|
|
2114
|
+
query = query.where("createdAt", "<=", to);
|
|
2293
2115
|
}
|
|
2116
|
+
const completedQuery = query.clone().where("status", "completed");
|
|
2117
|
+
const [{ completedCount }] = await completedQuery.count("* as completedCount");
|
|
2118
|
+
const failedQuery = query.clone().where("status", "failed");
|
|
2119
|
+
const [{ failedCount }] = await failedQuery.count("* as failedCount");
|
|
2120
|
+
const durationQuery = query.clone().where("status", "completed").whereNotNull("duration").select(db2.raw('AVG("duration") as averageDuration'));
|
|
2121
|
+
const [{ averageDuration }] = await durationQuery;
|
|
2122
|
+
return {
|
|
2123
|
+
completedCount: Number(completedCount),
|
|
2124
|
+
failedCount: Number(failedCount),
|
|
2125
|
+
averageDuration: averageDuration ? Number(averageDuration) : 0
|
|
2126
|
+
};
|
|
2294
2127
|
}
|
|
2128
|
+
} : {}
|
|
2129
|
+
};
|
|
2130
|
+
}
|
|
2131
|
+
function createSDL(tables) {
|
|
2132
|
+
let typeDefs = `
|
|
2133
|
+
scalar JSON
|
|
2134
|
+
scalar Date
|
|
2135
|
+
|
|
2136
|
+
type Query {
|
|
2137
|
+
`;
|
|
2138
|
+
let mutationDefs = `
|
|
2139
|
+
type Mutation {
|
|
2140
|
+
`;
|
|
2141
|
+
let modelDefs = "";
|
|
2142
|
+
const resolvers = { JSON: import_graphql_type_json.default, Date: GraphQLDate, Query: {}, Mutation: {} };
|
|
2143
|
+
for (const table of tables) {
|
|
2144
|
+
const tableNamePlural = table.name.plural.toLowerCase();
|
|
2145
|
+
const tableNameSingular = table.name.singular.toLowerCase();
|
|
2146
|
+
const tableNameSingularUpperCaseFirst = table.name.singular.charAt(0).toUpperCase() + table.name.singular.slice(1);
|
|
2147
|
+
typeDefs += `
|
|
2148
|
+
${tableNameSingular}ById(id: ID!): ${tableNameSingular}
|
|
2149
|
+
${tableNamePlural}Pagination(limit: Int, page: Int, filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingularUpperCaseFirst}PaginationResult
|
|
2150
|
+
${tableNameSingular}One(filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingular}
|
|
2151
|
+
${tableNamePlural === "jobs" ? `jobStatistics(user: ID, agent: String, from: String, to: String): JobStatistics` : ""}
|
|
2152
|
+
`;
|
|
2153
|
+
mutationDefs += `
|
|
2154
|
+
${tableNamePlural}CreateOne(input: ${tableNameSingular}Input!): ${tableNameSingular}
|
|
2155
|
+
${tableNamePlural}UpdateOne(where: JSON!, input: ${tableNameSingular}Input!): ${tableNameSingular}
|
|
2156
|
+
${tableNamePlural}UpdateOneById(id: ID!, input: ${tableNameSingular}Input!): ${tableNameSingular}
|
|
2157
|
+
${tableNamePlural}RemoveOne(where: JSON!): ${tableNameSingular}
|
|
2158
|
+
${tableNamePlural}RemoveOneById(id: ID!): ${tableNameSingular}
|
|
2159
|
+
`;
|
|
2160
|
+
modelDefs += createTypeDefs(table);
|
|
2161
|
+
modelDefs += createFilterTypeDefs(table);
|
|
2162
|
+
modelDefs += `
|
|
2163
|
+
type ${tableNameSingularUpperCaseFirst}PaginationResult {
|
|
2164
|
+
pageInfo: PageInfo!
|
|
2165
|
+
items: [${tableNameSingular}]!
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
type PageInfo {
|
|
2169
|
+
pageCount: Int!
|
|
2170
|
+
itemCount: Int!
|
|
2171
|
+
currentPage: Int!
|
|
2172
|
+
hasPreviousPage: Boolean!
|
|
2173
|
+
hasNextPage: Boolean!
|
|
2174
|
+
}
|
|
2175
|
+
`;
|
|
2176
|
+
if (tableNamePlural === "jobs") {
|
|
2177
|
+
modelDefs += `
|
|
2178
|
+
type JobStatistics {
|
|
2179
|
+
completedCount: Int!
|
|
2180
|
+
failedCount: Int!
|
|
2181
|
+
averageDuration: Float!
|
|
2182
|
+
}
|
|
2183
|
+
`;
|
|
2295
2184
|
}
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
}
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2185
|
+
Object.assign(resolvers.Query, createQueries(table));
|
|
2186
|
+
Object.assign(resolvers.Mutation, createMutations(table));
|
|
2187
|
+
}
|
|
2188
|
+
typeDefs += "}\n";
|
|
2189
|
+
mutationDefs += "}\n";
|
|
2190
|
+
const fullSDL = typeDefs + mutationDefs + modelDefs;
|
|
2191
|
+
const schema = (0, import_schema.makeExecutableSchema)({
|
|
2192
|
+
typeDefs: fullSDL,
|
|
2193
|
+
resolvers
|
|
2194
|
+
});
|
|
2195
|
+
console.log("\n\u{1F4CA} GraphQL Schema Overview\n");
|
|
2196
|
+
const queriesTable = Object.keys(resolvers.Query).map((query) => ({
|
|
2197
|
+
"Operation Type": "Query",
|
|
2198
|
+
"Name": query,
|
|
2199
|
+
"Description": "Retrieves data"
|
|
2200
|
+
}));
|
|
2201
|
+
const mutationsTable = Object.keys(resolvers.Mutation).map((mutation) => ({
|
|
2202
|
+
"Operation Type": "Mutation",
|
|
2203
|
+
"Name": mutation,
|
|
2204
|
+
"Description": "Modifies data"
|
|
2205
|
+
}));
|
|
2206
|
+
const typesTable = tables.flatMap(
|
|
2207
|
+
(table) => table.fields.map((field) => ({
|
|
2208
|
+
"Type": table.name.singular,
|
|
2209
|
+
"Field": field.name,
|
|
2210
|
+
"Field Type": field.type,
|
|
2211
|
+
"Required": field.required ? "Yes" : "No"
|
|
2212
|
+
}))
|
|
2213
|
+
);
|
|
2214
|
+
console.log("\u{1F50D} Operations:");
|
|
2215
|
+
console.table([...queriesTable, ...mutationsTable]);
|
|
2216
|
+
console.log("\n\u{1F4DD} Types and Fields:");
|
|
2217
|
+
console.table(typesTable);
|
|
2218
|
+
console.log("\n");
|
|
2219
|
+
return schema;
|
|
2220
|
+
}
|
|
2221
|
+
var sensitiveFields = ["anthropic_token"];
|
|
2222
|
+
var encryptSensitiveFields = (input) => {
|
|
2223
|
+
sensitiveFields.forEach((field) => {
|
|
2224
|
+
if (input[field]) {
|
|
2225
|
+
input[field] = import_crypto_js.default.AES.encrypt(input[field], process.env.NEXTAUTH_SECRET).toString();
|
|
2336
2226
|
}
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
};
|
|
2340
|
-
}
|
|
2227
|
+
});
|
|
2228
|
+
return input;
|
|
2341
2229
|
};
|
|
2342
2230
|
|
|
2343
2231
|
// src/registry/routes.ts
|
|
2344
|
-
var
|
|
2232
|
+
var import_express5 = require("@as-integrations/express5");
|
|
2345
2233
|
|
|
2346
|
-
// src/
|
|
2347
|
-
var
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
}
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2234
|
+
// src/postgres/core-schema.ts
|
|
2235
|
+
var agentMessagesSchema = {
|
|
2236
|
+
name: {
|
|
2237
|
+
plural: "agent_messages",
|
|
2238
|
+
singular: "agent_message"
|
|
2239
|
+
},
|
|
2240
|
+
fields: [
|
|
2241
|
+
{
|
|
2242
|
+
name: "content",
|
|
2243
|
+
type: "text"
|
|
2244
|
+
},
|
|
2245
|
+
{
|
|
2246
|
+
name: "title",
|
|
2247
|
+
type: "text"
|
|
2248
|
+
},
|
|
2249
|
+
{
|
|
2250
|
+
name: "session",
|
|
2251
|
+
type: "text"
|
|
2364
2252
|
}
|
|
2365
|
-
|
|
2366
|
-
this.queues.push(newQueue);
|
|
2367
|
-
return newQueue;
|
|
2368
|
-
}
|
|
2253
|
+
]
|
|
2369
2254
|
};
|
|
2370
|
-
var
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2255
|
+
var agentSessionsSchema = {
|
|
2256
|
+
name: {
|
|
2257
|
+
plural: "agent_sessions",
|
|
2258
|
+
singular: "agent_session"
|
|
2259
|
+
},
|
|
2260
|
+
fields: [
|
|
2261
|
+
{
|
|
2262
|
+
name: "agent",
|
|
2263
|
+
type: "uuid"
|
|
2264
|
+
},
|
|
2265
|
+
{
|
|
2266
|
+
name: "user",
|
|
2267
|
+
// next auth stores users with id type SERIAL, so we need to use number
|
|
2268
|
+
type: "number"
|
|
2269
|
+
},
|
|
2270
|
+
{
|
|
2271
|
+
name: "title",
|
|
2272
|
+
type: "text"
|
|
2273
|
+
}
|
|
2274
|
+
]
|
|
2380
2275
|
};
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2276
|
+
var usersSchema = {
|
|
2277
|
+
name: {
|
|
2278
|
+
plural: "users",
|
|
2279
|
+
singular: "user"
|
|
2280
|
+
},
|
|
2281
|
+
fields: [
|
|
2282
|
+
{
|
|
2283
|
+
name: "firstname",
|
|
2284
|
+
type: "text"
|
|
2285
|
+
},
|
|
2286
|
+
{
|
|
2287
|
+
name: "name",
|
|
2288
|
+
type: "text"
|
|
2289
|
+
},
|
|
2290
|
+
{
|
|
2291
|
+
name: "lastname",
|
|
2292
|
+
type: "text"
|
|
2293
|
+
},
|
|
2294
|
+
{
|
|
2295
|
+
name: "email",
|
|
2296
|
+
type: "text",
|
|
2297
|
+
index: true
|
|
2298
|
+
},
|
|
2299
|
+
{
|
|
2300
|
+
name: "temporary_token",
|
|
2301
|
+
type: "text"
|
|
2302
|
+
},
|
|
2303
|
+
{
|
|
2304
|
+
name: "type",
|
|
2305
|
+
type: "text",
|
|
2306
|
+
index: true
|
|
2307
|
+
},
|
|
2308
|
+
{
|
|
2309
|
+
name: "profile_image",
|
|
2310
|
+
type: "text"
|
|
2311
|
+
},
|
|
2312
|
+
{
|
|
2313
|
+
name: "super_admin",
|
|
2314
|
+
type: "boolean",
|
|
2315
|
+
default: false
|
|
2316
|
+
},
|
|
2317
|
+
{
|
|
2318
|
+
name: "status",
|
|
2319
|
+
type: "text"
|
|
2320
|
+
},
|
|
2321
|
+
{
|
|
2322
|
+
name: "emailVerified",
|
|
2323
|
+
type: "text"
|
|
2324
|
+
},
|
|
2325
|
+
{
|
|
2326
|
+
name: "apikey",
|
|
2327
|
+
type: "text"
|
|
2328
|
+
},
|
|
2329
|
+
{
|
|
2330
|
+
name: "last_used",
|
|
2331
|
+
type: "date"
|
|
2332
|
+
},
|
|
2333
|
+
{
|
|
2334
|
+
name: "anthropic_token",
|
|
2335
|
+
type: "text"
|
|
2336
|
+
},
|
|
2337
|
+
{
|
|
2338
|
+
name: "role",
|
|
2339
|
+
type: "uuid"
|
|
2400
2340
|
}
|
|
2401
|
-
|
|
2402
|
-
|
|
2341
|
+
]
|
|
2342
|
+
};
|
|
2343
|
+
var rolesSchema = {
|
|
2344
|
+
name: {
|
|
2345
|
+
plural: "roles",
|
|
2346
|
+
singular: "role"
|
|
2347
|
+
},
|
|
2348
|
+
fields: [
|
|
2349
|
+
{
|
|
2350
|
+
name: "name",
|
|
2351
|
+
type: "text"
|
|
2352
|
+
},
|
|
2353
|
+
{
|
|
2354
|
+
name: "is_admin",
|
|
2355
|
+
type: "boolean",
|
|
2356
|
+
default: false
|
|
2357
|
+
},
|
|
2358
|
+
{
|
|
2359
|
+
name: "agents",
|
|
2360
|
+
type: "json"
|
|
2403
2361
|
}
|
|
2404
|
-
|
|
2405
|
-
|
|
2362
|
+
]
|
|
2363
|
+
};
|
|
2364
|
+
var statisticsSchema = {
|
|
2365
|
+
name: {
|
|
2366
|
+
plural: "statistics",
|
|
2367
|
+
singular: "statistic"
|
|
2368
|
+
},
|
|
2369
|
+
fields: [
|
|
2370
|
+
{
|
|
2371
|
+
name: "name",
|
|
2372
|
+
type: "text"
|
|
2373
|
+
},
|
|
2374
|
+
{
|
|
2375
|
+
name: "label",
|
|
2376
|
+
type: "text"
|
|
2377
|
+
},
|
|
2378
|
+
{
|
|
2379
|
+
name: "type",
|
|
2380
|
+
type: "text"
|
|
2381
|
+
},
|
|
2382
|
+
{
|
|
2383
|
+
name: "total",
|
|
2384
|
+
type: "number"
|
|
2406
2385
|
}
|
|
2407
|
-
|
|
2386
|
+
]
|
|
2387
|
+
};
|
|
2388
|
+
var workflowSchema = {
|
|
2389
|
+
name: {
|
|
2390
|
+
plural: "workflows",
|
|
2391
|
+
singular: "workflow"
|
|
2408
2392
|
},
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2393
|
+
fields: [
|
|
2394
|
+
{
|
|
2395
|
+
name: "workflow_name",
|
|
2396
|
+
type: "text"
|
|
2397
|
+
},
|
|
2398
|
+
{
|
|
2399
|
+
name: "run_id",
|
|
2400
|
+
type: "text"
|
|
2401
|
+
},
|
|
2402
|
+
{
|
|
2403
|
+
name: "snapshot",
|
|
2404
|
+
type: "text"
|
|
2412
2405
|
}
|
|
2413
|
-
|
|
2414
|
-
|
|
2406
|
+
]
|
|
2407
|
+
};
|
|
2408
|
+
var evalResultsSchema = {
|
|
2409
|
+
name: {
|
|
2410
|
+
plural: "eval_results",
|
|
2411
|
+
singular: "eval_result"
|
|
2412
|
+
},
|
|
2413
|
+
fields: [
|
|
2414
|
+
{
|
|
2415
|
+
name: "input",
|
|
2416
|
+
type: "longText"
|
|
2417
|
+
},
|
|
2418
|
+
{
|
|
2419
|
+
name: "output",
|
|
2420
|
+
type: "longText"
|
|
2421
|
+
},
|
|
2422
|
+
{
|
|
2423
|
+
name: "duration",
|
|
2424
|
+
type: "number"
|
|
2425
|
+
},
|
|
2426
|
+
{
|
|
2427
|
+
name: "category",
|
|
2428
|
+
type: "text"
|
|
2429
|
+
},
|
|
2430
|
+
{
|
|
2431
|
+
name: "metadata",
|
|
2432
|
+
type: "json"
|
|
2433
|
+
},
|
|
2434
|
+
{
|
|
2435
|
+
name: "result",
|
|
2436
|
+
type: "number"
|
|
2437
|
+
},
|
|
2438
|
+
{
|
|
2439
|
+
name: "agent_id",
|
|
2440
|
+
type: "uuid"
|
|
2441
|
+
},
|
|
2442
|
+
{
|
|
2443
|
+
name: "workflow_id",
|
|
2444
|
+
type: "uuid"
|
|
2445
|
+
},
|
|
2446
|
+
{
|
|
2447
|
+
name: "eval_type",
|
|
2448
|
+
type: "text"
|
|
2449
|
+
},
|
|
2450
|
+
{
|
|
2451
|
+
name: "eval_name",
|
|
2452
|
+
type: "text"
|
|
2453
|
+
},
|
|
2454
|
+
{
|
|
2455
|
+
name: "comment",
|
|
2456
|
+
type: "longText"
|
|
2415
2457
|
}
|
|
2416
|
-
|
|
2458
|
+
]
|
|
2459
|
+
};
|
|
2460
|
+
var jobsSchema = {
|
|
2461
|
+
name: {
|
|
2462
|
+
plural: "jobs",
|
|
2463
|
+
singular: "job"
|
|
2417
2464
|
},
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2465
|
+
fields: [
|
|
2466
|
+
{
|
|
2467
|
+
name: "redis",
|
|
2468
|
+
type: "text"
|
|
2469
|
+
},
|
|
2470
|
+
{
|
|
2471
|
+
name: "session",
|
|
2472
|
+
type: "text"
|
|
2473
|
+
},
|
|
2474
|
+
{
|
|
2475
|
+
name: "status",
|
|
2476
|
+
type: "text"
|
|
2477
|
+
},
|
|
2478
|
+
{
|
|
2479
|
+
name: "type",
|
|
2480
|
+
type: "text"
|
|
2481
|
+
},
|
|
2482
|
+
{
|
|
2483
|
+
name: "result",
|
|
2484
|
+
type: "longText"
|
|
2485
|
+
},
|
|
2486
|
+
{
|
|
2487
|
+
name: "name",
|
|
2488
|
+
type: "text"
|
|
2489
|
+
},
|
|
2490
|
+
{
|
|
2491
|
+
name: "agent",
|
|
2492
|
+
type: "uuid"
|
|
2493
|
+
},
|
|
2494
|
+
{
|
|
2495
|
+
name: "workflow",
|
|
2496
|
+
type: "uuid"
|
|
2497
|
+
},
|
|
2498
|
+
{
|
|
2499
|
+
name: "user",
|
|
2500
|
+
// next auth stores users with id type SERIAL, so we need to use number
|
|
2501
|
+
type: "number"
|
|
2502
|
+
},
|
|
2503
|
+
{
|
|
2504
|
+
name: "item",
|
|
2505
|
+
type: "uuid"
|
|
2506
|
+
},
|
|
2507
|
+
{
|
|
2508
|
+
name: "steps",
|
|
2509
|
+
type: "number"
|
|
2510
|
+
},
|
|
2511
|
+
{
|
|
2512
|
+
name: "inputs",
|
|
2513
|
+
type: "json"
|
|
2514
|
+
},
|
|
2515
|
+
{
|
|
2516
|
+
name: "finished_at",
|
|
2517
|
+
type: "date"
|
|
2518
|
+
},
|
|
2519
|
+
{
|
|
2520
|
+
name: "duration",
|
|
2521
|
+
type: "number"
|
|
2424
2522
|
}
|
|
2425
|
-
|
|
2426
|
-
}
|
|
2427
|
-
});
|
|
2428
|
-
var map = (field) => {
|
|
2429
|
-
let type;
|
|
2430
|
-
switch (field.type) {
|
|
2431
|
-
case "text":
|
|
2432
|
-
case "shortText":
|
|
2433
|
-
case "longText":
|
|
2434
|
-
case "code":
|
|
2435
|
-
type = "String";
|
|
2436
|
-
break;
|
|
2437
|
-
case "number":
|
|
2438
|
-
type = "Float";
|
|
2439
|
-
break;
|
|
2440
|
-
case "boolean":
|
|
2441
|
-
type = "Boolean";
|
|
2442
|
-
break;
|
|
2443
|
-
case "json":
|
|
2444
|
-
type = "JSON";
|
|
2445
|
-
break;
|
|
2446
|
-
case "date":
|
|
2447
|
-
type = "Date";
|
|
2448
|
-
break;
|
|
2449
|
-
default:
|
|
2450
|
-
type = "String";
|
|
2451
|
-
}
|
|
2452
|
-
return type;
|
|
2453
|
-
};
|
|
2454
|
-
function createTypeDefs(table) {
|
|
2455
|
-
const fields = table.fields.map((field) => {
|
|
2456
|
-
let type;
|
|
2457
|
-
type = map(field);
|
|
2458
|
-
const required = field.required ? "!" : "";
|
|
2459
|
-
return ` ${field.name}: ${type}${required}`;
|
|
2460
|
-
});
|
|
2461
|
-
const typeDef = `
|
|
2462
|
-
type ${table.name.singular} {
|
|
2463
|
-
${fields.join("\n")}
|
|
2464
|
-
id: ID!
|
|
2465
|
-
createdAt: Date!
|
|
2466
|
-
updatedAt: Date!
|
|
2467
|
-
}
|
|
2468
|
-
`;
|
|
2469
|
-
const inputDef = `
|
|
2470
|
-
input ${table.name.singular}Input {
|
|
2471
|
-
${table.fields.map((f) => ` ${f.name}: ${map(f)}`).join("\n")}
|
|
2472
|
-
}
|
|
2473
|
-
`;
|
|
2474
|
-
return typeDef + inputDef;
|
|
2475
|
-
}
|
|
2476
|
-
function createFilterTypeDefs(table) {
|
|
2477
|
-
const fieldFilters = table.fields.map((field) => {
|
|
2478
|
-
let type;
|
|
2479
|
-
type = map(field);
|
|
2480
|
-
return `
|
|
2481
|
-
${field.name}: FilterOperator${type}`;
|
|
2482
|
-
});
|
|
2483
|
-
const tableNameSingularUpperCaseFirst = table.name.singular.charAt(0).toUpperCase() + table.name.singular.slice(1);
|
|
2484
|
-
const operatorTypes = `
|
|
2485
|
-
input FilterOperatorString {
|
|
2486
|
-
eq: String
|
|
2487
|
-
ne: String
|
|
2488
|
-
in: [String]
|
|
2489
|
-
contains: String
|
|
2490
|
-
}
|
|
2491
|
-
|
|
2492
|
-
input FilterOperatorDate {
|
|
2493
|
-
lte: Date
|
|
2494
|
-
gte: Date
|
|
2495
|
-
}
|
|
2496
|
-
|
|
2497
|
-
input FilterOperatorFloat {
|
|
2498
|
-
eq: Float
|
|
2499
|
-
ne: Float
|
|
2500
|
-
in: [Float]
|
|
2501
|
-
}
|
|
2502
|
-
|
|
2503
|
-
input FilterOperatorBoolean {
|
|
2504
|
-
eq: Boolean
|
|
2505
|
-
ne: Boolean
|
|
2506
|
-
in: [Boolean]
|
|
2507
|
-
}
|
|
2508
|
-
|
|
2509
|
-
input FilterOperatorJSON {
|
|
2510
|
-
eq: JSON
|
|
2511
|
-
ne: JSON
|
|
2512
|
-
in: [JSON]
|
|
2513
|
-
}
|
|
2514
|
-
|
|
2515
|
-
input SortBy {
|
|
2516
|
-
field: String!
|
|
2517
|
-
direction: SortDirection!
|
|
2518
|
-
}
|
|
2519
|
-
|
|
2520
|
-
enum SortDirection {
|
|
2521
|
-
ASC
|
|
2522
|
-
DESC
|
|
2523
|
-
}
|
|
2524
|
-
|
|
2525
|
-
input Filter${tableNameSingularUpperCaseFirst} {
|
|
2526
|
-
${fieldFilters.join("\n")}
|
|
2527
|
-
}`;
|
|
2528
|
-
return operatorTypes;
|
|
2529
|
-
}
|
|
2530
|
-
var getRequestedFields = (info) => {
|
|
2531
|
-
const selections = info.operation.selectionSet.selections[0].selectionSet.selections;
|
|
2532
|
-
const itemsSelection = selections.find((s) => s.name.value === "items");
|
|
2533
|
-
const fields = itemsSelection ? Object.keys(itemsSelection.selectionSet.selections.reduce((acc, field) => {
|
|
2534
|
-
acc[field.name.value] = true;
|
|
2535
|
-
return acc;
|
|
2536
|
-
}, {})) : Object.keys(selections.reduce((acc, field) => {
|
|
2537
|
-
acc[field.name.value] = true;
|
|
2538
|
-
return acc;
|
|
2539
|
-
}, {}));
|
|
2540
|
-
return fields.filter((field) => field !== "pageInfo" && field !== "items");
|
|
2523
|
+
]
|
|
2541
2524
|
};
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
const results = await db2(tableNamePlural).insert({
|
|
2552
|
-
...input,
|
|
2553
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
2554
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
2555
|
-
}).returning(requestedFields);
|
|
2556
|
-
return results[0];
|
|
2557
|
-
},
|
|
2558
|
-
[`${tableNamePlural}UpdateOne`]: async (_, args, context, info) => {
|
|
2559
|
-
const { db: db2 } = context;
|
|
2560
|
-
let { where, input } = args;
|
|
2561
|
-
input = encryptSensitiveFields(input);
|
|
2562
|
-
await db2(tableNamePlural).where(where).update({
|
|
2563
|
-
...input,
|
|
2564
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
2565
|
-
});
|
|
2566
|
-
const requestedFields = getRequestedFields(info);
|
|
2567
|
-
const result = await db2.from(tableNamePlural).select(requestedFields).where(where).first();
|
|
2568
|
-
return result;
|
|
2525
|
+
var agentsSchema = {
|
|
2526
|
+
name: {
|
|
2527
|
+
plural: "agents",
|
|
2528
|
+
singular: "agent"
|
|
2529
|
+
},
|
|
2530
|
+
fields: [
|
|
2531
|
+
{
|
|
2532
|
+
name: "name",
|
|
2533
|
+
type: "text"
|
|
2569
2534
|
},
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
const { db: db2 } = context;
|
|
2574
|
-
await db2(tableNamePlural).where({ id }).update({
|
|
2575
|
-
...input,
|
|
2576
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
2577
|
-
});
|
|
2578
|
-
const requestedFields = getRequestedFields(info);
|
|
2579
|
-
const result = await db2.from(tableNamePlural).select(requestedFields).where({ id }).first();
|
|
2580
|
-
return result;
|
|
2535
|
+
{
|
|
2536
|
+
name: "description",
|
|
2537
|
+
type: "text"
|
|
2581
2538
|
},
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
const requestedFields = getRequestedFields(info);
|
|
2586
|
-
const result = await db2.from(tableNamePlural).select(requestedFields).where(where).first();
|
|
2587
|
-
await db2(tableNamePlural).where(where).del();
|
|
2588
|
-
return result;
|
|
2539
|
+
{
|
|
2540
|
+
name: "extensions",
|
|
2541
|
+
type: "json"
|
|
2589
2542
|
},
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
const requestedFields = getRequestedFields(info);
|
|
2594
|
-
const result = await db2.from(tableNamePlural).select(requestedFields).where({ id }).first();
|
|
2595
|
-
await db2(tableNamePlural).where({ id }).del();
|
|
2596
|
-
return result;
|
|
2597
|
-
}
|
|
2598
|
-
};
|
|
2599
|
-
}
|
|
2600
|
-
function createQueries(table) {
|
|
2601
|
-
const tableNamePlural = table.name.plural.toLowerCase();
|
|
2602
|
-
const tableNameSingular = table.name.singular.toLowerCase();
|
|
2603
|
-
const applyFilters = (query, filters) => {
|
|
2604
|
-
filters.forEach((filter) => {
|
|
2605
|
-
Object.entries(filter).forEach(([fieldName, operators]) => {
|
|
2606
|
-
if (operators) {
|
|
2607
|
-
if (operators.eq !== void 0) {
|
|
2608
|
-
query = query.where(fieldName, operators.eq);
|
|
2609
|
-
}
|
|
2610
|
-
if (operators.ne !== void 0) {
|
|
2611
|
-
query = query.whereRaw(`?? IS DISTINCT FROM ?`, [fieldName, operators.ne]);
|
|
2612
|
-
}
|
|
2613
|
-
if (operators.in !== void 0) {
|
|
2614
|
-
query = query.whereIn(fieldName, operators.in);
|
|
2615
|
-
}
|
|
2616
|
-
if (operators.contains !== void 0) {
|
|
2617
|
-
query = query.where(fieldName, "like", `%${operators.contains}%`);
|
|
2618
|
-
}
|
|
2619
|
-
}
|
|
2620
|
-
});
|
|
2621
|
-
});
|
|
2622
|
-
return query;
|
|
2623
|
-
};
|
|
2624
|
-
const applySorting = (query, sort) => {
|
|
2625
|
-
if (sort) {
|
|
2626
|
-
query = query.orderBy(sort.field, sort.direction.toLowerCase());
|
|
2627
|
-
}
|
|
2628
|
-
return query;
|
|
2629
|
-
};
|
|
2630
|
-
return {
|
|
2631
|
-
[`${tableNameSingular}ById`]: async (_, args, context, info) => {
|
|
2632
|
-
const { db: db2 } = context;
|
|
2633
|
-
const requestedFields = getRequestedFields(info);
|
|
2634
|
-
const result = await db2.from(tableNamePlural).select(requestedFields).where({ id: args.id }).first();
|
|
2635
|
-
return result;
|
|
2543
|
+
{
|
|
2544
|
+
name: "backend",
|
|
2545
|
+
type: "text"
|
|
2636
2546
|
},
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
const requestedFields = getRequestedFields(info);
|
|
2641
|
-
let query = db2.from(tableNamePlural).select(requestedFields);
|
|
2642
|
-
query = applyFilters(query, filters);
|
|
2643
|
-
query = applySorting(query, sort);
|
|
2644
|
-
const result = await query.first();
|
|
2645
|
-
return result;
|
|
2547
|
+
{
|
|
2548
|
+
name: "type",
|
|
2549
|
+
type: "text"
|
|
2646
2550
|
},
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
baseQuery = applyFilters(baseQuery, filters);
|
|
2652
|
-
const [{ count }] = await baseQuery.clone().count("* as count");
|
|
2653
|
-
const itemCount = Number(count);
|
|
2654
|
-
const pageCount = Math.ceil(itemCount / limit);
|
|
2655
|
-
const currentPage = page;
|
|
2656
|
-
const hasPreviousPage = currentPage > 1;
|
|
2657
|
-
const hasNextPage = currentPage < pageCount - 1;
|
|
2658
|
-
let dataQuery = baseQuery.clone();
|
|
2659
|
-
const requestedFields = getRequestedFields(info);
|
|
2660
|
-
dataQuery = applySorting(dataQuery, sort);
|
|
2661
|
-
if (page > 1) {
|
|
2662
|
-
dataQuery = dataQuery.offset((page - 1) * limit);
|
|
2663
|
-
}
|
|
2664
|
-
const items = await dataQuery.select(requestedFields).limit(limit);
|
|
2665
|
-
return {
|
|
2666
|
-
pageInfo: {
|
|
2667
|
-
pageCount,
|
|
2668
|
-
itemCount,
|
|
2669
|
-
currentPage,
|
|
2670
|
-
hasPreviousPage,
|
|
2671
|
-
hasNextPage
|
|
2672
|
-
},
|
|
2673
|
-
items
|
|
2674
|
-
};
|
|
2551
|
+
{
|
|
2552
|
+
name: "active",
|
|
2553
|
+
type: "boolean",
|
|
2554
|
+
default: false
|
|
2675
2555
|
},
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
}
|
|
2685
|
-
if (agent) {
|
|
2686
|
-
query = query.where("agent", agent);
|
|
2687
|
-
}
|
|
2688
|
-
if (from) {
|
|
2689
|
-
query = query.where("createdAt", ">=", from);
|
|
2690
|
-
}
|
|
2691
|
-
if (to) {
|
|
2692
|
-
query = query.where("createdAt", "<=", to);
|
|
2693
|
-
}
|
|
2694
|
-
const completedQuery = query.clone().where("status", "completed");
|
|
2695
|
-
const [{ completedCount }] = await completedQuery.count("* as completedCount");
|
|
2696
|
-
const failedQuery = query.clone().where("status", "failed");
|
|
2697
|
-
const [{ failedCount }] = await failedQuery.count("* as failedCount");
|
|
2698
|
-
const durationQuery = query.clone().where("status", "completed").whereNotNull("duration").select(db2.raw('AVG("duration") as averageDuration'));
|
|
2699
|
-
const [{ averageDuration }] = await durationQuery;
|
|
2700
|
-
return {
|
|
2701
|
-
completedCount: Number(completedCount),
|
|
2702
|
-
failedCount: Number(failedCount),
|
|
2703
|
-
averageDuration: averageDuration ? Number(averageDuration) : 0
|
|
2704
|
-
};
|
|
2705
|
-
}
|
|
2706
|
-
} : {}
|
|
2707
|
-
};
|
|
2708
|
-
}
|
|
2709
|
-
function createSDL(tables) {
|
|
2710
|
-
let typeDefs = `
|
|
2711
|
-
scalar JSON
|
|
2712
|
-
scalar Date
|
|
2713
|
-
|
|
2714
|
-
type Query {
|
|
2715
|
-
`;
|
|
2716
|
-
let mutationDefs = `
|
|
2717
|
-
type Mutation {
|
|
2718
|
-
`;
|
|
2719
|
-
let modelDefs = "";
|
|
2720
|
-
const resolvers = { JSON: import_graphql_type_json.default, Date: GraphQLDate, Query: {}, Mutation: {} };
|
|
2721
|
-
for (const table of tables) {
|
|
2722
|
-
const tableNamePlural = table.name.plural.toLowerCase();
|
|
2723
|
-
const tableNameSingular = table.name.singular.toLowerCase();
|
|
2724
|
-
const tableNameSingularUpperCaseFirst = table.name.singular.charAt(0).toUpperCase() + table.name.singular.slice(1);
|
|
2725
|
-
typeDefs += `
|
|
2726
|
-
${tableNameSingular}ById(id: ID!): ${tableNameSingular}
|
|
2727
|
-
${tableNamePlural}Pagination(limit: Int, page: Int, filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingularUpperCaseFirst}PaginationResult
|
|
2728
|
-
${tableNameSingular}One(filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingular}
|
|
2729
|
-
${tableNamePlural === "jobs" ? `jobStatistics(user: ID, agent: String, from: String, to: String): JobStatistics` : ""}
|
|
2730
|
-
`;
|
|
2731
|
-
mutationDefs += `
|
|
2732
|
-
${tableNamePlural}CreateOne(input: ${tableNameSingular}Input!): ${tableNameSingular}
|
|
2733
|
-
${tableNamePlural}UpdateOne(where: JSON!, input: ${tableNameSingular}Input!): ${tableNameSingular}
|
|
2734
|
-
${tableNamePlural}UpdateOneById(id: ID!, input: ${tableNameSingular}Input!): ${tableNameSingular}
|
|
2735
|
-
${tableNamePlural}RemoveOne(where: JSON!): ${tableNameSingular}
|
|
2736
|
-
${tableNamePlural}RemoveOneById(id: ID!): ${tableNameSingular}
|
|
2737
|
-
`;
|
|
2738
|
-
modelDefs += createTypeDefs(table);
|
|
2739
|
-
modelDefs += createFilterTypeDefs(table);
|
|
2740
|
-
modelDefs += `
|
|
2741
|
-
type ${tableNameSingularUpperCaseFirst}PaginationResult {
|
|
2742
|
-
pageInfo: PageInfo!
|
|
2743
|
-
items: [${tableNameSingular}]!
|
|
2744
|
-
}
|
|
2745
|
-
|
|
2746
|
-
type PageInfo {
|
|
2747
|
-
pageCount: Int!
|
|
2748
|
-
itemCount: Int!
|
|
2749
|
-
currentPage: Int!
|
|
2750
|
-
hasPreviousPage: Boolean!
|
|
2751
|
-
hasNextPage: Boolean!
|
|
2752
|
-
}
|
|
2753
|
-
`;
|
|
2754
|
-
if (tableNamePlural === "jobs") {
|
|
2755
|
-
modelDefs += `
|
|
2756
|
-
type JobStatistics {
|
|
2757
|
-
completedCount: Int!
|
|
2758
|
-
failedCount: Int!
|
|
2759
|
-
averageDuration: Float!
|
|
2760
|
-
}
|
|
2761
|
-
`;
|
|
2762
|
-
}
|
|
2763
|
-
Object.assign(resolvers.Query, createQueries(table));
|
|
2764
|
-
Object.assign(resolvers.Mutation, createMutations(table));
|
|
2765
|
-
}
|
|
2766
|
-
typeDefs += "}\n";
|
|
2767
|
-
mutationDefs += "}\n";
|
|
2768
|
-
const fullSDL = typeDefs + mutationDefs + modelDefs;
|
|
2769
|
-
const schema = (0, import_schema.makeExecutableSchema)({
|
|
2770
|
-
typeDefs: fullSDL,
|
|
2771
|
-
resolvers
|
|
2772
|
-
});
|
|
2773
|
-
console.log("\n\u{1F4CA} GraphQL Schema Overview\n");
|
|
2774
|
-
const queriesTable = Object.keys(resolvers.Query).map((query) => ({
|
|
2775
|
-
"Operation Type": "Query",
|
|
2776
|
-
"Name": query,
|
|
2777
|
-
"Description": "Retrieves data"
|
|
2778
|
-
}));
|
|
2779
|
-
const mutationsTable = Object.keys(resolvers.Mutation).map((mutation) => ({
|
|
2780
|
-
"Operation Type": "Mutation",
|
|
2781
|
-
"Name": mutation,
|
|
2782
|
-
"Description": "Modifies data"
|
|
2783
|
-
}));
|
|
2784
|
-
const typesTable = tables.flatMap(
|
|
2785
|
-
(table) => table.fields.map((field) => ({
|
|
2786
|
-
"Type": table.name.singular,
|
|
2787
|
-
"Field": field.name,
|
|
2788
|
-
"Field Type": field.type,
|
|
2789
|
-
"Required": field.required ? "Yes" : "No"
|
|
2790
|
-
}))
|
|
2791
|
-
);
|
|
2792
|
-
console.log("\u{1F50D} Operations:");
|
|
2793
|
-
console.table([...queriesTable, ...mutationsTable]);
|
|
2794
|
-
console.log("\n\u{1F4DD} Types and Fields:");
|
|
2795
|
-
console.table(typesTable);
|
|
2796
|
-
console.log("\n");
|
|
2797
|
-
return schema;
|
|
2798
|
-
}
|
|
2799
|
-
var sensitiveFields = ["anthropic_token"];
|
|
2800
|
-
var encryptSensitiveFields = (input) => {
|
|
2801
|
-
sensitiveFields.forEach((field) => {
|
|
2802
|
-
if (input[field]) {
|
|
2803
|
-
input[field] = import_crypto_js.default.AES.encrypt(input[field], process.env.NEXTAUTH_SECRET).toString();
|
|
2556
|
+
{
|
|
2557
|
+
name: "public",
|
|
2558
|
+
type: "boolean",
|
|
2559
|
+
default: false
|
|
2560
|
+
},
|
|
2561
|
+
{
|
|
2562
|
+
name: "tools",
|
|
2563
|
+
type: "json"
|
|
2804
2564
|
}
|
|
2805
|
-
|
|
2806
|
-
return input;
|
|
2565
|
+
]
|
|
2807
2566
|
};
|
|
2808
2567
|
|
|
2809
|
-
// src/registry/routes.ts
|
|
2810
|
-
var import_express5 = require("@as-integrations/express5");
|
|
2811
|
-
|
|
2812
2568
|
// src/registry/uppy.ts
|
|
2813
2569
|
var import_express = require("express");
|
|
2814
2570
|
var createUppyRoutes = async (app) => {
|
|
@@ -4947,6 +4703,259 @@ var getTicket = new ExuluTool({
|
|
|
4947
4703
|
}
|
|
4948
4704
|
});
|
|
4949
4705
|
|
|
4706
|
+
// src/auth/generate-key.ts
|
|
4707
|
+
var import_bcryptjs2 = __toESM(require("bcryptjs"), 1);
|
|
4708
|
+
var SALT_ROUNDS = 12;
|
|
4709
|
+
async function encryptString(string) {
|
|
4710
|
+
const hash = await import_bcryptjs2.default.hash(string, SALT_ROUNDS);
|
|
4711
|
+
return hash;
|
|
4712
|
+
}
|
|
4713
|
+
var generateApiKey = async (name, email) => {
|
|
4714
|
+
const { db: db2 } = await postgresClient();
|
|
4715
|
+
console.log("[EXULU] Inserting default user and admin role.");
|
|
4716
|
+
const existingRole = await db2.from("roles").where({ name: "admin" }).first();
|
|
4717
|
+
let roleId;
|
|
4718
|
+
if (!existingRole) {
|
|
4719
|
+
console.log("[EXULU] Creating default admin role.");
|
|
4720
|
+
const role = await db2.from("roles").insert({
|
|
4721
|
+
name: "admin",
|
|
4722
|
+
is_admin: true,
|
|
4723
|
+
agents: []
|
|
4724
|
+
}).returning("id");
|
|
4725
|
+
roleId = role[0].id;
|
|
4726
|
+
} else {
|
|
4727
|
+
roleId = existingRole.id;
|
|
4728
|
+
}
|
|
4729
|
+
const newKeyName = name;
|
|
4730
|
+
const plainKey = `sk_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
|
|
4731
|
+
const postFix = `/${newKeyName.toLowerCase().trim().replaceAll(" ", "_")}`;
|
|
4732
|
+
const encryptedKey = await encryptString(plainKey);
|
|
4733
|
+
const existingApiUser = await db2.from("users").where({ email }).first();
|
|
4734
|
+
if (!existingApiUser) {
|
|
4735
|
+
console.log("[EXULU] Creating default api user.");
|
|
4736
|
+
await db2.from("users").insert({
|
|
4737
|
+
name,
|
|
4738
|
+
email,
|
|
4739
|
+
super_admin: true,
|
|
4740
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
4741
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
4742
|
+
type: "api",
|
|
4743
|
+
emailVerified: /* @__PURE__ */ new Date(),
|
|
4744
|
+
apikey: `${encryptedKey}${postFix}`,
|
|
4745
|
+
// password: "admin", todo add this again when we implement password auth / encryption as alternative to OTP
|
|
4746
|
+
role: roleId
|
|
4747
|
+
});
|
|
4748
|
+
console.log("[EXULU] Default api user created. Key: ", `${plainKey}${postFix}`);
|
|
4749
|
+
} else {
|
|
4750
|
+
console.log("[EXULU] API user with that name already exists.");
|
|
4751
|
+
}
|
|
4752
|
+
console.log("[EXULU] Key generated, copy and use the plain key from here, you will not be able to access it again.");
|
|
4753
|
+
console.log("[EXULU] Key: ", `${plainKey}${postFix}`);
|
|
4754
|
+
return {
|
|
4755
|
+
key: `${plainKey}${postFix}`
|
|
4756
|
+
};
|
|
4757
|
+
};
|
|
4758
|
+
|
|
4759
|
+
// src/postgres/init-db.ts
|
|
4760
|
+
var up = async function(knex) {
|
|
4761
|
+
if (!await knex.schema.hasTable("agent_sessions")) {
|
|
4762
|
+
console.log("[EXULU] Creating agent_sessions table.");
|
|
4763
|
+
await knex.schema.createTable("agent_sessions", (table) => {
|
|
4764
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
4765
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4766
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4767
|
+
for (const field of agentSessionsSchema.fields) {
|
|
4768
|
+
const { type, name, default: defaultValue } = field;
|
|
4769
|
+
if (!type || !name) {
|
|
4770
|
+
continue;
|
|
4771
|
+
}
|
|
4772
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4773
|
+
}
|
|
4774
|
+
});
|
|
4775
|
+
}
|
|
4776
|
+
if (!await knex.schema.hasTable("agent_messages")) {
|
|
4777
|
+
console.log("[EXULU] Creating agent_messages table.");
|
|
4778
|
+
await knex.schema.createTable("agent_messages", (table) => {
|
|
4779
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
4780
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4781
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4782
|
+
for (const field of agentMessagesSchema.fields) {
|
|
4783
|
+
const { type, name, default: defaultValue } = field;
|
|
4784
|
+
if (!type || !name) {
|
|
4785
|
+
continue;
|
|
4786
|
+
}
|
|
4787
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4788
|
+
}
|
|
4789
|
+
});
|
|
4790
|
+
}
|
|
4791
|
+
if (!await knex.schema.hasTable("roles")) {
|
|
4792
|
+
console.log("[EXULU] Creating roles table.");
|
|
4793
|
+
await knex.schema.createTable("roles", (table) => {
|
|
4794
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
4795
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4796
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4797
|
+
for (const field of rolesSchema.fields) {
|
|
4798
|
+
const { type, name, default: defaultValue } = field;
|
|
4799
|
+
if (!type || !name) {
|
|
4800
|
+
continue;
|
|
4801
|
+
}
|
|
4802
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4803
|
+
}
|
|
4804
|
+
});
|
|
4805
|
+
}
|
|
4806
|
+
if (!await knex.schema.hasTable("eval_results")) {
|
|
4807
|
+
console.log("[EXULU] Creating eval_results table.");
|
|
4808
|
+
await knex.schema.createTable("eval_results", (table) => {
|
|
4809
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
4810
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4811
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4812
|
+
for (const field of evalResultsSchema.fields) {
|
|
4813
|
+
const { type, name, default: defaultValue } = field;
|
|
4814
|
+
if (!type || !name) {
|
|
4815
|
+
continue;
|
|
4816
|
+
}
|
|
4817
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4818
|
+
}
|
|
4819
|
+
});
|
|
4820
|
+
}
|
|
4821
|
+
if (!await knex.schema.hasTable("statistics")) {
|
|
4822
|
+
console.log("[EXULU] Creating statistics table.");
|
|
4823
|
+
await knex.schema.createTable("statistics", (table) => {
|
|
4824
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
4825
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4826
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4827
|
+
for (const field of statisticsSchema.fields) {
|
|
4828
|
+
const { type, name, default: defaultValue } = field;
|
|
4829
|
+
if (!type || !name) {
|
|
4830
|
+
continue;
|
|
4831
|
+
}
|
|
4832
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4833
|
+
}
|
|
4834
|
+
});
|
|
4835
|
+
}
|
|
4836
|
+
if (!await knex.schema.hasTable("jobs")) {
|
|
4837
|
+
console.log("[EXULU] Creating jobs table.");
|
|
4838
|
+
await knex.schema.createTable("jobs", (table) => {
|
|
4839
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
4840
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4841
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4842
|
+
for (const field of jobsSchema.fields) {
|
|
4843
|
+
const { type, name, default: defaultValue } = field;
|
|
4844
|
+
if (!type || !name) {
|
|
4845
|
+
continue;
|
|
4846
|
+
}
|
|
4847
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4848
|
+
}
|
|
4849
|
+
});
|
|
4850
|
+
}
|
|
4851
|
+
if (!await knex.schema.hasTable("agents")) {
|
|
4852
|
+
console.log("[EXULU] Creating agents table.");
|
|
4853
|
+
await knex.schema.createTable("agents", (table) => {
|
|
4854
|
+
table.uuid("id").primary().defaultTo(knex.fn.uuid());
|
|
4855
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4856
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4857
|
+
for (const field of agentsSchema.fields) {
|
|
4858
|
+
const { type, name, default: defaultValue } = field;
|
|
4859
|
+
if (!type || !name) {
|
|
4860
|
+
continue;
|
|
4861
|
+
}
|
|
4862
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4863
|
+
}
|
|
4864
|
+
});
|
|
4865
|
+
}
|
|
4866
|
+
if (!await knex.schema.hasTable("verification_token")) {
|
|
4867
|
+
console.log("[EXULU] Creating verification_token table.");
|
|
4868
|
+
await knex.schema.createTable("verification_token", (table) => {
|
|
4869
|
+
table.text("identifier").notNullable();
|
|
4870
|
+
table.timestamp("expires", { useTz: true }).notNullable();
|
|
4871
|
+
table.text("token").notNullable();
|
|
4872
|
+
table.primary(["identifier", "token"]);
|
|
4873
|
+
});
|
|
4874
|
+
}
|
|
4875
|
+
if (!await knex.schema.hasTable("users")) {
|
|
4876
|
+
console.log("[EXULU] Creating users table.");
|
|
4877
|
+
await knex.schema.createTable("users", (table) => {
|
|
4878
|
+
table.increments("id").primary();
|
|
4879
|
+
table.timestamp("createdAt").defaultTo(knex.fn.now());
|
|
4880
|
+
table.timestamp("updatedAt").defaultTo(knex.fn.now());
|
|
4881
|
+
table.string("name", 255);
|
|
4882
|
+
table.string("password", 255);
|
|
4883
|
+
table.string("email", 255);
|
|
4884
|
+
table.timestamp("emailVerified", { useTz: true });
|
|
4885
|
+
table.text("image");
|
|
4886
|
+
for (const field of usersSchema.fields) {
|
|
4887
|
+
console.log("[EXULU] field", field);
|
|
4888
|
+
const { type, name, default: defaultValue } = field;
|
|
4889
|
+
if (name === "id" || name === "name" || name === "email" || name === "emailVerified" || name === "image") {
|
|
4890
|
+
continue;
|
|
4891
|
+
}
|
|
4892
|
+
if (!type || !name) {
|
|
4893
|
+
continue;
|
|
4894
|
+
}
|
|
4895
|
+
mapType(table, type, sanitizeName(name), defaultValue);
|
|
4896
|
+
}
|
|
4897
|
+
});
|
|
4898
|
+
}
|
|
4899
|
+
if (!await knex.schema.hasTable("accounts")) {
|
|
4900
|
+
console.log("[EXULU] Creating accounts table.");
|
|
4901
|
+
await knex.schema.createTable("accounts", (table) => {
|
|
4902
|
+
table.increments("id").primary();
|
|
4903
|
+
table.integer("userId").notNullable();
|
|
4904
|
+
table.string("type", 255).notNullable();
|
|
4905
|
+
table.string("provider", 255).notNullable();
|
|
4906
|
+
table.string("providerAccountId", 255).notNullable();
|
|
4907
|
+
table.text("refresh_token");
|
|
4908
|
+
table.text("access_token");
|
|
4909
|
+
table.bigInteger("expires_at");
|
|
4910
|
+
table.text("id_token");
|
|
4911
|
+
table.text("scope");
|
|
4912
|
+
table.text("session_state");
|
|
4913
|
+
table.text("token_type");
|
|
4914
|
+
});
|
|
4915
|
+
}
|
|
4916
|
+
};
|
|
4917
|
+
var execute = async () => {
|
|
4918
|
+
const { db: db2 } = await postgresClient();
|
|
4919
|
+
console.log("[EXULU] Checking Exulu IMP database status.");
|
|
4920
|
+
await up(db2);
|
|
4921
|
+
console.log("[EXULU] Inserting default user and admin role.");
|
|
4922
|
+
const existingRole = await db2.from("roles").where({ name: "admin" }).first();
|
|
4923
|
+
let roleId;
|
|
4924
|
+
if (!existingRole) {
|
|
4925
|
+
console.log("[EXULU] Creating default admin role.");
|
|
4926
|
+
const role = await db2.from("roles").insert({
|
|
4927
|
+
name: "admin",
|
|
4928
|
+
is_admin: true,
|
|
4929
|
+
agents: JSON.stringify([])
|
|
4930
|
+
}).returning("id");
|
|
4931
|
+
roleId = role[0].id;
|
|
4932
|
+
} else {
|
|
4933
|
+
roleId = existingRole.id;
|
|
4934
|
+
}
|
|
4935
|
+
const existingUser = await db2.from("users").where({ email: "admin@exulu.com" }).first();
|
|
4936
|
+
if (!existingUser) {
|
|
4937
|
+
const password = await encryptString("admin");
|
|
4938
|
+
console.log("[EXULU] Creating default admin user.");
|
|
4939
|
+
await db2.from("users").insert({
|
|
4940
|
+
name: "exulu",
|
|
4941
|
+
email: "admin@exulu.com",
|
|
4942
|
+
super_admin: true,
|
|
4943
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
4944
|
+
emailVerified: /* @__PURE__ */ new Date(),
|
|
4945
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
4946
|
+
password,
|
|
4947
|
+
type: "user",
|
|
4948
|
+
role: roleId
|
|
4949
|
+
});
|
|
4950
|
+
}
|
|
4951
|
+
const { key } = await generateApiKey("exulu", "api@exulu.com");
|
|
4952
|
+
console.log("[EXULU] Database initialized.");
|
|
4953
|
+
console.log("[EXULU] Default api key: ", `${key}`);
|
|
4954
|
+
console.log("[EXULU] Default password if using password auth: ", `admin`);
|
|
4955
|
+
console.log("[EXULU] Default email if using password auth: ", `admin@exulu.com`);
|
|
4956
|
+
return;
|
|
4957
|
+
};
|
|
4958
|
+
|
|
4950
4959
|
// src/registry/index.ts
|
|
4951
4960
|
var ExuluApp = class {
|
|
4952
4961
|
_agents = [];
|
|
@@ -4961,6 +4970,7 @@ var ExuluApp = class {
|
|
|
4961
4970
|
// Factory function so we can async
|
|
4962
4971
|
// initialize the MCP server if needed.
|
|
4963
4972
|
create = async ({ contexts, agents, workflows, config, tools }) => {
|
|
4973
|
+
await execute();
|
|
4964
4974
|
this._workflows = workflows ?? [];
|
|
4965
4975
|
this._contexts = contexts ?? {};
|
|
4966
4976
|
this._agents = [
|
|
@@ -6276,14 +6286,6 @@ var ExuluChunkers = {
|
|
|
6276
6286
|
rules: RecursiveRules
|
|
6277
6287
|
}
|
|
6278
6288
|
};
|
|
6279
|
-
var ExuluDatabase = {
|
|
6280
|
-
init: async () => {
|
|
6281
|
-
await execute();
|
|
6282
|
-
},
|
|
6283
|
-
generateApiKey: async (name, email) => {
|
|
6284
|
-
return await generateApiKey(name, email);
|
|
6285
|
-
}
|
|
6286
|
-
};
|
|
6287
6289
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6288
6290
|
0 && (module.exports = {
|
|
6289
6291
|
EXULU_JOB_STATUS_ENUM,
|
|
@@ -6293,7 +6295,6 @@ var ExuluDatabase = {
|
|
|
6293
6295
|
ExuluAuthentication,
|
|
6294
6296
|
ExuluChunkers,
|
|
6295
6297
|
ExuluContext,
|
|
6296
|
-
ExuluDatabase,
|
|
6297
6298
|
ExuluEmbedder,
|
|
6298
6299
|
ExuluEval,
|
|
6299
6300
|
ExuluJobs,
|