@dxos/plugin-github 0.13.0 → 0.14.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 (43) hide show
  1. package/dist/lib/GitHubOperation.mjs +27 -1
  2. package/dist/lib/GitHubOperation.mjs.map +1 -1
  3. package/dist/lib/chunk-PullRequestArticle.mjs +31 -11
  4. package/dist/lib/chunk-PullRequestArticle.mjs.map +1 -1
  5. package/dist/lib/chunk-import-pull-request.mjs +78 -3
  6. package/dist/lib/chunk-import-pull-request.mjs.map +1 -1
  7. package/dist/lib/chunk-refresh-pull-requests.mjs +49 -0
  8. package/dist/lib/chunk-refresh-pull-requests.mjs.map +1 -0
  9. package/dist/lib/chunk-sync-pull-request.mjs +11 -9
  10. package/dist/lib/chunk-sync-pull-request.mjs.map +1 -1
  11. package/dist/lib/operations.mjs +2 -1
  12. package/dist/lib/operations.mjs.map +1 -1
  13. package/dist/types/src/components/PullRequestOverview/CheckRunList.d.ts +5 -2
  14. package/dist/types/src/components/PullRequestOverview/CheckRunList.d.ts.map +1 -1
  15. package/dist/types/src/components/PullRequestOverview/CheckRunList.test.d.ts +2 -0
  16. package/dist/types/src/components/PullRequestOverview/CheckRunList.test.d.ts.map +1 -0
  17. package/dist/types/src/components/PullRequestStatus/PullRequestStatus.d.ts.map +1 -1
  18. package/dist/types/src/operations/import-pull-request.d.ts.map +1 -1
  19. package/dist/types/src/operations/index.d.ts.map +1 -1
  20. package/dist/types/src/operations/refresh-pull-requests.d.ts +5 -0
  21. package/dist/types/src/operations/refresh-pull-requests.d.ts.map +1 -0
  22. package/dist/types/src/operations/refresh.d.ts +37 -0
  23. package/dist/types/src/operations/refresh.d.ts.map +1 -0
  24. package/dist/types/src/operations/refresh.test.d.ts +2 -0
  25. package/dist/types/src/operations/refresh.test.d.ts.map +1 -0
  26. package/dist/types/src/operations/sync-pull-request.d.ts.map +1 -1
  27. package/dist/types/src/stories/PullRequestOverview.stories.d.ts.map +1 -1
  28. package/dist/types/src/types/GitHubOperation.d.ts +11 -0
  29. package/dist/types/src/types/GitHubOperation.d.ts.map +1 -1
  30. package/dist/types/tsconfig.tsbuildinfo +1 -1
  31. package/package.json +42 -42
  32. package/src/components/PullRequestOverview/ArtifactPill.tsx +1 -1
  33. package/src/components/PullRequestOverview/CheckRunList.test.ts +29 -0
  34. package/src/components/PullRequestOverview/CheckRunList.tsx +28 -7
  35. package/src/components/PullRequestStatus/PullRequestStatus.tsx +8 -5
  36. package/src/operations/import-pull-request.ts +8 -0
  37. package/src/operations/index.ts +1 -0
  38. package/src/operations/refresh-pull-requests.ts +69 -0
  39. package/src/operations/refresh.test.ts +112 -0
  40. package/src/operations/refresh.ts +111 -0
  41. package/src/operations/sync-pull-request.ts +10 -13
  42. package/src/stories/PullRequestOverview.stories.tsx +2 -1
  43. package/src/types/GitHubOperation.ts +26 -0
@@ -1,17 +1,86 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
1
2
  import { r as parsePullRequestReference } from "./chunk-github-link.mjs";
2
3
  import { l as fetchPullRequest, t as GitHubCredentials, y as responseStatus } from "./chunk-github-api.mjs";
3
- import { n as toPullRequestProps } from "./chunk-pull-request.mjs";
4
+ import { n as toPullRequestProps, t as pullRequestChanges } from "./chunk-pull-request.mjs";
4
5
  import { i as GitHubRepoInaccessibleError, n as GitHubPullRequestReferenceError } from "./chunk-errors.mjs";
5
6
  import { n as githubToken } from "./chunk-pull-request2.mjs";
6
7
  import { GitHubOperation } from "#types";
7
8
  import * as Operation from "@dxos/compute/Operation";
8
9
  import * as Effect from "effect/Effect";
9
10
  import { PullRequest } from "@dxos/types";
10
- import { Database, Filter, Ref } from "@dxos/echo";
11
+ import { Database, Filter, Obj, Ref } from "@dxos/echo";
11
12
  import * as Layer from "effect/Layer";
12
13
  import * as FetchHttpClient from "effect/http/FetchHttpClient";
14
+ import { log } from "@dxos/log";
13
15
  import * as SpaceOperation from "@dxos/plugin-space/SpaceOperation";
16
+ import * as Trigger from "@dxos/compute/Trigger";
17
+ //#region src/operations/refresh.ts
18
+ /**
19
+ * How often the space's refresh trigger polls its open pull requests: hourly, at an off-the-hour minute
20
+ * so the fleet of spaces does not land on EDGE's busiest tick, and because every open pull request
21
+ * costs a GitHub request against the connection's rate limit.
22
+ */
23
+ var REFRESH_CRON = "17 * * * *";
24
+ /** States GitHub can still move a pull request out of; a closed or merged one is settled. */
25
+ var IN_FLIGHT_STATES = ["open", "draft"];
26
+ /**
27
+ * Re-read one stored pull request from GitHub and write back the fields that changed.
28
+ *
29
+ * Uses the anonymous fallback, so a public pull request still refreshes behind a revoked token.
30
+ * Returns the names of the changed fields.
31
+ */
32
+ var refreshPullRequest = Effect.fn("refreshPullRequest")(function* (pullRequest, token) {
33
+ const pull = yield* fetchPullRequestWithFallback(pullRequest, token);
34
+ const changes = pullRequestChanges(pullRequest, pull);
35
+ const updated = Object.keys(changes);
36
+ if (updated.length > 0) Obj.update(pullRequest, (pullRequest) => {
37
+ Object.assign(pullRequest, changes);
38
+ });
39
+ return updated;
40
+ });
41
+ /** Code-unit order, so every peer and EDGE agree on it regardless of locale. */
42
+ var byId = (left, right) => left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
43
+ /**
44
+ * The slice of `pullRequests` the run in window `window` refreshes: consecutive windows walk the list in
45
+ * id order and wrap, so every pull request is refreshed once every `ceil(count / size)` runs without
46
+ * storing a cursor.
47
+ */
48
+ var selectRefreshBatch = (pullRequests, window, size = 20) => {
49
+ if (pullRequests.length <= size) return [...pullRequests];
50
+ const ordered = [...pullRequests].sort(byId);
51
+ const start = window * size % ordered.length;
52
+ return Array.from({ length: size }, (_, index) => ordered[(start + index) % ordered.length]);
53
+ };
54
+ /** The space's pull requests GitHub may still change. */
55
+ var queryInFlightPullRequests = () => Database.query(Filter.type(PullRequest.PullRequest)).run.pipe(Effect.map((pullRequests) => pullRequests.filter((pullRequest) => IN_FLIGHT_STATES.includes(pullRequest.state))), Effect.orDie);
56
+ var isRefreshTrigger = (trigger) => trigger.runnable?.uri === GitHubOperation.RefreshPullRequests.meta.key.toString();
57
+ /**
58
+ * Give the space its one pull-request refresh trigger, unless it has one already — including one the
59
+ * user disabled, which stays disabled.
60
+ *
61
+ * Peers that race to create it each add their own, so every caller converges on the same keeper (the
62
+ * lowest id) and removes the rest. The trigger runs on EDGE, so pull requests keep refreshing while no
63
+ * client has the space open.
64
+ */
65
+ var ensureRefreshTrigger = Effect.fn("ensureRefreshTrigger")(function* () {
66
+ const [keeper, ...duplicates] = (yield* Database.query(Filter.type(Trigger.Trigger)).run.pipe(Effect.orDie)).filter(isRefreshTrigger).sort(byId);
67
+ for (const duplicate of duplicates) yield* Database.remove(duplicate);
68
+ if (keeper) return keeper;
69
+ return yield* Database.add(Trigger.make({
70
+ enabled: true,
71
+ remote: true,
72
+ spec: Trigger.specTimer(REFRESH_CRON),
73
+ runnable: Ref.fromURI(GitHubOperation.RefreshPullRequests.meta.key),
74
+ input: {}
75
+ }));
76
+ });
77
+ //#endregion
14
78
  //#region src/operations/import-pull-request.ts
79
+ var import_pull_request_exports = /* @__PURE__ */ __exportAll({
80
+ default: () => handler,
81
+ fetchPullRequestWithFallback: () => fetchPullRequestWithFallback
82
+ });
83
+ var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-github/src/operations/import-pull-request.ts";
15
84
  /**
16
85
  * Statuses that may report the token's reach rather than the repository's absence, and so are worth
17
86
  * a second, anonymous attempt.
@@ -85,12 +154,18 @@ var handler = GitHubOperation.ImportPullRequest.pipe(Operation.withHandler(Effec
85
154
  const pull = yield* fetchPullRequestWithFallback(parsed, yield* githubToken());
86
155
  const { object } = yield* Operation.invoke(SpaceOperation.AddObject, { object: PullRequest.make(toPullRequestProps(parsed, pull)) });
87
156
  if (!PullRequest.instanceOf(object)) return yield* Effect.die(new GitHubPullRequestReferenceError({ context: { reference } }));
157
+ yield* ensureRefreshTrigger().pipe(Effect.catchDefect((defect) => Effect.sync(() => log.warn("refresh trigger setup failed", { defect }, {
158
+ "~LogMeta": "~LogMeta",
159
+ F: __dxlog_file,
160
+ L: 141,
161
+ S: this
162
+ }))));
88
163
  return {
89
164
  pullRequest: Ref.make(object),
90
165
  imported: true
91
166
  };
92
167
  }, Effect.provide(FetchHttpClient.layer))));
93
168
  //#endregion
94
- export { handler as default, fetchPullRequestWithFallback };
169
+ export { selectRefreshBatch as a, refreshPullRequest as i, ensureRefreshTrigger as n, queryInFlightPullRequests as r, import_pull_request_exports as t };
95
170
 
96
171
  //# sourceMappingURL=chunk-import-pull-request.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-import-pull-request.mjs","names":[],"sources":["../../src/operations/import-pull-request.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\nimport * as Layer from 'effect/Layer';\n\nimport * as Operation from '@dxos/compute/Operation';\nimport { Database, Filter, Ref } from '@dxos/echo';\nimport * as SpaceOperation from '@dxos/plugin-space/SpaceOperation';\nimport { PullRequest } from '@dxos/types';\n\nimport { GitHubOperation } from '#types';\n\nimport { GitHubPullRequestReferenceError, GitHubRepoInaccessibleError } from '../errors.ts';\nimport { type PullRequestReference, parsePullRequestReference } from '../github-link.ts';\nimport { toPullRequestProps } from '../pull-request.ts';\nimport { GitHubApi } from '../services/index.ts';\nimport { githubToken } from './pull-request.ts';\n\n/**\n * Statuses that may report the token's reach rather than the repository's absence, and so are worth\n * a second, anonymous attempt.\n *\n * 404 is the load-bearing one. GitHub answers 404 rather than 403 wherever a credential lacks access,\n * so as not to confirm what it cannot show, and a GitHub App user-to-server token — what this\n * connector holds — reaches only the repositories the App is installed on. A public repository the\n * App was never installed on therefore reads as absent. (A fine-grained PAT would not behave this\n * way: those carry read access to every public repository regardless of their selection.)\n *\n * Whatever produced it, the rule is the same: a status that a credential could have caused says\n * nothing about what an anonymous reader can see, and only the anonymous request settles it.\n */\nconst MAY_REFLECT_TOKEN_SCOPE = new Set([401, 403, 404]);\n\n/**\n * The pull request as the space's GitHub connection, falling back to an anonymous read whenever the\n * stored token is what stood in the way.\n *\n * A public pull request must never fail because of a credential. Three separate conditions make one\n * look unreachable — a revoked token (401), a suspended or SSO-blocked one (403), and a repository\n * outside the App installation the token belongs to (404) — and the anonymous retry, which is the\n * same request a space with no connection would make, resolves all three. The cost is one extra\n * request on a pull request that genuinely does not exist.\n *\n * `fetch` is injected so the fallback can be exercised without an HTTP client.\n */\nexport const fetchPullRequestWithFallback = (\n { owner, repo, number }: PullRequestReference,\n token: string,\n fetch: (\n owner: string,\n repo: string,\n number: number,\n ) => GitHubApi.GitHubEffect<GitHubApi.GitHubPull> = GitHubApi.fetchPullRequest,\n) =>\n // Suspended so each run starts with its own `tokenStatus`, which the fallback sets as it runs.\n Effect.suspend(() => {\n const fetchAs = (token: string) =>\n fetch(owner, repo, number).pipe(Effect.provide(Layer.succeed(GitHubApi.GitHubCredentials, { token })));\n\n // What the authenticated attempt answered, kept so a rejected credential (401) can be told from a\n // repository the credential simply does not reach (403/404) once the retry has also failed.\n let tokenStatus: number | undefined;\n\n return fetchAs(token).pipe(\n Effect.catchIf(\n (error) => {\n const status = GitHubApi.responseStatus(error);\n return token !== '' && status !== undefined && MAY_REFLECT_TOKEN_SCOPE.has(status);\n },\n (error) => {\n tokenStatus = GitHubApi.responseStatus(error);\n return fetchAs('');\n },\n ),\n // Out of reach anonymously too (GitHub answers 404 for a private repository seen without\n // credentials): a typed failure lets the dialog name the connection rather than the reference.\n Effect.catchIf(\n (error) => {\n const status = GitHubApi.responseStatus(error);\n return status !== undefined && MAY_REFLECT_TOKEN_SCOPE.has(status);\n },\n (error) =>\n Effect.die(\n new GitHubRepoInaccessibleError({\n context: {\n owner,\n repo,\n number,\n status: GitHubApi.responseStatus(error),\n connected: token !== '',\n tokenStatus,\n },\n }),\n ),\n ),\n Effect.orDie,\n );\n });\n\n/**\n * Import a pull request the user named, as the space's GitHub connection or anonymously.\n *\n * The object is filed through `SpaceOperation.AddObject` rather than added directly: an imported\n * pull request is something the user went looking for, so it belongs where they can find it again.\n */\nconst handler: Operation.WithHandler<typeof GitHubOperation.ImportPullRequest> = GitHubOperation.ImportPullRequest.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ reference }) {\n const parsed = parsePullRequestReference(reference);\n if (!parsed) {\n return yield* Effect.die(new GitHubPullRequestReferenceError({ context: { reference } }));\n }\n\n const { owner, repo, number } = parsed;\n const [existing] = yield* Database.query(Filter.type(PullRequest.PullRequest, { owner, repo, number })).run.pipe(\n Effect.orDie,\n );\n if (existing) {\n return { pullRequest: Ref.make(existing), imported: false };\n }\n\n const pull = yield* fetchPullRequestWithFallback(parsed, yield* githubToken());\n\n const { object } = yield* Operation.invoke(SpaceOperation.AddObject, {\n object: PullRequest.make(toPullRequestProps(parsed, pull)),\n });\n // `AddObject` answers with what it filed, typed as any object; the narrowing is what makes the\n // returned ref a pull request's rather than a cast.\n if (!PullRequest.instanceOf(object)) {\n return yield* Effect.die(new GitHubPullRequestReferenceError({ context: { reference } }));\n }\n\n return { pullRequest: Ref.make(object), imported: true };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n);\n\nexport default handler;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,IAAM,0CAA0B,IAAI,IAAI;CAAC;CAAK;CAAK;AAAG,CAAC;;;;;;;;;;;;;AAcvD,IAAa,gCACX,EAAE,OAAO,MAAM,UACf,OACA,QAIoD,qBAGpD,OAAO,cAAc;CACnB,MAAM,WAAW,UACf,MAAM,OAAO,MAAM,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,MAAM,QAAQ,mBAA6B,EAAE,MAAM,CAAC,CAAC,CAAC;CAIvG,IAAI;CAEJ,OAAO,QAAQ,KAAK,CAAC,CAAC,KACpB,OAAO,SACJ,UAAU;EACT,MAAM,SAAS,eAAyB,KAAK;EAC7C,OAAO,UAAU,MAAM,WAAW,KAAA,KAAa,wBAAwB,IAAI,MAAM;CACnF,IACC,UAAU;EACT,cAAc,eAAyB,KAAK;EAC5C,OAAO,QAAQ,EAAE;CACnB,CACF,GAGA,OAAO,SACJ,UAAU;EACT,MAAM,SAAS,eAAyB,KAAK;EAC7C,OAAO,WAAW,KAAA,KAAa,wBAAwB,IAAI,MAAM;CACnE,IACC,UACC,OAAO,IACL,IAAI,4BAA4B,EAC9B,SAAS;EACP;EACA;EACA;EACA,QAAQ,eAAyB,KAAK;EACtC,WAAW,UAAU;EACrB;CACF,EACF,CAAC,CACH,CACJ,GACA,OAAO,KACT;AACF,CAAC;;;;;;;AAQH,IAAM,UAA2E,gBAAgB,kBAAkB,KACjH,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa;CAClC,MAAM,SAAS,0BAA0B,SAAS;CAClD,IAAI,CAAC,QACH,OAAO,OAAO,OAAO,IAAI,IAAI,gCAAgC,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;CAG1F,MAAM,EAAE,OAAO,MAAM,WAAW;CAChC,MAAM,CAAC,YAAY,OAAO,SAAS,MAAM,OAAO,KAAK,YAAY,aAAa;EAAE;EAAO;EAAM;CAAO,CAAC,CAAC,CAAC,CAAC,IAAI,KAC1G,OAAO,KACT;CACA,IAAI,UACF,OAAO;EAAE,aAAa,IAAI,KAAK,QAAQ;EAAG,UAAU;CAAM;CAG5D,MAAM,OAAO,OAAO,6BAA6B,QAAQ,OAAO,YAAY,CAAC;CAE7E,MAAM,EAAE,WAAW,OAAO,UAAU,OAAO,eAAe,WAAW,EACnE,QAAQ,YAAY,KAAK,mBAAmB,QAAQ,IAAI,CAAC,EAC3D,CAAC;CAGD,IAAI,CAAC,YAAY,WAAW,MAAM,GAChC,OAAO,OAAO,OAAO,IAAI,IAAI,gCAAgC,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;CAG1F,OAAO;EAAE,aAAa,IAAI,KAAK,MAAM;EAAG,UAAU;CAAK;AACzD,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
1
+ {"version":3,"file":"chunk-import-pull-request.mjs","names":[],"sources":["../../src/operations/refresh.ts","../../src/operations/import-pull-request.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Trigger from '@dxos/compute/Trigger';\nimport { Database, Filter, Obj, Ref } from '@dxos/echo';\nimport { PullRequest } from '@dxos/types';\n\nimport { GitHubOperation } from '#types';\n\nimport { pullRequestChanges } from '../pull-request.ts';\nimport { fetchPullRequestWithFallback } from './import-pull-request.ts';\n\n/**\n * How often the space's refresh trigger polls its open pull requests: hourly, at an off-the-hour minute\n * so the fleet of spaces does not land on EDGE's busiest tick, and because every open pull request\n * costs a GitHub request against the connection's rate limit.\n */\nexport const REFRESH_CRON = '17 * * * *';\n\n/** States GitHub can still move a pull request out of; a closed or merged one is settled. */\nconst IN_FLIGHT_STATES: readonly PullRequest.State[] = ['open', 'draft'];\n\n/**\n * Re-read one stored pull request from GitHub and write back the fields that changed.\n *\n * Uses the anonymous fallback, so a public pull request still refreshes behind a revoked token.\n * Returns the names of the changed fields.\n */\nexport const refreshPullRequest = Effect.fn('refreshPullRequest')(function* (\n pullRequest: PullRequest.PullRequest,\n token: string,\n) {\n const pull = yield* fetchPullRequestWithFallback(pullRequest, token);\n const changes = pullRequestChanges(pullRequest, pull);\n const updated = Object.keys(changes);\n if (updated.length > 0) {\n Obj.update(pullRequest, (pullRequest) => {\n Object.assign(pullRequest, changes);\n });\n }\n\n return updated;\n});\n\n/** Code-unit order, so every peer and EDGE agree on it regardless of locale. */\nconst byId = (left: { id: string }, right: { id: string }): number =>\n left.id < right.id ? -1 : left.id > right.id ? 1 : 0;\n\n/** Most pull requests one run refreshes, so a run stays within GitHub's rate limit and EDGE's subrequest budget. */\nexport const REFRESH_BATCH_SIZE = 20;\n\n/**\n * The slice of `pullRequests` the run in window `window` refreshes: consecutive windows walk the list in\n * id order and wrap, so every pull request is refreshed once every `ceil(count / size)` runs without\n * storing a cursor.\n */\nexport const selectRefreshBatch = (\n pullRequests: readonly PullRequest.PullRequest[],\n window: number,\n size = REFRESH_BATCH_SIZE,\n): PullRequest.PullRequest[] => {\n if (pullRequests.length <= size) {\n return [...pullRequests];\n }\n const ordered = [...pullRequests].sort(byId);\n const start = (window * size) % ordered.length;\n return Array.from({ length: size }, (_, index) => ordered[(start + index) % ordered.length]);\n};\n\n/** The space's pull requests GitHub may still change. */\nexport const queryInFlightPullRequests = () =>\n Database.query(Filter.type(PullRequest.PullRequest)).run.pipe(\n Effect.map((pullRequests) => pullRequests.filter((pullRequest) => IN_FLIGHT_STATES.includes(pullRequest.state))),\n Effect.orDie,\n );\n\nconst isRefreshTrigger = (trigger: Trigger.Trigger): boolean =>\n trigger.runnable?.uri === GitHubOperation.RefreshPullRequests.meta.key.toString();\n\n/**\n * Give the space its one pull-request refresh trigger, unless it has one already — including one the\n * user disabled, which stays disabled.\n *\n * Peers that race to create it each add their own, so every caller converges on the same keeper (the\n * lowest id) and removes the rest. The trigger runs on EDGE, so pull requests keep refreshing while no\n * client has the space open.\n */\nexport const ensureRefreshTrigger = Effect.fn('ensureRefreshTrigger')(function* () {\n const triggers = yield* Database.query(Filter.type(Trigger.Trigger)).run.pipe(Effect.orDie);\n const [keeper, ...duplicates] = triggers.filter(isRefreshTrigger).sort(byId);\n for (const duplicate of duplicates) {\n yield* Database.remove(duplicate);\n }\n if (keeper) {\n return keeper;\n }\n\n return yield* Database.add(\n Trigger.make({\n enabled: true,\n remote: true,\n spec: Trigger.specTimer(REFRESH_CRON),\n // Statically defined in the registry, so referred to by key rather than copied into the space.\n runnable: Ref.fromURI(GitHubOperation.RefreshPullRequests.meta.key),\n input: {},\n }),\n );\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\nimport * as Layer from 'effect/Layer';\n\nimport * as Operation from '@dxos/compute/Operation';\nimport { Database, Filter, Ref } from '@dxos/echo';\nimport { log } from '@dxos/log';\nimport * as SpaceOperation from '@dxos/plugin-space/SpaceOperation';\nimport { PullRequest } from '@dxos/types';\n\nimport { GitHubOperation } from '#types';\n\nimport { GitHubPullRequestReferenceError, GitHubRepoInaccessibleError } from '../errors.ts';\nimport { type PullRequestReference, parsePullRequestReference } from '../github-link.ts';\nimport { toPullRequestProps } from '../pull-request.ts';\nimport { GitHubApi } from '../services/index.ts';\nimport { githubToken } from './pull-request.ts';\nimport { ensureRefreshTrigger } from './refresh.ts';\n\n/**\n * Statuses that may report the token's reach rather than the repository's absence, and so are worth\n * a second, anonymous attempt.\n *\n * 404 is the load-bearing one. GitHub answers 404 rather than 403 wherever a credential lacks access,\n * so as not to confirm what it cannot show, and a GitHub App user-to-server token — what this\n * connector holds — reaches only the repositories the App is installed on. A public repository the\n * App was never installed on therefore reads as absent. (A fine-grained PAT would not behave this\n * way: those carry read access to every public repository regardless of their selection.)\n *\n * Whatever produced it, the rule is the same: a status that a credential could have caused says\n * nothing about what an anonymous reader can see, and only the anonymous request settles it.\n */\nconst MAY_REFLECT_TOKEN_SCOPE = new Set([401, 403, 404]);\n\n/**\n * The pull request as the space's GitHub connection, falling back to an anonymous read whenever the\n * stored token is what stood in the way.\n *\n * A public pull request must never fail because of a credential. Three separate conditions make one\n * look unreachable — a revoked token (401), a suspended or SSO-blocked one (403), and a repository\n * outside the App installation the token belongs to (404) — and the anonymous retry, which is the\n * same request a space with no connection would make, resolves all three. The cost is one extra\n * request on a pull request that genuinely does not exist.\n *\n * `fetch` is injected so the fallback can be exercised without an HTTP client.\n */\nexport const fetchPullRequestWithFallback = (\n { owner, repo, number }: PullRequestReference,\n token: string,\n fetch: (\n owner: string,\n repo: string,\n number: number,\n ) => GitHubApi.GitHubEffect<GitHubApi.GitHubPull> = GitHubApi.fetchPullRequest,\n) =>\n // Suspended so each run starts with its own `tokenStatus`, which the fallback sets as it runs.\n Effect.suspend(() => {\n const fetchAs = (token: string) =>\n fetch(owner, repo, number).pipe(Effect.provide(Layer.succeed(GitHubApi.GitHubCredentials, { token })));\n\n // What the authenticated attempt answered, kept so a rejected credential (401) can be told from a\n // repository the credential simply does not reach (403/404) once the retry has also failed.\n let tokenStatus: number | undefined;\n\n return fetchAs(token).pipe(\n Effect.catchIf(\n (error) => {\n const status = GitHubApi.responseStatus(error);\n return token !== '' && status !== undefined && MAY_REFLECT_TOKEN_SCOPE.has(status);\n },\n (error) => {\n tokenStatus = GitHubApi.responseStatus(error);\n return fetchAs('');\n },\n ),\n // Out of reach anonymously too (GitHub answers 404 for a private repository seen without\n // credentials): a typed failure lets the dialog name the connection rather than the reference.\n Effect.catchIf(\n (error) => {\n const status = GitHubApi.responseStatus(error);\n return status !== undefined && MAY_REFLECT_TOKEN_SCOPE.has(status);\n },\n (error) =>\n Effect.die(\n new GitHubRepoInaccessibleError({\n context: {\n owner,\n repo,\n number,\n status: GitHubApi.responseStatus(error),\n connected: token !== '',\n tokenStatus,\n },\n }),\n ),\n ),\n Effect.orDie,\n );\n });\n\n/**\n * Import a pull request the user named, as the space's GitHub connection or anonymously.\n *\n * The object is filed through `SpaceOperation.AddObject` rather than added directly: an imported\n * pull request is something the user went looking for, so it belongs where they can find it again.\n */\nconst handler: Operation.WithHandler<typeof GitHubOperation.ImportPullRequest> = GitHubOperation.ImportPullRequest.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ reference }) {\n const parsed = parsePullRequestReference(reference);\n if (!parsed) {\n return yield* Effect.die(new GitHubPullRequestReferenceError({ context: { reference } }));\n }\n\n const { owner, repo, number } = parsed;\n const [existing] = yield* Database.query(Filter.type(PullRequest.PullRequest, { owner, repo, number })).run.pipe(\n Effect.orDie,\n );\n if (existing) {\n return { pullRequest: Ref.make(existing), imported: false };\n }\n\n const pull = yield* fetchPullRequestWithFallback(parsed, yield* githubToken());\n\n const { object } = yield* Operation.invoke(SpaceOperation.AddObject, {\n object: PullRequest.make(toPullRequestProps(parsed, pull)),\n });\n // `AddObject` answers with what it filed, typed as any object; the narrowing is what makes the\n // returned ref a pull request's rather than a cast.\n if (!PullRequest.instanceOf(object)) {\n return yield* Effect.die(new GitHubPullRequestReferenceError({ context: { reference } }));\n }\n\n // The first pull request a space holds is what makes refreshing them worth a schedule.\n yield* ensureRefreshTrigger().pipe(\n // The import already succeeded; a missing schedule is recovered the next time a pull request opens.\n Effect.catchDefect((defect) => Effect.sync(() => log.warn('refresh trigger setup failed', { defect }))),\n );\n\n return { pullRequest: Ref.make(object), imported: true };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n);\n\nexport default handler;\n"],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import { n as githubToken } from "./chunk-pull-request2.mjs";
2
+ import { a as selectRefreshBatch, i as refreshPullRequest, n as ensureRefreshTrigger, r as queryInFlightPullRequests } from "./chunk-import-pull-request.mjs";
3
+ import { GitHubOperation } from "#types";
4
+ import * as Operation from "@dxos/compute/Operation";
5
+ import * as Effect from "effect/Effect";
6
+ import * as FetchHttpClient from "effect/http/FetchHttpClient";
7
+ import { log } from "@dxos/log";
8
+ import * as Clock from "effect/Clock";
9
+ //#region src/operations/refresh-pull-requests.ts
10
+ var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-github/src/operations/refresh-pull-requests.ts";
11
+ /** Bounded so a space with many open pull requests does not burst GitHub's secondary rate limit. */
12
+ var REFRESH_CONCURRENCY = 2;
13
+ /** The hourly `REFRESH_CRON` period, so each scheduled run lands in its own batch window. */
14
+ var REFRESH_INTERVAL_MS = 36e5;
15
+ var handler = GitHubOperation.RefreshPullRequests.pipe(Operation.withHandler(Effect.fn(function* () {
16
+ yield* ensureRefreshTrigger();
17
+ const inFlight = yield* queryInFlightPullRequests();
18
+ if (inFlight.length === 0) return {
19
+ checked: 0,
20
+ updated: 0,
21
+ failed: 0
22
+ };
23
+ const window = Math.floor((yield* Clock.currentTimeMillis) / REFRESH_INTERVAL_MS);
24
+ const pullRequests = selectRefreshBatch(inFlight, window);
25
+ const token = yield* githubToken();
26
+ const results = yield* Effect.forEach(pullRequests, (pullRequest) => refreshPullRequest(pullRequest, token).pipe(Effect.map((updated) => updated.length > 0 ? "updated" : "unchanged"), Effect.catchDefect((cause) => Effect.sync(() => {
27
+ log.warn("pull request refresh failed", {
28
+ owner: pullRequest.owner,
29
+ repo: pullRequest.repo,
30
+ number: pullRequest.number,
31
+ cause
32
+ }, {
33
+ "~LogMeta": "~LogMeta",
34
+ F: __dxlog_file,
35
+ L: 47,
36
+ S: this
37
+ });
38
+ return "failed";
39
+ }))), { concurrency: REFRESH_CONCURRENCY });
40
+ return {
41
+ checked: pullRequests.length,
42
+ updated: results.filter((result) => result === "updated").length,
43
+ failed: results.filter((result) => result === "failed").length
44
+ };
45
+ }, Effect.provide(FetchHttpClient.layer))));
46
+ //#endregion
47
+ export { handler as default };
48
+
49
+ //# sourceMappingURL=chunk-refresh-pull-requests.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-refresh-pull-requests.mjs","names":[],"sources":["../../src/operations/refresh-pull-requests.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Clock from 'effect/Clock';\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\n\nimport * as Operation from '@dxos/compute/Operation';\nimport { log } from '@dxos/log';\n\nimport { GitHubOperation } from '#types';\n\nimport { githubToken } from './pull-request.ts';\nimport { ensureRefreshTrigger, queryInFlightPullRequests, refreshPullRequest, selectRefreshBatch } from './refresh.ts';\n\n/** Bounded so a space with many open pull requests does not burst GitHub's secondary rate limit. */\nconst REFRESH_CONCURRENCY = 2;\n\n/** The hourly `REFRESH_CRON` period, so each scheduled run lands in its own batch window. */\nconst REFRESH_INTERVAL_MS = 60 * 60 * 1000;\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.RefreshPullRequests> =\n GitHubOperation.RefreshPullRequests.pipe(\n Operation.withHandler(\n Effect.fn(function* () {\n // Collapses any duplicate a racing peer created, so the space keeps one schedule.\n yield* ensureRefreshTrigger();\n const inFlight = yield* queryInFlightPullRequests();\n if (inFlight.length === 0) {\n return { checked: 0, updated: 0, failed: 0 };\n }\n\n const window = Math.floor((yield* Clock.currentTimeMillis) / REFRESH_INTERVAL_MS);\n const pullRequests = selectRefreshBatch(inFlight, window);\n\n const token = yield* githubToken();\n const results = yield* Effect.forEach(\n pullRequests,\n (pullRequest) =>\n // One deleted or unreachable pull request must not fail the run: EDGE disables a trigger\n // after repeated failures, which would stop refreshing every other one.\n refreshPullRequest(pullRequest, token).pipe(\n Effect.map((updated) => (updated.length > 0 ? 'updated' : 'unchanged')),\n Effect.catchDefect((cause) =>\n Effect.sync(() => {\n log.warn('pull request refresh failed', {\n owner: pullRequest.owner,\n repo: pullRequest.repo,\n number: pullRequest.number,\n cause,\n });\n return 'failed' as const;\n }),\n ),\n ),\n { concurrency: REFRESH_CONCURRENCY },\n );\n\n return {\n checked: pullRequests.length,\n updated: results.filter((result) => result === 'updated').length,\n failed: results.filter((result) => result === 'failed').length,\n };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;;;;;AAiBA,IAAM,sBAAsB;;AAG5B,IAAM,sBAAsB;AAE5B,IAAM,UACJ,gBAAgB,oBAAoB,KAClC,UAAU,YACR,OAAO,GAAG,aAAa;CAErB,OAAO,qBAAqB;CAC5B,MAAM,WAAW,OAAO,0BAA0B;CAClD,IAAI,SAAS,WAAW,GACtB,OAAO;EAAE,SAAS;EAAG,SAAS;EAAG,QAAQ;CAAE;CAG7C,MAAM,SAAS,KAAK,OAAO,OAAO,MAAM,qBAAqB,mBAAmB;CAChF,MAAM,eAAe,mBAAmB,UAAU,MAAM;CAExD,MAAM,QAAQ,OAAO,YAAY;CACjC,MAAM,UAAU,OAAO,OAAO,QAC5B,eACC,gBAGC,mBAAmB,aAAa,KAAK,CAAC,CAAC,KACrC,OAAO,KAAK,YAAa,QAAQ,SAAS,IAAI,YAAY,WAAY,GACtE,OAAO,aAAa,UAClB,OAAO,WAAW;EAChB,IAAI,KAAK,+BAA+B;GACtC,OAAO,YAAY;GACnB,MAAM,YAAY;GAClB,QAAQ,YAAY;GACpB;EACF,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA;EAAA,CAAC;EACD,OAAO;CACT,CAAC,CACH,CACF,GACF,EAAE,aAAa,oBAAoB,CACrC;CAEA,OAAO;EACL,SAAS,aAAa;EACtB,SAAS,QAAQ,QAAQ,WAAW,WAAW,SAAS,CAAC,CAAC;EAC1D,QAAQ,QAAQ,QAAQ,WAAW,WAAW,QAAQ,CAAC,CAAC;CAC1D;AACF,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
@@ -1,21 +1,23 @@
1
- import { t as pullRequestChanges } from "./chunk-pull-request.mjs";
2
1
  import { n as githubToken, r as resolvePullRequest } from "./chunk-pull-request2.mjs";
3
- import { fetchPullRequestWithFallback } from "./chunk-import-pull-request.mjs";
2
+ import { i as refreshPullRequest, n as ensureRefreshTrigger } from "./chunk-import-pull-request.mjs";
4
3
  import { GitHubOperation } from "#types";
5
4
  import * as Operation from "@dxos/compute/Operation";
6
5
  import * as Effect from "effect/Effect";
7
- import { Database, Obj } from "@dxos/echo";
6
+ import { Database } from "@dxos/echo";
8
7
  import * as FetchHttpClient from "effect/http/FetchHttpClient";
8
+ import { log } from "@dxos/log";
9
9
  //#region src/operations/sync-pull-request.ts
10
+ var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-github/src/operations/sync-pull-request.ts";
10
11
  var handler = GitHubOperation.SyncPullRequest.pipe(Operation.withHandler(Effect.fn(function* ({ pullRequest: ref }) {
11
12
  const { pullRequest, db } = yield* resolvePullRequest(ref);
12
13
  const token = yield* githubToken().pipe(Effect.provide(Database.layer(db)));
13
- const pull = yield* fetchPullRequestWithFallback(pullRequest, token);
14
- const changes = pullRequestChanges(pullRequest, pull);
15
- const updated = Object.keys(changes);
16
- if (updated.length > 0) Obj.update(pullRequest, (pullRequest) => {
17
- Object.assign(pullRequest, changes);
18
- });
14
+ const updated = yield* refreshPullRequest(pullRequest, token);
15
+ yield* ensureRefreshTrigger().pipe(Effect.provide(Database.layer(db)), Effect.catchDefect((defect) => Effect.sync(() => log.warn("refresh trigger setup failed", { defect }, {
16
+ "~LogMeta": "~LogMeta",
17
+ F: __dxlog_file,
18
+ L: 27,
19
+ S: this
20
+ }))));
19
21
  return { updated };
20
22
  }, Effect.provide(FetchHttpClient.layer))));
21
23
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-sync-pull-request.mjs","names":[],"sources":["../../src/operations/sync-pull-request.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\n\nimport * as Operation from '@dxos/compute/Operation';\nimport { Database, Obj } from '@dxos/echo';\n\nimport { GitHubOperation } from '#types';\n\nimport { pullRequestChanges } from '../pull-request.ts';\nimport { fetchPullRequestWithFallback } from './import-pull-request.ts';\nimport { githubToken, resolvePullRequest } from './pull-request.ts';\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.SyncPullRequest> = GitHubOperation.SyncPullRequest.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: ref }) {\n const { pullRequest, db } = yield* resolvePullRequest(ref);\n const token = yield* githubToken().pipe(Effect.provide(Database.layer(db)));\n // With the anonymous fallback, so a public pull request still refreshes behind a revoked token.\n const pull = yield* fetchPullRequestWithFallback(pullRequest, token);\n const changes = pullRequestChanges(pullRequest, pull);\n const updated = Object.keys(changes);\n if (updated.length > 0) {\n Obj.update(pullRequest, (pullRequest) => {\n Object.assign(pullRequest, changes);\n });\n }\n\n return { updated };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n);\n\nexport default handler;\n"],"mappings":";;;;;;;;;AAgBA,IAAM,UAAyE,gBAAgB,gBAAgB,KAC7G,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,OAAO;CACzC,MAAM,EAAE,aAAa,OAAO,OAAO,mBAAmB,GAAG;CACzD,MAAM,QAAQ,OAAO,YAAY,CAAC,CAAC,KAAK,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,CAAC;CAE1E,MAAM,OAAO,OAAO,6BAA6B,aAAa,KAAK;CACnE,MAAM,UAAU,mBAAmB,aAAa,IAAI;CACpD,MAAM,UAAU,OAAO,KAAK,OAAO;CACnC,IAAI,QAAQ,SAAS,GACnB,IAAI,OAAO,cAAc,gBAAgB;EACvC,OAAO,OAAO,aAAa,OAAO;CACpC,CAAC;CAGH,OAAO,EAAE,QAAQ;AACnB,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
1
+ {"version":3,"file":"chunk-sync-pull-request.mjs","names":[],"sources":["../../src/operations/sync-pull-request.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\n\nimport * as Operation from '@dxos/compute/Operation';\nimport { Database } from '@dxos/echo';\nimport { log } from '@dxos/log';\n\nimport { GitHubOperation } from '#types';\n\nimport { githubToken, resolvePullRequest } from './pull-request.ts';\nimport { ensureRefreshTrigger, refreshPullRequest } from './refresh.ts';\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.SyncPullRequest> = GitHubOperation.SyncPullRequest.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: ref }) {\n const { pullRequest, db } = yield* resolvePullRequest(ref);\n const token = yield* githubToken().pipe(Effect.provide(Database.layer(db)));\n const updated = yield* refreshPullRequest(pullRequest, token);\n // Spaces that imported pull requests before the scheduled refresh existed get it on next open.\n yield* ensureRefreshTrigger().pipe(\n Effect.provide(Database.layer(db)),\n // The refresh already succeeded; the schedule is retried on the next open.\n Effect.catchDefect((defect) => Effect.sync(() => log.warn('refresh trigger setup failed', { defect }))),\n );\n return { updated };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n);\n\nexport default handler;\n"],"mappings":";;;;;;;;;;AAgBA,IAAM,UAAyE,gBAAgB,gBAAgB,KAC7G,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,OAAO;CACzC,MAAM,EAAE,aAAa,OAAO,OAAO,mBAAmB,GAAG;CACzD,MAAM,QAAQ,OAAO,YAAY,CAAC,CAAC,KAAK,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,CAAC;CAC1E,MAAM,UAAU,OAAO,mBAAmB,aAAa,KAAK;CAE5D,OAAO,qBAAqB,CAAC,CAAC,KAC5B,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,GAEjC,OAAO,aAAa,WAAW,OAAO,WAAW,IAAI,KAAK,gCAAgC,EAAE,OAAO,GAAA;EAAA,YAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA;CAAA,CAAC,CAAC,CAAC,CACxG;CACA,OAAO,EAAE,QAAQ;AACnB,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
@@ -7,13 +7,14 @@ var GitHubOperationHandlerSet = OperationHandlerSet.lazy([
7
7
  GitHubOperation.MaterializeGitHubTarget.pipe(Operation.lazyHandler(() => import("./chunk-materialize-target.mjs"))),
8
8
  GitHubOperation.SyncGitHubRepositories.pipe(Operation.lazyHandler(() => import("./chunk-sync.mjs"))),
9
9
  GitHubOperation.GenerateWalkthrough.pipe(Operation.lazyHandler(() => import("./chunk-generate-walkthrough.mjs"))),
10
- GitHubOperation.ImportPullRequest.pipe(Operation.lazyHandler(() => import("./chunk-import-pull-request.mjs"))),
10
+ GitHubOperation.ImportPullRequest.pipe(Operation.lazyHandler(() => import("./chunk-import-pull-request.mjs").then((n) => n.t))),
11
11
  GitHubOperation.ImportPullRequestFromSnapshot.pipe(Operation.lazyHandler(() => import("./chunk-import-pull-request-from-snapshot.mjs"))),
12
12
  GitHubOperation.SubmitPullRequestApproval.pipe(Operation.lazyHandler(() => import("./chunk-submit-pull-request-approval.mjs"))),
13
13
  GitHubOperation.AddPullRequestComment.pipe(Operation.lazyHandler(() => import("./chunk-add-pull-request-comment.mjs"))),
14
14
  GitHubOperation.AddPullRequestReviewComment.pipe(Operation.lazyHandler(() => import("./chunk-add-pull-request-review-comment.mjs"))),
15
15
  GitHubOperation.GetPullRequestStatus.pipe(Operation.lazyHandler(() => import("./chunk-get-pull-request-status.mjs"))),
16
16
  GitHubOperation.SyncPullRequest.pipe(Operation.lazyHandler(() => import("./chunk-sync-pull-request.mjs"))),
17
+ GitHubOperation.RefreshPullRequests.pipe(Operation.lazyHandler(() => import("./chunk-refresh-pull-requests.mjs"))),
17
18
  GitHubOperation.GetPullRequestDiff.pipe(Operation.lazyHandler(() => import("./chunk-get-pull-request-diff.mjs")))
18
19
  ]);
19
20
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"operations.mjs","names":[],"sources":["../../src/operations/index.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Operation from '@dxos/compute/Operation';\nimport * as OperationHandlerSet from '@dxos/compute/OperationHandlerSet';\n\nimport { GitHubOperation } from '#types';\n\nexport const GitHubOperationHandlerSet = OperationHandlerSet.lazy([\n GitHubOperation.GetGitHubRepositories.pipe(Operation.lazyHandler(() => import('./get-repositories.ts'))),\n GitHubOperation.MaterializeGitHubTarget.pipe(Operation.lazyHandler(() => import('./materialize-target.ts'))),\n GitHubOperation.SyncGitHubRepositories.pipe(Operation.lazyHandler(() => import('./sync.ts'))),\n GitHubOperation.GenerateWalkthrough.pipe(Operation.lazyHandler(() => import('./generate-walkthrough.ts'))),\n GitHubOperation.ImportPullRequest.pipe(Operation.lazyHandler(() => import('./import-pull-request.ts'))),\n GitHubOperation.ImportPullRequestFromSnapshot.pipe(\n Operation.lazyHandler(() => import('./import-pull-request-from-snapshot.ts')),\n ),\n GitHubOperation.SubmitPullRequestApproval.pipe(\n Operation.lazyHandler(() => import('./submit-pull-request-approval.ts')),\n ),\n GitHubOperation.AddPullRequestComment.pipe(Operation.lazyHandler(() => import('./add-pull-request-comment.ts'))),\n GitHubOperation.AddPullRequestReviewComment.pipe(\n Operation.lazyHandler(() => import('./add-pull-request-review-comment.ts')),\n ),\n GitHubOperation.GetPullRequestStatus.pipe(Operation.lazyHandler(() => import('./get-pull-request-status.ts'))),\n GitHubOperation.SyncPullRequest.pipe(Operation.lazyHandler(() => import('./sync-pull-request.ts'))),\n GitHubOperation.GetPullRequestDiff.pipe(Operation.lazyHandler(() => import('./get-pull-request-diff.ts'))),\n]);\n"],"mappings":";;;;AASA,IAAa,4BAA4B,oBAAoB,KAAK;CAChE,gBAAgB,sBAAsB,KAAK,UAAU,kBAAkB,OAAO,+BAAwB,CAAC;CACvG,gBAAgB,wBAAwB,KAAK,UAAU,kBAAkB,OAAO,iCAA0B,CAAC;CAC3G,gBAAgB,uBAAuB,KAAK,UAAU,kBAAkB,OAAO,mBAAY,CAAC;CAC5F,gBAAgB,oBAAoB,KAAK,UAAU,kBAAkB,OAAO,mCAA4B,CAAC;CACzG,gBAAgB,kBAAkB,KAAK,UAAU,kBAAkB,OAAO,kCAA2B,CAAC;CACtG,gBAAgB,8BAA8B,KAC5C,UAAU,kBAAkB,OAAO,gDAAyC,CAC9E;CACA,gBAAgB,0BAA0B,KACxC,UAAU,kBAAkB,OAAO,2CAAoC,CACzE;CACA,gBAAgB,sBAAsB,KAAK,UAAU,kBAAkB,OAAO,uCAAgC,CAAC;CAC/G,gBAAgB,4BAA4B,KAC1C,UAAU,kBAAkB,OAAO,8CAAuC,CAC5E;CACA,gBAAgB,qBAAqB,KAAK,UAAU,kBAAkB,OAAO,sCAA+B,CAAC;CAC7G,gBAAgB,gBAAgB,KAAK,UAAU,kBAAkB,OAAO,gCAAyB,CAAC;CAClG,gBAAgB,mBAAmB,KAAK,UAAU,kBAAkB,OAAO,oCAA6B,CAAC;AAC3G,CAAC"}
1
+ {"version":3,"file":"operations.mjs","names":[],"sources":["../../src/operations/index.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Operation from '@dxos/compute/Operation';\nimport * as OperationHandlerSet from '@dxos/compute/OperationHandlerSet';\n\nimport { GitHubOperation } from '#types';\n\nexport const GitHubOperationHandlerSet = OperationHandlerSet.lazy([\n GitHubOperation.GetGitHubRepositories.pipe(Operation.lazyHandler(() => import('./get-repositories.ts'))),\n GitHubOperation.MaterializeGitHubTarget.pipe(Operation.lazyHandler(() => import('./materialize-target.ts'))),\n GitHubOperation.SyncGitHubRepositories.pipe(Operation.lazyHandler(() => import('./sync.ts'))),\n GitHubOperation.GenerateWalkthrough.pipe(Operation.lazyHandler(() => import('./generate-walkthrough.ts'))),\n GitHubOperation.ImportPullRequest.pipe(Operation.lazyHandler(() => import('./import-pull-request.ts'))),\n GitHubOperation.ImportPullRequestFromSnapshot.pipe(\n Operation.lazyHandler(() => import('./import-pull-request-from-snapshot.ts')),\n ),\n GitHubOperation.SubmitPullRequestApproval.pipe(\n Operation.lazyHandler(() => import('./submit-pull-request-approval.ts')),\n ),\n GitHubOperation.AddPullRequestComment.pipe(Operation.lazyHandler(() => import('./add-pull-request-comment.ts'))),\n GitHubOperation.AddPullRequestReviewComment.pipe(\n Operation.lazyHandler(() => import('./add-pull-request-review-comment.ts')),\n ),\n GitHubOperation.GetPullRequestStatus.pipe(Operation.lazyHandler(() => import('./get-pull-request-status.ts'))),\n GitHubOperation.SyncPullRequest.pipe(Operation.lazyHandler(() => import('./sync-pull-request.ts'))),\n GitHubOperation.RefreshPullRequests.pipe(Operation.lazyHandler(() => import('./refresh-pull-requests.ts'))),\n GitHubOperation.GetPullRequestDiff.pipe(Operation.lazyHandler(() => import('./get-pull-request-diff.ts'))),\n]);\n"],"mappings":";;;;AASA,IAAa,4BAA4B,oBAAoB,KAAK;CAChE,gBAAgB,sBAAsB,KAAK,UAAU,kBAAkB,OAAO,+BAAwB,CAAC;CACvG,gBAAgB,wBAAwB,KAAK,UAAU,kBAAkB,OAAO,iCAA0B,CAAC;CAC3G,gBAAgB,uBAAuB,KAAK,UAAU,kBAAkB,OAAO,mBAAY,CAAC;CAC5F,gBAAgB,oBAAoB,KAAK,UAAU,kBAAkB,OAAO,mCAA4B,CAAC;CACzG,gBAAgB,kBAAkB,KAAK,UAAU,kBAAkB,OAAO,kCAA2B,CAAA,MAAA,MAAA,EAAA,CAAA,CAAA,CAAC;CACtG,gBAAgB,8BAA8B,KAC5C,UAAU,kBAAkB,OAAO,gDAAyC,CAC9E;CACA,gBAAgB,0BAA0B,KACxC,UAAU,kBAAkB,OAAO,2CAAoC,CACzE;CACA,gBAAgB,sBAAsB,KAAK,UAAU,kBAAkB,OAAO,uCAAgC,CAAC;CAC/G,gBAAgB,4BAA4B,KAC1C,UAAU,kBAAkB,OAAO,8CAAuC,CAC5E;CACA,gBAAgB,qBAAqB,KAAK,UAAU,kBAAkB,OAAO,sCAA+B,CAAC;CAC7G,gBAAgB,gBAAgB,KAAK,UAAU,kBAAkB,OAAO,gCAAyB,CAAC;CAClG,gBAAgB,oBAAoB,KAAK,UAAU,kBAAkB,OAAO,oCAA6B,CAAC;CAC1G,gBAAgB,mBAAmB,KAAK,UAAU,kBAAkB,OAAO,oCAA6B,CAAC;AAC3G,CAAC"}
@@ -1,7 +1,10 @@
1
1
  import React from 'react';
2
2
  import { type GitHubOperation } from '#types';
3
- /** `4m 12s`, or undefined for a run that has not both started and finished. */
4
- export declare const formatDuration: (startedAt?: string, completedAt?: string) => string | undefined;
3
+ /**
4
+ * `4m 12s` from start to finish, or to `now` for a run still in progress;
5
+ * undefined for a run that has not started, or has not finished when no `now` is given.
6
+ */
7
+ export declare const formatDuration: (startedAt?: string, completedAt?: string, now?: number) => string | undefined;
5
8
  /** Sorts runs by what needs attention, then by name so shards read in order. */
6
9
  export declare const sortCheckRuns: (runs: readonly GitHubOperation.CheckRun[]) => GitHubOperation.CheckRun[];
7
10
  export type CheckRunListProps = {
@@ -1 +1 @@
1
- {"version":3,"file":"CheckRunList.d.ts","sourceRoot":"","sources":["../../../../../src/components/PullRequestOverview/CheckRunList.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAOvC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAa9C,+EAA+E;AAC/E,eAAO,MAAM,cAAc,eAAgB,MAAM,gBAAgB,MAAM,KAAG,MAAM,GAAG,SAUlF,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,aAAa,SAAU,SAAS,eAAe,CAAC,QAAQ,EAAE,KAAG,eAAe,CAAC,QAAQ,EAK/F,CAAC;AAEJ,MAAM,MAAM,iBAAiB,GAAG;IAC9B,6CAA6C;IAC7C,IAAI,CAAC,EAAE,SAAS,eAAe,CAAC,QAAQ,EAAE,CAAC;CAC5C,CAAC;AAEF,gGAAgG;AAChG,eAAO,MAAM,YAAY,aAAc,iBAAiB,sBA0CvD,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,eAAe,UAAW,SAAS,eAAe,CAAC,QAAQ,EAAE,KAAG,MAuB5E,CAAC"}
1
+ {"version":3,"file":"CheckRunList.d.ts","sourceRoot":"","sources":["../../../../../src/components/PullRequestOverview/CheckRunList.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAO5D,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAa9C;;;GAGG;AACH,eAAO,MAAM,cAAc,eAAgB,MAAM,gBAAgB,MAAM,QAAQ,MAAM,KAAG,MAAM,GAAG,SAWhG,CAAC;AAgBF,gFAAgF;AAChF,eAAO,MAAM,aAAa,SAAU,SAAS,eAAe,CAAC,QAAQ,EAAE,KAAG,eAAe,CAAC,QAAQ,EAK/F,CAAC;AAEJ,MAAM,MAAM,iBAAiB,GAAG;IAC9B,6CAA6C;IAC7C,IAAI,CAAC,EAAE,SAAS,eAAe,CAAC,QAAQ,EAAE,CAAC;CAC5C,CAAC;AAEF,gGAAgG;AAChG,eAAO,MAAM,YAAY,aAAc,iBAAiB,sBA6CvD,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,eAAe,UAAW,SAAS,eAAe,CAAC,QAAQ,EAAE,KAAG,MAuB5E,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=CheckRunList.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckRunList.test.d.ts","sourceRoot":"","sources":["../../../../../src/components/PullRequestOverview/CheckRunList.test.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"PullRequestStatus.d.ts","sourceRoot":"","sources":["../../../../../src/components/PullRequestStatus/PullRequestStatus.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAsB9C,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC;IAC1B,mGAAmG;IACnG,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,eAAe,CAAC,WAAW,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,EAAE,CAAC,EAAE;QAAE,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC;QAAC,MAAM,EAAE,eAAe,CAAC,WAAW,CAAA;KAAE,CAAC;CAC9E,CAAC;AAEF,0GAA0G;AAC1G,eAAO,MAAM,iBAAiB,4CAA6C,sBAAsB,sBAsChG,CAAC"}
1
+ {"version":3,"file":"PullRequestStatus.d.ts","sourceRoot":"","sources":["../../../../../src/components/PullRequestStatus/PullRequestStatus.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAsB9C,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC;IAC1B,mGAAmG;IACnG,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,eAAe,CAAC,WAAW,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,EAAE,CAAC,EAAE;QAAE,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC;QAAC,MAAM,EAAE,eAAe,CAAC,WAAW,CAAA;KAAE,CAAC;CAC9E,CAAC;AAEF,0GAA0G;AAC1G,eAAO,MAAM,iBAAiB,4CAA6C,sBAAsB,sBAwChG,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"import-pull-request.d.ts","sourceRoot":"","sources":["../../../../src/operations/import-pull-request.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAIxC,OAAO,KAAK,SAAS,MAAM,yBAAyB,CAAC;AAKrD,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAGzC,OAAO,EAAE,KAAK,oBAAoB,EAA6B,MAAM,mBAAmB,CAAC;AAEzF,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAkBjD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,4BAA4B,4BACd,oBAAoB,SACtC,MAAM,UACN,CACL,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,KACX,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sDA6C/C,CAAC;AAEL;;;;;GAKG;AACH,QAAA,MAAM,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC,OAAO,eAAe,CAAC,iBAAiB,CA8B5E,CAAC;eAEa,OAAO"}
1
+ {"version":3,"file":"import-pull-request.d.ts","sourceRoot":"","sources":["../../../../src/operations/import-pull-request.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAIxC,OAAO,KAAK,SAAS,MAAM,yBAAyB,CAAC;AAMrD,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAGzC,OAAO,EAAE,KAAK,oBAAoB,EAA6B,MAAM,mBAAmB,CAAC;AAEzF,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAmBjD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,4BAA4B,4BACd,oBAAoB,SACtC,MAAM,UACN,CACL,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,KACX,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sDA6C/C,CAAC;AAEL;;;;;GAKG;AACH,QAAA,MAAM,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC,OAAO,eAAe,CAAC,iBAAiB,CAoC5E,CAAC;eAEa,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/operations/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,mBAAmB,MAAM,mCAAmC,CAAC;AAIzE,eAAO,MAAM,yBAAyB,yCAmBpC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/operations/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,mBAAmB,MAAM,mCAAmC,CAAC;AAIzE,eAAO,MAAM,yBAAyB,yCAoBpC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import * as Operation from '@dxos/compute/Operation';
2
+ import { GitHubOperation } from '#types';
3
+ declare const handler: Operation.WithHandler<typeof GitHubOperation.RefreshPullRequests>;
4
+ export default handler;
5
+ //# sourceMappingURL=refresh-pull-requests.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh-pull-requests.d.ts","sourceRoot":"","sources":["../../../../src/operations/refresh-pull-requests.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,SAAS,MAAM,yBAAyB,CAAC;AAGrD,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAWzC,QAAA,MAAM,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC,OAAO,eAAe,CAAC,mBAAmB,CA4C5E,CAAC;eAEW,OAAO"}
@@ -0,0 +1,37 @@
1
+ import * as Effect from 'effect/Effect';
2
+ import * as Trigger from '@dxos/compute/Trigger';
3
+ import { Database } from '@dxos/echo';
4
+ import { PullRequest } from '@dxos/types';
5
+ /**
6
+ * How often the space's refresh trigger polls its open pull requests: hourly, at an off-the-hour minute
7
+ * so the fleet of spaces does not land on EDGE's busiest tick, and because every open pull request
8
+ * costs a GitHub request against the connection's rate limit.
9
+ */
10
+ export declare const REFRESH_CRON = "17 * * * *";
11
+ /**
12
+ * Re-read one stored pull request from GitHub and write back the fields that changed.
13
+ *
14
+ * Uses the anonymous fallback, so a public pull request still refreshes behind a revoked token.
15
+ * Returns the names of the changed fields.
16
+ */
17
+ export declare const refreshPullRequest: (pullRequest: PullRequest.PullRequest, token: string) => Effect.Effect<string[], never, import("effect/http/HttpClient").HttpClient>;
18
+ /** Most pull requests one run refreshes, so a run stays within GitHub's rate limit and EDGE's subrequest budget. */
19
+ export declare const REFRESH_BATCH_SIZE = 20;
20
+ /**
21
+ * The slice of `pullRequests` the run in window `window` refreshes: consecutive windows walk the list in
22
+ * id order and wrap, so every pull request is refreshed once every `ceil(count / size)` runs without
23
+ * storing a cursor.
24
+ */
25
+ export declare const selectRefreshBatch: (pullRequests: readonly PullRequest.PullRequest[], window: number, size?: number) => PullRequest.PullRequest[];
26
+ /** The space's pull requests GitHub may still change. */
27
+ export declare const queryInFlightPullRequests: () => Effect.Effect<(PullRequest.PullRequest & import("@dxos/echo/Entity").OfKind<import("@dxos/echo/internal").EntityKind.Object>)[], never, Database.Service>;
28
+ /**
29
+ * Give the space its one pull-request refresh trigger, unless it has one already — including one the
30
+ * user disabled, which stays disabled.
31
+ *
32
+ * Peers that race to create it each add their own, so every caller converges on the same keeper (the
33
+ * lowest id) and removes the rest. The trigger runs on EDGE, so pull requests keep refreshing while no
34
+ * client has the space open.
35
+ */
36
+ export declare const ensureRefreshTrigger: () => Effect.Effect<Trigger.Trigger & import("@dxos/echo/Entity").OfKind<import("@dxos/echo/internal").EntityKind.Object>, never, Database.Service>;
37
+ //# sourceMappingURL=refresh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../../../../src/operations/refresh.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO1C;;;;GAIG;AACH,eAAO,MAAM,YAAY,eAAe,CAAC;AAKzC;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,sIAc7B,CAAC;AAMH,oHAAoH;AACpH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,iBACf,SAAS,WAAW,CAAC,WAAW,EAAE,UACxC,MAAM,oBAEb,WAAW,CAAC,WAAW,EAOzB,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,yBAAyB,iKAInC,CAAC;AAKJ;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,qJAoB/B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=refresh.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh.test.d.ts","sourceRoot":"","sources":["../../../../src/operations/refresh.test.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"sync-pull-request.d.ts","sourceRoot":"","sources":["../../../../src/operations/sync-pull-request.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,SAAS,MAAM,yBAAyB,CAAC;AAGrD,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAMzC,QAAA,MAAM,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC,OAAO,eAAe,CAAC,eAAe,CAkB1E,CAAC;eAEa,OAAO"}
1
+ {"version":3,"file":"sync-pull-request.d.ts","sourceRoot":"","sources":["../../../../src/operations/sync-pull-request.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,SAAS,MAAM,yBAAyB,CAAC;AAIrD,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAKzC,QAAA,MAAM,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC,OAAO,eAAe,CAAC,eAAe,CAe1E,CAAC;eAEa,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"PullRequestOverview.stories.d.ts","sourceRoot":"","sources":["../../../../src/stories/PullRequestOverview.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAK,MAAM,OAAO,CAAC;AAY1B,OAAO,EAAE,mBAAmB,EAAiC,MAAM,4CAA4C,CAAC;AAGhH,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmBkC,CAAC;eAE9B,IAAI;AAEnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAanC,oGAAoG;AACpG,eAAO,MAAM,OAAO,EAAE,KAkBrB,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,aAAa,EAAE,KAiB3B,CAAC;AAEF,4CAA4C;AAC5C,eAAO,MAAM,eAAe,EAAE,KAS7B,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,KAAK,EAAE,KAEnB,CAAC"}
1
+ {"version":3,"file":"PullRequestOverview.stories.d.ts","sourceRoot":"","sources":["../../../../src/stories/PullRequestOverview.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAK,MAAM,OAAO,CAAC;AAY1B,OAAO,EAAE,mBAAmB,EAAiC,MAAM,4CAA4C,CAAC;AAGhH,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmBkC,CAAC;eAE9B,IAAI;AAEnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAanC,oGAAoG;AACpG,eAAO,MAAM,OAAO,EAAE,KAkBrB,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,aAAa,EAAE,KAkB3B,CAAC;AAEF,4CAA4C;AAC5C,eAAO,MAAM,eAAe,EAAE,KAS7B,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,KAAK,EAAE,KAEnB,CAAC"}
@@ -192,6 +192,17 @@ export declare const SyncPullRequest: Operation.Definition<{
192
192
  }, {
193
193
  readonly updated: readonly string[];
194
194
  }, never>;
195
+ /**
196
+ * Refresh every pull request in the space that is still in flight (open or draft) from GitHub.
197
+ *
198
+ * Run on a schedule by the space's refresh trigger (see `ensureRefreshTrigger`), so pull requests the
199
+ * user is not looking at still track their state; one unreachable pull request does not fail the rest.
200
+ */
201
+ export declare const RefreshPullRequests: Operation.Definition<{}, {
202
+ readonly checked: number;
203
+ readonly updated: number;
204
+ readonly failed: number;
205
+ }, Database.Service>;
195
206
  /** Aggregate outcome of a commit's check runs; `none` when the commit has no checks at all. */
196
207
  export declare const CiState: Schema.Literals<readonly ["success", "failure", "pending", "none"]>;
197
208
  export type CiState = Schema.Schema.Type<typeof CiState>;
@@ -1 +1 @@
1
- {"version":3,"file":"GitHubOperation.d.ts","sourceRoot":"","sources":["../../../../src/types/GitHubOperation.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,KAAK,SAAS,MAAM,yBAAyB,CAAC;AACrD,OAAO,KAAK,KAAK,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAO,GAAG,EAAO,MAAM,YAAY,CAAC;AAIrD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGxC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAEhD;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;SAShC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;SASlC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,WAAW;;EAKtB,CAAC;AAEH,MAAM,WAAW,WAAY,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,WAAW,CAAC;CAAG;AAE9E;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;SAiBT,CAAC;AAE3B;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB;;;;;oBAkByB,CAAC;AAExD;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAeN,CAAC;AAErC;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;4CAwBN,CAAC;AAE3B;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;SAsBpC,CAAC;AAEH,uFAAuF;AACvF,eAAO,MAAM,qBAAqB;;;;;;SAgBhC,CAAC;AAEH,oGAAoG;AACpG,eAAO,MAAM,2BAA2B;;;;;;;;;;SAsBtC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;SAeQ,CAAC;AAErC,+FAA+F;AAC/F,eAAO,MAAM,OAAO,qEAA6D,CAAC;AAClF,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,OAAO,CAAC,CAAC;AAEzD,eAAO,MAAM,WAAW;;;;;EAKtB,CAAC;AACH,MAAM,WAAW,WAAY,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,WAAW,CAAC;CAAG;AAE9E;;;GAGG;AACH,eAAO,MAAM,WAAW,qEAA6D,CAAC;AACtF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,WAAW,CAAC,CAAC;AAEjE,0GAA0G;AAC1G,eAAO,MAAM,YAAY,mFAA2E,CAAC;AACrG,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,YAAY,CAAC,CAAC;AAEnE,iEAAiE;AACjE,eAAO,MAAM,QAAQ;;;IAGnB,sHAAsH;;IAEtH,qFAAqF;;;;EAIrF,CAAC;AACH,MAAM,WAAW,QAAS,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,QAAQ,CAAC;CAAG;AAExE,0FAA0F;AAC1F,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;SAwB/B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;;SAe7B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,gBAAiB,WAAW,CAAC,WAAW,KAAG,MACP,CAAC"}
1
+ {"version":3,"file":"GitHubOperation.d.ts","sourceRoot":"","sources":["../../../../src/types/GitHubOperation.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,KAAK,SAAS,MAAM,yBAAyB,CAAC;AACrD,OAAO,KAAK,KAAK,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAO,GAAG,EAAO,MAAM,YAAY,CAAC;AAIrD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGxC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAEhD;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;SAShC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;SASlC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,WAAW;;EAKtB,CAAC;AAEH,MAAM,WAAW,WAAY,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,WAAW,CAAC;CAAG;AAE9E;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;SAiBT,CAAC;AAE3B;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB;;;;;oBAkByB,CAAC;AAExD;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAeN,CAAC;AAErC;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;4CAwBN,CAAC;AAE3B;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;SAsBpC,CAAC;AAEH,uFAAuF;AACvF,eAAO,MAAM,qBAAqB;;;;;;SAgBhC,CAAC;AAEH,oGAAoG;AACpG,eAAO,MAAM,2BAA2B;;;;;;;;;;SAsBtC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;SAeQ,CAAC;AAErC;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB;;;;oBAkBI,CAAC;AAErC,+FAA+F;AAC/F,eAAO,MAAM,OAAO,qEAA6D,CAAC;AAClF,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,OAAO,CAAC,CAAC;AAEzD,eAAO,MAAM,WAAW;;;;;EAKtB,CAAC;AACH,MAAM,WAAW,WAAY,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,WAAW,CAAC;CAAG;AAE9E;;;GAGG;AACH,eAAO,MAAM,WAAW,qEAA6D,CAAC;AACtF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,WAAW,CAAC,CAAC;AAEjE,0GAA0G;AAC1G,eAAO,MAAM,YAAY,mFAA2E,CAAC;AACrG,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,YAAY,CAAC,CAAC;AAEnE,iEAAiE;AACjE,eAAO,MAAM,QAAQ;;;IAGnB,sHAAsH;;IAEtH,qFAAqF;;;;EAIrF,CAAC;AACH,MAAM,WAAW,QAAS,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,QAAQ,CAAC;CAAG;AAExE,0FAA0F;AAC1F,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;SAwB/B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;;SAe7B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,gBAAiB,WAAW,CAAC,WAAW,KAAG,MACP,CAAC"}