@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.
- package/README.md +108 -125
- package/dist/client.d.ts +12 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +250 -41
- package/dist/client.js.map +1 -1
- package/dist/error-utils.d.ts +20 -0
- package/dist/error-utils.d.ts.map +1 -0
- package/dist/error-utils.js +67 -0
- package/dist/error-utils.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +152 -22
- package/dist/index.js.map +1 -1
- package/dist/live-edit.d.ts.map +1 -1
- package/dist/live-edit.js +263 -102
- package/dist/live-edit.js.map +1 -1
- package/dist/logging.d.ts +6 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +58 -0
- package/dist/logging.js.map +1 -0
- package/dist/react/index.d.ts +3 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +2 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/no-mess-field.d.ts +10 -0
- package/dist/react/no-mess-field.d.ts.map +1 -0
- package/dist/react/no-mess-field.js +7 -0
- package/dist/react/no-mess-field.js.map +1 -0
- package/dist/react/no-mess-preview.d.ts +2 -6
- package/dist/react/no-mess-preview.d.ts.map +1 -1
- package/dist/react/no-mess-preview.js.map +1 -1
- package/dist/react/no-mess-provider.d.ts +21 -0
- package/dist/react/no-mess-provider.d.ts.map +1 -0
- package/dist/react/no-mess-provider.js +286 -0
- package/dist/react/no-mess-provider.js.map +1 -0
- package/dist/react/use-no-mess-live-edit.d.ts.map +1 -1
- package/dist/react/use-no-mess-live-edit.js +32 -2
- package/dist/react/use-no-mess-live-edit.js.map +1 -1
- package/dist/react/use-no-mess-preview.d.ts.map +1 -1
- package/dist/react/use-no-mess-preview.js +29 -6
- package/dist/react/use-no-mess-preview.js.map +1 -1
- package/dist/types.d.ts +78 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +23 -4
- package/dist/types.js.map +1 -1
- 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
|
-
##
|
|
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:
|
|
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
|
-
|
|
26
|
+
## Preview-Only Route
|
|
27
|
+
|
|
28
|
+
Use this when you want a dedicated `/no-mess-preview` page.
|
|
32
29
|
|
|
33
30
|
```tsx
|
|
34
|
-
|
|
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
|
-
|
|
37
|
-
const { entry, isLoading, error } = useNoMessPreview({
|
|
38
|
-
apiKey: "your-api-key",
|
|
39
|
-
});
|
|
50
|
+
## Route-Aware Preview and Live Edit
|
|
40
51
|
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
### Shopify data
|
|
78
|
+
### 2. Bind the rendered entry
|
|
51
79
|
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
71
|
-
|
|
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
|
-
###
|
|
138
|
+
### Preview / Live Edit
|
|
85
139
|
|
|
86
140
|
| Method | Description |
|
|
87
141
|
|--------|-------------|
|
|
88
|
-
| `client.
|
|
89
|
-
| `client.
|
|
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
|
-
###
|
|
145
|
+
### React (`@no-mess/client/react`)
|
|
94
146
|
|
|
95
|
-
|
|
|
96
|
-
|
|
97
|
-
| `
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
|
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
|
-
|
|
156
|
+
## Migration
|
|
140
157
|
|
|
141
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"
|
|
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"}
|