@kubun/protocol 0.4.0 → 0.5.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/lib/index.d.ts +3 -2
- package/lib/index.js +1 -8
- package/lib/models/cluster.d.ts +36 -1
- package/lib/models/cluster.js +1 -132
- package/lib/models/document.d.ts +153 -1
- package/lib/models/document.js +1 -525
- package/lib/models/graph.d.ts +0 -1
- package/lib/models/graph.js +1 -52
- package/lib/models/json-schema.d.ts +0 -1
- package/lib/models/json-schema.js +1 -320
- package/lib/models/value.d.ts +0 -1
- package/lib/models/value.js +1 -16
- package/lib/services/document.d.ts +0 -1
- package/lib/services/document.js +1 -50
- package/lib/services/graph.d.ts +1913 -1660
- package/lib/services/graph.js +1 -239
- package/lib/services/sync.d.ts +182 -0
- package/lib/services/sync.js +1 -0
- package/lib/types.d.ts +0 -1
- package/lib/types.js +1 -1
- package/package.json +6 -6
- package/lib/index.d.ts.map +0 -1
- package/lib/models/cluster.d.ts.map +0 -1
- package/lib/models/document.d.ts.map +0 -1
- package/lib/models/graph.d.ts.map +0 -1
- package/lib/models/json-schema.d.ts.map +0 -1
- package/lib/models/value.d.ts.map +0 -1
- package/lib/services/document.d.ts.map +0 -1
- package/lib/services/graph.d.ts.map +0 -1
- package/lib/types.d.ts.map +0 -1
package/lib/models/document.js
CHANGED
|
@@ -1,525 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { DocumentModelID, ScalarModelID, ShapeModelID } from '@kubun/id';
|
|
3
|
-
import { pascalCase } from 'change-case';
|
|
4
|
-
import { baseObjectModel, nameString, referencesRecordModel } from './json-schema.js';
|
|
5
|
-
import { binaryStringValue, didStringValue } from './value.js';
|
|
6
|
-
export const documentModelVersion = {
|
|
7
|
-
type: 'string',
|
|
8
|
-
const: '1.0'
|
|
9
|
-
};
|
|
10
|
-
export const documentFieldMetaAccount = {
|
|
11
|
-
type: 'object',
|
|
12
|
-
properties: {
|
|
13
|
-
type: {
|
|
14
|
-
type: 'string',
|
|
15
|
-
const: 'account'
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
required: [
|
|
19
|
-
'type'
|
|
20
|
-
],
|
|
21
|
-
additionalProperties: false
|
|
22
|
-
};
|
|
23
|
-
export const documentFieldMetaAttachment = {
|
|
24
|
-
type: 'object',
|
|
25
|
-
properties: {
|
|
26
|
-
type: {
|
|
27
|
-
type: 'string',
|
|
28
|
-
const: 'attachment'
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
required: [
|
|
32
|
-
'type'
|
|
33
|
-
],
|
|
34
|
-
additionalProperties: false
|
|
35
|
-
};
|
|
36
|
-
export const documentFieldMetaDocument = {
|
|
37
|
-
type: 'object',
|
|
38
|
-
properties: {
|
|
39
|
-
type: {
|
|
40
|
-
type: 'string',
|
|
41
|
-
const: 'document'
|
|
42
|
-
},
|
|
43
|
-
model: {
|
|
44
|
-
anyOf: [
|
|
45
|
-
{
|
|
46
|
-
type: 'string'
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
type: 'null'
|
|
50
|
-
}
|
|
51
|
-
]
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
required: [
|
|
55
|
-
'type',
|
|
56
|
-
'model'
|
|
57
|
-
],
|
|
58
|
-
additionalProperties: false
|
|
59
|
-
};
|
|
60
|
-
export const documentFieldMeta = {
|
|
61
|
-
anyOf: [
|
|
62
|
-
documentFieldMetaAccount,
|
|
63
|
-
documentFieldMetaAttachment,
|
|
64
|
-
documentFieldMetaDocument
|
|
65
|
-
]
|
|
66
|
-
};
|
|
67
|
-
export const documentFieldsMeta = {
|
|
68
|
-
type: 'object',
|
|
69
|
-
additionalProperties: documentFieldMeta
|
|
70
|
-
};
|
|
71
|
-
export const documentModelSchema = {
|
|
72
|
-
type: 'object',
|
|
73
|
-
properties: {
|
|
74
|
-
...baseObjectModel.properties,
|
|
75
|
-
$defs: referencesRecordModel
|
|
76
|
-
},
|
|
77
|
-
required: [
|
|
78
|
-
...baseObjectModel.required,
|
|
79
|
-
'$defs'
|
|
80
|
-
],
|
|
81
|
-
additionalProperties: false
|
|
82
|
-
};
|
|
83
|
-
export const documentModelBase = {
|
|
84
|
-
type: 'object',
|
|
85
|
-
properties: {
|
|
86
|
-
name: nameString,
|
|
87
|
-
version: documentModelVersion,
|
|
88
|
-
interfaces: {
|
|
89
|
-
type: 'array',
|
|
90
|
-
items: {
|
|
91
|
-
type: 'string'
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
schema: documentModelSchema,
|
|
95
|
-
fieldsMeta: documentFieldsMeta
|
|
96
|
-
},
|
|
97
|
-
required: [
|
|
98
|
-
'name',
|
|
99
|
-
'version',
|
|
100
|
-
'interfaces',
|
|
101
|
-
'schema',
|
|
102
|
-
'fieldsMeta'
|
|
103
|
-
],
|
|
104
|
-
additionalProperties: false
|
|
105
|
-
};
|
|
106
|
-
export const documentModelDefault = {
|
|
107
|
-
type: 'object',
|
|
108
|
-
properties: {
|
|
109
|
-
...documentModelBase.properties,
|
|
110
|
-
behavior: {
|
|
111
|
-
type: 'string',
|
|
112
|
-
const: 'default'
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
required: [
|
|
116
|
-
...documentModelBase.required,
|
|
117
|
-
'behavior'
|
|
118
|
-
],
|
|
119
|
-
additionalProperties: false
|
|
120
|
-
};
|
|
121
|
-
export const documentModelInterface = {
|
|
122
|
-
type: 'object',
|
|
123
|
-
properties: {
|
|
124
|
-
...documentModelBase.properties,
|
|
125
|
-
behavior: {
|
|
126
|
-
type: 'string',
|
|
127
|
-
const: 'interface'
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
required: [
|
|
131
|
-
...documentModelBase.required,
|
|
132
|
-
'behavior'
|
|
133
|
-
],
|
|
134
|
-
additionalProperties: false
|
|
135
|
-
};
|
|
136
|
-
export const documentModelUnique = {
|
|
137
|
-
type: 'object',
|
|
138
|
-
properties: {
|
|
139
|
-
...documentModelBase.properties,
|
|
140
|
-
behavior: {
|
|
141
|
-
type: 'string',
|
|
142
|
-
const: 'unique'
|
|
143
|
-
},
|
|
144
|
-
uniqueFields: {
|
|
145
|
-
type: 'array',
|
|
146
|
-
items: {
|
|
147
|
-
type: 'string'
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
required: [
|
|
152
|
-
...documentModelBase.required,
|
|
153
|
-
'behavior',
|
|
154
|
-
'uniqueFields'
|
|
155
|
-
],
|
|
156
|
-
additionalProperties: false
|
|
157
|
-
};
|
|
158
|
-
export const documentModel = {
|
|
159
|
-
$id: 'urn:kubun:protocol:model:document',
|
|
160
|
-
anyOf: [
|
|
161
|
-
documentModelDefault,
|
|
162
|
-
documentModelInterface,
|
|
163
|
-
documentModelUnique
|
|
164
|
-
]
|
|
165
|
-
};
|
|
166
|
-
export const documentModelsCluster = {
|
|
167
|
-
type: 'array',
|
|
168
|
-
items: documentModel
|
|
169
|
-
};
|
|
170
|
-
export const documentModelsRecord = {
|
|
171
|
-
type: 'object',
|
|
172
|
-
additionalProperties: documentModel
|
|
173
|
-
};
|
|
174
|
-
export const setDocumentMutation = {
|
|
175
|
-
$id: 'urn:kubun:protocol:mutation:set',
|
|
176
|
-
type: 'object',
|
|
177
|
-
properties: {
|
|
178
|
-
typ: {
|
|
179
|
-
type: 'string',
|
|
180
|
-
const: 'set'
|
|
181
|
-
},
|
|
182
|
-
iss: didStringValue,
|
|
183
|
-
aud: didStringValue,
|
|
184
|
-
sub: {
|
|
185
|
-
type: 'string'
|
|
186
|
-
},
|
|
187
|
-
data: {
|
|
188
|
-
anyOf: [
|
|
189
|
-
binaryStringValue,
|
|
190
|
-
{
|
|
191
|
-
type: 'null'
|
|
192
|
-
}
|
|
193
|
-
]
|
|
194
|
-
},
|
|
195
|
-
unq: binaryStringValue,
|
|
196
|
-
cap: {
|
|
197
|
-
anyOf: [
|
|
198
|
-
{
|
|
199
|
-
type: 'string'
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
type: 'array',
|
|
203
|
-
items: {
|
|
204
|
-
type: 'string'
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
]
|
|
208
|
-
}
|
|
209
|
-
},
|
|
210
|
-
required: [
|
|
211
|
-
'iss',
|
|
212
|
-
'sub',
|
|
213
|
-
'typ',
|
|
214
|
-
'data',
|
|
215
|
-
'unq'
|
|
216
|
-
],
|
|
217
|
-
additionalProperties: false
|
|
218
|
-
};
|
|
219
|
-
export const changeDocumentMutation = {
|
|
220
|
-
$id: 'urn:kubun:protocol:mutation:change',
|
|
221
|
-
type: 'object',
|
|
222
|
-
properties: {
|
|
223
|
-
typ: {
|
|
224
|
-
type: 'string',
|
|
225
|
-
const: 'change'
|
|
226
|
-
},
|
|
227
|
-
iss: didStringValue,
|
|
228
|
-
sub: {
|
|
229
|
-
type: 'string'
|
|
230
|
-
},
|
|
231
|
-
data: {
|
|
232
|
-
anyOf: [
|
|
233
|
-
binaryStringValue,
|
|
234
|
-
{
|
|
235
|
-
type: 'null'
|
|
236
|
-
}
|
|
237
|
-
]
|
|
238
|
-
},
|
|
239
|
-
inc: {
|
|
240
|
-
type: 'boolean'
|
|
241
|
-
},
|
|
242
|
-
cap: {
|
|
243
|
-
anyOf: [
|
|
244
|
-
{
|
|
245
|
-
type: 'string'
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
type: 'array',
|
|
249
|
-
items: {
|
|
250
|
-
type: 'string'
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
]
|
|
254
|
-
}
|
|
255
|
-
},
|
|
256
|
-
required: [
|
|
257
|
-
'iss',
|
|
258
|
-
'sub',
|
|
259
|
-
'typ',
|
|
260
|
-
'data',
|
|
261
|
-
'inc'
|
|
262
|
-
],
|
|
263
|
-
additionalProperties: false
|
|
264
|
-
};
|
|
265
|
-
export const documentMutation = {
|
|
266
|
-
$id: 'urn:kubun:protocol:mutation',
|
|
267
|
-
anyOf: [
|
|
268
|
-
setDocumentMutation,
|
|
269
|
-
changeDocumentMutation
|
|
270
|
-
]
|
|
271
|
-
};
|
|
272
|
-
// Normalization logic
|
|
273
|
-
export const validateDocumentModel = createValidator(documentModel);
|
|
274
|
-
export const REFERENCE_PREFIX = '#/$defs/';
|
|
275
|
-
function toReference(id) {
|
|
276
|
-
return `${REFERENCE_PREFIX}${id}`;
|
|
277
|
-
}
|
|
278
|
-
const JSONObjectSchema = {
|
|
279
|
-
type: 'object',
|
|
280
|
-
title: 'JSONObject',
|
|
281
|
-
additionalProperties: true
|
|
282
|
-
};
|
|
283
|
-
const LOCAL_ID_REGEXP = /^#([0-9]+)$/;
|
|
284
|
-
// TODO: add fieldsMeta for account and attachment when walking the schema
|
|
285
|
-
export class DocumentModelNormalizer {
|
|
286
|
-
#inputModel;
|
|
287
|
-
#interfaces = new Set();
|
|
288
|
-
#logger;
|
|
289
|
-
#normalizedSchema;
|
|
290
|
-
#refs;
|
|
291
|
-
#root;
|
|
292
|
-
#schemaProperties = {};
|
|
293
|
-
#schemaReferences = {};
|
|
294
|
-
#schemaRequired = new Set();
|
|
295
|
-
#fieldsMeta = {};
|
|
296
|
-
constructor(params){
|
|
297
|
-
this.#inputModel = params.inputModel;
|
|
298
|
-
this.#logger = params.logger;
|
|
299
|
-
const inputSchema = params.inputModel.schema ?? {};
|
|
300
|
-
this.#processInterfaces(params.interfaceModels);
|
|
301
|
-
this.#processMeta(inputSchema, params.normalizedInterfaceIDs);
|
|
302
|
-
this.#refs = inputSchema.$defs ?? {};
|
|
303
|
-
this.#root = {
|
|
304
|
-
...inputSchema,
|
|
305
|
-
type: 'object',
|
|
306
|
-
properties: this.#schemaProperties,
|
|
307
|
-
required: Array.from(this.#schemaRequired),
|
|
308
|
-
additionalProperties: false,
|
|
309
|
-
$defs: {
|
|
310
|
-
...inputSchema.$defs,
|
|
311
|
-
...this.#schemaReferences
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
this.#normalizedSchema = this.#normalizeSchema();
|
|
315
|
-
this.#processFieldsMeta();
|
|
316
|
-
}
|
|
317
|
-
#processInterfaces(interfaceModels) {
|
|
318
|
-
// Add interface fields
|
|
319
|
-
for (const interfaceModel of interfaceModels){
|
|
320
|
-
for (const interfaceID of interfaceModel.interfaces){
|
|
321
|
-
this.#interfaces.add(interfaceID);
|
|
322
|
-
}
|
|
323
|
-
for (const requiredKey of interfaceModel.schema.required){
|
|
324
|
-
this.#schemaRequired.add(requiredKey);
|
|
325
|
-
}
|
|
326
|
-
Object.assign(this.#schemaProperties, interfaceModel.schema.properties);
|
|
327
|
-
Object.assign(this.#schemaReferences, interfaceModel.schema.$defs);
|
|
328
|
-
Object.assign(this.#fieldsMeta, interfaceModel.fieldsMeta ?? {});
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
#processMeta(inputSchema, normalizedInterfaceIDs) {
|
|
332
|
-
for (const interfaceID of normalizedInterfaceIDs){
|
|
333
|
-
this.#interfaces.add(interfaceID);
|
|
334
|
-
}
|
|
335
|
-
for (const requiredKey of inputSchema.required ?? []){
|
|
336
|
-
this.#schemaRequired.add(requiredKey);
|
|
337
|
-
}
|
|
338
|
-
Object.assign(this.#schemaProperties, inputSchema.properties ?? {});
|
|
339
|
-
Object.assign(this.#fieldsMeta, this.#inputModel.fieldsMeta ?? {});
|
|
340
|
-
}
|
|
341
|
-
#normalizeSchema() {
|
|
342
|
-
const schema = this.#root;
|
|
343
|
-
const entries = Object.entries(schema.properties ?? {});
|
|
344
|
-
if (entries.length === 0) {
|
|
345
|
-
throw new Error('Document schema must contain at least one property');
|
|
346
|
-
}
|
|
347
|
-
const properties = {};
|
|
348
|
-
for (const [key, value] of entries){
|
|
349
|
-
properties[key] = {
|
|
350
|
-
$ref: this.#encodeSchema(key, value)
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
return {
|
|
354
|
-
type: 'object',
|
|
355
|
-
properties,
|
|
356
|
-
additionalProperties: false,
|
|
357
|
-
required: schema.required ?? [],
|
|
358
|
-
$defs: this.#refs
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
#encodeSchema(fieldKey, schema) {
|
|
362
|
-
if (schema.$ref != null) {
|
|
363
|
-
const resolvedSchema = this.#resolveReference(schema.$ref);
|
|
364
|
-
return this.#encodeSchema(fieldKey, resolvedSchema);
|
|
365
|
-
}
|
|
366
|
-
const type = schema.type;
|
|
367
|
-
if (type == null) {
|
|
368
|
-
throw new Error('Invalid schema: missing type');
|
|
369
|
-
}
|
|
370
|
-
switch(type){
|
|
371
|
-
case 'array':
|
|
372
|
-
{
|
|
373
|
-
if (schema.title == null) {
|
|
374
|
-
throw new Error('Invalid array schema: missing title');
|
|
375
|
-
}
|
|
376
|
-
if (schema.items == null) {
|
|
377
|
-
throw new Error('Invalid array schema: missing items');
|
|
378
|
-
}
|
|
379
|
-
const { default: _, ...rest } = schema;
|
|
380
|
-
return this.#addShape({
|
|
381
|
-
...rest,
|
|
382
|
-
title: pascalCase(schema.title),
|
|
383
|
-
items: {
|
|
384
|
-
$ref: this.#encodeSchema(fieldKey, schema.items)
|
|
385
|
-
}
|
|
386
|
-
});
|
|
387
|
-
}
|
|
388
|
-
case 'object':
|
|
389
|
-
{
|
|
390
|
-
if (schema.additionalProperties) {
|
|
391
|
-
return this.#addShape(JSONObjectSchema);
|
|
392
|
-
}
|
|
393
|
-
if (schema.title == null) {
|
|
394
|
-
throw new Error('Invalid object schema: missing title');
|
|
395
|
-
}
|
|
396
|
-
const entries = Object.entries(schema.properties ?? {});
|
|
397
|
-
if (entries.length === 0) {
|
|
398
|
-
throw new Error('Invalid object schema: must contain at least one property');
|
|
399
|
-
}
|
|
400
|
-
const properties = {};
|
|
401
|
-
for (const [key, value] of entries){
|
|
402
|
-
properties[key] = {
|
|
403
|
-
$ref: this.#encodeSchema(key, value)
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
return this.#addShape({
|
|
407
|
-
type: 'object',
|
|
408
|
-
title: pascalCase(schema.title),
|
|
409
|
-
properties,
|
|
410
|
-
required: schema.required ?? [],
|
|
411
|
-
additionalProperties: false
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
|
-
default:
|
|
415
|
-
return this.#addScalar(fieldKey, schema);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
#resolveReference(ref) {
|
|
419
|
-
if (!ref.startsWith('#')) {
|
|
420
|
-
throw new Error(`Invalid reference format: ${ref}`);
|
|
421
|
-
}
|
|
422
|
-
// Handle #/$defs/ references
|
|
423
|
-
if (ref.startsWith(REFERENCE_PREFIX)) {
|
|
424
|
-
const key = ref.slice(REFERENCE_PREFIX.length);
|
|
425
|
-
const resolved = this.#root.$defs?.[key];
|
|
426
|
-
if (resolved == null) {
|
|
427
|
-
throw new Error(`Reference not found: ${ref}`);
|
|
428
|
-
}
|
|
429
|
-
return resolved;
|
|
430
|
-
}
|
|
431
|
-
// Handle other JSON Schema references like #/properties/, #/items/, etc.
|
|
432
|
-
const segments = ref.split('/').slice(1);
|
|
433
|
-
// biome-ignore lint/suspicious/noExplicitAny: mixed type
|
|
434
|
-
let current = this.#root;
|
|
435
|
-
for (const segment of segments){
|
|
436
|
-
if (current == null || typeof current !== 'object') {
|
|
437
|
-
throw new Error(`Invalid reference path: ${ref}`);
|
|
438
|
-
}
|
|
439
|
-
current = current[segment];
|
|
440
|
-
if (current == null) {
|
|
441
|
-
throw new Error(`Reference not found: ${ref}`);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
return current;
|
|
445
|
-
}
|
|
446
|
-
#addScalar(fieldKey, schema) {
|
|
447
|
-
const id = ScalarModelID.create(schema);
|
|
448
|
-
let normalizedSchema = schema;
|
|
449
|
-
if (schema.type === 'boolean') {
|
|
450
|
-
const { title: _, ...rest } = schema;
|
|
451
|
-
normalizedSchema = rest;
|
|
452
|
-
} else if (schema.title != null) {
|
|
453
|
-
const lowerCaseTitle = schema.title.toLowerCase();
|
|
454
|
-
if (lowerCaseTitle === 'attachmentid') {
|
|
455
|
-
this.#fieldsMeta[fieldKey] = {
|
|
456
|
-
type: 'attachment'
|
|
457
|
-
};
|
|
458
|
-
normalizedSchema = {
|
|
459
|
-
...schema,
|
|
460
|
-
title: 'attachmentid'
|
|
461
|
-
};
|
|
462
|
-
} else if (lowerCaseTitle === 'did') {
|
|
463
|
-
this.#fieldsMeta[fieldKey] = {
|
|
464
|
-
type: 'account'
|
|
465
|
-
};
|
|
466
|
-
normalizedSchema = {
|
|
467
|
-
...schema,
|
|
468
|
-
title: 'did'
|
|
469
|
-
};
|
|
470
|
-
} else if (lowerCaseTitle === 'docid') {
|
|
471
|
-
if (this.#fieldsMeta[fieldKey] == null) {
|
|
472
|
-
this.#logger.warn('Missing fieldMeta entry for document reference {fieldKey} of model {inputModel}', {
|
|
473
|
-
fieldKey,
|
|
474
|
-
inputModel: this.#inputModel
|
|
475
|
-
});
|
|
476
|
-
this.#fieldsMeta[fieldKey] = {
|
|
477
|
-
type: 'document',
|
|
478
|
-
model: null
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
normalizedSchema = {
|
|
482
|
-
...schema,
|
|
483
|
-
title: 'docid'
|
|
484
|
-
};
|
|
485
|
-
} else {
|
|
486
|
-
normalizedSchema = {
|
|
487
|
-
...schema,
|
|
488
|
-
title: pascalCase(schema.title)
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
this.#refs[id.toString()] = normalizedSchema;
|
|
493
|
-
return toReference(id);
|
|
494
|
-
}
|
|
495
|
-
#addShape(schema) {
|
|
496
|
-
const id = ShapeModelID.create(schema);
|
|
497
|
-
this.#refs[id.toString()] = schema;
|
|
498
|
-
return toReference(id);
|
|
499
|
-
}
|
|
500
|
-
#processFieldsMeta() {
|
|
501
|
-
// Convert model relations by index to local IDs
|
|
502
|
-
for (const [key, field] of Object.entries(this.#fieldsMeta)){
|
|
503
|
-
if (field.type !== 'document' || field.model === null) {
|
|
504
|
-
continue;
|
|
505
|
-
}
|
|
506
|
-
const match = field.model.match(LOCAL_ID_REGEXP);
|
|
507
|
-
if (match != null) {
|
|
508
|
-
this.#fieldsMeta[key] = {
|
|
509
|
-
...field,
|
|
510
|
-
model: DocumentModelID.local(Number.parseInt(match[1], 10)).toString()
|
|
511
|
-
};
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
toDocumentModel() {
|
|
516
|
-
return asType(validateDocumentModel, {
|
|
517
|
-
version: '1.0',
|
|
518
|
-
behavior: 'default',
|
|
519
|
-
...this.#inputModel,
|
|
520
|
-
interfaces: Array.from(this.#interfaces),
|
|
521
|
-
schema: this.#normalizedSchema,
|
|
522
|
-
fieldsMeta: this.#fieldsMeta
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
}
|
|
1
|
+
import{asType as e,createValidator as t}from"@enkaku/schema";import{DocumentModelID as r,ScalarModelID as o,ShapeModelID as i}from"@kubun/id";import{pascalCase as s}from"change-case";import{baseObjectModel as n,nameString as a,referencesRecordModel as d}from"./json-schema.js";import{binaryStringValue as c,didStringValue as l}from"./value.js";export const documentModelVersion={type:"string",const:"1.0"};export const documentFieldMetaAccount={type:"object",properties:{type:{type:"string",const:"account"},searchable:{type:"boolean"}},required:["type"],additionalProperties:!1};export const documentFieldMetaAttachment={type:"object",properties:{type:{type:"string",const:"attachment"},searchable:{type:"boolean"}},required:["type"],additionalProperties:!1};export const documentFieldMetaDocument={type:"object",properties:{type:{type:"string",const:"document"},model:{anyOf:[{type:"string"},{type:"null"}]},searchable:{type:"boolean"}},required:["type","model"],additionalProperties:!1};export const documentFieldMeta={anyOf:[documentFieldMetaAccount,documentFieldMetaAttachment,documentFieldMetaDocument]};export const documentFieldsMeta={type:"object",additionalProperties:documentFieldMeta};export const documentModelSchema={type:"object",properties:{...n.properties,$defs:d},required:[...n.required,"$defs"],additionalProperties:!1};export const documentModelBase={type:"object",properties:{name:a,version:documentModelVersion,interfaces:{type:"array",items:{type:"string"}},schema:documentModelSchema,fieldsMeta:documentFieldsMeta},required:["name","version","interfaces","schema","fieldsMeta"],additionalProperties:!1};export const documentModelDefault={type:"object",properties:{...documentModelBase.properties,behavior:{type:"string",const:"default"}},required:[...documentModelBase.required,"behavior"],additionalProperties:!1};export const documentModelInterface={type:"object",properties:{...documentModelBase.properties,behavior:{type:"string",const:"interface"}},required:[...documentModelBase.required,"behavior"],additionalProperties:!1};export const documentModelUnique={type:"object",properties:{...documentModelBase.properties,behavior:{type:"string",const:"unique"},uniqueFields:{type:"array",items:{type:"string"}}},required:[...documentModelBase.required,"behavior","uniqueFields"],additionalProperties:!1};export const documentModel={$id:"urn:kubun:protocol:model:document",anyOf:[documentModelDefault,documentModelInterface,documentModelUnique]};export const documentModelsCluster={type:"array",items:documentModel};export const documentModelsRecord={type:"object",additionalProperties:documentModel};export const setDocumentMutation={$id:"urn:kubun:protocol:mutation:set",type:"object",properties:{typ:{type:"string",const:"set"},iss:l,aud:l,sub:{type:"string"},data:{anyOf:[c,{type:"null"}]},unq:c,cap:{anyOf:[{type:"string"},{type:"array",items:{type:"string"}}]}},required:["iss","sub","typ","data","unq"],additionalProperties:!1};export const changeDocumentMutation={$id:"urn:kubun:protocol:mutation:change",type:"object",properties:{typ:{type:"string",const:"change"},iss:l,sub:{type:"string"},data:{anyOf:[c,{type:"null"}]},inc:{type:"boolean"},cap:{anyOf:[{type:"string"},{type:"array",items:{type:"string"}}]}},required:["iss","sub","typ","data","inc"],additionalProperties:!1};export const documentMutation={$id:"urn:kubun:protocol:mutation",anyOf:[setDocumentMutation,changeDocumentMutation]};export const validateDocumentModel=t(documentModel);export const REFERENCE_PREFIX="#/$defs/";let p={type:"object",title:"JSONObject",additionalProperties:!0},u=/^#([0-9]+)$/;export class DocumentModelNormalizer{#e;#t=new Set;#r;#o;#i;#s;#n={};#a={};#d=new Set;#c={};constructor(e){this.#e=e.inputModel,this.#r=e.logger;let t=e.inputModel.schema??{};this.#l(e.interfaceModels),this.#p(t,e.normalizedInterfaceIDs),this.#i=t.$defs??{},this.#s={...t,type:"object",properties:this.#n,required:Array.from(this.#d),additionalProperties:!1,$defs:{...t.$defs,...this.#a}},this.#o=this.#u(),this.#m()}#l(e){for(let t of e){for(let e of t.interfaces)this.#t.add(e);for(let e of t.schema.required)this.#d.add(e);Object.assign(this.#n,t.schema.properties),Object.assign(this.#a,t.schema.$defs),Object.assign(this.#c,t.fieldsMeta??{})}}#p(e,t){for(let e of t)this.#t.add(e);for(let t of e.required??[])this.#d.add(t);Object.assign(this.#n,e.properties??{}),Object.assign(this.#c,this.#e.fieldsMeta??{})}#u(){let e=this.#s,t=Object.entries(e.properties??{});if(0===t.length)throw Error("Document schema must contain at least one property");let r={};for(let[e,o]of t)r[e]={$ref:this.#h(e,o)};return{type:"object",properties:r,additionalProperties:!1,required:e.required??[],$defs:this.#i}}#h(e,t){if(null!=t.$ref){let r=this.#f(t.$ref);return this.#h(e,r)}let r=t.type;if(null==r)throw Error("Invalid schema: missing type");switch(r){case"array":{if(null==t.title)throw Error("Invalid array schema: missing title");if(null==t.items)throw Error("Invalid array schema: missing items");let{default:r,...o}=t;return this.#y({...o,title:s(t.title),items:{$ref:this.#h(e,t.items)}})}case"object":{if(t.additionalProperties)return this.#y(p);if(null==t.title)throw Error("Invalid object schema: missing title");let e=Object.entries(t.properties??{});if(0===e.length)throw Error("Invalid object schema: must contain at least one property");let r={};for(let[t,o]of e)r[t]={$ref:this.#h(t,o)};return this.#y({type:"object",title:s(t.title),properties:r,required:t.required??[],additionalProperties:!1})}default:return this.#M(e,t)}}#f(e){if(!e.startsWith("#"))throw Error(`Invalid reference format: ${e}`);if(e.startsWith(REFERENCE_PREFIX)){let t=e.slice(REFERENCE_PREFIX.length),r=this.#s.$defs?.[t];if(null==r)throw Error(`Reference not found: ${e}`);return r}let t=e.split("/").slice(1),r=this.#s;for(let o of t){if(null==r||"object"!=typeof r)throw Error(`Invalid reference path: ${e}`);if(null==(r=r[o]))throw Error(`Reference not found: ${e}`)}return r}#M(e,t){let r=o.create(t),i=t;if("boolean"===t.type){let{title:e,...r}=t;i=r}else if(null!=t.title){let r=t.title.toLowerCase();"attachmentid"===r?(this.#c[e]={type:"attachment"},i={...t,title:"attachmentid"}):"did"===r?(this.#c[e]={type:"account"},i={...t,title:"did"}):"docid"===r?(null==this.#c[e]&&(this.#r.warn("Missing fieldMeta entry for document reference {fieldKey} of model {inputModel}",{fieldKey:e,inputModel:this.#e}),this.#c[e]={type:"document",model:null}),i={...t,title:"docid"}):i={...t,title:s(t.title)}}return this.#i[r.toString()]=i,`${REFERENCE_PREFIX}${r}`}#y(e){let t=i.create(e);return this.#i[t.toString()]=e,`${REFERENCE_PREFIX}${t}`}#m(){for(let[e,t]of Object.entries(this.#c)){if("document"!==t.type||null===t.model)continue;let o=t.model.match(u);null!=o&&(this.#c[e]={...t,model:r.local(Number.parseInt(o[1],10)).toString()})}}toDocumentModel(){return e(validateDocumentModel,{version:"1.0",behavior:"default",...this.#e,interfaces:Array.from(this.#t),schema:this.#o,fieldsMeta:this.#c})}}
|
package/lib/models/graph.d.ts
CHANGED
package/lib/models/graph.js
CHANGED
|
@@ -1,52 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
export class GraphModel {
|
|
3
|
-
static fromClusters(params) {
|
|
4
|
-
const record = {};
|
|
5
|
-
// Verify all clusters and merge their document models into a single record
|
|
6
|
-
for (const clusterRecord of params.clusters.map(verifyCluster)){
|
|
7
|
-
Object.assign(record, clusterRecord);
|
|
8
|
-
}
|
|
9
|
-
return new GraphModel({
|
|
10
|
-
aliases: params.aliases,
|
|
11
|
-
record
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
#aliases;
|
|
15
|
-
#record;
|
|
16
|
-
constructor(params){
|
|
17
|
-
// If no aliases are provided, fallback to using the model names
|
|
18
|
-
this.#aliases = params.aliases ?? Object.entries(params.record).reduce((acc, [id, model])=>{
|
|
19
|
-
if (acc[model.name] == null) {
|
|
20
|
-
acc[model.name] = id;
|
|
21
|
-
} else {
|
|
22
|
-
console.warn(`Duplicate model name ${model.name} in GraphModel record, ignoring model ID ${id} in aliases`);
|
|
23
|
-
}
|
|
24
|
-
return acc;
|
|
25
|
-
}, {});
|
|
26
|
-
this.#record = params.record;
|
|
27
|
-
}
|
|
28
|
-
get aliases() {
|
|
29
|
-
return this.#aliases;
|
|
30
|
-
}
|
|
31
|
-
get record() {
|
|
32
|
-
return this.#record;
|
|
33
|
-
}
|
|
34
|
-
getAlias(modelID) {
|
|
35
|
-
for (const [alias, id] of Object.entries(this.#aliases)){
|
|
36
|
-
if (id === modelID) {
|
|
37
|
-
return alias;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
getModel(aliasOrID) {
|
|
43
|
-
const id = this.#aliases[aliasOrID] ?? aliasOrID;
|
|
44
|
-
return this.#record[id] ?? null;
|
|
45
|
-
}
|
|
46
|
-
toJSON() {
|
|
47
|
-
return {
|
|
48
|
-
aliases: this.#aliases,
|
|
49
|
-
record: this.#record
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
}
|
|
1
|
+
import{verifyCluster as e}from"./cluster.js";export class GraphModel{static fromClusters(r){let s={};for(let t of r.clusters.map(e))Object.assign(s,t);return new GraphModel({aliases:r.aliases,record:s})}#e;#r;constructor(e){this.#e=e.aliases??Object.entries(e.record).reduce((e,[r,s])=>(null==e[s.name]?e[s.name]=r:console.warn(`Duplicate model name ${s.name} in GraphModel record, ignoring model ID ${r} in aliases`),e),{}),this.#r=e.record}get aliases(){return this.#e}get record(){return this.#r}getAlias(e){for(let[r,s]of Object.entries(this.#e))if(s===e)return r;return null}getModel(e){let r=this.#e[e]??e;return this.#r[r]??null}toJSON(){return{aliases:this.#e,record:this.#r}}}
|