@hexclave/shared 1.0.45 → 1.0.46

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 (109) hide show
  1. package/dist/{admin-interface-B-UjGQ0i.d.ts → admin-interface-DQcggLpw.d.ts} +11 -11
  2. package/dist/{admin-interface-B-UjGQ0i.d.ts.map → admin-interface-DQcggLpw.d.ts.map} +1 -1
  3. package/dist/{admin-metrics-1yiWGq9z.d.ts → admin-metrics-bsOkw4YQ.d.ts} +15 -15
  4. package/dist/{admin-metrics-1yiWGq9z.d.ts.map → admin-metrics-bsOkw4YQ.d.ts.map} +1 -1
  5. package/dist/{client-interface-DjVtlQix.d.ts → client-interface-BQz4jNAC.d.ts} +10 -10
  6. package/dist/{client-interface-DjVtlQix.d.ts.map → client-interface-BQz4jNAC.d.ts.map} +1 -1
  7. package/dist/config/schema.d.ts +1 -1
  8. package/dist/config-authoring.d.ts +1 -1
  9. package/dist/{current-user-BCkMYzHx.d.ts → current-user-BBoN3hsn.d.ts} +17 -17
  10. package/dist/{current-user-BCkMYzHx.d.ts.map → current-user-BBoN3hsn.d.ts.map} +1 -1
  11. package/dist/dates-BRAvSk6L.d.ts +40 -0
  12. package/dist/{dates-B6ne9iOR.d.ts.map → dates-BRAvSk6L.d.ts.map} +1 -1
  13. package/dist/{email-outbox-BRZiK0ZG.d.ts → email-outbox-CYmVerum.d.ts} +225 -225
  14. package/dist/{email-outbox-BRZiK0ZG.d.ts.map → email-outbox-CYmVerum.d.ts.map} +1 -1
  15. package/dist/esm/config/schema.d.ts +116 -116
  16. package/dist/esm/interface/admin-metrics.d.ts +14 -14
  17. package/dist/esm/interface/conversations.d.ts +37 -37
  18. package/dist/esm/interface/crud/current-user.d.ts +16 -16
  19. package/dist/esm/interface/crud/email-outbox.d.ts +224 -224
  20. package/dist/esm/interface/crud/invoices.d.ts +2 -2
  21. package/dist/esm/interface/crud/products.d.ts +21 -21
  22. package/dist/esm/interface/crud/project-api-keys.d.ts +4 -4
  23. package/dist/esm/interface/crud/projects.d.ts +59 -59
  24. package/dist/esm/interface/crud/team-member-profiles.d.ts +32 -32
  25. package/dist/esm/interface/crud/transactions.d.ts +17 -17
  26. package/dist/esm/interface/crud/transactions.d.ts.map +1 -1
  27. package/dist/esm/interface/crud/users.d.ts +22 -22
  28. package/dist/esm/interface/plan-usage.d.ts +1 -1
  29. package/dist/esm/interface/webhooks.d.ts +4 -4
  30. package/dist/esm/known-errors.d.ts +3 -3
  31. package/dist/esm/schema-fields.d.ts +12 -12
  32. package/dist/esm/schema-fields.d.ts.map +1 -1
  33. package/dist/esm/schema-fields.js +2 -2
  34. package/dist/esm/schema-fields.js.map +1 -1
  35. package/dist/esm/sessions.d.ts +9 -9
  36. package/dist/esm/utils/currencies.d.ts +16 -1
  37. package/dist/esm/utils/currencies.d.ts.map +1 -1
  38. package/dist/esm/utils/currencies.js +24 -1
  39. package/dist/esm/utils/currencies.js.map +1 -1
  40. package/dist/esm/utils/dates.d.ts +18 -1
  41. package/dist/esm/utils/dates.d.ts.map +1 -1
  42. package/dist/esm/utils/dates.js +36 -15
  43. package/dist/esm/utils/dates.js.map +1 -1
  44. package/dist/helpers/password.d.ts +1 -1
  45. package/dist/helpers/production-mode.d.ts +1 -1
  46. package/dist/index.d.ts +4 -4
  47. package/dist/interface/admin-interface.d.ts +2 -2
  48. package/dist/interface/admin-metrics.d.ts +1 -1
  49. package/dist/interface/client-interface.d.ts +1 -1
  50. package/dist/interface/conversations.d.ts +37 -37
  51. package/dist/interface/crud/current-user.d.ts +1 -1
  52. package/dist/interface/crud/email-outbox.d.ts +1 -1
  53. package/dist/interface/crud/invoices.d.ts +1 -1
  54. package/dist/interface/crud/products.d.ts +1 -1
  55. package/dist/interface/crud/project-api-keys.d.ts +1 -1
  56. package/dist/interface/crud/projects.d.ts +1 -1
  57. package/dist/interface/crud/team-member-profiles.d.ts +1 -1
  58. package/dist/interface/crud/transactions.d.ts +1 -1
  59. package/dist/interface/crud/users.d.ts +1 -1
  60. package/dist/interface/plan-usage.d.ts +1 -1
  61. package/dist/interface/server-interface.d.ts +1 -1
  62. package/dist/interface/webhooks.d.ts +1 -1
  63. package/dist/{invoices-BGLLnTlR.d.ts → invoices-CHo9YKbI.d.ts} +3 -3
  64. package/dist/{invoices-BGLLnTlR.d.ts.map → invoices-CHo9YKbI.d.ts.map} +1 -1
  65. package/dist/{known-errors-g7JC8z58.d.ts → known-errors-Bm4a61wL.d.ts} +4 -4
  66. package/dist/{known-errors-g7JC8z58.d.ts.map → known-errors-Bm4a61wL.d.ts.map} +1 -1
  67. package/dist/known-errors.d.ts +1 -1
  68. package/dist/{plan-usage-BigvGIcT.d.ts → plan-usage-ChUZqQWw.d.ts} +2 -2
  69. package/dist/{plan-usage-BigvGIcT.d.ts.map → plan-usage-ChUZqQWw.d.ts.map} +1 -1
  70. package/dist/{products-D_fcxfR0.d.ts → products-D4o8A2W0.d.ts} +23 -23
  71. package/dist/{products-D_fcxfR0.d.ts.map → products-D4o8A2W0.d.ts.map} +1 -1
  72. package/dist/{project-api-keys-OQqmKtMS.d.ts → project-api-keys--7V5X_UW.d.ts} +5 -5
  73. package/dist/{project-api-keys-OQqmKtMS.d.ts.map → project-api-keys--7V5X_UW.d.ts.map} +1 -1
  74. package/dist/{projects-C42SVFvm.d.ts → projects-CFTNXRfG.d.ts} +60 -60
  75. package/dist/{projects-C42SVFvm.d.ts.map → projects-CFTNXRfG.d.ts.map} +1 -1
  76. package/dist/{schema-Bgy-GC70.d.ts → schema-Daq0b_sf.d.ts} +118 -118
  77. package/dist/{schema-Bgy-GC70.d.ts.map → schema-Daq0b_sf.d.ts.map} +1 -1
  78. package/dist/{schema-fields-BljhsWsa.d.ts → schema-fields-DZtDQEEO.d.ts} +14 -14
  79. package/dist/schema-fields-DZtDQEEO.d.ts.map +1 -0
  80. package/dist/schema-fields.d.ts +1 -1
  81. package/dist/schema-fields.js +2 -2
  82. package/dist/schema-fields.js.map +1 -1
  83. package/dist/{server-interface-C1W1tZ_y.d.ts → server-interface-BjY-eS4Q.d.ts} +8 -8
  84. package/dist/{server-interface-C1W1tZ_y.d.ts.map → server-interface-BjY-eS4Q.d.ts.map} +1 -1
  85. package/dist/{sessions-C0nM8bE_.d.ts → sessions-CI-0TBQb.d.ts} +11 -11
  86. package/dist/{sessions-C0nM8bE_.d.ts.map → sessions-CI-0TBQb.d.ts.map} +1 -1
  87. package/dist/sessions.d.ts +1 -1
  88. package/dist/{team-member-profiles-CgYXR-Rx.d.ts → team-member-profiles-BoDEqx-0.d.ts} +33 -33
  89. package/dist/{team-member-profiles-CgYXR-Rx.d.ts.map → team-member-profiles-BoDEqx-0.d.ts.map} +1 -1
  90. package/dist/{transactions-BomBBiph.d.ts → transactions-CHNUJ42J.d.ts} +19 -19
  91. package/dist/transactions-CHNUJ42J.d.ts.map +1 -0
  92. package/dist/{users-7MKfEyyq.d.ts → users-DHNRwoSz.d.ts} +24 -24
  93. package/dist/{users-7MKfEyyq.d.ts.map → users-DHNRwoSz.d.ts.map} +1 -1
  94. package/dist/utils/currencies.d.ts +16 -1
  95. package/dist/utils/currencies.d.ts.map +1 -1
  96. package/dist/utils/currencies.js +24 -0
  97. package/dist/utils/currencies.js.map +1 -1
  98. package/dist/utils/dates.d.ts +2 -2
  99. package/dist/utils/dates.js +36 -14
  100. package/dist/utils/dates.js.map +1 -1
  101. package/dist/{webhooks-C5gG85Ce.d.ts → webhooks-8Ts1Clcb.d.ts} +5 -5
  102. package/dist/{webhooks-C5gG85Ce.d.ts.map → webhooks-8Ts1Clcb.d.ts.map} +1 -1
  103. package/package.json +1 -1
  104. package/src/schema-fields.ts +13 -2
  105. package/src/utils/currencies.tsx +69 -0
  106. package/src/utils/dates.tsx +104 -15
  107. package/dist/dates-B6ne9iOR.d.ts +0 -23
  108. package/dist/schema-fields-BljhsWsa.d.ts.map +0 -1
  109. package/dist/transactions-BomBBiph.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"dates.js","names":["intervalSchema","HexclaveAssertionError"],"sources":["../../src/utils/dates.tsx"],"sourcesContent":["import { intervalSchema } from \"../schema-fields\";\nimport { HexclaveAssertionError } from \"./errors\";\nimport { remainder } from \"./math\";\n\nexport function isWeekend(date: Date): boolean {\n return date.getDay() === 0 || date.getDay() === 6;\n}\n\nimport.meta.vitest?.test(\"isWeekend\", ({ expect }) => {\n // Sunday (day 0)\n expect(isWeekend(new Date(2023, 0, 1))).toBe(true);\n // Saturday (day 6)\n expect(isWeekend(new Date(2023, 0, 7))).toBe(true);\n // Monday (day 1)\n expect(isWeekend(new Date(2023, 0, 2))).toBe(false);\n // Friday (day 5)\n expect(isWeekend(new Date(2023, 0, 6))).toBe(false);\n});\n\nconst agoUnits = [\n [60, 'second'],\n [60, 'minute'],\n [24, 'hour'],\n [7, 'day'],\n [5, 'week'],\n] as const;\n\nexport function fromNow(date: Date): string {\n return fromNowDetailed(date).result;\n}\n\nimport.meta.vitest?.test(\"fromNow\", ({ expect }) => {\n // Set a fixed date for testing\n const fixedDate = new Date(\"2023-01-15T12:00:00.000Z\");\n\n // Use Vitest's fake timers\n import.meta.vitest?.vi.useFakeTimers();\n import.meta.vitest?.vi.setSystemTime(fixedDate);\n\n // Test past times\n expect(fromNow(new Date(\"2023-01-15T11:59:50.000Z\"))).toBe(\"just now\");\n expect(fromNow(new Date(\"2023-01-15T11:59:00.000Z\"))).toBe(\"1 minute ago\");\n expect(fromNow(new Date(\"2023-01-15T11:00:00.000Z\"))).toBe(\"1 hour ago\");\n expect(fromNow(new Date(\"2023-01-14T12:00:00.000Z\"))).toBe(\"1 day ago\");\n expect(fromNow(new Date(\"2023-01-08T12:00:00.000Z\"))).toBe(\"1 week ago\");\n\n // Test future times\n expect(fromNow(new Date(\"2023-01-15T12:00:10.000Z\"))).toBe(\"just now\");\n expect(fromNow(new Date(\"2023-01-15T12:01:00.000Z\"))).toBe(\"in 1 minute\");\n expect(fromNow(new Date(\"2023-01-15T13:00:00.000Z\"))).toBe(\"in 1 hour\");\n expect(fromNow(new Date(\"2023-01-16T12:00:00.000Z\"))).toBe(\"in 1 day\");\n expect(fromNow(new Date(\"2023-01-22T12:00:00.000Z\"))).toBe(\"in 1 week\");\n\n // Test very old dates (should use date format)\n expect(fromNow(new Date(\"2022-01-15T12:00:00.000Z\"))).toMatch(/Jan 15, 2022/);\n\n // Restore real timers\n import.meta.vitest?.vi.useRealTimers();\n});\n\nexport function fromNowDetailed(date: Date): {\n result: string,\n /**\n * May be Infinity if the result will never change.\n */\n secondsUntilChange: number,\n} {\n if (!(date instanceof Date)) {\n throw new Error(`fromNow only accepts Date objects (received: ${date})`);\n }\n\n const now = new Date();\n const elapsed = now.getTime() - date.getTime();\n\n let remainingInUnit = Math.abs(elapsed) / 1000;\n if (remainingInUnit < 15) {\n return {\n result: 'just now',\n secondsUntilChange: 15 - remainingInUnit,\n };\n }\n let unitInSeconds = 1;\n for (const [nextUnitSize, unitName] of agoUnits) {\n const rounded = Math.round(remainingInUnit);\n if (rounded < nextUnitSize) {\n if (elapsed < 0) {\n return {\n result: `in ${rounded} ${unitName}${rounded === 1 ? '' : 's'}`,\n secondsUntilChange: remainder((remainingInUnit - rounded + 0.5) * unitInSeconds, unitInSeconds),\n };\n } else {\n return {\n result: `${rounded} ${unitName}${rounded === 1 ? '' : 's'} ago`,\n secondsUntilChange: remainder((rounded - remainingInUnit - 0.5) * unitInSeconds, unitInSeconds),\n };\n }\n }\n unitInSeconds *= nextUnitSize;\n remainingInUnit /= nextUnitSize;\n }\n\n return {\n result: date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }),\n secondsUntilChange: Infinity,\n };\n}\n\n/**\n * Returns a string representation of the given date in the format expected by the `datetime-local` input type.\n */\nexport function getInputDatetimeLocalString(date: Date): string {\n date = new Date(date);\n date.setMinutes(date.getMinutes() - date.getTimezoneOffset());\n return date.toISOString().slice(0, 19);\n}\n\nimport.meta.vitest?.test(\"getInputDatetimeLocalString\", ({ expect }) => {\n // Use Vitest's fake timers to ensure consistent timezone behavior\n import.meta.vitest?.vi.useFakeTimers();\n\n // Test with a specific date\n const mockDate = new Date(\"2023-01-15T12:30:45.000Z\");\n const result = getInputDatetimeLocalString(mockDate);\n\n // The result should be in the format YYYY-MM-DDTHH:MM:SS\n expect(result).toMatch(/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$/);\n\n // Test with different dates\n const dates = [\n new Date(\"2023-01-01T00:00:00.000Z\"),\n new Date(\"2023-06-15T23:59:59.000Z\"),\n new Date(\"2023-12-31T12:34:56.000Z\"),\n ];\n\n for (const date of dates) {\n const result = getInputDatetimeLocalString(date);\n expect(result).toMatch(/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$/);\n }\n\n // Restore real timers\n import.meta.vitest?.vi.useRealTimers();\n});\n\n\nexport type Interval = [number, 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'];\nexport type DayInterval = [number, 'day' | 'week' | 'month' | 'year'];\n\nfunction applyInterval(date: Date, times: number, interval: Interval): Date {\n if (!intervalSchema.isValidSync(interval)) {\n throw new HexclaveAssertionError(`Invalid interval`, { interval });\n }\n const [amount, unit] = interval;\n switch (unit) {\n case 'millisecond': {\n date.setMilliseconds(date.getMilliseconds() + amount * times);\n break;\n }\n case 'second': {\n date.setSeconds(date.getSeconds() + amount * times);\n break;\n }\n case 'minute': {\n date.setMinutes(date.getMinutes() + amount * times);\n break;\n }\n case 'hour': {\n date.setHours(date.getHours() + amount * times);\n break;\n }\n case 'day': {\n date.setDate(date.getDate() + amount * times);\n break;\n }\n case 'week': {\n date.setDate(date.getDate() + amount * times * 7);\n break;\n }\n case 'month': {\n date.setMonth(date.getMonth() + amount * times);\n break;\n }\n case 'year': {\n date.setFullYear(date.getFullYear() + amount * times);\n break;\n }\n default: {\n throw new HexclaveAssertionError(`Invalid interval despite schema validation`, { interval });\n }\n }\n return date;\n}\n\nexport function subtractInterval(date: Date, interval: Interval): Date {\n return applyInterval(date, -1, interval);\n}\n\nexport function addInterval(date: Date, interval: Interval): Date {\n return applyInterval(date, 1, interval);\n}\n\nexport const FAR_FUTURE_DATE = new Date(8640000000000000); // 13 Sep 275760 00:00:00 UTC\n\nfunction getMsPerDayIntervalUnit(unit: 'day' | 'week'): number {\n if (unit === 'day') {\n return 24 * 60 * 60 * 1000;\n }\n return 7 * 24 * 60 * 60 * 1000;\n}\n\n\nexport function getIntervalsElapsed(anchor: Date, to: Date, repeat: DayInterval): number {\n const [amount, unit] = repeat;\n if (to <= anchor) return 0;\n if (unit === 'day' || unit === 'week') {\n const msPerUnit = getMsPerDayIntervalUnit(unit);\n const diffMs = to.getTime() - anchor.getTime();\n return Math.floor(diffMs / (msPerUnit * amount));\n }\n if ([\"month\", \"year\"].includes(unit)) {\n let count = 0;\n let current = new Date(anchor);\n for (; ;) {\n const next = addInterval(new Date(current), [amount, unit]);\n if (next > to) break;\n current = next;\n count += 1;\n }\n return count;\n }\n return 0;\n}\n\nimport.meta.vitest?.test(\"getIntervalsElapsed\", ({ expect }) => {\n const anchor = new Date('2025-01-01T00:00:00.000Z');\n const to = new Date('2025-01-15T00:00:00.000Z');\n expect(getIntervalsElapsed(anchor, to, [1, 'week'])).toBe(2);\n expect(getIntervalsElapsed(anchor, to, [3, 'day'])).toBe(4);\n\n const mAnchor = new Date('2023-01-31T00:00:00.000Z');\n const mTo = new Date('2023-03-01T00:00:00.000Z');\n expect(getIntervalsElapsed(mAnchor, mTo, [1, 'month'])).toBe(0);\n\n const yAnchor = new Date('2020-01-01T00:00:00.000Z');\n const yTo = new Date('2022-06-01T00:00:00.000Z');\n expect(getIntervalsElapsed(yAnchor, yTo, [1, 'year'])).toBe(2);\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"dates.js","names":["intervalSchema","HexclaveAssertionError"],"sources":["../../src/utils/dates.tsx"],"sourcesContent":["import { intervalSchema } from \"../schema-fields\";\nimport { HexclaveAssertionError } from \"./errors\";\nimport { remainder } from \"./math\";\n\nexport function isWeekend(date: Date): boolean {\n return date.getDay() === 0 || date.getDay() === 6;\n}\n\nimport.meta.vitest?.test(\"isWeekend\", ({ expect }) => {\n // Sunday (day 0)\n expect(isWeekend(new Date(2023, 0, 1))).toBe(true);\n // Saturday (day 6)\n expect(isWeekend(new Date(2023, 0, 7))).toBe(true);\n // Monday (day 1)\n expect(isWeekend(new Date(2023, 0, 2))).toBe(false);\n // Friday (day 5)\n expect(isWeekend(new Date(2023, 0, 6))).toBe(false);\n});\n\nconst agoUnits = [\n [60, 'second'],\n [60, 'minute'],\n [24, 'hour'],\n [7, 'day'],\n [5, 'week'],\n] as const;\n\nexport function fromNow(date: Date): string {\n return fromNowDetailed(date).result;\n}\n\nimport.meta.vitest?.test(\"fromNow\", ({ expect }) => {\n // Set a fixed date for testing\n const fixedDate = new Date(\"2023-01-15T12:00:00.000Z\");\n\n // Use Vitest's fake timers\n import.meta.vitest?.vi.useFakeTimers();\n import.meta.vitest?.vi.setSystemTime(fixedDate);\n\n // Test past times\n expect(fromNow(new Date(\"2023-01-15T11:59:50.000Z\"))).toBe(\"just now\");\n expect(fromNow(new Date(\"2023-01-15T11:59:00.000Z\"))).toBe(\"1 minute ago\");\n expect(fromNow(new Date(\"2023-01-15T11:00:00.000Z\"))).toBe(\"1 hour ago\");\n expect(fromNow(new Date(\"2023-01-14T12:00:00.000Z\"))).toBe(\"1 day ago\");\n expect(fromNow(new Date(\"2023-01-08T12:00:00.000Z\"))).toBe(\"1 week ago\");\n\n // Test future times\n expect(fromNow(new Date(\"2023-01-15T12:00:10.000Z\"))).toBe(\"just now\");\n expect(fromNow(new Date(\"2023-01-15T12:01:00.000Z\"))).toBe(\"in 1 minute\");\n expect(fromNow(new Date(\"2023-01-15T13:00:00.000Z\"))).toBe(\"in 1 hour\");\n expect(fromNow(new Date(\"2023-01-16T12:00:00.000Z\"))).toBe(\"in 1 day\");\n expect(fromNow(new Date(\"2023-01-22T12:00:00.000Z\"))).toBe(\"in 1 week\");\n\n // Test very old dates (should use date format)\n expect(fromNow(new Date(\"2022-01-15T12:00:00.000Z\"))).toMatch(/Jan 15, 2022/);\n\n // Restore real timers\n import.meta.vitest?.vi.useRealTimers();\n});\n\nexport function fromNowDetailed(date: Date): {\n result: string,\n /**\n * May be Infinity if the result will never change.\n */\n secondsUntilChange: number,\n} {\n if (!(date instanceof Date)) {\n throw new Error(`fromNow only accepts Date objects (received: ${date})`);\n }\n\n const now = new Date();\n const elapsed = now.getTime() - date.getTime();\n\n let remainingInUnit = Math.abs(elapsed) / 1000;\n if (remainingInUnit < 15) {\n return {\n result: 'just now',\n secondsUntilChange: 15 - remainingInUnit,\n };\n }\n let unitInSeconds = 1;\n for (const [nextUnitSize, unitName] of agoUnits) {\n const rounded = Math.round(remainingInUnit);\n if (rounded < nextUnitSize) {\n if (elapsed < 0) {\n return {\n result: `in ${rounded} ${unitName}${rounded === 1 ? '' : 's'}`,\n secondsUntilChange: remainder((remainingInUnit - rounded + 0.5) * unitInSeconds, unitInSeconds),\n };\n } else {\n return {\n result: `${rounded} ${unitName}${rounded === 1 ? '' : 's'} ago`,\n secondsUntilChange: remainder((rounded - remainingInUnit - 0.5) * unitInSeconds, unitInSeconds),\n };\n }\n }\n unitInSeconds *= nextUnitSize;\n remainingInUnit /= nextUnitSize;\n }\n\n return {\n result: date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }),\n secondsUntilChange: Infinity,\n };\n}\n\n/**\n * Returns a string representation of the given date in the format expected by the `datetime-local` input type.\n */\nexport function getInputDatetimeLocalString(date: Date): string {\n date = new Date(date);\n date.setMinutes(date.getMinutes() - date.getTimezoneOffset());\n return date.toISOString().slice(0, 19);\n}\n\nimport.meta.vitest?.test(\"getInputDatetimeLocalString\", ({ expect }) => {\n // Use Vitest's fake timers to ensure consistent timezone behavior\n import.meta.vitest?.vi.useFakeTimers();\n\n // Test with a specific date\n const mockDate = new Date(\"2023-01-15T12:30:45.000Z\");\n const result = getInputDatetimeLocalString(mockDate);\n\n // The result should be in the format YYYY-MM-DDTHH:MM:SS\n expect(result).toMatch(/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$/);\n\n // Test with different dates\n const dates = [\n new Date(\"2023-01-01T00:00:00.000Z\"),\n new Date(\"2023-06-15T23:59:59.000Z\"),\n new Date(\"2023-12-31T12:34:56.000Z\"),\n ];\n\n for (const date of dates) {\n const result = getInputDatetimeLocalString(date);\n expect(result).toMatch(/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$/);\n }\n\n // Restore real timers\n import.meta.vitest?.vi.useRealTimers();\n});\n\n\nexport type Interval = [number, 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'];\nexport type DayInterval = [number, 'day' | 'week' | 'month' | 'year'];\n\nfunction applyInterval(date: Date, times: number, interval: Interval): Date {\n if (!intervalSchema.isValidSync(interval)) {\n throw new HexclaveAssertionError(`Invalid interval`, { interval });\n }\n const [amount, unit] = interval;\n switch (unit) {\n case 'millisecond': {\n date.setMilliseconds(date.getMilliseconds() + amount * times);\n break;\n }\n case 'second': {\n date.setSeconds(date.getSeconds() + amount * times);\n break;\n }\n case 'minute': {\n date.setMinutes(date.getMinutes() + amount * times);\n break;\n }\n case 'hour': {\n date.setHours(date.getHours() + amount * times);\n break;\n }\n case 'day': {\n date.setDate(date.getDate() + amount * times);\n break;\n }\n case 'week': {\n date.setDate(date.getDate() + amount * times * 7);\n break;\n }\n case 'month': {\n date.setMonth(date.getMonth() + amount * times);\n break;\n }\n case 'year': {\n date.setFullYear(date.getFullYear() + amount * times);\n break;\n }\n default: {\n throw new HexclaveAssertionError(`Invalid interval despite schema validation`, { interval });\n }\n }\n return date;\n}\n\nexport function subtractInterval(date: Date, interval: Interval): Date {\n return applyInterval(date, -1, interval);\n}\n\n// One-shot local-time interval arithmetic that OVERFLOWS (Jan 31 + 1 month -> Mar 3, via\n// Date#setMonth) rather than clamping. Use this for single-step period math where JS/Stripe overflow\n// semantics are what we want (e.g. computing a subscription's currentPeriodEnd). For recurring\n// grant/reset BOUNDARIES, use `nthDayIntervalMillis` / `getIntervalsElapsed` instead — they clamp to\n// month-end and compute in UTC from a fixed anchor, and mixing the two would drift.\nexport function addInterval(date: Date, interval: Interval): Date {\n return applyInterval(date, 1, interval);\n}\n\nexport const FAR_FUTURE_DATE = new Date(8640000000000000); // 13 Sep 275760 00:00:00 UTC\n\nfunction getMsPerDayIntervalUnit(unit: 'day' | 'week'): number {\n if (unit === 'day') {\n return 24 * 60 * 60 * 1000;\n }\n return 7 * 24 * 60 * 60 * 1000;\n}\n\n\n// The number of full `repeat` intervals elapsed from `anchor` up to (and including) `to`, i.e. the\n// largest n >= 0 with the n-th boundary <= to. Boundaries are the SAME ones `nthDayIntervalMillis`\n// computes (anchor-relative, UTC, month-end clamped), so counting and boundary-computation never\n// disagree — a Jan 31 monthly anchor has elapsed one interval by Feb 28, matching the reset the\n// bulldozer item-repeat fold actually emits. (This is why it must NOT be built on `addInterval`,\n// which is local-time and overflows instead of clamping.)\nexport function getIntervalsElapsed(anchor: Date, to: Date, repeat: DayInterval): number {\n const [amount, unit] = repeat;\n const toMillis = to.getTime();\n if (toMillis <= anchor.getTime()) return 0;\n if (unit === 'day' || unit === 'week') {\n const msPerUnit = getMsPerDayIntervalUnit(unit);\n const diffMs = toMillis - anchor.getTime();\n return Math.floor(diffMs / (msPerUnit * amount));\n }\n // month/year: walk anchor-relative boundaries. The count is small in practice (bounded by the\n // number of billing periods since the anchor), so a linear walk is fine.\n let count = 0;\n while (nthDayIntervalMillis(anchor.getTime(), repeat, count + 1) <= toMillis) count += 1;\n return count;\n}\n\nimport.meta.vitest?.test(\"getIntervalsElapsed\", ({ expect }) => {\n const anchor = new Date('2025-01-01T00:00:00.000Z');\n const to = new Date('2025-01-15T00:00:00.000Z');\n expect(getIntervalsElapsed(anchor, to, [1, 'week'])).toBe(2);\n expect(getIntervalsElapsed(anchor, to, [3, 'day'])).toBe(4);\n\n // Jan 31 monthly anchor: the first boundary is clamped to Feb 28, which is <= Mar 1, so one\n // interval has elapsed (anchor-relative clamped math, consistent with nthDayIntervalMillis).\n const mAnchor = new Date('2023-01-31T00:00:00.000Z');\n const mTo = new Date('2023-03-01T00:00:00.000Z');\n expect(getIntervalsElapsed(mAnchor, mTo, [1, 'month'])).toBe(1);\n\n const yAnchor = new Date('2020-01-01T00:00:00.000Z');\n const yTo = new Date('2022-06-01T00:00:00.000Z');\n expect(getIntervalsElapsed(yAnchor, yTo, [1, 'year'])).toBe(2);\n});\n\n/**\n * The UTC millis of the `occurrence`-th (1-based) repeat of `interval` after `anchorMillis`.\n *\n * Each boundary is computed from the *original* anchor (never by stepping off the previous, possibly\n * clamped, boundary) so the anchor's day-of-month is preserved across resets: a Jan 31 anchor yields\n * Feb 28, Mar 31, Apr 30, ... (matching Stripe's billing-cycle behavior) rather than drifting to\n * Feb 28, Mar 28, ... . Month/year overflow (e.g. Jan 31 -> Feb) is clamped to the target month's\n * last day. Day/week are exact multiples (no calendar involved, so no drift possible).\n *\n * Everything is done in UTC (unlike `addInterval`, which uses local-time Date accessors) so the\n * result is deterministic regardless of the server's timezone — this is relied upon by bulldozer\n * folds, which must be reproducible across machines.\n *\n * `occurrence` 0 returns the anchor itself; `getIntervalsElapsed` counts these same boundaries, so\n * the two are always consistent for a given DayInterval.\n */\nexport function nthDayIntervalMillis(anchorMillis: number, interval: DayInterval, occurrence: number): number {\n const [count, unit] = interval;\n const totalUnits = count * occurrence;\n if (unit === 'day' || unit === 'week') {\n return anchorMillis + totalUnits * getMsPerDayIntervalUnit(unit);\n }\n const anchor = new Date(anchorMillis);\n const monthsToAdd = unit === 'year' ? totalUnits * 12 : totalUnits;\n const absoluteMonth = anchor.getUTCFullYear() * 12 + anchor.getUTCMonth() + monthsToAdd;\n const targetYear = Math.floor(absoluteMonth / 12);\n const targetMonth = absoluteMonth - targetYear * 12;\n // Day 0 of the following month is the last day of the target month, so this gives its length.\n const daysInTargetMonth = new Date(Date.UTC(targetYear, targetMonth + 1, 0)).getUTCDate();\n const clampedDay = Math.min(anchor.getUTCDate(), daysInTargetMonth);\n return Date.UTC(\n targetYear,\n targetMonth,\n clampedDay,\n anchor.getUTCHours(),\n anchor.getUTCMinutes(),\n anchor.getUTCSeconds(),\n anchor.getUTCMilliseconds(),\n );\n}\n\nimport.meta.vitest?.test(\"nthDayIntervalMillis\", ({ expect }) => {\n const at = (iso: string) => new Date(iso).getTime();\n const iso = (millis: number) => new Date(millis).toISOString();\n\n // day / week are exact multiples (no drift), and honor the count.\n const dayAnchor = at('2025-01-01T08:30:00.000Z');\n expect(iso(nthDayIntervalMillis(dayAnchor, [1, 'day'], 1))).toBe('2025-01-02T08:30:00.000Z');\n expect(iso(nthDayIntervalMillis(dayAnchor, [3, 'day'], 4))).toBe('2025-01-13T08:30:00.000Z');\n expect(iso(nthDayIntervalMillis(dayAnchor, [2, 'week'], 3))).toBe('2025-02-12T08:30:00.000Z'); // 6 weeks = 42 days after Jan 1\n\n // Jan 31 monthly: clamp in short months, restore to the anchor day in long ones.\n const jan31 = at('2025-01-31T00:00:00.000Z');\n expect(iso(nthDayIntervalMillis(jan31, [1, 'month'], 1))).toBe('2025-02-28T00:00:00.000Z');\n expect(iso(nthDayIntervalMillis(jan31, [1, 'month'], 2))).toBe('2025-03-31T00:00:00.000Z');\n expect(iso(nthDayIntervalMillis(jan31, [1, 'month'], 3))).toBe('2025-04-30T00:00:00.000Z');\n\n // Anchor-day preservation: a Feb 28 anchor stays on day 28 (never jumps to Mar 31), unlike the\n // Jan 31 anchor above which restores to Mar 31. This is the evidence we compute from the anchor.\n const feb28 = at('2025-02-28T00:00:00.000Z');\n expect(iso(nthDayIntervalMillis(feb28, [1, 'month'], 1))).toBe('2025-03-28T00:00:00.000Z');\n\n // Leap-year Feb: Feb 29 anchor clamps to Feb 28 in a non-leap year and restores in the next leap year.\n const feb29 = at('2024-02-29T00:00:00.000Z');\n expect(iso(nthDayIntervalMillis(feb29, [1, 'year'], 1))).toBe('2025-02-28T00:00:00.000Z');\n expect(iso(nthDayIntervalMillis(feb29, [1, 'year'], 4))).toBe('2028-02-29T00:00:00.000Z');\n // Jan 31 monthly landing in a leap February clamps to Feb 29, not Feb 28.\n const jan31Leap = at('2024-01-31T00:00:00.000Z');\n expect(iso(nthDayIntervalMillis(jan31Leap, [1, 'month'], 1))).toBe('2024-02-29T00:00:00.000Z');\n\n // End-of-December rollover: absolute-month math carries the year.\n const dec31 = at('2025-12-31T00:00:00.000Z');\n expect(iso(nthDayIntervalMillis(dec31, [1, 'month'], 1))).toBe('2026-01-31T00:00:00.000Z');\n expect(iso(nthDayIntervalMillis(dec31, [1, 'month'], 2))).toBe('2026-02-28T00:00:00.000Z');\n expect(iso(nthDayIntervalMillis(dec31, [1, 'month'], 3))).toBe('2026-03-31T00:00:00.000Z');\n expect(iso(nthDayIntervalMillis(dec31, [1, 'year'], 1))).toBe('2026-12-31T00:00:00.000Z');\n\n // Time-of-day is preserved through month clamping.\n const withTime = at('2025-01-31T13:45:59.123Z');\n expect(iso(nthDayIntervalMillis(withTime, [1, 'month'], 1))).toBe('2025-02-28T13:45:59.123Z');\n});\n"],"mappings":"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"}
@@ -20,10 +20,10 @@ declare const webhookEvents: readonly [WebhookEvent<yup$1.ObjectSchema<{
20
20
  client_metadata?: {} | null | undefined;
21
21
  client_read_only_metadata?: {} | null | undefined;
22
22
  server_metadata?: {} | null | undefined;
23
- id: string;
24
23
  display_name: string;
25
- profile_image_url: string | null;
24
+ id: string;
26
25
  created_at_millis: number;
26
+ profile_image_url: string | null;
27
27
  } | null;
28
28
  selected_team_id: string | null;
29
29
  profile_image_url: string | null;
@@ -110,10 +110,10 @@ declare const webhookEvents: readonly [WebhookEvent<yup$1.ObjectSchema<{
110
110
  client_metadata?: {} | null | undefined;
111
111
  client_read_only_metadata?: {} | null | undefined;
112
112
  server_metadata?: {} | null | undefined;
113
- id: string;
114
113
  display_name: string;
115
- profile_image_url: string | null;
114
+ id: string;
116
115
  created_at_millis: number;
116
+ profile_image_url: string | null;
117
117
  } | null;
118
118
  selected_team_id: string | null;
119
119
  profile_image_url: string | null;
@@ -323,4 +323,4 @@ declare const webhookEvents: readonly [WebhookEvent<yup$1.ObjectSchema<{
323
323
  }];
324
324
  //#endregion
325
325
  export { webhookEvents as n, WebhookEvent as t };
326
- //# sourceMappingURL=webhooks-C5gG85Ce.d.ts.map
326
+ //# sourceMappingURL=webhooks-8Ts1Clcb.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks-C5gG85Ce.d.ts","names":[],"sources":["../src/interface/webhooks.ts"],"mappings":";;;KAMY,YAAA,WAAuB,KAAA,CAAI,MAAA;EACrC,IAAA;EACA,MAAA,EAAQ,CAAC;EACT,QAAA;IACE,OAAA;IACA,WAAA;IACA,IAAA;EAAA;AAAA;AAAA,cAIS,aAAA,YAAa,YAAA,CAAA,KAAA,CAAA,YAAA"}
1
+ {"version":3,"file":"webhooks-8Ts1Clcb.d.ts","names":[],"sources":["../src/interface/webhooks.ts"],"mappings":";;;KAMY,YAAA,WAAuB,KAAA,CAAI,MAAA;EACrC,IAAA;EACA,MAAA,EAAQ,CAAC;EACT,QAAA;IACE,OAAA;IACA,WAAA;IACA,IAAA;EAAA;AAAA;AAAA,cAIS,aAAA,YAAa,YAAA,CAAA,KAAA,CAAA,YAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hexclave/shared",
3
- "version": "1.0.45",
3
+ "version": "1.0.46",
4
4
  "repository": "https://github.com/hexclave/hexclave",
5
5
  "files": [
6
6
  "README.md",
@@ -444,10 +444,21 @@ import.meta.vitest?.test("countryCodeSchema", async ({ expect }) => {
444
444
  await expect(countryCodeSchema.validate(" us ")).resolves.toBe("US");
445
445
  await expect(countryCodeSchema.validate("usa")).rejects.toThrow("must be a 2-letter country code");
446
446
  });
447
- export const intervalSchema = yupTuple<Interval>([yupNumber().min(0).integer().defined(), yupString().oneOf(['millisecond', 'second', 'minute', 'hour', 'day', 'week', 'month', 'year']).defined()]);
448
- export const dayIntervalSchema = yupTuple<DayInterval>([yupNumber().min(0).integer().defined(), yupString().oneOf(['day', 'week', 'month', 'year']).defined()]);
447
+ // Interval counts must be >= 1: a zero-length interval is meaningless for billing
448
+ // intervals, free trials, and item repeats alike, and a zero repeat interval in
449
+ // particular makes the bulldozer tick loop spin forever on a never-advancing
450
+ // trigger (see apps/bulldozer-js repeatIntervalMs).
451
+ export const intervalSchema = yupTuple<Interval>([yupNumber().min(1).integer().defined(), yupString().oneOf(['millisecond', 'second', 'minute', 'hour', 'day', 'week', 'month', 'year']).defined()]);
452
+ export const dayIntervalSchema = yupTuple<DayInterval>([yupNumber().min(1).integer().defined(), yupString().oneOf(['day', 'week', 'month', 'year']).defined()]);
449
453
  export const intervalOrNeverSchema = yupUnion(intervalSchema.defined(), yupString().oneOf(['never']).defined());
450
454
  export const dayIntervalOrNeverSchema = yupUnion(dayIntervalSchema.defined(), yupString().oneOf(['never']).defined());
455
+ import.meta.vitest?.test("interval schemas reject a zero/negative count", async ({ expect }) => {
456
+ await expect(intervalSchema.validate([1, "day"])).resolves.toEqual([1, "day"]);
457
+ await expect(dayIntervalSchema.validate([2, "month"])).resolves.toEqual([2, "month"]);
458
+ await expect(intervalSchema.validate([0, "day"])).rejects.toThrow();
459
+ await expect(dayIntervalSchema.validate([0, "month"])).rejects.toThrow();
460
+ await expect(dayIntervalSchema.validate([-1, "day"])).rejects.toThrow();
461
+ });
451
462
  /**
452
463
  * This schema is useful for fields where the user can specify the ID, such as price IDs. It is particularly common
453
464
  * for IDs in the config schema.
@@ -18,6 +18,40 @@ export function moneyAmountToStripeUnits(amount: MoneyAmount, currency: Currency
18
18
  return Number.parseInt(whole + paddedFractional, 10);
19
19
  }
20
20
 
21
+ /**
22
+ * Inverse of `moneyAmountToStripeUnits`: formats an integer minor-unit amount
23
+ * (e.g. cents) back into the canonical decimal money string for the currency.
24
+ * E.g. for USD (2 decimals): 5000 → "50.00", 1 → "0.01"; for JPY (0 decimals):
25
+ * 500 → "500".
26
+ *
27
+ * Prefer this over `String(number)` whenever an amount is scaled: money math
28
+ * must happen in integer minor units, because float multiplication like
29
+ * `19.99 * 3` yields `59.97000000000001`, which `moneyAmountSchema` then rejects
30
+ * for having more than the currency's allowed decimals.
31
+ *
32
+ * Money amounts are non-negative (see `MoneyAmount`), so a negative input is a
33
+ * programming error and throws rather than silently dropping the sign.
34
+ */
35
+ export function stripeUnitsToMoneyAmount(stripeUnits: number, currency: Currency): MoneyAmount {
36
+ if (!Number.isFinite(stripeUnits) || Math.trunc(stripeUnits) !== stripeUnits) {
37
+ throw new HexclaveAssertionError("Stripe units must be an integer", { stripeUnits });
38
+ }
39
+ if (stripeUnits < 0) {
40
+ throw new HexclaveAssertionError("Money amounts are non-negative; cannot represent negative stripe units", { stripeUnits });
41
+ }
42
+ if (currency.stripeDecimals !== currency.decimals) {
43
+ throw new HexclaveAssertionError("unimplemented: TODO support different decimal configurations");
44
+ }
45
+ const decimals = currency.decimals;
46
+ if (decimals === 0) return `${stripeUnits}` as MoneyAmount;
47
+ // Pad so there's always at least one integer digit plus `decimals` fractional
48
+ // digits, then split at the dot position.
49
+ const padded = stripeUnits.toString().padStart(decimals + 1, "0");
50
+ const integerPart = padded.slice(0, padded.length - decimals);
51
+ const fractionalPart = padded.slice(padded.length - decimals);
52
+ return `${integerPart}.${fractionalPart}` as MoneyAmount;
53
+ }
54
+
21
55
  import.meta.vitest?.describe("moneyAmountToStripeUnits", (test) => {
22
56
  const USD = SUPPORTED_CURRENCIES.find((c) => c.code === "USD")!;
23
57
 
@@ -51,3 +85,38 @@ import.meta.vitest?.describe("moneyAmountToStripeUnits", (test) => {
51
85
  expect(() => moneyAmountToStripeUnits("05" as MoneyAmount, USD)).toThrow();
52
86
  });
53
87
  });
88
+
89
+ import.meta.vitest?.describe("stripeUnitsToMoneyAmount", (test) => {
90
+ const USD = SUPPORTED_CURRENCIES.find((c) => c.code === "USD")!;
91
+ const JPY = SUPPORTED_CURRENCIES.find((c) => c.code === "JPY")!;
92
+
93
+ test("formats USD minor units as a 2-decimal string", ({ expect }) => {
94
+ expect(stripeUnitsToMoneyAmount(5000, USD)).toBe("50.00");
95
+ expect(stripeUnitsToMoneyAmount(1, USD)).toBe("0.01");
96
+ expect(stripeUnitsToMoneyAmount(100, USD)).toBe("1.00");
97
+ expect(stripeUnitsToMoneyAmount(0, USD)).toBe("0.00");
98
+ });
99
+
100
+ test("formats 0-decimal currencies without a dot", ({ expect }) => {
101
+ expect(stripeUnitsToMoneyAmount(500, JPY)).toBe("500");
102
+ expect(stripeUnitsToMoneyAmount(0, JPY)).toBe("0");
103
+ });
104
+
105
+ test("round-trips with moneyAmountToStripeUnits", ({ expect }) => {
106
+ for (const cents of [0, 1, 5, 50, 99, 100, 1234, 100000]) {
107
+ expect(moneyAmountToStripeUnits(stripeUnitsToMoneyAmount(cents, USD), USD)).toBe(cents);
108
+ }
109
+ });
110
+
111
+ test("scaling in minor units avoids float artifacts", ({ expect }) => {
112
+ // 19.99 * 3 in float is 59.97000000000001; via minor units it is exact.
113
+ const scaled = moneyAmountToStripeUnits("19.99" as MoneyAmount, USD) * 3;
114
+ expect(stripeUnitsToMoneyAmount(scaled, USD)).toBe("59.97");
115
+ });
116
+
117
+ test("rejects non-integer and negative inputs", ({ expect }) => {
118
+ expect(() => stripeUnitsToMoneyAmount(1.5, USD)).toThrow();
119
+ expect(() => stripeUnitsToMoneyAmount(-1, USD)).toThrow();
120
+ expect(() => stripeUnitsToMoneyAmount(Number.NaN, USD)).toThrow();
121
+ });
122
+ });
@@ -194,6 +194,11 @@ export function subtractInterval(date: Date, interval: Interval): Date {
194
194
  return applyInterval(date, -1, interval);
195
195
  }
196
196
 
197
+ // One-shot local-time interval arithmetic that OVERFLOWS (Jan 31 + 1 month -> Mar 3, via
198
+ // Date#setMonth) rather than clamping. Use this for single-step period math where JS/Stripe overflow
199
+ // semantics are what we want (e.g. computing a subscription's currentPeriodEnd). For recurring
200
+ // grant/reset BOUNDARIES, use `nthDayIntervalMillis` / `getIntervalsElapsed` instead — they clamp to
201
+ // month-end and compute in UTC from a fixed anchor, and mixing the two would drift.
197
202
  export function addInterval(date: Date, interval: Interval): Date {
198
203
  return applyInterval(date, 1, interval);
199
204
  }
@@ -208,26 +213,26 @@ function getMsPerDayIntervalUnit(unit: 'day' | 'week'): number {
208
213
  }
209
214
 
210
215
 
216
+ // The number of full `repeat` intervals elapsed from `anchor` up to (and including) `to`, i.e. the
217
+ // largest n >= 0 with the n-th boundary <= to. Boundaries are the SAME ones `nthDayIntervalMillis`
218
+ // computes (anchor-relative, UTC, month-end clamped), so counting and boundary-computation never
219
+ // disagree — a Jan 31 monthly anchor has elapsed one interval by Feb 28, matching the reset the
220
+ // bulldozer item-repeat fold actually emits. (This is why it must NOT be built on `addInterval`,
221
+ // which is local-time and overflows instead of clamping.)
211
222
  export function getIntervalsElapsed(anchor: Date, to: Date, repeat: DayInterval): number {
212
223
  const [amount, unit] = repeat;
213
- if (to <= anchor) return 0;
224
+ const toMillis = to.getTime();
225
+ if (toMillis <= anchor.getTime()) return 0;
214
226
  if (unit === 'day' || unit === 'week') {
215
227
  const msPerUnit = getMsPerDayIntervalUnit(unit);
216
- const diffMs = to.getTime() - anchor.getTime();
228
+ const diffMs = toMillis - anchor.getTime();
217
229
  return Math.floor(diffMs / (msPerUnit * amount));
218
230
  }
219
- if (["month", "year"].includes(unit)) {
220
- let count = 0;
221
- let current = new Date(anchor);
222
- for (; ;) {
223
- const next = addInterval(new Date(current), [amount, unit]);
224
- if (next > to) break;
225
- current = next;
226
- count += 1;
227
- }
228
- return count;
229
- }
230
- return 0;
231
+ // month/year: walk anchor-relative boundaries. The count is small in practice (bounded by the
232
+ // number of billing periods since the anchor), so a linear walk is fine.
233
+ let count = 0;
234
+ while (nthDayIntervalMillis(anchor.getTime(), repeat, count + 1) <= toMillis) count += 1;
235
+ return count;
231
236
  }
232
237
 
233
238
  import.meta.vitest?.test("getIntervalsElapsed", ({ expect }) => {
@@ -236,11 +241,95 @@ import.meta.vitest?.test("getIntervalsElapsed", ({ expect }) => {
236
241
  expect(getIntervalsElapsed(anchor, to, [1, 'week'])).toBe(2);
237
242
  expect(getIntervalsElapsed(anchor, to, [3, 'day'])).toBe(4);
238
243
 
244
+ // Jan 31 monthly anchor: the first boundary is clamped to Feb 28, which is <= Mar 1, so one
245
+ // interval has elapsed (anchor-relative clamped math, consistent with nthDayIntervalMillis).
239
246
  const mAnchor = new Date('2023-01-31T00:00:00.000Z');
240
247
  const mTo = new Date('2023-03-01T00:00:00.000Z');
241
- expect(getIntervalsElapsed(mAnchor, mTo, [1, 'month'])).toBe(0);
248
+ expect(getIntervalsElapsed(mAnchor, mTo, [1, 'month'])).toBe(1);
242
249
 
243
250
  const yAnchor = new Date('2020-01-01T00:00:00.000Z');
244
251
  const yTo = new Date('2022-06-01T00:00:00.000Z');
245
252
  expect(getIntervalsElapsed(yAnchor, yTo, [1, 'year'])).toBe(2);
246
253
  });
254
+
255
+ /**
256
+ * The UTC millis of the `occurrence`-th (1-based) repeat of `interval` after `anchorMillis`.
257
+ *
258
+ * Each boundary is computed from the *original* anchor (never by stepping off the previous, possibly
259
+ * clamped, boundary) so the anchor's day-of-month is preserved across resets: a Jan 31 anchor yields
260
+ * Feb 28, Mar 31, Apr 30, ... (matching Stripe's billing-cycle behavior) rather than drifting to
261
+ * Feb 28, Mar 28, ... . Month/year overflow (e.g. Jan 31 -> Feb) is clamped to the target month's
262
+ * last day. Day/week are exact multiples (no calendar involved, so no drift possible).
263
+ *
264
+ * Everything is done in UTC (unlike `addInterval`, which uses local-time Date accessors) so the
265
+ * result is deterministic regardless of the server's timezone — this is relied upon by bulldozer
266
+ * folds, which must be reproducible across machines.
267
+ *
268
+ * `occurrence` 0 returns the anchor itself; `getIntervalsElapsed` counts these same boundaries, so
269
+ * the two are always consistent for a given DayInterval.
270
+ */
271
+ export function nthDayIntervalMillis(anchorMillis: number, interval: DayInterval, occurrence: number): number {
272
+ const [count, unit] = interval;
273
+ const totalUnits = count * occurrence;
274
+ if (unit === 'day' || unit === 'week') {
275
+ return anchorMillis + totalUnits * getMsPerDayIntervalUnit(unit);
276
+ }
277
+ const anchor = new Date(anchorMillis);
278
+ const monthsToAdd = unit === 'year' ? totalUnits * 12 : totalUnits;
279
+ const absoluteMonth = anchor.getUTCFullYear() * 12 + anchor.getUTCMonth() + monthsToAdd;
280
+ const targetYear = Math.floor(absoluteMonth / 12);
281
+ const targetMonth = absoluteMonth - targetYear * 12;
282
+ // Day 0 of the following month is the last day of the target month, so this gives its length.
283
+ const daysInTargetMonth = new Date(Date.UTC(targetYear, targetMonth + 1, 0)).getUTCDate();
284
+ const clampedDay = Math.min(anchor.getUTCDate(), daysInTargetMonth);
285
+ return Date.UTC(
286
+ targetYear,
287
+ targetMonth,
288
+ clampedDay,
289
+ anchor.getUTCHours(),
290
+ anchor.getUTCMinutes(),
291
+ anchor.getUTCSeconds(),
292
+ anchor.getUTCMilliseconds(),
293
+ );
294
+ }
295
+
296
+ import.meta.vitest?.test("nthDayIntervalMillis", ({ expect }) => {
297
+ const at = (iso: string) => new Date(iso).getTime();
298
+ const iso = (millis: number) => new Date(millis).toISOString();
299
+
300
+ // day / week are exact multiples (no drift), and honor the count.
301
+ const dayAnchor = at('2025-01-01T08:30:00.000Z');
302
+ expect(iso(nthDayIntervalMillis(dayAnchor, [1, 'day'], 1))).toBe('2025-01-02T08:30:00.000Z');
303
+ expect(iso(nthDayIntervalMillis(dayAnchor, [3, 'day'], 4))).toBe('2025-01-13T08:30:00.000Z');
304
+ expect(iso(nthDayIntervalMillis(dayAnchor, [2, 'week'], 3))).toBe('2025-02-12T08:30:00.000Z'); // 6 weeks = 42 days after Jan 1
305
+
306
+ // Jan 31 monthly: clamp in short months, restore to the anchor day in long ones.
307
+ const jan31 = at('2025-01-31T00:00:00.000Z');
308
+ expect(iso(nthDayIntervalMillis(jan31, [1, 'month'], 1))).toBe('2025-02-28T00:00:00.000Z');
309
+ expect(iso(nthDayIntervalMillis(jan31, [1, 'month'], 2))).toBe('2025-03-31T00:00:00.000Z');
310
+ expect(iso(nthDayIntervalMillis(jan31, [1, 'month'], 3))).toBe('2025-04-30T00:00:00.000Z');
311
+
312
+ // Anchor-day preservation: a Feb 28 anchor stays on day 28 (never jumps to Mar 31), unlike the
313
+ // Jan 31 anchor above which restores to Mar 31. This is the evidence we compute from the anchor.
314
+ const feb28 = at('2025-02-28T00:00:00.000Z');
315
+ expect(iso(nthDayIntervalMillis(feb28, [1, 'month'], 1))).toBe('2025-03-28T00:00:00.000Z');
316
+
317
+ // Leap-year Feb: Feb 29 anchor clamps to Feb 28 in a non-leap year and restores in the next leap year.
318
+ const feb29 = at('2024-02-29T00:00:00.000Z');
319
+ expect(iso(nthDayIntervalMillis(feb29, [1, 'year'], 1))).toBe('2025-02-28T00:00:00.000Z');
320
+ expect(iso(nthDayIntervalMillis(feb29, [1, 'year'], 4))).toBe('2028-02-29T00:00:00.000Z');
321
+ // Jan 31 monthly landing in a leap February clamps to Feb 29, not Feb 28.
322
+ const jan31Leap = at('2024-01-31T00:00:00.000Z');
323
+ expect(iso(nthDayIntervalMillis(jan31Leap, [1, 'month'], 1))).toBe('2024-02-29T00:00:00.000Z');
324
+
325
+ // End-of-December rollover: absolute-month math carries the year.
326
+ const dec31 = at('2025-12-31T00:00:00.000Z');
327
+ expect(iso(nthDayIntervalMillis(dec31, [1, 'month'], 1))).toBe('2026-01-31T00:00:00.000Z');
328
+ expect(iso(nthDayIntervalMillis(dec31, [1, 'month'], 2))).toBe('2026-02-28T00:00:00.000Z');
329
+ expect(iso(nthDayIntervalMillis(dec31, [1, 'month'], 3))).toBe('2026-03-31T00:00:00.000Z');
330
+ expect(iso(nthDayIntervalMillis(dec31, [1, 'year'], 1))).toBe('2026-12-31T00:00:00.000Z');
331
+
332
+ // Time-of-day is preserved through month clamping.
333
+ const withTime = at('2025-01-31T13:45:59.123Z');
334
+ expect(iso(nthDayIntervalMillis(withTime, [1, 'month'], 1))).toBe('2025-02-28T13:45:59.123Z');
335
+ });
@@ -1,23 +0,0 @@
1
- //#region src/utils/dates.d.ts
2
- declare function isWeekend(date: Date): boolean;
3
- declare function fromNow(date: Date): string;
4
- declare function fromNowDetailed(date: Date): {
5
- result: string;
6
- /**
7
- * May be Infinity if the result will never change.
8
- */
9
- secondsUntilChange: number;
10
- };
11
- /**
12
- * Returns a string representation of the given date in the format expected by the `datetime-local` input type.
13
- */
14
- declare function getInputDatetimeLocalString(date: Date): string;
15
- type Interval = [number, 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'];
16
- type DayInterval = [number, 'day' | 'week' | 'month' | 'year'];
17
- declare function subtractInterval(date: Date, interval: Interval): Date;
18
- declare function addInterval(date: Date, interval: Interval): Date;
19
- declare const FAR_FUTURE_DATE: Date;
20
- declare function getIntervalsElapsed(anchor: Date, to: Date, repeat: DayInterval): number;
21
- //#endregion
22
- export { fromNow as a, getIntervalsElapsed as c, addInterval as i, isWeekend as l, FAR_FUTURE_DATE as n, fromNowDetailed as o, Interval as r, getInputDatetimeLocalString as s, DayInterval as t, subtractInterval as u };
23
- //# sourceMappingURL=dates-B6ne9iOR.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema-fields-BljhsWsa.d.ts","names":[],"sources":["../src/schema-fields.ts"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"transactions-BomBBiph.d.ts","names":[],"sources":["../src/interface/crud/transactions.ts"],"mappings":";;;;cAwFa,sBAAA,gBAAsB,WAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAMxB,WAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAEC,gBAAA,GAAmB,SAAS,QAAQ,sBAAA;AAAA,cAEnC,iBAAA;AAAA,KAUD,eAAA,WAA0B,iBAAiB;AAAA,cAE1C,iBAAA,gBAAiB,YAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAkBlB,WAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAEA,WAAA,GAAc,SAAS,QAAQ,iBAAA"}