@memberjunction/metadata-sync 2.111.1 → 2.113.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/README.md +86 -11
- package/dist/constants/metadata-keywords.d.ts +282 -0
- package/dist/constants/metadata-keywords.js +364 -0
- package/dist/constants/metadata-keywords.js.map +1 -0
- package/dist/lib/FieldExternalizer.js +5 -4
- package/dist/lib/FieldExternalizer.js.map +1 -1
- package/dist/lib/RecordProcessor.js +5 -4
- package/dist/lib/RecordProcessor.js.map +1 -1
- package/dist/lib/json-preprocessor.js +7 -6
- package/dist/lib/json-preprocessor.js.map +1 -1
- package/dist/lib/record-dependency-analyzer.js +18 -17
- package/dist/lib/record-dependency-analyzer.js.map +1 -1
- package/dist/lib/sync-engine.js +22 -26
- package/dist/lib/sync-engine.js.map +1 -1
- package/dist/services/ValidationService.js +28 -40
- package/dist/services/ValidationService.js.map +1 -1
- package/dist/types/validation.d.ts +6 -1
- package/dist/types/validation.js.map +1 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -828,13 +828,16 @@ Support environment-specific values:
|
|
|
828
828
|
- `@env:VARIABLE_NAME`
|
|
829
829
|
- Useful for different environments (dev/staging/prod)
|
|
830
830
|
|
|
831
|
-
### Automatic JSON Stringification
|
|
832
|
-
When a field value is an array or object, the tool automatically converts it to a JSON string for database storage:
|
|
833
|
-
- Arrays and objects are detected and stringified with pretty formatting (2-space indentation)
|
|
834
|
-
- Maintains clean, readable JSON in source files while storing as strings in database
|
|
835
|
-
- Works seamlessly with all field types that accept text content
|
|
831
|
+
### Automatic JSON Stringification with Reference Processing
|
|
836
832
|
|
|
837
|
-
|
|
833
|
+
When a field value is an array or object, the tool automatically:
|
|
834
|
+
1. **Recursively processes** all `@lookup:`, `@file:`, `@parent:`, `@root:` references inside the object
|
|
835
|
+
2. **Converts to JSON string** with pretty formatting (2-space indentation) for database storage
|
|
836
|
+
3. **Maintains clean structure** in source files while storing as strings in database
|
|
837
|
+
|
|
838
|
+
This is extremely powerful for JSON-typed fields like `Configuration`, `Settings`, `Metadata`, etc.
|
|
839
|
+
|
|
840
|
+
#### Basic Example
|
|
838
841
|
```json
|
|
839
842
|
{
|
|
840
843
|
"fields": {
|
|
@@ -846,16 +849,88 @@ Examples:
|
|
|
846
849
|
"items": [1, 2, 3]
|
|
847
850
|
}
|
|
848
851
|
},
|
|
849
|
-
"Tags": ["tag1", "tag2", "tag3"]
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
852
|
+
"Tags": ["tag1", "tag2", "tag3"]
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
The `Configuration` and `Tags` fields will automatically be converted to JSON strings when pushed to the database.
|
|
858
|
+
|
|
859
|
+
#### Advanced Example: References Inside JSON Fields
|
|
860
|
+
|
|
861
|
+
**This is the powerful part** - you can use `@lookup:` and other references INSIDE object-typed fields:
|
|
862
|
+
|
|
863
|
+
```json
|
|
864
|
+
{
|
|
865
|
+
"fields": {
|
|
866
|
+
"Name": "Agent Memory Manager Job",
|
|
867
|
+
"CronExpression": "0 */15 * * * *",
|
|
868
|
+
"Configuration": {
|
|
869
|
+
"AgentID": "@lookup:AI Agents.Name=Memory Manager",
|
|
870
|
+
"InitialMessage": "Analyze recent conversations",
|
|
871
|
+
"Settings": {
|
|
872
|
+
"MaxNotes": 5,
|
|
873
|
+
"Strategy": "Relevant",
|
|
874
|
+
"TargetAgentID": "@lookup:AI Agents.Name=Sage"
|
|
875
|
+
}
|
|
853
876
|
}
|
|
854
877
|
}
|
|
855
878
|
}
|
|
856
879
|
```
|
|
857
880
|
|
|
858
|
-
|
|
881
|
+
When pushed to the database, this becomes:
|
|
882
|
+
```json
|
|
883
|
+
{
|
|
884
|
+
"Configuration": "{\"AgentID\":\"actual-uuid-here\",\"InitialMessage\":\"Analyze recent conversations\",\"Settings\":{\"MaxNotes\":5,\"Strategy\":\"Relevant\",\"TargetAgentID\":\"another-uuid-here\"}}"
|
|
885
|
+
}
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
**Benefits:**
|
|
889
|
+
- ✅ **Human-readable**: Use agent names, not UUIDs in your metadata
|
|
890
|
+
- ✅ **Maintainable**: Changes to entity names don't break references
|
|
891
|
+
- ✅ **Type-safe**: Structured objects in source, properly stringified for DB
|
|
892
|
+
- ✅ **Nested support**: References work at any depth in the object tree
|
|
893
|
+
|
|
894
|
+
#### Common Use Cases
|
|
895
|
+
|
|
896
|
+
**Scheduled Job Configuration:**
|
|
897
|
+
```json
|
|
898
|
+
{
|
|
899
|
+
"Configuration": {
|
|
900
|
+
"AgentID": "@lookup:AI Agents.Name=Report Generator",
|
|
901
|
+
"Schedule": "daily",
|
|
902
|
+
"Recipients": "@lookup:Users.Email=admin@company.com"
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
**Action Parameters:**
|
|
908
|
+
```json
|
|
909
|
+
{
|
|
910
|
+
"DefaultParameters": {
|
|
911
|
+
"TargetEntityID": "@lookup:Entities.Name=Customers",
|
|
912
|
+
"TemplateID": "@lookup:Templates.Name=Welcome Email",
|
|
913
|
+
"Settings": {
|
|
914
|
+
"SendImmediate": true,
|
|
915
|
+
"Priority": "High"
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
**AI Configuration:**
|
|
922
|
+
```json
|
|
923
|
+
{
|
|
924
|
+
"AIConfig": {
|
|
925
|
+
"PreferredModelID": "@lookup:AI Models.Name=GPT 4.1",
|
|
926
|
+
"FallbackModels": [
|
|
927
|
+
"@lookup:AI Models.Name=Claude Sonnet 3.7",
|
|
928
|
+
"@lookup:AI Models.Name=Gemini Pro"
|
|
929
|
+
],
|
|
930
|
+
"Temperature": 0.7
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
```
|
|
859
934
|
|
|
860
935
|
### {@include} References in Files
|
|
861
936
|
Enable content composition within non-JSON files (like .md, .html, .txt) using JSDoc-style include syntax:
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized metadata keyword constants for MemberJunction MetadataSync package.
|
|
3
|
+
*
|
|
4
|
+
* These keywords are special prefixes used in metadata JSON files to reference external
|
|
5
|
+
* content, perform lookups, access environment variables, and establish hierarchical relationships.
|
|
6
|
+
*
|
|
7
|
+
* @module metadata-keywords
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // Using @file: to reference external content
|
|
11
|
+
* {
|
|
12
|
+
* "Prompt": "@file:greeting.prompt.md"
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // Using @lookup: to find an entity by field value
|
|
17
|
+
* {
|
|
18
|
+
* "CategoryID": "@lookup:AI Prompt Categories.Name=Examples"
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // Using @parent: to reference parent entity fields
|
|
23
|
+
* {
|
|
24
|
+
* "PromptID": "@parent:ID"
|
|
25
|
+
* }
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Metadata keyword constants.
|
|
29
|
+
* These are the special @ prefixes recognized by MetadataSync for field value processing.
|
|
30
|
+
*/
|
|
31
|
+
export declare const METADATA_KEYWORDS: {
|
|
32
|
+
/**
|
|
33
|
+
* @file: - Loads content from an external file
|
|
34
|
+
*
|
|
35
|
+
* Reads the contents of a file (relative to the JSON metadata file) and uses it as the field value.
|
|
36
|
+
* Supports text files, markdown, JSON, and other formats.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* "@file:greeting.prompt.md"
|
|
40
|
+
* "@file:./shared/common-prompt.md"
|
|
41
|
+
* "@file:../templates/standard-header.md"
|
|
42
|
+
*/
|
|
43
|
+
readonly FILE: "@file:";
|
|
44
|
+
/**
|
|
45
|
+
* @lookup: - Looks up an entity record by field value(s)
|
|
46
|
+
*
|
|
47
|
+
* Finds an entity record matching the specified criteria and uses its ID.
|
|
48
|
+
* Supports single-field and multi-field lookups, with optional auto-creation.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* "@lookup:AI Prompt Types.Name=Chat"
|
|
52
|
+
* "@lookup:Users.Email=john@example.com&Department=Sales"
|
|
53
|
+
* "@lookup:Categories.Name=Examples?create"
|
|
54
|
+
* "@lookup:Categories.Name=Examples?create&Description=Example prompts"
|
|
55
|
+
*/
|
|
56
|
+
readonly LOOKUP: "@lookup:";
|
|
57
|
+
/**
|
|
58
|
+
* @parent: - References a field from the parent entity
|
|
59
|
+
*
|
|
60
|
+
* In nested/related entity structures, accesses a field value from the immediate parent record.
|
|
61
|
+
* Only valid when processing nested entities that have a parent context.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* "@parent:ID"
|
|
65
|
+
* "@parent:Name"
|
|
66
|
+
* "@parent:CategoryID"
|
|
67
|
+
*/
|
|
68
|
+
readonly PARENT: "@parent:";
|
|
69
|
+
/**
|
|
70
|
+
* @root: - References a field from the root entity
|
|
71
|
+
*
|
|
72
|
+
* In nested/related entity structures, accesses a field value from the top-level root record.
|
|
73
|
+
* Only valid when processing nested entities that have a root context.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* "@root:ID"
|
|
77
|
+
* "@root:Name"
|
|
78
|
+
*/
|
|
79
|
+
readonly ROOT: "@root:";
|
|
80
|
+
/**
|
|
81
|
+
* @env: - Reads an environment variable
|
|
82
|
+
*
|
|
83
|
+
* Gets the value of an environment variable at runtime.
|
|
84
|
+
* Useful for configuration values that differ between environments.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* "@env:VARIABLE_NAME"
|
|
88
|
+
* "@env:NODE_ENV"
|
|
89
|
+
*/
|
|
90
|
+
readonly ENV: "@env:";
|
|
91
|
+
/**
|
|
92
|
+
* @url: - Fetches content from a URL
|
|
93
|
+
*
|
|
94
|
+
* Downloads content from a remote URL and uses it as the field value.
|
|
95
|
+
* Supports HTTP/HTTPS URLs and file:// URLs.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* "@url:https://example.com/prompts/greeting.md"
|
|
99
|
+
* "@url:https://raw.githubusercontent.com/company/prompts/main/customer.md"
|
|
100
|
+
*/
|
|
101
|
+
readonly URL: "@url:";
|
|
102
|
+
/**
|
|
103
|
+
* @template: - Loads a template JSON file
|
|
104
|
+
*
|
|
105
|
+
* Loads a JSON template file and uses its contents, replacing any template variables.
|
|
106
|
+
* Useful for standardizing common configurations across multiple records.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* "@template:templates/standard-ai-models.json"
|
|
110
|
+
*/
|
|
111
|
+
readonly TEMPLATE: "@template:";
|
|
112
|
+
/**
|
|
113
|
+
* @include or @include.* - Includes content from another file
|
|
114
|
+
*
|
|
115
|
+
* Special directive (not a field value) that merges content from external files.
|
|
116
|
+
* Can be used in both objects and arrays. Supports spread and property modes.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* { "@include": "common-fields.json" }
|
|
120
|
+
* [ "@include:items.json" ]
|
|
121
|
+
* { "@include.models": { "file": "models.json", "mode": "property" } }
|
|
122
|
+
*/
|
|
123
|
+
readonly INCLUDE: "@include";
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Type representing all metadata keyword values.
|
|
127
|
+
*/
|
|
128
|
+
export type MetadataKeyword = typeof METADATA_KEYWORDS[keyof typeof METADATA_KEYWORDS];
|
|
129
|
+
/**
|
|
130
|
+
* Type representing metadata keyword types (without the colon for keywords that have it).
|
|
131
|
+
*/
|
|
132
|
+
export type MetadataKeywordType = 'file' | 'lookup' | 'parent' | 'root' | 'env' | 'url' | 'template' | 'include';
|
|
133
|
+
/**
|
|
134
|
+
* Array of all metadata keyword prefixes for iteration.
|
|
135
|
+
* This array maintains the order of keywords for consistent processing.
|
|
136
|
+
*/
|
|
137
|
+
export declare const METADATA_KEYWORD_PREFIXES: ReadonlyArray<string>;
|
|
138
|
+
/**
|
|
139
|
+
* Checks if a value is a string that starts with any recognized metadata keyword.
|
|
140
|
+
*
|
|
141
|
+
* This is a type-safe check that handles non-string values gracefully.
|
|
142
|
+
* Returns false for null, undefined, objects, numbers, etc.
|
|
143
|
+
*
|
|
144
|
+
* @param value - The value to check (can be any type)
|
|
145
|
+
* @returns true if value is a string starting with a metadata keyword, false otherwise
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* isMetadataKeyword('@file:template.md') // true
|
|
149
|
+
* isMetadataKeyword('@lookup:Users.Email=test@example.com') // true
|
|
150
|
+
* isMetadataKeyword('@parent:ID') // true
|
|
151
|
+
* isMetadataKeyword('regular string') // false
|
|
152
|
+
* isMetadataKeyword(123) // false
|
|
153
|
+
* isMetadataKeyword(null) // false
|
|
154
|
+
* isMetadataKeyword('@unknown:value') // false
|
|
155
|
+
*/
|
|
156
|
+
export declare function isMetadataKeyword(value: unknown): value is string;
|
|
157
|
+
/**
|
|
158
|
+
* Determines which metadata keyword type a string value uses.
|
|
159
|
+
*
|
|
160
|
+
* Examines the prefix of a string and returns the corresponding keyword type.
|
|
161
|
+
* Returns null if the value doesn't use any recognized metadata keyword.
|
|
162
|
+
*
|
|
163
|
+
* @param value - The string value to analyze
|
|
164
|
+
* @returns The keyword type ('file', 'lookup', etc.) or null if no keyword is found
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* getMetadataKeywordType('@file:template.md') // 'file'
|
|
168
|
+
* getMetadataKeywordType('@lookup:Users.Name=John') // 'lookup'
|
|
169
|
+
* getMetadataKeywordType('@parent:ID') // 'parent'
|
|
170
|
+
* getMetadataKeywordType('@include') // 'include'
|
|
171
|
+
* getMetadataKeywordType('regular string') // null
|
|
172
|
+
* getMetadataKeywordType('@unknown:value') // null
|
|
173
|
+
*/
|
|
174
|
+
export declare function getMetadataKeywordType(value: string): MetadataKeywordType | null;
|
|
175
|
+
/**
|
|
176
|
+
* Type-safe check for metadata keywords that handles any value type.
|
|
177
|
+
*
|
|
178
|
+
* This is an alias for isMetadataKeyword() provided for semantic clarity
|
|
179
|
+
* when you want to explicitly check if a value has a metadata keyword.
|
|
180
|
+
*
|
|
181
|
+
* @param value - Any value to check
|
|
182
|
+
* @returns true if value is a string with a metadata keyword, false otherwise
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* const fieldValue = record.Get('SomeField');
|
|
186
|
+
* if (hasMetadataKeyword(fieldValue)) {
|
|
187
|
+
* // fieldValue is guaranteed to be a string with a metadata keyword
|
|
188
|
+
* const type = getMetadataKeywordType(fieldValue);
|
|
189
|
+
* }
|
|
190
|
+
*/
|
|
191
|
+
export declare function hasMetadataKeyword(value: unknown): value is string;
|
|
192
|
+
/**
|
|
193
|
+
* Checks if a string starts with @ but is NOT a metadata keyword.
|
|
194
|
+
*
|
|
195
|
+
* This is useful for filtering out @ strings that are not metadata keywords,
|
|
196
|
+
* such as npm package names (@mui/material, @angular/core) or email addresses.
|
|
197
|
+
*
|
|
198
|
+
* @param value - The value to check
|
|
199
|
+
* @returns true if value starts with @ but is not a metadata keyword
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* isNonKeywordAtSymbol('@mui/material') // true
|
|
203
|
+
* isNonKeywordAtSymbol('@angular/core') // true
|
|
204
|
+
* isNonKeywordAtSymbol('@file:template.md') // false
|
|
205
|
+
* isNonKeywordAtSymbol('regular string') // false
|
|
206
|
+
*/
|
|
207
|
+
export declare function isNonKeywordAtSymbol(value: unknown): boolean;
|
|
208
|
+
/**
|
|
209
|
+
* Extracts the value portion after a metadata keyword prefix.
|
|
210
|
+
*
|
|
211
|
+
* Removes the keyword prefix from a string and returns the remaining value.
|
|
212
|
+
* Returns null if the string doesn't use a metadata keyword.
|
|
213
|
+
*
|
|
214
|
+
* @param value - The string containing a metadata keyword
|
|
215
|
+
* @returns The value after the keyword prefix, or null if no keyword found
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* extractKeywordValue('@file:template.md') // 'template.md'
|
|
219
|
+
* extractKeywordValue('@lookup:Users.Email=test@example.com') // 'Users.Email=test@example.com'
|
|
220
|
+
* extractKeywordValue('@parent:ID') // 'ID'
|
|
221
|
+
* extractKeywordValue('regular string') // null
|
|
222
|
+
*/
|
|
223
|
+
export declare function extractKeywordValue(value: string): string | null;
|
|
224
|
+
/**
|
|
225
|
+
* List of metadata keywords that require a parent context to function.
|
|
226
|
+
* These keywords cannot be used at the top level of metadata - they only work
|
|
227
|
+
* in nested/related entities where a parent record exists.
|
|
228
|
+
*/
|
|
229
|
+
export declare const CONTEXT_DEPENDENT_KEYWORDS: readonly ["@parent:", "@root:"];
|
|
230
|
+
/**
|
|
231
|
+
* List of metadata keywords that reference external resources.
|
|
232
|
+
* These keywords load content from files, URLs, or other external sources.
|
|
233
|
+
*/
|
|
234
|
+
export declare const EXTERNAL_REFERENCE_KEYWORDS: readonly ["@file:", "@url:", "@template:"];
|
|
235
|
+
/**
|
|
236
|
+
* List of metadata keywords that perform database lookups.
|
|
237
|
+
*/
|
|
238
|
+
export declare const LOOKUP_KEYWORDS: readonly ["@lookup:"];
|
|
239
|
+
/**
|
|
240
|
+
* List of metadata keywords that access runtime configuration.
|
|
241
|
+
*/
|
|
242
|
+
export declare const RUNTIME_KEYWORDS: readonly ["@env:"];
|
|
243
|
+
/**
|
|
244
|
+
* Checks if a keyword requires a parent/root context.
|
|
245
|
+
*
|
|
246
|
+
* @param keyword - The keyword to check
|
|
247
|
+
* @returns true if the keyword requires context (parent or root)
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* isContextDependentKeyword('@parent:') // true
|
|
251
|
+
* isContextDependentKeyword('@root:') // true
|
|
252
|
+
* isContextDependentKeyword('@file:') // false
|
|
253
|
+
*/
|
|
254
|
+
export declare function isContextDependentKeyword(keyword: string): boolean;
|
|
255
|
+
/**
|
|
256
|
+
* Checks if a keyword references an external resource.
|
|
257
|
+
*
|
|
258
|
+
* @param keyword - The keyword to check
|
|
259
|
+
* @returns true if the keyword loads external content
|
|
260
|
+
*
|
|
261
|
+
* @example
|
|
262
|
+
* isExternalReferenceKeyword('@file:') // true
|
|
263
|
+
* isExternalReferenceKeyword('@url:') // true
|
|
264
|
+
* isExternalReferenceKeyword('@lookup:') // false
|
|
265
|
+
*/
|
|
266
|
+
export declare function isExternalReferenceKeyword(keyword: string): boolean;
|
|
267
|
+
/**
|
|
268
|
+
* Creates a metadata keyword reference string.
|
|
269
|
+
*
|
|
270
|
+
* Helper function to construct properly formatted keyword references.
|
|
271
|
+
* This ensures consistent formatting across the codebase.
|
|
272
|
+
*
|
|
273
|
+
* @param type - The keyword type
|
|
274
|
+
* @param value - The value after the keyword
|
|
275
|
+
* @returns Formatted keyword reference string
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* createKeywordReference('file', 'template.md') // '@file:template.md'
|
|
279
|
+
* createKeywordReference('lookup', 'Users.Email=test@example.com') // '@lookup:Users.Email=test@example.com'
|
|
280
|
+
* createKeywordReference('parent', 'ID') // '@parent:ID'
|
|
281
|
+
*/
|
|
282
|
+
export declare function createKeywordReference(type: MetadataKeywordType, value: string): string;
|