mirror of
https://github.com/standardnotes/server
synced 2026-02-06 02:01:13 -05:00
Compare commits
8 Commits
@standardn
...
@standardn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ad605c906 | ||
|
|
db4c49c57b | ||
|
|
b5c72dda8f | ||
|
|
e06cc3ba80 | ||
|
|
8a72a1a559 | ||
|
|
3f61d3163e | ||
|
|
34b3c7ce16 | ||
|
|
0ce4185379 |
1
.pnp.cjs
generated
1
.pnp.cjs
generated
@@ -3218,6 +3218,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||
["@standardnotes/security", "workspace:packages/security"],\
|
||||
["@standardnotes/time", "workspace:packages/time"],\
|
||||
["@types/cors", "npm:2.8.12"],\
|
||||
["@types/express", "npm:4.17.13"],\
|
||||
["@types/ioredis", "npm:4.28.10"],\
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.27.1...@standardnotes/api-gateway@1.27.2) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.27.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.27.0...@standardnotes/api-gateway@1.27.1) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.27.1",
|
||||
"version": "1.27.2",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.40.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.40.1...@standardnotes/auth-server@1.40.2) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.40.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.40.0...@standardnotes/auth-server@1.40.1) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.40.1",
|
||||
"version": "1.40.2",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.8.21](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.8.20...@standardnotes/domain-events-infra@1.8.21) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.8.20](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.8.19...@standardnotes/domain-events-infra@1.8.20) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events-infra",
|
||||
"version": "1.8.20",
|
||||
"version": "1.8.21",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [2.65.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.64.1...@standardnotes/domain-events@2.65.0) (2022-10-10)
|
||||
|
||||
### Features
|
||||
|
||||
* add workspace invite created event ([db4c49c](https://github.com/standardnotes/server/commit/db4c49c57b81bfea6b8c6b8774c6a30e0561e154))
|
||||
|
||||
## [2.64.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.64.0...@standardnotes/domain-events@2.64.1) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events",
|
||||
"version": "2.64.1",
|
||||
"version": "2.65.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { DomainEventInterface } from './DomainEventInterface'
|
||||
import { WorkspaceInviteCreatedEventPayload } from './WorkspaceInviteCreatedEventPayload'
|
||||
|
||||
export interface WorkspaceInviteCreatedEvent extends DomainEventInterface {
|
||||
type: 'WORKSPACE_INVITE_CREATED'
|
||||
payload: WorkspaceInviteCreatedEventPayload
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface WorkspaceInviteCreatedEventPayload {
|
||||
inviterUuid: string
|
||||
inviteeEmail: string
|
||||
inviteUuid: string
|
||||
workspaceUuid: string
|
||||
}
|
||||
@@ -100,6 +100,8 @@ export * from './Event/UserRolesChangedEvent'
|
||||
export * from './Event/UserRolesChangedEventPayload'
|
||||
export * from './Event/UserSignedInEvent'
|
||||
export * from './Event/UserSignedInEventPayload'
|
||||
export * from './Event/WorkspaceInviteCreatedEvent'
|
||||
export * from './Event/WorkspaceInviteCreatedEventPayload'
|
||||
|
||||
export * from './Handler/DomainEventHandlerInterface'
|
||||
export * from './Handler/DomainEventMessageHandlerInterface'
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.4.0](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.3.25...@standardnotes/event-store@1.4.0) (2022-10-10)
|
||||
|
||||
### Features
|
||||
|
||||
* add workspace invite created event ([db4c49c](https://github.com/standardnotes/server/commit/db4c49c57b81bfea6b8c6b8774c6a30e0561e154))
|
||||
|
||||
## [1.3.25](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.3.24...@standardnotes/event-store@1.3.25) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/event-store",
|
||||
"version": "1.3.25",
|
||||
"version": "1.4.0",
|
||||
"description": "Event Store Service",
|
||||
"private": true,
|
||||
"main": "dist/src/index.js",
|
||||
|
||||
@@ -86,6 +86,7 @@ export class ContainerConfigLoader {
|
||||
['SUBSCRIPTION_RATE_ADJUSTED', container.get(TYPES.EventHandler)],
|
||||
['REFUND_REQUESTED', container.get(TYPES.EventHandler)],
|
||||
['INVOICE_GENERATED', container.get(TYPES.EventHandler)],
|
||||
['WORKSPACE_INVITE_CREATED', container.get(TYPES.EventHandler)],
|
||||
])
|
||||
|
||||
container
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.6.12](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.6.11...@standardnotes/files-server@1.6.12) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.6.11](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.6.10...@standardnotes/files-server@1.6.11) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files-server",
|
||||
"version": "1.6.11",
|
||||
"version": "1.6.12",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.10.40](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.39...@standardnotes/scheduler-server@1.10.40) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.39](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.38...@standardnotes/scheduler-server@1.10.39) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/scheduler-server",
|
||||
"version": "1.10.39",
|
||||
"version": "1.10.40",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.9.2](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.9.1...@standardnotes/syncing-server@1.9.2) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.9.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.9.0...@standardnotes/syncing-server@1.9.1) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/syncing-server",
|
||||
"version": "1.9.1",
|
||||
"version": "1.9.2",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,28 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.4.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.4.0...@standardnotes/workspace-server@1.4.1) (2022-10-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/workspace-server
|
||||
|
||||
# [1.4.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.3.0...@standardnotes/workspace-server@1.4.0) (2022-10-10)
|
||||
|
||||
### Features
|
||||
|
||||
* **workspace:** add inviting to workspace ([e06cc3b](https://github.com/standardnotes/server/commit/e06cc3ba80fd3bbf8a5fb0e176bc76b4318a36e9))
|
||||
|
||||
# [1.3.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.2.3...@standardnotes/workspace-server@1.3.0) (2022-10-10)
|
||||
|
||||
### Features
|
||||
|
||||
* **workspace:** add creating root workspace upon user registration ([3f61d31](https://github.com/standardnotes/server/commit/3f61d3163ef91b3b94056208a41bb4858c0df259))
|
||||
|
||||
## [1.2.3](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.2.2...@standardnotes/workspace-server@1.2.3) (2022-10-10)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **workspace:** add optional parameters to creating workspace ([0ce4185](https://github.com/standardnotes/server/commit/0ce4185379d921cf69eb27c94d63933b8cabc2e7))
|
||||
|
||||
## [1.2.2](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.2.1...@standardnotes/workspace-server@1.2.2) (2022-10-10)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
19
packages/workspace/migrations/1665390489236-optional-keys.ts
Normal file
19
packages/workspace/migrations/1665390489236-optional-keys.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class optionalKeys1665390489236 implements MigrationInterface {
|
||||
name = 'optionalKeys1665390489236'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `workspace_users` CHANGE `public_key` `public_key` varchar(255) NULL')
|
||||
await queryRunner.query(
|
||||
'ALTER TABLE `workspace_users` CHANGE `encrypted_private_key` `encrypted_private_key` varchar(255) NULL',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'ALTER TABLE `workspace_users` CHANGE `encrypted_private_key` `encrypted_private_key` varchar(255) NOT NULL',
|
||||
)
|
||||
await queryRunner.query('ALTER TABLE `workspace_users` CHANGE `public_key` `public_key` varchar(255) NOT NULL')
|
||||
}
|
||||
}
|
||||
27
packages/workspace/migrations/1665394559520-add-invites.ts
Normal file
27
packages/workspace/migrations/1665394559520-add-invites.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class addInvites1665394559520 implements MigrationInterface {
|
||||
name = 'addInvites1665394559520'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE `workspace_invites` (`uuid` varchar(36) NOT NULL, `inviter_uuid` varchar(36) NOT NULL, `invitee_email` varchar(255) NOT NULL, `status` varchar(64) NOT NULL, `accepting_user_uuid` varchar(36) NULL, `workspace_uuid` varchar(36) NOT NULL, `created_at` bigint NOT NULL, `updated_at` bigint NOT NULL, PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
await queryRunner.query('ALTER TABLE `workspaces` ADD `created_at` bigint NOT NULL')
|
||||
await queryRunner.query('ALTER TABLE `workspaces` ADD `updated_at` bigint NOT NULL')
|
||||
await queryRunner.query('ALTER TABLE `workspace_users` ADD `created_at` bigint NOT NULL')
|
||||
await queryRunner.query('ALTER TABLE `workspace_users` ADD `updated_at` bigint NOT NULL')
|
||||
await queryRunner.query(
|
||||
'ALTER TABLE `workspace_invites` ADD CONSTRAINT `FK_782df40d03151dd3998acd0a6ba` FOREIGN KEY (`workspace_uuid`) REFERENCES `workspaces`(`uuid`) ON DELETE CASCADE ON UPDATE NO ACTION',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `workspace_invites` DROP FOREIGN KEY `FK_782df40d03151dd3998acd0a6ba`')
|
||||
await queryRunner.query('ALTER TABLE `workspace_users` DROP COLUMN `updated_at`')
|
||||
await queryRunner.query('ALTER TABLE `workspace_users` DROP COLUMN `created_at`')
|
||||
await queryRunner.query('ALTER TABLE `workspaces` DROP COLUMN `updated_at`')
|
||||
await queryRunner.query('ALTER TABLE `workspaces` DROP COLUMN `created_at`')
|
||||
await queryRunner.query('DROP TABLE `workspace_invites`')
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/workspace-server",
|
||||
"version": "1.2.2",
|
||||
"version": "1.4.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -27,9 +27,10 @@
|
||||
"@sentry/node": "^7.3.0",
|
||||
"@standardnotes/api": "^1.11.0",
|
||||
"@standardnotes/common": "workspace:*",
|
||||
"@standardnotes/domain-events": "workspace:*",
|
||||
"@standardnotes/domain-events-infra": "workspace:*",
|
||||
"@standardnotes/domain-events": "workspace:^",
|
||||
"@standardnotes/domain-events-infra": "workspace:^",
|
||||
"@standardnotes/security": "workspace:*",
|
||||
"@standardnotes/time": "workspace:^",
|
||||
"aws-sdk": "^2.1159.0",
|
||||
"cors": "2.8.5",
|
||||
"dotenv": "^16.0.1",
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
DomainEventMessageHandlerInterface,
|
||||
DomainEventSubscriberFactoryInterface,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { TimerInterface, Timer } from '@standardnotes/time'
|
||||
import { Env } from './Env'
|
||||
import TYPES from './Types'
|
||||
import { AppDataSource } from './DataSource'
|
||||
@@ -30,6 +31,11 @@ import { Workspace } from '../Domain/Workspace/Workspace'
|
||||
import { WorkspaceUser } from '../Domain/Workspace/WorkspaceUser'
|
||||
import { CreateWorkspace } from '../Domain/UseCase/CreateWorkspace/CreateWorkspace'
|
||||
import { WorkspacesController } from '../Controller/WorkspacesController'
|
||||
import { UserRegisteredEventHandler } from '../Domain/Handler/UserRegisteredEventHandler'
|
||||
import { WorkspaceInviteRepositoryInterface } from '../Domain/Invite/WorkspaceInviteRepositoryInterface'
|
||||
import { MySQLWorkspaceInviteRepository } from '../Infra/MySQL/MySQLWorkspaceInviteRepository'
|
||||
import { WorkspaceInvite } from '../Domain/Invite/WorkspaceInvite'
|
||||
import { InviteToWorkspace } from '../Domain/UseCase/InviteToWorkspace/InviteToWorkspace'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const newrelicFormatter = require('@newrelic/winston-enricher')
|
||||
@@ -95,6 +101,9 @@ export class ContainerConfigLoader {
|
||||
// Repositories
|
||||
container.bind<WorkspaceRepositoryInterface>(TYPES.WorkspaceRepository).to(MySQLWorkspaceRepository)
|
||||
container.bind<WorkspaceUserRepositoryInterface>(TYPES.WorkspaceUserRepository).to(MySQLWorkspaceUserRepository)
|
||||
container
|
||||
.bind<WorkspaceInviteRepositoryInterface>(TYPES.WorkspaceInviteRepository)
|
||||
.to(MySQLWorkspaceInviteRepository)
|
||||
// ORM
|
||||
container
|
||||
.bind<Repository<Workspace>>(TYPES.ORMWorkspaceRepository)
|
||||
@@ -102,6 +111,9 @@ export class ContainerConfigLoader {
|
||||
container
|
||||
.bind<Repository<WorkspaceUser>>(TYPES.ORMWorkspaceUserRepository)
|
||||
.toConstantValue(AppDataSource.getRepository(WorkspaceUser))
|
||||
container
|
||||
.bind<Repository<WorkspaceInvite>>(TYPES.ORMWorkspaceInviteRepository)
|
||||
.toConstantValue(AppDataSource.getRepository(WorkspaceInvite))
|
||||
// Middleware
|
||||
container.bind<ApiGatewayAuthMiddleware>(TYPES.ApiGatewayAuthMiddleware).to(ApiGatewayAuthMiddleware)
|
||||
// env vars
|
||||
@@ -115,9 +127,12 @@ export class ContainerConfigLoader {
|
||||
container.bind(TYPES.VERSION).toConstantValue(env.get('VERSION'))
|
||||
|
||||
// use cases
|
||||
container.bind(TYPES.CreateWorkspace).to(CreateWorkspace)
|
||||
container.bind<CreateWorkspace>(TYPES.CreateWorkspace).to(CreateWorkspace)
|
||||
container.bind<InviteToWorkspace>(TYPES.InviteToWorkspace).to(InviteToWorkspace)
|
||||
// Handlers
|
||||
container.bind<UserRegisteredEventHandler>(TYPES.UserRegisteredEventHandler).to(UserRegisteredEventHandler)
|
||||
// Services
|
||||
container.bind<TimerInterface>(TYPES.Timer).toConstantValue(new Timer())
|
||||
container
|
||||
.bind<TokenDecoderInterface<CrossServiceTokenData>>(TYPES.CrossServiceTokenDecoder)
|
||||
.toConstantValue(new TokenDecoder<CrossServiceTokenData>(container.get(TYPES.AUTH_JWT_SECRET)))
|
||||
@@ -134,7 +149,9 @@ export class ContainerConfigLoader {
|
||||
)
|
||||
}
|
||||
|
||||
const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([])
|
||||
const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
|
||||
['USER_REGISTERED', container.get(TYPES.UserRegisteredEventHandler)],
|
||||
])
|
||||
|
||||
if (env.get('SQS_QUEUE_URL', true)) {
|
||||
container
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { DataSource, LoggerOptions } from 'typeorm'
|
||||
import { WorkspaceInvite } from '../Domain/Invite/WorkspaceInvite'
|
||||
import { Workspace } from '../Domain/Workspace/Workspace'
|
||||
import { WorkspaceUser } from '../Domain/Workspace/WorkspaceUser'
|
||||
import { Env } from './Env'
|
||||
@@ -34,7 +35,7 @@ export const AppDataSource = new DataSource({
|
||||
],
|
||||
removeNodeErrorCount: 10,
|
||||
},
|
||||
entities: [Workspace, WorkspaceUser],
|
||||
entities: [Workspace, WorkspaceUser, WorkspaceInvite],
|
||||
migrations: [env.get('DB_MIGRATIONS_PATH', true) ?? 'dist/migrations/*.js'],
|
||||
migrationsRun: true,
|
||||
logging: <LoggerOptions>env.get('DB_DEBUG_LEVEL'),
|
||||
|
||||
@@ -8,9 +8,11 @@ const TYPES = {
|
||||
// Repositories
|
||||
WorkspaceRepository: Symbol.for('WorkspaceRepository'),
|
||||
WorkspaceUserRepository: Symbol.for('WorkspaceUserRepository'),
|
||||
WorkspaceInviteRepository: Symbol.for('WorkspaceInviteRepository'),
|
||||
// ORM
|
||||
ORMWorkspaceRepository: Symbol.for('ORMWorkspaceRepository'),
|
||||
ORMWorkspaceUserRepository: Symbol.for('ORMWorkspaceUserRepository'),
|
||||
ORMWorkspaceInviteRepository: Symbol.for('ORMWorkspaceInviteRepository'),
|
||||
// Middleware
|
||||
ApiGatewayAuthMiddleware: Symbol.for('ApiGatewayAuthMiddleware'),
|
||||
// env vars
|
||||
@@ -25,8 +27,11 @@ const TYPES = {
|
||||
VERSION: Symbol.for('VERSION'),
|
||||
// use cases
|
||||
CreateWorkspace: Symbol.for('CreateWorkspace'),
|
||||
InviteToWorkspace: Symbol.for('InviteToWorkspace'),
|
||||
// Handlers
|
||||
UserRegisteredEventHandler: Symbol.for('UserRegisteredEventHandler'),
|
||||
// Services
|
||||
Timer: Symbol.for('Timer'),
|
||||
CrossServiceTokenDecoder: Symbol.for('CrossServiceTokenDecoder'),
|
||||
DomainEventPublisher: Symbol.for('DomainEventPublisher'),
|
||||
DomainEventSubscriberFactory: Symbol.for('DomainEventSubscriberFactory'),
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { UserRegisteredEvent } from '@standardnotes/domain-events'
|
||||
|
||||
import { UserRegisteredEventHandler } from './UserRegisteredEventHandler'
|
||||
import { CreateWorkspace } from '../UseCase/CreateWorkspace/CreateWorkspace'
|
||||
import { ProtocolVersion } from '@standardnotes/common'
|
||||
|
||||
describe('UserRegisteredEventHandler', () => {
|
||||
let createWorkspace: CreateWorkspace
|
||||
let event: UserRegisteredEvent
|
||||
|
||||
const createHandler = () => new UserRegisteredEventHandler(createWorkspace)
|
||||
|
||||
beforeEach(() => {
|
||||
createWorkspace = {} as jest.Mocked<CreateWorkspace>
|
||||
createWorkspace.execute = jest.fn()
|
||||
|
||||
event = {} as jest.Mocked<UserRegisteredEvent>
|
||||
event.createdAt = new Date(1)
|
||||
event.payload = {
|
||||
userUuid: '1-2-3',
|
||||
email: 'test@test.te',
|
||||
protocolVersion: ProtocolVersion.V005,
|
||||
}
|
||||
})
|
||||
|
||||
it('should create a root workspace for newly registered user', async () => {
|
||||
await createHandler().handle(event)
|
||||
|
||||
expect(createWorkspace.execute).toHaveBeenCalledWith({
|
||||
ownerUuid: '1-2-3',
|
||||
type: 'root',
|
||||
})
|
||||
})
|
||||
|
||||
it('should not create a root workspace for newly registered user on legacy protocols', async () => {
|
||||
event.payload.protocolVersion = ProtocolVersion.V004
|
||||
|
||||
await createHandler().handle(event)
|
||||
|
||||
expect(createWorkspace.execute).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,22 @@
|
||||
import { ProtocolVersion, WorkspaceType } from '@standardnotes/common'
|
||||
import { DomainEventHandlerInterface, UserRegisteredEvent } from '@standardnotes/domain-events'
|
||||
import { inject, injectable } from 'inversify'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { CreateWorkspace } from '../UseCase/CreateWorkspace/CreateWorkspace'
|
||||
|
||||
@injectable()
|
||||
export class UserRegisteredEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(@inject(TYPES.CreateWorkspace) private createWorkspace: CreateWorkspace) {}
|
||||
|
||||
async handle(event: UserRegisteredEvent): Promise<void> {
|
||||
if (event.payload.protocolVersion !== ProtocolVersion.V005) {
|
||||
return
|
||||
}
|
||||
|
||||
await this.createWorkspace.execute({
|
||||
ownerUuid: event.payload.userUuid,
|
||||
type: WorkspaceType.Root,
|
||||
})
|
||||
}
|
||||
}
|
||||
68
packages/workspace/src/Domain/Invite/WorkspaceInvite.ts
Normal file
68
packages/workspace/src/Domain/Invite/WorkspaceInvite.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'
|
||||
import { Workspace } from '../Workspace/Workspace'
|
||||
import { WorkspaceInviteStatus } from './WorkspaceInviteStatus'
|
||||
|
||||
@Entity({ name: 'workspace_invites' })
|
||||
export class WorkspaceInvite {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
declare uuid: string
|
||||
|
||||
@Column({
|
||||
name: 'inviter_uuid',
|
||||
length: 36,
|
||||
})
|
||||
declare inviterUuid: string
|
||||
|
||||
@Column({
|
||||
name: 'invitee_email',
|
||||
length: 255,
|
||||
})
|
||||
declare inviteeEmail: string
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'varchar',
|
||||
length: 64,
|
||||
})
|
||||
declare status: WorkspaceInviteStatus
|
||||
|
||||
@Column({
|
||||
name: 'accepting_user_uuid',
|
||||
type: 'varchar',
|
||||
length: 36,
|
||||
nullable: true,
|
||||
})
|
||||
declare acceptingUserUuid: string | null
|
||||
|
||||
@Column({
|
||||
name: 'workspace_uuid',
|
||||
length: 36,
|
||||
})
|
||||
declare workspaceUuid: string
|
||||
|
||||
@Column({
|
||||
name: 'created_at',
|
||||
type: 'bigint',
|
||||
})
|
||||
declare createdAt: number
|
||||
|
||||
@Column({
|
||||
name: 'updated_at',
|
||||
type: 'bigint',
|
||||
})
|
||||
declare updatedAt: number
|
||||
|
||||
@ManyToOne(
|
||||
/* istanbul ignore next */
|
||||
() => Workspace,
|
||||
/* istanbul ignore next */
|
||||
(workspace) => workspace.invites,
|
||||
/* istanbul ignore next */
|
||||
{ onDelete: 'CASCADE' },
|
||||
)
|
||||
@JoinColumn(
|
||||
/* istanbul ignore next */
|
||||
{ name: 'workspace_uuid' },
|
||||
)
|
||||
declare workspace: Promise<Workspace>
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { WorkspaceInvite } from './WorkspaceInvite'
|
||||
|
||||
export interface WorkspaceInviteRepositoryInterface {
|
||||
save(workspace: WorkspaceInvite): Promise<WorkspaceInvite>
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export enum WorkspaceInviteStatus {
|
||||
Created = 'created',
|
||||
Accepted = 'accepted',
|
||||
}
|
||||
@@ -6,14 +6,19 @@ import { WorkspaceRepositoryInterface } from '../../Workspace/WorkspaceRepositor
|
||||
import { WorkspaceUserRepositoryInterface } from '../../Workspace/WorkspaceUserRepositoryInterface'
|
||||
|
||||
import { CreateWorkspace } from './CreateWorkspace'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
|
||||
describe('CreateWorkspace', () => {
|
||||
let workspaceRepository: WorkspaceRepositoryInterface
|
||||
let workspaceUserRepository: WorkspaceUserRepositoryInterface
|
||||
let timer: TimerInterface
|
||||
|
||||
const createUseCase = () => new CreateWorkspace(workspaceRepository, workspaceUserRepository)
|
||||
const createUseCase = () => new CreateWorkspace(workspaceRepository, workspaceUserRepository, timer)
|
||||
|
||||
beforeEach(() => {
|
||||
timer = {} as jest.Mocked<TimerInterface>
|
||||
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(1)
|
||||
|
||||
workspaceRepository = {} as jest.Mocked<WorkspaceRepositoryInterface>
|
||||
workspaceRepository.save = jest.fn().mockImplementation((workspace) => {
|
||||
return {
|
||||
@@ -39,6 +44,8 @@ describe('CreateWorkspace', () => {
|
||||
expect(workspaceRepository.save).toHaveBeenCalledWith({
|
||||
name: 'A Team',
|
||||
type: 'root',
|
||||
createdAt: 1,
|
||||
updatedAt: 1,
|
||||
})
|
||||
expect(workspaceUserRepository.save).toHaveBeenCalledWith({
|
||||
accessLevel: 'owner',
|
||||
@@ -48,29 +55,29 @@ describe('CreateWorkspace', () => {
|
||||
status: 'active',
|
||||
userUuid: '1-2-3',
|
||||
workspaceUuid: 'w-1-2-3',
|
||||
createdAt: 1,
|
||||
updatedAt: 1,
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a workspace without a name and owner association with it', async () => {
|
||||
it('should create a workspace without optional parameters', async () => {
|
||||
await createUseCase().execute({
|
||||
encryptedPrivateKey: 'foo',
|
||||
encryptedWorkspaceKey: 'bar',
|
||||
publicKey: 'buzz',
|
||||
ownerUuid: '1-2-3',
|
||||
type: WorkspaceType.Private,
|
||||
})
|
||||
|
||||
expect(workspaceRepository.save).toHaveBeenCalledWith({
|
||||
type: 'private',
|
||||
createdAt: 1,
|
||||
updatedAt: 1,
|
||||
})
|
||||
expect(workspaceUserRepository.save).toHaveBeenCalledWith({
|
||||
accessLevel: 'owner',
|
||||
encryptedWorkspaceKey: 'bar',
|
||||
encryptedPrivateKey: 'foo',
|
||||
publicKey: 'buzz',
|
||||
status: 'active',
|
||||
userUuid: '1-2-3',
|
||||
workspaceUuid: 'w-1-2-3',
|
||||
createdAt: 1,
|
||||
updatedAt: 1,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
import { inject, injectable } from 'inversify'
|
||||
|
||||
import TYPES from '../../../Bootstrap/Types'
|
||||
@@ -17,6 +18,7 @@ export class CreateWorkspace implements UseCaseInterface {
|
||||
constructor(
|
||||
@inject(TYPES.WorkspaceRepository) private workspaceRepository: WorkspaceRepositoryInterface,
|
||||
@inject(TYPES.WorkspaceUserRepository) private workspaceUserRepository: WorkspaceUserRepositoryInterface,
|
||||
@inject(TYPES.Timer) private timer: TimerInterface,
|
||||
) {}
|
||||
|
||||
async execute(dto: CreateWorkspaceDTO): Promise<CreateWorkspaceResponse> {
|
||||
@@ -25,17 +27,28 @@ export class CreateWorkspace implements UseCaseInterface {
|
||||
workspace.name = dto.name
|
||||
}
|
||||
workspace.type = dto.type
|
||||
const timestamp = this.timer.getTimestampInMicroseconds()
|
||||
workspace.createdAt = timestamp
|
||||
workspace.updatedAt = timestamp
|
||||
|
||||
workspace = await this.workspaceRepository.save(workspace)
|
||||
|
||||
const ownerAssociation = new WorkspaceUser()
|
||||
ownerAssociation.accessLevel = WorkspaceAccessLevel.Owner
|
||||
ownerAssociation.encryptedWorkspaceKey = dto.encryptedWorkspaceKey
|
||||
ownerAssociation.encryptedPrivateKey = dto.encryptedPrivateKey
|
||||
ownerAssociation.publicKey = dto.publicKey
|
||||
if (dto.encryptedWorkspaceKey !== undefined) {
|
||||
ownerAssociation.encryptedWorkspaceKey = dto.encryptedWorkspaceKey
|
||||
}
|
||||
if (dto.encryptedPrivateKey !== undefined) {
|
||||
ownerAssociation.encryptedPrivateKey = dto.encryptedPrivateKey
|
||||
}
|
||||
if (dto.publicKey !== undefined) {
|
||||
ownerAssociation.publicKey = dto.publicKey
|
||||
}
|
||||
ownerAssociation.status = WorkspaceUserStatus.Active
|
||||
ownerAssociation.userUuid = dto.ownerUuid
|
||||
ownerAssociation.workspaceUuid = workspace.uuid
|
||||
ownerAssociation.createdAt = timestamp
|
||||
ownerAssociation.updatedAt = timestamp
|
||||
|
||||
await this.workspaceUserRepository.save(ownerAssociation)
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@ import { Uuid, WorkspaceType } from '@standardnotes/common'
|
||||
|
||||
export type CreateWorkspaceDTO = {
|
||||
ownerUuid: Uuid
|
||||
encryptedWorkspaceKey: string
|
||||
encryptedPrivateKey: string
|
||||
publicKey: string
|
||||
type: WorkspaceType
|
||||
encryptedWorkspaceKey?: string
|
||||
encryptedPrivateKey?: string
|
||||
publicKey?: string
|
||||
name?: string
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import 'reflect-metadata'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
|
||||
import { WorkspaceInviteRepositoryInterface } from '../../Invite/WorkspaceInviteRepositoryInterface'
|
||||
|
||||
import { InviteToWorkspace } from './InviteToWorkspace'
|
||||
|
||||
describe('InviteToWorkspace', () => {
|
||||
let workspaceInviteRepository: WorkspaceInviteRepositoryInterface
|
||||
let timer: TimerInterface
|
||||
|
||||
const createUseCase = () => new InviteToWorkspace(workspaceInviteRepository, timer)
|
||||
|
||||
beforeEach(() => {
|
||||
workspaceInviteRepository = {} as jest.Mocked<WorkspaceInviteRepositoryInterface>
|
||||
workspaceInviteRepository.save = jest.fn().mockImplementation((invite) => {
|
||||
return {
|
||||
...invite,
|
||||
uuid: 'i-1-2-3',
|
||||
}
|
||||
})
|
||||
|
||||
timer = {} as jest.Mocked<TimerInterface>
|
||||
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(1)
|
||||
})
|
||||
|
||||
it('should create an invite', async () => {
|
||||
const result = await createUseCase().execute({
|
||||
inviteeEmail: 'test@test.te',
|
||||
inviterUuid: 'u-1-2-3',
|
||||
workspaceUuid: 'w-1-2-3',
|
||||
})
|
||||
|
||||
expect(result).toEqual({ uuid: 'i-1-2-3' })
|
||||
|
||||
expect(workspaceInviteRepository.save).toHaveBeenCalledWith({
|
||||
inviterUuid: 'u-1-2-3',
|
||||
inviteeEmail: 'test@test.te',
|
||||
workspaceUuid: 'w-1-2-3',
|
||||
status: 'created',
|
||||
createdAt: 1,
|
||||
updatedAt: 1,
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,37 @@
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
import { inject, injectable } from 'inversify'
|
||||
|
||||
import TYPES from '../../../Bootstrap/Types'
|
||||
import { WorkspaceInvite } from '../../Invite/WorkspaceInvite'
|
||||
import { WorkspaceInviteRepositoryInterface } from '../../Invite/WorkspaceInviteRepositoryInterface'
|
||||
import { WorkspaceInviteStatus } from '../../Invite/WorkspaceInviteStatus'
|
||||
|
||||
import { UseCaseInterface } from '../UseCaseInterface'
|
||||
import { InviteToWorkspaceDTO } from './InviteToWorkspaceDTO'
|
||||
import { InviteToWorkspaceResponse } from './InviteToWorkspaceResponse'
|
||||
|
||||
@injectable()
|
||||
export class InviteToWorkspace implements UseCaseInterface {
|
||||
constructor(
|
||||
@inject(TYPES.WorkspaceInviteRepository) private workspaceInviteRepository: WorkspaceInviteRepositoryInterface,
|
||||
@inject(TYPES.Timer) private timer: TimerInterface,
|
||||
) {}
|
||||
|
||||
async execute(dto: InviteToWorkspaceDTO): Promise<InviteToWorkspaceResponse> {
|
||||
let invite = new WorkspaceInvite()
|
||||
invite.inviterUuid = dto.inviterUuid
|
||||
invite.inviteeEmail = dto.inviteeEmail
|
||||
invite.workspaceUuid = dto.workspaceUuid
|
||||
invite.status = WorkspaceInviteStatus.Created
|
||||
|
||||
const timestamp = this.timer.getTimestampInMicroseconds()
|
||||
invite.createdAt = timestamp
|
||||
invite.updatedAt = timestamp
|
||||
|
||||
invite = await this.workspaceInviteRepository.save(invite)
|
||||
|
||||
return {
|
||||
uuid: invite.uuid,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { Uuid } from '@standardnotes/common'
|
||||
|
||||
export type InviteToWorkspaceDTO = {
|
||||
workspaceUuid: Uuid
|
||||
inviterUuid: Uuid
|
||||
inviteeEmail: string
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export type InviteToWorkspaceResponse = {
|
||||
uuid: string
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { WorkspaceType } from '@standardnotes/common'
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'
|
||||
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm'
|
||||
import { WorkspaceInvite } from '../Invite/WorkspaceInvite'
|
||||
|
||||
@Entity({ name: 'workspaces' })
|
||||
export class Workspace {
|
||||
@@ -23,4 +24,24 @@ export class Workspace {
|
||||
default: 0,
|
||||
})
|
||||
declare keyRotationIndex: number
|
||||
|
||||
@Column({
|
||||
name: 'created_at',
|
||||
type: 'bigint',
|
||||
})
|
||||
declare createdAt: number
|
||||
|
||||
@Column({
|
||||
name: 'updated_at',
|
||||
type: 'bigint',
|
||||
})
|
||||
declare updatedAt: number
|
||||
|
||||
@OneToMany(
|
||||
/* istanbul ignore next */
|
||||
() => WorkspaceInvite,
|
||||
/* istanbul ignore next */
|
||||
(workspaceInvite) => workspaceInvite.workspace,
|
||||
)
|
||||
declare invites: Promise<WorkspaceInvite[]>
|
||||
}
|
||||
|
||||
@@ -38,15 +38,17 @@ export class WorkspaceUser {
|
||||
name: 'public_key',
|
||||
length: 255,
|
||||
type: 'varchar',
|
||||
nullable: true,
|
||||
})
|
||||
declare publicKey: string
|
||||
declare publicKey: string | null
|
||||
|
||||
@Column({
|
||||
name: 'encrypted_private_key',
|
||||
length: 255,
|
||||
type: 'varchar',
|
||||
nullable: true,
|
||||
})
|
||||
declare encryptedPrivateKey: string
|
||||
declare encryptedPrivateKey: string | null
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
@@ -59,4 +61,16 @@ export class WorkspaceUser {
|
||||
default: 0,
|
||||
})
|
||||
declare keyRotationIndex: number
|
||||
|
||||
@Column({
|
||||
name: 'created_at',
|
||||
type: 'bigint',
|
||||
})
|
||||
declare createdAt: number
|
||||
|
||||
@Column({
|
||||
name: 'updated_at',
|
||||
type: 'bigint',
|
||||
})
|
||||
declare updatedAt: number
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { Repository, SelectQueryBuilder } from 'typeorm'
|
||||
|
||||
import { WorkspaceInvite } from '../../Domain/Invite/WorkspaceInvite'
|
||||
import { MySQLWorkspaceInviteRepository } from './MySQLWorkspaceInviteRepository'
|
||||
|
||||
describe('MySQLWorkspaceInviteRepository', () => {
|
||||
let ormRepository: Repository<WorkspaceInvite>
|
||||
let invite: WorkspaceInvite
|
||||
let queryBuilder: SelectQueryBuilder<WorkspaceInvite>
|
||||
|
||||
const createRepository = () => new MySQLWorkspaceInviteRepository(ormRepository)
|
||||
|
||||
beforeEach(() => {
|
||||
invite = {} as jest.Mocked<WorkspaceInvite>
|
||||
|
||||
queryBuilder = {} as jest.Mocked<SelectQueryBuilder<WorkspaceInvite>>
|
||||
|
||||
ormRepository = {} as jest.Mocked<Repository<WorkspaceInvite>>
|
||||
ormRepository.save = jest.fn()
|
||||
ormRepository.createQueryBuilder = jest.fn().mockImplementation(() => queryBuilder)
|
||||
})
|
||||
|
||||
it('should save', async () => {
|
||||
await createRepository().save(invite)
|
||||
|
||||
expect(ormRepository.save).toHaveBeenCalledWith(invite)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Repository } from 'typeorm'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { WorkspaceInvite } from '../../Domain/Invite/WorkspaceInvite'
|
||||
import { WorkspaceInviteRepositoryInterface } from '../../Domain/Invite/WorkspaceInviteRepositoryInterface'
|
||||
|
||||
@injectable()
|
||||
export class MySQLWorkspaceInviteRepository implements WorkspaceInviteRepositoryInterface {
|
||||
constructor(
|
||||
@inject(TYPES.ORMWorkspaceInviteRepository)
|
||||
private ormRepository: Repository<WorkspaceInvite>,
|
||||
) {}
|
||||
|
||||
async save(workspaceInvite: WorkspaceInvite): Promise<WorkspaceInvite> {
|
||||
return this.ormRepository.save(workspaceInvite)
|
||||
}
|
||||
}
|
||||
11
yarn.lock
11
yarn.lock
@@ -1949,7 +1949,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/domain-events-infra@workspace:*, @standardnotes/domain-events-infra@workspace:packages/domain-events-infra":
|
||||
"@standardnotes/domain-events-infra@workspace:*, @standardnotes/domain-events-infra@workspace:^, @standardnotes/domain-events-infra@workspace:packages/domain-events-infra":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/domain-events-infra@workspace:packages/domain-events-infra"
|
||||
dependencies:
|
||||
@@ -1970,7 +1970,7 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/domain-events@workspace:*, @standardnotes/domain-events@workspace:packages/domain-events":
|
||||
"@standardnotes/domain-events@workspace:*, @standardnotes/domain-events@workspace:^, @standardnotes/domain-events@workspace:packages/domain-events":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/domain-events@workspace:packages/domain-events"
|
||||
dependencies:
|
||||
@@ -2397,7 +2397,7 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/time@workspace:*, @standardnotes/time@workspace:packages/time":
|
||||
"@standardnotes/time@workspace:*, @standardnotes/time@workspace:^, @standardnotes/time@workspace:packages/time":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/time@workspace:packages/time"
|
||||
dependencies:
|
||||
@@ -2444,9 +2444,10 @@ __metadata:
|
||||
"@sentry/node": ^7.3.0
|
||||
"@standardnotes/api": ^1.11.0
|
||||
"@standardnotes/common": "workspace:*"
|
||||
"@standardnotes/domain-events": "workspace:*"
|
||||
"@standardnotes/domain-events-infra": "workspace:*"
|
||||
"@standardnotes/domain-events": "workspace:^"
|
||||
"@standardnotes/domain-events-infra": "workspace:^"
|
||||
"@standardnotes/security": "workspace:*"
|
||||
"@standardnotes/time": "workspace:^"
|
||||
"@types/cors": ^2.8.9
|
||||
"@types/express": ^4.17.11
|
||||
"@types/ioredis": ^4.28.10
|
||||
|
||||
Reference in New Issue
Block a user