@semiont/backend 0.2.46 → 0.3.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/dist/index.js +507 -101
- 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,9 +15215,91 @@ var openapi_default = {
|
|
|
15204
15215
|
description: "Entity types associated with the annotation"
|
|
15205
15216
|
}
|
|
15206
15217
|
}
|
|
15218
|
+
},
|
|
15219
|
+
graphContext: {
|
|
15220
|
+
type: "object",
|
|
15221
|
+
description: "Graph-derived context from the knowledge base",
|
|
15222
|
+
properties: {
|
|
15223
|
+
connections: {
|
|
15224
|
+
type: "array",
|
|
15225
|
+
description: "Resources connected to the source resource via annotations",
|
|
15226
|
+
items: {
|
|
15227
|
+
type: "object",
|
|
15228
|
+
properties: {
|
|
15229
|
+
resourceId: {
|
|
15230
|
+
type: "string",
|
|
15231
|
+
description: "ID of the connected resource"
|
|
15232
|
+
},
|
|
15233
|
+
resourceName: {
|
|
15234
|
+
type: "string",
|
|
15235
|
+
description: "Name of the connected resource"
|
|
15236
|
+
},
|
|
15237
|
+
entityTypes: {
|
|
15238
|
+
type: "array",
|
|
15239
|
+
items: {
|
|
15240
|
+
type: "string"
|
|
15241
|
+
},
|
|
15242
|
+
description: "Entity types on the connected resource"
|
|
15243
|
+
},
|
|
15244
|
+
bidirectional: {
|
|
15245
|
+
type: "boolean",
|
|
15246
|
+
description: "Whether the connection goes both ways"
|
|
15247
|
+
}
|
|
15248
|
+
},
|
|
15249
|
+
required: [
|
|
15250
|
+
"resourceId",
|
|
15251
|
+
"resourceName",
|
|
15252
|
+
"bidirectional"
|
|
15253
|
+
]
|
|
15254
|
+
}
|
|
15255
|
+
},
|
|
15256
|
+
citedByCount: {
|
|
15257
|
+
type: "integer",
|
|
15258
|
+
description: "Number of other resources that reference the source resource"
|
|
15259
|
+
},
|
|
15260
|
+
citedBy: {
|
|
15261
|
+
type: "array",
|
|
15262
|
+
description: "Resources that reference the source resource",
|
|
15263
|
+
items: {
|
|
15264
|
+
type: "object",
|
|
15265
|
+
properties: {
|
|
15266
|
+
resourceId: {
|
|
15267
|
+
type: "string"
|
|
15268
|
+
},
|
|
15269
|
+
resourceName: {
|
|
15270
|
+
type: "string"
|
|
15271
|
+
}
|
|
15272
|
+
},
|
|
15273
|
+
required: [
|
|
15274
|
+
"resourceId",
|
|
15275
|
+
"resourceName"
|
|
15276
|
+
]
|
|
15277
|
+
}
|
|
15278
|
+
},
|
|
15279
|
+
siblingEntityTypes: {
|
|
15280
|
+
type: "array",
|
|
15281
|
+
items: {
|
|
15282
|
+
type: "string"
|
|
15283
|
+
},
|
|
15284
|
+
description: "Entity types from other annotations on the same resource"
|
|
15285
|
+
},
|
|
15286
|
+
entityTypeFrequencies: {
|
|
15287
|
+
type: "object",
|
|
15288
|
+
description: "Global frequency counts for entity types (for IDF-like weighting)",
|
|
15289
|
+
additionalProperties: {
|
|
15290
|
+
type: "integer"
|
|
15291
|
+
}
|
|
15292
|
+
},
|
|
15293
|
+
inferredRelationshipSummary: {
|
|
15294
|
+
type: "string",
|
|
15295
|
+
description: "LLM-generated summary of the annotation's relationships in the knowledge graph"
|
|
15296
|
+
}
|
|
15297
|
+
}
|
|
15207
15298
|
}
|
|
15208
15299
|
},
|
|
15209
15300
|
required: [
|
|
15301
|
+
"annotation",
|
|
15302
|
+
"sourceResource",
|
|
15210
15303
|
"sourceContext"
|
|
15211
15304
|
]
|
|
15212
15305
|
}
|
|
@@ -16096,6 +16189,235 @@ adminRouter.get("/api/admin/oauth/config", async (c) => {
|
|
|
16096
16189
|
};
|
|
16097
16190
|
return c.json(response, 200);
|
|
16098
16191
|
});
|
|
16192
|
+
var adminMiddleware2 = /* @__PURE__ */ __name(async (c, next) => {
|
|
16193
|
+
const user = c.get("user");
|
|
16194
|
+
if (!user || !user.isAdmin) {
|
|
16195
|
+
return c.json({
|
|
16196
|
+
error: "Forbidden: Admin access required"
|
|
16197
|
+
}, 403);
|
|
16198
|
+
}
|
|
16199
|
+
return next();
|
|
16200
|
+
}, "adminMiddleware");
|
|
16201
|
+
var moderatorMiddleware = /* @__PURE__ */ __name(async (c, next) => {
|
|
16202
|
+
const user = c.get("user");
|
|
16203
|
+
if (!user || !user.isModerator && !user.isAdmin) {
|
|
16204
|
+
return c.json({
|
|
16205
|
+
error: "Forbidden: Moderator or Admin access required"
|
|
16206
|
+
}, 403);
|
|
16207
|
+
}
|
|
16208
|
+
return next();
|
|
16209
|
+
}, "moderatorMiddleware");
|
|
16210
|
+
var exchangeRouter = new Hono();
|
|
16211
|
+
exchangeRouter.use("/api/admin/exchange/*", authMiddleware, adminMiddleware2);
|
|
16212
|
+
exchangeRouter.use("/api/moderate/exchange/*", authMiddleware, moderatorMiddleware);
|
|
16213
|
+
exchangeRouter.post("/api/admin/exchange/backup", async (c) => {
|
|
16214
|
+
const mm = c.get("makeMeaning");
|
|
16215
|
+
const config2 = c.get("config");
|
|
16216
|
+
const sourceUrl = config2.services?.backend?.publicURL ?? "http://localhost:4000";
|
|
16217
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
16218
|
+
const filename = `semiont-backup-${timestamp}.tar.gz`;
|
|
16219
|
+
let controller;
|
|
16220
|
+
const webReadable = new ReadableStream({
|
|
16221
|
+
start(ctrl) {
|
|
16222
|
+
controller = ctrl;
|
|
16223
|
+
}
|
|
16224
|
+
});
|
|
16225
|
+
const nodeWritable = new Writable({
|
|
16226
|
+
write(chunk, _encoding, callback) {
|
|
16227
|
+
controller.enqueue(chunk);
|
|
16228
|
+
callback();
|
|
16229
|
+
},
|
|
16230
|
+
final(callback) {
|
|
16231
|
+
controller.close();
|
|
16232
|
+
callback();
|
|
16233
|
+
}
|
|
16234
|
+
});
|
|
16235
|
+
(async () => {
|
|
16236
|
+
try {
|
|
16237
|
+
await exportBackup({
|
|
16238
|
+
eventStore: mm.kb.eventStore,
|
|
16239
|
+
content: mm.kb.content,
|
|
16240
|
+
sourceUrl
|
|
16241
|
+
}, nodeWritable);
|
|
16242
|
+
} catch (err) {
|
|
16243
|
+
controller.error(err);
|
|
16244
|
+
}
|
|
16245
|
+
})();
|
|
16246
|
+
return new Response(webReadable, {
|
|
16247
|
+
headers: {
|
|
16248
|
+
"Content-Type": "application/gzip",
|
|
16249
|
+
"Content-Disposition": `attachment; filename="${filename}"`,
|
|
16250
|
+
"Cache-Control": "no-cache"
|
|
16251
|
+
}
|
|
16252
|
+
});
|
|
16253
|
+
});
|
|
16254
|
+
exchangeRouter.post("/api/admin/exchange/restore", async (c) => {
|
|
16255
|
+
const formData = await c.req.formData();
|
|
16256
|
+
const file = formData.get("file");
|
|
16257
|
+
if (!file) {
|
|
16258
|
+
return c.json({
|
|
16259
|
+
error: "No file provided"
|
|
16260
|
+
}, 400);
|
|
16261
|
+
}
|
|
16262
|
+
const eventBus2 = c.get("eventBus");
|
|
16263
|
+
const buffer = Buffer.from(await file.arrayBuffer());
|
|
16264
|
+
const encoder = new TextEncoder();
|
|
16265
|
+
const stream = new ReadableStream({
|
|
16266
|
+
async start(controller) {
|
|
16267
|
+
const send = /* @__PURE__ */ __name((data) => {
|
|
16268
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
|
|
16269
|
+
|
|
16270
|
+
`));
|
|
16271
|
+
}, "send");
|
|
16272
|
+
try {
|
|
16273
|
+
const input = new Readable({
|
|
16274
|
+
read() {
|
|
16275
|
+
}
|
|
16276
|
+
});
|
|
16277
|
+
input.push(buffer);
|
|
16278
|
+
input.push(null);
|
|
16279
|
+
send({
|
|
16280
|
+
phase: "started",
|
|
16281
|
+
message: "Restoring backup..."
|
|
16282
|
+
});
|
|
16283
|
+
const result = await importBackup(input, {
|
|
16284
|
+
eventBus: eventBus2
|
|
16285
|
+
});
|
|
16286
|
+
send({
|
|
16287
|
+
phase: "complete",
|
|
16288
|
+
result: {
|
|
16289
|
+
stats: result.stats,
|
|
16290
|
+
hashChainValid: result.hashChainValid
|
|
16291
|
+
}
|
|
16292
|
+
});
|
|
16293
|
+
} catch (err) {
|
|
16294
|
+
send({
|
|
16295
|
+
phase: "error",
|
|
16296
|
+
message: err instanceof Error ? err.message : String(err)
|
|
16297
|
+
});
|
|
16298
|
+
} finally {
|
|
16299
|
+
controller.close();
|
|
16300
|
+
}
|
|
16301
|
+
}
|
|
16302
|
+
});
|
|
16303
|
+
return new Response(stream, {
|
|
16304
|
+
headers: {
|
|
16305
|
+
"Content-Type": "text/event-stream",
|
|
16306
|
+
"Cache-Control": "no-cache",
|
|
16307
|
+
"Connection": "keep-alive"
|
|
16308
|
+
}
|
|
16309
|
+
});
|
|
16310
|
+
});
|
|
16311
|
+
exchangeRouter.post("/api/moderate/exchange/export", async (c) => {
|
|
16312
|
+
const mm = c.get("makeMeaning");
|
|
16313
|
+
const config2 = c.get("config");
|
|
16314
|
+
const sourceUrl = config2.services?.backend?.publicURL ?? "http://localhost:4000";
|
|
16315
|
+
const includeArchived = c.req.query("includeArchived") === "true";
|
|
16316
|
+
const entityTypes = await readEntityTypesProjection({
|
|
16317
|
+
services: {
|
|
16318
|
+
filesystem: config2.services?.filesystem
|
|
16319
|
+
},
|
|
16320
|
+
_metadata: config2._metadata
|
|
16321
|
+
});
|
|
16322
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
16323
|
+
const filename = `semiont-export-${timestamp}.tar.gz`;
|
|
16324
|
+
let controller;
|
|
16325
|
+
const webReadable = new ReadableStream({
|
|
16326
|
+
start(ctrl) {
|
|
16327
|
+
controller = ctrl;
|
|
16328
|
+
}
|
|
16329
|
+
});
|
|
16330
|
+
const nodeWritable = new Writable({
|
|
16331
|
+
write(chunk, _encoding, callback) {
|
|
16332
|
+
controller.enqueue(chunk);
|
|
16333
|
+
callback();
|
|
16334
|
+
},
|
|
16335
|
+
final(callback) {
|
|
16336
|
+
controller.close();
|
|
16337
|
+
callback();
|
|
16338
|
+
}
|
|
16339
|
+
});
|
|
16340
|
+
(async () => {
|
|
16341
|
+
try {
|
|
16342
|
+
await exportLinkedData({
|
|
16343
|
+
views: mm.kb.views,
|
|
16344
|
+
content: mm.kb.content,
|
|
16345
|
+
sourceUrl,
|
|
16346
|
+
entityTypes,
|
|
16347
|
+
includeArchived
|
|
16348
|
+
}, nodeWritable);
|
|
16349
|
+
} catch (err) {
|
|
16350
|
+
controller.error(err);
|
|
16351
|
+
}
|
|
16352
|
+
})();
|
|
16353
|
+
return new Response(webReadable, {
|
|
16354
|
+
headers: {
|
|
16355
|
+
"Content-Type": "application/gzip",
|
|
16356
|
+
"Content-Disposition": `attachment; filename="${filename}"`,
|
|
16357
|
+
"Cache-Control": "no-cache"
|
|
16358
|
+
}
|
|
16359
|
+
});
|
|
16360
|
+
});
|
|
16361
|
+
exchangeRouter.post("/api/moderate/exchange/import", async (c) => {
|
|
16362
|
+
const formData = await c.req.formData();
|
|
16363
|
+
const file = formData.get("file");
|
|
16364
|
+
if (!file) {
|
|
16365
|
+
return c.json({
|
|
16366
|
+
error: "No file provided"
|
|
16367
|
+
}, 400);
|
|
16368
|
+
}
|
|
16369
|
+
const eventBus2 = c.get("eventBus");
|
|
16370
|
+
const user = c.get("user");
|
|
16371
|
+
const buffer = Buffer.from(await file.arrayBuffer());
|
|
16372
|
+
const encoder = new TextEncoder();
|
|
16373
|
+
const stream = new ReadableStream({
|
|
16374
|
+
async start(controller) {
|
|
16375
|
+
const send = /* @__PURE__ */ __name((data) => {
|
|
16376
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
|
|
16377
|
+
|
|
16378
|
+
`));
|
|
16379
|
+
}, "send");
|
|
16380
|
+
try {
|
|
16381
|
+
const input = new Readable({
|
|
16382
|
+
read() {
|
|
16383
|
+
}
|
|
16384
|
+
});
|
|
16385
|
+
input.push(buffer);
|
|
16386
|
+
input.push(null);
|
|
16387
|
+
send({
|
|
16388
|
+
phase: "started",
|
|
16389
|
+
message: "Importing linked data..."
|
|
16390
|
+
});
|
|
16391
|
+
const result = await importLinkedData(input, {
|
|
16392
|
+
eventBus: eventBus2,
|
|
16393
|
+
userId: userId(user.id)
|
|
16394
|
+
});
|
|
16395
|
+
send({
|
|
16396
|
+
phase: "complete",
|
|
16397
|
+
result: {
|
|
16398
|
+
resourcesCreated: result.resourcesCreated,
|
|
16399
|
+
annotationsCreated: result.annotationsCreated,
|
|
16400
|
+
entityTypesAdded: result.entityTypesAdded
|
|
16401
|
+
}
|
|
16402
|
+
});
|
|
16403
|
+
} catch (err) {
|
|
16404
|
+
send({
|
|
16405
|
+
phase: "error",
|
|
16406
|
+
message: err instanceof Error ? err.message : String(err)
|
|
16407
|
+
});
|
|
16408
|
+
} finally {
|
|
16409
|
+
controller.close();
|
|
16410
|
+
}
|
|
16411
|
+
}
|
|
16412
|
+
});
|
|
16413
|
+
return new Response(stream, {
|
|
16414
|
+
headers: {
|
|
16415
|
+
"Content-Type": "text/event-stream",
|
|
16416
|
+
"Cache-Control": "no-cache",
|
|
16417
|
+
"Connection": "keep-alive"
|
|
16418
|
+
}
|
|
16419
|
+
});
|
|
16420
|
+
});
|
|
16099
16421
|
function createResourceRouter() {
|
|
16100
16422
|
const router = new Hono();
|
|
16101
16423
|
router.use("/api/resources/*", authMiddleware);
|
|
@@ -16129,7 +16451,7 @@ function registerCreateResource(router) {
|
|
|
16129
16451
|
const arrayBuffer = await file.arrayBuffer();
|
|
16130
16452
|
const contentBuffer = Buffer.from(arrayBuffer);
|
|
16131
16453
|
const eventBus2 = c.get("eventBus");
|
|
16132
|
-
const
|
|
16454
|
+
const resourceId20 = await ResourceOperations.createResource({
|
|
16133
16455
|
name,
|
|
16134
16456
|
content: contentBuffer,
|
|
16135
16457
|
format,
|
|
@@ -16138,7 +16460,7 @@ function registerCreateResource(router) {
|
|
|
16138
16460
|
creationMethod: creationMethod || void 0
|
|
16139
16461
|
}, userId(user.id), eventBus2);
|
|
16140
16462
|
return c.json({
|
|
16141
|
-
resourceId:
|
|
16463
|
+
resourceId: resourceId20
|
|
16142
16464
|
}, 202);
|
|
16143
16465
|
});
|
|
16144
16466
|
}
|
|
@@ -16188,7 +16510,7 @@ function getBodySource(body) {
|
|
|
16188
16510
|
const itemType = item.type;
|
|
16189
16511
|
const itemSource = item.source;
|
|
16190
16512
|
if (itemType === "SpecificResource" && typeof itemSource === "string") {
|
|
16191
|
-
return
|
|
16513
|
+
return itemSource;
|
|
16192
16514
|
}
|
|
16193
16515
|
}
|
|
16194
16516
|
}
|
|
@@ -16198,7 +16520,7 @@ function getBodySource(body) {
|
|
|
16198
16520
|
const bodyType = body.type;
|
|
16199
16521
|
const bodySource = body.source;
|
|
16200
16522
|
if (bodyType === "SpecificResource" && typeof bodySource === "string") {
|
|
16201
|
-
return
|
|
16523
|
+
return bodySource;
|
|
16202
16524
|
}
|
|
16203
16525
|
}
|
|
16204
16526
|
return null;
|
|
@@ -17868,7 +18190,6 @@ function registerGetResourceLLMContext(router) {
|
|
|
17868
18190
|
router.get("/resources/:id/llm-context", async (c) => {
|
|
17869
18191
|
const { id } = c.req.param();
|
|
17870
18192
|
const query = c.req.query();
|
|
17871
|
-
const config2 = c.get("config");
|
|
17872
18193
|
const eventBus2 = c.get("eventBus");
|
|
17873
18194
|
const depth = query.depth ? Number(query.depth) : 2;
|
|
17874
18195
|
const maxResources = query.maxResources ? Number(query.maxResources) : 10;
|
|
@@ -17884,9 +18205,8 @@ function registerGetResourceLLMContext(router) {
|
|
|
17884
18205
|
message: 'Query parameter "maxResources" must be between 1 and 20'
|
|
17885
18206
|
});
|
|
17886
18207
|
}
|
|
17887
|
-
const resourceUri3 = `${config2.services.backend.publicURL}/resources/${id}`;
|
|
17888
18208
|
eventBus2.get("gather:resource-requested").next({
|
|
17889
|
-
|
|
18209
|
+
resourceId: resourceId(id),
|
|
17890
18210
|
options: {
|
|
17891
18211
|
depth,
|
|
17892
18212
|
maxResources,
|
|
@@ -17895,10 +18215,10 @@ function registerGetResourceLLMContext(router) {
|
|
|
17895
18215
|
}
|
|
17896
18216
|
});
|
|
17897
18217
|
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.
|
|
18218
|
+
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
18219
|
ok: true,
|
|
17900
18220
|
context: e.context
|
|
17901
|
-
}))), eventBus2.get("gather:resource-failed").pipe((0, import_operators2.filter)((e) => e.
|
|
18221
|
+
}))), eventBus2.get("gather:resource-failed").pipe((0, import_operators2.filter)((e) => e.resourceId === id), (0, import_operators2.map)((e) => ({
|
|
17902
18222
|
ok: false,
|
|
17903
18223
|
error: e.error
|
|
17904
18224
|
})))).pipe((0, import_operators2.take)(1), (0, import_operators2.timeout)(3e4)));
|
|
@@ -17932,7 +18252,6 @@ function registerGetAnnotationLLMContext(router) {
|
|
|
17932
18252
|
router.get("/resources/:resourceId/annotations/:annotationId/llm-context", async (c) => {
|
|
17933
18253
|
const { resourceId: resourceIdParam, annotationId: annotationIdParam } = c.req.param();
|
|
17934
18254
|
const query = c.req.query();
|
|
17935
|
-
const config2 = c.get("config");
|
|
17936
18255
|
const eventBus2 = c.get("eventBus");
|
|
17937
18256
|
const includeSourceContext = query.includeSourceContext === "false" ? false : true;
|
|
17938
18257
|
const includeTargetContext = query.includeTargetContext === "false" ? false : true;
|
|
@@ -17942,11 +18261,9 @@ function registerGetAnnotationLLMContext(router) {
|
|
|
17942
18261
|
message: 'Query parameter "contextWindow" must be between 100 and 5000'
|
|
17943
18262
|
});
|
|
17944
18263
|
}
|
|
17945
|
-
const fullAnnotationUri = `${config2.services.backend.publicURL}/annotations/${annotationIdParam}`;
|
|
17946
|
-
const resourceUri3 = `${config2.services.backend.publicURL}/resources/${resourceIdParam}`;
|
|
17947
18264
|
eventBus2.get("gather:requested").next({
|
|
17948
|
-
|
|
17949
|
-
|
|
18265
|
+
annotationId: annotationId(annotationIdParam),
|
|
18266
|
+
resourceId: resourceId(resourceIdParam),
|
|
17950
18267
|
options: {
|
|
17951
18268
|
includeSourceContext,
|
|
17952
18269
|
includeTargetContext,
|
|
@@ -17954,10 +18271,10 @@ function registerGetAnnotationLLMContext(router) {
|
|
|
17954
18271
|
}
|
|
17955
18272
|
});
|
|
17956
18273
|
try {
|
|
17957
|
-
const result = await (0, import_rxjs3.firstValueFrom)((0, import_rxjs3.merge)(eventBus2.get("gather:complete").pipe((0, import_operators3.filter)((e) => e.
|
|
18274
|
+
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
18275
|
ok: true,
|
|
17959
18276
|
response: e.response
|
|
17960
|
-
}))), eventBus2.get("gather:failed").pipe((0, import_operators3.filter)((e) => e.
|
|
18277
|
+
}))), eventBus2.get("gather:failed").pipe((0, import_operators3.filter)((e) => e.annotationId === annotationIdParam), (0, import_operators3.map)((e) => ({
|
|
17961
18278
|
ok: false,
|
|
17962
18279
|
error: e.error
|
|
17963
18280
|
})))).pipe((0, import_operators3.take)(1), (0, import_operators3.timeout)(3e4)));
|
|
@@ -18017,6 +18334,129 @@ function registerGetReferencedBy(router) {
|
|
|
18017
18334
|
});
|
|
18018
18335
|
}
|
|
18019
18336
|
__name(registerGetReferencedBy, "registerGetReferencedBy");
|
|
18337
|
+
init_logger();
|
|
18338
|
+
function registerBindSearchStream(router) {
|
|
18339
|
+
router.post("/resources/:id/bind-search-stream", async (c) => {
|
|
18340
|
+
const { id } = c.req.param();
|
|
18341
|
+
const logger2 = getLogger().child({
|
|
18342
|
+
component: "bind-search-stream",
|
|
18343
|
+
resourceId: id
|
|
18344
|
+
});
|
|
18345
|
+
const user = c.get("user");
|
|
18346
|
+
if (!user) {
|
|
18347
|
+
throw new HTTPException(401, {
|
|
18348
|
+
message: "Authentication required"
|
|
18349
|
+
});
|
|
18350
|
+
}
|
|
18351
|
+
const body = await c.req.json();
|
|
18352
|
+
const { referenceId, context, limit, useSemanticScoring } = body;
|
|
18353
|
+
if (!referenceId || !context) {
|
|
18354
|
+
throw new HTTPException(400, {
|
|
18355
|
+
message: "referenceId and context are required"
|
|
18356
|
+
});
|
|
18357
|
+
}
|
|
18358
|
+
const eventBus2 = c.get("eventBus");
|
|
18359
|
+
const { kb } = c.get("makeMeaning");
|
|
18360
|
+
const resource = await ResourceContext.getResourceMetadata(resourceId(id), kb);
|
|
18361
|
+
if (!resource) {
|
|
18362
|
+
throw new HTTPException(404, {
|
|
18363
|
+
message: "Resource not found"
|
|
18364
|
+
});
|
|
18365
|
+
}
|
|
18366
|
+
const correlationId = crypto.randomUUID();
|
|
18367
|
+
logger2.info("Starting bind search stream", {
|
|
18368
|
+
referenceId,
|
|
18369
|
+
correlationId
|
|
18370
|
+
});
|
|
18371
|
+
c.header("X-Accel-Buffering", "no");
|
|
18372
|
+
c.header("Cache-Control", "no-cache, no-transform");
|
|
18373
|
+
return streamSSE(c, async (stream) => {
|
|
18374
|
+
let isStreamClosed = false;
|
|
18375
|
+
const subscriptions = [];
|
|
18376
|
+
let closeStreamCallback = null;
|
|
18377
|
+
const streamPromise = new Promise((resolve2) => {
|
|
18378
|
+
closeStreamCallback = resolve2;
|
|
18379
|
+
});
|
|
18380
|
+
const cleanup = /* @__PURE__ */ __name(() => {
|
|
18381
|
+
if (isStreamClosed) return;
|
|
18382
|
+
isStreamClosed = true;
|
|
18383
|
+
subscriptions.forEach((sub) => sub.unsubscribe());
|
|
18384
|
+
if (closeStreamCallback) closeStreamCallback();
|
|
18385
|
+
}, "cleanup");
|
|
18386
|
+
try {
|
|
18387
|
+
subscriptions.push(eventBus2.get("bind:search-results").subscribe(async (event) => {
|
|
18388
|
+
if (event.correlationId !== correlationId) return;
|
|
18389
|
+
if (isStreamClosed) return;
|
|
18390
|
+
logger2.info("Bind search completed", {
|
|
18391
|
+
referenceId,
|
|
18392
|
+
resultCount: event.results.length
|
|
18393
|
+
});
|
|
18394
|
+
try {
|
|
18395
|
+
await writeTypedSSE(stream, {
|
|
18396
|
+
data: JSON.stringify({
|
|
18397
|
+
referenceId: event.referenceId,
|
|
18398
|
+
results: event.results
|
|
18399
|
+
}),
|
|
18400
|
+
event: "bind:search-results",
|
|
18401
|
+
id: String(Date.now())
|
|
18402
|
+
});
|
|
18403
|
+
} catch (error) {
|
|
18404
|
+
logger2.warn("Client disconnected during results");
|
|
18405
|
+
}
|
|
18406
|
+
cleanup();
|
|
18407
|
+
}));
|
|
18408
|
+
subscriptions.push(eventBus2.get("bind:search-failed").subscribe(async (event) => {
|
|
18409
|
+
if (event.correlationId !== correlationId) return;
|
|
18410
|
+
if (isStreamClosed) return;
|
|
18411
|
+
logger2.error("Bind search failed", {
|
|
18412
|
+
referenceId,
|
|
18413
|
+
error: event.error
|
|
18414
|
+
});
|
|
18415
|
+
try {
|
|
18416
|
+
await writeTypedSSE(stream, {
|
|
18417
|
+
data: JSON.stringify({
|
|
18418
|
+
referenceId: event.referenceId,
|
|
18419
|
+
error: event.error.message
|
|
18420
|
+
}),
|
|
18421
|
+
event: "bind:search-failed",
|
|
18422
|
+
id: String(Date.now())
|
|
18423
|
+
});
|
|
18424
|
+
} catch (error) {
|
|
18425
|
+
logger2.warn("Client disconnected during error");
|
|
18426
|
+
}
|
|
18427
|
+
cleanup();
|
|
18428
|
+
}));
|
|
18429
|
+
eventBus2.get("bind:search-requested").next({
|
|
18430
|
+
correlationId,
|
|
18431
|
+
referenceId,
|
|
18432
|
+
context,
|
|
18433
|
+
limit,
|
|
18434
|
+
useSemanticScoring
|
|
18435
|
+
});
|
|
18436
|
+
c.req.raw.signal.addEventListener("abort", () => {
|
|
18437
|
+
logger2.info("Client disconnected from bind search stream");
|
|
18438
|
+
cleanup();
|
|
18439
|
+
});
|
|
18440
|
+
} catch (error) {
|
|
18441
|
+
try {
|
|
18442
|
+
await writeTypedSSE(stream, {
|
|
18443
|
+
data: JSON.stringify({
|
|
18444
|
+
referenceId,
|
|
18445
|
+
error: error instanceof Error ? error.message : "Search failed"
|
|
18446
|
+
}),
|
|
18447
|
+
event: "bind:search-failed",
|
|
18448
|
+
id: String(Date.now())
|
|
18449
|
+
});
|
|
18450
|
+
} catch (sseError) {
|
|
18451
|
+
logger2.warn("Could not send error to client");
|
|
18452
|
+
}
|
|
18453
|
+
cleanup();
|
|
18454
|
+
}
|
|
18455
|
+
return streamPromise;
|
|
18456
|
+
});
|
|
18457
|
+
});
|
|
18458
|
+
}
|
|
18459
|
+
__name(registerBindSearchStream, "registerBindSearchStream");
|
|
18020
18460
|
function registerTokenRoutes(router) {
|
|
18021
18461
|
router.get("/api/clone-tokens/:token", async (c) => {
|
|
18022
18462
|
const { token } = c.req.param();
|
|
@@ -18195,18 +18635,17 @@ init_logger();
|
|
|
18195
18635
|
function registerGetEventStream(router) {
|
|
18196
18636
|
router.get("/resources/:id/events/stream", async (c) => {
|
|
18197
18637
|
const { id } = c.req.param();
|
|
18198
|
-
const config2 = c.get("config");
|
|
18199
18638
|
const logger2 = getLogger().child({
|
|
18200
18639
|
component: "events-stream",
|
|
18201
18640
|
resourceId: id
|
|
18202
18641
|
});
|
|
18203
|
-
const
|
|
18642
|
+
const rId = resourceId(id);
|
|
18204
18643
|
logger2.info("Client connecting to resource events stream", {
|
|
18205
|
-
|
|
18644
|
+
resourceId: rId
|
|
18206
18645
|
});
|
|
18207
18646
|
const { eventStore } = c.get("makeMeaning");
|
|
18208
18647
|
const query = new EventQuery(eventStore.log.storage);
|
|
18209
|
-
const events = await query.getResourceEvents(
|
|
18648
|
+
const events = await query.getResourceEvents(rId);
|
|
18210
18649
|
if (events.length === 0) {
|
|
18211
18650
|
logger2.warn("Resource not found - no events exist");
|
|
18212
18651
|
throw new HTTPException(404, {
|
|
@@ -18249,11 +18688,11 @@ function registerGetEventStream(router) {
|
|
|
18249
18688
|
}
|
|
18250
18689
|
}, "cleanup");
|
|
18251
18690
|
const streamId = `${id.substring(0, 16)}...${Math.random().toString(36).substring(7)}`;
|
|
18252
|
-
logger2.info("Subscribing to events for resource
|
|
18691
|
+
logger2.info("Subscribing to events for resource", {
|
|
18253
18692
|
streamId,
|
|
18254
|
-
|
|
18693
|
+
resourceId: rId
|
|
18255
18694
|
});
|
|
18256
|
-
subscription = eventStore.bus.subscriptions.subscribe(
|
|
18695
|
+
subscription = eventStore.bus.subscriptions.subscribe(rId, async (storedEvent) => {
|
|
18257
18696
|
if (isStreamClosed) {
|
|
18258
18697
|
logger2.info("Stream already closed, ignoring event", {
|
|
18259
18698
|
streamId,
|
|
@@ -18284,14 +18723,7 @@ function registerGetEventStream(router) {
|
|
|
18284
18723
|
});
|
|
18285
18724
|
let jsonData;
|
|
18286
18725
|
try {
|
|
18287
|
-
const startStringify = Date.now();
|
|
18288
18726
|
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
18727
|
} catch (stringifyError) {
|
|
18296
18728
|
logger2.error("JSON.stringify FAILED", {
|
|
18297
18729
|
streamId,
|
|
@@ -18299,23 +18731,14 @@ function registerGetEventStream(router) {
|
|
|
18299
18731
|
});
|
|
18300
18732
|
throw stringifyError;
|
|
18301
18733
|
}
|
|
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
18734
|
await stream.writeSSE({
|
|
18310
18735
|
data: jsonData,
|
|
18311
18736
|
event: storedEvent.event.type,
|
|
18312
18737
|
id: storedEvent.metadata.sequenceNumber.toString()
|
|
18313
18738
|
});
|
|
18314
|
-
const writeTime = Date.now() - startWrite;
|
|
18315
18739
|
logger2.info("Successfully wrote event to SSE stream", {
|
|
18316
18740
|
streamId,
|
|
18317
|
-
eventType: storedEvent.event.type
|
|
18318
|
-
time: writeTime
|
|
18741
|
+
eventType: storedEvent.event.type
|
|
18319
18742
|
});
|
|
18320
18743
|
} catch (error) {
|
|
18321
18744
|
logger2.error("Error writing event to SSE stream", {
|
|
@@ -18355,16 +18778,9 @@ function registerCreateAnnotation(router) {
|
|
|
18355
18778
|
const { id } = c.req.param();
|
|
18356
18779
|
const request = c.get("validatedBody");
|
|
18357
18780
|
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
18781
|
let annotation;
|
|
18366
18782
|
try {
|
|
18367
|
-
({ annotation } = assembleAnnotation(request, userToAgent(user)
|
|
18783
|
+
({ annotation } = assembleAnnotation(request, userToAgent(user)));
|
|
18368
18784
|
} catch (error) {
|
|
18369
18785
|
if (error instanceof Error) {
|
|
18370
18786
|
throw new HTTPException(400, {
|
|
@@ -18459,7 +18875,6 @@ function registerYieldResourceStream(router, jobQueue) {
|
|
|
18459
18875
|
body
|
|
18460
18876
|
});
|
|
18461
18877
|
const user = c.get("user");
|
|
18462
|
-
const config2 = c.get("config");
|
|
18463
18878
|
if (!user) {
|
|
18464
18879
|
throw new HTTPException(401, {
|
|
18465
18880
|
message: "Authentication required"
|
|
@@ -18476,14 +18891,13 @@ function registerYieldResourceStream(router, jobQueue) {
|
|
|
18476
18891
|
count: linkingAnnotations.length,
|
|
18477
18892
|
ids: linkingAnnotations.map((a) => a.id)
|
|
18478
18893
|
});
|
|
18479
|
-
|
|
18480
|
-
|
|
18481
|
-
expectedAnnotationUri
|
|
18894
|
+
logger2.info("Looking for annotation", {
|
|
18895
|
+
annotationId: annotationIdParam
|
|
18482
18896
|
});
|
|
18483
|
-
const reference = projection.annotations.find((a) => a.id ===
|
|
18897
|
+
const reference = projection.annotations.find((a) => a.id === annotationIdParam && a.motivation === "linking");
|
|
18484
18898
|
if (!reference) {
|
|
18485
18899
|
logger2.warn("Annotation not found", {
|
|
18486
|
-
|
|
18900
|
+
expectedId: annotationIdParam,
|
|
18487
18901
|
availableIds: projection.annotations.map((a) => a.id)
|
|
18488
18902
|
});
|
|
18489
18903
|
throw new HTTPException(404, {
|
|
@@ -18665,14 +19079,14 @@ function registerYieldResourceStream(router, jobQueue) {
|
|
|
18665
19079
|
__name(registerYieldResourceStream, "registerYieldResourceStream");
|
|
18666
19080
|
function registerGetAnnotationHistory(router) {
|
|
18667
19081
|
router.get("/resources/:resourceId/annotations/:annotationId/history", async (c) => {
|
|
18668
|
-
const { resourceId:
|
|
19082
|
+
const { resourceId: resourceId20, annotationId: annotationId6 } = c.req.param();
|
|
18669
19083
|
const eventBus2 = c.get("eventBus");
|
|
18670
19084
|
const correlationId = crypto.randomUUID();
|
|
18671
19085
|
try {
|
|
18672
19086
|
const response = await eventBusRequest(eventBus2, "browse:annotation-history-requested", {
|
|
18673
19087
|
correlationId,
|
|
18674
|
-
resourceId: resourceId(
|
|
18675
|
-
annotationId: annotationId(
|
|
19088
|
+
resourceId: resourceId(resourceId20),
|
|
19089
|
+
annotationId: annotationId(annotationId6)
|
|
18676
19090
|
}, "browse:annotation-history-result", "browse:annotation-history-failed");
|
|
18677
19091
|
return c.json(response);
|
|
18678
19092
|
} catch (error) {
|
|
@@ -18713,6 +19127,7 @@ function createResourcesRouter(jobQueue) {
|
|
|
18713
19127
|
registerGetResourceLLMContext(resourcesRouter2);
|
|
18714
19128
|
registerGetAnnotationLLMContext(resourcesRouter2);
|
|
18715
19129
|
registerGetReferencedBy(resourcesRouter2);
|
|
19130
|
+
registerBindSearchStream(resourcesRouter2);
|
|
18716
19131
|
registerGetResourceAnnotations(resourcesRouter2);
|
|
18717
19132
|
registerCreateAnnotation(resourcesRouter2);
|
|
18718
19133
|
registerGetAnnotation(resourcesRouter2);
|
|
@@ -18739,39 +19154,30 @@ function registerGetAnnotationUri(router) {
|
|
|
18739
19154
|
const { id } = c.req.param();
|
|
18740
19155
|
const query = c.req.query();
|
|
18741
19156
|
const { kb } = c.get("makeMeaning");
|
|
18742
|
-
const
|
|
18743
|
-
if (!
|
|
19157
|
+
const resourceIdParam = query.resourceId;
|
|
19158
|
+
if (!resourceIdParam) {
|
|
18744
19159
|
throw new HTTPException(400, {
|
|
18745
19160
|
message: "resourceId query parameter is required"
|
|
18746
19161
|
});
|
|
18747
19162
|
}
|
|
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
19163
|
if (prefersHtml(c)) {
|
|
18757
19164
|
const frontendUrl = getFrontendUrl();
|
|
18758
19165
|
const normalizedBase = frontendUrl.endsWith("/") ? frontendUrl.slice(0, -1) : frontendUrl;
|
|
18759
|
-
const redirectUrl = `${normalizedBase}/annotations/${id}?resourceId=${
|
|
19166
|
+
const redirectUrl = `${normalizedBase}/annotations/${id}?resourceId=${resourceIdParam}`;
|
|
18760
19167
|
return c.redirect(redirectUrl, 302);
|
|
18761
19168
|
}
|
|
18762
|
-
const projection = await AnnotationContext.getResourceAnnotations(resourceId(
|
|
19169
|
+
const projection = await AnnotationContext.getResourceAnnotations(resourceId(resourceIdParam), kb);
|
|
18763
19170
|
const annotation = projection.annotations.find((a) => a.id === id);
|
|
18764
19171
|
if (!annotation) {
|
|
18765
19172
|
throw new HTTPException(404, {
|
|
18766
19173
|
message: "Annotation not found in resource"
|
|
18767
19174
|
});
|
|
18768
19175
|
}
|
|
18769
|
-
const resource = await ResourceContext.getResourceMetadata(resourceId(
|
|
19176
|
+
const resource = await ResourceContext.getResourceMetadata(resourceId(resourceIdParam), kb);
|
|
18770
19177
|
let resolvedResource = null;
|
|
18771
19178
|
const bodySource = getBodySource(annotation.body);
|
|
18772
19179
|
if (annotation.motivation === "linking" && bodySource) {
|
|
18773
|
-
|
|
18774
|
-
resolvedResource = await ResourceContext.getResourceMetadata(resourceId(bodyDocId), kb);
|
|
19180
|
+
resolvedResource = await ResourceContext.getResourceMetadata(resourceId(bodySource), kb);
|
|
18775
19181
|
}
|
|
18776
19182
|
const response = {
|
|
18777
19183
|
annotation,
|
|
@@ -18788,8 +19194,8 @@ operationsRouter.get("/api/annotations/:id/context", async (c) => {
|
|
|
18788
19194
|
const { id } = c.req.param();
|
|
18789
19195
|
const query = c.req.query();
|
|
18790
19196
|
const { kb } = c.get("makeMeaning");
|
|
18791
|
-
const
|
|
18792
|
-
if (!
|
|
19197
|
+
const resourceId20 = query.resourceId;
|
|
19198
|
+
if (!resourceId20) {
|
|
18793
19199
|
throw new HTTPException(400, {
|
|
18794
19200
|
message: "resourceId query parameter is required"
|
|
18795
19201
|
});
|
|
@@ -18807,7 +19213,7 @@ operationsRouter.get("/api/annotations/:id/context", async (c) => {
|
|
|
18807
19213
|
});
|
|
18808
19214
|
}
|
|
18809
19215
|
try {
|
|
18810
|
-
const response = await AnnotationContext.getAnnotationContext(annotationId(id), resourceId(
|
|
19216
|
+
const response = await AnnotationContext.getAnnotationContext(annotationId(id), resourceId(resourceId20), contextBefore, contextAfter, kb);
|
|
18811
19217
|
return c.json(response);
|
|
18812
19218
|
} catch (error) {
|
|
18813
19219
|
if (error instanceof Error && error.message === "Annotation not found") {
|
|
@@ -18837,14 +19243,14 @@ operationsRouter.get("/api/annotations/:id/summary", async (c) => {
|
|
|
18837
19243
|
const { id } = c.req.param();
|
|
18838
19244
|
const query = c.req.query();
|
|
18839
19245
|
const { kb, inferenceClient } = c.get("makeMeaning");
|
|
18840
|
-
const
|
|
18841
|
-
if (!
|
|
19246
|
+
const resourceId20 = query.resourceId;
|
|
19247
|
+
if (!resourceId20) {
|
|
18842
19248
|
throw new HTTPException(400, {
|
|
18843
19249
|
message: "resourceId query parameter is required"
|
|
18844
19250
|
});
|
|
18845
19251
|
}
|
|
18846
19252
|
try {
|
|
18847
|
-
const response = await AnnotationContext.generateAnnotationSummary(annotationId(id), resourceId(
|
|
19253
|
+
const response = await AnnotationContext.generateAnnotationSummary(annotationId(id), resourceId(resourceId20), kb, inferenceClient);
|
|
18848
19254
|
return c.json(response);
|
|
18849
19255
|
} catch (error) {
|
|
18850
19256
|
if (error instanceof Error && error.message === "Annotation not found") {
|
|
@@ -19205,6 +19611,7 @@ app.route("/", healthRouter);
|
|
|
19205
19611
|
app.route("/", authRouter);
|
|
19206
19612
|
app.route("/", statusRouter);
|
|
19207
19613
|
app.route("/", adminRouter);
|
|
19614
|
+
app.route("/", exchangeRouter);
|
|
19208
19615
|
var resourcesRouter = createResourcesRouter(makeMeaning.jobQueue);
|
|
19209
19616
|
app.route("/", resourcesRouter);
|
|
19210
19617
|
app.route("/", annotationsRouter);
|
|
@@ -19271,8 +19678,7 @@ app.all("/api/*", (c) => {
|
|
|
19271
19678
|
}, 404);
|
|
19272
19679
|
});
|
|
19273
19680
|
var port = backendService.port || 4e3;
|
|
19274
|
-
|
|
19275
|
-
if (nodeEnv !== "test") {
|
|
19681
|
+
if (config.env?.NODE_ENV !== "test") {
|
|
19276
19682
|
serve({
|
|
19277
19683
|
fetch: app.fetch,
|
|
19278
19684
|
port,
|
|
@@ -19280,7 +19686,7 @@ if (nodeEnv !== "test") {
|
|
|
19280
19686
|
}, async (info) => {
|
|
19281
19687
|
logger.info("Semiont Backend ready", {
|
|
19282
19688
|
url: `http://localhost:${info.port}/api`,
|
|
19283
|
-
environment:
|
|
19689
|
+
environment: config.env?.NODE_ENV ?? "development"
|
|
19284
19690
|
});
|
|
19285
19691
|
try {
|
|
19286
19692
|
const { JWTService: JWTService2 } = await Promise.resolve().then(() => (init_jwt(), jwt_exports));
|