@distilled.cloud/expo-eas 1.0.0-rc.11 → 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 +8 -5
- package/lib/protocol.js.map +1 -1
- package/lib/response-validation.test.d.ts +4 -0
- package/lib/response-validation.test.d.ts.map +1 -0
- package/lib/response-validation.test.js +39 -0
- package/lib/response-validation.test.js.map +1 -0
- package/package.json +4 -4
- package/src/protocol.ts +19 -8
- package/src/response-validation.test.ts +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# @distilled.cloud/expo-eas
|
|
2
|
+
|
|
3
|
+
Effect-native SDK for [expo-eas](https://www.npmjs.com/package/@distilled.cloud/expo-eas).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @distilled.cloud/expo-eas 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 Eas from "@distilled.cloud/expo-eas";
|
|
17
|
+
|
|
18
|
+
const program = Effect.gen(function* () {
|
|
19
|
+
const result = yield* Eas.getUserPreference({});
|
|
20
|
+
return result;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const Live = Layer.mergeAll(
|
|
24
|
+
FetchHttpClient.layer,
|
|
25
|
+
Eas.CredentialsFromEnv,
|
|
26
|
+
Eas.ExpoGraphqlProtocol,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
program.pipe(Effect.provide(Live), Effect.runPromise);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Auth
|
|
33
|
+
|
|
34
|
+
Required: `EXPO_TOKEN`. Optional: `EXPO_API_URL`. Sent as `Authorization: Bearer`.
|
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 { Credentials } from "./credentials.ts";
|
|
6
6
|
import { type DefaultErrors } from "./errors.ts";
|
package/lib/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAItC,OAAO,KAAK,KAAK,UAAU,MAAM,
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAItC,OAAO,KAAK,KAAK,UAAU,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,KAAK,eAAe,MAAM,6BAA6B,CAAC;AAGpE,OAAO,KAAK,GAAG,MAAM,2BAA2B,CAAC;AAQjD,OAAO,EAAe,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EACL,KAAK,aAAa,EAInB,MAAM,aAAa,CAAC;AASrB;;;;;;;;;GASG;AACH,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,eAAe,CAAC,eAAe,CAAC;AAE7E,sEAAsE;AACtE,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC;AAiQnE;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAQzD,CAAC"}
|
package/lib/protocol.js
CHANGED
|
@@ -28,10 +28,11 @@ import * as Effect from "effect/Effect";
|
|
|
28
28
|
import * as Layer from "effect/Layer";
|
|
29
29
|
import * as Redacted from "effect/Redacted";
|
|
30
30
|
import * as Schema from "effect/Schema";
|
|
31
|
-
import * as HttpClientRequest from "effect/
|
|
31
|
+
import * as HttpClientRequest from "effect/http/HttpClientRequest";
|
|
32
32
|
import * as API from "@distilled.cloud/core/api";
|
|
33
33
|
import { getAnn } from "@distilled.cloud/core/protocol-http";
|
|
34
34
|
import { HTTP_STATUS_MAP } from "@distilled.cloud/core/errors";
|
|
35
|
+
import { failIfStrict, validateResponse, } from "@distilled.cloud/core/response-validation";
|
|
35
36
|
import { parseRetryAfterForStatus } from "@distilled.cloud/core/retry-after";
|
|
36
37
|
import { Credentials } from "./credentials.js";
|
|
37
38
|
import { EAS_ERROR_CODE_MAP, EasParseError, UnknownEasError, } from "./errors.js";
|
|
@@ -183,10 +184,11 @@ const decode = ({ response, outputAst, }) => Effect.gen(function* () {
|
|
|
183
184
|
if (status >= 400) {
|
|
184
185
|
return yield* matchError(status, text, headers);
|
|
185
186
|
}
|
|
186
|
-
|
|
187
|
+
// Lenient mode returns the body as read.
|
|
188
|
+
return yield* failIfStrict(new EasParseError({
|
|
187
189
|
body: text,
|
|
188
190
|
cause: "response body is not valid JSON",
|
|
189
|
-
}));
|
|
191
|
+
}), text).pipe(Effect.catch(fail));
|
|
190
192
|
}
|
|
191
193
|
// GraphQL errors[] (even on HTTP 200) or HTTP-level failure → typed
|
|
192
194
|
// error via the ported v0 matcher.
|
|
@@ -199,7 +201,8 @@ const decode = ({ response, outputAst, }) => Effect.gen(function* () {
|
|
|
199
201
|
return yield* matchError(status, json, headers);
|
|
200
202
|
}
|
|
201
203
|
// Success: unwrap `data.<responsePath>` and return it verbatim (member
|
|
202
|
-
// names are GraphQL field names — no wire renames).
|
|
204
|
+
// names are GraphQL field names — no wire renames). Strict mode
|
|
205
|
+
// (core/response-validation) checks it against the output schema.
|
|
203
206
|
const path = getAnn(outputAst, responsePathSymbol);
|
|
204
207
|
let payload = envelope !== null && typeof envelope === "object"
|
|
205
208
|
? envelope.data
|
|
@@ -212,7 +215,7 @@ const decode = ({ response, outputAst, }) => Effect.gen(function* () {
|
|
|
212
215
|
: undefined;
|
|
213
216
|
}
|
|
214
217
|
}
|
|
215
|
-
return payload === undefined ? null : payload;
|
|
218
|
+
return yield* validateResponse(outputAst, payload === undefined ? null : payload, (cause) => new EasParseError({ body: json, cause })).pipe(Effect.catch(fail));
|
|
216
219
|
});
|
|
217
220
|
/**
|
|
218
221
|
* EAS GraphQL protocol layer.
|
package/lib/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;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;AAIxC,OAAO,KAAK,iBAAiB,MAAM,
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-validation.test.d.ts","sourceRoot":"","sources":["../src/response-validation.test.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AA+CpD,eAAO,MAAM,oBAAoB,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,cAAc,CAAC,GACvE,IAAI,GACJ,KAAY,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
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 { EasParseError } from "./errors.js";
|
|
8
|
+
import * as Retry from "./retry.js";
|
|
9
|
+
import { accessTokenDeleteAccessToken } from "./services/eas.js";
|
|
10
|
+
const TestCredentials = Layer.succeed(Credentials, Effect.succeed({
|
|
11
|
+
accessToken: Redacted.make("test"),
|
|
12
|
+
apiBaseUrl: DEFAULT_API_BASE_URL,
|
|
13
|
+
}));
|
|
14
|
+
// accessTokenDeleteAccessToken declares `{ id: string }`, unwrapped from
|
|
15
|
+
// `data.accessToken.deleteAccessToken`.
|
|
16
|
+
const run = (body) => runValidationModes(accessTokenDeleteAccessToken({ id: "tok_1" }).pipe(Retry.none, Effect.provide(TestCredentials)), { body });
|
|
17
|
+
const envelope = (payload) => JSON.stringify({ data: { accessToken: { deleteAccessToken: payload } } });
|
|
18
|
+
describe("EAS response validation", () => {
|
|
19
|
+
test("a matching body succeeds unchanged in both modes", async () => {
|
|
20
|
+
const payload = { id: "tok_1" };
|
|
21
|
+
const { lenient, strict } = await run(envelope(payload));
|
|
22
|
+
expect(lenient).toMatchObject({ _tag: "Success", success: payload });
|
|
23
|
+
expect(strict).toMatchObject({ _tag: "Success", success: payload });
|
|
24
|
+
});
|
|
25
|
+
test("a body missing required members: lenient returns it, strict fails", async () => {
|
|
26
|
+
const { lenient, strict } = await run(envelope({}));
|
|
27
|
+
expect(lenient).toMatchObject({ _tag: "Success", success: {} });
|
|
28
|
+
expect(strict._tag).toBe("Failure");
|
|
29
|
+
expect(strict.failure).toBeInstanceOf(EasParseError);
|
|
30
|
+
});
|
|
31
|
+
test("a non-JSON body: lenient returns the text, strict fails", async () => {
|
|
32
|
+
const { lenient, strict } = await run("not json");
|
|
33
|
+
expect(lenient).toMatchObject({ _tag: "Success", success: "not json" });
|
|
34
|
+
expect(strict.failure).toBeInstanceOf(EasParseError);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
// EasParseError is part of every operation's declared error type.
|
|
38
|
+
export const parseErrorIsDeclared = true;
|
|
39
|
+
//# 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/expo-eas",
|
|
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",
|
|
@@ -65,15 +65,15 @@
|
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@distilled.cloud/core": "1.0.0-rc.
|
|
68
|
+
"@distilled.cloud/core": "1.0.0-rc.13"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/bun": "1.3.14",
|
|
72
72
|
"@types/node": "26.2.0",
|
|
73
|
-
"@effect/platform-bun": "
|
|
73
|
+
"@effect/platform-bun": "^4.0.0"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
|
-
"effect": "
|
|
76
|
+
"effect": "^4.0.0"
|
|
77
77
|
},
|
|
78
78
|
"scripts": {
|
|
79
79
|
"build": "tsc -b",
|
package/src/protocol.ts
CHANGED
|
@@ -29,13 +29,17 @@ import * as Layer from "effect/Layer";
|
|
|
29
29
|
import * as Redacted from "effect/Redacted";
|
|
30
30
|
import * as Schema from "effect/Schema";
|
|
31
31
|
import type * as AST from "effect/SchemaAST";
|
|
32
|
-
import type * as HttpClient from "effect/
|
|
33
|
-
import type * as HttpClientError from "effect/
|
|
34
|
-
import * as HttpClientRequest from "effect/
|
|
35
|
-
import type * as HttpClientResponse from "effect/
|
|
32
|
+
import type * as HttpClient from "effect/http/HttpClient";
|
|
33
|
+
import type * as HttpClientError from "effect/http/HttpClientError";
|
|
34
|
+
import * as HttpClientRequest from "effect/http/HttpClientRequest";
|
|
35
|
+
import type * as HttpClientResponse from "effect/http/HttpClientResponse";
|
|
36
36
|
import * as API from "@distilled.cloud/core/api";
|
|
37
37
|
import { getAnn } from "@distilled.cloud/core/protocol-http";
|
|
38
38
|
import { HTTP_STATUS_MAP } from "@distilled.cloud/core/errors";
|
|
39
|
+
import {
|
|
40
|
+
failIfStrict,
|
|
41
|
+
validateResponse,
|
|
42
|
+
} from "@distilled.cloud/core/response-validation";
|
|
39
43
|
import { parseRetryAfterForStatus } from "@distilled.cloud/core/retry-after";
|
|
40
44
|
import { type Config, Credentials } from "./credentials.ts";
|
|
41
45
|
import {
|
|
@@ -277,12 +281,14 @@ const decode = ({
|
|
|
277
281
|
if (status >= 400) {
|
|
278
282
|
return yield* matchError(status, text, headers);
|
|
279
283
|
}
|
|
280
|
-
|
|
284
|
+
// Lenient mode returns the body as read.
|
|
285
|
+
return yield* failIfStrict(
|
|
281
286
|
new EasParseError({
|
|
282
287
|
body: text,
|
|
283
288
|
cause: "response body is not valid JSON",
|
|
284
289
|
}),
|
|
285
|
-
|
|
290
|
+
text,
|
|
291
|
+
).pipe(Effect.catch(fail));
|
|
286
292
|
}
|
|
287
293
|
|
|
288
294
|
// GraphQL errors[] (even on HTTP 200) or HTTP-level failure → typed
|
|
@@ -298,7 +304,8 @@ const decode = ({
|
|
|
298
304
|
}
|
|
299
305
|
|
|
300
306
|
// Success: unwrap `data.<responsePath>` and return it verbatim (member
|
|
301
|
-
// names are GraphQL field names — no wire renames).
|
|
307
|
+
// names are GraphQL field names — no wire renames). Strict mode
|
|
308
|
+
// (core/response-validation) checks it against the output schema.
|
|
302
309
|
const path = getAnn(outputAst, responsePathSymbol) as string | undefined;
|
|
303
310
|
let payload: unknown =
|
|
304
311
|
envelope !== null && typeof envelope === "object"
|
|
@@ -312,7 +319,11 @@ const decode = ({
|
|
|
312
319
|
: undefined;
|
|
313
320
|
}
|
|
314
321
|
}
|
|
315
|
-
return
|
|
322
|
+
return yield* validateResponse(
|
|
323
|
+
outputAst,
|
|
324
|
+
payload === undefined ? null : payload,
|
|
325
|
+
(cause) => new EasParseError({ body: json, cause }),
|
|
326
|
+
).pipe(Effect.catch(fail));
|
|
316
327
|
});
|
|
317
328
|
|
|
318
329
|
/**
|
|
@@ -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 { EasParseError } from "./errors.ts";
|
|
8
|
+
import * as Retry from "./retry.ts";
|
|
9
|
+
import { accessTokenDeleteAccessToken } from "./services/eas.ts";
|
|
10
|
+
import type { ExpoEasOpError } from "./protocol.ts";
|
|
11
|
+
|
|
12
|
+
const TestCredentials = Layer.succeed(
|
|
13
|
+
Credentials,
|
|
14
|
+
Effect.succeed({
|
|
15
|
+
accessToken: Redacted.make("test"),
|
|
16
|
+
apiBaseUrl: DEFAULT_API_BASE_URL,
|
|
17
|
+
}),
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
// accessTokenDeleteAccessToken declares `{ id: string }`, unwrapped from
|
|
21
|
+
// `data.accessToken.deleteAccessToken`.
|
|
22
|
+
const run = (body: string) =>
|
|
23
|
+
runValidationModes(
|
|
24
|
+
accessTokenDeleteAccessToken({ id: "tok_1" }).pipe(
|
|
25
|
+
Retry.none,
|
|
26
|
+
Effect.provide(TestCredentials),
|
|
27
|
+
),
|
|
28
|
+
{ body },
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const envelope = (payload: unknown) =>
|
|
32
|
+
JSON.stringify({ data: { accessToken: { deleteAccessToken: payload } } });
|
|
33
|
+
|
|
34
|
+
describe("EAS response validation", () => {
|
|
35
|
+
test("a matching body succeeds unchanged in both modes", async () => {
|
|
36
|
+
const payload = { id: "tok_1" };
|
|
37
|
+
const { lenient, strict } = await run(envelope(payload));
|
|
38
|
+
expect(lenient).toMatchObject({ _tag: "Success", success: payload });
|
|
39
|
+
expect(strict).toMatchObject({ _tag: "Success", success: payload });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("a body missing required members: lenient returns it, strict fails", async () => {
|
|
43
|
+
const { lenient, strict } = await run(envelope({}));
|
|
44
|
+
expect(lenient).toMatchObject({ _tag: "Success", success: {} });
|
|
45
|
+
expect(strict._tag).toBe("Failure");
|
|
46
|
+
expect((strict as any).failure).toBeInstanceOf(EasParseError);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("a non-JSON body: lenient returns the text, strict fails", async () => {
|
|
50
|
+
const { lenient, strict } = await run("not json");
|
|
51
|
+
expect(lenient).toMatchObject({ _tag: "Success", success: "not json" });
|
|
52
|
+
expect((strict as any).failure).toBeInstanceOf(EasParseError);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// EasParseError is part of every operation's declared error type.
|
|
57
|
+
export const parseErrorIsDeclared: [EasParseError] extends [ExpoEasOpError]
|
|
58
|
+
? true
|
|
59
|
+
: false = true;
|