Compare commits

..

12 Commits

Author SHA1 Message Date
standardci
3da952fa52 chore(release): publish new version
- @standardnotes/analytics@1.50.0
 - @standardnotes/api-gateway@1.36.12
 - @standardnotes/auth-server@1.51.0
 - @standardnotes/domain-events-infra@1.9.11
 - @standardnotes/domain-events@2.77.0
 - @standardnotes/event-store@1.6.6
 - @standardnotes/files-server@1.8.6
 - @standardnotes/scheduler-server@1.13.7
 - @standardnotes/syncing-server@1.10.23
 - @standardnotes/websockets-server@1.4.6
 - @standardnotes/workspace-server@1.17.6
2022-11-07 09:03:54 +00:00
Karol Sójko
f1834d58d2 feat(analytics): add handling subscription purchased events 2022-11-07 10:02:07 +01:00
standardci
b0cde4ab75 chore(release): publish new version
- @standardnotes/analytics@1.49.0
 - @standardnotes/api-gateway@1.36.11
 - @standardnotes/auth-server@1.50.0
 - @standardnotes/domain-events-infra@1.9.10
 - @standardnotes/domain-events@2.76.0
 - @standardnotes/event-store@1.6.5
 - @standardnotes/files-server@1.8.5
 - @standardnotes/scheduler-server@1.13.6
 - @standardnotes/syncing-server@1.10.22
 - @standardnotes/websockets-server@1.4.5
 - @standardnotes/workspace-server@1.17.5
2022-11-07 06:45:26 +00:00
Karol Sójko
197c9914ca feat(analytics): add handling subscription refunded event 2022-11-07 07:43:36 +01:00
standardci
d7ef6898be chore(release): publish new version
- @standardnotes/analytics@1.48.0
 - @standardnotes/api-gateway@1.36.10
 - @standardnotes/auth-server@1.49.13
 - @standardnotes/syncing-server@1.10.21
2022-11-07 06:13:47 +00:00
Karol Sójko
2aa57f1f0d feat(analytics): add subscription renewed event handler 2022-11-07 07:11:10 +01:00
standardci
dcc0e38707 chore(release): publish new version
- @standardnotes/analytics@1.47.0
 - @standardnotes/api-gateway@1.36.9
 - @standardnotes/auth-server@1.49.12
 - @standardnotes/domain-events-infra@1.9.9
 - @standardnotes/domain-events@2.75.0
 - @standardnotes/event-store@1.6.4
 - @standardnotes/files-server@1.8.4
 - @standardnotes/scheduler-server@1.13.5
 - @standardnotes/syncing-server@1.10.20
 - @standardnotes/websockets-server@1.4.4
 - @standardnotes/workspace-server@1.17.4
2022-11-04 14:01:17 +00:00
Karol Sójko
037fb2398a feat(analytics): add subscription cancelled event handler 2022-11-04 14:59:30 +01:00
Karol Sójko
182512d07c fix(syncing-server): event specs 2022-11-04 14:59:30 +01:00
Karol Sójko
a3be4b063d fix(auth): event specs 2022-11-04 14:59:30 +01:00
standardci
a97be4c342 chore(release): publish new version
- @standardnotes/analytics@1.46.0
 - @standardnotes/api-gateway@1.36.8
 - @standardnotes/auth-server@1.49.11
 - @standardnotes/syncing-server@1.10.19
2022-11-04 13:28:39 +00:00
Karol Sójko
5902cbb621 feat(analytics): add payment success event handler 2022-11-04 14:26:47 +01:00
42 changed files with 875 additions and 11 deletions

View File

@@ -3,6 +3,36 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.50.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.49.0...@standardnotes/analytics@1.50.0) (2022-11-07)
### Features
* **analytics:** add handling subscription purchased events ([f1834d5](https://github.com/standardnotes/server/commit/f1834d58d2215c81322e82a0ec279617103b3260))
# [1.49.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.48.0...@standardnotes/analytics@1.49.0) (2022-11-07)
### Features
* **analytics:** add handling subscription refunded event ([197c991](https://github.com/standardnotes/server/commit/197c9914caf8fb31ce3ee69d05381d2a6416b366))
# [1.48.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.47.0...@standardnotes/analytics@1.48.0) (2022-11-07)
### Features
* **analytics:** add subscription renewed event handler ([2aa57f1](https://github.com/standardnotes/server/commit/2aa57f1f0ddace741b79e9375b87464eaaba6320))
# [1.47.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.46.0...@standardnotes/analytics@1.47.0) (2022-11-04)
### Features
* **analytics:** add subscription cancelled event handler ([037fb23](https://github.com/standardnotes/server/commit/037fb2398ae9aaa11682e1a8576bab28c69e0f9b))
# [1.46.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.45.0...@standardnotes/analytics@1.46.0) (2022-11-04)
### Features
* **analytics:** add payment success event handler ([5902cbb](https://github.com/standardnotes/server/commit/5902cbb6218a5b3982b4c56f8d6644f4f5bc6d32))
# [1.45.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.44.0...@standardnotes/analytics@1.45.0) (2022-11-04)
### Features

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/analytics",
"version": "1.45.0",
"version": "1.50.0",
"engines": {
"node": ">=14.0.0 <17.0.0"
},

View File

@@ -36,6 +36,11 @@ import { GetUserAnalyticsId } from '../Domain/UseCase/GetUserAnalyticsId/GetUser
import { UserRegisteredEventHandler } from '../Domain/Handler/UserRegisteredEventHandler'
import { AccountDeletionRequestedEventHandler } from '../Domain/Handler/AccountDeletionRequestedEventHandler'
import { PaymentFailedEventHandler } from '../Domain/Handler/PaymentFailedEventHandler'
import { PaymentSuccessEventHandler } from '../Domain/Handler/PaymentSuccessEventHandler'
import { SubscriptionCancelledEventHandler } from '../Domain/Handler/SubscriptionCancelledEventHandler'
import { SubscriptionRenewedEventHandler } from '../Domain/Handler/SubscriptionRenewedEventHandler'
import { SubscriptionRefundedEventHandler } from '../Domain/Handler/SubscriptionRefundedEventHandler'
import { SubscriptionPurchasedEventHandler } from '../Domain/Handler/SubscriptionPurchasedEventHandler'
// eslint-disable-next-line @typescript-eslint/no-var-requires
const newrelicFormatter = require('@newrelic/winston-enricher')
@@ -123,6 +128,19 @@ export class ContainerConfigLoader {
.bind<AccountDeletionRequestedEventHandler>(TYPES.AccountDeletionRequestedEventHandler)
.to(AccountDeletionRequestedEventHandler)
container.bind<PaymentFailedEventHandler>(TYPES.PaymentFailedEventHandler).to(PaymentFailedEventHandler)
container.bind<PaymentSuccessEventHandler>(TYPES.PaymentSuccessEventHandler).to(PaymentSuccessEventHandler)
container
.bind<SubscriptionCancelledEventHandler>(TYPES.SubscriptionCancelledEventHandler)
.to(SubscriptionCancelledEventHandler)
container
.bind<SubscriptionRenewedEventHandler>(TYPES.SubscriptionRenewedEventHandler)
.to(SubscriptionRenewedEventHandler)
container
.bind<SubscriptionRefundedEventHandler>(TYPES.SubscriptionRefundedEventHandler)
.to(SubscriptionRefundedEventHandler)
container
.bind<SubscriptionPurchasedEventHandler>(TYPES.SubscriptionPurchasedEventHandler)
.to(SubscriptionPurchasedEventHandler)
// Services
container.bind<DomainEventFactory>(TYPES.DomainEventFactory).to(DomainEventFactory)

View File

@@ -21,6 +21,11 @@ const TYPES = {
UserRegisteredEventHandler: Symbol.for('UserRegisteredEventHandler'),
AccountDeletionRequestedEventHandler: Symbol.for('AccountDeletionRequestedEventHandler'),
PaymentFailedEventHandler: Symbol.for('PaymentFailedEventHandler'),
PaymentSuccessEventHandler: Symbol.for('PaymentSuccessEventHandler'),
SubscriptionCancelledEventHandler: Symbol.for('SubscriptionCancelledEventHandler'),
SubscriptionRenewedEventHandler: Symbol.for('SubscriptionRenewedEventHandler'),
SubscriptionRefundedEventHandler: Symbol.for('SubscriptionRefundedEventHandler'),
SubscriptionPurchasedEventHandler: Symbol.for('SubscriptionPurchasedEventHandler'),
// Services
DomainEventPublisher: Symbol.for('DomainEventPublisher'),
DomainEventSubscriberFactory: Symbol.for('DomainEventSubscriberFactory'),

View File

@@ -0,0 +1,75 @@
import 'reflect-metadata'
import { PaymentSuccessEvent } from '@standardnotes/domain-events'
import { PaymentSuccessEventHandler } from './PaymentSuccessEventHandler'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
import { Logger } from 'winston'
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
import { Period } from '../Time/Period'
describe('PaymentSuccessEventHandler', () => {
let event: PaymentSuccessEvent
let getUserAnalyticsId: GetUserAnalyticsId
let analyticsStore: AnalyticsStoreInterface
let statisticsStore: StatisticsStoreInterface
let logger: Logger
const createHandler = () =>
new PaymentSuccessEventHandler(getUserAnalyticsId, analyticsStore, statisticsStore, logger)
beforeEach(() => {
getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
analyticsStore.markActivity = jest.fn()
statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
statisticsStore.incrementMeasure = jest.fn()
event = {} as jest.Mocked<PaymentSuccessEvent>
event.payload = {
userEmail: 'test@test.com',
amount: 12.45,
billingFrequency: 12,
paymentType: 'initial',
subscriptionName: 'PRO_PLAN',
}
logger = {} as jest.Mocked<Logger>
logger.warn = jest.fn()
})
it('should mark payment success for analytics', async () => {
await createHandler().handle(event)
expect(analyticsStore.markActivity).toHaveBeenCalled()
expect(statisticsStore.incrementMeasure).toHaveBeenNthCalledWith(
2,
'pro-subscription-initial-annual-payments-income',
12.45,
[Period.Today, Period.ThisWeek, Period.ThisMonth],
)
})
it('should mark non-detailed payment success statistics for analytics', async () => {
event.payload = {
userEmail: 'test@test.com',
amount: 12.45,
billingFrequency: 13,
paymentType: 'initial',
subscriptionName: 'PRO_PLAN',
}
await createHandler().handle(event)
expect(statisticsStore.incrementMeasure).toBeCalledTimes(1)
expect(statisticsStore.incrementMeasure).toHaveBeenNthCalledWith(1, 'income', 12.45, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
])
})
})

View File

@@ -0,0 +1,93 @@
import { PaymentType, SubscriptionBillingFrequency, SubscriptionName } from '@standardnotes/common'
import { DomainEventHandlerInterface, PaymentSuccessEvent } from '@standardnotes/domain-events'
import { inject, injectable } from 'inversify'
import { Logger } from 'winston'
import TYPES from '../../Bootstrap/Types'
import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
import { StatisticsMeasure } from '../Statistics/StatisticsMeasure'
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
import { Period } from '../Time/Period'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
@injectable()
export class PaymentSuccessEventHandler implements DomainEventHandlerInterface {
private readonly DETAILED_MEASURES = new Map([
[
SubscriptionName.PlusPlan,
new Map([
[
PaymentType.Initial,
new Map([
[SubscriptionBillingFrequency.Monthly, StatisticsMeasure.PlusSubscriptionInitialMonthlyPaymentsIncome],
[SubscriptionBillingFrequency.Annual, StatisticsMeasure.PlusSubscriptionInitialAnnualPaymentsIncome],
]),
],
[
PaymentType.Renewal,
new Map([
[SubscriptionBillingFrequency.Monthly, StatisticsMeasure.PlusSubscriptionRenewingMonthlyPaymentsIncome],
[SubscriptionBillingFrequency.Annual, StatisticsMeasure.PlusSubscriptionRenewingAnnualPaymentsIncome],
]),
],
]),
],
[
SubscriptionName.ProPlan,
new Map([
[
PaymentType.Initial,
new Map([
[SubscriptionBillingFrequency.Monthly, StatisticsMeasure.ProSubscriptionInitialMonthlyPaymentsIncome],
[SubscriptionBillingFrequency.Annual, StatisticsMeasure.ProSubscriptionInitialAnnualPaymentsIncome],
]),
],
[
PaymentType.Renewal,
new Map([
[SubscriptionBillingFrequency.Monthly, StatisticsMeasure.ProSubscriptionRenewingMonthlyPaymentsIncome],
[SubscriptionBillingFrequency.Annual, StatisticsMeasure.ProSubscriptionRenewingAnnualPaymentsIncome],
]),
],
]),
],
])
constructor(
@inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
@inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
@inject(TYPES.Logger) private logger: Logger,
) {}
async handle(event: PaymentSuccessEvent): Promise<void> {
const { analyticsId } = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
await this.analyticsStore.markActivity([AnalyticsActivity.PaymentSuccess], analyticsId, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
])
const statisticMeasures = [StatisticsMeasure.Income]
const detailedMeasure = this.DETAILED_MEASURES.get(event.payload.subscriptionName as SubscriptionName)
?.get(event.payload.paymentType as PaymentType)
?.get(event.payload.billingFrequency as SubscriptionBillingFrequency)
if (detailedMeasure !== undefined) {
statisticMeasures.push(detailedMeasure)
} else {
this.logger.warn(
`Could not find detailed measure for: subscription - ${event.payload.subscriptionName}, payment type - ${event.payload.paymentType}, billing frequency - ${event.payload.billingFrequency}`,
)
}
for (const measure of statisticMeasures) {
await this.statisticsStore.incrementMeasure(measure, event.payload.amount, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
])
}
}
}

View File

@@ -0,0 +1,69 @@
import 'reflect-metadata'
import { SubscriptionName } from '@standardnotes/common'
import { SubscriptionCancelledEvent } from '@standardnotes/domain-events'
import { SubscriptionCancelledEventHandler } from './SubscriptionCancelledEventHandler'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
import { StatisticsMeasure } from '../Statistics/StatisticsMeasure'
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
import { Period } from '../Time/Period'
describe('SubscriptionCancelledEventHandler', () => {
let event: SubscriptionCancelledEvent
let getUserAnalyticsId: GetUserAnalyticsId
let analyticsStore: AnalyticsStoreInterface
let statisticsStore: StatisticsStoreInterface
const createHandler = () => new SubscriptionCancelledEventHandler(getUserAnalyticsId, analyticsStore, statisticsStore)
beforeEach(() => {
getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
analyticsStore.markActivity = jest.fn()
statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
statisticsStore.incrementMeasure = jest.fn()
event = {} as jest.Mocked<SubscriptionCancelledEvent>
event.createdAt = new Date(1)
event.payload = {
subscriptionId: 1,
userEmail: 'test@test.com',
subscriptionName: SubscriptionName.ProPlan,
subscriptionCreatedAt: 1642395451515000,
subscriptionUpdatedAt: 1642395451515001,
lastPayedAt: 1642395451515001,
subscriptionEndsAt: 1642395451515000 + 10,
timestamp: 1,
offline: false,
replaced: false,
}
})
it('should track subscription cancelled statistics', async () => {
event.payload.timestamp = 1642395451516000
await createHandler().handle(event)
expect(analyticsStore.markActivity).toHaveBeenCalled()
expect(statisticsStore.incrementMeasure).toHaveBeenCalledWith(StatisticsMeasure.SubscriptionLength, 1000, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
])
})
it('should not track statistics for subscriptions that are in a legacy 5 year plan', async () => {
event.payload.timestamp = 1642395451516000
event.payload.subscriptionEndsAt = 1642395451515000 + 126_230_400_000_001
event.payload.subscriptionCreatedAt = 1642395451515000
await createHandler().handle(event)
expect(statisticsStore.incrementMeasure).not.toHaveBeenCalled()
})
})

View File

@@ -0,0 +1,60 @@
import { DomainEventHandlerInterface, SubscriptionCancelledEvent } from '@standardnotes/domain-events'
import { inject, injectable } from 'inversify'
import TYPES from '../../Bootstrap/Types'
import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
import { StatisticsMeasure } from '../Statistics/StatisticsMeasure'
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
import { Period } from '../Time/Period'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
@injectable()
export class SubscriptionCancelledEventHandler implements DomainEventHandlerInterface {
constructor(
@inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
@inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
) {}
async handle(event: SubscriptionCancelledEvent): Promise<void> {
const { analyticsId } = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionCancelled], analyticsId, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
])
await this.trackSubscriptionStatistics(event)
}
private async trackSubscriptionStatistics(event: SubscriptionCancelledEvent) {
if (this.isLegacy5yearSubscriptionPlan(event.payload.subscriptionEndsAt, event.payload.subscriptionCreatedAt)) {
return
}
const subscriptionLength = event.payload.timestamp - event.payload.subscriptionCreatedAt
await this.statisticsStore.incrementMeasure(StatisticsMeasure.SubscriptionLength, subscriptionLength, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
])
const remainingSubscriptionTime = event.payload.subscriptionEndsAt - event.payload.timestamp
const totalSubscriptionTime = event.payload.subscriptionEndsAt - event.payload.lastPayedAt
const remainingSubscriptionPercentage = Math.floor((remainingSubscriptionTime / totalSubscriptionTime) * 100)
await this.statisticsStore.incrementMeasure(
StatisticsMeasure.RemainingSubscriptionTimePercentage,
remainingSubscriptionPercentage,
[Period.Today, Period.ThisWeek, Period.ThisMonth],
)
}
private isLegacy5yearSubscriptionPlan(subscriptionEndsAt: number, subscriptionCreatedAt: number) {
const fourYearsInMicroseconds = 126_230_400_000_000
return subscriptionEndsAt - subscriptionCreatedAt > fourYearsInMicroseconds
}
}

View File

@@ -0,0 +1,71 @@
import 'reflect-metadata'
import { SubscriptionName } from '@standardnotes/common'
import { SubscriptionPurchasedEvent } from '@standardnotes/domain-events'
import { SubscriptionPurchasedEventHandler } from './SubscriptionPurchasedEventHandler'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
import { Period } from '../Time/Period'
describe('SubscriptionPurchasedEventHandler', () => {
let event: SubscriptionPurchasedEvent
let subscriptionExpiresAt: number
let getUserAnalyticsId: GetUserAnalyticsId
let analyticsStore: AnalyticsStoreInterface
let statisticsStore: StatisticsStoreInterface
const createHandler = () => new SubscriptionPurchasedEventHandler(getUserAnalyticsId, analyticsStore, statisticsStore)
beforeEach(() => {
statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
statisticsStore.incrementMeasure = jest.fn()
statisticsStore.setMeasure = jest.fn()
event = {} as jest.Mocked<SubscriptionPurchasedEvent>
event.createdAt = new Date(1)
event.payload = {
subscriptionId: 1,
userEmail: 'test@test.com',
subscriptionName: SubscriptionName.ProPlan,
subscriptionExpiresAt,
timestamp: 60,
offline: false,
discountCode: null,
limitedDiscountPurchased: false,
newSubscriber: true,
totalActiveSubscriptionsCount: 123,
userRegisteredAt: 23,
}
getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
analyticsStore.markActivity = jest.fn()
analyticsStore.unmarkActivity = jest.fn()
})
it('should mark subscription creation statistics', async () => {
await createHandler().handle(event)
expect(statisticsStore.incrementMeasure).toHaveBeenCalled()
})
it("should not measure registration to subscription time if this is not user's first subscription", async () => {
event.payload.newSubscriber = false
await createHandler().handle(event)
expect(statisticsStore.incrementMeasure).not.toHaveBeenCalled()
})
it('should update analytics on limited discount offer purchasing', async () => {
event.payload.limitedDiscountPurchased = true
await createHandler().handle(event)
expect(analyticsStore.markActivity).toHaveBeenCalledWith(['limited-discount-offer-purchased'], 3, [Period.Today])
})
})

View File

@@ -0,0 +1,58 @@
import { DomainEventHandlerInterface, SubscriptionPurchasedEvent } from '@standardnotes/domain-events'
import { inject, injectable } from 'inversify'
import TYPES from '../../Bootstrap/Types'
import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
import { StatisticsMeasure } from '../Statistics/StatisticsMeasure'
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
import { Period } from '../Time/Period'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
@injectable()
export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInterface {
constructor(
@inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
@inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
) {}
async handle(event: SubscriptionPurchasedEvent): Promise<void> {
const { analyticsId } = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionPurchased], analyticsId, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
])
await this.analyticsStore.unmarkActivity(
[AnalyticsActivity.ExistingCustomersChurn, AnalyticsActivity.NewCustomersChurn],
analyticsId,
[Period.Today, Period.ThisWeek, Period.ThisMonth],
)
if (event.payload.limitedDiscountPurchased) {
await this.analyticsStore.markActivity([AnalyticsActivity.LimitedDiscountOfferPurchased], analyticsId, [
Period.Today,
])
}
if (event.payload.newSubscriber) {
await this.statisticsStore.incrementMeasure(
StatisticsMeasure.RegistrationToSubscriptionTime,
event.payload.timestamp - event.payload.userRegisteredAt,
[Period.Today, Period.ThisWeek, Period.ThisMonth],
)
await this.statisticsStore.incrementMeasure(StatisticsMeasure.NewCustomers, 1, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
Period.ThisYear,
])
await this.statisticsStore.setMeasure(
StatisticsMeasure.TotalCustomers,
event.payload.totalActiveSubscriptionsCount,
[Period.Today, Period.ThisWeek, Period.ThisMonth, Period.ThisYear],
)
}
}
}

View File

@@ -0,0 +1,78 @@
import 'reflect-metadata'
import { SubscriptionName } from '@standardnotes/common'
import { SubscriptionRefundedEvent } from '@standardnotes/domain-events'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
import { SubscriptionRefundedEventHandler } from './SubscriptionRefundedEventHandler'
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
import { Period } from '../Time/Period'
describe('SubscriptionRefundedEventHandler', () => {
let event: SubscriptionRefundedEvent
let getUserAnalyticsId: GetUserAnalyticsId
let analyticsStore: AnalyticsStoreInterface
let statisticsStore: StatisticsStoreInterface
const createHandler = () => new SubscriptionRefundedEventHandler(getUserAnalyticsId, analyticsStore, statisticsStore)
beforeEach(() => {
event = {} as jest.Mocked<SubscriptionRefundedEvent>
event.createdAt = new Date(1)
event.payload = {
subscriptionId: 1,
userEmail: 'test@test.com',
subscriptionName: SubscriptionName.PlusPlan,
timestamp: 1,
offline: false,
userExistingSubscriptionsCount: 3,
totalActiveSubscriptionsCount: 1,
}
getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
analyticsStore.markActivity = jest.fn()
analyticsStore.wasActivityDone = jest.fn().mockReturnValue(true)
statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
statisticsStore.setMeasure = jest.fn()
})
it('should mark churn for new customer', async () => {
event.payload.userExistingSubscriptionsCount = 1
await createHandler().handle(event)
expect(analyticsStore.markActivity).toHaveBeenCalledWith([AnalyticsActivity.SubscriptionRefunded], 3, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
])
expect(analyticsStore.markActivity).toHaveBeenCalledWith([AnalyticsActivity.NewCustomersChurn], 3, [
Period.ThisMonth,
])
})
it('should mark churn for existing customer', async () => {
await createHandler().handle(event)
expect(analyticsStore.markActivity).toHaveBeenCalledWith([AnalyticsActivity.ExistingCustomersChurn], 3, [
Period.ThisMonth,
])
})
it('should not mark churn if customer did not purchase subscription in defined analytic periods', async () => {
analyticsStore.wasActivityDone = jest.fn().mockReturnValue(false)
await createHandler().handle(event)
expect(analyticsStore.markActivity).not.toHaveBeenCalledWith([AnalyticsActivity.ExistingCustomersChurn], 3, [
Period.ThisMonth,
])
})
})

View File

@@ -0,0 +1,54 @@
import { DomainEventHandlerInterface, SubscriptionRefundedEvent } from '@standardnotes/domain-events'
import { inject, injectable } from 'inversify'
import TYPES from '../../Bootstrap/Types'
import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
import { StatisticsMeasure } from '../Statistics/StatisticsMeasure'
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
import { Period } from '../Time/Period'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
@injectable()
export class SubscriptionRefundedEventHandler implements DomainEventHandlerInterface {
constructor(
@inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
@inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
) {}
async handle(event: SubscriptionRefundedEvent): Promise<void> {
const { analyticsId } = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionRefunded], analyticsId, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
])
await this.markChurnActivity(analyticsId, event)
}
private async markChurnActivity(analyticsId: number, event: SubscriptionRefundedEvent): Promise<void> {
const churnActivity =
event.payload.userExistingSubscriptionsCount > 1
? AnalyticsActivity.ExistingCustomersChurn
: AnalyticsActivity.NewCustomersChurn
for (const period of [Period.ThisMonth, Period.ThisWeek, Period.Today]) {
const customerPurchasedInPeriod = await this.analyticsStore.wasActivityDone(
AnalyticsActivity.SubscriptionPurchased,
analyticsId,
period,
)
if (customerPurchasedInPeriod) {
await this.analyticsStore.markActivity([churnActivity], analyticsId, [period])
}
}
await this.statisticsStore.setMeasure(
StatisticsMeasure.TotalCustomers,
event.payload.totalActiveSubscriptionsCount,
[Period.Today, Period.ThisWeek, Period.ThisMonth, Period.ThisYear],
)
}
}

View File

@@ -0,0 +1,43 @@
import 'reflect-metadata'
import { SubscriptionName } from '@standardnotes/common'
import { SubscriptionRenewedEvent } from '@standardnotes/domain-events'
import { SubscriptionRenewedEventHandler } from './SubscriptionRenewedEventHandler'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
describe('SubscriptionRenewedEventHandler', () => {
let event: SubscriptionRenewedEvent
let getUserAnalyticsId: GetUserAnalyticsId
let analyticsStore: AnalyticsStoreInterface
const createHandler = () => new SubscriptionRenewedEventHandler(getUserAnalyticsId, analyticsStore)
beforeEach(() => {
event = {} as jest.Mocked<SubscriptionRenewedEvent>
event.createdAt = new Date(1)
event.payload = {
subscriptionId: 1,
userEmail: 'test@test.com',
subscriptionName: SubscriptionName.ProPlan,
subscriptionExpiresAt: 2,
timestamp: 1,
offline: false,
}
getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
analyticsStore.markActivity = jest.fn()
analyticsStore.unmarkActivity = jest.fn()
})
it('should track subscription renewed statistics', async () => {
await createHandler().handle(event)
expect(analyticsStore.markActivity).toHaveBeenCalled()
expect(analyticsStore.unmarkActivity).toHaveBeenCalled()
})
})

View File

@@ -0,0 +1,30 @@
import { DomainEventHandlerInterface, SubscriptionRenewedEvent } from '@standardnotes/domain-events'
import { inject, injectable } from 'inversify'
import TYPES from '../../Bootstrap/Types'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
import { Period } from '../Time/Period'
@injectable()
export class SubscriptionRenewedEventHandler implements DomainEventHandlerInterface {
constructor(
@inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
) {}
async handle(event: SubscriptionRenewedEvent): Promise<void> {
const { analyticsId } = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionRenewed], analyticsId, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
])
await this.analyticsStore.unmarkActivity(
[AnalyticsActivity.ExistingCustomersChurn, AnalyticsActivity.NewCustomersChurn],
analyticsId,
[Period.Today, Period.ThisWeek, Period.ThisMonth],
)
}
}

View File

@@ -3,6 +3,26 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.36.12](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.36.11...@standardnotes/api-gateway@1.36.12) (2022-11-07)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.36.11](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.36.10...@standardnotes/api-gateway@1.36.11) (2022-11-07)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.36.10](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.36.9...@standardnotes/api-gateway@1.36.10) (2022-11-07)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.36.9](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.36.8...@standardnotes/api-gateway@1.36.9) (2022-11-04)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.36.8](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.36.7...@standardnotes/api-gateway@1.36.8) (2022-11-04)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.36.7](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.36.6...@standardnotes/api-gateway@1.36.7) (2022-11-04)
**Note:** Version bump only for package @standardnotes/api-gateway

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api-gateway",
"version": "1.36.7",
"version": "1.36.12",
"engines": {
"node": ">=16.0.0 <17.0.0"
},

View File

@@ -3,6 +3,32 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.51.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.50.0...@standardnotes/auth-server@1.51.0) (2022-11-07)
### Features
* **analytics:** add handling subscription purchased events ([f1834d5](https://github.com/standardnotes/server/commit/f1834d58d2215c81322e82a0ec279617103b3260))
# [1.50.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.49.13...@standardnotes/auth-server@1.50.0) (2022-11-07)
### Features
* **analytics:** add handling subscription refunded event ([197c991](https://github.com/standardnotes/server/commit/197c9914caf8fb31ce3ee69d05381d2a6416b366))
## [1.49.13](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.49.12...@standardnotes/auth-server@1.49.13) (2022-11-07)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.49.12](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.49.11...@standardnotes/auth-server@1.49.12) (2022-11-04)
### Bug Fixes
* **auth:** event specs ([a3be4b0](https://github.com/standardnotes/server/commit/a3be4b063d679c125d152e7025750a6ca1d5d7a1))
## [1.49.11](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.49.10...@standardnotes/auth-server@1.49.11) (2022-11-04)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.49.10](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.49.9...@standardnotes/auth-server@1.49.10) (2022-11-04)
**Note:** Version bump only for package @standardnotes/auth-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/auth-server",
"version": "1.49.10",
"version": "1.51.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},

View File

@@ -80,6 +80,7 @@ describe('AccountDeletionRequestedEventHandler', () => {
event.createdAt = new Date(1)
event.payload = {
userUuid: '1-2-3',
userCreatedAtTimestamp: 1,
regularSubscriptionUuid: '2-3-4',
}

View File

@@ -71,6 +71,10 @@ describe('SubscriptionCancelledEventHandler', () => {
timestamp,
offline: false,
replaced: false,
subscriptionCreatedAt: 1,
subscriptionEndsAt: 2,
subscriptionUpdatedAt: 2,
lastPayedAt: 1,
}
})

View File

@@ -105,6 +105,10 @@ describe('SubscriptionPurchasedEventHandler', () => {
timestamp: dayjs.utc().valueOf(),
offline: false,
discountCode: null,
limitedDiscountPurchased: false,
newSubscriber: true,
totalActiveSubscriptionsCount: 123,
userRegisteredAt: dayjs.utc().valueOf() - 23,
}
subscriptionSettingService = {} as jest.Mocked<SubscriptionSettingServiceInterface>

View File

@@ -80,6 +80,8 @@ describe('SubscriptionRefundedEventHandler', () => {
subscriptionName: SubscriptionName.PlusPlan,
timestamp,
offline: false,
userExistingSubscriptionsCount: 3,
totalActiveSubscriptionsCount: 1,
}
getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.9.11](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.10...@standardnotes/domain-events-infra@1.9.11) (2022-11-07)
**Note:** Version bump only for package @standardnotes/domain-events-infra
## [1.9.10](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.9...@standardnotes/domain-events-infra@1.9.10) (2022-11-07)
**Note:** Version bump only for package @standardnotes/domain-events-infra
## [1.9.9](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.8...@standardnotes/domain-events-infra@1.9.9) (2022-11-04)
**Note:** Version bump only for package @standardnotes/domain-events-infra
## [1.9.8](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.7...@standardnotes/domain-events-infra@1.9.8) (2022-11-04)
**Note:** Version bump only for package @standardnotes/domain-events-infra

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-events-infra",
"version": "1.9.8",
"version": "1.9.11",
"engines": {
"node": ">=16.0.0 <17.0.0"
},

View File

@@ -3,6 +3,24 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.77.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.76.0...@standardnotes/domain-events@2.77.0) (2022-11-07)
### Features
* **analytics:** add handling subscription purchased events ([f1834d5](https://github.com/standardnotes/server/commit/f1834d58d2215c81322e82a0ec279617103b3260))
# [2.76.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.75.0...@standardnotes/domain-events@2.76.0) (2022-11-07)
### Features
* **analytics:** add handling subscription refunded event ([197c991](https://github.com/standardnotes/server/commit/197c9914caf8fb31ce3ee69d05381d2a6416b366))
# [2.75.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.74.1...@standardnotes/domain-events@2.75.0) (2022-11-04)
### Features
* **analytics:** add subscription cancelled event handler ([037fb23](https://github.com/standardnotes/server/commit/037fb2398ae9aaa11682e1a8576bab28c69e0f9b))
## [2.74.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.74.0...@standardnotes/domain-events@2.74.1) (2022-11-04)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-events",
"version": "2.74.1",
"version": "2.77.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},

View File

@@ -4,6 +4,10 @@ export interface SubscriptionCancelledEventPayload {
userEmail: string
subscriptionId: number
subscriptionName: SubscriptionName
subscriptionCreatedAt: number
subscriptionUpdatedAt: number
lastPayedAt: number
subscriptionEndsAt: number
timestamp: number
offline: boolean
replaced: boolean

View File

@@ -8,4 +8,8 @@ export interface SubscriptionPurchasedEventPayload {
timestamp: number
offline: boolean
discountCode: string | null
limitedDiscountPurchased: boolean
newSubscriber: boolean
totalActiveSubscriptionsCount: number
userRegisteredAt: number
}

View File

@@ -4,6 +4,8 @@ export interface SubscriptionRefundedEventPayload {
userEmail: string
subscriptionId: number
subscriptionName: SubscriptionName
userExistingSubscriptionsCount: number
totalActiveSubscriptionsCount: number
timestamp: number
offline: boolean
}

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.6.6](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.6.5...@standardnotes/event-store@1.6.6) (2022-11-07)
**Note:** Version bump only for package @standardnotes/event-store
## [1.6.5](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.6.4...@standardnotes/event-store@1.6.5) (2022-11-07)
**Note:** Version bump only for package @standardnotes/event-store
## [1.6.4](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.6.3...@standardnotes/event-store@1.6.4) (2022-11-04)
**Note:** Version bump only for package @standardnotes/event-store
## [1.6.3](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.6.2...@standardnotes/event-store@1.6.3) (2022-11-04)
**Note:** Version bump only for package @standardnotes/event-store

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/event-store",
"version": "1.6.3",
"version": "1.6.6",
"description": "Event Store Service",
"private": true,
"main": "dist/src/index.js",

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.8.6](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.8.5...@standardnotes/files-server@1.8.6) (2022-11-07)
**Note:** Version bump only for package @standardnotes/files-server
## [1.8.5](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.8.4...@standardnotes/files-server@1.8.5) (2022-11-07)
**Note:** Version bump only for package @standardnotes/files-server
## [1.8.4](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.8.3...@standardnotes/files-server@1.8.4) (2022-11-04)
**Note:** Version bump only for package @standardnotes/files-server
## [1.8.3](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.8.2...@standardnotes/files-server@1.8.3) (2022-11-04)
**Note:** Version bump only for package @standardnotes/files-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files-server",
"version": "1.8.3",
"version": "1.8.6",
"engines": {
"node": ">=16.0.0 <17.0.0"
},

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.13.7](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.13.6...@standardnotes/scheduler-server@1.13.7) (2022-11-07)
**Note:** Version bump only for package @standardnotes/scheduler-server
## [1.13.6](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.13.5...@standardnotes/scheduler-server@1.13.6) (2022-11-07)
**Note:** Version bump only for package @standardnotes/scheduler-server
## [1.13.5](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.13.4...@standardnotes/scheduler-server@1.13.5) (2022-11-04)
**Note:** Version bump only for package @standardnotes/scheduler-server
## [1.13.4](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.13.3...@standardnotes/scheduler-server@1.13.4) (2022-11-04)
**Note:** Version bump only for package @standardnotes/scheduler-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/scheduler-server",
"version": "1.13.4",
"version": "1.13.7",
"engines": {
"node": ">=16.0.0 <17.0.0"
},

View File

@@ -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.10.23](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.10.22...@standardnotes/syncing-server@1.10.23) (2022-11-07)
**Note:** Version bump only for package @standardnotes/syncing-server
## [1.10.22](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.10.21...@standardnotes/syncing-server@1.10.22) (2022-11-07)
**Note:** Version bump only for package @standardnotes/syncing-server
## [1.10.21](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.10.20...@standardnotes/syncing-server@1.10.21) (2022-11-07)
**Note:** Version bump only for package @standardnotes/syncing-server
## [1.10.20](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.10.19...@standardnotes/syncing-server@1.10.20) (2022-11-04)
### Bug Fixes
* **syncing-server:** event specs ([182512d](https://github.com/standardnotes/syncing-server-js/commit/182512d07c68ae644594404724bf1a0f5e0c71ae))
## [1.10.19](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.10.18...@standardnotes/syncing-server@1.10.19) (2022-11-04)
**Note:** Version bump only for package @standardnotes/syncing-server
## [1.10.18](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.10.17...@standardnotes/syncing-server@1.10.18) (2022-11-04)
**Note:** Version bump only for package @standardnotes/syncing-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/syncing-server",
"version": "1.10.18",
"version": "1.10.23",
"engines": {
"node": ">=16.0.0 <17.0.0"
},

View File

@@ -31,6 +31,7 @@ describe('AccountDeletionRequestedEventHandler', () => {
event.createdAt = new Date(1)
event.payload = {
userUuid: '2-3-4',
userCreatedAtTimestamp: 1,
regularSubscriptionUuid: '1-2-3',
}
})

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.4.6](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.4.5...@standardnotes/websockets-server@1.4.6) (2022-11-07)
**Note:** Version bump only for package @standardnotes/websockets-server
## [1.4.5](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.4.4...@standardnotes/websockets-server@1.4.5) (2022-11-07)
**Note:** Version bump only for package @standardnotes/websockets-server
## [1.4.4](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.4.3...@standardnotes/websockets-server@1.4.4) (2022-11-04)
**Note:** Version bump only for package @standardnotes/websockets-server
## [1.4.3](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.4.2...@standardnotes/websockets-server@1.4.3) (2022-11-04)
**Note:** Version bump only for package @standardnotes/websockets-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/websockets-server",
"version": "1.4.3",
"version": "1.4.6",
"engines": {
"node": ">=16.0.0 <17.0.0"
},

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.17.6](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.5...@standardnotes/workspace-server@1.17.6) (2022-11-07)
**Note:** Version bump only for package @standardnotes/workspace-server
## [1.17.5](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.4...@standardnotes/workspace-server@1.17.5) (2022-11-07)
**Note:** Version bump only for package @standardnotes/workspace-server
## [1.17.4](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.3...@standardnotes/workspace-server@1.17.4) (2022-11-04)
**Note:** Version bump only for package @standardnotes/workspace-server
## [1.17.3](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.2...@standardnotes/workspace-server@1.17.3) (2022-11-04)
**Note:** Version bump only for package @standardnotes/workspace-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/workspace-server",
"version": "1.17.3",
"version": "1.17.6",
"engines": {
"node": ">=16.0.0 <17.0.0"
},