@queryweave/server 0.1.0-alpha.1 → 0.1.0-beta.1

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/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  Web-standard helpers for request-scoped query state.
4
4
 
5
+ ```sh
6
+ pnpm add @queryweave/server
7
+ ```
8
+
5
9
  ```ts
6
10
  import { createQueryUrl, encodeQuery, readRequestQuery, readUrlQuery } from "@queryweave/server";
7
11
 
@@ -13,3 +17,5 @@ createQueryUrl("https://example.test/products", productFilters, values);
13
17
 
14
18
  Every helper is a pure function over `URL` and `Request`. There is no stored state, so request data
15
19
  cannot leak between calls, and no Node.js built-in, browser history, or frontend framework is used.
20
+
21
+ Documentation: https://queryweave-docs.vercel.app/adapters/server/
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ import { DecodeResult, QueryModel, QueryModelValues, QueryParamDefinitions, Quer
7
7
  * navigation, and no framework coupling, so the same helpers work in Node.js, edge, and worker
8
8
  * runtimes.
9
9
  */
10
- /** Base used when a relative URL string is supplied. */
10
+ /** Base used when a relative URL string is supplied to {@link createQueryUrl}. */
11
11
  declare const relativeUrlBase = "http://queryweave.invalid";
12
12
  /** A read-only source backed by a web-standard `Request`. */
13
13
  interface WebRequestQuerySource extends QuerySource {
@@ -29,7 +29,8 @@ declare function encodeQuery<TDefs extends QueryParamDefinitions>(model: QueryMo
29
29
  * Build a URL that carries the model's canonical query.
30
30
  *
31
31
  * Query keys the model does not manage are preserved from `base`, in their original order, after
32
- * the managed keys.
32
+ * the managed keys. Unlike the readers above, this needs a well-formed `base`: a string that is
33
+ * not an absolute URL is resolved against {@link relativeUrlBase}.
33
34
  */
34
35
  declare function createQueryUrl<TDefs extends QueryParamDefinitions>(base: string | URL, model: QueryModel<TDefs>, value: QueryModelValues<TDefs>): URL;
35
36
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;cAqBa;;UAGI,8BAA8B;WACpC,SAAS;;;iBAeJ,aAAa,cAAc,uBACzC,cAAc,KACd,OAAO,WAAW,SACjB,aAAa,iBAAiB;;iBAKX,kBAAkB,cAAc,uBACpD,cAAc,KACd,OAAO,WAAW,SACjB,QAAQ,aAAa,iBAAiB;;iBAKzB,iBAAiB,cAAc,uBAC7C,SAAS,SACT,OAAO,WAAW,SACjB,aAAa,iBAAiB;;iBAKX,sBAAsB,cAAc,uBACxD,SAAS,SACT,OAAO,WAAW,SACjB,QAAQ,aAAa,iBAAiB;;iBAKzB,yBAAyB,SAAS,UAAU;;iBAQ5C,YAAY,cAAc,uBACxC,OAAO,WAAW,QAClB,OAAO,iBAAiB;;;;;;;iBAWV,eAAe,cAAc,uBAC3C,eAAe,KACf,OAAO,WAAW,QAClB,OAAO,iBAAiB,SACvB"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;cAqBa;;UAGI,8BAA8B;WACpC,SAAS;;;iBA+BJ,aAAa,cAAc,uBACzC,cAAc,KACd,OAAO,WAAW,SACjB,aAAa,iBAAiB;;iBAKX,kBAAkB,cAAc,uBACpD,cAAc,KACd,OAAO,WAAW,SACjB,QAAQ,aAAa,iBAAiB;;iBAKzB,iBAAiB,cAAc,uBAC7C,SAAS,SACT,OAAO,WAAW,SACjB,aAAa,iBAAiB;;iBAKX,sBAAsB,cAAc,uBACxD,SAAS,SACT,OAAO,WAAW,SACjB,QAAQ,aAAa,iBAAiB;;iBAKzB,yBAAyB,SAAS,UAAU;;iBAQ5C,YAAY,cAAc,uBACxC,OAAO,WAAW,QAClB,OAAO,iBAAiB;;;;;;;;iBAYV,eAAe,cAAc,uBAC3C,eAAe,KACf,OAAO,WAAW,QAClB,OAAO,iBAAiB,SACvB"}
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import { formatQueryString, normalizeQueryEntries } from "@queryweave/core";
8
8
  * navigation, and no framework coupling, so the same helpers work in Node.js, edge, and worker
9
9
  * runtimes.
10
10
  */
11
- /** Base used when a relative URL string is supplied. */
11
+ /** Base used when a relative URL string is supplied to {@link createQueryUrl}. */
12
12
  const relativeUrlBase = "http://queryweave.invalid";
13
13
  function toUrl(url) {
14
14
  if (typeof url !== "string") return url;
@@ -18,13 +18,26 @@ function toUrl(url) {
18
18
  return new URL(url, relativeUrlBase);
19
19
  }
20
20
  }
21
+ /**
22
+ * The query part of a URL or URL-like string, including its leading `?` when present.
23
+ *
24
+ * Reading does not parse the whole URL: a request line with an unusual host or path still has a
25
+ * perfectly readable query, and a query string is untrusted input that must never throw.
26
+ */
27
+ function searchOf(url) {
28
+ if (typeof url !== "string") return url.search;
29
+ const hash = url.indexOf("#");
30
+ const end = hash === -1 ? url.length : hash;
31
+ const start = url.indexOf("?");
32
+ return start === -1 || start > end ? "" : url.slice(start, end);
33
+ }
21
34
  /** Decode the query of a URL or URL-like string with a model. */
22
35
  function readUrlQuery(url, model) {
23
- return model.decode(toUrl(url).search);
36
+ return model.decode(searchOf(url));
24
37
  }
25
38
  /** Decode the query of a URL or URL-like string, awaiting asynchronous validation. */
26
39
  async function readUrlQueryAsync(url, model) {
27
- return model.decodeAsync(toUrl(url).search);
40
+ return model.decodeAsync(searchOf(url));
28
41
  }
29
42
  /** Decode the query of a web-standard request with a model. */
30
43
  function readRequestQuery(request, model) {
@@ -38,7 +51,7 @@ async function readRequestQueryAsync(request, model) {
38
51
  function createRequestQuerySource(request) {
39
52
  return {
40
53
  request,
41
- read: () => toUrl(request.url).search
54
+ read: () => searchOf(request.url)
42
55
  };
43
56
  }
44
57
  /** Encode typed state into a canonical query string without a leading `?`. */
@@ -49,7 +62,8 @@ function encodeQuery(model, value) {
49
62
  * Build a URL that carries the model's canonical query.
50
63
  *
51
64
  * Query keys the model does not manage are preserved from `base`, in their original order, after
52
- * the managed keys.
65
+ * the managed keys. Unlike the readers above, this needs a well-formed `base`: a string that is
66
+ * not an absolute URL is resolved against {@link relativeUrlBase}.
53
67
  */
54
68
  function createQueryUrl(base, model, value) {
55
69
  const target = new URL(toUrl(base).href);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import {\n formatQueryString,\n normalizeQueryEntries,\n type DecodeResult,\n type QueryEntry,\n type QueryModel,\n type QueryModelValues,\n type QueryOutput,\n type QueryParamDefinitions,\n type QuerySource,\n} from \"@queryweave/core\";\n\n/**\n * Web-standard helpers for request-scoped query state.\n *\n * Everything here is a pure function over `URL` and `Request`. There is no runtime state, no\n * navigation, and no framework coupling, so the same helpers work in Node.js, edge, and worker\n * runtimes.\n */\n\n/** Base used when a relative URL string is supplied. */\nexport const relativeUrlBase = \"http://queryweave.invalid\";\n\n/** A read-only source backed by a web-standard `Request`. */\nexport interface WebRequestQuerySource extends QuerySource {\n readonly request: Request;\n}\n\nfunction toUrl(url: string | URL): URL {\n if (typeof url !== \"string\") {\n return url;\n }\n try {\n return new URL(url);\n } catch {\n return new URL(url, relativeUrlBase);\n }\n}\n\n/** Decode the query of a URL or URL-like string with a model. */\nexport function readUrlQuery<TDefs extends QueryParamDefinitions>(\n url: string | URL,\n model: QueryModel<TDefs>,\n): DecodeResult<QueryModelValues<TDefs>> {\n return model.decode(toUrl(url).search);\n}\n\n/** Decode the query of a URL or URL-like string, awaiting asynchronous validation. */\nexport async function readUrlQueryAsync<TDefs extends QueryParamDefinitions>(\n url: string | URL,\n model: QueryModel<TDefs>,\n): Promise<DecodeResult<QueryModelValues<TDefs>>> {\n return model.decodeAsync(toUrl(url).search);\n}\n\n/** Decode the query of a web-standard request with a model. */\nexport function readRequestQuery<TDefs extends QueryParamDefinitions>(\n request: Request,\n model: QueryModel<TDefs>,\n): DecodeResult<QueryModelValues<TDefs>> {\n return readUrlQuery(request.url, model);\n}\n\n/** Decode the query of a web-standard request, awaiting asynchronous validation. */\nexport async function readRequestQueryAsync<TDefs extends QueryParamDefinitions>(\n request: Request,\n model: QueryModel<TDefs>,\n): Promise<DecodeResult<QueryModelValues<TDefs>>> {\n return readUrlQueryAsync(request.url, model);\n}\n\n/** Create a request-scoped read-only source for a web-standard request. */\nexport function createRequestQuerySource(request: Request): WebRequestQuerySource {\n return {\n request,\n read: () => toUrl(request.url).search,\n };\n}\n\n/** Encode typed state into a canonical query string without a leading `?`. */\nexport function encodeQuery<TDefs extends QueryParamDefinitions>(\n model: QueryModel<TDefs>,\n value: QueryModelValues<TDefs>,\n): string {\n return formatQueryString(model.encode(value));\n}\n\n/**\n * Build a URL that carries the model's canonical query.\n *\n * Query keys the model does not manage are preserved from `base`, in their original order, after\n * the managed keys.\n */\nexport function createQueryUrl<TDefs extends QueryParamDefinitions>(\n base: string | URL,\n model: QueryModel<TDefs>,\n value: QueryModelValues<TDefs>,\n): URL {\n const target = new URL(toUrl(base).href);\n const managedKeys = new Set<string>(model.keys());\n const unmanaged: QueryEntry[] = normalizeQueryEntries(target.search).filter(\n ([key]) => !managedKeys.has(key),\n );\n const output: QueryOutput = [...model.encode(value), ...unmanaged];\n target.search = formatQueryString(output);\n return target;\n}\n"],"mappings":";;;;;;;;;;;AAqBA,MAAa,kBAAkB;AAO/B,SAAS,MAAM,KAAwB;CACrC,IAAI,OAAO,QAAQ,UACjB,OAAO;CAET,IAAI;EACF,OAAO,IAAI,IAAI,GAAG;CACpB,QAAQ;EACN,OAAO,IAAI,IAAI,KAAK,eAAe;CACrC;AACF;;AAGA,SAAgB,aACd,KACA,OACuC;CACvC,OAAO,MAAM,OAAO,MAAM,GAAG,CAAC,CAAC,MAAM;AACvC;;AAGA,eAAsB,kBACpB,KACA,OACgD;CAChD,OAAO,MAAM,YAAY,MAAM,GAAG,CAAC,CAAC,MAAM;AAC5C;;AAGA,SAAgB,iBACd,SACA,OACuC;CACvC,OAAO,aAAa,QAAQ,KAAK,KAAK;AACxC;;AAGA,eAAsB,sBACpB,SACA,OACgD;CAChD,OAAO,kBAAkB,QAAQ,KAAK,KAAK;AAC7C;;AAGA,SAAgB,yBAAyB,SAAyC;CAChF,OAAO;EACL;EACA,YAAY,MAAM,QAAQ,GAAG,CAAC,CAAC;CACjC;AACF;;AAGA,SAAgB,YACd,OACA,OACQ;CACR,OAAO,kBAAkB,MAAM,OAAO,KAAK,CAAC;AAC9C;;;;;;;AAQA,SAAgB,eACd,MACA,OACA,OACK;CACL,MAAM,SAAS,IAAI,IAAI,MAAM,IAAI,CAAC,CAAC,IAAI;CACvC,MAAM,cAAc,IAAI,IAAY,MAAM,KAAK,CAAC;CAChD,MAAM,YAA0B,sBAAsB,OAAO,MAAM,CAAC,CAAC,QAClE,CAAC,SAAS,CAAC,YAAY,IAAI,GAAG,CACjC;CAEA,OAAO,SAAS,kBAAkB,CADL,GAAG,MAAM,OAAO,KAAK,GAAG,GAAG,SACjB,CAAC;CACxC,OAAO;AACT"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import {\n formatQueryString,\n normalizeQueryEntries,\n type DecodeResult,\n type QueryEntry,\n type QueryModel,\n type QueryModelValues,\n type QueryOutput,\n type QueryParamDefinitions,\n type QuerySource,\n} from \"@queryweave/core\";\n\n/**\n * Web-standard helpers for request-scoped query state.\n *\n * Everything here is a pure function over `URL` and `Request`. There is no runtime state, no\n * navigation, and no framework coupling, so the same helpers work in Node.js, edge, and worker\n * runtimes.\n */\n\n/** Base used when a relative URL string is supplied to {@link createQueryUrl}. */\nexport const relativeUrlBase = \"http://queryweave.invalid\";\n\n/** A read-only source backed by a web-standard `Request`. */\nexport interface WebRequestQuerySource extends QuerySource {\n readonly request: Request;\n}\n\nfunction toUrl(url: string | URL): URL {\n if (typeof url !== \"string\") {\n return url;\n }\n try {\n return new URL(url);\n } catch {\n return new URL(url, relativeUrlBase);\n }\n}\n\n/**\n * The query part of a URL or URL-like string, including its leading `?` when present.\n *\n * Reading does not parse the whole URL: a request line with an unusual host or path still has a\n * perfectly readable query, and a query string is untrusted input that must never throw.\n */\nfunction searchOf(url: string | URL): string {\n if (typeof url !== \"string\") {\n return url.search;\n }\n const hash = url.indexOf(\"#\");\n const end = hash === -1 ? url.length : hash;\n const start = url.indexOf(\"?\");\n return start === -1 || start > end ? \"\" : url.slice(start, end);\n}\n\n/** Decode the query of a URL or URL-like string with a model. */\nexport function readUrlQuery<TDefs extends QueryParamDefinitions>(\n url: string | URL,\n model: QueryModel<TDefs>,\n): DecodeResult<QueryModelValues<TDefs>> {\n return model.decode(searchOf(url));\n}\n\n/** Decode the query of a URL or URL-like string, awaiting asynchronous validation. */\nexport async function readUrlQueryAsync<TDefs extends QueryParamDefinitions>(\n url: string | URL,\n model: QueryModel<TDefs>,\n): Promise<DecodeResult<QueryModelValues<TDefs>>> {\n return model.decodeAsync(searchOf(url));\n}\n\n/** Decode the query of a web-standard request with a model. */\nexport function readRequestQuery<TDefs extends QueryParamDefinitions>(\n request: Request,\n model: QueryModel<TDefs>,\n): DecodeResult<QueryModelValues<TDefs>> {\n return readUrlQuery(request.url, model);\n}\n\n/** Decode the query of a web-standard request, awaiting asynchronous validation. */\nexport async function readRequestQueryAsync<TDefs extends QueryParamDefinitions>(\n request: Request,\n model: QueryModel<TDefs>,\n): Promise<DecodeResult<QueryModelValues<TDefs>>> {\n return readUrlQueryAsync(request.url, model);\n}\n\n/** Create a request-scoped read-only source for a web-standard request. */\nexport function createRequestQuerySource(request: Request): WebRequestQuerySource {\n return {\n request,\n read: () => searchOf(request.url),\n };\n}\n\n/** Encode typed state into a canonical query string without a leading `?`. */\nexport function encodeQuery<TDefs extends QueryParamDefinitions>(\n model: QueryModel<TDefs>,\n value: QueryModelValues<TDefs>,\n): string {\n return formatQueryString(model.encode(value));\n}\n\n/**\n * Build a URL that carries the model's canonical query.\n *\n * Query keys the model does not manage are preserved from `base`, in their original order, after\n * the managed keys. Unlike the readers above, this needs a well-formed `base`: a string that is\n * not an absolute URL is resolved against {@link relativeUrlBase}.\n */\nexport function createQueryUrl<TDefs extends QueryParamDefinitions>(\n base: string | URL,\n model: QueryModel<TDefs>,\n value: QueryModelValues<TDefs>,\n): URL {\n const target = new URL(toUrl(base).href);\n const managedKeys = new Set<string>(model.keys());\n const unmanaged: QueryEntry[] = normalizeQueryEntries(target.search).filter(\n ([key]) => !managedKeys.has(key),\n );\n const output: QueryOutput = [...model.encode(value), ...unmanaged];\n target.search = formatQueryString(output);\n return target;\n}\n"],"mappings":";;;;;;;;;;;AAqBA,MAAa,kBAAkB;AAO/B,SAAS,MAAM,KAAwB;CACrC,IAAI,OAAO,QAAQ,UACjB,OAAO;CAET,IAAI;EACF,OAAO,IAAI,IAAI,GAAG;CACpB,QAAQ;EACN,OAAO,IAAI,IAAI,KAAK,eAAe;CACrC;AACF;;;;;;;AAQA,SAAS,SAAS,KAA2B;CAC3C,IAAI,OAAO,QAAQ,UACjB,OAAO,IAAI;CAEb,MAAM,OAAO,IAAI,QAAQ,GAAG;CAC5B,MAAM,MAAM,SAAS,KAAK,IAAI,SAAS;CACvC,MAAM,QAAQ,IAAI,QAAQ,GAAG;CAC7B,OAAO,UAAU,MAAM,QAAQ,MAAM,KAAK,IAAI,MAAM,OAAO,GAAG;AAChE;;AAGA,SAAgB,aACd,KACA,OACuC;CACvC,OAAO,MAAM,OAAO,SAAS,GAAG,CAAC;AACnC;;AAGA,eAAsB,kBACpB,KACA,OACgD;CAChD,OAAO,MAAM,YAAY,SAAS,GAAG,CAAC;AACxC;;AAGA,SAAgB,iBACd,SACA,OACuC;CACvC,OAAO,aAAa,QAAQ,KAAK,KAAK;AACxC;;AAGA,eAAsB,sBACpB,SACA,OACgD;CAChD,OAAO,kBAAkB,QAAQ,KAAK,KAAK;AAC7C;;AAGA,SAAgB,yBAAyB,SAAyC;CAChF,OAAO;EACL;EACA,YAAY,SAAS,QAAQ,GAAG;CAClC;AACF;;AAGA,SAAgB,YACd,OACA,OACQ;CACR,OAAO,kBAAkB,MAAM,OAAO,KAAK,CAAC;AAC9C;;;;;;;;AASA,SAAgB,eACd,MACA,OACA,OACK;CACL,MAAM,SAAS,IAAI,IAAI,MAAM,IAAI,CAAC,CAAC,IAAI;CACvC,MAAM,cAAc,IAAI,IAAY,MAAM,KAAK,CAAC;CAChD,MAAM,YAA0B,sBAAsB,OAAO,MAAM,CAAC,CAAC,QAClE,CAAC,SAAS,CAAC,YAAY,IAAI,GAAG,CACjC;CAEA,OAAO,SAAS,kBAAkB,CADL,GAAG,MAAM,OAAO,KAAK,GAAG,GAAG,SACjB,CAAC;CACxC,OAAO;AACT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@queryweave/server",
3
- "version": "0.1.0-alpha.1",
3
+ "version": "0.1.0-beta.1",
4
4
  "description": "Web-standard server contracts for QueryWeave.",
5
5
  "keywords": [
6
6
  "query",
@@ -38,13 +38,13 @@
38
38
  "provenance": true
39
39
  },
40
40
  "dependencies": {
41
- "@queryweave/core": "0.1.0-alpha.1"
41
+ "@queryweave/core": "0.1.0-beta.1"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@queryweave/typescript-config": "0.0.0"
45
45
  },
46
46
  "engines": {
47
- "node": ">=24.18.0"
47
+ "node": ">=22.12.0"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "tsdown",