@awesome-lang-auth/node 1.10.1
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/LICENSE +21 -0
- package/README.detailed.md +4059 -0
- package/README.md +248 -0
- package/dist/abstract/base-auth-strategy.abstract.d.ts +7 -0
- package/dist/abstract/base-auth-strategy.abstract.d.ts.map +1 -0
- package/dist/abstract/base-auth-strategy.abstract.js +7 -0
- package/dist/abstract/base-auth-strategy.abstract.js.map +1 -0
- package/dist/abstract/base-oauth-strategy.abstract.d.ts +27 -0
- package/dist/abstract/base-oauth-strategy.abstract.d.ts.map +1 -0
- package/dist/abstract/base-oauth-strategy.abstract.js +11 -0
- package/dist/abstract/base-oauth-strategy.abstract.js.map +1 -0
- package/dist/adapters/express.d.ts +45 -0
- package/dist/adapters/express.d.ts.map +1 -0
- package/dist/adapters/express.js +49 -0
- package/dist/adapters/express.js.map +1 -0
- package/dist/adapters/fastify.d.ts +72 -0
- package/dist/adapters/fastify.d.ts.map +1 -0
- package/dist/adapters/fastify.js +63 -0
- package/dist/adapters/fastify.js.map +1 -0
- package/dist/auth-configurator.d.ts +65 -0
- package/dist/auth-configurator.d.ts.map +1 -0
- package/dist/auth-configurator.js +127 -0
- package/dist/auth-configurator.js.map +1 -0
- package/dist/events/auth-event-bus.d.ts +68 -0
- package/dist/events/auth-event-bus.d.ts.map +1 -0
- package/dist/events/auth-event-bus.js +60 -0
- package/dist/events/auth-event-bus.js.map +1 -0
- package/dist/events/auth-event-names.d.ts +34 -0
- package/dist/events/auth-event-names.d.ts.map +1 -0
- package/dist/events/auth-event-names.js +41 -0
- package/dist/events/auth-event-names.js.map +1 -0
- package/dist/http-types.d.ts +135 -0
- package/dist/http-types.d.ts.map +1 -0
- package/dist/http-types.js +18 -0
- package/dist/http-types.js.map +1 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/api-key-store.interface.d.ts +94 -0
- package/dist/interfaces/api-key-store.interface.d.ts.map +1 -0
- package/dist/interfaces/api-key-store.interface.js +3 -0
- package/dist/interfaces/api-key-store.interface.js.map +1 -0
- package/dist/interfaces/auth-strategy.interface.d.ts +6 -0
- package/dist/interfaces/auth-strategy.interface.d.ts.map +1 -0
- package/dist/interfaces/auth-strategy.interface.js +3 -0
- package/dist/interfaces/auth-strategy.interface.js.map +1 -0
- package/dist/interfaces/linked-accounts-store.interface.d.ts +74 -0
- package/dist/interfaces/linked-accounts-store.interface.d.ts.map +1 -0
- package/dist/interfaces/linked-accounts-store.interface.js +3 -0
- package/dist/interfaces/linked-accounts-store.interface.js.map +1 -0
- package/dist/interfaces/pending-link-store.interface.d.ts +77 -0
- package/dist/interfaces/pending-link-store.interface.d.ts.map +1 -0
- package/dist/interfaces/pending-link-store.interface.js +3 -0
- package/dist/interfaces/pending-link-store.interface.js.map +1 -0
- package/dist/interfaces/roles-permissions-store.interface.d.ts +129 -0
- package/dist/interfaces/roles-permissions-store.interface.d.ts.map +1 -0
- package/dist/interfaces/roles-permissions-store.interface.js +3 -0
- package/dist/interfaces/roles-permissions-store.interface.js.map +1 -0
- package/dist/interfaces/session-store.interface.d.ts +92 -0
- package/dist/interfaces/session-store.interface.d.ts.map +1 -0
- package/dist/interfaces/session-store.interface.js +3 -0
- package/dist/interfaces/session-store.interface.js.map +1 -0
- package/dist/interfaces/settings-store.interface.d.ts +91 -0
- package/dist/interfaces/settings-store.interface.d.ts.map +1 -0
- package/dist/interfaces/settings-store.interface.js +3 -0
- package/dist/interfaces/settings-store.interface.js.map +1 -0
- package/dist/interfaces/sse-distributor.interface.d.ts +25 -0
- package/dist/interfaces/sse-distributor.interface.d.ts.map +1 -0
- package/dist/interfaces/sse-distributor.interface.js +3 -0
- package/dist/interfaces/sse-distributor.interface.js.map +1 -0
- package/dist/interfaces/telemetry-store.interface.d.ts +72 -0
- package/dist/interfaces/telemetry-store.interface.d.ts.map +1 -0
- package/dist/interfaces/telemetry-store.interface.js +3 -0
- package/dist/interfaces/telemetry-store.interface.js.map +1 -0
- package/dist/interfaces/template-store.interface.d.ts +37 -0
- package/dist/interfaces/template-store.interface.d.ts.map +1 -0
- package/dist/interfaces/template-store.interface.js +3 -0
- package/dist/interfaces/template-store.interface.js.map +1 -0
- package/dist/interfaces/tenant-store.interface.d.ts +97 -0
- package/dist/interfaces/tenant-store.interface.d.ts.map +1 -0
- package/dist/interfaces/tenant-store.interface.js +3 -0
- package/dist/interfaces/tenant-store.interface.js.map +1 -0
- package/dist/interfaces/token-store.interface.d.ts +10 -0
- package/dist/interfaces/token-store.interface.d.ts.map +1 -0
- package/dist/interfaces/token-store.interface.js +3 -0
- package/dist/interfaces/token-store.interface.js.map +1 -0
- package/dist/interfaces/user-metadata-store.interface.d.ts +50 -0
- package/dist/interfaces/user-metadata-store.interface.d.ts.map +1 -0
- package/dist/interfaces/user-metadata-store.interface.js +3 -0
- package/dist/interfaces/user-metadata-store.interface.js.map +1 -0
- package/dist/interfaces/user-store.interface.d.ts +113 -0
- package/dist/interfaces/user-store.interface.d.ts.map +1 -0
- package/dist/interfaces/user-store.interface.js +3 -0
- package/dist/interfaces/user-store.interface.js.map +1 -0
- package/dist/interfaces/webhook-store.interface.d.ts +139 -0
- package/dist/interfaces/webhook-store.interface.d.ts.map +1 -0
- package/dist/interfaces/webhook-store.interface.js +3 -0
- package/dist/interfaces/webhook-store.interface.js.map +1 -0
- package/dist/middleware/api-key.middleware.d.ts +35 -0
- package/dist/middleware/api-key.middleware.d.ts.map +1 -0
- package/dist/middleware/api-key.middleware.js +45 -0
- package/dist/middleware/api-key.middleware.js.map +1 -0
- package/dist/middleware/auth.middleware.d.ts +13 -0
- package/dist/middleware/auth.middleware.d.ts.map +1 -0
- package/dist/middleware/auth.middleware.js +55 -0
- package/dist/middleware/auth.middleware.js.map +1 -0
- package/dist/middleware/jwks-auth.middleware.d.ts +18 -0
- package/dist/middleware/jwks-auth.middleware.d.ts.map +1 -0
- package/dist/middleware/jwks-auth.middleware.js +77 -0
- package/dist/middleware/jwks-auth.middleware.js.map +1 -0
- package/dist/models/api-key.model.d.ts +66 -0
- package/dist/models/api-key.model.d.ts.map +1 -0
- package/dist/models/api-key.model.js +3 -0
- package/dist/models/api-key.model.js.map +1 -0
- package/dist/models/auth-config.model.d.ts +387 -0
- package/dist/models/auth-config.model.d.ts.map +1 -0
- package/dist/models/auth-config.model.js +3 -0
- package/dist/models/auth-config.model.js.map +1 -0
- package/dist/models/errors.d.ts +7 -0
- package/dist/models/errors.d.ts.map +1 -0
- package/dist/models/errors.js +14 -0
- package/dist/models/errors.js.map +1 -0
- package/dist/models/session.model.d.ts +28 -0
- package/dist/models/session.model.d.ts.map +1 -0
- package/dist/models/session.model.js +3 -0
- package/dist/models/session.model.js.map +1 -0
- package/dist/models/tenant.model.d.ts +20 -0
- package/dist/models/tenant.model.d.ts.map +1 -0
- package/dist/models/tenant.model.js +3 -0
- package/dist/models/tenant.model.js.map +1 -0
- package/dist/models/token.model.d.ts +21 -0
- package/dist/models/token.model.d.ts.map +1 -0
- package/dist/models/token.model.js +3 -0
- package/dist/models/token.model.js.map +1 -0
- package/dist/models/user.model.d.ts +92 -0
- package/dist/models/user.model.d.ts.map +1 -0
- package/dist/models/user.model.js +3 -0
- package/dist/models/user.model.js.map +1 -0
- package/dist/router/admin.router.d.ts +188 -0
- package/dist/router/admin.router.d.ts.map +1 -0
- package/dist/router/admin.router.js +1507 -0
- package/dist/router/admin.router.js.map +1 -0
- package/dist/router/auth.router.d.ts +199 -0
- package/dist/router/auth.router.d.ts.map +1 -0
- package/dist/router/auth.router.js +1636 -0
- package/dist/router/auth.router.js.map +1 -0
- package/dist/router/openapi.d.ts +98 -0
- package/dist/router/openapi.d.ts.map +1 -0
- package/dist/router/openapi.js +1518 -0
- package/dist/router/openapi.js.map +1 -0
- package/dist/router/router-events.d.ts +38 -0
- package/dist/router/router-events.d.ts.map +1 -0
- package/dist/router/router-events.js +74 -0
- package/dist/router/router-events.js.map +1 -0
- package/dist/router/tools.router.d.ts +104 -0
- package/dist/router/tools.router.d.ts.map +1 -0
- package/dist/router/tools.router.js +227 -0
- package/dist/router/tools.router.js.map +1 -0
- package/dist/router/ui.router.d.ts +49 -0
- package/dist/router/ui.router.d.ts.map +1 -0
- package/dist/router/ui.router.js +272 -0
- package/dist/router/ui.router.js.map +1 -0
- package/dist/services/api-key.service.d.ts +53 -0
- package/dist/services/api-key.service.d.ts.map +1 -0
- package/dist/services/api-key.service.js +66 -0
- package/dist/services/api-key.service.js.map +1 -0
- package/dist/services/jwks.service.d.ts +73 -0
- package/dist/services/jwks.service.d.ts.map +1 -0
- package/dist/services/jwks.service.js +174 -0
- package/dist/services/jwks.service.js.map +1 -0
- package/dist/services/mailer.service.d.ts +30 -0
- package/dist/services/mailer.service.d.ts.map +1 -0
- package/dist/services/mailer.service.js +248 -0
- package/dist/services/mailer.service.js.map +1 -0
- package/dist/services/notification.service.d.ts +110 -0
- package/dist/services/notification.service.d.ts.map +1 -0
- package/dist/services/notification.service.js +79 -0
- package/dist/services/notification.service.js.map +1 -0
- package/dist/services/password.service.d.ts +5 -0
- package/dist/services/password.service.d.ts.map +1 -0
- package/dist/services/password.service.js +17 -0
- package/dist/services/password.service.js.map +1 -0
- package/dist/services/sms.service.d.ts +14 -0
- package/dist/services/sms.service.d.ts.map +1 -0
- package/dist/services/sms.service.js +51 -0
- package/dist/services/sms.service.js.map +1 -0
- package/dist/services/token.service.d.ts +62 -0
- package/dist/services/token.service.d.ts.map +1 -0
- package/dist/services/token.service.js +354 -0
- package/dist/services/token.service.js.map +1 -0
- package/dist/stores/memory-template.store.d.ts +12 -0
- package/dist/stores/memory-template.store.d.ts.map +1 -0
- package/dist/stores/memory-template.store.js +35 -0
- package/dist/stores/memory-template.store.js.map +1 -0
- package/dist/strategies/api-key/api-key.strategy.d.ts +72 -0
- package/dist/strategies/api-key/api-key.strategy.d.ts.map +1 -0
- package/dist/strategies/api-key/api-key.strategy.js +182 -0
- package/dist/strategies/api-key/api-key.strategy.js.map +1 -0
- package/dist/strategies/local/local.strategy.d.ts +19 -0
- package/dist/strategies/local/local.strategy.d.ts.map +1 -0
- package/dist/strategies/local/local.strategy.js +45 -0
- package/dist/strategies/local/local.strategy.js.map +1 -0
- package/dist/strategies/magic-link/magic-link.strategy.d.ts +8 -0
- package/dist/strategies/magic-link/magic-link.strategy.d.ts.map +1 -0
- package/dist/strategies/magic-link/magic-link.strategy.js +53 -0
- package/dist/strategies/magic-link/magic-link.strategy.js.map +1 -0
- package/dist/strategies/oauth/generic-oauth.strategy.d.ts +120 -0
- package/dist/strategies/oauth/generic-oauth.strategy.d.ts.map +1 -0
- package/dist/strategies/oauth/generic-oauth.strategy.js +88 -0
- package/dist/strategies/oauth/generic-oauth.strategy.js.map +1 -0
- package/dist/strategies/oauth/github.strategy.d.ts +31 -0
- package/dist/strategies/oauth/github.strategy.d.ts.map +1 -0
- package/dist/strategies/oauth/github.strategy.js +72 -0
- package/dist/strategies/oauth/github.strategy.js.map +1 -0
- package/dist/strategies/oauth/google.strategy.d.ts +31 -0
- package/dist/strategies/oauth/google.strategy.d.ts.map +1 -0
- package/dist/strategies/oauth/google.strategy.js +61 -0
- package/dist/strategies/oauth/google.strategy.js.map +1 -0
- package/dist/strategies/sms/sms.strategy.d.ts +7 -0
- package/dist/strategies/sms/sms.strategy.d.ts.map +1 -0
- package/dist/strategies/sms/sms.strategy.js +39 -0
- package/dist/strategies/sms/sms.strategy.js.map +1 -0
- package/dist/strategies/two-factor/totp.strategy.d.ts +12 -0
- package/dist/strategies/two-factor/totp.strategy.d.ts.map +1 -0
- package/dist/strategies/two-factor/totp.strategy.js +32 -0
- package/dist/strategies/two-factor/totp.strategy.js.map +1 -0
- package/dist/tools/auth-tools.d.ts +200 -0
- package/dist/tools/auth-tools.d.ts.map +1 -0
- package/dist/tools/auth-tools.js +232 -0
- package/dist/tools/auth-tools.js.map +1 -0
- package/dist/tools/sse-manager.d.ts +118 -0
- package/dist/tools/sse-manager.d.ts.map +1 -0
- package/dist/tools/sse-manager.js +163 -0
- package/dist/tools/sse-manager.js.map +1 -0
- package/dist/tools/sse-notify.decorator.d.ts +74 -0
- package/dist/tools/sse-notify.decorator.d.ts.map +1 -0
- package/dist/tools/sse-notify.decorator.js +78 -0
- package/dist/tools/sse-notify.decorator.js.map +1 -0
- package/dist/tools/webhook-action.d.ts +130 -0
- package/dist/tools/webhook-action.d.ts.map +1 -0
- package/dist/tools/webhook-action.js +144 -0
- package/dist/tools/webhook-action.js.map +1 -0
- package/dist/tools/webhook-sender.d.ts +31 -0
- package/dist/tools/webhook-sender.d.ts.map +1 -0
- package/dist/tools/webhook-sender.js +80 -0
- package/dist/tools/webhook-sender.js.map +1 -0
- package/dist/ui-assets/2fa.html +115 -0
- package/dist/ui-assets/account-conflict.html +108 -0
- package/dist/ui-assets/admin.css +263 -0
- package/dist/ui-assets/admin.js +1927 -0
- package/dist/ui-assets/auth.js +725 -0
- package/dist/ui-assets/base.css +219 -0
- package/dist/ui-assets/forgot-password.html +93 -0
- package/dist/ui-assets/link-verify.html +74 -0
- package/dist/ui-assets/login.html +135 -0
- package/dist/ui-assets/magic-link.html +112 -0
- package/dist/ui-assets/register.html +122 -0
- package/dist/ui-assets/reset-password.html +103 -0
- package/dist/ui-assets/ui-i18n-keys.json +78 -0
- package/dist/ui-assets/verify-email.html +66 -0
- package/package.json +89 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.JwksService = exports.JwksClient = void 0;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
const https_1 = __importDefault(require("https"));
|
|
9
|
+
const http_1 = __importDefault(require("http"));
|
|
10
|
+
/**
|
|
11
|
+
* A simple cached JWKS client for Resource Server use.
|
|
12
|
+
* Fetches and caches the public keys from a remote JWKS URL.
|
|
13
|
+
*/
|
|
14
|
+
class JwksClient {
|
|
15
|
+
constructor(jwksUrl, options = {}) {
|
|
16
|
+
this.jwksUrl = jwksUrl;
|
|
17
|
+
this.cachedDocument = null;
|
|
18
|
+
this.cacheExpiry = 0;
|
|
19
|
+
this.fetchPromise = null;
|
|
20
|
+
this.cacheTtl = options.cacheTtl ?? 3600000;
|
|
21
|
+
this.fetchTimeout = options.fetchTimeout ?? 5000;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the JWKS document, fetching from remote if the cache is stale.
|
|
25
|
+
* Uses stale-while-revalidate: returns the cached doc immediately if available,
|
|
26
|
+
* then refreshes in the background when TTL expires.
|
|
27
|
+
*/
|
|
28
|
+
async getJwks() {
|
|
29
|
+
const now = Date.now();
|
|
30
|
+
if (this.cachedDocument && now < this.cacheExpiry) {
|
|
31
|
+
return this.cachedDocument;
|
|
32
|
+
}
|
|
33
|
+
// If a fetch is already in progress, wait for it
|
|
34
|
+
if (this.fetchPromise) {
|
|
35
|
+
return this.fetchPromise;
|
|
36
|
+
}
|
|
37
|
+
// Stale-while-revalidate: return cached doc immediately if we have one,
|
|
38
|
+
// and trigger background refresh
|
|
39
|
+
if (this.cachedDocument) {
|
|
40
|
+
this.fetchPromise = this._fetch()
|
|
41
|
+
.then((doc) => {
|
|
42
|
+
this.cachedDocument = doc;
|
|
43
|
+
this.cacheExpiry = Date.now() + this.cacheTtl;
|
|
44
|
+
this.fetchPromise = null;
|
|
45
|
+
return doc;
|
|
46
|
+
})
|
|
47
|
+
.catch(() => {
|
|
48
|
+
this.fetchPromise = null;
|
|
49
|
+
return this.cachedDocument;
|
|
50
|
+
});
|
|
51
|
+
// Return stale cache immediately
|
|
52
|
+
return this.cachedDocument;
|
|
53
|
+
}
|
|
54
|
+
// No cache at all — must wait for the initial fetch
|
|
55
|
+
this.fetchPromise = this._fetch().then((doc) => {
|
|
56
|
+
this.cachedDocument = doc;
|
|
57
|
+
this.cacheExpiry = Date.now() + this.cacheTtl;
|
|
58
|
+
this.fetchPromise = null;
|
|
59
|
+
return doc;
|
|
60
|
+
});
|
|
61
|
+
try {
|
|
62
|
+
return await this.fetchPromise;
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
this.fetchPromise = null;
|
|
66
|
+
throw err;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Find a JWK by its key ID (`kid`). Returns null if not found. */
|
|
70
|
+
async getKey(kid) {
|
|
71
|
+
const doc = await this.getJwks();
|
|
72
|
+
return doc.keys.find((k) => k.kid === kid) ?? null;
|
|
73
|
+
}
|
|
74
|
+
/** Force-invalidate the cache so the next call fetches fresh keys. */
|
|
75
|
+
invalidateCache() {
|
|
76
|
+
this.cachedDocument = null;
|
|
77
|
+
this.cacheExpiry = 0;
|
|
78
|
+
this.fetchPromise = null;
|
|
79
|
+
}
|
|
80
|
+
_fetch() {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
const url = new URL(this.jwksUrl);
|
|
83
|
+
const transport = url.protocol === 'https:' ? https_1.default : http_1.default;
|
|
84
|
+
const timeout = setTimeout(() => reject(new Error(`JWKS fetch timed out: ${this.jwksUrl}`)), this.fetchTimeout);
|
|
85
|
+
const req = transport.get(this.jwksUrl, (res) => {
|
|
86
|
+
if (res.statusCode !== 200) {
|
|
87
|
+
clearTimeout(timeout);
|
|
88
|
+
reject(new Error(`JWKS fetch failed with status ${res.statusCode}`));
|
|
89
|
+
res.resume();
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
let data = '';
|
|
93
|
+
res.on('data', (chunk) => { data += chunk.toString(); });
|
|
94
|
+
res.on('end', () => {
|
|
95
|
+
clearTimeout(timeout);
|
|
96
|
+
try {
|
|
97
|
+
const doc = JSON.parse(data);
|
|
98
|
+
if (!Array.isArray(doc.keys)) {
|
|
99
|
+
reject(new Error('Invalid JWKS document: missing "keys" array'));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
resolve(doc);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
reject(new Error('Invalid JWKS document: failed to parse JSON'));
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
req.on('error', (err) => {
|
|
110
|
+
clearTimeout(timeout);
|
|
111
|
+
reject(err);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
exports.JwksClient = JwksClient;
|
|
117
|
+
class JwksService {
|
|
118
|
+
/**
|
|
119
|
+
* Generate an RSA-2048 keypair.
|
|
120
|
+
* Returns PEM-encoded `privateKey` and `publicKey` strings.
|
|
121
|
+
*/
|
|
122
|
+
static generateKeypair() {
|
|
123
|
+
const { privateKey, publicKey } = crypto_1.default.generateKeyPairSync('rsa', {
|
|
124
|
+
modulusLength: 2048,
|
|
125
|
+
publicKeyEncoding: { type: 'spki', format: 'pem' },
|
|
126
|
+
privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
|
|
127
|
+
});
|
|
128
|
+
return { privateKey, publicKey };
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Derive the public key PEM from a private key PEM.
|
|
132
|
+
*/
|
|
133
|
+
static derivePublicKey(privateKeyPem) {
|
|
134
|
+
const keyObj = crypto_1.default.createPrivateKey(privateKeyPem);
|
|
135
|
+
return crypto_1.default.createPublicKey(keyObj).export({ type: 'spki', format: 'pem' });
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Convert a PEM-encoded RSA public key to JWK format.
|
|
139
|
+
*/
|
|
140
|
+
static publicKeyToJwk(publicKeyPem, kid) {
|
|
141
|
+
const keyObj = crypto_1.default.createPublicKey(publicKeyPem);
|
|
142
|
+
const jwk = keyObj.export({ format: 'jwk' });
|
|
143
|
+
return {
|
|
144
|
+
kty: jwk.kty,
|
|
145
|
+
use: 'sig',
|
|
146
|
+
alg: 'RS256',
|
|
147
|
+
kid,
|
|
148
|
+
n: jwk.n,
|
|
149
|
+
e: jwk.e,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Build a full JWKS document from a PEM-encoded RSA public key.
|
|
154
|
+
*/
|
|
155
|
+
static buildJwksDocument(publicKeyPem, kid = 'provisioner-key-1') {
|
|
156
|
+
return { keys: [JwksService.publicKeyToJwk(publicKeyPem, kid)] };
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Create a cached JWKS client for a remote URL (Resource Server use).
|
|
160
|
+
*/
|
|
161
|
+
static createRemoteClient(jwksUrl, options) {
|
|
162
|
+
return new JwksClient(jwksUrl, options);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Convert a JWK (`n`, `e` fields) to an RSA public key PEM string
|
|
166
|
+
* usable by `jwt.verify()`.
|
|
167
|
+
*/
|
|
168
|
+
static jwkToPublicKey(jwk) {
|
|
169
|
+
const keyObj = crypto_1.default.createPublicKey({ key: jwk, format: 'jwk' });
|
|
170
|
+
return keyObj.export({ type: 'spki', format: 'pem' });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
exports.JwksService = JwksService;
|
|
174
|
+
//# sourceMappingURL=jwks.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwks.service.js","sourceRoot":"","sources":["../../src/services/jwks.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { MailerConfig } from '../models/auth-config.model';
|
|
2
|
+
import { ITemplateStore } from '../interfaces/template-store.interface';
|
|
3
|
+
export declare class MailerService {
|
|
4
|
+
private readonly config;
|
|
5
|
+
private readonly templateStore?;
|
|
6
|
+
constructor(config: MailerConfig, templateStore?: ITemplateStore | undefined);
|
|
7
|
+
private render;
|
|
8
|
+
sendPasswordReset(to: string, _token: string, link: string, lang?: string): Promise<void>;
|
|
9
|
+
sendMagicLink(to: string, _token: string, link: string, lang?: string): Promise<void>;
|
|
10
|
+
sendWelcome(to: string, data: Record<string, unknown>, lang?: string): Promise<void>;
|
|
11
|
+
sendVerificationEmail(to: string, _token: string, link: string, lang?: string): Promise<void>;
|
|
12
|
+
sendEmailChanged(to: string, newEmail: string, lang?: string): Promise<void>;
|
|
13
|
+
sendInvitation(to: string, link: string, data: Record<string, unknown>, lang?: string): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Send a custom (free-form) email notification.
|
|
16
|
+
*
|
|
17
|
+
* Use this when you need to send an arbitrary business notification (e.g.
|
|
18
|
+
* "your subscription expires in 3 days") using the same transport that is
|
|
19
|
+
* already configured for auth emails.
|
|
20
|
+
*
|
|
21
|
+
* @param to Recipient email address.
|
|
22
|
+
* @param subject Subject line.
|
|
23
|
+
* @param html HTML body.
|
|
24
|
+
* @param text Plain-text fallback (defaults to stripped HTML).
|
|
25
|
+
*/
|
|
26
|
+
sendCustom(to: string, subject: string, html: string, text?: string): Promise<void>;
|
|
27
|
+
private resolveLang;
|
|
28
|
+
private send;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=mailer.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailer.service.d.ts","sourceRoot":"","sources":["../../src/services/mailer.service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AA0IxE,qBAAa,aAAa;IAEtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;gBADd,MAAM,EAAE,YAAY,EACpB,aAAa,CAAC,EAAE,cAAc,YAAA;YAGnC,MAAM;IAoCd,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKzF,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrF,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpF,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7F,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5E,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB3G;;;;;;;;;;;OAWG;IACG,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAczF,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,IAAI;CA+Bb"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.MailerService = void 0;
|
|
7
|
+
const https_1 = __importDefault(require("https"));
|
|
8
|
+
const http_1 = __importDefault(require("http"));
|
|
9
|
+
const url_1 = require("url");
|
|
10
|
+
function passwordResetTemplate(link, lang) {
|
|
11
|
+
if (lang === 'it') {
|
|
12
|
+
return {
|
|
13
|
+
subject: 'Reimposta la tua password',
|
|
14
|
+
html: `<p>Hai richiesto di reimpostare la tua password.</p>
|
|
15
|
+
<p>Clicca sul link seguente per procedere (valido 1 ora):</p>
|
|
16
|
+
<p><a href="${link}">${link}</a></p>
|
|
17
|
+
<p>Se non hai richiesto questo, ignora questa email.</p>`,
|
|
18
|
+
text: `Hai richiesto di reimpostare la tua password.\n\nClicca sul link seguente (valido 1 ora):\n${link}\n\nSe non hai richiesto questo, ignora questa email.`,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
subject: 'Reset your password',
|
|
23
|
+
html: `<p>You requested a password reset.</p>
|
|
24
|
+
<p>Click the link below to proceed (valid for 1 hour):</p>
|
|
25
|
+
<p><a href="${link}">${link}</a></p>
|
|
26
|
+
<p>If you did not request this, please ignore this email.</p>`,
|
|
27
|
+
text: `You requested a password reset.\n\nClick the link below (valid for 1 hour):\n${link}\n\nIf you did not request this, please ignore this email.`,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function magicLinkTemplate(link, lang) {
|
|
31
|
+
if (lang === 'it') {
|
|
32
|
+
return {
|
|
33
|
+
subject: 'Il tuo link di accesso',
|
|
34
|
+
html: `<p>Hai richiesto un link di accesso.</p>
|
|
35
|
+
<p>Clicca sul link seguente per accedere (valido 15 minuti):</p>
|
|
36
|
+
<p><a href="${link}">${link}</a></p>
|
|
37
|
+
<p>Se non hai richiesto questo, ignora questa email.</p>`,
|
|
38
|
+
text: `Hai richiesto un link di accesso.\n\nClicca sul link seguente (valido 15 minuti):\n${link}\n\nSe non hai richiesto questo, ignora questa email.`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
subject: 'Your magic sign-in link',
|
|
43
|
+
html: `<p>You requested a sign-in link.</p>
|
|
44
|
+
<p>Click the link below to sign in (valid for 15 minutes):</p>
|
|
45
|
+
<p><a href="${link}">${link}</a></p>
|
|
46
|
+
<p>If you did not request this, please ignore this email.</p>`,
|
|
47
|
+
text: `You requested a sign-in link.\n\nClick the link below (valid for 15 minutes):\n${link}\n\nIf you did not request this, please ignore this email.`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function welcomeTemplate(data, lang) {
|
|
51
|
+
const loginUrl = data['loginUrl'] ?? '';
|
|
52
|
+
const tempPassword = data['tempPassword'];
|
|
53
|
+
if (lang === 'it') {
|
|
54
|
+
const passwordLine = tempPassword
|
|
55
|
+
? `<p>Password temporanea: <strong>${tempPassword}</strong></p>`
|
|
56
|
+
: '';
|
|
57
|
+
const passwordText = tempPassword ? `Password temporanea: ${tempPassword}\n` : '';
|
|
58
|
+
return {
|
|
59
|
+
subject: 'Benvenuto! Il tuo account è stato creato',
|
|
60
|
+
html: `<p>Il tuo account è stato creato con successo.</p>
|
|
61
|
+
${passwordLine}
|
|
62
|
+
<p>Accedi qui: <a href="${loginUrl}">${loginUrl}</a></p>`,
|
|
63
|
+
text: `Il tuo account è stato creato con successo.\n${passwordText}Accedi qui: ${loginUrl}`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const passwordLine = tempPassword
|
|
67
|
+
? `<p>Temporary password: <strong>${tempPassword}</strong></p>`
|
|
68
|
+
: '';
|
|
69
|
+
const passwordText = tempPassword ? `Temporary password: ${tempPassword}\n` : '';
|
|
70
|
+
return {
|
|
71
|
+
subject: 'Welcome! Your account has been created',
|
|
72
|
+
html: `<p>Your account has been created successfully.</p>
|
|
73
|
+
${passwordLine}
|
|
74
|
+
<p>Sign in here: <a href="${loginUrl}">${loginUrl}</a></p>`,
|
|
75
|
+
text: `Your account has been created successfully.\n${passwordText}Sign in here: ${loginUrl}`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function verificationEmailTemplate(link, lang) {
|
|
79
|
+
if (lang === 'it') {
|
|
80
|
+
return {
|
|
81
|
+
subject: 'Verifica il tuo indirizzo email',
|
|
82
|
+
html: `<p>Grazie per esserti registrato.</p>
|
|
83
|
+
<p>Clicca sul link seguente per verificare il tuo indirizzo email (valido 24 ore):</p>
|
|
84
|
+
<p><a href="${link}">${link}</a></p>
|
|
85
|
+
<p>Se non hai creato un account, ignora questa email.</p>`,
|
|
86
|
+
text: `Grazie per esserti registrato.\n\nClicca sul link seguente per verificare il tuo indirizzo email (valido 24 ore):\n${link}\n\nSe non hai creato un account, ignora questa email.`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
subject: 'Verify your email address',
|
|
91
|
+
html: `<p>Thank you for signing up.</p>
|
|
92
|
+
<p>Click the link below to verify your email address (valid for 24 hours):</p>
|
|
93
|
+
<p><a href="${link}">${link}</a></p>
|
|
94
|
+
<p>If you did not create an account, please ignore this email.</p>`,
|
|
95
|
+
text: `Thank you for signing up.\n\nClick the link below to verify your email address (valid for 24 hours):\n${link}\n\nIf you did not create an account, please ignore this email.`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function emailChangedTemplate(newEmail, lang) {
|
|
99
|
+
if (lang === 'it') {
|
|
100
|
+
return {
|
|
101
|
+
subject: 'Il tuo indirizzo email è stato aggiornato',
|
|
102
|
+
html: `<p>Questo è un avviso che il tuo indirizzo email è stato aggiornato a <strong>${newEmail}</strong>.</p>
|
|
103
|
+
<p>Se non hai richiesto questa modifica, contatta immediatamente il supporto.</p>`,
|
|
104
|
+
text: `Il tuo indirizzo email è stato aggiornato a ${newEmail}.\n\nSe non hai richiesto questa modifica, contatta immediatamente il supporto.`,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
subject: 'Your email address has been updated',
|
|
109
|
+
html: `<p>This is a notice that your email address has been updated to <strong>${newEmail}</strong>.</p>
|
|
110
|
+
<p>If you did not request this change, please contact support immediately.</p>`,
|
|
111
|
+
text: `Your email address has been updated to ${newEmail}.\n\nIf you did not request this change, please contact support immediately.`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
class MailerService {
|
|
115
|
+
constructor(config, templateStore) {
|
|
116
|
+
this.config = config;
|
|
117
|
+
this.templateStore = templateStore;
|
|
118
|
+
}
|
|
119
|
+
async render(templateId, lang, data, fallback) {
|
|
120
|
+
const l = this.resolveLang(lang);
|
|
121
|
+
if (this.templateStore) {
|
|
122
|
+
const tpl = await this.templateStore.getMailTemplate(templateId);
|
|
123
|
+
if (tpl && tpl.baseHtml && tpl.baseText) {
|
|
124
|
+
const translations = tpl.translations[l] || tpl.translations['en'] || {};
|
|
125
|
+
const interpolate = (str) => {
|
|
126
|
+
// 1. Interpolate translations: {{T.key}}
|
|
127
|
+
let result = str.replace(/\{\{T\.([^}]+)\}\}/g, (_, key) => translations[key] || `[${key}]`);
|
|
128
|
+
// 2. Interpolate data: {{KEY}}
|
|
129
|
+
result = result.replace(/\{\{([^}]+)\}\}/g, (_, key) => {
|
|
130
|
+
if (key.startsWith('T.'))
|
|
131
|
+
return _; // already handled
|
|
132
|
+
return String(data[key] ?? `[${key}]`);
|
|
133
|
+
});
|
|
134
|
+
return result;
|
|
135
|
+
};
|
|
136
|
+
const subject = translations['subject'] || fallback(l).subject;
|
|
137
|
+
return {
|
|
138
|
+
subject: interpolate(subject),
|
|
139
|
+
html: interpolate(tpl.baseHtml),
|
|
140
|
+
text: interpolate(tpl.baseText),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return fallback(l);
|
|
145
|
+
}
|
|
146
|
+
// ---- Public helpers -------------------------------------------------------
|
|
147
|
+
async sendPasswordReset(to, _token, link, lang) {
|
|
148
|
+
const tpl = await this.render('password-reset', lang || '', { link, token: _token }, (l) => passwordResetTemplate(link, l));
|
|
149
|
+
await this.send({ to, ...tpl, from: this.config.from, fromName: this.config.fromName, provider: this.config.provider });
|
|
150
|
+
}
|
|
151
|
+
async sendMagicLink(to, _token, link, lang) {
|
|
152
|
+
const tpl = await this.render('magic-link', lang || '', { link, token: _token }, (l) => magicLinkTemplate(link, l));
|
|
153
|
+
await this.send({ to, ...tpl, from: this.config.from, fromName: this.config.fromName, provider: this.config.provider });
|
|
154
|
+
}
|
|
155
|
+
async sendWelcome(to, data, lang) {
|
|
156
|
+
const tpl = await this.render('welcome', lang || '', data, (l) => welcomeTemplate(data, l));
|
|
157
|
+
await this.send({ to, ...tpl, from: this.config.from, fromName: this.config.fromName, provider: this.config.provider });
|
|
158
|
+
}
|
|
159
|
+
async sendVerificationEmail(to, _token, link, lang) {
|
|
160
|
+
const tpl = await this.render('verify-email', lang || '', { link, token: _token }, (l) => verificationEmailTemplate(link, l));
|
|
161
|
+
await this.send({ to, ...tpl, from: this.config.from, fromName: this.config.fromName, provider: this.config.provider });
|
|
162
|
+
}
|
|
163
|
+
async sendEmailChanged(to, newEmail, lang) {
|
|
164
|
+
const tpl = await this.render('email-changed', lang || '', { newEmail }, (l) => emailChangedTemplate(newEmail, l));
|
|
165
|
+
await this.send({ to, ...tpl, from: this.config.from, fromName: this.config.fromName, provider: this.config.provider });
|
|
166
|
+
}
|
|
167
|
+
async sendInvitation(to, link, data, lang) {
|
|
168
|
+
const tpl = await this.render('invitation', lang || '', { ...data, link }, (l) => {
|
|
169
|
+
// Fallback for invitation if not defined in store
|
|
170
|
+
if (l === 'it') {
|
|
171
|
+
return {
|
|
172
|
+
subject: 'Invito ad unirsi',
|
|
173
|
+
html: `<p>Sei stato invitato.</p><p><a href="${link}">${link}</a></p>`,
|
|
174
|
+
text: `Sei stato invitato.\n\n${link}`
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
subject: 'Invitation to join',
|
|
179
|
+
html: `<p>You have been invited.</p><p><a href="${link}">${link}</a></p>`,
|
|
180
|
+
text: `You have been invited.\n\n${link}`
|
|
181
|
+
};
|
|
182
|
+
});
|
|
183
|
+
await this.send({ to, ...tpl, from: this.config.from, fromName: this.config.fromName, provider: this.config.provider });
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Send a custom (free-form) email notification.
|
|
187
|
+
*
|
|
188
|
+
* Use this when you need to send an arbitrary business notification (e.g.
|
|
189
|
+
* "your subscription expires in 3 days") using the same transport that is
|
|
190
|
+
* already configured for auth emails.
|
|
191
|
+
*
|
|
192
|
+
* @param to Recipient email address.
|
|
193
|
+
* @param subject Subject line.
|
|
194
|
+
* @param html HTML body.
|
|
195
|
+
* @param text Plain-text fallback (defaults to stripped HTML).
|
|
196
|
+
*/
|
|
197
|
+
async sendCustom(to, subject, html, text) {
|
|
198
|
+
await this.send({
|
|
199
|
+
to,
|
|
200
|
+
subject,
|
|
201
|
+
html,
|
|
202
|
+
text: text ?? html,
|
|
203
|
+
from: this.config.from,
|
|
204
|
+
fromName: this.config.fromName,
|
|
205
|
+
provider: this.config.provider,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
// ---- Transport ------------------------------------------------------------
|
|
209
|
+
resolveLang(lang) {
|
|
210
|
+
if (lang === 'it')
|
|
211
|
+
return 'it';
|
|
212
|
+
if (lang === 'en')
|
|
213
|
+
return 'en';
|
|
214
|
+
return this.config.defaultLang ?? 'en';
|
|
215
|
+
}
|
|
216
|
+
send(payload) {
|
|
217
|
+
return new Promise((resolve, reject) => {
|
|
218
|
+
const url = new url_1.URL(this.config.endpoint);
|
|
219
|
+
const body = JSON.stringify(payload);
|
|
220
|
+
const options = {
|
|
221
|
+
hostname: url.hostname,
|
|
222
|
+
port: url.port || (url.protocol === 'https:' ? 443 : 80),
|
|
223
|
+
path: url.pathname + (url.search || ''),
|
|
224
|
+
method: 'POST',
|
|
225
|
+
headers: {
|
|
226
|
+
'Content-Type': 'application/json',
|
|
227
|
+
'Content-Length': Buffer.byteLength(body),
|
|
228
|
+
'X-API-Key': this.config.apiKey,
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
const transport = url.protocol === 'https:' ? https_1.default : http_1.default;
|
|
232
|
+
const req = transport.request(options, (res) => {
|
|
233
|
+
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
234
|
+
resolve();
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
reject(new Error(`Mailer request failed with status ${res.statusCode}`));
|
|
238
|
+
}
|
|
239
|
+
res.resume();
|
|
240
|
+
});
|
|
241
|
+
req.on('error', reject);
|
|
242
|
+
req.write(body);
|
|
243
|
+
req.end();
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
exports.MailerService = MailerService;
|
|
248
|
+
//# sourceMappingURL=mailer.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailer.service.js","sourceRoot":"","sources":["../../src/services/mailer.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notification service for awesome-node-auth.
|
|
3
|
+
*
|
|
4
|
+
* Provides a thin, transport-agnostic wrapper around the built-in
|
|
5
|
+
* `MailerService` and `SmsService` so that business-level notifications
|
|
6
|
+
* (e.g. "your subscription will expire in 3 days") can be sent over the same
|
|
7
|
+
* transports that are already configured for authentication flows — without
|
|
8
|
+
* passing the entire `AuthConfig` to `AuthTools`.
|
|
9
|
+
*
|
|
10
|
+
* @since 1.8.0
|
|
11
|
+
*/
|
|
12
|
+
import { MailerConfig } from '../models/auth-config.model';
|
|
13
|
+
import { SmsConfig } from './sms.service';
|
|
14
|
+
export { SmsConfig };
|
|
15
|
+
/**
|
|
16
|
+
* Configuration for the email notification transport.
|
|
17
|
+
*
|
|
18
|
+
* Uses the same shape as `MailerConfig` so that the same object can be passed
|
|
19
|
+
* to both `AuthConfig.email.mailer` and `NotificationService`.
|
|
20
|
+
*
|
|
21
|
+
* @since 1.8.0
|
|
22
|
+
*/
|
|
23
|
+
export type EmailNotificationConfig = MailerConfig;
|
|
24
|
+
/**
|
|
25
|
+
* Configuration for the SMS notification transport.
|
|
26
|
+
*
|
|
27
|
+
* Uses the same shape as `SmsConfig` so that the same object can be passed to
|
|
28
|
+
* both `AuthConfig.sms` and `NotificationService`.
|
|
29
|
+
*
|
|
30
|
+
* @since 1.8.0
|
|
31
|
+
*/
|
|
32
|
+
export type SmsNotificationConfig = SmsConfig;
|
|
33
|
+
/**
|
|
34
|
+
* Options for {@link NotificationService.sendEmail}.
|
|
35
|
+
*
|
|
36
|
+
* @since 1.8.0
|
|
37
|
+
*/
|
|
38
|
+
export interface SendEmailOptions {
|
|
39
|
+
/** Recipient email address. */
|
|
40
|
+
to: string;
|
|
41
|
+
/** Email subject line. */
|
|
42
|
+
subject: string;
|
|
43
|
+
/** HTML body. */
|
|
44
|
+
html: string;
|
|
45
|
+
/** Plain-text fallback body. */
|
|
46
|
+
text?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Options for {@link NotificationService.sendSms}.
|
|
50
|
+
*
|
|
51
|
+
* @since 1.8.0
|
|
52
|
+
*/
|
|
53
|
+
export interface SendSmsOptions {
|
|
54
|
+
/** Recipient phone number (E.164 format recommended). */
|
|
55
|
+
to: string;
|
|
56
|
+
/** SMS message body. */
|
|
57
|
+
message: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* A thin facade that exposes email and SMS sending without requiring the
|
|
61
|
+
* entire `AuthConfig`. Intended for use with `AuthTools.notify()` when
|
|
62
|
+
* email or SMS channels are requested.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* import { NotificationService } from '@awesome-lang-auth/node';
|
|
67
|
+
*
|
|
68
|
+
* const notifications = new NotificationService({
|
|
69
|
+
* email: { endpoint: process.env.MAILER_ENDPOINT!, apiKey: process.env.MAILER_KEY!, from: 'no-reply@example.com' },
|
|
70
|
+
* sms: { endpoint: process.env.SMS_ENDPOINT!, apiKey: process.env.SMS_KEY!, username: '...', password: '...' },
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* await notifications.sendEmail({
|
|
74
|
+
* to: 'alice@example.com',
|
|
75
|
+
* subject: 'Subscription expiring',
|
|
76
|
+
* html: '<p>Your subscription expires in 3 days.</p>',
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @since 1.8.0
|
|
81
|
+
*/
|
|
82
|
+
export declare class NotificationService {
|
|
83
|
+
private readonly mailer?;
|
|
84
|
+
private readonly sms?;
|
|
85
|
+
constructor(opts?: {
|
|
86
|
+
email?: EmailNotificationConfig;
|
|
87
|
+
sms?: SmsNotificationConfig;
|
|
88
|
+
});
|
|
89
|
+
/**
|
|
90
|
+
* Send a custom email notification.
|
|
91
|
+
*
|
|
92
|
+
* Throws if no email transport is configured.
|
|
93
|
+
*
|
|
94
|
+
* @since 1.8.0
|
|
95
|
+
*/
|
|
96
|
+
sendEmail(opts: SendEmailOptions): Promise<void>;
|
|
97
|
+
/**
|
|
98
|
+
* Send a custom SMS notification.
|
|
99
|
+
*
|
|
100
|
+
* Throws if no SMS transport is configured.
|
|
101
|
+
*
|
|
102
|
+
* @since 1.8.0
|
|
103
|
+
*/
|
|
104
|
+
sendSms(opts: SendSmsOptions): Promise<void>;
|
|
105
|
+
/** `true` when an email transport is configured. */
|
|
106
|
+
get hasEmail(): boolean;
|
|
107
|
+
/** `true` when an SMS transport is configured. */
|
|
108
|
+
get hasSms(): boolean;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=notification.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification.service.d.ts","sourceRoot":"","sources":["../../src/services/notification.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB;;;;;;;GAOG;AACH,MAAM,MAAM,uBAAuB,GAAG,YAAY,CAAC;AAEnD;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,SAAS,CAAC;AAE9C;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,+BAA+B;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,yDAAyD;IACzD,EAAE,EAAE,MAAM,CAAC;IACX,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAa;gBAEtB,IAAI,GAAE;QAChB,KAAK,CAAC,EAAE,uBAAuB,CAAC;QAChC,GAAG,CAAC,EAAE,qBAAqB,CAAC;KACxB;IAKN;;;;;;OAMG;IACG,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOtD;;;;;;OAMG;IACG,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlD,oDAAoD;IACpD,IAAI,QAAQ,IAAI,OAAO,CAA0B;IACjD,kDAAkD;IAClD,IAAI,MAAM,IAAI,OAAO,CAAuB;CAC7C"}
|