@kubun/server 0.1.0 → 0.2.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/data/automerge.d.ts +5 -0
- package/lib/data/automerge.d.ts.map +1 -0
- package/lib/data/automerge.js +8 -0
- package/lib/data/graphql.d.ts +4 -4
- package/lib/data/graphql.d.ts.map +1 -1
- package/lib/data/graphql.js +7 -4
- package/lib/data/mutations.d.ts +12 -3
- package/lib/data/mutations.d.ts.map +1 -1
- package/lib/data/mutations.js +65 -29
- package/lib/handlers/document.d.ts +8 -0
- package/lib/handlers/document.d.ts.map +1 -0
- package/lib/handlers/document.js +30 -0
- package/lib/handlers/graph.d.ts +4 -4
- package/lib/handlers/graph.d.ts.map +1 -1
- package/lib/handlers/graph.js +47 -23
- package/lib/handlers/index.d.ts +4 -4
- package/lib/handlers/index.d.ts.map +1 -1
- package/lib/handlers/index.js +5 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/server.d.ts +11 -9
- package/lib/server.d.ts.map +1 -1
- package/lib/server.js +15 -16
- package/package.json +16 -16
- package/lib/data/cursor.d.ts +0 -8
- package/lib/data/cursor.d.ts.map +0 -1
- package/lib/data/cursor.js +0 -7
- package/lib/data/db.d.ts +0 -31
- package/lib/data/db.d.ts.map +0 -1
- package/lib/data/db.js +0 -192
- package/lib/data/engines/engine.d.ts +0 -6
- package/lib/data/engines/engine.d.ts.map +0 -1
- package/lib/data/engines/engine.js +0 -12
- package/lib/data/engines/postgres.d.ts +0 -25
- package/lib/data/engines/postgres.d.ts.map +0 -1
- package/lib/data/engines/postgres.js +0 -30
- package/lib/data/engines/sqlite.d.ts +0 -24
- package/lib/data/engines/sqlite.d.ts.map +0 -1
- package/lib/data/engines/sqlite.js +0 -29
- package/lib/data/engines/types.d.ts +0 -19
- package/lib/data/engines/types.d.ts.map +0 -1
- package/lib/data/engines/types.js +0 -1
- package/lib/data/migrations/0-init.d.ts +0 -4
- package/lib/data/migrations/0-init.d.ts.map +0 -1
- package/lib/data/migrations/0-init.js +0 -22
- package/lib/data/migrations/migrations.d.ts +0 -4
- package/lib/data/migrations/migrations.d.ts.map +0 -1
- package/lib/data/migrations/migrations.js +0 -6
- package/lib/data/query-builder.d.ts +0 -12
- package/lib/data/query-builder.d.ts.map +0 -1
- package/lib/data/query-builder.js +0 -218
- package/lib/data/types.d.ts +0 -134
- package/lib/data/types.d.ts.map +0 -1
- package/lib/data/types.js +0 -1
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import * as A from '@automerge/automerge/slim';
|
|
2
|
+
import type { DocumentData } from '@kubun/protocol';
|
|
3
|
+
export declare const automergeReady: PromiseLike<void>;
|
|
4
|
+
export declare function automergeToData(doc: A.Doc<DocumentData>): DocumentData;
|
|
5
|
+
//# sourceMappingURL=automerge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"automerge.d.ts","sourceRoot":"","sources":["../../src/data/automerge.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAEnD,eAAO,MAAM,cAAc,mBAA0D,CAAA;AAErF,wBAAgB,eAAe,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,YAAY,CAEtE"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// @ts-ignore missing type definition
|
|
2
|
+
import { automergeWasmBase64 } from '@automerge/automerge/automerge.wasm.base64.js';
|
|
3
|
+
import * as A from '@automerge/automerge/slim';
|
|
4
|
+
import { lazy } from '@enkaku/async';
|
|
5
|
+
export const automergeReady = lazy(()=>A.initializeBase64Wasm(automergeWasmBase64));
|
|
6
|
+
export function automergeToData(doc) {
|
|
7
|
+
return JSON.parse(JSON.stringify(doc));
|
|
8
|
+
}
|
package/lib/data/graphql.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import type { Document, DocumentData, QueryDocumentsParams } from '@kubun/db';
|
|
2
|
+
import { SchemaBuilder, type SharedDefinitions } from '@kubun/graphql';
|
|
1
3
|
import type { DocumentID } from '@kubun/id';
|
|
2
4
|
import { type Connection, type ConnectionArguments } from 'graphql-relay';
|
|
3
|
-
import { SchemaBuilder, type SharedDefinitions } from '../../../graphql/lib/schema.js';
|
|
4
|
-
import type { Document, DocumentData, QueryDocumentsParams } from './types.js';
|
|
5
5
|
export type ContextListDocumentsParams = {
|
|
6
6
|
model: string | null;
|
|
7
7
|
ids: Array<string>;
|
|
@@ -11,11 +11,11 @@ export type Context = {
|
|
|
11
11
|
listDocuments: (params: ContextListDocumentsParams) => Promise<Array<Document>>;
|
|
12
12
|
loadDocument: (id: DocumentID | string) => Promise<Document | null>;
|
|
13
13
|
queryDocuments: (params: QueryDocumentsParams) => Promise<Connection<Document>>;
|
|
14
|
-
viewerDID: string
|
|
14
|
+
viewerDID: string;
|
|
15
15
|
mutatedDocuments?: Record<string, Document>;
|
|
16
16
|
};
|
|
17
17
|
export declare class ServerSchemaBuilder extends SchemaBuilder<Document, Context> {
|
|
18
|
-
getViewer(ctx: Context): string
|
|
18
|
+
getViewer(ctx: Context): string;
|
|
19
19
|
loadDocument(id: string, ctx: Context): Promise<Document | null>;
|
|
20
20
|
resolveConnection(model: string | null, args: ConnectionArguments, ctx: Context): Promise<Connection<Document>>;
|
|
21
21
|
resolveList(model: string | null, ids: Array<string>, ctx: Context): Promise<Array<Document>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../src/data/graphql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../src/data/graphql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAC7E,OAAO,EAAkB,aAAa,EAAE,KAAK,iBAAiB,EAAU,MAAM,gBAAgB,CAAA;AAC9F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE3C,OAAO,EACL,KAAK,UAAU,EACf,KAAK,mBAAmB,EAEzB,MAAM,eAAe,CAAA;AAEtB,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC1E,aAAa,EAAE,CAAC,MAAM,EAAE,0BAA0B,KAAK,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC/E,YAAY,EAAE,CAAC,EAAE,EAAE,UAAU,GAAG,MAAM,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAA;IACnE,cAAc,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC/E,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;CAC5C,CAAA;AAED,qBAAa,mBAAoB,SAAQ,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC;IACvE,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM;IAIzB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAIhE,iBAAiB,CACrB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,IAAI,EAAE,mBAAmB,EACzB,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAI1B,WAAW,CACf,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,EAClB,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAI3B,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,iBAAiB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,IAAI;CAiEpF"}
|
package/lib/data/graphql.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { PatchOperation, SchemaBuilder, toList } from '@kubun/graphql';
|
|
1
2
|
import { GraphQLID, GraphQLNonNull } from 'graphql';
|
|
2
3
|
import { mutationWithClientMutationId } from 'graphql-relay';
|
|
3
|
-
import { SchemaBuilder } from '../../../graphql/lib/schema.js';
|
|
4
4
|
export class ServerSchemaBuilder extends SchemaBuilder {
|
|
5
5
|
getViewer(ctx) {
|
|
6
6
|
return ctx.viewerDID;
|
|
@@ -30,7 +30,7 @@ export class ServerSchemaBuilder extends SchemaBuilder {
|
|
|
30
30
|
case 'interface':
|
|
31
31
|
// Interfaces don't have mutations
|
|
32
32
|
return;
|
|
33
|
-
case '
|
|
33
|
+
case 'default':
|
|
34
34
|
{
|
|
35
35
|
this._mutations[`create${name}`] = mutationWithClientMutationId({
|
|
36
36
|
name: `Create${name}`,
|
|
@@ -54,7 +54,7 @@ export class ServerSchemaBuilder extends SchemaBuilder {
|
|
|
54
54
|
});
|
|
55
55
|
break;
|
|
56
56
|
}
|
|
57
|
-
case '
|
|
57
|
+
case 'unique':
|
|
58
58
|
{
|
|
59
59
|
this._mutations[`set${name}`] = mutationWithClientMutationId({
|
|
60
60
|
name: `Set${name}`,
|
|
@@ -85,7 +85,10 @@ export class ServerSchemaBuilder extends SchemaBuilder {
|
|
|
85
85
|
id: {
|
|
86
86
|
type: new GraphQLNonNull(GraphQLID)
|
|
87
87
|
},
|
|
88
|
-
|
|
88
|
+
patch: {
|
|
89
|
+
type: new GraphQLNonNull(toList(PatchOperation))
|
|
90
|
+
},
|
|
91
|
+
from: {
|
|
89
92
|
type: this._inputObjects[`${id}-update`]
|
|
90
93
|
}
|
|
91
94
|
}),
|
package/lib/data/mutations.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type { Document } from '
|
|
3
|
-
|
|
1
|
+
import { type Validator } from '@enkaku/schema';
|
|
2
|
+
import type { Document, KubunDB } from '@kubun/db';
|
|
3
|
+
import { type DocumentData } from '@kubun/protocol';
|
|
4
|
+
type DocumentValidator = Validator<DocumentData>;
|
|
5
|
+
type ValidatorsRecord = Record<string, Promise<DocumentValidator>>;
|
|
6
|
+
export type MutationContext = {
|
|
7
|
+
db: KubunDB;
|
|
8
|
+
validators: ValidatorsRecord;
|
|
9
|
+
};
|
|
10
|
+
export declare function getDocumentValidator(ctx: MutationContext, id: string): Promise<DocumentValidator>;
|
|
11
|
+
export declare function applyMutation(ctx: MutationContext, token: string): Promise<Document>;
|
|
12
|
+
export {};
|
|
4
13
|
//# sourceMappingURL=mutations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutations.d.ts","sourceRoot":"","sources":["../../src/data/mutations.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mutations.d.ts","sourceRoot":"","sources":["../../src/data/mutations.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAA2B,MAAM,gBAAgB,CAAA;AAExE,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAElD,OAAO,EAAE,KAAK,YAAY,EAA2C,MAAM,iBAAiB,CAAA;AAM5F,KAAK,iBAAiB,GAAG,SAAS,CAAC,YAAY,CAAC,CAAA;AAChD,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAElE,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,OAAO,CAAA;IACX,UAAU,EAAE,gBAAgB,CAAA;CAC7B,CAAA;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAOjG;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4E1F"}
|
package/lib/data/mutations.js
CHANGED
|
@@ -1,45 +1,68 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-ignore missing type definition
|
|
2
|
+
import * as A from '@automerge/automerge/slim';
|
|
2
3
|
import { fromB64 } from '@enkaku/codec';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
4
|
+
import { asType, createValidator } from '@enkaku/schema';
|
|
5
|
+
import { verifyToken } from '@enkaku/token';
|
|
5
6
|
import { DocumentID } from '@kubun/id';
|
|
6
7
|
import { documentMutation } from '@kubun/protocol';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return
|
|
8
|
+
import { automergeReady, automergeToData } from './automerge.js';
|
|
9
|
+
const validateMutation = createValidator(documentMutation);
|
|
10
|
+
export function getDocumentValidator(ctx, id) {
|
|
11
|
+
if (ctx.validators[id] == null) {
|
|
12
|
+
ctx.validators[id] = ctx.db.getDocumentModel(id).then((model)=>createValidator({
|
|
13
|
+
...model.schema,
|
|
14
|
+
$id: id
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
return ctx.validators[id];
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
export async function applyMutation(ctx, token) {
|
|
20
|
+
const [verified] = await Promise.all([
|
|
21
|
+
verifyToken(token),
|
|
22
|
+
automergeReady
|
|
23
|
+
]);
|
|
24
|
+
const mutation = asType(validateMutation, verified.payload);
|
|
22
25
|
switch(mutation.typ){
|
|
23
26
|
case 'change':
|
|
24
27
|
{
|
|
25
28
|
const id = DocumentID.fromString(mutation.sub);
|
|
26
|
-
const
|
|
29
|
+
const docID = id.toString();
|
|
30
|
+
const doc = await ctx.db.getDocument(id);
|
|
27
31
|
if (doc == null) {
|
|
28
|
-
throw new Error(`Document not found: ${
|
|
32
|
+
throw new Error(`Document not found: ${docID}`);
|
|
29
33
|
}
|
|
30
34
|
if (mutation.iss !== doc.owner) {
|
|
31
35
|
// TODO: verify capabilities if issuer is not owner
|
|
32
36
|
throw new Error('Invalid mutation issuer');
|
|
33
37
|
}
|
|
34
38
|
if (mutation.data === null) {
|
|
35
|
-
return await db.saveDocument(
|
|
39
|
+
return await ctx.db.saveDocument({
|
|
40
|
+
id,
|
|
41
|
+
data: null,
|
|
42
|
+
state: null
|
|
43
|
+
});
|
|
36
44
|
}
|
|
37
45
|
if (doc.data === null) {
|
|
38
|
-
throw new Error(`Cannot apply changes to empty document: ${
|
|
46
|
+
throw new Error(`Cannot apply changes to empty document: ${docID}`);
|
|
39
47
|
}
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
const [docStates, validator] = await Promise.all([
|
|
49
|
+
ctx.db.getDocumentStates([
|
|
50
|
+
docID
|
|
51
|
+
]),
|
|
52
|
+
getDocumentValidator(ctx, id.model.toString())
|
|
53
|
+
]);
|
|
54
|
+
// Create doc from data object if state is not present
|
|
55
|
+
const currentDoc = docStates[docID] ? A.load(docStates[docID]) : A.from(doc.data);
|
|
56
|
+
const changes = fromB64(mutation.data);
|
|
57
|
+
// Apply incremental changes or full merge
|
|
58
|
+
const newDoc = mutation.inc ? A.loadIncremental(currentDoc, changes) : A.merge(currentDoc, A.load(changes));
|
|
59
|
+
// Validate merged data
|
|
60
|
+
const data = asType(validator, automergeToData(newDoc));
|
|
61
|
+
return await ctx.db.saveDocument({
|
|
62
|
+
id,
|
|
63
|
+
data,
|
|
64
|
+
state: A.save(newDoc)
|
|
65
|
+
});
|
|
43
66
|
}
|
|
44
67
|
case 'set':
|
|
45
68
|
{
|
|
@@ -49,16 +72,29 @@ export async function applyMutation(db, token) {
|
|
|
49
72
|
throw new Error('Invalid mutation issuer');
|
|
50
73
|
}
|
|
51
74
|
const id = DocumentID.fromString(mutation.sub);
|
|
52
|
-
const
|
|
53
|
-
|
|
75
|
+
const [doc, validator] = await Promise.all([
|
|
76
|
+
ctx.db.getDocument(id),
|
|
77
|
+
getDocumentValidator(ctx, id.model.toString())
|
|
78
|
+
]);
|
|
79
|
+
const mergeDoc = mutation.data === null ? null : A.load(fromB64(mutation.data));
|
|
80
|
+
const data = mergeDoc ? asType(validator, automergeToData(mergeDoc)) : null;
|
|
54
81
|
if (doc === null) {
|
|
55
|
-
return await db.createDocument(
|
|
82
|
+
return await ctx.db.createDocument({
|
|
83
|
+
id,
|
|
84
|
+
owner,
|
|
85
|
+
data,
|
|
86
|
+
state: mergeDoc ? A.save(mergeDoc) : null,
|
|
87
|
+
unique: fromB64(mutation.unq)
|
|
88
|
+
});
|
|
56
89
|
}
|
|
57
90
|
if (doc.owner !== owner) {
|
|
58
91
|
throw new Error(`Cannot change owner from ${doc.owner} to ${owner} in document: ${id.toString()}`);
|
|
59
92
|
}
|
|
60
|
-
|
|
61
|
-
|
|
93
|
+
return await ctx.db.saveDocument({
|
|
94
|
+
id,
|
|
95
|
+
data,
|
|
96
|
+
state: mergeDoc ? A.save(mergeDoc) : null
|
|
97
|
+
});
|
|
62
98
|
}
|
|
63
99
|
default:
|
|
64
100
|
throw new Error('Unsupported mutation type');
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ProcedureHandlers } from '@enkaku/server';
|
|
2
|
+
import type { KubunDB } from '@kubun/db';
|
|
3
|
+
import type { DocumentProtocol } from '@kubun/protocol';
|
|
4
|
+
export type CreateHandlersParams = {
|
|
5
|
+
db: KubunDB;
|
|
6
|
+
};
|
|
7
|
+
export declare function createHandlers(handlersParams: CreateHandlersParams): ProcedureHandlers<DocumentProtocol>;
|
|
8
|
+
//# sourceMappingURL=document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../src/handlers/document.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAIvD,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,OAAO,CAAA;CACZ,CAAA;AAED,wBAAgB,cAAc,CAC5B,cAAc,EAAE,oBAAoB,GACnC,iBAAiB,CAAC,gBAAgB,CAAC,CA+BrC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// import * as A from '@automerge/automerge/slim'
|
|
2
|
+
import { toB64 } from '@enkaku/codec';
|
|
3
|
+
export function createHandlers(handlersParams) {
|
|
4
|
+
const { db } = handlersParams;
|
|
5
|
+
return {
|
|
6
|
+
'document/sync': async (ctx)=>{
|
|
7
|
+
const ids = Object.keys(ctx.param.documents);
|
|
8
|
+
// const [loadedStates] = await Promise.all([db.getDocumentStates(ids), automergeReady])
|
|
9
|
+
const loadedStates = await db.getDocumentStates(ids);
|
|
10
|
+
const states = ids.reduce((acc, id)=>{
|
|
11
|
+
const loaded = loadedStates[id];
|
|
12
|
+
if (loaded == null) {
|
|
13
|
+
acc[id] = null;
|
|
14
|
+
return acc;
|
|
15
|
+
}
|
|
16
|
+
const provided = ctx.param.documents[id];
|
|
17
|
+
if (provided == null) {
|
|
18
|
+
acc[id] = toB64(loaded);
|
|
19
|
+
} else {
|
|
20
|
+
// TODO: send diff rather than full doc state
|
|
21
|
+
acc[id] = toB64(loaded);
|
|
22
|
+
}
|
|
23
|
+
return acc;
|
|
24
|
+
}, {});
|
|
25
|
+
return {
|
|
26
|
+
states
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
package/lib/handlers/graph.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
import type
|
|
1
|
+
import type { ProcedureHandlers } from '@enkaku/server';
|
|
2
|
+
import type { KubunDB } from '@kubun/db';
|
|
3
|
+
import { type GraphProtocol } from '@kubun/protocol';
|
|
4
4
|
export type CreateHandlersParams = {
|
|
5
5
|
db: KubunDB;
|
|
6
6
|
};
|
|
7
|
-
export declare function createHandlers(handlersParams: CreateHandlersParams):
|
|
7
|
+
export declare function createHandlers(handlersParams: CreateHandlersParams): ProcedureHandlers<GraphProtocol>;
|
|
8
8
|
//# sourceMappingURL=graph.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/handlers/graph.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/handlers/graph.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAEvD,OAAO,KAAK,EAIV,OAAO,EAER,MAAM,WAAW,CAAA;AAElB,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,iBAAiB,CAAA;AAWxB,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,OAAO,CAAA;CACZ,CAAA;AAcD,wBAAgB,cAAc,CAC5B,cAAc,EAAE,oBAAoB,GACnC,iBAAiB,CAAC,aAAa,CAAC,CA0LlC"}
|
package/lib/handlers/graph.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { fromB64, toB64 } from '@enkaku/codec';
|
|
1
2
|
import { AttachmentID, DocumentID } from '@kubun/id';
|
|
2
3
|
import { GraphModel } from '@kubun/protocol';
|
|
3
4
|
import { Kind, OperationTypeNode, execute, parse } from 'graphql';
|
|
4
|
-
import { fromB64 } from '@enkaku/codec';
|
|
5
5
|
import { ServerSchemaBuilder } from '../data/graphql.js';
|
|
6
6
|
import { applyMutation } from '../data/mutations.js';
|
|
7
7
|
export function createHandlers(handlersParams) {
|
|
@@ -9,7 +9,12 @@ export function createHandlers(handlersParams) {
|
|
|
9
9
|
const graphModels = {};
|
|
10
10
|
async function getGraphModels(id) {
|
|
11
11
|
if (graphModels[id] == null) {
|
|
12
|
-
graphModels[id] = db.getGraph(id)
|
|
12
|
+
graphModels[id] = db.getGraph(id).then((graph)=>{
|
|
13
|
+
if (graph == null) {
|
|
14
|
+
throw new Error(`Graph not found: ${id}`);
|
|
15
|
+
}
|
|
16
|
+
return graph.record;
|
|
17
|
+
});
|
|
13
18
|
}
|
|
14
19
|
return await graphModels[id];
|
|
15
20
|
}
|
|
@@ -88,7 +93,7 @@ export function createHandlers(handlersParams) {
|
|
|
88
93
|
loadDocument,
|
|
89
94
|
queryDocuments,
|
|
90
95
|
mutatedDocuments: contextParams.mutatedDocuments,
|
|
91
|
-
viewerDID: contextParams.viewerDID
|
|
96
|
+
viewerDID: contextParams.viewerDID
|
|
92
97
|
};
|
|
93
98
|
}
|
|
94
99
|
async function executeGraphQL(params) {
|
|
@@ -115,12 +120,13 @@ export function createHandlers(handlersParams) {
|
|
|
115
120
|
};
|
|
116
121
|
}
|
|
117
122
|
return {
|
|
118
|
-
'graph/
|
|
119
|
-
const model = GraphModel.fromClusters({
|
|
120
|
-
clusters: ctx.
|
|
123
|
+
'graph/deploy': async (ctx)=>{
|
|
124
|
+
const model = await GraphModel.fromClusters({
|
|
125
|
+
clusters: ctx.param.clusters
|
|
121
126
|
});
|
|
122
127
|
const id = await db.createGraph({
|
|
123
|
-
|
|
128
|
+
id: ctx.param.id,
|
|
129
|
+
name: ctx.param.name,
|
|
124
130
|
record: model.record
|
|
125
131
|
});
|
|
126
132
|
return {
|
|
@@ -128,28 +134,38 @@ export function createHandlers(handlersParams) {
|
|
|
128
134
|
models: model.record
|
|
129
135
|
};
|
|
130
136
|
},
|
|
137
|
+
'graph/list': async ()=>{
|
|
138
|
+
const graphs = await db.listGraphs();
|
|
139
|
+
return {
|
|
140
|
+
graphs: graphs.map((graph)=>({
|
|
141
|
+
id: graph.id,
|
|
142
|
+
name: graph.name
|
|
143
|
+
}))
|
|
144
|
+
};
|
|
145
|
+
},
|
|
131
146
|
'graph/load': async (ctx)=>{
|
|
132
147
|
return {
|
|
133
|
-
models: await getGraphModels(ctx.
|
|
148
|
+
models: await getGraphModels(ctx.param.id)
|
|
134
149
|
};
|
|
135
150
|
},
|
|
136
151
|
'graph/query': async (ctx)=>{
|
|
137
|
-
|
|
138
|
-
//
|
|
139
|
-
// viewer ID is token audience or fallback to the issuer
|
|
152
|
+
const payload = ctx.message.payload;
|
|
153
|
+
// TODO: viewerDID is token subject or fallback to the issuer
|
|
140
154
|
// also add token capabilities check
|
|
155
|
+
const viewerDID = payload.iss;
|
|
141
156
|
return await executeGraphQL({
|
|
142
157
|
type: OperationTypeNode.QUERY,
|
|
143
|
-
schemaID: ctx.
|
|
144
|
-
text: ctx.
|
|
145
|
-
variables: ctx.
|
|
158
|
+
schemaID: ctx.param.id,
|
|
159
|
+
text: ctx.param.text,
|
|
160
|
+
variables: ctx.param.variables ?? {},
|
|
161
|
+
viewerDID
|
|
146
162
|
});
|
|
147
163
|
},
|
|
148
164
|
'graph/mutate': async (ctx)=>{
|
|
149
|
-
const attachments = Object.entries(ctx.
|
|
165
|
+
const attachments = Object.entries(ctx.param.attachments ?? {}).map(([key, value])=>{
|
|
150
166
|
const aid = AttachmentID.fromString(key);
|
|
151
167
|
return {
|
|
152
|
-
id: aid.
|
|
168
|
+
id: toB64(aid.digest),
|
|
153
169
|
data: fromB64(value)
|
|
154
170
|
};
|
|
155
171
|
});
|
|
@@ -158,16 +174,24 @@ export function createHandlers(handlersParams) {
|
|
|
158
174
|
}
|
|
159
175
|
// Apply mutations and make the documents available to the GraphQL resolvers in the context
|
|
160
176
|
const mutatedDocuments = {};
|
|
161
|
-
|
|
162
|
-
|
|
177
|
+
const validators = {};
|
|
178
|
+
await Promise.all(Object.entries(ctx.param.mutations).map(async ([key, mutation])=>{
|
|
179
|
+
mutatedDocuments[key] = await applyMutation({
|
|
180
|
+
db,
|
|
181
|
+
validators
|
|
182
|
+
}, mutation);
|
|
163
183
|
}));
|
|
184
|
+
const payload = ctx.message.payload;
|
|
185
|
+
// TODO: viewerDID is token subject or fallback to the issuer
|
|
186
|
+
// also add token capabilities check
|
|
187
|
+
const viewerDID = payload.iss;
|
|
164
188
|
return await executeGraphQL({
|
|
165
189
|
type: OperationTypeNode.MUTATION,
|
|
166
|
-
schemaID: ctx.
|
|
167
|
-
text: ctx.
|
|
168
|
-
variables: ctx.
|
|
169
|
-
|
|
170
|
-
|
|
190
|
+
schemaID: ctx.param.id,
|
|
191
|
+
text: ctx.param.text,
|
|
192
|
+
variables: ctx.param.variables ?? {},
|
|
193
|
+
mutatedDocuments,
|
|
194
|
+
viewerDID
|
|
171
195
|
});
|
|
172
196
|
}
|
|
173
197
|
};
|
package/lib/handlers/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
1
|
+
import type { ProcedureHandlers } from '@enkaku/server';
|
|
2
|
+
import type { KubunDB } from '@kubun/db';
|
|
3
|
+
import type { Protocol } from '@kubun/protocol';
|
|
4
4
|
export type CreateHandlersParams = {
|
|
5
5
|
db: KubunDB;
|
|
6
6
|
};
|
|
7
|
-
export type Handlers =
|
|
7
|
+
export type Handlers = ProcedureHandlers<Protocol>;
|
|
8
8
|
export declare function createHandlers(params: CreateHandlersParams): Handlers;
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAK/C,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,OAAO,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AAElD,wBAAgB,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,QAAQ,CAKrE"}
|
package/lib/handlers/index.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { createHandlers as documentHandlers } from './document.js';
|
|
1
2
|
import { createHandlers as graphHandlers } from './graph.js';
|
|
2
3
|
export function createHandlers(params) {
|
|
3
|
-
return
|
|
4
|
+
return {
|
|
5
|
+
...documentHandlers(params),
|
|
6
|
+
...graphHandlers(params)
|
|
7
|
+
};
|
|
4
8
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { KubunServer, type ServerParams } from './server.js';
|
|
1
|
+
export { type CreateHandlersParams, createHandlers } from './handlers/index.js';
|
|
2
|
+
export { type CreateClientParams, KubunServer, type ServerParams } from './server.js';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,oBAAoB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAC/E,OAAO,EAAE,KAAK,kBAAkB,EAAE,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA"}
|
package/lib/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { createHandlers } from './handlers/index.js';
|
|
2
2
|
export { KubunServer } from './server.js';
|
package/lib/server.d.ts
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import type { Signer } from '@enkaku/jwt';
|
|
2
1
|
import { type Server } from '@enkaku/server';
|
|
3
|
-
import { KubunClient } from '@kubun/client';
|
|
4
|
-
import type
|
|
5
|
-
import {
|
|
2
|
+
import { type ClientParams, KubunClient } from '@kubun/client';
|
|
3
|
+
import { type DBParams, KubunDB } from '@kubun/db';
|
|
4
|
+
import type { Protocol, ServerTransport } from '@kubun/protocol';
|
|
6
5
|
export type ServerParams = {
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
access?: Record<string, boolean | Array<string>>;
|
|
7
|
+
db: KubunDB | DBParams;
|
|
8
|
+
id: string;
|
|
9
|
+
};
|
|
10
|
+
export type CreateClientParams = Omit<ClientParams, 'serverID' | 'transport'> & {
|
|
11
|
+
signal?: AbortSignal;
|
|
9
12
|
};
|
|
10
13
|
export declare class KubunServer {
|
|
11
14
|
#private;
|
|
12
15
|
constructor(params: ServerParams);
|
|
13
|
-
get client(): KubunClient;
|
|
14
16
|
get db(): KubunDB;
|
|
15
|
-
createClient(
|
|
16
|
-
serve(transport: ServerTransport, signal?: AbortSignal): Server
|
|
17
|
+
createClient(params: CreateClientParams): KubunClient;
|
|
18
|
+
serve(transport: ServerTransport, signal?: AbortSignal): Server<Protocol>;
|
|
17
19
|
}
|
|
18
20
|
//# sourceMappingURL=server.d.ts.map
|
package/lib/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAS,MAAM,gBAAgB,CAAA;AAEnD,OAAO,EAAE,KAAK,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC9D,OAAO,EAAE,KAAK,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,KAAK,EAAiB,QAAQ,EAAiB,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAI9F,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;IAChD,EAAE,EAAE,OAAO,GAAG,QAAQ,CAAA;IACtB,EAAE,EAAE,MAAM,CAAA;CACX,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,WAAW,CAAC,GAAG;IAC9E,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,qBAAa,WAAW;;gBAMV,MAAM,EAAE,YAAY;IAQhC,IAAI,EAAE,IAAI,OAAO,CAEhB;IAED,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,WAAW;IAOrD,KAAK,CAAC,SAAS,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC;CAS1E"}
|
package/lib/server.js
CHANGED
|
@@ -1,43 +1,42 @@
|
|
|
1
1
|
import { serve } from '@enkaku/server';
|
|
2
|
-
import {
|
|
2
|
+
import { DirectTransports } from '@enkaku/transport';
|
|
3
3
|
import { KubunClient } from '@kubun/client';
|
|
4
|
-
import { KubunDB } from '
|
|
4
|
+
import { KubunDB } from '@kubun/db';
|
|
5
5
|
import { createHandlers } from './handlers/index.js';
|
|
6
6
|
export class KubunServer {
|
|
7
|
-
#
|
|
7
|
+
#access;
|
|
8
8
|
#db;
|
|
9
9
|
#handlers;
|
|
10
|
-
#
|
|
10
|
+
#id;
|
|
11
11
|
constructor(params){
|
|
12
|
-
const { db,
|
|
12
|
+
const { access, db, id } = params;
|
|
13
|
+
this.#access = access ?? {};
|
|
13
14
|
this.#db = db instanceof KubunDB ? db : new KubunDB(db);
|
|
14
15
|
this.#handlers = createHandlers({
|
|
15
16
|
db: this.#db
|
|
16
17
|
});
|
|
17
|
-
this.#
|
|
18
|
-
}
|
|
19
|
-
get client() {
|
|
20
|
-
if (this.#client == null) {
|
|
21
|
-
this.#client = this.createClient(this.#signer);
|
|
22
|
-
}
|
|
23
|
-
return this.#client;
|
|
18
|
+
this.#id = id;
|
|
24
19
|
}
|
|
25
20
|
get db() {
|
|
26
21
|
return this.#db;
|
|
27
22
|
}
|
|
28
|
-
createClient(
|
|
29
|
-
const
|
|
23
|
+
createClient(params) {
|
|
24
|
+
const { signal, ...clientParams } = params;
|
|
25
|
+
const transports = new DirectTransports({
|
|
30
26
|
signal
|
|
31
27
|
});
|
|
32
28
|
this.serve(transports.server, signal);
|
|
33
29
|
return new KubunClient({
|
|
34
|
-
|
|
35
|
-
transport: transports.client
|
|
30
|
+
serverID: this.#id,
|
|
31
|
+
transport: transports.client,
|
|
32
|
+
...clientParams
|
|
36
33
|
});
|
|
37
34
|
}
|
|
38
35
|
serve(transport, signal) {
|
|
39
36
|
return serve({
|
|
37
|
+
access: this.#access,
|
|
40
38
|
handlers: this.#handlers,
|
|
39
|
+
id: this.#id,
|
|
41
40
|
signal,
|
|
42
41
|
transport
|
|
43
42
|
});
|