@igniter-js/mail 0.1.13 → 0.1.14
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/AGENTS.md +38 -2
- package/README.md +40 -0
- package/dist/adapters/index.js +2 -2
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/index.mjs +1 -1
- package/dist/adapters/index.mjs.map +1 -1
- package/dist/index.d.mts +75 -4
- package/dist/index.d.ts +75 -4
- package/dist/index.js +186 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +185 -3
- package/dist/index.mjs.map +1 -1
- package/dist/telemetry/index.d.mts +119 -0
- package/dist/telemetry/index.d.ts +119 -0
- package/dist/telemetry/index.js +17 -0
- package/dist/telemetry/index.js.map +1 -1
- package/dist/telemetry/index.mjs +17 -0
- package/dist/telemetry/index.mjs.map +1 -1
- package/package.json +4 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { StandardSchemaV1,
|
|
1
|
+
import { StandardSchemaV1, IgniterLogger, IgniterError } from '@igniter-js/common';
|
|
2
|
+
import { JobLimiter, IgniterJobQueueAdapter } from '@igniter-js/core';
|
|
2
3
|
import { I as IgniterMailAdapter } from './index-CbiH0sth.js';
|
|
3
4
|
export { b as IgniterMailAdapterCredentials, a as IgniterMailAdapterSendParams, M as MockMailAdapter, P as PostmarkMailAdapter, R as ResendMailAdapter, S as SendGridMailAdapter, c as SmtpMailAdapter } from './index-CbiH0sth.js';
|
|
4
5
|
import { ReactElement } from 'react';
|
|
@@ -10,11 +11,44 @@ import { IgniterTelemetryManager } from '@igniter-js/telemetry';
|
|
|
10
11
|
interface IgniterMailTemplateBuilt<TSchema extends StandardSchemaV1> {
|
|
11
12
|
/** Default subject for the template (can be overridden per-send). */
|
|
12
13
|
subject: string;
|
|
14
|
+
/** Optional display name for Studio and tooling. */
|
|
15
|
+
name?: string;
|
|
16
|
+
/** Optional description for Studio and tooling. */
|
|
17
|
+
description?: string;
|
|
18
|
+
/** Optional path hint for Studio and tooling. */
|
|
19
|
+
path?: string;
|
|
20
|
+
/** Optional created timestamp (ISO string). */
|
|
21
|
+
createdAt?: string;
|
|
22
|
+
/** Optional updated timestamp (ISO string). */
|
|
23
|
+
updatedAt?: string;
|
|
24
|
+
/** Optional list of variable names for Studio and tooling. */
|
|
25
|
+
variables?: string[];
|
|
13
26
|
/** Schema used to validate and infer template payload. */
|
|
14
27
|
schema: TSchema;
|
|
15
28
|
/** React Email component renderer. */
|
|
16
29
|
render: (data: StandardSchemaV1.InferInput<TSchema>) => ReactElement;
|
|
17
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Template metadata exposed by {@link IIgniterMail}.
|
|
33
|
+
*/
|
|
34
|
+
interface IgniterMailTemplateMeta {
|
|
35
|
+
/** Template identifier (registry key). */
|
|
36
|
+
id: string;
|
|
37
|
+
/** Display name. */
|
|
38
|
+
name: string;
|
|
39
|
+
/** Description for UI listings. */
|
|
40
|
+
description: string;
|
|
41
|
+
/** Path hint for routing. */
|
|
42
|
+
path: string;
|
|
43
|
+
/** Subject line for the template. */
|
|
44
|
+
subject: string;
|
|
45
|
+
/** Creation timestamp (ISO string). */
|
|
46
|
+
createdAt: string;
|
|
47
|
+
/** Last update timestamp (ISO string). */
|
|
48
|
+
updatedAt: string;
|
|
49
|
+
/** Optional list of variables for the template. */
|
|
50
|
+
variables?: string[];
|
|
51
|
+
}
|
|
18
52
|
/**
|
|
19
53
|
* Extracts the valid template keys from a template map.
|
|
20
54
|
*/
|
|
@@ -107,6 +141,31 @@ interface IgniterMailHooks<TTemplates extends object> {
|
|
|
107
141
|
/** Invoked after a successful send. */
|
|
108
142
|
onSendSuccess?: (params: IgniterMailSendParams<TTemplates, any>) => Promise<void>;
|
|
109
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Template registry API exposed by {@link IIgniterMail}.
|
|
146
|
+
*/
|
|
147
|
+
interface IgniterMailTemplatesAPI<TTemplates extends object> {
|
|
148
|
+
/**
|
|
149
|
+
* Lists all registered templates with metadata.
|
|
150
|
+
*/
|
|
151
|
+
list: () => Promise<IgniterMailTemplateMeta[]>;
|
|
152
|
+
/**
|
|
153
|
+
* Resolves a template metadata entry by id.
|
|
154
|
+
*
|
|
155
|
+
* @param id - Template key.
|
|
156
|
+
*/
|
|
157
|
+
get: <TSelectedTemplate extends IgniterMailTemplateKey<TTemplates>>(id: TSelectedTemplate) => Promise<IgniterMailTemplateMeta | null>;
|
|
158
|
+
/**
|
|
159
|
+
* Renders a template to HTML + text.
|
|
160
|
+
*
|
|
161
|
+
* @param id - Template key.
|
|
162
|
+
* @param variables - Template input payload.
|
|
163
|
+
*/
|
|
164
|
+
render: <TSelectedTemplate extends IgniterMailTemplateKey<TTemplates>>(id: TSelectedTemplate, variables?: IgniterMailTemplatePayload<TTemplates[TSelectedTemplate]>) => Promise<{
|
|
165
|
+
html: string;
|
|
166
|
+
text: string;
|
|
167
|
+
}>;
|
|
168
|
+
}
|
|
110
169
|
/**
|
|
111
170
|
* Options used to initialize {@link IgniterMail}.
|
|
112
171
|
*/
|
|
@@ -133,6 +192,10 @@ interface IIgniterMail<TTemplates extends object> {
|
|
|
133
192
|
* Access via `typeof mail.$Infer` (type-level only).
|
|
134
193
|
*/
|
|
135
194
|
readonly $Infer: IgniterMailInfer<TTemplates>;
|
|
195
|
+
/**
|
|
196
|
+
* Template registry helpers.
|
|
197
|
+
*/
|
|
198
|
+
readonly templates: IgniterMailTemplatesAPI<TTemplates>;
|
|
136
199
|
/** Sends an email immediately. */
|
|
137
200
|
send: <TSelectedTemplate extends IgniterMailTemplateKey<TTemplates>>(params: IgniterMailSendParams<TTemplates, TSelectedTemplate>) => Promise<void>;
|
|
138
201
|
/** Schedules an email for a future date (requires queue adapter). */
|
|
@@ -223,7 +286,7 @@ declare const IgniterMailTemplate: typeof IgniterMailTemplateBuilder;
|
|
|
223
286
|
*/
|
|
224
287
|
declare class IgniterMailManagerCore<TTemplates extends object> implements IIgniterMail<TTemplates> {
|
|
225
288
|
private readonly adapter;
|
|
226
|
-
private readonly
|
|
289
|
+
private readonly templateRegistry;
|
|
227
290
|
private readonly logger?;
|
|
228
291
|
private readonly telemetry?;
|
|
229
292
|
private readonly queue?;
|
|
@@ -235,7 +298,15 @@ declare class IgniterMailManagerCore<TTemplates extends object> implements IIgni
|
|
|
235
298
|
* Access via `typeof mail.$Infer` (type-level only).
|
|
236
299
|
*/
|
|
237
300
|
readonly $Infer: IgniterMailInfer<TTemplates>;
|
|
301
|
+
/**
|
|
302
|
+
* Template registry helpers.
|
|
303
|
+
*/
|
|
304
|
+
readonly templates: IgniterMailTemplatesAPI<TTemplates>;
|
|
238
305
|
constructor(options: IgniterMailOptions<TTemplates>);
|
|
306
|
+
private buildTemplateMeta;
|
|
307
|
+
private listTemplates;
|
|
308
|
+
private getTemplate;
|
|
309
|
+
private renderTemplate;
|
|
239
310
|
private ensureQueueJobRegistered;
|
|
240
311
|
private validateTemplateData;
|
|
241
312
|
/**
|
|
@@ -256,7 +327,7 @@ declare class IgniterMailManagerCore<TTemplates extends object> implements IIgni
|
|
|
256
327
|
/**
|
|
257
328
|
* Known error codes thrown by `@igniter-js/mail` runtime.
|
|
258
329
|
*/
|
|
259
|
-
type IgniterMailErrorCode = 'MAIL_PROVIDER_FROM_REQUIRED' | 'MAIL_PROVIDER_ADAPTER_REQUIRED' | 'MAIL_PROVIDER_ADAPTER_SECRET_REQUIRED' | 'MAIL_PROVIDER_ADAPTER_NOT_FOUND' | 'MAIL_PROVIDER_TEMPLATES_REQUIRED' | 'MAIL_PROVIDER_TEMPLATE_NOT_FOUND' | 'MAIL_PROVIDER_TEMPLATE_DATA_INVALID' | 'MAIL_PROVIDER_SCHEDULE_DATE_INVALID' | 'MAIL_PROVIDER_SEND_FAILED' | 'MAIL_PROVIDER_SCHEDULE_FAILED' | 'MAIL_ADAPTER_CONFIGURATION_INVALID' | 'MAIL_TEMPLATE_CONFIGURATION_INVALID' | 'MAIL_PROVIDER_SCHEDULE_QUEUE_NOT_CONFIGURED';
|
|
330
|
+
type IgniterMailErrorCode = 'MAIL_PROVIDER_FROM_REQUIRED' | 'MAIL_PROVIDER_ADAPTER_REQUIRED' | 'MAIL_PROVIDER_ADAPTER_SECRET_REQUIRED' | 'MAIL_PROVIDER_ADAPTER_NOT_FOUND' | 'MAIL_PROVIDER_TEMPLATES_REQUIRED' | 'MAIL_PROVIDER_TEMPLATE_NOT_FOUND' | 'MAIL_PROVIDER_TEMPLATE_DATA_INVALID' | 'MAIL_PROVIDER_TEMPLATE_LIST_FAILED' | 'MAIL_PROVIDER_TEMPLATE_GET_FAILED' | 'MAIL_PROVIDER_TEMPLATE_RENDER_FAILED' | 'MAIL_PROVIDER_SCHEDULE_DATE_INVALID' | 'MAIL_PROVIDER_SEND_FAILED' | 'MAIL_PROVIDER_SCHEDULE_FAILED' | 'MAIL_ADAPTER_CONFIGURATION_INVALID' | 'MAIL_TEMPLATE_CONFIGURATION_INVALID' | 'MAIL_PROVIDER_SCHEDULE_QUEUE_NOT_CONFIGURED';
|
|
260
331
|
/**
|
|
261
332
|
* Payload used to create an {@link IgniterMailError}.
|
|
262
333
|
*/
|
|
@@ -306,4 +377,4 @@ declare class IgniterMailSchema {
|
|
|
306
377
|
static createPassthroughSchema(): StandardSchemaV1;
|
|
307
378
|
}
|
|
308
379
|
|
|
309
|
-
export { type IIgniterMail, IgniterMail, IgniterMailAdapter, IgniterMailBuilder, IgniterMailError, type IgniterMailErrorCode, type IgniterMailErrorPayload, type IgniterMailHooks, type IgniterMailInfer, IgniterMailManagerCore, type IgniterMailOptions, type IgniterMailQueueConfig, type IgniterMailQueueOptions, IgniterMailSchema, type IgniterMailSendParams, IgniterMailTemplate, IgniterMailTemplateBuilder, type IgniterMailTemplateBuilt, type IgniterMailTemplateKey, type IgniterMailTemplatePayload };
|
|
380
|
+
export { type IIgniterMail, IgniterMail, IgniterMailAdapter, IgniterMailBuilder, IgniterMailError, type IgniterMailErrorCode, type IgniterMailErrorPayload, type IgniterMailHooks, type IgniterMailInfer, IgniterMailManagerCore, type IgniterMailOptions, type IgniterMailQueueConfig, type IgniterMailQueueOptions, IgniterMailSchema, type IgniterMailSendParams, IgniterMailTemplate, IgniterMailTemplateBuilder, type IgniterMailTemplateBuilt, type IgniterMailTemplateKey, type IgniterMailTemplateMeta, type IgniterMailTemplatePayload, type IgniterMailTemplatesAPI };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var common = require('@igniter-js/common');
|
|
4
4
|
var resend = require('resend');
|
|
5
5
|
var nodemailer = require('nodemailer');
|
|
6
6
|
var React = require('react');
|
|
@@ -12,7 +12,7 @@ var nodemailer__default = /*#__PURE__*/_interopDefault(nodemailer);
|
|
|
12
12
|
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
13
13
|
|
|
14
14
|
// src/errors/mail.error.ts
|
|
15
|
-
var IgniterMailError = class _IgniterMailError extends
|
|
15
|
+
var IgniterMailError = class _IgniterMailError extends common.IgniterError {
|
|
16
16
|
constructor(payload) {
|
|
17
17
|
super({
|
|
18
18
|
code: payload.code,
|
|
@@ -402,11 +402,193 @@ var IgniterMailManagerCore = class {
|
|
|
402
402
|
});
|
|
403
403
|
}
|
|
404
404
|
this.adapter = adapter;
|
|
405
|
-
this.
|
|
405
|
+
this.templateRegistry = templates;
|
|
406
406
|
this.logger = logger;
|
|
407
407
|
this.telemetry = telemetry;
|
|
408
408
|
this.queue = queue;
|
|
409
409
|
this.options = rest;
|
|
410
|
+
this.templates = {
|
|
411
|
+
list: async () => this.listTemplates(),
|
|
412
|
+
get: async (id) => this.getTemplate(id),
|
|
413
|
+
render: async (id, variables) => this.renderTemplate(id, variables)
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
buildTemplateMeta(key, template) {
|
|
417
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
418
|
+
return {
|
|
419
|
+
id: key,
|
|
420
|
+
name: template.name ?? key,
|
|
421
|
+
description: template.description ?? `Template ${key}`,
|
|
422
|
+
path: template.path ?? `mail/${key}`,
|
|
423
|
+
subject: template.subject,
|
|
424
|
+
createdAt: template.createdAt ?? now,
|
|
425
|
+
updatedAt: template.updatedAt ?? now,
|
|
426
|
+
variables: template.variables
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
async listTemplates() {
|
|
430
|
+
const startTime = Date.now();
|
|
431
|
+
this.logger?.debug("IgniterMail.templates.list started");
|
|
432
|
+
this.telemetry?.emit("igniter.mail.templates.list.started", {
|
|
433
|
+
level: "debug",
|
|
434
|
+
attributes: {}
|
|
435
|
+
});
|
|
436
|
+
try {
|
|
437
|
+
const results = Object.entries(this.templateRegistry).map(
|
|
438
|
+
([key, template]) => this.buildTemplateMeta(
|
|
439
|
+
key,
|
|
440
|
+
template
|
|
441
|
+
)
|
|
442
|
+
);
|
|
443
|
+
this.telemetry?.emit("igniter.mail.templates.list.success", {
|
|
444
|
+
level: "info",
|
|
445
|
+
attributes: {
|
|
446
|
+
"ctx.mail.template.count": results.length,
|
|
447
|
+
"ctx.mail.duration_ms": Date.now() - startTime
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
this.logger?.info("IgniterMail.templates.list success", {
|
|
451
|
+
count: results.length,
|
|
452
|
+
durationMs: Date.now() - startTime
|
|
453
|
+
});
|
|
454
|
+
return results;
|
|
455
|
+
} catch (error) {
|
|
456
|
+
const normalizedError = IgniterMailError.is(error) ? error : new IgniterMailError({
|
|
457
|
+
code: "MAIL_PROVIDER_TEMPLATE_LIST_FAILED",
|
|
458
|
+
message: "MAIL_PROVIDER_TEMPLATE_LIST_FAILED",
|
|
459
|
+
cause: error,
|
|
460
|
+
logger: this.logger
|
|
461
|
+
});
|
|
462
|
+
this.telemetry?.emit("igniter.mail.templates.list.error", {
|
|
463
|
+
level: "error",
|
|
464
|
+
attributes: {
|
|
465
|
+
"ctx.mail.error.code": normalizedError.code,
|
|
466
|
+
"ctx.mail.error.message": normalizedError.message,
|
|
467
|
+
"ctx.mail.duration_ms": Date.now() - startTime
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
this.logger?.error("IgniterMail.templates.list failed", normalizedError);
|
|
471
|
+
throw normalizedError;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
async getTemplate(id) {
|
|
475
|
+
const startTime = Date.now();
|
|
476
|
+
this.logger?.debug("IgniterMail.templates.get started", {
|
|
477
|
+
template: String(id)
|
|
478
|
+
});
|
|
479
|
+
this.telemetry?.emit("igniter.mail.templates.get.started", {
|
|
480
|
+
level: "debug",
|
|
481
|
+
attributes: {
|
|
482
|
+
"ctx.mail.template_id": String(id)
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
try {
|
|
486
|
+
const template = this.templateRegistry[id];
|
|
487
|
+
if (!template) {
|
|
488
|
+
this.telemetry?.emit("igniter.mail.templates.get.success", {
|
|
489
|
+
level: "info",
|
|
490
|
+
attributes: {
|
|
491
|
+
"ctx.mail.template_id": String(id),
|
|
492
|
+
"ctx.mail.duration_ms": Date.now() - startTime
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
const result = this.buildTemplateMeta(String(id), template);
|
|
498
|
+
this.telemetry?.emit("igniter.mail.templates.get.success", {
|
|
499
|
+
level: "info",
|
|
500
|
+
attributes: {
|
|
501
|
+
"ctx.mail.template_id": String(id),
|
|
502
|
+
"ctx.mail.duration_ms": Date.now() - startTime
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
return result;
|
|
506
|
+
} catch (error) {
|
|
507
|
+
const normalizedError = IgniterMailError.is(error) ? error : new IgniterMailError({
|
|
508
|
+
code: "MAIL_PROVIDER_TEMPLATE_GET_FAILED",
|
|
509
|
+
message: "MAIL_PROVIDER_TEMPLATE_GET_FAILED",
|
|
510
|
+
cause: error,
|
|
511
|
+
logger: this.logger,
|
|
512
|
+
metadata: { template: String(id) }
|
|
513
|
+
});
|
|
514
|
+
this.telemetry?.emit("igniter.mail.templates.get.error", {
|
|
515
|
+
level: "error",
|
|
516
|
+
attributes: {
|
|
517
|
+
"ctx.mail.template_id": String(id),
|
|
518
|
+
"ctx.mail.error.code": normalizedError.code,
|
|
519
|
+
"ctx.mail.error.message": normalizedError.message,
|
|
520
|
+
"ctx.mail.duration_ms": Date.now() - startTime
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
this.logger?.error("IgniterMail.templates.get failed", normalizedError);
|
|
524
|
+
throw normalizedError;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
async renderTemplate(id, variables) {
|
|
528
|
+
const startTime = Date.now();
|
|
529
|
+
this.logger?.debug("IgniterMail.templates.render started", {
|
|
530
|
+
template: String(id)
|
|
531
|
+
});
|
|
532
|
+
this.telemetry?.emit("igniter.mail.templates.render.started", {
|
|
533
|
+
level: "debug",
|
|
534
|
+
attributes: {
|
|
535
|
+
"ctx.mail.template_id": String(id)
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
try {
|
|
539
|
+
const template = this.templateRegistry[id];
|
|
540
|
+
if (!template) {
|
|
541
|
+
throw new IgniterMailError({
|
|
542
|
+
code: "MAIL_PROVIDER_TEMPLATE_NOT_FOUND",
|
|
543
|
+
message: "MAIL_PROVIDER_TEMPLATE_NOT_FOUND",
|
|
544
|
+
logger: this.logger,
|
|
545
|
+
metadata: { template: String(id) }
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
const validatedData = await this.validateTemplateData(
|
|
549
|
+
template,
|
|
550
|
+
variables ?? {}
|
|
551
|
+
);
|
|
552
|
+
const MailTemplate = template.render;
|
|
553
|
+
const html = await components.render(
|
|
554
|
+
/* @__PURE__ */ React__default.default.createElement(MailTemplate, { ...validatedData })
|
|
555
|
+
);
|
|
556
|
+
const text = await components.render(
|
|
557
|
+
/* @__PURE__ */ React__default.default.createElement(MailTemplate, { ...validatedData }),
|
|
558
|
+
{ plainText: true }
|
|
559
|
+
);
|
|
560
|
+
this.telemetry?.emit("igniter.mail.templates.render.success", {
|
|
561
|
+
level: "info",
|
|
562
|
+
attributes: {
|
|
563
|
+
"ctx.mail.template_id": String(id),
|
|
564
|
+
"ctx.mail.duration_ms": Date.now() - startTime
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
this.logger?.info("IgniterMail.templates.render success", {
|
|
568
|
+
template: String(id),
|
|
569
|
+
durationMs: Date.now() - startTime
|
|
570
|
+
});
|
|
571
|
+
return { html, text };
|
|
572
|
+
} catch (error) {
|
|
573
|
+
const normalizedError = IgniterMailError.is(error) ? error : new IgniterMailError({
|
|
574
|
+
code: "MAIL_PROVIDER_TEMPLATE_RENDER_FAILED",
|
|
575
|
+
message: "MAIL_PROVIDER_TEMPLATE_RENDER_FAILED",
|
|
576
|
+
cause: error,
|
|
577
|
+
logger: this.logger,
|
|
578
|
+
metadata: { template: String(id) }
|
|
579
|
+
});
|
|
580
|
+
this.telemetry?.emit("igniter.mail.templates.render.error", {
|
|
581
|
+
level: "error",
|
|
582
|
+
attributes: {
|
|
583
|
+
"ctx.mail.template_id": String(id),
|
|
584
|
+
"ctx.mail.error.code": normalizedError.code,
|
|
585
|
+
"ctx.mail.error.message": normalizedError.message,
|
|
586
|
+
"ctx.mail.duration_ms": Date.now() - startTime
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
this.logger?.error("IgniterMail.templates.render failed", normalizedError);
|
|
590
|
+
throw normalizedError;
|
|
591
|
+
}
|
|
410
592
|
}
|
|
411
593
|
async ensureQueueJobRegistered() {
|
|
412
594
|
const queue = this.queue;
|
|
@@ -477,7 +659,7 @@ var IgniterMailManagerCore = class {
|
|
|
477
659
|
}
|
|
478
660
|
});
|
|
479
661
|
await this.onSendStarted(params);
|
|
480
|
-
const template = this.
|
|
662
|
+
const template = this.templateRegistry[params.template];
|
|
481
663
|
if (!template) {
|
|
482
664
|
throw new IgniterMailError({
|
|
483
665
|
code: "MAIL_PROVIDER_TEMPLATE_NOT_FOUND",
|