@semiont/graph 0.5.30 → 0.5.32

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.d.ts CHANGED
@@ -84,6 +84,40 @@ declare function createGraphDatabase(config: GraphDatabaseConfig): GraphDatabase
84
84
  declare function getGraphDatabase(graphConfig: GraphServiceConfig): Promise<GraphDatabase>;
85
85
  declare function closeGraphDatabase(): Promise<void>;
86
86
 
87
+ /**
88
+ * The annotation codec — the one module that decides how a W3C annotation
89
+ * becomes stored properties and back.
90
+ *
91
+ * Every store keeps its own dialect (Cypher parameters, Gremlin
92
+ * `.property()` chains, a Map) and its own way of flattening what the driver
93
+ * hands back into a property bag. What none of them owns any more is the
94
+ * SHAPE: the W3C envelope, which fields are required, how a selector is
95
+ * serialized, how the body array is reconstructed from entity tags and a
96
+ * linking source. Those lived in three near-verbatim copies that disagreed
97
+ * in four places, and each disagreement was a bug — a resource-level
98
+ * annotation came back carrying `selector: {}`, which is not a legal
99
+ * selector, and a motivation-less row was silently relabelled `'linking'`.
100
+ *
101
+ * The codec manufactures nothing. Absence is stored as absence and read back
102
+ * as absence, in both directions.
103
+ */
104
+
105
+ /**
106
+ * What the graph is SUPPOSED to hold for this annotation — the codec's own
107
+ * statement of it, obtained by round-tripping through both halves.
108
+ *
109
+ * The graph is a purpose-built projection, not a copy of the views: it stores
110
+ * what graph queries need and nothing else. `wasAttributedTo`, for instance,
111
+ * rides on almost every annotation in the log and the encoder deliberately
112
+ * writes none of it. So "is the graph correct?" cannot be answered by comparing
113
+ * it to a view — only by comparing it to what this module says it should be.
114
+ *
115
+ * Callers get a value scoped to exactly the fields the encoder writes, in the
116
+ * decoded shape, free of any store's physical dialect. Widen or narrow the
117
+ * encoder and this follows automatically; there is no second list to maintain.
118
+ */
119
+ declare function intendedGraphAnnotation(annotation: Annotation): Annotation;
120
+
87
121
  declare class Neo4jGraphDatabase implements GraphDatabase {
88
122
  private driver;
89
123
  private neo4j;
@@ -375,5 +409,5 @@ declare class MemoryGraphDatabase implements GraphDatabase {
375
409
  clearDatabase(): Promise<void>;
376
410
  }
377
411
 
378
- export { JanusGraphDatabase, MemoryGraphDatabase, Neo4jGraphDatabase, NeptuneGraphDatabase, closeGraphDatabase, compareByRecencyThenId, createGraphDatabase, getGraphDatabase };
412
+ export { JanusGraphDatabase, MemoryGraphDatabase, Neo4jGraphDatabase, NeptuneGraphDatabase, closeGraphDatabase, compareByRecencyThenId, createGraphDatabase, getGraphDatabase, intendedGraphAnnotation };
379
413
  export type { GraphDatabase };
package/dist/index.js CHANGED
@@ -56,18 +56,19 @@ function queryResources(all, filter) {
56
56
  }
57
57
 
58
58
  // src/implementations/neptune.ts
59
- import { getEntityTypes } from "@semiont/ontology";
59
+ import { getEntityTypes as getEntityTypes2 } from "@semiont/ontology";
60
60
 
61
61
  // src/annotation-codec.ts
62
62
  import { annotationId as makeAnnotationId } from "@semiont/core";
63
63
  import { getBodySource, getExactText, getTargetSelector, getTargetSource } from "@semiont/core";
64
+ import { getEntityTypes } from "@semiont/ontology";
64
65
  function storedAnnotationType(motivation) {
65
66
  return motivation === "highlighting" ? "TextualBody" : "SpecificResource";
66
67
  }
67
68
  function motivationForCategory(category) {
68
69
  return category === "highlight" ? "highlighting" : "linking";
69
70
  }
70
- function buildAnnotation(input, created) {
71
+ function buildAnnotation(input) {
71
72
  const annotation = {
72
73
  "@context": "http://www.w3.org/ns/anno.jsonld",
73
74
  type: "Annotation",
@@ -75,7 +76,7 @@ function buildAnnotation(input, created) {
75
76
  motivation: input.motivation,
76
77
  target: input.target,
77
78
  creator: input.creator,
78
- created
79
+ created: input.created
79
80
  };
80
81
  if (input.body && (!Array.isArray(input.body) || input.body.length > 0)) {
81
82
  annotation.body = input.body;
@@ -87,7 +88,6 @@ function encodeAnnotation(annotation) {
87
88
  const bodySource = getBodySource(annotation.body);
88
89
  const resourceId = getTargetSource(annotation.target);
89
90
  if (!resourceId) throw new Error(`Annotation ${annotation.id} has no target source`);
90
- if (!annotation.created) throw new Error(`Annotation ${annotation.id} has no created timestamp`);
91
91
  const props = {
92
92
  id: annotation.id,
93
93
  resourceId,
@@ -154,6 +154,9 @@ function decodeSelector(raw) {
154
154
  if (!parsed || Object.keys(parsed).length === 0) return void 0;
155
155
  return parsed;
156
156
  }
157
+ function intendedGraphAnnotation(annotation) {
158
+ return decodeAnnotation(encodeAnnotation(annotation), getEntityTypes(annotation));
159
+ }
157
160
 
158
161
  // src/implementations/neptune.ts
159
162
  import { v4 as uuidv4 } from "uuid";
@@ -167,7 +170,7 @@ var cardinality;
167
170
  var __;
168
171
  async function loadDependencies() {
169
172
  if (!NeptuneClient) {
170
- const neptuneModule = await import("./dist-es-F44WH2AS.js");
173
+ const neptuneModule = await import("./dist-es-7XA2K3QN.js");
171
174
  NeptuneClient = neptuneModule.NeptuneClient;
172
175
  DescribeDBClustersCommand = neptuneModule.DescribeDBClustersCommand;
173
176
  }
@@ -435,11 +438,11 @@ var NeptuneGraphDatabase = class {
435
438
  }
436
439
  }
437
440
  async createAnnotation(input) {
438
- const annotation = buildAnnotation(input, (/* @__PURE__ */ new Date()).toISOString());
441
+ const annotation = buildAnnotation(input);
439
442
  const props = encodeAnnotation(annotation);
440
443
  const targetSource = props.resourceId;
441
444
  const bodySource = props.source;
442
- const entityTypes = getEntityTypes(input);
445
+ const entityTypes = getEntityTypes2(input);
443
446
  try {
444
447
  let vertex = this.g.addV("Annotation");
445
448
  for (const [key, value] of Object.entries(props)) {
@@ -490,7 +493,7 @@ var NeptuneGraphDatabase = class {
490
493
  }
491
494
  if (updates.body !== void 0) {
492
495
  const bodySource = getBodySource2(updates.body);
493
- const entityTypes2 = getEntityTypes({ body: updates.body });
496
+ const entityTypes2 = getEntityTypes2({ body: updates.body });
494
497
  if (bodySource) {
495
498
  traversal = traversal.property("source", bodySource);
496
499
  }
@@ -863,7 +866,7 @@ var NeptuneGraphDatabase = class {
863
866
  // src/implementations/neo4j.ts
864
867
  import { v4 as uuidv42 } from "uuid";
865
868
  import { getPrimaryRepresentation as getPrimaryRepresentation2, getStorageUri as getStorageUri3 } from "@semiont/core";
866
- import { getEntityTypes as getEntityTypes2 } from "@semiont/ontology";
869
+ import { getEntityTypes as getEntityTypes3 } from "@semiont/ontology";
867
870
  function motivationToLabel(motivation) {
868
871
  return motivation.charAt(0).toUpperCase() + motivation.slice(1);
869
872
  }
@@ -989,7 +992,7 @@ var Neo4jGraphDatabase = class {
989
992
  d.entityTypes = $entityTypes,
990
993
  d.format = $format,
991
994
  d.archived = $archived,
992
- d.created = datetime($created),
995
+ d.created = $created,
993
996
  d.creator = $creator,
994
997
  d.contentChecksum = $contentChecksum,
995
998
  d.sourceAnnotationId = $sourceAnnotationId,
@@ -1129,16 +1132,16 @@ var Neo4jGraphDatabase = class {
1129
1132
  async createAnnotation(input) {
1130
1133
  const session = this.getSession();
1131
1134
  try {
1132
- const annotation = buildAnnotation(input, (/* @__PURE__ */ new Date()).toISOString());
1135
+ const annotation = buildAnnotation(input);
1133
1136
  const props = encodeAnnotation(annotation);
1134
1137
  const targetSource = props.resourceId;
1135
1138
  const bodySource = props.source;
1136
- const entityTypes = getEntityTypes2(input);
1139
+ const entityTypes = getEntityTypes3(input);
1137
1140
  const motivationLabel = motivationToLabel(annotation.motivation);
1138
1141
  const cypher = bodySource ? `MATCH (from:Resource {id: $targetSource})
1139
1142
  MATCH (to:Resource {id: $bodySource})
1140
1143
  CREATE (a:Annotation:${motivationLabel})
1141
- SET a = $props, a.created = datetime($created)
1144
+ SET a = $props
1142
1145
  CREATE (a)-[:BELONGS_TO]->(from)
1143
1146
  CREATE (a)-[:REFERENCES]->(to)
1144
1147
  FOREACH (entityType IN $entityTypes |
@@ -1147,7 +1150,7 @@ var Neo4jGraphDatabase = class {
1147
1150
  )
1148
1151
  RETURN a` : `MATCH (d:Resource {id: $targetSource})
1149
1152
  CREATE (a:Annotation:${motivationLabel})
1150
- SET a = $props, a.created = datetime($created)
1153
+ SET a = $props
1151
1154
  CREATE (a)-[:BELONGS_TO]->(d)
1152
1155
  FOREACH (entityType IN $entityTypes |
1153
1156
  MERGE (et:EntityType {name: entityType})
@@ -1156,7 +1159,6 @@ var Neo4jGraphDatabase = class {
1156
1159
  RETURN a`;
1157
1160
  const result = await session.run(cypher, {
1158
1161
  props,
1159
- created: annotation.created,
1160
1162
  targetSource,
1161
1163
  bodySource: bodySource ?? null,
1162
1164
  entityTypes
@@ -1646,7 +1648,7 @@ var Neo4jGraphDatabase = class {
1646
1648
  d.entityTypes = r.entityTypes,
1647
1649
  d.format = r.format,
1648
1650
  d.archived = r.archived,
1649
- d.created = datetime(r.created),
1651
+ d.created = r.created,
1650
1652
  d.creator = r.creator,
1651
1653
  d.contentChecksum = r.contentChecksum,
1652
1654
  d.sourceAnnotationId = r.sourceAnnotationId,
@@ -1789,7 +1791,7 @@ function normalizeProperties2(props) {
1789
1791
  // src/implementations/janusgraph.ts
1790
1792
  import { resourceId as makeResourceId } from "@semiont/core";
1791
1793
  import { getBodySource as getBodySource3, getPrimaryRepresentation as getPrimaryRepresentation3, getResourceId as getResourceId2, getStorageUri as getStorageUri4 } from "@semiont/core";
1792
- import { getEntityTypes as getEntityTypes3 } from "@semiont/ontology";
1794
+ import { getEntityTypes as getEntityTypes4 } from "@semiont/ontology";
1793
1795
  import { v4 as uuidv43 } from "uuid";
1794
1796
  function getPropertyValue(props, key) {
1795
1797
  if (!props[key]) return void 0;
@@ -1951,11 +1953,11 @@ var JanusGraphDatabase = class {
1951
1953
  return queryResources(docs.map((v) => this.vertexToResource(v)), filter);
1952
1954
  }
1953
1955
  async createAnnotation(input) {
1954
- const annotation = buildAnnotation(input, (/* @__PURE__ */ new Date()).toISOString());
1956
+ const annotation = buildAnnotation(input);
1955
1957
  const props = encodeAnnotation(annotation);
1956
1958
  const targetSource = props.resourceId;
1957
1959
  const bodySource = props.source;
1958
- const entityTypes = getEntityTypes3(input);
1960
+ const entityTypes = getEntityTypes4(input);
1959
1961
  let vertex = this.g.addV("Annotation");
1960
1962
  for (const [key, value] of Object.entries(props)) {
1961
1963
  vertex = vertex.property(key, value);
@@ -2000,7 +2002,7 @@ var JanusGraphDatabase = class {
2000
2002
  }
2001
2003
  if (updates.body !== void 0) {
2002
2004
  const bodySource = getBodySource3(updates.body);
2003
- const entityTypes = getEntityTypes3({ body: updates.body });
2005
+ const entityTypes = getEntityTypes4({ body: updates.body });
2004
2006
  if (bodySource) {
2005
2007
  await traversalQuery.property("source", bodySource).next();
2006
2008
  }
@@ -2092,11 +2094,11 @@ var JanusGraphDatabase = class {
2092
2094
  });
2093
2095
  if (entityTypes && entityTypes.length > 0) {
2094
2096
  return annotations.filter((ann) => {
2095
- const annEntityTypes = getEntityTypes3(ann);
2097
+ const annEntityTypes = getEntityTypes4(ann);
2096
2098
  return annEntityTypes.some((type) => entityTypes.includes(type));
2097
2099
  });
2098
2100
  }
2099
- return annotations.filter((ann) => getEntityTypes3(ann).length > 0);
2101
+ return annotations.filter((ann) => getEntityTypes4(ann).length > 0);
2100
2102
  }
2101
2103
  async getResourceAnnotations(resourceId) {
2102
2104
  const { annotations } = await this.listAnnotations({ resourceId });
@@ -2164,7 +2166,7 @@ var JanusGraphDatabase = class {
2164
2166
  const annotations = await this.fetchAnnotationsWithEntityTypes(anns);
2165
2167
  const highlights = annotations.filter((a) => a.motivation === "highlighting");
2166
2168
  const references = annotations.filter((a) => a.motivation === "linking");
2167
- const entityReferences = references.filter((a) => getEntityTypes3(a).length > 0);
2169
+ const entityReferences = references.filter((a) => getEntityTypes4(a).length > 0);
2168
2170
  return {
2169
2171
  resourceCount: resources.length,
2170
2172
  annotationCount: annotations.length,
@@ -2269,7 +2271,7 @@ var JanusGraphDatabase = class {
2269
2271
  import { resourceId as makeResourceId2 } from "@semiont/core";
2270
2272
  import { v4 as uuidv44 } from "uuid";
2271
2273
  import { getBodySource as getBodySource4, getTargetSource as getTargetSource3, getResourceId as getResourceId3, getPrimaryRepresentation as getPrimaryRepresentation4, getResourceEntityTypes as getResourceEntityTypes2 } from "@semiont/core";
2272
- import { getEntityTypes as getEntityTypes4 } from "@semiont/ontology";
2274
+ import { getEntityTypes as getEntityTypes5 } from "@semiont/ontology";
2273
2275
  var MemoryGraphDatabase = class {
2274
2276
  connected = false;
2275
2277
  logger;
@@ -2323,8 +2325,8 @@ var MemoryGraphDatabase = class {
2323
2325
  async createAnnotation(input) {
2324
2326
  const id = input.id;
2325
2327
  const annotation = decodeAnnotation(
2326
- encodeAnnotation(buildAnnotation(input, (/* @__PURE__ */ new Date()).toISOString())),
2327
- getEntityTypes4(input)
2328
+ encodeAnnotation(buildAnnotation(input)),
2329
+ getEntityTypes5(input)
2328
2330
  );
2329
2331
  this.annotations.set(id, annotation);
2330
2332
  this.logger?.debug("Created annotation", {
@@ -2391,9 +2393,9 @@ var MemoryGraphDatabase = class {
2391
2393
  }
2392
2394
  async getEntityReferences(resourceId, entityTypes) {
2393
2395
  const resourceIdStr = String(resourceId);
2394
- let refs = Array.from(this.annotations.values()).filter((sel) => getTargetSource3(sel.target) === resourceIdStr && getEntityTypes4(sel).length > 0);
2396
+ let refs = Array.from(this.annotations.values()).filter((sel) => getTargetSource3(sel.target) === resourceIdStr && getEntityTypes5(sel).length > 0);
2395
2397
  if (entityTypes && entityTypes.length > 0) {
2396
- refs = refs.filter((sel) => getEntityTypes4(sel).some((type) => entityTypes.includes(type)));
2398
+ refs = refs.filter((sel) => getEntityTypes5(sel).some((type) => entityTypes.includes(type)));
2397
2399
  }
2398
2400
  return refs;
2399
2401
  }
@@ -2484,7 +2486,7 @@ var MemoryGraphDatabase = class {
2484
2486
  const highlightCount = annotations.filter((a) => a.motivation === "highlighting").length;
2485
2487
  const referenceCount = annotations.filter((a) => a.motivation === "linking").length;
2486
2488
  const entityReferenceCount = annotations.filter(
2487
- (a) => a.motivation === "linking" && getEntityTypes4(a).length > 0
2489
+ (a) => a.motivation === "linking" && getEntityTypes5(a).length > 0
2488
2490
  ).length;
2489
2491
  return {
2490
2492
  resourceCount: this.resources.size,
@@ -2663,6 +2665,7 @@ export {
2663
2665
  closeGraphDatabase,
2664
2666
  compareByRecencyThenId,
2665
2667
  createGraphDatabase,
2666
- getGraphDatabase
2668
+ getGraphDatabase,
2669
+ intendedGraphAnnotation
2667
2670
  };
2668
2671
  //# sourceMappingURL=index.js.map