@prenta/client 0.6.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/CHANGELOG.md ADDED
@@ -0,0 +1,166 @@
1
+ # @actuate-media/client
2
+
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5eea995: Product rename: ActuateCMS is now **Prenta**. Every package moves from the
8
+ `@actuate-media/*` scope to `@prenta/*` with simplified names (`@prenta/core`,
9
+ `@prenta/admin`, `create-prenta`), and version numbers continue from where the
10
+ old scope left off.
11
+
12
+ This is a clean break — no backwards-compat aliases:
13
+ - **npm packages**: `@actuate-media/cms-core` → `@prenta/core`,
14
+ `@actuate-media/cms-admin` → `@prenta/admin`, all other packages keep their
15
+ suffix under `@prenta/*`. `create-actuate-cms` → `create-prenta`
16
+ (`npm create prenta`), `create-actuate-astro` → `create-prenta-astro`.
17
+ CLI bins: `actuate`/`actuate-cms` → `prenta`/`prenta-cms`; `actuate-mcp` →
18
+ `prenta-mcp`.
19
+ - **Database**: migration `0012_rename_to_prenta` renames all 36 `actuate_*`
20
+ tables to `prenta_*` in place (plus prefixed constraints, indexes, and
21
+ sequences). Run `prisma migrate deploy` when upgrading.
22
+ - **Runtime identifiers**: `getActuateConfig` → `getPrentaConfig`,
23
+ `handleActuateAPI` → `handlePrentaAPI`, `ActuateClient` → `PrentaClient`,
24
+ `ActuateDB` → `PrentaDB`, config file `actuate.config.ts` →
25
+ `prenta.config.ts`, CSS scopes `.actuate-admin`/`.actuate-canvas` →
26
+ `.prenta-admin`/`.prenta-canvas`, preview protocol `actuate-preview:*` →
27
+ `prenta-preview:*`, webhook headers `X-Actuate-*` → `X-Prenta-*`, session
28
+ cookie `actuate_session` → `prenta_session`, env vars `ACTUATE_*` →
29
+ `PRENTA_*`, purge route `/api/actuate/purge` → `/api/prenta/purge`.
30
+ - **Sessions and webhooks**: all sessions reset on upgrade (cookie + JWT issuer
31
+ changed); webhook consumers must re-verify signatures against the new
32
+ `X-Prenta-*` headers.
33
+
34
+ The old `@actuate-media/*` packages are deprecated on npm and will receive no
35
+ further releases.
36
+
37
+ ## 0.5.3
38
+
39
+ ### Patch Changes
40
+
41
+ - 041a228: Add the MIT `license` field to every published package (previously missing) and correct `repository.url` to `github.com/actuate-media/actuatecms` (13 packages carried the wrong org).
42
+
43
+ ## 0.5.2
44
+
45
+ ### Patch Changes
46
+
47
+ - 854152d: Developer experience improvements from external-consumer feedback:
48
+ - Every published package now ships its `CHANGELOG.md` in the npm tarball, and packages that were missing a `README.md` (cli, cms-admin, cms-core, import, platform-vercel, all plugins, sections-react) now have one — so release notes and usage docs are visible on npmjs.com and in `node_modules`.
49
+ - New client-safe form validation entry point: `@actuate-media/cms-core/forms/client` exports `validateFormFieldClient()`, `validateFormValuesClient()`, visibility/conditional helpers, and the exact `FORM_EMAIL_RE` / `FORM_PHONE_RE` regexes the server enforces — zero Node dependencies, so public-site forms can mirror server rules without reimplementing them. The server validator now imports the same primitives, so client and server can never drift.
50
+
51
+ ## 0.5.1
52
+
53
+ ### Patch Changes
54
+
55
+ - 29f32ba: Formally declare `@actuate-media/client` as a **read-only delivery SDK** (roadmap B3 decision). Added a package README and expanded the `ActuateClient` JSDoc to state the scope explicitly: the SDK covers `list`/`get`/`getGlobal`/`resolve`/`listMedia` for fetching published content and ships no write methods by design. Programmatic authoring is routed to MCP (`@actuate-media/mcp-server`) or the authenticated HTTP API. No runtime/API changes.
56
+
57
+ ## 0.5.0
58
+
59
+ ### Minor Changes
60
+
61
+ - 01eef99: Add `SCHEDULED_UNPUBLISH` to the document status union and export a shared
62
+ `ActuateDocumentStatus` type. The server's `DocumentStatus` enum includes
63
+ `SCHEDULED_UNPUBLISH` (used by scheduled unpublish flows), but the client's
64
+ `ActuateDocument.status` / `ListQuery.status` unions omitted it — so a document
65
+ the API could legitimately return wasn't representable in a consumer's typed
66
+ `switch`/filter. The unions now match the server contract exactly.
67
+
68
+ ## 0.4.0
69
+
70
+ ### Minor Changes
71
+
72
+ - ae1af8f: Authoring correctness fixes for the AI site-building workflow (roadmap WS-B/E quick wins).
73
+ - **cms-core**: `createDocument` now honors a requested `status` (`DRAFT` or
74
+ `PUBLISHED`) instead of always forcing `DRAFT`. Publishing on create is gated
75
+ to EDITOR/ADMIN, stamps `publishedAt`, and emits the `document.published`
76
+ webhook + sitemap notify. This fixes `POST /page-builder/create?publish=true`
77
+ (and `status: 'PUBLISHED'`), which previously created a draft silently.
78
+ Statuses other than `DRAFT`/`PUBLISHED` on create are rejected with guidance
79
+ to schedule/archive via update.
80
+ - **client**: `listMedia()` now returns the canonical
81
+ `{ docs, total, page, pageSize, totalPages }` (`MediaList`) envelope. The
82
+ server returns the asset array under `items`/`data` (never `docs`), so the
83
+ previous typing made `listMedia().docs` always `undefined`. Adds exported
84
+ `MediaAsset` and `MediaList` types and an optional `init` (signal/cache) arg.
85
+ - **mcp-server**: the `list_media` tool now normalizes the same `items`→`docs`
86
+ shape so its output matches `list_documents`.
87
+ - **create-actuate-cms**: generated `TextBlock`/`ImageTextBlock` now sanitize
88
+ author-supplied HTML with `sanitizeHtml` before `dangerouslySetInnerHTML`
89
+ (was an XSS vector on hostile content).
90
+
91
+ ## 0.3.0
92
+
93
+ ### Minor Changes
94
+
95
+ - abc7924: Phase 5.5 #1: tag-based edge caching for public document reads.
96
+ - **`@actuate-media/client`**: `list`, `get`, `global`, `resolve`, and
97
+ `listMedia` now automatically attach per-resource cache tags
98
+ (`actuate:collection:<slug>`, `actuate:doc:<id>`,
99
+ `actuate:global:<slug>`, `actuate:path:<path>`) alongside the existing
100
+ wholesale `actuate` tag. New exported helpers `actuateTag(kind, slug)`
101
+ and `actuateTags(kind, ...)` return the canonical tag set so a
102
+ webhook handler can call `revalidateTag()` with the exact same
103
+ strings the SDK uses for reads. The `tags` field on `defaultCache`
104
+ remains opt-in; resource tags are merged on top of it and deduped.
105
+ `revalidate: false` (no-store) bypasses tag emission entirely.
106
+ - **`@actuate-media/cms-core`**: new top-level `cache?: CacheConfig`
107
+ field on `ActuateCMSConfig`. When `cache.publicReads.enabled` is true
108
+ the four read endpoints (`GET /collections/:slug`,
109
+ `GET /collections/:slug/:id`, `GET /globals/:slug`, `GET /resolve`)
110
+ emit `Cache-Control: public, s-maxage=<maxAge>, stale-while-revalidate=<swr>`
111
+ for unauthenticated and API-key requests. Session-cookie requests
112
+ always get `private, no-store`; preview-token resolve requests bypass
113
+ the cache. New `cache.onInvalidate` hook fires after every
114
+ create/update/delete and global update with the canonical tag set;
115
+ failures are swallowed so cache invalidation can never roll back a
116
+ successful write. The cache layer is off by default — existing
117
+ consumers see no behaviour change until they opt in. See
118
+ `docs/caching.md` for the full contract.
119
+
120
+ ## 0.2.2
121
+
122
+ ### Patch Changes
123
+
124
+ - 4259d9a: Remove dead 404 catch from `resolvePagePath` in `@actuate-media/client/next`.
125
+
126
+ `resolvePagePath` used to wrap `client.resolve(path)` in its own try/catch that returned `null` on 404. As of `@actuate-media/client@0.2.1`, `client.resolve()` already handles 404 internally and returns `null`, making the wrapper's catch block dead code that misleads consumers into thinking `resolve()` still throws on 404. The helper is now a thin pass-through that delegates directly to `client.resolve()` — non-404 errors still propagate, which is what you want inside a Server Component (Next.js renders a 500).
127
+
128
+ Caught by Cursor Bugbot during review of PR #66. Regression test added.
129
+
130
+ ## 0.2.1
131
+
132
+ ### Patch Changes
133
+
134
+ - 75e696d: Fix two correctness bugs in `@actuate-media/client` introduced in 0.1/0.2:
135
+ - `ActuateClient.resolve(path)` now returns `null` when the CMS responds with `404` for an unmatched path, matching the documented `Promise<ActuateDocument | null>` contract. It previously threw `ActuateError` for any missing route, forcing callers to wrap every `resolve()` in a try/catch.
136
+ - `ActuateClient.global(slug)` now correctly unwraps the single-level `{ data: <global> }` envelope that `GET /globals/:slug` returns. It previously looked for `data.data`, so every call returned `undefined`.
137
+
138
+ Regression tests added for both behaviors. No public API surface changes.
139
+
140
+ ## 0.2.0
141
+
142
+ ### Minor Changes
143
+
144
+ - 866a861: Ship `@actuate-media/client` — the official type-safe HTTP client for
145
+ reading Actuate CMS content (Phase 1 of the roadmap).
146
+
147
+ The package exposes three sub-paths:
148
+ - `@actuate-media/client` — the core `ActuateClient` / `createClient`
149
+ factory. Pass your `actuate.config.ts` as a generic parameter and the
150
+ client surface auto-derives field types from your collection
151
+ definitions — no codegen step required.
152
+ - `@actuate-media/client/react` — dependency-free `useCollection`,
153
+ `useContent`, and `useGlobal` hooks for client components. Built-in
154
+ AbortController support cancels stale requests on key change.
155
+ - `@actuate-media/client/next` — `createNextClient()` that defaults to
156
+ Next.js fetch cache semantics (`revalidate` + `tags`) plus an
157
+ `actuateTag()` helper for `revalidateTag()` invalidation from webhook
158
+ handlers.
159
+
160
+ The runtime is < 5 KB gzipped with zero dependencies. React is an
161
+ optional peer dependency (only required if you import from `./react`).
162
+
163
+ Tests: 9 unit tests covering pagination, filters, auth headers, custom
164
+ headers, public/no-key mode, default+per-call cache, error envelopes.
165
+
166
+ Docs: `docs/client-sdk.md`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Actuate Media
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # @prenta/client
2
+
3
+ Type-safe **read / delivery** client and React hooks for the
4
+ [Prenta CMS](https://github.com/actuate-media/prenta) REST API.
5
+
6
+ ```bash
7
+ npm install @prenta/client
8
+ ```
9
+
10
+ ## Scope: read-only by design
11
+
12
+ This SDK is the **delivery** layer — it fetches **published** content into a
13
+ frontend. It is intentionally **read-only** and ships **no**
14
+ create/update/delete/publish or upload methods.
15
+
16
+ | You want to… | Use |
17
+ | ---------------------------------- | ------------------------------------------------------------- |
18
+ | Render published content in a site | **This package** (`@prenta/client`) |
19
+ | Create / edit / publish content | **MCP** (`@prenta/mcp-server`) — for AI agents & tooling |
20
+ | Script writes from a backend / CI | The authenticated **HTTP API** (`POST/PUT/DELETE /api/cms/…`) |
21
+
22
+ Keeping authoring out of the delivery package is a deliberate decision: the
23
+ delivery bundle stays small, its API key only needs the `read` scope, and the
24
+ entire write surface stays auditable in one place (the CMS API + MCP server).
25
+ If you need an authoring SDK, drive the documented HTTP endpoints — the same
26
+ ones the [MCP server](https://github.com/actuate-media/prenta) calls.
27
+
28
+ ## Usage
29
+
30
+ ```ts
31
+ import { PrentaClient } from '@prenta/client'
32
+ import type prentaConfig from './prenta.config'
33
+
34
+ const client = new PrentaClient<typeof prentaConfig>({
35
+ url: 'https://your-site.com',
36
+ apiKey: process.env.PRENTA_API_KEY, // read scope is sufficient
37
+ })
38
+
39
+ // List published posts (typed by your config)
40
+ const { docs } = await client.list('posts', { status: 'PUBLISHED' })
41
+
42
+ // Fetch a single document, a global, or resolve a public URL
43
+ const post = await client.get('posts', id)
44
+ const brand = await client.getGlobal('brand')
45
+ const page = await client.resolve('/about')
46
+
47
+ // Media assets come back as the canonical { docs, total, page, … } envelope
48
+ const { docs: media } = await client.listMedia({ search: 'logo' })
49
+ ```
50
+
51
+ React and Next.js entrypoints are available at `@prenta/client/react`
52
+ and `@prenta/client/next` (the latter wires `next/cache` tags +
53
+ `revalidate`).
54
+
55
+ ## License
56
+
57
+ MIT
@@ -0,0 +1,147 @@
1
+ import type { PrentaConfigLike, PrentaDocument, PrentaList, CollectionData, GlobalData, ListQuery, MediaList } from './types.js';
2
+ export type { PrentaConfigLike, PrentaDocument, PrentaDocumentStatus, PrentaList, PrentaFieldDefinition, CollectionData, GlobalData, FieldToType, FieldsToData, ListQuery, MediaAsset, MediaList, } from './types.js';
3
+ export interface PrentaClientOptions {
4
+ /** Base URL of the CMS (e.g. `https://maidpro.co`). `/api/cms` is appended automatically. */
5
+ url: string;
6
+ /** API key with at least `read` scope on the collections you want to query. */
7
+ apiKey?: string;
8
+ /** Override the global `fetch` implementation (e.g. in tests, or to bind a custom retry policy). */
9
+ fetchImpl?: typeof fetch;
10
+ /**
11
+ * Optional default cache settings forwarded to `fetch` as request init.
12
+ * Used by `next` integration to set `next: { revalidate, tags }`.
13
+ */
14
+ defaultCache?: {
15
+ revalidate?: number | false;
16
+ tags?: string[];
17
+ };
18
+ /** Additional headers attached to every request (e.g. a tenant header). */
19
+ headers?: Record<string, string>;
20
+ }
21
+ export declare class PrentaError extends Error {
22
+ readonly status: number;
23
+ readonly response: unknown;
24
+ constructor(message: string, status: number, response?: unknown);
25
+ }
26
+ /**
27
+ * Type-safe **read / delivery** client for the Prenta CMS REST API.
28
+ *
29
+ * Scope (deliberate): this SDK is **read-only**. It covers the public
30
+ * delivery surface — `list`, `get`, `getGlobal`, `resolve`, `listMedia`,
31
+ * plus the React/Next cache helpers — for fetching published content into a
32
+ * frontend. It intentionally ships **no** create/update/delete/publish or
33
+ * upload methods.
34
+ *
35
+ * **Authoring belongs to agents and tooling, not the delivery SDK.** To
36
+ * create or mutate content programmatically, drive the CMS over **MCP**
37
+ * (`@prenta/mcp-server`) or call the authenticated HTTP API directly
38
+ * (`POST/PUT/DELETE /api/cms/collections/:slug`, `/media/upload`, …). Keeping
39
+ * authoring out of this package keeps the delivery bundle small, its API key
40
+ * scoped to `read`, and the write surface auditable in one place.
41
+ *
42
+ * The class is generic over a config type so consumers get field-level
43
+ * autocomplete when they pass their `typeof prentaConfig` as the type
44
+ * parameter. Consumers who don't pass a config still get a working — but
45
+ * loosely-typed — client.
46
+ */
47
+ export declare class PrentaClient<Config extends PrentaConfigLike = PrentaConfigLike> {
48
+ readonly url: string;
49
+ readonly apiKey?: string;
50
+ private readonly fetchImpl;
51
+ private readonly defaultCache?;
52
+ private readonly extraHeaders?;
53
+ constructor(opts: PrentaClientOptions);
54
+ private headers;
55
+ private request;
56
+ /**
57
+ * List documents in a collection. Returns `{ docs, total, page, pageSize, totalPages }`.
58
+ *
59
+ * @example
60
+ * const { docs } = await client.list('posts', { status: 'PUBLISHED' })
61
+ */
62
+ list<Slug extends keyof NonNullable<Config['collections']> & string>(collection: Slug, query?: ListQuery, init?: {
63
+ signal?: AbortSignal;
64
+ cache?: PrentaClientOptions['defaultCache'];
65
+ }): Promise<PrentaList<CollectionData<Config, Slug>>>;
66
+ /** Fetch a single document by ID. */
67
+ get<Slug extends keyof NonNullable<Config['collections']> & string>(collection: Slug, id: string, init?: {
68
+ populate?: string;
69
+ signal?: AbortSignal;
70
+ cache?: PrentaClientOptions['defaultCache'];
71
+ }): Promise<PrentaDocument<CollectionData<Config, Slug>>>;
72
+ /** Resolve a public URL path (e.g. `/blog/my-post`) to its document. */
73
+ resolve(path: string, init?: {
74
+ signal?: AbortSignal;
75
+ cache?: PrentaClientOptions['defaultCache'];
76
+ }): Promise<PrentaDocument | null>;
77
+ /** Fetch a global by slug. */
78
+ global<Slug extends keyof NonNullable<Config['globals']> & string>(slug: Slug, init?: {
79
+ signal?: AbortSignal;
80
+ cache?: PrentaClientOptions['defaultCache'];
81
+ }): Promise<GlobalData<Config, Slug>>;
82
+ /**
83
+ * List media assets. Returns the canonical `{ docs, total, page, pageSize,
84
+ * totalPages }` envelope (same shape as {@link PrentaClient.list}).
85
+ *
86
+ * The `GET /media` endpoint returns the asset array under `items`/`data`
87
+ * (never `docs`), plus pagination fields. This method normalizes that into
88
+ * the standard list contract so callers can destructure `{ docs }` exactly
89
+ * like collection lists.
90
+ */
91
+ listMedia(query?: {
92
+ page?: number;
93
+ pageSize?: number;
94
+ search?: string;
95
+ }, init?: {
96
+ signal?: AbortSignal;
97
+ cache?: PrentaClientOptions['defaultCache'];
98
+ }): Promise<MediaList>;
99
+ }
100
+ /**
101
+ * Tag-helper for `next/cache` `revalidateTag` calls. Returns the canonical
102
+ * tag the SDK applies for a given collection, global, single document, or
103
+ * resolved path.
104
+ *
105
+ * The full tag taxonomy is documented in {@link prentaTags}.
106
+ */
107
+ export declare function prentaTag(kind: 'collection' | 'global' | 'doc' | 'path', slug: string): string;
108
+ /**
109
+ * Canonical cache-tag set the SDK emits on a given request. Exported so
110
+ * consumers can call `revalidateTag()` from a webhook handler with the
111
+ * exact same tags the SDK uses for reads.
112
+ *
113
+ * Tag taxonomy:
114
+ *
115
+ * - `prenta` — the always-on global tag (added on every request). A
116
+ * single `revalidateTag('prenta')` blows away the entire CMS cache.
117
+ * Use sparingly — most invalidations should be narrower.
118
+ * - `prenta:collection:<slug>` — list responses for `<slug>`. Invalidate
119
+ * when any document in the collection is created, updated, or deleted.
120
+ * - `prenta:doc:<id>` — single-document responses. Invalidate when that
121
+ * specific document is updated or deleted.
122
+ * - `prenta:global:<slug>` — global responses for `<slug>`. Invalidate
123
+ * when the global is updated.
124
+ * - `prenta:path:<path>` — `resolve(path)` responses. Tagged on read but
125
+ * the server does not currently invalidate these automatically; if you
126
+ * move a document or change a slug, invalidate the affected path tag
127
+ * from your own webhook handler.
128
+ *
129
+ * @example
130
+ * // In a Next.js webhook handler:
131
+ * import { prentaTags } from '@prenta/client'
132
+ * import { revalidateTag } from 'next/cache'
133
+ * for (const t of prentaTags('collection', event.collection)) {
134
+ * revalidateTag(t)
135
+ * }
136
+ */
137
+ export declare function prentaTags(kind: 'collection', slug: string): string[];
138
+ export declare function prentaTags(kind: 'doc', collectionSlug: string, id: string): string[];
139
+ export declare function prentaTags(kind: 'global', slug: string): string[];
140
+ export declare function prentaTags(kind: 'path', path: string): string[];
141
+ export declare function prentaTags(kind: 'all'): string[];
142
+ /**
143
+ * Convenience factory. Equivalent to `new PrentaClient(opts)` but reads
144
+ * nicely as `const cms = createClient<typeof config>({...})`.
145
+ */
146
+ export declare function createClient<Config extends PrentaConfigLike = PrentaConfigLike>(opts: PrentaClientOptions): PrentaClient<Config>;
147
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,UAAU,EACV,cAAc,EACd,UAAU,EACV,SAAS,EAET,SAAS,EACV,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,UAAU,EACV,qBAAqB,EACrB,cAAc,EACd,UAAU,EACV,WAAW,EACX,YAAY,EACZ,SAAS,EACT,UAAU,EACV,SAAS,GACV,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,mBAAmB;IAClC,6FAA6F;IAC7F,GAAG,EAAE,MAAM,CAAA;IACX,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oGAAoG;IACpG,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;IACxB;;;OAGG;IACH,YAAY,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;IAC/D,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC;AAED,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;gBACd,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO;CAMhE;AAuCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,YAAY,CAAC,MAAM,SAAS,gBAAgB,GAAG,gBAAgB;IAC1E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;IACxC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAqC;IACnE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAwB;gBAE1C,IAAI,EAAE,mBAAmB;IASrC,OAAO,CAAC,OAAO;YASD,OAAO;IA4DrB;;;;;OAKG;IACH,IAAI,CAAC,IAAI,SAAS,MAAM,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,MAAM,EACjE,UAAU,EAAE,IAAI,EAChB,KAAK,CAAC,EAAE,SAAS,EACjB,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,KAAK,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;KAAE,GAC3E,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IA2BpD,qCAAqC;IACrC,GAAG,CAAC,IAAI,SAAS,MAAM,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,MAAM,EAChE,UAAU,EAAE,IAAI,EAChB,EAAE,EAAE,MAAM,EACV,IAAI,CAAC,EAAE;QACL,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,MAAM,CAAC,EAAE,WAAW,CAAA;QACpB,KAAK,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;KAC5C,GACA,OAAO,CAAC,cAAc,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAexD,wEAAwE;IAClE,OAAO,CACX,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,KAAK,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;KAAE,GAC3E,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAgBjC,8BAA8B;IAC9B,MAAM,CAAC,IAAI,SAAS,MAAM,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,MAAM,EAC/D,IAAI,EAAE,IAAI,EACV,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,KAAK,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;KAAE,GAC3E,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAapC;;;;;;;;OAQG;IACH,SAAS,CACP,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,EAC7D,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,KAAK,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;KAAE,GAC3E,OAAO,CAAC,SAAS,CAAC;CAwBtB;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;AACtE,wBAAgB,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;AACrF,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;AAClE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;AAChE,wBAAgB,UAAU,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,EAAE,CAAA;AAsBjD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,SAAS,gBAAgB,GAAG,gBAAgB,EAC7E,IAAI,EAAE,mBAAmB,GACxB,YAAY,CAAC,MAAM,CAAC,CAEtB"}
package/dist/index.js ADDED
@@ -0,0 +1,269 @@
1
+ export class PrentaError extends Error {
2
+ status;
3
+ response;
4
+ constructor(message, status, response) {
5
+ super(message);
6
+ this.name = 'PrentaError';
7
+ this.status = status;
8
+ this.response = response;
9
+ }
10
+ }
11
+ /**
12
+ * Merge a per-call cache override with the client's default cache config
13
+ * and a set of canonical per-resource tags the SDK always wants on the
14
+ * request. Order matters for readability but not for behaviour — the
15
+ * fetch cache treats the tag list as a set.
16
+ *
17
+ * Returns `undefined` when there's nothing to merge so callers can keep
18
+ * `cache:` off the request init entirely on runtimes that don't
19
+ * understand Next.js fetch extensions.
20
+ */
21
+ function mergeTags(perCall, client, resourceTags) {
22
+ // The per-call override wins on `revalidate` because callers
23
+ // legitimately need to bypass caching for one-off invalidation reads.
24
+ const revalidate = perCall?.revalidate ?? client?.revalidate;
25
+ // `revalidate: false` (= no-store) means "don't cache at all", so emitting
26
+ // tags would be misleading. Honour the bypass.
27
+ if (revalidate === false) {
28
+ return { revalidate: false };
29
+ }
30
+ // The wholesale `prenta` tag is always included so a single
31
+ // `revalidateTag('prenta')` from a panic-button webhook still
32
+ // invalidates every SDK-tagged response, regardless of whether the
33
+ // user opted into the Next.js entrypoint defaults.
34
+ const merged = new Set(['prenta']);
35
+ for (const t of resourceTags)
36
+ merged.add(t);
37
+ if (client?.tags)
38
+ for (const t of client.tags)
39
+ merged.add(t);
40
+ if (perCall?.tags)
41
+ for (const t of perCall.tags)
42
+ merged.add(t);
43
+ const out = {};
44
+ if (typeof revalidate === 'number')
45
+ out.revalidate = revalidate;
46
+ out.tags = Array.from(merged);
47
+ return out;
48
+ }
49
+ /**
50
+ * Type-safe **read / delivery** client for the Prenta CMS REST API.
51
+ *
52
+ * Scope (deliberate): this SDK is **read-only**. It covers the public
53
+ * delivery surface — `list`, `get`, `getGlobal`, `resolve`, `listMedia`,
54
+ * plus the React/Next cache helpers — for fetching published content into a
55
+ * frontend. It intentionally ships **no** create/update/delete/publish or
56
+ * upload methods.
57
+ *
58
+ * **Authoring belongs to agents and tooling, not the delivery SDK.** To
59
+ * create or mutate content programmatically, drive the CMS over **MCP**
60
+ * (`@prenta/mcp-server`) or call the authenticated HTTP API directly
61
+ * (`POST/PUT/DELETE /api/cms/collections/:slug`, `/media/upload`, …). Keeping
62
+ * authoring out of this package keeps the delivery bundle small, its API key
63
+ * scoped to `read`, and the write surface auditable in one place.
64
+ *
65
+ * The class is generic over a config type so consumers get field-level
66
+ * autocomplete when they pass their `typeof prentaConfig` as the type
67
+ * parameter. Consumers who don't pass a config still get a working — but
68
+ * loosely-typed — client.
69
+ */
70
+ export class PrentaClient {
71
+ url;
72
+ apiKey;
73
+ fetchImpl;
74
+ defaultCache;
75
+ extraHeaders;
76
+ constructor(opts) {
77
+ if (!opts.url)
78
+ throw new Error('PrentaClient: `url` is required');
79
+ this.url = opts.url.replace(/\/+$/, '');
80
+ this.apiKey = opts.apiKey;
81
+ this.fetchImpl = opts.fetchImpl ?? fetch;
82
+ this.defaultCache = opts.defaultCache;
83
+ this.extraHeaders = opts.headers;
84
+ }
85
+ headers(extra) {
86
+ return {
87
+ Accept: 'application/json',
88
+ ...(this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}),
89
+ ...this.extraHeaders,
90
+ ...extra,
91
+ };
92
+ }
93
+ async request(method, path, init) {
94
+ let target = `${this.url}/api/cms${path}`;
95
+ if (init?.query) {
96
+ const params = new URLSearchParams();
97
+ for (const [k, v] of Object.entries(init.query)) {
98
+ if (v !== undefined)
99
+ params.set(k, String(v));
100
+ }
101
+ const q = params.toString();
102
+ if (q)
103
+ target += `?${q}`;
104
+ }
105
+ const fetchInit = {
106
+ method,
107
+ headers: this.headers(init?.body ? { 'Content-Type': 'application/json' } : undefined),
108
+ signal: init?.signal,
109
+ };
110
+ if (init?.body !== undefined) {
111
+ fetchInit.body = JSON.stringify(init.body);
112
+ }
113
+ const cache = init?.cache ?? this.defaultCache;
114
+ if (cache) {
115
+ if (cache.revalidate === false) {
116
+ ;
117
+ fetchInit.cache = 'no-store';
118
+ }
119
+ else if (typeof cache.revalidate === 'number' || cache.tags) {
120
+ // Next.js fetch extensions are ignored by other runtimes, which is
121
+ // safe — they're additive metadata.
122
+ fetchInit.next = {
123
+ ...(typeof cache.revalidate === 'number' ? { revalidate: cache.revalidate } : {}),
124
+ ...(cache.tags ? { tags: cache.tags } : {}),
125
+ };
126
+ }
127
+ }
128
+ const res = await this.fetchImpl(target, fetchInit);
129
+ const text = await res.text();
130
+ let parsed = null;
131
+ if (text) {
132
+ try {
133
+ parsed = JSON.parse(text);
134
+ }
135
+ catch {
136
+ // non-JSON body — keep raw text for the error.
137
+ }
138
+ }
139
+ if (!res.ok) {
140
+ const msg = parsed?.error ?? `${method} ${path} failed: ${res.status}`;
141
+ throw new PrentaError(msg, res.status, parsed ?? text);
142
+ }
143
+ return parsed;
144
+ }
145
+ // ─── Collections ─────────────────────────────────────────────────────
146
+ /**
147
+ * List documents in a collection. Returns `{ docs, total, page, pageSize, totalPages }`.
148
+ *
149
+ * @example
150
+ * const { docs } = await client.list('posts', { status: 'PUBLISHED' })
151
+ */
152
+ list(collection, query, init) {
153
+ const flatFilters = {};
154
+ if (query?.filters) {
155
+ for (const [k, v] of Object.entries(query.filters)) {
156
+ flatFilters[`filter.${k}`] = v;
157
+ }
158
+ }
159
+ return this.request('GET', `/collections/${encodeURIComponent(collection)}`, {
160
+ query: {
161
+ page: query?.page,
162
+ pageSize: query?.pageSize,
163
+ status: query?.status,
164
+ locale: query?.locale,
165
+ search: query?.search,
166
+ populate: query?.populate,
167
+ sort: query?.sort,
168
+ ...flatFilters,
169
+ },
170
+ signal: init?.signal,
171
+ cache: mergeTags(init?.cache, this.defaultCache, [`prenta:collection:${collection}`]),
172
+ }).then((r) => r.data);
173
+ }
174
+ /** Fetch a single document by ID. */
175
+ get(collection, id, init) {
176
+ return this.request('GET', `/collections/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, {
177
+ query: init?.populate ? { populate: init.populate } : undefined,
178
+ signal: init?.signal,
179
+ cache: mergeTags(init?.cache, this.defaultCache, [
180
+ `prenta:collection:${collection}`,
181
+ `prenta:doc:${id}`,
182
+ ]),
183
+ }).then((r) => r.data);
184
+ }
185
+ /** Resolve a public URL path (e.g. `/blog/my-post`) to its document. */
186
+ async resolve(path, init) {
187
+ try {
188
+ const response = await this.request('GET', '/resolve', {
189
+ query: { path },
190
+ signal: init?.signal,
191
+ cache: mergeTags(init?.cache, this.defaultCache, [`prenta:path:${path}`]),
192
+ });
193
+ return response.data;
194
+ }
195
+ catch (err) {
196
+ if (err instanceof PrentaError && err.status === 404)
197
+ return null;
198
+ throw err;
199
+ }
200
+ }
201
+ // ─── Globals ─────────────────────────────────────────────────────────
202
+ /** Fetch a global by slug. */
203
+ global(slug, init) {
204
+ return this.request('GET', `/globals/${encodeURIComponent(slug)}`, {
205
+ signal: init?.signal,
206
+ cache: mergeTags(init?.cache, this.defaultCache, [`prenta:global:${slug}`]),
207
+ }).then((r) => r.data);
208
+ }
209
+ // ─── Media ───────────────────────────────────────────────────────────
210
+ /**
211
+ * List media assets. Returns the canonical `{ docs, total, page, pageSize,
212
+ * totalPages }` envelope (same shape as {@link PrentaClient.list}).
213
+ *
214
+ * The `GET /media` endpoint returns the asset array under `items`/`data`
215
+ * (never `docs`), plus pagination fields. This method normalizes that into
216
+ * the standard list contract so callers can destructure `{ docs }` exactly
217
+ * like collection lists.
218
+ */
219
+ listMedia(query, init) {
220
+ return this.request('GET', '/media', {
221
+ query: query,
222
+ signal: init?.signal,
223
+ cache: mergeTags(init?.cache, this.defaultCache, ['prenta:collection:media']),
224
+ }).then((r) => {
225
+ const envelope = r.data ?? {};
226
+ const docs = envelope.items ?? envelope.data ?? [];
227
+ const total = envelope.total ?? docs.length;
228
+ const page = envelope.page ?? query?.page ?? 1;
229
+ const pageSize = envelope.pageSize ?? query?.pageSize ?? docs.length;
230
+ const totalPages = envelope.totalPages ?? (pageSize > 0 ? Math.ceil(total / pageSize) : 1);
231
+ return { docs, total, page, pageSize, totalPages };
232
+ });
233
+ }
234
+ }
235
+ /**
236
+ * Tag-helper for `next/cache` `revalidateTag` calls. Returns the canonical
237
+ * tag the SDK applies for a given collection, global, single document, or
238
+ * resolved path.
239
+ *
240
+ * The full tag taxonomy is documented in {@link prentaTags}.
241
+ */
242
+ export function prentaTag(kind, slug) {
243
+ return `prenta:${kind}:${slug}`;
244
+ }
245
+ export function prentaTags(kind, slugOrPath, id) {
246
+ // Every tag set includes `prenta` so a wholesale invalidation always
247
+ // works as a last resort. Narrower tags are appended after.
248
+ const base = ['prenta'];
249
+ if (kind === 'all')
250
+ return base;
251
+ if (kind === 'doc') {
252
+ if (!slugOrPath || !id) {
253
+ throw new Error("prentaTags('doc', collectionSlug, id) requires both arguments");
254
+ }
255
+ return [...base, `prenta:collection:${slugOrPath}`, `prenta:doc:${id}`];
256
+ }
257
+ if (slugOrPath === undefined) {
258
+ throw new Error(`prentaTags('${kind}', slug) requires a slug`);
259
+ }
260
+ return [...base, `prenta:${kind}:${slugOrPath}`];
261
+ }
262
+ /**
263
+ * Convenience factory. Equivalent to `new PrentaClient(opts)` but reads
264
+ * nicely as `const cms = createClient<typeof config>({...})`.
265
+ */
266
+ export function createClient(opts) {
267
+ return new PrentaClient(opts);
268
+ }
269
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/next.d.ts ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Next.js server helpers for the Prenta client SDK.
3
+ *
4
+ * These are thin wrappers around `PrentaClient` that default to
5
+ * Next-friendly cache semantics. Use them inside Server Components,
6
+ * Route Handlers, or `generateStaticParams` for tag-based revalidation
7
+ * to play nicely with Prenta webhooks.
8
+ *
9
+ * On non-Next runtimes (e.g. Hono, Bun, Cloudflare Workers) the same
10
+ * methods work — the `next` fetch options become inert metadata.
11
+ */
12
+ import { PrentaClient } from './index.js';
13
+ import type { PrentaClientOptions, PrentaDocument } from './index.js';
14
+ import type { PrentaConfigLike, CollectionData, GlobalData } from './types.js';
15
+ export interface NextPrentaClientOptions extends PrentaClientOptions {
16
+ /** Default revalidation seconds for every request. Pass `false` for `cache: 'no-store'`. */
17
+ revalidate?: number | false;
18
+ /**
19
+ * Default cache tags applied to every request. Use with
20
+ * `revalidateTag()` from `next/cache` to invalidate from webhooks.
21
+ * Defaults to `['prenta']` so a single `revalidateTag('prenta')`
22
+ * call invalidates the whole CMS layer.
23
+ */
24
+ tags?: string[];
25
+ }
26
+ /**
27
+ * Build an Prenta client preconfigured for Next.js fetch semantics.
28
+ *
29
+ * @example
30
+ * // app/lib/cms.ts
31
+ * import { createNextClient } from '@prenta/client/next'
32
+ * import type config from '@/prenta.config'
33
+ * export const cms = createNextClient<typeof config>({
34
+ * url: process.env.PRENTA_URL!,
35
+ * apiKey: process.env.PRENTA_API_KEY,
36
+ * revalidate: 60,
37
+ * tags: ['prenta'],
38
+ * })
39
+ */
40
+ export declare function createNextClient<Config extends PrentaConfigLike = PrentaConfigLike>(opts: NextPrentaClientOptions): PrentaClient<Config>;
41
+ /**
42
+ * Quick-helper to fetch a single document by URL path inside a Server
43
+ * Component. Returns `null` when no document matches the path.
44
+ *
45
+ * @remarks Thin re-export of {@link PrentaClient.resolve} kept for
46
+ * Server-Component ergonomics (you can pass the client as the first arg
47
+ * without wrapping in a closure). `client.resolve()` already returns
48
+ * `null` on 404 as of `@prenta/client@0.2.1`, so this helper does
49
+ * not catch any additional errors — non-404 failures still throw, which
50
+ * is what you want inside Server Components (Next.js renders a 500).
51
+ */
52
+ export declare function resolvePagePath<Config extends PrentaConfigLike>(client: PrentaClient<Config>, path: string): Promise<PrentaDocument | null>;
53
+ export type { PrentaClientOptions, PrentaDocument, PrentaList } from './index.js';
54
+ export { PrentaClient, PrentaError, prentaTag, prentaTags, createClient } from './index.js';
55
+ export type CollectionDataOf<Config extends PrentaConfigLike, Slug extends keyof NonNullable<Config['collections']> & string> = CollectionData<Config, Slug>;
56
+ export type GlobalDataOf<Config extends PrentaConfigLike, Slug extends keyof NonNullable<Config['globals']> & string> = GlobalData<Config, Slug>;
57
+ export type { ListQuery, CollectionData, GlobalData } from './types.js';
58
+ //# sourceMappingURL=next.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../src/next.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,YAAY,EAAgB,MAAM,YAAY,CAAA;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAc,MAAM,YAAY,CAAA;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAa,MAAM,YAAY,CAAA;AAEzF,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE,4FAA4F;IAC5F,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IAC3B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CAChB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,SAAS,gBAAgB,GAAG,gBAAgB,EACjF,IAAI,EAAE,uBAAuB,GAC5B,YAAY,CAAC,MAAM,CAAC,CAUtB;AAOD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,MAAM,SAAS,gBAAgB,EAC7D,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,EAC5B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAEhC;AAGD,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACjF,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAG3F,MAAM,MAAM,gBAAgB,CAC1B,MAAM,SAAS,gBAAgB,EAC/B,IAAI,SAAS,MAAM,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,MAAM,IAC5D,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;AAEhC,MAAM,MAAM,YAAY,CACtB,MAAM,SAAS,gBAAgB,EAC/B,IAAI,SAAS,MAAM,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,MAAM,IACxD,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;AAE5B,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA"}
package/dist/next.js ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Next.js server helpers for the Prenta client SDK.
3
+ *
4
+ * These are thin wrappers around `PrentaClient` that default to
5
+ * Next-friendly cache semantics. Use them inside Server Components,
6
+ * Route Handlers, or `generateStaticParams` for tag-based revalidation
7
+ * to play nicely with Prenta webhooks.
8
+ *
9
+ * On non-Next runtimes (e.g. Hono, Bun, Cloudflare Workers) the same
10
+ * methods work — the `next` fetch options become inert metadata.
11
+ */
12
+ import { createClient } from './index.js';
13
+ /**
14
+ * Build an Prenta client preconfigured for Next.js fetch semantics.
15
+ *
16
+ * @example
17
+ * // app/lib/cms.ts
18
+ * import { createNextClient } from '@prenta/client/next'
19
+ * import type config from '@/prenta.config'
20
+ * export const cms = createNextClient<typeof config>({
21
+ * url: process.env.PRENTA_URL!,
22
+ * apiKey: process.env.PRENTA_API_KEY,
23
+ * revalidate: 60,
24
+ * tags: ['prenta'],
25
+ * })
26
+ */
27
+ export function createNextClient(opts) {
28
+ const { revalidate, tags, ...rest } = opts;
29
+ return createClient({
30
+ ...rest,
31
+ defaultCache: {
32
+ ...(typeof revalidate === 'number' ? { revalidate } : {}),
33
+ ...(revalidate === false ? { revalidate: false } : {}),
34
+ tags: tags ?? ['prenta'],
35
+ },
36
+ });
37
+ }
38
+ // Tag helpers (`prentaTag`, `prentaTags`) live in `./index.js` so they're
39
+ // importable from runtimes that don't pull in this Next-specific entrypoint.
40
+ // They are re-exported below for ergonomics — using
41
+ // `@prenta/client/next` in app code keeps a single import surface.
42
+ /**
43
+ * Quick-helper to fetch a single document by URL path inside a Server
44
+ * Component. Returns `null` when no document matches the path.
45
+ *
46
+ * @remarks Thin re-export of {@link PrentaClient.resolve} kept for
47
+ * Server-Component ergonomics (you can pass the client as the first arg
48
+ * without wrapping in a closure). `client.resolve()` already returns
49
+ * `null` on 404 as of `@prenta/client@0.2.1`, so this helper does
50
+ * not catch any additional errors — non-404 failures still throw, which
51
+ * is what you want inside Server Components (Next.js renders a 500).
52
+ */
53
+ export function resolvePagePath(client, path) {
54
+ return client.resolve(path);
55
+ }
56
+ export { PrentaClient, PrentaError, prentaTag, prentaTags, createClient } from './index.js';
57
+ //# sourceMappingURL=next.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next.js","sourceRoot":"","sources":["../src/next.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAgB,YAAY,EAAE,MAAM,YAAY,CAAA;AAgBvD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAA6B;IAE7B,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAA;IAC1C,OAAO,YAAY,CAAS;QAC1B,GAAG,IAAI;QACP,YAAY,EAAE;YACZ,GAAG,CAAC,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzD,GAAG,CAAC,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/D,IAAI,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC;SACzB;KACF,CAAC,CAAA;AACJ,CAAC;AAED,0EAA0E;AAC1E,6EAA6E;AAC7E,oDAAoD;AACpD,mEAAmE;AAEnE;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAC7B,MAA4B,EAC5B,IAAY;IAEZ,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;AAC7B,CAAC;AAID,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,32 @@
1
+ import type { PrentaClient, PrentaClientOptions, PrentaDocument, PrentaList } from './index.js';
2
+ import type { PrentaConfigLike, CollectionData, GlobalData, ListQuery } from './types.js';
3
+ export interface UseQueryResult<T> {
4
+ data: T | undefined;
5
+ error: Error | undefined;
6
+ isLoading: boolean;
7
+ /** Manually re-run the query. Useful for mutations + refetch flows. */
8
+ refetch: () => void;
9
+ }
10
+ interface BaseHookOptions {
11
+ /** Skip fetching when false. Lets consumers conditionally enable a hook. */
12
+ enabled?: boolean;
13
+ }
14
+ /**
15
+ * Lightweight client-side hook for a collection list. We deliberately keep
16
+ * this dependency-free (no SWR/React Query) so the SDK stays embeddable in
17
+ * any React app. Consumers who want richer caching can call the underlying
18
+ * client methods directly inside their preferred data-fetching library.
19
+ */
20
+ export declare function useCollection<Config extends PrentaConfigLike, Slug extends keyof NonNullable<Config['collections']> & string>(client: PrentaClient<Config>, collection: Slug, query?: ListQuery, opts?: BaseHookOptions): UseQueryResult<PrentaList<CollectionData<Config, Slug>>>;
21
+ /**
22
+ * Fetch a single document by ID. Pass `null`/`undefined` for the id to
23
+ * disable the hook (no fetch happens until a real id is supplied).
24
+ */
25
+ export declare function useContent<Config extends PrentaConfigLike, Slug extends keyof NonNullable<Config['collections']> & string>(client: PrentaClient<Config>, collection: Slug, id: string | null | undefined, init?: {
26
+ populate?: string;
27
+ } & BaseHookOptions): UseQueryResult<PrentaDocument<CollectionData<Config, Slug>>>;
28
+ /** Fetch a global by slug. */
29
+ export declare function useGlobal<Config extends PrentaConfigLike, Slug extends keyof NonNullable<Config['globals']> & string>(client: PrentaClient<Config>, slug: Slug, opts?: BaseHookOptions): UseQueryResult<GlobalData<Config, Slug>>;
30
+ export { PrentaClient, createClient, PrentaError } from './index.js';
31
+ export type { PrentaClientOptions };
32
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC/F,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEzF,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,IAAI,EAAE,CAAC,GAAG,SAAS,CAAA;IACnB,KAAK,EAAE,KAAK,GAAG,SAAS,CAAA;IACxB,SAAS,EAAE,OAAO,CAAA;IAClB,uEAAuE;IACvE,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,UAAU,eAAe;IACvB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,MAAM,SAAS,gBAAgB,EAC/B,IAAI,SAAS,MAAM,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,MAAM,EAE9D,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,EAC5B,UAAU,EAAE,IAAI,EAChB,KAAK,CAAC,EAAE,SAAS,EACjB,IAAI,CAAC,EAAE,eAAe,GACrB,cAAc,CAAC,UAAU,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CA2C1D;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,MAAM,SAAS,gBAAgB,EAC/B,IAAI,SAAS,MAAM,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,MAAM,EAE9D,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,EAC5B,UAAU,EAAE,IAAI,EAChB,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC7B,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,eAAe,GAC7C,cAAc,CAAC,cAAc,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAqD9D;AAED,8BAA8B;AAC9B,wBAAgB,SAAS,CACvB,MAAM,SAAS,gBAAgB,EAC/B,IAAI,SAAS,MAAM,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,MAAM,EAE1D,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,EAC5B,IAAI,EAAE,IAAI,EACV,IAAI,CAAC,EAAE,eAAe,GACrB,cAAc,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CA2C1C;AAGD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACpE,YAAY,EAAE,mBAAmB,EAAE,CAAA"}
package/dist/react.js ADDED
@@ -0,0 +1,156 @@
1
+ 'use client';
2
+ import { useEffect, useRef, useState } from 'react';
3
+ /**
4
+ * Lightweight client-side hook for a collection list. We deliberately keep
5
+ * this dependency-free (no SWR/React Query) so the SDK stays embeddable in
6
+ * any React app. Consumers who want richer caching can call the underlying
7
+ * client methods directly inside their preferred data-fetching library.
8
+ */
9
+ export function useCollection(client, collection, query, opts) {
10
+ const [data, setData] = useState(undefined);
11
+ const [error, setError] = useState(undefined);
12
+ const [isLoading, setIsLoading] = useState(opts?.enabled !== false);
13
+ const versionRef = useRef(0);
14
+ const key = JSON.stringify({ collection, query, enabled: opts?.enabled ?? true });
15
+ const run = () => {
16
+ if (opts?.enabled === false) {
17
+ setIsLoading(false);
18
+ return;
19
+ }
20
+ const controller = new AbortController();
21
+ versionRef.current += 1;
22
+ const version = versionRef.current;
23
+ setIsLoading(true);
24
+ setError(undefined);
25
+ client
26
+ .list(collection, query, { signal: controller.signal })
27
+ .then((result) => {
28
+ if (version !== versionRef.current)
29
+ return;
30
+ setData(result);
31
+ })
32
+ .catch((err) => {
33
+ if (controller.signal.aborted)
34
+ return;
35
+ if (version !== versionRef.current)
36
+ return;
37
+ setError(err instanceof Error ? err : new Error(String(err)));
38
+ })
39
+ .finally(() => {
40
+ if (version !== versionRef.current)
41
+ return;
42
+ setIsLoading(false);
43
+ });
44
+ return () => controller.abort();
45
+ };
46
+ useEffect(() => {
47
+ const cleanup = run();
48
+ return cleanup;
49
+ // eslint-disable-next-line react-hooks/exhaustive-deps
50
+ }, [key]);
51
+ return { data, error, isLoading, refetch: run };
52
+ }
53
+ /**
54
+ * Fetch a single document by ID. Pass `null`/`undefined` for the id to
55
+ * disable the hook (no fetch happens until a real id is supplied).
56
+ */
57
+ export function useContent(client, collection, id, init) {
58
+ const [data, setData] = useState(undefined);
59
+ const [error, setError] = useState(undefined);
60
+ const [isLoading, setIsLoading] = useState(Boolean(id) && init?.enabled !== false);
61
+ const versionRef = useRef(0);
62
+ const key = JSON.stringify({
63
+ collection,
64
+ id,
65
+ populate: init?.populate,
66
+ enabled: init?.enabled ?? true,
67
+ });
68
+ const run = () => {
69
+ if (!id || init?.enabled === false) {
70
+ setIsLoading(false);
71
+ return;
72
+ }
73
+ const controller = new AbortController();
74
+ versionRef.current += 1;
75
+ const version = versionRef.current;
76
+ setIsLoading(true);
77
+ setError(undefined);
78
+ client
79
+ .get(collection, id, {
80
+ ...(init?.populate ? { populate: init.populate } : {}),
81
+ signal: controller.signal,
82
+ })
83
+ .then((doc) => {
84
+ if (version !== versionRef.current)
85
+ return;
86
+ setData(doc);
87
+ })
88
+ .catch((err) => {
89
+ if (controller.signal.aborted)
90
+ return;
91
+ if (version !== versionRef.current)
92
+ return;
93
+ setError(err instanceof Error ? err : new Error(String(err)));
94
+ })
95
+ .finally(() => {
96
+ if (version !== versionRef.current)
97
+ return;
98
+ setIsLoading(false);
99
+ });
100
+ return () => controller.abort();
101
+ };
102
+ useEffect(() => {
103
+ const cleanup = run();
104
+ return cleanup;
105
+ // eslint-disable-next-line react-hooks/exhaustive-deps
106
+ }, [key]);
107
+ return { data, error, isLoading, refetch: run };
108
+ }
109
+ /** Fetch a global by slug. */
110
+ export function useGlobal(client, slug, opts) {
111
+ const [data, setData] = useState(undefined);
112
+ const [error, setError] = useState(undefined);
113
+ const [isLoading, setIsLoading] = useState(opts?.enabled !== false);
114
+ const versionRef = useRef(0);
115
+ const key = JSON.stringify({ slug, enabled: opts?.enabled ?? true });
116
+ const run = () => {
117
+ if (opts?.enabled === false) {
118
+ setIsLoading(false);
119
+ return;
120
+ }
121
+ const controller = new AbortController();
122
+ versionRef.current += 1;
123
+ const version = versionRef.current;
124
+ setIsLoading(true);
125
+ setError(undefined);
126
+ client
127
+ .global(slug, { signal: controller.signal })
128
+ .then((result) => {
129
+ if (version !== versionRef.current)
130
+ return;
131
+ setData(result);
132
+ })
133
+ .catch((err) => {
134
+ if (controller.signal.aborted)
135
+ return;
136
+ if (version !== versionRef.current)
137
+ return;
138
+ setError(err instanceof Error ? err : new Error(String(err)));
139
+ })
140
+ .finally(() => {
141
+ if (version !== versionRef.current)
142
+ return;
143
+ setIsLoading(false);
144
+ });
145
+ return () => controller.abort();
146
+ };
147
+ useEffect(() => {
148
+ const cleanup = run();
149
+ return cleanup;
150
+ // eslint-disable-next-line react-hooks/exhaustive-deps
151
+ }, [key]);
152
+ return { data, error, isLoading, refetch: run };
153
+ }
154
+ // Re-export the parent module so consumers can `import { useContent, createClient } from '@prenta/client/react'`.
155
+ export { PrentaClient, createClient, PrentaError } from './index.js';
156
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Type system for the Prenta client SDK.
3
+ *
4
+ * The key trick: callers pass their `prenta.config.ts` as a generic type
5
+ * parameter to `createClient<typeof config>()`. The SDK then surfaces a
6
+ * typed `client.<collection>` accessor where every field's TS type is
7
+ * derived from the config. No codegen, no `prenta.types.d.ts` file —
8
+ * the user's source of truth is the config itself.
9
+ *
10
+ * If a consumer can't (or won't) pass their config, the client falls back
11
+ * to a generic `Record<string, unknown>` shape so calls still type-check.
12
+ */
13
+ export interface PrentaFieldDefinition {
14
+ type: string;
15
+ required?: boolean;
16
+ defaultValue?: unknown;
17
+ options?: Array<{
18
+ value: string;
19
+ label?: string;
20
+ }> | readonly string[];
21
+ fields?: Record<string, PrentaFieldDefinition>;
22
+ relationTo?: string;
23
+ }
24
+ /** Map a single field's declared `type` to the corresponding TypeScript type. */
25
+ export type FieldToType<F extends PrentaFieldDefinition> = F['type'] extends 'text' | 'richText' | 'slug' | 'url' | 'email' | 'color' | 'date' ? string : F['type'] extends 'number' ? number : F['type'] extends 'boolean' ? boolean : F['type'] extends 'json' ? unknown : F['type'] extends 'select' ? F extends {
26
+ options: ReadonlyArray<{
27
+ value: infer V;
28
+ }>;
29
+ } ? V : F extends {
30
+ options: readonly string[];
31
+ } ? F['options'][number] : string : F['type'] extends 'relationship' ? string : F['type'] extends 'media' ? {
32
+ id: string;
33
+ url: string;
34
+ alt?: string;
35
+ } : F['type'] extends 'array' ? F extends {
36
+ fields: infer SF extends Record<string, PrentaFieldDefinition>;
37
+ } ? Array<FieldsToData<SF>> : unknown[] : F['type'] extends 'blocks' ? Array<Record<string, unknown>> : unknown;
38
+ /** Map a fields record to the `data` shape persisted for that collection. */
39
+ export type FieldsToData<F extends Record<string, PrentaFieldDefinition>> = {
40
+ [K in keyof F]?: FieldToType<F[K]>;
41
+ };
42
+ /**
43
+ * Document lifecycle status. Mirrors the `DocumentStatus` enum in cms-core's
44
+ * Prisma schema — keep these in sync (an exhaustive `switch` on the client side
45
+ * must handle every value the server can return, including `SCHEDULED_UNPUBLISH`).
46
+ */
47
+ export type PrentaDocumentStatus = 'DRAFT' | 'PUBLISHED' | 'ARCHIVED' | 'SCHEDULED' | 'SCHEDULED_UNPUBLISH';
48
+ /** The wire shape of a single document returned by the CMS. */
49
+ export interface PrentaDocument<TData = Record<string, unknown>> {
50
+ id: string;
51
+ collection: string;
52
+ status: PrentaDocumentStatus;
53
+ title?: string;
54
+ slug?: string;
55
+ locale?: string;
56
+ data: TData;
57
+ publishedAt?: string | null;
58
+ createdAt: string;
59
+ updatedAt: string;
60
+ /** Page-builder collections additionally carry a `layout` + `pageSettings`. */
61
+ layout?: unknown;
62
+ pageSettings?: Record<string, unknown>;
63
+ }
64
+ /** Pagination envelope for list endpoints. */
65
+ export interface PrentaList<TData = Record<string, unknown>> {
66
+ docs: Array<PrentaDocument<TData>>;
67
+ total: number;
68
+ page: number;
69
+ pageSize: number;
70
+ totalPages: number;
71
+ }
72
+ /**
73
+ * A media asset as returned by `GET /media`. The server normalizes each row
74
+ * (see `normalizeMediaItem` in cms-core) into these stable fields. Extra
75
+ * provider/columns are passed through, so the index signature stays open.
76
+ */
77
+ export interface MediaAsset {
78
+ id: string;
79
+ /** Original filename (also exposed as `filename`). */
80
+ name: string;
81
+ filename?: string;
82
+ /** MIME type (also exposed as `mimeType`). */
83
+ type: string;
84
+ mimeType?: string;
85
+ /** Human-readable size (e.g. "1.2 MB"); `sizeBytes` is the raw byte count. */
86
+ size: string;
87
+ sizeBytes: number;
88
+ /** Public URL of the asset. */
89
+ url: string;
90
+ width?: number | null;
91
+ height?: number | null;
92
+ dimensions?: string;
93
+ format?: string;
94
+ altTag: string;
95
+ title: string;
96
+ /** Documents that reference this asset. */
97
+ usedOn: Array<{
98
+ page: string;
99
+ path: string;
100
+ }>;
101
+ createdAt?: string;
102
+ updatedAt?: string;
103
+ [key: string]: unknown;
104
+ }
105
+ /**
106
+ * Pagination envelope for `GET /media`. Mirrors {@link PrentaList} (the
107
+ * `{ docs, total, page, pageSize, totalPages }` contract) so media lists are
108
+ * unwrapped the same way as collection lists.
109
+ */
110
+ export interface MediaList {
111
+ docs: MediaAsset[];
112
+ total: number;
113
+ page: number;
114
+ pageSize: number;
115
+ totalPages: number;
116
+ }
117
+ export interface PrentaConfigLike {
118
+ collections?: Record<string, {
119
+ fields: Record<string, PrentaFieldDefinition>;
120
+ type?: 'page' | 'post';
121
+ }>;
122
+ globals?: Record<string, {
123
+ fields: Record<string, PrentaFieldDefinition>;
124
+ }>;
125
+ }
126
+ /** Extract the data-shape for a given collection key from a config. */
127
+ export type CollectionData<Config extends PrentaConfigLike, Slug extends keyof NonNullable<Config['collections']>> = FieldsToData<NonNullable<Config['collections']>[Slug]['fields']>;
128
+ /** Extract the data-shape for a given global key from a config. */
129
+ export type GlobalData<Config extends PrentaConfigLike, Slug extends keyof NonNullable<Config['globals']>> = FieldsToData<NonNullable<Config['globals']>[Slug]['fields']>;
130
+ export interface ListQuery {
131
+ page?: number;
132
+ pageSize?: number;
133
+ status?: PrentaDocumentStatus;
134
+ locale?: string;
135
+ search?: string;
136
+ populate?: string;
137
+ /** Arbitrary filter columns the CMS allows (status, locale, folderId, …). */
138
+ filters?: Record<string, string | number | boolean>;
139
+ sort?: string;
140
+ }
141
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,SAAS,MAAM,EAAE,CAAA;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAA;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,iFAAiF;AACjF,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,qBAAqB,IAAI,CAAC,CAAC,MAAM,CAAC,SAChE,MAAM,GACN,UAAU,GACV,MAAM,GACN,KAAK,GACL,OAAO,GACP,OAAO,GACP,MAAM,GACN,MAAM,GACN,CAAC,CAAC,MAAM,CAAC,SAAS,QAAQ,GACxB,MAAM,GACN,CAAC,CAAC,MAAM,CAAC,SAAS,SAAS,GACzB,OAAO,GACP,CAAC,CAAC,MAAM,CAAC,SAAS,MAAM,GACtB,OAAO,GACP,CAAC,CAAC,MAAM,CAAC,SAAS,QAAQ,GACxB,CAAC,SAAS;IAAE,OAAO,EAAE,aAAa,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC,CAAA;CAAE,GACtD,CAAC,GACD,CAAC,SAAS;IAAE,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACtC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,GACpB,MAAM,GACV,CAAC,CAAC,MAAM,CAAC,SAAS,cAAc,GAC9B,MAAM,GACN,CAAC,CAAC,MAAM,CAAC,SAAS,OAAO,GACvB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACzC,CAAC,CAAC,MAAM,CAAC,SAAS,OAAO,GACvB,CAAC,SAAS;IAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAA;CAAE,GAC1E,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,GACvB,OAAO,EAAE,GACX,CAAC,CAAC,MAAM,CAAC,SAAS,QAAQ,GACxB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC9B,OAAO,CAAA;AAE3B,6EAA6E;AAC7E,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,IAAI;KACzE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACnC,CAAA;AAID;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAC5B,OAAO,GACP,WAAW,GACX,UAAU,GACV,WAAW,GACX,qBAAqB,CAAA;AAEzB,+DAA+D;AAC/D,MAAM,WAAW,cAAc,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC7D,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,oBAAoB,CAAA;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,KAAK,CAAA;IACX,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACvC;AAED,8CAA8C;AAC9C,MAAM,WAAW,UAAU,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACzD,IAAI,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,2CAA2C;IAC3C,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,UAAU,EAAE,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACnB;AAID,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,MAAM,CAClB,MAAM,EACN;QACE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAA;QAC7C,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KACvB,CACF,CAAA;IACD,OAAO,CAAC,EAAE,MAAM,CACd,MAAM,EACN;QACE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAA;KAC9C,CACF,CAAA;CACF;AAED,uEAAuE;AACvE,MAAM,MAAM,cAAc,CACxB,MAAM,SAAS,gBAAgB,EAC/B,IAAI,SAAS,MAAM,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IACnD,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;AAEpE,mEAAmE;AACnE,MAAM,MAAM,UAAU,CACpB,MAAM,SAAS,gBAAgB,EAC/B,IAAI,SAAS,MAAM,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAC/C,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;AAIhE,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,oBAAoB,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAA;IACnD,IAAI,CAAC,EAAE,MAAM,CAAA;CACd"}
package/dist/types.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Type system for the Prenta client SDK.
3
+ *
4
+ * The key trick: callers pass their `prenta.config.ts` as a generic type
5
+ * parameter to `createClient<typeof config>()`. The SDK then surfaces a
6
+ * typed `client.<collection>` accessor where every field's TS type is
7
+ * derived from the config. No codegen, no `prenta.types.d.ts` file —
8
+ * the user's source of truth is the config itself.
9
+ *
10
+ * If a consumer can't (or won't) pass their config, the client falls back
11
+ * to a generic `Record<string, unknown>` shape so calls still type-check.
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@prenta/client",
3
+ "version": "0.6.0",
4
+ "license": "MIT",
5
+ "description": "Type-safe read/delivery client and React hooks for the Prenta CMS REST API (read-only; author content over MCP or the HTTP API).",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/actuate-media/prenta.git",
9
+ "directory": "packages/client"
10
+ },
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "type": "module",
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js",
21
+ "default": "./dist/index.js"
22
+ },
23
+ "./react": {
24
+ "types": "./dist/react.d.ts",
25
+ "import": "./dist/react.js",
26
+ "default": "./dist/react.js"
27
+ },
28
+ "./next": {
29
+ "types": "./dist/next.d.ts",
30
+ "import": "./dist/next.js",
31
+ "default": "./dist/next.js"
32
+ }
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "CHANGELOG.md"
37
+ ],
38
+ "peerDependencies": {
39
+ "react": ">=18.0.0"
40
+ },
41
+ "peerDependenciesMeta": {
42
+ "react": {
43
+ "optional": true
44
+ }
45
+ },
46
+ "devDependencies": {
47
+ "@types/react": "^19.0.0",
48
+ "react": "^19.2.0",
49
+ "typescript": "^5.7.0",
50
+ "vitest": "^4.1.0"
51
+ },
52
+ "scripts": {
53
+ "build": "tsc --project tsconfig.json",
54
+ "dev": "tsc --project tsconfig.json --watch --preserveWatchOutput",
55
+ "type-check": "tsc --noEmit",
56
+ "test": "vitest run",
57
+ "clean": "rm -rf dist .turbo"
58
+ }
59
+ }