@dyrected/admin 2.5.61 → 2.5.62

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.
@@ -2,7 +2,7 @@ import { VariantProps } from 'class-variance-authority';
2
2
  import * as React from "react";
3
3
  declare const buttonVariants: (props?: {
4
4
  variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost";
5
- size?: "default" | "sm" | "lg" | "icon";
5
+ size?: "icon" | "default" | "sm" | "lg";
6
6
  } & import('class-variance-authority/types').ClassProp) => string;
7
7
  export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
8
8
  asChild?: boolean;
@@ -48,7 +48,7 @@ declare const CommandGroup: React.ForwardRefExoticComponent<Omit<{
48
48
  ref?: React.Ref<HTMLDivElement>;
49
49
  } & {
50
50
  asChild?: boolean;
51
- }, "key" | keyof React.HTMLAttributes<HTMLDivElement> | "asChild">, "value" | "heading"> & {
51
+ }, "key" | keyof React.HTMLAttributes<HTMLDivElement> | "asChild">, "heading" | "value"> & {
52
52
  heading?: React.ReactNode;
53
53
  value?: string;
54
54
  forceMount?: boolean;
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ import React, { Component, StrictMode, createContext, createElement, useCallback
3
3
  import { createRoot } from "react-dom/client";
4
4
  import { HashRouter, Link, MemoryRouter, Route, Routes, useLocation, useNavigate, useParams, useSearchParams } from "react-router-dom";
5
5
  import { QueryClient, QueryClientProvider, keepPreviousData, useInfiniteQuery, useMutation, useQueries, useQuery, useQueryClient } from "@tanstack/react-query";
6
- import { PREVIEW_TOKEN_PARAM, createClient } from "@dyrected/sdk";
6
+ import { DyrectedError, PREVIEW_TOKEN_PARAM, createClient } from "@dyrected/sdk";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { AlertCircle, AlertTriangle, AlignCenter, AlignLeft, AlignRight, Archive, ArrowDown, ArrowLeft, ArrowRight, ArrowUp, ArrowUpDown, ArrowUpRight, Bold, Braces, Calendar, Check, CheckCircle, CheckCircle2, ChevronDown, ChevronLeft, ChevronLeftIcon, ChevronRight, ChevronRightIcon, ChevronUp, ChevronsUpDown, Circle, Clock, Clock3, Code, Copy, Database, Download, ExternalLink, Eye, EyeOff, FileDown, FileIcon, FileText, FileUp, Filter, Globe, GripVertical, Heading1, Heading2, Heading3, Heading4, Heading5, Heading6, History, Home, Image as Image$1, Info, Italic, KeyRound, Layers, LayoutDashboard, LayoutGrid, Library, Link as Link$1, List, ListOrdered, Loader2, Lock, LogOut, Mail, Menu, Monitor, Moon, MoreHorizontal, MousePointer2, PanelLeftClose, PanelLeftOpen, Pencil, Play, Plus, Quote, RotateCcw, Save, Scissors, Search, Settings, Settings2, Share2, Shield, Smartphone, Sparkles, Star, Strikethrough, Sun, Table, Trash2, Underline, Undo2, Upload, UploadCloud, Users, Video, Volume2, Workflow, X, XCircle, icons } from "lucide-react";
9
9
  import { clsx } from "clsx";
@@ -67,6 +67,35 @@ function useDyrected() {
67
67
  }
68
68
  //#endregion
69
69
  //#region src/providers/dyrected-provider.tsx
70
+ function resolveBlock(block, registry) {
71
+ return {
72
+ ...block,
73
+ fields: block.fields.map((field) => resolveFieldBlocks(field, registry))
74
+ };
75
+ }
76
+ function resolveFieldBlocks(field, registry) {
77
+ const next = { ...field };
78
+ if (next.fields) next.fields = next.fields.map((child) => resolveFieldBlocks(child, registry));
79
+ if (next.type === "blocks" && next.blockReferences?.length) {
80
+ next.blocks = next.blockReferences.map((slug) => registry.get(slug)).filter((block) => !!block);
81
+ next.blocks = next.blocks.map((block) => resolveBlock(block, registry));
82
+ } else if (next.blocks) next.blocks = next.blocks.map((block) => resolveBlock(block, registry));
83
+ return next;
84
+ }
85
+ function resolveSchemas(schema) {
86
+ const registry = new Map((schema.blocks ?? []).map((block) => [block.slug, block]));
87
+ return {
88
+ ...schema,
89
+ collections: schema.collections.map((collection) => ({
90
+ ...collection,
91
+ fields: collection.fields.map((field) => resolveFieldBlocks(field, registry))
92
+ })),
93
+ globals: schema.globals.map((global) => ({
94
+ ...global,
95
+ fields: global.fields.map((field) => resolveFieldBlocks(field, registry))
96
+ }))
97
+ };
98
+ }
70
99
  function DyrectedProvider({ children, apiKey: initialApiKey, baseUrl: initialBaseUrl, siteId: initialSiteId, initialToken, defaultTechStack, components }) {
71
100
  const [baseUrl, setBaseUrl] = useState(() => initialBaseUrl || (typeof window !== "undefined" ? localStorage.getItem("dyrected_url") : null) || "");
72
101
  const [apiKey, setApiKey] = useState(() => initialApiKey || (typeof window !== "undefined" ? localStorage.getItem("dyrected_key") : null) || void 0);
@@ -94,7 +123,8 @@ function DyrectedProvider({ children, apiKey: initialApiKey, baseUrl: initialBas
94
123
  };
95
124
  client.getSchemas().then((nextSchemas) => {
96
125
  if (cancelled) return;
97
- setSchemas((prev) => prev === nextSchemas ? prev : nextSchemas);
126
+ const resolved = resolveSchemas(nextSchemas);
127
+ setSchemas((prev) => prev === resolved ? prev : resolved);
98
128
  }, (err) => {
99
129
  if (cancelled) return;
100
130
  console.error("Failed to fetch schemas:", err);
@@ -108,6 +138,16 @@ function DyrectedProvider({ children, apiKey: initialApiKey, baseUrl: initialBas
108
138
  useEffect(() => {
109
139
  if (initialToken && client) client.setToken(initialToken);
110
140
  }, [initialToken, client]);
141
+ const clearPersistedAuthState = useCallback((nextClient) => {
142
+ localStorage.removeItem("dyrected_token");
143
+ localStorage.removeItem("dyrected_admin_auth_collection");
144
+ (nextClient ?? client)?.clearToken();
145
+ setAuthCollectionSlug(null);
146
+ setUser(null);
147
+ }, [client]);
148
+ const shouldClearStoredAuth = useCallback((error) => {
149
+ return error instanceof DyrectedError && (error.statusCode === 401 || error.statusCode === 404);
150
+ }, []);
111
151
  const setAuth = useCallback((newUrl, newKey, newSiteId) => {
112
152
  localStorage.setItem("dyrected_url", newUrl);
113
153
  localStorage.setItem("dyrected_key", newKey);
@@ -119,11 +159,7 @@ function DyrectedProvider({ children, apiKey: initialApiKey, baseUrl: initialBas
119
159
  }, []);
120
160
  const setToken = useCallback((token, collectionSlug) => {
121
161
  if (!token) {
122
- localStorage.removeItem("dyrected_token");
123
- localStorage.removeItem("dyrected_admin_auth_collection");
124
- if (client) client.clearToken();
125
- setAuthCollectionSlug(null);
126
- setUser(null);
162
+ clearPersistedAuthState(client);
127
163
  return;
128
164
  }
129
165
  const resolvedCollectionSlug = collectionSlug || authCollectionSlug || getAdminCollectionSlug(schemas);
@@ -134,12 +170,20 @@ function DyrectedProvider({ children, apiKey: initialApiKey, baseUrl: initialBas
134
170
  }
135
171
  if (client) {
136
172
  client.setToken(token);
137
- if (resolvedCollectionSlug) client.collection(resolvedCollectionSlug).me().then((nextUser) => setUser(nextUser), () => setUser(null));
173
+ if (resolvedCollectionSlug) client.collection(resolvedCollectionSlug).me().then((nextUser) => setUser(nextUser), (error) => {
174
+ if (shouldClearStoredAuth(error)) {
175
+ clearPersistedAuthState(client);
176
+ return;
177
+ }
178
+ setUser(null);
179
+ });
138
180
  }
139
181
  }, [
140
182
  authCollectionSlug,
183
+ clearPersistedAuthState,
141
184
  client,
142
- schemas
185
+ schemas,
186
+ shouldClearStoredAuth
143
187
  ]);
144
188
  useEffect(() => {
145
189
  if (initialToken || !client || !schemas || activeUser) return;
@@ -147,21 +191,39 @@ function DyrectedProvider({ children, apiKey: initialApiKey, baseUrl: initialBas
147
191
  const resolvedCollectionSlug = authCollectionSlug || getAdminCollectionSlug(schemas);
148
192
  if (!token || !resolvedCollectionSlug) return;
149
193
  client.setToken(token);
150
- client.collection(resolvedCollectionSlug).me().then((nextUser) => setUser(nextUser), () => setUser(null));
194
+ client.collection(resolvedCollectionSlug).me().then((nextUser) => setUser(nextUser), (error) => {
195
+ if (shouldClearStoredAuth(error)) {
196
+ clearPersistedAuthState(client);
197
+ return;
198
+ }
199
+ setUser(null);
200
+ });
151
201
  }, [
152
202
  activeUser,
153
203
  authCollectionSlug,
204
+ clearPersistedAuthState,
154
205
  client,
155
206
  initialToken,
156
- schemas
207
+ schemas,
208
+ shouldClearStoredAuth
157
209
  ]);
158
210
  const logout = useCallback(() => {
159
- localStorage.removeItem("dyrected_token");
160
- localStorage.removeItem("dyrected_admin_auth_collection");
161
- if (client) client.clearToken();
162
- setAuthCollectionSlug(null);
163
- setUser(null);
164
- }, [client]);
211
+ (async () => {
212
+ const resolvedCollectionSlug = authCollectionSlug || getAdminCollectionSlug(schemas);
213
+ try {
214
+ if (client && resolvedCollectionSlug) await client.collection(resolvedCollectionSlug).logout();
215
+ } catch (error) {
216
+ console.warn("Failed to revoke admin session during logout:", error);
217
+ } finally {
218
+ clearPersistedAuthState(client);
219
+ }
220
+ })();
221
+ }, [
222
+ authCollectionSlug,
223
+ clearPersistedAuthState,
224
+ client,
225
+ schemas
226
+ ]);
165
227
  return /* @__PURE__ */ jsx(DyrectedContext.Provider, {
166
228
  value: {
167
229
  client,
@@ -976,7 +1038,7 @@ function isNewerVersion(latest, current) {
976
1038
  return false;
977
1039
  }
978
1040
  function useUpdateCheck() {
979
- const currentVersion = "2.5.60";
1041
+ const currentVersion = "2.5.62";
980
1042
  const [updateInfo, setUpdateInfo] = useState(() => {
981
1043
  if (typeof window === "undefined") return null;
982
1044
  const cacheKey = "dyrected_latest_release";
@@ -1202,7 +1264,7 @@ function getStatusLabel(doc) {
1202
1264
  }
1203
1265
  function Dashboard() {
1204
1266
  const { client, components, user } = useDyrected();
1205
- const currentVersion = "2.5.60";
1267
+ const currentVersion = "2.5.62";
1206
1268
  const [latestVersion, setLatestVersion] = useState(() => {
1207
1269
  if (typeof window === "undefined") return null;
1208
1270
  return localStorage.getItem("dyrected_latest_release");
@@ -11815,10 +11877,10 @@ function LivePreviewPane({ previewUrl, data, mode = "postMessage", collectionSlu
11815
11877
  const [tokenSrc, setTokenSrc] = useState(null);
11816
11878
  const [tokenError, setTokenError] = useState(null);
11817
11879
  const lastDataKeyRef = useRef(null);
11880
+ const dataKey = safeStringify(data);
11818
11881
  useEffect(() => {
11819
11882
  if (mode !== "token" || !client || !collectionSlug) return;
11820
- const key = safeStringify(data);
11821
- if (key === lastDataKeyRef.current) return;
11883
+ if (dataKey === lastDataKeyRef.current) return;
11822
11884
  let cancelled = false;
11823
11885
  const timer = setTimeout(async () => {
11824
11886
  try {
@@ -11828,7 +11890,7 @@ function LivePreviewPane({ previewUrl, data, mode = "postMessage", collectionSlu
11828
11890
  data
11829
11891
  });
11830
11892
  if (cancelled) return;
11831
- lastDataKeyRef.current = key;
11893
+ lastDataKeyRef.current = dataKey;
11832
11894
  setTokenSrc(withPreviewToken(previewUrl, token));
11833
11895
  setTokenError(null);
11834
11896
  } catch (err) {
@@ -11846,7 +11908,7 @@ function LivePreviewPane({ previewUrl, data, mode = "postMessage", collectionSlu
11846
11908
  collectionSlug,
11847
11909
  documentId,
11848
11910
  previewUrl,
11849
- data
11911
+ dataKey
11850
11912
  ]);
11851
11913
  const iframeSrc = mode === "token" ? tokenSrc ?? previewUrl : previewUrl;
11852
11914
  useEffect(() => {
@@ -14672,7 +14734,7 @@ function SetupPromptUI({ config }) {
14672
14734
  setCopied(true);
14673
14735
  window.setTimeout(() => setCopied(false), 1800);
14674
14736
  }
14675
- const currentVersion = "2.5.60";
14737
+ const currentVersion = "2.5.62";
14676
14738
  const [latestVersion, setLatestVersion] = useState(() => {
14677
14739
  if (typeof window === "undefined") return null;
14678
14740
  return localStorage.getItem("dyrected_latest_release");
@@ -7,6 +7,6 @@ export interface DyrectedProviderProps {
7
7
  siteId?: string;
8
8
  initialToken?: string;
9
9
  defaultTechStack?: string;
10
- components?: DyrectedContextType['components'];
10
+ components?: DyrectedContextType["components"];
11
11
  }
12
- export declare function DyrectedProvider({ children, apiKey: initialApiKey, baseUrl: initialBaseUrl, siteId: initialSiteId, initialToken, defaultTechStack, components }: DyrectedProviderProps): React.JSX.Element;
12
+ export declare function DyrectedProvider({ children, apiKey: initialApiKey, baseUrl: initialBaseUrl, siteId: initialSiteId, initialToken, defaultTechStack, components, }: DyrectedProviderProps): React.JSX.Element;
@@ -1,8 +1,9 @@
1
1
  import { ComponentType } from 'react';
2
- import { AdminConfig, CollectionConfig, GlobalConfig, PublicAdminAuthConfig } from '@dyrected/core';
2
+ import { AdminConfig, Block, CollectionConfig, GlobalConfig, PublicAdminAuthConfig } from '@dyrected/core';
3
3
  import { DyrectedClient, PaginatedResult } from '@dyrected/sdk';
4
4
  /** All collection and global schemas returned by the backend, plus optional admin config. */
5
5
  export interface AdminSchemas {
6
+ blocks?: Block[];
6
7
  collections: CollectionConfig[];
7
8
  globals: GlobalConfig[];
8
9
  admin?: AdminConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dyrected/admin",
3
- "version": "2.5.61",
3
+ "version": "2.5.62",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"
@@ -64,9 +64,9 @@
64
64
  "tailwind-merge": "^3.5.0",
65
65
  "tailwindcss-animate": "^1.0.7",
66
66
  "zod": "^3.25.76",
67
- "@dyrected/core": "^2.5.61",
68
- "@dyrected/knowledge": "^0.2.13",
69
- "@dyrected/sdk": "^2.5.61"
67
+ "@dyrected/core": "^2.5.62",
68
+ "@dyrected/knowledge": "^0.2.15",
69
+ "@dyrected/sdk": "^2.5.62"
70
70
  },
71
71
  "peerDependencies": {
72
72
  "@tanstack/react-query": "^5.0.0",