@bevel-software/platform-core-backend 0.12.1 → 0.13.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 (158) hide show
  1. package/THIRD-PARTY-NOTICES.md +5 -3
  2. package/dist/core/create-core-server.d.ts.map +1 -1
  3. package/dist/core/create-core-server.js +8 -1
  4. package/dist/core/create-core-server.js.map +1 -1
  5. package/dist/core/create-core-services.d.ts.map +1 -1
  6. package/dist/core/create-core-services.js.map +1 -1
  7. package/dist/modules/access/access-control.service.d.ts +58 -2
  8. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  9. package/dist/modules/access/access-control.service.js +174 -33
  10. package/dist/modules/access/access-control.service.js.map +1 -1
  11. package/dist/modules/access/admin-locked-commit.d.ts.map +1 -1
  12. package/dist/modules/access/admin-locked-commit.js +1 -0
  13. package/dist/modules/access/admin-locked-commit.js.map +1 -1
  14. package/dist/modules/access/synced-groups-committer.js +1 -1
  15. package/dist/modules/access/synced-groups-committer.js.map +1 -1
  16. package/dist/modules/access-model/access-errors.d.ts +11 -0
  17. package/dist/modules/access-model/access-errors.d.ts.map +1 -1
  18. package/dist/modules/access-model/access-errors.js +14 -0
  19. package/dist/modules/access-model/access-errors.js.map +1 -1
  20. package/dist/modules/access-model/access-grammar.d.ts +24 -8
  21. package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
  22. package/dist/modules/access-model/access-grammar.js +64 -3
  23. package/dist/modules/access-model/access-grammar.js.map +1 -1
  24. package/dist/modules/declared-variables/declared-variables.routes.d.ts +42 -0
  25. package/dist/modules/declared-variables/declared-variables.routes.d.ts.map +1 -0
  26. package/dist/modules/declared-variables/declared-variables.routes.js +135 -0
  27. package/dist/modules/declared-variables/declared-variables.routes.js.map +1 -0
  28. package/dist/modules/declared-variables/index.d.ts +2 -0
  29. package/dist/modules/declared-variables/index.d.ts.map +1 -0
  30. package/dist/modules/declared-variables/index.js +2 -0
  31. package/dist/modules/declared-variables/index.js.map +1 -0
  32. package/dist/modules/diff/diff.routes.d.ts +1 -1
  33. package/dist/modules/diff/diff.routes.d.ts.map +1 -1
  34. package/dist/modules/diff/diff.routes.js +3 -3
  35. package/dist/modules/diff/diff.routes.js.map +1 -1
  36. package/dist/modules/kb-fs/locking-filesystem.d.ts +16 -0
  37. package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
  38. package/dist/modules/kb-fs/locking-filesystem.js +20 -0
  39. package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
  40. package/dist/modules/kb-fs/repo-path.d.ts +32 -0
  41. package/dist/modules/kb-fs/repo-path.d.ts.map +1 -0
  42. package/dist/modules/kb-fs/repo-path.js +54 -0
  43. package/dist/modules/kb-fs/repo-path.js.map +1 -0
  44. package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -1
  45. package/dist/modules/secrets-vault/db-secrets-vault.service.js +60 -18
  46. package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -1
  47. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts +20 -0
  48. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts.map +1 -1
  49. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js +121 -47
  50. package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js.map +1 -1
  51. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
  52. package/dist/modules/secrets-vault/secrets-vault.routes.js +20 -2
  53. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
  54. package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
  55. package/dist/modules/tool-helpers/tool-context.js +1 -0
  56. package/dist/modules/tool-helpers/tool-context.js.map +1 -1
  57. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
  58. package/dist/modules/tool-manuals/mcp-json-discovery.js +45 -12
  59. package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
  60. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
  61. package/dist/modules/tool-manuals/mcp-server-edit.service.js +2 -1
  62. package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
  63. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +40 -8
  64. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
  65. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +38 -14
  66. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  67. package/dist/modules/tool-manuals/tool-manuals.service.js +164 -55
  68. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  69. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  70. package/dist/modules/tool-manuals/tool-manuals.tools.js +10 -5
  71. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  72. package/dist/modules/tool-manuals/utcp-cli-parse-only.d.ts +55 -0
  73. package/dist/modules/tool-manuals/utcp-cli-parse-only.d.ts.map +1 -0
  74. package/dist/modules/tool-manuals/utcp-cli-parse-only.js +76 -0
  75. package/dist/modules/tool-manuals/utcp-cli-parse-only.js.map +1 -0
  76. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +3 -1
  77. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  78. package/dist/modules/workflow/agent-tools/workflow.tools.js +19 -2
  79. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  80. package/dist/modules/workflow/git/git.service.d.ts +32 -1
  81. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  82. package/dist/modules/workflow/git/git.service.js +70 -5
  83. package/dist/modules/workflow/git/git.service.js.map +1 -1
  84. package/dist/modules/workflow/git/pull-request.service.d.ts +3 -3
  85. package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
  86. package/dist/modules/workflow/git/pull-request.service.js +20 -2
  87. package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
  88. package/dist/modules/workflow/pending-commits.worker.d.ts +8 -0
  89. package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -1
  90. package/dist/modules/workflow/pending-commits.worker.js +74 -16
  91. package/dist/modules/workflow/pending-commits.worker.js.map +1 -1
  92. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
  93. package/dist/modules/workflow/review-workflow/review-workflow.service.js +7 -0
  94. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
  95. package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
  96. package/dist/modules/workflow/workflow.routes.js +12 -0
  97. package/dist/modules/workflow/workflow.routes.js.map +1 -1
  98. package/dist/modules/workflow/workflow.service.d.ts +1 -0
  99. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  100. package/dist/modules/workflow/workflow.service.js +4 -0
  101. package/dist/modules/workflow/workflow.service.js.map +1 -1
  102. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  103. package/dist/modules/workspace/workspace.tools.js +31 -15
  104. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  105. package/kb-template/AGENTS.md +52 -8
  106. package/package.json +4 -3
  107. package/src/core/create-core-server.ts +13 -1
  108. package/src/core/create-core-services.ts +1 -0
  109. package/src/modules/access/__tests__/access-control.atref-cache.test.ts +260 -0
  110. package/src/modules/access/__tests__/access-groups.test.ts +28 -0
  111. package/src/modules/access/access-control.service.ts +198 -37
  112. package/src/modules/access/admin-locked-commit.ts +1 -0
  113. package/src/modules/access/synced-groups-committer.ts +1 -1
  114. package/src/modules/access-model/__tests__/access-grammar.test.ts +101 -1
  115. package/src/modules/access-model/access-errors.ts +19 -0
  116. package/src/modules/access-model/access-grammar.ts +67 -3
  117. package/src/modules/declared-variables/__tests__/declared-variables.route.test.ts +166 -0
  118. package/src/modules/declared-variables/declared-variables.routes.ts +151 -0
  119. package/src/modules/declared-variables/index.ts +1 -0
  120. package/src/modules/diff/__tests__/diff.routes.rejectPathsLocked.test.ts +4 -4
  121. package/src/modules/diff/diff.routes.ts +3 -2
  122. package/src/modules/kb-fs/__tests__/locking-filesystem.test.ts +306 -131
  123. package/src/modules/kb-fs/__tests__/repo-path.test.ts +106 -0
  124. package/src/modules/kb-fs/locking-filesystem.ts +30 -0
  125. package/src/modules/kb-fs/repo-path.ts +56 -0
  126. package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +104 -0
  127. package/src/modules/secrets-vault/__tests__/mcp-oauth-discovery.service.test.ts +52 -0
  128. package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +48 -1
  129. package/src/modules/secrets-vault/db-secrets-vault.service.ts +73 -22
  130. package/src/modules/secrets-vault/mcp-oauth-discovery.service.ts +141 -50
  131. package/src/modules/secrets-vault/secrets-vault.routes.ts +600 -582
  132. package/src/modules/tool-helpers/tool-context.ts +1 -0
  133. package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +38 -0
  134. package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +2 -0
  135. package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +243 -0
  136. package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +95 -0
  137. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +17 -1
  138. package/src/modules/tool-manuals/mcp-json-discovery.ts +39 -15
  139. package/src/modules/tool-manuals/mcp-server-edit.service.ts +2 -1
  140. package/src/modules/tool-manuals/tool-manuals.contract.ts +40 -9
  141. package/src/modules/tool-manuals/tool-manuals.service.ts +156 -28
  142. package/src/modules/tool-manuals/tool-manuals.tools.ts +10 -5
  143. package/src/modules/tool-manuals/utcp-cli-parse-only.ts +76 -0
  144. package/src/modules/workflow/__tests__/pending-commits.worker.test.ts +46 -0
  145. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +60 -1
  146. package/src/modules/workflow/agent-tools/workflow.tools.ts +18 -1
  147. package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +56 -0
  148. package/src/modules/workflow/git/__tests__/git.service.commitFile.strayPath.test.ts +162 -0
  149. package/src/modules/workflow/git/__tests__/pull-request.service.getPrDetail.test.ts +114 -0
  150. package/src/modules/workflow/git/git.service.ts +73 -6
  151. package/src/modules/workflow/git/pull-request.service.ts +22 -4
  152. package/src/modules/workflow/pending-commits.worker.ts +80 -18
  153. package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +60 -0
  154. package/src/modules/workflow/review-workflow/review-workflow.service.ts +5 -0
  155. package/src/modules/workflow/workflow.routes.ts +12 -0
  156. package/src/modules/workflow/workflow.service.ts +5 -1
  157. package/src/modules/workspace/__tests__/workspace.tools.test.ts +45 -0
  158. package/src/modules/workspace/workspace.tools.ts +35 -15
@@ -10,6 +10,22 @@ export type McpAuthDiscovery =
10
10
  /** The server wants auth but the spec chain didn't complete — leave the tool as-is. */
11
11
  | { status: 'unsupported'; reason: string };
12
12
 
13
+ /** Where a server's sign-in lives — the spec chain's answer before any client exists. */
14
+ interface AuthorizationServerInfo {
15
+ authorizationUrl: string;
16
+ tokenUrl: string;
17
+ /** RFC 7591 endpoint, when the AS offers dynamic registration. */
18
+ registrationUrl?: string;
19
+ /** RFC 8707 resource indicator: the PRM's `resource`, else the MCP URL itself. */
20
+ resource: string;
21
+ scopes?: string[];
22
+ }
23
+
24
+ type AuthorizationServerResolution =
25
+ | { status: 'open' }
26
+ | { status: 'found'; as: AuthorizationServerInfo }
27
+ | { status: 'unsupported'; reason: string };
28
+
13
29
  const FETCH_TIMEOUT_MS = 5_000;
14
30
  /** Re-probe an open/unsupported server after this long (it may grow/lose auth). */
15
31
  const NEGATIVE_TTL_MS = 5 * 60_000;
@@ -37,12 +53,21 @@ const OAUTH_TTL_MS = 60 * 60_000;
37
53
  * row from the shared one, and the UTCP variable loader injects the fresh
38
54
  * access token into the manual's `Authorization` header at call time.
39
55
  *
56
+ * Providers without dynamic registration (HubSpot, Google) stop at step 3.
57
+ * For those, `providerForDeclaredClient` runs steps 1–3 for a client id the
58
+ * OWNER registered by hand and declared on the manual — same endpoints, same
59
+ * PKCE, same resource indicator, nothing persisted (the owner's client-secret
60
+ * save pins the completed provider).
61
+ *
40
62
  * Every fetch is SSRF-guarded (https-only, no redirects, bounded) — these URLs
41
63
  * originate from user-authored `.tool` files and remote servers' own metadata.
42
64
  */
43
65
  export class McpOAuthDiscoveryService {
44
66
  private readonly cache = new Map<string, { result: McpAuthDiscovery; expiresAt: number }>();
45
67
  private readonly inflight = new Map<string, Promise<McpAuthDiscovery>>();
68
+ /** The metadata walk alone, per MCP URL — shared by every declared client on that server. */
69
+ private readonly asCache = new Map<string, { result: AuthorizationServerResolution; expiresAt: number }>();
70
+ private readonly asInflight = new Map<string, Promise<AuthorizationServerResolution>>();
46
71
 
47
72
  constructor(
48
73
  private readonly deps: {
@@ -75,6 +100,30 @@ export class McpOAuthDiscoveryService {
75
100
  return pending;
76
101
  }
77
102
 
103
+ /**
104
+ * The provider for a client the OWNER registered: the server's discovered
105
+ * endpoints + resource indicator around the declared `clientId`, PKCE on (the
106
+ * MCP spec requires it; a provider without it ignores the parameters). No
107
+ * registration call, no vault write — the metadata is cached per URL so a
108
+ * re-scan or a second declared client on the same server costs no network.
109
+ */
110
+ async providerForDeclaredClient(manualName: string, mcpUrl: string, clientId: string): Promise<McpAuthDiscovery> {
111
+ const resolved = await this.resolveAuthorizationServer(manualName, mcpUrl);
112
+ if (resolved.status === 'open') {
113
+ return {
114
+ status: 'unsupported',
115
+ reason:
116
+ 'the server did not ask for a sign-in and publishes no OAuth metadata — declare `authorizationUrl` and `tokenUrl` on the sign-in variable if it needs one',
117
+ };
118
+ }
119
+ if (resolved.status === 'unsupported') return resolved;
120
+ const { authorizationUrl, tokenUrl, resource, scopes } = resolved.as;
121
+ return {
122
+ status: 'oauth',
123
+ provider: { authorizationUrl, tokenUrl, clientId, scopes, pkce: true, resource },
124
+ };
125
+ }
126
+
78
127
  private remember(key: string, result: McpAuthDiscovery): McpAuthDiscovery {
79
128
  const ttl = result.status === 'oauth' ? OAUTH_TTL_MS : NEGATIVE_TTL_MS;
80
129
  this.cache.set(key, { result, expiresAt: this.now() + ttl });
@@ -114,6 +163,89 @@ export class McpOAuthDiscoveryService {
114
163
  }
115
164
 
116
165
  private async discoverFresh(manualName: string, key: string, mcpUrl: string): Promise<McpAuthDiscovery> {
166
+ const resolved = await this.resolveAuthorizationServer(manualName, mcpUrl);
167
+ if (resolved.status !== 'found') return resolved;
168
+ const { authorizationUrl, tokenUrl, registrationUrl, resource, scopes } = resolved.as;
169
+ if (!registrationUrl) {
170
+ return {
171
+ status: 'unsupported',
172
+ reason:
173
+ 'the server requires sign-in but does not allow automatic client registration — register an OAuth app ' +
174
+ `with the provider (redirect URI: ${this.deps.redirectUri}), declare its client id on a user-scoped ` +
175
+ 'sign-in variable (the server editor on the tool\'s page, or the plugin.json extensions entry), then set its client secret',
176
+ };
177
+ }
178
+
179
+ // 4. Dynamic client registration (RFC 7591), as a PUBLIC client: PKCE
180
+ // carries the proof, no secret to store or leak.
181
+ assertSafeFetchUrl(registrationUrl, { requireHttps: true, label: 'registration_endpoint' });
182
+ const regRes = await this.fetchRaw(registrationUrl, {
183
+ method: 'POST',
184
+ headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
185
+ body: JSON.stringify({
186
+ client_name: 'Bevel Knowledge Base',
187
+ redirect_uris: [this.deps.redirectUri],
188
+ grant_types: ['authorization_code', 'refresh_token'],
189
+ response_types: ['code'],
190
+ token_endpoint_auth_method: 'none',
191
+ }),
192
+ });
193
+ if (!regRes.ok) {
194
+ return { status: 'unsupported', reason: `client registration failed: HTTP ${regRes.status}` };
195
+ }
196
+ const reg = (await regRes.json().catch(() => null)) as Record<string, unknown> | null;
197
+ const clientId = typeof reg?.client_id === 'string' ? reg.client_id : '';
198
+ if (!clientId) {
199
+ return { status: 'unsupported', reason: 'client registration returned no client_id' };
200
+ }
201
+ const clientSecret = typeof reg?.client_secret === 'string' && reg.client_secret ? reg.client_secret : undefined;
202
+
203
+ const provider: OAuthProviderConfig = {
204
+ authorizationUrl,
205
+ tokenUrl,
206
+ clientId,
207
+ clientSecret,
208
+ scopes,
209
+ pkce: true,
210
+ publicClient: !clientSecret,
211
+ resource,
212
+ };
213
+ await this.deps.secretsVault.putSharedOAuthProvider({
214
+ key,
215
+ label: `${manualName} sign-in`,
216
+ provider,
217
+ });
218
+ // Return the stored (public) shape — no secret rides in cache entries.
219
+ const publicProvider = { ...provider };
220
+ delete publicProvider.clientSecret;
221
+ return { status: 'oauth', provider: publicProvider };
222
+ }
223
+
224
+ /** Steps 1–3, memoised per MCP URL (positive and negative alike, short TTL). */
225
+ private async resolveAuthorizationServer(manualName: string, mcpUrl: string): Promise<AuthorizationServerResolution> {
226
+ const cached = this.asCache.get(mcpUrl);
227
+ if (cached && cached.expiresAt > this.now()) return cached.result;
228
+ let pending = this.asInflight.get(mcpUrl);
229
+ if (!pending) {
230
+ pending = this.resolveAuthorizationServerFresh(mcpUrl)
231
+ .catch((err: unknown): AuthorizationServerResolution => ({
232
+ status: 'unsupported',
233
+ reason: err instanceof Error ? err.message : String(err),
234
+ }))
235
+ .then((result) => {
236
+ if (result.status === 'unsupported') {
237
+ console.warn(`[mcp-oauth-discovery] "${manualName}" (${mcpUrl}): ${result.reason}`);
238
+ }
239
+ this.asCache.set(mcpUrl, { result, expiresAt: this.now() + NEGATIVE_TTL_MS });
240
+ return result;
241
+ })
242
+ .finally(() => this.asInflight.delete(mcpUrl));
243
+ this.asInflight.set(mcpUrl, pending);
244
+ }
245
+ return pending;
246
+ }
247
+
248
+ private async resolveAuthorizationServerFresh(mcpUrl: string): Promise<AuthorizationServerResolution> {
117
249
  // 1. Probe: an unauthenticated initialize. A 401/403, or ANY response
118
250
  // carrying a `WWW-Authenticate` challenge, means the server wants OAuth;
119
251
  // a redirect to a login page (fetch throws under `redirect:'error'`)
@@ -205,57 +337,16 @@ export class McpOAuthDiscoveryService {
205
337
  if (!authorizationUrl || !tokenUrl) {
206
338
  return { status: 'unsupported', reason: 'authorization-server metadata is missing endpoints' };
207
339
  }
208
- if (!registrationUrl) {
209
- return {
210
- status: 'unsupported',
211
- reason:
212
- 'server requires sign-in but does not support automatic client registration — declare the oauth provider in the .tool file instead',
213
- };
214
- }
215
-
216
- // 4. Dynamic client registration (RFC 7591), as a PUBLIC client: PKCE
217
- // carries the proof, no secret to store or leak.
218
- assertSafeFetchUrl(registrationUrl, { requireHttps: true, label: 'registration_endpoint' });
219
- const regRes = await this.fetchRaw(registrationUrl, {
220
- method: 'POST',
221
- headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
222
- body: JSON.stringify({
223
- client_name: 'Bevel Knowledge Base',
224
- redirect_uris: [this.deps.redirectUri],
225
- grant_types: ['authorization_code', 'refresh_token'],
226
- response_types: ['code'],
227
- token_endpoint_auth_method: 'none',
228
- }),
229
- });
230
- if (!regRes.ok) {
231
- return { status: 'unsupported', reason: `client registration failed: HTTP ${regRes.status}` };
232
- }
233
- const reg = (await regRes.json().catch(() => null)) as Record<string, unknown> | null;
234
- const clientId = typeof reg?.client_id === 'string' ? reg.client_id : '';
235
- if (!clientId) {
236
- return { status: 'unsupported', reason: 'client registration returned no client_id' };
237
- }
238
- const clientSecret = typeof reg?.client_secret === 'string' && reg.client_secret ? reg.client_secret : undefined;
239
-
240
- const provider: OAuthProviderConfig = {
241
- authorizationUrl,
242
- tokenUrl,
243
- clientId,
244
- clientSecret,
245
- scopes,
246
- pkce: true,
247
- publicClient: !clientSecret,
248
- resource,
340
+ return {
341
+ status: 'found',
342
+ as: {
343
+ authorizationUrl,
344
+ tokenUrl,
345
+ ...(registrationUrl ? { registrationUrl } : {}),
346
+ resource,
347
+ ...(scopes ? { scopes } : {}),
348
+ },
249
349
  };
250
- await this.deps.secretsVault.putSharedOAuthProvider({
251
- key,
252
- label: `${manualName} sign-in`,
253
- provider,
254
- });
255
- // Return the stored (public) shape — no secret rides in cache entries.
256
- const publicProvider = { ...provider };
257
- delete publicProvider.clientSecret;
258
- return { status: 'oauth', provider: publicProvider };
259
350
  }
260
351
 
261
352
  private async fetchRaw(url: string, init: RequestInit): Promise<Response> {