tinacms 0.0.0-d7c745e-20250102002342 → 0.0.0-de1bef5-20250124020627

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function(global, factory) {
2
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.tinacms = {}));
3
- })(this, function(exports2) {
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("async-lock")) : typeof define === "function" && define.amd ? define(["exports", "async-lock"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.tinacms = {}, global.NOOP));
3
+ })(this, function(exports2, AsyncLock) {
4
4
  "use strict";
5
5
  const TINA_HOST = "content.tinajs.io";
6
6
  class TinaClient {
@@ -26,6 +26,7 @@
26
26
  if (this.cacheDir && typeof window === "undefined" && typeof require !== "undefined") {
27
27
  const { NodeCache: NodeCache2 } = await Promise.resolve().then(() => nodeCache);
28
28
  this.cache = await NodeCache2(this.cacheDir);
29
+ this.cacheLock = new AsyncLock();
29
30
  }
30
31
  } catch (e) {
31
32
  console.error(e);
@@ -62,42 +63,58 @@
62
63
  ...providedFetchOptions
63
64
  };
64
65
  let key = "";
66
+ let result;
65
67
  if (this.cache) {
66
68
  key = this.cache.makeKey(bodyString);
67
- const value = await this.cache.get(key);
68
- if (value) {
69
- return value;
70
- }
71
- }
72
- const res = await fetch(url, optionsObject);
73
- if (!res.ok) {
74
- let additionalInfo = "";
75
- if (res.status === 401) {
76
- additionalInfo = "Please check that your client ID, URL and read only token are configured properly.";
77
- }
78
- throw new Error(
79
- `Server responded with status code ${res.status}, ${res.statusText}. ${additionalInfo ? additionalInfo : ""} Please see our FAQ for more information: https://tina.io/docs/errors/faq/`
80
- );
81
- }
82
- const json = await res.json();
83
- if (json.errors && errorPolicyDefined === "throw") {
84
- throw new Error(
85
- `Unable to fetch, please see our FAQ for more information: https://tina.io/docs/errors/faq/
86
- Errors:
87
- ${json.errors.map((error) => error.message).join("\n")}`
69
+ await this.cacheLock.acquire(key, async () => {
70
+ result = await this.cache.get(key);
71
+ if (!result) {
72
+ result = await requestFromServer(
73
+ url,
74
+ args.query,
75
+ optionsObject,
76
+ errorPolicyDefined
77
+ );
78
+ await this.cache.set(key, result);
79
+ }
80
+ });
81
+ } else {
82
+ result = await requestFromServer(
83
+ url,
84
+ args.query,
85
+ optionsObject,
86
+ errorPolicyDefined
88
87
  );
89
88
  }
90
- const result = {
91
- data: json == null ? void 0 : json.data,
92
- errors: (json == null ? void 0 : json.errors) || null,
93
- query: args.query
94
- };
95
- if (this.cache) {
96
- await this.cache.set(key, result);
97
- }
98
89
  return result;
99
90
  }
100
91
  }
92
+ async function requestFromServer(url, query, optionsObject, errorPolicyDefined) {
93
+ const res = await fetch(url, optionsObject);
94
+ if (!res.ok) {
95
+ let additionalInfo = "";
96
+ if (res.status === 401) {
97
+ additionalInfo = "Please check that your client ID, URL and read only token are configured properly.";
98
+ }
99
+ throw new Error(
100
+ `Server responded with status code ${res.status}, ${res.statusText}. ${additionalInfo ? additionalInfo : ""} Please see our FAQ for more information: https://tina.io/docs/errors/faq/`
101
+ );
102
+ }
103
+ const json = await res.json();
104
+ if (json.errors && errorPolicyDefined === "throw") {
105
+ throw new Error(
106
+ `Unable to fetch, please see our FAQ for more information: https://tina.io/docs/errors/faq/
107
+ Errors:
108
+ ${json.errors.map((error) => error.message).join("\n")}`
109
+ );
110
+ }
111
+ const result = {
112
+ data: json == null ? void 0 : json.data,
113
+ errors: (json == null ? void 0 : json.errors) || null,
114
+ query
115
+ };
116
+ return result;
117
+ }
101
118
  function createClient(args) {
102
119
  const client = new TinaClient(args);
103
120
  return client;
@@ -129,22 +146,35 @@
129
146
  return createHash("sha256").update(input).digest("hex");
130
147
  },
131
148
  get: async (key) => {
149
+ let readValue;
150
+ const cacheFilename = `${cacheDir}/${key}`;
132
151
  try {
133
- const data = await fs.promises.readFile(`${cacheDir}/${key}`, "utf-8");
134
- return JSON.parse(data);
152
+ const data = await fs.promises.readFile(cacheFilename, "utf-8");
153
+ readValue = JSON.parse(data);
135
154
  } catch (e) {
136
- if (e.code === "ENOENT") {
137
- return void 0;
155
+ if (e.code !== "ENOENT") {
156
+ console.error(
157
+ `Failed to read cache file to ${cacheFilename}: ${e.message}`
158
+ );
138
159
  }
139
- throw e;
140
160
  }
161
+ return readValue;
141
162
  },
142
163
  set: async (key, value) => {
143
- await fs.promises.writeFile(
144
- `${cacheDir}/${key}`,
145
- JSON.stringify(value),
146
- "utf-8"
147
- );
164
+ const cacheFilename = `${cacheDir}/${key}`;
165
+ try {
166
+ await fs.promises.writeFile(cacheFilename, JSON.stringify(value), {
167
+ encoding: "utf-8",
168
+ flag: "wx"
169
+ // Don't overwrite existing caches
170
+ });
171
+ } catch (e) {
172
+ if (e.code !== "EEXIST") {
173
+ console.error(
174
+ `Failed to write cache file to ${cacheFilename}: ${e.message}`
175
+ );
176
+ }
177
+ }
148
178
  }
149
179
  };
150
180
  };
package/dist/client.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import AsyncLock from "async-lock";
1
2
  const TINA_HOST = "content.tinajs.io";
2
3
  class TinaClient {
3
4
  constructor({
@@ -20,8 +21,9 @@ class TinaClient {
20
21
  }
21
22
  try {
22
23
  if (this.cacheDir && typeof window === "undefined" && typeof require !== "undefined") {
23
- const { NodeCache } = await import("./node-cache-4c336858.mjs");
24
+ const { NodeCache } = await import("./node-cache-5e8db9f0.mjs");
24
25
  this.cache = await NodeCache(this.cacheDir);
26
+ this.cacheLock = new AsyncLock();
25
27
  }
26
28
  } catch (e) {
27
29
  console.error(e);
@@ -58,42 +60,58 @@ class TinaClient {
58
60
  ...providedFetchOptions
59
61
  };
60
62
  let key = "";
63
+ let result;
61
64
  if (this.cache) {
62
65
  key = this.cache.makeKey(bodyString);
63
- const value = await this.cache.get(key);
64
- if (value) {
65
- return value;
66
- }
67
- }
68
- const res = await fetch(url, optionsObject);
69
- if (!res.ok) {
70
- let additionalInfo = "";
71
- if (res.status === 401) {
72
- additionalInfo = "Please check that your client ID, URL and read only token are configured properly.";
73
- }
74
- throw new Error(
75
- `Server responded with status code ${res.status}, ${res.statusText}. ${additionalInfo ? additionalInfo : ""} Please see our FAQ for more information: https://tina.io/docs/errors/faq/`
66
+ await this.cacheLock.acquire(key, async () => {
67
+ result = await this.cache.get(key);
68
+ if (!result) {
69
+ result = await requestFromServer(
70
+ url,
71
+ args.query,
72
+ optionsObject,
73
+ errorPolicyDefined
74
+ );
75
+ await this.cache.set(key, result);
76
+ }
77
+ });
78
+ } else {
79
+ result = await requestFromServer(
80
+ url,
81
+ args.query,
82
+ optionsObject,
83
+ errorPolicyDefined
76
84
  );
77
85
  }
78
- const json = await res.json();
79
- if (json.errors && errorPolicyDefined === "throw") {
80
- throw new Error(
81
- `Unable to fetch, please see our FAQ for more information: https://tina.io/docs/errors/faq/
82
- Errors:
83
- ${json.errors.map((error) => error.message).join("\n")}`
84
- );
85
- }
86
- const result = {
87
- data: json == null ? void 0 : json.data,
88
- errors: (json == null ? void 0 : json.errors) || null,
89
- query: args.query
90
- };
91
- if (this.cache) {
92
- await this.cache.set(key, result);
93
- }
94
86
  return result;
95
87
  }
96
88
  }
89
+ async function requestFromServer(url, query, optionsObject, errorPolicyDefined) {
90
+ const res = await fetch(url, optionsObject);
91
+ if (!res.ok) {
92
+ let additionalInfo = "";
93
+ if (res.status === 401) {
94
+ additionalInfo = "Please check that your client ID, URL and read only token are configured properly.";
95
+ }
96
+ throw new Error(
97
+ `Server responded with status code ${res.status}, ${res.statusText}. ${additionalInfo ? additionalInfo : ""} Please see our FAQ for more information: https://tina.io/docs/errors/faq/`
98
+ );
99
+ }
100
+ const json = await res.json();
101
+ if (json.errors && errorPolicyDefined === "throw") {
102
+ throw new Error(
103
+ `Unable to fetch, please see our FAQ for more information: https://tina.io/docs/errors/faq/
104
+ Errors:
105
+ ${json.errors.map((error) => error.message).join("\n")}`
106
+ );
107
+ }
108
+ const result = {
109
+ data: json == null ? void 0 : json.data,
110
+ errors: (json == null ? void 0 : json.errors) || null,
111
+ query
112
+ };
113
+ return result;
114
+ }
97
115
  function createClient(args) {
98
116
  const client = new TinaClient(args);
99
117
  return client;
package/dist/index.js CHANGED
@@ -9300,6 +9300,20 @@ flowchart TD
9300
9300
  }
9301
9301
  }
9302
9302
  }
9303
+ const encodeUrlIfNeeded = (url) => {
9304
+ if (url) {
9305
+ try {
9306
+ const parsed = new URL(url);
9307
+ parsed.pathname = parsed.pathname.split("/").filter((part) => part !== "").map(encodeURIComponent).join("/");
9308
+ return parsed.toString();
9309
+ } catch (e) {
9310
+ console.error("Failed to parse URL:", e);
9311
+ return url;
9312
+ }
9313
+ } else {
9314
+ return url;
9315
+ }
9316
+ };
9303
9317
  let MediaManager$1 = class MediaManager {
9304
9318
  constructor(store, events) {
9305
9319
  this.store = store;
@@ -9372,6 +9386,20 @@ flowchart TD
9372
9386
  try {
9373
9387
  this.events.dispatch({ type: "media:list:start", ...options });
9374
9388
  const media = await this.store.list(options);
9389
+ media.items = media.items.map((item) => {
9390
+ if (item.type === "dir") {
9391
+ return item;
9392
+ }
9393
+ if (item.thumbnails) {
9394
+ for (const [size, src] of Object.entries(item.thumbnails)) {
9395
+ item.thumbnails[size] = encodeUrlIfNeeded(src);
9396
+ }
9397
+ }
9398
+ return {
9399
+ ...item,
9400
+ src: encodeUrlIfNeeded(item.src)
9401
+ };
9402
+ });
9375
9403
  this.events.dispatch({ type: "media:list:success", ...options, media });
9376
9404
  return media;
9377
9405
  } catch (error) {
@@ -10179,7 +10207,7 @@ flowchart TD
10179
10207
  "Event Log"
10180
10208
  ));
10181
10209
  };
10182
- const version = "2.5.2";
10210
+ const version = "2.6.1";
10183
10211
  const Nav = ({
10184
10212
  isLocalMode,
10185
10213
  className = "",
@@ -14585,7 +14613,12 @@ flowchart TD
14585
14613
  const [itemsShown, setItemsShown] = React.useState(11);
14586
14614
  const { overrides, templates } = useToolbarContext();
14587
14615
  const showEmbedButton = templates.length > 0;
14588
- let items2 = overrides === void 0 ? Object.values(toolbarItems) : overrides.map((item) => toolbarItems[item]).filter((item) => item !== void 0);
14616
+ let items2 = [];
14617
+ if (Array.isArray(overrides)) {
14618
+ items2 = overrides === void 0 ? Object.values(toolbarItems) : overrides.map((item) => toolbarItems[item]).filter((item) => item !== void 0);
14619
+ } else {
14620
+ items2 = (overrides == null ? void 0 : overrides.toolbar) === void 0 ? Object.values(toolbarItems) : overrides.toolbar.map((item) => toolbarItems[item]).filter((item) => item !== void 0);
14621
+ }
14589
14622
  if (!showEmbedButton) {
14590
14623
  items2 = items2.filter((item) => item.label !== toolbarItems.embed.label);
14591
14624
  }
@@ -14913,6 +14946,9 @@ flowchart TD
14913
14946
  if (typeof string !== "string") {
14914
14947
  return false;
14915
14948
  }
14949
+ if (string.startsWith("#")) {
14950
+ return true;
14951
+ }
14916
14952
  const generalMatch = string.match(protocolAndDomainRE);
14917
14953
  const emailLinkMatch = string.match(emailLintRE);
14918
14954
  const localUrlMatch = string.match(localUrlRE);
@@ -14934,12 +14970,12 @@ flowchart TD
14934
14970
  }
14935
14971
  return localhostDomainRE.test(everythingAfterProtocol) || nonLocalhostDomainRE.test(everythingAfterProtocol);
14936
14972
  };
14937
- const RichEditor = (props) => {
14973
+ const RichEditor = ({ input, tinaForm, field }) => {
14938
14974
  var _a;
14939
14975
  const initialValue = React.useMemo(
14940
14976
  () => {
14941
14977
  var _a2, _b;
14942
- return ((_b = (_a2 = props.input.value) == null ? void 0 : _a2.children) == null ? void 0 : _b.length) ? props.input.value.children.map(helpers.normalize) : [{ type: "p", children: [{ type: "text", text: "" }] }];
14978
+ return ((_b = (_a2 = input.value) == null ? void 0 : _a2.children) == null ? void 0 : _b.length) ? input.value.children.map(helpers.normalize) : [{ type: "p", children: [{ type: "text", text: "" }] }];
14943
14979
  },
14944
14980
  []
14945
14981
  );
@@ -14967,7 +15003,7 @@ flowchart TD
14967
15003
  ),
14968
15004
  []
14969
15005
  );
14970
- const tempId = [props.tinaForm.id, props.input.name].join(".");
15006
+ const tempId = [tinaForm.id, input.name].join(".");
14971
15007
  const id = React.useMemo(() => uuid() + tempId, [tempId]);
14972
15008
  const ref = React.useRef(null);
14973
15009
  React.useEffect(() => {
@@ -14977,13 +15013,13 @@ flowchart TD
14977
15013
  const plateElement = (_a2 = ref.current) == null ? void 0 : _a2.querySelector(
14978
15014
  '[role="textbox"]'
14979
15015
  );
14980
- if (props.field.experimental_focusIntent && plateElement) {
15016
+ if (field.experimental_focusIntent && plateElement) {
14981
15017
  if (plateElement)
14982
15018
  plateElement.focus();
14983
15019
  }
14984
15020
  }, 100);
14985
15021
  }
14986
- }, [props.field.experimental_focusIntent, ref]);
15022
+ }, [field.experimental_focusIntent, ref]);
14987
15023
  return /* @__PURE__ */ React.createElement("div", { ref }, /* @__PURE__ */ React.createElement(
14988
15024
  plateCommon.Plate,
14989
15025
  {
@@ -14991,7 +15027,7 @@ flowchart TD
14991
15027
  initialValue,
14992
15028
  plugins: plugins$2,
14993
15029
  onChange: (value) => {
14994
- props.input.onChange({
15030
+ input.onChange({
14995
15031
  type: "root",
14996
15032
  children: value
14997
15033
  });
@@ -15000,12 +15036,12 @@ flowchart TD
15000
15036
  /* @__PURE__ */ React.createElement(TooltipProvider, null, /* @__PURE__ */ React.createElement(
15001
15037
  ToolbarProvider,
15002
15038
  {
15003
- tinaForm: props.tinaForm,
15004
- templates: props.field.templates,
15005
- overrides: (_a = props.field) == null ? void 0 : _a.toolbarOverride
15039
+ tinaForm,
15040
+ templates: field.templates,
15041
+ overrides: (field == null ? void 0 : field.toolbarOverride) ? field.toolbarOverride : field.overrides
15006
15042
  },
15007
15043
  /* @__PURE__ */ React.createElement(FixedToolbar, null, /* @__PURE__ */ React.createElement(FixedToolbarButtons, null)),
15008
- /* @__PURE__ */ React.createElement(FloatingToolbar, null, /* @__PURE__ */ React.createElement(FloatingToolbarButtons, null))
15044
+ ((_a = field == null ? void 0 : field.overrides) == null ? void 0 : _a.showFloatingToolbar) !== false ? /* @__PURE__ */ React.createElement(FloatingToolbar, null, /* @__PURE__ */ React.createElement(FloatingToolbarButtons, null)) : null
15009
15045
  ), /* @__PURE__ */ React.createElement(Editor, null))
15010
15046
  ));
15011
15047
  };
package/dist/index.mjs CHANGED
@@ -9327,6 +9327,20 @@ class TinaMediaStore {
9327
9327
  }
9328
9328
  }
9329
9329
  }
9330
+ const encodeUrlIfNeeded = (url) => {
9331
+ if (url) {
9332
+ try {
9333
+ const parsed = new URL(url);
9334
+ parsed.pathname = parsed.pathname.split("/").filter((part) => part !== "").map(encodeURIComponent).join("/");
9335
+ return parsed.toString();
9336
+ } catch (e) {
9337
+ console.error("Failed to parse URL:", e);
9338
+ return url;
9339
+ }
9340
+ } else {
9341
+ return url;
9342
+ }
9343
+ };
9330
9344
  let MediaManager$1 = class MediaManager {
9331
9345
  constructor(store, events) {
9332
9346
  this.store = store;
@@ -9399,6 +9413,20 @@ let MediaManager$1 = class MediaManager {
9399
9413
  try {
9400
9414
  this.events.dispatch({ type: "media:list:start", ...options });
9401
9415
  const media = await this.store.list(options);
9416
+ media.items = media.items.map((item) => {
9417
+ if (item.type === "dir") {
9418
+ return item;
9419
+ }
9420
+ if (item.thumbnails) {
9421
+ for (const [size, src] of Object.entries(item.thumbnails)) {
9422
+ item.thumbnails[size] = encodeUrlIfNeeded(src);
9423
+ }
9424
+ }
9425
+ return {
9426
+ ...item,
9427
+ src: encodeUrlIfNeeded(item.src)
9428
+ };
9429
+ });
9402
9430
  this.events.dispatch({ type: "media:list:success", ...options, media });
9403
9431
  return media;
9404
9432
  } catch (error) {
@@ -10206,7 +10234,7 @@ const SyncStatus = ({ cms, setEventsOpen }) => {
10206
10234
  "Event Log"
10207
10235
  ));
10208
10236
  };
10209
- const version = "2.5.2";
10237
+ const version = "2.6.1";
10210
10238
  const Nav = ({
10211
10239
  isLocalMode,
10212
10240
  className = "",
@@ -14612,7 +14640,12 @@ function FixedToolbarButtons() {
14612
14640
  const [itemsShown, setItemsShown] = React__default.useState(11);
14613
14641
  const { overrides, templates } = useToolbarContext();
14614
14642
  const showEmbedButton = templates.length > 0;
14615
- let items2 = overrides === void 0 ? Object.values(toolbarItems) : overrides.map((item) => toolbarItems[item]).filter((item) => item !== void 0);
14643
+ let items2 = [];
14644
+ if (Array.isArray(overrides)) {
14645
+ items2 = overrides === void 0 ? Object.values(toolbarItems) : overrides.map((item) => toolbarItems[item]).filter((item) => item !== void 0);
14646
+ } else {
14647
+ items2 = (overrides == null ? void 0 : overrides.toolbar) === void 0 ? Object.values(toolbarItems) : overrides.toolbar.map((item) => toolbarItems[item]).filter((item) => item !== void 0);
14648
+ }
14616
14649
  if (!showEmbedButton) {
14617
14650
  items2 = items2.filter((item) => item.label !== toolbarItems.embed.label);
14618
14651
  }
@@ -14940,6 +14973,9 @@ const isUrl = (string) => {
14940
14973
  if (typeof string !== "string") {
14941
14974
  return false;
14942
14975
  }
14976
+ if (string.startsWith("#")) {
14977
+ return true;
14978
+ }
14943
14979
  const generalMatch = string.match(protocolAndDomainRE);
14944
14980
  const emailLinkMatch = string.match(emailLintRE);
14945
14981
  const localUrlMatch = string.match(localUrlRE);
@@ -14961,12 +14997,12 @@ const isUrl = (string) => {
14961
14997
  }
14962
14998
  return localhostDomainRE.test(everythingAfterProtocol) || nonLocalhostDomainRE.test(everythingAfterProtocol);
14963
14999
  };
14964
- const RichEditor = (props) => {
15000
+ const RichEditor = ({ input, tinaForm, field }) => {
14965
15001
  var _a;
14966
15002
  const initialValue = React__default.useMemo(
14967
15003
  () => {
14968
15004
  var _a2, _b;
14969
- return ((_b = (_a2 = props.input.value) == null ? void 0 : _a2.children) == null ? void 0 : _b.length) ? props.input.value.children.map(helpers.normalize) : [{ type: "p", children: [{ type: "text", text: "" }] }];
15005
+ return ((_b = (_a2 = input.value) == null ? void 0 : _a2.children) == null ? void 0 : _b.length) ? input.value.children.map(helpers.normalize) : [{ type: "p", children: [{ type: "text", text: "" }] }];
14970
15006
  },
14971
15007
  []
14972
15008
  );
@@ -14994,7 +15030,7 @@ const RichEditor = (props) => {
14994
15030
  ),
14995
15031
  []
14996
15032
  );
14997
- const tempId = [props.tinaForm.id, props.input.name].join(".");
15033
+ const tempId = [tinaForm.id, input.name].join(".");
14998
15034
  const id = React__default.useMemo(() => uuid() + tempId, [tempId]);
14999
15035
  const ref = React__default.useRef(null);
15000
15036
  React__default.useEffect(() => {
@@ -15004,13 +15040,13 @@ const RichEditor = (props) => {
15004
15040
  const plateElement = (_a2 = ref.current) == null ? void 0 : _a2.querySelector(
15005
15041
  '[role="textbox"]'
15006
15042
  );
15007
- if (props.field.experimental_focusIntent && plateElement) {
15043
+ if (field.experimental_focusIntent && plateElement) {
15008
15044
  if (plateElement)
15009
15045
  plateElement.focus();
15010
15046
  }
15011
15047
  }, 100);
15012
15048
  }
15013
- }, [props.field.experimental_focusIntent, ref]);
15049
+ }, [field.experimental_focusIntent, ref]);
15014
15050
  return /* @__PURE__ */ React__default.createElement("div", { ref }, /* @__PURE__ */ React__default.createElement(
15015
15051
  Plate,
15016
15052
  {
@@ -15018,7 +15054,7 @@ const RichEditor = (props) => {
15018
15054
  initialValue,
15019
15055
  plugins: plugins$2,
15020
15056
  onChange: (value) => {
15021
- props.input.onChange({
15057
+ input.onChange({
15022
15058
  type: "root",
15023
15059
  children: value
15024
15060
  });
@@ -15027,12 +15063,12 @@ const RichEditor = (props) => {
15027
15063
  /* @__PURE__ */ React__default.createElement(TooltipProvider, null, /* @__PURE__ */ React__default.createElement(
15028
15064
  ToolbarProvider,
15029
15065
  {
15030
- tinaForm: props.tinaForm,
15031
- templates: props.field.templates,
15032
- overrides: (_a = props.field) == null ? void 0 : _a.toolbarOverride
15066
+ tinaForm,
15067
+ templates: field.templates,
15068
+ overrides: (field == null ? void 0 : field.toolbarOverride) ? field.toolbarOverride : field.overrides
15033
15069
  },
15034
15070
  /* @__PURE__ */ React__default.createElement(FixedToolbar, null, /* @__PURE__ */ React__default.createElement(FixedToolbarButtons, null)),
15035
- /* @__PURE__ */ React__default.createElement(FloatingToolbar, null, /* @__PURE__ */ React__default.createElement(FloatingToolbarButtons, null))
15071
+ ((_a = field == null ? void 0 : field.overrides) == null ? void 0 : _a.showFloatingToolbar) !== false ? /* @__PURE__ */ React__default.createElement(FloatingToolbar, null, /* @__PURE__ */ React__default.createElement(FloatingToolbarButtons, null)) : null
15036
15072
  ), /* @__PURE__ */ React__default.createElement(Editor, null))
15037
15073
  ));
15038
15074
  };
@@ -25,22 +25,35 @@ const NodeCache = async (dir) => {
25
25
  return createHash("sha256").update(input).digest("hex");
26
26
  },
27
27
  get: async (key) => {
28
+ let readValue;
29
+ const cacheFilename = `${cacheDir}/${key}`;
28
30
  try {
29
- const data = await fs.promises.readFile(`${cacheDir}/${key}`, "utf-8");
30
- return JSON.parse(data);
31
+ const data = await fs.promises.readFile(cacheFilename, "utf-8");
32
+ readValue = JSON.parse(data);
31
33
  } catch (e) {
32
- if (e.code === "ENOENT") {
33
- return void 0;
34
+ if (e.code !== "ENOENT") {
35
+ console.error(
36
+ `Failed to read cache file to ${cacheFilename}: ${e.message}`
37
+ );
34
38
  }
35
- throw e;
36
39
  }
40
+ return readValue;
37
41
  },
38
42
  set: async (key, value) => {
39
- await fs.promises.writeFile(
40
- `${cacheDir}/${key}`,
41
- JSON.stringify(value),
42
- "utf-8"
43
- );
43
+ const cacheFilename = `${cacheDir}/${key}`;
44
+ try {
45
+ await fs.promises.writeFile(cacheFilename, JSON.stringify(value), {
46
+ encoding: "utf-8",
47
+ flag: "wx"
48
+ // Don't overwrite existing caches
49
+ });
50
+ } catch (e) {
51
+ if (e.code !== "EEXIST") {
52
+ console.error(
53
+ `Failed to write cache file to ${cacheFilename}: ${e.message}`
54
+ );
55
+ }
56
+ }
44
57
  }
45
58
  };
46
59
  };
@@ -2,16 +2,18 @@ import React from 'react';
2
2
  import { type InputFieldType } from '../wrap-field-with-meta';
3
3
  import type { MdxTemplate } from './plate/types';
4
4
  import type { InputProps } from '../../../fields/components';
5
- import type { ToolbarOverrideType } from './plate/toolbar/toolbar-overrides';
5
+ import type { ToolbarOverrides, ToolbarOverrideType } from './plate/toolbar/toolbar-overrides';
6
6
  export type RichTextType = React.PropsWithChildren<InputFieldType<InputProps, {
7
7
  templates: MdxTemplate[];
8
8
  toolbarOverride?: ToolbarOverrideType[];
9
+ overrides?: ToolbarOverrides;
9
10
  }>>;
10
11
  export declare const MdxFieldPlugin: {
11
12
  name: string;
12
13
  Component: (props: InputFieldType<InputProps, {
13
14
  templates: MdxTemplate[];
14
15
  toolbarOverride?: ToolbarOverrideType[];
16
+ overrides?: ToolbarOverrides;
15
17
  }>) => React.JSX.Element;
16
18
  };
17
19
  export declare const MdxFieldPluginExtendible: {
@@ -20,5 +22,6 @@ export declare const MdxFieldPluginExtendible: {
20
22
  Component: (props: InputFieldType<InputProps, {
21
23
  templates: MdxTemplate[];
22
24
  toolbarOverride?: ToolbarOverrideType[];
25
+ overrides?: ToolbarOverrides;
23
26
  }>) => React.JSX.Element;
24
27
  };
@@ -1,3 +1,3 @@
1
1
  import React from 'react';
2
2
  import type { RichTextType } from '..';
3
- export declare const RichEditor: (props: RichTextType) => React.JSX.Element;
3
+ export declare const RichEditor: ({ input, tinaForm, field }: RichTextType) => React.JSX.Element;
@@ -6,3 +6,7 @@ export declare const EMBED_ICON_WIDTH = 78;
6
6
  export declare const CONTAINER_MD_BREAKPOINT = 448;
7
7
  export declare const FLOAT_BUTTON_WIDTH = 25;
8
8
  export declare const HEADING_LABEL = "Headings";
9
+ export type ToolbarOverrides = {
10
+ toolbar?: ToolbarOverrideType[];
11
+ showFloatingToolbar?: boolean;
12
+ };
@@ -2,11 +2,11 @@ import React from 'react';
2
2
  import { type ReactNode } from 'react';
3
3
  import type { Form } from '../../../../../forms';
4
4
  import type { MdxTemplate } from '../types';
5
- import type { ToolbarOverrideType } from './toolbar-overrides';
5
+ import type { ToolbarOverrides, ToolbarOverrideType } from './toolbar-overrides';
6
6
  interface ToolbarContextProps {
7
7
  tinaForm: Form;
8
8
  templates: MdxTemplate[];
9
- overrides: ToolbarOverrideType[];
9
+ overrides: ToolbarOverrideType[] | ToolbarOverrides;
10
10
  }
11
11
  interface ToolbarProviderProps extends ToolbarContextProps {
12
12
  children: ReactNode;
@@ -1,3 +1,5 @@
1
+ import AsyncLock from 'async-lock';
2
+ import type { GraphQLError } from 'graphql';
1
3
  import type { Config } from '@tinacms/schema-tools';
2
4
  import type { Cache } from '../cache/index';
3
5
  export declare const TINA_HOST = "content.tinajs.io";
@@ -25,12 +27,17 @@ export declare class TinaClient<GenQueries> {
25
27
  queries: GenQueries;
26
28
  errorPolicy: Config['client']['errorPolicy'];
27
29
  initialized: boolean;
30
+ cacheLock: AsyncLock | undefined;
28
31
  cacheDir: string;
29
32
  cache: Cache;
30
33
  constructor({ token, url, queries, errorPolicy, cacheDir, }: TinaClientArgs<GenQueries>);
31
34
  init(): Promise<void>;
32
35
  request<DataType extends Record<string, any> = any>({ errorPolicy, ...args }: TinaClientRequestArgs, options: {
33
36
  fetchOptions?: Parameters<typeof fetch>[1];
34
- }): Promise<any>;
37
+ }): Promise<{
38
+ data: DataType;
39
+ errors: GraphQLError[] | null;
40
+ query: string;
41
+ }>;
35
42
  }
36
43
  export declare function createClient<GenQueries>(args: TinaClientArgs<GenQueries>): TinaClient<GenQueries>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tinacms",
3
- "version": "0.0.0-d7c745e-20250102002342",
3
+ "version": "0.0.0-de1bef5-20250124020627",
4
4
  "main": "dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "exports": {
@@ -92,6 +92,7 @@
92
92
  "@udecode/plate-resizable": "36.0.0",
93
93
  "@udecode/plate-slash-command": "^36.0.0",
94
94
  "@udecode/plate-table": "36.5.8",
95
+ "async-lock": "^1.4.1",
95
96
  "class-variance-authority": "^0.7.0",
96
97
  "clsx": "^2.1.1",
97
98
  "cmdk": "^1.0.4",
@@ -128,9 +129,9 @@
128
129
  "webfontloader": "1.6.28",
129
130
  "yup": "^1.4.0",
130
131
  "zod": "^3.23.8",
131
- "@tinacms/mdx": "0.0.0-d7c745e-20250102002342",
132
- "@tinacms/schema-tools": "1.6.9",
133
- "@tinacms/search": "0.0.0-d7c745e-20250102002342"
132
+ "@tinacms/mdx": "1.5.4",
133
+ "@tinacms/schema-tools": "1.7.0",
134
+ "@tinacms/search": "1.0.37"
134
135
  },
135
136
  "devDependencies": {
136
137
  "@graphql-tools/utils": "^10.5.6",