@kywi-software/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +172 -0
- package/dist/__tests__/auth-client.test.d.ts +2 -0
- package/dist/__tests__/auth-client.test.d.ts.map +1 -0
- package/dist/__tests__/auth-client.test.js +97 -0
- package/dist/__tests__/auth-client.test.js.map +1 -0
- package/dist/__tests__/content-client.test.d.ts +2 -0
- package/dist/__tests__/content-client.test.d.ts.map +1 -0
- package/dist/__tests__/content-client.test.js +178 -0
- package/dist/__tests__/content-client.test.js.map +1 -0
- package/dist/__tests__/create-sdk.test.d.ts +2 -0
- package/dist/__tests__/create-sdk.test.d.ts.map +1 -0
- package/dist/__tests__/create-sdk.test.js +86 -0
- package/dist/__tests__/create-sdk.test.js.map +1 -0
- package/dist/__tests__/feed-client.test.d.ts +2 -0
- package/dist/__tests__/feed-client.test.d.ts.map +1 -0
- package/dist/__tests__/feed-client.test.js +81 -0
- package/dist/__tests__/feed-client.test.js.map +1 -0
- package/dist/__tests__/hooks.test.d.ts +2 -0
- package/dist/__tests__/hooks.test.d.ts.map +1 -0
- package/dist/__tests__/hooks.test.js +123 -0
- package/dist/__tests__/hooks.test.js.map +1 -0
- package/dist/__tests__/http-client.test.d.ts +2 -0
- package/dist/__tests__/http-client.test.d.ts.map +1 -0
- package/dist/__tests__/http-client.test.js +164 -0
- package/dist/__tests__/http-client.test.js.map +1 -0
- package/dist/__tests__/i18n-client.test.d.ts +2 -0
- package/dist/__tests__/i18n-client.test.d.ts.map +1 -0
- package/dist/__tests__/i18n-client.test.js +73 -0
- package/dist/__tests__/i18n-client.test.js.map +1 -0
- package/dist/__tests__/media-client.test.d.ts +2 -0
- package/dist/__tests__/media-client.test.d.ts.map +1 -0
- package/dist/__tests__/media-client.test.js +115 -0
- package/dist/__tests__/media-client.test.js.map +1 -0
- package/dist/__tests__/nav-client.test.d.ts +2 -0
- package/dist/__tests__/nav-client.test.d.ts.map +1 -0
- package/dist/__tests__/nav-client.test.js +81 -0
- package/dist/__tests__/nav-client.test.js.map +1 -0
- package/dist/__tests__/sdk-scope-additions.test.d.ts +2 -0
- package/dist/__tests__/sdk-scope-additions.test.d.ts.map +1 -0
- package/dist/__tests__/sdk-scope-additions.test.js +420 -0
- package/dist/__tests__/sdk-scope-additions.test.js.map +1 -0
- package/dist/__tests__/site-client.test.d.ts +2 -0
- package/dist/__tests__/site-client.test.d.ts.map +1 -0
- package/dist/__tests__/site-client.test.js +52 -0
- package/dist/__tests__/site-client.test.js.map +1 -0
- package/dist/__tests__/user-client.test.d.ts +2 -0
- package/dist/__tests__/user-client.test.d.ts.map +1 -0
- package/dist/__tests__/user-client.test.js +51 -0
- package/dist/__tests__/user-client.test.js.map +1 -0
- package/dist/auth-client.d.ts +10 -0
- package/dist/auth-client.d.ts.map +1 -0
- package/dist/auth-client.js +34 -0
- package/dist/auth-client.js.map +1 -0
- package/dist/category-client.d.ts +4 -0
- package/dist/category-client.d.ts.map +1 -0
- package/dist/category-client.js +36 -0
- package/dist/category-client.js.map +1 -0
- package/dist/content-client.d.ts +4 -0
- package/dist/content-client.d.ts.map +1 -0
- package/dist/content-client.js +89 -0
- package/dist/content-client.js.map +1 -0
- package/dist/create-sdk.d.ts +3 -0
- package/dist/create-sdk.d.ts.map +1 -0
- package/dist/create-sdk.js +43 -0
- package/dist/create-sdk.js.map +1 -0
- package/dist/feed-client.d.ts +4 -0
- package/dist/feed-client.d.ts.map +1 -0
- package/dist/feed-client.js +64 -0
- package/dist/feed-client.js.map +1 -0
- package/dist/form-client.d.ts +4 -0
- package/dist/form-client.d.ts.map +1 -0
- package/dist/form-client.js +17 -0
- package/dist/form-client.js.map +1 -0
- package/dist/hooks/context.d.ts +8 -0
- package/dist/hooks/context.d.ts.map +1 -0
- package/dist/hooks/context.js +15 -0
- package/dist/hooks/context.js.map +1 -0
- package/dist/hooks/index.d.ts +8 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +7 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/use-content.d.ts +13 -0
- package/dist/hooks/use-content.d.ts.map +1 -0
- package/dist/hooks/use-content.js +16 -0
- package/dist/hooks/use-content.js.map +1 -0
- package/dist/hooks/use-feed.d.ts +5 -0
- package/dist/hooks/use-feed.d.ts.map +1 -0
- package/dist/hooks/use-feed.js +13 -0
- package/dist/hooks/use-feed.js.map +1 -0
- package/dist/hooks/use-nav.d.ts +5 -0
- package/dist/hooks/use-nav.d.ts.map +1 -0
- package/dist/hooks/use-nav.js +12 -0
- package/dist/hooks/use-nav.js.map +1 -0
- package/dist/hooks/use-sdk-query.d.ts +8 -0
- package/dist/hooks/use-sdk-query.d.ts.map +1 -0
- package/dist/hooks/use-sdk-query.js +32 -0
- package/dist/hooks/use-sdk-query.js.map +1 -0
- package/dist/hooks-client.d.ts +4 -0
- package/dist/hooks-client.d.ts.map +1 -0
- package/dist/hooks-client.js +20 -0
- package/dist/hooks-client.js.map +1 -0
- package/dist/http-client.d.ts +14 -0
- package/dist/http-client.d.ts.map +1 -0
- package/dist/http-client.js +78 -0
- package/dist/http-client.js.map +1 -0
- package/dist/i18n-client.d.ts +3 -0
- package/dist/i18n-client.d.ts.map +1 -0
- package/dist/i18n-client.js +26 -0
- package/dist/i18n-client.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/layout-client.d.ts +4 -0
- package/dist/layout-client.d.ts.map +1 -0
- package/dist/layout-client.js +17 -0
- package/dist/layout-client.js.map +1 -0
- package/dist/media-client.d.ts +4 -0
- package/dist/media-client.d.ts.map +1 -0
- package/dist/media-client.js +36 -0
- package/dist/media-client.js.map +1 -0
- package/dist/nav-client.d.ts +4 -0
- package/dist/nav-client.d.ts.map +1 -0
- package/dist/nav-client.js +36 -0
- package/dist/nav-client.js.map +1 -0
- package/dist/search-client.d.ts +4 -0
- package/dist/search-client.d.ts.map +1 -0
- package/dist/search-client.js +17 -0
- package/dist/search-client.js.map +1 -0
- package/dist/site-client.d.ts +4 -0
- package/dist/site-client.d.ts.map +1 -0
- package/dist/site-client.js +25 -0
- package/dist/site-client.js.map +1 -0
- package/dist/tree-client.d.ts +4 -0
- package/dist/tree-client.d.ts.map +1 -0
- package/dist/tree-client.js +22 -0
- package/dist/tree-client.js.map +1 -0
- package/dist/types.d.ts +367 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -0
- package/dist/user-client.d.ts +4 -0
- package/dist/user-client.d.ts.map +1 -0
- package/dist/user-client.js +49 -0
- package/dist/user-client.js.map +1 -0
- package/dist/version-client.d.ts +4 -0
- package/dist/version-client.d.ts.map +1 -0
- package/dist/version-client.js +16 -0
- package/dist/version-client.js.map +1 -0
- package/dist/workflow-client.d.ts +4 -0
- package/dist/workflow-client.d.ts.map +1 -0
- package/dist/workflow-client.js +17 -0
- package/dist/workflow-client.js.map +1 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# @kywi-software/sdk
|
|
2
|
+
|
|
3
|
+
A standalone HTTP client for the Kywi CMS REST API (`/api/v1/*`). Pure `fetch`
|
|
4
|
+
under the hood, no runtime dependency on `@kywi-software/core` — usable from a headless
|
|
5
|
+
frontend, a separate Node service, or any React app under `./hooks`.
|
|
6
|
+
|
|
7
|
+
Every export below is read from `packages/sdk/src/*.ts` and its tests
|
|
8
|
+
(`packages/sdk/src/__tests__/*.test.ts`); if this file and the source ever
|
|
9
|
+
disagree, the source wins.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @kywi-software/sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Inside this monorepo the package is linked via the workspace protocol.
|
|
18
|
+
`pnpm --filter @kywi-software/sdk build` compiles `src/` to `dist/` via
|
|
19
|
+
`tsc`; `exports` in `package.json` points `.` at `dist/index.js` and
|
|
20
|
+
`./hooks` at `dist/hooks/index.js`. `react`/`react-dom` are optional peer
|
|
21
|
+
dependencies, only needed for `./hooks`.
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { createKywiSdk } from '@kywi-software/sdk'
|
|
27
|
+
|
|
28
|
+
const kywi = createKywiSdk({
|
|
29
|
+
baseUrl: 'https://example.com/api/v1',
|
|
30
|
+
// one of:
|
|
31
|
+
apiKey: 'kywi_xxxxxxxx', // a Kywi API key (from /admin/web-services/api-keys)
|
|
32
|
+
// token: '<jwt>', // or a JWT access token (e.g. from kywi.auth.login())
|
|
33
|
+
defaultSiteId: 'default', // used when a call omits siteId
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const page = await kywi.content.getBySlug('about')
|
|
37
|
+
const nav = await kywi.nav.getTree()
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Authentication — how the API key / token actually rides on the request
|
|
41
|
+
|
|
42
|
+
`KywiHttpClient` (`src/http-client.ts`) puts **both** `apiKey` and `token` on
|
|
43
|
+
the `Authorization: Bearer <value>` header — there is no `x-api-key` header.
|
|
44
|
+
This matches the server: `resolveAuth` reads `Authorization: Bearer <token>`
|
|
45
|
+
and treats a value with the `kywi_` prefix as an API key, anything else as a
|
|
46
|
+
JWT. If both `apiKey` and `token` are set, `token` wins (it's applied last in
|
|
47
|
+
the constructor).
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
// API key
|
|
51
|
+
createKywiSdk({ baseUrl, apiKey: 'kywi_xxxxxxxx' })
|
|
52
|
+
|
|
53
|
+
// JWT (e.g. after auth.login())
|
|
54
|
+
const { accessToken } = await kywi.auth.login('user@example.com', 'password')
|
|
55
|
+
createKywiSdk({ baseUrl, token: accessToken })
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`auth.refresh()` and manual token rotation update the client via
|
|
59
|
+
`http.setToken(newToken)` (not exposed on the scope object directly — call it
|
|
60
|
+
on a `KywiHttpClient` instance you construct yourself if you need to swap
|
|
61
|
+
tokens on a long-lived client without rebuilding the whole SDK).
|
|
62
|
+
|
|
63
|
+
### Every success response unwraps `{ data }`
|
|
64
|
+
|
|
65
|
+
The Kywi API wraps every success body in `{ data: … }` (list endpoints add
|
|
66
|
+
`{ data, meta }`) and every error in `{ error: { code, message, details? } }`
|
|
67
|
+
(`jsonOk`/`jsonError` server-side). **Every SDK client — including
|
|
68
|
+
`auth`, added after the original scopes — unwraps `res.data`** so callers get
|
|
69
|
+
plain values (`ContentItem`, `AuthResult`, etc.), never the envelope. A 404 is
|
|
70
|
+
returned as the parsed `{ error }` body rather than thrown, which most clients
|
|
71
|
+
turn into `null` (e.g. `content.getById`, `content.getBySlug`); a non-OK,
|
|
72
|
+
non-404 response throws `KywiSdkError` with `.status` and `.body`.
|
|
73
|
+
|
|
74
|
+
### `siteId` goes on the query string, not the request body
|
|
75
|
+
|
|
76
|
+
`content.create()` resolves `siteId` (explicit arg, else `config.defaultSiteId`)
|
|
77
|
+
and appends it as a query param — `POST /content/page?siteId=default` — not as
|
|
78
|
+
a body field. The server's create schema is `.strict()`, so a `siteId` key
|
|
79
|
+
inside the JSON body is rejected with 400. Every read/list method
|
|
80
|
+
(`getBySlug`, `list`, …) also sends `siteId` as a query param, for consistency.
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
// Correct — siteId is threaded through as a query param internally
|
|
84
|
+
await kywi.content.create('page', { title: 'New Page' }, 'site-b-corp')
|
|
85
|
+
|
|
86
|
+
// Do NOT do this — { siteId } inside `data` would be a plain field write,
|
|
87
|
+
// and the server itself would 400 on an unknown strict-schema key.
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Scopes
|
|
91
|
+
|
|
92
|
+
`createKywiSdk()` returns a `KywiSdkScope` (`src/types.ts`) with these
|
|
93
|
+
sub-scopes, all HTTP-backed except `i18n` (client-side only, from
|
|
94
|
+
pre-loaded bundles):
|
|
95
|
+
|
|
96
|
+
| Scope | Methods | Notes |
|
|
97
|
+
|---|---|---|
|
|
98
|
+
| `auth` | `login`, `register`, `refresh`, `forgotPassword`, `resetPassword`, `logout` | `src/auth-client.ts` |
|
|
99
|
+
| `content` | `getBySlug`, `getById`, `getChildren`, `list`, `create`, `update`, `delete`, `publish`, `unpublish` | type-agnostic ops (`getById`/`delete`/`publish`/`unpublish`/`getChildren`) hit `/content/by-id/:id*`; typed ops (`list`/`create`/`update`) hit `/content/:type*` |
|
|
100
|
+
| `nav` | `getTree`, `getBreadcrumbs`, `getChildren` | |
|
|
101
|
+
| `site` | `getConfig`, `list`, `updateSettings` | |
|
|
102
|
+
| `user` | `getCurrent`, `getById`, `list`, `create` | |
|
|
103
|
+
| `feeds` | `query`, `get`, `list`, `create`, `update`, `delete` | |
|
|
104
|
+
| `media` | `upload`, `list`, `getById`, `delete` | `upload` takes a `File \| Buffer` |
|
|
105
|
+
| `layout` | `get`, `update`, `updateRegion` | page layout documents |
|
|
106
|
+
| `search` | `search` | |
|
|
107
|
+
| `versions` | `list`, `get`, `restore` | content version history |
|
|
108
|
+
| `workflow` | `publish`, `unpublish`, `restore`, `permanentDelete` | trash/publish workflow, ID-based |
|
|
109
|
+
| `categories` | `list`, `getById`, `create`, `update`, `delete`, `tree` | |
|
|
110
|
+
| `forms` | `submit`, `listSubmissions`, `getCsrfToken` | |
|
|
111
|
+
| `tree` | `getChildren`, `getBreadcrumbs`, `move`, `reorder` | site-tree drag/drop operations |
|
|
112
|
+
| `hooks` | `listWebhooks`, `createWebhook`, `updateWebhook`, `deleteWebhook` | webhook endpoints |
|
|
113
|
+
| `i18n` (optional) | `get`, `getLocale` | only present when `config.bundles` **and** `config.locale` are both set |
|
|
114
|
+
|
|
115
|
+
The full method signatures are the source of truth in `src/types.ts`
|
|
116
|
+
(`KywiSdk*Scope` interfaces) — read them before wiring a new call, since
|
|
117
|
+
several return `null` on 404 rather than throwing (`content.getById`,
|
|
118
|
+
`content.getBySlug`, `content.update`, `site.getConfig`, `user.getCurrent`,
|
|
119
|
+
`user.getById`) while others throw `KywiSdkError`.
|
|
120
|
+
|
|
121
|
+
## React hooks (`@kywi-software/sdk/hooks`)
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
import { KywiSdkProvider, useKywiSdkContent, useKywiSdkNav } from '@kywi-software/sdk/hooks'
|
|
125
|
+
import { createKywiSdk } from '@kywi-software/sdk'
|
|
126
|
+
|
|
127
|
+
const sdk = createKywiSdk({ baseUrl: '/api/v1', defaultSiteId: 'default' })
|
|
128
|
+
|
|
129
|
+
function App() {
|
|
130
|
+
return (
|
|
131
|
+
<KywiSdkProvider sdk={sdk}>
|
|
132
|
+
<Page />
|
|
133
|
+
</KywiSdkProvider>
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function Page() {
|
|
138
|
+
const { data, loading, error } = useKywiSdkContent('about')
|
|
139
|
+
const nav = useKywiSdkNav()
|
|
140
|
+
// ...
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Exported from `src/hooks/index.ts`: `KywiSdkProvider`/`useKywiSdk` (context),
|
|
145
|
+
`useSdkQuery` (generic fetch-on-mount-and-deps-change hook), plus thin
|
|
146
|
+
wrappers `useKywiSdkContent`/`useKywiSdkContentById`/`useKywiSdkContentList`,
|
|
147
|
+
`useKywiSdkNav`/`useKywiSdkBreadcrumbs`, `useKywiSdkFeed`/`useKywiSdkFeedQuery`.
|
|
148
|
+
`react`/`react-dom` are optional peer dependencies — only needed if you import
|
|
149
|
+
from `@kywi-software/sdk/hooks`.
|
|
150
|
+
|
|
151
|
+
## Errors
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { KywiSdkError } from '@kywi-software/sdk'
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
await kywi.content.create('page', { title: 'x' })
|
|
158
|
+
} catch (err) {
|
|
159
|
+
if (err instanceof KywiSdkError) {
|
|
160
|
+
console.error(err.status, err.body)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Testing
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
pnpm --filter @kywi-software/sdk test
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
All client tests stub `global.fetch` (`vi.stubGlobal('fetch', mockFetch)`) —
|
|
172
|
+
no network or database access required.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/auth-client.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { KywiHttpClient } from '../http-client.js';
|
|
3
|
+
import { createAuthClient } from '../auth-client.js';
|
|
4
|
+
const mockFetch = vi.fn();
|
|
5
|
+
vi.stubGlobal('fetch', mockFetch);
|
|
6
|
+
function ok(data, status = 200) {
|
|
7
|
+
return new Response(JSON.stringify(data), {
|
|
8
|
+
status,
|
|
9
|
+
headers: { 'Content-Type': 'application/json' },
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
describe('AuthClient', () => {
|
|
13
|
+
let client;
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
mockFetch.mockReset();
|
|
16
|
+
const http = new KywiHttpClient({ baseUrl: 'https://api.test/api/v1' });
|
|
17
|
+
client = createAuthClient(http);
|
|
18
|
+
});
|
|
19
|
+
// ── login ─────────────────────────────────────────────────────────────
|
|
20
|
+
it('login sends correct URL and body', async () => {
|
|
21
|
+
const authResult = {
|
|
22
|
+
accessToken: 'at1',
|
|
23
|
+
refreshToken: 'rt1',
|
|
24
|
+
user: { id: 'u1', role: 'admin', groups: ['editors'] },
|
|
25
|
+
};
|
|
26
|
+
mockFetch.mockResolvedValue(ok({ data: authResult }));
|
|
27
|
+
const result = await client.login('user@example.com', 'secret');
|
|
28
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
29
|
+
expect(new URL(url).pathname).toBe('/api/v1/auth/login');
|
|
30
|
+
expect(JSON.parse(init.body)).toEqual({ email: 'user@example.com', password: 'secret' });
|
|
31
|
+
expect(result).toEqual(authResult);
|
|
32
|
+
});
|
|
33
|
+
// ── register ──────────────────────────────────────────────────────────
|
|
34
|
+
it('register sends correct URL and body', async () => {
|
|
35
|
+
const authResult = {
|
|
36
|
+
accessToken: 'at2',
|
|
37
|
+
refreshToken: 'rt2',
|
|
38
|
+
user: { id: 'u2', role: 'member', groups: [] },
|
|
39
|
+
};
|
|
40
|
+
mockFetch.mockResolvedValue(ok({ data: authResult }));
|
|
41
|
+
const data = { email: 'new@example.com', password: 'pass', firstName: 'Ada', lastName: 'Lovelace' };
|
|
42
|
+
const result = await client.register(data);
|
|
43
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
44
|
+
expect(new URL(url).pathname).toBe('/api/v1/auth/register');
|
|
45
|
+
expect(JSON.parse(init.body)).toEqual(data);
|
|
46
|
+
expect(result).toEqual(authResult);
|
|
47
|
+
});
|
|
48
|
+
it('register sends correct URL and body without optional fields', async () => {
|
|
49
|
+
const authResult = {
|
|
50
|
+
accessToken: 'at3',
|
|
51
|
+
refreshToken: 'rt3',
|
|
52
|
+
user: { id: 'u3', role: 'member', groups: [] },
|
|
53
|
+
};
|
|
54
|
+
mockFetch.mockResolvedValue(ok({ data: authResult }));
|
|
55
|
+
const result = await client.register({ email: 'min@example.com', password: 'pw' });
|
|
56
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
57
|
+
expect(new URL(url).pathname).toBe('/api/v1/auth/register');
|
|
58
|
+
expect(JSON.parse(init.body)).toEqual({ email: 'min@example.com', password: 'pw' });
|
|
59
|
+
expect(result).toEqual(authResult);
|
|
60
|
+
});
|
|
61
|
+
// ── refresh ───────────────────────────────────────────────────────────
|
|
62
|
+
it('refresh sends correct URL and body', async () => {
|
|
63
|
+
mockFetch.mockResolvedValue(ok({ data: { accessToken: 'new-at' } }));
|
|
64
|
+
const result = await client.refresh('rt-abc');
|
|
65
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
66
|
+
expect(new URL(url).pathname).toBe('/api/v1/auth/refresh');
|
|
67
|
+
expect(JSON.parse(init.body)).toEqual({ refreshToken: 'rt-abc' });
|
|
68
|
+
expect(result).toEqual({ accessToken: 'new-at' });
|
|
69
|
+
});
|
|
70
|
+
// ── forgotPassword ────────────────────────────────────────────────────
|
|
71
|
+
it('forgotPassword sends correct URL and body', async () => {
|
|
72
|
+
mockFetch.mockResolvedValue(ok({ data: { message: 'Email sent' } }));
|
|
73
|
+
const result = await client.forgotPassword('lost@example.com');
|
|
74
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
75
|
+
expect(new URL(url).pathname).toBe('/api/v1/auth/forgot-password');
|
|
76
|
+
expect(JSON.parse(init.body)).toEqual({ email: 'lost@example.com' });
|
|
77
|
+
expect(result).toEqual({ message: 'Email sent' });
|
|
78
|
+
});
|
|
79
|
+
// ── resetPassword ─────────────────────────────────────────────────────
|
|
80
|
+
it('resetPassword sends correct URL and body', async () => {
|
|
81
|
+
mockFetch.mockResolvedValue(ok({ data: { message: 'Password reset' } }));
|
|
82
|
+
const result = await client.resetPassword('tok123', 'user@example.com', 'newpass');
|
|
83
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
84
|
+
expect(new URL(url).pathname).toBe('/api/v1/auth/reset-password');
|
|
85
|
+
expect(JSON.parse(init.body)).toEqual({ token: 'tok123', email: 'user@example.com', newPassword: 'newpass' });
|
|
86
|
+
expect(result).toEqual({ message: 'Password reset' });
|
|
87
|
+
});
|
|
88
|
+
// ── logout ────────────────────────────────────────────────────────────
|
|
89
|
+
it('logout sends correct URL', async () => {
|
|
90
|
+
mockFetch.mockResolvedValue(ok(null, 200));
|
|
91
|
+
await client.logout();
|
|
92
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
93
|
+
expect(new URL(url).pathname).toBe('/api/v1/auth/logout');
|
|
94
|
+
expect(init.method).toBe('POST');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=auth-client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-client.test.js","sourceRoot":"","sources":["../../src/__tests__/auth-client.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/content-client.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { KywiHttpClient } from '../http-client.js';
|
|
3
|
+
import { createContentClient } from '../content-client.js';
|
|
4
|
+
const mockFetch = vi.fn();
|
|
5
|
+
vi.stubGlobal('fetch', mockFetch);
|
|
6
|
+
function ok(data, status = 200) {
|
|
7
|
+
return new Response(JSON.stringify(data), {
|
|
8
|
+
status,
|
|
9
|
+
headers: { 'Content-Type': 'application/json' },
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function notFound() {
|
|
13
|
+
return new Response(JSON.stringify({ error: { code: 'NOT_FOUND', message: 'Not found' } }), { status: 404, headers: { 'Content-Type': 'application/json' } });
|
|
14
|
+
}
|
|
15
|
+
describe('ContentClient', () => {
|
|
16
|
+
let client;
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
mockFetch.mockReset();
|
|
19
|
+
const http = new KywiHttpClient({ baseUrl: 'https://api.test/api/v1' });
|
|
20
|
+
client = createContentClient(http, 'default-site');
|
|
21
|
+
});
|
|
22
|
+
// ── getBySlug ─────────────────────────────────────────────────────────
|
|
23
|
+
it('getBySlug sends correct URL with default siteId', async () => {
|
|
24
|
+
const item = { id: '1', title: 'Hello' };
|
|
25
|
+
mockFetch.mockResolvedValue(ok({ data: item }));
|
|
26
|
+
const result = await client.getBySlug('hello');
|
|
27
|
+
const url = new URL(mockFetch.mock.calls[0][0]);
|
|
28
|
+
expect(url.pathname).toBe('/api/v1/content/slug/hello');
|
|
29
|
+
expect(url.searchParams.get('siteId')).toBe('default-site');
|
|
30
|
+
expect(result).toEqual(item);
|
|
31
|
+
});
|
|
32
|
+
it('getBySlug uses provided siteId', async () => {
|
|
33
|
+
mockFetch.mockResolvedValue(ok({ data: { id: '1' } }));
|
|
34
|
+
await client.getBySlug('hello', 'other-site');
|
|
35
|
+
const url = new URL(mockFetch.mock.calls[0][0]);
|
|
36
|
+
expect(url.searchParams.get('siteId')).toBe('other-site');
|
|
37
|
+
});
|
|
38
|
+
it('getBySlug returns null on 404', async () => {
|
|
39
|
+
mockFetch.mockResolvedValue(notFound());
|
|
40
|
+
const result = await client.getBySlug('missing');
|
|
41
|
+
expect(result).toBeNull();
|
|
42
|
+
});
|
|
43
|
+
// ── getById ───────────────────────────────────────────────────────────
|
|
44
|
+
it('getById sends correct URL', async () => {
|
|
45
|
+
const item = { id: 'abc', title: 'Test' };
|
|
46
|
+
mockFetch.mockResolvedValue(ok({ data: item }));
|
|
47
|
+
const result = await client.getById('abc');
|
|
48
|
+
const url = new URL(mockFetch.mock.calls[0][0]);
|
|
49
|
+
expect(url.pathname).toBe('/api/v1/content/by-id/abc');
|
|
50
|
+
expect(result).toEqual(item);
|
|
51
|
+
});
|
|
52
|
+
it('getById returns null on 404', async () => {
|
|
53
|
+
mockFetch.mockResolvedValue(notFound());
|
|
54
|
+
const result = await client.getById('missing');
|
|
55
|
+
expect(result).toBeNull();
|
|
56
|
+
});
|
|
57
|
+
// ── getChildren ───────────────────────────────────────────────────────
|
|
58
|
+
it('getChildren sends correct URL', async () => {
|
|
59
|
+
const children = [{ id: 'c1' }, { id: 'c2' }];
|
|
60
|
+
mockFetch.mockResolvedValue(ok({ data: children }));
|
|
61
|
+
const result = await client.getChildren('parent1');
|
|
62
|
+
const url = new URL(mockFetch.mock.calls[0][0]);
|
|
63
|
+
expect(url.pathname).toBe('/api/v1/content/by-id/parent1/children');
|
|
64
|
+
expect(result).toEqual(children);
|
|
65
|
+
});
|
|
66
|
+
// ── list ──────────────────────────────────────────────────────────────
|
|
67
|
+
it('list sends correct URL with default siteId', async () => {
|
|
68
|
+
mockFetch.mockResolvedValue(ok({ data: [{ id: '1' }], meta: { total: 1, page: 1, pageSize: 20, totalPages: 1 } }));
|
|
69
|
+
const result = await client.list('page');
|
|
70
|
+
const url = new URL(mockFetch.mock.calls[0][0]);
|
|
71
|
+
expect(url.pathname).toBe('/api/v1/content/page');
|
|
72
|
+
expect(url.searchParams.get('siteId')).toBe('default-site');
|
|
73
|
+
expect(result).toEqual({ rows: [{ id: '1' }], total: 1 });
|
|
74
|
+
});
|
|
75
|
+
it('list passes all optional params', async () => {
|
|
76
|
+
mockFetch.mockResolvedValue(ok({ data: [], meta: { total: 0, page: 2, pageSize: 5, totalPages: 0 } }));
|
|
77
|
+
await client.list('post', 'other-site', {
|
|
78
|
+
page: 2,
|
|
79
|
+
limit: 5,
|
|
80
|
+
sort: 'title',
|
|
81
|
+
dir: 'desc',
|
|
82
|
+
status: 'published',
|
|
83
|
+
search: 'hello',
|
|
84
|
+
parentId: 'p1',
|
|
85
|
+
});
|
|
86
|
+
const url = new URL(mockFetch.mock.calls[0][0]);
|
|
87
|
+
expect(url.searchParams.get('siteId')).toBe('other-site');
|
|
88
|
+
expect(url.searchParams.get('page')).toBe('2');
|
|
89
|
+
expect(url.searchParams.get('limit')).toBe('5');
|
|
90
|
+
expect(url.searchParams.get('sort')).toBe('title');
|
|
91
|
+
expect(url.searchParams.get('dir')).toBe('desc');
|
|
92
|
+
expect(url.searchParams.get('status')).toBe('published');
|
|
93
|
+
expect(url.searchParams.get('search')).toBe('hello');
|
|
94
|
+
expect(url.searchParams.get('parentId')).toBe('p1');
|
|
95
|
+
});
|
|
96
|
+
// ── create ────────────────────────────────────────────────────────────
|
|
97
|
+
it('create sends POST with siteId as a query param (not body)', async () => {
|
|
98
|
+
const created = { id: 'new1', title: 'New' };
|
|
99
|
+
mockFetch.mockResolvedValue(ok({ data: created }));
|
|
100
|
+
const result = await client.create('page', { title: 'New' });
|
|
101
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
102
|
+
const parsed = new URL(url);
|
|
103
|
+
expect(parsed.pathname).toBe('/api/v1/content/page');
|
|
104
|
+
// siteId must ride on the query string — the server's create schema is
|
|
105
|
+
// strict and 400s on an in-body siteId.
|
|
106
|
+
expect(parsed.searchParams.get('siteId')).toBe('default-site');
|
|
107
|
+
expect(init.method).toBe('POST');
|
|
108
|
+
expect(JSON.parse(init.body)).toEqual({ title: 'New' });
|
|
109
|
+
expect(result).toEqual(created);
|
|
110
|
+
});
|
|
111
|
+
it('create uses provided siteId as a query param', async () => {
|
|
112
|
+
mockFetch.mockResolvedValue(ok({ data: { id: '1' } }));
|
|
113
|
+
await client.create('page', { title: 'X' }, 'custom-site');
|
|
114
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
115
|
+
expect(new URL(url).searchParams.get('siteId')).toBe('custom-site');
|
|
116
|
+
expect(JSON.parse(init.body).siteId).toBeUndefined();
|
|
117
|
+
});
|
|
118
|
+
// ── update ────────────────────────────────────────────────────────────
|
|
119
|
+
it('update sends PUT with correct URL', async () => {
|
|
120
|
+
const updated = { id: '1', title: 'Updated' };
|
|
121
|
+
mockFetch.mockResolvedValue(ok({ data: updated }));
|
|
122
|
+
const result = await client.update('page', '1', { title: 'Updated' });
|
|
123
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
124
|
+
expect(new URL(url).pathname).toBe('/api/v1/content/page/1');
|
|
125
|
+
expect(init.method).toBe('PUT');
|
|
126
|
+
expect(result).toEqual(updated);
|
|
127
|
+
});
|
|
128
|
+
it('update returns null on 404', async () => {
|
|
129
|
+
mockFetch.mockResolvedValue(notFound());
|
|
130
|
+
const result = await client.update('page', 'missing', { title: 'X' });
|
|
131
|
+
expect(result).toBeNull();
|
|
132
|
+
});
|
|
133
|
+
// ── delete ────────────────────────────────────────────────────────────
|
|
134
|
+
it('delete sends DELETE and returns true', async () => {
|
|
135
|
+
mockFetch.mockResolvedValue(ok({ data: { deleted: true } }));
|
|
136
|
+
const result = await client.delete('1');
|
|
137
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
138
|
+
expect(new URL(url).pathname).toBe('/api/v1/content/by-id/1');
|
|
139
|
+
expect(init.method).toBe('DELETE');
|
|
140
|
+
expect(result).toBe(true);
|
|
141
|
+
});
|
|
142
|
+
it('delete returns false on 404', async () => {
|
|
143
|
+
mockFetch.mockResolvedValue(notFound());
|
|
144
|
+
const result = await client.delete('missing');
|
|
145
|
+
expect(result).toBe(false);
|
|
146
|
+
});
|
|
147
|
+
// ── publish ───────────────────────────────────────────────────────────
|
|
148
|
+
it('publish sends POST and returns item', async () => {
|
|
149
|
+
const item = { id: '1', status: 'published' };
|
|
150
|
+
mockFetch.mockResolvedValue(ok({ data: item }));
|
|
151
|
+
const result = await client.publish('1');
|
|
152
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
153
|
+
expect(new URL(url).pathname).toBe('/api/v1/content/by-id/1/publish');
|
|
154
|
+
expect(init.method).toBe('POST');
|
|
155
|
+
expect(result).toEqual(item);
|
|
156
|
+
});
|
|
157
|
+
it('publish returns null on 404', async () => {
|
|
158
|
+
mockFetch.mockResolvedValue(notFound());
|
|
159
|
+
const result = await client.publish('missing');
|
|
160
|
+
expect(result).toBeNull();
|
|
161
|
+
});
|
|
162
|
+
// ── unpublish ─────────────────────────────────────────────────────────
|
|
163
|
+
it('unpublish sends POST and returns item', async () => {
|
|
164
|
+
const item = { id: '1', status: 'draft' };
|
|
165
|
+
mockFetch.mockResolvedValue(ok({ data: item }));
|
|
166
|
+
const result = await client.unpublish('1');
|
|
167
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
168
|
+
expect(new URL(url).pathname).toBe('/api/v1/content/by-id/1/unpublish');
|
|
169
|
+
expect(init.method).toBe('POST');
|
|
170
|
+
expect(result).toEqual(item);
|
|
171
|
+
});
|
|
172
|
+
it('unpublish returns null on 404', async () => {
|
|
173
|
+
mockFetch.mockResolvedValue(notFound());
|
|
174
|
+
const result = await client.unpublish('missing');
|
|
175
|
+
expect(result).toBeNull();
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
//# sourceMappingURL=content-client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-client.test.js","sourceRoot":"","sources":["../../src/__tests__/content-client.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-sdk.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/create-sdk.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeAll, afterAll } from 'vitest';
|
|
2
|
+
import { createKywiSdk } from '../create-sdk.js';
|
|
3
|
+
const mockFetch = vi.fn();
|
|
4
|
+
beforeAll(() => {
|
|
5
|
+
vi.stubGlobal('fetch', mockFetch);
|
|
6
|
+
});
|
|
7
|
+
afterAll(() => {
|
|
8
|
+
vi.unstubAllGlobals();
|
|
9
|
+
});
|
|
10
|
+
function makeConfig(overrides) {
|
|
11
|
+
return {
|
|
12
|
+
baseUrl: 'https://api.test.com/v1',
|
|
13
|
+
apiKey: 'test-key',
|
|
14
|
+
defaultSiteId: 'site-1',
|
|
15
|
+
...overrides,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
describe('createKywiSdk', () => {
|
|
19
|
+
it('returns scope with all sub-scopes', () => {
|
|
20
|
+
const sdk = createKywiSdk(makeConfig());
|
|
21
|
+
expect(sdk.content).toBeDefined();
|
|
22
|
+
expect(sdk.nav).toBeDefined();
|
|
23
|
+
expect(sdk.site).toBeDefined();
|
|
24
|
+
expect(sdk.user).toBeDefined();
|
|
25
|
+
expect(sdk.feeds).toBeDefined();
|
|
26
|
+
});
|
|
27
|
+
it('i18n is undefined when bundles/locale not provided', () => {
|
|
28
|
+
const sdk = createKywiSdk(makeConfig());
|
|
29
|
+
expect(sdk.i18n).toBeUndefined();
|
|
30
|
+
});
|
|
31
|
+
it('i18n is present when both bundles and locale provided', () => {
|
|
32
|
+
const bundles = new Map([
|
|
33
|
+
['en', new Map([['greeting', 'Hello']])],
|
|
34
|
+
]);
|
|
35
|
+
const sdk = createKywiSdk(makeConfig({ bundles, locale: 'en' }));
|
|
36
|
+
expect(sdk.i18n).toBeDefined();
|
|
37
|
+
});
|
|
38
|
+
it('i18n.get returns correct value', () => {
|
|
39
|
+
const bundles = new Map([
|
|
40
|
+
['en', new Map([['greeting', 'Hello {{name}}']])],
|
|
41
|
+
]);
|
|
42
|
+
const sdk = createKywiSdk(makeConfig({ bundles, locale: 'en' }));
|
|
43
|
+
expect(sdk.i18n.get('greeting', undefined, { name: 'World' })).toBe('Hello World');
|
|
44
|
+
});
|
|
45
|
+
it('i18n.getLocale returns configured locale', () => {
|
|
46
|
+
const bundles = new Map([
|
|
47
|
+
['en', new Map([['key', 'value']])],
|
|
48
|
+
]);
|
|
49
|
+
const sdk = createKywiSdk(makeConfig({ bundles, locale: 'en' }));
|
|
50
|
+
expect(sdk.i18n.getLocale()).toBe('en');
|
|
51
|
+
});
|
|
52
|
+
it('all content scope methods are callable functions', () => {
|
|
53
|
+
const sdk = createKywiSdk(makeConfig());
|
|
54
|
+
expect(typeof sdk.content.getBySlug).toBe('function');
|
|
55
|
+
expect(typeof sdk.content.getById).toBe('function');
|
|
56
|
+
expect(typeof sdk.content.getChildren).toBe('function');
|
|
57
|
+
expect(typeof sdk.content.list).toBe('function');
|
|
58
|
+
expect(typeof sdk.content.create).toBe('function');
|
|
59
|
+
expect(typeof sdk.content.update).toBe('function');
|
|
60
|
+
expect(typeof sdk.content.delete).toBe('function');
|
|
61
|
+
expect(typeof sdk.content.publish).toBe('function');
|
|
62
|
+
expect(typeof sdk.content.unpublish).toBe('function');
|
|
63
|
+
});
|
|
64
|
+
it('all nav scope methods are callable functions', () => {
|
|
65
|
+
const sdk = createKywiSdk(makeConfig());
|
|
66
|
+
expect(typeof sdk.nav.getTree).toBe('function');
|
|
67
|
+
expect(typeof sdk.nav.getBreadcrumbs).toBe('function');
|
|
68
|
+
expect(typeof sdk.nav.getChildren).toBe('function');
|
|
69
|
+
});
|
|
70
|
+
it('all site scope methods are callable functions', () => {
|
|
71
|
+
const sdk = createKywiSdk(makeConfig());
|
|
72
|
+
expect(typeof sdk.site.getConfig).toBe('function');
|
|
73
|
+
expect(typeof sdk.site.list).toBe('function');
|
|
74
|
+
});
|
|
75
|
+
it('all user scope methods are callable functions', () => {
|
|
76
|
+
const sdk = createKywiSdk(makeConfig());
|
|
77
|
+
expect(typeof sdk.user.getCurrent).toBe('function');
|
|
78
|
+
expect(typeof sdk.user.getById).toBe('function');
|
|
79
|
+
});
|
|
80
|
+
it('all feeds scope methods are callable functions', () => {
|
|
81
|
+
const sdk = createKywiSdk(makeConfig());
|
|
82
|
+
expect(typeof sdk.feeds.query).toBe('function');
|
|
83
|
+
expect(typeof sdk.feeds.get).toBe('function');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=create-sdk.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-sdk.test.js","sourceRoot":"","sources":["../../src/__tests__/create-sdk.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feed-client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/feed-client.test.ts"],"names":[],"mappings":""}
|