@alpaca-headless/alpaca-headless-nextjs 0.0.4 → 1.0.13

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 (139) hide show
  1. package/dist/cjs/components/Image.js +36 -0
  2. package/dist/cjs/components/Link.js +22 -0
  3. package/dist/cjs/components/Picture.js +119 -0
  4. package/dist/cjs/components/PictureEditor.js +43 -0
  5. package/dist/cjs/components/Placeholder.js +40 -4
  6. package/dist/cjs/components/RichText.js +44 -0
  7. package/dist/cjs/components/RichTextEditor.js +82 -0
  8. package/dist/cjs/components/Slot.js +8 -0
  9. package/dist/cjs/components/Text.js +24 -4
  10. package/dist/cjs/components/TextEditor.js +68 -0
  11. package/dist/cjs/components/Translate.js +14 -0
  12. package/dist/cjs/components/index.js +5 -0
  13. package/dist/cjs/editor/AiTerminal.js +150 -0
  14. package/dist/cjs/editor/ComponentInfo.js +14 -0
  15. package/dist/cjs/editor/ComponentPalette.js +78 -0
  16. package/dist/cjs/editor/ComponentTree.js +200 -0
  17. package/dist/cjs/editor/ContentTree.js +120 -0
  18. package/dist/cjs/editor/Debug.js +16 -0
  19. package/dist/cjs/editor/DictionaryEditor.js +35 -0
  20. package/dist/cjs/editor/EditFrame.js +61 -0
  21. package/dist/cjs/editor/EditHistory.js +30 -0
  22. package/dist/cjs/editor/Editor.js +27 -0
  23. package/dist/cjs/editor/EditorClient.js +457 -0
  24. package/dist/cjs/editor/EditorClientHost.js +37 -0
  25. package/dist/cjs/editor/FieldList.js +59 -0
  26. package/dist/cjs/editor/GraphQL.js +90 -0
  27. package/dist/cjs/editor/LanguageSelector.js +21 -0
  28. package/dist/cjs/editor/MediaSelector.js +61 -0
  29. package/dist/cjs/editor/PageInfo.js +12 -0
  30. package/dist/cjs/editor/PlaceholderDropZone.js +54 -0
  31. package/dist/cjs/editor/PlaceholderDropZoneHost.js +37 -0
  32. package/dist/cjs/editor/Terminal.js +51 -0
  33. package/dist/cjs/editor/TranslateEditor.js +25 -0
  34. package/dist/cjs/editor/VersionSelector.js +21 -0
  35. package/dist/cjs/editor/componentTreeHelper.js +18 -0
  36. package/dist/cjs/editor/contentService.js +38 -0
  37. package/dist/cjs/editor/editContext.js +35 -0
  38. package/dist/cjs/editor/editService.js +150 -0
  39. package/dist/cjs/editor/fieldTypes/RichTextEditor.js +19 -0
  40. package/dist/cjs/editor/fieldTypes/SingleLineText.js +17 -0
  41. package/dist/cjs/editor/index.js +18 -0
  42. package/dist/cjs/graphQLTypes.js +2 -0
  43. package/dist/cjs/index.js +15 -0
  44. package/dist/cjs/loadRouteData.js +98 -40
  45. package/dist/cjs/mediaProtection.js +56 -0
  46. package/dist/editor.css +120 -0
  47. package/dist/esm/components/Image.js +32 -0
  48. package/dist/esm/components/Link.js +18 -0
  49. package/dist/esm/components/Picture.js +115 -0
  50. package/dist/esm/components/PictureEditor.js +39 -0
  51. package/dist/esm/components/Placeholder.js +38 -5
  52. package/dist/esm/components/RichText.js +37 -0
  53. package/dist/esm/components/RichTextEditor.js +55 -0
  54. package/dist/esm/components/Slot.js +5 -0
  55. package/dist/esm/components/Text.js +24 -4
  56. package/dist/esm/components/TextEditor.js +41 -0
  57. package/dist/esm/components/Translate.js +10 -0
  58. package/dist/esm/components/index.js +5 -0
  59. package/dist/esm/editor/AiTerminal.js +146 -0
  60. package/dist/esm/editor/ComponentInfo.js +10 -0
  61. package/dist/esm/editor/ComponentPalette.js +71 -0
  62. package/dist/esm/editor/ComponentTree.js +196 -0
  63. package/dist/esm/editor/ContentTree.js +117 -0
  64. package/dist/esm/editor/Debug.js +9 -0
  65. package/dist/esm/editor/DictionaryEditor.js +31 -0
  66. package/dist/esm/editor/EditFrame.js +57 -0
  67. package/dist/esm/editor/EditHistory.js +26 -0
  68. package/dist/esm/editor/Editor.js +23 -0
  69. package/dist/esm/editor/EditorClient.js +450 -0
  70. package/dist/esm/editor/EditorClientHost.js +7 -0
  71. package/dist/esm/editor/FieldList.js +55 -0
  72. package/dist/esm/editor/GraphQL.js +83 -0
  73. package/dist/esm/editor/LanguageSelector.js +17 -0
  74. package/dist/esm/editor/MediaSelector.js +54 -0
  75. package/dist/esm/editor/PageInfo.js +8 -0
  76. package/dist/esm/editor/PlaceholderDropZone.js +50 -0
  77. package/dist/esm/editor/PlaceholderDropZoneHost.js +7 -0
  78. package/dist/esm/editor/Terminal.js +47 -0
  79. package/dist/esm/editor/TranslateEditor.js +21 -0
  80. package/dist/esm/editor/VersionSelector.js +17 -0
  81. package/dist/esm/editor/componentTreeHelper.js +14 -0
  82. package/dist/esm/editor/contentService.js +31 -0
  83. package/dist/esm/editor/editContext.js +5 -0
  84. package/dist/esm/editor/editService.js +139 -0
  85. package/dist/esm/editor/fieldTypes/RichTextEditor.js +15 -0
  86. package/dist/esm/editor/fieldTypes/SingleLineText.js +13 -0
  87. package/dist/esm/editor/index.js +2 -0
  88. package/dist/esm/graphQLTypes.js +1 -0
  89. package/dist/esm/index.js +2 -0
  90. package/dist/esm/loadRouteData.js +97 -39
  91. package/dist/esm/mediaProtection.js +49 -0
  92. package/package.json +16 -4
  93. package/types/alpacaContext.d.ts +11 -0
  94. package/types/components/Image.d.ts +10 -0
  95. package/types/components/Link.d.ts +6 -0
  96. package/types/components/Picture.d.ts +20 -0
  97. package/types/components/PictureEditor.d.ts +3 -0
  98. package/types/components/RichText.d.ts +7 -0
  99. package/types/components/RichTextEditor.d.ts +296 -0
  100. package/types/components/Slot.d.ts +4 -0
  101. package/types/components/Text.d.ts +3 -2
  102. package/types/components/TextEditor.d.ts +296 -0
  103. package/types/components/Translate.d.ts +3 -0
  104. package/types/components/index.d.ts +5 -0
  105. package/types/editor/AiTerminal.d.ts +4 -0
  106. package/types/editor/ComponentInfo.d.ts +4 -0
  107. package/types/editor/ComponentPalette.d.ts +7 -0
  108. package/types/editor/ComponentTree.d.ts +5 -0
  109. package/types/editor/ContentTree.d.ts +13 -0
  110. package/types/editor/Debug.d.ts +6 -0
  111. package/types/editor/DictionaryEditor.d.ts +3 -0
  112. package/types/editor/EditFrame.d.ts +6 -0
  113. package/types/editor/EditHistory.d.ts +4 -0
  114. package/types/editor/Editor.d.ts +6 -0
  115. package/types/editor/EditorClient.d.ts +9 -0
  116. package/types/editor/EditorClientHost.d.ts +8 -0
  117. package/types/editor/FieldList.d.ts +4 -0
  118. package/types/editor/GraphQL.d.ts +5 -0
  119. package/types/editor/LanguageSelector.d.ts +5 -0
  120. package/types/editor/MediaSelector.d.ts +5 -0
  121. package/types/editor/PageInfo.d.ts +4 -0
  122. package/types/editor/PlaceholderDropZone.d.ts +6 -0
  123. package/types/editor/PlaceholderDropZoneHost.d.ts +6 -0
  124. package/types/editor/Terminal.d.ts +4 -0
  125. package/types/editor/TranslateEditor.d.ts +3 -0
  126. package/types/editor/VersionSelector.d.ts +5 -0
  127. package/types/editor/componentTreeHelper.d.ts +2 -0
  128. package/types/editor/contentService.d.ts +14 -0
  129. package/types/editor/editContext.d.ts +81 -0
  130. package/types/editor/editService.d.ts +12 -0
  131. package/types/editor/fieldTypes/RichTextEditor.d.ts +4 -0
  132. package/types/editor/fieldTypes/SingleLineText.d.ts +4 -0
  133. package/types/editor/index.d.ts +2 -0
  134. package/types/fieldTypes.d.ts +63 -1
  135. package/types/graphQLTypes.d.ts +24 -0
  136. package/types/index.d.ts +2 -0
  137. package/types/layoutData.d.ts +56 -1
  138. package/types/loadRouteData.d.ts +30 -1
  139. package/types/mediaProtection.d.ts +2 -0
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ export function PageInfo({ page }) {
4
+ var _a;
5
+ if (!(page === null || page === void 0 ? void 0 : page.fields))
6
+ return;
7
+ return (_jsxs("div", { className: "p-1", children: [_jsx("h2", { className: "text-xl font-bold my-2", children: page.path }), _jsxs("div", { className: "text-xs", children: ["ID: ", page.id] }), _jsxs("div", { className: "text-xs", children: ["Language: ", page.language] }), _jsxs("div", { className: "text-xs", children: ["Version: ", page.version] }), page.translations && (_jsxs("div", { className: "text-xs", children: ["Languages: ", (_a = page.translations) === null || _a === void 0 ? void 0 : _a.join(", ")] }))] }));
8
+ }
@@ -0,0 +1,50 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ import { ProgressBar } from "primereact/progressbar";
5
+ import { useEditContext } from "..";
6
+ export function PlaceholderDropZone({ placeholder, index, parentName, }) {
7
+ const [isInserting, setIsInserting] = useState(false);
8
+ const [isSelected, setIsSelected] = useState(false);
9
+ const editContext = useEditContext();
10
+ if (!editContext)
11
+ return;
12
+ const { selection, refreshCompletedFlag, dragObject, selectedForInsertion } = editContext;
13
+ function isAnyPlaceholderSelected() {
14
+ return selection.find((x) => x.indexOf("_") > 0) != undefined;
15
+ }
16
+ useEffect(() => {
17
+ setIsInserting(false);
18
+ }, [refreshCompletedFlag]);
19
+ useEffect(() => {
20
+ var _a;
21
+ const isSelectedForInsertion = editContext.selectedForInsertion.length > 0 &&
22
+ placeholder.key.indexOf(editContext.selectedForInsertion) >= 0;
23
+ const dragObjectAllowed = (editContext.dragObject ? true : false) &&
24
+ ((_a = placeholder.insertOptions) === null || _a === void 0 ? void 0 : _a.find((x) => { var _a; return x.id == ((_a = editContext.dragObject) === null || _a === void 0 ? void 0 : _a.templateId); })) != undefined;
25
+ const selected = (isSelectedForInsertion ||
26
+ (!isAnyPlaceholderSelected() && editContext.dragObject != undefined)) &&
27
+ (!editContext.dragObject ? true : false || dragObjectAllowed);
28
+ setIsSelected(selected);
29
+ }, [selection, dragObject, selectedForInsertion, editContext]);
30
+ function dragOver(ev) {
31
+ var _a;
32
+ ev.dataTransfer.dropEffect =
33
+ ((_a = editContext === null || editContext === void 0 ? void 0 : editContext.dragObject) === null || _a === void 0 ? void 0 : _a.type) == "template" ? "copy" : "move";
34
+ ev.preventDefault();
35
+ }
36
+ function drop(ev) {
37
+ ev.preventDefault();
38
+ setIsInserting(true);
39
+ editContext.droppedInPlaceholder(placeholder.key, index);
40
+ }
41
+ if (isInserting)
42
+ return (_jsx("div", { className: " bg-gray-200 p-10", children: _jsx(ProgressBar, { mode: "indeterminate", style: { height: "6px" } }) }));
43
+ return (_jsx("div", { onClick: (ev) => {
44
+ // editContext.setSelectedForInsertion(placeholder.key + "_" + index);
45
+ editContext.openComponentPalette();
46
+ ev.stopPropagation();
47
+ }, onDragOver: dragOver, onDrop: drop,
48
+ // ref={setNodeRef}
49
+ className: `ape-placeholder ${isSelected ? "" : "ape-hidden"}`, children: _jsx("div", { className: "p-6 max-w-sm mx-auto bg-white rounded-xl shadow-md flex items-center space-x-4", children: _jsxs("div", { children: [_jsxs("div", { className: "text-xl font-medium text-black", children: ["Placeholder ", parentName, " / ", placeholder.name, " ", index] }), _jsx("p", { className: "text-gray-500", children: "You can add your components here." })] }) }) }));
50
+ }
@@ -0,0 +1,7 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import dynamic from "next/dynamic";
4
+ const PlaceholderDropZone = dynamic(() => import("./PlaceholderDropZone").then((dnd) => dnd.PlaceholderDropZone), { ssr: false });
5
+ export function PlaceholderDropZoneHost({ placeholder, index, parentName, }) {
6
+ return (_jsx(PlaceholderDropZone, { placeholder: placeholder, index: index, parentName: parentName }));
7
+ }
@@ -0,0 +1,47 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { InputTextarea } from "primereact/inputtextarea";
4
+ import { useEffect, useRef, useState } from "react";
5
+ export function Terminal({ commandHandler, onReset, }) {
6
+ const [value, setValue] = useState("");
7
+ const [response, setResponse] = useState();
8
+ const [messages, setMessages] = useState([]);
9
+ const bottomRef = useRef(null);
10
+ const messageRef = useRef(messages);
11
+ useEffect(() => {
12
+ messageRef.current = messages;
13
+ }, [messages]);
14
+ const callback = (text, finished) => {
15
+ if (!finished)
16
+ setResponse(text);
17
+ else {
18
+ setResponse(undefined);
19
+ setMessages([...messageRef.current, { type: "response", text }]);
20
+ }
21
+ };
22
+ const handleKeyPress = (e) => {
23
+ if (e.key === "Enter" && !e.shiftKey) {
24
+ e.preventDefault(); // Prevent newline insertion
25
+ setMessages([...messages, { type: "command", text: value }]);
26
+ setValue("");
27
+ setResponse("...");
28
+ commandHandler(value, callback);
29
+ }
30
+ };
31
+ useEffect(() => {
32
+ var _a;
33
+ // 👇️ scroll to bottom every time messages change
34
+ (_a = bottomRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
35
+ }, [messages, response]);
36
+ const getClasses = (m) => {
37
+ if (m.type === "response")
38
+ return "text-blue-500";
39
+ return "";
40
+ };
41
+ return (_jsxs("div", { className: "flex flex-col h-full", children: [_jsx("div", { className: "p-4 border-b border-gray-200", children: _jsx("button", { onClick: () => {
42
+ setMessages([]);
43
+ onReset();
44
+ }, children: _jsx("i", { className: "pi pi-trash" }) }) }), _jsxs("div", { className: "overflow-y-auto h-full overflow-x-hidden p-2", children: [messages.map((m, i) => (_jsx("div", { className: getClasses(m), children: m.text }, i))), response != null && (_jsxs("div", { className: "flex", children: [_jsxs("div", { className: "text-xs", children: [" ", _jsx("i", { className: "pi pi-spin pi-spinner" })] }), _jsx("div", { dangerouslySetInnerHTML: {
45
+ __html: response.replaceAll("\\n", "<br>"),
46
+ } })] })), _jsx("div", { ref: bottomRef })] }), _jsx(InputTextarea, { value: value, className: "border-0 border-t-2 rounded-none", onKeyDown: handleKeyPress, onChange: (e) => setValue(e.target.value), rows: 5, cols: 30 })] }));
47
+ }
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useEffect } from "react";
4
+ import { useEditContext } from "..";
5
+ export function TranslateEditor({ text }) {
6
+ const context = useEditContext();
7
+ if (!context || !context.dictionary)
8
+ return text;
9
+ const dictionary = context.dictionary;
10
+ useEffect(() => {
11
+ if (Object.keys(dictionary).indexOf(text) < 0 &&
12
+ context.unresolvedDictionaryKeys.indexOf(text) < 0) {
13
+ console.log("Pushing...");
14
+ context.setUnresolvedDictionaryKeys([
15
+ ...context.unresolvedDictionaryKeys,
16
+ text,
17
+ ]);
18
+ }
19
+ }, []);
20
+ return (dictionary[text] || _jsx("span", { className: "p-1 ring-2 ring-red-500", children: text }));
21
+ }
@@ -0,0 +1,17 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { Dropdown } from "primereact/dropdown";
4
+ export function VersionSelector({ page, onVersionSelected, }) {
5
+ if (page == null)
6
+ return;
7
+ const selectedVersionTemplate = (option, props) => {
8
+ if (option) {
9
+ return _jsx("div", { children: option.version });
10
+ }
11
+ return _jsx("span", { children: props.placeholder });
12
+ };
13
+ const versionOptionTemplate = (option) => {
14
+ return (_jsxs("div", { children: [option.version, " ", _jsxs("div", { className: "text-xs", children: ["(", option.updated.toString(), " by ", option.updatedBy, ")"] })] }));
15
+ };
16
+ return (_jsx(_Fragment, { children: _jsx(Dropdown, { value: page.version, onChange: (e) => onVersionSelected(e.value), options: page.versions, optionValue: "version", optionLabel: "version", placeholder: "Select a version", valueTemplate: selectedVersionTemplate, itemTemplate: versionOptionTemplate }) }));
17
+ }
@@ -0,0 +1,14 @@
1
+ export function findComponent(id, placeholders) {
2
+ for (const p of placeholders) {
3
+ for (const c of p.components) {
4
+ if (c.id == id) {
5
+ return c;
6
+ }
7
+ const match = findComponent(id, c.placeholders);
8
+ if (match) {
9
+ return match;
10
+ }
11
+ }
12
+ }
13
+ return null;
14
+ }
@@ -0,0 +1,31 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import Cookies from "universal-cookie";
11
+ export function getChildren(itemId, sessionId, templateIds = []) {
12
+ return __awaiter(this, void 0, void 0, function* () {
13
+ let url = "/alpaca/headless/editor/children?itemId=" +
14
+ itemId +
15
+ "&sessionId=" +
16
+ sessionId;
17
+ url = templateIds.reduce((u, t) => u + "&templateIds=" + t, url);
18
+ const response = yield fetch(url, {
19
+ method: "GET",
20
+ credentials: "include",
21
+ headers: {
22
+ "Content-Type": "application/json",
23
+ Cookie: new Cookies().getAll(),
24
+ },
25
+ next: {
26
+ revalidate: 0,
27
+ },
28
+ });
29
+ return yield response.json();
30
+ });
31
+ }
@@ -0,0 +1,5 @@
1
+ "use client";
2
+ import React, { useContext } from "react";
3
+ const EditContext = React.createContext(undefined);
4
+ export const EditContextProvider = EditContext.Provider;
5
+ export const useEditContext = () => useContext(EditContext);
@@ -0,0 +1,139 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import Cookies from "universal-cookie";
11
+ export let currentOperation = undefined;
12
+ export function setCurrentOperation(operation) {
13
+ currentOperation = operation;
14
+ }
15
+ export function executeEditOperation(editOperation, sessionId) {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ const response = yield fetch("/alpaca/headless/editor/edit?sessionId=" + sessionId, {
18
+ method: "POST",
19
+ body: JSON.stringify(editOperation),
20
+ credentials: "include",
21
+ headers: {
22
+ "Content-Type": "application/json",
23
+ Cookie: new Cookies().getAll(),
24
+ },
25
+ next: {
26
+ revalidate: 0,
27
+ },
28
+ });
29
+ if (response.status === 500 || response.redirected) {
30
+ return {
31
+ type: "error",
32
+ summary: "Error",
33
+ details: "An error occured while saving changes.",
34
+ };
35
+ }
36
+ if (response.status === 401) {
37
+ return {
38
+ type: "unauthenticated",
39
+ summary: "Unauthorized",
40
+ details: "Not logged in anymore?",
41
+ };
42
+ }
43
+ return yield response.json();
44
+ });
45
+ }
46
+ export function executeUndo(sessionId) {
47
+ return __awaiter(this, void 0, void 0, function* () {
48
+ const response = yield fetch("/alpaca/headless/editor/undo?sessionId=" + sessionId, {
49
+ method: "POST",
50
+ body: "",
51
+ credentials: "include",
52
+ headers: {
53
+ "Content-Type": "application/json",
54
+ Cookie: new Cookies().getAll(),
55
+ },
56
+ next: {
57
+ revalidate: 0,
58
+ },
59
+ });
60
+ if (response.status === 500 || response.redirected) {
61
+ return {
62
+ type: "error",
63
+ summary: "Error",
64
+ details: "An error occured while saving changes.",
65
+ };
66
+ }
67
+ if (response.status === 401) {
68
+ return {
69
+ type: "error",
70
+ summary: "Unauthorized",
71
+ details: "Not logged in anymore?",
72
+ };
73
+ }
74
+ return { type: "success" };
75
+ });
76
+ }
77
+ export function executeRedo(sessionId) {
78
+ return __awaiter(this, void 0, void 0, function* () {
79
+ const response = yield fetch("/alpaca/headless/editor/redo?sessionId=" + sessionId, {
80
+ method: "POST",
81
+ body: "",
82
+ credentials: "include",
83
+ headers: {
84
+ "Content-Type": "application/json",
85
+ Cookie: new Cookies().getAll(),
86
+ },
87
+ next: {
88
+ revalidate: 0,
89
+ },
90
+ });
91
+ if (response.status === 500 || response.redirected) {
92
+ return {
93
+ type: "error",
94
+ summary: "Error",
95
+ details: "An error occured while saving changes.",
96
+ };
97
+ }
98
+ if (response.status === 401) {
99
+ return {
100
+ type: "error",
101
+ summary: "Unauthorized",
102
+ details: "Not logged in anymore?",
103
+ };
104
+ }
105
+ return { type: "success" };
106
+ });
107
+ }
108
+ export function commitChanges(sessionId) {
109
+ return __awaiter(this, void 0, void 0, function* () {
110
+ const response = yield fetch("/alpaca/headless/editor/commit?sessionId=" + sessionId, {
111
+ method: "POST",
112
+ body: "",
113
+ credentials: "include",
114
+ headers: {
115
+ "Content-Type": "application/json",
116
+ Cookie: new Cookies().getAll(),
117
+ },
118
+ next: {
119
+ revalidate: 0,
120
+ },
121
+ });
122
+ if (response.ok)
123
+ return { type: "success" };
124
+ else {
125
+ if (response.status === 401) {
126
+ return {
127
+ type: "error",
128
+ summary: "Unauthorized",
129
+ details: "Not logged in anymore?",
130
+ };
131
+ }
132
+ return {
133
+ type: "error",
134
+ summary: "Error",
135
+ details: "An error occured while saving changes.",
136
+ };
137
+ }
138
+ });
139
+ }
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useEditContext } from "../..";
4
+ import { Editor } from "primereact/editor";
5
+ export function RichTextEditor({ field }) {
6
+ const editContext = useEditContext();
7
+ if (!editContext)
8
+ return;
9
+ return (_jsx(Editor, { value: field.value, style: { width: "100%" }, onTextChange: (e) => {
10
+ var _a;
11
+ // console.log("Text change: " + field.itemId);
12
+ editContext.editField(field, (_a = e.htmlValue) !== null && _a !== void 0 ? _a : "", true);
13
+ field.value = e.htmlValue;
14
+ } }, field.itemId + field.id + field.language + field.version));
15
+ }
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useEditContext } from "../..";
4
+ import { InputText } from "primereact/inputtext";
5
+ export function SingleLineText({ field }) {
6
+ const editContext = useEditContext();
7
+ if (!editContext)
8
+ return;
9
+ return (_jsx(InputText, { value: field.value, style: { width: "100%" }, onChange: (e) => {
10
+ editContext.editField(field, e.target.value, false);
11
+ field.value = e.target.value;
12
+ } }, field.itemId + field.id + field.language + field.version));
13
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./Editor";
2
+ export * from "./editContext";
@@ -0,0 +1 @@
1
+ export {};
package/dist/esm/index.js CHANGED
@@ -3,3 +3,5 @@ export * from "./loadRouteData";
3
3
  export * from "./components";
4
4
  export * from "./alpacaContext";
5
5
  export * from "./fieldTypes";
6
+ export * from "./editor";
7
+ export * as GraphQLTypes from "./graphQLTypes";
@@ -9,57 +9,115 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { useAlpacaContext } from "./alpacaContext";
11
11
  import { cookies } from "next/headers";
12
+ import { cache } from "react";
13
+ const fetchRouteData = cache((path, host, mode, itemId, language, session, version) => __awaiter(void 0, void 0, void 0, function* () {
14
+ const request = {
15
+ Path: path,
16
+ Host: host,
17
+ Mode: mode,
18
+ ItemId: itemId,
19
+ Language: language,
20
+ SessionId: session,
21
+ Version: version,
22
+ };
23
+ const url = process.env.LAYOUT_SERVICE_URL +
24
+ "/alpaca/headless/layout?session=" +
25
+ session;
26
+ console.log(`Fetching page layout from ${url}. Host:${request.Host} Path: ${request.Path}`);
27
+ const response = yield fetch(url, {
28
+ method: "POST",
29
+ body: JSON.stringify(request),
30
+ credentials: "include",
31
+ headers: {
32
+ "Content-Type": "application/json",
33
+ Cookie: cookies().toString(),
34
+ "x-api-key": getApiKey(),
35
+ },
36
+ next: {
37
+ tags: ["pages"],
38
+ revalidate: mode === "preview" || mode == "edit" ? 0 : 30,
39
+ },
40
+ });
41
+ console.log("STATUS: " + response.status + " mode: " + mode);
42
+ if (response.status === 404) {
43
+ return {
44
+ type: "notfound",
45
+ };
46
+ }
47
+ if (response.status === 301) {
48
+ return {
49
+ type: "redirect",
50
+ location: response.url,
51
+ };
52
+ }
53
+ if (!response.ok) {
54
+ const message = yield response.text();
55
+ return {
56
+ type: "error",
57
+ errorCode: response.status,
58
+ message: message,
59
+ };
60
+ }
61
+ const data = yield response.json();
62
+ //console.log(JSON.stringify(data, null, 2));
63
+ const context = useAlpacaContext();
64
+ context.pageContext = {
65
+ itemId: data.page.id,
66
+ language: data.page.language,
67
+ site: data.site,
68
+ pageEditing: data.page.editing,
69
+ pageState: "",
70
+ database: data.page.database,
71
+ };
72
+ context.fields = data.page.fields;
73
+ context.edit = data.edit;
74
+ const dictionary = yield loadDictionary(context.pageContext.site.name, context.pageContext.language, mode);
75
+ context.dictionary = dictionary;
76
+ context.translate = (text) => {
77
+ return context.dictionary[text] || text;
78
+ };
79
+ return Object.assign(Object.assign({}, data.page), { type: "page" });
80
+ }));
12
81
  export function loadRouteData(params, searchParams, host) {
13
82
  var _a, _b;
14
83
  return __awaiter(this, void 0, void 0, function* () {
15
- const request = {
16
- Path: (_b = (_a = params.path) === null || _a === void 0 ? void 0 : _a.join("/")) !== null && _b !== void 0 ? _b : "/",
17
- Host: host,
18
- Mode: searchParams["mode"] || "preview",
19
- ItemId: searchParams["itemid"],
20
- Language: searchParams["language"],
21
- };
22
- const url = process.env.LAYOUT_SERVICE_URL + "/alpaca/headless/layout";
23
- console.log(`Fetching page layout from ${url}. Host:${request.Host} Path: ${request.Path}`);
84
+ const result = yield fetchRouteData((_b = (_a = params.path) === null || _a === void 0 ? void 0 : _a.join("/")) !== null && _b !== void 0 ? _b : "/", host, searchParams["mode"] || "normal", searchParams["itemid"], searchParams["language"], searchParams["session"], searchParams["version"]);
85
+ return result;
86
+ });
87
+ }
88
+ function loadDictionary(siteName, language, mode) {
89
+ return __awaiter(this, void 0, void 0, function* () {
90
+ const url = process.env.LAYOUT_SERVICE_URL +
91
+ "/alpaca/headless/dictionary?siteName=" +
92
+ siteName +
93
+ "&language=" +
94
+ language;
95
+ console.log(`Fetching dictionary from ${url}.`);
24
96
  const response = yield fetch(url, {
25
- method: "POST",
26
- body: JSON.stringify(request),
97
+ method: "GET",
27
98
  credentials: "include",
28
99
  headers: {
29
100
  "Content-Type": "application/json",
30
101
  Cookie: cookies().toString(),
102
+ "x-api-key": getApiKey(),
103
+ },
104
+ next: {
105
+ tags: ["dictionary"],
106
+ revalidate: mode === "preview" || mode == "edit" ? 15 : 600,
31
107
  },
32
- next: { tags: ["pages"], revalidate: 10 },
33
108
  });
34
- if (response.status === 404) {
35
- return {
36
- type: "notfound",
37
- };
38
- }
39
- if (response.status === 301) {
40
- return {
41
- type: "redirect",
42
- location: response.url,
43
- };
44
- }
45
- if (response.status !== 200) {
46
- const message = yield response.text();
47
- return {
48
- type: "error",
49
- errorCode: response.status,
50
- message: message,
51
- };
109
+ if (!response.ok) {
110
+ console.log("Could not load dictionary: Response code: " + response.status);
111
+ return {};
52
112
  }
53
113
  const data = yield response.json();
54
114
  console.log(data);
55
- const context = useAlpacaContext();
56
- context.pageContext = {
57
- itemId: data.page.id,
58
- language: data.page.language,
59
- site: data.site,
60
- pageEditing: true,
61
- pageState: "",
62
- };
63
- return Object.assign(Object.assign({}, data.page), { type: "page" });
115
+ return data;
64
116
  });
65
117
  }
118
+ function getApiKey() {
119
+ const apiKey = process.env.ALPACA_HEADLESS_API_KEY || process.env.API_KEY;
120
+ if (!apiKey)
121
+ console.log("ERROR: Could not find API key environment variable: ALPACA_HEADLESS_API_KEY");
122
+ return apiKey;
123
+ }
@@ -0,0 +1,49 @@
1
+ import crypto from "crypto";
2
+ import "url";
3
+ const protectedParams = [
4
+ "w",
5
+ "h",
6
+ "mw",
7
+ "mh",
8
+ "sc",
9
+ "as",
10
+ "bc",
11
+ "db",
12
+ "iar",
13
+ "la",
14
+ "thn",
15
+ "vs",
16
+ "sc_content",
17
+ "sc_lang",
18
+ "sc_site",
19
+ "gray",
20
+ "rev",
21
+ "devicepixelratio",
22
+ "encodequality",
23
+ "rx",
24
+ "ry",
25
+ "rw",
26
+ "rh",
27
+ "crop",
28
+ ];
29
+ export function hashImageUrl(url) {
30
+ if (!process.env.MEDIA_REQUESTPROTECTION_SHAREDSECRET)
31
+ return url;
32
+ if (!url)
33
+ return url;
34
+ const baseURL = 'http://temp-base-url.com'; // This will serve as a placeholder.
35
+ const uri = new URL(url.toLowerCase(), baseURL);
36
+ uri.searchParams.delete("hash");
37
+ const searchParams = protectedParams
38
+ .map((x) => ({ name: x, val: uri.searchParams.get(x) }))
39
+ .filter((x) => x.val)
40
+ .map((x) => x.name + "=" + x.val)
41
+ .join("&");
42
+ const stringToProtect = uri.pathname.substring(1) + "?" + searchParams;
43
+ const hash = crypto
44
+ .createHash("md5")
45
+ .update(stringToProtect + process.env.MEDIA_REQUESTPROTECTION_SHAREDSECRET, "utf16le")
46
+ .digest("hex");
47
+ uri.searchParams.set("hash", hash);
48
+ return url.startsWith('http') ? uri.toString() : uri.pathname + uri.search;
49
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alpaca-headless/alpaca-headless-nextjs",
3
- "version": "0.0.4",
3
+ "version": "1.0.13",
4
4
  "description": "Alpaca Headless NextJs Integration",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -9,12 +9,14 @@
9
9
  "dist",
10
10
  "types",
11
11
  "/*.js",
12
+ "/*.css",
12
13
  "/*.d.ts"
13
14
  ],
14
15
  "scripts": {
15
- "build": "npm run build:cjs && npm run build:esm",
16
+ "build": "npm run build:cjs && npm run build:esm && npm run copy-files",
16
17
  "build:cjs": "node tools/cleanup cjs && tsc -p config/tsconfig.cjs.json --noEmit false",
17
18
  "build:esm": "node tools/cleanup esm && tsc -p config/tsconfig.esm.json --noEmit false",
19
+ "copy-files": "copyfiles -u 1 -E -V \"src/editor.css\" dist/",
18
20
  "clean": "node tools/cleanup",
19
21
  "package": "npm run build && npm pack"
20
22
  },
@@ -22,11 +24,21 @@
22
24
  "license": "MIT",
23
25
  "dependencies": {
24
26
  "autoprefixer": "10.4.14",
25
- "next": "13.4.9",
27
+ "copyfiles": "^2.4.1",
28
+ "crypto": "^1.0.1",
29
+ "cryptography": "^1.2.3",
30
+ "graphql-formatter": "^1.0.3",
31
+ "next": "13.5.1",
26
32
  "node-cleanup": "^2.1.2",
33
+ "prettier": "^3.0.3",
34
+ "primereact": "^9.6.2",
35
+ "quill": "^1.3.7",
27
36
  "react": "18.2.0",
28
37
  "react-dom": "18.2.0",
29
- "server-only": "^0.0.1"
38
+ "react-json-pretty": "^2.2.0",
39
+ "react-uuid": "^2.0.0",
40
+ "server-only": "^0.0.1",
41
+ "universal-cookie": "^6.1.1"
30
42
  },
31
43
  "devDependencies": {
32
44
  "@types/node": "20.4.1",