@effected/github 0.15.1 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,7 +25,7 @@ Hand-rolled octokit wrappers tend to converge on the same shape: a `rest<T>(oper
25
25
 
26
26
  The error model gets the same treatment. `GitHubError.kind` is a literal union (`notFound`, `alreadyExists`, `rejected`, `unauthorized`, `rateLimited`, `transport`, `decode`) produced by one classification step, `GitHubError.fromOctokit`, instead of one hand-written mapper per resource. `kind: "alreadyExists"` is what makes `GitBranch.upsert` and `GitTag.upsert` a single round trip in the common case, rather than a create-then-catch-then-check-then-reset dance repeated at every call site that needs it.
27
27
 
28
- This package also owns the octokit runtime so nothing downstream has to. `@octokit/rest` and `@octokit/auth-app` are deliberately absent — the rest wrapper is a request-logging plugin plus 1.4 MB of duplicate endpoint types, and `auth-app` drags in `createOAuthUserAuth`, roughly 492 KB of OAuth machinery this package never calls. GitHub App JWTs are signed by `universal-github-app-jwt` instead, the same zero-dependency signer `@octokit/auth-app` itself uses. A consumer that only authenticates with a token it already holds never links the JWT signer at all: the App-authenticated layer lives in its own module (`GitHubApp`), and nothing here is gathered into a namespace object that would defeat that split.
28
+ This package also owns the octokit runtime so nothing downstream has to. `@octokit/rest` and `@octokit/auth-app` are deliberately absent — the rest wrapper is a request-logging plugin plus 1.4 MB of duplicate endpoint types, and `auth-app` drags in `createOAuthUserAuth`, roughly 492 KB of OAuth machinery this package never calls. GitHub App JWTs are signed by the kit's own `@effected/jwt` instead: WebCrypto RS256 with no runtime dependencies, so App auth runs on Cloudflare Workers as well as Node. A consumer that only authenticates with a token it already holds never links the JWT signer at all: the App-authenticated layer lives in its own module (`GitHubApp`), and nothing here is gathered into a namespace object that would defeat that split.
29
29
 
30
30
  ## Install
31
31
 
package/Repo.js CHANGED
@@ -16,6 +16,15 @@ input: Schema.String }) {
16
16
  /**
17
17
  * Which repository an operation acts on.
18
18
  *
19
+ * @remarks
20
+ * **`RepoRef.make` validates at construction and throws** on an empty `owner`
21
+ * or `repo`, so inside an `Effect` a bad value dies rather than failing. That
22
+ * is right for a coordinate the program itself spells out, and wrong for one
23
+ * built from data: for a slug read from a database row, a config file or a
24
+ * webhook, use {@link RepoRef.parse}, which fails with a typed
25
+ * {@link InvalidRepoRefError} instead (or {@link RepoRef.parseResult}
26
+ * outside an `Effect`).
27
+ *
19
28
  * @public
20
29
  */
21
30
  var RepoRef = class RepoRef extends Schema.Class("RepoRef")({
@@ -41,7 +50,13 @@ var RepoRef = class RepoRef extends Schema.Class("RepoRef")({
41
50
  repo
42
51
  }));
43
52
  }
44
- /** Parse `"owner/repo"`. */
53
+ /**
54
+ * Parse `"owner/repo"`, failing with a typed {@link InvalidRepoRefError}.
55
+ *
56
+ * @remarks
57
+ * The typed path for building a `Repo` from stored data, such as a stored
58
+ * `full_name`: a malformed value fails here, where `make` would die.
59
+ */
45
60
  static parse = Effect.fn("RepoRef.parse")((slug) => Effect.fromResult(RepoRef.parseResult(slug)));
46
61
  /** `"owner/repo"`. */
47
62
  get slug() {
@@ -61,6 +61,7 @@ var WorkflowDispatch = class WorkflowDispatch extends Context.Service()("@effect
61
61
  static makeTest = (overrides = {}) => ({
62
62
  dispatch: overrides.dispatch ?? (() => unstubbed("dispatch")),
63
63
  runStatus: overrides.runStatus ?? (() => unstubbed("runStatus")),
64
+ cancelRun: overrides.cancelRun ?? (() => unstubbed("cancelRun")),
64
65
  list: overrides.list ?? Effect.sync(() => unstubbed("list")),
65
66
  dispatchAndWait: overrides.dispatchAndWait ?? (() => unstubbed("dispatchAndWait"))
66
67
  });
@@ -93,38 +94,53 @@ const make = (client) => {
93
94
  ...inputs !== void 0 ? { inputs } : {}
94
95
  });
95
96
  });
97
+ const runStatus = Effect.fn("WorkflowDispatch.runStatus")(function* (runId) {
98
+ const { owner, repo } = yield* Repo;
99
+ yield* Effect.annotateCurrentSpan({
100
+ owner,
101
+ repo,
102
+ runId
103
+ });
104
+ const raw = yield* client.request("GET /repos/{owner}/{repo}/actions/runs/{run_id}", {
105
+ owner,
106
+ repo,
107
+ run_id: runId
108
+ });
109
+ return statusOf(raw);
110
+ });
111
+ const list = Effect.fn("WorkflowDispatch.list")(function* () {
112
+ const { owner, repo } = yield* Repo;
113
+ yield* Effect.annotateCurrentSpan({
114
+ owner,
115
+ repo
116
+ });
117
+ return (yield* client.paginate("GET /repos/{owner}/{repo}/actions/workflows", {
118
+ owner,
119
+ repo
120
+ })).map((workflow) => ({
121
+ id: workflow.id,
122
+ name: workflow.name,
123
+ path: workflow.path,
124
+ state: workflow.state
125
+ }));
126
+ });
96
127
  return {
97
128
  dispatch,
98
- runStatus: Effect.fn("WorkflowDispatch.runStatus")(function* (runId) {
129
+ runStatus,
130
+ cancelRun: Effect.fn("WorkflowDispatch.cancelRun")(function* (runId) {
99
131
  const { owner, repo } = yield* Repo;
100
132
  yield* Effect.annotateCurrentSpan({
101
133
  owner,
102
134
  repo,
103
135
  runId
104
136
  });
105
- const raw = yield* client.request("GET /repos/{owner}/{repo}/actions/runs/{run_id}", {
137
+ return yield* client.request("POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel", {
106
138
  owner,
107
139
  repo,
108
140
  run_id: runId
109
- });
110
- return statusOf(raw);
141
+ }).pipe(Effect.as("cancelled"), Effect.catchIf((error) => error.status === 409, () => Effect.succeed("alreadyCompleted")));
111
142
  }),
112
- list: Effect.fn("WorkflowDispatch.list")(function* () {
113
- const { owner, repo } = yield* Repo;
114
- yield* Effect.annotateCurrentSpan({
115
- owner,
116
- repo
117
- });
118
- return (yield* client.paginate("GET /repos/{owner}/{repo}/actions/workflows", {
119
- owner,
120
- repo
121
- })).map((workflow) => ({
122
- id: workflow.id,
123
- name: workflow.name,
124
- path: workflow.path,
125
- state: workflow.state
126
- }));
127
- })(),
143
+ list: list(),
128
144
  dispatchAndWait: Effect.fn("WorkflowDispatch.dispatchAndWait")(function* (workflow, ref, options) {
129
145
  const { owner, repo } = yield* Repo;
130
146
  const interval = options?.poll?.interval ?? DEFAULT_INTERVAL;