tinacms 1.5.22 → 1.5.24

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/index.mjs CHANGED
@@ -24,11 +24,12 @@ import * as pkg$1 from "react-color";
24
24
  import * as pkg from "color-string";
25
25
  import * as dropzone from "react-dropzone";
26
26
  import { EditContext, useEditState, setEditing } from "@tinacms/sharedctx";
27
- import { isHotkey } from "is-hotkey";
28
- import { computePosition, flip, shift } from "@floating-ui/dom";
27
+ import get from "lodash.get";
29
28
  import moment from "moment";
30
29
  import { formatDistanceToNow } from "date-fns";
31
30
  import { useWindowWidth } from "@react-hook/window-size";
31
+ import { isHotkey } from "is-hotkey";
32
+ import { computePosition, flip, shift } from "@floating-ui/dom";
32
33
  import { getIntrospectionQuery, buildClientSchema, print, parse as parse$3, buildSchema } from "graphql";
33
34
  import gql$1 from "graphql-tag";
34
35
  import { TinaSchema, addNamespaceToSchema, parseURL, resolveForm, normalizePath, validateSchema } from "@tinacms/schema-tools";
@@ -37,42 +38,6 @@ import * as yup from "yup";
37
38
  import { diff } from "@graphql-inspector/core";
38
39
  import { NavLink, useSearchParams, useNavigate, useLocation, useParams, Link, HashRouter, Routes, Route } from "react-router-dom";
39
40
  import { stringifyMDX } from "@tinacms/mdx";
40
- function popupWindow(url, title, window2, w, h) {
41
- const y = window2.top.outerHeight / 2 + window2.top.screenY - h / 2;
42
- const x = window2.top.outerWidth / 2 + window2.top.screenX - w / 2;
43
- return window2.open(
44
- url,
45
- title,
46
- "toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, copyhistory=no, width=" + w + ", height=" + h + ", top=" + y + ", left=" + x
47
- );
48
- }
49
- const TINA_LOGIN_EVENT = "tinaCloudLogin";
50
- const AUTH_TOKEN_KEY = "tinacms-auth";
51
- const authenticate = (clientId, frontendUrl) => {
52
- return new Promise((resolve) => {
53
- let authTab;
54
- window.addEventListener("message", function(e) {
55
- if (e.data.source === TINA_LOGIN_EVENT) {
56
- if (authTab) {
57
- authTab.close();
58
- }
59
- resolve({
60
- id_token: e.data.id_token,
61
- access_token: e.data.access_token,
62
- refresh_token: e.data.refresh_token
63
- });
64
- }
65
- });
66
- const origin = `${window.location.protocol}//${window.location.host}`;
67
- authTab = popupWindow(
68
- `${frontendUrl}/signin?clientId=${clientId}&origin=${origin}`,
69
- "_blank",
70
- window,
71
- 1e3,
72
- 700
73
- );
74
- });
75
- };
76
41
  const ModalProvider = ({ children }) => {
77
42
  const [modalRootContainerRef, setModalRootContainerRef] = useState(
78
43
  null
@@ -1817,8 +1782,15 @@ class Form {
1817
1782
  return this.finalForm.subscribe(cb, options2);
1818
1783
  };
1819
1784
  this.handleSubmit = async (values, form, cb) => {
1785
+ var _a;
1820
1786
  try {
1821
- const response = await this.onSubmit(values, form, cb);
1787
+ const valOverride = await ((_a = this.beforeSubmit) == null ? void 0 : _a.call(this, values));
1788
+ if (valOverride) {
1789
+ for (const [key, value] of Object.entries(valOverride)) {
1790
+ form.change(key, value);
1791
+ }
1792
+ }
1793
+ const response = await this.onSubmit(valOverride || values, form, cb);
1822
1794
  form.initialize(values);
1823
1795
  return response;
1824
1796
  } catch (error) {
@@ -2356,6 +2328,7 @@ const InnerField = ({ field, form, fieldPlugins, index, activeFieldName }) => {
2356
2328
  {
2357
2329
  name: field.name,
2358
2330
  key: field.name,
2331
+ isEqual: (a, b) => isEqual(field, a, b),
2359
2332
  type,
2360
2333
  parse: parse2 ? (value, name) => parse2(value, name, field) : void 0,
2361
2334
  format: format2 ? (value, name) => format2(value, name, field) : void 0,
@@ -2413,6 +2386,18 @@ function getProp(name, field, plugin) {
2413
2386
  }
2414
2387
  return prop;
2415
2388
  }
2389
+ const isEqual = (field, a, b) => {
2390
+ const replacer = (key, value) => {
2391
+ if (key === "id") {
2392
+ return void 0;
2393
+ }
2394
+ return value;
2395
+ };
2396
+ if (field.type === "rich-text") {
2397
+ return JSON.stringify(a, replacer) === JSON.stringify(b, replacer);
2398
+ }
2399
+ return a === b;
2400
+ };
2416
2401
  const FF = Form$1;
2417
2402
  const FormLegacy = ({ form, children }) => {
2418
2403
  const [i, setI] = React.useState(0);
@@ -2457,7 +2442,7 @@ const Button = ({
2457
2442
  disabled,
2458
2443
  rounded = "full",
2459
2444
  children,
2460
- className,
2445
+ className = "",
2461
2446
  ...props
2462
2447
  }) => {
2463
2448
  const baseClasses = "icon-parent inline-flex items-center font-medium focus:outline-none focus:ring-2 focus:shadow-outline text-center inline-flex justify-center transition-all duration-150 ease-out ";
@@ -3073,6 +3058,9 @@ function IoMdClose(props) {
3073
3058
  function IoMdRefresh(props) {
3074
3059
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 512 512" }, "child": [{ "tag": "path", "attr": { "d": "M256 388c-72.597 0-132-59.405-132-132 0-72.601 59.403-132 132-132 36.3 0 69.299 15.4 92.406 39.601L278 234h154V80l-51.698 51.702C348.406 99.798 304.406 80 256 80c-96.797 0-176 79.203-176 176s78.094 176 176 176c81.045 0 148.287-54.134 169.401-128H378.85c-18.745 49.561-67.138 84-122.85 84z" } }] })(props);
3075
3060
  }
3061
+ function MdVpnKey(props) {
3062
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "fill": "none", "d": "M0 0h24v24H0z" } }, { "tag": "path", "attr": { "d": "M12.65 10A5.99 5.99 0 007 6c-3.31 0-6 2.69-6 6s2.69 6 6 6a5.99 5.99 0 005.65-4H17v4h4v-4h2v-4H12.65zM7 14c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z" } }] })(props);
3063
+ }
3076
3064
  function MdKeyboardArrowDown(props) {
3077
3065
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "fill": "none", "d": "M0 0h24v24H0V0z" } }, { "tag": "path", "attr": { "d": "M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z" } }] })(props);
3078
3066
  }
@@ -3134,14 +3122,14 @@ const useBranchData = () => {
3134
3122
  return branchData;
3135
3123
  };
3136
3124
  const textFieldClasses = "shadow-inner focus:shadow-outline focus:border-blue-500 focus:outline-none block text-base placeholder:text-gray-300 px-3 py-2 text-gray-600 w-full bg-white border border-gray-200 transition-all ease-out duration-150 focus:text-gray-900 rounded-md";
3137
- const disabledClasses = "opacity-50 pointer-events-none cursor-not-allowed";
3125
+ const disabledClasses$1 = "opacity-50 pointer-events-none cursor-not-allowed";
3138
3126
  const BaseTextField = React.forwardRef(({ className, disabled, ...rest }, ref) => {
3139
3127
  return /* @__PURE__ */ React.createElement(
3140
3128
  "input",
3141
3129
  {
3142
3130
  ref,
3143
3131
  type: "text",
3144
- className: `${textFieldClasses} ${disabled ? disabledClasses : ""} ${className}`,
3132
+ className: `${textFieldClasses} ${disabled ? disabledClasses$1 : ""} ${className}`,
3145
3133
  ...rest
3146
3134
  }
3147
3135
  );
@@ -3960,6 +3948,20 @@ function toProps(option) {
3960
3948
  return option;
3961
3949
  return { value: option, label: option };
3962
3950
  }
3951
+ const passwordFieldClasses = "shadow-inner focus:shadow-outline focus:border-blue-500 focus:outline-none block text-base placeholder:text-gray-300 px-3 py-2 text-gray-600 w-full bg-white border border-gray-200 transition-all ease-out duration-150 focus:text-gray-900 rounded-md";
3952
+ const disabledClasses = "opacity-50 pointer-events-none cursor-not-allowed";
3953
+ const errorClasses = "border-red-500 focus:border-red-500 focus:shadow-outline-red";
3954
+ const BasePasswordField = React.forwardRef(({ className, disabled, error, ...rest }, ref) => {
3955
+ return /* @__PURE__ */ React.createElement(
3956
+ "input",
3957
+ {
3958
+ ref,
3959
+ type: "password",
3960
+ className: `${passwordFieldClasses} ${disabled ? disabledClasses : ""} ${className} ${error ? errorClasses : ""}`,
3961
+ ...rest
3962
+ }
3963
+ );
3964
+ });
3963
3965
  const Group$1 = wrapFieldWithError(({ tinaForm, field }) => {
3964
3966
  const cms = useCMS$1();
3965
3967
  React.useState(false);
@@ -5046,9 +5048,19 @@ const TextField = wrapFieldsWithMeta(
5046
5048
  const TextFieldPlugin = {
5047
5049
  name: "text",
5048
5050
  Component: TextField,
5049
- validate(value, values, meta, field) {
5051
+ validate(value, allValues, meta, field) {
5052
+ var _a;
5050
5053
  if (field.required && !value)
5051
5054
  return "Required";
5055
+ if (field.uid) {
5056
+ const path = field.name.split(".");
5057
+ const fieldName = path[path.length - 1];
5058
+ const parent = path.slice(0, path.length - 2);
5059
+ const items = get(allValues, parent);
5060
+ if (((_a = items == null ? void 0 : items.filter((item) => item[fieldName] === value)) == null ? void 0 : _a.length) > 1) {
5061
+ return `Item with this unique id already exists`;
5062
+ }
5063
+ }
5052
5064
  },
5053
5065
  parse: parse$2
5054
5066
  };
@@ -5711,7 +5723,7 @@ var testPassiveEventSupport = function testPassiveEventSupport2() {
5711
5723
  }
5712
5724
  var passive = false;
5713
5725
  var options = Object.defineProperty({}, "passive", {
5714
- get: function get() {
5726
+ get: function get2() {
5715
5727
  passive = true;
5716
5728
  }
5717
5729
  });
@@ -6559,6 +6571,111 @@ const HiddenFieldPlugin = {
6559
6571
  Component: HiddenField,
6560
6572
  parse: parse$2
6561
6573
  };
6574
+ const PasswordMask = "********";
6575
+ const PasswordFieldComponent = wrapFieldsWithMeta(({ field, form, meta, input, children }) => {
6576
+ const ref1 = React.useRef(null);
6577
+ const ref2 = React.useRef(null);
6578
+ const [error, setError] = React.useState(false);
6579
+ const [password, setPassword] = React.useState();
6580
+ const [confirmPassword, setConfirmPassword] = React.useState();
6581
+ const [passwordChangeRequired, setPasswordChangeRequired] = React.useState(input.value.passwordChangeRequired);
6582
+ React.useEffect(() => {
6583
+ if (password) {
6584
+ if (password === confirmPassword) {
6585
+ setError(false);
6586
+ form.change(field.name, { value: password, passwordChangeRequired });
6587
+ } else {
6588
+ setError(true);
6589
+ form.change(field.name, void 0);
6590
+ }
6591
+ } else {
6592
+ setError(false);
6593
+ form.change(field.name, { passwordChangeRequired });
6594
+ }
6595
+ }, [password, confirmPassword, passwordChangeRequired]);
6596
+ return /* @__PURE__ */ React.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-row space-x-4" }, /* @__PURE__ */ React.createElement(
6597
+ BasePasswordField,
6598
+ {
6599
+ autoComplete: "off",
6600
+ value: password ?? PasswordMask,
6601
+ ref: ref1,
6602
+ disabled: (field == null ? void 0 : field.disabled) ?? false,
6603
+ error,
6604
+ placeholder: field.placeholder || "Password",
6605
+ onKeyDown: (_) => {
6606
+ if (password === void 0) {
6607
+ setPassword("");
6608
+ }
6609
+ if (confirmPassword === void 0) {
6610
+ setConfirmPassword("");
6611
+ }
6612
+ },
6613
+ onChange: (event) => {
6614
+ setPassword(event.target.value);
6615
+ }
6616
+ }
6617
+ ), /* @__PURE__ */ React.createElement(
6618
+ BasePasswordField,
6619
+ {
6620
+ autoComplete: "off",
6621
+ ref: ref2,
6622
+ value: confirmPassword ?? PasswordMask,
6623
+ disabled: (field == null ? void 0 : field.disabled) ?? false,
6624
+ error,
6625
+ placeholder: field.confirmPlaceholder || "Confirm Password",
6626
+ onKeyDown: (_) => {
6627
+ setPasswordChangeRequired(true);
6628
+ if (password === void 0) {
6629
+ setPassword("");
6630
+ }
6631
+ if (confirmPassword === void 0) {
6632
+ setConfirmPassword("");
6633
+ }
6634
+ },
6635
+ onChange: (event) => {
6636
+ setConfirmPassword(event.target.value);
6637
+ }
6638
+ }
6639
+ ), /* @__PURE__ */ React.createElement(
6640
+ Button,
6641
+ {
6642
+ variant: "secondary",
6643
+ disabled: password === void 0 && confirmPassword === void 0,
6644
+ onClick: () => {
6645
+ setError(false);
6646
+ setPassword(void 0);
6647
+ setConfirmPassword(void 0);
6648
+ setPasswordChangeRequired(void 0);
6649
+ form.change(field.name, void 0);
6650
+ }
6651
+ },
6652
+ "Reset"
6653
+ )), /* @__PURE__ */ React.createElement("div", { className: "flex w-full items-center pl-1 pt-3" }, /* @__PURE__ */ React.createElement(
6654
+ Toggle,
6655
+ {
6656
+ field: { name: "passwordChangeRequired", component: "toggle" },
6657
+ input: {
6658
+ value: passwordChangeRequired ?? true,
6659
+ onChange: () => setPasswordChangeRequired(!passwordChangeRequired)
6660
+ },
6661
+ name: "passwordChangeRequired"
6662
+ }
6663
+ ), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", { className: "block font-sans text-xs font-semibold text-gray-700 whitespace-normal h-full items-center ml-1" }, "Require Password Change on Next Login"))));
6664
+ });
6665
+ const PasswordFieldPlugin = {
6666
+ name: "password",
6667
+ Component: PasswordFieldComponent,
6668
+ validate(value, values, meta, field) {
6669
+ let password = value;
6670
+ if (Array.isArray(value)) {
6671
+ password = value[0];
6672
+ }
6673
+ if (field.required && (password == null ? void 0 : password.passwordChangeRequired) === void 0) {
6674
+ return "Required";
6675
+ }
6676
+ },
6677
+ parse: parse$2
6678
+ };
6562
6679
  function GrCircleQuestion(props) {
6563
6680
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "fill": "none", "stroke": "#000", "strokeWidth": "2", "d": "M12,22 C17.5228475,22 22,17.5228475 22,12 C22,6.4771525 17.5228475,2 12,2 C6.4771525,2 2,6.4771525 2,12 C2,17.5228475 6.4771525,22 12,22 Z M12,15 L12,14 C12,13 12,12.5 13,12 C14,11.5 15,11 15,9.5 C15,8.5 14,7 12,7 C10,7 9,8.26413718 9,10 M12,16 L12,18" } }] })(props);
6564
6681
  }
@@ -7120,7 +7237,7 @@ const BranchSelector = ({
7120
7237
  toolbarItems: [
7121
7238
  branch.githubPullRequestUrl && {
7122
7239
  name: "github-pr",
7123
- label: "View in Github",
7240
+ label: "View in GitHub",
7124
7241
  Icon: /* @__PURE__ */ React.createElement(BiLinkExternal, { className: "w-5 h-auto text-blue-500 opacity-70" }),
7125
7242
  onMouseDown: () => {
7126
7243
  window.open(branch.githubPullRequestUrl, "_blank");
@@ -7513,14 +7630,19 @@ class TinaMediaStore {
7513
7630
  if (!this.api) {
7514
7631
  this.api = (_b = (_a = this.cms) == null ? void 0 : _a.api) == null ? void 0 : _b.tina;
7515
7632
  this.isLocal = !!this.api.isLocalMode;
7516
- const contentApiUrl = new URL(this.api.contentApiUrl);
7517
- this.url = `${contentApiUrl.origin}/media`;
7518
- if (!this.isLocal) {
7519
- if ((_d = (_c = this.api.options) == null ? void 0 : _c.tinaioConfig) == null ? void 0 : _d.assetsApiUrlOverride) {
7520
- const url = new URL(this.api.assetsApiUrl);
7521
- this.url = `${url.origin}/v1/${this.api.clientId}`;
7522
- } else {
7523
- this.url = `${contentApiUrl.origin.replace("content", "assets")}/v1/${this.api.clientId}`;
7633
+ if (!this.isStatic) {
7634
+ const contentApiUrl = new URL(this.api.contentApiUrl);
7635
+ this.url = `${contentApiUrl.origin}/media`;
7636
+ if (!this.isLocal) {
7637
+ if ((_d = (_c = this.api.options) == null ? void 0 : _c.tinaioConfig) == null ? void 0 : _d.assetsApiUrlOverride) {
7638
+ const url = new URL(this.api.assetsApiUrl);
7639
+ this.url = `${url.origin}/v1/${this.api.clientId}`;
7640
+ } else {
7641
+ this.url = `${contentApiUrl.origin.replace(
7642
+ "content",
7643
+ "assets"
7644
+ )}/v1/${this.api.clientId}`;
7645
+ }
7524
7646
  }
7525
7647
  }
7526
7648
  }
@@ -7542,6 +7664,10 @@ class TinaMediaStore {
7542
7664
  `${this.url}/upload_url/${path}`,
7543
7665
  { method: "GET" }
7544
7666
  );
7667
+ if (res.status === 412) {
7668
+ const { message = "Unexpected error generating upload url" } = await res.json();
7669
+ throw new Error(message);
7670
+ }
7545
7671
  const { signedUrl } = await res.json();
7546
7672
  if (!signedUrl) {
7547
7673
  throw new Error("Unexpected error generating upload url");
@@ -7656,6 +7782,38 @@ class TinaMediaStore {
7656
7782
  }
7657
7783
  async list(options) {
7658
7784
  this.setup();
7785
+ if (this.staticMedia) {
7786
+ const offset = options.offset || 0;
7787
+ const media = this.staticMedia[String(offset)];
7788
+ let hasMore = false;
7789
+ if (this.staticMedia[String(Number(offset) + 20)]) {
7790
+ hasMore = true;
7791
+ }
7792
+ if (options.directory) {
7793
+ let depth = 0;
7794
+ const pathToDirectory = options.directory.split("/");
7795
+ let currentFolder = media;
7796
+ let hasMore2 = false;
7797
+ while (depth < pathToDirectory.length) {
7798
+ const nextFolder = currentFolder.find(
7799
+ (item) => item.type === "dir" && item.filename === pathToDirectory[depth]
7800
+ );
7801
+ if (nextFolder) {
7802
+ const offset2 = options.offset || 0;
7803
+ currentFolder = nextFolder.children[String(offset2)];
7804
+ if (nextFolder.children[String(Number(offset2) + 20)]) {
7805
+ hasMore2 = true;
7806
+ }
7807
+ }
7808
+ depth++;
7809
+ }
7810
+ return {
7811
+ items: currentFolder,
7812
+ nextOffset: hasMore2 ? Number(offset) + 20 : null
7813
+ };
7814
+ }
7815
+ return { items: media, nextOffset: hasMore ? Number(offset) + 20 : null };
7816
+ }
7659
7817
  let res;
7660
7818
  if (!this.isLocal) {
7661
7819
  if (await this.isAuthenticated()) {
@@ -7708,38 +7866,6 @@ class TinaMediaStore {
7708
7866
  filename: dir
7709
7867
  });
7710
7868
  }
7711
- if (this.staticMedia) {
7712
- const offset = options.offset || 0;
7713
- const media = this.staticMedia[String(offset)];
7714
- let hasMore = false;
7715
- if (this.staticMedia[String(Number(offset) + 20)]) {
7716
- hasMore = true;
7717
- }
7718
- if (options.directory) {
7719
- let depth = 0;
7720
- const pathToDirectory = options.directory.split("/");
7721
- let currentFolder = media;
7722
- let hasMore2 = false;
7723
- while (depth < pathToDirectory.length) {
7724
- const nextFolder = currentFolder.find(
7725
- (item) => item.type === "dir" && item.filename === pathToDirectory[depth]
7726
- );
7727
- if (nextFolder) {
7728
- const offset2 = options.offset || 0;
7729
- currentFolder = nextFolder.children[String(offset2)];
7730
- if (nextFolder.children[String(Number(offset2) + 20)]) {
7731
- hasMore2 = true;
7732
- }
7733
- }
7734
- depth++;
7735
- }
7736
- return {
7737
- items: currentFolder,
7738
- nextOffset: hasMore2 ? Number(offset) + 20 : null
7739
- };
7740
- }
7741
- return { items: media, nextOffset: hasMore ? Number(offset) + 20 : null };
7742
- }
7743
7869
  return {
7744
7870
  items,
7745
7871
  nextOffset: cursor || 0
@@ -8405,6 +8531,9 @@ const FormHeader = ({ activeForm }) => {
8405
8531
  function ImFilesEmpty(props) {
8406
8532
  return GenIcon({ "tag": "svg", "attr": { "version": "1.1", "viewBox": "0 0 16 16" }, "child": [{ "tag": "path", "attr": { "d": "M14.341 5.579c-0.347-0.473-0.831-1.027-1.362-1.558s-1.085-1.015-1.558-1.362c-0.806-0.591-1.197-0.659-1.421-0.659h-5.75c-0.689 0-1.25 0.561-1.25 1.25v11.5c0 0.689 0.561 1.25 1.25 1.25h9.5c0.689 0 1.25-0.561 1.25-1.25v-7.75c0-0.224-0.068-0.615-0.659-1.421zM12.271 4.729c0.48 0.48 0.856 0.912 1.134 1.271h-2.406v-2.405c0.359 0.278 0.792 0.654 1.271 1.134v0zM14 14.75c0 0.136-0.114 0.25-0.25 0.25h-9.5c-0.136 0-0.25-0.114-0.25-0.25v-11.5c0-0.135 0.114-0.25 0.25-0.25 0 0 5.749-0 5.75 0v3.5c0 0.276 0.224 0.5 0.5 0.5h3.5v7.75z" } }, { "tag": "path", "attr": { "d": "M9.421 0.659c-0.806-0.591-1.197-0.659-1.421-0.659h-5.75c-0.689 0-1.25 0.561-1.25 1.25v11.5c0 0.604 0.43 1.109 1 1.225v-12.725c0-0.135 0.115-0.25 0.25-0.25h7.607c-0.151-0.124-0.297-0.238-0.437-0.341z" } }] })(props);
8407
8533
  }
8534
+ function ImUsers(props) {
8535
+ return GenIcon({ "tag": "svg", "attr": { "version": "1.1", "viewBox": "0 0 18 16" }, "child": [{ "tag": "path", "attr": { "d": "M12 12.041v-0.825c1.102-0.621 2-2.168 2-3.716 0-2.485 0-4.5-3-4.5s-3 2.015-3 4.5c0 1.548 0.898 3.095 2 3.716v0.825c-3.392 0.277-6 1.944-6 3.959h14c0-2.015-2.608-3.682-6-3.959z" } }, { "tag": "path", "attr": { "d": "M5.112 12.427c0.864-0.565 1.939-0.994 3.122-1.256-0.235-0.278-0.449-0.588-0.633-0.922-0.475-0.863-0.726-1.813-0.726-2.748 0-1.344 0-2.614 0.478-3.653 0.464-1.008 1.299-1.633 2.488-1.867-0.264-1.195-0.968-1.98-2.841-1.98-3 0-3 2.015-3 4.5 0 1.548 0.898 3.095 2 3.716v0.825c-3.392 0.277-6 1.944-6 3.959h4.359c0.227-0.202 0.478-0.393 0.753-0.573z" } }] })(props);
8536
+ }
8408
8537
  const LocalWarning = () => {
8409
8538
  return /* @__PURE__ */ React.createElement(
8410
8539
  "a",
@@ -8492,10 +8621,10 @@ const useGetEvents = (cms, cursor, existingEvents) => {
8492
8621
  const [error, setError] = useState(void 0);
8493
8622
  React.useEffect(() => {
8494
8623
  const fetchEvents = async () => {
8495
- var _a, _b, _c, _d;
8624
+ var _a, _b, _c, _d, _e;
8496
8625
  let doFetchEvents = false;
8497
8626
  if (!((_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isCustomContentApi)) {
8498
- doFetchEvents = await ((_d = (_c = cms.api) == null ? void 0 : _c.tina) == null ? void 0 : _d.isAuthenticated());
8627
+ doFetchEvents = await ((_e = (_d = (_c = cms.api) == null ? void 0 : _c.tina) == null ? void 0 : _d.authProvider) == null ? void 0 : _e.isAuthenticated());
8499
8628
  }
8500
8629
  if (doFetchEvents) {
8501
8630
  try {
@@ -8654,17 +8783,40 @@ const Nav = ({
8654
8783
  RenderNavSite,
8655
8784
  RenderNavCloud,
8656
8785
  RenderNavCollection,
8786
+ AuthRenderNavCollection,
8657
8787
  ...props
8658
8788
  }) => {
8659
8789
  const cms = useCMS$1();
8660
8790
  const { setEdit } = useEditState();
8661
8791
  const [eventsOpen, setEventsOpen] = React.useState(false);
8792
+ const { contentCollections, authCollection } = collectionsInfo.collections.reduce(
8793
+ (acc, collection) => {
8794
+ if (collection.isAuthCollection) {
8795
+ acc.authCollection = collection;
8796
+ } else {
8797
+ acc.contentCollections.push(collection);
8798
+ }
8799
+ return acc;
8800
+ },
8801
+ {
8802
+ contentCollections: []
8803
+ }
8804
+ );
8662
8805
  function closeEventsModal() {
8663
8806
  setEventsOpen(false);
8664
8807
  }
8665
8808
  const WrappedSyncStatus = React.forwardRef(
8666
8809
  (props2, ref) => /* @__PURE__ */ React.createElement(SyncStatus, { ...props2 })
8667
8810
  );
8811
+ const screenCategories = screens.reduce(
8812
+ (acc, screen) => {
8813
+ const category = screen.navCategory || "Site";
8814
+ acc[category] = acc[category] || [];
8815
+ acc[category].push(screen);
8816
+ return acc;
8817
+ },
8818
+ { Site: [] }
8819
+ );
8668
8820
  return /* @__PURE__ */ React.createElement(
8669
8821
  "div",
8670
8822
  {
@@ -8710,18 +8862,21 @@ const Nav = ({
8710
8862
  {
8711
8863
  className: `text-lg px-4 py-2 first:pt-3 last:pb-3 tracking-wide whitespace-nowrap flex items-center opacity-80 text-gray-600 hover:text-blue-400 hover:bg-gray-50 hover:opacity-100`,
8712
8864
  onClick: async () => {
8713
- var _a, _b, _c, _d, _e, _f;
8865
+ var _a, _b, _c, _d, _e, _f, _g, _h;
8714
8866
  updateBodyDisplacement({
8715
8867
  displayState: "closed",
8716
8868
  sidebarWidth: null,
8717
8869
  resizingSidebar: false
8718
8870
  });
8719
8871
  try {
8720
- if ((_b = (_a = cms == null ? void 0 : cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.logout) {
8721
- await cms.api.tina.logout();
8722
- if ((_d = (_c = cms == null ? void 0 : cms.api) == null ? void 0 : _c.tina) == null ? void 0 : _d.onLogout) {
8723
- await ((_f = (_e = cms == null ? void 0 : cms.api) == null ? void 0 : _e.tina) == null ? void 0 : _f.onLogout());
8872
+ if ((_c = (_b = (_a = cms == null ? void 0 : cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.authProvider) == null ? void 0 : _c.logout) {
8873
+ await ((_d = cms.api.tina) == null ? void 0 : _d.authProvider.logout());
8874
+ if ((_f = (_e = cms == null ? void 0 : cms.api) == null ? void 0 : _e.tina) == null ? void 0 : _f.onLogout) {
8875
+ await ((_h = (_g = cms == null ? void 0 : cms.api) == null ? void 0 : _g.tina) == null ? void 0 : _h.onLogout());
8724
8876
  }
8877
+ window.location.href = new URL(
8878
+ window.location.href
8879
+ ).pathname;
8725
8880
  }
8726
8881
  setEdit(false);
8727
8882
  } catch (e) {
@@ -8754,13 +8909,25 @@ const Nav = ({
8754
8909
  CollectionsList,
8755
8910
  {
8756
8911
  RenderNavCollection,
8757
- ...collectionsInfo
8912
+ collections: contentCollections
8758
8913
  }
8759
- )), (screens.length > 0 || contentCreators.length) > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("h4", { className: "uppercase font-sans font-bold text-sm mb-3 mt-8 text-gray-700" }, "Site"), /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-4" }, screens.map((view) => {
8914
+ )), (screenCategories.Site.length > 0 || contentCreators.length) > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("h4", { className: "uppercase font-sans font-bold text-sm mb-3 mt-8 text-gray-700" }, "Site"), /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-4" }, screenCategories.Site.map((view) => {
8760
8915
  return /* @__PURE__ */ React.createElement("li", { key: `nav-site-${view.name}` }, /* @__PURE__ */ React.createElement(RenderNavSite, { view }));
8761
8916
  }), contentCreators.map((plugin, idx) => {
8762
8917
  return /* @__PURE__ */ React.createElement(CreateContentNavItem, { key: `plugin-${idx}`, plugin });
8763
- }))), !!(cloudConfigs == null ? void 0 : cloudConfigs.length) && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("h4", { className: "uppercase font-sans font-bold text-sm mb-3 mt-8 text-gray-700" }, "Cloud"), /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-4" }, cloudConfigs.map((config) => {
8918
+ }), authCollection && /* @__PURE__ */ React.createElement(
8919
+ CollectionsList,
8920
+ {
8921
+ RenderNavCollection: AuthRenderNavCollection,
8922
+ collections: [authCollection]
8923
+ }
8924
+ ))), Object.entries(screenCategories).map(([category, screens2]) => {
8925
+ if (category !== "Site") {
8926
+ return /* @__PURE__ */ React.createElement("div", { key: category }, /* @__PURE__ */ React.createElement("h4", { className: "uppercase font-sans font-bold text-sm mb-3 mt-8 text-gray-700" }, category), /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-4" }, screens2.map((view) => {
8927
+ return /* @__PURE__ */ React.createElement("li", { key: `nav-site-${view.name}` }, /* @__PURE__ */ React.createElement(RenderNavSite, { view }));
8928
+ })));
8929
+ }
8930
+ }), !!(cloudConfigs == null ? void 0 : cloudConfigs.length) && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("h4", { className: "uppercase font-sans font-bold text-sm mb-3 mt-8 text-gray-700" }, "Cloud"), /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-4" }, cloudConfigs.map((config) => {
8764
8931
  return /* @__PURE__ */ React.createElement("li", { key: `nav-site-${config.name}` }, /* @__PURE__ */ React.createElement(RenderNavCloud, { config }));
8765
8932
  }))))
8766
8933
  );
@@ -8917,6 +9084,12 @@ const Sidebar$1 = ({
8917
9084
  const [activeScreen, setActiveView] = useState(null);
8918
9085
  const [sidebarWidth, setSidebarWidth] = React.useState(defaultWidth);
8919
9086
  const [formIsPristine, setFormIsPristine] = React.useState(true);
9087
+ const activeScreens = allScreens.filter(
9088
+ (screen) => {
9089
+ var _a2, _b2;
9090
+ return screen.navCategory !== "Account" || ((_b2 = (_a2 = cms.api.tina) == null ? void 0 : _a2.authProvider) == null ? void 0 : _b2.getLoginStrategy()) === "UsernamePassword";
9091
+ }
9092
+ );
8920
9093
  const setDisplayState = (value) => cms.dispatch({ type: "sidebar:set-display-state", value });
8921
9094
  const displayState = cms.state.sidebarDisplayState;
8922
9095
  React.useEffect(() => {
@@ -9012,7 +9185,7 @@ const Sidebar$1 = ({
9012
9185
  isLocalMode: (_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode,
9013
9186
  showCollections: isTinaAdminEnabled,
9014
9187
  collectionsInfo,
9015
- screens: allScreens,
9188
+ screens: activeScreens,
9016
9189
  cloudConfigs: allConfigs,
9017
9190
  contentCreators,
9018
9191
  sidebarWidth,
@@ -9035,6 +9208,16 @@ const Sidebar$1 = ({
9035
9208
  },
9036
9209
  collection
9037
9210
  }
9211
+ ),
9212
+ AuthRenderNavCollection: ({ collection }) => /* @__PURE__ */ React.createElement(
9213
+ SidebarCollectionLink,
9214
+ {
9215
+ onClick: () => {
9216
+ setMenuIsOpen(false);
9217
+ },
9218
+ collection,
9219
+ Icon: ImUsers
9220
+ }
9038
9221
  )
9039
9222
  }
9040
9223
  ), /* @__PURE__ */ React.createElement(SidebarBody, null, /* @__PURE__ */ React.createElement(
@@ -9069,7 +9252,7 @@ const Sidebar$1 = ({
9069
9252
  className: "rounded-r-md",
9070
9253
  showCollections: isTinaAdminEnabled,
9071
9254
  collectionsInfo,
9072
- screens: allScreens,
9255
+ screens: activeScreens,
9073
9256
  cloudConfigs: allConfigs,
9074
9257
  contentCreators,
9075
9258
  sidebarWidth,
@@ -9092,6 +9275,16 @@ const Sidebar$1 = ({
9092
9275
  },
9093
9276
  collection
9094
9277
  }
9278
+ ),
9279
+ AuthRenderNavCollection: ({ collection }) => /* @__PURE__ */ React.createElement(
9280
+ SidebarCollectionLink,
9281
+ {
9282
+ onClick: () => {
9283
+ setMenuIsOpen(false);
9284
+ },
9285
+ collection,
9286
+ Icon: ImUsers
9287
+ }
9095
9288
  )
9096
9289
  },
9097
9290
  /* @__PURE__ */ React.createElement("div", { className: "absolute top-8 right-0 transform translate-x-full overflow-hidden" }, /* @__PURE__ */ React.createElement(
@@ -9253,6 +9446,7 @@ const SidebarCloudLink$1 = ({ config }) => {
9253
9446
  return /* @__PURE__ */ React.createElement("span", { className: "text-base tracking-wide text-gray-500 hover:text-blue-600 flex items-center opacity-90 hover:opacity-100" }, /* @__PURE__ */ React.createElement(config.Icon, { className: "mr-2 h-6 opacity-80 w-auto" }), /* @__PURE__ */ React.createElement("a", { target: "_blank", href: config.link.href }, config.link.text));
9254
9447
  };
9255
9448
  const SidebarCollectionLink = ({
9449
+ Icon = ImFilesEmpty,
9256
9450
  collection,
9257
9451
  onClick
9258
9452
  }) => {
@@ -9265,7 +9459,7 @@ const SidebarCollectionLink = ({
9265
9459
  href: `${tinaPreview ? `/${tinaPreview}/index.html#` : "/admin#"}/collections/${collection.name}/~`,
9266
9460
  className: "text-base tracking-wide text-gray-500 hover:text-blue-600 flex items-center opacity-90 hover:opacity-100"
9267
9461
  },
9268
- /* @__PURE__ */ React.createElement(ImFilesEmpty, { className: "mr-2 h-6 opacity-80 w-auto" }),
9462
+ /* @__PURE__ */ React.createElement(Icon, { className: "mr-2 h-6 opacity-80 w-auto" }),
9269
9463
  " ",
9270
9464
  collection.label ? collection.label : collection.name
9271
9465
  );
@@ -9981,7 +10175,9 @@ const SyncStatusContainer = ({ children }) => {
9981
10175
  setSyncStatus(project.mediaBranch ? "synced" : "needs-sync");
9982
10176
  }
9983
10177
  };
9984
- checkSyncStatus();
10178
+ if (!cms.media.store.isStatic) {
10179
+ checkSyncStatus();
10180
+ }
9985
10181
  }, []);
9986
10182
  return syncStatus == "needs-sync" ? /* @__PURE__ */ React__default.createElement("div", { className: "h-full flex items-center justify-center p-6 bg-gradient-to-t from-gray-200 to-transparent" }, /* @__PURE__ */ React__default.createElement("div", { className: "rounded-lg border shadow-sm px-4 lg:px-6 py-3 lg:py-4 bg-gradient-to-r from-yellow-50 to-yellow-100 border-yellow-200 mx-auto mb-12" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex items-start sm:items-center gap-2" }, /* @__PURE__ */ React__default.createElement(
9987
10183
  BiError,
@@ -10071,6 +10267,108 @@ const MediaManagerScreenPlugin = createScreen({
10071
10267
  allowDelete: true
10072
10268
  }
10073
10269
  });
10270
+ function UpdatePassword(props) {
10271
+ const cms = useCMS$1();
10272
+ const client = cms.api.tina;
10273
+ const [password, setPassword] = useState("");
10274
+ const [confirmPassword, setConfirmPassword] = useState("");
10275
+ const [dirty, setDirty] = useState(false);
10276
+ const [result, setResult] = useState(null);
10277
+ const [formState, setFormState] = useState("idle");
10278
+ const [passwordChangeRequired, setPasswordChangeRequired] = useState(false);
10279
+ useEffect(() => {
10280
+ var _a;
10281
+ (_a = client == null ? void 0 : client.authProvider) == null ? void 0 : _a.getUser().then(
10282
+ (user) => setPasswordChangeRequired((user == null ? void 0 : user.passwordChangeRequired) ?? false)
10283
+ );
10284
+ }, []);
10285
+ let err = null;
10286
+ if (dirty && password !== confirmPassword) {
10287
+ err = "Passwords do not match";
10288
+ }
10289
+ if (dirty && !password) {
10290
+ err = "Please enter a password";
10291
+ }
10292
+ const updatePassword = async () => {
10293
+ var _a;
10294
+ setResult(null);
10295
+ setFormState("busy");
10296
+ const res = await cms.api.tina.request(
10297
+ `mutation($password: String!) { updatePassword(password: $password) }`,
10298
+ {
10299
+ variables: {
10300
+ password
10301
+ }
10302
+ }
10303
+ );
10304
+ if (!(res == null ? void 0 : res.updatePassword)) {
10305
+ setResult("Error updating password");
10306
+ } else {
10307
+ setDirty(false);
10308
+ setPassword("");
10309
+ setConfirmPassword("");
10310
+ setResult("Password updated");
10311
+ setPasswordChangeRequired(false);
10312
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
10313
+ (_a = client == null ? void 0 : client.authProvider) == null ? void 0 : _a.logout().then(async () => {
10314
+ if (typeof (client == null ? void 0 : client.onLogout) === "function") {
10315
+ await client.onLogout();
10316
+ }
10317
+ window.location.href = new URL(window.location.href).pathname;
10318
+ }).catch((e) => console.error(e));
10319
+ }
10320
+ setFormState("idle");
10321
+ };
10322
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("div", { className: "flex justify-center items-center h-full" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-col space-y-8 p-6" }, passwordChangeRequired && /* @__PURE__ */ React__default.createElement("div", { className: "text-center text-red-500" }, "Your password has expired. Please update your password."), /* @__PURE__ */ React__default.createElement("label", { className: "block" }, /* @__PURE__ */ React__default.createElement("span", { className: "text-gray-700" }, "New Password"), /* @__PURE__ */ React__default.createElement(
10323
+ BaseTextField,
10324
+ {
10325
+ type: "password",
10326
+ name: "password",
10327
+ id: "password",
10328
+ placeholder: "Enter password",
10329
+ className: err ? "border-red-500" : "border-gray-300 focus:ring-indigo-500 focus:border-indigo-500",
10330
+ value: password,
10331
+ onKeyDown: () => {
10332
+ setDirty(true);
10333
+ setResult(null);
10334
+ },
10335
+ onChange: (e) => setPassword(e.target.value),
10336
+ required: true
10337
+ }
10338
+ )), /* @__PURE__ */ React__default.createElement("label", { className: "block" }, /* @__PURE__ */ React__default.createElement("span", { className: "text-gray-700" }, "Confirm New Password"), /* @__PURE__ */ React__default.createElement(
10339
+ BaseTextField,
10340
+ {
10341
+ type: "password",
10342
+ name: "confirmPassword",
10343
+ id: "confirmPassword",
10344
+ placeholder: "Confirm password",
10345
+ className: err ? "border-red-500" : "border-gray-300 focus:ring-indigo-500 focus:border-indigo-500",
10346
+ value: confirmPassword,
10347
+ onKeyDown: () => {
10348
+ setDirty(true);
10349
+ setResult(null);
10350
+ },
10351
+ onChange: (e) => setConfirmPassword(e.target.value),
10352
+ required: true
10353
+ }
10354
+ )), result && /* @__PURE__ */ React__default.createElement("div", { className: "text-center text-sm text-gray-500" }, result), err && /* @__PURE__ */ React__default.createElement("div", { className: "text-center text-sm text-red-500" }, err), /* @__PURE__ */ React__default.createElement(
10355
+ Button,
10356
+ {
10357
+ onClick: updatePassword,
10358
+ disabled: err,
10359
+ variant: "primary",
10360
+ busy: formState === "busy"
10361
+ },
10362
+ "Update"
10363
+ ))));
10364
+ }
10365
+ const PasswordScreenPlugin = createScreen({
10366
+ name: "Change Password",
10367
+ Component: UpdatePassword,
10368
+ Icon: MdVpnKey,
10369
+ layout: "fullscreen",
10370
+ navCategory: "Account"
10371
+ });
10074
10372
  function createCloudConfig({
10075
10373
  ...options
10076
10374
  }) {
@@ -10100,7 +10398,8 @@ const DEFAULT_FIELDS = [
10100
10398
  CheckboxGroupFieldPlugin,
10101
10399
  ReferenceFieldPlugin,
10102
10400
  ButtonToggleFieldPlugin,
10103
- HiddenFieldPlugin
10401
+ HiddenFieldPlugin,
10402
+ PasswordFieldPlugin
10104
10403
  ];
10105
10404
  class TinaCMS extends CMS {
10106
10405
  constructor({
@@ -10118,7 +10417,7 @@ class TinaCMS extends CMS {
10118
10417
  return {
10119
10418
  error: event.error,
10120
10419
  level: "error",
10121
- message: `Failed to upload file(s) ${event == null ? void 0 : event.uploaded.map((x) => x.file.name).join(", ")}. See error message:
10420
+ message: `Failed to upload file(s) ${event == null ? void 0 : event.uploaded.map((x) => x.file.name).join(", ")}.
10122
10421
 
10123
10422
  ${event == null ? void 0 : event.error.toString()}`
10124
10423
  };
@@ -10139,6 +10438,7 @@ class TinaCMS extends CMS {
10139
10438
  }
10140
10439
  });
10141
10440
  this.plugins.add(MediaManagerScreenPlugin);
10441
+ this.plugins.add(PasswordScreenPlugin);
10142
10442
  if (isLocalClient !== true) {
10143
10443
  if (clientId) {
10144
10444
  this.plugins.add(
@@ -10829,6 +11129,16 @@ const FormBuilder = ({
10829
11129
  const [createBranchModalOpen, setCreateBranchModalOpen] = React.useState(false);
10830
11130
  const tinaForm = form.tinaForm;
10831
11131
  const finalForm = form.tinaForm.finalForm;
11132
+ const schema = cms.api.tina.schema;
11133
+ React.useEffect(() => {
11134
+ var _a;
11135
+ const collection = schema.getCollectionByFullPath(tinaForm.relativePath);
11136
+ if ((_a = collection == null ? void 0 : collection.ui) == null ? void 0 : _a.beforeSubmit) {
11137
+ tinaForm.beforeSubmit = (values) => collection.ui.beforeSubmit({ cms, form: tinaForm, values });
11138
+ } else {
11139
+ tinaForm.beforeSubmit = void 0;
11140
+ }
11141
+ }, [tinaForm.relativePath]);
10832
11142
  const moveArrayItem = React.useCallback(
10833
11143
  (result) => {
10834
11144
  if (!result.destination || !finalForm)
@@ -10861,18 +11171,7 @@ const FormBuilder = ({
10861
11171
  {
10862
11172
  key: tinaForm.id,
10863
11173
  form: tinaForm.finalForm,
10864
- onSubmit: async (values, form2, cb) => {
10865
- var _a, _b;
10866
- const schema = cms.api.tina.schema;
10867
- const collection = schema.getCollectionByFullPath(tinaForm.relativePath);
10868
- const valOverride = ((_a = collection == null ? void 0 : collection.ui) == null ? void 0 : _a.beforeSubmit) ? await ((_b = collection == null ? void 0 : collection.ui) == null ? void 0 : _b.beforeSubmit({ cms, values, form: tinaForm })) : false;
10869
- if (valOverride) {
10870
- for (const [key, value] of Object.entries(valOverride)) {
10871
- form2.change(key, value);
10872
- }
10873
- }
10874
- return tinaForm.onSubmit(valOverride || values, form2, cb);
10875
- }
11174
+ onSubmit: tinaForm.onSubmit
10876
11175
  },
10877
11176
  ({
10878
11177
  handleSubmit,
@@ -26369,25 +26668,6 @@ const parseSearchIndexResponse = (data, options) => {
26369
26668
  };
26370
26669
  }
26371
26670
  };
26372
- const captureBranchName = /^refs\/heads\/(.*)/;
26373
- const parseRefForBranchName = (ref) => {
26374
- const matches = ref.match(captureBranchName);
26375
- return matches[1];
26376
- };
26377
- const ListBranchResponse = z.object({
26378
- name: z.string(),
26379
- protected: z.boolean().optional().default(false),
26380
- githubPullRequestUrl: z.string().optional()
26381
- }).array().nonempty();
26382
- const IndexStatusResponse = z.object({
26383
- status: z.union([
26384
- z.literal("complete"),
26385
- z.literal("unknown"),
26386
- z.literal("failed"),
26387
- z.literal("inprogress")
26388
- ]).optional(),
26389
- timestamp: z.number().optional()
26390
- });
26391
26671
  function asyncPoll(fn, pollInterval = 5 * 1e3, pollTimeout = 30 * 1e3) {
26392
26672
  const endTime = (/* @__PURE__ */ new Date()).getTime() + pollTimeout;
26393
26673
  let stop = false;
@@ -26412,9 +26692,251 @@ function asyncPoll(fn, pollInterval = 5 * 1e3, pollTimeout = 30 * 1e3) {
26412
26692
  };
26413
26693
  return [new Promise(checkCondition), cancel];
26414
26694
  }
26695
+ function popupWindow(url, title, window2, w, h) {
26696
+ const y = window2.top.outerHeight / 2 + window2.top.screenY - h / 2;
26697
+ const x = window2.top.outerWidth / 2 + window2.top.screenX - w / 2;
26698
+ return window2.open(
26699
+ url,
26700
+ title,
26701
+ "toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, copyhistory=no, width=" + w + ", height=" + h + ", top=" + y + ", left=" + x
26702
+ );
26703
+ }
26704
+ const TINA_LOGIN_EVENT = "tinaCloudLogin";
26705
+ const AUTH_TOKEN_KEY = "tinacms-auth";
26706
+ const authenticate = (clientId, frontendUrl) => {
26707
+ return new Promise((resolve) => {
26708
+ let authTab;
26709
+ window.addEventListener("message", function(e) {
26710
+ if (e.data.source === TINA_LOGIN_EVENT) {
26711
+ if (authTab) {
26712
+ authTab.close();
26713
+ }
26714
+ resolve({
26715
+ id_token: e.data.id_token,
26716
+ access_token: e.data.access_token,
26717
+ refresh_token: e.data.refresh_token
26718
+ });
26719
+ }
26720
+ });
26721
+ const origin = `${window.location.protocol}//${window.location.host}`;
26722
+ authTab = popupWindow(
26723
+ `${frontendUrl}/signin?clientId=${clientId}&origin=${origin}`,
26724
+ "_blank",
26725
+ window,
26726
+ 1e3,
26727
+ 700
26728
+ );
26729
+ });
26730
+ };
26731
+ const DefaultSessionProvider = ({
26732
+ children
26733
+ }) => /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children);
26734
+ class AbstractAuthProvider {
26735
+ /**
26736
+ * Wraps the normal fetch function with same API but adds the authorization header token.
26737
+ *
26738
+ * @example
26739
+ * const test = await tinaCloudClient.fetchWithToken(`/mycustomAPI/thing/one`) // the token will be passed in the authorization header
26740
+ *
26741
+ * @param input fetch function input
26742
+ * @param init fetch function init
26743
+ */
26744
+ async fetchWithToken(input, init) {
26745
+ const headers2 = (init == null ? void 0 : init.headers) || {};
26746
+ const token = await this.getToken();
26747
+ if (token == null ? void 0 : token.id_token) {
26748
+ headers2["Authorization"] = "Bearer " + (token == null ? void 0 : token.id_token);
26749
+ }
26750
+ return await fetch(input, {
26751
+ ...init || {},
26752
+ headers: new Headers(headers2)
26753
+ });
26754
+ }
26755
+ async authorize(context) {
26756
+ return this.getToken();
26757
+ }
26758
+ async isAuthorized(context) {
26759
+ return !!await this.authorize(context);
26760
+ }
26761
+ async isAuthenticated() {
26762
+ return !!await this.getUser();
26763
+ }
26764
+ getLoginStrategy() {
26765
+ return "Redirect";
26766
+ }
26767
+ getSessionProvider() {
26768
+ return DefaultSessionProvider;
26769
+ }
26770
+ }
26771
+ class TinaCloudAuthProvider extends AbstractAuthProvider {
26772
+ constructor({
26773
+ clientId,
26774
+ identityApiUrl,
26775
+ tokenStorage = "MEMORY",
26776
+ frontendUrl,
26777
+ ...options
26778
+ }) {
26779
+ super();
26780
+ this.frontendUrl = frontendUrl;
26781
+ this.clientId = clientId;
26782
+ this.identityApiUrl = identityApiUrl;
26783
+ switch (tokenStorage) {
26784
+ case "LOCAL_STORAGE":
26785
+ this.getToken = async function() {
26786
+ const tokens = localStorage.getItem(AUTH_TOKEN_KEY) || null;
26787
+ if (tokens) {
26788
+ return await this.getRefreshedToken(tokens);
26789
+ } else {
26790
+ return {
26791
+ access_token: null,
26792
+ id_token: null,
26793
+ refresh_token: null
26794
+ };
26795
+ }
26796
+ };
26797
+ this.setToken = function(token) {
26798
+ localStorage.setItem(AUTH_TOKEN_KEY, JSON.stringify(token, null, 2));
26799
+ };
26800
+ break;
26801
+ case "MEMORY":
26802
+ this.getToken = async () => {
26803
+ if (this.token) {
26804
+ return await this.getRefreshedToken(this.token);
26805
+ } else {
26806
+ return {
26807
+ access_token: null,
26808
+ id_token: null,
26809
+ refresh_token: null
26810
+ };
26811
+ }
26812
+ };
26813
+ this.setToken = (token) => {
26814
+ this.token = JSON.stringify(token, null, 2);
26815
+ };
26816
+ break;
26817
+ case "CUSTOM":
26818
+ if (!options.getTokenFn) {
26819
+ throw new Error(
26820
+ "When CUSTOM token storage is selected, a getTokenFn must be provided"
26821
+ );
26822
+ }
26823
+ this.getToken = options.getTokenFn;
26824
+ break;
26825
+ }
26826
+ }
26827
+ async authenticate() {
26828
+ const token = await authenticate(this.clientId, this.frontendUrl);
26829
+ this.setToken(token);
26830
+ return token;
26831
+ }
26832
+ async getUser() {
26833
+ if (!this.clientId) {
26834
+ return null;
26835
+ }
26836
+ const url = `${this.identityApiUrl}/v2/apps/${this.clientId}/currentUser`;
26837
+ try {
26838
+ const res = await this.fetchWithToken(url, {
26839
+ method: "GET"
26840
+ });
26841
+ const val = await res.json();
26842
+ if (!res.status.toString().startsWith("2")) {
26843
+ console.error(val.error);
26844
+ return null;
26845
+ }
26846
+ return val;
26847
+ } catch (e) {
26848
+ console.error(e);
26849
+ return null;
26850
+ }
26851
+ }
26852
+ async logout() {
26853
+ this.setToken(null);
26854
+ }
26855
+ async getRefreshedToken(tokens) {
26856
+ const { access_token, id_token, refresh_token } = JSON.parse(tokens);
26857
+ const { exp, iss, client_id } = this.parseJwt(access_token);
26858
+ if (Date.now() / 1e3 >= exp - 120) {
26859
+ const refreshResponse = await fetch(iss, {
26860
+ method: "POST",
26861
+ headers: {
26862
+ "Content-Type": "application/x-amz-json-1.1",
26863
+ "x-amz-target": "AWSCognitoIdentityProviderService.InitiateAuth"
26864
+ },
26865
+ body: JSON.stringify({
26866
+ ClientId: client_id,
26867
+ AuthFlow: "REFRESH_TOKEN_AUTH",
26868
+ AuthParameters: {
26869
+ REFRESH_TOKEN: refresh_token,
26870
+ DEVICE_KEY: null
26871
+ }
26872
+ })
26873
+ });
26874
+ if (refreshResponse.status !== 200) {
26875
+ throw new Error("Unable to refresh auth tokens");
26876
+ }
26877
+ const responseJson = await refreshResponse.json();
26878
+ const newToken = {
26879
+ access_token: responseJson.AuthenticationResult.AccessToken,
26880
+ id_token: responseJson.AuthenticationResult.IdToken,
26881
+ refresh_token
26882
+ };
26883
+ this.setToken(newToken);
26884
+ return Promise.resolve(newToken);
26885
+ }
26886
+ return Promise.resolve({ access_token, id_token, refresh_token });
26887
+ }
26888
+ parseJwt(token) {
26889
+ const base64Url = token.split(".")[1];
26890
+ const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
26891
+ const jsonPayload = decodeURIComponent(
26892
+ atob(base64).split("").map(function(c) {
26893
+ return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
26894
+ }).join("")
26895
+ );
26896
+ return JSON.parse(jsonPayload);
26897
+ }
26898
+ }
26899
+ const LOCAL_CLIENT_KEY = "tina.local.isLogedIn";
26900
+ class LocalAuthProvider extends AbstractAuthProvider {
26901
+ constructor() {
26902
+ super();
26903
+ }
26904
+ async authenticate() {
26905
+ localStorage.setItem(LOCAL_CLIENT_KEY, "true");
26906
+ return { access_token: "LOCAL", id_token: "LOCAL", refresh_token: "LOCAL" };
26907
+ }
26908
+ async getUser() {
26909
+ return localStorage.getItem(LOCAL_CLIENT_KEY) === "true";
26910
+ }
26911
+ async getToken() {
26912
+ return Promise.resolve({ id_token: "" });
26913
+ }
26914
+ async logout() {
26915
+ localStorage.removeItem(LOCAL_CLIENT_KEY);
26916
+ }
26917
+ }
26918
+ const captureBranchName = /^refs\/heads\/(.*)/;
26919
+ const parseRefForBranchName = (ref) => {
26920
+ const matches = ref.match(captureBranchName);
26921
+ return matches[1];
26922
+ };
26923
+ const ListBranchResponse = z.object({
26924
+ name: z.string(),
26925
+ protected: z.boolean().optional().default(false),
26926
+ githubPullRequestUrl: z.string().optional()
26927
+ }).array().nonempty();
26928
+ const IndexStatusResponse = z.object({
26929
+ status: z.union([
26930
+ z.literal("complete"),
26931
+ z.literal("unknown"),
26932
+ z.literal("failed"),
26933
+ z.literal("inprogress")
26934
+ ]).optional(),
26935
+ timestamp: z.number().optional()
26936
+ });
26415
26937
  class Client {
26416
26938
  constructor({ tokenStorage = "MEMORY", ...options }) {
26417
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X;
26939
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
26418
26940
  this.events = new EventBus();
26419
26941
  this.protectedBranches = [];
26420
26942
  this.usingEditorialWorkflow = false;
@@ -26468,20 +26990,8 @@ mutation addPendingDocumentMutation(
26468
26990
  return parse$3(data.getOptimizedQuery);
26469
26991
  };
26470
26992
  this.tinaGraphQLVersion = options.tinaGraphQLVersion;
26471
- this.onLogin = (_d = (_c = (_b = (_a = options.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.admin) == null ? void 0 : _c.auth) == null ? void 0 : _d.onLogin;
26472
- this.onLogout = (_h = (_g = (_f = (_e = options.schema) == null ? void 0 : _e.config) == null ? void 0 : _f.admin) == null ? void 0 : _g.auth) == null ? void 0 : _h.onLogout;
26473
- if ((_l = (_k = (_j = (_i = options.schema) == null ? void 0 : _i.config) == null ? void 0 : _j.admin) == null ? void 0 : _k.auth) == null ? void 0 : _l.logout) {
26474
- this.onLogout = (_p = (_o = (_n = (_m = options.schema) == null ? void 0 : _m.config) == null ? void 0 : _n.admin) == null ? void 0 : _o.auth) == null ? void 0 : _p.logout;
26475
- }
26476
- if ((_t = (_s = (_r = (_q = options.schema) == null ? void 0 : _q.config) == null ? void 0 : _r.admin) == null ? void 0 : _s.auth) == null ? void 0 : _t.getUser) {
26477
- this.getUser = (_x = (_w = (_v = (_u = options.schema) == null ? void 0 : _u.config) == null ? void 0 : _v.admin) == null ? void 0 : _w.auth) == null ? void 0 : _x.getUser;
26478
- }
26479
- if ((_B = (_A = (_z = (_y = options.schema) == null ? void 0 : _y.config) == null ? void 0 : _z.admin) == null ? void 0 : _A.auth) == null ? void 0 : _B.authenticate) {
26480
- this.authenticate = (_F = (_E = (_D = (_C = options.schema) == null ? void 0 : _C.config) == null ? void 0 : _D.admin) == null ? void 0 : _E.auth) == null ? void 0 : _F.authenticate;
26481
- }
26482
- if ((_J = (_I = (_H = (_G = options.schema) == null ? void 0 : _G.config) == null ? void 0 : _H.admin) == null ? void 0 : _I.auth) == null ? void 0 : _J.authorize) {
26483
- this.authorize = (_N = (_M = (_L = (_K = options.schema) == null ? void 0 : _K.config) == null ? void 0 : _L.admin) == null ? void 0 : _M.auth) == null ? void 0 : _N.authorize;
26484
- }
26993
+ this.onLogin = ((_d = (_c = (_b = (_a = options.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.admin) == null ? void 0 : _c.authHooks) == null ? void 0 : _d.onLogin) || ((_h = (_g = (_f = (_e = options.schema) == null ? void 0 : _e.config) == null ? void 0 : _f.admin) == null ? void 0 : _g.auth) == null ? void 0 : _h.onLogin);
26994
+ this.onLogout = ((_l = (_k = (_j = (_i = options.schema) == null ? void 0 : _i.config) == null ? void 0 : _j.admin) == null ? void 0 : _k.authHooks) == null ? void 0 : _l.onLogout) || ((_p = (_o = (_n = (_m = options.schema) == null ? void 0 : _m.config) == null ? void 0 : _n.admin) == null ? void 0 : _o.auth) == null ? void 0 : _p.onLogout);
26485
26995
  if (options.schema) {
26486
26996
  const enrichedSchema = new TinaSchema({
26487
26997
  version: { fullVersion: "", major: "", minor: "", patch: "" },
@@ -26491,7 +27001,7 @@ mutation addPendingDocumentMutation(
26491
27001
  this.schema = enrichedSchema;
26492
27002
  }
26493
27003
  this.options = options;
26494
- if ((_P = (_O = options.schema) == null ? void 0 : _O.config) == null ? void 0 : _P.contentApiUrlOverride) {
27004
+ if ((_r = (_q = options.schema) == null ? void 0 : _q.config) == null ? void 0 : _r.contentApiUrlOverride) {
26495
27005
  this.options.customContentApiUrl = options.schema.config.contentApiUrlOverride;
26496
27006
  }
26497
27007
  this.setBranch(options.branch);
@@ -26502,52 +27012,13 @@ mutation addPendingDocumentMutation(
26502
27012
  }
26503
27013
  );
26504
27014
  this.clientId = options.clientId;
26505
- switch (tokenStorage) {
26506
- case "LOCAL_STORAGE":
26507
- this.getToken = async function() {
26508
- const tokens = localStorage.getItem(AUTH_TOKEN_KEY) || null;
26509
- if (tokens) {
26510
- return await this.getRefreshedToken(tokens);
26511
- } else {
26512
- return {
26513
- access_token: null,
26514
- id_token: null,
26515
- refresh_token: null
26516
- };
26517
- }
26518
- };
26519
- this.setToken = function(token) {
26520
- localStorage.setItem(AUTH_TOKEN_KEY, JSON.stringify(token, null, 2));
26521
- };
26522
- break;
26523
- case "MEMORY":
26524
- this.getToken = async () => {
26525
- if (this.token) {
26526
- return await this.getRefreshedToken(this.token);
26527
- } else {
26528
- return {
26529
- access_token: null,
26530
- id_token: null,
26531
- refresh_token: null
26532
- };
26533
- }
26534
- };
26535
- this.setToken = (token) => {
26536
- this.token = JSON.stringify(token, null, 2);
26537
- };
26538
- break;
26539
- case "CUSTOM":
26540
- if (!options.getTokenFn) {
26541
- throw new Error(
26542
- "When CUSTOM token storage is selected, a getTokenFn must be provided"
26543
- );
26544
- }
26545
- this.getToken = options.getTokenFn;
26546
- break;
26547
- }
26548
- if ((_T = (_S = (_R = (_Q = options.schema) == null ? void 0 : _Q.config) == null ? void 0 : _R.admin) == null ? void 0 : _S.auth) == null ? void 0 : _T.getToken) {
26549
- this.getToken = (_X = (_W = (_V = (_U = options.schema) == null ? void 0 : _U.config) == null ? void 0 : _V.admin) == null ? void 0 : _W.auth) == null ? void 0 : _X.getToken;
26550
- }
27015
+ this.authProvider = ((_u = (_t = (_s = this.schema) == null ? void 0 : _s.config) == null ? void 0 : _t.config) == null ? void 0 : _u.authProvider) || new TinaCloudAuthProvider({
27016
+ clientId: options.clientId,
27017
+ identityApiUrl: this.identityApiUrl,
27018
+ getTokenFn: options.getTokenFn,
27019
+ tokenStorage,
27020
+ frontendUrl: this.frontendUrl
27021
+ });
26551
27022
  }
26552
27023
  get isLocalMode() {
26553
27024
  return false;
@@ -26564,12 +27035,16 @@ mutation addPendingDocumentMutation(
26564
27035
  this.identityApiUrl = ((_c = this.options.tinaioConfig) == null ? void 0 : _c.identityApiUrlOverride) || "https://identity.tinajs.io";
26565
27036
  this.contentApiBase = ((_d = this.options.tinaioConfig) == null ? void 0 : _d.contentApiUrlOverride) || `https://content.tinajs.io`;
26566
27037
  this.contentApiUrl = this.options.customContentApiUrl || `${this.contentApiBase}/${this.tinaGraphQLVersion}/content/${this.options.clientId}/github/${encodedBranch}`;
27038
+ if (this.authProvider instanceof TinaCloudAuthProvider) {
27039
+ this.authProvider.identityApiUrl = this.identityApiUrl;
27040
+ this.authProvider.frontendUrl = this.frontendUrl;
27041
+ }
26567
27042
  }
26568
27043
  getBranch() {
26569
27044
  return this.branch;
26570
27045
  }
26571
27046
  async request(query, { variables }) {
26572
- const token = await this.getToken();
27047
+ const token = await this.authProvider.getToken();
26573
27048
  const headers2 = {
26574
27049
  "Content-Type": "application/json"
26575
27050
  };
@@ -26616,7 +27091,7 @@ mutation addPendingDocumentMutation(
26616
27091
  async checkSyncStatus({
26617
27092
  assetsSyncing
26618
27093
  }) {
26619
- const res = await this.fetchWithToken(
27094
+ const res = await this.authProvider.fetchWithToken(
26620
27095
  `${this.assetsApiUrl}/v1/${this.clientId}/syncStatus`,
26621
27096
  {
26622
27097
  method: "POST",
@@ -26630,7 +27105,7 @@ mutation addPendingDocumentMutation(
26630
27105
  return jsonRes;
26631
27106
  }
26632
27107
  async getProject() {
26633
- const res = await this.fetchWithToken(
27108
+ const res = await this.authProvider.fetchWithToken(
26634
27109
  `${this.identityApiUrl}/v2/apps/${this.clientId}`,
26635
27110
  {
26636
27111
  method: "GET"
@@ -26646,7 +27121,7 @@ mutation addPendingDocumentMutation(
26646
27121
  }) {
26647
27122
  const url = `${this.contentApiBase}/github/${this.clientId}/create_pull_request`;
26648
27123
  try {
26649
- const res = await this.fetchWithToken(url, {
27124
+ const res = await this.authProvider.fetchWithToken(url, {
26650
27125
  method: "POST",
26651
27126
  body: JSON.stringify({
26652
27127
  baseBranch,
@@ -26675,119 +27150,19 @@ mutation addPendingDocumentMutation(
26675
27150
  events: []
26676
27151
  };
26677
27152
  } else {
26678
- return (await this.fetchWithToken(
27153
+ return (await this.authProvider.fetchWithToken(
26679
27154
  `${this.contentApiBase}/events/${this.clientId}/${this.branch}?limit=${limit || 1}${cursor ? `&cursor=${cursor}` : ""}`,
26680
27155
  { method: "GET" }
26681
27156
  )).json();
26682
27157
  }
26683
27158
  }
26684
- parseJwt(token) {
26685
- const base64Url = token.split(".")[1];
26686
- const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
26687
- const jsonPayload = decodeURIComponent(
26688
- atob(base64).split("").map(function(c) {
26689
- return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
26690
- }).join("")
26691
- );
26692
- return JSON.parse(jsonPayload);
26693
- }
26694
- async getRefreshedToken(tokens) {
26695
- const { access_token, id_token, refresh_token } = JSON.parse(tokens);
26696
- const { exp, iss, client_id } = this.parseJwt(access_token);
26697
- if (Date.now() / 1e3 >= exp - 120) {
26698
- const refreshResponse = await fetch(iss, {
26699
- method: "POST",
26700
- headers: {
26701
- "Content-Type": "application/x-amz-json-1.1",
26702
- "x-amz-target": "AWSCognitoIdentityProviderService.InitiateAuth"
26703
- },
26704
- body: JSON.stringify({
26705
- ClientId: client_id,
26706
- AuthFlow: "REFRESH_TOKEN_AUTH",
26707
- AuthParameters: {
26708
- REFRESH_TOKEN: refresh_token,
26709
- DEVICE_KEY: null
26710
- }
26711
- })
26712
- });
26713
- if (refreshResponse.status !== 200) {
26714
- throw new Error("Unable to refresh auth tokens");
26715
- }
26716
- const responseJson = await refreshResponse.json();
26717
- const newToken = {
26718
- access_token: responseJson.AuthenticationResult.AccessToken,
26719
- id_token: responseJson.AuthenticationResult.IdToken,
26720
- refresh_token
26721
- };
26722
- this.setToken(newToken);
26723
- return Promise.resolve(newToken);
26724
- }
26725
- return Promise.resolve({ access_token, id_token, refresh_token });
26726
- }
26727
- async isAuthorized(context) {
26728
- return !!await this.authorize(context);
26729
- }
26730
- async isAuthenticated() {
26731
- return !!await this.getUser();
26732
- }
26733
- async logout() {
26734
- this.setToken(null);
26735
- }
26736
- async authenticate() {
26737
- const token = await authenticate(this.clientId, this.frontendUrl);
26738
- this.setToken(token);
26739
- return token;
26740
- }
26741
- async authorize(context) {
26742
- return this.getToken();
26743
- }
26744
- /**
26745
- * Wraps the normal fetch function with same API but adds the authorization header token.
26746
- *
26747
- * @example
26748
- * const test = await tinaCloudClient.fetchWithToken(`/mycustomAPI/thing/one`) // the token will be passed in the authorization header
26749
- *
26750
- * @param input fetch function input
26751
- * @param init fetch function init
26752
- */
26753
- async fetchWithToken(input, init) {
26754
- const headers2 = (init == null ? void 0 : init.headers) || {};
26755
- const token = await this.getToken();
26756
- if (token == null ? void 0 : token.id_token) {
26757
- headers2["Authorization"] = "Bearer " + (token == null ? void 0 : token.id_token);
26758
- }
26759
- return await fetch(input, {
26760
- ...init,
26761
- headers: new Headers(headers2)
26762
- });
26763
- }
26764
- async getUser() {
26765
- if (!this.clientId) {
26766
- return null;
26767
- }
26768
- const url = `${this.identityApiUrl}/v2/apps/${this.clientId}/currentUser`;
26769
- try {
26770
- const res = await this.fetchWithToken(url, {
26771
- method: "GET"
26772
- });
26773
- const val = await res.json();
26774
- if (!res.status.toString().startsWith("2")) {
26775
- console.error(val.error);
26776
- return null;
26777
- }
26778
- return val;
26779
- } catch (e) {
26780
- console.error(e);
26781
- return null;
26782
- }
26783
- }
26784
27159
  async getBillingState() {
26785
27160
  if (!this.clientId) {
26786
27161
  return null;
26787
27162
  }
26788
27163
  const url = `${this.identityApiUrl}/v2/apps/${this.clientId}/billing/state`;
26789
27164
  try {
26790
- const res = await this.fetchWithToken(url, {
27165
+ const res = await this.authProvider.fetchWithToken(url, {
26791
27166
  method: "GET"
26792
27167
  });
26793
27168
  const val = await res.json();
@@ -26853,7 +27228,7 @@ mutation addPendingDocumentMutation(
26853
27228
  }
26854
27229
  async getIndexStatus({ ref }) {
26855
27230
  const url = `${this.contentApiBase}/db/${this.clientId}/status/${ref}`;
26856
- const res = await this.fetchWithToken(url);
27231
+ const res = await this.authProvider.fetchWithToken(url);
26857
27232
  const result = await res.json();
26858
27233
  const parsedResult = IndexStatusResponse.parse(result);
26859
27234
  return parsedResult;
@@ -26861,7 +27236,7 @@ mutation addPendingDocumentMutation(
26861
27236
  async listBranches(args) {
26862
27237
  try {
26863
27238
  const url = `${this.contentApiBase}/github/${this.clientId}/list_branches`;
26864
- const res = await this.fetchWithToken(url, {
27239
+ const res = await this.authProvider.fetchWithToken(url, {
26865
27240
  method: "GET"
26866
27241
  });
26867
27242
  const branches = await res.json();
@@ -26891,7 +27266,7 @@ mutation addPendingDocumentMutation(
26891
27266
  async createBranch({ baseBranch, branchName }) {
26892
27267
  const url = `${this.contentApiBase}/github/${this.clientId}/create_branch`;
26893
27268
  try {
26894
- const res = await this.fetchWithToken(url, {
27269
+ const res = await this.authProvider.fetchWithToken(url, {
26895
27270
  method: "POST",
26896
27271
  body: JSON.stringify({
26897
27272
  baseBranch,
@@ -26915,9 +27290,9 @@ mutation addPendingDocumentMutation(
26915
27290
  }
26916
27291
  }
26917
27292
  const DEFAULT_LOCAL_TINA_GQL_SERVER_URL = "http://localhost:4001/graphql";
26918
- const LOCAL_CLIENT_KEY = "tina.local.isLogedIn";
26919
27293
  class LocalClient extends Client {
26920
27294
  constructor(props) {
27295
+ var _a, _b, _c;
26921
27296
  const clientProps = {
26922
27297
  ...props,
26923
27298
  clientId: "",
@@ -26926,21 +27301,11 @@ class LocalClient extends Client {
26926
27301
  customContentApiUrl: props && props.customContentApiUrl ? props.customContentApiUrl : DEFAULT_LOCAL_TINA_GQL_SERVER_URL
26927
27302
  };
26928
27303
  super(clientProps);
27304
+ this.authProvider = ((_c = (_b = (_a = this.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.config) == null ? void 0 : _c.authProvider) || new LocalAuthProvider();
26929
27305
  }
26930
27306
  get isLocalMode() {
26931
27307
  return true;
26932
27308
  }
26933
- // These functions allow the local client to have a login state so that we can correctly call the "OnLogin" callback. This is important for things like preview mode
26934
- async logout() {
26935
- localStorage.removeItem(LOCAL_CLIENT_KEY);
26936
- }
26937
- async authenticate() {
26938
- localStorage.setItem(LOCAL_CLIENT_KEY, "true");
26939
- return { access_token: "LOCAL", id_token: "LOCAL", refresh_token: "LOCAL" };
26940
- }
26941
- async getUser() {
26942
- return localStorage.getItem(LOCAL_CLIENT_KEY) === "true";
26943
- }
26944
27309
  }
26945
27310
  class TinaCMSSearchClient {
26946
27311
  constructor(client, tinaSearchConfig) {
@@ -26955,13 +27320,13 @@ class TinaCMSSearchClient {
26955
27320
  );
26956
27321
  const opt = optionsToSearchIndexOptions(options);
26957
27322
  const optionsParam = opt["PAGE"] ? `&options=${JSON.stringify(opt)}` : "";
26958
- const res = await this.client.fetchWithToken(
27323
+ const res = await this.client.authProvider.fetchWithToken(
26959
27324
  `${this.client.contentApiBase}/searchIndex/${this.client.clientId}/${this.client.getBranch()}?q=${JSON.stringify(q)}${optionsParam}`
26960
27325
  );
26961
27326
  return parseSearchIndexResponse(await res.json(), options);
26962
27327
  }
26963
27328
  async del(ids) {
26964
- const res = await this.client.fetchWithToken(
27329
+ const res = await this.client.authProvider.fetchWithToken(
26965
27330
  `${this.client.contentApiBase}/searchIndex/${this.client.clientId}/${this.client.getBranch()}?ids=${ids.join(",")}`,
26966
27331
  {
26967
27332
  method: "DELETE"
@@ -26972,7 +27337,7 @@ class TinaCMSSearchClient {
26972
27337
  }
26973
27338
  }
26974
27339
  async put(docs) {
26975
- const res = await this.client.fetchWithToken(
27340
+ const res = await this.client.authProvider.fetchWithToken(
26976
27341
  `${this.client.contentApiBase}/searchIndex/${this.client.clientId}/${this.client.getBranch()}`,
26977
27342
  {
26978
27343
  method: "POST",
@@ -26998,7 +27363,7 @@ class LocalSearchClient {
26998
27363
  const q = queryToSearchIndexQuery(query);
26999
27364
  const opt = optionsToSearchIndexOptions(options);
27000
27365
  const optionsParam = opt["PAGE"] ? `&options=${JSON.stringify(opt)}` : "";
27001
- const res = await this.client.fetchWithToken(
27366
+ const res = await this.client.authProvider.fetchWithToken(
27002
27367
  `http://localhost:4001/searchIndex?q=${JSON.stringify(q)}${optionsParam}`
27003
27368
  );
27004
27369
  return parseSearchIndexResponse(await res.json(), options);
@@ -27014,12 +27379,19 @@ class LocalSearchClient {
27014
27379
  }
27015
27380
  }
27016
27381
  function ModalBuilder(modalProps) {
27017
- return /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(ModalPopup, null, /* @__PURE__ */ React__default.createElement(ModalHeader, null, modalProps.title), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("p", null, modalProps.message), modalProps.error && /* @__PURE__ */ React__default.createElement(ErrorLabel, null, modalProps.error)), /* @__PURE__ */ React__default.createElement(ModalActions, null, modalProps.actions.map((action) => /* @__PURE__ */ React__default.createElement(AsyncButton, { key: action.name, ...action })))));
27382
+ return /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(ModalPopup, null, /* @__PURE__ */ React__default.createElement(ModalHeader, null, modalProps.title), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, modalProps.message && /* @__PURE__ */ React__default.createElement("p", null, modalProps.message), modalProps.error && /* @__PURE__ */ React__default.createElement(ErrorLabel, null, modalProps.error), modalProps.children), /* @__PURE__ */ React__default.createElement(ModalActions, null, modalProps.actions.map((action) => /* @__PURE__ */ React__default.createElement(AsyncButton, { key: action.name, ...action })))));
27018
27383
  }
27019
27384
  const ErrorLabel = ({ style = {}, ...props }) => /* @__PURE__ */ React__default.createElement("p", { style: { ...style, color: "var(--tina-color-error)" }, ...props });
27020
27385
  const AsyncButton = ({ name, primary, action }) => {
27021
27386
  const [submitting, setSubmitting] = useState(false);
27387
+ const [mounted, setMounted] = useState(false);
27388
+ useEffect(() => {
27389
+ setMounted(true);
27390
+ return () => setMounted(false);
27391
+ }, []);
27022
27392
  const onClick = useCallback(async () => {
27393
+ if (!mounted)
27394
+ return;
27023
27395
  setSubmitting(true);
27024
27396
  try {
27025
27397
  await action();
@@ -27028,7 +27400,7 @@ const AsyncButton = ({ name, primary, action }) => {
27028
27400
  setSubmitting(false);
27029
27401
  throw e;
27030
27402
  }
27031
- }, [action, setSubmitting]);
27403
+ }, [action, setSubmitting, mounted]);
27032
27404
  return /* @__PURE__ */ React__default.createElement(
27033
27405
  Button,
27034
27406
  {
@@ -27104,7 +27476,7 @@ class TinaAdminApi {
27104
27476
  }
27105
27477
  }
27106
27478
  async isAuthenticated() {
27107
- return await this.api.isAuthenticated();
27479
+ return await this.api.authProvider.isAuthenticated();
27108
27480
  }
27109
27481
  async checkGraphqlSchema({ localSchema }) {
27110
27482
  const schemaFromCloud = await this.api.getSchema();
@@ -27426,17 +27798,29 @@ const AuthWallInner = ({
27426
27798
  loginScreen,
27427
27799
  getModalActions
27428
27800
  }) => {
27429
- var _a, _b, _c, _d, _e;
27801
+ var _a, _b, _c;
27430
27802
  const client = cms.api.tina;
27431
- const isTinaCloud = !client.isLocalMode && !((_e = (_d = (_c = (_b = (_a = client.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.config) == null ? void 0 : _c.admin) == null ? void 0 : _d.auth) == null ? void 0 : _e.customAuth);
27803
+ const isTinaCloud = !client.isLocalMode && !((_c = (_b = (_a = client.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.config) == null ? void 0 : _c.contentApiUrlOverride);
27804
+ const loginStrategy = client.authProvider.getLoginStrategy();
27432
27805
  const [activeModal, setActiveModal] = useState(null);
27433
27806
  const [errorMessage, setErrorMessage] = useState();
27434
27807
  const [showChildren, setShowChildren] = useState(false);
27808
+ const [authProps, setAuthProps] = useState({ username: "", password: "" });
27809
+ const [authenticated, setAuthenticated] = useState(false);
27435
27810
  React__default.useEffect(() => {
27436
- client.isAuthenticated().then((isAuthenticated) => {
27811
+ let mounted = true;
27812
+ client.authProvider.isAuthenticated().then((isAuthenticated) => {
27813
+ if (!mounted)
27814
+ return;
27437
27815
  if (isAuthenticated) {
27438
- client.isAuthorized().then((isAuthorized) => {
27816
+ client.authProvider.isAuthorized().then(async (isAuthorized) => {
27817
+ if (!mounted)
27818
+ return;
27439
27819
  if (isAuthorized) {
27820
+ const user = await client.authProvider.getUser();
27821
+ if (user.passwordChangeRequired) {
27822
+ window.location.hash = "#/screens/change_password";
27823
+ }
27440
27824
  setShowChildren(true);
27441
27825
  cms.enable();
27442
27826
  } else {
@@ -27447,6 +27831,8 @@ const AuthWallInner = ({
27447
27831
  setActiveModal("error");
27448
27832
  }
27449
27833
  }).catch((e) => {
27834
+ if (!mounted)
27835
+ return;
27450
27836
  console.error(e);
27451
27837
  setErrorMessage({ title: "Unexpected Error:", message: `${e}` });
27452
27838
  setActiveModal("error");
@@ -27457,33 +27843,59 @@ const AuthWallInner = ({
27457
27843
  });
27458
27844
  }
27459
27845
  }).catch((e) => {
27846
+ if (!mounted)
27847
+ return;
27460
27848
  console.error(e);
27461
27849
  setErrorMessage({ title: "Unexpected Error:", message: `${e}` });
27462
27850
  setActiveModal("error");
27463
27851
  });
27464
- }, []);
27852
+ return () => {
27853
+ mounted = false;
27854
+ };
27855
+ }, [authenticated]);
27465
27856
  const onAuthenticated = async () => {
27466
- if (await client.isAuthorized()) {
27467
- setShowChildren(true);
27468
- setActiveModal(null);
27469
- cms.events.dispatch({ type: "cms:login" });
27470
- } else {
27471
- setErrorMessage({
27472
- title: "Access Denied:",
27473
- message: "Not Authorized To Edit"
27474
- });
27475
- setActiveModal("error");
27476
- }
27857
+ setAuthenticated(true);
27858
+ setActiveModal(null);
27859
+ cms.events.dispatch({ type: "cms:login" });
27477
27860
  };
27478
27861
  const otherModalActions = getModalActions ? getModalActions({
27479
27862
  closeModal: () => {
27480
27863
  setActiveModal(null);
27481
27864
  }
27482
27865
  }) : [];
27483
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, activeModal === "authenticate" && /* @__PURE__ */ React__default.createElement(
27866
+ const handleAuthenticate = async () => {
27867
+ try {
27868
+ setAuthenticated(false);
27869
+ const token = await client.authProvider.authenticate(authProps);
27870
+ if (typeof (client == null ? void 0 : client.onLogin) === "function") {
27871
+ await (client == null ? void 0 : client.onLogin({ token }));
27872
+ }
27873
+ return onAuthenticated();
27874
+ } catch (e) {
27875
+ console.error(e);
27876
+ setActiveModal("error");
27877
+ setErrorMessage({
27878
+ title: "Authentication Error",
27879
+ message: `${e}`
27880
+ });
27881
+ }
27882
+ };
27883
+ let modalTitle = "Tina Cloud Authorization";
27884
+ if (activeModal === "authenticate" && loginStrategy === "Redirect" && !isTinaCloud) {
27885
+ modalTitle = "Enter into edit mode";
27886
+ } else if (activeModal === "authenticate" && loginStrategy === "UsernamePassword") {
27887
+ modalTitle = "Sign in to Tina";
27888
+ } else if (activeModal === "error") {
27889
+ if (loginStrategy === "Redirect" && !isTinaCloud) {
27890
+ modalTitle = "Enter into edit mode";
27891
+ } else if (loginStrategy === "UsernamePassword") {
27892
+ modalTitle = "Sign in to Tina";
27893
+ }
27894
+ }
27895
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, activeModal === "authenticate" && loginStrategy === "Redirect" && /* @__PURE__ */ React__default.createElement(
27484
27896
  ModalBuilder,
27485
27897
  {
27486
- title: isTinaCloud ? "Tina Cloud Authorization" : "Enter into edit mode",
27898
+ title: modalTitle,
27487
27899
  message: isTinaCloud ? "To save edits, Tina Cloud authorization is required. On save, changes will get committed using your account." : "To save edits, enter into edit mode. On save, changes will saved to the local filesystem.",
27488
27900
  close,
27489
27901
  actions: [
@@ -27498,30 +27910,61 @@ const AuthWallInner = ({
27498
27910
  },
27499
27911
  {
27500
27912
  name: isTinaCloud ? "Continue to Tina Cloud" : "Enter Edit Mode",
27501
- action: async () => {
27502
- try {
27503
- const token = await client.authenticate();
27504
- if (typeof (client == null ? void 0 : client.onLogin) === "function") {
27505
- await (client == null ? void 0 : client.onLogin({ token }));
27506
- }
27507
- return onAuthenticated();
27508
- } catch (e) {
27509
- console.error(e);
27510
- setActiveModal("error");
27511
- setErrorMessage({
27512
- title: "Unexpected Error:",
27513
- message: `${e}`
27514
- });
27515
- }
27516
- },
27913
+ action: handleAuthenticate,
27517
27914
  primary: true
27518
27915
  }
27519
27916
  ]
27520
27917
  }
27918
+ ), activeModal === "authenticate" && loginStrategy === "UsernamePassword" && /* @__PURE__ */ React__default.createElement(
27919
+ ModalBuilder,
27920
+ {
27921
+ title: modalTitle,
27922
+ message: "",
27923
+ close,
27924
+ actions: [
27925
+ ...otherModalActions,
27926
+ {
27927
+ name: "Login",
27928
+ action: handleAuthenticate,
27929
+ primary: true
27930
+ }
27931
+ ]
27932
+ },
27933
+ /* @__PURE__ */ React__default.createElement("div", { className: "flex items-center justify-center bg-gray-50 px-4 sm:px-6 lg:px-8" }, /* @__PURE__ */ React__default.createElement("div", { className: "max-w-md w-full space-y-6" }, /* @__PURE__ */ React__default.createElement("label", { className: "block" }, /* @__PURE__ */ React__default.createElement("span", { className: "text-gray-700" }, "Username"), /* @__PURE__ */ React__default.createElement(
27934
+ BaseTextField,
27935
+ {
27936
+ id: "username",
27937
+ name: "username",
27938
+ type: "text",
27939
+ autoComplete: "username",
27940
+ required: true,
27941
+ placeholder: "Username",
27942
+ value: authProps.username,
27943
+ onChange: (e) => setAuthProps((prevState) => ({
27944
+ ...prevState,
27945
+ username: e.target.value
27946
+ }))
27947
+ }
27948
+ )), /* @__PURE__ */ React__default.createElement("label", { className: "block" }, /* @__PURE__ */ React__default.createElement("span", { className: "text-gray-700" }, "Password"), /* @__PURE__ */ React__default.createElement(
27949
+ BaseTextField,
27950
+ {
27951
+ id: "password",
27952
+ name: "password",
27953
+ type: "password",
27954
+ autoComplete: "current-password",
27955
+ required: true,
27956
+ placeholder: "Password",
27957
+ value: authProps.password,
27958
+ onChange: (e) => setAuthProps((prevState) => ({
27959
+ ...prevState,
27960
+ password: e.target.value
27961
+ }))
27962
+ }
27963
+ ))))
27521
27964
  ), activeModal === "error" && errorMessage && /* @__PURE__ */ React__default.createElement(
27522
27965
  ModalBuilder,
27523
27966
  {
27524
- title: isTinaCloud ? "Tina Cloud Authorization" : "Enter into edit mode",
27967
+ title: modalTitle,
27525
27968
  message: errorMessage.title,
27526
27969
  error: errorMessage.message,
27527
27970
  close,
@@ -27533,13 +27976,12 @@ const AuthWallInner = ({
27533
27976
  try {
27534
27977
  setActiveModal(null);
27535
27978
  setErrorMessage(void 0);
27536
- await client.logout();
27537
- await client.onLogout();
27538
- const token = await client.authenticate();
27539
- if (typeof (client == null ? void 0 : client.onLogin) === "function") {
27540
- await (client == null ? void 0 : client.onLogin({ token }));
27979
+ const { authProvider } = client;
27980
+ await authProvider.logout();
27981
+ if (typeof (client == null ? void 0 : client.onLogout) === "function") {
27982
+ await client.onLogout();
27541
27983
  }
27542
- return onAuthenticated();
27984
+ window.location.href = new URL(window.location.href).pathname;
27543
27985
  } catch (e) {
27544
27986
  console.error(e);
27545
27987
  setActiveModal("error");
@@ -27556,7 +27998,7 @@ const AuthWallInner = ({
27556
27998
  ), showChildren ? children : loginScreen ? loginScreen : null);
27557
27999
  };
27558
28000
  const TinaCloudProvider = (props) => {
27559
- var _a, _b, _c, _d, _e;
28001
+ var _a, _b, _c;
27560
28002
  const baseBranch = props.branch || "main";
27561
28003
  const [currentBranch, setCurrentBranch] = useLocalStorage(
27562
28004
  "tinacms-current-branch",
@@ -27579,7 +28021,7 @@ const TinaCloudProvider = (props) => {
27579
28021
  cms.api.tina.setBranch(currentBranch);
27580
28022
  }
27581
28023
  useEffect(() => {
27582
- var _a2, _b2, _c2, _d2, _e2, _f;
28024
+ var _a2, _b2, _c2, _d, _e, _f;
27583
28025
  let searchClient;
27584
28026
  if (props.isLocalClient) {
27585
28027
  searchClient = new LocalSearchClient(cms.api.tina);
@@ -27588,10 +28030,10 @@ const TinaCloudProvider = (props) => {
27588
28030
  if (hasTinaSearch) {
27589
28031
  searchClient = new TinaCMSSearchClient(
27590
28032
  cms.api.tina,
27591
- (_d2 = (_c2 = props.schema.config) == null ? void 0 : _c2.search) == null ? void 0 : _d2.tina
28033
+ (_d = (_c2 = props.schema.config) == null ? void 0 : _c2.search) == null ? void 0 : _d.tina
27592
28034
  );
27593
28035
  } else {
27594
- searchClient = (_f = (_e2 = props.schema.config) == null ? void 0 : _e2.search) == null ? void 0 : _f.searchClient;
28036
+ searchClient = (_f = (_e = props.schema.config) == null ? void 0 : _e.search) == null ? void 0 : _f.searchClient;
27595
28037
  }
27596
28038
  }
27597
28039
  if (searchClient) {
@@ -27602,7 +28044,7 @@ const TinaCloudProvider = (props) => {
27602
28044
  cms.registerApi("admin", new TinaAdminApi(cms));
27603
28045
  }
27604
28046
  const setupMedia = async (staticMedia) => {
27605
- var _a2, _b2, _c2, _d2, _e2, _f, _g;
28047
+ var _a2, _b2, _c2, _d, _e, _f, _g;
27606
28048
  const hasTinaMedia = Boolean((_b2 = (_a2 = props.schema.config) == null ? void 0 : _a2.media) == null ? void 0 : _b2.tina);
27607
28049
  if (hasTinaMedia) {
27608
28050
  cms.media.store = new TinaMediaStore(cms, staticMedia);
@@ -27610,9 +28052,9 @@ const TinaCloudProvider = (props) => {
27610
28052
  /*
27611
28053
  Has tina custom media (set up in the schema or define schema)
27612
28054
  */
27613
- ((_d2 = (_c2 = props.schema.config) == null ? void 0 : _c2.media) == null ? void 0 : _d2.loadCustomStore) || props.mediaStore
28055
+ ((_d = (_c2 = props.schema.config) == null ? void 0 : _c2.media) == null ? void 0 : _d.loadCustomStore) || props.mediaStore
27614
28056
  ) {
27615
- const mediaStoreFromProps = ((_f = (_e2 = props.schema.config) == null ? void 0 : _e2.media) == null ? void 0 : _f.loadCustomStore) || props.mediaStore;
28057
+ const mediaStoreFromProps = ((_f = (_e = props.schema.config) == null ? void 0 : _e.media) == null ? void 0 : _f.loadCustomStore) || props.mediaStore;
27616
28058
  if ((_g = mediaStoreFromProps.prototype) == null ? void 0 : _g.persist) {
27617
28059
  cms.media.store = new mediaStoreFromProps(cms.api.tina);
27618
28060
  } else {
@@ -27624,7 +28066,8 @@ const TinaCloudProvider = (props) => {
27624
28066
  }
27625
28067
  };
27626
28068
  const client = cms.api.tina;
27627
- const isTinaCloud = !client.isLocalMode && !((_e = (_d = (_c = (_b = (_a = client.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.config) == null ? void 0 : _c.admin) == null ? void 0 : _d.auth) == null ? void 0 : _e.customAuth);
28069
+ const isTinaCloud = !client.isLocalMode && !((_c = (_b = (_a = client.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.config) == null ? void 0 : _c.contentApiUrlOverride);
28070
+ const SessionProvider = client.authProvider.getSessionProvider();
27628
28071
  const handleListBranches = async () => {
27629
28072
  const branches = await cms.api.tina.listBranches({
27630
28073
  includeIndexStatus: true
@@ -27638,7 +28081,9 @@ const TinaCloudProvider = (props) => {
27638
28081
  const newBranch = await cms.api.tina.createBranch(data);
27639
28082
  return newBranch;
27640
28083
  };
27641
- setupMedia(props.staticMedia);
28084
+ setupMedia(props.staticMedia).catch((e) => {
28085
+ console.error(e);
28086
+ });
27642
28087
  const [branchingEnabled, setBranchingEnabled] = React__default.useState(
27643
28088
  () => cms.flags.get("branch-switcher")
27644
28089
  );
@@ -27691,7 +28136,7 @@ const TinaCloudProvider = (props) => {
27691
28136
  });
27692
28137
  return unsubscribe;
27693
28138
  }, [isTinaCloud, cms]);
27694
- return /* @__PURE__ */ React__default.createElement(
28139
+ return /* @__PURE__ */ React__default.createElement(SessionProvider, { basePath: "/api/tina/auth" }, /* @__PURE__ */ React__default.createElement(
27695
28140
  BranchDataProvider,
27696
28141
  {
27697
28142
  currentBranch,
@@ -27700,7 +28145,7 @@ const TinaCloudProvider = (props) => {
27700
28145
  }
27701
28146
  },
27702
28147
  /* @__PURE__ */ React__default.createElement(TinaProvider, { cms }, /* @__PURE__ */ React__default.createElement(AuthWallInner, { ...props, cms }))
27703
- );
28148
+ ));
27704
28149
  };
27705
28150
  const TinaCloudAuthWall = TinaCloudProvider;
27706
28151
  class ContentCreatorPlugin {
@@ -27979,14 +28424,13 @@ const TinaCMSProvider2 = ({
27979
28424
  schema,
27980
28425
  ...props
27981
28426
  }) => {
27982
- var _a, _b, _c, _d, _e, _f;
28427
+ var _a, _b, _c;
27983
28428
  if (props == null ? void 0 : props.apiURL) {
27984
28429
  console.warn(
27985
28430
  "The apiURL prop is deprecated. Please see https://tina.io/blog/tina-v-0.68.14 for information on how to upgrade to the new API"
27986
28431
  );
27987
28432
  }
27988
28433
  const apiURL = ((_a = props == null ? void 0 : props.client) == null ? void 0 : _a.apiUrl) || (props == null ? void 0 : props.apiURL);
27989
- const isLocalOverride = (_d = (_c = (_b = schema == null ? void 0 : schema.config) == null ? void 0 : _b.admin) == null ? void 0 : _c.auth) == null ? void 0 : _d.useLocalAuth;
27990
28434
  const { branch, clientId, isLocalClient } = apiURL ? parseURL(apiURL) : {
27991
28435
  branch: props.branch,
27992
28436
  clientId: props.clientId,
@@ -28012,10 +28456,10 @@ const TinaCMSProvider2 = ({
28012
28456
  TinaCloudProvider,
28013
28457
  {
28014
28458
  branch,
28015
- clientId: clientId || ((_e = schema == null ? void 0 : schema.config) == null ? void 0 : _e.clientId),
28459
+ clientId: clientId || ((_b = schema == null ? void 0 : schema.config) == null ? void 0 : _b.clientId),
28016
28460
  tinaioConfig: props.tinaioConfig,
28017
- isLocalClient: isLocalOverride || isLocalClient,
28018
- isSelfHosted: !!((_f = schema == null ? void 0 : schema.config) == null ? void 0 : _f.contentApiUrlOverride),
28461
+ isLocalClient,
28462
+ isSelfHosted: !!((_c = schema == null ? void 0 : schema.config) == null ? void 0 : _c.contentApiUrlOverride),
28019
28463
  cmsCallback: props.cmsCallback,
28020
28464
  mediaStore: props.mediaStore,
28021
28465
  apiUrl: apiURL,
@@ -28219,6 +28663,12 @@ const Sidebar = ({ cms }) => {
28219
28663
  const navBreakpoint2 = 1e3;
28220
28664
  const windowWidth = useWindowWidth();
28221
28665
  const renderDesktopNav = windowWidth > navBreakpoint2;
28666
+ const activeScreens = screens.filter(
28667
+ (screen) => {
28668
+ var _a2;
28669
+ return screen.navCategory !== "Account" || ((_a2 = cms.api.tina.authProvider) == null ? void 0 : _a2.getLoginStrategy()) === "UsernamePassword";
28670
+ }
28671
+ );
28222
28672
  return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, renderDesktopNav && /* @__PURE__ */ React__default.createElement(
28223
28673
  Nav,
28224
28674
  {
@@ -28226,7 +28676,7 @@ const Sidebar = ({ cms }) => {
28226
28676
  sidebarWidth: 360,
28227
28677
  showCollections: true,
28228
28678
  collectionsInfo,
28229
- screens,
28679
+ screens: activeScreens,
28230
28680
  cloudConfigs,
28231
28681
  contentCreators: [],
28232
28682
  RenderNavSite: ({ view }) => /* @__PURE__ */ React__default.createElement(
@@ -28245,6 +28695,14 @@ const Sidebar = ({ cms }) => {
28245
28695
  to: `/collections/${collection.name}/~`,
28246
28696
  Icon: ImFilesEmpty
28247
28697
  }
28698
+ ),
28699
+ AuthRenderNavCollection: ({ collection }) => /* @__PURE__ */ React__default.createElement(
28700
+ SidebarLink,
28701
+ {
28702
+ label: collection.label ? collection.label : collection.name,
28703
+ to: `/collections/${collection.name}/~`,
28704
+ Icon: ImUsers
28705
+ }
28248
28706
  )
28249
28707
  }
28250
28708
  ), !renderDesktopNav && /* @__PURE__ */ React__default.createElement(Transition, { show: menuIsOpen }, /* @__PURE__ */ React__default.createElement(
@@ -28266,7 +28724,7 @@ const Sidebar = ({ cms }) => {
28266
28724
  sidebarWidth: 360,
28267
28725
  showCollections: true,
28268
28726
  collectionsInfo,
28269
- screens,
28727
+ screens: activeScreens,
28270
28728
  cloudConfigs,
28271
28729
  contentCreators: [],
28272
28730
  RenderNavSite: ({ view }) => /* @__PURE__ */ React__default.createElement(
@@ -28291,6 +28749,17 @@ const Sidebar = ({ cms }) => {
28291
28749
  setMenuIsOpen(false);
28292
28750
  }
28293
28751
  }
28752
+ ),
28753
+ AuthRenderNavCollection: ({ collection }) => /* @__PURE__ */ React__default.createElement(
28754
+ SidebarLink,
28755
+ {
28756
+ label: collection.label ? collection.label : collection.name,
28757
+ to: `/collections/${collection.name}/~`,
28758
+ Icon: ImUsers,
28759
+ onClick: () => {
28760
+ setMenuIsOpen(false);
28761
+ }
28762
+ }
28294
28763
  )
28295
28764
  },
28296
28765
  /* @__PURE__ */ React__default.createElement("div", { className: "absolute top-8 right-0 transform translate-x-full overflow-hidden" }, /* @__PURE__ */ React__default.createElement(
@@ -28429,11 +28898,11 @@ const LogoutRedirect = () => {
28429
28898
  const [searchParams] = useSearchParams();
28430
28899
  const slug = searchParams.get("slug") || "/";
28431
28900
  const logout2 = async () => {
28432
- var _a, _b, _c, _d, _e, _f;
28433
- if ((_b = (_a = cms == null ? void 0 : cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.logout) {
28434
- await cms.api.tina.logout();
28435
- if ((_d = (_c = cms == null ? void 0 : cms.api) == null ? void 0 : _c.tina) == null ? void 0 : _d.onLogout) {
28436
- await ((_f = (_e = cms == null ? void 0 : cms.api) == null ? void 0 : _e.tina) == null ? void 0 : _f.onLogout());
28901
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
28902
+ if ((_c = (_b = (_a = cms == null ? void 0 : cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.authProvider) == null ? void 0 : _c.logout) {
28903
+ await ((_f = (_e = (_d = cms == null ? void 0 : cms.api) == null ? void 0 : _d.tina) == null ? void 0 : _e.authProvider) == null ? void 0 : _f.logout());
28904
+ if ((_h = (_g = cms == null ? void 0 : cms.api) == null ? void 0 : _g.tina) == null ? void 0 : _h.onLogout) {
28905
+ await ((_j = (_i = cms == null ? void 0 : cms.api) == null ? void 0 : _i.tina) == null ? void 0 : _j.onLogout());
28437
28906
  }
28438
28907
  }
28439
28908
  setEdit(false);
@@ -29437,8 +29906,7 @@ const SearchInput = ({
29437
29906
  setSearch(searchInput);
29438
29907
  setSearchLoaded(false);
29439
29908
  },
29440
- variant: "primary",
29441
- type: "submit"
29909
+ variant: "primary"
29442
29910
  },
29443
29911
  "Search ",
29444
29912
  /* @__PURE__ */ React__default.createElement(BiSearch, { className: "w-5 h-full ml-1.5 opacity-70" })
@@ -29722,13 +30190,13 @@ const RenderForm$1 = ({
29722
30190
  }
29723
30191
  const defaultItem = customDefaults || // @ts-ignore internal types aren't up to date
29724
30192
  ((_d = template.ui) == null ? void 0 : _d.defaultItem) || // @ts-ignore
29725
- (template == null ? void 0 : template.defaultItem);
30193
+ (template == null ? void 0 : template.defaultItem) || {};
29726
30194
  const form = useMemo(() => {
29727
30195
  var _a2, _b2;
29728
30196
  const folderName = folder.fullyQualifiedName ? folder.name : "";
29729
30197
  return new Form({
29730
30198
  crudType: "create",
29731
- initialValues: typeof defaultItem === "function" ? defaultItem() : defaultItem,
30199
+ initialValues: typeof defaultItem === "function" ? { ...defaultItem(), _template: templateName } : { ...defaultItem, _template: templateName },
29732
30200
  extraSubscribeValues: { active: true, submitting: true, touched: true },
29733
30201
  onChange: (values) => {
29734
30202
  var _a3, _b3;
@@ -30260,10 +30728,12 @@ const MaybeRedirectToPreview = ({
30260
30728
  redirect,
30261
30729
  children
30262
30730
  }) => {
30731
+ const cms = useCMS$1();
30263
30732
  const navigate = useNavigate();
30264
30733
  React__default.useEffect(() => {
30734
+ const basePath = cms.flags.get("tina-basepath");
30265
30735
  if (redirect) {
30266
- navigate("/~");
30736
+ navigate(`/~${basePath ? `/${basePath}` : ""}`);
30267
30737
  }
30268
30738
  }, [redirect]);
30269
30739
  return children;
@@ -30507,22 +30977,6 @@ class RouteMappingPlugin {
30507
30977
  this.mapper = mapper;
30508
30978
  }
30509
30979
  }
30510
- const defineSchema = (config) => {
30511
- validateSchema({ schema: config });
30512
- return config;
30513
- };
30514
- const defineLegacyConfig = (config) => {
30515
- validateSchema({ schema: config.schema });
30516
- return config;
30517
- };
30518
- const defineStaticConfig = (config) => {
30519
- if (!config.schema) {
30520
- throw new Error("Static config must have a schema");
30521
- }
30522
- validateSchema({ schema: config.schema });
30523
- return config;
30524
- };
30525
- const defineConfig = defineStaticConfig;
30526
30980
  const tinaTableTemplate = {
30527
30981
  name: "table",
30528
30982
  label: "Table",
@@ -30532,6 +30986,13 @@ const tinaTableTemplate = {
30532
30986
  label: "First row is a header",
30533
30987
  type: "boolean"
30534
30988
  },
30989
+ {
30990
+ name: "align",
30991
+ label: "Align",
30992
+ type: "string",
30993
+ list: true,
30994
+ description: 'Possible values: "left", "right", or "center".'
30995
+ },
30535
30996
  {
30536
30997
  name: "tableRows",
30537
30998
  label: "Rows",
@@ -30544,7 +31005,7 @@ const tinaTableTemplate = {
30544
31005
  return {
30545
31006
  label: value.tableCells.map((cellItem) => {
30546
31007
  var _a;
30547
- return (_a = stringifyCell(cellItem.tableCell)) == null ? void 0 : _a.trim();
31008
+ return (_a = stringifyCell(cellItem.value)) == null ? void 0 : _a.trim();
30548
31009
  }).join(" | ")
30549
31010
  };
30550
31011
  }
@@ -30559,24 +31020,36 @@ const tinaTableTemplate = {
30559
31020
  list: true,
30560
31021
  type: "object",
30561
31022
  ui: {
30562
- itemProps: (value) => {
31023
+ itemProps: (cell) => {
30563
31024
  var _a;
30564
- if (value) {
30565
- if (value.tableCell) {
31025
+ if (cell) {
31026
+ if (cell.value) {
30566
31027
  return {
30567
- label: (_a = stringifyCell(value.tableCell)) == null ? void 0 : _a.trim()
31028
+ label: (_a = stringifyCell(cell.value)) == null ? void 0 : _a.trim()
30568
31029
  };
30569
31030
  }
30570
31031
  }
30571
- return { label: "Table Cell" };
31032
+ return { label: "Value" };
30572
31033
  }
30573
31034
  },
30574
31035
  fields: [
30575
31036
  {
30576
- label: "Table Cell",
30577
- description: "Note: table cells do not support block-level elements like headers, code blocks, or lists. Any block-level items other than the first paragraph will be ignored.",
30578
- name: "tableCell",
30579
- type: "rich-text"
31037
+ label: "Value",
31038
+ description: "Note: table cells do not support block-level elements like headers, code blocks, or lists. Any block-level items other than the first paragraph will be considered invalid.",
31039
+ name: "value",
31040
+ type: "rich-text",
31041
+ ui: {
31042
+ validate(value) {
31043
+ try {
31044
+ tableCellSchema.parse(value);
31045
+ } catch (e) {
31046
+ if (e instanceof z.ZodError) {
31047
+ return e.errors[0].message;
31048
+ }
31049
+ return e.message;
31050
+ }
31051
+ }
31052
+ }
30580
31053
  }
30581
31054
  ]
30582
31055
  }
@@ -30584,10 +31057,56 @@ const tinaTableTemplate = {
30584
31057
  }
30585
31058
  ]
30586
31059
  };
31060
+ const tableCellSchema = z.object({
31061
+ type: z.literal("root"),
31062
+ children: z.array(
31063
+ z.object({
31064
+ type: z.string(),
31065
+ children: z.any().array()
31066
+ })
31067
+ ).refine(
31068
+ (value) => {
31069
+ const firstValue = value[0];
31070
+ return firstValue && firstValue.type === "p";
31071
+ },
31072
+ {
31073
+ message: `Table cell content cannot contain block elements like headers, blockquotes, or lists.`
31074
+ }
31075
+ ).refine(
31076
+ (value) => {
31077
+ var _a;
31078
+ if (value.length > 1) {
31079
+ const secondBlock = value[1];
31080
+ return secondBlock && secondBlock.children.length === 1 && !((_a = secondBlock.children[0]) == null ? void 0 : _a.text);
31081
+ }
31082
+ return true;
31083
+ },
31084
+ {
31085
+ message: `Table cells can only have 1 block level element.`
31086
+ }
31087
+ )
31088
+ });
30587
31089
  const stringifyCell = (cell) => {
30588
31090
  return stringifyMDX(cell, { name: "body", type: "rich-text" }, () => "");
30589
31091
  };
31092
+ const defineSchema = (config) => {
31093
+ validateSchema({ schema: config });
31094
+ return config;
31095
+ };
31096
+ const defineLegacyConfig = (config) => {
31097
+ validateSchema({ schema: config.schema });
31098
+ return config;
31099
+ };
31100
+ const defineStaticConfig = (config) => {
31101
+ if (!config.schema) {
31102
+ throw new Error("Static config must have a schema");
31103
+ }
31104
+ validateSchema({ schema: config.schema });
31105
+ return config;
31106
+ };
31107
+ const defineConfig = defineStaticConfig;
30590
31108
  export {
31109
+ AbstractAuthProvider,
30591
31110
  ActionButton,
30592
31111
  AddIcon,
30593
31112
  AlertIcon,
@@ -30596,6 +31115,7 @@ export {
30596
31115
  AlignLeft,
30597
31116
  AlignRight,
30598
31117
  AuthWallInner,
31118
+ BasePasswordField,
30599
31119
  BaseTextField,
30600
31120
  BillingWarning,
30601
31121
  BlocksField,
@@ -30690,6 +31210,7 @@ export {
30690
31210
  ListField,
30691
31211
  ListFieldPlugin,
30692
31212
  LoadingDots,
31213
+ LocalAuthProvider,
30693
31214
  LocalClient,
30694
31215
  LocalSearchClient,
30695
31216
  LocalWarning,
@@ -30718,6 +31239,8 @@ export {
30718
31239
  OverflowMenu$1 as OverflowMenu,
30719
31240
  PanelBody,
30720
31241
  PanelHeader$1 as PanelHeader,
31242
+ PasswordFieldComponent,
31243
+ PasswordFieldPlugin,
30721
31244
  PopupModal,
30722
31245
  PrefixedTextField,
30723
31246
  PullRequestIcon,
@@ -30759,6 +31282,7 @@ export {
30759
31282
  TinaCMSProvider,
30760
31283
  TinaCMSProvider2,
30761
31284
  TinaCMSSearchClient,
31285
+ TinaCloudAuthProvider,
30762
31286
  TinaCloudAuthWall,
30763
31287
  TinaCloudProvider,
30764
31288
  TinaField,
@@ -30777,7 +31301,6 @@ export {
30777
31301
  UploadIcon,
30778
31302
  WarningIcon,
30779
31303
  assertShape,
30780
- asyncPoll,
30781
31304
  classNames,
30782
31305
  createClient,
30783
31306
  TinaCMSProvider2 as default,
@@ -30789,6 +31312,7 @@ export {
30789
31312
  getFilteredBranchList,
30790
31313
  getStaticPropsForTina,
30791
31314
  gql,
31315
+ passwordFieldClasses,
30792
31316
  resolveField,
30793
31317
  safeAssertShape,
30794
31318
  selectFieldClasses,