@tinacms/graphql 0.0.0-bc59a81-20241030011355 → 0.0.0-bdc07c1-20250506013835

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: {
@@ -86,6 +95,15 @@ var SysFieldDefinition = {
86
95
  arguments: [],
87
96
  directives: []
88
97
  },
98
+ {
99
+ kind: "Field",
100
+ name: {
101
+ kind: "Name",
102
+ value: "hasReferences"
103
+ },
104
+ arguments: [],
105
+ directives: []
106
+ },
89
107
  {
90
108
  kind: "Field",
91
109
  name: {
@@ -126,6 +144,10 @@ var SysFieldDefinition = {
126
144
  }
127
145
  };
128
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
+ */
129
151
  FormFieldBuilder: ({
130
152
  name,
131
153
  additionalFields
@@ -349,6 +371,8 @@ var astBuilder = {
349
371
  kind: "Name",
350
372
  value: name
351
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
352
376
  fields
353
377
  }),
354
378
  UnionTypeDefinition: ({
@@ -361,6 +385,8 @@ var astBuilder = {
361
385
  value: name
362
386
  },
363
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
364
390
  types: types.map((name2) => ({
365
391
  kind: "NamedType",
366
392
  name: {
@@ -457,8 +483,11 @@ var astBuilder = {
457
483
  string: "String",
458
484
  boolean: "Boolean",
459
485
  number: "Float",
486
+ // FIXME - needs to be float or int
460
487
  datetime: "String",
488
+ // FIXME
461
489
  image: "String",
490
+ // FIXME
462
491
  text: "String"
463
492
  };
464
493
  return scalars[type];
@@ -957,8 +986,7 @@ var astBuilder = {
957
986
  }
958
987
  };
959
988
  var capitalize = (s) => {
960
- if (typeof s !== "string")
961
- return "";
989
+ if (typeof s !== "string") return "";
962
990
  return s.charAt(0).toUpperCase() + s.slice(1);
963
991
  };
964
992
  var extractInlineTypes = (item) => {
@@ -1001,41 +1029,6 @@ function* walk(maybeNode, visited = /* @__PURE__ */ new WeakSet()) {
1001
1029
  yield maybeNode;
1002
1030
  visited.add(maybeNode);
1003
1031
  }
1004
- function addNamespaceToSchema(maybeNode, namespace = []) {
1005
- if (typeof maybeNode === "string") {
1006
- return maybeNode;
1007
- }
1008
- if (typeof maybeNode === "boolean") {
1009
- return maybeNode;
1010
- }
1011
- const newNode = maybeNode;
1012
- const keys = Object.keys(maybeNode);
1013
- Object.values(maybeNode).map((m, index) => {
1014
- const key = keys[index];
1015
- if (Array.isArray(m)) {
1016
- newNode[key] = m.map((element) => {
1017
- if (!element) {
1018
- return;
1019
- }
1020
- if (!element.hasOwnProperty("name")) {
1021
- return element;
1022
- }
1023
- const value = element.name || element.value;
1024
- return addNamespaceToSchema(element, [...namespace, value]);
1025
- });
1026
- } else {
1027
- if (!m) {
1028
- return;
1029
- }
1030
- if (!m.hasOwnProperty("name")) {
1031
- newNode[key] = m;
1032
- } else {
1033
- newNode[key] = addNamespaceToSchema(m, [...namespace, m.name]);
1034
- }
1035
- }
1036
- });
1037
- return { ...newNode, namespace };
1038
- }
1039
1032
  var generateNamespacedFieldName = (names, suffix = "") => {
1040
1033
  return (suffix ? [...names, suffix] : names).map(capitalize).join("");
1041
1034
  };
@@ -1195,6 +1188,11 @@ var scalarDefinitions = [
1195
1188
  required: true,
1196
1189
  type: astBuilder.TYPES.String
1197
1190
  }),
1191
+ astBuilder.FieldDefinition({
1192
+ name: "hasReferences",
1193
+ required: false,
1194
+ type: astBuilder.TYPES.Boolean
1195
+ }),
1198
1196
  astBuilder.FieldDefinition({
1199
1197
  name: "breadcrumbs",
1200
1198
  required: true,
@@ -1408,6 +1406,19 @@ var Builder = class {
1408
1406
  this.addToLookupMap = (lookup) => {
1409
1407
  this.lookupMap[lookup.type] = lookup;
1410
1408
  };
1409
+ /**
1410
+ * ```graphql
1411
+ * # ex.
1412
+ * {
1413
+ * getCollection(collection: $collection) {
1414
+ * name
1415
+ * documents {...}
1416
+ * }
1417
+ * }
1418
+ * ```
1419
+ *
1420
+ * @param collections
1421
+ */
1411
1422
  this.buildCollectionDefinition = async (collections) => {
1412
1423
  const name = "collection";
1413
1424
  const typeName = "Collection";
@@ -1478,6 +1489,19 @@ var Builder = class {
1478
1489
  required: true
1479
1490
  });
1480
1491
  };
1492
+ /**
1493
+ * ```graphql
1494
+ * # ex.
1495
+ * {
1496
+ * getCollections {
1497
+ * name
1498
+ * documents {...}
1499
+ * }
1500
+ * }
1501
+ * ```
1502
+ *
1503
+ * @param collections
1504
+ */
1481
1505
  this.buildMultiCollectionDefinition = async (collections) => {
1482
1506
  const name = "collections";
1483
1507
  const typeName = "Collection";
@@ -1488,6 +1512,17 @@ var Builder = class {
1488
1512
  required: true
1489
1513
  });
1490
1514
  };
1515
+ /**
1516
+ * ```graphql
1517
+ * # ex.
1518
+ * {
1519
+ * node(id: $id) {
1520
+ * id
1521
+ * data {...}
1522
+ * }
1523
+ * }
1524
+ * ```
1525
+ */
1491
1526
  this.multiNodeDocument = async () => {
1492
1527
  const name = "node";
1493
1528
  const args = [
@@ -1508,6 +1543,19 @@ var Builder = class {
1508
1543
  required: true
1509
1544
  });
1510
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
+ */
1511
1559
  this.multiCollectionDocument = async (collections) => {
1512
1560
  const name = "document";
1513
1561
  const args = [
@@ -1533,6 +1581,19 @@ var Builder = class {
1533
1581
  required: true
1534
1582
  });
1535
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
+ */
1536
1597
  this.addMultiCollectionDocumentMutation = async () => {
1537
1598
  return astBuilder.FieldDefinition({
1538
1599
  name: "addPendingDocument",
@@ -1557,6 +1618,19 @@ var Builder = class {
1557
1618
  type: astBuilder.TYPES.MultiCollectionDocument
1558
1619
  });
1559
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
+ */
1560
1634
  this.buildCreateCollectionDocumentMutation = async (collections) => {
1561
1635
  return astBuilder.FieldDefinition({
1562
1636
  name: "createDocument",
@@ -1584,6 +1658,19 @@ var Builder = class {
1584
1658
  type: astBuilder.TYPES.MultiCollectionDocument
1585
1659
  });
1586
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
+ */
1587
1674
  this.buildUpdateCollectionDocumentMutation = async (collections) => {
1588
1675
  return astBuilder.FieldDefinition({
1589
1676
  name: "updateDocument",
@@ -1611,6 +1698,19 @@ var Builder = class {
1611
1698
  type: astBuilder.TYPES.MultiCollectionDocument
1612
1699
  });
1613
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
+ */
1614
1714
  this.buildDeleteCollectionDocumentMutation = async (collections) => {
1615
1715
  return astBuilder.FieldDefinition({
1616
1716
  name: "deleteDocument",
@@ -1630,6 +1730,19 @@ var Builder = class {
1630
1730
  type: astBuilder.TYPES.MultiCollectionDocument
1631
1731
  });
1632
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
+ */
1633
1746
  this.buildCreateCollectionFolderMutation = async () => {
1634
1747
  return astBuilder.FieldDefinition({
1635
1748
  name: "createFolder",
@@ -1649,6 +1762,19 @@ var Builder = class {
1649
1762
  type: astBuilder.TYPES.MultiCollectionDocument
1650
1763
  });
1651
1764
  };
1765
+ /**
1766
+ * ```graphql
1767
+ * # ex.
1768
+ * {
1769
+ * getPostDocument(relativePath: $relativePath) {
1770
+ * id
1771
+ * data {...}
1772
+ * }
1773
+ * }
1774
+ * ```
1775
+ *
1776
+ * @param collection
1777
+ */
1652
1778
  this.collectionDocument = async (collection) => {
1653
1779
  const name = NAMER.queryName([collection.name]);
1654
1780
  const type = await this._buildCollectionDocumentType(collection);
@@ -1709,6 +1835,20 @@ var Builder = class {
1709
1835
  const args = [];
1710
1836
  return astBuilder.FieldDefinition({ type, name, args, required: false });
1711
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
+ */
1712
1852
  this.collectionFragment = async (collection) => {
1713
1853
  const name = NAMER.dataTypeName(collection.namespace);
1714
1854
  const fragmentName = NAMER.fragmentName(collection.namespace);
@@ -1722,6 +1862,20 @@ var Builder = class {
1722
1862
  selections: filterSelections(selections)
1723
1863
  });
1724
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
+ * */
1725
1879
  this._getCollectionFragmentSelections = async (collection, depth) => {
1726
1880
  const selections = [];
1727
1881
  selections.push({
@@ -1803,9 +1957,9 @@ var Builder = class {
1803
1957
  ]
1804
1958
  });
1805
1959
  }
1960
+ // TODO: Should we throw here?
1806
1961
  case "reference":
1807
- if (depth >= this.maxDepth)
1808
- return false;
1962
+ if (depth >= this.maxDepth) return false;
1809
1963
  if (!("collections" in field)) {
1810
1964
  return false;
1811
1965
  }
@@ -1837,6 +1991,7 @@ var Builder = class {
1837
1991
  name: field.name,
1838
1992
  selections: [
1839
1993
  ...selections,
1994
+ // This is ... on Document { id }
1840
1995
  {
1841
1996
  kind: "InlineFragment",
1842
1997
  typeCondition: {
@@ -1867,6 +2022,19 @@ var Builder = class {
1867
2022
  });
1868
2023
  }
1869
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
+ */
1870
2038
  this.updateCollectionDocumentMutation = async (collection) => {
1871
2039
  return astBuilder.FieldDefinition({
1872
2040
  type: await this._buildCollectionDocumentType(collection),
@@ -1886,6 +2054,19 @@ var Builder = class {
1886
2054
  ]
1887
2055
  });
1888
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
+ */
1889
2070
  this.createCollectionDocumentMutation = async (collection) => {
1890
2071
  return astBuilder.FieldDefinition({
1891
2072
  type: await this._buildCollectionDocumentType(collection),
@@ -1905,6 +2086,22 @@ var Builder = class {
1905
2086
  ]
1906
2087
  });
1907
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
+ */
1908
2105
  this.collectionDocumentList = async (collection) => {
1909
2106
  const connectionName = NAMER.referenceConnectionType(collection.namespace);
1910
2107
  this.addToLookupMap({
@@ -1920,6 +2117,10 @@ var Builder = class {
1920
2117
  collection
1921
2118
  });
1922
2119
  };
2120
+ /**
2121
+ * GraphQL type definitions which remain unchanged regardless
2122
+ * of the supplied Tina schema. Ex. "node" interface
2123
+ */
1923
2124
  this.buildStaticDefinitions = () => staticDefinitions;
1924
2125
  this._buildCollectionDocumentType = async (collection, suffix = "", extraFields = [], extraInterfaces = []) => {
1925
2126
  const documentTypeName = NAMER.documentTypeName(collection.namespace);
@@ -2424,6 +2625,7 @@ var Builder = class {
2424
2625
  name: NAMER.dataFilterTypeName(namespace),
2425
2626
  fields: await sequential(collections, async (collection2) => {
2426
2627
  return astBuilder.InputValueDefinition({
2628
+ // @ts-ignore
2427
2629
  name: collection2.name,
2428
2630
  type: NAMER.dataFilterTypeName(collection2.namespace)
2429
2631
  });
@@ -2612,7 +2814,8 @@ Visit https://tina.io/docs/errors/ui-not-supported/ for more information
2612
2814
  ]
2613
2815
  });
2614
2816
  };
2615
- this.maxDepth = config?.tinaSchema.schema?.config?.client?.referenceDepth ?? 2;
2817
+ this.maxDepth = // @ts-ignore
2818
+ config?.tinaSchema.schema?.config?.client?.referenceDepth ?? 2;
2616
2819
  this.tinaSchema = config.tinaSchema;
2617
2820
  this.lookupMap = {};
2618
2821
  }
@@ -2623,8 +2826,7 @@ Visit https://tina.io/docs/errors/ui-not-supported/ for more information
2623
2826
  selections.push(field);
2624
2827
  });
2625
2828
  const filteredSelections = filterSelections(selections);
2626
- if (!filteredSelections.length)
2627
- return false;
2829
+ if (!filteredSelections.length) return false;
2628
2830
  return astBuilder.InlineFragmentDefinition({
2629
2831
  selections: filteredSelections,
2630
2832
  name: NAMER.dataTypeName(template.namespace)
@@ -2661,6 +2863,7 @@ var filterSelections = (arr) => {
2661
2863
  import { TinaSchema } from "@tinacms/schema-tools";
2662
2864
 
2663
2865
  // src/schema/validate.ts
2866
+ import { addNamespaceToSchema } from "@tinacms/schema-tools";
2664
2867
  import deepClone from "lodash.clonedeep";
2665
2868
  import * as yup2 from "yup";
2666
2869
  import {
@@ -2707,6 +2910,7 @@ var validationCollectionsPathAndMatch = (collections) => {
2707
2910
  }).map((x) => `${x.path}${x.format || "md"}`);
2708
2911
  if (noMatchCollections.length !== new Set(noMatchCollections).size) {
2709
2912
  throw new Error(
2913
+ // TODO: add a link to the docs
2710
2914
  "Two collections without match can not have the same `path`. Please make the `path` unique or add a matches property to the collection."
2711
2915
  );
2712
2916
  }
@@ -2815,7 +3019,7 @@ var validateField = async (field) => {
2815
3019
  // package.json
2816
3020
  var package_default = {
2817
3021
  name: "@tinacms/graphql",
2818
- version: "1.5.6",
3022
+ version: "1.5.16",
2819
3023
  main: "dist/index.js",
2820
3024
  module: "dist/index.mjs",
2821
3025
  typings: "dist/index.d.ts",
@@ -2842,8 +3046,8 @@ var package_default = {
2842
3046
  build: "tinacms-scripts build",
2843
3047
  docs: "pnpm typedoc",
2844
3048
  serve: "pnpm nodemon dist/server.js",
2845
- test: "jest",
2846
- "test-watch": "jest --watch"
3049
+ test: "vitest run",
3050
+ "test-watch": "vitest"
2847
3051
  },
2848
3052
  dependencies: {
2849
3053
  "@iarna/toml": "^2.2.5",
@@ -2851,25 +3055,28 @@ var package_default = {
2851
3055
  "@tinacms/schema-tools": "workspace:*",
2852
3056
  "abstract-level": "^1.0.4",
2853
3057
  "date-fns": "^2.30.0",
2854
- "fast-glob": "^3.3.2",
2855
- "fs-extra": "^11.2.0",
3058
+ "fast-glob": "^3.3.3",
3059
+ "fs-extra": "^11.3.0",
2856
3060
  "glob-parent": "^6.0.2",
2857
3061
  graphql: "15.8.0",
2858
3062
  "gray-matter": "^4.0.3",
2859
- "isomorphic-git": "^1.27.1",
3063
+ "isomorphic-git": "^1.29.0",
2860
3064
  "js-sha1": "^0.6.0",
2861
3065
  "js-yaml": "^3.14.1",
2862
- "jsonpath-plus": "^6.0.1",
3066
+ "jsonpath-plus": "10.1.0",
2863
3067
  "lodash.clonedeep": "^4.5.0",
2864
3068
  "lodash.set": "^4.3.2",
2865
3069
  "lodash.uniqby": "^4.7.0",
2866
3070
  "many-level": "^2.0.0",
2867
3071
  micromatch: "4.0.8",
2868
3072
  "normalize-path": "^3.0.0",
2869
- "readable-stream": "^4.5.2",
3073
+ "readable-stream": "^4.7.0",
2870
3074
  scmp: "^2.1.0",
2871
3075
  yup: "^0.32.11"
2872
3076
  },
3077
+ peerDependencies: {
3078
+ "@tinacms/common": "workspace:*"
3079
+ },
2873
3080
  publishConfig: {
2874
3081
  registry: "https://registry.npmjs.org"
2875
3082
  },
@@ -2884,24 +3091,23 @@ var package_default = {
2884
3091
  "@types/estree": "^0.0.50",
2885
3092
  "@types/express": "^4.17.21",
2886
3093
  "@types/fs-extra": "^9.0.13",
2887
- "@types/jest": "^26.0.24",
2888
3094
  "@types/js-yaml": "^3.12.10",
2889
3095
  "@types/lodash.camelcase": "^4.3.9",
2890
3096
  "@types/lodash.upperfirst": "^4.3.9",
2891
3097
  "@types/lru-cache": "^5.1.1",
2892
3098
  "@types/mdast": "^3.0.15",
2893
3099
  "@types/micromatch": "^4.0.9",
2894
- "@types/node": "^22.7.4",
3100
+ "@types/node": "^22.13.1",
2895
3101
  "@types/normalize-path": "^3.0.2",
2896
3102
  "@types/ws": "^7.4.7",
2897
3103
  "@types/yup": "^0.29.14",
2898
- jest: "^29.7.0",
2899
- "jest-diff": "^29.7.0",
2900
3104
  "jest-file-snapshot": "^0.5.0",
2901
- "jest-matcher-utils": "^29.7.0",
2902
3105
  "memory-level": "^1.0.0",
2903
3106
  nodemon: "3.1.4",
2904
- typescript: "^5.6.2"
3107
+ typescript: "^5.7.3",
3108
+ vite: "^4.5.9",
3109
+ vitest: "^0.32.4",
3110
+ zod: "^3.24.2"
2905
3111
  }
2906
3112
  };
2907
3113
 
@@ -2972,6 +3178,7 @@ var _buildFragments = async (builder, tinaSchema) => {
2972
3178
  const fragDoc = {
2973
3179
  kind: "Document",
2974
3180
  definitions: uniqBy2(
3181
+ // @ts-ignore
2975
3182
  extractInlineTypes(fragmentDefinitionsFields),
2976
3183
  (node) => node.name.value
2977
3184
  )
@@ -2994,6 +3201,7 @@ var _buildQueries = async (builder, tinaSchema) => {
2994
3201
  fragName,
2995
3202
  queryName: queryListName,
2996
3203
  filterType: queryFilterTypeName,
3204
+ // look for flag to see if the data layer is enabled
2997
3205
  dataLayer: Boolean(
2998
3206
  tinaSchema.config?.meta?.flags?.find((x) => x === "experimentalData")
2999
3207
  )
@@ -3003,6 +3211,7 @@ var _buildQueries = async (builder, tinaSchema) => {
3003
3211
  const queryDoc = {
3004
3212
  kind: "Document",
3005
3213
  definitions: uniqBy2(
3214
+ // @ts-ignore
3006
3215
  extractInlineTypes(operationsDefinitions),
3007
3216
  (node) => node.name.value
3008
3217
  )
@@ -3054,7 +3263,9 @@ var _buildSchema = async (builder, tinaSchema) => {
3054
3263
  await builder.buildCreateCollectionFolderMutation()
3055
3264
  );
3056
3265
  await sequential(collections, async (collection) => {
3057
- queryTypeDefinitionFields.push(await builder.collectionDocument(collection));
3266
+ queryTypeDefinitionFields.push(
3267
+ await builder.collectionDocument(collection)
3268
+ );
3058
3269
  if (collection.isAuthCollection) {
3059
3270
  queryTypeDefinitionFields.push(
3060
3271
  await builder.authenticationCollectionDocument(collection)
@@ -3091,6 +3302,7 @@ var _buildSchema = async (builder, tinaSchema) => {
3091
3302
  return {
3092
3303
  kind: "Document",
3093
3304
  definitions: uniqBy2(
3305
+ // @ts-ignore
3094
3306
  extractInlineTypes(definitions),
3095
3307
  (node) => node.name.value
3096
3308
  )
@@ -3107,6 +3319,9 @@ import isValid from "date-fns/isValid/index.js";
3107
3319
  // src/mdx/index.ts
3108
3320
  import { parseMDX, stringifyMDX } from "@tinacms/mdx";
3109
3321
 
3322
+ // src/resolver/index.ts
3323
+ import { JSONPath as JSONPath2 } from "jsonpath-plus";
3324
+
3110
3325
  // src/resolver/error.ts
3111
3326
  var TinaGraphQLError = class extends Error {
3112
3327
  constructor(message, extensions) {
@@ -3292,8 +3507,7 @@ var resolveMediaCloudToRelative = (value, config = { useRelativeMedia: true }, s
3292
3507
  }
3293
3508
  if (Array.isArray(value)) {
3294
3509
  return value.map((v) => {
3295
- if (!v || typeof v !== "string")
3296
- return v;
3510
+ if (!v || typeof v !== "string") return v;
3297
3511
  const cleanMediaRoot = cleanUpSlashes(
3298
3512
  schema.config.media.tina.mediaRoot
3299
3513
  );
@@ -3321,8 +3535,7 @@ var resolveMediaRelativeToCloud = (value, config = { useRelativeMedia: true }, s
3321
3535
  }
3322
3536
  if (Array.isArray(value)) {
3323
3537
  return value.map((v) => {
3324
- if (!v || typeof v !== "string")
3325
- return v;
3538
+ if (!v || typeof v !== "string") return v;
3326
3539
  const strippedValue = v.replace(cleanMediaRoot, "");
3327
3540
  return `https://${config.assetsHost}/${config.clientId}${strippedValue}`;
3328
3541
  });
@@ -3340,8 +3553,7 @@ var cleanUpSlashes = (path7) => {
3340
3553
  return "";
3341
3554
  };
3342
3555
  var hasTinaMediaConfig = (schema) => {
3343
- if (!schema.config?.media?.tina)
3344
- return false;
3556
+ if (!schema.config?.media?.tina) return false;
3345
3557
  if (typeof schema.config?.media?.tina?.publicFolder !== "string" && typeof schema.config?.media?.tina?.mediaRoot !== "string")
3346
3558
  return false;
3347
3559
  return true;
@@ -3368,7 +3580,9 @@ var LevelProxyHandler = {
3368
3580
  throw new Error(`The property, ${property.toString()}, doesn't exist`);
3369
3581
  }
3370
3582
  if (typeof target[property] !== "function") {
3371
- throw new Error(`The property, ${property.toString()}, is not a function`);
3583
+ throw new Error(
3584
+ `The property, ${property.toString()}, is not a function`
3585
+ );
3372
3586
  }
3373
3587
  if (property === "get") {
3374
3588
  return async (...args) => {
@@ -3385,6 +3599,7 @@ var LevelProxyHandler = {
3385
3599
  } else if (property === "sublevel") {
3386
3600
  return (...args) => {
3387
3601
  return new Proxy(
3602
+ // eslint-disable-next-line prefer-spread
3388
3603
  target[property].apply(target, args),
3389
3604
  LevelProxyHandler
3390
3605
  );
@@ -3752,6 +3967,9 @@ var loadAndParseWithAliases = async (bridge, filepath, collection, templateInfo)
3752
3967
 
3753
3968
  // src/database/datalayer.ts
3754
3969
  var DEFAULT_COLLECTION_SORT_KEY = "__filepath__";
3970
+ var REFS_COLLECTIONS_SORT_KEY = "__refs__";
3971
+ var REFS_REFERENCE_FIELD = "__tina_ref__";
3972
+ var REFS_PATH_FIELD = "__tina_ref_path__";
3755
3973
  var DEFAULT_NUMERIC_LPAD = 4;
3756
3974
  var applyPadding = (input, pad) => {
3757
3975
  if (pad) {
@@ -4261,6 +4479,7 @@ var makeFolderOpsForCollection = (folderTree, collection, indexDefinitions, opTy
4261
4479
  result.push({
4262
4480
  type: opType,
4263
4481
  key: `${collection.path}/${subFolderKey}.${collection.format}`,
4482
+ // replace the root with the collection path
4264
4483
  sublevel: indexSublevel,
4265
4484
  value: {}
4266
4485
  });
@@ -4324,6 +4543,57 @@ var makeIndexOpsForDocument = (filepath, collection, indexDefinitions, data, opT
4324
4543
  }
4325
4544
  return result;
4326
4545
  };
4546
+ var makeRefOpsForDocument = (filepath, collection, references, data, opType, level) => {
4547
+ const result = [];
4548
+ if (collection) {
4549
+ for (const [c, referencePaths] of Object.entries(references || {})) {
4550
+ if (!referencePaths.length) {
4551
+ continue;
4552
+ }
4553
+ const collectionSublevel = level.sublevel(c, SUBLEVEL_OPTIONS);
4554
+ const refSublevel = collectionSublevel.sublevel(
4555
+ REFS_COLLECTIONS_SORT_KEY,
4556
+ SUBLEVEL_OPTIONS
4557
+ );
4558
+ const references2 = {};
4559
+ for (const path7 of referencePaths) {
4560
+ const ref = JSONPath({ path: path7, json: data });
4561
+ if (!ref) {
4562
+ continue;
4563
+ }
4564
+ if (Array.isArray(ref)) {
4565
+ for (const r of ref) {
4566
+ if (!r) {
4567
+ continue;
4568
+ }
4569
+ if (references2[r]) {
4570
+ references2[r].push(path7);
4571
+ } else {
4572
+ references2[r] = [path7];
4573
+ }
4574
+ }
4575
+ } else {
4576
+ if (references2[ref]) {
4577
+ references2[ref].push(path7);
4578
+ } else {
4579
+ references2[ref] = [path7];
4580
+ }
4581
+ }
4582
+ }
4583
+ for (const ref of Object.keys(references2)) {
4584
+ for (const path7 of references2[ref]) {
4585
+ result.push({
4586
+ type: opType,
4587
+ key: `${ref}${INDEX_KEY_FIELD_SEPARATOR}${path7}${INDEX_KEY_FIELD_SEPARATOR}${filepath}`,
4588
+ sublevel: refSublevel,
4589
+ value: opType === "put" ? {} : void 0
4590
+ });
4591
+ }
4592
+ }
4593
+ }
4594
+ }
4595
+ return result;
4596
+ };
4327
4597
  var makeStringEscaper = (regex, replacement) => {
4328
4598
  return (input) => {
4329
4599
  if (Array.isArray(input)) {
@@ -4375,6 +4645,7 @@ var resolveFieldData = async ({ namespace, ...field }, rawData, accumulator, tin
4375
4645
  case "password":
4376
4646
  accumulator[field.name] = {
4377
4647
  value: void 0,
4648
+ // never resolve the password hash
4378
4649
  passwordChangeRequired: value["passwordChangeRequired"] ?? false
4379
4650
  };
4380
4651
  break;
@@ -4469,7 +4740,7 @@ var resolveFieldData = async ({ namespace, ...field }, rawData, accumulator, tin
4469
4740
  }
4470
4741
  return accumulator;
4471
4742
  };
4472
- var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config, isAudit) => {
4743
+ var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config, isAudit, hasReferences) => {
4473
4744
  const collection = tinaSchema.getCollection(rawData._collection);
4474
4745
  try {
4475
4746
  const template = tinaSchema.getTemplateForData({
@@ -4523,6 +4794,7 @@ var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config,
4523
4794
  basename,
4524
4795
  filename,
4525
4796
  extension,
4797
+ hasReferences,
4526
4798
  path: fullPath,
4527
4799
  relativePath,
4528
4800
  breadcrumbs,
@@ -4542,6 +4814,34 @@ var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config,
4542
4814
  throw e;
4543
4815
  }
4544
4816
  };
4817
+ var updateObjectWithJsonPath = (obj, path7, oldValue, newValue) => {
4818
+ let updated = false;
4819
+ if (!path7.includes(".") && !path7.includes("[")) {
4820
+ if (path7 in obj && obj[path7] === oldValue) {
4821
+ obj[path7] = newValue;
4822
+ updated = true;
4823
+ }
4824
+ return { object: obj, updated };
4825
+ }
4826
+ const parentPath = path7.replace(/\.[^.\[\]]+$/, "");
4827
+ const keyToUpdate = path7.match(/[^.\[\]]+$/)[0];
4828
+ const parents = JSONPath2({
4829
+ path: parentPath,
4830
+ json: obj,
4831
+ resultType: "value"
4832
+ });
4833
+ if (parents.length > 0) {
4834
+ parents.forEach((parent) => {
4835
+ if (parent && typeof parent === "object" && keyToUpdate in parent) {
4836
+ if (parent[keyToUpdate] === oldValue) {
4837
+ parent[keyToUpdate] = newValue;
4838
+ updated = true;
4839
+ }
4840
+ }
4841
+ });
4842
+ }
4843
+ return { object: obj, updated };
4844
+ };
4545
4845
  var Resolver = class {
4546
4846
  constructor(init) {
4547
4847
  this.init = init;
@@ -4549,6 +4849,7 @@ var Resolver = class {
4549
4849
  const collection = this.tinaSchema.getCollection(collectionName);
4550
4850
  const extraFields = {};
4551
4851
  return {
4852
+ // return the collection and hasDocuments to resolve documents at a lower level
4552
4853
  documents: { collection, hasDocuments },
4553
4854
  ...collection,
4554
4855
  ...extraFields
@@ -4556,7 +4857,9 @@ var Resolver = class {
4556
4857
  };
4557
4858
  this.getRaw = async (fullPath) => {
4558
4859
  if (typeof fullPath !== "string") {
4559
- throw new Error(`fullPath must be of type string for getDocument request`);
4860
+ throw new Error(
4861
+ `fullPath must be of type string for getDocument request`
4862
+ );
4560
4863
  }
4561
4864
  return this.database.get(fullPath);
4562
4865
  };
@@ -4583,22 +4886,28 @@ var Resolver = class {
4583
4886
  );
4584
4887
  }
4585
4888
  };
4586
- this.getDocument = async (fullPath) => {
4889
+ this.getDocument = async (fullPath, opts = {}) => {
4587
4890
  if (typeof fullPath !== "string") {
4588
- throw new Error(`fullPath must be of type string for getDocument request`);
4891
+ throw new Error(
4892
+ `fullPath must be of type string for getDocument request`
4893
+ );
4589
4894
  }
4590
4895
  const rawData = await this.getRaw(fullPath);
4896
+ const hasReferences = opts?.checkReferences ? await this.hasReferences(fullPath, opts.collection) : void 0;
4591
4897
  return transformDocumentIntoPayload(
4592
4898
  fullPath,
4593
4899
  rawData,
4594
4900
  this.tinaSchema,
4595
4901
  this.config,
4596
- this.isAudit
4902
+ this.isAudit,
4903
+ hasReferences
4597
4904
  );
4598
4905
  };
4599
4906
  this.deleteDocument = async (fullPath) => {
4600
4907
  if (typeof fullPath !== "string") {
4601
- throw new Error(`fullPath must be of type string for getDocument request`);
4908
+ throw new Error(
4909
+ `fullPath must be of type string for getDocument request`
4910
+ );
4602
4911
  }
4603
4912
  await this.database.delete(fullPath);
4604
4913
  };
@@ -4633,7 +4942,9 @@ var Resolver = class {
4633
4942
  );
4634
4943
  } else {
4635
4944
  return this.buildFieldMutations(
4945
+ // @ts-ignore FIXME Argument of type 'string | object' is not assignable to parameter of type '{ [fieldName: string]: string | object | (string | object)[]; }'
4636
4946
  fieldValue,
4947
+ //@ts-ignore
4637
4948
  objectTemplate,
4638
4949
  existingData
4639
4950
  );
@@ -4645,6 +4956,7 @@ var Resolver = class {
4645
4956
  fieldValue.map(async (item) => {
4646
4957
  if (typeof item === "string") {
4647
4958
  throw new Error(
4959
+ //@ts-ignore
4648
4960
  `Expected object for template value for field ${field.name}`
4649
4961
  );
4650
4962
  }
@@ -4653,16 +4965,19 @@ var Resolver = class {
4653
4965
  });
4654
4966
  const [templateName] = Object.entries(item)[0];
4655
4967
  const template = templates.find(
4968
+ //@ts-ignore
4656
4969
  (template2) => template2.name === templateName
4657
4970
  );
4658
4971
  if (!template) {
4659
4972
  throw new Error(`Expected to find template ${templateName}`);
4660
4973
  }
4661
4974
  return {
4975
+ // @ts-ignore FIXME Argument of type 'unknown' is not assignable to parameter of type '{ [fieldName: string]: string | { [key: string]: unknown; } | (string | { [key: string]: unknown; })[]; }'
4662
4976
  ...await this.buildFieldMutations(
4663
4977
  item[template.name],
4664
4978
  template
4665
4979
  ),
4980
+ //@ts-ignore
4666
4981
  _template: template.name
4667
4982
  };
4668
4983
  })
@@ -4670,6 +4985,7 @@ var Resolver = class {
4670
4985
  } else {
4671
4986
  if (typeof fieldValue === "string") {
4672
4987
  throw new Error(
4988
+ //@ts-ignore
4673
4989
  `Expected object for template value for field ${field.name}`
4674
4990
  );
4675
4991
  }
@@ -4678,16 +4994,19 @@ var Resolver = class {
4678
4994
  });
4679
4995
  const [templateName] = Object.entries(fieldValue)[0];
4680
4996
  const template = templates.find(
4997
+ //@ts-ignore
4681
4998
  (template2) => template2.name === templateName
4682
4999
  );
4683
5000
  if (!template) {
4684
5001
  throw new Error(`Expected to find template ${templateName}`);
4685
5002
  }
4686
5003
  return {
5004
+ // @ts-ignore FIXME Argument of type 'unknown' is not assignable to parameter of type '{ [fieldName: string]: string | { [key: string]: unknown; } | (string | { [key: string]: unknown; })[]; }'
4687
5005
  ...await this.buildFieldMutations(
4688
5006
  fieldValue[template.name],
4689
5007
  template
4690
5008
  ),
5009
+ //@ts-ignore
4691
5010
  _template: template.name
4692
5011
  };
4693
5012
  }
@@ -4727,6 +5046,7 @@ var Resolver = class {
4727
5046
  return this.getDocument(realPath);
4728
5047
  }
4729
5048
  const params = await this.buildObjectMutations(
5049
+ // @ts-ignore
4730
5050
  args.params[collection.name],
4731
5051
  collection
4732
5052
  );
@@ -4772,6 +5092,7 @@ var Resolver = class {
4772
5092
  const values = {
4773
5093
  ...oldDoc,
4774
5094
  ...await this.buildFieldMutations(
5095
+ // @ts-ignore FIXME: failing on unknown, which we don't need to know because it's recursive
4775
5096
  templateParams,
4776
5097
  template,
4777
5098
  doc?._rawData
@@ -4785,13 +5106,22 @@ var Resolver = class {
4785
5106
  return this.getDocument(realPath);
4786
5107
  }
4787
5108
  const params = await this.buildObjectMutations(
5109
+ //@ts-ignore
4788
5110
  isCollectionSpecific ? args.params : args.params[collection.name],
4789
5111
  collection,
4790
5112
  doc?._rawData
4791
5113
  );
4792
- await this.database.put(realPath, { ...oldDoc, ...params }, collection.name);
5114
+ await this.database.put(
5115
+ realPath,
5116
+ { ...oldDoc, ...params },
5117
+ collection.name
5118
+ );
4793
5119
  return this.getDocument(realPath);
4794
5120
  };
5121
+ /**
5122
+ * Returns top-level fields which are not defined in the collection, so their
5123
+ * values are not eliminated from Tina when new values are saved
5124
+ */
4795
5125
  this.resolveLegacyValues = (oldDoc, collection) => {
4796
5126
  const legacyValues = {};
4797
5127
  Object.entries(oldDoc).forEach(([key, value]) => {
@@ -4896,6 +5226,40 @@ var Resolver = class {
4896
5226
  if (isDeletion) {
4897
5227
  const doc = await this.getDocument(realPath);
4898
5228
  await this.deleteDocument(realPath);
5229
+ if (await this.hasReferences(realPath, collection)) {
5230
+ const collRefs = await this.findReferences(realPath, collection);
5231
+ for (const [collection2, docsWithRefs] of Object.entries(collRefs)) {
5232
+ for (const [pathToDocWithRef, referencePaths] of Object.entries(
5233
+ docsWithRefs
5234
+ )) {
5235
+ let refDoc = await this.getRaw(pathToDocWithRef);
5236
+ let hasUpdate = false;
5237
+ for (const path7 of referencePaths) {
5238
+ const { object: object2, updated } = updateObjectWithJsonPath(
5239
+ refDoc,
5240
+ path7,
5241
+ realPath,
5242
+ null
5243
+ );
5244
+ refDoc = object2;
5245
+ hasUpdate = updated || hasUpdate;
5246
+ }
5247
+ if (hasUpdate) {
5248
+ const collectionWithRef = this.tinaSchema.getCollectionByFullPath(pathToDocWithRef);
5249
+ if (!collectionWithRef) {
5250
+ throw new Error(
5251
+ `Unable to find collection for ${pathToDocWithRef}`
5252
+ );
5253
+ }
5254
+ await this.database.put(
5255
+ pathToDocWithRef,
5256
+ refDoc,
5257
+ collectionWithRef.name
5258
+ );
5259
+ }
5260
+ }
5261
+ }
5262
+ }
4899
5263
  return doc;
4900
5264
  }
4901
5265
  if (isUpdateName) {
@@ -4912,12 +5276,49 @@ var Resolver = class {
4912
5276
  collection?.path,
4913
5277
  args.params.relativePath
4914
5278
  );
5279
+ if (newRealPath === realPath) {
5280
+ return doc;
5281
+ }
4915
5282
  await this.database.put(newRealPath, doc._rawData, collection.name);
4916
5283
  await this.deleteDocument(realPath);
5284
+ const collRefs = await this.findReferences(realPath, collection);
5285
+ for (const [collection2, docsWithRefs] of Object.entries(collRefs)) {
5286
+ for (const [pathToDocWithRef, referencePaths] of Object.entries(
5287
+ docsWithRefs
5288
+ )) {
5289
+ let docWithRef = await this.getRaw(pathToDocWithRef);
5290
+ let hasUpdate = false;
5291
+ for (const path7 of referencePaths) {
5292
+ const { object: object2, updated } = updateObjectWithJsonPath(
5293
+ docWithRef,
5294
+ path7,
5295
+ realPath,
5296
+ newRealPath
5297
+ );
5298
+ docWithRef = object2;
5299
+ hasUpdate = updated || hasUpdate;
5300
+ }
5301
+ if (hasUpdate) {
5302
+ const collectionWithRef = this.tinaSchema.getCollectionByFullPath(pathToDocWithRef);
5303
+ if (!collectionWithRef) {
5304
+ throw new Error(
5305
+ `Unable to find collection for ${pathToDocWithRef}`
5306
+ );
5307
+ }
5308
+ await this.database.put(
5309
+ pathToDocWithRef,
5310
+ docWithRef,
5311
+ collectionWithRef.name
5312
+ );
5313
+ }
5314
+ }
5315
+ }
4917
5316
  return this.getDocument(newRealPath);
4918
5317
  }
4919
5318
  if (alreadyExists === false) {
4920
- throw new Error(`Unable to update document, ${realPath} does not exist`);
5319
+ throw new Error(
5320
+ `Unable to update document, ${realPath} does not exist`
5321
+ );
4921
5322
  }
4922
5323
  return this.updateResolveDocument({
4923
5324
  collection,
@@ -4927,7 +5328,10 @@ var Resolver = class {
4927
5328
  isCollectionSpecific
4928
5329
  });
4929
5330
  } else {
4930
- return this.getDocument(realPath);
5331
+ return this.getDocument(realPath, {
5332
+ collection,
5333
+ checkReferences: true
5334
+ });
4931
5335
  }
4932
5336
  };
4933
5337
  this.resolveCollectionConnections = async ({ ids }) => {
@@ -4964,6 +5368,7 @@ var Resolver = class {
4964
5368
  },
4965
5369
  collection: referencedCollection,
4966
5370
  hydrator: (path7) => path7
5371
+ // just return the path
4967
5372
  }
4968
5373
  );
4969
5374
  const { edges } = resolvedCollectionConnection;
@@ -5031,6 +5436,82 @@ var Resolver = class {
5031
5436
  }
5032
5437
  };
5033
5438
  };
5439
+ /**
5440
+ * Checks if a document has references to it
5441
+ * @param id The id of the document to check for references
5442
+ * @param c The collection to check for references
5443
+ * @returns true if the document has references, false otherwise
5444
+ */
5445
+ this.hasReferences = async (id, c) => {
5446
+ let count = 0;
5447
+ await this.database.query(
5448
+ {
5449
+ collection: c.name,
5450
+ filterChain: makeFilterChain({
5451
+ conditions: [
5452
+ {
5453
+ filterPath: REFS_REFERENCE_FIELD,
5454
+ filterExpression: {
5455
+ _type: "string",
5456
+ _list: false,
5457
+ eq: id
5458
+ }
5459
+ }
5460
+ ]
5461
+ }),
5462
+ sort: REFS_COLLECTIONS_SORT_KEY
5463
+ },
5464
+ (refId) => {
5465
+ count++;
5466
+ return refId;
5467
+ }
5468
+ );
5469
+ if (count) {
5470
+ return true;
5471
+ }
5472
+ return false;
5473
+ };
5474
+ /**
5475
+ * Finds references to a document
5476
+ * @param id the id of the document to find references to
5477
+ * @param c the collection to find references in
5478
+ * @returns a map of references to the document
5479
+ */
5480
+ this.findReferences = async (id, c) => {
5481
+ const references = {};
5482
+ await this.database.query(
5483
+ {
5484
+ collection: c.name,
5485
+ filterChain: makeFilterChain({
5486
+ conditions: [
5487
+ {
5488
+ filterPath: REFS_REFERENCE_FIELD,
5489
+ filterExpression: {
5490
+ _type: "string",
5491
+ _list: false,
5492
+ eq: id
5493
+ }
5494
+ }
5495
+ ]
5496
+ }),
5497
+ sort: REFS_COLLECTIONS_SORT_KEY
5498
+ },
5499
+ (refId, rawItem) => {
5500
+ if (!references[c.name]) {
5501
+ references[c.name] = {};
5502
+ }
5503
+ if (!references[c.name][refId]) {
5504
+ references[c.name][refId] = [];
5505
+ }
5506
+ const referencePath = rawItem?.[REFS_PATH_FIELD];
5507
+ if (referencePath) {
5508
+ references[c.name][refId].push(referencePath);
5509
+ }
5510
+ return refId;
5511
+ }
5512
+ );
5513
+ return references;
5514
+ };
5034
5515
  this.buildFieldMutations = async (fieldParams, template, existingData) => {
5035
5516
  const accum = {};
5036
5517
  for (const passwordField of template.fields.filter(
@@ -5117,6 +5598,27 @@ var Resolver = class {
5117
5598
  }
5118
5599
  return accum;
5119
5600
  };
5601
+ /**
5602
+ * A mutation looks nearly identical between updateDocument:
5603
+ * ```graphql
5604
+ * updateDocument(collection: $collection,relativePath: $path, params: {
5605
+ * post: {
5606
+ * title: "Hello, World"
5607
+ * }
5608
+ * })`
5609
+ * ```
5610
+ * and `updatePostDocument`:
5611
+ * ```graphql
5612
+ * updatePostDocument(relativePath: $path, params: {
5613
+ * title: "Hello, World"
5614
+ * })
5615
+ * ```
5616
+ * The problem here is that we don't know whether the payload came from `updateDocument`
5617
+ * or `updatePostDocument` (we could, but for now it's easier not to pipe those details through),
5618
+ * But we do know that when given a `args.collection` value, we can assume that
5619
+ * this was a `updateDocument` request, and thus - should grab the data
5620
+ * from the corresponding field name in the key
5621
+ */
5120
5622
  this.buildParams = (args) => {
5121
5623
  try {
5122
5624
  assertShape(
@@ -5216,7 +5718,10 @@ var resolve = async ({
5216
5718
  const graphQLSchema = buildASTSchema(graphQLSchemaAst);
5217
5719
  const tinaConfig = await database.getTinaSchema();
5218
5720
  const tinaSchema = await createSchema({
5721
+ // TODO: please update all the types to import from @tinacms/schema-tools
5722
+ // @ts-ignore
5219
5723
  schema: tinaConfig,
5724
+ // @ts-ignore
5220
5725
  flags: tinaConfig?.meta?.flags
5221
5726
  });
5222
5727
  const resolver = createResolver({
@@ -5233,8 +5738,7 @@ var resolve = async ({
5233
5738
  database
5234
5739
  },
5235
5740
  typeResolver: async (source, _args, info) => {
5236
- if (source.__typename)
5237
- return source.__typename;
5741
+ if (source.__typename) return source.__typename;
5238
5742
  const namedType = getNamedType(info.returnType).toString();
5239
5743
  const lookup = await database.getLookup(namedType);
5240
5744
  if (lookup.resolveType === "unionData") {
@@ -5383,11 +5887,13 @@ var resolve = async ({
5383
5887
  set(
5384
5888
  params,
5385
5889
  userField.path.slice(1),
5890
+ // remove _rawData from users path
5386
5891
  users.map((u) => {
5387
5892
  if (user[idFieldName] === u[idFieldName]) {
5388
5893
  return user;
5389
5894
  }
5390
5895
  return {
5896
+ // don't overwrite other users' passwords
5391
5897
  ...u,
5392
5898
  [passwordFieldName]: {
5393
5899
  ...u[passwordFieldName],
@@ -5410,6 +5916,9 @@ var resolve = async ({
5410
5916
  }
5411
5917
  const isCreation = lookup[info.fieldName] === "create";
5412
5918
  switch (lookup.resolveType) {
5919
+ /**
5920
+ * `node(id: $id)`
5921
+ */
5413
5922
  case "nodeDocument":
5414
5923
  assertShape(
5415
5924
  args,
@@ -5441,6 +5950,7 @@ var resolve = async ({
5441
5950
  collection: args.collection,
5442
5951
  isMutation,
5443
5952
  isCreation,
5953
+ // Right now this is the only case for deletion
5444
5954
  isDeletion: info.fieldName === "deleteDocument",
5445
5955
  isFolderCreation: info.fieldName === "createFolder",
5446
5956
  isUpdateName: Boolean(args?.params?.relativePath),
@@ -5450,6 +5960,9 @@ var resolve = async ({
5450
5960
  return result;
5451
5961
  }
5452
5962
  return value;
5963
+ /**
5964
+ * eg `getMovieDocument.data.actors`
5965
+ */
5453
5966
  case "multiCollectionDocumentList":
5454
5967
  if (Array.isArray(value)) {
5455
5968
  return {
@@ -5461,7 +5974,15 @@ var resolve = async ({
5461
5974
  }
5462
5975
  if (info.fieldName === "documents" && value?.collection && value?.hasDocuments) {
5463
5976
  let filter = args.filter;
5464
- 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") {
5977
+ if (
5978
+ // 1. Make sure that the filter exists
5979
+ typeof args?.filter !== "undefined" && args?.filter !== null && // 2. Make sure that the collection name exists
5980
+ // @ts-ignore
5981
+ typeof value?.collection?.name === "string" && // 3. Make sure that the collection name is in the filter and is not undefined
5982
+ // @ts-ignore
5983
+ Object.keys(args.filter).includes(value?.collection?.name) && // @ts-ignore
5984
+ typeof args.filter[value?.collection?.name] !== "undefined"
5985
+ ) {
5465
5986
  filter = args.filter[value.collection.name];
5466
5987
  }
5467
5988
  return resolver.resolveCollectionConnection({
@@ -5469,12 +5990,20 @@ var resolve = async ({
5469
5990
  ...args,
5470
5991
  filter
5471
5992
  },
5993
+ // @ts-ignore
5472
5994
  collection: value.collection
5473
5995
  });
5474
5996
  }
5475
5997
  throw new Error(
5476
5998
  `Expected an array for result of ${info.fieldName} at ${info.path}`
5477
5999
  );
6000
+ /**
6001
+ * Collections-specific getter
6002
+ * eg. `getPostDocument`/`createPostDocument`/`updatePostDocument`
6003
+ *
6004
+ * if coming from a query result
6005
+ * the field will be `node`
6006
+ */
5478
6007
  case "collectionDocument": {
5479
6008
  if (value) {
5480
6009
  return value;
@@ -5489,11 +6018,32 @@ var resolve = async ({
5489
6018
  });
5490
6019
  return result;
5491
6020
  }
6021
+ /**
6022
+ * Collections-specific list getter
6023
+ * eg. `getPageList`
6024
+ */
5492
6025
  case "collectionDocumentList":
5493
6026
  return resolver.resolveCollectionConnection({
5494
6027
  args,
5495
6028
  collection: tinaSchema.getCollection(lookup.collection)
5496
6029
  });
6030
+ /**
6031
+ * A polymorphic data set, it can be from a document's data
6032
+ * of any nested object which can be one of many shapes
6033
+ *
6034
+ * ```graphql
6035
+ * getPostDocument(relativePath: $relativePath) {
6036
+ * data {...} <- this part
6037
+ * }
6038
+ * ```
6039
+ * ```graphql
6040
+ * getBlockDocument(relativePath: $relativePath) {
6041
+ * data {
6042
+ * blocks {...} <- or this part
6043
+ * }
6044
+ * }
6045
+ * ```
6046
+ */
5497
6047
  case "unionData":
5498
6048
  if (!value) {
5499
6049
  if (args.relativePath) {
@@ -5558,8 +6108,7 @@ var TinaLevelClient = class extends ManyLevelGuest {
5558
6108
  this.port = port || 9e3;
5559
6109
  }
5560
6110
  openConnection() {
5561
- if (this._connected)
5562
- return;
6111
+ if (this._connected) return;
5563
6112
  const socket = connect(this.port);
5564
6113
  pipeline(socket, this.createRpcStream(), socket, () => {
5565
6114
  this._connected = false;
@@ -5569,7 +6118,7 @@ var TinaLevelClient = class extends ManyLevelGuest {
5569
6118
  };
5570
6119
 
5571
6120
  // src/database/index.ts
5572
- import path4 from "path";
6121
+ import path4 from "node:path";
5573
6122
  import { GraphQLError as GraphQLError5 } from "graphql";
5574
6123
  import micromatch2 from "micromatch";
5575
6124
  import sha2 from "js-sha1";
@@ -5704,6 +6253,7 @@ var Database = class {
5704
6253
  );
5705
6254
  const indexDefinitions = await this.getIndexDefinitions(this.contentLevel);
5706
6255
  const collectionIndexDefinitions = indexDefinitions?.[collection.name];
6256
+ const collectionReferences = (await this.getCollectionReferences())?.[collection.name];
5707
6257
  const normalizedPath = normalizePath(filepath);
5708
6258
  if (!collection?.isDetached) {
5709
6259
  if (this.bridge) {
@@ -5732,6 +6282,14 @@ var Database = class {
5732
6282
  let delOps = [];
5733
6283
  if (!isGitKeep(normalizedPath, collection)) {
5734
6284
  putOps = [
6285
+ ...makeRefOpsForDocument(
6286
+ normalizedPath,
6287
+ collection?.name,
6288
+ collectionReferences,
6289
+ dataFields,
6290
+ "put",
6291
+ level
6292
+ ),
5735
6293
  ...makeIndexOpsForDocument(
5736
6294
  normalizedPath,
5737
6295
  collection?.name,
@@ -5740,6 +6298,7 @@ var Database = class {
5740
6298
  "put",
5741
6299
  level
5742
6300
  ),
6301
+ // folder indices
5743
6302
  ...makeIndexOpsForDocument(
5744
6303
  normalizedPath,
5745
6304
  `${collection?.name}_${folderKey}`,
@@ -5754,6 +6313,14 @@ var Database = class {
5754
6313
  SUBLEVEL_OPTIONS
5755
6314
  ).get(normalizedPath);
5756
6315
  delOps = existingItem ? [
6316
+ ...makeRefOpsForDocument(
6317
+ normalizedPath,
6318
+ collection?.name,
6319
+ collectionReferences,
6320
+ existingItem,
6321
+ "del",
6322
+ level
6323
+ ),
5757
6324
  ...makeIndexOpsForDocument(
5758
6325
  normalizedPath,
5759
6326
  collection?.name,
@@ -5762,6 +6329,7 @@ var Database = class {
5762
6329
  "del",
5763
6330
  level
5764
6331
  ),
6332
+ // folder indices
5765
6333
  ...makeIndexOpsForDocument(
5766
6334
  normalizedPath,
5767
6335
  `${collection?.name}_${folderKey}`,
@@ -5800,6 +6368,7 @@ var Database = class {
5800
6368
  );
5801
6369
  collectionIndexDefinitions = indexDefinitions?.[collectionName];
5802
6370
  }
6371
+ const collectionReferences = (await this.getCollectionReferences())?.[collectionName];
5803
6372
  const normalizedPath = normalizePath(filepath);
5804
6373
  const dataFields = await this.formatBodyOnPayload(filepath, data);
5805
6374
  const collection = await this.collectionForPath(filepath);
@@ -5847,6 +6416,14 @@ var Database = class {
5847
6416
  let delOps = [];
5848
6417
  if (!isGitKeep(normalizedPath, collection)) {
5849
6418
  putOps = [
6419
+ ...makeRefOpsForDocument(
6420
+ normalizedPath,
6421
+ collectionName,
6422
+ collectionReferences,
6423
+ dataFields,
6424
+ "put",
6425
+ level
6426
+ ),
5850
6427
  ...makeIndexOpsForDocument(
5851
6428
  normalizedPath,
5852
6429
  collectionName,
@@ -5855,6 +6432,7 @@ var Database = class {
5855
6432
  "put",
5856
6433
  level
5857
6434
  ),
6435
+ // folder indices
5858
6436
  ...makeIndexOpsForDocument(
5859
6437
  normalizedPath,
5860
6438
  `${collection?.name}_${folderKey}`,
@@ -5869,6 +6447,14 @@ var Database = class {
5869
6447
  SUBLEVEL_OPTIONS
5870
6448
  ).get(normalizedPath);
5871
6449
  delOps = existingItem ? [
6450
+ ...makeRefOpsForDocument(
6451
+ normalizedPath,
6452
+ collectionName,
6453
+ collectionReferences,
6454
+ existingItem,
6455
+ "del",
6456
+ level
6457
+ ),
5872
6458
  ...makeIndexOpsForDocument(
5873
6459
  normalizedPath,
5874
6460
  collectionName,
@@ -5877,6 +6463,7 @@ var Database = class {
5877
6463
  "del",
5878
6464
  level
5879
6465
  ),
6466
+ // folder indices
5880
6467
  ...makeIndexOpsForDocument(
5881
6468
  normalizedPath,
5882
6469
  `${collection?.name}_${folderKey}`,
@@ -5954,6 +6541,7 @@ var Database = class {
5954
6541
  aliasedData,
5955
6542
  extension,
5956
6543
  writeTemplateKey,
6544
+ //templateInfo.type === 'union',
5957
6545
  {
5958
6546
  frontmatterFormat: collection?.frontmatterFormat,
5959
6547
  frontmatterDelimiters: collection?.frontmatterDelimiters
@@ -5992,6 +6580,7 @@ var Database = class {
5992
6580
  SUBLEVEL_OPTIONS
5993
6581
  ).get(graphqlPath);
5994
6582
  };
6583
+ //TODO - is there a reason why the database fetches some config with "bridge.get", and some with "store.get"?
5995
6584
  this.getGraphQLSchemaFromBridge = async () => {
5996
6585
  if (!this.bridge) {
5997
6586
  throw new Error(`No bridge configured`);
@@ -6028,6 +6617,22 @@ var Database = class {
6028
6617
  this.tinaSchema = await createSchema({ schema });
6029
6618
  return this.tinaSchema;
6030
6619
  };
6620
+ this.getCollectionReferences = async (level) => {
6621
+ if (this.collectionReferences) {
6622
+ return this.collectionReferences;
6623
+ }
6624
+ const result = {};
6625
+ const schema = await this.getSchema(level || this.contentLevel);
6626
+ const collections = schema.getCollections();
6627
+ for (const collection of collections) {
6628
+ const collectionReferences = this.tinaSchema.findReferencesFromCollection(
6629
+ collection.name
6630
+ );
6631
+ result[collection.name] = collectionReferences;
6632
+ }
6633
+ this.collectionReferences = result;
6634
+ return result;
6635
+ };
6031
6636
  this.getIndexDefinitions = async (level) => {
6032
6637
  if (!this.collectionIndexDefinitions) {
6033
6638
  await new Promise(async (resolve2, reject) => {
@@ -6037,10 +6642,53 @@ var Database = class {
6037
6642
  const collections = schema.getCollections();
6038
6643
  for (const collection of collections) {
6039
6644
  const indexDefinitions = {
6040
- [DEFAULT_COLLECTION_SORT_KEY]: { fields: [] }
6645
+ [DEFAULT_COLLECTION_SORT_KEY]: { fields: [] },
6646
+ // provide a default sort key which is the file sort
6647
+ // pseudo-index for the collection's references
6648
+ [REFS_COLLECTIONS_SORT_KEY]: {
6649
+ fields: [
6650
+ {
6651
+ name: REFS_REFERENCE_FIELD,
6652
+ type: "string",
6653
+ list: false
6654
+ },
6655
+ {
6656
+ name: REFS_PATH_FIELD,
6657
+ type: "string",
6658
+ list: false
6659
+ }
6660
+ ]
6661
+ }
6041
6662
  };
6042
- if (collection.fields) {
6043
- for (const field of collection.fields) {
6663
+ let fields = [];
6664
+ if (collection.templates) {
6665
+ const templateFieldMap = {};
6666
+ const conflictedFields = /* @__PURE__ */ new Set();
6667
+ for (const template of collection.templates) {
6668
+ for (const field of template.fields) {
6669
+ if (!templateFieldMap[field.name]) {
6670
+ templateFieldMap[field.name] = field;
6671
+ } else {
6672
+ if (templateFieldMap[field.name].type !== field.type) {
6673
+ console.warn(
6674
+ `Field ${field.name} has conflicting types in templates - skipping index`
6675
+ );
6676
+ conflictedFields.add(field.name);
6677
+ }
6678
+ }
6679
+ }
6680
+ }
6681
+ for (const conflictedField in conflictedFields) {
6682
+ delete templateFieldMap[conflictedField];
6683
+ }
6684
+ for (const field of Object.values(templateFieldMap)) {
6685
+ fields.push(field);
6686
+ }
6687
+ } else if (collection.fields) {
6688
+ fields = collection.fields;
6689
+ }
6690
+ if (fields) {
6691
+ for (const field of fields) {
6044
6692
  if (field.indexed !== void 0 && field.indexed === false || field.type === "object") {
6045
6693
  continue;
6046
6694
  }
@@ -6188,29 +6836,36 @@ var Database = class {
6188
6836
  }
6189
6837
  startKey = startKey || key || "";
6190
6838
  endKey = key || "";
6191
- edges = [...edges, { cursor: key, path: filepath }];
6839
+ edges = [...edges, { cursor: key, path: filepath, value: itemRecord }];
6192
6840
  }
6193
6841
  return {
6194
- edges: await sequential(edges, async (edge) => {
6195
- try {
6196
- const node = await hydrator(edge.path);
6197
- return {
6198
- node,
6199
- cursor: btoa(edge.cursor)
6200
- };
6201
- } catch (error) {
6202
- console.log(error);
6203
- if (error instanceof Error && (!edge.path.includes(".tina/__generated__/_graphql.json") || !edge.path.includes("tina/__generated__/_graphql.json"))) {
6204
- throw new TinaQueryError({
6205
- originalError: error,
6206
- file: edge.path,
6207
- collection: collection.name,
6208
- stack: error.stack
6209
- });
6842
+ edges: await sequential(
6843
+ edges,
6844
+ async ({
6845
+ cursor,
6846
+ path: path7,
6847
+ value
6848
+ }) => {
6849
+ try {
6850
+ const node = await hydrator(path7, value);
6851
+ return {
6852
+ node,
6853
+ cursor: btoa(cursor)
6854
+ };
6855
+ } catch (error) {
6856
+ console.log(error);
6857
+ if (error instanceof Error && (!path7.includes(".tina/__generated__/_graphql.json") || !path7.includes("tina/__generated__/_graphql.json"))) {
6858
+ throw new TinaQueryError({
6859
+ originalError: error,
6860
+ file: path7,
6861
+ collection: collection.name,
6862
+ stack: error.stack
6863
+ });
6864
+ }
6865
+ throw error;
6210
6866
  }
6211
- throw error;
6212
6867
  }
6213
- }),
6868
+ ),
6214
6869
  pageInfo: {
6215
6870
  hasPreviousPage,
6216
6871
  hasNextPage,
@@ -6334,13 +6989,14 @@ var Database = class {
6334
6989
  documentPaths,
6335
6990
  async (collection, documentPaths2) => {
6336
6991
  if (collection && !collection.isDetached) {
6337
- await _indexContent(
6338
- this,
6339
- this.contentLevel,
6340
- documentPaths2,
6992
+ await _indexContent({
6993
+ database: this,
6994
+ level: this.contentLevel,
6995
+ documentPaths: documentPaths2,
6341
6996
  enqueueOps,
6342
- collection
6343
- );
6997
+ collection,
6998
+ isPartialReindex: true
6999
+ });
6344
7000
  }
6345
7001
  }
6346
7002
  );
@@ -6356,17 +7012,18 @@ var Database = class {
6356
7012
  throw new Error(`No collection found for path: ${filepath}`);
6357
7013
  }
6358
7014
  const indexDefinitions = await this.getIndexDefinitions(this.contentLevel);
7015
+ const collectionReferences = (await this.getCollectionReferences())?.[collection.name];
6359
7016
  const collectionIndexDefinitions = indexDefinitions?.[collection.name];
6360
7017
  let level = this.contentLevel;
6361
7018
  if (collection?.isDetached) {
6362
7019
  level = this.appLevel.sublevel(collection?.name, SUBLEVEL_OPTIONS);
6363
7020
  }
6364
- const itemKey = normalizePath(filepath);
7021
+ const normalizedPath = normalizePath(filepath);
6365
7022
  const rootSublevel = level.sublevel(
6366
7023
  CONTENT_ROOT_PREFIX,
6367
7024
  SUBLEVEL_OPTIONS
6368
7025
  );
6369
- const item = await rootSublevel.get(itemKey);
7026
+ const item = await rootSublevel.get(normalizedPath);
6370
7027
  if (item) {
6371
7028
  const folderTreeBuilder = new FolderTreeBuilder();
6372
7029
  const folderKey = folderTreeBuilder.update(
@@ -6374,16 +7031,25 @@ var Database = class {
6374
7031
  collection.path || ""
6375
7032
  );
6376
7033
  await this.contentLevel.batch([
7034
+ ...makeRefOpsForDocument(
7035
+ normalizedPath,
7036
+ collection.name,
7037
+ collectionReferences,
7038
+ item,
7039
+ "del",
7040
+ level
7041
+ ),
6377
7042
  ...makeIndexOpsForDocument(
6378
- filepath,
7043
+ normalizedPath,
6379
7044
  collection.name,
6380
7045
  collectionIndexDefinitions,
6381
7046
  item,
6382
7047
  "del",
6383
7048
  level
6384
7049
  ),
7050
+ // folder indices
6385
7051
  ...makeIndexOpsForDocument(
6386
- filepath,
7052
+ normalizedPath,
6387
7053
  `${collection.name}_${folderKey}`,
6388
7054
  collectionIndexDefinitions,
6389
7055
  item,
@@ -6392,17 +7058,17 @@ var Database = class {
6392
7058
  ),
6393
7059
  {
6394
7060
  type: "del",
6395
- key: itemKey,
7061
+ key: normalizedPath,
6396
7062
  sublevel: rootSublevel
6397
7063
  }
6398
7064
  ]);
6399
7065
  }
6400
7066
  if (!collection?.isDetached) {
6401
7067
  if (this.bridge) {
6402
- await this.bridge.delete(normalizePath(filepath));
7068
+ await this.bridge.delete(normalizedPath);
6403
7069
  }
6404
7070
  try {
6405
- await this.onDelete(normalizePath(filepath));
7071
+ await this.onDelete(normalizedPath);
6406
7072
  } catch (e) {
6407
7073
  throw new GraphQLError5(
6408
7074
  `Error running onDelete hook for ${filepath}: ${e}`,
@@ -6437,20 +7103,26 @@ var Database = class {
6437
7103
  );
6438
7104
  const doc = await level2.keys({ limit: 1 }).next();
6439
7105
  if (!doc) {
6440
- await _indexContent(
6441
- this,
6442
- level2,
6443
- contentPaths,
7106
+ await _indexContent({
7107
+ database: this,
7108
+ level: level2,
7109
+ documentPaths: contentPaths,
6444
7110
  enqueueOps,
6445
7111
  collection,
6446
- userFields.map((field) => [
7112
+ passwordFields: userFields.map((field) => [
6447
7113
  ...field.path,
6448
7114
  field.passwordFieldName
6449
7115
  ])
6450
- );
7116
+ });
6451
7117
  }
6452
7118
  } else {
6453
- await _indexContent(this, level, contentPaths, enqueueOps, collection);
7119
+ await _indexContent({
7120
+ database: this,
7121
+ level,
7122
+ documentPaths: contentPaths,
7123
+ enqueueOps,
7124
+ collection
7125
+ });
6454
7126
  }
6455
7127
  }
6456
7128
  );
@@ -6536,6 +7208,9 @@ var Database = class {
6536
7208
  info: templateInfo
6537
7209
  };
6538
7210
  }
7211
+ /**
7212
+ * Clears the internal cache of the tinaSchema and the lookup file. This allows the state to be reset
7213
+ */
6539
7214
  clearCache() {
6540
7215
  this.tinaSchema = null;
6541
7216
  this._lookup = null;
@@ -6586,7 +7261,15 @@ var hashPasswordValues = async (data, passwordFields) => Promise.all(
6586
7261
  )
6587
7262
  );
6588
7263
  var isGitKeep = (filepath, collection) => filepath.endsWith(`.gitkeep.${collection?.format || "md"}`);
6589
- var _indexContent = async (database, level, documentPaths, enqueueOps, collection, passwordFields) => {
7264
+ var _indexContent = async ({
7265
+ database,
7266
+ level,
7267
+ documentPaths,
7268
+ enqueueOps,
7269
+ collection,
7270
+ passwordFields,
7271
+ isPartialReindex
7272
+ }) => {
6590
7273
  let collectionIndexDefinitions;
6591
7274
  let collectionPath;
6592
7275
  if (collection) {
@@ -6597,6 +7280,7 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6597
7280
  }
6598
7281
  collectionPath = collection.path;
6599
7282
  }
7283
+ const collectionReferences = (await database.getCollectionReferences())?.[collection?.name];
6600
7284
  const tinaSchema = await database.getSchema();
6601
7285
  let templateInfo = null;
6602
7286
  if (collection) {
@@ -6618,12 +7302,61 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6618
7302
  await hashPasswordValues(aliasedData, passwordFields);
6619
7303
  }
6620
7304
  const normalizedPath = normalizePath(filepath);
7305
+ const rootSublevel = level.sublevel(
7306
+ CONTENT_ROOT_PREFIX,
7307
+ SUBLEVEL_OPTIONS
7308
+ );
6621
7309
  const folderKey = folderTreeBuilder.update(
6622
7310
  normalizedPath,
6623
7311
  collectionPath || ""
6624
7312
  );
7313
+ if (isPartialReindex) {
7314
+ const item = await rootSublevel.get(normalizedPath);
7315
+ if (item) {
7316
+ await database.contentLevel.batch([
7317
+ ...makeRefOpsForDocument(
7318
+ normalizedPath,
7319
+ collection?.name,
7320
+ collectionReferences,
7321
+ item,
7322
+ "del",
7323
+ level
7324
+ ),
7325
+ ...makeIndexOpsForDocument(
7326
+ normalizedPath,
7327
+ collection.name,
7328
+ collectionIndexDefinitions,
7329
+ item,
7330
+ "del",
7331
+ level
7332
+ ),
7333
+ // folder indices
7334
+ ...makeIndexOpsForDocument(
7335
+ normalizedPath,
7336
+ `${collection.name}_${folderKey}`,
7337
+ collectionIndexDefinitions,
7338
+ item,
7339
+ "del",
7340
+ level
7341
+ ),
7342
+ {
7343
+ type: "del",
7344
+ key: normalizedPath,
7345
+ sublevel: rootSublevel
7346
+ }
7347
+ ]);
7348
+ }
7349
+ }
6625
7350
  if (!isGitKeep(filepath, collection)) {
6626
7351
  await enqueueOps([
7352
+ ...makeRefOpsForDocument(
7353
+ normalizedPath,
7354
+ collection?.name,
7355
+ collectionReferences,
7356
+ aliasedData,
7357
+ "put",
7358
+ level
7359
+ ),
6627
7360
  ...makeIndexOpsForDocument(
6628
7361
  normalizedPath,
6629
7362
  collection?.name,
@@ -6632,6 +7365,7 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6632
7365
  "put",
6633
7366
  level
6634
7367
  ),
7368
+ // folder indexes
6635
7369
  ...makeIndexOpsForDocument(
6636
7370
  normalizedPath,
6637
7371
  `${collection?.name}_${folderKey}`,
@@ -6686,6 +7420,7 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6686
7420
  throw new Error(`No indexDefinitions for collection ${collection.name}`);
6687
7421
  }
6688
7422
  }
7423
+ const collectionReferences = (await database.getCollectionReferences())?.[collection?.name];
6689
7424
  const tinaSchema = await database.getSchema();
6690
7425
  let templateInfo = null;
6691
7426
  if (collection) {
@@ -6709,6 +7444,14 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6709
7444
  item
6710
7445
  ) : item;
6711
7446
  await enqueueOps([
7447
+ ...makeRefOpsForDocument(
7448
+ itemKey,
7449
+ collection?.name,
7450
+ collectionReferences,
7451
+ aliasedData,
7452
+ "del",
7453
+ database.contentLevel
7454
+ ),
6712
7455
  ...makeIndexOpsForDocument(
6713
7456
  itemKey,
6714
7457
  collection.name,
@@ -6717,6 +7460,7 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6717
7460
  "del",
6718
7461
  database.contentLevel
6719
7462
  ),
7463
+ // folder indexes
6720
7464
  ...makeIndexOpsForDocument(
6721
7465
  itemKey,
6722
7466
  `${collection?.name}_${folderKey}`,
@@ -6932,17 +7676,26 @@ var IsomorphicBridge = class {
6932
7676
  getAuthor() {
6933
7677
  return {
6934
7678
  ...this.author,
6935
- timestamp: Math.round(new Date().getTime() / 1e3),
7679
+ timestamp: Math.round((/* @__PURE__ */ new Date()).getTime() / 1e3),
6936
7680
  timezoneOffset: 0
6937
7681
  };
6938
7682
  }
6939
7683
  getCommitter() {
6940
7684
  return {
6941
7685
  ...this.committer,
6942
- timestamp: Math.round(new Date().getTime() / 1e3),
7686
+ timestamp: Math.round((/* @__PURE__ */ new Date()).getTime() / 1e3),
6943
7687
  timezoneOffset: 0
6944
7688
  };
6945
7689
  }
7690
+ /**
7691
+ * Recursively populate paths matching `pattern` for the given `entry`
7692
+ *
7693
+ * @param pattern - pattern to filter paths by
7694
+ * @param entry - TreeEntry to start building list from
7695
+ * @param path - base path
7696
+ * @param results
7697
+ * @private
7698
+ */
6946
7699
  async listEntries({
6947
7700
  pattern,
6948
7701
  entry,
@@ -6975,6 +7728,15 @@ var IsomorphicBridge = class {
6975
7728
  });
6976
7729
  }
6977
7730
  }
7731
+ /**
7732
+ * For the specified path, returns an object with an array containing the parts of the path (pathParts)
7733
+ * and an array containing the WalkerEntry objects for the path parts (pathEntries). Any null elements in the
7734
+ * pathEntries are placeholders for non-existent entries.
7735
+ *
7736
+ * @param path - path being resolved
7737
+ * @param ref - ref to resolve path entries for
7738
+ * @private
7739
+ */
6978
7740
  async resolvePathEntries(path7, ref) {
6979
7741
  let pathParts = path7.split("/");
6980
7742
  const result = await git2.walk({
@@ -7005,6 +7767,17 @@ var IsomorphicBridge = class {
7005
7767
  }
7006
7768
  return { pathParts, pathEntries };
7007
7769
  }
7770
+ /**
7771
+ * Updates tree entry and associated parent tree entries
7772
+ *
7773
+ * @param existingOid - the existing OID
7774
+ * @param updatedOid - the updated OID
7775
+ * @param path - the path of the entry being updated
7776
+ * @param type - the type of the entry being updated (blob or tree)
7777
+ * @param pathEntries - parent path entries
7778
+ * @param pathParts - parent path parts
7779
+ * @private
7780
+ */
7008
7781
  async updateTreeHierarchy(existingOid, updatedOid, path7, type, pathEntries, pathParts) {
7009
7782
  const lastIdx = pathEntries.length - 1;
7010
7783
  const parentEntry = pathEntries[lastIdx];
@@ -7060,6 +7833,13 @@ var IsomorphicBridge = class {
7060
7833
  );
7061
7834
  }
7062
7835
  }
7836
+ /**
7837
+ * Creates a commit for the specified tree and updates the specified ref to point to the commit
7838
+ *
7839
+ * @param treeSha - sha of the new tree
7840
+ * @param ref - the ref that should be updated
7841
+ * @private
7842
+ */
7063
7843
  async commitTree(treeSha, ref) {
7064
7844
  const commitSha = await git2.writeCommit({
7065
7845
  ...this.isomorphicConfig,
@@ -7072,6 +7852,7 @@ var IsomorphicBridge = class {
7072
7852
  })
7073
7853
  ],
7074
7854
  message: this.commitMessage,
7855
+ // TODO these should be configurable
7075
7856
  author: this.getAuthor(),
7076
7857
  committer: this.getCommitter()
7077
7858
  }
@@ -7309,5 +8090,5 @@ export {
7309
8090
  transformDocument,
7310
8091
  transformDocumentIntoPayload
7311
8092
  };
7312
- //! Replaces _.flattenDeep()
7313
8093
  //! Replaces _.get()
8094
+ //! Replaces _.flattenDeep()