@kubun/graphql 0.7.1 → 0.8.1

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/context.d.ts CHANGED
@@ -1,9 +1,69 @@
1
1
  import type { Tracer } from '@enkaku/otel';
2
- import type { KubunDB } from '@kubun/db';
3
- import type { DocumentData, DocumentFilter, DocumentNode } from '@kubun/protocol';
2
+ import { DocumentID } from '@kubun/id';
3
+ import type { DocumentData, DocumentFilter, DocumentNode, DocumentOrderBy } from '@kubun/protocol';
4
4
  import type { GraphQLResolveInfo } from 'graphql';
5
5
  import type { Connection, Edge } from 'graphql-relay';
6
6
  import type { AllConnectionArguments, ModelAccessDefaults, UpdateMutationInput } from './types.js';
7
+ /**
8
+ * Event data for document save notifications used by subscriptions.
9
+ */
10
+ export type DocumentSavedEvent = {
11
+ type: 'create' | 'update';
12
+ document: DocumentNode;
13
+ previous: {
14
+ data: DocumentData | null;
15
+ };
16
+ getCursor(): string;
17
+ };
18
+ /**
19
+ * Event emitter interface for document events used by subscriptions.
20
+ */
21
+ export type DocumentEventEmitter = {
22
+ on(event: 'document:saved', handler: (data: DocumentSavedEvent) => void): () => void;
23
+ };
24
+ /**
25
+ * Read-only database interface required by the GraphQL read context.
26
+ * This replaces the direct KubunDB dependency, allowing any store
27
+ * implementation (e.g. GraphStoreAPI) to be used.
28
+ */
29
+ export type ReadContextDB = {
30
+ getDocument(id: DocumentID): Promise<DocumentNode | null>;
31
+ queryDocuments(params: {
32
+ modelIDs: Array<string>;
33
+ filter?: DocumentFilter;
34
+ orderBy?: DocumentOrderBy;
35
+ owner?: string;
36
+ catalogID?: string;
37
+ first?: number | null;
38
+ last?: number | null;
39
+ before?: string | null;
40
+ after?: string | null;
41
+ }): Promise<{
42
+ entries: Array<{
43
+ cursor: string;
44
+ document: DocumentNode;
45
+ }>;
46
+ hasMore: boolean;
47
+ }>;
48
+ listDocuments(params: {
49
+ modelIDs: Array<string>;
50
+ docIDs: Array<string>;
51
+ }): Promise<Array<DocumentNode>>;
52
+ countDocuments(params: {
53
+ modelIDs: Array<string>;
54
+ filter?: DocumentFilter;
55
+ catalogID?: string;
56
+ }): Promise<number>;
57
+ searchDocuments(params: {
58
+ query: string;
59
+ modelIDs: Array<string>;
60
+ first?: number;
61
+ }): Promise<Array<{
62
+ documentID: string;
63
+ modelID: string;
64
+ rank: number;
65
+ }>>;
66
+ };
7
67
  /**
8
68
  * Query functions requiring server implementation
9
69
  */
@@ -23,7 +83,7 @@ export type QueryContext = {
23
83
  * Subscription functions requiring server implementation
24
84
  */
25
85
  export type SubscriptionContext = {
26
- subscribeToDocumentCreated(modelIDs: Array<string>): AsyncGenerator<DocumentNode>;
86
+ subscribeToDocumentCreated(modelIDs: Array<string>, owner?: string): AsyncGenerator<DocumentNode>;
27
87
  subscribeToDocumentChanged(id: string): AsyncGenerator<DocumentNode>;
28
88
  subscribeToDocumentRemoved(): AsyncGenerator<string>;
29
89
  subscribeToDocumentEdgeAdded(modelIDs: Array<string>, hasRelation: (data: DocumentData) => boolean): AsyncGenerator<Edge<DocumentNode>>;
@@ -46,8 +106,10 @@ export type ComplexityStats = {
46
106
  resolverTimings?: Map<string, number>;
47
107
  };
48
108
  export type ReadContextParams = {
49
- db: KubunDB;
109
+ store: ReadContextDB;
110
+ events?: DocumentEventEmitter;
50
111
  viewerDID: string;
112
+ catalogID?: string;
51
113
  accessChecker?: AccessChecker;
52
114
  warnings?: Array<AccessWarning>;
53
115
  complexity?: ComplexityStats;
package/lib/context.js CHANGED
@@ -1 +1 @@
1
- import{defer as e}from"@enkaku/async";import{withSpan as t}from"@enkaku/otel";import{DocumentID as o}from"@kubun/id";import{KubunAttributeKeys as n,KubunSpanNames as r}from"@kubun/protocol";export function createReadContext(l){let{db:s,viewerDID:i,accessChecker:u}=l;function a(e,o,n){return null!=l.tracer?t(l.tracer,e,{attributes:o},async()=>n()):n()}function c(t,o){let n=!1,r=null,l=[],i=s.events.on("document:saved",e=>{if(t(e)){let t=o(e);null==r?l.push(t):(r.resolve(t),r=null)}}),u=()=>(i(),n=!0,Promise.resolve({done:!0,value:void 0}));return{[Symbol.asyncDispose]:()=>(i(),n=!0,Promise.resolve()),[Symbol.asyncIterator](){return this},next:()=>{if(n)return Promise.resolve({done:!0,value:void 0});let t=l.shift();return null!=t?Promise.resolve({value:t,done:!1}):(r=e()).promise.then(e=>({value:e,done:!1}))},return:u,throw:u}}return{getViewer:()=>i,async loadDocument(e){let t=`document:${e}`,i=l.complexity?.resolverTimings!=null?performance.now():0,c=await a(r.DATA_QUERY,{[n.DOCUMENT_ID]:e},async()=>{let t=await s.getDocument(o.fromString(e));return t?u&&!await u(t,"read")?(null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e}`,code:"KB07"}),null):(null!=l.complexity&&(l.complexity.resolverCount++,l.complexity.documentsScanned++),t):null});if(l.complexity?.resolverTimings!=null){let e=Math.round((performance.now()-i)*100)/100,o=l.complexity.resolverTimings.get(t)??0;l.complexity.resolverTimings.set(t,o+e)}return c},searchDocuments:async(e,t,o)=>await s.searchDocuments({query:e,modelIDs:t,first:o}),async resolveConnection(e,t){let o=`connection:${e.join(",")}`,i=l.complexity?.resolverTimings!=null?performance.now():0,c=await a(r.DATA_QUERY,{[n.MODEL_ID]:e.join(",")},async()=>{if(null!=t.search&&""!==t.search.trim()){let o=await s.searchDocuments({query:t.search,modelIDs:e,first:200});if(0===o.length){if(null!=l.complexity)for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);return{edges:[],pageInfo:{hasNextPage:!1,hasPreviousPage:!1,startCursor:null,endCursor:null}}}let n=o.map(e=>e.documentID),r=await s.listDocuments({modelIDs:e,docIDs:n}),i=r;if(u)for(let e of(i=[],r))await u(e,"read")?i.push(e):null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e.id}`,code:"KB07"});let a=new Map(o.map(e=>[e.documentID,e.rank]));i.sort((e,t)=>Math.abs(a.get(t.id)??0)-Math.abs(a.get(e.id)??0));let c=i.slice(0,t.first??50);if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=c.length}return{edges:c.map((e,t)=>({cursor:String(t),node:e})),pageInfo:{hasNextPage:i.length>c.length,hasPreviousPage:!1,startCursor:c.length>0?"0":null,endCursor:c.length>0?String(c.length-1):null}}}if(null==u){let{entries:o,hasMore:n}=await s.queryDocuments({...t,modelIDs:e});if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=o.length}return{edges:o.map(e=>({cursor:e.cursor,node:e.document})),pageInfo:{hasNextPage:!!t.first&&n,hasPreviousPage:!t.first&&n,endCursor:o.at(-1)?.cursor??null,startCursor:o.at(0)?.cursor??null}}}let o=[],n=0,r=0;if(null!=t.first){let i=2*(n=t.first),a=t.after;for(;o.length<n&&r<10;){let{entries:c,hasMore:m}=await s.queryDocuments({...t,modelIDs:e,first:i,after:a});if(0===c.length&&!m)break;for(let e of c)if(await u(e.document,"read")){if(o.push(e),o.length>=n)break}else null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e.document.id}`,code:"KB07"});if(!m)break;a=c.at(-1)?.cursor??null,r++}}else if(null!=t.last){let i=2*(n=t.last),a=t.before;for(;o.length<n&&r<10;){let{entries:c,hasMore:m}=await s.queryDocuments({...t,modelIDs:e,last:i,before:a});if(0===c.length&&!m)break;for(let e of[...c].reverse())if(await u(e.document,"read")){if(o.unshift(e),o.length>=n)break}else null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e.document.id}`,code:"KB07"});if(!m)break;a=c.at(0)?.cursor??null,r++}}let i=o.slice(0,n),a=o.length>n;if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=i.length}return{edges:i.map(e=>({cursor:e.cursor,node:e.document})),pageInfo:{hasNextPage:!!t.first&&a,hasPreviousPage:!t.first&&a,endCursor:i.at(-1)?.cursor??null,startCursor:i.at(0)?.cursor??null}}});if(l.complexity?.resolverTimings!=null){let e=Math.round((performance.now()-i)*100)/100,t=l.complexity.resolverTimings.get(o)??0;l.complexity.resolverTimings.set(o,t+e)}return c},async resolveList(e,t){let o=`list:${e.join(",")}`,i=l.complexity?.resolverTimings!=null?performance.now():0,c=await a(r.DATA_QUERY,{[n.MODEL_ID]:e.join(",")},async()=>{let o=await s.listDocuments({modelIDs:e,docIDs:t});if(!u){if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=o.length}return o}let n=[];for(let e of o)await u(e,"read")?n.push(e):null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e.id}`,code:"KB07"});if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=n.length}return n});if(l.complexity?.resolverTimings!=null){let e=Math.round((performance.now()-i)*100)/100,t=l.complexity.resolverTimings.get(o)??0;l.complexity.resolverTimings.set(o,t+e)}return c},async resolveCount(e,t){let o=`count:${e.join(",")}`,i=l.complexity?.resolverTimings!=null?performance.now():0,u=await a(r.DATA_QUERY,{[n.MODEL_ID]:e.join(",")},async()=>(null!=l.complexity&&l.complexity.resolverCount++,await s.countDocuments({modelIDs:e,filter:t})));if(l.complexity?.resolverTimings!=null){let e=Math.round((performance.now()-i)*100)/100,t=l.complexity.resolverTimings.get(o)??0;l.complexity.resolverTimings.set(o,t+e)}return u},subscribeToDocumentCreated(e){let t=c(t=>"create"===t.type&&e.includes(t.document.model),e=>e.document);return u?async function*(){for await(let e of t)await u(e,"read")&&(yield e)}():t},subscribeToDocumentChanged(e){let t=c(t=>"update"===t.type&&t.document.id===e&&null!==t.document.data,e=>e.document);return u?async function*(){for await(let e of t)await u(e,"read")&&(yield e)}():t},subscribeToDocumentRemoved:()=>c(e=>"update"===e.type&&null===e.document.data,e=>e.document.id),subscribeToDocumentEdgeAdded(e,t){let o=c(o=>null!==o.document.data&&e.includes(o.document.model)&&t(o.document.data)&&("create"===o.type||null!==o.previous.data&&t(o.previous.data)),e=>({cursor:e.getCursor(),node:e.document}));return u?async function*(){for await(let e of o)await u(e.node,"read")&&(yield e)}():o},subscribeToDocumentEdgeRemoved:(e,t)=>c(o=>"update"===o.type&&e.includes(o.document.model)&&null!==o.previous.data&&t(o.previous.data)&&(null===o.document.data||!t(o.document.data)),e=>e.document.id)}}
1
+ import{defer as e}from"@enkaku/async";import{withSpan as t}from"@enkaku/otel";import{DocumentID as o}from"@kubun/id";import{KubunAttributeKeys as n,KubunSpanNames as r}from"@kubun/protocol";export function createReadContext(l){let{store:s,viewerDID:i,accessChecker:a}=l;function u(e,o,n){return null!=l.tracer?t(l.tracer,e,{attributes:o},async()=>n()):n()}function c(t,o){let n=!1,r=null,s=[];if(null==l.events)throw Error("Subscriptions require a document event emitter");let i=l.events.on("document:saved",e=>{if(t(e)){let t=o(e);null==r?s.push(t):(r.resolve(t),r=null)}}),a=()=>(i(),n=!0,Promise.resolve({done:!0,value:void 0}));return{[Symbol.asyncDispose]:()=>(i(),n=!0,Promise.resolve()),[Symbol.asyncIterator](){return this},next:()=>{if(n)return Promise.resolve({done:!0,value:void 0});let t=s.shift();return null!=t?Promise.resolve({value:t,done:!1}):(r=e()).promise.then(e=>({value:e,done:!1}))},return:a,throw:a}}return{getViewer:()=>i,async loadDocument(e){let t=`document:${e}`,i=l.complexity?.resolverTimings!=null?performance.now():0,c=await u(r.DATA_QUERY,{[n.DOCUMENT_ID]:e},async()=>{let t=await s.getDocument(o.fromString(e));return t?a&&!await a(t,"read")?(null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e}`,code:"KB07"}),null):(null!=l.complexity&&(l.complexity.resolverCount++,l.complexity.documentsScanned++),t):null});if(l.complexity?.resolverTimings!=null){let e=Math.round((performance.now()-i)*100)/100,o=l.complexity.resolverTimings.get(t)??0;l.complexity.resolverTimings.set(t,o+e)}return c},searchDocuments:async(e,t,o)=>await s.searchDocuments({query:e,modelIDs:t,first:o}),async resolveConnection(e,t){let o=`connection:${e.join(",")}`,i=l.complexity?.resolverTimings!=null?performance.now():0,c=await u(r.DATA_QUERY,{[n.MODEL_ID]:e.join(",")},async()=>{if(null!=t.search&&""!==t.search.trim()){let o=await s.searchDocuments({query:t.search,modelIDs:e,first:200});if(0===o.length){if(null!=l.complexity)for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);return{edges:[],pageInfo:{hasNextPage:!1,hasPreviousPage:!1,startCursor:null,endCursor:null}}}let n=o.map(e=>e.documentID),r=await s.listDocuments({modelIDs:e,docIDs:n}),i=r;if(a)for(let e of(i=[],r))await a(e,"read")?i.push(e):null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e.id}`,code:"KB07"});let u=new Map(o.map(e=>[e.documentID,e.rank]));i.sort((e,t)=>Math.abs(u.get(t.id)??0)-Math.abs(u.get(e.id)??0));let c=i.slice(0,t.first??50);if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=c.length}return{edges:c.map((e,t)=>({cursor:String(t),node:e})),pageInfo:{hasNextPage:i.length>c.length,hasPreviousPage:!1,startCursor:c.length>0?"0":null,endCursor:c.length>0?String(c.length-1):null}}}if(null==a){let{entries:o,hasMore:n}=await s.queryDocuments({...t,modelIDs:e,catalogID:l.catalogID});if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=o.length}return{edges:o.map(e=>({cursor:e.cursor,node:e.document})),pageInfo:{hasNextPage:!!t.first&&n,hasPreviousPage:!t.first&&n,endCursor:o.at(-1)?.cursor??null,startCursor:o.at(0)?.cursor??null}}}let o=[],n=0,r=0;if(null!=t.first){let i=2*(n=t.first),u=t.after;for(;o.length<n&&r<10;){let{entries:c,hasMore:m}=await s.queryDocuments({...t,modelIDs:e,catalogID:l.catalogID,first:i,after:u});if(0===c.length&&!m)break;for(let e of c)if(await a(e.document,"read")){if(o.push(e),o.length>=n)break}else null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e.document.id}`,code:"KB07"});if(!m)break;u=c.at(-1)?.cursor??null,r++}}else if(null!=t.last){let i=2*(n=t.last),u=t.before;for(;o.length<n&&r<10;){let{entries:c,hasMore:m}=await s.queryDocuments({...t,modelIDs:e,catalogID:l.catalogID,last:i,before:u});if(0===c.length&&!m)break;for(let e of[...c].reverse())if(await a(e.document,"read")){if(o.unshift(e),o.length>=n)break}else null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e.document.id}`,code:"KB07"});if(!m)break;u=c.at(0)?.cursor??null,r++}}let i=o.slice(0,n),u=o.length>n;if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=i.length}return{edges:i.map(e=>({cursor:e.cursor,node:e.document})),pageInfo:{hasNextPage:!!t.first&&u,hasPreviousPage:!t.first&&u,endCursor:i.at(-1)?.cursor??null,startCursor:i.at(0)?.cursor??null}}});if(l.complexity?.resolverTimings!=null){let e=Math.round((performance.now()-i)*100)/100,t=l.complexity.resolverTimings.get(o)??0;l.complexity.resolverTimings.set(o,t+e)}return c},async resolveList(e,t){let o=`list:${e.join(",")}`,i=l.complexity?.resolverTimings!=null?performance.now():0,c=await u(r.DATA_QUERY,{[n.MODEL_ID]:e.join(",")},async()=>{let o=await s.listDocuments({modelIDs:e,docIDs:t});if(!a){if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=o.length}return o}let n=[];for(let e of o)await a(e,"read")?n.push(e):null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e.id}`,code:"KB07"});if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=n.length}return n});if(l.complexity?.resolverTimings!=null){let e=Math.round((performance.now()-i)*100)/100,t=l.complexity.resolverTimings.get(o)??0;l.complexity.resolverTimings.set(o,t+e)}return c},async resolveCount(e,t){let o=`count:${e.join(",")}`,i=l.complexity?.resolverTimings!=null?performance.now():0,a=await u(r.DATA_QUERY,{[n.MODEL_ID]:e.join(",")},async()=>(null!=l.complexity&&l.complexity.resolverCount++,await s.countDocuments({modelIDs:e,filter:t,catalogID:l.catalogID})));if(l.complexity?.resolverTimings!=null){let e=Math.round((performance.now()-i)*100)/100,t=l.complexity.resolverTimings.get(o)??0;l.complexity.resolverTimings.set(o,t+e)}return a},subscribeToDocumentCreated(e,t){let o=c(o=>"create"===o.type&&e.includes(o.document.model)&&(null==t||o.document.owner===t),e=>e.document);return a?async function*(){for await(let e of o)await a(e,"read")&&(yield e)}():o},subscribeToDocumentChanged(e){let t=c(t=>"update"===t.type&&t.document.id===e&&null!==t.document.data,e=>e.document);return a?async function*(){for await(let e of t)await a(e,"read")&&(yield e)}():t},subscribeToDocumentRemoved:()=>c(e=>"update"===e.type&&null===e.document.data,e=>e.document.id),subscribeToDocumentEdgeAdded(e,t){let o=c(o=>null!==o.document.data&&e.includes(o.document.model)&&t(o.document.data)&&("create"===o.type||null!==o.previous.data&&t(o.previous.data)),e=>({cursor:e.getCursor(),node:e.document}));return a?async function*(){for await(let e of o)await a(e.node,"read")&&(yield e)}():o},subscribeToDocumentEdgeRemoved:(e,t)=>c(o=>"update"===o.type&&e.includes(o.document.model)&&null!==o.previous.data&&t(o.previous.data)&&(null===o.document.data||!t(o.document.data)),e=>e.document.id)}}
package/lib/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export type { AccessWarning, ComplexityStats, Context, CreateMutationParams, MutationContext, QueryContext, ReadContextParams, ReadOnlyContext, RemoveMutationParams, SetDocumentAccessOverrideParams, SetModelAccessDefaultsParams, SetMutationParams, SubscriptionContext, UpdateMutationParams, } from './context.js';
1
+ export type { AccessWarning, ComplexityStats, Context, CreateMutationParams, DocumentEventEmitter, DocumentSavedEvent, MutationContext, QueryContext, ReadContextDB, ReadContextParams, ReadOnlyContext, RemoveMutationParams, SetDocumentAccessOverrideParams, SetModelAccessDefaultsParams, SetMutationParams, SubscriptionContext, UpdateMutationParams, } from './context.js';
2
2
  export { createReadContext } from './context.js';
3
3
  export { GraphQLAttachmentID, GraphQLDocID } from './identifiers.js';
4
- export type { SchemaBuilderParams, SharedDefinitions, } from './schema.js';
4
+ export type { ExtensionResolvers, SchemaBuilderParams, SharedDefinitions, } from './schema.js';
5
5
  export { createSchema, SchemaBuilder } from './schema.js';
6
6
  export type * from './types.js';
package/lib/schema.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AttachmentID, DocumentModelID } from '@kubun/id';
2
2
  import type { ArrayModel, DocumentData, DocumentModel, DocumentModelSchema, DocumentModelsRecord, DocumentNode, ObjectModel, ReferencesRecordModel, ScalarModel, StringCustomModel, StringEnumModel, StringFormatModel, StringModel, TypeModel } from '@kubun/protocol';
3
- import { GraphQLEnumType, type GraphQLFieldConfig, type GraphQLFieldConfigMap, GraphQLInputObjectType, type GraphQLInputType, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, type GraphQLOutputType, type GraphQLScalarType, GraphQLSchema } from 'graphql';
3
+ import { GraphQLEnumType, type GraphQLFieldConfig, type GraphQLFieldConfigMap, type GraphQLFieldResolver, GraphQLInputObjectType, type GraphQLInputType, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, type GraphQLOutputType, type GraphQLScalarType, GraphQLSchema } from 'graphql';
4
4
  import type { Context } from './context.js';
5
5
  export declare function toDocumentModelID(id: DocumentModelID | string): DocumentModelID;
6
6
  export declare function getGlobalID(id: DocumentModelID | string, globalID: DocumentModelID | string): DocumentModelID;
@@ -24,6 +24,18 @@ type RelationField = {
24
24
  isList: boolean;
25
25
  };
26
26
  type RelationFields = Record<string, Array<RelationField>>;
27
+ export type ExtensionResolvers = {
28
+ queryFields?: Record<string, GraphQLFieldResolver<unknown, Context>>;
29
+ mutationFields?: Record<string, GraphQLFieldResolver<unknown, Context>>;
30
+ subscriptionFields?: Record<string, {
31
+ resolve: GraphQLFieldResolver<unknown, Context>;
32
+ subscribe: GraphQLFieldResolver<unknown, Context>;
33
+ }>;
34
+ typeFields?: Record<string, Record<string, GraphQLFieldResolver<unknown, Context>>>;
35
+ nodeResolvers?: Record<string, {
36
+ resolve: (localID: string, ctx: Context) => Promise<unknown> | unknown;
37
+ }>;
38
+ };
27
39
  export type SchemaBuilderParams = {
28
40
  record: DocumentModelsRecord;
29
41
  aliases?: Record<string, string>;
@@ -32,8 +44,12 @@ export type SchemaBuilderParams = {
32
44
  includeRelationDependencies?: boolean;
33
45
  includeMutations?: boolean;
34
46
  includeSubscriptions?: boolean;
47
+ extensionSDL?: string;
48
+ extensionResolvers?: ExtensionResolvers;
49
+ stubExtensionResolvers?: boolean;
35
50
  };
36
51
  export declare class SchemaBuilder {
52
+ #private;
37
53
  _aliases: Record<string, string>;
38
54
  _aliasToModelID: Record<string, string>;
39
55
  _definitions: SharedDefinitions | undefined;
@@ -50,6 +66,12 @@ export declare class SchemaBuilder {
50
66
  _record: DocumentModelsRecord;
51
67
  _references: ReferencesRecordModel;
52
68
  _relationsTo: Record<string, RelationFields>;
69
+ _extensionSDL: string | undefined;
70
+ _extensionResolvers: ExtensionResolvers | undefined;
71
+ _stubExtensionResolvers: boolean;
72
+ _pluginNodeResolvers: Record<string, {
73
+ resolve: (localID: string, ctx: Context) => Promise<unknown> | unknown;
74
+ }>;
53
75
  _subscriptions: GraphQLFieldConfigMap<unknown, Context>;
54
76
  _types: Record<string, GraphQLOutputType>;
55
77
  constructor(params: SchemaBuilderParams);
package/lib/schema.js CHANGED
@@ -1 +1 @@
1
- import{AttachmentID as e,DocumentID as t,DocumentModelID as i,decodeID as n}from"@kubun/id";import{REFERENCE_PREFIX as s}from"@kubun/protocol";import{pascalCase as r}from"change-case";import{GraphQLBoolean as l,GraphQLEnumType as o,GraphQLFloat as a,GraphQLID as u,GraphQLInputObjectType as c,GraphQLInt as d,GraphQLInterfaceType as p,GraphQLList as h,GraphQLNonNull as f,GraphQLObjectType as m,GraphQLSchema as y,GraphQLString as _,isEnumType as b,isListType as w,isNonNullType as D}from"graphql";import{connectionArgs as I,connectionDefinitions as g,mutationWithClientMutationId as O,nodeDefinitions as $}from"graphql-relay";import{GraphQLDateTimeISO as v,GraphQLDID as j,GraphQLDuration as S,GraphQLEmailAddress as M,GraphQLJSON as T,GraphQLJSONObject as F}from"graphql-scalars";import{GraphQLAttachmentID as R,GraphQLDocID as A}from"./identifiers.js";import{GraphQLURL as L}from"./scalars.js";import{getUniqueDocValue as q}from"./utils.js";let P={date:_,time:_,"date-time":_,duration:S,email:M,uri:L},C={attachmentid:R,did:j,docid:A};function E(e){return e.slice(s.length)}function G(e){return w(e)||D(e)&&w(e.ofType)}export function toDocumentModelID(e){return e instanceof i?e:i.fromString(e)}export function getGlobalID(e,t){let i=toDocumentModelID(e);return i.isLocal?i.toGlobal(toDocumentModelID(t)):i}export function toList(e){return new h(new f(e))}export function toOuputList(e){return new h(new f(e))}function V(e){return new c({name:`${e.name}ValueFilter`,isOneOf:!0,fields:{isNull:{type:l},equalTo:{type:e},notEqualTo:{type:e},in:{type:toList(e)},notIn:{type:toList(e)},lessThan:{type:e},lessThanOrEqualTo:{type:e},greaterThan:{type:e},greaterThanOrEqualTo:{type:e}}})}let B={AccountValueFilter:new c({name:"AccountValueFilter",isOneOf:!0,fields:{equalTo:{type:j},notEqualTo:{type:j},in:{type:toList(j)},notIn:{type:toList(j)}}}),BooleanValueFilter:new c({name:"BooleanValueFilter",isOneOf:!0,fields:{isNull:{type:l},equalTo:{type:l}}}),FloatValueFilter:V(a),IntValueFilter:V(d),StringValueFilter:V(_)},k={GraphQLBoolean:"BooleanValueFilter",GraphQLDID:"AccountValueFilter",GraphQLFloat:"FloatValueFilter",GraphQLInt:"IntValueFilter",GraphQLString:"StringValueFilter"},x=new c({name:"PatchSetOperation",fields:{path:{type:new f(_)},value:{type:T}}}),N=new c({name:"PatchRemoveOperation",fields:{path:{type:new f(_)}}}),Q=new c({name:"PatchDestinationOperation",fields:{from:{type:new f(_)},path:{type:new f(_)}}});export const PatchOperation=new c({name:"PatchOperation",isOneOf:!0,fields:{add:{type:x},set:{type:x},remove:{type:N},replace:{type:x},copy:{type:Q},move:{type:Q}}});let U=new o({name:"OrderByDirection",values:{ASC:{value:"asc"},DESC:{value:"desc"}}}),W=new m({name:"AccessRule",fields:{level:{type:new f(_)},allowedDIDs:{type:new h(new f(_))}}}),z=new m({name:"AccessPermissions",fields:{read:{type:W},write:{type:W}}}),H=new m({name:"ModelAccessDefaults",fields:()=>({ownerDID:{type:new f(_)},modelId:{type:new f(u)},permissions:{type:new f(z)}})});export class SchemaBuilder{_aliases;_aliasToModelID;_definitions;_implemented={};_includedModelIDs;_includeInterfaceDependencies;_includeMutations;_includeRelationDependencies;_includeSubscriptions;_inputObjects={...B,PatchOperation};_mutations={};_nodeModelIDs;_onlyModels;_record;_references={};_relationsTo={};_subscriptions={};_types={OrderByDirection:U};constructor(e){for(let[t,i]of(this._record=e.record,this._onlyModels=e.onlyModels??null,this._includeInterfaceDependencies=e.includeInterfaceDependencies??!0,this._includeRelationDependencies=e.includeRelationDependencies??!0,this._includeMutations=e.includeMutations??!0,this._includeSubscriptions=e.includeSubscriptions??!0,this._aliasToModelID=e.aliases??{},this._aliases={},Object.entries(this._aliasToModelID)))this._aliases[i]=t;this._includedModelIDs=this._resolveModelIDsToInclude();let t={};for(let[n,s]of Object.entries(e.record)){let e=i.fromString(n);for(let i of(Object.assign(this._references,s.schema.$defs??{}),s.interfaces)){let s=getGlobalID(i,e).toString();t[s]??=new Set,t[s].add(n)}for(let[t,i]of Object.entries(s.fieldsMeta))if("document"===i.type&&null!=i.model){let r=E(s.schema.properties[t]?.$ref),l="array"===this._getReferenceSchema(r).type,o=getGlobalID(i.model,e).toString();this._relationsTo[o]??={},this._relationsTo[o][t]??=[],this._relationsTo[o][t].push({model:n,isList:l})}}let n=new Set;for(let e of Object.keys(t)){let i=new Set;for(let s of(!function e(t,i,n){let s=i[n];if(null==s)throw Error(`Interface ${n} not found in record`);for(let n of s)null!=i[n]?e(t,i,n):t.add(n)}(i,t,e),0!==i.size&&(this._implemented[e]=Array.from(i)),i))n.add(s)}this._nodeModelIDs=Array.from(n)}_resolveModelIdentifier(e){if(null!=this._record[e])return e;let t=this._aliasToModelID[e];if(null!=t&&null!=this._record[t])return t;throw Error(`Model identifier "${e}" not found. Must be a valid model ID or alias.`)}_resolveModelIDsToInclude(){if(null==this._onlyModels||0===this._onlyModels.length)return new Set(Object.keys(this._record));let e=new Set;for(let t of this._onlyModels){let i=this._resolveModelIdentifier(t);e.add(i)}if(!this._includeInterfaceDependencies&&!this._includeRelationDependencies)return e;let t=Array.from(e),i=new Set;for(;t.length>0;){let n=t.pop();if(null==n||i.has(n))continue;i.add(n);let s=this._record[n];if(null!=s){if(this._includeInterfaceDependencies)for(let i of s.interfaces){let s=getGlobalID(i,n).toString();e.has(s)||(e.add(s),t.push(s))}if(this._includeRelationDependencies){for(let i of Object.values(s.fieldsMeta))if("document"===i.type&&null!=i.model&&null!==i.model){let s=getGlobalID(i.model,n).toString();e.has(s)||(e.add(s),t.push(s))}}}}return e}getModelIDs(e){return null===e?this._nodeModelIDs:this._implemented[e]??[e]}build(){let e=this._buildSharedDefinitions();this._definitions=e;let t={nodes:e.nodesField,...e.queryFields};for(let e of this._includedModelIDs){this._buildDocument(e);let i=this._aliases[e],n={type:this._inputObjects[`${e}-filter`]};t[`all${i}`]={type:this._types[`${e}-connection`],args:{...I,filter:n,orderBy:{type:toList(this._inputObjects[`${e}-order`])},search:{type:_}},resolve:async(t,i,n)=>await n.resolveConnection(this.getModelIDs(e),i)},t[`all${i}Count`]={type:new f(d),args:{filter:n},resolve:(t,i,n)=>n.resolveCount(this.getModelIDs(e),i.filter)}}let i=[...this._includedModelIDs][0];if(null!=i){let n=this._types[`${i}-connection`].getFields().pageInfo.type,s=new m({name:"SearchResultEdge",fields:()=>({cursor:{type:new f(_)},node:{type:new f(e.nodeInterface)},rank:{type:new f(a)}})}),r=new m({name:"SearchResultConnection",fields:()=>({edges:{type:new f(new h(new f(s)))},pageInfo:{type:n}})});t.search={type:new f(r),args:{query:{type:new f(_)},models:{type:new h(new f(_))},first:{type:d},after:{type:_}},resolve:async(e,t,i)=>{let{query:n,models:s,first:r}=t;if(""===n.trim())throw Error("Search query must not be empty");let l=s?s.map(e=>this._aliasToModelID[e]??e):[...this._includedModelIDs],o=await i.searchDocuments(n,l,r??20),a=o.map(e=>e.documentID),u=[...new Set(o.map(e=>e.modelID))],c=new Map((a.length>0?await i.resolveList(u,a):[]).map(e=>[e.id,e])),d=[];for(let e of o){let t=c.get(e.documentID);null!=t&&d.push({cursor:String(d.length),node:t,rank:Math.abs(e.rank)})}return{edges:d,pageInfo:{hasNextPage:!1,hasPreviousPage:!1,startCursor:d.length>0?d[0].cursor:null,endCursor:d.length>0?d[d.length-1].cursor:null}}}}}if(this._includeMutations){this._mutations.setModelAccessDefaults={type:H,args:{modelId:{type:new f(u)},permissionType:{type:new f(_)},accessLevel:{type:new f(_)},allowedDIDs:{type:toList(_)}},resolve:async(e,t,i)=>await i.executeSetModelAccessDefaults({modelID:t.modelId,permissionType:t.permissionType,accessLevel:t.accessLevel,allowedDIDs:t.allowedDIDs??null})},this._mutations.removeModelAccessDefaults={type:l,args:{modelId:{type:new f(u)},permissionTypes:{type:new f(toList(_))}},resolve:async(e,t,i)=>(await i.executeRemoveModelAccessDefaults(t.modelId,t.permissionTypes),!0)},this._mutations.setDocumentAccessOverride={type:e.documentInterface,args:{documentId:{type:new f(u)},permissionType:{type:new f(_)},accessLevel:{type:new f(_)},allowedDIDs:{type:toList(_)}},resolve:async(e,t,i)=>await i.executeSetDocumentAccessOverride({documentID:t.documentId,permissionType:t.permissionType,accessLevel:t.accessLevel,allowedDIDs:t.allowedDIDs??null})},this._mutations.removeDocumentAccessOverride={type:l,args:{documentId:{type:new f(u)},permissionTypes:{type:new f(toList(_))}},resolve:async(e,t,i)=>(await i.executeRemoveDocumentAccessOverride(t.documentId,t.permissionTypes),!0)};let t=new m({name:"BeginTransactionPayload",fields:{transactionID:{type:new f(u)}}}),i=new m({name:"CommitTransactionPayload",fields:{success:{type:new f(l)}}}),n=new m({name:"RollbackTransactionPayload",fields:{success:{type:new f(l)}}});this._mutations.beginTransaction={type:new f(t),args:{},resolve:(e,t,i)=>i.beginTransaction()},this._mutations.commitTransaction={type:new f(i),args:{transactionID:{type:new f(u)}},resolve:async(e,t,i)=>await i.commitTransaction(t.transactionID)},this._mutations.rollbackTransaction={type:new f(n),args:{transactionID:{type:new f(u)}},resolve:(e,t,i)=>i.rollbackTransaction(t.transactionID)}}let n={query:new m({name:"Query",fields:t})};return this._includeMutations&&(n.mutation=new m({name:"Mutation",fields:this._mutations})),this._includeSubscriptions&&(n.subscription=new m({name:"Subscription",fields:()=>{let t={documentChanged:{type:new f(e.documentInterface),args:{id:{type:new f(u)}},resolve:e=>e,subscribe:(e,t,i)=>i.subscribeToDocumentChanged(t.id)},documentRemoved:{type:new f(u),resolve:e=>e,subscribe:(e,t,i)=>i.subscribeToDocumentRemoved()}};for(let[e,i]of Object.entries(this._record)){if(!this._includedModelIDs.has(e))continue;let n=this._aliases[e];for(let s of(t[`new${n}Created`]={type:new f(this._types[e]),resolve:e=>e,subscribe:(t,i,n)=>n.subscribeToDocumentCreated(this.getModelIDs(e))},i.interfaces??[])){let i=getGlobalID(s,e).toString();for(let[e,n]of Object.entries(this._relationsTo[i]??{}))for(let s of n)this._buildRelationSubscriptions(t,i,e,s)}for(let[i,n]of Object.entries(this._relationsTo[e]??{}))for(let s of n)this._includedModelIDs.has(s.model)&&this._buildRelationSubscriptions(t,e,i,s)}return t}})),new y(n)}_getDefinitions(){if(null==this._definitions)throw Error("Definitions must be initialized");return this._definitions}_getReference(e,t){let i=E(e),n=this._types[i];if(null!=n)return n;let s=this._getReferenceSchema(i);return this._buildReference(i,s,t)}_getReferenceSchema(e){let t=this._references[e];if(null==t)throw Error(`Could not find reference: ${e}`);return t}_getReferenceInput(e,t,i=""){let n=E(e),s=this._getReferenceSchema(n);if("array"===s.type)return new h(new f(this._getReferenceInput(s.items.$ref,!1,s.title)));if("object"===s.type){if(s.additionalProperties)return F;let e=t?`${n}-partial`:n,l=this._inputObjects[e];if(null!=l)return l;let o={};for(let[e,i]of Object.entries(s.properties)){let n=this._getReferenceInput(i.$ref,t,s.title);o[e]={type:t||!s.required.includes(e)?n:new f(n)}}let a=this._aliases[n]??r(i+s.title),u=new c({name:t?`Partial${a}Input`:`${a}Input`,fields:o});return this._inputObjects[e]=u,u}return this._buildScalar(n,s,i)}_buildSharedDefinitions(){let i=$(async(i,s)=>{if(i.startsWith("did:"))return i;let r=n(i);if(r instanceof e)return r;if(r instanceof t)return await s.loadDocument(i);throw Error(`Unsupported node ID: ${i}`)},t=>"string"==typeof t?"AccountNode":t instanceof e?"AttachmentNode":this._aliases[t.model]),s=new m({name:"AccountNode",interfaces:[i.nodeInterface],fields:()=>{let e={id:{type:new f(u),description:"Globally unique identifier of the account (DID string)",resolve:e=>e},isViewer:{type:new f(l),description:"Whether the authenticated request issuer is this account or not",resolve:(e,t,i)=>i.getViewer()===e}};for(let[i,n]of Object.entries(this._record))if(this._includedModelIDs.has(i))switch(n.behavior){case"interface":continue;case"default":{let t=this._aliases[i];e[`own${t}Connection`]={type:this._types[`${i}-connection`],args:{...I,filter:{type:this._inputObjects[`${i}-filter`]},orderBy:{type:toList(this._inputObjects[`${i}-order`])}},resolve:async(e,t,n)=>await n.resolveConnection(this.getModelIDs(i),{...t,owner:e})};break}case"unique":{let s=this._aliases[i];e[`own${s}`]={type:this._types[i],args:n.uniqueFields.length?{with:{type:new f(this._buildSetInputObjectType(i,n.uniqueFields))}}:{},resolve:async(e,s,r)=>{let l=q(n.uniqueFields,s.with),o=t.create(i,e,l);return await r.loadDocument(o.toString())}}}}return e}}),r=new m({name:"AttachmentNode",interfaces:[i.nodeInterface],fields:{id:{type:new f(u),resolve:e=>e.toString()},contentLength:{type:new f(d)},mimeType:{type:new f(_)}}}),o={id:{type:new f(u)},model:{type:new f(_)},owner:{type:new f(s)},createdAt:{type:new f(v)},updatedAt:{type:v},accessPermissions:{type:z,resolve:e=>e.data?.accessPermissions??null}},a=new p({name:"DocumentNode",interfaces:[i.nodeInterface],fields:o,resolveType:e=>this._aliases[e.model]}),c={node:i.nodeField,viewer:{type:s,description:"Account issuing the request, if authenticated",resolve:(e,t,i)=>i.getViewer()}};return{...i,accountObject:s,attachmentObject:r,documentInterface:a,documentNodeFields:o,queryFields:c}}_buildDocument(e){if(null!=this._types[e])return this._types[e];let t=this._record[e];if(null==t)throw Error(`Could not find model id: ${e}`);let i=this._getDefinitions();this._aliases[e]??=r(t.name);let n=this._aliases[e],s={name:n,interfaces:()=>[i.documentInterface,i.nodeInterface].concat(t.interfaces.map(t=>this._types[getGlobalID(t,e).toString()]).filter(e=>null!=e)),fields:()=>this._buildDocumentFields(e,t,n)},l="interface"===t.behavior,o=l?new p({...s,resolveType:e=>this._aliases[e.model]}):new m(s),{connectionType:a,edgeType:c}=g({nodeType:o});return this._types[e]=o,this._types[`${e}-connection`]=a,this._types[`${e}-edge`]=c,this._buildDocumentDataObject(e,t,n),this._buildDocumentInput(e,t),this._buildObjectFilterInput(e,t.schema,n,!0),this._buildObjectOrderByInput(e,t.schema,n,!0),!l&&this._includeMutations&&("default"===t.behavior?this._mutations[`create${n}`]=O({name:`Create${n}`,inputFields:()=>({data:{type:new f(this._inputObjects[e])},transactionID:{type:u}}),outputFields:()=>({...i.queryFields,document:{type:this._types[e]}}),mutateAndGetPayload:async(t,i,n)=>({document:await i.executeCreateMutation({modelID:e,data:t.data,info:n,transactionID:t.transactionID})})}):"unique"===t.behavior&&(this._mutations[`set${n}`]=O({name:`Set${n}`,inputFields:()=>({data:{type:new f(this._inputObjects[e])},transactionID:{type:u}}),outputFields:()=>({...i.queryFields,document:{type:this._types[e]}}),mutateAndGetPayload:async(i,n,s)=>{let r=q(t.uniqueFields,i.data);return{document:await n.executeSetMutation({modelID:e,unique:r,data:i.data,info:s,transactionID:i.transactionID})}}})),this._mutations[`update${n}`]=O({name:`Update${n}`,inputFields:()=>({id:{type:new f(u)},patch:{type:new f(toList(PatchOperation))},from:{type:this._inputObjects[`${e}-update`]},transactionID:{type:u}}),outputFields:()=>({...i.queryFields,document:{type:this._types[e]}}),mutateAndGetPayload:async(e,t,i)=>({document:await t.executeUpdateMutation({input:e,info:i,transactionID:e.transactionID})})}),this._mutations[`remove${n}`]=O({name:`Remove${n}`,inputFields:()=>({id:{type:new f(u)},transactionID:{type:u}}),outputFields:()=>({...i.queryFields,id:{type:new f(u)}}),mutateAndGetPayload:async(e,t,i)=>(await t.executeRemoveMutation({id:e.id,info:i,transactionID:e.transactionID}),{id:e.id})})),o}_buildDocumentFields(t,i,n){let s=this._buildDocumentDataObject(t,i,n),r=this._getDefinitions(),l={...r.documentNodeFields,data:{type:new f(s)}};for(let[n,o]of Object.entries(s.getFields())){let s=i.fieldsMeta[n];if(null!=s)switch(s.type){case"account":G(o.type)?l[`${n}Accounts`]={type:new f(toOuputList(r.accountObject)),resolve:e=>e.data?.[n]??[]}:l[`${n}Account`]={type:r.accountObject,resolve:e=>e.data?.[n]??null};break;case"attachment":G(o.type)?l[`${n}Attachments`]={type:new f(toOuputList(r.attachmentObject)),resolve:t=>(t.data?.[n]??[]).map(e.fromString)}:l[`${n}Attachment`]={type:r.attachmentObject,resolve:t=>{let i=t.data?.[n];return i?e.fromString(i):null}};break;case"document":{let e,i,a=s.model;if(void 0===a)continue;null===a?(e=null,i=r.documentInterface):(e=getGlobalID(a,t).toString(),this._includedModelIDs.has(e)?i=this._buildDocument(e):(i=r.documentInterface,e=null)),G(o.type)?l[`${n}Documents`]={type:new f(toOuputList(i)),resolve:async(t,i,s)=>{let r=t.data?.[n]??[];return r.length?await s.resolveList(this.getModelIDs(e),r):[]}}:l[`${n}Document`]={type:i,resolve:async(e,t,i)=>{let s=e.data?.[n];return s?await i.loadDocument(s):null}}}}}for(let e of i.interfaces??[]){let i=getGlobalID(e,t).toString();for(let[e,t]of Object.entries(this._relationsTo[i]??{}))for(let i of t)this._includedModelIDs.has(i.model)&&this._buildRelationFields(l,e,i)}for(let[e,i]of Object.entries(this._relationsTo[t]??{}))for(let t of i)this._includedModelIDs.has(t.model)&&this._buildRelationFields(l,e,t);return l}_buildDocumentDataObject(e,t,i){let n=`${e}-data`;if(null!=this._types[n])return this._types[n];let s=t.schema.required??[],r={};for(let[i,n]of Object.entries(t.schema.properties??{})){let t=n.$ref;if(null==t)throw Error(`Missing ref for field ${i} of object ${e}`);let l=this._getReference(t);r[i]={type:s.includes(i)?new f(l):l}}let l={name:`${i}Data`,interfaces:()=>t.interfaces.map(t=>{let i=`${getGlobalID(t,e).toString()}-data`;return this._types[i]}).filter(e=>null!=e),fields:r},o="interface"===t.behavior?new p(l):new m(l);return this._types[n]=o,o}_buildDocumentInput(e,t){if("interface"===t.behavior)return;let i={},n={};for(let[e,s]of Object.entries(t.schema.properties)){let r=s.$ref,l=this._getReferenceInput(r,!1);i[e]={type:t.schema.required.includes(e)?new f(l):l};let o=E(r);null==this._getReferenceSchema(o).const&&(n[e]={type:this._getReferenceInput(r,!0)})}let s=this._aliases[e];this._inputObjects[e]=new c({name:`${s}Input`,fields:i}),this._inputObjects[`${e}-update`]=new c({name:`Partial${s}Input`,fields:n})}_buildReferenceFilterInput(e,t=""){let i=E(e),n=this._getReferenceSchema(i),s=t;if("object"===n.type)return n.additionalProperties?null:this._buildObjectFilterInput(i,n,t);if("array"===n.type){let e=this._aliases[i]??r(t+n.title);return s=e,new c({name:`${e}Filter`,isOneOf:!0,fields:{isNull:{type:l}}})}let o=this._buildScalar(i,n,s),a=k[o.name];if(null!=a)return this._inputObjects[a];let u=b(o)?new c({name:`${o.name}ValueFilter`,isOneOf:!0,fields:{isNull:{type:l},equalTo:{type:o},notEqualTo:{type:o},in:{type:toList(o)},notIn:{type:toList(o)}}}):V(o);return null==this._inputObjects[u.name]&&(this._inputObjects[u.name]=u),this._inputObjects[u.name]}_buildReferenceOrderByInput(e,t=""){let i=E(e),n=this._getReferenceSchema(i);switch(n.type){case"array":return null;case"object":return n.additionalProperties?null:this._buildObjectOrderByInput(i,n,t);default:return U}}_buildObjectFilterInput(e,t,i="",n=!1){let s=`${e}-filter`,l=this._inputObjects[s];if(null!=l)return l;let o=this._aliases[e]??r(i+(t.title??"")),a=n?{_owner:{type:this._inputObjects.AccountValueFilter}}:{};for(let[e,i]of Object.entries(t.properties)){let t=this._buildReferenceFilterInput(i.$ref,o);null!==t&&(a[e]={type:t})}let u=new c({name:`${o}ObjectFilter`,fields:a}),d=new c({name:`${o}Filter`,isOneOf:!0,fields:()=>({where:{type:u},and:{type:toList(this._inputObjects[s])},or:{type:toList(this._inputObjects[s])},not:{type:this._inputObjects[s]}})});return this._inputObjects[s]=d,d}_buildObjectOrderByInput(e,t,i="",n=!1){let s=`${e}-order`,l=this._inputObjects[s];if(null!=l)return l;let o=this._aliases[e]??r(i+(t.title??"")),a=n?{_docOwner:{type:U},_createdAt:{type:U}}:{};for(let[e,i]of Object.entries(t.properties)){let t=this._buildReferenceOrderByInput(i.$ref,o);null!=t&&(a[e]={type:t})}let u=new c({name:`${o}OrderBy`,isOneOf:!0,fields:a});return this._inputObjects[s]=u,u}_buildSetInputObjectType(e,t,i){let n=i?r(i):"",s=`${e}-with-${n}`,l=this._inputObjects[s];if(null!=l)return l;let o=this._record[e],a=this._aliases[e];return this._inputObjects[s]=new c({name:`With${n}${a}Input`,fields:()=>{let e={};for(let i of t){let t=o.schema.properties[i];if(null==t)throw Error(`Field ${i} not found on model ${a}`);let n=this._getReferenceInput(t.$ref,!1);e[i]={type:new f(n)}}return e}}),this._inputObjects[s]}_buildReference(e,t,i=""){if(null!=this._types[e])return this._types[e];switch(t.type){case"array":return this._types[e]=this._buildArray(t,i),this._types[e];case"object":return this._types[e]=t.additionalProperties?F:this._buildObject(e,t,i),this._types[e];default:return this._buildScalar(e,t,i)}}_buildScalar(e,t,i=""){if(null!=this._types[e])return this._types[e];switch(t.type){case"boolean":this._types[e]=l;break;case"integer":this._types[e]=d;break;case"number":this._types[e]=a;break;case"string":this._types[e]=this._buildString(t,i)}return this._types[e]}_buildArray(e,t=""){let i=e.items.$ref;return new h(new f(this._getReference(i,r(t+e.title))))}_buildObject(e,t,i=""){let n=r(i+t.title),s=this._buildObjectFields(e,t,n);return new m({name:n,fields:s})}_buildObjectFields(e,t,i=""){let n=t.required??[],s={};for(let[r,l]of Object.entries(t.properties??{})){let t=l.$ref;if(null==t)throw Error(`Missing ref for field ${r} of object ${e}`);let o=this._getReference(t,i);s[r]={type:n.includes(r)?new f(o):o}}return s}_buildRelationFields(e,t,i){if(i.isList)return;let n=i.model,s=`${r(t)}Of${this._aliases[n]}`;e[`in${s}`]={type:new f(this._types[`${n}-connection`]),args:{...I,filter:{type:this._inputObjects[`${n}-filter`]},orderBy:{type:toList(this._inputObjects[`${n}-order`])}},resolve:(e,i,s)=>{let r={where:{[t]:{equalTo:e.id}}},l=i.filter?{and:[i.filter,r]}:r;return s.resolveConnection(this.getModelIDs(n),{...i,filter:l})}},e[`in${s}Count`]={type:new f(d),args:{filter:{type:this._inputObjects[`${n}-filter`]}},resolve:(e,i,s)=>{let r={where:{[t]:{equalTo:e.id}}},l=i.filter?{and:[i.filter,r]}:r;return s.resolveCount(this.getModelIDs(n),l)}}}_buildRelationSubscriptions(e,t,i,n){if(n.isList)return;let s=r(i);e[`edge${this._aliases[n.model]}AddedAs${s}To${this._aliases[t]}`]={type:new f(this._types[`${n.model}-edge`]),args:{id:{type:new f(u)}},resolve:e=>e,subscribe:(e,t,s)=>s.subscribeToDocumentEdgeAdded(this.getModelIDs(n.model),e=>e[i]===t.id)},e[`edge${this._aliases[n.model]}RemovedAs${s}From${this._aliases[t]}`]={type:new f(u),args:{id:{type:new f(u)}},resolve:e=>e,subscribe:(e,t,s)=>s.subscribeToDocumentEdgeRemoved(this.getModelIDs(n.model),e=>e[i]===t.id)}}_buildString(e,t){return null!=e.const?_:null!=e.enum?this._buildEnumString(e,t):null!=e.format?this._buildFormatString(e):this._buildCustomString(e)}_buildCustomString(e){return null==e.title?_:C[e.title.toLowerCase()]??_}_buildEnumString(e,t=""){let i=r(t+e.title),n=`${i}-enum`;if(null==this._types[n]){let t={};for(let i of e.enum)t[i]={value:i};this._types[n]=new o({name:i,values:t})}return this._types[n]}_buildFormatString(e){let t=P[e.format];if(null==t)throw Error(`Unsupported string format: ${e.format}`);return t}}export function createSchema(e){return new SchemaBuilder(e).build()}
1
+ import{AttachmentID as e,DocumentID as t,DocumentModelID as i,decodeID as n,PluginNodeID as s}from"@kubun/id";import{REFERENCE_PREFIX as r}from"@kubun/protocol";import{pascalCase as l}from"change-case";import{extendSchema as o,GraphQLBoolean as a,GraphQLEnumType as u,GraphQLFloat as c,GraphQLID as d,GraphQLInputObjectType as p,GraphQLInt as f,GraphQLInterfaceType as h,GraphQLList as y,GraphQLNonNull as m,GraphQLObjectType as _,GraphQLSchema as b,GraphQLString as w,isEnumType as D,isListType as g,isNonNullType as I,isObjectType as O,isScalarType as v,parse as $}from"graphql";import{connectionArgs as j,connectionDefinitions as S,mutationWithClientMutationId as F,nodeDefinitions as M}from"graphql-relay";import{GraphQLDateTimeISO as T,GraphQLDID as R,GraphQLDuration as L,GraphQLEmailAddress as E,GraphQLJSON as x,GraphQLJSONObject as A}from"graphql-scalars";import{GraphQLAttachmentID as q,GraphQLDocID as P}from"./identifiers.js";import{GraphQLURL as C}from"./scalars.js";import{getUniqueDocValue as G}from"./utils.js";function N(e){if(I(e))return N(e.ofType);if(g(e))return[];if(v(e))switch(e.name){case"String":case"ID":return"";case"Int":case"Float":return 0;case"Boolean":return!1;default:return null}if(D(e)){let t=e.getValues();return t[0]?.value??null}return{}}let V={date:w,time:w,"date-time":w,duration:L,email:E,uri:C},k={attachmentid:q,did:R,docid:P};function B(e){return e.slice(r.length)}function Q(e){return g(e)||I(e)&&g(e.ofType)}export function toDocumentModelID(e){return e instanceof i?e:i.fromString(e)}export function getGlobalID(e,t){let i=toDocumentModelID(e);return i.isLocal?i.toGlobal(toDocumentModelID(t)):i}export function toList(e){return new y(new m(e))}export function toOuputList(e){return new y(new m(e))}function U(e){return new p({name:`${e.name}ValueFilter`,isOneOf:!0,fields:{isNull:{type:a},equalTo:{type:e},notEqualTo:{type:e},in:{type:toList(e)},notIn:{type:toList(e)},lessThan:{type:e},lessThanOrEqualTo:{type:e},greaterThan:{type:e},greaterThanOrEqualTo:{type:e}}})}let W={AccountValueFilter:new p({name:"AccountValueFilter",isOneOf:!0,fields:{equalTo:{type:R},notEqualTo:{type:R},in:{type:toList(R)},notIn:{type:toList(R)}}}),BooleanValueFilter:new p({name:"BooleanValueFilter",isOneOf:!0,fields:{isNull:{type:a},equalTo:{type:a}}}),FloatValueFilter:U(c),IntValueFilter:U(f),StringValueFilter:U(w)},z={GraphQLBoolean:"BooleanValueFilter",GraphQLDID:"AccountValueFilter",GraphQLFloat:"FloatValueFilter",GraphQLInt:"IntValueFilter",GraphQLString:"StringValueFilter"},H=new p({name:"PatchSetOperation",fields:{path:{type:new m(w)},value:{type:x}}}),J=new p({name:"PatchRemoveOperation",fields:{path:{type:new m(w)}}}),K=new p({name:"PatchDestinationOperation",fields:{from:{type:new m(w)},path:{type:new m(w)}}});export const PatchOperation=new p({name:"PatchOperation",isOneOf:!0,fields:{add:{type:H},set:{type:H},remove:{type:J},replace:{type:H},copy:{type:K},move:{type:K}}});let X=new u({name:"OrderByDirection",values:{ASC:{value:"asc"},DESC:{value:"desc"}}}),Y=new _({name:"AccessRule",fields:{level:{type:new m(w)},allowedDIDs:{type:new y(new m(w))}}}),Z=new _({name:"AccessPermissions",fields:{read:{type:Y},write:{type:Y}}}),ee=new _({name:"ModelAccessDefaults",fields:()=>({ownerDID:{type:new m(w)},modelID:{type:new m(d)},permissions:{type:new m(Z)}})});export class SchemaBuilder{_aliases;_aliasToModelID;_definitions;_implemented={};_includedModelIDs;_includeInterfaceDependencies;_includeMutations;_includeRelationDependencies;_includeSubscriptions;_inputObjects={...W,PatchOperation};_mutations={};_nodeModelIDs;_onlyModels;_record;_references={};_relationsTo={};_extensionSDL;_extensionResolvers;_stubExtensionResolvers;_pluginNodeResolvers={};_subscriptions={};_types={OrderByDirection:X};constructor(e){for(let[t,i]of(this._record=e.record,this._onlyModels=e.onlyModels??null,this._includeInterfaceDependencies=e.includeInterfaceDependencies??!0,this._includeRelationDependencies=e.includeRelationDependencies??!0,this._includeMutations=e.includeMutations??!0,this._includeSubscriptions=e.includeSubscriptions??!0,this._extensionSDL=e.extensionSDL,this._extensionResolvers=e.extensionResolvers,this._stubExtensionResolvers=e.stubExtensionResolvers??!1,this._aliasToModelID=e.aliases??{},this._aliases={},Object.entries(this._aliasToModelID)))this._aliases[i]=t;for(let[t,i]of Object.entries(e.record))if(null==this._aliases[t]){let e=l(i.name);this._aliases[t]=e,this._aliasToModelID[e]??=t}this._includedModelIDs=this._resolveModelIDsToInclude();let t={};for(let[n,s]of Object.entries(e.record)){let e=i.fromString(n);for(let i of(Object.assign(this._references,s.schema.$defs??{}),s.interfaces)){let s=getGlobalID(i,e).toString();t[s]??=new Set,t[s].add(n)}for(let[t,i]of Object.entries(s.fieldsMeta))if("document"===i.type&&null!=i.model){let r=B(s.schema.properties[t]?.$ref),l="array"===this._getReferenceSchema(r).type,o=getGlobalID(i.model,e).toString();this._relationsTo[o]??={},this._relationsTo[o][t]??=[],this._relationsTo[o][t].push({model:n,isList:l})}}let n=new Set;for(let e of Object.keys(t)){let i=new Set;for(let s of(!function e(t,i,n){let s=i[n];if(null==s)throw Error(`Interface ${n} not found in record`);for(let n of s)null!=i[n]?e(t,i,n):t.add(n)}(i,t,e),0!==i.size&&(this._implemented[e]=Array.from(i)),i))n.add(s)}this._nodeModelIDs=Array.from(n)}_resolveModelIdentifier(e){if(null!=this._record[e])return e;let t=this._aliasToModelID[e];if(null!=t&&null!=this._record[t])return t;throw Error(`Model identifier "${e}" not found. Must be a valid model ID or alias.`)}_resolveModelIDsToInclude(){if(null==this._onlyModels||0===this._onlyModels.length)return new Set(Object.keys(this._record));let e=new Set;for(let t of this._onlyModels){let i=this._resolveModelIdentifier(t);e.add(i)}if(!this._includeInterfaceDependencies&&!this._includeRelationDependencies)return e;let t=Array.from(e),i=new Set;for(;t.length>0;){let n=t.pop();if(null==n||i.has(n))continue;i.add(n);let s=this._record[n];if(null!=s){if(this._includeInterfaceDependencies)for(let i of s.interfaces){let s=getGlobalID(i,n).toString();e.has(s)||(e.add(s),t.push(s))}if(this._includeRelationDependencies){for(let i of Object.values(s.fieldsMeta))if("document"===i.type&&null!=i.model&&null!==i.model){let s=getGlobalID(i.model,n).toString();e.has(s)||(e.add(s),t.push(s))}}}}return e}getModelIDs(e){return null===e?this._nodeModelIDs:this._implemented[e]??[e]}build(){let e=this._buildSharedDefinitions();this._definitions=e;let t={nodes:e.nodesField,...e.queryFields};for(let e of this._includedModelIDs){this._buildDocument(e);let i=this._aliases[e],n={type:this._inputObjects[`${e}-filter`]};t[`all${i}`]={type:this._types[`${e}-connection`],args:{...j,filter:n,orderBy:{type:toList(this._inputObjects[`${e}-order`])},search:{type:w}},resolve:async(t,i,n)=>await n.resolveConnection(this.getModelIDs(e),i)},t[`all${i}Count`]={type:new m(f),args:{filter:n},resolve:(t,i,n)=>n.resolveCount(this.getModelIDs(e),i.filter)}}let i=[...this._includedModelIDs][0];if(null!=i){let n=this._types[`${i}-connection`].getFields().pageInfo.type,s=new _({name:"SearchResultEdge",fields:()=>({cursor:{type:new m(w)},node:{type:new m(e.nodeInterface)},rank:{type:new m(c)}})}),r=new _({name:"SearchResultConnection",fields:()=>({edges:{type:new m(new y(new m(s)))},pageInfo:{type:n}})});t.search={type:new m(r),args:{query:{type:new m(w)},models:{type:new y(new m(w))},first:{type:f},after:{type:w}},resolve:async(e,t,i)=>{let{query:n,models:s,first:r}=t;if(""===n.trim())throw Error("Search query must not be empty");let l=s?s.map(e=>this._aliasToModelID[e]??e):[...this._includedModelIDs],o=await i.searchDocuments(n,l,r??20),a=o.map(e=>e.documentID),u=[...new Set(o.map(e=>e.modelID))],c=new Map((a.length>0?await i.resolveList(u,a):[]).map(e=>[e.id,e])),d=[];for(let e of o){let t=c.get(e.documentID);null!=t&&d.push({cursor:String(d.length),node:t,rank:Math.abs(e.rank)})}return{edges:d,pageInfo:{hasNextPage:!1,hasPreviousPage:!1,startCursor:d.length>0?d[0].cursor:null,endCursor:d.length>0?d[d.length-1].cursor:null}}}}}if(this._includeMutations){this._mutations.setModelAccessDefaults={type:ee,args:{modelID:{type:new m(d)},permissionType:{type:new m(w)},accessLevel:{type:new m(w)},allowedDIDs:{type:toList(w)}},resolve:async(e,t,i)=>await i.executeSetModelAccessDefaults({modelID:t.modelID,permissionType:t.permissionType,accessLevel:t.accessLevel,allowedDIDs:t.allowedDIDs??null})},this._mutations.removeModelAccessDefaults={type:a,args:{modelID:{type:new m(d)},permissionTypes:{type:new m(toList(w))}},resolve:async(e,t,i)=>(await i.executeRemoveModelAccessDefaults(t.modelID,t.permissionTypes),!0)},this._mutations.setDocumentAccessOverride={type:e.documentInterface,args:{documentID:{type:new m(d)},permissionType:{type:new m(w)},accessLevel:{type:new m(w)},allowedDIDs:{type:toList(w)}},resolve:async(e,t,i)=>await i.executeSetDocumentAccessOverride({documentID:t.documentID,permissionType:t.permissionType,accessLevel:t.accessLevel,allowedDIDs:t.allowedDIDs??null})},this._mutations.removeDocumentAccessOverride={type:a,args:{documentID:{type:new m(d)},permissionTypes:{type:new m(toList(w))}},resolve:async(e,t,i)=>(await i.executeRemoveDocumentAccessOverride(t.documentID,t.permissionTypes),!0)};let t=new _({name:"BeginTransactionPayload",fields:{transactionID:{type:new m(d)}}}),i=new _({name:"CommitTransactionPayload",fields:{success:{type:new m(a)}}}),n=new _({name:"RollbackTransactionPayload",fields:{success:{type:new m(a)}}});this._mutations.beginTransaction={type:new m(t),args:{},resolve:(e,t,i)=>i.beginTransaction()},this._mutations.commitTransaction={type:new m(i),args:{transactionID:{type:new m(d)}},resolve:async(e,t,i)=>await i.commitTransaction(t.transactionID)},this._mutations.rollbackTransaction={type:new m(n),args:{transactionID:{type:new m(d)}},resolve:(e,t,i)=>i.rollbackTransaction(t.transactionID)}}let n={query:new _({name:"Query",fields:t})};this._includeMutations&&(n.mutation=new _({name:"Mutation",fields:this._mutations})),this._includeSubscriptions&&(n.subscription=new _({name:"Subscription",fields:()=>{let t={...this._subscriptions};if(this._includeSubscriptions)for(let[i,n]of(t.documentChanged={type:new m(e.documentInterface),args:{id:{type:new m(d)}},resolve:e=>e,subscribe:(e,t,i)=>i.subscribeToDocumentChanged(t.id)},t.documentRemoved={type:new m(d),resolve:e=>e,subscribe:(e,t,i)=>i.subscribeToDocumentRemoved()},Object.entries(this._record))){if(!this._includedModelIDs.has(i))continue;let e=this._aliases[i];for(let s of(t[`new${e}Created`]={type:new m(this._types[i]),args:{owner:{type:d}},resolve:e=>e,subscribe:(e,t,n)=>n.subscribeToDocumentCreated(this.getModelIDs(i),t.owner??void 0)},n.interfaces??[])){let e=getGlobalID(s,i).toString();for(let[i,n]of Object.entries(this._relationsTo[e]??{}))for(let s of n)this._buildRelationSubscriptions(t,e,i,s)}for(let[e,n]of Object.entries(this._relationsTo[i]??{}))for(let s of n)this._includedModelIDs.has(s.model)&&this._buildRelationSubscriptions(t,i,e,s)}return t}}));let s=new b(n);if(null!=this._extensionSDL){let e=new Set(Object.keys(s.getTypeMap()));s=o(s,$(this._extensionSDL)),this._stubExtensionResolvers&&this.#e(s,e)}return null!=this._extensionResolvers&&this.#t(s,this._extensionResolvers),s}#t(e,t){let i=e.getQueryType();if(null!=i&&null!=t.queryFields){let e=i.getFields();for(let[i,n]of Object.entries(t.queryFields)){if(null==e[i])throw Error(`Extension resolver for query field "${i}" has no matching field in SDL`);e[i].resolve=n}}let n=e.getMutationType();if(null!=n&&null!=t.mutationFields){let e=n.getFields();for(let[i,n]of Object.entries(t.mutationFields)){if(null==e[i])throw Error(`Extension resolver for mutation field "${i}" has no matching field in SDL`);e[i].resolve=n}}let s=e.getSubscriptionType();if(null!=s&&null!=t.subscriptionFields){let e=s.getFields();for(let[i,n]of Object.entries(t.subscriptionFields)){if(null==e[i])throw Error(`Extension resolver for subscription field "${i}" has no matching field in SDL`);e[i].resolve=n.resolve,e[i].subscribe=n.subscribe}}if(null!=t.typeFields)for(let[i,n]of Object.entries(t.typeFields)){let t=e.getType(i);if(null==t)throw Error(`Extension resolver references type "${i}" which does not exist in the schema`);if(!O(t))throw Error(`Extension resolver references type "${i}" which is not an object type`);let s=t.getFields();for(let[e,t]of Object.entries(n)){if(null==s[e])throw Error(`Extension resolver for field "${e}" on type "${i}" has no matching field in SDL`);s[e].resolve=t}}if(null!=t.nodeResolvers)for(let[e,i]of Object.entries(t.nodeResolvers))this._pluginNodeResolvers[e]=i}#e(e,t){for(let t of[e.getQueryType(),e.getMutationType()])if(null!=t)for(let e of Object.values(t.getFields()))null==e.resolve&&(e.resolve=()=>N(e.type));for(let[i,n]of Object.entries(e.getTypeMap()))if(!t.has(i)&&O(n)){for(let e of Object.values(n.getFields()))if(null==e.resolve){let t=e.type;e.resolve=i=>i[e.name]??N(t)}}}_getDefinitions(){if(null==this._definitions)throw Error("Definitions must be initialized");return this._definitions}_getReference(e,t){let i=B(e),n=this._types[i];if(null!=n)return n;let s=this._getReferenceSchema(i);return this._buildReference(i,s,t)}_getReferenceSchema(e){let t=this._references[e];if(null==t)throw Error(`Could not find reference: ${e}`);return t}_getReferenceInput(e,t,i=""){let n=B(e),s=this._getReferenceSchema(n);if("array"===s.type)return new y(new m(this._getReferenceInput(s.items.$ref,!1,s.title)));if("object"===s.type){if(s.additionalProperties)return A;let e=t?`${n}-partial`:n,r=this._inputObjects[e];if(null!=r)return r;let o={};for(let[e,i]of Object.entries(s.properties)){let n=this._getReferenceInput(i.$ref,t,s.title);o[e]={type:t||!s.required.includes(e)?n:new m(n)}}let a=this._aliases[n]??l(i+s.title),u=new p({name:t?`Partial${a}Input`:`${a}Input`,fields:o});return this._inputObjects[e]=u,u}return this._buildScalar(n,s,i)}_buildSharedDefinitions(){let i=M(async(i,r)=>{if(i.startsWith("did:"))return i;let l=n(i);if(l instanceof e)return l;if(l instanceof t)return await r.loadDocument(i);if(l instanceof s){let e=this._pluginNodeResolvers[l.typeName];if(null==e)throw Error(`No node resolver registered for plugin type "${l.typeName}"`);let t=await e.resolve(l.localID,r);if(null==t)throw Error(`Node resolver for "${l.typeName}" returned null for localID "${l.localID}"`);return{...t,__typename:l.typeName}}throw Error(`Unsupported node ID: ${i}`)},t=>{if("string"==typeof t)return"AccountNode";if(t instanceof e)return"AttachmentNode";if(null!=t&&"object"==typeof t&&"model"in t)return this._aliases[t.model];if(null!=t&&"object"==typeof t&&"__typename"in t)return t.__typename;throw Error("Unknown node type")}),r=new _({name:"AccountNode",interfaces:[i.nodeInterface],fields:()=>{let e={id:{type:new m(d),description:"Globally unique identifier of the account (DID string)",resolve:e=>e},isViewer:{type:new m(a),description:"Whether the authenticated request issuer is this account or not",resolve:(e,t,i)=>i.getViewer()===e}};for(let[i,n]of Object.entries(this._record))if(this._includedModelIDs.has(i))switch(n.behavior){case"interface":continue;case"default":{let t=this._aliases[i];e[`own${t}Connection`]={type:this._types[`${i}-connection`],args:{...j,filter:{type:this._inputObjects[`${i}-filter`]},orderBy:{type:toList(this._inputObjects[`${i}-order`])}},resolve:async(e,t,n)=>await n.resolveConnection(this.getModelIDs(i),{...t,owner:e})};break}case"unique":{let s=this._aliases[i];e[`own${s}`]={type:this._types[i],args:n.uniqueFields.length?{with:{type:new m(this._buildSetInputObjectType(i,n.uniqueFields))}}:{},resolve:async(e,s,r)=>{let l=G(n.uniqueFields,s.with),o=t.create(i,e,l);return await r.loadDocument(o.toString())}}}}return e}}),l=new _({name:"AttachmentNode",interfaces:[i.nodeInterface],fields:{id:{type:new m(d),resolve:e=>e.toString()},contentLength:{type:new m(f)},mimeType:{type:new m(w)}}}),o={id:{type:new m(d)},model:{type:new m(w)},owner:{type:new m(r)},createdAt:{type:new m(T)},updatedAt:{type:T},accessPermissions:{type:Z,resolve:e=>e.data?.accessPermissions??null}},u=new h({name:"DocumentNode",interfaces:[i.nodeInterface],fields:o,resolveType:e=>this._aliases[e.model]}),c={node:i.nodeField,viewer:{type:r,description:"Account issuing the request, if authenticated",resolve:(e,t,i)=>i.getViewer()}};return{...i,accountObject:r,attachmentObject:l,documentInterface:u,documentNodeFields:o,queryFields:c}}_buildDocument(e){if(null!=this._types[e])return this._types[e];let t=this._record[e];if(null==t)throw Error(`Could not find model id: ${e}`);let i=this._getDefinitions();this._aliases[e]??=l(t.name);let n=this._aliases[e],s={name:n,interfaces:()=>[i.documentInterface,i.nodeInterface].concat(t.interfaces.map(t=>this._types[getGlobalID(t,e).toString()]).filter(e=>null!=e)),fields:()=>this._buildDocumentFields(e,t,n)},r="interface"===t.behavior,o=r?new h({...s,resolveType:e=>this._aliases[e.model]}):new _(s),{connectionType:a,edgeType:u}=S({nodeType:o});return this._types[e]=o,this._types[`${e}-connection`]=a,this._types[`${e}-edge`]=u,this._buildDocumentDataObject(e,t,n),this._buildDocumentInput(e,t),this._buildObjectFilterInput(e,t.schema,n,!0),this._buildObjectOrderByInput(e,t.schema,n,!0),!r&&this._includeMutations&&("default"===t.behavior?this._mutations[`create${n}`]=F({name:`Create${n}`,inputFields:()=>({data:{type:new m(this._inputObjects[e])},transactionID:{type:d}}),outputFields:()=>({...i.queryFields,document:{type:this._types[e]}}),mutateAndGetPayload:async(t,i,n)=>({document:await i.executeCreateMutation({modelID:e,data:t.data,info:n,transactionID:t.transactionID})})}):"unique"===t.behavior&&(this._mutations[`set${n}`]=F({name:`Set${n}`,inputFields:()=>({data:{type:new m(this._inputObjects[e])},transactionID:{type:d}}),outputFields:()=>({...i.queryFields,document:{type:this._types[e]}}),mutateAndGetPayload:async(i,n,s)=>{let r=G(t.uniqueFields,i.data);return{document:await n.executeSetMutation({modelID:e,unique:r,data:i.data,info:s,transactionID:i.transactionID})}}})),this._mutations[`update${n}`]=F({name:`Update${n}`,inputFields:()=>({id:{type:new m(d)},patch:{type:new m(toList(PatchOperation))},from:{type:this._inputObjects[`${e}-update`]},transactionID:{type:d}}),outputFields:()=>({...i.queryFields,document:{type:this._types[e]}}),mutateAndGetPayload:async(e,t,i)=>({document:await t.executeUpdateMutation({input:e,info:i,transactionID:e.transactionID})})}),this._mutations[`remove${n}`]=F({name:`Remove${n}`,inputFields:()=>({id:{type:new m(d)},transactionID:{type:d}}),outputFields:()=>({...i.queryFields,id:{type:new m(d)}}),mutateAndGetPayload:async(e,t,i)=>(await t.executeRemoveMutation({id:e.id,info:i,transactionID:e.transactionID}),{id:e.id})})),o}_buildDocumentFields(t,i,n){let s=this._buildDocumentDataObject(t,i,n),r=this._getDefinitions(),l={...r.documentNodeFields,data:{type:new m(s)}};for(let[n,o]of Object.entries(s.getFields())){let s=i.fieldsMeta[n];if(null!=s)switch(s.type){case"account":Q(o.type)?l[`${n}Accounts`]={type:new m(toOuputList(r.accountObject)),resolve:e=>e.data?.[n]??[]}:l[`${n}Account`]={type:r.accountObject,resolve:e=>e.data?.[n]??null};break;case"attachment":Q(o.type)?l[`${n}Attachments`]={type:new m(toOuputList(r.attachmentObject)),resolve:t=>(t.data?.[n]??[]).map(e.fromString)}:l[`${n}Attachment`]={type:r.attachmentObject,resolve:t=>{let i=t.data?.[n];return i?e.fromString(i):null}};break;case"document":{let e,i,a=s.model;if(void 0===a)continue;null===a?(e=null,i=r.documentInterface):(e=getGlobalID(a,t).toString(),this._includedModelIDs.has(e)?i=this._buildDocument(e):(i=r.documentInterface,e=null)),Q(o.type)?l[`${n}Documents`]={type:new m(toOuputList(i)),resolve:async(t,i,s)=>{let r=t.data?.[n]??[];return r.length?await s.resolveList(this.getModelIDs(e),r):[]}}:l[`${n}Document`]={type:i,resolve:async(e,t,i)=>{let s=e.data?.[n];return s?await i.loadDocument(s):null}}}}}for(let e of i.interfaces??[]){let i=getGlobalID(e,t).toString();for(let[e,t]of Object.entries(this._relationsTo[i]??{}))for(let i of t)this._includedModelIDs.has(i.model)&&this._buildRelationFields(l,e,i)}for(let[e,i]of Object.entries(this._relationsTo[t]??{}))for(let t of i)this._includedModelIDs.has(t.model)&&this._buildRelationFields(l,e,t);return l}_buildDocumentDataObject(e,t,i){let n=`${e}-data`;if(null!=this._types[n])return this._types[n];let s=t.schema.required??[],r={};for(let[i,n]of Object.entries(t.schema.properties??{})){let t=n.$ref;if(null==t)throw Error(`Missing ref for field ${i} of object ${e}`);let l=this._getReference(t);r[i]={type:s.includes(i)?new m(l):l}}let l={name:`${i}Data`,interfaces:()=>t.interfaces.map(t=>{let i=`${getGlobalID(t,e).toString()}-data`;return this._types[i]}).filter(e=>null!=e),fields:r},o="interface"===t.behavior?new h(l):new _(l);return this._types[n]=o,o}_buildDocumentInput(e,t){if("interface"===t.behavior)return;let i={},n={};for(let[e,s]of Object.entries(t.schema.properties)){let r=s.$ref,l=this._getReferenceInput(r,!1);i[e]={type:t.schema.required.includes(e)?new m(l):l};let o=B(r);null==this._getReferenceSchema(o).const&&(n[e]={type:this._getReferenceInput(r,!0)})}let s=this._aliases[e];this._inputObjects[e]=new p({name:`${s}Input`,fields:i}),this._inputObjects[`${e}-update`]=new p({name:`Partial${s}Input`,fields:n})}_buildReferenceFilterInput(e,t=""){let i=B(e),n=this._getReferenceSchema(i),s=t;if("object"===n.type)return n.additionalProperties?null:this._buildObjectFilterInput(i,n,t);if("array"===n.type){let e=this._aliases[i]??l(t+n.title);return s=e,new p({name:`${e}Filter`,isOneOf:!0,fields:{isNull:{type:a}}})}let r=this._buildScalar(i,n,s),o=z[r.name];if(null!=o)return this._inputObjects[o];let u=D(r)?new p({name:`${r.name}ValueFilter`,isOneOf:!0,fields:{isNull:{type:a},equalTo:{type:r},notEqualTo:{type:r},in:{type:toList(r)},notIn:{type:toList(r)}}}):U(r);return null==this._inputObjects[u.name]&&(this._inputObjects[u.name]=u),this._inputObjects[u.name]}_buildReferenceOrderByInput(e,t=""){let i=B(e),n=this._getReferenceSchema(i);switch(n.type){case"array":return null;case"object":return n.additionalProperties?null:this._buildObjectOrderByInput(i,n,t);default:return X}}_buildObjectFilterInput(e,t,i="",n=!1){let s=`${e}-filter`,r=this._inputObjects[s];if(null!=r)return r;let o=this._aliases[e]??l(i+(t.title??"")),a=n?{_owner:{type:this._inputObjects.AccountValueFilter}}:{};for(let[e,i]of Object.entries(t.properties)){let t=this._buildReferenceFilterInput(i.$ref,o);null!==t&&(a[e]={type:t})}let u=new p({name:`${o}ObjectFilter`,fields:a}),c=new p({name:`${o}Filter`,isOneOf:!0,fields:()=>({where:{type:u},and:{type:toList(this._inputObjects[s])},or:{type:toList(this._inputObjects[s])},not:{type:this._inputObjects[s]}})});return this._inputObjects[s]=c,c}_buildObjectOrderByInput(e,t,i="",n=!1){let s=`${e}-order`,r=this._inputObjects[s];if(null!=r)return r;let o=this._aliases[e]??l(i+(t.title??"")),a=n?{_docOwner:{type:X},_createdAt:{type:X}}:{};for(let[e,i]of Object.entries(t.properties)){let t=this._buildReferenceOrderByInput(i.$ref,o);null!=t&&(a[e]={type:t})}let u=new p({name:`${o}OrderBy`,isOneOf:!0,fields:a});return this._inputObjects[s]=u,u}_buildSetInputObjectType(e,t,i){let n=i?l(i):"",s=`${e}-with-${n}`,r=this._inputObjects[s];if(null!=r)return r;let o=this._record[e],a=this._aliases[e];return this._inputObjects[s]=new p({name:`With${n}${a}Input`,fields:()=>{let e={};for(let i of t){let t=o.schema.properties[i];if(null==t)throw Error(`Field ${i} not found on model ${a}`);let n=this._getReferenceInput(t.$ref,!1);e[i]={type:new m(n)}}return e}}),this._inputObjects[s]}_buildReference(e,t,i=""){if(null!=this._types[e])return this._types[e];switch(t.type){case"array":return this._types[e]=this._buildArray(t,i),this._types[e];case"object":return this._types[e]=t.additionalProperties?A:this._buildObject(e,t,i),this._types[e];default:return this._buildScalar(e,t,i)}}_buildScalar(e,t,i=""){if(null!=this._types[e])return this._types[e];switch(t.type){case"boolean":this._types[e]=a;break;case"integer":this._types[e]=f;break;case"number":this._types[e]=c;break;case"string":this._types[e]=this._buildString(t,i)}return this._types[e]}_buildArray(e,t=""){let i=e.items.$ref;return new y(new m(this._getReference(i,l(t+e.title))))}_buildObject(e,t,i=""){let n=l(i+t.title),s=this._buildObjectFields(e,t,n);return new _({name:n,fields:s})}_buildObjectFields(e,t,i=""){let n=t.required??[],s={};for(let[r,l]of Object.entries(t.properties??{})){let t=l.$ref;if(null==t)throw Error(`Missing ref for field ${r} of object ${e}`);let o=this._getReference(t,i);s[r]={type:n.includes(r)?new m(o):o}}return s}_buildRelationFields(e,t,i){if(i.isList)return;let n=i.model,s=`${l(t)}Of${this._aliases[n]}`;e[`in${s}`]={type:new m(this._types[`${n}-connection`]),args:{...j,filter:{type:this._inputObjects[`${n}-filter`]},orderBy:{type:toList(this._inputObjects[`${n}-order`])}},resolve:(e,i,s)=>{let r={where:{[t]:{equalTo:e.id}}},l=i.filter?{and:[i.filter,r]}:r;return s.resolveConnection(this.getModelIDs(n),{...i,filter:l})}},e[`in${s}Count`]={type:new m(f),args:{filter:{type:this._inputObjects[`${n}-filter`]}},resolve:(e,i,s)=>{let r={where:{[t]:{equalTo:e.id}}},l=i.filter?{and:[i.filter,r]}:r;return s.resolveCount(this.getModelIDs(n),l)}}}_buildRelationSubscriptions(e,t,i,n){if(n.isList)return;let s=l(i);e[`edge${this._aliases[n.model]}AddedAs${s}To${this._aliases[t]}`]={type:new m(this._types[`${n.model}-edge`]),args:{id:{type:new m(d)}},resolve:e=>e,subscribe:(e,t,s)=>s.subscribeToDocumentEdgeAdded(this.getModelIDs(n.model),e=>e[i]===t.id)},e[`edge${this._aliases[n.model]}RemovedAs${s}From${this._aliases[t]}`]={type:new m(d),args:{id:{type:new m(d)}},resolve:e=>e,subscribe:(e,t,s)=>s.subscribeToDocumentEdgeRemoved(this.getModelIDs(n.model),e=>e[i]===t.id)}}_buildString(e,t){return null!=e.const?w:null!=e.enum?this._buildEnumString(e,t):null!=e.format?this._buildFormatString(e):this._buildCustomString(e)}_buildCustomString(e){return null==e.title?w:k[e.title.toLowerCase()]??w}_buildEnumString(e,t=""){let i=l(t+e.title),n=`${i}-enum`;if(null==this._types[n]){let t={};for(let i of e.enum)t[i]={value:i};this._types[n]=new u({name:i,values:t})}return this._types[n]}_buildFormatString(e){let t=V[e.format];if(null==t)throw Error(`Unsupported string format: ${e.format}`);return t}}export function createSchema(e){return new SchemaBuilder(e).build()}
package/lib/types.d.ts CHANGED
@@ -39,7 +39,7 @@ export type UpdateMutationInput = {
39
39
  /** Model-level access control defaults configuration */
40
40
  export type ModelAccessDefaults = {
41
41
  ownerDID: string;
42
- modelId: string;
42
+ modelID: string;
43
43
  permissions: {
44
44
  read?: {
45
45
  level: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubun/graphql",
3
- "version": "0.7.1",
3
+ "version": "0.8.1",
4
4
  "license": "see LICENSE.md",
5
5
  "keywords": [],
6
6
  "type": "module",
@@ -17,20 +17,22 @@
17
17
  "dependencies": {
18
18
  "@enkaku/async": "^0.14.0",
19
19
  "@enkaku/codec": "^0.14.0",
20
+ "@enkaku/event": "^0.14.1",
20
21
  "@enkaku/otel": "^0.14.0",
21
22
  "change-case": "^5.4.4",
22
- "graphql": "^16.13.1",
23
+ "graphql": "^16.13.2",
23
24
  "graphql-relay": "^0.10.2",
24
25
  "graphql-scalars": "^1.25.0",
25
26
  "multiformats": "^13.4.2",
26
- "@kubun/protocol": "^0.7.1",
27
- "@kubun/id": "^0.7.0"
27
+ "@kubun/hlc": "^0.8.0",
28
+ "@kubun/id": "^0.8.0",
29
+ "@kubun/protocol": "^0.8.0"
28
30
  },
29
31
  "devDependencies": {
30
32
  "@enkaku/capability": "^0.14.0",
31
- "@enkaku/token": "0.14.0",
32
- "@kubun/db": "^0.7.0",
33
- "@kubun/test-utils": "^0.7.0"
33
+ "@enkaku/token": "0.14.1",
34
+ "@kubun/test-utils": "^0.8.0",
35
+ "@kubun/db-better-sqlite": "^0.8.1"
34
36
  },
35
37
  "scripts": {
36
38
  "build:clean": "del lib",
@@ -38,7 +40,7 @@
38
40
  "build:types": "tsc --emitDeclarationOnly --skipLibCheck",
39
41
  "build:types:ci": "tsc --emitDeclarationOnly --declarationMap false",
40
42
  "build": "pnpm run build:clean && pnpm run build:js && pnpm run build:types",
41
- "test:types": "tsc --noEmit",
43
+ "test:types": "tsc --noEmit -p tsconfig.test.json",
42
44
  "test:unit": "vitest run",
43
45
  "test": "pnpm run test:types && pnpm run test:unit"
44
46
  }