@distilled.cloud/coinbase 1.0.0-rc.12 → 1.0.0-rc.13
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/README.md +34 -0
- package/lib/protocol.d.ts +2 -2
- package/lib/protocol.d.ts.map +1 -1
- package/lib/protocol.js +7 -4
- package/lib/protocol.js.map +1 -1
- package/lib/response-validation.test.d.ts +6 -0
- package/lib/response-validation.test.d.ts.map +1 -0
- package/lib/response-validation.test.js +42 -0
- package/lib/response-validation.test.js.map +1 -0
- package/package.json +4 -4
- package/src/protocol.ts +14 -6
- package/src/response-validation.test.ts +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# @distilled.cloud/coinbase
|
|
2
|
+
|
|
3
|
+
Effect-native SDK for [coinbase](https://www.npmjs.com/package/@distilled.cloud/coinbase).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @distilled.cloud/coinbase effect
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { Effect, Layer } from "effect";
|
|
15
|
+
import * as FetchHttpClient from "effect/http/FetchHttpClient";
|
|
16
|
+
import * as Coinbase from "@distilled.cloud/coinbase";
|
|
17
|
+
|
|
18
|
+
const program = Effect.gen(function* () {
|
|
19
|
+
const result = yield* Coinbase.listBalances({});
|
|
20
|
+
return result;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const Live = Layer.mergeAll(
|
|
24
|
+
FetchHttpClient.layer,
|
|
25
|
+
Coinbase.CredentialsFromEnv,
|
|
26
|
+
Coinbase.CoinbaseProtocol,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
program.pipe(Effect.provide(Live), Effect.runPromise);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Auth
|
|
33
|
+
|
|
34
|
+
Required: `CDP_API_KEY_ID`, `CDP_API_KEY_NAME`, `CDP_API_KEY_SECRET`, `CDP_WALLET_SECRET`.
|
package/lib/protocol.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Layer from "effect/Layer";
|
|
2
|
-
import type * as HttpClient from "effect/
|
|
3
|
-
import type * as HttpClientError from "effect/
|
|
2
|
+
import type * as HttpClient from "effect/http/HttpClient";
|
|
3
|
+
import type * as HttpClientError from "effect/http/HttpClientError";
|
|
4
4
|
import * as API from "@distilled.cloud/core/api";
|
|
5
5
|
import { type ConfigError } from "@distilled.cloud/core/errors";
|
|
6
6
|
import { Credentials } from "./credentials.ts";
|
package/lib/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAKtC,OAAO,KAAK,KAAK,UAAU,MAAM,
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAKtC,OAAO,KAAK,KAAK,UAAU,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,KAAK,eAAe,MAAM,6BAA6B,CAAC;AAGpE,OAAO,KAAK,GAAG,MAAM,2BAA2B,CAAC;AAMjD,OAAO,EACL,KAAK,WAAW,EAEjB,MAAM,8BAA8B,CAAC;AAItC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAGL,KAAK,aAAa,EAInB,MAAM,aAAa,CAAC;AAErB;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GACvB,aAAa,GACb,WAAW,GACX,eAAe,CAAC,eAAe,CAAC;AAEpC,2EAA2E;AAC3E,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC;AAyVpE;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAQtD,CAAC"}
|
package/lib/protocol.js
CHANGED
|
@@ -41,14 +41,15 @@ import * as Layer from "effect/Layer";
|
|
|
41
41
|
import * as Redacted from "effect/Redacted";
|
|
42
42
|
import * as Schema from "effect/Schema";
|
|
43
43
|
import * as crypto from "node:crypto";
|
|
44
|
-
import * as HttpClientRequest from "effect/
|
|
44
|
+
import * as HttpClientRequest from "effect/http/HttpClientRequest";
|
|
45
45
|
import * as API from "@distilled.cloud/core/api";
|
|
46
46
|
import { buildRequest, mapKeys } from "@distilled.cloud/core/protocol-http";
|
|
47
47
|
import { unwrapRedactedDeep, wrapSensitive, } from "@distilled.cloud/core/protocol-rest";
|
|
48
48
|
import { HTTP_STATUS_MAP, } from "@distilled.cloud/core/errors";
|
|
49
|
+
import { validateResponse } from "@distilled.cloud/core/response-validation";
|
|
49
50
|
import { parseRetryAfterForStatus } from "@distilled.cloud/core/retry-after";
|
|
50
51
|
import { Credentials } from "./credentials.js";
|
|
51
|
-
import { COINBASE_HTTP_STATUS_MAP, ERROR_TYPE_MAP, STANDARD_ERROR_TYPE_MAP, UnknownCoinbaseError, } from "./errors.js";
|
|
52
|
+
import { COINBASE_HTTP_STATUS_MAP, CoinbaseParseError, ERROR_TYPE_MAP, STANDARD_ERROR_TYPE_MAP, UnknownCoinbaseError, } from "./errors.js";
|
|
52
53
|
// Bridge: Protocol.decode is typed as Effect<unknown> (no error channel), but
|
|
53
54
|
// Coinbase failures are real typed errors that the operation's explicit
|
|
54
55
|
// `CoinbaseOpError` annotation re-surfaces. Fail with the instance and erase
|
|
@@ -306,9 +307,11 @@ const decode = ({ response, outputAst, }) => Effect.gen(function* () {
|
|
|
306
307
|
}
|
|
307
308
|
// No envelope: the response body IS the payload, mapped onto the output
|
|
308
309
|
// schema (wire names → TS names), with members marked T.SensitiveValue
|
|
309
|
-
// delivered as Redacted.
|
|
310
|
+
// delivered as Redacted. Strict mode (core/response-validation) checks
|
|
311
|
+
// the mapped body against the output schema first.
|
|
310
312
|
const body = json === undefined ? {} : json;
|
|
311
|
-
|
|
313
|
+
const mapped = yield* validateResponse(outputAst, mapKeys(outputAst, body, "decode"), (cause) => new CoinbaseParseError({ body: json ?? text, cause })).pipe(Effect.catch(fail));
|
|
314
|
+
return wrapSensitive(outputAst, mapped);
|
|
312
315
|
});
|
|
313
316
|
/**
|
|
314
317
|
* Coinbase CDP protocol layer.
|
package/lib/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAGtC,OAAO,KAAK,iBAAiB,MAAM,
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CoinbaseParseError } from "./errors.ts";
|
|
2
|
+
import type { CoinbaseOpError } from "./protocol.ts";
|
|
3
|
+
export declare const parseErrorIsDeclared: [CoinbaseParseError] extends [
|
|
4
|
+
CoinbaseOpError
|
|
5
|
+
] ? true : false;
|
|
6
|
+
//# sourceMappingURL=response-validation.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-validation.test.d.ts","sourceRoot":"","sources":["../src/response-validation.test.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AA6CrD,eAAO,MAAM,oBAAoB,EAAE,CAAC,kBAAkB,CAAC,SAAS;IAC9D,eAAe;CAChB,GACG,IAAI,GACJ,KAAY,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { runValidationModes } from "@distilled.cloud/core/testing";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Layer from "effect/Layer";
|
|
5
|
+
import * as Redacted from "effect/Redacted";
|
|
6
|
+
import { Credentials, DEFAULT_API_BASE_URL } from "./credentials.js";
|
|
7
|
+
import { CoinbaseParseError } from "./errors.js";
|
|
8
|
+
import * as Retry from "./retry.js";
|
|
9
|
+
import { listEvmAccounts } from "./services/cdp.js";
|
|
10
|
+
// A dummy Ed25519 key (32-byte seed + 32 bytes) — only used to sign the JWT.
|
|
11
|
+
const TestCredentials = Layer.succeed(Credentials, Effect.succeed({
|
|
12
|
+
apiKeyId: "test",
|
|
13
|
+
apiKeySecret: Redacted.make(Buffer.alloc(64, 1).toString("base64")),
|
|
14
|
+
apiBaseUrl: DEFAULT_API_BASE_URL,
|
|
15
|
+
}));
|
|
16
|
+
// listEvmAccounts declares `{ accounts: { address: string; … }[]; nextPageToken?: string }`.
|
|
17
|
+
const run = (body) => runValidationModes(listEvmAccounts({}).pipe(Retry.none, Effect.provide(TestCredentials)), { body });
|
|
18
|
+
describe("Coinbase response validation", () => {
|
|
19
|
+
test("a matching body succeeds unchanged in both modes", async () => {
|
|
20
|
+
const body = {
|
|
21
|
+
accounts: [{ address: "0x0000000000000000000000000000000000000001" }],
|
|
22
|
+
};
|
|
23
|
+
const { lenient, strict } = await run(JSON.stringify(body));
|
|
24
|
+
expect(lenient).toMatchObject({ _tag: "Success", success: body });
|
|
25
|
+
expect(strict).toMatchObject({ _tag: "Success", success: body });
|
|
26
|
+
});
|
|
27
|
+
test("a body missing required members: lenient returns it, strict fails", async () => {
|
|
28
|
+
const body = { accounts: [{ name: "main" }] };
|
|
29
|
+
const { lenient, strict } = await run(JSON.stringify(body));
|
|
30
|
+
expect(lenient).toMatchObject({ _tag: "Success", success: body });
|
|
31
|
+
expect(strict._tag).toBe("Failure");
|
|
32
|
+
expect(strict.failure).toBeInstanceOf(CoinbaseParseError);
|
|
33
|
+
});
|
|
34
|
+
test("a non-JSON body: lenient returns the text, strict fails", async () => {
|
|
35
|
+
const { lenient, strict } = await run("not json");
|
|
36
|
+
expect(lenient).toMatchObject({ _tag: "Success", success: "not json" });
|
|
37
|
+
expect(strict.failure).toBeInstanceOf(CoinbaseParseError);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
// CoinbaseParseError is part of every operation's declared error type.
|
|
41
|
+
export const parseErrorIsDeclared = true;
|
|
42
|
+
//# sourceMappingURL=response-validation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-validation.test.js","sourceRoot":"","sources":["../src/response-validation.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@distilled.cloud/coinbase",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.13",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/alchemy-run/distilled",
|
|
@@ -58,15 +58,15 @@
|
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@distilled.cloud/core": "1.0.0-rc.
|
|
61
|
+
"@distilled.cloud/core": "1.0.0-rc.13"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@types/bun": "1.3.14",
|
|
65
65
|
"@types/node": "26.2.0",
|
|
66
|
-
"@effect/platform-bun": "
|
|
66
|
+
"@effect/platform-bun": "^4.0.0"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"effect": "
|
|
69
|
+
"effect": "^4.0.0"
|
|
70
70
|
},
|
|
71
71
|
"scripts": {
|
|
72
72
|
"build": "tsc -b",
|
package/src/protocol.ts
CHANGED
|
@@ -42,10 +42,10 @@ import * as Redacted from "effect/Redacted";
|
|
|
42
42
|
import * as Schema from "effect/Schema";
|
|
43
43
|
import type * as AST from "effect/SchemaAST";
|
|
44
44
|
import * as crypto from "node:crypto";
|
|
45
|
-
import type * as HttpClient from "effect/
|
|
46
|
-
import type * as HttpClientError from "effect/
|
|
47
|
-
import * as HttpClientRequest from "effect/
|
|
48
|
-
import type * as HttpClientResponse from "effect/
|
|
45
|
+
import type * as HttpClient from "effect/http/HttpClient";
|
|
46
|
+
import type * as HttpClientError from "effect/http/HttpClientError";
|
|
47
|
+
import * as HttpClientRequest from "effect/http/HttpClientRequest";
|
|
48
|
+
import type * as HttpClientResponse from "effect/http/HttpClientResponse";
|
|
49
49
|
import * as API from "@distilled.cloud/core/api";
|
|
50
50
|
import { buildRequest, mapKeys } from "@distilled.cloud/core/protocol-http";
|
|
51
51
|
import {
|
|
@@ -56,11 +56,13 @@ import {
|
|
|
56
56
|
type ConfigError,
|
|
57
57
|
HTTP_STATUS_MAP,
|
|
58
58
|
} from "@distilled.cloud/core/errors";
|
|
59
|
+
import { validateResponse } from "@distilled.cloud/core/response-validation";
|
|
59
60
|
import { parseRetryAfterForStatus } from "@distilled.cloud/core/retry-after";
|
|
60
61
|
import type { Config } from "./credentials.ts";
|
|
61
62
|
import { Credentials } from "./credentials.ts";
|
|
62
63
|
import {
|
|
63
64
|
COINBASE_HTTP_STATUS_MAP,
|
|
65
|
+
CoinbaseParseError,
|
|
64
66
|
type DefaultErrors,
|
|
65
67
|
ERROR_TYPE_MAP,
|
|
66
68
|
STANDARD_ERROR_TYPE_MAP,
|
|
@@ -413,9 +415,15 @@ const decode = ({
|
|
|
413
415
|
|
|
414
416
|
// No envelope: the response body IS the payload, mapped onto the output
|
|
415
417
|
// schema (wire names → TS names), with members marked T.SensitiveValue
|
|
416
|
-
// delivered as Redacted.
|
|
418
|
+
// delivered as Redacted. Strict mode (core/response-validation) checks
|
|
419
|
+
// the mapped body against the output schema first.
|
|
417
420
|
const body = json === undefined ? {} : json;
|
|
418
|
-
|
|
421
|
+
const mapped = yield* validateResponse(
|
|
422
|
+
outputAst,
|
|
423
|
+
mapKeys(outputAst, body, "decode"),
|
|
424
|
+
(cause) => new CoinbaseParseError({ body: json ?? text, cause }),
|
|
425
|
+
).pipe(Effect.catch(fail));
|
|
426
|
+
return wrapSensitive(outputAst, mapped);
|
|
419
427
|
});
|
|
420
428
|
|
|
421
429
|
/**
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { runValidationModes } from "@distilled.cloud/core/testing";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Layer from "effect/Layer";
|
|
5
|
+
import * as Redacted from "effect/Redacted";
|
|
6
|
+
import { Credentials, DEFAULT_API_BASE_URL } from "./credentials.ts";
|
|
7
|
+
import { CoinbaseParseError } from "./errors.ts";
|
|
8
|
+
import * as Retry from "./retry.ts";
|
|
9
|
+
import { listEvmAccounts } from "./services/cdp.ts";
|
|
10
|
+
import type { CoinbaseOpError } from "./protocol.ts";
|
|
11
|
+
|
|
12
|
+
// A dummy Ed25519 key (32-byte seed + 32 bytes) — only used to sign the JWT.
|
|
13
|
+
const TestCredentials = Layer.succeed(
|
|
14
|
+
Credentials,
|
|
15
|
+
Effect.succeed({
|
|
16
|
+
apiKeyId: "test",
|
|
17
|
+
apiKeySecret: Redacted.make(Buffer.alloc(64, 1).toString("base64")),
|
|
18
|
+
apiBaseUrl: DEFAULT_API_BASE_URL,
|
|
19
|
+
}),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
// listEvmAccounts declares `{ accounts: { address: string; … }[]; nextPageToken?: string }`.
|
|
23
|
+
const run = (body: string) =>
|
|
24
|
+
runValidationModes(
|
|
25
|
+
listEvmAccounts({}).pipe(Retry.none, Effect.provide(TestCredentials)),
|
|
26
|
+
{ body },
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
describe("Coinbase response validation", () => {
|
|
30
|
+
test("a matching body succeeds unchanged in both modes", async () => {
|
|
31
|
+
const body = {
|
|
32
|
+
accounts: [{ address: "0x0000000000000000000000000000000000000001" }],
|
|
33
|
+
};
|
|
34
|
+
const { lenient, strict } = await run(JSON.stringify(body));
|
|
35
|
+
expect(lenient).toMatchObject({ _tag: "Success", success: body });
|
|
36
|
+
expect(strict).toMatchObject({ _tag: "Success", success: body });
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("a body missing required members: lenient returns it, strict fails", async () => {
|
|
40
|
+
const body = { accounts: [{ name: "main" }] };
|
|
41
|
+
const { lenient, strict } = await run(JSON.stringify(body));
|
|
42
|
+
expect(lenient).toMatchObject({ _tag: "Success", success: body });
|
|
43
|
+
expect(strict._tag).toBe("Failure");
|
|
44
|
+
expect((strict as any).failure).toBeInstanceOf(CoinbaseParseError);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("a non-JSON body: lenient returns the text, strict fails", async () => {
|
|
48
|
+
const { lenient, strict } = await run("not json");
|
|
49
|
+
expect(lenient).toMatchObject({ _tag: "Success", success: "not json" });
|
|
50
|
+
expect((strict as any).failure).toBeInstanceOf(CoinbaseParseError);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// CoinbaseParseError is part of every operation's declared error type.
|
|
55
|
+
export const parseErrorIsDeclared: [CoinbaseParseError] extends [
|
|
56
|
+
CoinbaseOpError,
|
|
57
|
+
]
|
|
58
|
+
? true
|
|
59
|
+
: false = true;
|