@estokad/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 +17 -0
- package/README.md +109 -0
- package/dist/client.d.ts +11 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +39 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +30 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +49 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/transport.d.ts +20 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +127 -0
- package/dist/transport.js.map +1 -0
- package/dist/type-client.d.ts +24 -0
- package/dist/type-client.d.ts.map +1 -0
- package/dist/type-client.js +72 -0
- package/dist/type-client.js.map +1 -0
- package/dist/types.d.ts +33 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Copyright © 2026 Samarkand Industries OÜ. All rights reserved.
|
|
2
|
+
|
|
3
|
+
Estokad is proprietary software. Source code in this repository is the
|
|
4
|
+
confidential intellectual property of Samarkand Industries OÜ
|
|
5
|
+
(registered Tallinn, Estonia).
|
|
6
|
+
|
|
7
|
+
Permission to use, copy, modify, or distribute this software is granted
|
|
8
|
+
only under a separate written agreement signed by Samarkand Industries
|
|
9
|
+
OÜ. Without such agreement, no license is granted, expressed or implied.
|
|
10
|
+
|
|
11
|
+
Public-facing components — the SDK packages published to npm under the
|
|
12
|
+
`@estokad/*` scope, and the SDKs' published documentation — are licensed
|
|
13
|
+
separately. See the LICENSE file inside each `packages/*` directory or
|
|
14
|
+
the package's npm registry page for the terms that apply to that
|
|
15
|
+
specific package.
|
|
16
|
+
|
|
17
|
+
Contact: legal@samarkandindustries.com
|
package/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# @estokad/sdk
|
|
2
|
+
|
|
3
|
+
Framework-agnostic TypeScript client for the Estokad content API. End-to-end typed: your `defineType()` schemas drive the response types, no codegen step.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @estokad/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quickstart
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { createClient } from '@estokad/sdk'
|
|
15
|
+
|
|
16
|
+
const cms = createClient({
|
|
17
|
+
workspace: 'my-workspace',
|
|
18
|
+
apiUrl: 'https://api.estokad.com',
|
|
19
|
+
apiKey: process.env.ESTOKAD_API_KEY!,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// Fetch a list
|
|
23
|
+
const articles = await cms.list('article', { first: 20 })
|
|
24
|
+
|
|
25
|
+
// Fetch by id or slug
|
|
26
|
+
const article = await cms.fetch('article', 'launch-week-day-1')
|
|
27
|
+
|
|
28
|
+
// Singleton
|
|
29
|
+
const settings = await cms.singleton('siteSettings').fetch()
|
|
30
|
+
|
|
31
|
+
// Mutations (require write or management scope)
|
|
32
|
+
await cms.update('article', article.id, { title: 'Updated' })
|
|
33
|
+
await cms.publish('article', article.id)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Typing your responses
|
|
37
|
+
|
|
38
|
+
Declare a `ContentTypes` interface and the SDK becomes fully typed:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import type { ContentTypes } from '@estokad/sdk'
|
|
42
|
+
|
|
43
|
+
declare module '@estokad/sdk' {
|
|
44
|
+
interface ContentTypes {
|
|
45
|
+
article: {
|
|
46
|
+
title: string
|
|
47
|
+
body: string
|
|
48
|
+
publishedAt: string | null
|
|
49
|
+
}
|
|
50
|
+
siteSettings: {
|
|
51
|
+
siteName: string
|
|
52
|
+
ga4MeasurementId: string
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Now `articles[0].title` is typed as `string`, no `any` anywhere.
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
In a real project, the type generation step is automatic — see [`@estokad/cli`](https://www.npmjs.com/package/@estokad/cli) `estokad pull` which writes a `.estokad/types.ts` declaration file alongside your `schemas/*.ts` files.
|
|
61
|
+
|
|
62
|
+
## Errors
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import {
|
|
66
|
+
EstokadError,
|
|
67
|
+
NotFoundError,
|
|
68
|
+
ValidationError,
|
|
69
|
+
RateLimitError,
|
|
70
|
+
UnauthorizedError,
|
|
71
|
+
} from '@estokad/sdk'
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
await cms.update('article', id, { title: '' })
|
|
75
|
+
} catch (err) {
|
|
76
|
+
if (err instanceof ValidationError) {
|
|
77
|
+
console.error('field issues:', err.issues)
|
|
78
|
+
} else if (err instanceof RateLimitError) {
|
|
79
|
+
console.error('retry after seconds:', err.retryAfter)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## GraphQL escape hatch
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const result = await cms.gql<{ article: { title: string } }>(
|
|
88
|
+
`query($id: ID!) { article(id: $id) { title } }`,
|
|
89
|
+
{ id: 'launch-week-day-1' },
|
|
90
|
+
)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Framework adapters
|
|
94
|
+
|
|
95
|
+
Don't use this directly — use one of the adapters:
|
|
96
|
+
|
|
97
|
+
- [`@estokad/next`](https://www.npmjs.com/package/@estokad/next) for Next.js (App Router + draft mode + visual edit).
|
|
98
|
+
- [`@estokad/nuxt`](https://www.npmjs.com/package/@estokad/nuxt) for Nuxt 3.
|
|
99
|
+
- [`@estokad/svelte`](https://www.npmjs.com/package/@estokad/svelte) for SvelteKit.
|
|
100
|
+
|
|
101
|
+
Each wraps `createClient` with the framework's preferred conventions (cookies, server-side fetch, etc.).
|
|
102
|
+
|
|
103
|
+
## Documentation
|
|
104
|
+
|
|
105
|
+
Full reference at [`docs.estokad.com`](https://docs.estokad.com). AI-friendly index at [`docs.estokad.com/llms.txt`](https://docs.estokad.com/llms.txt).
|
|
106
|
+
|
|
107
|
+
## License
|
|
108
|
+
|
|
109
|
+
Apache-2.0. Estokad is a Samarkand Industries OÜ product.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TypeClient } from './type-client.js';
|
|
2
|
+
import type { ClientOptions, ContentTypes } from './types.js';
|
|
3
|
+
export type Client = {
|
|
4
|
+
readonly [K in keyof ContentTypes]: TypeClient<ContentTypes[K]>;
|
|
5
|
+
} & {
|
|
6
|
+
/** Run a raw GraphQL query against the workspace's `/graphql` endpoint.
|
|
7
|
+
* Throws on transport errors and on top-level `errors[]`. */
|
|
8
|
+
readonly gql: <T>(query: string, variables?: Record<string, unknown>) => Promise<T>;
|
|
9
|
+
};
|
|
10
|
+
export declare function createClient(options: ClientOptions): Client;
|
|
11
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE7D,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,EAAE,CAAC,IAAI,MAAM,YAAY,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;CAChE,GAAG;IACF;kEAC8D;IAC9D,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;CACpF,CAAA;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAyB3D"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// createClient — the user-facing entry point.
|
|
2
|
+
//
|
|
3
|
+
// Returns a Proxy so `client.<typeName>` resolves to a TypeClient<T> at
|
|
4
|
+
// runtime. The static type is computed from the `ContentTypes` interface
|
|
5
|
+
// declared via module augmentation by consumers; without augmentation,
|
|
6
|
+
// `Client` is `{}` and TypeScript stops you at the property access. The
|
|
7
|
+
// Proxy still works at runtime for ad-hoc string access (testing, dev).
|
|
8
|
+
//
|
|
9
|
+
// The Proxy also exposes a non-typed-by-content `gql` method for raw
|
|
10
|
+
// GraphQL access. Reference fields auto-resolve to nested objects on the
|
|
11
|
+
// server side via DataLoader (M2.2b); consumers can write the GraphQL
|
|
12
|
+
// query themselves until the codegen pipeline lands.
|
|
13
|
+
import { graphqlRequest, resolveConfig } from './transport.js';
|
|
14
|
+
import { TypeClient } from './type-client.js';
|
|
15
|
+
export function createClient(options) {
|
|
16
|
+
const config = resolveConfig(options);
|
|
17
|
+
const cache = new Map();
|
|
18
|
+
return new Proxy({}, {
|
|
19
|
+
get(_target, prop) {
|
|
20
|
+
if (typeof prop !== 'string')
|
|
21
|
+
return undefined;
|
|
22
|
+
// Block introspection probes that would otherwise instantiate a
|
|
23
|
+
// bogus TypeClient (e.g. tools inspecting `then` to check for
|
|
24
|
+
// promise-likeness).
|
|
25
|
+
if (prop === 'then' || prop === 'toJSON' || prop.startsWith('_'))
|
|
26
|
+
return undefined;
|
|
27
|
+
if (prop === 'gql') {
|
|
28
|
+
return (query, variables = {}) => graphqlRequest(config, query, variables);
|
|
29
|
+
}
|
|
30
|
+
let client = cache.get(prop);
|
|
31
|
+
if (!client) {
|
|
32
|
+
client = new TypeClient(prop, config);
|
|
33
|
+
cache.set(prop, client);
|
|
34
|
+
}
|
|
35
|
+
return client;
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,EAAE;AACF,wEAAwE;AACxE,yEAAyE;AACzE,uEAAuE;AACvE,wEAAwE;AACxE,wEAAwE;AACxE,EAAE;AACF,qEAAqE;AACrE,yEAAyE;AACzE,sEAAsE;AACtE,qDAAqD;AAErD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAW7C,MAAM,UAAU,YAAY,CAAC,OAAsB;IACjD,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,CAAA;IACrC,MAAM,KAAK,GAAG,IAAI,GAAG,EAA+B,CAAA;IAEpD,OAAO,IAAI,KAAK,CAAC,EAAY,EAAE;QAC7B,GAAG,CAAC,OAAO,EAAE,IAAI;YACf,IAAI,OAAO,IAAI,KAAK,QAAQ;gBAAE,OAAO,SAAS,CAAA;YAC9C,gEAAgE;YAChE,8DAA8D;YAC9D,qBAAqB;YACrB,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,OAAO,SAAS,CAAA;YAElF,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;gBACnB,OAAO,CAAI,KAAa,EAAE,YAAqC,EAAE,EAAE,EAAE,CACnE,cAAc,CAAI,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAA;YAC/C,CAAC;YAED,IAAI,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;gBACrC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;YACzB,CAAC;YACD,OAAO,MAAM,CAAA;QACf,CAAC;KACF,CAAC,CAAA;AACJ,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare class EstokadError extends Error {
|
|
2
|
+
readonly status: number;
|
|
3
|
+
readonly body: string;
|
|
4
|
+
constructor(message: string, status: number, body: string);
|
|
5
|
+
}
|
|
6
|
+
export declare class NotFoundError extends EstokadError {
|
|
7
|
+
constructor(body: string);
|
|
8
|
+
}
|
|
9
|
+
export declare class ValidationError extends EstokadError {
|
|
10
|
+
readonly issues: ReadonlyArray<{
|
|
11
|
+
readonly path: string;
|
|
12
|
+
readonly message: string;
|
|
13
|
+
}>;
|
|
14
|
+
constructor(body: string, issues: ReadonlyArray<{
|
|
15
|
+
readonly path: string;
|
|
16
|
+
readonly message: string;
|
|
17
|
+
}>);
|
|
18
|
+
}
|
|
19
|
+
export declare class RateLimitError extends EstokadError {
|
|
20
|
+
readonly retryAfter: number;
|
|
21
|
+
constructor(body: string, retryAfter: number);
|
|
22
|
+
}
|
|
23
|
+
export declare class UnauthorizedError extends EstokadError {
|
|
24
|
+
constructor(body: string);
|
|
25
|
+
}
|
|
26
|
+
export declare class WrongRegionError extends EstokadError {
|
|
27
|
+
readonly redirect: string;
|
|
28
|
+
constructor(body: string, redirect: string);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAGA,qBAAa,YAAa,SAAQ,KAAK;aAGnB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM;gBAF5B,OAAO,EAAE,MAAM,EACC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM;CAK/B;AAED,qBAAa,aAAc,SAAQ,YAAY;gBACjC,IAAI,EAAE,MAAM;CAIzB;AAED,qBAAa,eAAgB,SAAQ,YAAY;aAG7B,MAAM,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;gBAD1F,IAAI,EAAE,MAAM,EACI,MAAM,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAK7F;AAED,qBAAa,cAAe,SAAQ,YAAY;aAG5B,UAAU,EAAE,MAAM;gBADlC,IAAI,EAAE,MAAM,EACI,UAAU,EAAE,MAAM;CAKrC;AAED,qBAAa,iBAAkB,SAAQ,YAAY;gBACrC,IAAI,EAAE,MAAM;CAIzB;AAED,qBAAa,gBAAiB,SAAQ,YAAY;aAG9B,QAAQ,EAAE,MAAM;gBADhC,IAAI,EAAE,MAAM,EACI,QAAQ,EAAE,MAAM;CAKnC"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Structured errors for the Estokad SDK. Consumers do `instanceof` checks to
|
|
2
|
+
// branch (per docs/api.md § 10).
|
|
3
|
+
export class EstokadError extends Error {
|
|
4
|
+
status;
|
|
5
|
+
body;
|
|
6
|
+
constructor(message, status, body) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.body = body;
|
|
10
|
+
this.name = 'EstokadError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class NotFoundError extends EstokadError {
|
|
14
|
+
constructor(body) {
|
|
15
|
+
super('Not found', 404, body);
|
|
16
|
+
this.name = 'NotFoundError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export class ValidationError extends EstokadError {
|
|
20
|
+
issues;
|
|
21
|
+
constructor(body, issues) {
|
|
22
|
+
super('Validation failed', 422, body);
|
|
23
|
+
this.issues = issues;
|
|
24
|
+
this.name = 'ValidationError';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export class RateLimitError extends EstokadError {
|
|
28
|
+
retryAfter;
|
|
29
|
+
constructor(body, retryAfter) {
|
|
30
|
+
super('Rate limited', 429, body);
|
|
31
|
+
this.retryAfter = retryAfter;
|
|
32
|
+
this.name = 'RateLimitError';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export class UnauthorizedError extends EstokadError {
|
|
36
|
+
constructor(body) {
|
|
37
|
+
super('Unauthorized', 401, body);
|
|
38
|
+
this.name = 'UnauthorizedError';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export class WrongRegionError extends EstokadError {
|
|
42
|
+
redirect;
|
|
43
|
+
constructor(body, redirect) {
|
|
44
|
+
super('Wrong region for this workspace', 308, body);
|
|
45
|
+
this.redirect = redirect;
|
|
46
|
+
this.name = 'WrongRegionError';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,iCAAiC;AAEjC,MAAM,OAAO,YAAa,SAAQ,KAAK;IAGnB;IACA;IAHlB,YACE,OAAe,EACC,MAAc,EACd,IAAY;QAE5B,KAAK,CAAC,OAAO,CAAC,CAAA;QAHE,WAAM,GAAN,MAAM,CAAQ;QACd,SAAI,GAAJ,IAAI,CAAQ;QAG5B,IAAI,CAAC,IAAI,GAAG,cAAc,CAAA;IAC5B,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,YAAY;IAC7C,YAAY,IAAY;QACtB,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;QAC7B,IAAI,CAAC,IAAI,GAAG,eAAe,CAAA;IAC7B,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,YAAY;IAG7B;IAFlB,YACE,IAAY,EACI,MAA0E;QAE1F,KAAK,CAAC,mBAAmB,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;QAFrB,WAAM,GAAN,MAAM,CAAoE;QAG1F,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,cAAe,SAAQ,YAAY;IAG5B;IAFlB,YACE,IAAY,EACI,UAAkB;QAElC,KAAK,CAAC,cAAc,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;QAFhB,eAAU,GAAV,UAAU,CAAQ;QAGlC,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAA;IAC9B,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,YAAY;IACjD,YAAY,IAAY;QACtB,KAAK,CAAC,cAAc,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;QAChC,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAA;IACjC,CAAC;CACF;AAED,MAAM,OAAO,gBAAiB,SAAQ,YAAY;IAG9B;IAFlB,YACE,IAAY,EACI,QAAgB;QAEhC,KAAK,CAAC,iCAAiC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;QAFnC,aAAQ,GAAR,QAAQ,CAAQ;QAGhC,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAA;IAChC,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createClient } from './client.js';
|
|
2
|
+
export type { Client } from './client.js';
|
|
3
|
+
export { TypeClient } from './type-client.js';
|
|
4
|
+
export { EstokadError, NotFoundError, RateLimitError, UnauthorizedError, ValidationError, WrongRegionError, } from './errors.js';
|
|
5
|
+
export type { ClientOptions, ContentTypes, EntryEnvelope, EntryMeta, ListArgs } from './types.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EACL,YAAY,EACZ,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,gBAAgB,GACjB,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EACL,YAAY,EACZ,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,gBAAgB,GACjB,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ClientOptions } from './types.js';
|
|
2
|
+
interface RequestOptions {
|
|
3
|
+
readonly method?: string;
|
|
4
|
+
readonly body?: unknown;
|
|
5
|
+
readonly idempotencyKey?: string;
|
|
6
|
+
readonly query?: Record<string, string | number | undefined>;
|
|
7
|
+
}
|
|
8
|
+
export interface ResolvedConfig {
|
|
9
|
+
readonly apiUrl: string;
|
|
10
|
+
readonly workspace: string;
|
|
11
|
+
readonly apiKey: string;
|
|
12
|
+
readonly fetch: typeof globalThis.fetch;
|
|
13
|
+
}
|
|
14
|
+
export declare function resolveConfig(options: ClientOptions): ResolvedConfig;
|
|
15
|
+
export declare function request<T>(config: ResolvedConfig, path: string, opts?: RequestOptions): Promise<T>;
|
|
16
|
+
/** Run a GraphQL operation against the workspace's `/graphql` endpoint.
|
|
17
|
+
* Throws `EstokadError` if the response carries top-level `errors`. */
|
|
18
|
+
export declare function graphqlRequest<T>(config: ResolvedConfig, query: string, variables?: Record<string, unknown>): Promise<T>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAI/C,UAAU,cAAc;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,CAAA;CAC7D;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CACxC;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,cAAc,CAapE;AAED,wBAAsB,OAAO,CAAC,CAAC,EAC7B,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,CAAC,CAAC,CAyBZ;AAkBD;wEACwE;AACxE,wBAAsB,cAAc,CAAC,CAAC,EACpC,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACtC,OAAO,CAAC,CAAC,CAAC,CA0BZ"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// HTTP transport for the SDK.
|
|
2
|
+
//
|
|
3
|
+
// Wraps fetch with auth, error mapping (docs/api.md § 8 status codes), and
|
|
4
|
+
// idempotency keys for create. Other domains (graphql in M2.2b, webhooks in
|
|
5
|
+
// later phases) reuse this same primitive.
|
|
6
|
+
import { EstokadError, NotFoundError, RateLimitError, UnauthorizedError, ValidationError, WrongRegionError, } from './errors.js';
|
|
7
|
+
const DEFAULT_REGION = 'eu-fra-1';
|
|
8
|
+
export function resolveConfig(options) {
|
|
9
|
+
if (!options.workspace)
|
|
10
|
+
throw new EstokadError('workspace is required', 0, '');
|
|
11
|
+
if (!options.apiKey)
|
|
12
|
+
throw new EstokadError('apiKey is required', 0, '');
|
|
13
|
+
const region = options.region ?? DEFAULT_REGION;
|
|
14
|
+
const apiUrl = options.apiUrl ?? `https://${region.split('-')[0] ?? 'eu'}.api.estokad.eu`;
|
|
15
|
+
return {
|
|
16
|
+
apiUrl: apiUrl.replace(/\/$/, ''),
|
|
17
|
+
workspace: options.workspace,
|
|
18
|
+
apiKey: options.apiKey,
|
|
19
|
+
fetch: options.fetch ?? globalThis.fetch.bind(globalThis),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export async function request(config, path, opts = {}) {
|
|
23
|
+
const url = buildUrl(config, path, opts.query);
|
|
24
|
+
const headers = {
|
|
25
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
26
|
+
Accept: 'application/json',
|
|
27
|
+
};
|
|
28
|
+
const init = {
|
|
29
|
+
method: opts.method ?? 'GET',
|
|
30
|
+
headers,
|
|
31
|
+
};
|
|
32
|
+
if (opts.body !== undefined) {
|
|
33
|
+
headers['Content-Type'] = 'application/json';
|
|
34
|
+
init.body = JSON.stringify(opts.body);
|
|
35
|
+
}
|
|
36
|
+
if (opts.idempotencyKey) {
|
|
37
|
+
headers['Idempotency-Key'] = opts.idempotencyKey;
|
|
38
|
+
}
|
|
39
|
+
const res = await config.fetch(url, init);
|
|
40
|
+
if (!res.ok) {
|
|
41
|
+
throw await mapError(res);
|
|
42
|
+
}
|
|
43
|
+
// 204 No Content (delete)
|
|
44
|
+
if (res.status === 204)
|
|
45
|
+
return undefined;
|
|
46
|
+
return (await res.json());
|
|
47
|
+
}
|
|
48
|
+
function buildUrl(config, path, query) {
|
|
49
|
+
const base = `${config.apiUrl}/v1/${encodeURIComponent(config.workspace)}${path}`;
|
|
50
|
+
if (!query)
|
|
51
|
+
return base;
|
|
52
|
+
const params = new URLSearchParams();
|
|
53
|
+
for (const [k, v] of Object.entries(query)) {
|
|
54
|
+
if (v === undefined)
|
|
55
|
+
continue;
|
|
56
|
+
params.set(k, String(v));
|
|
57
|
+
}
|
|
58
|
+
const qs = params.toString();
|
|
59
|
+
return qs ? `${base}?${qs}` : base;
|
|
60
|
+
}
|
|
61
|
+
/** Run a GraphQL operation against the workspace's `/graphql` endpoint.
|
|
62
|
+
* Throws `EstokadError` if the response carries top-level `errors`. */
|
|
63
|
+
export async function graphqlRequest(config, query, variables = {}) {
|
|
64
|
+
const url = `${config.apiUrl}/v1/${encodeURIComponent(config.workspace)}/graphql`;
|
|
65
|
+
const res = await config.fetch(url, {
|
|
66
|
+
method: 'POST',
|
|
67
|
+
headers: {
|
|
68
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
69
|
+
'Content-Type': 'application/json',
|
|
70
|
+
Accept: 'application/json',
|
|
71
|
+
},
|
|
72
|
+
body: JSON.stringify({ query, variables }),
|
|
73
|
+
});
|
|
74
|
+
if (!res.ok) {
|
|
75
|
+
throw await mapError(res);
|
|
76
|
+
}
|
|
77
|
+
const body = (await res.json());
|
|
78
|
+
if (body.errors && body.errors.length > 0) {
|
|
79
|
+
throw new EstokadError(`GraphQL error: ${body.errors.map((e) => e.message).join(' / ')}`, 400, JSON.stringify(body.errors));
|
|
80
|
+
}
|
|
81
|
+
if (body.data === undefined) {
|
|
82
|
+
throw new EstokadError('GraphQL response missing data', 0, JSON.stringify(body));
|
|
83
|
+
}
|
|
84
|
+
return body.data;
|
|
85
|
+
}
|
|
86
|
+
async function mapError(res) {
|
|
87
|
+
let body = '';
|
|
88
|
+
try {
|
|
89
|
+
body = await res.text();
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
body = res.statusText;
|
|
93
|
+
}
|
|
94
|
+
const parsed = safeJson(body);
|
|
95
|
+
switch (res.status) {
|
|
96
|
+
case 401:
|
|
97
|
+
return new UnauthorizedError(body);
|
|
98
|
+
case 404:
|
|
99
|
+
return new NotFoundError(body);
|
|
100
|
+
case 422: {
|
|
101
|
+
const issues = Array.isArray(parsed.issues)
|
|
102
|
+
? parsed.issues
|
|
103
|
+
: [];
|
|
104
|
+
return new ValidationError(body, issues);
|
|
105
|
+
}
|
|
106
|
+
case 429: {
|
|
107
|
+
const retryAfter = Number(res.headers.get('Retry-After') ?? '1');
|
|
108
|
+
return new RateLimitError(body, retryAfter);
|
|
109
|
+
}
|
|
110
|
+
case 308:
|
|
111
|
+
case 301: {
|
|
112
|
+
const redirect = String(parsed.redirect ?? '');
|
|
113
|
+
return new WrongRegionError(body, redirect);
|
|
114
|
+
}
|
|
115
|
+
default:
|
|
116
|
+
return new EstokadError(`API ${res.status}`, res.status, body);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function safeJson(text) {
|
|
120
|
+
try {
|
|
121
|
+
return JSON.parse(text);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return {};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,EAAE;AACF,2EAA2E;AAC3E,4EAA4E;AAC5E,2CAA2C;AAE3C,OAAO,EACL,YAAY,EACZ,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,gBAAgB,GACjB,MAAM,aAAa,CAAA;AAGpB,MAAM,cAAc,GAAG,UAAU,CAAA;AAgBjC,MAAM,UAAU,aAAa,CAAC,OAAsB;IAClD,IAAI,CAAC,OAAO,CAAC,SAAS;QAAE,MAAM,IAAI,YAAY,CAAC,uBAAuB,EAAE,CAAC,EAAE,EAAE,CAAC,CAAA;IAC9E,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,MAAM,IAAI,YAAY,CAAC,oBAAoB,EAAE,CAAC,EAAE,EAAE,CAAC,CAAA;IAExE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,cAAc,CAAA;IAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,WAAW,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,iBAAiB,CAAA;IAEzF,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;QACjC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;KAC1D,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,MAAsB,EACtB,IAAY,EACZ,OAAuB,EAAE;IAEzB,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;IAC9C,MAAM,OAAO,GAA2B;QACtC,aAAa,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE;QACxC,MAAM,EAAE,kBAAkB;KAC3B,CAAA;IACD,MAAM,IAAI,GAAgB;QACxB,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,KAAK;QAC5B,OAAO;KACR,CAAA;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAA;QAC5C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACvC,CAAC;IACD,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,OAAO,CAAC,iBAAiB,CAAC,GAAG,IAAI,CAAC,cAAc,CAAA;IAClD,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IACzC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC3B,CAAC;IACD,0BAA0B;IAC1B,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO,SAAc,CAAA;IAC7C,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAM,CAAA;AAChC,CAAC;AAED,SAAS,QAAQ,CACf,MAAsB,EACtB,IAAY,EACZ,KAAmD;IAEnD,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,MAAM,OAAO,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,CAAA;IACjF,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAA;IACpC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3C,IAAI,CAAC,KAAK,SAAS;YAAE,SAAQ;QAC7B,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1B,CAAC;IACD,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;IAC5B,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AACpC,CAAC;AAED;wEACwE;AACxE,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAsB,EACtB,KAAa,EACb,YAAqC,EAAE;IAEvC,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,MAAM,OAAO,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAA;IACjF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;QAClC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE;YACxC,cAAc,EAAE,kBAAkB;YAClC,MAAM,EAAE,kBAAkB;SAC3B;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;KAC3C,CAAC,CAAA;IACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC3B,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA8D,CAAA;IAC5F,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,YAAY,CACpB,kBAAkB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,EACjE,GAAG,EACH,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAC5B,CAAA;IACH,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,YAAY,CAAC,+BAA+B,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;IAClF,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAA;AAClB,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,GAAa;IACnC,IAAI,IAAI,GAAG,EAAE,CAAA;IACb,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,GAAG,GAAG,CAAC,UAAU,CAAA;IACvB,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;IAE7B,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC;QACnB,KAAK,GAAG;YACN,OAAO,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAA;QACpC,KAAK,GAAG;YACN,OAAO,IAAI,aAAa,CAAC,IAAI,CAAC,CAAA;QAChC,KAAK,GAAG,CAAC,CAAC,CAAC;YACT,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAE,MAA+B,CAAC,MAAM,CAAC;gBACnE,CAAC,CAAE,MAAuE,CAAC,MAAM;gBACjF,CAAC,CAAC,EAAE,CAAA;YACN,OAAO,IAAI,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QAC1C,CAAC;QACD,KAAK,GAAG,CAAC,CAAC,CAAC;YACT,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,CAAA;YAChE,OAAO,IAAI,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;QAC7C,CAAC;QACD,KAAK,GAAG,CAAC;QACT,KAAK,GAAG,CAAC,CAAC,CAAC;YACT,MAAM,QAAQ,GAAG,MAAM,CAAE,MAAgC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAA;YACzE,OAAO,IAAI,gBAAgB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;QAC7C,CAAC;QACD;YACE,OAAO,IAAI,YAAY,CAAC,OAAO,GAAG,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IAClE,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ResolvedConfig } from './transport.js';
|
|
2
|
+
import type { EntryEnvelope, ListArgs } from './types.js';
|
|
3
|
+
export declare class TypeClient<T> {
|
|
4
|
+
private readonly typeName;
|
|
5
|
+
private readonly config;
|
|
6
|
+
constructor(typeName: string, config: ResolvedConfig);
|
|
7
|
+
/** Single fetch by id (or slug — pass `{ slug }` instead of `{ id }`).
|
|
8
|
+
* Returns null on 404, matching the shape consumers expect from
|
|
9
|
+
* getStaticProps / getServerSideProps. (M2.2c) */
|
|
10
|
+
get(args: {
|
|
11
|
+
id: string;
|
|
12
|
+
} | {
|
|
13
|
+
slug: string;
|
|
14
|
+
}): Promise<EntryEnvelope<T> | null>;
|
|
15
|
+
/** List with `first` / `offset`. Filters + orderBy + cursor pagination
|
|
16
|
+
* arrive in M2.1b once the API exposes them. */
|
|
17
|
+
list(args?: ListArgs): Promise<EntryEnvelope<T>[]>;
|
|
18
|
+
create(data: Partial<T>): Promise<EntryEnvelope<T>>;
|
|
19
|
+
update(id: string, data: Partial<T>): Promise<EntryEnvelope<T>>;
|
|
20
|
+
publish(id: string): Promise<EntryEnvelope<T>>;
|
|
21
|
+
unpublish(id: string): Promise<EntryEnvelope<T>>;
|
|
22
|
+
delete(id: string): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=type-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-client.d.ts","sourceRoot":"","sources":["../src/type-client.ts"],"names":[],"mappings":"AAMA,OAAO,EAAW,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAEzD,qBAAa,UAAU,CAAC,CAAC;IAErB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc;IAGzC;;uDAEmD;IAC7C,GAAG,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAcpF;qDACiD;IAC3C,IAAI,CAAC,IAAI,GAAE,QAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IActD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IASnD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAS/D,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAS9C,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAShD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAOxC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Per-content-type CRUD facade. One TypeClient per content type, exposed
|
|
2
|
+
// via the Proxy in client.ts so consumers do `client.pressRelease.get(...)`.
|
|
3
|
+
//
|
|
4
|
+
// All operations are REST in M2.2; GraphQL transport for reads (with
|
|
5
|
+
// reference resolution via DataLoader) lands in M2.2b.
|
|
6
|
+
import { request } from './transport.js';
|
|
7
|
+
export class TypeClient {
|
|
8
|
+
typeName;
|
|
9
|
+
config;
|
|
10
|
+
constructor(typeName, config) {
|
|
11
|
+
this.typeName = typeName;
|
|
12
|
+
this.config = config;
|
|
13
|
+
}
|
|
14
|
+
/** Single fetch by id (or slug — pass `{ slug }` instead of `{ id }`).
|
|
15
|
+
* Returns null on 404, matching the shape consumers expect from
|
|
16
|
+
* getStaticProps / getServerSideProps. (M2.2c) */
|
|
17
|
+
async get(args) {
|
|
18
|
+
const path = 'slug' in args
|
|
19
|
+
? `/content/${encodeURIComponent(this.typeName)}/_slug/${encodeURIComponent(args.slug)}`
|
|
20
|
+
: `/content/${encodeURIComponent(this.typeName)}/${encodeURIComponent(args.id)}`;
|
|
21
|
+
try {
|
|
22
|
+
const body = await request(this.config, path);
|
|
23
|
+
return body.entry;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
if (isNotFound(err))
|
|
27
|
+
return null;
|
|
28
|
+
throw err;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** List with `first` / `offset`. Filters + orderBy + cursor pagination
|
|
32
|
+
* arrive in M2.1b once the API exposes them. */
|
|
33
|
+
async list(args = {}) {
|
|
34
|
+
const body = await request(this.config, `/content/${encodeURIComponent(this.typeName)}`, {
|
|
35
|
+
query: {
|
|
36
|
+
first: args.first ?? 20,
|
|
37
|
+
offset: args.offset ?? 0,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
return body.entries;
|
|
41
|
+
}
|
|
42
|
+
async create(data) {
|
|
43
|
+
const body = await request(this.config, `/content/${encodeURIComponent(this.typeName)}`, { method: 'POST', body: data, idempotencyKey: cryptoRandomKey() });
|
|
44
|
+
return body.entry;
|
|
45
|
+
}
|
|
46
|
+
async update(id, data) {
|
|
47
|
+
const body = await request(this.config, `/content/${encodeURIComponent(this.typeName)}/${encodeURIComponent(id)}`, { method: 'PATCH', body: data });
|
|
48
|
+
return body.entry;
|
|
49
|
+
}
|
|
50
|
+
async publish(id) {
|
|
51
|
+
const body = await request(this.config, `/content/${encodeURIComponent(this.typeName)}/${encodeURIComponent(id)}/publish`, { method: 'POST' });
|
|
52
|
+
return body.entry;
|
|
53
|
+
}
|
|
54
|
+
async unpublish(id) {
|
|
55
|
+
const body = await request(this.config, `/content/${encodeURIComponent(this.typeName)}/${encodeURIComponent(id)}/unpublish`, { method: 'POST' });
|
|
56
|
+
return body.entry;
|
|
57
|
+
}
|
|
58
|
+
async delete(id) {
|
|
59
|
+
await request(this.config, `/content/${encodeURIComponent(this.typeName)}/${encodeURIComponent(id)}`, { method: 'DELETE' });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function isNotFound(err) {
|
|
63
|
+
return typeof err === 'object' && err !== null && err.status === 404;
|
|
64
|
+
}
|
|
65
|
+
function cryptoRandomKey() {
|
|
66
|
+
// Deterministic shape across Node + browsers + edge runtimes.
|
|
67
|
+
if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.randomUUID) {
|
|
68
|
+
return globalThis.crypto.randomUUID();
|
|
69
|
+
}
|
|
70
|
+
return Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=type-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-client.js","sourceRoot":"","sources":["../src/type-client.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface ContentTypes {
|
|
2
|
+
}
|
|
3
|
+
export interface ClientOptions {
|
|
4
|
+
/** Workspace slug (e.g. `white-castle`). */
|
|
5
|
+
readonly workspace: string;
|
|
6
|
+
/** Region code; defaults to `eu-fra-1`. */
|
|
7
|
+
readonly region?: string;
|
|
8
|
+
/** API base URL. Defaults to `https://{region}.api.estokad.eu` if region
|
|
9
|
+
* matches the public regions; for self-hosted / dev, set explicitly. */
|
|
10
|
+
readonly apiUrl?: string;
|
|
11
|
+
/** est_dlv_*, est_drf_*, or est_mgt_* per docs/api.md § 3. */
|
|
12
|
+
readonly apiKey: string;
|
|
13
|
+
/** True to read drafts; requires an `est_drf_*` or `est_mgt_*` key. */
|
|
14
|
+
readonly draft?: boolean;
|
|
15
|
+
/** Override fetch (testing). Defaults to global fetch. */
|
|
16
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
17
|
+
}
|
|
18
|
+
export interface EntryMeta {
|
|
19
|
+
readonly publishedAt: string | null;
|
|
20
|
+
readonly updatedAt: string;
|
|
21
|
+
readonly createdAt: string;
|
|
22
|
+
readonly status: 'published' | 'draft';
|
|
23
|
+
}
|
|
24
|
+
/** Common shape every entry has on top of its content fields. */
|
|
25
|
+
export type EntryEnvelope<T> = T & {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly _meta?: EntryMeta;
|
|
28
|
+
};
|
|
29
|
+
export interface ListArgs {
|
|
30
|
+
readonly first?: number;
|
|
31
|
+
readonly offset?: number;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,YAAY;CAK5B;AAED,MAAM,WAAW,aAAa;IAC5B,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB;6EACyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,uEAAuE;IACvE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;IACxB,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CACzC;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAA;CACvC;AAED,iEAAiE;AACjE,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAC3B,CAAA;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Shape declarations for the SDK.
|
|
2
|
+
//
|
|
3
|
+
// ContentTypes is the contract consumers extend via declaration merging
|
|
4
|
+
// (per docs/schema-system.md § 9 and api.md § 10):
|
|
5
|
+
//
|
|
6
|
+
// declare module '@estokad/sdk' {
|
|
7
|
+
// interface ContentTypes {
|
|
8
|
+
// pressRelease: PressRelease
|
|
9
|
+
// author: Author
|
|
10
|
+
// }
|
|
11
|
+
// }
|
|
12
|
+
//
|
|
13
|
+
// `estokad push` writes a generated d.ts that augments ContentTypes for
|
|
14
|
+
// every type the workspace knows; consumers don't import the types
|
|
15
|
+
// manually. Until that codegen is wired (M2.2b), consumers can declare-merge
|
|
16
|
+
// by hand against any TS interface.
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,wEAAwE;AACxE,mDAAmD;AACnD,EAAE;AACF,oCAAoC;AACpC,+BAA+B;AAC/B,mCAAmC;AACnC,uBAAuB;AACvB,QAAQ;AACR,MAAM;AACN,EAAE;AACF,wEAAwE;AACxE,mEAAmE;AACnE,6EAA6E;AAC7E,oCAAoC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@estokad/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Framework-agnostic TypeScript client for the Estokad content API.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/ELIASspaceMercer/estokad.git",
|
|
10
|
+
"directory": "packages/sdk"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://docs.estokad.com/docs/api",
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^22.10.0",
|
|
29
|
+
"typescript": "^5.7.0",
|
|
30
|
+
"vitest": "^2.1.0"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc -p tsconfig.json",
|
|
34
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
35
|
+
"test": "vitest run",
|
|
36
|
+
"lint": "eslint ."
|
|
37
|
+
}
|
|
38
|
+
}
|