@tinacms/schema-tools 2.8.1 → 2.8.3

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.
@@ -0,0 +1,37 @@
1
+ /** Path-collision fragment thrown by the @tinacms/graphql resolver. */
2
+ export declare const ERR_ALREADY_EXISTS = "already exists";
3
+ /** AsyncPoller lifecycle signals (tinacms internalClient). */
4
+ export declare const ASYNC_POLLER_ERROR: {
5
+ readonly CANCELLED: "AsyncPoller: cancelled";
6
+ readonly TIMEOUT: "AsyncPoller: reached timeout";
7
+ readonly STATUS_UNKNOWN: "AsyncPoller: status unknown for too long, please check indexing progress on the TinaCloud dashboard";
8
+ };
9
+ export type AsyncPollerError = (typeof ASYNC_POLLER_ERROR)[keyof typeof ASYNC_POLLER_ERROR];
10
+ /**
11
+ * Filesystem path-traversal prefix (CWE-22). The full emitted message MUST
12
+ * keep this exact prefix — do not reword.
13
+ *
14
+ * The path-traversal producers (the @tinacms/graphql filesystem and isomorphic
15
+ * bridges, and the @tinacms/cli path guard) inline this literal rather than
16
+ * importing the constant: those modules are loaded by jest from source across a
17
+ * package boundary, where importing the schema-tools ESM build throws "Cannot
18
+ * use import statement outside a module". This is the canonical reference for
19
+ * the string; keep the inlined literals byte-identical to it. The real contract
20
+ * is enforced by the `toThrow('Path traversal detected')` assertions in the
21
+ * bridge and CLI suites, not by this constant.
22
+ */
23
+ export declare const ERR_PATH_TRAVERSAL = "Path traversal detected";
24
+ /** TinaCloud: a document still has inbound references on delete/rename. */
25
+ export declare const ERR_HAS_REFERENCES = "has references";
26
+ /** TinaCloud: the branch schema has not finished indexing. */
27
+ export declare const ERR_NOT_INDEXED = "has not been indexed by TinaCloud";
28
+ /** TinaCloud: a branch with the given name already exists (editorial workflow). */
29
+ export declare const ERR_BRANCH_EXISTS = "already exists";
30
+ /**
31
+ * TinaCloud: branch-name conflict (editorial workflow fallback path). Broad by
32
+ * necessity — this matches the substring of an external server message we do
33
+ * not own, so it cannot be narrowed without risking a missed match. The
34
+ * structured `errorCode` switch above is the preferred path; this is the
35
+ * no-code fallback.
36
+ */
37
+ export declare const ERR_BRANCH_CONFLICT = "conflict";
package/dist/index.d.ts CHANGED
@@ -4,4 +4,6 @@ export * from './validate';
4
4
  export * from './util/namer';
5
5
  export * from './util/parseURL';
6
6
  export * from './util/normalizePath';
7
+ export * from './util/relativePath';
7
8
  export * from './util/headingLevels';
9
+ export * from './errors';
package/dist/index.js CHANGED
@@ -1627,7 +1627,7 @@ const parseURL = (url) => {
1627
1627
  if (!isTinaCloud) {
1628
1628
  return {
1629
1629
  branch: null,
1630
- isLocalClient: true,
1630
+ isLocalClient: false,
1631
1631
  clientId: null,
1632
1632
  host: params.host
1633
1633
  };
@@ -1642,7 +1642,7 @@ const parseURL = (url) => {
1642
1642
  const clientId = result == null ? void 0 : result.clientId;
1643
1643
  if (!branch || !clientId) {
1644
1644
  throw new Error(
1645
- `Invalid URL format provided. Expected: https://content.tinajs.io/<Version>/content/<ClientID>/github/<Branch> but but received ${url}`
1645
+ `Invalid URL format provided. Expected: https://content.tinajs.io/<Version>/content/<ClientID>/github/<Branch> but received ${url}`
1646
1646
  );
1647
1647
  }
1648
1648
  return {
@@ -2812,6 +2812,9 @@ const validateSchema = ({ schema }) => {
2812
2812
  throw new Error(e);
2813
2813
  }
2814
2814
  };
2815
+ const RELATIVE_PATH_REGEX = /^[a-zA-Z0-9\-_./]+$/;
2816
+ const RELATIVE_PATH_ALLOWED_CHARS_MESSAGE = "Must contain only a-z, A-Z, 0-9, -, _, ., or /.";
2817
+ const isValidRelativePath = (value) => RELATIVE_PATH_REGEX.test(value);
2815
2818
  const isHeadingLevel = (value) => {
2816
2819
  switch (value) {
2817
2820
  case "h1":
@@ -2833,16 +2836,37 @@ const normalizeHeadingLevels = (configured) => {
2833
2836
  }
2834
2837
  return Array.from(seen);
2835
2838
  };
2839
+ const ERR_ALREADY_EXISTS = "already exists";
2840
+ const ASYNC_POLLER_ERROR = {
2841
+ CANCELLED: "AsyncPoller: cancelled",
2842
+ TIMEOUT: "AsyncPoller: reached timeout",
2843
+ STATUS_UNKNOWN: "AsyncPoller: status unknown for too long, please check indexing progress on the TinaCloud dashboard"
2844
+ };
2845
+ const ERR_PATH_TRAVERSAL = "Path traversal detected";
2846
+ const ERR_HAS_REFERENCES = "has references";
2847
+ const ERR_NOT_INDEXED = "has not been indexed by TinaCloud";
2848
+ const ERR_BRANCH_EXISTS = "already exists";
2849
+ const ERR_BRANCH_CONFLICT = "conflict";
2836
2850
  export {
2837
2851
  ALL_HEADING_LEVELS,
2852
+ ASYNC_POLLER_ERROR,
2838
2853
  CONTENT_FORMATS,
2854
+ ERR_ALREADY_EXISTS,
2855
+ ERR_BRANCH_CONFLICT,
2856
+ ERR_BRANCH_EXISTS,
2857
+ ERR_HAS_REFERENCES,
2858
+ ERR_NOT_INDEXED,
2859
+ ERR_PATH_TRAVERSAL,
2839
2860
  NAMER,
2861
+ RELATIVE_PATH_ALLOWED_CHARS_MESSAGE,
2862
+ RELATIVE_PATH_REGEX,
2840
2863
  TINA_HOST,
2841
2864
  TinaSchema,
2842
2865
  TinaSchemaValidationError,
2843
2866
  addNamespaceToSchema,
2844
2867
  canonicalPath,
2845
2868
  isHeadingLevel,
2869
+ isValidRelativePath,
2846
2870
  normalizeHeadingLevels,
2847
2871
  normalizePath,
2848
2872
  parseURL,
@@ -446,6 +446,14 @@ interface AuthHooks {
446
446
  }
447
447
  type AuthOptions = AuthHooks & AuthProvider;
448
448
  export interface Config<CMSCallback = undefined, FormifyCallback = undefined, DocumentCreatorCallback = undefined, Store = undefined, SearchClient = undefined> {
449
+ /**
450
+ * Points the admin UI at a custom/self-hosted content API instead of TinaCloud.
451
+ *
452
+ * Can be a relative URL, such as `/api/tina/gql`, or an absolute URL, such as
453
+ * `https://example.com/api/content`. When set, the admin UI will not show the
454
+ * Local Mode banner; Local Mode is only detected when this option is unset and
455
+ * the content API resolves to `localhost`.
456
+ */
449
457
  contentApiUrlOverride?: string;
450
458
  authProvider?: AuthProvider;
451
459
  admin?: {
@@ -0,0 +1,6 @@
1
+ /** Allowlist for a relativePath segment (filename or folder name); source of truth shared with the resolver's validateRelativePath so the UI can reject invalid names inline. */
2
+ export declare const RELATIVE_PATH_REGEX: RegExp;
3
+ /** Inline form-validation message for {@link RELATIVE_PATH_REGEX}. */
4
+ export declare const RELATIVE_PATH_ALLOWED_CHARS_MESSAGE = "Must contain only a-z, A-Z, 0-9, -, _, ., or /.";
5
+ /** True when `value` contains only characters allowed in a relativePath. */
6
+ export declare const isValidRelativePath: (value: string) => boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tinacms/schema-tools",
3
3
  "type": "module",
4
- "version": "2.8.1",
4
+ "version": "2.8.3",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "files": [
@@ -24,7 +24,7 @@
24
24
  "ts-jest": "^29.2.5",
25
25
  "typescript": "^5.7.3",
26
26
  "yup": "^1.6.1",
27
- "@tinacms/scripts": "1.6.1"
27
+ "@tinacms/scripts": "1.6.2"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "react": ">=16.14.0",