@open-mercato/shared 0.8.1-develop.7274.1.21a0083828 → 0.8.1-develop.7294.1.0ef99fc518
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -1
- package/build.mjs +4 -1
- package/dist/lib/crud/errors.js +6 -1
- package/dist/lib/crud/errors.js.map +2 -2
- package/dist/lib/crud/factory.js +22 -13
- package/dist/lib/crud/factory.js.map +2 -2
- package/dist/lib/custom-fields/kinds.js +113 -0
- package/dist/lib/custom-fields/kinds.js.map +7 -0
- package/dist/lib/encryption/indexDoc.js +12 -9
- package/dist/lib/encryption/indexDoc.js.map +2 -2
- package/dist/lib/i18n/server.js +1 -1
- package/dist/lib/i18n/server.js.map +2 -2
- package/dist/lib/location/countries.generated.js +265 -0
- package/dist/lib/location/countries.generated.js.map +7 -0
- package/dist/lib/location/countries.js +2 -13
- package/dist/lib/location/countries.js.map +2 -2
- package/dist/lib/navigation/pageReload.js +11 -0
- package/dist/lib/navigation/pageReload.js.map +7 -0
- package/dist/lib/schedule/interval.js +33 -0
- package/dist/lib/schedule/interval.js.map +7 -0
- package/dist/lib/schedule/invalidScheduleValue.js +19 -0
- package/dist/lib/schedule/invalidScheduleValue.js.map +7 -0
- package/dist/lib/version.js +1 -1
- package/dist/lib/version.js.map +1 -1
- package/package.json +3 -2
- package/scripts/generate-countries.mjs +75 -0
- package/src/lib/crud/__tests__/crud-factory.test.ts +177 -0
- package/src/lib/crud/__tests__/errors.test.ts +31 -1
- package/src/lib/crud/errors.ts +16 -0
- package/src/lib/crud/factory.ts +37 -15
- package/src/lib/custom-fields/__tests__/kinds.test.ts +208 -0
- package/src/lib/custom-fields/kinds.ts +205 -0
- package/src/lib/encryption/__tests__/indexDoc.custom-field-kinds.test.ts +127 -0
- package/src/lib/encryption/__tests__/indexDoc.test.ts +39 -0
- package/src/lib/encryption/indexDoc.ts +16 -7
- package/src/lib/i18n/__tests__/dictionary-locale-fallback.test.ts +49 -0
- package/src/lib/i18n/server.ts +13 -5
- package/src/lib/location/__tests__/countries.test.ts +25 -0
- package/src/lib/location/countries.generated.ts +264 -0
- package/src/lib/location/countries.ts +2 -23
- package/src/lib/navigation/__tests__/pageReload.test.ts +58 -0
- package/src/lib/navigation/pageReload.ts +43 -0
- package/src/lib/schedule/__tests__/interval.test.ts +37 -0
- package/src/lib/schedule/interval.ts +45 -0
- package/src/lib/schedule/invalidScheduleValue.ts +33 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MIN_SCHEDULE_INTERVAL_MS,
|
|
3
|
+
isValidScheduleInterval,
|
|
4
|
+
parseScheduleInterval,
|
|
5
|
+
} from '../interval'
|
|
6
|
+
|
|
7
|
+
describe('parseScheduleInterval', () => {
|
|
8
|
+
it('converts each documented unit to milliseconds', () => {
|
|
9
|
+
expect(parseScheduleInterval('90s')).toBe(90 * 1000)
|
|
10
|
+
expect(parseScheduleInterval('15m')).toBe(15 * 60 * 1000)
|
|
11
|
+
expect(parseScheduleInterval('6h')).toBe(6 * 60 * 60 * 1000)
|
|
12
|
+
expect(parseScheduleInterval('1d')).toBe(24 * 60 * 60 * 1000)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('rejects a value that carries no unit', () => {
|
|
16
|
+
expect(() => parseScheduleInterval('3600')).toThrow('Invalid interval format: 3600')
|
|
17
|
+
})
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
describe('isValidScheduleInterval', () => {
|
|
21
|
+
it.each(['1h', '6h', '24h', '15m', '60s', '1d'])('accepts the documented format %s', (interval) => {
|
|
22
|
+
expect(isValidScheduleInterval(interval)).toBe(true)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it.each(['3600', '', ' 1h', '1h ', '1.5h', '-1h', 'hourly', '1w', '1H'])(
|
|
26
|
+
'rejects %p, which the scheduler could never run',
|
|
27
|
+
(interval) => {
|
|
28
|
+
expect(isValidScheduleInterval(interval)).toBe(false)
|
|
29
|
+
},
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
it('rejects an interval shorter than the enforced minimum', () => {
|
|
33
|
+
expect(MIN_SCHEDULE_INTERVAL_MS).toBe(60 * 1000)
|
|
34
|
+
expect(isValidScheduleInterval('30s')).toBe(false)
|
|
35
|
+
expect(isValidScheduleInterval('0m')).toBe(false)
|
|
36
|
+
})
|
|
37
|
+
})
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical interval-format rules for recurring schedules.
|
|
3
|
+
*
|
|
4
|
+
* Both the scheduler runtime and the API validators that reject a schedule
|
|
5
|
+
* before it is persisted read the format from here, so the documented format
|
|
6
|
+
* (`<number><unit>`, e.g. `15m`, `1h`, `24h`) cannot drift between the layer
|
|
7
|
+
* that accepts a value and the layer that has to run it.
|
|
8
|
+
*/
|
|
9
|
+
export const MIN_SCHEDULE_INTERVAL_MS = 60 * 1000
|
|
10
|
+
|
|
11
|
+
export const SCHEDULE_INTERVAL_PATTERN = /^(\d+)(s|m|h|d)$/
|
|
12
|
+
|
|
13
|
+
const UNIT_MULTIPLIERS: Record<string, number> = {
|
|
14
|
+
s: 1000,
|
|
15
|
+
m: 60 * 1000,
|
|
16
|
+
h: 60 * 60 * 1000,
|
|
17
|
+
d: 24 * 60 * 60 * 1000,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type ScheduleIntervalUnit = 's' | 'm' | 'h' | 'd'
|
|
21
|
+
|
|
22
|
+
export type ScheduleIntervalParts = {
|
|
23
|
+
amount: number
|
|
24
|
+
unit: ScheduleIntervalUnit
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function matchScheduleInterval(interval: string): ScheduleIntervalParts | null {
|
|
28
|
+
const match = SCHEDULE_INTERVAL_PATTERN.exec(interval)
|
|
29
|
+
if (!match) return null
|
|
30
|
+
return { amount: Number.parseInt(match[1], 10), unit: match[2] as ScheduleIntervalUnit }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function parseScheduleInterval(interval: string): number {
|
|
34
|
+
const parts = matchScheduleInterval(interval)
|
|
35
|
+
if (!parts) {
|
|
36
|
+
throw new Error(`Invalid interval format: ${interval}. Expected format: <number><unit> (e.g., 15m, 2h, 1d)`)
|
|
37
|
+
}
|
|
38
|
+
return parts.amount * UNIT_MULTIPLIERS[parts.unit]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function isValidScheduleInterval(interval: string): boolean {
|
|
42
|
+
const parts = matchScheduleInterval(interval)
|
|
43
|
+
if (!parts) return false
|
|
44
|
+
return parts.amount * UNIT_MULTIPLIERS[parts.unit] >= MIN_SCHEDULE_INTERVAL_MS
|
|
45
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export const INVALID_SCHEDULE_VALUE_CODE = 'INVALID_SCHEDULE_VALUE'
|
|
2
|
+
|
|
3
|
+
export type ScheduleValueKind = 'cron' | 'interval'
|
|
4
|
+
|
|
5
|
+
export type InvalidScheduleValueError = Error & {
|
|
6
|
+
code: typeof INVALID_SCHEDULE_VALUE_CODE
|
|
7
|
+
scheduleType: ScheduleValueKind
|
|
8
|
+
scheduleValue: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function createInvalidScheduleValueError(
|
|
12
|
+
scheduleType: ScheduleValueKind,
|
|
13
|
+
scheduleValue: string,
|
|
14
|
+
message: string,
|
|
15
|
+
): InvalidScheduleValueError {
|
|
16
|
+
return Object.assign(new Error(message), {
|
|
17
|
+
code: INVALID_SCHEDULE_VALUE_CODE,
|
|
18
|
+
scheduleType,
|
|
19
|
+
scheduleValue,
|
|
20
|
+
} as const)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Structural check rather than `instanceof`: the error crosses a package
|
|
25
|
+
* boundary (and a production bundle), where a duplicated class identity would
|
|
26
|
+
* make `instanceof` silently false.
|
|
27
|
+
*/
|
|
28
|
+
export function isInvalidScheduleValueError(error: unknown): error is InvalidScheduleValueError {
|
|
29
|
+
if (typeof error !== 'object' || error === null) return false
|
|
30
|
+
const candidate = error as { code?: unknown; scheduleType?: unknown }
|
|
31
|
+
return candidate.code === INVALID_SCHEDULE_VALUE_CODE
|
|
32
|
+
&& (candidate.scheduleType === 'cron' || candidate.scheduleType === 'interval')
|
|
33
|
+
}
|