@stonecrop/graphql-client 0.13.14 → 0.15.0

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/src/client.ts CHANGED
@@ -7,6 +7,7 @@ import type {
7
7
  GetRecordsOptions,
8
8
  } from '@stonecrop/schema'
9
9
  import type { GetRecordResult } from './types'
10
+ import { GET_META_QUERY, GET_ALL_META_QUERY, RUN_ACTION_MUTATION } from './queries'
10
11
 
11
12
  export type { DoctypeContext, DoctypeRef }
12
13
  export type { GetRecordResult }
@@ -88,48 +89,9 @@ export class StonecropClient implements DataClient {
88
89
  const cached = this.metaCache.get(context.doctype)
89
90
  if (cached) return cached
90
91
 
91
- const result = await this.query<{ stonecropMeta: DoctypeMeta | null }>(
92
- `
93
- query GetMeta($doctype: String!) {
94
- stonecropMeta(doctype: $doctype) {
95
- name
96
- slug
97
- fields {
98
- fieldname
99
- fieldtype
100
- component
101
- label
102
- width
103
- align
104
- required
105
- readOnly
106
- edit
107
- hidden
108
- default
109
- options
110
- mask
111
- precision
112
- scale
113
- mode
114
- validation
115
- }
116
- workflow {
117
- states
118
- actions {
119
- label
120
- handler
121
- requiredFields
122
- allowedStates
123
- confirm
124
- args
125
- }
126
- }
127
- inherits
128
- }
129
- }
130
- `,
131
- { doctype: context.doctype }
132
- )
92
+ const result = await this.query<{ stonecropMeta: DoctypeMeta | null }>(GET_META_QUERY, {
93
+ doctype: context.doctype,
94
+ })
133
95
 
134
96
  if (result.stonecropMeta) {
135
97
  this.metaCache.set(context.doctype, result.stonecropMeta)
@@ -142,47 +104,7 @@ export class StonecropClient implements DataClient {
142
104
  * Get all doctype metadata
143
105
  */
144
106
  async getAllMeta(): Promise<DoctypeMeta[]> {
145
- const result = await this.query<{ stonecropAllMeta: DoctypeMeta[] }>(
146
- `
147
- query GetAllMeta {
148
- stonecropAllMeta {
149
- name
150
- slug
151
- fields {
152
- fieldname
153
- fieldtype
154
- component
155
- label
156
- width
157
- align
158
- required
159
- readOnly
160
- edit
161
- hidden
162
- default
163
- options
164
- mask
165
- precision
166
- scale
167
- mode
168
- validation
169
- }
170
- workflow {
171
- states
172
- actions {
173
- label
174
- handler
175
- requiredFields
176
- allowedStates
177
- confirm
178
- args
179
- }
180
- }
181
- inherits
182
- }
183
- }
184
- `
185
- )
107
+ const result = await this.query<{ stonecropAllMeta: DoctypeMeta[] }>(GET_ALL_META_QUERY)
186
108
 
187
109
  for (const meta of result.stonecropAllMeta) {
188
110
  this.metaCache.set(meta.name, meta)
@@ -284,22 +206,11 @@ export class StonecropClient implements DataClient {
284
206
  ): Promise<{ success: boolean; data: unknown; error: string | null }> {
285
207
  const result = await this.query<{
286
208
  stonecropAction: { success: boolean; data: unknown; error: string | null }
287
- }>(
288
- `
289
- mutation RunAction($doctype: String!, $action: String!, $args: JSON) {
290
- stonecropAction(doctype: $doctype, action: $action, args: $args) {
291
- success
292
- data
293
- error
294
- }
295
- }
296
- `,
297
- {
298
- doctype: doctype.name,
299
- action,
300
- args,
301
- }
302
- )
209
+ }>(RUN_ACTION_MUTATION, {
210
+ doctype: doctype.name,
211
+ action,
212
+ args,
213
+ })
303
214
 
304
215
  return result.stonecropAction
305
216
  }
package/src/queries.ts ADDED
@@ -0,0 +1,106 @@
1
+ /**
2
+ * GraphQL query documents sent by {@link StonecropClient} to the middleware.
3
+ *
4
+ * These are the client's half of the wire contract with `@stonecrop/graphql-middleware`.
5
+ * They live here as exported constants (rather than inline in the client methods) so the
6
+ * cross-package contract test can validate the exact strings the client sends against the
7
+ * middleware's published SDL — a field the server drops while a query still selects it must
8
+ * fail CI, not production.
9
+ *
10
+ * @public
11
+ */
12
+ export const GET_META_QUERY = `
13
+ query GetMeta($doctype: String!) {
14
+ stonecropMeta(doctype: $doctype) {
15
+ name
16
+ slug
17
+ fields {
18
+ kind
19
+ fieldname
20
+ component
21
+ doctype
22
+ label
23
+ width
24
+ align
25
+ edit
26
+ mask
27
+ format
28
+ mode
29
+ options
30
+ required
31
+ readOnly
32
+ hidden
33
+ default
34
+ validation
35
+ cardinality
36
+ source
37
+ }
38
+ workflow {
39
+ states
40
+ actions {
41
+ label
42
+ requiredFields
43
+ allowedStates
44
+ }
45
+ }
46
+ inherits
47
+ }
48
+ }
49
+ `
50
+
51
+ /**
52
+ * Mutation document for dispatching a workflow action (the server-owned transition).
53
+ * @public
54
+ */
55
+ export const RUN_ACTION_MUTATION = `
56
+ mutation RunAction($doctype: String!, $action: String!, $args: JSON) {
57
+ stonecropAction(doctype: $doctype, action: $action, args: $args) {
58
+ success
59
+ data
60
+ error
61
+ }
62
+ }
63
+ `
64
+
65
+ /**
66
+ * Query document for fetching all doctype metadata.
67
+ * @public
68
+ */
69
+ export const GET_ALL_META_QUERY = `
70
+ query GetAllMeta {
71
+ stonecropAllMeta {
72
+ name
73
+ slug
74
+ fields {
75
+ kind
76
+ fieldname
77
+ component
78
+ doctype
79
+ label
80
+ width
81
+ align
82
+ edit
83
+ mask
84
+ format
85
+ mode
86
+ options
87
+ required
88
+ readOnly
89
+ hidden
90
+ default
91
+ validation
92
+ cardinality
93
+ source
94
+ }
95
+ workflow {
96
+ states
97
+ actions {
98
+ label
99
+ requiredFields
100
+ allowedStates
101
+ }
102
+ }
103
+ inherits
104
+ }
105
+ }
106
+ `
package/dist/client.js DELETED
@@ -1,247 +0,0 @@
1
- /**
2
- * Client for interacting with Stonecrop GraphQL API.
3
- *
4
- * Acts as a transport layer — it passes requests to the middleware and returns
5
- * merged results. Does not construct queries itself.
6
- *
7
- * @public
8
- */
9
- export class StonecropClient {
10
- endpoint;
11
- headers;
12
- metaCache = new Map();
13
- constructor(options) {
14
- this.endpoint = options.endpoint;
15
- this.headers = {
16
- 'Content-Type': 'application/json',
17
- ...options.headers,
18
- };
19
- }
20
- /**
21
- * Execute a GraphQL query against the configured endpoint.
22
- *
23
- * @param query - GraphQL query string
24
- * @param variables - Query variables
25
- * @throws Error if the GraphQL response contains errors
26
- */
27
- async query(query, variables) {
28
- const response = await fetch(this.endpoint, {
29
- method: 'POST',
30
- headers: this.headers,
31
- body: JSON.stringify({ query, variables }),
32
- });
33
- const json = (await response.json());
34
- if (json.errors?.length) {
35
- throw new Error(json.errors[0].message);
36
- }
37
- return json.data;
38
- }
39
- /**
40
- * Execute a GraphQL mutation. Delegates to query() since both use POST.
41
- *
42
- * @param mutation - GraphQL mutation string
43
- * @param variables - Mutation variables
44
- */
45
- async mutate(mutation, variables) {
46
- return this.query(mutation, variables);
47
- }
48
- /**
49
- * Get doctype metadata
50
- * @param context - Doctype context containing doctype name
51
- */
52
- async getMeta(context) {
53
- const cached = this.metaCache.get(context.doctype);
54
- if (cached)
55
- return cached;
56
- const result = await this.query(`
57
- query GetMeta($doctype: String!) {
58
- stonecropMeta(doctype: $doctype) {
59
- name
60
- slug
61
- tableName
62
- fields {
63
- fieldname
64
- fieldtype
65
- component
66
- label
67
- width
68
- align
69
- required
70
- readOnly
71
- edit
72
- hidden
73
- default
74
- options
75
- mask
76
- precision
77
- scale
78
- mode
79
- validation
80
- }
81
- workflow {
82
- states
83
- actions {
84
- label
85
- handler
86
- requiredFields
87
- allowedStates
88
- confirm
89
- args
90
- }
91
- }
92
- inherits
93
- }
94
- }
95
- `, { doctype: context.doctype });
96
- if (result.stonecropMeta) {
97
- this.metaCache.set(context.doctype, result.stonecropMeta);
98
- }
99
- return result.stonecropMeta;
100
- }
101
- /**
102
- * Get all doctype metadata
103
- */
104
- async getAllMeta() {
105
- const result = await this.query(`
106
- query GetAllMeta {
107
- stonecropAllMeta {
108
- name
109
- slug
110
- tableName
111
- fields {
112
- fieldname
113
- fieldtype
114
- component
115
- label
116
- width
117
- align
118
- required
119
- readOnly
120
- edit
121
- hidden
122
- default
123
- options
124
- mask
125
- precision
126
- scale
127
- mode
128
- validation
129
- }
130
- workflow {
131
- states
132
- actions {
133
- label
134
- handler
135
- requiredFields
136
- allowedStates
137
- confirm
138
- args
139
- }
140
- }
141
- inherits
142
- }
143
- }
144
- `);
145
- for (const meta of result.stonecropAllMeta) {
146
- this.metaCache.set(meta.name, meta);
147
- }
148
- return result.stonecropAllMeta;
149
- }
150
- /**
151
- * Get a single record by ID.
152
- *
153
- * Routes through the stonecropRecord resolver which handles nested data
154
- * fetching based on the includeNested option.
155
- *
156
- * @param doctype - Doctype reference (name and optional slug)
157
- * @param recordId - Record ID to fetch
158
- * @param options - Query options (includeNested, maxDepth)
159
- */
160
- async getRecord(doctype, recordId, options) {
161
- const result = await this.query(`query GetRecord($doctype: String!, $id: String!, $options: JSON) {
162
- stonecropRecord(doctype: $doctype, id: $id, options: $options) {
163
- data
164
- unknownLinks
165
- }
166
- }`, {
167
- doctype: doctype.name,
168
- id: recordId,
169
- options: options?.includeNested
170
- ? {
171
- includeNested: options.includeNested,
172
- maxDepth: options.maxDepth,
173
- }
174
- : undefined,
175
- });
176
- return {
177
- record: result.stonecropRecord?.data ?? null,
178
- unknownLinks: result.stonecropRecord?.unknownLinks,
179
- };
180
- }
181
- /**
182
- * Get multiple records with optional filtering and pagination.
183
- *
184
- * Returns flat arrays — the middleware merges connection format (\{ nodes: [...] \})
185
- * into plain arrays before returning.
186
- *
187
- * @param doctype - Doctype reference (name and optional slug)
188
- * @param options - Query options (filters, orderBy, limit, offset)
189
- */
190
- async getRecords(doctype, options) {
191
- const result = await this.query(`
192
- query GetRecords(
193
- $doctype: String!
194
- $filters: JSON
195
- $orderBy: String
196
- $limit: Int
197
- $offset: Int
198
- ) {
199
- stonecropRecords(
200
- doctype: $doctype
201
- filters: $filters
202
- orderBy: $orderBy
203
- limit: $limit
204
- offset: $offset
205
- ) {
206
- data
207
- count
208
- }
209
- }
210
- `, {
211
- doctype: doctype.name,
212
- ...options,
213
- });
214
- return result.stonecropRecords.data;
215
- }
216
- /**
217
- * Execute a doctype action
218
- * @param doctype - Doctype reference (name and optional slug)
219
- * @param action - Action name to execute
220
- * @param args - Action arguments
221
- */
222
- async runAction(doctype, action, args) {
223
- const result = await this.query(`
224
- mutation RunAction($doctype: String!, $action: String!, $args: JSON) {
225
- stonecropAction(doctype: $doctype, action: $action, args: $args) {
226
- success
227
- data
228
- error
229
- }
230
- }
231
- `, {
232
- doctype: doctype.name,
233
- action,
234
- args,
235
- });
236
- return result.stonecropAction;
237
- }
238
- /**
239
- * Clear the cached doctype metadata.
240
- *
241
- * Call this if the server-side doctype schema has changed and you need
242
- * to fetch fresh metadata (e.g., after adding a new field).
243
- */
244
- clearMetaCache() {
245
- this.metaCache.clear();
246
- }
247
- }
@@ -1,53 +0,0 @@
1
- import { gql } from 'graphql-request';
2
- /**
3
- * This is the schema for the GraphQL API.
4
- * @public
5
- */
6
- const typeDefs = gql `
7
- type Doctype {
8
- id: ID!
9
- name: String!
10
- workflow: String!
11
- schema: String!
12
- actions: String!
13
- }
14
-
15
- type DoctypeField {
16
- id: ID!
17
- label: String!
18
- fieldtype: String
19
- component: String
20
- required: Boolean
21
- readonly: Boolean
22
- }
23
-
24
- type DoctypeWorkflow {
25
- name: String!
26
- machine: StateMachine!
27
- }
28
-
29
- type StateMachine {
30
- id: ID!
31
- }
32
-
33
- type DoctypeAction {
34
- eventName: String!
35
- callback: String
36
- }
37
-
38
- type Query {
39
- getMeta(doctype: String!): Doctype # ∪ error
40
- getRecords(doctype: String!, filters: [String]): [String] # ∪ error
41
- getRecord(doctype: String!, id: ID!): String # ∪ error
42
- }
43
-
44
- type Mutation {
45
- runAction(doctype: String!, id: [ID!]!, functionName: String!): [String!]! # ∪ error
46
- }
47
-
48
- schema {
49
- query: Query
50
- mutation: Mutation
51
- }
52
- `;
53
- export default typeDefs;