marginfuse 0.2.0 → 0.2.2

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/CHANGELOG.md CHANGED
@@ -4,6 +4,34 @@ All notable changes to this project are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project
5
5
  follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.2.2]
8
+
9
+ ### Fixed
10
+
11
+ - The user-agent reported `marginfuse-node/0.1.0` on every request, two
12
+ releases after 0.1.0. The version was a literal that nothing compared to
13
+ `package.json`, so support questions about which version sent a request got
14
+ a wrong answer. It is now derived from a single constant and a test asserts
15
+ the two agree.
16
+
17
+ ### Changed
18
+
19
+ - Public documentation comments no longer cite internal specification section
20
+ numbers. They shipped in `dist/index.d.ts`, so hovering `decide()` in an
21
+ editor showed a reference to a document nobody outside can read. The
22
+ comments now say what the methods do.
23
+
24
+ ## [0.2.1]
25
+
26
+ No code changes. This is the first release published by the release workflow
27
+ rather than from a laptop, so it is the first to carry a
28
+ [provenance attestation](https://docs.npmjs.com/generating-provenance-statements):
29
+ the build that produced this tarball is publicly verifiable, and it was
30
+ published through OIDC with no npm token existing anywhere in this repository.
31
+
32
+ 0.2.0 had to be published locally, because trusted publishing is configured on
33
+ a package settings page that does not exist until the package does.
34
+
7
35
  ## [0.2.0]
8
36
 
9
37
  First release from this repository. Earlier versions were published from a
package/dist/index.cjs CHANGED
@@ -20,11 +20,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ CONTRACT_VERSION: () => CONTRACT_VERSION,
23
24
  MarginFuse: () => MarginFuse,
24
25
  fromOpenRouter: () => fromOpenRouter
25
26
  });
26
27
  module.exports = __toCommonJS(index_exports);
27
28
 
29
+ // src/version.ts
30
+ var VERSION = "0.2.2";
31
+
28
32
  // src/client.ts
29
33
  var DEFAULT_BASE_URL = "https://api.marginfuse.com";
30
34
  var DEFAULT_TIMEOUT_MS = 1500;
@@ -46,8 +50,9 @@ var MarginFuse = class {
46
50
  this.fetchImpl = options.fetch ?? fetch;
47
51
  }
48
52
  /**
49
- * Pre-request policy check (protection-ready integrations, §13.2).
50
- * Always resolves. On any failure resolves {action:"allow", degraded:true}.
53
+ * Asks whether the next provider call should run.
54
+ * Always resolves. On any failure resolves {action:"allow", degraded:true},
55
+ * because MarginFuse being unreachable must never become your outage.
51
56
  */
52
57
  async decide(params) {
53
58
  const failOpen = (reason) => ({
@@ -79,8 +84,9 @@ var MarginFuse = class {
79
84
  }
80
85
  }
81
86
  /**
82
- * Report actual usage after the provider call (monitor-only §13.1 and
83
- * post-request reconciliation §25.3). Fire-and-forget with retries.
87
+ * Reports what a provider call actually consumed, after it happened.
88
+ * Returns immediately and retries in the background. Call flush() before
89
+ * the process exits, or the last events go with it.
84
90
  */
85
91
  track(params) {
86
92
  const event = {
@@ -113,7 +119,7 @@ var MarginFuse = class {
113
119
  this.track(params);
114
120
  await this.flush();
115
121
  }
116
- /** Tell MarginFuse what your app actually did with a decision (§25.2). */
122
+ /** Tells MarginFuse what your application did with a decision. */
117
123
  acknowledge(decisionId, acknowledgment) {
118
124
  this.background(async () => {
119
125
  try {
@@ -200,7 +206,7 @@ var MarginFuse = class {
200
206
  headers: {
201
207
  authorization: `Bearer ${this.apiKey}`,
202
208
  "content-type": "application/json",
203
- "user-agent": "marginfuse-node/0.1.0"
209
+ "user-agent": `marginfuse-node/${VERSION}`
204
210
  },
205
211
  body: JSON.stringify(body),
206
212
  signal: AbortSignal.timeout(timeoutMs)
@@ -257,8 +263,12 @@ function fromOpenRouter(usage) {
257
263
  const hasCost = typeof cost === "number" && Number.isFinite(cost) && cost >= 0;
258
264
  return { usage: out, ...hasCost ? { costUsd: creditsToUsd(cost) } : {} };
259
265
  }
266
+
267
+ // src/index.ts
268
+ var CONTRACT_VERSION = 1;
260
269
  // Annotate the CommonJS export names for ESM import in node:
261
270
  0 && (module.exports = {
271
+ CONTRACT_VERSION,
262
272
  MarginFuse,
263
273
  fromOpenRouter
264
274
  });
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Wire types for the MarginFuse SDK. Deliberately: there is NO field for
3
3
  * prompt text, responses, or documents - the SDK cannot leak what it cannot
4
- * carry (spec §5.6, §33).
4
+ * carry.
5
5
  */
6
6
  interface Usage {
7
7
  inputTokens?: number;
@@ -69,7 +69,7 @@ interface MarginFuseOptions {
69
69
  /**
70
70
  * MarginFuse Node SDK.
71
71
  *
72
- * Reliability contract (spec §5.5, §29.3): this SDK NEVER throws into
72
+ * Reliability contract: this SDK NEVER throws into
73
73
  * application code and NEVER blocks a request on MarginFuse availability.
74
74
  * decide() fails open to "allow" on any timeout or error; track()/report()
75
75
  * retry in the background and surface problems only via options.onError.
@@ -84,18 +84,20 @@ declare class MarginFuse {
84
84
  private readonly pending;
85
85
  constructor(options: MarginFuseOptions);
86
86
  /**
87
- * Pre-request policy check (protection-ready integrations, §13.2).
88
- * Always resolves. On any failure resolves {action:"allow", degraded:true}.
87
+ * Asks whether the next provider call should run.
88
+ * Always resolves. On any failure resolves {action:"allow", degraded:true},
89
+ * because MarginFuse being unreachable must never become your outage.
89
90
  */
90
91
  decide(params: DecideParams): Promise<Decision>;
91
92
  /**
92
- * Report actual usage after the provider call (monitor-only §13.1 and
93
- * post-request reconciliation §25.3). Fire-and-forget with retries.
93
+ * Reports what a provider call actually consumed, after it happened.
94
+ * Returns immediately and retries in the background. Call flush() before
95
+ * the process exits, or the last events go with it.
94
96
  */
95
97
  track(params: TrackParams): void;
96
98
  /** Awaitable variant of track for jobs/scripts that must not exit early. */
97
99
  trackAndWait(params: TrackParams): Promise<void>;
98
- /** Tell MarginFuse what your app actually did with a decision (§25.2). */
100
+ /** Tells MarginFuse what your application did with a decision. */
99
101
  acknowledge(decisionId: string, acknowledgment: Acknowledgment): void;
100
102
  /**
101
103
  * Full protection loop in one wrapper: decide → run your provider call with
@@ -188,4 +190,17 @@ declare function fromOpenRouter(usage: OpenRouterUsage | null | undefined): Pick
188
190
  costUsd?: string;
189
191
  };
190
192
 
191
- export { type Acknowledgment, type DecideParams, type Decision, type DecisionAction, MarginFuse, type MarginFuseOptions, type OpenRouterUsage, type Outcome, type TrackParams, type Usage, fromOpenRouter };
193
+ /**
194
+ * The version of the shared SDK contract this build was verified against.
195
+ *
196
+ * Package versions differ per language, because each tracks its own breaking
197
+ * changes: a rename in Python must not tell Node users something broke. What
198
+ * makes the SDKs interchangeable is this, not the package version. Two SDKs
199
+ * reporting the same contract version have passed the same scenarios and the
200
+ * same vectors.
201
+ *
202
+ * See github.com/marginfuse/sdk-contract.
203
+ */
204
+ declare const CONTRACT_VERSION = 1;
205
+
206
+ export { type Acknowledgment, CONTRACT_VERSION, type DecideParams, type Decision, type DecisionAction, MarginFuse, type MarginFuseOptions, type OpenRouterUsage, type Outcome, type TrackParams, type Usage, fromOpenRouter };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Wire types for the MarginFuse SDK. Deliberately: there is NO field for
3
3
  * prompt text, responses, or documents - the SDK cannot leak what it cannot
4
- * carry (spec §5.6, §33).
4
+ * carry.
5
5
  */
6
6
  interface Usage {
7
7
  inputTokens?: number;
@@ -69,7 +69,7 @@ interface MarginFuseOptions {
69
69
  /**
70
70
  * MarginFuse Node SDK.
71
71
  *
72
- * Reliability contract (spec §5.5, §29.3): this SDK NEVER throws into
72
+ * Reliability contract: this SDK NEVER throws into
73
73
  * application code and NEVER blocks a request on MarginFuse availability.
74
74
  * decide() fails open to "allow" on any timeout or error; track()/report()
75
75
  * retry in the background and surface problems only via options.onError.
@@ -84,18 +84,20 @@ declare class MarginFuse {
84
84
  private readonly pending;
85
85
  constructor(options: MarginFuseOptions);
86
86
  /**
87
- * Pre-request policy check (protection-ready integrations, §13.2).
88
- * Always resolves. On any failure resolves {action:"allow", degraded:true}.
87
+ * Asks whether the next provider call should run.
88
+ * Always resolves. On any failure resolves {action:"allow", degraded:true},
89
+ * because MarginFuse being unreachable must never become your outage.
89
90
  */
90
91
  decide(params: DecideParams): Promise<Decision>;
91
92
  /**
92
- * Report actual usage after the provider call (monitor-only §13.1 and
93
- * post-request reconciliation §25.3). Fire-and-forget with retries.
93
+ * Reports what a provider call actually consumed, after it happened.
94
+ * Returns immediately and retries in the background. Call flush() before
95
+ * the process exits, or the last events go with it.
94
96
  */
95
97
  track(params: TrackParams): void;
96
98
  /** Awaitable variant of track for jobs/scripts that must not exit early. */
97
99
  trackAndWait(params: TrackParams): Promise<void>;
98
- /** Tell MarginFuse what your app actually did with a decision (§25.2). */
100
+ /** Tells MarginFuse what your application did with a decision. */
99
101
  acknowledge(decisionId: string, acknowledgment: Acknowledgment): void;
100
102
  /**
101
103
  * Full protection loop in one wrapper: decide → run your provider call with
@@ -188,4 +190,17 @@ declare function fromOpenRouter(usage: OpenRouterUsage | null | undefined): Pick
188
190
  costUsd?: string;
189
191
  };
190
192
 
191
- export { type Acknowledgment, type DecideParams, type Decision, type DecisionAction, MarginFuse, type MarginFuseOptions, type OpenRouterUsage, type Outcome, type TrackParams, type Usage, fromOpenRouter };
193
+ /**
194
+ * The version of the shared SDK contract this build was verified against.
195
+ *
196
+ * Package versions differ per language, because each tracks its own breaking
197
+ * changes: a rename in Python must not tell Node users something broke. What
198
+ * makes the SDKs interchangeable is this, not the package version. Two SDKs
199
+ * reporting the same contract version have passed the same scenarios and the
200
+ * same vectors.
201
+ *
202
+ * See github.com/marginfuse/sdk-contract.
203
+ */
204
+ declare const CONTRACT_VERSION = 1;
205
+
206
+ export { type Acknowledgment, CONTRACT_VERSION, type DecideParams, type Decision, type DecisionAction, MarginFuse, type MarginFuseOptions, type OpenRouterUsage, type Outcome, type TrackParams, type Usage, fromOpenRouter };
package/dist/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ // src/version.ts
2
+ var VERSION = "0.2.2";
3
+
1
4
  // src/client.ts
2
5
  var DEFAULT_BASE_URL = "https://api.marginfuse.com";
3
6
  var DEFAULT_TIMEOUT_MS = 1500;
@@ -19,8 +22,9 @@ var MarginFuse = class {
19
22
  this.fetchImpl = options.fetch ?? fetch;
20
23
  }
21
24
  /**
22
- * Pre-request policy check (protection-ready integrations, §13.2).
23
- * Always resolves. On any failure resolves {action:"allow", degraded:true}.
25
+ * Asks whether the next provider call should run.
26
+ * Always resolves. On any failure resolves {action:"allow", degraded:true},
27
+ * because MarginFuse being unreachable must never become your outage.
24
28
  */
25
29
  async decide(params) {
26
30
  const failOpen = (reason) => ({
@@ -52,8 +56,9 @@ var MarginFuse = class {
52
56
  }
53
57
  }
54
58
  /**
55
- * Report actual usage after the provider call (monitor-only §13.1 and
56
- * post-request reconciliation §25.3). Fire-and-forget with retries.
59
+ * Reports what a provider call actually consumed, after it happened.
60
+ * Returns immediately and retries in the background. Call flush() before
61
+ * the process exits, or the last events go with it.
57
62
  */
58
63
  track(params) {
59
64
  const event = {
@@ -86,7 +91,7 @@ var MarginFuse = class {
86
91
  this.track(params);
87
92
  await this.flush();
88
93
  }
89
- /** Tell MarginFuse what your app actually did with a decision (§25.2). */
94
+ /** Tells MarginFuse what your application did with a decision. */
90
95
  acknowledge(decisionId, acknowledgment) {
91
96
  this.background(async () => {
92
97
  try {
@@ -173,7 +178,7 @@ var MarginFuse = class {
173
178
  headers: {
174
179
  authorization: `Bearer ${this.apiKey}`,
175
180
  "content-type": "application/json",
176
- "user-agent": "marginfuse-node/0.1.0"
181
+ "user-agent": `marginfuse-node/${VERSION}`
177
182
  },
178
183
  body: JSON.stringify(body),
179
184
  signal: AbortSignal.timeout(timeoutMs)
@@ -230,7 +235,11 @@ function fromOpenRouter(usage) {
230
235
  const hasCost = typeof cost === "number" && Number.isFinite(cost) && cost >= 0;
231
236
  return { usage: out, ...hasCost ? { costUsd: creditsToUsd(cost) } : {} };
232
237
  }
238
+
239
+ // src/index.ts
240
+ var CONTRACT_VERSION = 1;
233
241
  export {
242
+ CONTRACT_VERSION,
234
243
  MarginFuse,
235
244
  fromOpenRouter
236
245
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "marginfuse",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "MarginFuse server-side SDK. AI profitability guardrails: connect revenue to per-request AI cost and stop loss-making requests before they run. Sends usage metadata only, never prompts or responses.",
5
5
  "license": "MIT",
6
6
  "author": "Pemira Labs",