@backstage/plugin-notifications-backend 0.6.4-next.1 → 0.6.4
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 +30 -0
- package/dist/actions/createGetNotificationsAction.cjs.js +154 -0
- package/dist/actions/createGetNotificationsAction.cjs.js.map +1 -0
- package/dist/actions/index.cjs.js +10 -0
- package/dist/actions/index.cjs.js.map +1 -0
- package/dist/database/DatabaseNotificationsStore.cjs.js +2 -2
- package/dist/database/DatabaseNotificationsStore.cjs.js.map +1 -1
- package/dist/plugin.cjs.js +7 -2
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/service/parseEntityOrderFieldParams.cjs.js +0 -2
- package/dist/service/parseEntityOrderFieldParams.cjs.js.map +1 -1
- package/package.json +17 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @backstage/plugin-notifications-backend
|
|
2
2
|
|
|
3
|
+
## 0.6.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 4c1fd43: Added an action to get a user's notifications
|
|
8
|
+
- 070af42: Fix handling of `limit=0` in `getNotifications` query to return empty results instead of all notifications
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
- @backstage/backend-plugin-api@1.9.0
|
|
11
|
+
- @backstage/errors@1.3.0
|
|
12
|
+
- @backstage/catalog-model@1.8.0
|
|
13
|
+
- @backstage/plugin-catalog-node@2.2.0
|
|
14
|
+
- @backstage/plugin-signals-node@0.2.0
|
|
15
|
+
- @backstage/plugin-notifications-node@0.2.25
|
|
16
|
+
- @backstage/config@1.3.7
|
|
17
|
+
- @backstage/plugin-notifications-common@0.2.2
|
|
18
|
+
|
|
19
|
+
## 0.6.4-next.2
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Updated dependencies
|
|
24
|
+
- @backstage/errors@1.3.0-next.0
|
|
25
|
+
- @backstage/plugin-catalog-node@2.2.0-next.2
|
|
26
|
+
- @backstage/backend-plugin-api@1.9.0-next.2
|
|
27
|
+
- @backstage/catalog-model@1.7.8-next.0
|
|
28
|
+
- @backstage/config@1.3.7-next.0
|
|
29
|
+
- @backstage/plugin-notifications-node@0.2.25-next.2
|
|
30
|
+
- @backstage/plugin-notifications-common@0.2.2-next.0
|
|
31
|
+
- @backstage/plugin-signals-node@0.1.30-next.2
|
|
32
|
+
|
|
3
33
|
## 0.6.4-next.1
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var errors = require('@backstage/errors');
|
|
4
|
+
|
|
5
|
+
const createGetNotificationsAction = ({
|
|
6
|
+
store,
|
|
7
|
+
auth,
|
|
8
|
+
actionsRegistry
|
|
9
|
+
}) => {
|
|
10
|
+
actionsRegistry.register({
|
|
11
|
+
name: "get-notifications",
|
|
12
|
+
title: "Get Notifications",
|
|
13
|
+
description: `
|
|
14
|
+
Fetches notifications for the currently authenticated user from the Backstage notifications system.
|
|
15
|
+
|
|
16
|
+
Each notification has an \`id\`, \`origin\` (the plugin or service that sent it), a \`payload\` with
|
|
17
|
+
\`title\`, optional \`description\`, optional \`link\`, \`severity\` (one of "critical", "high", "normal", "low"),
|
|
18
|
+
and optional \`topic\`. Notifications also carry \`created\` and optionally \`read\`, \`saved\`, and \`updated\` timestamps.
|
|
19
|
+
|
|
20
|
+
## Filters
|
|
21
|
+
|
|
22
|
+
Use the \`view\` field to control which notifications are returned:
|
|
23
|
+
- \`"unread"\` (default) \u2014 only notifications the user has not yet read. Use this to surface new, actionable items.
|
|
24
|
+
- \`"read"\` \u2014 only notifications the user has already read.
|
|
25
|
+
- \`"saved"\` \u2014 only notifications the user has explicitly saved/bookmarked.
|
|
26
|
+
- \`"all"\` \u2014 all notifications regardless of read or saved status.
|
|
27
|
+
|
|
28
|
+
Additional filters can be combined with \`view\`:
|
|
29
|
+
- \`search\` \u2014 free-text search across notification titles and descriptions.
|
|
30
|
+
- \`topic\` \u2014 filter to a specific topic string, e.g. "ci/cd" or "deployment".
|
|
31
|
+
- \`minimumSeverity\` \u2014 minimum severity level; returns this severity and anything more severe ("critical" > "high" > "normal" > "low").
|
|
32
|
+
- \`createdAfter\` \u2014 ISO 8601 datetime string; only return notifications created after this time.
|
|
33
|
+
|
|
34
|
+
## Pagination
|
|
35
|
+
|
|
36
|
+
Use \`offset\` and \`limit\` to paginate. The response includes \`totalCount\` so you can calculate further pages.
|
|
37
|
+
|
|
38
|
+
## Examples
|
|
39
|
+
|
|
40
|
+
- Get my unread notifications: use default values (no input required).
|
|
41
|
+
- Get all notifications from the past week: set \`view: "all"\` and \`createdAfter\` to 7 days ago.
|
|
42
|
+
- Get high-priority unread alerts: set \`minimumSeverity: "high"\` (view defaults to "unread").
|
|
43
|
+
`,
|
|
44
|
+
attributes: {
|
|
45
|
+
destructive: false,
|
|
46
|
+
readOnly: true,
|
|
47
|
+
idempotent: true
|
|
48
|
+
},
|
|
49
|
+
schema: {
|
|
50
|
+
input: (z) => z.object({
|
|
51
|
+
view: z.enum(["unread", "read", "saved", "all"]).optional().describe(
|
|
52
|
+
'Which notifications to return. Defaults to "unread". "unread" returns only unread notifications, "read" returns only read notifications, "saved" returns bookmarked notifications, "all" returns everything.'
|
|
53
|
+
),
|
|
54
|
+
search: z.string().optional().describe(
|
|
55
|
+
"Free-text search string to filter notifications by title or description."
|
|
56
|
+
),
|
|
57
|
+
topic: z.string().optional().describe(
|
|
58
|
+
'Filter to notifications with this specific topic, e.g. "ci/cd".'
|
|
59
|
+
),
|
|
60
|
+
minimumSeverity: z.enum(["critical", "high", "normal", "low"]).optional().describe(
|
|
61
|
+
'Minimum severity to include. "critical" is most severe, "low" is least. For example, "high" returns "critical" and "high" notifications only.'
|
|
62
|
+
),
|
|
63
|
+
createdAfter: z.string().optional().describe(
|
|
64
|
+
'ISO 8601 datetime string. Only return notifications created after this time, e.g. "2025-01-01T00:00:00Z".'
|
|
65
|
+
),
|
|
66
|
+
offset: z.number().int().min(0).optional().describe(
|
|
67
|
+
"Number of notifications to skip for pagination. Defaults to 0."
|
|
68
|
+
),
|
|
69
|
+
limit: z.number().int().min(1).max(100).optional().describe(
|
|
70
|
+
"Maximum number of notifications to return (1\u2013100). Defaults to 10."
|
|
71
|
+
)
|
|
72
|
+
}),
|
|
73
|
+
output: (z) => z.object({
|
|
74
|
+
notifications: z.array(z.object({}).passthrough()).describe("List of notifications matching the filters."),
|
|
75
|
+
totalCount: z.number().describe(
|
|
76
|
+
"Total number of notifications matching the filters, useful for pagination."
|
|
77
|
+
)
|
|
78
|
+
})
|
|
79
|
+
},
|
|
80
|
+
examples: [
|
|
81
|
+
{
|
|
82
|
+
title: "Get my unread notifications",
|
|
83
|
+
description: "Returns up to 10 unread notifications (the default).",
|
|
84
|
+
input: {},
|
|
85
|
+
output: {
|
|
86
|
+
notifications: [
|
|
87
|
+
{
|
|
88
|
+
id: "abc123",
|
|
89
|
+
origin: "catalog",
|
|
90
|
+
created: "2025-04-01T10:00:00.000Z",
|
|
91
|
+
payload: {
|
|
92
|
+
title: "Component entity missing owner",
|
|
93
|
+
severity: "high",
|
|
94
|
+
link: "/catalog/default/component/my-service"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
totalCount: 1
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
title: "Get all notifications from the past week",
|
|
103
|
+
input: {
|
|
104
|
+
view: "all",
|
|
105
|
+
createdAfter: "2025-04-03T00:00:00Z",
|
|
106
|
+
limit: 25
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
title: "Get high-priority unread alerts",
|
|
111
|
+
input: { minimumSeverity: "high" }
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
action: async ({ input, credentials, logger }) => {
|
|
115
|
+
if (!auth.isPrincipal(credentials, "user")) {
|
|
116
|
+
throw new errors.NotAllowedError("This action requires user credentials");
|
|
117
|
+
}
|
|
118
|
+
const { userEntityRef } = credentials.principal;
|
|
119
|
+
logger.info(
|
|
120
|
+
`Fetching notifications for user "${userEntityRef}" (view=${input.view ?? "unread"})`
|
|
121
|
+
);
|
|
122
|
+
let read;
|
|
123
|
+
if (input.view === "unread" || input.view === void 0) {
|
|
124
|
+
read = false;
|
|
125
|
+
} else if (input.view === "read") {
|
|
126
|
+
read = true;
|
|
127
|
+
}
|
|
128
|
+
const opts = {
|
|
129
|
+
user: userEntityRef,
|
|
130
|
+
offset: input.offset ?? 0,
|
|
131
|
+
limit: input.limit ?? 10,
|
|
132
|
+
search: input.search,
|
|
133
|
+
topic: input.topic,
|
|
134
|
+
minimumSeverity: input.minimumSeverity,
|
|
135
|
+
createdAfter: input.createdAfter ? new Date(input.createdAfter) : void 0,
|
|
136
|
+
read,
|
|
137
|
+
saved: input.view === "saved" ? true : void 0
|
|
138
|
+
};
|
|
139
|
+
const [notifications, totalCount] = await Promise.all([
|
|
140
|
+
store.getNotifications(opts),
|
|
141
|
+
store.getNotificationsCount(opts)
|
|
142
|
+
]);
|
|
143
|
+
return {
|
|
144
|
+
output: {
|
|
145
|
+
notifications,
|
|
146
|
+
totalCount
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
exports.createGetNotificationsAction = createGetNotificationsAction;
|
|
154
|
+
//# sourceMappingURL=createGetNotificationsAction.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createGetNotificationsAction.cjs.js","sources":["../../src/actions/createGetNotificationsAction.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 */\nimport { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha';\nimport { AuthService } from '@backstage/backend-plugin-api';\nimport { NotAllowedError } from '@backstage/errors';\nimport { NotificationsStore } from '../database';\n\nexport const createGetNotificationsAction = ({\n store,\n auth,\n actionsRegistry,\n}: {\n store: NotificationsStore;\n auth: AuthService;\n actionsRegistry: ActionsRegistryService;\n}) => {\n actionsRegistry.register({\n name: 'get-notifications',\n title: 'Get Notifications',\n description: `\nFetches notifications for the currently authenticated user from the Backstage notifications system.\n\nEach notification has an \\`id\\`, \\`origin\\` (the plugin or service that sent it), a \\`payload\\` with\n\\`title\\`, optional \\`description\\`, optional \\`link\\`, \\`severity\\` (one of \"critical\", \"high\", \"normal\", \"low\"),\nand optional \\`topic\\`. Notifications also carry \\`created\\` and optionally \\`read\\`, \\`saved\\`, and \\`updated\\` timestamps.\n\n## Filters\n\nUse the \\`view\\` field to control which notifications are returned:\n- \\`\"unread\"\\` (default) — only notifications the user has not yet read. Use this to surface new, actionable items.\n- \\`\"read\"\\` — only notifications the user has already read.\n- \\`\"saved\"\\` — only notifications the user has explicitly saved/bookmarked.\n- \\`\"all\"\\` — all notifications regardless of read or saved status.\n\nAdditional filters can be combined with \\`view\\`:\n- \\`search\\` — free-text search across notification titles and descriptions.\n- \\`topic\\` — filter to a specific topic string, e.g. \"ci/cd\" or \"deployment\".\n- \\`minimumSeverity\\` — minimum severity level; returns this severity and anything more severe (\"critical\" > \"high\" > \"normal\" > \"low\").\n- \\`createdAfter\\` — ISO 8601 datetime string; only return notifications created after this time.\n\n## Pagination\n\nUse \\`offset\\` and \\`limit\\` to paginate. The response includes \\`totalCount\\` so you can calculate further pages.\n\n## Examples\n\n- Get my unread notifications: use default values (no input required).\n- Get all notifications from the past week: set \\`view: \"all\"\\` and \\`createdAfter\\` to 7 days ago.\n- Get high-priority unread alerts: set \\`minimumSeverity: \"high\"\\` (view defaults to \"unread\").\n `,\n attributes: {\n destructive: false,\n readOnly: true,\n idempotent: true,\n },\n schema: {\n input: z =>\n z.object({\n view: z\n .enum(['unread', 'read', 'saved', 'all'])\n .optional()\n .describe(\n 'Which notifications to return. Defaults to \"unread\". \"unread\" returns only unread notifications, \"read\" returns only read notifications, \"saved\" returns bookmarked notifications, \"all\" returns everything.',\n ),\n search: z\n .string()\n .optional()\n .describe(\n 'Free-text search string to filter notifications by title or description.',\n ),\n topic: z\n .string()\n .optional()\n .describe(\n 'Filter to notifications with this specific topic, e.g. \"ci/cd\".',\n ),\n minimumSeverity: z\n .enum(['critical', 'high', 'normal', 'low'])\n .optional()\n .describe(\n 'Minimum severity to include. \"critical\" is most severe, \"low\" is least. For example, \"high\" returns \"critical\" and \"high\" notifications only.',\n ),\n createdAfter: z\n .string()\n .optional()\n .describe(\n 'ISO 8601 datetime string. Only return notifications created after this time, e.g. \"2025-01-01T00:00:00Z\".',\n ),\n offset: z\n .number()\n .int()\n .min(0)\n .optional()\n .describe(\n 'Number of notifications to skip for pagination. Defaults to 0.',\n ),\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .describe(\n 'Maximum number of notifications to return (1–100). Defaults to 10.',\n ),\n }),\n output: z =>\n z.object({\n notifications: z\n .array(z.object({}).passthrough())\n .describe('List of notifications matching the filters.'),\n totalCount: z\n .number()\n .describe(\n 'Total number of notifications matching the filters, useful for pagination.',\n ),\n }),\n },\n examples: [\n {\n title: 'Get my unread notifications',\n description: 'Returns up to 10 unread notifications (the default).',\n input: {},\n output: {\n notifications: [\n {\n id: 'abc123',\n origin: 'catalog',\n created: '2025-04-01T10:00:00.000Z',\n payload: {\n title: 'Component entity missing owner',\n severity: 'high',\n link: '/catalog/default/component/my-service',\n },\n },\n ],\n totalCount: 1,\n },\n },\n {\n title: 'Get all notifications from the past week',\n input: {\n view: 'all',\n createdAfter: '2025-04-03T00:00:00Z',\n limit: 25,\n },\n },\n {\n title: 'Get high-priority unread alerts',\n input: { minimumSeverity: 'high' },\n },\n ],\n action: async ({ input, credentials, logger }) => {\n if (!auth.isPrincipal(credentials, 'user')) {\n throw new NotAllowedError('This action requires user credentials');\n }\n\n const { userEntityRef } = credentials.principal;\n\n logger.info(\n `Fetching notifications for user \"${userEntityRef}\" (view=${\n input.view ?? 'unread'\n })`,\n );\n\n let read: boolean | undefined;\n if (input.view === 'unread' || input.view === undefined) {\n read = false;\n } else if (input.view === 'read') {\n read = true;\n }\n\n const opts = {\n user: userEntityRef,\n offset: input.offset ?? 0,\n limit: input.limit ?? 10,\n search: input.search,\n topic: input.topic,\n minimumSeverity: input.minimumSeverity,\n createdAfter: input.createdAfter\n ? new Date(input.createdAfter)\n : undefined,\n read,\n saved: input.view === 'saved' ? true : undefined,\n };\n\n const [notifications, totalCount] = await Promise.all([\n store.getNotifications(opts),\n store.getNotificationsCount(opts),\n ]);\n\n return {\n output: {\n notifications,\n totalCount,\n },\n };\n },\n });\n};\n"],"names":["NotAllowedError"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var createGetNotificationsAction = require('./createGetNotificationsAction.cjs.js');
|
|
4
|
+
|
|
5
|
+
const createNotificationsActions = (options) => {
|
|
6
|
+
createGetNotificationsAction.createGetNotificationsAction(options);
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
exports.createNotificationsActions = createNotificationsActions;
|
|
10
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../../src/actions/index.ts"],"sourcesContent":["/*\n * Copyright 2025 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 */\nimport { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha';\nimport { AuthService } from '@backstage/backend-plugin-api';\nimport { NotificationsStore } from '../database';\nimport { createGetNotificationsAction } from './createGetNotificationsAction';\n\nexport const createNotificationsActions = (options: {\n actionsRegistry: ActionsRegistryService;\n auth: AuthService;\n store: NotificationsStore;\n}) => {\n createGetNotificationsAction(options);\n};\n"],"names":["createGetNotificationsAction"],"mappings":";;;;AAoBO,MAAM,0BAAA,GAA6B,CAAC,OAAA,KAIrC;AACJ,EAAAA,yDAAA,CAA6B,OAAO,CAAA;AACtC;;;;"}
|
|
@@ -184,10 +184,10 @@ class DatabaseNotificationsStore {
|
|
|
184
184
|
query.where("created", ">=", options.createdAfter.toISOString());
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
|
-
if (options.limit) {
|
|
187
|
+
if (options.limit !== void 0) {
|
|
188
188
|
query.limit(options.limit);
|
|
189
189
|
}
|
|
190
|
-
if (options.offset) {
|
|
190
|
+
if (options.offset !== void 0) {
|
|
191
191
|
query.offset(options.offset);
|
|
192
192
|
}
|
|
193
193
|
if (options.search) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatabaseNotificationsStore.cjs.js","sources":["../../src/database/DatabaseNotificationsStore.ts"],"sourcesContent":["/*\n * Copyright 2023 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 */\nimport {\n DatabaseService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\nimport {\n NotificationGetOptions,\n NotificationModifyOptions,\n NotificationsStore,\n TopicGetOptions,\n} from './NotificationsStore';\nimport {\n Notification,\n NotificationSettings,\n notificationSeverities,\n NotificationSeverity,\n} from '@backstage/plugin-notifications-common';\nimport { Knex } from 'knex';\nimport crypto from 'node:crypto';\nimport { durationToMilliseconds, HumanDuration } from '@backstage/types';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage/plugin-notifications-backend',\n 'migrations',\n);\n\nconst NOTIFICATION_COLUMNS = [\n 'id',\n 'title',\n 'description',\n 'severity',\n 'link',\n 'origin',\n 'scope',\n 'topic',\n 'icon',\n 'created',\n 'updated',\n 'user',\n 'read',\n 'saved',\n];\n\ntype NotificationRowType = {\n id: string;\n user: string;\n title: string;\n description?: string | null;\n severity: string;\n link: string | null;\n origin: string;\n scope: string | null;\n topic: string | null;\n created: Date;\n updated: Date | null;\n read: Date | null;\n saved: Date | null;\n icon: string | null;\n};\n\ntype BroadcastRowType = {\n id: string;\n title: string;\n description: string | null;\n link: string | null;\n origin: string;\n scope: string | null;\n topic: string | null;\n created: Date;\n updated: Date | null;\n icon: string | null;\n};\n\ntype BroadcastUserStatusRowType = {\n broadcast_id: string;\n user: string;\n read: Date | null;\n saved: Date | null;\n};\n\ntype UserSettingsRowType = {\n user: string;\n channel: string;\n origin: string;\n enabled: boolean;\n};\n\nexport const normalizeSeverity = (input?: string): NotificationSeverity => {\n let lower = (input ?? 'normal').toLowerCase() as NotificationSeverity;\n if (notificationSeverities.indexOf(lower) < 0) {\n lower = 'normal';\n }\n return lower;\n};\n\nexport const generateSettingsHash = (\n user: string,\n channel: string,\n origin: string,\n topic: string | null,\n): string => {\n const rawKey = `${user}|${channel}|${origin}|${topic ?? ''}`;\n return crypto.createHash('sha256').update(rawKey).digest('hex');\n};\n\n/** @internal */\nexport class DatabaseNotificationsStore implements NotificationsStore {\n private readonly isSQLite = false;\n\n private readonly db: Knex;\n\n private constructor(db: Knex) {\n this.db = db;\n this.isSQLite = this.db.client.config.client.includes('sqlite3');\n }\n\n static async create({\n database,\n skipMigrations,\n }: {\n database: DatabaseService;\n skipMigrations?: boolean;\n }): Promise<DatabaseNotificationsStore> {\n const client = await database.getClient();\n\n if (!database.migrations?.skip && !skipMigrations) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n return new DatabaseNotificationsStore(client);\n }\n\n private mapToInteger = (val: string | number | undefined): number => {\n return typeof val === 'string' ? Number.parseInt(val, 10) : val ?? 0;\n };\n\n private mapToNotifications = (rows: any[]): Notification[] => {\n return rows.map(row => ({\n id: row.id,\n user: row.type === 'broadcast' ? null : row.user,\n created: new Date(row.created),\n saved: row.saved,\n read: row.read,\n updated: row.updated,\n origin: row.origin,\n payload: {\n title: row.title,\n description: row.description,\n link: row.link,\n topic: row.topic,\n severity: row.severity,\n scope: row.scope,\n icon: row.icon,\n },\n }));\n };\n\n private mapToNotificationSettings = (rows: any[]): NotificationSettings => {\n return rows.reduce(\n (acc, row) => {\n let chan = acc.channels.find(\n (channel: { id: string }) => channel.id === row.channel,\n );\n if (!chan) {\n acc.channels.push({\n id: row.channel,\n origins: [],\n });\n chan = acc.channels[acc.channels.length - 1];\n }\n let origin = chan.origins.find(\n (ori: { id: string }) => ori.id === row.origin,\n );\n if (!origin) {\n origin = {\n id: row.origin,\n enabled: true,\n topics: [],\n };\n chan.origins.push(origin);\n }\n if (row.topic === null) {\n origin.enabled = Boolean(row.enabled);\n } else {\n let topic = origin.topics.find(\n (top: { id: string }) => top.id === row.topic,\n );\n if (!topic) {\n topic = {\n id: row.topic,\n enabled: Boolean(row.enabled),\n };\n origin.topics.push(topic);\n }\n }\n return acc;\n },\n { channels: [] },\n );\n };\n\n private mapNotificationToDbRow = (notification: Notification) => {\n return {\n id: notification.id,\n user: notification.user,\n origin: notification.origin,\n created: notification.created,\n topic: notification.payload?.topic,\n link: notification.payload?.link,\n title: notification.payload?.title,\n description: notification.payload?.description,\n severity: normalizeSeverity(notification.payload?.severity),\n scope: notification.payload?.scope,\n icon: notification.payload.icon,\n saved: notification.saved,\n read: notification.read,\n };\n };\n\n private mapBroadcastToDbRow = (notification: Notification) => {\n return {\n id: notification.id,\n origin: notification.origin,\n created: notification.created,\n topic: notification.payload?.topic,\n link: notification.payload?.link,\n title: notification.payload?.title,\n description: notification.payload?.description,\n severity: normalizeSeverity(notification.payload?.severity),\n icon: notification.payload.icon,\n scope: notification.payload?.scope,\n };\n };\n\n private getBroadcastUnion = (user?: string | null) => {\n return this.db<BroadcastRowType>('broadcast')\n .leftJoin('broadcast_user_status', function clause() {\n const join = this.on('id', '=', 'broadcast_user_status.broadcast_id');\n if (user !== null && user !== undefined) {\n join.andOnVal('user', '=', user);\n }\n })\n .select([...NOTIFICATION_COLUMNS, this.db.raw(\"'broadcast' as type\")]);\n };\n\n private getNotificationsBaseQuery = (\n options: NotificationGetOptions | NotificationModifyOptions,\n ) => {\n const { user, orderField } = options;\n\n const subQuery = this.db<NotificationRowType>('notification')\n .select([...NOTIFICATION_COLUMNS, this.db.raw(\"'entity' as type\")])\n .unionAll([this.getBroadcastUnion(user)])\n .as('notifications');\n\n const query = this.db.from(subQuery).where(q => {\n q.where('user', user).orWhereNull('user');\n });\n\n if (orderField && orderField.length > 0) {\n orderField.forEach(orderBy => {\n query.orderBy(orderBy.field, orderBy.order);\n });\n } else if (!orderField) {\n query.orderBy('created', 'desc');\n }\n\n if (options.createdAfter) {\n if (this.isSQLite) {\n query.where('created', '>=', options.createdAfter.valueOf());\n } else {\n query.where('created', '>=', options.createdAfter.toISOString());\n }\n }\n\n if (options.limit) {\n query.limit(options.limit);\n }\n\n if (options.offset) {\n query.offset(options.offset);\n }\n\n if (options.search) {\n query.whereRaw(\n `(LOWER(title) LIKE LOWER(?) OR LOWER(description) LIKE LOWER(?))`,\n [`%${options.search}%`, `%${options.search}%`],\n );\n }\n\n if (options.ids) {\n query.whereIn('id', options.ids);\n }\n\n if (options.read) {\n query.whereNotNull('read');\n } else if (options.read === false) {\n query.whereNull('read');\n } // or match both if undefined\n\n if (options.topic) {\n query.where('topic', '=', options.topic);\n }\n\n if (options.saved) {\n query.whereNotNull('saved');\n } else if (options.saved === false) {\n query.whereNull('saved');\n } // or match both if undefined\n\n if (options.minimumSeverity !== undefined) {\n const idx = notificationSeverities.indexOf(options.minimumSeverity);\n const equalOrHigher = notificationSeverities.slice(0, idx + 1);\n query.whereIn('severity', equalOrHigher);\n }\n\n return query;\n };\n\n async getNotifications(options: NotificationGetOptions) {\n const notificationQuery = this.getNotificationsBaseQuery(options);\n const notifications = await notificationQuery.select([\n ...NOTIFICATION_COLUMNS,\n 'type',\n ]);\n return this.mapToNotifications(notifications);\n }\n\n async getNotificationsCount(options: NotificationGetOptions) {\n const countOptions: NotificationGetOptions = { ...options };\n countOptions.limit = undefined;\n countOptions.offset = undefined;\n countOptions.orderField = [];\n const notificationQuery = this.getNotificationsBaseQuery(countOptions);\n const response = await notificationQuery.count('id as CNT');\n return Number(response[0].CNT);\n }\n\n async saveNotification(notification: Notification) {\n await this.db\n .insert(this.mapNotificationToDbRow(notification))\n .into('notification');\n }\n\n async saveBroadcast(notification: Notification) {\n await this.db\n .insert(this.mapBroadcastToDbRow(notification))\n .into('broadcast');\n if (notification.saved || notification.read) {\n await this.db\n .insert({\n user: notification.user,\n broadcast_id: notification.id,\n saved: notification.saved,\n read: notification.read,\n })\n .into('broadcast_user_status');\n }\n }\n\n async getStatus(options: NotificationGetOptions) {\n const notificationQuery = this.getNotificationsBaseQuery({\n ...options,\n orderField: [],\n });\n const readSubQuery = notificationQuery\n .clone()\n .count('id')\n .whereNotNull('read')\n .as('READ');\n const unreadSubQuery = notificationQuery\n .clone()\n .count('id')\n .whereNull('read')\n .as('UNREAD');\n\n const query = await notificationQuery\n .select(readSubQuery, unreadSubQuery)\n .first();\n\n return {\n unread: this.mapToInteger((query as any)?.UNREAD),\n read: this.mapToInteger((query as any)?.READ),\n };\n }\n\n async getExistingScopeNotification(options: {\n user: string;\n scope: string;\n origin: string;\n }) {\n const query = this.db<NotificationRowType>('notification')\n .where('user', options.user)\n .where('scope', options.scope)\n .where('origin', options.origin)\n .limit(1);\n\n const rows = await query;\n if (!rows || rows.length === 0) {\n return null;\n }\n return this.mapToNotifications(rows)[0];\n }\n\n async getExistingScopeBroadcast(options: { scope: string; origin: string }) {\n const query = this.db<BroadcastRowType>('broadcast')\n .where('scope', options.scope)\n .where('origin', options.origin)\n .limit(1);\n\n const rows = await query;\n if (!rows || rows.length === 0) {\n return null;\n }\n return this.mapToNotifications(rows)[0];\n }\n\n async restoreExistingNotification({\n id,\n notification,\n }: {\n id: string;\n notification: Notification;\n }) {\n const updateColumns = {\n title: notification.payload.title,\n description: notification.payload.description,\n link: notification.payload.link,\n topic: notification.payload.topic,\n updated: new Date(),\n severity: normalizeSeverity(notification.payload?.severity),\n read: null,\n };\n\n const notificationQuery = this.db('notification')\n .where('id', id)\n .where('user', notification.user);\n const broadcastQuery = this.db('broadcast').where('id', id);\n\n await Promise.all([\n notificationQuery.update(updateColumns),\n broadcastQuery.update({ ...updateColumns, read: undefined }),\n ]);\n\n return await this.getNotification({ id, user: notification.user });\n }\n\n async getNotification(options: {\n id: string;\n user?: string | null;\n }): Promise<Notification | null> {\n const rows = await this.db\n .select('*')\n .from(\n this.db<NotificationRowType>('notification')\n .select([...NOTIFICATION_COLUMNS, this.db.raw(\"'entity' as type\")])\n .unionAll([this.getBroadcastUnion(options.user)])\n .as('notifications'),\n )\n .where('id', options.id)\n .limit(1);\n if (!rows || rows.length === 0) {\n return null;\n }\n return this.mapToNotifications(rows)[0];\n }\n\n private markReadSaved = async (\n ids: string[],\n user: string,\n read?: Date | null,\n saved?: Date | null,\n ) => {\n await this.db<NotificationRowType>('notification')\n .whereIn('id', ids)\n .where('user', user)\n .update({ read, saved });\n\n const broadcasts = this.mapToNotifications(\n await this.db('broadcast').whereIn('id', ids).select(),\n );\n\n if (broadcasts.length > 0)\n if (!this.isSQLite) {\n await this.db<BroadcastUserStatusRowType>('broadcast_user_status')\n .insert(\n broadcasts.map(b => ({\n broadcast_id: b.id,\n user,\n read,\n saved,\n })),\n )\n .onConflict(['broadcast_id', 'user'])\n .merge(['read', 'saved']);\n } else {\n // SQLite does not support upsert so fall back to this (mostly for tests and local dev)\n for (const b of broadcasts) {\n const baseQuery = this.db<BroadcastUserStatusRowType>(\n 'broadcast_user_status',\n )\n .where('broadcast_id', b.id)\n .where('user', user);\n const exists = await baseQuery.clone().limit(1).select().first();\n if (exists) {\n await baseQuery.clone().update({ read, saved });\n } else {\n await baseQuery\n .clone()\n .insert({ broadcast_id: b.id, user, read, saved });\n }\n }\n }\n };\n\n async markRead(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, new Date(), undefined);\n }\n\n async markUnread(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, null, undefined);\n }\n\n async markSaved(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, undefined, new Date());\n }\n\n async markUnsaved(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, undefined, null);\n }\n\n async getUserNotificationOrigins(options: {\n user: string;\n }): Promise<{ origins: string[] }> {\n const rows: { origin: string }[] = await this.db<NotificationRowType>(\n 'notification',\n )\n .where('user', options.user)\n .select('origin')\n .distinct();\n return { origins: rows.map(row => row.origin) };\n }\n\n async getUserNotificationTopics(options: {\n user: string;\n }): Promise<{ topics: { origin: string; topic: string }[] }> {\n const rows: { topic: string; origin: string }[] =\n await this.db<NotificationRowType>('notification')\n .where('user', options.user)\n .select('topic', 'origin')\n .whereNotNull('topic')\n .distinct();\n\n return {\n topics: rows.map(row => ({ origin: row.origin, topic: row.topic })),\n };\n }\n\n async getNotificationSettings(options: {\n user: string;\n origin?: string;\n channel?: string;\n topic?: string;\n }): Promise<NotificationSettings> {\n const settingsQuery = this.db<UserSettingsRowType>('user_settings').where(\n 'user',\n options.user,\n );\n if (options.origin) {\n settingsQuery.where('origin', options.origin);\n }\n\n if (options.channel) {\n settingsQuery.where('channel', options.channel);\n }\n\n if (options.topic) {\n settingsQuery.where('topic', options.topic);\n }\n const settings = await settingsQuery.select();\n return this.mapToNotificationSettings(settings);\n }\n\n async saveNotificationSettings(options: {\n user: string;\n settings: NotificationSettings;\n }): Promise<void> {\n const rows: {\n settings_key_hash: string;\n user: string;\n channel: string;\n origin: string;\n topic: string | null;\n enabled: boolean;\n }[] = [];\n\n options.settings.channels.forEach(channel => {\n channel.origins.forEach(origin => {\n rows.push({\n settings_key_hash: generateSettingsHash(\n options.user,\n channel.id,\n origin.id,\n null,\n ),\n user: options.user,\n channel: channel.id,\n origin: origin.id,\n topic: null,\n enabled: origin.enabled,\n });\n\n origin.topics?.forEach(topic => {\n rows.push({\n settings_key_hash: generateSettingsHash(\n options.user,\n channel.id,\n origin.id,\n topic.id,\n ),\n user: options.user,\n channel: channel.id,\n origin: origin.id,\n topic: topic.id,\n enabled: origin.enabled && topic.enabled,\n });\n });\n });\n });\n\n await this.db<UserSettingsRowType>('user_settings')\n .where('user', options.user)\n .delete();\n await this.db<UserSettingsRowType>('user_settings').insert(rows);\n }\n\n async getTopics(options: TopicGetOptions): Promise<{ topics: string[] }> {\n const notificationQuery = this.getNotificationsBaseQuery({\n ...options,\n orderField: [{ field: 'topic', order: 'asc' }],\n });\n const topics = await notificationQuery\n .whereNotNull('topic')\n .distinct(['topic']);\n return { topics: topics.map(row => row.topic) };\n }\n\n async clearNotifications(options: {\n maxAge: HumanDuration;\n }): Promise<{ deletedCount: number }> {\n const ms = durationToMilliseconds(options.maxAge);\n const now = new Date(new Date().getTime() - ms);\n const notificationsCount = await this.db('notification')\n .where(builder => {\n builder.where('created', '<=', now).whereNull('updated');\n })\n .orWhere('updated', '<=', now)\n .delete();\n const broadcastsCount = await this.db('broadcast')\n .where(builder => {\n builder.where('created', '<=', now).whereNull('updated');\n })\n .orWhere('updated', '<=', now)\n .delete();\n return { deletedCount: notificationsCount + broadcastsCount };\n }\n}\n"],"names":["resolvePackagePath","notificationSeverities","crypto","durationToMilliseconds"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DatabaseNotificationsStore.cjs.js","sources":["../../src/database/DatabaseNotificationsStore.ts"],"sourcesContent":["/*\n * Copyright 2023 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 */\nimport {\n DatabaseService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\nimport {\n NotificationGetOptions,\n NotificationModifyOptions,\n NotificationsStore,\n TopicGetOptions,\n} from './NotificationsStore';\nimport {\n Notification,\n NotificationSettings,\n notificationSeverities,\n NotificationSeverity,\n} from '@backstage/plugin-notifications-common';\nimport { Knex } from 'knex';\nimport crypto from 'node:crypto';\nimport { durationToMilliseconds, HumanDuration } from '@backstage/types';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage/plugin-notifications-backend',\n 'migrations',\n);\n\nconst NOTIFICATION_COLUMNS = [\n 'id',\n 'title',\n 'description',\n 'severity',\n 'link',\n 'origin',\n 'scope',\n 'topic',\n 'icon',\n 'created',\n 'updated',\n 'user',\n 'read',\n 'saved',\n];\n\ntype NotificationRowType = {\n id: string;\n user: string;\n title: string;\n description?: string | null;\n severity: string;\n link: string | null;\n origin: string;\n scope: string | null;\n topic: string | null;\n created: Date;\n updated: Date | null;\n read: Date | null;\n saved: Date | null;\n icon: string | null;\n};\n\ntype BroadcastRowType = {\n id: string;\n title: string;\n description: string | null;\n link: string | null;\n origin: string;\n scope: string | null;\n topic: string | null;\n created: Date;\n updated: Date | null;\n icon: string | null;\n};\n\ntype BroadcastUserStatusRowType = {\n broadcast_id: string;\n user: string;\n read: Date | null;\n saved: Date | null;\n};\n\ntype UserSettingsRowType = {\n user: string;\n channel: string;\n origin: string;\n enabled: boolean;\n};\n\nexport const normalizeSeverity = (input?: string): NotificationSeverity => {\n let lower = (input ?? 'normal').toLowerCase() as NotificationSeverity;\n if (notificationSeverities.indexOf(lower) < 0) {\n lower = 'normal';\n }\n return lower;\n};\n\nexport const generateSettingsHash = (\n user: string,\n channel: string,\n origin: string,\n topic: string | null,\n): string => {\n const rawKey = `${user}|${channel}|${origin}|${topic ?? ''}`;\n return crypto.createHash('sha256').update(rawKey).digest('hex');\n};\n\n/** @internal */\nexport class DatabaseNotificationsStore implements NotificationsStore {\n private readonly isSQLite = false;\n\n private readonly db: Knex;\n\n private constructor(db: Knex) {\n this.db = db;\n this.isSQLite = this.db.client.config.client.includes('sqlite3');\n }\n\n static async create({\n database,\n skipMigrations,\n }: {\n database: DatabaseService;\n skipMigrations?: boolean;\n }): Promise<DatabaseNotificationsStore> {\n const client = await database.getClient();\n\n if (!database.migrations?.skip && !skipMigrations) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n return new DatabaseNotificationsStore(client);\n }\n\n private mapToInteger = (val: string | number | undefined): number => {\n return typeof val === 'string' ? Number.parseInt(val, 10) : val ?? 0;\n };\n\n private mapToNotifications = (rows: any[]): Notification[] => {\n return rows.map(row => ({\n id: row.id,\n user: row.type === 'broadcast' ? null : row.user,\n created: new Date(row.created),\n saved: row.saved,\n read: row.read,\n updated: row.updated,\n origin: row.origin,\n payload: {\n title: row.title,\n description: row.description,\n link: row.link,\n topic: row.topic,\n severity: row.severity,\n scope: row.scope,\n icon: row.icon,\n },\n }));\n };\n\n private mapToNotificationSettings = (rows: any[]): NotificationSettings => {\n return rows.reduce(\n (acc, row) => {\n let chan = acc.channels.find(\n (channel: { id: string }) => channel.id === row.channel,\n );\n if (!chan) {\n acc.channels.push({\n id: row.channel,\n origins: [],\n });\n chan = acc.channels[acc.channels.length - 1];\n }\n let origin = chan.origins.find(\n (ori: { id: string }) => ori.id === row.origin,\n );\n if (!origin) {\n origin = {\n id: row.origin,\n enabled: true,\n topics: [],\n };\n chan.origins.push(origin);\n }\n if (row.topic === null) {\n origin.enabled = Boolean(row.enabled);\n } else {\n let topic = origin.topics.find(\n (top: { id: string }) => top.id === row.topic,\n );\n if (!topic) {\n topic = {\n id: row.topic,\n enabled: Boolean(row.enabled),\n };\n origin.topics.push(topic);\n }\n }\n return acc;\n },\n { channels: [] },\n );\n };\n\n private mapNotificationToDbRow = (notification: Notification) => {\n return {\n id: notification.id,\n user: notification.user,\n origin: notification.origin,\n created: notification.created,\n topic: notification.payload?.topic,\n link: notification.payload?.link,\n title: notification.payload?.title,\n description: notification.payload?.description,\n severity: normalizeSeverity(notification.payload?.severity),\n scope: notification.payload?.scope,\n icon: notification.payload.icon,\n saved: notification.saved,\n read: notification.read,\n };\n };\n\n private mapBroadcastToDbRow = (notification: Notification) => {\n return {\n id: notification.id,\n origin: notification.origin,\n created: notification.created,\n topic: notification.payload?.topic,\n link: notification.payload?.link,\n title: notification.payload?.title,\n description: notification.payload?.description,\n severity: normalizeSeverity(notification.payload?.severity),\n icon: notification.payload.icon,\n scope: notification.payload?.scope,\n };\n };\n\n private getBroadcastUnion = (user?: string | null) => {\n return this.db<BroadcastRowType>('broadcast')\n .leftJoin('broadcast_user_status', function clause() {\n const join = this.on('id', '=', 'broadcast_user_status.broadcast_id');\n if (user !== null && user !== undefined) {\n join.andOnVal('user', '=', user);\n }\n })\n .select([...NOTIFICATION_COLUMNS, this.db.raw(\"'broadcast' as type\")]);\n };\n\n private getNotificationsBaseQuery = (\n options: NotificationGetOptions | NotificationModifyOptions,\n ) => {\n const { user, orderField } = options;\n\n const subQuery = this.db<NotificationRowType>('notification')\n .select([...NOTIFICATION_COLUMNS, this.db.raw(\"'entity' as type\")])\n .unionAll([this.getBroadcastUnion(user)])\n .as('notifications');\n\n const query = this.db.from(subQuery).where(q => {\n q.where('user', user).orWhereNull('user');\n });\n\n if (orderField && orderField.length > 0) {\n orderField.forEach(orderBy => {\n query.orderBy(orderBy.field, orderBy.order);\n });\n } else if (!orderField) {\n query.orderBy('created', 'desc');\n }\n\n if (options.createdAfter) {\n if (this.isSQLite) {\n query.where('created', '>=', options.createdAfter.valueOf());\n } else {\n query.where('created', '>=', options.createdAfter.toISOString());\n }\n }\n\n if (options.limit !== undefined) {\n query.limit(options.limit);\n }\n\n if (options.offset !== undefined) {\n query.offset(options.offset);\n }\n\n if (options.search) {\n query.whereRaw(\n `(LOWER(title) LIKE LOWER(?) OR LOWER(description) LIKE LOWER(?))`,\n [`%${options.search}%`, `%${options.search}%`],\n );\n }\n\n if (options.ids) {\n query.whereIn('id', options.ids);\n }\n\n if (options.read) {\n query.whereNotNull('read');\n } else if (options.read === false) {\n query.whereNull('read');\n } // or match both if undefined\n\n if (options.topic) {\n query.where('topic', '=', options.topic);\n }\n\n if (options.saved) {\n query.whereNotNull('saved');\n } else if (options.saved === false) {\n query.whereNull('saved');\n } // or match both if undefined\n\n if (options.minimumSeverity !== undefined) {\n const idx = notificationSeverities.indexOf(options.minimumSeverity);\n const equalOrHigher = notificationSeverities.slice(0, idx + 1);\n query.whereIn('severity', equalOrHigher);\n }\n\n return query;\n };\n\n async getNotifications(options: NotificationGetOptions) {\n const notificationQuery = this.getNotificationsBaseQuery(options);\n const notifications = await notificationQuery.select([\n ...NOTIFICATION_COLUMNS,\n 'type',\n ]);\n return this.mapToNotifications(notifications);\n }\n\n async getNotificationsCount(options: NotificationGetOptions) {\n const countOptions: NotificationGetOptions = { ...options };\n countOptions.limit = undefined;\n countOptions.offset = undefined;\n countOptions.orderField = [];\n const notificationQuery = this.getNotificationsBaseQuery(countOptions);\n const response = await notificationQuery.count('id as CNT');\n return Number(response[0].CNT);\n }\n\n async saveNotification(notification: Notification) {\n await this.db\n .insert(this.mapNotificationToDbRow(notification))\n .into('notification');\n }\n\n async saveBroadcast(notification: Notification) {\n await this.db\n .insert(this.mapBroadcastToDbRow(notification))\n .into('broadcast');\n if (notification.saved || notification.read) {\n await this.db\n .insert({\n user: notification.user,\n broadcast_id: notification.id,\n saved: notification.saved,\n read: notification.read,\n })\n .into('broadcast_user_status');\n }\n }\n\n async getStatus(options: NotificationGetOptions) {\n const notificationQuery = this.getNotificationsBaseQuery({\n ...options,\n orderField: [],\n });\n const readSubQuery = notificationQuery\n .clone()\n .count('id')\n .whereNotNull('read')\n .as('READ');\n const unreadSubQuery = notificationQuery\n .clone()\n .count('id')\n .whereNull('read')\n .as('UNREAD');\n\n const query = await notificationQuery\n .select(readSubQuery, unreadSubQuery)\n .first();\n\n return {\n unread: this.mapToInteger((query as any)?.UNREAD),\n read: this.mapToInteger((query as any)?.READ),\n };\n }\n\n async getExistingScopeNotification(options: {\n user: string;\n scope: string;\n origin: string;\n }) {\n const query = this.db<NotificationRowType>('notification')\n .where('user', options.user)\n .where('scope', options.scope)\n .where('origin', options.origin)\n .limit(1);\n\n const rows = await query;\n if (!rows || rows.length === 0) {\n return null;\n }\n return this.mapToNotifications(rows)[0];\n }\n\n async getExistingScopeBroadcast(options: { scope: string; origin: string }) {\n const query = this.db<BroadcastRowType>('broadcast')\n .where('scope', options.scope)\n .where('origin', options.origin)\n .limit(1);\n\n const rows = await query;\n if (!rows || rows.length === 0) {\n return null;\n }\n return this.mapToNotifications(rows)[0];\n }\n\n async restoreExistingNotification({\n id,\n notification,\n }: {\n id: string;\n notification: Notification;\n }) {\n const updateColumns = {\n title: notification.payload.title,\n description: notification.payload.description,\n link: notification.payload.link,\n topic: notification.payload.topic,\n updated: new Date(),\n severity: normalizeSeverity(notification.payload?.severity),\n read: null,\n };\n\n const notificationQuery = this.db('notification')\n .where('id', id)\n .where('user', notification.user);\n const broadcastQuery = this.db('broadcast').where('id', id);\n\n await Promise.all([\n notificationQuery.update(updateColumns),\n broadcastQuery.update({ ...updateColumns, read: undefined }),\n ]);\n\n return await this.getNotification({ id, user: notification.user });\n }\n\n async getNotification(options: {\n id: string;\n user?: string | null;\n }): Promise<Notification | null> {\n const rows = await this.db\n .select('*')\n .from(\n this.db<NotificationRowType>('notification')\n .select([...NOTIFICATION_COLUMNS, this.db.raw(\"'entity' as type\")])\n .unionAll([this.getBroadcastUnion(options.user)])\n .as('notifications'),\n )\n .where('id', options.id)\n .limit(1);\n if (!rows || rows.length === 0) {\n return null;\n }\n return this.mapToNotifications(rows)[0];\n }\n\n private markReadSaved = async (\n ids: string[],\n user: string,\n read?: Date | null,\n saved?: Date | null,\n ) => {\n await this.db<NotificationRowType>('notification')\n .whereIn('id', ids)\n .where('user', user)\n .update({ read, saved });\n\n const broadcasts = this.mapToNotifications(\n await this.db('broadcast').whereIn('id', ids).select(),\n );\n\n if (broadcasts.length > 0)\n if (!this.isSQLite) {\n await this.db<BroadcastUserStatusRowType>('broadcast_user_status')\n .insert(\n broadcasts.map(b => ({\n broadcast_id: b.id,\n user,\n read,\n saved,\n })),\n )\n .onConflict(['broadcast_id', 'user'])\n .merge(['read', 'saved']);\n } else {\n // SQLite does not support upsert so fall back to this (mostly for tests and local dev)\n for (const b of broadcasts) {\n const baseQuery = this.db<BroadcastUserStatusRowType>(\n 'broadcast_user_status',\n )\n .where('broadcast_id', b.id)\n .where('user', user);\n const exists = await baseQuery.clone().limit(1).select().first();\n if (exists) {\n await baseQuery.clone().update({ read, saved });\n } else {\n await baseQuery\n .clone()\n .insert({ broadcast_id: b.id, user, read, saved });\n }\n }\n }\n };\n\n async markRead(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, new Date(), undefined);\n }\n\n async markUnread(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, null, undefined);\n }\n\n async markSaved(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, undefined, new Date());\n }\n\n async markUnsaved(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, undefined, null);\n }\n\n async getUserNotificationOrigins(options: {\n user: string;\n }): Promise<{ origins: string[] }> {\n const rows: { origin: string }[] = await this.db<NotificationRowType>(\n 'notification',\n )\n .where('user', options.user)\n .select('origin')\n .distinct();\n return { origins: rows.map(row => row.origin) };\n }\n\n async getUserNotificationTopics(options: {\n user: string;\n }): Promise<{ topics: { origin: string; topic: string }[] }> {\n const rows: { topic: string; origin: string }[] =\n await this.db<NotificationRowType>('notification')\n .where('user', options.user)\n .select('topic', 'origin')\n .whereNotNull('topic')\n .distinct();\n\n return {\n topics: rows.map(row => ({ origin: row.origin, topic: row.topic })),\n };\n }\n\n async getNotificationSettings(options: {\n user: string;\n origin?: string;\n channel?: string;\n topic?: string;\n }): Promise<NotificationSettings> {\n const settingsQuery = this.db<UserSettingsRowType>('user_settings').where(\n 'user',\n options.user,\n );\n if (options.origin) {\n settingsQuery.where('origin', options.origin);\n }\n\n if (options.channel) {\n settingsQuery.where('channel', options.channel);\n }\n\n if (options.topic) {\n settingsQuery.where('topic', options.topic);\n }\n const settings = await settingsQuery.select();\n return this.mapToNotificationSettings(settings);\n }\n\n async saveNotificationSettings(options: {\n user: string;\n settings: NotificationSettings;\n }): Promise<void> {\n const rows: {\n settings_key_hash: string;\n user: string;\n channel: string;\n origin: string;\n topic: string | null;\n enabled: boolean;\n }[] = [];\n\n options.settings.channels.forEach(channel => {\n channel.origins.forEach(origin => {\n rows.push({\n settings_key_hash: generateSettingsHash(\n options.user,\n channel.id,\n origin.id,\n null,\n ),\n user: options.user,\n channel: channel.id,\n origin: origin.id,\n topic: null,\n enabled: origin.enabled,\n });\n\n origin.topics?.forEach(topic => {\n rows.push({\n settings_key_hash: generateSettingsHash(\n options.user,\n channel.id,\n origin.id,\n topic.id,\n ),\n user: options.user,\n channel: channel.id,\n origin: origin.id,\n topic: topic.id,\n enabled: origin.enabled && topic.enabled,\n });\n });\n });\n });\n\n await this.db<UserSettingsRowType>('user_settings')\n .where('user', options.user)\n .delete();\n await this.db<UserSettingsRowType>('user_settings').insert(rows);\n }\n\n async getTopics(options: TopicGetOptions): Promise<{ topics: string[] }> {\n const notificationQuery = this.getNotificationsBaseQuery({\n ...options,\n orderField: [{ field: 'topic', order: 'asc' }],\n });\n const topics = await notificationQuery\n .whereNotNull('topic')\n .distinct(['topic']);\n return { topics: topics.map(row => row.topic) };\n }\n\n async clearNotifications(options: {\n maxAge: HumanDuration;\n }): Promise<{ deletedCount: number }> {\n const ms = durationToMilliseconds(options.maxAge);\n const now = new Date(new Date().getTime() - ms);\n const notificationsCount = await this.db('notification')\n .where(builder => {\n builder.where('created', '<=', now).whereNull('updated');\n })\n .orWhere('updated', '<=', now)\n .delete();\n const broadcastsCount = await this.db('broadcast')\n .where(builder => {\n builder.where('created', '<=', now).whereNull('updated');\n })\n .orWhere('updated', '<=', now)\n .delete();\n return { deletedCount: notificationsCount + broadcastsCount };\n }\n}\n"],"names":["resolvePackagePath","notificationSeverities","crypto","durationToMilliseconds"],"mappings":"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"}
|
package/dist/plugin.cjs.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
+
var alpha = require('@backstage/backend-plugin-api/alpha');
|
|
4
5
|
var router = require('./service/router.cjs.js');
|
|
6
|
+
var index = require('./actions/index.cjs.js');
|
|
5
7
|
var pluginSignalsNode = require('@backstage/plugin-signals-node');
|
|
6
8
|
var pluginNotificationsNode = require('@backstage/plugin-notifications-node');
|
|
7
9
|
var pluginCatalogNode = require('@backstage/plugin-catalog-node');
|
|
@@ -48,7 +50,8 @@ const notificationsPlugin = backendPluginApi.createBackendPlugin({
|
|
|
48
50
|
signals: pluginSignalsNode.signalsServiceRef,
|
|
49
51
|
config: backendPluginApi.coreServices.rootConfig,
|
|
50
52
|
catalog: pluginCatalogNode.catalogServiceRef,
|
|
51
|
-
scheduler: backendPluginApi.coreServices.scheduler
|
|
53
|
+
scheduler: backendPluginApi.coreServices.scheduler,
|
|
54
|
+
actionsRegistry: alpha.actionsRegistryServiceRef
|
|
52
55
|
},
|
|
53
56
|
async init({
|
|
54
57
|
auth,
|
|
@@ -60,7 +63,8 @@ const notificationsPlugin = backendPluginApi.createBackendPlugin({
|
|
|
60
63
|
signals,
|
|
61
64
|
config,
|
|
62
65
|
catalog,
|
|
63
|
-
scheduler
|
|
66
|
+
scheduler,
|
|
67
|
+
actionsRegistry
|
|
64
68
|
}) {
|
|
65
69
|
const store = await DatabaseNotificationsStore.DatabaseNotificationsStore.create({ database });
|
|
66
70
|
httpRouter.use(
|
|
@@ -88,6 +92,7 @@ const notificationsPlugin = backendPluginApi.createBackendPlugin({
|
|
|
88
92
|
store
|
|
89
93
|
);
|
|
90
94
|
await cleaner.initTaskRunner();
|
|
95
|
+
index.createNotificationsActions({ actionsRegistry, auth, store });
|
|
91
96
|
}
|
|
92
97
|
});
|
|
93
98
|
}
|
package/dist/plugin.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2023 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 {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\nimport { signalsServiceRef } from '@backstage/plugin-signals-node';\nimport {\n NotificationProcessor,\n NotificationRecipientResolver,\n notificationsProcessingExtensionPoint,\n NotificationsProcessingExtensionPoint,\n} from '@backstage/plugin-notifications-node';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node';\nimport { DatabaseNotificationsStore } from './database';\nimport { NotificationCleaner } from './service/NotificationCleaner.ts';\n\nclass NotificationsProcessingExtensionPointImpl\n implements NotificationsProcessingExtensionPoint\n{\n #processors = new Array<NotificationProcessor>();\n #recipientResolver: NotificationRecipientResolver | undefined = undefined;\n\n addProcessor(\n ...processors: Array<NotificationProcessor | Array<NotificationProcessor>>\n ): void {\n this.#processors.push(...processors.flat());\n }\n\n get processors() {\n return this.#processors;\n }\n\n setNotificationRecipientResolver(\n resolver: NotificationRecipientResolver,\n ): void {\n if (this.#recipientResolver) {\n throw new Error(\n 'Notification recipient resolver is already set. You can only set it once.',\n );\n }\n this.#recipientResolver = resolver;\n }\n\n get recipientResolver() {\n return this.#recipientResolver;\n }\n}\n\n/**\n * Notifications backend plugin\n *\n * @public\n */\nexport const notificationsPlugin = createBackendPlugin({\n pluginId: 'notifications',\n register(env) {\n const processingExtensions =\n new NotificationsProcessingExtensionPointImpl();\n env.registerExtensionPoint(\n notificationsProcessingExtensionPoint,\n processingExtensions,\n );\n\n env.registerInit({\n deps: {\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n userInfo: coreServices.userInfo,\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n database: coreServices.database,\n signals: signalsServiceRef,\n config: coreServices.rootConfig,\n catalog: catalogServiceRef,\n scheduler: coreServices.scheduler,\n },\n async init({\n auth,\n httpAuth,\n userInfo,\n httpRouter,\n logger,\n database,\n signals,\n config,\n catalog,\n scheduler,\n }) {\n const store = await DatabaseNotificationsStore.create({ database });\n\n httpRouter.use(\n await createRouter({\n auth,\n httpAuth,\n userInfo,\n logger,\n config,\n store,\n catalog,\n signals,\n processors: processingExtensions.processors,\n recipientResolver: processingExtensions.recipientResolver,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n\n const cleaner = new NotificationCleaner(\n config,\n scheduler,\n logger,\n store,\n );\n await cleaner.initTaskRunner();\n },\n });\n },\n});\n"],"names":["createBackendPlugin","notificationsProcessingExtensionPoint","coreServices","signalsServiceRef","catalogServiceRef","DatabaseNotificationsStore","createRouter","NotificationCleaner"],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2023 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 {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha';\nimport { createRouter } from './service/router';\nimport { createNotificationsActions } from './actions';\nimport { signalsServiceRef } from '@backstage/plugin-signals-node';\nimport {\n NotificationProcessor,\n NotificationRecipientResolver,\n notificationsProcessingExtensionPoint,\n NotificationsProcessingExtensionPoint,\n} from '@backstage/plugin-notifications-node';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node';\nimport { DatabaseNotificationsStore } from './database';\nimport { NotificationCleaner } from './service/NotificationCleaner.ts';\n\nclass NotificationsProcessingExtensionPointImpl\n implements NotificationsProcessingExtensionPoint\n{\n #processors = new Array<NotificationProcessor>();\n #recipientResolver: NotificationRecipientResolver | undefined = undefined;\n\n addProcessor(\n ...processors: Array<NotificationProcessor | Array<NotificationProcessor>>\n ): void {\n this.#processors.push(...processors.flat());\n }\n\n get processors() {\n return this.#processors;\n }\n\n setNotificationRecipientResolver(\n resolver: NotificationRecipientResolver,\n ): void {\n if (this.#recipientResolver) {\n throw new Error(\n 'Notification recipient resolver is already set. You can only set it once.',\n );\n }\n this.#recipientResolver = resolver;\n }\n\n get recipientResolver() {\n return this.#recipientResolver;\n }\n}\n\n/**\n * Notifications backend plugin\n *\n * @public\n */\nexport const notificationsPlugin = createBackendPlugin({\n pluginId: 'notifications',\n register(env) {\n const processingExtensions =\n new NotificationsProcessingExtensionPointImpl();\n env.registerExtensionPoint(\n notificationsProcessingExtensionPoint,\n processingExtensions,\n );\n\n env.registerInit({\n deps: {\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n userInfo: coreServices.userInfo,\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n database: coreServices.database,\n signals: signalsServiceRef,\n config: coreServices.rootConfig,\n catalog: catalogServiceRef,\n scheduler: coreServices.scheduler,\n actionsRegistry: actionsRegistryServiceRef,\n },\n async init({\n auth,\n httpAuth,\n userInfo,\n httpRouter,\n logger,\n database,\n signals,\n config,\n catalog,\n scheduler,\n actionsRegistry,\n }) {\n const store = await DatabaseNotificationsStore.create({ database });\n\n httpRouter.use(\n await createRouter({\n auth,\n httpAuth,\n userInfo,\n logger,\n config,\n store,\n catalog,\n signals,\n processors: processingExtensions.processors,\n recipientResolver: processingExtensions.recipientResolver,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n\n const cleaner = new NotificationCleaner(\n config,\n scheduler,\n logger,\n store,\n );\n await cleaner.initTaskRunner();\n\n createNotificationsActions({ actionsRegistry, auth, store });\n },\n });\n },\n});\n"],"names":["createBackendPlugin","notificationsProcessingExtensionPoint","coreServices","signalsServiceRef","catalogServiceRef","actionsRegistryServiceRef","DatabaseNotificationsStore","createRouter","NotificationCleaner","createNotificationsActions"],"mappings":";;;;;;;;;;;;AAkCA,MAAM,yCAAA,CAEN;AAAA,EACE,WAAA,GAAc,IAAI,KAAA,EAA6B;AAAA,EAC/C,kBAAA,GAAgE,MAAA;AAAA,EAEhE,gBACK,UAAA,EACG;AACN,IAAA,IAAA,CAAK,WAAA,CAAY,IAAA,CAAK,GAAG,UAAA,CAAW,MAAM,CAAA;AAAA,EAC5C;AAAA,EAEA,IAAI,UAAA,GAAa;AACf,IAAA,OAAO,IAAA,CAAK,WAAA;AAAA,EACd;AAAA,EAEA,iCACE,QAAA,EACM;AACN,IAAA,IAAI,KAAK,kBAAA,EAAoB;AAC3B,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AACA,IAAA,IAAA,CAAK,kBAAA,GAAqB,QAAA;AAAA,EAC5B;AAAA,EAEA,IAAI,iBAAA,GAAoB;AACtB,IAAA,OAAO,IAAA,CAAK,kBAAA;AAAA,EACd;AACF;AAOO,MAAM,sBAAsBA,oCAAA,CAAoB;AAAA,EACrD,QAAA,EAAU,eAAA;AAAA,EACV,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,oBAAA,GACJ,IAAI,yCAAA,EAA0C;AAChD,IAAA,GAAA,CAAI,sBAAA;AAAA,MACFC,6DAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,GAAA,CAAI,YAAA,CAAa;AAAA,MACf,IAAA,EAAM;AAAA,QACJ,MAAMC,6BAAA,CAAa,IAAA;AAAA,QACnB,UAAUA,6BAAA,CAAa,QAAA;AAAA,QACvB,UAAUA,6BAAA,CAAa,QAAA;AAAA,QACvB,YAAYA,6BAAA,CAAa,UAAA;AAAA,QACzB,QAAQA,6BAAA,CAAa,MAAA;AAAA,QACrB,UAAUA,6BAAA,CAAa,QAAA;AAAA,QACvB,OAAA,EAASC,mCAAA;AAAA,QACT,QAAQD,6BAAA,CAAa,UAAA;AAAA,QACrB,OAAA,EAASE,mCAAA;AAAA,QACT,WAAWF,6BAAA,CAAa,SAAA;AAAA,QACxB,eAAA,EAAiBG;AAAA,OACnB;AAAA,MACA,MAAM,IAAA,CAAK;AAAA,QACT,IAAA;AAAA,QACA,QAAA;AAAA,QACA,QAAA;AAAA,QACA,UAAA;AAAA,QACA,MAAA;AAAA,QACA,QAAA;AAAA,QACA,OAAA;AAAA,QACA,MAAA;AAAA,QACA,OAAA;AAAA,QACA,SAAA;AAAA,QACA;AAAA,OACF,EAAG;AACD,QAAA,MAAM,QAAQ,MAAMC,qDAAA,CAA2B,MAAA,CAAO,EAAE,UAAU,CAAA;AAElE,QAAA,UAAA,CAAW,GAAA;AAAA,UACT,MAAMC,mBAAA,CAAa;AAAA,YACjB,IAAA;AAAA,YACA,QAAA;AAAA,YACA,QAAA;AAAA,YACA,MAAA;AAAA,YACA,MAAA;AAAA,YACA,KAAA;AAAA,YACA,OAAA;AAAA,YACA,OAAA;AAAA,YACA,YAAY,oBAAA,CAAqB,UAAA;AAAA,YACjC,mBAAmB,oBAAA,CAAqB;AAAA,WACzC;AAAA,SACH;AACA,QAAA,UAAA,CAAW,aAAA,CAAc;AAAA,UACvB,IAAA,EAAM,SAAA;AAAA,UACN,KAAA,EAAO;AAAA,SACR,CAAA;AAED,QAAA,MAAM,UAAU,IAAIC,uCAAA;AAAA,UAClB,MAAA;AAAA,UACA,SAAA;AAAA,UACA,MAAA;AAAA,UACA;AAAA,SACF;AACA,QAAA,MAAM,QAAQ,cAAA,EAAe;AAE7B,QAAAC,gCAAA,CAA2B,EAAE,eAAA,EAAiB,IAAA,EAAM,KAAA,EAAO,CAAA;AAAA,MAC7D;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
|
|
@@ -29,7 +29,5 @@ function isOrder(order) {
|
|
|
29
29
|
return ["asc", "desc"].includes(order);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
exports.isOrder = isOrder;
|
|
33
32
|
exports.parseEntityOrderFieldParams = parseEntityOrderFieldParams;
|
|
34
|
-
exports.parseStringsParam = parseStringsParam;
|
|
35
33
|
//# sourceMappingURL=parseEntityOrderFieldParams.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseEntityOrderFieldParams.cjs.js","sources":["../../src/service/parseEntityOrderFieldParams.ts"],"sourcesContent":["/*\n * Copyright 2024 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\n// This file is based on the plugins/catalog-backend\n\nimport { InputError } from '@backstage/errors';\nimport { EntityOrder } from '../database';\n\n/**\n * Takes a single unknown parameter and makes sure that it's a single string or\n * an array of strings, and returns as an array.\n */\
|
|
1
|
+
{"version":3,"file":"parseEntityOrderFieldParams.cjs.js","sources":["../../src/service/parseEntityOrderFieldParams.ts"],"sourcesContent":["/*\n * Copyright 2024 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\n// This file is based on the plugins/catalog-backend\n\nimport { InputError } from '@backstage/errors';\nimport { EntityOrder } from '../database';\n\n/**\n * Takes a single unknown parameter and makes sure that it's a single string or\n * an array of strings, and returns as an array.\n */\nfunction parseStringsParam(param: unknown, ctx: string): string[] | undefined {\n if (param === undefined) {\n return undefined;\n }\n\n const array = [param].flat();\n if (array.some(p => typeof p !== 'string')) {\n throw new InputError(`Invalid ${ctx}, not a string`);\n }\n\n return array as string[];\n}\n\nexport function parseEntityOrderFieldParams(\n params: Record<string, unknown>,\n): EntityOrder[] | undefined {\n const orderFieldStrings = parseStringsParam(params.orderField, 'orderField');\n if (!orderFieldStrings) {\n return undefined;\n }\n\n return orderFieldStrings.map(orderFieldString => {\n const [field, order] = orderFieldString.split(',');\n\n if (order !== undefined && !isOrder(order)) {\n throw new InputError('Invalid order field order, must be asc or desc');\n }\n return { field, order };\n });\n}\n\nfunction isOrder(order: string): order is 'asc' | 'desc' {\n return ['asc', 'desc'].includes(order);\n}\n"],"names":["InputError"],"mappings":";;;;AAyBA,SAAS,iBAAA,CAAkB,OAAgB,GAAA,EAAmC;AAC5E,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,KAAA,GAAQ,CAAC,KAAK,CAAA,CAAE,IAAA,EAAK;AAC3B,EAAA,IAAI,MAAM,IAAA,CAAK,CAAA,CAAA,KAAK,OAAO,CAAA,KAAM,QAAQ,CAAA,EAAG;AAC1C,IAAA,MAAM,IAAIA,iBAAA,CAAW,CAAA,QAAA,EAAW,GAAG,CAAA,cAAA,CAAgB,CAAA;AAAA,EACrD;AAEA,EAAA,OAAO,KAAA;AACT;AAEO,SAAS,4BACd,MAAA,EAC2B;AAC3B,EAAA,MAAM,iBAAA,GAAoB,iBAAA,CAAkB,MAAA,CAAO,UAAA,EAAY,YAAY,CAAA;AAC3E,EAAA,IAAI,CAAC,iBAAA,EAAmB;AACtB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAO,iBAAA,CAAkB,IAAI,CAAA,gBAAA,KAAoB;AAC/C,IAAA,MAAM,CAAC,KAAA,EAAO,KAAK,CAAA,GAAI,gBAAA,CAAiB,MAAM,GAAG,CAAA;AAEjD,IAAA,IAAI,KAAA,KAAU,MAAA,IAAa,CAAC,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC1C,MAAA,MAAM,IAAIA,kBAAW,gDAAgD,CAAA;AAAA,IACvE;AACA,IAAA,OAAO,EAAE,OAAO,KAAA,EAAM;AAAA,EACxB,CAAC,CAAA;AACH;AAEA,SAAS,QAAQ,KAAA,EAAwC;AACvD,EAAA,OAAO,CAAC,KAAA,EAAO,MAAM,CAAA,CAAE,SAAS,KAAK,CAAA;AACvC;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-notifications-backend",
|
|
3
|
-
"version": "0.6.4
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "backend-plugin",
|
|
6
6
|
"pluginId": "notifications",
|
|
@@ -45,15 +45,15 @@
|
|
|
45
45
|
"test": "backstage-cli package test"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@backstage/backend-plugin-api": "1.9.0
|
|
49
|
-
"@backstage/catalog-model": "1.
|
|
50
|
-
"@backstage/config": "1.3.
|
|
51
|
-
"@backstage/errors": "1.
|
|
52
|
-
"@backstage/plugin-catalog-node": "2.
|
|
53
|
-
"@backstage/plugin-notifications-common": "0.2.
|
|
54
|
-
"@backstage/plugin-notifications-node": "0.2.25
|
|
55
|
-
"@backstage/plugin-signals-node": "0.
|
|
56
|
-
"@backstage/types": "1.2.2",
|
|
48
|
+
"@backstage/backend-plugin-api": "^1.9.0",
|
|
49
|
+
"@backstage/catalog-model": "^1.8.0",
|
|
50
|
+
"@backstage/config": "^1.3.7",
|
|
51
|
+
"@backstage/errors": "^1.3.0",
|
|
52
|
+
"@backstage/plugin-catalog-node": "^2.2.0",
|
|
53
|
+
"@backstage/plugin-notifications-common": "^0.2.2",
|
|
54
|
+
"@backstage/plugin-notifications-node": "^0.2.25",
|
|
55
|
+
"@backstage/plugin-signals-node": "^0.2.0",
|
|
56
|
+
"@backstage/types": "^1.2.2",
|
|
57
57
|
"express": "^4.22.0",
|
|
58
58
|
"express-promise-router": "^4.1.0",
|
|
59
59
|
"knex": "^3.0.0",
|
|
@@ -61,13 +61,13 @@
|
|
|
61
61
|
"uuid": "^11.0.0"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@backstage/backend-defaults": "0.
|
|
65
|
-
"@backstage/backend-test-utils": "1.11.2
|
|
66
|
-
"@backstage/cli": "0.36.1
|
|
67
|
-
"@backstage/plugin-auth-backend": "0.28.0
|
|
68
|
-
"@backstage/plugin-auth-backend-module-guest-provider": "0.2.18
|
|
69
|
-
"@backstage/plugin-events-backend": "0.6.1
|
|
70
|
-
"@backstage/plugin-signals-backend": "0.3.14
|
|
64
|
+
"@backstage/backend-defaults": "^0.17.0",
|
|
65
|
+
"@backstage/backend-test-utils": "^1.11.2",
|
|
66
|
+
"@backstage/cli": "^0.36.1",
|
|
67
|
+
"@backstage/plugin-auth-backend": "^0.28.0",
|
|
68
|
+
"@backstage/plugin-auth-backend-module-guest-provider": "^0.2.18",
|
|
69
|
+
"@backstage/plugin-events-backend": "^0.6.1",
|
|
70
|
+
"@backstage/plugin-signals-backend": "^0.3.14",
|
|
71
71
|
"@types/express": "^4.17.6",
|
|
72
72
|
"@types/supertest": "^2.0.8",
|
|
73
73
|
"supertest": "^7.0.0"
|