@tinacms/graphql 0.0.0-c45ac5d-20241213020122 → 0.0.0-c466c52-20250801052040

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -68,6 +68,15 @@ var SysFieldDefinition = {
68
68
  selectionSet: {
69
69
  kind: "SelectionSet",
70
70
  selections: [
71
+ // {
72
+ // kind: 'Field' as const,
73
+ // name: {
74
+ // kind: 'Name' as const,
75
+ // value: 'title',
76
+ // },
77
+ // arguments: [],
78
+ // directives: [],
79
+ // },
71
80
  {
72
81
  kind: "Field",
73
82
  name: {
@@ -135,6 +144,10 @@ var SysFieldDefinition = {
135
144
  }
136
145
  };
137
146
  var astBuilder = {
147
+ /**
148
+ * `FormFieldBuilder` acts as a shortcut to building an entire `ObjectTypeDefinition`, we use this
149
+ * because all Tina field objects share a common set of fields ('name', 'label', 'component')
150
+ */
138
151
  FormFieldBuilder: ({
139
152
  name,
140
153
  additionalFields
@@ -358,6 +371,8 @@ var astBuilder = {
358
371
  kind: "Name",
359
372
  value: name
360
373
  },
374
+ // @ts-ignore FIXME; this is being handled properly but we're lying to
375
+ // ts and then fixing it in the `extractInlineTypes` function
361
376
  fields
362
377
  }),
363
378
  UnionTypeDefinition: ({
@@ -370,6 +385,8 @@ var astBuilder = {
370
385
  value: name
371
386
  },
372
387
  directives: [],
388
+ // @ts-ignore FIXME; this is being handled properly but we're lying to
389
+ // ts and then fixing it in the `extractInlineTypes` function
373
390
  types: types.map((name2) => ({
374
391
  kind: "NamedType",
375
392
  name: {
@@ -466,8 +483,11 @@ var astBuilder = {
466
483
  string: "String",
467
484
  boolean: "Boolean",
468
485
  number: "Float",
486
+ // FIXME - needs to be float or int
469
487
  datetime: "String",
488
+ // FIXME
470
489
  image: "String",
490
+ // FIXME
471
491
  text: "String"
472
492
  };
473
493
  return scalars[type];
@@ -966,8 +986,7 @@ var astBuilder = {
966
986
  }
967
987
  };
968
988
  var capitalize = (s) => {
969
- if (typeof s !== "string")
970
- return "";
989
+ if (typeof s !== "string") return "";
971
990
  return s.charAt(0).toUpperCase() + s.slice(1);
972
991
  };
973
992
  var extractInlineTypes = (item) => {
@@ -1010,41 +1029,6 @@ function* walk(maybeNode, visited = /* @__PURE__ */ new WeakSet()) {
1010
1029
  yield maybeNode;
1011
1030
  visited.add(maybeNode);
1012
1031
  }
1013
- function addNamespaceToSchema(maybeNode, namespace = []) {
1014
- if (typeof maybeNode === "string") {
1015
- return maybeNode;
1016
- }
1017
- if (typeof maybeNode === "boolean") {
1018
- return maybeNode;
1019
- }
1020
- const newNode = maybeNode;
1021
- const keys = Object.keys(maybeNode);
1022
- Object.values(maybeNode).map((m, index) => {
1023
- const key = keys[index];
1024
- if (Array.isArray(m)) {
1025
- newNode[key] = m.map((element) => {
1026
- if (!element) {
1027
- return;
1028
- }
1029
- if (!element.hasOwnProperty("name")) {
1030
- return element;
1031
- }
1032
- const value = element.name || element.value;
1033
- return addNamespaceToSchema(element, [...namespace, value]);
1034
- });
1035
- } else {
1036
- if (!m) {
1037
- return;
1038
- }
1039
- if (!m.hasOwnProperty("name")) {
1040
- newNode[key] = m;
1041
- } else {
1042
- newNode[key] = addNamespaceToSchema(m, [...namespace, m.name]);
1043
- }
1044
- }
1045
- });
1046
- return { ...newNode, namespace };
1047
- }
1048
1032
  var generateNamespacedFieldName = (names, suffix = "") => {
1049
1033
  return (suffix ? [...names, suffix] : names).map(capitalize).join("");
1050
1034
  };
@@ -1422,6 +1406,19 @@ var Builder = class {
1422
1406
  this.addToLookupMap = (lookup) => {
1423
1407
  this.lookupMap[lookup.type] = lookup;
1424
1408
  };
1409
+ /**
1410
+ * ```graphql
1411
+ * # ex.
1412
+ * {
1413
+ * getCollection(collection: $collection) {
1414
+ * name
1415
+ * documents {...}
1416
+ * }
1417
+ * }
1418
+ * ```
1419
+ *
1420
+ * @param collections
1421
+ */
1425
1422
  this.buildCollectionDefinition = async (collections) => {
1426
1423
  const name = "collection";
1427
1424
  const typeName = "Collection";
@@ -1492,6 +1489,19 @@ var Builder = class {
1492
1489
  required: true
1493
1490
  });
1494
1491
  };
1492
+ /**
1493
+ * ```graphql
1494
+ * # ex.
1495
+ * {
1496
+ * getCollections {
1497
+ * name
1498
+ * documents {...}
1499
+ * }
1500
+ * }
1501
+ * ```
1502
+ *
1503
+ * @param collections
1504
+ */
1495
1505
  this.buildMultiCollectionDefinition = async (collections) => {
1496
1506
  const name = "collections";
1497
1507
  const typeName = "Collection";
@@ -1502,6 +1512,17 @@ var Builder = class {
1502
1512
  required: true
1503
1513
  });
1504
1514
  };
1515
+ /**
1516
+ * ```graphql
1517
+ * # ex.
1518
+ * {
1519
+ * node(id: $id) {
1520
+ * id
1521
+ * data {...}
1522
+ * }
1523
+ * }
1524
+ * ```
1525
+ */
1505
1526
  this.multiNodeDocument = async () => {
1506
1527
  const name = "node";
1507
1528
  const args = [
@@ -1522,6 +1543,19 @@ var Builder = class {
1522
1543
  required: true
1523
1544
  });
1524
1545
  };
1546
+ /**
1547
+ * ```graphql
1548
+ * # ex.
1549
+ * {
1550
+ * getDocument(collection: $collection, relativePath: $relativePath) {
1551
+ * id
1552
+ * data {...}
1553
+ * }
1554
+ * }
1555
+ * ```
1556
+ *
1557
+ * @param collections
1558
+ */
1525
1559
  this.multiCollectionDocument = async (collections) => {
1526
1560
  const name = "document";
1527
1561
  const args = [
@@ -1547,6 +1581,19 @@ var Builder = class {
1547
1581
  required: true
1548
1582
  });
1549
1583
  };
1584
+ /**
1585
+ * ```graphql
1586
+ * # ex.
1587
+ * {
1588
+ * addPendingDocument(collection: $collection, relativePath: $relativePath, params: $params) {
1589
+ * id
1590
+ * data {...}
1591
+ * }
1592
+ * }
1593
+ * ```
1594
+ *
1595
+ * @param collections
1596
+ */
1550
1597
  this.addMultiCollectionDocumentMutation = async () => {
1551
1598
  return astBuilder.FieldDefinition({
1552
1599
  name: "addPendingDocument",
@@ -1571,6 +1618,19 @@ var Builder = class {
1571
1618
  type: astBuilder.TYPES.MultiCollectionDocument
1572
1619
  });
1573
1620
  };
1621
+ /**
1622
+ * ```graphql
1623
+ * # ex.
1624
+ * {
1625
+ * createDocument(relativePath: $relativePath, params: $params) {
1626
+ * id
1627
+ * data {...}
1628
+ * }
1629
+ * }
1630
+ * ```
1631
+ *
1632
+ * @param collections
1633
+ */
1574
1634
  this.buildCreateCollectionDocumentMutation = async (collections) => {
1575
1635
  return astBuilder.FieldDefinition({
1576
1636
  name: "createDocument",
@@ -1598,6 +1658,19 @@ var Builder = class {
1598
1658
  type: astBuilder.TYPES.MultiCollectionDocument
1599
1659
  });
1600
1660
  };
1661
+ /**
1662
+ * ```graphql
1663
+ * # ex.
1664
+ * {
1665
+ * updateDocument(relativePath: $relativePath, params: $params) {
1666
+ * id
1667
+ * data {...}
1668
+ * }
1669
+ * }
1670
+ * ```
1671
+ *
1672
+ * @param collections
1673
+ */
1601
1674
  this.buildUpdateCollectionDocumentMutation = async (collections) => {
1602
1675
  return astBuilder.FieldDefinition({
1603
1676
  name: "updateDocument",
@@ -1625,6 +1698,19 @@ var Builder = class {
1625
1698
  type: astBuilder.TYPES.MultiCollectionDocument
1626
1699
  });
1627
1700
  };
1701
+ /**
1702
+ * ```graphql
1703
+ * # ex.
1704
+ * {
1705
+ * deleteDocument(relativePath: $relativePath, params: $params) {
1706
+ * id
1707
+ * data {...}
1708
+ * }
1709
+ * }
1710
+ * ```
1711
+ *
1712
+ * @param collections
1713
+ */
1628
1714
  this.buildDeleteCollectionDocumentMutation = async (collections) => {
1629
1715
  return astBuilder.FieldDefinition({
1630
1716
  name: "deleteDocument",
@@ -1644,6 +1730,19 @@ var Builder = class {
1644
1730
  type: astBuilder.TYPES.MultiCollectionDocument
1645
1731
  });
1646
1732
  };
1733
+ /**
1734
+ * ```graphql
1735
+ * # ex.
1736
+ * {
1737
+ * createFolder(folderName: $folderName, params: $params) {
1738
+ * id
1739
+ * data {...}
1740
+ * }
1741
+ * }
1742
+ * ```
1743
+ *
1744
+ * @param collections
1745
+ */
1647
1746
  this.buildCreateCollectionFolderMutation = async () => {
1648
1747
  return astBuilder.FieldDefinition({
1649
1748
  name: "createFolder",
@@ -1663,6 +1762,19 @@ var Builder = class {
1663
1762
  type: astBuilder.TYPES.MultiCollectionDocument
1664
1763
  });
1665
1764
  };
1765
+ /**
1766
+ * ```graphql
1767
+ * # ex.
1768
+ * {
1769
+ * getPostDocument(relativePath: $relativePath) {
1770
+ * id
1771
+ * data {...}
1772
+ * }
1773
+ * }
1774
+ * ```
1775
+ *
1776
+ * @param collection
1777
+ */
1666
1778
  this.collectionDocument = async (collection) => {
1667
1779
  const name = NAMER.queryName([collection.name]);
1668
1780
  const type = await this._buildCollectionDocumentType(collection);
@@ -1723,6 +1835,20 @@ var Builder = class {
1723
1835
  const args = [];
1724
1836
  return astBuilder.FieldDefinition({ type, name, args, required: false });
1725
1837
  };
1838
+ /**
1839
+ * Turns a collection into a fragment that gets updated on build. This fragment does not resolve references
1840
+ * ```graphql
1841
+ * # ex.
1842
+ * fragment AuthorsParts on Authors {
1843
+ * name
1844
+ * avatar
1845
+ * ...
1846
+ * }
1847
+ * ```
1848
+ *
1849
+ * @public
1850
+ * @param collection a TinaCloud collection
1851
+ */
1726
1852
  this.collectionFragment = async (collection) => {
1727
1853
  const name = NAMER.dataTypeName(collection.namespace);
1728
1854
  const fragmentName = NAMER.fragmentName(collection.namespace);
@@ -1736,6 +1862,20 @@ var Builder = class {
1736
1862
  selections: filterSelections(selections)
1737
1863
  });
1738
1864
  };
1865
+ /**
1866
+ * Given a collection this function returns its selections set. For example for Post this would return
1867
+ *
1868
+ * "
1869
+ * body
1870
+ * title
1871
+ * ... on Author {
1872
+ * name
1873
+ * heroImg
1874
+ * }
1875
+ *
1876
+ * But in the AST format
1877
+ *
1878
+ * */
1739
1879
  this._getCollectionFragmentSelections = async (collection, depth) => {
1740
1880
  const selections = [];
1741
1881
  selections.push({
@@ -1817,9 +1957,9 @@ var Builder = class {
1817
1957
  ]
1818
1958
  });
1819
1959
  }
1960
+ // TODO: Should we throw here?
1820
1961
  case "reference":
1821
- if (depth >= this.maxDepth)
1822
- return false;
1962
+ if (depth >= this.maxDepth) return false;
1823
1963
  if (!("collections" in field)) {
1824
1964
  return false;
1825
1965
  }
@@ -1851,6 +1991,7 @@ var Builder = class {
1851
1991
  name: field.name,
1852
1992
  selections: [
1853
1993
  ...selections,
1994
+ // This is ... on Document { id }
1854
1995
  {
1855
1996
  kind: "InlineFragment",
1856
1997
  typeCondition: {
@@ -1881,6 +2022,19 @@ var Builder = class {
1881
2022
  });
1882
2023
  }
1883
2024
  };
2025
+ /**
2026
+ * ```graphql
2027
+ * # ex.
2028
+ * mutation {
2029
+ * updatePostDocument(relativePath: $relativePath, params: $params) {
2030
+ * id
2031
+ * data {...}
2032
+ * }
2033
+ * }
2034
+ * ```
2035
+ *
2036
+ * @param collection
2037
+ */
1884
2038
  this.updateCollectionDocumentMutation = async (collection) => {
1885
2039
  return astBuilder.FieldDefinition({
1886
2040
  type: await this._buildCollectionDocumentType(collection),
@@ -1900,6 +2054,19 @@ var Builder = class {
1900
2054
  ]
1901
2055
  });
1902
2056
  };
2057
+ /**
2058
+ * ```graphql
2059
+ * # ex.
2060
+ * mutation {
2061
+ * createPostDocument(relativePath: $relativePath, params: $params) {
2062
+ * id
2063
+ * data {...}
2064
+ * }
2065
+ * }
2066
+ * ```
2067
+ *
2068
+ * @param collection
2069
+ */
1903
2070
  this.createCollectionDocumentMutation = async (collection) => {
1904
2071
  return astBuilder.FieldDefinition({
1905
2072
  type: await this._buildCollectionDocumentType(collection),
@@ -1919,6 +2086,22 @@ var Builder = class {
1919
2086
  ]
1920
2087
  });
1921
2088
  };
2089
+ /**
2090
+ * ```graphql
2091
+ * # ex.
2092
+ * {
2093
+ * getPostList(first: 10) {
2094
+ * edges {
2095
+ * node {
2096
+ * id
2097
+ * }
2098
+ * }
2099
+ * }
2100
+ * }
2101
+ * ```
2102
+ *
2103
+ * @param collection
2104
+ */
1922
2105
  this.collectionDocumentList = async (collection) => {
1923
2106
  const connectionName = NAMER.referenceConnectionType(collection.namespace);
1924
2107
  this.addToLookupMap({
@@ -1934,6 +2117,10 @@ var Builder = class {
1934
2117
  collection
1935
2118
  });
1936
2119
  };
2120
+ /**
2121
+ * GraphQL type definitions which remain unchanged regardless
2122
+ * of the supplied Tina schema. Ex. "node" interface
2123
+ */
1937
2124
  this.buildStaticDefinitions = () => staticDefinitions;
1938
2125
  this._buildCollectionDocumentType = async (collection, suffix = "", extraFields = [], extraInterfaces = []) => {
1939
2126
  const documentTypeName = NAMER.documentTypeName(collection.namespace);
@@ -2438,6 +2625,7 @@ var Builder = class {
2438
2625
  name: NAMER.dataFilterTypeName(namespace),
2439
2626
  fields: await sequential(collections, async (collection2) => {
2440
2627
  return astBuilder.InputValueDefinition({
2628
+ // @ts-ignore
2441
2629
  name: collection2.name,
2442
2630
  type: NAMER.dataFilterTypeName(collection2.namespace)
2443
2631
  });
@@ -2626,7 +2814,8 @@ Visit https://tina.io/docs/errors/ui-not-supported/ for more information
2626
2814
  ]
2627
2815
  });
2628
2816
  };
2629
- this.maxDepth = config?.tinaSchema.schema?.config?.client?.referenceDepth ?? 2;
2817
+ this.maxDepth = // @ts-ignore
2818
+ config?.tinaSchema.schema?.config?.client?.referenceDepth ?? 2;
2630
2819
  this.tinaSchema = config.tinaSchema;
2631
2820
  this.lookupMap = {};
2632
2821
  }
@@ -2637,8 +2826,7 @@ Visit https://tina.io/docs/errors/ui-not-supported/ for more information
2637
2826
  selections.push(field);
2638
2827
  });
2639
2828
  const filteredSelections = filterSelections(selections);
2640
- if (!filteredSelections.length)
2641
- return false;
2829
+ if (!filteredSelections.length) return false;
2642
2830
  return astBuilder.InlineFragmentDefinition({
2643
2831
  selections: filteredSelections,
2644
2832
  name: NAMER.dataTypeName(template.namespace)
@@ -2675,6 +2863,7 @@ var filterSelections = (arr) => {
2675
2863
  import { TinaSchema } from "@tinacms/schema-tools";
2676
2864
 
2677
2865
  // src/schema/validate.ts
2866
+ import { addNamespaceToSchema } from "@tinacms/schema-tools";
2678
2867
  import deepClone from "lodash.clonedeep";
2679
2868
  import * as yup2 from "yup";
2680
2869
  import {
@@ -2721,6 +2910,7 @@ var validationCollectionsPathAndMatch = (collections) => {
2721
2910
  }).map((x) => `${x.path}${x.format || "md"}`);
2722
2911
  if (noMatchCollections.length !== new Set(noMatchCollections).size) {
2723
2912
  throw new Error(
2913
+ // TODO: add a link to the docs
2724
2914
  "Two collections without match can not have the same `path`. Please make the `path` unique or add a matches property to the collection."
2725
2915
  );
2726
2916
  }
@@ -2829,7 +3019,7 @@ var validateField = async (field) => {
2829
3019
  // package.json
2830
3020
  var package_default = {
2831
3021
  name: "@tinacms/graphql",
2832
- version: "1.5.8",
3022
+ version: "1.6.0",
2833
3023
  main: "dist/index.js",
2834
3024
  module: "dist/index.mjs",
2835
3025
  typings: "dist/index.d.ts",
@@ -2855,33 +3045,32 @@ var package_default = {
2855
3045
  types: "pnpm tsc",
2856
3046
  build: "tinacms-scripts build",
2857
3047
  docs: "pnpm typedoc",
2858
- serve: "pnpm nodemon dist/server.js",
2859
- test: "jest",
2860
- "test-watch": "jest --watch"
3048
+ test: "vitest run",
3049
+ "test-watch": "vitest"
2861
3050
  },
2862
3051
  dependencies: {
2863
- "@iarna/toml": "^2.2.5",
3052
+ "@iarna/toml": "catalog:",
2864
3053
  "@tinacms/mdx": "workspace:*",
2865
3054
  "@tinacms/schema-tools": "workspace:*",
2866
- "abstract-level": "^1.0.4",
3055
+ "abstract-level": "catalog:",
2867
3056
  "date-fns": "^2.30.0",
2868
- "fast-glob": "^3.3.2",
2869
- "fs-extra": "^11.2.0",
2870
- "glob-parent": "^6.0.2",
3057
+ "fast-glob": "catalog:",
3058
+ "fs-extra": "catalog:",
3059
+ "glob-parent": "catalog:",
2871
3060
  graphql: "15.8.0",
2872
- "gray-matter": "^4.0.3",
2873
- "isomorphic-git": "^1.27.1",
2874
- "js-sha1": "^0.6.0",
3061
+ "gray-matter": "catalog:",
3062
+ "isomorphic-git": "catalog:",
3063
+ "js-sha1": "catalog:",
2875
3064
  "js-yaml": "^3.14.1",
2876
- "jsonpath-plus": "10.1.0",
2877
- "lodash.clonedeep": "^4.5.0",
2878
- "lodash.set": "^4.3.2",
2879
- "lodash.uniqby": "^4.7.0",
2880
- "many-level": "^2.0.0",
2881
- micromatch: "4.0.8",
2882
- "normalize-path": "^3.0.0",
2883
- "readable-stream": "^4.5.2",
2884
- scmp: "^2.1.0",
3065
+ "jsonpath-plus": "catalog:",
3066
+ "lodash.clonedeep": "catalog:",
3067
+ "lodash.set": "catalog:",
3068
+ "lodash.uniqby": "catalog:",
3069
+ "many-level": "catalog:",
3070
+ micromatch: "catalog:",
3071
+ "normalize-path": "catalog:",
3072
+ "readable-stream": "catalog:",
3073
+ scmp: "catalog:",
2885
3074
  yup: "^0.32.11"
2886
3075
  },
2887
3076
  publishConfig: {
@@ -2896,26 +3085,24 @@ var package_default = {
2896
3085
  "@tinacms/scripts": "workspace:*",
2897
3086
  "@types/cors": "^2.8.17",
2898
3087
  "@types/estree": "^0.0.50",
2899
- "@types/express": "^4.17.21",
3088
+ "@types/express": "catalog:",
2900
3089
  "@types/fs-extra": "^9.0.13",
2901
- "@types/jest": "^26.0.24",
2902
3090
  "@types/js-yaml": "^3.12.10",
2903
- "@types/lodash.camelcase": "^4.3.9",
2904
- "@types/lodash.upperfirst": "^4.3.9",
2905
- "@types/lru-cache": "^5.1.1",
2906
- "@types/mdast": "^3.0.15",
2907
- "@types/micromatch": "^4.0.9",
2908
- "@types/node": "^22.9.0",
2909
- "@types/normalize-path": "^3.0.2",
2910
- "@types/ws": "^7.4.7",
3091
+ "@types/lodash.camelcase": "catalog:",
3092
+ "@types/lodash.upperfirst": "catalog:",
3093
+ "@types/lru-cache": "catalog:",
3094
+ "@types/mdast": "catalog:",
3095
+ "@types/micromatch": "catalog:",
3096
+ "@types/node": "^22.13.1",
3097
+ "@types/normalize-path": "catalog:",
3098
+ "@types/ws": "catalog:",
2911
3099
  "@types/yup": "^0.29.14",
2912
- jest: "^29.7.0",
2913
- "jest-diff": "^29.7.0",
2914
3100
  "jest-file-snapshot": "^0.5.0",
2915
- "jest-matcher-utils": "^29.7.0",
2916
- "memory-level": "^1.0.0",
2917
- nodemon: "3.1.4",
2918
- typescript: "^5.6.3"
3101
+ "memory-level": "catalog:",
3102
+ typescript: "^5.7.3",
3103
+ vite: "^4.5.9",
3104
+ vitest: "^0.32.4",
3105
+ zod: "^3.24.2"
2919
3106
  }
2920
3107
  };
2921
3108
 
@@ -2986,6 +3173,7 @@ var _buildFragments = async (builder, tinaSchema) => {
2986
3173
  const fragDoc = {
2987
3174
  kind: "Document",
2988
3175
  definitions: uniqBy2(
3176
+ // @ts-ignore
2989
3177
  extractInlineTypes(fragmentDefinitionsFields),
2990
3178
  (node) => node.name.value
2991
3179
  )
@@ -3008,6 +3196,7 @@ var _buildQueries = async (builder, tinaSchema) => {
3008
3196
  fragName,
3009
3197
  queryName: queryListName,
3010
3198
  filterType: queryFilterTypeName,
3199
+ // look for flag to see if the data layer is enabled
3011
3200
  dataLayer: Boolean(
3012
3201
  tinaSchema.config?.meta?.flags?.find((x) => x === "experimentalData")
3013
3202
  )
@@ -3017,6 +3206,7 @@ var _buildQueries = async (builder, tinaSchema) => {
3017
3206
  const queryDoc = {
3018
3207
  kind: "Document",
3019
3208
  definitions: uniqBy2(
3209
+ // @ts-ignore
3020
3210
  extractInlineTypes(operationsDefinitions),
3021
3211
  (node) => node.name.value
3022
3212
  )
@@ -3068,7 +3258,9 @@ var _buildSchema = async (builder, tinaSchema) => {
3068
3258
  await builder.buildCreateCollectionFolderMutation()
3069
3259
  );
3070
3260
  await sequential(collections, async (collection) => {
3071
- queryTypeDefinitionFields.push(await builder.collectionDocument(collection));
3261
+ queryTypeDefinitionFields.push(
3262
+ await builder.collectionDocument(collection)
3263
+ );
3072
3264
  if (collection.isAuthCollection) {
3073
3265
  queryTypeDefinitionFields.push(
3074
3266
  await builder.authenticationCollectionDocument(collection)
@@ -3105,6 +3297,7 @@ var _buildSchema = async (builder, tinaSchema) => {
3105
3297
  return {
3106
3298
  kind: "Document",
3107
3299
  definitions: uniqBy2(
3300
+ // @ts-ignore
3108
3301
  extractInlineTypes(definitions),
3109
3302
  (node) => node.name.value
3110
3303
  )
@@ -3117,404 +3310,165 @@ import { graphql, buildASTSchema, getNamedType, GraphQLError as GraphQLError4 }
3117
3310
  // src/resolver/index.ts
3118
3311
  import path3 from "path";
3119
3312
  import isValid from "date-fns/isValid/index.js";
3313
+ import { JSONPath as JSONPath2 } from "jsonpath-plus";
3120
3314
 
3121
3315
  // src/mdx/index.ts
3122
- import { parseMDX, stringifyMDX } from "@tinacms/mdx";
3316
+ import { parseMDX, serializeMDX } from "@tinacms/mdx";
3123
3317
 
3124
3318
  // src/resolver/index.ts
3125
- import { JSONPath as JSONPath2 } from "jsonpath-plus";
3319
+ import { GraphQLError as GraphQLError2 } from "graphql";
3126
3320
 
3127
- // src/resolver/error.ts
3128
- var TinaGraphQLError = class extends Error {
3129
- constructor(message, extensions) {
3130
- super(message);
3131
- if (!this.name) {
3132
- Object.defineProperty(this, "name", { value: "TinaGraphQLError" });
3133
- }
3134
- this.extensions = { ...extensions };
3135
- }
3321
+ // src/database/datalayer.ts
3322
+ import { JSONPath } from "jsonpath-plus";
3323
+ import sha from "js-sha1";
3324
+
3325
+ // src/database/level.ts
3326
+ var ARRAY_ITEM_VALUE_SEPARATOR = ",";
3327
+ var INDEX_KEY_FIELD_SEPARATOR = "";
3328
+ var CONTENT_ROOT_PREFIX = "~";
3329
+ var SUBLEVEL_OPTIONS = {
3330
+ separator: INDEX_KEY_FIELD_SEPARATOR,
3331
+ valueEncoding: "json"
3136
3332
  };
3137
- var TinaFetchError = class extends Error {
3138
- constructor(message, args) {
3139
- super(message);
3140
- this.name = "TinaFetchError";
3141
- this.collection = args.collection;
3142
- this.stack = args.stack;
3143
- this.file = args.file;
3144
- this.originalError = args.originalError;
3333
+ var LevelProxyHandler = {
3334
+ get: function(target, property) {
3335
+ if (!target[property]) {
3336
+ throw new Error(`The property, ${property.toString()}, doesn't exist`);
3337
+ }
3338
+ if (typeof target[property] !== "function") {
3339
+ throw new Error(
3340
+ `The property, ${property.toString()}, is not a function`
3341
+ );
3342
+ }
3343
+ if (property === "get") {
3344
+ return async (...args) => {
3345
+ let result;
3346
+ try {
3347
+ result = await target[property].apply(target, args);
3348
+ } catch (e) {
3349
+ if (e.code !== "LEVEL_NOT_FOUND") {
3350
+ throw e;
3351
+ }
3352
+ }
3353
+ return result;
3354
+ };
3355
+ } else if (property === "sublevel") {
3356
+ return (...args) => {
3357
+ return new Proxy(
3358
+ // eslint-disable-next-line prefer-spread
3359
+ target[property].apply(target, args),
3360
+ LevelProxyHandler
3361
+ );
3362
+ };
3363
+ } else {
3364
+ return (...args) => target[property].apply(target, args);
3365
+ }
3145
3366
  }
3146
3367
  };
3147
- var TinaQueryError = class extends TinaFetchError {
3148
- constructor(args) {
3149
- super(
3150
- `Error querying file ${args.file} from collection ${args.collection}. ${auditMessage(args.includeAuditMessage)}`,
3151
- args
3152
- );
3368
+ var LevelProxy = class {
3369
+ constructor(level) {
3370
+ return new Proxy(level, LevelProxyHandler);
3153
3371
  }
3154
3372
  };
3155
- var TinaParseDocumentError = class extends TinaFetchError {
3156
- constructor(args) {
3157
- super(
3158
- `Error parsing file ${args.file} from collection ${args.collection}. ${auditMessage(args.includeAuditMessage)}`,
3159
- args
3373
+
3374
+ // src/database/datalayer.ts
3375
+ import path2 from "path";
3376
+
3377
+ // src/database/util.ts
3378
+ import toml from "@iarna/toml";
3379
+ import {
3380
+ normalizePath
3381
+ } from "@tinacms/schema-tools";
3382
+ import matter from "gray-matter";
3383
+ import yaml from "js-yaml";
3384
+ import path from "path";
3385
+ import micromatch from "micromatch";
3386
+
3387
+ // src/database/alias-utils.ts
3388
+ var replaceBlockAliases = (template, item) => {
3389
+ const output = { ...item };
3390
+ const templateKey = template.templateKey || "_template";
3391
+ const templateName = output[templateKey];
3392
+ const matchingTemplate = template.templates.find(
3393
+ (t) => t.nameOverride == templateName || t.name == templateName
3394
+ );
3395
+ if (!matchingTemplate) {
3396
+ throw new Error(
3397
+ `Block template "${templateName}" is not defined for field "${template.name}"`
3160
3398
  );
3161
3399
  }
3162
- toString() {
3163
- return super.toString() + "\n OriginalError: \n" + this.originalError.toString();
3400
+ output._template = matchingTemplate.name;
3401
+ if (templateKey != "_template") {
3402
+ delete output[templateKey];
3164
3403
  }
3404
+ return output;
3165
3405
  };
3166
- var auditMessage = (includeAuditMessage = true) => includeAuditMessage ? `Please run "tinacms audit" or add the --verbose option for more info` : "";
3167
- var handleFetchErrorError = (e, verbose) => {
3168
- if (e instanceof Error) {
3169
- if (e instanceof TinaFetchError) {
3170
- if (verbose) {
3171
- console.log(e.toString());
3172
- console.log(e);
3173
- console.log(e.stack);
3406
+ var replaceNameOverrides = (template, obj) => {
3407
+ if (template.list) {
3408
+ return obj.map((item) => {
3409
+ if (isBlockField(template)) {
3410
+ item = replaceBlockAliases(template, item);
3174
3411
  }
3175
- }
3412
+ return _replaceNameOverrides(
3413
+ getTemplateForData(template, item).fields,
3414
+ item
3415
+ );
3416
+ });
3176
3417
  } else {
3177
- console.error(e);
3418
+ return _replaceNameOverrides(getTemplateForData(template, obj).fields, obj);
3178
3419
  }
3179
- throw e;
3180
3420
  };
3181
-
3182
- // src/resolver/filter-utils.ts
3183
- var resolveReferences = async (filter, fields, resolver) => {
3184
- for (const fieldKey of Object.keys(filter)) {
3185
- const fieldDefinition = fields.find(
3186
- (f) => f.name === fieldKey
3421
+ function isBlockField(field) {
3422
+ return field && field.type === "object" && field.templates?.length > 0;
3423
+ }
3424
+ var _replaceNameOverrides = (fields, obj) => {
3425
+ const output = {};
3426
+ Object.keys(obj).forEach((key) => {
3427
+ const field = fields.find(
3428
+ (fieldWithMatchingAlias) => (fieldWithMatchingAlias?.nameOverride || fieldWithMatchingAlias?.name) === key
3187
3429
  );
3188
- if (fieldDefinition) {
3189
- if (fieldDefinition.type === "reference") {
3190
- const { edges, values } = await resolver(filter, fieldDefinition);
3191
- if (edges.length === 1) {
3192
- filter[fieldKey] = {
3193
- eq: values[0]
3194
- };
3195
- } else if (edges.length > 1) {
3196
- filter[fieldKey] = {
3197
- in: values
3198
- };
3199
- } else {
3200
- filter[fieldKey] = {
3201
- eq: "___null___"
3202
- };
3203
- }
3204
- } else if (fieldDefinition.type === "object") {
3205
- if (fieldDefinition.templates) {
3206
- for (const templateName of Object.keys(filter[fieldKey])) {
3207
- const template = fieldDefinition.templates.find(
3208
- (template2) => !(typeof template2 === "string") && template2.name === templateName
3209
- );
3210
- if (template) {
3211
- await resolveReferences(
3212
- filter[fieldKey][templateName],
3213
- template.fields,
3214
- resolver
3215
- );
3216
- } else {
3217
- throw new Error(`Template ${templateName} not found`);
3218
- }
3219
- }
3220
- } else {
3221
- await resolveReferences(
3222
- filter[fieldKey],
3223
- fieldDefinition.fields,
3224
- resolver
3225
- );
3226
- }
3430
+ output[field?.name || key] = field?.type == "object" ? replaceNameOverrides(field, obj[key]) : obj[key];
3431
+ });
3432
+ return output;
3433
+ };
3434
+ var getTemplateForData = (field, data) => {
3435
+ if (field.templates?.length) {
3436
+ const templateKey = "_template";
3437
+ if (data[templateKey]) {
3438
+ const result = field.templates.find(
3439
+ (template) => template.nameOverride === data[templateKey] || template.name === data[templateKey]
3440
+ );
3441
+ if (result) {
3442
+ return result;
3227
3443
  }
3228
- } else {
3229
- throw new Error(`Unable to find field ${fieldKey}`);
3444
+ throw new Error(
3445
+ `Template "${data[templateKey]}" is not defined for field "${field.name}"`
3446
+ );
3230
3447
  }
3448
+ throw new Error(
3449
+ `Missing required key "${templateKey}" on field "${field.name}"`
3450
+ );
3451
+ } else {
3452
+ return field;
3231
3453
  }
3232
3454
  };
3233
- var collectConditionsForChildFields = (filterNode, fields, pathExpression, collectCondition) => {
3234
- for (const childFieldName of Object.keys(filterNode)) {
3235
- const childField = fields.find((field) => field.name === childFieldName);
3236
- if (!childField) {
3237
- throw new Error(`Unable to find type for field ${childFieldName}`);
3238
- }
3239
- collectConditionsForField(
3240
- childFieldName,
3241
- childField,
3242
- filterNode[childFieldName],
3243
- pathExpression,
3244
- collectCondition
3455
+ var applyBlockAliases = (template, item) => {
3456
+ const output = { ...item };
3457
+ const templateKey = template.templateKey || "_template";
3458
+ const templateName = output._template;
3459
+ const matchingTemplate = template.templates.find(
3460
+ (t) => t.nameOverride == templateName || t.name == templateName
3461
+ );
3462
+ if (!matchingTemplate) {
3463
+ throw new Error(
3464
+ `Block template "${templateName}" is not defined for field "${template.name}"`
3245
3465
  );
3246
3466
  }
3247
- };
3248
- var collectConditionsForObjectField = (fieldName, field, filterNode, pathExpression, collectCondition) => {
3249
- if (field.list && field.templates) {
3250
- for (const [filterKey, childFilterNode] of Object.entries(filterNode)) {
3251
- const template = field.templates.find(
3252
- (template2) => !(typeof template2 === "string") && template2.name === filterKey
3253
- );
3254
- const jsonPath = `${fieldName}[?(@._template=="${filterKey}")]`;
3255
- const filterPath = pathExpression ? `${pathExpression}.${jsonPath}` : jsonPath;
3256
- collectConditionsForChildFields(
3257
- childFilterNode,
3258
- template.fields,
3259
- filterPath,
3260
- collectCondition
3261
- );
3262
- }
3263
- } else {
3264
- const jsonPath = `${fieldName}${field.list ? "[*]" : ""}`;
3265
- const filterPath = pathExpression ? `${pathExpression}.${jsonPath}` : `${jsonPath}`;
3266
- collectConditionsForChildFields(
3267
- filterNode,
3268
- field.fields,
3269
- filterPath,
3270
- collectCondition
3271
- );
3272
- }
3273
- };
3274
- var collectConditionsForField = (fieldName, field, filterNode, pathExpression, collectCondition) => {
3275
- if (field.type === "object") {
3276
- collectConditionsForObjectField(
3277
- fieldName,
3278
- field,
3279
- filterNode,
3280
- pathExpression,
3281
- collectCondition
3282
- );
3283
- } else {
3284
- collectCondition({
3285
- filterPath: pathExpression ? `${pathExpression}.${fieldName}` : fieldName,
3286
- filterExpression: {
3287
- _type: field.type,
3288
- _list: !!field.list,
3289
- ...filterNode
3290
- }
3291
- });
3292
- }
3293
- };
3294
-
3295
- // src/resolver/media-utils.ts
3296
- var resolveMediaCloudToRelative = (value, config = { useRelativeMedia: true }, schema) => {
3297
- if (config && value) {
3298
- if (config.useRelativeMedia === true) {
3299
- return value;
3300
- }
3301
- if (hasTinaMediaConfig(schema) === true) {
3302
- const assetsURL = `https://${config.assetsHost}/${config.clientId}`;
3303
- if (typeof value === "string" && value.includes(assetsURL)) {
3304
- const cleanMediaRoot = cleanUpSlashes(
3305
- schema.config.media.tina.mediaRoot
3306
- );
3307
- const strippedURL = value.replace(assetsURL, "");
3308
- return `${cleanMediaRoot}${strippedURL}`;
3309
- }
3310
- if (Array.isArray(value)) {
3311
- return value.map((v) => {
3312
- if (!v || typeof v !== "string")
3313
- return v;
3314
- const cleanMediaRoot = cleanUpSlashes(
3315
- schema.config.media.tina.mediaRoot
3316
- );
3317
- const strippedURL = v.replace(assetsURL, "");
3318
- return `${cleanMediaRoot}${strippedURL}`;
3319
- });
3320
- }
3321
- return value;
3322
- }
3323
- return value;
3324
- } else {
3325
- return value;
3326
- }
3327
- };
3328
- var resolveMediaRelativeToCloud = (value, config = { useRelativeMedia: true }, schema) => {
3329
- if (config && value) {
3330
- if (config.useRelativeMedia === true) {
3331
- return value;
3332
- }
3333
- if (hasTinaMediaConfig(schema) === true) {
3334
- const cleanMediaRoot = cleanUpSlashes(schema.config.media.tina.mediaRoot);
3335
- if (typeof value === "string") {
3336
- const strippedValue = value.replace(cleanMediaRoot, "");
3337
- return `https://${config.assetsHost}/${config.clientId}${strippedValue}`;
3338
- }
3339
- if (Array.isArray(value)) {
3340
- return value.map((v) => {
3341
- if (!v || typeof v !== "string")
3342
- return v;
3343
- const strippedValue = v.replace(cleanMediaRoot, "");
3344
- return `https://${config.assetsHost}/${config.clientId}${strippedValue}`;
3345
- });
3346
- }
3347
- }
3348
- return value;
3349
- } else {
3350
- return value;
3351
- }
3352
- };
3353
- var cleanUpSlashes = (path7) => {
3354
- if (path7) {
3355
- return `/${path7.replace(/^\/+|\/+$/gm, "")}`;
3356
- }
3357
- return "";
3358
- };
3359
- var hasTinaMediaConfig = (schema) => {
3360
- if (!schema.config?.media?.tina)
3361
- return false;
3362
- if (typeof schema.config?.media?.tina?.publicFolder !== "string" && typeof schema.config?.media?.tina?.mediaRoot !== "string")
3363
- return false;
3364
- return true;
3365
- };
3366
-
3367
- // src/resolver/index.ts
3368
- import { GraphQLError as GraphQLError2 } from "graphql";
3369
-
3370
- // src/database/datalayer.ts
3371
- import { JSONPath } from "jsonpath-plus";
3372
- import sha from "js-sha1";
3373
-
3374
- // src/database/level.ts
3375
- var ARRAY_ITEM_VALUE_SEPARATOR = ",";
3376
- var INDEX_KEY_FIELD_SEPARATOR = "";
3377
- var CONTENT_ROOT_PREFIX = "~";
3378
- var SUBLEVEL_OPTIONS = {
3379
- separator: INDEX_KEY_FIELD_SEPARATOR,
3380
- valueEncoding: "json"
3381
- };
3382
- var LevelProxyHandler = {
3383
- get: function(target, property) {
3384
- if (!target[property]) {
3385
- throw new Error(`The property, ${property.toString()}, doesn't exist`);
3386
- }
3387
- if (typeof target[property] !== "function") {
3388
- throw new Error(`The property, ${property.toString()}, is not a function`);
3389
- }
3390
- if (property === "get") {
3391
- return async (...args) => {
3392
- let result;
3393
- try {
3394
- result = await target[property].apply(target, args);
3395
- } catch (e) {
3396
- if (e.code !== "LEVEL_NOT_FOUND") {
3397
- throw e;
3398
- }
3399
- }
3400
- return result;
3401
- };
3402
- } else if (property === "sublevel") {
3403
- return (...args) => {
3404
- return new Proxy(
3405
- target[property].apply(target, args),
3406
- LevelProxyHandler
3407
- );
3408
- };
3409
- } else {
3410
- return (...args) => target[property].apply(target, args);
3411
- }
3412
- }
3413
- };
3414
- var LevelProxy = class {
3415
- constructor(level) {
3416
- return new Proxy(level, LevelProxyHandler);
3417
- }
3418
- };
3419
-
3420
- // src/database/datalayer.ts
3421
- import path2 from "path";
3422
-
3423
- // src/database/util.ts
3424
- import toml from "@iarna/toml";
3425
- import yaml from "js-yaml";
3426
- import matter from "gray-matter";
3427
- import {
3428
- normalizePath
3429
- } from "@tinacms/schema-tools";
3430
- import micromatch from "micromatch";
3431
- import path from "path";
3432
-
3433
- // src/database/alias-utils.ts
3434
- var replaceBlockAliases = (template, item) => {
3435
- const output = { ...item };
3436
- const templateKey = template.templateKey || "_template";
3437
- const templateName = output[templateKey];
3438
- const matchingTemplate = template.templates.find(
3439
- (t) => t.nameOverride == templateName || t.name == templateName
3440
- );
3441
- if (!matchingTemplate) {
3442
- throw new Error(
3443
- `Block template "${templateName}" is not defined for field "${template.name}"`
3444
- );
3445
- }
3446
- output._template = matchingTemplate.name;
3447
- if (templateKey != "_template") {
3448
- delete output[templateKey];
3449
- }
3450
- return output;
3451
- };
3452
- var replaceNameOverrides = (template, obj) => {
3453
- if (template.list) {
3454
- return obj.map((item) => {
3455
- if (isBlockField(template)) {
3456
- item = replaceBlockAliases(template, item);
3457
- }
3458
- return _replaceNameOverrides(
3459
- getTemplateForData(template, item).fields,
3460
- item
3461
- );
3462
- });
3463
- } else {
3464
- return _replaceNameOverrides(getTemplateForData(template, obj).fields, obj);
3465
- }
3466
- };
3467
- function isBlockField(field) {
3468
- return field && field.type === "object" && field.templates?.length > 0;
3469
- }
3470
- var _replaceNameOverrides = (fields, obj) => {
3471
- const output = {};
3472
- Object.keys(obj).forEach((key) => {
3473
- const field = fields.find(
3474
- (fieldWithMatchingAlias) => (fieldWithMatchingAlias?.nameOverride || fieldWithMatchingAlias?.name) === key
3475
- );
3476
- output[field?.name || key] = field?.type == "object" ? replaceNameOverrides(field, obj[key]) : obj[key];
3477
- });
3478
- return output;
3479
- };
3480
- var getTemplateForData = (field, data) => {
3481
- if (field.templates?.length) {
3482
- const templateKey = "_template";
3483
- if (data[templateKey]) {
3484
- const result = field.templates.find(
3485
- (template) => template.nameOverride === data[templateKey] || template.name === data[templateKey]
3486
- );
3487
- if (result) {
3488
- return result;
3489
- }
3490
- throw new Error(
3491
- `Template "${data[templateKey]}" is not defined for field "${field.name}"`
3492
- );
3493
- }
3494
- throw new Error(
3495
- `Missing required key "${templateKey}" on field "${field.name}"`
3496
- );
3497
- } else {
3498
- return field;
3499
- }
3500
- };
3501
- var applyBlockAliases = (template, item) => {
3502
- const output = { ...item };
3503
- const templateKey = template.templateKey || "_template";
3504
- const templateName = output._template;
3505
- const matchingTemplate = template.templates.find(
3506
- (t) => t.nameOverride == templateName || t.name == templateName
3507
- );
3508
- if (!matchingTemplate) {
3509
- throw new Error(
3510
- `Block template "${templateName}" is not defined for field "${template.name}"`
3511
- );
3512
- }
3513
- output[templateKey] = matchingTemplate.nameOverride || matchingTemplate.name;
3514
- if (templateKey != "_template") {
3515
- delete output._template;
3516
- }
3517
- return output;
3467
+ output[templateKey] = matchingTemplate.nameOverride || matchingTemplate.name;
3468
+ if (templateKey != "_template") {
3469
+ delete output._template;
3470
+ }
3471
+ return output;
3518
3472
  };
3519
3473
  var applyNameOverrides = (template, obj) => {
3520
3474
  if (template.list) {
@@ -3769,6 +3723,9 @@ var loadAndParseWithAliases = async (bridge, filepath, collection, templateInfo)
3769
3723
 
3770
3724
  // src/database/datalayer.ts
3771
3725
  var DEFAULT_COLLECTION_SORT_KEY = "__filepath__";
3726
+ var REFS_COLLECTIONS_SORT_KEY = "__refs__";
3727
+ var REFS_REFERENCE_FIELD = "__tina_ref__";
3728
+ var REFS_PATH_FIELD = "__tina_ref_path__";
3772
3729
  var DEFAULT_NUMERIC_LPAD = 4;
3773
3730
  var applyPadding = (input, pad) => {
3774
3731
  if (pad) {
@@ -4278,6 +4235,7 @@ var makeFolderOpsForCollection = (folderTree, collection, indexDefinitions, opTy
4278
4235
  result.push({
4279
4236
  type: opType,
4280
4237
  key: `${collection.path}/${subFolderKey}.${collection.format}`,
4238
+ // replace the root with the collection path
4281
4239
  sublevel: indexSublevel,
4282
4240
  value: {}
4283
4241
  });
@@ -4311,55 +4269,343 @@ var makeFolderOpsForCollection = (folderTree, collection, indexDefinitions, opTy
4311
4269
  });
4312
4270
  }
4313
4271
  }
4314
- return result;
4272
+ return result;
4273
+ };
4274
+ var makeIndexOpsForDocument = (filepath, collection, indexDefinitions, data, opType, level, escapeStr = stringEscaper) => {
4275
+ const result = [];
4276
+ if (collection) {
4277
+ const collectionSublevel = level.sublevel(collection, SUBLEVEL_OPTIONS);
4278
+ for (const [sort, definition] of Object.entries(indexDefinitions)) {
4279
+ const indexedValue = makeKeyForField(definition, data, escapeStr);
4280
+ const indexSublevel = collectionSublevel.sublevel(sort, SUBLEVEL_OPTIONS);
4281
+ if (sort === DEFAULT_COLLECTION_SORT_KEY) {
4282
+ result.push({
4283
+ type: opType,
4284
+ key: filepath,
4285
+ sublevel: indexSublevel,
4286
+ value: opType === "put" ? {} : void 0
4287
+ });
4288
+ } else {
4289
+ if (indexedValue) {
4290
+ result.push({
4291
+ type: opType,
4292
+ key: `${indexedValue}${INDEX_KEY_FIELD_SEPARATOR}${filepath}`,
4293
+ sublevel: indexSublevel,
4294
+ value: opType === "put" ? {} : void 0
4295
+ });
4296
+ }
4297
+ }
4298
+ }
4299
+ }
4300
+ return result;
4301
+ };
4302
+ var makeRefOpsForDocument = (filepath, collection, references, data, opType, level) => {
4303
+ const result = [];
4304
+ if (collection) {
4305
+ for (const [c, referencePaths] of Object.entries(references || {})) {
4306
+ if (!referencePaths.length) {
4307
+ continue;
4308
+ }
4309
+ const collectionSublevel = level.sublevel(c, SUBLEVEL_OPTIONS);
4310
+ const refSublevel = collectionSublevel.sublevel(
4311
+ REFS_COLLECTIONS_SORT_KEY,
4312
+ SUBLEVEL_OPTIONS
4313
+ );
4314
+ const references2 = {};
4315
+ for (const path7 of referencePaths) {
4316
+ const ref = JSONPath({ path: path7, json: data });
4317
+ if (!ref) {
4318
+ continue;
4319
+ }
4320
+ if (Array.isArray(ref)) {
4321
+ for (const r of ref) {
4322
+ if (!r) {
4323
+ continue;
4324
+ }
4325
+ if (references2[r]) {
4326
+ references2[r].push(path7);
4327
+ } else {
4328
+ references2[r] = [path7];
4329
+ }
4330
+ }
4331
+ } else {
4332
+ if (references2[ref]) {
4333
+ references2[ref].push(path7);
4334
+ } else {
4335
+ references2[ref] = [path7];
4336
+ }
4337
+ }
4338
+ }
4339
+ for (const ref of Object.keys(references2)) {
4340
+ for (const path7 of references2[ref]) {
4341
+ result.push({
4342
+ type: opType,
4343
+ key: `${ref}${INDEX_KEY_FIELD_SEPARATOR}${path7}${INDEX_KEY_FIELD_SEPARATOR}${filepath}`,
4344
+ sublevel: refSublevel,
4345
+ value: opType === "put" ? {} : void 0
4346
+ });
4347
+ }
4348
+ }
4349
+ }
4350
+ }
4351
+ return result;
4352
+ };
4353
+ var makeStringEscaper = (regex, replacement) => {
4354
+ return (input) => {
4355
+ if (Array.isArray(input)) {
4356
+ return input.map(
4357
+ (val) => val.replace(regex, replacement)
4358
+ );
4359
+ } else {
4360
+ if (typeof input === "string") {
4361
+ return input.replace(regex, replacement);
4362
+ } else {
4363
+ return input;
4364
+ }
4365
+ }
4366
+ };
4367
+ };
4368
+ var stringEscaper = makeStringEscaper(
4369
+ new RegExp(INDEX_KEY_FIELD_SEPARATOR, "gm"),
4370
+ encodeURIComponent(INDEX_KEY_FIELD_SEPARATOR)
4371
+ );
4372
+
4373
+ // src/resolver/error.ts
4374
+ var TinaGraphQLError = class extends Error {
4375
+ constructor(message, extensions) {
4376
+ super(message);
4377
+ if (!this.name) {
4378
+ Object.defineProperty(this, "name", { value: "TinaGraphQLError" });
4379
+ }
4380
+ this.extensions = { ...extensions };
4381
+ }
4382
+ };
4383
+ var TinaFetchError = class extends Error {
4384
+ constructor(message, args) {
4385
+ super(message);
4386
+ this.name = "TinaFetchError";
4387
+ this.collection = args.collection;
4388
+ this.stack = args.stack;
4389
+ this.file = args.file;
4390
+ this.originalError = args.originalError;
4391
+ }
4392
+ };
4393
+ var TinaQueryError = class extends TinaFetchError {
4394
+ constructor(args) {
4395
+ super(
4396
+ `Error querying file ${args.file} from collection ${args.collection}. ${auditMessage(args.includeAuditMessage)}`,
4397
+ args
4398
+ );
4399
+ }
4400
+ };
4401
+ var TinaParseDocumentError = class extends TinaFetchError {
4402
+ constructor(args) {
4403
+ super(
4404
+ `Error parsing file ${args.file} from collection ${args.collection}. ${auditMessage(args.includeAuditMessage)}`,
4405
+ args
4406
+ );
4407
+ }
4408
+ toString() {
4409
+ return super.toString() + "\n OriginalError: \n" + this.originalError.toString();
4410
+ }
4411
+ };
4412
+ var auditMessage = (includeAuditMessage = true) => includeAuditMessage ? `Please run "tinacms audit" or add the --verbose option for more info` : "";
4413
+ var handleFetchErrorError = (e, verbose) => {
4414
+ if (e instanceof Error) {
4415
+ if (e instanceof TinaFetchError) {
4416
+ if (verbose) {
4417
+ console.log(e.toString());
4418
+ console.log(e);
4419
+ console.log(e.stack);
4420
+ }
4421
+ }
4422
+ } else {
4423
+ console.error(e);
4424
+ }
4425
+ throw e;
4426
+ };
4427
+
4428
+ // src/resolver/filter-utils.ts
4429
+ var resolveReferences = async (filter, fields, resolver) => {
4430
+ for (const fieldKey of Object.keys(filter)) {
4431
+ const fieldDefinition = fields.find(
4432
+ (f) => f.name === fieldKey
4433
+ );
4434
+ if (fieldDefinition) {
4435
+ if (fieldDefinition.type === "reference") {
4436
+ const { edges, values } = await resolver(filter, fieldDefinition);
4437
+ if (edges.length === 1) {
4438
+ filter[fieldKey] = {
4439
+ eq: values[0]
4440
+ };
4441
+ } else if (edges.length > 1) {
4442
+ filter[fieldKey] = {
4443
+ in: values
4444
+ };
4445
+ } else {
4446
+ filter[fieldKey] = {
4447
+ eq: "___null___"
4448
+ };
4449
+ }
4450
+ } else if (fieldDefinition.type === "object") {
4451
+ if (fieldDefinition.templates) {
4452
+ for (const templateName of Object.keys(filter[fieldKey])) {
4453
+ const template = fieldDefinition.templates.find(
4454
+ (template2) => !(typeof template2 === "string") && template2.name === templateName
4455
+ );
4456
+ if (template) {
4457
+ await resolveReferences(
4458
+ filter[fieldKey][templateName],
4459
+ template.fields,
4460
+ resolver
4461
+ );
4462
+ } else {
4463
+ throw new Error(`Template ${templateName} not found`);
4464
+ }
4465
+ }
4466
+ } else {
4467
+ await resolveReferences(
4468
+ filter[fieldKey],
4469
+ fieldDefinition.fields,
4470
+ resolver
4471
+ );
4472
+ }
4473
+ }
4474
+ } else {
4475
+ throw new Error(`Unable to find field ${fieldKey}`);
4476
+ }
4477
+ }
4478
+ };
4479
+ var collectConditionsForChildFields = (filterNode, fields, pathExpression, collectCondition) => {
4480
+ for (const childFieldName of Object.keys(filterNode)) {
4481
+ const childField = fields.find((field) => field.name === childFieldName);
4482
+ if (!childField) {
4483
+ throw new Error(`Unable to find type for field ${childFieldName}`);
4484
+ }
4485
+ collectConditionsForField(
4486
+ childFieldName,
4487
+ childField,
4488
+ filterNode[childFieldName],
4489
+ pathExpression,
4490
+ collectCondition
4491
+ );
4492
+ }
4493
+ };
4494
+ var collectConditionsForObjectField = (fieldName, field, filterNode, pathExpression, collectCondition) => {
4495
+ if (field.list && field.templates) {
4496
+ for (const [filterKey, childFilterNode] of Object.entries(filterNode)) {
4497
+ const template = field.templates.find(
4498
+ (template2) => !(typeof template2 === "string") && template2.name === filterKey
4499
+ );
4500
+ const jsonPath = `${fieldName}[?(@._template=="${filterKey}")]`;
4501
+ const filterPath = pathExpression ? `${pathExpression}.${jsonPath}` : jsonPath;
4502
+ collectConditionsForChildFields(
4503
+ childFilterNode,
4504
+ template.fields,
4505
+ filterPath,
4506
+ collectCondition
4507
+ );
4508
+ }
4509
+ } else {
4510
+ const jsonPath = `${fieldName}${field.list ? "[*]" : ""}`;
4511
+ const filterPath = pathExpression ? `${pathExpression}.${jsonPath}` : `${jsonPath}`;
4512
+ collectConditionsForChildFields(
4513
+ filterNode,
4514
+ field.fields,
4515
+ filterPath,
4516
+ collectCondition
4517
+ );
4518
+ }
4519
+ };
4520
+ var collectConditionsForField = (fieldName, field, filterNode, pathExpression, collectCondition) => {
4521
+ if (field.type === "object") {
4522
+ collectConditionsForObjectField(
4523
+ fieldName,
4524
+ field,
4525
+ filterNode,
4526
+ pathExpression,
4527
+ collectCondition
4528
+ );
4529
+ } else {
4530
+ collectCondition({
4531
+ filterPath: pathExpression ? `${pathExpression}.${fieldName}` : fieldName,
4532
+ filterExpression: {
4533
+ _type: field.type,
4534
+ _list: !!field.list,
4535
+ ...filterNode
4536
+ }
4537
+ });
4538
+ }
4539
+ };
4540
+
4541
+ // src/resolver/media-utils.ts
4542
+ var resolveMediaCloudToRelative = (value, config = { useRelativeMedia: true }, schema) => {
4543
+ if (config && value) {
4544
+ if (config.useRelativeMedia === true) {
4545
+ return value;
4546
+ }
4547
+ if (hasTinaMediaConfig(schema) === true) {
4548
+ const assetsURL = `https://${config.assetsHost}/${config.clientId}`;
4549
+ if (typeof value === "string" && value.includes(assetsURL)) {
4550
+ const cleanMediaRoot = cleanUpSlashes(
4551
+ schema.config.media.tina.mediaRoot
4552
+ );
4553
+ const strippedURL = value.replace(assetsURL, "");
4554
+ return `${cleanMediaRoot}${strippedURL}`;
4555
+ }
4556
+ if (Array.isArray(value)) {
4557
+ return value.map((v) => {
4558
+ if (!v || typeof v !== "string") return v;
4559
+ const cleanMediaRoot = cleanUpSlashes(
4560
+ schema.config.media.tina.mediaRoot
4561
+ );
4562
+ const strippedURL = v.replace(assetsURL, "");
4563
+ return `${cleanMediaRoot}${strippedURL}`;
4564
+ });
4565
+ }
4566
+ return value;
4567
+ }
4568
+ return value;
4569
+ } else {
4570
+ return value;
4571
+ }
4315
4572
  };
4316
- var makeIndexOpsForDocument = (filepath, collection, indexDefinitions, data, opType, level, escapeStr = stringEscaper) => {
4317
- const result = [];
4318
- if (collection) {
4319
- const collectionSublevel = level.sublevel(collection, SUBLEVEL_OPTIONS);
4320
- for (const [sort, definition] of Object.entries(indexDefinitions)) {
4321
- const indexedValue = makeKeyForField(definition, data, escapeStr);
4322
- const indexSublevel = collectionSublevel.sublevel(sort, SUBLEVEL_OPTIONS);
4323
- if (sort === DEFAULT_COLLECTION_SORT_KEY) {
4324
- result.push({
4325
- type: opType,
4326
- key: filepath,
4327
- sublevel: indexSublevel,
4328
- value: opType === "put" ? {} : void 0
4573
+ var resolveMediaRelativeToCloud = (value, config = { useRelativeMedia: true }, schema) => {
4574
+ if (config && value) {
4575
+ if (config.useRelativeMedia === true) {
4576
+ return value;
4577
+ }
4578
+ if (hasTinaMediaConfig(schema) === true) {
4579
+ const cleanMediaRoot = cleanUpSlashes(schema.config.media.tina.mediaRoot);
4580
+ if (typeof value === "string") {
4581
+ const strippedValue = value.replace(cleanMediaRoot, "");
4582
+ return `https://${config.assetsHost}/${config.clientId}${strippedValue}`;
4583
+ }
4584
+ if (Array.isArray(value)) {
4585
+ return value.map((v) => {
4586
+ if (!v || typeof v !== "string") return v;
4587
+ const strippedValue = v.replace(cleanMediaRoot, "");
4588
+ return `https://${config.assetsHost}/${config.clientId}${strippedValue}`;
4329
4589
  });
4330
- } else {
4331
- if (indexedValue) {
4332
- result.push({
4333
- type: opType,
4334
- key: `${indexedValue}${INDEX_KEY_FIELD_SEPARATOR}${filepath}`,
4335
- sublevel: indexSublevel,
4336
- value: opType === "put" ? {} : void 0
4337
- });
4338
- }
4339
4590
  }
4340
4591
  }
4592
+ return value;
4593
+ } else {
4594
+ return value;
4341
4595
  }
4342
- return result;
4343
4596
  };
4344
- var makeStringEscaper = (regex, replacement) => {
4345
- return (input) => {
4346
- if (Array.isArray(input)) {
4347
- return input.map(
4348
- (val) => val.replace(regex, replacement)
4349
- );
4350
- } else {
4351
- if (typeof input === "string") {
4352
- return input.replace(regex, replacement);
4353
- } else {
4354
- return input;
4355
- }
4356
- }
4357
- };
4597
+ var cleanUpSlashes = (path7) => {
4598
+ if (path7) {
4599
+ return `/${path7.replace(/^\/+|\/+$/gm, "")}`;
4600
+ }
4601
+ return "";
4602
+ };
4603
+ var hasTinaMediaConfig = (schema) => {
4604
+ if (!schema.config?.media?.tina) return false;
4605
+ if (typeof schema.config?.media?.tina?.publicFolder !== "string" && typeof schema.config?.media?.tina?.mediaRoot !== "string")
4606
+ return false;
4607
+ return true;
4358
4608
  };
4359
- var stringEscaper = makeStringEscaper(
4360
- new RegExp(INDEX_KEY_FIELD_SEPARATOR, "gm"),
4361
- encodeURIComponent(INDEX_KEY_FIELD_SEPARATOR)
4362
- );
4363
4609
 
4364
4610
  // src/resolver/index.ts
4365
4611
  var createResolver = (args) => {
@@ -4392,6 +4638,7 @@ var resolveFieldData = async ({ namespace, ...field }, rawData, accumulator, tin
4392
4638
  case "password":
4393
4639
  accumulator[field.name] = {
4394
4640
  value: void 0,
4641
+ // never resolve the password hash
4395
4642
  passwordChangeRequired: value["passwordChangeRequired"] ?? false
4396
4643
  };
4397
4644
  break;
@@ -4560,24 +4807,33 @@ var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config,
4560
4807
  throw e;
4561
4808
  }
4562
4809
  };
4563
- var updateObjectWithJsonPath = (obj, path7, newValue) => {
4810
+ var updateObjectWithJsonPath = (obj, path7, oldValue, newValue) => {
4811
+ let updated = false;
4564
4812
  if (!path7.includes(".") && !path7.includes("[")) {
4565
- if (path7 in obj) {
4813
+ if (path7 in obj && obj[path7] === oldValue) {
4566
4814
  obj[path7] = newValue;
4815
+ updated = true;
4567
4816
  }
4568
- return obj;
4569
- }
4570
- const parentPath = path7.replace(/\.[^.]+$/, "");
4571
- const keyToUpdate = path7.match(/[^.]+$/)[0];
4572
- const parents = JSONPath2({ path: parentPath, json: obj, resultType: "value" });
4817
+ return { object: obj, updated };
4818
+ }
4819
+ const parentPath = path7.replace(/\.[^.\[\]]+$/, "");
4820
+ const keyToUpdate = path7.match(/[^.\[\]]+$/)[0];
4821
+ const parents = JSONPath2({
4822
+ path: parentPath,
4823
+ json: obj,
4824
+ resultType: "value"
4825
+ });
4573
4826
  if (parents.length > 0) {
4574
4827
  parents.forEach((parent) => {
4575
4828
  if (parent && typeof parent === "object" && keyToUpdate in parent) {
4576
- parent[keyToUpdate] = newValue;
4829
+ if (parent[keyToUpdate] === oldValue) {
4830
+ parent[keyToUpdate] = newValue;
4831
+ updated = true;
4832
+ }
4577
4833
  }
4578
4834
  });
4579
4835
  }
4580
- return obj;
4836
+ return { object: obj, updated };
4581
4837
  };
4582
4838
  var Resolver = class {
4583
4839
  constructor(init) {
@@ -4586,6 +4842,7 @@ var Resolver = class {
4586
4842
  const collection = this.tinaSchema.getCollection(collectionName);
4587
4843
  const extraFields = {};
4588
4844
  return {
4845
+ // return the collection and hasDocuments to resolve documents at a lower level
4589
4846
  documents: { collection, hasDocuments },
4590
4847
  ...collection,
4591
4848
  ...extraFields
@@ -4593,7 +4850,9 @@ var Resolver = class {
4593
4850
  };
4594
4851
  this.getRaw = async (fullPath) => {
4595
4852
  if (typeof fullPath !== "string") {
4596
- throw new Error(`fullPath must be of type string for getDocument request`);
4853
+ throw new Error(
4854
+ `fullPath must be of type string for getDocument request`
4855
+ );
4597
4856
  }
4598
4857
  return this.database.get(fullPath);
4599
4858
  };
@@ -4622,7 +4881,9 @@ var Resolver = class {
4622
4881
  };
4623
4882
  this.getDocument = async (fullPath, opts = {}) => {
4624
4883
  if (typeof fullPath !== "string") {
4625
- throw new Error(`fullPath must be of type string for getDocument request`);
4884
+ throw new Error(
4885
+ `fullPath must be of type string for getDocument request`
4886
+ );
4626
4887
  }
4627
4888
  const rawData = await this.getRaw(fullPath);
4628
4889
  const hasReferences = opts?.checkReferences ? await this.hasReferences(fullPath, opts.collection) : void 0;
@@ -4637,7 +4898,9 @@ var Resolver = class {
4637
4898
  };
4638
4899
  this.deleteDocument = async (fullPath) => {
4639
4900
  if (typeof fullPath !== "string") {
4640
- throw new Error(`fullPath must be of type string for getDocument request`);
4901
+ throw new Error(
4902
+ `fullPath must be of type string for getDocument request`
4903
+ );
4641
4904
  }
4642
4905
  await this.database.delete(fullPath);
4643
4906
  };
@@ -4672,7 +4935,9 @@ var Resolver = class {
4672
4935
  );
4673
4936
  } else {
4674
4937
  return this.buildFieldMutations(
4938
+ // @ts-ignore FIXME Argument of type 'string | object' is not assignable to parameter of type '{ [fieldName: string]: string | object | (string | object)[]; }'
4675
4939
  fieldValue,
4940
+ //@ts-ignore
4676
4941
  objectTemplate,
4677
4942
  existingData
4678
4943
  );
@@ -4684,6 +4949,7 @@ var Resolver = class {
4684
4949
  fieldValue.map(async (item) => {
4685
4950
  if (typeof item === "string") {
4686
4951
  throw new Error(
4952
+ //@ts-ignore
4687
4953
  `Expected object for template value for field ${field.name}`
4688
4954
  );
4689
4955
  }
@@ -4692,16 +4958,19 @@ var Resolver = class {
4692
4958
  });
4693
4959
  const [templateName] = Object.entries(item)[0];
4694
4960
  const template = templates.find(
4961
+ //@ts-ignore
4695
4962
  (template2) => template2.name === templateName
4696
4963
  );
4697
4964
  if (!template) {
4698
4965
  throw new Error(`Expected to find template ${templateName}`);
4699
4966
  }
4700
4967
  return {
4968
+ // @ts-ignore FIXME Argument of type 'unknown' is not assignable to parameter of type '{ [fieldName: string]: string | { [key: string]: unknown; } | (string | { [key: string]: unknown; })[]; }'
4701
4969
  ...await this.buildFieldMutations(
4702
4970
  item[template.name],
4703
4971
  template
4704
4972
  ),
4973
+ //@ts-ignore
4705
4974
  _template: template.name
4706
4975
  };
4707
4976
  })
@@ -4709,6 +4978,7 @@ var Resolver = class {
4709
4978
  } else {
4710
4979
  if (typeof fieldValue === "string") {
4711
4980
  throw new Error(
4981
+ //@ts-ignore
4712
4982
  `Expected object for template value for field ${field.name}`
4713
4983
  );
4714
4984
  }
@@ -4717,16 +4987,19 @@ var Resolver = class {
4717
4987
  });
4718
4988
  const [templateName] = Object.entries(fieldValue)[0];
4719
4989
  const template = templates.find(
4990
+ //@ts-ignore
4720
4991
  (template2) => template2.name === templateName
4721
4992
  );
4722
4993
  if (!template) {
4723
4994
  throw new Error(`Expected to find template ${templateName}`);
4724
4995
  }
4725
4996
  return {
4997
+ // @ts-ignore FIXME Argument of type 'unknown' is not assignable to parameter of type '{ [fieldName: string]: string | { [key: string]: unknown; } | (string | { [key: string]: unknown; })[]; }'
4726
4998
  ...await this.buildFieldMutations(
4727
4999
  fieldValue[template.name],
4728
5000
  template
4729
5001
  ),
5002
+ //@ts-ignore
4730
5003
  _template: template.name
4731
5004
  };
4732
5005
  }
@@ -4766,6 +5039,7 @@ var Resolver = class {
4766
5039
  return this.getDocument(realPath);
4767
5040
  }
4768
5041
  const params = await this.buildObjectMutations(
5042
+ // @ts-ignore
4769
5043
  args.params[collection.name],
4770
5044
  collection
4771
5045
  );
@@ -4811,6 +5085,7 @@ var Resolver = class {
4811
5085
  const values = {
4812
5086
  ...oldDoc,
4813
5087
  ...await this.buildFieldMutations(
5088
+ // @ts-ignore FIXME: failing on unknown, which we don't need to know because it's recursive
4814
5089
  templateParams,
4815
5090
  template,
4816
5091
  doc?._rawData
@@ -4824,13 +5099,22 @@ var Resolver = class {
4824
5099
  return this.getDocument(realPath);
4825
5100
  }
4826
5101
  const params = await this.buildObjectMutations(
5102
+ //@ts-ignore
4827
5103
  isCollectionSpecific ? args.params : args.params[collection.name],
4828
5104
  collection,
4829
5105
  doc?._rawData
4830
5106
  );
4831
- await this.database.put(realPath, { ...oldDoc, ...params }, collection.name);
5107
+ await this.database.put(
5108
+ realPath,
5109
+ { ...oldDoc, ...params },
5110
+ collection.name
5111
+ );
4832
5112
  return this.getDocument(realPath);
4833
5113
  };
5114
+ /**
5115
+ * Returns top-level fields which are not defined in the collection, so their
5116
+ * values are not eliminated from Tina when new values are saved
5117
+ */
4834
5118
  this.resolveLegacyValues = (oldDoc, collection) => {
4835
5119
  const legacyValues = {};
4836
5120
  Object.entries(oldDoc).forEach(([key, value]) => {
@@ -4937,17 +5221,35 @@ var Resolver = class {
4937
5221
  await this.deleteDocument(realPath);
4938
5222
  if (await this.hasReferences(realPath, collection)) {
4939
5223
  const collRefs = await this.findReferences(realPath, collection);
4940
- for (const [collection2, refFields] of Object.entries(collRefs)) {
4941
- for (const [refPath, refs] of Object.entries(refFields)) {
4942
- let refDoc = await this.getRaw(refPath);
4943
- for (const ref of refs) {
4944
- refDoc = updateObjectWithJsonPath(
5224
+ for (const [collection2, docsWithRefs] of Object.entries(collRefs)) {
5225
+ for (const [pathToDocWithRef, referencePaths] of Object.entries(
5226
+ docsWithRefs
5227
+ )) {
5228
+ let refDoc = await this.getRaw(pathToDocWithRef);
5229
+ let hasUpdate = false;
5230
+ for (const path7 of referencePaths) {
5231
+ const { object: object2, updated } = updateObjectWithJsonPath(
4945
5232
  refDoc,
4946
- ref.path.join("."),
5233
+ path7,
5234
+ realPath,
4947
5235
  null
4948
5236
  );
5237
+ refDoc = object2;
5238
+ hasUpdate = updated || hasUpdate;
5239
+ }
5240
+ if (hasUpdate) {
5241
+ const collectionWithRef = this.tinaSchema.getCollectionByFullPath(pathToDocWithRef);
5242
+ if (!collectionWithRef) {
5243
+ throw new Error(
5244
+ `Unable to find collection for ${pathToDocWithRef}`
5245
+ );
5246
+ }
5247
+ await this.database.put(
5248
+ pathToDocWithRef,
5249
+ refDoc,
5250
+ collectionWithRef.name
5251
+ );
4949
5252
  }
4950
- await this.database.put(refPath, refDoc, collection2);
4951
5253
  }
4952
5254
  }
4953
5255
  }
@@ -4967,26 +5269,49 @@ var Resolver = class {
4967
5269
  collection?.path,
4968
5270
  args.params.relativePath
4969
5271
  );
5272
+ if (newRealPath === realPath) {
5273
+ return doc;
5274
+ }
4970
5275
  await this.database.put(newRealPath, doc._rawData, collection.name);
4971
5276
  await this.deleteDocument(realPath);
4972
5277
  const collRefs = await this.findReferences(realPath, collection);
4973
- for (const [collection2, refFields] of Object.entries(collRefs)) {
4974
- for (const [refPath, refs] of Object.entries(refFields)) {
4975
- let refDoc = await this.getRaw(refPath);
4976
- for (const ref of refs) {
4977
- refDoc = updateObjectWithJsonPath(
4978
- refDoc,
4979
- ref.path.join("."),
5278
+ for (const [collection2, docsWithRefs] of Object.entries(collRefs)) {
5279
+ for (const [pathToDocWithRef, referencePaths] of Object.entries(
5280
+ docsWithRefs
5281
+ )) {
5282
+ let docWithRef = await this.getRaw(pathToDocWithRef);
5283
+ let hasUpdate = false;
5284
+ for (const path7 of referencePaths) {
5285
+ const { object: object2, updated } = updateObjectWithJsonPath(
5286
+ docWithRef,
5287
+ path7,
5288
+ realPath,
4980
5289
  newRealPath
4981
5290
  );
5291
+ docWithRef = object2;
5292
+ hasUpdate = updated || hasUpdate;
5293
+ }
5294
+ if (hasUpdate) {
5295
+ const collectionWithRef = this.tinaSchema.getCollectionByFullPath(pathToDocWithRef);
5296
+ if (!collectionWithRef) {
5297
+ throw new Error(
5298
+ `Unable to find collection for ${pathToDocWithRef}`
5299
+ );
5300
+ }
5301
+ await this.database.put(
5302
+ pathToDocWithRef,
5303
+ docWithRef,
5304
+ collectionWithRef.name
5305
+ );
4982
5306
  }
4983
- await this.database.put(refPath, refDoc, collection2);
4984
5307
  }
4985
5308
  }
4986
5309
  return this.getDocument(newRealPath);
4987
5310
  }
4988
5311
  if (alreadyExists === false) {
4989
- throw new Error(`Unable to update document, ${realPath} does not exist`);
5312
+ throw new Error(
5313
+ `Unable to update document, ${realPath} does not exist`
5314
+ );
4990
5315
  }
4991
5316
  return this.updateResolveDocument({
4992
5317
  collection,
@@ -5036,6 +5361,7 @@ var Resolver = class {
5036
5361
  },
5037
5362
  collection: referencedCollection,
5038
5363
  hydrator: (path7) => path7
5364
+ // just return the path
5039
5365
  }
5040
5366
  );
5041
5367
  const { edges } = resolvedCollectionConnection;
@@ -5103,78 +5429,80 @@ var Resolver = class {
5103
5429
  }
5104
5430
  };
5105
5431
  };
5432
+ /**
5433
+ * Checks if a document has references to it
5434
+ * @param id The id of the document to check for references
5435
+ * @param c The collection to check for references
5436
+ * @returns true if the document has references, false otherwise
5437
+ */
5106
5438
  this.hasReferences = async (id, c) => {
5107
5439
  let count = 0;
5108
- const deepRefs = this.tinaSchema.findReferences(c.name);
5109
- for (const [collection, refs] of Object.entries(deepRefs)) {
5110
- for (const ref of refs) {
5111
- await this.database.query(
5112
- {
5113
- collection,
5114
- filterChain: makeFilterChain({
5115
- conditions: [
5116
- {
5117
- filterPath: ref.path.join("."),
5118
- filterExpression: {
5119
- _type: "reference",
5120
- _list: false,
5121
- eq: id
5122
- }
5123
- }
5124
- ]
5125
- }),
5126
- sort: ref.field.name
5127
- },
5128
- (refId) => {
5129
- count++;
5130
- return refId;
5131
- }
5132
- );
5133
- if (count) {
5134
- return true;
5135
- }
5440
+ await this.database.query(
5441
+ {
5442
+ collection: c.name,
5443
+ filterChain: makeFilterChain({
5444
+ conditions: [
5445
+ {
5446
+ filterPath: REFS_REFERENCE_FIELD,
5447
+ filterExpression: {
5448
+ _type: "string",
5449
+ _list: false,
5450
+ eq: id
5451
+ }
5452
+ }
5453
+ ]
5454
+ }),
5455
+ sort: REFS_COLLECTIONS_SORT_KEY
5456
+ },
5457
+ (refId) => {
5458
+ count++;
5459
+ return refId;
5136
5460
  }
5461
+ );
5462
+ if (count) {
5463
+ return true;
5137
5464
  }
5138
5465
  return false;
5139
5466
  };
5467
+ /**
5468
+ * Finds references to a document
5469
+ * @param id the id of the document to find references to
5470
+ * @param c the collection to find references in
5471
+ * @returns a map of references to the document
5472
+ */
5140
5473
  this.findReferences = async (id, c) => {
5141
5474
  const references = {};
5142
- const deepRefs = this.tinaSchema.findReferences(c.name);
5143
- for (const [collection, refs] of Object.entries(deepRefs)) {
5144
- for (const ref of refs) {
5145
- await this.database.query(
5146
- {
5147
- collection,
5148
- filterChain: makeFilterChain({
5149
- conditions: [
5150
- {
5151
- filterPath: ref.path.join("."),
5152
- filterExpression: {
5153
- _type: "reference",
5154
- _list: false,
5155
- eq: id
5156
- }
5157
- }
5158
- ]
5159
- }),
5160
- sort: ref.field.name
5161
- },
5162
- (refId) => {
5163
- if (!references[collection]) {
5164
- references[collection] = {};
5165
- }
5166
- if (!references[collection][refId]) {
5167
- references[collection][refId] = [];
5475
+ await this.database.query(
5476
+ {
5477
+ collection: c.name,
5478
+ filterChain: makeFilterChain({
5479
+ conditions: [
5480
+ {
5481
+ filterPath: REFS_REFERENCE_FIELD,
5482
+ filterExpression: {
5483
+ _type: "string",
5484
+ _list: false,
5485
+ eq: id
5486
+ }
5168
5487
  }
5169
- references[collection][refId].push({
5170
- path: ref.path,
5171
- field: ref.field
5172
- });
5173
- return refId;
5174
- }
5175
- );
5488
+ ]
5489
+ }),
5490
+ sort: REFS_COLLECTIONS_SORT_KEY
5491
+ },
5492
+ (refId, rawItem) => {
5493
+ if (!references[c.name]) {
5494
+ references[c.name] = {};
5495
+ }
5496
+ if (!references[c.name][refId]) {
5497
+ references[c.name][refId] = [];
5498
+ }
5499
+ const referencePath = rawItem?.[REFS_PATH_FIELD];
5500
+ if (referencePath) {
5501
+ references[c.name][refId].push(referencePath);
5502
+ }
5503
+ return refId;
5176
5504
  }
5177
- }
5505
+ );
5178
5506
  return references;
5179
5507
  };
5180
5508
  this.buildFieldMutations = async (fieldParams, template, existingData) => {
@@ -5244,7 +5572,7 @@ var Resolver = class {
5244
5572
  }
5245
5573
  break;
5246
5574
  case "rich-text":
5247
- accum[fieldName] = stringifyMDX(
5575
+ accum[fieldName] = serializeMDX(
5248
5576
  fieldValue,
5249
5577
  field,
5250
5578
  (fieldValue2) => resolveMediaCloudToRelative(
@@ -5263,6 +5591,27 @@ var Resolver = class {
5263
5591
  }
5264
5592
  return accum;
5265
5593
  };
5594
+ /**
5595
+ * A mutation looks nearly identical between updateDocument:
5596
+ * ```graphql
5597
+ * updateDocument(collection: $collection,relativePath: $path, params: {
5598
+ * post: {
5599
+ * title: "Hello, World"
5600
+ * }
5601
+ * })`
5602
+ * ```
5603
+ * and `updatePostDocument`:
5604
+ * ```graphql
5605
+ * updatePostDocument(relativePath: $path, params: {
5606
+ * title: "Hello, World"
5607
+ * })
5608
+ * ```
5609
+ * The problem here is that we don't know whether the payload came from `updateDocument`
5610
+ * or `updatePostDocument` (we could, but for now it's easier not to pipe those details through),
5611
+ * But we do know that when given a `args.collection` value, we can assume that
5612
+ * this was a `updateDocument` request, and thus - should grab the data
5613
+ * from the corresponding field name in the key
5614
+ */
5266
5615
  this.buildParams = (args) => {
5267
5616
  try {
5268
5617
  assertShape(
@@ -5362,7 +5711,10 @@ var resolve = async ({
5362
5711
  const graphQLSchema = buildASTSchema(graphQLSchemaAst);
5363
5712
  const tinaConfig = await database.getTinaSchema();
5364
5713
  const tinaSchema = await createSchema({
5714
+ // TODO: please update all the types to import from @tinacms/schema-tools
5715
+ // @ts-ignore
5365
5716
  schema: tinaConfig,
5717
+ // @ts-ignore
5366
5718
  flags: tinaConfig?.meta?.flags
5367
5719
  });
5368
5720
  const resolver = createResolver({
@@ -5379,8 +5731,7 @@ var resolve = async ({
5379
5731
  database
5380
5732
  },
5381
5733
  typeResolver: async (source, _args, info) => {
5382
- if (source.__typename)
5383
- return source.__typename;
5734
+ if (source.__typename) return source.__typename;
5384
5735
  const namedType = getNamedType(info.returnType).toString();
5385
5736
  const lookup = await database.getLookup(namedType);
5386
5737
  if (lookup.resolveType === "unionData") {
@@ -5529,11 +5880,13 @@ var resolve = async ({
5529
5880
  set(
5530
5881
  params,
5531
5882
  userField.path.slice(1),
5883
+ // remove _rawData from users path
5532
5884
  users.map((u) => {
5533
5885
  if (user[idFieldName] === u[idFieldName]) {
5534
5886
  return user;
5535
5887
  }
5536
5888
  return {
5889
+ // don't overwrite other users' passwords
5537
5890
  ...u,
5538
5891
  [passwordFieldName]: {
5539
5892
  ...u[passwordFieldName],
@@ -5556,6 +5909,9 @@ var resolve = async ({
5556
5909
  }
5557
5910
  const isCreation = lookup[info.fieldName] === "create";
5558
5911
  switch (lookup.resolveType) {
5912
+ /**
5913
+ * `node(id: $id)`
5914
+ */
5559
5915
  case "nodeDocument":
5560
5916
  assertShape(
5561
5917
  args,
@@ -5587,6 +5943,7 @@ var resolve = async ({
5587
5943
  collection: args.collection,
5588
5944
  isMutation,
5589
5945
  isCreation,
5946
+ // Right now this is the only case for deletion
5590
5947
  isDeletion: info.fieldName === "deleteDocument",
5591
5948
  isFolderCreation: info.fieldName === "createFolder",
5592
5949
  isUpdateName: Boolean(args?.params?.relativePath),
@@ -5596,6 +5953,9 @@ var resolve = async ({
5596
5953
  return result;
5597
5954
  }
5598
5955
  return value;
5956
+ /**
5957
+ * eg `getMovieDocument.data.actors`
5958
+ */
5599
5959
  case "multiCollectionDocumentList":
5600
5960
  if (Array.isArray(value)) {
5601
5961
  return {
@@ -5607,7 +5967,15 @@ var resolve = async ({
5607
5967
  }
5608
5968
  if (info.fieldName === "documents" && value?.collection && value?.hasDocuments) {
5609
5969
  let filter = args.filter;
5610
- if (typeof args?.filter !== "undefined" && args?.filter !== null && typeof value?.collection?.name === "string" && Object.keys(args.filter).includes(value?.collection?.name) && typeof args.filter[value?.collection?.name] !== "undefined") {
5970
+ if (
5971
+ // 1. Make sure that the filter exists
5972
+ typeof args?.filter !== "undefined" && args?.filter !== null && // 2. Make sure that the collection name exists
5973
+ // @ts-ignore
5974
+ typeof value?.collection?.name === "string" && // 3. Make sure that the collection name is in the filter and is not undefined
5975
+ // @ts-ignore
5976
+ Object.keys(args.filter).includes(value?.collection?.name) && // @ts-ignore
5977
+ typeof args.filter[value?.collection?.name] !== "undefined"
5978
+ ) {
5611
5979
  filter = args.filter[value.collection.name];
5612
5980
  }
5613
5981
  return resolver.resolveCollectionConnection({
@@ -5615,12 +5983,20 @@ var resolve = async ({
5615
5983
  ...args,
5616
5984
  filter
5617
5985
  },
5986
+ // @ts-ignore
5618
5987
  collection: value.collection
5619
5988
  });
5620
5989
  }
5621
5990
  throw new Error(
5622
5991
  `Expected an array for result of ${info.fieldName} at ${info.path}`
5623
5992
  );
5993
+ /**
5994
+ * Collections-specific getter
5995
+ * eg. `getPostDocument`/`createPostDocument`/`updatePostDocument`
5996
+ *
5997
+ * if coming from a query result
5998
+ * the field will be `node`
5999
+ */
5624
6000
  case "collectionDocument": {
5625
6001
  if (value) {
5626
6002
  return value;
@@ -5635,11 +6011,32 @@ var resolve = async ({
5635
6011
  });
5636
6012
  return result;
5637
6013
  }
6014
+ /**
6015
+ * Collections-specific list getter
6016
+ * eg. `getPageList`
6017
+ */
5638
6018
  case "collectionDocumentList":
5639
6019
  return resolver.resolveCollectionConnection({
5640
6020
  args,
5641
6021
  collection: tinaSchema.getCollection(lookup.collection)
5642
6022
  });
6023
+ /**
6024
+ * A polymorphic data set, it can be from a document's data
6025
+ * of any nested object which can be one of many shapes
6026
+ *
6027
+ * ```graphql
6028
+ * getPostDocument(relativePath: $relativePath) {
6029
+ * data {...} <- this part
6030
+ * }
6031
+ * ```
6032
+ * ```graphql
6033
+ * getBlockDocument(relativePath: $relativePath) {
6034
+ * data {
6035
+ * blocks {...} <- or this part
6036
+ * }
6037
+ * }
6038
+ * ```
6039
+ */
5643
6040
  case "unionData":
5644
6041
  if (!value) {
5645
6042
  if (args.relativePath) {
@@ -5704,8 +6101,7 @@ var TinaLevelClient = class extends ManyLevelGuest {
5704
6101
  this.port = port || 9e3;
5705
6102
  }
5706
6103
  openConnection() {
5707
- if (this._connected)
5708
- return;
6104
+ if (this._connected) return;
5709
6105
  const socket = connect(this.port);
5710
6106
  pipeline(socket, this.createRpcStream(), socket, () => {
5711
6107
  this._connected = false;
@@ -5715,7 +6111,7 @@ var TinaLevelClient = class extends ManyLevelGuest {
5715
6111
  };
5716
6112
 
5717
6113
  // src/database/index.ts
5718
- import path4 from "path";
6114
+ import path4 from "node:path";
5719
6115
  import { GraphQLError as GraphQLError5 } from "graphql";
5720
6116
  import micromatch2 from "micromatch";
5721
6117
  import sha2 from "js-sha1";
@@ -5850,6 +6246,7 @@ var Database = class {
5850
6246
  );
5851
6247
  const indexDefinitions = await this.getIndexDefinitions(this.contentLevel);
5852
6248
  const collectionIndexDefinitions = indexDefinitions?.[collection.name];
6249
+ const collectionReferences = (await this.getCollectionReferences())?.[collection.name];
5853
6250
  const normalizedPath = normalizePath(filepath);
5854
6251
  if (!collection?.isDetached) {
5855
6252
  if (this.bridge) {
@@ -5878,6 +6275,14 @@ var Database = class {
5878
6275
  let delOps = [];
5879
6276
  if (!isGitKeep(normalizedPath, collection)) {
5880
6277
  putOps = [
6278
+ ...makeRefOpsForDocument(
6279
+ normalizedPath,
6280
+ collection?.name,
6281
+ collectionReferences,
6282
+ dataFields,
6283
+ "put",
6284
+ level
6285
+ ),
5881
6286
  ...makeIndexOpsForDocument(
5882
6287
  normalizedPath,
5883
6288
  collection?.name,
@@ -5886,6 +6291,7 @@ var Database = class {
5886
6291
  "put",
5887
6292
  level
5888
6293
  ),
6294
+ // folder indices
5889
6295
  ...makeIndexOpsForDocument(
5890
6296
  normalizedPath,
5891
6297
  `${collection?.name}_${folderKey}`,
@@ -5900,6 +6306,14 @@ var Database = class {
5900
6306
  SUBLEVEL_OPTIONS
5901
6307
  ).get(normalizedPath);
5902
6308
  delOps = existingItem ? [
6309
+ ...makeRefOpsForDocument(
6310
+ normalizedPath,
6311
+ collection?.name,
6312
+ collectionReferences,
6313
+ existingItem,
6314
+ "del",
6315
+ level
6316
+ ),
5903
6317
  ...makeIndexOpsForDocument(
5904
6318
  normalizedPath,
5905
6319
  collection?.name,
@@ -5908,6 +6322,7 @@ var Database = class {
5908
6322
  "del",
5909
6323
  level
5910
6324
  ),
6325
+ // folder indices
5911
6326
  ...makeIndexOpsForDocument(
5912
6327
  normalizedPath,
5913
6328
  `${collection?.name}_${folderKey}`,
@@ -5946,6 +6361,7 @@ var Database = class {
5946
6361
  );
5947
6362
  collectionIndexDefinitions = indexDefinitions?.[collectionName];
5948
6363
  }
6364
+ const collectionReferences = (await this.getCollectionReferences())?.[collectionName];
5949
6365
  const normalizedPath = normalizePath(filepath);
5950
6366
  const dataFields = await this.formatBodyOnPayload(filepath, data);
5951
6367
  const collection = await this.collectionForPath(filepath);
@@ -5993,6 +6409,14 @@ var Database = class {
5993
6409
  let delOps = [];
5994
6410
  if (!isGitKeep(normalizedPath, collection)) {
5995
6411
  putOps = [
6412
+ ...makeRefOpsForDocument(
6413
+ normalizedPath,
6414
+ collectionName,
6415
+ collectionReferences,
6416
+ dataFields,
6417
+ "put",
6418
+ level
6419
+ ),
5996
6420
  ...makeIndexOpsForDocument(
5997
6421
  normalizedPath,
5998
6422
  collectionName,
@@ -6001,6 +6425,7 @@ var Database = class {
6001
6425
  "put",
6002
6426
  level
6003
6427
  ),
6428
+ // folder indices
6004
6429
  ...makeIndexOpsForDocument(
6005
6430
  normalizedPath,
6006
6431
  `${collection?.name}_${folderKey}`,
@@ -6015,6 +6440,14 @@ var Database = class {
6015
6440
  SUBLEVEL_OPTIONS
6016
6441
  ).get(normalizedPath);
6017
6442
  delOps = existingItem ? [
6443
+ ...makeRefOpsForDocument(
6444
+ normalizedPath,
6445
+ collectionName,
6446
+ collectionReferences,
6447
+ existingItem,
6448
+ "del",
6449
+ level
6450
+ ),
6018
6451
  ...makeIndexOpsForDocument(
6019
6452
  normalizedPath,
6020
6453
  collectionName,
@@ -6023,6 +6456,7 @@ var Database = class {
6023
6456
  "del",
6024
6457
  level
6025
6458
  ),
6459
+ // folder indices
6026
6460
  ...makeIndexOpsForDocument(
6027
6461
  normalizedPath,
6028
6462
  `${collection?.name}_${folderKey}`,
@@ -6100,6 +6534,7 @@ var Database = class {
6100
6534
  aliasedData,
6101
6535
  extension,
6102
6536
  writeTemplateKey,
6537
+ //templateInfo.type === 'union',
6103
6538
  {
6104
6539
  frontmatterFormat: collection?.frontmatterFormat,
6105
6540
  frontmatterDelimiters: collection?.frontmatterDelimiters
@@ -6138,6 +6573,7 @@ var Database = class {
6138
6573
  SUBLEVEL_OPTIONS
6139
6574
  ).get(graphqlPath);
6140
6575
  };
6576
+ //TODO - is there a reason why the database fetches some config with "bridge.get", and some with "store.get"?
6141
6577
  this.getGraphQLSchemaFromBridge = async () => {
6142
6578
  if (!this.bridge) {
6143
6579
  throw new Error(`No bridge configured`);
@@ -6174,6 +6610,22 @@ var Database = class {
6174
6610
  this.tinaSchema = await createSchema({ schema });
6175
6611
  return this.tinaSchema;
6176
6612
  };
6613
+ this.getCollectionReferences = async (level) => {
6614
+ if (this.collectionReferences) {
6615
+ return this.collectionReferences;
6616
+ }
6617
+ const result = {};
6618
+ const schema = await this.getSchema(level || this.contentLevel);
6619
+ const collections = schema.getCollections();
6620
+ for (const collection of collections) {
6621
+ const collectionReferences = this.tinaSchema.findReferencesFromCollection(
6622
+ collection.name
6623
+ );
6624
+ result[collection.name] = collectionReferences;
6625
+ }
6626
+ this.collectionReferences = result;
6627
+ return result;
6628
+ };
6177
6629
  this.getIndexDefinitions = async (level) => {
6178
6630
  if (!this.collectionIndexDefinitions) {
6179
6631
  await new Promise(async (resolve2, reject) => {
@@ -6183,10 +6635,53 @@ var Database = class {
6183
6635
  const collections = schema.getCollections();
6184
6636
  for (const collection of collections) {
6185
6637
  const indexDefinitions = {
6186
- [DEFAULT_COLLECTION_SORT_KEY]: { fields: [] }
6638
+ [DEFAULT_COLLECTION_SORT_KEY]: { fields: [] },
6639
+ // provide a default sort key which is the file sort
6640
+ // pseudo-index for the collection's references
6641
+ [REFS_COLLECTIONS_SORT_KEY]: {
6642
+ fields: [
6643
+ {
6644
+ name: REFS_REFERENCE_FIELD,
6645
+ type: "string",
6646
+ list: false
6647
+ },
6648
+ {
6649
+ name: REFS_PATH_FIELD,
6650
+ type: "string",
6651
+ list: false
6652
+ }
6653
+ ]
6654
+ }
6187
6655
  };
6188
- if (collection.fields) {
6189
- for (const field of collection.fields) {
6656
+ let fields = [];
6657
+ if (collection.templates) {
6658
+ const templateFieldMap = {};
6659
+ const conflictedFields = /* @__PURE__ */ new Set();
6660
+ for (const template of collection.templates) {
6661
+ for (const field of template.fields) {
6662
+ if (!templateFieldMap[field.name]) {
6663
+ templateFieldMap[field.name] = field;
6664
+ } else {
6665
+ if (templateFieldMap[field.name].type !== field.type) {
6666
+ console.warn(
6667
+ `Field ${field.name} has conflicting types in templates - skipping index`
6668
+ );
6669
+ conflictedFields.add(field.name);
6670
+ }
6671
+ }
6672
+ }
6673
+ }
6674
+ for (const conflictedField in conflictedFields) {
6675
+ delete templateFieldMap[conflictedField];
6676
+ }
6677
+ for (const field of Object.values(templateFieldMap)) {
6678
+ fields.push(field);
6679
+ }
6680
+ } else if (collection.fields) {
6681
+ fields = collection.fields;
6682
+ }
6683
+ if (fields) {
6684
+ for (const field of fields) {
6190
6685
  if (field.indexed !== void 0 && field.indexed === false || field.type === "object") {
6191
6686
  continue;
6192
6687
  }
@@ -6334,29 +6829,36 @@ var Database = class {
6334
6829
  }
6335
6830
  startKey = startKey || key || "";
6336
6831
  endKey = key || "";
6337
- edges = [...edges, { cursor: key, path: filepath }];
6832
+ edges = [...edges, { cursor: key, path: filepath, value: itemRecord }];
6338
6833
  }
6339
6834
  return {
6340
- edges: await sequential(edges, async (edge) => {
6341
- try {
6342
- const node = await hydrator(edge.path);
6343
- return {
6344
- node,
6345
- cursor: btoa(edge.cursor)
6346
- };
6347
- } catch (error) {
6348
- console.log(error);
6349
- if (error instanceof Error && (!edge.path.includes(".tina/__generated__/_graphql.json") || !edge.path.includes("tina/__generated__/_graphql.json"))) {
6350
- throw new TinaQueryError({
6351
- originalError: error,
6352
- file: edge.path,
6353
- collection: collection.name,
6354
- stack: error.stack
6355
- });
6835
+ edges: await sequential(
6836
+ edges,
6837
+ async ({
6838
+ cursor,
6839
+ path: path7,
6840
+ value
6841
+ }) => {
6842
+ try {
6843
+ const node = await hydrator(path7, value);
6844
+ return {
6845
+ node,
6846
+ cursor: btoa(cursor)
6847
+ };
6848
+ } catch (error) {
6849
+ console.log(error);
6850
+ if (error instanceof Error && (!path7.includes(".tina/__generated__/_graphql.json") || !path7.includes("tina/__generated__/_graphql.json"))) {
6851
+ throw new TinaQueryError({
6852
+ originalError: error,
6853
+ file: path7,
6854
+ collection: collection.name,
6855
+ stack: error.stack
6856
+ });
6857
+ }
6858
+ throw error;
6356
6859
  }
6357
- throw error;
6358
6860
  }
6359
- }),
6861
+ ),
6360
6862
  pageInfo: {
6361
6863
  hasPreviousPage,
6362
6864
  hasNextPage,
@@ -6480,13 +6982,14 @@ var Database = class {
6480
6982
  documentPaths,
6481
6983
  async (collection, documentPaths2) => {
6482
6984
  if (collection && !collection.isDetached) {
6483
- await _indexContent(
6484
- this,
6485
- this.contentLevel,
6486
- documentPaths2,
6985
+ await _indexContent({
6986
+ database: this,
6987
+ level: this.contentLevel,
6988
+ documentPaths: documentPaths2,
6487
6989
  enqueueOps,
6488
- collection
6489
- );
6990
+ collection,
6991
+ isPartialReindex: true
6992
+ });
6490
6993
  }
6491
6994
  }
6492
6995
  );
@@ -6502,17 +7005,18 @@ var Database = class {
6502
7005
  throw new Error(`No collection found for path: ${filepath}`);
6503
7006
  }
6504
7007
  const indexDefinitions = await this.getIndexDefinitions(this.contentLevel);
7008
+ const collectionReferences = (await this.getCollectionReferences())?.[collection.name];
6505
7009
  const collectionIndexDefinitions = indexDefinitions?.[collection.name];
6506
7010
  let level = this.contentLevel;
6507
7011
  if (collection?.isDetached) {
6508
7012
  level = this.appLevel.sublevel(collection?.name, SUBLEVEL_OPTIONS);
6509
7013
  }
6510
- const itemKey = normalizePath(filepath);
7014
+ const normalizedPath = normalizePath(filepath);
6511
7015
  const rootSublevel = level.sublevel(
6512
7016
  CONTENT_ROOT_PREFIX,
6513
7017
  SUBLEVEL_OPTIONS
6514
7018
  );
6515
- const item = await rootSublevel.get(itemKey);
7019
+ const item = await rootSublevel.get(normalizedPath);
6516
7020
  if (item) {
6517
7021
  const folderTreeBuilder = new FolderTreeBuilder();
6518
7022
  const folderKey = folderTreeBuilder.update(
@@ -6520,16 +7024,25 @@ var Database = class {
6520
7024
  collection.path || ""
6521
7025
  );
6522
7026
  await this.contentLevel.batch([
7027
+ ...makeRefOpsForDocument(
7028
+ normalizedPath,
7029
+ collection.name,
7030
+ collectionReferences,
7031
+ item,
7032
+ "del",
7033
+ level
7034
+ ),
6523
7035
  ...makeIndexOpsForDocument(
6524
- filepath,
7036
+ normalizedPath,
6525
7037
  collection.name,
6526
7038
  collectionIndexDefinitions,
6527
7039
  item,
6528
7040
  "del",
6529
7041
  level
6530
7042
  ),
7043
+ // folder indices
6531
7044
  ...makeIndexOpsForDocument(
6532
- filepath,
7045
+ normalizedPath,
6533
7046
  `${collection.name}_${folderKey}`,
6534
7047
  collectionIndexDefinitions,
6535
7048
  item,
@@ -6538,17 +7051,17 @@ var Database = class {
6538
7051
  ),
6539
7052
  {
6540
7053
  type: "del",
6541
- key: itemKey,
7054
+ key: normalizedPath,
6542
7055
  sublevel: rootSublevel
6543
7056
  }
6544
7057
  ]);
6545
7058
  }
6546
7059
  if (!collection?.isDetached) {
6547
7060
  if (this.bridge) {
6548
- await this.bridge.delete(normalizePath(filepath));
7061
+ await this.bridge.delete(normalizedPath);
6549
7062
  }
6550
7063
  try {
6551
- await this.onDelete(normalizePath(filepath));
7064
+ await this.onDelete(normalizedPath);
6552
7065
  } catch (e) {
6553
7066
  throw new GraphQLError5(
6554
7067
  `Error running onDelete hook for ${filepath}: ${e}`,
@@ -6583,20 +7096,26 @@ var Database = class {
6583
7096
  );
6584
7097
  const doc = await level2.keys({ limit: 1 }).next();
6585
7098
  if (!doc) {
6586
- await _indexContent(
6587
- this,
6588
- level2,
6589
- contentPaths,
7099
+ await _indexContent({
7100
+ database: this,
7101
+ level: level2,
7102
+ documentPaths: contentPaths,
6590
7103
  enqueueOps,
6591
7104
  collection,
6592
- userFields.map((field) => [
7105
+ passwordFields: userFields.map((field) => [
6593
7106
  ...field.path,
6594
7107
  field.passwordFieldName
6595
7108
  ])
6596
- );
7109
+ });
6597
7110
  }
6598
7111
  } else {
6599
- await _indexContent(this, level, contentPaths, enqueueOps, collection);
7112
+ await _indexContent({
7113
+ database: this,
7114
+ level,
7115
+ documentPaths: contentPaths,
7116
+ enqueueOps,
7117
+ collection
7118
+ });
6600
7119
  }
6601
7120
  }
6602
7121
  );
@@ -6682,6 +7201,9 @@ var Database = class {
6682
7201
  info: templateInfo
6683
7202
  };
6684
7203
  }
7204
+ /**
7205
+ * Clears the internal cache of the tinaSchema and the lookup file. This allows the state to be reset
7206
+ */
6685
7207
  clearCache() {
6686
7208
  this.tinaSchema = null;
6687
7209
  this._lookup = null;
@@ -6732,7 +7254,15 @@ var hashPasswordValues = async (data, passwordFields) => Promise.all(
6732
7254
  )
6733
7255
  );
6734
7256
  var isGitKeep = (filepath, collection) => filepath.endsWith(`.gitkeep.${collection?.format || "md"}`);
6735
- var _indexContent = async (database, level, documentPaths, enqueueOps, collection, passwordFields) => {
7257
+ var _indexContent = async ({
7258
+ database,
7259
+ level,
7260
+ documentPaths,
7261
+ enqueueOps,
7262
+ collection,
7263
+ passwordFields,
7264
+ isPartialReindex
7265
+ }) => {
6736
7266
  let collectionIndexDefinitions;
6737
7267
  let collectionPath;
6738
7268
  if (collection) {
@@ -6743,6 +7273,7 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6743
7273
  }
6744
7274
  collectionPath = collection.path;
6745
7275
  }
7276
+ const collectionReferences = (await database.getCollectionReferences())?.[collection?.name];
6746
7277
  const tinaSchema = await database.getSchema();
6747
7278
  let templateInfo = null;
6748
7279
  if (collection) {
@@ -6764,12 +7295,61 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6764
7295
  await hashPasswordValues(aliasedData, passwordFields);
6765
7296
  }
6766
7297
  const normalizedPath = normalizePath(filepath);
7298
+ const rootSublevel = level.sublevel(
7299
+ CONTENT_ROOT_PREFIX,
7300
+ SUBLEVEL_OPTIONS
7301
+ );
6767
7302
  const folderKey = folderTreeBuilder.update(
6768
7303
  normalizedPath,
6769
7304
  collectionPath || ""
6770
7305
  );
7306
+ if (isPartialReindex) {
7307
+ const item = await rootSublevel.get(normalizedPath);
7308
+ if (item) {
7309
+ await database.contentLevel.batch([
7310
+ ...makeRefOpsForDocument(
7311
+ normalizedPath,
7312
+ collection?.name,
7313
+ collectionReferences,
7314
+ item,
7315
+ "del",
7316
+ level
7317
+ ),
7318
+ ...makeIndexOpsForDocument(
7319
+ normalizedPath,
7320
+ collection.name,
7321
+ collectionIndexDefinitions,
7322
+ item,
7323
+ "del",
7324
+ level
7325
+ ),
7326
+ // folder indices
7327
+ ...makeIndexOpsForDocument(
7328
+ normalizedPath,
7329
+ `${collection.name}_${folderKey}`,
7330
+ collectionIndexDefinitions,
7331
+ item,
7332
+ "del",
7333
+ level
7334
+ ),
7335
+ {
7336
+ type: "del",
7337
+ key: normalizedPath,
7338
+ sublevel: rootSublevel
7339
+ }
7340
+ ]);
7341
+ }
7342
+ }
6771
7343
  if (!isGitKeep(filepath, collection)) {
6772
7344
  await enqueueOps([
7345
+ ...makeRefOpsForDocument(
7346
+ normalizedPath,
7347
+ collection?.name,
7348
+ collectionReferences,
7349
+ aliasedData,
7350
+ "put",
7351
+ level
7352
+ ),
6773
7353
  ...makeIndexOpsForDocument(
6774
7354
  normalizedPath,
6775
7355
  collection?.name,
@@ -6778,6 +7358,7 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6778
7358
  "put",
6779
7359
  level
6780
7360
  ),
7361
+ // folder indexes
6781
7362
  ...makeIndexOpsForDocument(
6782
7363
  normalizedPath,
6783
7364
  `${collection?.name}_${folderKey}`,
@@ -6832,6 +7413,7 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6832
7413
  throw new Error(`No indexDefinitions for collection ${collection.name}`);
6833
7414
  }
6834
7415
  }
7416
+ const collectionReferences = (await database.getCollectionReferences())?.[collection?.name];
6835
7417
  const tinaSchema = await database.getSchema();
6836
7418
  let templateInfo = null;
6837
7419
  if (collection) {
@@ -6855,6 +7437,14 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6855
7437
  item
6856
7438
  ) : item;
6857
7439
  await enqueueOps([
7440
+ ...makeRefOpsForDocument(
7441
+ itemKey,
7442
+ collection?.name,
7443
+ collectionReferences,
7444
+ aliasedData,
7445
+ "del",
7446
+ database.contentLevel
7447
+ ),
6858
7448
  ...makeIndexOpsForDocument(
6859
7449
  itemKey,
6860
7450
  collection.name,
@@ -6863,6 +7453,7 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6863
7453
  "del",
6864
7454
  database.contentLevel
6865
7455
  ),
7456
+ // folder indexes
6866
7457
  ...makeIndexOpsForDocument(
6867
7458
  itemKey,
6868
7459
  `${collection?.name}_${folderKey}`,
@@ -6983,8 +7574,8 @@ import path6 from "path";
6983
7574
  import normalize from "normalize-path";
6984
7575
  var FilesystemBridge = class {
6985
7576
  constructor(rootPath, outputPath) {
6986
- this.rootPath = rootPath || "";
6987
- this.outputPath = outputPath || rootPath;
7577
+ this.rootPath = path6.resolve(rootPath);
7578
+ this.outputPath = outputPath ? path6.resolve(outputPath) : this.rootPath;
6988
7579
  }
6989
7580
  async glob(pattern, extension) {
6990
7581
  const basePath = path6.join(this.outputPath, ...pattern.split("/"));
@@ -6996,19 +7587,19 @@ var FilesystemBridge = class {
6996
7587
  }
6997
7588
  );
6998
7589
  const posixRootPath = normalize(this.outputPath);
6999
- return items.map((item) => {
7000
- return item.replace(posixRootPath, "").replace(/^\/|\/$/g, "");
7001
- });
7590
+ return items.map(
7591
+ (item) => item.substring(posixRootPath.length).replace(/^\/|\/$/g, "")
7592
+ );
7002
7593
  }
7003
7594
  async delete(filepath) {
7004
7595
  await fs2.remove(path6.join(this.outputPath, filepath));
7005
7596
  }
7006
7597
  async get(filepath) {
7007
- return fs2.readFileSync(path6.join(this.outputPath, filepath)).toString();
7598
+ return (await fs2.readFile(path6.join(this.outputPath, filepath))).toString();
7008
7599
  }
7009
7600
  async put(filepath, data, basePathOverride) {
7010
7601
  const basePath = basePathOverride || this.outputPath;
7011
- await fs2.outputFileSync(path6.join(basePath, filepath), data);
7602
+ await fs2.outputFile(path6.join(basePath, filepath), data);
7012
7603
  }
7013
7604
  };
7014
7605
  var AuditFileSystemBridge = class extends FilesystemBridge {
@@ -7078,17 +7669,26 @@ var IsomorphicBridge = class {
7078
7669
  getAuthor() {
7079
7670
  return {
7080
7671
  ...this.author,
7081
- timestamp: Math.round(new Date().getTime() / 1e3),
7672
+ timestamp: Math.round((/* @__PURE__ */ new Date()).getTime() / 1e3),
7082
7673
  timezoneOffset: 0
7083
7674
  };
7084
7675
  }
7085
7676
  getCommitter() {
7086
7677
  return {
7087
7678
  ...this.committer,
7088
- timestamp: Math.round(new Date().getTime() / 1e3),
7679
+ timestamp: Math.round((/* @__PURE__ */ new Date()).getTime() / 1e3),
7089
7680
  timezoneOffset: 0
7090
7681
  };
7091
7682
  }
7683
+ /**
7684
+ * Recursively populate paths matching `pattern` for the given `entry`
7685
+ *
7686
+ * @param pattern - pattern to filter paths by
7687
+ * @param entry - TreeEntry to start building list from
7688
+ * @param path - base path
7689
+ * @param results
7690
+ * @private
7691
+ */
7092
7692
  async listEntries({
7093
7693
  pattern,
7094
7694
  entry,
@@ -7121,6 +7721,15 @@ var IsomorphicBridge = class {
7121
7721
  });
7122
7722
  }
7123
7723
  }
7724
+ /**
7725
+ * For the specified path, returns an object with an array containing the parts of the path (pathParts)
7726
+ * and an array containing the WalkerEntry objects for the path parts (pathEntries). Any null elements in the
7727
+ * pathEntries are placeholders for non-existent entries.
7728
+ *
7729
+ * @param path - path being resolved
7730
+ * @param ref - ref to resolve path entries for
7731
+ * @private
7732
+ */
7124
7733
  async resolvePathEntries(path7, ref) {
7125
7734
  let pathParts = path7.split("/");
7126
7735
  const result = await git2.walk({
@@ -7151,6 +7760,17 @@ var IsomorphicBridge = class {
7151
7760
  }
7152
7761
  return { pathParts, pathEntries };
7153
7762
  }
7763
+ /**
7764
+ * Updates tree entry and associated parent tree entries
7765
+ *
7766
+ * @param existingOid - the existing OID
7767
+ * @param updatedOid - the updated OID
7768
+ * @param path - the path of the entry being updated
7769
+ * @param type - the type of the entry being updated (blob or tree)
7770
+ * @param pathEntries - parent path entries
7771
+ * @param pathParts - parent path parts
7772
+ * @private
7773
+ */
7154
7774
  async updateTreeHierarchy(existingOid, updatedOid, path7, type, pathEntries, pathParts) {
7155
7775
  const lastIdx = pathEntries.length - 1;
7156
7776
  const parentEntry = pathEntries[lastIdx];
@@ -7206,6 +7826,13 @@ var IsomorphicBridge = class {
7206
7826
  );
7207
7827
  }
7208
7828
  }
7829
+ /**
7830
+ * Creates a commit for the specified tree and updates the specified ref to point to the commit
7831
+ *
7832
+ * @param treeSha - sha of the new tree
7833
+ * @param ref - the ref that should be updated
7834
+ * @private
7835
+ */
7209
7836
  async commitTree(treeSha, ref) {
7210
7837
  const commitSha = await git2.writeCommit({
7211
7838
  ...this.isomorphicConfig,
@@ -7218,6 +7845,7 @@ var IsomorphicBridge = class {
7218
7845
  })
7219
7846
  ],
7220
7847
  message: this.commitMessage,
7848
+ // TODO these should be configurable
7221
7849
  author: this.getAuthor(),
7222
7850
  committer: this.getCommitter()
7223
7851
  }
@@ -7455,5 +8083,5 @@ export {
7455
8083
  transformDocument,
7456
8084
  transformDocumentIntoPayload
7457
8085
  };
7458
- //! Replaces _.flattenDeep()
7459
8086
  //! Replaces _.get()
8087
+ //! Replaces _.flattenDeep()