@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
@@ -0,0 +1,21 @@
1
+ import type { NoMessContextValue, NoMessEntry, NoMessLiveRouteProviderProps, NoMessProviderProps, UseNoMessEditableEntryOptions } from "../types.js";
2
+ /**
3
+ * Provider for route-aware preview and live edit on real site routes.
4
+ * Keeps the legacy preview-only APIs available while adding route reporting
5
+ * and entry binding for live edit on delivered pages.
6
+ */
7
+ export declare function NoMessLiveRouteProvider({ children, liveEditConfig, ...previewConfig }: NoMessLiveRouteProviderProps): import("react/jsx-runtime").JSX.Element;
8
+ /**
9
+ * Backward-compatible alias for the route-aware provider.
10
+ */
11
+ export declare function NoMessProvider(props: NoMessProviderProps): import("react/jsx-runtime").JSX.Element;
12
+ /** Access the current no-mess provider context. */
13
+ export declare function useNoMess(): NoMessContextValue | null;
14
+ /** Read a single live field override from provider context. */
15
+ export declare function useNoMessField<T = unknown>(fieldName: string): T | undefined;
16
+ /**
17
+ * Returns the entry visible on the current route, switching to preview/draft
18
+ * content when the active iframe session targets this entry.
19
+ */
20
+ export declare function useNoMessEditableEntry<T extends NoMessEntry>(entry: T, options?: UseNoMessEditableEntryOptions): T;
21
+ //# sourceMappingURL=no-mess-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-mess-provider.d.ts","sourceRoot":"","sources":["../../src/react/no-mess-provider.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,kBAAkB,EAClB,WAAW,EACX,4BAA4B,EAC5B,mBAAmB,EAEnB,6BAA6B,EAG9B,MAAM,aAAa,CAAC;AAwErB;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,cAAc,EACd,GAAG,aAAa,EACjB,EAAE,4BAA4B,2CAuK9B;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,2CAExD;AAED,mDAAmD;AACnD,wBAAgB,SAAS,8BAExB;AAED,+DAA+D;AAC/D,wBAAgB,cAAc,CAAC,CAAC,GAAG,OAAO,EAAE,SAAS,EAAE,MAAM,iBAI5D;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,WAAW,EAC1D,KAAK,EAAE,CAAC,EACR,OAAO,CAAC,EAAE,6BAA6B,KA4DxC"}
@@ -0,0 +1,286 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useEffect, useMemo, useRef, useState, } from "react";
4
+ import { NoMessClient } from "../client.js";
5
+ import { normalizeNoMessError } from "../error-utils.js";
6
+ import { createPreviewHandler } from "../index.js";
7
+ import { createLiveEditHandler } from "../live-edit.js";
8
+ import { DEFAULT_ADMIN_ORIGIN } from "../types.js";
9
+ const REPORTED_ROUTE_CACHE_PREFIX = "no-mess:reported-route";
10
+ const REPORTED_ROUTE_TTL_MS = 24 * 60 * 60 * 1000;
11
+ const TRANSIENT_PARAMS = ["preview", "secret", "sid", "slug", "type"];
12
+ const NoMessContext = createContext(null);
13
+ function sortSearchParams(url) {
14
+ const entries = [...url.searchParams.entries()].sort(([a], [b]) => a.localeCompare(b));
15
+ url.search = "";
16
+ for (const [key, value] of entries) {
17
+ url.searchParams.append(key, value);
18
+ }
19
+ }
20
+ function normalizeRouteUrl(url) {
21
+ const normalized = new URL(url, window.location.href);
22
+ for (const param of TRANSIENT_PARAMS) {
23
+ normalized.searchParams.delete(param);
24
+ }
25
+ sortSearchParams(normalized);
26
+ return normalized.toString();
27
+ }
28
+ function createReportedRouteCacheKey(entryId, url) {
29
+ return `${REPORTED_ROUTE_CACHE_PREFIX}:${entryId}:${url}`;
30
+ }
31
+ function shouldReportRoute(entryId, url) {
32
+ if (typeof localStorage === "undefined") {
33
+ return true;
34
+ }
35
+ const key = createReportedRouteCacheKey(entryId, url);
36
+ const lastReportedAt = Number(localStorage.getItem(key) ?? "0");
37
+ return (!lastReportedAt || Date.now() - lastReportedAt >= REPORTED_ROUTE_TTL_MS);
38
+ }
39
+ function markRouteReported(entryId, url) {
40
+ if (typeof localStorage === "undefined") {
41
+ return;
42
+ }
43
+ const key = createReportedRouteCacheKey(entryId, url);
44
+ localStorage.setItem(key, String(Date.now()));
45
+ }
46
+ function defaultPreviewState() {
47
+ return {
48
+ entry: null,
49
+ error: null,
50
+ errorDetails: null,
51
+ isLoading: true,
52
+ status: "waiting-for-admin",
53
+ };
54
+ }
55
+ function defaultLiveEditState() {
56
+ return {
57
+ isLiveEditActive: false,
58
+ fieldOverrides: {},
59
+ error: null,
60
+ errorDetails: null,
61
+ };
62
+ }
63
+ /**
64
+ * Provider for route-aware preview and live edit on real site routes.
65
+ * Keeps the legacy preview-only APIs available while adding route reporting
66
+ * and entry binding for live edit on delivered pages.
67
+ */
68
+ export function NoMessLiveRouteProvider({ children, liveEditConfig, ...previewConfig }) {
69
+ const [isIframe, setIsIframe] = useState(false);
70
+ const [preview, setPreview] = useState(defaultPreviewState);
71
+ const [liveEdit, setLiveEdit] = useState(defaultLiveEditState);
72
+ const adminOrigin = liveEditConfig?.adminOrigin ??
73
+ previewConfig.adminOrigin ??
74
+ DEFAULT_ADMIN_ORIGIN;
75
+ const client = useMemo(() => new NoMessClient({
76
+ apiKey: previewConfig.apiKey,
77
+ apiUrl: previewConfig.apiUrl,
78
+ logger: previewConfig.logger,
79
+ }), [previewConfig.apiKey, previewConfig.apiUrl, previewConfig.logger]);
80
+ useEffect(() => {
81
+ const iframe = window.self !== window.top;
82
+ setIsIframe(iframe);
83
+ if (!iframe) {
84
+ setPreview({
85
+ entry: null,
86
+ error: null,
87
+ errorDetails: null,
88
+ isLoading: false,
89
+ status: "ready",
90
+ });
91
+ return;
92
+ }
93
+ const previewHandler = createPreviewHandler({
94
+ client: {
95
+ exchangePreviewSession: async (...args) => {
96
+ setPreview((current) => ({
97
+ ...current,
98
+ isLoading: true,
99
+ status: "exchanging-session",
100
+ }));
101
+ return client.exchangePreviewSession(...args);
102
+ },
103
+ },
104
+ adminOrigin,
105
+ logger: previewConfig.logger,
106
+ onEntry: (entry) => {
107
+ setPreview({
108
+ entry,
109
+ error: null,
110
+ errorDetails: null,
111
+ isLoading: false,
112
+ status: "ready",
113
+ });
114
+ },
115
+ onError: (error) => {
116
+ const normalized = normalizeNoMessError(error, {
117
+ kind: "runtime",
118
+ code: "preview_exchange_failed",
119
+ operation: "NoMessLiveRouteProvider.onPreviewError",
120
+ });
121
+ setPreview({
122
+ entry: null,
123
+ error: normalized,
124
+ errorDetails: normalized,
125
+ isLoading: false,
126
+ status: "error",
127
+ });
128
+ },
129
+ });
130
+ const liveEditHandler = createLiveEditHandler({
131
+ adminOrigin,
132
+ logger: liveEditConfig?.logger ?? previewConfig.logger,
133
+ onEnter: () => {
134
+ setLiveEdit({
135
+ isLiveEditActive: true,
136
+ fieldOverrides: {},
137
+ error: null,
138
+ errorDetails: null,
139
+ });
140
+ },
141
+ onExit: () => {
142
+ setLiveEdit({
143
+ isLiveEditActive: false,
144
+ fieldOverrides: {},
145
+ error: null,
146
+ errorDetails: null,
147
+ });
148
+ },
149
+ onError: (error) => {
150
+ const normalized = normalizeNoMessError(error, {
151
+ kind: "runtime",
152
+ code: "live_edit_runtime_failed",
153
+ operation: "NoMessLiveRouteProvider.onLiveEditError",
154
+ });
155
+ setLiveEdit((current) => ({
156
+ ...current,
157
+ error: normalized,
158
+ errorDetails: normalized,
159
+ }));
160
+ },
161
+ });
162
+ const handleMessage = (event) => {
163
+ if (event.origin !== adminOrigin)
164
+ return;
165
+ const data = event.data;
166
+ if (!data || typeof data.type !== "string")
167
+ return;
168
+ if (data.type === "no-mess:field-updated" &&
169
+ typeof data.fieldName === "string") {
170
+ setLiveEdit((current) => ({
171
+ ...current,
172
+ fieldOverrides: {
173
+ ...current.fieldOverrides,
174
+ [data.fieldName]: data.value,
175
+ },
176
+ }));
177
+ }
178
+ };
179
+ previewHandler.start();
180
+ window.addEventListener("message", handleMessage);
181
+ return () => {
182
+ previewHandler.cleanup();
183
+ liveEditHandler.cleanup();
184
+ window.removeEventListener("message", handleMessage);
185
+ };
186
+ }, [adminOrigin, client, liveEditConfig?.logger, previewConfig.logger]);
187
+ const value = useMemo(() => ({
188
+ adminOrigin,
189
+ apiKey: previewConfig.apiKey,
190
+ apiUrl: previewConfig.apiUrl,
191
+ bindEntry: (entryId) => {
192
+ if (!isIframe)
193
+ return;
194
+ window.parent.postMessage({ type: "no-mess:entry-bound", entryId }, adminOrigin);
195
+ },
196
+ client,
197
+ isIframe,
198
+ preview,
199
+ liveEdit,
200
+ }), [
201
+ adminOrigin,
202
+ client,
203
+ isIframe,
204
+ liveEdit,
205
+ preview,
206
+ previewConfig.apiKey,
207
+ previewConfig.apiUrl,
208
+ ]);
209
+ return _jsx(NoMessContext, { value: value, children: children });
210
+ }
211
+ /**
212
+ * Backward-compatible alias for the route-aware provider.
213
+ */
214
+ export function NoMessProvider(props) {
215
+ return _jsx(NoMessLiveRouteProvider, { ...props });
216
+ }
217
+ /** Access the current no-mess provider context. */
218
+ export function useNoMess() {
219
+ return useContext(NoMessContext);
220
+ }
221
+ /** Read a single live field override from provider context. */
222
+ export function useNoMessField(fieldName) {
223
+ const ctx = useContext(NoMessContext);
224
+ if (!ctx)
225
+ return undefined;
226
+ return ctx.liveEdit.fieldOverrides[fieldName];
227
+ }
228
+ /**
229
+ * Returns the entry visible on the current route, switching to preview/draft
230
+ * content when the active iframe session targets this entry.
231
+ */
232
+ export function useNoMessEditableEntry(entry, options) {
233
+ const ctx = useContext(NoMessContext);
234
+ const lastBoundEntryId = useRef(null);
235
+ const registerCurrentUrl = options?.registerCurrentUrl ?? true;
236
+ useEffect(() => {
237
+ if (!ctx || !registerCurrentUrl)
238
+ return;
239
+ if (typeof window === "undefined")
240
+ return;
241
+ let normalizedUrl;
242
+ try {
243
+ normalizedUrl = normalizeRouteUrl(options?.url ?? window.location.href);
244
+ }
245
+ catch {
246
+ return;
247
+ }
248
+ if (!shouldReportRoute(entry._id, normalizedUrl)) {
249
+ return;
250
+ }
251
+ let cancelled = false;
252
+ const reportOptions = {
253
+ entryId: entry._id,
254
+ url: normalizedUrl,
255
+ };
256
+ void ctx.client
257
+ .reportLiveEditRoute(reportOptions)
258
+ .then(() => {
259
+ if (!cancelled) {
260
+ markRouteReported(entry._id, normalizedUrl);
261
+ }
262
+ })
263
+ .catch(() => { });
264
+ return () => {
265
+ cancelled = true;
266
+ };
267
+ }, [ctx, entry._id, options?.url, registerCurrentUrl]);
268
+ const matchesPreviewEntry = ctx?.preview.entry?._id === entry._id;
269
+ useEffect(() => {
270
+ if (!ctx || !ctx.isIframe || !matchesPreviewEntry)
271
+ return;
272
+ if (lastBoundEntryId.current === entry._id)
273
+ return;
274
+ ctx.bindEntry(entry._id);
275
+ lastBoundEntryId.current = entry._id;
276
+ }, [ctx, entry._id, matchesPreviewEntry]);
277
+ if (!ctx || !matchesPreviewEntry) {
278
+ return entry;
279
+ }
280
+ return {
281
+ ...entry,
282
+ ...ctx.preview.entry,
283
+ ...ctx.liveEdit.fieldOverrides,
284
+ };
285
+ }
286
+ //# sourceMappingURL=no-mess-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-mess-provider.js","sourceRoot":"","sources":["../../src/react/no-mess-provider.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-no-mess-live-edit.d.ts","sourceRoot":"","sources":["../../src/react/use-no-mess-live-edit.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,aAAa,CAAC;AAGrB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,uBAAuB,GAC9B,uBAAuB,CAiDzB"}
1
+ {"version":3,"file":"use-no-mess-live-edit.d.ts","sourceRoot":"","sources":["../../src/react/use-no-mess-live-edit.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,aAAa,CAAC;AAGrB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,uBAAuB,GAC9B,uBAAuB,CA8EzB"}
@@ -1,5 +1,7 @@
1
1
  "use client";
2
2
  import { useCallback, useEffect, useRef, useState } from "react";
3
+ import { normalizeNoMessError } from "../error-utils.js";
4
+ import { createSdkLogger } from "../logging.js";
3
5
  import { createLiveEditHandler } from "../live-edit.js";
4
6
  import { DEFAULT_ADMIN_ORIGIN } from "../types.js";
5
7
  /**
@@ -19,8 +21,12 @@ import { DEFAULT_ADMIN_ORIGIN } from "../types.js";
19
21
  export function useNoMessLiveEdit(config) {
20
22
  const [isLiveEditActive, setIsLiveEditActive] = useState(false);
21
23
  const [fieldOverrides, setFieldOverrides] = useState({});
24
+ const [error, setError] = useState(null);
25
+ const [errorDetails, setErrorDetails] = useState(null);
22
26
  const configRef = useRef(config);
23
27
  configRef.current = config;
28
+ const loggerRef = useRef(createSdkLogger(config.logger));
29
+ loggerRef.current = createSdkLogger(config.logger);
24
30
  const handleFieldUpdate = useCallback((event) => {
25
31
  const origin = configRef.current.adminOrigin ?? DEFAULT_ADMIN_ORIGIN;
26
32
  if (event.origin !== origin)
@@ -28,25 +34,49 @@ export function useNoMessLiveEdit(config) {
28
34
  const data = event.data;
29
35
  if (!data || typeof data.type !== "string")
30
36
  return;
31
- if (data.type === "no-mess:field-updated" && data.fieldName) {
37
+ if (data.type === "no-mess:field-updated" && typeof data.fieldName === "string") {
32
38
  setFieldOverrides((prev) => ({
33
39
  ...prev,
34
40
  [data.fieldName]: data.value,
35
41
  }));
42
+ return;
43
+ }
44
+ if (data.type === "no-mess:field-updated") {
45
+ loggerRef.current({
46
+ level: "debug",
47
+ code: "live_edit_runtime_failed",
48
+ message: "Ignored malformed live edit field update message in React state bridge",
49
+ scope: "live-edit-react",
50
+ operation: "useNoMessLiveEdit.handleFieldUpdate",
51
+ timestamp: new Date().toISOString(),
52
+ context: {},
53
+ });
36
54
  }
37
55
  }, []);
38
56
  useEffect(() => {
39
57
  const adminOrigin = configRef.current.adminOrigin ?? DEFAULT_ADMIN_ORIGIN;
40
58
  const handle = createLiveEditHandler({
41
59
  adminOrigin,
60
+ logger: configRef.current.logger,
42
61
  onEnter: () => {
43
62
  setIsLiveEditActive(true);
44
63
  setFieldOverrides({});
64
+ setError(null);
65
+ setErrorDetails(null);
45
66
  },
46
67
  onExit: () => {
47
68
  setIsLiveEditActive(false);
48
69
  setFieldOverrides({});
49
70
  },
71
+ onError: (err) => {
72
+ const normalized = normalizeNoMessError(err, {
73
+ kind: "runtime",
74
+ code: "live_edit_runtime_failed",
75
+ operation: "useNoMessLiveEdit.onError",
76
+ });
77
+ setError(normalized);
78
+ setErrorDetails(normalized);
79
+ },
50
80
  });
51
81
  // Also listen for field-updated to track overrides in React state
52
82
  window.addEventListener("message", handleFieldUpdate);
@@ -55,6 +85,6 @@ export function useNoMessLiveEdit(config) {
55
85
  window.removeEventListener("message", handleFieldUpdate);
56
86
  };
57
87
  }, [handleFieldUpdate]);
58
- return { isLiveEditActive, fieldOverrides };
88
+ return { isLiveEditActive, fieldOverrides, error, errorDetails };
59
89
  }
60
90
  //# sourceMappingURL=use-no-mess-live-edit.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-no-mess-live-edit.js","sourceRoot":"","sources":["../../src/react/use-no-mess-live-edit.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAKxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAA+B;IAE/B,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChE,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAClD,EAAE,CACH,CAAC;IAEF,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC;IAE3B,MAAM,iBAAiB,GAAG,WAAW,CAAC,CAAC,KAAmB,EAAE,EAAE;QAC5D,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,WAAW,IAAI,oBAAoB,CAAC;QACrE,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM;YAAE,OAAO;QAEpC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO;QAEnD,IAAI,IAAI,CAAC,IAAI,KAAK,uBAAuB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC5D,iBAAiB,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBAC3B,GAAG,IAAI;gBACP,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,KAAK;aAC7B,CAAC,CAAC,CAAC;QACN,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,WAAW,IAAI,oBAAoB,CAAC;QAE1E,MAAM,MAAM,GAAG,qBAAqB,CAAC;YACnC,WAAW;YACX,OAAO,EAAE,GAAG,EAAE;gBACZ,mBAAmB,CAAC,IAAI,CAAC,CAAC;gBAC1B,iBAAiB,CAAC,EAAE,CAAC,CAAC;YACxB,CAAC;YACD,MAAM,EAAE,GAAG,EAAE;gBACX,mBAAmB,CAAC,KAAK,CAAC,CAAC;gBAC3B,iBAAiB,CAAC,EAAE,CAAC,CAAC;YACxB,CAAC;SACF,CAAC,CAAC;QAEH,kEAAkE;QAClE,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;QAEtD,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;QAC3D,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAExB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,CAAC;AAC9C,CAAC"}
1
+ {"version":3,"file":"use-no-mess-live-edit.js","sourceRoot":"","sources":["../../src/react/use-no-mess-live-edit.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-no-mess-preview.d.ts","sourceRoot":"","sources":["../../src/react/use-no-mess-preview.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,WAAW,EACX,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,aAAa,CAAC;AAGrB,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAClE,MAAM,EAAE,sBAAsB,GAC7B,sBAAsB,CAAC,CAAC,CAAC,CAiC3B"}
1
+ {"version":3,"file":"use-no-mess-preview.d.ts","sourceRoot":"","sources":["../../src/react/use-no-mess-preview.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,WAAW,EAEX,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,aAAa,CAAC;AAGrB,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAClE,MAAM,EAAE,sBAAsB,GAC7B,sBAAsB,CAAC,CAAC,CAAC,CA0D3B"}
@@ -1,35 +1,58 @@
1
1
  "use client";
2
2
  import { useEffect, useRef, useState } from "react";
3
3
  import { NoMessClient } from "../client.js";
4
+ import { normalizeNoMessError } from "../error-utils.js";
4
5
  import { createPreviewHandler } from "../index.js";
5
6
  import { DEFAULT_ADMIN_ORIGIN } from "../types.js";
6
7
  export function useNoMessPreview(config) {
7
8
  const [entry, setEntry] = useState(null);
8
9
  const [error, setError] = useState(null);
9
- const [isLoading, setIsLoading] = useState(true);
10
+ const [errorDetails, setErrorDetails] = useState(null);
11
+ const [status, setStatus] = useState("waiting-for-admin");
10
12
  const configRef = useRef(config);
11
13
  configRef.current = config;
12
14
  useEffect(() => {
13
- const client = new NoMessClient({
15
+ const baseClient = new NoMessClient({
14
16
  apiKey: configRef.current.apiKey,
15
17
  apiUrl: configRef.current.apiUrl,
18
+ logger: configRef.current.logger,
16
19
  });
20
+ const client = {
21
+ exchangePreviewSession: async (...args) => {
22
+ setStatus("exchanging-session");
23
+ return baseClient.exchangePreviewSession(...args);
24
+ },
25
+ };
17
26
  const handler = createPreviewHandler({
18
27
  client,
19
28
  adminOrigin: configRef.current.adminOrigin ?? DEFAULT_ADMIN_ORIGIN,
29
+ logger: configRef.current.logger,
20
30
  onEntry: (e) => {
21
31
  setEntry(e);
22
32
  setError(null);
23
- setIsLoading(false);
33
+ setErrorDetails(null);
34
+ setStatus("ready");
24
35
  },
25
36
  onError: (err) => {
26
- setError(err);
27
- setIsLoading(false);
37
+ const normalized = normalizeNoMessError(err, {
38
+ kind: "runtime",
39
+ code: "preview_exchange_failed",
40
+ operation: "useNoMessPreview.onError",
41
+ });
42
+ setError(normalized);
43
+ setErrorDetails(normalized);
44
+ setStatus("error");
28
45
  },
29
46
  });
30
47
  handler.start();
31
48
  return () => handler.cleanup();
32
49
  }, []);
33
- return { entry, error, isLoading };
50
+ return {
51
+ entry,
52
+ error,
53
+ errorDetails,
54
+ isLoading: status !== "ready" && status !== "error",
55
+ status,
56
+ };
34
57
  }
35
58
  //# sourceMappingURL=use-no-mess-preview.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-no-mess-preview.js","sourceRoot":"","sources":["../../src/react/use-no-mess-preview.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAMnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,UAAU,gBAAgB,CAC9B,MAA8B;IAE9B,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAW,IAAI,CAAC,CAAC;IACnD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IACvD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEjD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC;IAE3B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC;YAC9B,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,MAAM;YAChC,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,MAAM;SACjC,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,oBAAoB,CAAC;YACnC,MAAM;YACN,WAAW,EAAE,SAAS,CAAC,OAAO,CAAC,WAAW,IAAI,oBAAoB;YAClE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;gBACb,QAAQ,CAAC,CAAM,CAAC,CAAC;gBACjB,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACf,YAAY,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;YACD,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACf,QAAQ,CAAC,GAAG,CAAC,CAAC;gBACd,YAAY,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IACjC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AACrC,CAAC"}
1
+ {"version":3,"file":"use-no-mess-preview.js","sourceRoot":"","sources":["../../src/react/use-no-mess-preview.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAOnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,UAAU,gBAAgB,CAC9B,MAA8B;IAE9B,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAW,IAAI,CAAC,CAAC;IACnD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IACvD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAqB,IAAI,CAAC,CAAC;IAC3E,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAClC,mBAAmB,CACpB,CAAC;IAEF,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC;IAE3B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,UAAU,GAAG,IAAI,YAAY,CAAC;YAClC,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,MAAM;YAChC,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,MAAM;YAChC,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,MAAM;SACjC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG;YACb,sBAAsB,EAAE,KAAK,EAAE,GAAG,IAAwD,EAAE,EAAE;gBAC5F,SAAS,CAAC,oBAAoB,CAAC,CAAC;gBAChC,OAAO,UAAU,CAAC,sBAAsB,CAAC,GAAG,IAAI,CAAC,CAAC;YACpD,CAAC;SACF,CAAC;QAEF,MAAM,OAAO,GAAG,oBAAoB,CAAC;YACnC,MAAM;YACN,WAAW,EAAE,SAAS,CAAC,OAAO,CAAC,WAAW,IAAI,oBAAoB;YAClE,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,MAAM;YAChC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;gBACb,QAAQ,CAAC,CAAM,CAAC,CAAC;gBACjB,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACf,eAAe,CAAC,IAAI,CAAC,CAAC;gBACtB,SAAS,CAAC,OAAO,CAAC,CAAC;YACrB,CAAC;YACD,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACf,MAAM,UAAU,GAAG,oBAAoB,CAAC,GAAG,EAAE;oBAC3C,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,yBAAyB;oBAC/B,SAAS,EAAE,0BAA0B;iBACtC,CAAC,CAAC;gBACH,QAAQ,CAAC,UAAU,CAAC,CAAC;gBACrB,eAAe,CAAC,UAAU,CAAC,CAAC;gBAC5B,SAAS,CAAC,OAAO,CAAC,CAAC;YACrB,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IACjC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO;QACL,KAAK;QACL,KAAK;QACL,YAAY;QACZ,SAAS,EAAE,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,OAAO;QACnD,MAAM;KACP,CAAC;AACJ,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,5 +1,31 @@
1
- export declare const DEFAULT_API_URL = "https://api.no-mess.xyz";
1
+ export declare const DEFAULT_API_URL = "https://api.nomess.xyz";
2
2
  export declare const DEFAULT_ADMIN_ORIGIN = "https://admin.no-mess.xyz";
3
+ export type NoMessErrorKind = "config" | "network" | "http" | "response" | "crypto" | "protocol" | "runtime";
4
+ export type NoMessErrorCode = "secret_key_in_browser" | "request_failed" | "http_error" | "invalid_success_response" | "invalid_error_response" | "crypto_unavailable" | "invalid_session_secret" | "preview_message_invalid" | "preview_exchange_failed" | "preview_postmessage_failed" | "live_edit_runtime_failed";
5
+ export type NoMessLogLevel = "debug" | "info" | "warn" | "error";
6
+ export interface NoMessLogEvent {
7
+ level: NoMessLogLevel;
8
+ code: NoMessErrorCode;
9
+ message: string;
10
+ scope: string;
11
+ operation?: string;
12
+ error?: NoMessError;
13
+ timestamp: string;
14
+ context: Record<string, unknown>;
15
+ }
16
+ export type NoMessLogger = (event: NoMessLogEvent) => void;
17
+ export interface NoMessErrorOptions {
18
+ kind?: NoMessErrorKind;
19
+ code?: NoMessErrorCode;
20
+ status?: number;
21
+ retryable?: boolean;
22
+ operation?: string;
23
+ method?: string;
24
+ url?: string;
25
+ requestId?: string;
26
+ details?: Record<string, unknown>;
27
+ cause?: unknown;
28
+ }
3
29
  export interface NoMessClientConfig {
4
30
  apiUrl?: string;
5
31
  /**
@@ -10,6 +36,7 @@ export interface NoMessClientConfig {
10
36
  * - **Publishable key**: Safe for client-side use. Read-only access to published content.
11
37
  */
12
38
  apiKey: string;
39
+ logger?: NoMessLogger;
13
40
  }
14
41
  /** Returns true if the key is a publishable key (nm_pub_ prefix). */
15
42
  export declare function isPublishableKey(key: string): boolean;
@@ -66,6 +93,11 @@ export interface PreviewSessionAuth {
66
93
  sessionId: string;
67
94
  sessionSecret: string;
68
95
  }
96
+ /** Report a delivery URL for route-aware Live Edit. */
97
+ export interface ReportLiveEditRouteOptions {
98
+ entryId: string;
99
+ url?: string;
100
+ }
69
101
  export interface PreviewExchangeResult {
70
102
  entry: NoMessEntry;
71
103
  sessionId: string;
@@ -78,16 +110,21 @@ export interface PreviewHandlerConfig {
78
110
  adminOrigin: string;
79
111
  onEntry: (entry: NoMessEntry) => void;
80
112
  onError?: (error: Error) => void;
113
+ logger?: NoMessLogger;
81
114
  }
82
115
  export interface UseNoMessPreviewConfig {
83
116
  apiKey: string;
84
117
  apiUrl?: string;
85
118
  adminOrigin?: string;
119
+ logger?: NoMessLogger;
86
120
  }
121
+ export type UseNoMessPreviewStatus = "waiting-for-admin" | "exchanging-session" | "ready" | "error";
87
122
  export interface UseNoMessPreviewResult<T extends NoMessEntry = NoMessEntry> {
88
123
  entry: T | null;
89
124
  error: Error | null;
125
+ errorDetails: NoMessError | null;
90
126
  isLoading: boolean;
127
+ status: UseNoMessPreviewStatus;
91
128
  }
92
129
  export interface ContentTypeSchema {
93
130
  name: string;
@@ -138,6 +175,30 @@ export interface SchemaGetResponse {
138
175
  contentType: ContentTypeSchema;
139
176
  sdkExample: string;
140
177
  }
178
+ /** Props for the route-aware provider used on real site routes. */
179
+ export interface NoMessLiveRouteProviderProps extends UseNoMessPreviewConfig {
180
+ children: import("react").ReactNode;
181
+ liveEditConfig?: UseNoMessLiveEditConfig;
182
+ }
183
+ /** Backward-compatible alias for the route-aware provider props. */
184
+ export interface NoMessProviderProps extends NoMessLiveRouteProviderProps {
185
+ }
186
+ /** Options for binding a rendered entry to the current route. */
187
+ export interface UseNoMessEditableEntryOptions {
188
+ registerCurrentUrl?: boolean;
189
+ url?: string;
190
+ }
191
+ /** Shared provider context for preview/live-edit state. */
192
+ export interface NoMessContextValue {
193
+ adminOrigin: string;
194
+ apiKey: string;
195
+ apiUrl?: string;
196
+ bindEntry: (entryId: string) => void;
197
+ client: Pick<import("./client.js").NoMessClient, "reportLiveEditRoute">;
198
+ isIframe: boolean;
199
+ preview: UseNoMessPreviewResult;
200
+ liveEdit: UseNoMessLiveEditResult;
201
+ }
141
202
  export interface LiveEditFieldInfo {
142
203
  name: string;
143
204
  type: string;
@@ -148,19 +209,34 @@ export interface LiveEditConfig {
148
209
  onFieldClicked?: (fieldName: string) => void;
149
210
  onEnter?: () => void;
150
211
  onExit?: () => void;
212
+ onError?: (error: Error) => void;
213
+ logger?: NoMessLogger;
151
214
  }
152
215
  export interface LiveEditHandle {
153
216
  cleanup: () => void;
154
217
  }
155
218
  export interface UseNoMessLiveEditConfig {
156
219
  adminOrigin?: string;
220
+ logger?: NoMessLogger;
157
221
  }
158
222
  export interface UseNoMessLiveEditResult {
159
223
  isLiveEditActive: boolean;
160
224
  fieldOverrides: Record<string, unknown>;
225
+ error: Error | null;
226
+ errorDetails: NoMessError | null;
161
227
  }
162
228
  export declare class NoMessError extends Error {
163
- status: number;
229
+ readonly kind: NoMessErrorKind;
230
+ readonly code: NoMessErrorCode;
231
+ readonly status?: number;
232
+ readonly retryable: boolean;
233
+ readonly operation?: string;
234
+ readonly method?: string;
235
+ readonly url?: string;
236
+ readonly requestId?: string;
237
+ readonly details?: Record<string, unknown>;
238
+ readonly cause?: unknown;
164
239
  constructor(message: string, status: number);
240
+ constructor(message: string, options?: NoMessErrorOptions);
165
241
  }
166
242
  //# sourceMappingURL=types.d.ts.map