@no-mess/client 0.2.0 → 0.4.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.
Files changed (46) hide show
  1. package/README.md +108 -125
  2. package/dist/client.d.ts +12 -2
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +250 -41
  5. package/dist/client.js.map +1 -1
  6. package/dist/error-utils.d.ts +20 -0
  7. package/dist/error-utils.d.ts.map +1 -0
  8. package/dist/error-utils.js +67 -0
  9. package/dist/error-utils.js.map +1 -0
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +152 -22
  13. package/dist/index.js.map +1 -1
  14. package/dist/live-edit.d.ts.map +1 -1
  15. package/dist/live-edit.js +263 -102
  16. package/dist/live-edit.js.map +1 -1
  17. package/dist/logging.d.ts +6 -0
  18. package/dist/logging.d.ts.map +1 -0
  19. package/dist/logging.js +58 -0
  20. package/dist/logging.js.map +1 -0
  21. package/dist/react/index.d.ts +3 -1
  22. package/dist/react/index.d.ts.map +1 -1
  23. package/dist/react/index.js +2 -0
  24. package/dist/react/index.js.map +1 -1
  25. package/dist/react/no-mess-field.d.ts +10 -0
  26. package/dist/react/no-mess-field.d.ts.map +1 -0
  27. package/dist/react/no-mess-field.js +7 -0
  28. package/dist/react/no-mess-field.js.map +1 -0
  29. package/dist/react/no-mess-preview.d.ts +2 -6
  30. package/dist/react/no-mess-preview.d.ts.map +1 -1
  31. package/dist/react/no-mess-preview.js.map +1 -1
  32. package/dist/react/no-mess-provider.d.ts +21 -0
  33. package/dist/react/no-mess-provider.d.ts.map +1 -0
  34. package/dist/react/no-mess-provider.js +286 -0
  35. package/dist/react/no-mess-provider.js.map +1 -0
  36. package/dist/react/use-no-mess-live-edit.d.ts.map +1 -1
  37. package/dist/react/use-no-mess-live-edit.js +32 -2
  38. package/dist/react/use-no-mess-live-edit.js.map +1 -1
  39. package/dist/react/use-no-mess-preview.d.ts.map +1 -1
  40. package/dist/react/use-no-mess-preview.js +29 -6
  41. package/dist/react/use-no-mess-preview.js.map +1 -1
  42. package/dist/types.d.ts +78 -2
  43. package/dist/types.d.ts.map +1 -1
  44. package/dist/types.js +23 -4
  45. package/dist/types.js.map +1 -1
  46. package/package.json +1 -1
package/README.md CHANGED
@@ -10,65 +10,119 @@ npm install @no-mess/client
10
10
  bun add @no-mess/client
11
11
  ```
12
12
 
13
- ## Usage
14
-
15
- ### Fetching content
13
+ ## Fetch Content
16
14
 
17
15
  ```ts
18
16
  import { createNoMessClient } from "@no-mess/client";
19
17
 
20
18
  const client = createNoMessClient({
21
- apiKey: "your-api-key",
19
+ apiKey: process.env.NO_MESS_API_KEY!,
22
20
  });
23
21
 
24
- // Get all entries of a content type
25
22
  const posts = await client.getEntries("blog-post");
26
-
27
- // Get a single entry by slug
28
23
  const post = await client.getEntry("blog-post", "hello-world");
29
24
  ```
30
25
 
31
- ### Live preview (React)
26
+ ## Preview-Only Route
27
+
28
+ Use this when you want a dedicated `/no-mess-preview` page.
32
29
 
33
30
  ```tsx
34
- import { useNoMessPreview } from "@no-mess/client/react";
31
+ "use client";
32
+
33
+ import { NoMessPreview } from "@no-mess/client/react";
34
+
35
+ export default function PreviewPage() {
36
+ return (
37
+ <NoMessPreview apiKey={process.env.NEXT_PUBLIC_NO_MESS_PUBLISHABLE_KEY!}>
38
+ {({ entry, error, isLoading }) => {
39
+ if (isLoading) return <p>Loading preview...</p>;
40
+ if (error) return <p>{error.message}</p>;
41
+ if (!entry) return null;
42
+
43
+ return <h1>{entry.title}</h1>;
44
+ }}
45
+ </NoMessPreview>
46
+ );
47
+ }
48
+ ```
35
49
 
36
- function PreviewPage() {
37
- const { entry, isLoading, error } = useNoMessPreview({
38
- apiKey: "your-api-key",
39
- });
50
+ ## Route-Aware Preview and Live Edit
40
51
 
41
- if (isLoading) return <p>Loading preview...</p>;
42
- if (error) return <p>Error: {error.message}</p>;
52
+ This is the recommended integration path. It lets the dashboard open real site
53
+ routes, apply unsaved iframe-only edits before publish, and store reported
54
+ delivery URLs per entry.
43
55
 
44
- return <h1>{entry?.fields.title}</h1>;
56
+ ### 1. Wrap the route tree
57
+
58
+ ```tsx
59
+ "use client";
60
+
61
+ import { NoMessLiveRouteProvider } from "@no-mess/client/react";
62
+
63
+ export default function SiteLayout({
64
+ children,
65
+ }: {
66
+ children: React.ReactNode;
67
+ }) {
68
+ return (
69
+ <NoMessLiveRouteProvider
70
+ apiKey={process.env.NEXT_PUBLIC_NO_MESS_PUBLISHABLE_KEY!}
71
+ >
72
+ {children}
73
+ </NoMessLiveRouteProvider>
74
+ );
45
75
  }
46
76
  ```
47
77
 
48
- The `useNoMessPreview` hook handles the postMessage handshake between the no-mess admin dashboard and your preview iframe automatically.
49
-
50
- ### Shopify data
78
+ ### 2. Bind the rendered entry
51
79
 
52
- ```ts
53
- const products = await client.getProducts();
54
- const product = await client.getProduct("product-handle");
55
- const collections = await client.getCollections();
56
- const collection = await client.getCollection("collection-handle");
80
+ ```tsx
81
+ "use client";
82
+
83
+ import {
84
+ NoMessField,
85
+ useNoMessEditableEntry,
86
+ } from "@no-mess/client/react";
87
+
88
+ export function BlogArticle({ entry }) {
89
+ const editableEntry = useNoMessEditableEntry(entry);
90
+
91
+ return (
92
+ <article>
93
+ <NoMessField as="h1" name="title">
94
+ {editableEntry.title}
95
+ </NoMessField>
96
+ <NoMessField as="div" name="body">
97
+ {editableEntry.body}
98
+ </NoMessField>
99
+ </article>
100
+ );
101
+ }
57
102
  ```
58
103
 
59
- ## Configuration
104
+ `useNoMessEditableEntry()` automatically:
105
+ - swaps in draft content for the active iframe session
106
+ - applies unsaved field overrides from Live Edit
107
+ - reports the current URL for route-aware reopening
108
+ - emits the entry-bound signal used by dashboard warnings
109
+
110
+ ## Manual Route Reporting
111
+
112
+ If you need custom reporting logic, call the client method directly:
60
113
 
61
114
  ```ts
115
+ import { createNoMessClient } from "@no-mess/client";
116
+
62
117
  const client = createNoMessClient({
63
- apiKey: "nm_...", // Required — secret or publishable key
64
- apiUrl: "https://...", // Optional — defaults to https://api.no-mess.xyz
118
+ apiKey: process.env.NEXT_PUBLIC_NO_MESS_PUBLISHABLE_KEY!,
65
119
  });
66
- ```
67
-
68
- ### API Key Types
69
120
 
70
- - **Secret keys** (`nm_...`) — Full access. Use server-side only.
71
- - **Publishable keys** (`nm_pub_...`) — Read-only access to published content. Safe for client-side use.
121
+ await client.reportLiveEditRoute({
122
+ entryId: "entry_123",
123
+ url: window.location.href,
124
+ });
125
+ ```
72
126
 
73
127
  ## API Reference
74
128
 
@@ -81,108 +135,37 @@ const client = createNoMessClient({
81
135
  | `client.getEntries(contentType)` | Fetch all published entries of a content type |
82
136
  | `client.getEntry(contentType, slug)` | Get a single entry by slug |
83
137
 
84
- ### Shopify
138
+ ### Preview / Live Edit
85
139
 
86
140
  | Method | Description |
87
141
  |--------|-------------|
88
- | `client.getProducts()` | List all synced Shopify products |
89
- | `client.getProduct(handle)` | Get a product by handle |
90
- | `client.getCollections()` | List all synced Shopify collections |
91
- | `client.getCollection(handle)` | Get a collection by handle |
142
+ | `client.exchangePreviewSession(session)` | Exchange a preview session token for draft content |
143
+ | `client.reportLiveEditRoute({ entryId, url? })` | Report the current delivery URL for route-aware Live Edit |
92
144
 
93
- ### Preview
145
+ ### React (`@no-mess/client/react`)
94
146
 
95
- | Method | Description |
96
- |--------|-------------|
97
- | `client.exchangePreviewSession(session)` | Exchange a preview session token (HMAC-SHA256 auth) |
98
-
99
- ### React Hooks (`@no-mess/client/react`)
100
-
101
- | Hook | Description |
102
- |------|-------------|
103
- | `useNoMessPreview(config)` | Subscribe to live preview updates in an iframe |
104
- | `useNoMessLiveEdit(config)` | Enable live editing with field-level updates |
105
-
106
- ## Schema Builder
107
-
108
- The `@no-mess/client/schema` export provides helpers for defining content type schemas in code. Used by the [no-mess CLI](../no-mess-cli) to push and pull schemas.
109
-
110
- ```ts
111
- import { defineSchema, defineContentType, field } from "@no-mess/client/schema";
112
-
113
- export default defineSchema({
114
- contentTypes: [
115
- defineContentType("blog-post", {
116
- name: "Blog Post",
117
- description: "Articles for the blog",
118
- fields: {
119
- title: field.text({ required: true }),
120
- body: field.textarea({ required: true }),
121
- heroImage: field.image(),
122
- publishedAt: field.datetime(),
123
- featured: field.boolean(),
124
- externalUrl: field.url(),
125
- category: field.select({
126
- choices: [
127
- { label: "Tech", value: "tech" },
128
- { label: "Design", value: "design" },
129
- ],
130
- }),
131
- relatedProduct: field.shopifyProduct(),
132
- featuredCollection: field.shopifyCollection(),
133
- },
134
- }),
135
- ],
136
- });
137
- ```
147
+ | API | Description |
148
+ |-----|-------------|
149
+ | `NoMessPreview` | Preview-only route wrapper |
150
+ | `useNoMessPreview(config)` | Hook alternative for preview-only pages |
151
+ | `NoMessLiveRouteProvider` | Route-aware provider for real site routes |
152
+ | `useNoMessEditableEntry(entry, options?)` | Returns the active draft entry and reports the route |
153
+ | `NoMessField` | Convenience component for `data-no-mess-field` annotations |
154
+ | `useNoMessField(fieldName)` | Read a single field override from provider context |
138
155
 
139
- ### Field Types
156
+ ## Migration
140
157
 
141
- | Builder | Type | Description |
142
- |---------|------|-------------|
143
- | `field.text()` | `text` | Plain text input |
144
- | `field.textarea()` | `textarea` | Multi-line text |
145
- | `field.number()` | `number` | Numeric value |
146
- | `field.boolean()` | `boolean` | True/false toggle |
147
- | `field.datetime()` | `datetime` | Date/time picker |
148
- | `field.url()` | `url` | URL field |
149
- | `field.image()` | `image` | Image upload |
150
- | `field.select(opts)` | `select` | Dropdown with choices (requires `choices` array) |
151
- | `field.shopifyProduct()` | `shopifyProduct` | Shopify product reference |
152
- | `field.shopifyCollection()` | `shopifyCollection` | Shopify collection reference |
153
-
154
- ### Field Options
155
-
156
- All field builders accept an options object:
157
-
158
- ```ts
159
- field.text({
160
- required: true, // Whether the field is required (default: false)
161
- description: "...", // Help text shown in the dashboard
162
- })
163
- ```
164
-
165
- The `select` builder additionally requires a `choices` array:
166
-
167
- ```ts
168
- field.select({
169
- required: true,
170
- choices: [
171
- { label: "Draft", value: "draft" },
172
- { label: "Published", value: "published" },
173
- ],
174
- })
175
- ```
158
+ If you already use `useNoMessPreview()` and `useNoMessLiveEdit()` on
159
+ `/no-mess-preview`:
176
160
 
177
- ### Schema Utilities
161
+ 1. Keep the existing preview route in place.
162
+ 2. Add `NoMessLiveRouteProvider` to the real route tree.
163
+ 3. Replace direct entry rendering with `useNoMessEditableEntry(entry)` on the
164
+ routes you want Live Edit to open.
165
+ 4. Add `data-no-mess-field` annotations or `NoMessField` wrappers.
178
166
 
179
- | Function | Description |
180
- |----------|-------------|
181
- | `defineSchema({ contentTypes })` | Define a complete schema with content types |
182
- | `defineContentType(slug, options)` | Define a single content type |
183
- | `parseSchemaSource(source)` | Parse a schema.ts source string into a schema definition |
184
- | `generateSchemaSource(schema)` | Generate schema.ts source from a schema definition |
185
- | `generateContentTypeSource(contentType)` | Generate source for a single content type |
167
+ If you do nothing, the legacy preview route keeps working. You only miss the
168
+ route-aware Live Edit workflow.
186
169
 
187
170
  ## License
188
171
 
package/dist/client.d.ts CHANGED
@@ -1,9 +1,12 @@
1
- import type { GetEntryOptions, NoMessClientConfig, NoMessEntry, PreviewExchangeResult, PreviewSessionAuth, SchemaGetResponse, SchemaListResponse, ShopifyCollection, ShopifyProduct } from "./types.js";
1
+ import type { GetEntryOptions, NoMessClientConfig, NoMessEntry, PreviewExchangeResult, PreviewSessionAuth, ReportLiveEditRouteOptions, SchemaGetResponse, SchemaListResponse, ShopifyCollection, ShopifyProduct } from "./types.js";
2
2
  export declare class NoMessClient {
3
3
  private apiUrl;
4
4
  private apiKey;
5
+ private logger;
5
6
  constructor(config: NoMessClientConfig);
6
- private fetch;
7
+ private emitErrorLog;
8
+ private readResponseText;
9
+ private request;
7
10
  /**
8
11
  * List all content type schemas with fields, TypeScript interfaces, and entry counts.
9
12
  */
@@ -42,10 +45,17 @@ export declare class NoMessClient {
42
45
  * Computes an HMAC-SHA256 proof and sends it to the server for verification.
43
46
  */
44
47
  exchangePreviewSession(session: PreviewSessionAuth): Promise<PreviewExchangeResult>;
48
+ /**
49
+ * Report that an entry is rendered on the current site URL for route-aware live edit.
50
+ */
51
+ reportLiveEditRoute(options: ReportLiveEditRouteOptions): Promise<{
52
+ ok: boolean;
53
+ }>;
45
54
  /**
46
55
  * Compute HMAC-SHA256 proof for preview session authentication.
47
56
  * Uses Web Crypto API (works in browsers, Node.js 18+, Deno, Bun, edge runtimes).
48
57
  */
49
58
  private computeProof;
59
+ private toBase64;
50
60
  }
51
61
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACf,MAAM,YAAY,CAAC;AAGpB,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,kBAAkB;YAiBxB,KAAK;IA+BnB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAI/C;;OAEG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAI7D;;OAEG;IACG,UAAU,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAClD,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,CAAC,EAAE,CAAC;IAIf;;;OAGG;IACG,QAAQ,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAChD,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,CAAC,CAAC;IAWb;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAI9C;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAIzD;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAIpD;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAI/D;;;OAGG;IACG,sBAAsB,CAC1B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,qBAAqB,CAAC;IAkCjC;;;OAGG;YACW,YAAY;CA0B3B"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,WAAW,EAEX,qBAAqB,EACrB,kBAAkB,EAClB,0BAA0B,EAC1B,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACf,MAAM,YAAY,CAAC;AAWpB,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAqC;gBAEvC,MAAM,EAAE,kBAAkB;IAyBtC,OAAO,CAAC,YAAY;YAyBN,gBAAgB;YA6BhB,OAAO;IAoGrB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAQ/C;;OAEG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAQ7D;;OAEG;IACG,UAAU,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAClD,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,CAAC,EAAE,CAAC;IAQf;;;OAGG;IACG,QAAQ,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAChD,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,CAAC,CAAC;IAiBb;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAQ9C;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAQzD;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAQpD;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAQ/D;;;OAGG;IACG,sBAAsB,CAC1B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,qBAAqB,CAAC;IAoBjC;;OAEG;IACG,mBAAmB,CACvB,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAC;IAS3B;;;OAGG;YACW,YAAY;IA8F1B,OAAO,CAAC,QAAQ;CAmBjB"}