mirror of
https://github.com/standardnotes/server
synced 2026-01-26 14:01:08 -05:00
Compare commits
15 Commits
@standardn
...
@standardn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c6cf9651d | ||
|
|
8668fec33d | ||
|
|
76e34131fb | ||
|
|
3c40ee4b4a | ||
|
|
5abd7ae32c | ||
|
|
09b3f9a0d7 | ||
|
|
19455ba6a7 | ||
|
|
7d042689f0 | ||
|
|
f43fbf1584 | ||
|
|
24c0cb8366 | ||
|
|
2236cc3828 | ||
|
|
039d44718a | ||
|
|
f075cd8c4d | ||
|
|
ea0f3e8999 | ||
|
|
e7736bba25 |
@@ -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.34.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.33.0...@standardnotes/analytics@1.34.0) (2022-10-04)
|
||||
|
||||
### Features
|
||||
|
||||
* **analytics:** add new statistics measures for income ([19455ba](https://github.com/standardnotes/server/commit/19455ba6a7d84a389830c728c3dfea550b156985))
|
||||
|
||||
# [1.33.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.32.0...@standardnotes/analytics@1.33.0) (2022-10-03)
|
||||
|
||||
### Features
|
||||
|
||||
* add calculating monthly churn rate ([f075cd8](https://github.com/standardnotes/server/commit/f075cd8c4dfc411ba513dfec21bb84c03b238254))
|
||||
|
||||
# [1.32.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.31.1...@standardnotes/analytics@1.32.0) (2022-09-30)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/analytics",
|
||||
"version": "1.32.0",
|
||||
"version": "1.34.0",
|
||||
"engines": {
|
||||
"node": ">=14.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -12,7 +12,7 @@ export interface AnalyticsStoreInterface {
|
||||
secondActivity: AnalyticsActivity
|
||||
secondActivityPeriodKey: string
|
||||
}): Promise<number>
|
||||
calculateActivityTotalCount(activity: AnalyticsActivity, period: Period): Promise<number>
|
||||
calculateActivityTotalCount(activity: AnalyticsActivity, periodOrPeriodKey: Period | string): Promise<number>
|
||||
calculateActivityChangesTotalCount(
|
||||
activity: AnalyticsActivity,
|
||||
period: Period,
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
export enum StatisticsMeasure {
|
||||
Income = 'income',
|
||||
PlusSubscriptionInitialMonthlyPaymentsIncome = 'plus-subscription-initial-monthly-payments-income',
|
||||
ProSubscriptionInitialMonthlyPaymentsIncome = 'pro-subscription-initial-monthly-payments-income',
|
||||
PlusSubscriptionInitialAnnualPaymentsIncome = 'plus-subscription-initial-annual-payments-income',
|
||||
ProSubscriptionInitialAnnualPaymentsIncome = 'pro-subscription-initial-annual-payments-income',
|
||||
PlusSubscriptionRenewingMonthlyPaymentsIncome = 'plus-subscription-renewing-monthly-payments-income',
|
||||
ProSubscriptionRenewingMonthlyPaymentsIncome = 'pro-subscription-renewing-monthly-payments-income',
|
||||
PlusSubscriptionRenewingAnnualPaymentsIncome = 'plus-subscription-renewing-annual-payments-income',
|
||||
ProSubscriptionRenewingAnnualPaymentsIncome = 'pro-subscription-renewing-annual-payments-income',
|
||||
SubscriptionLength = 'subscription-length',
|
||||
RegistrationLength = 'registration-length',
|
||||
RegistrationToSubscriptionTime = 'registration-to-subscription-time',
|
||||
|
||||
@@ -11,5 +11,5 @@ export interface StatisticsStoreInterface {
|
||||
incrementMeasure(measure: StatisticsMeasure, value: number, periods: Period[]): Promise<void>
|
||||
setMeasure(measure: StatisticsMeasure, value: number, periods: Period[]): Promise<void>
|
||||
getMeasureAverage(measure: StatisticsMeasure, period: Period): Promise<number>
|
||||
getMeasureTotal(measure: StatisticsMeasure, period: Period): Promise<number>
|
||||
getMeasureTotal(measure: StatisticsMeasure, periodOrPeriodKey: Period | string): Promise<number>
|
||||
}
|
||||
|
||||
@@ -14,4 +14,16 @@ export enum Period {
|
||||
Q2ThisYear,
|
||||
Q3ThisYear,
|
||||
Q4ThisYear,
|
||||
JanuaryThisYear,
|
||||
FebruaryThisYear,
|
||||
MarchThisYear,
|
||||
AprilThisYear,
|
||||
MayThisYear,
|
||||
JuneThisYear,
|
||||
JulyThisYear,
|
||||
AugustThisYear,
|
||||
SeptemberThisYear,
|
||||
OctoberThisYear,
|
||||
NovemberThisYear,
|
||||
DecemberThisYear,
|
||||
}
|
||||
|
||||
@@ -3,6 +3,20 @@ import { PeriodKeyGenerator } from './PeriodKeyGenerator'
|
||||
|
||||
describe('PeriodKeyGenerator', () => {
|
||||
const createGenerator = () => new PeriodKeyGenerator()
|
||||
const months = [
|
||||
Period.JanuaryThisYear,
|
||||
Period.FebruaryThisYear,
|
||||
Period.MarchThisYear,
|
||||
Period.AprilThisYear,
|
||||
Period.MayThisYear,
|
||||
Period.JuneThisYear,
|
||||
Period.JulyThisYear,
|
||||
Period.AugustThisYear,
|
||||
Period.SeptemberThisYear,
|
||||
Period.OctoberThisYear,
|
||||
Period.NovemberThisYear,
|
||||
Period.DecemberThisYear,
|
||||
]
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers()
|
||||
@@ -48,6 +62,23 @@ describe('PeriodKeyGenerator', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('should generate period keys for this year', () => {
|
||||
expect(createGenerator().getDiscretePeriodKeys(Period.ThisYear)).toEqual([
|
||||
'2022-1',
|
||||
'2022-2',
|
||||
'2022-3',
|
||||
'2022-4',
|
||||
'2022-5',
|
||||
'2022-6',
|
||||
'2022-7',
|
||||
'2022-8',
|
||||
'2022-9',
|
||||
'2022-10',
|
||||
'2022-11',
|
||||
'2022-12',
|
||||
])
|
||||
})
|
||||
|
||||
it('should generate period keys for last 7 days', () => {
|
||||
expect(createGenerator().getDiscretePeriodKeys(Period.Last7Days)).toEqual([
|
||||
'2022-5-17',
|
||||
@@ -60,6 +91,81 @@ describe('PeriodKeyGenerator', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('should generate period keys for this month', () => {
|
||||
expect(createGenerator().getDiscretePeriodKeys(Period.ThisMonth)).toEqual([
|
||||
'2022-5-1',
|
||||
'2022-5-2',
|
||||
'2022-5-3',
|
||||
'2022-5-4',
|
||||
'2022-5-5',
|
||||
'2022-5-6',
|
||||
'2022-5-7',
|
||||
'2022-5-8',
|
||||
'2022-5-9',
|
||||
'2022-5-10',
|
||||
'2022-5-11',
|
||||
'2022-5-12',
|
||||
'2022-5-13',
|
||||
'2022-5-14',
|
||||
'2022-5-15',
|
||||
'2022-5-16',
|
||||
'2022-5-17',
|
||||
'2022-5-18',
|
||||
'2022-5-19',
|
||||
'2022-5-20',
|
||||
'2022-5-21',
|
||||
'2022-5-22',
|
||||
'2022-5-23',
|
||||
'2022-5-24',
|
||||
'2022-5-25',
|
||||
'2022-5-26',
|
||||
'2022-5-27',
|
||||
'2022-5-28',
|
||||
'2022-5-29',
|
||||
'2022-5-30',
|
||||
'2022-5-31',
|
||||
])
|
||||
})
|
||||
|
||||
it('should generate period keys for specific month', () => {
|
||||
expect(createGenerator().getDiscretePeriodKeys(Period.FebruaryThisYear)).toEqual([
|
||||
'2022-2-1',
|
||||
'2022-2-2',
|
||||
'2022-2-3',
|
||||
'2022-2-4',
|
||||
'2022-2-5',
|
||||
'2022-2-6',
|
||||
'2022-2-7',
|
||||
'2022-2-8',
|
||||
'2022-2-9',
|
||||
'2022-2-10',
|
||||
'2022-2-11',
|
||||
'2022-2-12',
|
||||
'2022-2-13',
|
||||
'2022-2-14',
|
||||
'2022-2-15',
|
||||
'2022-2-16',
|
||||
'2022-2-17',
|
||||
'2022-2-18',
|
||||
'2022-2-19',
|
||||
'2022-2-20',
|
||||
'2022-2-21',
|
||||
'2022-2-22',
|
||||
'2022-2-23',
|
||||
'2022-2-24',
|
||||
'2022-2-25',
|
||||
'2022-2-26',
|
||||
'2022-2-27',
|
||||
'2022-2-28',
|
||||
])
|
||||
})
|
||||
|
||||
it('should generate period keys for specific months', () => {
|
||||
for (const month of months) {
|
||||
expect(createGenerator().getDiscretePeriodKeys(month).length >= 28).toBeTruthy()
|
||||
}
|
||||
})
|
||||
|
||||
it('should generate period keys for Q1', () => {
|
||||
expect(createGenerator().getDiscretePeriodKeys(Period.Q1ThisYear)).toEqual(['2022-1', '2022-2', '2022-3'])
|
||||
})
|
||||
@@ -76,6 +182,10 @@ describe('PeriodKeyGenerator', () => {
|
||||
expect(createGenerator().getDiscretePeriodKeys(Period.Q4ThisYear)).toEqual(['2022-10', '2022-11', '2022-12'])
|
||||
})
|
||||
|
||||
it('should generate a period key for this year', () => {
|
||||
expect(createGenerator().getPeriodKey(Period.ThisYear)).toEqual('2022')
|
||||
})
|
||||
|
||||
it('should generate a period key for today', () => {
|
||||
expect(createGenerator().getPeriodKey(Period.Today)).toEqual('2022-5-24')
|
||||
})
|
||||
@@ -104,6 +214,12 @@ describe('PeriodKeyGenerator', () => {
|
||||
expect(createGenerator().getPeriodKey(Period.ThisMonth)).toEqual('2022-5')
|
||||
})
|
||||
|
||||
it('should generate a period key for each month', () => {
|
||||
for (let i = 0; i < months.length; i++) {
|
||||
expect(createGenerator().getPeriodKey(months[i])).toEqual(`2022-${i + 1}`)
|
||||
}
|
||||
})
|
||||
|
||||
it('should generate a period key for last month', () => {
|
||||
expect(createGenerator().getPeriodKey(Period.LastMonth)).toEqual('2022-4')
|
||||
})
|
||||
@@ -129,4 +245,19 @@ describe('PeriodKeyGenerator', () => {
|
||||
|
||||
expect(error).not.toBeNull()
|
||||
})
|
||||
|
||||
it('should convert period key to period', () => {
|
||||
expect(createGenerator().convertPeriodKeyToPeriod('2022-1')).toEqual(Period.JanuaryThisYear)
|
||||
expect(createGenerator().convertPeriodKeyToPeriod('2022-2')).toEqual(Period.FebruaryThisYear)
|
||||
expect(createGenerator().convertPeriodKeyToPeriod('2022-3')).toEqual(Period.MarchThisYear)
|
||||
expect(createGenerator().convertPeriodKeyToPeriod('2022-4')).toEqual(Period.AprilThisYear)
|
||||
expect(createGenerator().convertPeriodKeyToPeriod('2022-5')).toEqual(Period.MayThisYear)
|
||||
expect(createGenerator().convertPeriodKeyToPeriod('2022-6')).toEqual(Period.JuneThisYear)
|
||||
expect(createGenerator().convertPeriodKeyToPeriod('2022-7')).toEqual(Period.JulyThisYear)
|
||||
expect(createGenerator().convertPeriodKeyToPeriod('2022-8')).toEqual(Period.AugustThisYear)
|
||||
expect(createGenerator().convertPeriodKeyToPeriod('2022-9')).toEqual(Period.SeptemberThisYear)
|
||||
expect(createGenerator().convertPeriodKeyToPeriod('2022-10')).toEqual(Period.OctoberThisYear)
|
||||
expect(createGenerator().convertPeriodKeyToPeriod('2022-11')).toEqual(Period.NovemberThisYear)
|
||||
expect(createGenerator().convertPeriodKeyToPeriod('2022-12')).toEqual(Period.DecemberThisYear)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,6 +2,28 @@ import { Period } from './Period'
|
||||
import { PeriodKeyGeneratorInterface } from './PeriodKeyGeneratorInterface'
|
||||
|
||||
export class PeriodKeyGenerator implements PeriodKeyGeneratorInterface {
|
||||
private readonly MONTHS = [
|
||||
Period.JanuaryThisYear,
|
||||
Period.FebruaryThisYear,
|
||||
Period.MarchThisYear,
|
||||
Period.AprilThisYear,
|
||||
Period.MayThisYear,
|
||||
Period.JuneThisYear,
|
||||
Period.JulyThisYear,
|
||||
Period.AugustThisYear,
|
||||
Period.SeptemberThisYear,
|
||||
Period.OctoberThisYear,
|
||||
Period.NovemberThisYear,
|
||||
Period.DecemberThisYear,
|
||||
]
|
||||
|
||||
convertPeriodKeyToPeriod(periodKey: string): Period {
|
||||
const date = new Date(periodKey)
|
||||
const month = this.getMonth(date)
|
||||
|
||||
return this.MONTHS[+month - 1]
|
||||
}
|
||||
|
||||
getDiscretePeriodKeys(period: Period): string[] {
|
||||
const periodKeys = []
|
||||
|
||||
@@ -26,6 +48,23 @@ export class PeriodKeyGenerator implements PeriodKeyGeneratorInterface {
|
||||
return this.generateMonthlyKeysRange(6, 9)
|
||||
case Period.Q4ThisYear:
|
||||
return this.generateMonthlyKeysRange(9, 12)
|
||||
case Period.ThisYear:
|
||||
return this.generateMonthlyKeysRange(0, 12)
|
||||
case Period.ThisMonth:
|
||||
return this.generateDailyKeysRange()
|
||||
case Period.JanuaryThisYear:
|
||||
case Period.FebruaryThisYear:
|
||||
case Period.MarchThisYear:
|
||||
case Period.AprilThisYear:
|
||||
case Period.MayThisYear:
|
||||
case Period.JuneThisYear:
|
||||
case Period.JulyThisYear:
|
||||
case Period.AugustThisYear:
|
||||
case Period.SeptemberThisYear:
|
||||
case Period.OctoberThisYear:
|
||||
case Period.NovemberThisYear:
|
||||
case Period.DecemberThisYear:
|
||||
return this.generateDailyKeysRange(period - 15)
|
||||
default:
|
||||
throw new Error(`Unsuporrted period: ${period}`)
|
||||
}
|
||||
@@ -51,6 +90,30 @@ export class PeriodKeyGenerator implements PeriodKeyGeneratorInterface {
|
||||
return this.getMonthlyKey(this.getLastMonthDate())
|
||||
case Period.ThisYear:
|
||||
return this.getYearlyKey()
|
||||
case Period.JanuaryThisYear:
|
||||
return this.generateMonthlyKeysRange(0, 1)[0]
|
||||
case Period.FebruaryThisYear:
|
||||
return this.generateMonthlyKeysRange(1, 2)[0]
|
||||
case Period.MarchThisYear:
|
||||
return this.generateMonthlyKeysRange(2, 3)[0]
|
||||
case Period.AprilThisYear:
|
||||
return this.generateMonthlyKeysRange(3, 4)[0]
|
||||
case Period.MayThisYear:
|
||||
return this.generateMonthlyKeysRange(4, 5)[0]
|
||||
case Period.JuneThisYear:
|
||||
return this.generateMonthlyKeysRange(5, 6)[0]
|
||||
case Period.JulyThisYear:
|
||||
return this.generateMonthlyKeysRange(6, 7)[0]
|
||||
case Period.AugustThisYear:
|
||||
return this.generateMonthlyKeysRange(7, 8)[0]
|
||||
case Period.SeptemberThisYear:
|
||||
return this.generateMonthlyKeysRange(8, 9)[0]
|
||||
case Period.OctoberThisYear:
|
||||
return this.generateMonthlyKeysRange(9, 10)[0]
|
||||
case Period.NovemberThisYear:
|
||||
return this.generateMonthlyKeysRange(10, 11)[0]
|
||||
case Period.DecemberThisYear:
|
||||
return this.generateMonthlyKeysRange(11, 12)[0]
|
||||
default:
|
||||
throw new Error(`Unsuporrted period: ${period}`)
|
||||
}
|
||||
@@ -149,4 +212,22 @@ export class PeriodKeyGenerator implements PeriodKeyGeneratorInterface {
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
private generateDailyKeysRange(month?: number): string[] {
|
||||
const today = new Date()
|
||||
if (month) {
|
||||
today.setMonth(month)
|
||||
}
|
||||
const numberOfDays = new Date(today.getFullYear(), today.getMonth() + 1, 0).getDate()
|
||||
|
||||
const keys = []
|
||||
for (let i = 1; i <= numberOfDays; i++) {
|
||||
const date = new Date()
|
||||
date.setMonth(today.getMonth())
|
||||
date.setDate(i)
|
||||
keys.push(this.getDailyKey(date))
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,5 +2,6 @@ import { Period } from './Period'
|
||||
|
||||
export interface PeriodKeyGeneratorInterface {
|
||||
getPeriodKey(period: Period): string
|
||||
convertPeriodKeyToPeriod(periodKey: string): Period
|
||||
getDiscretePeriodKeys(period: Period): string[]
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ describe('RedisAnalyticsStore', () => {
|
||||
expect(caughtError).not.toBeNull()
|
||||
})
|
||||
|
||||
it('should calculate total count of activities', async () => {
|
||||
it('should calculate total count of activities by period', async () => {
|
||||
redisClient.bitcount = jest.fn().mockReturnValue(70)
|
||||
|
||||
expect(await createStore().calculateActivityTotalCount(AnalyticsActivity.EditingItems, Period.Yesterday)).toEqual(
|
||||
@@ -112,6 +112,14 @@ describe('RedisAnalyticsStore', () => {
|
||||
expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:period-key')
|
||||
})
|
||||
|
||||
it('should calculate total count of activities by period key', async () => {
|
||||
redisClient.bitcount = jest.fn().mockReturnValue(70)
|
||||
|
||||
expect(await createStore().calculateActivityTotalCount(AnalyticsActivity.EditingItems, '2022-10-03')).toEqual(70)
|
||||
|
||||
expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:2022-10-03')
|
||||
})
|
||||
|
||||
it('should calculate activity retention', async () => {
|
||||
redisClient.bitcount = jest.fn().mockReturnValueOnce(7).mockReturnValueOnce(10)
|
||||
|
||||
|
||||
@@ -134,9 +134,12 @@ export class RedisAnalyticsStore implements AnalyticsStoreInterface {
|
||||
})
|
||||
}
|
||||
|
||||
async calculateActivityTotalCount(activity: AnalyticsActivity, period: Period): Promise<number> {
|
||||
return this.redisClient.bitcount(
|
||||
`bitmap:action:${activity}:timespan:${this.periodKeyGenerator.getPeriodKey(period)}`,
|
||||
)
|
||||
async calculateActivityTotalCount(activity: AnalyticsActivity, periodOrPeriodKey: Period | string): Promise<number> {
|
||||
let periodKey = periodOrPeriodKey
|
||||
if (!isNaN(+periodOrPeriodKey)) {
|
||||
periodKey = this.periodKeyGenerator.getPeriodKey(periodOrPeriodKey as Period)
|
||||
}
|
||||
|
||||
return this.redisClient.bitcount(`bitmap:action:${activity}:timespan:${periodKey}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,4 +125,20 @@ describe('RedisStatisticsStore', () => {
|
||||
|
||||
expect(await createStore().getMeasureAverage(StatisticsMeasure.Income, Period.Today)).toEqual(0)
|
||||
})
|
||||
|
||||
it('should retrieve a measurement total for period', async () => {
|
||||
redisClient.get = jest.fn().mockReturnValueOnce(5)
|
||||
|
||||
expect(await createStore().getMeasureTotal(StatisticsMeasure.Income, Period.Today)).toEqual(5)
|
||||
|
||||
expect(redisClient.get).toHaveBeenCalledWith('count:measure:income:timespan:period-key')
|
||||
})
|
||||
|
||||
it('should retrieve a measurement total for period key', async () => {
|
||||
redisClient.get = jest.fn().mockReturnValueOnce(5)
|
||||
|
||||
expect(await createStore().getMeasureTotal(StatisticsMeasure.Income, '2022-10-03')).toEqual(5)
|
||||
|
||||
expect(redisClient.get).toHaveBeenCalledWith('count:measure:income:timespan:2022-10-03')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -18,10 +18,13 @@ export class RedisStatisticsStore implements StatisticsStoreInterface {
|
||||
await pipeline.exec()
|
||||
}
|
||||
|
||||
async getMeasureTotal(measure: StatisticsMeasure, period: Period): Promise<number> {
|
||||
const totalValue = await this.redisClient.get(
|
||||
`count:measure:${measure}:timespan:${this.periodKeyGenerator.getPeriodKey(period)}`,
|
||||
)
|
||||
async getMeasureTotal(measure: StatisticsMeasure, periodOrPeriodKey: Period | string): Promise<number> {
|
||||
let periodKey = periodOrPeriodKey
|
||||
if (!isNaN(+periodOrPeriodKey)) {
|
||||
periodKey = this.periodKeyGenerator.getPeriodKey(periodOrPeriodKey as Period)
|
||||
}
|
||||
|
||||
const totalValue = await this.redisClient.get(`count:measure:${measure}:timespan:${periodKey}`)
|
||||
|
||||
if (totalValue === null) {
|
||||
return 0
|
||||
|
||||
@@ -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.24.5](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.24.4...@standardnotes/api-gateway@1.24.5) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.24.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.24.3...@standardnotes/api-gateway@1.24.4) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.24.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.24.2...@standardnotes/api-gateway@1.24.3) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.24.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.24.1...@standardnotes/api-gateway@1.24.2) (2022-10-03)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api-gateway:** report churn values for empty months ([f43fbf1](https://github.com/standardnotes/api-gateway/commit/f43fbf15844be05add905134dfb3e8ca90f78458))
|
||||
|
||||
## [1.24.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.24.0...@standardnotes/api-gateway@1.24.1) (2022-10-03)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add debug logs for churn calculation ([2236cc3](https://github.com/standardnotes/api-gateway/commit/2236cc3828167e4b94defbde2691bba38458bd1c))
|
||||
|
||||
# [1.24.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.23.0...@standardnotes/api-gateway@1.24.0) (2022-10-03)
|
||||
|
||||
### Features
|
||||
|
||||
* add calculating monthly churn rate ([f075cd8](https://github.com/standardnotes/api-gateway/commit/f075cd8c4dfc411ba513dfec21bb84c03b238254))
|
||||
|
||||
# [1.23.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.22.6...@standardnotes/api-gateway@1.23.0) (2022-09-30)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -136,6 +136,39 @@ const requestReport = async (
|
||||
}
|
||||
}
|
||||
|
||||
const monthlyPeriodKeys = periodKeyGenerator.getDiscretePeriodKeys(Period.ThisYear)
|
||||
const churnRates = []
|
||||
for (const monthPeriodKey of monthlyPeriodKeys) {
|
||||
const monthPeriod = periodKeyGenerator.convertPeriodKeyToPeriod(monthPeriodKey)
|
||||
const dailyPeriodKeys = periodKeyGenerator.getDiscretePeriodKeys(monthPeriod)
|
||||
|
||||
const totalCustomerCounts: Array<number> = []
|
||||
for (const dailyPeriodKey of dailyPeriodKeys) {
|
||||
const customersCount = await statisticsStore.getMeasureTotal(StatisticsMeasure.TotalCustomers, dailyPeriodKey)
|
||||
totalCustomerCounts.push(customersCount)
|
||||
}
|
||||
const filteredTotalCustomerCounts = totalCustomerCounts.filter((count) => !!count)
|
||||
const averageCustomersCount = filteredTotalCustomerCounts.length
|
||||
? filteredTotalCustomerCounts.reduce((total, current) => total + current, 0) / filteredTotalCustomerCounts.length
|
||||
: 0
|
||||
|
||||
const existingCustomersChurn = await analyticsStore.calculateActivityTotalCount(
|
||||
AnalyticsActivity.ExistingCustomersChurn,
|
||||
monthPeriodKey,
|
||||
)
|
||||
const newCustomersChurn = await analyticsStore.calculateActivityTotalCount(
|
||||
AnalyticsActivity.NewCustomersChurn,
|
||||
monthPeriodKey,
|
||||
)
|
||||
|
||||
const totalChurn = existingCustomersChurn + newCustomersChurn
|
||||
|
||||
churnRates.push({
|
||||
periodKey: monthPeriodKey,
|
||||
rate: averageCustomersCount ? (totalChurn / averageCustomersCount) * 100 : 0,
|
||||
})
|
||||
}
|
||||
|
||||
const event: DailyAnalyticsReportGeneratedEvent = {
|
||||
type: 'DAILY_ANALYTICS_REPORT_GENERATED',
|
||||
createdAt: new Date(),
|
||||
@@ -163,6 +196,10 @@ const requestReport = async (
|
||||
},
|
||||
},
|
||||
],
|
||||
churn: {
|
||||
periodKeys: monthlyPeriodKeys,
|
||||
values: churnRates,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.23.0",
|
||||
"version": "1.24.5",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -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.37.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.36.4...@standardnotes/auth-server@1.37.0) (2022-10-04)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add detailed income stats ([8668fec](https://github.com/standardnotes/server/commit/8668fec33dac1598bdc4d6ca869c296ed6eaa617))
|
||||
|
||||
## [1.36.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.36.3...@standardnotes/auth-server@1.36.4) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.36.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.36.2...@standardnotes/auth-server@1.36.3) (2022-10-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** turn down severity of logs for predicate verification ([09b3f9a](https://github.com/standardnotes/server/commit/09b3f9a0d787d2a329f84e2d625ec8a63b4bd847))
|
||||
|
||||
## [1.36.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.36.1...@standardnotes/auth-server@1.36.2) (2022-10-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.36.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.36.0...@standardnotes/auth-server@1.36.1) (2022-10-03)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** counting active subscriptions ([e7736bb](https://github.com/standardnotes/server/commit/e7736bba250782a3967fd08c82dbf32884b5b892))
|
||||
|
||||
# [1.36.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.35.0...@standardnotes/auth-server@1.36.0) (2022-10-03)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.36.0",
|
||||
"version": "1.37.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { PaymentSuccessEvent } from '@standardnotes/domain-events'
|
||||
import { AnalyticsStoreInterface, StatisticsStoreInterface } from '@standardnotes/analytics'
|
||||
import { AnalyticsStoreInterface, Period, StatisticsStoreInterface } from '@standardnotes/analytics'
|
||||
|
||||
import { PaymentSuccessEventHandler } from './PaymentSuccessEventHandler'
|
||||
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
|
||||
@@ -38,14 +38,41 @@ describe('PaymentSuccessEventHandler', () => {
|
||||
event.payload = {
|
||||
userEmail: 'test@test.com',
|
||||
amount: 12.45,
|
||||
billingFrequency: 12,
|
||||
paymentType: 'initial',
|
||||
subscriptionName: 'PRO_PLAN',
|
||||
}
|
||||
})
|
||||
|
||||
it('should mark payment failed for analytics', async () => {
|
||||
it('should mark payment success for analytics', async () => {
|
||||
await createHandler().handle(event)
|
||||
|
||||
expect(analyticsStore.markActivity).toHaveBeenCalled()
|
||||
expect(statisticsStore.incrementMeasure).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,
|
||||
])
|
||||
})
|
||||
|
||||
it('should not mark payment failed for analytics if user is not found', async () => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
StatisticsMeasure,
|
||||
StatisticsStoreInterface,
|
||||
} from '@standardnotes/analytics'
|
||||
import { PaymentType, SubscriptionBillingFrequency, SubscriptionName } from '@standardnotes/common'
|
||||
import { DomainEventHandlerInterface, PaymentSuccessEvent } from '@standardnotes/domain-events'
|
||||
import { inject, injectable } from 'inversify'
|
||||
|
||||
@@ -14,6 +15,47 @@ import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
|
||||
|
||||
@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.UserRepository) private userRepository: UserRepositoryInterface,
|
||||
@inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
|
||||
@@ -34,10 +76,21 @@ export class PaymentSuccessEventHandler implements DomainEventHandlerInterface {
|
||||
Period.ThisMonth,
|
||||
])
|
||||
|
||||
await this.statisticsStore.incrementMeasure(StatisticsMeasure.Income, event.payload.amount, [
|
||||
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)
|
||||
}
|
||||
|
||||
for (const measure of statisticMeasures) {
|
||||
await this.statisticsStore.incrementMeasure(measure, event.payload.amount, [
|
||||
Period.Today,
|
||||
Period.ThisWeek,
|
||||
Period.ThisMonth,
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ describe('PredicateVerificationRequestedEventHandler', () => {
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
logger.warn = jest.fn()
|
||||
logger.info = jest.fn()
|
||||
logger.debug = jest.fn()
|
||||
|
||||
event = {} as jest.Mocked<PredicateVerificationRequestedEvent>
|
||||
event.meta = {
|
||||
|
||||
@@ -23,7 +23,7 @@ export class PredicateVerificationRequestedEventHandler implements DomainEventHa
|
||||
) {}
|
||||
|
||||
async handle(event: PredicateVerificationRequestedEvent): Promise<void> {
|
||||
this.logger.info(`Received verification request of predicate: ${event.payload.predicate.name}`)
|
||||
this.logger.debug(`Received verification request of predicate: ${event.payload.predicate.name}`)
|
||||
|
||||
let userUuid = event.meta.correlation.userIdentifier
|
||||
if (event.meta.correlation.userIdentifierType === 'email') {
|
||||
@@ -55,7 +55,7 @@ export class PredicateVerificationRequestedEventHandler implements DomainEventHa
|
||||
}),
|
||||
)
|
||||
|
||||
this.logger.info(
|
||||
this.logger.debug(
|
||||
`Published predicate verification (${predicateVerificationResult}) result for: ${event.payload.predicate.name}`,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -66,18 +66,16 @@ describe('MySQLUserSubscriptionRepository', () => {
|
||||
it('should count all active subscriptions', async () => {
|
||||
ormRepository.createQueryBuilder = jest.fn().mockImplementation(() => selectQueryBuilder)
|
||||
|
||||
selectQueryBuilder.select = jest.fn().mockReturnThis()
|
||||
selectQueryBuilder.distinct = jest.fn().mockReturnThis()
|
||||
selectQueryBuilder.groupBy = jest.fn().mockReturnThis()
|
||||
selectQueryBuilder.where = jest.fn().mockReturnThis()
|
||||
selectQueryBuilder.getCount = jest.fn().mockReturnValue(2)
|
||||
|
||||
const result = await createRepository().countActiveSubscriptions()
|
||||
|
||||
expect(selectQueryBuilder.select).toHaveBeenCalledWith('user_uuid')
|
||||
expect(selectQueryBuilder.distinct).toHaveBeenCalled()
|
||||
expect(selectQueryBuilder.where).toHaveBeenCalledWith('ends_at > :timestamp', {
|
||||
timestamp: 123,
|
||||
})
|
||||
expect(selectQueryBuilder.groupBy).toHaveBeenCalledWith('user_uuid')
|
||||
expect(selectQueryBuilder.getCount).toHaveBeenCalled()
|
||||
expect(result).toEqual(2)
|
||||
})
|
||||
|
||||
@@ -19,9 +19,8 @@ export class MySQLUserSubscriptionRepository implements UserSubscriptionReposito
|
||||
async countActiveSubscriptions(): Promise<number> {
|
||||
return await this.ormRepository
|
||||
.createQueryBuilder()
|
||||
.select('user_uuid')
|
||||
.distinct()
|
||||
.where('ends_at > :timestamp', { timestamp: this.timer.getTimestampInMicroseconds() })
|
||||
.groupBy('user_uuid')
|
||||
.getCount()
|
||||
}
|
||||
|
||||
|
||||
@@ -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.35.0](https://github.com/standardnotes/server/compare/@standardnotes/common@1.34.0...@standardnotes/common@1.35.0) (2022-10-04)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add detailed income stats ([8668fec](https://github.com/standardnotes/server/commit/8668fec33dac1598bdc4d6ca869c296ed6eaa617))
|
||||
|
||||
# [1.34.0](https://github.com/standardnotes/server/compare/@standardnotes/common@1.33.0...@standardnotes/common@1.34.0) (2022-10-04)
|
||||
|
||||
### Features
|
||||
|
||||
* **common:** add subscription billing frequency ([3c40ee4](https://github.com/standardnotes/server/commit/3c40ee4b4a33dffc35da148a0fa1582c08619733))
|
||||
|
||||
# [1.33.0](https://github.com/standardnotes/server/compare/@standardnotes/common@1.32.0...@standardnotes/common@1.33.0) (2022-09-19)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/common",
|
||||
"version": "1.33.0",
|
||||
"version": "1.35.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
5
packages/common/src/Domain/Payment/PaymentType.ts
Normal file
5
packages/common/src/Domain/Payment/PaymentType.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
/* istanbul ignore file */
|
||||
export enum PaymentType {
|
||||
Initial = 'initial',
|
||||
Renewal = 'renewal',
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/* istanbul ignore file */
|
||||
export enum SubscriptionBillingFrequency {
|
||||
Monthly = 1,
|
||||
Annual = 12,
|
||||
}
|
||||
@@ -14,9 +14,11 @@ export * from './KeyParams/KeyParamsContent002'
|
||||
export * from './KeyParams/KeyParamsContent003'
|
||||
export * from './KeyParams/KeyParamsContent004'
|
||||
export * from './KeyParams/KeyParamsOrigination'
|
||||
export * from './Payment/PaymentType'
|
||||
export * from './Protocol/ProtocolVersion'
|
||||
export * from './Role/PaidRoles'
|
||||
export * from './Role/RoleName'
|
||||
export * from './Subscription/SubscriptionBillingFrequency'
|
||||
export * from './Subscription/SubscriptionName'
|
||||
export * from './Type/Either'
|
||||
export * from './Type/Only'
|
||||
|
||||
@@ -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.16](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.8.15...@standardnotes/domain-events-infra@1.8.16) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.8.15](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.8.14...@standardnotes/domain-events-infra@1.8.15) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.8.14](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.8.13...@standardnotes/domain-events-infra@1.8.14) (2022-10-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.8.13](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.8.12...@standardnotes/domain-events-infra@1.8.13) (2022-09-28)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events-infra",
|
||||
"version": "1.8.13",
|
||||
"version": "1.8.16",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [2.62.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.61.1...@standardnotes/domain-events@2.62.0) (2022-10-04)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add detailed income stats ([8668fec](https://github.com/standardnotes/server/commit/8668fec33dac1598bdc4d6ca869c296ed6eaa617))
|
||||
|
||||
## [2.61.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.61.0...@standardnotes/domain-events@2.61.1) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events
|
||||
|
||||
# [2.61.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.60.7...@standardnotes/domain-events@2.61.0) (2022-10-03)
|
||||
|
||||
### Features
|
||||
|
||||
* add calculating monthly churn rate ([f075cd8](https://github.com/standardnotes/server/commit/f075cd8c4dfc411ba513dfec21bb84c03b238254))
|
||||
|
||||
## [2.60.7](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.60.6...@standardnotes/domain-events@2.60.7) (2022-09-28)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events",
|
||||
"version": "2.60.7",
|
||||
"version": "2.62.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -40,4 +40,11 @@ export interface DailyAnalyticsReportGeneratedEventPayload {
|
||||
}>
|
||||
}
|
||||
}>
|
||||
churn: {
|
||||
periodKeys: Array<string>
|
||||
values: Array<{
|
||||
rate: number
|
||||
periodKey: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
export interface PaymentSuccessEventPayload {
|
||||
userEmail: string
|
||||
amount: number
|
||||
billingFrequency: number
|
||||
paymentType: string
|
||||
subscriptionName: string
|
||||
}
|
||||
|
||||
@@ -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.3.21](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.3.20...@standardnotes/event-store@1.3.21) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.3.20](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.3.19...@standardnotes/event-store@1.3.20) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.3.19](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.3.18...@standardnotes/event-store@1.3.19) (2022-10-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.3.18](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.3.17...@standardnotes/event-store@1.3.18) (2022-09-28)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/event-store",
|
||||
"version": "1.3.18",
|
||||
"version": "1.3.21",
|
||||
"description": "Event Store Service",
|
||||
"private": true,
|
||||
"main": "dist/src/index.js",
|
||||
|
||||
@@ -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.7](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.6.6...@standardnotes/files-server@1.6.7) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.6.6](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.6.5...@standardnotes/files-server@1.6.6) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.6.5](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.6.4...@standardnotes/files-server@1.6.5) (2022-10-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.6.4](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.6.3...@standardnotes/files-server@1.6.4) (2022-09-28)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files-server",
|
||||
"version": "1.6.4",
|
||||
"version": "1.6.7",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.4.4](https://github.com/standardnotes/server/compare/@standardnotes/predicates@1.4.3...@standardnotes/predicates@1.4.4) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/predicates
|
||||
|
||||
## [1.4.3](https://github.com/standardnotes/server/compare/@standardnotes/predicates@1.4.2...@standardnotes/predicates@1.4.3) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/predicates
|
||||
|
||||
## [1.4.2](https://github.com/standardnotes/server/compare/@standardnotes/predicates@1.4.1...@standardnotes/predicates@1.4.2) (2022-09-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/predicates
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/predicates",
|
||||
"version": "1.4.2",
|
||||
"version": "1.4.4",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -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.10.35](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.34...@standardnotes/scheduler-server@1.10.35) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.34](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.33...@standardnotes/scheduler-server@1.10.34) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.33](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.32...@standardnotes/scheduler-server@1.10.33) (2022-10-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.32](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.31...@standardnotes/scheduler-server@1.10.32) (2022-09-28)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/scheduler-server",
|
||||
"version": "1.10.32",
|
||||
"version": "1.10.35",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.4.2](https://github.com/standardnotes/server/compare/@standardnotes/security@1.4.1...@standardnotes/security@1.4.2) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/security
|
||||
|
||||
## [1.4.1](https://github.com/standardnotes/server/compare/@standardnotes/security@1.4.0...@standardnotes/security@1.4.1) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/security
|
||||
|
||||
# [1.4.0](https://github.com/standardnotes/server/compare/@standardnotes/security@1.3.3...@standardnotes/security@1.4.0) (2022-09-21)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/security",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.2",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.8.19](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.8.18...@standardnotes/syncing-server@1.8.19) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.8.18](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.8.17...@standardnotes/syncing-server@1.8.18) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.8.17](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.8.16...@standardnotes/syncing-server@1.8.17) (2022-10-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.8.16](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.8.15...@standardnotes/syncing-server@1.8.16) (2022-10-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.8.15](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.8.14...@standardnotes/syncing-server@1.8.15) (2022-09-30)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/syncing-server",
|
||||
"version": "1.8.15",
|
||||
"version": "1.8.19",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user