@utaba/deep-memory-storage-cosmosdb 0.5.1 → 0.6.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/dist/index.cjs +76 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -1
- package/dist/index.d.ts +32 -1
- package/dist/index.js +77 -8
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1319,6 +1319,23 @@ var CosmosDbProvider = class {
|
|
|
1319
1319
|
rejectUnauthorized: config.rejectUnauthorized
|
|
1320
1320
|
});
|
|
1321
1321
|
}
|
|
1322
|
+
/**
|
|
1323
|
+
* Reject any repositoryId that is not a valid v4 UUID.
|
|
1324
|
+
*
|
|
1325
|
+
* Every partition-scoped query filters on repositoryId. Since repositoryId is
|
|
1326
|
+
* the CosmosDB partition key, a predicate with a different value would target
|
|
1327
|
+
* a different partition. Strict format validation at the provider boundary
|
|
1328
|
+
* prevents injection (e.g. strings containing quotes or Gremlin syntax) from
|
|
1329
|
+
* ever reaching query construction.
|
|
1330
|
+
*/
|
|
1331
|
+
assertValidRepositoryId(repositoryId) {
|
|
1332
|
+
if (!(0, import_deep_memory5.isValidUuid)(repositoryId)) {
|
|
1333
|
+
throw new import_deep_memory5.InvalidInputError(
|
|
1334
|
+
"repositoryId",
|
|
1335
|
+
`repositoryId must be a valid v4 UUID; got '${repositoryId}'`
|
|
1336
|
+
);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1322
1339
|
// ─── Lifecycle ─────────────────────────────────────────────────────
|
|
1323
1340
|
async initialize() {
|
|
1324
1341
|
await this.conn.connect();
|
|
@@ -1404,93 +1421,120 @@ var CosmosDbProvider = class {
|
|
|
1404
1421
|
}
|
|
1405
1422
|
// ─── Repository ────────────────────────────────────────────────────
|
|
1406
1423
|
async createRepository(config) {
|
|
1424
|
+
this.assertValidRepositoryId(config.repositoryId);
|
|
1407
1425
|
return createRepository(this.conn, config);
|
|
1408
1426
|
}
|
|
1409
1427
|
async getRepository(repositoryId) {
|
|
1428
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1410
1429
|
return getRepository(this.conn, repositoryId);
|
|
1411
1430
|
}
|
|
1412
1431
|
async listRepositories(filter) {
|
|
1413
1432
|
return listRepositories(this.conn, filter);
|
|
1414
1433
|
}
|
|
1415
1434
|
async updateRepository(repositoryId, updates) {
|
|
1435
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1416
1436
|
return updateRepository(this.conn, repositoryId, updates);
|
|
1417
1437
|
}
|
|
1418
1438
|
async deleteRepository(repositoryId, onProgress) {
|
|
1439
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1419
1440
|
return deleteRepository(this.conn, repositoryId, onProgress);
|
|
1420
1441
|
}
|
|
1421
1442
|
async deleteAllContents(repositoryId, onProgress) {
|
|
1443
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1422
1444
|
return deleteAllContents(this.conn, repositoryId, onProgress);
|
|
1423
1445
|
}
|
|
1424
1446
|
async getRepositoryStats(repositoryId) {
|
|
1447
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1425
1448
|
return getRepositoryStats(this.conn, repositoryId);
|
|
1426
1449
|
}
|
|
1427
1450
|
// ─── Vocabulary ────────────────────────────────────────────────────
|
|
1428
1451
|
async getVocabulary(repositoryId) {
|
|
1452
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1429
1453
|
return getVocabulary(this.conn, repositoryId);
|
|
1430
1454
|
}
|
|
1431
1455
|
async saveVocabulary(repositoryId, vocabulary) {
|
|
1456
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1432
1457
|
return saveVocabulary(this.conn, repositoryId, vocabulary);
|
|
1433
1458
|
}
|
|
1434
1459
|
async getVocabularyChangeLog(repositoryId, options) {
|
|
1460
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1435
1461
|
return getVocabularyChangeLog(this.conn, repositoryId, options);
|
|
1436
1462
|
}
|
|
1437
1463
|
// ─── Entities ──────────────────────────────────────────────────────
|
|
1438
1464
|
async createEntity(repositoryId, entity) {
|
|
1465
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1439
1466
|
return createEntity(this.conn, repositoryId, entity);
|
|
1440
1467
|
}
|
|
1441
1468
|
async getEntity(repositoryId, entityId) {
|
|
1469
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1442
1470
|
return getEntity(this.conn, repositoryId, entityId);
|
|
1443
1471
|
}
|
|
1444
1472
|
async getEntityBySlug(repositoryId, slug) {
|
|
1473
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1445
1474
|
return getEntityBySlug(this.conn, repositoryId, slug);
|
|
1446
1475
|
}
|
|
1447
1476
|
async getEntities(repositoryId, entityIds) {
|
|
1477
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1448
1478
|
return getEntities(this.conn, repositoryId, entityIds);
|
|
1449
1479
|
}
|
|
1450
1480
|
async updateEntity(repositoryId, entityId, updates) {
|
|
1481
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1451
1482
|
return updateEntity(this.conn, repositoryId, entityId, updates);
|
|
1452
1483
|
}
|
|
1453
1484
|
async deleteEntity(repositoryId, entityId) {
|
|
1485
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1454
1486
|
return deleteEntity(this.conn, repositoryId, entityId);
|
|
1455
1487
|
}
|
|
1456
1488
|
async deleteEntitiesByType(repositoryId, entityType) {
|
|
1489
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1457
1490
|
return deleteEntitiesByType(this.conn, repositoryId, entityType);
|
|
1458
1491
|
}
|
|
1459
1492
|
async findEntities(repositoryId, query) {
|
|
1493
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1460
1494
|
return findEntities(this.conn, repositoryId, query);
|
|
1461
1495
|
}
|
|
1462
1496
|
// ─── Relationships ─────────────────────────────────────────────────
|
|
1463
1497
|
async createRelationship(repositoryId, relationship) {
|
|
1498
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1464
1499
|
return createRelationship(this.conn, repositoryId, relationship);
|
|
1465
1500
|
}
|
|
1466
1501
|
async getRelationship(repositoryId, relationshipId) {
|
|
1502
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1467
1503
|
return getRelationship(this.conn, repositoryId, relationshipId);
|
|
1468
1504
|
}
|
|
1469
1505
|
async getEntityRelationships(repositoryId, entityId, options) {
|
|
1506
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1470
1507
|
return getEntityRelationships(this.conn, repositoryId, entityId, options);
|
|
1471
1508
|
}
|
|
1472
1509
|
async deleteRelationship(repositoryId, relationshipId) {
|
|
1510
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1473
1511
|
return deleteRelationship(this.conn, repositoryId, relationshipId);
|
|
1474
1512
|
}
|
|
1475
1513
|
async deleteRelationshipsByType(repositoryId, relationshipType) {
|
|
1514
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1476
1515
|
return deleteRelationshipsByType(this.conn, repositoryId, relationshipType);
|
|
1477
1516
|
}
|
|
1478
1517
|
// ─── Graph Traversal (StorageProvider) ─────────────────────────────
|
|
1479
1518
|
async exploreNeighborhood(repositoryId, entityId, options) {
|
|
1519
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1480
1520
|
return exploreNeighborhood(this.conn, repositoryId, entityId, options);
|
|
1481
1521
|
}
|
|
1482
1522
|
async findPaths(repositoryId, sourceId, targetId, options) {
|
|
1523
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1483
1524
|
return findPaths(this.conn, repositoryId, sourceId, targetId, options);
|
|
1484
1525
|
}
|
|
1485
1526
|
// ─── Timeline ──────────────────────────────────────────────────────
|
|
1486
1527
|
async getTimeline(repositoryId, entityId, options) {
|
|
1528
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1487
1529
|
return getTimeline(this.conn, repositoryId, entityId, options);
|
|
1488
1530
|
}
|
|
1489
1531
|
// ─── Bulk Operations ───────────────────────────────────────────────
|
|
1490
1532
|
exportAll(repositoryId) {
|
|
1533
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1491
1534
|
return exportAll(this.conn, repositoryId);
|
|
1492
1535
|
}
|
|
1493
1536
|
async importBulk(repositoryId, data, options) {
|
|
1537
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1494
1538
|
return importBulk(this.conn, repositoryId, data, options);
|
|
1495
1539
|
}
|
|
1496
1540
|
// ─── GraphTraversalProvider ────────────────────────────────────────
|
|
@@ -1507,17 +1551,20 @@ var CosmosDbProvider = class {
|
|
|
1507
1551
|
supportsRelationshipSummary: false
|
|
1508
1552
|
};
|
|
1509
1553
|
}
|
|
1510
|
-
async traverse(repositoryId, spec
|
|
1554
|
+
async traverse(repositoryId, spec) {
|
|
1555
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1511
1556
|
const startTime = Date.now();
|
|
1512
1557
|
const vocabulary = await this.getVocabulary(repositoryId);
|
|
1513
|
-
const compiled =
|
|
1558
|
+
const compiled = this.compiler.compile(spec, vocabulary);
|
|
1514
1559
|
const scopedQuery = compiled.query.replace(
|
|
1515
1560
|
"g.V()",
|
|
1516
|
-
|
|
1561
|
+
"g.V().has('repositoryId', pRid)"
|
|
1517
1562
|
);
|
|
1563
|
+
const scopedParams = { ...compiled.params, pRid: repositoryId };
|
|
1518
1564
|
try {
|
|
1519
|
-
const result = await this.conn.submit(scopedQuery,
|
|
1565
|
+
const result = await this.conn.submit(scopedQuery, scopedParams);
|
|
1520
1566
|
const executionTimeMs = Date.now() - startTime;
|
|
1567
|
+
const detailLevel = spec.detailLevel ?? "summary";
|
|
1521
1568
|
const entities = [];
|
|
1522
1569
|
const relationships = [];
|
|
1523
1570
|
const paths = [];
|
|
@@ -1529,7 +1576,8 @@ var CosmosDbProvider = class {
|
|
|
1529
1576
|
for (const obj of pathData.objects) {
|
|
1530
1577
|
const props = obj;
|
|
1531
1578
|
if (props["entityType"]) {
|
|
1532
|
-
|
|
1579
|
+
const stored = entityFromGremlin(props);
|
|
1580
|
+
pathEntities.push((0, import_deep_memory5.projectEntity)(stored, detailLevel));
|
|
1533
1581
|
}
|
|
1534
1582
|
}
|
|
1535
1583
|
if (pathEntities.length > 0) {
|
|
@@ -1543,8 +1591,8 @@ var CosmosDbProvider = class {
|
|
|
1543
1591
|
}
|
|
1544
1592
|
} else {
|
|
1545
1593
|
for (const item of result.items) {
|
|
1546
|
-
const
|
|
1547
|
-
entities.push(
|
|
1594
|
+
const stored = entityFromGremlin(item);
|
|
1595
|
+
entities.push((0, import_deep_memory5.projectEntity)(stored, detailLevel));
|
|
1548
1596
|
}
|
|
1549
1597
|
}
|
|
1550
1598
|
const limit = spec.limit ?? 50;
|
|
@@ -1576,6 +1624,27 @@ var CosmosDbProvider = class {
|
|
|
1576
1624
|
);
|
|
1577
1625
|
}
|
|
1578
1626
|
}
|
|
1627
|
+
/**
|
|
1628
|
+
* Execute a raw Gremlin query with caller-supplied bindings.
|
|
1629
|
+
*
|
|
1630
|
+
* ⚠️ ELEVATED PRIVILEGE — SYSTEM-LEVEL OPERATION ⚠️
|
|
1631
|
+
*
|
|
1632
|
+
* This method is an unscoped pass-through: it does not filter by repository,
|
|
1633
|
+
* does not inject the partition key, and performs no validation on the query
|
|
1634
|
+
* string. A single call can read or mutate any vertex or edge in the
|
|
1635
|
+
* container regardless of which repository (partition) it belongs to.
|
|
1636
|
+
*
|
|
1637
|
+
* DO NOT expose this method to AI agents, end users, or any untrusted caller.
|
|
1638
|
+
* It is intended for:
|
|
1639
|
+
* - administrative tooling (migrations, diagnostics, repairs)
|
|
1640
|
+
* - internal library operations that need cross-partition reach
|
|
1641
|
+
*
|
|
1642
|
+
* `repositoryId` is accepted for interface symmetry but is intentionally
|
|
1643
|
+
* ignored here — the caller is trusted to scope the query themselves.
|
|
1644
|
+
*
|
|
1645
|
+
* For agent-facing graph queries use {@link traverse}, which enforces the
|
|
1646
|
+
* repositoryId partition predicate.
|
|
1647
|
+
*/
|
|
1579
1648
|
async executeNativeQuery(_repositoryId, query, params) {
|
|
1580
1649
|
const startTime = Date.now();
|
|
1581
1650
|
try {
|