adispatchd 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +195 -2
- package/dist/api/errors.d.ts +27 -0
- package/dist/api/errors.js +80 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.js +11 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/logs.d.ts +30 -0
- package/dist/api/logs.js +88 -0
- package/dist/api/logs.js.map +1 -0
- package/dist/api/serialize.d.ts +65 -0
- package/dist/api/serialize.js +135 -0
- package/dist/api/serialize.js.map +1 -0
- package/dist/api/server.d.ts +89 -0
- package/dist/api/server.js +751 -0
- package/dist/api/server.js.map +1 -0
- package/dist/api/sse.d.ts +90 -0
- package/dist/api/sse.js +225 -0
- package/dist/api/sse.js.map +1 -0
- package/dist/app.d.ts +173 -0
- package/dist/app.js +488 -0
- package/dist/app.js.map +1 -0
- package/dist/cli/config-validate.d.ts +6 -0
- package/dist/cli/config-validate.js +39 -0
- package/dist/cli/config-validate.js.map +1 -0
- package/dist/cli/control.d.ts +31 -0
- package/dist/cli/control.js +186 -0
- package/dist/cli/control.js.map +1 -0
- package/dist/cli/http-client.d.ts +57 -0
- package/dist/cli/http-client.js +174 -0
- package/dist/cli/http-client.js.map +1 -0
- package/dist/cli/index.d.ts +14 -0
- package/dist/cli/index.js +14 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-templates.d.ts +20 -0
- package/dist/cli/init-templates.js +275 -0
- package/dist/cli/init-templates.js.map +1 -0
- package/dist/cli/init.d.ts +16 -0
- package/dist/cli/init.js +107 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +25 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/program.d.ts +102 -0
- package/dist/cli/program.js +133 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/service.d.ts +27 -0
- package/dist/cli/service.js +252 -0
- package/dist/cli/service.js.map +1 -0
- package/dist/cli/start.d.ts +22 -0
- package/dist/cli/start.js +133 -0
- package/dist/cli/start.js.map +1 -0
- package/dist/cli/workflow-dry-run.d.ts +13 -0
- package/dist/cli/workflow-dry-run.js +144 -0
- package/dist/cli/workflow-dry-run.js.map +1 -0
- package/dist/config/field-catalog.d.ts +33 -0
- package/dist/config/field-catalog.js +172 -0
- package/dist/config/field-catalog.js.map +1 -0
- package/dist/config/filter-schema.d.ts +15 -0
- package/dist/config/filter-schema.js +110 -0
- package/dist/config/filter-schema.js.map +1 -0
- package/dist/config/index.d.ts +15 -0
- package/dist/config/index.js +16 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/issues.d.ts +27 -0
- package/dist/config/issues.js +37 -0
- package/dist/config/issues.js.map +1 -0
- package/dist/config/loader.d.ts +32 -0
- package/dist/config/loader.js +250 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/manager.d.ts +153 -0
- package/dist/config/manager.js +276 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/model.d.ts +334 -0
- package/dist/config/model.js +2 -0
- package/dist/config/model.js.map +1 -0
- package/dist/config/normalize.d.ts +20 -0
- package/dist/config/normalize.js +200 -0
- package/dist/config/normalize.js.map +1 -0
- package/dist/config/parameters.d.ts +37 -0
- package/dist/config/parameters.js +71 -0
- package/dist/config/parameters.js.map +1 -0
- package/dist/config/public.d.ts +6 -0
- package/dist/config/public.js +18 -0
- package/dist/config/public.js.map +1 -0
- package/dist/config/schemas.d.ts +538 -0
- package/dist/config/schemas.js +321 -0
- package/dist/config/schemas.js.map +1 -0
- package/dist/config/snapshot.d.ts +38 -0
- package/dist/config/snapshot.js +57 -0
- package/dist/config/snapshot.js.map +1 -0
- package/dist/config/validate.d.ts +33 -0
- package/dist/config/validate.js +346 -0
- package/dist/config/validate.js.map +1 -0
- package/dist/core/clock.d.ts +59 -0
- package/dist/core/clock.js +133 -0
- package/dist/core/clock.js.map +1 -0
- package/dist/core/duration.d.ts +19 -0
- package/dist/core/duration.js +93 -0
- package/dist/core/duration.js.map +1 -0
- package/dist/core/errors.d.ts +62 -0
- package/dist/core/errors.js +72 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/ids.d.ts +57 -0
- package/dist/core/ids.js +88 -0
- package/dist/core/ids.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.js +14 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +100 -0
- package/dist/core/logger.js +207 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/paths.d.ts +84 -0
- package/dist/core/paths.js +138 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/template.d.ts +136 -0
- package/dist/core/template.js +261 -0
- package/dist/core/template.js.map +1 -0
- package/dist/core/types.d.ts +544 -0
- package/dist/core/types.js +172 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/worker-protocol.d.ts +102 -0
- package/dist/core/worker-protocol.js +75 -0
- package/dist/core/worker-protocol.js.map +1 -0
- package/dist/executors/classify.d.ts +25 -0
- package/dist/executors/classify.js +54 -0
- package/dist/executors/classify.js.map +1 -0
- package/dist/executors/dispatcher.d.ts +35 -0
- package/dist/executors/dispatcher.js +68 -0
- package/dist/executors/dispatcher.js.map +1 -0
- package/dist/executors/env.d.ts +43 -0
- package/dist/executors/env.js +66 -0
- package/dist/executors/env.js.map +1 -0
- package/dist/executors/event-parser.d.ts +41 -0
- package/dist/executors/event-parser.js +106 -0
- package/dist/executors/event-parser.js.map +1 -0
- package/dist/executors/index.d.ts +12 -0
- package/dist/executors/index.js +13 -0
- package/dist/executors/index.js.map +1 -0
- package/dist/executors/log-capture.d.ts +57 -0
- package/dist/executors/log-capture.js +155 -0
- package/dist/executors/log-capture.js.map +1 -0
- package/dist/executors/process-identity.d.ts +124 -0
- package/dist/executors/process-identity.js +283 -0
- package/dist/executors/process-identity.js.map +1 -0
- package/dist/executors/shell-executor.d.ts +35 -0
- package/dist/executors/shell-executor.js +478 -0
- package/dist/executors/shell-executor.js.map +1 -0
- package/dist/executors/stream-redactor.d.ts +40 -0
- package/dist/executors/stream-redactor.js +89 -0
- package/dist/executors/stream-redactor.js.map +1 -0
- package/dist/executors/workspace.d.ts +10 -0
- package/dist/executors/workspace.js +47 -0
- package/dist/executors/workspace.js.map +1 -0
- package/dist/filters/evaluate.d.ts +77 -0
- package/dist/filters/evaluate.js +187 -0
- package/dist/filters/evaluate.js.map +1 -0
- package/dist/filters/fields.d.ts +35 -0
- package/dist/filters/fields.js +75 -0
- package/dist/filters/fields.js.map +1 -0
- package/dist/filters/index.d.ts +11 -0
- package/dist/filters/index.js +12 -0
- package/dist/filters/index.js.map +1 -0
- package/dist/filters/iso-date.d.ts +10 -0
- package/dist/filters/iso-date.js +42 -0
- package/dist/filters/iso-date.js.map +1 -0
- package/dist/filters/predicate.d.ts +24 -0
- package/dist/filters/predicate.js +178 -0
- package/dist/filters/predicate.js.map +1 -0
- package/dist/filters/priority.d.ts +51 -0
- package/dist/filters/priority.js +91 -0
- package/dist/filters/priority.js.map +1 -0
- package/dist/filters/pushdown.d.ts +12 -0
- package/dist/filters/pushdown.js +52 -0
- package/dist/filters/pushdown.js.map +1 -0
- package/dist/filters/shell-check.d.ts +110 -0
- package/dist/filters/shell-check.js +304 -0
- package/dist/filters/shell-check.js.map +1 -0
- package/dist/identities/github-app.d.ts +55 -0
- package/dist/identities/github-app.js +160 -0
- package/dist/identities/github-app.js.map +1 -0
- package/dist/identities/index.d.ts +6 -0
- package/dist/identities/index.js +7 -0
- package/dist/identities/index.js.map +1 -0
- package/dist/identities/jwt.d.ts +24 -0
- package/dist/identities/jwt.js +56 -0
- package/dist/identities/jwt.js.map +1 -0
- package/dist/lifecycle/context.d.ts +106 -0
- package/dist/lifecycle/context.js +170 -0
- package/dist/lifecycle/context.js.map +1 -0
- package/dist/lifecycle/engine.d.ts +185 -0
- package/dist/lifecycle/engine.js +551 -0
- package/dist/lifecycle/engine.js.map +1 -0
- package/dist/lifecycle/errors.d.ts +48 -0
- package/dist/lifecycle/errors.js +71 -0
- package/dist/lifecycle/errors.js.map +1 -0
- package/dist/lifecycle/index.d.ts +9 -0
- package/dist/lifecycle/index.js +9 -0
- package/dist/lifecycle/index.js.map +1 -0
- package/dist/lifecycle/performers.d.ts +66 -0
- package/dist/lifecycle/performers.js +179 -0
- package/dist/lifecycle/performers.js.map +1 -0
- package/dist/notifications/index.d.ts +6 -0
- package/dist/notifications/index.js +7 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/service.d.ts +115 -0
- package/dist/notifications/service.js +364 -0
- package/dist/notifications/service.js.map +1 -0
- package/dist/persistence/actions.d.ts +101 -0
- package/dist/persistence/actions.js +196 -0
- package/dist/persistence/actions.js.map +1 -0
- package/dist/persistence/blocks.d.ts +85 -0
- package/dist/persistence/blocks.js +140 -0
- package/dist/persistence/blocks.js.map +1 -0
- package/dist/persistence/cron-firings.d.ts +55 -0
- package/dist/persistence/cron-firings.js +70 -0
- package/dist/persistence/cron-firings.js.map +1 -0
- package/dist/persistence/database.d.ts +60 -0
- package/dist/persistence/database.js +124 -0
- package/dist/persistence/database.js.map +1 -0
- package/dist/persistence/errors.d.ts +39 -0
- package/dist/persistence/errors.js +67 -0
- package/dist/persistence/errors.js.map +1 -0
- package/dist/persistence/events.d.ts +72 -0
- package/dist/persistence/events.js +83 -0
- package/dist/persistence/events.js.map +1 -0
- package/dist/persistence/index.d.ts +18 -0
- package/dist/persistence/index.js +19 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/persistence/instance-lock.d.ts +26 -0
- package/dist/persistence/instance-lock.js +117 -0
- package/dist/persistence/instance-lock.js.map +1 -0
- package/dist/persistence/lock-keys.d.ts +16 -0
- package/dist/persistence/lock-keys.js +41 -0
- package/dist/persistence/lock-keys.js.map +1 -0
- package/dist/persistence/notifications.d.ts +113 -0
- package/dist/persistence/notifications.js +213 -0
- package/dist/persistence/notifications.js.map +1 -0
- package/dist/persistence/persistence.d.ts +46 -0
- package/dist/persistence/persistence.js +42 -0
- package/dist/persistence/persistence.js.map +1 -0
- package/dist/persistence/retention.d.ts +46 -0
- package/dist/persistence/retention.js +68 -0
- package/dist/persistence/retention.js.map +1 -0
- package/dist/persistence/runs.d.ts +215 -0
- package/dist/persistence/runs.js +417 -0
- package/dist/persistence/runs.js.map +1 -0
- package/dist/persistence/schema.d.ts +16 -0
- package/dist/persistence/schema.js +183 -0
- package/dist/persistence/schema.js.map +1 -0
- package/dist/persistence/sqlite.d.ts +49 -0
- package/dist/persistence/sqlite.js +131 -0
- package/dist/persistence/sqlite.js.map +1 -0
- package/dist/runs/controller.d.ts +307 -0
- package/dist/runs/controller.js +1078 -0
- package/dist/runs/controller.js.map +1 -0
- package/dist/runs/errors.d.ts +20 -0
- package/dist/runs/errors.js +26 -0
- package/dist/runs/errors.js.map +1 -0
- package/dist/runs/event-bus.d.ts +106 -0
- package/dist/runs/event-bus.js +105 -0
- package/dist/runs/event-bus.js.map +1 -0
- package/dist/runs/execution.d.ts +39 -0
- package/dist/runs/execution.js +146 -0
- package/dist/runs/execution.js.map +1 -0
- package/dist/runs/index.d.ts +12 -0
- package/dist/runs/index.js +13 -0
- package/dist/runs/index.js.map +1 -0
- package/dist/runs/retention.d.ts +64 -0
- package/dist/runs/retention.js +232 -0
- package/dist/runs/retention.js.map +1 -0
- package/dist/runs/workspace.d.ts +20 -0
- package/dist/runs/workspace.js +51 -0
- package/dist/runs/workspace.js.map +1 -0
- package/dist/scheduler/checks.d.ts +41 -0
- package/dist/scheduler/checks.js +111 -0
- package/dist/scheduler/checks.js.map +1 -0
- package/dist/scheduler/cron.d.ts +32 -0
- package/dist/scheduler/cron.js +83 -0
- package/dist/scheduler/cron.js.map +1 -0
- package/dist/scheduler/dry-run.d.ts +42 -0
- package/dist/scheduler/dry-run.js +167 -0
- package/dist/scheduler/dry-run.js.map +1 -0
- package/dist/scheduler/errors.d.ts +22 -0
- package/dist/scheduler/errors.js +22 -0
- package/dist/scheduler/errors.js.map +1 -0
- package/dist/scheduler/format.d.ts +3 -0
- package/dist/scheduler/format.js +73 -0
- package/dist/scheduler/format.js.map +1 -0
- package/dist/scheduler/index.d.ts +13 -0
- package/dist/scheduler/index.js +14 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/planner.d.ts +88 -0
- package/dist/scheduler/planner.js +255 -0
- package/dist/scheduler/planner.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +160 -0
- package/dist/scheduler/scheduler.js +680 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/dist/scheduler/state.d.ts +26 -0
- package/dist/scheduler/state.js +25 -0
- package/dist/scheduler/state.js.map +1 -0
- package/dist/scheduler/types.d.ts +197 -0
- package/dist/scheduler/types.js +3 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/service/index.d.ts +6 -0
- package/dist/service/index.js +7 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/install.d.ts +93 -0
- package/dist/service/install.js +250 -0
- package/dist/service/install.js.map +1 -0
- package/dist/service/unit.d.ts +50 -0
- package/dist/service/unit.js +171 -0
- package/dist/service/unit.js.map +1 -0
- package/dist/sources/github/adapter.d.ts +99 -0
- package/dist/sources/github/adapter.js +336 -0
- package/dist/sources/github/adapter.js.map +1 -0
- package/dist/sources/github/fields.d.ts +8 -0
- package/dist/sources/github/fields.js +72 -0
- package/dist/sources/github/fields.js.map +1 -0
- package/dist/sources/github/http.d.ts +100 -0
- package/dist/sources/github/http.js +288 -0
- package/dist/sources/github/http.js.map +1 -0
- package/dist/sources/github/index.d.ts +6 -0
- package/dist/sources/github/index.js +7 -0
- package/dist/sources/github/index.js.map +1 -0
- package/dist/sources/github/pushdown.d.ts +14 -0
- package/dist/sources/github/pushdown.js +47 -0
- package/dist/sources/github/pushdown.js.map +1 -0
- package/dist/sources/github/refs.d.ts +17 -0
- package/dist/sources/github/refs.js +61 -0
- package/dist/sources/github/refs.js.map +1 -0
- package/dist/sources/index.d.ts +6 -0
- package/dist/sources/index.js +7 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/ui/index.d.ts +12 -0
- package/dist/ui/index.js +28 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/public/app.css +239 -0
- package/dist/ui/public/favicon.svg +1 -0
- package/dist/ui/public/index.html +27 -0
- package/dist/ui/public/js/client/api.js +68 -0
- package/dist/ui/public/js/client/app.js +146 -0
- package/dist/ui/public/js/client/dom.js +34 -0
- package/dist/ui/public/js/client/page.js +9 -0
- package/dist/ui/public/js/client/pages/actions.js +35 -0
- package/dist/ui/public/js/client/pages/blocked.js +58 -0
- package/dist/ui/public/js/client/pages/config.js +126 -0
- package/dist/ui/public/js/client/pages/dashboard.js +175 -0
- package/dist/ui/public/js/client/pages/run.js +367 -0
- package/dist/ui/public/js/client/pages/runs.js +72 -0
- package/dist/ui/public/js/client/pages/views.js +80 -0
- package/dist/ui/public/js/client/pages/workflows.js +291 -0
- package/dist/ui/public/js/client/types.js +1 -0
- package/dist/ui/public/js/client/ui.js +152 -0
- package/dist/ui/public/js/shared/dom.js +77 -0
- package/dist/ui/public/js/shared/events.js +88 -0
- package/dist/ui/public/js/shared/format.js +213 -0
- package/dist/ui/public/js/shared/logs.js +136 -0
- package/dist/ui/public/js/shared/params.js +90 -0
- package/dist/ui/public/js/shared/route.js +36 -0
- package/dist/ui/public/js/shared/sort.js +70 -0
- package/dist/ui/public/js/shared/sse.js +193 -0
- package/dist/ui/public/js/shared/throttle.js +65 -0
- package/dist/views/index.d.ts +6 -0
- package/dist/views/index.js +7 -0
- package/dist/views/index.js.map +1 -0
- package/dist/views/service.d.ts +131 -0
- package/dist/views/service.js +264 -0
- package/dist/views/service.js.map +1 -0
- package/docs/api.md +239 -0
- package/docs/configuration-reference.md +1785 -0
- package/docs/cron-semantics.md +96 -0
- package/docs/manual-tests/github-fixture/config.yaml +30 -0
- package/docs/manual-tests/github-fixture/helpers.sh +93 -0
- package/docs/manual-tests/github-fixture/identities.yaml +18 -0
- package/docs/manual-tests/github-fixture/scripts/test-worker.sh +100 -0
- package/docs/manual-tests/github-fixture/sources.yaml +13 -0
- package/docs/manual-tests/github-fixture/views/dependencies.yaml +17 -0
- package/docs/manual-tests/github-fixture/views/needs-maintainer.yaml +17 -0
- package/docs/manual-tests/github-fixture/workflows/coder-test.yaml +76 -0
- package/docs/manual-tests/github-fixture/workflows/commenter-test.yaml +63 -0
- package/docs/manual-tests/github-fixture/workflows/reviewer-test.yaml +60 -0
- package/docs/manual-tests/github.md +1308 -0
- package/docs/manual-tests/process-supervision.md +64 -0
- package/docs/manual-tests/systemd.md +68 -0
- package/docs/operations.md +271 -0
- package/docs/worker-protocol.md +145 -0
- package/examples/config/config.yaml +35 -0
- package/examples/config/identities.yaml +18 -0
- package/examples/config/sources.yaml +13 -0
- package/examples/config/views/needs-maintainer.yaml +15 -0
- package/examples/config/workflows/coder-project-a.yaml +86 -0
- package/examples/config/workflows/deploy.yaml +15 -0
- package/examples/config/workflows/nightly-maintenance.yaml +13 -0
- package/package.json +75 -4
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal GitHub REST client on top of an injectable `fetch` (no Octokit).
|
|
3
|
+
*
|
|
4
|
+
* - Pins the REST API version ({@link GITHUB_API_VERSION}) and the
|
|
5
|
+
* `application/vnd.github+json` media type.
|
|
6
|
+
* - Maps HTTP failures to {@link SourceError} kinds (auth, forbidden,
|
|
7
|
+
* not_found, rate_limited, transient, invalid). Messages never contain the
|
|
8
|
+
* token or request headers (Spec §20.4).
|
|
9
|
+
* - Retries idempotent requests on transient errors and rate limits using the
|
|
10
|
+
* injected {@link Timers}; mutating requests are never retried blindly and are
|
|
11
|
+
* flagged `outcomeUnknown` when the request may have taken effect.
|
|
12
|
+
* - Follows `Link: <…>; rel="next"` pagination, but only within the API origin
|
|
13
|
+
* so the token is never sent to a foreign host.
|
|
14
|
+
*/
|
|
15
|
+
import { SourceError, noopLogger, sleep, systemTimers, } from '../../core/index.js';
|
|
16
|
+
/** Pinned GitHub REST API version (sent as `X-GitHub-Api-Version`). */
|
|
17
|
+
export const GITHUB_API_VERSION = '2026-03-10';
|
|
18
|
+
/** Default REST API base URL. */
|
|
19
|
+
export const GITHUB_API_BASE_URL = 'https://api.github.com';
|
|
20
|
+
/** Media type requested from the API. */
|
|
21
|
+
export const GITHUB_ACCEPT = 'application/vnd.github+json';
|
|
22
|
+
/** Default per-page size used for list endpoints. */
|
|
23
|
+
export const DEFAULT_PER_PAGE = 100;
|
|
24
|
+
/** GitHub REST client. One instance can be shared by adapters and credential providers. */
|
|
25
|
+
export class GitHubHttpClient {
|
|
26
|
+
baseUrl;
|
|
27
|
+
fetchImpl;
|
|
28
|
+
clock;
|
|
29
|
+
timers;
|
|
30
|
+
logger;
|
|
31
|
+
maxRetries;
|
|
32
|
+
maxRetryWaitMs;
|
|
33
|
+
retryBaseDelayMs;
|
|
34
|
+
requestTimeoutMs;
|
|
35
|
+
maxPages;
|
|
36
|
+
userAgent;
|
|
37
|
+
origin;
|
|
38
|
+
constructor(options) {
|
|
39
|
+
this.baseUrl = (options.baseUrl ?? GITHUB_API_BASE_URL).replace(/\/+$/, '');
|
|
40
|
+
this.origin = new URL(this.baseUrl).origin;
|
|
41
|
+
this.fetchImpl = options.fetch ?? ((input, init) => fetch(input, init));
|
|
42
|
+
this.clock = options.clock;
|
|
43
|
+
this.timers = options.timers ?? systemTimers;
|
|
44
|
+
this.logger = options.logger ?? noopLogger;
|
|
45
|
+
this.maxRetries = options.maxRetries ?? 2;
|
|
46
|
+
this.maxRetryWaitMs = options.maxRetryWaitMs ?? 60_000;
|
|
47
|
+
this.retryBaseDelayMs = options.retryBaseDelayMs ?? 1_000;
|
|
48
|
+
this.requestTimeoutMs = options.requestTimeoutMs ?? 30_000;
|
|
49
|
+
this.maxPages = options.maxPages ?? 50;
|
|
50
|
+
this.userAgent = options.userAgent ?? 'adispatchd';
|
|
51
|
+
}
|
|
52
|
+
/** Perform one request (with retries for idempotent calls) and parse the JSON body. */
|
|
53
|
+
async request(method, path, options = {}) {
|
|
54
|
+
const url = this.buildUrl(path, options.query);
|
|
55
|
+
return this.requestUrl(method, url, options);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* GET all pages of a list endpoint by following `Link: rel="next"`.
|
|
59
|
+
* `per_page` defaults to {@link DEFAULT_PER_PAGE}.
|
|
60
|
+
*/
|
|
61
|
+
async paginate(path, options = {}) {
|
|
62
|
+
const items = [];
|
|
63
|
+
let url = this.buildUrl(path, { per_page: DEFAULT_PER_PAGE, ...options.query });
|
|
64
|
+
let pages = 0;
|
|
65
|
+
while (url) {
|
|
66
|
+
if (pages >= this.maxPages) {
|
|
67
|
+
throw new SourceError('invalid', `Pagination limit of ${this.maxPages} pages exceeded for GET ${describePath(url)}`, {
|
|
68
|
+
retryable: false,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const res = await this.requestUrl('GET', url, options);
|
|
72
|
+
pages += 1;
|
|
73
|
+
if (!Array.isArray(res.data)) {
|
|
74
|
+
throw new SourceError('invalid', `Expected a JSON array from GET ${describePath(url)}`, { status: res.status });
|
|
75
|
+
}
|
|
76
|
+
items.push(...res.data);
|
|
77
|
+
url = this.nextPageUrl(res.headers.get('link'));
|
|
78
|
+
}
|
|
79
|
+
return items;
|
|
80
|
+
}
|
|
81
|
+
buildUrl(path, query) {
|
|
82
|
+
const url = new URL(`${this.baseUrl}${path.startsWith('/') ? path : `/${path}`}`);
|
|
83
|
+
for (const [key, value] of Object.entries(query ?? {})) {
|
|
84
|
+
if (value !== undefined)
|
|
85
|
+
url.searchParams.set(key, String(value));
|
|
86
|
+
}
|
|
87
|
+
return url;
|
|
88
|
+
}
|
|
89
|
+
nextPageUrl(link) {
|
|
90
|
+
const next = parseLinkHeader(link).next;
|
|
91
|
+
if (!next)
|
|
92
|
+
return null;
|
|
93
|
+
let url;
|
|
94
|
+
try {
|
|
95
|
+
url = new URL(next);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
if (url.origin !== this.origin) {
|
|
101
|
+
// Never forward the token to another host.
|
|
102
|
+
this.logger.warn('Ignoring pagination link to foreign origin', { origin: url.origin });
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
return url;
|
|
106
|
+
}
|
|
107
|
+
async requestUrl(method, url, options) {
|
|
108
|
+
const idempotent = options.idempotent ?? method === 'GET';
|
|
109
|
+
for (let attempt = 0;; attempt++) {
|
|
110
|
+
try {
|
|
111
|
+
return await this.once(method, url, options, idempotent);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
if (!(err instanceof SourceError) || options.signal?.aborted)
|
|
115
|
+
throw err;
|
|
116
|
+
const retryAllowed = err.kind === 'rate_limited' || (idempotent && err.kind === 'transient');
|
|
117
|
+
if (!retryAllowed || attempt >= this.maxRetries)
|
|
118
|
+
throw err;
|
|
119
|
+
const delay = err.kind === 'rate_limited'
|
|
120
|
+
? (err.retryAfterMs ?? this.retryBaseDelayMs)
|
|
121
|
+
: (err.retryAfterMs ?? this.retryBaseDelayMs * 2 ** attempt);
|
|
122
|
+
if (delay > this.maxRetryWaitMs)
|
|
123
|
+
throw err;
|
|
124
|
+
this.logger.warn('GitHub request failed, retrying', {
|
|
125
|
+
method,
|
|
126
|
+
path: describePath(url),
|
|
127
|
+
kind: err.kind,
|
|
128
|
+
status: err.status,
|
|
129
|
+
attempt: attempt + 1,
|
|
130
|
+
delayMs: delay,
|
|
131
|
+
});
|
|
132
|
+
await sleep(this.timers, delay, options.signal);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async once(method, url, options, idempotent) {
|
|
137
|
+
const headers = {
|
|
138
|
+
Accept: GITHUB_ACCEPT,
|
|
139
|
+
'X-GitHub-Api-Version': GITHUB_API_VERSION,
|
|
140
|
+
'User-Agent': this.userAgent,
|
|
141
|
+
};
|
|
142
|
+
if (options.token)
|
|
143
|
+
headers.Authorization = `Bearer ${options.token}`;
|
|
144
|
+
let body;
|
|
145
|
+
if (options.body !== undefined) {
|
|
146
|
+
headers['Content-Type'] = 'application/json';
|
|
147
|
+
body = JSON.stringify(options.body);
|
|
148
|
+
}
|
|
149
|
+
const signals = [];
|
|
150
|
+
if (options.signal)
|
|
151
|
+
signals.push(options.signal);
|
|
152
|
+
if (this.requestTimeoutMs > 0)
|
|
153
|
+
signals.push(AbortSignal.timeout(this.requestTimeoutMs));
|
|
154
|
+
const signal = signals.length === 0 ? undefined : signals.length === 1 ? signals[0] : AbortSignal.any(signals);
|
|
155
|
+
const label = `${method} ${describePath(url)}`;
|
|
156
|
+
let res;
|
|
157
|
+
try {
|
|
158
|
+
res = await this.fetchImpl(url.toString(), { method, headers, ...(body !== undefined ? { body } : {}), ...(signal ? { signal } : {}) });
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
if (options.signal?.aborted)
|
|
162
|
+
throw options.signal.reason ?? err;
|
|
163
|
+
const timedOut = err instanceof Error && (err.name === 'TimeoutError' || err.name === 'AbortError');
|
|
164
|
+
// Never include the raw error: some fetch implementations echo request details.
|
|
165
|
+
throw new SourceError('transient', `${label} failed: ${timedOut ? 'request timed out' : 'network error'}`, {
|
|
166
|
+
outcomeUnknown: !idempotent,
|
|
167
|
+
details: { method, path: describePath(url) },
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
const text = await safeText(res);
|
|
171
|
+
if (res.ok) {
|
|
172
|
+
let data = null;
|
|
173
|
+
if (text.length > 0) {
|
|
174
|
+
try {
|
|
175
|
+
data = JSON.parse(text);
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// For a mutating request the change may have been applied although the body is unusable.
|
|
179
|
+
throw idempotent
|
|
180
|
+
? new SourceError('invalid', `${label} returned invalid JSON`, { status: res.status, retryable: false })
|
|
181
|
+
: new SourceError('transient', `${label} returned invalid JSON; outcome unknown`, {
|
|
182
|
+
status: res.status,
|
|
183
|
+
outcomeUnknown: true,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return { status: res.status, data: data, headers: res.headers };
|
|
188
|
+
}
|
|
189
|
+
throw this.toError(res, text, label, idempotent);
|
|
190
|
+
}
|
|
191
|
+
toError(res, text, label, idempotent) {
|
|
192
|
+
const status = res.status;
|
|
193
|
+
const apiMessage = extractMessage(text);
|
|
194
|
+
const message = `${label} failed with HTTP ${status}${apiMessage ? `: ${apiMessage}` : ''}`;
|
|
195
|
+
const details = { status, path: label.slice(label.indexOf(' ') + 1) };
|
|
196
|
+
const retryAfterMs = this.retryAfter(res.headers);
|
|
197
|
+
const rateLimited = status === 429 ||
|
|
198
|
+
(status === 403 &&
|
|
199
|
+
(res.headers.get('x-ratelimit-remaining') === '0' ||
|
|
200
|
+
res.headers.has('retry-after') ||
|
|
201
|
+
/rate limit/i.test(apiMessage ?? '')));
|
|
202
|
+
if (rateLimited) {
|
|
203
|
+
return new SourceError('rate_limited', message, {
|
|
204
|
+
status,
|
|
205
|
+
details,
|
|
206
|
+
retryAfterMs: retryAfterMs ?? 60_000,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
if (status === 401)
|
|
210
|
+
return new SourceError('auth', message, { status, details });
|
|
211
|
+
if (status === 403)
|
|
212
|
+
return new SourceError('forbidden', message, { status, details });
|
|
213
|
+
if (status === 404 || status === 410)
|
|
214
|
+
return new SourceError('not_found', message, { status, details });
|
|
215
|
+
if (status >= 500) {
|
|
216
|
+
return new SourceError('transient', message, {
|
|
217
|
+
status,
|
|
218
|
+
details,
|
|
219
|
+
outcomeUnknown: !idempotent,
|
|
220
|
+
...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
return new SourceError('invalid', message, { status, details });
|
|
224
|
+
}
|
|
225
|
+
/** Wait time from `Retry-After` (seconds) or `X-RateLimit-Reset` (epoch seconds). */
|
|
226
|
+
retryAfter(headers) {
|
|
227
|
+
const retryAfter = headers.get('retry-after');
|
|
228
|
+
if (retryAfter !== null) {
|
|
229
|
+
const seconds = Number(retryAfter);
|
|
230
|
+
if (Number.isFinite(seconds) && seconds >= 0)
|
|
231
|
+
return Math.ceil(seconds * 1000);
|
|
232
|
+
}
|
|
233
|
+
const reset = headers.get('x-ratelimit-reset');
|
|
234
|
+
if (reset !== null && headers.get('x-ratelimit-remaining') === '0') {
|
|
235
|
+
const resetMs = Number(reset) * 1000;
|
|
236
|
+
if (Number.isFinite(resetMs))
|
|
237
|
+
return Math.max(0, resetMs - this.clock.now().getTime()) + 1_000;
|
|
238
|
+
}
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/** Parse an RFC 8288 `Link` header into `{ rel: url }`. */
|
|
243
|
+
export function parseLinkHeader(header) {
|
|
244
|
+
const out = {};
|
|
245
|
+
if (!header)
|
|
246
|
+
return out;
|
|
247
|
+
for (const part of header.split(',')) {
|
|
248
|
+
const match = /<([^>]*)>\s*;(.*)/.exec(part.trim());
|
|
249
|
+
if (!match)
|
|
250
|
+
continue;
|
|
251
|
+
const [, url, params] = match;
|
|
252
|
+
const rel = /rel="?([^";]+)"?/.exec(params ?? '');
|
|
253
|
+
if (url !== undefined && rel?.[1]) {
|
|
254
|
+
for (const name of rel[1].trim().split(/\s+/))
|
|
255
|
+
out[name] = url;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return out;
|
|
259
|
+
}
|
|
260
|
+
/** Path (without query string) for messages; query strings could contain user data only, but stay short. */
|
|
261
|
+
function describePath(url) {
|
|
262
|
+
return url.pathname;
|
|
263
|
+
}
|
|
264
|
+
async function safeText(res) {
|
|
265
|
+
try {
|
|
266
|
+
return await res.text();
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return '';
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function extractMessage(text) {
|
|
273
|
+
if (!text)
|
|
274
|
+
return undefined;
|
|
275
|
+
try {
|
|
276
|
+
const parsed = JSON.parse(text);
|
|
277
|
+
if (typeof parsed.message === 'string')
|
|
278
|
+
return truncate(parsed.message, 200);
|
|
279
|
+
}
|
|
280
|
+
catch {
|
|
281
|
+
// non-JSON error body: do not echo arbitrary content
|
|
282
|
+
}
|
|
283
|
+
return undefined;
|
|
284
|
+
}
|
|
285
|
+
function truncate(text, max) {
|
|
286
|
+
return text.length > max ? `${text.slice(0, max)}…` : text;
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/sources/github/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sources/github/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conservative filter pushdown into `GET /repos/{o}/{r}/issues` query
|
|
3
|
+
* parameters. Only top-level conjunctions are considered; everything else is
|
|
4
|
+
* evaluated locally by the caller (the result may be a superset).
|
|
5
|
+
*/
|
|
6
|
+
import { type FilterNode } from '../../core/index.js';
|
|
7
|
+
/** Query parameters derived from a filter. */
|
|
8
|
+
export interface IssueListQuery {
|
|
9
|
+
state: 'open' | 'closed' | 'all';
|
|
10
|
+
/** Labels that must all be present (GitHub `labels=a,b` is a conjunction). */
|
|
11
|
+
labels: string[];
|
|
12
|
+
}
|
|
13
|
+
/** Derive list query parameters from `filter`; default `state=open`. */
|
|
14
|
+
export declare function pushdownQuery(filter: FilterNode | undefined): IssueListQuery;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conservative filter pushdown into `GET /repos/{o}/{r}/issues` query
|
|
3
|
+
* parameters. Only top-level conjunctions are considered; everything else is
|
|
4
|
+
* evaluated locally by the caller (the result may be a superset).
|
|
5
|
+
*/
|
|
6
|
+
import { isFilterAll, isFilterPredicate } from '../../core/index.js';
|
|
7
|
+
/** Derive list query parameters from `filter`; default `state=open`. */
|
|
8
|
+
export function pushdownQuery(filter) {
|
|
9
|
+
const query = { state: 'open', labels: [] };
|
|
10
|
+
if (!filter)
|
|
11
|
+
return query;
|
|
12
|
+
const conjuncts = isFilterPredicate(filter)
|
|
13
|
+
? [filter]
|
|
14
|
+
: isFilterAll(filter)
|
|
15
|
+
? filter.all.filter(isFilterPredicate)
|
|
16
|
+
: [];
|
|
17
|
+
for (const p of conjuncts) {
|
|
18
|
+
if (p.field === 'labels' && p.operator === 'contains' && typeof p.value === 'string') {
|
|
19
|
+
// Commas cannot be expressed in the comma-separated `labels` parameter.
|
|
20
|
+
if (p.value !== '' && !p.value.includes(',') && !query.labels.includes(p.value))
|
|
21
|
+
query.labels.push(p.value);
|
|
22
|
+
}
|
|
23
|
+
else if (p.field === 'state') {
|
|
24
|
+
const states = stateSet(p);
|
|
25
|
+
if (states)
|
|
26
|
+
query.state = states;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return query;
|
|
30
|
+
}
|
|
31
|
+
function stateSet(p) {
|
|
32
|
+
if (p.operator === 'equals' && (p.value === 'open' || p.value === 'closed'))
|
|
33
|
+
return p.value;
|
|
34
|
+
if (p.operator === 'in' && Array.isArray(p.value)) {
|
|
35
|
+
const values = new Set(p.value);
|
|
36
|
+
const open = values.has('open');
|
|
37
|
+
const closed = values.has('closed');
|
|
38
|
+
if (open && closed)
|
|
39
|
+
return 'all';
|
|
40
|
+
if (open)
|
|
41
|
+
return 'open';
|
|
42
|
+
if (closed)
|
|
43
|
+
return 'closed';
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=pushdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pushdown.js","sourceRoot":"","sources":["../../../src/sources/github/pushdown.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAyC,MAAM,qBAAqB,CAAC;AAS5G,wEAAwE;AACxE,MAAM,UAAU,aAAa,CAAC,MAA8B;IAC1D,MAAM,KAAK,GAAmB,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC5D,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,MAAM,SAAS,GAAsB,iBAAiB,CAAC,MAAM,CAAC;QAC5D,CAAC,CAAC,CAAC,MAAM,CAAC;QACV,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC;YACnB,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC;YACtC,CAAC,CAAC,EAAE,CAAC;IACT,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,IAAI,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,KAAK,UAAU,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YACrF,wEAAwE;YACxE,IAAI,CAAC,CAAC,KAAK,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;gBAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC9G,CAAC;aAAM,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC3B,IAAI,MAAM;gBAAE,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC;QACnC,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,CAAkB;IAClC,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,IAAI,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC;QAAE,OAAO,CAAC,CAAC,KAAK,CAAC;IAC5F,IAAI,CAAC,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,IAAI,IAAI,MAAM;YAAE,OAAO,KAAK,CAAC;QACjC,IAAI,IAAI;YAAE,OAAO,MAAM,CAAC;QACxB,IAAI,MAAM;YAAE,OAAO,QAAQ,CAAC;IAC9B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsing of user-supplied item references for a GitHub source.
|
|
3
|
+
*/
|
|
4
|
+
/** Pattern of a valid GitHub item ID (issue/PR number as decimal string). */
|
|
5
|
+
export declare const ITEM_ID_PATTERN: RegExp;
|
|
6
|
+
/**
|
|
7
|
+
* Parse `ref` into an item ID (issue/PR number) of the repository
|
|
8
|
+
* `owner/repo`, or `null`. Accepted forms:
|
|
9
|
+
* - `123`, `#123`
|
|
10
|
+
* - `owner/repo#123`
|
|
11
|
+
* - `https://github.com/owner/repo/issues/123` and `/pull/123`
|
|
12
|
+
* (optional trailing path such as `/files`, query and fragment)
|
|
13
|
+
*
|
|
14
|
+
* Owner and repository are compared case-insensitively (GitHub semantics);
|
|
15
|
+
* references to other repositories yield `null`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseGitHubItemRef(ref: string, owner: string, repo: string, webBaseUrl?: string): string | null;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsing of user-supplied item references for a GitHub source.
|
|
3
|
+
*/
|
|
4
|
+
/** Pattern of a valid GitHub item ID (issue/PR number as decimal string). */
|
|
5
|
+
export const ITEM_ID_PATTERN = /^[1-9]\d{0,9}$/;
|
|
6
|
+
/**
|
|
7
|
+
* Parse `ref` into an item ID (issue/PR number) of the repository
|
|
8
|
+
* `owner/repo`, or `null`. Accepted forms:
|
|
9
|
+
* - `123`, `#123`
|
|
10
|
+
* - `owner/repo#123`
|
|
11
|
+
* - `https://github.com/owner/repo/issues/123` and `/pull/123`
|
|
12
|
+
* (optional trailing path such as `/files`, query and fragment)
|
|
13
|
+
*
|
|
14
|
+
* Owner and repository are compared case-insensitively (GitHub semantics);
|
|
15
|
+
* references to other repositories yield `null`.
|
|
16
|
+
*/
|
|
17
|
+
export function parseGitHubItemRef(ref, owner, repo, webBaseUrl = 'https://github.com') {
|
|
18
|
+
const text = ref.trim();
|
|
19
|
+
const bare = /^#?(\d+)$/.exec(text);
|
|
20
|
+
if (bare)
|
|
21
|
+
return normalizeNumber(bare[1]);
|
|
22
|
+
const short = /^([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+)#(\d+)$/.exec(text);
|
|
23
|
+
if (short)
|
|
24
|
+
return sameRepo(short[1], short[2], owner, repo) ? normalizeNumber(short[3]) : null;
|
|
25
|
+
let url;
|
|
26
|
+
try {
|
|
27
|
+
url = new URL(text);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const base = new URL(webBaseUrl);
|
|
33
|
+
if (url.protocol !== 'https:' && url.protocol !== 'http:')
|
|
34
|
+
return null;
|
|
35
|
+
if (url.host.toLowerCase() !== base.host.toLowerCase())
|
|
36
|
+
return null;
|
|
37
|
+
const basePath = base.pathname.replace(/\/+$/, '');
|
|
38
|
+
if (!url.pathname.startsWith(`${basePath}/`))
|
|
39
|
+
return null;
|
|
40
|
+
const segments = url.pathname.slice(basePath.length + 1).split('/');
|
|
41
|
+
const [o, r, kind, number] = segments;
|
|
42
|
+
if (o === undefined || r === undefined || number === undefined)
|
|
43
|
+
return null;
|
|
44
|
+
if (kind !== 'issues' && kind !== 'pull' && kind !== 'pulls')
|
|
45
|
+
return null;
|
|
46
|
+
if (!sameRepo(o, r, owner, repo))
|
|
47
|
+
return null;
|
|
48
|
+
if (!/^\d+$/.test(number))
|
|
49
|
+
return null;
|
|
50
|
+
return normalizeNumber(number);
|
|
51
|
+
}
|
|
52
|
+
function sameRepo(o, r, owner, repo) {
|
|
53
|
+
return o?.toLowerCase() === owner.toLowerCase() && r?.toLowerCase() === repo.toLowerCase();
|
|
54
|
+
}
|
|
55
|
+
function normalizeNumber(digits) {
|
|
56
|
+
if (digits === undefined)
|
|
57
|
+
return null;
|
|
58
|
+
const normalized = digits.replace(/^0+/, '');
|
|
59
|
+
return ITEM_ID_PATTERN.test(normalized) ? normalized : null;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=refs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refs.js","sourceRoot":"","sources":["../../../src/sources/github/refs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sources/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Entry module of the built UI, relative to the UI directory. */
|
|
2
|
+
export declare const UI_ENTRY = "js/client/app.js";
|
|
3
|
+
/** True if `dir` contains a complete built UI (index.html + compiled entry). */
|
|
4
|
+
export declare function isUiDir(dir: string): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Locate the built web UI:
|
|
7
|
+
* 1. `<this module>/public` – `dist/ui/public` when running from `dist/`;
|
|
8
|
+
* 2. `<repo>/dist/ui/public` – when running from sources (`tsx src/cli/main.ts`)
|
|
9
|
+
* after `npm run build` / `npm run build:ui`.
|
|
10
|
+
* Returns `null` if no built UI exists (the API then runs without UI).
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveUiDir(moduleUrl?: string): string | null;
|
package/dist/ui/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component `ui` – public API (WI-11). The browser code lives in
|
|
3
|
+
* `src/ui/client` + `src/ui/shared` and is compiled by `tsconfig.ui.json`;
|
|
4
|
+
* `npm run build` writes the complete static UI to `dist/ui/public`.
|
|
5
|
+
* Other components import from this module only.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
/** Entry module of the built UI, relative to the UI directory. */
|
|
11
|
+
export const UI_ENTRY = 'js/client/app.js';
|
|
12
|
+
/** True if `dir` contains a complete built UI (index.html + compiled entry). */
|
|
13
|
+
export function isUiDir(dir) {
|
|
14
|
+
return existsSync(path.join(dir, 'index.html')) && existsSync(path.join(dir, UI_ENTRY));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Locate the built web UI:
|
|
18
|
+
* 1. `<this module>/public` – `dist/ui/public` when running from `dist/`;
|
|
19
|
+
* 2. `<repo>/dist/ui/public` – when running from sources (`tsx src/cli/main.ts`)
|
|
20
|
+
* after `npm run build` / `npm run build:ui`.
|
|
21
|
+
* Returns `null` if no built UI exists (the API then runs without UI).
|
|
22
|
+
*/
|
|
23
|
+
export function resolveUiDir(moduleUrl = import.meta.url) {
|
|
24
|
+
const here = path.dirname(fileURLToPath(moduleUrl));
|
|
25
|
+
const candidates = [path.join(here, 'public'), path.resolve(here, '..', '..', 'dist', 'ui', 'public')];
|
|
26
|
+
return candidates.find(isUiDir) ?? null;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,kEAAkE;AAClE,MAAM,CAAC,MAAM,QAAQ,GAAG,kBAAkB,CAAC;AAE3C,gFAAgF;AAChF,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC1F,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,SAAS,GAAW,OAAO,IAAI,CAAC,GAAG;IAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;IACpD,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IACvG,OAAO,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;AAC1C,CAAC"}
|