@hasna/economy 0.2.33 → 0.2.34

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/dist/cli/index.js CHANGED
@@ -3924,12 +3924,45 @@ function getGeminiBillingExportPath() {
3924
3924
  function toISODate(d) {
3925
3925
  return d.toISOString().substring(0, 10);
3926
3926
  }
3927
+ function isValidDateParts(year, month, day) {
3928
+ const d = new Date(Date.UTC(year, month - 1, day));
3929
+ return d.getUTCFullYear() === year && d.getUTCMonth() === month - 1 && d.getUTCDate() === day;
3930
+ }
3931
+ function formatDateParts(year, month, day) {
3932
+ return `${String(year).padStart(4, "0")}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
3933
+ }
3927
3934
  function parseDate(value) {
3935
+ if (typeof value === "number" && Number.isInteger(value)) {
3936
+ return value >= 100001 && value <= 999912 ? parseDate(String(value)) : null;
3937
+ }
3928
3938
  if (typeof value !== "string" || !value.trim())
3929
3939
  return null;
3930
- const d = new Date(value);
3940
+ const trimmed = value.trim();
3941
+ const compactMonth = /^(\d{4})(\d{2})$/.exec(trimmed);
3942
+ if (compactMonth) {
3943
+ const year = Number(compactMonth[1]);
3944
+ const month = Number(compactMonth[2]);
3945
+ return isValidDateParts(year, month, 1) ? formatDateParts(year, month, 1) : null;
3946
+ }
3947
+ const dashedMonth = /^(\d{4})-(\d{2})$/.exec(trimmed);
3948
+ if (dashedMonth) {
3949
+ const year = Number(dashedMonth[1]);
3950
+ const month = Number(dashedMonth[2]);
3951
+ return isValidDateParts(year, month, 1) ? formatDateParts(year, month, 1) : null;
3952
+ }
3953
+ const isoDate = /^(\d{4})-(\d{2})-(\d{2})(?:$|[T\s])/.exec(trimmed);
3954
+ if (isoDate) {
3955
+ const year = Number(isoDate[1]);
3956
+ const month = Number(isoDate[2]);
3957
+ const day = Number(isoDate[3]);
3958
+ if (!isValidDateParts(year, month, day))
3959
+ return null;
3960
+ if (trimmed.length === 10)
3961
+ return formatDateParts(year, month, day);
3962
+ }
3963
+ const d = new Date(trimmed);
3931
3964
  if (Number.isNaN(d.getTime()))
3932
- return value.substring(0, 10);
3965
+ return null;
3933
3966
  return toISODate(d);
3934
3967
  }
3935
3968
  function parseCsv(content) {
@@ -1 +1 @@
1
- {"version":3,"file":"billing.d.ts","sourceRoot":"","sources":["../../src/ingest/billing.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAA;AA0G7D,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,QAAQ,EACZ,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/D,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAuD7C;AAeD,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,QAAQ,EACZ,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/D,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAqD7C;AAED,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,QAAQ,EACZ,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/D,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAwC/D"}
1
+ {"version":3,"file":"billing.d.ts","sourceRoot":"","sources":["../../src/ingest/billing.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAA;AA+I7D,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,QAAQ,EACZ,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/D,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAuD7C;AAeD,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,QAAQ,EACZ,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/D,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAqD7C;AAED,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,QAAQ,EACZ,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/D,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAwC/D"}
@@ -1793,12 +1793,45 @@ function getGeminiBillingExportPath() {
1793
1793
  function toISODate(d) {
1794
1794
  return d.toISOString().substring(0, 10);
1795
1795
  }
1796
+ function isValidDateParts(year, month, day) {
1797
+ const d = new Date(Date.UTC(year, month - 1, day));
1798
+ return d.getUTCFullYear() === year && d.getUTCMonth() === month - 1 && d.getUTCDate() === day;
1799
+ }
1800
+ function formatDateParts(year, month, day) {
1801
+ return `${String(year).padStart(4, "0")}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
1802
+ }
1796
1803
  function parseDate(value) {
1804
+ if (typeof value === "number" && Number.isInteger(value)) {
1805
+ return value >= 100001 && value <= 999912 ? parseDate(String(value)) : null;
1806
+ }
1797
1807
  if (typeof value !== "string" || !value.trim())
1798
1808
  return null;
1799
- const d = new Date(value);
1809
+ const trimmed = value.trim();
1810
+ const compactMonth = /^(\d{4})(\d{2})$/.exec(trimmed);
1811
+ if (compactMonth) {
1812
+ const year = Number(compactMonth[1]);
1813
+ const month = Number(compactMonth[2]);
1814
+ return isValidDateParts(year, month, 1) ? formatDateParts(year, month, 1) : null;
1815
+ }
1816
+ const dashedMonth = /^(\d{4})-(\d{2})$/.exec(trimmed);
1817
+ if (dashedMonth) {
1818
+ const year = Number(dashedMonth[1]);
1819
+ const month = Number(dashedMonth[2]);
1820
+ return isValidDateParts(year, month, 1) ? formatDateParts(year, month, 1) : null;
1821
+ }
1822
+ const isoDate = /^(\d{4})-(\d{2})-(\d{2})(?:$|[T\s])/.exec(trimmed);
1823
+ if (isoDate) {
1824
+ const year = Number(isoDate[1]);
1825
+ const month = Number(isoDate[2]);
1826
+ const day = Number(isoDate[3]);
1827
+ if (!isValidDateParts(year, month, day))
1828
+ return null;
1829
+ if (trimmed.length === 10)
1830
+ return formatDateParts(year, month, day);
1831
+ }
1832
+ const d = new Date(trimmed);
1800
1833
  if (Number.isNaN(d.getTime()))
1801
- return value.substring(0, 10);
1834
+ return null;
1802
1835
  return toISODate(d);
1803
1836
  }
1804
1837
  function parseCsv(content) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/economy",
3
- "version": "0.2.33",
3
+ "version": "0.2.34",
4
4
  "description": "AI coding cost tracker — CLI + MCP server + REST API + web dashboard for Claude Code, Codex, Gemini, OpenCode, Cursor, Pi, and Hermes",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",