@parhelia/alpaca 0.1.12451

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,2 @@
1
+ export declare function GraphQL(): import("react/jsx-runtime").JSX.Element | null;
2
+ //# sourceMappingURL=GraphQL.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GraphQL.d.ts","sourceRoot":"","sources":["../src/GraphQL.tsx"],"names":[],"mappings":"AA+BA,wBAAgB,OAAO,mDAmQtB"}
@@ -0,0 +1,185 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useState } from "react";
3
+ import { ActionButton, createAgentCommand, getComponentById, SecretAgentIcon, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, useEditContext, } from "@parhelia/core";
4
+ import { getGraphQLSchema, } from "./graphqlService";
5
+ import { GraphiQLPanel } from "./GraphiQLPanel";
6
+ function sameItem(left, right) {
7
+ return (!!left &&
8
+ !!right &&
9
+ left.id === right.id &&
10
+ left.language === right.language &&
11
+ left.version === right.version);
12
+ }
13
+ export function GraphQL() {
14
+ const editContext = useEditContext();
15
+ const pageItem = editContext?.page?.item ?? editContext?.item;
16
+ const selectionKey = editContext?.selection?.join("|") || "";
17
+ const [query, setQuery] = useState("");
18
+ const [schemaResult, setSchemaResult] = useState({});
19
+ const [showSchemaSpinner, setShowSchemaSpinner] = useState(false);
20
+ const [aiGeneratedQuery, setAiGeneratedQuery] = useState("");
21
+ const [graphiqlVariables, setGraphiqlVariables] = useState("{}");
22
+ const [baseItem, setBaseItem] = useState(null);
23
+ const selectedComponent = useMemo(() => {
24
+ if (!editContext?.page || (editContext.selection?.length || 0) !== 1) {
25
+ return null;
26
+ }
27
+ return getComponentById(editContext.selection[0], editContext.page) || null;
28
+ }, [editContext?.page, selectionKey]);
29
+ const baseItemDescriptor = useMemo(() => {
30
+ const componentItem = selectedComponent?.datasourceItem || selectedComponent?.items?.[0];
31
+ return componentItem || pageItem?.descriptor || pageItem || null;
32
+ }, [selectedComponent, pageItem]);
33
+ const currentItem = useMemo(() => baseItemDescriptor
34
+ ? {
35
+ id: baseItemDescriptor.id,
36
+ language: baseItemDescriptor.language,
37
+ version: baseItemDescriptor.version,
38
+ }
39
+ : null, [
40
+ baseItemDescriptor?.id,
41
+ baseItemDescriptor?.language,
42
+ baseItemDescriptor?.version,
43
+ ]);
44
+ const baseItemLabel = useMemo(() => {
45
+ const componentItem = selectedComponent?.datasourceItem || selectedComponent?.items?.[0];
46
+ return componentItem?.name || pageItem?.name || currentItem?.id || "";
47
+ }, [selectedComponent, pageItem?.name, currentItem?.id]);
48
+ useEffect(() => {
49
+ let isCancelled = false;
50
+ const loadBaseItem = async () => {
51
+ if (!editContext || !baseItemDescriptor) {
52
+ setBaseItem(null);
53
+ return;
54
+ }
55
+ if (pageItem &&
56
+ sameItem({
57
+ id: pageItem.id,
58
+ language: pageItem.language,
59
+ version: pageItem.version,
60
+ }, {
61
+ id: baseItemDescriptor.id,
62
+ language: baseItemDescriptor.language,
63
+ version: baseItemDescriptor.version,
64
+ })) {
65
+ setBaseItem(pageItem);
66
+ return;
67
+ }
68
+ try {
69
+ const nextItem = await editContext.itemsRepository.getItem(baseItemDescriptor);
70
+ if (!isCancelled) {
71
+ setBaseItem(nextItem || null);
72
+ }
73
+ }
74
+ catch (error) {
75
+ console.error("Failed to load base item for GraphQL panel:", error);
76
+ if (!isCancelled) {
77
+ setBaseItem(null);
78
+ }
79
+ }
80
+ };
81
+ void loadBaseItem();
82
+ return () => {
83
+ isCancelled = true;
84
+ };
85
+ }, [
86
+ editContext,
87
+ baseItemDescriptor?.id,
88
+ baseItemDescriptor?.language,
89
+ baseItemDescriptor?.version,
90
+ pageItem,
91
+ ]);
92
+ const queryField = useMemo(() => baseItem?.fields?.find((field) => field.name === "_GraphQL" || field.name === "graphql_query") || null, [baseItem]);
93
+ useEffect(() => {
94
+ setQuery(queryField?.rawValue || "");
95
+ }, [queryField?.id, queryField?.rawValue]);
96
+ useEffect(() => {
97
+ setSchemaResult({});
98
+ setGraphiqlVariables("{}");
99
+ setAiGeneratedQuery("");
100
+ }, [currentItem?.id, currentItem?.language, currentItem?.version]);
101
+ useEffect(() => {
102
+ if (currentItem && !schemaResult?.data && !showSchemaSpinner) {
103
+ void fetchSchema();
104
+ }
105
+ }, [
106
+ currentItem?.id,
107
+ currentItem?.language,
108
+ currentItem?.version,
109
+ schemaResult?.data,
110
+ showSchemaSpinner,
111
+ ]);
112
+ useEffect(() => {
113
+ if (!editContext || !currentItem)
114
+ return;
115
+ const factoryName = "graphql:context:v1";
116
+ const factory = async () => ({
117
+ schema: schemaResult?.data || "",
118
+ currentQuery: query,
119
+ itemContext: {
120
+ id: currentItem.id,
121
+ language: currentItem.language,
122
+ version: currentItem.version,
123
+ },
124
+ });
125
+ editContext.registerContextFactory?.(factoryName, factory);
126
+ return () => editContext.unregisterContextFactory?.(factoryName);
127
+ }, [
128
+ editContext,
129
+ currentItem?.id,
130
+ currentItem?.language,
131
+ currentItem?.version,
132
+ query,
133
+ schemaResult?.data,
134
+ ]);
135
+ if (!currentItem)
136
+ return null;
137
+ const activeItem = currentItem;
138
+ async function fetchSchema() {
139
+ setShowSchemaSpinner(true);
140
+ try {
141
+ const response = await getGraphQLSchema({
142
+ id: activeItem.id,
143
+ language: activeItem.language,
144
+ version: activeItem.version,
145
+ mode: "edit",
146
+ siteName: "website",
147
+ });
148
+ setSchemaResult(response.error
149
+ ? {
150
+ status: response.status,
151
+ error: response.error,
152
+ transport: response.transport,
153
+ }
154
+ : {
155
+ data: response.data,
156
+ status: response.status,
157
+ transport: response.transport,
158
+ });
159
+ }
160
+ catch (error) {
161
+ console.error("Schema fetch error:", error);
162
+ setSchemaResult({ error: String(error) });
163
+ }
164
+ finally {
165
+ setShowSchemaSpinner(false);
166
+ }
167
+ }
168
+ const applyQueryToEditor = (newQuery) => {
169
+ setQuery(newQuery);
170
+ setAiGeneratedQuery(newQuery);
171
+ };
172
+ return (_jsxs("div", { className: "relative flex h-full min-h-0 flex-col overflow-hidden text-xs", children: [aiGeneratedQuery && aiGeneratedQuery !== query && (_jsxs("div", { className: "shrink-0 flex items-center gap-2 border-b border-yellow-200 bg-yellow-50 p-2 text-xs", children: [_jsx("span", { className: "text-yellow-800", children: "AI generated a new query" }), _jsx(ActionButton, { onClick: () => applyQueryToEditor(aiGeneratedQuery), className: "p-1 text-xs", variant: "outline", children: "Apply" }), _jsx(ActionButton, { onClick: () => setAiGeneratedQuery(""), className: "p-1", variant: "ghost", children: "x" })] })), _jsx(GraphiQLPanel, { item: currentItem, itemLabel: baseItemLabel, query: query, variables: graphiqlVariables, onQueryChange: setQuery, onVariablesChange: setGraphiqlVariables, onExecutionResult: () => { }, headerActions: _jsx(TooltipProvider, { delayDuration: 300, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs(ActionButton, { variant: "outline", className: "h-8 w-8 rounded-full p-0", onClick: () => {
173
+ editContext?.executeCommand?.({
174
+ command: createAgentCommand,
175
+ data: {
176
+ profileName: "GraphQL Assistant",
177
+ contextFactory: "graphql:context:v1",
178
+ initialPrompt: "Help with the current GraphQL query and schema.",
179
+ additionalData: {
180
+ source: "GraphQLPanel",
181
+ },
182
+ },
183
+ });
184
+ }, children: [_jsx(SecretAgentIcon, { size: 16, strokeWidth: 1.5 }), _jsx("span", { className: "sr-only", children: "Start GraphQL Agent" })] }) }), _jsx(TooltipContent, { children: "Start GraphQL Agent" })] }) }) })] }));
185
+ }
@@ -0,0 +1,15 @@
1
+ import "graphiql/style.css";
2
+ import "@graphiql/plugin-explorer/style.css";
3
+ import "graphiql/setup-workers/webpack";
4
+ import { GraphiQLExecutionResult, GraphQLPanelItem } from "./graphqlService";
5
+ export declare function GraphiQLPanel({ item, query, variables, onQueryChange, onVariablesChange, onExecutionResult, itemLabel, headerActions, }: {
6
+ item: GraphQLPanelItem;
7
+ query: string;
8
+ variables: string;
9
+ onQueryChange: (query: string) => void;
10
+ onVariablesChange: (variables: string) => void;
11
+ onExecutionResult: (result: GraphiQLExecutionResult) => void;
12
+ itemLabel?: string;
13
+ headerActions?: React.ReactNode;
14
+ }): import("react/jsx-runtime").JSX.Element;
15
+ //# sourceMappingURL=GraphiQLPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GraphiQLPanel.d.ts","sourceRoot":"","sources":["../src/GraphiQLPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,qCAAqC,CAAC;AAC7C,OAAO,gCAAgC,CAAC;AAOxC,OAAO,EAGL,uBAAuB,EAEvB,gBAAgB,EAEjB,MAAM,kBAAkB,CAAC;AAwD1B,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,SAAS,EACT,aAAa,GACd,EAAE;IACD,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,iBAAiB,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACjC,2CA4IA"}
@@ -0,0 +1,119 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import "graphiql/style.css";
3
+ import "@graphiql/plugin-explorer/style.css";
4
+ import "graphiql/setup-workers/webpack";
5
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
6
+ import { GraphiQL as GraphiQLIDE } from "graphiql";
7
+ import { useGraphiQL, useGraphiQLActions } from "@graphiql/react";
8
+ import { explorerPlugin } from "@graphiql/plugin-explorer";
9
+ import { executeGraphiQLRequest, fetchGraphiQLSchema, isSchemaIntrospectionQuery, } from "./graphqlService";
10
+ function GraphiQLSyncBridge({ query, variables, }) {
11
+ const { updateActiveTabValues } = useGraphiQLActions();
12
+ const activeQuery = useGraphiQL((state) => state.tabs[state.activeTabIndex]?.query ?? "");
13
+ const activeVariables = useGraphiQL((state) => state.tabs[state.activeTabIndex]?.variables ?? "");
14
+ const pendingExternalState = useRef(null);
15
+ useEffect(() => {
16
+ if (activeQuery !== query || activeVariables !== variables) {
17
+ pendingExternalState.current = { query, variables };
18
+ updateActiveTabValues({ query, variables });
19
+ }
20
+ }, [activeQuery, activeVariables, query, updateActiveTabValues, variables]);
21
+ useEffect(() => {
22
+ if (pendingExternalState.current &&
23
+ pendingExternalState.current.query === activeQuery &&
24
+ pendingExternalState.current.variables === activeVariables) {
25
+ pendingExternalState.current = null;
26
+ }
27
+ }, [activeQuery, activeVariables]);
28
+ return null;
29
+ }
30
+ function parseVariables(variables) {
31
+ if (!variables.trim()) {
32
+ return null;
33
+ }
34
+ try {
35
+ return JSON.parse(variables);
36
+ }
37
+ catch (error) {
38
+ throw new Error(error instanceof Error
39
+ ? `Variables JSON is invalid: ${error.message}`
40
+ : "Variables JSON is invalid.");
41
+ }
42
+ }
43
+ export function GraphiQLPanel({ item, query, variables, onQueryChange, onVariablesChange, onExecutionResult, itemLabel, headerActions, }) {
44
+ const [schemaResult, setSchemaResult] = useState({});
45
+ const [isRefreshingSchema, setIsRefreshingSchema] = useState(false);
46
+ const explorer = useMemo(() => explorerPlugin(), []);
47
+ const plugins = useMemo(() => [explorer], [explorer]);
48
+ const handleEditHeaders = useCallback(() => { }, []);
49
+ const graphiqlSchema = schemaResult.schema ?? null;
50
+ const refreshSchema = useCallback(async () => {
51
+ setIsRefreshingSchema(true);
52
+ try {
53
+ const result = await fetchGraphiQLSchema(item);
54
+ setSchemaResult(result);
55
+ }
56
+ finally {
57
+ setIsRefreshingSchema(false);
58
+ }
59
+ }, [item.id, item.language, item.version]);
60
+ useEffect(() => {
61
+ setSchemaResult({});
62
+ }, [item.id, item.language, item.version]);
63
+ useEffect(() => {
64
+ if (!graphiqlSchema && !isRefreshingSchema) {
65
+ void refreshSchema();
66
+ }
67
+ }, [graphiqlSchema, isRefreshingSchema, refreshSchema]);
68
+ const fetcher = useCallback(async (graphQLParams) => {
69
+ if (!graphQLParams.query) {
70
+ return {
71
+ errors: [{ message: "No GraphQL query was provided." }],
72
+ };
73
+ }
74
+ let parsedVariables = null;
75
+ try {
76
+ parsedVariables = parseVariables(variables);
77
+ }
78
+ catch (error) {
79
+ return {
80
+ errors: [
81
+ { message: error instanceof Error ? error.message : String(error) },
82
+ ],
83
+ };
84
+ }
85
+ const result = await executeGraphiQLRequest({
86
+ item,
87
+ query: graphQLParams.query,
88
+ variables: graphQLParams.variables ?? parsedVariables,
89
+ operationName: graphQLParams.operationName,
90
+ });
91
+ if (isSchemaIntrospectionQuery(graphQLParams.query)) {
92
+ setSchemaResult(result);
93
+ }
94
+ else {
95
+ onExecutionResult(result);
96
+ }
97
+ if (result.error) {
98
+ return {
99
+ data: result.data,
100
+ errors: [{ message: result.error }],
101
+ };
102
+ }
103
+ return {
104
+ data: result.data ?? null,
105
+ errors: result.errors,
106
+ };
107
+ }, [item.id, item.language, item.version, onExecutionResult, variables]);
108
+ const lastTransportMessage = useMemo(() => {
109
+ if (schemaResult.transport?.used === "v1-fallback") {
110
+ return `Schema fetch fell back to v1 after v2 status ${schemaResult.transport.fallbackFromStatus}.`;
111
+ }
112
+ return "";
113
+ }, [schemaResult.transport]);
114
+ return (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col bg-white", children: [_jsx("style", { children: `
115
+ .alpaca-graphiql-shell .graphiql-logo {
116
+ display: none;
117
+ }
118
+ ` }), _jsxs("div", { className: "flex items-center justify-between gap-3 border-b border-gray-200 bg-gray-50 px-3 py-2 text-xs text-gray-600", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2", children: [_jsxs("span", { children: ["Base item: ", _jsx("span", { className: "font-mono", children: itemLabel || item.id })] }), _jsxs("span", { children: [item.language, " v", item.version] })] }), headerActions && (_jsx("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: headerActions }))] }), !!lastTransportMessage && (_jsx("div", { className: "border-b border-amber-300 bg-amber-50 px-3 py-2 text-xs text-amber-800", children: lastTransportMessage })), schemaResult.error && (_jsx("div", { className: "border-b border-red-300 bg-red-50 px-3 py-2 text-xs text-red-800", children: schemaResult.error })), _jsx("div", { className: "alpaca-graphiql-shell min-h-0 flex-1 bg-white [&_.graphiql-container]:h-full", children: _jsx(GraphiQLIDE, { className: "h-full", fetcher: fetcher, schema: graphiqlSchema, forcedTheme: "light", initialQuery: query, initialVariables: variables, initialHeaders: "", onEditQuery: onQueryChange, onEditVariables: onVariablesChange, onEditHeaders: handleEditHeaders, isHeadersEditorEnabled: false, defaultEditorToolsVisibility: "variables", plugins: plugins, children: _jsx(GraphiQLSyncBridge, { query: query, variables: variables }) }) })] }));
119
+ }
@@ -0,0 +1,2 @@
1
+ export declare function Layout(): import("react/jsx-runtime").JSX.Element | null;
2
+ //# sourceMappingURL=Layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Layout.d.ts","sourceRoot":"","sources":["../src/Layout.tsx"],"names":[],"mappings":"AAYA,wBAAgB,MAAM,mDA0GrB"}
package/dist/Layout.js ADDED
@@ -0,0 +1,66 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from "react";
3
+ import { ObjectInspector, ObjectLabel, ObjectRootLabel } from "react-inspector";
4
+ import { CopyButton, getComponentByIdFromHeadlessLayout, SimpleTabs, useEditContext, usePageViewContext, } from "@parhelia/core";
5
+ import { getPageJson } from "./services";
6
+ export function Layout() {
7
+ const [activeTab, setActiveTab] = useState(0);
8
+ const [pageLayout, setPageLayout] = useState(null);
9
+ const editContext = useEditContext();
10
+ if (!editContext)
11
+ return null;
12
+ usePageViewContext({
13
+ pageItemDescriptor: editContext.item?.descriptor,
14
+ itemsRepository: editContext.itemsRepository,
15
+ configuration: editContext.configuration,
16
+ });
17
+ useEffect(() => {
18
+ const loadLayout = async () => {
19
+ if (!editContext.item)
20
+ return;
21
+ const layout = await getPageJson(editContext.item.descriptor);
22
+ setPageLayout(layout);
23
+ };
24
+ loadLayout();
25
+ }, [editContext.item]);
26
+ const page = pageLayout;
27
+ let component = null;
28
+ if (page) {
29
+ const selectedComponents = editContext.selection
30
+ .map((x) => getComponentByIdFromHeadlessLayout(x, page))
31
+ .filter((x) => x);
32
+ component = selectedComponents.length === 1 ? selectedComponents[0] : null;
33
+ }
34
+ if (!component && !page)
35
+ return null;
36
+ const replacer = function (key, value) {
37
+ if (key === "parentComponent" ||
38
+ key === "placeholderReference" ||
39
+ key === "_editor") {
40
+ return undefined;
41
+ }
42
+ return value;
43
+ };
44
+ const tabs = [];
45
+ const defaultNodeRenderer = ({ depth, name, data, isNonenumerable }) => {
46
+ if (name == "__editor" ||
47
+ name == "parentComponent" ||
48
+ name == "placeholderReference") {
49
+ return null;
50
+ }
51
+ return depth === 0 ? (_jsx(ObjectRootLabel, { name: name, data: data })) : (_jsx(ObjectLabel, { name: name, data: data, isNonenumerable: isNonenumerable }));
52
+ };
53
+ if (component) {
54
+ tabs.push({
55
+ label: "Component",
56
+ id: "component",
57
+ content: (_jsx("div", { className: "relative h-full min-h-0", children: _jsx("div", { className: "absolute inset-0 overflow-auto p-2", children: _jsx(ObjectInspector, { data: component, nodeRenderer: defaultNodeRenderer }) }) })),
58
+ });
59
+ }
60
+ tabs.push({
61
+ label: "Page",
62
+ id: "page",
63
+ content: (_jsx("div", { className: "relative h-full min-h-0", children: _jsx("div", { className: "absolute inset-0 overflow-auto p-2", children: _jsx(ObjectInspector, { data: page, nodeRenderer: defaultNodeRenderer }) }) })),
64
+ });
65
+ return (_jsxs("div", { className: "relative flex h-full min-h-0 flex-col", children: [_jsx(SimpleTabs, { tabs: tabs, activeTab: activeTab, setActiveTab: setActiveTab, className: "border-gray-3 flex border-b px-2 pt-2 text-xs" }), _jsx("div", { className: "absolute top-2 right-1 h-4 w-4", children: _jsx(CopyButton, { textToCopy: JSON.stringify(activeTab === 0 && component ? component : page, replacer, 2), iconOnly: true }) })] }));
66
+ }
@@ -0,0 +1,77 @@
1
+ import { GraphQLSchema } from "graphql";
2
+ export type ExecuteGraphQLParams = {
3
+ query: string;
4
+ tags?: string[];
5
+ host?: string;
6
+ path?: string;
7
+ language?: string;
8
+ mode?: string;
9
+ itemId?: string;
10
+ version?: number;
11
+ revalidate?: number;
12
+ siteName?: string;
13
+ sessionId?: string;
14
+ schema?: string;
15
+ };
16
+ export type GraphQLTransport = {
17
+ requested: "v2";
18
+ used: "v2" | "v1-fallback";
19
+ fallbackFromStatus?: number;
20
+ };
21
+ export type GraphQLQueryResult = {
22
+ data?: any;
23
+ status: number;
24
+ errors?: any;
25
+ transport: GraphQLTransport;
26
+ };
27
+ export type GraphQLSchemaResult = {
28
+ data?: string;
29
+ status: number;
30
+ error?: string;
31
+ transport: GraphQLTransport;
32
+ };
33
+ export declare const INTROSPECTION_QUERY: string;
34
+ export type GraphQLPanelItem = {
35
+ id: string;
36
+ language: string;
37
+ version: number;
38
+ };
39
+ export type QueryNormalizationResult = {
40
+ query?: string;
41
+ warning?: string;
42
+ error?: string;
43
+ };
44
+ export type GraphiQLExecutionResult = {
45
+ status?: number;
46
+ data?: any;
47
+ errors?: any;
48
+ error?: string;
49
+ warning?: string;
50
+ transport?: GraphQLTransport;
51
+ compiledQuery?: string;
52
+ };
53
+ export type GraphiQLSchemaResult = GraphiQLExecutionResult & {
54
+ rawSchemaText?: string;
55
+ schema?: GraphQLSchema;
56
+ };
57
+ export declare function isSchemaIntrospectionQuery(query: string): boolean;
58
+ export declare function createExplicitItemArgs(item: GraphQLPanelItem): string;
59
+ export declare function createStarterQuery(item: GraphQLPanelItem): string;
60
+ export declare function normalizePanelQuery(query: string, item: GraphQLPanelItem): QueryNormalizationResult;
61
+ export declare function executeGraphQLQuery({ query, host, path, language, mode, itemId, version, siteName, schema, sessionId, }: ExecuteGraphQLParams): Promise<GraphQLQueryResult>;
62
+ export declare function getGraphQLSchema({ id, language, version, mode, siteName, }: {
63
+ id: string;
64
+ language?: string;
65
+ version?: number;
66
+ mode?: string;
67
+ siteName?: string;
68
+ }): Promise<GraphQLSchemaResult>;
69
+ export declare function executeGraphiQLRequest(options: {
70
+ item: GraphQLPanelItem;
71
+ query: string;
72
+ variables?: Record<string, unknown> | null;
73
+ operationName?: string | null;
74
+ }): Promise<GraphiQLExecutionResult>;
75
+ export declare function fetchGraphiQLSchema(item: GraphQLPanelItem): Promise<GraphiQLSchemaResult>;
76
+ export declare function getSchemaContextValue(schemaResult: GraphiQLSchemaResult): string;
77
+ //# sourceMappingURL=graphqlService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphqlService.d.ts","sourceRoot":"","sources":["../src/graphqlService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,518 @@
1
+ import { get, post } from "@parhelia/core";
2
+ import { buildClientSchema, getIntrospectionQuery, Kind, parse, print, visit, } from "graphql";
3
+ const GRAPHQL_V2_QUERY_URL = "/alpaca/headless/graphql/v2/query";
4
+ const GRAPHQL_V1_QUERY_URL = "/alpaca/headless/graphql";
5
+ const GRAPHQL_V1_SCHEMA_URL = "/alpaca/headless/graphql/schema";
6
+ const V2_TO_V1_FALLBACK_STATUSES = new Set([
7
+ 400, 404, 405, 415, 500, 501, 502, 503, 504,
8
+ ]);
9
+ const DEFAULT_INTROSPECTION_QUERY = getIntrospectionQuery({
10
+ descriptions: true,
11
+ schemaDescription: true,
12
+ directiveIsRepeatable: true,
13
+ });
14
+ export const INTROSPECTION_QUERY = DEFAULT_INTROSPECTION_QUERY;
15
+ function shouldFallbackToV1(status) {
16
+ return V2_TO_V1_FALLBACK_STATUSES.has(status);
17
+ }
18
+ export function isSchemaIntrospectionQuery(query) {
19
+ return /\b__(schema|type)\b/.test(query);
20
+ }
21
+ export function createExplicitItemArgs(item) {
22
+ return `id: "${item.id}", language: "${item.language}", version: ${item.version}`;
23
+ }
24
+ function createExplicitItemArgumentNodes(item) {
25
+ return [
26
+ {
27
+ kind: Kind.ARGUMENT,
28
+ name: { kind: Kind.NAME, value: "id" },
29
+ value: { kind: Kind.STRING, value: item.id },
30
+ },
31
+ {
32
+ kind: Kind.ARGUMENT,
33
+ name: { kind: Kind.NAME, value: "language" },
34
+ value: { kind: Kind.STRING, value: item.language },
35
+ },
36
+ {
37
+ kind: Kind.ARGUMENT,
38
+ name: { kind: Kind.NAME, value: "version" },
39
+ value: { kind: Kind.INT, value: String(item.version) },
40
+ },
41
+ ];
42
+ }
43
+ export function createStarterQuery(item) {
44
+ return `query CurrentItem {
45
+ item(${createExplicitItemArgs(item)}) {
46
+ id
47
+ name
48
+ path
49
+ }
50
+ }`;
51
+ }
52
+ function hasExplicitItemSelector(query) {
53
+ return /item\s*\((?=[^)]*\bid\s*:)(?=[^)]*\blanguage\s*:)(?=[^)]*\bversion\s*:)[^)]*\)/i.test(query);
54
+ }
55
+ function rewriteContextShortcutItems(query, item) {
56
+ let rewritten = false;
57
+ const explicitArgs = createExplicitItemArgs(item);
58
+ const rewrittenQuery = query.replace(/item\s*\(([^)]*)\)/gi, (match, args) => {
59
+ if (/path\s*:\s*["']__[^"']+["']/i.test(args)) {
60
+ rewritten = true;
61
+ return `item(${explicitArgs})`;
62
+ }
63
+ return match;
64
+ });
65
+ return { rewrittenQuery, rewritten };
66
+ }
67
+ function rewriteImplicitItemSelections(query, item) {
68
+ try {
69
+ let rewritten = false;
70
+ const parsed = parse(query);
71
+ const explicitArgs = createExplicitItemArgumentNodes(item);
72
+ const rewrittenDocument = visit(parsed, {
73
+ Field(node, _key, parent, _path, ancestors) {
74
+ if (node.name.value !== "item" ||
75
+ (node.arguments?.length ?? 0) > 0 ||
76
+ !node.selectionSet) {
77
+ return;
78
+ }
79
+ const parentNode = ancestors[ancestors.length - 1];
80
+ const inOperationSelectionSet = parentNode &&
81
+ typeof parentNode === "object" &&
82
+ "kind" in parentNode &&
83
+ parentNode.kind === Kind.SELECTION_SET &&
84
+ ancestors.some((ancestor) => ancestor &&
85
+ typeof ancestor === "object" &&
86
+ "kind" in ancestor &&
87
+ ancestor.kind === Kind.OPERATION_DEFINITION);
88
+ if (!inOperationSelectionSet) {
89
+ return;
90
+ }
91
+ rewritten = true;
92
+ return {
93
+ ...node,
94
+ arguments: explicitArgs,
95
+ };
96
+ },
97
+ });
98
+ return {
99
+ rewrittenQuery: print(rewrittenDocument),
100
+ rewritten,
101
+ };
102
+ }
103
+ catch {
104
+ return { rewrittenQuery: query, rewritten: false };
105
+ }
106
+ }
107
+ export function normalizePanelQuery(query, item) {
108
+ if (isSchemaIntrospectionQuery(query) || hasExplicitItemSelector(query)) {
109
+ return { query };
110
+ }
111
+ const { rewrittenQuery, rewritten } = rewriteContextShortcutItems(query, item);
112
+ if (rewritten && hasExplicitItemSelector(rewrittenQuery)) {
113
+ return {
114
+ query: rewrittenQuery,
115
+ warning: "Query used context shortcuts and was rewritten to explicit item(id, language, version).",
116
+ };
117
+ }
118
+ const { rewrittenQuery: implicitItemQuery, rewritten: implicitItemRewritten, } = rewriteImplicitItemSelections(query, item);
119
+ if (implicitItemRewritten && hasExplicitItemSelector(implicitItemQuery)) {
120
+ return {
121
+ query: implicitItemQuery,
122
+ warning: "Query used item without arguments and was rewritten to explicit item(id, language, version) for the selected base item.",
123
+ };
124
+ }
125
+ if (/\b__page\b/i.test(query)) {
126
+ return {
127
+ error: "Context shortcuts like __page are not allowed. Use item(id, language, version) explicitly instead.",
128
+ };
129
+ }
130
+ return { query };
131
+ }
132
+ function getDatabaseFromMode(mode) {
133
+ const lowered = mode?.toLowerCase();
134
+ if (lowered === "edit" || lowered === "preview") {
135
+ return "master";
136
+ }
137
+ return "web";
138
+ }
139
+ function getStatus(result) {
140
+ return result.response?.status ?? 500;
141
+ }
142
+ function getErrorMessage(result) {
143
+ return result.details || result.summary || result.rawDetails || "Request failed";
144
+ }
145
+ function joinWarnings(...warnings) {
146
+ return warnings.filter(Boolean).join(" ");
147
+ }
148
+ function parseJsonSafely(text) {
149
+ if (!text.trim()) {
150
+ return undefined;
151
+ }
152
+ try {
153
+ return JSON.parse(text);
154
+ }
155
+ catch {
156
+ return undefined;
157
+ }
158
+ }
159
+ function getOperationDefinitions(document) {
160
+ return document.definitions.filter((definition) => definition.kind === Kind.OPERATION_DEFINITION);
161
+ }
162
+ function getSelectedOperation(document, operationName) {
163
+ const operations = getOperationDefinitions(document);
164
+ if (operationName) {
165
+ const matchingOperation = operations.find((operation) => operation.name?.value === operationName);
166
+ if (!matchingOperation) {
167
+ throw new Error(`Could not find operation "${operationName}" in the current document.`);
168
+ }
169
+ return matchingOperation;
170
+ }
171
+ if (operations.length !== 1) {
172
+ throw new Error("Alpaca GraphQL execution expects a single operation. Select exactly one operation before running the query.");
173
+ }
174
+ const selectedOperation = operations[0];
175
+ if (!selectedOperation) {
176
+ throw new Error("No GraphQL operation was found in the current document.");
177
+ }
178
+ return selectedOperation;
179
+ }
180
+ function collectReferencedFragments(definition, fragmentMap, visited = new Set()) {
181
+ visit(definition, {
182
+ FragmentSpread(node) {
183
+ if (visited.has(node.name.value)) {
184
+ return;
185
+ }
186
+ visited.add(node.name.value);
187
+ const fragment = fragmentMap.get(node.name.value);
188
+ if (fragment) {
189
+ collectReferencedFragments(fragment, fragmentMap, visited);
190
+ }
191
+ },
192
+ });
193
+ return visited;
194
+ }
195
+ function createValueNode(value) {
196
+ if (value === null) {
197
+ return { kind: Kind.NULL };
198
+ }
199
+ if (Array.isArray(value)) {
200
+ return {
201
+ kind: Kind.LIST,
202
+ values: value.map((entry) => createValueNode(entry)),
203
+ };
204
+ }
205
+ switch (typeof value) {
206
+ case "boolean":
207
+ return { kind: Kind.BOOLEAN, value };
208
+ case "number":
209
+ if (!Number.isFinite(value)) {
210
+ throw new Error("Only finite numbers can be inlined into GraphQL queries.");
211
+ }
212
+ return Number.isInteger(value)
213
+ ? { kind: Kind.INT, value: String(value) }
214
+ : { kind: Kind.FLOAT, value: String(value) };
215
+ case "string":
216
+ return { kind: Kind.STRING, value };
217
+ case "object":
218
+ return {
219
+ kind: Kind.OBJECT,
220
+ fields: Object.entries(value).map(([name, entry]) => ({
221
+ kind: Kind.OBJECT_FIELD,
222
+ name: { kind: Kind.NAME, value: name },
223
+ value: createValueNode(entry),
224
+ })),
225
+ };
226
+ default:
227
+ throw new Error(`Unsupported variable value type "${typeof value}" for GraphQL inlining.`);
228
+ }
229
+ }
230
+ function compileQueryForExecution(options) {
231
+ try {
232
+ const document = parse(options.query);
233
+ const selectedOperation = getSelectedOperation(document, options.operationName);
234
+ const fragmentMap = new Map(document.definitions
235
+ .filter((definition) => definition.kind === Kind.FRAGMENT_DEFINITION)
236
+ .map((definition) => [definition.name.value, definition]));
237
+ const referencedFragments = collectReferencedFragments(selectedOperation, fragmentMap);
238
+ const reducedDocument = {
239
+ kind: Kind.DOCUMENT,
240
+ definitions: [
241
+ selectedOperation,
242
+ ...Array.from(referencedFragments)
243
+ .map((name) => fragmentMap.get(name))
244
+ .filter((definition) => Boolean(definition)),
245
+ ],
246
+ };
247
+ const variableDefinitions = selectedOperation.variableDefinitions ?? [];
248
+ const hasVariables = variableDefinitions.length > 0 &&
249
+ variableDefinitions.some((definition) => options.variables?.[definition.variable.name.value] !== undefined ||
250
+ definition.defaultValue !== undefined);
251
+ if (!hasVariables) {
252
+ return { ok: true, query: print(reducedDocument) };
253
+ }
254
+ const inlinedDocument = visit(reducedDocument, {
255
+ OperationDefinition(node) {
256
+ return {
257
+ ...node,
258
+ variableDefinitions: [],
259
+ };
260
+ },
261
+ Variable(node) {
262
+ const definition = variableDefinitions.find((entry) => entry.variable.name.value === node.name.value);
263
+ if (!definition) {
264
+ throw new Error(`Unknown variable "${node.name.value}" in GraphQL query.`);
265
+ }
266
+ const explicitValue = options.variables?.[node.name.value];
267
+ if (explicitValue !== undefined) {
268
+ return createValueNode(explicitValue);
269
+ }
270
+ if (definition.defaultValue) {
271
+ return definition.defaultValue;
272
+ }
273
+ throw new Error(`Variable "$${node.name.value}" is required, but Alpaca GraphQL requests do not accept a separate variables payload.`);
274
+ },
275
+ });
276
+ return {
277
+ ok: true,
278
+ query: print(inlinedDocument),
279
+ warning: "Variables were inlined client-side because the Alpaca GraphQL endpoints do not accept a separate variables payload.",
280
+ };
281
+ }
282
+ catch (error) {
283
+ return {
284
+ ok: false,
285
+ error: error instanceof Error ? error.message : String(error),
286
+ };
287
+ }
288
+ }
289
+ export async function executeGraphQLQuery({ query, host, path, language, mode, itemId, version, siteName, schema, sessionId, }) {
290
+ const modeValue = mode || "normal";
291
+ const v2Response = await post(GRAPHQL_V2_QUERY_URL, {
292
+ Query: query,
293
+ Schema: schema,
294
+ ItemContext: {
295
+ Database: getDatabaseFromMode(modeValue),
296
+ Language: language,
297
+ SiteName: siteName || "website",
298
+ ItemId: itemId,
299
+ Mode: modeValue,
300
+ },
301
+ }, sessionId);
302
+ if (v2Response.type === "success") {
303
+ if (v2Response.data?.errors) {
304
+ return {
305
+ status: 400,
306
+ errors: v2Response.data.errors,
307
+ transport: { requested: "v2", used: "v2" },
308
+ };
309
+ }
310
+ return {
311
+ data: v2Response.data?.data,
312
+ status: getStatus(v2Response),
313
+ transport: { requested: "v2", used: "v2" },
314
+ };
315
+ }
316
+ const v2Status = getStatus(v2Response);
317
+ if (!shouldFallbackToV1(v2Status)) {
318
+ return {
319
+ status: v2Status,
320
+ errors: [{ message: getErrorMessage(v2Response) }],
321
+ transport: { requested: "v2", used: "v2" },
322
+ };
323
+ }
324
+ const v1Response = await post(GRAPHQL_V1_QUERY_URL, {
325
+ Query: query,
326
+ Host: host,
327
+ Path: path,
328
+ ItemId: itemId,
329
+ Language: language,
330
+ Version: version,
331
+ Mode: mode,
332
+ SiteName: siteName,
333
+ Schema: schema,
334
+ }, sessionId);
335
+ if (v1Response.type !== "success") {
336
+ return {
337
+ status: getStatus(v1Response),
338
+ errors: [{ message: getErrorMessage(v1Response) }],
339
+ transport: {
340
+ requested: "v2",
341
+ used: "v1-fallback",
342
+ fallbackFromStatus: v2Status,
343
+ },
344
+ };
345
+ }
346
+ if (v1Response.data?.errors) {
347
+ return {
348
+ status: 400,
349
+ errors: v1Response.data.errors,
350
+ transport: {
351
+ requested: "v2",
352
+ used: "v1-fallback",
353
+ fallbackFromStatus: v2Status,
354
+ },
355
+ };
356
+ }
357
+ console.warn("GraphQL v2 request fell back to v1", JSON.stringify({
358
+ v2Status,
359
+ v1Status: getStatus(v1Response),
360
+ endpoint: GRAPHQL_V2_QUERY_URL,
361
+ }));
362
+ return {
363
+ data: v1Response.data?.data,
364
+ status: getStatus(v1Response),
365
+ transport: {
366
+ requested: "v2",
367
+ used: "v1-fallback",
368
+ fallbackFromStatus: v2Status,
369
+ },
370
+ };
371
+ }
372
+ export async function getGraphQLSchema({ id, language, version, mode, siteName, }) {
373
+ const v2Response = await executeGraphQLQuery({
374
+ query: DEFAULT_INTROSPECTION_QUERY,
375
+ itemId: id,
376
+ language,
377
+ version,
378
+ mode: mode || "edit",
379
+ siteName,
380
+ });
381
+ if (v2Response.status === 200 && !v2Response.errors) {
382
+ return {
383
+ data: JSON.stringify(v2Response.data ?? {}, null, 2),
384
+ status: v2Response.status,
385
+ transport: v2Response.transport,
386
+ };
387
+ }
388
+ if (!shouldFallbackToV1(v2Response.status)) {
389
+ return {
390
+ status: v2Response.status,
391
+ error: v2Response.errors?.[0]?.message || "Schema introspection failed",
392
+ transport: v2Response.transport,
393
+ };
394
+ }
395
+ const v1Url = `${GRAPHQL_V1_SCHEMA_URL}?id=${encodeURIComponent(id)}`;
396
+ const v1Response = await get(v1Url);
397
+ if (v1Response.type !== "success") {
398
+ return {
399
+ status: getStatus(v1Response),
400
+ error: getErrorMessage(v1Response),
401
+ transport: {
402
+ requested: "v2",
403
+ used: "v1-fallback",
404
+ fallbackFromStatus: v2Response.status,
405
+ },
406
+ };
407
+ }
408
+ const schemaText = v1Response.data ?? (await v1Response.response.text());
409
+ console.warn("GraphQL schema request fell back to v1", JSON.stringify({
410
+ v2Status: v2Response.status,
411
+ v1Status: getStatus(v1Response),
412
+ endpoint: v1Url,
413
+ }));
414
+ return {
415
+ data: schemaText,
416
+ status: getStatus(v1Response),
417
+ transport: {
418
+ requested: "v2",
419
+ used: "v1-fallback",
420
+ fallbackFromStatus: v2Response.status,
421
+ },
422
+ };
423
+ }
424
+ export async function executeGraphiQLRequest(options) {
425
+ const compiledQuery = compileQueryForExecution({
426
+ query: options.query,
427
+ variables: options.variables,
428
+ operationName: options.operationName,
429
+ });
430
+ if (!compiledQuery.ok) {
431
+ return { status: 400, error: compiledQuery.error };
432
+ }
433
+ const normalized = normalizePanelQuery(compiledQuery.query, options.item);
434
+ if (normalized.error) {
435
+ return {
436
+ status: 400,
437
+ error: normalized.error,
438
+ compiledQuery: compiledQuery.query,
439
+ };
440
+ }
441
+ const effectiveQuery = normalized.query ?? compiledQuery.query;
442
+ const warning = joinWarnings(normalized.warning, compiledQuery.warning);
443
+ try {
444
+ const response = await executeGraphQLQuery({
445
+ query: effectiveQuery,
446
+ itemId: options.item.id,
447
+ language: options.item.language,
448
+ version: options.item.version,
449
+ mode: "edit",
450
+ siteName: "website",
451
+ schema: "Default",
452
+ });
453
+ return {
454
+ ...response,
455
+ error: response.status && response.status !== 200 && !response.errors
456
+ ? "GraphQL request failed"
457
+ : undefined,
458
+ warning,
459
+ compiledQuery: effectiveQuery,
460
+ };
461
+ }
462
+ catch (error) {
463
+ return {
464
+ error: error instanceof Error ? error.message : String(error),
465
+ warning,
466
+ compiledQuery: effectiveQuery,
467
+ };
468
+ }
469
+ }
470
+ export async function fetchGraphiQLSchema(item) {
471
+ const response = await getGraphQLSchema({
472
+ id: item.id,
473
+ language: item.language,
474
+ version: item.version,
475
+ mode: "edit",
476
+ siteName: "website",
477
+ });
478
+ if (response.error) {
479
+ return {
480
+ status: response.status,
481
+ error: response.error,
482
+ transport: response.transport,
483
+ };
484
+ }
485
+ try {
486
+ const rawSchemaText = response.data ?? "";
487
+ const parsedSchema = rawSchemaText ? JSON.parse(rawSchemaText) : undefined;
488
+ return {
489
+ data: parsedSchema,
490
+ schema: parsedSchema ? buildClientSchema(parsedSchema) : undefined,
491
+ status: response.status,
492
+ transport: response.transport,
493
+ rawSchemaText,
494
+ };
495
+ }
496
+ catch (error) {
497
+ return {
498
+ status: response.status,
499
+ error: error instanceof Error
500
+ ? `Schema parsing failed: ${error.message}`
501
+ : "Schema parsing failed.",
502
+ transport: response.transport,
503
+ rawSchemaText: response.data,
504
+ };
505
+ }
506
+ }
507
+ export function getSchemaContextValue(schemaResult) {
508
+ if (schemaResult.data) {
509
+ return JSON.stringify(schemaResult.data, null, 2);
510
+ }
511
+ if (schemaResult.rawSchemaText) {
512
+ return schemaResult.rawSchemaText;
513
+ }
514
+ if (schemaResult.error) {
515
+ return schemaResult.error;
516
+ }
517
+ return "";
518
+ }
@@ -0,0 +1,3 @@
1
+ import { EditorConfiguration } from "@parhelia/core";
2
+ export declare function configureAlpacaDebug(configuration: EditorConfiguration): EditorConfiguration;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EAIpB,MAAM,gBAAgB,CAAC;AAsCxB,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,mBAAmB,uBAqBtE"}
package/dist/index.js ADDED
@@ -0,0 +1,52 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PanelsTopLeft } from "lucide-react";
3
+ import { GraphQLIcon, JsonIcon, } from "@parhelia/core";
4
+ import { Layout } from "./Layout";
5
+ import { GraphQL } from "./GraphQL";
6
+ const layoutDebugSidebar = {
7
+ id: "layout",
8
+ title: "Layout",
9
+ icon: _jsx(PanelsTopLeft, { strokeWidth: 1 }),
10
+ position: "left",
11
+ sortOrder: 100,
12
+ panels: [
13
+ {
14
+ name: "layout",
15
+ icon: _jsx(JsonIcon, {}),
16
+ title: "Layout",
17
+ content: _jsx(Layout, {}),
18
+ initialSize: 100,
19
+ },
20
+ ],
21
+ };
22
+ const graphqlSidebar = {
23
+ id: "graphql",
24
+ title: "GraphQL",
25
+ icon: _jsx(GraphQLIcon, {}),
26
+ position: "left",
27
+ sortOrder: 101,
28
+ panels: [
29
+ {
30
+ name: "graphql",
31
+ icon: _jsx(GraphQLIcon, {}),
32
+ title: "GraphQL",
33
+ content: _jsx(GraphQL, {}),
34
+ initialSize: 100,
35
+ },
36
+ ],
37
+ };
38
+ export function configureAlpacaDebug(configuration) {
39
+ const sidebars = (configuration.editor?.sidebars || []).filter((s) => s.id !== "debug");
40
+ const hasLayoutDebugSidebar = sidebars.some((s) => s.id === layoutDebugSidebar.id);
41
+ const hasGraphqlSidebar = sidebars.some((s) => s.id === graphqlSidebar.id);
42
+ const nextSidebars = [...sidebars];
43
+ if (!hasLayoutDebugSidebar)
44
+ nextSidebars.push(layoutDebugSidebar);
45
+ if (!hasGraphqlSidebar)
46
+ nextSidebars.push(graphqlSidebar);
47
+ configuration.editor = {
48
+ ...configuration.editor,
49
+ sidebars: nextSidebars,
50
+ };
51
+ return configuration;
52
+ }
@@ -0,0 +1,3 @@
1
+ import { ItemDescriptor } from "@parhelia/core";
2
+ export declare function getPageJson(page: ItemDescriptor): Promise<any>;
3
+ //# sourceMappingURL=services.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAQ,MAAM,gBAAgB,CAAC;AAEtD,wBAAsB,WAAW,CAAC,IAAI,EAAE,cAAc,gBAQrD"}
@@ -0,0 +1,10 @@
1
+ import { post } from "@parhelia/core";
2
+ export async function getPageJson(page) {
3
+ const response = await post("/alpaca/headless/layout", {
4
+ itemId: page.id,
5
+ language: page.language,
6
+ version: page.version,
7
+ mode: "preview",
8
+ });
9
+ return response.data?.page;
10
+ }
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@parhelia/alpaca",
3
+ "version": "0.1.12451",
4
+ "type": "module",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "development": "./src/index.tsx",
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ },
17
+ "./styles.css": "./styles.css"
18
+ },
19
+ "files": [
20
+ "dist/",
21
+ "styles.css",
22
+ "README.md",
23
+ "LICENSE"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsc -p tsconfig.build.json",
27
+ "lint": "eslint . --max-warnings 0",
28
+ "check-types": "tsc --noEmit"
29
+ },
30
+ "devDependencies": {
31
+ "@repo/eslint-config": "*",
32
+ "@repo/typescript-config": "*",
33
+ "@tailwindcss/postcss": "^4.1.18",
34
+ "@types/node": "^22.13.9",
35
+ "@types/react": "19.2.14",
36
+ "@types/react-dom": "19.2.3",
37
+ "eslint": "^9.22.0",
38
+ "tailwindcss": "^4.1.18",
39
+ "typescript": "5.8.2"
40
+ },
41
+ "dependencies": {
42
+ "@graphiql/plugin-explorer": "^5.1.1",
43
+ "@graphiql/react": "^0.37.3",
44
+ "@parhelia/core": "*",
45
+ "@uiw/react-textarea-code-editor": "^3.1.1",
46
+ "graphiql": "^5.2.2",
47
+ "graphql": "^15.10.1",
48
+ "lucide-react": "^0.486.0",
49
+ "postcss": "^8.5.3",
50
+ "react": "19.2.4",
51
+ "react-dom": "19.2.4",
52
+ "react-inspector": "^6.0.2"
53
+ },
54
+ "overrides": {
55
+ "@types/react": "19.2.14",
56
+ "@types/react-dom": "19.2.3"
57
+ }
58
+ }
package/styles.css ADDED
@@ -0,0 +1,8 @@
1
+ /*
2
+ This package intentionally does NOT ship a Tailwind utilities bundle.
3
+ The consuming app should generate utilities by scanning this package's
4
+ compiled JS output.
5
+ */
6
+
7
+ @source "./src/**/*.{js,ts,jsx,tsx}";
8
+ @source "./dist/**/*.js";