@modernrelay/orbit-omnigraph 0.18.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -15
- package/dist/{chunk-PPUJ64QF.js → chunk-TFBKN675.js} +43 -31
- package/dist/chunk-TFBKN675.js.map +1 -0
- package/dist/codegen-cli.js +10 -18
- package/dist/codegen-cli.js.map +1 -1
- package/dist/index.d.ts +32 -28
- package/dist/index.js +16 -15
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +3 -3
- package/dist/server.js.map +1 -1
- package/package.json +9 -5
- package/dist/chunk-PPUJ64QF.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -24,8 +24,8 @@ interface DecodedSourceId {
|
|
|
24
24
|
/**
|
|
25
25
|
* Encode a `(kind, sourceId)` pair as a collision-proof orbit id.
|
|
26
26
|
*
|
|
27
|
-
* - Nodes: `encodeSourceId(NodeType,
|
|
28
|
-
* - Edges: `encodeSourceId(EdgeName,
|
|
27
|
+
* - Nodes: `encodeSourceId(NodeType, id)` using the top-level export id
|
|
28
|
+
* - Edges: `encodeSourceId(EdgeName, id)` using the top-level export id; endpoints use
|
|
29
29
|
* `encodeSourceId(endpointType, from|to)`.
|
|
30
30
|
*/
|
|
31
31
|
declare function encodeSourceId(kind: string, sourceId: string): string;
|
|
@@ -166,10 +166,10 @@ interface BigIntKeyWarning {
|
|
|
166
166
|
property: string;
|
|
167
167
|
}
|
|
168
168
|
/**
|
|
169
|
-
* Find `I64`/`U64` properties used as
|
|
169
|
+
* Find `I64`/`U64` properties used as schema keys (`@key`). The
|
|
170
170
|
* HTTP path emits native JSON numbers even past ±2^53, where `JSON.parse`
|
|
171
|
-
* silently rounds them
|
|
172
|
-
*
|
|
171
|
+
* silently rounds them. Physical entity ids are separate strings and stay
|
|
172
|
+
* exact; warn that key attributes themselves may lose precision.
|
|
173
173
|
*/
|
|
174
174
|
declare function bigIntKeyWarnings(schema: PgSchema): BigIntKeyWarning[];
|
|
175
175
|
|
|
@@ -185,22 +185,19 @@ declare function bigIntKeyWarnings(schema: PgSchema): BigIntKeyWarning[];
|
|
|
185
185
|
* a schema's own `type` property passes through as ordinary data,
|
|
186
186
|
* - edge endpoint types are resolved from the `.pg` schema because edge lines
|
|
187
187
|
* carry bare `from`/`to` ids,
|
|
188
|
-
* - attr values are normalized
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
* `'YYYY-MM-DD'` (UTC)
|
|
193
|
-
* * `DateTime` — export sends **epoch milliseconds** (number) →
|
|
194
|
-
* ISO 8601 (`'YYYY-MM-DDTHH:MM:SS.mmmZ'`)
|
|
188
|
+
* - attr values are normalized for generated types and temporal dimensions:
|
|
189
|
+
* * `Date` — export sends `'YYYY-MM-DD'`; signed years use ISO's six digits
|
|
190
|
+
* * `DateTime` — export sends a UTC string without a timezone suffix →
|
|
191
|
+
* ISO 8601 with explicit UTC (`'YYYY-MM-DDTHH:MM:SS.mmmZ'`)
|
|
195
192
|
* * `Blob` — inline internal blobs arrive as `'base64:<data>'` →
|
|
196
193
|
* `'data:application/octet-stream;base64,<data>'`;
|
|
197
194
|
* external-URI refs pass through verbatim
|
|
198
|
-
* *
|
|
195
|
+
* * missing nullable schema properties — explicit `null`
|
|
196
|
+
* * everything else — verbatim. Physical identity is top-level `id`;
|
|
197
|
+
* `data.id`, when present, is an ordinary user property.
|
|
199
198
|
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
* server-side, so export-loaded data never contains the sentinels.
|
|
203
|
-
* This module therefore does NOT special-case them.
|
|
199
|
+
* The server rejects non-finite stored floats during export. Computed
|
|
200
|
+
* non-finite query values render as null; neither path uses string sentinels.
|
|
204
201
|
*/
|
|
205
202
|
|
|
206
203
|
/** An edge line names an edge type the `.pg` schema does not declare. */
|
|
@@ -209,7 +206,7 @@ declare class UnknownEdgeTypeError extends Error {
|
|
|
209
206
|
readonly edgeName: string;
|
|
210
207
|
constructor(edgeName: string);
|
|
211
208
|
}
|
|
212
|
-
/** An export line is structurally unusable (e.g. missing/non-string `
|
|
209
|
+
/** An export line is structurally unusable (e.g. missing/non-string `id`). */
|
|
213
210
|
declare class InvalidExportLineError extends Error {
|
|
214
211
|
readonly name = "InvalidExportLineError";
|
|
215
212
|
constructor(message: string);
|
|
@@ -217,11 +214,13 @@ declare class InvalidExportLineError extends Error {
|
|
|
217
214
|
interface NodeExportLine {
|
|
218
215
|
kind: 'node';
|
|
219
216
|
type: string;
|
|
217
|
+
id: string;
|
|
220
218
|
data: Record<string, unknown>;
|
|
221
219
|
}
|
|
222
220
|
interface EdgeExportLine {
|
|
223
221
|
kind: 'edge';
|
|
224
222
|
edge: string;
|
|
223
|
+
id: string;
|
|
225
224
|
from: string;
|
|
226
225
|
to: string;
|
|
227
226
|
data: Record<string, unknown>;
|
|
@@ -231,9 +230,10 @@ type ClassifiedExportLine = NodeExportLine | EdgeExportLine | {
|
|
|
231
230
|
};
|
|
232
231
|
/**
|
|
233
232
|
* Classify one parsed export line using the adapter's wire shapes:
|
|
234
|
-
* - node line: `{"type": "<NodeType>", "
|
|
235
|
-
* - edge line: `{"edge": "<EdgeName>", "from": <src id>, "to": <dst id>, "data": {
|
|
236
|
-
*
|
|
233
|
+
* - node line: `{"type": "<NodeType>", "id": <id>, "data": {…props}}`
|
|
234
|
+
* - edge line: `{"edge": "<EdgeName>", "id": <id>, "from": <src id>, "to": <dst id>, "data": {…props}}`
|
|
235
|
+
* Unknown envelopes return `{ kind: 'unknown' }`. Recognized entities without
|
|
236
|
+
* a physical identity reject instead of falling back to a user property.
|
|
237
237
|
*/
|
|
238
238
|
declare function classifyExportLine(line: unknown): ClassifiedExportLine;
|
|
239
239
|
/**
|
|
@@ -251,24 +251,26 @@ declare function classifyExportLine(line: unknown): ClassifiedExportLine;
|
|
|
251
251
|
declare const ORBIT_TYPE_KEY = "orbit:type";
|
|
252
252
|
/**
|
|
253
253
|
* Normalize a node export line to a `GraphNode`:
|
|
254
|
-
* `id = encodeSourceId(type,
|
|
254
|
+
* `id = encodeSourceId(type, id)`, `attrs = { …data, 'orbit:type' }`
|
|
255
255
|
* with value normalization driven by the schema's property types. A node type
|
|
256
256
|
* absent from the schema is tolerated — its attrs pass through verbatim
|
|
257
257
|
* (identity never needs the schema on the node path).
|
|
258
258
|
*/
|
|
259
259
|
declare function normalizeNode(line: {
|
|
260
260
|
type: string;
|
|
261
|
+
id: string;
|
|
261
262
|
data: Record<string, unknown>;
|
|
262
263
|
}, schema: PgSchema): GraphNode;
|
|
263
264
|
/**
|
|
264
265
|
* Normalize an edge export line to a `GraphEdge`:
|
|
265
|
-
* `id = encodeSourceId(edge,
|
|
266
|
+
* `id = encodeSourceId(edge, id)`; `source`/`target` namespace the bare
|
|
266
267
|
* `from`/`to` ids with the endpoint node types resolved from the schema.
|
|
267
268
|
* Throws {@link UnknownEdgeTypeError} when the schema does not declare
|
|
268
269
|
* the edge — endpoint identity cannot be constructed without it.
|
|
269
270
|
*/
|
|
270
271
|
declare function normalizeEdge(line: {
|
|
271
272
|
edge: string;
|
|
273
|
+
id: string;
|
|
272
274
|
from: string;
|
|
273
275
|
to: string;
|
|
274
276
|
data: Record<string, unknown>;
|
|
@@ -381,8 +383,9 @@ interface OmnigraphLoadResult {
|
|
|
381
383
|
serverVersion: string;
|
|
382
384
|
/**
|
|
383
385
|
* Non-fatal observations: SDK/server major.minor mismatch, accepted
|
|
384
|
-
* drift, big-int
|
|
385
|
-
* hides a retry or accepted-drift decision.
|
|
386
|
+
* drift, big-int key attribute precision hazards, and skipped unknown
|
|
387
|
+
* lines. Never hides a retry or accepted-drift decision. HTTP API contract
|
|
388
|
+
* mismatches are fatal errors, not warnings.
|
|
386
389
|
*/
|
|
387
390
|
warnings: string[];
|
|
388
391
|
}
|
|
@@ -500,12 +503,12 @@ declare function createOmnigraphSource(options: OmnigraphSourceOptions): Omnigra
|
|
|
500
503
|
*/
|
|
501
504
|
|
|
502
505
|
/** One stored-query result row: projection column → value. Bare-variable
|
|
503
|
-
* projections (`return { $s }`) hold whole-node structs including
|
|
506
|
+
* projections (`return { $s }`) hold whole-node structs including `@id`. */
|
|
504
507
|
type OmnigraphSearchRow = Record<string, unknown>;
|
|
505
508
|
/**
|
|
506
509
|
* The required column→node-type mapping:
|
|
507
510
|
*
|
|
508
|
-
* - a record `{
|
|
511
|
+
* - a record `{ s: 'Signal' }` — the FIRST listed column present in a row
|
|
509
512
|
* with a node struct supplies the physical id, encoded under the mapped
|
|
510
513
|
* type name;
|
|
511
514
|
* - or a per-row function returning the node type name — the row's first
|
|
@@ -544,4 +547,5 @@ interface OmnigraphSearchServiceOptions<N = Record<string, unknown>> {
|
|
|
544
547
|
*/
|
|
545
548
|
declare function createOmnigraphSearchService<N = Record<string, unknown>>(options: OmnigraphSearchServiceOptions<N>): SearchService<N>;
|
|
546
549
|
|
|
547
|
-
export {
|
|
550
|
+
export { InvalidExportLineError, ORBIT_TYPE_KEY, OmnigraphDriftError, UnknownEdgeTypeError, bigIntKeyWarnings, classifyExportLine, createOmnigraphSearchService, createOmnigraphSource, decodeSourceId, edgeEndpointTypes, encodeSourceId, encodeSyntheticEdgeId, normalizeEdge, normalizeNode, parsePgSchema, schemaFingerprint };
|
|
551
|
+
export type { BigIntKeyWarning, ClassifiedExportLine, DecodedSourceId, EdgeExportLine, IngestTarget, NodeExportLine, OmnigraphDataRef, OmnigraphDriftPolicy, OmnigraphLoadCounts, OmnigraphLoadProgress, OmnigraphLoadResult, OmnigraphSearchRow, OmnigraphSearchServiceOptions, OmnigraphSearchTypeOf, OmnigraphSource, OmnigraphSourceOptions, PgEdgeType, PgInterfaceType, PgNodeType, PgProperty, PgScalarName, PgSchema, PgType };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { encodeSourceId, parsePgSchema, schemaFingerprint, bigIntKeyWarnings, classifyExportLine, normalizeNode, normalizeEdge } from './chunk-
|
|
2
|
-
export { InvalidExportLineError, ORBIT_TYPE_KEY, UnknownEdgeTypeError, bigIntKeyWarnings, classifyExportLine, decodeSourceId, edgeEndpointTypes, encodeSourceId, encodeSyntheticEdgeId, normalizeEdge, normalizeNode, parsePgSchema, schemaFingerprint } from './chunk-
|
|
1
|
+
import { encodeSourceId, parsePgSchema, schemaFingerprint, bigIntKeyWarnings, classifyExportLine, normalizeNode, normalizeEdge } from './chunk-TFBKN675.js';
|
|
2
|
+
export { InvalidExportLineError, ORBIT_TYPE_KEY, UnknownEdgeTypeError, bigIntKeyWarnings, classifyExportLine, decodeSourceId, edgeEndpointTypes, encodeSourceId, encodeSyntheticEdgeId, normalizeEdge, normalizeNode, parsePgSchema, schemaFingerprint } from './chunk-TFBKN675.js';
|
|
3
3
|
import { SERVER_VERSION, OmnigraphError } from '@modernrelay/omnigraph';
|
|
4
4
|
import { OrbitOperationError } from '@modernrelay/orbit-core';
|
|
5
5
|
|
|
@@ -57,7 +57,8 @@ function throwIfAborted(signal) {
|
|
|
57
57
|
function isAbortError(err) {
|
|
58
58
|
return err instanceof Error && err.name === "AbortError";
|
|
59
59
|
}
|
|
60
|
-
function mapError(err) {
|
|
60
|
+
function mapError(err, signal) {
|
|
61
|
+
throwIfAborted(signal);
|
|
61
62
|
if (err instanceof OmnigraphError && !isAbortError(err)) {
|
|
62
63
|
return new Error(`omnigraph: ${err.name} (status ${err.status}): ${err.message}`);
|
|
63
64
|
}
|
|
@@ -85,14 +86,13 @@ function createOmnigraphSource(options) {
|
|
|
85
86
|
const client = options.client.graph(graphId);
|
|
86
87
|
const datasetKey = typeNames === void 0 ? `og:${graphId}:${branch}` : `og:${graphId}:${branch}:types=${typeNames.join(",")}`;
|
|
87
88
|
async function newestHead(signal) {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
if (newest === void 0) {
|
|
89
|
+
const { headCommitId } = await client.commits.list({ branch, limit: 1 }, callOpts(signal));
|
|
90
|
+
if (headCommitId == null) {
|
|
91
91
|
throw new Error(
|
|
92
92
|
`omnigraph: branch '${branch}' of graph '${graphId}' has no commits \u2014 nothing to export`
|
|
93
93
|
);
|
|
94
94
|
}
|
|
95
|
-
return
|
|
95
|
+
return headCommitId;
|
|
96
96
|
}
|
|
97
97
|
async function runAttempt(target, signal, warnings, attempt) {
|
|
98
98
|
throwIfAborted(signal);
|
|
@@ -104,7 +104,7 @@ function createOmnigraphSource(options) {
|
|
|
104
104
|
for (const hazard of bigIntKeyWarnings(schema)) {
|
|
105
105
|
pushUnique(
|
|
106
106
|
warnings,
|
|
107
|
-
`omnigraph: ${hazard.type}.${hazard.property} is a 64-bit integer
|
|
107
|
+
`omnigraph: ${hazard.type}.${hazard.property} is a 64-bit integer schema key \u2014 JSON parsing silently rounds attribute values past \xB12^53; physical ids remain exact strings`
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
const provisionalRef = {
|
|
@@ -279,7 +279,7 @@ function createOmnigraphSource(options) {
|
|
|
279
279
|
} catch {
|
|
280
280
|
}
|
|
281
281
|
}
|
|
282
|
-
throw mapError(err);
|
|
282
|
+
throw mapError(err, signal);
|
|
283
283
|
} finally {
|
|
284
284
|
try {
|
|
285
285
|
await iterator.return?.();
|
|
@@ -293,7 +293,7 @@ function createOmnigraphSource(options) {
|
|
|
293
293
|
try {
|
|
294
294
|
serverVersion = (await client.health(callOpts(signal))).version;
|
|
295
295
|
} catch (err) {
|
|
296
|
-
throw mapError(err);
|
|
296
|
+
throw mapError(err, signal);
|
|
297
297
|
}
|
|
298
298
|
const server = majorMinor(serverVersion);
|
|
299
299
|
const sdk = majorMinor(SERVER_VERSION);
|
|
@@ -307,7 +307,7 @@ function createOmnigraphSource(options) {
|
|
|
307
307
|
try {
|
|
308
308
|
outcome = await runAttempt(target, signal, warnings, attempt);
|
|
309
309
|
} catch (err) {
|
|
310
|
-
throw mapError(err);
|
|
310
|
+
throw mapError(err, signal);
|
|
311
311
|
}
|
|
312
312
|
if (outcome.kind === "retry") continue;
|
|
313
313
|
return {
|
|
@@ -342,7 +342,7 @@ function mapError2(err) {
|
|
|
342
342
|
return err;
|
|
343
343
|
}
|
|
344
344
|
function isNodeStruct(value) {
|
|
345
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value
|
|
345
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value["@id"] === "string";
|
|
346
346
|
}
|
|
347
347
|
function extractRows(response, queryName) {
|
|
348
348
|
const rows = response.rows;
|
|
@@ -370,15 +370,15 @@ function resolveIdentity(row, typeOf, queryName) {
|
|
|
370
370
|
}
|
|
371
371
|
for (const key of Object.keys(row)) {
|
|
372
372
|
const value = row[key];
|
|
373
|
-
if (isNodeStruct(value)) return { kind, sourceId: value
|
|
373
|
+
if (isNodeStruct(value)) return { kind, sourceId: value["@id"] };
|
|
374
374
|
}
|
|
375
375
|
throw new Error(
|
|
376
|
-
`omnigraph: '${queryName}' search row has no node-struct column (an object with a string 'id') \u2014 project the matched entity bare (return { $s }) so its physical id is available`
|
|
376
|
+
`omnigraph: '${queryName}' search row has no node-struct column (an object with a string '@id') \u2014 project the matched entity bare (return { $s }) so its physical id is available`
|
|
377
377
|
);
|
|
378
378
|
}
|
|
379
379
|
for (const [column, kind] of Object.entries(typeOf)) {
|
|
380
380
|
const value = row[column];
|
|
381
|
-
if (isNodeStruct(value)) return { kind, sourceId: value
|
|
381
|
+
if (isNodeStruct(value)) return { kind, sourceId: value["@id"] };
|
|
382
382
|
}
|
|
383
383
|
throw new Error(
|
|
384
384
|
`omnigraph: '${queryName}' search row has no node struct under the mapped column(s) ${JSON.stringify(Object.keys(typeOf))} \u2014 the typeOf record must key the columns that contain bare-variable node projections`
|
|
@@ -420,6 +420,7 @@ function createOmnigraphSearchService(options) {
|
|
|
420
420
|
try {
|
|
421
421
|
response = await client.queries.invoke(queryName, input, { signal: ctx.signal });
|
|
422
422
|
} catch (err) {
|
|
423
|
+
throwIfAborted2(ctx.signal, queryName);
|
|
423
424
|
throw mapError2(err);
|
|
424
425
|
}
|
|
425
426
|
throwIfAborted2(ctx.signal, queryName);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/loader.ts","../src/searchService.ts"],"names":["activeSession","throwIfAborted","isAbortError","mapError","OmnigraphError"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * v1 export loader.\n *\n * The organizing rule: graphs load via `og.export` — one streamed\n * NDJSON pass, edge lines first (lexicographic table-key order), driven\n * straight into a `purpose:'replace'` ingest session on the target. Queries\n * never introduce nodes or edges.\n *\n * Revision stamp: the canonical `sourceRevision` hashes\n * `{ graphId, branch, headBefore, headAfter, schemaFingerprint }` (plus the\n * sorted `typeNames` subset when the export is partial), but\n * `headAfter` is only knowable after the stream — while core's\n * `BeginIngestOptions` requires `sourceRevision` up front for a replace\n * session. Resolution: under the rejecting/retrying policies the session\n * begins under the PROVISIONAL revision (the canonical hash with\n * `headAfter:= headBefore`), the stream appends into it, and `headAfter` is\n * captured BEFORE `commit`. `accept-warn` is the exception: normalized\n * batches are buffered until `headAfter` is known, then appended once into a\n * session opened with the canonical FINAL revision:\n *\n * - equal heads → provisional === final; commit cleanly. The session only\n * ever commits a revision whose hash is truthful.\n * - drifted heads → `driftPolicy` decides: `'reject'` aborts the session\n * (graph untouched) and throws {@link OmnigraphDriftError};\n * `'accept-warn'` commits the buffered export under the\n * final revision, records BOTH heads in `dataRef`, and\n * adds a warning;\n * `'retry-once'` aborts and restarts the whole load once\n * (a second drift rejects).\n *\n * This is sound because a replace session is atomic and invisible until\n * commit: nothing is published under a revision the policy did not\n * explicitly accept.\n *\n * Error surface: SDK typed errors never cross this package's public\n * surface — they are mapped to plain `Error`s with a stable `omnigraph:`\n * message prefix.\n */\n\nimport { OmnigraphError, SERVER_VERSION } from '@modernrelay/omnigraph';\nimport type { CallOptions, ExportInput, Omnigraph } from '@modernrelay/omnigraph';\nimport { OrbitOperationError } from '@modernrelay/orbit-core';\nimport type { GraphEdge, GraphNode, IngestBatch, IngestSession } from '@modernrelay/orbit-core';\n\nimport { classifyExportLine, normalizeEdge, normalizeNode } from './normalize';\nimport { bigIntKeyWarnings, parsePgSchema, schemaFingerprint } from './pgSchema';\nimport type { PgSchema } from './pgSchema';\nimport type {\n IngestTarget,\n OmnigraphDataRef,\n OmnigraphLoadResult,\n OmnigraphSourceOptions,\n} from './types';\n\nconst DEFAULT_BATCH_SIZE = 2000;\n\n/**\n * Finite whole-export cap for the necessarily atomic replace session. A\n * whole-graph load stages EVERY row before commit, so this is a total-load\n * memory bound, not a backpressure window — real graphs routinely exceed\n * 100 MB of serialized rows (the intel fixture streams ~128 MB), so the\n * default is deliberately generous; callers with tighter memory budgets pass\n * `maxPendingBytes` explicitly.\n */\nconst DEFAULT_MAX_PENDING_BYTES = 512 * 1024 * 1024;\n\n/** Stateless and safe to reuse; counts serialized UTF-8 rather than UTF-16 code units. */\nconst UTF8_ENCODER = new TextEncoder();\n\n/**\n * Raised when a branch moves during export and the configured drift policy\n * rejects the load. The session is aborted and the target graph is untouched.\n */\nexport class OmnigraphDriftError extends Error {\n override readonly name = 'OmnigraphDriftError';\n readonly graphId: string;\n readonly branch: string;\n readonly headBefore: string;\n readonly headAfter: string;\n constructor(graphId: string, branch: string, headBefore: string, headAfter: string) {\n super(\n `omnigraph: branch '${branch}' of graph '${graphId}' changed during export ` +\n `(head ${headBefore} → ${headAfter}); session aborted per driftPolicy (` +\n `service:omnigraph-source-changed-during-export)`,\n );\n this.graphId = graphId;\n this.branch = branch;\n this.headBefore = headBefore;\n this.headAfter = headAfter;\n }\n}\n\n/** The one load path a v1 source exposes. */\nexport interface OmnigraphSource {\n /**\n * Stream one export of the configured graph/branch into `target` via a\n * `purpose:'replace'` ingest session. Resolves with the revision-stamped\n * result; rejects with the session aborted and the target untouched.\n * `signal` aborts both the HTTP stream and the session.\n */\n load(target: IngestTarget, signal?: AbortSignal): Promise<OmnigraphLoadResult>;\n}\n\n// ---------------------------------------------------------------------------\n// Small pure helpers\n// ---------------------------------------------------------------------------\n\n/** FNV-1a 64-bit over the UTF-8 bytes of `s`, as 16 lowercase hex chars. */\nfunction hash64(s: string): string {\n const MASK64 = 0xffffffffffffffffn;\n let h = 0xcbf29ce484222325n;\n for (const b of new TextEncoder().encode(s)) {\n h ^= BigInt(b);\n h = (h * 0x100000001b3n) & MASK64;\n }\n return h.toString(16).padStart(16, '0');\n}\n\n/**\n * The canonical adapter source revision: a hash of the readable `dataRef` object\n * `{ graphId, branch, headBefore, headAfter, schemaFingerprint, typeNames? }`\n * (`dataRef` itself retains the readable form).\n */\nfunction canonicalSourceRevision(ref: OmnigraphDataRef): string {\n // typeNames joins the tuple ONLY when present, so full-export\n // hashes stay byte-identical to every previously persisted revision.\n const tuple: unknown[] = [\n ref.graphId,\n ref.branch,\n ref.headBefore,\n ref.headAfter,\n ref.schemaFingerprint,\n ];\n if (ref.typeNames !== undefined) tuple.push(ref.typeNames);\n return `og:${hash64(JSON.stringify(tuple))}`;\n}\n\n/** `'0.8.1'` → `'0.8'`; null when unparseable. */\nfunction majorMinor(version: string): string | null {\n const m = /^(\\d+)\\.(\\d+)/.exec(version);\n return m ? `${m[1]}.${m[2]}` : null;\n}\n\n/** CallOptions without an explicit-undefined signal (exactOptionalPropertyTypes). */\nfunction callOpts(signal: AbortSignal | undefined): CallOptions {\n return signal ? { signal } : {};\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw new DOMException('omnigraph: load aborted by caller signal', 'AbortError');\n }\n}\n\nfunction isAbortError(err: unknown): boolean {\n return err instanceof Error && err.name === 'AbortError';\n}\n\n/**\n * SDK typed errors (`NetworkError`, `ConflictError`, …) never leak across the\n * public surface; they rethrow as plain `Error`s with a stable prefix.\n * Abort rejections and this package's own errors pass through unchanged.\n */\nfunction mapError(err: unknown): unknown {\n if (err instanceof OmnigraphError && !isAbortError(err)) {\n return new Error(`omnigraph: ${err.name} (status ${err.status}): ${err.message}`);\n }\n return err;\n}\n\nfunction pushUnique(warnings: string[], warning: string): void {\n if (!warnings.includes(warning)) warnings.push(warning);\n}\n\n// ---------------------------------------------------------------------------\n// createOmnigraphSource\n// ---------------------------------------------------------------------------\n\ninterface AttemptSuccess {\n kind: 'done';\n sourceRevision: string;\n dataRef: OmnigraphDataRef;\n counts: { lines: number; nodes: number; edges: number; bytes: number };\n}\n\ninterface AttemptRetry {\n kind: 'retry';\n}\n\n/**\n * Create a v1 export-backed data source. The client must be\n * preconfigured. In the browser, use a safe same-origin or public client;\n * there is deliberately no `baseUrl`/`token` option here. Authenticated\n * construction lives only in `@modernrelay/orbit-omnigraph/server`.\n */\nexport function createOmnigraphSource(options: OmnigraphSourceOptions): OmnigraphSource {\n const graphId = options.graphId;\n const branch = options.branch ?? 'main';\n const batchSize =\n options.batchSize === undefined ? DEFAULT_BATCH_SIZE : options.batchSize;\n if (!Number.isSafeInteger(batchSize) || batchSize <= 0) {\n throw new TypeError('createOmnigraphSource: batchSize must be a positive safe integer');\n }\n const maxPendingBytes =\n options.maxPendingBytes === undefined ? DEFAULT_MAX_PENDING_BYTES : options.maxPendingBytes;\n if (!Number.isSafeInteger(maxPendingBytes) || maxPendingBytes <= 0) {\n throw new TypeError(\n 'createOmnigraphSource: maxPendingBytes must be a positive safe integer',\n );\n }\n const driftPolicy = options.driftPolicy ?? 'reject';\n const onProgress = options.onProgress;\n // Sorted canonical form: ['B','A'] and ['A','B'] are the SAME subset and\n // must produce the same identity coordinate.\n const typeNames =\n options.typeNames === undefined ? undefined : [...options.typeNames].sort();\n /** Every call is scoped to the graph (SDK cluster routing). */\n const client: Omnigraph = options.client.graph(graphId);\n // A partial export is a DIFFERENT dataset lifetime than the full graph;\n // positions, selection, and history must not carry across subsets.\n const datasetKey =\n typeNames === undefined\n ? `og:${graphId}:${branch}`\n : `og:${graphId}:${branch}:types=${typeNames.join(',')}`;\n\n async function newestHead(signal: AbortSignal | undefined): Promise<string> {\n const commits = await client.commits.list({ branch }, callOpts(signal));\n const newest = commits[0]; // SDK: most recent first\n if (newest === undefined) {\n throw new Error(\n `omnigraph: branch '${branch}' of graph '${graphId}' has no commits — nothing to export`,\n );\n }\n return newest.graphCommitId;\n }\n\n async function runAttempt(\n target: IngestTarget,\n signal: AbortSignal | undefined,\n warnings: string[],\n attempt: number,\n ): Promise<AttemptSuccess | AttemptRetry> {\n throwIfAborted(signal);\n // Pin the target's SOURCE lineage before any remote work: a competing\n // replace/snapshot landing mid-stream must fail the load. Overlay-only\n // model advances are benign for a replace commit (it supersedes overlays\n // anyway), so the CAS base itself is read fresh at each beginIngest\n // pinning it here made long accept-warn streams fail late (and livelock)\n // under unrelated concurrent overlay traffic.\n const baseSource = target.getRevisions().source;\n\n // The before/after head bracket must enclose BOTH the schema read and the\n // export. Otherwise a schema migration between schema.get and the first\n // head sample could look quiescent while we normalize with stale types.\n const headBefore = await newestHead(signal);\n\n // Endpoint-type resolution + wire-type normalization + the fingerprint\n // half of the revision stamp.\n const schemaSource = (await client.schema.get(callOpts(signal))).schemaSource;\n const schema: PgSchema = parsePgSchema(schemaSource);\n const fingerprint = schemaFingerprint(schemaSource);\n for (const hazard of bigIntKeyWarnings(schema)) {\n pushUnique(\n warnings,\n `omnigraph: ${hazard.type}.${hazard.property} is a 64-bit integer used as identity — ` +\n `JSON parsing silently rounds values past ±2^53, which can collapse distinct ids`,\n );\n }\n // NOTE: a schema-declared `type` property needs no warning — the\n // adapter's discriminator lives at the namespaced ORBIT_TYPE_KEY, so the\n // source's own `type` loads as ordinary data with nothing to report.\n\n const provisionalRef: OmnigraphDataRef = {\n graphId,\n branch,\n headBefore,\n headAfter: headBefore, // provisional: assume quiescence, verify after the stream\n schemaFingerprint: fingerprint,\n ...(typeNames !== undefined ? { typeNames } : {}),\n };\n const provisionalRevision = canonicalSourceRevision(provisionalRef);\n\n function beginSession(sourceRevision: string): IngestSession {\n const now = target.getRevisions();\n if (now.source !== baseSource) {\n throw new Error(\n `omnigraph: the target's source lineage changed while the load was streaming ` +\n `(a competing replace or snapshot landed); aborting instead of overwriting it`,\n );\n }\n return target.beginIngest({\n purpose: 'replace',\n datasetKey,\n sourceRevision,\n baseModelRevision: now.model,\n maxPendingBytes,\n });\n }\n\n // `accept-warn` cannot open a truthful session until headAfter is known.\n // Buffer only that opt-in policy; rejecting/retrying loads keep streaming\n // directly into the atomic target under the provisional revision.\n let session: IngestSession | undefined =\n driftPolicy === 'accept-warn' ? undefined : beginSession(provisionalRevision);\n const requestId = hash64(`${datasetKey}|${provisionalRevision}|${attempt}`);\n\n interface BufferedBatch {\n nodes: GraphNode[];\n edges: GraphEdge[];\n bytes: number;\n progress: { lines: number; nodes: number; edges: number; bytes: number };\n }\n const bufferedBatches: Array<BufferedBatch | undefined> | undefined =\n driftPolicy === 'accept-warn' ? [] : undefined;\n\n let lines = 0;\n let nodeCount = 0;\n let edgeCount = 0;\n let bytes = 0;\n let unknown = 0;\n let sequence = 0;\n let pendingNodes: GraphNode[] = [];\n let pendingEdges: GraphEdge[] = [];\n let pendingBytes = 0;\n let acceptedBytes = 0;\n\n /**\n * Replace ingestion is atomic, so neither core staging nor accept-warn's\n * adapter buffer can drain before commit. Enforce the same finite\n * whole-load budget before retaining the next normalized row.\n */\n function accountAcceptedBytes(lineBytes: number): void {\n const next = acceptedBytes + lineBytes;\n if (next > maxPendingBytes) {\n throw new OrbitOperationError(\n { code: 'queue-overflow', queuedBytes: next, limit: maxPendingBytes },\n `omnigraph: export rows require at least ${next} bytes, exceeding ` +\n `maxPendingBytes ${maxPendingBytes}; load aborted before commit`,\n );\n }\n acceptedBytes = next;\n pendingBytes += lineBytes;\n }\n\n /** Await every append; retain bounded adapter-side pending batches. */\n async function flush(): Promise<void> {\n if (pendingNodes.length === 0 && pendingEdges.length === 0) return;\n const nodes = pendingNodes;\n const edges = pendingEdges;\n const batchBytes = pendingBytes;\n const progress = { lines, nodes: nodeCount, edges: edgeCount, bytes };\n pendingNodes = [];\n pendingEdges = [];\n pendingBytes = 0;\n\n if (bufferedBatches !== undefined) {\n bufferedBatches.push({ nodes, edges, bytes: batchBytes, progress });\n return;\n }\n\n const activeSession = session;\n if (activeSession === undefined) throw new Error('omnigraph: internal missing ingest session');\n const batch: IngestBatch = {\n sequence,\n batchId: `og:${requestId}:${sequence}`,\n bytes: batchBytes,\n };\n if (edges.length > 0) batch.edges = edges;\n if (nodes.length > 0) batch.nodes = nodes;\n sequence += 1;\n await activeSession.append(batch);\n onProgress?.(progress);\n }\n\n /** Commit buffered accept-warn rows once, under the now-known final revision. */\n async function commitBuffered(sourceRevision: string): Promise<void> {\n if (bufferedBatches === undefined) {\n throw new Error('omnigraph: internal missing accept-warn batch buffer');\n }\n const finalSession = beginSession(sourceRevision);\n session = finalSession;\n const finalRequestId = hash64(`${datasetKey}|${sourceRevision}|${attempt}`);\n for (let i = 0; i < bufferedBatches.length; i++) {\n throwIfAborted(signal);\n const buffered = bufferedBatches[i];\n if (buffered === undefined) continue;\n // Release the buffer's array slot as soon as ownership passes to the\n // target session; the local `buffered` reference dies this iteration.\n bufferedBatches[i] = undefined;\n const batch: IngestBatch = {\n sequence: i,\n batchId: `og:${finalRequestId}:${i}`,\n bytes: buffered.bytes,\n };\n if (buffered.edges.length > 0) batch.edges = buffered.edges;\n if (buffered.nodes.length > 0) batch.nodes = buffered.nodes;\n await finalSession.append(batch);\n onProgress?.(buffered.progress);\n }\n bufferedBatches.length = 0;\n throwIfAborted(signal);\n await finalSession.commit();\n }\n\n // Bind the iterator ONCE and\n // make sure early exits cancel the underlying stream via `return`.\n const exportInput: ExportInput = { branch, ...(typeNames !== undefined ? { typeNames } : {}) };\n const iterator = client\n .export<Record<string, unknown>>(exportInput, callOpts(signal))\n [Symbol.asyncIterator]();\n\n try {\n for (;;) {\n throwIfAborted(signal);\n const step = await iterator.next();\n if (step.done === true) break;\n const line = step.value;\n lines += 1;\n // The SDK exposes parsed rows rather than raw chunks. Re-serialize to\n // UTF-8 and include one NDJSON newline: a conservative, consistent\n // accounting unit for progress, batches, and the whole-load cap.\n const lineBytes = UTF8_ENCODER.encode(JSON.stringify(line)).byteLength + 1;\n bytes += lineBytes;\n const classified = classifyExportLine(line);\n if (classified.kind === 'node') {\n const node = normalizeNode(classified, schema);\n accountAcceptedBytes(lineBytes);\n pendingNodes.push(node);\n nodeCount += 1;\n } else if (classified.kind === 'edge') {\n const edge = normalizeEdge(classified, schema);\n accountAcceptedBytes(lineBytes);\n pendingEdges.push(edge);\n edgeCount += 1;\n } else {\n unknown += 1;\n }\n if (pendingNodes.length + pendingEdges.length >= batchSize) await flush();\n }\n await flush();\n\n if (unknown > 0) {\n pushUnique(warnings, `omnigraph: skipped ${unknown} unrecognized export line(s)`);\n }\n\n // Revision stamp, second half: the head AFTER the stream, captured\n // BEFORE commit.\n throwIfAborted(signal);\n const headAfter = await newestHead(signal);\n throwIfAborted(signal);\n const counts = { lines, nodes: nodeCount, edges: edgeCount, bytes };\n\n if (driftPolicy === 'accept-warn') {\n const finalRef: OmnigraphDataRef = { ...provisionalRef, headAfter };\n const finalRevision = canonicalSourceRevision(finalRef);\n if (headAfter !== headBefore) {\n pushUnique(\n warnings,\n `omnigraph: branch '${branch}' advanced during export (head ${headBefore} → ` +\n `${headAfter}); committed under the canonical final revision per ` +\n `driftPolicy:'accept-warn' — dataRef records both heads`,\n );\n }\n await commitBuffered(finalRevision);\n return { kind: 'done', sourceRevision: finalRevision, dataRef: finalRef, counts };\n }\n\n if (headAfter === headBefore) {\n const activeSession = session;\n if (activeSession === undefined) throw new Error('omnigraph: internal missing ingest session');\n await activeSession.commit();\n return { kind: 'done', sourceRevision: provisionalRevision, dataRef: provisionalRef, counts };\n }\n\n // Branch drift maps to service:omnigraph-source-changed-during-export.\n const activeSession = session;\n if (activeSession === undefined) throw new Error('omnigraph: internal missing ingest session');\n await activeSession.abort('omnigraph: source changed during export');\n if (driftPolicy === 'retry-once' && attempt === 1) {\n pushUnique(\n warnings,\n `omnigraph: branch '${branch}' advanced during export (head ${headBefore} → ` +\n `${headAfter}); load restarted once per driftPolicy:'retry-once'`,\n );\n return { kind: 'retry' };\n }\n throw new OmnigraphDriftError(graphId, branch, headBefore, headAfter);\n } catch (err) {\n if (session?.state === 'open') {\n try {\n await session.abort(err);\n } catch {\n // the original failure wins\n }\n }\n throw mapError(err);\n } finally {\n // Cancel the underlying NDJSON stream on any non-exhausted exit.\n try {\n await iterator.return?.();\n } catch {\n // stream teardown must never mask the outcome\n }\n }\n }\n\n async function load(target: IngestTarget, signal?: AbortSignal): Promise<OmnigraphLoadResult> {\n const warnings: string[] = [];\n\n // Surface an SDK/server major.minor mismatch as a warning, never a hard\n // failure.\n let serverVersion: string;\n try {\n serverVersion = (await client.health(callOpts(signal))).version;\n } catch (err) {\n throw mapError(err);\n }\n const server = majorMinor(serverVersion);\n const sdk = majorMinor(SERVER_VERSION);\n if (server === null || server !== sdk) {\n warnings.push(\n `omnigraph: server version ${serverVersion} does not match the SDK-pinned server ` +\n `version ${SERVER_VERSION} (major.minor differ) — SDK behavior is undefined ` +\n `against this server`,\n );\n }\n\n for (let attempt = 1; ; attempt += 1) {\n let outcome: AttemptSuccess | AttemptRetry;\n try {\n outcome = await runAttempt(target, signal, warnings, attempt);\n } catch (err) {\n // Covers SDK errors thrown before the session/stream phase\n // (schema.get, commits.list); mapError is a no-op on already-mapped\n // or package-owned errors.\n throw mapError(err);\n }\n if (outcome.kind === 'retry') continue;\n return {\n sourceRevision: outcome.sourceRevision,\n dataRef: outcome.dataRef,\n counts: outcome.counts,\n serverVersion,\n warnings,\n };\n }\n }\n\n return { load };\n}\n","/**\n * Stored-query `SearchService` integration.\n *\n * A stored query using `bm25`/`fuzzy`/`nearest`/`rrf` with\n * `order { score desc } limit K` returns entity rows plus a score column; this\n * module wires it as a `SearchService` via\n * `og.queries.invoke(name, { params, branch })`, passing\n * `RequestContext.signal` through SDK `CallOptions`. Core performs revision\n * admission — the service only declares `revisionDependencies: ['source']`\n * (results come from the server-side branch, so they are invalidated by a\n * source change, never by client-side model/scope drift).\n *\n * Identity: Omnigraph ids are unique per type only, and a query row\n * carries no type discriminator of its own — so the adapter REQUIRES a\n * caller-supplied column→node-type mapping (`typeOf`), either a\n * `{ column: NodeType }` record keyed by the projection columns that hold\n * bare-variable node structs, or a per-row function. Every returned id is\n * qualified through `encodeSourceId(nodeType, physicalId)` — the same codec\n * every other adapter path uses — so results round-trip `decodeSourceId` and\n * match export-loaded node ids exactly.\n *\n * Partial-load caveat: search runs server-side over the whole branch, so a\n * partial export load can return ids outside the loaded set.\n * `activateSearchResult` classifies those as `'not-loaded'`; constrain the\n * stored query to the loaded types, or load the full graph, to avoid the\n * mismatch.\n *\n * Error surface: SDK typed errors never cross this package's public\n * surface — they rethrow as plain `Error`s with the stable `omnigraph:`\n * prefix. Abort rejections pass through unchanged.\n */\n\nimport { OmnigraphError } from '@modernrelay/omnigraph';\nimport type { InvokeQueryInput, Omnigraph } from '@modernrelay/omnigraph';\nimport type { RequestContext, SearchResult, SearchService } from '@modernrelay/orbit-core';\n\nimport { encodeSourceId } from './idCodec';\n\n/** One stored-query result row: projection column → value. Bare-variable\n * projections (`return { $s }`) hold whole-node structs including `id`. */\nexport type OmnigraphSearchRow = Record<string, unknown>;\n\n/**\n * The required column→node-type mapping:\n *\n * - a record `{ '$s': 'Signal' }` — the FIRST listed column present in a row\n * with a node struct supplies the physical id, encoded under the mapped\n * type name;\n * - or a per-row function returning the node type name — the row's first\n * node-struct column (row key order) supplies the physical id.\n */\nexport type OmnigraphSearchTypeOf =\n | ((row: OmnigraphSearchRow) => string)\n | Readonly<Record<string, string>>;\n\nexport interface OmnigraphSearchServiceOptions<N = Record<string, unknown>> {\n /** A **preconfigured** SDK client — no `baseUrl`/`token` here. */\n client: Omnigraph;\n /** Cluster graph id; the invoke is scoped via `client.graph(graphId)`. */\n graphId: string;\n /** Branch the stored query reads. Default `'main'`. */\n branch?: string;\n /** Registry name of the stored search query (`POST /queries/{name}`).\n * Invoking a known name works whether or not it is `mcp.expose`d. */\n queryName: string;\n /** Builds the stored query's `params` object from the call.\n * Default: `(q, limit) => ({ q, limit })`. */\n params?: (q: string, limit: number) => Record<string, unknown>;\n /** REQUIRED mapping from row to node type — see\n * {@link OmnigraphSearchTypeOf}. */\n typeOf: OmnigraphSearchTypeOf;\n /** Column whose value becomes `label` (String-coerced when present).\n * Default: the first string-valued column in row key order. */\n labelColumn?: string;\n /** Full custom row→result escape hatch: overrides the default mapping\n * (including `typeOf`/`labelColumn`); return `null` to skip a row. The\n * returned `id` MUST already be type-qualified via `encodeSourceId`. */\n mapRow?: (row: OmnigraphSearchRow) => SearchResult<N> | null;\n}\n\n// ---------------------------------------------------------------------------\n// Small pure helpers\n// ---------------------------------------------------------------------------\n\nfunction defaultParams(q: string, limit: number): Record<string, unknown> {\n return { q, limit };\n}\n\nfunction throwIfAborted(signal: AbortSignal, queryName: string): void {\n if (signal.aborted) {\n throw new DOMException(\n `omnigraph: search query '${queryName}' aborted by request signal`,\n 'AbortError',\n );\n }\n}\n\nfunction isAbortError(err: unknown): boolean {\n return err instanceof Error && err.name === 'AbortError';\n}\n\n/** SDK typed errors rethrow as plain prefixed `Error`s; abort rejections\n * and everything else pass through unchanged. */\nfunction mapError(err: unknown): unknown {\n if (err instanceof OmnigraphError && !isAbortError(err)) {\n return new Error(`omnigraph: ${err.name} (status ${err.status}): ${err.message}`);\n }\n return err;\n}\n\n/** A bare-variable projection value: a whole-node struct carrying its\n * physical id (`return { $s }` yields `{ id,...props }`). */\nfunction isNodeStruct(value: unknown): value is { id: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n typeof (value as { id?: unknown }).id === 'string'\n );\n}\n\n/** The invoke response must be a READ envelope with tabular rows — a stored\n * mutation (Change envelope) or malformed body is a hard error. */\nfunction extractRows(response: unknown, queryName: string): readonly OmnigraphSearchRow[] {\n const rows = (response as { rows?: unknown }).rows;\n if (!Array.isArray(rows)) {\n throw new Error(\n `omnigraph: stored query '${queryName}' did not return a read envelope with rows — ` +\n `the configured search query must be a stored READ query (not a mutation)`,\n );\n }\n for (const row of rows) {\n if (typeof row !== 'object' || row === null || Array.isArray(row)) {\n throw new Error(\n `omnigraph: stored query '${queryName}' returned a non-object row — ` +\n `expected column→value row objects`,\n );\n }\n }\n return rows as OmnigraphSearchRow[];\n}\n\ninterface ResolvedIdentity {\n kind: string;\n sourceId: string;\n}\n\n/** Resolve the `(nodeType, physicalId)` pair for one row via `typeOf`. */\nfunction resolveIdentity(\n row: OmnigraphSearchRow,\n typeOf: OmnigraphSearchTypeOf,\n queryName: string,\n): ResolvedIdentity {\n if (typeof typeOf === 'function') {\n const kind = typeOf(row);\n if (typeof kind !== 'string' || kind.length === 0) {\n throw new Error(\n `omnigraph: typeOf returned ${JSON.stringify(kind)} for a '${queryName}' search row — ` +\n `typeOf must return a non-empty node type name`,\n );\n }\n for (const key of Object.keys(row)) {\n const value = row[key];\n if (isNodeStruct(value)) return { kind, sourceId: value.id };\n }\n throw new Error(\n `omnigraph: '${queryName}' search row has no node-struct column (an object with a ` +\n `string 'id') — project the matched entity bare (return { $s }) so its physical ` +\n `id is available`,\n );\n }\n for (const [column, kind] of Object.entries(typeOf)) {\n const value = row[column];\n if (isNodeStruct(value)) return { kind, sourceId: value.id };\n }\n throw new Error(\n `omnigraph: '${queryName}' search row has no node struct under the mapped column(s) ` +\n `${JSON.stringify(Object.keys(typeOf))} — the typeOf record must key the ` +\n `columns that contain bare-variable node projections`,\n );\n}\n\n// ---------------------------------------------------------------------------\n// createOmnigraphSearchService\n// ---------------------------------------------------------------------------\n\n/**\n * Create the stored-query search service. Plug it into core as\n * `services.search`; the instance owns `RequestContext` creation,\n * revision-keyed caching, supersede cancellation, and stale-result rejection\n * at admission.\n */\nexport function createOmnigraphSearchService<N = Record<string, unknown>>(\n options: OmnigraphSearchServiceOptions<N>,\n): SearchService<N> {\n const { graphId, queryName, typeOf, labelColumn, mapRow } = options;\n const branch = options.branch ?? 'main';\n const buildParams = options.params ?? defaultParams;\n /** Every call is scoped to the graph (SDK cluster routing). */\n const client: Omnigraph = options.client.graph(graphId);\n\n function mapRowDefault(row: OmnigraphSearchRow): SearchResult<N> {\n const { kind, sourceId } = resolveIdentity(row, typeOf, queryName);\n const result: SearchResult<N> = { id: encodeSourceId(kind, sourceId) };\n\n const score = row['score'];\n if (typeof score === 'number' && Number.isFinite(score)) result.score = score;\n\n if (labelColumn !== undefined) {\n const value = row[labelColumn];\n if (typeof value === 'string' || typeof value === 'number') result.label = String(value);\n } else {\n for (const key of Object.keys(row)) {\n if (key === 'score') continue; // the score lane never doubles as a label\n const value = row[key];\n if (typeof value === 'string') {\n result.label = value;\n break;\n }\n }\n }\n return result;\n }\n\n return {\n revisionDependencies: ['source'],\n async search(\n q: string,\n searchOptions: { limit: number },\n ctx: RequestContext,\n ): Promise<readonly SearchResult<N>[]> {\n throwIfAborted(ctx.signal, queryName);\n const limit = Number.isFinite(searchOptions.limit) ? Math.floor(searchOptions.limit) : 0;\n if (q.length === 0 || limit <= 0) return [];\n\n const input: InvokeQueryInput = { branch, params: buildParams(q, limit) };\n let response: unknown;\n try {\n response = await client.queries.invoke(queryName, input, { signal: ctx.signal });\n } catch (err) {\n throw mapError(err);\n }\n throwIfAborted(ctx.signal, queryName);\n\n const rows = extractRows(response, queryName);\n const results: SearchResult<N>[] = [];\n for (const row of rows) {\n if (results.length >= limit) break; // defensive cap — the query owns K\n const mapped = mapRow !== undefined ? mapRow(row) : mapRowDefault(row);\n if (mapped !== null) results.push(mapped);\n }\n return results;\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/loader.ts","../src/searchService.ts"],"names":["activeSession","throwIfAborted","isAbortError","mapError","OmnigraphError"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * v1 export loader.\n *\n * The organizing rule: graphs load via `og.export` — one streamed\n * NDJSON pass, edge lines first (lexicographic table-key order), driven\n * straight into a `purpose:'replace'` ingest session on the target. Queries\n * never introduce nodes or edges.\n *\n * Revision stamp: the canonical `sourceRevision` hashes\n * `{ graphId, branch, headBefore, headAfter, schemaFingerprint }` (plus the\n * sorted `typeNames` subset when the export is partial), but\n * `headAfter` is only knowable after the stream — while core's\n * `BeginIngestOptions` requires `sourceRevision` up front for a replace\n * session. Resolution: under the rejecting/retrying policies the session\n * begins under the PROVISIONAL revision (the canonical hash with\n * `headAfter:= headBefore`), the stream appends into it, and `headAfter` is\n * captured BEFORE `commit`. `accept-warn` is the exception: normalized\n * batches are buffered until `headAfter` is known, then appended once into a\n * session opened with the canonical FINAL revision:\n *\n * - equal heads → provisional === final; commit cleanly. The session only\n * ever commits a revision whose hash is truthful.\n * - drifted heads → `driftPolicy` decides: `'reject'` aborts the session\n * (graph untouched) and throws {@link OmnigraphDriftError};\n * `'accept-warn'` commits the buffered export under the\n * final revision, records BOTH heads in `dataRef`, and\n * adds a warning;\n * `'retry-once'` aborts and restarts the whole load once\n * (a second drift rejects).\n *\n * This is sound because a replace session is atomic and invisible until\n * commit: nothing is published under a revision the policy did not\n * explicitly accept.\n *\n * Error surface: SDK typed errors never cross this package's public\n * surface — they are mapped to plain `Error`s with a stable `omnigraph:`\n * message prefix.\n */\n\nimport { OmnigraphError, SERVER_VERSION } from '@modernrelay/omnigraph';\nimport type { CallOptions, ExportInput, Omnigraph } from '@modernrelay/omnigraph';\nimport { OrbitOperationError } from '@modernrelay/orbit-core';\nimport type { GraphEdge, GraphNode, IngestBatch, IngestSession } from '@modernrelay/orbit-core';\n\nimport { classifyExportLine, normalizeEdge, normalizeNode } from './normalize';\nimport { bigIntKeyWarnings, parsePgSchema, schemaFingerprint } from './pgSchema';\nimport type { PgSchema } from './pgSchema';\nimport type {\n IngestTarget,\n OmnigraphDataRef,\n OmnigraphLoadResult,\n OmnigraphSourceOptions,\n} from './types';\n\nconst DEFAULT_BATCH_SIZE = 2000;\n\n/**\n * Finite whole-export cap for the necessarily atomic replace session. A\n * whole-graph load stages EVERY row before commit, so this is a total-load\n * memory bound, not a backpressure window — real graphs routinely exceed\n * 100 MB of serialized rows (the intel fixture streams ~128 MB), so the\n * default is deliberately generous; callers with tighter memory budgets pass\n * `maxPendingBytes` explicitly.\n */\nconst DEFAULT_MAX_PENDING_BYTES = 512 * 1024 * 1024;\n\n/** Stateless and safe to reuse; counts serialized UTF-8 rather than UTF-16 code units. */\nconst UTF8_ENCODER = new TextEncoder();\n\n/**\n * Raised when a branch moves during export and the configured drift policy\n * rejects the load. The session is aborted and the target graph is untouched.\n */\nexport class OmnigraphDriftError extends Error {\n override readonly name = 'OmnigraphDriftError';\n readonly graphId: string;\n readonly branch: string;\n readonly headBefore: string;\n readonly headAfter: string;\n constructor(graphId: string, branch: string, headBefore: string, headAfter: string) {\n super(\n `omnigraph: branch '${branch}' of graph '${graphId}' changed during export ` +\n `(head ${headBefore} → ${headAfter}); session aborted per driftPolicy (` +\n `service:omnigraph-source-changed-during-export)`,\n );\n this.graphId = graphId;\n this.branch = branch;\n this.headBefore = headBefore;\n this.headAfter = headAfter;\n }\n}\n\n/** The one load path a v1 source exposes. */\nexport interface OmnigraphSource {\n /**\n * Stream one export of the configured graph/branch into `target` via a\n * `purpose:'replace'` ingest session. Resolves with the revision-stamped\n * result; rejects with the session aborted and the target untouched.\n * `signal` aborts both the HTTP stream and the session.\n */\n load(target: IngestTarget, signal?: AbortSignal): Promise<OmnigraphLoadResult>;\n}\n\n// ---------------------------------------------------------------------------\n// Small pure helpers\n// ---------------------------------------------------------------------------\n\n/** FNV-1a 64-bit over the UTF-8 bytes of `s`, as 16 lowercase hex chars. */\nfunction hash64(s: string): string {\n const MASK64 = 0xffffffffffffffffn;\n let h = 0xcbf29ce484222325n;\n for (const b of new TextEncoder().encode(s)) {\n h ^= BigInt(b);\n h = (h * 0x100000001b3n) & MASK64;\n }\n return h.toString(16).padStart(16, '0');\n}\n\n/**\n * The canonical adapter source revision: a hash of the readable `dataRef` object\n * `{ graphId, branch, headBefore, headAfter, schemaFingerprint, typeNames? }`\n * (`dataRef` itself retains the readable form).\n */\nfunction canonicalSourceRevision(ref: OmnigraphDataRef): string {\n // typeNames joins the tuple ONLY when present, so full-export\n // hashes stay byte-identical to every previously persisted revision.\n const tuple: unknown[] = [\n ref.graphId,\n ref.branch,\n ref.headBefore,\n ref.headAfter,\n ref.schemaFingerprint,\n ];\n if (ref.typeNames !== undefined) tuple.push(ref.typeNames);\n return `og:${hash64(JSON.stringify(tuple))}`;\n}\n\n/** `'0.8.1'` → `'0.8'`; null when unparseable. */\nfunction majorMinor(version: string): string | null {\n const m = /^(\\d+)\\.(\\d+)/.exec(version);\n return m ? `${m[1]}.${m[2]}` : null;\n}\n\n/** CallOptions without an explicit-undefined signal (exactOptionalPropertyTypes). */\nfunction callOpts(signal: AbortSignal | undefined): CallOptions {\n return signal ? { signal } : {};\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw new DOMException('omnigraph: load aborted by caller signal', 'AbortError');\n }\n}\n\nfunction isAbortError(err: unknown): boolean {\n return err instanceof Error && err.name === 'AbortError';\n}\n\n/**\n * SDK typed errors (`NetworkError`, `ConflictError`, …) never leak across the\n * public surface; they rethrow as plain `Error`s with a stable prefix.\n * Abort rejections and this package's own errors pass through unchanged.\n */\nfunction mapError(err: unknown, signal?: AbortSignal): unknown {\n throwIfAborted(signal);\n if (err instanceof OmnigraphError && !isAbortError(err)) {\n return new Error(`omnigraph: ${err.name} (status ${err.status}): ${err.message}`);\n }\n return err;\n}\n\nfunction pushUnique(warnings: string[], warning: string): void {\n if (!warnings.includes(warning)) warnings.push(warning);\n}\n\n// ---------------------------------------------------------------------------\n// createOmnigraphSource\n// ---------------------------------------------------------------------------\n\ninterface AttemptSuccess {\n kind: 'done';\n sourceRevision: string;\n dataRef: OmnigraphDataRef;\n counts: { lines: number; nodes: number; edges: number; bytes: number };\n}\n\ninterface AttemptRetry {\n kind: 'retry';\n}\n\n/**\n * Create a v1 export-backed data source. The client must be\n * preconfigured. In the browser, use a safe same-origin or public client;\n * there is deliberately no `baseUrl`/`token` option here. Authenticated\n * construction lives only in `@modernrelay/orbit-omnigraph/server`.\n */\nexport function createOmnigraphSource(options: OmnigraphSourceOptions): OmnigraphSource {\n const graphId = options.graphId;\n const branch = options.branch ?? 'main';\n const batchSize =\n options.batchSize === undefined ? DEFAULT_BATCH_SIZE : options.batchSize;\n if (!Number.isSafeInteger(batchSize) || batchSize <= 0) {\n throw new TypeError('createOmnigraphSource: batchSize must be a positive safe integer');\n }\n const maxPendingBytes =\n options.maxPendingBytes === undefined ? DEFAULT_MAX_PENDING_BYTES : options.maxPendingBytes;\n if (!Number.isSafeInteger(maxPendingBytes) || maxPendingBytes <= 0) {\n throw new TypeError(\n 'createOmnigraphSource: maxPendingBytes must be a positive safe integer',\n );\n }\n const driftPolicy = options.driftPolicy ?? 'reject';\n const onProgress = options.onProgress;\n // Sorted canonical form: ['B','A'] and ['A','B'] are the SAME subset and\n // must produce the same identity coordinate.\n const typeNames =\n options.typeNames === undefined ? undefined : [...options.typeNames].sort();\n /** Every call is scoped to the graph (SDK cluster routing). */\n const client: Omnigraph = options.client.graph(graphId);\n // A partial export is a DIFFERENT dataset lifetime than the full graph;\n // positions, selection, and history must not carry across subsets.\n const datasetKey =\n typeNames === undefined\n ? `og:${graphId}:${branch}`\n : `og:${graphId}:${branch}:types=${typeNames.join(',')}`;\n\n async function newestHead(signal: AbortSignal | undefined): Promise<string> {\n // A fresh first page captures the current branch head. We only need that\n // coordinate, not the full history or a continuation pinned to an old head.\n const { headCommitId } = await client.commits.list({ branch, limit: 1 }, callOpts(signal));\n if (headCommitId == null) {\n throw new Error(\n `omnigraph: branch '${branch}' of graph '${graphId}' has no commits — nothing to export`,\n );\n }\n return headCommitId;\n }\n\n async function runAttempt(\n target: IngestTarget,\n signal: AbortSignal | undefined,\n warnings: string[],\n attempt: number,\n ): Promise<AttemptSuccess | AttemptRetry> {\n throwIfAborted(signal);\n // Pin the target's SOURCE lineage before any remote work: a competing\n // replace/snapshot landing mid-stream must fail the load. Overlay-only\n // model advances are benign for a replace commit (it supersedes overlays\n // anyway), so the CAS base itself is read fresh at each beginIngest\n // pinning it here made long accept-warn streams fail late (and livelock)\n // under unrelated concurrent overlay traffic.\n const baseSource = target.getRevisions().source;\n\n // The before/after head bracket must enclose BOTH the schema read and the\n // export. Otherwise a schema migration between schema.get and the first\n // head sample could look quiescent while we normalize with stale types.\n const headBefore = await newestHead(signal);\n\n // Endpoint-type resolution + wire-type normalization + the fingerprint\n // half of the revision stamp.\n const schemaSource = (await client.schema.get(callOpts(signal))).schemaSource;\n const schema: PgSchema = parsePgSchema(schemaSource);\n const fingerprint = schemaFingerprint(schemaSource);\n for (const hazard of bigIntKeyWarnings(schema)) {\n pushUnique(\n warnings,\n `omnigraph: ${hazard.type}.${hazard.property} is a 64-bit integer schema key — ` +\n `JSON parsing silently rounds attribute values past ±2^53; physical ids remain exact strings`,\n );\n }\n // NOTE: a schema-declared `type` property needs no warning — the\n // adapter's discriminator lives at the namespaced ORBIT_TYPE_KEY, so the\n // source's own `type` loads as ordinary data with nothing to report.\n\n const provisionalRef: OmnigraphDataRef = {\n graphId,\n branch,\n headBefore,\n headAfter: headBefore, // provisional: assume quiescence, verify after the stream\n schemaFingerprint: fingerprint,\n ...(typeNames !== undefined ? { typeNames } : {}),\n };\n const provisionalRevision = canonicalSourceRevision(provisionalRef);\n\n function beginSession(sourceRevision: string): IngestSession {\n const now = target.getRevisions();\n if (now.source !== baseSource) {\n throw new Error(\n `omnigraph: the target's source lineage changed while the load was streaming ` +\n `(a competing replace or snapshot landed); aborting instead of overwriting it`,\n );\n }\n return target.beginIngest({\n purpose: 'replace',\n datasetKey,\n sourceRevision,\n baseModelRevision: now.model,\n maxPendingBytes,\n });\n }\n\n // `accept-warn` cannot open a truthful session until headAfter is known.\n // Buffer only that opt-in policy; rejecting/retrying loads keep streaming\n // directly into the atomic target under the provisional revision.\n let session: IngestSession | undefined =\n driftPolicy === 'accept-warn' ? undefined : beginSession(provisionalRevision);\n const requestId = hash64(`${datasetKey}|${provisionalRevision}|${attempt}`);\n\n interface BufferedBatch {\n nodes: GraphNode[];\n edges: GraphEdge[];\n bytes: number;\n progress: { lines: number; nodes: number; edges: number; bytes: number };\n }\n const bufferedBatches: Array<BufferedBatch | undefined> | undefined =\n driftPolicy === 'accept-warn' ? [] : undefined;\n\n let lines = 0;\n let nodeCount = 0;\n let edgeCount = 0;\n let bytes = 0;\n let unknown = 0;\n let sequence = 0;\n let pendingNodes: GraphNode[] = [];\n let pendingEdges: GraphEdge[] = [];\n let pendingBytes = 0;\n let acceptedBytes = 0;\n\n /**\n * Replace ingestion is atomic, so neither core staging nor accept-warn's\n * adapter buffer can drain before commit. Enforce the same finite\n * whole-load budget before retaining the next normalized row.\n */\n function accountAcceptedBytes(lineBytes: number): void {\n const next = acceptedBytes + lineBytes;\n if (next > maxPendingBytes) {\n throw new OrbitOperationError(\n { code: 'queue-overflow', queuedBytes: next, limit: maxPendingBytes },\n `omnigraph: export rows require at least ${next} bytes, exceeding ` +\n `maxPendingBytes ${maxPendingBytes}; load aborted before commit`,\n );\n }\n acceptedBytes = next;\n pendingBytes += lineBytes;\n }\n\n /** Await every append; retain bounded adapter-side pending batches. */\n async function flush(): Promise<void> {\n if (pendingNodes.length === 0 && pendingEdges.length === 0) return;\n const nodes = pendingNodes;\n const edges = pendingEdges;\n const batchBytes = pendingBytes;\n const progress = { lines, nodes: nodeCount, edges: edgeCount, bytes };\n pendingNodes = [];\n pendingEdges = [];\n pendingBytes = 0;\n\n if (bufferedBatches !== undefined) {\n bufferedBatches.push({ nodes, edges, bytes: batchBytes, progress });\n return;\n }\n\n const activeSession = session;\n if (activeSession === undefined) throw new Error('omnigraph: internal missing ingest session');\n const batch: IngestBatch = {\n sequence,\n batchId: `og:${requestId}:${sequence}`,\n bytes: batchBytes,\n };\n if (edges.length > 0) batch.edges = edges;\n if (nodes.length > 0) batch.nodes = nodes;\n sequence += 1;\n await activeSession.append(batch);\n onProgress?.(progress);\n }\n\n /** Commit buffered accept-warn rows once, under the now-known final revision. */\n async function commitBuffered(sourceRevision: string): Promise<void> {\n if (bufferedBatches === undefined) {\n throw new Error('omnigraph: internal missing accept-warn batch buffer');\n }\n const finalSession = beginSession(sourceRevision);\n session = finalSession;\n const finalRequestId = hash64(`${datasetKey}|${sourceRevision}|${attempt}`);\n for (let i = 0; i < bufferedBatches.length; i++) {\n throwIfAborted(signal);\n const buffered = bufferedBatches[i];\n if (buffered === undefined) continue;\n // Release the buffer's array slot as soon as ownership passes to the\n // target session; the local `buffered` reference dies this iteration.\n bufferedBatches[i] = undefined;\n const batch: IngestBatch = {\n sequence: i,\n batchId: `og:${finalRequestId}:${i}`,\n bytes: buffered.bytes,\n };\n if (buffered.edges.length > 0) batch.edges = buffered.edges;\n if (buffered.nodes.length > 0) batch.nodes = buffered.nodes;\n await finalSession.append(batch);\n onProgress?.(buffered.progress);\n }\n bufferedBatches.length = 0;\n throwIfAborted(signal);\n await finalSession.commit();\n }\n\n // Bind the iterator ONCE and\n // make sure early exits cancel the underlying stream via `return`.\n const exportInput: ExportInput = { branch, ...(typeNames !== undefined ? { typeNames } : {}) };\n const iterator = client\n .export<Record<string, unknown>>(exportInput, callOpts(signal))\n [Symbol.asyncIterator]();\n\n try {\n for (;;) {\n throwIfAborted(signal);\n const step = await iterator.next();\n if (step.done === true) break;\n const line = step.value;\n lines += 1;\n // The SDK exposes parsed rows rather than raw chunks. Re-serialize to\n // UTF-8 and include one NDJSON newline: a conservative, consistent\n // accounting unit for progress, batches, and the whole-load cap.\n const lineBytes = UTF8_ENCODER.encode(JSON.stringify(line)).byteLength + 1;\n bytes += lineBytes;\n const classified = classifyExportLine(line);\n if (classified.kind === 'node') {\n const node = normalizeNode(classified, schema);\n accountAcceptedBytes(lineBytes);\n pendingNodes.push(node);\n nodeCount += 1;\n } else if (classified.kind === 'edge') {\n const edge = normalizeEdge(classified, schema);\n accountAcceptedBytes(lineBytes);\n pendingEdges.push(edge);\n edgeCount += 1;\n } else {\n unknown += 1;\n }\n if (pendingNodes.length + pendingEdges.length >= batchSize) await flush();\n }\n await flush();\n\n if (unknown > 0) {\n pushUnique(warnings, `omnigraph: skipped ${unknown} unrecognized export line(s)`);\n }\n\n // Revision stamp, second half: the head AFTER the stream, captured\n // BEFORE commit.\n throwIfAborted(signal);\n const headAfter = await newestHead(signal);\n throwIfAborted(signal);\n const counts = { lines, nodes: nodeCount, edges: edgeCount, bytes };\n\n if (driftPolicy === 'accept-warn') {\n const finalRef: OmnigraphDataRef = { ...provisionalRef, headAfter };\n const finalRevision = canonicalSourceRevision(finalRef);\n if (headAfter !== headBefore) {\n pushUnique(\n warnings,\n `omnigraph: branch '${branch}' advanced during export (head ${headBefore} → ` +\n `${headAfter}); committed under the canonical final revision per ` +\n `driftPolicy:'accept-warn' — dataRef records both heads`,\n );\n }\n await commitBuffered(finalRevision);\n return { kind: 'done', sourceRevision: finalRevision, dataRef: finalRef, counts };\n }\n\n if (headAfter === headBefore) {\n const activeSession = session;\n if (activeSession === undefined) throw new Error('omnigraph: internal missing ingest session');\n await activeSession.commit();\n return { kind: 'done', sourceRevision: provisionalRevision, dataRef: provisionalRef, counts };\n }\n\n // Branch drift maps to service:omnigraph-source-changed-during-export.\n const activeSession = session;\n if (activeSession === undefined) throw new Error('omnigraph: internal missing ingest session');\n await activeSession.abort('omnigraph: source changed during export');\n if (driftPolicy === 'retry-once' && attempt === 1) {\n pushUnique(\n warnings,\n `omnigraph: branch '${branch}' advanced during export (head ${headBefore} → ` +\n `${headAfter}); load restarted once per driftPolicy:'retry-once'`,\n );\n return { kind: 'retry' };\n }\n throw new OmnigraphDriftError(graphId, branch, headBefore, headAfter);\n } catch (err) {\n if (session?.state === 'open') {\n try {\n await session.abort(err);\n } catch {\n // the original failure wins\n }\n }\n throw mapError(err, signal);\n } finally {\n // Cancel the underlying NDJSON stream on any non-exhausted exit.\n try {\n await iterator.return?.();\n } catch {\n // stream teardown must never mask the outcome\n }\n }\n }\n\n async function load(target: IngestTarget, signal?: AbortSignal): Promise<OmnigraphLoadResult> {\n const warnings: string[] = [];\n\n // Surface build-version skew as a warning after the SDK verifies the\n // HTTP API contract. Contract mismatches are hard failures.\n let serverVersion: string;\n try {\n serverVersion = (await client.health(callOpts(signal))).version;\n } catch (err) {\n throw mapError(err, signal);\n }\n const server = majorMinor(serverVersion);\n const sdk = majorMinor(SERVER_VERSION);\n if (server === null || server !== sdk) {\n warnings.push(\n `omnigraph: server version ${serverVersion} does not match the SDK-pinned server ` +\n `version ${SERVER_VERSION} (major.minor differ) — SDK behavior is undefined ` +\n `against this server`,\n );\n }\n\n for (let attempt = 1; ; attempt += 1) {\n let outcome: AttemptSuccess | AttemptRetry;\n try {\n outcome = await runAttempt(target, signal, warnings, attempt);\n } catch (err) {\n // Covers SDK errors thrown before the session/stream phase\n // (schema.get, commits.list); mapError is a no-op on already-mapped\n // or package-owned errors.\n throw mapError(err, signal);\n }\n if (outcome.kind === 'retry') continue;\n return {\n sourceRevision: outcome.sourceRevision,\n dataRef: outcome.dataRef,\n counts: outcome.counts,\n serverVersion,\n warnings,\n };\n }\n }\n\n return { load };\n}\n","/**\n * Stored-query `SearchService` integration.\n *\n * A stored query using `bm25`/`fuzzy`/`nearest`/`rrf` with\n * `order { score desc } limit K` returns entity rows plus a score column; this\n * module wires it as a `SearchService` via\n * `og.queries.invoke(name, { params, branch })`, passing\n * `RequestContext.signal` through SDK `CallOptions`. Core performs revision\n * admission — the service only declares `revisionDependencies: ['source']`\n * (results come from the server-side branch, so they are invalidated by a\n * source change, never by client-side model/scope drift).\n *\n * Identity: Omnigraph ids are unique per type only, and a query row\n * carries no type discriminator of its own — so the adapter REQUIRES a\n * caller-supplied column→node-type mapping (`typeOf`), either a\n * `{ column: NodeType }` record keyed by the projection columns that hold\n * bare-variable node structs, or a per-row function. Every returned id is\n * qualified through `encodeSourceId(nodeType, physicalId)` — the same codec\n * every other adapter path uses — so results round-trip `decodeSourceId` and\n * match export-loaded node ids exactly.\n *\n * Partial-load caveat: search runs server-side over the whole branch, so a\n * partial export load can return ids outside the loaded set.\n * `activateSearchResult` classifies those as `'not-loaded'`; constrain the\n * stored query to the loaded types, or load the full graph, to avoid the\n * mismatch.\n *\n * Error surface: SDK typed errors never cross this package's public\n * surface — they rethrow as plain `Error`s with the stable `omnigraph:`\n * prefix. Abort rejections pass through unchanged.\n */\n\nimport { OmnigraphError } from '@modernrelay/omnigraph';\nimport type { InvokeQueryInput, Omnigraph } from '@modernrelay/omnigraph';\nimport type { RequestContext, SearchResult, SearchService } from '@modernrelay/orbit-core';\n\nimport { encodeSourceId } from './idCodec';\n\n/** One stored-query result row: projection column → value. Bare-variable\n * projections (`return { $s }`) hold whole-node structs including `@id`. */\nexport type OmnigraphSearchRow = Record<string, unknown>;\n\n/**\n * The required column→node-type mapping:\n *\n * - a record `{ s: 'Signal' }` — the FIRST listed column present in a row\n * with a node struct supplies the physical id, encoded under the mapped\n * type name;\n * - or a per-row function returning the node type name — the row's first\n * node-struct column (row key order) supplies the physical id.\n */\nexport type OmnigraphSearchTypeOf =\n | ((row: OmnigraphSearchRow) => string)\n | Readonly<Record<string, string>>;\n\nexport interface OmnigraphSearchServiceOptions<N = Record<string, unknown>> {\n /** A **preconfigured** SDK client — no `baseUrl`/`token` here. */\n client: Omnigraph;\n /** Cluster graph id; the invoke is scoped via `client.graph(graphId)`. */\n graphId: string;\n /** Branch the stored query reads. Default `'main'`. */\n branch?: string;\n /** Registry name of the stored search query (`POST /queries/{name}`).\n * Invoking a known name works whether or not it is `mcp.expose`d. */\n queryName: string;\n /** Builds the stored query's `params` object from the call.\n * Default: `(q, limit) => ({ q, limit })`. */\n params?: (q: string, limit: number) => Record<string, unknown>;\n /** REQUIRED mapping from row to node type — see\n * {@link OmnigraphSearchTypeOf}. */\n typeOf: OmnigraphSearchTypeOf;\n /** Column whose value becomes `label` (String-coerced when present).\n * Default: the first string-valued column in row key order. */\n labelColumn?: string;\n /** Full custom row→result escape hatch: overrides the default mapping\n * (including `typeOf`/`labelColumn`); return `null` to skip a row. The\n * returned `id` MUST already be type-qualified via `encodeSourceId`. */\n mapRow?: (row: OmnigraphSearchRow) => SearchResult<N> | null;\n}\n\n// ---------------------------------------------------------------------------\n// Small pure helpers\n// ---------------------------------------------------------------------------\n\nfunction defaultParams(q: string, limit: number): Record<string, unknown> {\n return { q, limit };\n}\n\nfunction throwIfAborted(signal: AbortSignal, queryName: string): void {\n if (signal.aborted) {\n throw new DOMException(\n `omnigraph: search query '${queryName}' aborted by request signal`,\n 'AbortError',\n );\n }\n}\n\nfunction isAbortError(err: unknown): boolean {\n return err instanceof Error && err.name === 'AbortError';\n}\n\n/** SDK typed errors rethrow as plain prefixed `Error`s; abort rejections\n * and everything else pass through unchanged. */\nfunction mapError(err: unknown): unknown {\n if (err instanceof OmnigraphError && !isAbortError(err)) {\n return new Error(`omnigraph: ${err.name} (status ${err.status}): ${err.message}`);\n }\n return err;\n}\n\n/** A bare-variable projection value: a whole-node struct carrying its\n * physical id (`return { $s }` yields `s: { '@id': ..., ...props }`). */\nfunction isNodeStruct(value: unknown): value is { '@id': string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n typeof (value as { '@id'?: unknown })['@id'] === 'string'\n );\n}\n\n/** The invoke response must be a READ envelope with tabular rows — a stored\n * mutation (Change envelope) or malformed body is a hard error. */\nfunction extractRows(response: unknown, queryName: string): readonly OmnigraphSearchRow[] {\n const rows = (response as { rows?: unknown }).rows;\n if (!Array.isArray(rows)) {\n throw new Error(\n `omnigraph: stored query '${queryName}' did not return a read envelope with rows — ` +\n `the configured search query must be a stored READ query (not a mutation)`,\n );\n }\n for (const row of rows) {\n if (typeof row !== 'object' || row === null || Array.isArray(row)) {\n throw new Error(\n `omnigraph: stored query '${queryName}' returned a non-object row — ` +\n `expected column→value row objects`,\n );\n }\n }\n return rows as OmnigraphSearchRow[];\n}\n\ninterface ResolvedIdentity {\n kind: string;\n sourceId: string;\n}\n\n/** Resolve the `(nodeType, physicalId)` pair for one row via `typeOf`. */\nfunction resolveIdentity(\n row: OmnigraphSearchRow,\n typeOf: OmnigraphSearchTypeOf,\n queryName: string,\n): ResolvedIdentity {\n if (typeof typeOf === 'function') {\n const kind = typeOf(row);\n if (typeof kind !== 'string' || kind.length === 0) {\n throw new Error(\n `omnigraph: typeOf returned ${JSON.stringify(kind)} for a '${queryName}' search row — ` +\n `typeOf must return a non-empty node type name`,\n );\n }\n for (const key of Object.keys(row)) {\n const value = row[key];\n if (isNodeStruct(value)) return { kind, sourceId: value['@id'] };\n }\n throw new Error(\n `omnigraph: '${queryName}' search row has no node-struct column (an object with a ` +\n `string '@id') — project the matched entity bare (return { $s }) so its physical ` +\n `id is available`,\n );\n }\n for (const [column, kind] of Object.entries(typeOf)) {\n const value = row[column];\n if (isNodeStruct(value)) return { kind, sourceId: value['@id'] };\n }\n throw new Error(\n `omnigraph: '${queryName}' search row has no node struct under the mapped column(s) ` +\n `${JSON.stringify(Object.keys(typeOf))} — the typeOf record must key the ` +\n `columns that contain bare-variable node projections`,\n );\n}\n\n// ---------------------------------------------------------------------------\n// createOmnigraphSearchService\n// ---------------------------------------------------------------------------\n\n/**\n * Create the stored-query search service. Plug it into core as\n * `services.search`; the instance owns `RequestContext` creation,\n * revision-keyed caching, supersede cancellation, and stale-result rejection\n * at admission.\n */\nexport function createOmnigraphSearchService<N = Record<string, unknown>>(\n options: OmnigraphSearchServiceOptions<N>,\n): SearchService<N> {\n const { graphId, queryName, typeOf, labelColumn, mapRow } = options;\n const branch = options.branch ?? 'main';\n const buildParams = options.params ?? defaultParams;\n /** Every call is scoped to the graph (SDK cluster routing). */\n const client: Omnigraph = options.client.graph(graphId);\n\n function mapRowDefault(row: OmnigraphSearchRow): SearchResult<N> {\n const { kind, sourceId } = resolveIdentity(row, typeOf, queryName);\n const result: SearchResult<N> = { id: encodeSourceId(kind, sourceId) };\n\n const score = row['score'];\n if (typeof score === 'number' && Number.isFinite(score)) result.score = score;\n\n if (labelColumn !== undefined) {\n const value = row[labelColumn];\n if (typeof value === 'string' || typeof value === 'number') result.label = String(value);\n } else {\n for (const key of Object.keys(row)) {\n if (key === 'score') continue; // the score lane never doubles as a label\n const value = row[key];\n if (typeof value === 'string') {\n result.label = value;\n break;\n }\n }\n }\n return result;\n }\n\n return {\n revisionDependencies: ['source'],\n async search(\n q: string,\n searchOptions: { limit: number },\n ctx: RequestContext,\n ): Promise<readonly SearchResult<N>[]> {\n throwIfAborted(ctx.signal, queryName);\n const limit = Number.isFinite(searchOptions.limit) ? Math.floor(searchOptions.limit) : 0;\n if (q.length === 0 || limit <= 0) return [];\n\n const input: InvokeQueryInput = { branch, params: buildParams(q, limit) };\n let response: unknown;\n try {\n response = await client.queries.invoke(queryName, input, { signal: ctx.signal });\n } catch (err) {\n // Stored-query POSTs can also mutate, so the SDK reports a dispatched\n // cancellation conservatively. This service's contract is read-only;\n // retain Orbit's AbortError surface when its caller cancelled.\n throwIfAborted(ctx.signal, queryName);\n throw mapError(err);\n }\n throwIfAborted(ctx.signal, queryName);\n\n const rows = extractRows(response, queryName);\n const results: SearchResult<N>[] = [];\n for (const row of rows) {\n if (results.length >= limit) break; // defensive cap — the query owns K\n const mapped = mapRow !== undefined ? mapRow(row) : mapRowDefault(row);\n if (mapped !== null) results.push(mapped);\n }\n return results;\n },\n };\n}\n"]}
|
package/dist/server.d.ts
CHANGED
|
@@ -5,8 +5,7 @@ import { FetchLike, Omnigraph } from '@modernrelay/omnigraph';
|
|
|
5
5
|
*
|
|
6
6
|
* This module is the ONLY place in the adapter where an authenticated
|
|
7
7
|
* Omnigraph client is constructed. It must never be imported from browser
|
|
8
|
-
* code:
|
|
9
|
-
* bearer tokens (secret material), so browser deployments pass a
|
|
8
|
+
* code: this helper uses a static bearer token (secret material), so browser deployments pass a
|
|
10
9
|
* preconfigured safe same-origin/public client to `createOmnigraphSource`
|
|
11
10
|
* instead — typically routing reads through a proxy/BFF. The client-bundle
|
|
12
11
|
* exclusion gate in `scripts/pack-smoke.mjs` checks the
|
|
@@ -29,4 +28,5 @@ interface OmnigraphServerClientOptions {
|
|
|
29
28
|
*/
|
|
30
29
|
declare function createOmnigraphServerClient(options: OmnigraphServerClientOptions): Omnigraph;
|
|
31
30
|
|
|
32
|
-
export {
|
|
31
|
+
export { createOmnigraphServerClient };
|
|
32
|
+
export type { OmnigraphServerClientOptions };
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"sources":["../src/server.ts"],"names":[],"mappings":";;;AA8BO,SAAS,4BAA4B,OAAA,EAAkD;AAC5F,EAAA,MAAM,OAAyB,EAAE,OAAA,EAAS,QAAQ,OAAA,EAAS,KAAA,EAAO,QAAQ,KAAA,EAAM;AAChF,EAAA,IAAI,OAAA,CAAQ,KAAA,KAAU,MAAA,EAAW,IAAA,CAAK,QAAQ,OAAA,CAAQ,KAAA;AACtD,EAAA,OAAO,IAAI,UAAU,IAAI,CAAA;AAC3B","file":"server.js","sourcesContent":["/**\n * @modernrelay/orbit-omnigraph/server — **SERVER-ONLY** entry.\n *\n * This module is the ONLY place in the adapter where an authenticated\n * Omnigraph client is constructed. It must never be imported from browser\n * code: this helper uses a static bearer token (secret material), so browser deployments pass a\n * preconfigured safe same-origin/public client to `createOmnigraphSource`\n * instead — typically routing reads through a proxy/BFF. The client-bundle\n * exclusion gate in `scripts/pack-smoke.mjs` checks the\n * `createOmnigraphServerClient` sentinel and enforces that the browser entry\n * never pulls this module in.\n */\n\nimport { Omnigraph } from '@modernrelay/omnigraph';\nimport type { FetchLike, OmnigraphOptions } from '@modernrelay/omnigraph';\n\nexport interface OmnigraphServerClientOptions {\n /** Base URL of the omnigraph-server, e.g. `http://127.0.0.1:8080`. */\n baseUrl: string;\n /** Static bearer token — secret material; must stay server-side. */\n token: string;\n /** Inject a custom fetch (tracing, agents, testing). */\n fetch?: FetchLike;\n}\n\n/**\n * Construct an authenticated Omnigraph SDK client for server-only use. Pass\n * the result to `createOmnigraphSource({ client,... })` in server code, or\n * hand graph-scoped clones out via `client.graph(id)`.\n */\nexport function createOmnigraphServerClient(options: OmnigraphServerClientOptions): Omnigraph {\n const opts: OmnigraphOptions = { baseUrl: options.baseUrl, token: options.token };\n if (options.fetch !== undefined) opts.fetch = options.fetch;\n return new Omnigraph(opts);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modernrelay/orbit-omnigraph",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Omnigraph adapter for Orbit: og.export() loader with drift policies, .pg schema parser, and typed codegen.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
"directory": "packages/omnigraph"
|
|
10
10
|
},
|
|
11
11
|
"type": "module",
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=22"
|
|
14
|
+
},
|
|
12
15
|
"sideEffects": false,
|
|
13
16
|
"files": [
|
|
14
17
|
"dist"
|
|
@@ -30,12 +33,13 @@
|
|
|
30
33
|
"orbit-omnigraph-codegen": "./dist/codegen-cli.js"
|
|
31
34
|
},
|
|
32
35
|
"dependencies": {
|
|
33
|
-
"@modernrelay/omnigraph": "0.
|
|
34
|
-
"@modernrelay/orbit-core": "0.
|
|
36
|
+
"@modernrelay/omnigraph": "0.14.0",
|
|
37
|
+
"@modernrelay/orbit-core": "0.19.0"
|
|
35
38
|
},
|
|
36
39
|
"devDependencies": {
|
|
37
|
-
"typescript": "^
|
|
38
|
-
"vitest": "^
|
|
40
|
+
"typescript": "^7.0.2",
|
|
41
|
+
"vitest": "^5.0.5",
|
|
42
|
+
"@types/node": "^26.6.5"
|
|
39
43
|
},
|
|
40
44
|
"scripts": {
|
|
41
45
|
"build": "tsup",
|