@semiont/backend 0.2.46 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +511 -102
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import winston from 'winston';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import jwt from 'jsonwebtoken';
|
|
5
|
-
import { createConfigLoader, email, userId, accessToken, googleCredential, annotationId, resourceId, EventBus,
|
|
5
|
+
import { createConfigLoader, email, userId, accessToken, googleCredential, annotationId, resourceId, EventBus, jobId, entityType, assembleAnnotation, userToAgent } from '@semiont/core';
|
|
6
6
|
import { cors } from 'hono/cors';
|
|
7
7
|
import { serve } from '@hono/node-server';
|
|
8
8
|
import { Hono } from 'hono';
|
|
9
9
|
import { swaggerUI } from '@hono/swagger-ui';
|
|
10
|
-
import { AnnotationContext, startMakeMeaning, ResourceContext, ResourceOperations } from '@semiont/make-meaning';
|
|
10
|
+
import { exportBackup, importBackup, readEntityTypesProjection, exportLinkedData, importLinkedData, AnnotationContext, startMakeMeaning, ResourceContext, ResourceOperations } from '@semiont/make-meaning';
|
|
11
11
|
import * as fs from 'fs';
|
|
12
12
|
import * as path from 'path';
|
|
13
13
|
import { PrismaClient } from '@prisma/client';
|
|
@@ -15,6 +15,7 @@ import { HTTPException } from 'hono/http-exception';
|
|
|
15
15
|
import Ajv from 'ajv';
|
|
16
16
|
import addFormats from 'ajv-formats';
|
|
17
17
|
import * as argon2 from 'argon2';
|
|
18
|
+
import { Writable, Readable } from 'stream';
|
|
18
19
|
import { streamSSE } from 'hono/streaming';
|
|
19
20
|
import crypto2, { randomUUID } from 'crypto';
|
|
20
21
|
import { EventQuery } from '@semiont/event-sourcing';
|
|
@@ -66,8 +67,8 @@ __export(logger_exports, {
|
|
|
66
67
|
function getLoggerConfig(logLevel) {
|
|
67
68
|
const level = logLevel || process.env.LOG_LEVEL || "info";
|
|
68
69
|
const format = process.env.LOG_FORMAT || "json";
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
70
|
+
const nodeEnv = process.env.NODE_ENV || "development";
|
|
71
|
+
if (nodeEnv === "test") {
|
|
71
72
|
return {
|
|
72
73
|
level: "error",
|
|
73
74
|
format: "simple",
|
|
@@ -12073,8 +12074,8 @@ var getRouteLogger = /* @__PURE__ */ __name(() => getLogger().child({
|
|
|
12073
12074
|
}), "getRouteLogger");
|
|
12074
12075
|
var healthRouter = new Hono();
|
|
12075
12076
|
healthRouter.get("/api/health", async (c) => {
|
|
12076
|
-
const
|
|
12077
|
-
if (!
|
|
12077
|
+
const nodeEnv = process.env.NODE_ENV;
|
|
12078
|
+
if (!nodeEnv) {
|
|
12078
12079
|
throw new Error("NODE_ENV environment variable is required");
|
|
12079
12080
|
}
|
|
12080
12081
|
let startupFailed = false;
|
|
@@ -12098,7 +12099,7 @@ healthRouter.get("/api/health", async (c) => {
|
|
|
12098
12099
|
version: "0.1.0",
|
|
12099
12100
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12100
12101
|
database: "unknown",
|
|
12101
|
-
environment:
|
|
12102
|
+
environment: nodeEnv
|
|
12102
12103
|
};
|
|
12103
12104
|
return c.json(response2, 200);
|
|
12104
12105
|
}
|
|
@@ -12109,7 +12110,7 @@ healthRouter.get("/api/health", async (c) => {
|
|
|
12109
12110
|
version: "0.1.0",
|
|
12110
12111
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12111
12112
|
database: dbStatus ? "connected" : "disconnected",
|
|
12112
|
-
environment:
|
|
12113
|
+
environment: nodeEnv
|
|
12113
12114
|
};
|
|
12114
12115
|
return c.json(response, 200);
|
|
12115
12116
|
});
|
|
@@ -12553,8 +12554,8 @@ var openapi_default = {
|
|
|
12553
12554
|
]
|
|
12554
12555
|
},
|
|
12555
12556
|
context: {
|
|
12556
|
-
$ref: "#/components/schemas/
|
|
12557
|
-
description: "
|
|
12557
|
+
$ref: "#/components/schemas/GatheredContext",
|
|
12558
|
+
description: "Gathered context for this annotation"
|
|
12558
12559
|
},
|
|
12559
12560
|
sourceContext: {
|
|
12560
12561
|
type: "object",
|
|
@@ -13529,8 +13530,8 @@ var openapi_default = {
|
|
|
13529
13530
|
description: 'Language locale for generated content (e.g., "es", "fr", "ja")'
|
|
13530
13531
|
},
|
|
13531
13532
|
context: {
|
|
13532
|
-
$ref: "#/components/schemas/
|
|
13533
|
-
description: "
|
|
13533
|
+
$ref: "#/components/schemas/GatheredContext",
|
|
13534
|
+
description: "Gathered context including source document excerpts, metadata, and graph context"
|
|
13534
13535
|
},
|
|
13535
13536
|
temperature: {
|
|
13536
13537
|
type: "number",
|
|
@@ -14449,7 +14450,6 @@ var openapi_default = {
|
|
|
14449
14450
|
},
|
|
14450
14451
|
"@id": {
|
|
14451
14452
|
type: "string",
|
|
14452
|
-
format: "uri",
|
|
14453
14453
|
description: "Canonical URI/URN of the resource being described."
|
|
14454
14454
|
},
|
|
14455
14455
|
"@type": {
|
|
@@ -14560,14 +14560,12 @@ var openapi_default = {
|
|
|
14560
14560
|
description: "W3C PROV - source resources this was derived from",
|
|
14561
14561
|
oneOf: [
|
|
14562
14562
|
{
|
|
14563
|
-
type: "string"
|
|
14564
|
-
format: "uri"
|
|
14563
|
+
type: "string"
|
|
14565
14564
|
},
|
|
14566
14565
|
{
|
|
14567
14566
|
type: "array",
|
|
14568
14567
|
items: {
|
|
14569
|
-
type: "string"
|
|
14570
|
-
format: "uri"
|
|
14568
|
+
type: "string"
|
|
14571
14569
|
}
|
|
14572
14570
|
}
|
|
14573
14571
|
]
|
|
@@ -14657,6 +14655,11 @@ var openapi_default = {
|
|
|
14657
14655
|
sourceResourceId: {
|
|
14658
14656
|
type: "string",
|
|
14659
14657
|
description: "Application-specific: ID of source resource for clones/derivatives"
|
|
14658
|
+
},
|
|
14659
|
+
originatedFrom: {
|
|
14660
|
+
type: "string",
|
|
14661
|
+
format: "uri",
|
|
14662
|
+
description: "Original URI from a source knowledge base when this resource was imported"
|
|
14660
14663
|
}
|
|
14661
14664
|
}
|
|
14662
14665
|
},
|
|
@@ -15159,10 +15162,18 @@ var openapi_default = {
|
|
|
15159
15162
|
"value"
|
|
15160
15163
|
]
|
|
15161
15164
|
},
|
|
15162
|
-
|
|
15165
|
+
GatheredContext: {
|
|
15163
15166
|
type: "object",
|
|
15164
|
-
description: "Context
|
|
15167
|
+
description: "Context gathered for an annotation. Includes source document excerpts, metadata, and graph-derived context. Used by both Find (bind) and Generate (yield) flows.",
|
|
15165
15168
|
properties: {
|
|
15169
|
+
annotation: {
|
|
15170
|
+
$ref: "#/components/schemas/Annotation",
|
|
15171
|
+
description: "The annotation this context was gathered for"
|
|
15172
|
+
},
|
|
15173
|
+
sourceResource: {
|
|
15174
|
+
$ref: "#/components/schemas/ResourceDescriptor",
|
|
15175
|
+
description: "The resource containing the annotation"
|
|
15176
|
+
},
|
|
15166
15177
|
sourceContext: {
|
|
15167
15178
|
type: "object",
|
|
15168
15179
|
description: "Text context from the source document",
|
|
@@ -15186,7 +15197,7 @@ var openapi_default = {
|
|
|
15186
15197
|
},
|
|
15187
15198
|
metadata: {
|
|
15188
15199
|
type: "object",
|
|
15189
|
-
description: "
|
|
15200
|
+
description: "Context metadata about the annotation and its source",
|
|
15190
15201
|
properties: {
|
|
15191
15202
|
resourceType: {
|
|
15192
15203
|
type: "string",
|
|
@@ -15204,10 +15215,95 @@ var openapi_default = {
|
|
|
15204
15215
|
description: "Entity types associated with the annotation"
|
|
15205
15216
|
}
|
|
15206
15217
|
}
|
|
15218
|
+
},
|
|
15219
|
+
userHint: {
|
|
15220
|
+
type: "string",
|
|
15221
|
+
description: "User-provided textual hint to supplement or replace the selected text for search and generation"
|
|
15222
|
+
},
|
|
15223
|
+
graphContext: {
|
|
15224
|
+
type: "object",
|
|
15225
|
+
description: "Graph-derived context from the knowledge base",
|
|
15226
|
+
properties: {
|
|
15227
|
+
connections: {
|
|
15228
|
+
type: "array",
|
|
15229
|
+
description: "Resources connected to the source resource via annotations",
|
|
15230
|
+
items: {
|
|
15231
|
+
type: "object",
|
|
15232
|
+
properties: {
|
|
15233
|
+
resourceId: {
|
|
15234
|
+
type: "string",
|
|
15235
|
+
description: "ID of the connected resource"
|
|
15236
|
+
},
|
|
15237
|
+
resourceName: {
|
|
15238
|
+
type: "string",
|
|
15239
|
+
description: "Name of the connected resource"
|
|
15240
|
+
},
|
|
15241
|
+
entityTypes: {
|
|
15242
|
+
type: "array",
|
|
15243
|
+
items: {
|
|
15244
|
+
type: "string"
|
|
15245
|
+
},
|
|
15246
|
+
description: "Entity types on the connected resource"
|
|
15247
|
+
},
|
|
15248
|
+
bidirectional: {
|
|
15249
|
+
type: "boolean",
|
|
15250
|
+
description: "Whether the connection goes both ways"
|
|
15251
|
+
}
|
|
15252
|
+
},
|
|
15253
|
+
required: [
|
|
15254
|
+
"resourceId",
|
|
15255
|
+
"resourceName",
|
|
15256
|
+
"bidirectional"
|
|
15257
|
+
]
|
|
15258
|
+
}
|
|
15259
|
+
},
|
|
15260
|
+
citedByCount: {
|
|
15261
|
+
type: "integer",
|
|
15262
|
+
description: "Number of other resources that reference the source resource"
|
|
15263
|
+
},
|
|
15264
|
+
citedBy: {
|
|
15265
|
+
type: "array",
|
|
15266
|
+
description: "Resources that reference the source resource",
|
|
15267
|
+
items: {
|
|
15268
|
+
type: "object",
|
|
15269
|
+
properties: {
|
|
15270
|
+
resourceId: {
|
|
15271
|
+
type: "string"
|
|
15272
|
+
},
|
|
15273
|
+
resourceName: {
|
|
15274
|
+
type: "string"
|
|
15275
|
+
}
|
|
15276
|
+
},
|
|
15277
|
+
required: [
|
|
15278
|
+
"resourceId",
|
|
15279
|
+
"resourceName"
|
|
15280
|
+
]
|
|
15281
|
+
}
|
|
15282
|
+
},
|
|
15283
|
+
siblingEntityTypes: {
|
|
15284
|
+
type: "array",
|
|
15285
|
+
items: {
|
|
15286
|
+
type: "string"
|
|
15287
|
+
},
|
|
15288
|
+
description: "Entity types from other annotations on the same resource"
|
|
15289
|
+
},
|
|
15290
|
+
entityTypeFrequencies: {
|
|
15291
|
+
type: "object",
|
|
15292
|
+
description: "Global frequency counts for entity types (for IDF-like weighting)",
|
|
15293
|
+
additionalProperties: {
|
|
15294
|
+
type: "integer"
|
|
15295
|
+
}
|
|
15296
|
+
},
|
|
15297
|
+
inferredRelationshipSummary: {
|
|
15298
|
+
type: "string",
|
|
15299
|
+
description: "LLM-generated summary of the annotation's relationships in the knowledge graph"
|
|
15300
|
+
}
|
|
15301
|
+
}
|
|
15207
15302
|
}
|
|
15208
15303
|
},
|
|
15209
15304
|
required: [
|
|
15210
|
-
"
|
|
15305
|
+
"annotation",
|
|
15306
|
+
"sourceResource"
|
|
15211
15307
|
]
|
|
15212
15308
|
}
|
|
15213
15309
|
}
|
|
@@ -16096,6 +16192,235 @@ adminRouter.get("/api/admin/oauth/config", async (c) => {
|
|
|
16096
16192
|
};
|
|
16097
16193
|
return c.json(response, 200);
|
|
16098
16194
|
});
|
|
16195
|
+
var adminMiddleware2 = /* @__PURE__ */ __name(async (c, next) => {
|
|
16196
|
+
const user = c.get("user");
|
|
16197
|
+
if (!user || !user.isAdmin) {
|
|
16198
|
+
return c.json({
|
|
16199
|
+
error: "Forbidden: Admin access required"
|
|
16200
|
+
}, 403);
|
|
16201
|
+
}
|
|
16202
|
+
return next();
|
|
16203
|
+
}, "adminMiddleware");
|
|
16204
|
+
var moderatorMiddleware = /* @__PURE__ */ __name(async (c, next) => {
|
|
16205
|
+
const user = c.get("user");
|
|
16206
|
+
if (!user || !user.isModerator && !user.isAdmin) {
|
|
16207
|
+
return c.json({
|
|
16208
|
+
error: "Forbidden: Moderator or Admin access required"
|
|
16209
|
+
}, 403);
|
|
16210
|
+
}
|
|
16211
|
+
return next();
|
|
16212
|
+
}, "moderatorMiddleware");
|
|
16213
|
+
var exchangeRouter = new Hono();
|
|
16214
|
+
exchangeRouter.use("/api/admin/exchange/*", authMiddleware, adminMiddleware2);
|
|
16215
|
+
exchangeRouter.use("/api/moderate/exchange/*", authMiddleware, moderatorMiddleware);
|
|
16216
|
+
exchangeRouter.post("/api/admin/exchange/backup", async (c) => {
|
|
16217
|
+
const mm = c.get("makeMeaning");
|
|
16218
|
+
const config2 = c.get("config");
|
|
16219
|
+
const sourceUrl = config2.services?.backend?.publicURL ?? "http://localhost:4000";
|
|
16220
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
16221
|
+
const filename = `semiont-backup-${timestamp}.tar.gz`;
|
|
16222
|
+
let controller;
|
|
16223
|
+
const webReadable = new ReadableStream({
|
|
16224
|
+
start(ctrl) {
|
|
16225
|
+
controller = ctrl;
|
|
16226
|
+
}
|
|
16227
|
+
});
|
|
16228
|
+
const nodeWritable = new Writable({
|
|
16229
|
+
write(chunk, _encoding, callback) {
|
|
16230
|
+
controller.enqueue(chunk);
|
|
16231
|
+
callback();
|
|
16232
|
+
},
|
|
16233
|
+
final(callback) {
|
|
16234
|
+
controller.close();
|
|
16235
|
+
callback();
|
|
16236
|
+
}
|
|
16237
|
+
});
|
|
16238
|
+
(async () => {
|
|
16239
|
+
try {
|
|
16240
|
+
await exportBackup({
|
|
16241
|
+
eventStore: mm.kb.eventStore,
|
|
16242
|
+
content: mm.kb.content,
|
|
16243
|
+
sourceUrl
|
|
16244
|
+
}, nodeWritable);
|
|
16245
|
+
} catch (err) {
|
|
16246
|
+
controller.error(err);
|
|
16247
|
+
}
|
|
16248
|
+
})();
|
|
16249
|
+
return new Response(webReadable, {
|
|
16250
|
+
headers: {
|
|
16251
|
+
"Content-Type": "application/gzip",
|
|
16252
|
+
"Content-Disposition": `attachment; filename="${filename}"`,
|
|
16253
|
+
"Cache-Control": "no-cache"
|
|
16254
|
+
}
|
|
16255
|
+
});
|
|
16256
|
+
});
|
|
16257
|
+
exchangeRouter.post("/api/admin/exchange/restore", async (c) => {
|
|
16258
|
+
const formData = await c.req.formData();
|
|
16259
|
+
const file = formData.get("file");
|
|
16260
|
+
if (!file) {
|
|
16261
|
+
return c.json({
|
|
16262
|
+
error: "No file provided"
|
|
16263
|
+
}, 400);
|
|
16264
|
+
}
|
|
16265
|
+
const eventBus2 = c.get("eventBus");
|
|
16266
|
+
const buffer = Buffer.from(await file.arrayBuffer());
|
|
16267
|
+
const encoder = new TextEncoder();
|
|
16268
|
+
const stream = new ReadableStream({
|
|
16269
|
+
async start(controller) {
|
|
16270
|
+
const send = /* @__PURE__ */ __name((data) => {
|
|
16271
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
|
|
16272
|
+
|
|
16273
|
+
`));
|
|
16274
|
+
}, "send");
|
|
16275
|
+
try {
|
|
16276
|
+
const input = new Readable({
|
|
16277
|
+
read() {
|
|
16278
|
+
}
|
|
16279
|
+
});
|
|
16280
|
+
input.push(buffer);
|
|
16281
|
+
input.push(null);
|
|
16282
|
+
send({
|
|
16283
|
+
phase: "started",
|
|
16284
|
+
message: "Restoring backup..."
|
|
16285
|
+
});
|
|
16286
|
+
const result = await importBackup(input, {
|
|
16287
|
+
eventBus: eventBus2
|
|
16288
|
+
});
|
|
16289
|
+
send({
|
|
16290
|
+
phase: "complete",
|
|
16291
|
+
result: {
|
|
16292
|
+
stats: result.stats,
|
|
16293
|
+
hashChainValid: result.hashChainValid
|
|
16294
|
+
}
|
|
16295
|
+
});
|
|
16296
|
+
} catch (err) {
|
|
16297
|
+
send({
|
|
16298
|
+
phase: "error",
|
|
16299
|
+
message: err instanceof Error ? err.message : String(err)
|
|
16300
|
+
});
|
|
16301
|
+
} finally {
|
|
16302
|
+
controller.close();
|
|
16303
|
+
}
|
|
16304
|
+
}
|
|
16305
|
+
});
|
|
16306
|
+
return new Response(stream, {
|
|
16307
|
+
headers: {
|
|
16308
|
+
"Content-Type": "text/event-stream",
|
|
16309
|
+
"Cache-Control": "no-cache",
|
|
16310
|
+
"Connection": "keep-alive"
|
|
16311
|
+
}
|
|
16312
|
+
});
|
|
16313
|
+
});
|
|
16314
|
+
exchangeRouter.post("/api/moderate/exchange/export", async (c) => {
|
|
16315
|
+
const mm = c.get("makeMeaning");
|
|
16316
|
+
const config2 = c.get("config");
|
|
16317
|
+
const sourceUrl = config2.services?.backend?.publicURL ?? "http://localhost:4000";
|
|
16318
|
+
const includeArchived = c.req.query("includeArchived") === "true";
|
|
16319
|
+
const entityTypes = await readEntityTypesProjection({
|
|
16320
|
+
services: {
|
|
16321
|
+
filesystem: config2.services?.filesystem
|
|
16322
|
+
},
|
|
16323
|
+
_metadata: config2._metadata
|
|
16324
|
+
});
|
|
16325
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
16326
|
+
const filename = `semiont-export-${timestamp}.tar.gz`;
|
|
16327
|
+
let controller;
|
|
16328
|
+
const webReadable = new ReadableStream({
|
|
16329
|
+
start(ctrl) {
|
|
16330
|
+
controller = ctrl;
|
|
16331
|
+
}
|
|
16332
|
+
});
|
|
16333
|
+
const nodeWritable = new Writable({
|
|
16334
|
+
write(chunk, _encoding, callback) {
|
|
16335
|
+
controller.enqueue(chunk);
|
|
16336
|
+
callback();
|
|
16337
|
+
},
|
|
16338
|
+
final(callback) {
|
|
16339
|
+
controller.close();
|
|
16340
|
+
callback();
|
|
16341
|
+
}
|
|
16342
|
+
});
|
|
16343
|
+
(async () => {
|
|
16344
|
+
try {
|
|
16345
|
+
await exportLinkedData({
|
|
16346
|
+
views: mm.kb.views,
|
|
16347
|
+
content: mm.kb.content,
|
|
16348
|
+
sourceUrl,
|
|
16349
|
+
entityTypes,
|
|
16350
|
+
includeArchived
|
|
16351
|
+
}, nodeWritable);
|
|
16352
|
+
} catch (err) {
|
|
16353
|
+
controller.error(err);
|
|
16354
|
+
}
|
|
16355
|
+
})();
|
|
16356
|
+
return new Response(webReadable, {
|
|
16357
|
+
headers: {
|
|
16358
|
+
"Content-Type": "application/gzip",
|
|
16359
|
+
"Content-Disposition": `attachment; filename="${filename}"`,
|
|
16360
|
+
"Cache-Control": "no-cache"
|
|
16361
|
+
}
|
|
16362
|
+
});
|
|
16363
|
+
});
|
|
16364
|
+
exchangeRouter.post("/api/moderate/exchange/import", async (c) => {
|
|
16365
|
+
const formData = await c.req.formData();
|
|
16366
|
+
const file = formData.get("file");
|
|
16367
|
+
if (!file) {
|
|
16368
|
+
return c.json({
|
|
16369
|
+
error: "No file provided"
|
|
16370
|
+
}, 400);
|
|
16371
|
+
}
|
|
16372
|
+
const eventBus2 = c.get("eventBus");
|
|
16373
|
+
const user = c.get("user");
|
|
16374
|
+
const buffer = Buffer.from(await file.arrayBuffer());
|
|
16375
|
+
const encoder = new TextEncoder();
|
|
16376
|
+
const stream = new ReadableStream({
|
|
16377
|
+
async start(controller) {
|
|
16378
|
+
const send = /* @__PURE__ */ __name((data) => {
|
|
16379
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
|
|
16380
|
+
|
|
16381
|
+
`));
|
|
16382
|
+
}, "send");
|
|
16383
|
+
try {
|
|
16384
|
+
const input = new Readable({
|
|
16385
|
+
read() {
|
|
16386
|
+
}
|
|
16387
|
+
});
|
|
16388
|
+
input.push(buffer);
|
|
16389
|
+
input.push(null);
|
|
16390
|
+
send({
|
|
16391
|
+
phase: "started",
|
|
16392
|
+
message: "Importing linked data..."
|
|
16393
|
+
});
|
|
16394
|
+
const result = await importLinkedData(input, {
|
|
16395
|
+
eventBus: eventBus2,
|
|
16396
|
+
userId: userId(user.id)
|
|
16397
|
+
});
|
|
16398
|
+
send({
|
|
16399
|
+
phase: "complete",
|
|
16400
|
+
result: {
|
|
16401
|
+
resourcesCreated: result.resourcesCreated,
|
|
16402
|
+
annotationsCreated: result.annotationsCreated,
|
|
16403
|
+
entityTypesAdded: result.entityTypesAdded
|
|
16404
|
+
}
|
|
16405
|
+
});
|
|
16406
|
+
} catch (err) {
|
|
16407
|
+
send({
|
|
16408
|
+
phase: "error",
|
|
16409
|
+
message: err instanceof Error ? err.message : String(err)
|
|
16410
|
+
});
|
|
16411
|
+
} finally {
|
|
16412
|
+
controller.close();
|
|
16413
|
+
}
|
|
16414
|
+
}
|
|
16415
|
+
});
|
|
16416
|
+
return new Response(stream, {
|
|
16417
|
+
headers: {
|
|
16418
|
+
"Content-Type": "text/event-stream",
|
|
16419
|
+
"Cache-Control": "no-cache",
|
|
16420
|
+
"Connection": "keep-alive"
|
|
16421
|
+
}
|
|
16422
|
+
});
|
|
16423
|
+
});
|
|
16099
16424
|
function createResourceRouter() {
|
|
16100
16425
|
const router = new Hono();
|
|
16101
16426
|
router.use("/api/resources/*", authMiddleware);
|
|
@@ -16129,7 +16454,7 @@ function registerCreateResource(router) {
|
|
|
16129
16454
|
const arrayBuffer = await file.arrayBuffer();
|
|
16130
16455
|
const contentBuffer = Buffer.from(arrayBuffer);
|
|
16131
16456
|
const eventBus2 = c.get("eventBus");
|
|
16132
|
-
const
|
|
16457
|
+
const resourceId20 = await ResourceOperations.createResource({
|
|
16133
16458
|
name,
|
|
16134
16459
|
content: contentBuffer,
|
|
16135
16460
|
format,
|
|
@@ -16138,7 +16463,7 @@ function registerCreateResource(router) {
|
|
|
16138
16463
|
creationMethod: creationMethod || void 0
|
|
16139
16464
|
}, userId(user.id), eventBus2);
|
|
16140
16465
|
return c.json({
|
|
16141
|
-
resourceId:
|
|
16466
|
+
resourceId: resourceId20
|
|
16142
16467
|
}, 202);
|
|
16143
16468
|
});
|
|
16144
16469
|
}
|
|
@@ -16188,7 +16513,7 @@ function getBodySource(body) {
|
|
|
16188
16513
|
const itemType = item.type;
|
|
16189
16514
|
const itemSource = item.source;
|
|
16190
16515
|
if (itemType === "SpecificResource" && typeof itemSource === "string") {
|
|
16191
|
-
return
|
|
16516
|
+
return itemSource;
|
|
16192
16517
|
}
|
|
16193
16518
|
}
|
|
16194
16519
|
}
|
|
@@ -16198,7 +16523,7 @@ function getBodySource(body) {
|
|
|
16198
16523
|
const bodyType = body.type;
|
|
16199
16524
|
const bodySource = body.source;
|
|
16200
16525
|
if (bodyType === "SpecificResource" && typeof bodySource === "string") {
|
|
16201
|
-
return
|
|
16526
|
+
return bodySource;
|
|
16202
16527
|
}
|
|
16203
16528
|
}
|
|
16204
16529
|
return null;
|
|
@@ -17868,7 +18193,6 @@ function registerGetResourceLLMContext(router) {
|
|
|
17868
18193
|
router.get("/resources/:id/llm-context", async (c) => {
|
|
17869
18194
|
const { id } = c.req.param();
|
|
17870
18195
|
const query = c.req.query();
|
|
17871
|
-
const config2 = c.get("config");
|
|
17872
18196
|
const eventBus2 = c.get("eventBus");
|
|
17873
18197
|
const depth = query.depth ? Number(query.depth) : 2;
|
|
17874
18198
|
const maxResources = query.maxResources ? Number(query.maxResources) : 10;
|
|
@@ -17884,9 +18208,8 @@ function registerGetResourceLLMContext(router) {
|
|
|
17884
18208
|
message: 'Query parameter "maxResources" must be between 1 and 20'
|
|
17885
18209
|
});
|
|
17886
18210
|
}
|
|
17887
|
-
const resourceUri3 = `${config2.services.backend.publicURL}/resources/${id}`;
|
|
17888
18211
|
eventBus2.get("gather:resource-requested").next({
|
|
17889
|
-
|
|
18212
|
+
resourceId: resourceId(id),
|
|
17890
18213
|
options: {
|
|
17891
18214
|
depth,
|
|
17892
18215
|
maxResources,
|
|
@@ -17895,10 +18218,10 @@ function registerGetResourceLLMContext(router) {
|
|
|
17895
18218
|
}
|
|
17896
18219
|
});
|
|
17897
18220
|
try {
|
|
17898
|
-
const result = await (0, import_rxjs2.firstValueFrom)((0, import_rxjs2.merge)(eventBus2.get("gather:resource-complete").pipe((0, import_operators2.filter)((e) => e.
|
|
18221
|
+
const result = await (0, import_rxjs2.firstValueFrom)((0, import_rxjs2.merge)(eventBus2.get("gather:resource-complete").pipe((0, import_operators2.filter)((e) => e.resourceId === id), (0, import_operators2.map)((e) => ({
|
|
17899
18222
|
ok: true,
|
|
17900
18223
|
context: e.context
|
|
17901
|
-
}))), eventBus2.get("gather:resource-failed").pipe((0, import_operators2.filter)((e) => e.
|
|
18224
|
+
}))), eventBus2.get("gather:resource-failed").pipe((0, import_operators2.filter)((e) => e.resourceId === id), (0, import_operators2.map)((e) => ({
|
|
17902
18225
|
ok: false,
|
|
17903
18226
|
error: e.error
|
|
17904
18227
|
})))).pipe((0, import_operators2.take)(1), (0, import_operators2.timeout)(3e4)));
|
|
@@ -17932,7 +18255,6 @@ function registerGetAnnotationLLMContext(router) {
|
|
|
17932
18255
|
router.get("/resources/:resourceId/annotations/:annotationId/llm-context", async (c) => {
|
|
17933
18256
|
const { resourceId: resourceIdParam, annotationId: annotationIdParam } = c.req.param();
|
|
17934
18257
|
const query = c.req.query();
|
|
17935
|
-
const config2 = c.get("config");
|
|
17936
18258
|
const eventBus2 = c.get("eventBus");
|
|
17937
18259
|
const includeSourceContext = query.includeSourceContext === "false" ? false : true;
|
|
17938
18260
|
const includeTargetContext = query.includeTargetContext === "false" ? false : true;
|
|
@@ -17942,11 +18264,9 @@ function registerGetAnnotationLLMContext(router) {
|
|
|
17942
18264
|
message: 'Query parameter "contextWindow" must be between 100 and 5000'
|
|
17943
18265
|
});
|
|
17944
18266
|
}
|
|
17945
|
-
const fullAnnotationUri = `${config2.services.backend.publicURL}/annotations/${annotationIdParam}`;
|
|
17946
|
-
const resourceUri3 = `${config2.services.backend.publicURL}/resources/${resourceIdParam}`;
|
|
17947
18267
|
eventBus2.get("gather:requested").next({
|
|
17948
|
-
|
|
17949
|
-
|
|
18268
|
+
annotationId: annotationId(annotationIdParam),
|
|
18269
|
+
resourceId: resourceId(resourceIdParam),
|
|
17950
18270
|
options: {
|
|
17951
18271
|
includeSourceContext,
|
|
17952
18272
|
includeTargetContext,
|
|
@@ -17954,10 +18274,10 @@ function registerGetAnnotationLLMContext(router) {
|
|
|
17954
18274
|
}
|
|
17955
18275
|
});
|
|
17956
18276
|
try {
|
|
17957
|
-
const result = await (0, import_rxjs3.firstValueFrom)((0, import_rxjs3.merge)(eventBus2.get("gather:complete").pipe((0, import_operators3.filter)((e) => e.
|
|
18277
|
+
const result = await (0, import_rxjs3.firstValueFrom)((0, import_rxjs3.merge)(eventBus2.get("gather:complete").pipe((0, import_operators3.filter)((e) => e.annotationId === annotationIdParam), (0, import_operators3.map)((e) => ({
|
|
17958
18278
|
ok: true,
|
|
17959
18279
|
response: e.response
|
|
17960
|
-
}))), eventBus2.get("gather:failed").pipe((0, import_operators3.filter)((e) => e.
|
|
18280
|
+
}))), eventBus2.get("gather:failed").pipe((0, import_operators3.filter)((e) => e.annotationId === annotationIdParam), (0, import_operators3.map)((e) => ({
|
|
17961
18281
|
ok: false,
|
|
17962
18282
|
error: e.error
|
|
17963
18283
|
})))).pipe((0, import_operators3.take)(1), (0, import_operators3.timeout)(3e4)));
|
|
@@ -18017,6 +18337,129 @@ function registerGetReferencedBy(router) {
|
|
|
18017
18337
|
});
|
|
18018
18338
|
}
|
|
18019
18339
|
__name(registerGetReferencedBy, "registerGetReferencedBy");
|
|
18340
|
+
init_logger();
|
|
18341
|
+
function registerBindSearchStream(router) {
|
|
18342
|
+
router.post("/resources/:id/bind-search-stream", async (c) => {
|
|
18343
|
+
const { id } = c.req.param();
|
|
18344
|
+
const logger2 = getLogger().child({
|
|
18345
|
+
component: "bind-search-stream",
|
|
18346
|
+
resourceId: id
|
|
18347
|
+
});
|
|
18348
|
+
const user = c.get("user");
|
|
18349
|
+
if (!user) {
|
|
18350
|
+
throw new HTTPException(401, {
|
|
18351
|
+
message: "Authentication required"
|
|
18352
|
+
});
|
|
18353
|
+
}
|
|
18354
|
+
const body = await c.req.json();
|
|
18355
|
+
const { referenceId, context, limit, useSemanticScoring } = body;
|
|
18356
|
+
if (!referenceId || !context) {
|
|
18357
|
+
throw new HTTPException(400, {
|
|
18358
|
+
message: "referenceId and context are required"
|
|
18359
|
+
});
|
|
18360
|
+
}
|
|
18361
|
+
const eventBus2 = c.get("eventBus");
|
|
18362
|
+
const { kb } = c.get("makeMeaning");
|
|
18363
|
+
const resource = await ResourceContext.getResourceMetadata(resourceId(id), kb);
|
|
18364
|
+
if (!resource) {
|
|
18365
|
+
throw new HTTPException(404, {
|
|
18366
|
+
message: "Resource not found"
|
|
18367
|
+
});
|
|
18368
|
+
}
|
|
18369
|
+
const correlationId = crypto.randomUUID();
|
|
18370
|
+
logger2.info("Starting bind search stream", {
|
|
18371
|
+
referenceId,
|
|
18372
|
+
correlationId
|
|
18373
|
+
});
|
|
18374
|
+
c.header("X-Accel-Buffering", "no");
|
|
18375
|
+
c.header("Cache-Control", "no-cache, no-transform");
|
|
18376
|
+
return streamSSE(c, async (stream) => {
|
|
18377
|
+
let isStreamClosed = false;
|
|
18378
|
+
const subscriptions = [];
|
|
18379
|
+
let closeStreamCallback = null;
|
|
18380
|
+
const streamPromise = new Promise((resolve2) => {
|
|
18381
|
+
closeStreamCallback = resolve2;
|
|
18382
|
+
});
|
|
18383
|
+
const cleanup = /* @__PURE__ */ __name(() => {
|
|
18384
|
+
if (isStreamClosed) return;
|
|
18385
|
+
isStreamClosed = true;
|
|
18386
|
+
subscriptions.forEach((sub) => sub.unsubscribe());
|
|
18387
|
+
if (closeStreamCallback) closeStreamCallback();
|
|
18388
|
+
}, "cleanup");
|
|
18389
|
+
try {
|
|
18390
|
+
subscriptions.push(eventBus2.get("bind:search-results").subscribe(async (event) => {
|
|
18391
|
+
if (event.correlationId !== correlationId) return;
|
|
18392
|
+
if (isStreamClosed) return;
|
|
18393
|
+
logger2.info("Bind search completed", {
|
|
18394
|
+
referenceId,
|
|
18395
|
+
resultCount: event.results.length
|
|
18396
|
+
});
|
|
18397
|
+
try {
|
|
18398
|
+
await writeTypedSSE(stream, {
|
|
18399
|
+
data: JSON.stringify({
|
|
18400
|
+
referenceId: event.referenceId,
|
|
18401
|
+
results: event.results
|
|
18402
|
+
}),
|
|
18403
|
+
event: "bind:search-results",
|
|
18404
|
+
id: String(Date.now())
|
|
18405
|
+
});
|
|
18406
|
+
} catch (error) {
|
|
18407
|
+
logger2.warn("Client disconnected during results");
|
|
18408
|
+
}
|
|
18409
|
+
cleanup();
|
|
18410
|
+
}));
|
|
18411
|
+
subscriptions.push(eventBus2.get("bind:search-failed").subscribe(async (event) => {
|
|
18412
|
+
if (event.correlationId !== correlationId) return;
|
|
18413
|
+
if (isStreamClosed) return;
|
|
18414
|
+
logger2.error("Bind search failed", {
|
|
18415
|
+
referenceId,
|
|
18416
|
+
error: event.error
|
|
18417
|
+
});
|
|
18418
|
+
try {
|
|
18419
|
+
await writeTypedSSE(stream, {
|
|
18420
|
+
data: JSON.stringify({
|
|
18421
|
+
referenceId: event.referenceId,
|
|
18422
|
+
error: event.error.message
|
|
18423
|
+
}),
|
|
18424
|
+
event: "bind:search-failed",
|
|
18425
|
+
id: String(Date.now())
|
|
18426
|
+
});
|
|
18427
|
+
} catch (error) {
|
|
18428
|
+
logger2.warn("Client disconnected during error");
|
|
18429
|
+
}
|
|
18430
|
+
cleanup();
|
|
18431
|
+
}));
|
|
18432
|
+
eventBus2.get("bind:search-requested").next({
|
|
18433
|
+
correlationId,
|
|
18434
|
+
referenceId,
|
|
18435
|
+
context,
|
|
18436
|
+
limit,
|
|
18437
|
+
useSemanticScoring
|
|
18438
|
+
});
|
|
18439
|
+
c.req.raw.signal.addEventListener("abort", () => {
|
|
18440
|
+
logger2.info("Client disconnected from bind search stream");
|
|
18441
|
+
cleanup();
|
|
18442
|
+
});
|
|
18443
|
+
} catch (error) {
|
|
18444
|
+
try {
|
|
18445
|
+
await writeTypedSSE(stream, {
|
|
18446
|
+
data: JSON.stringify({
|
|
18447
|
+
referenceId,
|
|
18448
|
+
error: error instanceof Error ? error.message : "Search failed"
|
|
18449
|
+
}),
|
|
18450
|
+
event: "bind:search-failed",
|
|
18451
|
+
id: String(Date.now())
|
|
18452
|
+
});
|
|
18453
|
+
} catch (sseError) {
|
|
18454
|
+
logger2.warn("Could not send error to client");
|
|
18455
|
+
}
|
|
18456
|
+
cleanup();
|
|
18457
|
+
}
|
|
18458
|
+
return streamPromise;
|
|
18459
|
+
});
|
|
18460
|
+
});
|
|
18461
|
+
}
|
|
18462
|
+
__name(registerBindSearchStream, "registerBindSearchStream");
|
|
18020
18463
|
function registerTokenRoutes(router) {
|
|
18021
18464
|
router.get("/api/clone-tokens/:token", async (c) => {
|
|
18022
18465
|
const { token } = c.req.param();
|
|
@@ -18195,18 +18638,17 @@ init_logger();
|
|
|
18195
18638
|
function registerGetEventStream(router) {
|
|
18196
18639
|
router.get("/resources/:id/events/stream", async (c) => {
|
|
18197
18640
|
const { id } = c.req.param();
|
|
18198
|
-
const config2 = c.get("config");
|
|
18199
18641
|
const logger2 = getLogger().child({
|
|
18200
18642
|
component: "events-stream",
|
|
18201
18643
|
resourceId: id
|
|
18202
18644
|
});
|
|
18203
|
-
const
|
|
18645
|
+
const rId = resourceId(id);
|
|
18204
18646
|
logger2.info("Client connecting to resource events stream", {
|
|
18205
|
-
|
|
18647
|
+
resourceId: rId
|
|
18206
18648
|
});
|
|
18207
18649
|
const { eventStore } = c.get("makeMeaning");
|
|
18208
18650
|
const query = new EventQuery(eventStore.log.storage);
|
|
18209
|
-
const events = await query.getResourceEvents(
|
|
18651
|
+
const events = await query.getResourceEvents(rId);
|
|
18210
18652
|
if (events.length === 0) {
|
|
18211
18653
|
logger2.warn("Resource not found - no events exist");
|
|
18212
18654
|
throw new HTTPException(404, {
|
|
@@ -18249,11 +18691,11 @@ function registerGetEventStream(router) {
|
|
|
18249
18691
|
}
|
|
18250
18692
|
}, "cleanup");
|
|
18251
18693
|
const streamId = `${id.substring(0, 16)}...${Math.random().toString(36).substring(7)}`;
|
|
18252
|
-
logger2.info("Subscribing to events for resource
|
|
18694
|
+
logger2.info("Subscribing to events for resource", {
|
|
18253
18695
|
streamId,
|
|
18254
|
-
|
|
18696
|
+
resourceId: rId
|
|
18255
18697
|
});
|
|
18256
|
-
subscription = eventStore.bus.subscriptions.subscribe(
|
|
18698
|
+
subscription = eventStore.bus.subscriptions.subscribe(rId, async (storedEvent) => {
|
|
18257
18699
|
if (isStreamClosed) {
|
|
18258
18700
|
logger2.info("Stream already closed, ignoring event", {
|
|
18259
18701
|
streamId,
|
|
@@ -18284,14 +18726,7 @@ function registerGetEventStream(router) {
|
|
|
18284
18726
|
});
|
|
18285
18727
|
let jsonData;
|
|
18286
18728
|
try {
|
|
18287
|
-
const startStringify = Date.now();
|
|
18288
18729
|
jsonData = JSON.stringify(eventData);
|
|
18289
|
-
const stringifyTime = Date.now() - startStringify;
|
|
18290
|
-
logger2.info("JSON.stringify completed", {
|
|
18291
|
-
streamId,
|
|
18292
|
-
time: stringifyTime,
|
|
18293
|
-
size: jsonData.length
|
|
18294
|
-
});
|
|
18295
18730
|
} catch (stringifyError) {
|
|
18296
18731
|
logger2.error("JSON.stringify FAILED", {
|
|
18297
18732
|
streamId,
|
|
@@ -18299,23 +18734,14 @@ function registerGetEventStream(router) {
|
|
|
18299
18734
|
});
|
|
18300
18735
|
throw stringifyError;
|
|
18301
18736
|
}
|
|
18302
|
-
if (storedEvent.event.type === "annotation.body.updated") {
|
|
18303
|
-
logger2.info("annotation.body.updated payload", {
|
|
18304
|
-
streamId,
|
|
18305
|
-
payload: storedEvent.event.payload
|
|
18306
|
-
});
|
|
18307
|
-
}
|
|
18308
|
-
const startWrite = Date.now();
|
|
18309
18737
|
await stream.writeSSE({
|
|
18310
18738
|
data: jsonData,
|
|
18311
18739
|
event: storedEvent.event.type,
|
|
18312
18740
|
id: storedEvent.metadata.sequenceNumber.toString()
|
|
18313
18741
|
});
|
|
18314
|
-
const writeTime = Date.now() - startWrite;
|
|
18315
18742
|
logger2.info("Successfully wrote event to SSE stream", {
|
|
18316
18743
|
streamId,
|
|
18317
|
-
eventType: storedEvent.event.type
|
|
18318
|
-
time: writeTime
|
|
18744
|
+
eventType: storedEvent.event.type
|
|
18319
18745
|
});
|
|
18320
18746
|
} catch (error) {
|
|
18321
18747
|
logger2.error("Error writing event to SSE stream", {
|
|
@@ -18355,16 +18781,9 @@ function registerCreateAnnotation(router) {
|
|
|
18355
18781
|
const { id } = c.req.param();
|
|
18356
18782
|
const request = c.get("validatedBody");
|
|
18357
18783
|
const user = c.get("user");
|
|
18358
|
-
const config2 = c.get("config");
|
|
18359
|
-
const backendUrl = config2.services.backend?.publicURL;
|
|
18360
|
-
if (!backendUrl) {
|
|
18361
|
-
throw new HTTPException(500, {
|
|
18362
|
-
message: "Backend publicURL not configured"
|
|
18363
|
-
});
|
|
18364
|
-
}
|
|
18365
18784
|
let annotation;
|
|
18366
18785
|
try {
|
|
18367
|
-
({ annotation } = assembleAnnotation(request, userToAgent(user)
|
|
18786
|
+
({ annotation } = assembleAnnotation(request, userToAgent(user)));
|
|
18368
18787
|
} catch (error) {
|
|
18369
18788
|
if (error instanceof Error) {
|
|
18370
18789
|
throw new HTTPException(400, {
|
|
@@ -18459,7 +18878,6 @@ function registerYieldResourceStream(router, jobQueue) {
|
|
|
18459
18878
|
body
|
|
18460
18879
|
});
|
|
18461
18880
|
const user = c.get("user");
|
|
18462
|
-
const config2 = c.get("config");
|
|
18463
18881
|
if (!user) {
|
|
18464
18882
|
throw new HTTPException(401, {
|
|
18465
18883
|
message: "Authentication required"
|
|
@@ -18476,14 +18894,13 @@ function registerYieldResourceStream(router, jobQueue) {
|
|
|
18476
18894
|
count: linkingAnnotations.length,
|
|
18477
18895
|
ids: linkingAnnotations.map((a) => a.id)
|
|
18478
18896
|
});
|
|
18479
|
-
|
|
18480
|
-
|
|
18481
|
-
expectedAnnotationUri
|
|
18897
|
+
logger2.info("Looking for annotation", {
|
|
18898
|
+
annotationId: annotationIdParam
|
|
18482
18899
|
});
|
|
18483
|
-
const reference = projection.annotations.find((a) => a.id ===
|
|
18900
|
+
const reference = projection.annotations.find((a) => a.id === annotationIdParam && a.motivation === "linking");
|
|
18484
18901
|
if (!reference) {
|
|
18485
18902
|
logger2.warn("Annotation not found", {
|
|
18486
|
-
|
|
18903
|
+
expectedId: annotationIdParam,
|
|
18487
18904
|
availableIds: projection.annotations.map((a) => a.id)
|
|
18488
18905
|
});
|
|
18489
18906
|
throw new HTTPException(404, {
|
|
@@ -18665,14 +19082,14 @@ function registerYieldResourceStream(router, jobQueue) {
|
|
|
18665
19082
|
__name(registerYieldResourceStream, "registerYieldResourceStream");
|
|
18666
19083
|
function registerGetAnnotationHistory(router) {
|
|
18667
19084
|
router.get("/resources/:resourceId/annotations/:annotationId/history", async (c) => {
|
|
18668
|
-
const { resourceId:
|
|
19085
|
+
const { resourceId: resourceId20, annotationId: annotationId6 } = c.req.param();
|
|
18669
19086
|
const eventBus2 = c.get("eventBus");
|
|
18670
19087
|
const correlationId = crypto.randomUUID();
|
|
18671
19088
|
try {
|
|
18672
19089
|
const response = await eventBusRequest(eventBus2, "browse:annotation-history-requested", {
|
|
18673
19090
|
correlationId,
|
|
18674
|
-
resourceId: resourceId(
|
|
18675
|
-
annotationId: annotationId(
|
|
19091
|
+
resourceId: resourceId(resourceId20),
|
|
19092
|
+
annotationId: annotationId(annotationId6)
|
|
18676
19093
|
}, "browse:annotation-history-result", "browse:annotation-history-failed");
|
|
18677
19094
|
return c.json(response);
|
|
18678
19095
|
} catch (error) {
|
|
@@ -18713,6 +19130,7 @@ function createResourcesRouter(jobQueue) {
|
|
|
18713
19130
|
registerGetResourceLLMContext(resourcesRouter2);
|
|
18714
19131
|
registerGetAnnotationLLMContext(resourcesRouter2);
|
|
18715
19132
|
registerGetReferencedBy(resourcesRouter2);
|
|
19133
|
+
registerBindSearchStream(resourcesRouter2);
|
|
18716
19134
|
registerGetResourceAnnotations(resourcesRouter2);
|
|
18717
19135
|
registerCreateAnnotation(resourcesRouter2);
|
|
18718
19136
|
registerGetAnnotation(resourcesRouter2);
|
|
@@ -18739,39 +19157,30 @@ function registerGetAnnotationUri(router) {
|
|
|
18739
19157
|
const { id } = c.req.param();
|
|
18740
19158
|
const query = c.req.query();
|
|
18741
19159
|
const { kb } = c.get("makeMeaning");
|
|
18742
|
-
const
|
|
18743
|
-
if (!
|
|
19160
|
+
const resourceIdParam = query.resourceId;
|
|
19161
|
+
if (!resourceIdParam) {
|
|
18744
19162
|
throw new HTTPException(400, {
|
|
18745
19163
|
message: "resourceId query parameter is required"
|
|
18746
19164
|
});
|
|
18747
19165
|
}
|
|
18748
|
-
let extractedResourceId;
|
|
18749
|
-
try {
|
|
18750
|
-
extractedResourceId = resourceUriOrId.includes("://") ? uriToResourceId(resourceUriOrId) : resourceUriOrId;
|
|
18751
|
-
} catch (error) {
|
|
18752
|
-
throw new HTTPException(400, {
|
|
18753
|
-
message: "Invalid resourceId parameter"
|
|
18754
|
-
});
|
|
18755
|
-
}
|
|
18756
19166
|
if (prefersHtml(c)) {
|
|
18757
19167
|
const frontendUrl = getFrontendUrl();
|
|
18758
19168
|
const normalizedBase = frontendUrl.endsWith("/") ? frontendUrl.slice(0, -1) : frontendUrl;
|
|
18759
|
-
const redirectUrl = `${normalizedBase}/annotations/${id}?resourceId=${
|
|
19169
|
+
const redirectUrl = `${normalizedBase}/annotations/${id}?resourceId=${resourceIdParam}`;
|
|
18760
19170
|
return c.redirect(redirectUrl, 302);
|
|
18761
19171
|
}
|
|
18762
|
-
const projection = await AnnotationContext.getResourceAnnotations(resourceId(
|
|
19172
|
+
const projection = await AnnotationContext.getResourceAnnotations(resourceId(resourceIdParam), kb);
|
|
18763
19173
|
const annotation = projection.annotations.find((a) => a.id === id);
|
|
18764
19174
|
if (!annotation) {
|
|
18765
19175
|
throw new HTTPException(404, {
|
|
18766
19176
|
message: "Annotation not found in resource"
|
|
18767
19177
|
});
|
|
18768
19178
|
}
|
|
18769
|
-
const resource = await ResourceContext.getResourceMetadata(resourceId(
|
|
19179
|
+
const resource = await ResourceContext.getResourceMetadata(resourceId(resourceIdParam), kb);
|
|
18770
19180
|
let resolvedResource = null;
|
|
18771
19181
|
const bodySource = getBodySource(annotation.body);
|
|
18772
19182
|
if (annotation.motivation === "linking" && bodySource) {
|
|
18773
|
-
|
|
18774
|
-
resolvedResource = await ResourceContext.getResourceMetadata(resourceId(bodyDocId), kb);
|
|
19183
|
+
resolvedResource = await ResourceContext.getResourceMetadata(resourceId(bodySource), kb);
|
|
18775
19184
|
}
|
|
18776
19185
|
const response = {
|
|
18777
19186
|
annotation,
|
|
@@ -18788,8 +19197,8 @@ operationsRouter.get("/api/annotations/:id/context", async (c) => {
|
|
|
18788
19197
|
const { id } = c.req.param();
|
|
18789
19198
|
const query = c.req.query();
|
|
18790
19199
|
const { kb } = c.get("makeMeaning");
|
|
18791
|
-
const
|
|
18792
|
-
if (!
|
|
19200
|
+
const resourceId20 = query.resourceId;
|
|
19201
|
+
if (!resourceId20) {
|
|
18793
19202
|
throw new HTTPException(400, {
|
|
18794
19203
|
message: "resourceId query parameter is required"
|
|
18795
19204
|
});
|
|
@@ -18807,7 +19216,7 @@ operationsRouter.get("/api/annotations/:id/context", async (c) => {
|
|
|
18807
19216
|
});
|
|
18808
19217
|
}
|
|
18809
19218
|
try {
|
|
18810
|
-
const response = await AnnotationContext.getAnnotationContext(annotationId(id), resourceId(
|
|
19219
|
+
const response = await AnnotationContext.getAnnotationContext(annotationId(id), resourceId(resourceId20), contextBefore, contextAfter, kb);
|
|
18811
19220
|
return c.json(response);
|
|
18812
19221
|
} catch (error) {
|
|
18813
19222
|
if (error instanceof Error && error.message === "Annotation not found") {
|
|
@@ -18837,14 +19246,14 @@ operationsRouter.get("/api/annotations/:id/summary", async (c) => {
|
|
|
18837
19246
|
const { id } = c.req.param();
|
|
18838
19247
|
const query = c.req.query();
|
|
18839
19248
|
const { kb, inferenceClient } = c.get("makeMeaning");
|
|
18840
|
-
const
|
|
18841
|
-
if (!
|
|
19249
|
+
const resourceId20 = query.resourceId;
|
|
19250
|
+
if (!resourceId20) {
|
|
18842
19251
|
throw new HTTPException(400, {
|
|
18843
19252
|
message: "resourceId query parameter is required"
|
|
18844
19253
|
});
|
|
18845
19254
|
}
|
|
18846
19255
|
try {
|
|
18847
|
-
const response = await AnnotationContext.generateAnnotationSummary(annotationId(id), resourceId(
|
|
19256
|
+
const response = await AnnotationContext.generateAnnotationSummary(annotationId(id), resourceId(resourceId20), kb, inferenceClient);
|
|
18848
19257
|
return c.json(response);
|
|
18849
19258
|
} catch (error) {
|
|
18850
19259
|
if (error instanceof Error && error.message === "Annotation not found") {
|
|
@@ -19205,6 +19614,7 @@ app.route("/", healthRouter);
|
|
|
19205
19614
|
app.route("/", authRouter);
|
|
19206
19615
|
app.route("/", statusRouter);
|
|
19207
19616
|
app.route("/", adminRouter);
|
|
19617
|
+
app.route("/", exchangeRouter);
|
|
19208
19618
|
var resourcesRouter = createResourcesRouter(makeMeaning.jobQueue);
|
|
19209
19619
|
app.route("/", resourcesRouter);
|
|
19210
19620
|
app.route("/", annotationsRouter);
|
|
@@ -19271,8 +19681,7 @@ app.all("/api/*", (c) => {
|
|
|
19271
19681
|
}, 404);
|
|
19272
19682
|
});
|
|
19273
19683
|
var port = backendService.port || 4e3;
|
|
19274
|
-
|
|
19275
|
-
if (nodeEnv !== "test") {
|
|
19684
|
+
if (config.env?.NODE_ENV !== "test") {
|
|
19276
19685
|
serve({
|
|
19277
19686
|
fetch: app.fetch,
|
|
19278
19687
|
port,
|
|
@@ -19280,7 +19689,7 @@ if (nodeEnv !== "test") {
|
|
|
19280
19689
|
}, async (info) => {
|
|
19281
19690
|
logger.info("Semiont Backend ready", {
|
|
19282
19691
|
url: `http://localhost:${info.port}/api`,
|
|
19283
|
-
environment:
|
|
19692
|
+
environment: config.env?.NODE_ENV ?? "development"
|
|
19284
19693
|
});
|
|
19285
19694
|
try {
|
|
19286
19695
|
const { JWTService: JWTService2 } = await Promise.resolve().then(() => (init_jwt(), jwt_exports));
|