@stonecrop/nuxt 0.10.1 → 0.10.3
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.
- package/README.md +74 -9
- package/dist/module.json +1 -1
- package/dist/module.mjs +10 -11
- package/dist/runtime/app/composables/useStonecropRegistry.d.ts +141 -0
- package/dist/runtime/app/composables/useStonecropRegistry.js +98 -0
- package/package.json +9 -9
- /package/dist/runtime/{layouts → app/layouts}/StonecropHome.d.vue.ts +0 -0
- /package/dist/runtime/{layouts → app/layouts}/StonecropHome.vue +0 -0
- /package/dist/runtime/{layouts → app/layouts}/StonecropHome.vue.d.ts +0 -0
- /package/dist/runtime/{pages → app/pages}/DocBuilderDetail.d.vue.ts +0 -0
- /package/dist/runtime/{pages → app/pages}/DocBuilderDetail.vue +0 -0
- /package/dist/runtime/{pages → app/pages}/DocBuilderDetail.vue.d.ts +0 -0
- /package/dist/runtime/{pages → app/pages}/DocBuilderIndex.d.vue.ts +0 -0
- /package/dist/runtime/{pages → app/pages}/DocBuilderIndex.vue +0 -0
- /package/dist/runtime/{pages → app/pages}/DocBuilderIndex.vue.d.ts +0 -0
package/README.md
CHANGED
|
@@ -7,10 +7,10 @@ The official Nuxt module for Stonecrop - a schema-driven UI framework with event
|
|
|
7
7
|
|
|
8
8
|
## What is Stonecrop?
|
|
9
9
|
|
|
10
|
-
Stonecrop is a **schema-driven UI framework** that generates forms, tables, and workflows from JSON schemas.
|
|
10
|
+
Stonecrop is a **schema-driven UI framework** that generates forms, tables, and workflows from JSON schemas. You define your data structure once and Stonecrop handles UI generation, state management, and validation.
|
|
11
11
|
|
|
12
12
|
**Key Benefits:**
|
|
13
|
-
- **Schema-Driven**: Define data models in JSON
|
|
13
|
+
- **Schema-Driven**: Define data models in JSON; form and table rendering follows automatically
|
|
14
14
|
- **HST State Management**: Hierarchical State Tree for complex, nested application state
|
|
15
15
|
- **FSM Workflows**: XState-powered finite state machines for predictable business logic
|
|
16
16
|
- **Nuxt Native**: First-class integration with Nuxt 4's architecture
|
|
@@ -100,6 +100,27 @@ Create a JSON schema in `/doctypes/task.json`:
|
|
|
100
100
|
|
|
101
101
|
The module picks up this file and, if `pageComponent` is configured, registers a route at the doctype's `slug` value (or `task` if no slug is set), passing the parsed schema into `route.meta`.
|
|
102
102
|
|
|
103
|
+
### Wire Up Your Data Client
|
|
104
|
+
|
|
105
|
+
After installing the module, add a client-side plugin to connect your data transport. The `useStonecropRegistry()` composable gives you a stable API for this — no need to reach into `globalProperties` directly:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// app/plugins/stonecrop.client.ts
|
|
109
|
+
import { StonecropClient } from '@stonecrop/graphql-client'
|
|
110
|
+
|
|
111
|
+
export default defineNuxtPlugin(() => {
|
|
112
|
+
const client = new StonecropClient({ endpoint: '/graphql' })
|
|
113
|
+
const { setMeta, setFetchRecord, setFetchRecords } = useStonecropRegistry()
|
|
114
|
+
|
|
115
|
+
// Map the route path/segments to a doctype name, then delegate to your client
|
|
116
|
+
setMeta(({ segments }) => client.getMeta({ doctype: segments[0] }))
|
|
117
|
+
setFetchRecord((doctype, id) => client.getRecord(doctype, id))
|
|
118
|
+
setFetchRecords((doctype) => client.getRecords(doctype))
|
|
119
|
+
})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
This wires `useStonecrop()`'s automatic record loading to your GraphQL (or any other) backend. Without this step, `useStonecrop({ doctype, recordId })` falls back to a REST fetch stub that may not exist in your app.
|
|
123
|
+
|
|
103
124
|
### Use the Stonecrop Composable
|
|
104
125
|
|
|
105
126
|
In your page or component:
|
|
@@ -108,19 +129,20 @@ In your page or component:
|
|
|
108
129
|
<script setup lang="ts">
|
|
109
130
|
import taskDoctype from '~/doctypes/task.json'
|
|
110
131
|
|
|
111
|
-
// HST-reactive form setup
|
|
132
|
+
// HST-reactive form setup — pass doctype + recordId for full integration
|
|
112
133
|
const { stonecrop, provideHSTPath, handleHSTChange, formData } = useStonecrop({
|
|
113
134
|
doctype: taskDoctype,
|
|
114
135
|
recordId: 'task-123' // or undefined for new records
|
|
115
136
|
})
|
|
116
137
|
|
|
117
|
-
// Access the hierarchical state tree
|
|
118
|
-
const
|
|
138
|
+
// Access the hierarchical state tree directly
|
|
139
|
+
const store = stonecrop.value?.getStore()
|
|
140
|
+
const taskTitle = store?.get('task.task-123.title')
|
|
119
141
|
</script>
|
|
120
142
|
|
|
121
143
|
<template>
|
|
122
144
|
<AForm
|
|
123
|
-
:schema="
|
|
145
|
+
:schema="taskDoctype.fields"
|
|
124
146
|
:data="formData"
|
|
125
147
|
@update="handleHSTChange"
|
|
126
148
|
/>
|
|
@@ -276,10 +298,10 @@ export default defineNuxtConfig({
|
|
|
276
298
|
### Plugin Registration
|
|
277
299
|
|
|
278
300
|
The module auto-registers:
|
|
279
|
-
- `
|
|
280
|
-
- `
|
|
301
|
+
- `useStonecropRegistry()` - Composable for wiring data clients and `getMeta` after plugin install
|
|
302
|
+
- `useStonecrop()` - Main composable for HST integration (from `@stonecrop/stonecrop`)
|
|
281
303
|
- Pinia store configuration
|
|
282
|
-
-
|
|
304
|
+
- AForm and ATable component registration (from `@stonecrop/aform`)
|
|
283
305
|
|
|
284
306
|
## Why Schema-Driven?
|
|
285
307
|
|
|
@@ -299,6 +321,49 @@ The module auto-registers:
|
|
|
299
321
|
- **Self-Documenting**: Schemas serve as data model documentation
|
|
300
322
|
- **Easy Updates**: Change schema, UI updates automatically
|
|
301
323
|
|
|
324
|
+
## `useStonecropRegistry()` — Configuring the Framework After Install
|
|
325
|
+
|
|
326
|
+
The `@stonecrop/nuxt` runtime plugin installs `StonecropPlugin` with a router but no data transport, because data clients (GraphQL, tRPC, REST) are application-defined and cannot be serialised through `nuxt.config.ts` module options.
|
|
327
|
+
|
|
328
|
+
`useStonecropRegistry()` is the documented extension point for wiring your data transport after plugin install. Call it in a client-side plugin:
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
// app/plugins/stonecrop.client.ts
|
|
332
|
+
export default defineNuxtPlugin(() => {
|
|
333
|
+
const { setMeta, setFetchRecord, setFetchRecords } = useStonecropRegistry()
|
|
334
|
+
|
|
335
|
+
// setMeta — resolves doctype metadata from the current route
|
|
336
|
+
// The context has { path, segments } from the router; adapt to your API.
|
|
337
|
+
setMeta(async ({ segments }) => {
|
|
338
|
+
// Example: segments[0] is the doctype slug, e.g. "task" from /task/123
|
|
339
|
+
const doctype = segments[0]
|
|
340
|
+
const meta = await $fetch(`/api/doctypes/${doctype}`)
|
|
341
|
+
return meta
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
// setFetchRecord — replaces the default REST stub in useStonecrop({ recordId })
|
|
345
|
+
setFetchRecord(async (doctype, id) => {
|
|
346
|
+
return await $fetch(`/api/${doctype.slug}/${id}`)
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
// setFetchRecords — replaces the default REST stub for list loading
|
|
350
|
+
setFetchRecords(async (doctype) => {
|
|
351
|
+
return await $fetch(`/api/${doctype.slug}`)
|
|
352
|
+
})
|
|
353
|
+
})
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**Why a composable and not module options?** Nuxt module options are serialised at build time — functions cannot be passed through `nuxt.config.ts`. `useStonecropRegistry()` is the composable equivalent of `usePinia()` or `useNuxtApp()`: a stable, typed API for configuring the framework singleton after it has been installed.
|
|
357
|
+
|
|
358
|
+
### API
|
|
359
|
+
|
|
360
|
+
| Method | Signature | Description |
|
|
361
|
+
|--------|-----------|-------------|
|
|
362
|
+
| `setMeta` | `(fn: (ctx) => DoctypeMeta \| Promise<DoctypeMeta>) => void` | Sets the `getMeta` function on the Registry. Called by `useStonecrop()` to lazy-load doctype metadata for the current route. `ctx` = `{ path, segments }`. |
|
|
363
|
+
| `setFetchRecord` | `(fn: (doctype, id) => Promise<Record \| null>) => void` | Replaces the default REST fetch stub in `Stonecrop.getRecord()`. Enables GraphQL-backed or any other custom transport. |
|
|
364
|
+
| `setFetchRecords` | `(fn: (doctype) => Promise<Record[]>) => void` | Replaces the default REST fetch stub in `Stonecrop.getRecords()`. |
|
|
365
|
+
| `registry` | `Registry` | The raw Registry instance, for advanced use cases. |
|
|
366
|
+
|
|
302
367
|
## Advanced Features
|
|
303
368
|
|
|
304
369
|
### Hierarchical State Tree (HST)
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, realpathSync } from 'node:fs';
|
|
2
2
|
import { readdir, readFile } from 'node:fs/promises';
|
|
3
3
|
import { dirname, extname } from 'node:path';
|
|
4
|
-
import { createResolver, defineNuxtModule, useLogger, addVitePlugin, addLayout, extendPages, addServerHandler, addPlugin } from '@nuxt/kit';
|
|
4
|
+
import { createResolver, defineNuxtModule, useLogger, addVitePlugin, addLayout, extendPages, addServerHandler, addPlugin, addImportsDir } from '@nuxt/kit';
|
|
5
5
|
|
|
6
6
|
function createSymlinkedPackagesPlugin(options) {
|
|
7
7
|
const { rootDir, packages, logger } = options;
|
|
@@ -96,8 +96,7 @@ const module$1 = defineNuxtModule({
|
|
|
96
96
|
});
|
|
97
97
|
addVitePlugin(symlinkedPackagesPlugin);
|
|
98
98
|
}
|
|
99
|
-
const
|
|
100
|
-
const homepage = resolve(layoutsDir, "StonecropHome.vue");
|
|
99
|
+
const homepage = resolve("runtime/app/layouts/StonecropHome.vue");
|
|
101
100
|
addLayout(homepage, "home");
|
|
102
101
|
const appDir = nuxt.options.srcDir;
|
|
103
102
|
const doctypesDir = resolve(appDir, options.doctypesDir ?? "doctypes");
|
|
@@ -186,9 +185,8 @@ const module$1 = defineNuxtModule({
|
|
|
186
185
|
}
|
|
187
186
|
if (options.docbuilder) {
|
|
188
187
|
logger.log("DocBuilder enabled, adding routes and handlers");
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
const docBuilderDetail = resolve(pagesDir, "DocBuilderDetail.vue");
|
|
188
|
+
const docBuilderIndex = resolve("runtime/app/pages/DocBuilderIndex.vue");
|
|
189
|
+
const docBuilderDetail = resolve("runtime/app/pages/DocBuilderDetail.vue");
|
|
192
190
|
extendPages((pages) => {
|
|
193
191
|
pages.push({
|
|
194
192
|
name: "docbuilder-index",
|
|
@@ -204,24 +202,24 @@ const module$1 = defineNuxtModule({
|
|
|
204
202
|
});
|
|
205
203
|
const handlersDir = resolve("runtime/server/api/docbuilder");
|
|
206
204
|
addServerHandler({
|
|
207
|
-
route: "/api/docbuilder/doctypes",
|
|
205
|
+
route: "/api/_stonecrop/docbuilder/doctypes",
|
|
208
206
|
handler: resolve(handlersDir, "doctypes.get")
|
|
209
207
|
});
|
|
210
208
|
addServerHandler({
|
|
211
|
-
route: "/api/docbuilder/:doctype",
|
|
209
|
+
route: "/api/_stonecrop/docbuilder/:doctype",
|
|
212
210
|
handler: resolve(handlersDir, "[doctype].get")
|
|
213
211
|
});
|
|
214
212
|
addServerHandler({
|
|
215
|
-
route: "/api/docbuilder/validate",
|
|
213
|
+
route: "/api/_stonecrop/docbuilder/validate",
|
|
216
214
|
method: "post",
|
|
217
215
|
handler: resolve(handlersDir, "validate.post")
|
|
218
216
|
});
|
|
219
217
|
addServerHandler({
|
|
220
|
-
route: "/api/docbuilder/save",
|
|
218
|
+
route: "/api/_stonecrop/docbuilder/save",
|
|
221
219
|
method: "post",
|
|
222
220
|
handler: resolve(handlersDir, "save.post")
|
|
223
221
|
});
|
|
224
|
-
logger.log("Added DocBuilder API handlers");
|
|
222
|
+
logger.log("Added DocBuilder API handlers at /api/_stonecrop/docbuilder/");
|
|
225
223
|
}
|
|
226
224
|
const pluginPath = resolve("./runtime/plugin");
|
|
227
225
|
try {
|
|
@@ -230,6 +228,7 @@ const module$1 = defineNuxtModule({
|
|
|
230
228
|
logger.error("Error adding plugin:", pluginError);
|
|
231
229
|
throw new Error(`[@stonecrop/nuxt] Failed to add plugin at ${pluginPath}`);
|
|
232
230
|
}
|
|
231
|
+
addImportsDir(resolve("runtime/app/composables"));
|
|
233
232
|
}
|
|
234
233
|
});
|
|
235
234
|
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { DataClient, DoctypeMeta } from '@stonecrop/schema';
|
|
2
|
+
import type { RouteContext } from '@stonecrop/stonecrop';
|
|
3
|
+
/**
|
|
4
|
+
* Provides a stable, documented API for accessing and configuring the Stonecrop
|
|
5
|
+
* Registry instance after the `@stonecrop/nuxt` plugin has installed it.
|
|
6
|
+
*
|
|
7
|
+
* ## Why This Composable Exists
|
|
8
|
+
*
|
|
9
|
+
* Stonecrop's architecture separates concerns across packages:
|
|
10
|
+
* - **@stonecrop/schema**: Defines doctype schemas, `DoctypeContext`, and `DataClient` interface
|
|
11
|
+
* - **@stonecrop/stonecrop**: Core framework with `RouteContext` (path + segments) for routing
|
|
12
|
+
* - **@stonecrop/graphql-client**: Reference `DataClient` implementation using GraphQL
|
|
13
|
+
* - **@stonecrop/nuxt**: Nuxt integration that bootstraps the Registry and Stonecrop instances
|
|
14
|
+
*
|
|
15
|
+
* This composable bridges Nuxt's plugin lifecycle with Stonecrop's registry, allowing
|
|
16
|
+
* applications to inject their data client and configure metadata fetching after the
|
|
17
|
+
* framework is mounted.
|
|
18
|
+
*
|
|
19
|
+
* ## RouteContext vs DoctypeContext
|
|
20
|
+
*
|
|
21
|
+
* - **RouteContext** (`{ path, segments }`): Raw URL routing context. Used by the router
|
|
22
|
+
* layer to identify "where we are" in the application (e.g., `/plan/123` → segments `['plan', '123']`).
|
|
23
|
+
*
|
|
24
|
+
* - **DoctypeContext** (`{ doctype, recordId? }`): Semantic doctype context. Used by the
|
|
25
|
+
* data layer to identify "what we're working with" (e.g., `{ doctype: 'Plan', recordId: '123' }`).
|
|
26
|
+
*
|
|
27
|
+
* Your `setMeta` implementation bridges these: extract doctype/recordId from the route
|
|
28
|
+
* segments and pass `DoctypeContext` to your data client.
|
|
29
|
+
*
|
|
30
|
+
* ## Data Flow
|
|
31
|
+
*
|
|
32
|
+
* ```
|
|
33
|
+
* URL Route (/plan/123)
|
|
34
|
+
* ↓
|
|
35
|
+
* RouteContext ({ path: '/plan/123', segments: ['plan', '123'] })
|
|
36
|
+
* ↓
|
|
37
|
+
* getMeta (your implementation)
|
|
38
|
+
* ↓
|
|
39
|
+
* DoctypeContext ({ doctype: 'Plan', recordId: '123' })
|
|
40
|
+
* ↓
|
|
41
|
+
* DataClient.getMeta() → DoctypeMeta
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* // app/plugins/stonecrop.client.ts
|
|
47
|
+
* import { StonecropClient } from '@stonecrop/graphql-client'
|
|
48
|
+
*
|
|
49
|
+
* export default defineNuxtPlugin(() => {
|
|
50
|
+
* const client = new StonecropClient({ endpoint: '/graphql' })
|
|
51
|
+
* const { setClient, setMeta } = useStonecropRegistry()
|
|
52
|
+
*
|
|
53
|
+
* // Set the data client for record fetching
|
|
54
|
+
* setClient(client)
|
|
55
|
+
*
|
|
56
|
+
* // Bridge RouteContext → DoctypeContext for metadata fetching
|
|
57
|
+
* setMeta(({ segments }) => {
|
|
58
|
+
* const doctype = segments[0] // e.g. "plan" → doctype "Plan"
|
|
59
|
+
* return client.getMeta({ doctype }) // client expects DoctypeContext
|
|
60
|
+
* })
|
|
61
|
+
* })
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @public
|
|
65
|
+
*/
|
|
66
|
+
export declare function useStonecropRegistry(): {
|
|
67
|
+
/**
|
|
68
|
+
* The raw Registry instance, for advanced use cases.
|
|
69
|
+
* Prefer the typed setter methods below for normal configuration.
|
|
70
|
+
*/
|
|
71
|
+
registry: {
|
|
72
|
+
getMeta?: (routeContext: RouteContext) => DoctypeMeta | Promise<DoctypeMeta>;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Set the data client on the Stonecrop instance.
|
|
76
|
+
* Required before fetching records or dispatching actions.
|
|
77
|
+
*
|
|
78
|
+
* @param client - DataClient implementation (e.g., StonecropClient from \@stonecrop/graphql-client)
|
|
79
|
+
*
|
|
80
|
+
* @throws Error if Stonecrop instance is not available
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* const client = new StonecropClient({ endpoint: '/graphql' })
|
|
85
|
+
* setClient(client)
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
setClient(client: DataClient): void;
|
|
89
|
+
/**
|
|
90
|
+
* Get the currently configured data client.
|
|
91
|
+
* @returns The DataClient instance or undefined if not set
|
|
92
|
+
*/
|
|
93
|
+
getClient(): DataClient | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* Dispatch an action to the server via the configured data client.
|
|
96
|
+
* All state changes flow through this single mutation endpoint.
|
|
97
|
+
*
|
|
98
|
+
* @param doctype - Doctype reference (name and optional slug)
|
|
99
|
+
* @param action - Action name to execute (e.g., 'SUBMIT', 'APPROVE', 'save')
|
|
100
|
+
* @param args - Action arguments (typically record ID and/or form data)
|
|
101
|
+
* @returns Action result with success status, response data, and any error
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* // Save a record
|
|
106
|
+
* const result = await dispatchAction(doctype, 'save', [{ id: recordId, data: formData }])
|
|
107
|
+
*
|
|
108
|
+
* // Submit for approval
|
|
109
|
+
* const result = await dispatchAction(doctype, 'SUBMIT', [recordId])
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
dispatchAction(doctype: {
|
|
113
|
+
name: string;
|
|
114
|
+
slug?: string;
|
|
115
|
+
}, action: string, args?: unknown[]): Promise<{
|
|
116
|
+
success: boolean;
|
|
117
|
+
data: unknown;
|
|
118
|
+
error: string | null;
|
|
119
|
+
}>;
|
|
120
|
+
/**
|
|
121
|
+
* Set the `getMeta` function on the Registry.
|
|
122
|
+
* Called by `useStonecrop()` to lazy-load doctype metadata for the current route.
|
|
123
|
+
*
|
|
124
|
+
* You must bridge `RouteContext` → `DoctypeContext`:
|
|
125
|
+
* - Extract doctype name from `segments` (e.g., `segments[0]`)
|
|
126
|
+
* - Extract record ID from `segments` if present (e.g., `segments[1]`)
|
|
127
|
+
* - Pass `DoctypeContext` to your data client
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* // Map route to doctype
|
|
132
|
+
* setMeta(({ segments }) => {
|
|
133
|
+
* const doctype = segments[0] // /plan/123 → 'plan'
|
|
134
|
+
* return client.getMeta({ doctype }) // client expects DoctypeContext
|
|
135
|
+
* })
|
|
136
|
+
* ```
|
|
137
|
+
*
|
|
138
|
+
* @param fn - Function that receives RouteContext and returns DoctypeMeta.
|
|
139
|
+
*/
|
|
140
|
+
setMeta(fn: (routeContext: RouteContext) => DoctypeMeta | Promise<DoctypeMeta>): void;
|
|
141
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { useNuxtApp } from "nuxt/app";
|
|
2
|
+
export function useStonecropRegistry() {
|
|
3
|
+
const nuxtApp = useNuxtApp();
|
|
4
|
+
const registry = nuxtApp.$registry;
|
|
5
|
+
if (!registry) {
|
|
6
|
+
throw new Error(
|
|
7
|
+
"[useStonecropRegistry] The Stonecrop Registry is not available. Ensure @stonecrop/nuxt is installed and the plugin has run before calling this composable."
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
const stonecrop = nuxtApp.$stonecrop;
|
|
11
|
+
return {
|
|
12
|
+
/**
|
|
13
|
+
* The raw Registry instance, for advanced use cases.
|
|
14
|
+
* Prefer the typed setter methods below for normal configuration.
|
|
15
|
+
*/
|
|
16
|
+
registry,
|
|
17
|
+
/**
|
|
18
|
+
* Set the data client on the Stonecrop instance.
|
|
19
|
+
* Required before fetching records or dispatching actions.
|
|
20
|
+
*
|
|
21
|
+
* @param client - DataClient implementation (e.g., StonecropClient from \@stonecrop/graphql-client)
|
|
22
|
+
*
|
|
23
|
+
* @throws Error if Stonecrop instance is not available
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* const client = new StonecropClient({ endpoint: '/graphql' })
|
|
28
|
+
* setClient(client)
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
setClient(client) {
|
|
32
|
+
if (!stonecrop) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
"[useStonecropRegistry] Stonecrop instance is not available. Ensure @stonecrop/nuxt is installed and the plugin has run."
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
stonecrop.setClient(client);
|
|
38
|
+
},
|
|
39
|
+
/**
|
|
40
|
+
* Get the currently configured data client.
|
|
41
|
+
* @returns The DataClient instance or undefined if not set
|
|
42
|
+
*/
|
|
43
|
+
getClient() {
|
|
44
|
+
return stonecrop?.getClient();
|
|
45
|
+
},
|
|
46
|
+
/**
|
|
47
|
+
* Dispatch an action to the server via the configured data client.
|
|
48
|
+
* All state changes flow through this single mutation endpoint.
|
|
49
|
+
*
|
|
50
|
+
* @param doctype - Doctype reference (name and optional slug)
|
|
51
|
+
* @param action - Action name to execute (e.g., 'SUBMIT', 'APPROVE', 'save')
|
|
52
|
+
* @param args - Action arguments (typically record ID and/or form data)
|
|
53
|
+
* @returns Action result with success status, response data, and any error
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* // Save a record
|
|
58
|
+
* const result = await dispatchAction(doctype, 'save', [{ id: recordId, data: formData }])
|
|
59
|
+
*
|
|
60
|
+
* // Submit for approval
|
|
61
|
+
* const result = await dispatchAction(doctype, 'SUBMIT', [recordId])
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
dispatchAction(doctype, action, args) {
|
|
65
|
+
if (!stonecrop) {
|
|
66
|
+
return Promise.reject(
|
|
67
|
+
new Error(
|
|
68
|
+
"[useStonecropRegistry] Stonecrop instance is not available. Ensure @stonecrop/nuxt is installed and the plugin has run."
|
|
69
|
+
)
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
return stonecrop.dispatchAction(doctype, action, args);
|
|
73
|
+
},
|
|
74
|
+
/**
|
|
75
|
+
* Set the `getMeta` function on the Registry.
|
|
76
|
+
* Called by `useStonecrop()` to lazy-load doctype metadata for the current route.
|
|
77
|
+
*
|
|
78
|
+
* You must bridge `RouteContext` → `DoctypeContext`:
|
|
79
|
+
* - Extract doctype name from `segments` (e.g., `segments[0]`)
|
|
80
|
+
* - Extract record ID from `segments` if present (e.g., `segments[1]`)
|
|
81
|
+
* - Pass `DoctypeContext` to your data client
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* // Map route to doctype
|
|
86
|
+
* setMeta(({ segments }) => {
|
|
87
|
+
* const doctype = segments[0] // /plan/123 → 'plan'
|
|
88
|
+
* return client.getMeta({ doctype }) // client expects DoctypeContext
|
|
89
|
+
* })
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
* @param fn - Function that receives RouteContext and returns DoctypeMeta.
|
|
93
|
+
*/
|
|
94
|
+
setMeta(fn) {
|
|
95
|
+
registry.getMeta = fn;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stonecrop/nuxt",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3",
|
|
4
4
|
"description": "Nuxt module for Stonecrop",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -44,14 +44,14 @@
|
|
|
44
44
|
"jiti": "^2.4.2",
|
|
45
45
|
"pathe": "^2.0.3",
|
|
46
46
|
"prompts": "^2.4.2",
|
|
47
|
-
"@stonecrop/aform": "0.10.
|
|
48
|
-
"@stonecrop/atable": "0.10.
|
|
49
|
-
"@stonecrop/casl-middleware": "0.10.
|
|
50
|
-
"@stonecrop/node-editor": "0.10.
|
|
51
|
-
"@stonecrop/graphql-middleware": "0.10.
|
|
52
|
-
"@stonecrop/nuxt-grafserv": "0.10.
|
|
53
|
-
"@stonecrop/schema": "0.10.
|
|
54
|
-
"@stonecrop/stonecrop": "0.10.
|
|
47
|
+
"@stonecrop/aform": "0.10.3",
|
|
48
|
+
"@stonecrop/atable": "0.10.3",
|
|
49
|
+
"@stonecrop/casl-middleware": "0.10.3",
|
|
50
|
+
"@stonecrop/node-editor": "0.10.3",
|
|
51
|
+
"@stonecrop/graphql-middleware": "0.10.3",
|
|
52
|
+
"@stonecrop/nuxt-grafserv": "0.10.3",
|
|
53
|
+
"@stonecrop/schema": "0.10.3",
|
|
54
|
+
"@stonecrop/stonecrop": "0.10.3"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@eslint/js": "^9.39.2",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|