@dxos/plugin-github 0.13.0 → 0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a
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/dist/lib/GitHubCapabilities.mjs +1 -10
- package/dist/lib/GitHubEvents.mjs +1 -15
- package/dist/lib/GitHubOperation.mjs +1 -358
- package/dist/lib/GitHubPlugin.mjs +1 -16
- package/dist/lib/Walkthrough.mjs +1 -59
- package/dist/lib/capabilities.browser.mjs +1 -2
- package/dist/lib/capabilities.browser.mjs.map +1 -1
- package/dist/lib/capabilities.mjs +1 -2
- package/dist/lib/capabilities.mjs.map +1 -1
- package/dist/lib/capabilities.tauri.mjs +1 -2
- package/dist/lib/capabilities.tauri.mjs.map +1 -1
- package/dist/lib/chunk-Extensions.mjs +18 -0
- package/dist/lib/chunk-Extensions.mjs.map +1 -0
- package/dist/lib/chunk-GitHubCapabilities.mjs +10 -0
- package/dist/lib/chunk-GitHubCapabilities.mjs.map +1 -0
- package/dist/lib/chunk-GitHubEvents.mjs +15 -0
- package/dist/lib/chunk-GitHubEvents.mjs.map +1 -0
- package/dist/lib/chunk-GitHubOperation.mjs +386 -0
- package/dist/lib/chunk-GitHubOperation.mjs.map +1 -0
- package/dist/lib/chunk-GitHubPlugin.mjs +16 -0
- package/dist/lib/chunk-GitHubPlugin.mjs.map +1 -0
- package/dist/lib/chunk-ImportPullRequestDialog.mjs.map +1 -1
- package/dist/lib/chunk-PLUGIN.mjs +1 -1
- package/dist/lib/chunk-PullRequestArticle.mjs +64 -21
- package/dist/lib/chunk-PullRequestArticle.mjs.map +1 -1
- package/dist/lib/chunk-PullRequestArticle2.mjs +1 -2
- package/dist/lib/chunk-PullRequestCardMenu.mjs +1 -1
- package/dist/lib/chunk-PullRequestsArticle.mjs +3 -3
- package/dist/lib/chunk-PullRequestsArticle.mjs.map +1 -1
- package/dist/lib/chunk-Walkthrough.mjs +59 -0
- package/dist/lib/chunk-Walkthrough.mjs.map +1 -0
- package/dist/lib/chunk-WalkthroughArticle.mjs +1 -1
- package/dist/lib/chunk-add-pull-request-comment.mjs.map +1 -1
- package/dist/lib/chunk-add-pull-request-review-comment.mjs.map +1 -1
- package/dist/lib/chunk-connector.mjs.map +1 -1
- package/dist/lib/chunk-generate-walkthrough.mjs.map +1 -1
- package/dist/lib/chunk-get-pull-request-diff.mjs.map +1 -1
- package/dist/lib/chunk-get-pull-request-status.mjs.map +1 -1
- package/dist/lib/chunk-get-repositories.mjs.map +1 -1
- package/dist/lib/chunk-github-api.mjs +1 -0
- package/dist/lib/chunk-github-api.mjs.map +1 -1
- package/dist/lib/chunk-import-pull-request.mjs +78 -3
- package/dist/lib/chunk-import-pull-request.mjs.map +1 -1
- package/dist/lib/chunk-link-resolver.mjs.map +1 -1
- package/dist/lib/chunk-pull-request2.mjs +1 -0
- package/dist/lib/chunk-pull-request2.mjs.map +1 -1
- package/dist/lib/chunk-react-surface.mjs +4 -4
- package/dist/lib/chunk-react-surface.mjs.map +1 -1
- package/dist/lib/chunk-refresh-pull-requests.mjs +49 -0
- package/dist/lib/chunk-refresh-pull-requests.mjs.map +1 -0
- package/dist/lib/chunk-submit-pull-request-approval.mjs.map +1 -1
- package/dist/lib/chunk-sync-pull-request.mjs +11 -9
- package/dist/lib/chunk-sync-pull-request.mjs.map +1 -1
- package/dist/lib/chunk-sync.mjs.map +1 -1
- package/dist/lib/index.mjs +2 -2
- package/dist/lib/meta.mjs.map +1 -1
- package/dist/lib/ns/Extensions.mjs +2 -16
- package/dist/lib/operations.mjs +2 -1
- package/dist/lib/operations.mjs.map +1 -1
- package/dist/lib/types.mjs +4 -4
- package/dist/types/src/capabilities/gen/browser.d.ts.map +1 -1
- package/dist/types/src/capabilities/gen/tauri.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/cards/GitHubCard.d.ts.map +1 -1
- package/dist/types/src/components/PullRequestOverview/CheckRunList.d.ts +6 -3
- package/dist/types/src/components/PullRequestOverview/CheckRunList.d.ts.map +1 -1
- package/dist/types/src/components/PullRequestOverview/CheckRunList.test.d.ts +2 -0
- package/dist/types/src/components/PullRequestOverview/CheckRunList.test.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestOverview/PullRequestOverview.d.ts.map +1 -1
- package/dist/types/src/components/PullRequestStatus/PullRequestStatus.d.ts.map +1 -1
- package/dist/types/src/operations/import-pull-request.d.ts.map +1 -1
- package/dist/types/src/operations/index.d.ts.map +1 -1
- package/dist/types/src/operations/pull-request.d.ts.map +1 -1
- package/dist/types/src/operations/refresh-pull-requests.d.ts +5 -0
- package/dist/types/src/operations/refresh-pull-requests.d.ts.map +1 -0
- package/dist/types/src/operations/refresh.d.ts +37 -0
- package/dist/types/src/operations/refresh.d.ts.map +1 -0
- package/dist/types/src/operations/refresh.test.d.ts +2 -0
- package/dist/types/src/operations/refresh.test.d.ts.map +1 -0
- package/dist/types/src/operations/sync-pull-request.d.ts.map +1 -1
- package/dist/types/src/services/github-api.d.ts +1 -0
- package/dist/types/src/services/github-api.d.ts.map +1 -1
- package/dist/types/src/stories/PullRequestOverview.stories.d.ts +2 -0
- package/dist/types/src/stories/PullRequestOverview.stories.d.ts.map +1 -1
- package/dist/types/src/types/GitHubOperation.d.ts +14 -0
- package/dist/types/src/types/GitHubOperation.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +47 -47
- package/src/capabilities/gen/browser.ts +1 -3
- package/src/capabilities/gen/tauri.ts +1 -3
- package/src/capabilities/index.ts +1 -4
- package/src/cards/GitHubCard.tsx +7 -3
- package/src/components/PullRequestOverview/ArtifactPill.tsx +1 -1
- package/src/components/PullRequestOverview/CheckRunList.test.ts +29 -0
- package/src/components/PullRequestOverview/CheckRunList.tsx +62 -13
- package/src/components/PullRequestOverview/PullRequestOverview.tsx +5 -1
- package/src/components/PullRequestStatus/PullRequestStatus.tsx +8 -5
- package/src/containers/PullRequestsArticle/PullRequestsArticle.tsx +12 -10
- package/src/operations/import-pull-request.ts +8 -0
- package/src/operations/index.ts +1 -0
- package/src/operations/pull-request.ts +1 -0
- package/src/operations/refresh-pull-requests.ts +69 -0
- package/src/operations/refresh.test.ts +112 -0
- package/src/operations/refresh.ts +111 -0
- package/src/operations/sync-pull-request.ts +10 -13
- package/src/services/github-api.ts +1 -0
- package/src/stories/PullRequestOverview.stories.tsx +22 -1
- package/src/types/GitHubOperation.ts +28 -0
- package/dist/lib/GitHubCapabilities.mjs.map +0 -1
- package/dist/lib/GitHubEvents.mjs.map +0 -1
- package/dist/lib/GitHubOperation.mjs.map +0 -1
- package/dist/lib/GitHubPlugin.mjs.map +0 -1
- package/dist/lib/Walkthrough.mjs.map +0 -1
- package/dist/lib/ns/Extensions.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-github-api.mjs","names":[],"sources":["../../src/services/github-api.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// TODO(wittjosiah): Refactor to use a dfx-style Effect-native client.\n\nimport * as Cause from 'effect/Cause';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as HttpClient from 'effect/http/HttpClient';\nimport * as HttpClientError from 'effect/http/HttpClientError';\nimport * as HttpClientRequest from 'effect/http/HttpClientRequest';\nimport * as Layer from 'effect/Layer';\nimport * as Schedule from 'effect/Schedule';\nimport * as Schema from 'effect/Schema';\n\nimport { Database, type Ref } from '@dxos/echo';\nimport { type AccessToken, Connection } from '@dxos/link';\n\nimport { GITHUB_API_BASE } from '../constants.ts';\n\n/** Stored as `AccessToken.token`; sent as `Authorization: Bearer <token>`. Empty means anonymous. */\ntype GitHubCredentialsValue = {\n token: string;\n};\n\nconst ACCEPT = 'application/vnd.github+json';\n/** Serves a pull request as the unified diff git would produce, rather than as JSON. */\nconst DIFF_ACCEPT = 'application/vnd.github.v3.diff';\nconst API_VERSION = '2022-11-28';\nconst USER_AGENT = '@dxos/plugin-github';\n\n//\n// Subset schemas for the responses we care about\n//\n\nconst GitHubUserSchema = Schema.Struct({\n id: Schema.Number,\n login: Schema.String,\n name: Schema.NullOr(Schema.String).pipe(Schema.optional),\n email: Schema.NullOr(Schema.String).pipe(Schema.optional),\n avatar_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n bio: Schema.NullOr(Schema.String).pipe(Schema.optional),\n company: Schema.NullOr(Schema.String).pipe(Schema.optional),\n type: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\nexport type GitHubUser = Schema.Schema.Type<typeof GitHubUserSchema>;\n\nconst GitHubOrgSchema = Schema.Struct({\n id: Schema.Number,\n login: Schema.String,\n description: Schema.NullOr(Schema.String).pipe(Schema.optional),\n name: Schema.NullOr(Schema.String).pipe(Schema.optional),\n blog: Schema.NullOr(Schema.String).pipe(Schema.optional),\n avatar_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n location: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\nexport type GitHubOrg = Schema.Schema.Type<typeof GitHubOrgSchema>;\n\nconst GitHubRepoSchema = Schema.Struct({\n id: Schema.Number,\n name: Schema.String,\n full_name: Schema.String,\n description: Schema.NullOr(Schema.String).pipe(Schema.optional),\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n homepage: Schema.NullOr(Schema.String).pipe(Schema.optional),\n archived: Schema.Boolean.pipe(Schema.optional),\n disabled: Schema.Boolean.pipe(Schema.optional),\n fork: Schema.Boolean.pipe(Schema.optional),\n default_branch: Schema.NullOr(Schema.String).pipe(Schema.optional),\n owner: Schema.Struct({ id: Schema.Number, login: Schema.String }),\n});\nexport type GitHubRepo = Schema.Schema.Type<typeof GitHubRepoSchema>;\n\nconst GitHubLabelSchema = Schema.Struct({\n name: Schema.String,\n});\n\nconst GitHubPullRefSchema = Schema.Struct({\n url: Schema.String,\n merged_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\n\nconst GitHubMilestoneSchema = Schema.Struct({\n id: Schema.Number,\n number: Schema.Number,\n title: Schema.String,\n description: Schema.NullOr(Schema.String).pipe(Schema.optional),\n state: Schema.NullOr(Schema.String).pipe(Schema.optional),\n /** ISO datetime, unlike the date-only shape the local model stores. */\n due_on: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\nexport type GitHubMilestone = Schema.Schema.Type<typeof GitHubMilestoneSchema>;\n\nconst GitHubIssueSchema = Schema.Struct({\n id: Schema.Number,\n number: Schema.Number,\n title: Schema.String,\n body: Schema.NullOr(Schema.String).pipe(Schema.optional),\n state: Schema.String,\n state_reason: Schema.NullOr(Schema.String).pipe(Schema.optional),\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n comments: Schema.Number.pipe(Schema.optional),\n comments_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n created_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n updated_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n closed_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n user: Schema.NullOr(GitHubUserSchema).pipe(Schema.optional),\n assignees: Schema.Array(GitHubUserSchema).pipe(Schema.optional),\n labels: Schema.Array(GitHubLabelSchema).pipe(Schema.optional),\n milestone: Schema.NullOr(GitHubMilestoneSchema).pipe(Schema.optional),\n pull_request: Schema.NullOr(GitHubPullRefSchema).pipe(Schema.optional),\n});\nexport type GitHubIssue = Schema.Schema.Type<typeof GitHubIssueSchema>;\n\n/** GET /repos/{owner}/{repo}/pulls/{number} — the pull-request view, which alone carries the diff size and merge state. */\nconst GitHubPullSchema = Schema.Struct({\n id: Schema.Number,\n number: Schema.Number,\n title: Schema.String,\n body: Schema.NullOr(Schema.String).pipe(Schema.optional),\n state: Schema.String,\n draft: Schema.Boolean.pipe(Schema.optional),\n merged: Schema.Boolean.pipe(Schema.optional),\n merged_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n created_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n updated_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n user: Schema.NullOr(GitHubUserSchema).pipe(Schema.optional),\n labels: Schema.Array(GitHubLabelSchema).pipe(Schema.optional),\n additions: Schema.Number.pipe(Schema.optional),\n deletions: Schema.Number.pipe(Schema.optional),\n // `sha` pins the commit a derived artefact (a generated walkthrough) describes; `ref` is a branch\n // name and moves under it.\n base: Schema.Struct({ ref: Schema.String, sha: Schema.String.pipe(Schema.optional) }).pipe(Schema.optional),\n head: Schema.Struct({ ref: Schema.String, sha: Schema.String.pipe(Schema.optional) }).pipe(Schema.optional),\n});\nexport type GitHubPull = Schema.Schema.Type<typeof GitHubPullSchema>;\n\nconst GitHubCommentSchema = Schema.Struct({\n id: Schema.Number,\n body: Schema.NullOr(Schema.String).pipe(Schema.optional),\n user: Schema.NullOr(GitHubUserSchema).pipe(Schema.optional),\n created_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n updated_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\nexport type GitHubComment = Schema.Schema.Type<typeof GitHubCommentSchema>;\n\n//\n// Credentials service\n//\n\n/**\n * Layer-based credentials service. Mirrors `TrelloCredentials`: every API call\n * pulls the token from this service rather than threading it through as an\n * explicit parameter, so callers compose a single\n * `Effect.provide(GitHubApi.fromConnection(ref))` at the\n * operation boundary.\n *\n * Token sourcing: an operation invoked with a `Connection` composes\n * `fromConnection(ref)`; one invoked with an external-sync cursor composes\n * `fromAccessToken(cursor.spec.source)` directly (the cursor no longer relates\n * to `Connection`).\n */\nexport class GitHubCredentials extends Context.Service<GitHubCredentials, GitHubCredentialsValue>()(\n '@dxos/plugin-github/GitHubCredentials',\n) {}\n\n/** Creates a credentials layer from an AccessToken ref. Loads it and returns its `token`. */\nexport const fromAccessToken = (accessTokenRef: Ref.Ref<AccessToken.AccessToken>) =>\n Layer.effect(\n GitHubCredentials,\n Effect.gen(function* () {\n const accessToken = yield* Database.load(accessTokenRef);\n return { token: accessToken.token };\n }),\n );\n\n/** Creates a credentials layer from a Connection ref. Loads its `accessToken` and returns its `token`. */\nexport const fromConnection = (connectionRef: Ref.Ref<Connection.Connection>) =>\n Layer.effect(\n GitHubCredentials,\n Effect.gen(function* () {\n const connection = yield* Database.load(connectionRef);\n const accessToken = yield* Database.load(connection.accessToken);\n return { token: accessToken.token };\n }),\n );\n\n//\n// Request pipeline\n//\n\nexport type GitHubEffect<T> = Effect.Effect<\n T,\n HttpClientError.HttpClientError | Schema.SchemaError | Cause.TimeoutError,\n HttpClient.HttpClient | GitHubCredentials\n>;\n\n/**\n * Decide whether a GitHub request failure is worth retrying.\n * - Transport / encode failures: yes (transient by nature).\n * - 429 / 5xx: yes — exactly the cases retry was designed for.\n * - 4xx other than 429 (auth, validation, not-found): no — wastes time and\n * may exacerbate rate limiting on the same token.\n * - TimeoutException: yes.\n * - Schema decode failures (`ParseError`): no — payload won't become valid on retry.\n */\nconst shouldRetry = (error: HttpClientError.HttpClientError | Schema.SchemaError | Cause.TimeoutError): boolean => {\n if (error instanceof Schema.SchemaError) {\n return false;\n }\n if (Cause.isTimeoutError(error)) {\n return true;\n }\n // v4 hangs the specific failure off `HttpClientError.reason`: a transport-level failure is always\n // worth retrying, and a response failure only on 429/5xx.\n if (error.reason._tag !== 'StatusCodeError') {\n return true;\n }\n const status = error.reason.response.status;\n return status === 429 || (status >= 500 && status <= 599);\n};\n\n/**\n * The status a failed GitHub request answered with, or `undefined` for a transport, timeout or\n * decode failure. Callers branch on it to tell a dead credential (401) from an absent resource.\n */\nexport const responseStatus = (error: unknown): number | undefined =>\n HttpClientError.isHttpClientError(error) && error.reason._tag === 'StatusCodeError'\n ? error.reason.response.status\n : undefined;\n\n/** Anonymous when the token is empty: a bare `Bearer` header is rejected where no header is rate-limited. */\nconst withAuth = (req: HttpClientRequest.HttpClientRequest, creds: GitHubCredentialsValue, accept = ACCEPT) =>\n req.pipe(\n (req) => (creds.token ? HttpClientRequest.setHeader(req, 'Authorization', `Bearer ${creds.token}`) : req),\n HttpClientRequest.setHeader('Accept', accept),\n HttpClientRequest.setHeader('X-GitHub-Api-Version', API_VERSION),\n HttpClientRequest.setHeader('User-Agent', USER_AGENT),\n );\n\n/**\n * Build an unauthenticated GitHub API request, fetch + decode it as a single JSON\n * response, and apply timeout + retry. `withAuth` is applied here so callers never\n * have to remember to attach credentials (forgetting would silently 401).\n *\n * `filterStatusOk` converts non-2xx responses into a typed `ResponseError`\n * (carrying `status` and the raw body) BEFORE we try to decode the body —\n * otherwise GitHub error envelopes (`{ message, documentation_url }`) would\n * blow up against the success schema with a `ParseError`, masking the real\n * cause (e.g. a 403 from an integration token that lacks issue write).\n */\nconst githubRequest = <T>(build: () => HttpClientRequest.HttpClientRequest, schema: Schema.Codec<T>): GitHubEffect<T> =>\n Effect.gen(function* () {\n const creds = yield* GitHubCredentials;\n const httpClient = yield* HttpClient.HttpClient;\n const clientNoTracer = httpClient.pipe(\n HttpClient.transformResponse(Effect.provideService(HttpClient.TracerDisabledWhen, () => true)),\n HttpClient.filterStatusOk,\n );\n return yield* clientNoTracer.execute(withAuth(build(), creds)).pipe(\n Effect.flatMap((res) => Effect.flatMap(res.json, Schema.decodeUnknownEffect(schema))),\n Effect.timeout('15 seconds'),\n Effect.retry({\n schedule: Schedule.exponential('500 millis').pipe(Schedule.jittered, Schedule.upTo({ times: 3 })),\n while: shouldRetry,\n }),\n Effect.scoped,\n );\n });\n\n/**\n * Fetch a response GitHub serves as text rather than JSON — the `diff` media type, which has no\n * schema to decode against.\n *\n * The timeout is longer than `githubRequest`'s because a diff is the whole change rather than a\n * summary of it. GitHub answers 406 rather than truncating when a pull request exceeds its own\n * limits (roughly 300 files or 20k lines), which `filterStatusOk` surfaces as a typed failure.\n */\nconst githubText = (build: () => HttpClientRequest.HttpClientRequest, accept: string): GitHubEffect<string> =>\n Effect.gen(function* () {\n const creds = yield* GitHubCredentials;\n const httpClient = yield* HttpClient.HttpClient;\n const clientNoTracer = httpClient.pipe(\n HttpClient.transformResponse(Effect.provideService(HttpClient.TracerDisabledWhen, () => true)),\n HttpClient.filterStatusOk,\n );\n return yield* clientNoTracer.execute(withAuth(build(), creds, accept)).pipe(\n Effect.flatMap((res) => res.text),\n Effect.timeout('60 seconds'),\n Effect.retry({\n schedule: Schedule.exponential('500 millis').pipe(Schedule.jittered, Schedule.upTo({ times: 3 })),\n while: shouldRetry,\n }),\n Effect.scoped,\n );\n });\n\n//\n// Pagination\n//\n\n/**\n * Walk paginated GitHub list endpoints by following `Link: <…>; rel=\"next\"`.\n *\n * Sets `per_page=100` automatically; aggregates pages into a single array.\n * Returns the empty array if the first page is empty. Stops at `MAX_PAGES`\n * to bound memory + traffic for very large orgs/repos — in v1 we accept that\n * the very largest orgs may be partially synced and surface a TODO to add\n * cursor support.\n */\nconst MAX_PAGES = 10;\n\nconst getNextLink = (header: string | undefined): string | undefined => {\n if (!header) {\n return undefined;\n }\n // Link: <url>; rel=\"next\", <url>; rel=\"last\", …\n for (const part of header.split(',')) {\n const match = part.trim().match(/^<([^>]+)>;\\s*rel=\"([^\"]+)\"$/);\n if (match && match[2] === 'next') {\n return match[1];\n }\n }\n return undefined;\n};\n\n/**\n * Walks `rel=\"next\"` to the end, decoding each page with `pageSchema` and taking its items through\n * `select` — an endpoint that answers with an envelope rather than a bare array pages the same way.\n */\nconst githubPages = <TPage, T>(\n buildInitial: () => HttpClientRequest.HttpClientRequest,\n pageSchema: Schema.Codec<TPage>,\n select: (page: TPage) => readonly T[],\n): GitHubEffect<readonly T[]> =>\n Effect.gen(function* () {\n const httpClient = yield* HttpClient.HttpClient;\n const creds = yield* GitHubCredentials;\n const clientNoTracer = httpClient.pipe(\n HttpClient.transformResponse(Effect.provideService(HttpClient.TracerDisabledWhen, () => true)),\n HttpClient.filterStatusOk,\n );\n\n let nextUrl: string | undefined;\n let request = withAuth(buildInitial(), creds).pipe(HttpClientRequest.appendUrlParam('per_page', '100'));\n const out: T[] = [];\n\n for (let page = 0; page < MAX_PAGES; page++) {\n const result = yield* clientNoTracer.execute(request).pipe(\n Effect.flatMap((res) =>\n Effect.gen(function* () {\n const body = yield* res.json;\n const decoded = yield* Schema.decodeUnknownEffect(pageSchema)(body);\n return { decoded, link: res.headers['link'] };\n }),\n ),\n Effect.timeout('15 seconds'),\n Effect.retry({\n schedule: Schedule.exponential('500 millis').pipe(Schedule.jittered, Schedule.upTo({ times: 3 })),\n while: shouldRetry,\n }),\n Effect.scoped,\n );\n\n out.push(...select(result.decoded));\n nextUrl = getNextLink(result.link);\n if (!nextUrl) {\n break;\n }\n request = withAuth(HttpClientRequest.get(nextUrl), creds);\n }\n\n return out;\n });\n\nconst githubPaginated = <T>(\n buildInitial: () => HttpClientRequest.HttpClientRequest,\n itemSchema: Schema.Codec<T>,\n): GitHubEffect<readonly T[]> => githubPages(buildInitial, Schema.Array(itemSchema), (page) => page);\n\n//\n// API surface\n//\n\n/** GET /user — authenticated user profile. */\nexport const fetchUser = (): GitHubEffect<GitHubUser> =>\n githubRequest(() => HttpClientRequest.get(`${GITHUB_API_BASE}/user`), GitHubUserSchema);\n\n/** GET /user/orgs — orgs visible to the authenticated user. */\nexport const fetchUserOrgs = (): GitHubEffect<readonly GitHubOrg[]> =>\n githubPaginated(() => HttpClientRequest.get(`${GITHUB_API_BASE}/user/orgs`), GitHubOrgSchema);\n\n/**\n * GET /user/repos — every repo the authenticated user can see.\n *\n * Includes owner, collaborator, and org-member affiliations. For a GitHub App\n * user-to-server token this is intersected with the App's installation scope —\n * admins control which repos are visible by choosing All / Selected at install\n * time.\n */\nexport const fetchUserRepos = (): GitHubEffect<readonly GitHubRepo[]> =>\n githubPaginated(() => HttpClientRequest.get(`${GITHUB_API_BASE}/user/repos`), GitHubRepoSchema);\n\n/** GET /orgs/{org} — full org metadata. */\nexport const fetchOrg = (org: string): GitHubEffect<GitHubOrg> =>\n githubRequest(() => HttpClientRequest.get(`${GITHUB_API_BASE}/orgs/${encodeURIComponent(org)}`), GitHubOrgSchema);\n\n/** GET /orgs/{org}/members — public + private members (depends on token). */\nexport const fetchOrgMembers = (org: string): GitHubEffect<readonly GitHubUser[]> =>\n githubPaginated(\n () => HttpClientRequest.get(`${GITHUB_API_BASE}/orgs/${encodeURIComponent(org)}/members`),\n GitHubUserSchema,\n );\n\n/** GET /users/{login} — full user profile (org members lists return a partial form). */\nexport const fetchUserByLogin = (login: string): GitHubEffect<GitHubUser> =>\n githubRequest(() => HttpClientRequest.get(`${GITHUB_API_BASE}/users/${encodeURIComponent(login)}`), GitHubUserSchema);\n\n/** GET /orgs/{org}/repos — repos owned by the org. */\nexport const fetchOrgRepos = (org: string): GitHubEffect<readonly GitHubRepo[]> =>\n githubPaginated(\n () => HttpClientRequest.get(`${GITHUB_API_BASE}/orgs/${encodeURIComponent(org)}/repos`),\n GitHubRepoSchema,\n );\n\n/**\n * GET /repos/{owner}/{repo}/issues — both issues AND pull requests.\n *\n * `state=all` includes closed. PRs are distinguishable by a non-null\n * `pull_request` field. `since` is an optional ISO timestamp; when provided,\n * GitHub returns only issues updated at or after that point — we use this\n * for incremental syncs.\n */\nexport const fetchRepoIssues = (\n owner: string,\n repo: string,\n options: { since?: string } = {},\n): GitHubEffect<readonly GitHubIssue[]> =>\n githubPaginated(() => {\n let req = HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues`,\n ).pipe(HttpClientRequest.appendUrlParam('state', 'all'));\n if (options.since) {\n req = req.pipe(HttpClientRequest.appendUrlParam('since', options.since));\n }\n return req;\n }, GitHubIssueSchema);\n\n/** GET /repos/{owner}/{repo}. */\nexport const fetchRepo = (owner: string, repo: string): GitHubEffect<GitHubRepo> =>\n githubRequest(\n () => HttpClientRequest.get(`${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`),\n GitHubRepoSchema,\n );\n\n/** GET /repos/{owner}/{repo}/issues/{number} — an issue, or the issue view of a pull request. */\nexport const fetchIssue = (owner: string, repo: string, number: number): GitHubEffect<GitHubIssue> =>\n githubRequest(\n () =>\n HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${number}`,\n ),\n GitHubIssueSchema,\n );\n\n/** GET /repos/{owner}/{repo}/pulls/{number}. */\nexport const fetchPullRequest = (owner: string, repo: string, number: number): GitHubEffect<GitHubPull> =>\n githubRequest(\n () =>\n HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/pulls/${number}`,\n ),\n GitHubPullSchema,\n );\n\n/**\n * GET /repos/{owner}/{repo}/pulls/{number} as a unified diff — the same bytes `git diff` would\n * produce, which is what a generated walkthrough splices its chunks from.\n */\nexport const fetchPullRequestDiff = (owner: string, repo: string, number: number): GitHubEffect<string> =>\n githubText(\n () =>\n HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/pulls/${number}`,\n ),\n DIFF_ACCEPT,\n );\n\n/**\n * GET /repos/{owner}/{repo}/milestones — `state=all` so closed milestones stay mirrored (the\n * issues still assigned to them have to resolve to something).\n */\nexport const fetchRepoMilestones = (owner: string, repo: string): GitHubEffect<readonly GitHubMilestone[]> =>\n githubPaginated(\n () =>\n HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/milestones`,\n ).pipe(HttpClientRequest.appendUrlParam('state', 'all')),\n GitHubMilestoneSchema,\n );\n\n/** GET /repos/{owner}/{repo}/issues/{number}/comments. */\nexport const fetchIssueComments = (\n owner: string,\n repo: string,\n issueNumber: number,\n): GitHubEffect<readonly GitHubComment[]> =>\n githubPaginated(\n () =>\n HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${issueNumber}/comments`,\n ),\n GitHubCommentSchema,\n );\n\n//\n// Mutations (push)\n//\n\n/**\n * Write to a GitHub object (PATCH or POST, as `build` chooses). The shape mirrors {@link githubRequest} except the\n * body is `application/json`. Failures are\n * propagated unchanged; the caller is expected to surface them on the target\n * row's `lastError`.\n *\n * Only PATCH retries (429 / 5xx retry, 4xx don't). A POST here creates a comment or a review, and\n * GitHub can commit one before the response reaches us, so retrying a timeout would post it twice.\n */\nconst githubWrite = <T>(\n build: () => HttpClientRequest.HttpClientRequest,\n body: Record<string, unknown>,\n schema: Schema.Codec<T>,\n): GitHubEffect<T> =>\n Effect.gen(function* () {\n const creds = yield* GitHubCredentials;\n const httpClient = yield* HttpClient.HttpClient;\n const clientNoTracer = httpClient.pipe(\n HttpClient.transformResponse(Effect.provideService(HttpClient.TracerDisabledWhen, () => true)),\n HttpClient.filterStatusOk,\n );\n const request = withAuth(build(), creds).pipe(HttpClientRequest.bodyJsonUnsafe(body));\n const attempt = clientNoTracer.execute(request).pipe(\n Effect.flatMap((res) => Effect.flatMap(res.json, Schema.decodeUnknownEffect(schema))),\n Effect.timeout('15 seconds'),\n );\n return yield* (\n request.method === 'PATCH'\n ? attempt.pipe(\n Effect.retry({\n schedule: Schedule.exponential('500 millis').pipe(Schedule.jittered, Schedule.upTo({ times: 3 })),\n while: shouldRetry,\n }),\n )\n : attempt\n ).pipe(Effect.scoped);\n });\n\nexport type IssueUpdateInput = {\n title?: string;\n body?: string;\n state?: 'open' | 'closed';\n state_reason?: 'completed' | 'not_planned' | 'reopened' | null;\n};\n\n/**\n * PATCH /repos/{owner}/{repo}/issues/{number} — update title / body / state.\n *\n * GitHub conflates issues and PRs at this endpoint: the same PATCH works for\n * both, but PR-specific fields (head/base/draft) must go through the\n * `/pulls/{n}` endpoint. We only touch issue-mappable fields here.\n */\nexport const updateIssue = (\n owner: string,\n repo: string,\n issueNumber: number,\n input: IssueUpdateInput,\n): GitHubEffect<GitHubIssue> =>\n githubWrite(\n () =>\n HttpClientRequest.patch(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${issueNumber}`,\n ),\n input as unknown as Record<string, unknown>,\n GitHubIssueSchema,\n );\n\nexport type RepoUpdateInput = {\n /** GitHub allows the owner of a repo to rename it; this is rare and risky and we currently don't push it. */\n name?: string;\n description?: string;\n homepage?: string;\n};\n\n/**\n * PATCH /repos/{owner}/{repo} — update repo description and a small set of\n * mapped metadata. Renames (`name`) are accepted by the API but we don't push\n * them by default: a rename invalidates clones, breaks pinned URLs, and is\n * almost never what a user wants from a sync mirror.\n */\nexport const updateRepo = (owner: string, repo: string, input: RepoUpdateInput): GitHubEffect<GitHubRepo> =>\n githubWrite(\n () => HttpClientRequest.patch(`${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`),\n input as unknown as Record<string, unknown>,\n GitHubRepoSchema,\n );\n\nconst GitHubReviewSchema = Schema.Struct({\n id: Schema.Number,\n state: Schema.String,\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\nexport type GitHubReview = Schema.Schema.Type<typeof GitHubReviewSchema>;\n\n/** POST /repos/{owner}/{repo}/pulls/{number}/reviews with `event: APPROVE`. */\nexport const approvePullRequest = (\n owner: string,\n repo: string,\n number: number,\n body?: string,\n): GitHubEffect<GitHubReview> =>\n githubWrite(\n () =>\n HttpClientRequest.post(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/pulls/${number}/reviews`,\n ),\n { event: 'APPROVE', ...(body ? { body } : {}) },\n GitHubReviewSchema,\n );\n\nconst GitHubSubmittedReviewSchema = Schema.Struct({\n id: Schema.Number,\n /** `APPROVED`, `CHANGES_REQUESTED`, `COMMENTED`, `DISMISSED` or `PENDING`. */\n state: Schema.String,\n user: Schema.NullOr(Schema.Struct({ login: Schema.String })).pipe(Schema.optional),\n submitted_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\nexport type GitHubSubmittedReview = Schema.Schema.Type<typeof GitHubSubmittedReviewSchema>;\n\n/**\n * GET /repos/{owner}/{repo}/pulls/{number}/reviews — every page, oldest first, since a reviewer's\n * standing verdict is their latest review and a truncated list could miss it.\n */\nexport const fetchReviews = (\n owner: string,\n repo: string,\n number: number,\n): GitHubEffect<readonly GitHubSubmittedReview[]> =>\n githubPages(\n () =>\n HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/pulls/${number}/reviews`,\n ),\n Schema.Array(GitHubSubmittedReviewSchema),\n (page) => page,\n );\n\n/** POST /repos/{owner}/{repo}/issues/{number}/comments — a conversation comment, which a pull request shares with issues. */\nexport const createIssueComment = (\n owner: string,\n repo: string,\n issueNumber: number,\n body: string,\n): GitHubEffect<GitHubComment> =>\n githubWrite(\n () =>\n HttpClientRequest.post(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${issueNumber}/comments`,\n ),\n { body },\n GitHubCommentSchema,\n );\n\nconst GitHubCheckRunSchema = Schema.Struct({\n name: Schema.String,\n /** `queued`, `in_progress` or `completed`. */\n status: Schema.String,\n /** Set once `completed`: `success`, `failure`, `neutral`, `cancelled`, `skipped`, `timed_out`, `action_required`. */\n conclusion: Schema.NullOr(Schema.String).pipe(Schema.optional),\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n /** The provider's own page for the run (Depot, say), which GitHub's `html_url` only links back to. */\n details_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n started_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n completed_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\nexport type GitHubCheckRun = Schema.Schema.Type<typeof GitHubCheckRunSchema>;\n\nconst GitHubCheckRunsSchema = Schema.Struct({\n total_count: Schema.Number,\n check_runs: Schema.Array(GitHubCheckRunSchema),\n});\n\n/**\n * GET /repos/{owner}/{repo}/commits/{sha}/check-runs — every page, since a truncated list would\n * report a failing commit as green.\n */\nexport const fetchCheckRuns = (owner: string, repo: string, sha: string): GitHubEffect<readonly GitHubCheckRun[]> =>\n githubPages(\n () =>\n HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/commits/${encodeURIComponent(sha)}/check-runs`,\n ),\n GitHubCheckRunsSchema,\n ({ check_runs }) => check_runs,\n );\n\nexport type ReviewCommentInput = {\n body: string;\n /** Head SHA the line numbers refer to. */\n commit_id: string;\n path: string;\n line: number;\n /** `LEFT` is the base (removed) side, `RIGHT` the head (added or context) side. */\n side: 'LEFT' | 'RIGHT';\n};\n\n/** POST /repos/{owner}/{repo}/pulls/{number}/comments — a review comment on one line of the diff. */\nexport const createReviewComment = (\n owner: string,\n repo: string,\n number: number,\n input: ReviewCommentInput,\n): GitHubEffect<GitHubComment> =>\n githubWrite(\n () =>\n HttpClientRequest.post(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/pulls/${number}/comments`,\n ),\n input,\n GitHubCommentSchema,\n );\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chunk-github-api.mjs","names":[],"sources":["../../src/services/github-api.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// TODO(wittjosiah): Refactor to use a dfx-style Effect-native client.\n\nimport * as Cause from 'effect/Cause';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as HttpClient from 'effect/http/HttpClient';\nimport * as HttpClientError from 'effect/http/HttpClientError';\nimport * as HttpClientRequest from 'effect/http/HttpClientRequest';\nimport * as Layer from 'effect/Layer';\nimport * as Schedule from 'effect/Schedule';\nimport * as Schema from 'effect/Schema';\n\nimport { Database, type Ref } from '@dxos/echo';\nimport { type AccessToken, Connection } from '@dxos/link';\n\nimport { GITHUB_API_BASE } from '../constants.ts';\n\n/** Stored as `AccessToken.token`; sent as `Authorization: Bearer <token>`. Empty means anonymous. */\ntype GitHubCredentialsValue = {\n token: string;\n};\n\nconst ACCEPT = 'application/vnd.github+json';\n/** Serves a pull request as the unified diff git would produce, rather than as JSON. */\nconst DIFF_ACCEPT = 'application/vnd.github.v3.diff';\nconst API_VERSION = '2022-11-28';\nconst USER_AGENT = '@dxos/plugin-github';\n\n//\n// Subset schemas for the responses we care about\n//\n\nconst GitHubUserSchema = Schema.Struct({\n id: Schema.Number,\n login: Schema.String,\n name: Schema.NullOr(Schema.String).pipe(Schema.optional),\n email: Schema.NullOr(Schema.String).pipe(Schema.optional),\n avatar_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n bio: Schema.NullOr(Schema.String).pipe(Schema.optional),\n company: Schema.NullOr(Schema.String).pipe(Schema.optional),\n type: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\nexport type GitHubUser = Schema.Schema.Type<typeof GitHubUserSchema>;\n\nconst GitHubOrgSchema = Schema.Struct({\n id: Schema.Number,\n login: Schema.String,\n description: Schema.NullOr(Schema.String).pipe(Schema.optional),\n name: Schema.NullOr(Schema.String).pipe(Schema.optional),\n blog: Schema.NullOr(Schema.String).pipe(Schema.optional),\n avatar_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n location: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\nexport type GitHubOrg = Schema.Schema.Type<typeof GitHubOrgSchema>;\n\nconst GitHubRepoSchema = Schema.Struct({\n id: Schema.Number,\n name: Schema.String,\n full_name: Schema.String,\n description: Schema.NullOr(Schema.String).pipe(Schema.optional),\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n homepage: Schema.NullOr(Schema.String).pipe(Schema.optional),\n archived: Schema.Boolean.pipe(Schema.optional),\n disabled: Schema.Boolean.pipe(Schema.optional),\n fork: Schema.Boolean.pipe(Schema.optional),\n default_branch: Schema.NullOr(Schema.String).pipe(Schema.optional),\n owner: Schema.Struct({ id: Schema.Number, login: Schema.String }),\n});\nexport type GitHubRepo = Schema.Schema.Type<typeof GitHubRepoSchema>;\n\nconst GitHubLabelSchema = Schema.Struct({\n name: Schema.String,\n});\n\nconst GitHubPullRefSchema = Schema.Struct({\n url: Schema.String,\n merged_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\n\nconst GitHubMilestoneSchema = Schema.Struct({\n id: Schema.Number,\n number: Schema.Number,\n title: Schema.String,\n description: Schema.NullOr(Schema.String).pipe(Schema.optional),\n state: Schema.NullOr(Schema.String).pipe(Schema.optional),\n /** ISO datetime, unlike the date-only shape the local model stores. */\n due_on: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\nexport type GitHubMilestone = Schema.Schema.Type<typeof GitHubMilestoneSchema>;\n\nconst GitHubIssueSchema = Schema.Struct({\n id: Schema.Number,\n number: Schema.Number,\n title: Schema.String,\n body: Schema.NullOr(Schema.String).pipe(Schema.optional),\n state: Schema.String,\n state_reason: Schema.NullOr(Schema.String).pipe(Schema.optional),\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n comments: Schema.Number.pipe(Schema.optional),\n comments_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n created_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n updated_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n closed_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n user: Schema.NullOr(GitHubUserSchema).pipe(Schema.optional),\n assignees: Schema.Array(GitHubUserSchema).pipe(Schema.optional),\n labels: Schema.Array(GitHubLabelSchema).pipe(Schema.optional),\n milestone: Schema.NullOr(GitHubMilestoneSchema).pipe(Schema.optional),\n pull_request: Schema.NullOr(GitHubPullRefSchema).pipe(Schema.optional),\n});\nexport type GitHubIssue = Schema.Schema.Type<typeof GitHubIssueSchema>;\n\n/** GET /repos/{owner}/{repo}/pulls/{number} — the pull-request view, which alone carries the diff size and merge state. */\nconst GitHubPullSchema = Schema.Struct({\n id: Schema.Number,\n number: Schema.Number,\n title: Schema.String,\n body: Schema.NullOr(Schema.String).pipe(Schema.optional),\n state: Schema.String,\n draft: Schema.Boolean.pipe(Schema.optional),\n merged: Schema.Boolean.pipe(Schema.optional),\n merged_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n created_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n updated_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n user: Schema.NullOr(GitHubUserSchema).pipe(Schema.optional),\n labels: Schema.Array(GitHubLabelSchema).pipe(Schema.optional),\n additions: Schema.Number.pipe(Schema.optional),\n deletions: Schema.Number.pipe(Schema.optional),\n // `sha` pins the commit a derived artefact (a generated walkthrough) describes; `ref` is a branch\n // name and moves under it.\n base: Schema.Struct({ ref: Schema.String, sha: Schema.String.pipe(Schema.optional) }).pipe(Schema.optional),\n head: Schema.Struct({ ref: Schema.String, sha: Schema.String.pipe(Schema.optional) }).pipe(Schema.optional),\n});\nexport type GitHubPull = Schema.Schema.Type<typeof GitHubPullSchema>;\n\nconst GitHubCommentSchema = Schema.Struct({\n id: Schema.Number,\n body: Schema.NullOr(Schema.String).pipe(Schema.optional),\n user: Schema.NullOr(GitHubUserSchema).pipe(Schema.optional),\n created_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n updated_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\nexport type GitHubComment = Schema.Schema.Type<typeof GitHubCommentSchema>;\n\n//\n// Credentials service\n//\n\n/**\n * Layer-based credentials service. Mirrors `TrelloCredentials`: every API call\n * pulls the token from this service rather than threading it through as an\n * explicit parameter, so callers compose a single\n * `Effect.provide(GitHubApi.fromConnection(ref))` at the\n * operation boundary.\n *\n * Token sourcing: an operation invoked with a `Connection` composes\n * `fromConnection(ref)`; one invoked with an external-sync cursor composes\n * `fromAccessToken(cursor.spec.source)` directly (the cursor no longer relates\n * to `Connection`).\n */\nexport class GitHubCredentials extends Context.Service<GitHubCredentials, GitHubCredentialsValue>()(\n '@dxos/plugin-github/GitHubCredentials',\n) {}\n\n/** Creates a credentials layer from an AccessToken ref. Loads it and returns its `token`. */\nexport const fromAccessToken = (accessTokenRef: Ref.Ref<AccessToken.AccessToken>) =>\n Layer.effect(\n GitHubCredentials,\n Effect.gen(function* () {\n const accessToken = yield* Database.load(accessTokenRef);\n return { token: accessToken.token };\n }),\n );\n\n/** Creates a credentials layer from a Connection ref. Loads its `accessToken` and returns its `token`. */\nexport const fromConnection = (connectionRef: Ref.Ref<Connection.Connection>) =>\n Layer.effect(\n GitHubCredentials,\n Effect.gen(function* () {\n const connection = yield* Database.load(connectionRef);\n const accessToken = yield* Database.load(connection.accessToken);\n return { token: accessToken.token };\n }),\n );\n\n//\n// Request pipeline\n//\n\nexport type GitHubEffect<T> = Effect.Effect<\n T,\n HttpClientError.HttpClientError | Schema.SchemaError | Cause.TimeoutError,\n HttpClient.HttpClient | GitHubCredentials\n>;\n\n/**\n * Decide whether a GitHub request failure is worth retrying.\n * - Transport / encode failures: yes (transient by nature).\n * - 429 / 5xx: yes — exactly the cases retry was designed for.\n * - 4xx other than 429 (auth, validation, not-found): no — wastes time and\n * may exacerbate rate limiting on the same token.\n * - TimeoutException: yes.\n * - Schema decode failures (`ParseError`): no — payload won't become valid on retry.\n */\nconst shouldRetry = (error: HttpClientError.HttpClientError | Schema.SchemaError | Cause.TimeoutError): boolean => {\n if (error instanceof Schema.SchemaError) {\n return false;\n }\n if (Cause.isTimeoutError(error)) {\n return true;\n }\n // v4 hangs the specific failure off `HttpClientError.reason`: a transport-level failure is always\n // worth retrying, and a response failure only on 429/5xx.\n if (error.reason._tag !== 'StatusCodeError') {\n return true;\n }\n const status = error.reason.response.status;\n return status === 429 || (status >= 500 && status <= 599);\n};\n\n/**\n * The status a failed GitHub request answered with, or `undefined` for a transport, timeout or\n * decode failure. Callers branch on it to tell a dead credential (401) from an absent resource.\n */\nexport const responseStatus = (error: unknown): number | undefined =>\n HttpClientError.isHttpClientError(error) && error.reason._tag === 'StatusCodeError'\n ? error.reason.response.status\n : undefined;\n\n/** Anonymous when the token is empty: a bare `Bearer` header is rejected where no header is rate-limited. */\nconst withAuth = (req: HttpClientRequest.HttpClientRequest, creds: GitHubCredentialsValue, accept = ACCEPT) =>\n req.pipe(\n (req) => (creds.token ? HttpClientRequest.setHeader(req, 'Authorization', `Bearer ${creds.token}`) : req),\n HttpClientRequest.setHeader('Accept', accept),\n HttpClientRequest.setHeader('X-GitHub-Api-Version', API_VERSION),\n HttpClientRequest.setHeader('User-Agent', USER_AGENT),\n );\n\n/**\n * Build an unauthenticated GitHub API request, fetch + decode it as a single JSON\n * response, and apply timeout + retry. `withAuth` is applied here so callers never\n * have to remember to attach credentials (forgetting would silently 401).\n *\n * `filterStatusOk` converts non-2xx responses into a typed `ResponseError`\n * (carrying `status` and the raw body) BEFORE we try to decode the body —\n * otherwise GitHub error envelopes (`{ message, documentation_url }`) would\n * blow up against the success schema with a `ParseError`, masking the real\n * cause (e.g. a 403 from an integration token that lacks issue write).\n */\nconst githubRequest = <T>(build: () => HttpClientRequest.HttpClientRequest, schema: Schema.Codec<T>): GitHubEffect<T> =>\n Effect.gen(function* () {\n const creds = yield* GitHubCredentials;\n const httpClient = yield* HttpClient.HttpClient;\n const clientNoTracer = httpClient.pipe(\n HttpClient.transformResponse(Effect.provideService(HttpClient.TracerDisabledWhen, () => true)),\n HttpClient.filterStatusOk,\n );\n return yield* clientNoTracer.execute(withAuth(build(), creds)).pipe(\n Effect.flatMap((res) => Effect.flatMap(res.json, Schema.decodeUnknownEffect(schema))),\n Effect.timeout('15 seconds'),\n Effect.retry({\n schedule: Schedule.exponential('500 millis').pipe(Schedule.jittered, Schedule.upTo({ times: 3 })),\n while: shouldRetry,\n }),\n Effect.scoped,\n );\n });\n\n/**\n * Fetch a response GitHub serves as text rather than JSON — the `diff` media type, which has no\n * schema to decode against.\n *\n * The timeout is longer than `githubRequest`'s because a diff is the whole change rather than a\n * summary of it. GitHub answers 406 rather than truncating when a pull request exceeds its own\n * limits (roughly 300 files or 20k lines), which `filterStatusOk` surfaces as a typed failure.\n */\nconst githubText = (build: () => HttpClientRequest.HttpClientRequest, accept: string): GitHubEffect<string> =>\n Effect.gen(function* () {\n const creds = yield* GitHubCredentials;\n const httpClient = yield* HttpClient.HttpClient;\n const clientNoTracer = httpClient.pipe(\n HttpClient.transformResponse(Effect.provideService(HttpClient.TracerDisabledWhen, () => true)),\n HttpClient.filterStatusOk,\n );\n return yield* clientNoTracer.execute(withAuth(build(), creds, accept)).pipe(\n Effect.flatMap((res) => res.text),\n Effect.timeout('60 seconds'),\n Effect.retry({\n schedule: Schedule.exponential('500 millis').pipe(Schedule.jittered, Schedule.upTo({ times: 3 })),\n while: shouldRetry,\n }),\n Effect.scoped,\n );\n });\n\n//\n// Pagination\n//\n\n/**\n * Walk paginated GitHub list endpoints by following `Link: <…>; rel=\"next\"`.\n *\n * Sets `per_page=100` automatically; aggregates pages into a single array.\n * Returns the empty array if the first page is empty. Stops at `MAX_PAGES`\n * to bound memory + traffic for very large orgs/repos — in v1 we accept that\n * the very largest orgs may be partially synced and surface a TODO to add\n * cursor support.\n */\nconst MAX_PAGES = 10;\n\nconst getNextLink = (header: string | undefined): string | undefined => {\n if (!header) {\n return undefined;\n }\n // Link: <url>; rel=\"next\", <url>; rel=\"last\", …\n for (const part of header.split(',')) {\n const match = part.trim().match(/^<([^>]+)>;\\s*rel=\"([^\"]+)\"$/);\n if (match && match[2] === 'next') {\n return match[1];\n }\n }\n return undefined;\n};\n\n/**\n * Walks `rel=\"next\"` to the end, decoding each page with `pageSchema` and taking its items through\n * `select` — an endpoint that answers with an envelope rather than a bare array pages the same way.\n */\nconst githubPages = <TPage, T>(\n buildInitial: () => HttpClientRequest.HttpClientRequest,\n pageSchema: Schema.Codec<TPage>,\n select: (page: TPage) => readonly T[],\n): GitHubEffect<readonly T[]> =>\n Effect.gen(function* () {\n const httpClient = yield* HttpClient.HttpClient;\n const creds = yield* GitHubCredentials;\n const clientNoTracer = httpClient.pipe(\n HttpClient.transformResponse(Effect.provideService(HttpClient.TracerDisabledWhen, () => true)),\n HttpClient.filterStatusOk,\n );\n\n let nextUrl: string | undefined;\n let request = withAuth(buildInitial(), creds).pipe(HttpClientRequest.appendUrlParam('per_page', '100'));\n const out: T[] = [];\n\n for (let page = 0; page < MAX_PAGES; page++) {\n const result = yield* clientNoTracer.execute(request).pipe(\n Effect.flatMap((res) =>\n Effect.gen(function* () {\n const body = yield* res.json;\n const decoded = yield* Schema.decodeUnknownEffect(pageSchema)(body);\n return { decoded, link: res.headers['link'] };\n }),\n ),\n Effect.timeout('15 seconds'),\n Effect.retry({\n schedule: Schedule.exponential('500 millis').pipe(Schedule.jittered, Schedule.upTo({ times: 3 })),\n while: shouldRetry,\n }),\n Effect.scoped,\n );\n\n out.push(...select(result.decoded));\n nextUrl = getNextLink(result.link);\n if (!nextUrl) {\n break;\n }\n request = withAuth(HttpClientRequest.get(nextUrl), creds);\n }\n\n return out;\n });\n\nconst githubPaginated = <T>(\n buildInitial: () => HttpClientRequest.HttpClientRequest,\n itemSchema: Schema.Codec<T>,\n): GitHubEffect<readonly T[]> => githubPages(buildInitial, Schema.Array(itemSchema), (page) => page);\n\n//\n// API surface\n//\n\n/** GET /user — authenticated user profile. */\nexport const fetchUser = (): GitHubEffect<GitHubUser> =>\n githubRequest(() => HttpClientRequest.get(`${GITHUB_API_BASE}/user`), GitHubUserSchema);\n\n/** GET /user/orgs — orgs visible to the authenticated user. */\nexport const fetchUserOrgs = (): GitHubEffect<readonly GitHubOrg[]> =>\n githubPaginated(() => HttpClientRequest.get(`${GITHUB_API_BASE}/user/orgs`), GitHubOrgSchema);\n\n/**\n * GET /user/repos — every repo the authenticated user can see.\n *\n * Includes owner, collaborator, and org-member affiliations. For a GitHub App\n * user-to-server token this is intersected with the App's installation scope —\n * admins control which repos are visible by choosing All / Selected at install\n * time.\n */\nexport const fetchUserRepos = (): GitHubEffect<readonly GitHubRepo[]> =>\n githubPaginated(() => HttpClientRequest.get(`${GITHUB_API_BASE}/user/repos`), GitHubRepoSchema);\n\n/** GET /orgs/{org} — full org metadata. */\nexport const fetchOrg = (org: string): GitHubEffect<GitHubOrg> =>\n githubRequest(() => HttpClientRequest.get(`${GITHUB_API_BASE}/orgs/${encodeURIComponent(org)}`), GitHubOrgSchema);\n\n/** GET /orgs/{org}/members — public + private members (depends on token). */\nexport const fetchOrgMembers = (org: string): GitHubEffect<readonly GitHubUser[]> =>\n githubPaginated(\n () => HttpClientRequest.get(`${GITHUB_API_BASE}/orgs/${encodeURIComponent(org)}/members`),\n GitHubUserSchema,\n );\n\n/** GET /users/{login} — full user profile (org members lists return a partial form). */\nexport const fetchUserByLogin = (login: string): GitHubEffect<GitHubUser> =>\n githubRequest(() => HttpClientRequest.get(`${GITHUB_API_BASE}/users/${encodeURIComponent(login)}`), GitHubUserSchema);\n\n/** GET /orgs/{org}/repos — repos owned by the org. */\nexport const fetchOrgRepos = (org: string): GitHubEffect<readonly GitHubRepo[]> =>\n githubPaginated(\n () => HttpClientRequest.get(`${GITHUB_API_BASE}/orgs/${encodeURIComponent(org)}/repos`),\n GitHubRepoSchema,\n );\n\n/**\n * GET /repos/{owner}/{repo}/issues — both issues AND pull requests.\n *\n * `state=all` includes closed. PRs are distinguishable by a non-null\n * `pull_request` field. `since` is an optional ISO timestamp; when provided,\n * GitHub returns only issues updated at or after that point — we use this\n * for incremental syncs.\n */\nexport const fetchRepoIssues = (\n owner: string,\n repo: string,\n options: { since?: string } = {},\n): GitHubEffect<readonly GitHubIssue[]> =>\n githubPaginated(() => {\n let req = HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues`,\n ).pipe(HttpClientRequest.appendUrlParam('state', 'all'));\n if (options.since) {\n req = req.pipe(HttpClientRequest.appendUrlParam('since', options.since));\n }\n return req;\n }, GitHubIssueSchema);\n\n/** GET /repos/{owner}/{repo}. */\nexport const fetchRepo = (owner: string, repo: string): GitHubEffect<GitHubRepo> =>\n githubRequest(\n () => HttpClientRequest.get(`${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`),\n GitHubRepoSchema,\n );\n\n/** GET /repos/{owner}/{repo}/issues/{number} — an issue, or the issue view of a pull request. */\nexport const fetchIssue = (owner: string, repo: string, number: number): GitHubEffect<GitHubIssue> =>\n githubRequest(\n () =>\n HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${number}`,\n ),\n GitHubIssueSchema,\n );\n\n/** GET /repos/{owner}/{repo}/pulls/{number}. */\nexport const fetchPullRequest = (owner: string, repo: string, number: number): GitHubEffect<GitHubPull> =>\n githubRequest(\n () =>\n HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/pulls/${number}`,\n ),\n GitHubPullSchema,\n );\n\n/**\n * GET /repos/{owner}/{repo}/pulls/{number} as a unified diff — the same bytes `git diff` would\n * produce, which is what a generated walkthrough splices its chunks from.\n */\nexport const fetchPullRequestDiff = (owner: string, repo: string, number: number): GitHubEffect<string> =>\n githubText(\n () =>\n HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/pulls/${number}`,\n ),\n DIFF_ACCEPT,\n );\n\n/**\n * GET /repos/{owner}/{repo}/milestones — `state=all` so closed milestones stay mirrored (the\n * issues still assigned to them have to resolve to something).\n */\nexport const fetchRepoMilestones = (owner: string, repo: string): GitHubEffect<readonly GitHubMilestone[]> =>\n githubPaginated(\n () =>\n HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/milestones`,\n ).pipe(HttpClientRequest.appendUrlParam('state', 'all')),\n GitHubMilestoneSchema,\n );\n\n/** GET /repos/{owner}/{repo}/issues/{number}/comments. */\nexport const fetchIssueComments = (\n owner: string,\n repo: string,\n issueNumber: number,\n): GitHubEffect<readonly GitHubComment[]> =>\n githubPaginated(\n () =>\n HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${issueNumber}/comments`,\n ),\n GitHubCommentSchema,\n );\n\n//\n// Mutations (push)\n//\n\n/**\n * Write to a GitHub object (PATCH or POST, as `build` chooses). The shape mirrors {@link githubRequest} except the\n * body is `application/json`. Failures are\n * propagated unchanged; the caller is expected to surface them on the target\n * row's `lastError`.\n *\n * Only PATCH retries (429 / 5xx retry, 4xx don't). A POST here creates a comment or a review, and\n * GitHub can commit one before the response reaches us, so retrying a timeout would post it twice.\n */\nconst githubWrite = <T>(\n build: () => HttpClientRequest.HttpClientRequest,\n body: Record<string, unknown>,\n schema: Schema.Codec<T>,\n): GitHubEffect<T> =>\n Effect.gen(function* () {\n const creds = yield* GitHubCredentials;\n const httpClient = yield* HttpClient.HttpClient;\n const clientNoTracer = httpClient.pipe(\n HttpClient.transformResponse(Effect.provideService(HttpClient.TracerDisabledWhen, () => true)),\n HttpClient.filterStatusOk,\n );\n const request = withAuth(build(), creds).pipe(HttpClientRequest.bodyJsonUnsafe(body));\n const attempt = clientNoTracer.execute(request).pipe(\n Effect.flatMap((res) => Effect.flatMap(res.json, Schema.decodeUnknownEffect(schema))),\n Effect.timeout('15 seconds'),\n );\n return yield* (\n request.method === 'PATCH'\n ? attempt.pipe(\n Effect.retry({\n schedule: Schedule.exponential('500 millis').pipe(Schedule.jittered, Schedule.upTo({ times: 3 })),\n while: shouldRetry,\n }),\n )\n : attempt\n ).pipe(Effect.scoped);\n });\n\nexport type IssueUpdateInput = {\n title?: string;\n body?: string;\n state?: 'open' | 'closed';\n state_reason?: 'completed' | 'not_planned' | 'reopened' | null;\n};\n\n/**\n * PATCH /repos/{owner}/{repo}/issues/{number} — update title / body / state.\n *\n * GitHub conflates issues and PRs at this endpoint: the same PATCH works for\n * both, but PR-specific fields (head/base/draft) must go through the\n * `/pulls/{n}` endpoint. We only touch issue-mappable fields here.\n */\nexport const updateIssue = (\n owner: string,\n repo: string,\n issueNumber: number,\n input: IssueUpdateInput,\n): GitHubEffect<GitHubIssue> =>\n githubWrite(\n () =>\n HttpClientRequest.patch(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${issueNumber}`,\n ),\n input as unknown as Record<string, unknown>,\n GitHubIssueSchema,\n );\n\nexport type RepoUpdateInput = {\n /** GitHub allows the owner of a repo to rename it; this is rare and risky and we currently don't push it. */\n name?: string;\n description?: string;\n homepage?: string;\n};\n\n/**\n * PATCH /repos/{owner}/{repo} — update repo description and a small set of\n * mapped metadata. Renames (`name`) are accepted by the API but we don't push\n * them by default: a rename invalidates clones, breaks pinned URLs, and is\n * almost never what a user wants from a sync mirror.\n */\nexport const updateRepo = (owner: string, repo: string, input: RepoUpdateInput): GitHubEffect<GitHubRepo> =>\n githubWrite(\n () => HttpClientRequest.patch(`${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`),\n input as unknown as Record<string, unknown>,\n GitHubRepoSchema,\n );\n\nconst GitHubReviewSchema = Schema.Struct({\n id: Schema.Number,\n state: Schema.String,\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\nexport type GitHubReview = Schema.Schema.Type<typeof GitHubReviewSchema>;\n\n/** POST /repos/{owner}/{repo}/pulls/{number}/reviews with `event: APPROVE`. */\nexport const approvePullRequest = (\n owner: string,\n repo: string,\n number: number,\n body?: string,\n): GitHubEffect<GitHubReview> =>\n githubWrite(\n () =>\n HttpClientRequest.post(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/pulls/${number}/reviews`,\n ),\n { event: 'APPROVE', ...(body ? { body } : {}) },\n GitHubReviewSchema,\n );\n\nconst GitHubSubmittedReviewSchema = Schema.Struct({\n id: Schema.Number,\n /** `APPROVED`, `CHANGES_REQUESTED`, `COMMENTED`, `DISMISSED` or `PENDING`. */\n state: Schema.String,\n user: Schema.NullOr(Schema.Struct({ login: Schema.String })).pipe(Schema.optional),\n submitted_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\nexport type GitHubSubmittedReview = Schema.Schema.Type<typeof GitHubSubmittedReviewSchema>;\n\n/**\n * GET /repos/{owner}/{repo}/pulls/{number}/reviews — every page, oldest first, since a reviewer's\n * standing verdict is their latest review and a truncated list could miss it.\n */\nexport const fetchReviews = (\n owner: string,\n repo: string,\n number: number,\n): GitHubEffect<readonly GitHubSubmittedReview[]> =>\n githubPages(\n () =>\n HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/pulls/${number}/reviews`,\n ),\n Schema.Array(GitHubSubmittedReviewSchema),\n (page) => page,\n );\n\n/** POST /repos/{owner}/{repo}/issues/{number}/comments — a conversation comment, which a pull request shares with issues. */\nexport const createIssueComment = (\n owner: string,\n repo: string,\n issueNumber: number,\n body: string,\n): GitHubEffect<GitHubComment> =>\n githubWrite(\n () =>\n HttpClientRequest.post(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${issueNumber}/comments`,\n ),\n { body },\n GitHubCommentSchema,\n );\n\nconst GitHubCheckRunSchema = Schema.Struct({\n id: Schema.Number.pipe(Schema.optional),\n name: Schema.String,\n /** `queued`, `in_progress` or `completed`. */\n status: Schema.String,\n /** Set once `completed`: `success`, `failure`, `neutral`, `cancelled`, `skipped`, `timed_out`, `action_required`. */\n conclusion: Schema.NullOr(Schema.String).pipe(Schema.optional),\n html_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n /** The provider's own page for the run (Depot, say), which GitHub's `html_url` only links back to. */\n details_url: Schema.NullOr(Schema.String).pipe(Schema.optional),\n started_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n completed_at: Schema.NullOr(Schema.String).pipe(Schema.optional),\n});\nexport type GitHubCheckRun = Schema.Schema.Type<typeof GitHubCheckRunSchema>;\n\nconst GitHubCheckRunsSchema = Schema.Struct({\n total_count: Schema.Number,\n check_runs: Schema.Array(GitHubCheckRunSchema),\n});\n\n/**\n * GET /repos/{owner}/{repo}/commits/{sha}/check-runs — every page, since a truncated list would\n * report a failing commit as green.\n */\nexport const fetchCheckRuns = (owner: string, repo: string, sha: string): GitHubEffect<readonly GitHubCheckRun[]> =>\n githubPages(\n () =>\n HttpClientRequest.get(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/commits/${encodeURIComponent(sha)}/check-runs`,\n ),\n GitHubCheckRunsSchema,\n ({ check_runs }) => check_runs,\n );\n\nexport type ReviewCommentInput = {\n body: string;\n /** Head SHA the line numbers refer to. */\n commit_id: string;\n path: string;\n line: number;\n /** `LEFT` is the base (removed) side, `RIGHT` the head (added or context) side. */\n side: 'LEFT' | 'RIGHT';\n};\n\n/** POST /repos/{owner}/{repo}/pulls/{number}/comments — a review comment on one line of the diff. */\nexport const createReviewComment = (\n owner: string,\n repo: string,\n number: number,\n input: ReviewCommentInput,\n): GitHubEffect<GitHubComment> =>\n githubWrite(\n () =>\n HttpClientRequest.post(\n `${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/pulls/${number}/comments`,\n ),\n input,\n GitHubCommentSchema,\n );\n"],"mappings":"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"}
|
|
@@ -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 {
|
|
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":["GitHubApi.fetchPullRequest","GitHubApi.GitHubCredentials","GitHubApi.responseStatus"],"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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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-link-resolver.mjs","names":[],"sources":["../../src/capabilities/link-resolver.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 Capability from '@dxos/app-framework/Capability';\nimport { Database, Filter } from '@dxos/echo';\nimport { Connection } from '@dxos/link';\nimport { log } from '@dxos/log';\nimport * as PreviewCapabilities from '@dxos/plugin-preview/PreviewCapabilities';\nimport { Issue, PullRequest, Repo } from '@dxos/types';\n\nimport { GitHubCapabilities } from '#types';\n\nimport { GITHUB_PROVIDER_ID } from '../constants.ts';\nimport { type GitHubLink, githubLinkIcon, parseGitHubLink } from '../extensions/index.ts';\nimport { toPullRequestProps } from '../pull-request.ts';\nimport { GitHubApi } from '../services/index.ts';\n\n/**\n * Resolves a GitHub repository, pull-request or issue URL to an in-memory `Repo`, `PullRequest` or\n * `Issue` for the preview popover. The object comes from the contributed `LinkSource` when a host provides one and\n * from the GitHub API otherwise; either way it is built, not stored — a preview is not a sync.\n */\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n const capabilities = yield* Capability.Service;\n return Capability.contribute(PreviewCapabilities.LinkResolver, [\n {\n match: (url) => parseGitHubLink(url) !== undefined,\n // How GitHub itself shortens a bare reference: the number, or the repository's full name.\n label: (url) => {\n const link = parseGitHubLink(url);\n return link && (link.number !== undefined ? `#${link.number}` : `${link.owner}/${link.repo}`);\n },\n icon: githubLinkIcon,\n resolve: ({ eid }, context) =>\n Effect.gen(function* () {\n const link = parseGitHubLink(eid);\n if (!link) {\n return undefined;\n }\n const [source = fetchFromGitHub] = capabilities.getAll(GitHubCapabilities.LinkSource);\n const object = yield* source(link, context);\n return (\n object && { label: Repo.instanceOf(object) ? Repo.fullName(object) : Issue.reference(object), object }\n );\n }),\n },\n ]);\n }),\n);\n\n/**\n * The default source: each of the space's GitHub connection tokens in turn — a space can hold\n * several, and only some may reach a private repository — then anonymous, which reaches a public one.\n */\nconst fetchFromGitHub: GitHubCapabilities.GitHubLinkSource = (link, { db }) =>\n Effect.gen(function* () {\n const tokens = db ? yield* connectionTokens(db) : [];\n for (const token of [...tokens, '']) {\n const object = yield* fetchLink(link).pipe(\n Effect.provide(Layer.succeed(GitHubApi.GitHubCredentials, { token })),\n Effect.tapError((error) => Effect.sync(() => log.warn('github link preview failed', { url: link.url, error }))),\n Effect.catch(() => Effect.succeed(undefined)),\n );\n if (object) {\n return object;\n }\n }\n return undefined;\n }).pipe(\n Effect.provide(FetchHttpClient.layer),\n Effect.catch(() => Effect.succeed(undefined)),\n );\n\n/** The tokens of the space's GitHub connections, in query order. */\nconst connectionTokens = (db: NonNullable<PreviewCapabilities.PreviewLinkContext['db']>) =>\n Effect.gen(function* () {\n const connections = yield* Database.query(Filter.type(Connection.Connection)).run;\n const tokens: string[] = [];\n for (const connection of connections) {\n if (connection.connectorId !== GITHUB_PROVIDER_ID) {\n continue;\n }\n const accessToken = yield* Database.load(connection.accessToken);\n tokens.push(accessToken.token);\n }\n return tokens;\n }).pipe(Effect.provide(Database.layer(db)));\n\nconst fetchLink = (link: GitHubLink) =>\n Effect.gen(function* () {\n const { owner, repo, number } = link;\n if (link.kind === 'repo' || number === undefined) {\n return toRepo(link, yield* GitHubApi.fetchRepo(owner, repo));\n }\n if (link.kind === 'pull') {\n return toPullRequest(link, yield* GitHubApi.fetchPullRequest(owner, repo, number));\n }\n const issue = yield* GitHubApi.fetchIssue(owner, repo, number);\n // The issue endpoint answers for a pull request's number too; only the pull endpoint has its diff.\n if (issue.pull_request) {\n return toPullRequest(link, yield* GitHubApi.fetchPullRequest(owner, repo, number));\n }\n return toIssue(link, issue);\n });\n\nconst toRepo = ({ owner, url }: GitHubLink, repo: GitHubApi.GitHubRepo): Repo.Repo =>\n Repo.make({\n owner,\n name: repo.name,\n url: repo.html_url ?? url,\n description: repo.description ?? undefined,\n defaultBranch: repo.default_branch ?? undefined,\n });\n\nconst toIssue = ({ owner, repo, number = 0, url }: GitHubLink, issue: GitHubApi.GitHubIssue): Issue.Issue =>\n Issue.make({\n owner,\n repo,\n number,\n title: issue.title,\n url: issue.html_url ?? url,\n state: issue.state === 'closed' ? 'closed' : 'open',\n author: issue.user?.login,\n description: issue.body ?? undefined,\n labels: issue.labels?.map((label) => label.name),\n });\n\nconst toPullRequest = (\n { owner, repo, number = 0, url }: GitHubLink,\n pull: GitHubApi.GitHubPull,\n): PullRequest.PullRequest => PullRequest.make(toPullRequestProps({ owner, repo, number, url }, pull));\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA2BA,IAAA,wBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,MAAM,eAAe,OAAO,WAAW;CACvC,OAAO,WAAW,WAAW,oBAAoB,cAAc,CAC7D;EACE,QAAQ,QAAQ,gBAAgB,GAAG,MAAM,KAAA;EAEzC,QAAQ,QAAQ;GACd,MAAM,OAAO,gBAAgB,GAAG;GAChC,OAAO,SAAS,KAAK,WAAW,KAAA,IAAY,IAAI,KAAK,WAAW,GAAG,KAAK,MAAM,GAAG,KAAK;EACxF;EACA,MAAM;EACN,UAAU,EAAE,OAAO,YACjB,OAAO,IAAI,aAAa;GACtB,MAAM,OAAO,gBAAgB,GAAG;GAChC,IAAI,CAAC,MACH;GAEF,MAAM,CAAC,SAAS,mBAAmB,aAAa,OAAO,mBAAmB,UAAU;GACpF,MAAM,SAAS,OAAO,OAAO,MAAM,OAAO;GAC1C,OACE,UAAU;IAAE,OAAO,KAAK,WAAW,MAAM,IAAI,KAAK,SAAS,MAAM,IAAI,MAAM,UAAU,MAAM;IAAG;GAAO;EAEzG,CAAC;CACL,CACF,CAAC;AACH,CAAC,CACH;;;;;AAMA,IAAM,mBAAwD,MAAM,EAAE,SACpE,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,KAAK,OAAO,iBAAiB,EAAE,IAAI,CAAC;CACnD,KAAK,MAAM,SAAS,CAAC,GAAG,QAAQ,EAAE,GAAG;EACnC,MAAM,SAAS,OAAO,UAAU,IAAI,CAAC,CAAC,KACpC,OAAO,QAAQ,MAAM,
|
|
1
|
+
{"version":3,"file":"chunk-link-resolver.mjs","names":["GitHubApi.GitHubCredentials","GitHubApi.fetchRepo","GitHubApi.fetchPullRequest","GitHubApi.fetchIssue"],"sources":["../../src/capabilities/link-resolver.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 Capability from '@dxos/app-framework/Capability';\nimport { Database, Filter } from '@dxos/echo';\nimport { Connection } from '@dxos/link';\nimport { log } from '@dxos/log';\nimport * as PreviewCapabilities from '@dxos/plugin-preview/PreviewCapabilities';\nimport { Issue, PullRequest, Repo } from '@dxos/types';\n\nimport { GitHubCapabilities } from '#types';\n\nimport { GITHUB_PROVIDER_ID } from '../constants.ts';\nimport { type GitHubLink, githubLinkIcon, parseGitHubLink } from '../extensions/index.ts';\nimport { toPullRequestProps } from '../pull-request.ts';\nimport { GitHubApi } from '../services/index.ts';\n\n/**\n * Resolves a GitHub repository, pull-request or issue URL to an in-memory `Repo`, `PullRequest` or\n * `Issue` for the preview popover. The object comes from the contributed `LinkSource` when a host provides one and\n * from the GitHub API otherwise; either way it is built, not stored — a preview is not a sync.\n */\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n const capabilities = yield* Capability.Service;\n return Capability.contribute(PreviewCapabilities.LinkResolver, [\n {\n match: (url) => parseGitHubLink(url) !== undefined,\n // How GitHub itself shortens a bare reference: the number, or the repository's full name.\n label: (url) => {\n const link = parseGitHubLink(url);\n return link && (link.number !== undefined ? `#${link.number}` : `${link.owner}/${link.repo}`);\n },\n icon: githubLinkIcon,\n resolve: ({ eid }, context) =>\n Effect.gen(function* () {\n const link = parseGitHubLink(eid);\n if (!link) {\n return undefined;\n }\n const [source = fetchFromGitHub] = capabilities.getAll(GitHubCapabilities.LinkSource);\n const object = yield* source(link, context);\n return (\n object && { label: Repo.instanceOf(object) ? Repo.fullName(object) : Issue.reference(object), object }\n );\n }),\n },\n ]);\n }),\n);\n\n/**\n * The default source: each of the space's GitHub connection tokens in turn — a space can hold\n * several, and only some may reach a private repository — then anonymous, which reaches a public one.\n */\nconst fetchFromGitHub: GitHubCapabilities.GitHubLinkSource = (link, { db }) =>\n Effect.gen(function* () {\n const tokens = db ? yield* connectionTokens(db) : [];\n for (const token of [...tokens, '']) {\n const object = yield* fetchLink(link).pipe(\n Effect.provide(Layer.succeed(GitHubApi.GitHubCredentials, { token })),\n Effect.tapError((error) => Effect.sync(() => log.warn('github link preview failed', { url: link.url, error }))),\n Effect.catch(() => Effect.succeed(undefined)),\n );\n if (object) {\n return object;\n }\n }\n return undefined;\n }).pipe(\n Effect.provide(FetchHttpClient.layer),\n Effect.catch(() => Effect.succeed(undefined)),\n );\n\n/** The tokens of the space's GitHub connections, in query order. */\nconst connectionTokens = (db: NonNullable<PreviewCapabilities.PreviewLinkContext['db']>) =>\n Effect.gen(function* () {\n const connections = yield* Database.query(Filter.type(Connection.Connection)).run;\n const tokens: string[] = [];\n for (const connection of connections) {\n if (connection.connectorId !== GITHUB_PROVIDER_ID) {\n continue;\n }\n const accessToken = yield* Database.load(connection.accessToken);\n tokens.push(accessToken.token);\n }\n return tokens;\n }).pipe(Effect.provide(Database.layer(db)));\n\nconst fetchLink = (link: GitHubLink) =>\n Effect.gen(function* () {\n const { owner, repo, number } = link;\n if (link.kind === 'repo' || number === undefined) {\n return toRepo(link, yield* GitHubApi.fetchRepo(owner, repo));\n }\n if (link.kind === 'pull') {\n return toPullRequest(link, yield* GitHubApi.fetchPullRequest(owner, repo, number));\n }\n const issue = yield* GitHubApi.fetchIssue(owner, repo, number);\n // The issue endpoint answers for a pull request's number too; only the pull endpoint has its diff.\n if (issue.pull_request) {\n return toPullRequest(link, yield* GitHubApi.fetchPullRequest(owner, repo, number));\n }\n return toIssue(link, issue);\n });\n\nconst toRepo = ({ owner, url }: GitHubLink, repo: GitHubApi.GitHubRepo): Repo.Repo =>\n Repo.make({\n owner,\n name: repo.name,\n url: repo.html_url ?? url,\n description: repo.description ?? undefined,\n defaultBranch: repo.default_branch ?? undefined,\n });\n\nconst toIssue = ({ owner, repo, number = 0, url }: GitHubLink, issue: GitHubApi.GitHubIssue): Issue.Issue =>\n Issue.make({\n owner,\n repo,\n number,\n title: issue.title,\n url: issue.html_url ?? url,\n state: issue.state === 'closed' ? 'closed' : 'open',\n author: issue.user?.login,\n description: issue.body ?? undefined,\n labels: issue.labels?.map((label) => label.name),\n });\n\nconst toPullRequest = (\n { owner, repo, number = 0, url }: GitHubLink,\n pull: GitHubApi.GitHubPull,\n): PullRequest.PullRequest => PullRequest.make(toPullRequestProps({ owner, repo, number, url }, pull));\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA2BA,IAAA,wBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,MAAM,eAAe,OAAO,WAAW;CACvC,OAAO,WAAW,WAAW,oBAAoB,cAAc,CAC7D;EACE,QAAQ,QAAQ,gBAAgB,GAAG,MAAM,KAAA;EAEzC,QAAQ,QAAQ;GACd,MAAM,OAAO,gBAAgB,GAAG;GAChC,OAAO,SAAS,KAAK,WAAW,KAAA,IAAY,IAAI,KAAK,WAAW,GAAG,KAAK,MAAM,GAAG,KAAK;EACxF;EACA,MAAM;EACN,UAAU,EAAE,OAAO,YACjB,OAAO,IAAI,aAAa;GACtB,MAAM,OAAO,gBAAgB,GAAG;GAChC,IAAI,CAAC,MACH;GAEF,MAAM,CAAC,SAAS,mBAAmB,aAAa,OAAO,mBAAmB,UAAU;GACpF,MAAM,SAAS,OAAO,OAAO,MAAM,OAAO;GAC1C,OACE,UAAU;IAAE,OAAO,KAAK,WAAW,MAAM,IAAI,KAAK,SAAS,MAAM,IAAI,MAAM,UAAU,MAAM;IAAG;GAAO;EAEzG,CAAC;CACL,CACF,CAAC;AACH,CAAC,CACH;;;;;AAMA,IAAM,mBAAwD,MAAM,EAAE,SACpE,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,KAAK,OAAO,iBAAiB,EAAE,IAAI,CAAC;CACnD,KAAK,MAAM,SAAS,CAAC,GAAG,QAAQ,EAAE,GAAG;EACnC,MAAM,SAAS,OAAO,UAAU,IAAI,CAAC,CAAC,KACpC,OAAO,QAAQ,MAAM,QAAQA,mBAA6B,EAAE,MAAM,CAAC,CAAC,GACpE,OAAO,UAAU,UAAU,OAAO,WAAW,IAAI,KAAK,8BAA8B;GAAE,KAAK,KAAK;GAAK;EAAM,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA;EAAA,CAAC,CAAC,CAAC,GAC9G,OAAO,YAAY,OAAO,QAAQ,KAAA,CAAS,CAAC,CAC9C;EACA,IAAI,QACF,OAAO;CAEX;AAEF,CAAC,CAAC,CAAC,KACD,OAAO,QAAQ,gBAAgB,KAAK,GACpC,OAAO,YAAY,OAAO,QAAQ,KAAA,CAAS,CAAC,CAC9C;;AAGF,IAAM,oBAAoB,OACxB,OAAO,IAAI,aAAa;CACtB,MAAM,cAAc,OAAO,SAAS,MAAM,OAAO,KAAK,WAAW,UAAU,CAAC,CAAC,CAAC;CAC9E,MAAM,SAAmB,CAAC;CAC1B,KAAK,MAAM,cAAc,aAAa;EACpC,IAAI,WAAW,gBAAA,UACb;EAEF,MAAM,cAAc,OAAO,SAAS,KAAK,WAAW,WAAW;EAC/D,OAAO,KAAK,YAAY,KAAK;CAC/B;CACA,OAAO;AACT,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,CAAC;AAE5C,IAAM,aAAa,SACjB,OAAO,IAAI,aAAa;CACtB,MAAM,EAAE,OAAO,MAAM,WAAW;CAChC,IAAI,KAAK,SAAS,UAAU,WAAW,KAAA,GACrC,OAAO,OAAO,MAAM,OAAOC,UAAoB,OAAO,IAAI,CAAC;CAE7D,IAAI,KAAK,SAAS,QAChB,OAAO,cAAc,MAAM,OAAOC,iBAA2B,OAAO,MAAM,MAAM,CAAC;CAEnF,MAAM,QAAQ,OAAOC,WAAqB,OAAO,MAAM,MAAM;CAE7D,IAAI,MAAM,cACR,OAAO,cAAc,MAAM,OAAOD,iBAA2B,OAAO,MAAM,MAAM,CAAC;CAEnF,OAAO,QAAQ,MAAM,KAAK;AAC5B,CAAC;AAEH,IAAM,UAAU,EAAE,OAAO,OAAmB,SAC1C,KAAK,KAAK;CACR;CACA,MAAM,KAAK;CACX,KAAK,KAAK,YAAY;CACtB,aAAa,KAAK,eAAe,KAAA;CACjC,eAAe,KAAK,kBAAkB,KAAA;AACxC,CAAC;AAEH,IAAM,WAAW,EAAE,OAAO,MAAM,SAAS,GAAG,OAAmB,UAC7D,MAAM,KAAK;CACT;CACA;CACA;CACA,OAAO,MAAM;CACb,KAAK,MAAM,YAAY;CACvB,OAAO,MAAM,UAAU,WAAW,WAAW;CAC7C,QAAQ,MAAM,MAAM;CACpB,aAAa,MAAM,QAAQ,KAAA;CAC3B,QAAQ,MAAM,QAAQ,KAAK,UAAU,MAAM,IAAI;AACjD,CAAC;AAEH,IAAM,iBACJ,EAAE,OAAO,MAAM,SAAS,GAAG,OAC3B,SAC4B,YAAY,KAAK,mBAAmB;CAAE;CAAO;CAAM;CAAQ;AAAI,GAAG,IAAI,CAAC"}
|
|
@@ -56,6 +56,7 @@ var toCheckRun = (run) => {
|
|
|
56
56
|
const outcome = run.status !== "completed" ? "pending" : run.conclusion && FAILED_CONCLUSIONS.has(run.conclusion) ? "failure" : run.conclusion === "skipped" ? "skipped" : run.conclusion === "neutral" ? "neutral" : "success";
|
|
57
57
|
const url = run.details_url ?? run.html_url;
|
|
58
58
|
return {
|
|
59
|
+
...run.id !== void 0 ? { id: run.id } : {},
|
|
59
60
|
name: run.name,
|
|
60
61
|
outcome,
|
|
61
62
|
...run.conclusion ? { conclusion: run.conclusion } : {},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-pull-request2.mjs","names":[],"sources":["../../src/operations/pull-request.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\n\nimport { Database, Filter, Obj, type Ref } from '@dxos/echo';\nimport { Connection } from '@dxos/link';\nimport { type PullRequest } from '@dxos/types';\n\nimport { type GitHubOperation } from '#types';\n\nimport { GITHUB_PROVIDER_ID } from '../constants.ts';\nimport { GitHubPullRequestUnstoredError } from '../errors.ts';\nimport { GitHubApi } from '../services/index.ts';\n\n/**\n * The GitHub connection whose token requests are sent with: the first one holding a token. Shared by\n * the handlers and by the UI that sends the user to reconnect, so both name the same connection.\n */\nexport const githubConnection = () =>\n Effect.gen(function* () {\n const connections = yield* Database.query(Filter.type(Connection.Connection)).run;\n for (const connection of connections) {\n if (connection.connectorId !== GITHUB_PROVIDER_ID) {\n continue;\n }\n const accessToken = yield* Database.load(connection.accessToken);\n if (accessToken.token) {\n return { connection, token: accessToken.token };\n }\n }\n\n return undefined;\n });\n\n/**\n * The token of {@link githubConnection}, or empty for anonymous — which reaches any public pull\n * request, and is the only option in a space that has not connected GitHub.\n */\nexport const githubToken = () => githubConnection().pipe(Effect.map((selected) => selected?.token ?? ''));\n\n/**\n * The stored pull request behind an operation's input and credentials for its space.\n *\n * The invoker carries no database resolver, so handlers derive one from the pull request itself; a\n * preview card's in-memory pull request has none and cannot be acted on.\n */\nexport const resolvePullRequest = (ref: Ref.Ref<PullRequest.PullRequest>) =>\n Effect.gen(function* () {\n const pullRequest = ref.target;\n const db = pullRequest ? Obj.getDatabase(pullRequest) : undefined;\n if (!pullRequest || !db) {\n return yield* Effect.die(new GitHubPullRequestUnstoredError());\n }\n const token = yield* githubToken().pipe(Effect.provide(Database.layer(db)));\n return { pullRequest, db, credentials: Layer.succeed(GitHubApi.GitHubCredentials, { token }) };\n });\n\n// `stale` is a completed run GitHub never re-ran, which branch protection does not count as passing.\nconst FAILED_CONCLUSIONS = new Set([\n 'failure',\n 'cancelled',\n 'timed_out',\n 'action_required',\n 'startup_failure',\n 'stale',\n]);\n\n/** One check run as the article lists it: its outcome folded the way {@link summarizeCheckRuns} counts it. */\nexport const toCheckRun = (run: GitHubApi.GitHubCheckRun): GitHubOperation.CheckRun => {\n const outcome: GitHubOperation.CheckOutcome =\n run.status !== 'completed'\n ? 'pending'\n : run.conclusion && FAILED_CONCLUSIONS.has(run.conclusion)\n ? 'failure'\n : run.conclusion === 'skipped'\n ? 'skipped'\n : run.conclusion === 'neutral'\n ? 'neutral'\n : 'success';\n const url = run.details_url ?? run.html_url;\n return {\n name: run.name,\n outcome,\n ...(run.conclusion ? { conclusion: run.conclusion } : {}),\n ...(url ? { url } : {}),\n ...(run.started_at ? { startedAt: run.started_at } : {}),\n ...(run.completed_at ? { completedAt: run.completed_at } : {}),\n };\n};\n\n/** Folds a commit's check runs into one outcome: any failure fails, then any unfinished run is pending. */\nexport const summarizeCheckRuns = (\n runs: readonly GitHubApi.GitHubCheckRun[],\n): { ci: GitHubOperation.CiState; checks: GitHubOperation.CheckCounts } => {\n const checks = { total: runs.length, passed: 0, failed: 0, pending: 0 };\n for (const run of runs) {\n if (run.status !== 'completed') {\n checks.pending++;\n } else if (run.conclusion && FAILED_CONCLUSIONS.has(run.conclusion)) {\n checks.failed++;\n } else {\n checks.passed++;\n }\n }\n\n const ci: GitHubOperation.CiState =\n checks.total === 0 ? 'none' : checks.failed > 0 ? 'failure' : checks.pending > 0 ? 'pending' : 'success';\n return { ci, checks };\n};\n\n/** Review states that set a reviewer's standing verdict; a comment leaves the previous one in place. */\nconst VERDICT_STATES = new Set(['APPROVED', 'CHANGES_REQUESTED', 'DISMISSED']);\n\n/**\n * Folds a pull request's reviews into where they stand, from each reviewer's latest verdict — the\n * way GitHub reads them: a later approval clears that reviewer's request for changes, and a dismissal\n * withdraws whichever verdict it replaced.\n */\nexport const summarizeReviews = (\n reviews: readonly GitHubApi.GitHubSubmittedReview[],\n): { review: GitHubOperation.ReviewState; approvals: number } => {\n const verdicts = new Map<string, string>();\n for (const review of reviews) {\n const login = review.user?.login;\n if (login && VERDICT_STATES.has(review.state)) {\n verdicts.set(login, review.state);\n }\n }\n\n const states = [...verdicts.values()];\n const approvals = states.filter((state) => state === 'APPROVED').length;\n const review: GitHubOperation.ReviewState = states.includes('CHANGES_REQUESTED')\n ? 'changes_requested'\n : approvals > 0\n ? 'approved'\n : 'none';\n return { review, approvals };\n};\n"],"mappings":";;;;;;;;;;;;AAqBA,IAAa,yBACX,OAAO,IAAI,aAAa;CACtB,MAAM,cAAc,OAAO,SAAS,MAAM,OAAO,KAAK,WAAW,UAAU,CAAC,CAAC,CAAC;CAC9E,KAAK,MAAM,cAAc,aAAa;EACpC,IAAI,WAAW,gBAAA,UACb;EAEF,MAAM,cAAc,OAAO,SAAS,KAAK,WAAW,WAAW;EAC/D,IAAI,YAAY,OACd,OAAO;GAAE;GAAY,OAAO,YAAY;EAAM;CAElD;AAGF,CAAC;;;;;AAMH,IAAa,oBAAoB,iBAAiB,CAAC,CAAC,KAAK,OAAO,KAAK,aAAa,UAAU,SAAS,EAAE,CAAC;;;;;;;AAQxG,IAAa,sBAAsB,QACjC,OAAO,IAAI,aAAa;CACtB,MAAM,cAAc,IAAI;CACxB,MAAM,KAAK,cAAc,IAAI,YAAY,WAAW,IAAI,KAAA;CACxD,IAAI,CAAC,eAAe,CAAC,IACnB,OAAO,OAAO,OAAO,IAAI,IAAI,+BAA+B,CAAC;CAE/D,MAAM,QAAQ,OAAO,YAAY,CAAC,CAAC,KAAK,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,CAAC;CAC1E,OAAO;EAAE;EAAa;EAAI,aAAa,MAAM,
|
|
1
|
+
{"version":3,"file":"chunk-pull-request2.mjs","names":["GitHubApi.GitHubCredentials"],"sources":["../../src/operations/pull-request.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\n\nimport { Database, Filter, Obj, type Ref } from '@dxos/echo';\nimport { Connection } from '@dxos/link';\nimport { type PullRequest } from '@dxos/types';\n\nimport { type GitHubOperation } from '#types';\n\nimport { GITHUB_PROVIDER_ID } from '../constants.ts';\nimport { GitHubPullRequestUnstoredError } from '../errors.ts';\nimport { GitHubApi } from '../services/index.ts';\n\n/**\n * The GitHub connection whose token requests are sent with: the first one holding a token. Shared by\n * the handlers and by the UI that sends the user to reconnect, so both name the same connection.\n */\nexport const githubConnection = () =>\n Effect.gen(function* () {\n const connections = yield* Database.query(Filter.type(Connection.Connection)).run;\n for (const connection of connections) {\n if (connection.connectorId !== GITHUB_PROVIDER_ID) {\n continue;\n }\n const accessToken = yield* Database.load(connection.accessToken);\n if (accessToken.token) {\n return { connection, token: accessToken.token };\n }\n }\n\n return undefined;\n });\n\n/**\n * The token of {@link githubConnection}, or empty for anonymous — which reaches any public pull\n * request, and is the only option in a space that has not connected GitHub.\n */\nexport const githubToken = () => githubConnection().pipe(Effect.map((selected) => selected?.token ?? ''));\n\n/**\n * The stored pull request behind an operation's input and credentials for its space.\n *\n * The invoker carries no database resolver, so handlers derive one from the pull request itself; a\n * preview card's in-memory pull request has none and cannot be acted on.\n */\nexport const resolvePullRequest = (ref: Ref.Ref<PullRequest.PullRequest>) =>\n Effect.gen(function* () {\n const pullRequest = ref.target;\n const db = pullRequest ? Obj.getDatabase(pullRequest) : undefined;\n if (!pullRequest || !db) {\n return yield* Effect.die(new GitHubPullRequestUnstoredError());\n }\n const token = yield* githubToken().pipe(Effect.provide(Database.layer(db)));\n return { pullRequest, db, credentials: Layer.succeed(GitHubApi.GitHubCredentials, { token }) };\n });\n\n// `stale` is a completed run GitHub never re-ran, which branch protection does not count as passing.\nconst FAILED_CONCLUSIONS = new Set([\n 'failure',\n 'cancelled',\n 'timed_out',\n 'action_required',\n 'startup_failure',\n 'stale',\n]);\n\n/** One check run as the article lists it: its outcome folded the way {@link summarizeCheckRuns} counts it. */\nexport const toCheckRun = (run: GitHubApi.GitHubCheckRun): GitHubOperation.CheckRun => {\n const outcome: GitHubOperation.CheckOutcome =\n run.status !== 'completed'\n ? 'pending'\n : run.conclusion && FAILED_CONCLUSIONS.has(run.conclusion)\n ? 'failure'\n : run.conclusion === 'skipped'\n ? 'skipped'\n : run.conclusion === 'neutral'\n ? 'neutral'\n : 'success';\n const url = run.details_url ?? run.html_url;\n return {\n ...(run.id !== undefined ? { id: run.id } : {}),\n name: run.name,\n outcome,\n ...(run.conclusion ? { conclusion: run.conclusion } : {}),\n ...(url ? { url } : {}),\n ...(run.started_at ? { startedAt: run.started_at } : {}),\n ...(run.completed_at ? { completedAt: run.completed_at } : {}),\n };\n};\n\n/** Folds a commit's check runs into one outcome: any failure fails, then any unfinished run is pending. */\nexport const summarizeCheckRuns = (\n runs: readonly GitHubApi.GitHubCheckRun[],\n): { ci: GitHubOperation.CiState; checks: GitHubOperation.CheckCounts } => {\n const checks = { total: runs.length, passed: 0, failed: 0, pending: 0 };\n for (const run of runs) {\n if (run.status !== 'completed') {\n checks.pending++;\n } else if (run.conclusion && FAILED_CONCLUSIONS.has(run.conclusion)) {\n checks.failed++;\n } else {\n checks.passed++;\n }\n }\n\n const ci: GitHubOperation.CiState =\n checks.total === 0 ? 'none' : checks.failed > 0 ? 'failure' : checks.pending > 0 ? 'pending' : 'success';\n return { ci, checks };\n};\n\n/** Review states that set a reviewer's standing verdict; a comment leaves the previous one in place. */\nconst VERDICT_STATES = new Set(['APPROVED', 'CHANGES_REQUESTED', 'DISMISSED']);\n\n/**\n * Folds a pull request's reviews into where they stand, from each reviewer's latest verdict — the\n * way GitHub reads them: a later approval clears that reviewer's request for changes, and a dismissal\n * withdraws whichever verdict it replaced.\n */\nexport const summarizeReviews = (\n reviews: readonly GitHubApi.GitHubSubmittedReview[],\n): { review: GitHubOperation.ReviewState; approvals: number } => {\n const verdicts = new Map<string, string>();\n for (const review of reviews) {\n const login = review.user?.login;\n if (login && VERDICT_STATES.has(review.state)) {\n verdicts.set(login, review.state);\n }\n }\n\n const states = [...verdicts.values()];\n const approvals = states.filter((state) => state === 'APPROVED').length;\n const review: GitHubOperation.ReviewState = states.includes('CHANGES_REQUESTED')\n ? 'changes_requested'\n : approvals > 0\n ? 'approved'\n : 'none';\n return { review, approvals };\n};\n"],"mappings":";;;;;;;;;;;;AAqBA,IAAa,yBACX,OAAO,IAAI,aAAa;CACtB,MAAM,cAAc,OAAO,SAAS,MAAM,OAAO,KAAK,WAAW,UAAU,CAAC,CAAC,CAAC;CAC9E,KAAK,MAAM,cAAc,aAAa;EACpC,IAAI,WAAW,gBAAA,UACb;EAEF,MAAM,cAAc,OAAO,SAAS,KAAK,WAAW,WAAW;EAC/D,IAAI,YAAY,OACd,OAAO;GAAE;GAAY,OAAO,YAAY;EAAM;CAElD;AAGF,CAAC;;;;;AAMH,IAAa,oBAAoB,iBAAiB,CAAC,CAAC,KAAK,OAAO,KAAK,aAAa,UAAU,SAAS,EAAE,CAAC;;;;;;;AAQxG,IAAa,sBAAsB,QACjC,OAAO,IAAI,aAAa;CACtB,MAAM,cAAc,IAAI;CACxB,MAAM,KAAK,cAAc,IAAI,YAAY,WAAW,IAAI,KAAA;CACxD,IAAI,CAAC,eAAe,CAAC,IACnB,OAAO,OAAO,OAAO,IAAI,IAAI,+BAA+B,CAAC;CAE/D,MAAM,QAAQ,OAAO,YAAY,CAAC,CAAC,KAAK,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,CAAC;CAC1E,OAAO;EAAE;EAAa;EAAI,aAAa,MAAM,QAAQA,mBAA6B,EAAE,MAAM,CAAC;CAAE;AAC/F,CAAC;AAGH,IAAM,qCAAqB,IAAI,IAAI;CACjC;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,IAAa,cAAc,QAA4D;CACrF,MAAM,UACJ,IAAI,WAAW,cACX,YACA,IAAI,cAAc,mBAAmB,IAAI,IAAI,UAAU,IACrD,YACA,IAAI,eAAe,YACjB,YACA,IAAI,eAAe,YACjB,YACA;CACZ,MAAM,MAAM,IAAI,eAAe,IAAI;CACnC,OAAO;EACL,GAAI,IAAI,OAAO,KAAA,IAAY,EAAE,IAAI,IAAI,GAAG,IAAI,CAAC;EAC7C,MAAM,IAAI;EACV;EACA,GAAI,IAAI,aAAa,EAAE,YAAY,IAAI,WAAW,IAAI,CAAC;EACvD,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;EACrB,GAAI,IAAI,aAAa,EAAE,WAAW,IAAI,WAAW,IAAI,CAAC;EACtD,GAAI,IAAI,eAAe,EAAE,aAAa,IAAI,aAAa,IAAI,CAAC;CAC9D;AACF;;AAGA,IAAa,sBACX,SACyE;CACzE,MAAM,SAAS;EAAE,OAAO,KAAK;EAAQ,QAAQ;EAAG,QAAQ;EAAG,SAAS;CAAE;CACtE,KAAK,MAAM,OAAO,MAChB,IAAI,IAAI,WAAW,aACjB,OAAO;MACF,IAAI,IAAI,cAAc,mBAAmB,IAAI,IAAI,UAAU,GAChE,OAAO;MAEP,OAAO;CAMX,OAAO;EAAE,IADP,OAAO,UAAU,IAAI,SAAS,OAAO,SAAS,IAAI,YAAY,OAAO,UAAU,IAAI,YAAY;EACpF;CAAO;AACtB;;AAGA,IAAM,iCAAiB,IAAI,IAAI;CAAC;CAAY;CAAqB;AAAW,CAAC;;;;;;AAO7E,IAAa,oBACX,YAC+D;CAC/D,MAAM,2BAAW,IAAI,IAAoB;CACzC,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,QAAQ,OAAO,MAAM;EAC3B,IAAI,SAAS,eAAe,IAAI,OAAO,KAAK,GAC1C,SAAS,IAAI,OAAO,OAAO,KAAK;CAEpC;CAEA,MAAM,SAAS,CAAC,GAAG,SAAS,OAAO,CAAC;CACpC,MAAM,YAAY,OAAO,QAAQ,UAAU,UAAU,UAAU,CAAC,CAAC;CAMjE,OAAO;EAAE,QALmC,OAAO,SAAS,mBAAmB,IAC3E,sBACA,YAAY,IACV,aACA;EACW;CAAU;AAC7B"}
|
|
@@ -12,12 +12,12 @@ import * as Surface from "@dxos/app-framework/Surface";
|
|
|
12
12
|
import * as AppSurface from "@dxos/app-toolkit/AppSurface";
|
|
13
13
|
import { isSpace } from "@dxos/react-client/echo";
|
|
14
14
|
import * as Position from "@dxos/util/Position";
|
|
15
|
+
import { useObject } from "@dxos/echo-react";
|
|
15
16
|
import * as Card from "@dxos/react-ui/Card";
|
|
16
17
|
import * as Hooks$1 from "@dxos/react-ui/Hooks";
|
|
17
18
|
import * as Layout from "@dxos/react-ui/Layout";
|
|
18
19
|
import * as Tag$1 from "@dxos/react-ui/Tag";
|
|
19
20
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
-
import { useObject } from "@dxos/echo-react";
|
|
21
21
|
import * as Hooks from "@dxos/app-framework/Hooks";
|
|
22
22
|
//#region src/cards/GitHubCard.tsx
|
|
23
23
|
var stateHue = {
|
|
@@ -32,8 +32,8 @@ var stateHue = {
|
|
|
32
32
|
*/
|
|
33
33
|
var GitHubCard = ({ subject }) => {
|
|
34
34
|
const { t } = Hooks$1.useTranslation(meta.profile.key);
|
|
35
|
-
const
|
|
36
|
-
const
|
|
35
|
+
const [object] = useObject(subject);
|
|
36
|
+
const { owner, name, repo, number, state, author, additions, deletions, defaultBranch, description, url } = object;
|
|
37
37
|
return /* @__PURE__ */ jsxs(Card.Body, { children: [
|
|
38
38
|
/* @__PURE__ */ jsx(Card.Row, {
|
|
39
39
|
icon: "ph--github-logo--regular",
|
|
@@ -46,7 +46,7 @@ var GitHubCard = ({ subject }) => {
|
|
|
46
46
|
}) : void 0,
|
|
47
47
|
children: /* @__PURE__ */ jsx(Card.Text, {
|
|
48
48
|
variant: "muted",
|
|
49
|
-
children: [`${owner}/${name}`, number].filter(Boolean).join("#")
|
|
49
|
+
children: [`${owner}/${name ?? repo}`, number].filter(Boolean).join("#")
|
|
50
50
|
})
|
|
51
51
|
}),
|
|
52
52
|
author && /* @__PURE__ */ jsx(Card.Row, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-react-surface.mjs","names":[],"sources":["../../src/cards/GitHubCard.tsx","../../src/hooks/useSyncPullRequest.ts","../../src/cards/PullRequestCard.tsx","../../src/containers/index.ts","../../src/capabilities/react-surface.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport type * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport * as Card from '@dxos/react-ui/Card';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport * as Layout from '@dxos/react-ui/Layout';\nimport * as Tag from '@dxos/react-ui/Tag';\nimport { type Issue, type PullRequest, type Repo } from '@dxos/types';\n\nimport { meta } from '#meta';\n\ntype Subject = Repo.Repo | Issue.Issue | PullRequest.PullRequest;\n\n/**\n * What the card reads off any of the three types: each field is present on some of them and\n * optional here, so one render path shows whatever the subject carries.\n */\ntype Fields = {\n owner: string;\n number?: number;\n state?: PullRequest.State;\n author?: string;\n additions?: number;\n deletions?: number;\n defaultBranch?: string;\n description?: string;\n url?: string;\n};\n\nconst stateHue: Record<PullRequest.State, Tag.TagHue> = {\n open: 'green',\n closed: 'red',\n merged: 'purple',\n draft: 'neutral',\n};\n\n/**\n * Card content for a repository, pull request or issue: reference, state or branch, author, diff size, description and\n * the link out. Each row leads with an icon in the card's start rail, so the text lines up with the title.\n */\nexport const GitHubCard = ({ subject }: AppSurface.ObjectCardProps<Subject>) => {\n const { t } = Hooks.useTranslation(meta.profile.key);\n const { owner, number, state, author, additions, deletions, defaultBranch, description, url }: Fields = subject;\n const name = 'name' in subject ? subject.name : subject.repo;\n\n return (\n <Card.Body>\n <Card.Row\n icon='ph--github-logo--regular'\n trailing={\n state ? (\n <Tag.Tag hue={stateHue[state]}>{state}</Tag.Tag>\n ) : defaultBranch ? (\n <Tag.Tag hue='neutral'>{defaultBranch}</Tag.Tag>\n ) : undefined\n }\n >\n <Card.Text variant='muted'>{[`${owner}/${name}`, number].filter(Boolean).join('#')}</Card.Text>\n </Card.Row>\n {author && (\n <Card.Row icon='ph--user--regular'>\n <Card.Text variant='muted'>{author}</Card.Text>\n </Card.Row>\n )}\n {(additions !== undefined || deletions !== undefined) && (\n <Card.Row icon='ph--plus-minus--regular'>\n <Layout.Flex gap='sm' align='center'>\n {additions !== undefined && <span className='text-green-500'>+{additions}</span>}\n {deletions !== undefined && <span className='text-red-500'>−{deletions}</span>}\n </Layout.Flex>\n </Card.Row>\n )}\n {description && (\n <Card.Row icon='ph--text-align-left--regular'>\n <Card.Text lines={3} variant='muted'>\n {description}\n </Card.Text>\n </Card.Row>\n )}\n {url && (\n <Card.Row icon='ph--arrow-square-out--regular'>\n <a className='dx-link-accent' href={url} target='_blank' rel='noopener noreferrer'>\n {t('open-on-github.label')}\n </a>\n </Card.Row>\n )}\n </Card.Body>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useEffect } from 'react';\n\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport { Obj, Ref } from '@dxos/echo';\nimport { log } from '@dxos/log';\nimport { type PullRequest } from '@dxos/types';\n\nimport { GitHubOperation } from '#types';\n\n/** How long a re-sync stands before the pull request is read from GitHub again. */\nconst SYNC_INTERVAL = 5 * 60_000;\n\n// Keyed by object id: a board of pull request cards would otherwise spend one GitHub request per\n// card each time it mounts, and an anonymous caller has only 60 an hour. Entries past the interval\n// are pruned on every write, so the map holds only pull requests synced within it.\nconst lastSynced = new Map<string, number>();\n\nconst markSynced = (id: string, now: number) => {\n for (const [key, syncedAt] of lastSynced) {\n if (now - syncedAt >= SYNC_INTERVAL) {\n lastSynced.delete(key);\n }\n }\n lastSynced.set(id, now);\n};\n\n/**\n * Refreshes a stored pull request from GitHub when it is shown, since whatever shows it is the moment\n * its fields are worth trusting: a repository sync may be days old, and an import is never re-synced.\n *\n * A pull request held by no database (a link preview) is skipped, as there is nothing to write back to,\n * and one synced within {@link SYNC_INTERVAL} is skipped too.\n */\nexport const useSyncPullRequest = (pullRequest: PullRequest.PullRequest): void => {\n const { invokePromise } = Hooks.useOperationInvoker();\n const spaceId = Obj.getDatabase(pullRequest)?.spaceId;\n useEffect(() => {\n const now = Date.now();\n if (!spaceId || now - (lastSynced.get(pullRequest.id) ?? 0) < SYNC_INTERVAL) {\n return;\n }\n markSynced(pullRequest.id, now);\n void invokePromise(GitHubOperation.SyncPullRequest, { pullRequest: Ref.make(pullRequest) }, { spaceId }).then(\n ({ error }) => error && log.warn('pull request sync failed', { error }),\n );\n }, [invokePromise, pullRequest, spaceId]);\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport type * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport { useObject } from '@dxos/echo-react';\nimport { type PullRequest } from '@dxos/types';\n\nimport { useSyncPullRequest } from '../hooks/index.ts';\nimport { GitHubCard } from './GitHubCard.tsx';\n\n/**\n * A pull request's card, re-synced from GitHub whenever it is shown: the card is often where a stale\n * pull request is first read, e.g. in a task list's popover.\n */\nexport const PullRequestCard = ({ role, subject }: AppSurface.ObjectCardProps<PullRequest.PullRequest>) => {\n // Subscribed so the fields the sync writes back re-render the card.\n useObject(subject);\n useSyncPullRequest(subject);\n return <GitHubCard role={role} subject={subject} />;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type ComponentType, lazy } from 'react';\n\nexport const ImportPullRequestDialog: ComponentType<any> = lazy(() => import('./ImportPullRequestDialog/index.ts'));\nexport const PullRequestCardMenu: ComponentType<any> = lazy(() => import('./PullRequestCardMenu/index.ts'));\nexport const PullRequestArticle: ComponentType<any> = lazy(() => import('./PullRequestArticle/index.ts'));\nexport const PullRequestsArticle: ComponentType<any> = lazy(() => import('./PullRequestsArticle/index.ts'));\nexport const WalkthroughArticle: ComponentType<any> = lazy(() => import('./WalkthroughArticle/index.ts'));\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as Surface from '@dxos/app-framework/Surface';\nimport * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport { Type } from '@dxos/echo';\nimport { isSpace } from '@dxos/react-client/echo';\nimport { Issue, PullRequest, Repo } from '@dxos/types';\nimport * as Position from '@dxos/util/Position';\n\nimport { IMPORT_PULL_REQUEST_DIALOG } from '#meta';\nimport { Walkthrough } from '#types';\n\nimport { GitHubCard, PullRequestCard } from '../cards/index.ts';\nimport {\n ImportPullRequestDialog,\n PullRequestArticle,\n PullRequestCardMenu,\n PullRequestsArticle,\n WalkthroughArticle,\n} from '../containers/index.ts';\n\nexport default Capability.makeModule(() =>\n Effect.succeed(\n Capability.contribute(Capabilities.ReactSurface, [\n Surface.create({\n id: 'repoCard',\n position: Position.first,\n filter: AppSurface.object(AppSurface.CardContent, Repo.Repo),\n component: GitHubCard,\n props: ({ role, data: { subject } }) => ({ role, subject }),\n }),\n Surface.create({\n id: 'issueCard',\n position: Position.first,\n filter: AppSurface.object(AppSurface.CardContent, Issue.Issue),\n component: GitHubCard,\n props: ({ role, data: { subject } }) => ({ role, subject }),\n }),\n Surface.create({\n id: 'pullRequestCard',\n position: Position.first,\n filter: AppSurface.object(AppSurface.CardContent, PullRequest.PullRequest),\n component: PullRequestCard,\n props: ({ role, data: { subject } }) => ({ role, subject }),\n }),\n Surface.create({\n id: 'pullRequestCardMenu',\n filter: AppSurface.object(AppSurface.CardMenu, PullRequest.PullRequest),\n component: PullRequestCardMenu,\n props: ({ data: { subject, menu } }) => ({ subject, menu }),\n }),\n // The pull request is the article's subject, and the walkthrough it may have is something the\n // article renders — so a pull request with no narration yet still opens, and offers to write one.\n Surface.create({\n id: 'pullRequestArticle',\n filter: AppSurface.object(AppSurface.Article, PullRequest.PullRequest),\n component: PullRequestArticle,\n props: ({ role, data }) => ({ role, ...data }),\n }),\n // The pull request type's node (the space's Database section) opens as the triage list rather\n // than the generic type collection, which knows nothing of checks, tasks or relevance.\n Surface.create({\n id: 'pullRequestsArticle',\n position: Position.first,\n filter: AppSurface.subject(AppSurface.Article, isPullRequestType),\n component: PullRequestsArticle,\n props: ({ role, data: { attendableId, properties } }) => ({\n role,\n attendableId,\n db: isSpace(properties?.space) ? properties.space.db : undefined,\n }),\n }),\n // A walkthrough opened by id (an older link, a search result) resolves to the same review.\n Surface.create({\n id: 'walkthroughArticle',\n filter: AppSurface.object(AppSurface.Article, Walkthrough.Walkthrough),\n component: WalkthroughArticle,\n props: ({ role, data }) => ({ role, ...data }),\n }),\n Surface.create({\n id: IMPORT_PULL_REQUEST_DIALOG,\n filter: AppSurface.component(AppSurface.Dialog, IMPORT_PULL_REQUEST_DIALOG),\n component: ImportPullRequestDialog,\n }),\n ]),\n ),\n);\n\nconst PULL_REQUEST_TYPENAME = Type.getTypename(PullRequest.PullRequest);\n\nconst isPullRequestType = (subject: unknown): subject is Type.AnyEntity =>\n Type.isType(subject) && Type.getTypename(subject) === PULL_REQUEST_TYPENAME;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chunk-react-surface.mjs","names":["Hooks","Tag"],"sources":["../../src/cards/GitHubCard.tsx","../../src/hooks/useSyncPullRequest.ts","../../src/cards/PullRequestCard.tsx","../../src/containers/index.ts","../../src/capabilities/react-surface.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport type * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport { useObject } from '@dxos/echo-react';\nimport * as Card from '@dxos/react-ui/Card';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport * as Layout from '@dxos/react-ui/Layout';\nimport * as Tag from '@dxos/react-ui/Tag';\nimport { type Issue, type PullRequest, type Repo } from '@dxos/types';\n\nimport { meta } from '#meta';\n\ntype Subject = Repo.Repo | Issue.Issue | PullRequest.PullRequest;\n\n/**\n * What the card reads off any of the three types: each field is present on some of them and\n * optional here, so one render path shows whatever the subject carries.\n */\ntype Fields = {\n owner: string;\n name?: string;\n repo?: string;\n number?: number;\n state?: PullRequest.State;\n author?: string;\n additions?: number;\n deletions?: number;\n defaultBranch?: string;\n description?: string;\n url?: string;\n};\n\nconst stateHue: Record<PullRequest.State, Tag.TagHue> = {\n open: 'green',\n closed: 'red',\n merged: 'purple',\n draft: 'neutral',\n};\n\n/**\n * Card content for a repository, pull request or issue: reference, state or branch, author, diff size, description and\n * the link out. Each row leads with an icon in the card's start rail, so the text lines up with the title.\n */\nexport const GitHubCard = ({ subject }: AppSurface.ObjectCardProps<Subject>) => {\n const { t } = Hooks.useTranslation(meta.profile.key);\n const [object] = useObject(subject);\n const { owner, name, repo, number, state, author, additions, deletions, defaultBranch, description, url }: Fields =\n object;\n\n return (\n <Card.Body>\n <Card.Row\n icon='ph--github-logo--regular'\n trailing={\n state ? (\n <Tag.Tag hue={stateHue[state]}>{state}</Tag.Tag>\n ) : defaultBranch ? (\n <Tag.Tag hue='neutral'>{defaultBranch}</Tag.Tag>\n ) : undefined\n }\n >\n <Card.Text variant='muted'>{[`${owner}/${name ?? repo}`, number].filter(Boolean).join('#')}</Card.Text>\n </Card.Row>\n {author && (\n <Card.Row icon='ph--user--regular'>\n <Card.Text variant='muted'>{author}</Card.Text>\n </Card.Row>\n )}\n {(additions !== undefined || deletions !== undefined) && (\n <Card.Row icon='ph--plus-minus--regular'>\n <Layout.Flex gap='sm' align='center'>\n {additions !== undefined && <span className='text-green-500'>+{additions}</span>}\n {deletions !== undefined && <span className='text-red-500'>−{deletions}</span>}\n </Layout.Flex>\n </Card.Row>\n )}\n {description && (\n <Card.Row icon='ph--text-align-left--regular'>\n <Card.Text lines={3} variant='muted'>\n {description}\n </Card.Text>\n </Card.Row>\n )}\n {url && (\n <Card.Row icon='ph--arrow-square-out--regular'>\n <a className='dx-link-accent' href={url} target='_blank' rel='noopener noreferrer'>\n {t('open-on-github.label')}\n </a>\n </Card.Row>\n )}\n </Card.Body>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useEffect } from 'react';\n\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport { Obj, Ref } from '@dxos/echo';\nimport { log } from '@dxos/log';\nimport { type PullRequest } from '@dxos/types';\n\nimport { GitHubOperation } from '#types';\n\n/** How long a re-sync stands before the pull request is read from GitHub again. */\nconst SYNC_INTERVAL = 5 * 60_000;\n\n// Keyed by object id: a board of pull request cards would otherwise spend one GitHub request per\n// card each time it mounts, and an anonymous caller has only 60 an hour. Entries past the interval\n// are pruned on every write, so the map holds only pull requests synced within it.\nconst lastSynced = new Map<string, number>();\n\nconst markSynced = (id: string, now: number) => {\n for (const [key, syncedAt] of lastSynced) {\n if (now - syncedAt >= SYNC_INTERVAL) {\n lastSynced.delete(key);\n }\n }\n lastSynced.set(id, now);\n};\n\n/**\n * Refreshes a stored pull request from GitHub when it is shown, since whatever shows it is the moment\n * its fields are worth trusting: a repository sync may be days old, and an import is never re-synced.\n *\n * A pull request held by no database (a link preview) is skipped, as there is nothing to write back to,\n * and one synced within {@link SYNC_INTERVAL} is skipped too.\n */\nexport const useSyncPullRequest = (pullRequest: PullRequest.PullRequest): void => {\n const { invokePromise } = Hooks.useOperationInvoker();\n const spaceId = Obj.getDatabase(pullRequest)?.spaceId;\n useEffect(() => {\n const now = Date.now();\n if (!spaceId || now - (lastSynced.get(pullRequest.id) ?? 0) < SYNC_INTERVAL) {\n return;\n }\n markSynced(pullRequest.id, now);\n void invokePromise(GitHubOperation.SyncPullRequest, { pullRequest: Ref.make(pullRequest) }, { spaceId }).then(\n ({ error }) => error && log.warn('pull request sync failed', { error }),\n );\n }, [invokePromise, pullRequest, spaceId]);\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport type * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport { useObject } from '@dxos/echo-react';\nimport { type PullRequest } from '@dxos/types';\n\nimport { useSyncPullRequest } from '../hooks/index.ts';\nimport { GitHubCard } from './GitHubCard.tsx';\n\n/**\n * A pull request's card, re-synced from GitHub whenever it is shown: the card is often where a stale\n * pull request is first read, e.g. in a task list's popover.\n */\nexport const PullRequestCard = ({ role, subject }: AppSurface.ObjectCardProps<PullRequest.PullRequest>) => {\n // Subscribed so the fields the sync writes back re-render the card.\n useObject(subject);\n useSyncPullRequest(subject);\n return <GitHubCard role={role} subject={subject} />;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type ComponentType, lazy } from 'react';\n\nexport const ImportPullRequestDialog: ComponentType<any> = lazy(() => import('./ImportPullRequestDialog/index.ts'));\nexport const PullRequestCardMenu: ComponentType<any> = lazy(() => import('./PullRequestCardMenu/index.ts'));\nexport const PullRequestArticle: ComponentType<any> = lazy(() => import('./PullRequestArticle/index.ts'));\nexport const PullRequestsArticle: ComponentType<any> = lazy(() => import('./PullRequestsArticle/index.ts'));\nexport const WalkthroughArticle: ComponentType<any> = lazy(() => import('./WalkthroughArticle/index.ts'));\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as Surface from '@dxos/app-framework/Surface';\nimport * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport { Type } from '@dxos/echo';\nimport { isSpace } from '@dxos/react-client/echo';\nimport { Issue, PullRequest, Repo } from '@dxos/types';\nimport * as Position from '@dxos/util/Position';\n\nimport { IMPORT_PULL_REQUEST_DIALOG } from '#meta';\nimport { Walkthrough } from '#types';\n\nimport { GitHubCard, PullRequestCard } from '../cards/index.ts';\nimport {\n ImportPullRequestDialog,\n PullRequestArticle,\n PullRequestCardMenu,\n PullRequestsArticle,\n WalkthroughArticle,\n} from '../containers/index.ts';\n\nexport default Capability.makeModule(() =>\n Effect.succeed(\n Capability.contribute(Capabilities.ReactSurface, [\n Surface.create({\n id: 'repoCard',\n position: Position.first,\n filter: AppSurface.object(AppSurface.CardContent, Repo.Repo),\n component: GitHubCard,\n props: ({ role, data: { subject } }) => ({ role, subject }),\n }),\n Surface.create({\n id: 'issueCard',\n position: Position.first,\n filter: AppSurface.object(AppSurface.CardContent, Issue.Issue),\n component: GitHubCard,\n props: ({ role, data: { subject } }) => ({ role, subject }),\n }),\n Surface.create({\n id: 'pullRequestCard',\n position: Position.first,\n filter: AppSurface.object(AppSurface.CardContent, PullRequest.PullRequest),\n component: PullRequestCard,\n props: ({ role, data: { subject } }) => ({ role, subject }),\n }),\n Surface.create({\n id: 'pullRequestCardMenu',\n filter: AppSurface.object(AppSurface.CardMenu, PullRequest.PullRequest),\n component: PullRequestCardMenu,\n props: ({ data: { subject, menu } }) => ({ subject, menu }),\n }),\n // The pull request is the article's subject, and the walkthrough it may have is something the\n // article renders — so a pull request with no narration yet still opens, and offers to write one.\n Surface.create({\n id: 'pullRequestArticle',\n filter: AppSurface.object(AppSurface.Article, PullRequest.PullRequest),\n component: PullRequestArticle,\n props: ({ role, data }) => ({ role, ...data }),\n }),\n // The pull request type's node (the space's Database section) opens as the triage list rather\n // than the generic type collection, which knows nothing of checks, tasks or relevance.\n Surface.create({\n id: 'pullRequestsArticle',\n position: Position.first,\n filter: AppSurface.subject(AppSurface.Article, isPullRequestType),\n component: PullRequestsArticle,\n props: ({ role, data: { attendableId, properties } }) => ({\n role,\n attendableId,\n db: isSpace(properties?.space) ? properties.space.db : undefined,\n }),\n }),\n // A walkthrough opened by id (an older link, a search result) resolves to the same review.\n Surface.create({\n id: 'walkthroughArticle',\n filter: AppSurface.object(AppSurface.Article, Walkthrough.Walkthrough),\n component: WalkthroughArticle,\n props: ({ role, data }) => ({ role, ...data }),\n }),\n Surface.create({\n id: IMPORT_PULL_REQUEST_DIALOG,\n filter: AppSurface.component(AppSurface.Dialog, IMPORT_PULL_REQUEST_DIALOG),\n component: ImportPullRequestDialog,\n }),\n ]),\n ),\n);\n\nconst PULL_REQUEST_TYPENAME = Type.getTypename(PullRequest.PullRequest);\n\nconst isPullRequestType = (subject: unknown): subject is Type.AnyEntity =>\n Type.isType(subject) && Type.getTypename(subject) === PULL_REQUEST_TYPENAME;\n"],"mappings":"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"}
|