@volter/twin-github 0.1.2 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -36
- package/client/github-mirror.css +277 -319
- package/client/github-mirror.d.ts +418 -0
- package/client/github-mirror.js +485 -0
- package/client/github-mirror.tsx +153 -357
- package/client/pulls-rest.ts +159 -0
- package/client/pulls-workspace.tsx +841 -0
- package/dist/client/github-mirror.bundle.js +239 -0
- package/dist/client/github-mirror.css +916 -0
- package/dist/client/github-mirror.d.ts +418 -0
- package/dist/client/github-mirror.js +485 -0
- package/dist/client/github-mirror.tsx +1315 -0
- package/dist/client/pulls-rest.d.ts +42 -0
- package/dist/client/pulls-rest.js +140 -0
- package/dist/client/pulls-rest.ts +159 -0
- package/dist/client/pulls-workspace.bundle.js +22 -0
- package/dist/client/pulls-workspace.d.ts +114 -0
- package/dist/client/pulls-workspace.js +418 -0
- package/dist/client/pulls-workspace.tsx +841 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +40 -0
- package/dist/src/generated/graphql-sdl.gen.json +1 -0
- package/dist/src/generated/graphql.gen.json +1 -0
- package/dist/src/generated/surface.gen.json +1 -0
- package/dist/src/generated/ui.gen.json +1 -0
- package/dist/src/github-budget.d.ts +69 -0
- package/dist/src/github-budget.js +172 -0
- package/dist/src/github-capabilities.d.ts +5 -0
- package/dist/src/github-capabilities.js +4468 -0
- package/dist/src/github-conformance.d.ts +43 -0
- package/dist/src/github-conformance.js +76 -0
- package/dist/src/github-connector.d.ts +307 -0
- package/dist/src/github-connector.js +1398 -0
- package/dist/src/github-events.d.ts +41 -0
- package/dist/src/github-events.js +232 -0
- package/dist/src/github-git-http.d.ts +49 -0
- package/dist/src/github-git-http.js +185 -0
- package/dist/src/github-git-plane.d.ts +114 -0
- package/dist/src/github-git-plane.js +407 -0
- package/dist/src/github-mirror-state.d.ts +2 -0
- package/dist/src/github-mirror-state.js +335 -0
- package/dist/src/github-mirror-ui.d.ts +20 -0
- package/dist/src/github-mirror-ui.js +101 -0
- package/dist/src/github-server.d.ts +14 -0
- package/dist/src/github-server.js +240 -0
- package/dist/src/github-shared.d.ts +12 -0
- package/dist/src/github-shared.js +21 -0
- package/dist/src/github-twin.d.ts +1411 -0
- package/dist/src/github-twin.js +4084 -0
- package/dist/src/github-ui-conformance.d.ts +4 -0
- package/dist/src/github-ui-conformance.js +105 -0
- package/dist/src/github-ui-structure.d.ts +18 -0
- package/dist/src/github-ui-structure.js +251 -0
- package/dist/src/graphql-wire.d.ts +22 -0
- package/dist/src/graphql-wire.js +89 -0
- package/dist/src/index.d.ts +17 -0
- package/dist/src/index.js +104 -0
- package/dist/src/manifest.d.ts +8 -0
- package/dist/src/manifest.js +597 -0
- package/dist/src/npm-registry.d.ts +7 -0
- package/dist/src/npm-registry.js +47 -0
- package/dist/src/screens/app-installation.d.ts +3 -0
- package/dist/src/screens/app-installation.js +166 -0
- package/dist/src/screens/app-manifest.d.ts +3 -0
- package/dist/src/screens/app-manifest.js +81 -0
- package/dist/src/screens/oauth.d.ts +15 -0
- package/dist/src/screens/oauth.js +257 -0
- package/dist/src/screens/session.d.ts +8 -0
- package/dist/src/screens/session.js +170 -0
- package/dist/src/semantics/actions.d.ts +2 -0
- package/dist/src/semantics/actions.js +413 -0
- package/dist/src/semantics/activity.d.ts +4 -0
- package/dist/src/semantics/activity.js +161 -0
- package/dist/src/semantics/apps.d.ts +2 -0
- package/dist/src/semantics/apps.js +144 -0
- package/dist/src/semantics/branches.d.ts +2 -0
- package/dist/src/semantics/branches.js +136 -0
- package/dist/src/semantics/checks.d.ts +2 -0
- package/dist/src/semantics/checks.js +176 -0
- package/dist/src/semantics/code-scanning-upload.d.ts +2 -0
- package/dist/src/semantics/code-scanning-upload.js +97 -0
- package/dist/src/semantics/codespaces.d.ts +2 -0
- package/dist/src/semantics/codespaces.js +58 -0
- package/dist/src/semantics/commits.d.ts +2 -0
- package/dist/src/semantics/commits.js +109 -0
- package/dist/src/semantics/contents.d.ts +2 -0
- package/dist/src/semantics/contents.js +131 -0
- package/dist/src/semantics/deployments.d.ts +2 -0
- package/dist/src/semantics/deployments.js +127 -0
- package/dist/src/semantics/gists.d.ts +2 -0
- package/dist/src/semantics/gists.js +86 -0
- package/dist/src/semantics/git.d.ts +2 -0
- package/dist/src/semantics/git.js +235 -0
- package/dist/src/semantics/graphql.d.ts +7 -0
- package/dist/src/semantics/graphql.js +512 -0
- package/dist/src/semantics/index.d.ts +5 -0
- package/dist/src/semantics/index.js +62 -0
- package/dist/src/semantics/issues.d.ts +2 -0
- package/dist/src/semantics/issues.js +456 -0
- package/dist/src/semantics/keys.d.ts +2 -0
- package/dist/src/semantics/keys.js +66 -0
- package/dist/src/semantics/labels.d.ts +2 -0
- package/dist/src/semantics/labels.js +100 -0
- package/dist/src/semantics/meta.d.ts +12 -0
- package/dist/src/semantics/meta.js +144 -0
- package/dist/src/semantics/notifications.d.ts +4 -0
- package/dist/src/semantics/notifications.js +62 -0
- package/dist/src/semantics/orgs.d.ts +2 -0
- package/dist/src/semantics/orgs.js +420 -0
- package/dist/src/semantics/packages.d.ts +2 -0
- package/dist/src/semantics/packages.js +55 -0
- package/dist/src/semantics/pages.d.ts +2 -0
- package/dist/src/semantics/pages.js +176 -0
- package/dist/src/semantics/projects.d.ts +2 -0
- package/dist/src/semantics/projects.js +239 -0
- package/dist/src/semantics/pulls.d.ts +2 -0
- package/dist/src/semantics/pulls.js +462 -0
- package/dist/src/semantics/push-reactions.d.ts +101 -0
- package/dist/src/semantics/push-reactions.js +513 -0
- package/dist/src/semantics/releases.d.ts +19 -0
- package/dist/src/semantics/releases.js +231 -0
- package/dist/src/semantics/repo-invitations.d.ts +2 -0
- package/dist/src/semantics/repo-invitations.js +98 -0
- package/dist/src/semantics/repos.d.ts +17 -0
- package/dist/src/semantics/repos.js +390 -0
- package/dist/src/semantics/rulesets.d.ts +2 -0
- package/dist/src/semantics/rulesets.js +111 -0
- package/dist/src/semantics/search.d.ts +2 -0
- package/dist/src/semantics/search.js +84 -0
- package/dist/src/semantics/security.d.ts +2 -0
- package/dist/src/semantics/security.js +177 -0
- package/dist/src/semantics/shared.d.ts +61 -0
- package/dist/src/semantics/shared.js +151 -0
- package/dist/src/semantics/users.d.ts +2 -0
- package/dist/src/semantics/users.js +255 -0
- package/dist/src/semantics/webhooks.d.ts +2 -0
- package/dist/src/semantics/webhooks.js +107 -0
- package/dist/test-fixtures/github-a11y-reference.pr-list.SOURCE.md +56 -0
- package/dist/test-fixtures/github-a11y-reference.pr-list.json +1447 -0
- package/dist/test-fixtures/github-comment-schema.SOURCE.md +11 -0
- package/dist/test-fixtures/github-comment-schema.json +702 -0
- package/dist/test-fixtures/github-known-deviations.json +94 -0
- package/dist/test-fixtures/github-openapi-operations.SOURCE.md +76 -0
- package/dist/test-fixtures/github-openapi-operations.json +362 -0
- package/dist/test-fixtures/github-pull-schema.SOURCE.md +37 -0
- package/dist/test-fixtures/github-pull-schema.json +3601 -0
- package/dist/test-fixtures/github-review-schema.SOURCE.md +12 -0
- package/dist/test-fixtures/github-review-schema.json +236 -0
- package/package.json +20 -11
- package/src/cli.ts +7 -6
- package/src/generated/graphql-sdl.gen.json +1 -0
- package/src/generated/graphql.gen.json +1 -0
- package/src/generated/surface.gen.json +1 -0
- package/src/generated/ui.gen.json +1 -0
- package/src/github-a11y-snapshot.uitest.ts +5 -5
- package/src/github-budget.ts +4 -4
- package/src/github-capabilities.ts +1993 -556
- package/src/github-conformance.ts +12 -7
- package/src/github-connector.ts +108 -96
- package/src/github-events.ts +225 -95
- package/src/github-git-http.ts +48 -84
- package/src/github-git-plane.ts +247 -385
- package/src/github-journey.uitest.ts +28 -44
- package/src/github-mirror-state.ts +23 -61
- package/src/github-mirror-ui.ts +16 -10
- package/src/github-server.ts +158 -60
- package/src/github-shared.ts +1 -1
- package/src/github-twin.ts +1525 -4494
- package/src/github-ui-conformance.ts +7 -8
- package/src/github-ui-structure.ts +19 -18
- package/src/graphql-wire.ts +115 -0
- package/src/index.ts +50 -7
- package/src/manifest.ts +605 -0
- package/src/npm-registry.ts +43 -0
- package/src/screens/app-installation.tsx +217 -0
- package/src/screens/app-manifest.tsx +97 -0
- package/src/screens/oauth.tsx +258 -0
- package/src/screens/session.tsx +193 -0
- package/src/semantics/actions.ts +395 -0
- package/src/semantics/activity.ts +171 -0
- package/src/semantics/apps.ts +133 -0
- package/src/semantics/branches.ts +133 -0
- package/src/semantics/checks.ts +163 -0
- package/src/semantics/code-scanning-upload.ts +92 -0
- package/src/semantics/codespaces.ts +58 -0
- package/src/semantics/commits.ts +109 -0
- package/src/semantics/contents.ts +112 -0
- package/src/semantics/deployments.ts +116 -0
- package/src/semantics/gists.ts +85 -0
- package/src/semantics/git.ts +226 -0
- package/src/semantics/graphql.ts +505 -0
- package/src/semantics/index.ts +68 -0
- package/src/semantics/issues.ts +434 -0
- package/src/semantics/keys.ts +66 -0
- package/src/semantics/labels.ts +91 -0
- package/src/semantics/meta.ts +139 -0
- package/src/semantics/notifications.ts +58 -0
- package/src/semantics/orgs.ts +383 -0
- package/src/semantics/packages.ts +59 -0
- package/src/semantics/pages.ts +154 -0
- package/src/semantics/projects.ts +246 -0
- package/src/semantics/pulls.ts +421 -0
- package/src/semantics/push-reactions.ts +471 -0
- package/src/semantics/releases.ts +213 -0
- package/src/semantics/repo-invitations.ts +112 -0
- package/src/semantics/repos.ts +373 -0
- package/src/semantics/rulesets.ts +107 -0
- package/src/semantics/search.ts +83 -0
- package/src/semantics/security.ts +153 -0
- package/src/semantics/shared.ts +181 -0
- package/src/semantics/users.ts +252 -0
- package/src/semantics/webhooks.ts +101 -0
- package/test-fixtures/github-known-deviations.json +7 -8
- package/test-fixtures/github-openapi-operations.json +46 -227
- package/src/github-graphql.ts +0 -398
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"generatedBy":"scripts/derive-pack.ts","resources":{"email":{"list":"/user/emails","create":{"path":"/user/emails","encoding":"json","body":[]},"actions":[],"states":{},"embeds":{}},"key":{"list":"/user/keys","retrieve":"/user/keys/{key_id}","create":{"path":"/user/keys","encoding":"json","body":[{"name":"key","type":"string","required":true},{"name":"title","type":"string","required":false}]},"actions":[],"states":{},"embeds":{}},"gpg-key":{"list":"/user/gpg_keys","retrieve":"/user/gpg_keys/{gpg_key_id}","create":{"path":"/user/gpg_keys","encoding":"json","body":[{"name":"armored_public_key","type":"string","required":true},{"name":"name","type":"string","required":false}]},"actions":[],"states":{},"embeds":{}},"gist-simple":{"retrieve":"/gists/{gist_id}","create":{"path":"/gists","encoding":"json","body":[{"name":"description","type":"string","required":false},{"name":"files","type":"object","required":true},{"name":"public","type":"union","required":false}]},"actions":[],"states":{},"embeds":{}},"base-gist":{"list":"/gists","actions":[],"states":{},"embeds":{}},"thread":{"list":"/notifications","retrieve":"/notifications/threads/{thread_id}","actions":[],"states":{},"embeds":{}},"organization-full":{"retrieve":"/orgs/{org}","actions":[],"states":{},"embeds":{}},"org-membership":{"retrieve":"/orgs/{org}/memberships/{username}","actions":[],"states":{"state":["active","pending"]},"embeds":{}},"org-hook":{"list":"/orgs/{org}/hooks","retrieve":"/orgs/{org}/hooks/{hook_id}","create":{"path":"/orgs/{org}/hooks","encoding":"json","body":[{"name":"active","type":"boolean","required":false},{"name":"config","type":"object","required":true},{"name":"events","type":"array","required":false},{"name":"name","type":"string","required":true}]},"actions":[],"states":{},"embeds":{}},"issue-type":{"list":"/orgs/{org}/issue-types","create":{"path":"/orgs/{org}/issue-types","encoding":"json","body":[{"name":"color","type":"string","required":false},{"name":"description","type":"string","required":false},{"name":"is_enabled","type":"boolean","required":true},{"name":"name","type":"string","required":true}]},"actions":[],"states":{},"embeds":{}},"team-full":{"retrieve":"/orgs/{org}/teams/{team_slug}","create":{"path":"/orgs/{org}/teams","encoding":"json","body":[{"name":"description","type":"string","required":false},{"name":"maintainers","type":"array","required":false},{"name":"name","type":"string","required":true},{"name":"notification_setting","type":"string","required":false},{"name":"parent_team_id","type":"integer","required":false},{"name":"parent_team_slug","type":"string","required":false},{"name":"permission","type":"string","required":false},{"name":"privacy","type":"string","required":false},{"name":"repo_names","type":"array","required":false}]},"actions":[],"states":{},"embeds":{}},"team":{"list":"/orgs/{org}/teams","actions":[],"states":{},"embeds":{}},"team-repository":{"retrieve":"/orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}","actions":[],"states":{},"embeds":{}},"projects-v2":{"list":"/orgs/{org}/projectsV2","retrieve":"/orgs/{org}/projectsV2/{project_number}","actions":[],"states":{"state":["closed","open"]},"embeds":{}},"projects-v2-field":{"actions":[],"states":{},"embeds":{}},"projects-v2-item-with-content":{"actions":[],"states":{},"embeds":{}},"code-scanning-alert-items":{"list":"/repos/{owner}/{repo}/code-scanning/alerts","actions":[],"states":{"state":["dismissed","fixed","open"]},"embeds":{}},"code-scanning-analysis":{"list":"/repos/{owner}/{repo}/code-scanning/analyses","retrieve":"/repos/{owner}/{repo}/code-scanning/analyses/{analysis_id}","actions":[],"states":{},"embeds":{}},"dependabot-alert":{"list":"/repos/{owner}/{repo}/dependabot/alerts","retrieve":"/repos/{owner}/{repo}/dependabot/alerts/{alert_number}","actions":[{"operation":"dependabot/update-alert","method":"PATCH","path":"/repos/{owner}/{repo}/dependabot/alerts/{alert_number}","field":"state","from":"*","to":"dismissed"},{"operation":"dependabot/update-alert","method":"PATCH","path":"/repos/{owner}/{repo}/dependabot/alerts/{alert_number}","field":"state","from":"*","to":"open"}],"states":{"state":["dismissed","fixed","open"]},"embeds":{}},"secret-scanning-alert":{"list":"/repos/{owner}/{repo}/secret-scanning/alerts","actions":[],"states":{"state":["open","resolved"]},"embeds":{}},"page-build":{"list":"/repos/{owner}/{repo}/pages/builds","retrieve":"/repos/{owner}/{repo}/pages/builds/latest","actions":[],"states":{"status":["built"]},"embeds":{}},"package":{"list":"/user/packages","retrieve":"/user/packages/{package_type}/{package_name}","actions":[],"states":{},"embeds":{}},"package-version":{"list":"/user/packages/{package_type}/{package_name}/versions","retrieve":"/user/packages/{package_type}/{package_name}/versions/{package_version_id}","actions":[],"states":{},"embeds":{}},"installation":{"list":"/app/installations","retrieve":"/app/installations/{installation_id}","actions":[],"states":{},"embeds":{}},"workflow":{"list":"/repos/{owner}/{repo}/actions/workflows","retrieve":"/repos/{owner}/{repo}/actions/workflows/{workflow_id}","actions":[],"states":{"state":["active","disabled_fork","disabled_inactivity","disabled_manually"]},"embeds":{}},"workflow-run":{"list":"/repos/{owner}/{repo}/actions/runs","retrieve":"/repos/{owner}/{repo}/actions/runs/{run_id}","actions":[{"operation":"actions/re-run-workflow","method":"POST","path":"/repos/{owner}/{repo}/actions/runs/{run_id}/rerun","field":"status","from":"*","to":"queued"},{"operation":"actions/cancel-workflow-run","method":"POST","path":"/repos/{owner}/{repo}/actions/runs/{run_id}/cancel","field":"status","from":"*","to":"completed"}],"states":{"status":["completed","in_progress","queued"]},"embeds":{}},"job":{"list":"/repos/{owner}/{repo}/actions/runs/{run_id}/jobs","retrieve":"/repos/{owner}/{repo}/actions/jobs/{job_id}","actions":[],"states":{"status":["completed","in_progress","queued"]},"embeds":{}},"artifact":{"list":"/repos/{owner}/{repo}/actions/artifacts","retrieve":"/repos/{owner}/{repo}/actions/artifacts/{artifact_id}","actions":[],"states":{},"embeds":{}},"actions-secret":{"list":"/repos/{owner}/{repo}/actions/secrets","retrieve":"/repos/{owner}/{repo}/actions/secrets/{secret_name}","actions":[],"states":{},"embeds":{}},"actions-variable":{"list":"/repos/{owner}/{repo}/actions/variables","retrieve":"/repos/{owner}/{repo}/actions/variables/{name}","actions":[],"states":{},"embeds":{}},"organization-actions-secret":{"list":"/orgs/{org}/actions/secrets","retrieve":"/orgs/{org}/actions/secrets/{secret_name}","actions":[],"states":{},"embeds":{}},"organization-actions-variable":{"list":"/orgs/{org}/actions/variables","retrieve":"/orgs/{org}/actions/variables/{name}","actions":[],"states":{},"embeds":{}},"deploy-key":{"list":"/repos/{owner}/{repo}/keys","retrieve":"/repos/{owner}/{repo}/keys/{key_id}","create":{"path":"/repos/{owner}/{repo}/keys","encoding":"json","body":[{"name":"key","type":"string","required":true},{"name":"read_only","type":"boolean","required":false},{"name":"title","type":"string","required":false}]},"actions":[],"states":{},"embeds":{}},"autolink":{"list":"/repos/{owner}/{repo}/autolinks","retrieve":"/repos/{owner}/{repo}/autolinks/{autolink_id}","create":{"path":"/repos/{owner}/{repo}/autolinks","encoding":"json","body":[{"name":"is_alphanumeric","type":"boolean","required":false},{"name":"key_prefix","type":"string","required":true},{"name":"url_template","type":"string","required":true}]},"actions":[],"states":{},"embeds":{}},"repository-ruleset":{"list":"/repos/{owner}/{repo}/rulesets","retrieve":"/repos/{owner}/{repo}/rulesets/{ruleset_id}","create":{"path":"/repos/{owner}/{repo}/rulesets","encoding":"json","body":[{"name":"bypass_actors","type":"array","required":false},{"name":"conditions","type":"repository-ruleset-conditions","required":false},{"name":"enforcement","type":"repository-rule-enforcement","required":true},{"name":"name","type":"string","required":true},{"name":"rules","type":"array","required":false},{"name":"target","type":"string","required":false}]},"actions":[],"states":{},"embeds":{}},"rule-suite":{"retrieve":"/repos/{owner}/{repo}/rulesets/rule-suites/{rule_suite_id}","actions":[],"states":{},"embeds":{}},"deployment":{"list":"/repos/{owner}/{repo}/deployments","retrieve":"/repos/{owner}/{repo}/deployments/{deployment_id}","create":{"path":"/repos/{owner}/{repo}/deployments","encoding":"json","body":[{"name":"auto_merge","type":"boolean","required":false},{"name":"description","type":"string","required":false},{"name":"environment","type":"string","required":false},{"name":"payload","type":"union","required":false},{"name":"production_environment","type":"boolean","required":false},{"name":"ref","type":"string","required":true},{"name":"required_contexts","type":"array","required":false},{"name":"task","type":"string","required":false},{"name":"transient_environment","type":"boolean","required":false}]},"actions":[],"states":{},"embeds":{}},"deployment-status":{"list":"/repos/{owner}/{repo}/deployments/{deployment_id}/statuses","retrieve":"/repos/{owner}/{repo}/deployments/{deployment_id}/statuses/{status_id}","create":{"path":"/repos/{owner}/{repo}/deployments/{deployment_id}/statuses","encoding":"json","body":[{"name":"auto_inactive","type":"boolean","required":false},{"name":"description","type":"string","required":false},{"name":"environment","type":"string","required":false},{"name":"environment_url","type":"string","required":false},{"name":"log_url","type":"string","required":false},{"name":"state","type":"string","required":true},{"name":"target_url","type":"string","required":false}]},"actions":[],"states":{},"embeds":{}},"environment":{"list":"/repos/{owner}/{repo}/environments","retrieve":"/repos/{owner}/{repo}/environments/{environment_name}","actions":[],"states":{},"embeds":{}},"release":{"list":"/repos/{owner}/{repo}/releases","retrieve":"/repos/{owner}/{repo}/releases/latest","create":{"path":"/repos/{owner}/{repo}/releases","encoding":"json","body":[{"name":"body","type":"string","required":false},{"name":"discussion_category_name","type":"string","required":false},{"name":"draft","type":"boolean","required":false},{"name":"generate_release_notes","type":"boolean","required":false},{"name":"make_latest","type":"string","required":false},{"name":"name","type":"string","required":false},{"name":"prerelease","type":"boolean","required":false},{"name":"tag_name","type":"string","required":true},{"name":"target_commitish","type":"string","required":false}]},"actions":[{"operation":"repos/update-release","method":"PATCH","path":"/repos/{owner}/{repo}/releases/{release_id}","field":"draft","from":"*","to":"false"},{"operation":"repos/update-release","method":"PATCH","path":"/repos/{owner}/{repo}/releases/{release_id}","field":"draft","from":"*","to":"true"}],"states":{"draft":["false","true"]},"embeds":{}},"release-asset":{"list":"/repos/{owner}/{repo}/releases/{release_id}/assets","retrieve":"/repos/{owner}/{repo}/releases/assets/{asset_id}","create":{"path":"/repos/{owner}/{repo}/releases/{release_id}/assets","encoding":"none","body":[]},"actions":[],"states":{"state":["uploaded"]},"embeds":{}},"hook":{"list":"/repos/{owner}/{repo}/hooks","retrieve":"/repos/{owner}/{repo}/hooks/{hook_id}","create":{"path":"/repos/{owner}/{repo}/hooks","encoding":"json","body":[{"name":"active","type":"boolean","required":false},{"name":"config","type":"object","required":false},{"name":"events","type":"array","required":false},{"name":"name","type":"string","required":false}]},"actions":[],"states":{},"embeds":{}},"label":{"list":"/repos/{owner}/{repo}/labels","retrieve":"/repos/{owner}/{repo}/labels/{name}","create":{"path":"/repos/{owner}/{repo}/labels","encoding":"json","body":[{"name":"color","type":"string","required":false},{"name":"description","type":"string","required":false},{"name":"name","type":"string","required":true}]},"actions":[],"states":{},"embeds":{}},"milestone":{"list":"/repos/{owner}/{repo}/milestones","retrieve":"/repos/{owner}/{repo}/milestones/{milestone_number}","create":{"path":"/repos/{owner}/{repo}/milestones","encoding":"json","body":[{"name":"description","type":"string","required":false},{"name":"due_on","type":"string","required":false},{"name":"state","type":"string","required":false},{"name":"title","type":"string","required":true}]},"actions":[{"operation":"issues/update-milestone","method":"PATCH","path":"/repos/{owner}/{repo}/milestones/{milestone_number}","field":"state","from":"*","to":"closed"},{"operation":"issues/update-milestone","method":"PATCH","path":"/repos/{owner}/{repo}/milestones/{milestone_number}","field":"state","from":"*","to":"open"}],"states":{"state":["closed","open"]},"embeds":{}},"commit-comment":{"list":"/repos/{owner}/{repo}/comments","retrieve":"/repos/{owner}/{repo}/comments/{comment_id}","create":{"path":"/repos/{owner}/{repo}/commits/{commit_sha}/comments","encoding":"json","body":[{"name":"body","type":"string","required":true},{"name":"line","type":"integer","required":false},{"name":"path","type":"string","required":false},{"name":"position","type":"integer","required":false}]},"actions":[],"states":{},"embeds":{}},"status":{"list":"/repos/{owner}/{repo}/commits/{ref}/statuses","actions":[],"states":{},"embeds":{}},"check-run":{"list":"/repos/{owner}/{repo}/commits/{ref}/check-runs","retrieve":"/repos/{owner}/{repo}/check-runs/{check_run_id}","create":{"path":"/repos/{owner}/{repo}/check-runs","encoding":"json","body":[{"name":"actions","type":"array","required":false},{"name":"completed_at","type":"string","required":false},{"name":"conclusion","type":"string","required":false},{"name":"details_url","type":"string","required":false},{"name":"external_id","type":"string","required":false},{"name":"head_sha","type":"string","required":true},{"name":"name","type":"string","required":true},{"name":"output","type":"object","required":false},{"name":"started_at","type":"string","required":false},{"name":"status","type":"string","required":false}]},"actions":[{"operation":"checks/update","method":"PATCH","path":"/repos/{owner}/{repo}/check-runs/{check_run_id}","field":"status","from":"*","to":"in_progress"},{"operation":"checks/update","method":"PATCH","path":"/repos/{owner}/{repo}/check-runs/{check_run_id}","field":"status","from":"*","to":"completed"}],"states":{"status":["completed","in_progress","queued"]},"embeds":{}},"git-ref":{"retrieve":"/repos/{owner}/{repo}/git/ref/{ref}","actions":[],"states":{},"embeds":{}},"full-repository":{"retrieve":"/repos/{owner}/{repo}","actions":[{"operation":"repos/update","method":"PATCH","path":"/repos/{owner}/{repo}","field":"archived","from":"*","to":"true"},{"operation":"repos/update","method":"PATCH","path":"/repos/{owner}/{repo}","field":"archived","from":"*","to":"false"}],"states":{"archived":["false","true"]},"embeds":{}},"short-branch":{"list":"/repos/{owner}/{repo}/branches","actions":[],"states":{},"embeds":{}},"collaborator":{"list":"/repos/{owner}/{repo}/collaborators","actions":[],"states":{},"embeds":{}},"issue":{"list":"/repos/{owner}/{repo}/issues","retrieve":"/repos/{owner}/{repo}/issues/{issue_number}","create":{"path":"/repos/{owner}/{repo}/issues","encoding":"json","body":[{"name":"assignee","type":"string","required":false},{"name":"assignees","type":"array","required":false},{"name":"body","type":"string","required":false},{"name":"issue_field_values","type":"array","required":false},{"name":"labels","type":"array","required":false},{"name":"milestone","type":"union","required":false},{"name":"parent_issue_id","type":"integer","required":false},{"name":"title","type":"union","required":true},{"name":"type","type":"string","required":false}]},"actions":[{"operation":"issues/update","method":"PATCH","path":"/repos/{owner}/{repo}/issues/{issue_number}","field":"state","from":"*","to":"closed"},{"operation":"issues/update","method":"PATCH","path":"/repos/{owner}/{repo}/issues/{issue_number}","field":"state","from":"*","to":"open"},{"operation":"issues/lock","method":"PUT","path":"/repos/{owner}/{repo}/issues/{issue_number}/lock","field":"locked","from":"*","to":"true"},{"operation":"issues/unlock","method":"DELETE","path":"/repos/{owner}/{repo}/issues/{issue_number}/lock","field":"locked","from":"*","to":"false"}],"states":{"state":["closed","open"],"locked":["false","true"]},"embeds":{}},"issue-comment":{"list":"/repos/{owner}/{repo}/issues/{issue_number}/comments","retrieve":"/repos/{owner}/{repo}/issues/comments/{comment_id}","create":{"path":"/repos/{owner}/{repo}/issues/{issue_number}/comments","encoding":"json","body":[{"name":"body","type":"string","required":true}]},"actions":[],"states":{},"embeds":{}},"reaction":{"list":"/repos/{owner}/{repo}/issues/{issue_number}/reactions","create":{"path":"/repos/{owner}/{repo}/issues/{issue_number}/reactions","encoding":"json","body":[{"name":"content","type":"string","required":true}]},"actions":[],"states":{},"embeds":{}},"pull-request-review-comment":{"list":"/repos/{owner}/{repo}/pulls/{pull_number}/comments","retrieve":"/repos/{owner}/{repo}/pulls/comments/{comment_id}","create":{"path":"/repos/{owner}/{repo}/pulls/{pull_number}/comments","encoding":"json","body":[{"name":"body","type":"string","required":true},{"name":"commit_id","type":"string","required":true},{"name":"in_reply_to","type":"integer","required":false},{"name":"line","type":"integer","required":false},{"name":"path","type":"string","required":true},{"name":"position","type":"integer","required":false},{"name":"side","type":"string","required":false},{"name":"start_line","type":"integer","required":false},{"name":"start_side","type":"string","required":false},{"name":"subject_type","type":"string","required":false}]},"actions":[],"states":{},"embeds":{}},"pull-request":{"retrieve":"/repos/{owner}/{repo}/pulls/{pull_number}","create":{"path":"/repos/{owner}/{repo}/pulls","encoding":"json","body":[{"name":"base","type":"string","required":true},{"name":"body","type":"string","required":false},{"name":"draft","type":"boolean","required":false},{"name":"head","type":"string","required":true},{"name":"head_repo","type":"string","required":false},{"name":"issue","type":"integer","required":false},{"name":"maintainer_can_modify","type":"boolean","required":false},{"name":"title","type":"string","required":false}]},"actions":[{"operation":"pulls/update","method":"PATCH","path":"/repos/{owner}/{repo}/pulls/{pull_number}","field":"state","from":"*","to":"closed"},{"operation":"pulls/update","method":"PATCH","path":"/repos/{owner}/{repo}/pulls/{pull_number}","field":"state","from":"*","to":"open"},{"operation":"pulls/merge","method":"PUT","path":"/repos/{owner}/{repo}/pulls/{pull_number}/merge","field":"state","from":["open"],"to":"closed"},{"operation":"pulls/merge","method":"PUT","path":"/repos/{owner}/{repo}/pulls/{pull_number}/merge","field":"merged","from":["false"],"to":"true"},{"operation":"pulls/merge","method":"PUT","path":"/repos/{owner}/{repo}/pulls/{pull_number}/merge","field":"draft","from":["false"]}],"states":{"state":["closed","open"],"merged":["false","true"],"draft":["false","true"],"locked":["false","true"]},"embeds":{}},"pull-request-review":{"list":"/repos/{owner}/{repo}/pulls/{pull_number}/reviews","retrieve":"/repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}","create":{"path":"/repos/{owner}/{repo}/pulls/{pull_number}/reviews","encoding":"json","body":[{"name":"body","type":"string","required":false},{"name":"comments","type":"array","required":false},{"name":"commit_id","type":"string","required":false},{"name":"event","type":"string","required":false}]},"actions":[{"operation":"pulls/dismiss-review","method":"PUT","path":"/repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/dismissals","field":"state","from":"*","to":"DISMISSED"}],"states":{"state":["COMMENTED","DISMISSED"]},"embeds":{}},"codespace":{"list":"/user/codespaces","retrieve":"/user/codespaces/{codespace_name}","create":{"path":"/user/codespaces","encoding":"json","body":[]},"actions":[{"operation":"codespaces/start-for-authenticated-user","method":"POST","path":"/user/codespaces/{codespace_name}/start","field":"state","from":"*","to":"Available"},{"operation":"codespaces/stop-for-authenticated-user","method":"POST","path":"/user/codespaces/{codespace_name}/stop","field":"state","from":"*","to":"Shutdown"}],"states":{"state":["Available","Shutdown"]},"embeds":{}}}}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { RateBudget, type RateBudgetDeclaration, type RateBudgetOptions, type RateBudgetReservation, type RateBudgetSnapshot } from '@volter/world-core';
|
|
2
|
+
/** Rolling window, in ms. One HOUR — the horizon of GitHub's primary 5,000-requests limit. */
|
|
3
|
+
export declare const GITHUB_BUDGET_WINDOW_MS: number;
|
|
4
|
+
/**
|
|
5
|
+
* Weighted POINTS allowed inside one window. 600 points/hour is ≤ 12% of the primary 5,000
|
|
6
|
+
* requests/hour AND stays under the secondary 900 points/minute even if spent all at once.
|
|
7
|
+
*/
|
|
8
|
+
export declare const GITHUB_BUDGET_CEILING = 600;
|
|
9
|
+
/**
|
|
10
|
+
* Weighted points allowed in any 60-SECOND sub-window, enforced by the kernel independently of the
|
|
11
|
+
* hourly ceiling. Without it, an hour-long window admits its entire 600 points in one millisecond —
|
|
12
|
+
* twenty times what the austere fallback allows in a minute — and nothing in the kernel reached that
|
|
13
|
+
* (§9 round 2, 2026-07-26). 300 is deliberately HALF the hourly ceiling: a full PR pull of a busy
|
|
14
|
+
* repo is ~80 points and the largest realistic burst is well under it, while both of GitHub's
|
|
15
|
+
* per-minute legs are honoured with room to spare — 300 < the 900-points/minute secondary limit, and
|
|
16
|
+
* 300/8 = 37 writes < the 80 content-generating requests/minute.
|
|
17
|
+
*/
|
|
18
|
+
export declare const GITHUB_BUDGET_BURST_CEILING = 300;
|
|
19
|
+
/** Seconds. A `Retry-After` above this means the token is throttled hard — fail loudly, don't sleep. */
|
|
20
|
+
export declare const GITHUB_BUDGET_MAX_RETRY_AFTER_S = 300;
|
|
21
|
+
/** GitHub's OWN published point costs. Not a proxy for them — the numbers themselves. */
|
|
22
|
+
export declare const GITHUB_CALL_WEIGHTS: {
|
|
23
|
+
/**
|
|
24
|
+
* GitHub's own table prices a `POST`/`PATCH`/`PUT`/`DELETE` at **5 points**. This charges **8**,
|
|
25
|
+
* and the extra 3 are not a re-transcription of the vendor — they are what makes the OTHER
|
|
26
|
+
* documented write limit hold. GitHub caps content creation at **80 per minute** as well as 500
|
|
27
|
+
* per hour, and with an hour-long window a 5-point price lets 600/5 = 120 writes land inside a
|
|
28
|
+
* single minute: 1.5x that 80. At 8 points only 75 fit, which is under it. (§9 finding,
|
|
29
|
+
* 2026-07-26: the declaration cited the 80/min limit in its own header and then checked only the
|
|
30
|
+
* hourly leg.) Reads are unaffected, and the ratio is still write-dearer-than-read as published.
|
|
31
|
+
*/
|
|
32
|
+
readonly write: 8;
|
|
33
|
+
/** "Most REST API GET, HEAD, and OPTIONS requests" — 1 point, per GitHub's own table. */
|
|
34
|
+
readonly other: 1;
|
|
35
|
+
};
|
|
36
|
+
/** THE PACK'S DECLARATION — pure data, the only GitHub-specific thing in the whole budget. */
|
|
37
|
+
export declare const GITHUB_RATE_BUDGET: RateBudgetDeclaration;
|
|
38
|
+
/**
|
|
39
|
+
* Price one call by its octokit-style ROUTE (`"GET /repos/{owner}/{repo}/pulls"`). The route, not
|
|
40
|
+
* the substituted path, is the key: it is what GitHub's docs name endpoints by, and it keeps the
|
|
41
|
+
* ledger's classification stable across owners and repos. A route nobody classified still costs
|
|
42
|
+
* `defaultWeight` — an unknown endpoint must never be free.
|
|
43
|
+
*/
|
|
44
|
+
export declare function githubCallWeight(route: string): number;
|
|
45
|
+
/** Where GitHub's ledger lives. Token-keyed and cwd-independent by default (the primary limit is
|
|
46
|
+
* per token, so a cwd-scoped ledger would hand the same PAT a fresh allowance in every checkout,
|
|
47
|
+
* worktree and CI matrix leg — precisely the shape a matrix build has); pass `root` to opt into
|
|
48
|
+
* world-scoped accounting instead. */
|
|
49
|
+
export declare function githubBudgetPath(opts?: {
|
|
50
|
+
root?: string;
|
|
51
|
+
token?: string;
|
|
52
|
+
} | string): string;
|
|
53
|
+
/** Construction options for GitHub's budget. The vendor is fixed; everything else may only TIGHTEN. */
|
|
54
|
+
export type GithubBudgetOptions = Omit<RateBudgetOptions, 'vendor'>;
|
|
55
|
+
/**
|
|
56
|
+
* GitHub's budget — the shared kernel guard bound to this vendor's declaration. A real subclass,
|
|
57
|
+
* not an alias, so `budget instanceof GithubBudget` in `liveGithubExecute` means "a budget that
|
|
58
|
+
* accounts against GITHUB's ledger under GITHUB's ceiling": another vendor's `RateBudget` (with its
|
|
59
|
+
* own, possibly larger, ceiling) is NOT assignable there.
|
|
60
|
+
*/
|
|
61
|
+
export declare class GithubBudget extends RateBudget {
|
|
62
|
+
constructor(opts?: GithubBudgetOptions);
|
|
63
|
+
}
|
|
64
|
+
/** The typed refusal. One error class shared with every other vendor's budget; `err.vendor` says
|
|
65
|
+
* which one refused, and `err.kind` says why. */
|
|
66
|
+
export { RateBudgetError as GithubBudgetError } from '@volter/world-core';
|
|
67
|
+
export type { RateBudgetErrorKind as GithubBudgetErrorKind } from '@volter/world-core';
|
|
68
|
+
export type GithubBudgetReservation = RateBudgetReservation;
|
|
69
|
+
export type GithubBudgetSnapshot = RateBudgetSnapshot;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// GitHub's CLIENT-SIDE RATE BUDGET — the pack's DECLARATION (the numbers) plus the thin typed
|
|
2
|
+
// bindings `liveGithubExecute` uses. The MECHANISM — the durable token-keyed ledger, the rolling
|
|
3
|
+
// window, reserve-under-lock, the `Retry-After`/429 cooldown, fail-CLOSED on a corrupt ledger —
|
|
4
|
+
// lives ONCE in the vendor-agnostic kernel (`@volter/world-core` → `rateBudget.ts`). Read that module's
|
|
5
|
+
// header for the full rationale AND for the honest list of what the guard does not guarantee (an
|
|
6
|
+
// injected clock or ledger path still defeats it — it guards carelessness, not malice).
|
|
7
|
+
//
|
|
8
|
+
// ── WHY THIS EXISTS ─────────────────────────────────────────────────────────────────────────
|
|
9
|
+
// A real ~4.5-DAY vendor lockout (Figma, 2026-07-25) happened because raw API calls were made
|
|
10
|
+
// outside the pack's connector — no cache, no batching, no ceiling. Discipline only binds the code
|
|
11
|
+
// that follows it; a BUDGET binds the code that does not.
|
|
12
|
+
//
|
|
13
|
+
// ── HOW THE CEILING WAS CHOSEN: GITHUB'S OWN POINT SYSTEM ───────────────────────────────────
|
|
14
|
+
// GitHub is the one vendor in this repo whose published scheme is ALREADY a weighted point budget,
|
|
15
|
+
// so this declaration reproduces it rather than inventing a proxy for it. From
|
|
16
|
+
// https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api (read 2026-07-26):
|
|
17
|
+
// • PRIMARY, per authenticated personal access token: 5,000 requests per HOUR
|
|
18
|
+
// • SECONDARY, points per minute: 900 points per minute for REST endpoints
|
|
19
|
+
// — "most REST API GET, HEAD and OPTIONS requests" = 1 point
|
|
20
|
+
// — "most REST API POST, PATCH, PUT or DELETE requests" = 5 points
|
|
21
|
+
// • SECONDARY, concurrency: no more than 100 concurrent requests
|
|
22
|
+
// • SECONDARY, content creation: 80 per minute and 500 per hour
|
|
23
|
+
// The read weight IS GitHub's own number — 1 point. The write weight is deliberately DEARER than
|
|
24
|
+
// GitHub's 5 (it is 8); see `GITHUB_CALL_WEIGHTS.write` for why that is what makes the
|
|
25
|
+
// 80-content-creations-per-minute leg hold under an hour-long window. Nothing here is invented: the
|
|
26
|
+
// only departure from the published table is in the tightening direction, and it is labelled.
|
|
27
|
+
//
|
|
28
|
+
// The window is an HOUR (the kernel's maximum, and the horizon of GitHub's primary limit) and the
|
|
29
|
+
// ceiling is 600 points. That is bounded on BOTH published axes at once:
|
|
30
|
+
// • against the primary 5,000/hour: at most 600 requests can fit in 600 points, so ≤ 12% of it;
|
|
31
|
+
// • against the secondary 900 points/MINUTE: even spending the entire hour's allowance in a
|
|
32
|
+
// single instant is 600 points, still under 900 — the burst cannot breach it either;
|
|
33
|
+
// • against content creation (80/MINUTE and 500/hour): writes cost 8 rather than GitHub's own 5,
|
|
34
|
+
// because at 5 the hour-long window would admit 120 writes inside a single minute — 1.5x the
|
|
35
|
+
// 80/minute leg. At 8, only 75 fit, so BOTH legs hold. See `GITHUB_CALL_WEIGHTS.write`.
|
|
36
|
+
// A full PR pull of a busy repo is roughly 1 + 4 per PR ≈ 80 points for 20 PRs, so this admits
|
|
37
|
+
// about seven complete pulls an hour — far more than an on-demand connector needs, and far below
|
|
38
|
+
// the runaway shape.
|
|
39
|
+
//
|
|
40
|
+
// ⚠️ HONESTLY, ON THE COMPARISON WITH THE KERNEL FALLBACK. `DEFAULT_RATE_BUDGET` is 30 calls a
|
|
41
|
+
// minute, i.e. 1,800 an hour sustained. This declaration is TIGHTER sustained (600/hour) but LOOSER
|
|
42
|
+
// in a single minute — and that looseness is now BOUNDED AND ENFORCED rather than merely argued:
|
|
43
|
+
// `burstCeiling` caps any 60-second sub-window at 300 points, which the kernel refuses against
|
|
44
|
+
// independently of the hourly ceiling. 300 sits under both of GitHub's per-minute legs (the 900-
|
|
45
|
+
// points/minute secondary limit, and 300/8 = 37 writes against the 80 content-generating requests
|
|
46
|
+
// per minute), so the burst is inside the vendor's published contract by arithmetic, not by prose.
|
|
47
|
+
// An hour-long window is the only way to bound GitHub's hourly PRIMARY limit at all; the burst bound
|
|
48
|
+
// is what stops that from silently buying an instantaneous allowance nobody asked for.
|
|
49
|
+
//
|
|
50
|
+
// The window bounds spend, not PACE (the kernel refuses, it never sleeps — see its header). GitHub
|
|
51
|
+
// also caps concurrency at 100, which a weighted ledger does not model at all; that is the caller's
|
|
52
|
+
// job. The backstop for both is the cooldown, armed from `Retry-After` / a 403-or-429 /
|
|
53
|
+
// `x-ratelimit-remaining: 0`.
|
|
54
|
+
import { declareRateBudget, rateBudgetPath, rateBudgetWeight, RateBudget, } from '@volter/world-core';
|
|
55
|
+
const VENDOR = 'github';
|
|
56
|
+
/** Rolling window, in ms. One HOUR — the horizon of GitHub's primary 5,000-requests limit. */
|
|
57
|
+
export const GITHUB_BUDGET_WINDOW_MS = 60 * 60 * 1_000;
|
|
58
|
+
/**
|
|
59
|
+
* Weighted POINTS allowed inside one window. 600 points/hour is ≤ 12% of the primary 5,000
|
|
60
|
+
* requests/hour AND stays under the secondary 900 points/minute even if spent all at once.
|
|
61
|
+
*/
|
|
62
|
+
export const GITHUB_BUDGET_CEILING = 600;
|
|
63
|
+
/**
|
|
64
|
+
* Weighted points allowed in any 60-SECOND sub-window, enforced by the kernel independently of the
|
|
65
|
+
* hourly ceiling. Without it, an hour-long window admits its entire 600 points in one millisecond —
|
|
66
|
+
* twenty times what the austere fallback allows in a minute — and nothing in the kernel reached that
|
|
67
|
+
* (§9 round 2, 2026-07-26). 300 is deliberately HALF the hourly ceiling: a full PR pull of a busy
|
|
68
|
+
* repo is ~80 points and the largest realistic burst is well under it, while both of GitHub's
|
|
69
|
+
* per-minute legs are honoured with room to spare — 300 < the 900-points/minute secondary limit, and
|
|
70
|
+
* 300/8 = 37 writes < the 80 content-generating requests/minute.
|
|
71
|
+
*/
|
|
72
|
+
export const GITHUB_BUDGET_BURST_CEILING = 300;
|
|
73
|
+
/** Seconds. A `Retry-After` above this means the token is throttled hard — fail loudly, don't sleep. */
|
|
74
|
+
export const GITHUB_BUDGET_MAX_RETRY_AFTER_S = 300;
|
|
75
|
+
/** GitHub's OWN published point costs. Not a proxy for them — the numbers themselves. */
|
|
76
|
+
export const GITHUB_CALL_WEIGHTS = {
|
|
77
|
+
/**
|
|
78
|
+
* GitHub's own table prices a `POST`/`PATCH`/`PUT`/`DELETE` at **5 points**. This charges **8**,
|
|
79
|
+
* and the extra 3 are not a re-transcription of the vendor — they are what makes the OTHER
|
|
80
|
+
* documented write limit hold. GitHub caps content creation at **80 per minute** as well as 500
|
|
81
|
+
* per hour, and with an hour-long window a 5-point price lets 600/5 = 120 writes land inside a
|
|
82
|
+
* single minute: 1.5x that 80. At 8 points only 75 fit, which is under it. (§9 finding,
|
|
83
|
+
* 2026-07-26: the declaration cited the 80/min limit in its own header and then checked only the
|
|
84
|
+
* hourly leg.) Reads are unaffected, and the ratio is still write-dearer-than-read as published.
|
|
85
|
+
*/
|
|
86
|
+
write: 8,
|
|
87
|
+
/** "Most REST API GET, HEAD, and OPTIONS requests" — 1 point, per GitHub's own table. */
|
|
88
|
+
other: 1,
|
|
89
|
+
};
|
|
90
|
+
/** THE PACK'S DECLARATION — pure data, the only GitHub-specific thing in the whole budget. */
|
|
91
|
+
export const GITHUB_RATE_BUDGET = {
|
|
92
|
+
windowMs: GITHUB_BUDGET_WINDOW_MS,
|
|
93
|
+
ceiling: GITHUB_BUDGET_CEILING,
|
|
94
|
+
burstCeiling: GITHUB_BUDGET_BURST_CEILING,
|
|
95
|
+
defaultWeight: GITHUB_CALL_WEIGHTS.other,
|
|
96
|
+
maxRetryAfterSeconds: GITHUB_BUDGET_MAX_RETRY_AFTER_S,
|
|
97
|
+
// Keyed by the octokit-style ROUTE (`"POST /repos/{owner}/{repo}/pulls"`), so the method is the
|
|
98
|
+
// first token and GitHub's own read/write split is expressible as one anchored rule.
|
|
99
|
+
rules: [
|
|
100
|
+
{ match: '^(POST|PATCH|PUT|DELETE) ', weight: GITHUB_CALL_WEIGHTS.write },
|
|
101
|
+
],
|
|
102
|
+
reason: "GitHub's published scheme IS a weighted point budget, so these weights are its own numbers, not " +
|
|
103
|
+
'a proxy (docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api, read ' +
|
|
104
|
+
'2026-07-26): 5,000 requests/hour primary per PAT; secondary limits of 900 POINTS per minute ' +
|
|
105
|
+
'with GET/HEAD/OPTIONS = 1 point and POST/PATCH/PUT/DELETE = 5 points, 100 concurrent requests, ' +
|
|
106
|
+
'and 80 content-generating requests/minute / 500 per hour. 600 points per HOUR is bounded on ' +
|
|
107
|
+
'every axis at once: at most 600 requests fit in 600 points (≤12% of the 5,000/hour primary), and ' +
|
|
108
|
+
'spending the entire hour instantly is still 600 < the 900/minute secondary. Writes are charged 8 ' +
|
|
109
|
+
"rather than GitHub's own 5 — the only departure from its table, and a TIGHTENING: at 5 points the " +
|
|
110
|
+
'hour-long window would admit 120 writes inside one minute, 1.5x the documented 80/minute content-' +
|
|
111
|
+
'creation leg, while at 8 only 75 fit, so both the 80/minute and 500/hour legs hold. Versus the kernel fallback (30 ' +
|
|
112
|
+
'calls/min = 1,800/hour) this is TIGHTER sustained but LOOSER in one minute — and that looseness is ' +
|
|
113
|
+
'BOUNDED: burstCeiling caps any 60s sub-window at 300 points, which the kernel enforces separately, ' +
|
|
114
|
+
'and 300 sits under both per-minute legs (900 points/min, and 300/8 = 37 writes vs 80 content-' +
|
|
115
|
+
'generating requests/min). An hour-long window is the only way to bound ' +
|
|
116
|
+
"GitHub's hourly primary limit at all. It bounds spend, not pace, and does not model the " +
|
|
117
|
+
'concurrency cap; the Retry-After / 403-or-429 cooldown is the backstop for both.',
|
|
118
|
+
};
|
|
119
|
+
// Declared at module load, so merely importing this module (which `github-connector.ts` does) is
|
|
120
|
+
// enough to arm the real ceiling. `RateBudget` reads its policy live precisely so this declaration
|
|
121
|
+
// takes effect the moment it lands, and constructing through the subclass below (which imports this
|
|
122
|
+
// module) is what makes the ordering a non-issue in practice.
|
|
123
|
+
declareRateBudget(VENDOR, GITHUB_RATE_BUDGET);
|
|
124
|
+
/**
|
|
125
|
+
* Price one call by its octokit-style ROUTE (`"GET /repos/{owner}/{repo}/pulls"`). The route, not
|
|
126
|
+
* the substituted path, is the key: it is what GitHub's docs name endpoints by, and it keeps the
|
|
127
|
+
* ledger's classification stable across owners and repos. A route nobody classified still costs
|
|
128
|
+
* `defaultWeight` — an unknown endpoint must never be free.
|
|
129
|
+
*/
|
|
130
|
+
export function githubCallWeight(route) {
|
|
131
|
+
const at = route.indexOf('?');
|
|
132
|
+
const query = {};
|
|
133
|
+
if (at !== -1)
|
|
134
|
+
for (const [k, v] of new URLSearchParams(route.slice(at + 1)))
|
|
135
|
+
query[k] = v;
|
|
136
|
+
const raw = (at === -1 ? route : route.slice(0, at)).trim();
|
|
137
|
+
// NORMALIZED, because the method rule is otherwise trivially evaded (§9 finding, 2026-07-26):
|
|
138
|
+
// `fetch` upper-cases a known lowercase method before sending, so `'post /repos/…'` issues a real
|
|
139
|
+
// WRITE that a `^(POST|…) ` rule would price as a 1-point read; and a trailing slash makes a `$`
|
|
140
|
+
// anchor miss a route most routers treat as identical. Both are input variations, not attacks, and
|
|
141
|
+
// either one voids the read/write split that IS GitHub's own published point scheme.
|
|
142
|
+
const sp = raw.indexOf(' ');
|
|
143
|
+
const method = (sp === -1 ? raw : raw.slice(0, sp)).toUpperCase();
|
|
144
|
+
const path = sp === -1 ? '' : raw.slice(sp + 1);
|
|
145
|
+
const bare = path.length > 1 && path.endsWith('/') ? path.replace(/\/+$/, '') : path;
|
|
146
|
+
return rateBudgetWeight(VENDOR, bare === '' ? method : `${method} ${bare}`, query);
|
|
147
|
+
}
|
|
148
|
+
/** Where GitHub's ledger lives. Token-keyed and cwd-independent by default (the primary limit is
|
|
149
|
+
* per token, so a cwd-scoped ledger would hand the same PAT a fresh allowance in every checkout,
|
|
150
|
+
* worktree and CI matrix leg — precisely the shape a matrix build has); pass `root` to opt into
|
|
151
|
+
* world-scoped accounting instead. */
|
|
152
|
+
export function githubBudgetPath(opts = {}) {
|
|
153
|
+
const o = typeof opts === 'string' ? { root: opts } : opts;
|
|
154
|
+
// VENDOR spread LAST: a loosely-typed `{ vendor: 'other', … }` slipping through (TypeScript's
|
|
155
|
+
// excess-property check only catches object literals) must not redirect this pack's ledger to
|
|
156
|
+
// another vendor's file.
|
|
157
|
+
return rateBudgetPath({ ...o, vendor: VENDOR });
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* GitHub's budget — the shared kernel guard bound to this vendor's declaration. A real subclass,
|
|
161
|
+
* not an alias, so `budget instanceof GithubBudget` in `liveGithubExecute` means "a budget that
|
|
162
|
+
* accounts against GITHUB's ledger under GITHUB's ceiling": another vendor's `RateBudget` (with its
|
|
163
|
+
* own, possibly larger, ceiling) is NOT assignable there.
|
|
164
|
+
*/
|
|
165
|
+
export class GithubBudget extends RateBudget {
|
|
166
|
+
constructor(opts = {}) {
|
|
167
|
+
super({ ...opts, vendor: VENDOR });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/** The typed refusal. One error class shared with every other vendor's budget; `err.vendor` says
|
|
171
|
+
* which one refused, and `err.kind` says why. */
|
|
172
|
+
export { RateBudgetError as GithubBudgetError } from '@volter/world-core';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type CapabilityReport, type CapabilitySpec } from '@volter/world-tooling';
|
|
2
|
+
export declare function withRoot(fn: (root: string) => Promise<boolean>): Promise<boolean>;
|
|
3
|
+
export declare const GITHUB_CAPABILITIES: CapabilitySpec[];
|
|
4
|
+
export declare const GITHUB_AREAS: readonly ["actions", "activity", "api", "auth", "billing", "checks", "codespaces", "connector", "copilot", "deployments", "discussions", "fields", "gists", "git", "interactions", "issues", "marketplace", "meta", "migrations", "notifications", "orgs", "packages", "pages", "projects", "pulls", "releases", "repos", "scim", "search", "security", "ui", "users", "webhooks"];
|
|
5
|
+
export declare function githubCapabilities(): Promise<CapabilityReport>;
|