@hotmeshio/hotmesh 0.5.2 → 0.5.4
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 +93 -175
- package/build/index.d.ts +1 -3
- package/build/index.js +1 -5
- package/build/modules/enums.d.ts +4 -0
- package/build/modules/enums.js +5 -1
- package/build/modules/utils.d.ts +1 -9
- package/build/modules/utils.js +0 -6
- package/build/package.json +3 -4
- package/build/services/connector/factory.d.ts +2 -2
- package/build/services/connector/factory.js +11 -8
- package/build/services/connector/providers/postgres.d.ts +47 -0
- package/build/services/connector/providers/postgres.js +107 -0
- package/build/services/hotmesh/index.d.ts +8 -0
- package/build/services/hotmesh/index.js +27 -0
- package/build/services/memflow/client.d.ts +1 -1
- package/build/services/memflow/client.js +8 -6
- package/build/services/memflow/worker.js +3 -0
- package/build/services/pipe/functions/cron.js +1 -1
- package/build/services/store/providers/postgres/kvtables.js +19 -6
- package/build/services/store/providers/postgres/postgres.js +13 -2
- package/build/services/stream/providers/postgres/postgres.d.ts +6 -3
- package/build/services/stream/providers/postgres/postgres.js +169 -59
- package/build/services/sub/providers/postgres/postgres.d.ts +9 -0
- package/build/services/sub/providers/postgres/postgres.js +109 -18
- package/build/services/worker/index.js +4 -0
- package/build/types/hotmesh.d.ts +19 -5
- package/build/types/index.d.ts +0 -2
- package/env.example +11 -0
- package/index.ts +0 -4
- package/package.json +3 -4
- package/build/services/meshdata/index.d.ts +0 -795
- package/build/services/meshdata/index.js +0 -1235
- package/build/services/meshos/index.d.ts +0 -293
- package/build/services/meshos/index.js +0 -547
- package/build/types/manifest.d.ts +0 -52
- package/build/types/manifest.js +0 -2
- package/build/types/meshdata.d.ts +0 -252
- package/build/types/meshdata.js +0 -2
|
@@ -1,547 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MeshOS = void 0;
|
|
4
|
-
const index_1 = require("../meshdata/index");
|
|
5
|
-
const utils_1 = require("../../modules/utils");
|
|
6
|
-
const logger_1 = require("../logger");
|
|
7
|
-
/**
|
|
8
|
-
* MeshOS is an abstract base class for schema-driven entity management within the Mesh network.
|
|
9
|
-
* It provides a foundation for defining custom entities.
|
|
10
|
-
* By subclassing MeshOS, you can create entities with specific schemas and behaviors, enabling
|
|
11
|
-
* structured data storage, retrieval, and transactional workflows.
|
|
12
|
-
*
|
|
13
|
-
* ### Subclassing MeshOS
|
|
14
|
-
*
|
|
15
|
-
* Standard CRUD methods are included and use your provided schema to
|
|
16
|
-
* fields to return in the response: create, retrieve, update, delete.
|
|
17
|
-
*
|
|
18
|
-
* Search methods are included and use your provided schema to
|
|
19
|
-
* fields to return in the response: count, find, aggregate.
|
|
20
|
-
*
|
|
21
|
-
* Implement other methods as needed for the entity's
|
|
22
|
-
* functionality; For example, subclass/override methods like `create`
|
|
23
|
-
* to also spawn a transactional workflow
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```typescript
|
|
27
|
-
* import { MeshOS } from '@hotmeshio/hotmesh';
|
|
28
|
-
* import { Types } from '@hotmeshio/hotmesh';
|
|
29
|
-
* import { schema } from './schema'; // Import your schema
|
|
30
|
-
* import * as workflows from './workflows';
|
|
31
|
-
*
|
|
32
|
-
* class Widget extends MeshOS {
|
|
33
|
-
*
|
|
34
|
-
* //Subclass the `connect` method to connect workers and
|
|
35
|
-
* // hooks (optional) when the container starts
|
|
36
|
-
* async connect() {
|
|
37
|
-
* await this.meshData.connect({
|
|
38
|
-
* entity: this.getEntity(),
|
|
39
|
-
* //the `target widget workflow` runs as a transaction
|
|
40
|
-
* target: function() {
|
|
41
|
-
* return { hello: 'world' };
|
|
42
|
-
* },
|
|
43
|
-
* options: {
|
|
44
|
-
* namespace: this.getNamespace(),
|
|
45
|
-
* taskQueue: this.getTaskQueue(),
|
|
46
|
-
* },
|
|
47
|
-
* });
|
|
48
|
-
* }
|
|
49
|
-
*
|
|
50
|
-
* // subclass the `create` method to start a transactional
|
|
51
|
-
* // workflow; use the options/search field to set default
|
|
52
|
-
* // record data `{ ...input}` and invoke the `target widget workflow`
|
|
53
|
-
* async create(input: Types.StringAnyType): Promise<Types.StringStringType> {
|
|
54
|
-
* return await this.meshData.exec<Types.StringStringType>({
|
|
55
|
-
* entity: this.getEntity(),
|
|
56
|
-
* args: [{ ...input }],
|
|
57
|
-
* options: {
|
|
58
|
-
* id: input.id,
|
|
59
|
-
* ttl: '6 months',
|
|
60
|
-
* taskQueue: this.getTaskQueue(),
|
|
61
|
-
* namespace: this.getNamespace(),
|
|
62
|
-
* search: { data: { ...input }},
|
|
63
|
-
* },
|
|
64
|
-
* });
|
|
65
|
-
* }
|
|
66
|
-
* }
|
|
67
|
-
* ```
|
|
68
|
-
*
|
|
69
|
-
* ### Defining the Schema
|
|
70
|
-
*
|
|
71
|
-
* The schema defines the data model for your entity and is used for indexing and searching within the mesh network.
|
|
72
|
-
* Each field in the schema specifies the data type, whether it's required, and other indexing options.
|
|
73
|
-
*
|
|
74
|
-
* Here's an example of a schema (`schema.ts`):
|
|
75
|
-
*
|
|
76
|
-
* ```typescript
|
|
77
|
-
* import { Types } from '@hotmeshio/hotmesh';
|
|
78
|
-
*
|
|
79
|
-
* export const schema: Types.WorkflowSearchSchema = {
|
|
80
|
-
* /**
|
|
81
|
-
* * Unique identifier for the widget, including the entity prefix.
|
|
82
|
-
* *\/
|
|
83
|
-
* id: {
|
|
84
|
-
* type: 'TAG',
|
|
85
|
-
* primitive: 'string',
|
|
86
|
-
* required: true,
|
|
87
|
-
* examples: ['H56789'],
|
|
88
|
-
* },
|
|
89
|
-
* /**
|
|
90
|
-
* * entity type
|
|
91
|
-
* *\/
|
|
92
|
-
* $entity: {
|
|
93
|
-
* type: 'TAG',
|
|
94
|
-
* primitive: 'string',
|
|
95
|
-
* required: true,
|
|
96
|
-
* examples: ['widget'],
|
|
97
|
-
* },
|
|
98
|
-
* /**
|
|
99
|
-
* * Field indicating whether the widget is active ('y') or pruned ('n').
|
|
100
|
-
* *\/
|
|
101
|
-
* active: {
|
|
102
|
-
* type: 'TAG',
|
|
103
|
-
* primitive: 'string',
|
|
104
|
-
* required: true,
|
|
105
|
-
* examples: ['y', 'n'],
|
|
106
|
-
* },
|
|
107
|
-
* // ... other fields as needed
|
|
108
|
-
* };
|
|
109
|
-
* ```
|
|
110
|
-
*
|
|
111
|
-
* In your entity class (`Widget`), you use this schema in the
|
|
112
|
-
* `getSearchOptions` method to define how your entity's data
|
|
113
|
-
* is indexed and searched.
|
|
114
|
-
*/
|
|
115
|
-
class MeshOS {
|
|
116
|
-
/**
|
|
117
|
-
* Instances of MeshOS are typically initialized as a set, using a manifest.json
|
|
118
|
-
* file that describes statically the fully set names, passwords, entities, etc.
|
|
119
|
-
* The static init method is invoked to start this process (typically at server
|
|
120
|
-
* startup).
|
|
121
|
-
*/
|
|
122
|
-
constructor(providerConfig, namespace, entity, taskQueue, schema) {
|
|
123
|
-
this.connected = false;
|
|
124
|
-
this.workflow = {};
|
|
125
|
-
this.namespace = namespace; // e.g., 'sandbox', 'default', 'production'
|
|
126
|
-
this.entity = entity;
|
|
127
|
-
this.taskQueue = taskQueue;
|
|
128
|
-
this.schema = schema;
|
|
129
|
-
this.meshData = this.initializeMeshData(providerConfig);
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Return entity (e.g, book, library, user)
|
|
133
|
-
*/
|
|
134
|
-
getEntity() {
|
|
135
|
-
return this.entity;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Get Search options (initializes the search index, specific to the backend provider)
|
|
139
|
-
*/
|
|
140
|
-
getSearchOptions() {
|
|
141
|
-
return {
|
|
142
|
-
index: `${this.getNamespace()}-${this.getEntity()}`,
|
|
143
|
-
prefix: [this.getEntity()],
|
|
144
|
-
schema: this.getSchema(),
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Speficy a more-specific task queue than the default queue (v1, v1priority, v2, acmecorp, etc)
|
|
149
|
-
*/
|
|
150
|
-
getTaskQueue() {
|
|
151
|
-
return this.taskQueue;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Initialize MeshData instance (this backs/supports the class
|
|
155
|
-
* --the true provider of functionality)
|
|
156
|
-
*/
|
|
157
|
-
initializeMeshData(providerConfig) {
|
|
158
|
-
return new index_1.MeshData(providerConfig, this.getSearchOptions());
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Default target function
|
|
162
|
-
*/
|
|
163
|
-
async defaultTargetFn() {
|
|
164
|
-
return 'OK';
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Get namespace
|
|
168
|
-
*/
|
|
169
|
-
getNamespace() {
|
|
170
|
-
return this.namespace;
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Get schema
|
|
174
|
-
*/
|
|
175
|
-
getSchema() {
|
|
176
|
-
return this.schema;
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Connect to the database
|
|
180
|
-
*/
|
|
181
|
-
async connect() {
|
|
182
|
-
this.connected = await this.meshData.connect({
|
|
183
|
-
entity: this.getEntity(),
|
|
184
|
-
target: this.defaultTargetFn,
|
|
185
|
-
options: {
|
|
186
|
-
namespace: this.getNamespace(),
|
|
187
|
-
taskQueue: this.getTaskQueue(),
|
|
188
|
-
},
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Create the search index
|
|
193
|
-
*/
|
|
194
|
-
async index() {
|
|
195
|
-
await this.meshData.createSearchIndex(this.getEntity(), { namespace: this.getNamespace() }, this.getSearchOptions());
|
|
196
|
-
}
|
|
197
|
-
// On-container shutdown commands
|
|
198
|
-
/**
|
|
199
|
-
* Shutdown all connections
|
|
200
|
-
*/
|
|
201
|
-
static async shutdown() {
|
|
202
|
-
await index_1.MeshData.shutdown();
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Get index name
|
|
206
|
-
*/
|
|
207
|
-
getIndexName() {
|
|
208
|
-
return this.getSearchOptions().index;
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Create the data record
|
|
212
|
-
* NOTE: subclasses should override this method (or create
|
|
213
|
-
* an alternate method) for invoking a workflow when
|
|
214
|
-
* creating the record.
|
|
215
|
-
*/
|
|
216
|
-
async create(body) {
|
|
217
|
-
const id = body.id || (0, utils_1.guid)();
|
|
218
|
-
await this.meshData.set(this.getEntity(), id, {
|
|
219
|
-
search: { data: body },
|
|
220
|
-
namespace: this.getNamespace(),
|
|
221
|
-
});
|
|
222
|
-
return this.retrieve(id);
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Retrieve the record data
|
|
226
|
-
*/
|
|
227
|
-
async retrieve(id, sparse = false) {
|
|
228
|
-
const opts = this.getSearchOptions();
|
|
229
|
-
const fields = sparse ? ['id'] : Object.keys(opts?.schema || {});
|
|
230
|
-
const result = await this.meshData.get(this.getEntity(), id, {
|
|
231
|
-
fields,
|
|
232
|
-
namespace: this.getNamespace(),
|
|
233
|
-
});
|
|
234
|
-
if (!result?.id)
|
|
235
|
-
throw new Error(`${this.getEntity()} not found`);
|
|
236
|
-
return result;
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* Update the record data
|
|
240
|
-
*/
|
|
241
|
-
async update(id, body) {
|
|
242
|
-
await this.retrieve(id);
|
|
243
|
-
await this.meshData.set(this.getEntity(), id, {
|
|
244
|
-
search: { data: body },
|
|
245
|
-
namespace: this.getNamespace(),
|
|
246
|
-
});
|
|
247
|
-
return this.retrieve(id);
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Delete the record/workflow
|
|
251
|
-
*/
|
|
252
|
-
async delete(id) {
|
|
253
|
-
await this.retrieve(id);
|
|
254
|
-
await this.meshData.flush(this.getEntity(), id, this.getNamespace());
|
|
255
|
-
return true;
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* Find matching records
|
|
259
|
-
*/
|
|
260
|
-
async find(query = [], start = 0, size = 100) {
|
|
261
|
-
const opts = this.getSearchOptions();
|
|
262
|
-
return this.meshData.findWhere(this.getEntity(), {
|
|
263
|
-
query,
|
|
264
|
-
return: Object.keys(opts?.schema || {}),
|
|
265
|
-
limit: { start, size },
|
|
266
|
-
options: { namespace: this.getNamespace() },
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Count matching entities
|
|
271
|
-
*/
|
|
272
|
-
async count(query) {
|
|
273
|
-
return this.meshData.findWhere(this.getEntity(), {
|
|
274
|
-
query,
|
|
275
|
-
count: true,
|
|
276
|
-
options: { namespace: this.getNamespace() },
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Aggregate matching entities
|
|
281
|
-
*/
|
|
282
|
-
async aggregate(filter = [], apply = [], rows = [], columns = [], reduce = [], sort = [], start = 0, size = 100) {
|
|
283
|
-
const command = this.buildAggregateCommand(filter, apply, rows, columns, reduce, sort);
|
|
284
|
-
try {
|
|
285
|
-
const results = await this.meshData.find(this.getEntity(), {
|
|
286
|
-
index: this.getIndexName(),
|
|
287
|
-
namespace: this.getNamespace(),
|
|
288
|
-
taskQueue: this.getTaskQueue(),
|
|
289
|
-
search: this.getSearchOptions(),
|
|
290
|
-
}, ...command);
|
|
291
|
-
return {
|
|
292
|
-
count: results[0],
|
|
293
|
-
query: command.join(' '),
|
|
294
|
-
data: (0, utils_1.arrayToHash)(results),
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
catch (e) {
|
|
298
|
-
throw e;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* Build aggregate command
|
|
303
|
-
*/
|
|
304
|
-
buildAggregateCommand(filter, apply, rows, columns, reduce, sort) {
|
|
305
|
-
const command = ['FT.AGGREGATE', this.getIndexName() || 'default'];
|
|
306
|
-
const opts = this.getSearchOptions();
|
|
307
|
-
// Add filter
|
|
308
|
-
command.push(this.buildFilterCommand(filter));
|
|
309
|
-
// Add apply
|
|
310
|
-
apply.forEach((a) => command.push('APPLY', a.expression, 'AS', a.as));
|
|
311
|
-
// Add groupBy
|
|
312
|
-
const groupBy = rows.concat(columns);
|
|
313
|
-
if (groupBy.length > 0) {
|
|
314
|
-
command.push('GROUPBY', `${groupBy.length}`, ...groupBy.map((g) => opts?.schema?.[g] ? `@_${g}` : `@${g}`));
|
|
315
|
-
}
|
|
316
|
-
// Add reduce
|
|
317
|
-
reduce.forEach((r) => {
|
|
318
|
-
const op = r.operation.toUpperCase();
|
|
319
|
-
if (op === 'COUNT') {
|
|
320
|
-
command.push('REDUCE', op, '0', 'AS', r.as ?? 'count');
|
|
321
|
-
}
|
|
322
|
-
else if ([
|
|
323
|
-
'COUNT_DISTINCT',
|
|
324
|
-
'COUNT_DISTINCTISH',
|
|
325
|
-
'SUM',
|
|
326
|
-
'AVG',
|
|
327
|
-
'MIN',
|
|
328
|
-
'MAX',
|
|
329
|
-
'STDDEV',
|
|
330
|
-
'TOLIST',
|
|
331
|
-
].includes(op)) {
|
|
332
|
-
const property = r.property
|
|
333
|
-
? opts?.schema?.[r.property]
|
|
334
|
-
? `@_${r.property}`
|
|
335
|
-
: `@${r.property}`
|
|
336
|
-
: '';
|
|
337
|
-
command.push('REDUCE', op, '1', property, 'AS', r.as ?? `${r.operation}_${r.property}`);
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
// Add sort
|
|
341
|
-
if (sort.length > 0) {
|
|
342
|
-
command.push('SORTBY', `${2 * sort.length}`, ...sort.flatMap((s) => [
|
|
343
|
-
opts?.schema?.[s.field] ? `@_${s.field}` : `@${s.field}`,
|
|
344
|
-
s.order.toUpperCase() || 'DESC',
|
|
345
|
-
]));
|
|
346
|
-
}
|
|
347
|
-
return command;
|
|
348
|
-
}
|
|
349
|
-
/**
|
|
350
|
-
* Build filter command
|
|
351
|
-
*/
|
|
352
|
-
buildFilterCommand(filter) {
|
|
353
|
-
if (filter.length === 0)
|
|
354
|
-
return '*';
|
|
355
|
-
const opts = this.getSearchOptions();
|
|
356
|
-
return filter
|
|
357
|
-
.map((q) => {
|
|
358
|
-
const type = opts?.schema?.[q.field]?.type ?? 'TEXT';
|
|
359
|
-
switch (type) {
|
|
360
|
-
case 'TAG':
|
|
361
|
-
return `@_${q.field}:{${q.value}}`;
|
|
362
|
-
case 'TEXT':
|
|
363
|
-
return `@_${q.field}:${q.value}`;
|
|
364
|
-
case 'NUMERIC':
|
|
365
|
-
return `@_${q.field}:[${q.value}]`;
|
|
366
|
-
}
|
|
367
|
-
})
|
|
368
|
-
.join(' ');
|
|
369
|
-
}
|
|
370
|
-
/**
|
|
371
|
-
* Instance initializer
|
|
372
|
-
*/
|
|
373
|
-
async init(search = true) {
|
|
374
|
-
await this.connect();
|
|
375
|
-
if (search) {
|
|
376
|
-
await this.index();
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
// Static registration methods
|
|
380
|
-
/**
|
|
381
|
-
* Register a database
|
|
382
|
-
*/
|
|
383
|
-
static registerDatabase(id, config) {
|
|
384
|
-
MeshOS.databases[id] = config;
|
|
385
|
-
}
|
|
386
|
-
/**
|
|
387
|
-
* Register a namespace
|
|
388
|
-
*/
|
|
389
|
-
static registerNamespace(id, config) {
|
|
390
|
-
MeshOS.namespaces[id] = config;
|
|
391
|
-
}
|
|
392
|
-
/**
|
|
393
|
-
* Register an entity
|
|
394
|
-
*/
|
|
395
|
-
static registerEntity(id, config) {
|
|
396
|
-
MeshOS.entities[id] = config;
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Register a schema
|
|
400
|
-
*/
|
|
401
|
-
static registerSchema(id, schema) {
|
|
402
|
-
MeshOS.schemas[id] = schema;
|
|
403
|
-
}
|
|
404
|
-
/**
|
|
405
|
-
* Register a profile
|
|
406
|
-
*/
|
|
407
|
-
static registerProfile(id, config) {
|
|
408
|
-
MeshOS.profiles[id] = config;
|
|
409
|
-
}
|
|
410
|
-
/**
|
|
411
|
-
* Register a class
|
|
412
|
-
*/
|
|
413
|
-
static registerClass(id, entityClass) {
|
|
414
|
-
MeshOS.classes[id] = entityClass;
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* Initialize profiles
|
|
418
|
-
*/
|
|
419
|
-
static async init(p = MeshOS.profiles) {
|
|
420
|
-
for (const key in p) {
|
|
421
|
-
const profile = p[key];
|
|
422
|
-
if (profile.db?.connection) {
|
|
423
|
-
MeshOS.logger.info(`meshos-initializing`, {
|
|
424
|
-
db: profile.db.name,
|
|
425
|
-
key,
|
|
426
|
-
});
|
|
427
|
-
profile.instances = {};
|
|
428
|
-
for (const ns in profile.namespaces) {
|
|
429
|
-
const namespace = profile.namespaces[ns];
|
|
430
|
-
MeshOS.logger.info(`meshos-initializing-namespace`, {
|
|
431
|
-
namespace: ns,
|
|
432
|
-
label: namespace.label,
|
|
433
|
-
});
|
|
434
|
-
let pinstances = profile.instances[ns];
|
|
435
|
-
if (!pinstances) {
|
|
436
|
-
pinstances = {};
|
|
437
|
-
profile.instances[ns] = pinstances;
|
|
438
|
-
}
|
|
439
|
-
for (const entity of namespace.entities) {
|
|
440
|
-
MeshOS.logger.info(`meshos-initializing-entity`, {
|
|
441
|
-
entity: entity.name,
|
|
442
|
-
label: entity.label,
|
|
443
|
-
});
|
|
444
|
-
const instance = pinstances[entity.name] = new entity.class(profile.db.connection, ns, entity.name, entity.taskQueue, entity.schema);
|
|
445
|
-
await instance.init(profile.db.search);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
/**
|
|
452
|
-
* Find entity instance
|
|
453
|
-
*/
|
|
454
|
-
static findEntity(database, namespace, entity) {
|
|
455
|
-
if (!database || !MeshOS.profiles[database]) {
|
|
456
|
-
const activeProfiles = Object.keys(MeshOS.profiles).filter((key) => MeshOS.profiles[key]?.db);
|
|
457
|
-
throw new Error(`The database query parameter [${database}] was not found. Use one of: ${activeProfiles.join(', ')}`);
|
|
458
|
-
}
|
|
459
|
-
if (!namespace || !MeshOS.profiles[database]?.instances?.[namespace]) {
|
|
460
|
-
const activeNamespaces = Object.keys(MeshOS.profiles[database]?.instances ?? {});
|
|
461
|
-
throw new Error(`The namespace query parameter [${namespace}] was not found. Use one of: ${activeNamespaces.join(', ')}`);
|
|
462
|
-
}
|
|
463
|
-
const entities = MeshOS.profiles[database]?.instances?.[namespace] ?? {};
|
|
464
|
-
if (!entity || entity?.startsWith('-') || entity === '*') {
|
|
465
|
-
entity = Object.keys(entities)[0];
|
|
466
|
-
}
|
|
467
|
-
else if (entity?.endsWith('*')) {
|
|
468
|
-
entity = entity.slice(0, -1);
|
|
469
|
-
}
|
|
470
|
-
const target = MeshOS.profiles[database]?.instances?.[namespace]?.[entity];
|
|
471
|
-
if (!target) {
|
|
472
|
-
const fallback = Object.keys(entities)[0];
|
|
473
|
-
MeshOS.logger.error(`meshos-entity-not-found`, {
|
|
474
|
-
database,
|
|
475
|
-
namespace,
|
|
476
|
-
entity,
|
|
477
|
-
fallback,
|
|
478
|
-
});
|
|
479
|
-
return MeshOS.profiles[database]?.instances?.[namespace]?.[fallback];
|
|
480
|
-
}
|
|
481
|
-
return target;
|
|
482
|
-
}
|
|
483
|
-
/**
|
|
484
|
-
* Find schemas
|
|
485
|
-
*/
|
|
486
|
-
static findSchemas(database, ns) {
|
|
487
|
-
if (!database || !MeshOS.profiles[database]) {
|
|
488
|
-
const activeProfiles = Object.keys(MeshOS.profiles).filter((key) => MeshOS.profiles[key]?.db);
|
|
489
|
-
throw new Error(`The database query parameter [${database}] was not found. Use one of: ${activeProfiles.join(', ')}`);
|
|
490
|
-
}
|
|
491
|
-
const profile = MeshOS.profiles[database];
|
|
492
|
-
const namespacedInstance = profile.instances[ns];
|
|
493
|
-
const schemas = {};
|
|
494
|
-
for (const entityName in namespacedInstance) {
|
|
495
|
-
const entityInstance = namespacedInstance[entityName];
|
|
496
|
-
const opts = entityInstance.getSearchOptions();
|
|
497
|
-
schemas[opts.index ?? entityName] = opts.schema;
|
|
498
|
-
}
|
|
499
|
-
return schemas;
|
|
500
|
-
}
|
|
501
|
-
/**
|
|
502
|
-
* Serialize profiles to JSON
|
|
503
|
-
*/
|
|
504
|
-
static toJSON(p = MeshOS.profiles) {
|
|
505
|
-
const result = {};
|
|
506
|
-
for (const key in p) {
|
|
507
|
-
const profile = p[key];
|
|
508
|
-
if (!profile.db) {
|
|
509
|
-
continue;
|
|
510
|
-
}
|
|
511
|
-
else {
|
|
512
|
-
// Remove the sensitive `connection` field if present
|
|
513
|
-
const { connection, ...dbWithoutConnection } = profile.db;
|
|
514
|
-
result[key] = {
|
|
515
|
-
db: { ...dbWithoutConnection },
|
|
516
|
-
namespaces: {},
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
for (const ns in profile.namespaces) {
|
|
520
|
-
const namespace = profile.namespaces[ns];
|
|
521
|
-
result[key].namespaces[ns] = {
|
|
522
|
-
name: namespace.name,
|
|
523
|
-
label: namespace.label,
|
|
524
|
-
module: namespace.module,
|
|
525
|
-
entities: [],
|
|
526
|
-
};
|
|
527
|
-
for (const entity of namespace.entities) {
|
|
528
|
-
result[key].namespaces[ns].entities.push({
|
|
529
|
-
name: entity.name,
|
|
530
|
-
label: entity.label,
|
|
531
|
-
schema: entity.schema,
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
return result;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
exports.MeshOS = MeshOS;
|
|
540
|
-
// Static properties
|
|
541
|
-
MeshOS.databases = {};
|
|
542
|
-
MeshOS.namespaces = {};
|
|
543
|
-
MeshOS.entities = {};
|
|
544
|
-
MeshOS.schemas = {};
|
|
545
|
-
MeshOS.profiles = {};
|
|
546
|
-
MeshOS.classes = {};
|
|
547
|
-
MeshOS.logger = new logger_1.LoggerService('hotmesh', 'meshos');
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { MeshOS } from '../services/meshos';
|
|
2
|
-
import { WorkflowSearchSchema } from './memflow';
|
|
3
|
-
import { ProviderConfig, ProvidersConfig } from './provider';
|
|
4
|
-
export type DB = {
|
|
5
|
-
name: string;
|
|
6
|
-
label: string;
|
|
7
|
-
search: boolean;
|
|
8
|
-
connection: ProviderConfig | ProvidersConfig;
|
|
9
|
-
};
|
|
10
|
-
export type SubClassInstance<T extends typeof MeshOS> = T extends abstract new (...args: any) => infer R ? R : never;
|
|
11
|
-
export type AllSubclassInstances = SubClassInstance<(typeof MeshOS)['classes'][keyof (typeof MeshOS)['classes']]>;
|
|
12
|
-
export type EntityInstanceTypes = MeshOS;
|
|
13
|
-
export type SubclassType<T extends MeshOS = MeshOS> = new (...args: any[]) => T;
|
|
14
|
-
export type Entity = {
|
|
15
|
-
name: string;
|
|
16
|
-
label: string;
|
|
17
|
-
/**
|
|
18
|
-
* A more-specific value for workers when targeting version-specifc
|
|
19
|
-
* or priority-specific task queues.
|
|
20
|
-
* @default default
|
|
21
|
-
*/
|
|
22
|
-
taskQueue?: string;
|
|
23
|
-
schema: WorkflowSearchSchema;
|
|
24
|
-
class: SubclassType;
|
|
25
|
-
};
|
|
26
|
-
export type Namespace = {
|
|
27
|
-
name: string;
|
|
28
|
-
/**
|
|
29
|
-
* @deprecated; unused; name is the type; label is human-readable
|
|
30
|
-
*/
|
|
31
|
-
type: string;
|
|
32
|
-
label: string;
|
|
33
|
-
module: 'hotmesh' | 'meshcall' | 'memflow' | 'meshdata' | 'meshos';
|
|
34
|
-
entities: Entity[];
|
|
35
|
-
};
|
|
36
|
-
export type Namespaces = {
|
|
37
|
-
[key: string]: Namespace;
|
|
38
|
-
};
|
|
39
|
-
export type Instance = {
|
|
40
|
-
[key: string]: EntityInstanceTypes;
|
|
41
|
-
};
|
|
42
|
-
export type Instances = {
|
|
43
|
-
[key: string]: Instance;
|
|
44
|
-
};
|
|
45
|
-
export type Profile = {
|
|
46
|
-
db: DB;
|
|
47
|
-
namespaces: Namespaces;
|
|
48
|
-
instances?: Instances;
|
|
49
|
-
};
|
|
50
|
-
export type Profiles = {
|
|
51
|
-
[key: string]: Profile;
|
|
52
|
-
};
|
package/build/types/manifest.js
DELETED