katanakit-js 4.0.0 → 4.0.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 +326 -305
- 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/server.js +2 -2
- package/dist/adapters/express/server.js.map +1 -1
- package/dist/adapters/notion/notion.service.d.ts +2 -2
- package/dist/adapters/notion/notion.service.d.ts.map +1 -1
- package/dist/adapters/notion/notion.service.js +6 -6
- package/dist/adapters/notion/notion.service.js.map +1 -1
- package/dist/adapters/telegram/telegram.service.js +1 -1
- package/dist/adapters/telegram/telegram.service.js.map +1 -1
- package/dist/adapters/vue/query.d.ts +1 -2
- package/dist/adapters/vue/query.d.ts.map +1 -1
- package/dist/adapters/vue/query.js +1 -3
- package/dist/adapters/vue/query.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 +1 -1
- package/dist/adapters/wordpress/wordpress.service.d.ts.map +1 -1
- package/dist/adapters/wordpress/wordpress.service.js +3 -3
- package/dist/adapters/wordpress/wordpress.service.js.map +1 -1
- package/dist/core/services/dates.service.js +1 -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/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.map +1 -1
- package/dist/core/services/query.service.js +9 -8
- package/dist/core/services/query.service.js.map +1 -1
- package/dist/core/services/reactive.service.js +7 -7
- 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/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 +7 -5
- 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/types/index.d.ts +2 -5
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +17 -22
package/README.md
CHANGED
|
@@ -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,14 +158,14 @@ 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
|
|
|
@@ -208,7 +208,7 @@ const avatarUrl = useBuildUrl("myApi", "userAvatar", {
|
|
|
208
208
|
```ts
|
|
209
209
|
// Charts, maps, analytics — libraries that fetch their own data
|
|
210
210
|
const chartDataUrl = useBuildUrl("myApi", "analytics", {
|
|
211
|
-
|
|
211
|
+
query: { range: "7d", metric: "visits" },
|
|
212
212
|
});
|
|
213
213
|
new Chart(canvas, { data: chartDataUrl });
|
|
214
214
|
```
|
|
@@ -217,9 +217,12 @@ new Chart(canvas, { data: chartDataUrl });
|
|
|
217
217
|
|
|
218
218
|
```ts
|
|
219
219
|
// See the full URL before making the request
|
|
220
|
-
console.log(
|
|
221
|
-
|
|
222
|
-
|
|
220
|
+
console.log(
|
|
221
|
+
"Will fetch:",
|
|
222
|
+
useBuildUrl("myApi", "users", {
|
|
223
|
+
query: { page: 1, per_page: 20 },
|
|
224
|
+
}),
|
|
225
|
+
);
|
|
223
226
|
// → "https://api.myapp.com/v1/users?page=1&per_page=20"
|
|
224
227
|
```
|
|
225
228
|
|
|
@@ -228,7 +231,7 @@ console.log("Will fetch:", useBuildUrl("myApi", "users", {
|
|
|
228
231
|
```ts
|
|
229
232
|
// In Astro, Next.js, or Nuxt server code
|
|
230
233
|
const apiUrl = useBuildUrl("notion", "database", {
|
|
231
|
-
|
|
234
|
+
params: { id: "db-123" },
|
|
232
235
|
});
|
|
233
236
|
// Pass to client component or pre-render
|
|
234
237
|
```
|
|
@@ -266,11 +269,11 @@ const qc = useQueryClient();
|
|
|
266
269
|
|
|
267
270
|
// Fetch with cache, stale-while-revalidate, retry, and dedup.
|
|
268
271
|
const pokemon = await qc.fetchQuery<Pokemon>({
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
272
|
+
queryKey: ["pokemon", 25],
|
|
273
|
+
queryFn: () => useGetApi<Pokemon>("pokeapi", "pokemonById", { params: { id: 25 } }),
|
|
274
|
+
staleTime: 60_000, // Cache is fresh for 60s.
|
|
275
|
+
retry: 3, // Retry 3 times on failure.
|
|
276
|
+
refetchOnWindowFocus: true,
|
|
274
277
|
});
|
|
275
278
|
```
|
|
276
279
|
|
|
@@ -349,12 +352,12 @@ Use it when you need:
|
|
|
349
352
|
|
|
350
353
|
### When to use alternatives
|
|
351
354
|
|
|
352
|
-
| Need
|
|
353
|
-
|
|
354
|
-
| Streaming token-by-token
|
|
355
|
-
| RAG with embeddings
|
|
355
|
+
| Need | Use instead |
|
|
356
|
+
| ------------------------- | --------------------------------------------- |
|
|
357
|
+
| Streaming token-by-token | [Vercel AI SDK](https://sdk.vercel.ai) |
|
|
358
|
+
| RAG with embeddings | [LangChain.js](https://js.langchain.com) |
|
|
356
359
|
| Multi-agent orchestration | [CrewAI](https://github.com/crewAIInc/crewAI) |
|
|
357
|
-
| Full chatbot framework
|
|
360
|
+
| Full chatbot framework | [Botpress](https://botpress.com) |
|
|
358
361
|
|
|
359
362
|
Kitt stays small (0 dependencies) because it does one thing well:
|
|
360
363
|
**chat completions with tool calls, using any OpenAI-compatible endpoint.**
|
|
@@ -370,21 +373,21 @@ useInitAgent({ model: "qwen3.8-max" });
|
|
|
370
373
|
|
|
371
374
|
// Assistant — single-shot review / question.
|
|
372
375
|
const review = await useChat([
|
|
373
|
-
|
|
376
|
+
{ role: "user", content: "Summarize the benefits of solar energy in three bullet points." },
|
|
374
377
|
]);
|
|
375
378
|
if (review.ok) console.log(review.data);
|
|
376
379
|
|
|
377
380
|
// Agent — autonomous tool-calling loop that can act (read/write/run).
|
|
378
381
|
const result = await useRunAgent("Fix the type errors in src/", {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
382
|
+
tools: [
|
|
383
|
+
{
|
|
384
|
+
name: "readFile",
|
|
385
|
+
description: "Returns file contents",
|
|
386
|
+
parameters: { type: "object", properties: { path: { type: "string" } } },
|
|
387
|
+
execute: ({ path }) => fs.readFile(path, "utf8"),
|
|
388
|
+
},
|
|
389
|
+
],
|
|
390
|
+
maxSteps: 12,
|
|
388
391
|
});
|
|
389
392
|
```
|
|
390
393
|
|
|
@@ -404,20 +407,20 @@ import "dotenv/config";
|
|
|
404
407
|
import { useInitAssistant, useReply } from "katanakit-js";
|
|
405
408
|
|
|
406
409
|
useInitAssistant({
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
410
|
+
// apiKey — process.env.DASHSCOPE_API_KEY
|
|
411
|
+
// baseUrl — KITT_BASE_URL
|
|
412
|
+
// model — "qwen3.8-max"
|
|
413
|
+
// systemPrompt — KITT_SYSTEM_PROMPT
|
|
414
|
+
// store — in-memory (useCreateMemoryStore)
|
|
415
|
+
// tools — AiTool[]
|
|
416
|
+
// maxSteps — number
|
|
414
417
|
});
|
|
415
418
|
|
|
416
419
|
const result = await useReply(undefined, "What are your hours?");
|
|
417
420
|
if (result.ok) {
|
|
418
|
-
|
|
421
|
+
console.log(result.data.reply, result.data.sessionId);
|
|
419
422
|
} else {
|
|
420
|
-
|
|
423
|
+
console.error(result.error.message);
|
|
421
424
|
}
|
|
422
425
|
```
|
|
423
426
|
|
|
@@ -426,12 +429,12 @@ if (result.ok) {
|
|
|
426
429
|
|
|
427
430
|
Also on the main barrel:
|
|
428
431
|
|
|
429
|
-
| Helper
|
|
430
|
-
|
|
431
|
-
| `useCreateSession`
|
|
432
|
-
| `useGetHistory`
|
|
433
|
-
| `useResetSession`
|
|
434
|
-
| `useCreateMemoryStore` | `() => ConversationStore`
|
|
432
|
+
| Helper | Signature |
|
|
433
|
+
| ---------------------- | ------------------------------------- |
|
|
434
|
+
| `useCreateSession` | `(channel?) => Promise<string>` |
|
|
435
|
+
| `useGetHistory` | `(sessionId) => Promise<AiMessage[]>` |
|
|
436
|
+
| `useResetSession` | `(sessionId) => Promise<void>` |
|
|
437
|
+
| `useCreateMemoryStore` | `() => ConversationStore` |
|
|
435
438
|
|
|
436
439
|
Then start a channel (see below). Copy keys from [`.env.example`](https://github.com/senseikatana/katanakit/blob/main/.env.example):
|
|
437
440
|
|
|
@@ -450,11 +453,11 @@ DATABASE_URL=
|
|
|
450
453
|
|
|
451
454
|
### Run standalone (this repo)
|
|
452
455
|
|
|
453
|
-
| Script
|
|
454
|
-
|
|
455
|
-
| `bun run assistant:dev`
|
|
456
|
-
| `bun run telegram:dev`
|
|
457
|
-
| `bun run whatsapp:dev`
|
|
456
|
+
| Script | Starts |
|
|
457
|
+
| ------------------------ | --------------------------------------------------------------------------- |
|
|
458
|
+
| `bun run assistant:dev` | REST assistant. Uses Prisma when `DATABASE_URL` is set. |
|
|
459
|
+
| `bun run telegram:dev` | Telegram long polling. Requires `TELEGRAM_BOT_TOKEN`. |
|
|
460
|
+
| `bun run whatsapp:dev` | WhatsApp webhook. Requires `WHATSAPP_*`. |
|
|
458
461
|
| `bun run assistant:demo` | Demo in `examples/assistant/`. Set `KITT_CHANNEL=rest\|telegram\|whatsapp`. |
|
|
459
462
|
|
|
460
463
|
### REST
|
|
@@ -466,21 +469,21 @@ useStartAssistant(); // port?, host?, mountPath = "/assistant", options?
|
|
|
466
469
|
// or mount useCreateAssistantRouter() on an existing Express app
|
|
467
470
|
```
|
|
468
471
|
|
|
469
|
-
| Method
|
|
470
|
-
|
|
471
|
-
| `POST`
|
|
472
|
-
| `GET`
|
|
473
|
-
| `DELETE` | `/assistant/sessions/:id` | —
|
|
472
|
+
| Method | Path | Body | Response |
|
|
473
|
+
| -------- | ------------------------- | ------------------------- | ------------------------------------------- |
|
|
474
|
+
| `POST` | `/assistant/chat` | `{ sessionId?, message }` | `{ ok, data: { reply, sessionId }, error }` |
|
|
475
|
+
| `GET` | `/assistant/sessions/:id` | — | `{ sessionId, messages }` or `404` |
|
|
476
|
+
| `DELETE` | `/assistant/sessions/:id` | — | `204` or `404` |
|
|
474
477
|
|
|
475
478
|
The endpoints are **public by default**. In production pass an auth guard (applied to every
|
|
476
479
|
route). Unknown session ids return `404`, and `useReply` rejects a `sessionId` that does not exist.
|
|
477
480
|
|
|
478
481
|
```ts
|
|
479
482
|
useStartAssistant(3000, "localhost", "/assistant", {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
483
|
+
guard: (req, res, next) =>
|
|
484
|
+
req.header("authorization") === `Bearer ${process.env.ASSISTANT_API_KEY}`
|
|
485
|
+
? next()
|
|
486
|
+
: res.status(401).end(),
|
|
484
487
|
});
|
|
485
488
|
```
|
|
486
489
|
|
|
@@ -495,9 +498,12 @@ curl -X POST http://localhost:3000/assistant/chat \
|
|
|
495
498
|
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:
|
|
496
499
|
|
|
497
500
|
```ts
|
|
498
|
-
app.use(
|
|
499
|
-
|
|
500
|
-
|
|
501
|
+
app.use(
|
|
502
|
+
"/assistant",
|
|
503
|
+
useCreateAssistantRouter({
|
|
504
|
+
rateLimit: rateLimit({ windowMs: 60_000, max: 30 }),
|
|
505
|
+
}),
|
|
506
|
+
);
|
|
501
507
|
```
|
|
502
508
|
|
|
503
509
|
### Telegram (BotFather)
|
|
@@ -526,10 +532,10 @@ Webhook: `GET` / `POST` `/whatsapp/webhook`. Session ids are `wa:<phone>`.
|
|
|
526
532
|
import { useInitWhatsApp, useStartWhatsApp } from "katanakit-js/adapters/whatsapp";
|
|
527
533
|
|
|
528
534
|
useInitWhatsApp({
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
535
|
+
token: process.env.WHATSAPP_TOKEN,
|
|
536
|
+
phoneNumberId: process.env.WHATSAPP_PHONE_NUMBER_ID,
|
|
537
|
+
verifyToken: process.env.WHATSAPP_VERIFY_TOKEN,
|
|
538
|
+
appSecret: process.env.WHATSAPP_APP_SECRET,
|
|
533
539
|
});
|
|
534
540
|
useStartWhatsApp();
|
|
535
541
|
```
|
|
@@ -613,14 +619,14 @@ const result = await useGetApi("pokeapi", "pokemonById", { params: { id: 25 } })
|
|
|
613
619
|
|
|
614
620
|
```ts
|
|
615
621
|
import { useLogger, useInitApis, useGetApi } from "katanakit-js";
|
|
616
|
-
import { useRequest } from "katanakit-js/adapters/vue";
|
|
617
|
-
import { useUnwrap } from "katanakit-js/adapters/nuxt";
|
|
622
|
+
import { useRequest } from "katanakit-js/adapters/vue"; // Vue only
|
|
623
|
+
import { useUnwrap } from "katanakit-js/adapters/nuxt"; // Nuxt only
|
|
618
624
|
```
|
|
619
625
|
|
|
620
626
|
```html
|
|
621
627
|
<!-- vanilla -->
|
|
622
628
|
<script type="module">
|
|
623
|
-
|
|
629
|
+
import { useLogger } from "https://cdn.jsdelivr.net/npm/katanakit-js/+esm";
|
|
624
630
|
</script>
|
|
625
631
|
```
|
|
626
632
|
|
|
@@ -628,24 +634,24 @@ See [Getting Started](https://senseikatana.com/katanakit-js/docs/guides/getting-
|
|
|
628
634
|
|
|
629
635
|
## Framework Adapters
|
|
630
636
|
|
|
631
|
-
| Adapter
|
|
632
|
-
|
|
633
|
-
| **Express**
|
|
634
|
-
| **Nuxt**
|
|
635
|
-
| **Vue**
|
|
636
|
-
| **Astro**
|
|
637
|
-
| **Assistant** | `katanakit-js/adapters/assistant`
|
|
638
|
-
| **Telegram**
|
|
639
|
-
| **WhatsApp**
|
|
637
|
+
| Adapter | Import | Description |
|
|
638
|
+
| ------------- | ----------------------------------------------- | ------------------------------------------------------------ |
|
|
639
|
+
| **Express** | `katanakit-js/adapters/express` | Reference server with CORS and hardened headers |
|
|
640
|
+
| **Nuxt** | `katanakit-js/adapters/nuxt` | `useUnwrap`, `useSafeResponse`, `useEventResponse` |
|
|
641
|
+
| **Vue** | `katanakit-js/adapters/vue` | `useRequest` composable with reactivity |
|
|
642
|
+
| **Astro** | `katanakit-js` or `katanakit-js/adapters/astro` | `AstroService`, `RssService` |
|
|
643
|
+
| **Assistant** | `katanakit-js/adapters/assistant` | REST digital assistant (`useStartAssistant`) |
|
|
644
|
+
| **Telegram** | `katanakit-js/adapters/telegram` | BotFather bot (`useInitTelegram`, `useStartTelegramPolling`) |
|
|
645
|
+
| **WhatsApp** | `katanakit-js/adapters/whatsapp` | Meta Cloud API (`useInitWhatsApp`, `useStartWhatsApp`) |
|
|
640
646
|
|
|
641
647
|
## REST API Adapters
|
|
642
648
|
|
|
643
649
|
Typed adapters for popular REST APIs with auth, pagination helpers, and full TypeScript types.
|
|
644
650
|
All functions return `FetchResult<T>` — the same Safe Result pattern used by the HTTP client.
|
|
645
651
|
|
|
646
|
-
| Adapter
|
|
647
|
-
|
|
648
|
-
| **Notion**
|
|
652
|
+
| Adapter | Import | Description |
|
|
653
|
+
| ------------- | --------------------------------- | ----------------------------------------------------------------- |
|
|
654
|
+
| **Notion** | `katanakit-js/adapters/notion` | Pages, databases, blocks, search with cursor pagination |
|
|
649
655
|
| **WordPress** | `katanakit-js/adapters/wordpress` | Posts, pages, media, categories, tags, comments, users, batch ops |
|
|
650
656
|
|
|
651
657
|
### Notion
|
|
@@ -666,10 +672,10 @@ useInitNotion({ token: process.env.NOTION_TOKEN });
|
|
|
666
672
|
|
|
667
673
|
```ts
|
|
668
674
|
import {
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
675
|
+
useNotionGetPage,
|
|
676
|
+
useNotionCreatePage,
|
|
677
|
+
useNotionUpdatePage,
|
|
678
|
+
useNotionArchivePage,
|
|
673
679
|
} from "katanakit-js/adapters/notion";
|
|
674
680
|
|
|
675
681
|
// Get a single page with all its properties
|
|
@@ -678,24 +684,24 @@ if (page.ok) console.log(page.data.properties);
|
|
|
678
684
|
|
|
679
685
|
// Create a page inside a database
|
|
680
686
|
const created = await useNotionCreatePage(
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
687
|
+
{ type: "database_id", database_id: "db-id" },
|
|
688
|
+
{
|
|
689
|
+
Name: { title: [{ type: "text", text: { content: "My Task" } }] },
|
|
690
|
+
Status: { select: { name: "To Do" } },
|
|
691
|
+
},
|
|
686
692
|
);
|
|
687
693
|
|
|
688
694
|
// Create a child page with content blocks
|
|
689
695
|
const child = await useNotionCreatePage(
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
696
|
+
{ type: "page_id", page_id: "parent-id" },
|
|
697
|
+
{ title: { title: [{ type: "text", text: { content: "Child Page" } }] } },
|
|
698
|
+
[{ type: "paragraph", paragraph: { rich_text: [{ type: "text", text: { content: "Hello!" } }] } }],
|
|
693
699
|
);
|
|
694
700
|
|
|
695
701
|
// Update page properties (only changed fields)
|
|
696
702
|
await useNotionUpdatePage("page-id", {
|
|
697
|
-
|
|
698
|
-
|
|
703
|
+
Status: { select: { name: "Done" } },
|
|
704
|
+
DueDate: { date: { start: "2025-12-31" } },
|
|
699
705
|
});
|
|
700
706
|
|
|
701
707
|
// Archive (soft-delete) a page
|
|
@@ -706,26 +712,26 @@ await useNotionArchivePage("page-id");
|
|
|
706
712
|
|
|
707
713
|
```ts
|
|
708
714
|
import {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
715
|
+
useNotionGetDatabase,
|
|
716
|
+
useNotionQueryDatabase,
|
|
717
|
+
useNotionCreateDatabase,
|
|
718
|
+
useNotionUpdateDatabase,
|
|
719
|
+
useNotionListAllDatabasePages,
|
|
714
720
|
} from "katanakit-js/adapters/notion";
|
|
715
721
|
|
|
716
722
|
// Inspect database schema (property names, types, options)
|
|
717
723
|
const schema = await useNotionGetDatabase("db-id");
|
|
718
724
|
if (schema.ok) {
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
725
|
+
Object.entries(schema.data.properties).forEach(([name, prop]) => {
|
|
726
|
+
console.log(`${name}: ${prop.type}`);
|
|
727
|
+
});
|
|
722
728
|
}
|
|
723
729
|
|
|
724
730
|
// Query with filter + sort (single page of results)
|
|
725
731
|
const page1 = await useNotionQueryDatabase("db-id", {
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
732
|
+
filter: { property: "Status", select: { equals: "Published" } },
|
|
733
|
+
sorts: [{ property: "Date", direction: "descending" }],
|
|
734
|
+
page_size: 10,
|
|
729
735
|
});
|
|
730
736
|
|
|
731
737
|
// Get ALL pages (auto-pagination — handles cursors internally)
|
|
@@ -733,76 +739,74 @@ const all = await useNotionListAllDatabasePages("db-id");
|
|
|
733
739
|
|
|
734
740
|
// With filter + sort
|
|
735
741
|
const published = await useNotionListAllDatabasePages(
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
742
|
+
"db-id",
|
|
743
|
+
{ property: "Status", select: { equals: "Published" } },
|
|
744
|
+
[{ property: "Date", direction: "descending" }],
|
|
739
745
|
);
|
|
740
746
|
|
|
741
747
|
// Create a new database
|
|
742
748
|
await useNotionCreateDatabase(
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
749
|
+
{ type: "page_id", page_id: "parent-id" },
|
|
750
|
+
[{ type: "text", text: { content: "My Tasks" } }],
|
|
751
|
+
{
|
|
752
|
+
Name: { title: {} },
|
|
753
|
+
Status: { select: { options: [{ name: "To Do" }, { name: "Done" }] } },
|
|
754
|
+
Priority: { select: { options: [{ name: "Low" }, { name: "High" }] } },
|
|
755
|
+
},
|
|
750
756
|
);
|
|
751
757
|
|
|
752
758
|
// Rename a database
|
|
753
|
-
await useNotionUpdateDatabase("db-id", [
|
|
754
|
-
{ type: "text", text: { content: "Renamed Database" } },
|
|
755
|
-
]);
|
|
759
|
+
await useNotionUpdateDatabase("db-id", [{ type: "text", text: { content: "Renamed Database" } }]);
|
|
756
760
|
```
|
|
757
761
|
|
|
758
762
|
#### Blocks — read, write, append, delete page content
|
|
759
763
|
|
|
760
764
|
```ts
|
|
761
765
|
import {
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
766
|
+
useNotionGetBlock,
|
|
767
|
+
useNotionGetBlockChildren,
|
|
768
|
+
useNotionListAllBlockChildren,
|
|
769
|
+
useNotionAppendBlocks,
|
|
770
|
+
useNotionUpdateBlock,
|
|
771
|
+
useNotionDeleteBlock,
|
|
768
772
|
} from "katanakit-js/adapters/notion";
|
|
769
773
|
|
|
770
774
|
// Get ALL blocks of a page (auto-pagination)
|
|
771
775
|
const blocks = await useNotionListAllBlockChildren("page-id");
|
|
772
776
|
if (blocks.ok) {
|
|
773
|
-
|
|
777
|
+
blocks.data.forEach((b) => console.log(b.type)); // "paragraph", "heading_1", etc.
|
|
774
778
|
}
|
|
775
779
|
|
|
776
780
|
// Manual pagination (for fine-grained cursor control)
|
|
777
781
|
const page = await useNotionGetBlockChildren("page-id", { page_size: 50 });
|
|
778
782
|
if (page.ok) {
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
783
|
+
console.log(page.data.results); // blocks
|
|
784
|
+
console.log(page.data.has_more); // true if more pages exist
|
|
785
|
+
console.log(page.data.next_cursor); // pass as start_cursor for next page
|
|
782
786
|
}
|
|
783
787
|
|
|
784
788
|
// Append content blocks to a page
|
|
785
789
|
await useNotionAppendBlocks("page-id", [
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
790
|
+
{
|
|
791
|
+
type: "heading_2",
|
|
792
|
+
heading_2: { rich_text: [{ type: "text", text: { content: "New Section" } }] },
|
|
793
|
+
},
|
|
794
|
+
{
|
|
795
|
+
type: "paragraph",
|
|
796
|
+
paragraph: { rich_text: [{ type: "text", text: { content: "Body text here." } }] },
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
type: "to_do",
|
|
800
|
+
to_do: {
|
|
801
|
+
rich_text: [{ type: "text", text: { content: "Checklist item" } }],
|
|
802
|
+
checked: false,
|
|
803
|
+
},
|
|
804
|
+
},
|
|
801
805
|
]);
|
|
802
806
|
|
|
803
807
|
// Update a block's content
|
|
804
808
|
await useNotionUpdateBlock("block-id", {
|
|
805
|
-
|
|
809
|
+
paragraph: { rich_text: [{ type: "text", text: { content: "Updated text" } }] },
|
|
806
810
|
});
|
|
807
811
|
|
|
808
812
|
// Delete (archive) a block
|
|
@@ -819,14 +823,14 @@ const found = await useNotionSearchContent({ query: "meeting notes" });
|
|
|
819
823
|
|
|
820
824
|
// Search only databases
|
|
821
825
|
const dbs = await useNotionSearchContent({
|
|
822
|
-
|
|
823
|
-
|
|
826
|
+
query: "tasks",
|
|
827
|
+
filter: { value: "database", property: "object" },
|
|
824
828
|
});
|
|
825
829
|
|
|
826
830
|
// Search only pages, sorted by recently edited
|
|
827
831
|
const pages = await useNotionSearchContent({
|
|
828
|
-
|
|
829
|
-
|
|
832
|
+
filter: { value: "page", property: "object" },
|
|
833
|
+
sort: { direction: "descending", timestamp: "last_edited_time" },
|
|
830
834
|
});
|
|
831
835
|
```
|
|
832
836
|
|
|
@@ -841,22 +845,22 @@ if (user.ok) console.log(user.data.name);
|
|
|
841
845
|
|
|
842
846
|
// List all workspace members + bots
|
|
843
847
|
const users = await useNotionListUsers();
|
|
844
|
-
if (users.ok) users.data.results.forEach(u => console.log(u.name));
|
|
848
|
+
if (users.ok) users.data.results.forEach((u) => console.log(u.name));
|
|
845
849
|
```
|
|
846
850
|
|
|
847
851
|
#### Framework examples
|
|
848
852
|
|
|
849
|
-
| Framework
|
|
850
|
-
|
|
851
|
-
| **Vue 3**
|
|
852
|
-
| **Vue 3**
|
|
853
|
-
| **Nuxt 3**
|
|
854
|
-
| **Nuxt 3**
|
|
855
|
-
| **Astro**
|
|
856
|
-
| **Astro**
|
|
857
|
-
| **Next.js** | [`examples/notion/next-blog.tsx`](https://github.com/senseikatana/katanakit/tree/main/examples/notion/next-blog.tsx)
|
|
858
|
-
| **Next.js** | [`examples/notion/next-[slug].tsx`](https://github.com/senseikatana/katanakit/tree/main/examples/notion/next-[slug].tsx)
|
|
859
|
-
| **Node.js** | [`examples/notion/demo.ts`](https://github.com/senseikatana/katanakit/tree/main/examples/notion/demo.ts)
|
|
853
|
+
| Framework | Example | Description |
|
|
854
|
+
| ----------- | ------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- |
|
|
855
|
+
| **Vue 3** | [`examples/notion/vue-blog.vue`](https://github.com/senseikatana/katanakit/tree/main/examples/notion/vue-blog.vue) | Blog listing with `useQuery` composable |
|
|
856
|
+
| **Vue 3** | [`examples/notion/vue-post.vue`](https://github.com/senseikatana/katanakit/tree/main/examples/notion/vue-post.vue) | Single post view |
|
|
857
|
+
| **Nuxt 3** | [`examples/notion/nuxt-blog.vue`](https://github.com/senseikatana/katanakit/tree/main/examples/notion/nuxt-blog.vue) | SSR blog listing with `useAsyncData` |
|
|
858
|
+
| **Nuxt 3** | [`examples/notion/nuxt-post.vue`](https://github.com/senseikatana/katanakit/tree/main/examples/notion/nuxt-post.vue) | SSR single post view |
|
|
859
|
+
| **Astro** | [`examples/notion/astro-blog.astro`](https://github.com/senseikatana/katanakit/tree/main/examples/notion/astro-blog.astro) | Static blog listing |
|
|
860
|
+
| **Astro** | [`examples/notion/astro-[slug].astro`](https://github.com/senseikatana/katanakit/tree/main/examples/notion/astro-[slug].astro) | Dynamic `[slug]` route |
|
|
861
|
+
| **Next.js** | [`examples/notion/next-blog.tsx`](https://github.com/senseikatana/katanakit/tree/main/examples/notion/next-blog.tsx) | Server component blog listing |
|
|
862
|
+
| **Next.js** | [`examples/notion/next-[slug].tsx`](https://github.com/senseikatana/katanakit/tree/main/examples/notion/next-[slug].tsx) | Dynamic `[slug]` page |
|
|
863
|
+
| **Node.js** | [`examples/notion/demo.ts`](https://github.com/senseikatana/katanakit/tree/main/examples/notion/demo.ts) | Runnable demo covering all Notion operations |
|
|
860
864
|
|
|
861
865
|
### WordPress
|
|
862
866
|
|
|
@@ -871,20 +875,20 @@ import { useInitWordPress } from "katanakit-js/adapters/wordpress";
|
|
|
871
875
|
|
|
872
876
|
// Application Passwords (recommended) — WP Admin → Users → Your Profile → Application Passwords
|
|
873
877
|
useInitWordPress({
|
|
874
|
-
|
|
875
|
-
|
|
878
|
+
baseUrl: "https://mysite.com",
|
|
879
|
+
auth: { type: "application-passwords", username: "admin", password: "xxxx xxxx xxxx" },
|
|
876
880
|
});
|
|
877
881
|
|
|
878
882
|
// JWT tokens
|
|
879
883
|
useInitWordPress({
|
|
880
|
-
|
|
881
|
-
|
|
884
|
+
baseUrl: "https://mysite.com",
|
|
885
|
+
auth: { type: "jwt", token: "eyJhbGci..." },
|
|
882
886
|
});
|
|
883
887
|
|
|
884
888
|
// Nonce-based (for WP themes)
|
|
885
889
|
useInitWordPress({
|
|
886
|
-
|
|
887
|
-
|
|
890
|
+
baseUrl: "https://mysite.com",
|
|
891
|
+
auth: { type: "nonce", nonce: "abc123" },
|
|
888
892
|
});
|
|
889
893
|
```
|
|
890
894
|
|
|
@@ -892,22 +896,22 @@ useInitWordPress({
|
|
|
892
896
|
|
|
893
897
|
```ts
|
|
894
898
|
import {
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
899
|
+
useWpGetPosts,
|
|
900
|
+
useWpGetPost,
|
|
901
|
+
useWpCreatePost,
|
|
902
|
+
useWpUpdatePost,
|
|
903
|
+
useWpDeletePost,
|
|
904
|
+
useWpListAllPosts,
|
|
905
|
+
useWpSearchAllPosts,
|
|
906
|
+
useWpFindPostBySlug,
|
|
903
907
|
} from "katanakit-js/adapters/wordpress";
|
|
904
908
|
|
|
905
909
|
// List published posts (paginated)
|
|
906
910
|
const posts = await useWpGetPosts({
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
+
per_page: 5,
|
|
912
|
+
status: "publish",
|
|
913
|
+
orderby: "date",
|
|
914
|
+
order: "desc",
|
|
911
915
|
});
|
|
912
916
|
|
|
913
917
|
// Get a single post with embedded resources
|
|
@@ -916,19 +920,19 @@ if (post.ok) console.log(post.data.title.rendered);
|
|
|
916
920
|
|
|
917
921
|
// Create a post
|
|
918
922
|
await useWpCreatePost({
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
923
|
+
title: "My New Post",
|
|
924
|
+
content: "<p>Hello World!</p>",
|
|
925
|
+
status: "publish", // "draft" | "pending" | "publish"
|
|
926
|
+
categories: [1, 3],
|
|
927
|
+
tags: [5, 8],
|
|
924
928
|
});
|
|
925
929
|
|
|
926
930
|
// Update a post
|
|
927
931
|
await useWpUpdatePost(42, { title: "Updated Title", status: "publish" });
|
|
928
932
|
|
|
929
933
|
// Delete (trash or permanent)
|
|
930
|
-
await useWpDeletePost(42);
|
|
931
|
-
await useWpDeletePost(42, true);
|
|
934
|
+
await useWpDeletePost(42); // move to trash
|
|
935
|
+
await useWpDeletePost(42, true); // permanently delete
|
|
932
936
|
|
|
933
937
|
// Get ALL posts (auto-pagination — loops until exhausted)
|
|
934
938
|
const all = await useWpListAllPosts({ status: "publish" });
|
|
@@ -936,7 +940,7 @@ if (all.ok) console.log(`Total: ${all.data.length}`);
|
|
|
936
940
|
|
|
937
941
|
// Search ALL posts by keyword
|
|
938
942
|
const found = await useWpSearchAllPosts("tutorial");
|
|
939
|
-
if (found.ok) found.data.forEach(p => console.log(p.title.rendered));
|
|
943
|
+
if (found.ok) found.data.forEach((p) => console.log(p.title.rendered));
|
|
940
944
|
|
|
941
945
|
// Find post by slug (for dynamic routes like /blog/:slug)
|
|
942
946
|
const bySlug = await useWpFindPostBySlug("hello-world");
|
|
@@ -947,11 +951,11 @@ if (bySlug.ok && bySlug.data) console.log(bySlug.data.title.rendered);
|
|
|
947
951
|
|
|
948
952
|
```ts
|
|
949
953
|
import {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
954
|
+
useWpGetPages,
|
|
955
|
+
useWpGetPage,
|
|
956
|
+
useWpCreatePage,
|
|
957
|
+
useWpUpdatePage,
|
|
958
|
+
useWpDeletePage,
|
|
955
959
|
} from "katanakit-js/adapters/wordpress";
|
|
956
960
|
|
|
957
961
|
const pages = await useWpGetPages({ per_page: 20 });
|
|
@@ -960,10 +964,10 @@ const page = await useWpGetPage(10);
|
|
|
960
964
|
if (page.ok) console.log(page.data.title.rendered);
|
|
961
965
|
|
|
962
966
|
await useWpCreatePage({
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
+
title: "About Us",
|
|
968
|
+
content: "<p>Welcome to our site!</p>",
|
|
969
|
+
status: "publish",
|
|
970
|
+
parent: 0, // top-level page (set a page ID for child pages)
|
|
967
971
|
});
|
|
968
972
|
|
|
969
973
|
await useWpUpdatePage(10, { title: "Updated About" });
|
|
@@ -974,11 +978,11 @@ await useWpDeletePage(10); // trash
|
|
|
974
978
|
|
|
975
979
|
```ts
|
|
976
980
|
import {
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
981
|
+
useWpGetMedia,
|
|
982
|
+
useWpGetMediaItem,
|
|
983
|
+
useWpUploadMedia,
|
|
984
|
+
useWpUpdateMedia,
|
|
985
|
+
useWpDeleteMedia,
|
|
982
986
|
} from "katanakit-js/adapters/wordpress";
|
|
983
987
|
|
|
984
988
|
// List media items
|
|
@@ -991,9 +995,9 @@ if (item.ok) console.log(item.data.source_url);
|
|
|
991
995
|
// Upload from browser (File from <input type="file">)
|
|
992
996
|
const file = document.querySelector("input[type=file]").files[0];
|
|
993
997
|
const uploaded = await useWpUploadMedia(file, {
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
998
|
+
title: "My Image",
|
|
999
|
+
alt_text: "Description for accessibility",
|
|
1000
|
+
caption: "Image caption",
|
|
997
1001
|
});
|
|
998
1002
|
if (uploaded.ok) console.log(uploaded.data.source_url); // URL to use in content
|
|
999
1003
|
|
|
@@ -1013,10 +1017,16 @@ await useWpDeleteMedia(42, true); // permanent
|
|
|
1013
1017
|
|
|
1014
1018
|
```ts
|
|
1015
1019
|
import {
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
+
useWpGetCategories,
|
|
1021
|
+
useWpGetCategory,
|
|
1022
|
+
useWpCreateCategory,
|
|
1023
|
+
useWpUpdateCategory,
|
|
1024
|
+
useWpDeleteCategory,
|
|
1025
|
+
useWpGetTags,
|
|
1026
|
+
useWpGetTag,
|
|
1027
|
+
useWpCreateTag,
|
|
1028
|
+
useWpUpdateTag,
|
|
1029
|
+
useWpDeleteTag,
|
|
1020
1030
|
} from "katanakit-js/adapters/wordpress";
|
|
1021
1031
|
|
|
1022
1032
|
// Categories
|
|
@@ -1036,8 +1046,11 @@ await useWpDeleteTag(12);
|
|
|
1036
1046
|
|
|
1037
1047
|
```ts
|
|
1038
1048
|
import {
|
|
1039
|
-
|
|
1040
|
-
|
|
1049
|
+
useWpGetComments,
|
|
1050
|
+
useWpGetComment,
|
|
1051
|
+
useWpCreateComment,
|
|
1052
|
+
useWpUpdateComment,
|
|
1053
|
+
useWpDeleteComment,
|
|
1041
1054
|
} from "katanakit-js/adapters/wordpress";
|
|
1042
1055
|
|
|
1043
1056
|
// Get comments for a post
|
|
@@ -1045,10 +1058,10 @@ const comments = await useWpGetComments({ post: 42, per_page: 10 });
|
|
|
1045
1058
|
|
|
1046
1059
|
// Create a comment (public or authenticated)
|
|
1047
1060
|
await useWpCreateComment({
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1061
|
+
post: 42,
|
|
1062
|
+
content: "Great article!",
|
|
1063
|
+
author_name: "John",
|
|
1064
|
+
author_email: "john@example.com",
|
|
1052
1065
|
});
|
|
1053
1066
|
|
|
1054
1067
|
// Update / delete
|
|
@@ -1060,18 +1073,22 @@ await useWpDeleteComment(7);
|
|
|
1060
1073
|
|
|
1061
1074
|
```ts
|
|
1062
1075
|
import {
|
|
1063
|
-
|
|
1064
|
-
|
|
1076
|
+
useWpGetUsers,
|
|
1077
|
+
useWpGetUser,
|
|
1078
|
+
useWpGetCurrentUser,
|
|
1079
|
+
useWpCreateUser,
|
|
1080
|
+
useWpUpdateUser,
|
|
1081
|
+
useWpDeleteUser,
|
|
1065
1082
|
} from "katanakit-js/adapters/wordpress";
|
|
1066
1083
|
|
|
1067
1084
|
const users = await useWpGetUsers({ roles: "editor" });
|
|
1068
1085
|
const me = await useWpGetCurrentUser(); // authenticated user
|
|
1069
1086
|
|
|
1070
1087
|
await useWpCreateUser({
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1088
|
+
username: "johndoe",
|
|
1089
|
+
email: "john@example.com",
|
|
1090
|
+
password: "secure-password",
|
|
1091
|
+
roles: ["editor"],
|
|
1075
1092
|
});
|
|
1076
1093
|
|
|
1077
1094
|
await useWpUpdateUser(2, { name: "John Smith" });
|
|
@@ -1082,8 +1099,11 @@ await useWpDeleteUser(2, 1); // reassign content to user 1
|
|
|
1082
1099
|
|
|
1083
1100
|
```ts
|
|
1084
1101
|
import {
|
|
1085
|
-
|
|
1086
|
-
|
|
1102
|
+
useWpGetCustomPosts,
|
|
1103
|
+
useWpGetCustomPost,
|
|
1104
|
+
useWpCreateCustomPost,
|
|
1105
|
+
useWpUpdateCustomPost,
|
|
1106
|
+
useWpDeleteCustomPost,
|
|
1087
1107
|
} from "katanakit-js/adapters/wordpress";
|
|
1088
1108
|
|
|
1089
1109
|
// Works with any registered CPT: "product", "portfolio", "event", etc.
|
|
@@ -1091,9 +1111,9 @@ const products = await useWpGetCustomPosts("product", { per_page: 10 });
|
|
|
1091
1111
|
const product = await useWpGetCustomPost("product", 15);
|
|
1092
1112
|
|
|
1093
1113
|
await useWpCreateCustomPost("product", {
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1114
|
+
title: "Widget",
|
|
1115
|
+
content: "<p>A great widget</p>",
|
|
1116
|
+
status: "publish",
|
|
1097
1117
|
});
|
|
1098
1118
|
|
|
1099
1119
|
await useWpUpdateCustomPost("product", 15, { title: "Updated Widget" });
|
|
@@ -1106,13 +1126,13 @@ await useWpDeleteCustomPost("product", 15, true);
|
|
|
1106
1126
|
import { useWpBatch } from "katanakit-js/adapters/wordpress";
|
|
1107
1127
|
|
|
1108
1128
|
const result = await useWpBatch([
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1129
|
+
{ method: "GET", path: "/wp/v2/posts?per_page=2" },
|
|
1130
|
+
{ method: "GET", path: "/wp/v2/pages?per_page=2" },
|
|
1131
|
+
{ method: "GET", path: "/wp/v2/categories?per_page=5" },
|
|
1112
1132
|
]);
|
|
1113
1133
|
|
|
1114
1134
|
if (result.ok) {
|
|
1115
|
-
|
|
1135
|
+
result.data.responses.forEach((resp) => console.log(resp.status));
|
|
1116
1136
|
}
|
|
1117
1137
|
```
|
|
1118
1138
|
|
|
@@ -1124,8 +1144,8 @@ significantly for list views.
|
|
|
1124
1144
|
```ts
|
|
1125
1145
|
// Only fetch id, title, link, slug, and date
|
|
1126
1146
|
const posts = await useWpGetPosts({
|
|
1127
|
-
|
|
1128
|
-
|
|
1147
|
+
per_page: 20,
|
|
1148
|
+
_fields: "id,title,link,slug,date",
|
|
1129
1149
|
});
|
|
1130
1150
|
```
|
|
1131
1151
|
|
|
@@ -1140,16 +1160,17 @@ const posts = await useWpGetPosts({ _embed: true });
|
|
|
1140
1160
|
|
|
1141
1161
|
// Embed only specific resources
|
|
1142
1162
|
const posts = await useWpGetPosts({
|
|
1143
|
-
|
|
1163
|
+
_embed: "author,wp:featuredmedia",
|
|
1144
1164
|
});
|
|
1145
1165
|
|
|
1146
1166
|
// Access embedded data
|
|
1147
1167
|
if (posts.ok) {
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1168
|
+
for (const post of posts.data) {
|
|
1169
|
+
const author = post._embedded?.author?.[0]?.name;
|
|
1170
|
+
const image = post._embedded?.["wp:featuredmedia"]?.[0]?.source_url;
|
|
1171
|
+
const thumbnail =
|
|
1172
|
+
post._embedded?.["wp:featuredmedia"]?.[0]?.media_details?.sizes?.thumbnail?.source_url;
|
|
1173
|
+
}
|
|
1153
1174
|
}
|
|
1154
1175
|
```
|
|
1155
1176
|
|
|
@@ -1162,40 +1183,40 @@ media item, or custom post type entry.
|
|
|
1162
1183
|
```ts
|
|
1163
1184
|
// Request ACF fields explicitly with _fields
|
|
1164
1185
|
const posts = await useWpGetPosts({
|
|
1165
|
-
|
|
1166
|
-
|
|
1186
|
+
per_page: 5,
|
|
1187
|
+
_fields: "id,title,acf",
|
|
1167
1188
|
});
|
|
1168
1189
|
|
|
1169
1190
|
if (posts.ok) {
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1191
|
+
for (const post of posts.data) {
|
|
1192
|
+
if (post.acf) {
|
|
1193
|
+
// ACF fields are dynamic — access by field name
|
|
1194
|
+
console.log(post.acf.my_field_name);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1176
1197
|
}
|
|
1177
1198
|
|
|
1178
1199
|
// Combine _fields + _embed + ACF for full-featured list views
|
|
1179
1200
|
const full = await useWpGetPosts({
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1201
|
+
per_page: 5,
|
|
1202
|
+
_fields: "id,title,link,slug,date,acf",
|
|
1203
|
+
_embed: "author,wp:featuredmedia",
|
|
1183
1204
|
});
|
|
1184
1205
|
```
|
|
1185
1206
|
|
|
1186
1207
|
#### Framework examples
|
|
1187
1208
|
|
|
1188
|
-
| Framework
|
|
1189
|
-
|
|
1190
|
-
| **Vue 3**
|
|
1191
|
-
| **Vue 3**
|
|
1192
|
-
| **Nuxt 3**
|
|
1193
|
-
| **Nuxt 3**
|
|
1194
|
-
| **Astro**
|
|
1195
|
-
| **Astro**
|
|
1196
|
-
| **Next.js** | [`examples/wordpress/next-blog.tsx`](https://github.com/senseikatana/katanakit/tree/main/examples/wordpress/next-blog.tsx)
|
|
1197
|
-
| **Next.js** | [`examples/wordpress/next-[slug].tsx`](https://github.com/senseikatana/katanakit/tree/main/examples/wordpress/next-[slug].tsx)
|
|
1198
|
-
| **Node.js** | [`examples/wordpress/demo.ts`](https://github.com/senseikatana/katanakit/tree/main/examples/wordpress/demo.ts)
|
|
1209
|
+
| Framework | Example | Description |
|
|
1210
|
+
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------ |
|
|
1211
|
+
| **Vue 3** | [`examples/wordpress/vue-blog.vue`](https://github.com/senseikatana/katanakit/tree/main/examples/wordpress/vue-blog.vue) | Blog listing with categories, featured images, `_embed` |
|
|
1212
|
+
| **Vue 3** | [`examples/wordpress/vue-post.vue`](https://github.com/senseikatana/katanakit/tree/main/examples/wordpress/vue-post.vue) | Single post view with embedded author |
|
|
1213
|
+
| **Nuxt 3** | [`examples/wordpress/nuxt-blog.vue`](https://github.com/senseikatana/katanakit/tree/main/examples/wordpress/nuxt-blog.vue) | SSR blog listing with `useAsyncData` |
|
|
1214
|
+
| **Nuxt 3** | [`examples/wordpress/nuxt-post.vue`](https://github.com/senseikatana/katanakit/tree/main/examples/wordpress/nuxt-post.vue) | SSR single post view |
|
|
1215
|
+
| **Astro** | [`examples/wordpress/astro-blog.astro`](https://github.com/senseikatana/katanakit/tree/main/examples/wordpress/astro-blog.astro) | Static blog listing |
|
|
1216
|
+
| **Astro** | [`examples/wordpress/astro-[slug].astro`](https://github.com/senseikatana/katanakit/tree/main/examples/wordpress/astro-[slug].astro) | Dynamic `[slug]` route |
|
|
1217
|
+
| **Next.js** | [`examples/wordpress/next-blog.tsx`](https://github.com/senseikatana/katanakit/tree/main/examples/wordpress/next-blog.tsx) | Server component blog listing |
|
|
1218
|
+
| **Next.js** | [`examples/wordpress/next-[slug].tsx`](https://github.com/senseikatana/katanakit/tree/main/examples/wordpress/next-[slug].tsx) | Dynamic `[slug]` page |
|
|
1219
|
+
| **Node.js** | [`examples/wordpress/demo.ts`](https://github.com/senseikatana/katanakit/tree/main/examples/wordpress/demo.ts) | Runnable demo covering all WP operations, `_fields`, `_embed`, ACF |
|
|
1199
1220
|
|
|
1200
1221
|
## Contributing
|
|
1201
1222
|
|