@shivaedev/pr-watch 0.1.2 → 0.2.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.0 - 2026-10-25
4
+
5
+ ### Changed
6
+
7
+ - Send GitHub reads, queue-confirmation writes, conditional requests and Link pagination through effect-github. Keep polling slowdown and cooldown scheduling in the watcher, using shared resource observations and rate-limit retry instants. Permission failures retain the saved snapshot without imposing a quota cooldown.
8
+
9
+ ### Breaking
10
+
11
+ - Provide effect-github’s `GitHub.layer` and `GitHubToken.fromEnv` when composing `GitHubHttp.layer`. Remove `Options.token` and the token arguments to `argumentsFor`, `program` and `GitHubHttp` methods; configure authentication through `GitHubToken` instead. `GitHubHttp.get` and `post` return decoded bodies, and `list` collects paginated bodies. Replace `httpResponse` helpers and `quota.observeBudget`/`Budget` with effect-github; `pollDelay` now accepts its rate-limit observations and an optional retry instant.
12
+
3
13
  ## 0.1.2 - 2026-10-24
4
14
 
5
15
  ### Changed
package/README.md CHANGED
@@ -59,7 +59,7 @@ At a 60-second interval, for N open PRs, one page of checks per PR and one page
59
59
 
60
60
  These are request counts, not necessarily charged quota. With authentication, a successful ETag conditional request returning 304 costs zero primary rate-limit quota. Every REST endpoint sends `If-None-Match` after receiving an ETag and reuses its successful cached body on 304. Initial requests, changed responses and endpoints without ETags consume quota normally. Caches are in memory, so a restart makes fresh requests. Secondary limits still apply.
61
61
 
62
- The minimum interval doubles below 50% remaining quota, increases fivefold below 20% and tenfold below 10%. At low quota, the delay also spreads the observed round's request count over the remaining reset window. HTTP 403 and 429 trigger a cooldown of at least the supplied `Retry-After` (60 seconds when absent); exhausted primary quota waits until reset. No further request starts during a known cooldown.
62
+ The minimum interval doubles below 50% remaining quota, increases fivefold below 20% and tenfold below 10%. At low quota, the delay also spreads the observed round's request count over the remaining reset window. Rate-limited requests defer polling until effect-github’s `retryAt`, derived from `Retry-After` or the primary reset instant; exhausted primary quota waits until reset. Permission failures remain failed observations without a quota cooldown. No further request starts during a known cooldown.
63
63
 
64
64
  ### Restart and delivery limits
65
65
 
@@ -67,4 +67,4 @@ The state file records discovered open PR numbers and the last successfully comp
67
67
 
68
68
  Transitions that reverse between observations, including while the watcher is down, are not recovered. For example, leaving and rejoining the merge queue before the next observation produces no `dequeued` event. Stdout delivery is at-least-once across a crash: a crash after output but before the state replacement can repeat a line. There is no event history or acknowledged output protocol.
69
69
 
70
- The exported `StateFile.layer` requires Effect `FileSystem`, and `GitHubHttp.layer` requires Effect `HttpClient`. The CLI supplies `NodeFileSystem.layer` and a `FetchHttpClient` layer that refuses redirects. HTTP and file failures remain typed `WatchError` values.
70
+ The exported `StateFile.layer` requires Effect `FileSystem`. `GitHubHttp.layer` requires effect-github’s `GitHub` service, which owns authentication, conditional representations, Link pagination and rate-limit observations. Provide `GitHub.layer` with Effect `HttpClient` and `GitHubToken.fromEnv`; the token Layer reads `GH_TOKEN`, then `GITHUB_TOKEN`, and allows unauthenticated access when neither exists. Watcher `Options` contain polling and repository settings; authentication belongs to the Layer. The CLI supplies these Layers, `NodeFileSystem.layer` and a `FetchHttpClient` layer that refuses redirects. HTTP and file failures remain typed `WatchError` values.
@@ -1 +1 @@
1
- {"version":3,"file":"GitHub.d.ts","sourceRoot":"","sources":["../src/GitHub.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AAIxC,OAAO,EAAE,KAAK,OAAO,EAAiB,UAAU,EAAE,MAAM,YAAY,CAAC;AAkBrE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+EjB,CAAC"}
1
+ {"version":3,"file":"GitHub.d.ts","sourceRoot":"","sources":["../src/GitHub.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AAIxC,OAAO,EAAE,KAAK,OAAO,EAAiB,UAAU,EAAE,MAAM,YAAY,CAAC;AAkBrE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiEjB,CAAC"}
package/dist/GitHub.js CHANGED
@@ -27,21 +27,7 @@ export const GitHub = defineService({
27
27
  return Schema.decodeUnknownEffect(schema)(body).pipe(Effect.mapError(() => new WatchError({ message: "Invalid GitHub response" })));
28
28
  }
29
29
  function pages(options, path) {
30
- return Effect.gen(function* () {
31
- const bodies = [];
32
- const visited = new Set();
33
- let url = `${options.apiUrl}/repos/${options.repository}${path}`;
34
- while (url !== undefined) {
35
- if (visited.has(url)) {
36
- return yield* Effect.fail(new WatchError({ message: "Repeated pagination URL" }));
37
- }
38
- visited.add(url);
39
- const response = yield* http.get(url, options.token);
40
- bodies.push(response.body);
41
- url = response.next;
42
- }
43
- return bodies;
44
- });
30
+ return http.list(`${options.apiUrl}/repos/${options.repository}${path}`);
45
31
  }
46
32
  return {
47
33
  confirmQueue: (options, snapshot) => confirmQueue(http, options, snapshot),
@@ -60,8 +46,8 @@ export const GitHub = defineService({
60
46
  }));
61
47
  }),
62
48
  snapshot: (options, number, queued) => Effect.gen(function* () {
63
- const response = yield* http.get(`${options.apiUrl}/repos/${options.repository}/pulls/${number}`, options.token);
64
- const pr = yield* decode(Pull, response.body);
49
+ const response = yield* http.get(`${options.apiUrl}/repos/${options.repository}/pulls/${number}`);
50
+ const pr = yield* decode(Pull, response);
65
51
  if (pr.number !== number) {
66
52
  return yield* Effect.fail(new WatchError({ message: "GitHub returned the wrong PR" }));
67
53
  }
@@ -72,8 +58,8 @@ export const GitHub = defineService({
72
58
  if (pr.state === "open") {
73
59
  const bodies = yield* pages(options, `/commits/${pr.head.sha}/check-runs?per_page=100&filter=latest`);
74
60
  const checks = yield* Effect.forEach(bodies, (body) => decode(Checks, body));
75
- const statusResponse = yield* http.get(`${options.apiUrl}/repos/${options.repository}/commits/${pr.head.sha}/status`, options.token);
76
- const status = yield* decode(Status, statusResponse.body);
61
+ const statusResponse = yield* http.get(`${options.apiUrl}/repos/${options.repository}/commits/${pr.head.sha}/status`);
62
+ const status = yield* decode(Status, statusResponse);
77
63
  failed =
78
64
  checks.some((page) => page.checkRuns.some((check) => check.status === "completed" && failures.has(check.conclusion ?? "")))
79
65
  || ["failure", "error"].includes(status.state);
@@ -1 +1 @@
1
- {"version":3,"file":"GitHub.js","sourceRoot":"","sources":["../src/GitHub.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GitHub.js","sourceRoot":"","sources":["../src/GitHub.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,11 @@
1
1
  import { Effect } from "effect";
2
- import { HttpClient } from "effect/http";
3
- import { type CachedResponse } from "./httpResponse.ts";
4
2
  import { WatchError } from "./model.ts";
5
3
  export declare const GitHubHttp: import("effect/Context").Service<"@shivaedev/pr-watch/GitHubHttp", Readonly<{
6
4
  readonly delay: (interval: number) => Effect.Effect<number, never, never>;
7
- readonly get: (url: string, token: string) => Effect.Effect<CachedResponse, WatchError, never>;
8
- readonly post: (url: string, token: string, body: unknown) => Effect.Effect<CachedResponse, WatchError, never>;
5
+ readonly get: (url: string) => Effect.Effect<unknown, WatchError, never>;
6
+ readonly list: (url: string) => Effect.Effect<unknown[], WatchError, never>;
7
+ readonly post: (url: string, body: unknown) => Effect.Effect<unknown, WatchError, never>;
9
8
  }>> & {
10
- readonly layer: import("effect/Layer").Layer<"@shivaedev/pr-watch/GitHubHttp", never, HttpClient.HttpClient>;
9
+ readonly layer: import("effect/Layer").Layer<"@shivaedev/pr-watch/GitHubHttp", never, "@shivaedev/effect-github/GitHub">;
11
10
  };
12
11
  //# sourceMappingURL=GitHubHttp.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GitHubHttp.d.ts","sourceRoot":"","sources":["../src/GitHubHttp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,KAAK,cAAc,EAAiC,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,eAAO,MAAM,UAAU;;;;;;CAgDrB,CAAC"}
1
+ {"version":3,"file":"GitHubHttp.d.ts","sourceRoot":"","sources":["../src/GitHubHttp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,MAAM,EAAkB,MAAM,QAAQ,CAAC;AAIjE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGxC,eAAO,MAAM,UAAU;;;;;;;CAuDrB,CAAC"}
@@ -1,51 +1,48 @@
1
- import { Clock, Effect } from "effect";
2
- import { HttpClient } from "effect/http";
1
+ import { Clock, DateTime, Effect, Schema, Stream } from "effect";
2
+ import { GitHubRateLimited } from "@shivaedev/effect-github/errors.ts";
3
+ import { GitHub } from "@shivaedev/effect-github/GitHub.ts";
3
4
  import { defineService } from "@shivaedev/effect-service/defineService.ts";
4
- import { decodeResponse, fetchResponse } from "./httpResponse.js";
5
5
  import { WatchError } from "./model.js";
6
- import { observeBudget, pollDelay } from "./quota.js";
6
+ import { pollDelay, quotaRetryAt } from "./quota.js";
7
7
  export const GitHubHttp = defineService({
8
8
  id: "@shivaedev/pr-watch/GitHubHttp",
9
9
  initialize: Effect.gen(function* () {
10
- return {
11
- budget: { blockedUntil: 0, limit: 5000, remaining: 5000, reset: 0 },
12
- cache: new Map(),
13
- client: yield* HttpClient.HttpClient,
14
- requests: 0,
15
- };
10
+ return { github: yield* GitHub, requests: 0, retryAt: 0 };
16
11
  }),
17
12
  methods: (state) => {
18
- function request(url, token, body) {
13
+ function request(operation) {
19
14
  return Effect.gen(function* () {
20
15
  const now = yield* Clock.currentTimeMillis;
21
- if (state.budget.blockedUntil > now) {
22
- return yield* Effect.fail(new WatchError({ message: "GitHub quota cooldown" }));
23
- }
24
- const cached = body === undefined ? state.cache.get(url) : undefined;
25
- state.requests += 1;
26
- const response = yield* fetchResponse(state.client, url, token, cached, body);
27
- observeBudget(state.budget, response, yield* Clock.currentTimeMillis);
28
- if (response.status === 304 && cached !== undefined) {
29
- return cached;
16
+ const observations = yield* state.github.observations();
17
+ if (quotaRetryAt(observations, state.retryAt) > now) {
18
+ return yield* new WatchError({ message: "GitHub quota cooldown" });
30
19
  }
31
- const result = yield* decodeResponse(url, response);
32
- if (body === undefined) {
33
- state.cache.set(url, result);
20
+ return yield* operation;
21
+ }).pipe(Effect.scoped, Effect.timeout("30 seconds"), Effect.tapError((cause) => Effect.sync(() => {
22
+ if (cause instanceof GitHubRateLimited) {
23
+ state.retryAt = DateTime.toEpochMillis(cause.retryAt);
34
24
  }
35
- return result;
36
- }).pipe(Effect.scoped, Effect.timeout("30 seconds"), Effect.mapError((cause) => (cause instanceof WatchError ? cause : new WatchError({ message: cause.message }))));
25
+ })), Effect.mapError(() => new WatchError({ message: "GitHub request failed" })));
26
+ }
27
+ function counted(operation) {
28
+ return Effect.suspend(() => {
29
+ state.requests += 1;
30
+ return operation;
31
+ });
37
32
  }
38
33
  return {
39
34
  delay: (interval) => Effect.gen(function* () {
40
35
  const now = yield* Clock.currentTimeMillis;
41
- const delay = pollDelay(state.budget, interval, Math.max(1, state.requests), now);
36
+ const observations = yield* state.github.observations();
37
+ const delay = pollDelay(observations, interval, Math.max(1, state.requests), now, state.retryAt);
42
38
  state.requests = 0;
43
39
  return delay;
44
40
  }),
45
- get: (url, token) => request(url, token),
46
- post: (url, token, body) => request(url, token, body),
41
+ get: (url) => request(counted(state.github.read(url)).pipe(Effect.flatMap((response) => response.decode(Schema.Unknown)))),
42
+ list: (url) => request(Stream.unwrap(state.github.list(url)).pipe(Stream.mapEffect((response) => counted(response.decode(Schema.Unknown))), Stream.runCollect)),
43
+ post: (url, body) => request(counted(state.github.write("POST", url, body)).pipe(Effect.flatMap((response) => response.decode(Schema.Unknown)))),
47
44
  };
48
45
  },
49
- requires: [HttpClient.HttpClient],
46
+ requires: [GitHub],
50
47
  });
51
48
  //# sourceMappingURL=GitHubHttp.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"GitHubHttp.js","sourceRoot":"","sources":["../src/GitHubHttp.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GitHubHttp.js","sourceRoot":"","sources":["../src/GitHubHttp.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { Effect } from "effect";
2
2
  import { WatchError } from "./model.ts";
3
3
  export declare const help = "pr-watch --repo OWNER/REPO [--fleet | PR_NUMBER ...]\n --state PATH Snapshot file (default .pr-watch/OWNER-REPO.json)\n --interval SECONDS Poll interval (default 60; slows as quota falls)\n --once Poll once and exit\n --api-url URL GitHub REST base URL (default https://api.github.com)\n --help Show this help\nAuthentication: GH_TOKEN or GITHUB_TOKEN";
4
- export declare function argumentsFor(args: readonly string[], token: string): Effect.Effect<{
4
+ export declare function argumentsFor(args: readonly string[]): Effect.Effect<{
5
5
  help: true;
6
6
  once?: never;
7
7
  options?: never;
@@ -15,7 +15,6 @@ export declare function argumentsFor(args: readonly string[], token: string): Ef
15
15
  numbers: readonly number[];
16
16
  repository: string;
17
17
  stateFile: string;
18
- token: string;
19
18
  };
20
19
  }, WatchError, never>;
21
20
  //# sourceMappingURL=arguments.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"arguments.d.ts","sourceRoot":"","sources":["../src/arguments.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAgB,UAAU,EAAE,MAAM,YAAY,CAAC;AACtD,eAAO,MAAM,IAAI,4YAMwB,CAAC;AAC1C,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM;;;;;;;;;;;;;;;;sBA0ClE"}
1
+ {"version":3,"file":"arguments.d.ts","sourceRoot":"","sources":["../src/arguments.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAgB,UAAU,EAAE,MAAM,YAAY,CAAC;AACtD,eAAO,MAAM,IAAI,4YAMwB,CAAC;AAC1C,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE;;;;;;;;;;;;;;;sBAyCnD"}
package/dist/arguments.js CHANGED
@@ -8,7 +8,7 @@ export const help = `pr-watch --repo OWNER/REPO [--fleet | PR_NUMBER ...]
8
8
  --api-url URL GitHub REST base URL (default https://api.github.com)
9
9
  --help Show this help
10
10
  Authentication: GH_TOKEN or GITHUB_TOKEN`;
11
- export function argumentsFor(args, token) {
11
+ export function argumentsFor(args) {
12
12
  return Effect.try({
13
13
  catch: (cause) => new WatchError({ message: cause instanceof Error ? cause.message : "Invalid arguments" }),
14
14
  try: () => {
@@ -45,7 +45,6 @@ export function argumentsFor(args, token) {
45
45
  numbers,
46
46
  repository,
47
47
  stateFile: values.state ?? `.pr-watch/${repository.replace("/", "-")}.json`,
48
- token,
49
48
  },
50
49
  };
51
50
  },
@@ -1 +1 @@
1
- {"version":3,"file":"arguments.js","sourceRoot":"","sources":["../src/arguments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAgB,UAAU,EAAE,MAAM,YAAY,CAAC;AACtD,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;yCAMqB,CAAC;AAC1C,MAAM,UAAU,YAAY,CAAC,IAAuB,EAAE,KAAa;IAClE,OAAO,MAAM,CAAC,GAAG,CAAC;QACjB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC;QAC3G,GAAG,EAAE,GAAG,EAAE;YACT,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;gBACzC,gBAAgB,EAAE,IAAI;gBACtB,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;gBACf,OAAO,EAAE;oBACR,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBAC7B,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;oBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;oBACzB,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBAC5B,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;oBACzB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBACxB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;iBACzB;aACD,CAAC,CAAC;YACH,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;gBACjB,OAAO,EAAE,IAAI,EAAE,IAAa,EAAE,CAAC;YAChC,CAAC;YACD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrC,IAAI,UAAU,CAAC,KAAK,CAAC,qBAAqB,CAAC,KAAK,IAAI,EAAE,CAAC;gBACtD,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YAClD,CAAC;YACD,MAAM,OAAO,GAAG,UAAU,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC;YAC/D,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9C,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;YAC5C,OAAO;gBACN,IAAI,EAAE,KAAc;gBACpB,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,KAAK;gBAC1B,OAAO,EAAE;oBACR,MAAM;oBACN,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,KAAK;oBAC5B,QAAQ;oBACR,OAAO;oBACP,UAAU;oBACV,SAAS,EAAE,MAAM,CAAC,KAAK,IAAI,aAAa,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO;oBAC3E,KAAK;iBACa;aACnB,CAAC;QACH,CAAC;KACD,CAAC,CAAC;AACJ,CAAC;AACD,SAAS,UAAU,CAAC,WAA8B,EAAE,KAAc;IACjE,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACtD,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC;AACD,SAAS,WAAW,CAAC,KAAyB;IAC7C,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IAC5C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,IAAI,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,QAAQ,CAAC;AACjB,CAAC;AACD,SAAS,SAAS,CAAC,KAAyB;IAC3C,MAAM,MAAM,GAAG,CAAC,KAAK,IAAI,wBAAwB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACvE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IACzC,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxG,IAAI,CAAC,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QACrF,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"arguments.js","sourceRoot":"","sources":["../src/arguments.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -1,15 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import process from "node:process";
3
3
  import { NodeFileSystem } from "@effect/platform-node";
4
- import { Config, Effect, Layer } from "effect";
4
+ import { Effect, Layer } from "effect";
5
5
  import { FetchHttpClient } from "effect/http";
6
+ import { GitHub as GitHubClient } from "@shivaedev/effect-github/GitHub.ts";
7
+ import { GitHubToken } from "@shivaedev/effect-github/GitHubToken.ts";
6
8
  import { GitHub } from "./GitHub.js";
7
9
  import { GitHubHttp } from "./GitHubHttp.js";
8
10
  import { WatchError } from "./model.js";
9
11
  import { program } from "./program.js";
10
12
  import { StateFile } from "./StateFile.js";
11
13
  import { Watcher } from "./Watcher.js";
12
- const services = Watcher.layer.pipe(Layer.provide(Layer.mergeAll(StateFile.layer, GitHub.layer.pipe(Layer.provide(GitHubHttp.layer)))), Layer.provide(Layer.mergeAll(NodeFileSystem.layer, FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.RequestInit)({ redirect: "error" }))))));
14
+ const services = Watcher.layer.pipe(Layer.provide(Layer.mergeAll(StateFile.layer, GitHub.layer.pipe(Layer.provide(GitHubHttp.layer.pipe(Layer.provide(GitHubClient.layer), Layer.provide(GitHubToken.fromEnv)))))), Layer.provide(Layer.mergeAll(NodeFileSystem.layer, FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.RequestInit)({ redirect: "error" }))))));
13
15
  function write(stream) {
14
16
  return (line) => Effect.tryPromise({
15
17
  catch: () => new WatchError({ message: "Output stream failed" }),
@@ -20,10 +22,9 @@ const abort = new AbortController();
20
22
  process.once("SIGINT", () => abort.abort());
21
23
  process.once("SIGTERM", () => abort.abort());
22
24
  try {
23
- await Effect.runPromise(Effect.gen(function* () {
24
- const token = yield* Config.String("GH_TOKEN").pipe(Config.orElse(() => Config.String("GITHUB_TOKEN")), Config.withDefault(""));
25
- yield* program(process.argv.slice(2), token, write(process.stdout), write(process.stderr));
26
- }).pipe(Effect.provide(services)), { signal: abort.signal });
25
+ await Effect.runPromise(program(process.argv.slice(2), write(process.stdout), write(process.stderr)).pipe(Effect.provide(services)), {
26
+ signal: abort.signal,
27
+ });
27
28
  }
28
29
  catch (cause) {
29
30
  if (!abort.signal.aborted) {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -2,8 +2,9 @@ import { Effect } from "effect";
2
2
  import { type Options, WatchError } from "./model.ts";
3
3
  export declare const confirmQueue: (http: Readonly<{
4
4
  readonly delay: (interval: number) => Effect.Effect<number, never, never>;
5
- readonly get: (url: string, token: string) => Effect.Effect<import("./httpResponse.ts").CachedResponse, WatchError, never>;
6
- readonly post: (url: string, token: string, body: unknown) => Effect.Effect<import("./httpResponse.ts").CachedResponse, WatchError, never>;
5
+ readonly get: (url: string) => Effect.Effect<unknown, WatchError, never>;
6
+ readonly list: (url: string) => Effect.Effect<unknown[], WatchError, never>;
7
+ readonly post: (url: string, body: unknown) => Effect.Effect<unknown, WatchError, never>;
7
8
  }>, options: Options, snapshot: {
8
9
  readonly autoMerge: boolean;
9
10
  readonly branch: string;
@@ -1 +1 @@
1
- {"version":3,"file":"confirmQueue.d.ts","sourceRoot":"","sources":["../src/confirmQueue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAU,MAAM,QAAQ,CAAC;AAEtD,OAAO,EAAE,KAAK,OAAO,EAAiB,UAAU,EAAE,MAAM,YAAY,CAAC;AA6BrE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;qBAoBvB,CAAC"}
1
+ {"version":3,"file":"confirmQueue.d.ts","sourceRoot":"","sources":["../src/confirmQueue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAU,MAAM,QAAQ,CAAC;AAEtD,OAAO,EAAE,KAAK,OAAO,EAAiB,UAAU,EAAE,MAAM,YAAY,CAAC;AA6BrE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;qBAoBvB,CAAC"}
@@ -28,8 +28,8 @@ export const confirmQueue = Effect.fn("GitHub.confirmQueue")(function* (http, op
28
28
  url.pathname = `${url.pathname.replace(/\/$/u, "")}/graphql`;
29
29
  }
30
30
  const [owner, name] = options.repository.split("/");
31
- const response = yield* http.post(url.href, options.token, { query, variables: { name, number: snapshot.number, owner } });
32
- const body = yield* Schema.decodeUnknownEffect(QueueResponse)(response.body).pipe(Effect.mapError(() => new WatchError({ message: "Invalid GitHub queue confirmation" })));
31
+ const response = yield* http.post(url.href, { query, variables: { name, number: snapshot.number, owner } });
32
+ const body = yield* Schema.decodeUnknownEffect(QueueResponse)(response).pipe(Effect.mapError(() => new WatchError({ message: "Invalid GitHub queue confirmation" })));
33
33
  const pr = body.data?.repository?.pullRequest;
34
34
  if ((body.errors?.length ?? 0) > 0 || pr === undefined || pr === null || pr.state !== "OPEN") {
35
35
  return yield* Effect.fail(new WatchError({ message: `Queue confirmation unavailable for PR #${snapshot.number}` }));
@@ -1 +1 @@
1
- {"version":3,"file":"confirmQueue.js","sourceRoot":"","sources":["../src/confirmQueue.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"confirmQueue.js","sourceRoot":"","sources":["../src/confirmQueue.ts"],"names":[],"mappings":"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"}
package/dist/model.d.ts CHANGED
@@ -40,7 +40,6 @@ export interface Options {
40
40
  readonly numbers: readonly number[];
41
41
  readonly repository: string;
42
42
  readonly stateFile: string;
43
- readonly token: string;
44
43
  }
45
44
  export {};
46
45
  //# sourceMappingURL=model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;;;;AAChC,qBAAa,UAAW,SAAQ,eAE9B;CAAG;AACL,eAAO,MAAM,QAAQ;;;;;;;;;;EAUnB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAC;AAC5C,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;EAKhB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAC;AACtC,MAAM,WAAW,OAAO;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;;;;AAChC,qBAAa,UAAW,SAAQ,eAE9B;CAAG;AACL,eAAO,MAAM,QAAQ;;;;;;;;;;EAUnB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAC;AAC5C,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;EAKhB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAC;AACtC,MAAM,WAAW,OAAO;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B"}
package/dist/program.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { Effect } from "effect";
2
2
  import type { WatchError } from "./model.ts";
3
- export declare const program: (args: readonly string[], token: string, emit: (line: string) => Effect.Effect<void, WatchError>, diagnostic: (message: string) => Effect.Effect<void, WatchError>) => Effect.Effect<undefined, WatchError, "@shivaedev/pr-watch/Watcher">;
3
+ export declare const program: (args: readonly string[], emit: (line: string) => Effect.Effect<void, WatchError>, diagnostic: (message: string) => Effect.Effect<void, WatchError>) => Effect.Effect<undefined, WatchError, "@shivaedev/pr-watch/Watcher">;
4
4
  //# sourceMappingURL=program.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,OAAO,wDAGN,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,wBACjC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,wEAyB/D,CAAC"}
1
+ {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,OAAO,yCAEN,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,wBACjC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,wEAyB/D,CAAC"}
package/dist/program.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { Effect } from "effect";
2
2
  import { argumentsFor, help } from "./arguments.js";
3
3
  import { Watcher } from "./Watcher.js";
4
- export const program = Effect.fn("PrWatch.program")(function* (args, token, emit, diagnostic) {
5
- const parsed = yield* argumentsFor(args, token);
4
+ export const program = Effect.fn("PrWatch.program")(function* (args, emit, diagnostic) {
5
+ const parsed = yield* argumentsFor(args);
6
6
  if (parsed.help) {
7
7
  yield* emit(help);
8
8
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,QAAQ,CAAC,EAC5D,IAAuB,EACvB,KAAa,EACb,IAAuD,EACvD,UAAgE;IAEhE,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAChD,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,OAAO;IACR,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC;IAC/B,IAAI,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChD,OAAO,IAAI,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;QAC3F,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC/B,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC;QACxB,CAAC;aAAM,CAAC;YACP,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;gBACjB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC3C,CAAC;YACD,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAC1C,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YACjB,OAAO;QACR,CAAC;QACD,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpE,CAAC;AACF,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,QAAQ,CAAC,EAC5D,IAAuB,EACvB,IAAuD,EACvD,UAAgE;IAEhE,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,OAAO;IACR,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC;IAC/B,IAAI,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChD,OAAO,IAAI,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;QAC3F,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC/B,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC;QACxB,CAAC;aAAM,CAAC;YACP,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;gBACjB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC3C,CAAC;YACD,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAC1C,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YACjB,OAAO;QACR,CAAC;QACD,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpE,CAAC;AACF,CAAC,CAAC,CAAC"}
package/dist/quota.d.ts CHANGED
@@ -1,10 +1,4 @@
1
- import type { HttpClientResponse } from "effect/http";
2
- export interface Budget {
3
- blockedUntil: number;
4
- limit: number;
5
- remaining: number;
6
- reset: number;
7
- }
8
- export declare function observeBudget(budget: Budget, response: Pick<HttpClientResponse.HttpClientResponse, "headers" | "status">, now: number): void;
9
- export declare function pollDelay(budget: Budget, interval: number, requests: number, now: number): number;
1
+ import type { RateLimitObservation } from "@shivaedev/effect-github/rateLimits.ts";
2
+ export declare function quotaRetryAt(observations: readonly RateLimitObservation[], retryAt?: number): number;
3
+ export declare function pollDelay(observations: readonly RateLimitObservation[], interval: number, requests: number, now: number, retryAt?: number): number;
10
4
  //# sourceMappingURL=quota.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"quota.d.ts","sourceRoot":"","sources":["../src/quota.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,WAAW,MAAM;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACd;AAKD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,kBAAkB,CAAC,kBAAkB,EAAE,SAAS,GAAG,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAY5I;AACD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAKjG"}
1
+ {"version":3,"file":"quota.d.ts","sourceRoot":"","sources":["../src/quota.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAEnF,wBAAgB,YAAY,CAAC,YAAY,EAAE,SAAS,oBAAoB,EAAE,EAAE,OAAO,SAAI,GAAG,MAAM,CAE/F;AAED,wBAAgB,SAAS,CAAC,YAAY,EAAE,SAAS,oBAAoB,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,MAAM,CAW7I"}
package/dist/quota.js CHANGED
@@ -1,34 +1,14 @@
1
- function numeric(headers, name) {
2
- const value = headers[name];
3
- return value !== undefined && Number.isFinite(Number(value)) ? Number(value) : undefined;
1
+ import { DateTime } from "effect";
2
+ export function quotaRetryAt(observations, retryAt = 0) {
3
+ return Math.max(retryAt, ...observations.filter((budget) => budget.remaining === 0).map((budget) => DateTime.toEpochMillis(budget.reset)));
4
4
  }
5
- export function observeBudget(budget, response, now) {
6
- budget.remaining = numeric(response.headers, "x-ratelimit-remaining") ?? budget.remaining;
7
- budget.limit = numeric(response.headers, "x-ratelimit-limit") ?? budget.limit;
8
- budget.reset = (numeric(response.headers, "x-ratelimit-reset") ?? budget.reset / 1000) * 1000;
9
- if (response.status === 429 || response.status === 403) {
10
- const retry = response.headers["retry-after"] ?? null;
11
- const until = retryUntil(retry, now);
12
- budget.blockedUntil = Math.max(budget.blockedUntil, Number.isFinite(until) ? until : now + 60_000);
13
- }
14
- if (budget.remaining === 0) {
15
- budget.blockedUntil = Math.max(budget.blockedUntil, budget.reset);
16
- }
17
- }
18
- export function pollDelay(budget, interval, requests, now) {
19
- const ratio = budget.remaining / Math.max(1, budget.limit);
20
- const multiplier = slowdown(ratio);
21
- const paced = budget.remaining > 0 && ratio < 0.5 ? Math.ceil((Math.max(0, budget.reset - now) * requests) / budget.remaining) : 0;
22
- return Math.max(interval * multiplier, paced, budget.blockedUntil - now);
23
- }
24
- function retryUntil(retry, now) {
25
- if (retry === null) {
26
- return now + 60_000;
27
- }
28
- if (Number.isFinite(Number(retry))) {
29
- return now + Number(retry) * 1000;
30
- }
31
- return Date.parse(retry);
5
+ export function pollDelay(observations, interval, requests, now, retryAt = 0) {
6
+ return Math.max(interval, quotaRetryAt(observations, retryAt) - now, ...observations.map((budget) => {
7
+ const ratio = budget.remaining / Math.max(1, budget.limit);
8
+ const reset = DateTime.toEpochMillis(budget.reset);
9
+ const paced = budget.remaining > 0 && ratio < 0.5 ? Math.ceil((Math.max(0, reset - now) * requests) / budget.remaining) : 0;
10
+ return Math.max(interval * slowdown(ratio), paced);
11
+ }));
32
12
  }
33
13
  function slowdown(ratio) {
34
14
  if (ratio < 0.1) {
package/dist/quota.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"quota.js","sourceRoot":"","sources":["../src/quota.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"quota.js","sourceRoot":"","sources":["../src/quota.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAGlC,MAAM,UAAU,YAAY,CAAC,YAA6C,EAAE,OAAO,GAAG,CAAC;IACtF,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5I,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,YAA6C,EAAE,QAAgB,EAAE,QAAgB,EAAE,GAAW,EAAE,OAAO,GAAG,CAAC;IACpI,OAAO,IAAI,CAAC,GAAG,CACd,QAAQ,EACR,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,GAAG,GAAG,EACzC,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,GAAG,CAAC,IAAI,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5H,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IACpD,CAAC,CAAC,CACF,CAAC;AACH,CAAC;AACD,SAAS,QAAQ,CAAC,KAAa;IAC9B,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;QACjB,OAAO,EAAE,CAAC;IACX,CAAC;IACD,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;QACjB,OAAO,CAAC,CAAC;IACV,CAAC;IACD,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;QACjB,OAAO,CAAC,CAAC;IACV,CAAC;IACD,OAAO,CAAC,CAAC;AACV,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/pr-watch",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "One REST watcher for pull request transitions across a repository",
5
5
  "homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/pr-watch#readme",
6
6
  "bugs": {
@@ -43,15 +43,16 @@
43
43
  "README.md"
44
44
  ],
45
45
  "dependencies": {
46
+ "@shivaedev/effect-github": "0.2.0",
46
47
  "@shivaedev/effect-service": "0.4.1"
47
48
  },
48
49
  "devDependencies": {
49
50
  "@effect/platform-node": "4.0.5",
50
51
  "@effect/platform-node-shared": "4.0.5",
51
52
  "@effect/vitest": "4.0.5",
52
- "@shivaedev/effect-test": "0.7.2",
53
- "@shivaedev/quality": "0.34.0",
54
- "@shivaedev/test-story": "0.18.2",
53
+ "@shivaedev/effect-test": "0.8.1",
54
+ "@shivaedev/quality": "0.38.0",
55
+ "@shivaedev/test-story": "0.19.0",
55
56
  "@types/node": "24.19.2",
56
57
  "effect": "4.0.5",
57
58
  "typescript": "7.0.2",
package/src/GitHub.ts CHANGED
@@ -28,21 +28,7 @@ export const GitHub = defineService({
28
28
  return Schema.decodeUnknownEffect(schema)(body).pipe(Effect.mapError(() => new WatchError({ message: "Invalid GitHub response" })));
29
29
  }
30
30
  function pages(options: Options, path: string) {
31
- return Effect.gen(function* () {
32
- const bodies: unknown[] = [];
33
- const visited = new Set<string>();
34
- let url: string | undefined = `${options.apiUrl}/repos/${options.repository}${path}`;
35
- while (url !== undefined) {
36
- if (visited.has(url)) {
37
- return yield* Effect.fail(new WatchError({ message: "Repeated pagination URL" }));
38
- }
39
- visited.add(url);
40
- const response: Effect.Success<ReturnType<typeof http.get>> = yield* http.get(url, options.token);
41
- bodies.push(response.body);
42
- url = response.next;
43
- }
44
- return bodies;
45
- });
31
+ return http.list(`${options.apiUrl}/repos/${options.repository}${path}`);
46
32
  }
47
33
  return {
48
34
  confirmQueue: (options: Options, snapshot: Snapshot) => confirmQueue(http, options, snapshot),
@@ -66,8 +52,8 @@ export const GitHub = defineService({
66
52
  }),
67
53
  snapshot: (options: Options, number: number, queued: ReadonlySet<number>) =>
68
54
  Effect.gen(function* () {
69
- const response = yield* http.get(`${options.apiUrl}/repos/${options.repository}/pulls/${number}`, options.token);
70
- const pr = yield* decode(Pull, response.body);
55
+ const response = yield* http.get(`${options.apiUrl}/repos/${options.repository}/pulls/${number}`);
56
+ const pr = yield* decode(Pull, response);
71
57
  if (pr.number !== number) {
72
58
  return yield* Effect.fail(new WatchError({ message: "GitHub returned the wrong PR" }));
73
59
  }
@@ -78,8 +64,8 @@ export const GitHub = defineService({
78
64
  if (pr.state === "open") {
79
65
  const bodies = yield* pages(options, `/commits/${pr.head.sha}/check-runs?per_page=100&filter=latest`);
80
66
  const checks = yield* Effect.forEach(bodies, (body) => decode(Checks, body));
81
- const statusResponse = yield* http.get(`${options.apiUrl}/repos/${options.repository}/commits/${pr.head.sha}/status`, options.token);
82
- const status = yield* decode(Status, statusResponse.body);
67
+ const statusResponse = yield* http.get(`${options.apiUrl}/repos/${options.repository}/commits/${pr.head.sha}/status`);
68
+ const status = yield* decode(Status, statusResponse);
83
69
  failed =
84
70
  checks.some((page) => page.checkRuns.some((check) => check.status === "completed" && failures.has(check.conclusion ?? "")))
85
71
  || ["failure", "error"].includes(status.state);
package/src/GitHubHttp.ts CHANGED
@@ -1,55 +1,63 @@
1
- import { Clock, Effect } from "effect";
2
- import { HttpClient } from "effect/http";
1
+ import { Clock, DateTime, Effect, Schema, Stream } from "effect";
2
+ import { GitHubRateLimited } from "@shivaedev/effect-github/errors.ts";
3
+ import { GitHub } from "@shivaedev/effect-github/GitHub.ts";
3
4
  import { defineService } from "@shivaedev/effect-service/defineService.ts";
4
- import { type CachedResponse, decodeResponse, fetchResponse } from "./httpResponse.ts";
5
5
  import { WatchError } from "./model.ts";
6
- import { type Budget, observeBudget, pollDelay } from "./quota.ts";
6
+ import { pollDelay, quotaRetryAt } from "./quota.ts";
7
+
7
8
  export const GitHubHttp = defineService({
8
9
  id: "@shivaedev/pr-watch/GitHubHttp",
9
10
  initialize: Effect.gen(function* () {
10
- return {
11
- budget: { blockedUntil: 0, limit: 5000, remaining: 5000, reset: 0 } satisfies Budget,
12
- cache: new Map<string, CachedResponse>(),
13
- client: yield* HttpClient.HttpClient,
14
- requests: 0,
15
- };
11
+ return { github: yield* GitHub, requests: 0, retryAt: 0 };
16
12
  }),
17
13
  methods: (state) => {
18
- function request(url: string, token: string, body?: unknown) {
14
+ function request<T, E, R>(operation: Effect.Effect<T, E, R>) {
19
15
  return Effect.gen(function* () {
20
16
  const now = yield* Clock.currentTimeMillis;
21
- if (state.budget.blockedUntil > now) {
22
- return yield* Effect.fail(new WatchError({ message: "GitHub quota cooldown" }));
23
- }
24
- const cached = body === undefined ? state.cache.get(url) : undefined;
25
- state.requests += 1;
26
- const response = yield* fetchResponse(state.client, url, token, cached, body);
27
- observeBudget(state.budget, response, yield* Clock.currentTimeMillis);
28
- if (response.status === 304 && cached !== undefined) {
29
- return cached;
17
+ const observations = yield* state.github.observations();
18
+ if (quotaRetryAt(observations, state.retryAt) > now) {
19
+ return yield* new WatchError({ message: "GitHub quota cooldown" });
30
20
  }
31
- const result = yield* decodeResponse(url, response);
32
- if (body === undefined) {
33
- state.cache.set(url, result);
34
- }
35
- return result;
21
+ return yield* operation;
36
22
  }).pipe(
37
23
  Effect.scoped,
38
24
  Effect.timeout("30 seconds"),
39
- Effect.mapError((cause) => (cause instanceof WatchError ? cause : new WatchError({ message: cause.message }))),
25
+ Effect.tapError((cause) =>
26
+ Effect.sync(() => {
27
+ if (cause instanceof GitHubRateLimited) {
28
+ state.retryAt = DateTime.toEpochMillis(cause.retryAt);
29
+ }
30
+ }),
31
+ ),
32
+ Effect.mapError(() => new WatchError({ message: "GitHub request failed" })),
40
33
  );
41
34
  }
35
+ function counted<T, E, R>(operation: Effect.Effect<T, E, R>) {
36
+ return Effect.suspend(() => {
37
+ state.requests += 1;
38
+ return operation;
39
+ });
40
+ }
42
41
  return {
43
42
  delay: (interval: number) =>
44
43
  Effect.gen(function* () {
45
44
  const now = yield* Clock.currentTimeMillis;
46
- const delay = pollDelay(state.budget, interval, Math.max(1, state.requests), now);
45
+ const observations = yield* state.github.observations();
46
+ const delay = pollDelay(observations, interval, Math.max(1, state.requests), now, state.retryAt);
47
47
  state.requests = 0;
48
48
  return delay;
49
49
  }),
50
- get: (url: string, token: string) => request(url, token),
51
- post: (url: string, token: string, body: unknown) => request(url, token, body),
50
+ get: (url: string) => request(counted(state.github.read(url)).pipe(Effect.flatMap((response) => response.decode(Schema.Unknown)))),
51
+ list: (url: string) =>
52
+ request(
53
+ Stream.unwrap(state.github.list(url)).pipe(
54
+ Stream.mapEffect((response) => counted(response.decode(Schema.Unknown))),
55
+ Stream.runCollect,
56
+ ),
57
+ ),
58
+ post: (url: string, body: unknown) =>
59
+ request(counted(state.github.write("POST", url, body)).pipe(Effect.flatMap((response) => response.decode(Schema.Unknown)))),
52
60
  };
53
61
  },
54
- requires: [HttpClient.HttpClient],
62
+ requires: [GitHub],
55
63
  });
package/src/arguments.ts CHANGED
@@ -8,7 +8,7 @@ export const help = `pr-watch --repo OWNER/REPO [--fleet | PR_NUMBER ...]
8
8
  --api-url URL GitHub REST base URL (default https://api.github.com)
9
9
  --help Show this help
10
10
  Authentication: GH_TOKEN or GITHUB_TOKEN`;
11
- export function argumentsFor(args: readonly string[], token: string) {
11
+ export function argumentsFor(args: readonly string[]) {
12
12
  return Effect.try({
13
13
  catch: (cause) => new WatchError({ message: cause instanceof Error ? cause.message : "Invalid arguments" }),
14
14
  try: () => {
@@ -45,7 +45,6 @@ export function argumentsFor(args: readonly string[], token: string) {
45
45
  numbers,
46
46
  repository,
47
47
  stateFile: values.state ?? `.pr-watch/${repository.replace("/", "-")}.json`,
48
- token,
49
48
  } satisfies Options,
50
49
  };
51
50
  },
package/src/cli.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import process from "node:process";
3
3
  import { NodeFileSystem } from "@effect/platform-node";
4
- import { Config, Effect, Layer } from "effect";
4
+ import { Effect, Layer } from "effect";
5
5
  import { FetchHttpClient } from "effect/http";
6
+ import { GitHub as GitHubClient } from "@shivaedev/effect-github/GitHub.ts";
7
+ import { GitHubToken } from "@shivaedev/effect-github/GitHubToken.ts";
6
8
  import { GitHub } from "./GitHub.ts";
7
9
  import { GitHubHttp } from "./GitHubHttp.ts";
8
10
  import { WatchError } from "./model.ts";
@@ -11,7 +13,12 @@ import { StateFile } from "./StateFile.ts";
11
13
  import { Watcher } from "./Watcher.ts";
12
14
 
13
15
  const services = Watcher.layer.pipe(
14
- Layer.provide(Layer.mergeAll(StateFile.layer, GitHub.layer.pipe(Layer.provide(GitHubHttp.layer)))),
16
+ Layer.provide(
17
+ Layer.mergeAll(
18
+ StateFile.layer,
19
+ GitHub.layer.pipe(Layer.provide(GitHubHttp.layer.pipe(Layer.provide(GitHubClient.layer), Layer.provide(GitHubToken.fromEnv)))),
20
+ ),
21
+ ),
15
22
  Layer.provide(
16
23
  Layer.mergeAll(
17
24
  NodeFileSystem.layer,
@@ -30,16 +37,9 @@ const abort = new AbortController();
30
37
  process.once("SIGINT", () => abort.abort());
31
38
  process.once("SIGTERM", () => abort.abort());
32
39
  try {
33
- await Effect.runPromise(
34
- Effect.gen(function* () {
35
- const token = yield* Config.String("GH_TOKEN").pipe(
36
- Config.orElse(() => Config.String("GITHUB_TOKEN")),
37
- Config.withDefault(""),
38
- );
39
- yield* program(process.argv.slice(2), token, write(process.stdout), write(process.stderr));
40
- }).pipe(Effect.provide(services)),
41
- { signal: abort.signal },
42
- );
40
+ await Effect.runPromise(program(process.argv.slice(2), write(process.stdout), write(process.stderr)).pipe(Effect.provide(services)), {
41
+ signal: abort.signal,
42
+ });
43
43
  } catch (cause) {
44
44
  if (!abort.signal.aborted) {
45
45
  process.stderr.write(`${cause instanceof Error ? cause.message : "Watcher failed"}\n`);
@@ -40,8 +40,8 @@ export const confirmQueue = Effect.fn("GitHub.confirmQueue")(function* (
40
40
  url.pathname = `${url.pathname.replace(/\/$/u, "")}/graphql`;
41
41
  }
42
42
  const [owner, name] = options.repository.split("/");
43
- const response = yield* http.post(url.href, options.token, { query, variables: { name, number: snapshot.number, owner } });
44
- const body = yield* Schema.decodeUnknownEffect(QueueResponse)(response.body).pipe(
43
+ const response = yield* http.post(url.href, { query, variables: { name, number: snapshot.number, owner } });
44
+ const body = yield* Schema.decodeUnknownEffect(QueueResponse)(response).pipe(
45
45
  Effect.mapError(() => new WatchError({ message: "Invalid GitHub queue confirmation" })),
46
46
  );
47
47
  const pr = body.data?.repository?.pullRequest;
package/src/model.ts CHANGED
@@ -28,5 +28,4 @@ export interface Options {
28
28
  readonly numbers: readonly number[];
29
29
  readonly repository: string;
30
30
  readonly stateFile: string;
31
- readonly token: string;
32
31
  }
package/src/program.ts CHANGED
@@ -4,11 +4,10 @@ import type { WatchError } from "./model.ts";
4
4
  import { Watcher } from "./Watcher.ts";
5
5
  export const program = Effect.fn("PrWatch.program")(function* (
6
6
  args: readonly string[],
7
- token: string,
8
7
  emit: (line: string) => Effect.Effect<void, WatchError>,
9
8
  diagnostic: (message: string) => Effect.Effect<void, WatchError>,
10
9
  ) {
11
- const parsed = yield* argumentsFor(args, token);
10
+ const parsed = yield* argumentsFor(args);
12
11
  if (parsed.help) {
13
12
  yield* emit(help);
14
13
  return;
package/src/quota.ts CHANGED
@@ -1,42 +1,21 @@
1
- import type { HttpClientResponse } from "effect/http";
1
+ import { DateTime } from "effect";
2
+ import type { RateLimitObservation } from "@shivaedev/effect-github/rateLimits.ts";
2
3
 
3
- export interface Budget {
4
- blockedUntil: number;
5
- limit: number;
6
- remaining: number;
7
- reset: number;
4
+ export function quotaRetryAt(observations: readonly RateLimitObservation[], retryAt = 0): number {
5
+ return Math.max(retryAt, ...observations.filter((budget) => budget.remaining === 0).map((budget) => DateTime.toEpochMillis(budget.reset)));
8
6
  }
9
- function numeric(headers: Readonly<Record<string, string>>, name: string): number | undefined {
10
- const value = headers[name];
11
- return value !== undefined && Number.isFinite(Number(value)) ? Number(value) : undefined;
12
- }
13
- export function observeBudget(budget: Budget, response: Pick<HttpClientResponse.HttpClientResponse, "headers" | "status">, now: number): void {
14
- budget.remaining = numeric(response.headers, "x-ratelimit-remaining") ?? budget.remaining;
15
- budget.limit = numeric(response.headers, "x-ratelimit-limit") ?? budget.limit;
16
- budget.reset = (numeric(response.headers, "x-ratelimit-reset") ?? budget.reset / 1000) * 1000;
17
- if (response.status === 429 || response.status === 403) {
18
- const retry = response.headers["retry-after"] ?? null;
19
- const until = retryUntil(retry, now);
20
- budget.blockedUntil = Math.max(budget.blockedUntil, Number.isFinite(until) ? until : now + 60_000);
21
- }
22
- if (budget.remaining === 0) {
23
- budget.blockedUntil = Math.max(budget.blockedUntil, budget.reset);
24
- }
25
- }
26
- export function pollDelay(budget: Budget, interval: number, requests: number, now: number): number {
27
- const ratio = budget.remaining / Math.max(1, budget.limit);
28
- const multiplier = slowdown(ratio);
29
- const paced = budget.remaining > 0 && ratio < 0.5 ? Math.ceil((Math.max(0, budget.reset - now) * requests) / budget.remaining) : 0;
30
- return Math.max(interval * multiplier, paced, budget.blockedUntil - now);
31
- }
32
- function retryUntil(retry: string | null, now: number): number {
33
- if (retry === null) {
34
- return now + 60_000;
35
- }
36
- if (Number.isFinite(Number(retry))) {
37
- return now + Number(retry) * 1000;
38
- }
39
- return Date.parse(retry);
7
+
8
+ export function pollDelay(observations: readonly RateLimitObservation[], interval: number, requests: number, now: number, retryAt = 0): number {
9
+ return Math.max(
10
+ interval,
11
+ quotaRetryAt(observations, retryAt) - now,
12
+ ...observations.map((budget) => {
13
+ const ratio = budget.remaining / Math.max(1, budget.limit);
14
+ const reset = DateTime.toEpochMillis(budget.reset);
15
+ const paced = budget.remaining > 0 && ratio < 0.5 ? Math.ceil((Math.max(0, reset - now) * requests) / budget.remaining) : 0;
16
+ return Math.max(interval * slowdown(ratio), paced);
17
+ }),
18
+ );
40
19
  }
41
20
  function slowdown(ratio: number): number {
42
21
  if (ratio < 0.1) {
@@ -1,15 +0,0 @@
1
- import { Effect } from "effect";
2
- import { type HttpClient, type HttpClientResponse } from "effect/http";
3
- import { WatchError } from "./model.ts";
4
- export interface CachedResponse {
5
- readonly body: unknown;
6
- readonly etag: string | null;
7
- readonly next: string | undefined;
8
- }
9
- export declare function fetchResponse(client: HttpClient.HttpClient, url: string, token: string, cached: CachedResponse | undefined, body?: unknown): Effect.Effect<HttpClientResponse.HttpClientResponse, import("effect/http/HttpBody").HttpBodyError | import("effect/http/HttpClientError").HttpClientError, never>;
10
- export declare function decodeResponse(url: string, response: HttpClientResponse.HttpClientResponse): Effect.Effect<{
11
- body: import("effect/Schema").Json;
12
- etag: string | null;
13
- next: string | undefined;
14
- }, WatchError, never>;
15
- //# sourceMappingURL=httpResponse.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"httpResponse.d.ts","sourceRoot":"","sources":["../src/httpResponse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,KAAK,UAAU,EAAqB,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC1F,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AACD,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,SAAS,EAAE,IAAI,CAAC,EAAE,OAAO,qKAW1I;AACD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,CAAC,kBAAkB;;;;sBAgB1F"}
@@ -1,31 +0,0 @@
1
- import { Effect } from "effect";
2
- import { HttpClientRequest } from "effect/http";
3
- import { WatchError } from "./model.js";
4
- export function fetchResponse(client, url, token, cached, body) {
5
- const headers = { Accept: "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28" };
6
- if (token) {
7
- headers.Authorization = `Bearer ${token}`;
8
- }
9
- if (cached?.etag) {
10
- headers["If-None-Match"] = cached.etag;
11
- }
12
- return body === undefined
13
- ? client.get(url, { headers })
14
- : HttpClientRequest.post(url, { headers }).pipe(HttpClientRequest.bodyJson(body), Effect.flatMap(client.execute));
15
- }
16
- export function decodeResponse(url, response) {
17
- return Effect.gen(function* () {
18
- if (response.status < 200 || response.status >= 300) {
19
- return yield* Effect.fail(new WatchError({ message: `GitHub HTTP ${response.status} for ${new URL(url).pathname}` }));
20
- }
21
- const body = yield* response.json;
22
- const next = response.headers.link?.match(/<(?<url>[^>]+)>; rel="next"/u)?.groups?.url;
23
- yield* Effect.try(() => {
24
- if (next !== undefined && new URL(next).origin !== new URL(url).origin) {
25
- throw new Error("Cross-origin pagination refused");
26
- }
27
- });
28
- return { body, etag: response.headers.etag ?? null, next };
29
- }).pipe(Effect.mapError((cause) => (cause instanceof WatchError ? cause : new WatchError({ message: "Invalid GitHub response or pagination URL" }))));
30
- }
31
- //# sourceMappingURL=httpResponse.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"httpResponse.js","sourceRoot":"","sources":["../src/httpResponse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAmB,iBAAiB,EAA2B,MAAM,aAAa,CAAC;AAC1F,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAMxC,MAAM,UAAU,aAAa,CAAC,MAA6B,EAAE,GAAW,EAAE,KAAa,EAAE,MAAkC,EAAE,IAAc;IAC1I,MAAM,OAAO,GAA2B,EAAE,MAAM,EAAE,6BAA6B,EAAE,sBAAsB,EAAE,YAAY,EAAE,CAAC;IACxH,IAAI,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,aAAa,GAAG,UAAU,KAAK,EAAE,CAAC;IAC3C,CAAC;IACD,IAAI,MAAM,EAAE,IAAI,EAAE,CAAC;QAClB,OAAO,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,KAAK,SAAS;QACxB,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC;QAC9B,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AACpH,CAAC;AACD,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,QAA+C;IAC1F,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC1B,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;YACrD,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,eAAe,QAAQ,CAAC,MAAM,QAAQ,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;QACvH,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAClC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,8BAA8B,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC;QACvF,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE;YACtB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;gBACxE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;YACpD,CAAC;QACF,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,EAAE,IAAI,EAA2B,CAAC;IACrF,CAAC,CAAC,CAAC,IAAI,CACN,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,YAAY,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,2CAA2C,EAAE,CAAC,CAAC,CAAC,CAC5I,CAAC;AACH,CAAC"}
@@ -1,37 +0,0 @@
1
- import { Effect } from "effect";
2
- import { type HttpClient, HttpClientRequest, type HttpClientResponse } from "effect/http";
3
- import { WatchError } from "./model.ts";
4
- export interface CachedResponse {
5
- readonly body: unknown;
6
- readonly etag: string | null;
7
- readonly next: string | undefined;
8
- }
9
- export function fetchResponse(client: HttpClient.HttpClient, url: string, token: string, cached: CachedResponse | undefined, body?: unknown) {
10
- const headers: Record<string, string> = { Accept: "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28" };
11
- if (token) {
12
- headers.Authorization = `Bearer ${token}`;
13
- }
14
- if (cached?.etag) {
15
- headers["If-None-Match"] = cached.etag;
16
- }
17
- return body === undefined
18
- ? client.get(url, { headers })
19
- : HttpClientRequest.post(url, { headers }).pipe(HttpClientRequest.bodyJson(body), Effect.flatMap(client.execute));
20
- }
21
- export function decodeResponse(url: string, response: HttpClientResponse.HttpClientResponse) {
22
- return Effect.gen(function* () {
23
- if (response.status < 200 || response.status >= 300) {
24
- return yield* Effect.fail(new WatchError({ message: `GitHub HTTP ${response.status} for ${new URL(url).pathname}` }));
25
- }
26
- const body = yield* response.json;
27
- const next = response.headers.link?.match(/<(?<url>[^>]+)>; rel="next"/u)?.groups?.url;
28
- yield* Effect.try(() => {
29
- if (next !== undefined && new URL(next).origin !== new URL(url).origin) {
30
- throw new Error("Cross-origin pagination refused");
31
- }
32
- });
33
- return { body, etag: response.headers.etag ?? null, next } satisfies CachedResponse;
34
- }).pipe(
35
- Effect.mapError((cause) => (cause instanceof WatchError ? cause : new WatchError({ message: "Invalid GitHub response or pagination URL" }))),
36
- );
37
- }