tinacms 3.14.0 → 3.14.2

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.
@@ -3,7 +3,7 @@ export declare const PageWrapper: ({ headerClassName, children, }: {
3
3
  headerClassName?: string;
4
4
  children: React.ReactNode;
5
5
  }) => React.JSX.Element;
6
- export declare const PageHeader: ({ children, }: {
6
+ export declare const PageHeader: ({ children }: {
7
7
  children: React.ReactNode;
8
8
  }) => React.JSX.Element;
9
9
  export declare const PageBody: ({ children }: {
@@ -0,0 +1 @@
1
+ export * from './unifiedClient';
@@ -0,0 +1,175 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+ class AsyncLock {
5
+ constructor() {
6
+ __publicField(this, "queues", /* @__PURE__ */ new Map());
7
+ }
8
+ acquire(key, fn) {
9
+ const prev = this.queues.get(key) ?? Promise.resolve();
10
+ const next = prev.then(fn);
11
+ this.queues.set(
12
+ key,
13
+ next.then(
14
+ () => void 0,
15
+ () => void 0
16
+ )
17
+ );
18
+ return next;
19
+ }
20
+ }
21
+ const TINA_HOST = "content.tinajs.io";
22
+ function replaceGithubPathSplit(url, replacement) {
23
+ const parts = url.split("github/");
24
+ if (parts.length > 1 && replacement) {
25
+ return parts[0] + "github/" + replacement;
26
+ } else {
27
+ return url;
28
+ }
29
+ }
30
+ function isEdgeRuntimeWithoutFs() {
31
+ if (typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers") {
32
+ return true;
33
+ }
34
+ if (typeof globalThis.EdgeRuntime !== "undefined") {
35
+ return true;
36
+ }
37
+ return false;
38
+ }
39
+ class TinaClient {
40
+ constructor({
41
+ token,
42
+ url,
43
+ queries,
44
+ errorPolicy,
45
+ cacheDir,
46
+ cache
47
+ }) {
48
+ __publicField(this, "apiUrl");
49
+ __publicField(this, "readonlyToken");
50
+ __publicField(this, "queries");
51
+ __publicField(this, "errorPolicy");
52
+ __publicField(this, "initialized", false);
53
+ __publicField(this, "cacheLock");
54
+ __publicField(this, "cacheDir");
55
+ __publicField(this, "cache");
56
+ __publicField(this, "cacheEnabled");
57
+ this.apiUrl = url;
58
+ this.readonlyToken = token == null ? void 0 : token.trim();
59
+ this.queries = queries(this);
60
+ this.errorPolicy = errorPolicy || "throw";
61
+ this.cacheDir = cacheDir || "";
62
+ this.cacheEnabled = cache !== false;
63
+ }
64
+ async init() {
65
+ if (this.initialized) {
66
+ return;
67
+ }
68
+ try {
69
+ if (this.cacheEnabled && this.cacheDir && typeof window === "undefined" && !isEdgeRuntimeWithoutFs()) {
70
+ this.cache = await this.createCache(this.cacheDir);
71
+ if (this.cache) {
72
+ this.cacheLock = new AsyncLock();
73
+ }
74
+ }
75
+ } catch (e) {
76
+ console.error(e);
77
+ }
78
+ this.initialized = true;
79
+ }
80
+ async createCache(_dir) {
81
+ return null;
82
+ }
83
+ async request({ errorPolicy, ...args }, options) {
84
+ var _a;
85
+ await this.init();
86
+ const errorPolicyDefined = errorPolicy || this.errorPolicy;
87
+ const headers = new Headers();
88
+ if (this.readonlyToken) {
89
+ headers.append("X-API-KEY", this.readonlyToken);
90
+ }
91
+ headers.append("Content-Type", "application/json");
92
+ if (options == null ? void 0 : options.fetchOptions) {
93
+ if ((_a = options == null ? void 0 : options.fetchOptions) == null ? void 0 : _a.headers) {
94
+ Object.entries(options.fetchOptions.headers).forEach(([key2, value]) => {
95
+ headers.append(key2, value);
96
+ });
97
+ }
98
+ }
99
+ const { headers: _, ...providedFetchOptions } = (options == null ? void 0 : options.fetchOptions) || {};
100
+ const bodyString = JSON.stringify({
101
+ query: args.query,
102
+ variables: (args == null ? void 0 : args.variables) || {}
103
+ });
104
+ const optionsObject = {
105
+ method: "POST",
106
+ headers,
107
+ body: bodyString,
108
+ redirect: "follow",
109
+ ...providedFetchOptions
110
+ };
111
+ const draftBranch = headers.get("x-branch");
112
+ const url = replaceGithubPathSplit((args == null ? void 0 : args.url) || this.apiUrl, draftBranch);
113
+ let key = "";
114
+ let result;
115
+ if (this.cache) {
116
+ key = this.cache.makeKey(bodyString);
117
+ await this.cacheLock.acquire(key, async () => {
118
+ result = await this.cache.get(key);
119
+ if (!result) {
120
+ result = await requestFromServer(
121
+ url,
122
+ args.query,
123
+ optionsObject,
124
+ errorPolicyDefined
125
+ );
126
+ await this.cache.set(key, result);
127
+ }
128
+ });
129
+ } else {
130
+ result = await requestFromServer(
131
+ url,
132
+ args.query,
133
+ optionsObject,
134
+ errorPolicyDefined
135
+ );
136
+ }
137
+ return result;
138
+ }
139
+ }
140
+ async function requestFromServer(url, query, optionsObject, errorPolicyDefined) {
141
+ const res = await fetch(url, optionsObject);
142
+ if (!res.ok) {
143
+ let additionalInfo = "";
144
+ if (res.status === 401) {
145
+ additionalInfo = "Please check that your client ID, URL and read only token are configured properly.";
146
+ }
147
+ throw new Error(
148
+ `Server responded with status code ${res.status}, ${res.statusText}. ${additionalInfo ? additionalInfo : ""} Please see our FAQ for more information: https://tina.io/docs/r/FAQ/`
149
+ );
150
+ }
151
+ const json = await res.json();
152
+ if (json.errors && errorPolicyDefined === "throw") {
153
+ throw new Error(
154
+ `Unable to fetch, please see our FAQ for more information: https://tina.io/docs/r/FAQ/
155
+ Errors:
156
+ ${json.errors.map((error) => error.message).join("\n")}`
157
+ );
158
+ }
159
+ const result = {
160
+ data: json == null ? void 0 : json.data,
161
+ errors: (json == null ? void 0 : json.errors) || null,
162
+ query
163
+ };
164
+ return result;
165
+ }
166
+ function createClient(args) {
167
+ const client = new TinaClient(args);
168
+ return client;
169
+ }
170
+ export {
171
+ AsyncLock,
172
+ TINA_HOST,
173
+ TinaClient,
174
+ createClient
175
+ };
package/dist/client.d.ts CHANGED
@@ -1,4 +1,7 @@
1
- /**
2
-
3
- */
4
1
  export * from './unifiedClient';
2
+ import { TinaClient as BaseTinaClient } from './unifiedClient';
3
+ import type { TinaClientArgs } from './unifiedClient';
4
+ export declare class TinaClient<GenQueries> extends BaseTinaClient<GenQueries> {
5
+ protected createCache(dir: string): Promise<import("./cache").Cache>;
6
+ }
7
+ export declare function createClient<GenQueries>(args: TinaClientArgs<GenQueries>): TinaClient<GenQueries>;
package/dist/client.js CHANGED
@@ -1,125 +1,3 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropNames = Object.getOwnPropertyNames;
3
- var __esm = (fn, res, err) => function __init() {
4
- if (err) throw err[0];
5
- try {
6
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
- } catch (e) {
8
- throw err = [e], e;
9
- }
10
- };
11
- var __export = (target, all) => {
12
- for (var name in all)
13
- __defProp(target, name, { get: all[name], enumerable: true });
14
- };
15
-
16
- // src/cache/node-cache.ts
17
- var node_cache_exports = {};
18
- __export(node_cache_exports, {
19
- NodeCache: () => NodeCache,
20
- makeCacheDir: () => makeCacheDir
21
- });
22
- var resolveModule, getRootPath, makeCacheDir, NodeCache;
23
- var init_node_cache = __esm({
24
- "src/cache/node-cache.ts"() {
25
- resolveModule = (mod) => {
26
- if (mod && typeof mod === "object" && "default" in mod && mod.default) {
27
- return mod.default;
28
- }
29
- return mod;
30
- };
31
- getRootPath = (pathParts, pathArg) => {
32
- if (pathParts.length === 0) return null;
33
- const isWindows = pathArg.sep === "\\";
34
- const root = pathParts[0];
35
- return isWindows ? `${root}${pathArg.sep}` : `${pathArg.sep}${root}`;
36
- };
37
- makeCacheDir = (dir, fsArg, pathArg, osArg) => {
38
- const normalizedDir = pathArg.normalize(dir);
39
- const pathParts = normalizedDir.split(pathArg.sep).filter(Boolean);
40
- const cacheHash = pathParts[pathParts.length - 1];
41
- const rootPath = getRootPath(pathParts, pathArg);
42
- const rootExists = rootPath && fsArg.existsSync(rootPath);
43
- const cacheDir = rootExists ? normalizedDir : pathArg.join(osArg.tmpdir(), cacheHash);
44
- try {
45
- fsArg.mkdirSync(cacheDir, { recursive: true });
46
- } catch (error) {
47
- console.warn(
48
- `Warning: Failed to create cache directory: ${error.message}. Caching will be disabled.`
49
- );
50
- return null;
51
- }
52
- return cacheDir;
53
- };
54
- NodeCache = async (dir) => {
55
- try {
56
- const [fsModule, pathModule, osModule, cryptoModule] = await Promise.all([
57
- import("node:fs"),
58
- import("node:path"),
59
- import("node:os"),
60
- import("node:crypto")
61
- ]);
62
- const fs = resolveModule(fsModule);
63
- const path = resolveModule(pathModule);
64
- const os = resolveModule(osModule);
65
- const crypto = resolveModule(cryptoModule);
66
- if (typeof path?.join !== "function") {
67
- console.warn(
68
- "Warning: Node.js path module not available. Caching will be disabled."
69
- );
70
- return null;
71
- }
72
- const cacheDir = makeCacheDir(dir, fs, path, os);
73
- if (cacheDir === null) {
74
- return null;
75
- }
76
- return {
77
- makeKey: (key) => {
78
- const input = key && key instanceof Object ? JSON.stringify(key) : key || "";
79
- return crypto.createHash("sha256").update(input).digest("hex");
80
- },
81
- get: async (key) => {
82
- let readValue;
83
- const cacheFilename = path.join(cacheDir, key);
84
- try {
85
- const data = await fs.promises.readFile(cacheFilename, "utf-8");
86
- readValue = JSON.parse(data);
87
- } catch (e) {
88
- if (e.code !== "ENOENT") {
89
- console.warn(
90
- `Warning: Failed to read cache file ${cacheFilename}: ${e.message}`
91
- );
92
- }
93
- }
94
- return readValue;
95
- },
96
- set: async (key, value) => {
97
- const cacheFilename = path.join(cacheDir, key);
98
- try {
99
- await fs.promises.writeFile(cacheFilename, JSON.stringify(value), {
100
- encoding: "utf-8",
101
- flag: "wx"
102
- });
103
- } catch (e) {
104
- if (e.code !== "EEXIST") {
105
- console.warn(
106
- `Warning: Failed to write cache file ${cacheFilename}: ${e.message}`
107
- );
108
- }
109
- }
110
- }
111
- };
112
- } catch (e) {
113
- console.warn(
114
- "Warning: Failed to initialize cache. Caching will be disabled.",
115
- e.message
116
- );
117
- return null;
118
- }
119
- };
120
- }
121
- });
122
-
123
1
  // src/unifiedClient/asyncLock.ts
124
2
  var AsyncLock = class {
125
3
  queues = /* @__PURE__ */ new Map();
@@ -187,8 +65,7 @@ var TinaClient = class {
187
65
  }
188
66
  try {
189
67
  if (this.cacheEnabled && this.cacheDir && typeof window === "undefined" && !isEdgeRuntimeWithoutFs()) {
190
- const { NodeCache: NodeCache2 } = await Promise.resolve().then(() => (init_node_cache(), node_cache_exports));
191
- this.cache = await NodeCache2(this.cacheDir);
68
+ this.cache = await this.createCache(this.cacheDir);
192
69
  if (this.cache) {
193
70
  this.cacheLock = new AsyncLock();
194
71
  }
@@ -198,6 +75,9 @@ var TinaClient = class {
198
75
  }
199
76
  this.initialized = true;
200
77
  }
78
+ async createCache(_dir) {
79
+ return null;
80
+ }
201
81
  async request({ errorPolicy, ...args }, options) {
202
82
  await this.init();
203
83
  const errorPolicyDefined = errorPolicy || this.errorPolicy;
@@ -280,13 +160,116 @@ async function requestFromServer(url, query, optionsObject, errorPolicyDefined)
280
160
  };
281
161
  return result;
282
162
  }
163
+
164
+ // src/cache/node-cache.ts
165
+ var resolveModule = (mod) => {
166
+ if (mod && typeof mod === "object" && "default" in mod && mod.default) {
167
+ return mod.default;
168
+ }
169
+ return mod;
170
+ };
171
+ var getRootPath = (pathParts, pathArg) => {
172
+ if (pathParts.length === 0) return null;
173
+ const isWindows = pathArg.sep === "\\";
174
+ const root = pathParts[0];
175
+ return isWindows ? `${root}${pathArg.sep}` : `${pathArg.sep}${root}`;
176
+ };
177
+ var makeCacheDir = (dir, fsArg, pathArg, osArg) => {
178
+ const normalizedDir = pathArg.normalize(dir);
179
+ const pathParts = normalizedDir.split(pathArg.sep).filter(Boolean);
180
+ const cacheHash = pathParts[pathParts.length - 1];
181
+ const rootPath = getRootPath(pathParts, pathArg);
182
+ const rootExists = rootPath && fsArg.existsSync(rootPath);
183
+ const cacheDir = rootExists ? normalizedDir : pathArg.join(osArg.tmpdir(), cacheHash);
184
+ try {
185
+ fsArg.mkdirSync(cacheDir, { recursive: true });
186
+ } catch (error) {
187
+ console.warn(
188
+ `Warning: Failed to create cache directory: ${error.message}. Caching will be disabled.`
189
+ );
190
+ return null;
191
+ }
192
+ return cacheDir;
193
+ };
194
+ var NodeCache = async (dir) => {
195
+ try {
196
+ const [fsModule, pathModule, osModule, cryptoModule] = await Promise.all([
197
+ import("node:fs"),
198
+ import("node:path"),
199
+ import("node:os"),
200
+ import("node:crypto")
201
+ ]);
202
+ const fs = resolveModule(fsModule);
203
+ const path = resolveModule(pathModule);
204
+ const os = resolveModule(osModule);
205
+ const crypto = resolveModule(cryptoModule);
206
+ if (typeof path?.join !== "function") {
207
+ console.warn(
208
+ "Warning: Node.js path module not available. Caching will be disabled."
209
+ );
210
+ return null;
211
+ }
212
+ const cacheDir = makeCacheDir(dir, fs, path, os);
213
+ if (cacheDir === null) {
214
+ return null;
215
+ }
216
+ return {
217
+ makeKey: (key) => {
218
+ const input = key && key instanceof Object ? JSON.stringify(key) : key || "";
219
+ return crypto.createHash("sha256").update(input).digest("hex");
220
+ },
221
+ get: async (key) => {
222
+ let readValue;
223
+ const cacheFilename = path.join(cacheDir, key);
224
+ try {
225
+ const data = await fs.promises.readFile(cacheFilename, "utf-8");
226
+ readValue = JSON.parse(data);
227
+ } catch (e) {
228
+ if (e.code !== "ENOENT") {
229
+ console.warn(
230
+ `Warning: Failed to read cache file ${cacheFilename}: ${e.message}`
231
+ );
232
+ }
233
+ }
234
+ return readValue;
235
+ },
236
+ set: async (key, value) => {
237
+ const cacheFilename = path.join(cacheDir, key);
238
+ try {
239
+ await fs.promises.writeFile(cacheFilename, JSON.stringify(value), {
240
+ encoding: "utf-8",
241
+ flag: "wx"
242
+ });
243
+ } catch (e) {
244
+ if (e.code !== "EEXIST") {
245
+ console.warn(
246
+ `Warning: Failed to write cache file ${cacheFilename}: ${e.message}`
247
+ );
248
+ }
249
+ }
250
+ }
251
+ };
252
+ } catch (e) {
253
+ console.warn(
254
+ "Warning: Failed to initialize cache. Caching will be disabled.",
255
+ e.message
256
+ );
257
+ return null;
258
+ }
259
+ };
260
+
261
+ // src/client.ts
262
+ var TinaClient2 = class extends TinaClient {
263
+ createCache(dir) {
264
+ return NodeCache(dir);
265
+ }
266
+ };
283
267
  function createClient(args) {
284
- const client = new TinaClient(args);
285
- return client;
268
+ return new TinaClient2(args);
286
269
  }
287
270
  export {
288
271
  AsyncLock,
289
272
  TINA_HOST,
290
- TinaClient,
273
+ TinaClient2 as TinaClient,
291
274
  createClient
292
275
  };
package/dist/index.js CHANGED
@@ -32,7 +32,7 @@ import { useHTMLInputCursorState, useComboboxInput } from "@udecode/plate-combob
32
32
  import { useComboboxContext, Combobox as Combobox$1, useComboboxStore, ComboboxProvider, Portal, ComboboxPopover, ComboboxItem } from "@ariakit/react";
33
33
  import { filterWords } from "@udecode/plate-combobox";
34
34
  import { toggleList, unwrapList, getListItemEntry } from "@udecode/plate-list";
35
- import { normalizeHeadingLevels, ALL_HEADING_LEVELS, MEDIA_MIME_TYPES, extensionOf, resolveMediaAccept, ASYNC_POLLER_ERROR, MEDIA_CATEGORIES, canonicalPath, ERR_BRANCH_EXISTS, ERR_BRANCH_CONFLICT, isHeadingLevel, TinaSchema, addNamespaceToSchema, parseURL, ERR_HAS_REFERENCES, ERR_ALREADY_EXISTS, isValidRelativePath, RELATIVE_PATH_ALLOWED_CHARS_MESSAGE, resolveForm, RELATIVE_PATH_REGEX, normalizePath, ERR_NOT_INDEXED, validateSchema } from "@tinacms/schema-tools";
35
+ import { normalizeHeadingLevels, ALL_HEADING_LEVELS, MEDIA_MIME_TYPES, extensionOf, resolveMediaAccept, ASYNC_POLLER_ERROR, ERR_BRANCH_EXISTS, ERR_BRANCH_CONFLICT, MEDIA_CATEGORIES, canonicalPath, isHeadingLevel, TinaSchema, addNamespaceToSchema, parseURL, ERR_HAS_REFERENCES, ERR_ALREADY_EXISTS, isValidRelativePath, RELATIVE_PATH_ALLOWED_CHARS_MESSAGE, resolveForm, RELATIVE_PATH_REGEX, normalizePath, ERR_NOT_INDEXED, validateSchema } from "@tinacms/schema-tools";
36
36
  import { NAMER, resolveField } from "@tinacms/schema-tools";
37
37
  import { useBlockSelected, BlockSelectionPlugin } from "@udecode/plate-selection/react";
38
38
  import "@udecode/plate-dnd";
@@ -4136,9 +4136,7 @@ const InnerField = ({
4136
4136
  }
4137
4137
  );
4138
4138
  };
4139
- const FieldsGroup = ({
4140
- children
4141
- }) => {
4139
+ const FieldsGroup = ({ children }) => {
4142
4140
  return /* @__PURE__ */ React.createElement(
4143
4141
  "div",
4144
4142
  {
@@ -5361,6 +5359,7 @@ const Toggle = ({
5361
5359
  disabled = false
5362
5360
  }) => {
5363
5361
  const checked = !!(input.value || input.checked);
5362
+ const inputId = name2 ?? input.name;
5364
5363
  let labels = null;
5365
5364
  if (field.toggleLabels) {
5366
5365
  const fieldLabels = typeof field.toggleLabels === "object" && "true" in field.toggleLabels && "false" in field.toggleLabels && field.toggleLabels;
@@ -5375,7 +5374,7 @@ const Toggle = ({
5375
5374
  className: `text-sm ${!checked ? "text-blue-500 font-bold" : "text-gray-300"}`
5376
5375
  },
5377
5376
  labels.false
5378
- ), /* @__PURE__ */ React.createElement("div", { className: "relative w-12 h-7" }, /* @__PURE__ */ React.createElement(ToggleInput, { id: name2, type: "checkbox", ...input }), /* @__PURE__ */ React.createElement(
5377
+ ), /* @__PURE__ */ React.createElement("div", { className: "relative w-12 h-7" }, /* @__PURE__ */ React.createElement(ToggleInput, { type: "checkbox", ...input, id: inputId }), /* @__PURE__ */ React.createElement(
5379
5378
  "label",
5380
5379
  {
5381
5380
  className: "bg-none p-0 outline-none w-12 h-7",
@@ -5383,7 +5382,7 @@ const Toggle = ({
5383
5382
  opacity: disabled ? 0.4 : 1,
5384
5383
  pointerEvents: disabled ? "none" : "inherit"
5385
5384
  },
5386
- htmlFor: name2,
5385
+ htmlFor: inputId,
5387
5386
  role: "switch"
5388
5387
  },
5389
5388
  /* @__PURE__ */ React.createElement("div", { className: "relative w-[48px] h-7 rounded-3xl bg-white shadow-inner border border-gray-200 pointer-events-none -ml-0.5" }, /* @__PURE__ */ React.createElement(
@@ -5592,34 +5591,30 @@ const CheckboxGroup = ({
5592
5591
  checkboxOptions == null ? void 0 : checkboxOptions.map(toProps2).map(toComponent2)
5593
5592
  );
5594
5593
  };
5595
- const Input$1 = ({ ...props }) => {
5596
- return /* @__PURE__ */ React__default.createElement("input", { className: textFieldClasses, ...props });
5597
- };
5598
- const NumberInput = ({
5599
- onChange,
5600
- value,
5601
- step
5602
- }) => /* @__PURE__ */ React.createElement(
5603
- Input$1,
5604
- {
5605
- type: "number",
5606
- step,
5607
- value,
5608
- onChange: (event) => {
5609
- const inputValue = event.target.value;
5610
- const newValue = inputValue === "" ? void 0 : inputValue;
5611
- if (onChange) {
5612
- const syntheticEvent = {
5613
- ...event,
5614
- target: {
5615
- ...event.target,
5616
- value: newValue
5617
- }
5618
- };
5619
- onChange(syntheticEvent);
5594
+ const Input$1 = React__default.forwardRef((props, ref) => /* @__PURE__ */ React__default.createElement("input", { ref, className: textFieldClasses, ...props }));
5595
+ const NumberInput = React.forwardRef(
5596
+ ({ onChange, ...rest }, ref) => /* @__PURE__ */ React.createElement(
5597
+ Input$1,
5598
+ {
5599
+ ...rest,
5600
+ ref,
5601
+ type: "number",
5602
+ onChange: (event) => {
5603
+ const inputValue = event.target.value;
5604
+ const newValue = inputValue === "" ? void 0 : inputValue;
5605
+ if (onChange) {
5606
+ const syntheticEvent = {
5607
+ ...event,
5608
+ target: {
5609
+ ...event.target,
5610
+ value: newValue
5611
+ }
5612
+ };
5613
+ onChange(syntheticEvent);
5614
+ }
5620
5615
  }
5621
5616
  }
5622
- }
5617
+ )
5623
5618
  );
5624
5619
  const supportedFileTypes = [
5625
5620
  "text/*",
@@ -7563,7 +7558,13 @@ const ImageFieldPlugin = {
7563
7558
  };
7564
7559
  const parse$1 = (value) => value && +value;
7565
7560
  const NumberField = wrapFieldsWithMeta(({ input, field }) => {
7566
- return /* @__PURE__ */ React.createElement(NumberInput, { ...input, step: field.step });
7561
+ const ref = React.useRef(null);
7562
+ React.useEffect(() => {
7563
+ if (ref.current && field.experimental_focusIntent) {
7564
+ ref.current.focus();
7565
+ }
7566
+ }, [field.experimental_focusIntent]);
7567
+ return /* @__PURE__ */ React.createElement(NumberInput, { ...input, ref, step: field.step });
7567
7568
  });
7568
7569
  const NumberFieldPlugin = {
7569
7570
  name: "number",
@@ -8912,6 +8913,20 @@ function useLocalStorage(key, initialValue) {
8912
8913
  };
8913
8914
  return [storedValue, setValue];
8914
8915
  }
8916
+ const EditorialWorkflowErrorBox = ({
8917
+ error
8918
+ }) => /* @__PURE__ */ React__default.createElement("div", { className: "flex items-start gap-1 text-red-700 py-2 px-3 mb-4 bg-red-50 border border-red-200 rounded" }, /* @__PURE__ */ React__default.createElement(CircleAlert, { className: "w-5 h-auto text-red-400 flex-shrink-0" }), /* @__PURE__ */ React__default.createElement("span", { className: "text-sm whitespace-pre-line" }, /* @__PURE__ */ React__default.createElement("b", null, "Error:"), " ", error.messageParts.map(
8919
+ (part, index) => part.emphasis ? /* @__PURE__ */ React__default.createElement("b", { key: index }, part.text) : /* @__PURE__ */ React__default.createElement(React__default.Fragment, { key: index }, part.text)
8920
+ ), error.link && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, " ", /* @__PURE__ */ React__default.createElement(
8921
+ "a",
8922
+ {
8923
+ className: "underline text-tina-orange-dark font-medium",
8924
+ href: error.link.url,
8925
+ target: "_blank",
8926
+ rel: "noreferrer"
8927
+ },
8928
+ error.link.label
8929
+ ))));
8915
8930
  const Badge = ({
8916
8931
  children,
8917
8932
  calloutStyle = "warning",
@@ -10244,8 +10259,10 @@ const EDITORIAL_WORKFLOW_STATUS = {
10244
10259
  const EDITORIAL_WORKFLOW_ERROR = {
10245
10260
  BRANCH_EXISTS: "BRANCH_EXISTS",
10246
10261
  BRANCH_HIERARCHY_CONFLICT: "BRANCH_HIERARCHY_CONFLICT",
10247
- VALIDATION_FAILED: "VALIDATION_FAILED"
10262
+ VALIDATION_FAILED: "VALIDATION_FAILED",
10263
+ INDEXING_FAILED: "INDEXING_FAILED"
10248
10264
  };
10265
+ const EDITORIAL_WORKFLOW_EVENT_LOG_DOCS_URL = "https://tina.io/docs/tinacloud/dashboard/event-log#common-causes";
10249
10266
  const getEditorialWorkflowPrTitle = (branchName) => `${branchName.replace("tina/", "").replaceAll("-", " ")} (PR from TinaCMS)`;
10250
10267
  const TARGET_BRANCH_EXISTS_ERROR = "A branch with this name already exists";
10251
10268
  const checkBranchExists = async (tinaApi, branchName, debugLabel, branchType, fallback, signal) => {
@@ -10301,6 +10318,71 @@ const checkBranchGuard = async (tinaApi, baseBranch, targetBranch, debugLabel, s
10301
10318
  return { baseBranchExists: true, targetBranchExists: false };
10302
10319
  }
10303
10320
  };
10321
+ const plainMessage = (text) => [
10322
+ { text }
10323
+ ];
10324
+ const messageText = (parts) => parts.map((part) => part.text).join("");
10325
+ const pageNameFrom = (file) => {
10326
+ var _a;
10327
+ return ((_a = file.split("/").pop()) == null ? void 0 : _a.replace(/\.[^.]+$/, "")) || file;
10328
+ };
10329
+ const indexingFailureCopy = (file, collectionLabel) => {
10330
+ const subject = file ? `“${pageNameFrom(file)}”` : "your content";
10331
+ const messageParts = [
10332
+ { text: "We couldn't save your changes, because there's a problem with " },
10333
+ { text: subject, emphasis: true },
10334
+ ...collectionLabel ? [{ text: " in " }, { text: collectionLabel, emphasis: true }] : [],
10335
+ { text: ".\n\nFix that page, then save again." }
10336
+ ];
10337
+ return {
10338
+ messageParts,
10339
+ link: {
10340
+ url: EDITORIAL_WORKFLOW_EVENT_LOG_DOCS_URL,
10341
+ label: "How to resolve this"
10342
+ }
10343
+ };
10344
+ };
10345
+ const collectionLabelResolver = (schema) => (file) => {
10346
+ var _a;
10347
+ try {
10348
+ const collection = (_a = schema == null ? void 0 : schema.getCollectionByFullPath) == null ? void 0 : _a.call(schema, file);
10349
+ return (collection == null ? void 0 : collection.label) || (collection == null ? void 0 : collection.name);
10350
+ } catch {
10351
+ return void 0;
10352
+ }
10353
+ };
10354
+ const getEditorialWorkflowError = (e, resolveCollectionLabel) => {
10355
+ let errMessage = "Branch operation failed. Talking to GitHub was unsuccessful, please try again. If the problem persists please contact support at https://tina.io/support 🦙";
10356
+ const err = e;
10357
+ if (err.errorCode) {
10358
+ switch (err.errorCode) {
10359
+ case EDITORIAL_WORKFLOW_ERROR.BRANCH_EXISTS:
10360
+ errMessage = "A branch with this name already exists";
10361
+ break;
10362
+ case EDITORIAL_WORKFLOW_ERROR.BRANCH_HIERARCHY_CONFLICT:
10363
+ errMessage = err.message || "Branch name conflicts with an existing branch";
10364
+ break;
10365
+ case EDITORIAL_WORKFLOW_ERROR.VALIDATION_FAILED:
10366
+ errMessage = err.message || "Invalid branch name";
10367
+ break;
10368
+ case EDITORIAL_WORKFLOW_ERROR.INDEXING_FAILED:
10369
+ return indexingFailureCopy(
10370
+ err.file,
10371
+ err.file ? resolveCollectionLabel == null ? void 0 : resolveCollectionLabel(err.file) : void 0
10372
+ );
10373
+ default:
10374
+ errMessage = err.message || errMessage;
10375
+ break;
10376
+ }
10377
+ } else if (err.message) {
10378
+ if (err.message.toLowerCase().includes(ERR_BRANCH_EXISTS)) {
10379
+ errMessage = "A branch with this name already exists";
10380
+ } else if (err.message.toLowerCase().includes(ERR_BRANCH_CONFLICT)) {
10381
+ errMessage = err.message;
10382
+ }
10383
+ }
10384
+ return { messageParts: plainMessage(errMessage) };
10385
+ };
10304
10386
  const MEDIA_WORKFLOW_STEP = {
10305
10387
  BRANCH: 1,
10306
10388
  CONTENT: 2,
@@ -10604,7 +10686,8 @@ class TinaMediaStore {
10604
10686
  dispatchMediaWorkflowError(err) {
10605
10687
  this.cms.events.dispatch({
10606
10688
  type: "media:workflow:error",
10607
- message: err instanceof Error ? err.message : String(err)
10689
+ message: err instanceof Error ? err.message : String(err),
10690
+ error: err
10608
10691
  });
10609
10692
  }
10610
10693
  async runMediaOpWithWorkflow(decision, op) {
@@ -14222,12 +14305,12 @@ const FormModal = ({ plugin, close: close2 }) => {
14222
14305
  const name = "tinacms";
14223
14306
  const type = "module";
14224
14307
  const typings = "dist/index.d.ts";
14225
- const version = "3.14.0";
14308
+ const version = "3.14.2";
14226
14309
  const main = "dist/index.js";
14227
14310
  const module$1 = "./dist/index.js";
14228
- const exports$1 = { ".": "./dist/index.js", "./dist/client": "./dist/client.js", "./react": "./dist/react.js", "./dist/react": "./dist/react.js", "./tina-field": "./dist/tina-field.js", "./dist/tina-field": "./dist/tina-field.js", "./dist/rich-text": "./dist/rich-text/index.js", "./dist/rich-text/static": "./dist/rich-text/static.js", "./dist/rich-text/prism": "./dist/rich-text/prism.js" };
14311
+ const exports$1 = { ".": "./dist/index.js", "./dist/client": { "types": "./dist/client.d.ts", "browser": "./dist/client.browser.js", "default": "./dist/client.js" }, "./react": "./dist/react.js", "./dist/react": "./dist/react.js", "./tina-field": "./dist/tina-field.js", "./dist/tina-field": "./dist/tina-field.js", "./dist/rich-text": "./dist/rich-text/index.js", "./dist/rich-text/static": "./dist/rich-text/static.js", "./dist/rich-text/prism": "./dist/rich-text/prism.js" };
14229
14312
  const files = ["dist"];
14230
- const buildConfig = { "entryPoints": ["src/index.ts", "src/rich-text/index.tsx", "src/rich-text/static.tsx", "src/rich-text/prism.tsx", "src/react.tsx", "src/tina-field.ts", { "name": "src/client.ts", "target": "node" }] };
14313
+ const buildConfig = { "entryPoints": ["src/index.ts", "src/rich-text/index.tsx", "src/rich-text/static.tsx", "src/rich-text/prism.tsx", "src/react.tsx", "src/tina-field.ts", { "name": "src/client.ts", "target": "node" }, "src/client.browser.ts"] };
14231
14314
  const license = "Apache-2.0";
14232
14315
  const scripts = { "types": "pnpm tsc && pnpm tsc-alias", "build": "tinacms-scripts build", "test": "vitest run", "test-watch": "vitest" };
14233
14316
  const dependencies = { "@ariakit/react": "catalog:", "@dnd-kit/core": "catalog:", "@dnd-kit/sortable": "catalog:", "@dnd-kit/utilities": "catalog:", "@floating-ui/dom": "catalog:", "@floating-ui/react-dom": "catalog:", "@graphql-inspector/core": "^6.2.1", "@radix-ui/react-dialog": "catalog:", "@radix-ui/react-dropdown-menu": "catalog:", "@radix-ui/react-popover": "catalog:", "@radix-ui/react-select": "catalog:", "@radix-ui/react-separator": "catalog:", "@radix-ui/react-slot": "catalog:", "@radix-ui/react-toolbar": "catalog:", "@radix-ui/react-tooltip": "catalog:", "@react-hook/window-size": "catalog:", "@tanstack/react-table": "^8.21.3", "@tinacms/bridge": "workspace:^", "@tinacms/mdx": "workspace:^", "@tinacms/schema-tools": "workspace:^", "@tinacms/search": "workspace:^", "@udecode/cmdk": "catalog:", "@udecode/cn": "catalog:", "@udecode/plate": "catalog:", "@udecode/plate-autoformat": "catalog:", "@udecode/plate-basic-marks": "catalog:", "@udecode/plate-block-quote": "catalog:", "@udecode/plate-break": "catalog:", "@udecode/plate-code-block": "catalog:", "@udecode/plate-combobox": "catalog:", "@udecode/plate-dnd": "catalog:", "@udecode/plate-floating": "catalog:", "@udecode/plate-heading": "catalog:", "@udecode/plate-highlight": "catalog:", "@udecode/plate-horizontal-rule": "catalog:", "@udecode/plate-indent-list": "catalog:", "@udecode/plate-link": "catalog:", "@udecode/plate-list": "catalog:", "@udecode/plate-node-id": "catalog:", "@udecode/plate-reset-node": "catalog:", "@udecode/plate-resizable": "catalog:", "@udecode/plate-selection": "catalog:", "@udecode/plate-slash-command": "catalog:", "@udecode/plate-table": "catalog:", "@udecode/plate-trailing-block": "catalog:", "class-variance-authority": "catalog:", "clsx": "catalog:", "cmdk": "catalog:", "color-string": "catalog:", "date-fns": "4.1.0", "es-toolkit": "^1.42.0", "final-form": "catalog:", "final-form-arrays": "catalog:", "final-form-set-field-data": "catalog:", "graphql": "15.8.0", "graphql-tag": "catalog:", "is-hotkey": "catalog:", "lucide-react": "catalog:", "mermaid": "catalog:", "posthog-js": "^1.347.1", "prism-react-renderer": "catalog:", "prop-types": "catalog:", "react-colorful": "catalog:", "react-day-picker": "^9.13.0", "react-dnd": "catalog:", "react-dnd-html5-backend": "catalog:", "react-dropzone": "catalog:", "react-final-form": "catalog:", "react-router-dom": "catalog:", "react-use": "catalog:", "tailwind-merge": "^2.6.0", "webfontloader": "catalog:", "yup": "^1.6.1", "zod": "catalog:" };
@@ -14257,7 +14340,16 @@ const VersionInfo = () => {
14257
14340
  var _a, _b, _c, _d, _e, _f;
14258
14341
  const cms = useCMS();
14259
14342
  const optOutOfUpdateCheck = (_f = (_e = (_d = (_c = (_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.schema) == null ? void 0 : _c.config) == null ? void 0 : _d.config) == null ? void 0 : _e.ui) == null ? void 0 : _f.optOutOfUpdateCheck;
14260
- return /* @__PURE__ */ React__default.createElement("span", { className: "font-sans font-light text-xs mb-3 mt-4 text-gray-500" }, "TinaCMS v", version + " ", !optOutOfUpdateCheck && /* @__PURE__ */ React__default.createElement(LatestVersionCheck, null));
14343
+ return /* @__PURE__ */ React__default.createElement("span", { className: "font-sans font-light text-xs mb-3 mt-4 text-gray-500" }, "TinaCMS v", version + " ", !optOutOfUpdateCheck && /* @__PURE__ */ React__default.createElement(LatestVersionCheck, null), " ", /* @__PURE__ */ React__default.createElement(
14344
+ "a",
14345
+ {
14346
+ href: "https://tina.io/whats-new/tinacms/",
14347
+ target: "_blank",
14348
+ rel: "noopener noreferrer",
14349
+ className: "text-blue-600 hover:text-blue-400 underline whitespace-nowrap"
14350
+ },
14351
+ "See latest Releases"
14352
+ ));
14261
14353
  };
14262
14354
  const LatestVersionCheck = () => {
14263
14355
  const cms = useCMS();
@@ -17277,39 +17369,12 @@ const formatTime = (seconds) => {
17277
17369
  const secs = seconds % 60;
17278
17370
  return `${mins}:${secs.toString().padStart(2, "0")}`;
17279
17371
  };
17280
- const getEditorialWorkflowErrorMessage = (e) => {
17281
- let errMessage = "Branch operation failed. Talking to GitHub was unsuccessful, please try again. If the problem persists please contact support at https://tina.io/support 🦙";
17282
- const err = e;
17283
- if (err.errorCode) {
17284
- switch (err.errorCode) {
17285
- case EDITORIAL_WORKFLOW_ERROR.BRANCH_EXISTS:
17286
- errMessage = "A branch with this name already exists";
17287
- break;
17288
- case EDITORIAL_WORKFLOW_ERROR.BRANCH_HIERARCHY_CONFLICT:
17289
- errMessage = err.message || "Branch name conflicts with an existing branch";
17290
- break;
17291
- case EDITORIAL_WORKFLOW_ERROR.VALIDATION_FAILED:
17292
- errMessage = err.message || "Invalid branch name";
17293
- break;
17294
- default:
17295
- errMessage = err.message || errMessage;
17296
- break;
17297
- }
17298
- } else if (err.message) {
17299
- if (err.message.toLowerCase().includes(ERR_BRANCH_EXISTS)) {
17300
- errMessage = "A branch with this name already exists";
17301
- } else if (err.message.toLowerCase().includes(ERR_BRANCH_CONFLICT)) {
17302
- errMessage = err.message;
17303
- }
17304
- }
17305
- return errMessage;
17306
- };
17307
17372
  function useEditorialWorkflow() {
17308
17373
  const cms = useCMS$1();
17309
17374
  const tinaApi = cms.api.tina;
17310
17375
  const { setCurrentBranch } = useBranchData();
17311
17376
  const [isExecuting, setIsExecuting] = React.useState(false);
17312
- const [errorMessage, setErrorMessage] = React.useState("");
17377
+ const [error, setError] = React.useState(void 0);
17313
17378
  const [currentStep, setCurrentStep] = React.useState(0);
17314
17379
  const [elapsedTime, setElapsedTime] = React.useState(0);
17315
17380
  React.useEffect(() => {
@@ -17326,7 +17391,7 @@ function useEditorialWorkflow() {
17326
17391
  };
17327
17392
  }, [isExecuting, currentStep]);
17328
17393
  const reset = () => {
17329
- setErrorMessage("");
17394
+ setError(void 0);
17330
17395
  setIsExecuting(false);
17331
17396
  setCurrentStep(0);
17332
17397
  };
@@ -17352,7 +17417,7 @@ function useEditorialWorkflow() {
17352
17417
  );
17353
17418
  if (signal == null ? void 0 : signal.aborted) return { success: false };
17354
17419
  if (targetBranchExists) {
17355
- setErrorMessage(TARGET_BRANCH_EXISTS_ERROR);
17420
+ setError({ messageParts: plainMessage(TARGET_BRANCH_EXISTS_ERROR) });
17356
17421
  setIsExecuting(false);
17357
17422
  setCurrentStep(0);
17358
17423
  return { success: false, error: TARGET_BRANCH_EXISTS_ERROR };
@@ -17430,16 +17495,19 @@ function useEditorialWorkflow() {
17430
17495
  return { success: true };
17431
17496
  } catch (e) {
17432
17497
  console.error(e);
17433
- const errMessage = getEditorialWorkflowErrorMessage(e);
17434
- setErrorMessage(errMessage);
17498
+ const copy = getEditorialWorkflowError(
17499
+ e,
17500
+ collectionLabelResolver(cms.api.tina.schema)
17501
+ );
17502
+ setError(copy);
17435
17503
  setIsExecuting(false);
17436
17504
  setCurrentStep(0);
17437
- return { success: false, error: errMessage };
17505
+ return { success: false, error: messageText(copy.messageParts) };
17438
17506
  }
17439
17507
  };
17440
17508
  return {
17441
17509
  isExecuting,
17442
- errorMessage,
17510
+ error,
17443
17511
  currentStep,
17444
17512
  elapsedTime,
17445
17513
  executeWorkflow,
@@ -17556,7 +17624,7 @@ const CreateBranchModal = ({
17556
17624
  const branchGuardAbortRef = React.useRef(null);
17557
17625
  const {
17558
17626
  isExecuting,
17559
- errorMessage,
17627
+ error,
17560
17628
  currentStep,
17561
17629
  elapsedTime,
17562
17630
  executeWorkflow,
@@ -17598,7 +17666,7 @@ const CreateBranchModal = ({
17598
17666
  return;
17599
17667
  }
17600
17668
  setIsBranchGuardChecking(false);
17601
- const { success, error } = await executeWorkflow({
17669
+ const { success, error: error2 } = await executeWorkflow({
17602
17670
  branchName: targetBranch,
17603
17671
  baseBranch,
17604
17672
  path,
@@ -17616,7 +17684,7 @@ const CreateBranchModal = ({
17616
17684
  captureEvent(EditorialWorkflowSaveEvent, {
17617
17685
  choice: isDraft ? "draft" : "review",
17618
17686
  success,
17619
- error
17687
+ error: error2
17620
17688
  });
17621
17689
  if (success) {
17622
17690
  close2();
@@ -17640,7 +17708,7 @@ const CreateBranchModal = ({
17640
17708
  abortBranchGuard();
17641
17709
  close2();
17642
17710
  },
17643
- errorMessage,
17711
+ error,
17644
17712
  disabled: normalizedBranchName === "" || isBranchGuardChecking,
17645
17713
  onBranchNameChange: (value) => {
17646
17714
  abortBranchGuard();
@@ -17691,7 +17759,7 @@ const CreateBranchPromptModal = ({
17691
17759
  branchName,
17692
17760
  close: close2,
17693
17761
  disabled,
17694
- errorMessage,
17762
+ error,
17695
17763
  onBranchNameChange,
17696
17764
  onCreateBranch,
17697
17765
  onSaveToProtectedBranch,
@@ -17725,7 +17793,7 @@ const CreateBranchPromptModal = ({
17725
17793
  };
17726
17794
  const mainChoice = choices[main2] ?? choices.draft;
17727
17795
  const MainIcon = mainChoice.Icon;
17728
- return /* @__PURE__ */ React.createElement(Modal, { className: "flex" }, /* @__PURE__ */ React.createElement(PopupModal, { className: "w-auto" }, /* @__PURE__ */ React.createElement(ModalHeader, { close: close2 }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between w-full" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center" }, "Save changes to new branch"))), /* @__PURE__ */ React.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React.createElement("div", { className: "max-w-sm" }, errorMessage && /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-1 text-red-700 py-2 px-3 mb-4 bg-red-50 border border-red-200 rounded" }, /* @__PURE__ */ React.createElement(CircleAlert, { className: "w-5 h-auto text-red-400 flex-shrink-0" }), /* @__PURE__ */ React.createElement("span", { className: "text-sm" }, /* @__PURE__ */ React.createElement("b", null, "Error:"), " ", errorMessage)), /* @__PURE__ */ React.createElement("p", { className: "text-lg text-gray-700 font-bold mb-2" }, "First, let's create a copy"), /* @__PURE__ */ React.createElement("p", { className: "text-sm text-gray-700 mb-4 max-w-sm" }, "To make changes, you need to create a copy then get it approved and merged for it to go live.", /* @__PURE__ */ React.createElement("br", null), /* @__PURE__ */ React.createElement("br", null), /* @__PURE__ */ React.createElement("span", { className: "text-gray-500" }, "Learn more about "), /* @__PURE__ */ React.createElement(
17796
+ return /* @__PURE__ */ React.createElement(Modal, { className: "flex" }, /* @__PURE__ */ React.createElement(PopupModal, { className: "w-auto" }, /* @__PURE__ */ React.createElement(ModalHeader, { close: close2 }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between w-full" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center" }, "Save changes to new branch"))), /* @__PURE__ */ React.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React.createElement("div", { className: "max-w-sm" }, error && /* @__PURE__ */ React.createElement(EditorialWorkflowErrorBox, { error }), /* @__PURE__ */ React.createElement("p", { className: "text-lg text-gray-700 font-bold mb-2" }, "First, let's create a copy"), /* @__PURE__ */ React.createElement("p", { className: "text-sm text-gray-700 mb-4 max-w-sm" }, "To make changes, you need to create a copy then get it approved and merged for it to go live.", /* @__PURE__ */ React.createElement("br", null), /* @__PURE__ */ React.createElement("br", null), /* @__PURE__ */ React.createElement("span", { className: "text-gray-500" }, "Learn more about "), /* @__PURE__ */ React.createElement(
17729
17797
  "a",
17730
17798
  {
17731
17799
  className: "underline text-tina-orange-dark font-medium",
@@ -17852,7 +17920,7 @@ const BranchDeletedModal = ({
17852
17920
  const baseBranch = tinaApi.protectedBranches[0] || cms.api.tina.schema.config.config.repoProvider.defaultBranchName || "main";
17853
17921
  const {
17854
17922
  isExecuting,
17855
- errorMessage,
17923
+ error,
17856
17924
  currentStep,
17857
17925
  elapsedTime,
17858
17926
  executeWorkflow,
@@ -17882,7 +17950,7 @@ const BranchDeletedModal = ({
17882
17950
  className: "w-4 h-4 mt-0.5 flex-shrink-0 text-yellow-600",
17883
17951
  style: { fill: "none" }
17884
17952
  }
17885
- ), /* @__PURE__ */ React.createElement("span", null, "The branch", " ", /* @__PURE__ */ React.createElement("span", { className: "font-mono font-semibold" }, branchName), " ", "no longer exists. It may have been merged or deleted. Your changes cannot be pushed to it.")), /* @__PURE__ */ React.createElement("p", { className: "text-sm text-gray-700 mb-4" }, "Create a new branch from", " ", /* @__PURE__ */ React.createElement("span", { className: "font-mono font-semibold" }, baseBranch), " to continue editing, or cancel and switch to an existing branch from the branch menu."), errorMessage && /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-1 text-red-700 py-2 px-3 mb-4 bg-red-50 border border-red-200 rounded" }, /* @__PURE__ */ React.createElement(CircleAlert, { className: "w-5 h-auto text-red-400 flex-shrink-0" }), /* @__PURE__ */ React.createElement("span", { className: "text-sm" }, /* @__PURE__ */ React.createElement("b", null, "Error:"), " ", errorMessage)), /* @__PURE__ */ React.createElement(
17953
+ ), /* @__PURE__ */ React.createElement("span", null, "The branch", " ", /* @__PURE__ */ React.createElement("span", { className: "font-mono font-semibold" }, branchName), " ", "no longer exists. It may have been merged or deleted. Your changes cannot be pushed to it.")), /* @__PURE__ */ React.createElement("p", { className: "text-sm text-gray-700 mb-4" }, "Create a new branch from", " ", /* @__PURE__ */ React.createElement("span", { className: "font-mono font-semibold" }, baseBranch), " to continue editing, or cancel and switch to an existing branch from the branch menu."), error && /* @__PURE__ */ React.createElement(EditorialWorkflowErrorBox, { error }), /* @__PURE__ */ React.createElement(
17886
17954
  PrefixedTextField,
17887
17955
  {
17888
17956
  name: "new-branch-name",
@@ -71665,12 +71733,15 @@ const MediaWorkflowOverlay = () => {
71665
71733
  const offComplete = cms.events.subscribe("media:workflow:complete", (event) => {
71666
71734
  setCurrentBranch(event.branchName);
71667
71735
  });
71668
- const offError = cms.events.subscribe(
71669
- "media:workflow:error",
71670
- (event) => {
71671
- setState({ phase: "error", message: event.message });
71672
- }
71673
- );
71736
+ const offError = cms.events.subscribe("media:workflow:error", (event) => {
71737
+ setState({
71738
+ phase: "error",
71739
+ error: event.error === void 0 ? { messageParts: plainMessage(event.message) } : getEditorialWorkflowError(
71740
+ event.error,
71741
+ collectionLabelResolver(cms.api.tina.schema)
71742
+ )
71743
+ });
71744
+ });
71674
71745
  const offFinish = cms.events.subscribe("media:workflow:finish", () => {
71675
71746
  setState({ phase: "idle" });
71676
71747
  });
@@ -71704,7 +71775,7 @@ const MediaWorkflowOverlay = () => {
71704
71775
  setState({
71705
71776
  ...confirmState,
71706
71777
  isChecking: true,
71707
- errorMessage: ""
71778
+ error: void 0
71708
71779
  });
71709
71780
  const { baseBranchExists, targetBranchExists } = await checkBranchGuard(
71710
71781
  cms.api.tina,
@@ -71722,7 +71793,11 @@ const MediaWorkflowOverlay = () => {
71722
71793
  ...confirmState,
71723
71794
  branchName,
71724
71795
  isChecking: false,
71725
- errorMessage: `The branch ${confirmState.baseBranch} no longer exists. It may have been merged or deleted. Your changes cannot be pushed to it.`
71796
+ error: {
71797
+ messageParts: plainMessage(
71798
+ `The branch ${confirmState.baseBranch} no longer exists. It may have been merged or deleted. Your changes cannot be pushed to it.`
71799
+ )
71800
+ }
71726
71801
  });
71727
71802
  return;
71728
71803
  }
@@ -71734,7 +71809,7 @@ const MediaWorkflowOverlay = () => {
71734
71809
  ...confirmState,
71735
71810
  branchName,
71736
71811
  isChecking: false,
71737
- errorMessage: TARGET_BRANCH_EXISTS_ERROR
71812
+ error: { messageParts: plainMessage(TARGET_BRANCH_EXISTS_ERROR) }
71738
71813
  });
71739
71814
  return;
71740
71815
  }
@@ -71750,7 +71825,10 @@ const MediaWorkflowOverlay = () => {
71750
71825
  ...confirmState,
71751
71826
  branchName,
71752
71827
  isChecking: false,
71753
- errorMessage: getEditorialWorkflowErrorMessage(e)
71828
+ error: getEditorialWorkflowError(
71829
+ e,
71830
+ collectionLabelResolver(cms.api.tina.schema)
71831
+ )
71754
71832
  });
71755
71833
  }
71756
71834
  };
@@ -71766,14 +71844,14 @@ const MediaWorkflowOverlay = () => {
71766
71844
  setState({ phase: "idle" });
71767
71845
  },
71768
71846
  disabled: normalizeBranchName(state.branchName) === "" || state.isChecking,
71769
- errorMessage: state.errorMessage,
71847
+ error: state.error,
71770
71848
  onBranchNameChange: (branchName) => {
71771
71849
  abortPreflight();
71772
71850
  setState(
71773
71851
  (prev) => prev.phase === "confirming" ? {
71774
71852
  ...prev,
71775
71853
  branchName,
71776
- errorMessage: void 0,
71854
+ error: void 0,
71777
71855
  isChecking: false
71778
71856
  } : prev
71779
71857
  );
@@ -71799,7 +71877,7 @@ const MediaWorkflowOverlay = () => {
71799
71877
  );
71800
71878
  }
71801
71879
  const dismissError = () => setState({ phase: "idle" });
71802
- return /* @__PURE__ */ React.createElement(Modal, { className: "flex" }, /* @__PURE__ */ React.createElement(PopupModal, { className: "w-auto" }, /* @__PURE__ */ React.createElement(ModalHeader, { close: dismissError }, "Branch creation failed"), /* @__PURE__ */ React.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-1 text-red-700 py-2 px-3 bg-red-50 border border-red-200 rounded max-w-sm" }, /* @__PURE__ */ React.createElement(CircleAlert, { className: "w-5 h-auto text-red-400 flex-shrink-0" }), /* @__PURE__ */ React.createElement("span", { className: "text-sm" }, /* @__PURE__ */ React.createElement("b", null, "Error:"), " ", state.message)))));
71880
+ return /* @__PURE__ */ React.createElement(Modal, { className: "flex" }, /* @__PURE__ */ React.createElement(PopupModal, { className: "w-auto" }, /* @__PURE__ */ React.createElement(ModalHeader, { close: dismissError }, "Branch creation failed"), /* @__PURE__ */ React.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React.createElement("div", { className: "max-w-sm" }, /* @__PURE__ */ React.createElement(EditorialWorkflowErrorBox, { error: state.error })))));
71803
71881
  };
71804
71882
  function asyncPoll(fn, pollInterval = 5 * 1e3, pollTimeout = 30 * 1e3) {
71805
71883
  const endTime = (/* @__PURE__ */ new Date()).getTime() + pollTimeout;
@@ -71968,6 +72046,7 @@ async function authenticate(clientId, identityApiUrl, frontendUrl) {
71968
72046
  const DefaultSessionProvider = ({
71969
72047
  children
71970
72048
  }) => /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children);
72049
+ const bearerToken = (token) => (token == null ? void 0 : token.id_token) ?? (token == null ? void 0 : token.access_token) ?? null;
71971
72050
  class AbstractAuthProvider {
71972
72051
  constructor() {
71973
72052
  /**
@@ -72003,8 +72082,7 @@ class AbstractAuthProvider {
72003
72082
  return res;
72004
72083
  }
72005
72084
  async getAccessToken() {
72006
- const token = await this.getToken();
72007
- return (token == null ? void 0 : token.access_token) ?? (token == null ? void 0 : token.id_token) ?? null;
72085
+ return bearerToken(await this.getToken());
72008
72086
  }
72009
72087
  async authorize(context) {
72010
72088
  return this.getToken();
@@ -72409,7 +72487,7 @@ mutation addPendingDocumentMutation(
72409
72487
  const headers = {
72410
72488
  "Content-Type": "application/json"
72411
72489
  };
72412
- const accessToken = (token == null ? void 0 : token.id_token) ?? (token == null ? void 0 : token.access_token);
72490
+ const accessToken = bearerToken(token);
72413
72491
  if (accessToken) {
72414
72492
  headers["Authorization"] = "Bearer " + accessToken;
72415
72493
  }
@@ -72755,6 +72833,9 @@ mutation addPendingDocumentMutation(
72755
72833
  statusResponseBody.message || "Editorial workflow failed"
72756
72834
  );
72757
72835
  error.errorCode = statusResponseBody.errorCode || "WORKFLOW_FAILED";
72836
+ if (statusResponseBody.file) {
72837
+ error.file = statusResponseBody.file;
72838
+ }
72758
72839
  throw error;
72759
72840
  }
72760
72841
  if (statusResponse.status === 200) {
@@ -72795,6 +72876,9 @@ mutation addPendingDocumentMutation(
72795
72876
  if (responseBody == null ? void 0 : responseBody.conflictingBranch) {
72796
72877
  error.conflictingBranch = responseBody.conflictingBranch;
72797
72878
  }
72879
+ if (responseBody == null ? void 0 : responseBody.file) {
72880
+ error.file = responseBody.file;
72881
+ }
72798
72882
  return error;
72799
72883
  }
72800
72884
  async postEditorialWorkflow(url, body, errorFallback) {
@@ -74300,9 +74384,7 @@ const PageWrapper = ({
74300
74384
  }) => {
74301
74385
  return /* @__PURE__ */ React__default.createElement("div", { className: "relative left-0 w-full h-full bg-gradient-to-b from-gray-50/50 to-gray-50 overflow-y-auto transition-opacity duration-300 ease-out flex flex-col opacity-100" }, /* @__PURE__ */ React__default.createElement("div", { className: `py-2 w-full ${headerClassName}` }, /* @__PURE__ */ React__default.createElement(BillingWarning, null), /* @__PURE__ */ React__default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React__default.createElement(NavMenuTrigger, { className: "ml-2" }), /* @__PURE__ */ React__default.createElement(TinaIcon, { className: "self-center h-10 min-w-10 w-auto text-orange-500" }), /* @__PURE__ */ React__default.createElement(LocalWarning, null), /* @__PURE__ */ React__default.createElement(BranchButton, null), /* @__PURE__ */ React__default.createElement(BranchPreviewButton, null))), /* @__PURE__ */ React__default.createElement(AnnouncementsBanner, null), children);
74302
74386
  };
74303
- const PageHeader = ({
74304
- children
74305
- }) => {
74387
+ const PageHeader = ({ children }) => {
74306
74388
  return /* @__PURE__ */ React__default.createElement("div", { className: "pt-4 pb-2 px-6" }, /* @__PURE__ */ React__default.createElement("div", { className: "w-full flex justify-between items-end" }, children));
74307
74389
  };
74308
74390
  const PageBody = ({ children }) => /* @__PURE__ */ React__default.createElement("div", { className: "py-4 px-6" }, children);
@@ -0,0 +1,2 @@
1
+ import type { TokenObject } from '@tinacms/schema-tools';
2
+ export declare const bearerToken: (token: TokenObject | null | undefined) => string;
@@ -5,6 +5,4 @@ export interface InputProps {
5
5
  placeholder?: string;
6
6
  step?: string | number;
7
7
  }
8
- export declare const Input: ({ ...props }: {
9
- [x: string]: any;
10
- }) => React.JSX.Element;
8
+ export declare const Input: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
@@ -1,7 +1,5 @@
1
1
  import * as React from 'react';
2
- type a = React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
3
- export interface NumberProps extends a {
2
+ export interface NumberProps extends React.ComponentProps<'input'> {
4
3
  step?: string | number;
5
4
  }
6
- export declare const NumberInput: React.FC<NumberProps>;
7
- export {};
5
+ export declare const NumberInput: React.ForwardRefExoticComponent<Omit<NumberProps, "ref"> & React.RefAttributes<HTMLInputElement>>;
@@ -2,7 +2,7 @@ import { FC } from 'react';
2
2
  import * as React from 'react';
3
3
  import { Field } from '../../forms';
4
4
  export interface ToggleProps {
5
- name: string;
5
+ name?: string;
6
6
  input: any;
7
7
  field: ToggleFieldDefinition;
8
8
  disabled?: boolean;
@@ -10,7 +10,7 @@ export interface ToggleProps {
10
10
  onChange?: <T>(_event: React.ChangeEvent<T> | any) => void;
11
11
  onFocus?: <T>(_event?: React.FocusEvent<T>) => void;
12
12
  }
13
- interface ToggleFieldDefinition extends Field {
13
+ export interface ToggleFieldDefinition extends Field {
14
14
  component: 'toggle';
15
15
  toggleLabels?: boolean | FieldLabels;
16
16
  }
@@ -1,7 +1,7 @@
1
- export declare const ToggleField: (props: import("./wrap-field-with-meta").InputFieldType<import("..").ToggleProps, {}>) => import("react").JSX.Element;
1
+ export declare const ToggleField: (props: import("./wrap-field-with-meta").InputFieldType<import("..").ToggleProps, import("..").ToggleFieldDefinition>) => import("react").JSX.Element;
2
2
  export declare const ToggleFieldPlugin: {
3
3
  name: string;
4
4
  type: string;
5
- Component: (props: import("./wrap-field-with-meta").InputFieldType<import("..").ToggleProps, {}>) => import("react").JSX.Element;
5
+ Component: (props: import("./wrap-field-with-meta").InputFieldType<import("..").ToggleProps, import("..").ToggleFieldDefinition>) => import("react").JSX.Element;
6
6
  validate(value: any, values: any, meta: any, field: any): string;
7
7
  };
@@ -1,5 +1,6 @@
1
1
  import { Form } from '../forms';
2
2
  import * as React from 'react';
3
+ import { type EditorialWorkflowErrorCopy } from './editorial-workflow-utils';
3
4
  import { type SaveChoice } from './save-options';
4
5
  export declare const CreateBranchModal: ({ close, safeSubmit, path, values, crudType, tinaForm, onBaseBranchDeleted, }: {
5
6
  safeSubmit: (editorialWorkflowChoice?: SaveChoice) => Promise<void>;
@@ -10,11 +11,11 @@ export declare const CreateBranchModal: ({ close, safeSubmit, path, values, crud
10
11
  tinaForm?: Form;
11
12
  onBaseBranchDeleted?: () => void;
12
13
  }) => React.JSX.Element;
13
- export declare const CreateBranchPromptModal: ({ branchName, close, disabled, errorMessage, onBranchNameChange, onCreateBranch, onSaveToProtectedBranch, showSaveOptions, disablePublish, allowSaveToProtectedBranch, }: {
14
+ export declare const CreateBranchPromptModal: ({ branchName, close, disabled, error, onBranchNameChange, onCreateBranch, onSaveToProtectedBranch, showSaveOptions, disablePublish, allowSaveToProtectedBranch, }: {
14
15
  branchName: string;
15
16
  close: () => void;
16
17
  disabled?: boolean;
17
- errorMessage?: string;
18
+ error?: EditorialWorkflowErrorCopy;
18
19
  onBranchNameChange: (value: string) => void;
19
20
  onCreateBranch: (isDraft: boolean) => void;
20
21
  onSaveToProtectedBranch: () => void;
@@ -23,6 +23,7 @@ export declare const EDITORIAL_WORKFLOW_ERROR: {
23
23
  readonly BRANCH_EXISTS: "BRANCH_EXISTS";
24
24
  readonly BRANCH_HIERARCHY_CONFLICT: "BRANCH_HIERARCHY_CONFLICT";
25
25
  readonly VALIDATION_FAILED: "VALIDATION_FAILED";
26
+ readonly INDEXING_FAILED: "INDEXING_FAILED";
26
27
  };
27
28
  export type EditorialWorkflowError = (typeof EDITORIAL_WORKFLOW_ERROR)[keyof typeof EDITORIAL_WORKFLOW_ERROR];
28
29
  /**
@@ -31,7 +32,9 @@ export type EditorialWorkflowError = (typeof EDITORIAL_WORKFLOW_ERROR)[keyof typ
31
32
  export type EditorialWorkflowErrorDetails = Error & {
32
33
  errorCode?: string;
33
34
  conflictingBranch?: string;
35
+ file?: string;
34
36
  };
37
+ export declare const EDITORIAL_WORKFLOW_EVENT_LOG_DOCS_URL = "https://tina.io/docs/tinacloud/dashboard/event-log#common-causes";
35
38
  /**
36
39
  * Result from a completed editorial workflow operation
37
40
  */
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import type { EditorialWorkflowErrorCopy } from './editorial-workflow-utils';
3
+ export declare const EditorialWorkflowErrorBox: ({ error, }: {
4
+ error: EditorialWorkflowErrorCopy;
5
+ }) => React.JSX.Element;
@@ -1,3 +1,4 @@
1
+ import { type TinaSchema } from '@tinacms/schema-tools';
1
2
  export interface MediaWorkflowConfirmBranchEvent {
2
3
  type: 'media:workflow:confirm-branch';
3
4
  branchName: string;
@@ -24,3 +25,19 @@ export declare const checkBranchGuard: (tinaApi: {
24
25
  signal?: AbortSignal;
25
26
  }) => Promise<Record<string, boolean>>;
26
27
  }, baseBranch: string, targetBranch: string, debugLabel: string, signal?: AbortSignal) => Promise<BranchGuardResult>;
28
+ export interface EditorialWorkflowErrorLink {
29
+ url: string;
30
+ label: string;
31
+ }
32
+ export interface EditorialWorkflowMessagePart {
33
+ text: string;
34
+ emphasis?: boolean;
35
+ }
36
+ export interface EditorialWorkflowErrorCopy {
37
+ messageParts: EditorialWorkflowMessagePart[];
38
+ link?: EditorialWorkflowErrorLink;
39
+ }
40
+ export declare const plainMessage: (text: string) => EditorialWorkflowMessagePart[];
41
+ export declare const messageText: (parts: EditorialWorkflowMessagePart[]) => string;
42
+ export declare const collectionLabelResolver: (schema?: Pick<TinaSchema, "getCollectionByFullPath">) => (file: string) => string | undefined;
43
+ export declare const getEditorialWorkflowError: (e: unknown, resolveCollectionLabel?: (file: string) => string | undefined) => EditorialWorkflowErrorCopy;
@@ -7,6 +7,6 @@ export interface FieldsBuilderProps {
7
7
  padding?: boolean;
8
8
  }
9
9
  export declare function FieldsBuilder({ form, fields, activeFieldName, padding, }: FieldsBuilderProps): React.JSX.Element;
10
- export declare const FieldsGroup: ({ children, }: {
10
+ export declare const FieldsGroup: ({ children }: {
11
11
  children?: any | any[];
12
12
  }) => React.JSX.Element;
@@ -1,4 +1,6 @@
1
1
  import { Form } from '../forms';
2
+ import { type EditorialWorkflowErrorCopy } from './editorial-workflow-utils';
3
+ export { collectionLabelResolver, getEditorialWorkflowError, plainMessage, } from './editorial-workflow-utils';
2
4
  export declare const WORKFLOW_STEPS: {
3
5
  id: number;
4
6
  name: string;
@@ -18,7 +20,7 @@ export interface ExecuteWorkflowOptions {
18
20
  }
19
21
  export interface UseEditorialWorkflowResult {
20
22
  isExecuting: boolean;
21
- errorMessage: string;
23
+ error?: EditorialWorkflowErrorCopy;
22
24
  currentStep: number;
23
25
  elapsedTime: number;
24
26
  /** Resolves with the outcome; on failure `error` holds the message. */
@@ -29,5 +31,4 @@ export interface UseEditorialWorkflowResult {
29
31
  /** Reset error/executing state so the form can be retried */
30
32
  reset: () => void;
31
33
  }
32
- export declare const getEditorialWorkflowErrorMessage: (e: unknown) => string;
33
34
  export declare function useEditorialWorkflow(): UseEditorialWorkflowResult;
@@ -41,6 +41,7 @@ export declare class TinaClient<GenQueries> {
41
41
  cacheEnabled: boolean;
42
42
  constructor({ token, url, queries, errorPolicy, cacheDir, cache, }: TinaClientArgs<GenQueries>);
43
43
  init(): Promise<void>;
44
+ protected createCache(_dir: string): Promise<Cache | null>;
44
45
  request<DataType extends Record<string, any> = any>({ errorPolicy, ...args }: TinaClientRequestArgs, options: {
45
46
  fetchOptions?: Parameters<typeof fetch>[1];
46
47
  }): Promise<{
package/package.json CHANGED
@@ -2,12 +2,16 @@
2
2
  "name": "tinacms",
3
3
  "type": "module",
4
4
  "typings": "dist/index.d.ts",
5
- "version": "3.14.0",
5
+ "version": "3.14.2",
6
6
  "main": "dist/index.js",
7
7
  "module": "./dist/index.js",
8
8
  "exports": {
9
9
  ".": "./dist/index.js",
10
- "./dist/client": "./dist/client.js",
10
+ "./dist/client": {
11
+ "types": "./dist/client.d.ts",
12
+ "browser": "./dist/client.browser.js",
13
+ "default": "./dist/client.js"
14
+ },
11
15
  "./react": "./dist/react.js",
12
16
  "./dist/react": "./dist/react.js",
13
17
  "./tina-field": "./dist/tina-field.js",
@@ -30,7 +34,8 @@
30
34
  {
31
35
  "name": "src/client.ts",
32
36
  "target": "node"
33
- }
37
+ },
38
+ "src/client.browser.ts"
34
39
  ]
35
40
  },
36
41
  "license": "Apache-2.0",
@@ -105,10 +110,10 @@
105
110
  "webfontloader": "1.6.28",
106
111
  "yup": "^1.6.1",
107
112
  "zod": "^3.24.2",
113
+ "@tinacms/schema-tools": "^2.10.1",
108
114
  "@tinacms/bridge": "^0.3.1",
109
- "@tinacms/mdx": "^2.2.3",
110
- "@tinacms/search": "^1.2.25",
111
- "@tinacms/schema-tools": "^2.10.0"
115
+ "@tinacms/mdx": "^2.3.0",
116
+ "@tinacms/search": "^1.2.25"
112
117
  },
113
118
  "devDependencies": {
114
119
  "@graphql-tools/utils": "^10.8.1",