@atscript/moost-db 0.1.133 → 0.1.134
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 +121 -44
- package/dist/index.d.cts +52 -16
- package/dist/index.d.mts +52 -16
- package/dist/index.mjs +121 -44
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1181,6 +1181,13 @@ const OP_VERB = {
|
|
|
1181
1181
|
aggregate: "aggregate over",
|
|
1182
1182
|
bucket: "bucket"
|
|
1183
1183
|
};
|
|
1184
|
+
/** The one "nonexistent path" verdict — hidden paths answer with it byte for byte. */
|
|
1185
|
+
function unknownField(path) {
|
|
1186
|
+
return {
|
|
1187
|
+
path,
|
|
1188
|
+
message: `Unknown field "${path}"`
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1184
1191
|
function leafHint(leaves) {
|
|
1185
1192
|
if (leaves.length === 0) return "no leaf fields";
|
|
1186
1193
|
const shown = leaves.slice(0, 5).join(", ");
|
|
@@ -1380,10 +1387,7 @@ var FieldCapabilityIndex = class FieldCapabilityIndex {
|
|
|
1380
1387
|
* occurrence); it only matters for `op === "filter"` on a listed leaf.
|
|
1381
1388
|
*/
|
|
1382
1389
|
check(path, op, exists, predicate = "compare") {
|
|
1383
|
-
if (!exists(path)) return
|
|
1384
|
-
path,
|
|
1385
|
-
message: `Unknown field "${path}"`
|
|
1386
|
-
};
|
|
1390
|
+
if (!exists(path)) return unknownField(path);
|
|
1387
1391
|
const { kind, parent } = (0, _atscript_db.classifyQueryPath)(this, path);
|
|
1388
1392
|
if (kind === "nav") {
|
|
1389
1393
|
if (parent === void 0) return {
|
|
@@ -1424,12 +1428,16 @@ var FieldCapabilityIndex = class FieldCapabilityIndex {
|
|
|
1424
1428
|
}
|
|
1425
1429
|
}
|
|
1426
1430
|
switch (kind) {
|
|
1427
|
-
case "objectParent":
|
|
1431
|
+
case "objectParent": {
|
|
1428
1432
|
if (op === "select") return void 0;
|
|
1433
|
+
const all = this._objectParents.get(path);
|
|
1434
|
+
const leaves = all.filter(exists);
|
|
1435
|
+
if (leaves.length === 0 && all.length > 0) return unknownField(path);
|
|
1429
1436
|
return {
|
|
1430
1437
|
path,
|
|
1431
|
-
message: `"${path}" is a nested object — filter or sort on one of its leaves (${leafHint(
|
|
1438
|
+
message: `"${path}" is a nested object — filter or sort on one of its leaves (${leafHint(leaves)})`
|
|
1432
1439
|
};
|
|
1440
|
+
}
|
|
1433
1441
|
case "jsonDescendant": return {
|
|
1434
1442
|
path,
|
|
1435
1443
|
message: `"${path}" is inside JSON-stored column "${parent}" — this adapter cannot ${OP_VERB[op]} JSON paths; select "${parent}" and read the value client-side.`
|
|
@@ -1441,10 +1449,7 @@ var FieldCapabilityIndex = class FieldCapabilityIndex {
|
|
|
1441
1449
|
path,
|
|
1442
1450
|
message: `Cannot ${OP_VERB[op]} encrypted field "${path}"`
|
|
1443
1451
|
};
|
|
1444
|
-
default: return
|
|
1445
|
-
path,
|
|
1446
|
-
message: `Unknown field "${path}"`
|
|
1447
|
-
};
|
|
1452
|
+
default: return unknownField(path);
|
|
1448
1453
|
}
|
|
1449
1454
|
}
|
|
1450
1455
|
};
|
|
@@ -1486,6 +1491,7 @@ const GEO_CONTROLS = [
|
|
|
1486
1491
|
];
|
|
1487
1492
|
//#endregion
|
|
1488
1493
|
//#region src/as-db-readable.controller.ts
|
|
1494
|
+
var _AsDbReadableController;
|
|
1489
1495
|
/** Gate positions checked after the filter entries, in order; `refs[op]` are their paths. */
|
|
1490
1496
|
const PATH_OPS = [
|
|
1491
1497
|
"sort",
|
|
@@ -1495,7 +1501,7 @@ const PATH_OPS = [
|
|
|
1495
1501
|
"aggregate",
|
|
1496
1502
|
"bucket"
|
|
1497
1503
|
];
|
|
1498
|
-
let AsDbReadableController = class AsDbReadableController extends AsReadableController {
|
|
1504
|
+
let AsDbReadableController = _AsDbReadableController = class AsDbReadableController extends AsReadableController {
|
|
1499
1505
|
/** Reference to the underlying readable (table or view). */
|
|
1500
1506
|
readable;
|
|
1501
1507
|
/**
|
|
@@ -1535,6 +1541,15 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1535
1541
|
}
|
|
1536
1542
|
/** Bound once: the visibility check ({@link hasField}) the gate hands to `capabilities.check`. */
|
|
1537
1543
|
_exists = (path) => this.hasField(path);
|
|
1544
|
+
/**
|
|
1545
|
+
* Id-resolution options (since 0.1.134): `{ isFieldVisible: hasField }`
|
|
1546
|
+
* when a subclass overrides {@link hasField}, else `undefined` (the default
|
|
1547
|
+
* accepts every real path, so resolution stays unfiltered). A unique index
|
|
1548
|
+
* over a hidden field is never an identification.
|
|
1549
|
+
*/
|
|
1550
|
+
_idOpts;
|
|
1551
|
+
/** Narrowed id sources, one stable object per distinct visible-identification set. */
|
|
1552
|
+
_idSources = /* @__PURE__ */ new Map();
|
|
1538
1553
|
_preferredIdSet;
|
|
1539
1554
|
_overlayIsNoOp;
|
|
1540
1555
|
/** path → sibling-ref path for `@db.amount.currency.ref` / `@db.unit.ref`. */
|
|
@@ -1560,6 +1575,29 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1560
1575
|
this._quantityRefByPath = this._collectQuantityRefs();
|
|
1561
1576
|
const defaultOverlay = AsReadableController.prototype.applyMetaOverlay;
|
|
1562
1577
|
this._overlayIsNoOp = this.applyMetaOverlay === defaultOverlay;
|
|
1578
|
+
this._idOpts = this.hasField === _AsDbReadableController.prototype.hasField ? void 0 : { isFieldVisible: this._exists };
|
|
1579
|
+
}
|
|
1580
|
+
/**
|
|
1581
|
+
* The identifications this request may address rows through (since
|
|
1582
|
+
* 0.1.134): the readable's own, minus unique indexes over fields
|
|
1583
|
+
* {@link hasField} hides. Used by `/one?…`, `DELETE /?…` and action `ids`.
|
|
1584
|
+
* Stable per distinct outcome, so per-source caches keyed on it hit.
|
|
1585
|
+
*/
|
|
1586
|
+
get idSource() {
|
|
1587
|
+
const opts = this._idOpts;
|
|
1588
|
+
if (!opts) return this.readable;
|
|
1589
|
+
const visible = this.readable.identificationsVisibleTo(opts.isFieldVisible);
|
|
1590
|
+
if (visible.length === this.readable.identifications.length) return this.readable;
|
|
1591
|
+
const key = visible.map((ident) => ident.source).join("");
|
|
1592
|
+
let source = this._idSources.get(key);
|
|
1593
|
+
if (!source) {
|
|
1594
|
+
source = {
|
|
1595
|
+
identifications: visible,
|
|
1596
|
+
fieldDescriptors: this.readable.fieldDescriptors
|
|
1597
|
+
};
|
|
1598
|
+
this._idSources.set(key, source);
|
|
1599
|
+
}
|
|
1600
|
+
return source;
|
|
1563
1601
|
}
|
|
1564
1602
|
_collectInvertibleFields() {
|
|
1565
1603
|
const out = [];
|
|
@@ -1594,7 +1632,11 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1594
1632
|
* `$with` relation names and sub-query paths, and the `$search` fallback
|
|
1595
1633
|
* fields. A path it rejects is answered exactly like a nonexistent one
|
|
1596
1634
|
* (`Unknown field "x"` / `Unknown relation "x"`), so override it to hide
|
|
1597
|
-
* fields per request (read scopes).
|
|
1635
|
+
* fields per request (read scopes). Since 0.1.134 it also governs row
|
|
1636
|
+
* identification — a unique index over a hidden field is not an
|
|
1637
|
+
* identification for `/one/:id`, `/one?…`, `DELETE`, a PK-less `PATCH` or
|
|
1638
|
+
* an action id (primary key and `preferredId` always are) — and the
|
|
1639
|
+
* nested-object 400 hint lists visible leaves only. The default accepts every real path
|
|
1598
1640
|
* (`isValidFieldPath`). `/meta` does NOT consult it — prune hidden fields
|
|
1599
1641
|
* there with `applyMetaOverlay`. Native text search and vector search
|
|
1600
1642
|
* (`$vector` names an index) run inside the engine over its indexes, out of
|
|
@@ -1768,11 +1810,26 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1768
1810
|
return widened;
|
|
1769
1811
|
}
|
|
1770
1812
|
const widened = {};
|
|
1771
|
-
for (const path of this.
|
|
1813
|
+
for (const path of this._invertExclusion(excluded)) widened[path] = 1;
|
|
1772
1814
|
for (const field of this._preferredIdSet) widened[field] = 1;
|
|
1773
1815
|
return widened;
|
|
1774
1816
|
}
|
|
1775
1817
|
/**
|
|
1818
|
+
* The logical paths an exclusion keeps. A path goes when it, an ancestor
|
|
1819
|
+
* or a descendant is excluded: excluding an object parent excludes its
|
|
1820
|
+
* whole subtree, and a kept parent would carry an excluded child back
|
|
1821
|
+
* (its other leaves stay listed on their own). Before 0.1.134 only the
|
|
1822
|
+
* exact paths were dropped, so `$select=-a` still returned `a`'s leaves.
|
|
1823
|
+
*/
|
|
1824
|
+
_invertExclusion(excluded) {
|
|
1825
|
+
return this._invertibleFields.filter((path) => {
|
|
1826
|
+
if (excluded.has(path) || (0, _atscript_db.findAncestorInSet)(path, excluded) !== void 0) return false;
|
|
1827
|
+
const prefix = `${path}.`;
|
|
1828
|
+
for (const key of excluded) if (key.startsWith(prefix)) return false;
|
|
1829
|
+
return true;
|
|
1830
|
+
});
|
|
1831
|
+
}
|
|
1832
|
+
/**
|
|
1776
1833
|
* Auto-includes the sibling-ref field whenever its `@db.amount.currency.ref`
|
|
1777
1834
|
* / `@db.unit.ref` quantity is selected — UI must never get a value without
|
|
1778
1835
|
* its dimension. No-op when `$select` is undefined (full row covers it).
|
|
@@ -1835,10 +1892,7 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1835
1892
|
for (const [k, v] of Object.entries(obj)) if (v === 1 || v === true) included.push(k);
|
|
1836
1893
|
else if (v === 0 || v === false) excluded.push(k);
|
|
1837
1894
|
if (included.length > 0 && excluded.length === 0) return included;
|
|
1838
|
-
if (excluded.length > 0 && included.length === 0)
|
|
1839
|
-
const excludedSet = new Set(excluded);
|
|
1840
|
-
return this._invertibleFields.filter((path) => !excludedSet.has(path));
|
|
1841
|
-
}
|
|
1895
|
+
if (excluded.length > 0 && included.length === 0) return this._invertExclusion(new Set(excluded));
|
|
1842
1896
|
throw new _moostjs_event_http.HttpError(500, "[moost-db] mixed inclusion/exclusion projection reached augmenter; widenPreferredIdProjection should have rejected it");
|
|
1843
1897
|
}
|
|
1844
1898
|
/** WHY: filter row/rows envelopes by the per-request `applyMetaOverlay` action set; skip `meta()` when overlay is identity. */
|
|
@@ -2019,9 +2073,14 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
2019
2073
|
});
|
|
2020
2074
|
return result;
|
|
2021
2075
|
}
|
|
2022
|
-
/**
|
|
2076
|
+
/**
|
|
2077
|
+
* Pick the first identification (PK or unique index) whose fields are all
|
|
2078
|
+
* present in the query. A unique index over a field {@link hasField} hides
|
|
2079
|
+
* is not a candidate (since 0.1.134) — `?hidden=x` answers exactly like
|
|
2080
|
+
* `?nope=x`, so it cannot probe whether a row with that value exists.
|
|
2081
|
+
*/
|
|
2023
2082
|
extractIdShape(query) {
|
|
2024
|
-
for (const id of this.
|
|
2083
|
+
for (const id of this.idSource.identifications) {
|
|
2025
2084
|
const idObj = {};
|
|
2026
2085
|
let allPresent = true;
|
|
2027
2086
|
for (const field of id.fields) {
|
|
@@ -2258,7 +2317,7 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
2258
2317
|
...parsedControls,
|
|
2259
2318
|
$select: initialSelect
|
|
2260
2319
|
};
|
|
2261
|
-
const idFilter = this.readable.resolveIdFilter(id);
|
|
2320
|
+
const idFilter = this.readable.resolveIdFilter(id, this._idOpts);
|
|
2262
2321
|
let row = null;
|
|
2263
2322
|
if (idFilter) {
|
|
2264
2323
|
const overlay = await this.transformOne({});
|
|
@@ -2381,7 +2440,7 @@ __decorate([
|
|
|
2381
2440
|
__decorateMetadata("design:paramtypes", [typeof Record === "undefined" ? Object : Record, String]),
|
|
2382
2441
|
__decorateMetadata("design:returntype", Promise)
|
|
2383
2442
|
], AsDbReadableController.prototype, "getOneComposite", null);
|
|
2384
|
-
AsDbReadableController = __decorate([
|
|
2443
|
+
AsDbReadableController = _AsDbReadableController = __decorate([
|
|
2385
2444
|
(0, moost.Inherit)(),
|
|
2386
2445
|
__decorateParam(1, (0, moost.Inject)(READABLE_DEF)),
|
|
2387
2446
|
__decorateParam(1, (0, moost.Optional)()),
|
|
@@ -2413,6 +2472,9 @@ function hasWriteShape(data, many) {
|
|
|
2413
2472
|
let AsDbController = _AsDbController = class AsDbController extends AsDbReadableController {
|
|
2414
2473
|
constructor(app, table) {
|
|
2415
2474
|
super(app, table);
|
|
2475
|
+
const proto = _AsDbController.prototype;
|
|
2476
|
+
this._writeArgs = this._hookArgs(this.guardWrite !== proto.guardWrite ? (ctx) => this.guardWrite(ctx) : void 0);
|
|
2477
|
+
this._removeArgs = this._hookArgs(this.guardRemove !== proto.guardRemove ? (ctx) => this.guardRemove(ctx) : void 0);
|
|
2416
2478
|
}
|
|
2417
2479
|
buildCrud() {
|
|
2418
2480
|
return {
|
|
@@ -2480,19 +2542,20 @@ let AsDbController = _AsDbController = class AsDbController extends AsDbReadable
|
|
|
2480
2542
|
withTransaction(fn) {
|
|
2481
2543
|
return this.table.getAdapter().withTransaction(fn);
|
|
2482
2544
|
}
|
|
2545
|
+
/** The table write call's trailing options — see {@link _hookArgs}. */
|
|
2546
|
+
_writeArgs;
|
|
2547
|
+
/** `deleteOne`'s trailing options — see {@link _hookArgs}. */
|
|
2548
|
+
_removeArgs;
|
|
2483
2549
|
/**
|
|
2484
|
-
*
|
|
2485
|
-
*
|
|
2486
|
-
*
|
|
2550
|
+
* A table call's trailing options, built once: `guard` only when the guard
|
|
2551
|
+
* hook is overridden, `isFieldVisible` only when `hasField` is (an id or a
|
|
2552
|
+
* PK-less payload never resolves through a hidden unique key) — else
|
|
2553
|
+
* nothing, so an unmodified controller calls the table exactly as before.
|
|
2487
2554
|
*/
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
/** `deleteOne`'s trailing options: `[{ guard }]` only when `guardRemove` is overridden. */
|
|
2493
|
-
_removeArgs() {
|
|
2494
|
-
if (this.guardRemove === _AsDbController.prototype.guardRemove) return [];
|
|
2495
|
-
return [{ guard: (ctx) => this.guardRemove(ctx) }];
|
|
2555
|
+
_hookArgs(guard) {
|
|
2556
|
+
const opts = { ...this._idOpts };
|
|
2557
|
+
if (guard) opts.guard = guard;
|
|
2558
|
+
return Object.keys(opts).length > 0 ? [opts] : [];
|
|
2496
2559
|
}
|
|
2497
2560
|
/** Resolves a hook result: `undefined` aborts with `abortMessage`, an `Error` is thrown, anything else passes. */
|
|
2498
2561
|
async _checkHook(pending, abortMessage) {
|
|
@@ -2542,7 +2605,7 @@ let AsDbController = _AsDbController = class AsDbController extends AsDbReadable
|
|
|
2542
2605
|
}
|
|
2543
2606
|
/** Deletes by id (guard forwarded when overridden) and maps "nothing deleted" to 404. */
|
|
2544
2607
|
async _deleteOrThrow(id) {
|
|
2545
|
-
const result = await this.table.deleteOne(id, ...this._removeArgs
|
|
2608
|
+
const result = await this.table.deleteOne(id, ...this._removeArgs);
|
|
2546
2609
|
if (result.deletedCount < 1) throw new _moostjs_event_http.HttpError(404);
|
|
2547
2610
|
return result;
|
|
2548
2611
|
}
|
|
@@ -2553,10 +2616,10 @@ let AsDbController = _AsDbController = class AsDbController extends AsDbReadable
|
|
|
2553
2616
|
assertWriteShape(payload);
|
|
2554
2617
|
if (Array.isArray(payload)) {
|
|
2555
2618
|
const rows = await this._writeBody("insertMany", payload, true);
|
|
2556
|
-
return this.table.insertMany(rows, ...this._writeArgs
|
|
2619
|
+
return this.table.insertMany(rows, ...this._writeArgs);
|
|
2557
2620
|
}
|
|
2558
2621
|
const row = await this._writeBody("insert", payload, false);
|
|
2559
|
-
return this.table.insertOne(row, ...this._writeArgs
|
|
2622
|
+
return this.table.insertOne(row, ...this._writeArgs);
|
|
2560
2623
|
}
|
|
2561
2624
|
/**
|
|
2562
2625
|
* **PUT /** — fully replaces one or many records matched by primary key.
|
|
@@ -2573,11 +2636,11 @@ let AsDbController = _AsDbController = class AsDbController extends AsDbReadable
|
|
|
2573
2636
|
if (Array.isArray(payload)) {
|
|
2574
2637
|
const rows = await this._writeBody("replaceMany", payload, true);
|
|
2575
2638
|
this._resolveBulkCas(rows, versionColumn);
|
|
2576
|
-
return this.table.bulkReplace(rows, ...this._writeArgs
|
|
2639
|
+
return this.table.bulkReplace(rows, ...this._writeArgs);
|
|
2577
2640
|
}
|
|
2578
2641
|
const row = await this._writeBody("replace", payload, false);
|
|
2579
2642
|
const hadCas = this._resolveCas(row, versionColumn);
|
|
2580
|
-
const result = await this.table.replaceOne(row, ...this._writeArgs
|
|
2643
|
+
const result = await this.table.replaceOne(row, ...this._writeArgs);
|
|
2581
2644
|
if (hadCas && result.matchedCount === 0) throw await this._disambiguateMismatch(row, versionColumn);
|
|
2582
2645
|
return result;
|
|
2583
2646
|
}
|
|
@@ -2594,11 +2657,11 @@ let AsDbController = _AsDbController = class AsDbController extends AsDbReadable
|
|
|
2594
2657
|
if (Array.isArray(payload)) {
|
|
2595
2658
|
const rows = await this._writeBody("updateMany", payload, true);
|
|
2596
2659
|
this._resolveBulkCas(rows, versionColumn);
|
|
2597
|
-
return this.table.bulkUpdate(rows, ...this._writeArgs
|
|
2660
|
+
return this.table.bulkUpdate(rows, ...this._writeArgs);
|
|
2598
2661
|
}
|
|
2599
2662
|
const row = await this._writeBody("update", payload, false);
|
|
2600
2663
|
const hadCas = this._resolveCas(row, versionColumn);
|
|
2601
|
-
const result = await this.table.updateOne(row, ...this._writeArgs
|
|
2664
|
+
const result = await this.table.updateOne(row, ...this._writeArgs);
|
|
2602
2665
|
if (hadCas && result.matchedCount === 0) throw await this._disambiguateMismatch(row, versionColumn);
|
|
2603
2666
|
return result;
|
|
2604
2667
|
}
|
|
@@ -2609,7 +2672,7 @@ let AsDbController = _AsDbController = class AsDbController extends AsDbReadable
|
|
|
2609
2672
|
* but the supplied version is stale (§6.3). Callers throw the result.
|
|
2610
2673
|
*/
|
|
2611
2674
|
async _disambiguateMismatch(data, versionColumn) {
|
|
2612
|
-
const filter = this.table.resolveIdFilter(data);
|
|
2675
|
+
const filter = this.table.resolveIdFilter(data, this._idOpts);
|
|
2613
2676
|
const row = filter ? await this.table.findOne({
|
|
2614
2677
|
filter,
|
|
2615
2678
|
controls: {}
|
|
@@ -3158,8 +3221,11 @@ function isPlainObject(value) {
|
|
|
3158
3221
|
//#endregion
|
|
3159
3222
|
//#region src/actions/id-cache.ts
|
|
3160
3223
|
const boundTableKey = (0, _wooksjs_event_core.key)("atscript_db_action_bound_table");
|
|
3224
|
+
function controllerOf(ctx) {
|
|
3225
|
+
return (0, moost.useControllerContext)(ctx).getController();
|
|
3226
|
+
}
|
|
3161
3227
|
function controllerTable(ctx) {
|
|
3162
|
-
const ctrl = (
|
|
3228
|
+
const ctrl = controllerOf(ctx);
|
|
3163
3229
|
return ctrl?.readable ?? ctrl?.table ?? null;
|
|
3164
3230
|
}
|
|
3165
3231
|
function getActionTable(ctx) {
|
|
@@ -3180,11 +3246,22 @@ function noTableError(ctx) {
|
|
|
3180
3246
|
code: "ACTION_TABLE_NOT_BOUND"
|
|
3181
3247
|
});
|
|
3182
3248
|
}
|
|
3249
|
+
/**
|
|
3250
|
+
* Validates the body's `ids` against the action table's identifications. For
|
|
3251
|
+
* the controller's own table that is its `idSource` (since 0.1.134): a unique
|
|
3252
|
+
* index over a field `hasField` hides neither addresses a row nor appears in
|
|
3253
|
+
* the "must exactly match one of" message. An `opts.table` binding has no
|
|
3254
|
+
* visibility hook.
|
|
3255
|
+
*/
|
|
3183
3256
|
async function resolveValidatedId(ctx, validate) {
|
|
3184
|
-
|
|
3185
|
-
if (!
|
|
3257
|
+
let source = ctx.has(boundTableKey) ? ctx.get(boundTableKey) : void 0;
|
|
3258
|
+
if (!source) {
|
|
3259
|
+
const ctrl = controllerOf(ctx);
|
|
3260
|
+
source = ctrl?.idSource ?? ctrl?.readable ?? ctrl?.table ?? null;
|
|
3261
|
+
}
|
|
3262
|
+
if (!isIdValidationSource(source)) throw noTableError(ctx);
|
|
3186
3263
|
const env = await ctx.get(dbActionBodySlot);
|
|
3187
|
-
validate(env.ids,
|
|
3264
|
+
validate(env.ids, source);
|
|
3188
3265
|
return env.ids;
|
|
3189
3266
|
}
|
|
3190
3267
|
const dbActionIdSlot = (0, _wooksjs_event_core.cached)((ctx) => resolveValidatedId(ctx, validateSingleId));
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as resolveDbSpace, n as clearDbSpaces, r as provideDbSpace, t as DEFAULT_DB_SPACE } from "./db-space-registry-CWpYwZ4R.cjs";
|
|
2
2
|
import { TAtscriptAnnotatedType, TAtscriptDataType, TSerializeOptions, TSerializedAnnotatedType, TValidatorOptions, Validator } from "@atscript/typescript/utils";
|
|
3
|
-
import { AtscriptDbReadable, AtscriptDbTable, BucketUnit, FilterExpr, FlatOf, TCrudOp, TCrudPermissions, TCrudPermissions as TCrudPermissions$1, TDbActionInfo, TDbActionInfo as TDbActionInfo$1, TDbActionIntent, TDbActionIntent as TDbActionIntent$1, TDbActionLevel, TDbActionLevel as TDbActionLevel$1, TDbActionProcessor, TDbFieldMeta, TDbRemoveGuardContext, TDbRemoveGuardContext as TDbRemoveGuardContext$1, TDbWriteAction, TDbWriteAction as TDbWriteAction$1, TDbWriteGuardContext, TDbWriteGuardContext as TDbWriteGuardContext$1, TFilterPredicate, TIdentification, TMetaResponse, TQueryPathOp, TQueryPathOp as TQueryPathOp$1, TQueryPathRefs, TQueryPathSource, Uniquery, UniqueryControls, collectQueryPaths } from "@atscript/db";
|
|
3
|
+
import { AtscriptDbReadable, AtscriptDbTable, BucketUnit, FilterExpr, FlatOf, TCrudOp, TCrudPermissions, TCrudPermissions as TCrudPermissions$1, TDbActionInfo, TDbActionInfo as TDbActionInfo$1, TDbActionIntent, TDbActionIntent as TDbActionIntent$1, TDbActionLevel, TDbActionLevel as TDbActionLevel$1, TDbActionProcessor, TDbFieldMeta, TDbRemoveGuardContext, TDbRemoveGuardContext as TDbRemoveGuardContext$1, TDbWriteAction, TDbWriteAction as TDbWriteAction$1, TDbWriteGuardContext, TDbWriteGuardContext as TDbWriteGuardContext$1, TFilterPredicate, TIdResolveOptions, TIdentification, TMetaResponse, TQueryPathOp, TQueryPathOp as TQueryPathOp$1, TQueryPathRefs, TQueryPathSource, Uniquery, UniqueryControls, collectQueryPaths } from "@atscript/db";
|
|
4
4
|
import { HttpError } from "@moostjs/event-http";
|
|
5
5
|
import { Mate, Moost, TConsoleBase, TMateParamMeta, TMoostMetadata } from "moost";
|
|
6
6
|
import { parseUrl } from "@uniqu/url";
|
|
@@ -185,6 +185,13 @@ declare abstract class AsReadableController<T extends TAtscriptAnnotatedType = T
|
|
|
185
185
|
protected applyMetaOverlay(meta: TMetaResponse): TMetaResponse | Promise<TMetaResponse>;
|
|
186
186
|
}
|
|
187
187
|
//#endregion
|
|
188
|
+
//#region src/actions/id-validation.d.ts
|
|
189
|
+
/** Duck-typed shape; matches `AtscriptDbReadable`'s public surface. */
|
|
190
|
+
interface IdValidationSource {
|
|
191
|
+
readonly identifications: readonly TIdentification[];
|
|
192
|
+
readonly fieldDescriptors: readonly TDbFieldMeta[];
|
|
193
|
+
}
|
|
194
|
+
//#endregion
|
|
188
195
|
//#region src/meta/field-capabilities.d.ts
|
|
189
196
|
/**
|
|
190
197
|
* Per-path HTTP capability of a DB readable — the single source that both the
|
|
@@ -352,6 +359,15 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
|
|
|
352
359
|
protected metaCacheKey(): unknown;
|
|
353
360
|
/** Bound once: the visibility check ({@link hasField}) the gate hands to `capabilities.check`. */
|
|
354
361
|
private readonly _exists;
|
|
362
|
+
/**
|
|
363
|
+
* Id-resolution options (since 0.1.134): `{ isFieldVisible: hasField }`
|
|
364
|
+
* when a subclass overrides {@link hasField}, else `undefined` (the default
|
|
365
|
+
* accepts every real path, so resolution stays unfiltered). A unique index
|
|
366
|
+
* over a hidden field is never an identification.
|
|
367
|
+
*/
|
|
368
|
+
protected readonly _idOpts: TIdResolveOptions | undefined;
|
|
369
|
+
/** Narrowed id sources, one stable object per distinct visible-identification set. */
|
|
370
|
+
private readonly _idSources;
|
|
355
371
|
private readonly _preferredIdSet;
|
|
356
372
|
private readonly _overlayIsNoOp;
|
|
357
373
|
/** path → sibling-ref path for `@db.amount.currency.ref` / `@db.unit.ref`. */
|
|
@@ -367,6 +383,13 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
|
|
|
367
383
|
*/
|
|
368
384
|
private readonly _invertibleFields;
|
|
369
385
|
constructor(app: Moost, readable?: AtscriptDbReadable<T>);
|
|
386
|
+
/**
|
|
387
|
+
* The identifications this request may address rows through (since
|
|
388
|
+
* 0.1.134): the readable's own, minus unique indexes over fields
|
|
389
|
+
* {@link hasField} hides. Used by `/one?…`, `DELETE /?…` and action `ids`.
|
|
390
|
+
* Stable per distinct outcome, so per-source caches keyed on it hit.
|
|
391
|
+
*/
|
|
392
|
+
get idSource(): IdValidationSource;
|
|
370
393
|
private _collectInvertibleFields;
|
|
371
394
|
private _collectQuantityRefs;
|
|
372
395
|
private _collectAnnotated;
|
|
@@ -378,7 +401,11 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
|
|
|
378
401
|
* `$with` relation names and sub-query paths, and the `$search` fallback
|
|
379
402
|
* fields. A path it rejects is answered exactly like a nonexistent one
|
|
380
403
|
* (`Unknown field "x"` / `Unknown relation "x"`), so override it to hide
|
|
381
|
-
* fields per request (read scopes).
|
|
404
|
+
* fields per request (read scopes). Since 0.1.134 it also governs row
|
|
405
|
+
* identification — a unique index over a hidden field is not an
|
|
406
|
+
* identification for `/one/:id`, `/one?…`, `DELETE`, a PK-less `PATCH` or
|
|
407
|
+
* an action id (primary key and `preferredId` always are) — and the
|
|
408
|
+
* nested-object 400 hint lists visible leaves only. The default accepts every real path
|
|
382
409
|
* (`isValidFieldPath`). `/meta` does NOT consult it — prune hidden fields
|
|
383
410
|
* there with `applyMetaOverlay`. Native text search and vector search
|
|
384
411
|
* (`$vector` names an index) run inside the engine over its indexes, out of
|
|
@@ -453,6 +480,14 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
|
|
|
453
480
|
private widenPreferredIdProjection;
|
|
454
481
|
private _widenArrayProjection;
|
|
455
482
|
private _widenMapProjection;
|
|
483
|
+
/**
|
|
484
|
+
* The logical paths an exclusion keeps. A path goes when it, an ancestor
|
|
485
|
+
* or a descendant is excluded: excluding an object parent excludes its
|
|
486
|
+
* whole subtree, and a kept parent would carry an excluded child back
|
|
487
|
+
* (its other leaves stay listed on their own). Before 0.1.134 only the
|
|
488
|
+
* exact paths were dropped, so `$select=-a` still returned `a`'s leaves.
|
|
489
|
+
*/
|
|
490
|
+
private _invertExclusion;
|
|
456
491
|
/**
|
|
457
492
|
* Auto-includes the sibling-ref field whenever its `@db.amount.currency.ref`
|
|
458
493
|
* / `@db.unit.ref` quantity is selected — UI must never get a value without
|
|
@@ -523,7 +558,12 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
|
|
|
523
558
|
* family (count vs no-count).
|
|
524
559
|
*/
|
|
525
560
|
private _runReadWithActions;
|
|
526
|
-
/**
|
|
561
|
+
/**
|
|
562
|
+
* Pick the first identification (PK or unique index) whose fields are all
|
|
563
|
+
* present in the query. A unique index over a field {@link hasField} hides
|
|
564
|
+
* is not a candidate (since 0.1.134) — `?hidden=x` answers exactly like
|
|
565
|
+
* `?nope=x`, so it cannot probe whether a row with that value exists.
|
|
566
|
+
*/
|
|
527
567
|
protected extractIdShape(query: Record<string, string>): Record<string, unknown> | HttpError;
|
|
528
568
|
/**
|
|
529
569
|
* **GET /query** — returns an array of records or a count.
|
|
@@ -664,14 +704,17 @@ declare class AsDbController<T extends TAtscriptAnnotatedType = TAtscriptAnnotat
|
|
|
664
704
|
* several table operations.
|
|
665
705
|
*/
|
|
666
706
|
protected withTransaction<R>(fn: () => Promise<R>): Promise<R>;
|
|
707
|
+
/** The table write call's trailing options — see {@link _hookArgs}. */
|
|
708
|
+
private readonly _writeArgs;
|
|
709
|
+
/** `deleteOne`'s trailing options — see {@link _hookArgs}. */
|
|
710
|
+
private readonly _removeArgs;
|
|
667
711
|
/**
|
|
668
|
-
*
|
|
669
|
-
*
|
|
670
|
-
*
|
|
712
|
+
* A table call's trailing options, built once: `guard` only when the guard
|
|
713
|
+
* hook is overridden, `isFieldVisible` only when `hasField` is (an id or a
|
|
714
|
+
* PK-less payload never resolves through a hidden unique key) — else
|
|
715
|
+
* nothing, so an unmodified controller calls the table exactly as before.
|
|
671
716
|
*/
|
|
672
|
-
private
|
|
673
|
-
/** `deleteOne`'s trailing options: `[{ guard }]` only when `guardRemove` is overridden. */
|
|
674
|
-
private _removeArgs;
|
|
717
|
+
private _hookArgs;
|
|
675
718
|
/** Resolves a hook result: `undefined` aborts with `abortMessage`, an `Error` is thrown, anything else passes. */
|
|
676
719
|
private _checkHook;
|
|
677
720
|
/** Runs `onWrite` and re-applies the shape gate to its output (a non-object is a 500 "Not saved"). */
|
|
@@ -1528,13 +1571,6 @@ declare function getControllerFormType(ctor: Function, name: string): TAtscriptA
|
|
|
1528
1571
|
/** Discover actions on a controller, memoized per ctor. `info`-only callers map `e => e.info`. */
|
|
1529
1572
|
declare function discoverActions(controllerCtor: Function, app: Moost, logger: TConsoleBase): TDbActionEnvelope[];
|
|
1530
1573
|
//#endregion
|
|
1531
|
-
//#region src/actions/id-validation.d.ts
|
|
1532
|
-
/** Duck-typed shape; matches `AtscriptDbReadable`'s public surface. */
|
|
1533
|
-
interface IdValidationSource {
|
|
1534
|
-
readonly identifications: readonly TIdentification[];
|
|
1535
|
-
readonly fieldDescriptors: readonly TDbFieldMeta[];
|
|
1536
|
-
}
|
|
1537
|
-
//#endregion
|
|
1538
1574
|
//#region src/actions/id-cache.d.ts
|
|
1539
1575
|
declare const useDbActionId: import("@wooksjs/event-core").WookComposable<{
|
|
1540
1576
|
load: () => Promise<Record<string, unknown>>;
|
package/dist/index.d.mts
CHANGED
|
@@ -3,7 +3,7 @@ import { TAtscriptAnnotatedType, TAtscriptDataType, TSerializeOptions, TSerializ
|
|
|
3
3
|
import { HttpError } from "@moostjs/event-http";
|
|
4
4
|
import { Mate, Moost, TConsoleBase, TMateParamMeta, TMoostMetadata } from "moost";
|
|
5
5
|
import { parseUrl } from "@uniqu/url";
|
|
6
|
-
import { AtscriptDbReadable, AtscriptDbTable, BucketUnit, FilterExpr, FlatOf, TCrudOp, TCrudPermissions, TCrudPermissions as TCrudPermissions$1, TDbActionInfo, TDbActionInfo as TDbActionInfo$1, TDbActionIntent, TDbActionIntent as TDbActionIntent$1, TDbActionLevel, TDbActionLevel as TDbActionLevel$1, TDbActionProcessor, TDbFieldMeta, TDbRemoveGuardContext, TDbRemoveGuardContext as TDbRemoveGuardContext$1, TDbWriteAction, TDbWriteAction as TDbWriteAction$1, TDbWriteGuardContext, TDbWriteGuardContext as TDbWriteGuardContext$1, TFilterPredicate, TIdentification, TMetaResponse, TQueryPathOp, TQueryPathOp as TQueryPathOp$1, TQueryPathRefs, TQueryPathSource, Uniquery, UniqueryControls, collectQueryPaths } from "@atscript/db";
|
|
6
|
+
import { AtscriptDbReadable, AtscriptDbTable, BucketUnit, FilterExpr, FlatOf, TCrudOp, TCrudPermissions, TCrudPermissions as TCrudPermissions$1, TDbActionInfo, TDbActionInfo as TDbActionInfo$1, TDbActionIntent, TDbActionIntent as TDbActionIntent$1, TDbActionLevel, TDbActionLevel as TDbActionLevel$1, TDbActionProcessor, TDbFieldMeta, TDbRemoveGuardContext, TDbRemoveGuardContext as TDbRemoveGuardContext$1, TDbWriteAction, TDbWriteAction as TDbWriteAction$1, TDbWriteGuardContext, TDbWriteGuardContext as TDbWriteGuardContext$1, TFilterPredicate, TIdResolveOptions, TIdentification, TMetaResponse, TQueryPathOp, TQueryPathOp as TQueryPathOp$1, TQueryPathRefs, TQueryPathSource, Uniquery, UniqueryControls, collectQueryPaths } from "@atscript/db";
|
|
7
7
|
//#region src/as-readable.controller.d.ts
|
|
8
8
|
/**
|
|
9
9
|
* Abstract base class for read-only HTTP controllers over an Atscript interface.
|
|
@@ -185,6 +185,13 @@ declare abstract class AsReadableController<T extends TAtscriptAnnotatedType = T
|
|
|
185
185
|
protected applyMetaOverlay(meta: TMetaResponse): TMetaResponse | Promise<TMetaResponse>;
|
|
186
186
|
}
|
|
187
187
|
//#endregion
|
|
188
|
+
//#region src/actions/id-validation.d.ts
|
|
189
|
+
/** Duck-typed shape; matches `AtscriptDbReadable`'s public surface. */
|
|
190
|
+
interface IdValidationSource {
|
|
191
|
+
readonly identifications: readonly TIdentification[];
|
|
192
|
+
readonly fieldDescriptors: readonly TDbFieldMeta[];
|
|
193
|
+
}
|
|
194
|
+
//#endregion
|
|
188
195
|
//#region src/meta/field-capabilities.d.ts
|
|
189
196
|
/**
|
|
190
197
|
* Per-path HTTP capability of a DB readable — the single source that both the
|
|
@@ -352,6 +359,15 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
|
|
|
352
359
|
protected metaCacheKey(): unknown;
|
|
353
360
|
/** Bound once: the visibility check ({@link hasField}) the gate hands to `capabilities.check`. */
|
|
354
361
|
private readonly _exists;
|
|
362
|
+
/**
|
|
363
|
+
* Id-resolution options (since 0.1.134): `{ isFieldVisible: hasField }`
|
|
364
|
+
* when a subclass overrides {@link hasField}, else `undefined` (the default
|
|
365
|
+
* accepts every real path, so resolution stays unfiltered). A unique index
|
|
366
|
+
* over a hidden field is never an identification.
|
|
367
|
+
*/
|
|
368
|
+
protected readonly _idOpts: TIdResolveOptions | undefined;
|
|
369
|
+
/** Narrowed id sources, one stable object per distinct visible-identification set. */
|
|
370
|
+
private readonly _idSources;
|
|
355
371
|
private readonly _preferredIdSet;
|
|
356
372
|
private readonly _overlayIsNoOp;
|
|
357
373
|
/** path → sibling-ref path for `@db.amount.currency.ref` / `@db.unit.ref`. */
|
|
@@ -367,6 +383,13 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
|
|
|
367
383
|
*/
|
|
368
384
|
private readonly _invertibleFields;
|
|
369
385
|
constructor(app: Moost, readable?: AtscriptDbReadable<T>);
|
|
386
|
+
/**
|
|
387
|
+
* The identifications this request may address rows through (since
|
|
388
|
+
* 0.1.134): the readable's own, minus unique indexes over fields
|
|
389
|
+
* {@link hasField} hides. Used by `/one?…`, `DELETE /?…` and action `ids`.
|
|
390
|
+
* Stable per distinct outcome, so per-source caches keyed on it hit.
|
|
391
|
+
*/
|
|
392
|
+
get idSource(): IdValidationSource;
|
|
370
393
|
private _collectInvertibleFields;
|
|
371
394
|
private _collectQuantityRefs;
|
|
372
395
|
private _collectAnnotated;
|
|
@@ -378,7 +401,11 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
|
|
|
378
401
|
* `$with` relation names and sub-query paths, and the `$search` fallback
|
|
379
402
|
* fields. A path it rejects is answered exactly like a nonexistent one
|
|
380
403
|
* (`Unknown field "x"` / `Unknown relation "x"`), so override it to hide
|
|
381
|
-
* fields per request (read scopes).
|
|
404
|
+
* fields per request (read scopes). Since 0.1.134 it also governs row
|
|
405
|
+
* identification — a unique index over a hidden field is not an
|
|
406
|
+
* identification for `/one/:id`, `/one?…`, `DELETE`, a PK-less `PATCH` or
|
|
407
|
+
* an action id (primary key and `preferredId` always are) — and the
|
|
408
|
+
* nested-object 400 hint lists visible leaves only. The default accepts every real path
|
|
382
409
|
* (`isValidFieldPath`). `/meta` does NOT consult it — prune hidden fields
|
|
383
410
|
* there with `applyMetaOverlay`. Native text search and vector search
|
|
384
411
|
* (`$vector` names an index) run inside the engine over its indexes, out of
|
|
@@ -453,6 +480,14 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
|
|
|
453
480
|
private widenPreferredIdProjection;
|
|
454
481
|
private _widenArrayProjection;
|
|
455
482
|
private _widenMapProjection;
|
|
483
|
+
/**
|
|
484
|
+
* The logical paths an exclusion keeps. A path goes when it, an ancestor
|
|
485
|
+
* or a descendant is excluded: excluding an object parent excludes its
|
|
486
|
+
* whole subtree, and a kept parent would carry an excluded child back
|
|
487
|
+
* (its other leaves stay listed on their own). Before 0.1.134 only the
|
|
488
|
+
* exact paths were dropped, so `$select=-a` still returned `a`'s leaves.
|
|
489
|
+
*/
|
|
490
|
+
private _invertExclusion;
|
|
456
491
|
/**
|
|
457
492
|
* Auto-includes the sibling-ref field whenever its `@db.amount.currency.ref`
|
|
458
493
|
* / `@db.unit.ref` quantity is selected — UI must never get a value without
|
|
@@ -523,7 +558,12 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
|
|
|
523
558
|
* family (count vs no-count).
|
|
524
559
|
*/
|
|
525
560
|
private _runReadWithActions;
|
|
526
|
-
/**
|
|
561
|
+
/**
|
|
562
|
+
* Pick the first identification (PK or unique index) whose fields are all
|
|
563
|
+
* present in the query. A unique index over a field {@link hasField} hides
|
|
564
|
+
* is not a candidate (since 0.1.134) — `?hidden=x` answers exactly like
|
|
565
|
+
* `?nope=x`, so it cannot probe whether a row with that value exists.
|
|
566
|
+
*/
|
|
527
567
|
protected extractIdShape(query: Record<string, string>): Record<string, unknown> | HttpError;
|
|
528
568
|
/**
|
|
529
569
|
* **GET /query** — returns an array of records or a count.
|
|
@@ -664,14 +704,17 @@ declare class AsDbController<T extends TAtscriptAnnotatedType = TAtscriptAnnotat
|
|
|
664
704
|
* several table operations.
|
|
665
705
|
*/
|
|
666
706
|
protected withTransaction<R>(fn: () => Promise<R>): Promise<R>;
|
|
707
|
+
/** The table write call's trailing options — see {@link _hookArgs}. */
|
|
708
|
+
private readonly _writeArgs;
|
|
709
|
+
/** `deleteOne`'s trailing options — see {@link _hookArgs}. */
|
|
710
|
+
private readonly _removeArgs;
|
|
667
711
|
/**
|
|
668
|
-
*
|
|
669
|
-
*
|
|
670
|
-
*
|
|
712
|
+
* A table call's trailing options, built once: `guard` only when the guard
|
|
713
|
+
* hook is overridden, `isFieldVisible` only when `hasField` is (an id or a
|
|
714
|
+
* PK-less payload never resolves through a hidden unique key) — else
|
|
715
|
+
* nothing, so an unmodified controller calls the table exactly as before.
|
|
671
716
|
*/
|
|
672
|
-
private
|
|
673
|
-
/** `deleteOne`'s trailing options: `[{ guard }]` only when `guardRemove` is overridden. */
|
|
674
|
-
private _removeArgs;
|
|
717
|
+
private _hookArgs;
|
|
675
718
|
/** Resolves a hook result: `undefined` aborts with `abortMessage`, an `Error` is thrown, anything else passes. */
|
|
676
719
|
private _checkHook;
|
|
677
720
|
/** Runs `onWrite` and re-applies the shape gate to its output (a non-object is a 500 "Not saved"). */
|
|
@@ -1528,13 +1571,6 @@ declare function getControllerFormType(ctor: Function, name: string): TAtscriptA
|
|
|
1528
1571
|
/** Discover actions on a controller, memoized per ctor. `info`-only callers map `e => e.info`. */
|
|
1529
1572
|
declare function discoverActions(controllerCtor: Function, app: Moost, logger: TConsoleBase): TDbActionEnvelope[];
|
|
1530
1573
|
//#endregion
|
|
1531
|
-
//#region src/actions/id-validation.d.ts
|
|
1532
|
-
/** Duck-typed shape; matches `AtscriptDbReadable`'s public surface. */
|
|
1533
|
-
interface IdValidationSource {
|
|
1534
|
-
readonly identifications: readonly TIdentification[];
|
|
1535
|
-
readonly fieldDescriptors: readonly TDbFieldMeta[];
|
|
1536
|
-
}
|
|
1537
|
-
//#endregion
|
|
1538
1574
|
//#region src/actions/id-cache.d.ts
|
|
1539
1575
|
declare const useDbActionId: import("@wooksjs/event-core").WookComposable<{
|
|
1540
1576
|
load: () => Promise<Record<string, unknown>>;
|
package/dist/index.mjs
CHANGED
|
@@ -1180,6 +1180,13 @@ const OP_VERB = {
|
|
|
1180
1180
|
aggregate: "aggregate over",
|
|
1181
1181
|
bucket: "bucket"
|
|
1182
1182
|
};
|
|
1183
|
+
/** The one "nonexistent path" verdict — hidden paths answer with it byte for byte. */
|
|
1184
|
+
function unknownField(path) {
|
|
1185
|
+
return {
|
|
1186
|
+
path,
|
|
1187
|
+
message: `Unknown field "${path}"`
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1183
1190
|
function leafHint(leaves) {
|
|
1184
1191
|
if (leaves.length === 0) return "no leaf fields";
|
|
1185
1192
|
const shown = leaves.slice(0, 5).join(", ");
|
|
@@ -1379,10 +1386,7 @@ var FieldCapabilityIndex = class FieldCapabilityIndex {
|
|
|
1379
1386
|
* occurrence); it only matters for `op === "filter"` on a listed leaf.
|
|
1380
1387
|
*/
|
|
1381
1388
|
check(path, op, exists, predicate = "compare") {
|
|
1382
|
-
if (!exists(path)) return
|
|
1383
|
-
path,
|
|
1384
|
-
message: `Unknown field "${path}"`
|
|
1385
|
-
};
|
|
1389
|
+
if (!exists(path)) return unknownField(path);
|
|
1386
1390
|
const { kind, parent } = classifyQueryPath(this, path);
|
|
1387
1391
|
if (kind === "nav") {
|
|
1388
1392
|
if (parent === void 0) return {
|
|
@@ -1423,12 +1427,16 @@ var FieldCapabilityIndex = class FieldCapabilityIndex {
|
|
|
1423
1427
|
}
|
|
1424
1428
|
}
|
|
1425
1429
|
switch (kind) {
|
|
1426
|
-
case "objectParent":
|
|
1430
|
+
case "objectParent": {
|
|
1427
1431
|
if (op === "select") return void 0;
|
|
1432
|
+
const all = this._objectParents.get(path);
|
|
1433
|
+
const leaves = all.filter(exists);
|
|
1434
|
+
if (leaves.length === 0 && all.length > 0) return unknownField(path);
|
|
1428
1435
|
return {
|
|
1429
1436
|
path,
|
|
1430
|
-
message: `"${path}" is a nested object — filter or sort on one of its leaves (${leafHint(
|
|
1437
|
+
message: `"${path}" is a nested object — filter or sort on one of its leaves (${leafHint(leaves)})`
|
|
1431
1438
|
};
|
|
1439
|
+
}
|
|
1432
1440
|
case "jsonDescendant": return {
|
|
1433
1441
|
path,
|
|
1434
1442
|
message: `"${path}" is inside JSON-stored column "${parent}" — this adapter cannot ${OP_VERB[op]} JSON paths; select "${parent}" and read the value client-side.`
|
|
@@ -1440,10 +1448,7 @@ var FieldCapabilityIndex = class FieldCapabilityIndex {
|
|
|
1440
1448
|
path,
|
|
1441
1449
|
message: `Cannot ${OP_VERB[op]} encrypted field "${path}"`
|
|
1442
1450
|
};
|
|
1443
|
-
default: return
|
|
1444
|
-
path,
|
|
1445
|
-
message: `Unknown field "${path}"`
|
|
1446
|
-
};
|
|
1451
|
+
default: return unknownField(path);
|
|
1447
1452
|
}
|
|
1448
1453
|
}
|
|
1449
1454
|
};
|
|
@@ -1485,6 +1490,7 @@ const GEO_CONTROLS = [
|
|
|
1485
1490
|
];
|
|
1486
1491
|
//#endregion
|
|
1487
1492
|
//#region src/as-db-readable.controller.ts
|
|
1493
|
+
var _AsDbReadableController;
|
|
1488
1494
|
/** Gate positions checked after the filter entries, in order; `refs[op]` are their paths. */
|
|
1489
1495
|
const PATH_OPS = [
|
|
1490
1496
|
"sort",
|
|
@@ -1494,7 +1500,7 @@ const PATH_OPS = [
|
|
|
1494
1500
|
"aggregate",
|
|
1495
1501
|
"bucket"
|
|
1496
1502
|
];
|
|
1497
|
-
let AsDbReadableController = class AsDbReadableController extends AsReadableController {
|
|
1503
|
+
let AsDbReadableController = _AsDbReadableController = class AsDbReadableController extends AsReadableController {
|
|
1498
1504
|
/** Reference to the underlying readable (table or view). */
|
|
1499
1505
|
readable;
|
|
1500
1506
|
/**
|
|
@@ -1534,6 +1540,15 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1534
1540
|
}
|
|
1535
1541
|
/** Bound once: the visibility check ({@link hasField}) the gate hands to `capabilities.check`. */
|
|
1536
1542
|
_exists = (path) => this.hasField(path);
|
|
1543
|
+
/**
|
|
1544
|
+
* Id-resolution options (since 0.1.134): `{ isFieldVisible: hasField }`
|
|
1545
|
+
* when a subclass overrides {@link hasField}, else `undefined` (the default
|
|
1546
|
+
* accepts every real path, so resolution stays unfiltered). A unique index
|
|
1547
|
+
* over a hidden field is never an identification.
|
|
1548
|
+
*/
|
|
1549
|
+
_idOpts;
|
|
1550
|
+
/** Narrowed id sources, one stable object per distinct visible-identification set. */
|
|
1551
|
+
_idSources = /* @__PURE__ */ new Map();
|
|
1537
1552
|
_preferredIdSet;
|
|
1538
1553
|
_overlayIsNoOp;
|
|
1539
1554
|
/** path → sibling-ref path for `@db.amount.currency.ref` / `@db.unit.ref`. */
|
|
@@ -1559,6 +1574,29 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1559
1574
|
this._quantityRefByPath = this._collectQuantityRefs();
|
|
1560
1575
|
const defaultOverlay = AsReadableController.prototype.applyMetaOverlay;
|
|
1561
1576
|
this._overlayIsNoOp = this.applyMetaOverlay === defaultOverlay;
|
|
1577
|
+
this._idOpts = this.hasField === _AsDbReadableController.prototype.hasField ? void 0 : { isFieldVisible: this._exists };
|
|
1578
|
+
}
|
|
1579
|
+
/**
|
|
1580
|
+
* The identifications this request may address rows through (since
|
|
1581
|
+
* 0.1.134): the readable's own, minus unique indexes over fields
|
|
1582
|
+
* {@link hasField} hides. Used by `/one?…`, `DELETE /?…` and action `ids`.
|
|
1583
|
+
* Stable per distinct outcome, so per-source caches keyed on it hit.
|
|
1584
|
+
*/
|
|
1585
|
+
get idSource() {
|
|
1586
|
+
const opts = this._idOpts;
|
|
1587
|
+
if (!opts) return this.readable;
|
|
1588
|
+
const visible = this.readable.identificationsVisibleTo(opts.isFieldVisible);
|
|
1589
|
+
if (visible.length === this.readable.identifications.length) return this.readable;
|
|
1590
|
+
const key = visible.map((ident) => ident.source).join("");
|
|
1591
|
+
let source = this._idSources.get(key);
|
|
1592
|
+
if (!source) {
|
|
1593
|
+
source = {
|
|
1594
|
+
identifications: visible,
|
|
1595
|
+
fieldDescriptors: this.readable.fieldDescriptors
|
|
1596
|
+
};
|
|
1597
|
+
this._idSources.set(key, source);
|
|
1598
|
+
}
|
|
1599
|
+
return source;
|
|
1562
1600
|
}
|
|
1563
1601
|
_collectInvertibleFields() {
|
|
1564
1602
|
const out = [];
|
|
@@ -1593,7 +1631,11 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1593
1631
|
* `$with` relation names and sub-query paths, and the `$search` fallback
|
|
1594
1632
|
* fields. A path it rejects is answered exactly like a nonexistent one
|
|
1595
1633
|
* (`Unknown field "x"` / `Unknown relation "x"`), so override it to hide
|
|
1596
|
-
* fields per request (read scopes).
|
|
1634
|
+
* fields per request (read scopes). Since 0.1.134 it also governs row
|
|
1635
|
+
* identification — a unique index over a hidden field is not an
|
|
1636
|
+
* identification for `/one/:id`, `/one?…`, `DELETE`, a PK-less `PATCH` or
|
|
1637
|
+
* an action id (primary key and `preferredId` always are) — and the
|
|
1638
|
+
* nested-object 400 hint lists visible leaves only. The default accepts every real path
|
|
1597
1639
|
* (`isValidFieldPath`). `/meta` does NOT consult it — prune hidden fields
|
|
1598
1640
|
* there with `applyMetaOverlay`. Native text search and vector search
|
|
1599
1641
|
* (`$vector` names an index) run inside the engine over its indexes, out of
|
|
@@ -1767,11 +1809,26 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1767
1809
|
return widened;
|
|
1768
1810
|
}
|
|
1769
1811
|
const widened = {};
|
|
1770
|
-
for (const path of this.
|
|
1812
|
+
for (const path of this._invertExclusion(excluded)) widened[path] = 1;
|
|
1771
1813
|
for (const field of this._preferredIdSet) widened[field] = 1;
|
|
1772
1814
|
return widened;
|
|
1773
1815
|
}
|
|
1774
1816
|
/**
|
|
1817
|
+
* The logical paths an exclusion keeps. A path goes when it, an ancestor
|
|
1818
|
+
* or a descendant is excluded: excluding an object parent excludes its
|
|
1819
|
+
* whole subtree, and a kept parent would carry an excluded child back
|
|
1820
|
+
* (its other leaves stay listed on their own). Before 0.1.134 only the
|
|
1821
|
+
* exact paths were dropped, so `$select=-a` still returned `a`'s leaves.
|
|
1822
|
+
*/
|
|
1823
|
+
_invertExclusion(excluded) {
|
|
1824
|
+
return this._invertibleFields.filter((path) => {
|
|
1825
|
+
if (excluded.has(path) || findAncestorInSet(path, excluded) !== void 0) return false;
|
|
1826
|
+
const prefix = `${path}.`;
|
|
1827
|
+
for (const key of excluded) if (key.startsWith(prefix)) return false;
|
|
1828
|
+
return true;
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
/**
|
|
1775
1832
|
* Auto-includes the sibling-ref field whenever its `@db.amount.currency.ref`
|
|
1776
1833
|
* / `@db.unit.ref` quantity is selected — UI must never get a value without
|
|
1777
1834
|
* its dimension. No-op when `$select` is undefined (full row covers it).
|
|
@@ -1834,10 +1891,7 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1834
1891
|
for (const [k, v] of Object.entries(obj)) if (v === 1 || v === true) included.push(k);
|
|
1835
1892
|
else if (v === 0 || v === false) excluded.push(k);
|
|
1836
1893
|
if (included.length > 0 && excluded.length === 0) return included;
|
|
1837
|
-
if (excluded.length > 0 && included.length === 0)
|
|
1838
|
-
const excludedSet = new Set(excluded);
|
|
1839
|
-
return this._invertibleFields.filter((path) => !excludedSet.has(path));
|
|
1840
|
-
}
|
|
1894
|
+
if (excluded.length > 0 && included.length === 0) return this._invertExclusion(new Set(excluded));
|
|
1841
1895
|
throw new HttpError(500, "[moost-db] mixed inclusion/exclusion projection reached augmenter; widenPreferredIdProjection should have rejected it");
|
|
1842
1896
|
}
|
|
1843
1897
|
/** WHY: filter row/rows envelopes by the per-request `applyMetaOverlay` action set; skip `meta()` when overlay is identity. */
|
|
@@ -2018,9 +2072,14 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
2018
2072
|
});
|
|
2019
2073
|
return result;
|
|
2020
2074
|
}
|
|
2021
|
-
/**
|
|
2075
|
+
/**
|
|
2076
|
+
* Pick the first identification (PK or unique index) whose fields are all
|
|
2077
|
+
* present in the query. A unique index over a field {@link hasField} hides
|
|
2078
|
+
* is not a candidate (since 0.1.134) — `?hidden=x` answers exactly like
|
|
2079
|
+
* `?nope=x`, so it cannot probe whether a row with that value exists.
|
|
2080
|
+
*/
|
|
2022
2081
|
extractIdShape(query) {
|
|
2023
|
-
for (const id of this.
|
|
2082
|
+
for (const id of this.idSource.identifications) {
|
|
2024
2083
|
const idObj = {};
|
|
2025
2084
|
let allPresent = true;
|
|
2026
2085
|
for (const field of id.fields) {
|
|
@@ -2257,7 +2316,7 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
2257
2316
|
...parsedControls,
|
|
2258
2317
|
$select: initialSelect
|
|
2259
2318
|
};
|
|
2260
|
-
const idFilter = this.readable.resolveIdFilter(id);
|
|
2319
|
+
const idFilter = this.readable.resolveIdFilter(id, this._idOpts);
|
|
2261
2320
|
let row = null;
|
|
2262
2321
|
if (idFilter) {
|
|
2263
2322
|
const overlay = await this.transformOne({});
|
|
@@ -2380,7 +2439,7 @@ __decorate([
|
|
|
2380
2439
|
__decorateMetadata("design:paramtypes", [typeof Record === "undefined" ? Object : Record, String]),
|
|
2381
2440
|
__decorateMetadata("design:returntype", Promise)
|
|
2382
2441
|
], AsDbReadableController.prototype, "getOneComposite", null);
|
|
2383
|
-
AsDbReadableController = __decorate([
|
|
2442
|
+
AsDbReadableController = _AsDbReadableController = __decorate([
|
|
2384
2443
|
Inherit(),
|
|
2385
2444
|
__decorateParam(1, Inject(READABLE_DEF)),
|
|
2386
2445
|
__decorateParam(1, Optional()),
|
|
@@ -2412,6 +2471,9 @@ function hasWriteShape(data, many) {
|
|
|
2412
2471
|
let AsDbController = _AsDbController = class AsDbController extends AsDbReadableController {
|
|
2413
2472
|
constructor(app, table) {
|
|
2414
2473
|
super(app, table);
|
|
2474
|
+
const proto = _AsDbController.prototype;
|
|
2475
|
+
this._writeArgs = this._hookArgs(this.guardWrite !== proto.guardWrite ? (ctx) => this.guardWrite(ctx) : void 0);
|
|
2476
|
+
this._removeArgs = this._hookArgs(this.guardRemove !== proto.guardRemove ? (ctx) => this.guardRemove(ctx) : void 0);
|
|
2415
2477
|
}
|
|
2416
2478
|
buildCrud() {
|
|
2417
2479
|
return {
|
|
@@ -2479,19 +2541,20 @@ let AsDbController = _AsDbController = class AsDbController extends AsDbReadable
|
|
|
2479
2541
|
withTransaction(fn) {
|
|
2480
2542
|
return this.table.getAdapter().withTransaction(fn);
|
|
2481
2543
|
}
|
|
2544
|
+
/** The table write call's trailing options — see {@link _hookArgs}. */
|
|
2545
|
+
_writeArgs;
|
|
2546
|
+
/** `deleteOne`'s trailing options — see {@link _hookArgs}. */
|
|
2547
|
+
_removeArgs;
|
|
2482
2548
|
/**
|
|
2483
|
-
*
|
|
2484
|
-
*
|
|
2485
|
-
*
|
|
2549
|
+
* A table call's trailing options, built once: `guard` only when the guard
|
|
2550
|
+
* hook is overridden, `isFieldVisible` only when `hasField` is (an id or a
|
|
2551
|
+
* PK-less payload never resolves through a hidden unique key) — else
|
|
2552
|
+
* nothing, so an unmodified controller calls the table exactly as before.
|
|
2486
2553
|
*/
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
/** `deleteOne`'s trailing options: `[{ guard }]` only when `guardRemove` is overridden. */
|
|
2492
|
-
_removeArgs() {
|
|
2493
|
-
if (this.guardRemove === _AsDbController.prototype.guardRemove) return [];
|
|
2494
|
-
return [{ guard: (ctx) => this.guardRemove(ctx) }];
|
|
2554
|
+
_hookArgs(guard) {
|
|
2555
|
+
const opts = { ...this._idOpts };
|
|
2556
|
+
if (guard) opts.guard = guard;
|
|
2557
|
+
return Object.keys(opts).length > 0 ? [opts] : [];
|
|
2495
2558
|
}
|
|
2496
2559
|
/** Resolves a hook result: `undefined` aborts with `abortMessage`, an `Error` is thrown, anything else passes. */
|
|
2497
2560
|
async _checkHook(pending, abortMessage) {
|
|
@@ -2541,7 +2604,7 @@ let AsDbController = _AsDbController = class AsDbController extends AsDbReadable
|
|
|
2541
2604
|
}
|
|
2542
2605
|
/** Deletes by id (guard forwarded when overridden) and maps "nothing deleted" to 404. */
|
|
2543
2606
|
async _deleteOrThrow(id) {
|
|
2544
|
-
const result = await this.table.deleteOne(id, ...this._removeArgs
|
|
2607
|
+
const result = await this.table.deleteOne(id, ...this._removeArgs);
|
|
2545
2608
|
if (result.deletedCount < 1) throw new HttpError(404);
|
|
2546
2609
|
return result;
|
|
2547
2610
|
}
|
|
@@ -2552,10 +2615,10 @@ let AsDbController = _AsDbController = class AsDbController extends AsDbReadable
|
|
|
2552
2615
|
assertWriteShape(payload);
|
|
2553
2616
|
if (Array.isArray(payload)) {
|
|
2554
2617
|
const rows = await this._writeBody("insertMany", payload, true);
|
|
2555
|
-
return this.table.insertMany(rows, ...this._writeArgs
|
|
2618
|
+
return this.table.insertMany(rows, ...this._writeArgs);
|
|
2556
2619
|
}
|
|
2557
2620
|
const row = await this._writeBody("insert", payload, false);
|
|
2558
|
-
return this.table.insertOne(row, ...this._writeArgs
|
|
2621
|
+
return this.table.insertOne(row, ...this._writeArgs);
|
|
2559
2622
|
}
|
|
2560
2623
|
/**
|
|
2561
2624
|
* **PUT /** — fully replaces one or many records matched by primary key.
|
|
@@ -2572,11 +2635,11 @@ let AsDbController = _AsDbController = class AsDbController extends AsDbReadable
|
|
|
2572
2635
|
if (Array.isArray(payload)) {
|
|
2573
2636
|
const rows = await this._writeBody("replaceMany", payload, true);
|
|
2574
2637
|
this._resolveBulkCas(rows, versionColumn);
|
|
2575
|
-
return this.table.bulkReplace(rows, ...this._writeArgs
|
|
2638
|
+
return this.table.bulkReplace(rows, ...this._writeArgs);
|
|
2576
2639
|
}
|
|
2577
2640
|
const row = await this._writeBody("replace", payload, false);
|
|
2578
2641
|
const hadCas = this._resolveCas(row, versionColumn);
|
|
2579
|
-
const result = await this.table.replaceOne(row, ...this._writeArgs
|
|
2642
|
+
const result = await this.table.replaceOne(row, ...this._writeArgs);
|
|
2580
2643
|
if (hadCas && result.matchedCount === 0) throw await this._disambiguateMismatch(row, versionColumn);
|
|
2581
2644
|
return result;
|
|
2582
2645
|
}
|
|
@@ -2593,11 +2656,11 @@ let AsDbController = _AsDbController = class AsDbController extends AsDbReadable
|
|
|
2593
2656
|
if (Array.isArray(payload)) {
|
|
2594
2657
|
const rows = await this._writeBody("updateMany", payload, true);
|
|
2595
2658
|
this._resolveBulkCas(rows, versionColumn);
|
|
2596
|
-
return this.table.bulkUpdate(rows, ...this._writeArgs
|
|
2659
|
+
return this.table.bulkUpdate(rows, ...this._writeArgs);
|
|
2597
2660
|
}
|
|
2598
2661
|
const row = await this._writeBody("update", payload, false);
|
|
2599
2662
|
const hadCas = this._resolveCas(row, versionColumn);
|
|
2600
|
-
const result = await this.table.updateOne(row, ...this._writeArgs
|
|
2663
|
+
const result = await this.table.updateOne(row, ...this._writeArgs);
|
|
2601
2664
|
if (hadCas && result.matchedCount === 0) throw await this._disambiguateMismatch(row, versionColumn);
|
|
2602
2665
|
return result;
|
|
2603
2666
|
}
|
|
@@ -2608,7 +2671,7 @@ let AsDbController = _AsDbController = class AsDbController extends AsDbReadable
|
|
|
2608
2671
|
* but the supplied version is stale (§6.3). Callers throw the result.
|
|
2609
2672
|
*/
|
|
2610
2673
|
async _disambiguateMismatch(data, versionColumn) {
|
|
2611
|
-
const filter = this.table.resolveIdFilter(data);
|
|
2674
|
+
const filter = this.table.resolveIdFilter(data, this._idOpts);
|
|
2612
2675
|
const row = filter ? await this.table.findOne({
|
|
2613
2676
|
filter,
|
|
2614
2677
|
controls: {}
|
|
@@ -3157,8 +3220,11 @@ function isPlainObject$1(value) {
|
|
|
3157
3220
|
//#endregion
|
|
3158
3221
|
//#region src/actions/id-cache.ts
|
|
3159
3222
|
const boundTableKey = key("atscript_db_action_bound_table");
|
|
3223
|
+
function controllerOf(ctx) {
|
|
3224
|
+
return useControllerContext(ctx).getController();
|
|
3225
|
+
}
|
|
3160
3226
|
function controllerTable(ctx) {
|
|
3161
|
-
const ctrl =
|
|
3227
|
+
const ctrl = controllerOf(ctx);
|
|
3162
3228
|
return ctrl?.readable ?? ctrl?.table ?? null;
|
|
3163
3229
|
}
|
|
3164
3230
|
function getActionTable(ctx) {
|
|
@@ -3179,11 +3245,22 @@ function noTableError(ctx) {
|
|
|
3179
3245
|
code: "ACTION_TABLE_NOT_BOUND"
|
|
3180
3246
|
});
|
|
3181
3247
|
}
|
|
3248
|
+
/**
|
|
3249
|
+
* Validates the body's `ids` against the action table's identifications. For
|
|
3250
|
+
* the controller's own table that is its `idSource` (since 0.1.134): a unique
|
|
3251
|
+
* index over a field `hasField` hides neither addresses a row nor appears in
|
|
3252
|
+
* the "must exactly match one of" message. An `opts.table` binding has no
|
|
3253
|
+
* visibility hook.
|
|
3254
|
+
*/
|
|
3182
3255
|
async function resolveValidatedId(ctx, validate) {
|
|
3183
|
-
|
|
3184
|
-
if (!
|
|
3256
|
+
let source = ctx.has(boundTableKey) ? ctx.get(boundTableKey) : void 0;
|
|
3257
|
+
if (!source) {
|
|
3258
|
+
const ctrl = controllerOf(ctx);
|
|
3259
|
+
source = ctrl?.idSource ?? ctrl?.readable ?? ctrl?.table ?? null;
|
|
3260
|
+
}
|
|
3261
|
+
if (!isIdValidationSource(source)) throw noTableError(ctx);
|
|
3185
3262
|
const env = await ctx.get(dbActionBodySlot);
|
|
3186
|
-
validate(env.ids,
|
|
3263
|
+
validate(env.ids, source);
|
|
3187
3264
|
return env.ids;
|
|
3188
3265
|
}
|
|
3189
3266
|
const dbActionIdSlot = cached((ctx) => resolveValidatedId(ctx, validateSingleId));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/moost-db",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.134",
|
|
4
4
|
"description": "Generic database controller for Moost with Atscript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"annotations",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@uniqu/url": "^0.1.10",
|
|
47
|
-
"@atscript/db-memory": "^0.1.
|
|
47
|
+
"@atscript/db-memory": "^0.1.134"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@atscript/core": "^0.1.92",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"@wooksjs/event-core": "^0.7.23",
|
|
65
65
|
"@wooksjs/http-body": "^0.7.23",
|
|
66
66
|
"moost": "^0.6.37",
|
|
67
|
-
"@atscript/db": "^0.1.
|
|
67
|
+
"@atscript/db": "^0.1.134"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
70
|
"postinstall": "asc -f dts",
|