@kubun/graphql 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/context.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { Tracer } from '@enkaku/otel';
1
2
  import type { KubunDB } from '@kubun/db';
2
3
  import type { DocumentData, DocumentFilter, DocumentNode } from '@kubun/protocol';
3
4
  import type { GraphQLResolveInfo } from 'graphql';
@@ -33,10 +34,24 @@ export type SubscriptionContext = {
33
34
  */
34
35
  export type ReadOnlyContext = QueryContext & SubscriptionContext;
35
36
  export type AccessChecker = (doc: DocumentNode, permissionType: 'read' | 'write') => Promise<boolean>;
37
+ export type AccessWarning = {
38
+ message: string;
39
+ code: string;
40
+ path?: Array<string>;
41
+ };
42
+ export type ComplexityStats = {
43
+ documentsScanned: number;
44
+ modelsQueried: Set<string>;
45
+ resolverCount: number;
46
+ resolverTimings?: Map<string, number>;
47
+ };
36
48
  export type ReadContextParams = {
37
49
  db: KubunDB;
38
50
  viewerDID: string;
39
51
  accessChecker?: AccessChecker;
52
+ warnings?: Array<AccessWarning>;
53
+ complexity?: ComplexityStats;
54
+ tracer?: Tracer;
40
55
  };
41
56
  export declare function createReadContext(params: ReadContextParams): ReadOnlyContext;
42
57
  export type CreateMutationParams = {
package/lib/context.js CHANGED
@@ -1 +1 @@
1
- import{defer as e}from"@enkaku/async";import{DocumentID as t}from"@kubun/id";export function createReadContext(r){let{db:a,viewerDID:n,accessChecker:o}=r;function u(t,r){let n=!1,o=null,u=[],s=a.events.on("document:saved",e=>{if(t(e)){let t=r(e);null==o?u.push(t):(o.resolve(t),o=null)}}),l=()=>(s(),n=!0,Promise.resolve({done:!0,value:void 0}));return{[Symbol.asyncDispose]:()=>(s(),n=!0,Promise.resolve()),[Symbol.asyncIterator](){return this},next:()=>{if(n)return Promise.resolve({done:!0,value:void 0});let t=u.shift();return null!=t?Promise.resolve({value:t,done:!1}):(o=e()).promise.then(e=>({value:e,done:!1}))},return:l,throw:l}}return{getViewer:()=>n,async loadDocument(e){let r=await a.getDocument(t.fromString(e));return r&&(!o||await o(r,"read"))?r:null},searchDocuments:async(e,t,r)=>await a.searchDocuments({query:e,modelIDs:t,first:r}),async resolveConnection(e,t){if(null!=t.search&&""!==t.search.trim()){let r=await a.searchDocuments({query:t.search,modelIDs:e,first:200});if(0===r.length)return{edges:[],pageInfo:{hasNextPage:!1,hasPreviousPage:!1,startCursor:null,endCursor:null}};let n=r.map(e=>e.documentID),u=await a.listDocuments({modelIDs:e,docIDs:n}),s=u;if(o)for(let e of(s=[],u))await o(e,"read")&&s.push(e);let l=new Map(r.map(e=>[e.documentID,e.rank]));s.sort((e,t)=>Math.abs(l.get(t.id)??0)-Math.abs(l.get(e.id)??0));let i=s.slice(0,t.first??50);return{edges:i.map((e,t)=>({cursor:String(t),node:e})),pageInfo:{hasNextPage:s.length>i.length,hasPreviousPage:!1,startCursor:i.length>0?"0":null,endCursor:i.length>0?String(i.length-1):null}}}if(null==o){let{entries:r,hasMore:n}=await a.queryDocuments({...t,modelIDs:e});return{edges:r.map(e=>({cursor:e.cursor,node:e.document})),pageInfo:{hasNextPage:!!t.first&&n,hasPreviousPage:!t.first&&n,endCursor:r.at(-1)?.cursor??null,startCursor:r.at(0)?.cursor??null}}}let r=[],n=0,u=0;if(null!=t.first){let s=2*(n=t.first),l=t.after;for(;r.length<n&&u<10;){let{entries:i,hasMore:d}=await a.queryDocuments({...t,modelIDs:e,first:s,after:l});if(0===i.length&&!d)break;for(let e of i)if(await o(e.document,"read")&&(r.push(e),r.length>=n))break;if(!d)break;l=i.at(-1)?.cursor??null,u++}}else if(null!=t.last){let s=2*(n=t.last),l=t.before;for(;r.length<n&&u<10;){let{entries:i,hasMore:d}=await a.queryDocuments({...t,modelIDs:e,last:s,before:l});if(0===i.length&&!d)break;for(let e of[...i].reverse())if(await o(e.document,"read")&&(r.unshift(e),r.length>=n))break;if(!d)break;l=i.at(0)?.cursor??null,u++}}let s=r.slice(0,n),l=r.length>n;return{edges:s.map(e=>({cursor:e.cursor,node:e.document})),pageInfo:{hasNextPage:!!t.first&&l,hasPreviousPage:!t.first&&l,endCursor:s.at(-1)?.cursor??null,startCursor:s.at(0)?.cursor??null}}},async resolveList(e,t){let r=await a.listDocuments({modelIDs:e,docIDs:t});if(!o)return r;let n=[];for(let e of r)await o(e,"read")&&n.push(e);return n},resolveCount:async(e,t)=>await a.countDocuments({modelIDs:e,filter:t}),subscribeToDocumentCreated(e){let t=u(t=>"create"===t.type&&e.includes(t.document.model),e=>e.document);return o?async function*(){for await(let e of t)await o(e,"read")&&(yield e)}():t},subscribeToDocumentChanged(e){let t=u(t=>"update"===t.type&&t.document.id===e&&null!==t.document.data,e=>e.document);return o?async function*(){for await(let e of t)await o(e,"read")&&(yield e)}():t},subscribeToDocumentRemoved:()=>u(e=>"update"===e.type&&null===e.document.data,e=>e.document.id),subscribeToDocumentEdgeAdded(e,t){let r=u(r=>null!==r.document.data&&e.includes(r.document.model)&&t(r.document.data)&&("create"===r.type||null!==r.previous.data&&t(r.previous.data)),e=>({cursor:e.getCursor(),node:e.document}));return o?async function*(){for await(let e of r)await o(e.node,"read")&&(yield e)}():r},subscribeToDocumentEdgeRemoved:(e,t)=>u(r=>"update"===r.type&&e.includes(r.document.model)&&null!==r.previous.data&&t(r.previous.data)&&(null===r.document.data||!t(r.document.data)),e=>e.document.id)}}
1
+ import{defer as e}from"@enkaku/async";import{withSpan as t}from"@enkaku/otel";import{DocumentID as o}from"@kubun/id";import{KubunAttributeKeys as n,KubunSpanNames as r}from"@kubun/protocol";export function createReadContext(l){let{db:s,viewerDID:i,accessChecker:u}=l;function a(e,o,n){return null!=l.tracer?t(l.tracer,e,{attributes:o},async()=>n()):n()}function c(t,o){let n=!1,r=null,l=[],i=s.events.on("document:saved",e=>{if(t(e)){let t=o(e);null==r?l.push(t):(r.resolve(t),r=null)}}),u=()=>(i(),n=!0,Promise.resolve({done:!0,value:void 0}));return{[Symbol.asyncDispose]:()=>(i(),n=!0,Promise.resolve()),[Symbol.asyncIterator](){return this},next:()=>{if(n)return Promise.resolve({done:!0,value:void 0});let t=l.shift();return null!=t?Promise.resolve({value:t,done:!1}):(r=e()).promise.then(e=>({value:e,done:!1}))},return:u,throw:u}}return{getViewer:()=>i,async loadDocument(e){let t=`document:${e}`,i=l.complexity?.resolverTimings!=null?performance.now():0,c=await a(r.DATA_QUERY,{[n.DOCUMENT_ID]:e},async()=>{let t=await s.getDocument(o.fromString(e));return t?u&&!await u(t,"read")?(null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e}`,code:"KB07"}),null):(null!=l.complexity&&(l.complexity.resolverCount++,l.complexity.documentsScanned++),t):null});if(l.complexity?.resolverTimings!=null){let e=Math.round((performance.now()-i)*100)/100,o=l.complexity.resolverTimings.get(t)??0;l.complexity.resolverTimings.set(t,o+e)}return c},searchDocuments:async(e,t,o)=>await s.searchDocuments({query:e,modelIDs:t,first:o}),async resolveConnection(e,t){let o=`connection:${e.join(",")}`,i=l.complexity?.resolverTimings!=null?performance.now():0,c=await a(r.DATA_QUERY,{[n.MODEL_ID]:e.join(",")},async()=>{if(null!=t.search&&""!==t.search.trim()){let o=await s.searchDocuments({query:t.search,modelIDs:e,first:200});if(0===o.length){if(null!=l.complexity)for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);return{edges:[],pageInfo:{hasNextPage:!1,hasPreviousPage:!1,startCursor:null,endCursor:null}}}let n=o.map(e=>e.documentID),r=await s.listDocuments({modelIDs:e,docIDs:n}),i=r;if(u)for(let e of(i=[],r))await u(e,"read")?i.push(e):null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e.id}`,code:"KB07"});let a=new Map(o.map(e=>[e.documentID,e.rank]));i.sort((e,t)=>Math.abs(a.get(t.id)??0)-Math.abs(a.get(e.id)??0));let c=i.slice(0,t.first??50);if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=c.length}return{edges:c.map((e,t)=>({cursor:String(t),node:e})),pageInfo:{hasNextPage:i.length>c.length,hasPreviousPage:!1,startCursor:c.length>0?"0":null,endCursor:c.length>0?String(c.length-1):null}}}if(null==u){let{entries:o,hasMore:n}=await s.queryDocuments({...t,modelIDs:e});if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=o.length}return{edges:o.map(e=>({cursor:e.cursor,node:e.document})),pageInfo:{hasNextPage:!!t.first&&n,hasPreviousPage:!t.first&&n,endCursor:o.at(-1)?.cursor??null,startCursor:o.at(0)?.cursor??null}}}let o=[],n=0,r=0;if(null!=t.first){let i=2*(n=t.first),a=t.after;for(;o.length<n&&r<10;){let{entries:c,hasMore:m}=await s.queryDocuments({...t,modelIDs:e,first:i,after:a});if(0===c.length&&!m)break;for(let e of c)if(await u(e.document,"read")){if(o.push(e),o.length>=n)break}else null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e.document.id}`,code:"KB07"});if(!m)break;a=c.at(-1)?.cursor??null,r++}}else if(null!=t.last){let i=2*(n=t.last),a=t.before;for(;o.length<n&&r<10;){let{entries:c,hasMore:m}=await s.queryDocuments({...t,modelIDs:e,last:i,before:a});if(0===c.length&&!m)break;for(let e of[...c].reverse())if(await u(e.document,"read")){if(o.unshift(e),o.length>=n)break}else null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e.document.id}`,code:"KB07"});if(!m)break;a=c.at(0)?.cursor??null,r++}}let i=o.slice(0,n),a=o.length>n;if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=i.length}return{edges:i.map(e=>({cursor:e.cursor,node:e.document})),pageInfo:{hasNextPage:!!t.first&&a,hasPreviousPage:!t.first&&a,endCursor:i.at(-1)?.cursor??null,startCursor:i.at(0)?.cursor??null}}});if(l.complexity?.resolverTimings!=null){let e=Math.round((performance.now()-i)*100)/100,t=l.complexity.resolverTimings.get(o)??0;l.complexity.resolverTimings.set(o,t+e)}return c},async resolveList(e,t){let o=`list:${e.join(",")}`,i=l.complexity?.resolverTimings!=null?performance.now():0,c=await a(r.DATA_QUERY,{[n.MODEL_ID]:e.join(",")},async()=>{let o=await s.listDocuments({modelIDs:e,docIDs:t});if(!u){if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=o.length}return o}let n=[];for(let e of o)await u(e,"read")?n.push(e):null!=l.warnings&&l.warnings.push({message:`Access denied for document ${e.id}`,code:"KB07"});if(null!=l.complexity){for(let t of(l.complexity.resolverCount++,e))l.complexity.modelsQueried.add(t);l.complexity.documentsScanned+=n.length}return n});if(l.complexity?.resolverTimings!=null){let e=Math.round((performance.now()-i)*100)/100,t=l.complexity.resolverTimings.get(o)??0;l.complexity.resolverTimings.set(o,t+e)}return c},async resolveCount(e,t){let o=`count:${e.join(",")}`,i=l.complexity?.resolverTimings!=null?performance.now():0,u=await a(r.DATA_QUERY,{[n.MODEL_ID]:e.join(",")},async()=>(null!=l.complexity&&l.complexity.resolverCount++,await s.countDocuments({modelIDs:e,filter:t})));if(l.complexity?.resolverTimings!=null){let e=Math.round((performance.now()-i)*100)/100,t=l.complexity.resolverTimings.get(o)??0;l.complexity.resolverTimings.set(o,t+e)}return u},subscribeToDocumentCreated(e){let t=c(t=>"create"===t.type&&e.includes(t.document.model),e=>e.document);return u?async function*(){for await(let e of t)await u(e,"read")&&(yield e)}():t},subscribeToDocumentChanged(e){let t=c(t=>"update"===t.type&&t.document.id===e&&null!==t.document.data,e=>e.document);return u?async function*(){for await(let e of t)await u(e,"read")&&(yield e)}():t},subscribeToDocumentRemoved:()=>c(e=>"update"===e.type&&null===e.document.data,e=>e.document.id),subscribeToDocumentEdgeAdded(e,t){let o=c(o=>null!==o.document.data&&e.includes(o.document.model)&&t(o.document.data)&&("create"===o.type||null!==o.previous.data&&t(o.previous.data)),e=>({cursor:e.getCursor(),node:e.document}));return u?async function*(){for await(let e of o)await u(e.node,"read")&&(yield e)}():o},subscribeToDocumentEdgeRemoved:(e,t)=>c(o=>"update"===o.type&&e.includes(o.document.model)&&null!==o.previous.data&&t(o.previous.data)&&(null===o.document.data||!t(o.document.data)),e=>e.document.id)}}
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type { Context, CreateMutationParams, MutationContext, QueryContext, ReadContextParams, ReadOnlyContext, RemoveMutationParams, SetDocumentAccessOverrideParams, SetModelAccessDefaultsParams, SetMutationParams, SubscriptionContext, UpdateMutationParams, } from './context.js';
1
+ export type { AccessWarning, ComplexityStats, Context, CreateMutationParams, MutationContext, QueryContext, ReadContextParams, ReadOnlyContext, RemoveMutationParams, SetDocumentAccessOverrideParams, SetModelAccessDefaultsParams, SetMutationParams, SubscriptionContext, UpdateMutationParams, } from './context.js';
2
2
  export { createReadContext } from './context.js';
3
3
  export { GraphQLAttachmentID, GraphQLDocID } from './identifiers.js';
4
4
  export type { SchemaBuilderParams, SharedDefinitions, } from './schema.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubun/graphql",
3
- "version": "0.6.1",
3
+ "version": "0.7.1",
4
4
  "license": "see LICENSE.md",
5
5
  "keywords": [],
6
6
  "type": "module",
@@ -15,21 +15,22 @@
15
15
  ],
16
16
  "sideEffects": false,
17
17
  "dependencies": {
18
- "@enkaku/async": "^0.13.0",
19
- "@enkaku/codec": "^0.13.0",
18
+ "@enkaku/async": "^0.14.0",
19
+ "@enkaku/codec": "^0.14.0",
20
+ "@enkaku/otel": "^0.14.0",
20
21
  "change-case": "^5.4.4",
21
22
  "graphql": "^16.13.1",
22
23
  "graphql-relay": "^0.10.2",
23
24
  "graphql-scalars": "^1.25.0",
24
25
  "multiformats": "^13.4.2",
25
- "@kubun/id": "^0.6.0",
26
- "@kubun/protocol": "^0.6.0"
26
+ "@kubun/protocol": "^0.7.1",
27
+ "@kubun/id": "^0.7.0"
27
28
  },
28
29
  "devDependencies": {
29
- "@enkaku/capability": "^0.13.0",
30
- "@enkaku/token": "0.13.0",
31
- "@kubun/db": "^0.6.0",
32
- "@kubun/test-utils": "^0.6.0"
30
+ "@enkaku/capability": "^0.14.0",
31
+ "@enkaku/token": "0.14.0",
32
+ "@kubun/db": "^0.7.0",
33
+ "@kubun/test-utils": "^0.7.0"
33
34
  },
34
35
  "scripts": {
35
36
  "build:clean": "del lib",