alchemy 0.46.0 → 0.46.1

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.
Files changed (40) hide show
  1. package/bin/alchemy.mjs +156 -160
  2. package/bin/commands/login.ts +2 -5
  3. package/lib/cloudflare/api.d.ts +9 -5
  4. package/lib/cloudflare/api.d.ts.map +1 -1
  5. package/lib/cloudflare/api.js +6 -46
  6. package/lib/cloudflare/api.js.map +1 -1
  7. package/lib/cloudflare/auth.d.ts +16 -35
  8. package/lib/cloudflare/auth.d.ts.map +1 -1
  9. package/lib/cloudflare/auth.js +54 -24
  10. package/lib/cloudflare/auth.js.map +1 -1
  11. package/lib/cloudflare/{auth-wrangler.d.ts → oauth.d.ts} +11 -14
  12. package/lib/cloudflare/oauth.d.ts.map +1 -0
  13. package/lib/cloudflare/{auth-wrangler.js → oauth.js} +98 -109
  14. package/lib/cloudflare/oauth.js.map +1 -0
  15. package/lib/cloudflare/user.d.ts +1 -1
  16. package/lib/cloudflare/user.d.ts.map +1 -1
  17. package/lib/cloudflare/user.js +20 -29
  18. package/lib/cloudflare/user.js.map +1 -1
  19. package/lib/cloudflare/worker.d.ts +1 -0
  20. package/lib/cloudflare/worker.d.ts.map +1 -1
  21. package/lib/cloudflare/worker.js +4 -3
  22. package/lib/cloudflare/worker.js.map +1 -1
  23. package/lib/util/memoize.d.ts +0 -1
  24. package/lib/util/memoize.d.ts.map +1 -1
  25. package/lib/util/memoize.js +0 -13
  26. package/lib/util/memoize.js.map +1 -1
  27. package/lib/util/neverthrow.d.ts +7 -0
  28. package/lib/util/neverthrow.d.ts.map +1 -1
  29. package/lib/util/neverthrow.js +17 -0
  30. package/lib/util/neverthrow.js.map +1 -1
  31. package/package.json +1 -1
  32. package/src/cloudflare/api.ts +18 -57
  33. package/src/cloudflare/auth.ts +84 -68
  34. package/src/cloudflare/{auth-wrangler.ts → oauth.ts} +154 -168
  35. package/src/cloudflare/user.ts +33 -51
  36. package/src/cloudflare/worker.ts +9 -4
  37. package/src/util/memoize.ts +0 -17
  38. package/src/util/neverthrow.ts +28 -0
  39. package/lib/cloudflare/auth-wrangler.d.ts.map +0 -1
  40. package/lib/cloudflare/auth-wrangler.js.map +0 -1
@@ -1,18 +1,24 @@
1
1
  import kleur from "kleur";
2
- import { err, ok, ResultAsync } from "neverthrow";
2
+ import { err, ok, okAsync, ResultAsync } from "neverthrow";
3
+ import assert from "node:assert";
3
4
  import crypto from "node:crypto";
4
5
  import fs from "node:fs/promises";
5
6
  import os from "node:os";
6
7
  import path from "node:path";
7
8
  import open from "open";
8
9
  import { HTTPServer } from "../util/http-server.ts";
9
- import { memoize, memoizeSync } from "../util/memoize.ts";
10
- import { detached, ensure, singleFlight } from "../util/neverthrow.ts";
10
+ import { memoize } from "../util/memoize.ts";
11
+ import {
12
+ detached,
13
+ ensure,
14
+ fetchJSON,
15
+ HTTPError,
16
+ singleFlight,
17
+ } from "../util/neverthrow.ts";
11
18
  import { createXdgAppPaths } from "../util/xdg-paths.ts";
12
19
 
13
20
  const CLIENT_ID = "54d11594-84e4-41aa-b438-e81b8fa78ee7";
14
21
  const REDIRECT_URI = "http://localhost:8976/oauth/callback";
15
- const ALCHEMY_BASE_URL = "https://alchemy.run";
16
22
  export const DEFAULT_SCOPES = [
17
23
  "account:read",
18
24
  "user:read",
@@ -32,6 +38,7 @@ export const DEFAULT_SCOPES = [
32
38
  "containers:write",
33
39
  "cloudchamber:write",
34
40
  ];
41
+ const ALCHEMY_BASE_URL = "https://alchemy.run";
35
42
 
36
43
  interface WranglerConfig {
37
44
  oauth_token: string;
@@ -40,6 +47,28 @@ interface WranglerConfig {
40
47
  scopes: string[];
41
48
  }
42
49
 
50
+ let cached: WranglerConfig | undefined;
51
+
52
+ export const getRefreshedWranglerConfig = singleFlight(() =>
53
+ readWranglerConfig()
54
+ .andThen((config) => {
55
+ if (config.expiration_time.getTime() > Date.now() + 10 * 1000) {
56
+ return ok(config);
57
+ }
58
+ return fetchToken({
59
+ grant_type: "refresh_token",
60
+ refresh_token: config.refresh_token,
61
+ client_id: CLIENT_ID,
62
+ });
63
+ })
64
+ .orElse((error) => {
65
+ if (isInteractive()) {
66
+ return wranglerLogin();
67
+ }
68
+ return err(error);
69
+ }),
70
+ );
71
+
43
72
  const getWranglerConfigPath = memoize(async () => {
44
73
  const xdgConfigDir = createXdgAppPaths(".wrangler").config();
45
74
  const legacyConfigDir = path.join(os.homedir(), ".wrangler");
@@ -53,35 +82,31 @@ const getWranglerConfigPath = memoize(async () => {
53
82
  });
54
83
 
55
84
  const readWranglerConfig = () => {
56
- return ResultAsync.fromSafePromise(getWranglerConfigPath())
57
- .andThen((path) =>
58
- ResultAsync.fromPromise(
59
- fs.readFile(path, "utf-8").then(async (text) => {
60
- const toml = await import("@iarna/toml");
61
- return toml.parse(text.replace(/\r\n/g, "\n"));
62
- }),
63
- () => new Error("Failed to read Wrangler config."),
64
- ),
65
- )
66
- .andThen((config) => {
67
- if (
68
- typeof config.oauth_token !== "string" ||
69
- typeof config.refresh_token !== "string" ||
70
- !config.expiration_time ||
71
- !Array.isArray(config.scopes)
72
- ) {
73
- return err(new Error("Invalid Wrangler config."));
74
- }
75
- return ok({
85
+ if (cached) {
86
+ return okAsync(cached);
87
+ }
88
+ return ResultAsync.fromPromise(
89
+ getWranglerConfigPath().then(async (path): Promise<WranglerConfig> => {
90
+ const text = await fs.readFile(path, "utf-8");
91
+ const toml = await import("@iarna/toml");
92
+ const config = toml.parse(text.replace(/\r\n/g, "\n"));
93
+ assert(typeof config.oauth_token === "string");
94
+ assert(typeof config.refresh_token === "string");
95
+ assert(config.expiration_time instanceof Date);
96
+ assert(Array.isArray(config.scopes));
97
+ return {
76
98
  oauth_token: config.oauth_token,
77
99
  refresh_token: config.refresh_token,
78
- expiration_time: new Date(config.expiration_time as any),
79
- scopes: Array.from(config.scopes as string[]),
80
- } as WranglerConfig);
81
- });
100
+ expiration_time: new Date(config.expiration_time),
101
+ scopes: config.scopes as string[],
102
+ };
103
+ }),
104
+ () => new Error("Cloudflare credentials are missing or invalid."),
105
+ );
82
106
  };
83
107
 
84
108
  const writeWranglerConfig = (config: WranglerConfig) => {
109
+ cached = config;
85
110
  return ResultAsync.fromSafePromise(getWranglerConfigPath()).map(
86
111
  async (configPath) => {
87
112
  const toml = await import("@iarna/toml");
@@ -98,140 +123,6 @@ const writeWranglerConfig = (config: WranglerConfig) => {
98
123
  );
99
124
  };
100
125
 
101
- const fetchToken = (
102
- body:
103
- | {
104
- grant_type: "refresh_token";
105
- refresh_token: string;
106
- client_id: string;
107
- }
108
- | {
109
- grant_type: "authorization_code";
110
- code: string;
111
- code_verifier: string;
112
- client_id: string;
113
- redirect_uri: string;
114
- },
115
- ) => {
116
- return ResultAsync.fromPromise(
117
- fetch("https://dash.cloudflare.com/oauth2/token", {
118
- method: "POST",
119
- headers: {
120
- "Content-Type": "application/x-www-form-urlencoded",
121
- },
122
- body: new URLSearchParams(body),
123
- }),
124
- () =>
125
- new OAuthError({
126
- error: "fetch_error",
127
- error_description: "Failed to fetch OAuth token.",
128
- status_code: 0,
129
- }),
130
- )
131
- .andThen((res) =>
132
- ResultAsync.fromPromise(
133
- res.json(),
134
- () =>
135
- new OAuthError({
136
- error: "invalid_response",
137
- error_description: "The server returned an invalid response.",
138
- status_code: res.status,
139
- }),
140
- ).andThen((json) =>
141
- res.ok ? ok(json as OAuthTokens) : err(new OAuthError(json as any)),
142
- ),
143
- )
144
- .map(
145
- (tokens): WranglerConfig => ({
146
- oauth_token: tokens.access_token,
147
- refresh_token: tokens.refresh_token,
148
- expiration_time: new Date(Date.now() + tokens.expires_in * 1000),
149
- scopes: tokens.scope.split(" "),
150
- }),
151
- )
152
- .andTee((config) => writeWranglerConfig(config));
153
- };
154
-
155
- interface OAuthTokens {
156
- access_token: string;
157
- refresh_token: string;
158
- expires_in: number;
159
- scope: string;
160
- }
161
-
162
- export const getRefreshedWranglerConfig = singleFlight(
163
- memoizeSync(
164
- () => {
165
- return readWranglerConfig()
166
- .andThen((config) => {
167
- if (config.expiration_time.getTime() > Date.now() + 10 * 1000) {
168
- return ok(config);
169
- }
170
- return fetchToken({
171
- grant_type: "refresh_token",
172
- refresh_token: config.refresh_token,
173
- client_id: CLIENT_ID,
174
- });
175
- })
176
- .orElse((error) => {
177
- if (isInteractive()) {
178
- return wranglerLogin();
179
- }
180
- if (error instanceof OAuthError) {
181
- return err(error);
182
- }
183
- return ok(null);
184
- });
185
- },
186
- () => Math.floor(Date.now() / 5000).toString(),
187
- ),
188
- );
189
-
190
- const isInteractive = () => {
191
- return process.stdin.isTTY && process.stdout.isTTY && !process.env.CI;
192
- };
193
-
194
- const generateAuthorizationURL = (scopes: string[]) => {
195
- const state = crypto.randomBytes(32).toString("base64url");
196
- const verifier = crypto.randomBytes(96).toString("base64url");
197
- const challenge = crypto
198
- .createHash("sha256")
199
- .update(verifier)
200
- .digest("base64url");
201
- const url = new URL("https://dash.cloudflare.com/oauth2/auth");
202
- url.search = new URLSearchParams({
203
- response_type: "code",
204
- client_id: CLIENT_ID,
205
- redirect_uri: REDIRECT_URI,
206
- scope: [...scopes, "offline_access"].join(" "),
207
- state,
208
- code_challenge: challenge,
209
- code_challenge_method: "S256",
210
- }).toString();
211
- return { url: url.toString(), state, verifier };
212
- };
213
-
214
- class OAuthError extends Error {
215
- readonly error: string;
216
- readonly error_verbose?: string;
217
- readonly error_hint?: string;
218
- readonly status_code: number;
219
- constructor(params: {
220
- error: string;
221
- error_verbose?: string;
222
- error_description: string;
223
- error_hint?: string;
224
- status_code: number;
225
- }) {
226
- console.dir(params, { depth: null });
227
- super(params.error_description);
228
- this.error = params.error;
229
- this.error_verbose = params.error_verbose;
230
- this.error_hint = params.error_hint;
231
- this.status_code = params.status_code;
232
- }
233
- }
234
-
235
126
  export const wranglerLogin = (
236
127
  scopes: string[] = DEFAULT_SCOPES,
237
128
  log: (message: string) => void = console.log, // using console.log instead of logger.log to avoid bundling hell with CLI
@@ -249,6 +140,9 @@ export const wranglerLogin = (
249
140
  );
250
141
  open(challenge.url);
251
142
  const { result, ok, err } = detached<WranglerConfig, OAuthError>();
143
+ const renderResponse = async (type: "success" | "error") => {
144
+ return Response.redirect(`${ALCHEMY_BASE_URL}/auth/${type}`);
145
+ };
252
146
  const server = new HTTPServer({
253
147
  port: 8976,
254
148
  fetch: async (request) => {
@@ -268,7 +162,7 @@ export const wranglerLogin = (
268
162
  status_code: 400,
269
163
  }),
270
164
  );
271
- return Response.redirect(`${ALCHEMY_BASE_URL}/auth/error`);
165
+ return renderResponse("error");
272
166
  }
273
167
  if (!code || !state || state !== challenge.state) {
274
168
  err(
@@ -278,7 +172,7 @@ export const wranglerLogin = (
278
172
  status_code: 400,
279
173
  }),
280
174
  );
281
- return Response.redirect(`${ALCHEMY_BASE_URL}/auth/error`);
175
+ return renderResponse("error");
282
176
  }
283
177
  const tokens = await fetchToken({
284
178
  grant_type: "authorization_code",
@@ -289,10 +183,10 @@ export const wranglerLogin = (
289
183
  });
290
184
  if (tokens.isErr()) {
291
185
  err(tokens.error);
292
- return Response.redirect(`${ALCHEMY_BASE_URL}/auth/error`);
186
+ return renderResponse("error");
293
187
  }
294
188
  ok(tokens.value);
295
- return Response.redirect(`${ALCHEMY_BASE_URL}/auth/success`);
189
+ return renderResponse("success");
296
190
  },
297
191
  });
298
192
  const timeout = setTimeout(
@@ -307,8 +201,100 @@ export const wranglerLogin = (
307
201
  },
308
202
  1000 * 60 * 5,
309
203
  );
310
- return ensure(result, async () => {
204
+ return ensure(result, () => {
311
205
  clearTimeout(timeout);
312
- await server.stop();
206
+ void server.stop();
313
207
  });
314
208
  };
209
+
210
+ const generateAuthorizationURL = (scopes: string[]) => {
211
+ const state = crypto.randomBytes(32).toString("base64url");
212
+ const verifier = crypto.randomBytes(96).toString("base64url");
213
+ const challenge = crypto
214
+ .createHash("sha256")
215
+ .update(verifier)
216
+ .digest("base64url");
217
+ const url = new URL("https://dash.cloudflare.com/oauth2/auth");
218
+ url.search = new URLSearchParams({
219
+ response_type: "code",
220
+ client_id: CLIENT_ID,
221
+ redirect_uri: "http://localhost:8976/oauth/callback",
222
+ scope: [...scopes, "offline_access"].join(" "),
223
+ state,
224
+ code_challenge: challenge,
225
+ code_challenge_method: "S256",
226
+ }).toString();
227
+ return { url: url.toString(), state, verifier };
228
+ };
229
+
230
+ interface OAuthTokens {
231
+ access_token: string;
232
+ refresh_token: string;
233
+ expires_in: number;
234
+ scope: string;
235
+ }
236
+
237
+ interface OAuthErrorParams {
238
+ error: string;
239
+ error_description: string;
240
+ error_verbose?: string;
241
+ error_hint?: string;
242
+ status_code: number;
243
+ }
244
+
245
+ class OAuthError extends Error {
246
+ constructor(params: OAuthErrorParams) {
247
+ super(
248
+ `Cloudflare authentication failed with error ${params.error} (${params.status_code}): ${params.error_description}`,
249
+ );
250
+ }
251
+ }
252
+
253
+ const fetchToken = (
254
+ body:
255
+ | {
256
+ grant_type: "refresh_token";
257
+ refresh_token: string;
258
+ client_id: string;
259
+ }
260
+ | {
261
+ grant_type: "authorization_code";
262
+ code: string;
263
+ code_verifier: string;
264
+ client_id: string;
265
+ redirect_uri: string;
266
+ },
267
+ ) => {
268
+ return fetchJSON<OAuthTokens, OAuthErrorParams>(
269
+ "https://dash.cloudflare.com/oauth2/token",
270
+ {
271
+ method: "POST",
272
+ headers: {
273
+ "Content-Type": "application/x-www-form-urlencoded",
274
+ },
275
+ body: new URLSearchParams(body),
276
+ },
277
+ )
278
+ .map(
279
+ (tokens): WranglerConfig => ({
280
+ oauth_token: tokens.access_token,
281
+ refresh_token: tokens.refresh_token,
282
+ expiration_time: new Date(Date.now() + tokens.expires_in * 1000),
283
+ scopes: tokens.scope.split(" "),
284
+ }),
285
+ )
286
+ .mapErr((error) =>
287
+ error instanceof HTTPError
288
+ ? new OAuthError({
289
+ error: "http_error",
290
+ error_description: error.message,
291
+ status_code: error.status,
292
+ })
293
+ : new OAuthError(error),
294
+ )
295
+ .andTee((config) => writeWranglerConfig(config));
296
+ };
297
+
298
+ const isInteractive = () => {
299
+ return process.stdin.isTTY && process.stdout.isTTY && !process.env.CI;
300
+ };
@@ -1,7 +1,7 @@
1
1
  import type { Secret } from "../secret.ts";
2
2
  import { logger } from "../util/logger.ts";
3
3
  import { memoize } from "../util/memoize.ts";
4
- import { CloudflareApiError } from "./api-error.ts";
4
+ import { extractCloudflareResult } from "./api-response.ts";
5
5
  import {
6
6
  getCloudflareAuthHeaders,
7
7
  type CloudflareAuthOptions,
@@ -56,66 +56,48 @@ export interface CloudflareOrganization {
56
56
  roles: string[];
57
57
  }
58
58
 
59
- export const getCloudflareAccounts = memoize(
60
- async (options: CloudflareAuthOptions): Promise<CloudflareAccount[]> => {
59
+ export const getCloudflareAccountId = memoize(
60
+ async (options: CloudflareAuthOptions): Promise<string> => {
61
61
  const headers = await getCloudflareAuthHeaders(options);
62
- const accounts = await fetch(
63
- "https://api.cloudflare.com/client/v4/accounts",
64
- {
62
+ const accounts = await extractCloudflareResult<CloudflareAccount[]>(
63
+ "get accounts for authorized user",
64
+ fetch("https://api.cloudflare.com/client/v4/accounts", {
65
65
  headers,
66
- },
66
+ }),
67
67
  );
68
- if (accounts.ok) {
69
- return ((await accounts.json()) as any).result;
70
- } else {
71
- throw new CloudflareApiError(
72
- `Failed to get accounts for authorized user, please make sure you're authenticated (see: https://alchemy.run/guides/cloudflare/) or explicitly set the Cloudflare Account ID (see: https://alchemy.run/guides/cloudflare/#account-id)`,
73
- accounts,
68
+ if (!accounts[0]) {
69
+ throw new Error(
70
+ "No accounts found for authorized user. Please make sure you're authenticated (see: https://alchemy.run/guides/cloudflare/) or explicitly set the Cloudflare Account ID (see: https://alchemy.run/guides/cloudflare/#account-id)",
71
+ );
72
+ }
73
+ if (accounts.length > 1) {
74
+ logger.warnOnce(
75
+ [
76
+ "Multiple Cloudflare accounts found for authorized user:",
77
+ accounts.map((a, i) => `${i + 1}: ${a.name} (${a.id})`).join("\n"),
78
+ "The first account will be used by default. To use a different account, explicitly set the Cloudflare Account ID (see: https://alchemy.run/guides/cloudflare/#account-id)",
79
+ ].join("\n"),
74
80
  );
75
81
  }
82
+ return accounts[0].id;
76
83
  },
77
84
  );
78
85
 
79
86
  export const getUserEmailFromApiKey = memoize(
80
87
  async (apiKey: string): Promise<string> => {
81
- try {
82
- // Call the /user endpoint to get user information
83
- const response = await fetch(
84
- "https://api.cloudflare.com/client/v4/user",
85
- {
86
- headers: {
87
- "Content-Type": "application/json",
88
- "X-Auth-Key": apiKey,
89
- },
88
+ const result = await extractCloudflareResult<{
89
+ id: string;
90
+ name: string;
91
+ email: string;
92
+ }>(
93
+ "automatically discover email for API Key authentication",
94
+ fetch("https://api.cloudflare.com/client/v4/user", {
95
+ headers: {
96
+ "Content-Type": "application/json",
97
+ "X-Auth-Key": apiKey,
90
98
  },
91
- );
92
-
93
- if (!response.ok) {
94
- throw new Error(
95
- `Failed to get user information: ${response.status} ${response.statusText}`,
96
- );
97
- }
98
-
99
- const data = (await response.json()) as {
100
- success: boolean;
101
- result: {
102
- id: string;
103
- email: string;
104
- name: string;
105
- [key: string]: any;
106
- };
107
- };
108
-
109
- if (!data.success || !data.result || !data.result.email) {
110
- throw new Error("Cloudflare API did not return valid user information");
111
- }
112
-
113
- return data.result.email;
114
- } catch (error) {
115
- logger.error("Error retrieving email from Cloudflare API:", error);
116
- throw new Error(
117
- "Failed to automatically discover email for API Key authentication",
118
- );
119
- }
99
+ }),
100
+ );
101
+ return result.email;
120
102
  },
121
103
  );
@@ -28,6 +28,7 @@ import { CloudflareApiError, handleApiError } from "./api-error.ts";
28
28
  import {
29
29
  type CloudflareApi,
30
30
  type CloudflareApiOptions,
31
+ type InternalCloudflareApiOptions,
31
32
  createCloudflareApi,
32
33
  } from "./api.ts";
33
34
  import type { Assets } from "./assets.ts";
@@ -88,6 +89,10 @@ import { WorkerSubdomain, disableWorkerSubdomain } from "./worker-subdomain.ts";
88
89
  import { createTail } from "./worker-tail.ts";
89
90
  import { Workflow, isWorkflow, upsertWorkflow } from "./workflow.ts";
90
91
 
92
+ // Previous versions of `Worker` used the `Bundle` resource.
93
+ // This import is here to avoid errors when destroying the `Bundle` resource.
94
+ import "../esbuild/bundle.ts";
95
+
91
96
  /**
92
97
  * Configuration options for static assets
93
98
  */
@@ -1487,12 +1492,12 @@ const normalizeExportBindings = (
1487
1492
  );
1488
1493
  };
1489
1494
 
1490
- const normalizeApiOptions = (api: CloudflareApi): CloudflareApiOptions => ({
1495
+ const normalizeApiOptions = (
1496
+ api: CloudflareApi,
1497
+ ): InternalCloudflareApiOptions => ({
1491
1498
  accountId: api.accountId,
1492
- apiKey: api.apiKey,
1493
- apiToken: api.apiToken,
1494
- email: api.email,
1495
1499
  baseUrl: api.baseUrl,
1500
+ ...api.authOptions,
1496
1501
  });
1497
1502
 
1498
1503
  async function provisionContainers(
@@ -24,23 +24,6 @@ export function memoize<F extends (...args: any[]) => Promise<any>>(
24
24
  };
25
25
  }
26
26
 
27
- export function memoizeSync<F extends (...args: any[]) => any>(
28
- fn: F,
29
- keyFn: (...args: Parameters<F>) => string = defaultKeyFn,
30
- ) {
31
- const cache = new Map<string, ReturnType<F>>();
32
- return (...args: Parameters<F>): ReturnType<F> => {
33
- const key = keyFn(...args);
34
- const cached = cache.get(key);
35
- if (cached) {
36
- return cached;
37
- }
38
- const result = fn(...args);
39
- cache.set(key, result);
40
- return result;
41
- };
42
- }
43
-
44
27
  export const defaultKeyFn = (...args: any[]) => {
45
28
  return createHash("sha256").update(JSON.stringify(args)).digest("hex");
46
29
  };
@@ -34,3 +34,31 @@ export const singleFlight = <Args extends any[], Value, Error>(
34
34
  });
35
35
  };
36
36
  };
37
+
38
+ export class HTTPError extends Error {
39
+ constructor(
40
+ message: string,
41
+ public readonly status: number,
42
+ ) {
43
+ super(message);
44
+ }
45
+ }
46
+
47
+ // TODO: merge this with safe-fetch?
48
+ export const fetchResult = (url: string, init: RequestInit = {}) => {
49
+ return ResultAsync.fromPromise(
50
+ fetch(url, init),
51
+ () => new HTTPError(`Failed to ${init.method ?? "GET"} ${url}`, 0),
52
+ );
53
+ };
54
+
55
+ export const fetchJSON = <T, E>(url: string, init: RequestInit = {}) => {
56
+ return fetchResult(url, init).andThen(decodeJSON<T, E>);
57
+ };
58
+
59
+ export const decodeJSON = <T, E>(response: Response) => {
60
+ return ResultAsync.fromPromise(
61
+ response.json(),
62
+ () => new HTTPError("Failed to decode JSON", response.status),
63
+ ).andThen((json) => (response.ok ? ok(json as T) : err(json as E)));
64
+ };
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth-wrangler.d.ts","sourceRoot":"","sources":["../../src/cloudflare/auth-wrangler.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,WAAW,EAAE,MAAM,YAAY,CAAC;AAclD,eAAO,MAAM,cAAc,UAkB1B,CAAC;AAEF,UAAU,cAAc;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAyHD,eAAO,MAAM,0BAA0B,sDA0BtC,CAAC;AA0BF,cAAM,UAAW,SAAQ,KAAK;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;gBACjB,MAAM,EAAE;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;KACrB;CAQF;AAED,eAAO,MAAM,aAAa,GACxB,SAAQ,MAAM,EAAmB,EACjC,MAAK,CAAC,OAAO,EAAE,MAAM,KAAK,IAAkB,4CA6E7C,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth-wrangler.js","sourceRoot":"","sources":["../../src/cloudflare/auth-wrangler.ts"],"names":[],"mappings":"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"}