refactor(infra): directory structure (#4615)

This commit is contained in:
Joooye_34
2023-10-18 23:30:08 +08:00
committed by GitHub
parent 814d552be8
commit bed9310519
1150 changed files with 539 additions and 584 deletions

View File

@@ -0,0 +1,3 @@
# `GraphQL` client
Auto generated `GraphQL` client for affine.pro

View File

@@ -0,0 +1,32 @@
hooks:
afterOneFileWrite:
- prettier --write
config:
strict: true
maybeValue: T | null
declarationKind: interface
avoidOptionals: true
preResolveTypes: true
onlyOperationTypes: true
namingConvention:
enumValues: keep
scalars:
DateTime: string
Date: string
Decimal: number
UUID: string
ID: string
JSON: any
Upload: File
overwrite: true
schema: ../../backend/server/src/schema.gql
documents: ./src/**/*.gql
generates:
./src/schema.ts:
plugins:
- typescript
- typescript-operations
- add:
content: '/* eslint-disable */'
- ./export-gql-plugin.cjs:
output: ./src/graphql/index.ts

View File

@@ -0,0 +1,224 @@
const fs = require('fs');
const path = require('path');
const { Kind, print } = require('graphql');
const { upperFirst, lowerFirst } = require('lodash');
/**
* return exported name used in runtime.
*
* @param {import('graphql').ExecutableDefinitionNode} def
* @returns {string}
*/
function getExportedName(def) {
const name = lowerFirst(def.name?.value);
const suffix =
def.kind === Kind.OPERATION_DEFINITION
? upperFirst(def.operation)
: 'Fragment';
return name.endsWith(suffix) ? name : name + suffix;
}
/**
* @type {import('@graphql-codegen/plugin-helpers').CodegenPlugin}
*/
module.exports = {
plugin: (_schema, documents, { output }) => {
const nameLocationMap = new Map();
const locationSourceMap = new Map(
documents
.filter(source => !!source.location)
.map(source => [source.location, source])
);
/**
* @type {string[]}
*/
const defs = [];
const queries = [];
const mutations = [];
for (const [location, source] of locationSourceMap) {
if (
!source ||
!source.document ||
!location ||
source.document.kind !== Kind.DOCUMENT ||
!source.document.definitions ||
!source.document.definitions.length
) {
return;
}
const doc = source.document;
if (doc.definitions.length > 1) {
throw new Error('Only support one definition per file.');
}
const definition = doc.definitions[0];
if (!definition) {
throw new Error(`Found empty file ${location}.`);
}
if (
!definition.selectionSet ||
!definition.selectionSet.selections ||
definition.selectionSet.selections.length === 0
) {
throw new Error(`Found empty fields selection in file ${location}`);
}
if (
definition.kind === Kind.OPERATION_DEFINITION ||
definition.kind === Kind.FRAGMENT_DEFINITION
) {
if (!definition.name) {
throw new Error(`Anonymous definition found in ${location}`);
}
const exportedName = getExportedName(definition);
// duplication checking
if (nameLocationMap.has(exportedName)) {
throw new Error(
`name ${exportedName} export from ${location} are duplicated.`
);
} else {
/**
* @type {import('graphql').DefinitionNode[]}
*/
let importedDefinitions = [];
if (source.location) {
fs.readFileSync(source.location, 'utf8')
.split(/\r\n|\r|\n/)
.forEach(line => {
if (line[0] === '#') {
const [importKeyword, importPath] = line
.split(' ')
.filter(Boolean);
if (importKeyword === '#import') {
const realImportPath = path.posix.join(
location,
'..',
importPath.replace(/["']/g, '')
);
const imports =
locationSourceMap.get(realImportPath)?.document
.definitions;
if (imports) {
importedDefinitions = [
...importedDefinitions,
...imports,
];
}
}
}
});
}
const importing = importedDefinitions
.map(def => `\${${getExportedName(def)}}`)
.join('\n');
// is query or mutation
if (definition.kind === Kind.OPERATION_DEFINITION) {
// add for runtime usage
doc.operationName = definition.name.value;
doc.defName = definition.selectionSet.selections
.filter(field => field.kind === Kind.FIELD)
.map(field => field.name.value)
.join(',');
nameLocationMap.set(exportedName, location);
const containsFile = doc.definitions.some(def => {
const { variableDefinitions } = def;
if (variableDefinitions) {
return variableDefinitions.some(variableDefinition => {
if (
variableDefinition?.type?.type?.name?.value === 'Upload'
) {
return true;
}
return false;
});
} else {
return false;
}
});
defs.push(`export const ${exportedName} = {
id: '${exportedName}' as const,
operationName: '${doc.operationName}',
definitionName: '${doc.defName}',
containsFile: ${containsFile},
query: \`
${print(doc)}${importing || ''}\`,
};
`);
if (definition.operation === 'query') {
queries.push(exportedName);
} else if (definition.operation === 'mutation') {
mutations.push(exportedName);
}
} else {
defs.unshift(`export const ${exportedName} = \`
${print(doc)}${importing || ''}\``);
}
}
}
}
fs.writeFileSync(
output,
[
'/* do not manipulate this file manually. */',
`export interface GraphQLQuery {
id: string;
operationName: string;
definitionName: string;
query: string;
containsFile?: boolean;
}
`,
...defs,
].join('\n')
);
const queriesUnion = queries
.map(query => {
const queryName = upperFirst(query);
return `{
name: '${query}',
variables: ${queryName}Variables,
response: ${queryName}
}
`;
})
.join('|');
const mutationsUnion = mutations
.map(query => {
const queryName = upperFirst(query);
return `{
name: '${query}',
variables: ${queryName}Variables,
response: ${queryName}
}
`;
})
.join('|');
const queryTypes = queriesUnion
? `export type Queries = ${queriesUnion}`
: '';
const mutationsTypes = mutationsUnion
? `export type Mutations = ${mutationsUnion}`
: '';
return `
${queryTypes}
${mutationsTypes}
`;
},
validate: (_schema, _documents, { output }) => {
if (!output) {
throw new Error('Export plugin must be used with a output file given');
}
},
};

View File

@@ -0,0 +1,33 @@
{
"name": "@affine/graphql",
"version": "0.10.0-canary.1",
"description": "Autogenerated GraphQL client for affine.pro",
"license": "MIT",
"type": "module",
"main": "./src/index.ts",
"module": "./src/index.ts",
"exports": {
".": "./src/index.ts"
},
"devDependencies": {
"@graphql-codegen/add": "^5.0.0",
"@graphql-codegen/cli": "5.0.0",
"@graphql-codegen/typescript": "^4.0.1",
"@graphql-codegen/typescript-operations": "^4.0.1",
"@types/lodash-es": "^4.17.9",
"lodash-es": "^4.17.21",
"prettier": "^3.0.3",
"vitest": "0.34.6"
},
"scripts": {
"postinstall": "gql-gen"
},
"dependencies": {
"@affine/env": "workspace:*",
"graphql": "^16.8.1",
"nanoid": "^5.0.1"
},
"installConfig": {
"hoistingLimits": "workspaces"
}
}

View File

@@ -0,0 +1,159 @@
import { nanoid } from 'nanoid';
import type { Mock } from 'vitest';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { gqlFetcherFactory } from '../fetcher';
import type { GraphQLQuery } from '../graphql';
import {
generateRandUTF16Chars,
SPAN_ID_BYTES,
TRACE_ID_BYTES,
TraceReporter,
} from '../utils';
const query: GraphQLQuery = {
id: 'query',
query: 'query { field }',
operationName: 'query',
definitionName: 'query',
};
let fetch: Mock;
describe('GraphQL fetcher', () => {
beforeEach(() => {
fetch = vi.fn(() =>
Promise.resolve(
new Response(JSON.stringify({ data: { field: 1 } }), {
headers: {
'content-type': 'application/json',
},
})
)
);
vi.stubGlobal('fetch', fetch);
});
afterEach(() => {
fetch.mockReset();
});
const gql = gqlFetcherFactory('https://example.com/graphql');
it('should send POST request to given endpoint', async () => {
await gql(
// @ts-expect-error variables is actually optional
{ query }
);
expect(fetch).toBeCalledTimes(1);
expect(fetch.mock.lastCall[0]).toBe('https://example.com/graphql');
const ctx = fetch.mock.lastCall[1] as RequestInit;
expect(ctx.method).toBe('POST');
});
it('should send with correct graphql JSON body', async () => {
await gql({
query,
// @ts-expect-error forgive the fake variables
variables: { a: 1, b: '2', c: { d: false } },
});
expect(fetch.mock.lastCall[1]).toEqual(
expect.objectContaining({
body: '{"query":"query { field }","variables":{"a":1,"b":"2","c":{"d":false}},"operationName":"query"}',
headers: expect.objectContaining({
'content-type': 'application/json',
'x-definition-name': 'query',
'x-operation-name': 'query',
'x-request-id': expect.any(String),
}),
method: 'POST',
})
);
});
it('should correctly ignore nil variables', async () => {
await gql({
query,
// @ts-expect-error forgive the fake variables
variables: { a: false, b: null, c: undefined },
});
expect(fetch.mock.lastCall[1].body).toMatchInlineSnapshot(
'"{\\"query\\":\\"query { field }\\",\\"variables\\":{\\"a\\":false,\\"b\\":null},\\"operationName\\":\\"query\\"}"'
);
await gql({
query,
// @ts-expect-error forgive the fake variables
variables: { a: false, b: null, c: undefined },
keepNilVariables: false,
});
expect(fetch.mock.lastCall[1].body).toMatchInlineSnapshot(
'"{\\"query\\":\\"query { field }\\",\\"variables\\":{\\"a\\":false},\\"operationName\\":\\"query\\"}"'
);
});
it('should correct handle graphql error', async () => {
fetch.mockResolvedValue(
new Response(
JSON.stringify({
data: null,
errors: [{ message: 'error', path: ['field'] }],
}),
{
headers: {
'content-type': 'application/json',
},
status: 400,
}
)
);
await expect(gql({ query, variables: void 0 })).rejects
.toMatchInlineSnapshot(`
[
[GraphQLError: error],
]
`);
});
});
describe('Trace Reporter', () => {
const startTime = new Date().toISOString();
const traceId = generateRandUTF16Chars(TRACE_ID_BYTES);
const spanId = generateRandUTF16Chars(SPAN_ID_BYTES);
const requestId = nanoid();
it('spanId, traceId should be right format', () => {
expect(
new RegExp(`^[0-9a-f]{${SPAN_ID_BYTES * 2}}$`).test(
generateRandUTF16Chars(SPAN_ID_BYTES)
)
).toBe(true);
expect(
new RegExp(`^[0-9a-f]{${TRACE_ID_BYTES * 2}}$`).test(
generateRandUTF16Chars(TRACE_ID_BYTES)
)
).toBe(true);
});
it('test createTraceSpan', () => {
const traceSpan = TraceReporter.createTraceSpan(
traceId,
spanId,
startTime,
{ requestId }
);
expect(traceSpan.startTime).toBe(startTime);
expect(
traceSpan.name ===
`projects/{GCP_PROJECT_ID}/traces/${traceId}/spans/${spanId}`
).toBe(true);
expect(traceSpan.spanId).toBe(spanId);
expect(traceSpan.attributes.attributeMap.requestId?.stringValue.value).toBe(
requestId
);
});
});

View File

@@ -0,0 +1,260 @@
import type { ExecutionResult } from 'graphql';
import { GraphQLError } from 'graphql';
import { isNil, isObject, merge } from 'lodash-es';
import { nanoid } from 'nanoid';
import type { GraphQLQuery } from './graphql';
import type { Mutations, Queries } from './schema';
import {
generateRandUTF16Chars,
SPAN_ID_BYTES,
TRACE_FLAG,
TRACE_ID_BYTES,
TRACE_VERSION,
traceReporter,
} from './utils';
export type NotArray<T> = T extends Array<unknown> ? never : T;
export type _QueryVariables<Q extends GraphQLQuery> =
Q['id'] extends Queries['name']
? Extract<Queries, { name: Q['id'] }>['variables']
: Q['id'] extends Mutations['name']
? Extract<Mutations, { name: Q['id'] }>['variables']
: undefined;
export type QueryVariables<Q extends GraphQLQuery> = _QueryVariables<Q> extends
| never
| Record<string, never>
? never
: _QueryVariables<Q>;
export type QueryResponse<Q extends GraphQLQuery> = Extract<
Queries | Mutations,
{ name: Q['id'] }
>['response'];
type NullableKeys<T> = {
[K in keyof T]: null extends T[K] ? K : never;
}[keyof T];
type NonNullableKeys<T> = {
[K in keyof T]: null extends T[K] ? never : K;
}[keyof T];
export type RecursiveMaybeFields<T> = T extends
| number
| boolean
| string
| null
| undefined
? T
: {
[K in NullableKeys<T>]?: RecursiveMaybeFields<T[K]>;
} & {
[K in NonNullableKeys<T>]: RecursiveMaybeFields<T[K]>;
};
type AllowedRequestContext = Omit<RequestInit, 'method' | 'body'>;
export interface RequestBody {
operationName?: string;
variables: any;
query: string;
form?: FormData;
}
type QueryVariablesOption<Q extends GraphQLQuery> =
QueryVariables<Q> extends never
? {
variables?: undefined;
}
: { variables: RecursiveMaybeFields<QueryVariables<Q>> };
export type RequestOptions<Q extends GraphQLQuery> = QueryVariablesOption<Q> & {
/**
* parameter passed to `fetch` function
*/
context?: AllowedRequestContext;
/**
* Whether keep null or undefined value in variables.
*
* if `false` given, `{ a: 0, b: undefined, c: null }` will be converted to `{ a: 0 }`
*
* @default true
*/
keepNilVariables?: boolean;
};
export type QueryOptions<Q extends GraphQLQuery> = RequestOptions<Q> & {
query: Q;
};
export type MutationOptions<M extends GraphQLQuery> = RequestOptions<M> & {
mutation: M;
};
function filterEmptyValue(vars: any) {
const newVars: Record<string, any> = {};
Object.entries(vars).forEach(([key, value]) => {
if (isNil(value)) {
return;
}
if (isObject(value) && !(value instanceof File)) {
newVars[key] = filterEmptyValue(value);
return;
}
newVars[key] = value;
});
return newVars;
}
export function transformToForm(body: RequestBody) {
const form = new FormData();
const gqlBody: {
name?: string;
query: string;
variables: any;
map: any;
} = {
query: body.query,
variables: body.variables,
map: {},
};
if (body.operationName) {
gqlBody.name = body.operationName;
}
const map: Record<string, [string]> = {};
const files: File[] = [];
if (body.variables) {
let i = 0;
Object.entries(body.variables).forEach(([key, value]) => {
if (value instanceof File) {
map['0'] = [`variables.${key}`];
files[i] = value;
i++;
}
});
}
form.set('operations', JSON.stringify(gqlBody));
form.set('map', JSON.stringify(map));
for (const [i, file] of files.entries()) {
form.set(`${i}`, file);
}
return form;
}
function formatRequestBody<Q extends GraphQLQuery>({
query,
variables,
keepNilVariables,
}: QueryOptions<Q>): RequestBody | FormData {
const body: RequestBody = {
query: query.query,
variables:
keepNilVariables ?? true ? variables : filterEmptyValue(variables),
};
if (query.operationName) {
body.operationName = query.operationName;
}
if (query.containsFile) {
return transformToForm(body);
}
return body;
}
export const gqlFetcherFactory = (endpoint: string) => {
const gqlFetch = async <Query extends GraphQLQuery>(
options: QueryOptions<Query>
): Promise<QueryResponse<Query>> => {
const body = formatRequestBody(options);
const isFormData = body instanceof FormData;
const headers: Record<string, string> = {
'x-operation-name': options.query.operationName,
'x-definition-name': options.query.definitionName,
};
if (!isFormData) {
headers['content-type'] = 'application/json';
}
const ret = fetchWithTraceReport(
endpoint,
merge(options.context, {
method: 'POST',
headers,
body: isFormData ? body : JSON.stringify(body),
}),
{ event: 'GraphQLRequest' }
).then(async res => {
if (res.headers.get('content-type')?.startsWith('application/json')) {
const result = (await res.json()) as ExecutionResult;
if (res.status >= 400 || result.errors) {
if (result.errors && result.errors.length > 0) {
throw result.errors.map(
error => new GraphQLError(error.message, error)
);
} else {
throw new GraphQLError('Empty GraphQL error body');
}
} else if (result.data) {
// we have to cast here because the type of result.data is a union type
return result.data as any;
}
}
throw new GraphQLError('GraphQL query responds unexpected result');
});
return ret;
};
return gqlFetch;
};
export const fetchWithTraceReport = async (
input: RequestInfo | URL,
init?: RequestInit & { priority?: 'auto' | 'low' | 'high' }, // https://github.com/microsoft/TypeScript/issues/54472
traceOptions?: { event: string }
): Promise<Response> => {
const startTime = new Date().toISOString();
const spanId = generateRandUTF16Chars(SPAN_ID_BYTES);
const traceId = generateRandUTF16Chars(TRACE_ID_BYTES);
const traceparent = `${TRACE_VERSION}-${traceId}-${spanId}-${TRACE_FLAG}`;
init = init || {};
init.headers = init.headers || new Headers();
const requestId = nanoid();
const event = traceOptions?.event;
if (init.headers instanceof Headers) {
init.headers.append('x-request-id', requestId);
init.headers.append('traceparent', traceparent);
} else {
const headers = init.headers as Record<string, string>;
headers['x-request-id'] = requestId;
headers['traceparent'] = traceparent;
}
if (!traceReporter) {
return fetch(input, init);
}
try {
const response = await fetch(input, init);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
traceReporter!.cacheTrace(traceId, spanId, startTime, {
requestId,
...(event ? { event } : {}),
});
return response;
} catch (err) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
traceReporter!.uploadTrace(traceId, spanId, startTime, {
requestId,
...(event ? { event } : {}),
});
return await Promise.reject(err);
}
};

View File

@@ -0,0 +1,5 @@
query checkBlobSizes($workspaceId: String!, $size: Float!) {
checkBlobSize(workspaceId: $workspaceId, size: $size) {
size
}
}

View File

@@ -0,0 +1,3 @@
mutation deleteBlob($workspaceId: String!, $hash: String!) {
deleteBlob(workspaceId: $workspaceId, hash: $hash)
}

View File

@@ -0,0 +1,3 @@
query listBlobs($workspaceId: String!) {
listBlobs(workspaceId: $workspaceId)
}

View File

@@ -0,0 +1,3 @@
mutation setBlob($workspaceId: String!, $blob: Upload!) {
setBlob(workspaceId: $workspaceId, blob: $blob)
}

View File

@@ -0,0 +1,5 @@
query blobSizes($workspaceId: String!) {
collectBlobSizes(workspaceId: $workspaceId) {
size
}
}

View File

@@ -0,0 +1,5 @@
query allBlobSizes {
collectAllBlobSizes {
size
}
}

View File

@@ -0,0 +1,8 @@
mutation changeEmail($token: String!) {
changeEmail(token: $token) {
id
name
avatarUrl
email
}
}

View File

@@ -0,0 +1,8 @@
mutation changePassword($token: String!, $newPassword: String!) {
changePassword(token: $token, newPassword: $newPassword) {
id
name
avatarUrl
email
}
}

View File

@@ -0,0 +1,7 @@
mutation createWorkspace($init: Upload!) {
createWorkspace(init: $init) {
id
public
createdAt
}
}

View File

@@ -0,0 +1,5 @@
mutation deleteAccount {
deleteAccount {
success
}
}

View File

@@ -0,0 +1,3 @@
mutation deleteWorkspace($id: String!) {
deleteWorkspace(id: $id)
}

View File

@@ -0,0 +1,13 @@
query getCurrentUser {
currentUser {
id
name
email
emailVerified
avatarUrl
createdAt
token {
sessionToken
}
}
}

View File

@@ -0,0 +1,14 @@
query getInviteInfo($inviteId: String!) {
getInviteInfo(inviteId: $inviteId) {
workspace {
id
name
avatar
}
user {
id
name
avatarUrl
}
}
}

View File

@@ -0,0 +1,3 @@
query getIsOwner($workspaceId: String!) {
isOwner(workspaceId: $workspaceId)
}

View File

@@ -0,0 +1,5 @@
query getMemberCountByWorkspaceId($workspaceId: String!) {
workspace(id: $workspaceId) {
memberCount
}
}

View File

@@ -0,0 +1,14 @@
query getMembersByWorkspaceId($workspaceId: String!, $skip: Int!, $take: Int!) {
workspace(id: $workspaceId) {
members(skip: $skip, take: $take) {
id
name
email
avatarUrl
permission
inviteId
accepted
emailVerified
}
}
}

View File

@@ -0,0 +1,5 @@
query getPublicWorkspace($id: String!) {
publicWorkspace(id: $id) {
id
}
}

View File

@@ -0,0 +1,9 @@
query getUser($email: String!) {
user(email: $email) {
id
name
avatarUrl
email
hasPassword
}
}

View File

@@ -0,0 +1,5 @@
query getWorkspacePublicById($id: String!) {
workspace(id: $id) {
public
}
}

View File

@@ -0,0 +1,5 @@
query getWorkspaceSharedPages($workspaceId: String!) {
workspace(id: $workspaceId) {
sharedPages
}
}

View File

@@ -0,0 +1,5 @@
query getWorkspace($id: String!) {
workspace(id: $id) {
id
}
}

View File

@@ -0,0 +1,5 @@
query getWorkspaces {
workspaces {
id
}
}

View File

@@ -0,0 +1,528 @@
/* do not manipulate this file manually. */
export interface GraphQLQuery {
id: string;
operationName: string;
definitionName: string;
query: string;
containsFile?: boolean;
}
export const checkBlobSizesQuery = {
id: 'checkBlobSizesQuery' as const,
operationName: 'checkBlobSizes',
definitionName: 'checkBlobSize',
containsFile: false,
query: `
query checkBlobSizes($workspaceId: String!, $size: Float!) {
checkBlobSize(workspaceId: $workspaceId, size: $size) {
size
}
}`,
};
export const deleteBlobMutation = {
id: 'deleteBlobMutation' as const,
operationName: 'deleteBlob',
definitionName: 'deleteBlob',
containsFile: false,
query: `
mutation deleteBlob($workspaceId: String!, $hash: String!) {
deleteBlob(workspaceId: $workspaceId, hash: $hash)
}`,
};
export const listBlobsQuery = {
id: 'listBlobsQuery' as const,
operationName: 'listBlobs',
definitionName: 'listBlobs',
containsFile: false,
query: `
query listBlobs($workspaceId: String!) {
listBlobs(workspaceId: $workspaceId)
}`,
};
export const setBlobMutation = {
id: 'setBlobMutation' as const,
operationName: 'setBlob',
definitionName: 'setBlob',
containsFile: true,
query: `
mutation setBlob($workspaceId: String!, $blob: Upload!) {
setBlob(workspaceId: $workspaceId, blob: $blob)
}`,
};
export const blobSizesQuery = {
id: 'blobSizesQuery' as const,
operationName: 'blobSizes',
definitionName: 'collectBlobSizes',
containsFile: false,
query: `
query blobSizes($workspaceId: String!) {
collectBlobSizes(workspaceId: $workspaceId) {
size
}
}`,
};
export const allBlobSizesQuery = {
id: 'allBlobSizesQuery' as const,
operationName: 'allBlobSizes',
definitionName: 'collectAllBlobSizes',
containsFile: false,
query: `
query allBlobSizes {
collectAllBlobSizes {
size
}
}`,
};
export const changeEmailMutation = {
id: 'changeEmailMutation' as const,
operationName: 'changeEmail',
definitionName: 'changeEmail',
containsFile: false,
query: `
mutation changeEmail($token: String!) {
changeEmail(token: $token) {
id
name
avatarUrl
email
}
}`,
};
export const changePasswordMutation = {
id: 'changePasswordMutation' as const,
operationName: 'changePassword',
definitionName: 'changePassword',
containsFile: false,
query: `
mutation changePassword($token: String!, $newPassword: String!) {
changePassword(token: $token, newPassword: $newPassword) {
id
name
avatarUrl
email
}
}`,
};
export const createWorkspaceMutation = {
id: 'createWorkspaceMutation' as const,
operationName: 'createWorkspace',
definitionName: 'createWorkspace',
containsFile: true,
query: `
mutation createWorkspace($init: Upload!) {
createWorkspace(init: $init) {
id
public
createdAt
}
}`,
};
export const deleteAccountMutation = {
id: 'deleteAccountMutation' as const,
operationName: 'deleteAccount',
definitionName: 'deleteAccount',
containsFile: false,
query: `
mutation deleteAccount {
deleteAccount {
success
}
}`,
};
export const deleteWorkspaceMutation = {
id: 'deleteWorkspaceMutation' as const,
operationName: 'deleteWorkspace',
definitionName: 'deleteWorkspace',
containsFile: false,
query: `
mutation deleteWorkspace($id: String!) {
deleteWorkspace(id: $id)
}`,
};
export const getCurrentUserQuery = {
id: 'getCurrentUserQuery' as const,
operationName: 'getCurrentUser',
definitionName: 'currentUser',
containsFile: false,
query: `
query getCurrentUser {
currentUser {
id
name
email
emailVerified
avatarUrl
createdAt
token {
sessionToken
}
}
}`,
};
export const getInviteInfoQuery = {
id: 'getInviteInfoQuery' as const,
operationName: 'getInviteInfo',
definitionName: 'getInviteInfo',
containsFile: false,
query: `
query getInviteInfo($inviteId: String!) {
getInviteInfo(inviteId: $inviteId) {
workspace {
id
name
avatar
}
user {
id
name
avatarUrl
}
}
}`,
};
export const getIsOwnerQuery = {
id: 'getIsOwnerQuery' as const,
operationName: 'getIsOwner',
definitionName: 'isOwner',
containsFile: false,
query: `
query getIsOwner($workspaceId: String!) {
isOwner(workspaceId: $workspaceId)
}`,
};
export const getMemberCountByWorkspaceIdQuery = {
id: 'getMemberCountByWorkspaceIdQuery' as const,
operationName: 'getMemberCountByWorkspaceId',
definitionName: 'workspace',
containsFile: false,
query: `
query getMemberCountByWorkspaceId($workspaceId: String!) {
workspace(id: $workspaceId) {
memberCount
}
}`,
};
export const getMembersByWorkspaceIdQuery = {
id: 'getMembersByWorkspaceIdQuery' as const,
operationName: 'getMembersByWorkspaceId',
definitionName: 'workspace',
containsFile: false,
query: `
query getMembersByWorkspaceId($workspaceId: String!, $skip: Int!, $take: Int!) {
workspace(id: $workspaceId) {
members(skip: $skip, take: $take) {
id
name
email
avatarUrl
permission
inviteId
accepted
emailVerified
}
}
}`,
};
export const getPublicWorkspaceQuery = {
id: 'getPublicWorkspaceQuery' as const,
operationName: 'getPublicWorkspace',
definitionName: 'publicWorkspace',
containsFile: false,
query: `
query getPublicWorkspace($id: String!) {
publicWorkspace(id: $id) {
id
}
}`,
};
export const getUserQuery = {
id: 'getUserQuery' as const,
operationName: 'getUser',
definitionName: 'user',
containsFile: false,
query: `
query getUser($email: String!) {
user(email: $email) {
id
name
avatarUrl
email
hasPassword
}
}`,
};
export const getWorkspacePublicByIdQuery = {
id: 'getWorkspacePublicByIdQuery' as const,
operationName: 'getWorkspacePublicById',
definitionName: 'workspace',
containsFile: false,
query: `
query getWorkspacePublicById($id: String!) {
workspace(id: $id) {
public
}
}`,
};
export const getWorkspaceSharedPagesQuery = {
id: 'getWorkspaceSharedPagesQuery' as const,
operationName: 'getWorkspaceSharedPages',
definitionName: 'workspace',
containsFile: false,
query: `
query getWorkspaceSharedPages($workspaceId: String!) {
workspace(id: $workspaceId) {
sharedPages
}
}`,
};
export const getWorkspaceQuery = {
id: 'getWorkspaceQuery' as const,
operationName: 'getWorkspace',
definitionName: 'workspace',
containsFile: false,
query: `
query getWorkspace($id: String!) {
workspace(id: $id) {
id
}
}`,
};
export const getWorkspacesQuery = {
id: 'getWorkspacesQuery' as const,
operationName: 'getWorkspaces',
definitionName: 'workspaces',
containsFile: false,
query: `
query getWorkspaces {
workspaces {
id
}
}`,
};
export const leaveWorkspaceMutation = {
id: 'leaveWorkspaceMutation' as const,
operationName: 'leaveWorkspace',
definitionName: 'leaveWorkspace',
containsFile: false,
query: `
mutation leaveWorkspace($workspaceId: String!, $workspaceName: String!, $sendLeaveMail: Boolean) {
leaveWorkspace(
workspaceId: $workspaceId
workspaceName: $workspaceName
sendLeaveMail: $sendLeaveMail
)
}`,
};
export const removeAvatarMutation = {
id: 'removeAvatarMutation' as const,
operationName: 'removeAvatar',
definitionName: 'removeAvatar',
containsFile: false,
query: `
mutation removeAvatar {
removeAvatar {
success
}
}`,
};
export const revokeMemberPermissionMutation = {
id: 'revokeMemberPermissionMutation' as const,
operationName: 'revokeMemberPermission',
definitionName: 'revoke',
containsFile: false,
query: `
mutation revokeMemberPermission($workspaceId: String!, $userId: String!) {
revoke(workspaceId: $workspaceId, userId: $userId)
}`,
};
export const revokePageMutation = {
id: 'revokePageMutation' as const,
operationName: 'revokePage',
definitionName: 'revokePage',
containsFile: false,
query: `
mutation revokePage($workspaceId: String!, $pageId: String!) {
revokePage(workspaceId: $workspaceId, pageId: $pageId)
}`,
};
export const sendChangeEmailMutation = {
id: 'sendChangeEmailMutation' as const,
operationName: 'sendChangeEmail',
definitionName: 'sendChangeEmail',
containsFile: false,
query: `
mutation sendChangeEmail($email: String!, $callbackUrl: String!) {
sendChangeEmail(email: $email, callbackUrl: $callbackUrl)
}`,
};
export const sendChangePasswordEmailMutation = {
id: 'sendChangePasswordEmailMutation' as const,
operationName: 'sendChangePasswordEmail',
definitionName: 'sendChangePasswordEmail',
containsFile: false,
query: `
mutation sendChangePasswordEmail($email: String!, $callbackUrl: String!) {
sendChangePasswordEmail(email: $email, callbackUrl: $callbackUrl)
}`,
};
export const sendSetPasswordEmailMutation = {
id: 'sendSetPasswordEmailMutation' as const,
operationName: 'sendSetPasswordEmail',
definitionName: 'sendSetPasswordEmail',
containsFile: false,
query: `
mutation sendSetPasswordEmail($email: String!, $callbackUrl: String!) {
sendSetPasswordEmail(email: $email, callbackUrl: $callbackUrl)
}`,
};
export const sendVerifyChangeEmailMutation = {
id: 'sendVerifyChangeEmailMutation' as const,
operationName: 'sendVerifyChangeEmail',
definitionName: 'sendVerifyChangeEmail',
containsFile: false,
query: `
mutation sendVerifyChangeEmail($token: String!, $email: String!, $callbackUrl: String!) {
sendVerifyChangeEmail(token: $token, email: $email, callbackUrl: $callbackUrl)
}`,
};
export const setWorkspacePublicByIdMutation = {
id: 'setWorkspacePublicByIdMutation' as const,
operationName: 'setWorkspacePublicById',
definitionName: 'updateWorkspace',
containsFile: false,
query: `
mutation setWorkspacePublicById($id: ID!, $public: Boolean!) {
updateWorkspace(input: {id: $id, public: $public}) {
id
}
}`,
};
export const sharePageMutation = {
id: 'sharePageMutation' as const,
operationName: 'sharePage',
definitionName: 'sharePage',
containsFile: false,
query: `
mutation sharePage($workspaceId: String!, $pageId: String!) {
sharePage(workspaceId: $workspaceId, pageId: $pageId)
}`,
};
export const signInMutation = {
id: 'signInMutation' as const,
operationName: 'signIn',
definitionName: 'signIn',
containsFile: false,
query: `
mutation signIn($email: String!, $password: String!) {
signIn(email: $email, password: $password) {
token {
token
}
}
}`,
};
export const signUpMutation = {
id: 'signUpMutation' as const,
operationName: 'signUp',
definitionName: 'signUp',
containsFile: false,
query: `
mutation signUp($name: String!, $email: String!, $password: String!) {
signUp(name: $name, email: $email, password: $password) {
token {
token
}
}
}`,
};
export const uploadAvatarMutation = {
id: 'uploadAvatarMutation' as const,
operationName: 'uploadAvatar',
definitionName: 'uploadAvatar',
containsFile: true,
query: `
mutation uploadAvatar($avatar: Upload!) {
uploadAvatar(avatar: $avatar) {
id
name
avatarUrl
email
}
}`,
};
export const inviteByEmailMutation = {
id: 'inviteByEmailMutation' as const,
operationName: 'inviteByEmail',
definitionName: 'invite',
containsFile: false,
query: `
mutation inviteByEmail($workspaceId: String!, $email: String!, $permission: Permission!, $sendInviteMail: Boolean) {
invite(
workspaceId: $workspaceId
email: $email
permission: $permission
sendInviteMail: $sendInviteMail
)
}`,
};
export const acceptInviteByInviteIdMutation = {
id: 'acceptInviteByInviteIdMutation' as const,
operationName: 'acceptInviteByInviteId',
definitionName: 'acceptInviteById',
containsFile: false,
query: `
mutation acceptInviteByInviteId($workspaceId: String!, $inviteId: String!, $sendAcceptMail: Boolean) {
acceptInviteById(
workspaceId: $workspaceId
inviteId: $inviteId
sendAcceptMail: $sendAcceptMail
)
}`,
};
export const acceptInviteByWorkspaceIdMutation = {
id: 'acceptInviteByWorkspaceIdMutation' as const,
operationName: 'acceptInviteByWorkspaceId',
definitionName: 'acceptInvite',
containsFile: false,
query: `
mutation acceptInviteByWorkspaceId($workspaceId: String!) {
acceptInvite(workspaceId: $workspaceId)
}`,
};

View File

@@ -0,0 +1,11 @@
mutation leaveWorkspace(
$workspaceId: String!
$workspaceName: String!
$sendLeaveMail: Boolean
) {
leaveWorkspace(
workspaceId: $workspaceId
workspaceName: $workspaceName
sendLeaveMail: $sendLeaveMail
)
}

View File

@@ -0,0 +1,5 @@
mutation removeAvatar {
removeAvatar {
success
}
}

View File

@@ -0,0 +1,3 @@
mutation revokeMemberPermission($workspaceId: String!, $userId: String!) {
revoke(workspaceId: $workspaceId, userId: $userId)
}

View File

@@ -0,0 +1,3 @@
mutation revokePage($workspaceId: String!, $pageId: String!) {
revokePage(workspaceId: $workspaceId, pageId: $pageId)
}

View File

@@ -0,0 +1,3 @@
mutation sendChangeEmail($email: String!, $callbackUrl: String!) {
sendChangeEmail(email: $email, callbackUrl: $callbackUrl)
}

View File

@@ -0,0 +1,3 @@
mutation sendChangePasswordEmail($email: String!, $callbackUrl: String!) {
sendChangePasswordEmail(email: $email, callbackUrl: $callbackUrl)
}

View File

@@ -0,0 +1,3 @@
mutation sendSetPasswordEmail($email: String!, $callbackUrl: String!) {
sendSetPasswordEmail(email: $email, callbackUrl: $callbackUrl)
}

View File

@@ -0,0 +1,7 @@
mutation sendVerifyChangeEmail(
$token: String!
$email: String!
$callbackUrl: String!
) {
sendVerifyChangeEmail(token: $token, email: $email, callbackUrl: $callbackUrl)
}

View File

@@ -0,0 +1,5 @@
mutation setWorkspacePublicById($id: ID!, $public: Boolean!) {
updateWorkspace(input: { id: $id, public: $public }) {
id
}
}

View File

@@ -0,0 +1,3 @@
mutation sharePage($workspaceId: String!, $pageId: String!) {
sharePage(workspaceId: $workspaceId, pageId: $pageId)
}

View File

@@ -0,0 +1,7 @@
mutation signIn($email: String!, $password: String!) {
signIn(email: $email, password: $password) {
token {
token
}
}
}

View File

@@ -0,0 +1,7 @@
mutation signUp($name: String!, $email: String!, $password: String!) {
signUp(name: $name, email: $email, password: $password) {
token {
token
}
}
}

View File

@@ -0,0 +1,8 @@
mutation uploadAvatar($avatar: Upload!) {
uploadAvatar(avatar: $avatar) {
id
name
avatarUrl
email
}
}

View File

@@ -0,0 +1,13 @@
mutation inviteByEmail(
$workspaceId: String!
$email: String!
$permission: Permission!
$sendInviteMail: Boolean
) {
invite(
workspaceId: $workspaceId
email: $email
permission: $permission
sendInviteMail: $sendInviteMail
)
}

View File

@@ -0,0 +1,11 @@
mutation acceptInviteByInviteId(
$workspaceId: String!
$inviteId: String!
$sendAcceptMail: Boolean
) {
acceptInviteById(
workspaceId: $workspaceId
inviteId: $inviteId
sendAcceptMail: $sendAcceptMail
)
}

View File

@@ -0,0 +1,3 @@
mutation acceptInviteByWorkspaceId($workspaceId: String!) {
acceptInvite(workspaceId: $workspaceId)
}

View File

@@ -0,0 +1,5 @@
export * from './fetcher';
export * from './graphql';
export * from './schema';
export * from './utils';
import '@affine/env/global';

View File

@@ -0,0 +1,659 @@
/* eslint-disable */
export type Maybe<T> = T | null;
export type InputMaybe<T> = T | null;
export type Exact<T extends { [key: string]: unknown }> = {
[K in keyof T]: T[K];
};
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & {
[SubKey in K]?: Maybe<T[SubKey]>;
};
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & {
[SubKey in K]: Maybe<T[SubKey]>;
};
export type MakeEmpty<
T extends { [key: string]: unknown },
K extends keyof T,
> = { [_ in K]?: never };
export type Incremental<T> =
| T
| {
[P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never;
};
/** All built-in and custom scalars, mapped to their actual values */
export interface Scalars {
ID: { input: string; output: string };
String: { input: string; output: string };
Boolean: { input: boolean; output: boolean };
Int: { input: number; output: number };
Float: { input: number; output: number };
/** A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format. */
DateTime: { input: string; output: string };
/** The `Upload` scalar type represents a file upload. */
Upload: { input: File; output: File };
}
export enum NewFeaturesKind {
EarlyAccess = 'EarlyAccess',
}
/** User permission in workspace */
export enum Permission {
Admin = 'Admin',
Owner = 'Owner',
Read = 'Read',
Write = 'Write',
}
export interface UpdateWorkspaceInput {
id: Scalars['ID']['input'];
/** is Public workspace */
public: InputMaybe<Scalars['Boolean']['input']>;
}
export type CheckBlobSizesQueryVariables = Exact<{
workspaceId: Scalars['String']['input'];
size: Scalars['Float']['input'];
}>;
export type CheckBlobSizesQuery = {
__typename?: 'Query';
checkBlobSize: { __typename?: 'WorkspaceBlobSizes'; size: number };
};
export type DeleteBlobMutationVariables = Exact<{
workspaceId: Scalars['String']['input'];
hash: Scalars['String']['input'];
}>;
export type DeleteBlobMutation = {
__typename?: 'Mutation';
deleteBlob: boolean;
};
export type ListBlobsQueryVariables = Exact<{
workspaceId: Scalars['String']['input'];
}>;
export type ListBlobsQuery = { __typename?: 'Query'; listBlobs: Array<string> };
export type SetBlobMutationVariables = Exact<{
workspaceId: Scalars['String']['input'];
blob: Scalars['Upload']['input'];
}>;
export type SetBlobMutation = { __typename?: 'Mutation'; setBlob: string };
export type BlobSizesQueryVariables = Exact<{
workspaceId: Scalars['String']['input'];
}>;
export type BlobSizesQuery = {
__typename?: 'Query';
collectBlobSizes: { __typename?: 'WorkspaceBlobSizes'; size: number };
};
export type AllBlobSizesQueryVariables = Exact<{ [key: string]: never }>;
export type AllBlobSizesQuery = {
__typename?: 'Query';
collectAllBlobSizes: { __typename?: 'WorkspaceBlobSizes'; size: number };
};
export type ChangeEmailMutationVariables = Exact<{
token: Scalars['String']['input'];
}>;
export type ChangeEmailMutation = {
__typename?: 'Mutation';
changeEmail: {
__typename?: 'UserType';
id: string;
name: string;
avatarUrl: string | null;
email: string;
};
};
export type ChangePasswordMutationVariables = Exact<{
token: Scalars['String']['input'];
newPassword: Scalars['String']['input'];
}>;
export type ChangePasswordMutation = {
__typename?: 'Mutation';
changePassword: {
__typename?: 'UserType';
id: string;
name: string;
avatarUrl: string | null;
email: string;
};
};
export type CreateWorkspaceMutationVariables = Exact<{
init: Scalars['Upload']['input'];
}>;
export type CreateWorkspaceMutation = {
__typename?: 'Mutation';
createWorkspace: {
__typename?: 'WorkspaceType';
id: string;
public: boolean;
createdAt: string;
};
};
export type DeleteAccountMutationVariables = Exact<{ [key: string]: never }>;
export type DeleteAccountMutation = {
__typename?: 'Mutation';
deleteAccount: { __typename?: 'DeleteAccount'; success: boolean };
};
export type DeleteWorkspaceMutationVariables = Exact<{
id: Scalars['String']['input'];
}>;
export type DeleteWorkspaceMutation = {
__typename?: 'Mutation';
deleteWorkspace: boolean;
};
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never }>;
export type GetCurrentUserQuery = {
__typename?: 'Query';
currentUser: {
__typename?: 'UserType';
id: string;
name: string;
email: string;
emailVerified: string | null;
avatarUrl: string | null;
createdAt: string | null;
token: { __typename?: 'TokenType'; sessionToken: string | null };
};
};
export type GetInviteInfoQueryVariables = Exact<{
inviteId: Scalars['String']['input'];
}>;
export type GetInviteInfoQuery = {
__typename?: 'Query';
getInviteInfo: {
__typename?: 'InvitationType';
workspace: {
__typename?: 'InvitationWorkspaceType';
id: string;
name: string;
avatar: string;
};
user: {
__typename?: 'UserType';
id: string;
name: string;
avatarUrl: string | null;
};
};
};
export type GetIsOwnerQueryVariables = Exact<{
workspaceId: Scalars['String']['input'];
}>;
export type GetIsOwnerQuery = { __typename?: 'Query'; isOwner: boolean };
export type GetMemberCountByWorkspaceIdQueryVariables = Exact<{
workspaceId: Scalars['String']['input'];
}>;
export type GetMemberCountByWorkspaceIdQuery = {
__typename?: 'Query';
workspace: { __typename?: 'WorkspaceType'; memberCount: number };
};
export type GetMembersByWorkspaceIdQueryVariables = Exact<{
workspaceId: Scalars['String']['input'];
skip: Scalars['Int']['input'];
take: Scalars['Int']['input'];
}>;
export type GetMembersByWorkspaceIdQuery = {
__typename?: 'Query';
workspace: {
__typename?: 'WorkspaceType';
members: Array<{
__typename?: 'InviteUserType';
id: string;
name: string | null;
email: string | null;
avatarUrl: string | null;
permission: Permission;
inviteId: string;
accepted: boolean;
emailVerified: string | null;
}>;
};
};
export type GetPublicWorkspaceQueryVariables = Exact<{
id: Scalars['String']['input'];
}>;
export type GetPublicWorkspaceQuery = {
__typename?: 'Query';
publicWorkspace: { __typename?: 'WorkspaceType'; id: string };
};
export type GetUserQueryVariables = Exact<{
email: Scalars['String']['input'];
}>;
export type GetUserQuery = {
__typename?: 'Query';
user: {
__typename?: 'UserType';
id: string;
name: string;
avatarUrl: string | null;
email: string;
hasPassword: boolean | null;
} | null;
};
export type GetWorkspacePublicByIdQueryVariables = Exact<{
id: Scalars['String']['input'];
}>;
export type GetWorkspacePublicByIdQuery = {
__typename?: 'Query';
workspace: { __typename?: 'WorkspaceType'; public: boolean };
};
export type GetWorkspaceSharedPagesQueryVariables = Exact<{
workspaceId: Scalars['String']['input'];
}>;
export type GetWorkspaceSharedPagesQuery = {
__typename?: 'Query';
workspace: { __typename?: 'WorkspaceType'; sharedPages: Array<string> };
};
export type GetWorkspaceQueryVariables = Exact<{
id: Scalars['String']['input'];
}>;
export type GetWorkspaceQuery = {
__typename?: 'Query';
workspace: { __typename?: 'WorkspaceType'; id: string };
};
export type GetWorkspacesQueryVariables = Exact<{ [key: string]: never }>;
export type GetWorkspacesQuery = {
__typename?: 'Query';
workspaces: Array<{ __typename?: 'WorkspaceType'; id: string }>;
};
export type LeaveWorkspaceMutationVariables = Exact<{
workspaceId: Scalars['String']['input'];
workspaceName: Scalars['String']['input'];
sendLeaveMail: InputMaybe<Scalars['Boolean']['input']>;
}>;
export type LeaveWorkspaceMutation = {
__typename?: 'Mutation';
leaveWorkspace: boolean;
};
export type RemoveAvatarMutationVariables = Exact<{ [key: string]: never }>;
export type RemoveAvatarMutation = {
__typename?: 'Mutation';
removeAvatar: { __typename?: 'RemoveAvatar'; success: boolean };
};
export type RevokeMemberPermissionMutationVariables = Exact<{
workspaceId: Scalars['String']['input'];
userId: Scalars['String']['input'];
}>;
export type RevokeMemberPermissionMutation = {
__typename?: 'Mutation';
revoke: boolean;
};
export type RevokePageMutationVariables = Exact<{
workspaceId: Scalars['String']['input'];
pageId: Scalars['String']['input'];
}>;
export type RevokePageMutation = {
__typename?: 'Mutation';
revokePage: boolean;
};
export type SendChangeEmailMutationVariables = Exact<{
email: Scalars['String']['input'];
callbackUrl: Scalars['String']['input'];
}>;
export type SendChangeEmailMutation = {
__typename?: 'Mutation';
sendChangeEmail: boolean;
};
export type SendChangePasswordEmailMutationVariables = Exact<{
email: Scalars['String']['input'];
callbackUrl: Scalars['String']['input'];
}>;
export type SendChangePasswordEmailMutation = {
__typename?: 'Mutation';
sendChangePasswordEmail: boolean;
};
export type SendSetPasswordEmailMutationVariables = Exact<{
email: Scalars['String']['input'];
callbackUrl: Scalars['String']['input'];
}>;
export type SendSetPasswordEmailMutation = {
__typename?: 'Mutation';
sendSetPasswordEmail: boolean;
};
export type SendVerifyChangeEmailMutationVariables = Exact<{
token: Scalars['String']['input'];
email: Scalars['String']['input'];
callbackUrl: Scalars['String']['input'];
}>;
export type SendVerifyChangeEmailMutation = {
__typename?: 'Mutation';
sendVerifyChangeEmail: boolean;
};
export type SetWorkspacePublicByIdMutationVariables = Exact<{
id: Scalars['ID']['input'];
public: Scalars['Boolean']['input'];
}>;
export type SetWorkspacePublicByIdMutation = {
__typename?: 'Mutation';
updateWorkspace: { __typename?: 'WorkspaceType'; id: string };
};
export type SharePageMutationVariables = Exact<{
workspaceId: Scalars['String']['input'];
pageId: Scalars['String']['input'];
}>;
export type SharePageMutation = { __typename?: 'Mutation'; sharePage: boolean };
export type SignInMutationVariables = Exact<{
email: Scalars['String']['input'];
password: Scalars['String']['input'];
}>;
export type SignInMutation = {
__typename?: 'Mutation';
signIn: {
__typename?: 'UserType';
token: { __typename?: 'TokenType'; token: string };
};
};
export type SignUpMutationVariables = Exact<{
name: Scalars['String']['input'];
email: Scalars['String']['input'];
password: Scalars['String']['input'];
}>;
export type SignUpMutation = {
__typename?: 'Mutation';
signUp: {
__typename?: 'UserType';
token: { __typename?: 'TokenType'; token: string };
};
};
export type UploadAvatarMutationVariables = Exact<{
avatar: Scalars['Upload']['input'];
}>;
export type UploadAvatarMutation = {
__typename?: 'Mutation';
uploadAvatar: {
__typename?: 'UserType';
id: string;
name: string;
avatarUrl: string | null;
email: string;
};
};
export type InviteByEmailMutationVariables = Exact<{
workspaceId: Scalars['String']['input'];
email: Scalars['String']['input'];
permission: Permission;
sendInviteMail: InputMaybe<Scalars['Boolean']['input']>;
}>;
export type InviteByEmailMutation = { __typename?: 'Mutation'; invite: string };
export type AcceptInviteByInviteIdMutationVariables = Exact<{
workspaceId: Scalars['String']['input'];
inviteId: Scalars['String']['input'];
sendAcceptMail: InputMaybe<Scalars['Boolean']['input']>;
}>;
export type AcceptInviteByInviteIdMutation = {
__typename?: 'Mutation';
acceptInviteById: boolean;
};
export type AcceptInviteByWorkspaceIdMutationVariables = Exact<{
workspaceId: Scalars['String']['input'];
}>;
export type AcceptInviteByWorkspaceIdMutation = {
__typename?: 'Mutation';
acceptInvite: boolean;
};
export type Queries =
| {
name: 'checkBlobSizesQuery';
variables: CheckBlobSizesQueryVariables;
response: CheckBlobSizesQuery;
}
| {
name: 'listBlobsQuery';
variables: ListBlobsQueryVariables;
response: ListBlobsQuery;
}
| {
name: 'blobSizesQuery';
variables: BlobSizesQueryVariables;
response: BlobSizesQuery;
}
| {
name: 'allBlobSizesQuery';
variables: AllBlobSizesQueryVariables;
response: AllBlobSizesQuery;
}
| {
name: 'getCurrentUserQuery';
variables: GetCurrentUserQueryVariables;
response: GetCurrentUserQuery;
}
| {
name: 'getInviteInfoQuery';
variables: GetInviteInfoQueryVariables;
response: GetInviteInfoQuery;
}
| {
name: 'getIsOwnerQuery';
variables: GetIsOwnerQueryVariables;
response: GetIsOwnerQuery;
}
| {
name: 'getMemberCountByWorkspaceIdQuery';
variables: GetMemberCountByWorkspaceIdQueryVariables;
response: GetMemberCountByWorkspaceIdQuery;
}
| {
name: 'getMembersByWorkspaceIdQuery';
variables: GetMembersByWorkspaceIdQueryVariables;
response: GetMembersByWorkspaceIdQuery;
}
| {
name: 'getPublicWorkspaceQuery';
variables: GetPublicWorkspaceQueryVariables;
response: GetPublicWorkspaceQuery;
}
| {
name: 'getUserQuery';
variables: GetUserQueryVariables;
response: GetUserQuery;
}
| {
name: 'getWorkspacePublicByIdQuery';
variables: GetWorkspacePublicByIdQueryVariables;
response: GetWorkspacePublicByIdQuery;
}
| {
name: 'getWorkspaceSharedPagesQuery';
variables: GetWorkspaceSharedPagesQueryVariables;
response: GetWorkspaceSharedPagesQuery;
}
| {
name: 'getWorkspaceQuery';
variables: GetWorkspaceQueryVariables;
response: GetWorkspaceQuery;
}
| {
name: 'getWorkspacesQuery';
variables: GetWorkspacesQueryVariables;
response: GetWorkspacesQuery;
};
export type Mutations =
| {
name: 'deleteBlobMutation';
variables: DeleteBlobMutationVariables;
response: DeleteBlobMutation;
}
| {
name: 'setBlobMutation';
variables: SetBlobMutationVariables;
response: SetBlobMutation;
}
| {
name: 'changeEmailMutation';
variables: ChangeEmailMutationVariables;
response: ChangeEmailMutation;
}
| {
name: 'changePasswordMutation';
variables: ChangePasswordMutationVariables;
response: ChangePasswordMutation;
}
| {
name: 'createWorkspaceMutation';
variables: CreateWorkspaceMutationVariables;
response: CreateWorkspaceMutation;
}
| {
name: 'deleteAccountMutation';
variables: DeleteAccountMutationVariables;
response: DeleteAccountMutation;
}
| {
name: 'deleteWorkspaceMutation';
variables: DeleteWorkspaceMutationVariables;
response: DeleteWorkspaceMutation;
}
| {
name: 'leaveWorkspaceMutation';
variables: LeaveWorkspaceMutationVariables;
response: LeaveWorkspaceMutation;
}
| {
name: 'removeAvatarMutation';
variables: RemoveAvatarMutationVariables;
response: RemoveAvatarMutation;
}
| {
name: 'revokeMemberPermissionMutation';
variables: RevokeMemberPermissionMutationVariables;
response: RevokeMemberPermissionMutation;
}
| {
name: 'revokePageMutation';
variables: RevokePageMutationVariables;
response: RevokePageMutation;
}
| {
name: 'sendChangeEmailMutation';
variables: SendChangeEmailMutationVariables;
response: SendChangeEmailMutation;
}
| {
name: 'sendChangePasswordEmailMutation';
variables: SendChangePasswordEmailMutationVariables;
response: SendChangePasswordEmailMutation;
}
| {
name: 'sendSetPasswordEmailMutation';
variables: SendSetPasswordEmailMutationVariables;
response: SendSetPasswordEmailMutation;
}
| {
name: 'sendVerifyChangeEmailMutation';
variables: SendVerifyChangeEmailMutationVariables;
response: SendVerifyChangeEmailMutation;
}
| {
name: 'setWorkspacePublicByIdMutation';
variables: SetWorkspacePublicByIdMutationVariables;
response: SetWorkspacePublicByIdMutation;
}
| {
name: 'sharePageMutation';
variables: SharePageMutationVariables;
response: SharePageMutation;
}
| {
name: 'signInMutation';
variables: SignInMutationVariables;
response: SignInMutation;
}
| {
name: 'signUpMutation';
variables: SignUpMutationVariables;
response: SignUpMutation;
}
| {
name: 'uploadAvatarMutation';
variables: UploadAvatarMutationVariables;
response: UploadAvatarMutation;
}
| {
name: 'inviteByEmailMutation';
variables: InviteByEmailMutationVariables;
response: InviteByEmailMutation;
}
| {
name: 'acceptInviteByInviteIdMutation';
variables: AcceptInviteByInviteIdMutationVariables;
response: AcceptInviteByInviteIdMutation;
}
| {
name: 'acceptInviteByWorkspaceIdMutation';
variables: AcceptInviteByWorkspaceIdMutationVariables;
response: AcceptInviteByWorkspaceIdMutation;
};

View File

@@ -0,0 +1,209 @@
export const SPAN_ID_BYTES = 8;
export const TRACE_ID_BYTES = 16;
export const TRACE_VERSION = '00';
export const TRACE_FLAG = '01';
const BytesBuffer = Array(32);
type TraceSpan = {
name: string;
spanId: string;
displayName: {
value: string;
truncatedByteCount: number;
};
startTime: string;
endTime: string;
attributes: {
attributeMap: {
requestId?: {
stringValue: {
value: string;
truncatedByteCount: number;
};
};
event?: {
stringValue: {
value: string;
truncatedByteCount: 0;
};
};
};
droppedAttributesCount: number;
};
};
/**
* inspired by open-telemetry/opentelemetry-js
*/
export function generateRandUTF16Chars(bytes: number) {
for (let i = 0; i < bytes * 2; i++) {
BytesBuffer[i] = Math.floor(Math.random() * 16) + 48;
// valid hex characters in the range 48-57 and 97-102
if (BytesBuffer[i] >= 58) {
BytesBuffer[i] += 39;
}
}
return String.fromCharCode(...BytesBuffer.slice(0, bytes * 2));
}
export class TraceReporter {
static traceReportEndpoint = process.env.TRACE_REPORT_ENDPOINT;
static shouldReportTrace = process.env.SHOULD_REPORT_TRACE;
private spansCache = new Array<TraceSpan>();
private reportIntervalId: number | undefined | NodeJS.Timeout;
private reportInterval = 60_000;
private static instance: TraceReporter;
public static getInstance(): TraceReporter {
if (!TraceReporter.instance) {
const instance = (TraceReporter.instance = new TraceReporter());
instance.initTraceReport();
}
return TraceReporter.instance;
}
public cacheTrace(
traceId: string,
spanId: string,
startTime: string,
attributes: {
requestId?: string;
event?: string;
}
) {
const span = TraceReporter.createTraceSpan(
traceId,
spanId,
startTime,
attributes
);
this.spansCache.push(span);
if (this.spansCache.length <= 1) {
this.initTraceReport();
}
}
public uploadTrace(
traceId: string,
spanId: string,
startTime: string,
attributes: {
requestId?: string;
event?: string;
}
) {
const span = TraceReporter.createTraceSpan(
traceId,
spanId,
startTime,
attributes
);
TraceReporter.reportToTraceEndpoint(JSON.stringify({ spans: [span] }));
}
public static reportToTraceEndpoint(payload: string): void {
if (!TraceReporter.traceReportEndpoint) {
console.warn('No trace report endpoint found!');
return;
}
if (typeof navigator !== 'undefined') {
navigator.sendBeacon(TraceReporter.traceReportEndpoint, payload);
} else {
fetch(TraceReporter.traceReportEndpoint, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json',
},
body: payload,
}).catch(console.warn);
}
}
public static createTraceSpan(
traceId: string,
spanId: string,
startTime: string,
attributes: {
requestId?: string;
event?: string;
}
): TraceSpan {
const requestId = attributes.requestId;
const event = attributes.event;
return {
name: `projects/{GCP_PROJECT_ID}/traces/${traceId}/spans/${spanId}`,
spanId,
displayName: {
value: 'AFFiNE_REQUEST',
truncatedByteCount: 0,
},
startTime,
endTime: new Date().toISOString(),
attributes: {
attributeMap: {
...(!requestId
? {}
: {
requestId: {
stringValue: {
value: requestId,
truncatedByteCount: 0,
},
},
}),
...(!event
? {}
: {
event: {
stringValue: {
value: event,
truncatedByteCount: 0,
},
},
}),
},
droppedAttributesCount: 0,
},
};
}
private initTraceReport = () => {
if (!this.reportIntervalId && TraceReporter.shouldReportTrace) {
if (typeof window !== 'undefined') {
this.reportIntervalId = window.setInterval(
this.reportHandler,
this.reportInterval
);
} else {
this.reportIntervalId = setInterval(
this.reportHandler,
this.reportInterval
);
}
}
};
private reportHandler = () => {
if (this.spansCache.length <= 0) {
clearInterval(this.reportIntervalId);
this.reportIntervalId = undefined;
return;
}
TraceReporter.reportToTraceEndpoint(
JSON.stringify({ spans: [...this.spansCache] })
);
this.spansCache = [];
};
}
export const traceReporter = process.env.SHOULD_REPORT_TRACE
? TraceReporter.getInstance()
: null;

View File

@@ -0,0 +1,14 @@
{
"extends": "../../../tsconfig.json",
"include": ["./src"],
"compilerOptions": {
"composite": true,
"noEmit": false,
"outDir": "lib"
},
"references": [
{
"path": "../../common/env"
}
]
}