@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.
- package/LICENSE +21 -0
- package/README.md +210 -0
- package/dist/adapters/_netbytes.d.ts +31 -0
- package/dist/adapters/_netbytes.d.ts.map +1 -0
- package/dist/adapters/_netbytes.js +154 -0
- package/dist/adapters/_netbytes.js.map +1 -0
- package/dist/adapters/aws-lambda.d.ts +41 -0
- package/dist/adapters/aws-lambda.d.ts.map +1 -0
- package/dist/adapters/aws-lambda.js +65 -0
- package/dist/adapters/aws-lambda.js.map +1 -0
- package/dist/adapters/browser.d.ts +52 -0
- package/dist/adapters/browser.d.ts.map +1 -0
- package/dist/adapters/browser.js +127 -0
- package/dist/adapters/browser.js.map +1 -0
- package/dist/adapters/compute-wrap.d.ts +33 -0
- package/dist/adapters/compute-wrap.d.ts.map +1 -0
- package/dist/adapters/compute-wrap.js +188 -0
- package/dist/adapters/compute-wrap.js.map +1 -0
- package/dist/adapters/data/aws_lambda_pricing.json +61 -0
- package/dist/adapters/gpu-wrap.d.ts +31 -0
- package/dist/adapters/gpu-wrap.d.ts.map +1 -0
- package/dist/adapters/gpu-wrap.js +147 -0
- package/dist/adapters/gpu-wrap.js.map +1 -0
- package/dist/adapters/http.d.ts +58 -0
- package/dist/adapters/http.d.ts.map +1 -0
- package/dist/adapters/http.js +769 -0
- package/dist/adapters/http.js.map +1 -0
- package/dist/adapters/index.d.ts +11 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +12 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/network-accountant.d.ts +63 -0
- package/dist/adapters/network-accountant.d.ts.map +1 -0
- package/dist/adapters/network-accountant.js +153 -0
- package/dist/adapters/network-accountant.js.map +1 -0
- package/dist/cli/index.d.ts +13 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +225 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/scanner.d.ts +39 -0
- package/dist/cli/scanner.d.ts.map +1 -0
- package/dist/cli/scanner.js +480 -0
- package/dist/cli/scanner.js.map +1 -0
- package/dist/clients.d.ts +54 -0
- package/dist/clients.d.ts.map +1 -0
- package/dist/clients.js +240 -0
- package/dist/clients.js.map +1 -0
- package/dist/cloud-detect.d.ts +96 -0
- package/dist/cloud-detect.d.ts.map +1 -0
- package/dist/cloud-detect.js +545 -0
- package/dist/cloud-detect.js.map +1 -0
- package/dist/core/auto-task.d.ts +20 -0
- package/dist/core/auto-task.d.ts.map +1 -0
- package/dist/core/auto-task.js +34 -0
- package/dist/core/auto-task.js.map +1 -0
- package/dist/core/cgroup-reader.d.ts +45 -0
- package/dist/core/cgroup-reader.d.ts.map +1 -0
- package/dist/core/cgroup-reader.js +124 -0
- package/dist/core/cgroup-reader.js.map +1 -0
- package/dist/core/cgroup-walker.d.ts +60 -0
- package/dist/core/cgroup-walker.d.ts.map +1 -0
- package/dist/core/cgroup-walker.js +166 -0
- package/dist/core/cgroup-walker.js.map +1 -0
- package/dist/core/compute-accountant.d.ts +51 -0
- package/dist/core/compute-accountant.d.ts.map +1 -0
- package/dist/core/compute-accountant.js +179 -0
- package/dist/core/compute-accountant.js.map +1 -0
- package/dist/core/compute-runtime.d.ts +42 -0
- package/dist/core/compute-runtime.d.ts.map +1 -0
- package/dist/core/compute-runtime.js +80 -0
- package/dist/core/compute-runtime.js.map +1 -0
- package/dist/core/config.d.ts +44 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +66 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/context.d.ts +76 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +91 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/fargate-metadata.d.ts +27 -0
- package/dist/core/fargate-metadata.d.ts.map +1 -0
- package/dist/core/fargate-metadata.js +102 -0
- package/dist/core/fargate-metadata.js.map +1 -0
- package/dist/core/gpu-accountant.d.ts +104 -0
- package/dist/core/gpu-accountant.d.ts.map +1 -0
- package/dist/core/gpu-accountant.js +383 -0
- package/dist/core/gpu-accountant.js.map +1 -0
- package/dist/core/gpu-runtime.d.ts +58 -0
- package/dist/core/gpu-runtime.d.ts.map +1 -0
- package/dist/core/gpu-runtime.js +131 -0
- package/dist/core/gpu-runtime.js.map +1 -0
- package/dist/core/heuristics.d.ts +74 -0
- package/dist/core/heuristics.d.ts.map +1 -0
- package/dist/core/heuristics.js +182 -0
- package/dist/core/heuristics.js.map +1 -0
- package/dist/core/models.d.ts +149 -0
- package/dist/core/models.d.ts.map +1 -0
- package/dist/core/models.js +226 -0
- package/dist/core/models.js.map +1 -0
- package/dist/core/nvml-reader.d.ts +114 -0
- package/dist/core/nvml-reader.d.ts.map +1 -0
- package/dist/core/nvml-reader.js +323 -0
- package/dist/core/nvml-reader.js.map +1 -0
- package/dist/core/session.d.ts +48 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +123 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/tracker.d.ts +364 -0
- package/dist/core/tracker.d.ts.map +1 -0
- package/dist/core/tracker.js +1073 -0
- package/dist/core/tracker.js.map +1 -0
- package/dist/data/compute_prices.json +180 -0
- package/dist/data/egress_prices.json +418 -0
- package/dist/data/gpu_prices.json +412 -0
- package/dist/data/service_prices.json +2595 -0
- package/dist/dev-console.d.ts +12 -0
- package/dist/dev-console.d.ts.map +1 -0
- package/dist/dev-console.js +60 -0
- package/dist/dev-console.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/instruments/anthropic.d.ts +26 -0
- package/dist/instruments/anthropic.d.ts.map +1 -0
- package/dist/instruments/anthropic.js +242 -0
- package/dist/instruments/anthropic.js.map +1 -0
- package/dist/instruments/bedrock.d.ts +29 -0
- package/dist/instruments/bedrock.d.ts.map +1 -0
- package/dist/instruments/bedrock.js +215 -0
- package/dist/instruments/bedrock.js.map +1 -0
- package/dist/instruments/cohere.d.ts +29 -0
- package/dist/instruments/cohere.d.ts.map +1 -0
- package/dist/instruments/cohere.js +237 -0
- package/dist/instruments/cohere.js.map +1 -0
- package/dist/instruments/gemini.d.ts +30 -0
- package/dist/instruments/gemini.d.ts.map +1 -0
- package/dist/instruments/gemini.js +247 -0
- package/dist/instruments/gemini.js.map +1 -0
- package/dist/instruments/index.d.ts +35 -0
- package/dist/instruments/index.d.ts.map +1 -0
- package/dist/instruments/index.js +54 -0
- package/dist/instruments/index.js.map +1 -0
- package/dist/instruments/mcp.d.ts +24 -0
- package/dist/instruments/mcp.d.ts.map +1 -0
- package/dist/instruments/mcp.js +459 -0
- package/dist/instruments/mcp.js.map +1 -0
- package/dist/instruments/openai.d.ts +26 -0
- package/dist/instruments/openai.d.ts.map +1 -0
- package/dist/instruments/openai.js +221 -0
- package/dist/instruments/openai.js.map +1 -0
- package/dist/instruments/vercel-ai.d.ts +28 -0
- package/dist/instruments/vercel-ai.d.ts.map +1 -0
- package/dist/instruments/vercel-ai.js +192 -0
- package/dist/instruments/vercel-ai.js.map +1 -0
- package/dist/integrations/langchain.d.ts +65 -0
- package/dist/integrations/langchain.d.ts.map +1 -0
- package/dist/integrations/langchain.js +165 -0
- package/dist/integrations/langchain.js.map +1 -0
- package/dist/middleware/express.d.ts +55 -0
- package/dist/middleware/express.d.ts.map +1 -0
- package/dist/middleware/express.js +101 -0
- package/dist/middleware/express.js.map +1 -0
- package/dist/middleware/index.d.ts +6 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +5 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/pricing/compute-pricing.d.ts +57 -0
- package/dist/pricing/compute-pricing.d.ts.map +1 -0
- package/dist/pricing/compute-pricing.js +627 -0
- package/dist/pricing/compute-pricing.js.map +1 -0
- package/dist/pricing/cost_map.json +37665 -0
- package/dist/pricing/egress-pricing.d.ts +55 -0
- package/dist/pricing/egress-pricing.d.ts.map +1 -0
- package/dist/pricing/egress-pricing.js +226 -0
- package/dist/pricing/egress-pricing.js.map +1 -0
- package/dist/pricing/engine.d.ts +24 -0
- package/dist/pricing/engine.d.ts.map +1 -0
- package/dist/pricing/engine.js +148 -0
- package/dist/pricing/engine.js.map +1 -0
- package/dist/pricing/gpu-pricing.d.ts +63 -0
- package/dist/pricing/gpu-pricing.d.ts.map +1 -0
- package/dist/pricing/gpu-pricing.js +484 -0
- package/dist/pricing/gpu-pricing.js.map +1 -0
- package/dist/pricing/rates.d.ts +17 -0
- package/dist/pricing/rates.d.ts.map +1 -0
- package/dist/pricing/rates.js +102 -0
- package/dist/pricing/rates.js.map +1 -0
- package/dist/pricing/service-catalog.d.ts +87 -0
- package/dist/pricing/service-catalog.d.ts.map +1 -0
- package/dist/pricing/service-catalog.js +406 -0
- package/dist/pricing/service-catalog.js.map +1 -0
- package/dist/schema/dexcost-event.v1.json +111 -0
- package/dist/schema/dexcost-task.v1.json +160 -0
- package/dist/schema/validate.d.ts +15 -0
- package/dist/schema/validate.d.ts.map +1 -0
- package/dist/schema/validate.js +87 -0
- package/dist/schema/validate.js.map +1 -0
- package/dist/security/redaction.d.ts +55 -0
- package/dist/security/redaction.d.ts.map +1 -0
- package/dist/security/redaction.js +144 -0
- package/dist/security/redaction.js.map +1 -0
- package/dist/transport/buffer.d.ts +117 -0
- package/dist/transport/buffer.d.ts.map +1 -0
- package/dist/transport/buffer.js +759 -0
- package/dist/transport/buffer.js.map +1 -0
- package/dist/transport/pusher.d.ts +89 -0
- package/dist/transport/pusher.d.ts.map +1 -0
- package/dist/transport/pusher.js +323 -0
- package/dist/transport/pusher.js.map +1 -0
- 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"}
|