@open-mercato/shared 0.7.1-develop.7102.1.b41f7e3e51 → 0.7.1-develop.7104.1.1dd769bf1a
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/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +8 -0
- package/dist/lib/crud/factory.js +5 -4
- package/dist/lib/crud/factory.js.map +2 -2
- package/dist/lib/crud/ids.js +6 -3
- package/dist/lib/crud/ids.js.map +2 -2
- package/dist/lib/crud/query-params.js +33 -0
- package/dist/lib/crud/query-params.js.map +7 -0
- package/dist/lib/version.js +1 -1
- package/dist/lib/version.js.map +1 -1
- package/package.json +2 -2
- package/src/lib/crud/__tests__/crud-factory.test.ts +71 -0
- package/src/lib/crud/__tests__/ids.test.ts +29 -0
- package/src/lib/crud/__tests__/query-params.test.ts +98 -0
- package/src/lib/crud/factory.ts +5 -4
- package/src/lib/crud/ids.ts +11 -8
- package/src/lib/crud/query-params.ts +75 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
[build:shared] found
|
|
1
|
+
[build:shared] found 268 entry points
|
|
2
2
|
[build:shared] built successfully
|
package/AGENTS.md
CHANGED
|
@@ -253,6 +253,14 @@ MUST rules:
|
|
|
253
253
|
- `message` is passed through verbatim and is never derived from an entity name — keep routing 404 copy through `translate(...)` so it stays translatable.
|
|
254
254
|
- `assertFound` treats every falsy value as missing. Use it for entity/object lookups only, never to guard numbers or strings where `0`/`''` are valid results.
|
|
255
255
|
|
|
256
|
+
### Query Parameter Parsing — MUST NOT rebuild the query object with `Object.fromEntries`
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import { buildQueryParams, readQueryParamList, toQueryValueList } from '@open-mercato/shared/lib/crud/query-params'
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
`Object.fromEntries(url.searchParams.entries())` keeps only the LAST value of a repeated key, so `?status=win&status=loose` silently becomes `'loose'` (#5548). `buildQueryParams(url.searchParams)` groups instead: a key seen once stays a string, a key seen twice or more becomes `string[]`. It never splits on commas, so `?ids=a,b` and free-text filters keep their literal value. Where a field's contract says a comma separates values, use `readQueryParamList(searchParams, key)` (or `toQueryValueList(raw)` on an already-parsed value) — they treat the repeated and comma forms as equivalent. MUST use these instead of a per-route `getAll` + split + trim copy.
|
|
263
|
+
|
|
256
264
|
### CRUD Multi-ID Filtering
|
|
257
265
|
|
|
258
266
|
- Use `parseIdsParam()` and `mergeIdFilter()` from `@open-mercato/shared/lib/crud/ids` for factory-level `ids` query support.
|
package/dist/lib/crud/factory.js
CHANGED
|
@@ -48,6 +48,7 @@ import { getTranslationOverlayPlugin } from "@open-mercato/shared/lib/localizati
|
|
|
48
48
|
import { applyResponseEnrichers, applyResponseEnricherToRecord, resolveListCacheEnricherPlan } from "./enricher-runner.js";
|
|
49
49
|
import { runApiInterceptorsAfter, runApiInterceptorsBefore } from "./interceptor-runner.js";
|
|
50
50
|
import { mergeIdFilter, parseIdsParam, isIdsParamProvided } from "./ids.js";
|
|
51
|
+
import { buildQueryParams } from "./query-params.js";
|
|
51
52
|
import { mergeAdvancedFilters } from "./advanced-filter-integration.js";
|
|
52
53
|
import { parseExtensionHeaders } from "../umes/extension-headers.js";
|
|
53
54
|
import { createGenericOptimisticLockReader } from "./optimistic-lock.js";
|
|
@@ -991,7 +992,7 @@ function makeCrudRoute(opts) {
|
|
|
991
992
|
return json({ error: "Not implemented" }, { status: 501 });
|
|
992
993
|
}
|
|
993
994
|
const url = new URL(request.url);
|
|
994
|
-
const rawQueryParams =
|
|
995
|
+
const rawQueryParams = buildQueryParams(url.searchParams);
|
|
995
996
|
profiler.mark("query_parsed");
|
|
996
997
|
let validated = opts.list.schema.parse(rawQueryParams);
|
|
997
998
|
profiler.mark("query_validated");
|
|
@@ -2202,7 +2203,7 @@ function makeCrudRoute(opts) {
|
|
|
2202
2203
|
if (useCommand) {
|
|
2203
2204
|
const action = opts.actions.delete;
|
|
2204
2205
|
const body = await request.json().catch(() => ({}));
|
|
2205
|
-
const raw = { body, query:
|
|
2206
|
+
const raw = { body, query: buildQueryParams(url.searchParams) };
|
|
2206
2207
|
const parsed = action.schema ? action.schema.parse(raw) : raw;
|
|
2207
2208
|
const interceptorInput = parsed && typeof parsed === "object" && parsed.body && typeof parsed.body === "object" ? parsed.body : body;
|
|
2208
2209
|
const beforeInterceptors2 = await applyInterceptorsBefore({
|
|
@@ -2218,7 +2219,7 @@ function makeCrudRoute(opts) {
|
|
|
2218
2219
|
const interceptedBody = interceptorRequestPayload.body ?? {};
|
|
2219
2220
|
const reparsedRaw = {
|
|
2220
2221
|
body: interceptedBody,
|
|
2221
|
-
query:
|
|
2222
|
+
query: buildQueryParams(url.searchParams)
|
|
2222
2223
|
};
|
|
2223
2224
|
const reparsed = action.schema ? action.schema.parse(reparsedRaw) : reparsedRaw;
|
|
2224
2225
|
const input = action.mapInput ? await action.mapInput({ parsed: reparsed, raw: reparsedRaw, ctx }) : reparsed;
|
|
@@ -2321,7 +2322,7 @@ function makeCrudRoute(opts) {
|
|
|
2321
2322
|
request,
|
|
2322
2323
|
method: "DELETE",
|
|
2323
2324
|
body: idFrom === "query" ? void 0 : { id },
|
|
2324
|
-
query: idFrom === "query" ?
|
|
2325
|
+
query: idFrom === "query" ? buildQueryParams(url.searchParams) : void 0
|
|
2325
2326
|
});
|
|
2326
2327
|
if (beforeInterceptors.errorResponse) return beforeInterceptors.errorResponse;
|
|
2327
2328
|
interceptorRequestPayload = beforeInterceptors.requestPayload;
|