@quazardous/qdadm 2.16.0 → 2.16.1

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,195 @@
1
+ /**
2
+ * Unified Schema Types
3
+ *
4
+ * Core contracts that abstract differences between OpenAPI, Pydantic, and manual schema sources.
5
+ * These types provide a common format for entity and field definitions that can be used
6
+ * by connectors (schema sources) and generators (code output).
7
+ *
8
+ * @module gen/schema
9
+ */
10
+ /**
11
+ * Field Type Enumeration
12
+ *
13
+ * Unified field types that abstract source-specific types (OpenAPI string/integer,
14
+ * Pydantic str/int, etc.) into a common set.
15
+ */
16
+ export type UnifiedFieldType = 'text' | 'number' | 'boolean' | 'date' | 'datetime' | 'email' | 'url' | 'uuid' | 'array' | 'object';
17
+ /**
18
+ * Reference Definition
19
+ *
20
+ * Describes a relation to another entity for foreign key fields.
21
+ */
22
+ export interface UnifiedFieldReference {
23
+ /** Target entity name (e.g., 'users', 'categories') */
24
+ entity: string;
25
+ /** Field to display as label (e.g., 'name', 'title') */
26
+ labelField?: string;
27
+ }
28
+ /**
29
+ * Unified Field Schema
30
+ *
31
+ * Common field definition that abstracts OpenAPI property, Pydantic field, or manual definition.
32
+ * Connectors transform their source-specific formats into this common shape.
33
+ *
34
+ * @example
35
+ * // Simple text field
36
+ * const nameField: UnifiedFieldSchema = {
37
+ * name: 'name',
38
+ * type: 'text',
39
+ * label: 'Full Name',
40
+ * required: true
41
+ * }
42
+ *
43
+ * @example
44
+ * // Enum field with options
45
+ * const statusField: UnifiedFieldSchema = {
46
+ * name: 'status',
47
+ * type: 'text',
48
+ * label: 'Status',
49
+ * enum: ['draft', 'published', 'archived'],
50
+ * default: 'draft'
51
+ * }
52
+ *
53
+ * @example
54
+ * // Foreign key with reference
55
+ * const authorField: UnifiedFieldSchema = {
56
+ * name: 'author_id',
57
+ * type: 'number',
58
+ * label: 'Author',
59
+ * reference: {
60
+ * entity: 'users',
61
+ * labelField: 'username'
62
+ * }
63
+ * }
64
+ */
65
+ export interface UnifiedFieldSchema {
66
+ /** Field name (e.g., 'email', 'created_at') */
67
+ name: string;
68
+ /** Unified field type */
69
+ type: UnifiedFieldType;
70
+ /** Human-readable label (e.g., 'Email Address') */
71
+ label?: string;
72
+ /** Whether field is required (default: false) */
73
+ required?: boolean;
74
+ /** Whether field is read-only (default: false) */
75
+ readOnly?: boolean;
76
+ /** Whether field should be hidden in UI (default: false) */
77
+ hidden?: boolean;
78
+ /** Original format hint from source (e.g., 'date-time', 'uri', 'email') */
79
+ format?: string;
80
+ /** Allowed values for enumeration fields */
81
+ enum?: string[];
82
+ /** Default value for the field */
83
+ default?: unknown;
84
+ /** Relation to another entity */
85
+ reference?: UnifiedFieldReference;
86
+ /** Project-specific extensions */
87
+ extensions?: Record<string, unknown>;
88
+ /** Field display order */
89
+ order?: number;
90
+ /** Additional properties */
91
+ [key: string]: unknown;
92
+ }
93
+ /**
94
+ * Unified Entity Schema
95
+ *
96
+ * Common entity definition that abstracts OpenAPI path/schema, Pydantic model, or manual definition.
97
+ * This is the primary contract between schema sources (connectors) and consumers (generators, runtime).
98
+ *
99
+ * @example
100
+ * // Complete entity schema
101
+ * const usersSchema: UnifiedEntitySchema = {
102
+ * name: 'users',
103
+ * endpoint: '/api/users',
104
+ * label: 'User',
105
+ * labelPlural: 'Users',
106
+ * labelField: 'username',
107
+ * routePrefix: 'user',
108
+ * idField: 'id',
109
+ * readOnly: false,
110
+ * fields: {
111
+ * id: { name: 'id', type: 'number', readOnly: true },
112
+ * username: { name: 'username', type: 'text', required: true },
113
+ * email: { name: 'email', type: 'email', required: true },
114
+ * created_at: { name: 'created_at', type: 'datetime', readOnly: true }
115
+ * }
116
+ * }
117
+ */
118
+ export interface UnifiedEntitySchema {
119
+ /** Entity name, typically plural lowercase (e.g., 'users', 'blog_posts') */
120
+ name: string;
121
+ /** API endpoint path (e.g., '/users', '/api/v1/posts') */
122
+ endpoint: string;
123
+ /** Human-readable singular label (e.g., 'User', 'Blog Post') */
124
+ label?: string;
125
+ /** Human-readable plural label (e.g., 'Users', 'Blog Posts') */
126
+ labelPlural?: string;
127
+ /** Field used as display label (e.g., 'name', 'title') */
128
+ labelField?: string;
129
+ /** Route prefix for admin UI (e.g., 'user', 'blog-post') */
130
+ routePrefix?: string;
131
+ /** Primary key field name (default: 'id') */
132
+ idField?: string;
133
+ /** Whether entity is read-only (no create/update/delete) */
134
+ readOnly?: boolean;
135
+ /** Field definitions keyed by field name */
136
+ fields: Record<string, UnifiedFieldSchema>;
137
+ /** Project-specific extensions */
138
+ extensions?: Record<string, unknown>;
139
+ }
140
+ /**
141
+ * Valid field types for UnifiedFieldSchema
142
+ *
143
+ * Used for validation and documentation. Maps to common UI input types:
144
+ * - text: Single-line text input
145
+ * - number: Numeric input
146
+ * - boolean: Checkbox/toggle
147
+ * - date: Date picker (date only)
148
+ * - datetime: Date-time picker
149
+ * - email: Email input with validation
150
+ * - url: URL input with validation
151
+ * - uuid: UUID text input
152
+ * - array: Multi-value field (tags, list)
153
+ * - object: Nested object (JSON editor or subform)
154
+ */
155
+ export declare const UNIFIED_FIELD_TYPES: readonly ["text", "number", "boolean", "date", "datetime", "email", "url", "uuid", "array", "object"];
156
+ /**
157
+ * Check if a type is a valid UnifiedFieldType
158
+ *
159
+ * @param type - Type to validate
160
+ * @returns True if valid
161
+ *
162
+ * @example
163
+ * isValidFieldType('text') // true
164
+ * isValidFieldType('string') // false (OpenAPI type, not unified)
165
+ */
166
+ export declare function isValidFieldType(type: string): type is UnifiedFieldType;
167
+ /**
168
+ * Create a minimal field schema with defaults
169
+ *
170
+ * @param name - Field name
171
+ * @param type - Field type
172
+ * @param overrides - Additional field properties
173
+ * @returns Complete field schema
174
+ *
175
+ * @example
176
+ * const field = createFieldSchema('email', 'email', { required: true })
177
+ * // { name: 'email', type: 'email', required: true }
178
+ */
179
+ export declare function createFieldSchema(name: string, type: UnifiedFieldType, overrides?: Partial<UnifiedFieldSchema>): UnifiedFieldSchema;
180
+ /**
181
+ * Create a minimal entity schema with defaults
182
+ *
183
+ * @param name - Entity name
184
+ * @param endpoint - API endpoint
185
+ * @param fields - Field definitions
186
+ * @param overrides - Additional entity properties
187
+ * @returns Complete entity schema
188
+ *
189
+ * @example
190
+ * const schema = createEntitySchema('users', '/api/users', {
191
+ * id: createFieldSchema('id', 'number', { readOnly: true }),
192
+ * name: createFieldSchema('name', 'text', { required: true })
193
+ * })
194
+ */
195
+ export declare function createEntitySchema(name: string, endpoint: string, fields: Record<string, UnifiedFieldSchema>, overrides?: Partial<UnifiedEntitySchema>): UnifiedEntitySchema;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Unified Schema Types
3
+ *
4
+ * Core contracts that abstract differences between OpenAPI, Pydantic, and manual schema sources.
5
+ * These types provide a common format for entity and field definitions that can be used
6
+ * by connectors (schema sources) and generators (code output).
7
+ *
8
+ * @module gen/schema
9
+ */
10
+ /**
11
+ * Valid field types for UnifiedFieldSchema
12
+ *
13
+ * Used for validation and documentation. Maps to common UI input types:
14
+ * - text: Single-line text input
15
+ * - number: Numeric input
16
+ * - boolean: Checkbox/toggle
17
+ * - date: Date picker (date only)
18
+ * - datetime: Date-time picker
19
+ * - email: Email input with validation
20
+ * - url: URL input with validation
21
+ * - uuid: UUID text input
22
+ * - array: Multi-value field (tags, list)
23
+ * - object: Nested object (JSON editor or subform)
24
+ */
25
+ export const UNIFIED_FIELD_TYPES = [
26
+ 'text',
27
+ 'number',
28
+ 'boolean',
29
+ 'date',
30
+ 'datetime',
31
+ 'email',
32
+ 'url',
33
+ 'uuid',
34
+ 'array',
35
+ 'object',
36
+ ];
37
+ /**
38
+ * Check if a type is a valid UnifiedFieldType
39
+ *
40
+ * @param type - Type to validate
41
+ * @returns True if valid
42
+ *
43
+ * @example
44
+ * isValidFieldType('text') // true
45
+ * isValidFieldType('string') // false (OpenAPI type, not unified)
46
+ */
47
+ export function isValidFieldType(type) {
48
+ return UNIFIED_FIELD_TYPES.includes(type);
49
+ }
50
+ /**
51
+ * Create a minimal field schema with defaults
52
+ *
53
+ * @param name - Field name
54
+ * @param type - Field type
55
+ * @param overrides - Additional field properties
56
+ * @returns Complete field schema
57
+ *
58
+ * @example
59
+ * const field = createFieldSchema('email', 'email', { required: true })
60
+ * // { name: 'email', type: 'email', required: true }
61
+ */
62
+ export function createFieldSchema(name, type, overrides = {}) {
63
+ return {
64
+ name,
65
+ type,
66
+ ...overrides,
67
+ };
68
+ }
69
+ /**
70
+ * Create a minimal entity schema with defaults
71
+ *
72
+ * @param name - Entity name
73
+ * @param endpoint - API endpoint
74
+ * @param fields - Field definitions
75
+ * @param overrides - Additional entity properties
76
+ * @returns Complete entity schema
77
+ *
78
+ * @example
79
+ * const schema = createEntitySchema('users', '/api/users', {
80
+ * id: createFieldSchema('id', 'number', { readOnly: true }),
81
+ * name: createFieldSchema('name', 'text', { required: true })
82
+ * })
83
+ */
84
+ export function createEntitySchema(name, endpoint, fields, overrides = {}) {
85
+ return {
86
+ name,
87
+ endpoint,
88
+ fields,
89
+ ...overrides,
90
+ };
91
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Vite Plugin for qdadm EntityManager Generation
3
+ *
4
+ * Integrates generateManagers with Vite's build pipeline, triggering
5
+ * entity manager file generation during the buildStart hook.
6
+ *
7
+ * @experimental Undocumented build-time entry. Prefer the programmatic
8
+ * `generateManagers` entry (`@quazardous/qdadm/gen`), which is stable — see
9
+ * docs/API_STABILITY.md.
10
+ *
11
+ * @module gen/vite-plugin
12
+ */
13
+ import type { Plugin } from 'vite';
14
+ /**
15
+ * Plugin options for qdadmGen
16
+ */
17
+ export interface QdadmGenOptions {
18
+ /** Path to qdadm config file (default: 'qdadm.config.js') */
19
+ config?: string;
20
+ /** Override output directory for generated files */
21
+ output?: string;
22
+ }
23
+ /**
24
+ * Vite plugin for generating EntityManager files at build time
25
+ *
26
+ * Loads the qdadm configuration file and calls generateManagers during
27
+ * Vite's buildStart hook. Supports both ESM and CommonJS config files.
28
+ *
29
+ * @param options - Plugin options
30
+ * @returns Vite plugin object
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * // vite.config.js
35
+ * import { defineConfig } from 'vite'
36
+ * import { qdadmGen } from '@quazardous/qdadm/gen/vite-plugin'
37
+ *
38
+ * export default defineConfig({
39
+ * plugins: [
40
+ * qdadmGen({
41
+ * config: './qdadm.config.js',
42
+ * output: 'src/generated/managers/'
43
+ * })
44
+ * ]
45
+ * })
46
+ * ```
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * // qdadm.config.js
51
+ * export default {
52
+ * output: 'src/generated/managers/',
53
+ * entities: {
54
+ * users: {
55
+ * schema: { name: 'users', fields: { id: { type: 'integer' } } },
56
+ * endpoint: '/api/users',
57
+ * storageImport: '@quazardous/qdadm',
58
+ * storageClass: 'ApiStorage'
59
+ * }
60
+ * }
61
+ * }
62
+ * ```
63
+ */
64
+ export declare function qdadmGen(options?: QdadmGenOptions): Plugin;
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Vite Plugin for qdadm EntityManager Generation
3
+ *
4
+ * Integrates generateManagers with Vite's build pipeline, triggering
5
+ * entity manager file generation during the buildStart hook.
6
+ *
7
+ * @experimental Undocumented build-time entry. Prefer the programmatic
8
+ * `generateManagers` entry (`@quazardous/qdadm/gen`), which is stable — see
9
+ * docs/API_STABILITY.md.
10
+ *
11
+ * @module gen/vite-plugin
12
+ */
13
+ // Explicit .js extension: this module is compiled for Node (#1895), and Node
14
+ // ESM will not resolve an extensionless relative import. TypeScript maps the
15
+ // .js specifier back to the .ts source, so the bundler path is unaffected.
16
+ import { generateManagers } from './generateManagers.js';
17
+ import { pathToFileURL } from 'node:url';
18
+ import { resolve } from 'node:path';
19
+ /**
20
+ * Vite plugin for generating EntityManager files at build time
21
+ *
22
+ * Loads the qdadm configuration file and calls generateManagers during
23
+ * Vite's buildStart hook. Supports both ESM and CommonJS config files.
24
+ *
25
+ * @param options - Plugin options
26
+ * @returns Vite plugin object
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * // vite.config.js
31
+ * import { defineConfig } from 'vite'
32
+ * import { qdadmGen } from '@quazardous/qdadm/gen/vite-plugin'
33
+ *
34
+ * export default defineConfig({
35
+ * plugins: [
36
+ * qdadmGen({
37
+ * config: './qdadm.config.js',
38
+ * output: 'src/generated/managers/'
39
+ * })
40
+ * ]
41
+ * })
42
+ * ```
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * // qdadm.config.js
47
+ * export default {
48
+ * output: 'src/generated/managers/',
49
+ * entities: {
50
+ * users: {
51
+ * schema: { name: 'users', fields: { id: { type: 'integer' } } },
52
+ * endpoint: '/api/users',
53
+ * storageImport: '@quazardous/qdadm',
54
+ * storageClass: 'ApiStorage'
55
+ * }
56
+ * }
57
+ * }
58
+ * ```
59
+ */
60
+ export function qdadmGen(options = {}) {
61
+ const configPath = options.config || 'qdadm.config.js';
62
+ return {
63
+ name: 'qdadm-gen',
64
+ async buildStart() {
65
+ try {
66
+ // Resolve config path relative to cwd
67
+ const resolvedConfigPath = resolve(process.cwd(), configPath);
68
+ // Load config file dynamically
69
+ const configUrl = pathToFileURL(resolvedConfigPath).href;
70
+ const configModule = (await import(configUrl));
71
+ const loadedConfig = configModule.default || configModule;
72
+ // Validate loaded config
73
+ if (!loadedConfig || typeof loadedConfig !== 'object') {
74
+ throw new Error(`Invalid qdadm config at '${configPath}': must export an object`);
75
+ }
76
+ if (!loadedConfig.entities) {
77
+ throw new Error(`Invalid qdadm config at '${configPath}': missing 'entities' property`);
78
+ }
79
+ // Merge plugin options with config (plugin options take precedence)
80
+ const mergedConfig = {
81
+ ...loadedConfig,
82
+ ...(options.output && { output: options.output }),
83
+ };
84
+ // Generate managers
85
+ const generatedFiles = await generateManagers(mergedConfig);
86
+ // Log results
87
+ console.log(`[qdadm-gen] Generated ${generatedFiles.length} manager file(s)`);
88
+ for (const file of generatedFiles) {
89
+ console.log(` - ${file}`);
90
+ }
91
+ }
92
+ catch (error) {
93
+ // Wrap error with plugin context for clearer messages
94
+ const message = error instanceof Error ? error.message : String(error);
95
+ throw new Error(`[qdadm-gen] Failed to generate managers: ${message}`);
96
+ }
97
+ },
98
+ };
99
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * qdadm Vite dev plugin — exposes the running app's DebugBridge over HTTP.
3
+ *
4
+ * Endpoints (default prefix `/__qdadm`):
5
+ * GET /__qdadm/ — index of endpoints + cache stats
6
+ * GET /__qdadm/sessions — list of connected client sessions
7
+ * GET /__qdadm/describe.json — bridge.describe() (manifests)
8
+ * GET /__qdadm/snapshot.json — bridge.dump() (live state)
9
+ * POST /__qdadm/call — body {collector, action, args?}
10
+ *
11
+ * Session selection: every browser tab that loads the app gets a fresh
12
+ * session id (uuid in the injected client). All endpoints accept a
13
+ * `?session=<id|latest>` query param. Default is `latest` (the most recently
14
+ * active session).
15
+ *
16
+ * Wire-up: the plugin injects a small ESM script via `transformIndexHtml`.
17
+ * That inline script lives in Vite's HMR pipeline (so `import.meta.hot`
18
+ * works), polls for `window.__qdadm.debug.bridge`, then pushes describe +
19
+ * snapshot on every reactive tick. The plugin caches per-session payloads
20
+ * in memory; GETs are served from cache (no round-trip needed).
21
+ *
22
+ * `call` is always request-response — it mutates state in the live page.
23
+ *
24
+ * Cache responses include `X-Qdadm-Stale-Ms`, `X-Qdadm-Source: cache|live`,
25
+ * and `X-Qdadm-Session: <id>` headers.
26
+ */
27
+ import type { Plugin } from 'vite';
28
+ /** Typed page-side queries (#1398) — served by the injected client. */
29
+ export type DebugQueryType = 'describe' | 'dump' | 'call' | 'sessionInfo' | 'routes' | 'entityState' | 'entityCall' | 'storageDump' | 'bootlog' | 'recentSignals';
30
+ /** Broker surface exposed to sibling plugins via `plugin.api` (#1398). */
31
+ export interface QdadmDebugPluginApi {
32
+ /** Send a typed query to the page and await its reply. */
33
+ ask: (type: DebugQueryType, payload?: unknown, sessionId?: string) => Promise<unknown>;
34
+ /** Resolve a session param ('latest' or id) to a live session, if any. */
35
+ pickSession: (sessionParam: string | null) => {
36
+ id: string;
37
+ lastSeenAt: number;
38
+ meta: Record<string, unknown>;
39
+ } | null;
40
+ listSessions: () => Array<{
41
+ id: string;
42
+ firstSeenAt: number;
43
+ lastSeenAt: number;
44
+ ageMs: number;
45
+ hasDescribe: boolean;
46
+ hasSnapshot: boolean;
47
+ meta: Record<string, unknown>;
48
+ }>;
49
+ prefix: string;
50
+ }
51
+ export interface QdadmDebugPluginOptions {
52
+ /** URL prefix (default '/__qdadm') */
53
+ prefix?: string;
54
+ /** Request timeout ms for live fallback (default 3000) */
55
+ timeoutMs?: number;
56
+ /** Drop sessions inactive for this many ms (default 10 min) */
57
+ sessionTtlMs?: number;
58
+ }
59
+ export declare function qdadmDebugPlugin(options?: QdadmDebugPluginOptions): Plugin;
60
+ export default qdadmDebugPlugin;