@forge/api 2.15.0 → 2.15.1-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @forge/api
2
2
 
3
+ ## 2.15.1-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 55f66d2: Support fetch through proxy on the Node Runtime
8
+
3
9
  ## 2.15.0
4
10
 
5
11
  ### Minor Changes
@@ -5,7 +5,14 @@ import { FetchAPI } from '..';
5
5
  declare type FetchFunction = (url: RequestInfo | Url, options?: RequestInit) => Promise<Response>;
6
6
  declare type ProxyUrlProvider = 'app' | 'user' | 'none';
7
7
  declare type ProxyUrlRemote = 'jira' | 'confluence' | 'stargate' | 'bitbucket';
8
- export declare const createProxyFetch: (provider: ProxyUrlProvider, remote: ProxyUrlRemote) => FetchFunction;
8
+ declare type ProxyFetchArgs = {
9
+ type: 'fpp';
10
+ provider: ProxyUrlProvider;
11
+ remote: ProxyUrlRemote;
12
+ } | {
13
+ type: 'egress';
14
+ };
15
+ export declare const createProxyFetch: (args: ProxyFetchArgs) => FetchFunction;
9
16
  export declare function getNodeRuntimeAPI(): FetchAPI;
10
17
  export declare function getSandboxRuntimeAPI(api: any): FetchAPI;
11
18
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/api/fetch.ts"],"names":[],"mappings":";AAAA,OAAc,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAW,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAS9B,aAAK,aAAa,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,GAAG,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAC1F,aAAK,gBAAgB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAChD,aAAK,cAAc,GAAG,MAAM,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,CAAC;AAuBvE,eAAO,MAAM,gBAAgB,aAAc,gBAAgB,UAAU,cAAc,KAAG,aAkCnF,CAAC;AAuBJ,wBAAgB,iBAAiB,IAAI,QAAQ,CAoB5C;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,GAAG,GAAG,QAAQ,CAEvD"}
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/api/fetch.ts"],"names":[],"mappings":";AAAA,OAAc,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAW,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAQ9B,aAAK,aAAa,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,GAAG,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAC1F,aAAK,gBAAgB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAChD,aAAK,cAAc,GAAG,MAAM,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,CAAC;AA4BvE,aAAK,cAAc,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAyB/G,eAAO,MAAM,gBAAgB,SAAU,cAAc,KAAG,aAoCrD,CAAC;AAOJ,wBAAgB,iBAAiB,IAAI,QAAQ,CAoB5C;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,GAAG,GAAG,QAAQ,CAEvD"}
package/out/api/fetch.js CHANGED
@@ -6,7 +6,6 @@ const node_fetch_1 = tslib_1.__importStar(require("node-fetch"));
6
6
  const _1 = require(".");
7
7
  const runtime_1 = require("./runtime");
8
8
  const polyfill_response_1 = require("./polyfill-response");
9
- const egress_1 = require("@forge/egress");
10
9
  const errors_1 = require("./errors");
11
10
  const perf_hooks_1 = require("perf_hooks");
12
11
  const FORGE_PROXY_UPSTREAM_LATENCY_HEADER = 'forge-proxy-upstream-latency';
@@ -21,18 +20,38 @@ const remoteToMetric = {
21
20
  bitbucket: 'requestBitbucket',
22
21
  stargate: 'requestAtlassian'
23
22
  };
24
- const metricName = (provider, remote) => {
25
- if (provider === 'none') {
26
- return `api.${remoteToMetric[remote]}`;
23
+ const metricName = (args) => {
24
+ switch (args.type) {
25
+ case 'egress':
26
+ return 'api.fetch';
27
+ case 'fpp':
28
+ if (args.provider === 'none') {
29
+ return `api.${remoteToMetric[args.remote]}`;
30
+ }
31
+ return `api.${providerToMetric[args.provider]}.${remoteToMetric[args.remote]}`;
27
32
  }
28
- return `api.${providerToMetric[provider]}.${remoteToMetric[remote]}`;
29
33
  };
30
- const createProxyFetch = (provider, remote) => (0, runtime_1.wrapInMetrics)(metricName(provider, remote), async (url, options) => {
34
+ const createProxyRequest = ({ url: proxyUrl, token }, args, originalRequest) => {
35
+ let proxyRequest;
36
+ switch (args.type) {
37
+ case 'egress':
38
+ proxyRequest = new node_fetch_1.Request(`${proxyUrl}/egress`, originalRequest);
39
+ const url = new URL(originalRequest.url);
40
+ proxyRequest.headers.set('Forge-Proxy-Target-Relative', `${url.pathname}${url.search}`);
41
+ proxyRequest.headers.set('Forge-Proxy-Target-Host', url.hostname);
42
+ break;
43
+ case 'fpp':
44
+ proxyRequest = new node_fetch_1.Request(`${proxyUrl}/fpp/provider/${args.provider}/remote/${args.remote}`, originalRequest);
45
+ proxyRequest.headers.set('Forge-Proxy-Target-Relative', originalRequest.url);
46
+ break;
47
+ }
48
+ proxyRequest.headers.set('Forge-Proxy-Authorization', `Bearer ${token}`);
49
+ return proxyRequest;
50
+ };
51
+ const createProxyFetch = (args) => (0, runtime_1.wrapInMetrics)(metricName(args), async (url, options) => {
31
52
  const { proxy, metrics } = (0, runtime_1.getRuntime)();
32
53
  const request = new node_fetch_1.Request(url, options);
33
- const proxyRequest = new node_fetch_1.Request(`${proxy.url}/fpp/provider/${provider}/remote/${remote}`, request);
34
- proxyRequest.headers.set('Forge-Proxy-Target-Relative', request.url);
35
- proxyRequest.headers.set('Forge-Proxy-Authorization', `Bearer ${proxy.token}`);
54
+ const proxyRequest = createProxyRequest(proxy, args, request);
36
55
  const requestStart = perf_hooks_1.performance.now();
37
56
  const response = await (0, node_fetch_1.default)(proxyRequest);
38
57
  const requestEnd = perf_hooks_1.performance.now();
@@ -41,9 +60,13 @@ const createProxyFetch = (provider, remote) => (0, runtime_1.wrapInMetrics)(metr
41
60
  metrics.timing('proxy-success-overhead').set(requestEnd - requestStart - proxyUpstreamLatency);
42
61
  }
43
62
  if (response.headers.has('forge-proxy-error')) {
44
- if (response.headers.get('forge-proxy-error') === 'NEEDS_AUTHENTICATION_ERR') {
63
+ const errorReason = response.headers.get('forge-proxy-error');
64
+ if (errorReason === 'NEEDS_AUTHENTICATION_ERR') {
45
65
  throw new errors_1.NeedsAuthenticationError('Authentication Required', ATLASSIAN_TOKEN_SERVICE_KEY);
46
66
  }
67
+ if (errorReason === 'BLOCKED_EGRESS') {
68
+ throw new errors_1.ExternalEndpointNotAllowedError(request.url);
69
+ }
47
70
  throw new errors_1.ProxyRequestError(response.status, response.headers.get('forge-proxy-error'));
48
71
  }
49
72
  return response;
@@ -52,32 +75,24 @@ exports.createProxyFetch = createProxyFetch;
52
75
  const throwNotImplementedError = () => {
53
76
  throw new Error('not implemented');
54
77
  };
55
- const wrapExternalEgress = (url, options) => {
56
- const { allowedEgress } = (0, runtime_1.getRuntime)();
57
- const egressFilteringService = new egress_1.EgressFilteringService(allowedEgress);
58
- if (!egressFilteringService.isValidUrl(url)) {
59
- throw new Error(`URL not included in the external fetch backend permissions: ${url}. Visit go.atlassian.com/forge-egress for more information.`);
60
- }
61
- return (0, node_fetch_1.default)(url, options);
62
- };
63
78
  function getNodeRuntimeAPI() {
64
79
  return {
65
- fetch: (0, _1.wrapWithRouteUnwrapper)(wrapExternalEgress),
66
- requestJira: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)('none', 'jira')),
67
- requestConfluence: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)('none', 'confluence')),
68
- requestBitbucket: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)('none', 'bitbucket')),
80
+ fetch: (0, _1.wrapWithRouteUnwrapper)((0, exports.createProxyFetch)({ type: 'egress' })),
81
+ requestJira: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)({ type: 'fpp', provider: 'none', remote: 'jira' })),
82
+ requestConfluence: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)({ type: 'fpp', provider: 'none', remote: 'confluence' })),
83
+ requestBitbucket: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)({ type: 'fpp', provider: 'none', remote: 'bitbucket' })),
69
84
  asUser: () => ({
70
- requestJira: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)('user', 'jira')),
71
- requestConfluence: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)('user', 'confluence')),
72
- requestBitbucket: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)('user', 'bitbucket')),
73
- requestGraph: (0, _1.wrapRequestGraph)((0, exports.createProxyFetch)('user', 'stargate')),
85
+ requestJira: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)({ type: 'fpp', provider: 'user', remote: 'jira' })),
86
+ requestConfluence: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)({ type: 'fpp', provider: 'user', remote: 'confluence' })),
87
+ requestBitbucket: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)({ type: 'fpp', provider: 'user', remote: 'bitbucket' })),
88
+ requestGraph: (0, _1.wrapRequestGraph)((0, exports.createProxyFetch)({ type: 'fpp', provider: 'user', remote: 'stargate' })),
74
89
  withProvider: throwNotImplementedError
75
90
  }),
76
91
  asApp: () => ({
77
- requestJira: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)('app', 'jira')),
78
- requestConfluence: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)('app', 'confluence')),
79
- requestBitbucket: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)('app', 'bitbucket')),
80
- requestGraph: (0, _1.wrapRequestGraph)((0, exports.createProxyFetch)('app', 'stargate'))
92
+ requestJira: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)({ type: 'fpp', provider: 'app', remote: 'jira' })),
93
+ requestConfluence: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)({ type: 'fpp', provider: 'app', remote: 'confluence' })),
94
+ requestBitbucket: (0, _1.wrapRequestProduct)((0, exports.createProxyFetch)({ type: 'fpp', provider: 'app', remote: 'bitbucket' })),
95
+ requestGraph: (0, _1.wrapRequestGraph)((0, exports.createProxyFetch)({ type: 'fpp', provider: 'app', remote: 'stargate' }))
81
96
  })
82
97
  };
83
98
  }
@@ -1 +1 @@
1
- {"version":3,"file":"fetch-and-storage.d.ts","sourceRoot":"","sources":["../../src/runtime/fetch-and-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAA2C,MAAM,cAAc,CAAC;AAGzF,eAAO,MAAM,0BAA0B,EAAE,MAAM,UAAU,CAAC,OAAO,gBAAgB,CACO,CAAC;AAEzF,eAAO,MAAM,aAAa,WAQzB,CAAC;AAEF,eAAO,MAAM,WAAW,6BAOvB,CAAC"}
1
+ {"version":3,"file":"fetch-and-storage.d.ts","sourceRoot":"","sources":["../../src/runtime/fetch-and-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAA2C,MAAM,cAAc,CAAC;AAGzF,eAAO,MAAM,0BAA0B,EAAE,MAAM,UAAU,CAAC,OAAO,gBAAgB,CAET,CAAC;AAEzE,eAAO,MAAM,aAAa,WAQzB,CAAC;AAEF,eAAO,MAAM,WAAW,6BAOvB,CAAC"}
@@ -3,7 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getFetchAPI = exports.getContextAri = exports.createRequestStargateAsApp = void 0;
4
4
  const fetch_1 = require("../api/fetch");
5
5
  const runtime_1 = require("../api/runtime");
6
- const createRequestStargateAsApp = () => { var _a, _b; return (_b = (_a = global.api) === null || _a === void 0 ? void 0 : _a.asApp().__requestAtlassian) !== null && _b !== void 0 ? _b : (0, fetch_1.createProxyFetch)('app', 'stargate'); };
6
+ const createRequestStargateAsApp = () => {
7
+ var _a, _b;
8
+ return (_b = (_a = global.api) === null || _a === void 0 ? void 0 : _a.asApp().__requestAtlassian) !== null && _b !== void 0 ? _b : (0, fetch_1.createProxyFetch)({ type: 'fpp', provider: 'app', remote: 'stargate' });
9
+ };
7
10
  exports.createRequestStargateAsApp = createRequestStargateAsApp;
8
11
  const getContextAri = () => {
9
12
  var _a;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forge/api",
3
- "version": "2.15.0",
3
+ "version": "2.15.1-next.0",
4
4
  "description": "Forge API methods",
5
5
  "author": "Atlassian",
6
6
  "license": "UNLICENSED",
@@ -14,8 +14,9 @@
14
14
  "devDependencies": {
15
15
  "@forge/runtime": "4.3.1",
16
16
  "@forge/util": "1.2.2",
17
- "nock": "^10.0.6",
18
- "@types/node": "^12.12.63"
17
+ "@types/node": "^12.12.63",
18
+ "jest-matcher-specific-error": "^1.0.0",
19
+ "nock": "^10.0.6"
19
20
  },
20
21
  "dependencies": {
21
22
  "@forge/auth": "0.0.1",