@querykitjs/web 4.0.0 → 4.1.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@querykitjs/web",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "Frontend query-building for querykit — typed filters, pagination params & URL sync. Zero-dependency; you send the request.",
5
5
  "type": "module",
6
6
  "author": {
@@ -41,12 +41,38 @@
41
41
  "types": "./dist/react/index.d.cts",
42
42
  "default": "./dist/react/index.cjs"
43
43
  }
44
+ },
45
+ "./vue": {
46
+ "import": {
47
+ "types": "./dist/vue/index.d.ts",
48
+ "default": "./dist/vue/index.js"
49
+ },
50
+ "require": {
51
+ "types": "./dist/vue/index.d.cts",
52
+ "default": "./dist/vue/index.cjs"
53
+ }
54
+ },
55
+ "./angular": {
56
+ "import": {
57
+ "types": "./dist/angular/index.d.ts",
58
+ "default": "./dist/angular/index.js"
59
+ },
60
+ "require": {
61
+ "types": "./dist/angular/index.d.cts",
62
+ "default": "./dist/angular/index.cjs"
63
+ }
44
64
  }
45
65
  },
46
66
  "typesVersions": {
47
67
  "*": {
48
68
  "react": [
49
69
  "./dist/react/index.d.ts"
70
+ ],
71
+ "vue": [
72
+ "./dist/vue/index.d.ts"
73
+ ],
74
+ "angular": [
75
+ "./dist/angular/index.d.ts"
50
76
  ]
51
77
  }
52
78
  },
@@ -68,15 +94,24 @@
68
94
  "build": "tsup",
69
95
  "dev": "tsup --watch",
70
96
  "typecheck": "tsc --noEmit",
71
- "test:smoke": "bun run test/smoke.ts",
72
- "test:hook": "bun run test/hook.ts"
97
+ "test:smoke": "bun run test/smoke.ts && bun run test/url-state.ts && bun run test/vue.ts && bun run test/angular.ts && bun run test:real-routers",
98
+ "test:angular": "bun run test/angular.ts",
99
+ "test:real-routers": "bun run test/real-router-react.ts && bun run test/real-router-vue.ts && bun run test/real-router-angular.ts",
100
+ "test:url-state": "bun run test/url-state.ts",
101
+ "test:hook": "bun run test/hook.ts",
102
+ "test:vue": "bun run test/vue.ts"
73
103
  },
74
104
  "dependencies": {
75
- "@querykitjs/core": "^2.0.0"
105
+ "@querykitjs/core": "^2.1.0"
76
106
  },
77
107
  "peerDependencies": {
78
108
  "react": "^18.3 || ^19.2.7",
79
- "react-router": "^7.0 || ^8.0"
109
+ "react-router": "^7.0 || ^8.0",
110
+ "vue": "^3.5",
111
+ "vue-router": "^4.6 || ^5",
112
+ "@angular/core": "^21 || ^22",
113
+ "@angular/router": "^21 || ^22",
114
+ "rxjs": "^7.8"
80
115
  },
81
116
  "peerDependenciesMeta": {
82
117
  "react": {
@@ -84,14 +119,38 @@
84
119
  },
85
120
  "react-router": {
86
121
  "optional": true
122
+ },
123
+ "vue": {
124
+ "optional": true
125
+ },
126
+ "vue-router": {
127
+ "optional": true
128
+ },
129
+ "@angular/core": {
130
+ "optional": true
131
+ },
132
+ "@angular/router": {
133
+ "optional": true
134
+ },
135
+ "rxjs": {
136
+ "optional": true
87
137
  }
88
138
  },
89
139
  "devDependencies": {
140
+ "@angular/common": "22.2.4",
141
+ "@angular/compiler": "22.2.4",
142
+ "@angular/core": "22.2.4",
143
+ "@angular/platform-browser": "22.2.4",
144
+ "@angular/router": "22.2.4",
90
145
  "@types/react": "19.3.0",
91
146
  "@types/react-dom": "19.3.0",
147
+ "happy-dom": "21.0.4",
92
148
  "react": "19.3.1",
93
149
  "react-dom": "19.3.1",
94
- "react-router": "8.5.1"
150
+ "react-router": "8.5.1",
151
+ "rxjs": "7.8.2",
152
+ "vue": "3.5.44",
153
+ "vue-router": "5.4.0"
95
154
  },
96
155
  "keywords": [
97
156
  "querykit",
@@ -102,6 +161,8 @@
102
161
  "url-state",
103
162
  "search-params",
104
163
  "react",
164
+ "vue",
165
+ "angular",
105
166
  "frontend",
106
167
  "typescript"
107
168
  ]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: querykit-web
3
- description: Use when frontend code builds or reads a querykit list request (@querykitjs/web, @querykitjs/web/react) - createRegistry({ adapter }), qk.resource<T>(name), f filters, sort, list / infinite / cursor payloads, withTotal, parseList / parseInfinite / parseCursor, search, adapter-aware with, defineListSchema and URL helpers (readListParams, setPage, setSort), useListParams / useListParamsBase (clamped), fromSearchParams for SSR, query keys, or reading a 400 with isQueryKitError.
3
+ description: Use when frontend code builds or reads a querykit list request (@querykitjs/web, /react, /vue, /angular) - createRegistry({ adapter }), qk.resource<T>(name), f filters, sort, list / infinite / cursor payloads, withTotal, parseList / parseInfinite / parseCursor, search, adapter-aware with, defineListSchema and URL helpers (readListParams, setPage, setSort), useListParams / useListParamsBase (clamped) for React and Vue, injectListParams for Angular, createListState, fromSearchParams for SSR, query keys, or reading a 400 with isQueryKitError.
4
4
  ---
5
5
 
6
6
  ## Safety rules
@@ -15,7 +15,7 @@ description: Use when frontend code builds or reads a querykit list request (@qu
15
15
 
16
16
  ## When to use
17
17
 
18
- - A browser or SSR frontend (React, Next.js, any fetch client) that talks to a querykit backend.
18
+ - A browser or SSR frontend (React, Next.js, Vue, Nuxt, Angular, any fetch client) that talks to a querykit backend.
19
19
  - Building list, infinite-scroll or cursor request bodies, keeping filters in the URL, and caching with TanStack Query or SWR.
20
20
 
21
21
  The package builds the payload only. You send the request yourself.
@@ -33,7 +33,7 @@ interface User {
33
33
  }
34
34
 
35
35
  export const qk = createRegistry({
36
- adapter: "drizzle-pg", // "mongoose" | "drizzle-pg" | "drizzle-sqlite" | "prisma-pg" — types `with` only
36
+ adapter: "drizzle-pg", // "mongoose" | "mongodb" | "drizzle-pg" | "drizzle-sqlite" | "prisma-pg" — types `with` only
37
37
  defaults: { perPage: 20, limit: 20 },
38
38
  timestamps: { createdAt: "createdAt" }, // same name as the backend; the default sort is this field, desc
39
39
  });
@@ -103,6 +103,11 @@ const posts = createRegistry({ adapter: "drizzle-pg" }).resource<{ id: number; t
103
103
  // only relations and columns the backend lists in `relations`
104
104
  const body = posts.list({ with: { author: { columns: { name: true } } }, page: 1 });
105
105
  console.log(body.with);
106
+
107
+ // `@querykitjs/mongodb` loads no relations: `with` is a type error there — fetch the author with a second request
108
+ const comments = createRegistry({ adapter: "mongodb" }).resource<{ _id: string; authorId: string }>("comments");
109
+ const page = comments.list({ page: 1 });
110
+ console.log(page.page);
106
111
  ```
107
112
 
108
113
  ### Filters in the URL
@@ -146,6 +151,61 @@ export function UsersListPage() {
146
151
  }
147
152
  ```
148
153
 
154
+ ### Vue list page with `useListParams`
155
+
156
+ `@querykitjs/web/vue` has the same composables (peers `vue` ^3.5, `vue-router` 4 / 5). `params`, `clamped` and `searchParams` are computed refs; a setter calls `router.push({ query })`.
157
+
158
+ ```ts
159
+ import { createRegistry } from "@querykitjs/web";
160
+ import { useListParams } from "@querykitjs/web/vue";
161
+ import { computed } from "vue";
162
+
163
+ const users = createRegistry({ adapter: "drizzle-pg" }).resource<{ id: number; name: string; status: string }>("users");
164
+ const usersSchema = users.schema({ name: { operation: "%_%", trim: true }, status: { operation: "=" } });
165
+
166
+ // call inside <script setup> or setup()
167
+ export function useUsersList() {
168
+ const { params, clamped, setParam, setPage } = useListParams(users, { schema: usersSchema });
169
+ if (clamped.value) setPage(params.value.page ?? 1); // fix a hand-edited URL
170
+ const queryKey = computed(() => users.keys.list(params.value));
171
+ return { params, queryKey, setName: (name: string) => setParam("name", name) };
172
+ }
173
+ ```
174
+
175
+ ### Angular list page with `injectListParams`
176
+
177
+ `@querykitjs/web/angular` has the same state as signals (peers `@angular/core`, `@angular/router` 21 / 22, `rxjs`). A setter calls `router.navigate`. Call it in an injection context, or Angular throws `NG0203`.
178
+
179
+ ```ts
180
+ import { computed } from "@angular/core";
181
+ import { createRegistry } from "@querykitjs/web";
182
+ import { injectListParams } from "@querykitjs/web/angular";
183
+
184
+ const users = createRegistry({ adapter: "drizzle-pg" }).resource<{ id: number; name: string; status: string }>("users");
185
+ const usersSchema = users.schema({ name: { operation: "%_%", trim: true }, status: { operation: "=" } });
186
+
187
+ // call from a component field initializer or constructor
188
+ export function injectUsersList() {
189
+ const list = injectListParams(users, { schema: usersSchema });
190
+ const queryKey = computed(() => users.keys.list(list.params()));
191
+ return { list, queryKey, setName: (name: string) => list.setParam("name", name) };
192
+ }
193
+ ```
194
+
195
+ ### Any other framework with `createListState`
196
+
197
+ ```ts
198
+ import { createListState, createRegistry } from "@querykitjs/web";
199
+
200
+ const users = createRegistry({ adapter: "prisma-pg" }).resource<{ id: number; name: string }>("users");
201
+ const list = createListState(users, { schema: users.schema({ name: { operation: "%_%" } }) });
202
+
203
+ const current = new URLSearchParams("name=ali&page=3");
204
+ const { params } = list.read(current); // the payload to send
205
+ const next = list.actions(current).setSort([{ key: "name", direction: "asc" }]); // new params, page reset
206
+ history.pushState(null, "", `?${next.toString()}`);
207
+ ```
208
+
149
209
  ### SSR payload and a refused request
150
210
 
151
211
  ```ts