baysecms-client 1.0.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/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # BayseCMS Client SDK
2
+
3
+ Small TypeScript client for BayseCMS APIs with a focus on frontend DX.
4
+
5
+ ## Create Client
6
+
7
+ ```ts
8
+ import { createBayseCMSClient } from "@your-scope/client";
9
+
10
+ const cms = createBayseCMSClient({
11
+ baseUrl: "http://localhost:4000",
12
+ accessToken: "<jwt-access-token>"
13
+ });
14
+ ```
15
+
16
+ You can also provide:
17
+
18
+ - `getAccessToken: async () => string` for token refresh flows
19
+ - `apiKey`, `tenantId`, `workspaceId` for server-to-server usage
20
+
21
+ ## Frontend-ready v2 Delivery APIs
22
+
23
+ ### List content
24
+
25
+ ```ts
26
+ const response = await cms.getContent({
27
+ schema: "rooms",
28
+ limit: 20,
29
+ status: "published"
30
+ });
31
+
32
+ console.log(response.items);
33
+ console.log(response.pageInfo);
34
+ ```
35
+
36
+ ### Get by slug
37
+
38
+ ```ts
39
+ const room = await cms.getContentBySlug("rooms", "deluxe-room");
40
+ console.log(room.data.title);
41
+ ```
42
+
43
+ ## Response shape (v2)
44
+
45
+ Each item is normalized for frontend consumption:
46
+
47
+ ```ts
48
+ type DeliveryItem = {
49
+ id: string;
50
+ slug: string | null;
51
+ createdAt: string | null;
52
+ updatedAt: string | null;
53
+ data: Record<string, unknown>;
54
+ };
55
+ ```
56
+
57
+ Notes:
58
+
59
+ - `data` uses field keys as defined in schema
60
+ - image fields are normalized to `{ url, alt }` (or arrays of this shape)
61
+ - array/object fields are consistently normalized (`[]`, `{}`)
62
+
63
+ ## Legacy/admin APIs still available
64
+
65
+ The client also supports existing endpoints:
66
+
67
+ - `listSchemas()`
68
+ - `upsertContent(input)`
69
+ - `listDocuments(collection)`
70
+ - `getDocument(collection, documentId)`
71
+ - `deleteDocument(collection, documentId)`
72
+ - `listPublished(collection)`
73
+
74
+ ## Error handling
75
+
76
+ SDK throws `Error` with extra metadata:
77
+
78
+ - `error.status` (HTTP code)
79
+ - `error.body` (parsed response body when available)
80
+
81
+ Example:
82
+
83
+ ```ts
84
+ try {
85
+ await cms.getContent({ schema: "rooms" });
86
+ } catch (error) {
87
+ const e = error as Error & { status?: number; body?: unknown };
88
+ console.error(e.status, e.body);
89
+ }
90
+ ```
@@ -0,0 +1,45 @@
1
+ import type { ContentDocument, DeliveryBySlugResponse, DeliveryListQuery, DeliveryListResponse, ListSchemasResponse, OkResponse, UpsertContentInput } from "./types.js";
2
+ export type BayseCMSClientOptions = {
3
+ /** API origin, e.g. https://api.example.com */
4
+ baseUrl: string;
5
+ /** Bearer JWT (Cognito access token or HS256 dev token). */
6
+ getAccessToken?: () => string | Promise<string>;
7
+ /** Static token if you do not use async refresh. */
8
+ accessToken?: string;
9
+ /** Server-to-server or delivery-only auth */
10
+ apiKey?: string;
11
+ tenantId?: string;
12
+ workspaceId?: string;
13
+ };
14
+ export declare class BayseCMSClient {
15
+ private readonly options;
16
+ constructor(options: BayseCMSClientOptions);
17
+ private headers;
18
+ private request;
19
+ /** Raw GET request for generated helpers and advanced consumers. */
20
+ get<T>(path: string): Promise<T>;
21
+ /** Raw POST request for generated helpers and advanced consumers. */
22
+ post<T>(path: string, body?: unknown): Promise<T>;
23
+ /** List schema versions for the current tenant/workspace. */
24
+ listSchemas(): Promise<ListSchemasResponse>;
25
+ /** Single schema version (for building UIs / validation). */
26
+ getSchema(schemaId: string, version: number): Promise<unknown>;
27
+ /** Create or update a document (requires editor+ JWT). */
28
+ upsertContent(input: UpsertContentInput): Promise<OkResponse>;
29
+ /** All documents in a collection (draft + published). */
30
+ listDocuments(collection: string): Promise<ContentDocument[]>;
31
+ getDocument(collection: string, documentId: string): Promise<ContentDocument>;
32
+ deleteDocument(collection: string, documentId: string): Promise<OkResponse>;
33
+ /** Published documents for a collection (viewer JWT or API key). */
34
+ listPublished(collection: string): Promise<ContentDocument[]>;
35
+ /**
36
+ * Frontend-ready normalized content list (v2 API).
37
+ * Returns stable shape: { id, slug, createdAt, updatedAt, data }.
38
+ */
39
+ getContent(query: DeliveryListQuery): Promise<DeliveryListResponse>;
40
+ /**
41
+ * Frontend-ready single item fetch by slug (v2 API).
42
+ */
43
+ getContentBySlug(schema: string, slug: string): Promise<DeliveryBySlugResponse["item"]>;
44
+ }
45
+ export declare function createBayseCMSClient(options: BayseCMSClientOptions): BayseCMSClient;
package/dist/client.js ADDED
@@ -0,0 +1,118 @@
1
+ const normalizeBase = (url) => url.replace(/\/$/, "");
2
+ export class BayseCMSClient {
3
+ options;
4
+ constructor(options) {
5
+ this.options = options;
6
+ }
7
+ async headers() {
8
+ const h = {
9
+ "content-type": "application/json",
10
+ accept: "application/json"
11
+ };
12
+ let token = this.options.accessToken;
13
+ if (this.options.getAccessToken) {
14
+ token = await this.options.getAccessToken();
15
+ }
16
+ if (token) {
17
+ h.authorization = `Bearer ${token}`;
18
+ }
19
+ if (this.options.apiKey) {
20
+ h["x-api-key"] = this.options.apiKey;
21
+ }
22
+ else {
23
+ if (this.options.tenantId) {
24
+ h["x-tenant-id"] = this.options.tenantId;
25
+ }
26
+ if (this.options.workspaceId) {
27
+ h["x-workspace-id"] = this.options.workspaceId;
28
+ }
29
+ }
30
+ return h;
31
+ }
32
+ async request(method, path, body) {
33
+ const url = `${normalizeBase(this.options.baseUrl)}${path.startsWith("/") ? path : `/${path}`}`;
34
+ const res = await fetch(url, {
35
+ method,
36
+ headers: await this.headers(),
37
+ body: body !== undefined && method !== "GET" && method !== "DELETE" ? JSON.stringify(body) : undefined
38
+ });
39
+ const text = await res.text();
40
+ let data = text;
41
+ try {
42
+ data = text ? JSON.parse(text) : undefined;
43
+ }
44
+ catch {
45
+ data = text;
46
+ }
47
+ if (!res.ok) {
48
+ const err = new Error(`BayseCMS ${res.status}: ${typeof data === "string" ? data : JSON.stringify(data)}`);
49
+ err.status = res.status;
50
+ err.body = data;
51
+ throw err;
52
+ }
53
+ return data;
54
+ }
55
+ /** Raw GET request for generated helpers and advanced consumers. */
56
+ async get(path) {
57
+ return this.request("GET", path);
58
+ }
59
+ /** Raw POST request for generated helpers and advanced consumers. */
60
+ async post(path, body) {
61
+ return this.request("POST", path, body);
62
+ }
63
+ /** List schema versions for the current tenant/workspace. */
64
+ async listSchemas() {
65
+ return this.request("GET", "/schemas");
66
+ }
67
+ /** Single schema version (for building UIs / validation). */
68
+ async getSchema(schemaId, version) {
69
+ return this.request("GET", `/schemas/${encodeURIComponent(schemaId)}/${encodeURIComponent(String(version))}`);
70
+ }
71
+ /** Create or update a document (requires editor+ JWT). */
72
+ async upsertContent(input) {
73
+ return this.request("POST", "/content/upsert", input);
74
+ }
75
+ /** All documents in a collection (draft + published). */
76
+ async listDocuments(collection) {
77
+ const path = `/content/documents/${encodeURIComponent(collection)}`;
78
+ const res = await this.request("GET", path);
79
+ return res.items ?? [];
80
+ }
81
+ async getDocument(collection, documentId) {
82
+ return this.request("GET", `/content/documents/${encodeURIComponent(collection)}/${encodeURIComponent(documentId)}`);
83
+ }
84
+ async deleteDocument(collection, documentId) {
85
+ return this.request("DELETE", `/content/documents/${encodeURIComponent(collection)}/${encodeURIComponent(documentId)}`);
86
+ }
87
+ /** Published documents for a collection (viewer JWT or API key). */
88
+ async listPublished(collection) {
89
+ const path = `/delivery/${encodeURIComponent(collection)}`;
90
+ const res = await this.request("GET", path);
91
+ return res.items ?? [];
92
+ }
93
+ /**
94
+ * Frontend-ready normalized content list (v2 API).
95
+ * Returns stable shape: { id, slug, createdAt, updatedAt, data }.
96
+ */
97
+ async getContent(query) {
98
+ const params = new URLSearchParams();
99
+ params.set("schema", query.schema);
100
+ if (query.limit !== undefined)
101
+ params.set("limit", String(query.limit));
102
+ if (query.cursor)
103
+ params.set("cursor", query.cursor);
104
+ if (query.status)
105
+ params.set("status", query.status);
106
+ return this.request("GET", `/v2/content?${params.toString()}`);
107
+ }
108
+ /**
109
+ * Frontend-ready single item fetch by slug (v2 API).
110
+ */
111
+ async getContentBySlug(schema, slug) {
112
+ const res = await this.request("GET", `/v2/content/${encodeURIComponent(schema)}/${encodeURIComponent(slug)}`);
113
+ return res.item;
114
+ }
115
+ }
116
+ export function createBayseCMSClient(options) {
117
+ return new BayseCMSClient(options);
118
+ }
@@ -0,0 +1,3 @@
1
+ export { BayseCMSClient, createBayseCMSClient } from "./client.js";
2
+ export type { BayseCMSClientOptions } from "./client.js";
3
+ export type { ContentDocument, DeliveryBySlugResponse, DeliveryImage, DeliveryItem, DeliveryListQuery, DeliveryListResponse, ListDocumentsResponse, ListPublishedResponse, ListSchemasResponse, OkResponse, UpsertContentInput } from "./types.js";
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { BayseCMSClient, createBayseCMSClient } from "./client.js";
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Types aligned with BayseCMS HTTP API (delivery + content upsert).
3
+ */
4
+ export type UpsertContentInput = {
5
+ documentId: string;
6
+ collection: string;
7
+ schemaId: string;
8
+ schemaVersion: number;
9
+ status: "draft" | "published";
10
+ data: Record<string, unknown>;
11
+ };
12
+ export type ContentDocument = UpsertContentInput & {
13
+ createdAt?: string;
14
+ updatedAt?: string;
15
+ };
16
+ export type DeliveryImage = {
17
+ url: string;
18
+ alt?: string;
19
+ };
20
+ export type DeliveryItem = {
21
+ id: string;
22
+ slug: string | null;
23
+ createdAt: string | null;
24
+ updatedAt: string | null;
25
+ data: Record<string, unknown>;
26
+ };
27
+ export type DeliveryListQuery = {
28
+ schema: string;
29
+ limit?: number;
30
+ cursor?: string;
31
+ status?: "published" | "draft" | "all";
32
+ };
33
+ export type DeliveryPageInfo = {
34
+ nextCursor: string | null;
35
+ hasMore: boolean;
36
+ };
37
+ export type DeliveryListResponse = {
38
+ items: DeliveryItem[];
39
+ pageInfo: DeliveryPageInfo;
40
+ };
41
+ export type DeliveryBySlugResponse = {
42
+ item: DeliveryItem;
43
+ };
44
+ export type ListSchemasResponse = {
45
+ items: unknown[];
46
+ };
47
+ export type ListPublishedResponse = {
48
+ items: ContentDocument[];
49
+ };
50
+ export type OkResponse = {
51
+ ok: boolean;
52
+ };
53
+ export type ListDocumentsResponse = {
54
+ items: ContentDocument[];
55
+ };
package/dist/types.js ADDED
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Types aligned with BayseCMS HTTP API (delivery + content upsert).
3
+ */
4
+ export {};
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "baysecms-client",
3
+ "version": "1.0.0",
4
+ "description": "TypeScript client SDK for BayseCMS APIs",
5
+ "license": "UNLICENSED",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "sideEffects": false,
20
+ "scripts": {
21
+ "build": "tsc -p tsconfig.json"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ }
26
+ }