@nitrogenbuilder/connector-payload 0.1.34 → 0.1.35

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 (38) hide show
  1. package/dist/collections/NitrogenComponentCatalog.d.ts +2 -0
  2. package/dist/collections/NitrogenComponentCatalog.js +44 -0
  3. package/dist/collections/NitrogenComponentUsage.d.ts +2 -0
  4. package/dist/collections/NitrogenComponentUsage.js +81 -0
  5. package/dist/components/LockedJsonField.d.ts +2 -9
  6. package/dist/components/LockedJsonField.js +7 -6
  7. package/dist/components/LockedJsonFieldRuntime.d.ts +3 -7
  8. package/dist/components/LockedJsonFieldRuntime.js +21 -22
  9. package/dist/components/NitrogenComponentInventoryClient.d.ts +13 -0
  10. package/dist/components/NitrogenComponentInventoryClient.js +309 -0
  11. package/dist/components/NitrogenComponentInventoryField.d.ts +3 -0
  12. package/dist/components/NitrogenComponentInventoryField.js +26 -0
  13. package/dist/components/NitrogenComponentInventoryNavLink.d.ts +1 -0
  14. package/dist/components/NitrogenComponentInventoryNavLink.js +75 -0
  15. package/dist/components/NitrogenComponentInventoryReindexButton.d.ts +1 -0
  16. package/dist/components/NitrogenComponentInventoryReindexButton.js +91 -0
  17. package/dist/components/NitrogenComponentInventoryView.d.ts +2 -0
  18. package/dist/components/NitrogenComponentInventoryView.js +28 -0
  19. package/dist/components/NitrogenDataViewer.d.ts +2 -2
  20. package/dist/components/NitrogenDataViewer.js +7 -6
  21. package/dist/components/NitrogenDataViewerRuntime.d.ts +6 -2
  22. package/dist/components/NitrogenDataViewerRuntime.js +24 -40
  23. package/dist/components/NitrogenNavGroup.d.ts +1 -0
  24. package/dist/components/NitrogenNavGroup.js +74 -0
  25. package/dist/editor/NitrogenEditorPage.d.ts +1 -2
  26. package/dist/endpoints/component-inventory.d.ts +6 -0
  27. package/dist/endpoints/component-inventory.js +20 -0
  28. package/dist/frontend/NitrogenWrapper.d.ts +1 -2
  29. package/dist/globals/NitrogenComponents.d.ts +2 -0
  30. package/dist/globals/NitrogenComponents.js +22 -0
  31. package/dist/index.d.ts +12 -2
  32. package/dist/index.js +94 -3
  33. package/dist/inventory/indexing.d.ts +31 -0
  34. package/dist/inventory/indexing.js +230 -0
  35. package/dist/inventory/manifest.d.ts +3 -0
  36. package/dist/inventory/manifest.js +22 -0
  37. package/dist/types.d.ts +35 -1
  38. package/package.json +7 -2
package/dist/index.js CHANGED
@@ -1,5 +1,8 @@
1
1
  import { NitrogenTemplates } from "./collections/NitrogenTemplates";
2
+ import { NitrogenComponentCatalog } from './collections/NitrogenComponentCatalog';
3
+ import { NitrogenComponentUsage } from './collections/NitrogenComponentUsage';
2
4
  import { NitrogenSettings } from "./globals/NitrogenSettings";
5
+ import { NitrogenComponents } from './globals/NitrogenComponents';
3
6
  import { templatesEndpoints } from "./endpoints/templates";
4
7
  import { mediaEndpoints } from "./endpoints/media";
5
8
  import { nitrogenSettingsEndpoints } from "./endpoints/nitrogen-settings";
@@ -7,8 +10,10 @@ import { allEndpoints } from "./endpoints/all";
7
10
  import { collectionsEndpoints } from "./endpoints/collections";
8
11
  import { menuEndpoints } from "./endpoints/menu";
9
12
  import { createCollectionEndpoints } from "./endpoints/collection-endpoints";
13
+ import { createComponentInventoryEndpoints } from './endpoints/component-inventory';
10
14
  import { batchEndpoints } from "./endpoints/batch";
11
15
  import { registerCollection } from "./collection-registry";
16
+ import { deleteDocumentUsage, reindexDocumentUsage, syncComponentCatalog, } from './inventory/indexing';
12
17
  /** Fields required by Nitrogen that will be injected into collections if missing */
13
18
  const nitrogenRequiredFields = [
14
19
  {
@@ -37,10 +42,48 @@ export const nitrogenConnectorPlugin = (options = {}) => (incomingConfig) => {
37
42
  return incomingConfig;
38
43
  }
39
44
  const config = { ...incomingConfig };
45
+ const inventoryCollections = Array.from(new Set([
46
+ ...(options.collections || []),
47
+ ...(options.indexCollections || []),
48
+ 'nitrogen-templates',
49
+ ]));
50
+ const createAfterChangeHook = (collectionSlug) => {
51
+ return async ({ doc, req }) => {
52
+ if (doc) {
53
+ await reindexDocumentUsage(req.payload, collectionSlug, doc, collectionSlug === 'nitrogen-templates' ? 'template' : 'document');
54
+ }
55
+ return doc;
56
+ };
57
+ };
58
+ const createAfterDeleteHook = (collectionSlug) => {
59
+ return async ({ doc, id, req, }) => {
60
+ const sourceId = doc?.id ?? id;
61
+ if (sourceId !== undefined) {
62
+ await deleteDocumentUsage(req.payload, collectionSlug, sourceId);
63
+ }
64
+ return doc;
65
+ };
66
+ };
67
+ const withInventoryHooks = (collection, collectionSlug) => {
68
+ const hooks = collection.hooks || {};
69
+ return {
70
+ ...collection,
71
+ hooks: {
72
+ ...hooks,
73
+ afterChange: [...(hooks.afterChange || []), createAfterChangeHook(collectionSlug)],
74
+ afterDelete: [...(hooks.afterDelete || []), createAfterDeleteHook(collectionSlug)],
75
+ },
76
+ };
77
+ };
40
78
  // Add Nitrogen templates collection
41
- config.collections = [...(config.collections || []), NitrogenTemplates];
42
- // Add Nitrogen global settings
43
- config.globals = [...(config.globals || []), NitrogenSettings];
79
+ config.collections = [
80
+ ...(config.collections || []),
81
+ withInventoryHooks(NitrogenTemplates, 'nitrogen-templates'),
82
+ NitrogenComponentCatalog,
83
+ NitrogenComponentUsage,
84
+ ];
85
+ // Add Nitrogen globals
86
+ config.globals = [...(config.globals || []), NitrogenSettings, NitrogenComponents];
44
87
  // Add Nitrogen API endpoints
45
88
  config.endpoints = [
46
89
  ...(config.endpoints || []),
@@ -51,7 +94,45 @@ export const nitrogenConnectorPlugin = (options = {}) => (incomingConfig) => {
51
94
  ...collectionsEndpoints,
52
95
  ...menuEndpoints,
53
96
  ...batchEndpoints,
97
+ ...createComponentInventoryEndpoints({
98
+ collections: inventoryCollections,
99
+ componentManifest: options.componentManifest,
100
+ }),
54
101
  ];
102
+ const existingOnInit = config.onInit;
103
+ config.onInit = async (payload) => {
104
+ if (existingOnInit) {
105
+ await existingOnInit(payload);
106
+ }
107
+ try {
108
+ await syncComponentCatalog(payload, options.componentManifest);
109
+ }
110
+ catch (error) {
111
+ payload.logger.error(`[@nitrogenbuilder/connector-payload] Failed to sync component catalog: ${error instanceof Error ? error.message : String(error)}`);
112
+ }
113
+ for (const slug of ['nitrogen-components']) {
114
+ try {
115
+ await payload.findGlobal({
116
+ slug,
117
+ depth: 0,
118
+ overrideAccess: true,
119
+ });
120
+ }
121
+ catch {
122
+ try {
123
+ await payload.updateGlobal({
124
+ slug,
125
+ data: {},
126
+ depth: 0,
127
+ overrideAccess: true,
128
+ });
129
+ }
130
+ catch (error) {
131
+ payload.logger.warn(`[@nitrogenbuilder/connector-payload] Could not initialize global "${slug}": ${error instanceof Error ? error.message : String(error)}`);
132
+ }
133
+ }
134
+ }
135
+ };
55
136
  // Register templates collection
56
137
  registerCollection("nitrogen-templates", "nitrogen-templates", "/nitrogen-templates/[slug]");
57
138
  registerCollection("nitrogen_template", "nitrogen-templates", "/nitrogen-templates/[slug]");
@@ -133,6 +214,16 @@ export const nitrogenConnectorPlugin = (options = {}) => (incomingConfig) => {
133
214
  // Register in the collection registry for the `all` endpoint
134
215
  registerCollection(slug, slug, routePattern);
135
216
  }
217
+ for (const slug of inventoryCollections) {
218
+ if (slug === 'nitrogen-templates')
219
+ continue;
220
+ const existingIndex = (config.collections || []).findIndex((collection) => collection.slug === slug);
221
+ if (existingIndex === -1) {
222
+ console.warn(`[@nitrogenbuilder/connector-payload] Index collection "${slug}" not found in config.`);
223
+ continue;
224
+ }
225
+ config.collections[existingIndex] = withInventoryHooks(config.collections[existingIndex], slug);
226
+ }
136
227
  return config;
137
228
  };
138
229
  // Re-export for consumers who need direct access
@@ -0,0 +1,31 @@
1
+ import type { ComponentManifestEntry } from '@nitrogenbuilder/types';
2
+ import type { Payload, Where } from 'payload';
3
+ import type { NitrogenInventorySourceDoc } from '../types';
4
+ import { type NitrogenComponentManifestInput } from './manifest';
5
+ export declare const NITROGEN_COMPONENT_CATALOG_COLLECTION = "nitrogen-component-catalog";
6
+ export declare const NITROGEN_COMPONENT_USAGE_COLLECTION = "nitrogen-component-usage";
7
+ type ComponentUsageRecord = {
8
+ componentName: string;
9
+ depth: number;
10
+ moduleId: string;
11
+ modulePath: string;
12
+ parentComponentName?: string;
13
+ parentModuleId?: string;
14
+ parentModulePath?: string;
15
+ };
16
+ type ReindexResult = {
17
+ catalogCount: number;
18
+ documentCount: number;
19
+ usageCount: number;
20
+ };
21
+ export declare function extractComponentUsageRecords(modules: unknown): ComponentUsageRecord[];
22
+ export declare function findAllDocs<T extends object>(payload: Payload, collection: string, options?: {
23
+ limit?: number;
24
+ select?: Record<string, true>;
25
+ where?: Where;
26
+ }): Promise<T[]>;
27
+ export declare function syncComponentCatalog(payload: Payload, manifestInput?: NitrogenComponentManifestInput): Promise<ComponentManifestEntry[]>;
28
+ export declare function reindexDocumentUsage(payload: Payload, sourceCollection: string, doc: NitrogenInventorySourceDoc, sourceType?: 'document' | 'template'): Promise<number>;
29
+ export declare function deleteDocumentUsage(payload: Payload, sourceCollection: string, sourceDocumentId: string | number): Promise<void>;
30
+ export declare function reindexAllComponentInventory(payload: Payload, collections: string[], manifestInput?: NitrogenComponentManifestInput): Promise<ReindexResult>;
31
+ export {};
@@ -0,0 +1,230 @@
1
+ import { resolveComponentManifest, } from './manifest';
2
+ export const NITROGEN_COMPONENT_CATALOG_COLLECTION = 'nitrogen-component-catalog';
3
+ export const NITROGEN_COMPONENT_USAGE_COLLECTION = 'nitrogen-component-usage';
4
+ function moduleNameFromNode(node) {
5
+ const value = node.module;
6
+ if (typeof value === 'string')
7
+ return value;
8
+ if (value && typeof value === 'object' && typeof value.name === 'string') {
9
+ return String(value.name);
10
+ }
11
+ return null;
12
+ }
13
+ function collectUsageFromTree(modules, pathPrefix, results, parentContext, depth = 0) {
14
+ if (!Array.isArray(modules))
15
+ return;
16
+ modules.forEach((maybeNode, index) => {
17
+ if (!maybeNode || typeof maybeNode !== 'object')
18
+ return;
19
+ const node = maybeNode;
20
+ const modulePath = `${pathPrefix}[${index}]`;
21
+ const componentName = moduleNameFromNode(node);
22
+ const moduleId = typeof node.id === 'string' || typeof node.id === 'number'
23
+ ? String(node.id)
24
+ : modulePath;
25
+ const currentContext = componentName
26
+ ? {
27
+ componentName,
28
+ moduleId,
29
+ modulePath,
30
+ }
31
+ : parentContext;
32
+ if (componentName) {
33
+ results.push({
34
+ componentName,
35
+ depth,
36
+ moduleId,
37
+ modulePath,
38
+ parentComponentName: parentContext?.componentName,
39
+ parentModuleId: parentContext?.moduleId,
40
+ parentModulePath: parentContext?.modulePath,
41
+ });
42
+ }
43
+ const props = node.props;
44
+ if (props && typeof props === 'object') {
45
+ const children = props.children;
46
+ if (Array.isArray(children)) {
47
+ collectUsageFromTree(children, `${modulePath}.props.children`, results, currentContext, depth + 1);
48
+ }
49
+ else if (children && typeof children === 'object') {
50
+ for (const [slotName, slotChildren] of Object.entries(children)) {
51
+ collectUsageFromTree(slotChildren, `${modulePath}.props.children.${slotName}`, results, currentContext, depth + 1);
52
+ }
53
+ }
54
+ }
55
+ if (Array.isArray(node.children)) {
56
+ collectUsageFromTree(node.children, `${modulePath}.children`, results, currentContext, depth + 1);
57
+ }
58
+ });
59
+ }
60
+ export function extractComponentUsageRecords(modules) {
61
+ const results = [];
62
+ collectUsageFromTree(modules, 'modules', results);
63
+ return results;
64
+ }
65
+ export async function findAllDocs(payload, collection, options) {
66
+ const docs = [];
67
+ let page = 1;
68
+ let hasNextPage = true;
69
+ while (hasNextPage) {
70
+ const result = await payload.find({
71
+ collection: collection,
72
+ depth: 0,
73
+ limit: options?.limit ?? 200,
74
+ page,
75
+ overrideAccess: true,
76
+ pagination: true,
77
+ select: options?.select,
78
+ where: options?.where,
79
+ });
80
+ docs.push(...result.docs);
81
+ hasNextPage = Boolean(result.hasNextPage);
82
+ page += 1;
83
+ }
84
+ return docs;
85
+ }
86
+ async function deleteUsageDocs(payload, docs) {
87
+ for (const doc of docs) {
88
+ await payload.delete({
89
+ collection: NITROGEN_COMPONENT_USAGE_COLLECTION,
90
+ id: doc.id,
91
+ overrideAccess: true,
92
+ });
93
+ }
94
+ }
95
+ async function findUsageDocsForSource(payload, sourceCollection, sourceDocumentId) {
96
+ return findAllDocs(payload, NITROGEN_COMPONENT_USAGE_COLLECTION, {
97
+ limit: 100,
98
+ select: {
99
+ id: true,
100
+ },
101
+ where: {
102
+ and: [
103
+ {
104
+ sourceCollection: {
105
+ equals: sourceCollection,
106
+ },
107
+ },
108
+ {
109
+ sourceDocumentId: {
110
+ equals: sourceDocumentId,
111
+ },
112
+ },
113
+ ],
114
+ },
115
+ });
116
+ }
117
+ async function createUsageDocs(payload, sourceCollection, sourceType, doc) {
118
+ const sourceDocumentId = String(doc.id);
119
+ const usageRecords = extractComponentUsageRecords(doc.nitrogenData);
120
+ for (const record of usageRecords) {
121
+ await payload.create({
122
+ collection: NITROGEN_COMPONENT_USAGE_COLLECTION,
123
+ overrideAccess: true,
124
+ data: {
125
+ usageKey: `${sourceCollection}:${sourceDocumentId}:${record.moduleId}:${record.modulePath}:${record.componentName}`,
126
+ componentName: record.componentName,
127
+ depth: record.depth,
128
+ sourceCollection,
129
+ sourceType,
130
+ sourceDocumentId,
131
+ sourceTitle: doc.title || '',
132
+ sourceSlug: doc.slug || '',
133
+ sourceStatus: doc.status || doc._status || '',
134
+ moduleId: record.moduleId,
135
+ modulePath: record.modulePath,
136
+ parentComponentName: record.parentComponentName || '',
137
+ parentModuleId: record.parentModuleId || '',
138
+ parentModulePath: record.parentModulePath || '',
139
+ },
140
+ });
141
+ }
142
+ return usageRecords.length;
143
+ }
144
+ export async function syncComponentCatalog(payload, manifestInput) {
145
+ const manifest = await resolveComponentManifest(manifestInput);
146
+ const entries = manifest.components || [];
147
+ const existingDocs = await findAllDocs(payload, NITROGEN_COMPONENT_CATALOG_COLLECTION);
148
+ const existingByName = new Map(existingDocs.map((doc) => [doc.componentName, doc]));
149
+ const nextNames = new Set(entries.map((entry) => entry.name));
150
+ for (const entry of entries) {
151
+ const existing = existingByName.get(entry.name);
152
+ const data = {
153
+ componentName: entry.name,
154
+ scope: entry.scope || '',
155
+ sidebarCategory: entry.sidebarCategory || '',
156
+ icon: entry.icon || '',
157
+ definition: entry,
158
+ source: manifest.source || '',
159
+ };
160
+ if (existing) {
161
+ await payload.update({
162
+ collection: NITROGEN_COMPONENT_CATALOG_COLLECTION,
163
+ id: existing.id,
164
+ data,
165
+ overrideAccess: true,
166
+ });
167
+ }
168
+ else {
169
+ await payload.create({
170
+ collection: NITROGEN_COMPONENT_CATALOG_COLLECTION,
171
+ data,
172
+ overrideAccess: true,
173
+ });
174
+ }
175
+ }
176
+ for (const existing of existingDocs) {
177
+ if (!nextNames.has(existing.componentName)) {
178
+ await payload.delete({
179
+ collection: NITROGEN_COMPONENT_CATALOG_COLLECTION,
180
+ id: existing.id,
181
+ overrideAccess: true,
182
+ });
183
+ }
184
+ }
185
+ return entries;
186
+ }
187
+ export async function reindexDocumentUsage(payload, sourceCollection, doc, sourceType = 'document') {
188
+ const sourceDocumentId = String(doc.id);
189
+ const docsForSource = await findUsageDocsForSource(payload, sourceCollection, sourceDocumentId);
190
+ await deleteUsageDocs(payload, docsForSource);
191
+ return createUsageDocs(payload, sourceCollection, sourceType, doc);
192
+ }
193
+ export async function deleteDocumentUsage(payload, sourceCollection, sourceDocumentId) {
194
+ const docsForSource = await findUsageDocsForSource(payload, sourceCollection, String(sourceDocumentId));
195
+ await deleteUsageDocs(payload, docsForSource);
196
+ }
197
+ export async function reindexAllComponentInventory(payload, collections, manifestInput) {
198
+ const entries = await syncComponentCatalog(payload, manifestInput);
199
+ const usageDocs = await findAllDocs(payload, NITROGEN_COMPONENT_USAGE_COLLECTION, {
200
+ limit: 200,
201
+ select: {
202
+ id: true,
203
+ },
204
+ });
205
+ await deleteUsageDocs(payload, usageDocs);
206
+ let documentCount = 0;
207
+ let usageCount = 0;
208
+ for (const collection of collections) {
209
+ const docs = await findAllDocs(payload, collection, {
210
+ limit: 100,
211
+ select: {
212
+ id: true,
213
+ title: true,
214
+ slug: true,
215
+ status: true,
216
+ _status: true,
217
+ nitrogenData: true,
218
+ },
219
+ });
220
+ for (const doc of docs) {
221
+ documentCount += 1;
222
+ usageCount += await createUsageDocs(payload, collection, collection === 'nitrogen-templates' ? 'template' : 'document', doc);
223
+ }
224
+ }
225
+ return {
226
+ catalogCount: entries.length,
227
+ documentCount,
228
+ usageCount,
229
+ };
230
+ }
@@ -0,0 +1,3 @@
1
+ import type { ComponentManifest, ComponentManifestEntry } from '@nitrogenbuilder/types';
2
+ export type NitrogenComponentManifestInput = ComponentManifest | ComponentManifestEntry[] | (() => Promise<ComponentManifest | ComponentManifestEntry[]> | ComponentManifest | ComponentManifestEntry[]);
3
+ export declare function resolveComponentManifest(input?: NitrogenComponentManifestInput): Promise<ComponentManifest>;
@@ -0,0 +1,22 @@
1
+ export async function resolveComponentManifest(input) {
2
+ if (!input) {
3
+ return {
4
+ components: [],
5
+ generatedAt: new Date().toISOString(),
6
+ source: 'empty',
7
+ };
8
+ }
9
+ const resolved = typeof input === 'function' ? await input() : input;
10
+ if (Array.isArray(resolved)) {
11
+ return {
12
+ components: resolved,
13
+ generatedAt: new Date().toISOString(),
14
+ source: 'array',
15
+ };
16
+ }
17
+ return {
18
+ components: resolved.components || [],
19
+ generatedAt: resolved.generatedAt || new Date().toISOString(),
20
+ source: resolved.source,
21
+ };
22
+ }
package/dist/types.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * Document interfaces matching the Payload collection/global schemas,
5
5
  * plus request body shapes used by the API endpoints.
6
6
  */
7
- import type { BuilderModule } from '@nitrogenbuilder/types';
7
+ import type { BuilderModule, ComponentManifestEntry } from '@nitrogenbuilder/types';
8
8
  export type JsonObject = Record<string, unknown>;
9
9
  export type NitrogenModule = BuilderModule;
10
10
  interface NitrogenDocBase {
@@ -128,4 +128,38 @@ export interface RenderDataRequestBody {
128
128
  /** Which Payload collection to fetch dynamic data from */
129
129
  collection?: string;
130
130
  }
131
+ export interface NitrogenComponentCatalogDoc {
132
+ id: string | number;
133
+ componentName: string;
134
+ scope?: string;
135
+ sidebarCategory?: string;
136
+ icon?: string;
137
+ definition?: ComponentManifestEntry | JsonObject;
138
+ source?: string;
139
+ }
140
+ export interface NitrogenComponentUsageDoc {
141
+ id: string | number;
142
+ usageKey: string;
143
+ componentName: string;
144
+ depth?: number;
145
+ sourceCollection: string;
146
+ sourceType: string;
147
+ sourceDocumentId: string;
148
+ sourceTitle?: string;
149
+ sourceSlug?: string;
150
+ sourceStatus?: string;
151
+ moduleId?: string;
152
+ modulePath: string;
153
+ parentComponentName?: string;
154
+ parentModuleId?: string;
155
+ parentModulePath?: string;
156
+ }
157
+ export interface NitrogenInventorySourceDoc {
158
+ id: string | number;
159
+ title?: string;
160
+ slug?: string;
161
+ status?: string;
162
+ _status?: string;
163
+ nitrogenData?: JsonObject | JsonObject[];
164
+ }
131
165
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitrogenbuilder/connector-payload",
3
- "version": "0.1.34",
3
+ "version": "0.1.35",
4
4
  "description": "Nitrogen page builder connector plugin for Payload CMS 3.x",
5
5
  "author": "Leonardo Dentzien <leo@torchmedia.ca>",
6
6
  "type": "module",
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "peerDependencies": {
37
37
  "payload": "^3.0.0",
38
- "next": "^15.0.0",
38
+ "next": "^15.0.0 || ^16.0.0",
39
39
  "react": "^19.0.0",
40
40
  "@payloadcms/ui": "^3.0.0",
41
41
  "@nitrogenbuilder/client-react": ">=0.3.0",
@@ -43,8 +43,13 @@
43
43
  "@nitrogenbuilder/types": ">=0.3.0"
44
44
  },
45
45
  "devDependencies": {
46
+ "@payloadcms/ui": "3.83.0",
47
+ "next": "16.2.4",
48
+ "payload": "3.83.0",
46
49
  "@types/react": "^19.0.0",
47
50
  "@types/node": "^22.0.0",
51
+ "react": "19.2.5",
52
+ "react-dom": "19.2.5",
48
53
  "typescript": "^5.7.0",
49
54
  "@nitrogenbuilder/client-react": "link:../monogen/packages/client-react",
50
55
  "@nitrogenbuilder/client-core": "link:../monogen/packages/client-core",