@candledottv/agent-sdk 0.1.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.
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Shared base64/ArrayBuffer/Uint8Array conversion helpers for this SDK's crypto modules
3
+ * (wallet-import.ts, authorization-signature.ts, secret-store.ts). Internal only -- not
4
+ * re-exported from index.ts -- since these are plumbing for WebCrypto/HPKE call sites, not part
5
+ * of the SDK's public surface.
6
+ *
7
+ * These used to be copied near-identically in all three call sites. Consolidated here with
8
+ * byte-identical behavior to the originals: same `Buffer.from`/`.slice` calls, just given one
9
+ * home. Each call site keeps using whichever pair of functions matches the value shape it already
10
+ * works with (ArrayBuffer for WebCrypto/HPKE APIs, Uint8Array for everything else).
11
+ */
12
+ /** A `Uint8Array` sliced down to exactly its own bytes, safe to hand to WebCrypto/HPKE as an `ArrayBuffer`. */
13
+ export declare function toArrayBuffer(view: Uint8Array): ArrayBuffer;
14
+ export declare function arrayBufferToBase64(data: ArrayBuffer): string;
15
+ /** Decodes a base64 string to an `ArrayBuffer` containing exactly its bytes (no pooled-buffer slack). */
16
+ export declare function base64ToArrayBuffer(base64: string): ArrayBuffer;
17
+ export declare function toBase64(bytes: Uint8Array): string;
18
+ export declare function fromBase64(base64: string): Uint8Array;
19
+ //# sourceMappingURL=encoding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../../src/internal/encoding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,+GAA+G;AAC/G,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,CAE3D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAE7D;AAED,yGAAyG;AACzG,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAG/D;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAElD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAErD"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * keychain-secret-store: the OS-keychain `SecretStore` secret-store.ts's module doc deferred to
3
+ * "Phase 4", closing the loop with the Candle CLI's wallet import.
4
+ *
5
+ * `candle wallets import` stores each imported wallet's signer private key in the OS keychain:
6
+ * service `tv.candle.cli`, account `wallet_signer_<linkedWalletId>`, value = the PEM's base64
7
+ * body on a single line (the CLI's `pemToStoredSigner` form; a raw PEM contains newlines, which
8
+ * the CLI's macOS write path refuses by design). This store reads that exact contract, so an SDK
9
+ * agent on the same machine picks up CLI-imported wallets with zero manual key handling:
10
+ *
11
+ * const store = KeychainSecretStore.detect()
12
+ * const candle = new CandleClient({ apiKey, privyAppId, secretStore: store ?? undefined })
13
+ * await candle.trade({ ..., from: { linkedWalletId, privyWalletId } })
14
+ *
15
+ * `get()` re-armors the stored single-line value into standard PEM, which is what the signing
16
+ * path (`buildPrivyAuthorizationSignature`) consumes. `set()` accepts a PEM and stores the
17
+ * single-line form, so writes from either side stay format-compatible. Node-only (spawns
18
+ * `security` on macOS, `secret-tool` on Linux), like `EncryptedFileSecretStore`; browser and
19
+ * ephemeral runs keep using `InMemorySecretStore`.
20
+ *
21
+ * Secrets travel exclusively via the child's STDIN or its stdout, never argv, mirroring the
22
+ * CLI's own stores: macOS `security` only takes secrets as a `-w` argv flag in its normal form,
23
+ * so writes go through `security -i` (command-on-stdin mode) instead. The stored value is
24
+ * base64 by construction, so embedding it in the quoted `-w "<value>"` token cannot break out
25
+ * of the quoting; `assertStorable` makes that invariant checked rather than assumed.
26
+ */
27
+ import type { SecretStore } from "./secret-store";
28
+ export interface ExecResult {
29
+ status: number;
30
+ stdout: string;
31
+ }
32
+ export type ExecFn = (binary: string, args: string[], stdin?: string) => Promise<ExecResult>;
33
+ export declare class KeychainSecretStore implements SecretStore {
34
+ private readonly backend;
35
+ private readonly exec;
36
+ constructor(opts?: {
37
+ backend?: "security" | "secret-tool";
38
+ exec?: ExecFn;
39
+ });
40
+ /**
41
+ * The store for this machine, or `null` when no OS keychain tool is on `PATH` (fall back to
42
+ * `EncryptedFileSecretStore` or `InMemorySecretStore` then). Presence-only: a resolvable
43
+ * binary whose daemon is down surfaces later as `get() === null`, which every caller already
44
+ * handles as "no signer stored".
45
+ */
46
+ static detect(): KeychainSecretStore | null;
47
+ get(walletRef: string): Promise<string | null>;
48
+ set(walletRef: string, privateKeyPem: string): Promise<void>;
49
+ delete(walletRef: string): Promise<void>;
50
+ }
51
+ //# sourceMappingURL=keychain-secret-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keychain-secret-store.d.ts","sourceRoot":"","sources":["../src/keychain-secret-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AA4BjD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAA;AAiC5F,qBAAa,mBAAoB,YAAW,WAAW;IACrD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAQ;gBAEjB,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,UAAU,GAAG,aAAa,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAO;IAK9E;;;;;OAKG;IACH,MAAM,CAAC,MAAM,IAAI,mBAAmB,GAAG,IAAI;IAMrC,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAa9C,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB5D,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAS/C"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * secret-store: pluggable storage for an agent's P-256 signer private key (Agent Pilot Phase 3).
3
+ *
4
+ * Phase 3 lets a headless agent sign for its own linked wallets by holding the P-256 signer key
5
+ * (`generateSignerKeypair`'s `privateKeyPem`, wallet-import.ts) client-side, not on Candle's
6
+ * servers. Candle never sees this key; the SDK is where it has to live instead, so this module
7
+ * defines where and how. A later task (one-shot trade / selfLaunch) loads the key from a
8
+ * `SecretStore` by `walletRef` to compute the signature at call time.
9
+ *
10
+ * Two implementations ship here:
11
+ * - `InMemorySecretStore`: a plain `Map`, universal (browser or Node), for tests and ephemeral
12
+ * agent runs that re-import or re-generate the key each process start.
13
+ * - `EncryptedFileSecretStore`: AES-GCM-at-rest via WebCrypto, keyed from a passphrase through
14
+ * PBKDF2, Node-only (it touches the filesystem via `node:fs/promises`).
15
+ *
16
+ * An OS-keychain-backed store (macOS Keychain / libsecret / Windows Credential Manager) is
17
+ * deliberately NOT included here -- it is Node/CLI-specific and belongs to a later phase (Phase
18
+ * 4). Implement `SecretStore` for it then.
19
+ */
20
+ /**
21
+ * Storage for an agent's signer private-key PEM, keyed by `walletRef` (the caller's stable
22
+ * handle for a linked wallet: its `linkedWalletId` or its address). Implementations decide the
23
+ * medium (memory, an encrypted file, later an OS keychain) but must agree on this shape.
24
+ *
25
+ * Deliberately excluded from this module: an OS-keychain implementation. That store is
26
+ * Node/CLI-specific (macOS Keychain, libsecret, Windows Credential Manager) and is planned for
27
+ * Phase 4, not Phase 3 -- implement this interface against it there rather than here.
28
+ */
29
+ export interface SecretStore {
30
+ /** Returns the stored PEM for `walletRef`, or `null` if nothing is stored under that ref. */
31
+ get(walletRef: string): Promise<string | null>;
32
+ /** Stores `privateKeyPem` under `walletRef`, replacing any previous value for that ref. */
33
+ set(walletRef: string, privateKeyPem: string): Promise<void>;
34
+ /** Removes any stored value for `walletRef`. A no-op if nothing was stored under it. */
35
+ delete(walletRef: string): Promise<void>;
36
+ }
37
+ /**
38
+ * A plain in-memory `SecretStore`. Works identically in a browser or Node (no filesystem, no
39
+ * platform APIs), which makes it the right default for tests and for ephemeral agent runs that
40
+ * are fine re-deriving or re-importing the key on every process start. Nothing here survives
41
+ * process exit.
42
+ */
43
+ export declare class InMemorySecretStore implements SecretStore {
44
+ private readonly entries;
45
+ get(walletRef: string): Promise<string | null>;
46
+ set(walletRef: string, privateKeyPem: string): Promise<void>;
47
+ delete(walletRef: string): Promise<void>;
48
+ }
49
+ /**
50
+ * A `SecretStore` backed by a single encrypted JSON file, keyed from a passphrase. Node-only (it
51
+ * reads and writes the filesystem via `node:fs/promises`, imported lazily inside each method so
52
+ * that importing `InMemorySecretStore` from this module never drags a `node:fs` dependency into
53
+ * a browser bundle).
54
+ *
55
+ * Crypto construction (WebCrypto, matching wallet-import.ts's use of `crypto.subtle`):
56
+ * - Key derivation: PBKDF2-HMAC-SHA256, {@link PBKDF2_ITERATIONS} iterations at the time of
57
+ * writing, a random {@link SALT_LENGTH_BYTES}-byte salt generated fresh for every `set` call.
58
+ * Both the salt and the iteration count actually used are stored alongside that entry's
59
+ * ciphertext (not read back from the module constant), so a correct passphrase can always
60
+ * re-derive the key even after {@link PBKDF2_ITERATIONS} is raised for new entries later.
61
+ * - Encryption: AES-GCM-256, a random {@link IV_LENGTH_BYTES}-byte IV generated fresh for every
62
+ * `set` call (never reused across entries or across overwrites of the same entry).
63
+ * - At rest: one JSON object per file, one salt/iv/iterations/ciphertext record per `walletRef`.
64
+ * The ciphertext is AES-GCM's own output (ciphertext + auth tag), so a wrong passphrase
65
+ * derives the wrong key and `crypto.subtle.decrypt` throws on the auth-tag check -- it can
66
+ * never silently return garbage plaintext instead of the real PEM.
67
+ *
68
+ * Not safe for concurrent writers against the same file: `set` and `delete` both do a
69
+ * read-modify-write of the whole file, so two concurrent calls (same process or different
70
+ * processes) against the same `path` can race and lose one write.
71
+ */
72
+ export declare class EncryptedFileSecretStore implements SecretStore {
73
+ private readonly path;
74
+ private readonly passphrase;
75
+ constructor(path: string, passphrase: string);
76
+ get(walletRef: string): Promise<string | null>;
77
+ set(walletRef: string, privateKeyPem: string): Promise<void>;
78
+ delete(walletRef: string): Promise<void>;
79
+ private readFile;
80
+ private writeFile;
81
+ }
82
+ //# sourceMappingURL=secret-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-store.d.ts","sourceRoot":"","sources":["../src/secret-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,6FAA6F;IAC7F,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IAC9C,2FAA2F;IAC3F,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5D,wFAAwF;IACxF,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACzC;AAED;;;;;GAKG;AACH,qBAAa,mBAAoB,YAAW,WAAW;IACrD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IAE9C,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAI9C,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5D,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/C;AA6CD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,wBAAyB,YAAW,WAAW;IAExD,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,UAAU;gBADV,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM;IAG/B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAoB9C,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB5D,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAOhC,QAAQ;YAWR,SAAS;CAMxB"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Client-side HPKE for Candle's ciphertext-only wallet import (PR3, Task 8).
3
+ *
4
+ * `POST /api/v1/agent/wallets/import/init` proxies Privy's HPKE receiver public key so an agent
5
+ * can encrypt a wallet's private key locally; `POST /api/v1/agent/wallets/import/submit` accepts
6
+ * only the resulting ciphertext. Candle -- and the network in between -- never sees plaintext.
7
+ * `CandleClient.importWallet` (client.ts) drives both requests and is the only place in this SDK
8
+ * that ever holds the plaintext key; this module supplies the pure crypto it calls.
9
+ *
10
+ * HPKE parameters match Privy's import contract exactly (RFC 9180, mode Base):
11
+ * - KEM: DHKEM(P-256, HKDF-SHA256) -- `DhkemP256HkdfSha256`
12
+ * - KDF: HKDF-SHA256 -- `HkdfSha256`
13
+ * - AEAD: ChaCha20-Poly1305 -- `Chacha20Poly1305`
14
+ * All three wire values -- the receiver's `encryptionPublicKey` (input) and the `ciphertext` /
15
+ * `encapsulatedKey` this module produces (output) -- are base64-encoded raw KEM bytes (an
16
+ * uncompressed SEC1 point for the P-256 public key), never DER. DER only shows up below for the
17
+ * UNRELATED signer keypair, which is a separate WebCrypto ECDSA key, not part of the HPKE
18
+ * exchange.
19
+ *
20
+ * `@hpke/core`, `@hpke/chacha20poly1305`, and `@scure/base` are this SDK's first three runtime
21
+ * dependencies (previously zero -- see client.ts's module doc). All three already resolve in
22
+ * this monorepo as transitive hoists of apps/api's `@privy-io/server-auth`, but a phantom hoist
23
+ * is invisible to a package's own manifest: publishing the SDK without declaring them would
24
+ * break any consumer that doesn't happen to also depend on `@privy-io/server-auth`.
25
+ *
26
+ * CRITICAL: what gets HPKE-sealed is not the `privateKey` string's own UTF-8 bytes -- it is that
27
+ * string DECODED to the wallet's raw private-key bytes first, exactly like Privy's own reference
28
+ * import flow (node_modules/@privy-io/server-auth/dist/cjs/wallet-api/import.js,
29
+ * `handleWalletImport`): "evm" keys are hex (an optional leading "0x" is stripped, then
30
+ * hex-decoded), "solana" keys are base58 (decoded with `@scure/base`'s `base58.decode`, the same
31
+ * codec Privy's own SDK uses). Sealing the string's UTF-8 text instead -- what an earlier version
32
+ * of this module did -- produces a ciphertext that either fails to decrypt correctly on Privy's
33
+ * side or, worse, silently decrypts to the WRONG bytes and provisions a garbage-keyed wallet.
34
+ */
35
+ /**
36
+ * Chain for the linked-wallets import flow (PR3). "evm" covers every EVM chain (Privy's own
37
+ * `chain_type: "ethereum"`), not just Ethereum mainnet; "solana" is Solana. Deliberately NOT the
38
+ * launch-surface `Chain` in client.ts ("solana" | "hood"): import targets Privy's wallet chain
39
+ * types, which distinguish "solana" from EVM rather than from Candle's own Hood/base-mainnet
40
+ * split.
41
+ */
42
+ export type WalletChain = "solana" | "evm";
43
+ /**
44
+ * Decodes a Solana private key given as either a base58 string (`solana-keygen`'s
45
+ * "phantom-paste" form) or the JSON byte-array contents of an `id.json` keyfile (the form
46
+ * `solana-keygen new` actually writes to disk). Branches on whether the trimmed input starts
47
+ * with `[`: no -> base58 decode; yes -> parse as a 64-int 0..255 JSON array. That branch (rather
48
+ * than "try base58, then try JSON") is what lets a malformed array get a keyfile-specific error
49
+ * ("this looks like an id.json but...") instead of the generic base58 one.
50
+ */
51
+ export declare function parseSolanaSecret(input: string): Uint8Array;
52
+ export interface EncryptWalletKeyParams {
53
+ /** Which chain `privateKey` belongs to; selects how it is decoded to raw bytes before sealing. */
54
+ chain: WalletChain;
55
+ /**
56
+ * The wallet's private key exactly as the caller holds it: a hex string for "evm" (an optional
57
+ * leading "0x" is accepted and stripped), or a base58 string for "solana". This is decoded to
58
+ * raw bytes locally -- matching Privy's own wallet-import reference decode -- and THOSE bytes
59
+ * are what gets HPKE-sealed, never the input string's own UTF-8 text.
60
+ */
61
+ privateKey: string;
62
+ /** Privy's HPKE receiver public key from `/wallets/import/init`'s `encryptionPublicKey`, base64-encoded. */
63
+ encryptionPublicKey: string;
64
+ }
65
+ export interface EncryptWalletKeyResult {
66
+ /** Base64-encoded HPKE seal output; posted as `/wallets/import/submit`'s `ciphertext`. */
67
+ ciphertext: string;
68
+ /** Base64-encoded HPKE encapsulated key; posted as `/wallets/import/submit`'s `encapsulatedKey`. */
69
+ encapsulatedKey: string;
70
+ }
71
+ /**
72
+ * Encrypts `privateKey` (decoded to raw bytes per `chain`, see `decodeWalletPrivateKey`) to
73
+ * `encryptionPublicKey` under the HPKE suite above (RFC 9180 single-shot Base-mode seal with a
74
+ * fresh ephemeral sender keypair per call). Neither the input string nor its decoded bytes leave
75
+ * this function call; only the returned ciphertext and encapsulated key are meant to travel
76
+ * further.
77
+ */
78
+ export declare function encryptWalletKeyForImport(params: EncryptWalletKeyParams): Promise<EncryptWalletKeyResult>;
79
+ export interface SignerKeypair {
80
+ /** PEM-encoded PKCS8 private key. The caller keeps this; the SDK never transmits it anywhere. */
81
+ privateKeyPem: string;
82
+ /** Base64-encoded SPKI (DER) public key -- the value `CandleClient.importWallet`'s `signerPublicKey` expects. */
83
+ publicKeyDerBase64: string;
84
+ }
85
+ /**
86
+ * Generates a fresh P-256 (ECDSA) keypair via WebCrypto for use as an agent's wallet signer.
87
+ * Only `publicKeyDerBase64` is meant to leave the process (it becomes `signerPublicKey` in
88
+ * `/wallets/import/submit`, which Privy registers as a 1-of-1 key quorum authorized to sign for
89
+ * the imported wallet); `privateKeyPem` is the caller's to store and use for that later signing,
90
+ * never sent to Candle or Privy by this SDK.
91
+ */
92
+ export declare function generateSignerKeypair(): Promise<SignerKeypair>;
93
+ //# sourceMappingURL=wallet-import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet-import.d.ts","sourceRoot":"","sources":["../src/wallet-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAeH;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,KAAK,CAAA;AAE1C;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CA0B3D;AAkBD,MAAM,WAAW,sBAAsB;IACrC,kGAAkG;IAClG,KAAK,EAAE,WAAW,CAAA;IAClB;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB,4GAA4G;IAC5G,mBAAmB,EAAE,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACrC,0FAA0F;IAC1F,UAAU,EAAE,MAAM,CAAA;IAClB,oGAAoG;IACpG,eAAe,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAY/G;AAED,MAAM,WAAW,aAAa;IAC5B,iGAAiG;IACjG,aAAa,EAAE,MAAM,CAAA;IACrB,iHAAiH;IACjH,kBAAkB,EAAE,MAAM,CAAA;CAC3B;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,aAAa,CAAC,CAUpE"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Webhook signature verification for Candle webhook deliveries (Phase 2, R9).
3
+ *
4
+ * Every delivery carries `x-candle-signature: t=<unix seconds>,v1=<hex hmac-sha256(secret,
5
+ * "<t>.<body>")>` where `<body>` is the EXACT raw request body string (re-serializing the
6
+ * parsed JSON can reorder keys and break the signature; always verify the raw bytes as text).
7
+ *
8
+ * Implemented with `node:crypto` (`createHmac` + `timingSafeEqual`), which both Node 18+ and
9
+ * Bun provide, so the SDK stays zero-dependency. Edge runtimes without `node:crypto` would
10
+ * need a Web Crypto (`crypto.subtle`) implementation; that is a deliberate later concern, not
11
+ * covered here.
12
+ */
13
+ /**
14
+ * Returns true only when `header` carries a well-formed `t=...,v1=...` signature whose
15
+ * timestamp is within `toleranceSec` (default 300) of `nowSec` and whose `v1` digest matches
16
+ * HMAC-SHA256(secret, `${t}.${body}`). Never throws on malformed input; every failure mode
17
+ * (missing header, bad format, stale timestamp, wrong secret, tampered body) is `false`.
18
+ */
19
+ export declare function verifyWebhookSignature(secret: string, header: string | null | undefined, body: string, nowSec: number, toleranceSec?: number): boolean;
20
+ //# sourceMappingURL=webhooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../src/webhooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,YAAY,SAAM,GACjB,OAAO,CA0BT"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@candledottv/agent-sdk",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript SDK for the Candle agent rail: typed headless launches, market reads, and webhook verification",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "license": "MIT",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/candledottv/agentic.git",
18
+ "directory": "packages/sdk"
19
+ },
20
+ "homepage": "https://docs.candle.tv/developers/agent-sdk",
21
+ "bugs": {
22
+ "url": "https://github.com/candledottv/agentic/issues"
23
+ },
24
+ "keywords": [
25
+ "candle",
26
+ "solana",
27
+ "agent",
28
+ "sdk",
29
+ "token-launch",
30
+ "ai-agent"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "scripts": {
41
+ "build:js": "bun build src/index.ts --target=node --format=esm --packages=external --outfile=dist/index.js",
42
+ "build:types": "tsc -p tsconfig.build.json",
43
+ "build": "bun run build:js && bun run build:types",
44
+ "clean": "rm -rf dist",
45
+ "test": "bun test",
46
+ "typecheck": "tsc --noEmit",
47
+ "lint": "biome check ."
48
+ },
49
+ "dependencies": {
50
+ "@hpke/chacha20poly1305": "^1.6.2",
51
+ "@hpke/core": "^1.7.2",
52
+ "@scure/base": "^1.2.6",
53
+ "canonicalize": "^2.1.0"
54
+ },
55
+ "devDependencies": {
56
+ "@privy-io/server-auth": "^1.32.5",
57
+ "@types/bun": "^1.1.14",
58
+ "typescript": "^5.7.2"
59
+ }
60
+ }