tina4-nodejs 3.13.110 → 3.13.111

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.
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Engine-neutral graph shapes — the mirror of the relational DatabaseResult.
3
+ *
4
+ * GraphNode / GraphEdge are the portable node/edge core the unified surface
5
+ * returns; GraphResult is the raw-query result (records + columns), the same
6
+ * shape as `DatabaseResult`, so a graph read feels exactly like a SQL read.
7
+ * See tina4-documentation/plan/v3/decisions/ADR-0059.md and features/139.
8
+ */
9
+
10
+ /** Engine-neutral vertex: id, labels, properties. */
11
+ export class GraphNode {
12
+ readonly id: string;
13
+ readonly labels: string[];
14
+ readonly properties: Record<string, unknown>;
15
+
16
+ constructor(
17
+ id: string,
18
+ labels: string[] | null | undefined = null,
19
+ properties: Record<string, unknown> | null | undefined = null,
20
+ ) {
21
+ this.id = id;
22
+ this.labels = [...(labels ?? [])];
23
+ this.properties = { ...(properties ?? {}) };
24
+ }
25
+
26
+ toDict(): Record<string, unknown> {
27
+ return { id: this.id, labels: this.labels, properties: this.properties };
28
+ }
29
+ }
30
+
31
+ /** Engine-neutral edge: id, type, from/to node ids, properties. */
32
+ export class GraphEdge {
33
+ readonly id: string;
34
+ readonly type: string;
35
+ readonly from: string;
36
+ readonly to: string;
37
+ readonly properties: Record<string, unknown>;
38
+
39
+ constructor(
40
+ id: string,
41
+ type: string,
42
+ from: string,
43
+ to: string,
44
+ properties: Record<string, unknown> | null | undefined = null,
45
+ ) {
46
+ this.id = id;
47
+ this.type = type;
48
+ this.from = from;
49
+ this.to = to;
50
+ this.properties = { ...(properties ?? {}) };
51
+ }
52
+
53
+ toDict(): Record<string, unknown> {
54
+ return {
55
+ id: this.id,
56
+ type: this.type,
57
+ from: this.from,
58
+ to: this.to,
59
+ properties: this.properties,
60
+ };
61
+ }
62
+ }
63
+
64
+ /** A raw-query result — records + columns, same shape as DatabaseResult. */
65
+ export class GraphResult implements Iterable<Record<string, unknown>> {
66
+ readonly records: Record<string, unknown>[];
67
+ readonly columns: string[];
68
+
69
+ constructor(
70
+ records: Record<string, unknown>[] | null | undefined = null,
71
+ columns: string[] | null | undefined = null,
72
+ ) {
73
+ this.records = [...(records ?? [])];
74
+ this.columns = [...(columns ?? [])];
75
+ }
76
+
77
+ toArray(): Record<string, unknown>[] {
78
+ return this.records;
79
+ }
80
+
81
+ /** The first value of the first record, or null. */
82
+ scalar(): unknown {
83
+ if (this.records.length === 0) return null;
84
+ const values = Object.values(this.records[0]);
85
+ return values.length ? values[0] : null;
86
+ }
87
+
88
+ [Symbol.iterator](): Iterator<Record<string, unknown>> {
89
+ return this.records[Symbol.iterator]();
90
+ }
91
+
92
+ get length(): number {
93
+ return this.records.length;
94
+ }
95
+ }
@@ -1,115 +1,137 @@
1
- export type {
2
- FieldType,
3
- FieldDefinition,
4
- ModelDefinition,
5
- DatabaseAdapter,
6
- DatabaseResult as DatabaseWriteResult,
7
- ColumnInfo,
8
- QueryOptions,
9
- RelationshipDefinition,
10
- } from "./types.js";
11
-
12
- export { REQUIRED_ADAPTER_CAPABILITIES, NOT_REQUIRED_ON_ADAPTER } from "./types.js";
13
-
14
- export { DatabaseResult } from "./databaseResult.js";
15
- export type { ColumnInfoResult } from "./databaseResult.js";
16
- export { Database, initDatabase, getAdapter, setAdapter, bindDatabase, createAdapterFromUrl, closeDatabase, parseDatabaseUrl, setNamedAdapter, getNamedAdapter, resolveDbPool, stripTrailingSemicolons, wrapWithCache, resetRequestCaches } from "./database.js";
17
- export {
18
- adapterFetch, adapterQuery, adapterFetchOne, adapterExecute, adapterInsert,
19
- adapterStartTransaction, adapterCommit, adapterRollback,
20
- adapterTableExists, adapterTables, adapterColumns, adapterCreateTable,
21
- extractLastInsertId,
22
- } from "./database.js";
23
- export type { DatabaseConfig } from "./database.js";
24
- export { DatabaseUrl, redactCredentials } from "./databaseUrl.js";
25
- export type { DatabaseEngine } from "./databaseUrl.js";
26
- export { discoverModels } from "./model.js";
27
- export type { DiscoveredModel } from "./model.js";
28
- export {
29
- syncModels,
30
- ensureMigrationTable,
31
- getNextBatch,
32
- isMigrationApplied,
33
- recordMigration,
34
- applyMigration,
35
- rollback,
36
- getAppliedMigrations,
37
- getLastBatchMigrations,
38
- removeMigrationRecord,
39
- migrate,
40
- createMigration,
41
- status,
42
- Migration,
43
- splitStatements,
44
- parseSetTerm,
45
- normalizeQuotes,
46
- sortMigrationFiles,
47
- shouldSkipCreateTable,
48
- shouldSkipForFirebird,
49
- } from "./migration.js";
50
- export type { MigrationResult, MigrationStatus } from "./migration.js";
51
- export { AutoCrud, generateCrudRoutes, crudEligibleModels } from "./autoCrud.js";
52
- export type { AutoCrudOptions } from "./autoCrud.js";
53
- export { buildQuery, parseQueryString } from "./query.js";
54
- export { validate } from "./validation.js";
55
- export type { ValidationError } from "./validation.js";
56
- export { BaseModel, snakeToCamel, camelToSnake } from "./baseModel.js";
57
- export { QueryBuilder } from "./queryBuilder.js";
58
- export { SQLTranslator, QueryCache } from "./sqlTranslator.js";
59
- export { Point, SpatialNotSupportedError, DEFAULT_SRID } from "./point.js";
60
- export type { GeoJsonPoint } from "./point.js";
61
- export {
62
- DEFAULT_DATABASE_CONNECT_TIMEOUT_SECONDS,
63
- CONNECT_TIMEOUT_TOLERANCE_MS,
64
- connectTimeoutMillis,
65
- driverConnectTimeoutMillis,
66
- connectTarget,
67
- withConnectTimeout,
68
- } from "./connectTimeout.js";
69
- export { CachedDatabaseAdapter } from "./cachedDatabase.js";
70
- export type { CachedAdapterOptions } from "./cachedDatabase.js";
71
- export { FakeData } from "./fakeData.js";
72
- export { seedTable, seedOrm, seedModels, autoFieldMap } from "./seeder.js";
73
- export type { SeedSummary, SeedOptions } from "./seeder.js";
74
-
75
- // DocStore — pymongo-style document store with a zero-config SQLite (JSON1) fallback
76
- export {
77
- ObjectId, InvalidId, DocStoreDriverMissing, SqliteDatabase, SqliteCollection, Cursor,
78
- getCollection, isServerless, resetDefaultStore, closeDocStore,
79
- encodeValue, decodeValue, compileFilter,
80
- } from "./docstore.js";
81
- export type {
82
- InsertOneResult, InsertManyResult, UpdateResult, DeleteResult,
83
- } from "./docstore.js";
84
-
85
- // Database adapters
86
- export { SQLiteAdapter } from "./adapters/sqlite.js";
87
- export { PostgresAdapter } from "./adapters/postgres.js";
88
- export type { PostgresConfig } from "./adapters/postgres.js";
89
- export { MysqlAdapter } from "./adapters/mysql.js";
90
- export type { MysqlConfig } from "./adapters/mysql.js";
91
- export { MssqlAdapter } from "./adapters/mssql.js";
92
- export type { MssqlConfig } from "./adapters/mssql.js";
93
- export { FirebirdAdapter, normalizeFirebirdDbIdentifier, resolveFirebirdCharset } from "./adapters/firebird.js";
94
- export type { FirebirdConfig } from "./adapters/firebird.js";
95
- export { MongodbAdapter } from "./adapters/mongodb.js";
96
- export type { MongoConfig } from "./adapters/mongodb.js";
97
- export { OdbcAdapter } from "./adapters/odbc.js";
98
- export type { OdbcConfig } from "./adapters/odbc.js";
99
-
100
- // Realtime collaboration mount (calls + chat + files) — parity with the Python master.
101
- export {
102
- realtime,
103
- iceServers,
104
- type RealtimeOptions,
105
- LocalStorage,
106
- S3Storage,
107
- selectStorage,
108
- storageKey,
109
- type StorageBackend,
110
- Workspace as RealtimeWorkspace,
111
- Channel as RealtimeChannel,
112
- ChannelMember as RealtimeChannelMember,
113
- Message as RealtimeMessage,
114
- Attachment as RealtimeAttachment,
115
- } from "./realtime/index.js";
1
+ export type {
2
+ FieldType,
3
+ FieldDefinition,
4
+ ModelDefinition,
5
+ DatabaseAdapter,
6
+ DatabaseResult as DatabaseWriteResult,
7
+ ColumnInfo,
8
+ QueryOptions,
9
+ RelationshipDefinition,
10
+ } from "./types.js";
11
+
12
+ export { REQUIRED_ADAPTER_CAPABILITIES, NOT_REQUIRED_ON_ADAPTER } from "./types.js";
13
+
14
+ export { DatabaseResult } from "./databaseResult.js";
15
+ export type { ColumnInfoResult } from "./databaseResult.js";
16
+ export { Database, initDatabase, getAdapter, setAdapter, bindDatabase, createAdapterFromUrl, closeDatabase, parseDatabaseUrl, setNamedAdapter, getNamedAdapter, resolveDbPool, stripTrailingSemicolons, wrapWithCache, resetRequestCaches } from "./database.js";
17
+ export {
18
+ adapterFetch, adapterQuery, adapterFetchOne, adapterExecute, adapterInsert,
19
+ adapterStartTransaction, adapterCommit, adapterRollback,
20
+ adapterTableExists, adapterTables, adapterColumns, adapterCreateTable,
21
+ extractLastInsertId,
22
+ } from "./database.js";
23
+ export type { DatabaseConfig } from "./database.js";
24
+ export { DatabaseUrl, redactCredentials } from "./databaseUrl.js";
25
+ export type { DatabaseEngine } from "./databaseUrl.js";
26
+ export { discoverModels } from "./model.js";
27
+ export type { DiscoveredModel } from "./model.js";
28
+ export {
29
+ syncModels,
30
+ ensureMigrationTable,
31
+ getNextBatch,
32
+ isMigrationApplied,
33
+ recordMigration,
34
+ applyMigration,
35
+ rollback,
36
+ getAppliedMigrations,
37
+ getLastBatchMigrations,
38
+ removeMigrationRecord,
39
+ migrate,
40
+ createMigration,
41
+ status,
42
+ Migration,
43
+ splitStatements,
44
+ parseSetTerm,
45
+ normalizeQuotes,
46
+ sortMigrationFiles,
47
+ shouldSkipCreateTable,
48
+ shouldSkipForFirebird,
49
+ } from "./migration.js";
50
+ export type { MigrationResult, MigrationStatus } from "./migration.js";
51
+ export { AutoCrud, generateCrudRoutes, crudEligibleModels } from "./autoCrud.js";
52
+ export type { AutoCrudOptions } from "./autoCrud.js";
53
+ export { buildQuery, parseQueryString } from "./query.js";
54
+ export { validate } from "./validation.js";
55
+ export type { ValidationError } from "./validation.js";
56
+ export { BaseModel, snakeToCamel, camelToSnake } from "./baseModel.js";
57
+ export { QueryBuilder } from "./queryBuilder.js";
58
+ export { SQLTranslator, QueryCache } from "./sqlTranslator.js";
59
+ export { Point, SpatialNotSupportedError, DEFAULT_SRID } from "./point.js";
60
+ export type { GeoJsonPoint } from "./point.js";
61
+ export {
62
+ DEFAULT_DATABASE_CONNECT_TIMEOUT_SECONDS,
63
+ CONNECT_TIMEOUT_TOLERANCE_MS,
64
+ connectTimeoutMillis,
65
+ driverConnectTimeoutMillis,
66
+ connectTarget,
67
+ withConnectTimeout,
68
+ } from "./connectTimeout.js";
69
+ export { CachedDatabaseAdapter } from "./cachedDatabase.js";
70
+ export type { CachedAdapterOptions } from "./cachedDatabase.js";
71
+ export { FakeData } from "./fakeData.js";
72
+ export { seedTable, seedOrm, seedModels, autoFieldMap } from "./seeder.js";
73
+ export type { SeedSummary, SeedOptions } from "./seeder.js";
74
+
75
+ // DocStore — pymongo-style document store with a zero-config SQLite (JSON1) fallback
76
+ export {
77
+ ObjectId, InvalidId, DocStoreDriverMissing, SqliteDatabase, SqliteCollection, Cursor,
78
+ getCollection, isServerless, resetDefaultStore, closeDocStore,
79
+ encodeValue, decodeValue, compileFilter,
80
+ } from "./docstore.js";
81
+ export type {
82
+ InsertOneResult, InsertManyResult, UpdateResult, DeleteResult,
83
+ } from "./docstore.js";
84
+
85
+ // Database adapters
86
+ export { SQLiteAdapter } from "./adapters/sqlite.js";
87
+ export { PostgresAdapter } from "./adapters/postgres.js";
88
+ export type { PostgresConfig } from "./adapters/postgres.js";
89
+ export { MysqlAdapter } from "./adapters/mysql.js";
90
+ export type { MysqlConfig } from "./adapters/mysql.js";
91
+ export { MssqlAdapter } from "./adapters/mssql.js";
92
+ export type { MssqlConfig } from "./adapters/mssql.js";
93
+ export { FirebirdAdapter, normalizeFirebirdDbIdentifier, resolveFirebirdCharset } from "./adapters/firebird.js";
94
+ export type { FirebirdConfig } from "./adapters/firebird.js";
95
+ export { MongodbAdapter } from "./adapters/mongodb.js";
96
+ export type { MongoConfig } from "./adapters/mongodb.js";
97
+ export { OdbcAdapter } from "./adapters/odbc.js";
98
+ export type { OdbcConfig } from "./adapters/odbc.js";
99
+
100
+ // Graph data layer (Feature 139) — URL-selected graph databases, shaped like Database.
101
+ // The engine adapters (e.g. UltipaGraphAdapter) are deliberately NOT re-exported:
102
+ // they import their optional driver, so the factory loads them lazily and the core
103
+ // surface below stays driver-free (the zero-dependency-core rule, ADR-0059).
104
+ export { GraphDatabase } from "./graph/graphDatabase.js";
105
+ export type { GraphCredentials } from "./graph/graphDatabase.js";
106
+ export { GraphUrl } from "./graph/graphUrl.js";
107
+ export type { GraphEngine } from "./graph/graphUrl.js";
108
+ export { GraphNode, GraphEdge, GraphResult } from "./graph/shapes.js";
109
+ export { GraphError, GraphConnectTimeout } from "./graph/errors.js";
110
+ export type {
111
+ GraphAdapter,
112
+ GraphDirection,
113
+ NeighborOptions,
114
+ TraverseOptions,
115
+ } from "./graph/graphAdapter.js";
116
+ export {
117
+ resolveGraphConnectTimeout,
118
+ GRAPH_CONNECT_TIMEOUT_VARIABLE,
119
+ DEFAULT_GRAPH_CONNECT_TIMEOUT_SECONDS,
120
+ } from "./graph/connectTimeout.js";
121
+
122
+ // Realtime collaboration mount (calls + chat + files) — parity with the Python master.
123
+ export {
124
+ realtime,
125
+ iceServers,
126
+ type RealtimeOptions,
127
+ LocalStorage,
128
+ S3Storage,
129
+ selectStorage,
130
+ storageKey,
131
+ type StorageBackend,
132
+ Workspace as RealtimeWorkspace,
133
+ Channel as RealtimeChannel,
134
+ ChannelMember as RealtimeChannelMember,
135
+ Message as RealtimeMessage,
136
+ Attachment as RealtimeAttachment,
137
+ } from "./realtime/index.js";
@@ -0,0 +1,42 @@
1
+ /**
2
+ * ArangoDB graph adapter — the document/AQL engine behind the same surface.
3
+ *
4
+ * Wraps the community `arangojs` npm package (an OPTIONAL dependency — imported at
5
+ * the top of THIS module only, so `import "@tina4/orm"` stays driver-free; the
6
+ * GraphDatabase factory dynamically imports this module and turns a missing driver
7
+ * into the actionable install error). Arango is a document store, not a labelled-
8
+ * property graph, so the portable core maps onto ONE vertex collection + ONE edge
9
+ * collection: a node's `labels` and an edge's `type` are stored as document fields,
10
+ * ids are Arango `_id` handles (e.g. `tina4_nodes/123`), and traversal uses AQL
11
+ * `FOR v IN 1..N OUTBOUND ...`. Raw query()/execute() take AQL directly.
12
+ *
13
+ * The two collections are ensured lazily on the first query (the driver's
14
+ * constructor is synchronous and opens no connection), mirroring the Ultipa
15
+ * adapter's lazy connect.
16
+ */
17
+ import { GraphNode, GraphEdge, GraphResult } from "../shapes.js";
18
+ import type { GraphUrl } from "../graphUrl.js";
19
+ import type { GraphCredentials } from "../graphDatabase.js";
20
+ import type { GraphAdapter, NeighborOptions, TraverseOptions } from "../graphAdapter.js";
21
+ export declare class ArangoGraphAdapter implements GraphAdapter {
22
+ private readonly url;
23
+ private readonly db;
24
+ private ensured;
25
+ private lastError;
26
+ constructor(graphUrl: GraphUrl, credentials?: GraphCredentials);
27
+ private connectOrError;
28
+ private ensureCollections;
29
+ private aql;
30
+ query(text: string, params?: Record<string, unknown> | null): Promise<GraphResult>;
31
+ execute(text: string, params?: Record<string, unknown> | null): Promise<GraphResult>;
32
+ private nodeFromDoc;
33
+ addNode(label: string, properties?: Record<string, unknown> | null): Promise<GraphNode | null>;
34
+ addEdge(fromId: string, toId: string, type: string, properties?: Record<string, unknown> | null): Promise<GraphEdge | null>;
35
+ getNode(nodeId: string): Promise<GraphNode | null>;
36
+ updateNode(nodeId: string, properties: Record<string, unknown>): Promise<GraphNode | null>;
37
+ deleteNode(nodeId: string): Promise<boolean>;
38
+ neighbors(nodeId: string, options?: NeighborOptions): Promise<GraphNode[]>;
39
+ traverse(startId: string, options?: TraverseOptions): Promise<GraphNode[]>;
40
+ close(): Promise<void>;
41
+ getError(): string | null;
42
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Bolt graph adapter — Neo4j AND Memgraph (both speak Bolt + Cypher).
3
+ *
4
+ * Wraps the community `neo4j-driver` npm package (an OPTIONAL dependency — imported
5
+ * at the top of THIS module only, so `import "@tina4/orm"` stays driver-free; the
6
+ * GraphDatabase factory dynamically imports this module and turns a missing driver
7
+ * into the actionable install error). Neo4j and Memgraph share this ONE adapter;
8
+ * the URL scheme only picks the engine label and the default port.
9
+ *
10
+ * Cypher note (verified against live Neo4j + Memgraph on the lab, no mocks):
11
+ * `id(n)` is the portable node/edge id (an INTEGER on both — Neo4j's `elementId`
12
+ * is Neo4j-only, Memgraph has none); variable-length traversal is Cypher's
13
+ * `[*1..N]` (the OPPOSITE of Ultipa's GQL `{1,N}`); `SET n += $props` merges.
14
+ *
15
+ * The driver is configured with `disableLosslessIntegers: true`, so `id(n)` and
16
+ * integer properties come back as native JS numbers instead of the driver's
17
+ * `Integer` wrapper. Node ids are engine integers; the neutral GraphNode carries
18
+ * them as strings, so a Cypher `WHERE id(n) = $id` is fed `Number(id)` back.
19
+ */
20
+ import { GraphNode, GraphEdge, GraphResult } from "../shapes.js";
21
+ import type { GraphUrl } from "../graphUrl.js";
22
+ import type { GraphCredentials } from "../graphDatabase.js";
23
+ import type { GraphAdapter, NeighborOptions, TraverseOptions } from "../graphAdapter.js";
24
+ export declare class BoltGraphAdapter implements GraphAdapter {
25
+ private readonly url;
26
+ private readonly database;
27
+ private readonly driver;
28
+ private lastError;
29
+ constructor(graphUrl: GraphUrl, credentials?: GraphCredentials);
30
+ private run;
31
+ query(text: string, params?: Record<string, unknown> | null): Promise<GraphResult>;
32
+ execute(text: string, params?: Record<string, unknown> | null): Promise<GraphResult>;
33
+ private nodeFromRow;
34
+ addNode(label: string, properties?: Record<string, unknown> | null): Promise<GraphNode | null>;
35
+ addEdge(fromId: string, toId: string, type: string, properties?: Record<string, unknown> | null): Promise<GraphEdge | null>;
36
+ getNode(nodeId: string): Promise<GraphNode | null>;
37
+ updateNode(nodeId: string, properties: Record<string, unknown>): Promise<GraphNode | null>;
38
+ deleteNode(nodeId: string): Promise<boolean>;
39
+ neighbors(nodeId: string, options?: NeighborOptions): Promise<GraphNode[]>;
40
+ traverse(startId: string, options?: TraverseOptions): Promise<GraphNode[]>;
41
+ close(): Promise<void>;
42
+ getError(): string | null;
43
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Ultipa graph adapter — the portable core built in GQL over the tina4-ultipa driver.
3
+ *
4
+ * Wraps the standalone `tina4-ultipa` driver (an OPTIONAL dependency — imported at
5
+ * the top of THIS module only, so `import "@tina4/orm"` stays driver-free; the
6
+ * GraphDatabase factory dynamically imports this module and turns a missing driver
7
+ * into the actionable install error). The portable node/edge/traverse surface is
8
+ * expressed in Ultipa GQL on top of the driver's query()/execute(); raw
9
+ * query()/execute() send GQL straight through.
10
+ *
11
+ * GQL note: the exact statements are verified against the live Ultipa community
12
+ * edition on the lab (no mocks). Ultipa node ids are the engine's own UUID strings;
13
+ * we echo back whatever id(n)/id(e) returns without assuming a type. Reads go via
14
+ * query() (readOnly=true); writes via execute() (readOnly=false) — a write through
15
+ * query() is rejected by Ultipa.
16
+ */
17
+ import { GraphNode, GraphEdge, GraphResult } from "../shapes.js";
18
+ import type { GraphUrl } from "../graphUrl.js";
19
+ import type { GraphCredentials } from "../graphDatabase.js";
20
+ import type { GraphAdapter, NeighborOptions, TraverseOptions } from "../graphAdapter.js";
21
+ export declare class UltipaGraphAdapter implements GraphAdapter {
22
+ private readonly url;
23
+ private readonly client;
24
+ private lastError;
25
+ constructor(graphUrl: GraphUrl, credentials?: GraphCredentials);
26
+ private run;
27
+ query(text: string, params?: Record<string, unknown> | null): Promise<GraphResult>;
28
+ execute(text: string, params?: Record<string, unknown> | null): Promise<GraphResult>;
29
+ private nodeFromRow;
30
+ addNode(label: string, properties?: Record<string, unknown> | null): Promise<GraphNode | null>;
31
+ addEdge(fromId: string, toId: string, type: string, properties?: Record<string, unknown> | null): Promise<GraphEdge | null>;
32
+ getNode(nodeId: string): Promise<GraphNode | null>;
33
+ updateNode(nodeId: string, properties: Record<string, unknown>): Promise<GraphNode | null>;
34
+ deleteNode(nodeId: string): Promise<boolean>;
35
+ neighbors(nodeId: string, options?: NeighborOptions): Promise<GraphNode[]>;
36
+ traverse(startId: string, options?: TraverseOptions): Promise<GraphNode[]>;
37
+ close(): void;
38
+ getError(): string | null;
39
+ }
@@ -0,0 +1,12 @@
1
+ /** The env var name — one spelling, so grepping finds every reader. */
2
+ export declare const GRAPH_CONNECT_TIMEOUT_VARIABLE = "TINA4_GRAPH_CONNECT_TIMEOUT";
3
+ /** Seconds. Long enough for a cold connect, short enough to page. */
4
+ export declare const DEFAULT_GRAPH_CONNECT_TIMEOUT_SECONDS = 10;
5
+ /**
6
+ * Seconds a graph connect may block, or `null` when the bound is disabled (<= 0).
7
+ *
8
+ * Mirrors resolveConnectTimeout: a value <= 0 disables the bound, a non-number
9
+ * warns and uses the default. Seconds is the operator-facing unit (the Ultipa
10
+ * driver takes seconds), so no ms conversion happens here.
11
+ */
12
+ export declare function resolveGraphConnectTimeout(): number | null;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Graph layer errors — the graph siblings of the relational fail-loud contract.
3
+ *
4
+ * A bad graph statement RAISES (never a falsy return); the cause is readable via
5
+ * the adapter's getError() after the throw. An unreachable host throws
6
+ * GraphConnectTimeout within TINA4_GRAPH_CONNECT_TIMEOUT, naming host and port.
7
+ */
8
+ /** A graph operation failed (bad statement, engine error). */
9
+ export declare class GraphError extends Error {
10
+ constructor(message: string, cause?: unknown);
11
+ }
12
+ /**
13
+ * A graph connect exceeded TINA4_GRAPH_CONNECT_TIMEOUT.
14
+ *
15
+ * The message names the host, the port and the elapsed seconds — the mirror of
16
+ * the relational DatabaseConnectTimeout, so an operator can tell "my bound
17
+ * fired" apart from "the engine rejected me".
18
+ */
19
+ export declare class GraphConnectTimeout extends GraphError {
20
+ constructor(message: string, cause?: unknown);
21
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The one surface every graph engine implements.
3
+ *
4
+ * The portable node/edge/traverse core PLUS a raw query()/execute() pass-through
5
+ * in the engine's native dialect, and lifecycle. Every method is async — the
6
+ * Node graph drivers are async (gRPC/Bolt/HTTP), so the surface is async
7
+ * everywhere, matching the relational Database wrapper. See ADR-0059.
8
+ */
9
+ import type { GraphNode, GraphEdge, GraphResult } from "./shapes.js";
10
+ /** Direction of an edge relative to the anchor node. */
11
+ export type GraphDirection = "out" | "in" | "both";
12
+ /** Options for the one-hop neighbours read. */
13
+ export interface NeighborOptions {
14
+ direction?: GraphDirection;
15
+ edgeType?: string;
16
+ limit?: number;
17
+ }
18
+ /** Options for the bounded multi-hop traversal. */
19
+ export interface TraverseOptions {
20
+ depth?: number;
21
+ direction?: GraphDirection;
22
+ edgeType?: string;
23
+ limit?: number;
24
+ }
25
+ export interface GraphAdapter {
26
+ addNode(label: string, properties?: Record<string, unknown> | null): Promise<GraphNode | null>;
27
+ addEdge(fromId: string, toId: string, type: string, properties?: Record<string, unknown> | null): Promise<GraphEdge | null>;
28
+ getNode(nodeId: string): Promise<GraphNode | null>;
29
+ updateNode(nodeId: string, properties: Record<string, unknown>): Promise<GraphNode | null>;
30
+ deleteNode(nodeId: string): Promise<boolean>;
31
+ neighbors(nodeId: string, options?: NeighborOptions): Promise<GraphNode[]>;
32
+ traverse(startId: string, options?: TraverseOptions): Promise<GraphNode[]>;
33
+ query(text: string, params?: Record<string, unknown> | null): Promise<GraphResult>;
34
+ execute(text: string, params?: Record<string, unknown> | null): Promise<GraphResult>;
35
+ close(): Promise<void> | void;
36
+ /** Cause of the last failed operation, or null. */
37
+ getError(): string | null;
38
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The GraphAdapter URL-selected factory — the GraphDatabase sibling of Database.
3
+ *
4
+ * GraphDatabase.create picks an adapter by URL scheme and imports its driver
5
+ * lazily (dynamic import): a missing driver raises an actionable install error,
6
+ * never a bare module-not-found, and the graph CORE imports with no driver
7
+ * present (the zero-dependency-core rule). The barrel deliberately does NOT
8
+ * re-export any engine adapter, so importing @tina4/orm pulls in no graph driver.
9
+ */
10
+ import { type GraphEngine } from "./graphUrl.js";
11
+ import type { GraphAdapter } from "./graphAdapter.js";
12
+ /** Credentials passed alongside the URL when it carries none. */
13
+ export interface GraphCredentials {
14
+ username?: string;
15
+ password?: string;
16
+ }
17
+ export interface AdapterRegistration {
18
+ /** Dynamic import of the adapter module — the ONLY place a driver is pulled. */
19
+ load: () => Promise<Record<string, unknown>>;
20
+ className: string;
21
+ /** npm package that provides the engine driver. */
22
+ package: string;
23
+ /** The command that installs it. */
24
+ installCommand: string;
25
+ }
26
+ /**
27
+ * engine -> adapter registration. Selected lazily so importing this module pulls
28
+ * in NO engine driver. bolt (Neo4j/Memgraph) and arango land later — declared so
29
+ * the factory gives an actionable message rather than a bare KeyError.
30
+ */
31
+ export declare const ENGINE_ADAPTERS: Partial<Record<GraphEngine, AdapterRegistration>>;
32
+ export declare class GraphDatabase {
33
+ /**
34
+ * Parse the URL, pick the engine adapter, connect lazily.
35
+ *
36
+ * The engine driver is imported only here (first use of that engine); if it is
37
+ * absent the error names the package and the install command. Async because the
38
+ * driver import is dynamic — the connect itself still happens lazily on first
39
+ * operation (mirroring the relational adapters).
40
+ */
41
+ static create(url: string, credentials?: GraphCredentials): Promise<GraphAdapter>;
42
+ /** Build from TINA4_GRAPH_URL (+ TINA4_GRAPH_USERNAME/_PASSWORD). */
43
+ static fromEnv(envKey?: string): Promise<GraphAdapter | null>;
44
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Graph connection URL parser — the DatabaseUrl sibling for graph engines.
3
+ *
4
+ * Parse a graph connection URL into its parts, the same way DatabaseUrl does for
5
+ * SQL. `engine` is the CANONICAL name the factory selects an adapter by; a scheme
6
+ * alias (bolt/neo4j/memgraph all speak Bolt/Cypher and share ONE adapter) resolves
7
+ * to its engine here. See tina4-documentation/plan/v3/features/139-graph-databases.md.
8
+ */
9
+ /** The canonical graph engine names. */
10
+ export type GraphEngine = "ultipa" | "bolt" | "arango";
11
+ /** A parsed graph URL: engine, host, port, graph, credentials, params. */
12
+ export declare class GraphUrl {
13
+ readonly raw: string;
14
+ readonly scheme: string;
15
+ readonly engine: GraphEngine;
16
+ readonly host: string;
17
+ readonly port: number;
18
+ /** The graph/database name (leading slash stripped), or null when absent. */
19
+ readonly graph: string | null;
20
+ readonly username: string | null;
21
+ readonly password: string | null;
22
+ readonly params: Record<string, string>;
23
+ readonly useTls: boolean;
24
+ constructor(url: string);
25
+ /** host:port/graph — for messages, never carrying credentials. */
26
+ getDsn(): string;
27
+ static fromEnv(envKey?: string): GraphUrl | null;
28
+ }