ctct-helpers 0.0.1-security → 1.1.75
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.
Potentially problematic release.
This version of ctct-helpers might be problematic. Click here for more details.
- package/build.js +43 -0
- package/dist/ctct-helpers.js +933 -0
- package/js/csrf-token.js +25 -0
- package/js/env.js +25 -0
- package/js/index.js +13 -0
- package/js/rest-handler-legacy.js +165 -0
- package/js/rest-handler.js +263 -0
- package/package.json +29 -3
- package/README.md +0 -5
package/js/csrf-token.js
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
/**
|
2
|
+
* @module ctct-helpers/csrf-token
|
3
|
+
*/
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Get the crsfToken from the page
|
7
|
+
* @returns {String} The users' csrfToken, or 'local' if not found
|
8
|
+
*
|
9
|
+
* @example
|
10
|
+
* const options = { headers: {} };
|
11
|
+
* const token = getCsrfToken();
|
12
|
+
* if (env !== 'local') {
|
13
|
+
* options.headers['X-CSRF-Token'] = token;
|
14
|
+
* }
|
15
|
+
* const restHandler = new RestHandler('https://example.com', options);
|
16
|
+
*/
|
17
|
+
const getCsrfToken = () => {
|
18
|
+
const tokenEl = document.querySelector('meta[name="csrf-token"]');
|
19
|
+
if (tokenEl) {
|
20
|
+
return tokenEl.content;
|
21
|
+
}
|
22
|
+
return 'local';
|
23
|
+
};
|
24
|
+
|
25
|
+
export { getCsrfToken };
|
package/js/env.js
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
/**
|
2
|
+
* @module ctct-helpers/env
|
3
|
+
*/
|
4
|
+
|
5
|
+
const getHostName = () => {
|
6
|
+
return window.location.hostname;
|
7
|
+
};
|
8
|
+
|
9
|
+
/**
|
10
|
+
* Get the current CTCT environment by parsing a URL
|
11
|
+
* @param {String} [hostname] An optional hostname to parse
|
12
|
+
* @returns Current env (e.g. ".l1"), "." for prod, "local" for localhost
|
13
|
+
*
|
14
|
+
* @example
|
15
|
+
* const env = getEnv();
|
16
|
+
* if (env === 'local') {
|
17
|
+
* return 'https://localhost:9000/mock/contacts/lists';
|
18
|
+
* }
|
19
|
+
* return `https://app${env}constantcontact.com/v1/contacts/lists`;
|
20
|
+
*/
|
21
|
+
const getEnv = (hostname = getHostName()) => {
|
22
|
+
return hostname.includes('constantcontact') ? (hostname.match(/\.[dls]1\./) || '.')[0] : 'local';
|
23
|
+
};
|
24
|
+
|
25
|
+
export { getEnv };
|
package/js/index.js
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
import { getEnv } from './env';
|
2
|
+
import { getCsrfToken } from './csrf-token';
|
3
|
+
import RestHandler from './rest-handler';
|
4
|
+
import RestHandlerLegacy from './rest-handler-legacy';
|
5
|
+
|
6
|
+
export default {
|
7
|
+
getEnv,
|
8
|
+
getCsrfToken,
|
9
|
+
RestHandler,
|
10
|
+
RestHandlerLegacy,
|
11
|
+
};
|
12
|
+
|
13
|
+
export { getEnv, getCsrfToken, RestHandler, RestHandlerLegacy };
|
@@ -0,0 +1,165 @@
|
|
1
|
+
/**
|
2
|
+
* @module ctct-helpers/rest-handler-legacy
|
3
|
+
*/
|
4
|
+
|
5
|
+
import $ from 'jquery';
|
6
|
+
|
7
|
+
/**
|
8
|
+
* DO NOT USE THIS MODULE unless you absolutely need to use $.ajax() over fetch()!
|
9
|
+
* A simple REST handler for making AJAX requests to a single back-end service
|
10
|
+
* with CORS enabled. It is assumed that data is sent and received as JSON.
|
11
|
+
* Built around jQuery.ajax(), promisified for compatibility
|
12
|
+
*
|
13
|
+
* @example
|
14
|
+
* const restHandler = new RestHandler('https://example.com/api');
|
15
|
+
* restHandler.get('/some/endpoint').then((data) => {
|
16
|
+
* console.log(data);
|
17
|
+
* }).catch((error) => {
|
18
|
+
* console.error(error);
|
19
|
+
* });
|
20
|
+
*/
|
21
|
+
class RestHandlerLegacy {
|
22
|
+
/**
|
23
|
+
* Constructor
|
24
|
+
* @param {String} baseUrl - the base URL of the service (e.g. 'https://example.com/api')
|
25
|
+
* @param opts
|
26
|
+
*/
|
27
|
+
constructor(baseUrl, opts = {}) {
|
28
|
+
this.baseUrl = `https://${baseUrl}`;
|
29
|
+
// http://api.jquery.com/jquery.ajax/#jQuery-ajax-settings
|
30
|
+
this.defaults = {
|
31
|
+
timeout: 60 * 1000 * 2, // 2 minutes
|
32
|
+
contentType: 'application/json',
|
33
|
+
dataType: 'json',
|
34
|
+
global: true, // Set to false to avoid bubbling errors
|
35
|
+
crossDomain: true,
|
36
|
+
headers: {
|
37
|
+
'X-Requested-With': 'XMLHttpRequest',
|
38
|
+
},
|
39
|
+
xhrFields: {
|
40
|
+
withCredentials: true,
|
41
|
+
},
|
42
|
+
};
|
43
|
+
|
44
|
+
this.defaults = this._extend({}, this.defaults, opts);
|
45
|
+
}
|
46
|
+
|
47
|
+
/**
|
48
|
+
* Extend (NOT deep copy) multiple objects
|
49
|
+
* @param {...*} args objects to extend
|
50
|
+
* @return {Object} the new object
|
51
|
+
*/
|
52
|
+
_extend(...args) {
|
53
|
+
return $.extend.apply(null, args);
|
54
|
+
}
|
55
|
+
|
56
|
+
/**
|
57
|
+
* Make an AJAX request. User must specify the method type in the options.
|
58
|
+
* Not intended to be called directly - use one of the REST methods below.
|
59
|
+
* @param {String} url - the URL to the resource (e.g. '/some/endpoint')
|
60
|
+
* @param {Object} opts - options to override the defaults ('method' is required)
|
61
|
+
* @return {Promise} a promisified jqXHR object
|
62
|
+
*/
|
63
|
+
send(url, opts = {}) {
|
64
|
+
const options = this._extend({}, this.defaults, opts);
|
65
|
+
const jqXHR = $.ajax(`${this.baseUrl}${url}`, options);
|
66
|
+
return Promise.resolve(jqXHR);
|
67
|
+
}
|
68
|
+
|
69
|
+
/**
|
70
|
+
* Perform a GET request on the requested resource.
|
71
|
+
* @param {String} url - the URL to the resource (e.g. '/some/endpoint')
|
72
|
+
* @param {Object} opts - options to override the defaults
|
73
|
+
* @return {Promise} a promisified jqXHR object
|
74
|
+
*/
|
75
|
+
get(url, opts = {}) {
|
76
|
+
const options = this._extend(
|
77
|
+
{},
|
78
|
+
{
|
79
|
+
method: 'GET',
|
80
|
+
},
|
81
|
+
opts
|
82
|
+
);
|
83
|
+
return this.send(url, options);
|
84
|
+
}
|
85
|
+
|
86
|
+
/**
|
87
|
+
* Perform a POST request on the requested resource.
|
88
|
+
* @param {String} url - the URL to the resource (e.g. '/some/endpoint')
|
89
|
+
* @param {Object} data - the request body as a JS object
|
90
|
+
* @param {Object} opts - options to override the defaults
|
91
|
+
* @return {Promise} a promisified jqXHR object
|
92
|
+
*/
|
93
|
+
post(url, data, opts = {}) {
|
94
|
+
const payload = JSON.stringify(data);
|
95
|
+
const options = this._extend(
|
96
|
+
{},
|
97
|
+
{
|
98
|
+
method: 'POST',
|
99
|
+
data: payload,
|
100
|
+
},
|
101
|
+
opts
|
102
|
+
);
|
103
|
+
return this.send(url, options);
|
104
|
+
}
|
105
|
+
|
106
|
+
/**
|
107
|
+
* Perform a PATCH request on the requested resource.
|
108
|
+
* @param {String} url - the URL to the resource (e.g. '/some/endpoint')
|
109
|
+
* @param {Object} data - the request body as a JS object
|
110
|
+
* @param {Object} opts - options to override the defaults
|
111
|
+
* @return {Promise} a promisified jqXHR object
|
112
|
+
*/
|
113
|
+
patch(url, data, opts = {}) {
|
114
|
+
const payload = JSON.stringify(data);
|
115
|
+
const options = this._extend(
|
116
|
+
{},
|
117
|
+
{
|
118
|
+
method: 'PATCH',
|
119
|
+
data: payload,
|
120
|
+
},
|
121
|
+
opts
|
122
|
+
);
|
123
|
+
return this.send(url, options);
|
124
|
+
}
|
125
|
+
|
126
|
+
/**
|
127
|
+
* Perform a PUT request on the requested resource.
|
128
|
+
* @param {String} url - the URL to the resource (e.g. '/some/endpoint')
|
129
|
+
* @param {Object} data - the request body as a JS object
|
130
|
+
* @param {Object} opts - options to override the defaults
|
131
|
+
* @return {Promise} a promisified jqXHR object
|
132
|
+
*/
|
133
|
+
put(url, data, opts = {}) {
|
134
|
+
const payload = JSON.stringify(data);
|
135
|
+
const options = this._extend(
|
136
|
+
{},
|
137
|
+
{
|
138
|
+
method: 'PUT',
|
139
|
+
data: payload,
|
140
|
+
},
|
141
|
+
opts
|
142
|
+
);
|
143
|
+
return this.send(url, options);
|
144
|
+
}
|
145
|
+
|
146
|
+
/**
|
147
|
+
* Perform a DELETE request on the requested resource.
|
148
|
+
* @param {String} url - the URL to the resource (e.g. '/some/endpoint')
|
149
|
+
* @param {Object} opts - options to override the defaults
|
150
|
+
* @return {Promise} a promisified jqXHR object
|
151
|
+
*/
|
152
|
+
delete(url, opts = {}) {
|
153
|
+
const options = this._extend(
|
154
|
+
{},
|
155
|
+
{
|
156
|
+
method: 'DELETE',
|
157
|
+
},
|
158
|
+
opts
|
159
|
+
);
|
160
|
+
return this.send(url, options);
|
161
|
+
}
|
162
|
+
}
|
163
|
+
|
164
|
+
// Export the class below instead of same line as class declaration.
|
165
|
+
export default RestHandlerLegacy;
|
@@ -0,0 +1,263 @@
|
|
1
|
+
/**
|
2
|
+
* @module ctct-helpers/rest-handler
|
3
|
+
*/
|
4
|
+
|
5
|
+
import * as deepmerge from 'deepmerge';
|
6
|
+
|
7
|
+
const merge = (...args) => deepmerge.all(args);
|
8
|
+
|
9
|
+
const PARSERS = {
|
10
|
+
json: async response => response.json(),
|
11
|
+
string: async response => response.text(),
|
12
|
+
arrayBuffer: async response => response.arrayBuffer(),
|
13
|
+
form: async response => response.formData(),
|
14
|
+
blob: async response => response.blob(),
|
15
|
+
};
|
16
|
+
|
17
|
+
const parsePayload = payload => {
|
18
|
+
switch (typeof payload) {
|
19
|
+
case 'string':
|
20
|
+
return payload;
|
21
|
+
case 'object':
|
22
|
+
return JSON.stringify(payload);
|
23
|
+
default:
|
24
|
+
throw new Error('Request body must be either a String or an Object');
|
25
|
+
}
|
26
|
+
};
|
27
|
+
|
28
|
+
const parseResponse = async (response, parser) => {
|
29
|
+
const body = await parser(response);
|
30
|
+
if (response.ok) {
|
31
|
+
return body;
|
32
|
+
}
|
33
|
+
return Promise.reject({
|
34
|
+
status: response.status,
|
35
|
+
statusText: response.statusText,
|
36
|
+
body,
|
37
|
+
});
|
38
|
+
};
|
39
|
+
|
40
|
+
const DEFAULTS = {
|
41
|
+
// Custom options
|
42
|
+
timeout: 60 * 1000 * 2, // 2 minutes
|
43
|
+
includeResponseHeaders: false,
|
44
|
+
// Fetch options
|
45
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters
|
46
|
+
mode: 'cors',
|
47
|
+
credentials: 'same-origin',
|
48
|
+
cache: 'no-store',
|
49
|
+
redirect: 'follow',
|
50
|
+
headers: {
|
51
|
+
'X-Requested-With': 'XMLHttpRequest',
|
52
|
+
},
|
53
|
+
};
|
54
|
+
|
55
|
+
/**
|
56
|
+
* A simple REST handler for making AJAX requests to a single back-end service with CORS enabled.
|
57
|
+
* Built around Fetch and Promises. {@link https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API}
|
58
|
+
*
|
59
|
+
* By default, it is assumed that data is sent and received as JSON.
|
60
|
+
* Unlike straight fetch(), each method will reject if the status is not 200-299 ("ok").
|
61
|
+
*
|
62
|
+
* @example
|
63
|
+
* // with Promises
|
64
|
+
* const restHandler = new RestHandler('example.com/api');
|
65
|
+
* restHandler.get('/some/endpoint')
|
66
|
+
* .then((body) => {
|
67
|
+
* console.log(body); // => { ... }
|
68
|
+
* }).catch((error) => {
|
69
|
+
* console.log(error); // => { status: 404, statusText: "", body: {...} }
|
70
|
+
* });
|
71
|
+
*
|
72
|
+
* @example
|
73
|
+
* // with async/await
|
74
|
+
* const restHandler = new RestHandler('example.com/api');
|
75
|
+
* const example = async () => {
|
76
|
+
* try {
|
77
|
+
* const body = await restHandler.get('/some/endpoint');
|
78
|
+
* console.log(body); // => { ... }
|
79
|
+
* } catch (error) {
|
80
|
+
* console.log(error); // => { status: 404, statusText: "", body: {...} }
|
81
|
+
* }
|
82
|
+
* };
|
83
|
+
*
|
84
|
+
* @example
|
85
|
+
* // with non-JSON parser
|
86
|
+
* const restHandler = new RestHandler('example.com/api');
|
87
|
+
* restHandler.get('/some/endpoint', { parser: RestHandler.PARSERS.string })
|
88
|
+
* .then((body) => console.log(typeof body)); // => "string"
|
89
|
+
*
|
90
|
+
* @example
|
91
|
+
* // get response body and headers
|
92
|
+
* const restHandler = new RestHandler('example.com/api');
|
93
|
+
* // To get headers, see https://developer.mozilla.org/en-US/docs/Web/API/Headers
|
94
|
+
* restHandler.get('/some/endpoint', { includeResponseHeaders: true })
|
95
|
+
* .then(({body, headers}) => console.log(body, headers));
|
96
|
+
*/
|
97
|
+
class RestHandler {
|
98
|
+
/**
|
99
|
+
* Constructor
|
100
|
+
* @param {String} baseUrl - the base URL of the service without 'https://' (e.g. 'example.com/api')
|
101
|
+
* @param opts
|
102
|
+
*/
|
103
|
+
constructor(baseUrl, opts = {}) {
|
104
|
+
this.baseUrl = baseUrl.indexOf('https://') > -1 ? baseUrl : `https://${baseUrl}`;
|
105
|
+
this.defaults = merge({}, DEFAULTS, opts);
|
106
|
+
}
|
107
|
+
|
108
|
+
// Because Jasmine is dumb and you can't directly mock out window.fetch
|
109
|
+
async _fetch(url, options) {
|
110
|
+
const { timeout } = options;
|
111
|
+
// https://gist.github.com/davej/728b20518632d97eef1e5a13bf0d05c7
|
112
|
+
return Promise.race([
|
113
|
+
window.fetch(url, options),
|
114
|
+
new Promise((resolve, reject) =>
|
115
|
+
setTimeout(() => reject(new Error(`Request timeout after ${timeout}ms`)), timeout)
|
116
|
+
), // eslint-disable-line no-unused-vars
|
117
|
+
]);
|
118
|
+
}
|
119
|
+
|
120
|
+
/**
|
121
|
+
* Make an AJAX request. User must specify the method type in the options.
|
122
|
+
* Not intended to be called directly - use one of the REST methods (i.e. .get(), .post()).
|
123
|
+
* @param {String} url - the URL to the resource (e.g. '/some/endpoint')
|
124
|
+
* @param {Object} opts - options to override the defaults ('method' is required)
|
125
|
+
* @throws {Error} if the response has an unsupported content-type header
|
126
|
+
* @return {Promise} resolves to the parsed response body, rejects if not "ok"
|
127
|
+
*/
|
128
|
+
async send(url, opts = {}) {
|
129
|
+
let result;
|
130
|
+
const options = merge({}, this.defaults, opts);
|
131
|
+
const response = await this._fetch(`${this.baseUrl}${url}`, options);
|
132
|
+
// Make smart inferences: https://css-tricks.com/using-fetch/
|
133
|
+
const contentType = response.headers.get('content-type');
|
134
|
+
if (!contentType) {
|
135
|
+
// Some responses (e.g. PUT) might not return content at all!
|
136
|
+
result = true;
|
137
|
+
} else if (options.parser) {
|
138
|
+
// The user provided the specific parser to use
|
139
|
+
result = await parseResponse(response, options.parser);
|
140
|
+
} else if (contentType.includes('application/json')) {
|
141
|
+
result = await parseResponse(response, PARSERS.json);
|
142
|
+
} else if (contentType.includes('text/html')) {
|
143
|
+
result = await parseResponse(response, PARSERS.string);
|
144
|
+
} else {
|
145
|
+
throw new Error(`content-type ${contentType} is not supported. Try providing a custom options.parser!`);
|
146
|
+
}
|
147
|
+
// Optionally include response headers
|
148
|
+
if (options.includeResponseHeaders) {
|
149
|
+
result = {
|
150
|
+
body: result,
|
151
|
+
headers: response.headers,
|
152
|
+
};
|
153
|
+
}
|
154
|
+
return result;
|
155
|
+
}
|
156
|
+
|
157
|
+
/**
|
158
|
+
* Perform a GET request on the requested resource.
|
159
|
+
* @param {String} url - the URL to the resource (e.g. '/some/endpoint')
|
160
|
+
* @param {Object} opts - options to override the defaults
|
161
|
+
* @return {Promise} resolves to the parsed response body, rejects if not "ok"
|
162
|
+
*/
|
163
|
+
get(url, opts = {}) {
|
164
|
+
const options = merge(
|
165
|
+
{},
|
166
|
+
{
|
167
|
+
method: 'GET',
|
168
|
+
},
|
169
|
+
opts
|
170
|
+
);
|
171
|
+
return this.send(url, options);
|
172
|
+
}
|
173
|
+
|
174
|
+
/**
|
175
|
+
* Perform a POST request on the requested resource.
|
176
|
+
* @param {String} url - the URL to the resource (e.g. '/some/endpoint')
|
177
|
+
* @param {Object|String} data - the request body as a JS object
|
178
|
+
* @param {Object} opts - options to override the defaults
|
179
|
+
* @throws {Error} if data is not a string or an object
|
180
|
+
* @return {Promise} resolves to the parsed response body, rejects if not "ok"
|
181
|
+
*/
|
182
|
+
post(url, data, opts = {}) {
|
183
|
+
const payload = parsePayload(data);
|
184
|
+
const options = merge(
|
185
|
+
{},
|
186
|
+
{
|
187
|
+
method: 'POST',
|
188
|
+
body: payload,
|
189
|
+
},
|
190
|
+
opts
|
191
|
+
);
|
192
|
+
return this.send(url, options);
|
193
|
+
}
|
194
|
+
|
195
|
+
/**
|
196
|
+
* Perform a PATCH request on the requested resource.
|
197
|
+
* @param {String} url - the URL to the resource (e.g. '/some/endpoint')
|
198
|
+
* @param {Object|String} data - the request body as a JS object
|
199
|
+
* @param {Object} opts - options to override the defaults
|
200
|
+
* @throws {Error} if data is not a string or an object
|
201
|
+
* @return {Promise} resolves to the parsed response body, rejects if not "ok"
|
202
|
+
*/
|
203
|
+
patch(url, data, opts = {}) {
|
204
|
+
const payload = parsePayload(data);
|
205
|
+
const options = merge(
|
206
|
+
{},
|
207
|
+
{
|
208
|
+
method: 'PATCH',
|
209
|
+
body: payload,
|
210
|
+
},
|
211
|
+
opts
|
212
|
+
);
|
213
|
+
return this.send(url, options);
|
214
|
+
}
|
215
|
+
|
216
|
+
/**
|
217
|
+
* Perform a PUT request on the requested resource.
|
218
|
+
* @param {String} url - the URL to the resource (e.g. '/some/endpoint')
|
219
|
+
* @param {Object|String} data - the request body as a JS object
|
220
|
+
* @param {Object} opts - options to override the defaults
|
221
|
+
* @throws {Error} if data is not a string or an object
|
222
|
+
* @return {Promise} resolves to the parsed response body, rejects if not "ok"
|
223
|
+
*/
|
224
|
+
put(url, data, opts = {}) {
|
225
|
+
const payload = parsePayload(data);
|
226
|
+
const options = merge(
|
227
|
+
{},
|
228
|
+
{
|
229
|
+
method: 'PUT',
|
230
|
+
body: payload,
|
231
|
+
},
|
232
|
+
opts
|
233
|
+
);
|
234
|
+
return this.send(url, options);
|
235
|
+
}
|
236
|
+
|
237
|
+
/**
|
238
|
+
* Perform a DELETE request on the requested resource.
|
239
|
+
* @param {String} url - the URL to the resource (e.g. '/some/endpoint')
|
240
|
+
* @param {Object} opts - options to override the defaults
|
241
|
+
* @return {Promise} resolves to the parsed response body, rejects if not "ok"
|
242
|
+
*/
|
243
|
+
delete(url, opts = {}) {
|
244
|
+
const options = merge(
|
245
|
+
{},
|
246
|
+
{
|
247
|
+
method: 'DELETE',
|
248
|
+
},
|
249
|
+
opts
|
250
|
+
);
|
251
|
+
return this.send(url, options);
|
252
|
+
}
|
253
|
+
}
|
254
|
+
|
255
|
+
/**
|
256
|
+
* Convenience methods for parsing the response of a fetch() call.
|
257
|
+
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Body#Methods}
|
258
|
+
* @static
|
259
|
+
*/
|
260
|
+
RestHandler.PARSERS = PARSERS;
|
261
|
+
|
262
|
+
// Export the class below instead of same line as class declaration.
|
263
|
+
export default RestHandler;
|
package/package.json
CHANGED
@@ -1,6 +1,32 @@
|
|
1
1
|
{
|
2
2
|
"name": "ctct-helpers",
|
3
|
-
"version": "
|
4
|
-
"description": "
|
5
|
-
"
|
3
|
+
"version": "1.1.75",
|
4
|
+
"description": "",
|
5
|
+
"license": "MIT",
|
6
|
+
"author": "hctct",
|
7
|
+
"main": "index.js",
|
8
|
+
"scripts": {
|
9
|
+
"prebuild": "rimraf dist",
|
10
|
+
"build": "rollup --config script/build.js --configSrc ./",
|
11
|
+
"preinstall": "node build.js",
|
12
|
+
"lint": "eslint ./",
|
13
|
+
"prepare": "npm run build",
|
14
|
+
"spec": "mocha --harmony --require esm script/setup.js --recursive test",
|
15
|
+
"start": "npm run build -- --watch",
|
16
|
+
"pretest": "npm run lint && npm run build",
|
17
|
+
"test": "nyc npm run spec"
|
18
|
+
},
|
19
|
+
"dependencies": {
|
20
|
+
"deepmerge": "^4.2.2",
|
21
|
+
"jquery": "^3.6.0"
|
22
|
+
},
|
23
|
+
"devDependencies": {
|
24
|
+
"rimraf": "3.0.2",
|
25
|
+
"rollup": "1.28.0",
|
26
|
+
"rollup-plugin-size": "0.2.1",
|
27
|
+
"rollup-plugin-terser": "5.1.3"
|
28
|
+
},
|
29
|
+
"publishConfig": {
|
30
|
+
"access": "public"
|
31
|
+
}
|
6
32
|
}
|
package/README.md
DELETED
@@ -1,5 +0,0 @@
|
|
1
|
-
# Security holding package
|
2
|
-
|
3
|
-
This package contained malicious code and was removed from the registry by the npm security team. A placeholder was published to ensure users are not affected in the future.
|
4
|
-
|
5
|
-
Please refer to www.npmjs.com/advisories?search=ctct-helpers for more information.
|