@backstage/plugin-scaffolder-backend-module-sentry 0.3.8-next.2 → 0.4.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,18 @@
1
1
  # @backstage/plugin-scaffolder-backend-module-sentry
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 52b5c79: **BREAKING**: Restrict Sentry API requests to the configured API base URL. Move custom action-level `apiBaseUrl` values to `scaffolder.sentry.apiBaseUrl` before upgrading.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @backstage/config@1.3.9
13
+ - @backstage/plugin-scaffolder-node@0.13.7
14
+ - @backstage/backend-plugin-api@1.10.1
15
+
3
16
  ## 0.3.8-next.2
4
17
 
5
18
  ### Patch Changes
@@ -2,6 +2,7 @@
2
2
 
3
3
  var pluginScaffolderNode = require('@backstage/plugin-scaffolder-node');
4
4
  var errors = require('@backstage/errors');
5
+ var sentryApi = require('./sentryApi.cjs.js');
5
6
 
6
7
  function createSentryCreateProjectAction(options) {
7
8
  const { config } = options;
@@ -28,7 +29,7 @@ function createSentryCreateProjectAction(options) {
28
29
  description: "authenticate via bearer auth token. Requires scope: project:write"
29
30
  }).optional(),
30
31
  apiBaseUrl: (z) => z.string({
31
- description: "Optional base URL for the Sentry API. e.g. https://sentry.io/api/0"
32
+ description: "Optional compatibility value that must match the configured Sentry API base URL, or the default Sentry API URL if none is configured"
32
33
  }).optional()
33
34
  }
34
35
  },
@@ -55,33 +56,27 @@ function createSentryCreateProjectAction(options) {
55
56
  if (!token) {
56
57
  throw new errors.InputError(`No valid sentry token given`);
57
58
  }
58
- const baseUrl = apiBaseUrl || config.getOptionalString("scaffolder.sentry.apiBaseUrl") || "https://sentry.io/api/0";
59
+ const baseUrl = sentryApi.resolveSentryApiBaseUrl({
60
+ config,
61
+ inputApiBaseUrl: apiBaseUrl
62
+ });
59
63
  const { result } = await ctx.checkpoint({
60
64
  key: `create.project.${organizationSlug}.${teamSlug}`,
61
65
  fn: async () => {
62
- const response = await fetch(
63
- `${baseUrl}/teams/${organizationSlug}/${teamSlug}/projects/`,
64
- {
66
+ const { body: res, status } = await sentryApi.requestSentryApi({
67
+ url: `${baseUrl}/teams/${organizationSlug}/${teamSlug}/projects/`,
68
+ init: {
65
69
  method: "POST",
66
70
  headers: {
67
71
  Authorization: `Bearer ${token}`,
68
72
  "Content-Type": "application/json"
69
73
  },
70
74
  body: JSON.stringify(body)
71
- }
72
- );
73
- const contentType = response.headers.get("content-type");
74
- if (contentType !== "application/json") {
75
- throw new errors.InputError(
76
- `Unexpected Sentry Response Type: ${await response.text()}`
77
- );
78
- }
79
- const res = await response.json();
80
- if (response.status !== 201) {
81
- throw new errors.InputError(`Sentry Response was: ${await res.detail}`);
82
- }
75
+ },
76
+ expectedStatus: 201
77
+ });
83
78
  return {
84
- code: response.status,
79
+ code: status,
85
80
  result: res
86
81
  };
87
82
  }
@@ -1 +1 @@
1
- {"version":3,"file":"createProject.cjs.js","sources":["../../src/actions/createProject.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { InputError } from '@backstage/errors';\nimport { Config } from '@backstage/config';\n\n/**\n * Creates the `sentry:project:create` Scaffolder action.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/features/software-templates/writing-custom-actions}.\n *\n * @param options - Configuration of the Sentry API.\n * @public\n */\nexport function createSentryCreateProjectAction(options: { config: Config }) {\n const { config } = options;\n\n return createTemplateAction({\n id: 'sentry:project:create',\n schema: {\n input: {\n organizationSlug: z =>\n z.string({\n description: 'The slug of the organization the team belongs to',\n }),\n teamSlug: z =>\n z.string({\n description: 'The slug of the team to create a new project for',\n }),\n name: z =>\n z.string({\n description: 'The name for the new project',\n }),\n slug: z =>\n z\n .string({\n description:\n 'Optional slug for the new project. If not provided a slug is generated from the name',\n })\n .optional(),\n platform: z =>\n z\n .string({\n description: 'Optional sentry platform for the new project. ',\n })\n .optional(),\n authToken: z =>\n z\n .string({\n description:\n 'authenticate via bearer auth token. Requires scope: project:write',\n })\n .optional(),\n apiBaseUrl: z =>\n z\n .string({\n description:\n 'Optional base URL for the Sentry API. e.g. https://sentry.io/api/0',\n })\n .optional(),\n },\n },\n async handler(ctx) {\n const {\n organizationSlug,\n teamSlug,\n name,\n slug,\n platform,\n authToken,\n apiBaseUrl,\n } = ctx.input;\n\n const body: any = {\n name: name,\n };\n\n if (slug) {\n body.slug = slug;\n }\n\n if (platform) {\n body.platform = platform;\n }\n\n const token = authToken\n ? authToken\n : config.getOptionalString('scaffolder.sentry.token');\n\n if (!token) {\n throw new InputError(`No valid sentry token given`);\n }\n\n const baseUrl =\n apiBaseUrl ||\n config.getOptionalString('scaffolder.sentry.apiBaseUrl') ||\n 'https://sentry.io/api/0';\n\n const { result } = await ctx.checkpoint({\n key: `create.project.${organizationSlug}.${teamSlug}`,\n fn: async () => {\n const response = await fetch(\n `${baseUrl}/teams/${organizationSlug}/${teamSlug}/projects/`,\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n },\n );\n\n const contentType = response.headers.get('content-type');\n\n if (contentType !== 'application/json') {\n throw new InputError(\n `Unexpected Sentry Response Type: ${await response.text()}`,\n );\n }\n\n const res = await response.json();\n\n if (response.status !== 201) {\n throw new InputError(`Sentry Response was: ${await res.detail}`);\n }\n\n return {\n code: response.status,\n result: res as { id: string },\n };\n },\n });\n\n ctx.output('id', result.id);\n ctx.output('result', result);\n },\n });\n}\n"],"names":["createTemplateAction","InputError"],"mappings":"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"}
1
+ {"version":3,"file":"createProject.cjs.js","sources":["../../src/actions/createProject.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { InputError } from '@backstage/errors';\nimport { Config } from '@backstage/config';\nimport { requestSentryApi, resolveSentryApiBaseUrl } from './sentryApi';\n\n/**\n * Creates the `sentry:project:create` Scaffolder action.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/features/software-templates/writing-custom-actions}.\n *\n * @param options - Configuration of the Sentry API.\n * @public\n */\nexport function createSentryCreateProjectAction(options: { config: Config }) {\n const { config } = options;\n\n return createTemplateAction({\n id: 'sentry:project:create',\n schema: {\n input: {\n organizationSlug: z =>\n z.string({\n description: 'The slug of the organization the team belongs to',\n }),\n teamSlug: z =>\n z.string({\n description: 'The slug of the team to create a new project for',\n }),\n name: z =>\n z.string({\n description: 'The name for the new project',\n }),\n slug: z =>\n z\n .string({\n description:\n 'Optional slug for the new project. If not provided a slug is generated from the name',\n })\n .optional(),\n platform: z =>\n z\n .string({\n description: 'Optional sentry platform for the new project. ',\n })\n .optional(),\n authToken: z =>\n z\n .string({\n description:\n 'authenticate via bearer auth token. Requires scope: project:write',\n })\n .optional(),\n apiBaseUrl: z =>\n z\n .string({\n description:\n 'Optional compatibility value that must match the configured Sentry API base URL, or the default Sentry API URL if none is configured',\n })\n .optional(),\n },\n },\n async handler(ctx) {\n const {\n organizationSlug,\n teamSlug,\n name,\n slug,\n platform,\n authToken,\n apiBaseUrl,\n } = ctx.input;\n\n const body: any = {\n name: name,\n };\n\n if (slug) {\n body.slug = slug;\n }\n\n if (platform) {\n body.platform = platform;\n }\n\n const token = authToken\n ? authToken\n : config.getOptionalString('scaffolder.sentry.token');\n\n if (!token) {\n throw new InputError(`No valid sentry token given`);\n }\n\n const baseUrl = resolveSentryApiBaseUrl({\n config,\n inputApiBaseUrl: apiBaseUrl,\n });\n\n const { result } = await ctx.checkpoint({\n key: `create.project.${organizationSlug}.${teamSlug}`,\n fn: async () => {\n const { body: res, status } = await requestSentryApi<{ id: string }>({\n url: `${baseUrl}/teams/${organizationSlug}/${teamSlug}/projects/`,\n init: {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n },\n expectedStatus: 201,\n });\n\n return {\n code: status,\n result: res,\n };\n },\n });\n\n ctx.output('id', result.id);\n ctx.output('result', result);\n },\n });\n}\n"],"names":["createTemplateAction","InputError","resolveSentryApiBaseUrl","requestSentryApi"],"mappings":"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"}
@@ -2,6 +2,7 @@
2
2
 
3
3
  var pluginScaffolderNode = require('@backstage/plugin-scaffolder-node');
4
4
  var errors = require('@backstage/errors');
5
+ var sentryApi = require('./sentryApi.cjs.js');
5
6
 
6
7
  function createSentryFetchDSNAction(options) {
7
8
  const { config } = options;
@@ -20,7 +21,7 @@ function createSentryFetchDSNAction(options) {
20
21
  description: "authenticate via bearer auth token. Requires one of the following scopes: project:admin, project:read, project:write"
21
22
  }).optional(),
22
23
  apiBaseUrl: (z) => z.string({
23
- description: "Optional base URL for the Sentry API. e.g. https://sentry.io/api/0"
24
+ description: "Optional compatibility value that must match the configured Sentry API base URL, or the default Sentry API URL if none is configured"
24
25
  }).optional()
25
26
  },
26
27
  output: {
@@ -35,28 +36,21 @@ function createSentryFetchDSNAction(options) {
35
36
  if (!token) {
36
37
  throw new errors.InputError(`No valid sentry token given`);
37
38
  }
38
- const baseUrl = apiBaseUrl || config.getOptionalString("scaffolder.sentry.apiBaseUrl") || "https://sentry.io/api/0";
39
- const response = await fetch(
40
- `${baseUrl}/projects/${organizationSlug}/${projectSlug}/keys/`,
41
- {
39
+ const baseUrl = sentryApi.resolveSentryApiBaseUrl({
40
+ config,
41
+ inputApiBaseUrl: apiBaseUrl
42
+ });
43
+ const { body: keys } = await sentryApi.requestSentryApi({
44
+ url: `${baseUrl}/projects/${organizationSlug}/${projectSlug}/keys/`,
45
+ init: {
42
46
  method: "GET",
43
47
  headers: {
44
48
  Authorization: `Bearer ${token}`,
45
49
  "Content-Type": "application/json"
46
50
  }
47
- }
48
- );
49
- if (!response.headers.get("content-type")?.includes("application/json")) {
50
- throw new errors.InputError(
51
- `Unexpected Sentry Response Type: ${await response.text()}`
52
- );
53
- }
54
- const keys = await response.json();
55
- if (response.status !== 200) {
56
- throw new errors.InputError(
57
- `Sentry Response was: ${keys.detail || "Unknown error"}`
58
- );
59
- }
51
+ },
52
+ expectedStatus: 200
53
+ });
60
54
  if (!Array.isArray(keys) || keys.length === 0) {
61
55
  throw new errors.InputError("No keys found for the specified project");
62
56
  }
@@ -1 +1 @@
1
- {"version":3,"file":"fetchDSN.cjs.js","sources":["../../src/actions/fetchDSN.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { InputError } from '@backstage/errors';\nimport { Config } from '@backstage/config';\n\n/**\n * Creates the `sentry:fetch:dsn` Scaffolder action.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/features/software-templates/writing-custom-actions}.\n *\n * @param options - Configuration of the Sentry API.\n * @public\n */\nexport function createSentryFetchDSNAction(options: { config: Config }) {\n const { config } = options;\n\n return createTemplateAction({\n id: 'sentry:fetch:dsn',\n supportsDryRun: true,\n schema: {\n input: {\n organizationSlug: z =>\n z.string({\n description: 'The slug of the organization the project belongs to',\n }),\n projectSlug: z =>\n z.string({\n description: 'The slug of the project to fetch the DSN for',\n }),\n authToken: z =>\n z\n .string({\n description:\n 'authenticate via bearer auth token. Requires one of the following scopes: project:admin, project:read, project:write',\n })\n .optional(),\n apiBaseUrl: z =>\n z\n .string({\n description:\n 'Optional base URL for the Sentry API. e.g. https://sentry.io/api/0',\n })\n .optional(),\n },\n output: {\n dsn: z =>\n z\n .string({\n description: 'The public DSN of the Sentry project',\n })\n .optional(),\n },\n },\n async handler(ctx) {\n const { organizationSlug, projectSlug, authToken, apiBaseUrl } =\n ctx.input;\n\n const token = authToken\n ? authToken\n : config.getOptionalString('scaffolder.sentry.token');\n\n if (!token) {\n throw new InputError(`No valid sentry token given`);\n }\n\n const baseUrl =\n apiBaseUrl ||\n config.getOptionalString('scaffolder.sentry.apiBaseUrl') ||\n 'https://sentry.io/api/0';\n\n const response = await fetch(\n `${baseUrl}/projects/${organizationSlug}/${projectSlug}/keys/`,\n {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n },\n );\n\n if (!response.headers.get('content-type')?.includes('application/json')) {\n throw new InputError(\n `Unexpected Sentry Response Type: ${await response.text()}`,\n );\n }\n\n const keys = await response.json();\n\n if (response.status !== 200) {\n throw new InputError(\n `Sentry Response was: ${keys.detail || 'Unknown error'}`,\n );\n }\n\n if (!Array.isArray(keys) || keys.length === 0) {\n throw new InputError('No keys found for the specified project');\n }\n\n const publicDsn = keys[0]?.dsn?.public;\n if (!publicDsn) {\n throw new InputError('No public DSN found in project keys');\n }\n\n ctx.output('dsn', publicDsn);\n },\n });\n}\n"],"names":["createTemplateAction","InputError"],"mappings":"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"}
1
+ {"version":3,"file":"fetchDSN.cjs.js","sources":["../../src/actions/fetchDSN.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { InputError } from '@backstage/errors';\nimport { Config } from '@backstage/config';\nimport { requestSentryApi, resolveSentryApiBaseUrl } from './sentryApi';\n\n/**\n * Creates the `sentry:fetch:dsn` Scaffolder action.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/features/software-templates/writing-custom-actions}.\n *\n * @param options - Configuration of the Sentry API.\n * @public\n */\nexport function createSentryFetchDSNAction(options: { config: Config }) {\n const { config } = options;\n\n return createTemplateAction({\n id: 'sentry:fetch:dsn',\n supportsDryRun: true,\n schema: {\n input: {\n organizationSlug: z =>\n z.string({\n description: 'The slug of the organization the project belongs to',\n }),\n projectSlug: z =>\n z.string({\n description: 'The slug of the project to fetch the DSN for',\n }),\n authToken: z =>\n z\n .string({\n description:\n 'authenticate via bearer auth token. Requires one of the following scopes: project:admin, project:read, project:write',\n })\n .optional(),\n apiBaseUrl: z =>\n z\n .string({\n description:\n 'Optional compatibility value that must match the configured Sentry API base URL, or the default Sentry API URL if none is configured',\n })\n .optional(),\n },\n output: {\n dsn: z =>\n z\n .string({\n description: 'The public DSN of the Sentry project',\n })\n .optional(),\n },\n },\n async handler(ctx) {\n const { organizationSlug, projectSlug, authToken, apiBaseUrl } =\n ctx.input;\n\n const token = authToken\n ? authToken\n : config.getOptionalString('scaffolder.sentry.token');\n\n if (!token) {\n throw new InputError(`No valid sentry token given`);\n }\n\n const baseUrl = resolveSentryApiBaseUrl({\n config,\n inputApiBaseUrl: apiBaseUrl,\n });\n\n const { body: keys } = await requestSentryApi<unknown>({\n url: `${baseUrl}/projects/${organizationSlug}/${projectSlug}/keys/`,\n init: {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n },\n expectedStatus: 200,\n });\n\n if (!Array.isArray(keys) || keys.length === 0) {\n throw new InputError('No keys found for the specified project');\n }\n\n const publicDsn = keys[0]?.dsn?.public;\n if (!publicDsn) {\n throw new InputError('No public DSN found in project keys');\n }\n\n ctx.output('dsn', publicDsn);\n },\n });\n}\n"],"names":["createTemplateAction","InputError","resolveSentryApiBaseUrl","requestSentryApi"],"mappings":";;;;;;AA+BO,SAAS,2BAA2B,OAAA,EAA6B;AACtE,EAAA,MAAM,EAAE,QAAO,GAAI,OAAA;AAEnB,EAAA,OAAOA,yCAAA,CAAqB;AAAA,IAC1B,EAAA,EAAI,kBAAA;AAAA,IACJ,cAAA,EAAgB,IAAA;AAAA,IAChB,MAAA,EAAQ;AAAA,MACN,KAAA,EAAO;AAAA,QACL,gBAAA,EAAkB,CAAA,CAAA,KAChB,CAAA,CAAE,MAAA,CAAO;AAAA,UACP,WAAA,EAAa;AAAA,SACd,CAAA;AAAA,QACH,WAAA,EAAa,CAAA,CAAA,KACX,CAAA,CAAE,MAAA,CAAO;AAAA,UACP,WAAA,EAAa;AAAA,SACd,CAAA;AAAA,QACH,SAAA,EAAW,CAAA,CAAA,KACT,CAAA,CACG,MAAA,CAAO;AAAA,UACN,WAAA,EACE;AAAA,SACH,EACA,QAAA,EAAS;AAAA,QACd,UAAA,EAAY,CAAA,CAAA,KACV,CAAA,CACG,MAAA,CAAO;AAAA,UACN,WAAA,EACE;AAAA,SACH,EACA,QAAA;AAAS,OAChB;AAAA,MACA,MAAA,EAAQ;AAAA,QACN,GAAA,EAAK,CAAA,CAAA,KACH,CAAA,CACG,MAAA,CAAO;AAAA,UACN,WAAA,EAAa;AAAA,SACd,EACA,QAAA;AAAS;AAChB,KACF;AAAA,IACA,MAAM,QAAQ,GAAA,EAAK;AACjB,MAAA,MAAM,EAAE,gBAAA,EAAkB,WAAA,EAAa,SAAA,EAAW,UAAA,KAChD,GAAA,CAAI,KAAA;AAEN,MAAA,MAAM,KAAA,GAAQ,SAAA,GACV,SAAA,GACA,MAAA,CAAO,kBAAkB,yBAAyB,CAAA;AAEtD,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA,MAAM,IAAIC,kBAAW,CAAA,2BAAA,CAA6B,CAAA;AAAA,MACpD;AAEA,MAAA,MAAM,UAAUC,iCAAA,CAAwB;AAAA,QACtC,MAAA;AAAA,QACA,eAAA,EAAiB;AAAA,OAClB,CAAA;AAED,MAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,MAAMC,0BAAA,CAA0B;AAAA,QACrD,KAAK,CAAA,EAAG,OAAO,CAAA,UAAA,EAAa,gBAAgB,IAAI,WAAW,CAAA,MAAA,CAAA;AAAA,QAC3D,IAAA,EAAM;AAAA,UACJ,MAAA,EAAQ,KAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,aAAA,EAAe,UAAU,KAAK,CAAA,CAAA;AAAA,YAC9B,cAAA,EAAgB;AAAA;AAClB,SACF;AAAA,QACA,cAAA,EAAgB;AAAA,OACjB,CAAA;AAED,MAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,IAAK,IAAA,CAAK,WAAW,CAAA,EAAG;AAC7C,QAAA,MAAM,IAAIF,kBAAW,yCAAyC,CAAA;AAAA,MAChE;AAEA,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,CAAC,CAAA,EAAG,GAAA,EAAK,MAAA;AAChC,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,MAAM,IAAIA,kBAAW,qCAAqC,CAAA;AAAA,MAC5D;AAEA,MAAA,GAAA,CAAI,MAAA,CAAO,OAAO,SAAS,CAAA;AAAA,IAC7B;AAAA,GACD,CAAA;AACH;;;;"}
@@ -0,0 +1,71 @@
1
+ 'use strict';
2
+
3
+ var errors = require('@backstage/errors');
4
+
5
+ const DEFAULT_SENTRY_API_BASE_URL = "https://sentry.io/api/0";
6
+ function normalizeSentryApiBaseUrl(urlString, field) {
7
+ let url;
8
+ try {
9
+ url = new URL(urlString);
10
+ } catch {
11
+ throw new errors.InputError(`${field} must be a valid HTTP(S) URL`);
12
+ }
13
+ if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.search || url.hash) {
14
+ throw new errors.InputError(
15
+ `${field} must be an HTTP(S) URL without credentials, query parameters, or fragments`
16
+ );
17
+ }
18
+ return `${url.origin}${url.pathname.replace(/\/+$/, "")}`;
19
+ }
20
+ function resolveSentryApiBaseUrl(options) {
21
+ const configuredApiBaseUrl = options.config.getOptionalString(
22
+ "scaffolder.sentry.apiBaseUrl"
23
+ );
24
+ const effectiveApiBaseUrl = normalizeSentryApiBaseUrl(
25
+ configuredApiBaseUrl ?? DEFAULT_SENTRY_API_BASE_URL,
26
+ configuredApiBaseUrl ? "scaffolder.sentry.apiBaseUrl" : "default Sentry API base URL"
27
+ );
28
+ if (options.inputApiBaseUrl !== void 0) {
29
+ const inputApiBaseUrl = normalizeSentryApiBaseUrl(
30
+ options.inputApiBaseUrl,
31
+ "apiBaseUrl"
32
+ );
33
+ if (inputApiBaseUrl !== effectiveApiBaseUrl) {
34
+ throw new errors.InputError(
35
+ "apiBaseUrl must match the effective Sentry API base URL"
36
+ );
37
+ }
38
+ }
39
+ return effectiveApiBaseUrl;
40
+ }
41
+ async function requestSentryApi(options) {
42
+ let response;
43
+ try {
44
+ response = await fetch(options.url, {
45
+ ...options.init,
46
+ redirect: "error"
47
+ });
48
+ } catch {
49
+ throw new errors.InputError("Failed to request Sentry API");
50
+ }
51
+ if (response.status !== options.expectedStatus) {
52
+ throw new errors.InputError(
53
+ `Sentry API request failed with status ${response.status}`
54
+ );
55
+ }
56
+ if (!response.headers.get("content-type")?.toLowerCase().includes("application/json")) {
57
+ throw new errors.InputError("Unexpected Sentry response content type");
58
+ }
59
+ try {
60
+ return {
61
+ body: await response.json(),
62
+ status: response.status
63
+ };
64
+ } catch {
65
+ throw new errors.InputError("Invalid JSON response from Sentry");
66
+ }
67
+ }
68
+
69
+ exports.requestSentryApi = requestSentryApi;
70
+ exports.resolveSentryApiBaseUrl = resolveSentryApiBaseUrl;
71
+ //# sourceMappingURL=sentryApi.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentryApi.cjs.js","sources":["../../src/actions/sentryApi.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { InputError } from '@backstage/errors';\n\nconst DEFAULT_SENTRY_API_BASE_URL = 'https://sentry.io/api/0';\n\nfunction normalizeSentryApiBaseUrl(urlString: string, field: string): string {\n let url: URL;\n try {\n url = new URL(urlString);\n } catch {\n throw new InputError(`${field} must be a valid HTTP(S) URL`);\n }\n\n if (\n !['http:', 'https:'].includes(url.protocol) ||\n url.username ||\n url.password ||\n url.search ||\n url.hash\n ) {\n throw new InputError(\n `${field} must be an HTTP(S) URL without credentials, query parameters, or fragments`,\n );\n }\n\n return `${url.origin}${url.pathname.replace(/\\/+$/, '')}`;\n}\n\nexport function resolveSentryApiBaseUrl(options: {\n config: Config;\n inputApiBaseUrl?: string;\n}): string {\n const configuredApiBaseUrl = options.config.getOptionalString(\n 'scaffolder.sentry.apiBaseUrl',\n );\n const effectiveApiBaseUrl = normalizeSentryApiBaseUrl(\n configuredApiBaseUrl ?? DEFAULT_SENTRY_API_BASE_URL,\n configuredApiBaseUrl\n ? 'scaffolder.sentry.apiBaseUrl'\n : 'default Sentry API base URL',\n );\n\n if (options.inputApiBaseUrl !== undefined) {\n const inputApiBaseUrl = normalizeSentryApiBaseUrl(\n options.inputApiBaseUrl,\n 'apiBaseUrl',\n );\n if (inputApiBaseUrl !== effectiveApiBaseUrl) {\n throw new InputError(\n 'apiBaseUrl must match the effective Sentry API base URL',\n );\n }\n }\n\n return effectiveApiBaseUrl;\n}\n\nexport async function requestSentryApi<T>(options: {\n url: string;\n init: RequestInit;\n expectedStatus: number;\n}): Promise<{ body: T; status: number }> {\n let response: Response;\n try {\n response = await fetch(options.url, {\n ...options.init,\n redirect: 'error',\n });\n } catch {\n throw new InputError('Failed to request Sentry API');\n }\n\n if (response.status !== options.expectedStatus) {\n throw new InputError(\n `Sentry API request failed with status ${response.status}`,\n );\n }\n\n if (\n !response.headers\n .get('content-type')\n ?.toLowerCase()\n .includes('application/json')\n ) {\n throw new InputError('Unexpected Sentry response content type');\n }\n\n try {\n return {\n body: (await response.json()) as T,\n status: response.status,\n };\n } catch {\n throw new InputError('Invalid JSON response from Sentry');\n }\n}\n"],"names":["InputError"],"mappings":";;;;AAmBA,MAAM,2BAAA,GAA8B,yBAAA;AAEpC,SAAS,yBAAA,CAA0B,WAAmB,KAAA,EAAuB;AAC3E,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,IAAI,IAAI,SAAS,CAAA;AAAA,EACzB,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAIA,iBAAA,CAAW,CAAA,EAAG,KAAK,CAAA,4BAAA,CAA8B,CAAA;AAAA,EAC7D;AAEA,EAAA,IACE,CAAC,CAAC,OAAA,EAAS,QAAQ,CAAA,CAAE,SAAS,GAAA,CAAI,QAAQ,CAAA,IAC1C,GAAA,CAAI,YACJ,GAAA,CAAI,QAAA,IACJ,GAAA,CAAI,MAAA,IACJ,IAAI,IAAA,EACJ;AACA,IAAA,MAAM,IAAIA,iBAAA;AAAA,MACR,GAAG,KAAK,CAAA,2EAAA;AAAA,KACV;AAAA,EACF;AAEA,EAAA,OAAO,CAAA,EAAG,IAAI,MAAM,CAAA,EAAG,IAAI,QAAA,CAAS,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAC,CAAA,CAAA;AACzD;AAEO,SAAS,wBAAwB,OAAA,EAG7B;AACT,EAAA,MAAM,oBAAA,GAAuB,QAAQ,MAAA,CAAO,iBAAA;AAAA,IAC1C;AAAA,GACF;AACA,EAAA,MAAM,mBAAA,GAAsB,yBAAA;AAAA,IAC1B,oBAAA,IAAwB,2BAAA;AAAA,IACxB,uBACI,8BAAA,GACA;AAAA,GACN;AAEA,EAAA,IAAI,OAAA,CAAQ,oBAAoB,MAAA,EAAW;AACzC,IAAA,MAAM,eAAA,GAAkB,yBAAA;AAAA,MACtB,OAAA,CAAQ,eAAA;AAAA,MACR;AAAA,KACF;AACA,IAAA,IAAI,oBAAoB,mBAAA,EAAqB;AAC3C,MAAA,MAAM,IAAIA,iBAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,mBAAA;AACT;AAEA,eAAsB,iBAAoB,OAAA,EAID;AACvC,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI;AACF,IAAA,QAAA,GAAW,MAAM,KAAA,CAAM,OAAA,CAAQ,GAAA,EAAK;AAAA,MAClC,GAAG,OAAA,CAAQ,IAAA;AAAA,MACX,QAAA,EAAU;AAAA,KACX,CAAA;AAAA,EACH,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAIA,kBAAW,8BAA8B,CAAA;AAAA,EACrD;AAEA,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,OAAA,CAAQ,cAAA,EAAgB;AAC9C,IAAA,MAAM,IAAIA,iBAAA;AAAA,MACR,CAAA,sCAAA,EAAyC,SAAS,MAAM,CAAA;AAAA,KAC1D;AAAA,EACF;AAEA,EAAA,IACE,CAAC,QAAA,CAAS,OAAA,CACP,GAAA,CAAI,cAAc,GACjB,WAAA,EAAY,CACb,QAAA,CAAS,kBAAkB,CAAA,EAC9B;AACA,IAAA,MAAM,IAAIA,kBAAW,yCAAyC,CAAA;AAAA,EAChE;AAEA,EAAA,IAAI;AACF,IAAA,OAAO;AAAA,MACL,IAAA,EAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AAAA,MAC3B,QAAQ,QAAA,CAAS;AAAA,KACnB;AAAA,EACF,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAIA,kBAAW,mCAAmC,CAAA;AAAA,EAC1D;AACF;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-scaffolder-backend-module-sentry",
3
- "version": "0.3.8-next.2",
3
+ "version": "0.4.0",
4
4
  "backstage": {
5
5
  "role": "backend-plugin-module",
6
6
  "pluginId": "scaffolder",
@@ -51,17 +51,17 @@
51
51
  "test": "backstage-cli package test"
52
52
  },
53
53
  "dependencies": {
54
- "@backstage/backend-plugin-api": "1.10.1-next.1",
55
- "@backstage/config": "1.3.9-next.0",
56
- "@backstage/errors": "1.3.1",
57
- "@backstage/plugin-scaffolder-node": "0.13.7-next.2",
54
+ "@backstage/backend-plugin-api": "^1.10.1",
55
+ "@backstage/config": "^1.3.9",
56
+ "@backstage/errors": "^1.3.1",
57
+ "@backstage/plugin-scaffolder-node": "^0.13.7",
58
58
  "yaml": "^2.3.3"
59
59
  },
60
60
  "devDependencies": {
61
- "@backstage/backend-test-utils": "1.11.7-next.1",
62
- "@backstage/cli": "0.36.6-next.1",
63
- "@backstage/plugin-scaffolder-node-test-utils": "0.3.15-next.1",
64
- "@backstage/types": "1.2.2",
61
+ "@backstage/backend-test-utils": "^1.11.7",
62
+ "@backstage/cli": "^0.36.6",
63
+ "@backstage/plugin-scaffolder-node-test-utils": "^0.3.15",
64
+ "@backstage/types": "^1.2.2",
65
65
  "msw": "^2.0.0"
66
66
  },
67
67
  "configSchema": "config.schema.json"