@cmssy/core 5.0.0

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,63 @@
1
+ 'use strict';
2
+
3
+ // src/testing/edit-smoke.ts
4
+ var EDITOR_MARKER = /CmssyEditor|cmssy-edit/;
5
+ var SERVER_CHROME = /<header|<footer/;
6
+ async function html(url) {
7
+ const response = await fetch(url, { redirect: "manual" });
8
+ return { status: response.status, body: await response.text() };
9
+ }
10
+ async function checkCmssyEditMode(options) {
11
+ const { baseUrl, secret, path = "/" } = options;
12
+ const failures = [];
13
+ const url = (suffix) => `${baseUrl.replace(/\/+$/, "")}${suffix}`;
14
+ const publicPage = await html(url(path));
15
+ if (publicPage.status !== 200) {
16
+ failures.push(`public ${path}: expected 200, got ${publicPage.status}`);
17
+ }
18
+ if (EDITOR_MARKER.test(publicPage.body)) {
19
+ failures.push(`public ${path}: the editor is mounted on a public page`);
20
+ }
21
+ const hasServerChrome = SERVER_CHROME.test(publicPage.body);
22
+ const unverified = await html(url(`${path}?cmssyEdit=1`));
23
+ if (EDITOR_MARKER.test(unverified.body)) {
24
+ failures.push(
25
+ `${path}?cmssyEdit=1: edit mode without a secret - an unverified request must not open the editor (CMS-948)`
26
+ );
27
+ }
28
+ const verified = await html(
29
+ url(`${path}?cmssyEdit=1&cmssySecret=${encodeURIComponent(secret)}`)
30
+ );
31
+ if (verified.status !== 200) {
32
+ failures.push(`edit ${path}: expected 200, got ${verified.status}`);
33
+ }
34
+ if (!EDITOR_MARKER.test(verified.body)) {
35
+ failures.push(
36
+ `edit ${path}: no editor in the response - is the /cmssy-edit route mounted?`
37
+ );
38
+ }
39
+ if (hasServerChrome && SERVER_CHROME.test(verified.body)) {
40
+ failures.push(
41
+ `edit ${path}: the chrome is still server-rendered - the header and footer will be selectable but have no fields (is CMSSY_EDIT_HEADER set on the rewrite?)`
42
+ );
43
+ }
44
+ const { localizedPath, localizedMarker } = options;
45
+ if (localizedPath && localizedMarker) {
46
+ const localized = await html(
47
+ url(
48
+ `${localizedPath}?cmssyEdit=1&cmssySecret=${encodeURIComponent(secret)}`
49
+ )
50
+ );
51
+ if (!EDITOR_MARKER.test(localized.body)) {
52
+ failures.push(`edit ${localizedPath}: no editor in the response`);
53
+ }
54
+ if (!localized.body.includes(localizedMarker)) {
55
+ failures.push(
56
+ `edit ${localizedPath}: "${localizedMarker}" is missing - the preview renders in the default language, not the one the URL asks for`
57
+ );
58
+ }
59
+ }
60
+ return { ok: failures.length === 0, failures };
61
+ }
62
+
63
+ exports.checkCmssyEditMode = checkCmssyEditMode;
@@ -0,0 +1,39 @@
1
+ interface EditSmokeOptions {
2
+ /** A running build of the consumer app, e.g. http://localhost:3000. */
3
+ baseUrl: string;
4
+ /** The site's CMSSY_DRAFT_SECRET. Without it nothing can be verified. */
5
+ secret: string;
6
+ /** A published page to exercise. Defaults to "/". */
7
+ path?: string;
8
+ /**
9
+ * The same page under a language prefix, e.g. "/no". Pass it on a site whose
10
+ * URLs carry the language, and the check also proves the preview renders in
11
+ * THAT language rather than the default one.
12
+ */
13
+ localizedPath?: string;
14
+ /** A word only the localized page says - "Handlekurv", say. */
15
+ localizedMarker?: string;
16
+ }
17
+ interface EditSmokeResult {
18
+ ok: boolean;
19
+ failures: string[];
20
+ }
21
+ /**
22
+ * Proves a consumer app's EDIT path still works - the path a build cannot check,
23
+ * because the site compiles and serves fine while being uneditable.
24
+ *
25
+ * It asserts three independent things:
26
+ * 1. the public page renders WITHOUT the editor, chrome server-rendered;
27
+ * 2. a bare `?cmssyEdit=1` does NOT enter edit mode (an unverified pair must
28
+ * not open the door - CMS-948);
29
+ * 3. a verified `cmssyEdit=1` + `cmssySecret` renders the editor AND moves the
30
+ * chrome onto the edit bridge.
31
+ *
32
+ * Run it against a started production build:
33
+ *
34
+ * const result = await checkCmssyEditMode({ baseUrl, secret });
35
+ * expect(result.failures).toEqual([]);
36
+ */
37
+ declare function checkCmssyEditMode(options: EditSmokeOptions): Promise<EditSmokeResult>;
38
+
39
+ export { type EditSmokeOptions, type EditSmokeResult, checkCmssyEditMode };
@@ -0,0 +1,39 @@
1
+ interface EditSmokeOptions {
2
+ /** A running build of the consumer app, e.g. http://localhost:3000. */
3
+ baseUrl: string;
4
+ /** The site's CMSSY_DRAFT_SECRET. Without it nothing can be verified. */
5
+ secret: string;
6
+ /** A published page to exercise. Defaults to "/". */
7
+ path?: string;
8
+ /**
9
+ * The same page under a language prefix, e.g. "/no". Pass it on a site whose
10
+ * URLs carry the language, and the check also proves the preview renders in
11
+ * THAT language rather than the default one.
12
+ */
13
+ localizedPath?: string;
14
+ /** A word only the localized page says - "Handlekurv", say. */
15
+ localizedMarker?: string;
16
+ }
17
+ interface EditSmokeResult {
18
+ ok: boolean;
19
+ failures: string[];
20
+ }
21
+ /**
22
+ * Proves a consumer app's EDIT path still works - the path a build cannot check,
23
+ * because the site compiles and serves fine while being uneditable.
24
+ *
25
+ * It asserts three independent things:
26
+ * 1. the public page renders WITHOUT the editor, chrome server-rendered;
27
+ * 2. a bare `?cmssyEdit=1` does NOT enter edit mode (an unverified pair must
28
+ * not open the door - CMS-948);
29
+ * 3. a verified `cmssyEdit=1` + `cmssySecret` renders the editor AND moves the
30
+ * chrome onto the edit bridge.
31
+ *
32
+ * Run it against a started production build:
33
+ *
34
+ * const result = await checkCmssyEditMode({ baseUrl, secret });
35
+ * expect(result.failures).toEqual([]);
36
+ */
37
+ declare function checkCmssyEditMode(options: EditSmokeOptions): Promise<EditSmokeResult>;
38
+
39
+ export { type EditSmokeOptions, type EditSmokeResult, checkCmssyEditMode };
@@ -0,0 +1,61 @@
1
+ // src/testing/edit-smoke.ts
2
+ var EDITOR_MARKER = /CmssyEditor|cmssy-edit/;
3
+ var SERVER_CHROME = /<header|<footer/;
4
+ async function html(url) {
5
+ const response = await fetch(url, { redirect: "manual" });
6
+ return { status: response.status, body: await response.text() };
7
+ }
8
+ async function checkCmssyEditMode(options) {
9
+ const { baseUrl, secret, path = "/" } = options;
10
+ const failures = [];
11
+ const url = (suffix) => `${baseUrl.replace(/\/+$/, "")}${suffix}`;
12
+ const publicPage = await html(url(path));
13
+ if (publicPage.status !== 200) {
14
+ failures.push(`public ${path}: expected 200, got ${publicPage.status}`);
15
+ }
16
+ if (EDITOR_MARKER.test(publicPage.body)) {
17
+ failures.push(`public ${path}: the editor is mounted on a public page`);
18
+ }
19
+ const hasServerChrome = SERVER_CHROME.test(publicPage.body);
20
+ const unverified = await html(url(`${path}?cmssyEdit=1`));
21
+ if (EDITOR_MARKER.test(unverified.body)) {
22
+ failures.push(
23
+ `${path}?cmssyEdit=1: edit mode without a secret - an unverified request must not open the editor (CMS-948)`
24
+ );
25
+ }
26
+ const verified = await html(
27
+ url(`${path}?cmssyEdit=1&cmssySecret=${encodeURIComponent(secret)}`)
28
+ );
29
+ if (verified.status !== 200) {
30
+ failures.push(`edit ${path}: expected 200, got ${verified.status}`);
31
+ }
32
+ if (!EDITOR_MARKER.test(verified.body)) {
33
+ failures.push(
34
+ `edit ${path}: no editor in the response - is the /cmssy-edit route mounted?`
35
+ );
36
+ }
37
+ if (hasServerChrome && SERVER_CHROME.test(verified.body)) {
38
+ failures.push(
39
+ `edit ${path}: the chrome is still server-rendered - the header and footer will be selectable but have no fields (is CMSSY_EDIT_HEADER set on the rewrite?)`
40
+ );
41
+ }
42
+ const { localizedPath, localizedMarker } = options;
43
+ if (localizedPath && localizedMarker) {
44
+ const localized = await html(
45
+ url(
46
+ `${localizedPath}?cmssyEdit=1&cmssySecret=${encodeURIComponent(secret)}`
47
+ )
48
+ );
49
+ if (!EDITOR_MARKER.test(localized.body)) {
50
+ failures.push(`edit ${localizedPath}: no editor in the response`);
51
+ }
52
+ if (!localized.body.includes(localizedMarker)) {
53
+ failures.push(
54
+ `edit ${localizedPath}: "${localizedMarker}" is missing - the preview renders in the default language, not the one the URL asks for`
55
+ );
56
+ }
57
+ }
58
+ return { ok: failures.length === 0, failures };
59
+ }
60
+
61
+ export { checkCmssyEditMode };
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@cmssy/core",
3
+ "version": "5.0.0",
4
+ "description": "Framework-agnostic cmssy client: content, commerce, config, editor protocol. No React, no Next.",
5
+ "keywords": [
6
+ "cmssy",
7
+ "cms",
8
+ "headless",
9
+ "graphql",
10
+ "client"
11
+ ],
12
+ "homepage": "https://cmssy.com",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/cmssy-io/cmssy-sdk.git",
16
+ "directory": "packages/core"
17
+ },
18
+ "type": "module",
19
+ "license": "MIT",
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "sideEffects": false,
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "import": "./dist/index.js",
28
+ "require": "./dist/index.cjs"
29
+ },
30
+ "./testing": {
31
+ "types": "./dist/testing.d.ts",
32
+ "import": "./dist/testing.js",
33
+ "require": "./dist/testing.cjs"
34
+ }
35
+ },
36
+ "main": "./dist/index.cjs",
37
+ "module": "./dist/index.js",
38
+ "types": "./dist/index.d.ts",
39
+ "files": [
40
+ "dist"
41
+ ],
42
+ "devDependencies": {
43
+ "@types/node": "^20.0.0",
44
+ "graphql": "^16.10.0",
45
+ "tsup": "^8.3.0",
46
+ "typescript": "^5.6.0",
47
+ "vitest": "^2.1.0"
48
+ },
49
+ "dependencies": {
50
+ "@cmssy/types": "0.27.0",
51
+ "jose": "^6.2.3"
52
+ },
53
+ "scripts": {
54
+ "build": "tsup",
55
+ "test": "vitest run",
56
+ "typecheck": "tsc --noEmit"
57
+ }
58
+ }