@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 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.
@@ -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"}
@@ -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"}
@@ -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,4 @@
1
+ export { createClient } from './client.js';
2
+ export { TypeClient } from './type-client.js';
3
+ export { EstokadError, NotFoundError, RateLimitError, UnauthorizedError, ValidationError, WrongRegionError, } from './errors.js';
4
+ //# sourceMappingURL=index.js.map
@@ -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":"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"}
@@ -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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"}
@@ -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
+ }