tinacms 0.0.0-b54b303-20241210232138 → 0.0.0-b67f55a-20250513032422

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.
Files changed (50) hide show
  1. package/README.md +1 -1
  2. package/dist/admin/api.d.ts +1 -0
  3. package/dist/admin/components/GetCollection.d.ts +2 -2
  4. package/dist/auth/TinaCloudProvider.d.ts +1 -1
  5. package/dist/client.js +83 -46
  6. package/dist/client.js.map +1 -0
  7. package/dist/client.mjs +60 -36
  8. package/dist/client.mjs.map +1 -0
  9. package/dist/hooks/create-page-plugin.d.ts +1 -1
  10. package/dist/index.js +4411 -3240
  11. package/dist/index.js.map +1 -0
  12. package/dist/index.mjs +4433 -3262
  13. package/dist/index.mjs.map +1 -0
  14. package/dist/internalClient/index.d.ts +3 -3
  15. package/dist/{node-cache-4c336858.mjs → node-cache-5e8db9f0.mjs} +24 -10
  16. package/dist/node-cache-5e8db9f0.mjs.map +1 -0
  17. package/dist/react.d.ts +1 -0
  18. package/dist/react.js +14 -1
  19. package/dist/react.js.map +1 -0
  20. package/dist/react.mjs +14 -1
  21. package/dist/react.mjs.map +1 -0
  22. package/dist/rich-text/index.js +1 -0
  23. package/dist/rich-text/index.js.map +1 -0
  24. package/dist/rich-text/index.mjs +1 -0
  25. package/dist/rich-text/index.mjs.map +1 -0
  26. package/dist/rich-text/prism.js +2 -1
  27. package/dist/rich-text/prism.js.map +1 -0
  28. package/dist/rich-text/prism.mjs +2 -1
  29. package/dist/rich-text/prism.mjs.map +1 -0
  30. package/dist/toolkit/components/media/media-manager.d.ts +1 -1
  31. package/dist/toolkit/fields/components/reference/reference-select.d.ts +2 -2
  32. package/dist/toolkit/fields/plugins/mdx-field-plugin/index.d.ts +4 -1
  33. package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/components/plate-ui/indent-list-toolbar-button.d.ts +17 -5
  34. package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/components/plate-ui/mark-toolbar-button.d.ts +4 -18
  35. package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/index.d.ts +1 -1
  36. package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/plugins/ui/components.d.ts +6 -11
  37. package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/toolbar/toolbar-overrides.d.ts +5 -1
  38. package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/toolbar/toolbar-provider.d.ts +2 -2
  39. package/dist/toolkit/plugin-branch-switcher/branch-switcher-legacy.d.ts +1 -1
  40. package/dist/toolkit/plugin-branch-switcher/branch-switcher.d.ts +1 -1
  41. package/dist/toolkit/react-cloud-config/cloud-config-plugin.d.ts +3 -3
  42. package/dist/toolkit/react-sidebar/components/sidebar-body.d.ts +5 -4
  43. package/dist/toolkit/react-sidebar/components/sidebar-loading-placeholder.d.ts +2 -0
  44. package/dist/toolkit/react-sidebar/components/sidebar-no-forms-placeholder.d.ts +2 -0
  45. package/dist/toolkit/react-sidebar/sidebar.d.ts +2 -2
  46. package/dist/toolkit/tina-cms.d.ts +3 -3
  47. package/dist/toolkit/tina-state.d.ts +4 -0
  48. package/dist/unifiedClient/index.d.ts +8 -1
  49. package/package.json +37 -37
  50. package/dist/toolkit/react-sidebar/components/no-forms-placeholder.d.ts +0 -8
package/README.md CHANGED
@@ -24,7 +24,7 @@ Test a TinaCMS starter site locally
24
24
  npx create-tina-app@latest
25
25
  ```
26
26
 
27
- Or try a [demo site](https://app.tina.io/quickstart) on Tina Cloud.
27
+ Or try a [demo site](https://app.tina.io/quickstart) on TinaCloud.
28
28
 
29
29
  ## Documentation
30
30
 
@@ -7,6 +7,7 @@ export interface FilterArgs {
7
7
  filterField: string;
8
8
  collection?: string;
9
9
  relativePath?: string;
10
+ relativePathWithoutExtension?: string;
10
11
  newRelativePath?: string;
11
12
  startsWith?: string;
12
13
  endsWith?: string;
@@ -1,9 +1,9 @@
1
1
  /**
2
2
 
3
3
  */
4
- import React from 'react';
5
- import type { TinaCMS } from '@tinacms/toolkit';
6
4
  import type { Collection } from '@tinacms/schema-tools';
5
+ import type { TinaCMS } from '@tinacms/toolkit';
6
+ import React from 'react';
7
7
  import { FilterArgs } from '../api';
8
8
  import type { CollectionResponse } from '../types';
9
9
  export declare const useGetCollection: (cms: TinaCMS, collectionName: string, includeDocuments: boolean, folder: {
@@ -1,5 +1,5 @@
1
+ import { MediaStore, StaticMedia, TinaCMS } from '@tinacms/toolkit';
1
2
  import React from 'react';
2
- import { TinaCMS, MediaStore, StaticMedia } from '@tinacms/toolkit';
3
3
  import { Client, TinaIOConfig } from '../internalClient';
4
4
  import { CreateClientProps } from '../utils';
5
5
  export interface TinaCloudMediaStoreClass {
package/dist/client.js CHANGED
@@ -1,11 +1,16 @@
1
1
  (function(global, factory) {
2
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("fetch-ponyfill")) : typeof define === "function" && define.amd ? define(["exports", "fetch-ponyfill"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.tinacms = {}, global.NOOP));
3
- })(this, function(exports2, fetchPonyfill) {
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("async-lock")) : typeof define === "function" && define.amd ? define(["exports", "async-lock"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.tinacms = {}, global.NOOP));
3
+ })(this, function(exports2, AsyncLock) {
4
4
  "use strict";
5
- const { fetch: fetchPonyfillFN, Headers: HeadersPonyfill } = fetchPonyfill();
6
- const fetchDefined = typeof fetch === "undefined" ? fetchPonyfillFN : fetch;
7
- const HeadersDefined = typeof Headers === "undefined" ? HeadersPonyfill : Headers;
8
5
  const TINA_HOST = "content.tinajs.io";
6
+ function replaceGithubPathSplit(url, replacement) {
7
+ const parts = url.split("github/");
8
+ if (parts.length > 1 && replacement) {
9
+ return parts[0] + "github/" + replacement;
10
+ } else {
11
+ return url;
12
+ }
13
+ }
9
14
  class TinaClient {
10
15
  constructor({
11
16
  token,
@@ -29,6 +34,7 @@
29
34
  if (this.cacheDir && typeof window === "undefined" && typeof require !== "undefined") {
30
35
  const { NodeCache: NodeCache2 } = await Promise.resolve().then(() => nodeCache);
31
36
  this.cache = await NodeCache2(this.cacheDir);
37
+ this.cacheLock = new AsyncLock();
32
38
  }
33
39
  } catch (e) {
34
40
  console.error(e);
@@ -39,7 +45,7 @@
39
45
  var _a;
40
46
  await this.init();
41
47
  const errorPolicyDefined = errorPolicy || this.errorPolicy;
42
- const headers = new HeadersDefined();
48
+ const headers = new Headers();
43
49
  if (this.readonlyToken) {
44
50
  headers.append("X-API-KEY", this.readonlyToken);
45
51
  }
@@ -56,7 +62,6 @@
56
62
  query: args.query,
57
63
  variables: (args == null ? void 0 : args.variables) || {}
58
64
  });
59
- const url = (args == null ? void 0 : args.url) || this.apiUrl;
60
65
  const optionsObject = {
61
66
  method: "POST",
62
67
  headers,
@@ -64,43 +69,61 @@
64
69
  redirect: "follow",
65
70
  ...providedFetchOptions
66
71
  };
72
+ const draftBranch = headers.get("x-branch");
73
+ const url = replaceGithubPathSplit((args == null ? void 0 : args.url) || this.apiUrl, draftBranch);
67
74
  let key = "";
75
+ let result;
68
76
  if (this.cache) {
69
77
  key = this.cache.makeKey(bodyString);
70
- const value = await this.cache.get(key);
71
- if (value) {
72
- return value;
73
- }
74
- }
75
- const res = await fetchDefined(url, optionsObject);
76
- if (!res.ok) {
77
- let additionalInfo = "";
78
- if (res.status === 401) {
79
- additionalInfo = "Please check that your client ID, URL and read only token are configured properly.";
80
- }
81
- throw new Error(
82
- `Server responded with status code ${res.status}, ${res.statusText}. ${additionalInfo ? additionalInfo : ""} Please see our FAQ for more information: https://tina.io/docs/errors/faq/`
83
- );
84
- }
85
- const json = await res.json();
86
- if (json.errors && errorPolicyDefined === "throw") {
87
- throw new Error(
88
- `Unable to fetch, please see our FAQ for more information: https://tina.io/docs/errors/faq/
89
- Errors:
90
- ${json.errors.map((error) => error.message).join("\n")}`
78
+ await this.cacheLock.acquire(key, async () => {
79
+ result = await this.cache.get(key);
80
+ if (!result) {
81
+ result = await requestFromServer(
82
+ url,
83
+ args.query,
84
+ optionsObject,
85
+ errorPolicyDefined
86
+ );
87
+ await this.cache.set(key, result);
88
+ }
89
+ });
90
+ } else {
91
+ result = await requestFromServer(
92
+ url,
93
+ args.query,
94
+ optionsObject,
95
+ errorPolicyDefined
91
96
  );
92
97
  }
93
- const result = {
94
- data: json == null ? void 0 : json.data,
95
- errors: (json == null ? void 0 : json.errors) || null,
96
- query: args.query
97
- };
98
- if (this.cache) {
99
- await this.cache.set(key, result);
100
- }
101
98
  return result;
102
99
  }
103
100
  }
101
+ async function requestFromServer(url, query, optionsObject, errorPolicyDefined) {
102
+ const res = await fetch(url, optionsObject);
103
+ if (!res.ok) {
104
+ let additionalInfo = "";
105
+ if (res.status === 401) {
106
+ additionalInfo = "Please check that your client ID, URL and read only token are configured properly.";
107
+ }
108
+ throw new Error(
109
+ `Server responded with status code ${res.status}, ${res.statusText}. ${additionalInfo ? additionalInfo : ""} Please see our FAQ for more information: https://tina.io/docs/errors/faq/`
110
+ );
111
+ }
112
+ const json = await res.json();
113
+ if (json.errors && errorPolicyDefined === "throw") {
114
+ throw new Error(
115
+ `Unable to fetch, please see our FAQ for more information: https://tina.io/docs/errors/faq/
116
+ Errors:
117
+ ${json.errors.map((error) => error.message).join("\n")}`
118
+ );
119
+ }
120
+ const result = {
121
+ data: json == null ? void 0 : json.data,
122
+ errors: (json == null ? void 0 : json.errors) || null,
123
+ query
124
+ };
125
+ return result;
126
+ }
104
127
  function createClient(args) {
105
128
  const client = new TinaClient(args);
106
129
  return client;
@@ -132,22 +155,35 @@
132
155
  return createHash("sha256").update(input).digest("hex");
133
156
  },
134
157
  get: async (key) => {
158
+ let readValue;
159
+ const cacheFilename = `${cacheDir}/${key}`;
135
160
  try {
136
- const data = await fs.promises.readFile(`${cacheDir}/${key}`, "utf-8");
137
- return JSON.parse(data);
161
+ const data = await fs.promises.readFile(cacheFilename, "utf-8");
162
+ readValue = JSON.parse(data);
138
163
  } catch (e) {
139
- if (e.code === "ENOENT") {
140
- return void 0;
164
+ if (e.code !== "ENOENT") {
165
+ console.error(
166
+ `Failed to read cache file to ${cacheFilename}: ${e.message}`
167
+ );
141
168
  }
142
- throw e;
143
169
  }
170
+ return readValue;
144
171
  },
145
172
  set: async (key, value) => {
146
- await fs.promises.writeFile(
147
- `${cacheDir}/${key}`,
148
- JSON.stringify(value),
149
- "utf-8"
150
- );
173
+ const cacheFilename = `${cacheDir}/${key}`;
174
+ try {
175
+ await fs.promises.writeFile(cacheFilename, JSON.stringify(value), {
176
+ encoding: "utf-8",
177
+ flag: "wx"
178
+ // Don't overwrite existing caches
179
+ });
180
+ } catch (e) {
181
+ if (e.code !== "EEXIST") {
182
+ console.error(
183
+ `Failed to write cache file to ${cacheFilename}: ${e.message}`
184
+ );
185
+ }
186
+ }
151
187
  }
152
188
  };
153
189
  };
@@ -161,3 +197,4 @@
161
197
  exports2.createClient = createClient;
162
198
  Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
163
199
  });
200
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sources":["../src/unifiedClient/index.ts","../src/cache/node-cache.ts"],"sourcesContent":["import type { Config } from '@tinacms/schema-tools';\nimport AsyncLock from 'async-lock';\nimport type { GraphQLError } from 'graphql';\nimport type { Cache } from '../cache/index';\n\nexport const TINA_HOST = 'content.tinajs.io';\nexport interface TinaClientArgs<GenQueries = Record<string, unknown>> {\n url: string;\n token?: string;\n queries: (client: TinaClient<GenQueries>) => GenQueries;\n errorPolicy?: Config['client']['errorPolicy'];\n cacheDir?: string;\n}\nexport type TinaClientRequestArgs = {\n variables?: Record<string, any>;\n query: string;\n errorPolicy?: 'throw' | 'include';\n} & Partial<Omit<TinaClientArgs, 'queries'>>;\n\nexport type TinaClientURLParts = {\n host: string;\n clientId: string;\n branch: string;\n isLocalClient: boolean;\n};\n\n/**\n * Replaces the part of a URL after 'github/' with a specified replacement string.\n *\n * @param {string} url The original URL.\n * @param {string} replacement The string to replace the part after 'github/'.\n * @returns {string} The modified URL, or the original URL if 'github/' is not found.\n */\nfunction replaceGithubPathSplit(url: string, replacement: string) {\n const parts = url.split('github/');\n if (parts.length > 1 && replacement) {\n return parts[0] + 'github/' + replacement;\n } else {\n return url;\n }\n}\n\nexport class TinaClient<GenQueries> {\n public apiUrl: string;\n public readonlyToken?: string;\n public queries: GenQueries;\n public errorPolicy: Config['client']['errorPolicy'];\n initialized = false;\n cacheLock: AsyncLock | undefined;\n cacheDir: string;\n cache: Cache;\n\n constructor({\n token,\n url,\n queries,\n errorPolicy,\n cacheDir,\n }: TinaClientArgs<GenQueries>) {\n this.apiUrl = url;\n this.readonlyToken = token?.trim();\n this.queries = queries(this);\n this.errorPolicy = errorPolicy || 'throw';\n this.cacheDir = cacheDir || '';\n }\n\n async init() {\n if (this.initialized) {\n return;\n }\n try {\n if (\n this.cacheDir &&\n typeof window === 'undefined' &&\n typeof require !== 'undefined'\n ) {\n const { NodeCache } = await import('../cache/node-cache');\n this.cache = await NodeCache(this.cacheDir);\n this.cacheLock = new AsyncLock();\n }\n } catch (e) {\n console.error(e);\n }\n this.initialized = true;\n }\n\n public async request<DataType extends Record<string, any> = any>(\n { errorPolicy, ...args }: TinaClientRequestArgs,\n options: { fetchOptions?: Parameters<typeof fetch>[1] }\n ) {\n await this.init();\n const errorPolicyDefined = errorPolicy || this.errorPolicy;\n const headers = new Headers();\n if (this.readonlyToken) {\n headers.append('X-API-KEY', this.readonlyToken);\n }\n headers.append('Content-Type', 'application/json');\n if (options?.fetchOptions) {\n if (options?.fetchOptions?.headers) {\n Object.entries(options.fetchOptions.headers).forEach(([key, value]) => {\n headers.append(key, value);\n });\n }\n }\n const { headers: _, ...providedFetchOptions } = options?.fetchOptions || {};\n\n const bodyString = JSON.stringify({\n query: args.query,\n variables: args?.variables || {},\n });\n\n const optionsObject: Parameters<typeof fetch>[1] = {\n method: 'POST',\n headers,\n body: bodyString,\n redirect: 'follow',\n ...providedFetchOptions,\n };\n\n // Look for the header and change to use this branch instead of the build time generated branch.\n // This comes from the clients fetch options:\n //client.queries.collection({}, {\n // fetchOptions: {\n // headers: {\n // 'x-branch': cookieStore.get('x-branch')?.value,\n // },\n // },\n //})\n const draftBranch = headers.get('x-branch');\n const url = replaceGithubPathSplit(args?.url || this.apiUrl, draftBranch);\n\n let key = '';\n let result: {\n data: DataType;\n errors: GraphQLError[] | null;\n query: string;\n };\n if (this.cache) {\n key = this.cache.makeKey(bodyString);\n await this.cacheLock.acquire(key, async () => {\n result = await this.cache.get(key);\n if (!result) {\n result = await requestFromServer<DataType>(\n url,\n args.query,\n optionsObject,\n errorPolicyDefined\n );\n await this.cache.set(key, result);\n }\n });\n } else {\n result = await requestFromServer<DataType>(\n url,\n args.query,\n optionsObject,\n errorPolicyDefined\n );\n }\n\n return result;\n }\n}\n\nasync function requestFromServer<DataType extends Record<string, any> = any>(\n url: string,\n query: string,\n optionsObject: RequestInit,\n errorPolicyDefined: 'throw' | 'include'\n) {\n const res = await fetch(url, optionsObject);\n if (!res.ok) {\n let additionalInfo = '';\n if (res.status === 401) {\n additionalInfo =\n 'Please check that your client ID, URL and read only token are configured properly.';\n }\n\n throw new Error(\n `Server responded with status code ${res.status}, ${res.statusText}. ${\n additionalInfo ? additionalInfo : ''\n } Please see our FAQ for more information: https://tina.io/docs/errors/faq/`\n );\n }\n const json = await res.json();\n if (json.errors && errorPolicyDefined === 'throw') {\n throw new Error(\n `Unable to fetch, please see our FAQ for more information: https://tina.io/docs/errors/faq/\n Errors: \\n\\t${json.errors.map((error) => error.message).join('\\n')}`\n );\n }\n const result = {\n data: json?.data as DataType,\n errors: (json?.errors || null) as GraphQLError[] | null,\n query,\n };\n return result;\n}\n\nexport function createClient<GenQueries>(args: TinaClientArgs<GenQueries>) {\n const client = new TinaClient<ReturnType<typeof args.queries>>(args);\n return client;\n}\n","import type { Cache } from './index';\n\n// Create the cache directory if it doesn't exist.\n// Returns the path of the cache directory.\nexport const makeCacheDir = async (\n dir: string,\n fs: any,\n path: any,\n os: any\n) => {\n const pathParts = dir.split(path.sep).filter(Boolean);\n const cacheHash = pathParts[pathParts.length - 1];\n const rootUser = pathParts[0];\n let cacheDir = dir;\n\n // Check if the root directory exists. If not, create the cache in the tmp directory.\n if (!fs.existsSync(path.join(path.sep, rootUser))) {\n cacheDir = path.join(os.tmpdir(), cacheHash);\n }\n\n try {\n fs.mkdirSync(cacheDir, { recursive: true });\n } catch (error) {\n throw new Error(`Failed to create cache directory: ${error.message}`);\n }\n\n return cacheDir;\n};\n\nexport const NodeCache = async (dir: string): Promise<Cache> => {\n // TODO: These will need to be changed from using require to import when we eventually move to ESM\n const fs = require('node:fs');\n const path = require('node:path');\n const os = require('node:os');\n\n const { createHash } = require('node:crypto');\n const cacheDir = await makeCacheDir(dir, fs, path, os);\n\n return {\n makeKey: (key: any) => {\n const input =\n key && key instanceof Object ? JSON.stringify(key) : key || '';\n return createHash('sha256').update(input).digest('hex');\n },\n get: async (key: string) => {\n let readValue: object | undefined;\n\n const cacheFilename = `${cacheDir}/${key}`;\n try {\n const data = await fs.promises.readFile(cacheFilename, 'utf-8');\n readValue = JSON.parse(data);\n } catch (e) {\n if (e.code !== 'ENOENT') {\n console.error(\n `Failed to read cache file to ${cacheFilename}: ${e.message}`\n );\n }\n }\n\n return readValue;\n },\n set: async (key: string, value: any) => {\n const cacheFilename = `${cacheDir}/${key}`;\n try {\n await fs.promises.writeFile(cacheFilename, JSON.stringify(value), {\n encoding: 'utf-8',\n flag: 'wx', // Don't overwrite existing caches\n });\n } catch (e) {\n if (e.code !== 'EEXIST') {\n console.error(\n `Failed to write cache file to ${cacheFilename}: ${e.message}`\n );\n }\n }\n },\n };\n};\n"],"names":["NodeCache","key"],"mappings":"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"}
package/dist/client.mjs CHANGED
@@ -1,8 +1,13 @@
1
- import fetchPonyfill from "fetch-ponyfill";
2
- const { fetch: fetchPonyfillFN, Headers: HeadersPonyfill } = fetchPonyfill();
3
- const fetchDefined = typeof fetch === "undefined" ? fetchPonyfillFN : fetch;
4
- const HeadersDefined = typeof Headers === "undefined" ? HeadersPonyfill : Headers;
1
+ import AsyncLock from "async-lock";
5
2
  const TINA_HOST = "content.tinajs.io";
3
+ function replaceGithubPathSplit(url, replacement) {
4
+ const parts = url.split("github/");
5
+ if (parts.length > 1 && replacement) {
6
+ return parts[0] + "github/" + replacement;
7
+ } else {
8
+ return url;
9
+ }
10
+ }
6
11
  class TinaClient {
7
12
  constructor({
8
13
  token,
@@ -24,8 +29,9 @@ class TinaClient {
24
29
  }
25
30
  try {
26
31
  if (this.cacheDir && typeof window === "undefined" && typeof require !== "undefined") {
27
- const { NodeCache } = await import("./node-cache-4c336858.mjs");
32
+ const { NodeCache } = await import("./node-cache-5e8db9f0.mjs");
28
33
  this.cache = await NodeCache(this.cacheDir);
34
+ this.cacheLock = new AsyncLock();
29
35
  }
30
36
  } catch (e) {
31
37
  console.error(e);
@@ -36,7 +42,7 @@ class TinaClient {
36
42
  var _a;
37
43
  await this.init();
38
44
  const errorPolicyDefined = errorPolicy || this.errorPolicy;
39
- const headers = new HeadersDefined();
45
+ const headers = new Headers();
40
46
  if (this.readonlyToken) {
41
47
  headers.append("X-API-KEY", this.readonlyToken);
42
48
  }
@@ -53,7 +59,6 @@ class TinaClient {
53
59
  query: args.query,
54
60
  variables: (args == null ? void 0 : args.variables) || {}
55
61
  });
56
- const url = (args == null ? void 0 : args.url) || this.apiUrl;
57
62
  const optionsObject = {
58
63
  method: "POST",
59
64
  headers,
@@ -61,43 +66,61 @@ class TinaClient {
61
66
  redirect: "follow",
62
67
  ...providedFetchOptions
63
68
  };
69
+ const draftBranch = headers.get("x-branch");
70
+ const url = replaceGithubPathSplit((args == null ? void 0 : args.url) || this.apiUrl, draftBranch);
64
71
  let key = "";
72
+ let result;
65
73
  if (this.cache) {
66
74
  key = this.cache.makeKey(bodyString);
67
- const value = await this.cache.get(key);
68
- if (value) {
69
- return value;
70
- }
71
- }
72
- const res = await fetchDefined(url, optionsObject);
73
- if (!res.ok) {
74
- let additionalInfo = "";
75
- if (res.status === 401) {
76
- additionalInfo = "Please check that your client ID, URL and read only token are configured properly.";
77
- }
78
- throw new Error(
79
- `Server responded with status code ${res.status}, ${res.statusText}. ${additionalInfo ? additionalInfo : ""} Please see our FAQ for more information: https://tina.io/docs/errors/faq/`
80
- );
81
- }
82
- const json = await res.json();
83
- if (json.errors && errorPolicyDefined === "throw") {
84
- throw new Error(
85
- `Unable to fetch, please see our FAQ for more information: https://tina.io/docs/errors/faq/
86
- Errors:
87
- ${json.errors.map((error) => error.message).join("\n")}`
75
+ await this.cacheLock.acquire(key, async () => {
76
+ result = await this.cache.get(key);
77
+ if (!result) {
78
+ result = await requestFromServer(
79
+ url,
80
+ args.query,
81
+ optionsObject,
82
+ errorPolicyDefined
83
+ );
84
+ await this.cache.set(key, result);
85
+ }
86
+ });
87
+ } else {
88
+ result = await requestFromServer(
89
+ url,
90
+ args.query,
91
+ optionsObject,
92
+ errorPolicyDefined
88
93
  );
89
94
  }
90
- const result = {
91
- data: json == null ? void 0 : json.data,
92
- errors: (json == null ? void 0 : json.errors) || null,
93
- query: args.query
94
- };
95
- if (this.cache) {
96
- await this.cache.set(key, result);
97
- }
98
95
  return result;
99
96
  }
100
97
  }
98
+ async function requestFromServer(url, query, optionsObject, errorPolicyDefined) {
99
+ const res = await fetch(url, optionsObject);
100
+ if (!res.ok) {
101
+ let additionalInfo = "";
102
+ if (res.status === 401) {
103
+ additionalInfo = "Please check that your client ID, URL and read only token are configured properly.";
104
+ }
105
+ throw new Error(
106
+ `Server responded with status code ${res.status}, ${res.statusText}. ${additionalInfo ? additionalInfo : ""} Please see our FAQ for more information: https://tina.io/docs/errors/faq/`
107
+ );
108
+ }
109
+ const json = await res.json();
110
+ if (json.errors && errorPolicyDefined === "throw") {
111
+ throw new Error(
112
+ `Unable to fetch, please see our FAQ for more information: https://tina.io/docs/errors/faq/
113
+ Errors:
114
+ ${json.errors.map((error) => error.message).join("\n")}`
115
+ );
116
+ }
117
+ const result = {
118
+ data: json == null ? void 0 : json.data,
119
+ errors: (json == null ? void 0 : json.errors) || null,
120
+ query
121
+ };
122
+ return result;
123
+ }
101
124
  function createClient(args) {
102
125
  const client = new TinaClient(args);
103
126
  return client;
@@ -107,3 +130,4 @@ export {
107
130
  TinaClient,
108
131
  createClient
109
132
  };
133
+ //# sourceMappingURL=client.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.mjs","sources":["../src/unifiedClient/index.ts"],"sourcesContent":["import type { Config } from '@tinacms/schema-tools';\nimport AsyncLock from 'async-lock';\nimport type { GraphQLError } from 'graphql';\nimport type { Cache } from '../cache/index';\n\nexport const TINA_HOST = 'content.tinajs.io';\nexport interface TinaClientArgs<GenQueries = Record<string, unknown>> {\n url: string;\n token?: string;\n queries: (client: TinaClient<GenQueries>) => GenQueries;\n errorPolicy?: Config['client']['errorPolicy'];\n cacheDir?: string;\n}\nexport type TinaClientRequestArgs = {\n variables?: Record<string, any>;\n query: string;\n errorPolicy?: 'throw' | 'include';\n} & Partial<Omit<TinaClientArgs, 'queries'>>;\n\nexport type TinaClientURLParts = {\n host: string;\n clientId: string;\n branch: string;\n isLocalClient: boolean;\n};\n\n/**\n * Replaces the part of a URL after 'github/' with a specified replacement string.\n *\n * @param {string} url The original URL.\n * @param {string} replacement The string to replace the part after 'github/'.\n * @returns {string} The modified URL, or the original URL if 'github/' is not found.\n */\nfunction replaceGithubPathSplit(url: string, replacement: string) {\n const parts = url.split('github/');\n if (parts.length > 1 && replacement) {\n return parts[0] + 'github/' + replacement;\n } else {\n return url;\n }\n}\n\nexport class TinaClient<GenQueries> {\n public apiUrl: string;\n public readonlyToken?: string;\n public queries: GenQueries;\n public errorPolicy: Config['client']['errorPolicy'];\n initialized = false;\n cacheLock: AsyncLock | undefined;\n cacheDir: string;\n cache: Cache;\n\n constructor({\n token,\n url,\n queries,\n errorPolicy,\n cacheDir,\n }: TinaClientArgs<GenQueries>) {\n this.apiUrl = url;\n this.readonlyToken = token?.trim();\n this.queries = queries(this);\n this.errorPolicy = errorPolicy || 'throw';\n this.cacheDir = cacheDir || '';\n }\n\n async init() {\n if (this.initialized) {\n return;\n }\n try {\n if (\n this.cacheDir &&\n typeof window === 'undefined' &&\n typeof require !== 'undefined'\n ) {\n const { NodeCache } = await import('../cache/node-cache');\n this.cache = await NodeCache(this.cacheDir);\n this.cacheLock = new AsyncLock();\n }\n } catch (e) {\n console.error(e);\n }\n this.initialized = true;\n }\n\n public async request<DataType extends Record<string, any> = any>(\n { errorPolicy, ...args }: TinaClientRequestArgs,\n options: { fetchOptions?: Parameters<typeof fetch>[1] }\n ) {\n await this.init();\n const errorPolicyDefined = errorPolicy || this.errorPolicy;\n const headers = new Headers();\n if (this.readonlyToken) {\n headers.append('X-API-KEY', this.readonlyToken);\n }\n headers.append('Content-Type', 'application/json');\n if (options?.fetchOptions) {\n if (options?.fetchOptions?.headers) {\n Object.entries(options.fetchOptions.headers).forEach(([key, value]) => {\n headers.append(key, value);\n });\n }\n }\n const { headers: _, ...providedFetchOptions } = options?.fetchOptions || {};\n\n const bodyString = JSON.stringify({\n query: args.query,\n variables: args?.variables || {},\n });\n\n const optionsObject: Parameters<typeof fetch>[1] = {\n method: 'POST',\n headers,\n body: bodyString,\n redirect: 'follow',\n ...providedFetchOptions,\n };\n\n // Look for the header and change to use this branch instead of the build time generated branch.\n // This comes from the clients fetch options:\n //client.queries.collection({}, {\n // fetchOptions: {\n // headers: {\n // 'x-branch': cookieStore.get('x-branch')?.value,\n // },\n // },\n //})\n const draftBranch = headers.get('x-branch');\n const url = replaceGithubPathSplit(args?.url || this.apiUrl, draftBranch);\n\n let key = '';\n let result: {\n data: DataType;\n errors: GraphQLError[] | null;\n query: string;\n };\n if (this.cache) {\n key = this.cache.makeKey(bodyString);\n await this.cacheLock.acquire(key, async () => {\n result = await this.cache.get(key);\n if (!result) {\n result = await requestFromServer<DataType>(\n url,\n args.query,\n optionsObject,\n errorPolicyDefined\n );\n await this.cache.set(key, result);\n }\n });\n } else {\n result = await requestFromServer<DataType>(\n url,\n args.query,\n optionsObject,\n errorPolicyDefined\n );\n }\n\n return result;\n }\n}\n\nasync function requestFromServer<DataType extends Record<string, any> = any>(\n url: string,\n query: string,\n optionsObject: RequestInit,\n errorPolicyDefined: 'throw' | 'include'\n) {\n const res = await fetch(url, optionsObject);\n if (!res.ok) {\n let additionalInfo = '';\n if (res.status === 401) {\n additionalInfo =\n 'Please check that your client ID, URL and read only token are configured properly.';\n }\n\n throw new Error(\n `Server responded with status code ${res.status}, ${res.statusText}. ${\n additionalInfo ? additionalInfo : ''\n } Please see our FAQ for more information: https://tina.io/docs/errors/faq/`\n );\n }\n const json = await res.json();\n if (json.errors && errorPolicyDefined === 'throw') {\n throw new Error(\n `Unable to fetch, please see our FAQ for more information: https://tina.io/docs/errors/faq/\n Errors: \\n\\t${json.errors.map((error) => error.message).join('\\n')}`\n );\n }\n const result = {\n data: json?.data as DataType,\n errors: (json?.errors || null) as GraphQLError[] | null,\n query,\n };\n return result;\n}\n\nexport function createClient<GenQueries>(args: TinaClientArgs<GenQueries>) {\n const client = new TinaClient<ReturnType<typeof args.queries>>(args);\n return client;\n}\n"],"names":["key"],"mappings":"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"}
@@ -29,7 +29,7 @@ export type OnNewDocument = (args: {
29
29
  path: string;
30
30
  }) => void;
31
31
  export declare class ContentCreatorPlugin implements AddContentPlugin<FormShape> {
32
- __type: 'content-creator';
32
+ __type: "content-creator";
33
33
  fields: AddContentPlugin<FormShape>['fields'];
34
34
  onNewDocument?: OnNewDocument;
35
35
  onChange: (values: any) => void;