@kubun/graphql 0.8.2 → 0.10.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/context.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { Tracer } from '@enkaku/otel';
2
2
  import { DocumentID } from '@kubun/id';
3
- import type { DocumentData, DocumentFilter, DocumentNode, DocumentOrderBy } from '@kubun/protocol';
3
+ import type { AggregateHaving, AggregateSpec, AggregateValues, DocumentData, DocumentFilter, DocumentNode, DocumentOrderBy, GroupedAggregateOrderTerm, GroupedAggregateValue } from '@kubun/protocol';
4
+ import type { ViewerReadAccess } from '@kubun/store-graph';
4
5
  import type { GraphQLResolveInfo } from 'graphql';
5
6
  import type { Connection, Edge } from 'graphql-relay';
6
7
  import type { AllConnectionArguments, ModelAccessDefaults, UpdateMutationInput } from './types.js';
@@ -49,11 +50,30 @@ export type ReadContextDB = {
49
50
  modelIDs: Array<string>;
50
51
  docIDs: Array<string>;
51
52
  }): Promise<Array<DocumentNode>>;
52
- countDocuments(params: {
53
+ aggregateDocuments(params: {
53
54
  modelIDs: Array<string>;
54
55
  filter?: DocumentFilter;
56
+ owner?: string;
57
+ catalogID?: string;
58
+ count: boolean;
59
+ aggregates: Array<AggregateSpec>;
60
+ readAccess?: ViewerReadAccess;
61
+ }): Promise<AggregateValues>;
62
+ groupedAggregateDocuments(params: {
63
+ modelIDs: Array<string>;
64
+ filter?: DocumentFilter;
65
+ owner?: string;
55
66
  catalogID?: string;
56
- }): Promise<number>;
67
+ count: boolean;
68
+ aggregates: Array<AggregateSpec>;
69
+ groupBy: Array<{
70
+ keys: Array<string>;
71
+ }>;
72
+ having?: AggregateHaving;
73
+ orderBy?: Array<GroupedAggregateOrderTerm>;
74
+ limit?: number;
75
+ readAccess?: ViewerReadAccess;
76
+ }): Promise<Array<GroupedAggregateValue>>;
57
77
  searchDocuments(params: {
58
78
  query: string;
59
79
  modelIDs: Array<string>;
@@ -64,15 +84,65 @@ export type ReadContextDB = {
64
84
  rank: number;
65
85
  }>>;
66
86
  };
87
+ /**
88
+ * Query scope carried alongside a connection value so child resolvers (e.g.
89
+ * `aggregates`) can re-run against the exact same set of documents the page was
90
+ * built from. Shaped to feed the store aggregate query directly.
91
+ */
92
+ export type AggregateScope = {
93
+ modelIDs: Array<string>;
94
+ filter?: DocumentFilter;
95
+ owner?: string;
96
+ catalogID?: string;
97
+ };
98
+ /**
99
+ * Connection value returned by {@link QueryContext.resolveConnection}. Extends
100
+ * the graphql-relay connection (edges/pageInfo are untouched) with the query
101
+ * scope so the `aggregates` field can resolve consistently with the page.
102
+ */
103
+ export type ScopedConnection = Connection<DocumentNode> & {
104
+ aggregateScope: AggregateScope;
105
+ };
106
+ /**
107
+ * Aggregate request shaped by the connection's `aggregates` look-ahead: which
108
+ * ops over which fields were selected, plus whether a count was requested.
109
+ */
110
+ export type ResolveAggregateParams = {
111
+ filter?: DocumentFilter;
112
+ owner?: string;
113
+ catalogID?: string;
114
+ count: boolean;
115
+ aggregates: Array<AggregateSpec>;
116
+ };
117
+ /**
118
+ * Grouped-aggregate request shaped by the connection's `groupedAggregates`
119
+ * look-ahead and field arguments: the aggregate ops/fields and count selected,
120
+ * plus the `groupBy` buckets, optional `having` predicate, group `orderBy` terms
121
+ * and `limit` translated from the field arguments.
122
+ */
123
+ export type ResolveGroupedAggregateParams = {
124
+ filter?: DocumentFilter;
125
+ owner?: string;
126
+ catalogID?: string;
127
+ count: boolean;
128
+ aggregates: Array<AggregateSpec>;
129
+ groupBy: Array<{
130
+ keys: Array<string>;
131
+ }>;
132
+ having?: AggregateHaving;
133
+ orderBy?: Array<GroupedAggregateOrderTerm>;
134
+ limit?: number;
135
+ };
67
136
  /**
68
137
  * Query functions requiring server implementation
69
138
  */
70
139
  export type QueryContext = {
71
140
  getViewer(): string | null;
72
141
  loadDocument(id: string): Promise<DocumentNode | null>;
73
- resolveConnection(modelIDs: Array<string>, args: AllConnectionArguments): Promise<Connection<DocumentNode>>;
142
+ resolveConnection(modelIDs: Array<string>, args: AllConnectionArguments): Promise<ScopedConnection>;
74
143
  resolveList(modelIDs: Array<string>, ids: Array<string>): Promise<Array<DocumentNode>>;
75
- resolveCount(modelIDs: Array<string>, filter?: DocumentFilter): Promise<number>;
144
+ resolveAggregate(modelIDs: Array<string>, params: ResolveAggregateParams): Promise<AggregateValues>;
145
+ resolveGroupedAggregate(modelIDs: Array<string>, params: ResolveGroupedAggregateParams): Promise<Array<GroupedAggregateValue>>;
76
146
  searchDocuments(query: string, modelIDs: Array<string>, first?: number): Promise<Array<{
77
147
  documentID: string;
78
148
  modelID: string;
@@ -111,6 +181,7 @@ export type ReadContextParams = {
111
181
  viewerDID: string;
112
182
  catalogID?: string;
113
183
  accessChecker?: AccessChecker;
184
+ viewerReadAccess?: ViewerReadAccess;
114
185
  warnings?: Array<AccessWarning>;
115
186
  complexity?: ComplexityStats;
116
187
  tracer?: Tracer;
@@ -144,12 +215,16 @@ export type SetModelAccessDefaultsParams = {
144
215
  permissionType: 'read' | 'write';
145
216
  accessLevel: string;
146
217
  allowedDIDs: Array<string> | null;
218
+ allowedCircles: Array<string> | null;
219
+ allowedGroups: Array<string> | null;
147
220
  };
148
221
  export type SetDocumentAccessOverrideParams = {
149
222
  documentID: string;
150
223
  permissionType: 'read' | 'write';
151
224
  accessLevel: string;
152
225
  allowedDIDs: Array<string> | null;
226
+ allowedCircles: Array<string> | null;
227
+ allowedGroups: Array<string> | null;
153
228
  };
154
229
  /**
155
230
  * Mutation function requiring client implementation
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{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)}}
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 r,KubunSpanNames as n}from"@kubun/protocol";export function createReadContext(l){let{store:a,viewerDID:i,accessChecker:s,viewerReadAccess:u}=l;function c(e,o,r){return null!=l.tracer?t(l.tracer,e,{attributes:o},async()=>r()):r()}function m(t,o){let r=!1,n=null,a=[];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==n?a.push(t):(n.resolve(t),n=null)}}),s=()=>(i(),r=!0,Promise.resolve({done:!0,value:void 0}));return{[Symbol.asyncDispose]:()=>(i(),r=!0,Promise.resolve()),[Symbol.asyncIterator](){return this},next:()=>{if(r)return Promise.resolve({done:!0,value:void 0});let t=a.shift();return null!=t?Promise.resolve({value:t,done:!1}):(n=e()).promise.then(e=>({value:e,done:!1}))},return:s,throw:s}}return{getViewer:()=>i,async loadDocument(e){let t=`document:${e}`,i=l.complexity?.resolverTimings!=null?performance.now():0,u=await c(n.DATA_QUERY,{[r.DOCUMENT_ID]:e},async()=>{let t=await a.getDocument(o.fromString(e));return t?s&&!await s(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 u},searchDocuments:async(e,t,o)=>await a.searchDocuments({query:e,modelIDs:t,first:o}),async resolveConnection(e,t){let o=`connection:${e.join(",")}`,i=l.complexity?.resolverTimings!=null?performance.now():0,u={modelIDs:e,filter:t.filter,owner:t.owner,catalogID:l.catalogID},m=await c(n.DATA_QUERY,{[r.MODEL_ID]:e.join(",")},async()=>{if(null!=t.search&&""!==t.search.trim()){let o=await a.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 r=o.map(e=>e.documentID),n=await a.listDocuments({modelIDs:e,docIDs:r}),i=n;if(s)for(let e of(i=[],n))await s(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==s){let{entries:o,hasMore:r}=await a.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&&r,hasPreviousPage:!t.first&&r,endCursor:o.at(-1)?.cursor??null,startCursor:o.at(0)?.cursor??null}}}let o=[],r=0,n=0;if(null==t.first&&null==t.last){let{entries:n}=await a.queryDocuments({...t,modelIDs:e,catalogID:l.catalogID});for(let e of n)await s(e.document,"read")?o.push(e):null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e.document.id}`,code:"KB07"});r=o.length}else if(null!=t.first){let i=2*(r=t.first),u=t.after;for(;o.length<r&&n<10;){let{entries:c,hasMore:m}=await a.queryDocuments({...t,modelIDs:e,catalogID:l.catalogID,first:i,after:u});if(0===c.length&&!m)break;for(let e of c)if(await s(e.document,"read")){if(o.push(e),o.length>=r)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,n++}}else if(null!=t.last){let i=2*(r=t.last),u=t.before;for(;o.length<r&&n<10;){let{entries:c,hasMore:m}=await a.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 s(e.document,"read")){if(o.unshift(e),o.length>=r)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,n++}}let i=o.slice(0,r),u=o.length>r;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{...m,aggregateScope:u}},async resolveList(e,t){let o=`list:${e.join(",")}`,i=l.complexity?.resolverTimings!=null?performance.now():0,u=await c(n.DATA_QUERY,{[r.MODEL_ID]:e.join(",")},async()=>{let o=await a.listDocuments({modelIDs:e,docIDs:t});if(!s){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 r=[];for(let e of o)await s(e,"read")?r.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+=r.length}return r});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},async resolveAggregate(e,t){let o=`aggregate:${e.join(",")}`,i=l.complexity?.resolverTimings!=null?performance.now():0,s=await c(n.DATA_QUERY,{[r.MODEL_ID]:e.join(",")},async()=>(null!=l.complexity&&l.complexity.resolverCount++,await a.aggregateDocuments({modelIDs:e,filter:t.filter,owner:t.owner,catalogID:t.catalogID??l.catalogID,count:t.count,aggregates:t.aggregates,readAccess:u})));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 s},async resolveGroupedAggregate(e,t){let o=`grouped-aggregate:${e.join(",")}`,i=l.complexity?.resolverTimings!=null?performance.now():0,s=await c(n.DATA_QUERY,{[r.MODEL_ID]:e.join(",")},async()=>(null!=l.complexity&&l.complexity.resolverCount++,await a.groupedAggregateDocuments({modelIDs:e,filter:t.filter,owner:t.owner,catalogID:t.catalogID??l.catalogID,count:t.count,aggregates:t.aggregates,groupBy:t.groupBy,having:t.having,orderBy:t.orderBy,limit:t.limit,readAccess:u})));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 s},subscribeToDocumentCreated(e,t){let o=m(o=>"create"===o.type&&e.includes(o.document.model)&&(null==t||o.document.owner===t),e=>e.document);return s?async function*(){for await(let e of o)await s(e,"read")&&(yield e)}():o},subscribeToDocumentChanged(e){let t=m(t=>"update"===t.type&&t.document.id===e&&null!==t.document.data,e=>e.document);return s?async function*(){for await(let e of t)await s(e,"read")&&(yield e)}():t},subscribeToDocumentRemoved:()=>m(e=>"update"===e.type&&null===e.document.data,e=>e.document.id),subscribeToDocumentEdgeAdded(e,t){let o=m(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 s?async function*(){for await(let e of o)await s(e.node,"read")&&(yield e)}():o},subscribeToDocumentEdgeRemoved:(e,t)=>m(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,4 +1,4 @@
1
- export type { AccessWarning, ComplexityStats, Context, CreateMutationParams, DocumentEventEmitter, DocumentSavedEvent, MutationContext, PluginContextMap, QueryContext, ReadContextDB, ReadContextParams, ReadOnlyContext, RemoveMutationParams, SetDocumentAccessOverrideParams, SetModelAccessDefaultsParams, SetMutationParams, SubscriptionContext, UpdateMutationParams, } from './context.js';
1
+ export type { AccessWarning, AggregateScope, ComplexityStats, Context, CreateMutationParams, DocumentEventEmitter, DocumentSavedEvent, MutationContext, PluginContextMap, QueryContext, ReadContextDB, ReadContextParams, ReadOnlyContext, RemoveMutationParams, ScopedConnection, SetDocumentAccessOverrideParams, SetModelAccessDefaultsParams, SetMutationParams, SubscriptionContext, UpdateMutationParams, } from './context.js';
2
2
  export { createReadContext } from './context.js';
3
3
  export { GraphQLAttachmentID, GraphQLDocID } from './identifiers.js';
4
4
  export type { ExtensionResolvers, SchemaBuilderParams, SharedDefinitions, } from './schema.js';
package/lib/schema.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AttachmentID, DocumentModelID } from '@kubun/id';
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, type GraphQLFieldResolver, GraphQLInputObjectType, type GraphQLInputType, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, type GraphQLOutputType, type GraphQLScalarType, GraphQLSchema } from 'graphql';
2
+ import type { AggregateHaving, AggregateSpec, ArrayModel, DocumentData, DocumentModel, DocumentModelSchema, DocumentModelsRecord, DocumentNode, GroupedAggregateOrderTerm, ObjectModel, OrderByDirection as OrderByDirectionValue, ReferencesRecordModel, ScalarModel, StringCustomModel, StringEnumModel, StringFormatModel, StringModel, TypeModel } from '@kubun/protocol';
3
+ import { type FieldNode, GraphQLEnumType, type GraphQLFieldConfig, type GraphQLFieldConfigMap, type GraphQLFieldResolver, GraphQLInputObjectType, type GraphQLInputType, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, type GraphQLOutputType, type GraphQLResolveInfo, type GraphQLScalarType, GraphQLSchema, type SelectionNode } 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;
@@ -48,10 +48,36 @@ export type SchemaBuilderParams = {
48
48
  extensionResolvers?: ExtensionResolvers;
49
49
  stubExtensionResolvers?: boolean;
50
50
  };
51
+ /**
52
+ * One `GroupOrderBy` argument entry. Each present leaf names a finalised-group
53
+ * value to order by, with its direction. The same shape covers the keys and each
54
+ * aggregate op; only the leaves the caller selected are present.
55
+ */
56
+ export type GroupOrderBy = {
57
+ keys?: Record<string, OrderByDirectionValue>;
58
+ count?: OrderByDirectionValue;
59
+ sum?: Record<string, OrderByDirectionValue>;
60
+ average?: Record<string, OrderByDirectionValue>;
61
+ min?: Record<string, OrderByDirectionValue>;
62
+ max?: Record<string, OrderByDirectionValue>;
63
+ };
64
+ /**
65
+ * Resolved arguments of the `groupedAggregates` connection field. `groupBy` is a
66
+ * list of groupable field-key enum values; `having` mirrors {@link AggregateHaving}
67
+ * exactly (the value-filter operator names match), so it passes through untouched.
68
+ */
69
+ export type GroupedAggregateArguments = {
70
+ groupBy?: Array<string>;
71
+ having?: AggregateHaving;
72
+ orderBy?: Array<GroupOrderBy>;
73
+ limit?: number | null;
74
+ };
51
75
  export declare class SchemaBuilder {
52
76
  #private;
53
77
  _aliases: Record<string, string>;
54
78
  _aliasToModelID: Record<string, string>;
79
+ _aggregateNumericByModel: Record<string, Map<string, boolean>>;
80
+ _groupKeyNumericByModel: Record<string, Map<string, boolean>>;
55
81
  _definitions: SharedDefinitions | undefined;
56
82
  _implemented: Record<string, Array<string>>;
57
83
  _includedModelIDs: Set<string>;
@@ -85,6 +111,76 @@ export declare class SchemaBuilder {
85
111
  _getReferenceInput(path: string, isPartial: boolean, parentName?: string): GraphQLInputType;
86
112
  _buildSharedDefinitions(): SharedDefinitions;
87
113
  _buildDocument(id: string): GraphQLObjectType<DocumentNode, Context> | GraphQLInterfaceType;
114
+ /**
115
+ * Build the `<Model>Aggregate` type attached to the connection, exposing `count`
116
+ * plus per-field `sum`/`average`/`min`/`max` selections gated by field type.
117
+ *
118
+ * Eligibility follows what SQL can faithfully compute over JSON-extracted values:
119
+ * - sum/average: numeric fields only (integer, number).
120
+ * - min/max: numeric fields plus string/date fields (lexical for strings).
121
+ * Field-selection subtypes are only emitted when at least one field qualifies,
122
+ * since an object type with no fields is invalid GraphQL. `count` is always present.
123
+ */
124
+ _buildAggregate(id: string, model: DocumentModel, name: string): GraphQLObjectType;
125
+ /**
126
+ * Build the grouped-aggregate type surface for a model, reusing the v1
127
+ * `<Model>SumFields` / `AvgFields` / `MinMaxFields` types from
128
+ * `_buildAggregate` and the existing value-filter / `OrderByDirection` inputs.
129
+ *
130
+ * Groupable fields are every property resolving to a scalar (object/array fields
131
+ * excluded), which is broader than aggregate eligibility: boolean and enum fields
132
+ * can be grouped on but never summed. The sum/average and min/max sub-shapes are
133
+ * only emitted when the model actually has those eligible fields, matching the
134
+ * conditionals in `_buildAggregate`, since an object type with no fields is invalid.
135
+ *
136
+ * Produces, registered in `_types` / `_inputObjects`:
137
+ * `<Model>GroupBy` enum, `<Model>GroupKeys`, `<Model>GroupedAggregate`,
138
+ * `<Model>Having` (+ `HavingSum`/`HavingAverage`/`HavingMin`/`HavingMax`),
139
+ * `<Model>GroupOrderBy` (+ `GroupKeysOrderBy` and per-op `<Op>FieldsOrderBy`).
140
+ */
141
+ _buildGroupedAggregate(id: string, model: DocumentModel, name: string): GraphQLObjectType | null;
142
+ /**
143
+ * Inspect the selection set under the `aggregates` field to determine exactly
144
+ * which aggregation work to ask the store for: whether a count was selected,
145
+ * and for each of sum/average/min/max, which field subselections were
146
+ * requested. Field aggregates not selected are never computed, so a
147
+ * `{ count }`-only query issues `aggregates: []`.
148
+ *
149
+ * Reads the resolved field nodes via `info.fieldNodes`. Selections reached
150
+ * through fragment spreads and inline fragments are expanded transparently, so
151
+ * `aggregates { ...AggFields }`, `aggregates { ... { count } }` and
152
+ * `sum { ...SumFields }` all request the same work as their inlined forms.
153
+ */
154
+ _buildAggregateRequest(id: string, info: GraphQLResolveInfo): {
155
+ count: boolean;
156
+ aggregates: Array<AggregateSpec>;
157
+ };
158
+ /**
159
+ * Inspect the selection set under the `groupedAggregates` field to determine the
160
+ * aggregation work to ask the store for. The aggregate ops (`count`/`sum`/
161
+ * `average`/`min`/`max`) are nested directly under the field alongside `keys`,
162
+ * which is skipped here since it is shaped by the `groupBy` argument, not the
163
+ * selection. Fragment spreads and inline fragments are expanded transparently.
164
+ * Selecting only `keys` and `count` yields `aggregates: []`.
165
+ */
166
+ _buildGroupedAggregateRequest(id: string, info: GraphQLResolveInfo): {
167
+ count: boolean;
168
+ aggregates: Array<AggregateSpec>;
169
+ };
170
+ /**
171
+ * Translate the `orderBy` argument entries into store ordering terms over each
172
+ * finalised group. Each entry's present leaves become a term whose `path`
173
+ * navigates the group object (`['count']`, `['keys', field]`, `['sum', field]`,
174
+ * etc.) and whose `numeric` flag drives arithmetic comparison. List order is
175
+ * preserved so earlier terms take precedence and later terms break ties.
176
+ */
177
+ _buildGroupOrderBy(id: string, orderBy: Array<GroupOrderBy> | undefined): Array<GroupedAggregateOrderTerm>;
178
+ /**
179
+ * Walk a selection set and yield the underlying field nodes, expanding
180
+ * fragment spreads and inline fragments in place. The `visited` set tracks
181
+ * named fragments already entered so cyclic fragment references terminate.
182
+ */
183
+ _expandFieldSelections(selections: ReadonlyArray<SelectionNode>, info: GraphQLResolveInfo, visited: Set<string>): Generator<FieldNode>;
88
184
  _buildDocumentFields(id: string, model: DocumentModel, name: string): GraphQLFieldConfigMap<DocumentNode, Context>;
89
185
  _buildDocumentDataObject(id: string, model: DocumentModel, name: string): GraphQLInterfaceType | GraphQLObjectType<DocumentData, Context>;
90
186
  _buildDocumentInput(id: string, model: DocumentModel): void;
package/lib/schema.js CHANGED
@@ -1 +1 @@
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()}
1
+ import{AttachmentID as e,DocumentID as t,DocumentModelID as i,decodeID as n,PluginNodeID as s}from"@kubun/id";import{REFERENCE_PREFIX as l}from"@kubun/protocol";import{pascalCase as r}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 g,GraphQLString as b,isEnumType as w,isListType as v,isNonNullType as D,isObjectType as O,isScalarType as I,Kind as $,parse as j}from"graphql";import{connectionArgs as S,connectionDefinitions as F,mutationWithClientMutationId as M,nodeDefinitions as R}from"graphql-relay";import{GraphQLDateTimeISO as T,GraphQLDID as x,GraphQLDuration as A,GraphQLEmailAddress as L,GraphQLJSON as E,GraphQLJSONObject as k}from"graphql-scalars";import{GraphQLAttachmentID as q,GraphQLDocID as B}from"./identifiers.js";import{GraphQLURL as G}from"./scalars.js";import{getUniqueDocValue as N,validateAccessIdentifiers as P}from"./utils.js";function C(e){if(D(e))return C(e.ofType);if(v(e))return[];if(I(e))switch(e.name){case"String":case"ID":return"";case"Int":case"Float":return 0;case"Boolean":return!1;default:return null}if(w(e)){let t=e.getValues();return t[0]?.value??null}return{}}let V={date:b,time:b,"date-time":b,duration:A,email:L,uri:G},Q={attachmentid:q,did:x,docid:B};function H(e){return e.slice(l.length)}function K(e){return v(e)||D(e)&&v(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 z={AccountValueFilter:new p({name:"AccountValueFilter",isOneOf:!0,fields:{equalTo:{type:x},notEqualTo:{type:x},in:{type:toList(x)},notIn:{type:toList(x)}}}),BooleanValueFilter:new p({name:"BooleanValueFilter",isOneOf:!0,fields:{isNull:{type:a},equalTo:{type:a}}}),FloatValueFilter:U(c),IntValueFilter:U(f),StringValueFilter:U(b)},W={GraphQLBoolean:"BooleanValueFilter",GraphQLDID:"AccountValueFilter",GraphQLFloat:"FloatValueFilter",GraphQLInt:"IntValueFilter",GraphQLString:"StringValueFilter"},J=new p({name:"PatchSetOperation",fields:{path:{type:new m(b)},value:{type:E}}}),X=new p({name:"PatchRemoveOperation",fields:{path:{type:new m(b)}}}),Y=new p({name:"PatchDestinationOperation",fields:{from:{type:new m(b)},path:{type:new m(b)}}});export const PatchOperation=new p({name:"PatchOperation",isOneOf:!0,fields:{add:{type:J},set:{type:J},remove:{type:X},replace:{type:J},copy:{type:Y},move:{type:Y}}});let Z=new u({name:"OrderByDirection",values:{ASC:{value:"asc"},DESC:{value:"desc"}}}),ee=new _({name:"AccessRule",fields:{level:{type:new m(b)},allowedDIDs:{type:new y(new m(b))},allowedCircles:{type:new y(new m(b))},allowedGroups:{type:new y(new m(b))}}}),et=new _({name:"AccessPermissions",fields:{read:{type:ee},write:{type:ee}}}),ei=new _({name:"ModelAccessDefaults",fields:()=>({ownerDID:{type:new m(b)},modelID:{type:new m(d)},permissions:{type:new m(et)}})});export class SchemaBuilder{_aliases;_aliasToModelID;_aggregateNumericByModel={};_groupKeyNumericByModel={};_definitions;_implemented={};_includedModelIDs;_includeInterfaceDependencies;_includeMutations;_includeRelationDependencies;_includeSubscriptions;_inputObjects={...z,PatchOperation};_mutations={};_nodeModelIDs;_onlyModels;_record;_references={};_relationsTo={};_extensionSDL;_extensionResolvers;_stubExtensionResolvers;_pluginNodeResolvers={};_subscriptions={};_types={OrderByDirection:Z};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=r(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 l=H(s.schema.properties[t]?.$ref),r="array"===this._getReferenceSchema(l).type,o=getGlobalID(i.model,e).toString();this._relationsTo[o]??={},this._relationsTo[o][t]??=[],this._relationsTo[o][t].push({model:n,isList:r})}}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:{...S,filter:n,orderBy:{type:toList(this._inputObjects[`${e}-order`])},search:{type:b}},resolve:async(t,i,n)=>await n.resolveConnection(this.getModelIDs(e),i)}}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(b)},node:{type:new m(e.nodeInterface)},rank:{type:new m(c)}})}),l=new _({name:"SearchResultConnection",fields:()=>({edges:{type:new m(new y(new m(s)))},pageInfo:{type:n}})});t.search={type:new m(l),args:{query:{type:new m(b)},models:{type:new y(new m(b))},first:{type:f},after:{type:b}},resolve:async(e,t,i)=>{let{query:n,models:s,first:l}=t;if(""===n.trim())throw Error("Search query must not be empty");let r=s?s.map(e=>this._aliasToModelID[e]??e):[...this._includedModelIDs],o=await i.searchDocuments(n,r,l??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:ei,args:{modelID:{type:new m(d)},permissionType:{type:new m(b)},accessLevel:{type:new m(b)},allowedDIDs:{type:toList(b)},allowedCircles:{type:toList(b)},allowedGroups:{type:toList(b)}},resolve:async(e,t,i)=>{let n=t.allowedDIDs??null,s=t.allowedCircles??null,l=t.allowedGroups??null;return P({allowedDIDs:n,allowedCircles:s,allowedGroups:l}),await i.executeSetModelAccessDefaults({modelID:t.modelID,permissionType:t.permissionType,accessLevel:t.accessLevel,allowedDIDs:n,allowedCircles:s,allowedGroups:l})}},this._mutations.removeModelAccessDefaults={type:a,args:{modelID:{type:new m(d)},permissionTypes:{type:new m(toList(b))}},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(b)},accessLevel:{type:new m(b)},allowedDIDs:{type:toList(b)},allowedCircles:{type:toList(b)},allowedGroups:{type:toList(b)}},resolve:async(e,t,i)=>{let n=t.allowedDIDs??null,s=t.allowedCircles??null,l=t.allowedGroups??null;return P({allowedDIDs:n,allowedCircles:s,allowedGroups:l}),await i.executeSetDocumentAccessOverride({documentID:t.documentID,permissionType:t.permissionType,accessLevel:t.accessLevel,allowedDIDs:n,allowedCircles:s,allowedGroups:l})}},this._mutations.removeDocumentAccessOverride={type:a,args:{documentID:{type:new m(d)},permissionTypes:{type:new m(toList(b))}},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}),types:[G,x,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 g(n);if(null!=this._extensionSDL){let e=new Set(Object.keys(s.getTypeMap()));s=o(s,j(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=()=>C(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]??C(t)}}}_getDefinitions(){if(null==this._definitions)throw Error("Definitions must be initialized");return this._definitions}_getReference(e,t){let i=H(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=H(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 k;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 m(n)}}let a=this._aliases[n]??r(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=R(async(i,l)=>{if(i.startsWith("did:"))return i;let r=n(i);if(r instanceof e)return r;if(r instanceof t)return await l.loadDocument(i);if(r instanceof s){let e=this._pluginNodeResolvers[r.typeName];if(null==e)throw Error(`No node resolver registered for plugin type "${r.typeName}"`);let t=await e.resolve(r.localID,l);if(null==t)throw Error(`Node resolver for "${r.typeName}" returned null for localID "${r.localID}"`);return{...t,__typename:r.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")}),l=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:{...S,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,l)=>{let r=N(n.uniqueFields,s.with),o=t.create(i,e,r);return await l.loadDocument(o.toString())}}}}return e}}),r=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(b)}}}),o={id:{type:new m(d)},model:{type:new m(b)},owner:{type:new m(l)},createdAt:{type:new m(T)},updatedAt:{type:T},accessPermissions:{type:et,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:l,description:"Account issuing the request, if authenticated",resolve:(e,t,i)=>i.getViewer()}};return{...i,accountObject:l,attachmentObject:r,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]??=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 h({...s,resolveType:e=>this._aliases[e.model]}):new _(s),a=this._buildAggregate(e,t,n),u=this._buildGroupedAggregate(e,t,n),{connectionType:c,edgeType:p}=F({nodeType:o,connectionFields:()=>{let t={aggregates:{type:a,resolve:async(t,i,n,s)=>{let l=t.aggregateScope,{count:r,aggregates:o}=this._buildAggregateRequest(e,s);return await n.resolveAggregate(l.modelIDs,{filter:l.filter,owner:l.owner,catalogID:l.catalogID,count:r,aggregates:o})}}};return null!=u&&(t.groupedAggregates={type:new m(toOuputList(u)),args:{groupBy:{type:new m(toList(this._inputObjects[`${e}-group-by`]))},having:{type:this._inputObjects[`${e}-having`]},orderBy:{type:toList(this._inputObjects[`${e}-group-order`])},limit:{type:f}},resolve:async(t,i,n,s)=>{let l=t.aggregateScope,{count:r,aggregates:o}=this._buildGroupedAggregateRequest(e,s),a=(i.groupBy??[]).map(e=>({keys:[e]})),u=this._buildGroupOrderBy(e,i.orderBy);return await n.resolveGroupedAggregate(l.modelIDs,{filter:l.filter,owner:l.owner,catalogID:l.catalogID,count:r,aggregates:o,groupBy:a,having:i.having,orderBy:u.length>0?u:void 0,limit:i.limit??void 0})}}),t}});return this._types[e]=o,this._types[`${e}-connection`]=c,this._types[`${e}-edge`]=p,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}`]=M({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}`]=M({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 l=N(t.uniqueFields,i.data);return{document:await n.executeSetMutation({modelID:e,unique:l,data:i.data,info:s,transactionID:i.transactionID})}}})),this._mutations[`update${n}`]=M({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}`]=M({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}_buildAggregate(e,t,i){let n=this._types[`${e}-aggregate`];if(null!=n)return n;let s={},l={},r=new Map;for(let[e,i]of Object.entries(t.schema.properties??{})){let t=i.$ref;if(null==t)continue;let n=H(t),o=this._getReferenceSchema(n);if("object"===o.type||"array"===o.type)continue;let a=this._buildScalar(n,o),u=a===f||a===c,d=a===b;u&&(s[e]={type:a}),(u||d)&&(l[e]={type:a},r.set(e,u))}this._aggregateNumericByModel[e]=r;let o=Object.keys(s),a={count:{type:new m(f),resolve:e=>e.count??0}};if(o.length>0){let t=new _({name:`${i}SumFields`,fields:s}),n={};for(let e of o)n[e]={type:c};let l=new _({name:`${i}AvgFields`,fields:n});this._types[`${e}-aggregate-sum`]=t,this._types[`${e}-aggregate-avg`]=l,a.sum={type:t,resolve:e=>e.sum??null},a.average={type:l,resolve:e=>e.average??null}}if(Object.keys(l).length>0){let t=new _({name:`${i}MinMaxFields`,fields:l});this._types[`${e}-aggregate-min-max`]=t,a.min={type:t,resolve:e=>e.min??null},a.max={type:t,resolve:e=>e.max??null}}let u=new _({name:`${i}Aggregate`,fields:a});return this._types[`${e}-aggregate`]=u,u}_buildGroupedAggregate(e,t,i){let n=this._types[`${e}-grouped-aggregate`];if(null!=n)return n;let s=new Map,l=new Map;for(let[e,i]of Object.entries(t.schema.properties??{})){let t=i.$ref;if(null==t)continue;let n=H(t),r=this._getReferenceSchema(n);if("object"===r.type||"array"===r.type)continue;let o=this._buildScalar(n,r);s.set(e,o),l.set(e,o===f||o===c)}if(this._groupKeyNumericByModel[e]=l,0===s.size)return null;let r=this._types[`${e}-aggregate-sum`],o=this._types[`${e}-aggregate-avg`],a=this._types[`${e}-aggregate-min-max`],d={};for(let e of s.keys())d[e]={value:e};let h=new u({name:`${i}GroupBy`,values:d});this._types[`${e}-group-by`]=h,this._inputObjects[`${e}-group-by`]=h;let y={};for(let[e,t]of s)y[e]={type:t};let g=new _({name:`${i}GroupKeys`,fields:y});this._types[`${e}-group-keys`]=g;let b={keys:{type:new m(g),resolve:e=>e.keys},count:{type:new m(f),resolve:e=>e.count??0}};null!=r&&null!=o&&(b.sum={type:r,resolve:e=>e.sum??null},b.average={type:o,resolve:e=>e.average??null}),null!=a&&(b.min={type:a,resolve:e=>e.min??null},b.max={type:a,resolve:e=>e.max??null});let w=new _({name:`${i}GroupedAggregate`,fields:b});this._types[`${e}-grouped-aggregate`]=w;let v=e=>this._inputObjects[`${e.name}ValueFilter`],D={count:{type:this._inputObjects.IntValueFilter}};if(null!=r&&null!=o){let t={},n={};for(let[e,i]of Object.entries(r.getFields()))t[e]={type:v(i.type)},n[e]={type:this._inputObjects.FloatValueFilter};let s=new p({name:`${i}HavingSum`,fields:t}),l=new p({name:`${i}HavingAverage`,fields:n});this._inputObjects[`${e}-having-sum`]=s,this._inputObjects[`${e}-having-average`]=l,D.sum={type:s},D.average={type:l}}if(null!=a){let t={},n={};for(let[e,i]of Object.entries(a.getFields()))t[e]={type:v(i.type)},n[e]={type:v(i.type)};let s=new p({name:`${i}HavingMin`,fields:t}),l=new p({name:`${i}HavingMax`,fields:n});this._inputObjects[`${e}-having-min`]=s,this._inputObjects[`${e}-having-max`]=l,D.min={type:s},D.max={type:l}}let O=new p({name:`${i}Having`,fields:D});this._inputObjects[`${e}-having`]=O;let I=(e,t)=>{let i={};for(let e of t)i[e]={type:Z};return new p({name:e,fields:i})},$=I(`${i}GroupKeysOrderBy`,s.keys());this._inputObjects[`${e}-group-keys-order`]=$;let j={keys:{type:$},count:{type:Z}};if(null!=r&&null!=o){let t=I(`${i}SumFieldsOrderBy`,Object.keys(r.getFields())),n=I(`${i}AvgFieldsOrderBy`,Object.keys(o.getFields()));this._inputObjects[`${e}-sum-order`]=t,this._inputObjects[`${e}-avg-order`]=n,j.sum={type:t},j.average={type:n}}if(null!=a){let t=I(`${i}MinFieldsOrderBy`,Object.keys(a.getFields())),n=I(`${i}MaxFieldsOrderBy`,Object.keys(a.getFields()));this._inputObjects[`${e}-min-order`]=t,this._inputObjects[`${e}-max-order`]=n,j.min={type:t},j.max={type:n}}let S=new p({name:`${i}GroupOrderBy`,fields:j});return this._inputObjects[`${e}-group-order`]=S,w}_buildAggregateRequest(e,t){let i=this._aggregateNumericByModel[e]??new Map,n=["sum","average","min","max"],s=!1,l=[];for(let e of t.fieldNodes){let r=e.selectionSet?.selections??[];for(let e of this._expandFieldSelections(r,t,new Set)){let r=e.name.value;if("count"===r){s=!0;continue}if(!n.includes(r))continue;let o=e.selectionSet?.selections??[];for(let e of this._expandFieldSelections(o,t,new Set)){let t=e.name.value;l.push({op:r,keys:[t],numeric:i.get(t)??!1})}}}return{count:s,aggregates:l}}_buildGroupedAggregateRequest(e,t){let i=this._aggregateNumericByModel[e]??new Map,n=["sum","average","min","max"],s=!1,l=[];for(let e of t.fieldNodes){let r=e.selectionSet?.selections??[];for(let e of this._expandFieldSelections(r,t,new Set)){let r=e.name.value;if("count"===r){s=!0;continue}if("keys"===r||!n.includes(r))continue;let o=e.selectionSet?.selections??[];for(let e of this._expandFieldSelections(o,t,new Set)){let t=e.name.value;l.push({op:r,keys:[t],numeric:i.get(t)??!1})}}}return{count:s,aggregates:l}}_buildGroupOrderBy(e,t){if(null==t)return[];let i=this._aggregateNumericByModel[e]??new Map,n=this._groupKeyNumericByModel[e]??new Map,s=[];for(let e of t){for(let[t,i]of(null!=e.count&&s.push({path:["count"],direction:e.count,numeric:!0}),Object.entries(e.keys??{})))s.push({path:["keys",t],direction:i,numeric:n.get(t)??!1});for(let[t,n]of Object.entries(e.sum??{}))s.push({path:["sum",t],direction:n,numeric:i.get(t)??!1});for(let[t,i]of Object.entries(e.average??{}))s.push({path:["average",t],direction:i,numeric:!0});for(let[t,n]of Object.entries(e.min??{}))s.push({path:["min",t],direction:n,numeric:i.get(t)??!1});for(let[t,n]of Object.entries(e.max??{}))s.push({path:["max",t],direction:n,numeric:i.get(t)??!1})}return s}*_expandFieldSelections(e,t,i){for(let n of e)switch(n.kind){case $.FIELD:yield n;break;case $.INLINE_FRAGMENT:yield*this._expandFieldSelections(n.selectionSet.selections,t,i);break;case $.FRAGMENT_SPREAD:{let e=n.name.value;if(i.has(e))break;let s=t.fragments[e];if(null==s)break;i.add(e),yield*this._expandFieldSelections(s.selectionSet.selections,t,i)}}}_buildDocumentFields(t,i,n){let s=this._buildDocumentDataObject(t,i,n),l=this._getDefinitions(),r={...l.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":K(o.type)?r[`${n}Accounts`]={type:new m(toOuputList(l.accountObject)),resolve:e=>e.data?.[n]??[]}:r[`${n}Account`]={type:l.accountObject,resolve:e=>e.data?.[n]??null};break;case"attachment":K(o.type)?r[`${n}Attachments`]={type:new m(toOuputList(l.attachmentObject)),resolve:t=>(t.data?.[n]??[]).map(e.fromString)}:r[`${n}Attachment`]={type:l.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=l.documentInterface):(e=getGlobalID(a,t).toString(),this._includedModelIDs.has(e)?i=this._buildDocument(e):(i=l.documentInterface,e=null)),K(o.type)?r[`${n}Documents`]={type:new m(toOuputList(i)),resolve:async(t,i,s)=>{let l=t.data?.[n]??[];return l.length?await s.resolveList(this.getModelIDs(e),l):[]}}:r[`${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(r,e,i)}for(let[e,i]of Object.entries(this._relationsTo[t]??{}))for(let t of i)this._includedModelIDs.has(t.model)&&this._buildRelationFields(r,e,t);return r}_buildDocumentDataObject(e,t,i){let n=`${e}-data`;if(null!=this._types[n])return this._types[n];let s=t.schema.required??[],l={};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 r=this._getReference(t);l[i]={type:s.includes(i)?new m(r):r}}let r={name:`${i}Data`,interfaces:()=>t.interfaces.map(t=>{let i=`${getGlobalID(t,e).toString()}-data`;return this._types[i]}).filter(e=>null!=e),fields:l},o="interface"===t.behavior?new h(r):new _(r);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 l=s.$ref,r=this._getReferenceInput(l,!1);i[e]={type:t.schema.required.includes(e)?new m(r):r};let o=H(l);null==this._getReferenceSchema(o).const&&(n[e]={type:this._getReferenceInput(l,!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=H(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 p({name:`${e}Filter`,isOneOf:!0,fields:{isNull:{type:a}}})}let l=this._buildScalar(i,n,s),o=W[l.name];if(null!=o)return this._inputObjects[o];let u=w(l)?new p({name:`${l.name}ValueFilter`,isOneOf:!0,fields:{isNull:{type:a},equalTo:{type:l},notEqualTo:{type:l},in:{type:toList(l)},notIn:{type:toList(l)}}}):U(l);return null==this._inputObjects[u.name]&&(this._inputObjects[u.name]=u),this._inputObjects[u.name]}_buildReferenceOrderByInput(e,t=""){let i=H(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 Z}}_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 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`,l=this._inputObjects[s];if(null!=l)return l;let o=this._aliases[e]??r(i+(t.title??"")),a=n?{_docOwner:{type:Z},_createdAt:{type:Z}}:{};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?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 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?k: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,r(t+e.title))))}_buildObject(e,t,i=""){let n=r(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[l,r]of Object.entries(t.properties??{})){let t=r.$ref;if(null==t)throw Error(`Missing ref for field ${l} of object ${e}`);let o=this._getReference(t,i);s[l]={type:n.includes(l)?new m(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 m(this._types[`${n}-connection`]),args:{...S,filter:{type:this._inputObjects[`${n}-filter`]},orderBy:{type:toList(this._inputObjects[`${n}-order`])}},resolve:(e,i,s)=>{let l={where:{[t]:{equalTo:e.id}}},r=i.filter?{and:[i.filter,l]}:l;return s.resolveConnection(this.getModelIDs(n),{...i,filter:r})}}}_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 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?b:null!=e.enum?this._buildEnumString(e,t):null!=e.format?this._buildFormatString(e):this._buildCustomString(e)}_buildCustomString(e){return null==e.title?b:Q[e.title.toLowerCase()]??b}_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 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
@@ -44,10 +44,14 @@ export type ModelAccessDefaults = {
44
44
  read?: {
45
45
  level: string;
46
46
  allowedDIDs: Array<string>;
47
+ allowedCircles?: Array<string>;
48
+ allowedGroups?: Array<string>;
47
49
  };
48
50
  write?: {
49
51
  level: string;
50
52
  allowedDIDs: Array<string>;
53
+ allowedCircles?: Array<string>;
54
+ allowedGroups?: Array<string>;
51
55
  };
52
56
  };
53
57
  };
package/lib/utils.d.ts CHANGED
@@ -1,2 +1,31 @@
1
1
  import type { DocumentData } from '@kubun/protocol';
2
2
  export declare function getUniqueDocValue(fields: Array<string>, data: DocumentData): Uint8Array;
3
+ /**
4
+ * Validate that every entry of `dids` is a string with the `did:` prefix.
5
+ * Throws a user-facing error on the first malformed entry. Mirrors
6
+ * `validateDIDs` from `@kubun/engine`'s access-control module — duplicated
7
+ * here because `@kubun/graphql` is upstream of `@kubun/engine` in the
8
+ * dependency graph.
9
+ */
10
+ export declare function validateDIDs(dids: Array<string>): void;
11
+ /**
12
+ * Validate that an identifier (circle or group ID) is a non-empty,
13
+ * non-whitespace string. There is no canonical format helper for circle and
14
+ * group IDs in `@kubun/id` (they are app-supplied opaque strings — Kubun ID
15
+ * helpers cover content-addressed IDs only), so this check rejects only
16
+ * obvious garbage. Downstream membership checks won't match if the format is
17
+ * malformed beyond this — callers should treat malformed IDs as an empty
18
+ * scope.
19
+ */
20
+ export declare function validateIDs(ids: Array<string>, kind: 'circle' | 'group'): void;
21
+ /**
22
+ * Validate the three optional access-control identifier arrays passed to
23
+ * `setModelAccessDefaults` / `setDocumentAccessOverride` resolvers. Returns
24
+ * normally on success; throws a user-facing GraphQL error on malformed
25
+ * input. Each array, when non-null, is checked element-wise.
26
+ */
27
+ export declare function validateAccessIdentifiers(args: {
28
+ allowedDIDs: Array<string> | null;
29
+ allowedCircles: Array<string> | null;
30
+ allowedGroups: Array<string> | null;
31
+ }): void;
package/lib/utils.js CHANGED
@@ -1 +1 @@
1
- import{fromUTF as e}from"@enkaku/codec";export function getUniqueDocValue(n,o){return e(n.map(e=>String(o[e]??"")).join("|"))}
1
+ import{fromUTF as t}from"@enkaku/codec";export function getUniqueDocValue(e,o){return t(e.map(t=>String(o[t]??"")).join("|"))}export function validateDIDs(t){for(let e of t)if("string"!=typeof e||!e.startsWith("did:"))throw Error(`Invalid DID format: ${String(e)}`)}export function validateIDs(t,e){for(let o of t)if("string"!=typeof o||0===o.trim().length)throw Error(`Invalid ${e} ID: must be a non-empty string`)}export function validateAccessIdentifiers(t){null!=t.allowedDIDs&&validateDIDs(t.allowedDIDs),null!=t.allowedCircles&&validateIDs(t.allowedCircles,"circle"),null!=t.allowedGroups&&validateIDs(t.allowedGroups,"group")}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubun/graphql",
3
- "version": "0.8.2",
3
+ "version": "0.10.0",
4
4
  "license": "see LICENSE.md",
5
5
  "keywords": [],
6
6
  "type": "module",
@@ -15,24 +15,26 @@
15
15
  ],
16
16
  "sideEffects": false,
17
17
  "dependencies": {
18
- "@enkaku/async": "^0.14.1",
19
- "@enkaku/codec": "^0.14.0",
20
- "@enkaku/event": "^0.14.1",
21
- "@enkaku/otel": "^0.14.0",
18
+ "@enkaku/async": "^0.16.0",
19
+ "@enkaku/codec": "^0.16.0",
20
+ "@enkaku/event": "^0.16.0",
21
+ "@enkaku/otel": "^0.16.0",
22
22
  "change-case": "^5.4.4",
23
23
  "graphql": "^16.13.2",
24
24
  "graphql-relay": "^0.10.2",
25
25
  "graphql-scalars": "^1.25.0",
26
- "multiformats": "^13.4.2",
27
- "@kubun/hlc": "^0.8.0",
28
- "@kubun/id": "^0.8.0",
29
- "@kubun/protocol": "^0.8.1"
26
+ "multiformats": "^14.0.0",
27
+ "@kubun/hlc": "^0.10.0",
28
+ "@kubun/protocol": "^0.10.0",
29
+ "@kubun/id": "^0.10.0"
30
30
  },
31
31
  "devDependencies": {
32
- "@enkaku/capability": "^0.14.0",
33
- "@enkaku/token": "0.14.1",
34
- "@kubun/test-utils": "^0.8.0",
35
- "@kubun/db-better-sqlite": "^0.8.1"
32
+ "@enkaku/capability": "^0.16.0",
33
+ "@enkaku/token": "^0.16.0",
34
+ "@kubun/store-graph": "^0.10.0",
35
+ "@kubun/db-better-sqlite": "^0.10.0",
36
+ "@kubun/test-utils": "^0.10.0",
37
+ "@kubun/db": "^0.10.0"
36
38
  },
37
39
  "scripts": {
38
40
  "build:clean": "del lib",