@meeovi/directus-client 1.0.0 → 1.0.2

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 (55) hide show
  1. package/README.md +238 -0
  2. package/dist/client/createClient.d.ts +14 -0
  3. package/dist/client/createClient.js +18 -0
  4. package/dist/generators/form-engine.d.ts +13 -0
  5. package/dist/generators/form-engine.js +22 -0
  6. package/dist/generators/table-engine.d.ts +6 -0
  7. package/dist/generators/table-engine.js +9 -0
  8. package/dist/generators/validation-engine.d.ts +2 -0
  9. package/dist/generators/validation-engine.js +25 -0
  10. package/dist/generators/widget-registry.d.ts +9 -0
  11. package/dist/generators/widget-registry.js +54 -0
  12. package/dist/index.d.ts +13 -0
  13. package/dist/index.js +17 -0
  14. package/dist/react/DirectusProvider.d.ts +7 -0
  15. package/dist/react/DirectusProvider.js +6 -0
  16. package/dist/react/useDirectus.d.ts +2 -0
  17. package/dist/react/useDirectus.js +9 -0
  18. package/dist/schema/introspect.d.ts +5 -0
  19. package/dist/schema/introspect.js +30 -0
  20. package/dist/schema/types.d.ts +47 -0
  21. package/dist/schema/types.js +1 -0
  22. package/dist/utils/collections.d.ts +5 -0
  23. package/dist/utils/collections.js +13 -0
  24. package/dist/utils/fields.d.ts +4 -0
  25. package/dist/utils/fields.js +40 -0
  26. package/dist/utils/livePreview.d.ts +11 -0
  27. package/dist/utils/livePreview.js +11 -0
  28. package/dist/utils/useDirectusField.d.ts +10 -0
  29. package/dist/utils/useDirectusField.js +119 -0
  30. package/dist/utils/useDirectusRequest.d.ts +7 -0
  31. package/dist/utils/useDirectusRequest.js +33 -0
  32. package/dist/utils/useLivePreview.d.ts +1 -0
  33. package/dist/utils/useLivePreview.js +16 -0
  34. package/dist/utils/useVisualEditing.d.ts +18 -0
  35. package/dist/utils/useVisualEditing.js +27 -0
  36. package/dist/utils/visualEditing.d.ts +21 -0
  37. package/dist/utils/visualEditing.js +25 -0
  38. package/dist/vue/DirectusProvider.d.ts +15 -0
  39. package/dist/vue/DirectusProvider.js +12 -0
  40. package/dist/vue/useDirectus.d.ts +2 -0
  41. package/dist/vue/useDirectus.js +9 -0
  42. package/package.json +16 -5
  43. package/src/client/createClient.ts +5 -4
  44. package/src/generators/form-engine.ts +31 -81
  45. package/src/generators/widget-registry.ts +71 -4
  46. package/src/react/useDirectus.ts +1 -1
  47. package/src/utils/livePreview.ts +24 -0
  48. package/src/utils/visualEditing.ts +46 -0
  49. package/src/vue/useDirectus.ts +1 -1
  50. package/tsconfig.json +15 -0
  51. package/src/utils/useDirectusField.ts +0 -144
  52. package/src/utils/useDirectusRequest.ts +0 -32
  53. package/src/utils/useDirectusSchema.js +0 -9
  54. package/src/utils/useLivePreview.ts +0 -17
  55. package/src/utils/useVisualEditing.ts +0 -38
package/README.md CHANGED
@@ -0,0 +1,238 @@
1
+ # @meeovi/directus-client
2
+
3
+ A framework-agnostic, type-safe Directus client with optional bindings for Vue 3, Nuxt 3, and React. Includes schema introspection, auto-form and auto-table generators, validation utilities, and visual-editing / live-preview helpers.
4
+
5
+ Designed for modular, provider-agnostic platforms like Meeovi, but usable in any Directus-powered project.
6
+
7
+ ## Features
8
+
9
+ - Framework-agnostic Directus client
10
+ - Vue 3 bindings (`useDirectus`, `DirectusVueProvider`)
11
+ - React bindings (`useDirectus`, `DirectusReactProvider`)
12
+ - Schema introspection
13
+ - Auto-form engine
14
+ - Auto-table engine
15
+ - Validation engine
16
+ - Widget registry
17
+ - Visual editing utilities
18
+ - Live preview utilities
19
+ - Fully typed and tree-shakeable
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install @meeovi/directus-client
25
+ # or
26
+ pnpm add @meeovi/directus-client
27
+ ```
28
+
29
+ ## Package structure
30
+
31
+ ```
32
+ src/
33
+ client/
34
+ createClient.ts
35
+ vue/
36
+ DirectusProvider.ts
37
+ useDirectus.ts
38
+ react/
39
+ DirectusProvider.tsx
40
+ useDirectus.ts
41
+ schema/
42
+ types.ts
43
+ introspect.ts
44
+ utils/
45
+ collections.ts
46
+ fields.ts
47
+ generators/
48
+ form-engine.ts
49
+ table-engine.ts
50
+ validation-engine.ts
51
+ widget-registry.ts
52
+ visual-editing.ts
53
+ live-preview.ts
54
+ index.ts
55
+ ```
56
+
57
+ ## Usage
58
+
59
+ ### 1) Framework-agnostic
60
+
61
+ ```ts
62
+ import { createMeeoviDirectusClient } from '@meeovi/directus-client';
63
+
64
+ const directus = createMeeoviDirectusClient('https://your-directus-url.com');
65
+
66
+ // Example request
67
+ const products = await directus.client.request(directus.readItems('products'));
68
+ ```
69
+
70
+ ### 2) Vue 3
71
+
72
+ Wrap your app:
73
+
74
+ ```ts
75
+ import { DirectusVueProvider, createMeeoviDirectusClient } from '@meeovi/directus-client';
76
+
77
+ const directus = createMeeoviDirectusClient('https://cms.example.com');
78
+ ```
79
+
80
+ ```vue
81
+ <template>
82
+ <DirectusVueProvider :client="directus">
83
+ <App />
84
+ </DirectusVueProvider>
85
+ </template>
86
+ ```
87
+
88
+ Use inside components:
89
+
90
+ ```ts
91
+ import { useDirectus } from '@meeovi/directus-client';
92
+
93
+ const directus = useDirectus();
94
+ const items = await directus.client.request(directus.readItems('articles'));
95
+ ```
96
+
97
+ ### 3) Nuxt 3
98
+
99
+ Create a plugin:
100
+
101
+ ```ts
102
+ // plugins/directus.client.ts
103
+ import { defineNuxtPlugin, useRuntimeConfig } from '#imports';
104
+ import { createMeeoviDirectusClient, DirectusVueProvider } from '@meeovi/directus-client';
105
+
106
+ export default defineNuxtPlugin((nuxtApp) => {
107
+ const config = useRuntimeConfig();
108
+ const directus = createMeeoviDirectusClient(config.public.directus.url);
109
+
110
+ nuxtApp.provide('directus', directus);
111
+ nuxtApp.vueApp.component('DirectusVueProvider', DirectusVueProvider);
112
+ });
113
+ ```
114
+
115
+ Use it:
116
+
117
+ ```ts
118
+ const { $directus } = useNuxtApp();
119
+ const posts = await $directus.client.request($directus.readItems('posts'));
120
+ ```
121
+
122
+ ### 4) React
123
+
124
+ Wrap your app:
125
+
126
+ ```tsx
127
+ import { DirectusReactProvider, createMeeoviDirectusClient } from '@meeovi/directus-client';
128
+
129
+ const directus = createMeeoviDirectusClient('https://cms.example.com');
130
+
131
+ export function App() {
132
+ return (
133
+ <DirectusReactProvider client={directus}>
134
+ <YourRoutes />
135
+ </DirectusReactProvider>
136
+ );
137
+ }
138
+ ```
139
+
140
+ Use inside components:
141
+
142
+ ```tsx
143
+ import { useDirectus } from '@meeovi/directus-client';
144
+ const directus = useDirectus();
145
+ const items = await directus.client.request(directus.readItems('products'));
146
+ ```
147
+
148
+ ## Schema introspection
149
+
150
+ ```ts
151
+ import { introspectSchema } from '@meeovi/directus-client';
152
+
153
+ const schema = await introspectSchema(directus.client);
154
+ console.log(schema.directus_fields);
155
+ ```
156
+
157
+ ## Auto-Form Engine
158
+
159
+ ```ts
160
+ import { createFormEngine } from '@meeovi/directus-client';
161
+
162
+ const engine = createFormEngine('products', fields, directus);
163
+ engine.form.title = 'New Product';
164
+ const result = await engine.submit();
165
+ ```
166
+
167
+ ## Auto-Table Engine
168
+
169
+ ```ts
170
+ import { generateTableSchema } from '@meeovi/directus-client';
171
+ const table = generateTableSchema(fields);
172
+ console.log(table);
173
+ ```
174
+
175
+ ## Validation Engine
176
+
177
+ ```ts
178
+ import { validateField } from '@meeovi/directus-client';
179
+ const error = validateField(field, value);
180
+ if (error) console.error(error);
181
+ ```
182
+
183
+ ## Widget Registry
184
+
185
+ ```ts
186
+ import { widgetRegistry } from '@meeovi/directus-client';
187
+ console.log(widgetRegistry.text.component);
188
+ ```
189
+
190
+ ## Visual Editing (framework-agnostic)
191
+
192
+ ```ts
193
+ import { createVisualEditing } from '@meeovi/directus-client';
194
+
195
+ const visual = createVisualEditing({
196
+ enableVisualEditing: true,
197
+ directusUrl: 'https://cms.example.com',
198
+ query: { 'visual-editing': 'true' },
199
+ });
200
+
201
+ visual.apply({ elements: document.querySelectorAll('[data-editable]') });
202
+ ```
203
+
204
+ ## Live Preview (framework-agnostic)
205
+
206
+ ```ts
207
+ import { createLivePreview } from '@meeovi/directus-client';
208
+
209
+ const preview = createLivePreview({
210
+ query: Object.fromEntries(new URLSearchParams(location.search)),
211
+ });
212
+
213
+ if (preview.enabled) {
214
+ console.log('Preview token:', preview.state.token);
215
+ }
216
+ ```
217
+
218
+ ## TypeScript support
219
+
220
+ Everything is fully typed: Directus schema, client methods, form/table generators, visual editing, live preview, and framework bindings.
221
+
222
+ ## Build
223
+
224
+ If you’re working inside a monorepo:
225
+
226
+ ```bash
227
+ npm --workspace @meeovi/directus-client run build
228
+ # or
229
+ pnpm --filter @meeovi/directus-client build
230
+ ```
231
+
232
+ ## Contributing
233
+
234
+ PRs are welcome. This package is designed to be modular, extensible, and framework-agnostic — contributions that improve developer experience or expand framework bindings are encouraged.
235
+
236
+ ## License
237
+
238
+ MIT © Meeovi
@@ -0,0 +1,14 @@
1
+ import { readItem, readItems, createItem, updateItem, deleteItem, uploadFiles, readSingleton, readFieldsByCollection, type DirectusClient } from '@directus/sdk';
2
+ export interface MeeoviDirectusClient<Schema> {
3
+ client: DirectusClient<Schema>;
4
+ request: any;
5
+ readItem: typeof readItem;
6
+ readItems: typeof readItems;
7
+ createItem: typeof createItem;
8
+ updateItem: typeof updateItem;
9
+ deleteItem: typeof deleteItem;
10
+ uploadFiles: typeof uploadFiles;
11
+ readSingleton: typeof readSingleton;
12
+ readFieldsByCollection: typeof readFieldsByCollection;
13
+ }
14
+ export declare function createMeeoviDirectusClient<Schema>(url: string): MeeoviDirectusClient<Schema>;
@@ -0,0 +1,18 @@
1
+ import { createDirectus, rest, authentication, readItem, readItems, createItem, updateItem, deleteItem, uploadFiles, readSingleton, readFieldsByCollection } from '@directus/sdk';
2
+ export function createMeeoviDirectusClient(url) {
3
+ const client = createDirectus(url)
4
+ .with(rest())
5
+ .with(authentication());
6
+ return {
7
+ client,
8
+ request: client.request,
9
+ readItem,
10
+ readItems,
11
+ createItem,
12
+ updateItem,
13
+ deleteItem,
14
+ uploadFiles,
15
+ readSingleton,
16
+ readFieldsByCollection
17
+ };
18
+ }
@@ -0,0 +1,13 @@
1
+ import type { DirectusField } from '../schema/types';
2
+ export interface GeneratedFormField {
3
+ key: string;
4
+ widget: string;
5
+ type: string;
6
+ options?: Record<string, any>;
7
+ fields?: GeneratedFormField[];
8
+ isRepeatable?: boolean;
9
+ isFile?: boolean;
10
+ isRelational?: boolean;
11
+ }
12
+ export declare function generateFormField(field: DirectusField): GeneratedFormField;
13
+ export declare function generateFormSchema(fields: DirectusField[]): GeneratedFormField[];
@@ -0,0 +1,22 @@
1
+ import { widgetRegistry } from './widget-registry';
2
+ export function generateFormField(field) {
3
+ const widget = widgetRegistry[field.interface || 'input'];
4
+ const base = {
5
+ key: field.field,
6
+ widget: widget.component,
7
+ type: field.type,
8
+ options: field.options || {},
9
+ isRepeatable: widget.isRepeatable,
10
+ isFile: widget.isFile,
11
+ isRelational: widget.isRelational
12
+ };
13
+ if ((field.interface === 'repeater' || field.interface === 'group') && field.options?.fields) {
14
+ base.fields = field.options.fields.map((sub) => generateFormField(sub));
15
+ }
16
+ return base;
17
+ }
18
+ export function generateFormSchema(fields) {
19
+ return fields
20
+ .filter(f => f.interface !== 'presentation' && f.interface !== 'divider')
21
+ .map(generateFormField);
22
+ }
@@ -0,0 +1,6 @@
1
+ import type { DirectusField } from '../schema/types';
2
+ export declare function generateTableSchema(fields: DirectusField[]): {
3
+ key: string;
4
+ label: string;
5
+ type: string;
6
+ }[];
@@ -0,0 +1,9 @@
1
+ export function generateTableSchema(fields) {
2
+ return fields
3
+ .filter(f => !f.hidden)
4
+ .map(f => ({
5
+ key: f.field,
6
+ label: f.field.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()),
7
+ type: f.type
8
+ }));
9
+ }
@@ -0,0 +1,2 @@
1
+ import type { DirectusField } from '../schema/types';
2
+ export declare function validateField(field: DirectusField, value: any): string | null;
@@ -0,0 +1,25 @@
1
+ export function validateField(field, value) {
2
+ if (!field.validation)
3
+ return null;
4
+ try {
5
+ const validation = field.validation;
6
+ if (validation._and) {
7
+ for (const rule of validation._and) {
8
+ const fieldName = Object.keys(rule)[0];
9
+ if (!fieldName)
10
+ continue;
11
+ const ruleDef = rule[fieldName];
12
+ if (ruleDef?._regex) {
13
+ const regex = new RegExp(ruleDef._regex);
14
+ if (!regex.test(String(value ?? ''))) {
15
+ return field.validation_message || `${field.field} failed validation`;
16
+ }
17
+ }
18
+ }
19
+ }
20
+ }
21
+ catch {
22
+ return `Validation error for ${field.field}`;
23
+ }
24
+ return null;
25
+ }
@@ -0,0 +1,9 @@
1
+ export interface WidgetDefinition {
2
+ component: string;
3
+ props?: Record<string, any>;
4
+ isRepeatable?: boolean;
5
+ isRelational?: boolean;
6
+ isFile?: boolean;
7
+ }
8
+ export declare const widgetRegistry: Record<string, WidgetDefinition>;
9
+ export declare function extendWidgetRegistryFromDirectus(client: any): Promise<void>;
@@ -0,0 +1,54 @@
1
+ import { readItems } from "@directus/sdk";
2
+ export const widgetRegistry = {
3
+ // Basic inputs
4
+ input: { component: 'TextInput' },
5
+ textarea: { component: 'TextareaInput' },
6
+ boolean: { component: 'ToggleInput' },
7
+ slider: { component: 'SliderInput' },
8
+ color: { component: 'ColorPicker' },
9
+ rating: { component: 'RatingInput' },
10
+ // Selects
11
+ 'select-dropdown': { component: 'SelectInput' },
12
+ 'select-multiple-dropdown': { component: 'MultiSelectInput' },
13
+ tags: { component: 'TagInput' },
14
+ checkbox: { component: 'CheckboxInput' },
15
+ radio: { component: 'RadioInput' },
16
+ // Date/time
17
+ datetime: { component: 'DateTimeInput' },
18
+ date: { component: 'DateInput' },
19
+ time: { component: 'TimeInput' },
20
+ // Files
21
+ file: { component: 'FileInput', isFile: true },
22
+ files: { component: 'FilesInput', isFile: true },
23
+ image: { component: 'ImageInput', isFile: true },
24
+ images: { component: 'ImagesInput', isFile: true },
25
+ // Complex
26
+ repeater: { component: 'RepeaterInput', isRepeatable: true },
27
+ group: { component: 'GroupInput' },
28
+ json: { component: 'JsonEditor' },
29
+ code: { component: 'CodeEditor' },
30
+ wysiwyg: { component: 'WysiwygEditor' },
31
+ markdown: { component: 'MarkdownEditor' },
32
+ // Directus-specific
33
+ icon: { component: 'IconPicker' },
34
+ user: { component: 'UserSelect' },
35
+ role: { component: 'RoleSelect' },
36
+ translation: { component: 'TranslationInput' },
37
+ // Presentation (ignored in forms)
38
+ presentation: { component: 'PresentationBlock' },
39
+ divider: { component: 'DividerBlock' }
40
+ };
41
+ export async function extendWidgetRegistryFromDirectus(client) {
42
+ const extensions = await client.request(readItems('directus_extensions'));
43
+ for (const ext of extensions) {
44
+ if (ext.type !== 'interface')
45
+ continue;
46
+ const name = ext.name;
47
+ if (!widgetRegistry[name]) {
48
+ widgetRegistry[name] = {
49
+ component: 'CustomInterfaceRenderer',
50
+ props: { interfaceName: name }
51
+ };
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,13 @@
1
+ export * from './client/createClient';
2
+ export { default as DirectusVueProvider } from './vue/DirectusProvider';
3
+ export * from './vue/useDirectus';
4
+ export { DirectusProvider as DirectusReactProvider } from './react/DirectusProvider';
5
+ export * from './react/useDirectus';
6
+ export * from './schema/types';
7
+ export * from './schema/introspect';
8
+ export * from './utils/collections';
9
+ export * from './utils/fields';
10
+ export * from './generators/form-engine';
11
+ export * from './generators/table-engine';
12
+ export * from './generators/validation-engine';
13
+ export * from './generators/widget-registry';
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ // src/index.ts
2
+ export * from './client/createClient';
3
+ // Vue bindings
4
+ export { default as DirectusVueProvider } from './vue/DirectusProvider';
5
+ export * from './vue/useDirectus';
6
+ // React bindings
7
+ export { DirectusProvider as DirectusReactProvider } from './react/DirectusProvider';
8
+ export * from './react/useDirectus';
9
+ // Schema + generators + utils
10
+ export * from './schema/types';
11
+ export * from './schema/introspect';
12
+ export * from './utils/collections';
13
+ export * from './utils/fields';
14
+ export * from './generators/form-engine';
15
+ export * from './generators/table-engine';
16
+ export * from './generators/validation-engine';
17
+ export * from './generators/widget-registry';
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import type { MeeoviDirectusClient } from '../client/createClient';
3
+ export declare const DirectusContext: React.Context<MeeoviDirectusClient<any> | null>;
4
+ export declare function DirectusProvider({ client, children }: {
5
+ client: MeeoviDirectusClient<any>;
6
+ children: React.ReactNode;
7
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext } from 'react';
3
+ export const DirectusContext = createContext(null);
4
+ export function DirectusProvider({ client, children }) {
5
+ return (_jsx(DirectusContext.Provider, { value: client, children: children }));
6
+ }
@@ -0,0 +1,2 @@
1
+ import type { MeeoviDirectusClient } from '../client/createClient';
2
+ export declare function useReactDirectus<Schema>(): MeeoviDirectusClient<Schema>;
@@ -0,0 +1,9 @@
1
+ import { useContext } from 'react';
2
+ import { DirectusContext } from './DirectusProvider';
3
+ export function useReactDirectus() {
4
+ const client = useContext(DirectusContext);
5
+ if (!client) {
6
+ throw new Error('Directus client not provided. Wrap your app in <DirectusProvider>.');
7
+ }
8
+ return client;
9
+ }
@@ -0,0 +1,5 @@
1
+ import type { DirectusSchema, DirectusField, DirectusCollection, DirectusRelation } from './types';
2
+ export declare function introspectCollections(client: any): Promise<DirectusCollection[]>;
3
+ export declare function introspectFields(client: any, collection: string): Promise<DirectusField[]>;
4
+ export declare function introspectRelations(client: any): Promise<DirectusRelation[]>;
5
+ export declare function introspectSchema(client: any): Promise<DirectusSchema>;
@@ -0,0 +1,30 @@
1
+ // schema/introspect.ts
2
+ import { readFieldsByCollection, readItems } from '@directus/sdk';
3
+ export async function introspectCollections(client) {
4
+ return await client.request(readItems('directus_collection'));
5
+ }
6
+ export async function introspectFields(client, collection) {
7
+ return await client.request(readFieldsByCollection(collection));
8
+ }
9
+ export async function introspectRelations(client) {
10
+ return await client.request(readItems('directus_relations'));
11
+ }
12
+ export async function introspectSchema(client) {
13
+ const [collections, relations] = await Promise.all([
14
+ introspectCollections(client),
15
+ introspectRelations(client),
16
+ ]);
17
+ const fields = [];
18
+ for (const col of collections) {
19
+ const colFields = await introspectFields(client, col.collection);
20
+ fields.push(...colFields);
21
+ }
22
+ return {
23
+ collections,
24
+ fields,
25
+ relations,
26
+ directus_collections: collections,
27
+ directus_fields: fields,
28
+ directus_relations: relations,
29
+ };
30
+ }
@@ -0,0 +1,47 @@
1
+ export interface DirectusField {
2
+ collection: string;
3
+ field: string;
4
+ type: string;
5
+ interface?: string;
6
+ options?: Record<string, any>;
7
+ required?: boolean;
8
+ readonly?: boolean;
9
+ hidden?: boolean;
10
+ sort?: number;
11
+ special?: string[];
12
+ validation?: Record<string, any>;
13
+ validation_message?: string;
14
+ }
15
+ export interface DirectusRelation {
16
+ collection: string;
17
+ field: string;
18
+ related_collection: string | null;
19
+ meta?: Record<string, any>;
20
+ }
21
+ export interface DirectusCollection {
22
+ collection: string;
23
+ meta?: Record<string, any>;
24
+ schema?: Record<string, any>;
25
+ }
26
+ export interface DirectusSchema {
27
+ directus_collections: DirectusCollection[];
28
+ directus_relations: DirectusRelation[];
29
+ directus_fields: DirectusField[];
30
+ collections: DirectusCollection[];
31
+ fields: DirectusField[];
32
+ relations: DirectusRelation[];
33
+ }
34
+ export interface GeneratedFieldSchema {
35
+ key: string;
36
+ type: string;
37
+ widget: string;
38
+ required: boolean;
39
+ readonly: boolean;
40
+ hidden: boolean;
41
+ options?: Record<string, any>;
42
+ validation?: Record<string, any>;
43
+ }
44
+ export interface GeneratedCollectionSchema {
45
+ collection: string;
46
+ fields: GeneratedFieldSchema[];
47
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { DirectusSchema, DirectusCollection, DirectusField } from '../schema/types';
2
+ export declare function getCollection(schema: DirectusSchema, name: string): DirectusCollection | undefined;
3
+ export declare function getCollectionFields(schema: DirectusSchema, name: string): DirectusField[];
4
+ export declare function listCollections(schema: DirectusSchema): string[];
5
+ export declare function isSingleton(schema: DirectusSchema, name: string): boolean;
@@ -0,0 +1,13 @@
1
+ export function getCollection(schema, name) {
2
+ return schema.collections.find(c => c.collection === name);
3
+ }
4
+ export function getCollectionFields(schema, name) {
5
+ return schema.fields.filter(f => f.collection === name);
6
+ }
7
+ export function listCollections(schema) {
8
+ return schema.collections.map(c => c.collection);
9
+ }
10
+ export function isSingleton(schema, name) {
11
+ const col = getCollection(schema, name);
12
+ return col?.meta?.singleton === true;
13
+ }
@@ -0,0 +1,4 @@
1
+ import type { DirectusField, GeneratedFieldSchema } from '../schema/types';
2
+ export declare function mapFieldToWidget(field: DirectusField): string;
3
+ export declare function generateFieldSchema(field: DirectusField): GeneratedFieldSchema;
4
+ export declare function generateFieldsSchema(fields: DirectusField[]): GeneratedFieldSchema[];
@@ -0,0 +1,40 @@
1
+ export function mapFieldToWidget(field) {
2
+ if (field.interface)
3
+ return field.interface;
4
+ switch (field.type) {
5
+ case 'string':
6
+ case 'text':
7
+ return 'text';
8
+ case 'integer':
9
+ case 'bigInteger':
10
+ case 'float':
11
+ case 'decimal':
12
+ return 'number';
13
+ case 'boolean':
14
+ return 'checkbox';
15
+ case 'date':
16
+ case 'dateTime':
17
+ return 'date';
18
+ case 'json':
19
+ return 'json';
20
+ default:
21
+ return 'text';
22
+ }
23
+ }
24
+ export function generateFieldSchema(field) {
25
+ return {
26
+ key: field.field,
27
+ type: field.type,
28
+ widget: mapFieldToWidget(field),
29
+ required: field.required ?? false,
30
+ readonly: field.readonly ?? false,
31
+ hidden: field.hidden ?? false,
32
+ options: field.options ?? {},
33
+ validation: field.validation ?? {},
34
+ };
35
+ }
36
+ export function generateFieldsSchema(fields) {
37
+ return fields
38
+ .sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0))
39
+ .map(generateFieldSchema);
40
+ }
@@ -0,0 +1,11 @@
1
+ export interface LivePreviewState {
2
+ token?: string;
3
+ }
4
+ export interface LivePreviewOptions {
5
+ query?: Record<string, string | undefined>;
6
+ initialState?: LivePreviewState;
7
+ }
8
+ export declare function createLivePreview(options: LivePreviewOptions): {
9
+ enabled: boolean;
10
+ state: LivePreviewState;
11
+ };
@@ -0,0 +1,11 @@
1
+ export function createLivePreview(options) {
2
+ const { query = {}, initialState = {} } = options;
3
+ const shouldEnable = Boolean(query.preview) && Boolean(query.token);
4
+ const state = {
5
+ token: query.token || initialState.token,
6
+ };
7
+ return {
8
+ enabled: shouldEnable,
9
+ state,
10
+ };
11
+ }