@shivaedev/effect-github 0.0.0-stage → 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 (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +110 -2
  3. package/dist/GitHub.d.ts +25 -0
  4. package/dist/GitHub.d.ts.map +1 -0
  5. package/dist/GitHub.js +63 -0
  6. package/dist/GitHub.js.map +1 -0
  7. package/dist/GitHubConfig.d.ts +5 -0
  8. package/dist/GitHubConfig.d.ts.map +1 -0
  9. package/dist/GitHubConfig.js +5 -0
  10. package/dist/GitHubConfig.js.map +1 -0
  11. package/dist/GitHubToken.d.ts +9 -0
  12. package/dist/GitHubToken.d.ts.map +1 -0
  13. package/dist/GitHubToken.js +8 -0
  14. package/dist/GitHubToken.js.map +1 -0
  15. package/dist/cache.d.ts +12 -0
  16. package/dist/cache.d.ts.map +1 -0
  17. package/dist/cache.js +17 -0
  18. package/dist/cache.js.map +1 -0
  19. package/dist/errors.d.ts +23 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +18 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/githubApp.d.ts +14 -0
  24. package/dist/githubApp.d.ts.map +1 -0
  25. package/dist/githubApp.js +51 -0
  26. package/dist/githubApp.js.map +1 -0
  27. package/dist/json.d.ts +7 -0
  28. package/dist/json.d.ts.map +1 -0
  29. package/dist/json.js +14 -0
  30. package/dist/json.js.map +1 -0
  31. package/dist/rateLimits.d.ts +20 -0
  32. package/dist/rateLimits.d.ts.map +1 -0
  33. package/dist/rateLimits.js +43 -0
  34. package/dist/rateLimits.js.map +1 -0
  35. package/dist/requests.d.ts +9 -0
  36. package/dist/requests.d.ts.map +1 -0
  37. package/dist/requests.js +57 -0
  38. package/dist/requests.js.map +1 -0
  39. package/dist/status.d.ts +6 -0
  40. package/dist/status.d.ts.map +1 -0
  41. package/dist/status.js +33 -0
  42. package/dist/status.js.map +1 -0
  43. package/dist/verifyWebhook.d.ts +4 -0
  44. package/dist/verifyWebhook.d.ts.map +1 -0
  45. package/dist/verifyWebhook.js +14 -0
  46. package/dist/verifyWebhook.js.map +1 -0
  47. package/package.json +70 -3
  48. package/src/GitHub.ts +87 -0
  49. package/src/GitHubConfig.ts +5 -0
  50. package/src/GitHubToken.ts +18 -0
  51. package/src/cache.ts +25 -0
  52. package/src/errors.ts +17 -0
  53. package/src/githubApp.ts +66 -0
  54. package/src/json.ts +16 -0
  55. package/src/rateLimits.ts +56 -0
  56. package/src/requests.ts +68 -0
  57. package/src/status.ts +37 -0
  58. package/src/verifyWebhook.ts +19 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ShivaeDev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,111 @@
1
- # Temporary Holding Version
1
+ # @shivaedev/effect-github
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ GitHub integrations should share one client instead of repeating token headers, page loops and quota handling in every application. This package turns GitHub REST responses into Schema-decoded Effects and streams while keeping rate limits typed.
4
+
5
+ ## Read GitHub with less application code
6
+
7
+ Describe the response you need and read it. Unchanged responses reuse their decoded value after ETag revalidation; paged lists fetch as you consume them.
8
+
9
+ ```ts
10
+ import { Schema } from "effect";
11
+ import { read } from "@shivaedev/effect-github/GitHub.ts";
12
+
13
+ const Repository = Schema.Struct({ name: Schema.String });
14
+ const repository = read("/repos/acme/widgets", Repository);
15
+ ```
16
+
17
+ ## Using the client
18
+
19
+ `GitHub` is a native Context service declared with `defineService`. Its Layer owns the conditional response cache and resource observations. Provide an Effect `HttpClient` and a `GitHubToken` once, then use the Schema-aware `read`, `list` and `write` functions. Schema decoding services remain visible in their requirements.
20
+
21
+ ```ts
22
+ import { Effect, Layer, Schema, Stream } from "effect";
23
+ import { FetchHttpClient } from "effect/http";
24
+ import { GitHub, list, read, write } from "@shivaedev/effect-github/GitHub.ts";
25
+ import { GitHubToken } from "@shivaedev/effect-github/GitHubToken.ts";
26
+
27
+ const github = GitHub.layer.pipe(
28
+ Layer.provide(FetchHttpClient.layer),
29
+ Layer.provide(GitHubToken.fromEnv),
30
+ );
31
+ const Issue = Schema.Struct({ number: Schema.Number, title: Schema.String });
32
+ const program = Effect.gen(function* () {
33
+ const issue = yield* read("/repos/acme/widgets/issues/1", Issue);
34
+ const first = yield* list("/repos/acme/widgets/issues", Issue).pipe(
35
+ Stream.take(1),
36
+ Stream.runCollect,
37
+ );
38
+ const created = yield* write("POST", "/repos/acme/widgets/issues", { title: "A new issue" }, Issue);
39
+ return { issue, first, created };
40
+ });
41
+
42
+ await Effect.runPromise(program.pipe(Effect.provide(github)));
43
+ ```
44
+
45
+ `GitHubToken.fromEnv` reads `GH_TOKEN`, then `GITHUB_TOKEN`, through Effect Config. If neither is set, requests are unauthenticated. To supply a token directly, provide `GitHubToken` with `Option.some(Redacted.make(token))`; use `Option.none()` for anonymous access. Requests send `Accept: application/vnd.github+json` and `X-GitHub-Api-Version: 2022-11-28`.
46
+
47
+ The default base URL is `https://api.github.com`. Provide `GitHubConfig` from `@shivaedev/effect-github/GitHubConfig.ts` with `{ apiUrl }` for another GitHub API endpoint.
48
+
49
+ `read(path, schema)` decodes a JSON response. `list(path, itemSchema)` returns a Stream of decoded items across GitHub's Link pages, and stops fetching when consumption stops. `write(method, path, body, schema)` sends JSON with `POST` or `PATCH` and decodes its response. JSON response bodies are bounded at 1 MiB. The conditional cache holds up to 1000 representations and keeps decoded values separate for each Schema.
50
+
51
+ For diffs and artifacts, obtain the service and call `text(path, accept, byteLimit)` or `bytes(path, accept, byteLimit)`. Both bound the body before returning it and use your chosen media type.
52
+
53
+ ```ts
54
+ const diff = Effect.gen(function* () {
55
+ const github = yield* GitHub;
56
+ return yield* github.text("/repos/acme/widgets/pulls/1", "application/vnd.github.diff", 256 * 1024);
57
+ });
58
+ ```
59
+
60
+ The service's `read(path)` and `write(method, path, body)` return a representation with a generic `decode(schema)` method. Its `list(path)` returns an Effect containing a Stream of page representations. Prefer the exported functions for Schema-decoded items. A caller with a pacing policy can pass `github.list(path, beforeRequest)`: the callback receives the resource name before each page request, and its typed failure stops the stream. `github.resource(path)` returns the observed resource for that path, defaulting to core or search before the first response.
61
+
62
+ ### Acting as a GitHub App
63
+
64
+ Provide `githubApp` as the `GitHubToken` Layer to authenticate the same client as an installation. Give it the App ID, a PEM private key wrapped in `Redacted`, and an installation ID. This uses Node's built-in crypto; no JWT or Octokit dependency is needed.
65
+
66
+ ```ts
67
+ import { Layer, Redacted } from "effect";
68
+ import { FetchHttpClient } from "effect/http";
69
+ import { GitHub } from "@shivaedev/effect-github/GitHub.ts";
70
+ import { githubApp } from "@shivaedev/effect-github/githubApp.ts";
71
+
72
+ const appClient = (privateKey: Redacted.Redacted<string>) => GitHub.layer.pipe(
73
+ Layer.provide(githubApp({ appId: "123456", privateKey, installationId: 7 })),
74
+ Layer.provide(FetchHttpClient.layer),
75
+ );
76
+ ```
77
+
78
+ Alternatively, pass `{ appId, privateKey, owner: "acme", repository: "widgets" }`. The Layer resolves the installation through `GET /repos/{owner}/{repo}/installation` before exchanging the App JWT for an installation token. The RS256 JWT carries the App ID as `iss`, `iat` 60 seconds before the current time, and `exp` ten minutes ahead.
79
+
80
+ `GitHubToken` accepts a static Option or a lazy Effect returning one; the client resolves it on each request. Code that reads the service directly must evaluate an Effect value before inspecting the Option, using `Effect.isEffect(value) ? yield* value : value`.
81
+
82
+ The token is fetched on the first request and reused until five minutes before `expires_at`, using Effect's Clock. Concurrent requests share the in-flight exchange, including at refresh. A rejected exchange fails with `GitHubAppError` from `errors.ts`; a 401 has `{ stage: "exchange", status: 401 }`. Signing failures have `stage: "sign"`. These errors and their logs and spans contain no private key, App JWT or installation token.
83
+
84
+ ### Verifying webhooks
85
+
86
+ Pass the raw request bytes and the `X-Hub-Signature-256` header to `verifyWebhook` before parsing the body. It checks HMAC SHA-256 with a constant-time comparison, then decodes JSON with your Schema. A missing header, tampered body or wrong secret fails with `GitHubWebhookSignatureError` before Schema decoding.
87
+
88
+ ```ts
89
+ import { Redacted, Schema } from "effect";
90
+ import { verifyWebhook } from "@shivaedev/effect-github/verifyWebhook.ts";
91
+
92
+ const WorkflowRun = Schema.Struct({
93
+ action: Schema.String,
94
+ workflowRun: Schema.Struct({ id: Schema.Number, conclusion: Schema.String }),
95
+ }).pipe(Schema.encodeKeys({ workflowRun: "workflow_run" }));
96
+ const receiveWorkflowRun = (
97
+ rawBody: Uint8Array,
98
+ signature: string | undefined,
99
+ secret: Redacted.Redacted<string>,
100
+ ) => verifyWebhook(rawBody, signature, secret, WorkflowRun);
101
+ ```
102
+
103
+ This decodes a signed `workflow_run` delivery with the fields the application needs. Keep the body bytes as received: parsing and reserializing JSON changes what was signed.
104
+
105
+ ### Rate limits and failures
106
+
107
+ `github.observations()` returns the latest `resource`, `limit`, `remaining`, `used` and UTC `reset` from response headers, including conditional and failed responses. Core and search budgets remain separate. A primary or secondary rate limit fails with `GitHubRateLimited` from `@shivaedev/effect-github/errors.ts`; its `retryAt` is a UTC `DateTime` usable directly by a job scheduler. Requests to a blocked resource fail locally until that instant. Each rate-limited failure records a log and span event with the request path and budget, excluding credentials and query strings.
108
+
109
+ HTTP status failures use platform's typed `RemoteNotFound`, `RemoteUnauthorized` and other errors from `@shivaedev/platform/http-client/errors.ts`. An oversized body fails with `ResponseBodyTooLarge`; invalid response data fails with `Schema.SchemaError`. Transport failures use `GitHubTransportError`, which contains only the request path.
110
+
111
+ Install with `pnpm add @shivaedev/effect-github effect`. Choose and provide an Effect HTTP client appropriate to your runtime. Scheduling, retries and application policy stay with the caller.
@@ -0,0 +1,25 @@
1
+ import { Effect, Schema, Stream } from "effect";
2
+ import { HttpClient } from "effect/http";
3
+ import type { ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
4
+ import { GitHubToken } from "./GitHubToken.ts";
5
+ export declare const GitHub: import("effect/Context").Service<"@shivaedev/effect-github/GitHub", Readonly<{
6
+ readonly bytes: (path: string, accept: string, limit: number) => Effect.Effect<Uint8Array<ArrayBufferLike>, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
7
+ readonly list: (path: string, beforeRequest?: ((resource: string) => Effect.Effect<void, ServiceUnavailable>) | undefined) => Effect.Effect<Stream.Stream<{
8
+ decode: <TSchema extends Schema.Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], Schema.SchemaError, TSchema["DecodingServices"]>;
9
+ }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/Cause").NoSuchElementError | import("@shivaedev/platform/http-client/errors.ts").PaginationLinkError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | ServiceUnavailable | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>, never, never>;
10
+ readonly observations: () => Effect.Effect<import("./rateLimits.ts").RateLimitObservation[], never, never>;
11
+ readonly read: (path: string) => Effect.Effect<{
12
+ decode: <TSchema extends Schema.Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], Schema.SchemaError, TSchema["DecodingServices"]>;
13
+ }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
14
+ readonly resource: (path: string) => Effect.Effect<string, never, never>;
15
+ readonly text: (path: string, accept: string, limit: number) => Effect.Effect<string, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
16
+ readonly write: (method: "PATCH" | "POST", path: string, body: unknown) => Effect.Effect<{
17
+ decode: <TSchema extends Schema.Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], Schema.SchemaError, TSchema["DecodingServices"]>;
18
+ }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
19
+ }>> & {
20
+ readonly layer: import("effect/Layer").Layer<"@shivaedev/effect-github/GitHub", never, GitHubToken | HttpClient.HttpClient>;
21
+ };
22
+ export declare function read<TSchema extends Schema.Constraint>(path: string, schema: TSchema): Effect.Effect<TSchema["Type"], import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, "@shivaedev/effect-github/GitHub" | TSchema["DecodingServices"]>;
23
+ export declare function list<TSchema extends Schema.Constraint>(path: string, schema: TSchema): Stream.Stream<TSchema["Type"], import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/Cause").NoSuchElementError | import("@shivaedev/platform/http-client/errors.ts").PaginationLinkError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | ServiceUnavailable | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, "@shivaedev/effect-github/GitHub" | TSchema["DecodingServices"]>;
24
+ export declare function write<TSchema extends Schema.Constraint>(method: "POST" | "PATCH", path: string, body: unknown, schema: TSchema): Effect.Effect<TSchema["Type"], import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, "@shivaedev/effect-github/GitHub" | TSchema["DecodingServices"]>;
25
+ //# sourceMappingURL=GitHub.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitHub.d.ts","sourceRoot":"","sources":["../src/GitHub.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,UAAU,EAA8C,MAAM,aAAa,CAAC;AAErF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAIjF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAK/C,eAAO,MAAM,MAAM;;8DAkBqD,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,kBAAkB,CAAC;;;;;;;;;;;;;;CAyCxH,CAAC;AAEH,wBAAgB,IAAI,CAAC,OAAO,SAAS,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,wYAEpF;AAED,wBAAgB,IAAI,CAAC,OAAO,SAAS,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,mhBAKpF;AAED,wBAAgB,KAAK,CAAC,OAAO,SAAS,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,ubAE9H"}
package/dist/GitHub.js ADDED
@@ -0,0 +1,63 @@
1
+ import { Effect, Schema, Stream } from "effect";
2
+ import { HttpClient, HttpClientRequest } from "effect/http";
3
+ import { defineService } from "@shivaedev/effect-service/defineService.ts";
4
+ import { paginate } from "@shivaedev/platform/http-client/paginate.ts";
5
+ import { GitHubConfig } from "./GitHubConfig.js";
6
+ import { GitHubToken } from "./GitHubToken.js";
7
+ import { jsonResponse } from "./json.js";
8
+ import { rateLimits } from "./rateLimits.js";
9
+ import { requests } from "./requests.js";
10
+ export const GitHub = defineService({
11
+ id: "@shivaedev/effect-github/GitHub",
12
+ initialize: Effect.gen(function* () {
13
+ const config = yield* GitHubConfig;
14
+ const rates = rateLimits();
15
+ return {
16
+ apiUrl: config.apiUrl,
17
+ rates,
18
+ request: requests(yield* HttpClient.HttpClient, yield* GitHubToken, rates),
19
+ };
20
+ }),
21
+ methods: ({ apiUrl, rates, request }) => {
22
+ function get(path, accept = "application/vnd.github+json") {
23
+ return HttpClientRequest.get(new URL(path, apiUrl).href, { headers: { Accept: accept } });
24
+ }
25
+ function readRepresentation(path) {
26
+ return Effect.map(request(get(path), 1024 * 1024), jsonResponse);
27
+ }
28
+ function listRepresentations(path, beforeRequest) {
29
+ const entries = new WeakMap();
30
+ function fetchPage(input) {
31
+ return (beforeRequest?.(rates.resource(new URL(input.url).pathname)) ?? Effect.void).pipe(Effect.andThen(request(input, 1024 * 1024)), Effect.map((entry) => {
32
+ entries.set(entry.response, entry);
33
+ return entry.response;
34
+ }));
35
+ }
36
+ const client = HttpClient.makeWith((effect) => Effect.flatMap(effect, fetchPage), Effect.succeed);
37
+ return Effect.succeed(paginate(client, get(path)).pipe(Stream.mapEffect((response) => Effect.fromNullishOr(entries.get(response))), Stream.map(jsonResponse)));
38
+ }
39
+ function writeRepresentation(method, path, body) {
40
+ return HttpClientRequest.make(method)(new URL(path, apiUrl).href, { headers: { Accept: "application/vnd.github+json" } }).pipe(HttpClientRequest.bodyJson(body), Effect.flatMap((input) => request(input, 1024 * 1024)), Effect.map(jsonResponse));
41
+ }
42
+ return {
43
+ bytes: (path, accept, limit) => Effect.map(request(get(path, accept), limit), (entry) => entry.bytes),
44
+ list: listRepresentations,
45
+ observations: () => Effect.sync(() => [...rates.observations.values()]),
46
+ read: readRepresentation,
47
+ resource: (path) => Effect.sync(() => rates.resource(new URL(path, apiUrl).pathname)),
48
+ text: (path, accept, limit) => Effect.map(request(get(path, accept), limit), (entry) => new TextDecoder().decode(entry.bytes)),
49
+ write: writeRepresentation,
50
+ };
51
+ },
52
+ requires: [HttpClient.HttpClient, GitHubToken],
53
+ });
54
+ export function read(path, schema) {
55
+ return Effect.flatMap(GitHub, (github) => Effect.flatMap(github.read(path), (response) => response.decode(schema)));
56
+ }
57
+ export function list(path, schema) {
58
+ return Stream.unwrap(Effect.flatMap(GitHub, (github) => github.list(path))).pipe(Stream.mapEffect((response) => response.decode(Schema.Array(schema))), Stream.flatMap(Stream.fromIterable));
59
+ }
60
+ export function write(method, path, body, schema) {
61
+ return Effect.flatMap(GitHub, (github) => Effect.flatMap(github.write(method, path, body), (response) => response.decode(schema)));
62
+ }
63
+ //# sourceMappingURL=GitHub.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitHub.js","sourceRoot":"","sources":["../src/GitHub.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Context } from "effect";
2
+ export declare const GitHubConfig: Context.Reference<{
3
+ readonly apiUrl: string;
4
+ }>;
5
+ //# sourceMappingURL=GitHubConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitHubConfig.d.ts","sourceRoot":"","sources":["../src/GitHubConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEjC,eAAO,MAAM,YAAY;qBAAwC,MAAM;EAErE,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Context } from "effect";
2
+ export const GitHubConfig = Context.Reference("@shivaedev/effect-github/GitHubConfig", {
3
+ defaultValue: () => ({ apiUrl: "https://api.github.com" }),
4
+ });
5
+ //# sourceMappingURL=GitHubConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitHubConfig.js","sourceRoot":"","sources":["../src/GitHubConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEjC,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,CAA8B,uCAAuC,EAAE;IACnH,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;CAC1D,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { Config, Context, Effect, Layer, type Option, type Redacted } from "effect";
2
+ import type { GitHubAppError } from "./errors.ts";
3
+ type Token = Option.Option<Redacted.Redacted<string>>;
4
+ declare const GitHubToken_base: Context.ServiceClass<GitHubToken, "@shivaedev/effect-github/GitHubToken", Effect.Effect<Token, GitHubAppError, never> | Token>;
5
+ export declare class GitHubToken extends GitHubToken_base {
6
+ static readonly fromEnv: Layer.Layer<GitHubToken, Config.ConfigError, never>;
7
+ }
8
+ export {};
9
+ //# sourceMappingURL=GitHubToken.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitHubToken.d.ts","sourceRoot":"","sources":["../src/GitHubToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,MAAM,EAAE,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,KAAK,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;;AAEtD,qBAAa,WAAY,SAAQ,gBAEhC;IACA,MAAM,CAAC,QAAQ,CAAC,OAAO,sDAQrB;CACF"}
@@ -0,0 +1,8 @@
1
+ import { Config, Context, Effect, Layer } from "effect";
2
+ export class GitHubToken extends Context.Service()("@shivaedev/effect-github/GitHubToken") {
3
+ static fromEnv = Layer.effect(GitHubToken)(Effect.gen(function* () {
4
+ const token = yield* Config.Redacted("GH_TOKEN").pipe(Config.orElse(() => Config.Redacted("GITHUB_TOKEN")), Config.option);
5
+ return token;
6
+ }));
7
+ }
8
+ //# sourceMappingURL=GitHubToken.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitHubToken.js","sourceRoot":"","sources":["../src/GitHubToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAA8B,MAAM,QAAQ,CAAC;AAKpF,MAAM,OAAO,WAAY,SAAQ,OAAO,CAAC,OAAO,EAA6D,CAC5G,sCAAsC,CACtC;IACA,MAAM,CAAU,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAClD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,CACpD,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,EACpD,MAAM,CAAC,MAAM,CACb,CAAC;QACF,OAAO,KAAK,CAAC;IACd,CAAC,CAAC,CACF,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ import type { Schema } from "effect";
2
+ import type { HttpClientResponse } from "effect/http";
3
+ export interface CachedResponse {
4
+ readonly bytes: Uint8Array;
5
+ readonly decoded: Map<Schema.Constraint, unknown>;
6
+ readonly response: HttpClientResponse.HttpClientResponse;
7
+ }
8
+ export declare function responseCache(): {
9
+ get: (key: string) => CachedResponse | undefined;
10
+ set(key: string, entry: CachedResponse): void;
11
+ };
12
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAClD,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC,kBAAkB,CAAC;CACzD;AAED,wBAAgB,aAAa;IAG3B,GAAG,QAAQ,MAAM;IACjB,GAAG,MAAM,MAAM,SAAS,cAAc;EAWvC"}
package/dist/cache.js ADDED
@@ -0,0 +1,17 @@
1
+ export function responseCache() {
2
+ const entries = new Map();
3
+ return {
4
+ get: (key) => entries.get(key),
5
+ set(key, entry) {
6
+ entries.delete(key);
7
+ entries.set(key, entry);
8
+ if (entries.size > 1000) {
9
+ const first = entries.keys().next();
10
+ if (!first.done) {
11
+ entries.delete(first.value);
12
+ }
13
+ }
14
+ },
15
+ };
16
+ }
17
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,aAAa;IAC5B,MAAM,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;IAClD,OAAO;QACN,GAAG,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;QACtC,GAAG,CAAC,GAAW,EAAE,KAAqB;YACrC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACxB,IAAI,OAAO,CAAC,IAAI,GAAG,IAAI,EAAE,CAAC;gBACzB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;gBACpC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;oBACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBAC7B,CAAC;YACF,CAAC;QACF,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { Schema } from "effect";
2
+ declare const GitHubRateLimited_base: Schema.Class<GitHubRateLimited, Schema.TaggedStruct<"GitHubRateLimited", {
3
+ readonly resource: Schema.String;
4
+ readonly retryAt: Schema.DateTimeUtc;
5
+ }>, import("effect/Cause").YieldableError>;
6
+ export declare class GitHubRateLimited extends GitHubRateLimited_base {
7
+ }
8
+ declare const GitHubTransportError_base: Schema.Class<GitHubTransportError, Schema.TaggedStruct<"GitHubTransportError", {
9
+ readonly path: Schema.String;
10
+ }>, import("effect/Cause").YieldableError>;
11
+ export declare class GitHubTransportError extends GitHubTransportError_base {
12
+ }
13
+ declare const GitHubAppError_base: Schema.Class<GitHubAppError, Schema.TaggedStruct<"GitHubAppError", {
14
+ readonly stage: Schema.Literals<readonly ["sign", "exchange"]>;
15
+ readonly status: Schema.optional<Schema.Number>;
16
+ }>, import("effect/Cause").YieldableError>;
17
+ export declare class GitHubAppError extends GitHubAppError_base {
18
+ }
19
+ declare const GitHubWebhookSignatureError_base: Schema.Class<GitHubWebhookSignatureError, Schema.TaggedStruct<"GitHubWebhookSignatureError", {}>, import("effect/Cause").YieldableError>;
20
+ export declare class GitHubWebhookSignatureError extends GitHubWebhookSignatureError_base {
21
+ }
22
+ export {};
23
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;;;;;AAEhC,qBAAa,iBAAkB,SAAQ,sBAGrC;CAAG;;;;AAEL,qBAAa,oBAAqB,SAAQ,yBAExC;CAAG;;;;;AAEL,qBAAa,cAAe,SAAQ,mBAGlC;CAAG;;AAEL,qBAAa,2BAA4B,SAAQ,gCAAoF;CAAG"}
package/dist/errors.js ADDED
@@ -0,0 +1,18 @@
1
+ import { Schema } from "effect";
2
+ export class GitHubRateLimited extends Schema.TaggedError()("GitHubRateLimited", {
3
+ resource: Schema.String,
4
+ retryAt: Schema.DateTimeUtc,
5
+ }) {
6
+ }
7
+ export class GitHubTransportError extends Schema.TaggedError()("GitHubTransportError", {
8
+ path: Schema.String,
9
+ }) {
10
+ }
11
+ export class GitHubAppError extends Schema.TaggedError()("GitHubAppError", {
12
+ stage: Schema.Literals(["sign", "exchange"]),
13
+ status: Schema.optional(Schema.Number),
14
+ }) {
15
+ }
16
+ export class GitHubWebhookSignatureError extends Schema.TaggedError()("GitHubWebhookSignatureError", {}) {
17
+ }
18
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,OAAO,iBAAkB,SAAQ,MAAM,CAAC,WAAW,EAAqB,CAAC,mBAAmB,EAAE;IACnG,QAAQ,EAAE,MAAM,CAAC,MAAM;IACvB,OAAO,EAAE,MAAM,CAAC,WAAW;CAC3B,CAAC;CAAG;AAEL,MAAM,OAAO,oBAAqB,SAAQ,MAAM,CAAC,WAAW,EAAwB,CAAC,sBAAsB,EAAE;IAC5G,IAAI,EAAE,MAAM,CAAC,MAAM;CACnB,CAAC;CAAG;AAEL,MAAM,OAAO,cAAe,SAAQ,MAAM,CAAC,WAAW,EAAkB,CAAC,gBAAgB,EAAE;IAC1F,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;CACtC,CAAC;CAAG;AAEL,MAAM,OAAO,2BAA4B,SAAQ,MAAM,CAAC,WAAW,EAA+B,CAAC,6BAA6B,EAAE,EAAE,CAAC;CAAG"}
@@ -0,0 +1,14 @@
1
+ import { Layer, Redacted } from "effect";
2
+ import { HttpClient } from "effect/http";
3
+ import { GitHubToken } from "./GitHubToken.ts";
4
+ export type GitHubAppOptions = {
5
+ readonly appId: string;
6
+ readonly privateKey: Redacted.Redacted<string>;
7
+ } & ({
8
+ readonly installationId: number;
9
+ } | {
10
+ readonly owner: string;
11
+ readonly repository: string;
12
+ });
13
+ export declare function githubApp(options: GitHubAppOptions): Layer.Layer<GitHubToken, never, HttpClient.HttpClient>;
14
+ //# sourceMappingURL=githubApp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"githubApp.d.ts","sourceRoot":"","sources":["../src/githubApp.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,KAAK,EAAU,QAAQ,EAAU,MAAM,QAAQ,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAqB,MAAM,aAAa,CAAC;AAI5D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,MAAM,MAAM,gBAAgB,GAAG;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC/C,GAAG,CAAC;IAAE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAOpG,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,0DA+BlD"}
@@ -0,0 +1,51 @@
1
+ import { sign } from "node:crypto";
2
+ import { Clock, Effect, Exit, Layer, Option, Redacted, Schema } from "effect";
3
+ import { HttpClient, HttpClientRequest } from "effect/http";
4
+ import { readBoundedJson } from "@shivaedev/platform/http-client/body.ts";
5
+ import { GitHubAppError } from "./errors.js";
6
+ import { GitHubConfig } from "./GitHubConfig.js";
7
+ import { GitHubToken } from "./GitHubToken.js";
8
+ const Installation = Schema.Struct({ id: Schema.Number });
9
+ const AccessToken = Schema.Struct({ expiresAt: Schema.DateFromString, token: Schema.RedactedFromValue(Schema.String) }).pipe(Schema.encodeKeys({ expiresAt: "expires_at" }));
10
+ export function githubApp(options) {
11
+ return Layer.effect(GitHubToken)(Effect.gen(function* () {
12
+ const client = yield* HttpClient.HttpClient;
13
+ const { apiUrl } = yield* GitHubConfig;
14
+ const clock = yield* Clock.Clock;
15
+ let installationId = "installationId" in options ? options.installationId : undefined;
16
+ const request = appRequests(client, apiUrl);
17
+ const exchange = Effect.gen(function* () {
18
+ const now = Math.floor((yield* Clock.currentTimeMillis) / 1000);
19
+ const jwt = yield* Effect.try({
20
+ catch: () => new GitHubAppError({ stage: "sign" }),
21
+ try: () => {
22
+ const header = Buffer.from(JSON.stringify({ alg: "RS256", typ: "JWT" })).toString("base64url");
23
+ const payload = Buffer.from(JSON.stringify({ exp: now + 600, iat: now - 60, iss: options.appId })).toString("base64url");
24
+ const input = `${header}.${payload}`;
25
+ return `${input}.${sign("RSA-SHA256", Buffer.from(input), Redacted.value(options.privateKey)).toString("base64url")}`;
26
+ },
27
+ });
28
+ if (installationId === undefined && "owner" in options) {
29
+ const path = `/repos/${encodeURIComponent(options.owner)}/${encodeURIComponent(options.repository)}/installation`;
30
+ installationId = (yield* request("GET", path, jwt, Installation)).id;
31
+ }
32
+ return yield* request("POST", `/app/installations/${installationId}/access_tokens`, jwt, AccessToken);
33
+ });
34
+ const cached = yield* Effect.cachedWithTTL(exchange, (exit) => Exit.isSuccess(exit) ? Math.max(0, exit.value.expiresAt.getTime() - clock.currentTimeMillisUnsafe() - 300_000) : 0);
35
+ return Effect.map(cached, ({ token }) => Option.some(token));
36
+ }));
37
+ }
38
+ function appRequests(client, apiUrl) {
39
+ return Effect.fnUntraced(function* (method, path, jwt, schema) {
40
+ const response = yield* client
41
+ .execute(HttpClientRequest.make(method)(new URL(path, apiUrl).href, {
42
+ headers: { Accept: "application/vnd.github+json", Authorization: `Bearer ${jwt}`, "X-GitHub-Api-Version": "2022-11-28" },
43
+ }))
44
+ .pipe(Effect.mapError(() => new GitHubAppError({ stage: "exchange" })));
45
+ if (response.status < 200 || response.status >= 300) {
46
+ return yield* new GitHubAppError({ stage: "exchange", status: response.status });
47
+ }
48
+ return yield* readBoundedJson(response, 64 * 1024, schema).pipe(Effect.mapError(() => new GitHubAppError({ stage: "exchange" })));
49
+ });
50
+ }
51
+ //# sourceMappingURL=githubApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"githubApp.js","sourceRoot":"","sources":["../src/githubApp.ts"],"names":[],"mappings":"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"}
package/dist/json.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { Effect, Schema } from "effect";
2
+ import type { CachedResponse } from "./cache.ts";
3
+ export declare const decodeJson: <TSchema extends Schema.Constraint>(entry: CachedResponse, schema: TSchema) => Effect.Effect<TSchema["Type"], Schema.SchemaError, TSchema["DecodingServices"]>;
4
+ export declare function jsonResponse(entry: CachedResponse): {
5
+ decode: <TSchema extends Schema.Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], Schema.SchemaError, TSchema["DecodingServices"]>;
6
+ };
7
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,eAAO,MAAM,UAAU,GAAgC,OAAO,SAAS,MAAM,CAAC,UAAU,4HAQtF,CAAC;AAEH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc;IACxC,MAAM,GAAG,OAAO,SAAS,MAAM,CAAC,UAAU,UAAU,OAAO;EACpE"}
package/dist/json.js ADDED
@@ -0,0 +1,14 @@
1
+ import { Effect, Schema } from "effect";
2
+ export const decodeJson = Effect.fnUntraced(function* (entry, schema) {
3
+ const cached = entry.decoded.get(schema);
4
+ if (entry.decoded.has(schema) && Schema.is(schema)(cached)) {
5
+ return cached;
6
+ }
7
+ const value = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(schema))(new TextDecoder().decode(entry.bytes));
8
+ entry.decoded.set(schema, value);
9
+ return value;
10
+ });
11
+ export function jsonResponse(entry) {
12
+ return { decode: (schema) => decodeJson(entry, schema) };
13
+ }
14
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGxC,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAqC,KAAqB,EAAE,MAAe;IAC/H,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5D,OAAO,MAAM,CAAC;IACf,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IACtH,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC;AACd,CAAC,CAAC,CAAC;AAEH,MAAM,UAAU,YAAY,CAAC,KAAqB;IACjD,OAAO,EAAE,MAAM,EAAE,CAAoC,MAAe,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;AACtG,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { DateTime, Effect } from "effect";
2
+ import type { HttpClientResponse } from "effect/http";
3
+ import type { GitHubRateLimited } from "./errors.ts";
4
+ export interface RateLimitObservation {
5
+ readonly limit: number;
6
+ readonly remaining: number;
7
+ readonly reset: DateTime.Utc;
8
+ readonly resource: string;
9
+ readonly used: number;
10
+ }
11
+ export declare function rateLimits(): {
12
+ blocked: Map<string, GitHubRateLimited>;
13
+ failures: Map<string, number>;
14
+ observations: Map<string, RateLimitObservation>;
15
+ observe(response: HttpClientResponse.HttpClientResponse): string;
16
+ resource: (path: string) => string;
17
+ };
18
+ export type RateLimits = ReturnType<typeof rateLimits>;
19
+ export declare const failRateLimited: (path: string, error: GitHubRateLimited, remaining: number | undefined) => Effect.Effect<never, GitHubRateLimited, never>;
20
+ //# sourceMappingURL=rateLimits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rateLimits.d.ts","sourceRoot":"","sources":["../src/rateLimits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,UAAU;;;;sBAYN,kBAAkB,CAAC,kBAAkB;qBAPhC,MAAM;EA0B9B;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAEvD,eAAO,MAAM,eAAe,2HAQ1B,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { Clock, DateTime, Effect } from "effect";
2
+ export function rateLimits() {
3
+ const observations = new Map();
4
+ const blocked = new Map();
5
+ const failures = new Map();
6
+ const resources = new Map();
7
+ function resource(path) {
8
+ return resources.get(path) ?? (path.startsWith("/search/") ? "search" : "core");
9
+ }
10
+ return {
11
+ blocked,
12
+ failures,
13
+ observations,
14
+ observe(response) {
15
+ const headers = response.headers;
16
+ const path = new URL(response.request.url).pathname;
17
+ const name = headers["x-ratelimit-resource"] ?? resource(path);
18
+ resources.set(path, name);
19
+ const values = ["limit", "remaining", "used", "reset"].map((key) => headers[`x-ratelimit-${key}`]);
20
+ if (values.every((value) => value !== undefined && Number.isFinite(Number(value)))) {
21
+ observations.set(name, {
22
+ limit: Number(headers["x-ratelimit-limit"]),
23
+ remaining: Number(headers["x-ratelimit-remaining"]),
24
+ reset: DateTime.makeUnsafe(Number(headers["x-ratelimit-reset"]) * 1000),
25
+ resource: name,
26
+ used: Number(headers["x-ratelimit-used"]),
27
+ });
28
+ }
29
+ return name;
30
+ },
31
+ resource,
32
+ };
33
+ }
34
+ export const failRateLimited = Effect.fnUntraced(function* (path, error, remaining) {
35
+ const fields = { path, remaining, resource: error.resource, retryAt: DateTime.formatIso(error.retryAt) };
36
+ yield* Effect.logWarning("GitHub rate limited", fields);
37
+ const span = yield* Effect.currentSpan.pipe(Effect.option);
38
+ if (span._tag === "Some") {
39
+ span.value.event("GitHub.rateLimited", yield* Clock.currentTimeNanos, fields);
40
+ }
41
+ return yield* error;
42
+ });
43
+ //# sourceMappingURL=rateLimits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rateLimits.js","sourceRoot":"","sources":["../src/rateLimits.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { Effect } from "effect";
2
+ import { type HttpClient, HttpClientRequest } from "effect/http";
3
+ import { ResponseBodyTooLarge } from "@shivaedev/platform/http-client/errors.ts";
4
+ import { type CachedResponse } from "./cache.ts";
5
+ import { GitHubTransportError } from "./errors.ts";
6
+ import type { GitHubToken } from "./GitHubToken.ts";
7
+ import { type RateLimits } from "./rateLimits.ts";
8
+ export declare function requests(client: HttpClient.HttpClient, token: GitHubToken["Service"], rates: RateLimits): (input: HttpClientRequest.HttpClientRequest, limit: number) => Effect.Effect<CachedResponse, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | GitHubTransportError | ResponseBodyTooLarge | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
9
+ //# sourceMappingURL=requests.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requests.d.ts","sourceRoot":"","sources":["../src/requests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,MAAM,EAAoB,MAAM,QAAQ,CAAC;AAC5D,OAAO,EAAE,KAAK,UAAU,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,KAAK,cAAc,EAAiB,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGnE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,EAAE,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,UAAU,6SA0CvG"}