@venizia/ignis 0.4.6 → 0.4.7-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.md +1 -4
- package/README.md +2 -2
- package/dist/esm/base/applications/base.d.ts.map +1 -1
- package/dist/esm/base/applications/base.js +19 -15
- package/dist/esm/base/applications/base.js.map +1 -1
- package/dist/esm/base/applications/server.d.ts +14 -9
- package/dist/esm/base/applications/server.d.ts.map +1 -1
- package/dist/esm/base/applications/server.js +36 -29
- package/dist/esm/base/applications/server.js.map +1 -1
- package/dist/esm/base/controllers/grpc/adapter.d.ts.map +1 -1
- package/dist/esm/base/controllers/grpc/adapter.js +5 -1
- package/dist/esm/base/controllers/grpc/adapter.js.map +1 -1
- package/dist/esm/base/middlewares/request-spy/request-spy.middleware.d.ts.map +1 -1
- package/dist/esm/base/middlewares/request-spy/request-spy.middleware.js +9 -3
- package/dist/esm/base/middlewares/request-spy/request-spy.middleware.js.map +1 -1
- package/dist/esm/common/constants.d.ts.map +1 -1
- package/dist/esm/common/constants.js +2 -2
- package/dist/esm/common/constants.js.map +1 -1
- package/dist/esm/components/api-reference/ui/scalar.d.ts.map +1 -1
- package/dist/esm/components/api-reference/ui/scalar.js +2 -1
- package/dist/esm/components/api-reference/ui/scalar.js.map +1 -1
- package/dist/esm/components/api-reference/ui/swagger.d.ts.map +1 -1
- package/dist/esm/components/api-reference/ui/swagger.js +2 -1
- package/dist/esm/components/api-reference/ui/swagger.js.map +1 -1
- package/dist/esm/components/auth/authenticate/component.js +2 -2
- package/dist/esm/components/auth/authenticate/component.js.map +1 -1
- package/dist/esm/components/auth/authenticate/controllers/factory.d.ts +139 -136
- package/dist/esm/components/auth/authenticate/controllers/factory.d.ts.map +1 -1
- package/dist/esm/components/auth/authenticate/controllers/factory.js +175 -172
- package/dist/esm/components/auth/authenticate/controllers/factory.js.map +1 -1
- package/dist/esm/components/auth/authenticate/controllers/jwks/definitions.js +2 -2
- package/dist/esm/components/auth/authenticate/controllers/jwks/definitions.js.map +1 -1
- package/dist/esm/components/auth/authenticate/controllers/service-certs/definitions.js +2 -2
- package/dist/esm/components/auth/authenticate/controllers/service-certs/definitions.js.map +1 -1
- package/dist/esm/components/auth/authenticate/services/bearer/abstract.service.d.ts.map +1 -1
- package/dist/esm/components/auth/authenticate/services/bearer/abstract.service.js +4 -2
- package/dist/esm/components/auth/authenticate/services/bearer/abstract.service.js.map +1 -1
- package/dist/esm/components/auth/authenticate/services/service/signer.service.d.ts.map +1 -1
- package/dist/esm/components/auth/authenticate/services/service/signer.service.js +6 -4
- package/dist/esm/components/auth/authenticate/services/service/signer.service.js.map +1 -1
- package/dist/esm/components/auth/authorize/adapters/base-filtered.js +2 -2
- package/dist/esm/components/auth/authorize/adapters/base-filtered.js.map +1 -1
- package/dist/esm/components/auth/authorize/adapters/custom-grant-expander.d.ts.map +1 -1
- package/dist/esm/components/auth/authorize/adapters/custom-grant-expander.js +2 -2
- package/dist/esm/components/auth/authorize/adapters/custom-grant-expander.js.map +1 -1
- package/dist/esm/components/auth/authorize/adapters/scoped-casbin/adapter.d.ts.map +1 -1
- package/dist/esm/components/auth/authorize/adapters/scoped-casbin/adapter.js +6 -3
- package/dist/esm/components/auth/authorize/adapters/scoped-casbin/adapter.js.map +1 -1
- package/dist/esm/components/auth/authorize/enforcers/casbin-module.d.ts.map +1 -1
- package/dist/esm/components/auth/authorize/enforcers/casbin-module.js +2 -1
- package/dist/esm/components/auth/authorize/enforcers/casbin-module.js.map +1 -1
- package/dist/esm/components/auth/authorize/enforcers/casbin.enforcer.d.ts.map +1 -1
- package/dist/esm/components/auth/authorize/enforcers/casbin.enforcer.js +9 -3
- package/dist/esm/components/auth/authorize/enforcers/casbin.enforcer.js.map +1 -1
- package/dist/esm/components/auth/models/entities/columns.d.ts +99 -0
- package/dist/esm/components/auth/models/entities/columns.d.ts.map +1 -0
- package/dist/esm/components/auth/models/entities/columns.js +133 -0
- package/dist/esm/components/auth/models/entities/columns.js.map +1 -0
- package/dist/esm/components/auth/models/entities/index.d.ts +1 -2
- package/dist/esm/components/auth/models/entities/index.d.ts.map +1 -1
- package/dist/esm/components/auth/models/entities/index.js +1 -2
- package/dist/esm/components/auth/models/entities/index.js.map +1 -1
- package/dist/esm/components/auth/models/entities/permission.model.d.ts +1 -12
- package/dist/esm/components/auth/models/entities/permission.model.d.ts.map +1 -1
- package/dist/esm/components/auth/models/entities/permission.model.js +1 -36
- package/dist/esm/components/auth/models/entities/permission.model.js.map +1 -1
- package/dist/esm/components/auth/models/entities/policy-definition.model.d.ts +1 -49
- package/dist/esm/components/auth/models/entities/policy-definition.model.d.ts.map +1 -1
- package/dist/esm/components/auth/models/entities/policy-definition.model.js +1 -69
- package/dist/esm/components/auth/models/entities/policy-definition.model.js.map +1 -1
- package/dist/esm/components/controller/grpc/grpc.component.js +2 -2
- package/dist/esm/components/controller/grpc/grpc.component.js.map +1 -1
- package/dist/esm/components/health-check/component.d.ts.map +1 -1
- package/dist/esm/components/health-check/component.js +5 -3
- package/dist/esm/components/health-check/component.js.map +1 -1
- package/dist/esm/components/health-check/controller.js +5 -5
- package/dist/esm/components/health-check/controller.js.map +1 -1
- package/dist/esm/components/index.d.ts +0 -1
- package/dist/esm/components/index.d.ts.map +1 -1
- package/dist/esm/components/index.js +0 -1
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/components/mail/helpers/executors/bull-mq-executor.helper.d.ts.map +1 -1
- package/dist/esm/components/mail/helpers/executors/bull-mq-executor.helper.js +2 -1
- package/dist/esm/components/mail/helpers/executors/bull-mq-executor.helper.js.map +1 -1
- package/dist/esm/components/mail/helpers/transporters/amazon-ses-transporter.helper.d.ts.map +1 -1
- package/dist/esm/components/mail/helpers/transporters/amazon-ses-transporter.helper.js +13 -9
- package/dist/esm/components/mail/helpers/transporters/amazon-ses-transporter.helper.js.map +1 -1
- package/dist/esm/components/mail/helpers/transporters/mailgun-transporter.helper.d.ts.map +1 -1
- package/dist/esm/components/mail/helpers/transporters/mailgun-transporter.helper.js +5 -3
- package/dist/esm/components/mail/helpers/transporters/mailgun-transporter.helper.js.map +1 -1
- package/dist/esm/components/mail/helpers/transporters/nodemail-transporter.helper.d.ts.map +1 -1
- package/dist/esm/components/mail/helpers/transporters/nodemail-transporter.helper.js +9 -7
- package/dist/esm/components/mail/helpers/transporters/nodemail-transporter.helper.js.map +1 -1
- package/dist/esm/components/mail/services/generators/verification-data.d.ts.map +1 -1
- package/dist/esm/components/mail/services/generators/verification-data.js +7 -3
- package/dist/esm/components/mail/services/generators/verification-data.js.map +1 -1
- package/dist/esm/components/mail/services/mail.service.d.ts.map +1 -1
- package/dist/esm/components/mail/services/mail.service.js +12 -9
- package/dist/esm/components/mail/services/mail.service.js.map +1 -1
- package/dist/esm/components/mail/utilities/address.utility.d.ts +12 -8
- package/dist/esm/components/mail/utilities/address.utility.d.ts.map +1 -1
- package/dist/esm/components/mail/utilities/address.utility.js +30 -27
- package/dist/esm/components/mail/utilities/address.utility.js.map +1 -1
- package/dist/esm/components/mail/utilities/attachment.utility.d.ts +31 -29
- package/dist/esm/components/mail/utilities/attachment.utility.d.ts.map +1 -1
- package/dist/esm/components/mail/utilities/attachment.utility.js +94 -86
- package/dist/esm/components/mail/utilities/attachment.utility.js.map +1 -1
- package/dist/esm/components/mail/utilities/body.utility.d.ts +6 -4
- package/dist/esm/components/mail/utilities/body.utility.d.ts.map +1 -1
- package/dist/esm/components/mail/utilities/body.utility.js +14 -12
- package/dist/esm/components/mail/utilities/body.utility.js.map +1 -1
- package/dist/esm/components/mail/utilities/mime.utility.d.ts +23 -17
- package/dist/esm/components/mail/utilities/mime.utility.d.ts.map +1 -1
- package/dist/esm/components/mail/utilities/mime.utility.js +109 -98
- package/dist/esm/components/mail/utilities/mime.utility.js.map +1 -1
- package/dist/esm/components/mail/utilities/verification.utility.d.ts +8 -2
- package/dist/esm/components/mail/utilities/verification.utility.d.ts.map +1 -1
- package/dist/esm/components/mail/utilities/verification.utility.js +7 -5
- package/dist/esm/components/mail/utilities/verification.utility.js.map +1 -1
- package/dist/esm/components/socket-io/component.js +3 -3
- package/dist/esm/components/socket-io/component.js.map +1 -1
- package/dist/esm/components/socket-io/handlers/bun.handler.d.ts +13 -11
- package/dist/esm/components/socket-io/handlers/bun.handler.d.ts.map +1 -1
- package/dist/esm/components/socket-io/handlers/bun.handler.js +32 -30
- package/dist/esm/components/socket-io/handlers/bun.handler.js.map +1 -1
- package/dist/esm/components/static-asset/common/commit-token.d.ts +21 -16
- package/dist/esm/components/static-asset/common/commit-token.d.ts.map +1 -1
- package/dist/esm/components/static-asset/common/commit-token.js +35 -28
- package/dist/esm/components/static-asset/common/commit-token.js.map +1 -1
- package/dist/esm/components/static-asset/common/constants.d.ts +0 -2
- package/dist/esm/components/static-asset/common/constants.d.ts.map +1 -1
- package/dist/esm/components/static-asset/common/constants.js +1 -3
- package/dist/esm/components/static-asset/common/constants.js.map +1 -1
- package/dist/esm/components/static-asset/common/types.d.ts +0 -4
- package/dist/esm/components/static-asset/common/types.d.ts.map +1 -1
- package/dist/esm/components/static-asset/common/types.js.map +1 -1
- package/dist/esm/components/static-asset/component.js +2 -2
- package/dist/esm/components/static-asset/component.js.map +1 -1
- package/dist/esm/components/static-asset/controller/base.definition.d.ts +6 -6
- package/dist/esm/components/static-asset/controller/base.definition.d.ts.map +1 -1
- package/dist/esm/components/static-asset/controller/base.definition.js +224 -224
- package/dist/esm/components/static-asset/controller/base.definition.js.map +1 -1
- package/dist/esm/components/static-asset/controller/factory.d.ts +23 -23
- package/dist/esm/components/static-asset/controller/factory.d.ts.map +1 -1
- package/dist/esm/components/static-asset/controller/factory.js +104 -74
- package/dist/esm/components/static-asset/controller/factory.js.map +1 -1
- package/dist/esm/components/static-asset/controller/key-scope.d.ts +28 -26
- package/dist/esm/components/static-asset/controller/key-scope.d.ts.map +1 -1
- package/dist/esm/components/static-asset/controller/key-scope.js +34 -30
- package/dist/esm/components/static-asset/controller/key-scope.js.map +1 -1
- package/dist/esm/components/static-asset/controller/meta-link.d.ts +37 -33
- package/dist/esm/components/static-asset/controller/meta-link.d.ts.map +1 -1
- package/dist/esm/components/static-asset/controller/meta-link.js +86 -84
- package/dist/esm/components/static-asset/controller/meta-link.js.map +1 -1
- package/dist/esm/components/static-asset/controller/route-options.d.ts +18 -16
- package/dist/esm/components/static-asset/controller/route-options.d.ts.map +1 -1
- package/dist/esm/components/static-asset/controller/route-options.js +28 -26
- package/dist/esm/components/static-asset/controller/route-options.js.map +1 -1
- package/dist/esm/components/static-asset/models/base.model.js +3 -3
- package/dist/esm/components/static-asset/models/base.model.js.map +1 -1
- package/dist/esm/components/websocket/component.js +2 -2
- package/dist/esm/components/websocket/component.js.map +1 -1
- package/dist/esm/components/websocket/handlers/bun.handler.d.ts +6 -4
- package/dist/esm/components/websocket/handlers/bun.handler.d.ts.map +1 -1
- package/dist/esm/components/websocket/handlers/bun.handler.js +21 -19
- package/dist/esm/components/websocket/handlers/bun.handler.js.map +1 -1
- package/dist/esm/testing/assert-application-boots.d.ts +6 -1
- package/dist/esm/testing/assert-application-boots.d.ts.map +1 -1
- package/dist/esm/testing/assert-application-boots.js +139 -129
- package/dist/esm/testing/assert-application-boots.js.map +1 -1
- package/dist/esm/utilities/drizzle-result.utility.d.ts +6 -8
- package/dist/esm/utilities/drizzle-result.utility.d.ts.map +1 -1
- package/dist/esm/utilities/drizzle-result.utility.js +23 -49
- package/dist/esm/utilities/drizzle-result.utility.js.map +1 -1
- package/dist/esm/utilities/network.utility.d.ts.map +1 -1
- package/dist/esm/utilities/network.utility.js +1 -1
- package/dist/esm/utilities/network.utility.js.map +1 -1
- package/dist/presets/app/files/src/boot.test.ts +2 -2
- package/dist/presets/app/files/src/controllers/hello.controller.ts +2 -2
- package/dist/presets/app/preset.json +4 -4
- package/dist/presets/lib/preset.json +4 -4
- package/dist/presets/shared/files/.configs/formatters/.ignore +4 -0
- package/dist/presets/shared/files/.configs/lints/.ignore +4 -0
- package/dist/presets/shared/files/.configs/lints/eslint.config.mjs +4 -0
- package/dist/presets/shared/files/.configs/lints/oxlint.config.mts +4 -0
- package/dist/presets/shared/files/README.md +15 -0
- package/dist/presets/shared/files/src/index.test.ts +8 -0
- package/dist/presets/shared/files/src/index.ts +8 -0
- package/dist/presets/shared/files/tsconfig.json +20 -0
- package/dist/presets/shared/preset.json +35 -0
- package/package.json +11 -11
- package/dist/esm/components/auth/models/entities/role.model.d.ts +0 -10
- package/dist/esm/components/auth/models/entities/role.model.d.ts.map +0 -1
- package/dist/esm/components/auth/models/entities/role.model.js +0 -15
- package/dist/esm/components/auth/models/entities/role.model.js.map +0 -1
- package/dist/esm/components/auth/models/entities/user.model.d.ts +0 -28
- package/dist/esm/components/auth/models/entities/user.model.d.ts.map +0 -1
- package/dist/esm/components/auth/models/entities/user.model.js +0 -17
- package/dist/esm/components/auth/models/entities/user.model.js.map +0 -1
- package/dist/esm/components/controller/index.d.ts +0 -2
- package/dist/esm/components/controller/index.d.ts.map +0 -1
- package/dist/esm/components/controller/index.js +0 -7
- package/dist/esm/components/controller/index.js.map +0 -1
|
@@ -1,70 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
import { AuthorizationDomainScopes } from '@venizia/ignis-kernel';
|
|
3
|
-
import { integer, jsonb, text } from 'drizzle-orm/pg-core';
|
|
4
|
-
/** Column shape is inferred, never hand-declared, so it can never drift from the `$type<>()` narrowing below. */
|
|
5
|
-
const buildCommonPolicyDefinitionColumns = () => ({
|
|
6
|
-
metadata: jsonb('metadata').$type(),
|
|
7
|
-
variant: text('variant').$type().notNull(),
|
|
8
|
-
subjectType: text('subject_type').notNull(),
|
|
9
|
-
targetType: text('target_type').notNull(),
|
|
10
|
-
// `null` IS `ANY_MEMBER`, not "unknown"; the literal is refused by `policyDefinitionDomainShapeCheck`.
|
|
11
|
-
domainType: text('domain_type'),
|
|
12
|
-
action: text('action'),
|
|
13
|
-
effect: text('effect').$type(),
|
|
14
|
-
});
|
|
15
|
-
/**
|
|
16
|
-
* `Metadata` is a type parameter, not an `opts` field: unlike `extraVariants` there is no runtime
|
|
17
|
-
* value to infer from, so supplying it means spelling `Opts` too (no partial inference):
|
|
18
|
-
* `extraPolicyDefinitionColumns<{ idType: 'string' }, IMyMetadata>({ idType: 'string' })`.
|
|
19
|
-
* Keep `ops` in a custom shape if the app also issues subset grants - `customGrant` writes it.
|
|
20
|
-
*/
|
|
21
|
-
export const extraPolicyDefinitionColumns = (opts) => {
|
|
22
|
-
const { idType = 'number' } = opts ?? {};
|
|
23
|
-
const common = buildCommonPolicyDefinitionColumns();
|
|
24
|
-
switch (idType) {
|
|
25
|
-
case 'number': {
|
|
26
|
-
return {
|
|
27
|
-
...common,
|
|
28
|
-
subjectId: integer('subject_id').notNull(),
|
|
29
|
-
targetId: integer('target_id').notNull(),
|
|
30
|
-
domainId: integer('domain_id'),
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
case 'string': {
|
|
34
|
-
return {
|
|
35
|
-
...common,
|
|
36
|
-
subjectId: text('subject_id').notNull(),
|
|
37
|
-
targetId: text('target_id').notNull(),
|
|
38
|
-
domainId: text('domain_id'),
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
default: {
|
|
42
|
-
throw getError({
|
|
43
|
-
message: `[extraPolicyDefinitionColumns] Invalid idType | idType: ${idType}`,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
/**
|
|
49
|
-
* The three legal `(domain_type, domain_id)` pairs, as CHECK predicate TEXT for a migration - text,
|
|
50
|
-
* not a Drizzle `SQL`, because a column ref in a `sql` template renders schema-qualified, which a
|
|
51
|
-
* table-level CHECK rejects.
|
|
52
|
-
*
|
|
53
|
-
* The `IS NOT NULL` guard on the last branch looks redundant next to `NOT IN` and is not: a NULL
|
|
54
|
-
* `domain_type` makes `NOT IN` evaluate to NULL, and a CHECK rejects only on FALSE - without it an id
|
|
55
|
-
* with no type passes.
|
|
56
|
-
*/
|
|
57
|
-
export const policyDefinitionDomainShapeCheck = (opts) => {
|
|
58
|
-
const { domainTypeColumn = 'domain_type', domainIdColumn = 'domain_id' } = opts ?? {};
|
|
59
|
-
const { ANY_MEMBER, SYSTEM_WIDE } = AuthorizationDomainScopes;
|
|
60
|
-
return [
|
|
61
|
-
`(${domainTypeColumn} IS NULL AND ${domainIdColumn} IS NULL)`,
|
|
62
|
-
`OR (${domainTypeColumn} = '${SYSTEM_WIDE}' AND ${domainIdColumn} IS NULL)`,
|
|
63
|
-
`OR (
|
|
64
|
-
${domainTypeColumn} IS NOT NULL
|
|
65
|
-
AND ${domainTypeColumn} NOT IN ('${ANY_MEMBER}', '${SYSTEM_WIDE}')
|
|
66
|
-
AND ${domainIdColumn} IS NOT NULL
|
|
67
|
-
)`,
|
|
68
|
-
].join('\n');
|
|
69
|
-
};
|
|
1
|
+
export {};
|
|
70
2
|
//# sourceMappingURL=policy-definition.model.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy-definition.model.js","sourceRoot":"","sources":["../../../../../../src/components/auth/models/entities/policy-definition.model.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"policy-definition.model.js","sourceRoot":"","sources":["../../../../../../src/components/auth/models/entities/policy-definition.model.ts"],"names":[],"mappings":"","sourcesContent":["import type { TIdSchemaType } from '@venizia/ignis-kernel';\n\nexport type TPolicyDefinitionOptions<ExtraVariant extends string = never> = {\n idType?: TIdSchemaType;\n /**\n * App-only edge kinds stored in this same table alongside IGNIS's seven (e.g. `merchant_role`).\n * `ScopedCasbinAdapter` never selects an undeclared variant - it is purely the consumer's data.\n * Pass as an inline array literal; the `const` type parameter below infers the literal union\n * from it without needing `as const`.\n */\n extraVariants?: ReadonlyArray<ExtraVariant>;\n};\n"]}
|
|
@@ -3,7 +3,7 @@ import { ControllerTransports } from '@venizia/ignis-kernel';
|
|
|
3
3
|
import { BindingNamespaces } from '@venizia/ignis-kernel';
|
|
4
4
|
import { Binding, BindingValueTypes, MetadataRegistry } from '@venizia/ignis-kernel';
|
|
5
5
|
import { getError } from '@venizia/ignis-helpers/core';
|
|
6
|
-
import { HTTP,
|
|
6
|
+
import { HTTP, ObjectUtility } from '@venizia/ignis-helpers/common';
|
|
7
7
|
import { GrpcBindingKeys } from './common/types.js';
|
|
8
8
|
const DEFAULT_OPTIONS = {};
|
|
9
9
|
export class GrpcComponent extends BaseComponent {
|
|
@@ -48,7 +48,7 @@ export class GrpcComponent extends BaseComponent {
|
|
|
48
48
|
configured.add(binding.key);
|
|
49
49
|
continue;
|
|
50
50
|
}
|
|
51
|
-
if (!metadata?.path || isEmpty({ value: metadata.path })) {
|
|
51
|
+
if (!metadata?.path || ObjectUtility.isEmpty({ value: metadata.path })) {
|
|
52
52
|
throw getError({
|
|
53
53
|
statusCode: HTTP.ResultCodes.RS_5.InternalServerError,
|
|
54
54
|
message: `[registerControllers] key: '${binding.key}' | Invalid controller metadata, 'path' is required for gRPC controller metadata`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grpc.component.js","sourceRoot":"","sources":["../../../../../src/components/controller/grpc/grpc.component.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACrF,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"grpc.component.js","sourceRoot":"","sources":["../../../../../src/components/controller/grpc/grpc.component.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BaseApplication } from '@/base/applications';\nimport { BaseComponent } from '@venizia/ignis-kernel';\nimport { ControllerTransports } from '@venizia/ignis-kernel';\nimport type { AbstractGrpcController } from '@/base/controllers/grpc';\nimport { BindingNamespaces } from '@venizia/ignis-kernel';\nimport { Binding, BindingValueTypes, MetadataRegistry } from '@venizia/ignis-kernel';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport { HTTP, ObjectUtility } from '@venizia/ignis-helpers/common';\nimport type { IGrpcComponentConfig } from './common/types';\nimport { GrpcBindingKeys } from './common/types';\n\nconst DEFAULT_OPTIONS: IGrpcComponentConfig = {};\n\nexport class GrpcComponent extends BaseComponent {\n constructor(private application: BaseApplication) {\n super({\n scope: GrpcComponent.name,\n initDefault: { enable: true, container: application },\n bindings: {\n [GrpcBindingKeys.GRPC_COMPONENT_OPTIONS]: Binding.bind<IGrpcComponentConfig>({\n key: GrpcBindingKeys.GRPC_COMPONENT_OPTIONS,\n }).toValue(DEFAULT_OPTIONS),\n },\n });\n }\n\n override async binding(): Promise<void> {\n const logger = this.logger.for(this.binding.name);\n const router = this.application.getRootRouter();\n\n const options = this.application.get<IGrpcComponentConfig>({\n key: GrpcBindingKeys.GRPC_COMPONENT_OPTIONS,\n isOptional: true,\n });\n\n // Batch drained before re-scanning - see `RestApplication.registerDynamicBindings` for why.\n const configured = new Set<string>();\n\n let bindings = this.application.findByTag({\n tag: BindingNamespaces.CONTROLLER,\n exclude: configured,\n });\n\n while (bindings.length > 0) {\n for (const binding of bindings) {\n if (configured.has(binding.key)) {\n continue;\n }\n\n const target = binding.getBindingMeta({ type: BindingValueTypes.CLASS });\n if (!target) {\n configured.add(binding.key);\n continue;\n }\n\n const metadata = MetadataRegistry.getInstance().getControllerMetadata({ target });\n\n // Skip non-gRPC controllers — they are configured by RestComponent\n if (metadata?.transport !== ControllerTransports.GRPC) {\n configured.add(binding.key);\n continue;\n }\n\n if (!metadata?.path || ObjectUtility.isEmpty({ value: metadata.path })) {\n throw getError({\n statusCode: HTTP.ResultCodes.RS_5.InternalServerError,\n message: `[registerControllers] key: '${binding.key}' | Invalid controller metadata, 'path' is required for gRPC controller metadata`,\n });\n }\n\n const instance = this.application.get<AbstractGrpcController>({\n key: binding.key,\n isOptional: false,\n });\n\n if (!instance) {\n logger.debug('No binding instance | key: %s', binding.key);\n configured.add(binding.key);\n continue;\n }\n\n if (!instance.service) {\n logger.warn('gRPC controller has no service definition, skipping | key: %s', binding.key);\n configured.add(binding.key);\n continue;\n }\n\n instance.basePath = this.application.getProjectConfigs().path.base;\n instance.connectRpcModule = options?.module;\n instance.interceptors = options?.interceptors;\n await instance.configure();\n\n router.route(metadata.path, instance.getRouter());\n configured.add(binding.key);\n\n logger.info('Configured gRPC controller | key: %s | path: %s', binding.key, metadata.path);\n }\n\n // Re-fetch excluding already configured — picks up dynamically added controllers\n bindings = this.application.findByTag({\n tag: BindingNamespaces.CONTROLLER,\n exclude: configured,\n });\n }\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../../../src/components/health-check/component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAY5E,qBAAa,oBAAqB,SAAQ,aAAa,CAAC,mBAAmB,CAAC;IAEpB,OAAO,CAAC,WAAW;gBAAX,WAAW,EAAE,eAAe;IAa1F;;;;OAIG;IACY,SAAS,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBpD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../../../src/components/health-check/component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAY5E,qBAAa,oBAAqB,SAAQ,aAAa,CAAC,mBAAmB,CAAC;IAEpB,OAAO,CAAC,WAAW;gBAAX,WAAW,EAAE,eAAe;IAa1F;;;;OAIG;IACY,SAAS,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBpD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAqCxC"}
|
|
@@ -71,9 +71,11 @@ let HealthCheckComponent = HealthCheckComponent_1 = class HealthCheckComponent e
|
|
|
71
71
|
}
|
|
72
72
|
// `getAppInfo()` is async while the container builds the controller synchronously, so the
|
|
73
73
|
// resolved value is bound here rather than resolved inside the controller.
|
|
74
|
-
this.application
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
const binding = this.application.bind({
|
|
75
|
+
key: HealthCheckBindingKeys.APPLICATION_INFO,
|
|
76
|
+
});
|
|
77
|
+
const appInfo = await this.application.getAppInfo();
|
|
78
|
+
binding.toValue(appInfo);
|
|
77
79
|
// The gate and the app identity are per container, but `@controller` writes the PATH onto this
|
|
78
80
|
// one shared class in the process-wide MetadataRegistry, and `RestComponent` reads it back at
|
|
79
81
|
// step 8. Two applications booted one after another are safe; two booted CONCURRENTLY with
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.js","sourceRoot":"","sources":["../../../../src/components/health-check/component.ts"],"names":[],"mappings":";;;;;;;;;;;;;AACA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAA4B,MAAM,UAAU,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGhD,MAAM,iBAAiB,GAAG,SAAS,CAAC;AACpC,MAAM,eAAe,GAAwB;IAC3C,WAAW,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE;CACzC,CAAC;AAEF,IAAa,oBAAoB,4BAAjC,MAAa,oBAAqB,SAAQ,aAAkC;IAC1E,YAC8D,WAA4B;QAExF,KAAK,CAAC;YACJ,KAAK,EAAE,sBAAoB,CAAC,IAAI;YAChC,WAAW,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE;YACrD,QAAQ,EAAE;gBACR,CAAC,sBAAsB,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC,IAAI,CAAsB;oBAC/E,GAAG,EAAE,sBAAsB,CAAC,oBAAoB;iBACjD,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC;aAC5B;SACF,CAAC,CAAC;QAVyD,gBAAW,GAAX,WAAW,CAAiB;IAW1F,CAAC;IAED;;;;OAIG;IACM,KAAK,CAAC,SAAS,CAAC,IAA0B;QACjD,0FAA0F;QAC1F,8DAA8D;QAC9D,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,OAAO;QACT,CAAC;QAED,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,CAAC,WAAW;iBACb,IAAI,CAAsB,EAAE,GAAG,EAAE,sBAAsB,CAAC,oBAAoB,EAAE,CAAC;iBAC/E,OAAO,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;QAED,MAAM,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAEQ,KAAK,CAAC,OAAO;QACpB,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAsB;YAC9D,GAAG,EAAE,sBAAsB,CAAC,oBAAoB;YAChD,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;QAEH,6FAA6F;QAC7F,MAAM,IAAI,GAAG,aAAa,EAAE,WAAW,EAAE,IAAI,IAAI,iBAAiB,CAAC;QAEnE,uFAAuF;QACvF,uFAAuF;QACvF,+FAA+F;QAC/F,IAAI,aAAa,IAAI,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC;YACtF,IAAI,CAAC,MAAM;iBACR,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;iBACtB,IAAI,CACH,4NAA4N,EAC5N,IAAI,EACJ,WAAW,CAAC,OAAO,IAAI,OAAO,CAC/B,CAAC;QACN,CAAC;QAED,0FAA0F;QAC1F,2EAA2E;QAC3E,IAAI,CAAC,WAAW
|
|
1
|
+
{"version":3,"file":"component.js","sourceRoot":"","sources":["../../../../src/components/health-check/component.ts"],"names":[],"mappings":"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","sourcesContent":["import { type BaseApplication } from '@/base/applications';\nimport { BaseComponent } from '@venizia/ignis-kernel';\nimport { controller, inject } from '@/base/metadata';\nimport { CoreBindings } from '@venizia/ignis-kernel';\nimport { HealthCheckBindingKeys, type IHealthCheckOptions } from './common';\nimport { HealthCheckController } from './controller';\nimport { HealthCheckReporter } from './reporter';\nimport { Environment } from '@venizia/ignis-helpers';\nimport { Binding } from '@venizia/ignis-kernel';\nimport type { IApplicationInfo } from '@venizia/ignis-kernel';\n\nconst DEFAULT_REST_PATH = '/health';\nconst DEFAULT_OPTIONS: IHealthCheckOptions = {\n restOptions: { path: DEFAULT_REST_PATH },\n};\n\nexport class HealthCheckComponent extends BaseComponent<IHealthCheckOptions> {\n constructor(\n @inject({ key: CoreBindings.APPLICATION_INSTANCE }) private application: BaseApplication,\n ) {\n super({\n scope: HealthCheckComponent.name,\n initDefault: { enable: true, container: application },\n bindings: {\n [HealthCheckBindingKeys.HEALTH_CHECK_OPTIONS]: Binding.bind<IHealthCheckOptions>({\n key: HealthCheckBindingKeys.HEALTH_CHECK_OPTIONS,\n }).toValue(DEFAULT_OPTIONS),\n },\n });\n }\n\n /**\n * `application.component(HealthCheckComponent, { options })` lands here. Options given at the\n * call site are the most explicit statement of intent, so they take the binding over anything\n * bound earlier; `initDefaultBindings` then finds the key taken and leaves the default aside.\n */\n override async configure(opts?: IHealthCheckOptions): Promise<void> {\n // The base short-circuits a second call; binding before that check would swap the options\n // under routes that were already mounted from the first ones.\n if (this.isConfigured) {\n return;\n }\n\n if (opts !== undefined) {\n this.application\n .bind<IHealthCheckOptions>({ key: HealthCheckBindingKeys.HEALTH_CHECK_OPTIONS })\n .toValue(opts);\n }\n\n await super.configure(opts);\n }\n\n override async binding(): Promise<void> {\n const healthOptions = this.application.get<IHealthCheckOptions>({\n key: HealthCheckBindingKeys.HEALTH_CHECK_OPTIONS,\n isOptional: true,\n });\n\n // A partially filled options binding (env/config driven) must not take the app down at boot.\n const path = healthOptions?.restOptions?.path ?? DEFAULT_REST_PATH;\n\n // Legal, occasionally correct, and silent until now: `stats.enable: true` bypasses the\n // environment gate, so the same code that opened the route for a local run opens it in\n // production. Warn rather than refuse - only the operator knows whether the port is reachable.\n if (healthOptions && HealthCheckReporter.isStatsUnguarded({ options: healthOptions })) {\n this.logger\n .for(this.binding.name)\n .warn(\n 'GET %s/stats is ENABLED with no secretKey on env \"%s\" - build stamp, runtime version and memory are readable by anything that reaches this port. Set stats.secretKey, or drop stats.enable and let the environment decide.',\n path,\n Environment.ambient ?? 'unset',\n );\n }\n\n // `getAppInfo()` is async while the container builds the controller synchronously, so the\n // resolved value is bound here rather than resolved inside the controller.\n const binding = this.application.bind<IApplicationInfo>({\n key: HealthCheckBindingKeys.APPLICATION_INFO,\n });\n const appInfo = await this.application.getAppInfo();\n binding.toValue(appInfo);\n\n // The gate and the app identity are per container, but `@controller` writes the PATH onto this\n // one shared class in the process-wide MetadataRegistry, and `RestComponent` reads it back at\n // step 8. Two applications booted one after another are safe; two booted CONCURRENTLY with\n // different `restOptions.path` would race here, and nothing in this component prevents that.\n Reflect.decorate([controller({ path })], HealthCheckController);\n this.application.controller(HealthCheckController);\n }\n}\n"]}
|
|
@@ -13,7 +13,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
13
13
|
var HealthCheckController_1;
|
|
14
14
|
import { BaseRestController } from '../../base/controllers/index.js';
|
|
15
15
|
import { api, inject } from '../../base/metadata/index.js';
|
|
16
|
-
import {
|
|
16
|
+
import { OpenApiResponses } from '@venizia/ignis-kernel';
|
|
17
17
|
import { z } from '@hono/zod-openapi';
|
|
18
18
|
import { HTTP } from '@venizia/ignis-helpers/common';
|
|
19
19
|
import { HealthCheckBindingKeys, HealthCheckHeaders, HealthCheckRestPaths, } from './common/index.js';
|
|
@@ -22,7 +22,7 @@ const RouteConfigs = {
|
|
|
22
22
|
ROOT: {
|
|
23
23
|
method: HTTP.Methods.GET,
|
|
24
24
|
path: HealthCheckRestPaths.ROOT,
|
|
25
|
-
responses: jsonResponse({
|
|
25
|
+
responses: OpenApiResponses.jsonResponse({
|
|
26
26
|
schema: z.object({ status: z.string(), timestamp: z.iso.datetime() }).openapi({
|
|
27
27
|
description: 'HealthCheck Schema',
|
|
28
28
|
examples: [{ status: 'ok', timestamp: new Date().toISOString() }],
|
|
@@ -40,7 +40,7 @@ const RouteConfigs = {
|
|
|
40
40
|
}),
|
|
41
41
|
}),
|
|
42
42
|
},
|
|
43
|
-
responses: jsonResponse({
|
|
43
|
+
responses: OpenApiResponses.jsonResponse({
|
|
44
44
|
schema: z
|
|
45
45
|
.object({
|
|
46
46
|
status: z.string(),
|
|
@@ -69,7 +69,7 @@ const RouteConfigs = {
|
|
|
69
69
|
method: HTTP.Methods.POST,
|
|
70
70
|
path: HealthCheckRestPaths.PING,
|
|
71
71
|
request: {
|
|
72
|
-
body: jsonContent({
|
|
72
|
+
body: OpenApiResponses.jsonContent({
|
|
73
73
|
description: 'PING | Request body',
|
|
74
74
|
schema: z.object({
|
|
75
75
|
type: z.string().optional().default('PING'),
|
|
@@ -77,7 +77,7 @@ const RouteConfigs = {
|
|
|
77
77
|
}),
|
|
78
78
|
}),
|
|
79
79
|
},
|
|
80
|
-
responses: jsonResponse({
|
|
80
|
+
responses: OpenApiResponses.jsonResponse({
|
|
81
81
|
schema: z
|
|
82
82
|
.object({
|
|
83
83
|
type: z.string().optional().default('PONG'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../../src/components/health-check/controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseRestController, type TRouteContext } from '@/base/controllers';\nimport { api, inject } from '@/base/metadata';\nimport { jsonContent, jsonResponse } from '@venizia/ignis-kernel';\nimport type { IApplicationInfo } from '@venizia/ignis-kernel';\nimport { z } from '@hono/zod-openapi';\nimport { HTTP, type ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport {\n HealthCheckBindingKeys,\n HealthCheckHeaders,\n HealthCheckRestPaths,\n type IHealthCheckOptions,\n} from './common';\nimport { HealthCheckReporter } from './reporter';\n\nconst RouteConfigs = {\n ROOT: {\n method: HTTP.Methods.GET,\n path: HealthCheckRestPaths.ROOT,\n responses: jsonResponse({\n schema: z.object({ status: z.string(), timestamp: z.iso.datetime() }).openapi({\n description: 'HealthCheck Schema',\n examples: [{ status: 'ok', timestamp: new Date().toISOString() }],\n }),\n description: 'Health check status',\n }),\n },\n STATS: {\n method: HTTP.Methods.GET,\n path: HealthCheckRestPaths.STATS,\n request: {\n headers: z.object({\n [HealthCheckHeaders.SECRET_KEY]: z.string().optional().openapi({\n description: 'The stats key',\n }),\n }),\n },\n responses: jsonResponse({\n schema: z\n .object({\n status: z.string(),\n timestamp: z.iso.datetime(),\n build: z.object({\n service: z.string(),\n version: z.string(),\n commit: z.string(),\n branch: z.string(),\n builtAt: z.string(),\n }),\n process: z.object({\n pid: z.number(),\n uptime: z.number(),\n uptimeHuman: z.string(),\n runtime: z.string(),\n environment: z.string(),\n }),\n memory: z.object({ rss: z.string(), heapUsed: z.string(), heapTotal: z.string() }),\n })\n .openapi({ description: 'HealthCheck Stats Schema' }),\n description:\n 'Build stamp, process and memory - closed outside the development environments unless enabled',\n }),\n },\n PING: {\n method: HTTP.Methods.POST,\n path: HealthCheckRestPaths.PING,\n request: {\n body: jsonContent({\n description: 'PING | Request body',\n schema: z.object({\n type: z.string().optional().default('PING'),\n message: z.string().min(1).max(255),\n }),\n }),\n },\n responses: jsonResponse({\n schema: z\n .object({\n type: z.string().optional().default('PONG'),\n date: z.iso.datetime(),\n message: z.string(),\n })\n .openapi({\n description: 'HealthCheck PingPong Schema',\n examples: [{ date: new Date().toISOString(), message: 'ok' }],\n }),\n description: 'HealthCheck PingPong Message',\n }),\n },\n} as const;\n\nexport class HealthCheckController extends BaseRestController {\n /**\n * Both dependencies arrive through the container, so two applications in one process each get\n * their own gate - a static field would let the last one to boot decide for every other.\n */\n constructor(\n @inject({ key: HealthCheckBindingKeys.HEALTH_CHECK_OPTIONS, isOptional: true })\n private readonly healthOptions: IHealthCheckOptions = {},\n @inject({ key: HealthCheckBindingKeys.APPLICATION_INFO, isOptional: true })\n private readonly appInfo?: IApplicationInfo,\n ) {\n super({ scope: HealthCheckController.name });\n\n // Note: This is optional declare internal controller route definitions\n this.definitions = RouteConfigs;\n }\n\n override binding(): ValueOrPromise<void> {\n // Public liveness probe: status and clock only. Nothing here names a runtime or a version.\n this.bindRoute({ configs: RouteConfigs.ROOT }).to({\n handler: (context) => {\n return context.json(HealthCheckReporter.buildSummary(), HTTP.ResultCodes.RS_2.Ok);\n },\n });\n\n if (!HealthCheckReporter.isStatsEnabled({ options: this.healthOptions })) {\n this.logger\n .for(this.binding.name)\n .debug('Stats route disabled | path: %s', HealthCheckRestPaths.STATS);\n return;\n }\n\n this.bindRoute({ configs: RouteConfigs.STATS }).to({\n handler: (context) => {\n // `context.notFound()`, not a thrown 404: it runs the application's own notFound handler,\n // so the refusal is byte-identical to the answer for a route that was never mounted. A\n // thrown `ApplicationError` serializes a different body and would confirm the route exists.\n if (\n !HealthCheckReporter.isStatsAuthorized({\n options: this.healthOptions,\n header: context.req.header(HealthCheckHeaders.SECRET_KEY),\n })\n ) {\n return context.notFound();\n }\n\n return context.json(\n HealthCheckReporter.buildStats({ options: this.healthOptions, appInfo: this.appInfo }),\n HTTP.ResultCodes.RS_2.Ok,\n );\n },\n });\n }\n\n // Method 3: Using 'decorators' to create a controller route, with an explicit type assertion for the validated request data\n @api({ configs: RouteConfigs.PING })\n pingPong(context: TRouteContext) {\n const { message } = context.req.valid<{ type?: string; message: string }>('json');\n\n // Return type is automatically validated against the response schema\n return context.json(\n { type: 'PONG', date: new Date().toISOString(), message },\n HTTP.ResultCodes.RS_2.Ok,\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../../src/components/health-check/controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseRestController, type TRouteContext } from '@/base/controllers';\nimport { api, inject } from '@/base/metadata';\nimport { OpenApiResponses } from '@venizia/ignis-kernel';\nimport type { IApplicationInfo } from '@venizia/ignis-kernel';\nimport { z } from '@hono/zod-openapi';\nimport { HTTP, type ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport {\n HealthCheckBindingKeys,\n HealthCheckHeaders,\n HealthCheckRestPaths,\n type IHealthCheckOptions,\n} from './common';\nimport { HealthCheckReporter } from './reporter';\n\nconst RouteConfigs = {\n ROOT: {\n method: HTTP.Methods.GET,\n path: HealthCheckRestPaths.ROOT,\n responses: OpenApiResponses.jsonResponse({\n schema: z.object({ status: z.string(), timestamp: z.iso.datetime() }).openapi({\n description: 'HealthCheck Schema',\n examples: [{ status: 'ok', timestamp: new Date().toISOString() }],\n }),\n description: 'Health check status',\n }),\n },\n STATS: {\n method: HTTP.Methods.GET,\n path: HealthCheckRestPaths.STATS,\n request: {\n headers: z.object({\n [HealthCheckHeaders.SECRET_KEY]: z.string().optional().openapi({\n description: 'The stats key',\n }),\n }),\n },\n responses: OpenApiResponses.jsonResponse({\n schema: z\n .object({\n status: z.string(),\n timestamp: z.iso.datetime(),\n build: z.object({\n service: z.string(),\n version: z.string(),\n commit: z.string(),\n branch: z.string(),\n builtAt: z.string(),\n }),\n process: z.object({\n pid: z.number(),\n uptime: z.number(),\n uptimeHuman: z.string(),\n runtime: z.string(),\n environment: z.string(),\n }),\n memory: z.object({ rss: z.string(), heapUsed: z.string(), heapTotal: z.string() }),\n })\n .openapi({ description: 'HealthCheck Stats Schema' }),\n description:\n 'Build stamp, process and memory - closed outside the development environments unless enabled',\n }),\n },\n PING: {\n method: HTTP.Methods.POST,\n path: HealthCheckRestPaths.PING,\n request: {\n body: OpenApiResponses.jsonContent({\n description: 'PING | Request body',\n schema: z.object({\n type: z.string().optional().default('PING'),\n message: z.string().min(1).max(255),\n }),\n }),\n },\n responses: OpenApiResponses.jsonResponse({\n schema: z\n .object({\n type: z.string().optional().default('PONG'),\n date: z.iso.datetime(),\n message: z.string(),\n })\n .openapi({\n description: 'HealthCheck PingPong Schema',\n examples: [{ date: new Date().toISOString(), message: 'ok' }],\n }),\n description: 'HealthCheck PingPong Message',\n }),\n },\n} as const;\n\nexport class HealthCheckController extends BaseRestController {\n /**\n * Both dependencies arrive through the container, so two applications in one process each get\n * their own gate - a static field would let the last one to boot decide for every other.\n */\n constructor(\n @inject({ key: HealthCheckBindingKeys.HEALTH_CHECK_OPTIONS, isOptional: true })\n private readonly healthOptions: IHealthCheckOptions = {},\n @inject({ key: HealthCheckBindingKeys.APPLICATION_INFO, isOptional: true })\n private readonly appInfo?: IApplicationInfo,\n ) {\n super({ scope: HealthCheckController.name });\n\n // Note: This is optional declare internal controller route definitions\n this.definitions = RouteConfigs;\n }\n\n override binding(): ValueOrPromise<void> {\n // Public liveness probe: status and clock only. Nothing here names a runtime or a version.\n this.bindRoute({ configs: RouteConfigs.ROOT }).to({\n handler: (context) => {\n return context.json(HealthCheckReporter.buildSummary(), HTTP.ResultCodes.RS_2.Ok);\n },\n });\n\n if (!HealthCheckReporter.isStatsEnabled({ options: this.healthOptions })) {\n this.logger\n .for(this.binding.name)\n .debug('Stats route disabled | path: %s', HealthCheckRestPaths.STATS);\n return;\n }\n\n this.bindRoute({ configs: RouteConfigs.STATS }).to({\n handler: (context) => {\n // `context.notFound()`, not a thrown 404: it runs the application's own notFound handler,\n // so the refusal is byte-identical to the answer for a route that was never mounted. A\n // thrown `ApplicationError` serializes a different body and would confirm the route exists.\n if (\n !HealthCheckReporter.isStatsAuthorized({\n options: this.healthOptions,\n header: context.req.header(HealthCheckHeaders.SECRET_KEY),\n })\n ) {\n return context.notFound();\n }\n\n return context.json(\n HealthCheckReporter.buildStats({ options: this.healthOptions, appInfo: this.appInfo }),\n HTTP.ResultCodes.RS_2.Ok,\n );\n },\n });\n }\n\n // Method 3: Using 'decorators' to create a controller route, with an explicit type assertion for the validated request data\n @api({ configs: RouteConfigs.PING })\n pingPong(context: TRouteContext) {\n const { message } = context.req.valid<{ type?: string; message: string }>('json');\n\n // Return type is automatically validated against the response schema\n return context.json(\n { type: 'PONG', date: new Date().toISOString(), message },\n HTTP.ResultCodes.RS_2.Ok,\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAEhC,wGAAwG","sourcesContent":["export * from './auth';\nexport * from './health-check';\nexport * from './request-tracker';\nexport * from './api-reference';\n\n// Excluded from the barrel - import directly from the subpath: mail, socket-io, static-asset, websocket\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bull-mq-executor.helper.d.ts","sourceRoot":"","sources":["../../../../../../src/components/mail/helpers/executors/bull-mq-executor.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAY,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,KAAK,EACV,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAEjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,mBAAmB,EAIpB,MAAM,cAAc,CAAC;AAGtB,qBAAa,wBAAyB,SAAQ,UAAW,YAAW,kBAAkB;IACpF,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,IAAI,CAA0C;IAEtD,OAAO,CAAC,WAAW,CAAC,CAAmD;IACvE,OAAO,CAAC,aAAa,CAA8D;IACnF,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAA0B;IACxD,OAAO,CAAC,YAAY,CAAK;IAEzB,OAAO,CAAC,SAAS,CAAC,CAAmD;gBAEzD,IAAI,EAAE,uBAAuB;IAiBzC,SAAS,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAmC/C,YAAY,CAChB,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,CAAC,EAC3D,IAAI,CAAC,EAAE;QACL,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,GACA,OAAO,CAAC,IAAI,CAAC;IAkChB,SAAS,CAAC,IAAI,EAAE;QAAE,gBAAgB,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAsG1F,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBnD,6JAA6J;YAC/I,YAAY;IA2BpB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAOnC,sLAAsL;IAChL,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"bull-mq-executor.helper.d.ts","sourceRoot":"","sources":["../../../../../../src/components/mail/helpers/executors/bull-mq-executor.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAY,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,KAAK,EACV,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAEjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,mBAAmB,EAIpB,MAAM,cAAc,CAAC;AAGtB,qBAAa,wBAAyB,SAAQ,UAAW,YAAW,kBAAkB;IACpF,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,IAAI,CAA0C;IAEtD,OAAO,CAAC,WAAW,CAAC,CAAmD;IACvE,OAAO,CAAC,aAAa,CAA8D;IACnF,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAA0B;IACxD,OAAO,CAAC,YAAY,CAAK;IAEzB,OAAO,CAAC,SAAS,CAAC,CAAmD;gBAEzD,IAAI,EAAE,uBAAuB;IAiBzC,SAAS,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAmC/C,YAAY,CAChB,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,CAAC,EAC3D,IAAI,CAAC,EAAE;QACL,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,GACA,OAAO,CAAC,IAAI,CAAC;IAkChB,SAAS,CAAC,IAAI,EAAE;QAAE,gBAAgB,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAsG1F,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBnD,6JAA6J;YAC/I,YAAY;IA2BpB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAOnC,sLAAsL;IAChL,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmC5B,cAAc,IAAI,MAAM;IAIxB,OAAO,IAAI,WAAW,CAAC,OAAO,mBAAmB,CAAC;IAI5C,wBAAwB,CAC5B,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,gBAAgB,CAAC;CAqD7B"}
|
|
@@ -163,7 +163,8 @@ export class BullMQMailExecutorHelper extends BaseHelper {
|
|
|
163
163
|
}
|
|
164
164
|
/** Full teardown: workers -> queue -> Redis. Every step runs even if an earlier one failed (skipping leaks a queue client + Redis socket); failures are reported once, at the end. */
|
|
165
165
|
async close() {
|
|
166
|
-
const
|
|
166
|
+
const result = await this.closeWorkers();
|
|
167
|
+
const failures = [...result];
|
|
167
168
|
if (this.queueHelper) {
|
|
168
169
|
try {
|
|
169
170
|
await this.queueHelper.queue.close();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bull-mq-executor.helper.js","sourceRoot":"","sources":["../../../../../../src/components/mail/helpers/executors/bull-mq-executor.helper.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport { RedisSingleHelper } from '@venizia/ignis-helpers';\nimport type { TConstValue } from '@/helpers';\nimport { BullMQHelper } from '@venizia/ignis-helpers/bullmq';\nimport type {\n IBullMQMailExecutorOpts,\n IMailProcessorResult,\n IMailQueueExecutor,\n IMailQueueOptions,\n IMailQueueResult,\n IQueueJobPayload,\n} from '../../common';\nimport {\n BullMQExecutorModes,\n MailBackoffTypes,\n MailErrorCodes,\n MailExecutorErrors,\n} from '../../common';\nimport type { Job } from 'bullmq';\n\nexport class BullMQMailExecutorHelper extends BaseHelper implements IMailQueueExecutor {\n private queueIdentifier: string;\n private queueName: string;\n private mode: TConstValue<typeof BullMQExecutorModes>;\n\n private queueHelper?: BullMQHelper<IQueueJobPayload, IMailQueueResult>;\n private workerHelpers: BullMQHelper<IQueueJobPayload, IMailProcessorResult>[] = [];\n private redisConnection: RedisSingleHelper;\n private readonly bullmqModule?: typeof import('bullmq');\n private jobIdCounter = 0;\n\n private processor?: (email: string) => Promise<IMailProcessorResult>;\n\n constructor(opts: IBullMQMailExecutorOpts) {\n super({ scope: BullMQMailExecutorHelper.name });\n\n this.mode = opts.mode;\n\n this.redisConnection = new RedisSingleHelper({\n ...opts.redis,\n maxRetry: undefined,\n });\n\n this.bullmqModule = opts.module;\n this.queueIdentifier = opts.queue.identifier;\n this.queueName = opts.queue.name;\n\n this.initQueue(opts.queue);\n }\n\n initQueue(queue: { identifier: string; name: string }) {\n switch (this.mode) {\n case BullMQExecutorModes.QUEUE_ONLY:\n case BullMQExecutorModes.BOTH: {\n this.queueHelper = new BullMQHelper<IQueueJobPayload, IMailQueueResult>({\n identifier: queue.identifier,\n queueName: queue.name,\n redisConnection: this.redisConnection,\n role: 'queue',\n module: this.bullmqModule,\n });\n\n this.logger\n .for(this.constructor.name)\n .info(\n 'BullMQ queue executor initialized (queue enabled) | Identifier: %s | Mode: %s',\n this.queueIdentifier,\n this.mode,\n );\n break;\n }\n default: {\n this.logger\n .for(this.constructor.name)\n .info(\n 'BullMQ queue executor initialized (worker-only mode) | Identifier: %s | Mode: %s',\n this.queueIdentifier,\n this.mode,\n );\n\n break;\n }\n }\n }\n\n async setProcessor(\n processor: (email: string) => Promise<IMailProcessorResult>,\n opts?: {\n numberOfWorkers?: number;\n concurrencyPerWorker?: number;\n lockDuration?: number;\n },\n ): Promise<void> {\n this.processor = processor;\n\n if (this.mode === BullMQExecutorModes.QUEUE_ONLY) {\n this.logger\n .for(this.setProcessor.name)\n .warn('Skipping worker creation in queue-only mode. Workers will not be started.');\n return;\n }\n\n const numberOfWorkers = opts?.numberOfWorkers ?? 1;\n const concurrencyPerWorker = opts?.concurrencyPerWorker ?? 5;\n const lockDuration = opts?.lockDuration ?? 30000;\n\n await this.clearWorkers();\n\n for (let i = 0; i < numberOfWorkers; i++) {\n this.addWorker({\n workerIdentifier: `${this.queueIdentifier}-worker-${i}`,\n concurrency: concurrencyPerWorker,\n lockDuration,\n });\n }\n\n this.logger\n .for(this.setProcessor.name)\n .info(\n 'Processor registered | Mode: %s | Workers: %d | Concurrency per worker: %d',\n this.mode,\n numberOfWorkers,\n concurrencyPerWorker,\n );\n }\n\n addWorker(opts: { workerIdentifier: string; concurrency?: number; lockDuration?: number }): void {\n if (!this.processor) {\n throw getError({ message: MailExecutorErrors.PROCESSOR_NOT_SET });\n }\n\n const workerIdentifier = opts.workerIdentifier;\n const concurrency = opts?.concurrency ?? 5;\n const lockDuration = opts?.lockDuration ?? 30000;\n\n const workerHelper = new BullMQHelper<IQueueJobPayload, IMailProcessorResult>({\n identifier: workerIdentifier,\n queueName: this.queueName,\n redisConnection: this.redisConnection,\n role: 'worker',\n module: this.bullmqModule,\n numberOfWorker: concurrency,\n lockDuration,\n onWorkerData: async (job: Job<IQueueJobPayload, IMailProcessorResult>) => {\n const maxAttempts = job.data.options?.attempts ?? 3;\n\n this.logger\n .for('onWorkerData')\n .info(\n 'Processing job | Worker: %s | jobId: %s | email: %s | attempt: %d/%d',\n workerIdentifier,\n job.data.id,\n job.data.email,\n job.attemptsMade + 1,\n maxAttempts,\n );\n\n if (!this.processor) {\n // Returning undefined would let BullMQ mark the job COMPLETED and (with removeOnComplete) delete it - mail silently dropped.\n throw getError({\n messageCode: MailErrorCodes.SEND_FAILED,\n message: `[onWorkerData] ${MailExecutorErrors.PROCESSOR_NOT_SET} | jobId: ${job.data.id}`,\n });\n }\n\n const result = await this.processor(job.data.email);\n\n // A processor reports SMTP rejection by RETURNING `{ success: false }`; BullMQ only treats a REJECTION as failure, so resolving completes the job - no retry, no DLQ.\n if (result?.success === false) {\n throw getError({\n messageCode: MailErrorCodes.SEND_FAILED,\n message: `[onWorkerData] Processor reported failure | jobId: ${job.data.id} | reason: ${result.message}`,\n });\n }\n\n return result;\n },\n onWorkerDataCompleted: async (job: Job<IQueueJobPayload, IMailProcessorResult>) => {\n this.logger\n .for('onWorkerDataCompleted')\n .info(\n 'Job completed | Worker: %s | jobId: %s | email: %s',\n workerIdentifier,\n job.data.id,\n job.data.email,\n );\n },\n onWorkerDataFail: async (\n job: Job<IQueueJobPayload, IMailProcessorResult> | undefined,\n error: Error,\n ) => {\n if (job) {\n const maxAttempts = job.data.options?.attempts ?? 3;\n this.logger\n .for('onWorkerDataFail')\n .error(\n 'Job failed | Worker: %s | jobId: %s | email: %s | attempt: %d/%d | error: %s',\n workerIdentifier,\n job.data.id,\n job.data.email,\n job.attemptsMade,\n maxAttempts,\n error.message,\n );\n } else {\n this.logger\n .for('onWorkerDataFail')\n .error(\n 'Worker error (no job) | Worker: %s | error: %s',\n workerIdentifier,\n error.message,\n );\n }\n },\n });\n\n this.workerHelpers.push(workerHelper);\n\n this.logger\n .for(this.addWorker.name)\n .info(\n 'Worker added | Identifier: %s | Concurrency: %d | Total workers: %d',\n workerIdentifier,\n concurrency,\n this.workerHelpers.length,\n );\n }\n\n async removeWorker(index: number): Promise<boolean> {\n if (index < 0 || index >= this.workerHelpers.length) {\n this.logger.for(this.removeWorker.name).warn('Invalid worker index: %d', index);\n return false;\n }\n\n // Dropped from the list BEFORE the close is awaited: a rejecting close must not leave a half-closed worker still counted and still handed jobs.\n const [workerHelper] = this.workerHelpers.splice(index, 1);\n await workerHelper.worker.close();\n\n this.logger\n .for(this.removeWorker.name)\n .info('Worker removed | Index: %d | Remaining workers: %d', index, this.workerHelpers.length);\n\n return true;\n }\n\n /** Closes every worker without stopping at the first failure, always empties the list, and returns failures instead of throwing so teardown can continue. */\n private async closeWorkers(): Promise<Error[]> {\n const workerHelpers = this.workerHelpers;\n this.workerHelpers = [];\n\n const results = await Promise.allSettled(\n workerHelpers.map((workerHelper) => workerHelper.worker.close()),\n );\n\n const failures: Error[] = [];\n\n for (const result of results) {\n if (result.status !== 'rejected') {\n continue;\n }\n\n const error =\n result.reason instanceof Error\n ? result.reason\n : getError({ message: `Worker close failed | reason: ${String(result.reason)}` });\n\n failures.push(error);\n this.logger.for('closeWorkers').error('Failed to close worker | error: %s', error.message);\n }\n\n return failures;\n }\n\n async clearWorkers(): Promise<void> {\n const count = this.workerHelpers.length;\n await this.closeWorkers();\n\n this.logger.for(this.clearWorkers.name).info('All workers cleared | Count: %d', count);\n }\n\n /** Full teardown: workers -> queue -> Redis. Every step runs even if an earlier one failed (skipping leaks a queue client + Redis socket); failures are reported once, at the end. */\n async close(): Promise<void> {\n const failures: Error[] = [...(await this.closeWorkers())];\n\n if (this.queueHelper) {\n try {\n await this.queueHelper.queue.close();\n } catch (error) {\n const closeError = error instanceof Error ? error : getError({ message: String(error) });\n failures.push(closeError);\n this.logger.for(this.close.name).error('Failed to close queue | error: %s', closeError);\n }\n }\n\n try {\n await this.redisConnection.disconnect();\n } catch (error) {\n const disconnectError = error instanceof Error ? error : getError({ message: String(error) });\n failures.push(disconnectError);\n this.logger\n .for(this.close.name)\n .error('Failed to disconnect redis | error: %s', disconnectError);\n }\n\n if (failures.length > 0) {\n throw getError({\n message: `[close] Incomplete BullMQ mail executor teardown | failures: ${failures\n .map((failure) => failure.message)\n .join(' | ')}`,\n });\n }\n\n this.logger.for(this.close.name).info('BullMQ mail executor closed | Mode: %s', this.mode);\n }\n\n getWorkerCount(): number {\n return this.workerHelpers.length;\n }\n\n getMode(): TConstValue<typeof BullMQExecutorModes> {\n return this.mode;\n }\n\n async enqueueVerificationEmail(\n email: string,\n options?: IMailQueueOptions,\n ): Promise<IMailQueueResult> {\n if (this.mode === BullMQExecutorModes.WORKER_ONLY) {\n throw getError({\n message: 'Cannot enqueue jobs in worker-only mode. Set mode to \"queue-only\" or \"both\".',\n });\n }\n\n if (!this.queueHelper) {\n throw getError({\n message: 'Queue helper not initialized. This should not happen in queue-enabled mode.',\n });\n }\n\n if (!this.processor && this.mode !== BullMQExecutorModes.QUEUE_ONLY) {\n throw getError({ message: MailExecutorErrors.PROCESSOR_NOT_SET });\n }\n\n const jobId = `job_${++this.jobIdCounter}_${Date.now()}`;\n const job: IQueueJobPayload = {\n id: jobId,\n email,\n options,\n attempts: 0,\n scheduledAt: Date.now() + (options?.delay ?? 0),\n };\n\n this.logger\n .for(this.enqueueVerificationEmail.name)\n .info(\n 'Queuing email to BullMQ/Redis | jobId: %s | email: %s | mode: %s',\n jobId,\n email,\n this.mode,\n );\n\n const bullJob = await this.queueHelper.queue.add('send-verification-email', job, {\n priority: options?.priority,\n delay: options?.delay,\n attempts: options?.attempts ?? 3,\n backoff: {\n type: options?.backoff?.type ?? MailBackoffTypes.EXPONENTIAL,\n delay: options?.backoff?.delay ?? 1000,\n },\n removeOnComplete: true,\n removeOnFail: false,\n });\n\n return {\n jobId: bullJob.id ?? jobId,\n queued: true,\n message: 'Email queued successfully (BullMQ/Redis)',\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"bull-mq-executor.helper.js","sourceRoot":"","sources":["../../../../../../src/components/mail/helpers/executors/bull-mq-executor.helper.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport { RedisSingleHelper } from '@venizia/ignis-helpers';\nimport type { TConstValue } from '@/helpers';\nimport { BullMQHelper } from '@venizia/ignis-helpers/bullmq';\nimport type {\n IBullMQMailExecutorOpts,\n IMailProcessorResult,\n IMailQueueExecutor,\n IMailQueueOptions,\n IMailQueueResult,\n IQueueJobPayload,\n} from '../../common';\nimport {\n BullMQExecutorModes,\n MailBackoffTypes,\n MailErrorCodes,\n MailExecutorErrors,\n} from '../../common';\nimport type { Job } from 'bullmq';\n\nexport class BullMQMailExecutorHelper extends BaseHelper implements IMailQueueExecutor {\n private queueIdentifier: string;\n private queueName: string;\n private mode: TConstValue<typeof BullMQExecutorModes>;\n\n private queueHelper?: BullMQHelper<IQueueJobPayload, IMailQueueResult>;\n private workerHelpers: BullMQHelper<IQueueJobPayload, IMailProcessorResult>[] = [];\n private redisConnection: RedisSingleHelper;\n private readonly bullmqModule?: typeof import('bullmq');\n private jobIdCounter = 0;\n\n private processor?: (email: string) => Promise<IMailProcessorResult>;\n\n constructor(opts: IBullMQMailExecutorOpts) {\n super({ scope: BullMQMailExecutorHelper.name });\n\n this.mode = opts.mode;\n\n this.redisConnection = new RedisSingleHelper({\n ...opts.redis,\n maxRetry: undefined,\n });\n\n this.bullmqModule = opts.module;\n this.queueIdentifier = opts.queue.identifier;\n this.queueName = opts.queue.name;\n\n this.initQueue(opts.queue);\n }\n\n initQueue(queue: { identifier: string; name: string }) {\n switch (this.mode) {\n case BullMQExecutorModes.QUEUE_ONLY:\n case BullMQExecutorModes.BOTH: {\n this.queueHelper = new BullMQHelper<IQueueJobPayload, IMailQueueResult>({\n identifier: queue.identifier,\n queueName: queue.name,\n redisConnection: this.redisConnection,\n role: 'queue',\n module: this.bullmqModule,\n });\n\n this.logger\n .for(this.constructor.name)\n .info(\n 'BullMQ queue executor initialized (queue enabled) | Identifier: %s | Mode: %s',\n this.queueIdentifier,\n this.mode,\n );\n break;\n }\n default: {\n this.logger\n .for(this.constructor.name)\n .info(\n 'BullMQ queue executor initialized (worker-only mode) | Identifier: %s | Mode: %s',\n this.queueIdentifier,\n this.mode,\n );\n\n break;\n }\n }\n }\n\n async setProcessor(\n processor: (email: string) => Promise<IMailProcessorResult>,\n opts?: {\n numberOfWorkers?: number;\n concurrencyPerWorker?: number;\n lockDuration?: number;\n },\n ): Promise<void> {\n this.processor = processor;\n\n if (this.mode === BullMQExecutorModes.QUEUE_ONLY) {\n this.logger\n .for(this.setProcessor.name)\n .warn('Skipping worker creation in queue-only mode. Workers will not be started.');\n return;\n }\n\n const numberOfWorkers = opts?.numberOfWorkers ?? 1;\n const concurrencyPerWorker = opts?.concurrencyPerWorker ?? 5;\n const lockDuration = opts?.lockDuration ?? 30000;\n\n await this.clearWorkers();\n\n for (let i = 0; i < numberOfWorkers; i++) {\n this.addWorker({\n workerIdentifier: `${this.queueIdentifier}-worker-${i}`,\n concurrency: concurrencyPerWorker,\n lockDuration,\n });\n }\n\n this.logger\n .for(this.setProcessor.name)\n .info(\n 'Processor registered | Mode: %s | Workers: %d | Concurrency per worker: %d',\n this.mode,\n numberOfWorkers,\n concurrencyPerWorker,\n );\n }\n\n addWorker(opts: { workerIdentifier: string; concurrency?: number; lockDuration?: number }): void {\n if (!this.processor) {\n throw getError({ message: MailExecutorErrors.PROCESSOR_NOT_SET });\n }\n\n const workerIdentifier = opts.workerIdentifier;\n const concurrency = opts?.concurrency ?? 5;\n const lockDuration = opts?.lockDuration ?? 30000;\n\n const workerHelper = new BullMQHelper<IQueueJobPayload, IMailProcessorResult>({\n identifier: workerIdentifier,\n queueName: this.queueName,\n redisConnection: this.redisConnection,\n role: 'worker',\n module: this.bullmqModule,\n numberOfWorker: concurrency,\n lockDuration,\n onWorkerData: async (job: Job<IQueueJobPayload, IMailProcessorResult>) => {\n const maxAttempts = job.data.options?.attempts ?? 3;\n\n this.logger\n .for('onWorkerData')\n .info(\n 'Processing job | Worker: %s | jobId: %s | email: %s | attempt: %d/%d',\n workerIdentifier,\n job.data.id,\n job.data.email,\n job.attemptsMade + 1,\n maxAttempts,\n );\n\n if (!this.processor) {\n // Returning undefined would let BullMQ mark the job COMPLETED and (with removeOnComplete) delete it - mail silently dropped.\n throw getError({\n messageCode: MailErrorCodes.SEND_FAILED,\n message: `[onWorkerData] ${MailExecutorErrors.PROCESSOR_NOT_SET} | jobId: ${job.data.id}`,\n });\n }\n\n const result = await this.processor(job.data.email);\n\n // A processor reports SMTP rejection by RETURNING `{ success: false }`; BullMQ only treats a REJECTION as failure, so resolving completes the job - no retry, no DLQ.\n if (result?.success === false) {\n throw getError({\n messageCode: MailErrorCodes.SEND_FAILED,\n message: `[onWorkerData] Processor reported failure | jobId: ${job.data.id} | reason: ${result.message}`,\n });\n }\n\n return result;\n },\n onWorkerDataCompleted: async (job: Job<IQueueJobPayload, IMailProcessorResult>) => {\n this.logger\n .for('onWorkerDataCompleted')\n .info(\n 'Job completed | Worker: %s | jobId: %s | email: %s',\n workerIdentifier,\n job.data.id,\n job.data.email,\n );\n },\n onWorkerDataFail: async (\n job: Job<IQueueJobPayload, IMailProcessorResult> | undefined,\n error: Error,\n ) => {\n if (job) {\n const maxAttempts = job.data.options?.attempts ?? 3;\n this.logger\n .for('onWorkerDataFail')\n .error(\n 'Job failed | Worker: %s | jobId: %s | email: %s | attempt: %d/%d | error: %s',\n workerIdentifier,\n job.data.id,\n job.data.email,\n job.attemptsMade,\n maxAttempts,\n error.message,\n );\n } else {\n this.logger\n .for('onWorkerDataFail')\n .error(\n 'Worker error (no job) | Worker: %s | error: %s',\n workerIdentifier,\n error.message,\n );\n }\n },\n });\n\n this.workerHelpers.push(workerHelper);\n\n this.logger\n .for(this.addWorker.name)\n .info(\n 'Worker added | Identifier: %s | Concurrency: %d | Total workers: %d',\n workerIdentifier,\n concurrency,\n this.workerHelpers.length,\n );\n }\n\n async removeWorker(index: number): Promise<boolean> {\n if (index < 0 || index >= this.workerHelpers.length) {\n this.logger.for(this.removeWorker.name).warn('Invalid worker index: %d', index);\n return false;\n }\n\n // Dropped from the list BEFORE the close is awaited: a rejecting close must not leave a half-closed worker still counted and still handed jobs.\n const [workerHelper] = this.workerHelpers.splice(index, 1);\n await workerHelper.worker.close();\n\n this.logger\n .for(this.removeWorker.name)\n .info('Worker removed | Index: %d | Remaining workers: %d', index, this.workerHelpers.length);\n\n return true;\n }\n\n /** Closes every worker without stopping at the first failure, always empties the list, and returns failures instead of throwing so teardown can continue. */\n private async closeWorkers(): Promise<Error[]> {\n const workerHelpers = this.workerHelpers;\n this.workerHelpers = [];\n\n const results = await Promise.allSettled(\n workerHelpers.map((workerHelper) => workerHelper.worker.close()),\n );\n\n const failures: Error[] = [];\n\n for (const result of results) {\n if (result.status !== 'rejected') {\n continue;\n }\n\n const error =\n result.reason instanceof Error\n ? result.reason\n : getError({ message: `Worker close failed | reason: ${String(result.reason)}` });\n\n failures.push(error);\n this.logger.for('closeWorkers').error('Failed to close worker | error: %s', error.message);\n }\n\n return failures;\n }\n\n async clearWorkers(): Promise<void> {\n const count = this.workerHelpers.length;\n await this.closeWorkers();\n\n this.logger.for(this.clearWorkers.name).info('All workers cleared | Count: %d', count);\n }\n\n /** Full teardown: workers -> queue -> Redis. Every step runs even if an earlier one failed (skipping leaks a queue client + Redis socket); failures are reported once, at the end. */\n async close(): Promise<void> {\n const result = await this.closeWorkers();\n const failures: Error[] = [...result];\n\n if (this.queueHelper) {\n try {\n await this.queueHelper.queue.close();\n } catch (error) {\n const closeError = error instanceof Error ? error : getError({ message: String(error) });\n failures.push(closeError);\n this.logger.for(this.close.name).error('Failed to close queue | error: %s', closeError);\n }\n }\n\n try {\n await this.redisConnection.disconnect();\n } catch (error) {\n const disconnectError = error instanceof Error ? error : getError({ message: String(error) });\n failures.push(disconnectError);\n this.logger\n .for(this.close.name)\n .error('Failed to disconnect redis | error: %s', disconnectError);\n }\n\n if (failures.length > 0) {\n throw getError({\n message: `[close] Incomplete BullMQ mail executor teardown | failures: ${failures\n .map((failure) => failure.message)\n .join(' | ')}`,\n });\n }\n\n this.logger.for(this.close.name).info('BullMQ mail executor closed | Mode: %s', this.mode);\n }\n\n getWorkerCount(): number {\n return this.workerHelpers.length;\n }\n\n getMode(): TConstValue<typeof BullMQExecutorModes> {\n return this.mode;\n }\n\n async enqueueVerificationEmail(\n email: string,\n options?: IMailQueueOptions,\n ): Promise<IMailQueueResult> {\n if (this.mode === BullMQExecutorModes.WORKER_ONLY) {\n throw getError({\n message: 'Cannot enqueue jobs in worker-only mode. Set mode to \"queue-only\" or \"both\".',\n });\n }\n\n if (!this.queueHelper) {\n throw getError({\n message: 'Queue helper not initialized. This should not happen in queue-enabled mode.',\n });\n }\n\n if (!this.processor && this.mode !== BullMQExecutorModes.QUEUE_ONLY) {\n throw getError({ message: MailExecutorErrors.PROCESSOR_NOT_SET });\n }\n\n const jobId = `job_${++this.jobIdCounter}_${Date.now()}`;\n const job: IQueueJobPayload = {\n id: jobId,\n email,\n options,\n attempts: 0,\n scheduledAt: Date.now() + (options?.delay ?? 0),\n };\n\n this.logger\n .for(this.enqueueVerificationEmail.name)\n .info(\n 'Queuing email to BullMQ/Redis | jobId: %s | email: %s | mode: %s',\n jobId,\n email,\n this.mode,\n );\n\n const bullJob = await this.queueHelper.queue.add('send-verification-email', job, {\n priority: options?.priority,\n delay: options?.delay,\n attempts: options?.attempts ?? 3,\n backoff: {\n type: options?.backoff?.type ?? MailBackoffTypes.EXPONENTIAL,\n delay: options?.backoff?.delay ?? 1000,\n },\n removeOnComplete: true,\n removeOnFail: false,\n });\n\n return {\n jobId: bullJob.id ?? jobId,\n queued: true,\n message: 'Email queued successfully (BullMQ/Redis)',\n };\n }\n}\n"]}
|
package/dist/esm/components/mail/helpers/transporters/amazon-ses-transporter.helper.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"amazon-ses-transporter.helper.d.ts","sourceRoot":"","sources":["../../../../../../src/components/mail/helpers/transporters/amazon-ses-transporter.helper.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAY,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AAItB,qBAAa,wBAAyB,SAAQ,UAAW,YAAW,cAAc;IAChF,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,2BAA2B,CAAU;IAC7C,OAAO,CAAC,4BAA4B,CAAU;IAC9C,OAAO,CAAC,MAAM,CAAC,CAAqC;gBAExC,IAAI,EAAE;QAAE,MAAM,EAAE,gBAAgB,CAAC;QAAC,MAAM,CAAC,EAAE,gBAAgB,CAAA;KAAE;IAQnE,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"amazon-ses-transporter.helper.d.ts","sourceRoot":"","sources":["../../../../../../src/components/mail/helpers/transporters/amazon-ses-transporter.helper.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAY,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AAItB,qBAAa,wBAAyB,SAAQ,UAAW,YAAW,cAAc;IAChF,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,2BAA2B,CAAU;IAC7C,OAAO,CAAC,4BAA4B,CAAU;IAC9C,OAAO,CAAC,MAAM,CAAC,CAAqC;gBAExC,IAAI,EAAE;QAAE,MAAM,EAAE,gBAAgB,CAAC;QAAC,MAAM,CAAC,EAAE,gBAAgB,CAAA;KAAE;IAQnE,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;IAsDrD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAwB1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAWzC,SAAS,CAAC,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB;IAkBjE,OAAO,CAAC,cAAc;CAWvB"}
|
|
@@ -2,8 +2,8 @@ import { HTTP } from '@venizia/ignis-helpers/common';
|
|
|
2
2
|
import { ModuleUtility } from '@venizia/ignis-helpers';
|
|
3
3
|
import { BaseHelper, getError } from '@venizia/ignis-helpers/core';
|
|
4
4
|
import { MailErrorCodes, } from '../../common/index.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { MailAddressUtility, MailMimeUtility } from '../../utilities/index.js';
|
|
6
|
+
import { MailAttachmentUtility } from '../../utilities/attachment.utility.js';
|
|
7
7
|
export class AmazonSesTransportHelper extends BaseHelper {
|
|
8
8
|
constructor(opts) {
|
|
9
9
|
super({ scope: AmazonSesTransportHelper.name });
|
|
@@ -15,19 +15,23 @@ export class AmazonSesTransportHelper extends BaseHelper {
|
|
|
15
15
|
const logger = this.logger.for(this.send.name);
|
|
16
16
|
try {
|
|
17
17
|
logger.debug('Sending email with Amazon SES to: %s', message.to);
|
|
18
|
-
const rawMessage = await
|
|
18
|
+
const rawMessage = await MailMimeUtility.buildRawMessage({ message });
|
|
19
19
|
const command = new this.sendEmailCommandConstructor({
|
|
20
20
|
// `FromEmailAddress` carries the same RFC 5321/5322 mailbox syntax as the raw `From:`
|
|
21
21
|
// header and is subject to the same 7-bit-ASCII requirement - encoding it separately
|
|
22
22
|
// here (instead of passing `message.from` through untouched) is what keeps a non-ASCII
|
|
23
23
|
// display name from reaching the SES API as raw UTF-8 bytes.
|
|
24
|
-
FromEmailAddress: message.from
|
|
24
|
+
FromEmailAddress: message.from
|
|
25
|
+
? MailMimeUtility.formatAddressHeader({ value: message.from })
|
|
26
|
+
: message.from,
|
|
25
27
|
Destination: {
|
|
26
|
-
ToAddresses:
|
|
27
|
-
CcAddresses: message.cc ?
|
|
28
|
-
BccAddresses: message.bcc
|
|
28
|
+
ToAddresses: MailAddressUtility.splitList({ value: message.to }),
|
|
29
|
+
CcAddresses: message.cc ? MailAddressUtility.splitList({ value: message.cc }) : undefined,
|
|
30
|
+
BccAddresses: message.bcc
|
|
31
|
+
? MailAddressUtility.splitList({ value: message.bcc })
|
|
32
|
+
: undefined,
|
|
29
33
|
},
|
|
30
|
-
// No `ReplyToAddresses` here: `
|
|
34
|
+
// No `ReplyToAddresses` here: `MailMimeUtility.buildRawMessage` already writes a single, RFC
|
|
31
35
|
// 2047-encoded `Reply-To` header into the raw content. Setting both sends the same
|
|
32
36
|
// address through two channels SES treats independently - a client can end up showing a
|
|
33
37
|
// reply-to derived from whichever one SES prioritizes, and the other becomes a silent,
|
|
@@ -45,7 +49,7 @@ export class AmazonSesTransportHelper extends BaseHelper {
|
|
|
45
49
|
}
|
|
46
50
|
catch (error) {
|
|
47
51
|
logger.error('Amazon SES send failed | error: %s', error instanceof Error ? error.message : error);
|
|
48
|
-
|
|
52
|
+
MailAttachmentUtility.release({ attachments: message.attachments });
|
|
49
53
|
return {
|
|
50
54
|
success: false,
|
|
51
55
|
error: error instanceof Error ? error.message : 'Unknown error',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"amazon-ses-transporter.helper.js","sourceRoot":"","sources":["../../../../../../src/components/mail/helpers/transporters/amazon-ses-transporter.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAC;AACrD,OAAO,EAAE,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EACL,cAAc,GAOf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"amazon-ses-transporter.helper.js","sourceRoot":"","sources":["../../../../../../src/components/mail/helpers/transporters/amazon-ses-transporter.helper.ts"],"names":[],"mappings":"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","sourcesContent":["import { HTTP } from '@venizia/ignis-helpers/common';\nimport { ModuleUtility, type AnyType } from '@venizia/ignis-helpers';\nimport { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport {\n MailErrorCodes,\n type IMailMessage,\n type IMailSendResult,\n type IMailTransport,\n type TAmazonSesClient,\n type TAmazonSesConfig,\n type TAmazonSesModule,\n} from '../../common';\nimport { MailAddressUtility, MailMimeUtility } from '../../utilities';\nimport { MailAttachmentUtility } from '../../utilities/attachment.utility';\n\nexport class AmazonSesTransportHelper extends BaseHelper implements IMailTransport {\n private client: AnyType;\n private sendEmailCommandConstructor: AnyType;\n private getAccountCommandConstructor: AnyType;\n private module?: TAmazonSesModule<TAmazonSesConfig>;\n\n constructor(opts: { config: TAmazonSesConfig; module?: TAmazonSesModule }) {\n super({ scope: AmazonSesTransportHelper.name });\n\n this.module = opts.module;\n this.configure(opts.config);\n }\n\n // ------------------------------------------------------------------------------------\n async send(message: IMailMessage): Promise<IMailSendResult> {\n const logger = this.logger.for(this.send.name);\n\n try {\n logger.debug('Sending email with Amazon SES to: %s', message.to);\n\n const rawMessage = await MailMimeUtility.buildRawMessage({ message });\n const command = new this.sendEmailCommandConstructor({\n // `FromEmailAddress` carries the same RFC 5321/5322 mailbox syntax as the raw `From:`\n // header and is subject to the same 7-bit-ASCII requirement - encoding it separately\n // here (instead of passing `message.from` through untouched) is what keeps a non-ASCII\n // display name from reaching the SES API as raw UTF-8 bytes.\n FromEmailAddress: message.from\n ? MailMimeUtility.formatAddressHeader({ value: message.from })\n : message.from,\n Destination: {\n ToAddresses: MailAddressUtility.splitList({ value: message.to }),\n CcAddresses: message.cc ? MailAddressUtility.splitList({ value: message.cc }) : undefined,\n BccAddresses: message.bcc\n ? MailAddressUtility.splitList({ value: message.bcc })\n : undefined,\n },\n // No `ReplyToAddresses` here: `MailMimeUtility.buildRawMessage` already writes a single, RFC\n // 2047-encoded `Reply-To` header into the raw content. Setting both sends the same\n // address through two channels SES treats independently - a client can end up showing a\n // reply-to derived from whichever one SES prioritizes, and the other becomes a silent,\n // unencoded duplicate that skipped the address encoding path entirely.\n Content: {\n Raw: { Data: rawMessage },\n },\n });\n\n const result = await this.client.send(command);\n\n return {\n success: true,\n messageId: result.MessageId,\n response: result,\n };\n } catch (error) {\n logger.error(\n 'Amazon SES send failed | error: %s',\n error instanceof Error ? error.message : error,\n );\n MailAttachmentUtility.release({ attachments: message.attachments });\n\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n // ------------------------------------------------------------------------------------\n async verify(): Promise<boolean> {\n const logger = this.logger.for(this.verify.name);\n\n try {\n logger.info('Verifying Amazon SES account status');\n\n const command = new this.getAccountCommandConstructor({});\n const result = await this.client.send(command);\n const enabled = result.SendingEnabled === true;\n\n logger.info('Amazon SES account status: %s', enabled ? 'enabled' : 'disabled');\n\n return enabled;\n } catch (error) {\n logger.error(\n 'Amazon SES verification failed | error: %s',\n error instanceof Error ? error.message : error,\n );\n\n return false;\n }\n }\n\n // ------------------------------------------------------------------------------------\n async close(): Promise<void> {\n this.logger.for(this.close.name).info('Closing Amazon SES client');\n this.client.destroy?.();\n }\n\n // ------------------------------------------------------------------------------------\n configure(config: TAmazonSesConfig): void {\n this.validateConfig(config);\n\n const { client, SendEmailCommand, GetAccountCommand } = this.buildClient(config);\n\n this.client = client;\n this.sendEmailCommandConstructor = SendEmailCommand;\n this.getAccountCommandConstructor = GetAccountCommand;\n }\n\n // ------------------------------------------------------------------------------------\n protected buildClient(config: TAmazonSesConfig): TAmazonSesClient {\n const sesModule =\n this.module ?? ModuleUtility.loadSync<TAmazonSesModule>({ module: '@aws-sdk/client-sesv2' });\n\n const client = new sesModule.SESv2Client({\n region: config.region,\n credentials: config.credentials,\n endpoint: config.endpoint,\n });\n\n return {\n client,\n SendEmailCommand: sesModule.SendEmailCommand,\n GetAccountCommand: sesModule.GetAccountCommand,\n };\n }\n\n // ------------------------------------------------------------------------------------\n private validateConfig(config: TAmazonSesConfig): void {\n if (config.region) {\n return;\n }\n\n throw getError({\n statusCode: HTTP.ResultCodes.RS_5.InternalServerError,\n messageCode: MailErrorCodes.INVALID_CONFIGURATION,\n message: 'Invalid Amazon SES Configuration | Missing region',\n });\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mailgun-transporter.helper.d.ts","sourceRoot":"","sources":["../../../../../../src/components/mail/helpers/transporters/mailgun-transporter.helper.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAY,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAEV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,cAAc,EACd,cAAc,EACf,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"mailgun-transporter.helper.d.ts","sourceRoot":"","sources":["../../../../../../src/components/mail/helpers/transporters/mailgun-transporter.helper.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAY,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAEV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,cAAc,EACd,cAAc,EACf,MAAM,cAAc,CAAC;AAItB,qBAAa,sBAAuB,SAAQ,UAAW,YAAW,cAAc;IAC9E,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAC,CAAiB;gBAEpB,IAAI,EAAE;QAAE,MAAM,EAAE,cAAc,CAAC;QAAC,MAAM,CAAC,EAAE,cAAc,CAAA;KAAE;IAOrE,SAAS,CAAC,MAAM,EAAE,cAAc;IAOhC,sHAAsH;IACtH,OAAO,CAAC,cAAc;IAoBtB,+FAA+F;IAC/F,SAAS,CAAC,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO;IAQhD,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;IAmDrD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;CAmBjC"}
|