datanotes 3.0.0 → 3.1.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.
Files changed (60) hide show
  1. package/README.md +1 -5
  2. package/dist/api/client.d.cts +37 -4
  3. package/dist/api/client.d.ts +37 -4
  4. package/dist/api/index.cjs +388 -52
  5. package/dist/api/index.d.cts +3 -2
  6. package/dist/api/index.d.ts +3 -2
  7. package/dist/api/index.js +388 -52
  8. package/dist/api/mcp.cjs +6 -3
  9. package/dist/api/mcp.js +6 -3
  10. package/dist/api/otlp.d.cts +63 -15
  11. package/dist/api/otlp.d.ts +63 -15
  12. package/dist/api/redact.d.cts +25 -0
  13. package/dist/api/redact.d.ts +25 -0
  14. package/dist/api/tokens.d.cts +5 -0
  15. package/dist/api/tokens.d.ts +5 -0
  16. package/dist/api/tracing.d.cts +107 -0
  17. package/dist/api/tracing.d.ts +107 -0
  18. package/dist/datanotes.cjs +9380 -2554
  19. package/dist/docs/administration/limits.md +96 -12
  20. package/dist/docs/administration/run-the-service.md +18 -0
  21. package/dist/docs/api/operations/graph_neighbors.md +4 -2
  22. package/dist/docs/api/operations/graph_path.md +3 -3
  23. package/dist/docs/api/operations/graph_traverse.md +2 -2
  24. package/dist/docs/api/operations/record_tool_call.md +1 -0
  25. package/dist/docs/api/operations/tags/queries.md +2 -2
  26. package/dist/docs/api.md +3 -3
  27. package/dist/docs/develop/concurrency.md +36 -1
  28. package/dist/docs/develop/http-api.md +11 -1
  29. package/dist/docs/develop/telemetry.md +224 -25
  30. package/dist/docs/guides/data-quality/check-constraints.md +10 -10
  31. package/dist/docs/guides/data-quality/hand-edits.md +8 -8
  32. package/dist/docs/guides/database-objects/bases.md +11 -11
  33. package/dist/docs/guides/database-objects/catalogs-and-schemas.md +10 -10
  34. package/dist/docs/guides/database-objects/columns.md +38 -38
  35. package/dist/docs/guides/database-objects/relations.md +27 -27
  36. package/dist/docs/guides/database-objects/tables.md +37 -101
  37. package/dist/docs/guides/database-objects/views.md +44 -44
  38. package/dist/docs/guides/history/back-up.md +12 -4
  39. package/dist/docs/guides/history/change-data-feed.md +34 -34
  40. package/dist/docs/guides/history/journal-and-undo.md +12 -12
  41. package/dist/docs/guides/history/restore.md +20 -20
  42. package/dist/docs/guides/history/table-history.md +31 -31
  43. package/dist/docs/guides/history/vacuum.md +1 -10
  44. package/dist/docs/guides/read-and-write/automatic-links.md +15 -15
  45. package/dist/docs/guides/read-and-write/import-notes.md +20 -20
  46. package/dist/docs/guides/read-and-write/joins-and-aggregates.md +7 -7
  47. package/dist/docs/guides/read-and-write/read-and-filter.md +10 -10
  48. package/dist/docs/guides/read-and-write/write-rows.md +10 -10
  49. package/dist/docs/guides/search/link-graph.md +95 -0
  50. package/dist/docs/guides/search/text.md +1 -1
  51. package/dist/docs/guides/security/who-did-what.md +2 -0
  52. package/dist/docs/reference/cli.md +10 -3
  53. package/dist/docs/reference/compatibility.md +33 -13
  54. package/dist/docs/reference/operations/queries.md +3 -3
  55. package/dist/docs/reference/operations.md +11 -11
  56. package/dist/docs/reference/settings.md +37 -25
  57. package/dist/docs/release-notes.md +121 -0
  58. package/dist/docs/start/how-it-works.md +35 -3
  59. package/dist/docs/start/quick-start.md +2 -0
  60. package/package.json +3 -2
@@ -28,21 +28,33 @@ __export(index_exports, {
28
28
  OPERATIONS: () => OPERATIONS,
29
29
  OperationInputError: () => OperationInputError,
30
30
  OtlpLogExporter: () => OtlpLogExporter,
31
+ OtlpTraceExporter: () => OtlpTraceExporter,
31
32
  ROUTE_PREFIX: () => ROUTE_PREFIX,
33
+ TRACEPARENT_HEADER: () => TRACEPARENT_HEADER,
34
+ TRACESTATE_HEADER: () => TRACESTATE_HEADER,
35
+ TraceSpan: () => TraceSpan,
36
+ Tracer: () => Tracer,
32
37
  argumentsOf: () => argumentsOf,
33
38
  checkArguments: () => checkArguments,
34
39
  describeBatch: () => describeBatch,
35
40
  describeRefusal: () => describeRefusal,
36
41
  estimateTokens: () => estimateTokens,
37
42
  fetchTransport: () => fetchTransport,
43
+ formatTraceparent: () => formatTraceparent,
38
44
  guidanceIn: () => guidanceIn,
39
45
  guidedText: () => guidedText,
46
+ newSpanId: () => newSpanId,
47
+ newTraceId: () => newTraceId,
40
48
  operationRequest: () => operationRequest,
41
49
  operationRoute: () => operationRoute,
42
50
  otlpFromEnv: () => otlpFromEnv,
51
+ otlpTracesFromEnv: () => otlpTracesFromEnv,
43
52
  parseOtlpHeaders: () => parseOtlpHeaders,
53
+ parseTraceparent: () => parseTraceparent,
44
54
  resultOf: () => resultOf,
45
- toolDocs: () => toolDocs
55
+ samplerRatioFromEnv: () => samplerRatioFromEnv,
56
+ toolDocs: () => toolDocs,
57
+ traceHeaders: () => traceHeaders
46
58
  });
47
59
  module.exports = __toCommonJS(index_exports);
48
60
 
@@ -16003,7 +16015,7 @@ var OPERATIONS = [
16003
16015
  },
16004
16016
  {
16005
16017
  "name": "graph_neighbors",
16006
- "description": 'Direct neighbours of notes: what they link to (`out`) and what links to them (`in`,\nbacklinks), with counts per edge label. `direction`: out, in or both (default).\n\n`from_nodes` selects the notes: `{"paths": [...]}` and/or `{"table": ..., "where": {...}}`.\nEdges are labelled with their link column (`people`, `event`, \u2026) or `link` for other links.',
16018
+ "description": 'Direct neighbours of notes: what they link to (`out`) and what links to them (`in`,\nbacklinks), with counts per edge label. `direction`: out, in or both (default).\n\n`from_nodes` selects the notes: `{"paths": [...]}`, `{"table": ..., "where": {...}}` and/or\n`{"tables": [...]}`: the rows of several tables, by name or pattern (`["*"]` every table, `["personal.*"]` a\ncatalog\'s). The whole vault\'s graph in one call: `{"tables": ["*"]}` with direction `out` (at most 5000\nstart notes). Edges are labelled with their link column (`people`, `event`, \u2026) or `link` for other links.',
16007
16019
  "inputSchema": {
16008
16020
  "additionalProperties": false,
16009
16021
  "properties": {
@@ -16122,7 +16134,7 @@ var OPERATIONS = [
16122
16134
  },
16123
16135
  {
16124
16136
  "name": "graph_traverse",
16125
- "description": 'Breadth-first walk over links from `from_nodes` (`{"paths": [...]}` and/or `{"table", "where"}`).\n\n- `direction`: out (default, follow links), in (follow backlinks) or both.\n- `edges`: edge labels to follow (link columns such as `people`, `event`, or `link`).\n- `tables`: return only notes of these tables; `through`: only walk on through these tables.\n- `min_depth` (default 1) / `max_depth` (default 2, max 10), `limit` (default 500).\n\nEach node comes with `depth` and `via` (one shortest route). Example \u2014 moods tied to events\nwith Alice: from `{"table": "person", "where": {"name": "Alice"}}`, direction `in`, edges\n`["people", "event"]`, tables `["mood"]`, max_depth 2. Feed the paths to `select_rows` with\n`where: {"path": {"in": [...]}}` to aggregate them.',
16137
+ "description": 'Breadth-first walk over links from `from_nodes` (`{"paths": [...]}`, `{"table", "where"}` and/or `{"tables": [...]}`).\n\n- `direction`: out (default, follow links), in (follow backlinks) or both.\n- `edges`: edge labels to follow (link columns such as `people`, `event`, or `link`).\n- `tables`: return only notes of these tables; `through`: only walk on through these tables.\n- `min_depth` (default 1) / `max_depth` (default 2, max 10), `limit` (default 500).\n\nEach node comes with `depth` and `via` (one shortest route). Example \u2014 moods tied to events\nwith Alice: from `{"table": "person", "where": {"name": "Alice"}}`, direction `in`, edges\n`["people", "event"]`, tables `["mood"]`, max_depth 2. Feed the paths to `select_rows` with\n`where: {"path": {"in": [...]}}` to aggregate them.',
16126
16138
  "inputSchema": {
16127
16139
  "additionalProperties": false,
16128
16140
  "properties": {
@@ -16318,7 +16330,7 @@ var OPERATIONS = [
16318
16330
  },
16319
16331
  {
16320
16332
  "name": "graph_path",
16321
- "description": 'Shortest chain of links between two sets of notes (each `{"paths": [...]}` and/or\n`{"table", "where"}`): `found`, `length` and `path`: the steps (`from`, `label`, `direction`, `to`).\n`direction` both by default; `max_depth` default 6 (max 10).',
16333
+ "description": 'Shortest chain of links between two sets of notes (each `{"paths": [...]}`, `{"table", "where"}`\nand/or `{"tables": [...]}`): `found`, `length` and `path`: the steps (`from`, `label`, `direction`, `to`).\n`direction` both by default; `max_depth` default 6 (max 10).',
16322
16334
  "inputSchema": {
16323
16335
  "additionalProperties": false,
16324
16336
  "properties": {
@@ -16706,17 +16718,52 @@ function resultOf(status, json, text) {
16706
16718
  // src/api/tokens.ts
16707
16719
  function estimateTokens(text) {
16708
16720
  let n = 0;
16709
- for (const m of text.matchAll(/\p{L}+|\p{N}+|[^\s\p{L}\p{N}]/gu)) {
16710
- const s = m[0];
16711
- if (/^\p{L}/u.test(s)) n += Math.ceil(s.length / 4);
16712
- else if (/^\p{N}/u.test(s)) n += Math.ceil(s.length / 3);
16713
- else n += 1;
16721
+ let run = 0;
16722
+ for (let i = 0; i < text.length; ) {
16723
+ const c = text.charCodeAt(i);
16724
+ const cp = c >= 55296 && c <= 56319 ? text.codePointAt(i) : c;
16725
+ const width = cp > 65535 ? 2 : 1;
16726
+ const kind = classOf(cp);
16727
+ if (kind === LETTER && run >= 0) run += width;
16728
+ else if (kind === DIGIT && run <= 0) run -= width;
16729
+ else {
16730
+ n += run > 0 ? Math.ceil(run / 4) : Math.ceil(-run / 3);
16731
+ run = kind === LETTER ? width : kind === DIGIT ? -width : 0;
16732
+ if (kind === OTHER) n += 1;
16733
+ }
16734
+ i += width;
16735
+ }
16736
+ return n + (run > 0 ? Math.ceil(run / 4) : Math.ceil(-run / 3));
16737
+ }
16738
+ var LETTER = 0;
16739
+ var DIGIT = 1;
16740
+ var SPACE = 2;
16741
+ var OTHER = 3;
16742
+ function test(cp) {
16743
+ const ch = String.fromCodePoint(cp);
16744
+ return /\p{L}/u.test(ch) ? LETTER : /\p{N}/u.test(ch) ? DIGIT : /\s/u.test(ch) ? SPACE : OTHER;
16745
+ }
16746
+ var BMP = new Uint8Array(65536).fill(255);
16747
+ var ASTRAL = /* @__PURE__ */ new Map();
16748
+ var ASTRAL_KEPT = 4096;
16749
+ function classOf(cp) {
16750
+ if (cp <= 65535) {
16751
+ let k2 = BMP[cp];
16752
+ if (k2 === 255) BMP[cp] = k2 = test(cp);
16753
+ return k2;
16754
+ }
16755
+ let k = ASTRAL.get(cp);
16756
+ if (k === void 0) {
16757
+ k = test(cp);
16758
+ if (ASTRAL.size < ASTRAL_KEPT) ASTRAL.set(cp, k);
16714
16759
  }
16715
- return n;
16760
+ return k;
16716
16761
  }
16717
16762
 
16718
16763
  // src/api/otlp.ts
16719
16764
  var SEVERITY_NUMBER = { DEBUG: 5, INFO: 9, WARN: 13, ERROR: 17 };
16765
+ var SPAN_KIND = { internal: 1, server: 2, client: 3, producer: 4, consumer: 5 };
16766
+ var STATUS_CODE = { unset: 0, ok: 1, error: 2 };
16720
16767
  function attr(key, v) {
16721
16768
  if (v === void 0 || v === null) return null;
16722
16769
  if (typeof v === "boolean") return { key, value: { boolValue: v } };
@@ -16728,12 +16775,26 @@ var fetchSend = async (url, body, headers) => {
16728
16775
  const res = await fetch(url, { method: "POST", headers, body });
16729
16776
  if (!res.ok) throw new Error(`OTLP HTTP ${res.status}`);
16730
16777
  };
16778
+ function unixNano(ms) {
16779
+ const whole = Math.floor(ms);
16780
+ const frac = Math.round((ms - whole) * 1e6);
16781
+ return (BigInt(whole) * BigInt(1e6) + BigInt(frac)).toString();
16782
+ }
16731
16783
  var Pb = class {
16732
16784
  constructor() {
16733
16785
  this.parts = [];
16734
16786
  }
16735
16787
  varint(v) {
16736
- let x = BigInt.asUintN(64, v);
16788
+ if (typeof v === "number" && v >= 0 && v < 2 ** 31) {
16789
+ let x2 = v;
16790
+ while (x2 >= 128) {
16791
+ this.parts.push(x2 & 127 | 128);
16792
+ x2 >>>= 7;
16793
+ }
16794
+ this.parts.push(x2);
16795
+ return;
16796
+ }
16797
+ let x = BigInt.asUintN(64, BigInt(v));
16737
16798
  const b128 = BigInt(128);
16738
16799
  const low7 = BigInt(127);
16739
16800
  const seven = BigInt(7);
@@ -16744,11 +16805,16 @@ var Pb = class {
16744
16805
  this.parts.push(Number(x));
16745
16806
  }
16746
16807
  tag(field, wire) {
16747
- this.varint(BigInt(field << 3 | wire));
16808
+ this.varint(field << 3 | wire);
16748
16809
  }
16749
16810
  uint(field, v) {
16750
16811
  this.tag(field, 0);
16751
- this.varint(BigInt(v));
16812
+ this.varint(v);
16813
+ return this;
16814
+ }
16815
+ fixed32(field, v) {
16816
+ this.tag(field, 5);
16817
+ for (let i = 0; i < 4; i++) this.parts.push(v >>> 8 * i & 255);
16752
16818
  return this;
16753
16819
  }
16754
16820
  fixed64(field, v) {
@@ -16765,10 +16831,16 @@ var Pb = class {
16765
16831
  }
16766
16832
  bytes(field, data) {
16767
16833
  this.tag(field, 2);
16768
- this.varint(BigInt(data.length));
16834
+ this.varint(data.length);
16769
16835
  for (const x of data) this.parts.push(x);
16770
16836
  return this;
16771
16837
  }
16838
+ /** An id given in hex (trace and span ids), as bytes. */
16839
+ hex(field, hex) {
16840
+ const out = [];
16841
+ for (let i = 0; i < hex.length; i += 2) out.push(parseInt(hex.slice(i, i + 2), 16));
16842
+ return this.bytes(field, out);
16843
+ }
16772
16844
  string(field, s) {
16773
16845
  return this.bytes(field, new TextEncoder().encode(s));
16774
16846
  }
@@ -16791,13 +16863,15 @@ function pbAttrs(m, field, a) {
16791
16863
  }
16792
16864
  return m;
16793
16865
  }
16794
- var OtlpLogExporter = class {
16795
- constructor(o) {
16866
+ var OtlpBatcher = class {
16867
+ constructor(o, path, maxBatch) {
16796
16868
  this.o = o;
16869
+ this.path = path;
16870
+ this.maxBatch = maxBatch;
16797
16871
  this.buffer = [];
16798
16872
  this.inflight = Promise.resolve();
16799
16873
  this.timer = null;
16800
- /** Records sent, and records lost because the collector did not take them. */
16874
+ /** Items sent, and items lost because the collector did not take them (or the buffer was full). */
16801
16875
  this.sent = 0;
16802
16876
  this.dropped = 0;
16803
16877
  const every = o.flushMs ?? 5e3;
@@ -16806,19 +16880,60 @@ var OtlpLogExporter = class {
16806
16880
  this.timer.unref?.();
16807
16881
  }
16808
16882
  }
16809
- log(severity, body, attributes = {}) {
16810
- const ms = (this.o.now ?? Date.now)();
16811
- this.buffer.push({ timeUnixNano: `${Math.round(ms)}000000`, severity, body, attributes });
16812
- if (this.buffer.length >= (this.o.maxBatch ?? 50)) void this.flush();
16883
+ push(items) {
16884
+ const room = this.maxBatch * 8 - this.buffer.length;
16885
+ if (room < items.length) this.dropped += items.length - Math.max(room, 0);
16886
+ for (let i = 0; i < Math.min(items.length, Math.max(room, 0)); i++) this.buffer.push(items[i]);
16887
+ if (this.buffer.length >= this.maxBatch) void this.flush();
16888
+ }
16889
+ resource() {
16890
+ return { "service.name": this.o.serviceName, "service.version": this.o.serviceVersion, ...this.o.resource };
16813
16891
  }
16814
16892
  /** Send what is buffered. Never rejects. */
16815
16893
  flush() {
16816
16894
  if (this.buffer.length === 0) return this.inflight;
16817
- const batch = this.buffer;
16818
- this.buffer = [];
16819
- const resource = { "service.name": this.o.serviceName, "service.version": this.o.serviceVersion, ...this.o.resource };
16895
+ const send = this.o.send ?? fetchSend;
16896
+ const url = `${this.o.endpoint.replace(/\/+$/, "")}${this.path}`;
16820
16897
  const protobuf = (this.o.protocol ?? "http/protobuf") === "http/protobuf";
16821
- const body = protobuf ? this.protobuf(resource, batch) : JSON.stringify({
16898
+ const headers = { "Content-Type": protobuf ? "application/x-protobuf" : "application/json", ...this.o.headers ?? {} };
16899
+ while (this.buffer.length > 0) {
16900
+ const batch = this.buffer.splice(0, this.maxBatch);
16901
+ let body;
16902
+ try {
16903
+ body = this.encode(batch, protobuf);
16904
+ } catch {
16905
+ this.dropped += batch.length;
16906
+ continue;
16907
+ }
16908
+ this.inflight = this.inflight.then(
16909
+ () => send(url, body, headers).then(
16910
+ () => void (this.sent += batch.length),
16911
+ () => void (this.dropped += batch.length)
16912
+ )
16913
+ );
16914
+ }
16915
+ return this.inflight;
16916
+ }
16917
+ /** Stop the timer and send what is left. */
16918
+ async close() {
16919
+ if (this.timer) clearInterval(this.timer);
16920
+ this.timer = null;
16921
+ await this.flush();
16922
+ }
16923
+ };
16924
+ var OtlpLogExporter = class extends OtlpBatcher {
16925
+ constructor(o) {
16926
+ super(o, "/v1/logs", o.maxBatch ?? 50);
16927
+ }
16928
+ /** Buffer a record; `context`: the span it was made in (its trace and span id go with it). */
16929
+ log(severity, body, attributes = {}, context) {
16930
+ const ms = (this.o.now ?? Date.now)();
16931
+ this.push([{ timeUnixNano: `${Math.round(ms)}000000`, severity, body, attributes, ...context ? { context } : {} }]);
16932
+ }
16933
+ encode(batch, protobuf) {
16934
+ const resource = this.resource();
16935
+ if (protobuf) return this.protobuf(resource, batch);
16936
+ return JSON.stringify({
16822
16937
  resourceLogs: [
16823
16938
  {
16824
16939
  resource: { attributes: attrs(resource) },
@@ -16831,39 +16946,90 @@ var OtlpLogExporter = class {
16831
16946
  severityNumber: SEVERITY_NUMBER[r.severity],
16832
16947
  severityText: r.severity,
16833
16948
  body: { stringValue: r.body },
16834
- attributes: attrs(r.attributes)
16949
+ attributes: attrs(r.attributes),
16950
+ ...r.context ? { traceId: r.context.traceId, spanId: r.context.spanId, flags: r.context.sampled ? 1 : 0 } : {}
16835
16951
  }))
16836
16952
  }
16837
16953
  ]
16838
16954
  }
16839
16955
  ]
16840
16956
  });
16841
- const url = `${this.o.endpoint.replace(/\/+$/, "")}/v1/logs`;
16842
- const send = this.o.send ?? fetchSend;
16843
- this.inflight = this.inflight.then(
16844
- () => send(url, body, { "Content-Type": protobuf ? "application/x-protobuf" : "application/json", ...this.o.headers ?? {} }).then(
16845
- () => void (this.sent += batch.length),
16846
- () => void (this.dropped += batch.length)
16847
- )
16848
- );
16849
- return this.inflight;
16850
16957
  }
16851
16958
  protobuf(resource, batch) {
16852
16959
  const scope = new Pb().message(1, new Pb().string(1, this.o.serviceName));
16853
16960
  for (const r of batch) {
16854
16961
  const t = BigInt(r.timeUnixNano);
16855
16962
  const rec = new Pb().fixed64(1, t).uint(2, SEVERITY_NUMBER[r.severity]).string(3, r.severity).message(5, new Pb().string(1, r.body));
16856
- pbAttrs(rec, 6, r.attributes).fixed64(11, t);
16963
+ pbAttrs(rec, 6, r.attributes);
16964
+ if (r.context) rec.fixed32(8, r.context.sampled ? 1 : 0).hex(9, r.context.traceId).hex(10, r.context.spanId);
16965
+ rec.fixed64(11, t);
16857
16966
  scope.message(2, rec);
16858
16967
  }
16859
16968
  const resourceLogs = new Pb().message(1, pbAttrs(new Pb(), 1, resource)).message(2, scope);
16860
16969
  return new Pb().message(1, resourceLogs).finish();
16861
16970
  }
16862
- /** Stop the timer and send what is left. */
16863
- async close() {
16864
- if (this.timer) clearInterval(this.timer);
16865
- this.timer = null;
16866
- await this.flush();
16971
+ };
16972
+ var OtlpTraceExporter = class extends OtlpBatcher {
16973
+ constructor(o) {
16974
+ super(o, "/v1/traces", o.maxBatch ?? 512);
16975
+ }
16976
+ /** Buffer finished spans (sent with the next batch). Never throws. */
16977
+ export(spans) {
16978
+ this.push(Array.isArray(spans) ? spans : [spans]);
16979
+ }
16980
+ encode(batch, protobuf) {
16981
+ const resource = this.resource();
16982
+ if (protobuf) return this.protobuf(resource, batch);
16983
+ return JSON.stringify({
16984
+ resourceSpans: [
16985
+ {
16986
+ resource: { attributes: attrs(resource) },
16987
+ scopeSpans: [
16988
+ {
16989
+ scope: { name: this.o.serviceName, ...this.o.serviceVersion ? { version: this.o.serviceVersion } : {} },
16990
+ spans: batch.map((s) => ({
16991
+ traceId: s.traceId,
16992
+ spanId: s.spanId,
16993
+ ...s.parentSpanId ? { parentSpanId: s.parentSpanId } : {},
16994
+ ...s.traceState ? { traceState: s.traceState } : {},
16995
+ flags: 1,
16996
+ name: s.name,
16997
+ kind: SPAN_KIND[s.kind],
16998
+ startTimeUnixNano: unixNano(s.startMs),
16999
+ endTimeUnixNano: unixNano(s.endMs),
17000
+ attributes: attrs(s.attributes),
17001
+ ...s.droppedAttributes ? { droppedAttributesCount: s.droppedAttributes } : {},
17002
+ events: s.events.map((e) => ({ timeUnixNano: unixNano(e.timeMs), name: e.name, attributes: attrs(e.attributes) })),
17003
+ ...s.droppedEvents ? { droppedEventsCount: s.droppedEvents } : {},
17004
+ status: { code: STATUS_CODE[s.status.code], ...s.status.message ? { message: s.status.message } : {} }
17005
+ }))
17006
+ }
17007
+ ]
17008
+ }
17009
+ ]
17010
+ });
17011
+ }
17012
+ protobuf(resource, batch) {
17013
+ const scopeInfo = new Pb().string(1, this.o.serviceName);
17014
+ if (this.o.serviceVersion) scopeInfo.string(2, this.o.serviceVersion);
17015
+ const scope = new Pb().message(1, scopeInfo);
17016
+ for (const s of batch) {
17017
+ const span = new Pb().hex(1, s.traceId).hex(2, s.spanId);
17018
+ if (s.traceState) span.string(3, s.traceState);
17019
+ if (s.parentSpanId) span.hex(4, s.parentSpanId);
17020
+ span.string(5, s.name).uint(6, SPAN_KIND[s.kind]).fixed64(7, BigInt(unixNano(s.startMs))).fixed64(8, BigInt(unixNano(s.endMs)));
17021
+ pbAttrs(span, 9, s.attributes);
17022
+ if (s.droppedAttributes) span.uint(10, s.droppedAttributes);
17023
+ for (const e of s.events) span.message(11, pbAttrs(new Pb().fixed64(1, BigInt(unixNano(e.timeMs))).string(2, e.name), 3, e.attributes));
17024
+ if (s.droppedEvents) span.uint(12, s.droppedEvents);
17025
+ const status = new Pb();
17026
+ if (s.status.message) status.string(2, s.status.message);
17027
+ if (s.status.code !== "unset") status.uint(3, STATUS_CODE[s.status.code]);
17028
+ span.message(15, status).fixed32(16, 1);
17029
+ scope.message(2, span);
17030
+ }
17031
+ const resourceSpans = new Pb().message(1, pbAttrs(new Pb(), 1, resource)).message(2, scope);
17032
+ return new Pb().message(1, resourceSpans).finish();
16867
17033
  }
16868
17034
  };
16869
17035
  function parseOtlpHeaders(text) {
@@ -16885,12 +17051,18 @@ function parseOtlpHeaders(text) {
16885
17051
  var parseResourceAttributes = parseOtlpHeaders;
16886
17052
  var truthy = (v) => (v ?? "").trim().toLowerCase() === "true";
16887
17053
  function otlpFromEnv(env, defaults) {
16888
- if (truthy(env.OTEL_SDK_DISABLED) || (env.OTEL_LOGS_EXPORTER ?? "").trim().toLowerCase() === "none") return null;
16889
- const logs = env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT?.trim();
17054
+ return fromEnv(env, defaults, "LOGS", "logs");
17055
+ }
17056
+ function otlpTracesFromEnv(env, defaults) {
17057
+ return fromEnv(env, defaults, "TRACES", "traces");
17058
+ }
17059
+ function fromEnv(env, defaults, signal, path) {
17060
+ if (truthy(env.OTEL_SDK_DISABLED) || (env[`OTEL_${signal}_EXPORTER`] ?? "").trim().toLowerCase() === "none") return null;
17061
+ const own = env[`OTEL_EXPORTER_OTLP_${signal}_ENDPOINT`]?.trim();
16890
17062
  const base = env.OTEL_EXPORTER_OTLP_ENDPOINT?.trim();
16891
- const endpoint = logs ? logs.replace(/\/v1\/logs\/?$/, "") : base;
17063
+ const endpoint = own ? own.replace(new RegExp(`/v1/${path}/?$`), "") : base;
16892
17064
  if (!endpoint) return null;
16893
- const protocol = otlpProtocol(env.OTEL_EXPORTER_OTLP_LOGS_PROTOCOL ?? env.OTEL_EXPORTER_OTLP_PROTOCOL);
17065
+ const protocol = otlpProtocol(env[`OTEL_EXPORTER_OTLP_${signal}_PROTOCOL`] ?? env.OTEL_EXPORTER_OTLP_PROTOCOL);
16894
17066
  const resource = parseResourceAttributes(env.OTEL_RESOURCE_ATTRIBUTES);
16895
17067
  return {
16896
17068
  endpoint,
@@ -16898,14 +17070,139 @@ function otlpFromEnv(env, defaults) {
16898
17070
  ...defaults.serviceVersion ? { serviceVersion: defaults.serviceVersion } : {},
16899
17071
  ...protocol ? { protocol } : {},
16900
17072
  ...Object.keys(resource).length ? { resource } : {},
16901
- headers: { ...parseOtlpHeaders(env.OTEL_EXPORTER_OTLP_HEADERS), ...parseOtlpHeaders(env.OTEL_EXPORTER_OTLP_LOGS_HEADERS) }
17073
+ headers: { ...parseOtlpHeaders(env.OTEL_EXPORTER_OTLP_HEADERS), ...parseOtlpHeaders(env[`OTEL_EXPORTER_OTLP_${signal}_HEADERS`]) }
16902
17074
  };
16903
17075
  }
17076
+ function samplerRatioFromEnv(env) {
17077
+ const sampler = (env.OTEL_TRACES_SAMPLER ?? "").trim().toLowerCase().replace(/^parentbased_/, "");
17078
+ if (sampler === "always_on") return 1;
17079
+ if (sampler === "always_off") return 0;
17080
+ if (sampler !== "traceidratio") return void 0;
17081
+ const arg = Number((env.OTEL_TRACES_SAMPLER_ARG ?? "").trim() || "1");
17082
+ return Number.isFinite(arg) && arg >= 0 && arg <= 1 ? arg : 1;
17083
+ }
16904
17084
  function otlpProtocol(v) {
16905
17085
  const p = (v ?? "").trim().toLowerCase();
16906
17086
  return p === "http/protobuf" || p === "http/json" ? p : void 0;
16907
17087
  }
16908
17088
 
17089
+ // src/api/tracing.ts
17090
+ var TRACEPARENT_HEADER = "traceparent";
17091
+ var TRACESTATE_HEADER = "tracestate";
17092
+ var TRACEPARENT = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})(-.*)?$/;
17093
+ function parseTraceparent(traceparent, tracestate) {
17094
+ const m = TRACEPARENT.exec((typeof traceparent === "string" ? traceparent : "").trim().toLowerCase());
17095
+ if (!m) return null;
17096
+ const [, version, traceId, spanId, flags, rest] = m;
17097
+ if (version === "ff" || version === "00" && rest !== void 0) return null;
17098
+ if (/^0+$/.test(traceId) || /^0+$/.test(spanId)) return null;
17099
+ const state = (typeof tracestate === "string" ? tracestate : "").trim();
17100
+ return { traceId, spanId, sampled: (parseInt(flags, 16) & 1) === 1, ...state ? { traceState: state.slice(0, 512) } : {} };
17101
+ }
17102
+ function formatTraceparent(ctx) {
17103
+ return `00-${ctx.traceId}-${ctx.spanId}-${ctx.sampled ? "01" : "00"}`;
17104
+ }
17105
+ function traceHeaders(ctx) {
17106
+ return { [TRACEPARENT_HEADER]: formatTraceparent(ctx), ...ctx.traceState ? { [TRACESTATE_HEADER]: ctx.traceState } : {} };
17107
+ }
17108
+ function randomHex(bytes) {
17109
+ const b = new Uint8Array(bytes);
17110
+ const c = globalThis.crypto;
17111
+ if (c?.getRandomValues) c.getRandomValues(b);
17112
+ else for (let i = 0; i < bytes; i++) b[i] = Math.floor(Math.random() * 256);
17113
+ const hex = Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
17114
+ return /^0+$/.test(hex) ? randomHex(bytes) : hex;
17115
+ }
17116
+ var newTraceId = () => randomHex(16);
17117
+ var newSpanId = () => randomHex(8);
17118
+ var perf = globalThis.performance;
17119
+ var defaultNow = perf ? () => perf.timeOrigin + perf.now() : () => Date.now();
17120
+ var TraceSpan = class {
17121
+ constructor(tracer, name, kind, parent, recording, attributes) {
17122
+ this.tracer = tracer;
17123
+ this.name = name;
17124
+ this.kind = kind;
17125
+ this.parent = parent;
17126
+ this.recording = recording;
17127
+ this.attributes = {};
17128
+ this.events = [];
17129
+ this.status = { code: "unset" };
17130
+ this.ended = false;
17131
+ this.context = {
17132
+ traceId: parent?.traceId ?? newTraceId(),
17133
+ spanId: newSpanId(),
17134
+ sampled: recording,
17135
+ ...parent?.traceState ? { traceState: parent.traceState } : {}
17136
+ };
17137
+ this.startMs = tracer.now();
17138
+ this.setAttributes(attributes);
17139
+ }
17140
+ setAttribute(key, value) {
17141
+ if (value !== void 0 && value !== null) this.attributes[key] = value;
17142
+ return this;
17143
+ }
17144
+ setAttributes(attributes) {
17145
+ for (const k in attributes) this.setAttribute(k, attributes[k]);
17146
+ return this;
17147
+ }
17148
+ addEvent(name, attributes = {}) {
17149
+ this.events.push({ name, timeMs: this.tracer.now(), attributes });
17150
+ return this;
17151
+ }
17152
+ /** An `exception` event, `error.type` and status ERROR. */
17153
+ recordException(e) {
17154
+ const type = e instanceof Error ? e.name : typeof e;
17155
+ const message = e instanceof Error ? e.message : String(e);
17156
+ this.addEvent("exception", { "exception.type": type, "exception.message": message, ...e instanceof Error && e.stack ? { "exception.stacktrace": e.stack.slice(0, 8192) } : {} });
17157
+ if (!("error.type" in this.attributes)) this.attributes["error.type"] = type;
17158
+ return this.setStatus("error", message);
17159
+ }
17160
+ setStatus(code, message) {
17161
+ if (this.status.code === "error" && code !== "error") return this;
17162
+ this.status = code === "error" && message ? { code, message } : { code };
17163
+ return this;
17164
+ }
17165
+ end() {
17166
+ if (this.ended) return;
17167
+ this.ended = true;
17168
+ if (!this.recording) return;
17169
+ this.tracer.send({
17170
+ traceId: this.context.traceId,
17171
+ spanId: this.context.spanId,
17172
+ ...this.parent ? { parentSpanId: this.parent.spanId } : {},
17173
+ ...this.context.traceState ? { traceState: this.context.traceState } : {},
17174
+ name: this.name,
17175
+ kind: this.kind,
17176
+ startMs: this.startMs,
17177
+ endMs: this.tracer.now(),
17178
+ attributes: this.attributes,
17179
+ events: this.events,
17180
+ status: this.status
17181
+ });
17182
+ }
17183
+ };
17184
+ var Tracer = class {
17185
+ constructor(o) {
17186
+ this.o = o;
17187
+ this.now = o.now ?? defaultNow;
17188
+ }
17189
+ /** A new span: a child of `parent` (a context or a `traceparent` header), or a new trace. */
17190
+ startSpan(name, opts = {}) {
17191
+ const parent = typeof opts.parent === "string" ? parseTraceparent(opts.parent) : opts.parent ?? null;
17192
+ const ratio = this.o.sampleRatio ?? 1;
17193
+ const span = new TraceSpan(this, name, opts.kind ?? "internal", parent, true, opts.attributes ?? {});
17194
+ const recording = parent ? parent.sampled : ratio >= 1 || ratio > 0 && parseInt(span.context.traceId.slice(-13), 16) / 2 ** 52 < ratio;
17195
+ return recording ? span : new TraceSpan(this, name, opts.kind ?? "internal", parent ?? { ...span.context, sampled: false }, false, {});
17196
+ }
17197
+ /** @internal */
17198
+ send(span) {
17199
+ try {
17200
+ this.o.export([span]);
17201
+ } catch {
17202
+ }
17203
+ }
17204
+ };
17205
+
16909
17206
  // src/api/client.ts
16910
17207
  var ACTOR_HEADER = "X-Datanotes-Actor";
16911
17208
  var UNREACHABLE = {
@@ -16938,6 +17235,24 @@ function isEngineAnswer(json) {
16938
17235
  const o = json;
16939
17236
  return typeof o.ok === "boolean" || typeof o.error === "string";
16940
17237
  }
17238
+ function clientSpan(tracer, method, url, parent) {
17239
+ let target;
17240
+ try {
17241
+ target = new URL(url);
17242
+ } catch {
17243
+ target = null;
17244
+ }
17245
+ return tracer.startSpan(target ? `${method} ${target.pathname}` : method, {
17246
+ kind: "client",
17247
+ parent,
17248
+ attributes: {
17249
+ "http.request.method": method,
17250
+ "url.full": target ? `${target.protocol}//${target.host}${target.pathname}` : void 0,
17251
+ "server.address": target?.hostname,
17252
+ "server.port": target ? Number(target.port || (target.protocol === "https:" ? 443 : 80)) : void 0
17253
+ }
17254
+ });
17255
+ }
16941
17256
  function parse(text) {
16942
17257
  try {
16943
17258
  return text.trim() ? JSON.parse(text) : void 0;
@@ -16951,11 +17266,22 @@ var DatanotesClient = class {
16951
17266
  this.url = o.url.replace(/\/+$/, "");
16952
17267
  this.send = o.transport ?? fetchTransport;
16953
17268
  }
16954
- /** Send a request; the answer's status, its JSON (when it is JSON) and its text. */
17269
+ /** The parent of a request: the call's own `trace`, else the client's. */
17270
+ parentOf(trace) {
17271
+ const given = trace ?? (typeof this.o.trace === "function" ? this.o.trace() : this.o.trace);
17272
+ return typeof given === "string" ? parseTraceparent(given) : given ?? null;
17273
+ }
17274
+ /**
17275
+ * Send a request; the answer's status, its JSON (when it is JSON) and its text. `trace`: the
17276
+ * trace this request continues (over the client's `trace` option).
17277
+ */
16955
17278
  async request(method, path, body, opts = {}) {
16956
17279
  if (!this.url) throw new DatanotesError("engine address not set", "unreachable");
16957
17280
  if (!this.o.token) throw new DatanotesError("token not set", "auth");
16958
17281
  const actor = opts.actor ?? this.o.actor;
17282
+ const parent = this.parentOf(opts.trace);
17283
+ const span = this.o.tracer ? clientSpan(this.o.tracer, method, `${this.url}${path}`, parent) : void 0;
17284
+ const sent = span?.context ?? parent;
16959
17285
  let res;
16960
17286
  try {
16961
17287
  res = await this.send({
@@ -16965,13 +17291,20 @@ var DatanotesClient = class {
16965
17291
  Authorization: `Bearer ${this.o.token}`,
16966
17292
  ...body !== void 0 ? { "Content-Type": "application/json" } : {},
16967
17293
  ...opts.accept ? { Accept: opts.accept } : {},
16968
- ...actor && Object.keys(actor).length ? { [ACTOR_HEADER]: JSON.stringify(actor) } : {}
17294
+ ...actor && Object.keys(actor).length ? { [ACTOR_HEADER]: JSON.stringify(actor) } : {},
17295
+ ...sent ? traceHeaders(sent) : {}
16969
17296
  },
16970
17297
  ...body !== void 0 ? { body: JSON.stringify(body) } : {}
16971
17298
  });
16972
17299
  } catch (e) {
17300
+ span?.recordException(e);
17301
+ span?.end();
16973
17302
  throw new DatanotesError(`engine unreachable at ${this.url}: ${e instanceof Error ? e.message : String(e)}`, "unreachable");
16974
17303
  }
17304
+ span?.setAttribute("http.response.status_code", res.status);
17305
+ if (res.status >= 400) span?.setAttribute("error.type", String(res.status));
17306
+ if (res.status >= 500) span?.setStatus("error", `HTTP ${res.status}`);
17307
+ span?.end();
16975
17308
  if (res.status === 401) throw new DatanotesError("token refused by the engine", "auth", 401);
16976
17309
  const json = parse(res.text);
16977
17310
  const unreachable = res.status === 0 || res.status === 502 || res.status === 504 || res.status === 503 && !isEngineAnswer(json);
@@ -16989,7 +17322,7 @@ var DatanotesClient = class {
16989
17322
  * Arguments the operation does not take, or of the wrong type, are refused before anything is sent,
16990
17323
  * with the same message the engine gives.
16991
17324
  */
16992
- async call(name, args = {}, actor) {
17325
+ async call(name, args = {}, actor, options = {}) {
16993
17326
  let req;
16994
17327
  try {
16995
17328
  req = operationRequest(name, args);
@@ -16999,7 +17332,7 @@ var DatanotesClient = class {
16999
17332
  }
17000
17333
  const problem = checkArguments(name, args);
17001
17334
  if (problem) return { ok: false, value: guidedText(problem.message, problem) };
17002
- const r = await this.request(req.method, req.path, req.body, actor ? { actor } : {});
17335
+ const r = await this.request(req.method, req.path, req.body, { ...actor ? { actor } : {}, ...options.trace ? { trace: options.trace } : {} });
17003
17336
  return resultOf(r.status, r.json, r.text);
17004
17337
  }
17005
17338
  /** True when the engine answers `GET /` (no token needed). */
@@ -17011,8 +17344,11 @@ var DatanotesClient = class {
17011
17344
  return false;
17012
17345
  }
17013
17346
  }
17014
- /** Record an agent's tool call in the change feed (what MCP servers report). */
17347
+ /**
17348
+ * Record an agent's tool call in the change feed (what MCP servers report). Answers what the
17349
+ * engine said: `takes_summary` when it records a `value` sent cut with its `summary`.
17350
+ */
17015
17351
  async recordToolCall(call, actor) {
17016
- await this.post("/tool-calls/record/", call, actor);
17352
+ return this.post("/tool-calls/record/", call, actor);
17017
17353
  }
17018
17354
  };
@@ -9,5 +9,6 @@ export { operationRequest, operationRoute, CALLABLE_OPERATIONS, OperationInputEr
9
9
  export { resultOf, describeRefusal, describeBatch, type OperationResult } from "./results.cjs";
10
10
  export { estimateTokens } from "./tokens.cjs";
11
11
  export { argumentsOf, checkArguments, DOCS_BASE, guidanceIn, guidedText, toolDocs, type ArgumentProblem, type Guidance } from "./guidance.cjs";
12
- export { OtlpLogExporter, otlpFromEnv, parseOtlpHeaders, type OtlpOptions, type Severity, type AttrValue } from "./otlp.cjs";
13
- export { DatanotesClient, DatanotesError, fetchTransport, ACTOR_HEADER, type ActorInfo, type ClientOptions, type HttpRequest, type HttpResponse, type ToolCallRecord, type Transport, } from "./client.cjs";
12
+ export { OtlpLogExporter, OtlpTraceExporter, otlpFromEnv, otlpTracesFromEnv, samplerRatioFromEnv, parseOtlpHeaders, type OtlpOptions, type Severity, type AttrValue } from "./otlp.cjs";
13
+ export { Tracer, TraceSpan, parseTraceparent, formatTraceparent, traceHeaders, newTraceId, newSpanId, TRACEPARENT_HEADER, TRACESTATE_HEADER, type TraceContext, type TracerOptions, type SpanRecord, type SpanKind, type SpanStatusCode, } from "./tracing.cjs";
14
+ export { DatanotesClient, DatanotesError, fetchTransport, ACTOR_HEADER, type ActorInfo, type ClientOptions, type HttpRequest, type HttpResponse, type RecordedToolCall, type ToolCallRecord, type TraceParent, type Transport, } from "./client.cjs";
@@ -9,5 +9,6 @@ export { operationRequest, operationRoute, CALLABLE_OPERATIONS, OperationInputEr
9
9
  export { resultOf, describeRefusal, describeBatch, type OperationResult } from "./results.js";
10
10
  export { estimateTokens } from "./tokens.js";
11
11
  export { argumentsOf, checkArguments, DOCS_BASE, guidanceIn, guidedText, toolDocs, type ArgumentProblem, type Guidance } from "./guidance.js";
12
- export { OtlpLogExporter, otlpFromEnv, parseOtlpHeaders, type OtlpOptions, type Severity, type AttrValue } from "./otlp.js";
13
- export { DatanotesClient, DatanotesError, fetchTransport, ACTOR_HEADER, type ActorInfo, type ClientOptions, type HttpRequest, type HttpResponse, type ToolCallRecord, type Transport, } from "./client.js";
12
+ export { OtlpLogExporter, OtlpTraceExporter, otlpFromEnv, otlpTracesFromEnv, samplerRatioFromEnv, parseOtlpHeaders, type OtlpOptions, type Severity, type AttrValue } from "./otlp.js";
13
+ export { Tracer, TraceSpan, parseTraceparent, formatTraceparent, traceHeaders, newTraceId, newSpanId, TRACEPARENT_HEADER, TRACESTATE_HEADER, type TraceContext, type TracerOptions, type SpanRecord, type SpanKind, type SpanStatusCode, } from "./tracing.js";
14
+ export { DatanotesClient, DatanotesError, fetchTransport, ACTOR_HEADER, type ActorInfo, type ClientOptions, type HttpRequest, type HttpResponse, type RecordedToolCall, type ToolCallRecord, type TraceParent, type Transport, } from "./client.js";