@shivaedev/pr-watch 0.1.1 → 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.
Files changed (45) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +3 -7
  3. package/dist/GitHub.d.ts.map +1 -1
  4. package/dist/GitHub.js +5 -19
  5. package/dist/GitHub.js.map +1 -1
  6. package/dist/GitHubHttp.d.ts +4 -5
  7. package/dist/GitHubHttp.d.ts.map +1 -1
  8. package/dist/GitHubHttp.js +26 -29
  9. package/dist/GitHubHttp.js.map +1 -1
  10. package/dist/arguments.d.ts +1 -2
  11. package/dist/arguments.d.ts.map +1 -1
  12. package/dist/arguments.js +1 -2
  13. package/dist/arguments.js.map +1 -1
  14. package/dist/cli.js +7 -6
  15. package/dist/cli.js.map +1 -1
  16. package/dist/confirmQueue.d.ts +3 -2
  17. package/dist/confirmQueue.d.ts.map +1 -1
  18. package/dist/confirmQueue.js +2 -2
  19. package/dist/confirmQueue.js.map +1 -1
  20. package/dist/model.d.ts +0 -1
  21. package/dist/model.d.ts.map +1 -1
  22. package/dist/program.d.ts +1 -1
  23. package/dist/program.d.ts.map +1 -1
  24. package/dist/program.js +2 -2
  25. package/dist/program.js.map +1 -1
  26. package/dist/quota.d.ts +3 -9
  27. package/dist/quota.d.ts.map +1 -1
  28. package/dist/quota.js +10 -30
  29. package/dist/quota.js.map +1 -1
  30. package/package.json +15 -16
  31. package/src/GitHub.ts +5 -19
  32. package/src/GitHubHttp.ts +38 -30
  33. package/src/arguments.ts +1 -2
  34. package/src/cli.ts +12 -12
  35. package/src/confirmQueue.ts +2 -2
  36. package/src/model.ts +0 -1
  37. package/src/program.ts +1 -2
  38. package/src/quota.ts +16 -37
  39. package/dist/httpResponse.d.ts +0 -15
  40. package/dist/httpResponse.d.ts.map +0 -1
  41. package/dist/httpResponse.js +0 -31
  42. package/dist/httpResponse.js.map +0 -1
  43. package/docs/north-star.md +0 -7
  44. package/docs/roadmap.md +0 -18
  45. package/src/httpResponse.ts +0 -37
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
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
+
13
+ ## 0.1.2 - 2026-10-24
14
+
15
+ ### Changed
16
+
17
+ - Require Effect and its companion packages at exactly 4.0.5. Generated applications use the same versions.
18
+
3
19
  ## 0.1.1 - 2026-10-18
4
20
 
5
21
  ### Fixed
package/README.md CHANGED
@@ -23,7 +23,7 @@ Each successful observation compares a PR with its saved snapshot. The first obs
23
23
  Install with Node 24 or later and the repository's Effect peer version:
24
24
 
25
25
  ```sh
26
- npm install @shivaedev/pr-watch effect@4.0.4 @effect/platform-node@4.0.4 @effect/platform-node-shared@4.0.4
26
+ npm install @shivaedev/pr-watch effect@4.0.5 @effect/platform-node@4.0.5 @effect/platform-node-shared@4.0.5
27
27
  export GH_TOKEN=YOUR_READ_ONLY_TOKEN
28
28
  pr-watch --repo acme/project 42 57 --state ./watch-state.json
29
29
  pr-watch --repo acme/project --fleet --interval 60 --state ./fleet-state.json
@@ -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,8 +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.
71
-
72
- ### Evidence
73
-
74
- Synthetic HTTP tests cover conditional 304 responses, all eight events, already-stuck PRs at startup, terminal pruning across restarts, queue entry with a cleared auto-merge request, confirmed queue drops and rebuilds, manual auto-merge disablement, native IO injection and typed failures, checks independent of PR ETags, fleet discovery and pagination, quota slowdown, failed requests, and clean restart comparison. A CLI subprocess test verifies that pending mergeability diagnostics stay on stderr while stdout contains JSON event lines. The packed consumer runs the installed executable against a synthetic server. These tests establish the REST and GraphQL handling and installed package behavior; they do not establish live GitHub or Monitor adoption.
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":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAA+B,UAAU,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;IAChI,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IAC/D,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;IACxC,cAAc,EAAE,MAAM,CAAC,MAAM;IAC7B,MAAM,EAAE,MAAM,CAAC,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC,GAAG;IAClB,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC,MAAM;CACpB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC;AAC3F,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAClD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;AACzD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AACjG,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;AACtH,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AACvD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,OAAO,CAAC,CAAC,CAAC;AAC/G,MAAM,CAAC,MAAM,MAAM,GAAG,aAAa,CAAC;IACnC,EAAE,EAAE,4BAA4B;IAChC,UAAU,EAAE,UAAU;IACtB,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;QACjB,SAAS,MAAM,CAA6B,MAAe,EAAE,IAAa;YACzE,OAAO,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC,CAAC,CAAC,CAAC;QACrI,CAAC;QACD,SAAS,KAAK,CAAC,OAAgB,EAAE,IAAY;YAC5C,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,UAAU,OAAO,CAAC,UAAU,GAAG,IAAI,EAAE,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO;YACN,YAAY,EAAE,CAAC,OAAgB,EAAE,QAAkB,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC;YAC7F,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,CAAC,OAAgB,EAAE,EAAE,CAC9B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;gBACnB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,gCAAgC,CAAC,CAAC;gBACvE,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC9F,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;YAC5C,CAAC,CAAC;YACH,KAAK,EAAE,CAAC,OAAgB,EAAE,EAAE,CAC3B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;gBACnB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,6CAA6C,CAAC,CAAC;gBACpF,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;gBACvF,OAAO,IAAI,GAAG,CACb,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE;oBAChC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,uBAAuB,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC;oBAClE,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;gBACrD,CAAC,CAAC,CACF,CAAC;YACH,CAAC,CAAC;YACH,QAAQ,EAAE,CAAC,OAAgB,EAAE,MAAc,EAAE,MAA2B,EAAE,EAAE,CAC3E,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;gBACnB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,UAAU,OAAO,CAAC,UAAU,UAAU,MAAM,EAAE,CAAC,CAAC;gBAClG,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;gBACzC,IAAI,EAAE,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;oBAC1B,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,8BAA8B,EAAE,CAAC,CAAC,CAAC;gBACxF,CAAC;gBACD,IAAI,EAAE,CAAC,KAAK,KAAK,MAAM,IAAI,CAAC,EAAE,CAAC,SAAS,KAAK,IAAI,IAAI,EAAE,CAAC,cAAc,KAAK,SAAS,CAAC,EAAE,CAAC;oBACvF,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,gCAAgC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;gBAClG,CAAC;gBACD,IAAI,MAAM,GAAG,KAAK,CAAC;gBACnB,IAAI,EAAE,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;oBACzB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,YAAY,EAAE,CAAC,IAAI,CAAC,GAAG,wCAAwC,CAAC,CAAC;oBACtG,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;oBAC7E,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,UAAU,OAAO,CAAC,UAAU,YAAY,EAAE,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;oBACtH,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;oBACrD,MAAM;wBACL,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,WAAW,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC;+BACxH,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACjD,CAAC;gBACD,OAAO;oBACN,SAAS,EAAE,EAAE,CAAC,SAAS,KAAK,IAAI;oBAChC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG;oBACnB,KAAK,EAAE,EAAE,CAAC,cAAc,KAAK,OAAO;oBACpC,MAAM;oBACN,MAAM,EAAE,EAAE,CAAC,MAAM;oBACjB,MAAM;oBACN,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;oBAC1B,KAAK,EAAE,EAAE,CAAC,KAAK;oBACf,KAAK,EAAE,EAAE,CAAC,KAAK;iBACI,CAAC;YACtB,CAAC,CAAC;SACH,CAAC;IACH,CAAC;IACD,QAAQ,EAAE,CAAC,UAAU,CAAC;CACtB,CAAC,CAAC"}
@@ -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":"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"}
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;IACnD,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;iBACzD;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"}
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.1",
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": {
@@ -39,30 +39,29 @@
39
39
  "!src/**/*.test.ts",
40
40
  "!src/**/*.spec.ts",
41
41
  "!src/**/test-support",
42
- "docs",
43
42
  "CHANGELOG.md",
44
43
  "README.md"
45
44
  ],
46
45
  "dependencies": {
47
- "@shivaedev/effect-service": "0.4.0"
46
+ "@shivaedev/effect-github": "0.2.0",
47
+ "@shivaedev/effect-service": "0.4.1"
48
48
  },
49
49
  "devDependencies": {
50
- "@effect/platform-node": "4.0.4",
51
- "@effect/platform-node-shared": "4.0.4",
52
- "@effect/vitest": "4.0.4",
53
- "@shivaedev/effect-test": "0.6.0",
54
- "@shivaedev/quality": "0.25.0",
55
- "@shivaedev/test-story": "0.7.1",
50
+ "@effect/platform-node": "4.0.5",
51
+ "@effect/platform-node-shared": "4.0.5",
52
+ "@effect/vitest": "4.0.5",
53
+ "@shivaedev/effect-test": "0.8.1",
54
+ "@shivaedev/quality": "0.38.0",
55
+ "@shivaedev/test-story": "0.19.0",
56
56
  "@types/node": "24.19.2",
57
- "@typescript/native": "npm:typescript@7.0.2",
58
- "effect": "4.0.4",
59
- "typescript": "npm:@typescript/typescript6@6.0.2",
60
- "vitest": "5.0.3"
57
+ "effect": "4.0.5",
58
+ "typescript": "7.0.2",
59
+ "vitest": "5.0.5"
61
60
  },
62
61
  "peerDependencies": {
63
- "@effect/platform-node": "4.0.4",
64
- "@effect/platform-node-shared": "4.0.4",
65
- "effect": "4.0.4"
62
+ "@effect/platform-node": "4.0.5",
63
+ "@effect/platform-node-shared": "4.0.5",
64
+ "effect": "4.0.5"
66
65
  },
67
66
  "engines": {
68
67
  "node": ">=24"
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,7 +0,0 @@
1
- # One process for pull request observations
2
-
3
- An orchestrator needs to see merges, conflicts, failed checks and merge queue drops across a repository. One REST watcher shares discovery and queue requests, uses conditional responses, and keeps successful snapshots across restarts.
4
-
5
- Evidence wins over speed. A failed or rate-limited request cannot stand in for a negative observation. Check runs and commit statuses belong to the observed head; queue discovery comes from the queue refs, and a suspected drop is confirmed against the PR’s own queue entry and auto-merge state. Native Effect services own composition and interruption.
6
-
7
- Durability means comparison between successful snapshots. It does not recover transitions that reversed between observations. Stdout is at-least-once across a crash. Event history, acknowledged delivery, PR changes and automated reactions belong outside this package.
package/docs/roadmap.md DELETED
@@ -1,18 +0,0 @@
1
- # Roadmap
2
-
3
- ## Built
4
-
5
- - A REST executable for explicit PRs or repository-wide fleet discovery, using effect-service services.
6
- - ETag response reuse, quota pacing, queue-ref observations and eight transition events, distinguishing queue entry from disabled auto-merge.
7
- - Startup events for already-stuck auto-merges, terminal PR pruning and GraphQL confirmation of suspected queue drops.
8
- - Native Effect filesystem and HTTP services with typed failures.
9
- - Atomic snapshot persistence and comparison across clean restarts.
10
- - Synthetic HTTP tests and packed executable consumer scenarios.
11
-
12
- ## Next
13
-
14
- Work Fleet checks and delivery integrations can consume the event lines. Application adoption needs its own evidence.
15
-
16
- ## Maintainer decisions
17
-
18
- No additional delivery protocol or event history is part of this package.
@@ -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
- }