@wix/auto-patterns 1.38.0 → 1.40.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.
Files changed (30) hide show
  1. package/dist/cjs/components/AutoPatternsCollectionComponent/AutoPatternsCollectionComponent.js +72 -18
  2. package/dist/cjs/components/AutoPatternsCollectionComponent/AutoPatternsCollectionComponent.js.map +1 -1
  3. package/dist/cjs/components/AutoPatternsEntityPage/AutoPatternsEntityPage.js +41 -10
  4. package/dist/cjs/components/AutoPatternsEntityPage/AutoPatternsEntityPage.js.map +1 -1
  5. package/dist/cjs/components/AutoPatternsRoute/AutoPatternsPage.js +50 -14
  6. package/dist/cjs/components/AutoPatternsRoute/AutoPatternsPage.js.map +1 -1
  7. package/dist/cjs/hooks/useActionCell.js +14 -8
  8. package/dist/cjs/hooks/useActionCell.js.map +1 -1
  9. package/dist/cjs/types/actions/actionCell.js.map +1 -1
  10. package/dist/esm/components/AutoPatternsCollectionComponent/AutoPatternsCollectionComponent.js +28 -10
  11. package/dist/esm/components/AutoPatternsCollectionComponent/AutoPatternsCollectionComponent.js.map +1 -1
  12. package/dist/esm/components/AutoPatternsEntityPage/AutoPatternsEntityPage.js +18 -6
  13. package/dist/esm/components/AutoPatternsEntityPage/AutoPatternsEntityPage.js.map +1 -1
  14. package/dist/esm/components/AutoPatternsRoute/AutoPatternsPage.js +16 -6
  15. package/dist/esm/components/AutoPatternsRoute/AutoPatternsPage.js.map +1 -1
  16. package/dist/esm/hooks/useActionCell.js +14 -8
  17. package/dist/esm/hooks/useActionCell.js.map +1 -1
  18. package/dist/esm/types/actions/actionCell.js.map +1 -1
  19. package/dist/types/components/AutoPatternsCollectionComponent/AutoPatternsCollectionComponent.d.ts +1 -1
  20. package/dist/types/components/AutoPatternsCollectionComponent/AutoPatternsCollectionComponent.d.ts.map +1 -1
  21. package/dist/types/components/AutoPatternsEntityPage/AutoPatternsEntityPage.d.ts.map +1 -1
  22. package/dist/types/components/AutoPatternsRoute/AutoPatternsPage.d.ts.map +1 -1
  23. package/dist/types/hooks/useActionCell.d.ts.map +1 -1
  24. package/dist/types/types/actions/actionCell.d.ts +13 -1
  25. package/dist/types/types/actions/actionCell.d.ts.map +1 -1
  26. package/mcp-docs/action_cell.md +66 -8
  27. package/mcp-docs/app_config_structure.md +50 -43
  28. package/mcp-docs/auto-patterns-guide.md +116 -51
  29. package/mcp-docs/wix_fqdn_custom_data_source.md +360 -196
  30. package/package.json +12 -12
@@ -1,4 +1,4 @@
1
- # FQDN-Based Custom Data Source Implementation
1
+ ## Build a Custom Data Source from a Wix Business API FQDN (with Contacts v4 example)
2
2
 
3
3
  **🛑 CRITICAL PREREQUISITE**: This guide explains a specialized feature that exists within the broader auto-patterns framework. You **CANNOT** implement this guide without first having the complete content of the WixAutoPatternsGuide.
4
4
 
@@ -8,13 +8,44 @@
8
8
  2. **This document is NOT standalone** - it's an advanced feature guide that builds upon the core auto-patterns concepts
9
9
  3. **Without the WixAutoPatternsGuide content**, you will not understand the basic concepts, component structure, or implementation patterns required for this FQDN implementation
10
10
 
11
- When implementing a custom data source based on a Wix Business API FQDN, you'll need to understand several key concepts and follow specific implementation patterns. This guide covers the complete process from schema extraction to creating a foundation structure that **you will need to complete**.
11
+ This guide shows how to build an Auto-Patterns custom data source backed by a Wix Business API entity identified by its FQDN. You will:
12
12
 
13
- **⚠️ IMPORTANT**: This guide creates a foundation with helpful comments and unimplemented actions that throw exceptions. The actual data source implementation (CRUD operations) must be completed by you using the appropriate Wix Business API client library.
13
+ - Discover schema and client library via the Business Schema MCP
14
+ - Map the FQDN schema to a `SchemaConfig` (see `schema_config.md` for the full interface)
15
+ - Implement actions (CRUD + find)
16
+ - Wire the custom data source into your Auto-Patterns page
17
+
18
+ > IMPORTANT: Always use the Business Schema MCP as the source of truth for your target FQDN.
19
+ > - Run `client_lib` to determine the exact SDK/ambassador package to install and import
20
+ > - Run `fqdn_info` to see available actions, pagination mode, and request/response structure
21
+ > - (Optional) Run `fqdn_schema` for precise field shapes
22
+ > Do not rely on this example without verifying all details for your specific FQDN via MCP.
14
23
 
15
24
  **📝 MINIMAL IMPLEMENTATION APPROACH**: This guide focuses on creating a basic, functional dashboard page. Custom overrides (actions, columns, components, etc.) should only be implemented when explicitly requested by the user. A simple dashboard page requires only the core custom data source implementation without any additional overrides.
16
25
 
17
- ## Prerequisites: Required Tools and Knowledge
26
+ ### Non‑negotiable requirements (LLM guardrails)
27
+
28
+ - You **MUST** derive the SDK package, action names, required fields, and pagination mode from Business Schema MCP.
29
+ - You **MUST** install the package returned by `client_lib` before importing/using it.
30
+ - You **MUST** map API snake_case field segments to camelCase segments in `SchemaConfig`, preserving dot paths.
31
+ - You **MUST** set `supportedQueryOperators: []` for all fields in custom data sources.
32
+ - You **MUST** return the correct pagination shape from `actions.find` based on the API’s paging mode.
33
+ - You **MUST** pass required concurrency/identity fields (e.g., `revision` on Contacts v4 updates) exactly as specified by MCP.
34
+ - You **MUST** fully implement `SchemaConfig` (fields and actions). Do not leave placeholders; do not use `as any` to bypass typing.
35
+ - You **MUST NOT** create new custom entity types. Use SDK-exported types (from the ambassador/SDK package) or rely on inference. Avoid `any` that suppresses type errors.
36
+
37
+ ### LLM Quick‑Start Execution Plan (follow in order)
38
+
39
+ 1. **MUST** run `client_lib` on your FQDN and note the exact package name.
40
+ 2. **MUST** install that package (npm/yarn/pnpm) and import the correct client entry point.
41
+ 3. **MUST** run `fqdn_info` to list actions, required fields, and pagination type; use it to draft your actions.
42
+ 4. **MUST** run `fqdn_schema` if you need concrete field shapes; map fields to `SchemaConfig` with segment-wise snake_case→camelCase and preserved dot paths.
43
+ 5. **MUST** implement `actions` using the exact method names and payloads from MCP; add robust error handling.
44
+ 6. **MUST** implement `find` to return the correct pagination shape (cursor vs offset) per MCP.
45
+ 7. **MUST** register the custom data source and set matching `custom.id` in AppConfig.
46
+ 8. **MUST** keep `supportedQueryOperators: []` for all fields.
47
+
48
+ ### Prerequisites: Required Tools and Knowledge
18
49
 
19
50
  **🛑 ABSOLUTE REQUIREMENT - WixAutoPatternsGuide Content**:
20
51
 
@@ -26,6 +57,7 @@ When implementing a custom data source based on a Wix Business API FQDN, you'll
26
57
  **🛑 CRITICAL**: Before proceeding with this guide, you must have the following tools available:
27
58
 
28
59
  - `WixAutoPatternsGuide` tool for understanding auto-patterns fundamentals and implementation patterns (**MANDATORY FIRST STEP**)
60
+ - `fqdn_info` tool for extracting action information from FQDNs
29
61
  - `fqdn_schema` tool for extracting schema information from FQDNs
30
62
  - `client_lib` tool for determining the correct client library package
31
63
 
@@ -43,55 +75,65 @@ If you haven't already used the `WixAutoPatternsGuide` tool in this conversation
43
75
 
44
76
  **Without this foundational knowledge, you cannot successfully implement FQDN-based custom data sources.**
45
77
 
46
- To add these tools, you need to install the **business-schema-mcp** server:
47
-
48
- **Installation Instructions:**
49
-
50
- 1. Follow the setup instructions at: https://github.com/wix-private/mcp-servers/tree/master/packages/business-schema-mcp
51
- 2. Configure the MCP server according to the documentation
52
- 3. Restart your development environment to load the new tools
53
- 4. Return to this guide once the tools are available
78
+ **Tool Installation:**
79
+ - Business Schema MCP installed and available in your environment
80
+ - Tools used: `fqdn_info`, `fqdn_schema`, `client_lib`
81
+ - Installation: see the Business Schema MCP README (internal)
54
82
 
55
83
  **Tool Verification:**
56
84
  Before continuing, verify that you have access to:
57
85
 
86
+ - `fqdn_info` tool - for extracting action and pagination information from FQDNs
58
87
  - `fqdn_schema` tool - for extracting entity schema from FQDNs
59
88
  - `client_lib` tool - for determining the correct SDK package to use
60
89
 
61
- ## Step 1: Extract Schema Information
90
+ ### What you will build
62
91
 
63
- First, use the fqdn_schema tool to understand the structure of your target entity:
92
+ We'll create a custom data source for Contacts using `wix.contacts.v4.contact` as an example. The same steps apply to any other FQDN.
64
93
 
65
- ```
66
- Use fqdn_schema tool with your FQDN (e.g., "wix.bookings.v1.sessions")
67
- ```
94
+ ---
68
95
 
69
- This will provide you with:
96
+ ## 1) Discover schema and SDK with Business Schema MCP
70
97
 
71
- - Entity field definitions
72
- - Available actions/operations
73
- - Field types and constraints
74
- - Relationships and references
98
+ Use the MCP tools to examine the entity and determine which SDK package to use.
75
99
 
76
- ## Step 2: Determine Client Library
100
+ ```text
101
+ Call client_lib with: "wix.contacts.v4.contact" -> returns: @wix/crm
77
102
 
78
- Use the client_lib tool to identify the correct package for your FQDN:
103
+ Call fqdn_info with: "wix.contacts.v4.contact" -> see common methods like CreateContact, GetContact, UpdateContact, DeleteContact, QueryContacts (offset-based)
79
104
 
80
- ```
81
- Use client_lib tool with your FQDN to get the appropriate SDK package
105
+ Optionally call fqdn_schema for message shapes (Contact, CreateContactRequest, etc.)
82
106
  ```
83
107
 
84
- This will tell you which library to import for your custom data source implementation.
108
+ Notes for Contacts v4:
109
+ - Paging for `QueryContacts` is offset-based
110
+ - Identifier in routes is `id` or `contactId` depending on the action; the entity carries an `id` field
85
111
 
86
- ## Step 3: Map FQDN Schema to SchemaConfig
112
+ Using other FQDNs: always run `client_lib` to get the exact package. Some entities use an ambassador package (e.g., `@wix/ambassador-<product>-<version>-<resource>`); install and import accordingly.
87
113
 
88
- Transform the FQDN schema from Step 1 into a AutoPatterns-compatible SchemaConfig by mapping the FQDN field types to AutoPatterns field types. Identify appropriate fields for `displayField` and `idField` based on your FQDN schema.
114
+ LLM notes:
115
+ - You **MUST NOT** guess method names or shapes; copy them from `fqdn_info`.
116
+ - You **MUST NOT** assume pagination type; read it from `fqdn_info` and implement accordingly.
89
117
 
90
- **🛑 MANDATORY - Query Operators Must Be Empty Array**: When implementing a custom data source, you **MUST** set `supportedQueryOperators: []` (empty array) for all fields. This is required because:
118
+ ### Install the SDK package
91
119
 
92
- - Custom data sources handle all query operations directly through your implementation
93
- - You don't need to specify individual operators for each field
94
- - The custom data source `find` action will receive all queries regardless of declared operators
120
+ For the Contacts v4 example:
121
+
122
+ ```bash
123
+ npm i @wix/crm
124
+ # or
125
+ yarn add @wix/crm
126
+ # or
127
+ pnpm add @wix/crm
128
+ ```
129
+
130
+ For other FQDNs, install the package returned by `client_lib`.
131
+
132
+ ---
133
+
134
+ ## 2) Map FQDN fields to SchemaConfig
135
+
136
+ See `schema_config.md` for the interface. Derive your field list and types from Business Schema MCP (`fqdn_schema` / `fqdn_info`) for YOUR FQDN, then apply these **MUST** rules:
95
137
 
96
138
  ### ⚠️ CRITICAL: Field ID Conversion from snake_case to camelCase
97
139
 
@@ -107,6 +149,9 @@ Transform the FQDN schema from Step 1 into a AutoPatterns-compatible SchemaConfi
107
149
  - `last_activity.activity_date` → `lastActivity.activityDate` (NOT `lastActivityDate`)
108
150
  - `job_title` → `jobTitle`
109
151
  - `created_date` → `createdDate`
152
+ - `info.job_title` → `info.jobTitle`
153
+ - `info.name.first` → `info.name.first` (already camelCase, no change needed)
154
+ - `info.name.last` → `info.name.last` (already camelCase, no change needed)
110
155
 
111
156
  This conversion ensures:
112
157
 
@@ -115,170 +160,260 @@ This conversion ensures:
115
160
  - **Proper field mapping** between configuration and data source
116
161
  - **Seamless integration** with AutoPatterns components
117
162
 
118
- For the complete SchemaConfig interface, field definitions, and implementation details, refer to the "Schema Config" section.
163
+ **🛑 MANDATORY - Query Operators Must Be Empty Array**: When implementing a custom data source, you **MUST** set `supportedQueryOperators: []` (empty array) for all fields. This is required because:
164
+
165
+ - Custom data sources handle all query operations directly through your implementation
166
+ - You don't need to specify individual operators for each field
167
+ - The custom data source `find` action will receive all queries regardless of declared operators
168
+
169
+ **Additional Rules:**
170
+ - You **MUST** choose:
171
+ - `idField`: typically `id`
172
+ - `displayField`: a meaningful label, e.g., `displayName`, or build from name fields
173
+
174
+ Minimal example for a subset of Contacts fields:
175
+
176
+ ```ts
177
+ import type { SchemaConfig } from "@wix/auto-patterns"; // refer to your local types
178
+
179
+ const fields: SchemaConfig["fields"] = {
180
+ id: {
181
+ id: "id",
182
+ displayName: "ID",
183
+ type: "SHORT_TEXT",
184
+ validation: { required: true },
185
+ capabilities: { supportedQueryOperators: [], sortable: true }
186
+ },
187
+ displayName: {
188
+ id: "displayName",
189
+ displayName: "Display Name",
190
+ type: "SHORT_TEXT",
191
+ validation: { required: false },
192
+ capabilities: { supportedQueryOperators: [], sortable: true }
193
+ },
194
+ createdDate: {
195
+ id: "createdDate", // from created_date
196
+ displayName: "Created Date",
197
+ type: "DATETIME",
198
+ validation: { required: false },
199
+ capabilities: { supportedQueryOperators: [], sortable: true }
200
+ },
201
+ updatedDate: {
202
+ id: "updatedDate", // from updated_date
203
+ displayName: "Updated Date",
204
+ type: "DATETIME",
205
+ validation: { required: false },
206
+ capabilities: { supportedQueryOperators: [], sortable: true }
207
+ },
208
+ "name.first": {
209
+ id: "name.first",
210
+ displayName: "First Name",
211
+ type: "SHORT_TEXT",
212
+ validation: { required: false },
213
+ capabilities: { supportedQueryOperators: [], sortable: true }
214
+ },
215
+ "name.last": {
216
+ id: "name.last",
217
+ displayName: "Last Name",
218
+ type: "SHORT_TEXT",
219
+ validation: { required: false },
220
+ capabilities: { supportedQueryOperators: [], sortable: true }
221
+ },
222
+ "email.email": {
223
+ id: "email.email",
224
+ displayName: "Email",
225
+ type: "SHORT_TEXT",
226
+ validation: { required: false },
227
+ capabilities: { supportedQueryOperators: [], sortable: true }
228
+ },
229
+ "phone.phone": {
230
+ id: "phone.phone",
231
+ displayName: "Phone",
232
+ type: "SHORT_TEXT",
233
+ validation: { required: false },
234
+ capabilities: { supportedQueryOperators: [], sortable: true }
235
+ }
236
+ };
237
+
238
+ // Field mapping example ends here.
239
+ // You MUST NOT ship a partial SchemaConfig. Implement the full SchemaConfig with actions (see section 3).
240
+ ```
241
+
242
+ ---
243
+
244
+ ## 3) Implement SchemaConfig actions
245
+
246
+ Actions **MUST** call the correct Wix client library returned by `client_lib`. For Contacts v4 use `@wix/crm`. For any other FQDN, use MCP (`client_lib`, `fqdn_info`) to get the exact package and method names, then adapt the calls accordingly.
247
+
248
+ **⚠️ IMPORTANT**: You have two implementation approaches available:
249
+
250
+ 1. **Full Implementation** (recommended for production): Complete working implementation with actual API calls
251
+ 2. **Foundation with Guidance** (recommended for scaffolding): Unimplemented actions with helpful comments and error throwing
252
+
253
+ ### Implementation Approach 1: Full Implementation
254
+
255
+ Implementation **MUSTs**:
256
+ - You **MUST** wrap HTTP calls with consistent error handling (e.g., `errorHandler` from `@wix/essentials`).
257
+ - You **MUST** map outgoing payloads from camelCase (SchemaConfig/AppConfig) to API snake_case when required, and map responses back.
258
+ - You **MUST** respect pagination mode:
259
+ - Cursor-based APIs: return `{ items, cursor, total? }`
260
+ - Offset-based APIs (Contacts v4): return `{ items, hasNext, total? }`
261
+ - For Contacts v4 updates, you **MUST** pass both `contactId` and the latest `revision`.
262
+
263
+ #### Example implementation (Contacts v4, offset-based):
264
+
265
+ ```ts
266
+ import { contacts } from "@wix/crm";
267
+ import type { SchemaConfig, Query } from "@wix/auto-patterns";
268
+ // import { errorHandler } from "@wix/essentials"; // if used in your app shell
269
+
270
+ // NOTE: Some SDKs expose methods directly off the named export (no client instantiation).
271
+ // Always verify import/method patterns in MCP `client_lib` docs/examples.
272
+
273
+ function toApiContact(input) {
274
+ // Map camelCase fields used in forms/UI back to API shapes as needed.
275
+ // Example only – adapt to your fields. Many v4 fields are snake_case.
276
+ return input;
277
+ }
278
+
279
+ function fromApiContact(api) {
280
+ // Map API response to the fields you exposed in SchemaConfig
281
+ return {
282
+ id: api.id ?? api._id,
283
+ displayName: api.display_name ?? api.displayName ?? api.info?.name?.first ?? api.info?.name?.last,
284
+ createdDate: api.created_date ?? api.createdDate,
285
+ updatedDate: api.updated_date ?? api.updatedDate,
286
+ primaryInfo: api.primary_info ?? api.primaryInfo,
287
+ info: api.info
288
+ };
289
+ }
290
+
291
+ export const contactsSchemaWithActions: SchemaConfig = {
292
+ id: "Contacts",
293
+ idField: "id",
294
+ displayField: "displayName",
295
+ // Provide the full fields object from section 2 in your implementation
296
+ fields,
297
+ actions: {
298
+ async get(entityId: string) {
299
+ const res = await contacts.getContact({ id: entityId });
300
+ // Some SDKs return the entity at the root (res) instead of res.contact — verify via MCP
301
+ return fromApiContact(res.contact ?? res);
302
+ },
303
+
304
+ async create(newEntity) {
305
+ const res = await contacts.createContact({ info: toApiContact(newEntity).info });
306
+ return fromApiContact(res.contact ?? res);
307
+ },
308
+
309
+ async update(updatedEntity) {
310
+ // v4 requires id and revision on updates
311
+ const { id, revision, info } = toApiContact(updatedEntity);
312
+ const res = await contacts.updateContact({ contactId: id, revision, info });
313
+ return fromApiContact(res.contact ?? res);
314
+ },
315
+
316
+ async delete(entityId: string) {
317
+ await contacts.deleteContact({ contactId: entityId });
318
+ return { id: entityId };
319
+ },
119
320
 
120
- ## Step 4: Set Up Custom Data Source Structure
321
+ async bulkDelete(entityIds: string[]) {
322
+ // If bulk delete API is not available, fall back to per-entity updates as defined by MCP
323
+ await contacts.bulkDeleteContacts?.({ contactIds: entityIds })
324
+ ?? Promise.all(entityIds.map((id) => contacts.deleteContact({ contactId: id })));
325
+ return { ids: entityIds };
326
+ },
121
327
 
122
- Follow the complete custom data source implementation guide in the "Custom Overrides" section. The key FQDN-specific considerations are:
328
+ async find(query: Query) {
329
+ // Use QueryContacts (offset-based). Map Auto-Patterns Query to API query
330
+ const limit = query.limit ?? 25;
331
+ const offset = query.offset ?? (query.page ? (query.page - 1) * limit : 0);
332
+ const res = await contacts.queryContacts({
333
+ query: {
334
+ paging: { limit, offset },
335
+ // Map filters/sort/search into the API query as needed
336
+ filter: /* build from query.filters */ undefined,
337
+ sort: /* build from query.sort */ undefined,
338
+ search: query.search ?? undefined
339
+ }
340
+ });
341
+ const items = (res.contacts ?? []).map(fromApiContact);
342
+ const hasNext = res.paging?.hasNext ?? (items.length === limit);
343
+ return { items, hasNext, total: null };
344
+ }
345
+ }
346
+ };
347
+ ```
123
348
 
124
- 1. **Import the client library** identified in Step 2
125
- 2. **Use the field mappings** from Step 3 in your SchemaConfig
126
- 3. **⚠️ CRITICAL: DO NOT IMPLEMENT THE ACTIONS** - Instead, add guidance comments explaining how to use the imported client library for each CRUD operation, then throw an "unimplemented exception" error
127
- 4. **⚠️ CRITICAL: Add Error Handling** - When implementing the actions, you MUST wrap all HTTP requests with proper error handling using `errorHandler` from `@wix/essentials` (see "Error Handling for HTTP Requests" section)
349
+ Notes:
350
+ - Update requires the latest `revision`. Make sure your UI carries it and you pass it when updating.
351
+ - If you target other FQDNs, import and call the methods from the package returned by `client_lib`, and adapt pagination (cursor vs offset) accordingly.
352
+ - **Validation warning**: You **MUST** verify that each method you plan to call exists in the SDK for your FQDN. Replace non-existent operations with the supported alternatives per MCP (for example, use `update*` to set an `archived` flag if no `archive*` exists).
353
+ - **⚠️ CRITICAL: Add Error Handling** - When implementing the actions, you MUST wrap all HTTP requests with proper error handling using `errorHandler` from `@wix/essentials`
128
354
 
129
- **Important**: The schema actions should contain helpful comments but NOT actual implementations. Each action should throw an error indicating it's unimplemented and needs to be implemented by the user.
355
+ ---
356
+
357
+ ## 4) Set Up Custom Data Source Structure and Hook Pattern
130
358
 
131
359
  ### Custom Data Source Hook Implementation
132
360
 
133
- Create your custom data source with the hook pattern:
361
+ Create your custom data source with the hook pattern for better React integration:
134
362
 
135
- In `components/customDataSources/myCustomDataSource.ts`:
363
+ In `components/customDataSources/contactsDataSource.ts`:
136
364
 
137
365
  ```typescript
138
366
  import { SchemaConfig } from '@wix/auto-patterns/types';
367
+ import { contacts } from "@wix/crm";
368
+ // Choose your implementation approach from section 3 above
139
369
 
140
- export const myCustomDataSource = async (
370
+ export const contactsDataSource = async (
141
371
  collectionId: string,
142
372
  context: any,
143
373
  ): Promise<SchemaConfig> => {
144
- return {
145
- id: 'myCustomCollection',
146
- fields: {
147
- // Field definitions based on your FQDN schema mapping
148
- },
149
- displayField: 'name',
150
- idField: 'id',
151
- actions: {
152
- get: async (entityId: string) => {
153
- // TODO: Implement using your FQDN client library
154
- // Example:
155
- // return errorHandler.withErrorHandler(
156
- // async () => {
157
- // return yourFQDNClient.getEntity(entityId);
158
- // },
159
- // {}
160
- // );
161
- // Remember to map the response fields from snake_case to camelCase
162
- throw new Error(
163
- 'get action not implemented - user must implement this method',
164
- );
165
- },
166
- create: async (newEntity: any) => {
167
- // TODO: Implement using your FQDN client library
168
- // Example:
169
- // return errorHandler.withErrorHandler(
170
- // async () => {
171
- // return yourFQDNClient.createEntity(newEntity);
172
- // },
173
- // {}
174
- // );
175
- // Remember to map the request fields from camelCase to snake_case
176
- throw new Error(
177
- 'create action not implemented - user must implement this method',
178
- );
179
- },
180
- update: async (updatedEntity: any) => {
181
- // TODO: Implement using your FQDN client library
182
- // Example:
183
- // return errorHandler.withErrorHandler(
184
- // async () => {
185
- // return yourFQDNClient.updateEntity(updatedEntity);
186
- // },
187
- // {}
188
- // );
189
- // Remember to map the request fields from camelCase to snake_case
190
- throw new Error(
191
- 'update action not implemented - user must implement this method',
192
- );
193
- },
194
- delete: async (entityId: string) => {
195
- // TODO: Implement using your FQDN client library
196
- // Example:
197
- // return errorHandler.withErrorHandler(
198
- // async () => {
199
- // return yourFQDNClient.deleteEntity(entityId);
200
- // },
201
- // {}
202
- // );
203
- throw new Error(
204
- 'delete action not implemented - user must implement this method',
205
- );
206
- },
207
- bulkDelete: async (entityIds: string[]) => {
208
- // TODO: Implement using your FQDN client library
209
- // Example:
210
- // return errorHandler.withErrorHandler(
211
- // async () => {
212
- // return yourFQDNClient.bulkDeleteEntities(entityIds);
213
- // },
214
- // {}
215
- // );
216
- throw new Error(
217
- 'bulkDelete action not implemented - user must implement this method',
218
- );
219
- },
220
- find: async (query: Query, options?: any) => {
221
- // TODO: Implement using your FQDN client library
222
- // Example:
223
- // return errorHandler.withErrorHandler(
224
- // async () => {
225
- // return yourFQDNClient.queryEntities(query, options);
226
- // },
227
- // {}
228
- // );
229
- // Remember to map the response fields from snake_case to camelCase
230
- // IMPORTANT: Return shape depends on pagination mode.
231
- // Detect by presence of query.cursor (cursor mode) vs. query.offset/page (offset mode):
232
- // - Cursor mode: return { items, cursor, total? }
233
- // - Offset mode (default): return { items, hasNext, total? }
234
- throw new Error(
235
- 'find action not implemented - user must implement this method',
236
- );
237
- },
238
- move: async (
239
- id,
240
- {
241
- moveAfterId,
242
- }: {
243
- moveAfterId: string | null | undefined;
244
- },
245
- ) => {
246
- // TODO: Implement using your FQDN client library if it supports ordering/moving entities
247
- // Example:
248
- // return errorHandler.withErrorHandler(
249
- // async () => {
250
- // return yourFQDNClient.mvoeEntity(id, {
251
- // moveAfterCategoryId: moveAfterId,
252
- // position: moveAfterId ? 'AFTER' : 'FIRST',
253
- // })
254
- // },
255
- // {}
256
- // );
257
- throw new Error(
258
- 'move action not implemented - user must implement this method',
259
- );
260
- },
261
- },
262
- };
374
+ return contactsSchemaWithActions; // Your SchemaConfig from section 3
263
375
  };
264
376
  ```
265
377
 
266
378
  In `components/customDataSources/index.tsx`:
267
379
 
268
380
  ```typescript
269
- import { myCustomDataSource } from './myCustomDataSource';
381
+ import { contactsDataSource } from './contactsDataSource';
270
382
 
271
383
  export const useCustomDataSources = () => {
272
384
  // You can access React context and other hooks here
273
385
  return {
274
- myCustomDataSource,
386
+ contactsFqdn: contactsDataSource,
275
387
  };
276
388
  };
277
389
  ```
278
390
 
279
391
  For detailed implementation patterns, folder structure, and registration steps, refer to the **Custom Data Sources** section in "Custom Overrides".
280
392
 
281
- ## Step 5: Update AppConfig
393
+ ## 5) Register the custom data source and wire AppConfig
394
+
395
+ You **MUST** register the custom data source and reference it from AppConfig.
396
+
397
+ ### Register Custom Data Source
398
+
399
+ In your main page component, use the hook to register your custom data source:
400
+
401
+ ```tsx
402
+ import { AutoPatternsApp, AutoPatternsOverridesProvider } from "@wix/auto-patterns"; // adjust import path in your monorepo
403
+ import { useCustomDataSources } from '../components/customDataSources';
404
+
405
+ export function Page() {
406
+ const customDataSources = useCustomDataSources();
407
+
408
+ return (
409
+ <AutoPatternsOverridesProvider value={{ customDataSources }}>
410
+ <AutoPatternsApp configuration={config} />
411
+ </AutoPatternsOverridesProvider>
412
+ );
413
+ }
414
+ ```
415
+
416
+ ### Update AppConfig
282
417
 
283
418
  Configure your AppConfig to use the custom data source by setting:
284
419
 
@@ -288,55 +423,73 @@ Configure your AppConfig to use the custom data source by setting:
288
423
  **Key FQDN-specific configuration:**
289
424
 
290
425
  ```json
291
- "collection": {
292
- "collectionId": "yourCustomCollectionId",
293
- "entityTypeSource": "custom",
294
- "custom": {
295
- "id": "yourCustomDataSourceId"
426
+ {
427
+ "collection": {
428
+ "collectionId": "Contacts",
429
+ "entityTypeSource": "custom",
430
+ "custom": { "id": "contactsFqdn" },
431
+ "paginationMode": "offset" // v4 uses offset; use "cursor" for cursor-based APIs
296
432
  }
297
433
  }
298
434
  ```
299
435
 
300
436
  For complete AppConfig structure, configuration rules, and advanced options, refer to the "App Config Structure" section.
301
437
 
302
- ## Step 6: Register Custom Data Source
438
+ ---
303
439
 
304
- In your main page component, use the hook to register your custom data source:
440
+ ## 6) Building queries, filters and sorts
305
441
 
306
- ```tsx
307
- import { useCustomDataSources } from '../components/customDataSources';
442
+ - Keep `supportedQueryOperators: []` on fields. Build server-side WQL/search inside `actions.find`
443
+ - Map `Query.filters` to the API’s filter object
444
+ - Map `Query.sort` to API sorting
308
445
 
309
- export default function YourPage() {
310
- const customDataSources = useCustomDataSources();
446
+ For Contacts v4, you **MUST** use `QueryContacts` (WQL) and map your UI query object to the API query. For other entities, use their recommended query/search method per MCP and map accordingly.
311
447
 
312
- return (
313
- <AutoPatternsOverridesProvider value={{ customDataSources }}>
314
- <AutoPatternsApp configuration={config} />
315
- </AutoPatternsOverridesProvider>
316
- );
317
- }
318
- ```
448
+ ---
449
+
450
+ ## 7) Error handling and robustness
451
+
452
+ - Wrap all HTTP requests with a consistent error handler (e.g., `errorHandler` from `@wix/essentials`) in your app shell
453
+ - Surface meaningful messages using your `displayField`
454
+ - Handle retries or specific application codes (duplicate, permission, invalid argument) when appropriate
455
+
456
+ ---
457
+
458
+ ## 8) Contacts v4 field mapping reference (subset)
319
459
 
320
- ## Step 7: Implement Custom Actions (Only if Explicitly Requested)
460
+ Examples derived from `fqdn_info` and query/search patterns:
321
461
 
322
- **⚠️ IMPORTANT**: Custom actions should only be implemented when the user explicitly requests them. A basic dashboard page with standard CRUD operations does not require custom actions.
462
+ - `id` `id`
463
+ - `display_name` → `displayName`
464
+ - `created_date` → `createdDate`
465
+ - `updated_date` → `updatedDate`
466
+ - `info.name.first` → `info.name.first`
467
+ - `info.name.last` → `info.name.last`
468
+ - `primary_info.email` → `primaryInfo.email`
469
+ - `info.job_title` → `info.jobTitle`
470
+ - `last_activity.activity_date` → `lastActivity.activityDate`
471
+
472
+ Follow the snake_case-to-camelCase-per-segment rule and preserve dot paths. Use the original API field names when calling the SDK; use the camelCased paths in `SchemaConfig`/AppConfig.
323
473
 
324
- If the user specifically requests custom actions for your FQDN-based data source, follow the action implementation patterns from the "Custom Overrides" section. Your custom actions will have access to the same SDK utilities, but remember that they will need to interact with your FQDN-based API directly since the SchemaConfig actions from Step 4 are left unimplemented for you to complete.
474
+ ---
325
475
 
326
- ## FQDN-Specific Implementation Checklist
476
+ ## 9) FQDN-Specific Implementation Checklist
327
477
 
328
478
  ### Core Requirements (Always Required)
329
479
 
330
- ✅ **Schema Extraction**: Used fqdn_schema tool to understand entity structure
480
+ ✅ **Schema Extraction**: Used fqdn_info and/or fqdn_schema tools to understand entity structure
331
481
  ✅ **Client Library**: Used client_lib tool to identify correct SDK package
332
482
  ✅ **Field Mapping**: Mapped FQDN field types to AutoPatterns field types
333
- ✅ **Entity Info Mapping**: Mapped FQDN entity info to SchemaConfig properties (containsPii, extensible)
334
483
  ✅ **🛑 MANDATORY: Empty Query Operators**: Set `supportedQueryOperators: []` for ALL fields to avoid TypeScript errors
335
484
  ✅ **⚠️ CRITICAL: Field ID Conversion**: Converted individual field segments from snake_case to camelCase while preserving field path structure in SchemaConfig and AppConfig
485
+ ✅ **Package Installation**: Installed the exact SDK package reported by `client_lib` (e.g., `@wix/crm` for Contacts v4)
486
+ ✅ **Implementation Choice**: Chose either full implementation or foundation with guidance approach
487
+ ✅ **Pagination Shape**: Return the correct pagination shape from `find` (cursor vs offset per MCP)
336
488
  ✅ **AppConfig Update**: Set `entityTypeSource: "custom"` and provided custom.id
337
- ✅ **Custom Data Source Structure**: Followed "Custom Overrides" section for folder structure and registration
489
+ ✅ **Custom Data Source Structure**: Followed proper folder structure and registration
338
490
  ✅ **Hook Implementation**: Created useCustomDataSources hook for accessing React context
339
- **⚠️ CRITICAL: Unimplemented Actions**: All schema actions contain helpful comments but throw unimplemented exceptions - **user must implement these actions themselves**
491
+ **Registration**: Registered the custom data source in `AutoPatternsOverridesProvider`
492
+ ✅ **Matching IDs**: Used matching `custom.id` in AppConfig
340
493
 
341
494
  ### Optional Enhancements (Only When Explicitly Requested)
342
495
 
@@ -345,11 +498,10 @@ If the user specifically requests custom actions for your FQDN-based data source
345
498
  ⚠️ **Custom Components**: Only implement if user requests custom entity page components
346
499
  ⚠️ **Bulk Operations**: Only implement if user requests custom bulk actions beyond standard bulk delete
347
500
 
348
- ## Common FQDN-Specific Pitfalls to Avoid
501
+ ## 10) Common FQDN-Specific Pitfalls to Avoid
349
502
 
350
503
  - **⚠️ CRITICAL: Implementing Unnecessary Overrides**: Do NOT implement custom actions, column overrides, or custom components unless explicitly requested by the user - a basic dashboard page only needs the core custom data source
351
504
  - **⚠️ CRITICAL: Inconsistent Field ID Casing**: Failing to convert individual field segments from snake_case to camelCase while preserving field path structure in SchemaConfig and AppConfig - this is the most common mistake and will cause field mapping failures
352
- - **⚠️ CRITICAL: Implementing Actions**: DO NOT implement the schema actions - they should contain helpful comments and throw unimplemented exceptions for the user to complete
353
505
  - **🛑 CRITICAL: Query Operators MUST Be Empty Array**: You **MUST** use `supportedQueryOperators: []` (empty array) for all fields - attempting to specify actual operators will cause TypeScript compilation errors and is not supported for custom data sources
354
506
  - **Mismatched Field Types**: Ensure FQDN field types are correctly mapped to AutoPatterns types
355
507
  - **Wrong Client Library**: Use the exact client library returned by the client_lib tool
@@ -357,10 +509,15 @@ If the user specifically requests custom actions for your FQDN-based data source
357
509
  - **Display Field Selection**: Choose a display field that provides meaningful identification from your FQDN schema
358
510
  - **Custom Data Source ID Mismatch**: Ensure the custom.id in AppConfig matches your custom data source identifier
359
511
  - **Hook Registration**: Don't forget to register the custom data source through the useCustomDataSources hook
512
+ - **Mixing snake_case and camelCase**: In `SchemaConfig`/AppConfig field ids
513
+ - **Returning the wrong pagination shape**: From `find` action
514
+ - **Forgetting to pass `revision`**: On updates (especially v4/v5 APIs)
515
+ - **Using the wrong client library**: Always trust `client_lib` result
516
+ - **Missing error handling**: When implementing actions, wrap HTTP calls with proper error handling
360
517
 
361
- For general implementation pitfalls, refer to the "Custom Overrides" section.
518
+ ---
362
519
 
363
- ## Advanced Customization (Only When Explicitly Requested)
520
+ ## 11) Advanced Customization (Only When Explicitly Requested)
364
521
 
365
522
  **⚠️ IMPORTANT**: The following customizations should only be implemented when the user explicitly requests them. A basic dashboard page does not require these advanced features.
366
523
 
@@ -373,3 +530,10 @@ For advanced customization options when specifically requested, refer to these s
373
530
  - "Custom Overrides" - For column overrides and custom components
374
531
 
375
532
  By following these steps, you'll successfully implement a custom data source that integrates seamlessly with AutoPatternsApp while leveraging Wix Business APIs through their FQDNs.
533
+
534
+ ## 12) See also
535
+
536
+ - `schema_config.md` – Full `SchemaConfig` interface and field types
537
+ - `auto-patterns-guide.md` – End-to-end Auto-Patterns overview
538
+
539
+