@atscript/moost-db 0.1.62 → 0.1.63

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
@@ -691,6 +691,42 @@ let AsReadableController = class AsReadableController {
691
691
  const idx = url.indexOf("?");
692
692
  return (0, _uniqu_url.parseUrl)(idx >= 0 ? url.slice(idx + 1) : "");
693
693
  }
694
+ /**
695
+ * Parse a URL keeping only `$*` control keywords; report whether any
696
+ * non-control parts were present. Used by `/one` routes where the
697
+ * uniquery lexer cannot tokenise PK values containing `-` and other
698
+ * reserved chars, so non-control parts must be stripped before lexing.
699
+ * `/one/:id` rejects stray filter params with 400 via `hasNonControl`;
700
+ * `/one` (composite) ignores it because the composite-key params have
701
+ * already been extracted via `@Query()`.
702
+ */
703
+ parseControlsOnlyFromUrl(url) {
704
+ const idx = url.indexOf("?");
705
+ const qs = idx >= 0 ? url.slice(idx + 1) : "";
706
+ if (!qs) return {
707
+ parsed: (0, _uniqu_url.parseUrl)(""),
708
+ hasNonControl: false
709
+ };
710
+ const kept = [];
711
+ let hasNonControl = false;
712
+ for (const part of qs.split("&")) {
713
+ if (!part) continue;
714
+ const eq = part.indexOf("=");
715
+ const rawKey = eq === -1 ? part : part.slice(0, eq);
716
+ let key;
717
+ try {
718
+ key = decodeURIComponent(rawKey);
719
+ } catch {
720
+ key = rawKey;
721
+ }
722
+ if (key.startsWith("$")) kept.push(part);
723
+ else hasNonControl = true;
724
+ }
725
+ return {
726
+ parsed: (0, _uniqu_url.parseUrl)(kept.join("&")),
727
+ hasNonControl
728
+ };
729
+ }
694
730
  async returnOne(result) {
695
731
  const item = await result;
696
732
  if (!item) return new _moostjs_event_http.HttpError(404);
@@ -1298,9 +1334,9 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
1298
1334
  * **GET /one/:id** — retrieves a single record by ID or unique property.
1299
1335
  */
1300
1336
  async getOne(id, url) {
1301
- const parsed = this.parseQueryString(url);
1337
+ const { parsed, hasNonControl } = this.parseControlsOnlyFromUrl(url);
1338
+ if (hasNonControl) return new _moostjs_event_http.HttpError(400, "Filtering is not allowed for \"one\" endpoint");
1302
1339
  this._coerceActionsControl(parsed.controls);
1303
- if (Object.keys(parsed.filter).length > 0) return new _moostjs_event_http.HttpError(400, "Filtering is not allowed for \"one\" endpoint");
1304
1340
  const error = this.validateParsed(parsed, "getOne");
1305
1341
  if (error) return error;
1306
1342
  const rawSelect = await this.transformProjection(parsed.controls.$select);
@@ -1315,7 +1351,7 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
1315
1351
  async getOneComposite(query, url) {
1316
1352
  const idObj = this.extractIdShape(query);
1317
1353
  if (idObj instanceof _moostjs_event_http.HttpError) return idObj;
1318
- const parsed = this.parseQueryString(url);
1354
+ const { parsed } = this.parseControlsOnlyFromUrl(url);
1319
1355
  this._coerceActionsControl(parsed.controls);
1320
1356
  const rawSelect = await this.transformProjection(parsed.controls.$select);
1321
1357
  const select = this.widenPreferredIdProjection(rawSelect);
package/dist/index.d.cts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as _uniqu_url0 from "@uniqu/url";
2
+ import { parseUrl } from "@uniqu/url";
2
3
  import { TAtscriptAnnotatedType, TAtscriptDataType, TSerializeOptions, TSerializedAnnotatedType, Validator } from "@atscript/typescript/utils";
3
4
  import { AtscriptDbReadable, AtscriptDbTable, 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, TIdentification, TMetaResponse, Uniquery, UniqueryControls } from "@atscript/db";
4
5
  import { HttpError } from "@moostjs/event-http";
@@ -106,6 +107,19 @@ declare abstract class AsReadableController<T extends TAtscriptAnnotatedType = T
106
107
  */
107
108
  protected checkGates(filter: FilterExpr | undefined, controls: Record<string, unknown>, gates: ReadableGates): HttpError | undefined;
108
109
  protected parseQueryString(url: string): _uniqu_url0.UrlQuery;
110
+ /**
111
+ * Parse a URL keeping only `$*` control keywords; report whether any
112
+ * non-control parts were present. Used by `/one` routes where the
113
+ * uniquery lexer cannot tokenise PK values containing `-` and other
114
+ * reserved chars, so non-control parts must be stripped before lexing.
115
+ * `/one/:id` rejects stray filter params with 400 via `hasNonControl`;
116
+ * `/one` (composite) ignores it because the composite-key params have
117
+ * already been extracted via `@Query()`.
118
+ */
119
+ protected parseControlsOnlyFromUrl(url: string): {
120
+ parsed: ReturnType<typeof parseUrl>;
121
+ hasNonControl: boolean;
122
+ };
109
123
  protected returnOne(result: Promise<DataType | null>): Promise<DataType | HttpError>;
110
124
  /**
111
125
  * **GET /meta** — returns the bound interface's metadata envelope. The
package/dist/index.d.mts CHANGED
@@ -3,6 +3,7 @@ import { HttpError } from "@moostjs/event-http";
3
3
  import * as moost from "moost";
4
4
  import { Moost, TConsoleBase } from "moost";
5
5
  import * as _uniqu_url0 from "@uniqu/url";
6
+ import { parseUrl } from "@uniqu/url";
6
7
  import { AtscriptDbReadable, AtscriptDbTable, 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, TIdentification, TMetaResponse, Uniquery, UniqueryControls } from "@atscript/db";
7
8
  import * as _wooksjs_event_core0 from "@wooksjs/event-core";
8
9
 
@@ -106,6 +107,19 @@ declare abstract class AsReadableController<T extends TAtscriptAnnotatedType = T
106
107
  */
107
108
  protected checkGates(filter: FilterExpr | undefined, controls: Record<string, unknown>, gates: ReadableGates): HttpError | undefined;
108
109
  protected parseQueryString(url: string): _uniqu_url0.UrlQuery;
110
+ /**
111
+ * Parse a URL keeping only `$*` control keywords; report whether any
112
+ * non-control parts were present. Used by `/one` routes where the
113
+ * uniquery lexer cannot tokenise PK values containing `-` and other
114
+ * reserved chars, so non-control parts must be stripped before lexing.
115
+ * `/one/:id` rejects stray filter params with 400 via `hasNonControl`;
116
+ * `/one` (composite) ignores it because the composite-key params have
117
+ * already been extracted via `@Query()`.
118
+ */
119
+ protected parseControlsOnlyFromUrl(url: string): {
120
+ parsed: ReturnType<typeof parseUrl>;
121
+ hasNonControl: boolean;
122
+ };
109
123
  protected returnOne(result: Promise<DataType | null>): Promise<DataType | HttpError>;
110
124
  /**
111
125
  * **GET /meta** — returns the bound interface's metadata envelope. The
package/dist/index.mjs CHANGED
@@ -690,6 +690,42 @@ let AsReadableController = class AsReadableController {
690
690
  const idx = url.indexOf("?");
691
691
  return parseUrl(idx >= 0 ? url.slice(idx + 1) : "");
692
692
  }
693
+ /**
694
+ * Parse a URL keeping only `$*` control keywords; report whether any
695
+ * non-control parts were present. Used by `/one` routes where the
696
+ * uniquery lexer cannot tokenise PK values containing `-` and other
697
+ * reserved chars, so non-control parts must be stripped before lexing.
698
+ * `/one/:id` rejects stray filter params with 400 via `hasNonControl`;
699
+ * `/one` (composite) ignores it because the composite-key params have
700
+ * already been extracted via `@Query()`.
701
+ */
702
+ parseControlsOnlyFromUrl(url) {
703
+ const idx = url.indexOf("?");
704
+ const qs = idx >= 0 ? url.slice(idx + 1) : "";
705
+ if (!qs) return {
706
+ parsed: parseUrl(""),
707
+ hasNonControl: false
708
+ };
709
+ const kept = [];
710
+ let hasNonControl = false;
711
+ for (const part of qs.split("&")) {
712
+ if (!part) continue;
713
+ const eq = part.indexOf("=");
714
+ const rawKey = eq === -1 ? part : part.slice(0, eq);
715
+ let key;
716
+ try {
717
+ key = decodeURIComponent(rawKey);
718
+ } catch {
719
+ key = rawKey;
720
+ }
721
+ if (key.startsWith("$")) kept.push(part);
722
+ else hasNonControl = true;
723
+ }
724
+ return {
725
+ parsed: parseUrl(kept.join("&")),
726
+ hasNonControl
727
+ };
728
+ }
693
729
  async returnOne(result) {
694
730
  const item = await result;
695
731
  if (!item) return new HttpError(404);
@@ -1297,9 +1333,9 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
1297
1333
  * **GET /one/:id** — retrieves a single record by ID or unique property.
1298
1334
  */
1299
1335
  async getOne(id, url) {
1300
- const parsed = this.parseQueryString(url);
1336
+ const { parsed, hasNonControl } = this.parseControlsOnlyFromUrl(url);
1337
+ if (hasNonControl) return new HttpError(400, "Filtering is not allowed for \"one\" endpoint");
1301
1338
  this._coerceActionsControl(parsed.controls);
1302
- if (Object.keys(parsed.filter).length > 0) return new HttpError(400, "Filtering is not allowed for \"one\" endpoint");
1303
1339
  const error = this.validateParsed(parsed, "getOne");
1304
1340
  if (error) return error;
1305
1341
  const rawSelect = await this.transformProjection(parsed.controls.$select);
@@ -1314,7 +1350,7 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
1314
1350
  async getOneComposite(query, url) {
1315
1351
  const idObj = this.extractIdShape(query);
1316
1352
  if (idObj instanceof HttpError) return idObj;
1317
- const parsed = this.parseQueryString(url);
1353
+ const { parsed } = this.parseControlsOnlyFromUrl(url);
1318
1354
  this._coerceActionsControl(parsed.controls);
1319
1355
  const rawSelect = await this.transformProjection(parsed.controls.$select);
1320
1356
  const select = this.widenPreferredIdProjection(rawSelect);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/moost-db",
3
- "version": "0.1.62",
3
+ "version": "0.1.63",
4
4
  "description": "Generic database controller for Moost with Atscript.",
5
5
  "keywords": [
6
6
  "annotations",
@@ -58,7 +58,7 @@
58
58
  "@wooksjs/event-core": "^0.7.10",
59
59
  "@wooksjs/http-body": "^0.7.10",
60
60
  "moost": "^0.6.8",
61
- "@atscript/db": "^0.1.62"
61
+ "@atscript/db": "^0.1.63"
62
62
  },
63
63
  "scripts": {
64
64
  "postinstall": "asc -f dts",