sms-panel-manager 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/LICENSE +21 -0
- package/README.md +142 -2
- package/SECURITY.md +7 -0
- package/dist/encryption-BUH96uQn.d.cts +119 -0
- package/dist/encryption-Ckv6RYE0.d.ts +119 -0
- package/dist/index.cjs +565 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +546 -0
- package/dist/index.js.map +1 -0
- package/dist/manager-B3b12wET.d.cts +109 -0
- package/dist/manager-B3b12wET.d.ts +109 -0
- package/dist/mongoose.cjs +363 -0
- package/dist/mongoose.cjs.map +1 -0
- package/dist/mongoose.d.cts +132 -0
- package/dist/mongoose.d.ts +132 -0
- package/dist/mongoose.js +357 -0
- package/dist/mongoose.js.map +1 -0
- package/dist/nestjs.cjs +151 -0
- package/dist/nestjs.cjs.map +1 -0
- package/dist/nestjs.d.cts +38 -0
- package/dist/nestjs.d.ts +38 -0
- package/dist/nestjs.js +149 -0
- package/dist/nestjs.js.map +1 -0
- package/dist/provider-QoH6qlAe.d.cts +70 -0
- package/dist/provider-QoH6qlAe.d.ts +70 -0
- package/dist/providers.cjs +433 -0
- package/dist/providers.cjs.map +1 -0
- package/dist/providers.d.cts +139 -0
- package/dist/providers.d.ts +139 -0
- package/dist/providers.js +419 -0
- package/dist/providers.js.map +1 -0
- package/package.json +113 -4
package/dist/nestjs.cjs
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var common = require('@nestjs/common');
|
|
4
|
+
var zod = require('zod');
|
|
5
|
+
|
|
6
|
+
var __defProp = Object.defineProperty;
|
|
7
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
8
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
9
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
10
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
11
|
+
if (decorator = decorators[i])
|
|
12
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
13
|
+
if (kind && result) __defProp(target, key, result);
|
|
14
|
+
return result;
|
|
15
|
+
};
|
|
16
|
+
function createActionPayloadSchema(action) {
|
|
17
|
+
const shape = {
|
|
18
|
+
recipient: zod.z.string().min(1)
|
|
19
|
+
};
|
|
20
|
+
for (const [key, parameter] of Object.entries(action.params)) {
|
|
21
|
+
shape[key] = parameter.schema;
|
|
22
|
+
}
|
|
23
|
+
return zod.z.object(shape).strict();
|
|
24
|
+
}
|
|
25
|
+
function serializeSmsActions(actions) {
|
|
26
|
+
return Object.entries(actions).map(([key, action]) => ({
|
|
27
|
+
key,
|
|
28
|
+
title: action.title,
|
|
29
|
+
...action.description === void 0 ? {} : { description: action.description },
|
|
30
|
+
parameters: Object.entries(action.params).map(
|
|
31
|
+
([parameterKey, parameter]) => ({
|
|
32
|
+
key: parameterKey,
|
|
33
|
+
title: parameter.metadata.title,
|
|
34
|
+
...parameter.metadata.description === void 0 ? {} : { description: parameter.metadata.description },
|
|
35
|
+
type: parameter.type,
|
|
36
|
+
required: !parameter.isOptional
|
|
37
|
+
})
|
|
38
|
+
)
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/core/phone.ts
|
|
43
|
+
var IRAN_MOBILE_LOCAL = /^09\d{9}$/;
|
|
44
|
+
var InvalidIranianMobileNumberError = class extends TypeError {
|
|
45
|
+
code = "invalid_recipient";
|
|
46
|
+
constructor() {
|
|
47
|
+
super("Recipient must be a valid Iranian mobile number.");
|
|
48
|
+
this.name = "InvalidIranianMobileNumberError";
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
function normalizeIranianMobile(input) {
|
|
52
|
+
const normalized = input.trim().replace(/^0098/, "0").replace(/^\+98/, "0").replace(/^98/, "0");
|
|
53
|
+
if (!IRAN_MOBILE_LOCAL.test(normalized)) {
|
|
54
|
+
throw new InvalidIranianMobileNumberError();
|
|
55
|
+
}
|
|
56
|
+
return `+98${normalized.slice(1)}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/core/manager.ts
|
|
60
|
+
function createSmsManager(options) {
|
|
61
|
+
return {
|
|
62
|
+
async send(actionKey, payload, sendOptions = {}) {
|
|
63
|
+
const action = options.actions[actionKey];
|
|
64
|
+
if (action === void 0) {
|
|
65
|
+
throw new TypeError(`Unknown SMS action "${actionKey}".`);
|
|
66
|
+
}
|
|
67
|
+
const validated = createActionPayloadSchema(action).parse(payload);
|
|
68
|
+
const { recipient, ...parameters } = validated;
|
|
69
|
+
return options.executor.execute({
|
|
70
|
+
actionKey,
|
|
71
|
+
recipient: normalizeIranianMobile(recipient),
|
|
72
|
+
parameters,
|
|
73
|
+
options: sendOptions
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// src/nestjs/index.ts
|
|
80
|
+
function createSmsManagerToken(actions) {
|
|
81
|
+
return /* @__PURE__ */ Symbol(
|
|
82
|
+
`sms-panel-manager:${Object.keys(actions).sort().join(",")}`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
function adminControllers(actions, admin) {
|
|
86
|
+
if (admin?.enabled !== true) return [];
|
|
87
|
+
if (admin.guard === void 0) {
|
|
88
|
+
throw new TypeError(
|
|
89
|
+
"NestJS SMS administration controllers require a host-supplied guard."
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
const routePrefix = admin.routePrefix ?? "admin/sms";
|
|
93
|
+
const metadata = serializeSmsActions(actions);
|
|
94
|
+
let SmsAdminController = class {
|
|
95
|
+
actions() {
|
|
96
|
+
return metadata;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
__decorateClass([
|
|
100
|
+
common.Get("actions")
|
|
101
|
+
], SmsAdminController.prototype, "actions", 1);
|
|
102
|
+
SmsAdminController = __decorateClass([
|
|
103
|
+
common.Controller(routePrefix),
|
|
104
|
+
common.UseGuards(admin.guard)
|
|
105
|
+
], SmsAdminController);
|
|
106
|
+
return [SmsAdminController];
|
|
107
|
+
}
|
|
108
|
+
exports.SmsPanelModule = class SmsPanelModule {
|
|
109
|
+
static forRoot(options) {
|
|
110
|
+
const provider = {
|
|
111
|
+
provide: options.token,
|
|
112
|
+
useValue: createSmsManager({
|
|
113
|
+
actions: options.actions,
|
|
114
|
+
executor: options.executor
|
|
115
|
+
})
|
|
116
|
+
};
|
|
117
|
+
return {
|
|
118
|
+
module: exports.SmsPanelModule,
|
|
119
|
+
providers: [provider],
|
|
120
|
+
controllers: adminControllers(options.actions, options.admin),
|
|
121
|
+
exports: [options.token]
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
static forRootAsync(options) {
|
|
125
|
+
const provider = {
|
|
126
|
+
provide: options.token,
|
|
127
|
+
inject: [...options.inject ?? []],
|
|
128
|
+
useFactory: async (...dependencies) => {
|
|
129
|
+
const runtime = await options.useFactory(...dependencies);
|
|
130
|
+
return createSmsManager({
|
|
131
|
+
actions: options.actions,
|
|
132
|
+
executor: runtime.executor
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
return {
|
|
137
|
+
module: exports.SmsPanelModule,
|
|
138
|
+
...options.imports === void 0 ? {} : { imports: options.imports },
|
|
139
|
+
providers: [provider],
|
|
140
|
+
controllers: adminControllers(options.actions, options.admin),
|
|
141
|
+
exports: [options.token]
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
exports.SmsPanelModule = __decorateClass([
|
|
146
|
+
common.Module({})
|
|
147
|
+
], exports.SmsPanelModule);
|
|
148
|
+
|
|
149
|
+
exports.createSmsManagerToken = createSmsManagerToken;
|
|
150
|
+
//# sourceMappingURL=nestjs.cjs.map
|
|
151
|
+
//# sourceMappingURL=nestjs.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/actions.ts","../src/core/phone.ts","../src/core/manager.ts","../src/nestjs/index.ts"],"names":["z","Get","Controller","UseGuards","SmsPanelModule","Module"],"mappings":"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","file":"nestjs.cjs","sourcesContent":["import { z } from \"zod\";\n\nimport type { ParameterDescriptor } from \"./parameters.js\";\n\nexport type SmsParameterMap = Readonly<Record<string, ParameterDescriptor>>;\n\nexport interface SmsActionDefinition<\n TParams extends SmsParameterMap = SmsParameterMap,\n> {\n readonly title: string;\n readonly description?: string;\n readonly params: TParams;\n}\n\nexport type SmsActionMap = Readonly<Record<string, SmsActionDefinition>>;\n\nconst RESERVED_PARAMETER_KEYS = new Set([\n \"recipient\",\n \"idempotencyKey\",\n \"signal\",\n \"correlationId\",\n \"metadata\",\n]);\n\nexport function defineSmsActions<const TActions extends SmsActionMap>(\n actions: TActions,\n): TActions {\n for (const [actionKey, action] of Object.entries(actions)) {\n if (!/^[a-z][a-z0-9_]*$/.test(actionKey)) {\n throw new TypeError(\n `Invalid SMS action key \"${actionKey}\". Use lower snake_case.`,\n );\n }\n\n for (const parameterKey of Object.keys(action.params)) {\n if (RESERVED_PARAMETER_KEYS.has(parameterKey)) {\n throw new TypeError(\n `SMS action \"${actionKey}\" uses reserved parameter \"${parameterKey}\".`,\n );\n }\n }\n }\n\n return actions;\n}\n\ntype RequiredParameterKeys<TParams extends SmsParameterMap> = {\n [K in keyof TParams]-?: TParams[K][\"isOptional\"] extends true ? never : K;\n}[keyof TParams];\n\ntype OptionalParameterKeys<TParams extends SmsParameterMap> = {\n [K in keyof TParams]-?: TParams[K][\"isOptional\"] extends true ? K : never;\n}[keyof TParams];\n\ntype InferDescriptor<TDescriptor extends ParameterDescriptor> = z.output<\n TDescriptor[\"schema\"]\n>;\n\nexport type InferActionPayload<TAction extends SmsActionDefinition> = {\n recipient: string;\n} & {\n [K in RequiredParameterKeys<TAction[\"params\"]>]: InferDescriptor<\n TAction[\"params\"][K]\n >;\n} & {\n [K in OptionalParameterKeys<TAction[\"params\"]>]?: InferDescriptor<\n TAction[\"params\"][K]\n > extends infer TValue\n ? Exclude<TValue, undefined>\n : never;\n};\n\nexport function createActionPayloadSchema(\n action: SmsActionDefinition,\n): z.ZodObject<z.ZodRawShape> {\n const shape: Record<string, z.ZodType> = {\n recipient: z.string().min(1),\n };\n\n for (const [key, parameter] of Object.entries(action.params)) {\n shape[key] = parameter.schema;\n }\n\n return z.object(shape).strict();\n}\n\nexport interface SerializableActionMetadata {\n readonly key: string;\n readonly title: string;\n readonly description?: string;\n readonly parameters: readonly {\n readonly key: string;\n readonly title: string;\n readonly description?: string;\n readonly type: ParameterDescriptor[\"type\"];\n readonly required: boolean;\n }[];\n}\n\nexport function serializeSmsActions(\n actions: SmsActionMap,\n): readonly SerializableActionMetadata[] {\n return Object.entries(actions).map(([key, action]) => ({\n key,\n title: action.title,\n ...(action.description === undefined\n ? {}\n : { description: action.description }),\n parameters: Object.entries(action.params).map(\n ([parameterKey, parameter]) => ({\n key: parameterKey,\n title: parameter.metadata.title,\n ...(parameter.metadata.description === undefined\n ? {}\n : { description: parameter.metadata.description }),\n type: parameter.type,\n required: !parameter.isOptional,\n }),\n ),\n }));\n}\n","const IRAN_MOBILE_LOCAL = /^09\\d{9}$/;\n\nexport class InvalidIranianMobileNumberError extends TypeError {\n readonly code = \"invalid_recipient\";\n\n constructor() {\n super(\"Recipient must be a valid Iranian mobile number.\");\n this.name = \"InvalidIranianMobileNumberError\";\n }\n}\n\nexport function normalizeIranianMobile(input: string): `+98${string}` {\n const normalized = input\n .trim()\n .replace(/^0098/, \"0\")\n .replace(/^\\+98/, \"0\")\n .replace(/^98/, \"0\");\n\n if (!IRAN_MOBILE_LOCAL.test(normalized)) {\n throw new InvalidIranianMobileNumberError();\n }\n\n return `+98${normalized.slice(1)}`;\n}\n\nexport function toIranianLocalMobile(input: string): `09${string}` {\n const canonical = normalizeIranianMobile(input);\n return `0${canonical.slice(3)}` as `09${string}`;\n}\n","import {\n createActionPayloadSchema,\n type InferActionPayload,\n type SmsActionMap,\n} from \"./actions.js\";\nimport { normalizeIranianMobile } from \"./phone.js\";\n\nexport interface SmsSendOptions {\n readonly idempotencyKey?: string;\n readonly signal?: AbortSignal;\n readonly correlationId?: string;\n readonly metadata?: Readonly<\n Record<string, string | number | boolean | null>\n >;\n}\n\nexport interface SmsSendResult {\n readonly operationId: string;\n readonly status: \"pending\" | \"submitted\" | \"delivered\" | \"failed\" | \"unknown\";\n readonly providerMessageId?: string;\n}\n\nexport interface SmsSendCommand {\n readonly actionKey: string;\n readonly recipient: `+98${string}`;\n readonly parameters: Readonly<Record<string, unknown>>;\n readonly options: SmsSendOptions;\n}\n\nexport interface SmsSendExecutor {\n execute(command: SmsSendCommand): Promise<SmsSendResult>;\n}\n\nexport interface SmsManager<TActions extends SmsActionMap> {\n send<TKey extends keyof TActions & string>(\n action: TKey,\n payload: InferActionPayload<TActions[TKey]>,\n options?: SmsSendOptions,\n ): Promise<SmsSendResult>;\n}\n\nexport function createSmsManager<TActions extends SmsActionMap>(options: {\n readonly actions: TActions;\n readonly executor: SmsSendExecutor;\n}): SmsManager<TActions> {\n return {\n async send(actionKey, payload, sendOptions = {}) {\n const action = options.actions[actionKey];\n if (action === undefined) {\n throw new TypeError(`Unknown SMS action \"${actionKey}\".`);\n }\n const validated = createActionPayloadSchema(action).parse(payload);\n const { recipient, ...parameters } = validated;\n\n return options.executor.execute({\n actionKey,\n recipient: normalizeIranianMobile(recipient as string),\n parameters,\n options: sendOptions,\n });\n },\n };\n}\n","import {\n Controller,\n Get,\n Module,\n UseGuards,\n type CanActivate,\n type DynamicModule,\n type FactoryProvider,\n type ModuleMetadata,\n type Provider,\n type Type,\n} from \"@nestjs/common\";\n\nimport {\n serializeSmsActions,\n type SerializableActionMetadata,\n type SmsActionMap,\n} from \"../core/actions.js\";\nimport {\n createSmsManager,\n type SmsManager,\n type SmsSendExecutor,\n} from \"../core/manager.js\";\n\ndeclare const smsManagerTokenBrand: unique symbol;\nexport type SmsManagerToken<TActions extends SmsActionMap> = symbol & {\n readonly [smsManagerTokenBrand]: TActions;\n};\n\nexport function createSmsManagerToken<TActions extends SmsActionMap>(\n actions: TActions,\n): SmsManagerToken<TActions> {\n return Symbol(\n `sms-panel-manager:${Object.keys(actions).sort().join(\",\")}`,\n ) as SmsManagerToken<TActions>;\n}\n\nexport interface SmsAdminModuleOptions {\n readonly enabled?: boolean;\n readonly guard?: Type<CanActivate>;\n readonly routePrefix?: string;\n}\n\nexport interface SmsPanelModuleOptions<TActions extends SmsActionMap> {\n readonly actions: TActions;\n readonly token: SmsManagerToken<TActions>;\n readonly executor: SmsSendExecutor;\n readonly admin?: SmsAdminModuleOptions;\n}\n\nexport interface SmsPanelRuntimeOptions {\n readonly executor: SmsSendExecutor;\n}\n\nexport interface SmsPanelModuleAsyncOptions<\n TActions extends SmsActionMap,\n TDependencies extends unknown[] = [],\n> extends Pick<ModuleMetadata, \"imports\"> {\n readonly actions: TActions;\n readonly token: SmsManagerToken<TActions>;\n readonly admin?: SmsAdminModuleOptions;\n readonly inject?: FactoryProvider[\"inject\"];\n readonly useFactory: (\n ...dependencies: TDependencies\n ) => Promise<SmsPanelRuntimeOptions> | SmsPanelRuntimeOptions;\n}\n\nfunction adminControllers(\n actions: SmsActionMap,\n admin: SmsAdminModuleOptions | undefined,\n): Type[] {\n if (admin?.enabled !== true) return [];\n if (admin.guard === undefined) {\n throw new TypeError(\n \"NestJS SMS administration controllers require a host-supplied guard.\",\n );\n }\n\n const routePrefix = admin.routePrefix ?? \"admin/sms\";\n const metadata = serializeSmsActions(actions);\n\n @Controller(routePrefix)\n @UseGuards(admin.guard)\n class SmsAdminController {\n @Get(\"actions\")\n actions(): readonly SerializableActionMetadata[] {\n return metadata;\n }\n }\n\n return [SmsAdminController];\n}\n\n@Module({})\n// Nest modules intentionally expose static registration methods.\n// eslint-disable-next-line @typescript-eslint/no-extraneous-class\nexport class SmsPanelModule {\n static forRoot<TActions extends SmsActionMap>(\n options: SmsPanelModuleOptions<TActions>,\n ): DynamicModule {\n const provider: Provider = {\n provide: options.token,\n useValue: createSmsManager({\n actions: options.actions,\n executor: options.executor,\n }),\n };\n\n return {\n module: SmsPanelModule,\n providers: [provider],\n controllers: adminControllers(options.actions, options.admin),\n exports: [options.token],\n };\n }\n\n static forRootAsync<\n TActions extends SmsActionMap,\n TDependencies extends unknown[] = [],\n >(\n options: SmsPanelModuleAsyncOptions<TActions, TDependencies>,\n ): DynamicModule {\n const provider: Provider = {\n provide: options.token,\n inject: [...(options.inject ?? [])],\n useFactory: async (...dependencies: TDependencies) => {\n const runtime = await options.useFactory(...dependencies);\n return createSmsManager({\n actions: options.actions,\n executor: runtime.executor,\n });\n },\n };\n\n return {\n module: SmsPanelModule,\n ...(options.imports === undefined ? {} : { imports: options.imports }),\n providers: [provider],\n controllers: adminControllers(options.actions, options.admin),\n exports: [options.token],\n };\n }\n}\n\nexport type InjectedSmsManager<TToken> =\n TToken extends SmsManagerToken<infer TActions> ? SmsManager<TActions> : never;\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Type, CanActivate, DynamicModule, ModuleMetadata, FactoryProvider } from '@nestjs/common';
|
|
2
|
+
import { SmsActionMap, SmsManager, SmsSendExecutor } from './index.cjs';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
declare const smsManagerTokenBrand: unique symbol;
|
|
6
|
+
type SmsManagerToken<TActions extends SmsActionMap> = symbol & {
|
|
7
|
+
readonly [smsManagerTokenBrand]: TActions;
|
|
8
|
+
};
|
|
9
|
+
declare function createSmsManagerToken<TActions extends SmsActionMap>(actions: TActions): SmsManagerToken<TActions>;
|
|
10
|
+
interface SmsAdminModuleOptions {
|
|
11
|
+
readonly enabled?: boolean;
|
|
12
|
+
readonly guard?: Type<CanActivate>;
|
|
13
|
+
readonly routePrefix?: string;
|
|
14
|
+
}
|
|
15
|
+
interface SmsPanelModuleOptions<TActions extends SmsActionMap> {
|
|
16
|
+
readonly actions: TActions;
|
|
17
|
+
readonly token: SmsManagerToken<TActions>;
|
|
18
|
+
readonly executor: SmsSendExecutor;
|
|
19
|
+
readonly admin?: SmsAdminModuleOptions;
|
|
20
|
+
}
|
|
21
|
+
interface SmsPanelRuntimeOptions {
|
|
22
|
+
readonly executor: SmsSendExecutor;
|
|
23
|
+
}
|
|
24
|
+
interface SmsPanelModuleAsyncOptions<TActions extends SmsActionMap, TDependencies extends unknown[] = []> extends Pick<ModuleMetadata, "imports"> {
|
|
25
|
+
readonly actions: TActions;
|
|
26
|
+
readonly token: SmsManagerToken<TActions>;
|
|
27
|
+
readonly admin?: SmsAdminModuleOptions;
|
|
28
|
+
readonly inject?: FactoryProvider["inject"];
|
|
29
|
+
readonly useFactory: (...dependencies: TDependencies) => Promise<SmsPanelRuntimeOptions> | SmsPanelRuntimeOptions;
|
|
30
|
+
}
|
|
31
|
+
declare class SmsPanelModule {
|
|
32
|
+
static forRoot<TActions extends SmsActionMap>(options: SmsPanelModuleOptions<TActions>): DynamicModule;
|
|
33
|
+
static forRootAsync<TActions extends SmsActionMap, TDependencies extends unknown[] = []>(options: SmsPanelModuleAsyncOptions<TActions, TDependencies>): DynamicModule;
|
|
34
|
+
}
|
|
35
|
+
type InjectedSmsManager<TToken> = TToken extends SmsManagerToken<infer TActions> ? SmsManager<TActions> : never;
|
|
36
|
+
|
|
37
|
+
export { SmsPanelModule, createSmsManagerToken };
|
|
38
|
+
export type { InjectedSmsManager, SmsAdminModuleOptions, SmsManagerToken, SmsPanelModuleAsyncOptions, SmsPanelModuleOptions, SmsPanelRuntimeOptions };
|
package/dist/nestjs.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Type, CanActivate, DynamicModule, ModuleMetadata, FactoryProvider } from '@nestjs/common';
|
|
2
|
+
import { SmsActionMap, SmsManager, SmsSendExecutor } from './index.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
declare const smsManagerTokenBrand: unique symbol;
|
|
6
|
+
type SmsManagerToken<TActions extends SmsActionMap> = symbol & {
|
|
7
|
+
readonly [smsManagerTokenBrand]: TActions;
|
|
8
|
+
};
|
|
9
|
+
declare function createSmsManagerToken<TActions extends SmsActionMap>(actions: TActions): SmsManagerToken<TActions>;
|
|
10
|
+
interface SmsAdminModuleOptions {
|
|
11
|
+
readonly enabled?: boolean;
|
|
12
|
+
readonly guard?: Type<CanActivate>;
|
|
13
|
+
readonly routePrefix?: string;
|
|
14
|
+
}
|
|
15
|
+
interface SmsPanelModuleOptions<TActions extends SmsActionMap> {
|
|
16
|
+
readonly actions: TActions;
|
|
17
|
+
readonly token: SmsManagerToken<TActions>;
|
|
18
|
+
readonly executor: SmsSendExecutor;
|
|
19
|
+
readonly admin?: SmsAdminModuleOptions;
|
|
20
|
+
}
|
|
21
|
+
interface SmsPanelRuntimeOptions {
|
|
22
|
+
readonly executor: SmsSendExecutor;
|
|
23
|
+
}
|
|
24
|
+
interface SmsPanelModuleAsyncOptions<TActions extends SmsActionMap, TDependencies extends unknown[] = []> extends Pick<ModuleMetadata, "imports"> {
|
|
25
|
+
readonly actions: TActions;
|
|
26
|
+
readonly token: SmsManagerToken<TActions>;
|
|
27
|
+
readonly admin?: SmsAdminModuleOptions;
|
|
28
|
+
readonly inject?: FactoryProvider["inject"];
|
|
29
|
+
readonly useFactory: (...dependencies: TDependencies) => Promise<SmsPanelRuntimeOptions> | SmsPanelRuntimeOptions;
|
|
30
|
+
}
|
|
31
|
+
declare class SmsPanelModule {
|
|
32
|
+
static forRoot<TActions extends SmsActionMap>(options: SmsPanelModuleOptions<TActions>): DynamicModule;
|
|
33
|
+
static forRootAsync<TActions extends SmsActionMap, TDependencies extends unknown[] = []>(options: SmsPanelModuleAsyncOptions<TActions, TDependencies>): DynamicModule;
|
|
34
|
+
}
|
|
35
|
+
type InjectedSmsManager<TToken> = TToken extends SmsManagerToken<infer TActions> ? SmsManager<TActions> : never;
|
|
36
|
+
|
|
37
|
+
export { SmsPanelModule, createSmsManagerToken };
|
|
38
|
+
export type { InjectedSmsManager, SmsAdminModuleOptions, SmsManagerToken, SmsPanelModuleAsyncOptions, SmsPanelModuleOptions, SmsPanelRuntimeOptions };
|
package/dist/nestjs.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { Module, Get, Controller, UseGuards } from '@nestjs/common';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
7
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
8
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
9
|
+
if (decorator = decorators[i])
|
|
10
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
11
|
+
if (kind && result) __defProp(target, key, result);
|
|
12
|
+
return result;
|
|
13
|
+
};
|
|
14
|
+
function createActionPayloadSchema(action) {
|
|
15
|
+
const shape = {
|
|
16
|
+
recipient: z.string().min(1)
|
|
17
|
+
};
|
|
18
|
+
for (const [key, parameter] of Object.entries(action.params)) {
|
|
19
|
+
shape[key] = parameter.schema;
|
|
20
|
+
}
|
|
21
|
+
return z.object(shape).strict();
|
|
22
|
+
}
|
|
23
|
+
function serializeSmsActions(actions) {
|
|
24
|
+
return Object.entries(actions).map(([key, action]) => ({
|
|
25
|
+
key,
|
|
26
|
+
title: action.title,
|
|
27
|
+
...action.description === void 0 ? {} : { description: action.description },
|
|
28
|
+
parameters: Object.entries(action.params).map(
|
|
29
|
+
([parameterKey, parameter]) => ({
|
|
30
|
+
key: parameterKey,
|
|
31
|
+
title: parameter.metadata.title,
|
|
32
|
+
...parameter.metadata.description === void 0 ? {} : { description: parameter.metadata.description },
|
|
33
|
+
type: parameter.type,
|
|
34
|
+
required: !parameter.isOptional
|
|
35
|
+
})
|
|
36
|
+
)
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// src/core/phone.ts
|
|
41
|
+
var IRAN_MOBILE_LOCAL = /^09\d{9}$/;
|
|
42
|
+
var InvalidIranianMobileNumberError = class extends TypeError {
|
|
43
|
+
code = "invalid_recipient";
|
|
44
|
+
constructor() {
|
|
45
|
+
super("Recipient must be a valid Iranian mobile number.");
|
|
46
|
+
this.name = "InvalidIranianMobileNumberError";
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
function normalizeIranianMobile(input) {
|
|
50
|
+
const normalized = input.trim().replace(/^0098/, "0").replace(/^\+98/, "0").replace(/^98/, "0");
|
|
51
|
+
if (!IRAN_MOBILE_LOCAL.test(normalized)) {
|
|
52
|
+
throw new InvalidIranianMobileNumberError();
|
|
53
|
+
}
|
|
54
|
+
return `+98${normalized.slice(1)}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/core/manager.ts
|
|
58
|
+
function createSmsManager(options) {
|
|
59
|
+
return {
|
|
60
|
+
async send(actionKey, payload, sendOptions = {}) {
|
|
61
|
+
const action = options.actions[actionKey];
|
|
62
|
+
if (action === void 0) {
|
|
63
|
+
throw new TypeError(`Unknown SMS action "${actionKey}".`);
|
|
64
|
+
}
|
|
65
|
+
const validated = createActionPayloadSchema(action).parse(payload);
|
|
66
|
+
const { recipient, ...parameters } = validated;
|
|
67
|
+
return options.executor.execute({
|
|
68
|
+
actionKey,
|
|
69
|
+
recipient: normalizeIranianMobile(recipient),
|
|
70
|
+
parameters,
|
|
71
|
+
options: sendOptions
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/nestjs/index.ts
|
|
78
|
+
function createSmsManagerToken(actions) {
|
|
79
|
+
return /* @__PURE__ */ Symbol(
|
|
80
|
+
`sms-panel-manager:${Object.keys(actions).sort().join(",")}`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
function adminControllers(actions, admin) {
|
|
84
|
+
if (admin?.enabled !== true) return [];
|
|
85
|
+
if (admin.guard === void 0) {
|
|
86
|
+
throw new TypeError(
|
|
87
|
+
"NestJS SMS administration controllers require a host-supplied guard."
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
const routePrefix = admin.routePrefix ?? "admin/sms";
|
|
91
|
+
const metadata = serializeSmsActions(actions);
|
|
92
|
+
let SmsAdminController = class {
|
|
93
|
+
actions() {
|
|
94
|
+
return metadata;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
__decorateClass([
|
|
98
|
+
Get("actions")
|
|
99
|
+
], SmsAdminController.prototype, "actions", 1);
|
|
100
|
+
SmsAdminController = __decorateClass([
|
|
101
|
+
Controller(routePrefix),
|
|
102
|
+
UseGuards(admin.guard)
|
|
103
|
+
], SmsAdminController);
|
|
104
|
+
return [SmsAdminController];
|
|
105
|
+
}
|
|
106
|
+
var SmsPanelModule = class {
|
|
107
|
+
static forRoot(options) {
|
|
108
|
+
const provider = {
|
|
109
|
+
provide: options.token,
|
|
110
|
+
useValue: createSmsManager({
|
|
111
|
+
actions: options.actions,
|
|
112
|
+
executor: options.executor
|
|
113
|
+
})
|
|
114
|
+
};
|
|
115
|
+
return {
|
|
116
|
+
module: SmsPanelModule,
|
|
117
|
+
providers: [provider],
|
|
118
|
+
controllers: adminControllers(options.actions, options.admin),
|
|
119
|
+
exports: [options.token]
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
static forRootAsync(options) {
|
|
123
|
+
const provider = {
|
|
124
|
+
provide: options.token,
|
|
125
|
+
inject: [...options.inject ?? []],
|
|
126
|
+
useFactory: async (...dependencies) => {
|
|
127
|
+
const runtime = await options.useFactory(...dependencies);
|
|
128
|
+
return createSmsManager({
|
|
129
|
+
actions: options.actions,
|
|
130
|
+
executor: runtime.executor
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
return {
|
|
135
|
+
module: SmsPanelModule,
|
|
136
|
+
...options.imports === void 0 ? {} : { imports: options.imports },
|
|
137
|
+
providers: [provider],
|
|
138
|
+
controllers: adminControllers(options.actions, options.admin),
|
|
139
|
+
exports: [options.token]
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
SmsPanelModule = __decorateClass([
|
|
144
|
+
Module({})
|
|
145
|
+
], SmsPanelModule);
|
|
146
|
+
|
|
147
|
+
export { SmsPanelModule, createSmsManagerToken };
|
|
148
|
+
//# sourceMappingURL=nestjs.js.map
|
|
149
|
+
//# sourceMappingURL=nestjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/actions.ts","../src/core/phone.ts","../src/core/manager.ts","../src/nestjs/index.ts"],"names":[],"mappings":"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","file":"nestjs.js","sourcesContent":["import { z } from \"zod\";\n\nimport type { ParameterDescriptor } from \"./parameters.js\";\n\nexport type SmsParameterMap = Readonly<Record<string, ParameterDescriptor>>;\n\nexport interface SmsActionDefinition<\n TParams extends SmsParameterMap = SmsParameterMap,\n> {\n readonly title: string;\n readonly description?: string;\n readonly params: TParams;\n}\n\nexport type SmsActionMap = Readonly<Record<string, SmsActionDefinition>>;\n\nconst RESERVED_PARAMETER_KEYS = new Set([\n \"recipient\",\n \"idempotencyKey\",\n \"signal\",\n \"correlationId\",\n \"metadata\",\n]);\n\nexport function defineSmsActions<const TActions extends SmsActionMap>(\n actions: TActions,\n): TActions {\n for (const [actionKey, action] of Object.entries(actions)) {\n if (!/^[a-z][a-z0-9_]*$/.test(actionKey)) {\n throw new TypeError(\n `Invalid SMS action key \"${actionKey}\". Use lower snake_case.`,\n );\n }\n\n for (const parameterKey of Object.keys(action.params)) {\n if (RESERVED_PARAMETER_KEYS.has(parameterKey)) {\n throw new TypeError(\n `SMS action \"${actionKey}\" uses reserved parameter \"${parameterKey}\".`,\n );\n }\n }\n }\n\n return actions;\n}\n\ntype RequiredParameterKeys<TParams extends SmsParameterMap> = {\n [K in keyof TParams]-?: TParams[K][\"isOptional\"] extends true ? never : K;\n}[keyof TParams];\n\ntype OptionalParameterKeys<TParams extends SmsParameterMap> = {\n [K in keyof TParams]-?: TParams[K][\"isOptional\"] extends true ? K : never;\n}[keyof TParams];\n\ntype InferDescriptor<TDescriptor extends ParameterDescriptor> = z.output<\n TDescriptor[\"schema\"]\n>;\n\nexport type InferActionPayload<TAction extends SmsActionDefinition> = {\n recipient: string;\n} & {\n [K in RequiredParameterKeys<TAction[\"params\"]>]: InferDescriptor<\n TAction[\"params\"][K]\n >;\n} & {\n [K in OptionalParameterKeys<TAction[\"params\"]>]?: InferDescriptor<\n TAction[\"params\"][K]\n > extends infer TValue\n ? Exclude<TValue, undefined>\n : never;\n};\n\nexport function createActionPayloadSchema(\n action: SmsActionDefinition,\n): z.ZodObject<z.ZodRawShape> {\n const shape: Record<string, z.ZodType> = {\n recipient: z.string().min(1),\n };\n\n for (const [key, parameter] of Object.entries(action.params)) {\n shape[key] = parameter.schema;\n }\n\n return z.object(shape).strict();\n}\n\nexport interface SerializableActionMetadata {\n readonly key: string;\n readonly title: string;\n readonly description?: string;\n readonly parameters: readonly {\n readonly key: string;\n readonly title: string;\n readonly description?: string;\n readonly type: ParameterDescriptor[\"type\"];\n readonly required: boolean;\n }[];\n}\n\nexport function serializeSmsActions(\n actions: SmsActionMap,\n): readonly SerializableActionMetadata[] {\n return Object.entries(actions).map(([key, action]) => ({\n key,\n title: action.title,\n ...(action.description === undefined\n ? {}\n : { description: action.description }),\n parameters: Object.entries(action.params).map(\n ([parameterKey, parameter]) => ({\n key: parameterKey,\n title: parameter.metadata.title,\n ...(parameter.metadata.description === undefined\n ? {}\n : { description: parameter.metadata.description }),\n type: parameter.type,\n required: !parameter.isOptional,\n }),\n ),\n }));\n}\n","const IRAN_MOBILE_LOCAL = /^09\\d{9}$/;\n\nexport class InvalidIranianMobileNumberError extends TypeError {\n readonly code = \"invalid_recipient\";\n\n constructor() {\n super(\"Recipient must be a valid Iranian mobile number.\");\n this.name = \"InvalidIranianMobileNumberError\";\n }\n}\n\nexport function normalizeIranianMobile(input: string): `+98${string}` {\n const normalized = input\n .trim()\n .replace(/^0098/, \"0\")\n .replace(/^\\+98/, \"0\")\n .replace(/^98/, \"0\");\n\n if (!IRAN_MOBILE_LOCAL.test(normalized)) {\n throw new InvalidIranianMobileNumberError();\n }\n\n return `+98${normalized.slice(1)}`;\n}\n\nexport function toIranianLocalMobile(input: string): `09${string}` {\n const canonical = normalizeIranianMobile(input);\n return `0${canonical.slice(3)}` as `09${string}`;\n}\n","import {\n createActionPayloadSchema,\n type InferActionPayload,\n type SmsActionMap,\n} from \"./actions.js\";\nimport { normalizeIranianMobile } from \"./phone.js\";\n\nexport interface SmsSendOptions {\n readonly idempotencyKey?: string;\n readonly signal?: AbortSignal;\n readonly correlationId?: string;\n readonly metadata?: Readonly<\n Record<string, string | number | boolean | null>\n >;\n}\n\nexport interface SmsSendResult {\n readonly operationId: string;\n readonly status: \"pending\" | \"submitted\" | \"delivered\" | \"failed\" | \"unknown\";\n readonly providerMessageId?: string;\n}\n\nexport interface SmsSendCommand {\n readonly actionKey: string;\n readonly recipient: `+98${string}`;\n readonly parameters: Readonly<Record<string, unknown>>;\n readonly options: SmsSendOptions;\n}\n\nexport interface SmsSendExecutor {\n execute(command: SmsSendCommand): Promise<SmsSendResult>;\n}\n\nexport interface SmsManager<TActions extends SmsActionMap> {\n send<TKey extends keyof TActions & string>(\n action: TKey,\n payload: InferActionPayload<TActions[TKey]>,\n options?: SmsSendOptions,\n ): Promise<SmsSendResult>;\n}\n\nexport function createSmsManager<TActions extends SmsActionMap>(options: {\n readonly actions: TActions;\n readonly executor: SmsSendExecutor;\n}): SmsManager<TActions> {\n return {\n async send(actionKey, payload, sendOptions = {}) {\n const action = options.actions[actionKey];\n if (action === undefined) {\n throw new TypeError(`Unknown SMS action \"${actionKey}\".`);\n }\n const validated = createActionPayloadSchema(action).parse(payload);\n const { recipient, ...parameters } = validated;\n\n return options.executor.execute({\n actionKey,\n recipient: normalizeIranianMobile(recipient as string),\n parameters,\n options: sendOptions,\n });\n },\n };\n}\n","import {\n Controller,\n Get,\n Module,\n UseGuards,\n type CanActivate,\n type DynamicModule,\n type FactoryProvider,\n type ModuleMetadata,\n type Provider,\n type Type,\n} from \"@nestjs/common\";\n\nimport {\n serializeSmsActions,\n type SerializableActionMetadata,\n type SmsActionMap,\n} from \"../core/actions.js\";\nimport {\n createSmsManager,\n type SmsManager,\n type SmsSendExecutor,\n} from \"../core/manager.js\";\n\ndeclare const smsManagerTokenBrand: unique symbol;\nexport type SmsManagerToken<TActions extends SmsActionMap> = symbol & {\n readonly [smsManagerTokenBrand]: TActions;\n};\n\nexport function createSmsManagerToken<TActions extends SmsActionMap>(\n actions: TActions,\n): SmsManagerToken<TActions> {\n return Symbol(\n `sms-panel-manager:${Object.keys(actions).sort().join(\",\")}`,\n ) as SmsManagerToken<TActions>;\n}\n\nexport interface SmsAdminModuleOptions {\n readonly enabled?: boolean;\n readonly guard?: Type<CanActivate>;\n readonly routePrefix?: string;\n}\n\nexport interface SmsPanelModuleOptions<TActions extends SmsActionMap> {\n readonly actions: TActions;\n readonly token: SmsManagerToken<TActions>;\n readonly executor: SmsSendExecutor;\n readonly admin?: SmsAdminModuleOptions;\n}\n\nexport interface SmsPanelRuntimeOptions {\n readonly executor: SmsSendExecutor;\n}\n\nexport interface SmsPanelModuleAsyncOptions<\n TActions extends SmsActionMap,\n TDependencies extends unknown[] = [],\n> extends Pick<ModuleMetadata, \"imports\"> {\n readonly actions: TActions;\n readonly token: SmsManagerToken<TActions>;\n readonly admin?: SmsAdminModuleOptions;\n readonly inject?: FactoryProvider[\"inject\"];\n readonly useFactory: (\n ...dependencies: TDependencies\n ) => Promise<SmsPanelRuntimeOptions> | SmsPanelRuntimeOptions;\n}\n\nfunction adminControllers(\n actions: SmsActionMap,\n admin: SmsAdminModuleOptions | undefined,\n): Type[] {\n if (admin?.enabled !== true) return [];\n if (admin.guard === undefined) {\n throw new TypeError(\n \"NestJS SMS administration controllers require a host-supplied guard.\",\n );\n }\n\n const routePrefix = admin.routePrefix ?? \"admin/sms\";\n const metadata = serializeSmsActions(actions);\n\n @Controller(routePrefix)\n @UseGuards(admin.guard)\n class SmsAdminController {\n @Get(\"actions\")\n actions(): readonly SerializableActionMetadata[] {\n return metadata;\n }\n }\n\n return [SmsAdminController];\n}\n\n@Module({})\n// Nest modules intentionally expose static registration methods.\n// eslint-disable-next-line @typescript-eslint/no-extraneous-class\nexport class SmsPanelModule {\n static forRoot<TActions extends SmsActionMap>(\n options: SmsPanelModuleOptions<TActions>,\n ): DynamicModule {\n const provider: Provider = {\n provide: options.token,\n useValue: createSmsManager({\n actions: options.actions,\n executor: options.executor,\n }),\n };\n\n return {\n module: SmsPanelModule,\n providers: [provider],\n controllers: adminControllers(options.actions, options.admin),\n exports: [options.token],\n };\n }\n\n static forRootAsync<\n TActions extends SmsActionMap,\n TDependencies extends unknown[] = [],\n >(\n options: SmsPanelModuleAsyncOptions<TActions, TDependencies>,\n ): DynamicModule {\n const provider: Provider = {\n provide: options.token,\n inject: [...(options.inject ?? [])],\n useFactory: async (...dependencies: TDependencies) => {\n const runtime = await options.useFactory(...dependencies);\n return createSmsManager({\n actions: options.actions,\n executor: runtime.executor,\n });\n },\n };\n\n return {\n module: SmsPanelModule,\n ...(options.imports === undefined ? {} : { imports: options.imports }),\n providers: [provider],\n controllers: adminControllers(options.actions, options.admin),\n exports: [options.token],\n };\n }\n}\n\nexport type InjectedSmsManager<TToken> =\n TToken extends SmsManagerToken<infer TActions> ? SmsManager<TActions> : never;\n"]}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
type CredentialVerificationResult = {
|
|
4
|
+
readonly status: "verified";
|
|
5
|
+
readonly method: "account" | "credit" | "profile" | "lines";
|
|
6
|
+
readonly verifiedAt: Date;
|
|
7
|
+
} | {
|
|
8
|
+
readonly status: "invalid";
|
|
9
|
+
readonly code: "invalid_credentials";
|
|
10
|
+
} | {
|
|
11
|
+
readonly status: "unavailable";
|
|
12
|
+
readonly retryable: boolean;
|
|
13
|
+
};
|
|
14
|
+
type ProviderTemplateCapability = {
|
|
15
|
+
readonly binding: "named" | "ordered";
|
|
16
|
+
readonly canList: boolean;
|
|
17
|
+
readonly canInspect: boolean;
|
|
18
|
+
readonly canCreate: boolean;
|
|
19
|
+
} | {
|
|
20
|
+
readonly binding: "fixed-slots";
|
|
21
|
+
readonly slots: readonly string[];
|
|
22
|
+
readonly canList: boolean;
|
|
23
|
+
readonly canInspect: boolean;
|
|
24
|
+
readonly canCreate: boolean;
|
|
25
|
+
};
|
|
26
|
+
interface ProviderCapabilities {
|
|
27
|
+
readonly credentialVerification: {
|
|
28
|
+
readonly mode: "account" | "credit" | "profile" | "lines";
|
|
29
|
+
} | {
|
|
30
|
+
readonly mode: "unsupported";
|
|
31
|
+
};
|
|
32
|
+
readonly templates: ProviderTemplateCapability;
|
|
33
|
+
readonly deliveryStatus: "poll" | "webhook" | "poll-and-webhook" | "unsupported";
|
|
34
|
+
readonly providerIdempotency: boolean;
|
|
35
|
+
}
|
|
36
|
+
interface ProviderCallContext {
|
|
37
|
+
readonly signal?: AbortSignal;
|
|
38
|
+
readonly correlationId?: string;
|
|
39
|
+
}
|
|
40
|
+
interface ProviderTemplateSendInput<TTemplateReference = unknown, TProviderParameters = unknown> {
|
|
41
|
+
readonly recipient: `+98${string}`;
|
|
42
|
+
readonly template: TTemplateReference;
|
|
43
|
+
readonly parameters: TProviderParameters;
|
|
44
|
+
readonly clientReferenceId?: string;
|
|
45
|
+
}
|
|
46
|
+
type ProviderSubmissionResult = {
|
|
47
|
+
readonly status: "accepted";
|
|
48
|
+
readonly providerMessageId: string;
|
|
49
|
+
readonly acceptedAt?: Date;
|
|
50
|
+
} | {
|
|
51
|
+
readonly status: "rejected";
|
|
52
|
+
readonly code: string;
|
|
53
|
+
readonly retryable: false;
|
|
54
|
+
} | {
|
|
55
|
+
readonly status: "pre-acceptance-failure";
|
|
56
|
+
readonly code: string;
|
|
57
|
+
readonly retryable: boolean;
|
|
58
|
+
} | {
|
|
59
|
+
readonly status: "unknown";
|
|
60
|
+
readonly code: "unknown_outcome";
|
|
61
|
+
};
|
|
62
|
+
interface SmsProviderAdapter<TCredentials, TTemplateReference = unknown, TProviderParameters = unknown> {
|
|
63
|
+
readonly id: string;
|
|
64
|
+
readonly credentialSchema: z.ZodType<TCredentials>;
|
|
65
|
+
readonly capabilities: ProviderCapabilities;
|
|
66
|
+
verifyCredentials(credentials: TCredentials, context: ProviderCallContext): Promise<CredentialVerificationResult>;
|
|
67
|
+
sendTemplate(credentials: TCredentials, input: ProviderTemplateSendInput<TTemplateReference, TProviderParameters>, context: ProviderCallContext): Promise<ProviderSubmissionResult>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export type { CredentialVerificationResult as C, ProviderCallContext as P, SmsProviderAdapter as S, ProviderCapabilities as a, ProviderSubmissionResult as b, ProviderTemplateCapability as c, ProviderTemplateSendInput as d };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
type CredentialVerificationResult = {
|
|
4
|
+
readonly status: "verified";
|
|
5
|
+
readonly method: "account" | "credit" | "profile" | "lines";
|
|
6
|
+
readonly verifiedAt: Date;
|
|
7
|
+
} | {
|
|
8
|
+
readonly status: "invalid";
|
|
9
|
+
readonly code: "invalid_credentials";
|
|
10
|
+
} | {
|
|
11
|
+
readonly status: "unavailable";
|
|
12
|
+
readonly retryable: boolean;
|
|
13
|
+
};
|
|
14
|
+
type ProviderTemplateCapability = {
|
|
15
|
+
readonly binding: "named" | "ordered";
|
|
16
|
+
readonly canList: boolean;
|
|
17
|
+
readonly canInspect: boolean;
|
|
18
|
+
readonly canCreate: boolean;
|
|
19
|
+
} | {
|
|
20
|
+
readonly binding: "fixed-slots";
|
|
21
|
+
readonly slots: readonly string[];
|
|
22
|
+
readonly canList: boolean;
|
|
23
|
+
readonly canInspect: boolean;
|
|
24
|
+
readonly canCreate: boolean;
|
|
25
|
+
};
|
|
26
|
+
interface ProviderCapabilities {
|
|
27
|
+
readonly credentialVerification: {
|
|
28
|
+
readonly mode: "account" | "credit" | "profile" | "lines";
|
|
29
|
+
} | {
|
|
30
|
+
readonly mode: "unsupported";
|
|
31
|
+
};
|
|
32
|
+
readonly templates: ProviderTemplateCapability;
|
|
33
|
+
readonly deliveryStatus: "poll" | "webhook" | "poll-and-webhook" | "unsupported";
|
|
34
|
+
readonly providerIdempotency: boolean;
|
|
35
|
+
}
|
|
36
|
+
interface ProviderCallContext {
|
|
37
|
+
readonly signal?: AbortSignal;
|
|
38
|
+
readonly correlationId?: string;
|
|
39
|
+
}
|
|
40
|
+
interface ProviderTemplateSendInput<TTemplateReference = unknown, TProviderParameters = unknown> {
|
|
41
|
+
readonly recipient: `+98${string}`;
|
|
42
|
+
readonly template: TTemplateReference;
|
|
43
|
+
readonly parameters: TProviderParameters;
|
|
44
|
+
readonly clientReferenceId?: string;
|
|
45
|
+
}
|
|
46
|
+
type ProviderSubmissionResult = {
|
|
47
|
+
readonly status: "accepted";
|
|
48
|
+
readonly providerMessageId: string;
|
|
49
|
+
readonly acceptedAt?: Date;
|
|
50
|
+
} | {
|
|
51
|
+
readonly status: "rejected";
|
|
52
|
+
readonly code: string;
|
|
53
|
+
readonly retryable: false;
|
|
54
|
+
} | {
|
|
55
|
+
readonly status: "pre-acceptance-failure";
|
|
56
|
+
readonly code: string;
|
|
57
|
+
readonly retryable: boolean;
|
|
58
|
+
} | {
|
|
59
|
+
readonly status: "unknown";
|
|
60
|
+
readonly code: "unknown_outcome";
|
|
61
|
+
};
|
|
62
|
+
interface SmsProviderAdapter<TCredentials, TTemplateReference = unknown, TProviderParameters = unknown> {
|
|
63
|
+
readonly id: string;
|
|
64
|
+
readonly credentialSchema: z.ZodType<TCredentials>;
|
|
65
|
+
readonly capabilities: ProviderCapabilities;
|
|
66
|
+
verifyCredentials(credentials: TCredentials, context: ProviderCallContext): Promise<CredentialVerificationResult>;
|
|
67
|
+
sendTemplate(credentials: TCredentials, input: ProviderTemplateSendInput<TTemplateReference, TProviderParameters>, context: ProviderCallContext): Promise<ProviderSubmissionResult>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export type { CredentialVerificationResult as C, ProviderCallContext as P, SmsProviderAdapter as S, ProviderCapabilities as a, ProviderSubmissionResult as b, ProviderTemplateCapability as c, ProviderTemplateSendInput as d };
|