@semiont/backend 0.4.7 → 0.4.11
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 +379 -245
- package/dist/index.js.map +1 -1
- package/dist/openapi.json +172 -0
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -268,6 +268,21 @@ var init_jwt = __esm({
|
|
|
268
268
|
throw error;
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
|
+
static generateMediaToken(resourceId21, userId14) {
|
|
272
|
+
const payload = { purpose: "media", sub: resourceId21, userId: userId14 };
|
|
273
|
+
return jwt.sign(payload, this.getSecret(), { expiresIn: "5m" });
|
|
274
|
+
}
|
|
275
|
+
static verifyMediaToken(token, resourceId21) {
|
|
276
|
+
let decoded;
|
|
277
|
+
try {
|
|
278
|
+
decoded = jwt.verify(token, this.getSecret());
|
|
279
|
+
} catch (error) {
|
|
280
|
+
if (error instanceof jwt.TokenExpiredError) throw new Error("Media token expired");
|
|
281
|
+
throw new Error("Invalid media token");
|
|
282
|
+
}
|
|
283
|
+
if (decoded["purpose"] !== "media") throw new Error("Invalid media token");
|
|
284
|
+
if (decoded["sub"] !== resourceId21) throw new Error("Media token resource mismatch");
|
|
285
|
+
}
|
|
271
286
|
static isAllowedDomain(email) {
|
|
272
287
|
const parts = email.split("@");
|
|
273
288
|
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
@@ -9976,6 +9991,78 @@ function makeMeaningConfigFrom(config2) {
|
|
|
9976
9991
|
|
|
9977
9992
|
// src/index.ts
|
|
9978
9993
|
init_logger();
|
|
9994
|
+
var rootRouter = new Hono();
|
|
9995
|
+
rootRouter.get("/", (c) => {
|
|
9996
|
+
const config2 = c.get("config");
|
|
9997
|
+
const projectName = config2._metadata?.projectName ?? "";
|
|
9998
|
+
const projectVersion = config2._metadata?.projectVersion ?? "";
|
|
9999
|
+
const siteName = config2.site?.siteName ?? "";
|
|
10000
|
+
const html = `<!DOCTYPE html>
|
|
10001
|
+
<html lang="en">
|
|
10002
|
+
<head>
|
|
10003
|
+
<meta charset="UTF-8">
|
|
10004
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
10005
|
+
<title>Semiont</title>
|
|
10006
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10007
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
10008
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500&family=Orbitron:wght@700&display=swap" rel="stylesheet">
|
|
10009
|
+
<style>
|
|
10010
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
10011
|
+
body {
|
|
10012
|
+
background: #ffffff;
|
|
10013
|
+
color: #111827;
|
|
10014
|
+
font-family: 'Inter', -apple-system, sans-serif;
|
|
10015
|
+
min-height: 100vh;
|
|
10016
|
+
display: flex;
|
|
10017
|
+
flex-direction: column;
|
|
10018
|
+
align-items: center;
|
|
10019
|
+
justify-content: center;
|
|
10020
|
+
gap: 0.75rem;
|
|
10021
|
+
}
|
|
10022
|
+
h1 {
|
|
10023
|
+
font-family: 'Orbitron', sans-serif;
|
|
10024
|
+
font-size: 3rem;
|
|
10025
|
+
font-weight: 700;
|
|
10026
|
+
letter-spacing: 0.15em;
|
|
10027
|
+
color: #0066cc;
|
|
10028
|
+
}
|
|
10029
|
+
h2 {
|
|
10030
|
+
font-family: 'Inter', sans-serif;
|
|
10031
|
+
font-size: 0.9rem;
|
|
10032
|
+
font-weight: 500;
|
|
10033
|
+
letter-spacing: 0.3em;
|
|
10034
|
+
color: #6b7280;
|
|
10035
|
+
text-transform: uppercase;
|
|
10036
|
+
}
|
|
10037
|
+
.meta {
|
|
10038
|
+
margin-top: 1.5rem;
|
|
10039
|
+
font-size: 0.8rem;
|
|
10040
|
+
color: #9ca3af;
|
|
10041
|
+
display: flex;
|
|
10042
|
+
flex-direction: column;
|
|
10043
|
+
align-items: center;
|
|
10044
|
+
gap: 0.25rem;
|
|
10045
|
+
}
|
|
10046
|
+
a {
|
|
10047
|
+
color: #0066cc;
|
|
10048
|
+
text-decoration: none;
|
|
10049
|
+
font-size: 0.8rem;
|
|
10050
|
+
}
|
|
10051
|
+
a:hover { text-decoration: underline; }
|
|
10052
|
+
</style>
|
|
10053
|
+
</head>
|
|
10054
|
+
<body>
|
|
10055
|
+
<h1>SEMIONT</h1>
|
|
10056
|
+
<h2>knowledge base</h2>
|
|
10057
|
+
<div class="meta">
|
|
10058
|
+
${siteName ? `<span>${siteName}</span>` : ""}
|
|
10059
|
+
${projectName ? `<span>${projectName}${projectVersion ? " v" + projectVersion : ""}</span>` : ""}
|
|
10060
|
+
<a href="/api/health">/api/health</a>
|
|
10061
|
+
</div>
|
|
10062
|
+
</body>
|
|
10063
|
+
</html>`;
|
|
10064
|
+
return c.html(html);
|
|
10065
|
+
});
|
|
9979
10066
|
var globalForPrisma = global;
|
|
9980
10067
|
var DatabaseConnection = class {
|
|
9981
10068
|
static instance = null;
|
|
@@ -11542,6 +11629,10 @@ var openapi_default = {
|
|
|
11542
11629
|
GatherResourceStreamRequest: {
|
|
11543
11630
|
type: "object",
|
|
11544
11631
|
properties: {
|
|
11632
|
+
correlationId: {
|
|
11633
|
+
type: "string",
|
|
11634
|
+
description: "Client-generated correlation ID to thread the response back to the originating request"
|
|
11635
|
+
},
|
|
11545
11636
|
depth: {
|
|
11546
11637
|
type: "integer",
|
|
11547
11638
|
minimum: 1,
|
|
@@ -11567,6 +11658,10 @@ var openapi_default = {
|
|
|
11567
11658
|
GatherAnnotationStreamRequest: {
|
|
11568
11659
|
type: "object",
|
|
11569
11660
|
properties: {
|
|
11661
|
+
correlationId: {
|
|
11662
|
+
type: "string",
|
|
11663
|
+
description: "Client-generated correlation ID to thread the response back to the originating request"
|
|
11664
|
+
},
|
|
11570
11665
|
contextWindow: {
|
|
11571
11666
|
type: "integer",
|
|
11572
11667
|
minimum: 100,
|
|
@@ -13392,6 +13487,9 @@ var openapi_default = {
|
|
|
13392
13487
|
isAdmin: {
|
|
13393
13488
|
type: "boolean"
|
|
13394
13489
|
},
|
|
13490
|
+
isModerator: {
|
|
13491
|
+
type: "boolean"
|
|
13492
|
+
},
|
|
13395
13493
|
isActive: {
|
|
13396
13494
|
type: "boolean"
|
|
13397
13495
|
},
|
|
@@ -13419,6 +13517,7 @@ var openapi_default = {
|
|
|
13419
13517
|
"domain",
|
|
13420
13518
|
"provider",
|
|
13421
13519
|
"isAdmin",
|
|
13520
|
+
"isModerator",
|
|
13422
13521
|
"isActive",
|
|
13423
13522
|
"termsAcceptedAt",
|
|
13424
13523
|
"lastLogin",
|
|
@@ -13490,6 +13589,30 @@ var openapi_default = {
|
|
|
13490
13589
|
],
|
|
13491
13590
|
description: "W3C Web Annotation body purpose vocabulary - https://www.w3.org/TR/annotation-vocab/#motivation"
|
|
13492
13591
|
},
|
|
13592
|
+
MediaTokenRequest: {
|
|
13593
|
+
type: "object",
|
|
13594
|
+
properties: {
|
|
13595
|
+
resourceId: {
|
|
13596
|
+
type: "string",
|
|
13597
|
+
description: "The resource ID to generate a media token for"
|
|
13598
|
+
}
|
|
13599
|
+
},
|
|
13600
|
+
required: [
|
|
13601
|
+
"resourceId"
|
|
13602
|
+
]
|
|
13603
|
+
},
|
|
13604
|
+
MediaTokenResponse: {
|
|
13605
|
+
type: "object",
|
|
13606
|
+
properties: {
|
|
13607
|
+
token: {
|
|
13608
|
+
type: "string",
|
|
13609
|
+
description: "Short-lived media token for use as ?token= query parameter on resource URLs"
|
|
13610
|
+
}
|
|
13611
|
+
},
|
|
13612
|
+
required: [
|
|
13613
|
+
"token"
|
|
13614
|
+
]
|
|
13615
|
+
},
|
|
13493
13616
|
GatheredContext: {
|
|
13494
13617
|
type: "object",
|
|
13495
13618
|
description: "Context gathered for an annotation. Includes source document excerpts, metadata, and graph-derived context. Used by both Find (bind) and Generate (yield) flows.",
|
|
@@ -13633,6 +13756,37 @@ var openapi_default = {
|
|
|
13633
13756
|
"annotation",
|
|
13634
13757
|
"sourceResource"
|
|
13635
13758
|
]
|
|
13759
|
+
},
|
|
13760
|
+
MatchSearchStreamRequest: {
|
|
13761
|
+
type: "object",
|
|
13762
|
+
properties: {
|
|
13763
|
+
correlationId: {
|
|
13764
|
+
type: "string",
|
|
13765
|
+
description: "Client-generated correlation ID to thread the response back to the originating request"
|
|
13766
|
+
},
|
|
13767
|
+
referenceId: {
|
|
13768
|
+
type: "string",
|
|
13769
|
+
description: "Annotation ID of the reference to search candidates for"
|
|
13770
|
+
},
|
|
13771
|
+
context: {
|
|
13772
|
+
$ref: "#/components/schemas/GatheredContext",
|
|
13773
|
+
description: "Gathered context for the reference annotation"
|
|
13774
|
+
},
|
|
13775
|
+
limit: {
|
|
13776
|
+
type: "integer",
|
|
13777
|
+
minimum: 1,
|
|
13778
|
+
maximum: 20,
|
|
13779
|
+
description: "Maximum number of candidate results to return (default: 10)"
|
|
13780
|
+
},
|
|
13781
|
+
useSemanticScoring: {
|
|
13782
|
+
type: "boolean",
|
|
13783
|
+
description: "Enable semantic similarity scoring in addition to keyword matching (default: true)"
|
|
13784
|
+
}
|
|
13785
|
+
},
|
|
13786
|
+
required: [
|
|
13787
|
+
"referenceId",
|
|
13788
|
+
"context"
|
|
13789
|
+
]
|
|
13636
13790
|
}
|
|
13637
13791
|
}
|
|
13638
13792
|
}
|
|
@@ -13860,8 +14014,33 @@ var OAuthService = class {
|
|
|
13860
14014
|
return user;
|
|
13861
14015
|
}
|
|
13862
14016
|
};
|
|
14017
|
+
|
|
14018
|
+
// src/middleware/auth.ts
|
|
14019
|
+
init_jwt();
|
|
14020
|
+
var MEDIA_TOKEN_PATH = /^\/api\/resources\/([^/]+)$/;
|
|
13863
14021
|
var authMiddleware = async (c, next) => {
|
|
13864
14022
|
const logger2 = c.get("logger");
|
|
14023
|
+
if (c.req.method === "GET") {
|
|
14024
|
+
const mediaTokenParam = c.req.query("token");
|
|
14025
|
+
const match = c.req.path.match(MEDIA_TOKEN_PATH);
|
|
14026
|
+
const resourceId21 = match?.[1];
|
|
14027
|
+
if (mediaTokenParam && resourceId21) {
|
|
14028
|
+
try {
|
|
14029
|
+
JWTService.verifyMediaToken(mediaTokenParam, resourceId21);
|
|
14030
|
+
c.set("token", mediaTokenParam);
|
|
14031
|
+
await next();
|
|
14032
|
+
return;
|
|
14033
|
+
} catch (error) {
|
|
14034
|
+
logger2.warn("Authentication failed: Invalid media token", {
|
|
14035
|
+
type: "auth_failed",
|
|
14036
|
+
reason: "invalid_media_token",
|
|
14037
|
+
path: c.req.path,
|
|
14038
|
+
error: error instanceof Error ? error.message : String(error)
|
|
14039
|
+
});
|
|
14040
|
+
return c.json({ error: "Unauthorized" }, 401);
|
|
14041
|
+
}
|
|
14042
|
+
}
|
|
14043
|
+
}
|
|
13865
14044
|
const authHeader = c.req.header("Authorization");
|
|
13866
14045
|
let tokenStr;
|
|
13867
14046
|
if (authHeader?.startsWith("Bearer ")) {
|
|
@@ -14195,6 +14374,7 @@ authRouter.get("/api/users/me", authMiddleware, async (c) => {
|
|
|
14195
14374
|
domain: user.domain,
|
|
14196
14375
|
provider: user.provider,
|
|
14197
14376
|
isAdmin: user.isAdmin,
|
|
14377
|
+
isModerator: user.isModerator,
|
|
14198
14378
|
isActive: user.isActive,
|
|
14199
14379
|
termsAcceptedAt: user.termsAcceptedAt?.toISOString() || null,
|
|
14200
14380
|
lastLogin: user.lastLogin?.toISOString() || null,
|
|
@@ -14260,6 +14440,20 @@ authRouter.post("/api/tokens/mcp-generate", authMiddleware, async (c) => {
|
|
|
14260
14440
|
return c.json({ error: "Failed to generate refresh token" }, 401);
|
|
14261
14441
|
}
|
|
14262
14442
|
});
|
|
14443
|
+
authRouter.post("/api/tokens/media", authMiddleware, async (c) => {
|
|
14444
|
+
const user = c.get("user");
|
|
14445
|
+
let body;
|
|
14446
|
+
try {
|
|
14447
|
+
body = await c.req.json();
|
|
14448
|
+
} catch {
|
|
14449
|
+
return c.json({ error: "Invalid request body" }, 400);
|
|
14450
|
+
}
|
|
14451
|
+
if (!body.resourceId || typeof body.resourceId !== "string") {
|
|
14452
|
+
return c.json({ error: "resourceId is required" }, 400);
|
|
14453
|
+
}
|
|
14454
|
+
const token = JWTService.generateMediaToken(body.resourceId, user.id);
|
|
14455
|
+
return c.json({ token }, 200);
|
|
14456
|
+
});
|
|
14263
14457
|
authRouter.post("/api/users/accept-terms", authMiddleware, async (c) => {
|
|
14264
14458
|
const user = c.get("user");
|
|
14265
14459
|
await OAuthService.acceptTerms(userId(user.id));
|
|
@@ -14753,7 +14947,7 @@ function registerCreateResource(router) {
|
|
|
14753
14947
|
const arrayBuffer = await file.arrayBuffer();
|
|
14754
14948
|
const contentBuffer = Buffer.from(arrayBuffer);
|
|
14755
14949
|
const eventBus2 = c.get("eventBus");
|
|
14756
|
-
const
|
|
14950
|
+
const resourceId21 = await ResourceOperations.createResource(
|
|
14757
14951
|
{
|
|
14758
14952
|
name,
|
|
14759
14953
|
content: contentBuffer,
|
|
@@ -14766,47 +14960,9 @@ function registerCreateResource(router) {
|
|
|
14766
14960
|
userId(userToDid(user)),
|
|
14767
14961
|
eventBus2
|
|
14768
14962
|
);
|
|
14769
|
-
return c.json({ resourceId:
|
|
14963
|
+
return c.json({ resourceId: resourceId21 }, 202);
|
|
14770
14964
|
});
|
|
14771
14965
|
}
|
|
14772
|
-
|
|
14773
|
-
// src/middleware/content-negotiation.ts
|
|
14774
|
-
function prefersHtml(c) {
|
|
14775
|
-
const acceptHeader = c.req.header("Accept") || "";
|
|
14776
|
-
const userAgent = c.req.header("User-Agent") || "";
|
|
14777
|
-
const acceptsHtml = acceptHeader.includes("text/html");
|
|
14778
|
-
const acceptsJson = acceptHeader.includes("application/json") || acceptHeader.includes("application/ld+json");
|
|
14779
|
-
if (acceptsJson && !acceptsHtml) {
|
|
14780
|
-
return false;
|
|
14781
|
-
}
|
|
14782
|
-
if (acceptsHtml && acceptsJson) {
|
|
14783
|
-
const htmlIndex = acceptHeader.indexOf("text/html");
|
|
14784
|
-
const jsonIndex = Math.min(
|
|
14785
|
-
acceptHeader.indexOf("application/json") >= 0 ? acceptHeader.indexOf("application/json") : Infinity,
|
|
14786
|
-
acceptHeader.indexOf("application/ld+json") >= 0 ? acceptHeader.indexOf("application/ld+json") : Infinity
|
|
14787
|
-
);
|
|
14788
|
-
if (htmlIndex < jsonIndex) {
|
|
14789
|
-
return true;
|
|
14790
|
-
} else {
|
|
14791
|
-
return false;
|
|
14792
|
-
}
|
|
14793
|
-
}
|
|
14794
|
-
const isBrowser = /Mozilla|Chrome|Safari|Edge|Firefox|Opera/.test(userAgent);
|
|
14795
|
-
if (isBrowser && !acceptHeader && !userAgent.includes("curl")) {
|
|
14796
|
-
return true;
|
|
14797
|
-
}
|
|
14798
|
-
if (isBrowser && acceptsHtml && !userAgent.includes("curl")) {
|
|
14799
|
-
return true;
|
|
14800
|
-
}
|
|
14801
|
-
return acceptsHtml && !acceptsJson;
|
|
14802
|
-
}
|
|
14803
|
-
function getFrontendUrl() {
|
|
14804
|
-
const frontendUrl = process.env.FRONTEND_URL;
|
|
14805
|
-
if (!frontendUrl) {
|
|
14806
|
-
throw new Error("FRONTEND_URL environment variable is required for content negotiation");
|
|
14807
|
-
}
|
|
14808
|
-
return frontendUrl;
|
|
14809
|
-
}
|
|
14810
14966
|
var SSE_STREAM_CONNECTED = "stream-connected";
|
|
14811
14967
|
function getBodySource(body) {
|
|
14812
14968
|
if (Array.isArray(body)) {
|
|
@@ -14966,13 +15122,6 @@ function registerGetResourceUri(router) {
|
|
|
14966
15122
|
});
|
|
14967
15123
|
router.get("/resources/:id", async (c) => {
|
|
14968
15124
|
const { id } = c.req.param();
|
|
14969
|
-
const view = c.req.query("view");
|
|
14970
|
-
if (view === "semiont") {
|
|
14971
|
-
const frontendUrl = getFrontendUrl();
|
|
14972
|
-
const normalizedBase = frontendUrl.endsWith("/") ? frontendUrl.slice(0, -1) : frontendUrl;
|
|
14973
|
-
const redirectUrl = `${normalizedBase}/know/resource/${id}`;
|
|
14974
|
-
return c.redirect(redirectUrl, 302);
|
|
14975
|
-
}
|
|
14976
15125
|
const acceptHeader = c.req.header("Accept") || "application/ld+json";
|
|
14977
15126
|
if (acceptHeader.includes("text/") || acceptHeader.includes("image/") || acceptHeader.includes("application/pdf")) {
|
|
14978
15127
|
const { knowledgeSystem: { kb } } = c.get("makeMeaning");
|
|
@@ -15126,7 +15275,7 @@ var nanoid = (size = 21) => {
|
|
|
15126
15275
|
async function writeTypedSSE(stream, options) {
|
|
15127
15276
|
await stream.writeSSE({
|
|
15128
15277
|
event: options.event,
|
|
15129
|
-
data: options.data,
|
|
15278
|
+
data: JSON.stringify(options.data),
|
|
15130
15279
|
id: options.id
|
|
15131
15280
|
});
|
|
15132
15281
|
}
|
|
@@ -15210,16 +15359,13 @@ function registerAnnotateReferencesStream(router, jobQueue) {
|
|
|
15210
15359
|
logger2.info("[EventBus] Received mark:progress event", { progress, resourceId: id });
|
|
15211
15360
|
try {
|
|
15212
15361
|
await writeTypedSSE(stream, {
|
|
15213
|
-
data:
|
|
15362
|
+
data: {
|
|
15214
15363
|
status: progress.status || "scanning",
|
|
15215
15364
|
resourceId: resourceId(id),
|
|
15216
15365
|
currentEntityType: progress.currentEntityType,
|
|
15217
|
-
|
|
15218
|
-
|
|
15219
|
-
|
|
15220
|
-
message: progress.message || (progress.currentEntityType ? `Scanning for ${progress.currentEntityType}...` : "Processing..."),
|
|
15221
|
-
percentage: progress.percentage
|
|
15222
|
-
}),
|
|
15366
|
+
percentage: progress.percentage,
|
|
15367
|
+
message: progress.message || (progress.currentEntityType ? `Scanning for ${progress.currentEntityType}...` : "Processing...")
|
|
15368
|
+
},
|
|
15223
15369
|
event: "mark:progress",
|
|
15224
15370
|
id: String(Date.now())
|
|
15225
15371
|
});
|
|
@@ -15237,15 +15383,13 @@ function registerAnnotateReferencesStream(router, jobQueue) {
|
|
|
15237
15383
|
try {
|
|
15238
15384
|
const result = event.payload.result;
|
|
15239
15385
|
await writeTypedSSE(stream, {
|
|
15240
|
-
data:
|
|
15386
|
+
data: {
|
|
15241
15387
|
motivation: "linking",
|
|
15242
15388
|
status: "complete",
|
|
15243
15389
|
resourceId: resourceId(id),
|
|
15244
|
-
totalEntityTypes: entityTypes.length,
|
|
15245
|
-
processedEntityTypes: entityTypes.length,
|
|
15246
15390
|
foundCount: result?.totalFound,
|
|
15247
15391
|
message: result?.totalFound !== void 0 ? `Detection complete! Found ${result.totalFound} entities` : "Detection complete!"
|
|
15248
|
-
}
|
|
15392
|
+
},
|
|
15249
15393
|
event: "mark:assist-finished",
|
|
15250
15394
|
id: String(Date.now())
|
|
15251
15395
|
});
|
|
@@ -15262,13 +15406,10 @@ function registerAnnotateReferencesStream(router, jobQueue) {
|
|
|
15262
15406
|
logger2.info("Detection failed", { error: event.payload.error });
|
|
15263
15407
|
try {
|
|
15264
15408
|
await writeTypedSSE(stream, {
|
|
15265
|
-
data:
|
|
15266
|
-
status: "error",
|
|
15409
|
+
data: {
|
|
15267
15410
|
resourceId: resourceId(id),
|
|
15268
|
-
totalEntityTypes: entityTypes.length,
|
|
15269
|
-
processedEntityTypes: 0,
|
|
15270
15411
|
message: event.payload.error || "Detection failed"
|
|
15271
|
-
}
|
|
15412
|
+
},
|
|
15272
15413
|
event: "mark:assist-failed",
|
|
15273
15414
|
id: String(Date.now())
|
|
15274
15415
|
});
|
|
@@ -15398,11 +15539,11 @@ function registerAnnotateHighlightsStream(router, jobQueue) {
|
|
|
15398
15539
|
logger2.info("Detection started");
|
|
15399
15540
|
try {
|
|
15400
15541
|
await writeTypedSSE(stream, {
|
|
15401
|
-
data:
|
|
15542
|
+
data: {
|
|
15402
15543
|
status: "started",
|
|
15403
15544
|
resourceId: resourceId(id),
|
|
15404
15545
|
message: "Starting detection..."
|
|
15405
|
-
}
|
|
15546
|
+
},
|
|
15406
15547
|
event: "mark:progress",
|
|
15407
15548
|
id: String(Date.now())
|
|
15408
15549
|
});
|
|
@@ -15418,13 +15559,12 @@ function registerAnnotateHighlightsStream(router, jobQueue) {
|
|
|
15418
15559
|
logger2.info("Detection progress", { progress });
|
|
15419
15560
|
try {
|
|
15420
15561
|
await writeTypedSSE(stream, {
|
|
15421
|
-
data:
|
|
15562
|
+
data: {
|
|
15422
15563
|
status: progress.status || "analyzing",
|
|
15423
15564
|
resourceId: resourceId(id),
|
|
15424
|
-
stage: progress.status === "analyzing" || progress.status === "creating" ? progress.status : void 0,
|
|
15425
15565
|
percentage: progress.percentage,
|
|
15426
15566
|
message: progress.message || "Processing..."
|
|
15427
|
-
}
|
|
15567
|
+
},
|
|
15428
15568
|
event: "mark:progress",
|
|
15429
15569
|
id: String(Date.now())
|
|
15430
15570
|
});
|
|
@@ -15442,7 +15582,7 @@ function registerAnnotateHighlightsStream(router, jobQueue) {
|
|
|
15442
15582
|
try {
|
|
15443
15583
|
const result = event.payload.result;
|
|
15444
15584
|
await writeTypedSSE(stream, {
|
|
15445
|
-
data:
|
|
15585
|
+
data: {
|
|
15446
15586
|
motivation: "highlighting",
|
|
15447
15587
|
status: "complete",
|
|
15448
15588
|
resourceId: resourceId(id),
|
|
@@ -15450,7 +15590,7 @@ function registerAnnotateHighlightsStream(router, jobQueue) {
|
|
|
15450
15590
|
foundCount: result?.highlightsFound,
|
|
15451
15591
|
createdCount: result?.highlightsCreated,
|
|
15452
15592
|
message: result?.highlightsCreated !== void 0 ? `Complete! Created ${result.highlightsCreated} highlights` : "Highlight detection complete!"
|
|
15453
|
-
}
|
|
15593
|
+
},
|
|
15454
15594
|
event: "mark:assist-finished",
|
|
15455
15595
|
id: String(Date.now())
|
|
15456
15596
|
});
|
|
@@ -15467,11 +15607,10 @@ function registerAnnotateHighlightsStream(router, jobQueue) {
|
|
|
15467
15607
|
logger2.info("Detection failed", { error: event.payload.error });
|
|
15468
15608
|
try {
|
|
15469
15609
|
await writeTypedSSE(stream, {
|
|
15470
|
-
data:
|
|
15471
|
-
status: "error",
|
|
15610
|
+
data: {
|
|
15472
15611
|
resourceId: resourceId(id),
|
|
15473
15612
|
message: event.payload.error || "Highlight detection failed"
|
|
15474
|
-
}
|
|
15613
|
+
},
|
|
15475
15614
|
event: "mark:assist-failed",
|
|
15476
15615
|
id: String(Date.now())
|
|
15477
15616
|
});
|
|
@@ -15601,11 +15740,11 @@ function registerAnnotateAssessmentsStream(router, jobQueue) {
|
|
|
15601
15740
|
logger2.info("Detection started");
|
|
15602
15741
|
try {
|
|
15603
15742
|
await writeTypedSSE(stream, {
|
|
15604
|
-
data:
|
|
15743
|
+
data: {
|
|
15605
15744
|
status: "started",
|
|
15606
15745
|
resourceId: resourceId(id),
|
|
15607
15746
|
message: "Starting detection..."
|
|
15608
|
-
}
|
|
15747
|
+
},
|
|
15609
15748
|
event: "mark:progress",
|
|
15610
15749
|
id: String(Date.now())
|
|
15611
15750
|
});
|
|
@@ -15621,13 +15760,12 @@ function registerAnnotateAssessmentsStream(router, jobQueue) {
|
|
|
15621
15760
|
logger2.info("Detection progress", { progress });
|
|
15622
15761
|
try {
|
|
15623
15762
|
await writeTypedSSE(stream, {
|
|
15624
|
-
data:
|
|
15763
|
+
data: {
|
|
15625
15764
|
status: progress.status || "analyzing",
|
|
15626
15765
|
resourceId: resourceId(id),
|
|
15627
|
-
stage: progress.status === "analyzing" || progress.status === "creating" ? progress.status : void 0,
|
|
15628
15766
|
percentage: progress.percentage,
|
|
15629
15767
|
message: progress.message || "Processing..."
|
|
15630
|
-
}
|
|
15768
|
+
},
|
|
15631
15769
|
event: "mark:progress",
|
|
15632
15770
|
id: String(Date.now())
|
|
15633
15771
|
});
|
|
@@ -15649,7 +15787,7 @@ function registerAnnotateAssessmentsStream(router, jobQueue) {
|
|
|
15649
15787
|
try {
|
|
15650
15788
|
const result = event.payload.result;
|
|
15651
15789
|
await writeTypedSSE(stream, {
|
|
15652
|
-
data:
|
|
15790
|
+
data: {
|
|
15653
15791
|
motivation: "assessing",
|
|
15654
15792
|
status: "complete",
|
|
15655
15793
|
resourceId: resourceId(id),
|
|
@@ -15657,7 +15795,7 @@ function registerAnnotateAssessmentsStream(router, jobQueue) {
|
|
|
15657
15795
|
foundCount: result?.assessmentsFound,
|
|
15658
15796
|
createdCount: result?.assessmentsCreated,
|
|
15659
15797
|
message: result?.assessmentsCreated !== void 0 ? `Complete! Created ${result.assessmentsCreated} assessments` : "Assessment detection complete!"
|
|
15660
|
-
}
|
|
15798
|
+
},
|
|
15661
15799
|
event: "mark:assist-finished",
|
|
15662
15800
|
id: String(Date.now())
|
|
15663
15801
|
});
|
|
@@ -15674,11 +15812,10 @@ function registerAnnotateAssessmentsStream(router, jobQueue) {
|
|
|
15674
15812
|
logger2.info("Detection failed", { error: event.payload.error });
|
|
15675
15813
|
try {
|
|
15676
15814
|
await writeTypedSSE(stream, {
|
|
15677
|
-
data:
|
|
15678
|
-
status: "error",
|
|
15815
|
+
data: {
|
|
15679
15816
|
resourceId: resourceId(id),
|
|
15680
15817
|
message: event.payload.error || "Assessment detection failed"
|
|
15681
|
-
}
|
|
15818
|
+
},
|
|
15682
15819
|
event: "mark:assist-failed",
|
|
15683
15820
|
id: String(Date.now())
|
|
15684
15821
|
});
|
|
@@ -15808,11 +15945,11 @@ function registerAnnotateCommentsStream(router, jobQueue) {
|
|
|
15808
15945
|
logger2.info("Detection started");
|
|
15809
15946
|
try {
|
|
15810
15947
|
await writeTypedSSE(stream, {
|
|
15811
|
-
data:
|
|
15948
|
+
data: {
|
|
15812
15949
|
status: "started",
|
|
15813
15950
|
resourceId: resourceId(id),
|
|
15814
15951
|
message: "Starting detection..."
|
|
15815
|
-
}
|
|
15952
|
+
},
|
|
15816
15953
|
event: "mark:progress",
|
|
15817
15954
|
id: String(Date.now())
|
|
15818
15955
|
});
|
|
@@ -15828,13 +15965,12 @@ function registerAnnotateCommentsStream(router, jobQueue) {
|
|
|
15828
15965
|
logger2.info("Detection progress", { progress });
|
|
15829
15966
|
try {
|
|
15830
15967
|
await writeTypedSSE(stream, {
|
|
15831
|
-
data:
|
|
15968
|
+
data: {
|
|
15832
15969
|
status: progress.status || "analyzing",
|
|
15833
15970
|
resourceId: resourceId(id),
|
|
15834
|
-
stage: progress.status === "analyzing" || progress.status === "creating" ? progress.status : void 0,
|
|
15835
15971
|
percentage: progress.percentage,
|
|
15836
15972
|
message: progress.message || "Processing..."
|
|
15837
|
-
}
|
|
15973
|
+
},
|
|
15838
15974
|
event: "mark:progress",
|
|
15839
15975
|
id: String(Date.now())
|
|
15840
15976
|
});
|
|
@@ -15852,7 +15988,7 @@ function registerAnnotateCommentsStream(router, jobQueue) {
|
|
|
15852
15988
|
try {
|
|
15853
15989
|
const result = event.payload.result;
|
|
15854
15990
|
await writeTypedSSE(stream, {
|
|
15855
|
-
data:
|
|
15991
|
+
data: {
|
|
15856
15992
|
motivation: "commenting",
|
|
15857
15993
|
status: "complete",
|
|
15858
15994
|
resourceId: resourceId(id),
|
|
@@ -15860,7 +15996,7 @@ function registerAnnotateCommentsStream(router, jobQueue) {
|
|
|
15860
15996
|
foundCount: result?.commentsFound,
|
|
15861
15997
|
createdCount: result?.commentsCreated,
|
|
15862
15998
|
message: result?.commentsCreated !== void 0 ? `Complete! Created ${result.commentsCreated} comments` : "Comment detection complete!"
|
|
15863
|
-
}
|
|
15999
|
+
},
|
|
15864
16000
|
event: "mark:assist-finished",
|
|
15865
16001
|
id: String(Date.now())
|
|
15866
16002
|
});
|
|
@@ -15877,11 +16013,10 @@ function registerAnnotateCommentsStream(router, jobQueue) {
|
|
|
15877
16013
|
logger2.info("Detection failed", { error: event.payload.error });
|
|
15878
16014
|
try {
|
|
15879
16015
|
await writeTypedSSE(stream, {
|
|
15880
|
-
data:
|
|
15881
|
-
status: "error",
|
|
16016
|
+
data: {
|
|
15882
16017
|
resourceId: resourceId(id),
|
|
15883
16018
|
message: event.payload.error || "Comment detection failed"
|
|
15884
|
-
}
|
|
16019
|
+
},
|
|
15885
16020
|
event: "mark:assist-failed",
|
|
15886
16021
|
id: String(Date.now())
|
|
15887
16022
|
});
|
|
@@ -16185,12 +16320,12 @@ function registerAnnotateTagsStream(router, jobQueue) {
|
|
|
16185
16320
|
logger2.info("Detection started");
|
|
16186
16321
|
try {
|
|
16187
16322
|
await writeTypedSSE(stream, {
|
|
16188
|
-
data:
|
|
16323
|
+
data: {
|
|
16189
16324
|
status: "started",
|
|
16190
16325
|
resourceId: resourceId(id),
|
|
16191
16326
|
totalCategories: categories.length,
|
|
16192
16327
|
message: "Starting detection..."
|
|
16193
|
-
}
|
|
16328
|
+
},
|
|
16194
16329
|
event: "mark:progress",
|
|
16195
16330
|
id: String(Date.now())
|
|
16196
16331
|
});
|
|
@@ -16206,16 +16341,15 @@ function registerAnnotateTagsStream(router, jobQueue) {
|
|
|
16206
16341
|
logger2.info("Detection progress", { progress });
|
|
16207
16342
|
try {
|
|
16208
16343
|
await writeTypedSSE(stream, {
|
|
16209
|
-
data:
|
|
16344
|
+
data: {
|
|
16210
16345
|
status: progress.status || "analyzing",
|
|
16211
16346
|
resourceId: resourceId(id),
|
|
16212
|
-
stage: progress.status === "analyzing" || progress.status === "creating" ? progress.status : void 0,
|
|
16213
16347
|
percentage: progress.percentage,
|
|
16214
16348
|
currentCategory: progress.currentCategory,
|
|
16215
16349
|
processedCategories: progress.processedCategories,
|
|
16216
16350
|
totalCategories: progress.totalCategories,
|
|
16217
16351
|
message: progress.message || "Processing..."
|
|
16218
|
-
}
|
|
16352
|
+
},
|
|
16219
16353
|
event: "mark:progress",
|
|
16220
16354
|
id: String(Date.now())
|
|
16221
16355
|
});
|
|
@@ -16233,7 +16367,7 @@ function registerAnnotateTagsStream(router, jobQueue) {
|
|
|
16233
16367
|
try {
|
|
16234
16368
|
const result = event.payload.result;
|
|
16235
16369
|
await writeTypedSSE(stream, {
|
|
16236
|
-
data:
|
|
16370
|
+
data: {
|
|
16237
16371
|
motivation: "tagging",
|
|
16238
16372
|
status: "complete",
|
|
16239
16373
|
resourceId: resourceId(id),
|
|
@@ -16242,7 +16376,7 @@ function registerAnnotateTagsStream(router, jobQueue) {
|
|
|
16242
16376
|
createdCount: result?.tagsCreated,
|
|
16243
16377
|
byCategory: result?.byCategory,
|
|
16244
16378
|
message: result?.tagsCreated !== void 0 ? `Complete! Created ${result.tagsCreated} tags` : "Tag detection complete!"
|
|
16245
|
-
}
|
|
16379
|
+
},
|
|
16246
16380
|
event: "mark:assist-finished",
|
|
16247
16381
|
id: String(Date.now())
|
|
16248
16382
|
});
|
|
@@ -16259,11 +16393,10 @@ function registerAnnotateTagsStream(router, jobQueue) {
|
|
|
16259
16393
|
logger2.info("Detection failed", { error: event.payload.error });
|
|
16260
16394
|
try {
|
|
16261
16395
|
await writeTypedSSE(stream, {
|
|
16262
|
-
data:
|
|
16263
|
-
status: "error",
|
|
16396
|
+
data: {
|
|
16264
16397
|
resourceId: resourceId(id),
|
|
16265
16398
|
message: event.payload.error || "Tag detection failed"
|
|
16266
|
-
}
|
|
16399
|
+
},
|
|
16267
16400
|
event: "mark:assist-failed",
|
|
16268
16401
|
id: String(Date.now())
|
|
16269
16402
|
});
|
|
@@ -16337,118 +16470,122 @@ function registerGetReferencedBy(router) {
|
|
|
16337
16470
|
});
|
|
16338
16471
|
}
|
|
16339
16472
|
init_logger();
|
|
16340
|
-
function
|
|
16341
|
-
router.post(
|
|
16342
|
-
|
|
16343
|
-
|
|
16344
|
-
|
|
16345
|
-
|
|
16346
|
-
|
|
16347
|
-
|
|
16348
|
-
|
|
16349
|
-
throw new HTTPException(401, { message: "Authentication required" });
|
|
16350
|
-
}
|
|
16351
|
-
const body = await c.req.json();
|
|
16352
|
-
const { referenceId, context, limit, useSemanticScoring } = body;
|
|
16353
|
-
if (!referenceId || !context) {
|
|
16354
|
-
throw new HTTPException(400, { message: "referenceId and context are required" });
|
|
16355
|
-
}
|
|
16356
|
-
const eventBus2 = c.get("eventBus");
|
|
16357
|
-
const { knowledgeSystem: { kb } } = c.get("makeMeaning");
|
|
16358
|
-
const resource = await ResourceContext.getResourceMetadata(resourceId(id), kb);
|
|
16359
|
-
if (!resource) {
|
|
16360
|
-
throw new HTTPException(404, { message: "Resource not found" });
|
|
16361
|
-
}
|
|
16362
|
-
const correlationId = crypto.randomUUID();
|
|
16363
|
-
logger2.info("Starting bind search stream", { referenceId, correlationId });
|
|
16364
|
-
c.header("X-Accel-Buffering", "no");
|
|
16365
|
-
c.header("Cache-Control", "no-cache, no-transform");
|
|
16366
|
-
return streamSSE(c, async (stream) => {
|
|
16367
|
-
let isStreamClosed = false;
|
|
16368
|
-
const subscriptions = [];
|
|
16369
|
-
let closeStreamCallback = null;
|
|
16370
|
-
const streamPromise = new Promise((resolve) => {
|
|
16371
|
-
closeStreamCallback = resolve;
|
|
16473
|
+
function registerMatchSearchStream(router) {
|
|
16474
|
+
router.post(
|
|
16475
|
+
"/resources/:id/match-search-stream",
|
|
16476
|
+
validateRequestBody("MatchSearchStreamRequest"),
|
|
16477
|
+
async (c) => {
|
|
16478
|
+
const { id } = c.req.param();
|
|
16479
|
+
const logger2 = getLogger().child({
|
|
16480
|
+
component: "match-search-stream",
|
|
16481
|
+
resourceId: id
|
|
16372
16482
|
});
|
|
16373
|
-
const
|
|
16374
|
-
|
|
16375
|
-
|
|
16376
|
-
|
|
16377
|
-
|
|
16378
|
-
};
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
|
|
16384
|
-
|
|
16385
|
-
|
|
16386
|
-
|
|
16387
|
-
|
|
16388
|
-
|
|
16389
|
-
|
|
16390
|
-
|
|
16391
|
-
|
|
16392
|
-
|
|
16393
|
-
|
|
16394
|
-
|
|
16395
|
-
id: String(Date.now())
|
|
16396
|
-
});
|
|
16397
|
-
} catch (error) {
|
|
16398
|
-
logger2.warn("Client disconnected during results");
|
|
16399
|
-
}
|
|
16400
|
-
cleanup();
|
|
16401
|
-
})
|
|
16402
|
-
);
|
|
16403
|
-
subscriptions.push(
|
|
16404
|
-
eventBus2.get("match:search-failed").subscribe(async (event) => {
|
|
16405
|
-
if (event.correlationId !== correlationId) return;
|
|
16406
|
-
if (isStreamClosed) return;
|
|
16407
|
-
logger2.error("Bind search failed", { referenceId, error: event.error });
|
|
16408
|
-
try {
|
|
16409
|
-
await writeTypedSSE(stream, {
|
|
16410
|
-
data: JSON.stringify({
|
|
16411
|
-
referenceId: event.referenceId,
|
|
16412
|
-
error: event.error.message
|
|
16413
|
-
}),
|
|
16414
|
-
event: "match:search-failed",
|
|
16415
|
-
id: String(Date.now())
|
|
16416
|
-
});
|
|
16417
|
-
} catch (error) {
|
|
16418
|
-
logger2.warn("Client disconnected during error");
|
|
16419
|
-
}
|
|
16420
|
-
cleanup();
|
|
16421
|
-
})
|
|
16422
|
-
);
|
|
16423
|
-
eventBus2.get("match:search-requested").next({
|
|
16424
|
-
correlationId,
|
|
16425
|
-
referenceId,
|
|
16426
|
-
context,
|
|
16427
|
-
limit,
|
|
16428
|
-
useSemanticScoring
|
|
16429
|
-
});
|
|
16430
|
-
c.req.raw.signal.addEventListener("abort", () => {
|
|
16431
|
-
logger2.info("Client disconnected from bind search stream");
|
|
16432
|
-
cleanup();
|
|
16483
|
+
const user = c.get("user");
|
|
16484
|
+
if (!user) {
|
|
16485
|
+
throw new HTTPException(401, { message: "Authentication required" });
|
|
16486
|
+
}
|
|
16487
|
+
const body = c.get("validatedBody");
|
|
16488
|
+
const { referenceId, context, limit, useSemanticScoring } = body;
|
|
16489
|
+
const correlationId = body.correlationId ?? crypto.randomUUID();
|
|
16490
|
+
const eventBus2 = c.get("eventBus");
|
|
16491
|
+
const { knowledgeSystem: { kb } } = c.get("makeMeaning");
|
|
16492
|
+
const resource = await ResourceContext.getResourceMetadata(resourceId(id), kb);
|
|
16493
|
+
if (!resource) {
|
|
16494
|
+
throw new HTTPException(404, { message: "Resource not found" });
|
|
16495
|
+
}
|
|
16496
|
+
logger2.info("Starting match search stream", { referenceId, correlationId });
|
|
16497
|
+
c.header("X-Accel-Buffering", "no");
|
|
16498
|
+
c.header("Cache-Control", "no-cache, no-transform");
|
|
16499
|
+
return streamSSE(c, async (stream) => {
|
|
16500
|
+
let isStreamClosed = false;
|
|
16501
|
+
const subscriptions = [];
|
|
16502
|
+
let closeStreamCallback = null;
|
|
16503
|
+
const streamPromise = new Promise((resolve) => {
|
|
16504
|
+
closeStreamCallback = resolve;
|
|
16433
16505
|
});
|
|
16434
|
-
|
|
16506
|
+
const cleanup = () => {
|
|
16507
|
+
if (isStreamClosed) return;
|
|
16508
|
+
isStreamClosed = true;
|
|
16509
|
+
subscriptions.forEach((sub) => sub.unsubscribe());
|
|
16510
|
+
if (closeStreamCallback) closeStreamCallback();
|
|
16511
|
+
};
|
|
16435
16512
|
try {
|
|
16436
|
-
|
|
16437
|
-
|
|
16438
|
-
|
|
16439
|
-
|
|
16440
|
-
|
|
16441
|
-
|
|
16442
|
-
|
|
16513
|
+
subscriptions.push(
|
|
16514
|
+
eventBus2.get("match:search-results").subscribe(async (event) => {
|
|
16515
|
+
if (event.correlationId !== correlationId) return;
|
|
16516
|
+
if (isStreamClosed) return;
|
|
16517
|
+
logger2.info("Match search completed", {
|
|
16518
|
+
referenceId,
|
|
16519
|
+
resultCount: event.response.length
|
|
16520
|
+
});
|
|
16521
|
+
try {
|
|
16522
|
+
await writeTypedSSE(stream, {
|
|
16523
|
+
data: {
|
|
16524
|
+
correlationId: event.correlationId,
|
|
16525
|
+
referenceId: event.referenceId,
|
|
16526
|
+
response: event.response
|
|
16527
|
+
},
|
|
16528
|
+
event: "match:search-results",
|
|
16529
|
+
id: String(Date.now())
|
|
16530
|
+
});
|
|
16531
|
+
} catch {
|
|
16532
|
+
logger2.warn("Client disconnected during results");
|
|
16533
|
+
}
|
|
16534
|
+
cleanup();
|
|
16535
|
+
})
|
|
16536
|
+
);
|
|
16537
|
+
subscriptions.push(
|
|
16538
|
+
eventBus2.get("match:search-failed").subscribe(async (event) => {
|
|
16539
|
+
if (event.correlationId !== correlationId) return;
|
|
16540
|
+
if (isStreamClosed) return;
|
|
16541
|
+
logger2.error("Match search failed", { referenceId, error: event.error });
|
|
16542
|
+
try {
|
|
16543
|
+
await writeTypedSSE(stream, {
|
|
16544
|
+
data: {
|
|
16545
|
+
correlationId: event.correlationId,
|
|
16546
|
+
referenceId: event.referenceId,
|
|
16547
|
+
error: event.error
|
|
16548
|
+
},
|
|
16549
|
+
event: "match:search-failed",
|
|
16550
|
+
id: String(Date.now())
|
|
16551
|
+
});
|
|
16552
|
+
} catch {
|
|
16553
|
+
logger2.warn("Client disconnected during error");
|
|
16554
|
+
}
|
|
16555
|
+
cleanup();
|
|
16556
|
+
})
|
|
16557
|
+
);
|
|
16558
|
+
eventBus2.get("match:search-requested").next({
|
|
16559
|
+
correlationId,
|
|
16560
|
+
referenceId,
|
|
16561
|
+
context,
|
|
16562
|
+
limit,
|
|
16563
|
+
useSemanticScoring
|
|
16564
|
+
});
|
|
16565
|
+
c.req.raw.signal.addEventListener("abort", () => {
|
|
16566
|
+
logger2.info("Client disconnected from match search stream");
|
|
16567
|
+
cleanup();
|
|
16443
16568
|
});
|
|
16444
|
-
} catch (
|
|
16445
|
-
|
|
16569
|
+
} catch (error) {
|
|
16570
|
+
try {
|
|
16571
|
+
await writeTypedSSE(stream, {
|
|
16572
|
+
data: {
|
|
16573
|
+
correlationId,
|
|
16574
|
+
referenceId,
|
|
16575
|
+
error: error instanceof Error ? error.message : "Search failed"
|
|
16576
|
+
},
|
|
16577
|
+
event: "match:search-failed",
|
|
16578
|
+
id: String(Date.now())
|
|
16579
|
+
});
|
|
16580
|
+
} catch {
|
|
16581
|
+
logger2.warn("Could not send error to client");
|
|
16582
|
+
}
|
|
16583
|
+
cleanup();
|
|
16446
16584
|
}
|
|
16447
|
-
|
|
16448
|
-
}
|
|
16449
|
-
|
|
16450
|
-
|
|
16451
|
-
});
|
|
16585
|
+
return streamPromise;
|
|
16586
|
+
});
|
|
16587
|
+
}
|
|
16588
|
+
);
|
|
16452
16589
|
}
|
|
16453
16590
|
function registerTokenRoutes(router) {
|
|
16454
16591
|
router.get("/api/clone-tokens/:token", async (c) => {
|
|
@@ -16928,13 +17065,13 @@ function registerYieldResourceStream(router, jobQueue) {
|
|
|
16928
17065
|
logger2.info("Generation started");
|
|
16929
17066
|
try {
|
|
16930
17067
|
await writeTypedSSE(stream, {
|
|
16931
|
-
data:
|
|
17068
|
+
data: {
|
|
16932
17069
|
status: "started",
|
|
16933
17070
|
referenceId: reference.id,
|
|
16934
17071
|
resourceName,
|
|
16935
17072
|
percentage: 0,
|
|
16936
17073
|
message: "Starting..."
|
|
16937
|
-
}
|
|
17074
|
+
},
|
|
16938
17075
|
event: "yield:progress",
|
|
16939
17076
|
id: String(Date.now())
|
|
16940
17077
|
});
|
|
@@ -16950,13 +17087,13 @@ function registerYieldResourceStream(router, jobQueue) {
|
|
|
16950
17087
|
logger2.info("Generation progress", { progress });
|
|
16951
17088
|
try {
|
|
16952
17089
|
await writeTypedSSE(stream, {
|
|
16953
|
-
data:
|
|
17090
|
+
data: {
|
|
16954
17091
|
status: progress.status,
|
|
16955
17092
|
referenceId: reference.id,
|
|
16956
17093
|
resourceName,
|
|
16957
17094
|
percentage: progress.percentage || 0,
|
|
16958
17095
|
message: progress.message || `${progress.status}...`
|
|
16959
|
-
}
|
|
17096
|
+
},
|
|
16960
17097
|
event: "yield:progress",
|
|
16961
17098
|
id: String(Date.now())
|
|
16962
17099
|
});
|
|
@@ -16972,7 +17109,7 @@ function registerYieldResourceStream(router, jobQueue) {
|
|
|
16972
17109
|
logger2.info("Generation completed");
|
|
16973
17110
|
try {
|
|
16974
17111
|
await writeTypedSSE(stream, {
|
|
16975
|
-
data:
|
|
17112
|
+
data: {
|
|
16976
17113
|
status: "complete",
|
|
16977
17114
|
referenceId: reference.id,
|
|
16978
17115
|
resourceName,
|
|
@@ -16980,7 +17117,7 @@ function registerYieldResourceStream(router, jobQueue) {
|
|
|
16980
17117
|
sourceResourceId: resourceIdParam,
|
|
16981
17118
|
percentage: 100,
|
|
16982
17119
|
message: "Draft resource created! Ready for review."
|
|
16983
|
-
}
|
|
17120
|
+
},
|
|
16984
17121
|
event: "yield:finished",
|
|
16985
17122
|
id: String(Date.now())
|
|
16986
17123
|
});
|
|
@@ -17012,12 +17149,12 @@ function registerYieldResourceStream(router, jobQueue) {
|
|
|
17012
17149
|
} catch (error) {
|
|
17013
17150
|
try {
|
|
17014
17151
|
await writeTypedSSE(stream, {
|
|
17015
|
-
data:
|
|
17152
|
+
data: {
|
|
17016
17153
|
status: "error",
|
|
17017
17154
|
referenceId: reference.id,
|
|
17018
17155
|
percentage: 0,
|
|
17019
17156
|
message: error instanceof Error ? error.message : "Generation failed"
|
|
17020
|
-
}
|
|
17157
|
+
},
|
|
17021
17158
|
event: "yield:failed",
|
|
17022
17159
|
id: String(Date.now())
|
|
17023
17160
|
});
|
|
@@ -17050,12 +17187,7 @@ function registerGatherAnnotationStream(router) {
|
|
|
17050
17187
|
if (!user) {
|
|
17051
17188
|
throw new HTTPException(401, { message: "Authentication required" });
|
|
17052
17189
|
}
|
|
17053
|
-
|
|
17054
|
-
annotationId: annotationId(annotationIdParam),
|
|
17055
|
-
resourceId: resourceId(resourceIdParam),
|
|
17056
|
-
options: { includeSourceContext: true, includeTargetContext: true, contextWindow }
|
|
17057
|
-
});
|
|
17058
|
-
logger2.info("Emitted gather:requested", { annotationId: annotationIdParam, contextWindow });
|
|
17190
|
+
const correlationId = body.correlationId ?? crypto.randomUUID();
|
|
17059
17191
|
c.header("X-Accel-Buffering", "no");
|
|
17060
17192
|
c.header("Cache-Control", "no-cache, no-transform");
|
|
17061
17193
|
return streamSSE(c, async (stream) => {
|
|
@@ -17075,7 +17207,7 @@ function registerGatherAnnotationStream(router) {
|
|
|
17075
17207
|
if (isStreamClosed) return;
|
|
17076
17208
|
try {
|
|
17077
17209
|
await writeTypedSSE(stream, {
|
|
17078
|
-
data:
|
|
17210
|
+
data: { message: event.message, percentage: event.percentage },
|
|
17079
17211
|
event: "gather:annotation-progress",
|
|
17080
17212
|
id: String(Date.now())
|
|
17081
17213
|
});
|
|
@@ -17086,11 +17218,11 @@ function registerGatherAnnotationStream(router) {
|
|
|
17086
17218
|
);
|
|
17087
17219
|
subscriptions.push(
|
|
17088
17220
|
eventBus2.get("gather:complete").subscribe(async (event) => {
|
|
17089
|
-
if (event.
|
|
17221
|
+
if (event.correlationId !== correlationId) return;
|
|
17090
17222
|
if (isStreamClosed) return;
|
|
17091
17223
|
try {
|
|
17092
17224
|
await writeTypedSSE(stream, {
|
|
17093
|
-
data:
|
|
17225
|
+
data: { correlationId: event.correlationId, annotationId: event.annotationId, response: event.response },
|
|
17094
17226
|
event: "gather:annotation-finished",
|
|
17095
17227
|
id: String(Date.now())
|
|
17096
17228
|
});
|
|
@@ -17101,11 +17233,11 @@ function registerGatherAnnotationStream(router) {
|
|
|
17101
17233
|
);
|
|
17102
17234
|
subscriptions.push(
|
|
17103
17235
|
eventBus2.get("gather:failed").subscribe(async (event) => {
|
|
17104
|
-
if (event.
|
|
17236
|
+
if (event.correlationId !== correlationId) return;
|
|
17105
17237
|
if (isStreamClosed) return;
|
|
17106
17238
|
try {
|
|
17107
17239
|
await writeTypedSSE(stream, {
|
|
17108
|
-
data:
|
|
17240
|
+
data: { correlationId: event.correlationId, annotationId: event.annotationId, error: event.error },
|
|
17109
17241
|
event: "gather:failed",
|
|
17110
17242
|
id: String(Date.now())
|
|
17111
17243
|
});
|
|
@@ -17114,6 +17246,13 @@ function registerGatherAnnotationStream(router) {
|
|
|
17114
17246
|
cleanup();
|
|
17115
17247
|
})
|
|
17116
17248
|
);
|
|
17249
|
+
eventBus2.get("gather:requested").next({
|
|
17250
|
+
correlationId,
|
|
17251
|
+
annotationId: annotationId(annotationIdParam),
|
|
17252
|
+
resourceId: resourceId(resourceIdParam),
|
|
17253
|
+
options: { includeSourceContext: true, includeTargetContext: true, contextWindow }
|
|
17254
|
+
});
|
|
17255
|
+
logger2.info("Emitted gather:requested", { annotationId: annotationIdParam, correlationId, contextWindow });
|
|
17117
17256
|
keepAliveInterval = setInterval(async () => {
|
|
17118
17257
|
if (isStreamClosed) {
|
|
17119
17258
|
clearInterval(keepAliveInterval);
|
|
@@ -17137,14 +17276,14 @@ function registerGatherAnnotationStream(router) {
|
|
|
17137
17276
|
}
|
|
17138
17277
|
function registerGetAnnotationHistory(router) {
|
|
17139
17278
|
router.get("/resources/:resourceId/annotations/:annotationId/history", async (c) => {
|
|
17140
|
-
const { resourceId:
|
|
17279
|
+
const { resourceId: resourceId21, annotationId: annotationId7 } = c.req.param();
|
|
17141
17280
|
const eventBus2 = c.get("eventBus");
|
|
17142
17281
|
const correlationId = crypto.randomUUID();
|
|
17143
17282
|
try {
|
|
17144
17283
|
const response = await eventBusRequest(
|
|
17145
17284
|
eventBus2,
|
|
17146
17285
|
"browse:annotation-history-requested",
|
|
17147
|
-
{ correlationId, resourceId: resourceId(
|
|
17286
|
+
{ correlationId, resourceId: resourceId(resourceId21), annotationId: annotationId(annotationId7) },
|
|
17148
17287
|
"browse:annotation-history-result",
|
|
17149
17288
|
"browse:annotation-history-failed"
|
|
17150
17289
|
);
|
|
@@ -17178,7 +17317,7 @@ function createResourcesRouter(jobQueue) {
|
|
|
17178
17317
|
registerAnnotateCommentsStream(resourcesRouter2, jobQueue);
|
|
17179
17318
|
registerAnnotateTagsStream(resourcesRouter2, jobQueue);
|
|
17180
17319
|
registerGetReferencedBy(resourcesRouter2);
|
|
17181
|
-
|
|
17320
|
+
registerMatchSearchStream(resourcesRouter2);
|
|
17182
17321
|
registerGetResourceAnnotations(resourcesRouter2);
|
|
17183
17322
|
registerCreateAnnotation(resourcesRouter2);
|
|
17184
17323
|
registerGetAnnotation(resourcesRouter2);
|
|
@@ -17208,12 +17347,6 @@ function registerGetAnnotationUri(router) {
|
|
|
17208
17347
|
if (!resourceIdParam) {
|
|
17209
17348
|
throw new HTTPException(400, { message: "resourceId query parameter is required" });
|
|
17210
17349
|
}
|
|
17211
|
-
if (prefersHtml(c)) {
|
|
17212
|
-
const frontendUrl = getFrontendUrl();
|
|
17213
|
-
const normalizedBase = frontendUrl.endsWith("/") ? frontendUrl.slice(0, -1) : frontendUrl;
|
|
17214
|
-
const redirectUrl = `${normalizedBase}/annotations/${id}?resourceId=${resourceIdParam}`;
|
|
17215
|
-
return c.redirect(redirectUrl, 302);
|
|
17216
|
-
}
|
|
17217
17350
|
const projection = await AnnotationContext.getResourceAnnotations(resourceId(resourceIdParam), kb);
|
|
17218
17351
|
const annotation = projection.annotations.find((a) => a.id === id);
|
|
17219
17352
|
if (!annotation) {
|
|
@@ -17239,8 +17372,8 @@ operationsRouter.get("/api/annotations/:id/context", async (c) => {
|
|
|
17239
17372
|
const { id } = c.req.param();
|
|
17240
17373
|
const query = c.req.query();
|
|
17241
17374
|
const { knowledgeSystem: { kb } } = c.get("makeMeaning");
|
|
17242
|
-
const
|
|
17243
|
-
if (!
|
|
17375
|
+
const resourceId21 = query.resourceId;
|
|
17376
|
+
if (!resourceId21) {
|
|
17244
17377
|
throw new HTTPException(400, { message: "resourceId query parameter is required" });
|
|
17245
17378
|
}
|
|
17246
17379
|
const contextBefore = query.contextBefore ? Number(query.contextBefore) : 100;
|
|
@@ -17254,7 +17387,7 @@ operationsRouter.get("/api/annotations/:id/context", async (c) => {
|
|
|
17254
17387
|
try {
|
|
17255
17388
|
const response = await AnnotationContext.getAnnotationContext(
|
|
17256
17389
|
annotationId(id),
|
|
17257
|
-
resourceId(
|
|
17390
|
+
resourceId(resourceId21),
|
|
17258
17391
|
contextBefore,
|
|
17259
17392
|
contextAfter,
|
|
17260
17393
|
kb
|
|
@@ -17280,14 +17413,14 @@ operationsRouter.get("/api/annotations/:id/summary", async (c) => {
|
|
|
17280
17413
|
const { id } = c.req.param();
|
|
17281
17414
|
const query = c.req.query();
|
|
17282
17415
|
const { knowledgeSystem: { gatherer } } = c.get("makeMeaning");
|
|
17283
|
-
const
|
|
17284
|
-
if (!
|
|
17416
|
+
const resourceId21 = query.resourceId;
|
|
17417
|
+
if (!resourceId21) {
|
|
17285
17418
|
throw new HTTPException(400, { message: "resourceId query parameter is required" });
|
|
17286
17419
|
}
|
|
17287
17420
|
try {
|
|
17288
17421
|
const response = await gatherer.generateAnnotationSummary(
|
|
17289
17422
|
annotationId(id),
|
|
17290
|
-
resourceId(
|
|
17423
|
+
resourceId(resourceId21)
|
|
17291
17424
|
);
|
|
17292
17425
|
return c.json(response);
|
|
17293
17426
|
} catch (error) {
|
|
@@ -17774,6 +17907,7 @@ app.use("*", async (c, next) => {
|
|
|
17774
17907
|
c.set("makeMeaning", makeMeaning);
|
|
17775
17908
|
await next();
|
|
17776
17909
|
});
|
|
17910
|
+
app.route("/", rootRouter);
|
|
17777
17911
|
app.route("/", healthRouter);
|
|
17778
17912
|
app.route("/", authRouter);
|
|
17779
17913
|
app.route("/", statusRouter);
|