New:Socket for Asana Is Now Available.Learn more
Get Started

once-kernel

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

once-kernel - npm Package Compare versions

Comparing version
0.5.0
to
0.6.0
+117
dist/confirm.d.ts
/**
* World confirmation — asking the provider whether the effect actually exists.
*
* Everything else in this library reasons about our own records. That is the
* cheap half of the problem. The expensive half is the question an operator
* asks at 3am: *the call timed out — did it land?* Our database cannot answer
* that. It only knows what we did, not what arrived.
*
* A confirmer asks the system of record. Three outcomes, and the difference
* between them is the whole point:
*
* - `confirmed` — the provider has it. Replay; never re-run.
* - `absent` — the provider does not have it, asked properly. Safe to run.
* - `unknown` — we could not find out (network down, no permission, the
* provider has no way to look it up). **This is not
* `absent`.** Treating "I don't know" as "it didn't happen"
* is precisely how a retry becomes a double charge, and it
* is the most common mistake in code that tries to do this.
*
* Everything here is built to make that third case impossible to lose by
* accident: it is a distinct value, it carries a reason, and nothing collapses
* it into a boolean.
*/
/** What the world says about one effect. */
export type WorldState = "confirmed" | "absent" | "unknown";
export interface Confirmation {
state: WorldState;
/** Provider's own id for the effect, when it has one. */
ref?: string;
/** Provider-specific status string, verbatim — never interpreted here. */
providerStatus?: string;
/** Why we could not tell. Present only when state is "unknown". */
reason?: string;
}
/**
* A provider-specific confirmer.
*
* `lookup` receives whatever handle the caller stored at execution time (a
* message id, a payment intent id, an idempotency key) and reports what the
* provider says about it.
*/
export interface Confirmer {
/** Provider name, for receipts and the atlas. */
readonly provider: string;
lookup(ref: string): Promise<Confirmation>;
}
export interface HttpConfirmerOptions {
provider: string;
/** Build the lookup URL for a given ref. */
url: (ref: string) => string;
headers?: Record<string, string>;
/** Milliseconds before we give up and answer "unknown". */
timeoutMs?: number;
fetchImpl?: typeof fetch;
/**
* Decide what a 200 body means. Return `undefined` to accept the default:
* a 200 means confirmed. Providers that return 200 with a "deleted" or
* "failed" status need this hook.
*/
interpret?: (body: unknown) => Confirmation | undefined;
}
/**
* The general shape: GET the resource, and map the response honestly.
*
* 404 is the only status treated as `absent`, and only because it is the one
* status that means "this identifier is not known here". A 401, 403, 429 or
* 500 tells us about our access or their health, nothing about the effect —
* those are `unknown`, loudly.
*/
export declare function httpConfirmer(opts: HttpConfirmerOptions): Confirmer;
/**
* Resend — the first adapter, because it is the path we run in production and
* the one that burned us: our own mailer once reported 16 emails as sent when
* none had verifiably left, because it trusted its own status field.
*
* `GET /emails/{id}` is a read, permitted on a sending-scoped key (unlike
* /domains, which 403s — a different permission scope, learned the hard way).
*
* MEASURED BEHAVIOUR: see docs/PROVIDER-ATLAS.md. Anything not measured is
* marked as claimed-not-measured there rather than asserted here.
*/
export declare function resendConfirmer(apiKey: string, fetchImpl?: typeof fetch): Confirmer;
/**
* Stripe — payment intents, looked up by id.
*
* Stripe additionally supports idempotency keys on creation, which is a
* different mechanism from confirmation: the key prevents a duplicate, the
* lookup tells you whether one exists. We use both, and never assume the first
* makes the second unnecessary.
*/
export declare function stripeConfirmer(apiKey: string, fetchImpl?: typeof fetch): Confirmer;
export interface ResolveOptions {
confirmer: Confirmer;
/** Provider handle recorded when the effect was executed. */
ref: string;
}
export type Resolution = {
action: "replay";
confirmation: Confirmation;
} | {
action: "execute";
confirmation: Confirmation;
} | {
action: "escalate";
confirmation: Confirmation;
why: string;
};
/**
* The timeout resolver: given a handle, say what to do next.
*
* This is deliberately three-valued. Most implementations of this idea return
* a boolean and quietly turn `unknown` into `execute`, which is the double-fire
* bug wearing a helpful face. Here, not knowing escalates to a human — the only
* honest answer when the effect is irreversible.
*/
export declare function resolveAfterTimeout(opts: ResolveOptions): Promise<Resolution>;
//# sourceMappingURL=confirm.d.ts.map
{"version":3,"file":"confirm.d.ts","sourceRoot":"","sources":["../src/confirm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,4CAA4C;AAC5C,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,CAAC;IAClB,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,SAAS;IACxB,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,YAAY,GAAG,SAAS,CAAC;CACzD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,SAAS,CA+CnE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,GAAG,SAAS,CAiBnF;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,GAAG,SAAS,CAcnF;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,SAAS,CAAC;IACrB,6DAA6D;IAC7D,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,YAAY,EAAE,YAAY,CAAA;CAAE,GAChD;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,YAAY,EAAE,YAAY,CAAA;CAAE,GACjD;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,YAAY,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpE;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAYnF"}
/**
* World confirmation — asking the provider whether the effect actually exists.
*
* Everything else in this library reasons about our own records. That is the
* cheap half of the problem. The expensive half is the question an operator
* asks at 3am: *the call timed out — did it land?* Our database cannot answer
* that. It only knows what we did, not what arrived.
*
* A confirmer asks the system of record. Three outcomes, and the difference
* between them is the whole point:
*
* - `confirmed` — the provider has it. Replay; never re-run.
* - `absent` — the provider does not have it, asked properly. Safe to run.
* - `unknown` — we could not find out (network down, no permission, the
* provider has no way to look it up). **This is not
* `absent`.** Treating "I don't know" as "it didn't happen"
* is precisely how a retry becomes a double charge, and it
* is the most common mistake in code that tries to do this.
*
* Everything here is built to make that third case impossible to lose by
* accident: it is a distinct value, it carries a reason, and nothing collapses
* it into a boolean.
*/
/**
* The general shape: GET the resource, and map the response honestly.
*
* 404 is the only status treated as `absent`, and only because it is the one
* status that means "this identifier is not known here". A 401, 403, 429 or
* 500 tells us about our access or their health, nothing about the effect —
* those are `unknown`, loudly.
*/
export function httpConfirmer(opts) {
const doFetch = opts.fetchImpl ?? fetch;
const timeoutMs = opts.timeoutMs ?? 10_000;
return {
provider: opts.provider,
async lookup(ref) {
if (!ref) {
return { state: "unknown", reason: "no reference to look up — nothing was recorded at execution time" };
}
let res;
try {
res = await doFetch(opts.url(ref), {
method: "GET",
headers: opts.headers ?? {},
signal: AbortSignal.timeout(timeoutMs),
});
}
catch (err) {
// A failed lookup is not a zero. We genuinely do not know.
const msg = err instanceof Error ? err.message : String(err);
return { state: "unknown", reason: `lookup failed: ${msg}` };
}
if (res.status === 404) {
return { state: "absent", providerStatus: "404" };
}
if (!res.ok) {
return {
state: "unknown",
providerStatus: String(res.status),
reason: `provider answered ${res.status} — this says nothing about whether the effect exists`,
};
}
let body;
try {
body = await res.json();
}
catch {
// A 200 we cannot parse still tells us the id resolved.
return { state: "confirmed", ref, providerStatus: "200" };
}
const custom = opts.interpret?.(body);
if (custom)
return custom;
return { state: "confirmed", ref, providerStatus: "200" };
},
};
}
/**
* Resend — the first adapter, because it is the path we run in production and
* the one that burned us: our own mailer once reported 16 emails as sent when
* none had verifiably left, because it trusted its own status field.
*
* `GET /emails/{id}` is a read, permitted on a sending-scoped key (unlike
* /domains, which 403s — a different permission scope, learned the hard way).
*
* MEASURED BEHAVIOUR: see docs/PROVIDER-ATLAS.md. Anything not measured is
* marked as claimed-not-measured there rather than asserted here.
*/
export function resendConfirmer(apiKey, fetchImpl) {
return httpConfirmer({
provider: "resend",
url: (id) => `https://api.resend.com/emails/${encodeURIComponent(id)}`,
headers: { Authorization: `Bearer ${apiKey}` },
fetchImpl,
interpret: (body) => {
const b = body;
const status = (b?.last_event ?? b?.status);
if (!status)
return undefined;
// Resend reports a lifecycle, not a boolean. "bounced" still means the
// send HAPPENED — the effect exists, it simply failed downstream. That
// distinction matters: re-sending a bounced message is a decision for a
// human, not something a retry should do silently.
return { state: "confirmed", ref: String(b?.id ?? ""), providerStatus: status };
},
});
}
/**
* Stripe — payment intents, looked up by id.
*
* Stripe additionally supports idempotency keys on creation, which is a
* different mechanism from confirmation: the key prevents a duplicate, the
* lookup tells you whether one exists. We use both, and never assume the first
* makes the second unnecessary.
*/
export function stripeConfirmer(apiKey, fetchImpl) {
return httpConfirmer({
provider: "stripe",
url: (id) => `https://api.stripe.com/v1/payment_intents/${encodeURIComponent(id)}`,
headers: { Authorization: `Bearer ${apiKey}` },
fetchImpl,
interpret: (body) => {
const b = body;
const status = b?.status;
if (!status)
return undefined;
// canceled means the intent EXISTS and was cancelled — still confirmed.
return { state: "confirmed", ref: String(b?.id ?? ""), providerStatus: status };
},
});
}
/**
* The timeout resolver: given a handle, say what to do next.
*
* This is deliberately three-valued. Most implementations of this idea return
* a boolean and quietly turn `unknown` into `execute`, which is the double-fire
* bug wearing a helpful face. Here, not knowing escalates to a human — the only
* honest answer when the effect is irreversible.
*/
export async function resolveAfterTimeout(opts) {
const c = await opts.confirmer.lookup(opts.ref);
if (c.state === "confirmed")
return { action: "replay", confirmation: c };
if (c.state === "absent")
return { action: "execute", confirmation: c };
// The reason explains why we cannot tell; the consequence explains what is
// at stake. A human deciding at 3am needs both, so both are always present.
const cause = c.reason ?? "the provider could not tell us whether this effect exists";
return {
action: "escalate",
confirmation: c,
why: `${cause} — re-running may duplicate it, so this needs a human decision`,
};
}
//# sourceMappingURL=confirm.js.map
{"version":3,"file":"confirm.js","sourceRoot":"","sources":["../src/confirm.ts"],"names":[],"mappings":"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"}
+6
-2
{
"name": "once-kernel",
"version": "0.5.0",
"version": "0.6.0",
"description": "Idempotency kernel for side-effecting operations. 1,000 racing callers, exactly one execution — proven, not asserted.",

@@ -58,2 +58,6 @@ "keywords": [

"default": "./dist/ledger.js"
},
"./confirm": {
"types": "./dist/confirm.d.ts",
"default": "./dist/confirm.js"
}

@@ -72,3 +76,3 @@ },

"clean": "rm -rf dist",
"test": "node --experimental-strip-types --no-warnings --test test/canonical.test.ts test/kernel.test.ts test/store-conformance.test.ts test/guard.test.ts test/capabilities.test.ts test/readme.test.ts test/once-audit-cli.test.ts test/door.test.ts test/ledger.test.ts",
"test": "node --experimental-strip-types --no-warnings --test test/canonical.test.ts test/kernel.test.ts test/store-conformance.test.ts test/guard.test.ts test/capabilities.test.ts test/readme.test.ts test/once-audit-cli.test.ts test/door.test.ts test/ledger.test.ts test/confirm.test.ts",
"test:storm": "node --experimental-strip-types --no-warnings --test test/storm.test.ts",

@@ -75,0 +79,0 @@ "test:all": "npm run test && npm run test:storm",

@@ -166,2 +166,34 @@ # once-kernel

### Ask the world, and keep the third answer
Your database knows what you did, not what arrived. After a timeout, only the
provider can say whether the effect exists.
```ts
import { resendConfirmer, resolveAfterTimeout } from "once-kernel/confirm";
const r = await resolveAfterTimeout({
confirmer: resendConfirmer(process.env.RESEND_API_KEY!),
ref: storedMessageId,
});
switch (r.action) {
case "replay": return stored; // provider has it — never re-run
case "execute": return send(); // provider asked, genuinely absent
case "escalate": alertHuman(r.why); // we could not find out
}
```
Three answers, not two. `unknown` — a 500, a timeout, a revoked key — is **not**
`absent`. Most implementations return a boolean and quietly turn "I could not
find out" into "it didn't happen", which is the double-charge bug wearing a
helpful face. Here it escalates instead, because re-running an irreversible
effect on a guess is the thing we are trying to prevent.
Only 404 means absent. A `bounced` email is **confirmed** — the send happened,
delivery failed afterwards; re-sending it is a human's decision, not a retry's.
Measured provider behaviour, with claims and measurements kept strictly apart:
[docs/PROVIDER-ATLAS.md](docs/PROVIDER-ATLAS.md).
### Notarised receipts — evidence an outsider can check

@@ -168,0 +200,0 @@