@shivaedev/github 0.8.6 → 0.9.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 (61) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +47 -3
  3. package/dist/GitHub.d.ts +100 -17
  4. package/dist/GitHub.d.ts.map +1 -1
  5. package/dist/GitHub.js +4 -1
  6. package/dist/GitHub.js.map +1 -1
  7. package/dist/GitHubToken.d.ts +2 -2
  8. package/dist/GitHubToken.d.ts.map +1 -1
  9. package/dist/GitHubToken.js +1 -1
  10. package/dist/GitHubToken.js.map +1 -1
  11. package/dist/appTokens.d.ts +6 -0
  12. package/dist/appTokens.d.ts.map +1 -0
  13. package/dist/appTokens.js +64 -0
  14. package/dist/appTokens.js.map +1 -0
  15. package/dist/artifacts.d.ts +1 -1
  16. package/dist/authenticatedRequest.d.ts +1 -1
  17. package/dist/authenticatedRequest.d.ts.map +1 -1
  18. package/dist/authenticatedRequest.js +3 -2
  19. package/dist/authenticatedRequest.js.map +1 -1
  20. package/dist/cache.d.ts +2 -0
  21. package/dist/cache.d.ts.map +1 -1
  22. package/dist/cache.js +3 -0
  23. package/dist/cache.js.map +1 -1
  24. package/dist/checkRuns.d.ts +116 -11
  25. package/dist/checkRuns.d.ts.map +1 -1
  26. package/dist/checkRuns.js +39 -18
  27. package/dist/checkRuns.js.map +1 -1
  28. package/dist/githubApp.d.ts +2 -4
  29. package/dist/githubApp.d.ts.map +1 -1
  30. package/dist/githubApp.js +5 -55
  31. package/dist/githubApp.js.map +1 -1
  32. package/dist/installationClients.d.ts +185 -0
  33. package/dist/installationClients.d.ts.map +1 -0
  34. package/dist/installationClients.js +28 -0
  35. package/dist/installationClients.js.map +1 -0
  36. package/dist/json.d.ts.map +1 -1
  37. package/dist/json.js +4 -0
  38. package/dist/json.js.map +1 -1
  39. package/dist/representations.d.ts +4 -4
  40. package/dist/representations.d.ts.map +1 -1
  41. package/dist/representations.js +1 -1
  42. package/dist/representations.js.map +1 -1
  43. package/dist/requests.d.ts +2 -2
  44. package/dist/requests.d.ts.map +1 -1
  45. package/dist/requests.js +11 -9
  46. package/dist/requests.js.map +1 -1
  47. package/dist/status.d.ts +1 -1
  48. package/dist/status.d.ts.map +1 -1
  49. package/dist/stickyComments.d.ts +1 -1
  50. package/package.json +7 -7
  51. package/src/GitHub.ts +15 -1
  52. package/src/GitHubToken.ts +4 -2
  53. package/src/appTokens.ts +92 -0
  54. package/src/authenticatedRequest.ts +3 -1
  55. package/src/cache.ts +5 -0
  56. package/src/checkRuns.ts +58 -18
  57. package/src/githubApp.ts +6 -80
  58. package/src/installationClients.ts +44 -0
  59. package/src/json.ts +4 -0
  60. package/src/representations.ts +2 -2
  61. package/src/requests.ts +11 -9
@@ -0,0 +1,185 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { HttpClient } from "effect/http";
3
+ import type { AppCredentials } from "#appJwt.ts";
4
+ export declare const GitHubAppCredentials: Context.Service<{
5
+ readonly credentials: AppCredentials;
6
+ }, {
7
+ readonly credentials: AppCredentials;
8
+ }>;
9
+ export declare const GitHubApp: Context.Service<"@shivaedev/github/GitHubApp", Readonly<{
10
+ readonly installation: (installationId: number) => Effect.Effect<Readonly<{
11
+ readonly downloadArtifactArchive: (options: import("./artifacts.ts").ArtifactArchiveOptions) => Effect.Effect<Uint8Array<ArrayBuffer>, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubArtifactError | import("./errors.ts").GitHubArtifactTooLarge | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("@shivaedev/http/errors.ts").RemoteHttpError | import("@shivaedev/http/errors.ts").RemoteRateLimited | import("@shivaedev/http/errors.ts").RemoteUnauthorized | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge, never>;
12
+ readonly list: (path: string, beforeRequest?: ((resource: string) => Effect.Effect<void, import("@shivaedev/errors/taxonomy.ts").ServiceUnavailable>) | undefined, byteLimit?: number | undefined) => Effect.Effect<import("effect/Stream").Stream<{
13
+ decode: <TSchema extends import("effect/Schema").Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], import("effect/Schema").SchemaError, TSchema["DecodingServices"]>;
14
+ hasNext: boolean;
15
+ }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("effect/Cause").NoSuchElementError | import("@shivaedev/http/errors.ts").PaginationLinkError | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("@shivaedev/errors/taxonomy.ts").ServiceUnavailable | import("@shivaedev/http/errors.ts").RemoteStatusError, never>, never, never>;
16
+ readonly read: (path: string, byteLimit?: number | undefined) => Effect.Effect<{
17
+ decode: <TSchema extends import("effect/Schema").Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], import("effect/Schema").SchemaError, TSchema["DecodingServices"]>;
18
+ }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
19
+ readonly write: (method: "DELETE" | "PATCH" | "POST" | "PUT", path: string, body?: unknown, byteLimit?: number | undefined) => Effect.Effect<{
20
+ decode: <TSchema extends import("effect/Schema").Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], import("effect/Schema").SchemaError, TSchema["DecodingServices"]>;
21
+ }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
22
+ readonly createCheckRun: (owner: string, repo: string, input: {
23
+ readonly detailsUrl?: string | undefined;
24
+ readonly headSha: string;
25
+ readonly name: string;
26
+ readonly output?: {
27
+ readonly summary: string;
28
+ readonly text?: string | undefined;
29
+ readonly title: string;
30
+ } | undefined;
31
+ readonly conclusion?: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out" | undefined;
32
+ readonly status: "in_progress" | "queued";
33
+ } | {
34
+ readonly detailsUrl?: string | undefined;
35
+ readonly headSha: string;
36
+ readonly name: string;
37
+ readonly output?: {
38
+ readonly summary: string;
39
+ readonly text?: string | undefined;
40
+ readonly title: string;
41
+ } | undefined;
42
+ readonly conclusion: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out";
43
+ readonly status: "completed";
44
+ }) => Effect.Effect<{
45
+ readonly app?: {
46
+ readonly id: number;
47
+ } | null | undefined;
48
+ readonly conclusion: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out" | null;
49
+ readonly detailsUrl: string | null;
50
+ readonly headSha: string;
51
+ readonly id: number;
52
+ readonly name: string;
53
+ readonly output: {
54
+ readonly summary: string | null;
55
+ readonly text: string | null;
56
+ readonly title: string | null;
57
+ };
58
+ readonly status: "completed" | "in_progress" | "pending" | "queued" | "requested" | "waiting";
59
+ }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("effect/Schema").SchemaError | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
60
+ readonly findLatestCheckRun: (owner: string, repo: string, input: {
61
+ readonly appId?: number | undefined;
62
+ readonly headSha: string;
63
+ readonly name: string;
64
+ } | {
65
+ readonly appId: number;
66
+ readonly headSha: string;
67
+ readonly name?: string | undefined;
68
+ }) => Effect.Effect<import("effect/Option").Option<{
69
+ readonly app?: {
70
+ readonly id: number;
71
+ } | null | undefined;
72
+ readonly conclusion: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out" | null;
73
+ readonly detailsUrl: string | null;
74
+ readonly headSha: string;
75
+ readonly id: number;
76
+ readonly name: string;
77
+ readonly output: {
78
+ readonly summary: string | null;
79
+ readonly text: string | null;
80
+ readonly title: string | null;
81
+ };
82
+ readonly status: "completed" | "in_progress" | "pending" | "queued" | "requested" | "waiting";
83
+ }>, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("effect/Cause").NoSuchElementError | import("@shivaedev/http/errors.ts").PaginationLinkError | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("effect/Schema").SchemaError | import("@shivaedev/errors/taxonomy.ts").ServiceUnavailable | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
84
+ readonly updateCheckRun: (owner: string, repo: string, id: number, input: {
85
+ readonly detailsUrl?: string | undefined;
86
+ readonly output?: {
87
+ readonly summary: string;
88
+ readonly text?: string | undefined;
89
+ readonly title: string;
90
+ } | undefined;
91
+ readonly status: "in_progress" | "queued";
92
+ } | {
93
+ readonly conclusion: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out";
94
+ readonly detailsUrl?: string | undefined;
95
+ readonly output?: {
96
+ readonly summary: string;
97
+ readonly text?: string | undefined;
98
+ readonly title: string;
99
+ } | undefined;
100
+ readonly status: "completed";
101
+ }) => Effect.Effect<{
102
+ readonly app?: {
103
+ readonly id: number;
104
+ } | null | undefined;
105
+ readonly conclusion: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out" | null;
106
+ readonly detailsUrl: string | null;
107
+ readonly headSha: string;
108
+ readonly id: number;
109
+ readonly name: string;
110
+ readonly output: {
111
+ readonly summary: string | null;
112
+ readonly text: string | null;
113
+ readonly title: string | null;
114
+ };
115
+ readonly status: "completed" | "in_progress" | "pending" | "queued" | "requested" | "waiting";
116
+ }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("effect/Schema").SchemaError | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
117
+ readonly upsertCheckRun: (owner: string, repo: string, input: {
118
+ readonly detailsUrl?: string | undefined;
119
+ readonly headSha: string;
120
+ readonly name: string;
121
+ readonly output?: {
122
+ readonly summary: string;
123
+ readonly text?: string | undefined;
124
+ readonly title: string;
125
+ } | undefined;
126
+ readonly conclusion?: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out" | undefined;
127
+ readonly status: "in_progress" | "queued";
128
+ } | {
129
+ readonly detailsUrl?: string | undefined;
130
+ readonly headSha: string;
131
+ readonly name: string;
132
+ readonly output?: {
133
+ readonly summary: string;
134
+ readonly text?: string | undefined;
135
+ readonly title: string;
136
+ } | undefined;
137
+ readonly conclusion: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out";
138
+ readonly status: "completed";
139
+ }, appId?: number | undefined) => Effect.Effect<{
140
+ readonly app?: {
141
+ readonly id: number;
142
+ } | null | undefined;
143
+ readonly conclusion: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out" | null;
144
+ readonly detailsUrl: string | null;
145
+ readonly headSha: string;
146
+ readonly id: number;
147
+ readonly name: string;
148
+ readonly output: {
149
+ readonly summary: string | null;
150
+ readonly text: string | null;
151
+ readonly title: string | null;
152
+ };
153
+ readonly status: "completed" | "in_progress" | "pending" | "queued" | "requested" | "waiting";
154
+ }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("effect/Cause").NoSuchElementError | import("@shivaedev/http/errors.ts").PaginationLinkError | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("effect/Schema").SchemaError | import("@shivaedev/errors/taxonomy.ts").ServiceUnavailable | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
155
+ readonly upsertStickyComment: (input: {
156
+ readonly appId?: number | undefined;
157
+ readonly author?: string | undefined;
158
+ readonly body: string;
159
+ readonly marker: string;
160
+ readonly number: number;
161
+ readonly owner: string;
162
+ readonly repo: string;
163
+ }) => Effect.Effect<{
164
+ readonly body: string;
165
+ readonly id: number;
166
+ readonly performedViaGithubApp?: {
167
+ readonly id: number;
168
+ } | null | undefined;
169
+ readonly user: {
170
+ readonly login: string;
171
+ readonly type?: string | undefined;
172
+ } | null;
173
+ }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("effect/Cause").NoSuchElementError | import("@shivaedev/http/errors.ts").PaginationLinkError | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("effect/Schema").SchemaError | import("@shivaedev/errors/taxonomy.ts").ServiceUnavailable | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
174
+ readonly bytes: (path: string, accept: string, limit: number) => Effect.Effect<Uint8Array<ArrayBufferLike>, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
175
+ readonly observations: () => Effect.Effect<import("./rateLimits.ts").RateLimitObservation[], never, never>;
176
+ readonly resource: (path: string) => Effect.Effect<string, never, never>;
177
+ readonly text: (path: string, accept: string, limit: number) => Effect.Effect<string, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
178
+ }>, never, never>;
179
+ }>> & {
180
+ readonly layer: Layer.Layer<"@shivaedev/github/GitHubApp", never, HttpClient.HttpClient | {
181
+ readonly credentials: AppCredentials;
182
+ }>;
183
+ };
184
+ export declare function withInstallation<A, E, R>(installationId: number, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, "@shivaedev/github/GitHubApp" | Exclude<R, "@shivaedev/github/GitHub">>;
185
+ //# sourceMappingURL=installationClients.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installationClients.d.ts","sourceRoot":"","sources":["../src/installationClients.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKjD,eAAO,MAAM,oBAAoB;0BAA2C,cAAc;;;EAAuC,CAAC;AAElI,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BAFsD,cAAc;;CA6BxF,CAAC;AAEH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,+FAI/F"}
@@ -0,0 +1,28 @@
1
+ import { Cache, Context, Effect, Layer } from "effect";
2
+ import { HttpClient } from "effect/http";
3
+ import { defineService } from "@shivaedev/service/defineService.ts";
4
+ import { appTokens } from "#appTokens.ts";
5
+ import { GitHub } from "#GitHub.ts";
6
+ import { GitHubConfig } from "#GitHubConfig.ts";
7
+ export const GitHubAppCredentials = Context.Service("@shivaedev/github/AppCredentials");
8
+ export const GitHubApp = defineService({
9
+ id: "@shivaedev/github/GitHubApp",
10
+ initialize: Effect.gen(function* () {
11
+ const { credentials } = yield* GitHubAppCredentials;
12
+ const http = yield* HttpClient.HttpClient;
13
+ const config = yield* GitHubConfig;
14
+ return yield* Cache.make({
15
+ capacity: 100,
16
+ lookup: (installationId) => Layer.build(GitHub.layer.pipe(Layer.provide(appTokens({ ...credentials, installationId })), Layer.provide(Layer.succeed(HttpClient.HttpClient)(http)), Layer.provide(Layer.succeed(GitHubConfig)(config)))).pipe(Effect.scoped, Effect.map((context) => Context.get(context, GitHub))),
17
+ timeToLive: "30 minutes",
18
+ });
19
+ }),
20
+ methods: (clients) => ({
21
+ installation: (installationId) => Cache.get(clients, installationId).pipe(Effect.tap((client) => Cache.set(clients, installationId, client))),
22
+ }),
23
+ requires: [GitHubAppCredentials, HttpClient.HttpClient, GitHubConfig],
24
+ });
25
+ export function withInstallation(installationId, effect) {
26
+ return Effect.flatMap(GitHubApp, (app) => Effect.flatMap(app.installation(installationId), (client) => Effect.provideService(effect, GitHub, client)));
27
+ }
28
+ //# sourceMappingURL=installationClients.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installationClients.js","sourceRoot":"","sources":["../src/installationClients.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAEpE,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAA2C,kCAAkC,CAAC,CAAC;AAElI,MAAM,CAAC,MAAM,SAAS,GAAG,aAAa,CAAC;IACtC,EAAE,EAAE,6BAA6B;IACjC,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC/B,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,CAAC,oBAAoB,CAAC;QACpD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;QAC1C,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,YAAY,CAAC;QACnC,OAAO,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;YACxB,QAAQ,EAAE,GAAG;YACb,MAAM,EAAE,CAAC,cAAsB,EAAE,EAAE,CAClC,KAAK,CAAC,KAAK,CACV,MAAM,CAAC,KAAK,CAAC,IAAI,CAChB,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,GAAG,WAAW,EAAE,cAAc,EAAE,CAAC,CAAC,EAC5D,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,EACzD,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAClD,CACD,CAAC,IAAI,CACL,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CACrD;YACF,UAAU,EAAE,YAAY;SACxB,CAAC,CAAC;IACJ,CAAC,CAAC;IACF,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACtB,YAAY,EAAE,CAAC,cAAsB,EAAE,EAAE,CACxC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;KAC5G,CAAC;IACF,QAAQ,EAAE,CAAC,oBAAoB,EAAE,UAAU,CAAC,UAAU,EAAE,YAAY,CAAC;CACrE,CAAC,CAAC;AAEH,MAAM,UAAU,gBAAgB,CAAU,cAAsB,EAAE,MAA8B;IAC/F,OAAO,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CACxC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAC3G,CAAC;AACH,CAAC"}
@@ -1 +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"}
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,eAAO,MAAM,UAAU,GAAgC,OAAO,SAAS,MAAM,CAAC,UAAU,4HAWtF,CAAC;AAEH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc;IACxC,MAAM,GAAG,OAAO,SAAS,MAAM,CAAC,UAAU,UAAU,OAAO;EACpE"}
package/dist/json.js CHANGED
@@ -1,5 +1,9 @@
1
1
  import { Effect, Schema } from "effect";
2
+ import * as HttpStatus from "effect/http/HttpStatus";
2
3
  export const decodeJson = Effect.fnUntraced(function* (entry, schema) {
4
+ if (entry.response.status === HttpStatus.fromLiteral("NoContent")) {
5
+ return yield* Schema.decodeUnknownEffect(schema)(undefined);
6
+ }
3
7
  const cached = entry.decoded.get(schema);
4
8
  if (entry.decoded.has(schema) && Schema.is(schema)(cached)) {
5
9
  return cached;
package/dist/json.js.map CHANGED
@@ -1 +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"}
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAC;AAGrD,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAqC,KAAqB,EAAE,MAAe;IAC/H,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,UAAU,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC;QACnE,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC;IAC7D,CAAC;IACD,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"}
@@ -7,13 +7,13 @@ export declare function representations(apiUrl: string, request: ReturnType<type
7
7
  list: (path: string, beforeRequest?: (resource: string) => Effect.Effect<void, ServiceUnavailable>, byteLimit?: number) => Effect.Effect<Stream.Stream<{
8
8
  decode: <TSchema extends import("effect/Schema").Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], import("effect/Schema").SchemaError, TSchema["DecodingServices"]>;
9
9
  hasNext: boolean;
10
- }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/Cause").NoSuchElementError | import("@shivaedev/http/errors.ts").PaginationLinkError | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | ServiceUnavailable | import("@shivaedev/http/errors.ts").RemoteStatusError, never>, never, never>;
10
+ }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("effect/Cause").NoSuchElementError | import("@shivaedev/http/errors.ts").PaginationLinkError | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | ServiceUnavailable | import("@shivaedev/http/errors.ts").RemoteStatusError, never>, never, never>;
11
11
  read: (path: string, byteLimit?: number) => Effect.Effect<{
12
12
  decode: <TSchema extends import("effect/Schema").Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], import("effect/Schema").SchemaError, TSchema["DecodingServices"]>;
13
- }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
14
- write: (method: "POST" | "PATCH", path: string, body: unknown, byteLimit?: number) => Effect.Effect<{
13
+ }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
14
+ write: (method: "POST" | "PATCH" | "PUT" | "DELETE", path: string, body?: unknown, byteLimit?: number) => Effect.Effect<{
15
15
  decode: <TSchema extends import("effect/Schema").Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], import("effect/Schema").SchemaError, TSchema["DecodingServices"]>;
16
- }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
16
+ }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
17
17
  };
18
18
  export type Representations = Omit<ReturnType<typeof representations>, "get">;
19
19
  //# sourceMappingURL=representations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"representations.d.ts","sourceRoot":"","sources":["../src/representations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAc,iBAAiB,EAA2B,MAAM,aAAa,CAAC;AACrF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAKxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,wBAAgB,eAAe,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,EACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAClC,iBAAiB,SAAc;gBAEZ,MAAM;iBAOlB,MAAM,kBACI,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,kBAAkB,CAAC;;;;iBAL5C,MAAM;;;oBA6BH,MAAM,GAAG,OAAO,QAAQ,MAAM,QAAQ,OAAO;;;EAQlF;AAED,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,eAAe,CAAC,EAAE,KAAK,CAAC,CAAC"}
1
+ {"version":3,"file":"representations.d.ts","sourceRoot":"","sources":["../src/representations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAc,iBAAiB,EAA2B,MAAM,aAAa,CAAC;AACrF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAKxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,wBAAgB,eAAe,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,EACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAClC,iBAAiB,SAAc;gBAEZ,MAAM;iBAOlB,MAAM,kBACI,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,kBAAkB,CAAC;;;;iBAL5C,MAAM;;;oBA6BH,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,QAAQ,MAAM,SAAS,OAAO;;;EAQtG;AAED,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,eAAe,CAAC,EAAE,KAAK,CAAC,CAAC"}
@@ -22,7 +22,7 @@ export function representations(apiUrl, request, resource, responseByteLimit = 1
22
22
  return Effect.succeed(paginate(client, get(path)).pipe(Stream.mapEffect((response) => Effect.fromNullishOr(entries.get(response))), Stream.map((entry) => ({ ...jsonResponse(entry), hasNext: nextLink(entry.response.headers.link) !== undefined }))));
23
23
  }
24
24
  function writeRepresentation(method, path, body, byteLimit = responseByteLimit) {
25
- return HttpClientRequest.make(method)(new URL(path, apiUrl).href, { headers: { Accept: "application/vnd.github+json" } }).pipe(HttpClientRequest.bodyJson(body), Effect.flatMap((input) => request(input, byteLimit)), Effect.map(jsonResponse));
25
+ return HttpClientRequest.make(method)(new URL(path, apiUrl).href, { headers: { Accept: "application/vnd.github+json" } }).pipe((input) => (body === undefined ? Effect.succeed(input) : HttpClientRequest.bodyJson(input, body)), Effect.flatMap((input) => request(input, byteLimit)), Effect.map(jsonResponse));
26
26
  }
27
27
  return { get, list: listRepresentations, read: readRepresentation, write: writeRepresentation };
28
28
  }
@@ -1 +1 @@
1
- {"version":3,"file":"representations.js","sourceRoot":"","sources":["../src/representations.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"representations.js","sourceRoot":"","sources":["../src/representations.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,10 @@
1
1
  import { Effect } from "effect";
2
- import { type HttpClient, HttpClientRequest } from "effect/http";
2
+ import { HttpClient, HttpClientRequest } from "effect/http";
3
3
  import { ResponseBodyTooLarge } from "@shivaedev/http/errors.ts";
4
4
  import { type CachedResponse } from "./cache.ts";
5
5
  import { GitHubTransportError } from "./errors.ts";
6
6
  import type { GitHubToken } from "./GitHubToken.ts";
7
7
  import type { RateLimits } from "./rateLimits.ts";
8
8
  import type { TokenRefresh } from "./TokenRefresh.ts";
9
- export declare function requests(client: HttpClient.HttpClient, token: GitHubToken["Service"], rates: RateLimits, refresh?: typeof TokenRefresh.Service): (input: HttpClientRequest.HttpClientRequest, limit: number) => Effect.Effect<CachedResponse, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | GitHubTransportError | ResponseBodyTooLarge | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
9
+ export declare function requests(client: HttpClient.HttpClient, token: GitHubToken["Service"], rates: RateLimits, refresh?: typeof TokenRefresh.Service): (input: HttpClientRequest.HttpClientRequest, limit: number) => Effect.Effect<CachedResponse, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | GitHubTransportError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | ResponseBodyTooLarge | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
10
10
  //# sourceMappingURL=requests.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"requests.d.ts","sourceRoot":"","sources":["../src/requests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,KAAK,UAAU,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,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,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,wBAAgB,QAAQ,CACvB,MAAM,EAAE,UAAU,CAAC,UAAU,EAC7B,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC,EAC7B,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,OAAO,YAAY,CAAC,OAAmB,6XA2BhD"}
1
+ {"version":3,"file":"requests.d.ts","sourceRoot":"","sources":["../src/requests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAE5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,EAAE,KAAK,cAAc,EAAsC,MAAM,YAAY,CAAC;AACrF,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,wBAAgB,QAAQ,CACvB,MAAM,EAAE,UAAU,CAAC,UAAU,EAC7B,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC,EAC7B,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,OAAO,YAAY,CAAC,OAAmB,obA6BhD"}
package/dist/requests.js CHANGED
@@ -1,34 +1,36 @@
1
1
  import { Effect } from "effect";
2
- import { HttpClientRequest } from "effect/http";
2
+ import { HttpClient, HttpClientRequest } from "effect/http";
3
3
  import { readBoundedBody } from "@shivaedev/http/body.ts";
4
4
  import { ResponseBodyTooLarge } from "@shivaedev/http/errors.ts";
5
5
  import { authenticatedRequest } from "./authenticatedRequest.js";
6
- import { responseCache } from "./cache.js";
6
+ import { responseCache, revalidatedResponse } from "./cache.js";
7
7
  import { GitHubTransportError } from "./errors.js";
8
8
  import { isUnchanged } from "./status.js";
9
9
  export function requests(client, token, rates, refresh = undefined) {
10
10
  const cache = responseCache();
11
- const send = authenticatedRequest(client, token, rates, refresh);
11
+ const send = authenticatedRequest(HttpClient.withScope(client), token, rates, refresh);
12
12
  return Effect.fn("GitHub.request")(function* (input, limit) {
13
- const key = `${input.url} ${input.headers.accept}`;
13
+ const key = JSON.stringify([input.url, input.urlParams, input.headers.accept]);
14
14
  const cached = input.method === "GET" ? cache.get(key) : undefined;
15
15
  let request = HttpClientRequest.removeHeader(input, "if-none-match");
16
- if (cached?.response.headers.etag !== undefined) {
17
- request = HttpClientRequest.setHeader(request, "If-None-Match", cached.response.headers.etag);
16
+ if (cached?.etag !== undefined) {
17
+ request = HttpClientRequest.setHeader(request, "If-None-Match", cached.etag);
18
18
  }
19
19
  const response = yield* send(request, cached === undefined ? undefined : "revalidate");
20
20
  if (isUnchanged(response) && cached !== undefined) {
21
21
  if (cached.bytes.byteLength > limit) {
22
22
  return yield* new ResponseBodyTooLarge({ limit });
23
23
  }
24
- return cached;
24
+ const entry = revalidatedResponse(cached, response);
25
+ cache.set(key, entry);
26
+ return entry;
25
27
  }
26
28
  const bytes = yield* readBoundedBody(response, limit).pipe(Effect.catchTag("HttpClientError", (cause) => Effect.fail(new GitHubTransportError({ path: new URL(input.url).pathname }, { cause }))));
27
- const entry = { bytes, decoded: new Map(), response };
29
+ const entry = { bytes, decoded: new Map(), etag: response.headers.etag, response };
28
30
  if (input.method === "GET" && response.headers.etag !== undefined) {
29
31
  cache.set(key, entry);
30
32
  }
31
33
  return entry;
32
- });
34
+ }, Effect.scoped);
33
35
  }
34
36
  //# sourceMappingURL=requests.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"requests.js","sourceRoot":"","sources":["../src/requests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAmB,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAuB,aAAa,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGnD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1C,MAAM,UAAU,QAAQ,CACvB,MAA6B,EAC7B,KAA6B,EAC7B,KAAiB,EACjB,OAAO,GAAgC,SAAS;IAEhD,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,oBAAoB,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACjE,OAAO,MAAM,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,EAAE,KAA0C,EAAE,KAAa;QACtG,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACnE,IAAI,OAAO,GAAG,iBAAiB,CAAC,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;QACrE,IAAI,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACjD,OAAO,GAAG,iBAAiB,CAAC,SAAS,CAAC,OAAO,EAAE,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/F,CAAC;QACD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;QACvF,IAAI,WAAW,CAAC,QAAQ,CAAC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACnD,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG,KAAK,EAAE,CAAC;gBACrC,OAAO,KAAK,CAAC,CAAC,IAAI,oBAAoB,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YACnD,CAAC;YACD,OAAO,MAAM,CAAC;QACf,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,IAAI,CACzD,MAAM,CAAC,QAAQ,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,oBAAoB,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CACtI,CAAC;QACF,MAAM,KAAK,GAAmB,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,EAAE,QAAQ,EAAE,CAAC;QACtE,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACnE,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACvB,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"requests.js","sourceRoot":"","sources":["../src/requests.ts"],"names":[],"mappings":"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"}
package/dist/status.d.ts CHANGED
@@ -3,5 +3,5 @@ import { type HttpClientResponse } from "effect/http";
3
3
  import { GitHubConversationLocked, GitHubPermissionDenied, GitHubRateLimited } from "#errors.ts";
4
4
  export declare function isUnauthorized(response: HttpClientResponse.HttpClientResponse): boolean;
5
5
  export declare function isUnchanged(response: HttpClientResponse.HttpClientResponse): boolean;
6
- export declare const checkStatus: (response: HttpClientResponse.HttpClientResponse, resource: string, failures?: any) => Effect.Effect<HttpClientResponse.HttpClientResponse, GitHubConversationLocked | GitHubPermissionDenied | GitHubRateLimited | import("effect/http/HttpClientError").HttpClientError | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
6
+ export declare const checkStatus: (response: HttpClientResponse.HttpClientResponse, resource: string, failures?: any) => Effect.Effect<HttpClientResponse.HttpClientResponse, GitHubConversationLocked | GitHubPermissionDenied | GitHubRateLimited | import("effect/http/HttpClientError").HttpClientError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
7
7
  //# sourceMappingURL=status.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,MAAM,EAAkB,MAAM,QAAQ,CAAC;AAC1D,OAAO,EAAc,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAKlE,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEjG,wBAAgB,cAAc,CAAC,QAAQ,EAAE,kBAAkB,CAAC,kBAAkB,WAE7E;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,kBAAkB,CAAC,kBAAkB,WAE1E;AAED,eAAO,MAAM,WAAW,sYAgBtB,CAAC"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,MAAM,EAAkB,MAAM,QAAQ,CAAC;AAC1D,OAAO,EAAc,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAKlE,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEjG,wBAAgB,cAAc,CAAC,QAAQ,EAAE,kBAAkB,CAAC,kBAAkB,WAE7E;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,kBAAkB,CAAC,kBAAkB,WAE1E;AAED,eAAO,MAAM,WAAW,6bAgBtB,CAAC"}
@@ -41,6 +41,6 @@ export declare function stickyComments(client: Representations): {
41
41
  readonly login: string;
42
42
  readonly type?: string | undefined;
43
43
  } | null;
44
- }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("effect/Cause").NoSuchElementError | import("@shivaedev/http/errors.ts").PaginationLinkError | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | import("@shivaedev/errors/taxonomy.ts").ServiceUnavailable | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
44
+ }, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubConversationLocked | import("./errors.ts").GitHubPermissionDenied | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/http/errors.ts").InvalidBodyLimit | import("effect/Cause").NoSuchElementError | import("@shivaedev/http/errors.ts").PaginationLinkError | import("@shivaedev/http/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | import("@shivaedev/errors/taxonomy.ts").ServiceUnavailable | import("@shivaedev/http/errors.ts").RemoteStatusError, never>;
45
45
  };
46
46
  //# sourceMappingURL=stickyComments.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/github",
3
- "version": "0.8.6",
3
+ "version": "0.9.0",
4
4
  "description": "Typed GitHub REST requests, conditional reads and resource budgets for Effect applications",
5
5
  "keywords": [
6
6
  "effect"
@@ -43,17 +43,17 @@
43
43
  "README.md"
44
44
  ],
45
45
  "dependencies": {
46
- "@shivaedev/errors": "0.4.1",
47
- "@shivaedev/http": "0.3.1",
48
- "@shivaedev/service": "0.6.0"
46
+ "@shivaedev/errors": "0.5.0",
47
+ "@shivaedev/http": "0.4.0",
48
+ "@shivaedev/service": "0.6.1"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@effect/platform-node": "4.0.6",
52
52
  "@effect/platform-node-shared": "4.0.6",
53
53
  "@effect/vitest": "4.0.6",
54
- "@shivaedev/quality": "0.54.0",
55
- "@shivaedev/test": "0.12.0",
56
- "@shivaedev/test-story": "0.32.0",
54
+ "@shivaedev/quality": "0.55.0",
55
+ "@shivaedev/test": "0.12.1",
56
+ "@shivaedev/test-story": "0.33.0",
57
57
  "@types/node": "24.19.2",
58
58
  "effect": "4.0.6",
59
59
  "typescript": "7.0.2",
package/src/GitHub.ts CHANGED
@@ -64,8 +64,22 @@ export function listBounded<TSchema extends Schema.Constraint>(path: string, sch
64
64
  );
65
65
  }
66
66
 
67
+ type WriteMethod = "POST" | "PATCH" | "PUT" | "DELETE";
68
+
67
69
  export function write<TSchema extends Schema.Constraint>(
68
- method: "POST" | "PATCH",
70
+ method: WriteMethod,
71
+ path: string,
72
+ body: unknown,
73
+ schema: TSchema,
74
+ responseByteLimit?: number,
75
+ ): ReturnType<typeof writeDecoded<TSchema>>;
76
+ export function write(method: WriteMethod, path: string, body?: unknown): ReturnType<typeof writeDecoded<typeof Schema.Void>>;
77
+ export function write(method: WriteMethod, path: string, body?: unknown, schema: Schema.Constraint = Schema.Void, responseByteLimit?: number) {
78
+ return writeDecoded(method, path, body, schema, responseByteLimit);
79
+ }
80
+
81
+ function writeDecoded<TSchema extends Schema.Constraint>(
82
+ method: WriteMethod,
69
83
  path: string,
70
84
  body: unknown,
71
85
  schema: TSchema,
@@ -1,6 +1,6 @@
1
1
  import { Config, Context, Effect, Layer, Option, Redacted, Stream } from "effect";
2
2
  import { ChildProcess, ChildProcessSpawner } from "effect/process";
3
- import { type GitHubAppError, GitHubTokenError } from "./errors.ts";
3
+ import { type GitHubAppError, type GitHubRateLimited, GitHubTokenError } from "#errors.ts";
4
4
 
5
5
  type Token = Option.Option<Redacted.Redacted<string>>;
6
6
  const environmentToken = Config.Redacted("GH_TOKEN").pipe(
@@ -8,7 +8,9 @@ const environmentToken = Config.Redacted("GH_TOKEN").pipe(
8
8
  Config.option,
9
9
  );
10
10
 
11
- export class GitHubToken extends Context.Service<GitHubToken, Token | Effect.Effect<Token, GitHubAppError>>()("@shivaedev/github/GitHubToken") {
11
+ export class GitHubToken extends Context.Service<GitHubToken, Token | Effect.Effect<Token, GitHubAppError | GitHubRateLimited>>()(
12
+ "@shivaedev/github/GitHubToken",
13
+ ) {
12
14
  static readonly fromEnv = Layer.effect(GitHubToken)(environmentToken);
13
15
 
14
16
  static readonly fromEnvOrCli = Layer.effect(GitHubToken)(
@@ -0,0 +1,92 @@
1
+ import { Cache, Clock, Context, Effect, Exit, Layer, Option, type Redacted, Schema } from "effect";
2
+ import { HttpClient, HttpClientRequest } from "effect/http";
3
+ import { readBoundedJson } from "@shivaedev/http/body.ts";
4
+ import { appJwt } from "#appJwt.ts";
5
+ import { authenticatedRequest } from "#authenticatedRequest.ts";
6
+ import { GitHubAppError } from "#errors.ts";
7
+ import { GitHubConfig } from "#GitHubConfig.ts";
8
+ import { GitHubToken } from "#GitHubToken.ts";
9
+ import type { GitHubAppOptions } from "#githubApp.ts";
10
+ import { rateLimits } from "#rateLimits.ts";
11
+ import { TokenRefresh } from "#TokenRefresh.ts";
12
+
13
+ const Installation = Schema.Struct({ id: Schema.Number });
14
+ const AccessToken = Schema.Struct({ expiresAt: Schema.DateFromString, token: Schema.RedactedFromValue(Schema.String) }).pipe(
15
+ Schema.encodeKeys({ expiresAt: "expires_at" }),
16
+ );
17
+
18
+ export function appTokens(options: GitHubAppOptions) {
19
+ return Layer.effectContext(
20
+ Effect.gen(function* () {
21
+ if (!("installationId" in options || "owner" in options)) {
22
+ return Context.make(GitHubToken, Effect.map(appJwt(options), Option.some)).pipe(Context.add(TokenRefresh, undefined));
23
+ }
24
+ const client = yield* HttpClient.HttpClient;
25
+ const { apiUrl } = yield* GitHubConfig;
26
+ let installationId = "installationId" in options ? options.installationId : undefined;
27
+ const request = appRequests(client, apiUrl);
28
+ const exchange = Effect.gen(function* () {
29
+ const jwt = yield* appJwt(options);
30
+ if (installationId === undefined && "owner" in options && options.owner !== undefined) {
31
+ const path = `/repos/${encodeURIComponent(options.owner)}/${encodeURIComponent(options.repository)}/installation`;
32
+ installationId = (yield* request("GET", path, jwt, Installation)).id;
33
+ }
34
+ const access = yield* request("POST", `/app/installations/${installationId}/access_tokens`, jwt, AccessToken, {
35
+ permissions: options.scope?.permissions,
36
+ repositories: options.scope?.repositories,
37
+ "repository_ids": options.scope?.repositoryIds,
38
+ });
39
+ const now = yield* Clock.currentTimeMillis;
40
+ return { ...access, timeToLive: Math.max(0, access.expiresAt.getTime() - now - 300_000) };
41
+ });
42
+ const cache = yield* Cache.makeWith((_: undefined) => exchange, {
43
+ capacity: 1,
44
+ timeToLive: (exit) => (Exit.isSuccess(exit) ? exit.value.timeToLive : 0),
45
+ });
46
+ return Context.make(
47
+ GitHubToken,
48
+ Effect.map(Cache.get(cache, undefined), ({ token }) => Option.some(token)),
49
+ ).pipe(
50
+ Context.add(TokenRefresh, (rejected) =>
51
+ Cache.invalidateWhen(cache, undefined, ({ token }) => Option.isSome(rejected) && token === rejected.value),
52
+ ),
53
+ );
54
+ }),
55
+ );
56
+ }
57
+
58
+ function appRequests(client: HttpClient.HttpClient, apiUrl: string) {
59
+ const scoped = HttpClient.withScope(client);
60
+ const rates = rateLimits();
61
+ return Effect.fnUntraced(function* <TSchema extends Schema.Constraint>(
62
+ method: "GET" | "POST",
63
+ path: string,
64
+ jwt: Redacted.Redacted<string>,
65
+ schema: TSchema,
66
+ body?: unknown,
67
+ ) {
68
+ let input = HttpClientRequest.make(method)(new URL(path, apiUrl).href, {
69
+ headers: { Accept: "application/vnd.github+json" },
70
+ });
71
+ if (body !== undefined) {
72
+ input = yield* HttpClientRequest.bodyJson(input, body).pipe(Effect.mapError((cause) => new GitHubAppError({ reason: "encode" }, { cause })));
73
+ }
74
+ const response = yield* authenticatedRequest(
75
+ scoped,
76
+ Option.some(jwt),
77
+ rates,
78
+ )(input).pipe(
79
+ Effect.mapError((cause) => {
80
+ if (cause._tag === "GitHubRateLimited") {
81
+ return cause;
82
+ }
83
+ return cause._tag === "GitHubTransportError"
84
+ ? new GitHubAppError({ reason: "transport" }, { cause: cause.cause })
85
+ : new GitHubAppError({ reason: "status", status: "status" in cause ? cause.status : 403 });
86
+ }),
87
+ );
88
+ return yield* readBoundedJson(response, 64 * 1024, schema).pipe(
89
+ Effect.mapError((cause) => new GitHubAppError({ reason: cause._tag === "HttpClientError" ? "transport" : "response" }, { cause })),
90
+ );
91
+ }, Effect.scoped);
92
+ }