@verdaccio/hooks 8.0.0-next-8.12 → 8.0.0-next-8.13

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/src/index.ts DELETED
@@ -1 +0,0 @@
1
- export { handleNotify, notify, sendNotification } from './notify';
@@ -1,43 +0,0 @@
1
- import buildDebug from 'debug';
2
- import got from 'got-cjs';
3
-
4
- import { HTTP_STATUS } from '@verdaccio/core';
5
- import { logger } from '@verdaccio/logger';
6
-
7
- const debug = buildDebug('verdaccio:hooks:request');
8
-
9
- export type FetchOptions = {
10
- body: string;
11
- headers?: {};
12
- method?: string;
13
- };
14
-
15
- export async function notifyRequest(url: string, options: FetchOptions): Promise<boolean> {
16
- let response;
17
- try {
18
- debug('uri %o', url);
19
- response = got.post(url, {
20
- body: JSON.stringify(options.body),
21
- method: 'POST',
22
- headers: { 'Content-Type': 'application/json' },
23
- });
24
- debug('response.status %o', response.status);
25
- const body = await response.json();
26
- if (response.status >= HTTP_STATUS.BAD_REQUEST) {
27
- throw new Error(body);
28
- }
29
-
30
- logger.info(
31
- { content: options.body },
32
- 'The notification @{content} has been successfully dispatched'
33
- );
34
- return true;
35
- } catch (err: any) {
36
- debug('request error %o', err);
37
- logger.error(
38
- { errorMessage: err?.message },
39
- 'notify service has thrown an error: @{errorMessage}'
40
- );
41
- return false;
42
- }
43
- }
package/src/notify.ts DELETED
@@ -1,139 +0,0 @@
1
- /* eslint-disable no-undef */
2
- import buildDebug from 'debug';
3
- import Handlebars from 'handlebars';
4
-
5
- import { logger } from '@verdaccio/logger';
6
- import { Config, Notification, Package, RemoteUser } from '@verdaccio/types';
7
-
8
- import { FetchOptions, notifyRequest } from './notify-request';
9
-
10
- const debug = buildDebug('verdaccio:hooks');
11
-
12
- export function compileTemplate(content, metadata) {
13
- // FUTURE: multiple handlers
14
- return new Promise((resolve, reject) => {
15
- let handler;
16
- try {
17
- if (!handler) {
18
- debug('compile default template handler %o', content);
19
- const template: HandlebarsTemplateDelegate = Handlebars.compile(content);
20
- return resolve(template(metadata));
21
- }
22
- } catch (error: any) {
23
- debug('error template handler %o', error);
24
- reject(error);
25
- }
26
- });
27
- }
28
-
29
- export async function handleNotify(
30
- metadata: Partial<Package>,
31
- notifyEntry,
32
- remoteUser: Partial<RemoteUser>,
33
- publishedPackage: string
34
- ): Promise<boolean> {
35
- let regex;
36
- if (metadata.name && notifyEntry.packagePattern) {
37
- regex = new RegExp(notifyEntry.packagePattern, notifyEntry.packagePatternFlags || '');
38
- if (!regex.test(metadata.name)) {
39
- return false;
40
- }
41
- }
42
-
43
- let content;
44
- // FIXME: publisher is not part of the expected types metadata
45
- // @ts-ignore
46
- if (typeof metadata?.publisher === 'undefined' || metadata?.publisher === null) {
47
- // @ts-ignore
48
- metadata = { ...metadata, publishedPackage, publisher: { name: remoteUser.name as string } };
49
- debug('template metadata %o', metadata);
50
- content = await compileTemplate(notifyEntry.content, metadata);
51
- }
52
-
53
- const options: FetchOptions = {
54
- body: JSON.stringify(content),
55
- };
56
-
57
- // provides fallback support, it's accept an Object {} and Array of {}
58
- if (notifyEntry.headers && Array.isArray(notifyEntry.headers)) {
59
- const header = {};
60
- // FIXME: we can simplify this
61
- notifyEntry.headers.map(function (item): void {
62
- if (Object.is(item, item)) {
63
- for (const key in item) {
64
- /* eslint no-prototype-builtins: 0 */
65
- if (item.hasOwnProperty(key)) {
66
- header[key] = item[key];
67
- }
68
- }
69
- }
70
- });
71
- options.headers = header;
72
- } else if (Object.is(notifyEntry.headers, notifyEntry.headers)) {
73
- options.headers = notifyEntry.headers;
74
- }
75
-
76
- if (!notifyEntry.endpoint) {
77
- debug('error due endpoint is missing');
78
- throw new Error('missing parameter');
79
- }
80
-
81
- return notifyRequest(notifyEntry.endpoint, {
82
- method: notifyEntry.method,
83
- ...options,
84
- });
85
- }
86
-
87
- export function sendNotification(
88
- metadata: Partial<Package>,
89
- notify: Notification,
90
- remoteUser: Partial<RemoteUser>,
91
- publishedPackage: string
92
- ): Promise<boolean> {
93
- return handleNotify(metadata, notify, remoteUser, publishedPackage) as Promise<any>;
94
- }
95
-
96
- export async function notify(
97
- metadata: Partial<Package>,
98
- config: Partial<Config>,
99
- remoteUser: Partial<RemoteUser>,
100
- publishedPackage: string
101
- ): Promise<boolean[]> {
102
- debug('init send notification');
103
- if (config.notify) {
104
- const isSingle = Object.keys(config.notify).includes('method');
105
- if (isSingle) {
106
- debug('send single notification');
107
- try {
108
- const response = await sendNotification(
109
- metadata,
110
- config.notify as Notification,
111
- remoteUser,
112
- publishedPackage
113
- );
114
- return [response];
115
- } catch {
116
- debug('error on sending single notification');
117
- return [false];
118
- }
119
- } else {
120
- debug('send multiples notification');
121
- const results = await Promise.allSettled(
122
- Object.keys(config.notify).map((keyId: string) => {
123
- // @ts-ignore
124
- const item = config.notify[keyId];
125
- debug('send item %o', item);
126
- return sendNotification(metadata, item, remoteUser, publishedPackage);
127
- })
128
- ).catch((error) => {
129
- logger.error({ error }, 'notify request has failed: @error');
130
- });
131
-
132
- // @ts-ignore
133
- return Object.keys(results).map((promiseValue) => results[promiseValue].value);
134
- }
135
- } else {
136
- debug('no notifications configuration detected');
137
- return [false];
138
- }
139
- }
@@ -1,5 +0,0 @@
1
- import path from 'path';
2
-
3
- export const parseConfigurationFile = (name) => {
4
- return path.join(__dirname, `../partials/config/yaml/${name}.yaml`);
5
- };
@@ -1,83 +0,0 @@
1
- import nock from 'nock';
2
- import { beforeEach, describe, expect, test } from 'vitest';
3
-
4
- import { createRemoteUser, parseConfigFile } from '@verdaccio/config';
5
- import { setup } from '@verdaccio/logger';
6
- import { Config } from '@verdaccio/types';
7
-
8
- import { notify } from '../src/notify';
9
- import { parseConfigurationFile } from './__helper';
10
-
11
- const parseConfigurationNotifyFile = (name) => {
12
- return parseConfigurationFile(`notify/${name}`);
13
- };
14
- const singleHeaderNotificationConfig = parseConfigFile(
15
- parseConfigurationNotifyFile('single.header.notify')
16
- );
17
- const multiNotificationConfig = parseConfigFile(parseConfigurationNotifyFile('multiple.notify'));
18
-
19
- setup({});
20
-
21
- const domain = 'http://slack-service';
22
-
23
- const options = {
24
- path: '/foo?auth_token=mySecretToken',
25
- };
26
-
27
- describe('Notifications:: notifyRequest', () => {
28
- beforeEach(() => {
29
- nock.cleanAll();
30
- });
31
- test('when sending a empty notification', async () => {
32
- nock(domain).post(options.path).reply(200, { body: 'test' });
33
-
34
- const notificationResponse = await notify({}, {}, createRemoteUser('foo', []), 'bar');
35
- expect(notificationResponse).toEqual([false]);
36
- });
37
-
38
- test('when sending a single notification', async () => {
39
- nock(domain).post(options.path).reply(200, { body: 'test' });
40
- const notificationResponse = await notify(
41
- {},
42
- singleHeaderNotificationConfig,
43
- createRemoteUser('foo', []),
44
- 'bar'
45
- );
46
- expect(notificationResponse).toEqual([true]);
47
- });
48
-
49
- test('when notification endpoint is missing', async () => {
50
- nock(domain).post(options.path).reply(200, { body: 'test' });
51
- const name = 'package';
52
- const config: Partial<Config> = {
53
- // @ts-ignore
54
- notify: {
55
- method: 'POST',
56
- endpoint: undefined,
57
- content: '',
58
- },
59
- };
60
- const notificationResponse = await notify({ name }, config, createRemoteUser('foo', []), 'bar');
61
- expect(notificationResponse).toEqual([false]);
62
- });
63
-
64
- test('when multiple notifications', async () => {
65
- nock(domain)
66
- .post(options.path)
67
- .once()
68
- .reply(200, { body: 'test' })
69
- .post(options.path)
70
- .once()
71
- .reply(400, {})
72
- .post(options.path)
73
- .once()
74
- .reply(500, { message: 'Something bad happened' });
75
- // mockClient.intercept(options).reply(200, { body: 'test' });
76
- // mockClient.intercept(options).reply(400, {});
77
- // mockClient.intercept(options).reply(500, { message: 'Something bad happened' });
78
-
79
- const name = 'package';
80
- const responses = await notify({ name }, multiNotificationConfig, { name: 'foo' }, 'bar');
81
- expect(responses).toEqual([true, false, false]);
82
- });
83
- });
@@ -1,16 +0,0 @@
1
- notify:
2
- 'example-google-chat':
3
- method: POST
4
- headers: [{ 'Content-Type': 'application/json' }]
5
- endpoint: http://slack-service/foo?auth_token=mySecretToken
6
- content: '{"text":"New package published: `{{ name }}{{#each versions}} v{{version}}{{/each}}`"}'
7
- 'example-hipchat':
8
- method: POST
9
- headers: [{ 'Content-Type': 'application/json' }]
10
- endpoint: http://slack-service/foo?auth_token=mySecretToken
11
- content: '{"color":"green","message":"New package published: * {{ name }}*","notify":true,"message_format":"text"}'
12
- 'example-stride':
13
- method: POST
14
- headers: [{ 'Content-Type': 'application/json' }, { 'authorization': 'Bearer secretToken' }]
15
- endpoint: http://slack-service/foo?auth_token=mySecretToken
16
- content: '{"body": {"version": 1,"type": "doc","content": [{"type": "paragraph","content": [{"type": "text","text": "New package published: * {{ name }}* Publisher name: * {{ publisher.name }}"}]}]}}'
@@ -1,5 +0,0 @@
1
- notify:
2
- method: POST
3
- headers: { 'Content-Type': 'application/json' }
4
- endpoint: http://slack-service/foo?auth_token=mySecretToken
5
- content: '{"color":"green","message":"New package published: * {{ name }}*","notify":true,"message_format":"text"}'
@@ -1,5 +0,0 @@
1
- notify:
2
- method: POST
3
- headers: [{ 'Content-Type': 'application/json' }]
4
- endpoint: https://usagge.hipchat.com/v2/room/3729485/notification?auth_token=mySecretToken
5
- content: '{"color":"green","message":"New package published: * {{ name }}*","notify":true,"message_format":"text"}'
@@ -1,7 +0,0 @@
1
- notify:
2
- method: POST
3
- headers: { 'Content-Type': 'application/json' }
4
- packagePattern: package
5
- packagePatternFlags: g
6
- endpoint: https://usagge.hipchat.com/v2/room/3729485/notification?auth_token=mySecretToken
7
- content: '{"color":"green","message":"New package published: * {{ name }}*","notify":true,"message_format":"text"}'
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "rootDir": "./src",
5
- "outDir": "./build"
6
- },
7
- "include": ["src/**/*"],
8
- "exclude": ["src/**/*.test.ts"]
9
- }
package/tsconfig.json DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.reference.json",
3
- "compilerOptions": {
4
- "rootDir": "./src",
5
- "outDir": "./build"
6
- },
7
- "include": ["src/**/*"],
8
- "exclude": ["src/**/*.test.ts"],
9
- "references": [
10
- {
11
- "path": "../auth"
12
- },
13
- {
14
- "path": "../config"
15
- },
16
- {
17
- "path": "../logger/logger"
18
- }
19
- ]
20
- }