katanakit-js 3.2.2 → 4.0.3
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 +453 -326
- package/dist/adapters/angular/fetch.d.ts +37 -0
- package/dist/adapters/angular/fetch.d.ts.map +1 -0
- package/dist/adapters/angular/fetch.js +67 -0
- package/dist/adapters/angular/fetch.js.map +1 -0
- package/dist/adapters/angular/index.d.ts +5 -0
- package/dist/adapters/angular/index.d.ts.map +1 -0
- package/dist/adapters/angular/index.js +5 -0
- package/dist/adapters/angular/index.js.map +1 -0
- package/dist/adapters/angular/query.d.ts +90 -0
- package/dist/adapters/angular/query.d.ts.map +1 -0
- package/dist/adapters/angular/query.js +103 -0
- package/dist/adapters/angular/query.js.map +1 -0
- package/dist/adapters/angular/watch.d.ts +34 -0
- package/dist/adapters/angular/watch.d.ts.map +1 -0
- package/dist/adapters/angular/watch.js +38 -0
- package/dist/adapters/angular/watch.js.map +1 -0
- package/dist/adapters/assistant/assistant.service.js +1 -1
- package/dist/adapters/assistant/assistant.service.js.map +1 -1
- package/dist/adapters/astro/astro.service.d.ts +0 -1
- package/dist/adapters/astro/astro.service.d.ts.map +1 -1
- package/dist/adapters/astro/astro.service.js +0 -1
- package/dist/adapters/astro/astro.service.js.map +1 -1
- package/dist/adapters/bun/dummyjson.service.d.ts +88 -0
- package/dist/adapters/bun/dummyjson.service.d.ts.map +1 -0
- package/dist/adapters/bun/dummyjson.service.js +149 -0
- package/dist/adapters/bun/dummyjson.service.js.map +1 -0
- package/dist/adapters/bun/index.d.ts +5 -0
- package/dist/adapters/bun/index.d.ts.map +1 -0
- package/dist/adapters/bun/index.js +5 -0
- package/dist/adapters/bun/index.js.map +1 -0
- package/dist/adapters/bun/main.d.ts +2 -0
- package/dist/adapters/bun/main.d.ts.map +1 -0
- package/dist/adapters/bun/main.js +6 -0
- package/dist/adapters/bun/main.js.map +1 -0
- package/dist/adapters/bun/routes.d.ts +62 -0
- package/dist/adapters/bun/routes.d.ts.map +1 -0
- package/dist/adapters/bun/routes.js +60 -0
- package/dist/adapters/bun/routes.js.map +1 -0
- package/dist/adapters/bun/seed.d.ts +65 -0
- package/dist/adapters/bun/seed.d.ts.map +1 -0
- package/dist/adapters/bun/seed.js +117 -0
- package/dist/adapters/bun/seed.js.map +1 -0
- package/dist/adapters/bun/server.d.ts +53 -0
- package/dist/adapters/bun/server.d.ts.map +1 -0
- package/dist/adapters/bun/server.js +64 -0
- package/dist/adapters/bun/server.js.map +1 -0
- package/dist/adapters/express/app.d.ts +2 -1
- package/dist/adapters/express/app.d.ts.map +1 -1
- package/dist/adapters/express/app.js +14 -2
- package/dist/adapters/express/app.js.map +1 -1
- package/dist/adapters/express/products.controller.d.ts.map +1 -1
- package/dist/adapters/express/products.controller.js +3 -1
- package/dist/adapters/express/products.controller.js.map +1 -1
- package/dist/adapters/express/server.js +2 -2
- package/dist/adapters/express/server.js.map +1 -1
- package/dist/adapters/notion/notion.service.d.ts +4 -2
- package/dist/adapters/notion/notion.service.d.ts.map +1 -1
- package/dist/adapters/notion/notion.service.js +19 -5
- package/dist/adapters/notion/notion.service.js.map +1 -1
- package/dist/adapters/react/fetch.d.ts +44 -0
- package/dist/adapters/react/fetch.d.ts.map +1 -0
- package/dist/adapters/react/fetch.js +74 -0
- package/dist/adapters/react/fetch.js.map +1 -0
- package/dist/adapters/react/index.d.ts +5 -0
- package/dist/adapters/react/index.d.ts.map +1 -0
- package/dist/adapters/react/index.js +5 -0
- package/dist/adapters/react/index.js.map +1 -0
- package/dist/adapters/react/query.d.ts +59 -0
- package/dist/adapters/react/query.d.ts.map +1 -0
- package/dist/adapters/react/query.js +86 -0
- package/dist/adapters/react/query.js.map +1 -0
- package/dist/adapters/react/watch.d.ts +37 -0
- package/dist/adapters/react/watch.d.ts.map +1 -0
- package/dist/adapters/react/watch.js +39 -0
- package/dist/adapters/react/watch.js.map +1 -0
- package/dist/adapters/solid/fetch.d.ts +43 -0
- package/dist/adapters/solid/fetch.d.ts.map +1 -0
- package/dist/adapters/solid/fetch.js +72 -0
- package/dist/adapters/solid/fetch.js.map +1 -0
- package/dist/adapters/solid/index.d.ts +5 -0
- package/dist/adapters/solid/index.d.ts.map +1 -0
- package/dist/adapters/solid/index.js +5 -0
- package/dist/adapters/solid/index.js.map +1 -0
- package/dist/adapters/solid/query.d.ts +60 -0
- package/dist/adapters/solid/query.d.ts.map +1 -0
- package/dist/adapters/solid/query.js +88 -0
- package/dist/adapters/solid/query.js.map +1 -0
- package/dist/adapters/solid/watch.d.ts +32 -0
- package/dist/adapters/solid/watch.d.ts.map +1 -0
- package/dist/adapters/solid/watch.js +36 -0
- package/dist/adapters/solid/watch.js.map +1 -0
- package/dist/adapters/svelte/fetch.d.ts +40 -0
- package/dist/adapters/svelte/fetch.d.ts.map +1 -0
- package/dist/adapters/svelte/fetch.js +75 -0
- package/dist/adapters/svelte/fetch.js.map +1 -0
- package/dist/adapters/svelte/index.d.ts +5 -0
- package/dist/adapters/svelte/index.d.ts.map +1 -0
- package/dist/adapters/svelte/index.js +5 -0
- package/dist/adapters/svelte/index.js.map +1 -0
- package/dist/adapters/svelte/query.d.ts +60 -0
- package/dist/adapters/svelte/query.d.ts.map +1 -0
- package/dist/adapters/svelte/query.js +78 -0
- package/dist/adapters/svelte/query.js.map +1 -0
- package/dist/adapters/svelte/watch.d.ts +32 -0
- package/dist/adapters/svelte/watch.d.ts.map +1 -0
- package/dist/adapters/svelte/watch.js +41 -0
- package/dist/adapters/svelte/watch.js.map +1 -0
- package/dist/adapters/telegram/telegram.service.js +1 -1
- package/dist/adapters/telegram/telegram.service.js.map +1 -1
- package/dist/adapters/vanilla/index.d.ts +3 -0
- package/dist/adapters/vanilla/index.d.ts.map +1 -0
- package/dist/adapters/vanilla/index.js +3 -0
- package/dist/adapters/vanilla/index.js.map +1 -0
- package/dist/adapters/vanilla/query.d.ts +69 -0
- package/dist/adapters/vanilla/query.d.ts.map +1 -0
- package/dist/adapters/vanilla/query.js +76 -0
- package/dist/adapters/vanilla/query.js.map +1 -0
- package/dist/adapters/vue/index.d.ts +1 -0
- package/dist/adapters/vue/index.d.ts.map +1 -1
- package/dist/adapters/vue/index.js +1 -0
- package/dist/adapters/vue/index.js.map +1 -1
- package/dist/adapters/vue/query.d.ts +35 -87
- package/dist/adapters/vue/query.d.ts.map +1 -1
- package/dist/adapters/vue/query.js +57 -168
- package/dist/adapters/vue/query.js.map +1 -1
- package/dist/adapters/vue/vue.service.d.ts +9 -5
- package/dist/adapters/vue/vue.service.d.ts.map +1 -1
- package/dist/adapters/vue/vue.service.js +7 -3
- package/dist/adapters/vue/vue.service.js.map +1 -1
- package/dist/adapters/whatsapp/whatsapp.service.js +1 -1
- package/dist/adapters/whatsapp/whatsapp.service.js.map +1 -1
- package/dist/adapters/wordpress/wordpress.service.d.ts +2 -1
- package/dist/adapters/wordpress/wordpress.service.d.ts.map +1 -1
- package/dist/adapters/wordpress/wordpress.service.js +10 -5
- package/dist/adapters/wordpress/wordpress.service.js.map +1 -1
- package/dist/core/services/agent.service.d.ts.map +1 -1
- package/dist/core/services/agent.service.js +9 -1
- package/dist/core/services/agent.service.js.map +1 -1
- package/dist/core/services/dates.service.d.ts.map +1 -1
- package/dist/core/services/dates.service.js +2 -1
- package/dist/core/services/dates.service.js.map +1 -1
- package/dist/core/services/error.service.d.ts +1 -1
- package/dist/core/services/error.service.js +1 -1
- package/dist/core/services/http.service.d.ts +26 -5
- package/dist/core/services/http.service.d.ts.map +1 -1
- package/dist/core/services/http.service.js +30 -6
- package/dist/core/services/http.service.js.map +1 -1
- package/dist/core/services/logger.service.d.ts +10 -67
- package/dist/core/services/logger.service.d.ts.map +1 -1
- package/dist/core/services/logger.service.js +13 -139
- package/dist/core/services/logger.service.js.map +1 -1
- package/dist/core/services/query.service.d.ts +87 -130
- package/dist/core/services/query.service.d.ts.map +1 -1
- package/dist/core/services/query.service.js +99 -366
- package/dist/core/services/query.service.js.map +1 -1
- package/dist/core/services/reactive.service.d.ts.map +1 -1
- package/dist/core/services/reactive.service.js +7 -10
- package/dist/core/services/reactive.service.js.map +1 -1
- package/dist/core/services/timing.service.js +8 -8
- package/dist/core/services/timing.service.js.map +1 -1
- package/dist/core/services/utils.service.d.ts.map +1 -1
- package/dist/core/services/utils.service.js +3 -0
- package/dist/core/services/utils.service.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/dom/dom.service.d.ts.map +1 -1
- package/dist/infrastructure/dom/dom.service.js +18 -4
- package/dist/infrastructure/dom/dom.service.js.map +1 -1
- package/dist/infrastructure/observer/observer.service.js +2 -2
- package/dist/infrastructure/observer/observer.service.js.map +1 -1
- package/dist/infrastructure/sensors/sensors.service.js +6 -6
- package/dist/infrastructure/sensors/sensors.service.js.map +1 -1
- package/dist/infrastructure/storage/storage.service.d.ts.map +1 -1
- package/dist/infrastructure/storage/storage.service.js +12 -2
- package/dist/infrastructure/storage/storage.service.js.map +1 -1
- package/dist/prisma/assistant.store.d.ts +3 -0
- package/dist/prisma/assistant.store.d.ts.map +1 -1
- package/dist/prisma/assistant.store.js +12 -6
- package/dist/prisma/assistant.store.js.map +1 -1
- package/dist/prisma/use-prisma.d.ts +5 -4
- package/dist/prisma/use-prisma.d.ts.map +1 -1
- package/dist/prisma/use-prisma.js +5 -4
- package/dist/prisma/use-prisma.js.map +1 -1
- package/dist/types/index.d.ts +2 -6
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +251 -185
- package/dist/prisma/db.d.ts +0 -4
- package/dist/prisma/db.d.ts.map +0 -1
- package/dist/prisma/db.js +0 -12
- package/dist/prisma/db.js.map +0 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ npm install katanakit-js
|
|
|
9
9
|
# or
|
|
10
10
|
bun add katanakit-js
|
|
11
11
|
# or
|
|
12
|
-
|
|
12
|
+
bun add katanakit-js
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
### CDN (ESM)
|
|
@@ -18,16 +18,16 @@ In the browser, use jsDelivr **`/+esm`** so named exports and dependencies resol
|
|
|
18
18
|
|
|
19
19
|
```html
|
|
20
20
|
<script type="module">
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
import { useLogger, useGetApi, useInitApis } from "https://cdn.jsdelivr.net/npm/katanakit-js/+esm";
|
|
22
|
+
useLogger("ready");
|
|
23
23
|
</script>
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
| CDN
|
|
27
|
-
|
|
28
|
-
| **jsDelivr `/+esm`** (recommended) | `https://cdn.jsdelivr.net/npm/katanakit-js/+esm`
|
|
29
|
-
| **esm.sh**
|
|
30
|
-
| **Raw ESM file**
|
|
26
|
+
| CDN | URL |
|
|
27
|
+
| ---------------------------------- | --------------------------------------------------------------------------------------- |
|
|
28
|
+
| **jsDelivr `/+esm`** (recommended) | `https://cdn.jsdelivr.net/npm/katanakit-js/+esm` |
|
|
29
|
+
| **esm.sh** | `https://esm.sh/katanakit-js` |
|
|
30
|
+
| **Raw ESM file** | `https://cdn.jsdelivr.net/npm/katanakit-js/dist/index.js` (needs bundler or import map) |
|
|
31
31
|
|
|
32
32
|
Pin a version in production (e.g. `@2.14.2/+esm`). There is no IIFE/UMD build.
|
|
33
33
|
|
|
@@ -40,21 +40,21 @@ useLogger("boot");
|
|
|
40
40
|
|
|
41
41
|
// Register your APIs once
|
|
42
42
|
useInitApis({
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
pokeapi: {
|
|
44
|
+
baseUri: "https://pokeapi.co/api/v2",
|
|
45
|
+
endpoints: { pokemonById: "/pokemon/:id/" },
|
|
46
|
+
},
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
// Fetch with Safe Result — no try/catch needed for HTTP failures
|
|
50
50
|
const result = await useGetApi<{ name: string }>("pokeapi", "pokemonById", {
|
|
51
|
-
|
|
51
|
+
params: { id: 25 },
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
if (result.ok) {
|
|
55
|
-
|
|
55
|
+
console.log(result.data.name); // "pikachu"
|
|
56
56
|
} else {
|
|
57
|
-
|
|
57
|
+
console.error(result.error.message);
|
|
58
58
|
}
|
|
59
59
|
```
|
|
60
60
|
|
|
@@ -70,28 +70,28 @@ and returns a **Safe Result** (`{ ok, data, error }`) that never throws on HTTP
|
|
|
70
70
|
import { useInitApis } from "katanakit-js";
|
|
71
71
|
|
|
72
72
|
useInitApis({
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
73
|
+
// A public REST API
|
|
74
|
+
jsonplaceholder: {
|
|
75
|
+
baseUri: "https://jsonplaceholder.typicode.com",
|
|
76
|
+
endpoints: {
|
|
77
|
+
posts: "/posts",
|
|
78
|
+
postById: "/posts/:id",
|
|
79
|
+
},
|
|
80
|
+
// Applied automatically to specific endpoints (overridable per-call)
|
|
81
|
+
defaultQueryParams: {
|
|
82
|
+
posts: { _limit: 10 },
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
// Your own backend
|
|
87
|
+
myApi: {
|
|
88
|
+
baseUri: "https://api.myapp.com/v1",
|
|
89
|
+
endpoints: {
|
|
90
|
+
users: "/users",
|
|
91
|
+
userById: "/users/:id",
|
|
92
|
+
createUser: "/users",
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
95
|
});
|
|
96
96
|
```
|
|
97
97
|
|
|
@@ -106,13 +106,13 @@ if (list.ok) console.log(list.data);
|
|
|
106
106
|
|
|
107
107
|
// Read by ID — :id is replaced by params
|
|
108
108
|
const post = await useGetApi<{ title: string }>("jsonplaceholder", "postById", {
|
|
109
|
-
|
|
109
|
+
params: { id: 1 },
|
|
110
110
|
});
|
|
111
111
|
if (post.ok) console.log(post.data.title);
|
|
112
112
|
|
|
113
113
|
// Override default query params
|
|
114
114
|
const filtered = await useGetApi("jsonplaceholder", "posts", {
|
|
115
|
-
|
|
115
|
+
query: { _limit: 5, userId: 1 },
|
|
116
116
|
});
|
|
117
117
|
```
|
|
118
118
|
|
|
@@ -123,8 +123,8 @@ import { usePost, usePut, usePatch, useDelete } from "katanakit-js";
|
|
|
123
123
|
|
|
124
124
|
// POST — body is auto-serialized to JSON
|
|
125
125
|
const created = await usePost<{ id: number }>("myApi", "createUser", {
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
name: "Alice",
|
|
127
|
+
email: "alice@example.com",
|
|
128
128
|
});
|
|
129
129
|
|
|
130
130
|
// PUT — full replacement (body + path params)
|
|
@@ -143,10 +143,10 @@ There's no global interceptor — pass `headers` directly. This keeps things exp
|
|
|
143
143
|
|
|
144
144
|
```ts
|
|
145
145
|
const result = await useFetch("myApi", "users", {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
146
|
+
method: "GET",
|
|
147
|
+
headers: {
|
|
148
|
+
Authorization: `Bearer ${getToken()}`,
|
|
149
|
+
},
|
|
150
150
|
});
|
|
151
151
|
```
|
|
152
152
|
|
|
@@ -158,27 +158,82 @@ Every fetch returns `{ ok, data, error, status, url }`. No try/catch needed for
|
|
|
158
158
|
const result = await useGetApi("myApi", "userById", { params: { id: 99999 } });
|
|
159
159
|
|
|
160
160
|
if (result.ok) {
|
|
161
|
-
|
|
162
|
-
|
|
161
|
+
// result.data is typed
|
|
162
|
+
console.log(result.data);
|
|
163
163
|
} else {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
164
|
+
// result.error is always structured
|
|
165
|
+
console.log(result.error.status); // 404
|
|
166
|
+
console.log(result.error.message); // "HTTP Error: Not Found"
|
|
167
|
+
console.log(result.error.details); // parsed response body (if any)
|
|
168
|
+
console.log(result.url); // the URL that was called
|
|
169
169
|
}
|
|
170
170
|
```
|
|
171
171
|
|
|
172
172
|
### 6. Build URLs without fetching
|
|
173
173
|
|
|
174
|
+
`useBuildUrl` constructs a full URL from your registered APIs **without making
|
|
175
|
+
a request**. Use it to generate links, image sources, or pass URLs to libraries
|
|
176
|
+
that handle their own fetching.
|
|
177
|
+
|
|
178
|
+
#### Generate navigation links
|
|
179
|
+
|
|
174
180
|
```ts
|
|
175
181
|
import { useBuildUrl } from "katanakit-js";
|
|
176
182
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
query: {
|
|
183
|
+
// Build a download link
|
|
184
|
+
const downloadUrl = useBuildUrl("myApi", "export", {
|
|
185
|
+
query: { format: "pdf", lang: "es" },
|
|
186
|
+
});
|
|
187
|
+
// → "https://api.myapp.com/v1/export?format=pdf&lang=es"
|
|
188
|
+
|
|
189
|
+
// Use in a template
|
|
190
|
+
<a href={downloadUrl}>Download PDF</a>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
#### Generate image/file URLs
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
// Build an image URL for <img src>
|
|
197
|
+
const avatarUrl = useBuildUrl("myApi", "userAvatar", {
|
|
198
|
+
params: { id: 42 },
|
|
199
|
+
query: { size: "large" },
|
|
200
|
+
});
|
|
201
|
+
// → "https://api.myapp.com/v1/users/42/avatar?size=large"
|
|
202
|
+
|
|
203
|
+
<img src={avatarUrl} alt="User avatar" />
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
#### Pass to third-party libraries
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
// Charts, maps, analytics — libraries that fetch their own data
|
|
210
|
+
const chartDataUrl = useBuildUrl("myApi", "analytics", {
|
|
211
|
+
query: { range: "7d", metric: "visits" },
|
|
212
|
+
});
|
|
213
|
+
new Chart(canvas, { data: chartDataUrl });
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### Debug before fetching
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
// See the full URL before making the request
|
|
220
|
+
console.log(
|
|
221
|
+
"Will fetch:",
|
|
222
|
+
useBuildUrl("myApi", "users", {
|
|
223
|
+
query: { page: 1, per_page: 20 },
|
|
224
|
+
}),
|
|
225
|
+
);
|
|
226
|
+
// → "https://api.myapp.com/v1/users?page=1&per_page=20"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### SSR: construct URLs server-side
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
// In Astro, Next.js, or Nuxt server code
|
|
233
|
+
const apiUrl = useBuildUrl("notion", "database", {
|
|
234
|
+
params: { id: "db-123" },
|
|
180
235
|
});
|
|
181
|
-
//
|
|
236
|
+
// Pass to client component or pre-render
|
|
182
237
|
```
|
|
183
238
|
|
|
184
239
|
### 7. FormData and raw bodies
|
|
@@ -201,43 +256,42 @@ against a real API (JSONPlaceholder).
|
|
|
201
256
|
|
|
202
257
|
## QueryClient — Cached Data Fetching
|
|
203
258
|
|
|
204
|
-
The
|
|
205
|
-
|
|
206
|
-
`
|
|
259
|
+
The query layer is powered by **TanStack Query Core**, bundled as a dependency —
|
|
260
|
+
install `katanakit-js` and the engine comes with it. KatanaKit re-exports the full
|
|
261
|
+
`@tanstack/query-core` API and adds framework bindings plus a bridge for the
|
|
262
|
+
Safe Result pattern.
|
|
207
263
|
|
|
208
264
|
```ts
|
|
209
|
-
import {
|
|
265
|
+
import { useQueryClient, useInitQueryClient, useSafeQueryFn } from "katanakit-js";
|
|
210
266
|
import { useGetApi } from "katanakit-js";
|
|
211
267
|
|
|
212
|
-
//
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
// Fetch with cache, stale-while-revalidate, retry, and dedup.
|
|
216
|
-
const pokemon = await qc.fetchQuery<Pokemon>({
|
|
217
|
-
queryKey: ["pokemon", 25],
|
|
218
|
-
queryFn: () => useGetApi<Pokemon>("pokeapi", "pokemonById", { params: { id: 25 } }),
|
|
219
|
-
staleTime: 60_000, // Cache is fresh for 60s.
|
|
220
|
-
retry: 3, // Retry 3 times on failure.
|
|
221
|
-
refetchOnWindowFocus: true,
|
|
268
|
+
// Configure the shared client once (defaults for every query).
|
|
269
|
+
useInitQueryClient({
|
|
270
|
+
defaultOptions: { queries: { staleTime: 60_000, retry: 2 } },
|
|
222
271
|
});
|
|
272
|
+
|
|
273
|
+
// Access it anywhere to invalidate, prefetch, or set data.
|
|
274
|
+
const qc = useQueryClient();
|
|
275
|
+
await qc.invalidateQueries({ queryKey: ["pokemon"] });
|
|
223
276
|
```
|
|
224
277
|
|
|
225
278
|
### Vue composables
|
|
226
279
|
|
|
227
280
|
```vue
|
|
228
281
|
<script setup>
|
|
229
|
-
import { useQuery, useMutation, useQueryClient } from "katanakit-js/adapters/vue";
|
|
282
|
+
import { useQuery, useMutation, useQueryClient, useSafeQueryFn } from "katanakit-js/adapters/vue";
|
|
230
283
|
import { useGetApi, usePost } from "katanakit-js";
|
|
231
284
|
|
|
232
285
|
const qc = useQueryClient();
|
|
233
286
|
|
|
234
|
-
const
|
|
235
|
-
queryKey:
|
|
236
|
-
queryFn: () => useGetApi<User[]>("myApi", "users"),
|
|
287
|
+
const query = useQuery({
|
|
288
|
+
queryKey: ["users"],
|
|
289
|
+
queryFn: useSafeQueryFn(() => useGetApi<User[]>("myApi", "users")),
|
|
237
290
|
staleTime: 30_000,
|
|
238
291
|
});
|
|
292
|
+
// query.data, query.isPending, query.isFetching, query.error, query.status…
|
|
239
293
|
|
|
240
|
-
const
|
|
294
|
+
const mutation = useMutation({
|
|
241
295
|
mutationFn: (name: string) => usePost("myApi", "createUser", { name }),
|
|
242
296
|
onSuccess: () => qc.invalidateQueries({ queryKey: ["users"] }),
|
|
243
297
|
});
|
|
@@ -286,6 +340,27 @@ when you want sessions, persistence, and channels (REST, Telegram, WhatsApp). Fa
|
|
|
286
340
|
follow the Safe Result pattern: they **never throw**. Check `result.ok` and read `result.data`
|
|
287
341
|
or `result.error`.
|
|
288
342
|
|
|
343
|
+
### When to use Kitt
|
|
344
|
+
|
|
345
|
+
Kitt is a **lightweight, zero-dependency** wrapper for OpenAI-compatible APIs.
|
|
346
|
+
Use it when you need:
|
|
347
|
+
|
|
348
|
+
- **One-shot chat** — ask a question, get an answer (`useChat`)
|
|
349
|
+
- **Tool-calling agents** — autonomous loops that read/write/run (`useRunAgent`)
|
|
350
|
+
- **Session-aware bots** — REST, Telegram, WhatsApp channels (`useReply`)
|
|
351
|
+
|
|
352
|
+
### When to use alternatives
|
|
353
|
+
|
|
354
|
+
| Need | Use instead |
|
|
355
|
+
| ------------------------- | --------------------------------------------- |
|
|
356
|
+
| Streaming token-by-token | [Vercel AI SDK](https://sdk.vercel.ai) |
|
|
357
|
+
| RAG with embeddings | [LangChain.js](https://js.langchain.com) |
|
|
358
|
+
| Multi-agent orchestration | [CrewAI](https://github.com/crewAIInc/crewAI) |
|
|
359
|
+
| Full chatbot framework | [Botpress](https://botpress.com) |
|
|
360
|
+
|
|
361
|
+
Kitt stays small (0 dependencies) because it does one thing well:
|
|
362
|
+
**chat completions with tool calls, using any OpenAI-compatible endpoint.**
|
|
363
|
+
|
|
289
364
|
### Low-level API
|
|
290
365
|
|
|
291
366
|
```ts
|
|
@@ -297,21 +372,21 @@ useInitAgent({ model: "qwen3.8-max" });
|
|
|
297
372
|
|
|
298
373
|
// Assistant — single-shot review / question.
|
|
299
374
|
const review = await useChat([
|
|
300
|
-
|
|
375
|
+
{ role: "user", content: "Summarize the benefits of solar energy in three bullet points." },
|
|
301
376
|
]);
|
|
302
377
|
if (review.ok) console.log(review.data);
|
|
303
378
|
|
|
304
379
|
// Agent — autonomous tool-calling loop that can act (read/write/run).
|
|
305
380
|
const result = await useRunAgent("Fix the type errors in src/", {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
381
|
+
tools: [
|
|
382
|
+
{
|
|
383
|
+
name: "readFile",
|
|
384
|
+
description: "Returns file contents",
|
|
385
|
+
parameters: { type: "object", properties: { path: { type: "string" } } },
|
|
386
|
+
execute: ({ path }) => fs.readFile(path, "utf8"),
|
|
387
|
+
},
|
|
388
|
+
],
|
|
389
|
+
maxSteps: 12,
|
|
315
390
|
});
|
|
316
391
|
```
|
|
317
392
|
|
|
@@ -331,20 +406,20 @@ import "dotenv/config";
|
|
|
331
406
|
import { useInitAssistant, useReply } from "katanakit-js";
|
|
332
407
|
|
|
333
408
|
useInitAssistant({
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
409
|
+
// apiKey — process.env.DASHSCOPE_API_KEY
|
|
410
|
+
// baseUrl — KITT_BASE_URL
|
|
411
|
+
// model — "qwen3.8-max"
|
|
412
|
+
// systemPrompt — KITT_SYSTEM_PROMPT
|
|
413
|
+
// store — in-memory (useCreateMemoryStore)
|
|
414
|
+
// tools — AiTool[]
|
|
415
|
+
// maxSteps — number
|
|
341
416
|
});
|
|
342
417
|
|
|
343
418
|
const result = await useReply(undefined, "What are your hours?");
|
|
344
419
|
if (result.ok) {
|
|
345
|
-
|
|
420
|
+
console.log(result.data.reply, result.data.sessionId);
|
|
346
421
|
} else {
|
|
347
|
-
|
|
422
|
+
console.error(result.error.message);
|
|
348
423
|
}
|
|
349
424
|
```
|
|
350
425
|
|
|
@@ -353,12 +428,12 @@ if (result.ok) {
|
|
|
353
428
|
|
|
354
429
|
Also on the main barrel:
|
|
355
430
|
|
|
356
|
-
| Helper
|
|
357
|
-
|
|
358
|
-
| `useCreateSession`
|
|
359
|
-
| `useGetHistory`
|
|
360
|
-
| `useResetSession`
|
|
361
|
-
| `useCreateMemoryStore` | `() => ConversationStore`
|
|
431
|
+
| Helper | Signature |
|
|
432
|
+
| ---------------------- | ------------------------------------- |
|
|
433
|
+
| `useCreateSession` | `(channel?) => Promise<string>` |
|
|
434
|
+
| `useGetHistory` | `(sessionId) => Promise<AiMessage[]>` |
|
|
435
|
+
| `useResetSession` | `(sessionId) => Promise<void>` |
|
|
436
|
+
| `useCreateMemoryStore` | `() => ConversationStore` |
|
|
362
437
|
|
|
363
438
|
Then start a channel (see below). Copy keys from [`.env.example`](https://github.com/senseikatana/katanakit-js/blob/main/.env.example):
|
|
364
439
|
|
|
@@ -377,12 +452,12 @@ DATABASE_URL=
|
|
|
377
452
|
|
|
378
453
|
### Run standalone (this repo)
|
|
379
454
|
|
|
380
|
-
| Script
|
|
381
|
-
|
|
382
|
-
| `
|
|
383
|
-
| `
|
|
384
|
-
| `
|
|
385
|
-
| `
|
|
455
|
+
| Script | Starts |
|
|
456
|
+
| ------------------------ | --------------------------------------------------------------------------- |
|
|
457
|
+
| `bun run assistant:dev` | REST assistant. Uses Prisma when `DATABASE_URL` is set. |
|
|
458
|
+
| `bun run telegram:dev` | Telegram long polling. Requires `TELEGRAM_BOT_TOKEN`. |
|
|
459
|
+
| `bun run whatsapp:dev` | WhatsApp webhook. Requires `WHATSAPP_*`. |
|
|
460
|
+
| `bun run assistant:demo` | Demo in `examples/assistant/`. Set `KITT_CHANNEL=rest\|telegram\|whatsapp`. |
|
|
386
461
|
|
|
387
462
|
### REST
|
|
388
463
|
|
|
@@ -393,21 +468,21 @@ useStartAssistant(); // port?, host?, mountPath = "/assistant", options?
|
|
|
393
468
|
// or mount useCreateAssistantRouter() on an existing Express app
|
|
394
469
|
```
|
|
395
470
|
|
|
396
|
-
| Method
|
|
397
|
-
|
|
398
|
-
| `POST`
|
|
399
|
-
| `GET`
|
|
400
|
-
| `DELETE` | `/assistant/sessions/:id` | —
|
|
471
|
+
| Method | Path | Body | Response |
|
|
472
|
+
| -------- | ------------------------- | ------------------------- | ------------------------------------------- |
|
|
473
|
+
| `POST` | `/assistant/chat` | `{ sessionId?, message }` | `{ ok, data: { reply, sessionId }, error }` |
|
|
474
|
+
| `GET` | `/assistant/sessions/:id` | — | `{ sessionId, messages }` or `404` |
|
|
475
|
+
| `DELETE` | `/assistant/sessions/:id` | — | `204` or `404` |
|
|
401
476
|
|
|
402
477
|
The endpoints are **public by default**. In production pass an auth guard (applied to every
|
|
403
478
|
route). Unknown session ids return `404`, and `useReply` rejects a `sessionId` that does not exist.
|
|
404
479
|
|
|
405
480
|
```ts
|
|
406
481
|
useStartAssistant(3000, "localhost", "/assistant", {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
482
|
+
guard: (req, res, next) =>
|
|
483
|
+
req.header("authorization") === `Bearer ${process.env.ASSISTANT_API_KEY}`
|
|
484
|
+
? next()
|
|
485
|
+
: res.status(401).end(),
|
|
411
486
|
});
|
|
412
487
|
```
|
|
413
488
|
|
|
@@ -422,9 +497,12 @@ curl -X POST http://localhost:3000/assistant/chat \
|
|
|
422
497
|
POST `/chat` and POST `/whatsapp/webhook` are rate-limited by default (20 req/min and 60 req/min per IP). Override via the router options:
|
|
423
498
|
|
|
424
499
|
```ts
|
|
425
|
-
app.use(
|
|
426
|
-
|
|
427
|
-
|
|
500
|
+
app.use(
|
|
501
|
+
"/assistant",
|
|
502
|
+
useCreateAssistantRouter({
|
|
503
|
+
rateLimit: rateLimit({ windowMs: 60_000, max: 30 }),
|
|
504
|
+
}),
|
|
505
|
+
);
|
|
428
506
|
```
|
|
429
507
|
|
|
430
508
|
### Telegram (BotFather)
|
|
@@ -442,7 +520,7 @@ await useStartTelegramPolling();
|
|
|
442
520
|
2. Send `/newbot` — choose a name and a username.
|
|
443
521
|
3. Copy the token.
|
|
444
522
|
4. Set `TELEGRAM_BOT_TOKEN`.
|
|
445
|
-
5. Run `
|
|
523
|
+
5. Run `bun run telegram:dev` (long polling, no public URL).
|
|
446
524
|
6. Optional webhook: expose HTTPS and call `useHandleTelegramUpdate(update)` on inbound updates.
|
|
447
525
|
|
|
448
526
|
### WhatsApp (Meta Cloud API)
|
|
@@ -453,10 +531,10 @@ Webhook: `GET` / `POST` `/whatsapp/webhook`. Session ids are `wa:<phone>`.
|
|
|
453
531
|
import { useInitWhatsApp, useStartWhatsApp } from "katanakit-js/adapters/whatsapp";
|
|
454
532
|
|
|
455
533
|
useInitWhatsApp({
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
534
|
+
token: process.env.WHATSAPP_TOKEN,
|
|
535
|
+
phoneNumberId: process.env.WHATSAPP_PHONE_NUMBER_ID,
|
|
536
|
+
verifyToken: process.env.WHATSAPP_VERIFY_TOKEN,
|
|
537
|
+
appSecret: process.env.WHATSAPP_APP_SECRET,
|
|
460
538
|
});
|
|
461
539
|
useStartWhatsApp();
|
|
462
540
|
```
|
|
@@ -465,7 +543,7 @@ useStartWhatsApp();
|
|
|
465
543
|
2. Add the WhatsApp product.
|
|
466
544
|
3. Copy the temporary or permanent token, the Phone number ID, and the **App Secret**.
|
|
467
545
|
4. Set `WHATSAPP_TOKEN`, `WHATSAPP_PHONE_NUMBER_ID`, `WHATSAPP_VERIFY_TOKEN`, and `WHATSAPP_APP_SECRET`.
|
|
468
|
-
5. Run `
|
|
546
|
+
5. Run `bun run whatsapp:dev`.
|
|
469
547
|
6. Expose public HTTPS (Cloudflare Tunnel or ngrok) to `GET`/`POST` `/whatsapp/webhook`.
|
|
470
548
|
7. In Meta, set the webhook URL and verify token; subscribe to `messages`.
|
|
471
549
|
|
|
@@ -500,7 +578,7 @@ owns the database, run `prisma contract emit` then `prisma db init` in that app.
|
|
|
500
578
|
`readFile` on `knowledge-base.md` and `saveNote` to `notes.jsonl`.
|
|
501
579
|
|
|
502
580
|
```bash
|
|
503
|
-
|
|
581
|
+
bun run assistant:demo
|
|
504
582
|
# KITT_CHANNEL=rest|telegram|whatsapp
|
|
505
583
|
```
|
|
506
584
|
|
|
@@ -540,39 +618,39 @@ const result = await useGetApi("pokeapi", "pokemonById", { params: { id: 25 } })
|
|
|
540
618
|
|
|
541
619
|
```ts
|
|
542
620
|
import { useLogger, useInitApis, useGetApi } from "katanakit-js";
|
|
543
|
-
import {
|
|
544
|
-
import { useUnwrap } from "katanakit-js/adapters/nuxt";
|
|
621
|
+
import { useRequest } from "katanakit-js/adapters/vue"; // Vue only
|
|
622
|
+
import { useUnwrap } from "katanakit-js/adapters/nuxt"; // Nuxt only
|
|
545
623
|
```
|
|
546
624
|
|
|
547
625
|
```html
|
|
548
626
|
<!-- vanilla -->
|
|
549
627
|
<script type="module">
|
|
550
|
-
|
|
628
|
+
import { useLogger } from "https://cdn.jsdelivr.net/npm/katanakit-js/+esm";
|
|
551
629
|
</script>
|
|
552
630
|
```
|
|
553
631
|
|
|
554
|
-
See [Getting Started](https://senseikatana.com/
|
|
632
|
+
See [Getting Started](https://docs.senseikatana.com/docs/guides/getting-started/) for full recipes.
|
|
555
633
|
|
|
556
634
|
## Framework Adapters
|
|
557
635
|
|
|
558
|
-
| Adapter
|
|
559
|
-
|
|
560
|
-
| **Express**
|
|
561
|
-
| **Nuxt**
|
|
562
|
-
| **Vue**
|
|
563
|
-
| **Astro**
|
|
564
|
-
| **Assistant** | `katanakit-js/adapters/assistant`
|
|
565
|
-
| **Telegram**
|
|
566
|
-
| **WhatsApp**
|
|
636
|
+
| Adapter | Import | Description |
|
|
637
|
+
| ------------- | ----------------------------------------------- | ------------------------------------------------------------ |
|
|
638
|
+
| **Express** | `katanakit-js/adapters/express` | Reference server with CORS and hardened headers |
|
|
639
|
+
| **Nuxt** | `katanakit-js/adapters/nuxt` | `useUnwrap`, `useSafeResponse`, `useEventResponse` |
|
|
640
|
+
| **Vue** | `katanakit-js/adapters/vue` | `useRequest` composable with reactivity |
|
|
641
|
+
| **Astro** | `katanakit-js` or `katanakit-js/adapters/astro` | `AstroService`, `RssService` |
|
|
642
|
+
| **Assistant** | `katanakit-js/adapters/assistant` | REST digital assistant (`useStartAssistant`) |
|
|
643
|
+
| **Telegram** | `katanakit-js/adapters/telegram` | BotFather bot (`useInitTelegram`, `useStartTelegramPolling`) |
|
|
644
|
+
| **WhatsApp** | `katanakit-js/adapters/whatsapp` | Meta Cloud API (`useInitWhatsApp`, `useStartWhatsApp`) |
|
|
567
645
|
|
|
568
646
|
## REST API Adapters
|
|
569
647
|
|
|
570
648
|
Typed adapters for popular REST APIs with auth, pagination helpers, and full TypeScript types.
|
|
571
649
|
All functions return `FetchResult<T>` — the same Safe Result pattern used by the HTTP client.
|
|
572
650
|
|
|
573
|
-
| Adapter
|
|
574
|
-
|
|
575
|
-
| **Notion**
|
|
651
|
+
| Adapter | Import | Description |
|
|
652
|
+
| ------------- | --------------------------------- | ----------------------------------------------------------------- |
|
|
653
|
+
| **Notion** | `katanakit-js/adapters/notion` | Pages, databases, blocks, search with cursor pagination |
|
|
576
654
|
| **WordPress** | `katanakit-js/adapters/wordpress` | Posts, pages, media, categories, tags, comments, users, batch ops |
|
|
577
655
|
|
|
578
656
|
### Notion
|
|
@@ -593,10 +671,10 @@ useInitNotion({ token: process.env.NOTION_TOKEN });
|
|
|
593
671
|
|
|
594
672
|
```ts
|
|
595
673
|
import {
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
674
|
+
useNotionGetPage,
|
|
675
|
+
useNotionCreatePage,
|
|
676
|
+
useNotionUpdatePage,
|
|
677
|
+
useNotionArchivePage,
|
|
600
678
|
} from "katanakit-js/adapters/notion";
|
|
601
679
|
|
|
602
680
|
// Get a single page with all its properties
|
|
@@ -605,24 +683,24 @@ if (page.ok) console.log(page.data.properties);
|
|
|
605
683
|
|
|
606
684
|
// Create a page inside a database
|
|
607
685
|
const created = await useNotionCreatePage(
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
686
|
+
{ type: "database_id", database_id: "db-id" },
|
|
687
|
+
{
|
|
688
|
+
Name: { title: [{ type: "text", text: { content: "My Task" } }] },
|
|
689
|
+
Status: { select: { name: "To Do" } },
|
|
690
|
+
},
|
|
613
691
|
);
|
|
614
692
|
|
|
615
693
|
// Create a child page with content blocks
|
|
616
694
|
const child = await useNotionCreatePage(
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
695
|
+
{ type: "page_id", page_id: "parent-id" },
|
|
696
|
+
{ title: { title: [{ type: "text", text: { content: "Child Page" } }] } },
|
|
697
|
+
[{ type: "paragraph", paragraph: { rich_text: [{ type: "text", text: { content: "Hello!" } }] } }],
|
|
620
698
|
);
|
|
621
699
|
|
|
622
700
|
// Update page properties (only changed fields)
|
|
623
701
|
await useNotionUpdatePage("page-id", {
|
|
624
|
-
|
|
625
|
-
|
|
702
|
+
Status: { select: { name: "Done" } },
|
|
703
|
+
DueDate: { date: { start: "2025-12-31" } },
|
|
626
704
|
});
|
|
627
705
|
|
|
628
706
|
// Archive (soft-delete) a page
|
|
@@ -633,26 +711,26 @@ await useNotionArchivePage("page-id");
|
|
|
633
711
|
|
|
634
712
|
```ts
|
|
635
713
|
import {
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
714
|
+
useNotionGetDatabase,
|
|
715
|
+
useNotionQueryDatabase,
|
|
716
|
+
useNotionCreateDatabase,
|
|
717
|
+
useNotionUpdateDatabase,
|
|
718
|
+
useNotionListAllDatabasePages,
|
|
641
719
|
} from "katanakit-js/adapters/notion";
|
|
642
720
|
|
|
643
721
|
// Inspect database schema (property names, types, options)
|
|
644
722
|
const schema = await useNotionGetDatabase("db-id");
|
|
645
723
|
if (schema.ok) {
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
724
|
+
Object.entries(schema.data.properties).forEach(([name, prop]) => {
|
|
725
|
+
console.log(`${name}: ${prop.type}`);
|
|
726
|
+
});
|
|
649
727
|
}
|
|
650
728
|
|
|
651
729
|
// Query with filter + sort (single page of results)
|
|
652
730
|
const page1 = await useNotionQueryDatabase("db-id", {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
731
|
+
filter: { property: "Status", select: { equals: "Published" } },
|
|
732
|
+
sorts: [{ property: "Date", direction: "descending" }],
|
|
733
|
+
page_size: 10,
|
|
656
734
|
});
|
|
657
735
|
|
|
658
736
|
// Get ALL pages (auto-pagination — handles cursors internally)
|
|
@@ -660,76 +738,74 @@ const all = await useNotionListAllDatabasePages("db-id");
|
|
|
660
738
|
|
|
661
739
|
// With filter + sort
|
|
662
740
|
const published = await useNotionListAllDatabasePages(
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
741
|
+
"db-id",
|
|
742
|
+
{ property: "Status", select: { equals: "Published" } },
|
|
743
|
+
[{ property: "Date", direction: "descending" }],
|
|
666
744
|
);
|
|
667
745
|
|
|
668
746
|
// Create a new database
|
|
669
747
|
await useNotionCreateDatabase(
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
748
|
+
{ type: "page_id", page_id: "parent-id" },
|
|
749
|
+
[{ type: "text", text: { content: "My Tasks" } }],
|
|
750
|
+
{
|
|
751
|
+
Name: { title: {} },
|
|
752
|
+
Status: { select: { options: [{ name: "To Do" }, { name: "Done" }] } },
|
|
753
|
+
Priority: { select: { options: [{ name: "Low" }, { name: "High" }] } },
|
|
754
|
+
},
|
|
677
755
|
);
|
|
678
756
|
|
|
679
757
|
// Rename a database
|
|
680
|
-
await useNotionUpdateDatabase("db-id", [
|
|
681
|
-
{ type: "text", text: { content: "Renamed Database" } },
|
|
682
|
-
]);
|
|
758
|
+
await useNotionUpdateDatabase("db-id", [{ type: "text", text: { content: "Renamed Database" } }]);
|
|
683
759
|
```
|
|
684
760
|
|
|
685
761
|
#### Blocks — read, write, append, delete page content
|
|
686
762
|
|
|
687
763
|
```ts
|
|
688
764
|
import {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
765
|
+
useNotionGetBlock,
|
|
766
|
+
useNotionGetBlockChildren,
|
|
767
|
+
useNotionListAllBlockChildren,
|
|
768
|
+
useNotionAppendBlocks,
|
|
769
|
+
useNotionUpdateBlock,
|
|
770
|
+
useNotionDeleteBlock,
|
|
695
771
|
} from "katanakit-js/adapters/notion";
|
|
696
772
|
|
|
697
773
|
// Get ALL blocks of a page (auto-pagination)
|
|
698
774
|
const blocks = await useNotionListAllBlockChildren("page-id");
|
|
699
775
|
if (blocks.ok) {
|
|
700
|
-
|
|
776
|
+
blocks.data.forEach((b) => console.log(b.type)); // "paragraph", "heading_1", etc.
|
|
701
777
|
}
|
|
702
778
|
|
|
703
779
|
// Manual pagination (for fine-grained cursor control)
|
|
704
780
|
const page = await useNotionGetBlockChildren("page-id", { page_size: 50 });
|
|
705
781
|
if (page.ok) {
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
782
|
+
console.log(page.data.results); // blocks
|
|
783
|
+
console.log(page.data.has_more); // true if more pages exist
|
|
784
|
+
console.log(page.data.next_cursor); // pass as start_cursor for next page
|
|
709
785
|
}
|
|
710
786
|
|
|
711
787
|
// Append content blocks to a page
|
|
712
788
|
await useNotionAppendBlocks("page-id", [
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
789
|
+
{
|
|
790
|
+
type: "heading_2",
|
|
791
|
+
heading_2: { rich_text: [{ type: "text", text: { content: "New Section" } }] },
|
|
792
|
+
},
|
|
793
|
+
{
|
|
794
|
+
type: "paragraph",
|
|
795
|
+
paragraph: { rich_text: [{ type: "text", text: { content: "Body text here." } }] },
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
type: "to_do",
|
|
799
|
+
to_do: {
|
|
800
|
+
rich_text: [{ type: "text", text: { content: "Checklist item" } }],
|
|
801
|
+
checked: false,
|
|
802
|
+
},
|
|
803
|
+
},
|
|
728
804
|
]);
|
|
729
805
|
|
|
730
806
|
// Update a block's content
|
|
731
807
|
await useNotionUpdateBlock("block-id", {
|
|
732
|
-
|
|
808
|
+
paragraph: { rich_text: [{ type: "text", text: { content: "Updated text" } }] },
|
|
733
809
|
});
|
|
734
810
|
|
|
735
811
|
// Delete (archive) a block
|
|
@@ -746,14 +822,14 @@ const found = await useNotionSearchContent({ query: "meeting notes" });
|
|
|
746
822
|
|
|
747
823
|
// Search only databases
|
|
748
824
|
const dbs = await useNotionSearchContent({
|
|
749
|
-
|
|
750
|
-
|
|
825
|
+
query: "tasks",
|
|
826
|
+
filter: { value: "database", property: "object" },
|
|
751
827
|
});
|
|
752
828
|
|
|
753
829
|
// Search only pages, sorted by recently edited
|
|
754
830
|
const pages = await useNotionSearchContent({
|
|
755
|
-
|
|
756
|
-
|
|
831
|
+
filter: { value: "page", property: "object" },
|
|
832
|
+
sort: { direction: "descending", timestamp: "last_edited_time" },
|
|
757
833
|
});
|
|
758
834
|
```
|
|
759
835
|
|
|
@@ -768,22 +844,22 @@ if (user.ok) console.log(user.data.name);
|
|
|
768
844
|
|
|
769
845
|
// List all workspace members + bots
|
|
770
846
|
const users = await useNotionListUsers();
|
|
771
|
-
if (users.ok) users.data.results.forEach(u => console.log(u.name));
|
|
847
|
+
if (users.ok) users.data.results.forEach((u) => console.log(u.name));
|
|
772
848
|
```
|
|
773
849
|
|
|
774
850
|
#### Framework examples
|
|
775
851
|
|
|
776
|
-
| Framework
|
|
777
|
-
|
|
778
|
-
| **Vue 3**
|
|
779
|
-
| **Vue 3**
|
|
780
|
-
| **Nuxt 3**
|
|
781
|
-
| **Nuxt 3**
|
|
782
|
-
| **Astro**
|
|
783
|
-
| **Astro**
|
|
784
|
-
| **Next.js** | [`examples/notion/next-blog.tsx`](https://github.com/senseikatana/katanakit-js/tree/main/examples/notion/next-blog.tsx)
|
|
785
|
-
| **Next.js** | [`examples/notion/next-[slug].tsx`](https://github.com/senseikatana/katanakit-js/tree/main/examples/notion/next-[slug].tsx)
|
|
786
|
-
| **Node.js** | [`examples/notion/demo.ts`](https://github.com/senseikatana/katanakit-js/tree/main/examples/notion/demo.ts)
|
|
852
|
+
| Framework | Example | Description |
|
|
853
|
+
| ----------- | --------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
|
|
854
|
+
| **Vue 3** | [`examples/notion/vue-blog.vue`](https://github.com/senseikatana/katanakit-js/tree/main/examples/notion/vue-blog.vue) | Blog listing with `useQuery` composable |
|
|
855
|
+
| **Vue 3** | [`examples/notion/vue-post.vue`](https://github.com/senseikatana/katanakit-js/tree/main/examples/notion/vue-post.vue) | Single post view |
|
|
856
|
+
| **Nuxt 3** | [`examples/notion/nuxt-blog.vue`](https://github.com/senseikatana/katanakit-js/tree/main/examples/notion/nuxt-blog.vue) | SSR blog listing with `useAsyncData` |
|
|
857
|
+
| **Nuxt 3** | [`examples/notion/nuxt-post.vue`](https://github.com/senseikatana/katanakit-js/tree/main/examples/notion/nuxt-post.vue) | SSR single post view |
|
|
858
|
+
| **Astro** | [`examples/notion/astro-blog.astro`](https://github.com/senseikatana/katanakit-js/tree/main/examples/notion/astro-blog.astro) | Static blog listing |
|
|
859
|
+
| **Astro** | [`examples/notion/astro-[slug].astro`](https://github.com/senseikatana/katanakit-js/tree/main/examples/notion/astro-[slug].astro) | Dynamic `[slug]` route |
|
|
860
|
+
| **Next.js** | [`examples/notion/next-blog.tsx`](https://github.com/senseikatana/katanakit-js/tree/main/examples/notion/next-blog.tsx) | Server component blog listing |
|
|
861
|
+
| **Next.js** | [`examples/notion/next-[slug].tsx`](https://github.com/senseikatana/katanakit-js/tree/main/examples/notion/next-[slug].tsx) | Dynamic `[slug]` page |
|
|
862
|
+
| **Node.js** | [`examples/notion/demo.ts`](https://github.com/senseikatana/katanakit-js/tree/main/examples/notion/demo.ts) | Runnable demo covering all Notion operations |
|
|
787
863
|
|
|
788
864
|
### WordPress
|
|
789
865
|
|
|
@@ -798,20 +874,20 @@ import { useInitWordPress } from "katanakit-js/adapters/wordpress";
|
|
|
798
874
|
|
|
799
875
|
// Application Passwords (recommended) — WP Admin → Users → Your Profile → Application Passwords
|
|
800
876
|
useInitWordPress({
|
|
801
|
-
|
|
802
|
-
|
|
877
|
+
baseUrl: "https://mysite.com",
|
|
878
|
+
auth: { type: "application-passwords", username: "admin", password: "xxxx xxxx xxxx" },
|
|
803
879
|
});
|
|
804
880
|
|
|
805
881
|
// JWT tokens
|
|
806
882
|
useInitWordPress({
|
|
807
|
-
|
|
808
|
-
|
|
883
|
+
baseUrl: "https://mysite.com",
|
|
884
|
+
auth: { type: "jwt", token: "eyJhbGci..." },
|
|
809
885
|
});
|
|
810
886
|
|
|
811
887
|
// Nonce-based (for WP themes)
|
|
812
888
|
useInitWordPress({
|
|
813
|
-
|
|
814
|
-
|
|
889
|
+
baseUrl: "https://mysite.com",
|
|
890
|
+
auth: { type: "nonce", nonce: "abc123" },
|
|
815
891
|
});
|
|
816
892
|
```
|
|
817
893
|
|
|
@@ -819,22 +895,22 @@ useInitWordPress({
|
|
|
819
895
|
|
|
820
896
|
```ts
|
|
821
897
|
import {
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
898
|
+
useWpGetPosts,
|
|
899
|
+
useWpGetPost,
|
|
900
|
+
useWpCreatePost,
|
|
901
|
+
useWpUpdatePost,
|
|
902
|
+
useWpDeletePost,
|
|
903
|
+
useWpListAllPosts,
|
|
904
|
+
useWpSearchAllPosts,
|
|
905
|
+
useWpFindPostBySlug,
|
|
830
906
|
} from "katanakit-js/adapters/wordpress";
|
|
831
907
|
|
|
832
908
|
// List published posts (paginated)
|
|
833
909
|
const posts = await useWpGetPosts({
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
910
|
+
per_page: 5,
|
|
911
|
+
status: "publish",
|
|
912
|
+
orderby: "date",
|
|
913
|
+
order: "desc",
|
|
838
914
|
});
|
|
839
915
|
|
|
840
916
|
// Get a single post with embedded resources
|
|
@@ -843,19 +919,19 @@ if (post.ok) console.log(post.data.title.rendered);
|
|
|
843
919
|
|
|
844
920
|
// Create a post
|
|
845
921
|
await useWpCreatePost({
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
922
|
+
title: "My New Post",
|
|
923
|
+
content: "<p>Hello World!</p>",
|
|
924
|
+
status: "publish", // "draft" | "pending" | "publish"
|
|
925
|
+
categories: [1, 3],
|
|
926
|
+
tags: [5, 8],
|
|
851
927
|
});
|
|
852
928
|
|
|
853
929
|
// Update a post
|
|
854
930
|
await useWpUpdatePost(42, { title: "Updated Title", status: "publish" });
|
|
855
931
|
|
|
856
932
|
// Delete (trash or permanent)
|
|
857
|
-
await useWpDeletePost(42);
|
|
858
|
-
await useWpDeletePost(42, true);
|
|
933
|
+
await useWpDeletePost(42); // move to trash
|
|
934
|
+
await useWpDeletePost(42, true); // permanently delete
|
|
859
935
|
|
|
860
936
|
// Get ALL posts (auto-pagination — loops until exhausted)
|
|
861
937
|
const all = await useWpListAllPosts({ status: "publish" });
|
|
@@ -863,7 +939,7 @@ if (all.ok) console.log(`Total: ${all.data.length}`);
|
|
|
863
939
|
|
|
864
940
|
// Search ALL posts by keyword
|
|
865
941
|
const found = await useWpSearchAllPosts("tutorial");
|
|
866
|
-
if (found.ok) found.data.forEach(p => console.log(p.title.rendered));
|
|
942
|
+
if (found.ok) found.data.forEach((p) => console.log(p.title.rendered));
|
|
867
943
|
|
|
868
944
|
// Find post by slug (for dynamic routes like /blog/:slug)
|
|
869
945
|
const bySlug = await useWpFindPostBySlug("hello-world");
|
|
@@ -874,11 +950,11 @@ if (bySlug.ok && bySlug.data) console.log(bySlug.data.title.rendered);
|
|
|
874
950
|
|
|
875
951
|
```ts
|
|
876
952
|
import {
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
953
|
+
useWpGetPages,
|
|
954
|
+
useWpGetPage,
|
|
955
|
+
useWpCreatePage,
|
|
956
|
+
useWpUpdatePage,
|
|
957
|
+
useWpDeletePage,
|
|
882
958
|
} from "katanakit-js/adapters/wordpress";
|
|
883
959
|
|
|
884
960
|
const pages = await useWpGetPages({ per_page: 20 });
|
|
@@ -887,10 +963,10 @@ const page = await useWpGetPage(10);
|
|
|
887
963
|
if (page.ok) console.log(page.data.title.rendered);
|
|
888
964
|
|
|
889
965
|
await useWpCreatePage({
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
966
|
+
title: "About Us",
|
|
967
|
+
content: "<p>Welcome to our site!</p>",
|
|
968
|
+
status: "publish",
|
|
969
|
+
parent: 0, // top-level page (set a page ID for child pages)
|
|
894
970
|
});
|
|
895
971
|
|
|
896
972
|
await useWpUpdatePage(10, { title: "Updated About" });
|
|
@@ -901,11 +977,11 @@ await useWpDeletePage(10); // trash
|
|
|
901
977
|
|
|
902
978
|
```ts
|
|
903
979
|
import {
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
980
|
+
useWpGetMedia,
|
|
981
|
+
useWpGetMediaItem,
|
|
982
|
+
useWpUploadMedia,
|
|
983
|
+
useWpUpdateMedia,
|
|
984
|
+
useWpDeleteMedia,
|
|
909
985
|
} from "katanakit-js/adapters/wordpress";
|
|
910
986
|
|
|
911
987
|
// List media items
|
|
@@ -918,9 +994,9 @@ if (item.ok) console.log(item.data.source_url);
|
|
|
918
994
|
// Upload from browser (File from <input type="file">)
|
|
919
995
|
const file = document.querySelector("input[type=file]").files[0];
|
|
920
996
|
const uploaded = await useWpUploadMedia(file, {
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
997
|
+
title: "My Image",
|
|
998
|
+
alt_text: "Description for accessibility",
|
|
999
|
+
caption: "Image caption",
|
|
924
1000
|
});
|
|
925
1001
|
if (uploaded.ok) console.log(uploaded.data.source_url); // URL to use in content
|
|
926
1002
|
|
|
@@ -940,10 +1016,16 @@ await useWpDeleteMedia(42, true); // permanent
|
|
|
940
1016
|
|
|
941
1017
|
```ts
|
|
942
1018
|
import {
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1019
|
+
useWpGetCategories,
|
|
1020
|
+
useWpGetCategory,
|
|
1021
|
+
useWpCreateCategory,
|
|
1022
|
+
useWpUpdateCategory,
|
|
1023
|
+
useWpDeleteCategory,
|
|
1024
|
+
useWpGetTags,
|
|
1025
|
+
useWpGetTag,
|
|
1026
|
+
useWpCreateTag,
|
|
1027
|
+
useWpUpdateTag,
|
|
1028
|
+
useWpDeleteTag,
|
|
947
1029
|
} from "katanakit-js/adapters/wordpress";
|
|
948
1030
|
|
|
949
1031
|
// Categories
|
|
@@ -963,8 +1045,11 @@ await useWpDeleteTag(12);
|
|
|
963
1045
|
|
|
964
1046
|
```ts
|
|
965
1047
|
import {
|
|
966
|
-
|
|
967
|
-
|
|
1048
|
+
useWpGetComments,
|
|
1049
|
+
useWpGetComment,
|
|
1050
|
+
useWpCreateComment,
|
|
1051
|
+
useWpUpdateComment,
|
|
1052
|
+
useWpDeleteComment,
|
|
968
1053
|
} from "katanakit-js/adapters/wordpress";
|
|
969
1054
|
|
|
970
1055
|
// Get comments for a post
|
|
@@ -972,10 +1057,10 @@ const comments = await useWpGetComments({ post: 42, per_page: 10 });
|
|
|
972
1057
|
|
|
973
1058
|
// Create a comment (public or authenticated)
|
|
974
1059
|
await useWpCreateComment({
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1060
|
+
post: 42,
|
|
1061
|
+
content: "Great article!",
|
|
1062
|
+
author_name: "John",
|
|
1063
|
+
author_email: "john@example.com",
|
|
979
1064
|
});
|
|
980
1065
|
|
|
981
1066
|
// Update / delete
|
|
@@ -987,18 +1072,22 @@ await useWpDeleteComment(7);
|
|
|
987
1072
|
|
|
988
1073
|
```ts
|
|
989
1074
|
import {
|
|
990
|
-
|
|
991
|
-
|
|
1075
|
+
useWpGetUsers,
|
|
1076
|
+
useWpGetUser,
|
|
1077
|
+
useWpGetCurrentUser,
|
|
1078
|
+
useWpCreateUser,
|
|
1079
|
+
useWpUpdateUser,
|
|
1080
|
+
useWpDeleteUser,
|
|
992
1081
|
} from "katanakit-js/adapters/wordpress";
|
|
993
1082
|
|
|
994
1083
|
const users = await useWpGetUsers({ roles: "editor" });
|
|
995
1084
|
const me = await useWpGetCurrentUser(); // authenticated user
|
|
996
1085
|
|
|
997
1086
|
await useWpCreateUser({
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1087
|
+
username: "johndoe",
|
|
1088
|
+
email: "john@example.com",
|
|
1089
|
+
password: "secure-password",
|
|
1090
|
+
roles: ["editor"],
|
|
1002
1091
|
});
|
|
1003
1092
|
|
|
1004
1093
|
await useWpUpdateUser(2, { name: "John Smith" });
|
|
@@ -1009,8 +1098,11 @@ await useWpDeleteUser(2, 1); // reassign content to user 1
|
|
|
1009
1098
|
|
|
1010
1099
|
```ts
|
|
1011
1100
|
import {
|
|
1012
|
-
|
|
1013
|
-
|
|
1101
|
+
useWpGetCustomPosts,
|
|
1102
|
+
useWpGetCustomPost,
|
|
1103
|
+
useWpCreateCustomPost,
|
|
1104
|
+
useWpUpdateCustomPost,
|
|
1105
|
+
useWpDeleteCustomPost,
|
|
1014
1106
|
} from "katanakit-js/adapters/wordpress";
|
|
1015
1107
|
|
|
1016
1108
|
// Works with any registered CPT: "product", "portfolio", "event", etc.
|
|
@@ -1018,9 +1110,9 @@ const products = await useWpGetCustomPosts("product", { per_page: 10 });
|
|
|
1018
1110
|
const product = await useWpGetCustomPost("product", 15);
|
|
1019
1111
|
|
|
1020
1112
|
await useWpCreateCustomPost("product", {
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1113
|
+
title: "Widget",
|
|
1114
|
+
content: "<p>A great widget</p>",
|
|
1115
|
+
status: "publish",
|
|
1024
1116
|
});
|
|
1025
1117
|
|
|
1026
1118
|
await useWpUpdateCustomPost("product", 15, { title: "Updated Widget" });
|
|
@@ -1033,13 +1125,13 @@ await useWpDeleteCustomPost("product", 15, true);
|
|
|
1033
1125
|
import { useWpBatch } from "katanakit-js/adapters/wordpress";
|
|
1034
1126
|
|
|
1035
1127
|
const result = await useWpBatch([
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1128
|
+
{ method: "GET", path: "/wp/v2/posts?per_page=2" },
|
|
1129
|
+
{ method: "GET", path: "/wp/v2/pages?per_page=2" },
|
|
1130
|
+
{ method: "GET", path: "/wp/v2/categories?per_page=5" },
|
|
1039
1131
|
]);
|
|
1040
1132
|
|
|
1041
1133
|
if (result.ok) {
|
|
1042
|
-
|
|
1134
|
+
result.data.responses.forEach((resp) => console.log(resp.status));
|
|
1043
1135
|
}
|
|
1044
1136
|
```
|
|
1045
1137
|
|
|
@@ -1051,8 +1143,8 @@ significantly for list views.
|
|
|
1051
1143
|
```ts
|
|
1052
1144
|
// Only fetch id, title, link, slug, and date
|
|
1053
1145
|
const posts = await useWpGetPosts({
|
|
1054
|
-
|
|
1055
|
-
|
|
1146
|
+
per_page: 20,
|
|
1147
|
+
_fields: "id,title,link,slug,date",
|
|
1056
1148
|
});
|
|
1057
1149
|
```
|
|
1058
1150
|
|
|
@@ -1067,16 +1159,17 @@ const posts = await useWpGetPosts({ _embed: true });
|
|
|
1067
1159
|
|
|
1068
1160
|
// Embed only specific resources
|
|
1069
1161
|
const posts = await useWpGetPosts({
|
|
1070
|
-
|
|
1162
|
+
_embed: "author,wp:featuredmedia",
|
|
1071
1163
|
});
|
|
1072
1164
|
|
|
1073
1165
|
// Access embedded data
|
|
1074
1166
|
if (posts.ok) {
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1167
|
+
for (const post of posts.data) {
|
|
1168
|
+
const author = post._embedded?.author?.[0]?.name;
|
|
1169
|
+
const image = post._embedded?.["wp:featuredmedia"]?.[0]?.source_url;
|
|
1170
|
+
const thumbnail =
|
|
1171
|
+
post._embedded?.["wp:featuredmedia"]?.[0]?.media_details?.sizes?.thumbnail?.source_url;
|
|
1172
|
+
}
|
|
1080
1173
|
}
|
|
1081
1174
|
```
|
|
1082
1175
|
|
|
@@ -1089,51 +1182,85 @@ media item, or custom post type entry.
|
|
|
1089
1182
|
```ts
|
|
1090
1183
|
// Request ACF fields explicitly with _fields
|
|
1091
1184
|
const posts = await useWpGetPosts({
|
|
1092
|
-
|
|
1093
|
-
|
|
1185
|
+
per_page: 5,
|
|
1186
|
+
_fields: "id,title,acf",
|
|
1094
1187
|
});
|
|
1095
1188
|
|
|
1096
1189
|
if (posts.ok) {
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1190
|
+
for (const post of posts.data) {
|
|
1191
|
+
if (post.acf) {
|
|
1192
|
+
// ACF fields are dynamic — access by field name
|
|
1193
|
+
console.log(post.acf.my_field_name);
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1103
1196
|
}
|
|
1104
1197
|
|
|
1105
1198
|
// Combine _fields + _embed + ACF for full-featured list views
|
|
1106
1199
|
const full = await useWpGetPosts({
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1200
|
+
per_page: 5,
|
|
1201
|
+
_fields: "id,title,link,slug,date,acf",
|
|
1202
|
+
_embed: "author,wp:featuredmedia",
|
|
1110
1203
|
});
|
|
1111
1204
|
```
|
|
1112
1205
|
|
|
1113
1206
|
#### Framework examples
|
|
1114
1207
|
|
|
1115
|
-
| Framework
|
|
1116
|
-
|
|
1117
|
-
| **Vue 3**
|
|
1118
|
-
| **Vue 3**
|
|
1119
|
-
| **Nuxt 3**
|
|
1120
|
-
| **Nuxt 3**
|
|
1121
|
-
| **Astro**
|
|
1122
|
-
| **Astro**
|
|
1123
|
-
| **Next.js** | [`examples/wordpress/next-blog.tsx`](https://github.com/senseikatana/katanakit-js/tree/main/examples/wordpress/next-blog.tsx)
|
|
1124
|
-
| **Next.js** | [`examples/wordpress/next-[slug].tsx`](https://github.com/senseikatana/katanakit-js/tree/main/examples/wordpress/next-[slug].tsx)
|
|
1125
|
-
| **Node.js** | [`examples/wordpress/demo.ts`](https://github.com/senseikatana/katanakit-js/tree/main/examples/wordpress/demo.ts)
|
|
1208
|
+
| Framework | Example | Description |
|
|
1209
|
+
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
1210
|
+
| **Vue 3** | [`examples/wordpress/vue-blog.vue`](https://github.com/senseikatana/katanakit-js/tree/main/examples/wordpress/vue-blog.vue) | Blog listing with categories, featured images, `_embed` |
|
|
1211
|
+
| **Vue 3** | [`examples/wordpress/vue-post.vue`](https://github.com/senseikatana/katanakit-js/tree/main/examples/wordpress/vue-post.vue) | Single post view with embedded author |
|
|
1212
|
+
| **Nuxt 3** | [`examples/wordpress/nuxt-blog.vue`](https://github.com/senseikatana/katanakit-js/tree/main/examples/wordpress/nuxt-blog.vue) | SSR blog listing with `useAsyncData` |
|
|
1213
|
+
| **Nuxt 3** | [`examples/wordpress/nuxt-post.vue`](https://github.com/senseikatana/katanakit-js/tree/main/examples/wordpress/nuxt-post.vue) | SSR single post view |
|
|
1214
|
+
| **Astro** | [`examples/wordpress/astro-blog.astro`](https://github.com/senseikatana/katanakit-js/tree/main/examples/wordpress/astro-blog.astro) | Static blog listing |
|
|
1215
|
+
| **Astro** | [`examples/wordpress/astro-[slug].astro`](https://github.com/senseikatana/katanakit-js/tree/main/examples/wordpress/astro-[slug].astro) | Dynamic `[slug]` route |
|
|
1216
|
+
| **Next.js** | [`examples/wordpress/next-blog.tsx`](https://github.com/senseikatana/katanakit-js/tree/main/examples/wordpress/next-blog.tsx) | Server component blog listing |
|
|
1217
|
+
| **Next.js** | [`examples/wordpress/next-[slug].tsx`](https://github.com/senseikatana/katanakit-js/tree/main/examples/wordpress/next-[slug].tsx) | Dynamic `[slug]` page |
|
|
1218
|
+
| **Node.js** | [`examples/wordpress/demo.ts`](https://github.com/senseikatana/katanakit-js/tree/main/examples/wordpress/demo.ts) | Runnable demo covering all WP operations, `_fields`, `_embed`, ACF |
|
|
1219
|
+
|
|
1220
|
+
## Contributing
|
|
1221
|
+
|
|
1222
|
+
We welcome contributions from the community! Whether it's fixing a bug, adding
|
|
1223
|
+
a feature, or improving documentation, every contribution helps make KatanaKit
|
|
1224
|
+
better for everyone.
|
|
1225
|
+
|
|
1226
|
+
### Quick start
|
|
1227
|
+
|
|
1228
|
+
```bash
|
|
1229
|
+
git clone https://github.com/senseikatana/katanakit-js.git
|
|
1230
|
+
cd katanakit-js
|
|
1231
|
+
git checkout dev
|
|
1232
|
+
bun install
|
|
1233
|
+
bun run check # verify everything works
|
|
1234
|
+
```
|
|
1235
|
+
|
|
1236
|
+
### Ways to contribute
|
|
1237
|
+
|
|
1238
|
+
- **Report bugs** — [Open an issue](https://github.com/senseikatana/katanakit-js/issues) with a clear description and reproduction steps
|
|
1239
|
+
- **Suggest features** — [Start a discussion](https://github.com/senseikatana/katanakit-js/discussions) to propose new ideas
|
|
1240
|
+
- **Submit a PR** — Fork the repo, create a branch from `dev`, make your changes, and open a PR
|
|
1241
|
+
- **Improve docs** — Fix typos, add examples, or clarify explanations
|
|
1242
|
+
- **Add adapters** — Build integrations for new APIs or frameworks
|
|
1243
|
+
|
|
1244
|
+
### PR guidelines
|
|
1245
|
+
|
|
1246
|
+
1. Branch from `dev` (not `main`)
|
|
1247
|
+
2. Follow the `use*` naming convention
|
|
1248
|
+
3. Add TypeScript types in `src/types/index.ts`
|
|
1249
|
+
4. Run `bun run check` before submitting
|
|
1250
|
+
5. Update `CHANGELOG.md` if the public API changed
|
|
1251
|
+
|
|
1252
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full development contract.
|
|
1126
1253
|
|
|
1127
1254
|
## Documentation
|
|
1128
1255
|
|
|
1129
|
-
The docs site is deployed with
|
|
1256
|
+
The docs site is deployed with Cloudflare Pages at [docs.senseikatana.com](https://docs.senseikatana.com/).
|
|
1130
1257
|
|
|
1131
|
-
- [Getting Started](https://senseikatana.com/
|
|
1132
|
-
- [Architecture](https://senseikatana.com/
|
|
1133
|
-
- [UI Kit (Katana UI)](https://senseikatana.com/
|
|
1134
|
-
- [API Reference](https://senseikatana.com/
|
|
1135
|
-
- [Roadmap](https://senseikatana.com/
|
|
1136
|
-
- [Changelog](https://senseikatana.com/
|
|
1258
|
+
- [Getting Started](https://docs.senseikatana.com/docs/guides/getting-started/)
|
|
1259
|
+
- [Architecture](https://docs.senseikatana.com/docs/guides/architecture/)
|
|
1260
|
+
- [UI Kit (Katana UI)](https://docs.senseikatana.com/docs/ui-kit/)
|
|
1261
|
+
- [API Reference](https://docs.senseikatana.com/docs/api/)
|
|
1262
|
+
- [Roadmap](https://docs.senseikatana.com/docs/guides/roadmap/)
|
|
1263
|
+
- [Changelog](https://docs.senseikatana.com/docs/changelog/)
|
|
1137
1264
|
|
|
1138
1265
|
## License
|
|
1139
1266
|
|