@dexcost/sdk 0.2.0

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 (211) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +210 -0
  3. package/dist/adapters/_netbytes.d.ts +31 -0
  4. package/dist/adapters/_netbytes.d.ts.map +1 -0
  5. package/dist/adapters/_netbytes.js +154 -0
  6. package/dist/adapters/_netbytes.js.map +1 -0
  7. package/dist/adapters/aws-lambda.d.ts +41 -0
  8. package/dist/adapters/aws-lambda.d.ts.map +1 -0
  9. package/dist/adapters/aws-lambda.js +65 -0
  10. package/dist/adapters/aws-lambda.js.map +1 -0
  11. package/dist/adapters/browser.d.ts +52 -0
  12. package/dist/adapters/browser.d.ts.map +1 -0
  13. package/dist/adapters/browser.js +127 -0
  14. package/dist/adapters/browser.js.map +1 -0
  15. package/dist/adapters/compute-wrap.d.ts +33 -0
  16. package/dist/adapters/compute-wrap.d.ts.map +1 -0
  17. package/dist/adapters/compute-wrap.js +188 -0
  18. package/dist/adapters/compute-wrap.js.map +1 -0
  19. package/dist/adapters/data/aws_lambda_pricing.json +61 -0
  20. package/dist/adapters/gpu-wrap.d.ts +31 -0
  21. package/dist/adapters/gpu-wrap.d.ts.map +1 -0
  22. package/dist/adapters/gpu-wrap.js +147 -0
  23. package/dist/adapters/gpu-wrap.js.map +1 -0
  24. package/dist/adapters/http.d.ts +58 -0
  25. package/dist/adapters/http.d.ts.map +1 -0
  26. package/dist/adapters/http.js +769 -0
  27. package/dist/adapters/http.js.map +1 -0
  28. package/dist/adapters/index.d.ts +11 -0
  29. package/dist/adapters/index.d.ts.map +1 -0
  30. package/dist/adapters/index.js +12 -0
  31. package/dist/adapters/index.js.map +1 -0
  32. package/dist/adapters/network-accountant.d.ts +63 -0
  33. package/dist/adapters/network-accountant.d.ts.map +1 -0
  34. package/dist/adapters/network-accountant.js +153 -0
  35. package/dist/adapters/network-accountant.js.map +1 -0
  36. package/dist/cli/index.d.ts +13 -0
  37. package/dist/cli/index.d.ts.map +1 -0
  38. package/dist/cli/index.js +225 -0
  39. package/dist/cli/index.js.map +1 -0
  40. package/dist/cli/scanner.d.ts +39 -0
  41. package/dist/cli/scanner.d.ts.map +1 -0
  42. package/dist/cli/scanner.js +480 -0
  43. package/dist/cli/scanner.js.map +1 -0
  44. package/dist/clients.d.ts +54 -0
  45. package/dist/clients.d.ts.map +1 -0
  46. package/dist/clients.js +240 -0
  47. package/dist/clients.js.map +1 -0
  48. package/dist/cloud-detect.d.ts +96 -0
  49. package/dist/cloud-detect.d.ts.map +1 -0
  50. package/dist/cloud-detect.js +545 -0
  51. package/dist/cloud-detect.js.map +1 -0
  52. package/dist/core/auto-task.d.ts +20 -0
  53. package/dist/core/auto-task.d.ts.map +1 -0
  54. package/dist/core/auto-task.js +34 -0
  55. package/dist/core/auto-task.js.map +1 -0
  56. package/dist/core/cgroup-reader.d.ts +45 -0
  57. package/dist/core/cgroup-reader.d.ts.map +1 -0
  58. package/dist/core/cgroup-reader.js +124 -0
  59. package/dist/core/cgroup-reader.js.map +1 -0
  60. package/dist/core/cgroup-walker.d.ts +60 -0
  61. package/dist/core/cgroup-walker.d.ts.map +1 -0
  62. package/dist/core/cgroup-walker.js +166 -0
  63. package/dist/core/cgroup-walker.js.map +1 -0
  64. package/dist/core/compute-accountant.d.ts +51 -0
  65. package/dist/core/compute-accountant.d.ts.map +1 -0
  66. package/dist/core/compute-accountant.js +179 -0
  67. package/dist/core/compute-accountant.js.map +1 -0
  68. package/dist/core/compute-runtime.d.ts +42 -0
  69. package/dist/core/compute-runtime.d.ts.map +1 -0
  70. package/dist/core/compute-runtime.js +80 -0
  71. package/dist/core/compute-runtime.js.map +1 -0
  72. package/dist/core/config.d.ts +44 -0
  73. package/dist/core/config.d.ts.map +1 -0
  74. package/dist/core/config.js +66 -0
  75. package/dist/core/config.js.map +1 -0
  76. package/dist/core/context.d.ts +76 -0
  77. package/dist/core/context.d.ts.map +1 -0
  78. package/dist/core/context.js +91 -0
  79. package/dist/core/context.js.map +1 -0
  80. package/dist/core/fargate-metadata.d.ts +27 -0
  81. package/dist/core/fargate-metadata.d.ts.map +1 -0
  82. package/dist/core/fargate-metadata.js +102 -0
  83. package/dist/core/fargate-metadata.js.map +1 -0
  84. package/dist/core/gpu-accountant.d.ts +104 -0
  85. package/dist/core/gpu-accountant.d.ts.map +1 -0
  86. package/dist/core/gpu-accountant.js +383 -0
  87. package/dist/core/gpu-accountant.js.map +1 -0
  88. package/dist/core/gpu-runtime.d.ts +58 -0
  89. package/dist/core/gpu-runtime.d.ts.map +1 -0
  90. package/dist/core/gpu-runtime.js +131 -0
  91. package/dist/core/gpu-runtime.js.map +1 -0
  92. package/dist/core/heuristics.d.ts +74 -0
  93. package/dist/core/heuristics.d.ts.map +1 -0
  94. package/dist/core/heuristics.js +182 -0
  95. package/dist/core/heuristics.js.map +1 -0
  96. package/dist/core/models.d.ts +149 -0
  97. package/dist/core/models.d.ts.map +1 -0
  98. package/dist/core/models.js +226 -0
  99. package/dist/core/models.js.map +1 -0
  100. package/dist/core/nvml-reader.d.ts +114 -0
  101. package/dist/core/nvml-reader.d.ts.map +1 -0
  102. package/dist/core/nvml-reader.js +323 -0
  103. package/dist/core/nvml-reader.js.map +1 -0
  104. package/dist/core/session.d.ts +48 -0
  105. package/dist/core/session.d.ts.map +1 -0
  106. package/dist/core/session.js +123 -0
  107. package/dist/core/session.js.map +1 -0
  108. package/dist/core/tracker.d.ts +364 -0
  109. package/dist/core/tracker.d.ts.map +1 -0
  110. package/dist/core/tracker.js +1073 -0
  111. package/dist/core/tracker.js.map +1 -0
  112. package/dist/data/compute_prices.json +180 -0
  113. package/dist/data/egress_prices.json +418 -0
  114. package/dist/data/gpu_prices.json +412 -0
  115. package/dist/data/service_prices.json +2595 -0
  116. package/dist/dev-console.d.ts +12 -0
  117. package/dist/dev-console.d.ts.map +1 -0
  118. package/dist/dev-console.js +60 -0
  119. package/dist/dev-console.js.map +1 -0
  120. package/dist/index.d.ts +52 -0
  121. package/dist/index.d.ts.map +1 -0
  122. package/dist/index.js +61 -0
  123. package/dist/index.js.map +1 -0
  124. package/dist/instruments/anthropic.d.ts +26 -0
  125. package/dist/instruments/anthropic.d.ts.map +1 -0
  126. package/dist/instruments/anthropic.js +242 -0
  127. package/dist/instruments/anthropic.js.map +1 -0
  128. package/dist/instruments/bedrock.d.ts +29 -0
  129. package/dist/instruments/bedrock.d.ts.map +1 -0
  130. package/dist/instruments/bedrock.js +215 -0
  131. package/dist/instruments/bedrock.js.map +1 -0
  132. package/dist/instruments/cohere.d.ts +29 -0
  133. package/dist/instruments/cohere.d.ts.map +1 -0
  134. package/dist/instruments/cohere.js +237 -0
  135. package/dist/instruments/cohere.js.map +1 -0
  136. package/dist/instruments/gemini.d.ts +30 -0
  137. package/dist/instruments/gemini.d.ts.map +1 -0
  138. package/dist/instruments/gemini.js +247 -0
  139. package/dist/instruments/gemini.js.map +1 -0
  140. package/dist/instruments/index.d.ts +35 -0
  141. package/dist/instruments/index.d.ts.map +1 -0
  142. package/dist/instruments/index.js +54 -0
  143. package/dist/instruments/index.js.map +1 -0
  144. package/dist/instruments/mcp.d.ts +24 -0
  145. package/dist/instruments/mcp.d.ts.map +1 -0
  146. package/dist/instruments/mcp.js +459 -0
  147. package/dist/instruments/mcp.js.map +1 -0
  148. package/dist/instruments/openai.d.ts +26 -0
  149. package/dist/instruments/openai.d.ts.map +1 -0
  150. package/dist/instruments/openai.js +221 -0
  151. package/dist/instruments/openai.js.map +1 -0
  152. package/dist/instruments/vercel-ai.d.ts +28 -0
  153. package/dist/instruments/vercel-ai.d.ts.map +1 -0
  154. package/dist/instruments/vercel-ai.js +192 -0
  155. package/dist/instruments/vercel-ai.js.map +1 -0
  156. package/dist/integrations/langchain.d.ts +65 -0
  157. package/dist/integrations/langchain.d.ts.map +1 -0
  158. package/dist/integrations/langchain.js +165 -0
  159. package/dist/integrations/langchain.js.map +1 -0
  160. package/dist/middleware/express.d.ts +55 -0
  161. package/dist/middleware/express.d.ts.map +1 -0
  162. package/dist/middleware/express.js +101 -0
  163. package/dist/middleware/express.js.map +1 -0
  164. package/dist/middleware/index.d.ts +6 -0
  165. package/dist/middleware/index.d.ts.map +1 -0
  166. package/dist/middleware/index.js +5 -0
  167. package/dist/middleware/index.js.map +1 -0
  168. package/dist/pricing/compute-pricing.d.ts +57 -0
  169. package/dist/pricing/compute-pricing.d.ts.map +1 -0
  170. package/dist/pricing/compute-pricing.js +627 -0
  171. package/dist/pricing/compute-pricing.js.map +1 -0
  172. package/dist/pricing/cost_map.json +37665 -0
  173. package/dist/pricing/egress-pricing.d.ts +55 -0
  174. package/dist/pricing/egress-pricing.d.ts.map +1 -0
  175. package/dist/pricing/egress-pricing.js +226 -0
  176. package/dist/pricing/egress-pricing.js.map +1 -0
  177. package/dist/pricing/engine.d.ts +24 -0
  178. package/dist/pricing/engine.d.ts.map +1 -0
  179. package/dist/pricing/engine.js +148 -0
  180. package/dist/pricing/engine.js.map +1 -0
  181. package/dist/pricing/gpu-pricing.d.ts +63 -0
  182. package/dist/pricing/gpu-pricing.d.ts.map +1 -0
  183. package/dist/pricing/gpu-pricing.js +484 -0
  184. package/dist/pricing/gpu-pricing.js.map +1 -0
  185. package/dist/pricing/rates.d.ts +17 -0
  186. package/dist/pricing/rates.d.ts.map +1 -0
  187. package/dist/pricing/rates.js +102 -0
  188. package/dist/pricing/rates.js.map +1 -0
  189. package/dist/pricing/service-catalog.d.ts +87 -0
  190. package/dist/pricing/service-catalog.d.ts.map +1 -0
  191. package/dist/pricing/service-catalog.js +406 -0
  192. package/dist/pricing/service-catalog.js.map +1 -0
  193. package/dist/schema/dexcost-event.v1.json +111 -0
  194. package/dist/schema/dexcost-task.v1.json +160 -0
  195. package/dist/schema/validate.d.ts +15 -0
  196. package/dist/schema/validate.d.ts.map +1 -0
  197. package/dist/schema/validate.js +87 -0
  198. package/dist/schema/validate.js.map +1 -0
  199. package/dist/security/redaction.d.ts +55 -0
  200. package/dist/security/redaction.d.ts.map +1 -0
  201. package/dist/security/redaction.js +144 -0
  202. package/dist/security/redaction.js.map +1 -0
  203. package/dist/transport/buffer.d.ts +117 -0
  204. package/dist/transport/buffer.d.ts.map +1 -0
  205. package/dist/transport/buffer.js +759 -0
  206. package/dist/transport/buffer.js.map +1 -0
  207. package/dist/transport/pusher.d.ts +89 -0
  208. package/dist/transport/pusher.d.ts.map +1 -0
  209. package/dist/transport/pusher.js +323 -0
  210. package/dist/transport/pusher.js.map +1 -0
  211. package/package.json +93 -0
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Egress pricing engine — resolves a per-GB egress rate from
3
+ * `(provider, region)` using the bundled `data/egress_prices.json` catalog.
4
+ *
5
+ * Mirrors the Python `dexcost.egress_pricing` module in shape and contract:
6
+ * bundled JSON + a resolver that returns `(ratePerGb, pricingSource,
7
+ * costConfidence)` via the spec §7.1 5-tier degradation ladder.
8
+ *
9
+ * Fail-silent contract: every failure mode degrades through the ladder;
10
+ * the engine always returns a usable `EgressRate`.
11
+ *
12
+ * Numeric precision note: the TypeScript SDK uses `number` for cost fields,
13
+ * so rates are stored as strings (preserving catalog precision) and parsed
14
+ * only at the boundary. Catalog string values match the Python Decimal
15
+ * equivalents exactly — see `tests/egress-pricing.test.ts`.
16
+ */
17
+ /** Test-only: clear warn-once tracking. */
18
+ export declare function _resetEgressWarningStateForTests(): void;
19
+ export interface EgressRate {
20
+ /** Rate string from the catalog (e.g. "0.09", "0.1093"); caller parses. */
21
+ ratePerGb: string;
22
+ /** Audit-trail identifier (e.g. "egress_catalog:aws:us-east-1"). */
23
+ pricingSource: string;
24
+ /** Confidence band: "exact" | "computed" | "estimated". */
25
+ costConfidence: "exact" | "computed" | "estimated";
26
+ }
27
+ export declare class EgressPricingEngine {
28
+ private _catalog;
29
+ private _catalogVersion;
30
+ /**
31
+ * @param catalogJson Optional override — already-parsed JSON object. When
32
+ * omitted, the bundled `data/egress_prices.json` is loaded.
33
+ */
34
+ constructor(catalogJson?: object);
35
+ /** Load and parse a catalog from disk by file path. */
36
+ static fromPath(catalogPath: string): EgressPricingEngine;
37
+ private _loadBundled;
38
+ get catalogVersion(): string;
39
+ /** Rate for a call classified as internal traffic — always free. */
40
+ rateForInternal(): EgressRate;
41
+ /**
42
+ * Resolve an egress rate via the §7.1 degradation ladder.
43
+ *
44
+ * - Tier 1: `(provider, region)` exact match → region rate, `computed`.
45
+ * - Tier 2: provider known, region absent/unknown → provider default,
46
+ * `estimated`.
47
+ * - Tier 3: provider not detected / not in catalog → `_meta` default,
48
+ * `estimated`.
49
+ * - Tier 4: catalog unreadable or `_meta` default absent → hardcoded
50
+ * `"0.09"`, `estimated`.
51
+ */
52
+ resolveRate(provider: string | null, region: string | null): EgressRate;
53
+ private _isMeta;
54
+ }
55
+ //# sourceMappingURL=egress-pricing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"egress-pricing.d.ts","sourceRoot":"","sources":["../../src/pricing/egress-pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AA0BH,2CAA2C;AAC3C,wBAAgB,gCAAgC,IAAI,IAAI,CAEvD;AAMD,MAAM,WAAW,UAAU;IACzB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,aAAa,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,cAAc,EAAE,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC;CACpD;AAmDD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,eAAe,CAAqB;IAE5C;;;OAGG;gBACS,WAAW,CAAC,EAAE,MAAM;IAqBhC,uDAAuD;IACvD,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB;IAoCzD,OAAO,CAAC,YAAY;IAuBpB,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,oEAAoE;IACpE,eAAe,IAAI,UAAU;IAQ7B;;;;;;;;;;OAUG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,UAAU;IA4DvE,OAAO,CAAC,OAAO;CAOhB"}
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Egress pricing engine — resolves a per-GB egress rate from
3
+ * `(provider, region)` using the bundled `data/egress_prices.json` catalog.
4
+ *
5
+ * Mirrors the Python `dexcost.egress_pricing` module in shape and contract:
6
+ * bundled JSON + a resolver that returns `(ratePerGb, pricingSource,
7
+ * costConfidence)` via the spec §7.1 5-tier degradation ladder.
8
+ *
9
+ * Fail-silent contract: every failure mode degrades through the ladder;
10
+ * the engine always returns a usable `EgressRate`.
11
+ *
12
+ * Numeric precision note: the TypeScript SDK uses `number` for cost fields,
13
+ * so rates are stored as strings (preserving catalog precision) and parsed
14
+ * only at the boundary. Catalog string values match the Python Decimal
15
+ * equivalents exactly — see `tests/egress-pricing.test.ts`.
16
+ */
17
+ import { readFileSync } from "node:fs";
18
+ import { createRequire } from "node:module";
19
+ // ---------------------------------------------------------------------------
20
+ // Constants
21
+ // ---------------------------------------------------------------------------
22
+ /** Tier-4 ultimate fallback — used only when the catalog cannot be read at
23
+ * all AND `_meta.default_rate_usd_per_gb` cannot be resolved. */
24
+ const HARDCODED_DEFAULT = "0.09";
25
+ // ---------------------------------------------------------------------------
26
+ // Warn-once tracking (module-level state)
27
+ // ---------------------------------------------------------------------------
28
+ const _warnedModes = new Set();
29
+ function _warnOnce(mode, message) {
30
+ if (_warnedModes.has(mode))
31
+ return;
32
+ _warnedModes.add(mode);
33
+ // eslint-disable-next-line no-console
34
+ console.warn(`[dexcost.egress-pricing] ${message}`);
35
+ }
36
+ /** Test-only: clear warn-once tracking. */
37
+ export function _resetEgressWarningStateForTests() {
38
+ _warnedModes.clear();
39
+ }
40
+ // ---------------------------------------------------------------------------
41
+ // Helpers
42
+ // ---------------------------------------------------------------------------
43
+ /**
44
+ * Validate that a string/number is a usable decimal rate. Returns the
45
+ * normalised string form, or null if it cannot be parsed.
46
+ *
47
+ * We preserve the original string when possible to avoid float drift in
48
+ * stored data. For numbers we stringify via `String(v)` (catalog should
49
+ * always use strings, but this provides a safety net).
50
+ */
51
+ function _normaliseRate(value) {
52
+ if (value === null || value === undefined)
53
+ return null;
54
+ if (typeof value === "number") {
55
+ if (!Number.isFinite(value))
56
+ return null;
57
+ return String(value);
58
+ }
59
+ if (typeof value !== "string")
60
+ return null;
61
+ const trimmed = value.trim();
62
+ if (trimmed === "")
63
+ return null;
64
+ const parsed = Number.parseFloat(trimmed);
65
+ if (Number.isNaN(parsed) || !Number.isFinite(parsed))
66
+ return null;
67
+ // Preserve the original (string) representation — no float drift.
68
+ return trimmed;
69
+ }
70
+ // ---------------------------------------------------------------------------
71
+ // EgressPricingEngine
72
+ // ---------------------------------------------------------------------------
73
+ export class EgressPricingEngine {
74
+ _catalog = {};
75
+ _catalogVersion = "unknown";
76
+ /**
77
+ * @param catalogJson Optional override — already-parsed JSON object. When
78
+ * omitted, the bundled `data/egress_prices.json` is loaded.
79
+ */
80
+ constructor(catalogJson) {
81
+ if (catalogJson !== undefined) {
82
+ // Accept already-parsed JSON object (used by tests).
83
+ try {
84
+ this._catalog = catalogJson;
85
+ const meta = this._catalog._meta;
86
+ if (meta && typeof meta === "object") {
87
+ this._catalogVersion = String(meta.version ?? "unknown");
88
+ }
89
+ }
90
+ catch {
91
+ _warnOnce("catalog_malformed", "egress catalog malformed; falling back to hardcoded default");
92
+ this._catalog = {};
93
+ }
94
+ return;
95
+ }
96
+ this._loadBundled();
97
+ }
98
+ /** Load and parse a catalog from disk by file path. */
99
+ static fromPath(catalogPath) {
100
+ let raw;
101
+ try {
102
+ raw = readFileSync(catalogPath, "utf-8");
103
+ }
104
+ catch (err) {
105
+ const code = err.code;
106
+ if (code === "ENOENT") {
107
+ _warnOnce("catalog_missing", `egress catalog file not found (${catalogPath}); ` +
108
+ "falling back to hardcoded default");
109
+ }
110
+ else {
111
+ _warnOnce("catalog_unreadable", `egress catalog unreadable (${String(err)}); ` +
112
+ "falling back to hardcoded default");
113
+ }
114
+ return new EgressPricingEngine({});
115
+ }
116
+ let parsed;
117
+ try {
118
+ parsed = JSON.parse(raw);
119
+ }
120
+ catch (err) {
121
+ _warnOnce("catalog_malformed", `egress catalog malformed JSON (${String(err)}); ` +
122
+ "falling back to hardcoded default");
123
+ return new EgressPricingEngine({});
124
+ }
125
+ return new EgressPricingEngine(parsed);
126
+ }
127
+ _loadBundled() {
128
+ try {
129
+ const req = createRequire(import.meta.url);
130
+ const raw = req("../data/egress_prices.json");
131
+ this._catalog = raw;
132
+ const meta = raw._meta;
133
+ if (meta && typeof meta === "object") {
134
+ this._catalogVersion = String(meta.version ?? "unknown");
135
+ }
136
+ }
137
+ catch (err) {
138
+ _warnOnce("catalog_missing", `bundled egress catalog could not be loaded (${String(err)}); ` +
139
+ "falling back to hardcoded default");
140
+ this._catalog = {};
141
+ }
142
+ }
143
+ // -------------------------------------------------------------------------
144
+ // Public API
145
+ // -------------------------------------------------------------------------
146
+ get catalogVersion() {
147
+ return this._catalogVersion;
148
+ }
149
+ /** Rate for a call classified as internal traffic — always free. */
150
+ rateForInternal() {
151
+ return {
152
+ ratePerGb: "0",
153
+ pricingSource: "egress_catalog:internal",
154
+ costConfidence: "exact",
155
+ };
156
+ }
157
+ /**
158
+ * Resolve an egress rate via the §7.1 degradation ladder.
159
+ *
160
+ * - Tier 1: `(provider, region)` exact match → region rate, `computed`.
161
+ * - Tier 2: provider known, region absent/unknown → provider default,
162
+ * `estimated`.
163
+ * - Tier 3: provider not detected / not in catalog → `_meta` default,
164
+ * `estimated`.
165
+ * - Tier 4: catalog unreadable or `_meta` default absent → hardcoded
166
+ * `"0.09"`, `estimated`.
167
+ */
168
+ resolveRate(provider, region) {
169
+ if (provider) {
170
+ const block = this._catalog[provider];
171
+ if (block && typeof block === "object" && !this._isMeta(block)) {
172
+ const providerBlock = block;
173
+ const regions = providerBlock.regions ?? {};
174
+ if (region && Object.prototype.hasOwnProperty.call(regions, region)) {
175
+ const normalised = _normaliseRate(regions[region]);
176
+ if (normalised !== null) {
177
+ return {
178
+ ratePerGb: normalised,
179
+ pricingSource: `egress_catalog:${provider}:${region}`,
180
+ costConfidence: "computed",
181
+ };
182
+ }
183
+ _warnOnce(`region_rate_malformed:${provider}:${region}`, `egress region rate malformed for ${provider}/${region}`);
184
+ // Fall through to provider default.
185
+ }
186
+ const provDefault = _normaliseRate(providerBlock.default_usd_per_gb);
187
+ if (provDefault !== null) {
188
+ return {
189
+ ratePerGb: provDefault,
190
+ pricingSource: `egress_catalog:${provider}:default`,
191
+ costConfidence: "estimated",
192
+ };
193
+ }
194
+ }
195
+ }
196
+ const meta = this._catalog._meta;
197
+ if (meta && typeof meta === "object") {
198
+ const metaDefault = _normaliseRate(meta.default_rate_usd_per_gb);
199
+ if (metaDefault !== null) {
200
+ return {
201
+ ratePerGb: metaDefault,
202
+ pricingSource: "egress_catalog:default",
203
+ costConfidence: "estimated",
204
+ };
205
+ }
206
+ _warnOnce("meta_default_missing", "egress _meta.default_rate_usd_per_gb missing/malformed; " +
207
+ "using hardcoded default");
208
+ }
209
+ return {
210
+ ratePerGb: HARDCODED_DEFAULT,
211
+ pricingSource: "egress_catalog:default",
212
+ costConfidence: "estimated",
213
+ };
214
+ }
215
+ // -------------------------------------------------------------------------
216
+ // Private helpers
217
+ // -------------------------------------------------------------------------
218
+ _isMeta(block) {
219
+ // The `_meta` block isn't a provider block. The catalog uses a flat
220
+ // dictionary with provider names as keys and `_meta` as a sibling; we
221
+ // only call this on keys other than `_meta`, but defensively guard
222
+ // against shapes that look meta-ish.
223
+ return "default_rate_usd_per_gb" in block;
224
+ }
225
+ }
226
+ //# sourceMappingURL=egress-pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"egress-pricing.js","sourceRoot":"","sources":["../../src/pricing/egress-pricing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { PricingSource } from "../core/models.js";
2
+ export interface CostResult {
3
+ costUsd: number;
4
+ pricingSource: PricingSource;
5
+ costConfidence: "computed" | "unknown";
6
+ pricingVersion: string;
7
+ }
8
+ export declare class PricingEngine {
9
+ private _modelMap;
10
+ private _customPricing;
11
+ private _pricingVersion;
12
+ private _refreshInterval;
13
+ constructor();
14
+ get pricingVersion(): string;
15
+ getCost(model: string, inputTokens: number, outputTokens: number, cachedTokens?: number, cacheCreationTokens?: number): CostResult;
16
+ setCustomPricing(model: string, inputPer1k: number, outputPer1k: number): void;
17
+ private _apiKey;
18
+ setApiKey(key: string | undefined): void;
19
+ refreshFromServer(endpoint: string): Promise<void>;
20
+ startBackgroundRefresh(endpoint: string, intervalMs?: number): void;
21
+ stopBackgroundRefresh(): void;
22
+ private _resolveModel;
23
+ }
24
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/pricing/engine.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAQvD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,aAAa,CAAC;IAC7B,cAAc,EAAE,UAAU,GAAG,SAAS,CAAC;IACvC,cAAc,EAAE,MAAM,CAAC;CACxB;AAcD,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,cAAc,CAAyC;IAC/D,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,gBAAgB,CAA+C;;IAevE,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,OAAO,CACL,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,YAAY,GAAE,MAAU,EACxB,mBAAmB,GAAE,MAAU,GAC9B,UAAU;IAgDb,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAI9E,OAAO,CAAC,OAAO,CAAqB;IAEpC,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAIlC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwCxD,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAE,MAAmB,GAAG,IAAI;IAU/E,qBAAqB,IAAI,IAAI;IAO7B,OAAO,CAAC,aAAa;CAgBtB"}
@@ -0,0 +1,148 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFileSync } from "node:fs";
3
+ import { fileURLToPath } from "node:url";
4
+ import { dirname, join } from "node:path";
5
+ // Sprint 3 Theme E / §4.2.3 — Node 18 compat: runtime JSON load.
6
+ const _thisDir = dirname(fileURLToPath(import.meta.url));
7
+ const costMapData = JSON.parse(readFileSync(join(_thisDir, "cost_map.json"), "utf-8"));
8
+ export class PricingEngine {
9
+ _modelMap;
10
+ _customPricing = new Map();
11
+ _pricingVersion;
12
+ _refreshInterval = null;
13
+ constructor() {
14
+ try {
15
+ this._modelMap = costMapData;
16
+ this._pricingVersion = createHash("sha256")
17
+ .update(JSON.stringify(costMapData))
18
+ .digest("hex")
19
+ .slice(0, 12);
20
+ }
21
+ catch {
22
+ this._modelMap = {};
23
+ this._pricingVersion = "unknown";
24
+ }
25
+ }
26
+ get pricingVersion() {
27
+ return this._pricingVersion;
28
+ }
29
+ getCost(model, inputTokens, outputTokens, cachedTokens = 0, cacheCreationTokens = 0) {
30
+ const custom = this._customPricing.get(model);
31
+ if (custom) {
32
+ const cost = (custom.inputPer1k * inputTokens) / 1000 +
33
+ (custom.outputPer1k * outputTokens) / 1000;
34
+ return {
35
+ costUsd: cost,
36
+ costConfidence: "computed",
37
+ pricingSource: "custom",
38
+ pricingVersion: this._pricingVersion,
39
+ };
40
+ }
41
+ const info = this._resolveModel(model);
42
+ if (!info) {
43
+ return {
44
+ costUsd: 0,
45
+ costConfidence: "unknown",
46
+ pricingSource: "unknown",
47
+ pricingVersion: this._pricingVersion,
48
+ };
49
+ }
50
+ const inputRate = info.input_cost_per_token;
51
+ const outputRate = info.output_cost_per_token;
52
+ const cacheReadRate = info.cache_read_input_token_cost ?? 0;
53
+ const cacheCreationRate = info.cache_creation_input_token_cost ?? 0;
54
+ const effectiveCached = Math.min(cachedTokens, inputTokens);
55
+ const remaining = inputTokens - effectiveCached;
56
+ const effectiveCreation = Math.min(cacheCreationTokens, remaining);
57
+ const nonCachedInput = remaining - effectiveCreation;
58
+ const cost = inputRate * nonCachedInput +
59
+ cacheReadRate * effectiveCached +
60
+ cacheCreationRate * effectiveCreation +
61
+ outputRate * outputTokens;
62
+ return {
63
+ costUsd: cost,
64
+ costConfidence: "computed",
65
+ pricingSource: "litellm",
66
+ pricingVersion: this._pricingVersion,
67
+ };
68
+ }
69
+ setCustomPricing(model, inputPer1k, outputPer1k) {
70
+ this._customPricing.set(model, { inputPer1k, outputPer1k });
71
+ }
72
+ _apiKey;
73
+ setApiKey(key) {
74
+ this._apiKey = key;
75
+ }
76
+ async refreshFromServer(endpoint) {
77
+ try {
78
+ const headers = { "User-Agent": "dexcost-sdk" };
79
+ if (this._apiKey) {
80
+ headers["Authorization"] = `Bearer ${this._apiKey}`;
81
+ }
82
+ const response = await fetch(`${endpoint}/v1/api/pricing-data/latest`, {
83
+ headers,
84
+ });
85
+ if (!response.ok)
86
+ return;
87
+ const text = await response.text();
88
+ let payload;
89
+ try {
90
+ payload = JSON.parse(text);
91
+ }
92
+ catch {
93
+ return; // Malformed JSON — keep using bundled pricing
94
+ }
95
+ // Control Layer contract: pricing models are nested under
96
+ // payload.data.data, with payload.data.pricing_version alongside.
97
+ const rawData = payload.data;
98
+ if (!rawData || typeof rawData !== "object")
99
+ return;
100
+ const serverData = rawData.data;
101
+ if (!serverData || typeof serverData !== "object" || Object.keys(serverData).length === 0) {
102
+ return;
103
+ }
104
+ // Drop the schema sample if present (matches Python).
105
+ delete serverData.sample_spec;
106
+ this._modelMap = serverData;
107
+ this._pricingVersion =
108
+ typeof rawData.pricing_version === "string" && rawData.pricing_version
109
+ ? rawData.pricing_version
110
+ : createHash("sha256")
111
+ .update(JSON.stringify(serverData))
112
+ .digest("hex")
113
+ .slice(0, 12);
114
+ }
115
+ catch {
116
+ // Network error — keep using bundled pricing
117
+ }
118
+ }
119
+ startBackgroundRefresh(endpoint, intervalMs = 86_400_000) {
120
+ void this.refreshFromServer(endpoint);
121
+ const interval = setInterval(() => void this.refreshFromServer(endpoint), intervalMs);
122
+ interval.unref();
123
+ this._refreshInterval = interval;
124
+ }
125
+ stopBackgroundRefresh() {
126
+ if (this._refreshInterval !== null) {
127
+ clearInterval(this._refreshInterval);
128
+ this._refreshInterval = null;
129
+ }
130
+ }
131
+ _resolveModel(model) {
132
+ if (model in this._modelMap)
133
+ return this._modelMap[model];
134
+ if (model.includes("/")) {
135
+ const short = model.split("/").pop();
136
+ if (short in this._modelMap)
137
+ return this._modelMap[short];
138
+ }
139
+ const parts = model.split("-");
140
+ for (let i = parts.length - 1; i > 0; i--) {
141
+ const candidate = parts.slice(0, i).join("-");
142
+ if (candidate in this._modelMap)
143
+ return this._modelMap[candidate];
144
+ }
145
+ return undefined;
146
+ }
147
+ }
148
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/pricing/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * GPU pricing engine — Phase 2 v2.
3
+ *
4
+ * Dispatches on `details.billing_model` and applies the per-billing-model
5
+ * math from spec §6. Four discriminator values:
6
+ *
7
+ * - per_gpu_second_active — Modal / RunPod / Replicate
8
+ * - per_instance_hour — AWS EC2 GPU / GCP GCE bundled / Azure VM GPU
9
+ * - per_gpu_hour_reserved — Lambda Labs / CoreWeave / GCP N1+accelerator
10
+ * - per_vgpu_hour — Azure NVadsA10 v5 fractional (Decision #10)
11
+ *
12
+ * Per Decision #7: NO per-runtime memory-unit conversion table. VRAM tier
13
+ * is encoded in the SKU key (h100-80gb-sxm5 vs a100-40gb are separate
14
+ * catalog entries).
15
+ *
16
+ * Fail-silent (convention §9): every code path returns a usable GpuCost.
17
+ * Five-tier degradation ladder:
18
+ * Tier 1: per-region SKU exact
19
+ * Tier 2: per-runtime default
20
+ * Tier 3a: device-class fallback (Decision #4)
21
+ * Tier 3b: universal _meta default
22
+ * Tier 4: hardcoded constants
23
+ * Tier 5: try/except returns cost=0 + unknown
24
+ *
25
+ * Decision #1 measurement-side fallback: when details carries
26
+ * `_cgroup_scope_fallback`, it is appended to pricing_source and confidence
27
+ * drops to `estimated`.
28
+ *
29
+ * Mirrors python/src/dexcost/gpu_pricing.py.
30
+ */
31
+ import { Decimal } from "decimal.js";
32
+ import type { CloudEnv } from "../cloud-detect.js";
33
+ export declare function _resetWarningStateForTests(): void;
34
+ export interface GpuCost {
35
+ costUsd: Decimal;
36
+ pricingSource: string;
37
+ costConfidence: "computed" | "estimated" | "unknown";
38
+ }
39
+ export interface GpuPricingEngineOptions {
40
+ catalogPath?: string;
41
+ catalog?: Record<string, any>;
42
+ }
43
+ export declare class GpuPricingEngine {
44
+ private _catalog;
45
+ private _catalogVersion;
46
+ constructor(opts?: GpuPricingEngineOptions);
47
+ private _load;
48
+ get catalogVersion(): string;
49
+ /** Read-only catalog accessor — used by tests to verify rate sources. */
50
+ get catalog(): Record<string, any>;
51
+ resolveGpuCost(details: Record<string, any>, cloudEnv: CloudEnv, windowS?: Decimal): GpuCost;
52
+ private _dispatch;
53
+ private _perGpuSecond;
54
+ private _resolvePerGpuSecondRate;
55
+ private _perInstanceHour;
56
+ private _resolvePerInstanceRate;
57
+ private _perGpuHour;
58
+ private _resolvePerGpuHourRate;
59
+ private _perVgpuHour;
60
+ private _resolvePerVgpuRate;
61
+ private _deviceClassOrMetaFallback;
62
+ }
63
+ //# sourceMappingURL=gpu-pricing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gpu-pricing.d.ts","sourceRoot":"","sources":["../../src/pricing/gpu-pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAGrC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAMnD,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAsED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,UAAU,GAAG,WAAW,GAAG,SAAS,CAAC;CACtD;AAED,MAAM,WAAW,uBAAuB;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC/B;AAeD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,eAAe,CAAa;gBAExB,IAAI,CAAC,EAAE,uBAAuB;IAgB1C,OAAO,CAAC,KAAK;IAkDb,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,yEAAyE;IACzE,IAAI,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAEjC;IAMD,cAAc,CACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC5B,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO;IAkCV,OAAO,CAAC,SAAS;IA+BjB,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,wBAAwB;IAsDhC,OAAO,CAAC,gBAAgB;IAmCxB,OAAO,CAAC,uBAAuB;IAsC/B,OAAO,CAAC,WAAW;IA8BnB,OAAO,CAAC,sBAAsB;IAsD9B,OAAO,CAAC,YAAY;IAkCpB,OAAO,CAAC,mBAAmB;IA8B3B,OAAO,CAAC,0BAA0B;CAsDnC"}