@semiont/backend 0.4.2 → 0.4.3

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 CHANGED
@@ -1580,9 +1580,9 @@ var require_Subject = __commonJS({
1580
1580
  var ObjectUnsubscribedError_1 = require_ObjectUnsubscribedError();
1581
1581
  var arrRemove_1 = require_arrRemove();
1582
1582
  var errorContext_1 = require_errorContext();
1583
- var Subject = (function(_super) {
1584
- __extends(Subject2, _super);
1585
- function Subject2() {
1583
+ var Subject2 = (function(_super) {
1584
+ __extends(Subject3, _super);
1585
+ function Subject3() {
1586
1586
  var _this = _super.call(this) || this;
1587
1587
  _this.closed = false;
1588
1588
  _this.currentObservers = null;
@@ -1592,18 +1592,18 @@ var require_Subject = __commonJS({
1592
1592
  _this.thrownError = null;
1593
1593
  return _this;
1594
1594
  }
1595
- __name(Subject2, "Subject");
1596
- Subject2.prototype.lift = function(operator) {
1595
+ __name(Subject3, "Subject");
1596
+ Subject3.prototype.lift = function(operator) {
1597
1597
  var subject = new AnonymousSubject(this, this);
1598
1598
  subject.operator = operator;
1599
1599
  return subject;
1600
1600
  };
1601
- Subject2.prototype._throwIfClosed = function() {
1601
+ Subject3.prototype._throwIfClosed = function() {
1602
1602
  if (this.closed) {
1603
1603
  throw new ObjectUnsubscribedError_1.ObjectUnsubscribedError();
1604
1604
  }
1605
1605
  };
1606
- Subject2.prototype.next = function(value) {
1606
+ Subject3.prototype.next = function(value) {
1607
1607
  var _this = this;
1608
1608
  errorContext_1.errorContext(function() {
1609
1609
  var e_1, _a;
@@ -1631,7 +1631,7 @@ var require_Subject = __commonJS({
1631
1631
  }
1632
1632
  });
1633
1633
  };
1634
- Subject2.prototype.error = function(err) {
1634
+ Subject3.prototype.error = function(err) {
1635
1635
  var _this = this;
1636
1636
  errorContext_1.errorContext(function() {
1637
1637
  _this._throwIfClosed();
@@ -1645,7 +1645,7 @@ var require_Subject = __commonJS({
1645
1645
  }
1646
1646
  });
1647
1647
  };
1648
- Subject2.prototype.complete = function() {
1648
+ Subject3.prototype.complete = function() {
1649
1649
  var _this = this;
1650
1650
  errorContext_1.errorContext(function() {
1651
1651
  _this._throwIfClosed();
@@ -1658,11 +1658,11 @@ var require_Subject = __commonJS({
1658
1658
  }
1659
1659
  });
1660
1660
  };
1661
- Subject2.prototype.unsubscribe = function() {
1661
+ Subject3.prototype.unsubscribe = function() {
1662
1662
  this.isStopped = this.closed = true;
1663
1663
  this.observers = this.currentObservers = null;
1664
1664
  };
1665
- Object.defineProperty(Subject2.prototype, "observed", {
1665
+ Object.defineProperty(Subject3.prototype, "observed", {
1666
1666
  get: /* @__PURE__ */ __name(function() {
1667
1667
  var _a;
1668
1668
  return ((_a = this.observers) === null || _a === void 0 ? void 0 : _a.length) > 0;
@@ -1670,16 +1670,16 @@ var require_Subject = __commonJS({
1670
1670
  enumerable: false,
1671
1671
  configurable: true
1672
1672
  });
1673
- Subject2.prototype._trySubscribe = function(subscriber) {
1673
+ Subject3.prototype._trySubscribe = function(subscriber) {
1674
1674
  this._throwIfClosed();
1675
1675
  return _super.prototype._trySubscribe.call(this, subscriber);
1676
1676
  };
1677
- Subject2.prototype._subscribe = function(subscriber) {
1677
+ Subject3.prototype._subscribe = function(subscriber) {
1678
1678
  this._throwIfClosed();
1679
1679
  this._checkFinalizedStatuses(subscriber);
1680
1680
  return this._innerSubscribe(subscriber);
1681
1681
  };
1682
- Subject2.prototype._innerSubscribe = function(subscriber) {
1682
+ Subject3.prototype._innerSubscribe = function(subscriber) {
1683
1683
  var _this = this;
1684
1684
  var _a = this, hasError = _a.hasError, isStopped = _a.isStopped, observers = _a.observers;
1685
1685
  if (hasError || isStopped) {
@@ -1692,7 +1692,7 @@ var require_Subject = __commonJS({
1692
1692
  arrRemove_1.arrRemove(observers, subscriber);
1693
1693
  });
1694
1694
  };
1695
- Subject2.prototype._checkFinalizedStatuses = function(subscriber) {
1695
+ Subject3.prototype._checkFinalizedStatuses = function(subscriber) {
1696
1696
  var _a = this, hasError = _a.hasError, thrownError = _a.thrownError, isStopped = _a.isStopped;
1697
1697
  if (hasError) {
1698
1698
  subscriber.error(thrownError);
@@ -1700,17 +1700,17 @@ var require_Subject = __commonJS({
1700
1700
  subscriber.complete();
1701
1701
  }
1702
1702
  };
1703
- Subject2.prototype.asObservable = function() {
1703
+ Subject3.prototype.asObservable = function() {
1704
1704
  var observable = new Observable_1.Observable();
1705
1705
  observable.source = this;
1706
1706
  return observable;
1707
1707
  };
1708
- Subject2.create = function(destination, source) {
1708
+ Subject3.create = function(destination, source) {
1709
1709
  return new AnonymousSubject(destination, source);
1710
1710
  };
1711
- return Subject2;
1711
+ return Subject3;
1712
1712
  })(Observable_1.Observable);
1713
- exports$1.Subject = Subject;
1713
+ exports$1.Subject = Subject2;
1714
1714
  var AnonymousSubject = (function(_super) {
1715
1715
  __extends(AnonymousSubject2, _super);
1716
1716
  function AnonymousSubject2(destination, source) {
@@ -1737,7 +1737,7 @@ var require_Subject = __commonJS({
1737
1737
  return (_b = (_a = this.source) === null || _a === void 0 ? void 0 : _a.subscribe(subscriber)) !== null && _b !== void 0 ? _b : Subscription_1.EMPTY_SUBSCRIPTION;
1738
1738
  };
1739
1739
  return AnonymousSubject2;
1740
- })(Subject);
1740
+ })(Subject2);
1741
1741
  exports$1.AnonymousSubject = AnonymousSubject;
1742
1742
  }
1743
1743
  });
@@ -12854,6 +12854,48 @@ var openapi_default = {
12854
12854
  ],
12855
12855
  description: "Annotation body type - TextualBody for textual content, SpecificResource for resource links"
12856
12856
  },
12857
+ BeckonRequest: {
12858
+ type: "object",
12859
+ properties: {
12860
+ resourceId: {
12861
+ type: "string",
12862
+ description: "Resource to direct attention at"
12863
+ },
12864
+ annotationId: {
12865
+ type: "string",
12866
+ description: "Specific annotation within the resource (optional)"
12867
+ },
12868
+ message: {
12869
+ type: "string",
12870
+ description: "Human-readable context for the participant (max 500 chars)",
12871
+ maxLength: 500
12872
+ }
12873
+ },
12874
+ required: [
12875
+ "resourceId"
12876
+ ]
12877
+ },
12878
+ BeckonResponse: {
12879
+ type: "object",
12880
+ properties: {
12881
+ participant: {
12882
+ type: "string",
12883
+ description: "Username or agent identifier that was beckoned"
12884
+ },
12885
+ resourceId: {
12886
+ type: "string",
12887
+ description: "Resource the attention was directed at"
12888
+ },
12889
+ annotationId: {
12890
+ type: "string",
12891
+ description: "Annotation the attention was directed at (if provided)"
12892
+ }
12893
+ },
12894
+ required: [
12895
+ "participant",
12896
+ "resourceId"
12897
+ ]
12898
+ },
12857
12899
  BulkAddEntityTypesRequest: {
12858
12900
  type: "object",
12859
12901
  properties: {
@@ -13333,6 +13375,73 @@ var openapi_default = {
13333
13375
  "entityTypes"
13334
13376
  ]
13335
13377
  },
13378
+ GatherResourceStreamRequest: {
13379
+ type: "object",
13380
+ properties: {
13381
+ depth: {
13382
+ type: "integer",
13383
+ minimum: 1,
13384
+ maximum: 3,
13385
+ description: "Graph traversal depth (default: 2)"
13386
+ },
13387
+ maxResources: {
13388
+ type: "integer",
13389
+ minimum: 1,
13390
+ maximum: 20,
13391
+ description: "Maximum related resources to include (default: 10)"
13392
+ },
13393
+ includeContent: {
13394
+ type: "boolean",
13395
+ description: "Include full resource content (default: true)"
13396
+ },
13397
+ includeSummary: {
13398
+ type: "boolean",
13399
+ description: "Include AI-generated summary (default: false)"
13400
+ }
13401
+ }
13402
+ },
13403
+ GatherAnnotationStreamRequest: {
13404
+ type: "object",
13405
+ properties: {
13406
+ contextWindow: {
13407
+ type: "integer",
13408
+ minimum: 100,
13409
+ maximum: 5e3,
13410
+ description: "Characters of surrounding text context (default: 1000)"
13411
+ }
13412
+ }
13413
+ },
13414
+ BindAnnotationStreamRequest: {
13415
+ type: "object",
13416
+ properties: {
13417
+ resourceId: {
13418
+ type: "string",
13419
+ description: "Resource ID containing the annotation (required for O(1) Layer 3 lookup)"
13420
+ },
13421
+ operations: {
13422
+ type: "array",
13423
+ items: {
13424
+ oneOf: [
13425
+ {
13426
+ $ref: "#/components/schemas/BodyOperationAdd"
13427
+ },
13428
+ {
13429
+ $ref: "#/components/schemas/BodyOperationRemove"
13430
+ },
13431
+ {
13432
+ $ref: "#/components/schemas/BodyOperationReplace"
13433
+ }
13434
+ ]
13435
+ },
13436
+ minItems: 1,
13437
+ description: "Array of body modification operations to apply"
13438
+ }
13439
+ },
13440
+ required: [
13441
+ "resourceId",
13442
+ "operations"
13443
+ ]
13444
+ },
13336
13445
  AnnotateHighlightsStreamRequest: {
13337
13446
  type: "object",
13338
13447
  properties: {
@@ -14220,20 +14329,12 @@ var openapi_default = {
14220
14329
  type: "string",
14221
14330
  enum: [
14222
14331
  "assessing",
14223
- "bookmarking",
14224
- "classifying",
14225
14332
  "commenting",
14226
- "describing",
14227
- "editing",
14228
14333
  "highlighting",
14229
- "identifying",
14230
14334
  "linking",
14231
- "moderating",
14232
- "questioning",
14233
- "replying",
14234
14335
  "tagging"
14235
14336
  ],
14236
- description: "W3C Web Annotation motivation vocabulary - https://www.w3.org/TR/annotation-vocab/#motivation"
14337
+ description: "Semiont-supported W3C Web Annotation motivations - https://www.w3.org/TR/annotation-vocab/#motivation"
14237
14338
  },
14238
14339
  OAuthConfigResponse: {
14239
14340
  type: "object",
@@ -14803,7 +14904,7 @@ var openapi_default = {
14803
14904
  description: "IRI of the target resource"
14804
14905
  },
14805
14906
  purpose: {
14806
- $ref: "#/components/schemas/Motivation",
14907
+ $ref: "#/components/schemas/BodyPurpose",
14807
14908
  description: "Why this body is included"
14808
14909
  }
14809
14910
  },
@@ -14916,7 +15017,7 @@ var openapi_default = {
14916
15017
  description: "The text content (e.g., entity type name)"
14917
15018
  },
14918
15019
  purpose: {
14919
- $ref: "#/components/schemas/Motivation",
15020
+ $ref: "#/components/schemas/BodyPurpose",
14920
15021
  description: "Why this body is included"
14921
15022
  },
14922
15023
  format: {
@@ -15179,6 +15280,25 @@ var openapi_default = {
15179
15280
  "value"
15180
15281
  ]
15181
15282
  },
15283
+ BodyPurpose: {
15284
+ type: "string",
15285
+ enum: [
15286
+ "assessing",
15287
+ "bookmarking",
15288
+ "classifying",
15289
+ "commenting",
15290
+ "describing",
15291
+ "editing",
15292
+ "highlighting",
15293
+ "identifying",
15294
+ "linking",
15295
+ "moderating",
15296
+ "questioning",
15297
+ "replying",
15298
+ "tagging"
15299
+ ],
15300
+ description: "W3C Web Annotation body purpose vocabulary - https://www.w3.org/TR/annotation-vocab/#motivation"
15301
+ },
15182
15302
  GatheredContext: {
15183
15303
  type: "object",
15184
15304
  description: "Context gathered for an annotation. Includes source document excerpts, metadata, and graph-derived context. Used by both Find (bind) and Generate (yield) flows.",
@@ -16467,7 +16587,7 @@ function registerCreateResource(router) {
16467
16587
  const arrayBuffer = await file.arrayBuffer();
16468
16588
  const contentBuffer = Buffer.from(arrayBuffer);
16469
16589
  const eventBus2 = c.get("eventBus");
16470
- const resourceId20 = await ResourceOperations.createResource({
16590
+ const resourceId21 = await ResourceOperations.createResource({
16471
16591
  name,
16472
16592
  content: contentBuffer,
16473
16593
  format,
@@ -16477,7 +16597,7 @@ function registerCreateResource(router) {
16477
16597
  storageUri: storageUri || void 0
16478
16598
  }, userId(user.id), eventBus2);
16479
16599
  return c.json({
16480
- resourceId: resourceId20
16600
+ resourceId: resourceId21
16481
16601
  }, 202);
16482
16602
  });
16483
16603
  }
@@ -19096,13 +19216,13 @@ function registerYieldResourceStream(router, jobQueue) {
19096
19216
  __name(registerYieldResourceStream, "registerYieldResourceStream");
19097
19217
  function registerGetAnnotationHistory(router) {
19098
19218
  router.get("/resources/:resourceId/annotations/:annotationId/history", async (c) => {
19099
- const { resourceId: resourceId20, annotationId: annotationId6 } = c.req.param();
19219
+ const { resourceId: resourceId21, annotationId: annotationId6 } = c.req.param();
19100
19220
  const eventBus2 = c.get("eventBus");
19101
19221
  const correlationId = crypto.randomUUID();
19102
19222
  try {
19103
19223
  const response = await eventBusRequest(eventBus2, "browse:annotation-history-requested", {
19104
19224
  correlationId,
19105
- resourceId: resourceId(resourceId20),
19225
+ resourceId: resourceId(resourceId21),
19106
19226
  annotationId: annotationId(annotationId6)
19107
19227
  }, "browse:annotation-history-result", "browse:annotation-history-failed");
19108
19228
  return c.json(response);
@@ -19211,8 +19331,8 @@ operationsRouter.get("/api/annotations/:id/context", async (c) => {
19211
19331
  const { id } = c.req.param();
19212
19332
  const query = c.req.query();
19213
19333
  const { kb } = c.get("makeMeaning");
19214
- const resourceId20 = query.resourceId;
19215
- if (!resourceId20) {
19334
+ const resourceId21 = query.resourceId;
19335
+ if (!resourceId21) {
19216
19336
  throw new HTTPException(400, {
19217
19337
  message: "resourceId query parameter is required"
19218
19338
  });
@@ -19230,7 +19350,7 @@ operationsRouter.get("/api/annotations/:id/context", async (c) => {
19230
19350
  });
19231
19351
  }
19232
19352
  try {
19233
- const response = await AnnotationContext.getAnnotationContext(annotationId(id), resourceId(resourceId20), contextBefore, contextAfter, kb);
19353
+ const response = await AnnotationContext.getAnnotationContext(annotationId(id), resourceId(resourceId21), contextBefore, contextAfter, kb);
19234
19354
  return c.json(response);
19235
19355
  } catch (error) {
19236
19356
  if (error instanceof Error && error.message === "Annotation not found") {
@@ -19260,14 +19380,14 @@ operationsRouter.get("/api/annotations/:id/summary", async (c) => {
19260
19380
  const { id } = c.req.param();
19261
19381
  const query = c.req.query();
19262
19382
  const { kb, gathererInferenceClient: inferenceClient } = c.get("makeMeaning");
19263
- const resourceId20 = query.resourceId;
19264
- if (!resourceId20) {
19383
+ const resourceId21 = query.resourceId;
19384
+ if (!resourceId21) {
19265
19385
  throw new HTTPException(400, {
19266
19386
  message: "resourceId query parameter is required"
19267
19387
  });
19268
19388
  }
19269
19389
  try {
19270
- const response = await AnnotationContext.generateAnnotationSummary(annotationId(id), resourceId(resourceId20), kb, inferenceClient);
19390
+ const response = await AnnotationContext.generateAnnotationSummary(annotationId(id), resourceId(resourceId21), kb, inferenceClient);
19271
19391
  return c.json(response);
19272
19392
  } catch (error) {
19273
19393
  if (error instanceof Error && error.message === "Annotation not found") {
@@ -19472,6 +19592,122 @@ function createJobsRouter(_jobQueue, authMiddleware2) {
19472
19592
  }
19473
19593
  __name(createJobsRouter, "createJobsRouter");
19474
19594
 
19595
+ // src/routes/participants/attention-channels.ts
19596
+ var import_rxjs4 = __toESM(require_cjs());
19597
+ var channels = /* @__PURE__ */ new Map();
19598
+ function getOrCreateChannel(participantId) {
19599
+ if (!channels.has(participantId)) {
19600
+ channels.set(participantId, new import_rxjs4.Subject());
19601
+ }
19602
+ return channels.get(participantId);
19603
+ }
19604
+ __name(getOrCreateChannel, "getOrCreateChannel");
19605
+ function removeChannel(participantId) {
19606
+ channels.get(participantId)?.complete();
19607
+ channels.delete(participantId);
19608
+ }
19609
+ __name(removeChannel, "removeChannel");
19610
+
19611
+ // src/routes/participants/routes/beckon.ts
19612
+ function registerBeckon(router) {
19613
+ router.post("/api/participants/:id/attention", validateRequestBody("BeckonRequest"), async (c) => {
19614
+ const { id: participantId } = c.req.param();
19615
+ const request = c.get("validatedBody");
19616
+ getOrCreateChannel(participantId).next({
19617
+ resourceId: request.resourceId,
19618
+ ...request.annotationId ? {
19619
+ annotationId: request.annotationId
19620
+ } : {}
19621
+ });
19622
+ return c.json({
19623
+ participant: participantId,
19624
+ resourceId: resourceId(request.resourceId),
19625
+ ...request.annotationId ? {
19626
+ annotationId: request.annotationId
19627
+ } : {}
19628
+ }, 202);
19629
+ });
19630
+ }
19631
+ __name(registerBeckon, "registerBeckon");
19632
+ init_logger();
19633
+ function registerAttentionStream(router) {
19634
+ router.get("/api/participants/me/attention-stream", async (c) => {
19635
+ const user = c.get("user");
19636
+ const participantId = user.id;
19637
+ const logger2 = getLogger().child({
19638
+ component: "attention-stream",
19639
+ participantId
19640
+ });
19641
+ logger2.info("Client connecting to attention stream");
19642
+ return streamSSE(c, async (stream) => {
19643
+ await stream.writeSSE({
19644
+ data: JSON.stringify({
19645
+ type: "connected",
19646
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
19647
+ message: "Attention stream connected"
19648
+ }),
19649
+ event: SSE_STREAM_CONNECTED,
19650
+ id: String(Date.now())
19651
+ });
19652
+ let isStreamClosed = false;
19653
+ let keepAliveInterval = null;
19654
+ let closeStreamCallback = null;
19655
+ const streamPromise = new Promise((resolve) => {
19656
+ closeStreamCallback = resolve;
19657
+ });
19658
+ const cleanup = /* @__PURE__ */ __name(() => {
19659
+ if (isStreamClosed) return;
19660
+ isStreamClosed = true;
19661
+ if (keepAliveInterval) clearInterval(keepAliveInterval);
19662
+ subscription.unsubscribe();
19663
+ removeChannel(participantId);
19664
+ closeStreamCallback?.();
19665
+ }, "cleanup");
19666
+ const subject = getOrCreateChannel(participantId);
19667
+ const subscription = subject.subscribe(async (signal) => {
19668
+ if (isStreamClosed) return;
19669
+ try {
19670
+ await stream.writeSSE({
19671
+ data: JSON.stringify(signal),
19672
+ event: "beckon:focus",
19673
+ id: String(Date.now())
19674
+ });
19675
+ } catch (error) {
19676
+ logger2.error("Error writing beckon signal to attention stream", {
19677
+ error
19678
+ });
19679
+ cleanup();
19680
+ }
19681
+ });
19682
+ keepAliveInterval = setInterval(async () => {
19683
+ if (isStreamClosed) {
19684
+ if (keepAliveInterval) clearInterval(keepAliveInterval);
19685
+ return;
19686
+ }
19687
+ try {
19688
+ await stream.writeSSE({
19689
+ data: ":keep-alive"
19690
+ });
19691
+ } catch {
19692
+ cleanup();
19693
+ }
19694
+ }, 3e4);
19695
+ c.req.raw.signal.addEventListener("abort", () => {
19696
+ logger2.info("Client disconnected from attention stream");
19697
+ cleanup();
19698
+ });
19699
+ return streamPromise;
19700
+ });
19701
+ });
19702
+ }
19703
+ __name(registerAttentionStream, "registerAttentionStream");
19704
+
19705
+ // src/routes/participants/index.ts
19706
+ var participantsRouter = new Hono();
19707
+ participantsRouter.use("/api/participants/*", authMiddleware);
19708
+ registerBeckon(participantsRouter);
19709
+ registerAttentionStream(participantsRouter);
19710
+
19475
19711
  // src/middleware/security-headers.ts
19476
19712
  var securityHeaders = /* @__PURE__ */ __name(() => {
19477
19713
  return async (c, next) => {
@@ -19636,6 +19872,7 @@ app.route("/", entityTypesRouter);
19636
19872
  app.route("/", globalEventsRouter);
19637
19873
  var jobsRouter = createJobsRouter(makeMeaning.jobQueue, authMiddleware);
19638
19874
  app.route("/", jobsRouter);
19875
+ app.route("/", participantsRouter);
19639
19876
  app.get("/api", (c) => {
19640
19877
  const acceptHeader = c.req.header("Accept") || "";
19641
19878
  const userAgent = c.req.header("User-Agent") || "";