tinacms 0.66.8 → 0.66.9

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.js CHANGED
@@ -30,8 +30,8 @@ var __objRest = (source, exclude) => {
30
30
  return target;
31
31
  };
32
32
  (function(global, factory) {
33
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@tinacms/toolkit"), require("graphql"), require("lodash.set"), require("react"), require("graphql-tag"), require("styled-components"), require("yup"), require("@tinacms/sharedctx"), require("final-form"), require("url-pattern"), require("react-router-dom"), require("@headlessui/react")) : typeof define === "function" && define.amd ? define(["exports", "@tinacms/toolkit", "graphql", "lodash.set", "react", "graphql-tag", "styled-components", "yup", "@tinacms/sharedctx", "final-form", "url-pattern", "react-router-dom", "@headlessui/react"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.tinacms = {}, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP));
34
- })(this, function(exports2, toolkit, G, set, React, gql$1, styled, yup, sharedctx, finalForm, UrlPattern, reactRouterDom, react) {
33
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@tinacms/toolkit"), require("graphql"), require("lodash.set"), require("react"), require("final-form"), require("yup"), require("graphql-tag"), require("styled-components"), require("@tinacms/sharedctx"), require("url-pattern"), require("react-router-dom"), require("@headlessui/react")) : typeof define === "function" && define.amd ? define(["exports", "@tinacms/toolkit", "graphql", "lodash.set", "react", "final-form", "yup", "graphql-tag", "styled-components", "@tinacms/sharedctx", "url-pattern", "react-router-dom", "@headlessui/react"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.tinacms = {}, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP));
34
+ })(this, function(exports2, toolkit, G, set, React, finalForm, yup, gql$1, styled, sharedctx, UrlPattern, reactRouterDom, react) {
35
35
  "use strict";
36
36
  function _interopDefaultLegacy(e) {
37
37
  return e && typeof e === "object" && "default" in e ? e : { "default": e };
@@ -59,9 +59,9 @@ var __objRest = (source, exclude) => {
59
59
  var G__namespace = /* @__PURE__ */ _interopNamespace(G);
60
60
  var set__default = /* @__PURE__ */ _interopDefaultLegacy(set);
61
61
  var React__default = /* @__PURE__ */ _interopDefaultLegacy(React);
62
+ var yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
62
63
  var gql__default = /* @__PURE__ */ _interopDefaultLegacy(gql$1);
63
64
  var styled__default = /* @__PURE__ */ _interopDefaultLegacy(styled);
64
- var yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
65
65
  var UrlPattern__default = /* @__PURE__ */ _interopDefaultLegacy(UrlPattern);
66
66
  function popupWindow(url, title, window2, w, h) {
67
67
  const y = window2.top.outerHeight / 2 + window2.top.screenY - h / 2;
@@ -396,1306 +396,2486 @@ var __objRest = (source, exclude) => {
396
396
  throw new Error(`Expected an instance of GraphQLUnionType for type ${type.name}`);
397
397
  }
398
398
  }
399
- const isNodeField = (type) => {
400
- if (G__namespace.isUnionType(type)) {
401
- return type.getTypes().every((type2) => {
402
- return type2.getInterfaces().find((intfc) => intfc.name === "Node");
403
- });
404
- } else if (G__namespace.isObjectType(type)) {
405
- return !!type.getInterfaces().find((intfc) => intfc.name === "Node");
406
- } else if (G__namespace.isInterfaceType(type)) {
407
- if (type.name === "Node") {
408
- return true;
409
- }
410
- } else {
411
- throw new Error(`Expected GraphQLObjectType or GraphQLUnionType for isNodeField check`);
412
- }
413
- };
414
- const isConnectionField = (type) => {
415
- if (G__namespace.isObjectType(type)) {
416
- return !!type.getInterfaces().find((intfc) => intfc.name === "Connection");
417
- } else {
418
- throw new Error(`Expected GraphQLObjectType for isCollectionField check`);
419
- }
420
- };
421
- const getObjectField = (object, selectionNode) => {
422
- return object.getFields()[selectionNode.name.value];
423
- };
424
- const getSelectedUnionType = (unionType, selectionNode) => {
425
- return unionType.getTypes().find((type) => type.name === selectionNode.typeCondition.name.value);
399
+ const createClient = ({
400
+ clientId,
401
+ isLocalClient = true,
402
+ branch,
403
+ tinaioConfig
404
+ }) => {
405
+ return isLocalClient ? new LocalClient() : new Client({
406
+ clientId: clientId || "",
407
+ branch: branch || "main",
408
+ tokenStorage: "LOCAL_STORAGE",
409
+ tinaioConfig
410
+ });
426
411
  };
427
- function ensureNodeField(field) {
428
- if (!isNodeField(field)) {
429
- throw new Error(`Expected field to implement Node interface`);
430
- }
431
- }
432
- function ensureUnionType(type) {
433
- if (!G__namespace.isUnionType(type)) {
434
- throw new Error(`Expected type to be GraphQLUnionType`);
435
- }
436
- }
437
- function ensureObjectType(type) {
438
- if (!G__namespace.isObjectType(type)) {
439
- console.log(type);
440
- throw new Error(`Expected type to be GraphQLObjectType`);
441
- }
442
- }
443
- function ensureOperationDefinition(type) {
444
- if (type.kind !== "OperationDefinition") {
445
- throw new Error(`Expected top-level definition to be an OperationDefinition node, ensure your query has been optimized before calling formify`);
412
+ function assertShape(value, yupSchema, errorMessage) {
413
+ const shape = yupSchema(yup__namespace);
414
+ try {
415
+ shape.validateSync(value);
416
+ } catch (e) {
417
+ const message = errorMessage || `Failed to assertShape - ${e.message}`;
418
+ throw new Error(message);
446
419
  }
447
420
  }
448
- function getNameAndAlias(fieldNode, list) {
449
- return {
450
- name: fieldNode.name.value,
451
- alias: fieldNode.alias ? fieldNode.alias.value : fieldNode.name.value,
452
- list: !!list
453
- };
454
- }
455
- const node = G__namespace.parse(`
456
- query Sample {
457
- _internalSys: sys {
458
- path
459
- collection {
460
- name
461
- }
462
- }
463
- form
464
- values
465
- }`);
466
- const metaFields = node.definitions[0].selectionSet.selections;
467
- const NOOP = "This is either an error or is not yet supported";
468
- const UNEXPECTED = "Formify encountered an unexpected error, please contact support";
469
- const DATA_NODE_NAME = "data";
470
- const EDGES_NODE_NAME = "edges";
471
- const NODE_NAME = "node";
472
- const COLLECTION_FIELD_NAME = "getCollection";
473
- const COLLECTIONS_FIELD_NAME = "getCollections";
474
- const COLLECTIONS_DOCUMENTS_NAME = "documents";
475
- class FormifyError extends Error {
476
- constructor(code, details) {
477
- let message;
478
- switch (code) {
479
- case "NOOP":
480
- message = NOOP;
481
- break;
482
- case "UNEXPECTED":
483
- message = UNEXPECTED;
484
- break;
485
- default:
486
- message = "";
487
- break;
488
- }
489
- super(`${message} ${details || ""}`);
490
- this.name = "FormifyError";
421
+ function safeAssertShape(value, yupSchema) {
422
+ try {
423
+ assertShape(value, yupSchema);
424
+ return true;
425
+ } catch (e) {
426
+ return false;
491
427
  }
492
428
  }
493
- const formify = async ({
494
- schema,
429
+ function useGraphqlFormsUnstable({
430
+ variables,
431
+ onSubmit,
495
432
  query,
496
- getOptimizedQuery
497
- }) => {
498
- const nodes = [];
499
- const documentNode = G__namespace.parse(query);
500
- const visitor2 = {
501
- OperationDefinition: (node2) => {
502
- if (!node2.name) {
503
- return __spreadProps(__spreadValues({}, node2), {
504
- name: {
505
- kind: "Name",
506
- value: `QueryOperation`
507
- }
508
- });
433
+ formify: formify2,
434
+ eventList
435
+ }) {
436
+ const cms = toolkit.useCMS();
437
+ React__default["default"].useEffect(() => {
438
+ console.log("NOTE: using unstable formify");
439
+ }, []);
440
+ const state = useFormify({
441
+ query,
442
+ cms,
443
+ variables,
444
+ formify: formify2,
445
+ eventList,
446
+ onSubmit
447
+ });
448
+ return [state.data, state.status !== "done"];
449
+ }
450
+ function useGraphqlForms({
451
+ variables,
452
+ onSubmit,
453
+ formify: formify2 = null,
454
+ query
455
+ }) {
456
+ const cms = toolkit.useCMS();
457
+ const [formValues, setFormValues] = React__default["default"].useState({});
458
+ const [data, setData] = React__default["default"].useState(null);
459
+ const [initialData, setInitialData] = React__default["default"].useState({});
460
+ const [pendingReset, setPendingReset] = React__default["default"].useState(null);
461
+ const [isLoading, setIsLoading] = React__default["default"].useState(true);
462
+ const [newUpdate, setNewUpdate] = React__default["default"].useState(null);
463
+ const { currentBranch } = toolkit.useBranchData();
464
+ const updateData = async () => {
465
+ var _a;
466
+ if (newUpdate) {
467
+ const newValue = finalForm.getIn(formValues, newUpdate.get);
468
+ const activeForm = finalForm.getIn(data, [newUpdate.queryName, "form"].join("."));
469
+ if (!activeForm) {
470
+ throw new Error(`Unable to find form for query ${newUpdate.queryName}`);
509
471
  }
510
- return node2;
511
- }
512
- };
513
- const documentNodeWithName = G.visit(documentNode, visitor2);
514
- const optimizedQuery = await getOptimizedQuery(documentNodeWithName);
515
- const typeInfo = new G__namespace.TypeInfo(schema);
516
- const formifyConnection = ({
517
- namedFieldType,
518
- selectionNode,
519
- path
520
- }) => {
521
- ensureObjectType(namedFieldType);
522
- return __spreadProps(__spreadValues({}, selectionNode), {
523
- selectionSet: {
524
- kind: "SelectionSet",
525
- selections: selectionNode.selectionSet.selections.map((selectionNode2) => {
526
- switch (selectionNode2.kind) {
527
- case "Field":
528
- if (selectionNode2.name.value === EDGES_NODE_NAME) {
529
- const edgeField = namedFieldType.getFields()[EDGES_NODE_NAME];
530
- const edgeType = G__namespace.getNamedType(edgeField.type);
531
- ensureObjectType(edgeType);
532
- return __spreadProps(__spreadValues({}, selectionNode2), {
533
- selectionSet: {
534
- kind: "SelectionSet",
535
- selections: selectionNode2.selectionSet.selections.map((subSelectionNode) => {
536
- switch (subSelectionNode.kind) {
537
- case "Field":
538
- if (subSelectionNode.name.value === NODE_NAME) {
539
- const nodeField = edgeType.getFields()[NODE_NAME];
540
- return formifyNode({
541
- fieldOrInlineFragmentNode: subSelectionNode,
542
- parentType: nodeField.type,
543
- path: [
544
- ...path,
545
- getNameAndAlias(selectionNode2),
546
- getNameAndAlias(subSelectionNode, true)
547
- ]
548
- });
549
- } else {
550
- return subSelectionNode;
551
- }
552
- default:
553
- throw new FormifyError("NOOP");
554
- }
555
- })
556
- }
557
- });
558
- }
559
- return selectionNode2;
560
- default:
561
- throw new FormifyError("UNEXPECTED");
562
- }
563
- })
472
+ if (activeForm == null ? void 0 : activeForm.paths) {
473
+ const asyncUpdate = (_a = activeForm.paths) == null ? void 0 : _a.find((p) => p.dataPath.join(".") === newUpdate.setReference);
474
+ if (asyncUpdate) {
475
+ const res = await cms.api.tina.request(asyncUpdate.queryString, {
476
+ variables: { id: newValue }
477
+ });
478
+ const newData2 = finalForm.setIn(data, newUpdate.set, res.node);
479
+ const newDataAndNewJSONData2 = finalForm.setIn(newData2, newUpdate.set.replace("data", "dataJSON"), newValue);
480
+ setData(newDataAndNewJSONData2);
481
+ setNewUpdate(null);
482
+ return;
483
+ }
564
484
  }
565
- });
485
+ if (newUpdate.lookup) {
486
+ const field = getFieldUpdate(newUpdate, activeForm, formValues);
487
+ if (field && field.typeMap) {
488
+ newValue.forEach((item) => {
489
+ if (!item.__typename) {
490
+ item["__typename"] = field.typeMap[item._template];
491
+ }
492
+ });
493
+ }
494
+ }
495
+ const newData = finalForm.setIn(data, newUpdate.set, newValue);
496
+ const newDataAndNewJSONData = finalForm.setIn(newData, newUpdate.set.replace("data", "dataJSON"), newValue);
497
+ setData(newDataAndNewJSONData);
498
+ setNewUpdate(null);
499
+ }
566
500
  };
567
- function formifyNode({
568
- fieldOrInlineFragmentNode,
569
- parentType,
570
- path
571
- }) {
572
- let extraFields = [];
573
- const namedParentType = G__namespace.getNamedType(parentType);
574
- const formifiedNode = __spreadProps(__spreadValues({}, fieldOrInlineFragmentNode), {
575
- selectionSet: {
576
- kind: "SelectionSet",
577
- selections: [
578
- ...fieldOrInlineFragmentNode.selectionSet.selections.map((selectionNode) => {
579
- switch (selectionNode.kind) {
580
- case "InlineFragment":
581
- if (G__namespace.isInterfaceType(namedParentType)) {
582
- const type2 = schema.getImplementations(namedParentType).objects[selectionNode.typeCondition.name.value];
583
- return formifyNode({
584
- fieldOrInlineFragmentNode: selectionNode,
585
- parentType: type2,
586
- path
587
- });
588
- }
589
- ensureUnionType(namedParentType);
590
- const type = getSelectedUnionType(namedParentType, selectionNode);
591
- return formifyNode({
592
- fieldOrInlineFragmentNode: selectionNode,
593
- parentType: type,
594
- path
595
- });
596
- case "Field":
597
- if (selectionNode.name.value === DATA_NODE_NAME) {
598
- extraFields = metaFields;
599
- if (G__namespace.isObjectType(namedParentType)) {
600
- const field = getObjectField(namedParentType, selectionNode);
601
- const namedType = G__namespace.getNamedType(field.type);
602
- ensureObjectType(namedType);
603
- return __spreadProps(__spreadValues({}, selectionNode), {
604
- selectionSet: {
605
- kind: "SelectionSet",
606
- selections: [
607
- ...selectionNode.selectionSet.selections.map((subSelectionNode) => {
608
- switch (subSelectionNode.kind) {
609
- case "Field":
610
- const subSelectionField = getObjectField(namedType, subSelectionNode);
611
- if (!subSelectionField) {
612
- return subSelectionNode;
613
- }
614
- return formifyField({
615
- fieldNode: subSelectionNode,
616
- parentType: field.type,
617
- path: [
618
- ...path,
619
- getNameAndAlias(subSelectionNode, G__namespace.isListType(subSelectionField.type))
620
- ]
621
- });
622
- default:
623
- throw new FormifyError("UNEXPECTED", `selection ${subSelectionNode.kind}`);
624
- }
625
- })
626
- ]
627
- }
628
- });
629
- }
630
- return selectionNode;
631
- }
632
- return selectionNode;
633
- default:
634
- throw new FormifyError("UNEXPECTED");
635
- }
636
- }),
637
- ...extraFields
638
- ]
639
- }
640
- });
641
- return formifiedNode;
642
- }
643
- const formifyField = ({
644
- fieldNode,
645
- parentType,
646
- path
647
- }) => {
648
- const namedParentType = G__namespace.getNamedType(parentType);
649
- ensureObjectType(namedParentType);
650
- const field = getObjectField(namedParentType, fieldNode);
651
- if (!field) {
652
- if (fieldNode.name.value === "__typename") {
653
- return fieldNode;
654
- } else {
655
- throw new FormifyError("UNEXPECTED", `field with no associated type ${fieldNode.name.value}`);
656
- }
657
- }
658
- const namedType = G__namespace.getNamedType(field.type);
659
- if (G__namespace.isScalarType(namedType)) {
660
- return fieldNode;
501
+ React__default["default"].useEffect(() => {
502
+ updateData();
503
+ }, [JSON.stringify(formValues)]);
504
+ React__default["default"].useEffect(() => {
505
+ if (pendingReset) {
506
+ setData(__spreadProps(__spreadValues({}, data), { [pendingReset]: initialData[pendingReset] }));
507
+ setPendingReset(null);
661
508
  }
662
- return __spreadProps(__spreadValues({}, fieldNode), {
663
- selectionSet: {
664
- kind: "SelectionSet",
665
- selections: [
666
- ...fieldNode.selectionSet.selections.map((selectionNode) => {
667
- switch (selectionNode.kind) {
668
- case "Field":
669
- if (selectionNode.name.value === "__typename") {
670
- return selectionNode;
671
- }
672
- ensureObjectType(namedType);
673
- const field2 = getObjectField(namedType, selectionNode);
674
- if (!field2) {
675
- return fieldNode;
676
- }
677
- if (G__namespace.isScalarType(G__namespace.getNamedType(field2.type))) {
678
- return selectionNode;
679
- }
680
- return __spreadProps(__spreadValues({}, selectionNode), {
681
- selectionSet: {
682
- kind: "SelectionSet",
683
- selections: selectionNode.selectionSet.selections.map((selectionNode2) => {
684
- switch (selectionNode2.kind) {
685
- case "Field":
686
- if (selectionNode2.name.value === "__typename") {
687
- return selectionNode2;
688
- }
689
- return formifyField({
690
- fieldNode: selectionNode2,
691
- parentType: field2.type,
692
- path
693
- });
694
- case "InlineFragment":
695
- const namedType2 = G__namespace.getNamedType(field2.type);
696
- ensureNodeField(namedType2);
697
- return formifyNode({
698
- fieldOrInlineFragmentNode: selectionNode2,
699
- parentType: field2.type,
700
- path
701
- });
702
- default:
703
- throw new FormifyError("UNEXPECTED", `selection ${selectionNode2.kind}`);
704
- }
705
- })
706
- }
707
- });
708
- case "InlineFragment":
709
- ensureUnionType(namedType);
710
- if (isNodeField(namedType)) {
711
- const parentType2 = getSelectedUnionType(namedType, selectionNode);
712
- return formifyNode({
713
- fieldOrInlineFragmentNode: selectionNode,
714
- parentType: parentType2,
715
- path
716
- });
717
- }
718
- return __spreadProps(__spreadValues({}, selectionNode), {
719
- selectionSet: {
720
- kind: "SelectionSet",
721
- selections: selectionNode.selectionSet.selections.map((subSelectionNode) => {
722
- switch (subSelectionNode.kind) {
723
- case "Field":
724
- const parentType2 = getSelectedUnionType(namedType, selectionNode);
725
- return formifyField({
726
- fieldNode: subSelectionNode,
727
- parentType: parentType2,
728
- path
729
- });
730
- default:
731
- throw new FormifyError("UNEXPECTED", `selection ${subSelectionNode.kind}`);
732
- }
733
- })
734
- }
735
- });
736
- default:
737
- throw new FormifyError("UNEXPECTED", `selection ${selectionNode.kind}`);
738
- }
739
- })
740
- ]
741
- }
742
- });
743
- };
744
- const formifiedQuery = {
745
- kind: "Document",
746
- definitions: optimizedQuery.definitions.map((definition) => {
747
- typeInfo.enter(definition);
748
- ensureOperationDefinition(definition);
749
- const type = typeInfo.getType();
750
- const namedType = G__namespace.getNamedType(type);
751
- ensureObjectType(namedType);
752
- return __spreadProps(__spreadValues({}, definition), {
753
- selectionSet: {
754
- kind: "SelectionSet",
755
- selections: definition.selectionSet.selections.map((selectionNode) => {
756
- switch (selectionNode.kind) {
757
- case "Field":
758
- const parentType = type;
759
- const namedParentType = G__namespace.getNamedType(parentType);
760
- ensureObjectType(namedParentType);
761
- const field = getObjectField(namedParentType, selectionNode);
762
- const namedFieldType = G__namespace.getNamedType(field.type);
763
- if (isNodeField(namedFieldType)) {
764
- return formifyNode({
765
- fieldOrInlineFragmentNode: selectionNode,
766
- parentType: field.type,
767
- path: [getNameAndAlias(selectionNode)]
768
- });
769
- } else if (isConnectionField(namedFieldType)) {
770
- return formifyConnection({
771
- namedFieldType,
772
- selectionNode,
773
- path: [getNameAndAlias(selectionNode)]
774
- });
775
- }
776
- if (selectionNode.name.value === COLLECTION_FIELD_NAME || selectionNode.name.value === COLLECTIONS_FIELD_NAME) {
777
- return __spreadProps(__spreadValues({}, selectionNode), {
778
- selectionSet: {
779
- kind: "SelectionSet",
780
- selections: selectionNode.selectionSet.selections.map((selectionNode2) => {
781
- switch (selectionNode2.kind) {
782
- case "Field":
783
- if (selectionNode2.name.value === COLLECTIONS_DOCUMENTS_NAME) {
784
- ensureObjectType(namedFieldType);
785
- const n = namedFieldType.getFields()[COLLECTIONS_DOCUMENTS_NAME];
786
- const docType = G__namespace.getNamedType(n.type);
787
- return formifyConnection({
788
- namedFieldType: docType,
789
- selectionNode: selectionNode2,
790
- path: [getNameAndAlias(selectionNode2)]
791
- });
792
- }
793
- return selectionNode2;
794
- default:
795
- throw new FormifyError("NOOP");
796
- }
797
- })
798
- }
799
- });
800
- }
801
- throw new FormifyError("NOOP");
802
- default:
803
- throw new FormifyError("UNEXPECTED");
804
- }
805
- })
806
- }
807
- });
808
- })
809
- };
810
- nodes.map((node2) => {
811
- const namePath = [];
812
- const aliasPath = [];
813
- node2.path.forEach((p) => {
814
- namePath.push(p.name);
815
- aliasPath.push(p.alias);
816
- if (p.list) {
817
- namePath.push("NUM");
818
- aliasPath.push("NUM");
819
- }
820
- });
821
- JSON.stringify({
822
- namePath: namePath.join("."),
823
- aliasPath: aliasPath.join(".")
824
- }, null, 2);
825
- });
826
- return { formifiedQuery, nodes };
827
- };
828
- const captureBranchName = /^refs\/heads\/(.*)/;
829
- const parseRefForBranchName = (ref) => {
830
- const matches = ref.match(captureBranchName);
831
- return matches[1];
832
- };
833
- class Client {
834
- constructor(_a) {
835
- var _b = _a, { tokenStorage = "MEMORY" } = _b, options = __objRest(_b, ["tokenStorage"]);
836
- this.events = new toolkit.EventBus();
837
- this.addPendingContent = async (props) => {
838
- const mutation = `#graphql
839
- mutation addPendingDocumentMutation(
840
- $relativePath: String!
841
- $collection: String!
842
- $template: String
843
- ) {
844
- addPendingDocument(
845
- relativePath: $relativePath
846
- template: $template
847
- collection: $collection
848
- ) {
849
- ... on Document {
850
- sys {
851
- relativePath
852
- path
853
- breadcrumbs
854
- collection {
855
- slug
856
- }
509
+ }, [pendingReset]);
510
+ React__default["default"].useEffect(() => {
511
+ if (!query) {
512
+ setIsLoading(false);
513
+ return;
857
514
  }
858
- }
859
- }
860
- }`;
861
- const result = await this.request(mutation, {
862
- variables: props
863
- });
864
- return result;
865
- };
866
- this.getSchema = async () => {
867
- if (!this.schema) {
868
- const data = await this.request(G.getIntrospectionQuery(), {
869
- variables: {}
870
- });
871
- this.schema = G.buildClientSchema(data);
872
- }
873
- return this.schema;
874
- };
875
- this.getOptimizedQuery = async (documentNode) => {
876
- const data = await this.request(`query GetOptimizedQuery($queryString: String!) {
877
- getOptimizedQuery(queryString: $queryString)
878
- }`, {
879
- variables: { queryString: G.print(documentNode) }
880
- });
881
- return G.parse(data.getOptimizedQuery);
882
- };
883
- this.options = options;
884
- this.setBranch(options.branch);
885
- this.events.subscribe("branch:change", ({ branchName }) => {
886
- this.setBranch(branchName);
887
- });
888
- this.clientId = options.clientId;
889
- switch (tokenStorage) {
890
- case "LOCAL_STORAGE":
891
- this.getToken = async function() {
892
- const tokens = localStorage.getItem(AUTH_TOKEN_KEY) || null;
893
- if (tokens) {
894
- return await this.getRefreshedToken(tokens);
895
- } else {
896
- return {
897
- access_token: null,
898
- id_token: null,
899
- refresh_token: null
900
- };
515
+ const formIds = [];
516
+ setIsLoading(true);
517
+ cms.api.tina.requestWithForm((gql2) => gql2(query), {
518
+ variables,
519
+ useUnstableFormify: cms.flags.get("use-unstable-formify")
520
+ }).then((payload) => {
521
+ cms.plugins.remove(new toolkit.FormMetaPlugin({ name: "tina-admin-link" }));
522
+ setData(payload);
523
+ setInitialData(payload);
524
+ setIsLoading(false);
525
+ Object.entries(payload).map(([queryName, result]) => {
526
+ formIds.push(queryName);
527
+ const canBeFormified = safeAssertShape(result, (yup2) => yup2.object({
528
+ values: yup2.object().required(),
529
+ form: yup2.object().required()
530
+ }));
531
+ if (!canBeFormified) {
532
+ return;
533
+ }
534
+ assertShape(result, (yup2) => yup2.object({
535
+ values: yup2.object().required(),
536
+ form: yup2.object().required()
537
+ }), `Unable to build form shape for fields at ${queryName}`);
538
+ const formConfig = {
539
+ id: queryName,
540
+ label: result.form.label,
541
+ initialValues: result.values,
542
+ fields: result.form.fields,
543
+ reset: () => {
544
+ setPendingReset(queryName);
545
+ },
546
+ onSubmit: async (payload2) => {
547
+ try {
548
+ const params = transformDocumentIntoMutationRequestPayload(payload2, result.form.mutationInfo);
549
+ const variables2 = { params };
550
+ const mutationString = result.form.mutationInfo.string;
551
+ if (onSubmit) {
552
+ onSubmit({
553
+ queryString: mutationString,
554
+ mutationString,
555
+ variables: variables2
556
+ });
557
+ } else {
558
+ try {
559
+ await cms.api.tina.request(mutationString, {
560
+ variables: variables2
561
+ });
562
+ cms.alerts.success("Document saved!");
563
+ } catch (e) {
564
+ cms.alerts.error("There was a problem saving your document");
565
+ console.error(e);
566
+ }
567
+ }
568
+ } catch (e) {
569
+ console.error(e);
570
+ cms.alerts.error("There was a problem saving your document");
571
+ }
901
572
  }
902
573
  };
903
- this.setToken = function(token) {
904
- localStorage.setItem(AUTH_TOKEN_KEY, JSON.stringify(token, null, 2));
574
+ const { createForm, createGlobalForm } = generateFormCreators(cms);
575
+ const SKIPPED = "SKIPPED";
576
+ let form;
577
+ let skipped;
578
+ const skip = () => {
579
+ skipped = SKIPPED;
905
580
  };
906
- break;
907
- case "MEMORY":
908
- this.getToken = async () => {
909
- if (this.token) {
910
- return await this.getRefreshedToken(this.token);
581
+ if (skipped)
582
+ return;
583
+ if (formify2) {
584
+ form = formify2({ formConfig, createForm, createGlobalForm, skip }, cms);
585
+ } else {
586
+ form = createForm(formConfig);
587
+ }
588
+ if (!(form instanceof toolkit.Form)) {
589
+ if (skipped === SKIPPED) {
590
+ return;
591
+ }
592
+ throw new Error("formify must return a form or skip()");
593
+ }
594
+ const { change } = form.finalForm;
595
+ form.finalForm.change = (name, value) => {
596
+ let referenceName = "";
597
+ if (typeof name === "string") {
598
+ referenceName = name.split(".").filter((item) => isNaN(Number(item))).join(".");
911
599
  } else {
912
- return {
913
- access_token: null,
914
- id_token: null,
915
- refresh_token: null
916
- };
600
+ throw new Error(`Expected name to be of type string for FinalForm change callback`);
917
601
  }
602
+ setNewUpdate({
603
+ queryName,
604
+ get: [queryName, "values", name].join("."),
605
+ set: [queryName, "data", name].join("."),
606
+ setReference: [queryName, "data", referenceName].join(".")
607
+ });
608
+ return change(name, value);
918
609
  };
919
- this.setToken = (token) => {
920
- this.token = JSON.stringify(token, null, 2);
610
+ const _a = form.finalForm.mutators, { insert, move, remove } = _a, rest = __objRest(_a, ["insert", "move", "remove"]);
611
+ const prepareNewUpdate = (name, lookup) => {
612
+ const extra = {};
613
+ if (lookup) {
614
+ extra["lookup"] = lookup;
615
+ }
616
+ const referenceName = name.split(".").filter((item) => isNaN(Number(item))).join(".");
617
+ setNewUpdate(__spreadValues({
618
+ queryName,
619
+ get: [queryName, "values", name].join("."),
620
+ set: [queryName, "data", name].join("."),
621
+ setReference: [queryName, "data", referenceName].join(".")
622
+ }, extra));
921
623
  };
922
- break;
923
- case "CUSTOM":
924
- if (!options.getTokenFn) {
925
- throw new Error("When CUSTOM token storage is selected, a getTokenFn must be provided");
624
+ form.finalForm.mutators = __spreadValues({
625
+ insert: (...args) => {
626
+ const fieldName = args[0];
627
+ prepareNewUpdate(fieldName, fieldName);
628
+ insert(...args);
629
+ },
630
+ move: (...args) => {
631
+ const fieldName = args[0];
632
+ prepareNewUpdate(fieldName, fieldName);
633
+ move(...args);
634
+ },
635
+ remove: (...args) => {
636
+ const fieldName = args[0];
637
+ prepareNewUpdate(fieldName, fieldName);
638
+ remove(...args);
639
+ }
640
+ }, rest);
641
+ form.subscribe(({ values }) => {
642
+ setFormValues(__spreadProps(__spreadValues({}, formValues), { [queryName]: { values } }));
643
+ }, { values: true });
644
+ });
645
+ }).catch((e) => {
646
+ cms.alerts.error("There was a problem setting up forms for your query");
647
+ console.error("There was a problem setting up forms for your query");
648
+ console.error(e);
649
+ setIsLoading(false);
650
+ });
651
+ return () => {
652
+ formIds.forEach((name) => {
653
+ const formPlugin = cms.forms.find(name);
654
+ if (formPlugin) {
655
+ cms.forms.remove(formPlugin);
926
656
  }
927
- this.getToken = options.getTokenFn;
928
- break;
929
- }
930
- }
931
- get isLocalMode() {
932
- return this.contentApiUrl.includes("localhost");
657
+ });
658
+ };
659
+ }, [query, JSON.stringify(variables), currentBranch]);
660
+ return [data, isLoading];
661
+ }
662
+ const transformDocumentIntoMutationRequestPayload = (document, instructions) => {
663
+ const _a = document, { _collection, __typename, _template } = _a, rest = __objRest(_a, ["_collection", "__typename", "_template"]);
664
+ const params = transformParams(rest);
665
+ const paramsWithTemplate = instructions.includeTemplate ? { [_template]: params } : params;
666
+ return instructions.includeCollection ? { [_collection]: paramsWithTemplate } : paramsWithTemplate;
667
+ };
668
+ const transformParams = (data) => {
669
+ if (["string", "number", "boolean"].includes(typeof data)) {
670
+ return data;
933
671
  }
934
- setBranch(branchName) {
935
- var _a, _b, _c;
936
- const encodedBranch = encodeURIComponent(branchName);
937
- this.frontendUrl = ((_a = this.options.tinaioConfig) == null ? void 0 : _a.frontendUrlOverride) || "https://app.tina.io";
938
- this.identityApiUrl = ((_b = this.options.tinaioConfig) == null ? void 0 : _b.identityApiUrlOverride) || "https://identity.tinajs.io";
939
- this.contentApiBase = ((_c = this.options.tinaioConfig) == null ? void 0 : _c.contentApiUrlOverride) || `https://content.tinajs.io`;
940
- this.contentApiUrl = this.options.customContentApiUrl || `${this.contentApiBase}/content/${this.options.clientId}/github/${encodedBranch}`;
672
+ if (Array.isArray(data)) {
673
+ return data.map((item) => transformParams(item));
941
674
  }
942
- async requestWithForm(query, {
943
- variables,
944
- useUnstableFormify
945
- }) {
946
- const schema = await this.getSchema();
947
- let formifiedQuery;
948
- if (useUnstableFormify) {
949
- const res = await formify({
950
- schema,
951
- query: G.print(query(gql__default["default"])),
952
- getOptimizedQuery: this.getOptimizedQuery
675
+ try {
676
+ assertShape(data, (yup2) => yup2.object({ _template: yup2.string().required() }));
677
+ const _a = data, { _template, __typename } = _a, rest = __objRest(_a, ["_template", "__typename"]);
678
+ const nested = transformParams(rest);
679
+ return { [_template]: nested };
680
+ } catch (e) {
681
+ if (e.message === "Failed to assertShape - _template is a required field") {
682
+ if (!data) {
683
+ return [];
684
+ }
685
+ const accum = {};
686
+ Object.entries(data).map(([keyName, value]) => {
687
+ accum[keyName] = transformParams(value);
953
688
  });
954
- formifiedQuery = res.formifiedQuery;
689
+ return accum;
955
690
  } else {
956
- formifiedQuery = formify$1(query(gql__default["default"]), schema);
691
+ if (!data) {
692
+ return [];
693
+ }
694
+ throw e;
957
695
  }
958
- return this.request(G.print(formifiedQuery), { variables });
959
696
  }
960
- async request(query, { variables }) {
961
- const res = await fetch(this.contentApiUrl, {
962
- method: "POST",
963
- headers: {
964
- "Content-Type": "application/json",
965
- Authorization: "Bearer " + (await this.getToken()).id_token
966
- },
967
- body: JSON.stringify({
968
- query: typeof query === "function" ? G.print(query(gql__default["default"])) : query,
969
- variables
970
- })
697
+ };
698
+ const getFieldUpdate = (newUpdate, activeForm, formValues) => {
699
+ const items = newUpdate.lookup.split(".");
700
+ let currentFields = activeForm.fields;
701
+ items.map((item, index) => {
702
+ const lookupName = items.slice(0, index + 1).join(".");
703
+ const value = finalForm.getIn(formValues, [newUpdate.queryName, "values", lookupName].join("."));
704
+ if (isNaN(Number(item))) {
705
+ if (Array.isArray(currentFields)) {
706
+ currentFields = currentFields.find((field) => field.name === item);
707
+ }
708
+ } else {
709
+ const template = currentFields.templates ? currentFields.templates[value._template] : currentFields;
710
+ currentFields = template.fields;
711
+ }
712
+ });
713
+ return currentFields;
714
+ };
715
+ const generateFormCreators = (cms) => {
716
+ const createForm = (formConfig) => {
717
+ const form = new toolkit.Form(formConfig);
718
+ cms.forms.add(form);
719
+ return form;
720
+ };
721
+ const createGlobalForm = (formConfig, options) => {
722
+ const form = new toolkit.Form(formConfig);
723
+ cms.plugins.add(new toolkit.GlobalFormPlugin(form, options == null ? void 0 : options.icon, options == null ? void 0 : options.layout));
724
+ return form;
725
+ };
726
+ return { createForm, createGlobalForm };
727
+ };
728
+ const generateFormCreatorsUnstable = (cms, showInSidebar) => {
729
+ const createForm = (formConfig) => {
730
+ const form = new toolkit.Form(formConfig);
731
+ if (showInSidebar) {
732
+ cms.forms.add(form);
733
+ }
734
+ return form;
735
+ };
736
+ const createGlobalForm = (formConfig, options) => {
737
+ const form = new toolkit.Form(formConfig);
738
+ if (showInSidebar) {
739
+ cms.plugins.add(new toolkit.GlobalFormPlugin(form, options == null ? void 0 : options.icon, options == null ? void 0 : options.layout));
740
+ }
741
+ return form;
742
+ };
743
+ return { createForm, createGlobalForm };
744
+ };
745
+ const isNodeField = (type) => {
746
+ if (G__namespace.isUnionType(type)) {
747
+ return type.getTypes().every((type2) => {
748
+ return type2.getInterfaces().find((intfc) => intfc.name === "Node");
971
749
  });
972
- if (res.status !== 200) {
973
- throw new Error(`Unable to complete request, ${res.statusText}`);
974
- }
975
- const json = await res.json();
976
- if (json.errors) {
977
- throw new Error(`Unable to fetch, errors:
978
- ${json.errors.map((error) => error.message).join("\n")}`);
750
+ } else if (G__namespace.isObjectType(type)) {
751
+ return !!type.getInterfaces().find((intfc) => intfc.name === "Node");
752
+ } else if (G__namespace.isInterfaceType(type)) {
753
+ if (type.name === "Node") {
754
+ return true;
979
755
  }
980
- return json.data;
756
+ } else {
757
+ return false;
981
758
  }
982
- parseJwt(token) {
983
- const base64Url = token.split(".")[1];
984
- const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
985
- const jsonPayload = decodeURIComponent(atob(base64).split("").map(function(c) {
986
- return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
987
- }).join(""));
988
- return JSON.parse(jsonPayload);
759
+ };
760
+ const isConnectionField = (type) => {
761
+ if (G__namespace.isObjectType(type)) {
762
+ return !!type.getInterfaces().find((intfc) => intfc.name === "Connection");
763
+ } else {
764
+ throw new Error(`Expected GraphQLObjectType for isConnectionField check`);
989
765
  }
990
- async getRefreshedToken(tokens) {
991
- const { access_token, id_token, refresh_token } = JSON.parse(tokens);
992
- const { exp, iss, client_id } = this.parseJwt(access_token);
993
- if (Date.now() / 1e3 >= exp - 120) {
994
- const refreshResponse = await fetch(iss, {
995
- method: "POST",
996
- headers: {
997
- "Content-Type": "application/x-amz-json-1.1",
998
- "x-amz-target": "AWSCognitoIdentityProviderService.InitiateAuth"
999
- },
1000
- body: JSON.stringify({
1001
- ClientId: client_id,
1002
- AuthFlow: "REFRESH_TOKEN_AUTH",
1003
- AuthParameters: {
1004
- REFRESH_TOKEN: refresh_token,
1005
- DEVICE_KEY: null
1006
- }
1007
- })
1008
- });
1009
- if (refreshResponse.status !== 200) {
1010
- throw new Error("Unable to refresh auth tokens");
1011
- }
1012
- const responseJson = await refreshResponse.json();
1013
- const newToken = {
1014
- access_token: responseJson.AuthenticationResult.AccessToken,
1015
- id_token: responseJson.AuthenticationResult.IdToken,
1016
- refresh_token
1017
- };
1018
- this.setToken(newToken);
1019
- return Promise.resolve(newToken);
766
+ };
767
+ const getObjectField = (object, selectionNode) => {
768
+ return object.getFields()[selectionNode.name.value];
769
+ };
770
+ const getSelectedUnionType = (unionType, selectionNode) => {
771
+ return unionType.getTypes().find((type) => type.name === selectionNode.typeCondition.name.value);
772
+ };
773
+ function isListType(type) {
774
+ if (G__namespace.isListType(type)) {
775
+ return true;
776
+ } else if (G__namespace.isNonNullType(type)) {
777
+ if (G__namespace.isListType(type.ofType)) {
778
+ return true;
1020
779
  }
1021
- return Promise.resolve({ access_token, id_token, refresh_token });
1022
780
  }
1023
- async isAuthorized() {
1024
- return this.isAuthenticated();
781
+ return false;
782
+ }
783
+ function ensureNodeField(field) {
784
+ if (!isNodeField(field)) {
785
+ throw new Error(`Expected field to implement Node interface`);
1025
786
  }
1026
- async isAuthenticated() {
1027
- return !!await this.getUser();
787
+ }
788
+ function ensureUnionType(type) {
789
+ if (!G__namespace.isUnionType(type)) {
790
+ throw new Error(`Expected type to be GraphQLUnionType`);
1028
791
  }
1029
- async authenticate() {
1030
- const token = await authenticate(this.clientId, this.frontendUrl);
1031
- this.setToken(token);
1032
- return token;
792
+ }
793
+ function ensureObjectType(type) {
794
+ if (!G__namespace.isObjectType(type)) {
795
+ console.log(type);
796
+ throw new Error(`Expected type to be GraphQLObjectType`);
1033
797
  }
1034
- async fetchWithToken(input, init) {
1035
- const headers = (init == null ? void 0 : init.headers) || {};
1036
- return await fetch(input, __spreadProps(__spreadValues({}, init), {
1037
- headers: new Headers(__spreadValues({
1038
- Authorization: "Bearer " + (await this.getToken()).id_token
1039
- }, headers))
1040
- }));
798
+ }
799
+ function ensureOperationDefinition(type) {
800
+ if (type.kind !== "OperationDefinition") {
801
+ throw new Error(`Expected top-level definition to be an OperationDefinition node, ensure your query has been optimized before calling formify`);
1041
802
  }
1042
- async getUser() {
1043
- if (!this.clientId) {
1044
- return null;
803
+ }
804
+ function getNameAndAlias(fieldNode, list, isNode) {
805
+ return {
806
+ name: fieldNode.name.value,
807
+ alias: fieldNode.alias ? fieldNode.alias.value : fieldNode.name.value,
808
+ list: !!list,
809
+ isNode: !!isNode
810
+ };
811
+ }
812
+ const node = G__namespace.parse(`
813
+ query Sample {
814
+ _internalSys: sys {
815
+ path
816
+ collection {
817
+ name
818
+ }
819
+ }
820
+ form
821
+ values
822
+ }`);
823
+ const metaFields = node.definitions[0].selectionSet.selections;
824
+ const getRelativeBlueprint = (path) => {
825
+ let indexOfLastNode = 0;
826
+ path.forEach((item, i) => {
827
+ if (item.isNode) {
828
+ if (i === path.length - 1)
829
+ ;
830
+ else {
831
+ indexOfLastNode = i;
832
+ }
1045
833
  }
1046
- const url = `${this.identityApiUrl}/v2/apps/${this.clientId}/currentUser`;
1047
- try {
1048
- const res = await this.fetchWithToken(url, {
1049
- method: "GET"
1050
- });
1051
- const val = await res.json();
1052
- if (!res.status.toString().startsWith("2")) {
1053
- console.error(val.error);
1054
- return null;
834
+ });
835
+ const documentBlueprintPath = path.slice(0, indexOfLastNode + 1);
836
+ return getBlueprintNamePath({ path: documentBlueprintPath });
837
+ };
838
+ const getIn2 = (state, path) => {
839
+ const pathArray = path.split(".");
840
+ let latest = state;
841
+ pathArray.every((item, index) => {
842
+ if (item === "[]") {
843
+ const restOfItems = pathArray.slice(index + 1);
844
+ if (latest) {
845
+ const next = [];
846
+ if (Array.isArray(latest)) {
847
+ latest.forEach((latest2, index2) => {
848
+ const res = getIn2(latest2, restOfItems.join("."));
849
+ next.push(res);
850
+ });
851
+ } else {
852
+ throw new Error(`Expected value to be an array for "[]" item`);
853
+ }
854
+ if (next.length > 0) {
855
+ latest = next;
856
+ } else {
857
+ latest = void 0;
858
+ }
859
+ }
860
+ return false;
861
+ } else {
862
+ if (latest) {
863
+ latest = latest[item];
864
+ } else {
865
+ latest = void 0;
1055
866
  }
1056
- return val;
1057
- } catch (e) {
1058
- console.error(e);
1059
- return null;
1060
867
  }
1061
- }
1062
- async listBranches() {
1063
- const url = `${this.contentApiBase}/github/${this.clientId}/list_branches`;
1064
- const res = await this.fetchWithToken(url, {
1065
- method: "GET"
1066
- });
1067
- return res.json();
1068
- }
1069
- async createBranch({ baseBranch, branchName }) {
1070
- const url = `${this.contentApiBase}/github/${this.clientId}/create_branch`;
1071
- try {
1072
- const res = await this.fetchWithToken(url, {
1073
- method: "POST",
1074
- body: JSON.stringify({
1075
- baseBranch,
1076
- branchName
1077
- }),
1078
- headers: {
1079
- "Content-Type": "application/json"
868
+ return true;
869
+ });
870
+ return latest;
871
+ };
872
+ const getFieldNameOrAlias = (fieldBlueprint) => {
873
+ return fieldBlueprint.path[fieldBlueprint.path.length - 1].alias;
874
+ };
875
+ const spliceLocation = (string, location) => {
876
+ const accum = [];
877
+ let counter = 0;
878
+ string.split(".").forEach((item) => {
879
+ if (item === "[]") {
880
+ accum.push(location[counter]);
881
+ counter++;
882
+ } else {
883
+ accum.push(item);
884
+ }
885
+ });
886
+ return accum.join(".");
887
+ };
888
+ const getPathToChange = (documentBlueprint, formNode, event) => {
889
+ const fieldName = event.field.name;
890
+ const location = [...formNode.location, ...stripIndices(fieldName)];
891
+ const accum = [];
892
+ let counter = 0;
893
+ documentBlueprint.path.forEach((item) => {
894
+ accum.push(item.alias);
895
+ if (item.list) {
896
+ if (location[counter] !== void 0) {
897
+ accum.push(location[counter]);
898
+ counter++;
899
+ }
900
+ }
901
+ });
902
+ return accum.join(".");
903
+ };
904
+ const buildForm = (doc, cms, formify2, showInSidebar = false, onSubmit) => {
905
+ const { createForm, createGlobalForm } = generateFormCreatorsUnstable(cms, showInSidebar);
906
+ const SKIPPED = "SKIPPED";
907
+ let form;
908
+ let skipped;
909
+ const skip = () => {
910
+ skipped = SKIPPED;
911
+ };
912
+ if (skipped)
913
+ return;
914
+ const id = doc._internalSys.path;
915
+ const formConfig = __spreadProps(__spreadValues({
916
+ id
917
+ }, doc.form), {
918
+ label: doc.form.label,
919
+ initialValues: doc.values,
920
+ onSubmit: async (payload) => {
921
+ try {
922
+ const params = transformDocumentIntoMutationRequestPayload(payload, doc.form.mutationInfo);
923
+ const variables = { params };
924
+ const mutationString = doc.form.mutationInfo.string;
925
+ if (onSubmit) {
926
+ onSubmit({
927
+ queryString: mutationString,
928
+ mutationString,
929
+ variables
930
+ });
931
+ } else {
932
+ try {
933
+ await cms.api.tina.request(mutationString, {
934
+ variables
935
+ });
936
+ cms.alerts.success("Document saved!");
937
+ } catch (e) {
938
+ cms.alerts.error("There was a problem saving your document");
939
+ console.error(e);
940
+ }
1080
941
  }
1081
- });
1082
- return await res.json().then((r) => parseRefForBranchName(r.data.ref));
1083
- } catch (error) {
1084
- console.error("There was an error creating a new branch.", error);
1085
- return null;
942
+ } catch (e) {
943
+ console.error(e);
944
+ cms.alerts.error("There was a problem saving your document");
945
+ }
1086
946
  }
947
+ });
948
+ if (formify2) {
949
+ form = formify2({
950
+ formConfig,
951
+ createForm,
952
+ createGlobalForm,
953
+ skip
954
+ }, cms);
955
+ } else {
956
+ form = createForm(formConfig);
1087
957
  }
1088
- }
1089
- const DEFAULT_LOCAL_TINA_GQL_SERVER_URL = "http://localhost:4001/graphql";
1090
- class LocalClient extends Client {
1091
- constructor(props) {
1092
- const clientProps = {
1093
- clientId: "",
1094
- branch: "",
1095
- customContentApiUrl: props && props.customContentApiUrl ? props.customContentApiUrl : DEFAULT_LOCAL_TINA_GQL_SERVER_URL
1096
- };
1097
- super(clientProps);
958
+ if (!(form instanceof toolkit.Form)) {
959
+ if (skipped === SKIPPED) {
960
+ return;
961
+ }
962
+ throw new Error("formify must return a form or skip()");
1098
963
  }
1099
- async isAuthorized() {
1100
- return true;
964
+ return form;
965
+ };
966
+ const formNodeId = (formNode) => {
967
+ return spliceLocation(formNode.documentBlueprintId, formNode.location) + formNode.documentFormId;
968
+ };
969
+ const formNodePath = (formNode) => {
970
+ return spliceLocation(formNode.documentBlueprintId, formNode.location);
971
+ };
972
+ const formNodeNotIn = (formNode, formNodes) => {
973
+ return !formNodes.find((fn) => formNodeId(fn) === formNodeId(formNode));
974
+ };
975
+ const sequential = async (items, callback) => {
976
+ const accum = [];
977
+ if (!items) {
978
+ return [];
1101
979
  }
1102
- async isAuthenticated() {
1103
- return true;
980
+ const reducePromises = async (previous, endpoint) => {
981
+ const prev = await previous;
982
+ if (prev) {
983
+ accum.push(prev);
984
+ }
985
+ return callback(endpoint, accum.length);
986
+ };
987
+ const result = await items.reduce(reducePromises, Promise.resolve());
988
+ if (result) {
989
+ accum.push(result);
1104
990
  }
1105
- }
1106
- function ModalBuilder(modalProps) {
1107
- return /* @__PURE__ */ React__default["default"].createElement(toolkit.Modal, null, /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalPopup, null, /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalHeader, null, modalProps.title), /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalBody, {
1108
- padded: true
1109
- }, /* @__PURE__ */ React__default["default"].createElement("p", null, modalProps.message), modalProps.error && /* @__PURE__ */ React__default["default"].createElement(ErrorLabel, null, modalProps.error)), /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalActions, null, modalProps.actions.map((action) => /* @__PURE__ */ React__default["default"].createElement(AsyncButton, __spreadValues({
1110
- key: action.name
1111
- }, action))))));
1112
- }
1113
- const ErrorLabel = styled__default["default"].p`
1114
- color: var(--tina-color-error) !important;
1115
- `;
1116
- const AsyncButton = ({ name, primary, action }) => {
1117
- const [submitting, setSubmitting] = React.useState(false);
1118
- const onClick = React.useCallback(async () => {
1119
- setSubmitting(true);
1120
- try {
1121
- await action();
1122
- setSubmitting(false);
1123
- } catch (e) {
1124
- setSubmitting(false);
1125
- throw e;
991
+ return accum;
992
+ };
993
+ const getBlueprintId = (path) => {
994
+ const namePath = [];
995
+ const aliasPath = [];
996
+ path.forEach((p) => {
997
+ namePath.push(p.name);
998
+ aliasPath.push(p.alias);
999
+ if (p.list) {
1000
+ namePath.push("[]");
1001
+ aliasPath.push("[]");
1126
1002
  }
1127
- }, [action, setSubmitting]);
1128
- return /* @__PURE__ */ React__default["default"].createElement(toolkit.Button, {
1129
- variant: primary ? "primary" : "secondary",
1130
- onClick,
1131
- busy: submitting,
1132
- disabled: submitting
1133
- }, submitting && /* @__PURE__ */ React__default["default"].createElement(toolkit.LoadingDots, null), !submitting && name);
1003
+ });
1004
+ return namePath.join(".");
1005
+ };
1006
+ const getFormNodesStartingWith = (string, state) => {
1007
+ return state.formNodes.filter((subFormNode) => {
1008
+ return subFormNode.documentBlueprintId.startsWith(string);
1009
+ });
1010
+ };
1011
+ const getFormNodesForField = (fieldBlueprint, formNode, event, state) => {
1012
+ const pathToChange = getPathToChange(fieldBlueprint, formNode, event);
1013
+ const formNodes = getFormNodesStartingWith(fieldBlueprint.id, state);
1014
+ const eventLocation = [
1015
+ ...formNode.location,
1016
+ ...stripIndices(event.field.name)
1017
+ ];
1018
+ const existing = finalForm.getIn(state.data, pathToChange);
1019
+ return { pathToChange, formNodes, eventLocation, existing };
1020
+ };
1021
+ const matchLocation = (eventLocation, formNode) => {
1022
+ return eventLocation.every((item, index) => item === formNode.location[index]);
1023
+ };
1024
+ const bumpLocation = (location) => {
1025
+ return location.map((item, index) => {
1026
+ if (index === location.length - 1) {
1027
+ return item + 1;
1028
+ }
1029
+ return item;
1030
+ });
1031
+ };
1032
+ const maybeLowerLocation = (location, at) => {
1033
+ return location.map((item, index) => {
1034
+ if (index === location.length - 1) {
1035
+ return item < at ? item : item - 1;
1036
+ }
1037
+ return item;
1038
+ });
1039
+ };
1040
+ const matchesAt = (location, at) => {
1041
+ let matches = false;
1042
+ location.map((item, index) => {
1043
+ if (index === location.length - 1) {
1044
+ if (item === at) {
1045
+ matches = true;
1046
+ }
1047
+ }
1048
+ });
1049
+ return matches;
1134
1050
  };
1135
- const TINA_AUTH_CONFIG = "tina_auth_config";
1136
- const useTinaAuthRedirect = () => {
1137
- React.useEffect(() => {
1138
- const urlParams = new URLSearchParams(window.location.search);
1139
- const config = {
1140
- code: urlParams.get("code") || "",
1141
- scope: urlParams.get("scope") || "email",
1142
- state: urlParams.get("state")
1143
- };
1144
- if (!config.code) {
1145
- return;
1051
+ const swapLocation = (location, mapping) => {
1052
+ return location.map((item, index) => {
1053
+ if (index === location.length - 1) {
1054
+ return mapping[item];
1146
1055
  }
1147
- localStorage[TINA_AUTH_CONFIG] = JSON.stringify(config);
1148
- }, []);
1056
+ return item;
1057
+ });
1149
1058
  };
1150
- const createClient = ({
1151
- clientId,
1152
- isLocalClient = true,
1153
- branch,
1154
- tinaioConfig
1155
- }) => {
1156
- return isLocalClient ? new LocalClient() : new Client({
1157
- clientId: clientId || "",
1158
- branch: branch || "main",
1159
- tokenStorage: "LOCAL_STORAGE",
1160
- tinaioConfig
1059
+ const getBlueprintAliasPath = (blueprint) => {
1060
+ const namePath = [];
1061
+ const aliasPath = [];
1062
+ blueprint.path.forEach((p) => {
1063
+ namePath.push(p.name);
1064
+ aliasPath.push(p.alias);
1065
+ if (p.list) {
1066
+ namePath.push("[]");
1067
+ aliasPath.push("[]");
1068
+ }
1161
1069
  });
1070
+ return aliasPath.join(".");
1162
1071
  };
1163
- function assertShape(value, yupSchema, errorMessage) {
1164
- const shape = yupSchema(yup__namespace);
1165
- try {
1166
- shape.validateSync(value);
1167
- } catch (e) {
1168
- const message = errorMessage || `Failed to assertShape - ${e.message}`;
1169
- throw new Error(message);
1170
- }
1171
- }
1172
- function safeAssertShape(value, yupSchema) {
1173
- try {
1174
- assertShape(value, yupSchema);
1175
- return true;
1176
- } catch (e) {
1177
- return false;
1178
- }
1179
- }
1180
- class TinaAdminApi {
1181
- constructor(cms) {
1182
- this.api = cms.api.tina;
1183
- }
1184
- async isAuthenticated() {
1185
- return await this.api.isAuthenticated();
1186
- }
1187
- async fetchCollections() {
1188
- const response = await this.api.request(`#graphql
1189
- query{
1190
- getCollections {
1191
- label,
1192
- name
1193
- }
1194
- }`, { variables: {} });
1195
- return response;
1072
+ const getBlueprintFieldsForEvent = (blueprint, event) => {
1073
+ return blueprint.fields.filter((fbp) => {
1074
+ return getBlueprintNamePath(fbp) === getEventPath(event, blueprint);
1075
+ });
1076
+ };
1077
+ const getBlueprintNamePath = (blueprint) => {
1078
+ const namePath = [];
1079
+ const aliasPath = [];
1080
+ blueprint.path.forEach((p) => {
1081
+ namePath.push(p.name);
1082
+ aliasPath.push(p.alias);
1083
+ if (p.list) {
1084
+ namePath.push("[]");
1085
+ aliasPath.push("[]");
1086
+ }
1087
+ });
1088
+ return namePath.join(".");
1089
+ };
1090
+ const stripIndices = (string) => {
1091
+ const accum = [];
1092
+ const stringArray = string.split(".");
1093
+ stringArray.forEach((item) => {
1094
+ if (isNaN(item))
1095
+ ;
1096
+ else {
1097
+ accum.push(Number(item));
1098
+ }
1099
+ });
1100
+ return accum;
1101
+ };
1102
+ const replaceRealNum = (string) => {
1103
+ const stringArray = string.split(".");
1104
+ return stringArray.map((item) => {
1105
+ if (isNaN(item)) {
1106
+ return item;
1107
+ }
1108
+ return "[]";
1109
+ }).join(".");
1110
+ };
1111
+ const getFormNodesFromEvent = (state, event) => {
1112
+ const formNodes = state.formNodes.filter((formNode) => formNode.documentFormId === event.formId);
1113
+ return formNodes;
1114
+ };
1115
+ const DATA_NODE_NAME$1 = "data";
1116
+ const getEventPath = (event, blueprint) => {
1117
+ const eventPath = replaceRealNum(event.field.name);
1118
+ const items = [blueprint.id, DATA_NODE_NAME$1, eventPath];
1119
+ const isList = event.field.data.tinaField.list;
1120
+ if (isList && !eventPath.endsWith("[]")) {
1121
+ items.push("[]");
1196
1122
  }
1197
- async fetchCollection(collectionName, includeDocuments) {
1198
- const response = await this.api.request(`#graphql
1199
- query($collection: String!, $includeDocuments: Boolean!){
1200
- getCollection(collection: $collection){
1201
- name
1202
- label
1203
- format
1204
- templates
1205
- documents @include(if: $includeDocuments) {
1206
- totalCount
1207
- edges {
1208
- node {
1209
- ... on Document {
1210
- sys {
1211
- template
1212
- breadcrumbs
1213
- path
1214
- basename
1215
- relativePath
1216
- filename
1217
- extension
1218
- }
1219
- }
1220
- }
1123
+ return items.join(".");
1124
+ };
1125
+ const printEvent = (event) => {
1126
+ var _a, _b;
1127
+ return {
1128
+ type: event.type,
1129
+ value: event.value,
1130
+ previousValue: event.previousValue,
1131
+ mutationType: event.mutationType,
1132
+ formId: event.formId,
1133
+ field: {
1134
+ data: (_a = event.field) == null ? void 0 : _a.data,
1135
+ name: (_b = event.field) == null ? void 0 : _b.name
1136
+ }
1137
+ };
1138
+ };
1139
+ const getFormNodeBlueprint = (formNode, state) => {
1140
+ return state.blueprints.find((d) => d.id === formNode.documentBlueprintId);
1141
+ };
1142
+ const getMoveMapping = (existing, from, to) => {
1143
+ const newOrderObject = {};
1144
+ if (from < to) {
1145
+ existing.map((_, i) => {
1146
+ if (i === from) {
1147
+ newOrderObject[i] = to;
1148
+ return;
1149
+ }
1150
+ if (i > from) {
1151
+ if (i < to) {
1152
+ newOrderObject[i] = i - 1;
1153
+ return;
1154
+ } else {
1155
+ if (i === to) {
1156
+ newOrderObject[i] = i - 1;
1157
+ return;
1221
1158
  }
1159
+ newOrderObject[i] = i;
1160
+ return;
1222
1161
  }
1162
+ } else {
1163
+ newOrderObject[i] = i;
1164
+ return;
1223
1165
  }
1224
- }`, { variables: { collection: collectionName, includeDocuments } });
1225
- return response;
1226
- }
1227
- async fetchDocument(collectionName, relativePath) {
1228
- const response = await this.api.request(`#graphql
1229
- query($collection: String!, $relativePath: String!) {
1230
- getDocument(collection:$collection, relativePath:$relativePath) {
1231
- ... on Document {
1232
- form
1233
- values
1234
- }
1166
+ });
1167
+ } else {
1168
+ existing.map((_, i) => {
1169
+ if (i === from) {
1170
+ newOrderObject[i] = to;
1171
+ return;
1235
1172
  }
1236
- }`, { variables: { collection: collectionName, relativePath } });
1237
- return response;
1238
- }
1239
- async fetchDocumentFields() {
1240
- const response = await this.api.request(`#graphql
1241
- query {
1242
- getDocumentFields
1243
- }`, { variables: {} });
1244
- return response;
1245
- }
1246
- async createDocument(collectionName, relativePath, params) {
1247
- const response = await this.api.request(`#graphql
1248
- mutation($collection: String!, $relativePath: String!, $params: DocumentMutation!) {
1249
- createDocument(
1250
- collection: $collection,
1251
- relativePath: $relativePath,
1252
- params: $params
1253
- ){__typename}
1254
- }`, {
1255
- variables: {
1256
- collection: collectionName,
1257
- relativePath,
1258
- params
1173
+ if (i > to) {
1174
+ if (i < from) {
1175
+ newOrderObject[i] = i + 1;
1176
+ return;
1177
+ } else {
1178
+ newOrderObject[i] = i;
1179
+ return;
1180
+ }
1181
+ } else {
1182
+ if (i === to) {
1183
+ newOrderObject[i] = i + 1;
1184
+ return;
1185
+ }
1186
+ newOrderObject[i] = i;
1187
+ return;
1259
1188
  }
1260
1189
  });
1261
- return response;
1262
1190
  }
1263
- async updateDocument(collectionName, relativePath, params) {
1264
- const response = await this.api.request(`#graphql
1265
- mutation($collection: String!, $relativePath: String!, $params: DocumentMutation!) {
1266
- updateDocument(
1267
- collection: $collection,
1268
- relativePath: $relativePath,
1269
- params: $params
1270
- ){__typename}
1271
- }`, {
1272
- variables: {
1273
- collection: collectionName,
1274
- relativePath,
1275
- params
1276
- }
1191
+ return newOrderObject;
1192
+ };
1193
+ const getPathsToChange = (event, state) => {
1194
+ const pathsToChange = [];
1195
+ const formNodes = getFormNodesFromEvent(state, event);
1196
+ formNodes.forEach((formNode) => {
1197
+ const blueprint = getFormNodeBlueprint(formNode, state);
1198
+ getBlueprintFieldsForEvent(blueprint, event).forEach((fieldBlueprint) => {
1199
+ const pathToChange = getPathToChange(fieldBlueprint, formNode, event);
1200
+ pathsToChange.push({ pathToChange, formNode });
1277
1201
  });
1278
- return response;
1202
+ });
1203
+ return pathsToChange;
1204
+ };
1205
+ const getSubFields = (changeSet) => {
1206
+ var _a;
1207
+ const fields = changeSet.fieldDefinition.fields ? changeSet.fieldDefinition.fields : changeSet.fieldDefinition.templates[changeSet.value[0]._template].fields;
1208
+ let __typename;
1209
+ if ((_a = changeSet.fieldDefinition) == null ? void 0 : _a.templates) {
1210
+ __typename = changeSet.fieldDefinition.typeMap[changeSet.value[0]._template];
1279
1211
  }
1280
- }
1281
- function sleep(ms) {
1282
- return new Promise((resolve) => setTimeout(resolve, ms));
1283
- }
1284
- const AuthWallInner = ({
1285
- children,
1286
- cms,
1287
- loginScreen,
1288
- getModalActions
1212
+ return { fields, __typename };
1213
+ };
1214
+ const NOOP = "This is either an error or is not yet supported";
1215
+ const UNEXPECTED = "Formify encountered an unexpected error, please contact support";
1216
+ const EDGES_NODE_NAME = "edges";
1217
+ const NODE_NAME = "node";
1218
+ const COLLECTION_FIELD_NAME = "getCollection";
1219
+ const COLLECTIONS_FIELD_NAME = "getCollections";
1220
+ const COLLECTIONS_DOCUMENTS_NAME = "documents";
1221
+ const DATA_NODE_NAME = "data";
1222
+ const formify = async ({
1223
+ schema,
1224
+ query,
1225
+ getOptimizedQuery
1289
1226
  }) => {
1290
- const client = cms.api.tina;
1291
- const [activeModal, setActiveModal] = React.useState(null);
1292
- const [showChildren, setShowChildren] = React.useState(false);
1293
- React__default["default"].useEffect(() => {
1294
- client.isAuthenticated().then((isAuthenticated) => {
1295
- if (isAuthenticated) {
1296
- setShowChildren(true);
1297
- cms.enable();
1298
- } else {
1299
- sleep(500).then(() => {
1300
- setActiveModal("authenticate");
1227
+ const blueprints = [];
1228
+ const documentNode = G__namespace.parse(query);
1229
+ const visitor = {
1230
+ OperationDefinition: (node2) => {
1231
+ if (!node2.name) {
1232
+ return __spreadProps(__spreadValues({}, node2), {
1233
+ name: {
1234
+ kind: "Name",
1235
+ value: `QueryOperation`
1236
+ }
1301
1237
  });
1302
1238
  }
1239
+ return node2;
1240
+ }
1241
+ };
1242
+ const documentNodeWithName = G__namespace.visit(documentNode, visitor);
1243
+ const optimizedQuery = await getOptimizedQuery(documentNodeWithName);
1244
+ const typeInfo = new G__namespace.TypeInfo(schema);
1245
+ const formifyConnection = ({
1246
+ namedFieldType,
1247
+ selectionNode,
1248
+ path
1249
+ }) => {
1250
+ ensureObjectType(namedFieldType);
1251
+ return __spreadProps(__spreadValues({}, selectionNode), {
1252
+ selectionSet: {
1253
+ kind: "SelectionSet",
1254
+ selections: selectionNode.selectionSet.selections.map((selectionNode2) => {
1255
+ switch (selectionNode2.kind) {
1256
+ case "Field":
1257
+ if (selectionNode2.name.value === EDGES_NODE_NAME) {
1258
+ const edgeField = namedFieldType.getFields()[EDGES_NODE_NAME];
1259
+ const edgeType = G__namespace.getNamedType(edgeField.type);
1260
+ ensureObjectType(edgeType);
1261
+ const path2 = [
1262
+ ...path,
1263
+ getNameAndAlias(selectionNode2, true, false)
1264
+ ];
1265
+ return __spreadProps(__spreadValues({}, selectionNode2), {
1266
+ selectionSet: {
1267
+ kind: "SelectionSet",
1268
+ selections: selectionNode2.selectionSet.selections.map((subSelectionNode) => {
1269
+ switch (subSelectionNode.kind) {
1270
+ case "Field":
1271
+ if (subSelectionNode.name.value === NODE_NAME) {
1272
+ const nodeField = edgeType.getFields()[NODE_NAME];
1273
+ const path3 = [
1274
+ ...path2,
1275
+ getNameAndAlias(subSelectionNode, false, true)
1276
+ ];
1277
+ return formifyNode({
1278
+ fieldOrInlineFragmentNode: subSelectionNode,
1279
+ type: nodeField.type,
1280
+ path: path3,
1281
+ showInSidebar: false
1282
+ });
1283
+ } else {
1284
+ return subSelectionNode;
1285
+ }
1286
+ default:
1287
+ throw new FormifyError("NOOP");
1288
+ }
1289
+ })
1290
+ }
1291
+ });
1292
+ }
1293
+ return selectionNode2;
1294
+ default:
1295
+ throw new FormifyError("UNEXPECTED");
1296
+ }
1297
+ })
1298
+ }
1303
1299
  });
1304
- }, []);
1305
- const onAuthSuccess = async () => {
1306
- if (await client.isAuthenticated()) {
1307
- setShowChildren(true);
1308
- setActiveModal(null);
1309
- } else {
1310
- throw new Error("No access to repo");
1311
- }
1312
1300
  };
1313
- const otherModalActions = getModalActions ? getModalActions({
1314
- closeModal: () => {
1315
- setActiveModal(null);
1301
+ function formifyNode({
1302
+ fieldOrInlineFragmentNode,
1303
+ type,
1304
+ path,
1305
+ showInSidebar = false
1306
+ }) {
1307
+ let extraFields = [];
1308
+ const namedType = G__namespace.getNamedType(type);
1309
+ let hasDataJSONField = false;
1310
+ let hasValuesField = false;
1311
+ let shouldFormify = false;
1312
+ fieldOrInlineFragmentNode.selectionSet.selections.forEach((selection) => {
1313
+ if (selection.kind === "Field") {
1314
+ if (selection.name.value === "dataJSON") {
1315
+ shouldFormify = true;
1316
+ hasDataJSONField = true;
1317
+ }
1318
+ if (selection.name.value === "values") {
1319
+ shouldFormify = true;
1320
+ hasValuesField = true;
1321
+ }
1322
+ if (selection.name.value === "data") {
1323
+ shouldFormify = true;
1324
+ }
1325
+ }
1326
+ });
1327
+ if (shouldFormify) {
1328
+ blueprints.push({
1329
+ id: getBlueprintId(path),
1330
+ path,
1331
+ selection: fieldOrInlineFragmentNode,
1332
+ fields: [],
1333
+ showInSidebar,
1334
+ hasDataJSONField,
1335
+ hasValuesField
1336
+ });
1337
+ extraFields = metaFields;
1316
1338
  }
1317
- }) : [];
1318
- return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, activeModal === "authenticate" && /* @__PURE__ */ React__default["default"].createElement(ModalBuilder, {
1319
- title: "Tina Cloud Authorization",
1320
- message: "To save edits, Tina Cloud authorization is required. On save, changes will get commited using your account.",
1321
- close,
1322
- actions: [
1323
- ...otherModalActions,
1324
- {
1325
- action: async () => {
1326
- sharedctx.setEditing(false);
1327
- window.location.reload();
1328
- },
1329
- name: "Close",
1330
- primary: false
1331
- },
1332
- {
1333
- name: "Continue to Tina Cloud",
1334
- action: async () => {
1335
- await client.authenticate();
1336
- onAuthSuccess();
1337
- },
1338
- primary: true
1339
+ const formifiedNode = __spreadProps(__spreadValues({}, fieldOrInlineFragmentNode), {
1340
+ selectionSet: {
1341
+ kind: "SelectionSet",
1342
+ selections: [
1343
+ ...fieldOrInlineFragmentNode.selectionSet.selections.map((selectionNode) => {
1344
+ switch (selectionNode.kind) {
1345
+ case "InlineFragment":
1346
+ if (G__namespace.isInterfaceType(namedType)) {
1347
+ const subType2 = schema.getImplementations(namedType).objects.find((item) => item.name === selectionNode.typeCondition.name.value);
1348
+ return formifyNode({
1349
+ fieldOrInlineFragmentNode: selectionNode,
1350
+ type: subType2,
1351
+ path,
1352
+ showInSidebar: false
1353
+ });
1354
+ }
1355
+ ensureUnionType(namedType);
1356
+ const subType = getSelectedUnionType(namedType, selectionNode);
1357
+ return formifyNode({
1358
+ fieldOrInlineFragmentNode: selectionNode,
1359
+ type: subType,
1360
+ path,
1361
+ showInSidebar
1362
+ });
1363
+ case "Field":
1364
+ if (selectionNode.name.value === DATA_NODE_NAME) {
1365
+ const path2 = [
1366
+ ...path,
1367
+ getNameAndAlias(selectionNode, false, false)
1368
+ ];
1369
+ if (G__namespace.isObjectType(namedType)) {
1370
+ const field = getObjectField(namedType, selectionNode);
1371
+ const namedSubType = G__namespace.getNamedType(field.type);
1372
+ ensureObjectType(namedSubType);
1373
+ return __spreadProps(__spreadValues({}, selectionNode), {
1374
+ selectionSet: {
1375
+ kind: "SelectionSet",
1376
+ selections: [
1377
+ ...selectionNode.selectionSet.selections.map((subSelectionNode) => {
1378
+ switch (subSelectionNode.kind) {
1379
+ case "Field":
1380
+ const subSelectionField = getObjectField(namedSubType, subSelectionNode);
1381
+ if (!subSelectionField) {
1382
+ return subSelectionNode;
1383
+ }
1384
+ const subSelectionType = G__namespace.getNamedType(subSelectionField.type);
1385
+ return formifyField({
1386
+ fieldNode: subSelectionNode,
1387
+ parentType: field.type,
1388
+ path: [
1389
+ ...path2,
1390
+ getNameAndAlias(subSelectionNode, isListType(subSelectionField.type), isNodeField(subSelectionType))
1391
+ ]
1392
+ });
1393
+ default:
1394
+ throw new FormifyError("UNEXPECTED", `selection ${subSelectionNode.kind}`);
1395
+ }
1396
+ })
1397
+ ]
1398
+ }
1399
+ });
1400
+ }
1401
+ throw new FormifyError("UNEXPECTED");
1402
+ }
1403
+ return selectionNode;
1404
+ default:
1405
+ throw new FormifyError("UNEXPECTED");
1406
+ }
1407
+ }),
1408
+ ...extraFields
1409
+ ]
1339
1410
  }
1340
- ]
1341
- }), showChildren ? children : loginScreen ? loginScreen : null);
1342
- };
1343
- const TinaCloudProvider = (props) => {
1344
- const baseBranch = props.branch || "main";
1345
- const [currentBranch, setCurrentBranch] = toolkit.useLocalStorage("tinacms-current-branch", baseBranch);
1346
- useTinaAuthRedirect();
1347
- const cms = React__default["default"].useMemo(() => props.cms || new toolkit.TinaCMS({
1348
- enabled: true,
1349
- sidebar: true
1350
- }), [props.cms]);
1351
- if (!cms.api.tina) {
1352
- cms.registerApi("tina", createClient(props));
1353
- }
1354
- if (!cms.api.admin) {
1355
- cms.registerApi("admin", new TinaAdminApi(cms));
1411
+ });
1412
+ return formifiedNode;
1356
1413
  }
1357
- const setupMedia = async () => {
1358
- var _a;
1359
- if (props.mediaStore) {
1360
- if ((_a = props.mediaStore.prototype) == null ? void 0 : _a.persist) {
1361
- cms.media.store = new props.mediaStore(cms.api.tina);
1414
+ const formifyField = ({
1415
+ fieldNode,
1416
+ parentType,
1417
+ path
1418
+ }) => {
1419
+ const namedParentType = G__namespace.getNamedType(parentType);
1420
+ ensureObjectType(namedParentType);
1421
+ const field = getObjectField(namedParentType, fieldNode);
1422
+ if (!field) {
1423
+ if (fieldNode.name.value === "__typename") {
1424
+ return fieldNode;
1362
1425
  } else {
1363
- const MediaClass = await props.mediaStore();
1364
- cms.media.store = new MediaClass(cms.api.tina);
1426
+ throw new FormifyError("UNEXPECTED", `field with no associated type ${fieldNode.name.value}`);
1365
1427
  }
1366
1428
  }
1429
+ const namedType = G__namespace.getNamedType(field.type);
1430
+ const fieldBlueprint = {
1431
+ id: getBlueprintId([...path]),
1432
+ documentBlueprintId: getRelativeBlueprint(path),
1433
+ path: [...path]
1434
+ };
1435
+ const blueprint = blueprints.find((blueprint2) => blueprint2.id === getRelativeBlueprint(path));
1436
+ blueprint.fields.push(fieldBlueprint);
1437
+ if (G__namespace.isScalarType(namedType)) {
1438
+ return fieldNode;
1439
+ }
1440
+ return __spreadProps(__spreadValues({}, fieldNode), {
1441
+ selectionSet: {
1442
+ kind: "SelectionSet",
1443
+ selections: [
1444
+ ...fieldNode.selectionSet.selections.map((selectionNode) => {
1445
+ switch (selectionNode.kind) {
1446
+ case "Field":
1447
+ if (selectionNode.name.value === "__typename") {
1448
+ return selectionNode;
1449
+ }
1450
+ ensureObjectType(namedType);
1451
+ const subField = getObjectField(namedType, selectionNode);
1452
+ if (!subField) {
1453
+ return fieldNode;
1454
+ }
1455
+ if (G__namespace.isScalarType(G__namespace.getNamedType(subField.type))) {
1456
+ const newPath2 = [
1457
+ ...path,
1458
+ getNameAndAlias(selectionNode, isListType(subField.type), false)
1459
+ ];
1460
+ const fieldBlueprint3 = {
1461
+ id: getBlueprintId(newPath2),
1462
+ documentBlueprintId: getRelativeBlueprint(newPath2),
1463
+ path: newPath2
1464
+ };
1465
+ const blueprint3 = blueprints.find((blueprint4) => blueprint4.id === getRelativeBlueprint(path));
1466
+ blueprint3.fields.push(fieldBlueprint3);
1467
+ return selectionNode;
1468
+ }
1469
+ const subFieldType = subField.type;
1470
+ const namedSubFieldType = G__namespace.getNamedType(subFieldType);
1471
+ const newPath = [
1472
+ ...path,
1473
+ getNameAndAlias(selectionNode, isListType(subFieldType), isNodeField(namedSubFieldType))
1474
+ ];
1475
+ const fieldBlueprint2 = {
1476
+ id: getBlueprintId(newPath),
1477
+ documentBlueprintId: getRelativeBlueprint(newPath),
1478
+ path: newPath
1479
+ };
1480
+ const blueprint2 = blueprints.find((blueprint3) => blueprint3.id === getRelativeBlueprint(path));
1481
+ blueprint2.fields.push(fieldBlueprint2);
1482
+ return __spreadProps(__spreadValues({}, selectionNode), {
1483
+ selectionSet: {
1484
+ kind: "SelectionSet",
1485
+ selections: selectionNode.selectionSet.selections.map((subSelectionNode) => {
1486
+ switch (subSelectionNode.kind) {
1487
+ case "Field":
1488
+ if (subSelectionNode.name.value === "__typename") {
1489
+ return subSelectionNode;
1490
+ }
1491
+ ensureObjectType(namedSubFieldType);
1492
+ const subField1 = getObjectField(namedSubFieldType, subSelectionNode);
1493
+ const subType1 = subField1.type;
1494
+ const namedSubType2 = G__namespace.getNamedType(subType1);
1495
+ return formifyField({
1496
+ fieldNode: subSelectionNode,
1497
+ parentType: subFieldType,
1498
+ path: [
1499
+ ...path,
1500
+ getNameAndAlias(subSelectionNode, isListType(subType1), isNodeField(namedSubType2))
1501
+ ]
1502
+ });
1503
+ case "InlineFragment":
1504
+ const subNamedType = G__namespace.getNamedType(subField.type);
1505
+ ensureNodeField(subNamedType);
1506
+ ensureUnionType(subNamedType);
1507
+ const subType2 = getSelectedUnionType(subNamedType, subSelectionNode);
1508
+ const newPath2 = [
1509
+ ...path,
1510
+ getNameAndAlias(selectionNode, isListType(subField.type), true)
1511
+ ];
1512
+ return formifyNode({
1513
+ fieldOrInlineFragmentNode: subSelectionNode,
1514
+ type: subType2,
1515
+ path: newPath2,
1516
+ showInSidebar: false
1517
+ });
1518
+ default:
1519
+ throw new FormifyError("UNEXPECTED", `selection ${subSelectionNode.kind}`);
1520
+ }
1521
+ })
1522
+ }
1523
+ });
1524
+ case "InlineFragment":
1525
+ ensureUnionType(namedType);
1526
+ if (isNodeField(namedType)) {
1527
+ const parentType2 = getSelectedUnionType(namedType, selectionNode);
1528
+ return formifyNode({
1529
+ fieldOrInlineFragmentNode: selectionNode,
1530
+ type: parentType2,
1531
+ path,
1532
+ showInSidebar: false
1533
+ });
1534
+ }
1535
+ const subType = getSelectedUnionType(namedType, selectionNode);
1536
+ const namedSubType = G__namespace.getNamedType(subType);
1537
+ return __spreadProps(__spreadValues({}, selectionNode), {
1538
+ selectionSet: {
1539
+ kind: "SelectionSet",
1540
+ selections: selectionNode.selectionSet.selections.map((subSelectionNode) => {
1541
+ switch (subSelectionNode.kind) {
1542
+ case "Field":
1543
+ ensureObjectType(namedSubType);
1544
+ const subField2 = getObjectField(namedSubType, subSelectionNode);
1545
+ const subType2 = subField2.type;
1546
+ const namedSubType2 = G__namespace.getNamedType(subType2);
1547
+ return formifyField({
1548
+ fieldNode: subSelectionNode,
1549
+ parentType: subType,
1550
+ path: [
1551
+ ...path,
1552
+ getNameAndAlias(subSelectionNode, isListType(subType2), isNodeField(namedSubType2))
1553
+ ]
1554
+ });
1555
+ default:
1556
+ throw new FormifyError("UNEXPECTED", `selection ${subSelectionNode.kind}`);
1557
+ }
1558
+ })
1559
+ }
1560
+ });
1561
+ default:
1562
+ throw new FormifyError("UNEXPECTED", `selection ${selectionNode.kind}`);
1563
+ }
1564
+ })
1565
+ ]
1566
+ }
1567
+ });
1568
+ };
1569
+ const formifiedQuery = {
1570
+ kind: "Document",
1571
+ definitions: optimizedQuery.definitions.map((definition) => {
1572
+ typeInfo.enter(definition);
1573
+ ensureOperationDefinition(definition);
1574
+ const type = typeInfo.getType();
1575
+ const namedType = G__namespace.getNamedType(type);
1576
+ ensureObjectType(namedType);
1577
+ return __spreadProps(__spreadValues({}, definition), {
1578
+ selectionSet: {
1579
+ kind: "SelectionSet",
1580
+ selections: definition.selectionSet.selections.map((selectionNode) => {
1581
+ switch (selectionNode.kind) {
1582
+ case "Field":
1583
+ const parentType = type;
1584
+ const namedParentType = G__namespace.getNamedType(parentType);
1585
+ ensureObjectType(namedParentType);
1586
+ const field = getObjectField(namedParentType, selectionNode);
1587
+ const namedFieldType = G__namespace.getNamedType(field.type);
1588
+ if (isNodeField(namedFieldType)) {
1589
+ return formifyNode({
1590
+ fieldOrInlineFragmentNode: selectionNode,
1591
+ type: field.type,
1592
+ path: [getNameAndAlias(selectionNode, false, true)],
1593
+ showInSidebar: true
1594
+ });
1595
+ } else if (isConnectionField(namedFieldType)) {
1596
+ return formifyConnection({
1597
+ namedFieldType,
1598
+ selectionNode,
1599
+ path: [getNameAndAlias(selectionNode, false, false)]
1600
+ });
1601
+ }
1602
+ if (selectionNode.name.value === COLLECTION_FIELD_NAME || selectionNode.name.value === COLLECTIONS_FIELD_NAME) {
1603
+ const path = [
1604
+ getNameAndAlias(selectionNode, false, false)
1605
+ ];
1606
+ return __spreadProps(__spreadValues({}, selectionNode), {
1607
+ selectionSet: {
1608
+ kind: "SelectionSet",
1609
+ selections: selectionNode.selectionSet.selections.map((subSelectionNode) => {
1610
+ switch (subSelectionNode.kind) {
1611
+ case "Field":
1612
+ if (subSelectionNode.name.value === COLLECTIONS_DOCUMENTS_NAME) {
1613
+ ensureObjectType(namedFieldType);
1614
+ const n = namedFieldType.getFields()[COLLECTIONS_DOCUMENTS_NAME];
1615
+ const docType = G__namespace.getNamedType(n.type);
1616
+ return formifyConnection({
1617
+ namedFieldType: docType,
1618
+ selectionNode: subSelectionNode,
1619
+ path: [
1620
+ ...path,
1621
+ getNameAndAlias(subSelectionNode, isListType(docType), isNodeField(docType))
1622
+ ]
1623
+ });
1624
+ }
1625
+ return subSelectionNode;
1626
+ default:
1627
+ throw new FormifyError("NOOP");
1628
+ }
1629
+ })
1630
+ }
1631
+ });
1632
+ }
1633
+ throw new FormifyError("NOOP");
1634
+ default:
1635
+ throw new FormifyError("UNEXPECTED");
1636
+ }
1637
+ })
1638
+ }
1639
+ });
1640
+ })
1367
1641
  };
1368
- const handleListBranches = async () => {
1369
- const { owner, repo } = props;
1370
- const branches = await cms.api.tina.listBranches({ owner, repo });
1371
- if (!Array.isArray(branches)) {
1372
- return [];
1642
+ return { formifiedQuery, blueprints };
1643
+ };
1644
+ class FormifyError extends Error {
1645
+ constructor(code, details) {
1646
+ let message;
1647
+ switch (code) {
1648
+ case "NOOP":
1649
+ message = NOOP;
1650
+ break;
1651
+ case "UNEXPECTED":
1652
+ message = UNEXPECTED;
1653
+ break;
1654
+ default:
1655
+ message = "";
1656
+ break;
1373
1657
  }
1374
- return branches;
1375
- };
1376
- const handleCreateBranch = async (data) => {
1377
- const newBranch = await cms.api.tina.createBranch(data);
1378
- return newBranch;
1379
- };
1380
- setupMedia();
1381
- const [branchingEnabled, setBranchingEnabled] = React__default["default"].useState(() => cms.flags.get("branch-switcher"));
1382
- React__default["default"].useEffect(() => {
1383
- cms.events.subscribe("flag:set", ({ key, value }) => {
1384
- if (key === "branch-switcher") {
1385
- setBranchingEnabled(value);
1386
- }
1387
- });
1388
- }, [cms.events]);
1389
- React__default["default"].useEffect(() => {
1390
- let branchSwitcher;
1391
- if (branchingEnabled) {
1392
- branchSwitcher = new toolkit.BranchSwitcherPlugin({
1393
- listBranches: handleListBranches,
1394
- createBranch: handleCreateBranch
1658
+ super(`${message} ${details || ""}`);
1659
+ this.name = "FormifyError";
1660
+ }
1661
+ }
1662
+ function reducer(state, action) {
1663
+ var _a, _b, _c, _d;
1664
+ switch (action.type) {
1665
+ case "addDocumentBlueprints":
1666
+ return __spreadProps(__spreadValues({}, state), {
1667
+ status: "formified",
1668
+ blueprints: action.value.blueprints,
1669
+ query: action.value.formifiedQuery
1395
1670
  });
1396
- cms.plugins.add(branchSwitcher);
1397
- }
1398
- return () => {
1399
- if (branchingEnabled && branchSwitcher) {
1400
- cms.plugins.remove(branchSwitcher);
1671
+ case "addOrReplaceDocumentFormNode": {
1672
+ const existingDocumentForms = state.documentForms.filter((documentForm) => {
1673
+ var _a2, _b2;
1674
+ return documentForm.id !== ((_b2 = (_a2 = action.value) == null ? void 0 : _a2.documentForm) == null ? void 0 : _b2.id);
1675
+ });
1676
+ const existingDocumentFormNodes = state.formNodes.filter((formNode) => {
1677
+ return formNodeId(formNode) !== formNodeId(action.value.formNode);
1678
+ });
1679
+ const newDocumentForms = [];
1680
+ if ((_a = action.value) == null ? void 0 : _a.documentForm) {
1681
+ newDocumentForms.push((_b = action.value) == null ? void 0 : _b.documentForm);
1401
1682
  }
1402
- };
1403
- }, [branchingEnabled, props.branch]);
1404
- React__default["default"].useEffect(() => {
1405
- if (props.cmsCallback) {
1406
- props.cmsCallback(cms);
1407
- }
1408
- }, []);
1409
- return /* @__PURE__ */ React__default["default"].createElement(toolkit.BranchDataProvider, {
1410
- currentBranch,
1411
- setCurrentBranch: (b) => {
1412
- setCurrentBranch(b);
1683
+ return __spreadProps(__spreadValues({}, state), {
1684
+ formNodes: [...existingDocumentFormNodes, action.value.formNode],
1685
+ documentForms: [...existingDocumentForms, ...newDocumentForms]
1686
+ });
1413
1687
  }
1414
- }, /* @__PURE__ */ React__default["default"].createElement(toolkit.TinaProvider, {
1415
- cms
1416
- }, /* @__PURE__ */ React__default["default"].createElement(AuthWallInner, __spreadProps(__spreadValues({}, props), {
1417
- cms
1418
- }))));
1419
- };
1420
- const TinaCloudAuthWall = TinaCloudProvider;
1421
- function useGraphqlForms({
1422
- variables,
1423
- onSubmit,
1424
- formify: formify2 = null,
1425
- query
1426
- }) {
1427
- const cms = toolkit.useCMS();
1428
- const [formValues, setFormValues] = React__default["default"].useState({});
1429
- const [data, setData] = React__default["default"].useState(null);
1430
- const [initialData, setInitialData] = React__default["default"].useState({});
1431
- const [pendingReset, setPendingReset] = React__default["default"].useState(null);
1432
- const [isLoading, setIsLoading] = React__default["default"].useState(true);
1433
- const [newUpdate, setNewUpdate] = React__default["default"].useState(null);
1434
- const { currentBranch } = toolkit.useBranchData();
1435
- const updateData = async () => {
1436
- var _a;
1437
- if (newUpdate) {
1438
- const newValue = finalForm.getIn(formValues, newUpdate.get);
1439
- const activeForm = finalForm.getIn(data, [newUpdate.queryName, "form"].join("."));
1440
- if (!activeForm) {
1441
- throw new Error(`Unable to find form for query ${newUpdate.queryName}`);
1442
- }
1443
- if (activeForm == null ? void 0 : activeForm.paths) {
1444
- const asyncUpdate = (_a = activeForm.paths) == null ? void 0 : _a.find((p) => p.dataPath.join(".") === newUpdate.setReference);
1445
- if (asyncUpdate) {
1446
- const res = await cms.api.tina.request(asyncUpdate.queryString, {
1447
- variables: { id: newValue }
1448
- });
1449
- const newData2 = finalForm.setIn(data, newUpdate.set, res.node);
1450
- const newDataAndNewJSONData2 = finalForm.setIn(newData2, newUpdate.set.replace("data", "dataJSON"), newValue);
1451
- setData(newDataAndNewJSONData2);
1452
- setNewUpdate(null);
1453
- return;
1688
+ case "onFieldChange": {
1689
+ const event = action.value.event;
1690
+ const changeSets = [];
1691
+ const formNodesToReplace = [];
1692
+ const formNodesToRemove = [];
1693
+ const newFormNodes = [];
1694
+ const form = state.documentForms.find((documentForm) => documentForm.id === event.formId);
1695
+ getFormNodesFromEvent(state, event).forEach((formNode) => {
1696
+ const blueprint = getFormNodeBlueprint(formNode, state);
1697
+ if (blueprint.hasValuesField) {
1698
+ changeSets.push(__spreadProps(__spreadValues({
1699
+ path: [formNodePath(formNode), "values"].join(".")
1700
+ }, buildChangeSet(event, formNode)), {
1701
+ value: form.values,
1702
+ mutationType: {
1703
+ type: "global"
1704
+ }
1705
+ }));
1454
1706
  }
1455
- }
1456
- if (newUpdate.lookup) {
1457
- const field = getFieldUpdate(newUpdate, activeForm, formValues);
1458
- if (field && field.typeMap) {
1459
- newValue.forEach((item) => {
1460
- if (!item.__typename) {
1461
- item["__typename"] = field.typeMap[item._template];
1707
+ if (blueprint.hasDataJSONField) {
1708
+ changeSets.push(__spreadProps(__spreadValues({
1709
+ path: [formNodePath(formNode), "dataJSON"].join(".")
1710
+ }, buildChangeSet(event, formNode)), {
1711
+ value: form.values,
1712
+ mutationType: {
1713
+ type: "global"
1714
+ }
1715
+ }));
1716
+ }
1717
+ if (event.mutationType.type === "change") {
1718
+ if (!action.value.form) {
1719
+ getPathsToChange(event, state).forEach(({ formNode: formNode2, pathToChange }) => {
1720
+ changeSets.push(__spreadValues({
1721
+ path: pathToChange
1722
+ }, buildChangeSet(event, formNode2)));
1723
+ });
1724
+ }
1725
+ } else if (event.mutationType.type === "referenceChange") {
1726
+ getBlueprintFieldsForEvent(blueprint, event).forEach((fieldBlueprint) => {
1727
+ const { pathToChange, formNodes, eventLocation } = getFormNodesForField(fieldBlueprint, formNode, event, state);
1728
+ if (action.value.form) {
1729
+ const newFormNode = {
1730
+ documentBlueprintId: fieldBlueprint.id,
1731
+ documentFormId: action.value.form.id,
1732
+ location: eventLocation
1733
+ };
1734
+ newFormNodes.push(newFormNode);
1735
+ changeSets.push(__spreadValues({
1736
+ path: pathToChange
1737
+ }, buildChangeSet(event, newFormNode)));
1738
+ }
1739
+ formNodes.forEach((subFormNode) => {
1740
+ if (matchLocation(eventLocation, subFormNode)) {
1741
+ formNodesToReplace.push(subFormNode);
1742
+ }
1743
+ });
1744
+ });
1745
+ } else {
1746
+ getBlueprintFieldsForEvent(blueprint, event).forEach((fieldBlueprint) => {
1747
+ const { pathToChange, formNodes, existing, eventLocation } = getFormNodesForField(fieldBlueprint, formNode, event, state);
1748
+ if (event.mutationType.type === "insert") {
1749
+ formNodes.forEach((subFormNode) => {
1750
+ if (matchLocation(eventLocation, subFormNode)) {
1751
+ newFormNodes.push(__spreadProps(__spreadValues({}, subFormNode), {
1752
+ location: bumpLocation(subFormNode.location)
1753
+ }));
1754
+ formNodesToReplace.push(subFormNode);
1755
+ }
1756
+ });
1757
+ changeSets.push(__spreadValues({
1758
+ path: pathToChange
1759
+ }, buildChangeSet(event, formNode)));
1760
+ }
1761
+ if (event.mutationType.type === "remove") {
1762
+ const { at } = event.mutationType;
1763
+ formNodes.forEach((subFormNode) => {
1764
+ if (matchLocation(eventLocation, subFormNode)) {
1765
+ if (matchesAt(subFormNode.location, at)) {
1766
+ formNodesToRemove.push(subFormNode);
1767
+ } else {
1768
+ newFormNodes.push(__spreadProps(__spreadValues({}, subFormNode), {
1769
+ location: maybeLowerLocation(subFormNode.location, at)
1770
+ }));
1771
+ formNodesToReplace.push(subFormNode);
1772
+ }
1773
+ }
1774
+ });
1775
+ const next = existing.filter((_, index) => index !== at);
1776
+ changeSets.push(__spreadProps(__spreadValues({
1777
+ path: pathToChange
1778
+ }, buildChangeSet(event, formNode)), {
1779
+ value: next
1780
+ }));
1781
+ }
1782
+ if (event.mutationType.type === "move") {
1783
+ const next = [];
1784
+ const { from, to } = event.mutationType;
1785
+ const newOrderObject = getMoveMapping(existing, from, to);
1786
+ formNodes.forEach((subFormNode) => {
1787
+ if (matchLocation(eventLocation, subFormNode)) {
1788
+ newFormNodes.push(__spreadProps(__spreadValues({}, subFormNode), {
1789
+ location: swapLocation(subFormNode.location, newOrderObject)
1790
+ }));
1791
+ formNodesToReplace.push(subFormNode);
1792
+ }
1793
+ });
1794
+ Object.values(newOrderObject).forEach((orderIndex, index) => {
1795
+ next[orderIndex] = existing[index];
1796
+ });
1797
+ changeSets.push(__spreadProps(__spreadValues({
1798
+ path: pathToChange
1799
+ }, buildChangeSet(event, formNode)), {
1800
+ value: next
1801
+ }));
1462
1802
  }
1463
1803
  });
1464
1804
  }
1805
+ });
1806
+ const existingDocumentForms = state.documentForms.filter((documentForm) => {
1807
+ var _a2;
1808
+ return documentForm.id !== ((_a2 = action.value.form) == null ? void 0 : _a2.id);
1809
+ });
1810
+ const newDocumentForms = [];
1811
+ if ((_c = action.value) == null ? void 0 : _c.form) {
1812
+ newDocumentForms.push((_d = action.value) == null ? void 0 : _d.form);
1465
1813
  }
1466
- const newData = finalForm.setIn(data, newUpdate.set, newValue);
1467
- const newDataAndNewJSONData = finalForm.setIn(newData, newUpdate.set.replace("data", "dataJSON"), newValue);
1468
- setData(newDataAndNewJSONData);
1469
- setNewUpdate(null);
1814
+ return __spreadProps(__spreadValues({}, state), {
1815
+ changeSets,
1816
+ formNodes: [
1817
+ ...state.formNodes.filter((formNode) => formNodeNotIn(formNode, formNodesToReplace)).filter((formNode) => formNodeNotIn(formNode, formNodesToRemove)),
1818
+ ...newFormNodes
1819
+ ],
1820
+ documentForms: [...existingDocumentForms, ...newDocumentForms]
1821
+ });
1822
+ }
1823
+ case "formOnReset": {
1824
+ const { event } = action.value;
1825
+ const changeSets = [];
1826
+ const form = state.documentForms.find((documentForm) => documentForm.id === event.formId);
1827
+ state.formNodes.filter((fn) => fn.documentFormId === (form == null ? void 0 : form.id)).forEach((formNode) => {
1828
+ const blueprint = getFormNodeBlueprint(formNode, state);
1829
+ if (blueprint.hasValuesField) {
1830
+ changeSets.push(__spreadValues({
1831
+ path: [formNodePath(formNode), "values"].join(".")
1832
+ }, buildChangeSet(event, formNode)));
1833
+ }
1834
+ if (blueprint.hasDataJSONField) {
1835
+ changeSets.push(__spreadValues({
1836
+ path: [formNodePath(formNode), "dataJSON"].join(".")
1837
+ }, buildChangeSet(event, formNode)));
1838
+ }
1839
+ changeSets.push(__spreadValues({
1840
+ path: [formNodePath(formNode), "data"].join(".")
1841
+ }, buildChangeSet(event, formNode)));
1842
+ });
1843
+ return __spreadProps(__spreadValues({}, state), { changeSets });
1470
1844
  }
1845
+ case "ready":
1846
+ return __spreadProps(__spreadValues({}, state), { status: "ready" });
1847
+ case "done":
1848
+ return __spreadProps(__spreadValues({}, state), { status: "done" });
1849
+ case "setData":
1850
+ return __spreadProps(__spreadValues({}, state), { data: action.value });
1851
+ case "setIn": {
1852
+ let newData;
1853
+ if (action.value.displaceIndex) {
1854
+ const existing = finalForm.getIn(state.data, action.value.path) || [];
1855
+ newData = finalForm.setIn(state.data, action.value.path, [
1856
+ action.value.value,
1857
+ ...existing
1858
+ ]);
1859
+ } else {
1860
+ newData = finalForm.setIn(state.data, action.value.path, action.value.value);
1861
+ }
1862
+ const changeSets = state.changeSets.filter((cs) => cs.path !== action.value.path);
1863
+ return __spreadProps(__spreadValues({}, state), {
1864
+ data: newData,
1865
+ changeSets
1866
+ });
1867
+ }
1868
+ default:
1869
+ return state;
1870
+ }
1871
+ }
1872
+ const buildChangeSet = (event, formNode) => {
1873
+ var _a, _b, _c;
1874
+ return {
1875
+ fieldDefinition: (_b = (_a = event.field) == null ? void 0 : _a.data) == null ? void 0 : _b.tinaField,
1876
+ name: (_c = event.field) == null ? void 0 : _c.name,
1877
+ formId: event.formId,
1878
+ mutationType: event.mutationType,
1879
+ value: event.value,
1880
+ formNode
1471
1881
  };
1882
+ };
1883
+ const useFormify = ({
1884
+ query,
1885
+ cms,
1886
+ variables,
1887
+ onSubmit,
1888
+ formify: formifyFunc,
1889
+ eventList
1890
+ }) => {
1891
+ const formIds = React__default["default"].useRef([]);
1892
+ const [state, dispatch] = React__default["default"].useReducer(reducer, {
1893
+ status: "initialized",
1894
+ schema: void 0,
1895
+ query: query ? G__namespace.parse(query) : null,
1896
+ queryString: query,
1897
+ data: {},
1898
+ changeSets: [],
1899
+ count: 0,
1900
+ blueprints: [],
1901
+ formNodes: [],
1902
+ documentForms: []
1903
+ });
1472
1904
  React__default["default"].useEffect(() => {
1473
- updateData();
1474
- }, [JSON.stringify(formValues)]);
1475
- React__default["default"].useEffect(() => {
1476
- if (pendingReset) {
1477
- setData(__spreadProps(__spreadValues({}, data), { [pendingReset]: initialData[pendingReset] }));
1478
- setPendingReset(null);
1905
+ if (state.status === "initialized") {
1906
+ cms.api.tina.request(query, { variables }).then((res) => {
1907
+ delete res.paths;
1908
+ dispatch({ type: "setData", value: res });
1909
+ });
1479
1910
  }
1480
- }, [pendingReset]);
1911
+ }, [state.status]);
1481
1912
  React__default["default"].useEffect(() => {
1482
- if (!query) {
1483
- setIsLoading(false);
1484
- return;
1913
+ const run = async () => {
1914
+ const schema = await cms.api.tina.getSchema();
1915
+ const result = await formify({
1916
+ schema,
1917
+ query,
1918
+ getOptimizedQuery: cms.api.tina.getOptimizedQuery
1919
+ });
1920
+ dispatch({
1921
+ type: "addDocumentBlueprints",
1922
+ value: result
1923
+ });
1924
+ };
1925
+ if (state.status === "initialized") {
1926
+ run();
1485
1927
  }
1486
- const formIds = [];
1487
- setIsLoading(true);
1488
- cms.api.tina.requestWithForm((gql2) => gql2(query), {
1489
- variables,
1490
- useUnstableFormify: cms.flags.get("use-unstable-formify")
1491
- }).then((payload) => {
1492
- cms.plugins.remove(new toolkit.FormMetaPlugin({ name: "tina-admin-link" }));
1493
- setData(payload);
1494
- setInitialData(payload);
1495
- setIsLoading(false);
1496
- Object.entries(payload).map(([queryName, result]) => {
1497
- formIds.push(queryName);
1498
- const canBeFormified = safeAssertShape(result, (yup2) => yup2.object({
1499
- values: yup2.object().required(),
1500
- form: yup2.object().required()
1501
- }));
1502
- if (!canBeFormified) {
1503
- return;
1504
- }
1505
- assertShape(result, (yup2) => yup2.object({
1506
- values: yup2.object().required(),
1507
- form: yup2.object().required()
1508
- }), `Unable to build form shape for fields at ${queryName}`);
1509
- const formConfig = {
1510
- id: queryName,
1511
- label: result.form.label,
1512
- initialValues: result.values,
1513
- fields: result.form.fields,
1514
- reset: () => {
1515
- setPendingReset(queryName);
1516
- },
1517
- onSubmit: async (payload2) => {
1518
- try {
1519
- const params = transformDocumentIntoMutationRequestPayload(payload2, result.form.mutationInfo);
1520
- const variables2 = { params };
1521
- const mutationString = result.form.mutationInfo.string;
1522
- if (onSubmit) {
1523
- onSubmit({
1524
- queryString: mutationString,
1525
- mutationString,
1526
- variables: variables2
1527
- });
1928
+ }, [state.status]);
1929
+ React__default["default"].useEffect(() => {
1930
+ const run = async () => {
1931
+ const result = await cms.api.tina.request(G__namespace.print(state.query), {
1932
+ variables
1933
+ });
1934
+ state.blueprints.map((blueprint) => {
1935
+ const responseAtBlueprint = getIn2(result, getBlueprintAliasPath(blueprint));
1936
+ const location = [];
1937
+ const findFormNodes = (res, location2) => {
1938
+ if (Array.isArray(res)) {
1939
+ res.forEach((item, index) => {
1940
+ if (Array.isArray(item)) {
1941
+ findFormNodes(item, [...location2, index]);
1528
1942
  } else {
1529
- try {
1530
- await cms.api.tina.request(mutationString, {
1531
- variables: variables2
1943
+ if (item) {
1944
+ const form = buildForm(item, cms, formifyFunc, blueprint.showInSidebar, onSubmit);
1945
+ const formNode = buildFormNode(blueprint, form, [
1946
+ ...location2,
1947
+ index
1948
+ ]);
1949
+ dispatch({
1950
+ type: "addOrReplaceDocumentFormNode",
1951
+ value: {
1952
+ formNode,
1953
+ documentForm: form
1954
+ }
1532
1955
  });
1533
- cms.alerts.success("Document saved!");
1534
- } catch (e) {
1535
- cms.alerts.error("There was a problem saving your document");
1536
- console.error(e);
1537
1956
  }
1538
1957
  }
1539
- } catch (e) {
1540
- console.error(e);
1541
- cms.alerts.error("There was a problem saving your document");
1958
+ });
1959
+ } else {
1960
+ if (res) {
1961
+ const form = buildForm(res, cms, formifyFunc, blueprint.showInSidebar, onSubmit);
1962
+ const formNode = buildFormNode(blueprint, form, location2);
1963
+ dispatch({
1964
+ type: "addOrReplaceDocumentFormNode",
1965
+ value: {
1966
+ formNode,
1967
+ documentForm: form
1968
+ }
1969
+ });
1970
+ }
1971
+ }
1972
+ };
1973
+ findFormNodes(responseAtBlueprint, location);
1974
+ });
1975
+ dispatch({ type: "ready" });
1976
+ };
1977
+ if (state.status === "formified") {
1978
+ run();
1979
+ }
1980
+ }, [state.status]);
1981
+ React__default["default"].useEffect(() => {
1982
+ if (state.status === "ready") {
1983
+ cms.events.subscribe(`forms:reset`, (event) => {
1984
+ dispatch({ type: "formOnReset", value: { event } });
1985
+ });
1986
+ cms.events.subscribe(`forms:fields:onChange`, async (event) => {
1987
+ if (eventList) {
1988
+ eventList.push(printEvent(event));
1989
+ }
1990
+ if (event.field.data.tinaField.type === "reference") {
1991
+ let form;
1992
+ if (event.value && typeof event.value === "string") {
1993
+ const existingForm = cms.forms.find(event.value);
1994
+ if (existingForm) {
1995
+ form = existingForm;
1996
+ } else {
1997
+ const formInfo = await cms.api.tina.request(`#graphql
1998
+ query Node($id: String!) {
1999
+ node(id: $id) {
2000
+ ...on Document {
2001
+ form
2002
+ values
2003
+ _internalSys: sys {
2004
+ path
2005
+ }
2006
+ }
2007
+ }
2008
+ }
2009
+ `, { variables: { id: event.value } });
2010
+ form = buildForm(formInfo.node, cms, formifyFunc, false, onSubmit);
2011
+ }
2012
+ }
2013
+ dispatch({
2014
+ type: "onFieldChange",
2015
+ value: {
2016
+ event: __spreadProps(__spreadValues({}, event), {
2017
+ mutationType: { type: "referenceChange" }
2018
+ }),
2019
+ form
2020
+ }
2021
+ });
2022
+ } else {
2023
+ dispatch({ type: "onFieldChange", value: { event } });
2024
+ }
2025
+ });
2026
+ dispatch({ type: "done" });
2027
+ }
2028
+ }, [state.status]);
2029
+ React__default["default"].useEffect(() => {
2030
+ state.changeSets.forEach((changeSet) => {
2031
+ if (changeSet.mutationType.type === "reset") {
2032
+ const form = cms.forms.find(changeSet.formId);
2033
+ resolveSubFields({
2034
+ formNode: changeSet.formNode,
2035
+ form
2036
+ }).then((res) => {
2037
+ dispatch({
2038
+ type: "setIn",
2039
+ value: {
2040
+ value: res,
2041
+ path: changeSet.path
2042
+ }
2043
+ });
2044
+ });
2045
+ return;
2046
+ } else if (changeSet.mutationType.type === "insert") {
2047
+ if (changeSet.fieldDefinition.type === "object") {
2048
+ const fieldName = changeSet.fieldDefinition.list ? `${changeSet.name}.[]` : changeSet.name;
2049
+ const { fields, __typename } = getSubFields(changeSet);
2050
+ resolveSubFields({
2051
+ formNode: changeSet.formNode,
2052
+ prefix: replaceRealNum(fieldName),
2053
+ loc: [...stripIndices(changeSet.path), 0],
2054
+ form: {
2055
+ fields,
2056
+ values: changeSet.value[0]
2057
+ }
2058
+ }).then((res) => {
2059
+ const extra = {};
2060
+ if (__typename) {
2061
+ extra["__typename"] = __typename;
2062
+ }
2063
+ dispatch({
2064
+ type: "setIn",
2065
+ value: __spreadProps(__spreadValues({
2066
+ displaceIndex: true
2067
+ }, changeSet), {
2068
+ value: __spreadValues(__spreadValues({}, res), extra)
2069
+ })
2070
+ });
2071
+ });
2072
+ } else {
2073
+ dispatch({
2074
+ type: "setIn",
2075
+ value: __spreadProps(__spreadValues({
2076
+ displaceIndex: true
2077
+ }, changeSet), {
2078
+ value: changeSet.value[0]
2079
+ })
2080
+ });
2081
+ }
2082
+ } else {
2083
+ if (changeSet.mutationType.type === "referenceChange") {
2084
+ const { formNode } = changeSet;
2085
+ const blueprint = getFormNodeBlueprint(formNode, state);
2086
+ if (!changeSet.value) {
2087
+ dispatch({
2088
+ type: "setIn",
2089
+ value: __spreadProps(__spreadValues({}, changeSet), {
2090
+ value: null
2091
+ })
2092
+ });
2093
+ } else {
2094
+ cms.api.tina.request(`
2095
+ query Node($id: String!) {
2096
+ node(id: $id) {
2097
+ ${G__namespace.print(blueprint.selection)}
2098
+ }
1542
2099
  }
2100
+ `, { variables: { id: changeSet.value } }).then(async (res) => {
2101
+ const form = state.documentForms.find((documentForm) => documentForm.id === formNode.documentFormId);
2102
+ const data = await resolveSubFields({
2103
+ formNode,
2104
+ form,
2105
+ loc: formNode.location
2106
+ });
2107
+ dispatch({
2108
+ type: "setIn",
2109
+ value: __spreadProps(__spreadValues({}, changeSet), {
2110
+ value: __spreadProps(__spreadValues({}, res.node), {
2111
+ data
2112
+ })
2113
+ })
2114
+ });
2115
+ }).catch((e) => {
2116
+ cms.alerts.error(`Unexpected error fetching reference`);
2117
+ console.log(e);
2118
+ });
1543
2119
  }
1544
- };
1545
- const { createForm, createGlobalForm } = generateFormCreators(cms);
1546
- const SKIPPED = "SKIPPED";
1547
- let form;
1548
- let skipped;
1549
- const skip = () => {
1550
- skipped = SKIPPED;
1551
- };
1552
- if (skipped)
1553
- return;
1554
- if (formify2) {
1555
- form = formify2({ formConfig, createForm, createGlobalForm, skip }, cms);
1556
2120
  } else {
1557
- form = createForm(formConfig);
2121
+ dispatch({ type: "setIn", value: changeSet });
1558
2122
  }
1559
- if (!(form instanceof toolkit.Form)) {
1560
- if (skipped === SKIPPED) {
1561
- return;
1562
- }
1563
- throw new Error("formify must return a form or skip()");
2123
+ }
2124
+ });
2125
+ }, [state.changeSets.length]);
2126
+ React__default["default"].useEffect(() => {
2127
+ formIds.current = state.documentForms.map((df) => df.id);
2128
+ }, [state.documentForms.length]);
2129
+ React__default["default"].useEffect(() => {
2130
+ return () => {
2131
+ formIds.current.forEach((formId) => {
2132
+ const form = cms.forms.find(formId);
2133
+ if (form) {
2134
+ cms.plugins.remove(form);
1564
2135
  }
1565
- const { change } = form.finalForm;
1566
- form.finalForm.change = (name, value) => {
1567
- let referenceName = "";
1568
- if (typeof name === "string") {
1569
- referenceName = name.split(".").filter((item) => isNaN(Number(item))).join(".");
2136
+ });
2137
+ };
2138
+ }, []);
2139
+ const resolveSubFields = React__default["default"].useCallback(async (args) => {
2140
+ const { form, formNode, prefix, loc } = args;
2141
+ const data = {};
2142
+ await sequential(form.fields, async (field) => {
2143
+ const value = form.values[field.name];
2144
+ const fieldName = field.list ? `${field.name}.[]` : field.name;
2145
+ const blueprint = getFormNodeBlueprint(formNode, state);
2146
+ const blueprintName = getBlueprintNamePath(blueprint);
2147
+ const extra = [];
2148
+ if (prefix) {
2149
+ extra.push(prefix);
2150
+ }
2151
+ const matchName = [
2152
+ blueprintName,
2153
+ DATA_NODE_NAME,
2154
+ ...extra,
2155
+ fieldName
2156
+ ].join(".");
2157
+ const fieldBlueprints = blueprint.fields.filter((fieldBlueprint) => {
2158
+ return matchName === getBlueprintNamePath(fieldBlueprint);
2159
+ });
2160
+ switch (field.type) {
2161
+ case "object":
2162
+ if (field.templates) {
2163
+ if (field.list) {
2164
+ await sequential(fieldBlueprints, async (fieldBlueprint) => {
2165
+ const keyName = getFieldNameOrAlias(fieldBlueprint);
2166
+ if (!value) {
2167
+ data[keyName] = null;
2168
+ return true;
2169
+ }
2170
+ if (!Array.isArray(value)) {
2171
+ throw new Error(`Expected value for object list field to be an array`);
2172
+ }
2173
+ const d = [];
2174
+ await sequential(value, async (item, index) => {
2175
+ const template = field.templates[item._template];
2176
+ const d2 = await resolveSubFields({
2177
+ formNode,
2178
+ form: { fields: template.fields, values: item },
2179
+ prefix: [prefix, fieldName].join("."),
2180
+ loc: [...loc, index]
2181
+ });
2182
+ d.push(d2);
2183
+ });
2184
+ data[keyName] = d;
2185
+ });
2186
+ } else {
2187
+ throw new Error("blocks without list true is not yet supported");
2188
+ }
1570
2189
  } else {
1571
- throw new Error(`Expected name to be of type string for FinalForm change callback`);
2190
+ if (field.list) {
2191
+ await sequential(fieldBlueprints, async (fieldBlueprint) => {
2192
+ const keyName = getFieldNameOrAlias(fieldBlueprint);
2193
+ if (!value) {
2194
+ data[keyName] = null;
2195
+ return true;
2196
+ }
2197
+ if (!Array.isArray(value)) {
2198
+ throw new Error(`Expected value for object list field to be an array`);
2199
+ }
2200
+ const d = [];
2201
+ await sequential(value, async (item, index) => {
2202
+ const d2 = await resolveSubFields({
2203
+ formNode,
2204
+ form: { fields: field.fields, values: item },
2205
+ prefix: [prefix, fieldName].join("."),
2206
+ loc: [...loc, index]
2207
+ });
2208
+ d.push(d2);
2209
+ return true;
2210
+ });
2211
+ data[keyName] = d;
2212
+ return true;
2213
+ });
2214
+ } else {
2215
+ await sequential(fieldBlueprints, async (fieldBlueprint) => {
2216
+ const keyName = getFieldNameOrAlias(fieldBlueprint);
2217
+ if (!value) {
2218
+ data[keyName] = null;
2219
+ return true;
2220
+ }
2221
+ const d = await resolveSubFields({
2222
+ formNode,
2223
+ form: { fields: field.fields, values: value },
2224
+ prefix: [prefix, fieldName].join("."),
2225
+ loc
2226
+ });
2227
+ data[keyName] = d;
2228
+ return true;
2229
+ });
2230
+ }
1572
2231
  }
1573
- setNewUpdate({
1574
- queryName,
1575
- get: [queryName, "values", name].join("."),
1576
- set: [queryName, "data", name].join("."),
1577
- setReference: [queryName, "data", referenceName].join(".")
2232
+ break;
2233
+ case "reference":
2234
+ let form2;
2235
+ if (typeof value === "string") {
2236
+ const existingForm = cms.forms.find(value);
2237
+ if (existingForm) {
2238
+ form2 = existingForm;
2239
+ } else {
2240
+ const formInfo = await cms.api.tina.request(`#graphql
2241
+ query Node($id: String!) {
2242
+ node(id: $id) {
2243
+ ...on Document {
2244
+ form
2245
+ values
2246
+ _internalSys: sys {
2247
+ path
2248
+ }
2249
+ }
2250
+ }
2251
+ }
2252
+ `, { variables: { id: value } });
2253
+ form2 = buildForm(formInfo.node, cms, formifyFunc, false, onSubmit);
2254
+ }
2255
+ }
2256
+ await sequential(fieldBlueprints, async (fieldBlueprint) => {
2257
+ const keyName = getFieldNameOrAlias(fieldBlueprint);
2258
+ if (!value) {
2259
+ data[keyName] = null;
2260
+ return true;
2261
+ }
2262
+ const documentBlueprint = state.blueprints.find((dp) => getBlueprintNamePath(dp) === matchName);
2263
+ const location = [...formNode.location];
2264
+ if (loc) {
2265
+ loc.forEach((item) => location.push(item));
2266
+ }
2267
+ const subDocumentFormNode = buildFormNode(documentBlueprint, form2, location);
2268
+ dispatch({
2269
+ type: "addOrReplaceDocumentFormNode",
2270
+ value: {
2271
+ formNode: subDocumentFormNode,
2272
+ documentForm: form2
2273
+ }
2274
+ });
2275
+ const res = await cms.api.tina.request(`
2276
+ query Node($id: String!) {
2277
+ node(id: $id) {
2278
+ ${G__namespace.print(documentBlueprint.selection)}
2279
+ }
2280
+ }
2281
+ `, { variables: { id: value } });
2282
+ const d = await resolveSubFields({
2283
+ formNode: subDocumentFormNode,
2284
+ form: form2,
2285
+ loc: location
2286
+ });
2287
+ data[keyName] = __spreadProps(__spreadValues({}, res.node), { data: d });
1578
2288
  });
1579
- return change(name, value);
2289
+ break;
2290
+ default:
2291
+ fieldBlueprints.forEach((fieldBlueprint) => {
2292
+ const keyName = getFieldNameOrAlias(fieldBlueprint);
2293
+ if (!value) {
2294
+ data[keyName] = null;
2295
+ } else {
2296
+ data[keyName] = value;
2297
+ }
2298
+ });
2299
+ break;
2300
+ }
2301
+ return true;
2302
+ });
2303
+ return data;
2304
+ }, [cms, JSON.stringify(state), dispatch]);
2305
+ return __spreadProps(__spreadValues({}, state), {
2306
+ queryString: G__namespace.print(state.query)
2307
+ });
2308
+ };
2309
+ const buildFormNode = (documentBlueprint, form, location) => {
2310
+ return {
2311
+ documentBlueprintId: documentBlueprint.id,
2312
+ documentFormId: form.id,
2313
+ location
2314
+ };
2315
+ };
2316
+ const captureBranchName = /^refs\/heads\/(.*)/;
2317
+ const parseRefForBranchName = (ref) => {
2318
+ const matches = ref.match(captureBranchName);
2319
+ return matches[1];
2320
+ };
2321
+ class Client {
2322
+ constructor(_a) {
2323
+ var _b = _a, { tokenStorage = "MEMORY" } = _b, options = __objRest(_b, ["tokenStorage"]);
2324
+ this.events = new toolkit.EventBus();
2325
+ this.addPendingContent = async (props) => {
2326
+ const mutation = `#graphql
2327
+ mutation addPendingDocumentMutation(
2328
+ $relativePath: String!
2329
+ $collection: String!
2330
+ $template: String
2331
+ ) {
2332
+ addPendingDocument(
2333
+ relativePath: $relativePath
2334
+ template: $template
2335
+ collection: $collection
2336
+ ) {
2337
+ ... on Document {
2338
+ sys {
2339
+ relativePath
2340
+ path
2341
+ breadcrumbs
2342
+ collection {
2343
+ slug
2344
+ }
2345
+ }
2346
+ }
2347
+ }
2348
+ }`;
2349
+ const result = await this.request(mutation, {
2350
+ variables: props
2351
+ });
2352
+ return result;
2353
+ };
2354
+ this.getSchema = async () => {
2355
+ if (!this.schema) {
2356
+ const data = await this.request(G.getIntrospectionQuery(), {
2357
+ variables: {}
2358
+ });
2359
+ this.schema = G.buildClientSchema(data);
2360
+ }
2361
+ return this.schema;
2362
+ };
2363
+ this.getOptimizedQuery = async (documentNode) => {
2364
+ const data = await this.request(`query GetOptimizedQuery($queryString: String!) {
2365
+ getOptimizedQuery(queryString: $queryString)
2366
+ }`, {
2367
+ variables: { queryString: G.print(documentNode) }
2368
+ });
2369
+ return G.parse(data.getOptimizedQuery);
2370
+ };
2371
+ this.options = options;
2372
+ this.setBranch(options.branch);
2373
+ this.events.subscribe("branch:change", ({ branchName }) => {
2374
+ this.setBranch(branchName);
2375
+ });
2376
+ this.clientId = options.clientId;
2377
+ switch (tokenStorage) {
2378
+ case "LOCAL_STORAGE":
2379
+ this.getToken = async function() {
2380
+ const tokens = localStorage.getItem(AUTH_TOKEN_KEY) || null;
2381
+ if (tokens) {
2382
+ return await this.getRefreshedToken(tokens);
2383
+ } else {
2384
+ return {
2385
+ access_token: null,
2386
+ id_token: null,
2387
+ refresh_token: null
2388
+ };
2389
+ }
1580
2390
  };
1581
- const _a = form.finalForm.mutators, { insert, move, remove } = _a, rest = __objRest(_a, ["insert", "move", "remove"]);
1582
- const prepareNewUpdate = (name, lookup) => {
1583
- const extra = {};
1584
- if (lookup) {
1585
- extra["lookup"] = lookup;
2391
+ this.setToken = function(token) {
2392
+ localStorage.setItem(AUTH_TOKEN_KEY, JSON.stringify(token, null, 2));
2393
+ };
2394
+ break;
2395
+ case "MEMORY":
2396
+ this.getToken = async () => {
2397
+ if (this.token) {
2398
+ return await this.getRefreshedToken(this.token);
2399
+ } else {
2400
+ return {
2401
+ access_token: null,
2402
+ id_token: null,
2403
+ refresh_token: null
2404
+ };
1586
2405
  }
1587
- const referenceName = name.split(".").filter((item) => isNaN(Number(item))).join(".");
1588
- setNewUpdate(__spreadValues({
1589
- queryName,
1590
- get: [queryName, "values", name].join("."),
1591
- set: [queryName, "data", name].join("."),
1592
- setReference: [queryName, "data", referenceName].join(".")
1593
- }, extra));
1594
2406
  };
1595
- form.finalForm.mutators = __spreadValues({
1596
- insert: (...args) => {
1597
- const fieldName = args[0];
1598
- prepareNewUpdate(fieldName, fieldName);
1599
- insert(...args);
1600
- },
1601
- move: (...args) => {
1602
- const fieldName = args[0];
1603
- prepareNewUpdate(fieldName, fieldName);
1604
- move(...args);
1605
- },
1606
- remove: (...args) => {
1607
- const fieldName = args[0];
1608
- prepareNewUpdate(fieldName, fieldName);
1609
- remove(...args);
2407
+ this.setToken = (token) => {
2408
+ this.token = JSON.stringify(token, null, 2);
2409
+ };
2410
+ break;
2411
+ case "CUSTOM":
2412
+ if (!options.getTokenFn) {
2413
+ throw new Error("When CUSTOM token storage is selected, a getTokenFn must be provided");
2414
+ }
2415
+ this.getToken = options.getTokenFn;
2416
+ break;
2417
+ }
2418
+ }
2419
+ get isLocalMode() {
2420
+ return this.contentApiUrl.includes("localhost");
2421
+ }
2422
+ setBranch(branchName) {
2423
+ var _a, _b, _c;
2424
+ const encodedBranch = encodeURIComponent(branchName);
2425
+ this.frontendUrl = ((_a = this.options.tinaioConfig) == null ? void 0 : _a.frontendUrlOverride) || "https://app.tina.io";
2426
+ this.identityApiUrl = ((_b = this.options.tinaioConfig) == null ? void 0 : _b.identityApiUrlOverride) || "https://identity.tinajs.io";
2427
+ this.contentApiBase = ((_c = this.options.tinaioConfig) == null ? void 0 : _c.contentApiUrlOverride) || `https://content.tinajs.io`;
2428
+ this.contentApiUrl = this.options.customContentApiUrl || `${this.contentApiBase}/content/${this.options.clientId}/github/${encodedBranch}`;
2429
+ }
2430
+ async requestWithForm(query, {
2431
+ variables,
2432
+ useUnstableFormify
2433
+ }) {
2434
+ const schema = await this.getSchema();
2435
+ let formifiedQuery;
2436
+ if (useUnstableFormify) {
2437
+ const res = await formify({
2438
+ schema,
2439
+ query: G.print(query(gql__default["default"])),
2440
+ getOptimizedQuery: this.getOptimizedQuery
2441
+ });
2442
+ formifiedQuery = res.formifiedQuery;
2443
+ } else {
2444
+ formifiedQuery = formify$1(query(gql__default["default"]), schema);
2445
+ }
2446
+ return this.request(G.print(formifiedQuery), { variables });
2447
+ }
2448
+ async request(query, { variables }) {
2449
+ const res = await fetch(this.contentApiUrl, {
2450
+ method: "POST",
2451
+ headers: {
2452
+ "Content-Type": "application/json",
2453
+ Authorization: "Bearer " + (await this.getToken()).id_token
2454
+ },
2455
+ body: JSON.stringify({
2456
+ query: typeof query === "function" ? G.print(query(gql__default["default"])) : query,
2457
+ variables
2458
+ })
2459
+ });
2460
+ if (res.status !== 200) {
2461
+ throw new Error(`Unable to complete request, ${res.statusText}`);
2462
+ }
2463
+ const json = await res.json();
2464
+ if (json.errors) {
2465
+ throw new Error(`Unable to fetch, errors:
2466
+ ${json.errors.map((error) => error.message).join("\n")}`);
2467
+ }
2468
+ return json.data;
2469
+ }
2470
+ parseJwt(token) {
2471
+ const base64Url = token.split(".")[1];
2472
+ const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
2473
+ const jsonPayload = decodeURIComponent(atob(base64).split("").map(function(c) {
2474
+ return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
2475
+ }).join(""));
2476
+ return JSON.parse(jsonPayload);
2477
+ }
2478
+ async getRefreshedToken(tokens) {
2479
+ const { access_token, id_token, refresh_token } = JSON.parse(tokens);
2480
+ const { exp, iss, client_id } = this.parseJwt(access_token);
2481
+ if (Date.now() / 1e3 >= exp - 120) {
2482
+ const refreshResponse = await fetch(iss, {
2483
+ method: "POST",
2484
+ headers: {
2485
+ "Content-Type": "application/x-amz-json-1.1",
2486
+ "x-amz-target": "AWSCognitoIdentityProviderService.InitiateAuth"
2487
+ },
2488
+ body: JSON.stringify({
2489
+ ClientId: client_id,
2490
+ AuthFlow: "REFRESH_TOKEN_AUTH",
2491
+ AuthParameters: {
2492
+ REFRESH_TOKEN: refresh_token,
2493
+ DEVICE_KEY: null
1610
2494
  }
1611
- }, rest);
1612
- form.subscribe(({ values }) => {
1613
- setFormValues(__spreadProps(__spreadValues({}, formValues), { [queryName]: { values } }));
1614
- }, { values: true });
2495
+ })
1615
2496
  });
1616
- }).catch((e) => {
1617
- cms.alerts.error("There was a problem setting up forms for your query");
1618
- console.error("There was a problem setting up forms for your query");
2497
+ if (refreshResponse.status !== 200) {
2498
+ throw new Error("Unable to refresh auth tokens");
2499
+ }
2500
+ const responseJson = await refreshResponse.json();
2501
+ const newToken = {
2502
+ access_token: responseJson.AuthenticationResult.AccessToken,
2503
+ id_token: responseJson.AuthenticationResult.IdToken,
2504
+ refresh_token
2505
+ };
2506
+ this.setToken(newToken);
2507
+ return Promise.resolve(newToken);
2508
+ }
2509
+ return Promise.resolve({ access_token, id_token, refresh_token });
2510
+ }
2511
+ async isAuthorized() {
2512
+ return this.isAuthenticated();
2513
+ }
2514
+ async isAuthenticated() {
2515
+ return !!await this.getUser();
2516
+ }
2517
+ async authenticate() {
2518
+ const token = await authenticate(this.clientId, this.frontendUrl);
2519
+ this.setToken(token);
2520
+ return token;
2521
+ }
2522
+ async fetchWithToken(input, init) {
2523
+ const headers = (init == null ? void 0 : init.headers) || {};
2524
+ return await fetch(input, __spreadProps(__spreadValues({}, init), {
2525
+ headers: new Headers(__spreadValues({
2526
+ Authorization: "Bearer " + (await this.getToken()).id_token
2527
+ }, headers))
2528
+ }));
2529
+ }
2530
+ async getUser() {
2531
+ if (!this.clientId) {
2532
+ return null;
2533
+ }
2534
+ const url = `${this.identityApiUrl}/v2/apps/${this.clientId}/currentUser`;
2535
+ try {
2536
+ const res = await this.fetchWithToken(url, {
2537
+ method: "GET"
2538
+ });
2539
+ const val = await res.json();
2540
+ if (!res.status.toString().startsWith("2")) {
2541
+ console.error(val.error);
2542
+ return null;
2543
+ }
2544
+ return val;
2545
+ } catch (e) {
1619
2546
  console.error(e);
1620
- setIsLoading(false);
2547
+ return null;
2548
+ }
2549
+ }
2550
+ async listBranches() {
2551
+ const url = `${this.contentApiBase}/github/${this.clientId}/list_branches`;
2552
+ const res = await this.fetchWithToken(url, {
2553
+ method: "GET"
1621
2554
  });
1622
- return () => {
1623
- formIds.forEach((name) => {
1624
- const formPlugin = cms.forms.find(name);
1625
- if (formPlugin) {
1626
- cms.forms.remove(formPlugin);
2555
+ return res.json();
2556
+ }
2557
+ async createBranch({ baseBranch, branchName }) {
2558
+ const url = `${this.contentApiBase}/github/${this.clientId}/create_branch`;
2559
+ try {
2560
+ const res = await this.fetchWithToken(url, {
2561
+ method: "POST",
2562
+ body: JSON.stringify({
2563
+ baseBranch,
2564
+ branchName
2565
+ }),
2566
+ headers: {
2567
+ "Content-Type": "application/json"
1627
2568
  }
1628
2569
  });
2570
+ return await res.json().then((r) => parseRefForBranchName(r.data.ref));
2571
+ } catch (error) {
2572
+ console.error("There was an error creating a new branch.", error);
2573
+ return null;
2574
+ }
2575
+ }
2576
+ }
2577
+ const DEFAULT_LOCAL_TINA_GQL_SERVER_URL = "http://localhost:4001/graphql";
2578
+ class LocalClient extends Client {
2579
+ constructor(props) {
2580
+ const clientProps = {
2581
+ clientId: "",
2582
+ branch: "",
2583
+ customContentApiUrl: props && props.customContentApiUrl ? props.customContentApiUrl : DEFAULT_LOCAL_TINA_GQL_SERVER_URL
1629
2584
  };
1630
- }, [query, JSON.stringify(variables), currentBranch]);
1631
- return [data, isLoading];
2585
+ super(clientProps);
2586
+ }
2587
+ async isAuthorized() {
2588
+ return true;
2589
+ }
2590
+ async isAuthenticated() {
2591
+ return true;
2592
+ }
1632
2593
  }
1633
- const transformDocumentIntoMutationRequestPayload = (document, instructions) => {
1634
- const _a = document, { _collection, __typename, _template } = _a, rest = __objRest(_a, ["_collection", "__typename", "_template"]);
1635
- const params = transformParams(rest);
1636
- const paramsWithTemplate = instructions.includeTemplate ? { [_template]: params } : params;
1637
- return instructions.includeCollection ? { [_collection]: paramsWithTemplate } : paramsWithTemplate;
2594
+ function ModalBuilder(modalProps) {
2595
+ return /* @__PURE__ */ React__default["default"].createElement(toolkit.Modal, null, /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalPopup, null, /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalHeader, null, modalProps.title), /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalBody, {
2596
+ padded: true
2597
+ }, /* @__PURE__ */ React__default["default"].createElement("p", null, modalProps.message), modalProps.error && /* @__PURE__ */ React__default["default"].createElement(ErrorLabel, null, modalProps.error)), /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalActions, null, modalProps.actions.map((action) => /* @__PURE__ */ React__default["default"].createElement(AsyncButton, __spreadValues({
2598
+ key: action.name
2599
+ }, action))))));
2600
+ }
2601
+ const ErrorLabel = styled__default["default"].p`
2602
+ color: var(--tina-color-error) !important;
2603
+ `;
2604
+ const AsyncButton = ({ name, primary, action }) => {
2605
+ const [submitting, setSubmitting] = React.useState(false);
2606
+ const onClick = React.useCallback(async () => {
2607
+ setSubmitting(true);
2608
+ try {
2609
+ await action();
2610
+ setSubmitting(false);
2611
+ } catch (e) {
2612
+ setSubmitting(false);
2613
+ throw e;
2614
+ }
2615
+ }, [action, setSubmitting]);
2616
+ return /* @__PURE__ */ React__default["default"].createElement(toolkit.Button, {
2617
+ variant: primary ? "primary" : "secondary",
2618
+ onClick,
2619
+ busy: submitting,
2620
+ disabled: submitting
2621
+ }, submitting && /* @__PURE__ */ React__default["default"].createElement(toolkit.LoadingDots, null), !submitting && name);
1638
2622
  };
1639
- const transformParams = (data) => {
1640
- if (["string", "number", "boolean"].includes(typeof data)) {
1641
- return data;
2623
+ const TINA_AUTH_CONFIG = "tina_auth_config";
2624
+ const useTinaAuthRedirect = () => {
2625
+ React.useEffect(() => {
2626
+ const urlParams = new URLSearchParams(window.location.search);
2627
+ const config = {
2628
+ code: urlParams.get("code") || "",
2629
+ scope: urlParams.get("scope") || "email",
2630
+ state: urlParams.get("state")
2631
+ };
2632
+ if (!config.code) {
2633
+ return;
2634
+ }
2635
+ localStorage[TINA_AUTH_CONFIG] = JSON.stringify(config);
2636
+ }, []);
2637
+ };
2638
+ class TinaAdminApi {
2639
+ constructor(cms) {
2640
+ this.api = cms.api.tina;
2641
+ }
2642
+ async isAuthenticated() {
2643
+ return await this.api.isAuthenticated();
2644
+ }
2645
+ async fetchCollections() {
2646
+ const response = await this.api.request(`#graphql
2647
+ query{
2648
+ getCollections {
2649
+ label,
2650
+ name
2651
+ }
2652
+ }`, { variables: {} });
2653
+ return response;
2654
+ }
2655
+ async fetchCollection(collectionName, includeDocuments) {
2656
+ const response = await this.api.request(`#graphql
2657
+ query($collection: String!, $includeDocuments: Boolean!){
2658
+ getCollection(collection: $collection){
2659
+ name
2660
+ label
2661
+ format
2662
+ templates
2663
+ documents @include(if: $includeDocuments) {
2664
+ totalCount
2665
+ edges {
2666
+ node {
2667
+ ... on Document {
2668
+ sys {
2669
+ template
2670
+ breadcrumbs
2671
+ path
2672
+ basename
2673
+ relativePath
2674
+ filename
2675
+ extension
2676
+ }
2677
+ }
2678
+ }
2679
+ }
2680
+ }
2681
+ }
2682
+ }`, { variables: { collection: collectionName, includeDocuments } });
2683
+ return response;
2684
+ }
2685
+ async fetchDocument(collectionName, relativePath) {
2686
+ const response = await this.api.request(`#graphql
2687
+ query($collection: String!, $relativePath: String!) {
2688
+ getDocument(collection:$collection, relativePath:$relativePath) {
2689
+ ... on Document {
2690
+ form
2691
+ values
2692
+ }
2693
+ }
2694
+ }`, { variables: { collection: collectionName, relativePath } });
2695
+ return response;
1642
2696
  }
1643
- if (Array.isArray(data)) {
1644
- return data.map((item) => transformParams(item));
2697
+ async fetchDocumentFields() {
2698
+ const response = await this.api.request(`#graphql
2699
+ query {
2700
+ getDocumentFields
2701
+ }`, { variables: {} });
2702
+ return response;
1645
2703
  }
1646
- try {
1647
- assertShape(data, (yup2) => yup2.object({ _template: yup2.string().required() }));
1648
- const _a = data, { _template, __typename } = _a, rest = __objRest(_a, ["_template", "__typename"]);
1649
- const nested = transformParams(rest);
1650
- return { [_template]: nested };
1651
- } catch (e) {
1652
- if (e.message === "Failed to assertShape - _template is a required field") {
1653
- if (!data) {
1654
- return [];
2704
+ async createDocument(collectionName, relativePath, params) {
2705
+ const response = await this.api.request(`#graphql
2706
+ mutation($collection: String!, $relativePath: String!, $params: DocumentMutation!) {
2707
+ createDocument(
2708
+ collection: $collection,
2709
+ relativePath: $relativePath,
2710
+ params: $params
2711
+ ){__typename}
2712
+ }`, {
2713
+ variables: {
2714
+ collection: collectionName,
2715
+ relativePath,
2716
+ params
1655
2717
  }
1656
- const accum = {};
1657
- Object.entries(data).map(([keyName, value]) => {
1658
- accum[keyName] = transformParams(value);
1659
- });
1660
- return accum;
1661
- } else {
1662
- if (!data) {
1663
- return [];
2718
+ });
2719
+ return response;
2720
+ }
2721
+ async updateDocument(collectionName, relativePath, params) {
2722
+ const response = await this.api.request(`#graphql
2723
+ mutation($collection: String!, $relativePath: String!, $params: DocumentMutation!) {
2724
+ updateDocument(
2725
+ collection: $collection,
2726
+ relativePath: $relativePath,
2727
+ params: $params
2728
+ ){__typename}
2729
+ }`, {
2730
+ variables: {
2731
+ collection: collectionName,
2732
+ relativePath,
2733
+ params
1664
2734
  }
1665
- throw e;
1666
- }
2735
+ });
2736
+ return response;
1667
2737
  }
1668
- };
1669
- const getFieldUpdate = (newUpdate, activeForm, formValues) => {
1670
- const items = newUpdate.lookup.split(".");
1671
- let currentFields = activeForm.fields;
1672
- items.map((item, index) => {
1673
- const lookupName = items.slice(0, index + 1).join(".");
1674
- const value = finalForm.getIn(formValues, [newUpdate.queryName, "values", lookupName].join("."));
1675
- if (isNaN(Number(item))) {
1676
- if (Array.isArray(currentFields)) {
1677
- currentFields = currentFields.find((field) => field.name === item);
2738
+ }
2739
+ function sleep(ms) {
2740
+ return new Promise((resolve) => setTimeout(resolve, ms));
2741
+ }
2742
+ const AuthWallInner = ({
2743
+ children,
2744
+ cms,
2745
+ loginScreen,
2746
+ getModalActions
2747
+ }) => {
2748
+ const client = cms.api.tina;
2749
+ const [activeModal, setActiveModal] = React.useState(null);
2750
+ const [showChildren, setShowChildren] = React.useState(false);
2751
+ React__default["default"].useEffect(() => {
2752
+ client.isAuthenticated().then((isAuthenticated) => {
2753
+ if (isAuthenticated) {
2754
+ setShowChildren(true);
2755
+ cms.enable();
2756
+ } else {
2757
+ sleep(500).then(() => {
2758
+ setActiveModal("authenticate");
2759
+ });
1678
2760
  }
2761
+ });
2762
+ }, []);
2763
+ const onAuthSuccess = async () => {
2764
+ if (await client.isAuthenticated()) {
2765
+ setShowChildren(true);
2766
+ setActiveModal(null);
1679
2767
  } else {
1680
- const template = currentFields.templates ? currentFields.templates[value._template] : currentFields;
1681
- currentFields = template.fields;
2768
+ throw new Error("No access to repo");
1682
2769
  }
1683
- });
1684
- return currentFields;
2770
+ };
2771
+ const otherModalActions = getModalActions ? getModalActions({
2772
+ closeModal: () => {
2773
+ setActiveModal(null);
2774
+ }
2775
+ }) : [];
2776
+ return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, activeModal === "authenticate" && /* @__PURE__ */ React__default["default"].createElement(ModalBuilder, {
2777
+ title: "Tina Cloud Authorization",
2778
+ message: "To save edits, Tina Cloud authorization is required. On save, changes will get commited using your account.",
2779
+ close,
2780
+ actions: [
2781
+ ...otherModalActions,
2782
+ {
2783
+ action: async () => {
2784
+ sharedctx.setEditing(false);
2785
+ window.location.reload();
2786
+ },
2787
+ name: "Close",
2788
+ primary: false
2789
+ },
2790
+ {
2791
+ name: "Continue to Tina Cloud",
2792
+ action: async () => {
2793
+ await client.authenticate();
2794
+ onAuthSuccess();
2795
+ },
2796
+ primary: true
2797
+ }
2798
+ ]
2799
+ }), showChildren ? children : loginScreen ? loginScreen : null);
1685
2800
  };
1686
- const generateFormCreators = (cms) => {
1687
- const createForm = (formConfig) => {
1688
- const form = new toolkit.Form(formConfig);
1689
- cms.forms.add(form);
1690
- return form;
2801
+ const TinaCloudProvider = (props) => {
2802
+ const baseBranch = props.branch || "main";
2803
+ const [currentBranch, setCurrentBranch] = toolkit.useLocalStorage("tinacms-current-branch", baseBranch);
2804
+ useTinaAuthRedirect();
2805
+ const cms = React__default["default"].useMemo(() => props.cms || new toolkit.TinaCMS({
2806
+ enabled: true,
2807
+ sidebar: true
2808
+ }), [props.cms]);
2809
+ if (!cms.api.tina) {
2810
+ cms.registerApi("tina", createClient(props));
2811
+ }
2812
+ if (!cms.api.admin) {
2813
+ cms.registerApi("admin", new TinaAdminApi(cms));
2814
+ }
2815
+ const setupMedia = async () => {
2816
+ var _a;
2817
+ if (props.mediaStore) {
2818
+ if ((_a = props.mediaStore.prototype) == null ? void 0 : _a.persist) {
2819
+ cms.media.store = new props.mediaStore(cms.api.tina);
2820
+ } else {
2821
+ const MediaClass = await props.mediaStore();
2822
+ cms.media.store = new MediaClass(cms.api.tina);
2823
+ }
2824
+ }
1691
2825
  };
1692
- const createGlobalForm = (formConfig, options) => {
1693
- const form = new toolkit.Form(formConfig);
1694
- cms.plugins.add(new toolkit.GlobalFormPlugin(form, options == null ? void 0 : options.icon, options == null ? void 0 : options.layout));
1695
- return form;
2826
+ const handleListBranches = async () => {
2827
+ const { owner, repo } = props;
2828
+ const branches = await cms.api.tina.listBranches({ owner, repo });
2829
+ if (!Array.isArray(branches)) {
2830
+ return [];
2831
+ }
2832
+ return branches;
1696
2833
  };
1697
- return { createForm, createGlobalForm };
2834
+ const handleCreateBranch = async (data) => {
2835
+ const newBranch = await cms.api.tina.createBranch(data);
2836
+ return newBranch;
2837
+ };
2838
+ setupMedia();
2839
+ const [branchingEnabled, setBranchingEnabled] = React__default["default"].useState(() => cms.flags.get("branch-switcher"));
2840
+ React__default["default"].useEffect(() => {
2841
+ cms.events.subscribe("flag:set", ({ key, value }) => {
2842
+ if (key === "branch-switcher") {
2843
+ setBranchingEnabled(value);
2844
+ }
2845
+ });
2846
+ }, [cms.events]);
2847
+ React__default["default"].useEffect(() => {
2848
+ let branchSwitcher;
2849
+ if (branchingEnabled) {
2850
+ branchSwitcher = new toolkit.BranchSwitcherPlugin({
2851
+ listBranches: handleListBranches,
2852
+ createBranch: handleCreateBranch
2853
+ });
2854
+ cms.plugins.add(branchSwitcher);
2855
+ }
2856
+ return () => {
2857
+ if (branchingEnabled && branchSwitcher) {
2858
+ cms.plugins.remove(branchSwitcher);
2859
+ }
2860
+ };
2861
+ }, [branchingEnabled, props.branch]);
2862
+ React__default["default"].useEffect(() => {
2863
+ if (props.cmsCallback) {
2864
+ props.cmsCallback(cms);
2865
+ }
2866
+ }, []);
2867
+ return /* @__PURE__ */ React__default["default"].createElement(toolkit.BranchDataProvider, {
2868
+ currentBranch,
2869
+ setCurrentBranch: (b) => {
2870
+ setCurrentBranch(b);
2871
+ }
2872
+ }, /* @__PURE__ */ React__default["default"].createElement(toolkit.TinaProvider, {
2873
+ cms
2874
+ }, /* @__PURE__ */ React__default["default"].createElement(AuthWallInner, __spreadProps(__spreadValues({}, props), {
2875
+ cms
2876
+ }))));
1698
2877
  };
2878
+ const TinaCloudAuthWall = TinaCloudProvider;
1699
2879
  class ContentCreatorPlugin {
1700
2880
  constructor(options) {
1701
2881
  this.__type = "content-creator";
@@ -2039,13 +3219,25 @@ mutation addPendingDocumentMutation(
2039
3219
  payload: void 0,
2040
3220
  isLoading: true
2041
3221
  });
3222
+ const cms = toolkit.useCMS();
3223
+ const useUnstableFormify = React__default["default"].useMemo(() => {
3224
+ if (cms == null ? void 0 : cms.flags.get("use-unstable-formify")) {
3225
+ return true;
3226
+ }
3227
+ return false;
3228
+ }, [cms == null ? void 0 : cms.flags]);
2042
3229
  return /* @__PURE__ */ React__default["default"].createElement(sharedctx.TinaDataContext.Provider, {
2043
3230
  value: {
2044
3231
  setRequest,
2045
3232
  isLoading: state.isLoading,
2046
3233
  state: { payload: state.payload }
2047
3234
  }
2048
- }, /* @__PURE__ */ React__default["default"].createElement(FormRegistrar, {
3235
+ }, useUnstableFormify ? /* @__PURE__ */ React__default["default"].createElement(FormRegistrarUnstable, {
3236
+ key: request == null ? void 0 : request.query,
3237
+ request,
3238
+ formifyCallback,
3239
+ onPayloadStateChange: setState
3240
+ }) : /* @__PURE__ */ React__default["default"].createElement(FormRegistrar, {
2049
3241
  key: request == null ? void 0 : request.query,
2050
3242
  request,
2051
3243
  formifyCallback,
@@ -2074,6 +3266,35 @@ mutation addPendingDocumentMutation(
2074
3266
  }, [JSON.stringify(payload), isLoading]);
2075
3267
  return isLoading ? /* @__PURE__ */ React__default["default"].createElement(Loader, null, /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null)) : null;
2076
3268
  };
3269
+ const FormRegistrarUnstable = (props) => {
3270
+ var _a;
3271
+ if (!((_a = props.request) == null ? void 0 : _a.query)) {
3272
+ return null;
3273
+ }
3274
+ return /* @__PURE__ */ React__default["default"].createElement(FormRegistrarUnstableInner, __spreadValues({}, props));
3275
+ };
3276
+ const FormRegistrarUnstableInner = ({
3277
+ request,
3278
+ formifyCallback,
3279
+ onPayloadStateChange
3280
+ }) => {
3281
+ const cms = toolkit.useCMS();
3282
+ const [payload, isLoading] = useGraphqlFormsUnstable({
3283
+ query: request == null ? void 0 : request.query,
3284
+ variables: request == null ? void 0 : request.variables,
3285
+ formify: (args) => {
3286
+ if (formifyCallback) {
3287
+ return formifyCallback(args, cms);
3288
+ } else {
3289
+ return args.createForm(args.formConfig);
3290
+ }
3291
+ }
3292
+ });
3293
+ React__default["default"].useEffect(() => {
3294
+ onPayloadStateChange({ payload, isLoading });
3295
+ }, [JSON.stringify(payload), isLoading]);
3296
+ return isLoading ? /* @__PURE__ */ React__default["default"].createElement(Loader, null, /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null)) : null;
3297
+ };
2077
3298
  const Loader = (props) => {
2078
3299
  return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, /* @__PURE__ */ React__default["default"].createElement("div", {
2079
3300
  style: {
@@ -2875,9 +4096,9 @@ This will work when developing locally but NOT when deployed to production.
2875
4096
  }
2876
4097
  return true;
2877
4098
  }
2878
- const isValid = /^[_a-zA-Z][-,_a-zA-Z0-9]*$/.test(value);
4099
+ const isValid = /^[_a-zA-Z][.,-,_a-zA-Z0-9]*$/.test(value);
2879
4100
  if (value && !isValid) {
2880
- return "Must begin with a-z, A-Z, or _ and contain only a-z, A-Z, 0-9, - or _";
4101
+ return "Must begin with a-z, A-Z, or _ and contain only a-z, A-Z, 0-9, -, ., or _";
2881
4102
  }
2882
4103
  }
2883
4104
  },
@@ -3151,6 +4372,7 @@ This will work when developing locally but NOT when deployed to production.
3151
4372
  exports2.staticRequest = staticRequest;
3152
4373
  exports2.useDocumentCreatorPlugin = useDocumentCreatorPlugin;
3153
4374
  exports2.useGraphqlForms = useGraphqlForms;
4375
+ exports2.useGraphqlFormsUnstable = useGraphqlFormsUnstable;
3154
4376
  exports2.useTinaAuthRedirect = useTinaAuthRedirect;
3155
4377
  Object.keys(toolkit).forEach(function(k) {
3156
4378
  if (k !== "default" && !exports2.hasOwnProperty(k))