@bernierllc/email-sendgrid-plugin 1.4.5 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/errors.js +5 -0
- package/dist/api/rate-limiter.js +3 -1
- package/dist/api/sendgrid-client.js +4 -1
- package/dist/converters/template-converter.js +1 -0
- package/dist/errors.d.ts +11 -0
- package/dist/errors.js +24 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -1
- package/dist/plugin/sender-manager.js +6 -1
- package/dist/plugin/sendgrid-plugin.js +15 -4
- package/dist/plugin/sync-manager.js +4 -0
- package/dist/plugin/template-manager.js +5 -0
- package/dist/safety/ownership-validator.js +3 -1
- package/dist/safety/prefix-enforcer.js +1 -0
- package/package.json +8 -4
- package/.eslintrc.js +0 -27
- package/CHANGELOG.md +0 -117
- package/__tests__/api/rate-limiter.test.ts +0 -125
- package/__tests__/converters/attachment-header-mapping.test.ts +0 -337
- package/__tests__/converters/sender-converter.test.ts +0 -148
- package/__tests__/converters/template-converter.test.ts +0 -230
- package/__tests__/plugin/sender-manager.test.ts +0 -135
- package/__tests__/plugin/sendgrid-plugin.test.ts +0 -195
- package/__tests__/plugin/template-manager.test.ts +0 -110
- package/__tests__/safety/ownership-validator.test.ts +0 -130
- package/__tests__/safety/prefix-enforcer.test.ts +0 -136
- package/jest.config.js +0 -26
- package/src/api/errors.ts +0 -49
- package/src/api/rate-limiter.ts +0 -79
- package/src/api/sendgrid-client.ts +0 -86
- package/src/converters/sender-converter.ts +0 -138
- package/src/converters/template-converter.ts +0 -97
- package/src/index.ts +0 -61
- package/src/plugin/sender-manager.ts +0 -166
- package/src/plugin/sendgrid-plugin.ts +0 -316
- package/src/plugin/sync-manager.ts +0 -115
- package/src/plugin/template-manager.ts +0 -240
- package/src/safety/ownership-validator.ts +0 -55
- package/src/safety/prefix-enforcer.ts +0 -37
- package/src/types/config-types.ts +0 -34
- package/src/types/plugin-types.ts +0 -97
- package/src/types/sendgrid-types.ts +0 -98
- package/tsconfig.json +0 -18
package/dist/api/errors.js
CHANGED
|
@@ -9,6 +9,8 @@ Redistribution or use in other products or commercial offerings is not permitted
|
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.RateLimitError = exports.TemplateConflictError = exports.UnauthorizedTemplateAccessError = exports.TemplateNotFoundError = exports.SendGridApiError = void 0;
|
|
11
11
|
class SendGridApiError extends Error {
|
|
12
|
+
statusCode;
|
|
13
|
+
response;
|
|
12
14
|
constructor(message, statusCode, response) {
|
|
13
15
|
super(message);
|
|
14
16
|
this.statusCode = statusCode;
|
|
@@ -18,6 +20,7 @@ class SendGridApiError extends Error {
|
|
|
18
20
|
}
|
|
19
21
|
exports.SendGridApiError = SendGridApiError;
|
|
20
22
|
class TemplateNotFoundError extends Error {
|
|
23
|
+
templateId;
|
|
21
24
|
constructor(templateId) {
|
|
22
25
|
super(`Template not found: ${templateId}`);
|
|
23
26
|
this.templateId = templateId;
|
|
@@ -33,6 +36,8 @@ class UnauthorizedTemplateAccessError extends Error {
|
|
|
33
36
|
}
|
|
34
37
|
exports.UnauthorizedTemplateAccessError = UnauthorizedTemplateAccessError;
|
|
35
38
|
class TemplateConflictError extends Error {
|
|
39
|
+
templateId;
|
|
40
|
+
conflicts;
|
|
36
41
|
constructor(templateId, conflicts) {
|
|
37
42
|
super(`Template conflicts detected: ${conflicts.join(', ')}`);
|
|
38
43
|
this.templateId = templateId;
|
package/dist/api/rate-limiter.js
CHANGED
|
@@ -10,8 +10,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.SimpleRateLimiter = void 0;
|
|
11
11
|
const errors_1 = require("./errors");
|
|
12
12
|
class SimpleRateLimiter {
|
|
13
|
+
requestTimestamps = [];
|
|
14
|
+
maxRequestsPerSecond;
|
|
15
|
+
maxRequestsPerMinute;
|
|
13
16
|
constructor(config) {
|
|
14
|
-
this.requestTimestamps = [];
|
|
15
17
|
this.maxRequestsPerSecond = config.maxRequestsPerSecond;
|
|
16
18
|
this.maxRequestsPerMinute = config.maxRequestsPerMinute;
|
|
17
19
|
}
|
|
@@ -10,8 +10,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.SendGridClient = void 0;
|
|
11
11
|
const errors_1 = require("./errors");
|
|
12
12
|
class SendGridClient {
|
|
13
|
+
apiKey;
|
|
14
|
+
rateLimiter;
|
|
15
|
+
logger;
|
|
16
|
+
baseUrl = 'https://api.sendgrid.com/v3';
|
|
13
17
|
constructor(config) {
|
|
14
|
-
this.baseUrl = 'https://api.sendgrid.com/v3';
|
|
15
18
|
this.apiKey = config.apiKey;
|
|
16
19
|
this.rateLimiter = config.rateLimiter;
|
|
17
20
|
this.logger = config.logger;
|
|
@@ -9,6 +9,7 @@ Redistribution or use in other products or commercial offerings is not permitted
|
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.TemplateConverter = void 0;
|
|
11
11
|
class TemplateConverter {
|
|
12
|
+
prefixEnforcer;
|
|
12
13
|
constructor(prefixEnforcer) {
|
|
13
14
|
this.prefixEnforcer = prefixEnforcer;
|
|
14
15
|
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type EmailSendgridPluginErrorCode = 'EMAIL_SENDGRID_PLUGIN_ERROR' | 'INVALID_INPUT' | 'OPERATION_FAILED';
|
|
2
|
+
export interface EmailSendgridPluginErrorOptions {
|
|
3
|
+
cause?: Error;
|
|
4
|
+
code?: EmailSendgridPluginErrorCode;
|
|
5
|
+
context?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export declare class EmailSendgridPluginError extends Error {
|
|
8
|
+
readonly code: EmailSendgridPluginErrorCode;
|
|
9
|
+
readonly context?: Record<string, unknown>;
|
|
10
|
+
constructor(message: string, options?: EmailSendgridPluginErrorOptions);
|
|
11
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (c) 2025 Bernier LLC
|
|
4
|
+
|
|
5
|
+
This file is licensed to the client under a limited-use license.
|
|
6
|
+
The client may use and modify this code only within the scope of the project it was delivered for.
|
|
7
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.EmailSendgridPluginError = void 0;
|
|
11
|
+
class EmailSendgridPluginError extends Error {
|
|
12
|
+
code;
|
|
13
|
+
context;
|
|
14
|
+
constructor(message, options) {
|
|
15
|
+
super(message, options?.cause ? { cause: options.cause } : undefined);
|
|
16
|
+
this.name = 'EmailSendgridPluginError';
|
|
17
|
+
this.code = options?.code ?? 'EMAIL_SENDGRID_PLUGIN_ERROR';
|
|
18
|
+
if (options?.context !== undefined) {
|
|
19
|
+
this.context = options.context;
|
|
20
|
+
}
|
|
21
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.EmailSendgridPluginError = EmailSendgridPluginError;
|
package/dist/index.d.ts
CHANGED
|
@@ -12,3 +12,4 @@ export { SendGridApiError, TemplateNotFoundError, UnauthorizedTemplateAccessErro
|
|
|
12
12
|
export type { SendGridPluginConfig, ApiRequestOptions, ApiResponse } from './types/config-types';
|
|
13
13
|
export type { PluginConfig, ProviderCapability, Template, ProviderTemplate, TemplateVersion, SyncResult, ValidationResult, DateRange, TemplateAnalytics, FeatureConfig } from './types/plugin-types';
|
|
14
14
|
export type { VerifiedSender, SenderValidationResult, SendGridTemplateData, SendGridTemplateVersion, SendGridVerifiedSenderData, EmailAttachment, SendGridAttachment, SendGridMailPayload } from './types/sendgrid-types';
|
|
15
|
+
export { EmailSendgridPluginError, type EmailSendgridPluginErrorCode, type EmailSendgridPluginErrorOptions } from './errors';
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ The client may use and modify this code *only within the scope of the project it
|
|
|
7
7
|
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.RateLimitError = exports.TemplateConflictError = exports.UnauthorizedTemplateAccessError = exports.TemplateNotFoundError = exports.SendGridApiError = exports.SenderConverter = exports.TemplateConverter = exports.PrefixEnforcer = exports.OwnershipValidator = exports.SimpleRateLimiter = exports.SendGridClient = exports.SyncManager = exports.SenderManager = exports.TemplateManager = exports.SendGridTemplatePlugin = void 0;
|
|
10
|
+
exports.EmailSendgridPluginError = exports.RateLimitError = exports.TemplateConflictError = exports.UnauthorizedTemplateAccessError = exports.TemplateNotFoundError = exports.SendGridApiError = exports.SenderConverter = exports.TemplateConverter = exports.PrefixEnforcer = exports.OwnershipValidator = exports.SimpleRateLimiter = exports.SendGridClient = exports.SyncManager = exports.SenderManager = exports.TemplateManager = exports.SendGridTemplatePlugin = void 0;
|
|
11
11
|
// Main plugin class
|
|
12
12
|
var sendgrid_plugin_1 = require("./plugin/sendgrid-plugin");
|
|
13
13
|
Object.defineProperty(exports, "SendGridTemplatePlugin", { enumerable: true, get: function () { return sendgrid_plugin_1.SendGridTemplatePlugin; } });
|
|
@@ -40,3 +40,6 @@ Object.defineProperty(exports, "TemplateNotFoundError", { enumerable: true, get:
|
|
|
40
40
|
Object.defineProperty(exports, "UnauthorizedTemplateAccessError", { enumerable: true, get: function () { return errors_1.UnauthorizedTemplateAccessError; } });
|
|
41
41
|
Object.defineProperty(exports, "TemplateConflictError", { enumerable: true, get: function () { return errors_1.TemplateConflictError; } });
|
|
42
42
|
Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return errors_1.RateLimitError; } });
|
|
43
|
+
// Standard error type
|
|
44
|
+
var errors_2 = require("./errors");
|
|
45
|
+
Object.defineProperty(exports, "EmailSendgridPluginError", { enumerable: true, get: function () { return errors_2.EmailSendgridPluginError; } });
|
|
@@ -10,11 +10,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.SenderManager = void 0;
|
|
11
11
|
const errors_1 = require("../api/errors");
|
|
12
12
|
class SenderManager {
|
|
13
|
+
client;
|
|
14
|
+
converter;
|
|
15
|
+
logger;
|
|
16
|
+
sendersCache;
|
|
17
|
+
cacheTimestamp;
|
|
18
|
+
cacheTTL = 300000; // 5 minutes
|
|
13
19
|
constructor(client, converter, logger) {
|
|
14
20
|
this.client = client;
|
|
15
21
|
this.converter = converter;
|
|
16
22
|
this.logger = logger;
|
|
17
|
-
this.cacheTTL = 300000; // 5 minutes
|
|
18
23
|
}
|
|
19
24
|
async getVerifiedSenders(useCache = true) {
|
|
20
25
|
// Return cached data if valid
|
|
@@ -18,11 +18,22 @@ const template_manager_1 = require("./template-manager");
|
|
|
18
18
|
const sender_manager_1 = require("./sender-manager");
|
|
19
19
|
const sync_manager_1 = require("./sync-manager");
|
|
20
20
|
class SendGridTemplatePlugin {
|
|
21
|
+
name = 'sendgrid-templates';
|
|
22
|
+
version = '1.0.0';
|
|
23
|
+
providerId = 'sendgrid';
|
|
24
|
+
client;
|
|
25
|
+
rateLimiter;
|
|
26
|
+
ownershipValidator;
|
|
27
|
+
prefixEnforcer;
|
|
28
|
+
templateConverter;
|
|
29
|
+
senderConverter;
|
|
30
|
+
templateManager;
|
|
31
|
+
senderManager;
|
|
32
|
+
syncManager;
|
|
33
|
+
config;
|
|
34
|
+
logger;
|
|
35
|
+
initialized = false;
|
|
21
36
|
constructor(config) {
|
|
22
|
-
this.name = 'sendgrid-templates';
|
|
23
|
-
this.version = '1.0.0';
|
|
24
|
-
this.providerId = 'sendgrid';
|
|
25
|
-
this.initialized = false;
|
|
26
37
|
this.config = config;
|
|
27
38
|
}
|
|
28
39
|
async initialize(__pluginConfig) {
|
|
@@ -9,6 +9,10 @@ Redistribution or use in other products or commercial offerings is not permitted
|
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.SyncManager = void 0;
|
|
11
11
|
class SyncManager {
|
|
12
|
+
templateManager;
|
|
13
|
+
converter;
|
|
14
|
+
client;
|
|
15
|
+
logger;
|
|
12
16
|
constructor(templateManager, converter, client, logger) {
|
|
13
17
|
this.templateManager = templateManager;
|
|
14
18
|
this.converter = converter;
|
|
@@ -10,6 +10,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.TemplateManager = void 0;
|
|
11
11
|
const errors_1 = require("../api/errors");
|
|
12
12
|
class TemplateManager {
|
|
13
|
+
client;
|
|
14
|
+
ownershipValidator;
|
|
15
|
+
prefixEnforcer;
|
|
16
|
+
converter;
|
|
17
|
+
logger;
|
|
13
18
|
constructor(client, ownershipValidator, prefixEnforcer, converter, logger) {
|
|
14
19
|
this.client = client;
|
|
15
20
|
this.ownershipValidator = ownershipValidator;
|
|
@@ -10,8 +10,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.OwnershipValidator = void 0;
|
|
11
11
|
const errors_1 = require("../api/errors");
|
|
12
12
|
class OwnershipValidator {
|
|
13
|
+
appTemplateIds = new Set();
|
|
14
|
+
safetyMode;
|
|
15
|
+
logger;
|
|
13
16
|
constructor(safetyMode, logger) {
|
|
14
|
-
this.appTemplateIds = new Set();
|
|
15
17
|
this.safetyMode = safetyMode;
|
|
16
18
|
this.logger = logger;
|
|
17
19
|
}
|
|
@@ -9,6 +9,7 @@ Redistribution or use in other products or commercial offerings is not permitted
|
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.PrefixEnforcer = void 0;
|
|
11
11
|
class PrefixEnforcer {
|
|
12
|
+
prefix;
|
|
12
13
|
constructor(prefix) {
|
|
13
14
|
this.prefix = prefix;
|
|
14
15
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bernierllc/email-sendgrid-plugin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"deprecated": "This package is deprecated. SendGrid functionality has been merged into @bernierllc/email-sender@3.0.0+. See https://github.com/BernierLLC/tools/blob/main/packages/core/email-sender/MIGRATION.md for migration guide.",
|
|
5
5
|
"description": "SendGrid-specific template management, sender verification, and advanced features plugin for email template service",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist/**/*",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
8
12
|
"keywords": [
|
|
9
13
|
"sendgrid",
|
|
10
14
|
"email",
|
|
@@ -17,9 +21,9 @@
|
|
|
17
21
|
"license": "SEE LICENSE IN LICENSE",
|
|
18
22
|
"dependencies": {
|
|
19
23
|
"@sendgrid/mail": "^8.1.3",
|
|
20
|
-
"@bernierllc/logger": "1.
|
|
21
|
-
"@bernierllc/
|
|
22
|
-
"@bernierllc/
|
|
24
|
+
"@bernierllc/logger": "1.6.0",
|
|
25
|
+
"@bernierllc/rate-limiter": "0.5.0",
|
|
26
|
+
"@bernierllc/retry-policy": "0.6.0"
|
|
23
27
|
},
|
|
24
28
|
"devDependencies": {
|
|
25
29
|
"@types/jest": "^29.5.12",
|
package/.eslintrc.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright (c) 2025 Bernier LLC
|
|
3
|
-
|
|
4
|
-
This file is licensed to the client under a limited-use license.
|
|
5
|
-
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
-
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
module.exports = {
|
|
10
|
-
parser: '@typescript-eslint/parser',
|
|
11
|
-
extends: [
|
|
12
|
-
'eslint:recommended',
|
|
13
|
-
'plugin:@typescript-eslint/recommended',
|
|
14
|
-
],
|
|
15
|
-
parserOptions: {
|
|
16
|
-
ecmaVersion: 2020,
|
|
17
|
-
sourceType: 'module',
|
|
18
|
-
},
|
|
19
|
-
rules: {
|
|
20
|
-
'@typescript-eslint/no-explicit-any': 'warn',
|
|
21
|
-
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
22
|
-
'@typescript-eslint/no-unused-vars': ['error', {
|
|
23
|
-
'argsIgnorePattern': '^_+',
|
|
24
|
-
'varsIgnorePattern': '^_+'
|
|
25
|
-
}],
|
|
26
|
-
},
|
|
27
|
-
};
|
package/CHANGELOG.md
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
# Change Log
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
-
|
|
6
|
-
## [1.4.5](https://github.com/bernierllc/tools/compare/@bernierllc/email-sendgrid-plugin@1.4.4...@bernierllc/email-sendgrid-plugin@1.4.5) (2026-05-19)
|
|
7
|
-
|
|
8
|
-
**Note:** Version bump only for package @bernierllc/email-sendgrid-plugin
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
## [1.4.4](https://github.com/bernierllc/tools/compare/@bernierllc/email-sendgrid-plugin@1.4.3...@bernierllc/email-sendgrid-plugin@1.4.4) (2026-05-19)
|
|
15
|
-
|
|
16
|
-
**Note:** Version bump only for package @bernierllc/email-sendgrid-plugin
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
## [1.4.3](https://github.com/bernierllc/tools/compare/@bernierllc/email-sendgrid-plugin@1.4.2...@bernierllc/email-sendgrid-plugin@1.4.3) (2026-05-19)
|
|
23
|
-
|
|
24
|
-
**Note:** Version bump only for package @bernierllc/email-sendgrid-plugin
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
## [1.4.2](https://github.com/bernierllc/tools/compare/@bernierllc/email-sendgrid-plugin@1.4.1...@bernierllc/email-sendgrid-plugin@1.4.2) (2026-03-30)
|
|
31
|
-
|
|
32
|
-
**Note:** Version bump only for package @bernierllc/email-sendgrid-plugin
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
## [1.4.1](https://github.com/bernierllc/tools/compare/@bernierllc/email-sendgrid-plugin@1.4.0...@bernierllc/email-sendgrid-plugin@1.4.1) (2026-03-09)
|
|
39
|
-
|
|
40
|
-
**Note:** Version bump only for package @bernierllc/email-sendgrid-plugin
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
# [1.4.0](https://github.com/bernierllc/tools/compare/@bernierllc/email-sendgrid-plugin@1.3.0...@bernierllc/email-sendgrid-plugin@1.4.0) (2026-03-03)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
### Bug Fixes
|
|
50
|
-
|
|
51
|
-
* **email-sendgrid-plugin:** use workspace:* for internal dependencies ([5846df1](https://github.com/bernierllc/tools/commit/5846df165069987cac4f61dc44c2e09e403e8b66))
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
### Features
|
|
55
|
-
|
|
56
|
-
* **email:** add multi-provider capability matrix with smart routing ([#29](https://github.com/bernierllc/tools/issues/29)) ([b9c38c0](https://github.com/bernierllc/tools/commit/b9c38c0a93985dc1675681657cc2ec3a209a9435))
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
# 1.3.0 (2025-12-25)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
### Bug Fixes
|
|
66
|
-
|
|
67
|
-
* **ci:** add lerna version step before publish ([3d20300](https://github.com/bernierllc/tools/commit/3d203002143bf353fffafe4f8a78a99009567347))
|
|
68
|
-
* **ci:** correct jest testEnvironment paths for CI ([c47144c](https://github.com/bernierllc/tools/commit/c47144c3d78aec2be1e1454066c235c2227823fd))
|
|
69
|
-
* **ci:** fix release workflow + convert internal deps to workspace:* ([01c078b](https://github.com/bernierllc/tools/commit/01c078b49d6025f7eef750f79207a1c71c8d85dc))
|
|
70
|
-
* **jest:** resolve Node.js v25+ localStorage SecurityError ([8ffc512](https://github.com/bernierllc/tools/commit/8ffc512805519bc5ba523bdbcd1c457e84998c9e))
|
|
71
|
-
* update neverhub-adapter deps to workspace:* and publish 0.1.2 ([f0e3d04](https://github.com/bernierllc/tools/commit/f0e3d04d8d4f094e3bb899ddf81e93243d16e2c2))
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
### Features
|
|
75
|
-
|
|
76
|
-
* **email-sendgrid-plugin:** Implement SendGrid template management and sender verification plugin ([5368de9](https://github.com/bernierllc/tools/commit/5368de95d03888e5561fa0d01281f603b3f4a6f1))
|
|
77
|
-
* **email:** deprecate email-sendgrid-plugin and document consolidation status ([724e37c](https://github.com/bernierllc/tools/commit/724e37ca80dac6ddea112fdc1129fb78018c1c82))
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
# 1.2.0 (2025-12-25)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
### Bug Fixes
|
|
87
|
-
|
|
88
|
-
* **ci:** correct jest testEnvironment paths for CI ([c47144c](https://github.com/bernierllc/tools/commit/c47144c3d78aec2be1e1454066c235c2227823fd))
|
|
89
|
-
* **ci:** fix release workflow + convert internal deps to workspace:* ([01c078b](https://github.com/bernierllc/tools/commit/01c078b49d6025f7eef750f79207a1c71c8d85dc))
|
|
90
|
-
* **jest:** resolve Node.js v25+ localStorage SecurityError ([8ffc512](https://github.com/bernierllc/tools/commit/8ffc512805519bc5ba523bdbcd1c457e84998c9e))
|
|
91
|
-
* update neverhub-adapter deps to workspace:* and publish 0.1.2 ([f0e3d04](https://github.com/bernierllc/tools/commit/f0e3d04d8d4f094e3bb899ddf81e93243d16e2c2))
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
### Features
|
|
95
|
-
|
|
96
|
-
* **email-sendgrid-plugin:** Implement SendGrid template management and sender verification plugin ([5368de9](https://github.com/bernierllc/tools/commit/5368de95d03888e5561fa0d01281f603b3f4a6f1))
|
|
97
|
-
* **email:** deprecate email-sendgrid-plugin and document consolidation status ([724e37c](https://github.com/bernierllc/tools/commit/724e37ca80dac6ddea112fdc1129fb78018c1c82))
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
# @bernierllc/email-sendgrid-plugin
|
|
104
|
-
|
|
105
|
-
## 1.1.2
|
|
106
|
-
|
|
107
|
-
### Patch Changes
|
|
108
|
-
|
|
109
|
-
- Updated dependencies [[`73c1d1e`](https://github.com/bernierllc/tools/commit/73c1d1e46114cf2ccfd5b74b83743361247f4502)]:
|
|
110
|
-
- @bernierllc/logger@1.1.0
|
|
111
|
-
|
|
112
|
-
## 1.1.1
|
|
113
|
-
|
|
114
|
-
### Patch Changes
|
|
115
|
-
|
|
116
|
-
- Updated dependencies [[`24899fa`](https://github.com/bernierllc/tools/commit/24899fa4eaf80ae329f7bd74483cf97a132f5d4c)]:
|
|
117
|
-
- @bernierllc/logger@1.0.4
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright (c) 2025 Bernier LLC
|
|
3
|
-
|
|
4
|
-
This file is licensed to the client under a limited-use license.
|
|
5
|
-
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
-
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { SimpleRateLimiter } from '../../src/api/rate-limiter';
|
|
10
|
-
import { RateLimitError } from '../../src/api/errors';
|
|
11
|
-
|
|
12
|
-
describe('SimpleRateLimiter', () => {
|
|
13
|
-
describe('constructor', () => {
|
|
14
|
-
it('should create rate limiter with specified limits', () => {
|
|
15
|
-
const limiter = new SimpleRateLimiter({
|
|
16
|
-
maxRequestsPerSecond: 10,
|
|
17
|
-
maxRequestsPerMinute: 100
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
expect(limiter).toBeDefined();
|
|
21
|
-
expect(limiter.getRemainingCapacity()).toEqual({
|
|
22
|
-
perSecond: 10,
|
|
23
|
-
perMinute: 100
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
describe('acquire', () => {
|
|
29
|
-
it('should allow requests within per-second limit', async () => {
|
|
30
|
-
const limiter = new SimpleRateLimiter({
|
|
31
|
-
maxRequestsPerSecond: 5,
|
|
32
|
-
maxRequestsPerMinute: 100
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Should allow 5 requests without delay
|
|
36
|
-
for (let i = 0; i < 5; i++) {
|
|
37
|
-
await expect(limiter.acquire()).resolves.toBeUndefined();
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should enforce per-second rate limit', async () => {
|
|
42
|
-
const limiter = new SimpleRateLimiter({
|
|
43
|
-
maxRequestsPerSecond: 2,
|
|
44
|
-
maxRequestsPerMinute: 100
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// Use up per-second quota
|
|
48
|
-
await limiter.acquire();
|
|
49
|
-
await limiter.acquire();
|
|
50
|
-
|
|
51
|
-
const start = Date.now();
|
|
52
|
-
await limiter.acquire(); // Should wait
|
|
53
|
-
const elapsed = Date.now() - start;
|
|
54
|
-
|
|
55
|
-
expect(elapsed).toBeGreaterThanOrEqual(900); // Allow some margin
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should throw error if per-minute limit wait time exceeds threshold', async () => {
|
|
59
|
-
const limiter = new SimpleRateLimiter({
|
|
60
|
-
maxRequestsPerSecond: 100,
|
|
61
|
-
maxRequestsPerMinute: 2
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
// Use up per-minute quota
|
|
65
|
-
await limiter.acquire();
|
|
66
|
-
await limiter.acquire();
|
|
67
|
-
|
|
68
|
-
// Next request should throw since wait > 5s
|
|
69
|
-
await expect(limiter.acquire()).rejects.toThrow(RateLimitError);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it.skip('should clean up old timestamps (test too slow)', async () => {
|
|
73
|
-
// This test would take >60s to run, skipping for CI/CD speed
|
|
74
|
-
// Manual verification: timestamps older than 60s are filtered out
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
describe('getRemainingCapacity', () => {
|
|
79
|
-
it('should return correct remaining capacity', async () => {
|
|
80
|
-
const limiter = new SimpleRateLimiter({
|
|
81
|
-
maxRequestsPerSecond: 5,
|
|
82
|
-
maxRequestsPerMinute: 50
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// Initial capacity
|
|
86
|
-
expect(limiter.getRemainingCapacity()).toEqual({
|
|
87
|
-
perSecond: 5,
|
|
88
|
-
perMinute: 50
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
// After 2 requests
|
|
92
|
-
await limiter.acquire();
|
|
93
|
-
await limiter.acquire();
|
|
94
|
-
|
|
95
|
-
expect(limiter.getRemainingCapacity()).toEqual({
|
|
96
|
-
perSecond: 3,
|
|
97
|
-
perMinute: 48
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('should never return negative capacity', async () => {
|
|
102
|
-
const limiter = new SimpleRateLimiter({
|
|
103
|
-
maxRequestsPerSecond: 1,
|
|
104
|
-
maxRequestsPerMinute: 10
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
await limiter.acquire();
|
|
108
|
-
|
|
109
|
-
const capacity = limiter.getRemainingCapacity();
|
|
110
|
-
expect(capacity.perSecond).toBeGreaterThanOrEqual(0);
|
|
111
|
-
expect(capacity.perMinute).toBeGreaterThanOrEqual(0);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
describe('release', () => {
|
|
116
|
-
it('should be a no-op', () => {
|
|
117
|
-
const limiter = new SimpleRateLimiter({
|
|
118
|
-
maxRequestsPerSecond: 10,
|
|
119
|
-
maxRequestsPerMinute: 100
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
expect(() => limiter.release()).not.toThrow();
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
});
|