mirror of
https://github.com/standardnotes/server
synced 2026-01-24 17:01:09 -05:00
Compare commits
17 Commits
@standardn
...
@standardn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76e34131fb | ||
|
|
3c40ee4b4a | ||
|
|
5abd7ae32c | ||
|
|
09b3f9a0d7 | ||
|
|
19455ba6a7 | ||
|
|
7d042689f0 | ||
|
|
f43fbf1584 | ||
|
|
24c0cb8366 | ||
|
|
2236cc3828 | ||
|
|
039d44718a | ||
|
|
f075cd8c4d | ||
|
|
ea0f3e8999 | ||
|
|
e7736bba25 | ||
|
|
fdf8809e13 | ||
|
|
6a9d479f71 | ||
|
|
82c9637f37 | ||
|
|
dfab849f48 |
61
.pnp.cjs
generated
61
.pnp.cjs
generated
@@ -2484,14 +2484,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/api", [\
|
||||
["npm:1.8.1", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-api-npm-1.8.1-15c2e051d4-76c5d1a2d2.zip/node_modules/@standardnotes/api/",\
|
||||
["npm:1.9.0", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-api-npm-1.9.0-507434ff00-cc3feac393.zip/node_modules/@standardnotes/api/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/api", "npm:1.8.1"],\
|
||||
["@standardnotes/api", "npm:1.9.0"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/encryption", "npm:1.15.3"],\
|
||||
["@standardnotes/models", "npm:1.18.3"],\
|
||||
["@standardnotes/responses", "npm:1.10.2"],\
|
||||
["@standardnotes/encryption", "npm:1.15.9"],\
|
||||
["@standardnotes/models", "npm:1.22.0"],\
|
||||
["@standardnotes/responses", "npm:1.10.3"],\
|
||||
["@standardnotes/security", "workspace:packages/security"],\
|
||||
["@standardnotes/utils", "npm:1.9.0"],\
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
@@ -2563,7 +2563,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.0.0"],\
|
||||
["@sentry/node", "npm:7.5.0"],\
|
||||
["@standardnotes/analytics", "workspace:packages/analytics"],\
|
||||
["@standardnotes/api", "npm:1.8.1"],\
|
||||
["@standardnotes/api", "npm:1.9.0"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||
@@ -2688,14 +2688,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/encryption", [\
|
||||
["npm:1.15.3", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-encryption-npm-1.15.3-3580c52c1f-1a7863299f.zip/node_modules/@standardnotes/encryption/",\
|
||||
["npm:1.15.9", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-encryption-npm-1.15.9-00c7fac9f6-7595ac08ce.zip/node_modules/@standardnotes/encryption/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/encryption", "npm:1.15.3"],\
|
||||
["@standardnotes/encryption", "npm:1.15.9"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/models", "npm:1.18.3"],\
|
||||
["@standardnotes/responses", "npm:1.10.2"],\
|
||||
["@standardnotes/sncrypto-common", "npm:1.11.1"],\
|
||||
["@standardnotes/models", "npm:1.22.0"],\
|
||||
["@standardnotes/responses", "npm:1.10.3"],\
|
||||
["@standardnotes/sncrypto-common", "npm:1.12.0"],\
|
||||
["@standardnotes/utils", "npm:1.9.0"],\
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
],\
|
||||
@@ -2743,17 +2743,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:1.52.0", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-features-npm-1.52.0-8c1adf7881-3e6014272f.zip/node_modules/@standardnotes/features/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/features", "npm:1.52.0"],\
|
||||
["@standardnotes/auth", "npm:3.19.4"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/security", "workspace:packages/security"],\
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:1.52.1", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-features-npm-1.52.1-1fee85cf4e-ff3684399e.zip/node_modules/@standardnotes/features/",\
|
||||
"packageDependencies": [\
|
||||
@@ -2819,13 +2808,13 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/models", [\
|
||||
["npm:1.18.3", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-models-npm-1.18.3-6c65a62f30-21830c805f.zip/node_modules/@standardnotes/models/",\
|
||||
["npm:1.22.0", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-models-npm-1.22.0-2cc72f987b-9928246368.zip/node_modules/@standardnotes/models/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/models", "npm:1.18.3"],\
|
||||
["@standardnotes/models", "npm:1.22.0"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/features", "npm:1.52.0"],\
|
||||
["@standardnotes/responses", "npm:1.10.2"],\
|
||||
["@standardnotes/features", "npm:1.52.1"],\
|
||||
["@standardnotes/responses", "npm:1.10.3"],\
|
||||
["@standardnotes/utils", "npm:1.9.0"],\
|
||||
["lodash", "npm:4.17.21"],\
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
@@ -2862,12 +2851,12 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/responses", [\
|
||||
["npm:1.10.2", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-responses-npm-1.10.2-39d2d1f9b5-364724b5c7.zip/node_modules/@standardnotes/responses/",\
|
||||
["npm:1.10.3", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-responses-npm-1.10.3-7cdb15f83a-4a1e31eb89.zip/node_modules/@standardnotes/responses/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/responses", "npm:1.10.2"],\
|
||||
["@standardnotes/responses", "npm:1.10.3"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/features", "npm:1.52.0"],\
|
||||
["@standardnotes/features", "npm:1.52.1"],\
|
||||
["@standardnotes/security", "workspace:packages/security"],\
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
],\
|
||||
@@ -2978,10 +2967,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/sncrypto-common", [\
|
||||
["npm:1.11.1", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-sncrypto-common-npm-1.11.1-58d12d6912-69d698abb7.zip/node_modules/@standardnotes/sncrypto-common/",\
|
||||
["npm:1.12.0", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-sncrypto-common-npm-1.12.0-1a093ff006-b89a14bd23.zip/node_modules/@standardnotes/sncrypto-common/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/sncrypto-common", "npm:1.11.1"],\
|
||||
["@standardnotes/sncrypto-common", "npm:1.12.0"],\
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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,38 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [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
|
||||
|
||||
* **api-gateway:** add churn metrics to the report ([dfab849](https://github.com/standardnotes/api-gateway/commit/dfab849f48ab782c3cd2e97f52fdb72b7143002f))
|
||||
|
||||
## [1.22.6](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.22.5...@standardnotes/api-gateway@1.22.6) (2022-09-30)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
@@ -38,6 +38,8 @@ const requestReport = async (
|
||||
AnalyticsActivity.DeleteAccount,
|
||||
AnalyticsActivity.SubscriptionCancelled,
|
||||
AnalyticsActivity.SubscriptionRefunded,
|
||||
AnalyticsActivity.ExistingCustomersChurn,
|
||||
AnalyticsActivity.NewCustomersChurn,
|
||||
]
|
||||
|
||||
for (const analyticsName of thirtyDaysAnalyticsNames) {
|
||||
@@ -74,6 +76,8 @@ const requestReport = async (
|
||||
AnalyticsActivity.GeneralActivityPaidUsers,
|
||||
AnalyticsActivity.PaymentFailed,
|
||||
AnalyticsActivity.PaymentSuccess,
|
||||
AnalyticsActivity.NewCustomersChurn,
|
||||
AnalyticsActivity.ExistingCustomersChurn,
|
||||
]
|
||||
|
||||
for (const activityName of yesterdayActivityNames) {
|
||||
@@ -98,6 +102,8 @@ const requestReport = async (
|
||||
StatisticsMeasure.NotesCountFreeUsers,
|
||||
StatisticsMeasure.NotesCountPaidUsers,
|
||||
StatisticsMeasure.FilesCount,
|
||||
StatisticsMeasure.NewCustomers,
|
||||
StatisticsMeasure.TotalCustomers,
|
||||
]
|
||||
const statisticMeasures = []
|
||||
for (const statisticMeasureName of statisticMeasureNames) {
|
||||
@@ -130,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(),
|
||||
@@ -157,6 +196,10 @@ const requestReport = async (
|
||||
},
|
||||
},
|
||||
],
|
||||
churn: {
|
||||
periodKeys: monthlyPeriodKeys,
|
||||
values: churnRates,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.22.6",
|
||||
"version": "1.24.4",
|
||||
"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.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
|
||||
|
||||
* **auth:** disallow v1 sign in for users with 004 protocol version ([6a9d479](https://github.com/standardnotes/server/commit/6a9d479f7173268bc0c79b1c7583021989be783a))
|
||||
|
||||
# [1.35.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.34.1...@standardnotes/auth-server@1.35.0) (2022-09-30)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.35.0",
|
||||
"version": "1.36.4",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -34,7 +34,7 @@
|
||||
"@newrelic/winston-enricher": "^4.0.0",
|
||||
"@sentry/node": "^7.3.0",
|
||||
"@standardnotes/analytics": "workspace:*",
|
||||
"@standardnotes/api": "^1.8.1",
|
||||
"@standardnotes/api": "^1.9.0",
|
||||
"@standardnotes/common": "workspace:*",
|
||||
"@standardnotes/domain-events": "workspace:*",
|
||||
"@standardnotes/domain-events-infra": "workspace:*",
|
||||
|
||||
@@ -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}`,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import { Setting } from '../Setting/Setting'
|
||||
import { MuteSignInEmailsOption } from '@standardnotes/settings'
|
||||
import { PKCERepositoryInterface } from '../User/PKCERepositoryInterface'
|
||||
import { CrypterInterface } from '../Encryption/CrypterInterface'
|
||||
import { ProtocolVersion } from '@standardnotes/common'
|
||||
|
||||
describe('SignIn', () => {
|
||||
let user: User
|
||||
@@ -50,6 +51,7 @@ describe('SignIn', () => {
|
||||
user = {
|
||||
uuid: '1-2-3',
|
||||
email: 'test@test.com',
|
||||
version: ProtocolVersion.V004,
|
||||
} as jest.Mocked<User>
|
||||
user.encryptedPassword = '$2a$11$K3g6XoTau8VmLJcai1bB0eD9/YvBSBRtBhMprJOaVZ0U3SgasZH3a'
|
||||
|
||||
@@ -99,7 +101,10 @@ describe('SignIn', () => {
|
||||
logger.error = jest.fn()
|
||||
})
|
||||
|
||||
it('should sign in a user', async () => {
|
||||
it('should sign in a legacy user without code verifier', async () => {
|
||||
user.version = ProtocolVersion.V003
|
||||
userRepository.findOneByEmail = jest.fn().mockReturnValue(user)
|
||||
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
email: 'test@test.te',
|
||||
@@ -124,6 +129,22 @@ describe('SignIn', () => {
|
||||
expect(domainEventPublisher.publish).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not sign in a user without code verifier', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
email: 'test@test.te',
|
||||
password: 'qweqwe123123',
|
||||
userAgent: 'Google Chrome',
|
||||
apiVersion: '20190520',
|
||||
ephemeralSession: false,
|
||||
}),
|
||||
).toEqual({
|
||||
success: false,
|
||||
errorCode: 410,
|
||||
errorMessage: 'Please update your client application.',
|
||||
})
|
||||
})
|
||||
|
||||
it('should sign in a user with valid code verifier', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
@@ -165,6 +186,7 @@ describe('SignIn', () => {
|
||||
userAgent: 'Google Chrome',
|
||||
apiVersion: '20190520',
|
||||
ephemeralSession: false,
|
||||
codeVerifier: 'test',
|
||||
}),
|
||||
).toEqual({
|
||||
success: true,
|
||||
@@ -192,6 +214,7 @@ describe('SignIn', () => {
|
||||
userAgent: 'Google Chrome',
|
||||
apiVersion: '20190520',
|
||||
ephemeralSession: false,
|
||||
codeVerifier: 'test',
|
||||
}),
|
||||
).toEqual({
|
||||
success: true,
|
||||
@@ -218,6 +241,7 @@ describe('SignIn', () => {
|
||||
email: 'test@test.com',
|
||||
encryptedPassword: '$2a$11$K3g6XoTau8VmLJcai1bB0eD9/YvBSBRtBhMprJOaVZ0U3SgasZH3a',
|
||||
uuid: '1-2-3',
|
||||
version: '004',
|
||||
},
|
||||
})
|
||||
})
|
||||
@@ -234,6 +258,7 @@ describe('SignIn', () => {
|
||||
userAgent: 'Google Chrome',
|
||||
apiVersion: '20190520',
|
||||
ephemeralSession: false,
|
||||
codeVerifier: 'test',
|
||||
}),
|
||||
).toEqual({
|
||||
success: true,
|
||||
@@ -249,6 +274,7 @@ describe('SignIn', () => {
|
||||
userAgent: 'Google Chrome',
|
||||
apiVersion: '20190520',
|
||||
ephemeralSession: false,
|
||||
codeVerifier: 'test',
|
||||
}),
|
||||
).toEqual({
|
||||
success: false,
|
||||
@@ -284,6 +310,7 @@ describe('SignIn', () => {
|
||||
userAgent: 'Google Chrome',
|
||||
apiVersion: '20190520',
|
||||
ephemeralSession: false,
|
||||
codeVerifier: 'test',
|
||||
}),
|
||||
).toEqual({
|
||||
success: false,
|
||||
|
||||
@@ -21,6 +21,8 @@ import { UseCaseInterface } from './UseCaseInterface'
|
||||
import { PKCERepositoryInterface } from '../User/PKCERepositoryInterface'
|
||||
import { CrypterInterface } from '../Encryption/CrypterInterface'
|
||||
import { SignInDTOV2Challenged } from './SignInDTOV2Challenged'
|
||||
import { ProtocolVersion } from '@standardnotes/common'
|
||||
import { HttpStatusCode } from '@standardnotes/api'
|
||||
|
||||
@injectable()
|
||||
export class SignIn implements UseCaseInterface {
|
||||
@@ -39,7 +41,8 @@ export class SignIn implements UseCaseInterface {
|
||||
) {}
|
||||
|
||||
async execute(dto: SignInDTO): Promise<SignInResponse> {
|
||||
if (this.isCodeChallengedVersion(dto)) {
|
||||
const performingCodeChallengedSignIn = this.isCodeChallengedVersion(dto)
|
||||
if (performingCodeChallengedSignIn) {
|
||||
const validCodeVerifier = await this.validateCodeVerifier(dto.codeVerifier)
|
||||
if (!validCodeVerifier) {
|
||||
this.logger.debug('Code verifier does not match')
|
||||
@@ -62,6 +65,14 @@ export class SignIn implements UseCaseInterface {
|
||||
}
|
||||
}
|
||||
|
||||
if (user.version === ProtocolVersion.V004 && !performingCodeChallengedSignIn) {
|
||||
return {
|
||||
success: false,
|
||||
errorMessage: 'Please update your client application.',
|
||||
errorCode: HttpStatusCode.Gone,
|
||||
}
|
||||
}
|
||||
|
||||
const passwordMatches = await bcrypt.compare(dto.password, user.encryptedPassword)
|
||||
if (!passwordMatches) {
|
||||
this.logger.debug('Password does not match')
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { HttpStatusCode } from '@standardnotes/api'
|
||||
|
||||
import { AuthResponse20161215 } from '../Auth/AuthResponse20161215'
|
||||
import { AuthResponse20200115 } from '../Auth/AuthResponse20200115'
|
||||
|
||||
@@ -5,4 +7,5 @@ export type SignInResponse = {
|
||||
success: boolean
|
||||
authResponse?: AuthResponse20161215 | AuthResponse20200115
|
||||
errorMessage?: string
|
||||
errorCode?: HttpStatusCode
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ export class InversifyExpressAuthController extends BaseHttpController {
|
||||
message: signInResult.errorMessage,
|
||||
},
|
||||
},
|
||||
401,
|
||||
signInResult.errorCode ?? 401,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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,12 @@
|
||||
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/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.34.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
/* istanbul ignore file */
|
||||
export enum SubscriptionBillingFrequency {
|
||||
Monthly = 1,
|
||||
Annual = 12,
|
||||
}
|
||||
@@ -17,6 +17,7 @@ export * from './KeyParams/KeyParamsOrigination'
|
||||
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,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [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.15",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [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.61.1",
|
||||
"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
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.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.20",
|
||||
"description": "Event Store Service",
|
||||
"private": true,
|
||||
"main": "dist/src/index.js",
|
||||
|
||||
@@ -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.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.6",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.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.3",
|
||||
"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.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.34",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.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.1",
|
||||
"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.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.18",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
80
yarn.lock
80
yarn.lock
@@ -1803,18 +1803,18 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/api@npm:^1.8.1":
|
||||
version: 1.8.1
|
||||
resolution: "@standardnotes/api@npm:1.8.1"
|
||||
"@standardnotes/api@npm:^1.9.0":
|
||||
version: 1.9.0
|
||||
resolution: "@standardnotes/api@npm:1.9.0"
|
||||
dependencies:
|
||||
"@standardnotes/common": ^1.32.0
|
||||
"@standardnotes/encryption": 1.15.3
|
||||
"@standardnotes/models": 1.18.3
|
||||
"@standardnotes/responses": 1.10.2
|
||||
"@standardnotes/encryption": 1.15.9
|
||||
"@standardnotes/models": 1.22.0
|
||||
"@standardnotes/responses": 1.10.3
|
||||
"@standardnotes/security": ^1.1.0
|
||||
"@standardnotes/utils": 1.9.0
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: 76c5d1a2d29cf7f407813246febf54fe02c5d7cacedcfd1bf5f6ee6630d847f58cae0b5827fbba1c5c5d5a30e56095833c9eff8b413111f8aae9cc17802ffa63
|
||||
checksum: cc3feac3935a382e0ce1fcaf233206a547b6c998cb99ab362d5c7030b3f4e7cbbd3a083eab40bdecbcdc9497dcd283e4513e29dbf200e815ffa46b192ed61b01
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1825,7 +1825,7 @@ __metadata:
|
||||
"@newrelic/winston-enricher": ^4.0.0
|
||||
"@sentry/node": ^7.3.0
|
||||
"@standardnotes/analytics": "workspace:*"
|
||||
"@standardnotes/api": ^1.8.1
|
||||
"@standardnotes/api": ^1.9.0
|
||||
"@standardnotes/common": "workspace:*"
|
||||
"@standardnotes/domain-events": "workspace:*"
|
||||
"@standardnotes/domain-events-infra": "workspace:*"
|
||||
@@ -1951,17 +1951,17 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/encryption@npm:1.15.3":
|
||||
version: 1.15.3
|
||||
resolution: "@standardnotes/encryption@npm:1.15.3"
|
||||
"@standardnotes/encryption@npm:1.15.9":
|
||||
version: 1.15.9
|
||||
resolution: "@standardnotes/encryption@npm:1.15.9"
|
||||
dependencies:
|
||||
"@standardnotes/common": ^1.32.0
|
||||
"@standardnotes/models": 1.18.3
|
||||
"@standardnotes/responses": 1.10.2
|
||||
"@standardnotes/sncrypto-common": 1.11.1
|
||||
"@standardnotes/models": 1.22.0
|
||||
"@standardnotes/responses": 1.10.3
|
||||
"@standardnotes/sncrypto-common": 1.12.0
|
||||
"@standardnotes/utils": 1.9.0
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: 1a7863299f86ee28de1640b93277f8b3e206bec2b34a205eb6e6fd6c6899a4908623acd9f2452d71a83c542b1f181408e7743386e5e1079239c6c0fa384242c9
|
||||
checksum: 7595ac08cea6e54e1456cbff3958969318d90ae237aff166bc4429da5bcf6167c5eb03aa8658a1747486a0639b80b523dae46106ab253c75d24579643cf3e948
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1993,15 +1993,15 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/features@npm:1.52.0":
|
||||
version: 1.52.0
|
||||
resolution: "@standardnotes/features@npm:1.52.0"
|
||||
"@standardnotes/features@npm:1.52.1, @standardnotes/features@npm:^1.52.1":
|
||||
version: 1.52.1
|
||||
resolution: "@standardnotes/features@npm:1.52.1"
|
||||
dependencies:
|
||||
"@standardnotes/auth": ^3.19.4
|
||||
"@standardnotes/common": ^1.32.0
|
||||
"@standardnotes/security": ^1.2.0
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: 3e6014272f72ed33bc7de3cefb33a63a02866c01bfd4a54bc95426e2719f4997940de382cfd83982eaeafdbdf9afac558aecb9139117facfe9c7479089e2952d
|
||||
checksum: ff3684399e0e0c0e799f11e69dddea2e1f65f315e5a5dd3ca5640e24e836ee85faf1f5ee15fc804411bf083004527fcef08411d5c2d0b5894491bf2f28ceca68
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2016,18 +2016,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/features@npm:^1.52.1":
|
||||
version: 1.52.1
|
||||
resolution: "@standardnotes/features@npm:1.52.1"
|
||||
dependencies:
|
||||
"@standardnotes/auth": ^3.19.4
|
||||
"@standardnotes/common": ^1.32.0
|
||||
"@standardnotes/security": ^1.2.0
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: ff3684399e0e0c0e799f11e69dddea2e1f65f315e5a5dd3ca5640e24e836ee85faf1f5ee15fc804411bf083004527fcef08411d5c2d0b5894491bf2f28ceca68
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/files-server@workspace:packages/files":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/files-server@workspace:packages/files"
|
||||
@@ -2078,17 +2066,17 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/models@npm:1.18.3":
|
||||
version: 1.18.3
|
||||
resolution: "@standardnotes/models@npm:1.18.3"
|
||||
"@standardnotes/models@npm:1.22.0":
|
||||
version: 1.22.0
|
||||
resolution: "@standardnotes/models@npm:1.22.0"
|
||||
dependencies:
|
||||
"@standardnotes/common": ^1.32.0
|
||||
"@standardnotes/features": 1.52.0
|
||||
"@standardnotes/responses": 1.10.2
|
||||
"@standardnotes/features": 1.52.1
|
||||
"@standardnotes/responses": 1.10.3
|
||||
"@standardnotes/utils": 1.9.0
|
||||
lodash: ^4.17.21
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: 21830c805ffa1ac2184c64903f88915b7b439eb4eb80ac0686c4920a9a4c86cc6c71a3daeb1ede8f3fe6cf0ce106f7ba396f994165306c1c59c05902a7ec075a
|
||||
checksum: 9928246368b7de7062314374219065507642ed3b6764c27f14ed8d42f0c5a9370fab8731a43a57885a000e461ea60694ba4caa7d9940350839d487cedb7079b5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2117,15 +2105,15 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/responses@npm:1.10.2":
|
||||
version: 1.10.2
|
||||
resolution: "@standardnotes/responses@npm:1.10.2"
|
||||
"@standardnotes/responses@npm:1.10.3":
|
||||
version: 1.10.3
|
||||
resolution: "@standardnotes/responses@npm:1.10.3"
|
||||
dependencies:
|
||||
"@standardnotes/common": ^1.32.0
|
||||
"@standardnotes/features": 1.52.0
|
||||
"@standardnotes/features": 1.52.1
|
||||
"@standardnotes/security": ^1.1.0
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: 364724b5c7efa06948a240da82320817bce58049d6ea226cc2e828e86144ba4d19e5ae6fa437311438008b16aff7bd8cbe7e3f7475a2e9c89cf47650e1e1e9b0
|
||||
checksum: 4a1e31eb89342461488f00c65884839d7d935d47d4e217da83967c7cbe181fd0341ee58b744fe607def30d06cd1a8069c3b54f40b3933765303db35ee63f6a0d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2225,12 +2213,12 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/sncrypto-common@npm:1.11.1":
|
||||
version: 1.11.1
|
||||
resolution: "@standardnotes/sncrypto-common@npm:1.11.1"
|
||||
"@standardnotes/sncrypto-common@npm:1.12.0":
|
||||
version: 1.12.0
|
||||
resolution: "@standardnotes/sncrypto-common@npm:1.12.0"
|
||||
dependencies:
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: 69d698abb7ffc2aecfffd9ccf3e023adca73e5b27cfa1106dfdf10a13d6455b9581c9bf854b333f00255317ec62c384c516b218f40a55ee84fd4f659b8aef16b
|
||||
checksum: b89a14bd233cb781213b2e25dd8d7bfe911820d341903f2987647c168745c3afb710ad94fa42e50aaafb644ee4a7b5fd64ec137f622cfc082951fd584af0d230
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user