refactor(server): use ava (#4120)
This commit is contained in:
@@ -11,11 +11,8 @@
|
|||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"start": "node --loader ts-node/esm.mjs --es-module-specifier-resolution node ./src/index.ts",
|
"start": "node --loader ts-node/esm.mjs --es-module-specifier-resolution node ./src/index.ts",
|
||||||
"dev": "nodemon ./src/index.ts",
|
"dev": "nodemon ./src/index.ts",
|
||||||
"test": "yarn exec ts-node-esm ./scripts/run-test.ts all",
|
"test": "ava --concurrency 1 --serial",
|
||||||
"test:select": "yarn exec ts-node-esm ./scripts/run-test.ts",
|
"test:coverage": "c8 ava --concurrency 1 --serial",
|
||||||
"test:watch": "yarn exec ts-node-esm ./scripts/run-test.ts all --watch",
|
|
||||||
"test:select:watch": "yarn exec ts-node-esm ./scripts/run-test.ts --watch",
|
|
||||||
"test:coverage": "c8 yarn exec ts-node-esm ./scripts/run-test.ts all",
|
|
||||||
"postinstall": "prisma generate"
|
"postinstall": "prisma generate"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -90,6 +87,7 @@
|
|||||||
"@types/sinon": "^10.0.16",
|
"@types/sinon": "^10.0.16",
|
||||||
"@types/supertest": "^2.0.12",
|
"@types/supertest": "^2.0.12",
|
||||||
"@types/ws": "^8.5.5",
|
"@types/ws": "^8.5.5",
|
||||||
|
"ava": "^5.3.1",
|
||||||
"c8": "^8.0.1",
|
"c8": "^8.0.1",
|
||||||
"nodemon": "^3.0.1",
|
"nodemon": "^3.0.1",
|
||||||
"sinon": "^15.2.0",
|
"sinon": "^15.2.0",
|
||||||
@@ -97,6 +95,27 @@
|
|||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^5.2.2"
|
"typescript": "^5.2.2"
|
||||||
},
|
},
|
||||||
|
"ava": {
|
||||||
|
"extensions": {
|
||||||
|
"ts": "module"
|
||||||
|
},
|
||||||
|
"nodeArguments": [
|
||||||
|
"--loader",
|
||||||
|
"ts-node/esm.mjs",
|
||||||
|
"--es-module-specifier-resolution",
|
||||||
|
"node"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"src/**/*.spec.ts"
|
||||||
|
],
|
||||||
|
"require": [
|
||||||
|
"./src/prelude.ts"
|
||||||
|
],
|
||||||
|
"environmentVariables": {
|
||||||
|
"TS_NODE_PROJECT": "./tsconfig.json",
|
||||||
|
"NODE_ENV": "test"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nodemonConfig": {
|
"nodemonConfig": {
|
||||||
"exec": "node",
|
"exec": "node",
|
||||||
"script": "./src/index.ts",
|
"script": "./src/index.ts",
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
#!/usr/bin/env ts-node-esm
|
|
||||||
import { resolve } from 'node:path';
|
|
||||||
|
|
||||||
import * as p from '@clack/prompts';
|
|
||||||
import { spawn, spawnSync } from 'child_process';
|
|
||||||
import { readdir } from 'fs/promises';
|
|
||||||
import * as process from 'process';
|
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
|
|
||||||
import pkg from '../package.json' assert { type: 'json' };
|
|
||||||
|
|
||||||
const root = fileURLToPath(new URL('..', import.meta.url));
|
|
||||||
const testDir = resolve(root, 'src', 'tests');
|
|
||||||
const files = await readdir(testDir);
|
|
||||||
|
|
||||||
const watchMode = process.argv.includes('--watch');
|
|
||||||
|
|
||||||
const sharedArgs = [
|
|
||||||
...pkg.nodemonConfig.nodeArgs,
|
|
||||||
'--test',
|
|
||||||
watchMode ? '--watch' : '',
|
|
||||||
];
|
|
||||||
|
|
||||||
const env = {
|
|
||||||
PATH: process.env.PATH,
|
|
||||||
NODE_ENV: 'test',
|
|
||||||
DATABASE_URL: process.env.DATABASE_URL,
|
|
||||||
NODE_NO_WARNINGS: '1',
|
|
||||||
};
|
|
||||||
|
|
||||||
if (process.argv[2] === 'all') {
|
|
||||||
files.forEach(file => {
|
|
||||||
const path = resolve(testDir, file);
|
|
||||||
spawnSync('node', [...sharedArgs, path], {
|
|
||||||
cwd: root,
|
|
||||||
env,
|
|
||||||
stdio: 'inherit',
|
|
||||||
shell: true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const result = await p.group({
|
|
||||||
file: () =>
|
|
||||||
p.select({
|
|
||||||
message: 'Select a file to run',
|
|
||||||
options: files.map(file => ({
|
|
||||||
label: file,
|
|
||||||
value: file as any,
|
|
||||||
})),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const target = resolve(testDir, result.file);
|
|
||||||
|
|
||||||
const cp = spawn(
|
|
||||||
'node',
|
|
||||||
[
|
|
||||||
...sharedArgs,
|
|
||||||
'--test-reporter=spec',
|
|
||||||
'--test-reporter-destination=stdout',
|
|
||||||
target,
|
|
||||||
],
|
|
||||||
{
|
|
||||||
cwd: root,
|
|
||||||
env,
|
|
||||||
stdio: 'inherit',
|
|
||||||
shell: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
cp.on('exit', code => {
|
|
||||||
process.exit(code ?? 0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,7 @@ import { Module } from '@nestjs/common';
|
|||||||
import { AppController } from './app.controller';
|
import { AppController } from './app.controller';
|
||||||
import { ConfigModule } from './config';
|
import { ConfigModule } from './config';
|
||||||
import { MetricsModule } from './metrics';
|
import { MetricsModule } from './metrics';
|
||||||
import { BusinessModules, Providers } from './modules';
|
import { BusinessModules } from './modules';
|
||||||
import { PrismaModule } from './prisma';
|
import { PrismaModule } from './prisma';
|
||||||
import { SessionModule } from './session';
|
import { SessionModule } from './session';
|
||||||
import { StorageModule } from './storage';
|
import { StorageModule } from './storage';
|
||||||
@@ -19,7 +19,6 @@ import { RateLimiterModule } from './throttler';
|
|||||||
RateLimiterModule,
|
RateLimiterModule,
|
||||||
...BusinessModules,
|
...BusinessModules,
|
||||||
],
|
],
|
||||||
providers: Providers,
|
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
|||||||
|
|
||||||
import { AppModule } from './app';
|
import { AppModule } from './app';
|
||||||
import { Config } from './config';
|
import { Config } from './config';
|
||||||
|
import { ExceptionLogger } from './middleware/exception-logger';
|
||||||
import { serverTimingAndCache } from './middleware/timing';
|
import { serverTimingAndCache } from './middleware/timing';
|
||||||
import { RedisIoAdapter } from './modules/sync/redis-adapter';
|
import { RedisIoAdapter } from './modules/sync/redis-adapter';
|
||||||
|
|
||||||
@@ -75,6 +76,7 @@ app.use(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.useGlobalFilters(new ExceptionLogger());
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
|
|
||||||
const config = app.get(Config);
|
const config = app.get(Config);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Global, Module } from '@nestjs/common';
|
import { Global, Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { SessionService } from '../../session';
|
||||||
import { MAILER, MailService } from './mailer';
|
import { MAILER, MailService } from './mailer';
|
||||||
import { NextAuthController } from './next-auth.controller';
|
import { NextAuthController } from './next-auth.controller';
|
||||||
import { NextAuthOptionsProvider } from './next-auth-options';
|
import { NextAuthOptionsProvider } from './next-auth-options';
|
||||||
@@ -10,6 +11,7 @@ import { AuthService } from './service';
|
|||||||
@Module({
|
@Module({
|
||||||
providers: [
|
providers: [
|
||||||
AuthService,
|
AuthService,
|
||||||
|
SessionService,
|
||||||
AuthResolver,
|
AuthResolver,
|
||||||
NextAuthOptionsProvider,
|
NextAuthOptionsProvider,
|
||||||
MAILER,
|
MAILER,
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export class TokenType {
|
|||||||
export class AuthResolver {
|
export class AuthResolver {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly config: Config,
|
private readonly config: Config,
|
||||||
private auth: AuthService,
|
private readonly auth: AuthService,
|
||||||
private readonly session: SessionService
|
private readonly session: SessionService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { DynamicModule, Provider, Type } from '@nestjs/common';
|
import { DynamicModule, Type } from '@nestjs/common';
|
||||||
import { APP_FILTER } from '@nestjs/core';
|
|
||||||
|
|
||||||
import { GqlModule } from '../graphql.module';
|
import { GqlModule } from '../graphql.module';
|
||||||
import { ExceptionLogger } from '../middleware/exception-logger';
|
|
||||||
import { AuthModule } from './auth';
|
import { AuthModule } from './auth';
|
||||||
import { DocModule } from './doc';
|
import { DocModule } from './doc';
|
||||||
import { SyncModule } from './sync';
|
import { SyncModule } from './sync';
|
||||||
@@ -39,11 +37,4 @@ switch (SERVER_FLAVOR) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Providers: Provider[] = [
|
export { BusinessModules };
|
||||||
{
|
|
||||||
provide: APP_FILTER,
|
|
||||||
useClass: ExceptionLogger,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export { BusinessModules, Providers };
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { equal, ok } from 'node:assert';
|
import { equal, ok } from 'node:assert';
|
||||||
import { afterEach, beforeEach, describe, test } from 'node:test';
|
|
||||||
|
|
||||||
import { Transformer } from '@napi-rs/image';
|
import { Transformer } from '@napi-rs/image';
|
||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { Test } from '@nestjs/testing';
|
import { Test } from '@nestjs/testing';
|
||||||
import { hash } from '@node-rs/argon2';
|
import { hash } from '@node-rs/argon2';
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import test from 'ava';
|
||||||
import { Express } from 'express';
|
import { Express } from 'express';
|
||||||
// @ts-expect-error graphql-upload is not typed
|
// @ts-expect-error graphql-upload is not typed
|
||||||
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
||||||
@@ -15,83 +15,82 @@ import { AppModule } from '../app';
|
|||||||
|
|
||||||
const gql = '/graphql';
|
const gql = '/graphql';
|
||||||
|
|
||||||
describe('AppModule', async () => {
|
let app: INestApplication;
|
||||||
let app: INestApplication;
|
|
||||||
|
|
||||||
// cleanup database before each test
|
// cleanup database before each test
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
const client = new PrismaClient();
|
const client = new PrismaClient();
|
||||||
await client.$connect();
|
await client.$connect();
|
||||||
await client.user.deleteMany({});
|
await client.user.deleteMany({});
|
||||||
await client.user.create({
|
await client.user.create({
|
||||||
data: {
|
data: {
|
||||||
name: 'Alex Yang',
|
name: 'Alex Yang',
|
||||||
email: 'alex.yang@example.org',
|
email: 'alex.yang@example.org',
|
||||||
password: await hash('123456'),
|
password: await hash('123456'),
|
||||||
},
|
},
|
||||||
});
|
|
||||||
await client.$disconnect();
|
|
||||||
});
|
});
|
||||||
|
await client.$disconnect();
|
||||||
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
const module = await Test.createTestingModule({
|
const module = await Test.createTestingModule({
|
||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
}).compile();
|
}).compile();
|
||||||
app = module.createNestApplication({
|
app = module.createNestApplication({
|
||||||
cors: true,
|
cors: true,
|
||||||
bodyParser: true,
|
bodyParser: true,
|
||||||
});
|
|
||||||
app.use(
|
|
||||||
graphqlUploadExpress({
|
|
||||||
maxFileSize: 10 * 1024 * 1024,
|
|
||||||
maxFiles: 5,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
await app.init();
|
|
||||||
});
|
});
|
||||||
|
app.use(
|
||||||
|
graphqlUploadExpress({
|
||||||
|
maxFileSize: 10 * 1024 * 1024,
|
||||||
|
maxFiles: 5,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
await app.init();
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
test.afterEach(async () => {
|
||||||
await app.close();
|
await app.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
await test('should init app', async () => {
|
test('should init app', async () => {
|
||||||
ok(typeof app === 'object');
|
ok(typeof app === 'object');
|
||||||
await request(app.getHttpServer())
|
await request(app.getHttpServer())
|
||||||
.post(gql)
|
.post(gql)
|
||||||
.send({
|
.send({
|
||||||
query: `
|
query: `
|
||||||
query {
|
query {
|
||||||
error
|
error
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
.expect(400);
|
.expect(400);
|
||||||
|
|
||||||
const { token } = await createToken(app);
|
const { token } = await createToken(app);
|
||||||
|
|
||||||
await request(app.getHttpServer())
|
await request(app.getHttpServer())
|
||||||
.post(gql)
|
.post(gql)
|
||||||
.auth(token, { type: 'bearer' })
|
.auth(token, { type: 'bearer' })
|
||||||
.send({
|
.send({
|
||||||
query: `
|
query: `
|
||||||
query {
|
query {
|
||||||
__typename
|
__typename
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect(res => {
|
.expect(res => {
|
||||||
ok(res.body.data.__typename === 'Query');
|
ok(res.body.data.__typename === 'Query');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await test('should find default user', async () => {
|
test('should find default user', async () => {
|
||||||
const { token } = await createToken(app);
|
const { token } = await createToken(app);
|
||||||
await request(app.getHttpServer())
|
await request(app.getHttpServer())
|
||||||
.post(gql)
|
.post(gql)
|
||||||
.auth(token, { type: 'bearer' })
|
.auth(token, { type: 'bearer' })
|
||||||
.send({
|
.send({
|
||||||
query: `
|
query: `
|
||||||
query {
|
query {
|
||||||
user(email: "alex.yang@example.org") {
|
user(email: "alex.yang@example.org") {
|
||||||
email
|
email
|
||||||
@@ -99,29 +98,29 @@ describe('AppModule', async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect(res => {
|
.expect(res => {
|
||||||
equal(res.body.data.user.email, 'alex.yang@example.org');
|
equal(res.body.data.user.email, 'alex.yang@example.org');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await test('should be able to upload avatar', async () => {
|
test('should be able to upload avatar', async () => {
|
||||||
const { token, id } = await createToken(app);
|
const { token, id } = await createToken(app);
|
||||||
const png = await Transformer.fromRgbaPixels(
|
const png = await Transformer.fromRgbaPixels(
|
||||||
Buffer.alloc(400 * 400 * 4).fill(255),
|
Buffer.alloc(400 * 400 * 4).fill(255),
|
||||||
400,
|
400,
|
||||||
400
|
400
|
||||||
).png();
|
).png();
|
||||||
|
|
||||||
await request(app.getHttpServer())
|
await request(app.getHttpServer())
|
||||||
.post(gql)
|
.post(gql)
|
||||||
.auth(token, { type: 'bearer' })
|
.auth(token, { type: 'bearer' })
|
||||||
.field(
|
.field(
|
||||||
'operations',
|
'operations',
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
name: 'uploadAvatar',
|
name: 'uploadAvatar',
|
||||||
query: `mutation uploadAvatar($id: String!, $avatar: Upload!) {
|
query: `mutation uploadAvatar($id: String!, $avatar: Upload!) {
|
||||||
uploadAvatar(id: $id, avatar: $avatar) {
|
uploadAvatar(id: $id, avatar: $avatar) {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
@@ -130,17 +129,15 @@ describe('AppModule', async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
variables: { id, avatar: null },
|
variables: { id, avatar: null },
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
.field('map', JSON.stringify({ '0': ['variables.avatar'] }))
|
||||||
.field('map', JSON.stringify({ '0': ['variables.avatar'] }))
|
.attach('0', png, 'avatar.png')
|
||||||
.attach('0', png, 'avatar.png')
|
.expect(200)
|
||||||
.expect(200)
|
.expect(res => {
|
||||||
.expect(res => {
|
equal(res.body.data.uploadAvatar.id, id);
|
||||||
equal(res.body.data.uploadAvatar.id, id);
|
});
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
async function createToken(app: INestApplication<Express>): Promise<{
|
async function createToken(app: INestApplication<Express>): Promise<{
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/// <reference types="../global.d.ts" />
|
/// <reference types="../global.d.ts" />
|
||||||
import { equal } from 'node:assert';
|
import { equal } from 'node:assert';
|
||||||
import { afterEach, beforeEach, test } from 'node:test';
|
|
||||||
|
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import test from 'ava';
|
||||||
|
|
||||||
import { ConfigModule } from '../config';
|
import { ConfigModule } from '../config';
|
||||||
import { GqlModule } from '../graphql.module';
|
import { GqlModule } from '../graphql.module';
|
||||||
@@ -17,13 +17,13 @@ let auth: AuthService;
|
|||||||
let module: TestingModule;
|
let module: TestingModule;
|
||||||
|
|
||||||
// cleanup database before each test
|
// cleanup database before each test
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
const client = new PrismaClient();
|
const client = new PrismaClient();
|
||||||
await client.$connect();
|
await client.$connect();
|
||||||
await client.user.deleteMany({});
|
await client.user.deleteMany({});
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
module = await Test.createTestingModule({
|
module = await Test.createTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
@@ -43,16 +43,17 @@ beforeEach(async () => {
|
|||||||
auth = module.get(AuthService);
|
auth = module.get(AuthService);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
test.afterEach(async () => {
|
||||||
await module.close();
|
await module.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to register and signIn', async () => {
|
test('should be able to register and signIn', async t => {
|
||||||
await auth.signUp('Alex Yang', 'alexyang@example.org', '123456');
|
await auth.signUp('Alex Yang', 'alexyang@example.org', '123456');
|
||||||
await auth.signIn('alexyang@example.org', '123456');
|
await auth.signIn('alexyang@example.org', '123456');
|
||||||
|
t.pass();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to verify', async () => {
|
test('should be able to verify', async t => {
|
||||||
await auth.signUp('Alex Yang', 'alexyang@example.org', '123456');
|
await auth.signUp('Alex Yang', 'alexyang@example.org', '123456');
|
||||||
await auth.signIn('alexyang@example.org', '123456');
|
await auth.signIn('alexyang@example.org', '123456');
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
@@ -83,4 +84,5 @@ test('should be able to verify', async () => {
|
|||||||
equal(claim.emailVerified?.toISOString(), date.toISOString());
|
equal(claim.emailVerified?.toISOString(), date.toISOString());
|
||||||
equal(claim.createdAt.toISOString(), date.toISOString());
|
equal(claim.createdAt.toISOString(), date.toISOString());
|
||||||
}
|
}
|
||||||
|
t.pass();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
import { equal, ok } from 'node:assert';
|
import { ok } from 'node:assert';
|
||||||
import { beforeEach, test } from 'node:test';
|
|
||||||
|
|
||||||
import { Test } from '@nestjs/testing';
|
import { Test } from '@nestjs/testing';
|
||||||
|
import test from 'ava';
|
||||||
|
|
||||||
import { Config, ConfigModule } from '../config';
|
import { Config, ConfigModule } from '../config';
|
||||||
|
|
||||||
let config: Config;
|
let config: Config;
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
const module = await Test.createTestingModule({
|
const module = await Test.createTestingModule({
|
||||||
imports: [ConfigModule.forRoot()],
|
imports: [ConfigModule.forRoot()],
|
||||||
}).compile();
|
}).compile();
|
||||||
config = module.get(Config);
|
config = module.get(Config);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to get config', () => {
|
test('should be able to get config', t => {
|
||||||
ok(typeof config.host === 'string');
|
t.true(typeof config.host === 'string');
|
||||||
equal(config.env, 'test');
|
t.is(config.env, 'test');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to override config', async () => {
|
test('should be able to override config', async t => {
|
||||||
const module = await Test.createTestingModule({
|
const module = await Test.createTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
@@ -29,4 +29,5 @@ test('should be able to override config', async () => {
|
|||||||
const config = module.get(Config);
|
const config = module.get(Config);
|
||||||
|
|
||||||
ok(config.host, 'testing');
|
ok(config.host, 'testing');
|
||||||
|
t.pass();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { deepEqual, equal, ok } from 'node:assert';
|
import { deepEqual, equal, ok } from 'node:assert';
|
||||||
import { afterEach, beforeEach, mock, test } from 'node:test';
|
import { mock } from 'node:test';
|
||||||
|
|
||||||
import { INestApplication } from '@nestjs/common';
|
import { INestApplication } from '@nestjs/common';
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import test from 'ava';
|
||||||
import { register } from 'prom-client';
|
import { register } from 'prom-client';
|
||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
import { Doc as YDoc, encodeStateAsUpdate } from 'yjs';
|
import { Doc as YDoc, encodeStateAsUpdate } from 'yjs';
|
||||||
@@ -24,135 +25,137 @@ const createModule = () => {
|
|||||||
}).compile();
|
}).compile();
|
||||||
};
|
};
|
||||||
|
|
||||||
test('Doc Module', async t => {
|
let app: INestApplication;
|
||||||
let app: INestApplication;
|
let m: TestingModule;
|
||||||
let m: TestingModule;
|
let timer: Sinon.SinonFakeTimers;
|
||||||
let timer: Sinon.SinonFakeTimers;
|
|
||||||
|
|
||||||
// cleanup database before each test
|
// cleanup database before each test
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
timer = Sinon.useFakeTimers({
|
timer = Sinon.useFakeTimers({
|
||||||
toFake: ['setInterval'],
|
toFake: ['setInterval'],
|
||||||
});
|
|
||||||
await flushDB();
|
|
||||||
m = await createModule();
|
|
||||||
app = m.createNestApplication();
|
|
||||||
app.enableShutdownHooks();
|
|
||||||
await app.init();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await app.close();
|
|
||||||
timer.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
await t.test('should setup update poll interval', async () => {
|
|
||||||
register.clear();
|
|
||||||
const m = await createModule();
|
|
||||||
const manager = m.get(DocManager);
|
|
||||||
const fake = mock.method(manager, 'setup');
|
|
||||||
|
|
||||||
await m.createNestApplication().init();
|
|
||||||
|
|
||||||
equal(fake.mock.callCount(), 1);
|
|
||||||
// @ts-expect-error private member
|
|
||||||
ok(manager.job);
|
|
||||||
});
|
|
||||||
|
|
||||||
await t.test('should be able to stop poll', async () => {
|
|
||||||
const manager = m.get(DocManager);
|
|
||||||
const fake = mock.method(manager, 'destroy');
|
|
||||||
|
|
||||||
await app.close();
|
|
||||||
|
|
||||||
equal(fake.mock.callCount(), 1);
|
|
||||||
// @ts-expect-error private member
|
|
||||||
equal(manager.job, null);
|
|
||||||
});
|
|
||||||
|
|
||||||
await t.test('should poll when intervel due', async () => {
|
|
||||||
const manager = m.get(DocManager);
|
|
||||||
const interval = m.get(Config).doc.manager.updatePollInterval;
|
|
||||||
|
|
||||||
let resolve: any;
|
|
||||||
const fake = mock.method(manager, 'apply', () => {
|
|
||||||
return new Promise(_resolve => {
|
|
||||||
resolve = _resolve;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
timer.tick(interval);
|
|
||||||
equal(fake.mock.callCount(), 1);
|
|
||||||
|
|
||||||
// busy
|
|
||||||
timer.tick(interval);
|
|
||||||
// @ts-expect-error private member
|
|
||||||
equal(manager.busy, true);
|
|
||||||
equal(fake.mock.callCount(), 1);
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
await timer.tickAsync(1);
|
|
||||||
|
|
||||||
// @ts-expect-error private member
|
|
||||||
equal(manager.busy, false);
|
|
||||||
timer.tick(interval);
|
|
||||||
equal(fake.mock.callCount(), 2);
|
|
||||||
});
|
|
||||||
|
|
||||||
await t.test('should merge update when intervel due', async () => {
|
|
||||||
const db = m.get(PrismaService);
|
|
||||||
const manager = m.get(DocManager);
|
|
||||||
|
|
||||||
const doc = new YDoc();
|
|
||||||
const text = doc.getText('content');
|
|
||||||
text.insert(0, 'hello');
|
|
||||||
const update = encodeStateAsUpdate(doc);
|
|
||||||
|
|
||||||
const ws = await db.workspace.create({
|
|
||||||
data: {
|
|
||||||
id: '1',
|
|
||||||
public: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await db.update.createMany({
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
workspaceId: '1',
|
|
||||||
blob: Buffer.from([0, 0]),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
workspaceId: '1',
|
|
||||||
blob: Buffer.from(update),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
await manager.apply();
|
|
||||||
|
|
||||||
deepEqual(await manager.getLatestUpdate(ws.id, '1'), update);
|
|
||||||
|
|
||||||
let appendUpdate = Buffer.from([]);
|
|
||||||
doc.on('update', update => {
|
|
||||||
appendUpdate = Buffer.from(update);
|
|
||||||
});
|
|
||||||
text.insert(5, 'world');
|
|
||||||
|
|
||||||
await db.update.create({
|
|
||||||
data: {
|
|
||||||
workspaceId: ws.id,
|
|
||||||
id: '1',
|
|
||||||
blob: appendUpdate,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await manager.apply();
|
|
||||||
|
|
||||||
deepEqual(
|
|
||||||
await manager.getLatestUpdate(ws.id, '1'),
|
|
||||||
encodeStateAsUpdate(doc)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
await flushDB();
|
||||||
|
m = await createModule();
|
||||||
|
app = m.createNestApplication();
|
||||||
|
app.enableShutdownHooks();
|
||||||
|
await app.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterEach(async () => {
|
||||||
|
await app.close();
|
||||||
|
timer.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should setup update poll interval', async t => {
|
||||||
|
register.clear();
|
||||||
|
const m = await createModule();
|
||||||
|
const manager = m.get(DocManager);
|
||||||
|
const fake = mock.method(manager, 'setup');
|
||||||
|
|
||||||
|
await m.createNestApplication().init();
|
||||||
|
|
||||||
|
equal(fake.mock.callCount(), 1);
|
||||||
|
// @ts-expect-error private member
|
||||||
|
ok(manager.job);
|
||||||
|
t.pass();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should be able to stop poll', async t => {
|
||||||
|
const manager = m.get(DocManager);
|
||||||
|
const fake = mock.method(manager, 'destroy');
|
||||||
|
|
||||||
|
await app.close();
|
||||||
|
|
||||||
|
equal(fake.mock.callCount(), 1);
|
||||||
|
// @ts-expect-error private member
|
||||||
|
equal(manager.job, null);
|
||||||
|
t.pass();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should poll when intervel due', async t => {
|
||||||
|
const manager = m.get(DocManager);
|
||||||
|
const interval = m.get(Config).doc.manager.updatePollInterval;
|
||||||
|
|
||||||
|
let resolve: any;
|
||||||
|
const fake = mock.method(manager, 'apply', () => {
|
||||||
|
return new Promise(_resolve => {
|
||||||
|
resolve = _resolve;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
timer.tick(interval);
|
||||||
|
equal(fake.mock.callCount(), 1);
|
||||||
|
|
||||||
|
// busy
|
||||||
|
timer.tick(interval);
|
||||||
|
// @ts-expect-error private member
|
||||||
|
equal(manager.busy, true);
|
||||||
|
equal(fake.mock.callCount(), 1);
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
await timer.tickAsync(1);
|
||||||
|
|
||||||
|
// @ts-expect-error private member
|
||||||
|
equal(manager.busy, false);
|
||||||
|
timer.tick(interval);
|
||||||
|
equal(fake.mock.callCount(), 2);
|
||||||
|
t.pass();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should merge update when intervel due', async t => {
|
||||||
|
const db = m.get(PrismaService);
|
||||||
|
const manager = m.get(DocManager);
|
||||||
|
|
||||||
|
const doc = new YDoc();
|
||||||
|
const text = doc.getText('content');
|
||||||
|
text.insert(0, 'hello');
|
||||||
|
const update = encodeStateAsUpdate(doc);
|
||||||
|
|
||||||
|
const ws = await db.workspace.create({
|
||||||
|
data: {
|
||||||
|
id: '1',
|
||||||
|
public: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.update.createMany({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
workspaceId: '1',
|
||||||
|
blob: Buffer.from([0, 0]),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
workspaceId: '1',
|
||||||
|
blob: Buffer.from(update),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await manager.apply();
|
||||||
|
|
||||||
|
deepEqual(await manager.getLatestUpdate(ws.id, '1'), update);
|
||||||
|
|
||||||
|
let appendUpdate = Buffer.from([]);
|
||||||
|
doc.on('update', update => {
|
||||||
|
appendUpdate = Buffer.from(update);
|
||||||
|
});
|
||||||
|
text.insert(5, 'world');
|
||||||
|
|
||||||
|
await db.update.create({
|
||||||
|
data: {
|
||||||
|
workspaceId: ws.id,
|
||||||
|
id: '1',
|
||||||
|
blob: appendUpdate,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await manager.apply();
|
||||||
|
|
||||||
|
deepEqual(
|
||||||
|
await manager.getLatestUpdate(ws.id, '1'),
|
||||||
|
encodeStateAsUpdate(doc)
|
||||||
|
);
|
||||||
|
t.pass();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { ok } from 'node:assert';
|
import { ok } from 'node:assert';
|
||||||
import { afterEach, beforeEach, describe, it } from 'node:test';
|
|
||||||
|
|
||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { Test } from '@nestjs/testing';
|
import { Test } from '@nestjs/testing';
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import test from 'ava';
|
||||||
// @ts-expect-error graphql-upload is not typed
|
// @ts-expect-error graphql-upload is not typed
|
||||||
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
||||||
|
|
||||||
@@ -11,76 +11,75 @@ import { AppModule } from '../app';
|
|||||||
import { MailService } from '../modules/auth/mailer';
|
import { MailService } from '../modules/auth/mailer';
|
||||||
import { createWorkspace, getInviteInfo, inviteUser, signUp } from './utils';
|
import { createWorkspace, getInviteInfo, inviteUser, signUp } from './utils';
|
||||||
|
|
||||||
describe('Mail Module', () => {
|
let app: INestApplication;
|
||||||
let app: INestApplication;
|
|
||||||
|
|
||||||
const client = new PrismaClient();
|
const client = new PrismaClient();
|
||||||
|
|
||||||
let mail: MailService;
|
let mail: MailService;
|
||||||
|
|
||||||
// cleanup database before each test
|
// cleanup database before each test
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
await client.$connect();
|
await client.$connect();
|
||||||
await client.user.deleteMany({});
|
await client.user.deleteMany({});
|
||||||
await client.snapshot.deleteMany({});
|
await client.snapshot.deleteMany({});
|
||||||
await client.update.deleteMany({});
|
await client.update.deleteMany({});
|
||||||
await client.workspace.deleteMany({});
|
await client.workspace.deleteMany({});
|
||||||
await client.$disconnect();
|
await client.$disconnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
const module = await Test.createTestingModule({
|
const module = await Test.createTestingModule({
|
||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
}).compile();
|
}).compile();
|
||||||
app = module.createNestApplication();
|
app = module.createNestApplication();
|
||||||
app.use(
|
app.use(
|
||||||
graphqlUploadExpress({
|
graphqlUploadExpress({
|
||||||
maxFileSize: 10 * 1024 * 1024,
|
maxFileSize: 10 * 1024 * 1024,
|
||||||
maxFiles: 5,
|
maxFiles: 5,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
await app.init();
|
await app.init();
|
||||||
|
|
||||||
mail = module.get(MailService);
|
mail = module.get(MailService);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
test.afterEach(async () => {
|
||||||
await app.close();
|
await app.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should send invite email', async () => {
|
test('should send invite email', async t => {
|
||||||
if (mail.hasConfigured()) {
|
if (mail.hasConfigured()) {
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
||||||
|
|
||||||
const workspace = await createWorkspace(app, u1.token.token);
|
const workspace = await createWorkspace(app, u1.token.token);
|
||||||
const inviteId = await inviteUser(
|
const inviteId = await inviteUser(
|
||||||
app,
|
app,
|
||||||
u1.token.token,
|
u1.token.token,
|
||||||
workspace.id,
|
workspace.id,
|
||||||
u2.email,
|
u2.email,
|
||||||
'Admin'
|
'Admin'
|
||||||
);
|
);
|
||||||
|
|
||||||
const inviteInfo = await getInviteInfo(app, u1.token.token, inviteId);
|
const inviteInfo = await getInviteInfo(app, u1.token.token, inviteId);
|
||||||
|
|
||||||
const resp = await mail.sendInviteEmail(
|
const resp = await mail.sendInviteEmail(
|
||||||
'production@toeverything.info',
|
'production@toeverything.info',
|
||||||
inviteId,
|
inviteId,
|
||||||
{
|
{
|
||||||
workspace: {
|
workspace: {
|
||||||
id: inviteInfo.workspace.id,
|
id: inviteInfo.workspace.id,
|
||||||
name: inviteInfo.workspace.name,
|
name: inviteInfo.workspace.name,
|
||||||
avatar: '',
|
avatar: '',
|
||||||
},
|
},
|
||||||
user: {
|
user: {
|
||||||
avatar: inviteInfo.user?.avatarUrl || '',
|
avatar: inviteInfo.user?.avatarUrl || '',
|
||||||
name: inviteInfo.user?.name || '',
|
name: inviteInfo.user?.name || '',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
ok(resp.accepted.length === 1, 'failed to send invite email');
|
ok(resp.accepted.length === 1, 'failed to send invite email');
|
||||||
}
|
}
|
||||||
});
|
t.pass();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ok } from 'node:assert';
|
import { ok } from 'node:assert';
|
||||||
import { afterEach, beforeEach, test } from 'node:test';
|
|
||||||
|
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import test from 'ava';
|
||||||
import { register } from 'prom-client';
|
import { register } from 'prom-client';
|
||||||
|
|
||||||
import { MetricsModule } from '../metrics';
|
import { MetricsModule } from '../metrics';
|
||||||
@@ -11,7 +11,7 @@ import { PrismaModule } from '../prisma';
|
|||||||
let metrics: Metrics;
|
let metrics: Metrics;
|
||||||
let module: TestingModule;
|
let module: TestingModule;
|
||||||
|
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
module = await Test.createTestingModule({
|
module = await Test.createTestingModule({
|
||||||
imports: [MetricsModule, PrismaModule],
|
imports: [MetricsModule, PrismaModule],
|
||||||
}).compile();
|
}).compile();
|
||||||
@@ -19,11 +19,11 @@ beforeEach(async () => {
|
|||||||
metrics = module.get(Metrics);
|
metrics = module.get(Metrics);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
test.afterEach(async () => {
|
||||||
await module.close();
|
await module.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to increment counter', async () => {
|
test('should be able to increment counter', async t => {
|
||||||
metrics.socketIOEventCounter(1, { event: 'client-handshake' });
|
metrics.socketIOEventCounter(1, { event: 'client-handshake' });
|
||||||
const socketIOCounterMetric =
|
const socketIOCounterMetric =
|
||||||
await register.getSingleMetric('socket_io_counter');
|
await register.getSingleMetric('socket_io_counter');
|
||||||
@@ -33,9 +33,10 @@ test('should be able to increment counter', async () => {
|
|||||||
JSON.stringify((await socketIOCounterMetric.get()).values) ===
|
JSON.stringify((await socketIOCounterMetric.get()).values) ===
|
||||||
'[{"value":1,"labels":{"event":"client-handshake"}}]'
|
'[{"value":1,"labels":{"event":"client-handshake"}}]'
|
||||||
);
|
);
|
||||||
|
t.pass();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to timer', async () => {
|
test('should be able to timer', async t => {
|
||||||
let minimum: number;
|
let minimum: number;
|
||||||
{
|
{
|
||||||
const endTimer = metrics.socketIOEventTimer({ event: 'client-handshake' });
|
const endTimer = metrics.socketIOEventTimer({ event: 'client-handshake' });
|
||||||
@@ -76,4 +77,5 @@ test('should be able to timer', async () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
t.pass();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/// <reference types="../global.d.ts" />
|
/// <reference types="../global.d.ts" />
|
||||||
import { equal } from 'node:assert';
|
import { equal } from 'node:assert';
|
||||||
import { afterEach, beforeEach, test } from 'node:test';
|
|
||||||
|
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import test from 'ava';
|
||||||
|
|
||||||
import { ConfigModule } from '../config';
|
import { ConfigModule } from '../config';
|
||||||
import { SessionModule, SessionService } from '../session';
|
import { SessionModule, SessionService } from '../session';
|
||||||
@@ -12,31 +12,33 @@ let session: SessionService;
|
|||||||
let module: TestingModule;
|
let module: TestingModule;
|
||||||
|
|
||||||
// cleanup database before each test
|
// cleanup database before each test
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
const client = new PrismaClient();
|
const client = new PrismaClient();
|
||||||
await client.$connect();
|
await client.$connect();
|
||||||
await client.user.deleteMany({});
|
await client.user.deleteMany({});
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
module = await Test.createTestingModule({
|
module = await Test.createTestingModule({
|
||||||
imports: [ConfigModule.forRoot(), SessionModule],
|
imports: [ConfigModule.forRoot(), SessionModule],
|
||||||
}).compile();
|
}).compile();
|
||||||
session = module.get(SessionService);
|
session = module.get(SessionService);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
test.afterEach(async () => {
|
||||||
await module.close();
|
await module.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to set session', async () => {
|
test('should be able to set session', async t => {
|
||||||
await session.set('test', 'value');
|
await session.set('test', 'value');
|
||||||
equal(await session.get('test'), 'value');
|
equal(await session.get('test'), 'value');
|
||||||
|
t.pass();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be expired by ttl', async () => {
|
test('should be expired by ttl', async t => {
|
||||||
await session.set('test', 'value', 100);
|
await session.set('test', 'value', 100);
|
||||||
equal(await session.get('test'), 'value');
|
equal(await session.get('test'), 'value');
|
||||||
await new Promise(resolve => setTimeout(resolve, 500));
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
equal(await session.get('test'), undefined);
|
equal(await session.get('test'), undefined);
|
||||||
|
t.pass();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { ok, rejects } from 'node:assert';
|
import { ok, rejects } from 'node:assert';
|
||||||
import { afterEach, beforeEach, describe, it } from 'node:test';
|
|
||||||
|
|
||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { Test } from '@nestjs/testing';
|
import { Test } from '@nestjs/testing';
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import test from 'ava';
|
||||||
// @ts-expect-error graphql-upload is not typed
|
// @ts-expect-error graphql-upload is not typed
|
||||||
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
@@ -11,66 +11,67 @@ import request from 'supertest';
|
|||||||
import { AppModule } from '../app';
|
import { AppModule } from '../app';
|
||||||
import { currentUser, signUp } from './utils';
|
import { currentUser, signUp } from './utils';
|
||||||
|
|
||||||
describe('User Module', () => {
|
let app: INestApplication;
|
||||||
let app: INestApplication;
|
|
||||||
|
|
||||||
// cleanup database before each test
|
// cleanup database before each test
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
const client = new PrismaClient();
|
const client = new PrismaClient();
|
||||||
await client.$connect();
|
await client.$connect();
|
||||||
await client.user.deleteMany({});
|
await client.user.deleteMany({});
|
||||||
await client.$disconnect();
|
await client.$disconnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
const module = await Test.createTestingModule({
|
const module = await Test.createTestingModule({
|
||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
}).compile();
|
}).compile();
|
||||||
app = module.createNestApplication();
|
app = module.createNestApplication();
|
||||||
app.use(
|
app.use(
|
||||||
graphqlUploadExpress({
|
graphqlUploadExpress({
|
||||||
maxFileSize: 10 * 1024 * 1024,
|
maxFileSize: 10 * 1024 * 1024,
|
||||||
maxFiles: 5,
|
maxFiles: 5,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
await app.init();
|
await app.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
test.afterEach(async () => {
|
||||||
await app.close();
|
await app.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should register a user', async () => {
|
test('should register a user', async t => {
|
||||||
const user = await signUp(app, 'u1', 'u1@affine.pro', '123456');
|
const user = await signUp(app, 'u1', 'u1@affine.pro', '123456');
|
||||||
ok(typeof user.id === 'string', 'user.id is not a string');
|
ok(typeof user.id === 'string', 'user.id is not a string');
|
||||||
ok(user.name === 'u1', 'user.name is not valid');
|
ok(user.name === 'u1', 'user.name is not valid');
|
||||||
ok(user.email === 'u1@affine.pro', 'user.email is not valid');
|
ok(user.email === 'u1@affine.pro', 'user.email is not valid');
|
||||||
});
|
t.pass();
|
||||||
|
});
|
||||||
|
|
||||||
it('should get current user', async () => {
|
test('should get current user', async t => {
|
||||||
const user = await signUp(app, 'u1', 'u1@affine.pro', '123456');
|
const user = await signUp(app, 'u1', 'u1@affine.pro', '123456');
|
||||||
const currUser = await currentUser(app, user.token.token);
|
const currUser = await currentUser(app, user.token.token);
|
||||||
ok(currUser.id === user.id, 'user.id is not valid');
|
ok(currUser.id === user.id, 'user.id is not valid');
|
||||||
ok(currUser.name === user.name, 'user.name is not valid');
|
ok(currUser.name === user.name, 'user.name is not valid');
|
||||||
ok(currUser.email === user.email, 'user.email is not valid');
|
ok(currUser.email === user.email, 'user.email is not valid');
|
||||||
ok(currUser.hasPassword, 'currUser.hasPassword is not valid');
|
ok(currUser.hasPassword, 'currUser.hasPassword is not valid');
|
||||||
});
|
t.pass();
|
||||||
|
});
|
||||||
|
|
||||||
it('should be able to delete user', async () => {
|
test('should be able to delete user', async t => {
|
||||||
const user = await signUp(app, 'u1', 'u1@affine.pro', '123456');
|
const user = await signUp(app, 'u1', 'u1@affine.pro', '123456');
|
||||||
await request(app.getHttpServer())
|
await request(app.getHttpServer())
|
||||||
.post('/graphql')
|
.post('/graphql')
|
||||||
.auth(user.token.token, { type: 'bearer' })
|
.auth(user.token.token, { type: 'bearer' })
|
||||||
.send({
|
.send({
|
||||||
query: `
|
query: `
|
||||||
mutation {
|
mutation {
|
||||||
deleteAccount {
|
deleteAccount {
|
||||||
success
|
success
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
rejects(currentUser(app, user.token.token));
|
await rejects(currentUser(app, user.token.token));
|
||||||
});
|
t.pass();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { deepEqual, ok } from 'node:assert';
|
import { deepEqual, ok } from 'node:assert';
|
||||||
import { afterEach, beforeEach, describe, it } from 'node:test';
|
|
||||||
|
|
||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { Test } from '@nestjs/testing';
|
import { Test } from '@nestjs/testing';
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import test from 'ava';
|
||||||
// @ts-expect-error graphql-upload is not typed
|
// @ts-expect-error graphql-upload is not typed
|
||||||
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
@@ -18,116 +18,118 @@ import {
|
|||||||
signUp,
|
signUp,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
describe('Workspace Module - Blobs', () => {
|
let app: INestApplication;
|
||||||
let app: INestApplication;
|
|
||||||
|
|
||||||
const client = new PrismaClient();
|
const client = new PrismaClient();
|
||||||
|
|
||||||
// cleanup database before each test
|
// cleanup database before each test
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
await client.$connect();
|
await client.$connect();
|
||||||
await client.user.deleteMany({});
|
await client.user.deleteMany({});
|
||||||
await client.snapshot.deleteMany({});
|
await client.snapshot.deleteMany({});
|
||||||
await client.update.deleteMany({});
|
await client.update.deleteMany({});
|
||||||
await client.workspace.deleteMany({});
|
await client.workspace.deleteMany({});
|
||||||
await client.$disconnect();
|
await client.$disconnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
const module = await Test.createTestingModule({
|
const module = await Test.createTestingModule({
|
||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
}).compile();
|
}).compile();
|
||||||
app = module.createNestApplication();
|
app = module.createNestApplication();
|
||||||
app.use(
|
app.use(
|
||||||
graphqlUploadExpress({
|
graphqlUploadExpress({
|
||||||
maxFileSize: 10 * 1024 * 1024,
|
maxFileSize: 10 * 1024 * 1024,
|
||||||
maxFiles: 5,
|
maxFiles: 5,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
await app.init();
|
await app.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
test.afterEach(async () => {
|
||||||
await app.close();
|
await app.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set blobs', async () => {
|
test('should set blobs', async t => {
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
|
|
||||||
const workspace = await createWorkspace(app, u1.token.token);
|
const workspace = await createWorkspace(app, u1.token.token);
|
||||||
|
|
||||||
const buffer1 = Buffer.from([0, 0]);
|
const buffer1 = Buffer.from([0, 0]);
|
||||||
const hash1 = await setBlob(app, u1.token.token, workspace.id, buffer1);
|
const hash1 = await setBlob(app, u1.token.token, workspace.id, buffer1);
|
||||||
const buffer2 = Buffer.from([0, 1]);
|
const buffer2 = Buffer.from([0, 1]);
|
||||||
const hash2 = await setBlob(app, u1.token.token, workspace.id, buffer2);
|
const hash2 = await setBlob(app, u1.token.token, workspace.id, buffer2);
|
||||||
|
|
||||||
const server = app.getHttpServer();
|
const server = app.getHttpServer();
|
||||||
|
|
||||||
const response1 = await request(server)
|
const response1 = await request(server)
|
||||||
.get(`/api/workspaces/${workspace.id}/blobs/${hash1}`)
|
.get(`/api/workspaces/${workspace.id}/blobs/${hash1}`)
|
||||||
.auth(u1.token.token, { type: 'bearer' })
|
.auth(u1.token.token, { type: 'bearer' })
|
||||||
.buffer();
|
.buffer();
|
||||||
|
|
||||||
deepEqual(response1.body, buffer1, 'failed to get blob');
|
deepEqual(response1.body, buffer1, 'failed to get blob');
|
||||||
|
|
||||||
const response2 = await request(server)
|
const response2 = await request(server)
|
||||||
.get(`/api/workspaces/${workspace.id}/blobs/${hash2}`)
|
.get(`/api/workspaces/${workspace.id}/blobs/${hash2}`)
|
||||||
.auth(u1.token.token, { type: 'bearer' })
|
.auth(u1.token.token, { type: 'bearer' })
|
||||||
.buffer();
|
.buffer();
|
||||||
|
|
||||||
deepEqual(response2.body, buffer2, 'failed to get blob');
|
deepEqual(response2.body, buffer2, 'failed to get blob');
|
||||||
});
|
t.pass();
|
||||||
|
});
|
||||||
it('should list blobs', async () => {
|
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
test('should list blobs', async t => {
|
||||||
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
const workspace = await createWorkspace(app, u1.token.token);
|
|
||||||
const blobs = await listBlobs(app, u1.token.token, workspace.id);
|
const workspace = await createWorkspace(app, u1.token.token);
|
||||||
ok(blobs.length === 0, 'failed to list blobs');
|
const blobs = await listBlobs(app, u1.token.token, workspace.id);
|
||||||
|
ok(blobs.length === 0, 'failed to list blobs');
|
||||||
const buffer1 = Buffer.from([0, 0]);
|
|
||||||
const hash1 = await setBlob(app, u1.token.token, workspace.id, buffer1);
|
const buffer1 = Buffer.from([0, 0]);
|
||||||
const buffer2 = Buffer.from([0, 1]);
|
const hash1 = await setBlob(app, u1.token.token, workspace.id, buffer1);
|
||||||
const hash2 = await setBlob(app, u1.token.token, workspace.id, buffer2);
|
const buffer2 = Buffer.from([0, 1]);
|
||||||
|
const hash2 = await setBlob(app, u1.token.token, workspace.id, buffer2);
|
||||||
const ret = await listBlobs(app, u1.token.token, workspace.id);
|
|
||||||
ok(ret.length === 2, 'failed to list blobs');
|
const ret = await listBlobs(app, u1.token.token, workspace.id);
|
||||||
ok(ret[0] === hash1, 'failed to list blobs');
|
ok(ret.length === 2, 'failed to list blobs');
|
||||||
ok(ret[1] === hash2, 'failed to list blobs');
|
ok(ret[0] === hash1, 'failed to list blobs');
|
||||||
});
|
ok(ret[1] === hash2, 'failed to list blobs');
|
||||||
|
t.pass();
|
||||||
it('should calc blobs size', async () => {
|
});
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
|
||||||
|
test('should calc blobs size', async t => {
|
||||||
const workspace = await createWorkspace(app, u1.token.token);
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
|
|
||||||
const buffer1 = Buffer.from([0, 0]);
|
const workspace = await createWorkspace(app, u1.token.token);
|
||||||
await setBlob(app, u1.token.token, workspace.id, buffer1);
|
|
||||||
const buffer2 = Buffer.from([0, 1]);
|
const buffer1 = Buffer.from([0, 0]);
|
||||||
await setBlob(app, u1.token.token, workspace.id, buffer2);
|
await setBlob(app, u1.token.token, workspace.id, buffer1);
|
||||||
|
const buffer2 = Buffer.from([0, 1]);
|
||||||
const size = await collectBlobSizes(app, u1.token.token, workspace.id);
|
await setBlob(app, u1.token.token, workspace.id, buffer2);
|
||||||
ok(size === 4, 'failed to collect blob sizes');
|
|
||||||
});
|
const size = await collectBlobSizes(app, u1.token.token, workspace.id);
|
||||||
|
ok(size === 4, 'failed to collect blob sizes');
|
||||||
it('should calc all blobs size', async () => {
|
t.pass();
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
});
|
||||||
|
|
||||||
const workspace1 = await createWorkspace(app, u1.token.token);
|
test('should calc all blobs size', async t => {
|
||||||
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
const buffer1 = Buffer.from([0, 0]);
|
|
||||||
await setBlob(app, u1.token.token, workspace1.id, buffer1);
|
const workspace1 = await createWorkspace(app, u1.token.token);
|
||||||
const buffer2 = Buffer.from([0, 1]);
|
|
||||||
await setBlob(app, u1.token.token, workspace1.id, buffer2);
|
const buffer1 = Buffer.from([0, 0]);
|
||||||
|
await setBlob(app, u1.token.token, workspace1.id, buffer1);
|
||||||
const workspace2 = await createWorkspace(app, u1.token.token);
|
const buffer2 = Buffer.from([0, 1]);
|
||||||
|
await setBlob(app, u1.token.token, workspace1.id, buffer2);
|
||||||
const buffer3 = Buffer.from([0, 0]);
|
|
||||||
await setBlob(app, u1.token.token, workspace2.id, buffer3);
|
const workspace2 = await createWorkspace(app, u1.token.token);
|
||||||
const buffer4 = Buffer.from([0, 1]);
|
|
||||||
await setBlob(app, u1.token.token, workspace2.id, buffer4);
|
const buffer3 = Buffer.from([0, 0]);
|
||||||
|
await setBlob(app, u1.token.token, workspace2.id, buffer3);
|
||||||
const size = await collectAllBlobSizes(app, u1.token.token);
|
const buffer4 = Buffer.from([0, 1]);
|
||||||
ok(size === 8, 'failed to collect all blob sizes');
|
await setBlob(app, u1.token.token, workspace2.id, buffer4);
|
||||||
});
|
|
||||||
|
const size = await collectAllBlobSizes(app, u1.token.token);
|
||||||
|
ok(size === 8, 'failed to collect all blob sizes');
|
||||||
|
t.pass();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { ok } from 'node:assert';
|
import { ok } from 'node:assert';
|
||||||
import { afterEach, beforeEach, describe, it } from 'node:test';
|
|
||||||
|
|
||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { Test } from '@nestjs/testing';
|
import { Test } from '@nestjs/testing';
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import test from 'ava';
|
||||||
// @ts-expect-error graphql-upload is not typed
|
// @ts-expect-error graphql-upload is not typed
|
||||||
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
||||||
|
|
||||||
@@ -21,169 +21,168 @@ import {
|
|||||||
signUp,
|
signUp,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
describe('Workspace Module - invite', () => {
|
let app: INestApplication;
|
||||||
let app: INestApplication;
|
|
||||||
|
|
||||||
const client = new PrismaClient();
|
const client = new PrismaClient();
|
||||||
|
|
||||||
let auth: AuthService;
|
let auth: AuthService;
|
||||||
let mail: MailService;
|
let mail: MailService;
|
||||||
|
|
||||||
// cleanup database before each test
|
// cleanup database before each test
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
await client.$connect();
|
await client.$connect();
|
||||||
await client.user.deleteMany({});
|
await client.user.deleteMany({});
|
||||||
await client.snapshot.deleteMany({});
|
await client.snapshot.deleteMany({});
|
||||||
await client.update.deleteMany({});
|
await client.update.deleteMany({});
|
||||||
await client.workspace.deleteMany({});
|
await client.workspace.deleteMany({});
|
||||||
await client.$disconnect();
|
await client.$disconnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
const module = await Test.createTestingModule({
|
const module = await Test.createTestingModule({
|
||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
}).compile();
|
}).compile();
|
||||||
app = module.createNestApplication();
|
app = module.createNestApplication();
|
||||||
app.use(
|
app.use(
|
||||||
graphqlUploadExpress({
|
graphqlUploadExpress({
|
||||||
maxFileSize: 10 * 1024 * 1024,
|
maxFileSize: 10 * 1024 * 1024,
|
||||||
maxFiles: 5,
|
maxFiles: 5,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
await app.init();
|
await app.init();
|
||||||
|
|
||||||
auth = module.get(AuthService);
|
auth = module.get(AuthService);
|
||||||
mail = module.get(MailService);
|
mail = module.get(MailService);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
test.afterEach(async () => {
|
||||||
await app.close();
|
await app.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should invite a user', async () => {
|
test('should invite a user', async t => {
|
||||||
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
|
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
||||||
|
|
||||||
|
const workspace = await createWorkspace(app, u1.token.token);
|
||||||
|
|
||||||
|
const invite = await inviteUser(
|
||||||
|
app,
|
||||||
|
u1.token.token,
|
||||||
|
workspace.id,
|
||||||
|
u2.email,
|
||||||
|
'Admin'
|
||||||
|
);
|
||||||
|
ok(!!invite, 'failed to invite user');
|
||||||
|
t.pass();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should accept an invite', async t => {
|
||||||
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
|
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
||||||
|
|
||||||
|
const workspace = await createWorkspace(app, u1.token.token);
|
||||||
|
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin');
|
||||||
|
|
||||||
|
const accept = await acceptInvite(app, u2.token.token, workspace.id);
|
||||||
|
ok(accept === true, 'failed to accept invite');
|
||||||
|
|
||||||
|
const currWorkspace = await getWorkspace(app, u1.token.token, workspace.id);
|
||||||
|
const currMember = currWorkspace.members.find(u => u.email === u2.email);
|
||||||
|
ok(currMember !== undefined, 'failed to invite user');
|
||||||
|
ok(currMember.id === u2.id, 'failed to invite user');
|
||||||
|
ok(!currMember.accepted, 'failed to invite user');
|
||||||
|
t.pass();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should leave a workspace', async t => {
|
||||||
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
|
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
||||||
|
|
||||||
|
const workspace = await createWorkspace(app, u1.token.token);
|
||||||
|
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin');
|
||||||
|
await acceptInvite(app, u2.token.token, workspace.id);
|
||||||
|
|
||||||
|
const leave = await leaveWorkspace(app, u2.token.token, workspace.id);
|
||||||
|
ok(leave === true, 'failed to leave workspace');
|
||||||
|
t.pass();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should revoke a user', async t => {
|
||||||
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
|
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
||||||
|
|
||||||
|
const workspace = await createWorkspace(app, u1.token.token);
|
||||||
|
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin');
|
||||||
|
|
||||||
|
const currWorkspace = await getWorkspace(app, u1.token.token, workspace.id);
|
||||||
|
ok(currWorkspace.members.length === 2, 'failed to invite user');
|
||||||
|
|
||||||
|
const revoke = await revokeUser(app, u1.token.token, workspace.id, u2.id);
|
||||||
|
ok(revoke === true, 'failed to revoke user');
|
||||||
|
t.pass();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should create user if not exist', async t => {
|
||||||
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
|
|
||||||
|
const workspace = await createWorkspace(app, u1.token.token);
|
||||||
|
|
||||||
|
await inviteUser(app, u1.token.token, workspace.id, 'u2@affine.pro', 'Admin');
|
||||||
|
|
||||||
|
const user = await auth.getUserByEmail('u2@affine.pro');
|
||||||
|
ok(user !== undefined, 'failed to create user');
|
||||||
|
ok(user?.name === 'Unnamed', 'failed to create user');
|
||||||
|
t.pass();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should invite a user by link', async t => {
|
||||||
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
|
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
||||||
|
|
||||||
|
const workspace = await createWorkspace(app, u1.token.token);
|
||||||
|
|
||||||
|
const invite = await inviteUser(
|
||||||
|
app,
|
||||||
|
u1.token.token,
|
||||||
|
workspace.id,
|
||||||
|
u2.email,
|
||||||
|
'Admin'
|
||||||
|
);
|
||||||
|
|
||||||
|
const accept = await acceptInviteById(app, workspace.id, invite);
|
||||||
|
ok(accept === true, 'failed to accept invite');
|
||||||
|
|
||||||
|
const invite1 = await inviteUser(
|
||||||
|
app,
|
||||||
|
u1.token.token,
|
||||||
|
workspace.id,
|
||||||
|
u2.email,
|
||||||
|
'Admin'
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(invite === invite1, 'repeat the invitation must return same id');
|
||||||
|
|
||||||
|
const currWorkspace = await getWorkspace(app, u1.token.token, workspace.id);
|
||||||
|
const currMember = currWorkspace.members.find(u => u.email === u2.email);
|
||||||
|
ok(currMember !== undefined, 'failed to invite user');
|
||||||
|
ok(currMember.inviteId === invite, 'failed to check invite id');
|
||||||
|
t.pass();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should send invite email', async t => {
|
||||||
|
if (mail.hasConfigured()) {
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
const u2 = await signUp(app, 'test', 'production@toeverything.info', '1');
|
||||||
|
|
||||||
const workspace = await createWorkspace(app, u1.token.token);
|
const workspace = await createWorkspace(app, u1.token.token);
|
||||||
|
|
||||||
const invite = await inviteUser(
|
|
||||||
app,
|
|
||||||
u1.token.token,
|
|
||||||
workspace.id,
|
|
||||||
u2.email,
|
|
||||||
'Admin'
|
|
||||||
);
|
|
||||||
ok(!!invite, 'failed to invite user');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should accept an invite', async () => {
|
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
|
||||||
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
|
||||||
|
|
||||||
const workspace = await createWorkspace(app, u1.token.token);
|
|
||||||
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin');
|
|
||||||
|
|
||||||
const accept = await acceptInvite(app, u2.token.token, workspace.id);
|
|
||||||
ok(accept === true, 'failed to accept invite');
|
|
||||||
|
|
||||||
const currWorkspace = await getWorkspace(app, u1.token.token, workspace.id);
|
|
||||||
const currMember = currWorkspace.members.find(u => u.email === u2.email);
|
|
||||||
ok(currMember !== undefined, 'failed to invite user');
|
|
||||||
ok(currMember.id === u2.id, 'failed to invite user');
|
|
||||||
ok(!currMember.accepted, 'failed to invite user');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should leave a workspace', async () => {
|
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
|
||||||
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
|
||||||
|
|
||||||
const workspace = await createWorkspace(app, u1.token.token);
|
|
||||||
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin');
|
|
||||||
await acceptInvite(app, u2.token.token, workspace.id);
|
|
||||||
|
|
||||||
const leave = await leaveWorkspace(app, u2.token.token, workspace.id);
|
|
||||||
ok(leave === true, 'failed to leave workspace');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should revoke a user', async () => {
|
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
|
||||||
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
|
||||||
|
|
||||||
const workspace = await createWorkspace(app, u1.token.token);
|
|
||||||
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin');
|
|
||||||
|
|
||||||
const currWorkspace = await getWorkspace(app, u1.token.token, workspace.id);
|
|
||||||
ok(currWorkspace.members.length === 2, 'failed to invite user');
|
|
||||||
|
|
||||||
const revoke = await revokeUser(app, u1.token.token, workspace.id, u2.id);
|
|
||||||
ok(revoke === true, 'failed to revoke user');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create user if not exist', async () => {
|
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
|
||||||
|
|
||||||
const workspace = await createWorkspace(app, u1.token.token);
|
|
||||||
|
|
||||||
await inviteUser(
|
await inviteUser(
|
||||||
app,
|
|
||||||
u1.token.token,
|
|
||||||
workspace.id,
|
|
||||||
'u2@affine.pro',
|
|
||||||
'Admin'
|
|
||||||
);
|
|
||||||
|
|
||||||
const user = await auth.getUserByEmail('u2@affine.pro');
|
|
||||||
ok(user !== undefined, 'failed to create user');
|
|
||||||
ok(user?.name === 'Unnamed', 'failed to create user');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should invite a user by link', async () => {
|
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
|
||||||
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
|
||||||
|
|
||||||
const workspace = await createWorkspace(app, u1.token.token);
|
|
||||||
|
|
||||||
const invite = await inviteUser(
|
|
||||||
app,
|
app,
|
||||||
u1.token.token,
|
u1.token.token,
|
||||||
workspace.id,
|
workspace.id,
|
||||||
u2.email,
|
u2.email,
|
||||||
'Admin'
|
'Admin',
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
}
|
||||||
const accept = await acceptInviteById(app, workspace.id, invite);
|
t.pass();
|
||||||
ok(accept === true, 'failed to accept invite');
|
|
||||||
|
|
||||||
const invite1 = await inviteUser(
|
|
||||||
app,
|
|
||||||
u1.token.token,
|
|
||||||
workspace.id,
|
|
||||||
u2.email,
|
|
||||||
'Admin'
|
|
||||||
);
|
|
||||||
|
|
||||||
ok(invite === invite1, 'repeat the invitation must return same id');
|
|
||||||
|
|
||||||
const currWorkspace = await getWorkspace(app, u1.token.token, workspace.id);
|
|
||||||
const currMember = currWorkspace.members.find(u => u.email === u2.email);
|
|
||||||
ok(currMember !== undefined, 'failed to invite user');
|
|
||||||
ok(currMember.inviteId === invite, 'failed to check invite id');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should send invite email', async () => {
|
|
||||||
if (mail.hasConfigured()) {
|
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
|
||||||
const u2 = await signUp(app, 'test', 'production@toeverything.info', '1');
|
|
||||||
|
|
||||||
const workspace = await createWorkspace(app, u1.token.token);
|
|
||||||
await inviteUser(
|
|
||||||
app,
|
|
||||||
u1.token.token,
|
|
||||||
workspace.id,
|
|
||||||
u2.email,
|
|
||||||
'Admin',
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { deepEqual, ok, rejects } from 'node:assert';
|
import { deepEqual, ok, rejects } from 'node:assert';
|
||||||
import { afterEach, beforeEach, describe, it } from 'node:test';
|
|
||||||
|
|
||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { Test } from '@nestjs/testing';
|
import { Test } from '@nestjs/testing';
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import test from 'ava';
|
||||||
// @ts-expect-error graphql-upload is not typed
|
// @ts-expect-error graphql-upload is not typed
|
||||||
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
@@ -22,222 +22,213 @@ import {
|
|||||||
updateWorkspace,
|
updateWorkspace,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
describe('Workspace Module', () => {
|
let app: INestApplication;
|
||||||
let app: INestApplication;
|
|
||||||
|
|
||||||
const client = new PrismaClient();
|
const client = new PrismaClient();
|
||||||
|
|
||||||
// cleanup database before each test
|
// cleanup database before each test
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
await client.$connect();
|
await client.$connect();
|
||||||
await client.user.deleteMany({});
|
await client.user.deleteMany({});
|
||||||
await client.update.deleteMany({});
|
await client.update.deleteMany({});
|
||||||
await client.snapshot.deleteMany({});
|
await client.snapshot.deleteMany({});
|
||||||
await client.workspace.deleteMany({});
|
await client.workspace.deleteMany({});
|
||||||
await client.$disconnect();
|
await client.$disconnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
const module = await Test.createTestingModule({
|
const module = await Test.createTestingModule({
|
||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
}).compile();
|
}).compile();
|
||||||
app = module.createNestApplication();
|
app = module.createNestApplication();
|
||||||
app.use(
|
app.use(
|
||||||
graphqlUploadExpress({
|
graphqlUploadExpress({
|
||||||
maxFileSize: 10 * 1024 * 1024,
|
maxFileSize: 10 * 1024 * 1024,
|
||||||
maxFiles: 5,
|
maxFiles: 5,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
await app.init();
|
await app.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
test.afterEach(async () => {
|
||||||
await app.close();
|
await app.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should register a user', async () => {
|
test('should register a user', async t => {
|
||||||
const user = await signUp(app, 'u1', 'u1@affine.pro', '123456');
|
const user = await signUp(app, 'u1', 'u1@affine.pro', '123456');
|
||||||
ok(typeof user.id === 'string', 'user.id is not a string');
|
t.true(typeof user.id === 'string', 'user.id is not a string');
|
||||||
ok(user.name === 'u1', 'user.name is not valid');
|
t.true(user.name === 'u1', 'user.name is not valid');
|
||||||
ok(user.email === 'u1@affine.pro', 'user.email is not valid');
|
t.true(user.email === 'u1@affine.pro', 'user.email is not valid');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should be throttled at call signUp', async () => {
|
test.skip('should be throttled at call signUp', async t => {
|
||||||
let token = '';
|
let token = '';
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
token = (await signUp(app, `u${i}`, `u${i}@affine.pro`, `${i}`)).token
|
token = (await signUp(app, `u${i}`, `u${i}@affine.pro`, `${i}`)).token
|
||||||
.token;
|
.token;
|
||||||
// throttles are applied to each endpoint separately
|
// throttles are applied to each endpoint separately
|
||||||
await currentUser(app, token);
|
await currentUser(app, token);
|
||||||
}
|
}
|
||||||
await rejects(signUp(app, 'u11', 'u11@affine.pro', '11'));
|
await rejects(signUp(app, 'u11', 'u11@affine.pro', '11'));
|
||||||
await rejects(currentUser(app, token));
|
await rejects(currentUser(app, token));
|
||||||
});
|
t.pass();
|
||||||
|
});
|
||||||
it('should create a workspace', async () => {
|
|
||||||
const user = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
test('should create a workspace', async t => {
|
||||||
|
const user = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
const workspace = await createWorkspace(app, user.token.token);
|
|
||||||
ok(typeof workspace.id === 'string', 'workspace.id is not a string');
|
const workspace = await createWorkspace(app, user.token.token);
|
||||||
});
|
ok(typeof workspace.id === 'string', 'workspace.id is not a string');
|
||||||
|
t.pass();
|
||||||
it('should can publish workspace', async () => {
|
});
|
||||||
const user = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
|
||||||
const workspace = await createWorkspace(app, user.token.token);
|
test('should can publish workspace', async t => {
|
||||||
|
const user = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
const isPublic = await updateWorkspace(
|
const workspace = await createWorkspace(app, user.token.token);
|
||||||
app,
|
|
||||||
user.token.token,
|
const isPublic = await updateWorkspace(
|
||||||
workspace.id,
|
app,
|
||||||
true
|
user.token.token,
|
||||||
);
|
workspace.id,
|
||||||
ok(isPublic === true, 'failed to publish workspace');
|
true
|
||||||
|
);
|
||||||
const isPrivate = await updateWorkspace(
|
ok(isPublic === true, 'failed to publish workspace');
|
||||||
app,
|
|
||||||
user.token.token,
|
const isPrivate = await updateWorkspace(
|
||||||
workspace.id,
|
app,
|
||||||
false
|
user.token.token,
|
||||||
);
|
workspace.id,
|
||||||
ok(isPrivate === false, 'failed to unpublish workspace');
|
false
|
||||||
});
|
);
|
||||||
|
ok(isPrivate === false, 'failed to unpublish workspace');
|
||||||
it('should can read published workspace', async () => {
|
t.pass();
|
||||||
const user = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
});
|
||||||
const workspace = await createWorkspace(app, user.token.token);
|
|
||||||
|
test('should can read published workspace', async t => {
|
||||||
await rejects(
|
const user = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
getPublicWorkspace(app, 'not_exists_ws'),
|
const workspace = await createWorkspace(app, user.token.token);
|
||||||
'must not get not exists workspace'
|
|
||||||
);
|
await rejects(
|
||||||
await rejects(
|
getPublicWorkspace(app, 'not_exists_ws'),
|
||||||
getPublicWorkspace(app, workspace.id),
|
'must not get not exists workspace'
|
||||||
'must not get private workspace'
|
);
|
||||||
);
|
await rejects(
|
||||||
|
getPublicWorkspace(app, workspace.id),
|
||||||
await updateWorkspace(app, user.token.token, workspace.id, true);
|
'must not get private workspace'
|
||||||
|
);
|
||||||
const publicWorkspace = await getPublicWorkspace(app, workspace.id);
|
|
||||||
ok(publicWorkspace.id === workspace.id, 'failed to get public workspace');
|
await updateWorkspace(app, user.token.token, workspace.id, true);
|
||||||
});
|
|
||||||
|
const publicWorkspace = await getPublicWorkspace(app, workspace.id);
|
||||||
it('should share a page', async () => {
|
ok(publicWorkspace.id === workspace.id, 'failed to get public workspace');
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
t.pass();
|
||||||
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
});
|
||||||
|
|
||||||
const workspace = await createWorkspace(app, u1.token.token);
|
test('should share a page', async t => {
|
||||||
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
const share = await sharePage(app, u1.token.token, workspace.id, 'page1');
|
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
||||||
ok(share === true, 'failed to share page');
|
|
||||||
const pages = await getWorkspaceSharedPages(
|
const workspace = await createWorkspace(app, u1.token.token);
|
||||||
app,
|
|
||||||
u1.token.token,
|
const share = await sharePage(app, u1.token.token, workspace.id, 'page1');
|
||||||
workspace.id
|
t.true(share === true, 'failed to share page');
|
||||||
);
|
const pages = await getWorkspaceSharedPages(
|
||||||
ok(pages.length === 1, 'failed to get shared pages');
|
app,
|
||||||
ok(pages[0] === 'page1', 'failed to get shared page: page1');
|
u1.token.token,
|
||||||
|
workspace.id
|
||||||
const msg1 = await sharePage(app, u2.token.token, workspace.id, 'page2');
|
);
|
||||||
ok(msg1 === 'Permission denied', 'unauthorized user can share page');
|
t.true(pages.length === 1, 'failed to get shared pages');
|
||||||
const msg2 = await revokePage(
|
t.true(pages[0] === 'page1', 'failed to get shared page: page1');
|
||||||
app,
|
|
||||||
u2.token.token,
|
const msg1 = await sharePage(app, u2.token.token, workspace.id, 'page2');
|
||||||
'not_exists_ws',
|
t.true(msg1 === 'Permission denied', 'unauthorized user can share page');
|
||||||
'page2'
|
const msg2 = await revokePage(app, u2.token.token, 'not_exists_ws', 'page2');
|
||||||
);
|
t.true(msg2 === 'Permission denied', 'unauthorized user can share page');
|
||||||
ok(msg2 === 'Permission denied', 'unauthorized user can share page');
|
|
||||||
|
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin');
|
||||||
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin');
|
await acceptInvite(app, u2.token.token, workspace.id);
|
||||||
await acceptInvite(app, u2.token.token, workspace.id);
|
const invited = await sharePage(app, u2.token.token, workspace.id, 'page2');
|
||||||
const invited = await sharePage(app, u2.token.token, workspace.id, 'page2');
|
t.true(invited === true, 'failed to share page');
|
||||||
ok(invited === true, 'failed to share page');
|
|
||||||
|
const revoke = await revokePage(app, u1.token.token, workspace.id, 'page1');
|
||||||
const revoke = await revokePage(app, u1.token.token, workspace.id, 'page1');
|
t.true(revoke === true, 'failed to revoke page');
|
||||||
ok(revoke === true, 'failed to revoke page');
|
const pages2 = await getWorkspaceSharedPages(
|
||||||
const pages2 = await getWorkspaceSharedPages(
|
app,
|
||||||
app,
|
u1.token.token,
|
||||||
u1.token.token,
|
workspace.id
|
||||||
workspace.id
|
);
|
||||||
);
|
t.true(pages2.length === 1, 'failed to get shared pages');
|
||||||
ok(pages2.length === 1, 'failed to get shared pages');
|
t.true(pages2[0] === 'page2', 'failed to get shared page: page2');
|
||||||
ok(pages2[0] === 'page2', 'failed to get shared page: page2');
|
|
||||||
|
const msg3 = await revokePage(app, u1.token.token, workspace.id, 'page3');
|
||||||
const msg3 = await revokePage(app, u1.token.token, workspace.id, 'page3');
|
t.true(msg3 === false, 'can revoke non-exists page');
|
||||||
ok(msg3 === false, 'can revoke non-exists page');
|
|
||||||
|
const msg4 = await revokePage(app, u1.token.token, workspace.id, 'page2');
|
||||||
const msg4 = await revokePage(app, u1.token.token, workspace.id, 'page2');
|
t.true(msg4 === true, 'failed to revoke page');
|
||||||
ok(msg4 === true, 'failed to revoke page');
|
const page3 = await getWorkspaceSharedPages(
|
||||||
const page3 = await getWorkspaceSharedPages(
|
app,
|
||||||
app,
|
u1.token.token,
|
||||||
u1.token.token,
|
workspace.id
|
||||||
workspace.id
|
);
|
||||||
);
|
t.true(page3.length === 0, 'failed to get shared pages');
|
||||||
ok(page3.length === 0, 'failed to get shared pages');
|
});
|
||||||
});
|
|
||||||
|
test('should can get workspace doc', async t => {
|
||||||
it('should can get workspace doc', async () => {
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '2');
|
||||||
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '2');
|
const workspace = await createWorkspace(app, u1.token.token);
|
||||||
const workspace = await createWorkspace(app, u1.token.token);
|
|
||||||
|
const res1 = await request(app.getHttpServer())
|
||||||
const res1 = await request(app.getHttpServer())
|
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
||||||
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
.auth(u1.token.token, { type: 'bearer' })
|
||||||
.auth(u1.token.token, { type: 'bearer' })
|
.expect(200)
|
||||||
.expect(200)
|
.type('application/octet-stream');
|
||||||
.type('application/octet-stream');
|
|
||||||
|
deepEqual(res1.body, Buffer.from([0, 0]), 'failed to get doc with u1 token');
|
||||||
deepEqual(
|
|
||||||
res1.body,
|
await request(app.getHttpServer())
|
||||||
Buffer.from([0, 0]),
|
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
||||||
'failed to get doc with u1 token'
|
.expect(403);
|
||||||
);
|
await request(app.getHttpServer())
|
||||||
|
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
||||||
await request(app.getHttpServer())
|
.auth(u2.token.token, { type: 'bearer' })
|
||||||
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
.expect(403);
|
||||||
.expect(403);
|
|
||||||
await request(app.getHttpServer())
|
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin');
|
||||||
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
await request(app.getHttpServer())
|
||||||
.auth(u2.token.token, { type: 'bearer' })
|
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
||||||
.expect(403);
|
.auth(u2.token.token, { type: 'bearer' })
|
||||||
|
.expect(403);
|
||||||
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin');
|
|
||||||
await request(app.getHttpServer())
|
await acceptInvite(app, u2.token.token, workspace.id);
|
||||||
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
const res2 = await request(app.getHttpServer())
|
||||||
.auth(u2.token.token, { type: 'bearer' })
|
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
||||||
.expect(403);
|
.auth(u2.token.token, { type: 'bearer' })
|
||||||
|
.expect(200)
|
||||||
await acceptInvite(app, u2.token.token, workspace.id);
|
.type('application/octet-stream');
|
||||||
const res2 = await request(app.getHttpServer())
|
|
||||||
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
deepEqual(res2.body, Buffer.from([0, 0]), 'failed to get doc with u2 token');
|
||||||
.auth(u2.token.token, { type: 'bearer' })
|
t.pass();
|
||||||
.expect(200)
|
});
|
||||||
.type('application/octet-stream');
|
|
||||||
|
test('should be able to get public workspace doc', async t => {
|
||||||
deepEqual(
|
const user = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
res2.body,
|
const workspace = await createWorkspace(app, user.token.token);
|
||||||
Buffer.from([0, 0]),
|
|
||||||
'failed to get doc with u2 token'
|
const isPublic = await updateWorkspace(
|
||||||
);
|
app,
|
||||||
});
|
user.token.token,
|
||||||
|
workspace.id,
|
||||||
it('should be able to get public workspace doc', async () => {
|
true
|
||||||
const user = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
);
|
||||||
const workspace = await createWorkspace(app, user.token.token);
|
|
||||||
|
ok(isPublic === true, 'failed to publish workspace');
|
||||||
const isPublic = await updateWorkspace(
|
|
||||||
app,
|
const res = await request(app.getHttpServer())
|
||||||
user.token.token,
|
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
||||||
workspace.id,
|
.expect(200)
|
||||||
true
|
.type('application/octet-stream');
|
||||||
);
|
|
||||||
|
deepEqual(res.body, Buffer.from([0, 0]), 'failed to get public doc');
|
||||||
ok(isPublic === true, 'failed to publish workspace');
|
t.pass();
|
||||||
|
|
||||||
const res = await request(app.getHttpServer())
|
|
||||||
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
|
||||||
.expect(200)
|
|
||||||
.type('application/octet-stream');
|
|
||||||
|
|
||||||
deepEqual(res.body, Buffer.from([0, 0]), 'failed to get public doc');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
450
yarn.lock
450
yarn.lock
@@ -699,6 +699,7 @@ __metadata:
|
|||||||
"@types/sinon": ^10.0.16
|
"@types/sinon": ^10.0.16
|
||||||
"@types/supertest": ^2.0.12
|
"@types/supertest": ^2.0.12
|
||||||
"@types/ws": ^8.5.5
|
"@types/ws": ^8.5.5
|
||||||
|
ava: ^5.3.1
|
||||||
c8: ^8.0.1
|
c8: ^8.0.1
|
||||||
cookie-parser: ^1.4.6
|
cookie-parser: ^1.4.6
|
||||||
dotenv: ^16.3.1
|
dotenv: ^16.3.1
|
||||||
@@ -14762,6 +14763,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"aggregate-error@npm:^4.0.0":
|
||||||
|
version: 4.0.1
|
||||||
|
resolution: "aggregate-error@npm:4.0.1"
|
||||||
|
dependencies:
|
||||||
|
clean-stack: ^4.0.0
|
||||||
|
indent-string: ^5.0.0
|
||||||
|
checksum: bb3ffdfd13447800fff237c2cba752c59868ee669104bb995dfbbe0b8320e967d679e683dabb640feb32e4882d60258165cde0baafc4cd467cc7d275a13ad6b5
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"ahocorasick@npm:1.0.2":
|
"ahocorasick@npm:1.0.2":
|
||||||
version: 1.0.2
|
version: 1.0.2
|
||||||
resolution: "ahocorasick@npm:1.0.2"
|
resolution: "ahocorasick@npm:1.0.2"
|
||||||
@@ -14944,7 +14955,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.1.0":
|
"ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.1.0, ansi-styles@npm:^6.2.1":
|
||||||
version: 6.2.1
|
version: 6.2.1
|
||||||
resolution: "ansi-styles@npm:6.2.1"
|
resolution: "ansi-styles@npm:6.2.1"
|
||||||
checksum: ef940f2f0ced1a6347398da88a91da7930c33ecac3c77b72c5905f8b8fe402c52e6fde304ff5347f616e27a742da3f1dc76de98f6866c69251ad0b07a66776d9
|
checksum: ef940f2f0ced1a6347398da88a91da7930c33ecac3c77b72c5905f8b8fe402c52e6fde304ff5347f616e27a742da3f1dc76de98f6866c69251ad0b07a66776d9
|
||||||
@@ -15086,6 +15097,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"array-find-index@npm:^1.0.1":
|
||||||
|
version: 1.0.2
|
||||||
|
resolution: "array-find-index@npm:1.0.2"
|
||||||
|
checksum: aac128bf369e1ac6c06ff0bb330788371c0e256f71279fb92d745e26fb4b9db8920e485b4ec25e841c93146bf71a34dcdbcefa115e7e0f96927a214d237b7081
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"array-flatten@npm:1.1.1":
|
"array-flatten@npm:1.1.1":
|
||||||
version: 1.1.1
|
version: 1.1.1
|
||||||
resolution: "array-flatten@npm:1.1.1"
|
resolution: "array-flatten@npm:1.1.1"
|
||||||
@@ -15150,6 +15168,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"arrgv@npm:^1.0.2":
|
||||||
|
version: 1.0.2
|
||||||
|
resolution: "arrgv@npm:1.0.2"
|
||||||
|
checksum: 470bbb406ea3b34810dd8b03c0b33282617a42d9fce0ab45d58596efefd042fc548eda49161fa8e3f607cbe9df90e7a67003a09043ab9081eff70f97c63dd0e2
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"arrify@npm:^1.0.1":
|
"arrify@npm:^1.0.1":
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
resolution: "arrify@npm:1.0.1"
|
resolution: "arrify@npm:1.0.1"
|
||||||
@@ -15164,6 +15189,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"arrify@npm:^3.0.0":
|
||||||
|
version: 3.0.0
|
||||||
|
resolution: "arrify@npm:3.0.0"
|
||||||
|
checksum: d6c6f3dad9571234f320e130d57fddb2cc283c87f2ac7df6c7005dffc5161b7bb9376f4be655ed257050330336e84afc4f3020d77696ad231ff580a94ae5aba6
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"as-table@npm:^1.0.36":
|
"as-table@npm:^1.0.36":
|
||||||
version: 1.0.55
|
version: 1.0.55
|
||||||
resolution: "as-table@npm:1.0.55"
|
resolution: "as-table@npm:1.0.55"
|
||||||
@@ -15366,6 +15398,64 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"ava@npm:^5.3.1":
|
||||||
|
version: 5.3.1
|
||||||
|
resolution: "ava@npm:5.3.1"
|
||||||
|
dependencies:
|
||||||
|
acorn: ^8.8.2
|
||||||
|
acorn-walk: ^8.2.0
|
||||||
|
ansi-styles: ^6.2.1
|
||||||
|
arrgv: ^1.0.2
|
||||||
|
arrify: ^3.0.0
|
||||||
|
callsites: ^4.0.0
|
||||||
|
cbor: ^8.1.0
|
||||||
|
chalk: ^5.2.0
|
||||||
|
chokidar: ^3.5.3
|
||||||
|
chunkd: ^2.0.1
|
||||||
|
ci-info: ^3.8.0
|
||||||
|
ci-parallel-vars: ^1.0.1
|
||||||
|
clean-yaml-object: ^0.1.0
|
||||||
|
cli-truncate: ^3.1.0
|
||||||
|
code-excerpt: ^4.0.0
|
||||||
|
common-path-prefix: ^3.0.0
|
||||||
|
concordance: ^5.0.4
|
||||||
|
currently-unhandled: ^0.4.1
|
||||||
|
debug: ^4.3.4
|
||||||
|
emittery: ^1.0.1
|
||||||
|
figures: ^5.0.0
|
||||||
|
globby: ^13.1.4
|
||||||
|
ignore-by-default: ^2.1.0
|
||||||
|
indent-string: ^5.0.0
|
||||||
|
is-error: ^2.2.2
|
||||||
|
is-plain-object: ^5.0.0
|
||||||
|
is-promise: ^4.0.0
|
||||||
|
matcher: ^5.0.0
|
||||||
|
mem: ^9.0.2
|
||||||
|
ms: ^2.1.3
|
||||||
|
p-event: ^5.0.1
|
||||||
|
p-map: ^5.5.0
|
||||||
|
picomatch: ^2.3.1
|
||||||
|
pkg-conf: ^4.0.0
|
||||||
|
plur: ^5.1.0
|
||||||
|
pretty-ms: ^8.0.0
|
||||||
|
resolve-cwd: ^3.0.0
|
||||||
|
stack-utils: ^2.0.6
|
||||||
|
strip-ansi: ^7.0.1
|
||||||
|
supertap: ^3.0.1
|
||||||
|
temp-dir: ^3.0.0
|
||||||
|
write-file-atomic: ^5.0.1
|
||||||
|
yargs: ^17.7.2
|
||||||
|
peerDependencies:
|
||||||
|
"@ava/typescript": "*"
|
||||||
|
peerDependenciesMeta:
|
||||||
|
"@ava/typescript":
|
||||||
|
optional: true
|
||||||
|
bin:
|
||||||
|
ava: entrypoints/cli.mjs
|
||||||
|
checksum: 126a5932baef74eccd8bec992bd522e25c05b6ee4985dde87c20cece76c2377f0bf9448f242f3f9cd2abbf7a5ac932fe4e4abde2a23792d6271a6088e5a1984e
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"axios@npm:1.1.3":
|
"axios@npm:1.1.3":
|
||||||
version: 1.1.3
|
version: 1.1.3
|
||||||
resolution: "axios@npm:1.1.3"
|
resolution: "axios@npm:1.1.3"
|
||||||
@@ -15791,6 +15881,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"blueimp-md5@npm:^2.10.0":
|
||||||
|
version: 2.19.0
|
||||||
|
resolution: "blueimp-md5@npm:2.19.0"
|
||||||
|
checksum: 28095dcbd2c67152a2938006e8d7c74c3406ba6556071298f872505432feb2c13241b0476644160ee0a5220383ba94cb8ccdac0053b51f68d168728f9c382530
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"body-parser@npm:1.20.1":
|
"body-parser@npm:1.20.1":
|
||||||
version: 1.20.1
|
version: 1.20.1
|
||||||
resolution: "body-parser@npm:1.20.1"
|
resolution: "body-parser@npm:1.20.1"
|
||||||
@@ -16194,6 +16291,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"callsites@npm:^4.0.0":
|
||||||
|
version: 4.1.0
|
||||||
|
resolution: "callsites@npm:4.1.0"
|
||||||
|
checksum: 4ad31de7b7615fa25bdab9c2373865209d2d5190f895cdf2e2f518bd1dafa7ebcda2e6e9cc9640f2dfde6b3893d82fa4359a78ffc27baad2503227553c6882fa
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"camel-case@npm:^4.1.2":
|
"camel-case@npm:^4.1.2":
|
||||||
version: 4.1.2
|
version: 4.1.2
|
||||||
resolution: "camel-case@npm:4.1.2"
|
resolution: "camel-case@npm:4.1.2"
|
||||||
@@ -16292,6 +16396,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"cbor@npm:^8.1.0":
|
||||||
|
version: 8.1.0
|
||||||
|
resolution: "cbor@npm:8.1.0"
|
||||||
|
dependencies:
|
||||||
|
nofilter: ^3.1.0
|
||||||
|
checksum: a90338435dc7b45cc01461af979e3bb6ddd4f2a08584c437586039cd5f2235014c06e49d664295debbfb3514d87b2f06728092ab6aa6175e2e85e9cd7dc0c1fd
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"chai@npm:^4.3.7":
|
"chai@npm:^4.3.7":
|
||||||
version: 4.3.8
|
version: 4.3.8
|
||||||
resolution: "chai@npm:4.3.8"
|
resolution: "chai@npm:4.3.8"
|
||||||
@@ -16550,6 +16663,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"chunkd@npm:^2.0.1":
|
||||||
|
version: 2.0.1
|
||||||
|
resolution: "chunkd@npm:2.0.1"
|
||||||
|
checksum: bab8cc08c752a3648984385dc6f61d751e89dbeef648d22a3b661e1d470eaa0f5182f0b4303710f13ae83d2f85144f8eb2dde7a975861d9021b5c56b881f457b
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"ci-info@npm:^3.2.0, ci-info@npm:^3.8.0":
|
"ci-info@npm:^3.2.0, ci-info@npm:^3.8.0":
|
||||||
version: 3.8.0
|
version: 3.8.0
|
||||||
resolution: "ci-info@npm:3.8.0"
|
resolution: "ci-info@npm:3.8.0"
|
||||||
@@ -16557,6 +16677,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"ci-parallel-vars@npm:^1.0.1":
|
||||||
|
version: 1.0.1
|
||||||
|
resolution: "ci-parallel-vars@npm:1.0.1"
|
||||||
|
checksum: ae859831f7e8e3585db731b8306c336616e37bd709dad1d7775ea4c0731aefd94741dabb48201edc6827d000008fd7fb72cb977967614ee2d99d6b499f0c35fe
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"cjs-module-lexer@npm:^1.0.0, cjs-module-lexer@npm:^1.2.2":
|
"cjs-module-lexer@npm:^1.0.0, cjs-module-lexer@npm:^1.2.2":
|
||||||
version: 1.2.3
|
version: 1.2.3
|
||||||
resolution: "cjs-module-lexer@npm:1.2.3"
|
resolution: "cjs-module-lexer@npm:1.2.3"
|
||||||
@@ -16596,6 +16723,22 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"clean-stack@npm:^4.0.0":
|
||||||
|
version: 4.2.0
|
||||||
|
resolution: "clean-stack@npm:4.2.0"
|
||||||
|
dependencies:
|
||||||
|
escape-string-regexp: 5.0.0
|
||||||
|
checksum: 373f656a31face5c615c0839213b9b542a0a48057abfb1df66900eab4dc2a5c6097628e4a0b5aa559cdfc4e66f8a14ea47be9681773165a44470ef5fb8ccc172
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"clean-yaml-object@npm:^0.1.0":
|
||||||
|
version: 0.1.0
|
||||||
|
resolution: "clean-yaml-object@npm:0.1.0"
|
||||||
|
checksum: 0374ad2f1fbd4984ecf56ebc62200092f6372b9ccf1b7971bb979c328fb12fe76e759fb1e8adc491c80b7b1861f9f00c7f19813dd2a0f49c88231422c70451f4
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"cli-boxes@npm:^3.0.0":
|
"cli-boxes@npm:^3.0.0":
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
resolution: "cli-boxes@npm:3.0.0"
|
resolution: "cli-boxes@npm:3.0.0"
|
||||||
@@ -16812,6 +16955,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"code-excerpt@npm:^4.0.0":
|
||||||
|
version: 4.0.0
|
||||||
|
resolution: "code-excerpt@npm:4.0.0"
|
||||||
|
dependencies:
|
||||||
|
convert-to-spaces: ^2.0.1
|
||||||
|
checksum: d57137d8f4825879283a828cc02a1115b56858dc54ed06c625c8f67d6685d1becd2fbaa7f0ab19ecca1f5cca03f8c97bbc1f013cab40261e4d3275032e65efe9
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"collect-v8-coverage@npm:^1.0.0":
|
"collect-v8-coverage@npm:^1.0.0":
|
||||||
version: 1.0.2
|
version: 1.0.2
|
||||||
resolution: "collect-v8-coverage@npm:1.0.2"
|
resolution: "collect-v8-coverage@npm:1.0.2"
|
||||||
@@ -17089,6 +17241,22 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"concordance@npm:^5.0.4":
|
||||||
|
version: 5.0.4
|
||||||
|
resolution: "concordance@npm:5.0.4"
|
||||||
|
dependencies:
|
||||||
|
date-time: ^3.1.0
|
||||||
|
esutils: ^2.0.3
|
||||||
|
fast-diff: ^1.2.0
|
||||||
|
js-string-escape: ^1.0.1
|
||||||
|
lodash: ^4.17.15
|
||||||
|
md5-hex: ^3.0.1
|
||||||
|
semver: ^7.3.2
|
||||||
|
well-known-symbols: ^2.0.0
|
||||||
|
checksum: 749153ba711492feb7c3d2f5bb04c107157440b3e39509bd5dd19ee7b3ac751d1e4cd75796d9f702e0a713312dbc661421c68aa4a2c34d5f6d91f47e3a1c64a6
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"concurrently@npm:^8.2.1":
|
"concurrently@npm:^8.2.1":
|
||||||
version: 8.2.1
|
version: 8.2.1
|
||||||
resolution: "concurrently@npm:8.2.1"
|
resolution: "concurrently@npm:8.2.1"
|
||||||
@@ -17210,6 +17378,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"convert-to-spaces@npm:^2.0.1":
|
||||||
|
version: 2.0.1
|
||||||
|
resolution: "convert-to-spaces@npm:2.0.1"
|
||||||
|
checksum: bbb324e5916fe9866f65c0ff5f9c1ea933764d0bdb09fccaf59542e40545ed483db6b2339c6d9eb56a11965a58f1a6038f3174f0e2fb7601343c7107ca5e2751
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"cookie-parser@npm:^1.4.6":
|
"cookie-parser@npm:^1.4.6":
|
||||||
version: 1.4.6
|
version: 1.4.6
|
||||||
resolution: "cookie-parser@npm:1.4.6"
|
resolution: "cookie-parser@npm:1.4.6"
|
||||||
@@ -17651,6 +17826,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"currently-unhandled@npm:^0.4.1":
|
||||||
|
version: 0.4.1
|
||||||
|
resolution: "currently-unhandled@npm:0.4.1"
|
||||||
|
dependencies:
|
||||||
|
array-find-index: ^1.0.1
|
||||||
|
checksum: 1f59fe10b5339b54b1a1eee110022f663f3495cf7cf2f480686e89edc7fa8bfe42dbab4b54f85034bc8b092a76cc7becbc2dad4f9adad332ab5831bec39ad540
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"cwd@npm:^0.10.0":
|
"cwd@npm:^0.10.0":
|
||||||
version: 0.10.0
|
version: 0.10.0
|
||||||
resolution: "cwd@npm:0.10.0"
|
resolution: "cwd@npm:0.10.0"
|
||||||
@@ -17698,6 +17882,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"date-time@npm:^3.1.0":
|
||||||
|
version: 3.1.0
|
||||||
|
resolution: "date-time@npm:3.1.0"
|
||||||
|
dependencies:
|
||||||
|
time-zone: ^1.0.0
|
||||||
|
checksum: f9cfcd1b15dfeabab15c0b9d18eb9e4e2d9d4371713564178d46a8f91ad577a290b5178b80050718d02d9c0cf646f8a875011e12d1ed05871e9f72c72c8a8fe6
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"dayjs@npm:^1.11.3, dayjs@npm:^1.11.9":
|
"dayjs@npm:^1.11.3, dayjs@npm:^1.11.9":
|
||||||
version: 1.11.9
|
version: 1.11.9
|
||||||
resolution: "dayjs@npm:1.11.9"
|
resolution: "dayjs@npm:1.11.9"
|
||||||
@@ -18843,6 +19036,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"emittery@npm:^1.0.1":
|
||||||
|
version: 1.0.1
|
||||||
|
resolution: "emittery@npm:1.0.1"
|
||||||
|
checksum: d95faee6ffb2e023cadaa6804265fea5298c53d079f170112af8dfae3e141761363ea4510966128259346418e3ec7639310fd75059ecce2423bf8afd07004226
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"emoji-regex@npm:^8.0.0":
|
"emoji-regex@npm:^8.0.0":
|
||||||
version: 8.0.0
|
version: 8.0.0
|
||||||
resolution: "emoji-regex@npm:8.0.0"
|
resolution: "emoji-regex@npm:8.0.0"
|
||||||
@@ -19415,6 +19615,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"escape-string-regexp@npm:5.0.0, escape-string-regexp@npm:^5.0.0":
|
||||||
|
version: 5.0.0
|
||||||
|
resolution: "escape-string-regexp@npm:5.0.0"
|
||||||
|
checksum: 20daabe197f3cb198ec28546deebcf24b3dbb1a5a269184381b3116d12f0532e06007f4bc8da25669d6a7f8efb68db0758df4cd981f57bc5b57f521a3e12c59e
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"escape-string-regexp@npm:^1.0.2, escape-string-regexp@npm:^1.0.5":
|
"escape-string-regexp@npm:^1.0.2, escape-string-regexp@npm:^1.0.5":
|
||||||
version: 1.0.5
|
version: 1.0.5
|
||||||
resolution: "escape-string-regexp@npm:1.0.5"
|
resolution: "escape-string-regexp@npm:1.0.5"
|
||||||
@@ -19436,13 +19643,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"escape-string-regexp@npm:^5.0.0":
|
|
||||||
version: 5.0.0
|
|
||||||
resolution: "escape-string-regexp@npm:5.0.0"
|
|
||||||
checksum: 20daabe197f3cb198ec28546deebcf24b3dbb1a5a269184381b3116d12f0532e06007f4bc8da25669d6a7f8efb68db0758df4cd981f57bc5b57f521a3e12c59e
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"escodegen@npm:^2.0.0, escodegen@npm:^2.1.0":
|
"escodegen@npm:^2.0.0, escodegen@npm:^2.1.0":
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
resolution: "escodegen@npm:2.1.0"
|
resolution: "escodegen@npm:2.1.0"
|
||||||
@@ -19809,7 +20009,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"esutils@npm:^2.0.2":
|
"esutils@npm:^2.0.2, esutils@npm:^2.0.3":
|
||||||
version: 2.0.3
|
version: 2.0.3
|
||||||
resolution: "esutils@npm:2.0.3"
|
resolution: "esutils@npm:2.0.3"
|
||||||
checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87
|
checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87
|
||||||
@@ -20123,7 +20323,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"fast-diff@npm:^1.1.2":
|
"fast-diff@npm:^1.1.2, fast-diff@npm:^1.2.0":
|
||||||
version: 1.3.0
|
version: 1.3.0
|
||||||
resolution: "fast-diff@npm:1.3.0"
|
resolution: "fast-diff@npm:1.3.0"
|
||||||
checksum: d22d371b994fdc8cce9ff510d7b8dc4da70ac327bcba20df607dd5b9cae9f908f4d1028f5fe467650f058d1e7270235ae0b8230809a262b4df587a3b3aa216c3
|
checksum: d22d371b994fdc8cce9ff510d7b8dc4da70ac327bcba20df607dd5b9cae9f908f4d1028f5fe467650f058d1e7270235ae0b8230809a262b4df587a3b3aa216c3
|
||||||
@@ -20571,6 +20771,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"find-up@npm:^6.0.0":
|
||||||
|
version: 6.3.0
|
||||||
|
resolution: "find-up@npm:6.3.0"
|
||||||
|
dependencies:
|
||||||
|
locate-path: ^7.1.0
|
||||||
|
path-exists: ^5.0.0
|
||||||
|
checksum: 9a21b7f9244a420e54c6df95b4f6fc3941efd3c3e5476f8274eb452f6a85706e7a6a90de71353ee4f091fcb4593271a6f92810a324ec542650398f928783c280
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"flat-cache@npm:^3.0.4":
|
"flat-cache@npm:^3.0.4":
|
||||||
version: 3.1.0
|
version: 3.1.0
|
||||||
resolution: "flat-cache@npm:3.1.0"
|
resolution: "flat-cache@npm:3.1.0"
|
||||||
@@ -22325,6 +22535,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"ignore-by-default@npm:^2.1.0":
|
||||||
|
version: 2.1.0
|
||||||
|
resolution: "ignore-by-default@npm:2.1.0"
|
||||||
|
checksum: 2b2df4622b6a07a3e91893987be8f060dc553f7736b67e72aa2312041c450a6fa8371733d03c42f45a02e47ec824e961c2fba63a3d94fc59cbd669220a5b0d7a
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"ignore@npm:^5.0.4, ignore@npm:^5.2.0, ignore@npm:^5.2.4":
|
"ignore@npm:^5.0.4, ignore@npm:^5.2.0, ignore@npm:^5.2.4":
|
||||||
version: 5.2.4
|
version: 5.2.4
|
||||||
resolution: "ignore@npm:5.2.4"
|
resolution: "ignore@npm:5.2.4"
|
||||||
@@ -22415,6 +22632,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"indent-string@npm:^5.0.0":
|
||||||
|
version: 5.0.0
|
||||||
|
resolution: "indent-string@npm:5.0.0"
|
||||||
|
checksum: e466c27b6373440e6d84fbc19e750219ce25865cb82d578e41a6053d727e5520dc5725217d6eb1cc76005a1bb1696a0f106d84ce7ebda3033b963a38583fb3b3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"indexes-of@npm:^1.0.1":
|
"indexes-of@npm:^1.0.1":
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
resolution: "indexes-of@npm:1.0.1"
|
resolution: "indexes-of@npm:1.0.1"
|
||||||
@@ -22560,6 +22784,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"irregular-plurals@npm:^3.3.0":
|
||||||
|
version: 3.5.0
|
||||||
|
resolution: "irregular-plurals@npm:3.5.0"
|
||||||
|
checksum: 5b663091dc89155df7b2e9d053e8fb11941a0c4be95c4b6549ed3ea020489fdf4f75ea586c915b5b543704252679a5a6e8c6c3587da5ac3fc57b12da90a9aee7
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"is-absolute-url@npm:^3.0.0":
|
"is-absolute-url@npm:^3.0.0":
|
||||||
version: 3.0.3
|
version: 3.0.3
|
||||||
resolution: "is-absolute-url@npm:3.0.3"
|
resolution: "is-absolute-url@npm:3.0.3"
|
||||||
@@ -22688,6 +22919,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"is-error@npm:^2.2.2":
|
||||||
|
version: 2.2.2
|
||||||
|
resolution: "is-error@npm:2.2.2"
|
||||||
|
checksum: a97b39587150f0d38f9f93f64699807fe3020fe5edbd63548f234dc2ba96fd7c776d66c062bf031dfeb93c7f48db563ff6bde588418ca041da37c659a416f055
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"is-extglob@npm:^2.1.1":
|
"is-extglob@npm:^2.1.1":
|
||||||
version: 2.1.1
|
version: 2.1.1
|
||||||
resolution: "is-extglob@npm:2.1.1"
|
resolution: "is-extglob@npm:2.1.1"
|
||||||
@@ -22869,6 +23107,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"is-promise@npm:^4.0.0":
|
||||||
|
version: 4.0.0
|
||||||
|
resolution: "is-promise@npm:4.0.0"
|
||||||
|
checksum: 0b46517ad47b00b6358fd6553c83ec1f6ba9acd7ffb3d30a0bf519c5c69e7147c132430452351b8a9fc198f8dd6c4f76f8e6f5a7f100f8c77d57d9e0f4261a8a
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"is-regexp@npm:^1.0.0":
|
"is-regexp@npm:^1.0.0":
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
resolution: "is-regexp@npm:1.0.0"
|
resolution: "is-regexp@npm:1.0.0"
|
||||||
@@ -23940,6 +24185,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"js-string-escape@npm:^1.0.1":
|
||||||
|
version: 1.0.1
|
||||||
|
resolution: "js-string-escape@npm:1.0.1"
|
||||||
|
checksum: f11e0991bf57e0c183b55c547acec85bd2445f043efc9ea5aa68b41bd2a3e7d3ce94636cb233ae0d84064ba4c1a505d32e969813c5b13f81e7d4be12c59256fe
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"js-tiktoken@npm:^1.0.7":
|
"js-tiktoken@npm:^1.0.7":
|
||||||
version: 1.0.7
|
version: 1.0.7
|
||||||
resolution: "js-tiktoken@npm:1.0.7"
|
resolution: "js-tiktoken@npm:1.0.7"
|
||||||
@@ -23967,7 +24219,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"js-yaml@npm:^3.10.0, js-yaml@npm:^3.13.1":
|
"js-yaml@npm:^3.10.0, js-yaml@npm:^3.13.1, js-yaml@npm:^3.14.1":
|
||||||
version: 3.14.1
|
version: 3.14.1
|
||||||
resolution: "js-yaml@npm:3.14.1"
|
resolution: "js-yaml@npm:3.14.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -24802,6 +25054,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"load-json-file@npm:^7.0.0":
|
||||||
|
version: 7.0.1
|
||||||
|
resolution: "load-json-file@npm:7.0.1"
|
||||||
|
checksum: a560288da6891778321ef993e4bdbdf05374a4f3a3aeedd5ba6b64672798c830d748cfc59a2ec9891a3db30e78b3d04172e0dcb0d4828168289a393147ca0e74
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"loader-runner@npm:^4.1.0, loader-runner@npm:^4.2.0":
|
"loader-runner@npm:^4.1.0, loader-runner@npm:^4.2.0":
|
||||||
version: 4.3.0
|
version: 4.3.0
|
||||||
resolution: "loader-runner@npm:4.3.0"
|
resolution: "loader-runner@npm:4.3.0"
|
||||||
@@ -24865,6 +25124,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"locate-path@npm:^7.1.0":
|
||||||
|
version: 7.2.0
|
||||||
|
resolution: "locate-path@npm:7.2.0"
|
||||||
|
dependencies:
|
||||||
|
p-locate: ^6.0.0
|
||||||
|
checksum: c1b653bdf29beaecb3d307dfb7c44d98a2a98a02ebe353c9ad055d1ac45d6ed4e1142563d222df9b9efebc2bcb7d4c792b507fad9e7150a04c29530b7db570f8
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"lodash-es@npm:^4.17.21":
|
"lodash-es@npm:^4.17.21":
|
||||||
version: 4.17.21
|
version: 4.17.21
|
||||||
resolution: "lodash-es@npm:4.17.21"
|
resolution: "lodash-es@npm:4.17.21"
|
||||||
@@ -25374,7 +25642,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"map-age-cleaner@npm:^0.1.1":
|
"map-age-cleaner@npm:^0.1.1, map-age-cleaner@npm:^0.1.3":
|
||||||
version: 0.1.3
|
version: 0.1.3
|
||||||
resolution: "map-age-cleaner@npm:0.1.3"
|
resolution: "map-age-cleaner@npm:0.1.3"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -25474,6 +25742,24 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"matcher@npm:^5.0.0":
|
||||||
|
version: 5.0.0
|
||||||
|
resolution: "matcher@npm:5.0.0"
|
||||||
|
dependencies:
|
||||||
|
escape-string-regexp: ^5.0.0
|
||||||
|
checksum: 28f191c2d23fee0f6f32fd0181d9fe173b0ab815a919edba55605438a2f9fa40372e002574a1b17add981b0a8669c75bc6194318d065ed2dceffd8b160c38118
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"md5-hex@npm:^3.0.1":
|
||||||
|
version: 3.0.1
|
||||||
|
resolution: "md5-hex@npm:3.0.1"
|
||||||
|
dependencies:
|
||||||
|
blueimp-md5: ^2.10.0
|
||||||
|
checksum: 6799a19e8bdd3e0c2861b94c1d4d858a89220488d7885c1fa236797e367d0c2e5f2b789e05309307083503f85be3603a9686a5915568a473137d6b4117419cc2
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"md5@npm:^2.2.1, md5@npm:^2.3.0":
|
"md5@npm:^2.2.1, md5@npm:^2.3.0":
|
||||||
version: 2.3.0
|
version: 2.3.0
|
||||||
resolution: "md5@npm:2.3.0"
|
resolution: "md5@npm:2.3.0"
|
||||||
@@ -25542,6 +25828,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"mem@npm:^9.0.2":
|
||||||
|
version: 9.0.2
|
||||||
|
resolution: "mem@npm:9.0.2"
|
||||||
|
dependencies:
|
||||||
|
map-age-cleaner: ^0.1.3
|
||||||
|
mimic-fn: ^4.0.0
|
||||||
|
checksum: 07829bb182af0e3ecf748dc2edb1c3b10a256ef10458f7e24d06561a2adc2b3ef34d14abe81678bbcedb46faa477e7370223f118b1a5e1252da5fe43496f3967
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"memfs@npm:^3.4.3":
|
"memfs@npm:^3.4.3":
|
||||||
version: 3.5.3
|
version: 3.5.3
|
||||||
resolution: "memfs@npm:3.5.3"
|
resolution: "memfs@npm:3.5.3"
|
||||||
@@ -26108,7 +26404,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"ms@npm:2.1.3, ms@npm:^2.0.0, ms@npm:^2.1.1":
|
"ms@npm:2.1.3, ms@npm:^2.0.0, ms@npm:^2.1.1, ms@npm:^2.1.3":
|
||||||
version: 2.1.3
|
version: 2.1.3
|
||||||
resolution: "ms@npm:2.1.3"
|
resolution: "ms@npm:2.1.3"
|
||||||
checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d
|
checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d
|
||||||
@@ -26598,6 +26894,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"nofilter@npm:^3.1.0":
|
||||||
|
version: 3.1.0
|
||||||
|
resolution: "nofilter@npm:3.1.0"
|
||||||
|
checksum: 58aa85a5b4b35cbb6e42de8a8591c5e338061edc9f3e7286f2c335e9e9b9b8fa7c335ae45daa8a1f3433164dc0b9a3d187fa96f9516e04a17a1f9ce722becc4f
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"nopt@npm:^6.0.0":
|
"nopt@npm:^6.0.0":
|
||||||
version: 6.0.0
|
version: 6.0.0
|
||||||
resolution: "nopt@npm:6.0.0"
|
resolution: "nopt@npm:6.0.0"
|
||||||
@@ -27185,6 +27488,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"p-event@npm:^5.0.1":
|
||||||
|
version: 5.0.1
|
||||||
|
resolution: "p-event@npm:5.0.1"
|
||||||
|
dependencies:
|
||||||
|
p-timeout: ^5.0.2
|
||||||
|
checksum: 3bdd8df6092e6b149f25e9c2eb1c0843b3b4279b07be2a2c72c02b65b267a8908c2040fefd606f2497b0f2bcefcd214f8ca5a74f0c883515d400ccf1d88d5683
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"p-finally@npm:^1.0.0":
|
"p-finally@npm:^1.0.0":
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
resolution: "p-finally@npm:1.0.0"
|
resolution: "p-finally@npm:1.0.0"
|
||||||
@@ -27271,6 +27583,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"p-locate@npm:^6.0.0":
|
||||||
|
version: 6.0.0
|
||||||
|
resolution: "p-locate@npm:6.0.0"
|
||||||
|
dependencies:
|
||||||
|
p-limit: ^4.0.0
|
||||||
|
checksum: 2bfe5234efa5e7a4e74b30a5479a193fdd9236f8f6b4d2f3f69e3d286d9a7d7ab0c118a2a50142efcf4e41625def635bd9332d6cbf9cc65d85eb0718c579ab38
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"p-map@npm:^3.0.0":
|
"p-map@npm:^3.0.0":
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
resolution: "p-map@npm:3.0.0"
|
resolution: "p-map@npm:3.0.0"
|
||||||
@@ -27289,6 +27610,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"p-map@npm:^5.5.0":
|
||||||
|
version: 5.5.0
|
||||||
|
resolution: "p-map@npm:5.5.0"
|
||||||
|
dependencies:
|
||||||
|
aggregate-error: ^4.0.0
|
||||||
|
checksum: 065cb6fca6b78afbd070dd9224ff160dc23eea96e57863c09a0c8ea7ce921043f76854be7ee0abc295cff1ac9adcf700e79a1fbe3b80b625081087be58e7effb
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"p-queue@npm:^6.6.2":
|
"p-queue@npm:^6.6.2":
|
||||||
version: 6.6.2
|
version: 6.6.2
|
||||||
resolution: "p-queue@npm:6.6.2"
|
resolution: "p-queue@npm:6.6.2"
|
||||||
@@ -27318,6 +27648,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"p-timeout@npm:^5.0.2":
|
||||||
|
version: 5.1.0
|
||||||
|
resolution: "p-timeout@npm:5.1.0"
|
||||||
|
checksum: f5cd4e17301ff1ff1d8dbf2817df0ad88c6bba99349fc24d8d181827176ad4f8aca649190b8a5b1a428dfd6ddc091af4606835d3e0cb0656e04045da5c9e270c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"p-try@npm:^1.0.0":
|
"p-try@npm:^1.0.0":
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
resolution: "p-try@npm:1.0.0"
|
resolution: "p-try@npm:1.0.0"
|
||||||
@@ -27446,6 +27783,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"parse-ms@npm:^3.0.0":
|
||||||
|
version: 3.0.0
|
||||||
|
resolution: "parse-ms@npm:3.0.0"
|
||||||
|
checksum: fc602bba093835562321a67a9d6c8c9687ca4f26a09459a77e07ebd7efddd1a5766725ec60eb0c83a2abe67f7a23808f7deb1c1226727776eaf7f9607ae09db2
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"parse-passwd@npm:^1.0.0":
|
"parse-passwd@npm:^1.0.0":
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
resolution: "parse-passwd@npm:1.0.0"
|
resolution: "parse-passwd@npm:1.0.0"
|
||||||
@@ -27513,6 +27857,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"path-exists@npm:^5.0.0":
|
||||||
|
version: 5.0.0
|
||||||
|
resolution: "path-exists@npm:5.0.0"
|
||||||
|
checksum: 8ca842868cab09423994596eb2c5ec2a971c17d1a3cb36dbf060592c730c725cd524b9067d7d2a1e031fef9ba7bd2ac6dc5ec9fb92aa693265f7be3987045254
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"path-is-absolute@npm:^1.0.0":
|
"path-is-absolute@npm:^1.0.0":
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
resolution: "path-is-absolute@npm:1.0.1"
|
resolution: "path-is-absolute@npm:1.0.1"
|
||||||
@@ -27745,6 +28096,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"pkg-conf@npm:^4.0.0":
|
||||||
|
version: 4.0.0
|
||||||
|
resolution: "pkg-conf@npm:4.0.0"
|
||||||
|
dependencies:
|
||||||
|
find-up: ^6.0.0
|
||||||
|
load-json-file: ^7.0.0
|
||||||
|
checksum: 6da0c064a74f6c7ae80d7d68c5853e14f7e762a2a80c6ca9e0aa827002b90b69c86fefe3bac830b10a6f1739e7f96a1f728637f2a141e50b0fdafe92a2c3eab6
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"pkg-dir@npm:^3.0.0":
|
"pkg-dir@npm:^3.0.0":
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
resolution: "pkg-dir@npm:3.0.0"
|
resolution: "pkg-dir@npm:3.0.0"
|
||||||
@@ -27814,6 +28175,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"plur@npm:^5.1.0":
|
||||||
|
version: 5.1.0
|
||||||
|
resolution: "plur@npm:5.1.0"
|
||||||
|
dependencies:
|
||||||
|
irregular-plurals: ^3.3.0
|
||||||
|
checksum: 57e400dc4b926768fb0abab7f8688fe17e85673712134546e7beaaee188bae7e0504976e847d7e41d0d6103ff2fd61204095f03c2a45de19a8bad15aecb45cc1
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"pluralize@npm:^8.0.0":
|
"pluralize@npm:^8.0.0":
|
||||||
version: 8.0.0
|
version: 8.0.0
|
||||||
resolution: "pluralize@npm:8.0.0"
|
resolution: "pluralize@npm:8.0.0"
|
||||||
@@ -28519,6 +28889,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"pretty-ms@npm:^8.0.0":
|
||||||
|
version: 8.0.0
|
||||||
|
resolution: "pretty-ms@npm:8.0.0"
|
||||||
|
dependencies:
|
||||||
|
parse-ms: ^3.0.0
|
||||||
|
checksum: b7d2a8182887af0e5ab93f9df331f10db9b8eda86855e2de115eb01a6c501bde5631a8813b1b0abdd7d045e79b08ae875369a8fd279a3dacd6d9e572bdd3bfa6
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"pretty-time@npm:^1.1.0":
|
"pretty-time@npm:^1.1.0":
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
resolution: "pretty-time@npm:1.1.0"
|
resolution: "pretty-time@npm:1.1.0"
|
||||||
@@ -31184,7 +31563,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"stack-utils@npm:^2.0.3":
|
"stack-utils@npm:^2.0.3, stack-utils@npm:^2.0.6":
|
||||||
version: 2.0.6
|
version: 2.0.6
|
||||||
resolution: "stack-utils@npm:2.0.6"
|
resolution: "stack-utils@npm:2.0.6"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -31725,6 +32104,18 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"supertap@npm:^3.0.1":
|
||||||
|
version: 3.0.1
|
||||||
|
resolution: "supertap@npm:3.0.1"
|
||||||
|
dependencies:
|
||||||
|
indent-string: ^5.0.0
|
||||||
|
js-yaml: ^3.14.1
|
||||||
|
serialize-error: ^7.0.1
|
||||||
|
strip-ansi: ^7.0.1
|
||||||
|
checksum: ee3d71c1d25f7f15d4a849e72b0c5f430df7cd8f702cf082fdbec5642a9546be6557766745655fa3a3e9c88f7c7eed849f2d74457b5b72cb9d94a779c0c8a948
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"supertest@npm:^6.3.3":
|
"supertest@npm:^6.3.3":
|
||||||
version: 6.3.3
|
version: 6.3.3
|
||||||
resolution: "supertest@npm:6.3.3"
|
resolution: "supertest@npm:6.3.3"
|
||||||
@@ -32001,6 +32392,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"temp-dir@npm:^3.0.0":
|
||||||
|
version: 3.0.0
|
||||||
|
resolution: "temp-dir@npm:3.0.0"
|
||||||
|
checksum: 577211e995d1d584dd60f1469351d45e8a5b4524e4a9e42d3bdd12cfde1d0bb8f5898311bef24e02aaafb69514c1feb58c7b4c33dcec7129da3b0861a4ca935b
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"temp@npm:^0.8.4":
|
"temp@npm:^0.8.4":
|
||||||
version: 0.8.4
|
version: 0.8.4
|
||||||
resolution: "temp@npm:0.8.4"
|
resolution: "temp@npm:0.8.4"
|
||||||
@@ -32201,6 +32599,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"time-zone@npm:^1.0.0":
|
||||||
|
version: 1.0.0
|
||||||
|
resolution: "time-zone@npm:1.0.0"
|
||||||
|
checksum: e46f5a69b8c236dcd8e91e29d40d4e7a3495ed4f59888c3f84ce1d9678e20461421a6ba41233509d47dd94bc18f1a4377764838b21b584663f942b3426dcbce8
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"tiny-each-async@npm:2.0.3":
|
"tiny-each-async@npm:2.0.3":
|
||||||
version: 2.0.3
|
version: 2.0.3
|
||||||
resolution: "tiny-each-async@npm:2.0.3"
|
resolution: "tiny-each-async@npm:2.0.3"
|
||||||
@@ -34039,6 +34444,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"well-known-symbols@npm:^2.0.0":
|
||||||
|
version: 2.0.0
|
||||||
|
resolution: "well-known-symbols@npm:2.0.0"
|
||||||
|
checksum: 4f54bbc3012371cb4d228f436891b8e7536d34ac61a57541890257e96788608e096231e0121ac24d08ef2f908b3eb2dc0adba35023eaeb2a7df655da91415402
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"whatwg-encoding@npm:^2.0.0":
|
"whatwg-encoding@npm:^2.0.0":
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
resolution: "whatwg-encoding@npm:2.0.0"
|
resolution: "whatwg-encoding@npm:2.0.0"
|
||||||
@@ -34313,6 +34725,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"write-file-atomic@npm:^5.0.1":
|
||||||
|
version: 5.0.1
|
||||||
|
resolution: "write-file-atomic@npm:5.0.1"
|
||||||
|
dependencies:
|
||||||
|
imurmurhash: ^0.1.4
|
||||||
|
signal-exit: ^4.0.1
|
||||||
|
checksum: 8dbb0e2512c2f72ccc20ccedab9986c7d02d04039ed6e8780c987dc4940b793339c50172a1008eed7747001bfacc0ca47562668a069a7506c46c77d7ba3926a9
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"ws@npm:8.13.0, ws@npm:^8.11.0, ws@npm:^8.12.0, ws@npm:^8.13.0, ws@npm:^8.2.3":
|
"ws@npm:8.13.0, ws@npm:^8.11.0, ws@npm:^8.12.0, ws@npm:^8.13.0, ws@npm:^8.2.3":
|
||||||
version: 8.13.0
|
version: 8.13.0
|
||||||
resolution: "ws@npm:8.13.0"
|
resolution: "ws@npm:8.13.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user