@kubun/server 0.2.4 → 0.3.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/graphql.d.ts +14 -16
- package/lib/data/graphql.d.ts.map +1 -1
- package/lib/data/graphql.js +144 -101
- package/lib/data/mutations.d.ts.map +1 -1
- package/lib/data/mutations.js +3 -0
- package/lib/handlers/graph.d.ts +1 -1
- package/lib/handlers/graph.d.ts.map +1 -1
- package/lib/handlers/graph.js +81 -75
- package/package.json +16 -15
package/lib/data/graphql.d.ts
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
import type { Document,
|
|
2
|
-
import {
|
|
3
|
-
import type
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
createDocument: (modelID: string, data: DocumentData) => Promise<Document>;
|
|
7
|
-
listDocuments: (params: ListDocumentsParams) => Promise<Array<Document>>;
|
|
8
|
-
loadDocument: (id: DocumentID | string) => Promise<Document | null>;
|
|
9
|
-
queryDocuments: (params: QueryDocumentsParams) => Promise<Connection<Document>>;
|
|
1
|
+
import type { Document, KubunDB } from '@kubun/db';
|
|
2
|
+
import type { ContextType } from '@kubun/graphql';
|
|
3
|
+
import { type ExecutionArgs, type GraphQLSchema, type OperationTypeNode } from 'graphql';
|
|
4
|
+
export type ExecutionContext = {
|
|
5
|
+
db: KubunDB;
|
|
10
6
|
viewerDID: string;
|
|
11
7
|
mutatedDocuments?: Record<string, Document>;
|
|
12
8
|
};
|
|
13
|
-
export declare
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
export declare function createContext(ctx: ExecutionContext): ContextType<Document>;
|
|
10
|
+
export type ExecuteGraphQLParams = {
|
|
11
|
+
context: ExecutionContext;
|
|
12
|
+
schema: GraphQLSchema;
|
|
13
|
+
text: string;
|
|
14
|
+
type: OperationTypeNode;
|
|
15
|
+
variables: Record<string, unknown>;
|
|
16
|
+
};
|
|
17
|
+
export declare function getExecutionArgs(params: ExecuteGraphQLParams): ExecutionArgs;
|
|
20
18
|
//# sourceMappingURL=graphql.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../src/data/graphql.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../src/data/graphql.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAY,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAuB,MAAM,gBAAgB,CAAA;AAGtE,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,aAAa,EAElB,KAAK,iBAAiB,EAEvB,MAAM,SAAS,CAAA;AAGhB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,EAAE,EAAE,OAAO,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;CAC5C,CAAA;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,gBAAgB,GAAG,WAAW,CAAC,QAAQ,CAAC,CAmK1E;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,gBAAgB,CAAA;IACzB,MAAM,EAAE,aAAa,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,iBAAiB,CAAA;IACvB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC,CAAA;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,oBAAoB,GAAG,aAAa,CAiB5E"}
|
package/lib/data/graphql.js
CHANGED
|
@@ -1,109 +1,152 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
modelIDs: this.getModelIDs(model),
|
|
20
|
-
docIDs
|
|
1
|
+
import { defer } from '@enkaku/async';
|
|
2
|
+
import { DocumentID } from '@kubun/id';
|
|
3
|
+
import { Kind, parse } from 'graphql';
|
|
4
|
+
export function createContext(ctx) {
|
|
5
|
+
function createEventGenerator(filter, transform) {
|
|
6
|
+
let isDone = false;
|
|
7
|
+
let pending = null;
|
|
8
|
+
const queue = [];
|
|
9
|
+
const stop = ctx.db.events.on('document:saved', (event)=>{
|
|
10
|
+
if (filter(event)) {
|
|
11
|
+
const toPush = transform(event);
|
|
12
|
+
if (pending == null) {
|
|
13
|
+
queue.push(toPush);
|
|
14
|
+
} else {
|
|
15
|
+
pending.resolve(toPush);
|
|
16
|
+
pending = null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
21
19
|
});
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
type: new GraphQLNonNull(this._inputObjects[id])
|
|
40
|
-
}
|
|
41
|
-
}),
|
|
42
|
-
outputFields: ()=>({
|
|
43
|
-
...definitions.queryFields,
|
|
44
|
-
document: {
|
|
45
|
-
type: new GraphQLNonNull(this._types[id])
|
|
46
|
-
}
|
|
47
|
-
}),
|
|
48
|
-
mutateAndGetPayload: async (_input, ctx, info)=>{
|
|
49
|
-
const document = ctx.mutatedDocuments?.[info.path.key];
|
|
50
|
-
return {
|
|
51
|
-
document
|
|
52
|
-
};
|
|
53
|
-
}
|
|
20
|
+
const setDone = ()=>{
|
|
21
|
+
stop();
|
|
22
|
+
isDone = true;
|
|
23
|
+
return Promise.resolve({
|
|
24
|
+
done: true,
|
|
25
|
+
value: undefined
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
[Symbol.asyncIterator] () {
|
|
30
|
+
return this;
|
|
31
|
+
},
|
|
32
|
+
next: ()=>{
|
|
33
|
+
if (isDone) {
|
|
34
|
+
return Promise.resolve({
|
|
35
|
+
done: true,
|
|
36
|
+
value: undefined
|
|
54
37
|
});
|
|
55
|
-
break;
|
|
56
38
|
}
|
|
57
|
-
|
|
58
|
-
{
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
data: {
|
|
63
|
-
type: new GraphQLNonNull(this._inputObjects[id])
|
|
64
|
-
}
|
|
65
|
-
}),
|
|
66
|
-
outputFields: ()=>({
|
|
67
|
-
...definitions.queryFields,
|
|
68
|
-
document: {
|
|
69
|
-
type: new GraphQLNonNull(this._types[id])
|
|
70
|
-
}
|
|
71
|
-
}),
|
|
72
|
-
mutateAndGetPayload: async (_input, ctx, info)=>{
|
|
73
|
-
const document = ctx.mutatedDocuments?.[info.path.key];
|
|
74
|
-
return {
|
|
75
|
-
document
|
|
76
|
-
};
|
|
77
|
-
}
|
|
39
|
+
const value = queue.shift();
|
|
40
|
+
if (value != null) {
|
|
41
|
+
return Promise.resolve({
|
|
42
|
+
value,
|
|
43
|
+
done: false
|
|
78
44
|
});
|
|
79
|
-
break;
|
|
80
45
|
}
|
|
46
|
+
pending = defer();
|
|
47
|
+
return pending.promise.then((value)=>({
|
|
48
|
+
value,
|
|
49
|
+
done: false
|
|
50
|
+
}));
|
|
51
|
+
},
|
|
52
|
+
return: setDone,
|
|
53
|
+
throw: setDone
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function getMutationDocument(info) {
|
|
57
|
+
return ctx.mutatedDocuments?.[info.path.key];
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
getViewer () {
|
|
61
|
+
return ctx.viewerDID;
|
|
62
|
+
},
|
|
63
|
+
async loadDocument (id) {
|
|
64
|
+
return await ctx.db.getDocument(typeof id === 'string' ? DocumentID.fromString(id) : id);
|
|
65
|
+
},
|
|
66
|
+
async resolveConnection (modelIDs, args) {
|
|
67
|
+
// TODO: access control filtering
|
|
68
|
+
const { entries, hasMore } = await ctx.db.queryDocuments({
|
|
69
|
+
...args,
|
|
70
|
+
modelIDs
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
edges: entries.map((e)=>({
|
|
74
|
+
cursor: e.cursor,
|
|
75
|
+
node: e.document
|
|
76
|
+
})),
|
|
77
|
+
pageInfo: {
|
|
78
|
+
hasNextPage: args.first ? hasMore : false,
|
|
79
|
+
hasPreviousPage: args.first ? false : hasMore,
|
|
80
|
+
endCursor: entries.at(-1)?.cursor ?? null,
|
|
81
|
+
startCursor: entries.at(0)?.cursor ?? null
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
async resolveList (modelIDs, docIDs) {
|
|
86
|
+
return await ctx.db.listDocuments({
|
|
87
|
+
modelIDs,
|
|
88
|
+
docIDs
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
subscribeToDocumentCreated (modelIDs) {
|
|
92
|
+
return createEventGenerator((event)=>event.type === 'create' && modelIDs.includes(event.document.model), (event)=>event.document);
|
|
93
|
+
},
|
|
94
|
+
subscribeToDocumentChanged (id) {
|
|
95
|
+
return createEventGenerator((event)=>{
|
|
96
|
+
return event.type === 'update' && event.document.id === id && event.document.data !== null;
|
|
97
|
+
}, (event)=>event.document);
|
|
98
|
+
},
|
|
99
|
+
subscribeToDocumentRemoved () {
|
|
100
|
+
return createEventGenerator((event)=>event.type === 'update' && event.document.data === null, (event)=>event.document.id);
|
|
101
|
+
},
|
|
102
|
+
subscribeToDocumentEdgeAdded (modelIDs, hasRelation) {
|
|
103
|
+
return createEventGenerator((event)=>{
|
|
104
|
+
return(// document has data
|
|
105
|
+
event.document.data !== null && // document model is one of the target models
|
|
106
|
+
modelIDs.includes(event.document.model) && // relation field targets the expected document
|
|
107
|
+
hasRelation(event.document.data) && // new document or new relation to document
|
|
108
|
+
(event.type === 'create' || event.previous.data !== null && hasRelation(event.previous.data)));
|
|
109
|
+
}, (event)=>({
|
|
110
|
+
cursor: event.getCursor(),
|
|
111
|
+
node: event.document
|
|
112
|
+
}));
|
|
113
|
+
},
|
|
114
|
+
subscribeToDocumentEdgeRemoved (modelIDs, hasRelation) {
|
|
115
|
+
return createEventGenerator((event)=>{
|
|
116
|
+
return event.type === 'update' && // document model is one of the target models
|
|
117
|
+
modelIDs.includes(event.document.model) && // relation existed in previous version
|
|
118
|
+
event.previous.data !== null && hasRelation(event.previous.data) && // relation is removed
|
|
119
|
+
(event.document.data === null || !hasRelation(event.document.data));
|
|
120
|
+
}, (event)=>event.document.id);
|
|
121
|
+
},
|
|
122
|
+
async executeCreateMutation (modelID, data, info) {
|
|
123
|
+
return getMutationDocument(info);
|
|
124
|
+
},
|
|
125
|
+
async executeSetMutation (modelID, unique, data, info) {
|
|
126
|
+
return getMutationDocument(info);
|
|
127
|
+
},
|
|
128
|
+
async executeUpdateMutation (input, info) {
|
|
129
|
+
return getMutationDocument(info);
|
|
130
|
+
},
|
|
131
|
+
async executeRemoveMutation (id, info) {
|
|
132
|
+
// no-op
|
|
81
133
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
}),
|
|
95
|
-
outputFields: ()=>({
|
|
96
|
-
...definitions.queryFields,
|
|
97
|
-
document: {
|
|
98
|
-
type: this._types[id]
|
|
99
|
-
}
|
|
100
|
-
}),
|
|
101
|
-
mutateAndGetPayload: async (_input, ctx, info)=>{
|
|
102
|
-
const document = ctx.mutatedDocuments?.[info.path.key];
|
|
103
|
-
return {
|
|
104
|
-
document
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
});
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
export function getExecutionArgs(params) {
|
|
137
|
+
const document = parse(params.text);
|
|
138
|
+
const definition = document.definitions[0];
|
|
139
|
+
if (definition == null) {
|
|
140
|
+
throw new Error('Missing GraphQL document definition');
|
|
141
|
+
}
|
|
142
|
+
// Ensure the operation matching the expected type
|
|
143
|
+
if (definition.kind !== Kind.OPERATION_DEFINITION || definition.operation !== params.type) {
|
|
144
|
+
throw new Error(`Invalid GraphQL document definition: expected ${params.type} operation`);
|
|
108
145
|
}
|
|
146
|
+
return {
|
|
147
|
+
document,
|
|
148
|
+
schema: params.schema,
|
|
149
|
+
variableValues: params.variables,
|
|
150
|
+
contextValue: createContext(params.context)
|
|
151
|
+
};
|
|
109
152
|
}
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
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,CAiF1F"}
|
package/lib/data/mutations.js
CHANGED
|
@@ -38,6 +38,7 @@ export async function applyMutation(ctx, token) {
|
|
|
38
38
|
if (mutation.data === null) {
|
|
39
39
|
return await ctx.db.saveDocument({
|
|
40
40
|
id,
|
|
41
|
+
existing: doc,
|
|
41
42
|
data: null,
|
|
42
43
|
state: null
|
|
43
44
|
});
|
|
@@ -60,6 +61,7 @@ export async function applyMutation(ctx, token) {
|
|
|
60
61
|
const data = asType(validator, automergeToData(newDoc));
|
|
61
62
|
return await ctx.db.saveDocument({
|
|
62
63
|
id,
|
|
64
|
+
existing: doc,
|
|
63
65
|
data,
|
|
64
66
|
state: A.save(newDoc)
|
|
65
67
|
});
|
|
@@ -92,6 +94,7 @@ export async function applyMutation(ctx, token) {
|
|
|
92
94
|
}
|
|
93
95
|
return await ctx.db.saveDocument({
|
|
94
96
|
id,
|
|
97
|
+
existing: doc,
|
|
95
98
|
data,
|
|
96
99
|
state: mergeDoc ? A.save(mergeDoc) : null
|
|
97
100
|
});
|
package/lib/handlers/graph.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ProcedureHandlers } from '@enkaku/server';
|
|
2
2
|
import type { KubunDB } from '@kubun/db';
|
|
3
|
-
import {
|
|
3
|
+
import type { GraphProtocol } from '@kubun/protocol';
|
|
4
4
|
export type CreateHandlersParams = {
|
|
5
5
|
db: KubunDB;
|
|
6
6
|
};
|
|
@@ -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":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAEvD,OAAO,KAAK,EAAsC,OAAO,EAAE,MAAM,WAAW,CAAA;AAG5E,OAAO,KAAK,EAIV,aAAa,EACd,MAAM,iBAAiB,CAAA;AAsBxB,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,OAAO,CAAA;CACZ,CAAA;AAED,wBAAgB,cAAc,CAC5B,cAAc,EAAE,oBAAoB,GACnC,iBAAiB,CAAC,aAAa,CAAC,CAqJlC"}
|
package/lib/handlers/graph.js
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
import { defer } from '@enkaku/async';
|
|
1
2
|
import { fromB64, toB64 } from '@enkaku/codec';
|
|
2
|
-
import {
|
|
3
|
+
import { createSchema } from '@kubun/graphql';
|
|
4
|
+
import { AttachmentID } from '@kubun/id';
|
|
3
5
|
import { GraphModel } from '@kubun/protocol';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
+
import { OperationTypeNode, execute, subscribe } from 'graphql';
|
|
7
|
+
import { getExecutionArgs } from '../data/graphql.js';
|
|
6
8
|
import { applyMutation } from '../data/mutations.js';
|
|
9
|
+
function toGraphResult(result) {
|
|
10
|
+
return {
|
|
11
|
+
data: result.data,
|
|
12
|
+
errors: result.errors?.map((err)=>err.toJSON()),
|
|
13
|
+
extensions: result.extensions
|
|
14
|
+
};
|
|
15
|
+
}
|
|
7
16
|
export function createHandlers(handlersParams) {
|
|
8
17
|
const { db } = handlersParams;
|
|
9
18
|
const graphModels = {};
|
|
@@ -22,69 +31,16 @@ export function createHandlers(handlersParams) {
|
|
|
22
31
|
async function getGraphQLSchema(id) {
|
|
23
32
|
if (schemas[id] == null) {
|
|
24
33
|
schemas[id] = getGraphModels(id).then((record)=>{
|
|
25
|
-
const schema =
|
|
26
|
-
record
|
|
27
|
-
}).build();
|
|
34
|
+
const schema = createSchema(record);
|
|
28
35
|
// console.log(printSchema(schema))
|
|
29
36
|
return schema;
|
|
30
37
|
});
|
|
31
38
|
}
|
|
32
39
|
return await schemas[id];
|
|
33
40
|
}
|
|
34
|
-
function createContext(contextParams) {
|
|
35
|
-
async function createDocument(modelID, data) {
|
|
36
|
-
throw new Error('Not supported');
|
|
37
|
-
}
|
|
38
|
-
async function loadDocument(id) {
|
|
39
|
-
return await db.getDocument(typeof id === 'string' ? DocumentID.fromString(id) : id);
|
|
40
|
-
}
|
|
41
|
-
// TODO: access control filtering
|
|
42
|
-
async function queryDocuments(params) {
|
|
43
|
-
const { entries, hasMore } = await db.queryDocuments(params);
|
|
44
|
-
return {
|
|
45
|
-
edges: entries.map((e)=>({
|
|
46
|
-
cursor: e.cursor,
|
|
47
|
-
node: e.document
|
|
48
|
-
})),
|
|
49
|
-
pageInfo: {
|
|
50
|
-
hasNextPage: params.first ? hasMore : false,
|
|
51
|
-
hasPreviousPage: params.first ? false : hasMore,
|
|
52
|
-
endCursor: entries.at(-1)?.cursor ?? null,
|
|
53
|
-
startCursor: entries.at(0)?.cursor ?? null
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
return {
|
|
58
|
-
createDocument,
|
|
59
|
-
listDocuments: async (params)=>await db.listDocuments(params),
|
|
60
|
-
loadDocument,
|
|
61
|
-
queryDocuments,
|
|
62
|
-
mutatedDocuments: contextParams.mutatedDocuments,
|
|
63
|
-
viewerDID: contextParams.viewerDID
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
41
|
async function executeGraphQL(params) {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
const definition = document.definitions[0];
|
|
70
|
-
if (definition == null) {
|
|
71
|
-
throw new Error('Missing GraphQL document definition');
|
|
72
|
-
}
|
|
73
|
-
// Ensure the operation matching the expected type
|
|
74
|
-
if (definition.kind !== Kind.OPERATION_DEFINITION || definition.operation !== params.type) {
|
|
75
|
-
throw new Error(`Invalid GraphQL document definition: expected ${params.type} operation`);
|
|
76
|
-
}
|
|
77
|
-
const executionResult = await execute({
|
|
78
|
-
document,
|
|
79
|
-
schema,
|
|
80
|
-
variableValues: params.variables,
|
|
81
|
-
contextValue: createContext(params)
|
|
82
|
-
});
|
|
83
|
-
return {
|
|
84
|
-
data: executionResult.data,
|
|
85
|
-
errors: executionResult.errors?.map((err)=>err.toJSON()),
|
|
86
|
-
extensions: executionResult.extensions
|
|
87
|
-
};
|
|
42
|
+
const result = await execute(getExecutionArgs(params));
|
|
43
|
+
return toGraphResult(result);
|
|
88
44
|
}
|
|
89
45
|
return {
|
|
90
46
|
'graph/deploy': async (ctx)=>{
|
|
@@ -115,19 +71,6 @@ export function createHandlers(handlersParams) {
|
|
|
115
71
|
models: await getGraphModels(ctx.param.id)
|
|
116
72
|
};
|
|
117
73
|
},
|
|
118
|
-
'graph/query': async (ctx)=>{
|
|
119
|
-
const payload = ctx.message.payload;
|
|
120
|
-
// TODO: viewerDID is token subject or fallback to the issuer
|
|
121
|
-
// also add token capabilities check
|
|
122
|
-
const viewerDID = payload.iss;
|
|
123
|
-
return await executeGraphQL({
|
|
124
|
-
type: OperationTypeNode.QUERY,
|
|
125
|
-
schemaID: ctx.param.id,
|
|
126
|
-
text: ctx.param.text,
|
|
127
|
-
variables: ctx.param.variables ?? {},
|
|
128
|
-
viewerDID
|
|
129
|
-
});
|
|
130
|
-
},
|
|
131
74
|
'graph/mutate': async (ctx)=>{
|
|
132
75
|
const attachments = Object.entries(ctx.param.attachments ?? {}).map(([key, value])=>{
|
|
133
76
|
const aid = AttachmentID.fromString(key);
|
|
@@ -153,13 +96,76 @@ export function createHandlers(handlersParams) {
|
|
|
153
96
|
// also add token capabilities check
|
|
154
97
|
const viewerDID = payload.iss;
|
|
155
98
|
return await executeGraphQL({
|
|
99
|
+
schema: await getGraphQLSchema(ctx.param.id),
|
|
156
100
|
type: OperationTypeNode.MUTATION,
|
|
157
|
-
schemaID: ctx.param.id,
|
|
158
101
|
text: ctx.param.text,
|
|
159
102
|
variables: ctx.param.variables ?? {},
|
|
160
|
-
|
|
161
|
-
|
|
103
|
+
context: {
|
|
104
|
+
db,
|
|
105
|
+
mutatedDocuments,
|
|
106
|
+
viewerDID
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
'graph/query': async (ctx)=>{
|
|
111
|
+
const payload = ctx.message.payload;
|
|
112
|
+
// TODO: viewerDID is token subject or fallback to the issuer
|
|
113
|
+
// also add token capabilities check
|
|
114
|
+
const viewerDID = payload.iss;
|
|
115
|
+
return await executeGraphQL({
|
|
116
|
+
schema: await getGraphQLSchema(ctx.param.id),
|
|
117
|
+
type: OperationTypeNode.QUERY,
|
|
118
|
+
text: ctx.param.text,
|
|
119
|
+
variables: ctx.param.variables ?? {},
|
|
120
|
+
context: {
|
|
121
|
+
db,
|
|
122
|
+
viewerDID
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
},
|
|
126
|
+
'graph/subscribe': async (ctx)=>{
|
|
127
|
+
const payload = ctx.message.payload;
|
|
128
|
+
const viewerDID = payload.iss;
|
|
129
|
+
const args = getExecutionArgs({
|
|
130
|
+
schema: await getGraphQLSchema(ctx.param.id),
|
|
131
|
+
type: OperationTypeNode.SUBSCRIPTION,
|
|
132
|
+
text: ctx.param.text,
|
|
133
|
+
variables: ctx.param.variables ?? {},
|
|
134
|
+
context: {
|
|
135
|
+
db,
|
|
136
|
+
viewerDID
|
|
137
|
+
}
|
|
162
138
|
});
|
|
139
|
+
const subscription = await subscribe(args);
|
|
140
|
+
if (ctx.signal.aborted) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
if ('errors' in subscription) {
|
|
144
|
+
return toGraphResult(subscription);
|
|
145
|
+
}
|
|
146
|
+
const generator = subscription;
|
|
147
|
+
let aborted = false;
|
|
148
|
+
const done = defer();
|
|
149
|
+
ctx.signal.addEventListener('abort', ()=>{
|
|
150
|
+
aborted = true;
|
|
151
|
+
generator.return(null);
|
|
152
|
+
if (ctx.signal.reason === 'Close') {
|
|
153
|
+
done.resolve(null);
|
|
154
|
+
} else {
|
|
155
|
+
done.reject(ctx.signal.reason);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
const writer = ctx.writable.getWriter();
|
|
159
|
+
async function pull() {
|
|
160
|
+
const { done, value } = await generator.next();
|
|
161
|
+
if (aborted || done) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
await writer.write(toGraphResult(value));
|
|
165
|
+
void pull();
|
|
166
|
+
}
|
|
167
|
+
void pull();
|
|
168
|
+
return done.promise;
|
|
163
169
|
}
|
|
164
170
|
};
|
|
165
171
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubun/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"license": "see LICENSE.md",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"type": "module",
|
|
@@ -16,24 +16,25 @@
|
|
|
16
16
|
"sideEffects": false,
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@automerge/automerge": "^2.2.8",
|
|
19
|
-
"@enkaku/async": "^0.
|
|
20
|
-
"@enkaku/codec": "^0.
|
|
21
|
-
"@enkaku/schema": "^0.
|
|
22
|
-
"@enkaku/server": "^0.
|
|
23
|
-
"@enkaku/token": "^0.
|
|
24
|
-
"@enkaku/transport": "^0.
|
|
19
|
+
"@enkaku/async": "^0.12.0",
|
|
20
|
+
"@enkaku/codec": "^0.12.0",
|
|
21
|
+
"@enkaku/schema": "^0.12.0",
|
|
22
|
+
"@enkaku/server": "^0.12.0",
|
|
23
|
+
"@enkaku/token": "^0.12.0",
|
|
24
|
+
"@enkaku/transport": "^0.12.0",
|
|
25
25
|
"graphql": "^16.9.0",
|
|
26
|
-
"
|
|
27
|
-
"@kubun/
|
|
28
|
-
"@kubun/
|
|
29
|
-
"@kubun/
|
|
30
|
-
"@kubun/
|
|
31
|
-
"@kubun/id": "^0.2.0"
|
|
26
|
+
"@kubun/protocol": "^0.3.0",
|
|
27
|
+
"@kubun/client": "^0.3.0",
|
|
28
|
+
"@kubun/id": "^0.3.0",
|
|
29
|
+
"@kubun/graphql": "^0.3.0",
|
|
30
|
+
"@kubun/db": "^0.3.0"
|
|
32
31
|
},
|
|
33
32
|
"devDependencies": {
|
|
34
33
|
"@databases/pg-test": "^3.1.2",
|
|
35
|
-
"@
|
|
36
|
-
"
|
|
34
|
+
"@enkaku/stream": "^0.12.0",
|
|
35
|
+
"graphql-relay": "^0.10.2",
|
|
36
|
+
"@kubun/db-postgres": "^0.3.0",
|
|
37
|
+
"@kubun/db-sqlite": "^0.3.0"
|
|
37
38
|
},
|
|
38
39
|
"scripts": {
|
|
39
40
|
"build:clean": "del lib",
|