@tinacms/app 2.5.13 → 2.5.15
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/package.json +4 -4
- package/src/global.css +2 -2
- package/src/index.css +5 -5
- package/src/lib/graphql-reducer.ts +11 -13
- package/src/lib/preview-origin.test.ts +16 -9
- package/src/lib/preview-origin.ts +7 -15
- package/src/lib/errors.tsx +0 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinacms/app",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.15",
|
|
4
4
|
"main": "src/main.tsx",
|
|
5
5
|
"files": [
|
|
6
6
|
"src",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@graphiql/toolkit": "^0.11.3",
|
|
29
29
|
"@monaco-editor/loader": "^1.7.0",
|
|
30
30
|
"@radix-ui/react-popover": "^1.1.18",
|
|
31
|
-
"final-form": "
|
|
31
|
+
"final-form": "4.20.10",
|
|
32
32
|
"graphiql": "^4.1.2",
|
|
33
33
|
"graphql": "15.8.0",
|
|
34
34
|
"lucide-react": "^0.424.0",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"react-dom": "^18.3.1",
|
|
37
37
|
"react-router-dom": "^6.30.3",
|
|
38
38
|
"zod": "^3.24.2",
|
|
39
|
-
"
|
|
40
|
-
"tinacms": "^3.
|
|
39
|
+
"tinacms": "^3.14.4",
|
|
40
|
+
"@tinacms/mdx": "^2.3.0"
|
|
41
41
|
},
|
|
42
42
|
"repository": {
|
|
43
43
|
"url": "https://github.com/tinacms/tinacms.git",
|
package/src/global.css
CHANGED
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
--tina-font-weight-regular: 400;
|
|
46
46
|
--tina-font-weight-bold: 600;
|
|
47
47
|
|
|
48
|
-
--tina-shadow-big:
|
|
49
|
-
rgba(0, 0, 0, 0.1);
|
|
48
|
+
--tina-shadow-big:
|
|
49
|
+
0px 2px 3px rgba(0, 0, 0, 0.05), 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
50
50
|
--tina-shadow-small: 0px 2px 3px rgba(0, 0, 0, 0.12);
|
|
51
51
|
|
|
52
52
|
--tina-timing-short: 85ms;
|
package/src/index.css
CHANGED
|
@@ -28,16 +28,16 @@
|
|
|
28
28
|
body {
|
|
29
29
|
margin: 0;
|
|
30
30
|
padding: 0;
|
|
31
|
-
font-family:
|
|
32
|
-
|
|
33
|
-
sans-serif;
|
|
31
|
+
font-family:
|
|
32
|
+
-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu",
|
|
33
|
+
"Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
|
34
34
|
-webkit-font-smoothing: antialiased;
|
|
35
35
|
-moz-osx-font-smoothing: grayscale;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
code {
|
|
39
|
-
font-family:
|
|
40
|
-
monospace;
|
|
39
|
+
font-family:
|
|
40
|
+
source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
div.graphiql-explorer-root > div:last-child {
|
|
@@ -18,14 +18,14 @@ import {
|
|
|
18
18
|
TinaState,
|
|
19
19
|
isSessionExpiredError,
|
|
20
20
|
resolveField,
|
|
21
|
+
showErrorModal,
|
|
21
22
|
useCMS,
|
|
22
23
|
} from 'tinacms';
|
|
23
24
|
import { z } from 'zod';
|
|
24
25
|
import { FormifyCallback, createForm, createGlobalForm } from './build-form';
|
|
25
|
-
import { showErrorModal } from './errors';
|
|
26
26
|
import { expandQuery, isConnectionType, isNodeType } from './expand-query';
|
|
27
27
|
import {
|
|
28
|
-
|
|
28
|
+
getPreviewOrigin,
|
|
29
29
|
isFromTrustedPreviewOrigin,
|
|
30
30
|
postMessageToPreview,
|
|
31
31
|
} from './preview-origin';
|
|
@@ -205,12 +205,9 @@ export const useGraphQLReducer = (
|
|
|
205
205
|
|
|
206
206
|
const activeField = searchParams.get('active-field');
|
|
207
207
|
|
|
208
|
-
//
|
|
208
|
+
// The preview is always loaded from the admin's own origin. Used to validate
|
|
209
209
|
// inbound messages and as the explicit `targetOrigin` for outbound ones.
|
|
210
|
-
const expectedOrigin =
|
|
211
|
-
() => getExpectedPreviewOrigin(url),
|
|
212
|
-
[url]
|
|
213
|
-
);
|
|
210
|
+
const expectedOrigin = getPreviewOrigin();
|
|
214
211
|
|
|
215
212
|
React.useEffect(() => {
|
|
216
213
|
const run = async () => {
|
|
@@ -725,12 +722,13 @@ const onSubmit = async (
|
|
|
725
722
|
} catch (e) {
|
|
726
723
|
// request() already sent the user back to the login modal; no alert over it
|
|
727
724
|
if (isSessionExpiredError(e)) throw e;
|
|
728
|
-
cms.alerts.error(
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
725
|
+
cms.alerts.error(
|
|
726
|
+
() =>
|
|
727
|
+
ErrorDialog({
|
|
728
|
+
message: 'Tina caught an error while updating the page',
|
|
729
|
+
error: e,
|
|
730
|
+
}),
|
|
731
|
+
{ title: 'Save Failed' }
|
|
734
732
|
);
|
|
735
733
|
console.error(e);
|
|
736
734
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
getPreviewOrigin,
|
|
4
4
|
isFromTrustedPreviewOrigin,
|
|
5
5
|
postMessageToPreview,
|
|
6
6
|
} from './preview-origin';
|
|
7
7
|
|
|
8
|
-
const ADMIN = 'https://admin.example';
|
|
9
8
|
const PREVIEW = 'https://preview.example';
|
|
10
9
|
|
|
11
10
|
// A stand-in for the iframe's content window; we only need an identity to
|
|
@@ -15,15 +14,23 @@ const makePeerWindow = () =>
|
|
|
15
14
|
postMessage: ReturnType<typeof vi.fn>;
|
|
16
15
|
};
|
|
17
16
|
|
|
18
|
-
describe('
|
|
19
|
-
it('
|
|
20
|
-
expect(
|
|
17
|
+
describe('getPreviewOrigin', () => {
|
|
18
|
+
it('is the origin the admin itself is served from', () => {
|
|
19
|
+
expect(getPreviewOrigin()).toBe(window.location.origin);
|
|
21
20
|
});
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
/**
|
|
23
|
+
* The origin used to be resolved from the preview URL, so a URL naming
|
|
24
|
+
* another origin moved the trust anchor to it. The preview is always loaded
|
|
25
|
+
* from the admin's own origin, so nothing it carries is consulted here.
|
|
26
|
+
*/
|
|
27
|
+
it('takes no argument that could name another origin', () => {
|
|
28
|
+
expect(getPreviewOrigin.length).toBe(0);
|
|
29
|
+
expect(
|
|
30
|
+
(getPreviewOrigin as (...args: unknown[]) => string)(
|
|
31
|
+
`${PREVIEW}/posts/hello`
|
|
32
|
+
)
|
|
33
|
+
).toBe(window.location.origin);
|
|
27
34
|
});
|
|
28
35
|
});
|
|
29
36
|
|
|
@@ -7,23 +7,15 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Returns the origin
|
|
10
|
+
* Returns the origin the preview iframe is allowed to be on.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* origin.
|
|
12
|
+
* The admin only ever loads the preview from its own origin, so this is that
|
|
13
|
+
* origin and nothing else. It is deliberately not derived from the preview URL:
|
|
14
|
+
* reading the trust anchor out of a value the URL supplies is what allowed a
|
|
15
|
+
* crafted link to nominate the origin it would then be trusted from.
|
|
14
16
|
*/
|
|
15
|
-
export const
|
|
16
|
-
|
|
17
|
-
baseOrigin: string = typeof window !== 'undefined'
|
|
18
|
-
? window.location.origin
|
|
19
|
-
: ''
|
|
20
|
-
): string => {
|
|
21
|
-
try {
|
|
22
|
-
return new URL(url, baseOrigin || undefined).origin;
|
|
23
|
-
} catch {
|
|
24
|
-
return baseOrigin;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
17
|
+
export const getPreviewOrigin = (): string =>
|
|
18
|
+
typeof window !== 'undefined' ? window.location.origin : '';
|
|
27
19
|
|
|
28
20
|
/**
|
|
29
21
|
* Checks whether a MessageEvent came from the trusted preview iframe.
|
package/src/lib/errors.tsx
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { TinaCMS } from 'tinacms';
|
|
3
|
-
|
|
4
|
-
const TROUBLESHOOTING_URL = 'https://tina.io/docs/tinacloud/troubleshooting';
|
|
5
|
-
|
|
6
|
-
const ErrorModalContent = (props: { title: string; message: string }) => {
|
|
7
|
-
const { title, message } = props;
|
|
8
|
-
return (
|
|
9
|
-
<>
|
|
10
|
-
<div>{title}</div>
|
|
11
|
-
<p>{message}</p>
|
|
12
|
-
<a href={TROUBLESHOOTING_URL} target='_blank' rel='noopener noreferrer'>
|
|
13
|
-
Try these troubleshooting tips
|
|
14
|
-
</a>
|
|
15
|
-
</>
|
|
16
|
-
);
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export const showErrorModal = (
|
|
20
|
-
title: string,
|
|
21
|
-
message: string,
|
|
22
|
-
cms: TinaCMS
|
|
23
|
-
) => {
|
|
24
|
-
if (cms.alerts.all.some((a: { level: string }) => a.level === 'error'))
|
|
25
|
-
return;
|
|
26
|
-
cms.alerts.error(() => <ErrorModalContent title={title} message={message} />);
|
|
27
|
-
};
|