@memberjunction/global 4.0.0 → 4.1.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 +634 -0
- package/package.json +1 -1
- package/dist/Core.d.ts +0 -29
- package/dist/Core.d.ts.map +0 -1
- package/dist/Core.js +0 -58
- package/dist/Core.js.map +0 -1
- package/dist/generic/QueryCache.d.ts +0 -85
- package/dist/generic/QueryCache.d.ts.map +0 -1
- package/dist/generic/QueryCache.js +0 -198
- package/dist/generic/QueryCache.js.map +0 -1
- package/dist/generic/QueryCacheConfig.d.ts +0 -72
- package/dist/generic/QueryCacheConfig.d.ts.map +0 -1
- package/dist/generic/QueryCacheConfig.js +0 -3
- package/dist/generic/QueryCacheConfig.js.map +0 -1
- package/dist/generic/applicationInfo.d.ts +0 -138
- package/dist/generic/applicationInfo.d.ts.map +0 -1
- package/dist/generic/applicationInfo.js +0 -177
- package/dist/generic/applicationInfo.js.map +0 -1
- package/dist/generic/authEvaluator.d.ts +0 -25
- package/dist/generic/authEvaluator.d.ts.map +0 -1
- package/dist/generic/authEvaluator.js +0 -49
- package/dist/generic/authEvaluator.js.map +0 -1
- package/dist/generic/authTypes.d.ts +0 -193
- package/dist/generic/authTypes.d.ts.map +0 -1
- package/dist/generic/authTypes.js +0 -19
- package/dist/generic/authTypes.js.map +0 -1
- package/dist/generic/baseEngine.d.ts +0 -260
- package/dist/generic/baseEngine.d.ts.map +0 -1
- package/dist/generic/baseEngine.js +0 -510
- package/dist/generic/baseEngine.js.map +0 -1
- package/dist/generic/baseEntity.d.ts +0 -691
- package/dist/generic/baseEntity.d.ts.map +0 -1
- package/dist/generic/baseEntity.js +0 -1688
- package/dist/generic/baseEntity.js.map +0 -1
- package/dist/generic/baseInfo.d.ts +0 -24
- package/dist/generic/baseInfo.d.ts.map +0 -1
- package/dist/generic/baseInfo.js +0 -53
- package/dist/generic/baseInfo.js.map +0 -1
- package/dist/generic/compositeKey.d.ts +0 -206
- package/dist/generic/compositeKey.d.ts.map +0 -1
- package/dist/generic/compositeKey.js +0 -412
- package/dist/generic/compositeKey.js.map +0 -1
- package/dist/generic/databaseProviderBase.d.ts +0 -46
- package/dist/generic/databaseProviderBase.d.ts.map +0 -1
- package/dist/generic/databaseProviderBase.js +0 -14
- package/dist/generic/databaseProviderBase.js.map +0 -1
- package/dist/generic/entityInfo.d.ts +0 -983
- package/dist/generic/entityInfo.d.ts.map +0 -1
- package/dist/generic/entityInfo.js +0 -1401
- package/dist/generic/entityInfo.js.map +0 -1
- package/dist/generic/explorerNavigationItem.d.ts +0 -20
- package/dist/generic/explorerNavigationItem.d.ts.map +0 -1
- package/dist/generic/explorerNavigationItem.js +0 -29
- package/dist/generic/explorerNavigationItem.js.map +0 -1
- package/dist/generic/interfaces.d.ts +0 -610
- package/dist/generic/interfaces.d.ts.map +0 -1
- package/dist/generic/interfaces.js +0 -211
- package/dist/generic/interfaces.js.map +0 -1
- package/dist/generic/libraryInfo.d.ts +0 -40
- package/dist/generic/libraryInfo.d.ts.map +0 -1
- package/dist/generic/libraryInfo.js +0 -56
- package/dist/generic/libraryInfo.js.map +0 -1
- package/dist/generic/logging.d.ts +0 -179
- package/dist/generic/logging.d.ts.map +0 -1
- package/dist/generic/logging.js +0 -382
- package/dist/generic/logging.js.map +0 -1
- package/dist/generic/metadata.d.ts +0 -305
- package/dist/generic/metadata.d.ts.map +0 -1
- package/dist/generic/metadata.js +0 -454
- package/dist/generic/metadata.js.map +0 -1
- package/dist/generic/metadataUtil.d.ts +0 -8
- package/dist/generic/metadataUtil.d.ts.map +0 -1
- package/dist/generic/metadataUtil.js +0 -36
- package/dist/generic/metadataUtil.js.map +0 -1
- package/dist/generic/providerBase.d.ts +0 -546
- package/dist/generic/providerBase.d.ts.map +0 -1
- package/dist/generic/providerBase.js +0 -999
- package/dist/generic/providerBase.js.map +0 -1
- package/dist/generic/queryInfo.d.ts +0 -460
- package/dist/generic/queryInfo.d.ts.map +0 -1
- package/dist/generic/queryInfo.js +0 -633
- package/dist/generic/queryInfo.js.map +0 -1
- package/dist/generic/querySQLFilters.d.ts +0 -54
- package/dist/generic/querySQLFilters.d.ts.map +0 -1
- package/dist/generic/querySQLFilters.js +0 -84
- package/dist/generic/querySQLFilters.js.map +0 -1
- package/dist/generic/runQuery.d.ts +0 -96
- package/dist/generic/runQuery.d.ts.map +0 -1
- package/dist/generic/runQuery.js +0 -66
- package/dist/generic/runQuery.js.map +0 -1
- package/dist/generic/runQuerySQLFilterImplementations.d.ts +0 -51
- package/dist/generic/runQuerySQLFilterImplementations.d.ts.map +0 -1
- package/dist/generic/runQuerySQLFilterImplementations.js +0 -238
- package/dist/generic/runQuerySQLFilterImplementations.js.map +0 -1
- package/dist/generic/runReport.d.ts +0 -25
- package/dist/generic/runReport.d.ts.map +0 -1
- package/dist/generic/runReport.js +0 -42
- package/dist/generic/runReport.js.map +0 -1
- package/dist/generic/securityInfo.d.ts +0 -355
- package/dist/generic/securityInfo.d.ts.map +0 -1
- package/dist/generic/securityInfo.js +0 -425
- package/dist/generic/securityInfo.js.map +0 -1
- package/dist/generic/transactionGroup.d.ts +0 -184
- package/dist/generic/transactionGroup.d.ts.map +0 -1
- package/dist/generic/transactionGroup.js +0 -357
- package/dist/generic/transactionGroup.js.map +0 -1
- package/dist/generic/util.d.ts +0 -81
- package/dist/generic/util.d.ts.map +0 -1
- package/dist/generic/util.js +0 -301
- package/dist/generic/util.js.map +0 -1
- package/dist/views/runView.d.ts +0 -150
- package/dist/views/runView.d.ts.map +0 -1
- package/dist/views/runView.js +0 -100
- package/dist/views/runView.js.map +0 -1
- package/dist/views/viewInfo.d.ts +0 -121
- package/dist/views/viewInfo.d.ts.map +0 -1
- package/dist/views/viewInfo.js +0 -182
- package/dist/views/viewInfo.js.map +0 -1
- package/readme.md +0 -1168
package/README.md
ADDED
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
# @memberjunction/global
|
|
2
|
+
|
|
3
|
+
The foundational package for the entire MemberJunction ecosystem. `@memberjunction/global` provides the core infrastructure that every other MJ package depends on: a singleton coordination hub, a dynamic class factory with decorator-based registration, cross-environment global state management, and a collection of essential utilities for validation, diffing, caching, pattern matching, and more.
|
|
4
|
+
|
|
5
|
+
This package has **zero MJ dependencies** and sits at the very bottom of the dependency graph, making it safe to import from anywhere in the stack without circular dependency concerns.
|
|
6
|
+
|
|
7
|
+
## Architecture Overview
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
graph TD
|
|
11
|
+
subgraph MJGlobal["@memberjunction/global"]
|
|
12
|
+
direction TB
|
|
13
|
+
MJG["MJGlobal (Singleton Hub)"]
|
|
14
|
+
CF["ClassFactory"]
|
|
15
|
+
RC["@RegisterClass Decorator"]
|
|
16
|
+
OC["ObjectCache"]
|
|
17
|
+
BS["BaseSingleton<T>"]
|
|
18
|
+
EV["Event System (RxJS)"]
|
|
19
|
+
|
|
20
|
+
MJG --> CF
|
|
21
|
+
MJG --> OC
|
|
22
|
+
MJG --> EV
|
|
23
|
+
RC --> CF
|
|
24
|
+
MJG -.->|extends| BS
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
subgraph Utilities["Utility Modules"]
|
|
28
|
+
direction TB
|
|
29
|
+
DD["DeepDiffer"]
|
|
30
|
+
JV["JSONValidator"]
|
|
31
|
+
SE["SafeExpressionEvaluator"]
|
|
32
|
+
SQ["SQLExpressionValidator"]
|
|
33
|
+
CU["ClassUtils"]
|
|
34
|
+
PU["PatternUtils"]
|
|
35
|
+
WM["WarningManager"]
|
|
36
|
+
EU["EncryptionUtils"]
|
|
37
|
+
UT["String / JSON Utilities"]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
Core["@memberjunction/core"] --> MJGlobal
|
|
41
|
+
Entities["@memberjunction/core-entities"] --> MJGlobal
|
|
42
|
+
Server["@memberjunction/server"] --> MJGlobal
|
|
43
|
+
Angular["Angular packages"] --> MJGlobal
|
|
44
|
+
|
|
45
|
+
style MJGlobal fill:#2d6a9f,stroke:#1a4971,color:#fff
|
|
46
|
+
style Utilities fill:#7c5295,stroke:#563a6b,color:#fff
|
|
47
|
+
style Core fill:#2d8659,stroke:#1a5c3a,color:#fff
|
|
48
|
+
style Entities fill:#2d8659,stroke:#1a5c3a,color:#fff
|
|
49
|
+
style Server fill:#2d8659,stroke:#1a5c3a,color:#fff
|
|
50
|
+
style Angular fill:#2d8659,stroke:#1a5c3a,color:#fff
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install @memberjunction/global
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Core Concepts
|
|
60
|
+
|
|
61
|
+
### MJGlobal -- The Singleton Hub
|
|
62
|
+
|
|
63
|
+
`MJGlobal` is the central coordination point for the MemberJunction runtime. It is a singleton (via `BaseSingleton<T>`) that provides access to the class factory, a global event bus, a property bag, and an in-memory object cache.
|
|
64
|
+
|
|
65
|
+
```mermaid
|
|
66
|
+
classDiagram
|
|
67
|
+
class MJGlobal {
|
|
68
|
+
+Instance : MJGlobal$
|
|
69
|
+
+ClassFactory : ClassFactory
|
|
70
|
+
+ObjectCache : ObjectCache
|
|
71
|
+
+Properties : MJGlobalProperty[]
|
|
72
|
+
+RegisterComponent(component)
|
|
73
|
+
+RaiseEvent(event)
|
|
74
|
+
+GetEventListener(withReplay?) : Observable~MJEvent~
|
|
75
|
+
+Reset()
|
|
76
|
+
}
|
|
77
|
+
class ClassFactory {
|
|
78
|
+
+Register(baseClass, subClass, key?, priority?)
|
|
79
|
+
+CreateInstance~T~(baseClass, key?, ...params) : T
|
|
80
|
+
+GetRegistration(baseClass, key?) : ClassRegistration
|
|
81
|
+
+GetAllRegistrations(baseClass, key?) : ClassRegistration[]
|
|
82
|
+
+GetRegistrationsByRootClass(rootClass, key?) : ClassRegistration[]
|
|
83
|
+
}
|
|
84
|
+
class ObjectCache {
|
|
85
|
+
+Add~T~(key, object)
|
|
86
|
+
+Find~T~(key) : T
|
|
87
|
+
+Replace~T~(key, object)
|
|
88
|
+
+Remove(key)
|
|
89
|
+
+Clear()
|
|
90
|
+
}
|
|
91
|
+
MJGlobal --> ClassFactory
|
|
92
|
+
MJGlobal --> ObjectCache
|
|
93
|
+
|
|
94
|
+
style MJGlobal fill:#2d6a9f,stroke:#1a4971,color:#fff
|
|
95
|
+
style ClassFactory fill:#2d8659,stroke:#1a5c3a,color:#fff
|
|
96
|
+
style ObjectCache fill:#b8762f,stroke:#8a5722,color:#fff
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { MJGlobal } from '@memberjunction/global';
|
|
101
|
+
|
|
102
|
+
// Access the singleton
|
|
103
|
+
const g = MJGlobal.Instance;
|
|
104
|
+
|
|
105
|
+
// Use the class factory
|
|
106
|
+
const instance = g.ClassFactory.CreateInstance<MyBase>(MyBase, 'some-key');
|
|
107
|
+
|
|
108
|
+
// Use the object cache
|
|
109
|
+
g.ObjectCache.Add('config', { debug: true });
|
|
110
|
+
const config = g.ObjectCache.Find<{ debug: boolean }>('config');
|
|
111
|
+
|
|
112
|
+
// Use the global property bag
|
|
113
|
+
g.Properties.push({ key: 'appName', value: 'MyApp' });
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Class Factory and @RegisterClass
|
|
117
|
+
|
|
118
|
+
The class factory is MemberJunction's dependency injection system. It allows any module to register a subclass for a given base class and key, so that later code can request an instance by base class and key and automatically receive the most specific (highest-priority) subclass.
|
|
119
|
+
|
|
120
|
+
```mermaid
|
|
121
|
+
flowchart LR
|
|
122
|
+
A["@RegisterClass(BaseEntity, 'Users')"] -->|registers| CF["ClassFactory"]
|
|
123
|
+
B["@RegisterClass(BaseEntity, 'Users', 10)"] -->|higher priority| CF
|
|
124
|
+
CF -->|"CreateInstance(BaseEntity, 'Users')"| B
|
|
125
|
+
CF -->|returns instance of| SUB["UserEntity (priority 10)"]
|
|
126
|
+
|
|
127
|
+
style A fill:#64748b,stroke:#475569,color:#fff
|
|
128
|
+
style B fill:#2d8659,stroke:#1a5c3a,color:#fff
|
|
129
|
+
style CF fill:#2d6a9f,stroke:#1a4971,color:#fff
|
|
130
|
+
style SUB fill:#b8762f,stroke:#8a5722,color:#fff
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Decorator usage:**
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
137
|
+
|
|
138
|
+
// Register a subclass for a base class with a key
|
|
139
|
+
@RegisterClass(BaseFormComponent, 'Users')
|
|
140
|
+
export class UserFormComponent extends BaseFormComponent {
|
|
141
|
+
// ...
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Priority controls which registration wins
|
|
145
|
+
@RegisterClass(BaseFormComponent, 'Users', 10)
|
|
146
|
+
export class CustomUserFormComponent extends UserFormComponent {
|
|
147
|
+
// Wins over UserFormComponent because priority 10 > auto-assigned
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Programmatic registration:**
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
MJGlobal.Instance.ClassFactory.Register(
|
|
155
|
+
BaseEntity, // base class
|
|
156
|
+
UserEntity, // subclass
|
|
157
|
+
'Users', // key
|
|
158
|
+
5 // priority (optional)
|
|
159
|
+
);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Instance creation:**
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
const entity = MJGlobal.Instance.ClassFactory.CreateInstance<BaseEntity>(
|
|
166
|
+
BaseEntity,
|
|
167
|
+
'Users'
|
|
168
|
+
);
|
|
169
|
+
// Returns an instance of the highest-priority registered subclass for 'Users'
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Event System
|
|
173
|
+
|
|
174
|
+
MJGlobal provides a publish/subscribe event bus built on RxJS. Events can be observed in real-time or with replay (a `ReplaySubject` buffering up to 100 events for 30 seconds).
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
import { MJGlobal, MJEventType } from '@memberjunction/global';
|
|
178
|
+
|
|
179
|
+
// Subscribe to events (with replay for late subscribers)
|
|
180
|
+
MJGlobal.Instance.GetEventListener(true).subscribe(event => {
|
|
181
|
+
if (event.event === MJEventType.LoggedIn) {
|
|
182
|
+
console.log('User logged in:', event.args);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Raise an event
|
|
187
|
+
MJGlobal.Instance.RaiseEvent({
|
|
188
|
+
event: MJEventType.ComponentEvent,
|
|
189
|
+
eventCode: 'data-loaded',
|
|
190
|
+
args: { recordCount: 42 },
|
|
191
|
+
component: myComponent
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Built-in event types:**
|
|
196
|
+
|
|
197
|
+
| Event Type | Description |
|
|
198
|
+
|---|---|
|
|
199
|
+
| `ComponentRegistered` | A component was registered with MJGlobal |
|
|
200
|
+
| `ComponentUnregistered` | A component was unregistered |
|
|
201
|
+
| `ComponentEvent` | Generic component-level event |
|
|
202
|
+
| `LoggedIn` | User authentication succeeded |
|
|
203
|
+
| `LoggedOut` | User logged out |
|
|
204
|
+
| `LoginFailed` | Authentication attempt failed |
|
|
205
|
+
| `LogoutFailed` | Logout attempt failed |
|
|
206
|
+
| `ManualResizeRequest` | Request for UI components to recalculate layout |
|
|
207
|
+
| `DisplaySimpleNotificationRequest` | Request to show a notification to the user |
|
|
208
|
+
|
|
209
|
+
### BaseSingleton\<T\>
|
|
210
|
+
|
|
211
|
+
A generic abstract base class for implementing the singleton pattern. It uses the global object store (`window` in browsers, `global` in Node.js) to guarantee a single instance even when module code is duplicated across multiple bundle paths.
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import { BaseSingleton } from '@memberjunction/global';
|
|
215
|
+
|
|
216
|
+
export class MyService extends BaseSingleton<MyService> {
|
|
217
|
+
public static get Instance(): MyService {
|
|
218
|
+
return super.getInstance<MyService>();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
public DoWork(): void {
|
|
222
|
+
// service logic
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Usage
|
|
227
|
+
MyService.Instance.DoWork();
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Utility Modules
|
|
231
|
+
|
|
232
|
+
### DeepDiffer -- Object Comparison
|
|
233
|
+
|
|
234
|
+
Recursively compares two objects and produces a detailed, human-readable diff with change tracking.
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import { DeepDiffer, DiffChangeType } from '@memberjunction/global';
|
|
238
|
+
|
|
239
|
+
const differ = new DeepDiffer({
|
|
240
|
+
maxDepth: 10,
|
|
241
|
+
treatNullAsUndefined: true,
|
|
242
|
+
includeUnchanged: false
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
const result = differ.diff(
|
|
246
|
+
{ name: 'Alice', age: 30, tags: ['dev'] },
|
|
247
|
+
{ name: 'Alice', age: 31, tags: ['dev', 'lead'] }
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
console.log(result.summary);
|
|
251
|
+
// { added: 1, removed: 0, modified: 2, unchanged: 0, totalPaths: 3 }
|
|
252
|
+
|
|
253
|
+
console.log(result.formatted);
|
|
254
|
+
// === Deep Diff Summary ===
|
|
255
|
+
// Total changes: 3
|
|
256
|
+
// Added: 1
|
|
257
|
+
// Modified: 2
|
|
258
|
+
// ...
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### JSONValidator -- Template-Based Validation
|
|
262
|
+
|
|
263
|
+
A lightweight validator that checks objects against example templates using special field-name syntax for validation rules.
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import { JSONValidator } from '@memberjunction/global';
|
|
267
|
+
|
|
268
|
+
const validator = new JSONValidator();
|
|
269
|
+
|
|
270
|
+
const template = {
|
|
271
|
+
"name": "example", // required
|
|
272
|
+
"email?": "user@example.com", // optional (? suffix)
|
|
273
|
+
"config*": {}, // required, any content (* suffix)
|
|
274
|
+
"tags:[1+]": ["tag1"], // array with 1+ items
|
|
275
|
+
"count:number": 0, // must be a number
|
|
276
|
+
"title:string:!empty": "" // must be a non-empty string
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const result = validator.validate(myData, template);
|
|
280
|
+
if (!result.Success) {
|
|
281
|
+
console.log(result.Errors);
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
**Supported validation rules:**
|
|
286
|
+
|
|
287
|
+
| Syntax | Meaning |
|
|
288
|
+
|---|---|
|
|
289
|
+
| `field?` | Field is optional |
|
|
290
|
+
| `field*` | Required, accepts any content |
|
|
291
|
+
| `field:string` | Must be a string |
|
|
292
|
+
| `field:number` | Must be a number |
|
|
293
|
+
| `field:boolean` | Must be a boolean |
|
|
294
|
+
| `field:object` | Must be a plain object |
|
|
295
|
+
| `field:array` | Must be an array |
|
|
296
|
+
| `field:!empty` | Must not be empty |
|
|
297
|
+
| `field:[N+]` | Array with at least N elements |
|
|
298
|
+
| `field:[N-M]` | Array with N to M elements |
|
|
299
|
+
| `field:[=N]` | Array with exactly N elements |
|
|
300
|
+
|
|
301
|
+
### SafeExpressionEvaluator
|
|
302
|
+
|
|
303
|
+
Evaluates boolean expressions against context objects securely, blocking injection patterns like `eval()`, `require()`, `process.`, template literals, and more.
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
import { SafeExpressionEvaluator } from '@memberjunction/global';
|
|
307
|
+
|
|
308
|
+
const evaluator = new SafeExpressionEvaluator();
|
|
309
|
+
|
|
310
|
+
const result = evaluator.evaluate(
|
|
311
|
+
"customer.tier == 'premium' && order.total > 1000",
|
|
312
|
+
{
|
|
313
|
+
customer: { tier: 'premium' },
|
|
314
|
+
order: { total: 1500 }
|
|
315
|
+
}
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
if (result.success) {
|
|
319
|
+
console.log(result.value); // true
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Supports comparisons (`==`, `!=`, `<`, `>`, `<=`, `>=`), logical operators (`&&`, `||`, `!`), dot-notation property access, bracket-notation array access, and safe string/array methods (`.includes()`, `.startsWith()`, `.some()`, `.every()`, etc.).
|
|
324
|
+
|
|
325
|
+
### SQLExpressionValidator
|
|
326
|
+
|
|
327
|
+
Validates user-provided SQL expressions against injection attacks. Provides context-aware validation (WHERE clauses, ORDER BY, aggregates, field references) with an allowlist of safe SQL functions.
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
import { SQLExpressionValidator } from '@memberjunction/global';
|
|
331
|
+
|
|
332
|
+
const validator = SQLExpressionValidator.Instance;
|
|
333
|
+
|
|
334
|
+
// Validate a WHERE clause
|
|
335
|
+
const result = validator.validate("Status = 'Active' AND Total > 100", {
|
|
336
|
+
context: 'where_clause'
|
|
337
|
+
});
|
|
338
|
+
// result.valid === true
|
|
339
|
+
|
|
340
|
+
// Unsafe input is rejected
|
|
341
|
+
const bad = validator.validate("Name = 'test'; 1=1", {
|
|
342
|
+
context: 'where_clause'
|
|
343
|
+
});
|
|
344
|
+
// bad.valid === false
|
|
345
|
+
// bad.error === "Semicolons are not allowed in SQL expressions"
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### ClassUtils -- Reflection Helpers
|
|
349
|
+
|
|
350
|
+
Functions for introspecting class hierarchies at runtime.
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
import {
|
|
354
|
+
GetSuperclass,
|
|
355
|
+
GetRootClass,
|
|
356
|
+
IsSubclassOf,
|
|
357
|
+
IsRootClass,
|
|
358
|
+
GetClassInheritance,
|
|
359
|
+
GetFullClassHierarchy,
|
|
360
|
+
GetClassName,
|
|
361
|
+
IsClassConstructor
|
|
362
|
+
} from '@memberjunction/global';
|
|
363
|
+
|
|
364
|
+
const chain = GetClassInheritance(MyDerivedClass);
|
|
365
|
+
// [{ name: 'MyBaseClass', reference: ... }, { name: 'MyRootClass', reference: ... }]
|
|
366
|
+
|
|
367
|
+
const isChild = IsSubclassOf(ChildClass, ParentClass); // true
|
|
368
|
+
const root = GetRootClass(ChildClass); // returns the top-most user-defined class
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### PatternUtils -- Wildcard and Regex Matching
|
|
372
|
+
|
|
373
|
+
Converts wildcard patterns and regex strings to `RegExp` objects for flexible text matching.
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
import { parsePattern, matchesAnyPattern } from '@memberjunction/global';
|
|
377
|
+
|
|
378
|
+
const regex = parsePattern('*AIPrompt*'); // matches strings containing "AIPrompt"
|
|
379
|
+
const exact = parsePattern('Users'); // matches exactly "Users" (case-insensitive)
|
|
380
|
+
const re = parsePattern('/^sp_Create/i'); // parsed as a regex literal
|
|
381
|
+
|
|
382
|
+
const matches = matchesAnyPattern('AIPromptRuns', ['*Prompt*', '*Agent*']); // true
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### ObjectCache
|
|
386
|
+
|
|
387
|
+
A simple in-memory key-value cache with type-safe generic accessors. Keys are case-insensitive.
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
import { MJGlobal } from '@memberjunction/global';
|
|
391
|
+
|
|
392
|
+
const cache = MJGlobal.Instance.ObjectCache;
|
|
393
|
+
|
|
394
|
+
cache.Add('user-prefs', { theme: 'dark' });
|
|
395
|
+
const prefs = cache.Find<{ theme: string }>('User-Prefs'); // case-insensitive lookup
|
|
396
|
+
cache.Replace('user-prefs', { theme: 'light' });
|
|
397
|
+
cache.Remove('user-prefs');
|
|
398
|
+
cache.Clear();
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### WarningManager
|
|
402
|
+
|
|
403
|
+
A singleton warning system with session-level deduplication, debounced output, and tree-structured formatting. Tracks deprecation warnings, field-not-found warnings, and redundant load warnings.
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
import { WarningManager } from '@memberjunction/global';
|
|
407
|
+
|
|
408
|
+
const wm = WarningManager.Instance;
|
|
409
|
+
|
|
410
|
+
// Configure
|
|
411
|
+
wm.UpdateConfig({ DebounceMs: 5000, GroupWarnings: true });
|
|
412
|
+
|
|
413
|
+
// Record warnings (deduplicated and batched automatically)
|
|
414
|
+
wm.RecordEntityDeprecationWarning('User Preferences', 'BaseEntity::constructor');
|
|
415
|
+
wm.RecordFieldNotFoundWarning('Users', 'DeletedColumn', 'BaseEntity::SetMany');
|
|
416
|
+
wm.RecordRedundantLoadWarning('AI Models', ['DashboardEngine', 'AIEngine']);
|
|
417
|
+
|
|
418
|
+
// Force immediate output if needed
|
|
419
|
+
wm.FlushWarnings();
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### EncryptionUtils
|
|
423
|
+
|
|
424
|
+
Constants and utility functions for working with encrypted field values. Located in this foundational package so any package can detect encrypted values without depending on the full Encryption package.
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
import {
|
|
428
|
+
IsValueEncrypted,
|
|
429
|
+
IsEncryptedSentinel,
|
|
430
|
+
ENCRYPTION_MARKER,
|
|
431
|
+
ENCRYPTED_SENTINEL
|
|
432
|
+
} from '@memberjunction/global';
|
|
433
|
+
|
|
434
|
+
IsValueEncrypted('$ENC$keyId$AES-256-GCM$iv$ciphertext$authTag'); // true
|
|
435
|
+
IsValueEncrypted('[!ENCRYPTED$]'); // true (sentinel)
|
|
436
|
+
IsValueEncrypted('plain text'); // false
|
|
437
|
+
IsEncryptedSentinel('[!ENCRYPTED$]'); // true
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### String and JSON Utilities
|
|
441
|
+
|
|
442
|
+
A collection of utility functions for common string and JSON operations.
|
|
443
|
+
|
|
444
|
+
| Function | Description |
|
|
445
|
+
|---|---|
|
|
446
|
+
| `CleanJSON(input)` | Extracts and formats JSON from various formats (double-escaped, markdown blocks, mixed content) |
|
|
447
|
+
| `SafeJSONParse<T>(json, logErrors?)` | Parses JSON returning `T` or `null` without throwing |
|
|
448
|
+
| `CleanAndParseJSON<T>(input, logErrors?)` | Combines `CleanJSON` and `SafeJSONParse` in one call |
|
|
449
|
+
| `ParseJSONRecursive(obj, options?)` | Recursively parses nested JSON strings within objects |
|
|
450
|
+
| `CleanJavaScript(code)` | Extracts JavaScript from markdown code blocks |
|
|
451
|
+
| `CopyScalarsAndArrays<T>(input, resolveCircular?)` | Deep-copies scalar and array properties, optionally handling circular references |
|
|
452
|
+
| `convertCamelCaseToHaveSpaces(s)` | `"AIAgentRun"` becomes `"AI Agent Run"` |
|
|
453
|
+
| `stripWhitespace(s)` | Removes all whitespace from a string |
|
|
454
|
+
| `generatePluralName(singular, options?)` | Handles irregular and regular English pluralization |
|
|
455
|
+
| `getIrregularPlural(word)` | Looks up irregular plural forms |
|
|
456
|
+
| `adjustCasing(word, options?)` | Capitalizes first letter, entire word, or leaves as-is |
|
|
457
|
+
| `stripTrailingChars(s, chars, skipIfExact?)` | Removes trailing substring |
|
|
458
|
+
| `replaceAllSpaces(s)` | Removes all space characters |
|
|
459
|
+
| `compareStringsByLine(str1, str2, log?)` | Line-by-line diff with character-level detail |
|
|
460
|
+
| `IsOnlyTimezoneShift(date1, date2)` | Detects if two dates differ only by a whole-hour timezone offset |
|
|
461
|
+
| `InvokeManualResize(delay?, component?)` | Broadcasts a `ManualResizeRequest` event |
|
|
462
|
+
| `uuidv4()` | Generates a v4 UUID |
|
|
463
|
+
| `GetGlobalObjectStore()` | Returns `window` (browser) or `global` (Node.js) for cross-environment state |
|
|
464
|
+
|
|
465
|
+
### ValidationTypes
|
|
466
|
+
|
|
467
|
+
Standard validation result types used across the framework.
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
import { ValidationResult, ValidationErrorInfo, ValidationErrorType } from '@memberjunction/global';
|
|
471
|
+
|
|
472
|
+
const result = new ValidationResult();
|
|
473
|
+
result.Success = false;
|
|
474
|
+
result.Errors.push(
|
|
475
|
+
new ValidationErrorInfo('fieldName', 'Value is required', null, ValidationErrorType.Failure)
|
|
476
|
+
);
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
## Module Dependency Flow
|
|
480
|
+
|
|
481
|
+
```mermaid
|
|
482
|
+
flowchart TB
|
|
483
|
+
subgraph MJGlobal["@memberjunction/global (this package)"]
|
|
484
|
+
direction LR
|
|
485
|
+
G["MJGlobal"]
|
|
486
|
+
CF["ClassFactory"]
|
|
487
|
+
RC["RegisterClass"]
|
|
488
|
+
BS["BaseSingleton"]
|
|
489
|
+
OC["ObjectCache"]
|
|
490
|
+
U["Utilities"]
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
subgraph External["External Dependencies"]
|
|
494
|
+
RX["rxjs"]
|
|
495
|
+
LO["lodash"]
|
|
496
|
+
UUID["uuid"]
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
G --> RX
|
|
500
|
+
U --> LO
|
|
501
|
+
U --> UUID
|
|
502
|
+
|
|
503
|
+
subgraph Consumers["Consuming Packages (examples)"]
|
|
504
|
+
direction LR
|
|
505
|
+
MJC["@memberjunction/core"]
|
|
506
|
+
MCE["@memberjunction/core-entities"]
|
|
507
|
+
GQL["@memberjunction/graphql-dataprovider"]
|
|
508
|
+
ENC["@memberjunction/encryption"]
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
Consumers --> MJGlobal
|
|
512
|
+
|
|
513
|
+
style MJGlobal fill:#2d6a9f,stroke:#1a4971,color:#fff
|
|
514
|
+
style External fill:#b8762f,stroke:#8a5722,color:#fff
|
|
515
|
+
style Consumers fill:#2d8659,stroke:#1a5c3a,color:#fff
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
## API Reference
|
|
519
|
+
|
|
520
|
+
### MJGlobal
|
|
521
|
+
|
|
522
|
+
| Member | Type | Description |
|
|
523
|
+
|---|---|---|
|
|
524
|
+
| `Instance` | `MJGlobal` (static) | Returns the singleton instance |
|
|
525
|
+
| `ClassFactory` | `ClassFactory` | Access the class registration and instantiation system |
|
|
526
|
+
| `ObjectCache` | `ObjectCache` | In-memory key-value cache |
|
|
527
|
+
| `Properties` | `MJGlobalProperty[]` | Global property bag for arbitrary key-value storage |
|
|
528
|
+
| `RegisterComponent(component)` | `void` | Register an `IMJComponent` |
|
|
529
|
+
| `RaiseEvent(event)` | `void` | Publish an `MJEvent` to all listeners |
|
|
530
|
+
| `GetEventListener(withReplay?)` | `Observable<MJEvent>` | Subscribe to the event stream |
|
|
531
|
+
| `Reset()` | `void` | Reset all internal state (use with extreme caution) |
|
|
532
|
+
|
|
533
|
+
### ClassFactory
|
|
534
|
+
|
|
535
|
+
| Method | Returns | Description |
|
|
536
|
+
|---|---|---|
|
|
537
|
+
| `Register(baseClass, subClass, key?, priority?, skipNullKeyWarning?, autoRegisterWithRootClass?)` | `void` | Register a subclass for a base class and optional key |
|
|
538
|
+
| `CreateInstance<T>(baseClass, key?, ...params)` | `T \| null` | Create an instance of the highest-priority registered subclass |
|
|
539
|
+
| `GetRegistration(baseClass, key?)` | `ClassRegistration \| null` | Get the highest-priority registration |
|
|
540
|
+
| `GetAllRegistrations(baseClass, key?)` | `ClassRegistration[]` | Get all registrations for a base class and optional key |
|
|
541
|
+
| `GetRegistrationsByRootClass(rootClass, key?)` | `ClassRegistration[]` | Get registrations by root class in the hierarchy |
|
|
542
|
+
|
|
543
|
+
### RegisterClass Decorator
|
|
544
|
+
|
|
545
|
+
```typescript
|
|
546
|
+
function RegisterClass(
|
|
547
|
+
baseClass: unknown,
|
|
548
|
+
key?: string | null,
|
|
549
|
+
priority?: number,
|
|
550
|
+
skipNullKeyWarning?: boolean,
|
|
551
|
+
autoRegisterWithRootClass?: boolean
|
|
552
|
+
): (constructor: Function) => void;
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### ObjectCache
|
|
556
|
+
|
|
557
|
+
| Method | Returns | Description |
|
|
558
|
+
|---|---|---|
|
|
559
|
+
| `Add<T>(key, object)` | `void` | Add entry; throws if key exists |
|
|
560
|
+
| `Find<T>(key)` | `T \| null` | Case-insensitive key lookup |
|
|
561
|
+
| `Replace<T>(key, object)` | `void` | Replace or add entry |
|
|
562
|
+
| `Remove(key)` | `void` | Remove entry by key |
|
|
563
|
+
| `Clear()` | `void` | Remove all entries |
|
|
564
|
+
|
|
565
|
+
### DeepDiffer
|
|
566
|
+
|
|
567
|
+
| Method | Returns | Description |
|
|
568
|
+
|---|---|---|
|
|
569
|
+
| `diff<T>(oldValue, newValue)` | `DeepDiffResult` | Generate a full diff between two values |
|
|
570
|
+
| `updateConfig(config)` | `void` | Update configuration options |
|
|
571
|
+
|
|
572
|
+
### JSONValidator
|
|
573
|
+
|
|
574
|
+
| Method | Returns | Description |
|
|
575
|
+
|---|---|---|
|
|
576
|
+
| `validate(data, template, path?)` | `ValidationResult` | Validate data against a template |
|
|
577
|
+
| `validateAgainstSchema(data, schemaJson)` | `ValidationResult` | Validate against a JSON string schema |
|
|
578
|
+
| `cleanValidationSyntax<T>(data)` | `T` | Strip validation markers from keys |
|
|
579
|
+
|
|
580
|
+
### SafeExpressionEvaluator
|
|
581
|
+
|
|
582
|
+
| Method | Returns | Description |
|
|
583
|
+
|---|---|---|
|
|
584
|
+
| `evaluate(expression, context, enableDiagnostics?)` | `ExpressionEvaluationResult` | Evaluate a single boolean expression |
|
|
585
|
+
| `evaluateMultiple(expressions, context)` | `Record<string, ExpressionEvaluationResult>` | Evaluate multiple expressions |
|
|
586
|
+
|
|
587
|
+
### SQLExpressionValidator
|
|
588
|
+
|
|
589
|
+
| Method | Returns | Description |
|
|
590
|
+
|---|---|---|
|
|
591
|
+
| `Instance` (static) | `SQLExpressionValidator` | Singleton accessor |
|
|
592
|
+
| `validate(expression, options)` | `SQLValidationResult` | Validate a SQL expression |
|
|
593
|
+
|
|
594
|
+
### WarningManager
|
|
595
|
+
|
|
596
|
+
| Method | Returns | Description |
|
|
597
|
+
|---|---|---|
|
|
598
|
+
| `Instance` (static) | `WarningManager` | Singleton accessor |
|
|
599
|
+
| `UpdateConfig(config)` | `void` | Update warning configuration |
|
|
600
|
+
| `GetConfig()` | `Readonly<WarningConfig>` | Get current configuration |
|
|
601
|
+
| `RecordEntityDeprecationWarning(entityName, callerName)` | `boolean` | Record an entity deprecation warning |
|
|
602
|
+
| `RecordFieldDeprecationWarning(entityName, fieldName, callerName)` | `boolean` | Record a field deprecation warning |
|
|
603
|
+
| `RecordFieldNotFoundWarning(entityName, fieldName, context)` | `boolean` | Record a field-not-found warning |
|
|
604
|
+
| `RecordRedundantLoadWarning(entityName, engines)` | `boolean` | Record a redundant data loading warning |
|
|
605
|
+
| `FlushWarnings()` | `void` | Force immediate output of all pending warnings |
|
|
606
|
+
| `Reset()` | `void` | Clear all tracking state |
|
|
607
|
+
|
|
608
|
+
## Dependencies
|
|
609
|
+
|
|
610
|
+
| Package | Purpose |
|
|
611
|
+
|---|---|
|
|
612
|
+
| `rxjs` | Observable-based event system (`Subject`, `ReplaySubject`) |
|
|
613
|
+
| `lodash` | Deep comparison, type checking, object utilities |
|
|
614
|
+
| `uuid` | UUID v4 generation |
|
|
615
|
+
|
|
616
|
+
## Related Packages
|
|
617
|
+
|
|
618
|
+
| Package | Relationship |
|
|
619
|
+
|---|---|
|
|
620
|
+
| `@memberjunction/core` | Builds on MJGlobal; adds Metadata, RunView, BaseEntity, and more |
|
|
621
|
+
| `@memberjunction/core-entities` | Generated entity subclasses registered via `@RegisterClass` |
|
|
622
|
+
| `@memberjunction/encryption` | Full encryption implementation; uses `EncryptionUtils` constants from this package |
|
|
623
|
+
| `@memberjunction/server` | Server-side runtime that depends on MJGlobal for class factory and events |
|
|
624
|
+
| `@memberjunction/graphql-dataprovider` | Client-side data provider registered through the class factory |
|
|
625
|
+
|
|
626
|
+
## Build
|
|
627
|
+
|
|
628
|
+
```bash
|
|
629
|
+
# From the package directory
|
|
630
|
+
cd packages/MJGlobal
|
|
631
|
+
npm run build
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
The build step runs `tsc` followed by `tsc-alias` for path alias resolution.
|
package/package.json
CHANGED
package/dist/Core.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
export * from './generic/metadata.js';
|
|
2
|
-
export * from './generic/baseInfo.js';
|
|
3
|
-
export * from './generic/baseEngine.js';
|
|
4
|
-
export * from './views/runView.js';
|
|
5
|
-
export * from './generic/runReport.js';
|
|
6
|
-
export * from './generic/runQuery.js';
|
|
7
|
-
export * from './generic/interfaces.js';
|
|
8
|
-
export * from './generic/baseEntity.js';
|
|
9
|
-
export * from './generic/applicationInfo.js';
|
|
10
|
-
export * from './generic/providerBase.js';
|
|
11
|
-
export * from './generic/entityInfo.js';
|
|
12
|
-
export * from './generic/securityInfo.js';
|
|
13
|
-
export * from './generic/transactionGroup.js';
|
|
14
|
-
export * from './generic/util.js';
|
|
15
|
-
export * from './generic/logging.js';
|
|
16
|
-
export * from './generic/queryInfo.js';
|
|
17
|
-
export * from './generic/querySQLFilters.js';
|
|
18
|
-
export * from './generic/runQuerySQLFilterImplementations.js';
|
|
19
|
-
export * from './generic/libraryInfo.js';
|
|
20
|
-
export * from './generic/QueryCacheConfig.js';
|
|
21
|
-
export * from './generic/QueryCache.js';
|
|
22
|
-
export * from './generic/explorerNavigationItem.js';
|
|
23
|
-
export * from './generic/compositeKey.js';
|
|
24
|
-
export * from './generic/authEvaluator.js';
|
|
25
|
-
export * from './generic/metadataUtil.js';
|
|
26
|
-
export * from './generic/authTypes.js';
|
|
27
|
-
export * from './generic/databaseProviderBase.js';
|
|
28
|
-
export declare function SetProvider(provider: any): void;
|
|
29
|
-
//# sourceMappingURL=Core.d.ts.map
|
package/dist/Core.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Core.d.ts","sourceRoot":"","sources":["../src/Core.ts"],"names":[],"mappings":"AAMA,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AAEpC,cAAc,gCAAgC,CAAC;AAE/C,wBAAgB,WAAW,CAAC,QAAQ,KAAA,QAMnC"}
|