@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.
Files changed (45) hide show
  1. package/.turbo/turbo-build.log +2 -1
  2. package/build.mjs +4 -1
  3. package/dist/lib/crud/errors.js +6 -1
  4. package/dist/lib/crud/errors.js.map +2 -2
  5. package/dist/lib/crud/factory.js +22 -13
  6. package/dist/lib/crud/factory.js.map +2 -2
  7. package/dist/lib/custom-fields/kinds.js +113 -0
  8. package/dist/lib/custom-fields/kinds.js.map +7 -0
  9. package/dist/lib/encryption/indexDoc.js +12 -9
  10. package/dist/lib/encryption/indexDoc.js.map +2 -2
  11. package/dist/lib/i18n/server.js +1 -1
  12. package/dist/lib/i18n/server.js.map +2 -2
  13. package/dist/lib/location/countries.generated.js +265 -0
  14. package/dist/lib/location/countries.generated.js.map +7 -0
  15. package/dist/lib/location/countries.js +2 -13
  16. package/dist/lib/location/countries.js.map +2 -2
  17. package/dist/lib/navigation/pageReload.js +11 -0
  18. package/dist/lib/navigation/pageReload.js.map +7 -0
  19. package/dist/lib/schedule/interval.js +33 -0
  20. package/dist/lib/schedule/interval.js.map +7 -0
  21. package/dist/lib/schedule/invalidScheduleValue.js +19 -0
  22. package/dist/lib/schedule/invalidScheduleValue.js.map +7 -0
  23. package/dist/lib/version.js +1 -1
  24. package/dist/lib/version.js.map +1 -1
  25. package/package.json +3 -2
  26. package/scripts/generate-countries.mjs +75 -0
  27. package/src/lib/crud/__tests__/crud-factory.test.ts +177 -0
  28. package/src/lib/crud/__tests__/errors.test.ts +31 -1
  29. package/src/lib/crud/errors.ts +16 -0
  30. package/src/lib/crud/factory.ts +37 -15
  31. package/src/lib/custom-fields/__tests__/kinds.test.ts +208 -0
  32. package/src/lib/custom-fields/kinds.ts +205 -0
  33. package/src/lib/encryption/__tests__/indexDoc.custom-field-kinds.test.ts +127 -0
  34. package/src/lib/encryption/__tests__/indexDoc.test.ts +39 -0
  35. package/src/lib/encryption/indexDoc.ts +16 -7
  36. package/src/lib/i18n/__tests__/dictionary-locale-fallback.test.ts +49 -0
  37. package/src/lib/i18n/server.ts +13 -5
  38. package/src/lib/location/__tests__/countries.test.ts +25 -0
  39. package/src/lib/location/countries.generated.ts +264 -0
  40. package/src/lib/location/countries.ts +2 -23
  41. package/src/lib/navigation/__tests__/pageReload.test.ts +58 -0
  42. package/src/lib/navigation/pageReload.ts +43 -0
  43. package/src/lib/schedule/__tests__/interval.test.ts +37 -0
  44. package/src/lib/schedule/interval.ts +45 -0
  45. 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
+ }