@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.
Files changed (215) hide show
  1. package/README.md +88 -36
  2. package/client/github-mirror.css +277 -319
  3. package/client/github-mirror.d.ts +418 -0
  4. package/client/github-mirror.js +485 -0
  5. package/client/github-mirror.tsx +153 -357
  6. package/client/pulls-rest.ts +159 -0
  7. package/client/pulls-workspace.tsx +841 -0
  8. package/dist/client/github-mirror.bundle.js +239 -0
  9. package/dist/client/github-mirror.css +916 -0
  10. package/dist/client/github-mirror.d.ts +418 -0
  11. package/dist/client/github-mirror.js +485 -0
  12. package/dist/client/github-mirror.tsx +1315 -0
  13. package/dist/client/pulls-rest.d.ts +42 -0
  14. package/dist/client/pulls-rest.js +140 -0
  15. package/dist/client/pulls-rest.ts +159 -0
  16. package/dist/client/pulls-workspace.bundle.js +22 -0
  17. package/dist/client/pulls-workspace.d.ts +114 -0
  18. package/dist/client/pulls-workspace.js +418 -0
  19. package/dist/client/pulls-workspace.tsx +841 -0
  20. package/dist/src/cli.d.ts +2 -0
  21. package/dist/src/cli.js +40 -0
  22. package/dist/src/generated/graphql-sdl.gen.json +1 -0
  23. package/dist/src/generated/graphql.gen.json +1 -0
  24. package/dist/src/generated/surface.gen.json +1 -0
  25. package/dist/src/generated/ui.gen.json +1 -0
  26. package/dist/src/github-budget.d.ts +69 -0
  27. package/dist/src/github-budget.js +172 -0
  28. package/dist/src/github-capabilities.d.ts +5 -0
  29. package/dist/src/github-capabilities.js +4468 -0
  30. package/dist/src/github-conformance.d.ts +43 -0
  31. package/dist/src/github-conformance.js +76 -0
  32. package/dist/src/github-connector.d.ts +307 -0
  33. package/dist/src/github-connector.js +1398 -0
  34. package/dist/src/github-events.d.ts +41 -0
  35. package/dist/src/github-events.js +232 -0
  36. package/dist/src/github-git-http.d.ts +49 -0
  37. package/dist/src/github-git-http.js +185 -0
  38. package/dist/src/github-git-plane.d.ts +114 -0
  39. package/dist/src/github-git-plane.js +407 -0
  40. package/dist/src/github-mirror-state.d.ts +2 -0
  41. package/dist/src/github-mirror-state.js +335 -0
  42. package/dist/src/github-mirror-ui.d.ts +20 -0
  43. package/dist/src/github-mirror-ui.js +101 -0
  44. package/dist/src/github-server.d.ts +14 -0
  45. package/dist/src/github-server.js +240 -0
  46. package/dist/src/github-shared.d.ts +12 -0
  47. package/dist/src/github-shared.js +21 -0
  48. package/dist/src/github-twin.d.ts +1411 -0
  49. package/dist/src/github-twin.js +4084 -0
  50. package/dist/src/github-ui-conformance.d.ts +4 -0
  51. package/dist/src/github-ui-conformance.js +105 -0
  52. package/dist/src/github-ui-structure.d.ts +18 -0
  53. package/dist/src/github-ui-structure.js +251 -0
  54. package/dist/src/graphql-wire.d.ts +22 -0
  55. package/dist/src/graphql-wire.js +89 -0
  56. package/dist/src/index.d.ts +17 -0
  57. package/dist/src/index.js +104 -0
  58. package/dist/src/manifest.d.ts +8 -0
  59. package/dist/src/manifest.js +597 -0
  60. package/dist/src/npm-registry.d.ts +7 -0
  61. package/dist/src/npm-registry.js +47 -0
  62. package/dist/src/screens/app-installation.d.ts +3 -0
  63. package/dist/src/screens/app-installation.js +166 -0
  64. package/dist/src/screens/app-manifest.d.ts +3 -0
  65. package/dist/src/screens/app-manifest.js +81 -0
  66. package/dist/src/screens/oauth.d.ts +15 -0
  67. package/dist/src/screens/oauth.js +257 -0
  68. package/dist/src/screens/session.d.ts +8 -0
  69. package/dist/src/screens/session.js +170 -0
  70. package/dist/src/semantics/actions.d.ts +2 -0
  71. package/dist/src/semantics/actions.js +413 -0
  72. package/dist/src/semantics/activity.d.ts +4 -0
  73. package/dist/src/semantics/activity.js +161 -0
  74. package/dist/src/semantics/apps.d.ts +2 -0
  75. package/dist/src/semantics/apps.js +144 -0
  76. package/dist/src/semantics/branches.d.ts +2 -0
  77. package/dist/src/semantics/branches.js +136 -0
  78. package/dist/src/semantics/checks.d.ts +2 -0
  79. package/dist/src/semantics/checks.js +176 -0
  80. package/dist/src/semantics/code-scanning-upload.d.ts +2 -0
  81. package/dist/src/semantics/code-scanning-upload.js +97 -0
  82. package/dist/src/semantics/codespaces.d.ts +2 -0
  83. package/dist/src/semantics/codespaces.js +58 -0
  84. package/dist/src/semantics/commits.d.ts +2 -0
  85. package/dist/src/semantics/commits.js +109 -0
  86. package/dist/src/semantics/contents.d.ts +2 -0
  87. package/dist/src/semantics/contents.js +131 -0
  88. package/dist/src/semantics/deployments.d.ts +2 -0
  89. package/dist/src/semantics/deployments.js +127 -0
  90. package/dist/src/semantics/gists.d.ts +2 -0
  91. package/dist/src/semantics/gists.js +86 -0
  92. package/dist/src/semantics/git.d.ts +2 -0
  93. package/dist/src/semantics/git.js +235 -0
  94. package/dist/src/semantics/graphql.d.ts +7 -0
  95. package/dist/src/semantics/graphql.js +512 -0
  96. package/dist/src/semantics/index.d.ts +5 -0
  97. package/dist/src/semantics/index.js +62 -0
  98. package/dist/src/semantics/issues.d.ts +2 -0
  99. package/dist/src/semantics/issues.js +456 -0
  100. package/dist/src/semantics/keys.d.ts +2 -0
  101. package/dist/src/semantics/keys.js +66 -0
  102. package/dist/src/semantics/labels.d.ts +2 -0
  103. package/dist/src/semantics/labels.js +100 -0
  104. package/dist/src/semantics/meta.d.ts +12 -0
  105. package/dist/src/semantics/meta.js +144 -0
  106. package/dist/src/semantics/notifications.d.ts +4 -0
  107. package/dist/src/semantics/notifications.js +62 -0
  108. package/dist/src/semantics/orgs.d.ts +2 -0
  109. package/dist/src/semantics/orgs.js +420 -0
  110. package/dist/src/semantics/packages.d.ts +2 -0
  111. package/dist/src/semantics/packages.js +55 -0
  112. package/dist/src/semantics/pages.d.ts +2 -0
  113. package/dist/src/semantics/pages.js +176 -0
  114. package/dist/src/semantics/projects.d.ts +2 -0
  115. package/dist/src/semantics/projects.js +239 -0
  116. package/dist/src/semantics/pulls.d.ts +2 -0
  117. package/dist/src/semantics/pulls.js +462 -0
  118. package/dist/src/semantics/push-reactions.d.ts +101 -0
  119. package/dist/src/semantics/push-reactions.js +513 -0
  120. package/dist/src/semantics/releases.d.ts +19 -0
  121. package/dist/src/semantics/releases.js +231 -0
  122. package/dist/src/semantics/repo-invitations.d.ts +2 -0
  123. package/dist/src/semantics/repo-invitations.js +98 -0
  124. package/dist/src/semantics/repos.d.ts +17 -0
  125. package/dist/src/semantics/repos.js +390 -0
  126. package/dist/src/semantics/rulesets.d.ts +2 -0
  127. package/dist/src/semantics/rulesets.js +111 -0
  128. package/dist/src/semantics/search.d.ts +2 -0
  129. package/dist/src/semantics/search.js +84 -0
  130. package/dist/src/semantics/security.d.ts +2 -0
  131. package/dist/src/semantics/security.js +177 -0
  132. package/dist/src/semantics/shared.d.ts +61 -0
  133. package/dist/src/semantics/shared.js +151 -0
  134. package/dist/src/semantics/users.d.ts +2 -0
  135. package/dist/src/semantics/users.js +255 -0
  136. package/dist/src/semantics/webhooks.d.ts +2 -0
  137. package/dist/src/semantics/webhooks.js +107 -0
  138. package/dist/test-fixtures/github-a11y-reference.pr-list.SOURCE.md +56 -0
  139. package/dist/test-fixtures/github-a11y-reference.pr-list.json +1447 -0
  140. package/dist/test-fixtures/github-comment-schema.SOURCE.md +11 -0
  141. package/dist/test-fixtures/github-comment-schema.json +702 -0
  142. package/dist/test-fixtures/github-known-deviations.json +94 -0
  143. package/dist/test-fixtures/github-openapi-operations.SOURCE.md +76 -0
  144. package/dist/test-fixtures/github-openapi-operations.json +362 -0
  145. package/dist/test-fixtures/github-pull-schema.SOURCE.md +37 -0
  146. package/dist/test-fixtures/github-pull-schema.json +3601 -0
  147. package/dist/test-fixtures/github-review-schema.SOURCE.md +12 -0
  148. package/dist/test-fixtures/github-review-schema.json +236 -0
  149. package/package.json +20 -11
  150. package/src/cli.ts +7 -6
  151. package/src/generated/graphql-sdl.gen.json +1 -0
  152. package/src/generated/graphql.gen.json +1 -0
  153. package/src/generated/surface.gen.json +1 -0
  154. package/src/generated/ui.gen.json +1 -0
  155. package/src/github-a11y-snapshot.uitest.ts +5 -5
  156. package/src/github-budget.ts +4 -4
  157. package/src/github-capabilities.ts +1993 -556
  158. package/src/github-conformance.ts +12 -7
  159. package/src/github-connector.ts +108 -96
  160. package/src/github-events.ts +225 -95
  161. package/src/github-git-http.ts +48 -84
  162. package/src/github-git-plane.ts +247 -385
  163. package/src/github-journey.uitest.ts +28 -44
  164. package/src/github-mirror-state.ts +23 -61
  165. package/src/github-mirror-ui.ts +16 -10
  166. package/src/github-server.ts +158 -60
  167. package/src/github-shared.ts +1 -1
  168. package/src/github-twin.ts +1525 -4494
  169. package/src/github-ui-conformance.ts +7 -8
  170. package/src/github-ui-structure.ts +19 -18
  171. package/src/graphql-wire.ts +115 -0
  172. package/src/index.ts +50 -7
  173. package/src/manifest.ts +605 -0
  174. package/src/npm-registry.ts +43 -0
  175. package/src/screens/app-installation.tsx +217 -0
  176. package/src/screens/app-manifest.tsx +97 -0
  177. package/src/screens/oauth.tsx +258 -0
  178. package/src/screens/session.tsx +193 -0
  179. package/src/semantics/actions.ts +395 -0
  180. package/src/semantics/activity.ts +171 -0
  181. package/src/semantics/apps.ts +133 -0
  182. package/src/semantics/branches.ts +133 -0
  183. package/src/semantics/checks.ts +163 -0
  184. package/src/semantics/code-scanning-upload.ts +92 -0
  185. package/src/semantics/codespaces.ts +58 -0
  186. package/src/semantics/commits.ts +109 -0
  187. package/src/semantics/contents.ts +112 -0
  188. package/src/semantics/deployments.ts +116 -0
  189. package/src/semantics/gists.ts +85 -0
  190. package/src/semantics/git.ts +226 -0
  191. package/src/semantics/graphql.ts +505 -0
  192. package/src/semantics/index.ts +68 -0
  193. package/src/semantics/issues.ts +434 -0
  194. package/src/semantics/keys.ts +66 -0
  195. package/src/semantics/labels.ts +91 -0
  196. package/src/semantics/meta.ts +139 -0
  197. package/src/semantics/notifications.ts +58 -0
  198. package/src/semantics/orgs.ts +383 -0
  199. package/src/semantics/packages.ts +59 -0
  200. package/src/semantics/pages.ts +154 -0
  201. package/src/semantics/projects.ts +246 -0
  202. package/src/semantics/pulls.ts +421 -0
  203. package/src/semantics/push-reactions.ts +471 -0
  204. package/src/semantics/releases.ts +213 -0
  205. package/src/semantics/repo-invitations.ts +112 -0
  206. package/src/semantics/repos.ts +373 -0
  207. package/src/semantics/rulesets.ts +107 -0
  208. package/src/semantics/search.ts +83 -0
  209. package/src/semantics/security.ts +153 -0
  210. package/src/semantics/shared.ts +181 -0
  211. package/src/semantics/users.ts +252 -0
  212. package/src/semantics/webhooks.ts +101 -0
  213. package/test-fixtures/github-known-deviations.json +7 -8
  214. package/test-fixtures/github-openapi-operations.json +46 -227
  215. package/src/github-graphql.ts +0 -398
@@ -0,0 +1,8 @@
1
+ import type { DerivedManifest } from '@volter/world-core';
2
+ /** Path parameters whose values GitHub lets hold slashes, which its OpenAPI description does not say:
3
+ * a git ref (`heads/feature/x`, https://docs.github.com/rest/git/refs#get-a-reference), a file path
4
+ * (https://docs.github.com/rest/repos/contents#get-repository-content), a release tag, a branch name
5
+ * (https://docs.github.com/rest/branches/branches#get-a-branch), a label name, and a compare range
6
+ * (`base...head` where either is a branch). The surface's `spanning` list (github-server.ts). */
7
+ export declare const spanning: string[];
8
+ export declare const manifest: DerivedManifest;
@@ -0,0 +1,597 @@
1
+ import { callerLogin, GITHUB_WORLD_USER } from "./github-twin.js";
2
+ /** Path parameters whose values GitHub lets hold slashes, which its OpenAPI description does not say:
3
+ * a git ref (`heads/feature/x`, https://docs.github.com/rest/git/refs#get-a-reference), a file path
4
+ * (https://docs.github.com/rest/repos/contents#get-repository-content), a release tag, a branch name
5
+ * (https://docs.github.com/rest/branches/branches#get-a-branch), a label name, and a compare range
6
+ * (`base...head` where either is a branch). The surface's `spanning` list (github-server.ts). */
7
+ export const spanning = ['ref', 'path', 'tag', 'branch', 'name', 'basehead'];
8
+ /** A resource that lives in a repository: named by `{owner}/{repo}` and stored with that value in its
9
+ * `repository` field. Its `key`, where one is declared, is the subject id the twin mints for it from the
10
+ * path (locally created subjects; an observed one keeps the id it was observed under). The core serves
11
+ * none of these operations: the repository itself is stored under a sequence id (`repo:<n>`), so the
12
+ * core's parent check, which looks the parent up by subject id, can never find `{owner}/{repo}`; and
13
+ * every stored shape is the twin's (githubState folds and renames), not the answer. Handlers serve them. */
14
+ // a repository is stored as repo:<n> with its owner and name, and addressed by both
15
+ const inRepository = { params: ['owner', 'repo'], value: '{owner}/{repo}', field: 'repository', resource: 'full-repository', where: { owner: '{owner}', name: '{repo}' } };
16
+ export const manifest = {
17
+ vendor: 'github',
18
+ service: 'github',
19
+ // GitHub reads a body as JSON whatever its content type says (curl's default is a form type)
20
+ body: { json: 'always' },
21
+ ids: { template: '{n}' },
22
+ time: 'iso',
23
+ error: { message: '{message}', documentation_url: 'https://docs.github.com/rest', status: '{statusText}' },
24
+ readOnly: { status: 403, message: 'twin is read-only (mirror mode); start in simulator/fork to write' },
25
+ notFound: { status: 404, message: 'Not Found' },
26
+ list: {
27
+ style: 'envelope',
28
+ envelope: '{data}',
29
+ limit: { param: 'per_page', default: 30, max: 100 },
30
+ page: { param: 'page', link: true },
31
+ },
32
+ deleted: null,
33
+ // a token minted at the twin's user door names its user; the World's shared token names no one
34
+ identity: (authorization, root) => callerLogin((authorization ?? '').replace(/^(?:bearer|token)\s+/i, '').trim() || undefined, root) ?? GITHUB_WORLD_USER,
35
+ // Operations on a declared resource the core must not claim: GitHub's stored subjects are the twin's
36
+ // own shape (a sequence id such as `sshkey:3`, fields folded by githubState), not the vendor's, so
37
+ // the core reproduces none of them; each is a handler, or unserved (the vendor's Not Found).
38
+ unmodeled: [
39
+ 'actions/delete-environment-variable',
40
+ 'actions/delete-workflow-run',
41
+ 'actions/disable-workflow',
42
+ 'actions/enable-workflow',
43
+ 'actions/get-environment-variable',
44
+ 'actions/get-workflow-run-attempt',
45
+ 'actions/list-environment-variables',
46
+ 'actions/list-jobs-for-workflow-run-attempt',
47
+ 'actions/list-repo-organization-secrets',
48
+ 'actions/list-repo-organization-variables',
49
+ 'actions/list-workflow-run-artifacts',
50
+ 'activity/mark-thread-as-done',
51
+ 'agents/delete-org-secret',
52
+ 'agents/delete-org-variable',
53
+ 'agents/delete-repo-secret',
54
+ 'agents/delete-repo-variable',
55
+ 'agents/get-org-secret',
56
+ 'agents/get-org-variable',
57
+ 'agents/get-repo-secret',
58
+ 'agents/get-repo-variable',
59
+ 'agents/list-org-secrets',
60
+ 'agents/list-org-variables',
61
+ 'agents/list-repo-organization-secrets',
62
+ 'agents/list-repo-organization-variables',
63
+ 'agents/list-repo-secrets',
64
+ 'agents/list-repo-variables',
65
+ 'apps/delete-installation',
66
+ 'apps/get-org-installation',
67
+ 'apps/get-repo-installation',
68
+ 'apps/get-user-installation',
69
+ 'apps/list-installations-for-authenticated-user',
70
+ 'codespaces/create-with-repo-for-authenticated-user',
71
+ 'codespaces/get-codespaces-for-user-in-org',
72
+ 'codespaces/list-in-organization',
73
+ 'codespaces/list-in-repository-for-authenticated-user',
74
+ 'codespaces/update-for-authenticated-user',
75
+ 'gists/list-for-user',
76
+ 'gists/list-forks',
77
+ 'gists/list-public',
78
+ 'gists/list-starred',
79
+ 'git/list-matching-refs',
80
+ 'issues/add-blocked-by-dependency',
81
+ 'issues/delete-milestone',
82
+ 'issues/get-parent',
83
+ 'issues/list',
84
+ 'issues/list-comments-for-repo',
85
+ 'issues/list-dependencies-blocked-by',
86
+ 'issues/list-dependencies-blocking',
87
+ 'issues/list-for-authenticated-user',
88
+ 'issues/list-for-org',
89
+ 'issues/list-labels-for-milestone',
90
+ 'issues/remove-dependency-blocked-by',
91
+ 'orgs/delete',
92
+ 'orgs/get-membership-for-authenticated-user',
93
+ 'orgs/list-app-installations',
94
+ 'orgs/list-invitation-teams',
95
+ 'orgs/list-memberships-for-authenticated-user',
96
+ 'orgs/update-membership-for-authenticated-user',
97
+ 'packages/delete-package-for-org',
98
+ 'packages/delete-package-for-user',
99
+ 'packages/delete-package-version-for-org',
100
+ 'packages/delete-package-version-for-user',
101
+ 'packages/get-all-package-versions-for-package-owned-by-org',
102
+ 'packages/get-all-package-versions-for-package-owned-by-user',
103
+ 'packages/get-package-for-organization',
104
+ 'packages/get-package-for-user',
105
+ 'packages/get-package-version-for-organization',
106
+ 'packages/get-package-version-for-user',
107
+ 'packages/list-docker-migration-conflicting-packages-for-authenticated-user',
108
+ 'packages/list-docker-migration-conflicting-packages-for-organization',
109
+ 'packages/list-docker-migration-conflicting-packages-for-user',
110
+ 'packages/list-packages-for-organization',
111
+ 'packages/list-packages-for-user',
112
+ 'projects/add-field-for-org',
113
+ 'projects/add-field-for-user',
114
+ 'projects/delete-item-for-org',
115
+ 'projects/delete-item-for-user',
116
+ 'projects/get-field-for-org',
117
+ 'projects/get-field-for-user',
118
+ 'projects/get-for-user',
119
+ 'projects/get-org-item',
120
+ 'projects/get-user-item',
121
+ 'projects/list-fields-for-org',
122
+ 'projects/list-fields-for-user',
123
+ 'projects/list-for-user',
124
+ 'projects/list-items-for-org',
125
+ 'projects/list-items-for-user',
126
+ 'projects/list-view-items-for-org',
127
+ 'projects/list-view-items-for-user',
128
+ 'projects/update-item-for-org',
129
+ 'projects/update-item-for-user',
130
+ 'pulls/delete-pending-review',
131
+ 'pulls/list-review-comments-for-repo',
132
+ 'reactions/create-for-commit-comment',
133
+ 'reactions/create-for-release',
134
+ 'reactions/list-for-commit-comment',
135
+ 'reactions/list-for-release',
136
+ 'repos/add-team-access-restrictions',
137
+ 'repos/create-org-ruleset',
138
+ 'repos/delete-deployment',
139
+ 'repos/delete-org-ruleset',
140
+ 'repos/delete-release-asset',
141
+ 'repos/get-access-restrictions',
142
+ 'repos/get-org-rule-suite',
143
+ 'repos/get-org-ruleset',
144
+ 'repos/get-org-rulesets',
145
+ 'repos/get-teams-with-access-to-protected-branch',
146
+ 'repos/list-issue-types',
147
+ 'repos/list-teams',
148
+ 'repos/update-org-ruleset',
149
+ 'repos/update-release-asset',
150
+ 'teams/check-permissions-for-repo-legacy',
151
+ 'teams/delete-legacy',
152
+ 'teams/get-legacy',
153
+ 'teams/list-child-in-org',
154
+ 'teams/list-child-legacy',
155
+ 'teams/list-for-authenticated-user',
156
+ 'teams/remove-repo-legacy',
157
+ 'teams/update-legacy',
158
+ 'users/list-gpg-keys-for-user',
159
+ ],
160
+ // Every declared resource's served operations are handlers (semantics/); the declarations name the
161
+ // stored type and rule on the spec's state candidates.
162
+ // The screens applications and people reach (docs/contributing/architecture.md, "Screens"). Demand is the
163
+ // ladder's 85 applications: the code that sends a user to the page.
164
+ screens: [
165
+ {
166
+ id: 'sign-in', kind: 'flow', host: 'github.com', path: '/login', status: 'done',
167
+ demand: 'every github.com page a person reaches: each asks who is signed in', controls: ['Username or email address', 'Password', 'Sign in'],
168
+ source: 'https://docs.github.com/authentication/keeping-your-account-and-data-secure/about-authentication-to-github',
169
+ },
170
+ {
171
+ id: 'two-factor', kind: 'flow', host: 'github.com', path: '/sessions/two-factor/app', status: 'done',
172
+ demand: 'every person with two-factor authentication signing in, as GitHub requires of contributors', controls: ['Authentication code', 'Verify'],
173
+ source: 'https://docs.github.com/authentication/securing-your-account-with-two-factor-authentication-2fa/accessing-github-using-two-factor-authentication',
174
+ },
175
+ {
176
+ id: 'oauth-consent', kind: 'flow', host: 'github.com', path: '/login/oauth/authorize', status: 'done',
177
+ demand: '35 of 85 applications sign users in with GitHub', controls: ['Authorize {login}', 'Cancel'],
178
+ source: 'https://docs.github.com/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps',
179
+ },
180
+ {
181
+ id: 'app-installation', kind: 'flow', host: 'github.com', path: '/apps/{slug}/installations/new', status: 'done',
182
+ demand: '10 of 85 applications send an owner to install their GitHub App', controls: ['Install', 'Install & Authorize', 'Cancel', 'All repositories', 'Only select repositories', 'Switch account'],
183
+ source: 'https://docs.github.com/apps/using-github-apps/installing-a-github-app-from-a-third-party',
184
+ },
185
+ {
186
+ id: 'pull-requests', kind: 'workspace', host: 'github.com', path: '/{owner}/{repo}/pulls', status: 'done',
187
+ demand: 'testers and agents review pull requests', source: 'https://docs.github.com/pull-requests',
188
+ },
189
+ ],
190
+ resources: {
191
+ // users and keys (semantics/users.ts)
192
+ email: { storedAs: 'user_email', idPrefix: 'useremail:' },
193
+ key: { storedAs: 'user_ssh_key', idPrefix: 'sshkey:' },
194
+ 'gpg-key': { storedAs: 'user_gpg_key', idPrefix: 'gpgkey:' },
195
+ // gists (semantics/gists.ts): one stored gist answers both the full and the listed shape
196
+ 'gist-simple': { storedAs: 'gist', idPrefix: 'gist:' },
197
+ 'base-gist': { storedAs: 'gist', idPrefix: 'gist:' },
198
+ // notification threads (semantics/activity.ts)
199
+ thread: { storedAs: 'notification', idPrefix: 'notification:' },
200
+ // organizations and teams (semantics/orgs.ts)
201
+ // is_verified: GitHub verifies an organization's domain; no API moves it
202
+ 'organization-full': { storedAs: 'organization', idPrefix: 'org:', notState: ['is_verified'] },
203
+ 'org-membership': {
204
+ storedAs: 'org_membership',
205
+ idPrefix: 'orgmember:',
206
+ notState: ['role'],
207
+ state: {
208
+ // the twin confirms a membership as it sets it (no invitation to accept offline); GitHub starts
209
+ // one pending until the member accepts
210
+ state: { initial: 'active', vendorInitial: 'pending', transitions: [{ operation: 'orgs/update-membership-for-authenticated-user', from: ['pending'], to: 'active', source: 'https://docs.github.com/rest/orgs/members#update-an-organization-membership-for-the-authenticated-user' }] },
211
+ },
212
+ },
213
+ // active: a setting an edit names
214
+ 'org-hook': { storedAs: 'org_webhook', idPrefix: 'orghook:', notState: ['active'] },
215
+ 'issue-type': { storedAs: 'issue_type', idPrefix: 'issuetype:', notState: ['color', 'is_enabled'] },
216
+ 'team-full': { storedAs: 'team', idPrefix: 'team:', notState: ['notification_setting', 'privacy', 'type'] },
217
+ team: { storedAs: 'team', idPrefix: 'team:', notState: ['access_source', 'type'] },
218
+ // archived, disabled, is_template: the repository's own, ruled on full-repository
219
+ 'team-repository': { storedAs: 'team_repo', idPrefix: 'teamrepo:', notState: ['archived', 'disabled', 'is_template'], key: 'teamrepo:{org}#{team_slug}#{owner}/{repo}' },
220
+ // Projects v2 (semantics/projects.ts): GitHub moves a project's state by GraphQL's
221
+ // updateProjectV2 (closed), no REST operation: another wire's move (`external`); the twin stores
222
+ // it as `closed`. is_template: a setting (markProjectV2AsTemplate).
223
+ 'projects-v2': {
224
+ storedAs: 'project',
225
+ idPrefix: 'project:',
226
+ notState: ['is_template'],
227
+ state: {
228
+ state: {
229
+ initial: 'open',
230
+ transitions: [
231
+ { actor: 'external', from: ['open'], to: 'closed', source: 'https://docs.github.com/graphql/reference/mutations#updateprojectv2' },
232
+ { actor: 'external', from: ['closed'], to: 'open', source: 'https://docs.github.com/graphql/reference/mutations#updateprojectv2' },
233
+ ],
234
+ },
235
+ },
236
+ },
237
+ 'projects-v2-field': { storedAs: 'project_field', idPrefix: 'projectfield:', notState: ['data_type'] },
238
+ 'projects-v2-item-with-content': { storedAs: 'project_item', idPrefix: 'projectitem:', notState: ['content_type'] },
239
+ // security alerts (semantics/security.ts): the twin accepts any requested state on an update, as
240
+ // it always has; GitHub's documented moves are the machines
241
+ 'code-scanning-alert-items': {
242
+ storedAs: 'code_scanning_alert',
243
+ idPrefix: 'csalert:',
244
+ parent: inRepository,
245
+ key: 'csalert:{owner}/{repo}#{alert_number}',
246
+ notState: ['dismissed_reason'],
247
+ state: {
248
+ state: {
249
+ initial: 'open',
250
+ transitions: [
251
+ { operation: 'code-scanning/update-alert', from: '*', to: 'dismissed', source: 'https://docs.github.com/rest/code-scanning/code-scanning#update-a-code-scanning-alert' },
252
+ { operation: 'code-scanning/update-alert', from: '*', to: 'open', source: 'https://docs.github.com/rest/code-scanning/code-scanning#update-a-code-scanning-alert' },
253
+ // an analysis that no longer finds it fixes it (semantics/code-scanning-upload.ts)
254
+ { actor: 'vendor', from: ['open'], to: 'fixed', source: 'https://docs.github.com/code-security/code-scanning/managing-code-scanning-alerts/about-code-scanning-alerts#about-alert-details' },
255
+ ],
256
+ },
257
+ },
258
+ },
259
+ 'code-scanning-analysis': { storedAs: 'code_scanning_analysis', idPrefix: 'csanalysis:', parent: inRepository, key: 'csanalysis:{analysis_id}' },
260
+ 'dependabot-alert': {
261
+ storedAs: 'dependabot_alert',
262
+ idPrefix: 'dependabot:',
263
+ parent: inRepository,
264
+ key: 'dependabot:{owner}/{repo}#{alert_number}',
265
+ notState: ['dismissed_reason'],
266
+ state: {
267
+ state: {
268
+ initial: 'open',
269
+ transitions: [
270
+ { operation: 'dependabot/update-alert', from: '*', to: 'dismissed', source: 'https://docs.github.com/rest/dependabot/alerts#update-a-dependabot-alert' },
271
+ { operation: 'dependabot/update-alert', from: '*', to: 'open', source: 'https://docs.github.com/rest/dependabot/alerts#update-a-dependabot-alert' },
272
+ // a push whose manifest no longer asks for a vulnerable version fixes it (semantics/push-reactions.ts)
273
+ { actor: 'vendor', from: ['open'], to: 'fixed', source: 'https://docs.github.com/code-security/dependabot/dependabot-alerts/about-dependabot-alerts' },
274
+ ],
275
+ },
276
+ },
277
+ },
278
+ 'secret-scanning-alert': {
279
+ storedAs: 'secret_scanning_alert',
280
+ idPrefix: 'secretscan:',
281
+ parent: inRepository,
282
+ key: 'secretscan:{owner}/{repo}#{alert_number}',
283
+ notState: ['resolution', 'validity'],
284
+ state: {
285
+ state: {
286
+ initial: 'open',
287
+ transitions: [
288
+ { operation: 'secret-scanning/update-alert', from: '*', to: 'resolved', source: 'https://docs.github.com/rest/secret-scanning/secret-scanning#update-a-secret-scanning-alert' },
289
+ { operation: 'secret-scanning/update-alert', from: '*', to: 'open', source: 'https://docs.github.com/rest/secret-scanning/secret-scanning#update-a-secret-scanning-alert' },
290
+ ],
291
+ },
292
+ },
293
+ },
294
+ // Pages builds (semantics/pages.ts): GitHub queues a requested build and builds it (queued → building →
295
+ // built or errored, docs.github.com/rest/pages/pages#request-a-github-pages-build); the twin records it built
296
+ // as it is requested (nothing builds offline), so it makes none of those moves
297
+ 'page-build': {
298
+ storedAs: 'pages_build',
299
+ idPrefix: 'pagesbuild:',
300
+ parent: inRepository,
301
+ key: 'pagesbuild:{build_id}',
302
+ state: { status: { initial: 'built', vendorInitial: 'queued', transitions: [] } },
303
+ },
304
+ // packages (semantics/packages.ts)
305
+ package: { storedAs: 'package', idPrefix: 'package:', notState: ['package_type', 'visibility'] },
306
+ 'package-version': { storedAs: 'package_version', idPrefix: 'packageversion:' },
307
+ // app installations (semantics/apps.ts)
308
+ installation: { storedAs: 'app_installation', idPrefix: 'installation:', notState: ['repository_selection'] },
309
+ // Actions (semantics/actions.ts): no runner executes anything; runs move only by rerun, cancel
310
+ // and the twin's runner door, from any state, as the twin always has
311
+ workflow: {
312
+ storedAs: 'workflow',
313
+ idPrefix: 'workflow:',
314
+ parent: inRepository,
315
+ state: {
316
+ state: {
317
+ initial: 'active',
318
+ transitions: [
319
+ { operation: 'actions/disable-workflow', from: ['active'], to: 'disabled_manually', source: 'https://docs.github.com/rest/actions/workflows#disable-a-workflow' },
320
+ { operation: 'actions/enable-workflow', from: ['disabled_manually', 'disabled_inactivity', 'disabled_fork'], to: 'active', source: 'https://docs.github.com/rest/actions/workflows#enable-a-workflow' },
321
+ ],
322
+ },
323
+ },
324
+ },
325
+ 'workflow-run': {
326
+ storedAs: 'workflow_run',
327
+ idPrefix: 'run:',
328
+ parent: inRepository,
329
+ key: 'run:{run_id}',
330
+ // the result a completed run records, not a state of its own
331
+ notState: ['conclusion'],
332
+ state: {
333
+ // a runner finishing it is the vendor's move (the twin's runner door, /_twin/.../complete)
334
+ status: {
335
+ initial: 'queued',
336
+ transitions: [
337
+ { operation: 'actions/re-run-workflow', from: '*', to: 'queued', source: 'https://docs.github.com/rest/actions/workflow-runs#re-run-a-workflow' },
338
+ { operation: 'actions/cancel-workflow-run', from: '*', to: 'completed', source: 'https://docs.github.com/rest/actions/workflow-runs#cancel-a-workflow-run' },
339
+ // a first-time contributor's run from a fork waits, completed as action_required, until a maintainer approves it
340
+ { operation: 'actions/approve-workflow-run', from: ['completed'], to: 'queued', source: 'https://docs.github.com/rest/actions/workflow-runs#approve-a-workflow-run-for-a-fork-pull-request' },
341
+ // a runner picking it up (the twin's runner door, /_twin/.../start)
342
+ { actor: 'vendor', from: ['queued'], to: 'in_progress', refusal: { status: 409, message: 'The run has already started' }, source: 'https://docs.github.com/actions/about-github-actions/understanding-github-actions#runners' },
343
+ { actor: 'vendor', from: ['queued', 'in_progress'], to: 'completed', refusal: { status: 409, message: 'The run has already completed' }, source: 'https://docs.github.com/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/re-running-workflows-and-jobs' },
344
+ ],
345
+ },
346
+ },
347
+ },
348
+ job: {
349
+ storedAs: 'workflow_job',
350
+ idPrefix: 'job:',
351
+ parent: inRepository,
352
+ key: 'job:{job_id}',
353
+ // the result a completed job records, not a state of its own
354
+ notState: ['conclusion'],
355
+ state: {
356
+ // a job moves with its run: by the run's rerun and cancel, and when the runner finishes the run
357
+ status: {
358
+ initial: 'queued',
359
+ transitions: [
360
+ { operation: 'actions/re-run-workflow', from: '*', to: 'queued', source: 'https://docs.github.com/rest/actions/workflow-runs#re-run-a-workflow' },
361
+ { operation: 'actions/cancel-workflow-run', from: '*', to: 'completed', source: 'https://docs.github.com/rest/actions/workflow-runs#cancel-a-workflow-run' },
362
+ { actor: 'vendor', from: ['queued'], to: 'in_progress', source: 'https://docs.github.com/rest/actions/workflow-jobs#get-a-job-for-a-workflow-run' },
363
+ { actor: 'vendor', from: ['queued', 'in_progress'], to: 'completed', source: 'https://docs.github.com/rest/actions/workflow-jobs#get-a-job-for-a-workflow-run' },
364
+ ],
365
+ },
366
+ },
367
+ },
368
+ artifact: { storedAs: 'actions_artifact', idPrefix: 'artifact:', parent: inRepository, key: 'artifact:{artifact_id}' },
369
+ // a secret or variable is stored under its `container` (a repository, `owner/repo:env` for an
370
+ // environment's): one resource spans both, so no parent field names the repository alone
371
+ 'actions-secret': { storedAs: 'actions_secret', idPrefix: 'secret:repo:' },
372
+ 'actions-variable': { storedAs: 'actions_variable', idPrefix: 'variable:repo:' },
373
+ 'organization-actions-secret': { storedAs: 'actions_secret', idPrefix: 'secret:org:', notState: ['visibility'] },
374
+ 'organization-actions-variable': { storedAs: 'actions_variable', idPrefix: 'variable:org:', notState: ['visibility'] },
375
+ // deploy keys and autolinks (semantics/keys.ts)
376
+ 'deploy-key': { storedAs: 'deploy_key', idPrefix: 'deploykey:', parent: inRepository, key: 'deploykey:{key_id}' },
377
+ // is_alphanumeric: how the prefix matches, set at creation
378
+ autolink: { storedAs: 'autolink', idPrefix: 'autolink:', parent: inRepository, key: 'autolink:{autolink_id}', notState: ['is_alphanumeric'] },
379
+ // rulesets and rule suites (semantics/rulesets.ts): enforcement is a setting an update names, any
380
+ // value from any value; a suite's results are the outcome it recorded
381
+ 'repository-ruleset': { storedAs: 'ruleset', idPrefix: 'ruleset:', parent: inRepository, key: 'ruleset:{ruleset_id}', notState: ['current_user_can_bypass', 'enforcement', 'source_type', 'target'] },
382
+ 'rule-suite': { storedAs: 'rule_suite', idPrefix: 'rulesuite:', parent: inRepository, key: 'rulesuite:{rule_suite_id}', notState: ['evaluation_result', 'result'] },
383
+ // deployments and environments (semantics/deployments.ts): a status is created with its state and
384
+ // never moves (the deployment's state is its latest status)
385
+ deployment: { storedAs: 'deployment', idPrefix: 'deployment:', parent: inRepository, key: 'deployment:{deployment_id}' },
386
+ 'deployment-status': { storedAs: 'deployment_status', idPrefix: 'depstatus:', parent: inRepository, key: 'depstatus:{status_id}', notState: ['state'] },
387
+ environment: { storedAs: 'environment', idPrefix: 'env:', parent: inRepository, key: 'env:{owner}/{repo}#{environment_name}' },
388
+ // releases (semantics/releases.ts); tags are derived from published releases, never stored
389
+ // a release is created a draft or published; an edit publishes a draft (`draft: false`) or unpublishes
390
+ // it (`draft: true`), from either value as the twin always took it
391
+ release: {
392
+ storedAs: 'release',
393
+ idPrefix: 'release:',
394
+ parent: inRepository,
395
+ key: 'release:{release_id}',
396
+ state: {
397
+ draft: {
398
+ initial: false,
399
+ transitions: [
400
+ { operation: 'repos/update-release', from: '*', to: 'false', source: 'https://docs.github.com/rest/releases/releases#update-a-release' },
401
+ { operation: 'repos/update-release', from: '*', to: 'true', source: 'https://docs.github.com/rest/releases/releases#update-a-release' },
402
+ ],
403
+ },
404
+ },
405
+ },
406
+ 'release-asset': {
407
+ storedAs: 'release_asset',
408
+ idPrefix: 'asset:',
409
+ parent: inRepository,
410
+ key: 'asset:{asset_id}',
411
+ state: {
412
+ // the upload completing moves it open → uploaded on GitHub (docs.github.com/rest/releases/assets#upload-a-release-asset);
413
+ // the twin records an asset already uploaded, so it makes no move
414
+ state: { initial: 'uploaded', vendorInitial: 'open', transitions: [] },
415
+ },
416
+ },
417
+ // repository webhooks (semantics/webhooks.ts)
418
+ // active: a setting an edit names
419
+ hook: { storedAs: 'webhook', idPrefix: 'webhook:', parent: inRepository, key: 'webhook:{hook_id}', notState: ['active'] },
420
+ // labels and milestones (semantics/labels.ts): a milestone's state is set by an edit, any value
421
+ // from any value, as the twin always took it
422
+ label: { storedAs: 'label', idPrefix: 'label:', parent: inRepository },
423
+ milestone: {
424
+ storedAs: 'milestone',
425
+ idPrefix: 'milestone:',
426
+ parent: inRepository,
427
+ key: '{owner}/{repo}#milestone:{milestone_number}', number: { field: 'number' },
428
+ state: {
429
+ state: {
430
+ initial: 'open',
431
+ transitions: [
432
+ { operation: 'issues/update-milestone', from: '*', to: 'closed', source: 'https://docs.github.com/rest/issues/milestones#update-a-milestone' },
433
+ { operation: 'issues/update-milestone', from: '*', to: 'open', source: 'https://docs.github.com/rest/issues/milestones#update-a-milestone' },
434
+ ],
435
+ },
436
+ },
437
+ },
438
+ // commit comments (semantics/commits.ts); commits are the git plane's, never stored
439
+ 'commit-comment': { storedAs: 'commit_comment', idPrefix: 'commitcomment:', parent: inRepository, key: 'commitcomment:{comment_id}', notState: ['author_association'] },
440
+ // statuses and check runs (semantics/checks.ts): a caller moves a run to whatever status it posts,
441
+ // and a conclusion completes it; suites are derived from runs, never stored
442
+ // a status is created with its state and never moves (a commit's state is its latest per context)
443
+ status: { storedAs: 'commit_status', idPrefix: 'status:', parent: inRepository, notState: ['state'] },
444
+ 'check-run': {
445
+ storedAs: 'check_run',
446
+ idPrefix: 'check:',
447
+ parent: inRepository,
448
+ key: 'check:{check_run_id}',
449
+ notState: ['conclusion'],
450
+ state: {
451
+ status: {
452
+ initial: 'queued',
453
+ transitions: [
454
+ { operation: 'checks/update', from: '*', to: 'in_progress', source: 'https://docs.github.com/rest/checks/runs#update-a-check-run' },
455
+ { operation: 'checks/update', from: '*', to: 'completed', source: 'https://docs.github.com/rest/checks/runs#update-a-check-run' },
456
+ ],
457
+ },
458
+ },
459
+ },
460
+ // Git Data (semantics/git.ts): refs are rows; blobs, trees, commits and tags are objects in the git
461
+ // plane the surface names no resource for
462
+ 'git-ref': { storedAs: 'git_ref', idPrefix: 'gitref:', parent: inRepository, key: 'gitref:{owner}/{repo}#refs/{ref}' },
463
+ // repositories, branches and collaborators (semantics/repos.ts, semantics/branches.ts): a
464
+ // repository's merge and squash settings are settings an edit names, not states. An edit archives
465
+ // a repository and unarchives it; GitHub disables one on its own (no API moves `disabled`, and the
466
+ // twin never does); is_template is a setting.
467
+ 'full-repository': {
468
+ storedAs: 'repository',
469
+ idPrefix: 'repo:',
470
+ notState: ['disabled', 'is_template', 'merge_commit_message', 'merge_commit_title', 'pull_request_creation_policy', 'squash_merge_commit_message', 'squash_merge_commit_title'],
471
+ state: {
472
+ archived: {
473
+ initial: false,
474
+ transitions: [
475
+ { operation: 'repos/update', from: '*', to: 'true', source: 'https://docs.github.com/rest/repos/repos#update-a-repository' },
476
+ { operation: 'repos/update', from: '*', to: 'false', source: 'https://docs.github.com/rest/repos/repos#update-a-repository' },
477
+ ],
478
+ },
479
+ },
480
+ },
481
+ 'short-branch': { storedAs: 'branch', idPrefix: 'branch:', parent: inRepository, key: 'branch:{owner}/{repo}#{branch}' },
482
+ collaborator: { storedAs: 'collaborator', idPrefix: 'collab:', parent: inRepository, key: 'collab:{owner}/{repo}#{username}' },
483
+ // issues, their comments and reactions (semantics/issues.ts). An issue is keyed by its repository
484
+ // and number; its number is counted with the repository's pull requests (one sequence for both), so
485
+ // `number` cannot declare it. Its state moves by an edit from any value (closing defaults
486
+ // state_reason to completed, reopening to reopened).
487
+ issue: {
488
+ storedAs: 'issue',
489
+ idPrefix: 'issue:',
490
+ parent: inRepository,
491
+ key: '{owner}/{repo}#issue:{issue_number}',
492
+ // draft: a pull request's, which an issue answer carries for a pull request's number
493
+ notState: ['author_association', 'draft', 'state_reason'],
494
+ state: {
495
+ state: {
496
+ initial: 'open',
497
+ transitions: [
498
+ { operation: 'issues/update', from: '*', to: 'closed', source: 'https://docs.github.com/rest/issues/issues#update-an-issue' },
499
+ { operation: 'issues/update', from: '*', to: 'open', source: 'https://docs.github.com/rest/issues/issues#update-an-issue' },
500
+ // a pull request merged into the default branch closes the issues it links with a closing keyword, and so
501
+ // does a commit pushed there that names them (semantics/pulls.ts, semantics/push-reactions.ts)
502
+ { operation: 'pulls/merge', from: ['open'], to: 'closed', source: 'https://docs.github.com/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue' },
503
+ { actor: 'external', from: ['open'], to: 'closed', source: 'https://docs.github.com/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue' },
504
+ ],
505
+ },
506
+ // locking a locked conversation (or unlocking an unlocked one) is answered 204 as any other
507
+ locked: {
508
+ initial: false,
509
+ transitions: [
510
+ { operation: 'issues/lock', from: '*', to: 'true', source: 'https://docs.github.com/rest/issues/issues#lock-an-issue' },
511
+ { operation: 'issues/unlock', from: '*', to: 'false', source: 'https://docs.github.com/rest/issues/issues#unlock-an-issue' },
512
+ ],
513
+ },
514
+ },
515
+ },
516
+ 'issue-comment': { storedAs: 'issue_comment', idPrefix: 'comment:', parent: inRepository, key: 'comment:{comment_id}', notState: ['author_association'] },
517
+ reaction: { storedAs: 'reaction', idPrefix: 'reaction:', parent: inRepository, key: 'reaction:{reaction_id}', notState: ['content'] },
518
+ 'pull-request-review-comment': { storedAs: 'pull_request_review_comment', idPrefix: 'comment:', parent: inRepository, key: 'comment:{comment_id}', notState: ['author_association', 'side', 'start_side', 'subject_type'] },
519
+ // pull requests and reviews (semantics/pulls.ts): one machine per state field. A merge needs an open,
520
+ // unmerged, non-draft pull request (the handler asks ctx.legal of all three); an edit moves state
521
+ // from any value. Deleting the head branch closes it (git/delete-ref, on the pull request's machine).
522
+ // GitHub's auto-merge (GraphQL's enablePullRequestAutoMerge) lands one when its checks pass; the twin does
523
+ // not have it, so makes no such move. Draft moves by GraphQL alone
524
+ // (markPullRequestReadyForReview, convertPullRequestToDraft: another wire, `external`), which also
525
+ // needs it open (a merged one is closed). The conversation locks by the issue operations on its number.
526
+ 'pull-request': {
527
+ storedAs: 'pull_request',
528
+ idPrefix: 'pr:',
529
+ parent: inRepository,
530
+ key: '{owner}/{repo}#{pull_number}',
531
+ notState: ['author_association'],
532
+ state: {
533
+ state: {
534
+ initial: 'open',
535
+ transitions: [
536
+ { operation: 'pulls/update', from: '*', to: 'closed', source: 'https://docs.github.com/rest/pulls/pulls#update-a-pull-request' },
537
+ { operation: 'pulls/update', from: '*', to: 'open', source: 'https://docs.github.com/rest/pulls/pulls#update-a-pull-request' },
538
+ { operation: 'pulls/merge', from: ['open'], to: 'closed', refusal: { status: 405, message: 'Pull Request is not mergeable' }, source: 'https://docs.github.com/rest/pulls/pulls#merge-a-pull-request' },
539
+ { operation: 'git/delete-ref', from: ['open'], to: 'closed', source: 'https://docs.github.com/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-and-deleting-branches-within-your-repository#deleting-a-branch-used-for-a-pull-request' },
540
+ { actor: 'external', from: ['open'], refusal: { status: 422, message: 'Pull request must be open' }, source: 'https://docs.github.com/graphql/reference/mutations#markpullrequestreadyforreview' },
541
+ // deleting the head branch by a git push closes it too, the git wire's (github-git-http.ts); after the
542
+ // guard, so an ask that names no state finds the guard
543
+ { actor: 'external', from: ['open'], to: 'closed', source: 'https://docs.github.com/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-and-deleting-branches-within-your-repository#deleting-a-branch-used-for-a-pull-request' },
544
+ ],
545
+ },
546
+ merged: {
547
+ initial: false,
548
+ transitions: [
549
+ { operation: 'pulls/merge', from: ['false'], to: 'true', refusal: { status: 405, message: 'Pull Request is not mergeable' }, source: 'https://docs.github.com/rest/pulls/pulls#merge-a-pull-request' },
550
+ ],
551
+ },
552
+ // a guard: a draft is never merged
553
+ draft: {
554
+ initial: false,
555
+ transitions: [
556
+ { operation: 'pulls/merge', from: ['false'], refusal: { status: 405, message: 'Draft pull requests cannot be merged.' }, source: 'https://docs.github.com/rest/pulls/pulls#merge-a-pull-request' },
557
+ { actor: 'external', from: ['true'], to: 'false', refusal: { status: 422, message: 'Pull request is already ready for review' }, source: 'https://docs.github.com/graphql/reference/mutations#markpullrequestreadyforreview' },
558
+ { actor: 'external', from: ['false'], to: 'true', refusal: { status: 422, message: 'Pull request is already a draft' }, source: 'https://docs.github.com/graphql/reference/mutations#convertpullrequesttodraft' },
559
+ ],
560
+ },
561
+ locked: {
562
+ initial: false,
563
+ transitions: [
564
+ { operation: 'issues/lock', from: '*', to: 'true', source: 'https://docs.github.com/rest/issues/issues#lock-an-issue' },
565
+ { operation: 'issues/unlock', from: '*', to: 'false', source: 'https://docs.github.com/rest/issues/issues#unlock-an-issue' },
566
+ ],
567
+ },
568
+ },
569
+ },
570
+ 'pull-request-review': {
571
+ storedAs: 'pull_request_review',
572
+ idPrefix: 'review:',
573
+ parent: inRepository,
574
+ key: 'review:{review_id}',
575
+ notState: ['author_association'],
576
+ state: {
577
+ // set by the submitting event (APPROVE → APPROVED …); a dismissal overlays DISMISSED
578
+ state: { initial: 'COMMENTED', transitions: [{ operation: 'pulls/dismiss-review', from: '*', to: 'DISMISSED', source: 'https://docs.github.com/rest/pulls/reviews#dismiss-a-review-for-a-pull-request' }] },
579
+ },
580
+ },
581
+ // codespaces (semantics/codespaces.ts): start and stop move from any state, as the twin always has
582
+ codespace: {
583
+ storedAs: 'codespace',
584
+ idPrefix: 'codespace:',
585
+ notState: ['location'],
586
+ state: {
587
+ state: {
588
+ initial: 'Available',
589
+ transitions: [
590
+ { operation: 'codespaces/start-for-authenticated-user', from: '*', to: 'Available', source: 'https://docs.github.com/rest/codespaces/codespaces#start-a-codespace-for-the-authenticated-user' },
591
+ { operation: 'codespaces/stop-for-authenticated-user', from: '*', to: 'Shutdown', source: 'https://docs.github.com/rest/codespaces/codespaces#stop-a-codespace-for-the-authenticated-user' },
592
+ ],
593
+ },
594
+ },
595
+ },
596
+ },
597
+ };
@@ -0,0 +1,7 @@
1
+ type Flow = {
2
+ root?: string;
3
+ now: () => string;
4
+ };
5
+ /** npm.pkg.github.com's publish, or undefined for any other request. */
6
+ export declare function githubNpmRegistry(flow: Flow): (request: Request) => Promise<Response | undefined>;
7
+ export {};