@atscript/moost-db 0.1.161 → 0.1.162

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 CHANGED
@@ -88,7 +88,9 @@ const dbErrorCodeToStatus = {
88
88
  DEADLOCK: 503,
89
89
  LOCK_TIMEOUT: 503,
90
90
  SERIALIZATION_FAILURE: 503,
91
- BUCKET_TZ_UNAVAILABLE: 501
91
+ BUCKET_TZ_UNAVAILABLE: 501,
92
+ LOCK_NOT_SUPPORTED: 501,
93
+ ISOLATION_NOT_SUPPORTED: 501
92
94
  };
93
95
  function transformValidationError(error, reply) {
94
96
  const validation = validatorErrorToHttp(error);
@@ -2087,14 +2089,6 @@ function readRequestContext(endpoint, controls, filter) {
2087
2089
  }
2088
2090
  //#endregion
2089
2091
  //#region src/meta/terminal-ref.ts
2090
- const NAV_KEYS = [
2091
- "db.rel.to",
2092
- "db.rel.from",
2093
- "db.rel.via"
2094
- ];
2095
- function isNav(metadata) {
2096
- return NAV_KEYS.some((key) => metadata.has(key));
2097
- }
2098
2092
  /**
2099
2093
  * Resolves a (possibly dotted) prop path against an object type by walking
2100
2094
  * `type.props` one segment at a time. Bails with `undefined` as soon as a hop
@@ -2184,7 +2178,7 @@ function walk(node, def, shallow) {
2184
2178
  for (const [name, prop] of def.type.props) {
2185
2179
  const sProp = sType.props[name];
2186
2180
  if (!sProp) continue;
2187
- if (isNav(prop.metadata)) continue;
2181
+ if ((0, _atscript_db.isNavRelation)(prop)) continue;
2188
2182
  if (prop.ref?.field && sProp.ref && !("type" in sProp.ref.type)) {
2189
2183
  const terminal = resolveTerminalRef(prop);
2190
2184
  if (terminal) {
@@ -2877,7 +2871,7 @@ let AsReadableController = _AsReadableController = class AsReadableController {
2877
2871
  *
2878
2872
  * Annotation whitelist: keeps `meta.*`, `expect.*`, `db.rel.*`, the `db.*`
2879
2873
  * keys the shared db validator plugin reads in db-client (`db.json`,
2880
- * `db.patch.strategy`, `db.default*`, `db.onUpdate.now`, `db.column.version`,
2874
+ * `db.patch.strategy`, `db.default*`, `db.onUpdate.now` / `.inc`, `db.column.version`,
2881
2875
  * `db.column.derived`) and the client-facing `db.http.path` /
2882
2876
  * `db.writeOnly` / `db.sort.nulls`; strips every other `db.*` (table, column, index, etc.).
2883
2877
  * Override in subclass to customise — keep the validator keys, or client
@@ -2891,7 +2885,7 @@ let AsReadableController = _AsReadableController = class AsReadableController {
2891
2885
  key,
2892
2886
  value
2893
2887
  };
2894
- if (key === "db.json" || key === "db.patch.strategy" || key.startsWith("db.default") || key === "db.onUpdate.now" || key === "db.http.path" || key === "db.writeOnly" || key === "db.column.version" || key === "db.column.derived" || key === "db.sort.nulls") return {
2888
+ if (key === "db.json" || key === "db.patch.strategy" || key.startsWith("db.default") || key === "db.onUpdate.now" || key === "db.onUpdate.inc" || key === "db.http.path" || key === "db.writeOnly" || key === "db.column.version" || key === "db.column.derived" || key === "db.sort.nulls") return {
2895
2889
  key,
2896
2890
  value
2897
2891
  };
@@ -7827,10 +7821,13 @@ let AsDbController = _AsDbController = class AsDbController extends AsDbReadable
7827
7821
  /**
7828
7822
  * Runs `fn` inside the bound table's adapter transaction (nested calls
7829
7823
  * join it). For custom actions and routes that need one transaction across
7830
- * several table operations.
7824
+ * several table operations. `opts.isolation` (since 0.1.162) sets the
7825
+ * level of the transaction this call opens — see `TTransactionOptions`.
7826
+ * Inside it, `this.table.findOne(q, { lock: 'update' })` is a locking read
7827
+ * (never reachable from a URL — it is a server-side option only).
7831
7828
  */
7832
- withTransaction(fn) {
7833
- return this.table.getAdapter().withTransaction(fn);
7829
+ withTransaction(fn, opts) {
7830
+ return this.table.getAdapter().withTransaction(fn, opts);
7834
7831
  }
7835
7832
  /** The table write call's trailing options — see {@link _hookArgs}. */
7836
7833
  _writeArgs;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { a as resolveDbSpace, i as provideDbSpace, n as clearDbSpaces, r as closeDbSpaces, t as DEFAULT_DB_SPACE } from "./db-space-registry-fXB8LnGe.cjs";
2
2
  import { TAtscriptAnnotatedType, TAtscriptDataType, TSerializeOptions, TSerializedAnnotatedType, TValidatorOptions, Validator } from "@atscript/typescript/utils";
3
- import { AggregateFn, AtscriptDbReadable, AtscriptDbTable, BucketUnit, FilterExpr, FlatOf, NullsPlacement, TCrudOp, TCrudOp as TCrudOp$1, TCrudPermissions, TCrudPermissions as TCrudPermissions$1, TDbActionInfo, TDbActionInfo as TDbActionInfo$1, TDbActionIntent, TDbActionIntent as TDbActionIntent$1, TDbActionLevel, TDbActionLevel as TDbActionLevel$1, TDbActionProcessor, TDbActionTargetSummary, TDbActionTargetSummary as TDbActionTargetSummary$1, TDbAvailableActions, TDbAvailableActions as TDbAvailableActions$1, TDbFieldMeta, TDbRemoveGuardContext, TDbRemoveGuardContext as TDbRemoveGuardContext$1, TDbWriteAction, TDbWriteAction as TDbWriteAction$1, TDbWriteCheckContext, TDbWriteCheckContext as TDbWriteCheckContext$1, TDbWriteGuardContext, TDbWriteGuardContext as TDbWriteGuardContext$1, TFilterPredicate, TIdResolveOptions, TIdentification, TMetaResponse, TQueryPathOp, TQueryPathOp as TQueryPathOp$1, TQueryPathRefs, TQueryPathSource, Uniquery, UniqueryControls, collectQueryPaths } from "@atscript/db";
3
+ import { AggregateFn, AtscriptDbReadable, AtscriptDbTable, BucketUnit, FilterExpr, FlatOf, NullsPlacement, TCrudOp, TCrudOp as TCrudOp$1, TCrudPermissions, TCrudPermissions as TCrudPermissions$1, TDbActionInfo, TDbActionInfo as TDbActionInfo$1, TDbActionIntent, TDbActionIntent as TDbActionIntent$1, TDbActionLevel, TDbActionLevel as TDbActionLevel$1, TDbActionProcessor, TDbActionTargetSummary, TDbActionTargetSummary as TDbActionTargetSummary$1, TDbAvailableActions, TDbAvailableActions as TDbAvailableActions$1, TDbFieldMeta, TDbRemoveGuardContext, TDbRemoveGuardContext as TDbRemoveGuardContext$1, TDbWriteAction, TDbWriteAction as TDbWriteAction$1, TDbWriteCheckContext, TDbWriteCheckContext as TDbWriteCheckContext$1, TDbWriteGuardContext, TDbWriteGuardContext as TDbWriteGuardContext$1, TFilterPredicate, TIdResolveOptions, TIdentification, TMetaResponse, TQueryPathOp, TQueryPathOp as TQueryPathOp$1, TQueryPathRefs, TQueryPathSource, TTransactionOptions, 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";
@@ -241,7 +241,7 @@ declare abstract class AsReadableController<T extends TAtscriptAnnotatedType = T
241
241
  *
242
242
  * Annotation whitelist: keeps `meta.*`, `expect.*`, `db.rel.*`, the `db.*`
243
243
  * keys the shared db validator plugin reads in db-client (`db.json`,
244
- * `db.patch.strategy`, `db.default*`, `db.onUpdate.now`, `db.column.version`,
244
+ * `db.patch.strategy`, `db.default*`, `db.onUpdate.now` / `.inc`, `db.column.version`,
245
245
  * `db.column.derived`) and the client-facing `db.http.path` /
246
246
  * `db.writeOnly` / `db.sort.nulls`; strips every other `db.*` (table, column, index, etc.).
247
247
  * Override in subclass to customise — keep the validator keys, or client
@@ -2358,9 +2358,12 @@ declare class AsDbController<T extends TAtscriptAnnotatedType = TAtscriptAnnotat
2358
2358
  /**
2359
2359
  * Runs `fn` inside the bound table's adapter transaction (nested calls
2360
2360
  * join it). For custom actions and routes that need one transaction across
2361
- * several table operations.
2361
+ * several table operations. `opts.isolation` (since 0.1.162) sets the
2362
+ * level of the transaction this call opens — see `TTransactionOptions`.
2363
+ * Inside it, `this.table.findOne(q, { lock: 'update' })` is a locking read
2364
+ * (never reachable from a URL — it is a server-side option only).
2362
2365
  */
2363
- protected withTransaction<R>(fn: () => Promise<R>): Promise<R>;
2366
+ protected withTransaction<R>(fn: () => Promise<R>, opts?: TTransactionOptions): Promise<R>;
2364
2367
  /** The table write call's trailing options — see {@link _hookArgs}. */
2365
2368
  private readonly _writeArgs;
2366
2369
  /** `deleteOne`'s trailing options — see {@link _hookArgs}. */
package/dist/index.d.mts CHANGED
@@ -3,7 +3,7 @@ import { TAtscriptAnnotatedType, TAtscriptDataType, TSerializeOptions, TSerializ
3
3
  import { HttpError, MoostHttp } from "@moostjs/event-http";
4
4
  import { Mate, Moost, TConsoleBase, TMateParamMeta, TMoostMetadata } from "moost";
5
5
  import { parseUrl } from "@uniqu/url";
6
- import { AggregateFn, AtscriptDbReadable, AtscriptDbTable, BucketUnit, FilterExpr, FlatOf, NullsPlacement, TCrudOp, TCrudOp as TCrudOp$1, TCrudPermissions, TCrudPermissions as TCrudPermissions$1, TDbActionInfo, TDbActionInfo as TDbActionInfo$1, TDbActionIntent, TDbActionIntent as TDbActionIntent$1, TDbActionLevel, TDbActionLevel as TDbActionLevel$1, TDbActionProcessor, TDbActionTargetSummary, TDbActionTargetSummary as TDbActionTargetSummary$1, TDbAvailableActions, TDbAvailableActions as TDbAvailableActions$1, TDbFieldMeta, TDbRemoveGuardContext, TDbRemoveGuardContext as TDbRemoveGuardContext$1, TDbWriteAction, TDbWriteAction as TDbWriteAction$1, TDbWriteCheckContext, TDbWriteCheckContext as TDbWriteCheckContext$1, TDbWriteGuardContext, TDbWriteGuardContext as TDbWriteGuardContext$1, TFilterPredicate, TIdResolveOptions, TIdentification, TMetaResponse, TQueryPathOp, TQueryPathOp as TQueryPathOp$1, TQueryPathRefs, TQueryPathSource, Uniquery, UniqueryControls, collectQueryPaths } from "@atscript/db";
6
+ import { AggregateFn, AtscriptDbReadable, AtscriptDbTable, BucketUnit, FilterExpr, FlatOf, NullsPlacement, TCrudOp, TCrudOp as TCrudOp$1, TCrudPermissions, TCrudPermissions as TCrudPermissions$1, TDbActionInfo, TDbActionInfo as TDbActionInfo$1, TDbActionIntent, TDbActionIntent as TDbActionIntent$1, TDbActionLevel, TDbActionLevel as TDbActionLevel$1, TDbActionProcessor, TDbActionTargetSummary, TDbActionTargetSummary as TDbActionTargetSummary$1, TDbAvailableActions, TDbAvailableActions as TDbAvailableActions$1, TDbFieldMeta, TDbRemoveGuardContext, TDbRemoveGuardContext as TDbRemoveGuardContext$1, TDbWriteAction, TDbWriteAction as TDbWriteAction$1, TDbWriteCheckContext, TDbWriteCheckContext as TDbWriteCheckContext$1, TDbWriteGuardContext, TDbWriteGuardContext as TDbWriteGuardContext$1, TFilterPredicate, TIdResolveOptions, TIdentification, TMetaResponse, TQueryPathOp, TQueryPathOp as TQueryPathOp$1, TQueryPathRefs, TQueryPathSource, TTransactionOptions, Uniquery, UniqueryControls, collectQueryPaths } from "@atscript/db";
7
7
  import { EventContext } from "@wooksjs/event-core";
8
8
 
9
9
  //#region src/meta/meta-cache.d.ts
@@ -241,7 +241,7 @@ declare abstract class AsReadableController<T extends TAtscriptAnnotatedType = T
241
241
  *
242
242
  * Annotation whitelist: keeps `meta.*`, `expect.*`, `db.rel.*`, the `db.*`
243
243
  * keys the shared db validator plugin reads in db-client (`db.json`,
244
- * `db.patch.strategy`, `db.default*`, `db.onUpdate.now`, `db.column.version`,
244
+ * `db.patch.strategy`, `db.default*`, `db.onUpdate.now` / `.inc`, `db.column.version`,
245
245
  * `db.column.derived`) and the client-facing `db.http.path` /
246
246
  * `db.writeOnly` / `db.sort.nulls`; strips every other `db.*` (table, column, index, etc.).
247
247
  * Override in subclass to customise — keep the validator keys, or client
@@ -2358,9 +2358,12 @@ declare class AsDbController<T extends TAtscriptAnnotatedType = TAtscriptAnnotat
2358
2358
  /**
2359
2359
  * Runs `fn` inside the bound table's adapter transaction (nested calls
2360
2360
  * join it). For custom actions and routes that need one transaction across
2361
- * several table operations.
2361
+ * several table operations. `opts.isolation` (since 0.1.162) sets the
2362
+ * level of the transaction this call opens — see `TTransactionOptions`.
2363
+ * Inside it, `this.table.findOne(q, { lock: 'update' })` is a locking read
2364
+ * (never reachable from a URL — it is a server-side option only).
2362
2365
  */
2363
- protected withTransaction<R>(fn: () => Promise<R>): Promise<R>;
2366
+ protected withTransaction<R>(fn: () => Promise<R>, opts?: TTransactionOptions): Promise<R>;
2364
2367
  /** The table write call's trailing options — see {@link _hookArgs}. */
2365
2368
  private readonly _writeArgs;
2366
2369
  /** `deleteOne`'s trailing options — see {@link _hookArgs}. */
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ import { ValidatorError, defineAnnotatedType, isAnnotatedType, serializeAnnotate
3
3
  import { Body, Delete, Get, HttpError, MoostHttp, Patch, Post, Put, Query, Url, httpKind, prerenderJson } from "@moostjs/event-http";
4
4
  import { ApplyDecorators, Controller, Inherit, Inject, Intercept, Moost, Optional, Param, Pipe, Provide, Resolve, TInterceptorPriority, TPipePriority, current, defineBeforeInterceptor, defineInterceptor, definePipeFn, getMoostMate, useControllerContext, withControllerContext } from "moost";
5
5
  import { parseUrl } from "@uniqu/url";
6
- import { ADAPTER_FILTER_REASON, ALL_AGGREGATE_FNS, DbError, ENCRYPTED_REASON, acceptedOperatorsHint, aliasTargetOf, andFilters, bucketSourceVerdict, canFilterLeaf, checkHavingKeys, classifyQueryPath, collectQueryPaths, collectQueryPaths as collectQueryPaths$1, containsRelationFilter, findAncestorInSet, geoIndexNotFoundMessage, groupSourceVerdict, hasRelationOp, isEmptyObject, isJsonValueField, isPlainObject, isRelationOp, narrowerFilterOps, normalizeComputedSelect, numericOperandProblem, reconcileCas, resolveDesignType, searchIndexNotFoundMessage, searchMemberKind, selfOrAncestor, unsupportedOperatorMessage, vectorIndexNotFoundMessage } from "@atscript/db";
6
+ import { ADAPTER_FILTER_REASON, ALL_AGGREGATE_FNS, DbError, ENCRYPTED_REASON, acceptedOperatorsHint, aliasTargetOf, andFilters, bucketSourceVerdict, canFilterLeaf, checkHavingKeys, classifyQueryPath, collectQueryPaths, collectQueryPaths as collectQueryPaths$1, containsRelationFilter, findAncestorInSet, geoIndexNotFoundMessage, groupSourceVerdict, hasRelationOp, isEmptyObject, isJsonValueField, isNavRelation, isPlainObject, isRelationOp, narrowerFilterOps, normalizeComputedSelect, numericOperandProblem, reconcileCas, resolveDesignType, searchIndexNotFoundMessage, searchMemberKind, selfOrAncestor, unsupportedOperatorMessage, vectorIndexNotFoundMessage } from "@atscript/db";
7
7
  import { cached, current as current$1, defineWook, key, routeParamsKey, useRouteParams } from "@wooksjs/event-core";
8
8
  import { useBody } from "@wooksjs/http-body";
9
9
  import { BUCKET_UNITS } from "@uniqu/core";
@@ -87,7 +87,9 @@ const dbErrorCodeToStatus = {
87
87
  DEADLOCK: 503,
88
88
  LOCK_TIMEOUT: 503,
89
89
  SERIALIZATION_FAILURE: 503,
90
- BUCKET_TZ_UNAVAILABLE: 501
90
+ BUCKET_TZ_UNAVAILABLE: 501,
91
+ LOCK_NOT_SUPPORTED: 501,
92
+ ISOLATION_NOT_SUPPORTED: 501
91
93
  };
92
94
  function transformValidationError(error, reply) {
93
95
  const validation = validatorErrorToHttp(error);
@@ -2086,14 +2088,6 @@ function readRequestContext(endpoint, controls, filter) {
2086
2088
  }
2087
2089
  //#endregion
2088
2090
  //#region src/meta/terminal-ref.ts
2089
- const NAV_KEYS = [
2090
- "db.rel.to",
2091
- "db.rel.from",
2092
- "db.rel.via"
2093
- ];
2094
- function isNav(metadata) {
2095
- return NAV_KEYS.some((key) => metadata.has(key));
2096
- }
2097
2091
  /**
2098
2092
  * Resolves a (possibly dotted) prop path against an object type by walking
2099
2093
  * `type.props` one segment at a time. Bails with `undefined` as soon as a hop
@@ -2183,7 +2177,7 @@ function walk(node, def, shallow) {
2183
2177
  for (const [name, prop] of def.type.props) {
2184
2178
  const sProp = sType.props[name];
2185
2179
  if (!sProp) continue;
2186
- if (isNav(prop.metadata)) continue;
2180
+ if (isNavRelation(prop)) continue;
2187
2181
  if (prop.ref?.field && sProp.ref && !("type" in sProp.ref.type)) {
2188
2182
  const terminal = resolveTerminalRef(prop);
2189
2183
  if (terminal) {
@@ -2876,7 +2870,7 @@ let AsReadableController = _AsReadableController = class AsReadableController {
2876
2870
  *
2877
2871
  * Annotation whitelist: keeps `meta.*`, `expect.*`, `db.rel.*`, the `db.*`
2878
2872
  * keys the shared db validator plugin reads in db-client (`db.json`,
2879
- * `db.patch.strategy`, `db.default*`, `db.onUpdate.now`, `db.column.version`,
2873
+ * `db.patch.strategy`, `db.default*`, `db.onUpdate.now` / `.inc`, `db.column.version`,
2880
2874
  * `db.column.derived`) and the client-facing `db.http.path` /
2881
2875
  * `db.writeOnly` / `db.sort.nulls`; strips every other `db.*` (table, column, index, etc.).
2882
2876
  * Override in subclass to customise — keep the validator keys, or client
@@ -2890,7 +2884,7 @@ let AsReadableController = _AsReadableController = class AsReadableController {
2890
2884
  key,
2891
2885
  value
2892
2886
  };
2893
- if (key === "db.json" || key === "db.patch.strategy" || key.startsWith("db.default") || key === "db.onUpdate.now" || key === "db.http.path" || key === "db.writeOnly" || key === "db.column.version" || key === "db.column.derived" || key === "db.sort.nulls") return {
2887
+ if (key === "db.json" || key === "db.patch.strategy" || key.startsWith("db.default") || key === "db.onUpdate.now" || key === "db.onUpdate.inc" || key === "db.http.path" || key === "db.writeOnly" || key === "db.column.version" || key === "db.column.derived" || key === "db.sort.nulls") return {
2894
2888
  key,
2895
2889
  value
2896
2890
  };
@@ -7824,10 +7818,13 @@ let AsDbController = _AsDbController = class AsDbController extends AsDbReadable
7824
7818
  /**
7825
7819
  * Runs `fn` inside the bound table's adapter transaction (nested calls
7826
7820
  * join it). For custom actions and routes that need one transaction across
7827
- * several table operations.
7821
+ * several table operations. `opts.isolation` (since 0.1.162) sets the
7822
+ * level of the transaction this call opens — see `TTransactionOptions`.
7823
+ * Inside it, `this.table.findOne(q, { lock: 'update' })` is a locking read
7824
+ * (never reachable from a URL — it is a server-side option only).
7828
7825
  */
7829
- withTransaction(fn) {
7830
- return this.table.getAdapter().withTransaction(fn);
7826
+ withTransaction(fn, opts) {
7827
+ return this.table.getAdapter().withTransaction(fn, opts);
7831
7828
  }
7832
7829
  /** The table write call's trailing options — see {@link _hookArgs}. */
7833
7830
  _writeArgs;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/moost-db",
3
- "version": "0.1.161",
3
+ "version": "0.1.162",
4
4
  "description": "Generic database controller for Moost with Atscript.",
5
5
  "keywords": [
6
6
  "annotations",
@@ -44,29 +44,29 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@uniqu/url": "^0.1.15",
47
- "@atscript/db-memory": "^0.1.161"
47
+ "@atscript/db-memory": "^0.1.162"
48
48
  },
49
49
  "devDependencies": {
50
- "@atscript/core": "^0.1.108",
51
- "@atscript/typescript": "^0.1.108",
52
- "@moostjs/event-http": "^0.6.52",
50
+ "@atscript/core": "^0.1.109",
51
+ "@atscript/typescript": "^0.1.109",
52
+ "@moostjs/event-http": "^0.6.53",
53
53
  "@uniqu/core": "^0.1.15",
54
- "@wooksjs/event-core": "^0.7.30",
55
- "@wooksjs/event-http": "^0.7.30",
56
- "@wooksjs/http-body": "^0.7.30",
54
+ "@wooksjs/event-core": "^0.7.31",
55
+ "@wooksjs/event-http": "^0.7.31",
56
+ "@wooksjs/http-body": "^0.7.31",
57
57
  "better-sqlite3": "^12.6.2",
58
- "moost": "^0.6.52",
59
- "unplugin-atscript": "^0.1.108",
60
- "@atscript/db-sqlite": "^0.1.161"
58
+ "moost": "^0.6.53",
59
+ "unplugin-atscript": "^0.1.109",
60
+ "@atscript/db-sqlite": "^0.1.162"
61
61
  },
62
62
  "peerDependencies": {
63
- "@atscript/typescript": "^0.1.108",
64
- "@moostjs/event-http": "^0.6.52",
63
+ "@atscript/typescript": "^0.1.109",
64
+ "@moostjs/event-http": "^0.6.53",
65
65
  "@uniqu/core": "^0.1.15",
66
- "@wooksjs/event-core": "^0.7.30",
67
- "@wooksjs/http-body": "^0.7.30",
68
- "moost": "^0.6.52",
69
- "@atscript/db": "^0.1.161"
66
+ "@wooksjs/event-core": "^0.7.31",
67
+ "@wooksjs/http-body": "^0.7.31",
68
+ "moost": "^0.6.53",
69
+ "@atscript/db": "^0.1.162"
70
70
  },
71
71
  "scripts": {
72
72
  "build": "vp pack",