@k-msg/template 0.1.1 → 0.1.3
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/README.md +11 -15
- package/dist/builder/template.builder.d.ts +139 -0
- package/dist/index.d.ts +12 -461
- package/dist/index.js +38 -1274
- package/dist/index.js.map +98 -1
- package/dist/index.mjs +43 -0
- package/dist/index.mjs.map +98 -0
- package/dist/interpolator.d.ts +8 -0
- package/dist/parser/button.parser.d.ts +25 -0
- package/dist/parser/validator.d.ts +24 -0
- package/dist/parser/variable.parser.d.ts +27 -0
- package/dist/registry/template.registry.d.ts +168 -0
- package/dist/service.d.ts +14 -0
- package/dist/services/template.service.d.ts +10 -0
- package/dist/types/template.types.d.ts +150 -0
- package/package.json +18 -12
- package/dist/index.cjs +0 -1315
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -463
package/dist/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/parser/variable.parser.ts","../src/types/template.types.ts","../src/parser/button.parser.ts","../src/parser/validator.ts","../src/services/template.service.ts","../src/builder/template.builder.ts","../src/registry/template.registry.ts"],"sourcesContent":["/**\n * Template Engine\n * 템플릿 파싱, 변수 치환, 검증 기능 제공\n */\n\n// 핵심 서비스\nexport { TemplateService } from './services/template.service';\n\n// 파서 및 유틸리티\nexport { VariableParser } from './parser/variable.parser';\nexport { ButtonParser } from './parser/button.parser';\nexport { TemplateValidator, type ValidationResult } from './parser/validator';\n\n// Template Builder\nexport { TemplateBuilder, TemplateBuilders } from './builder/template.builder';\n\n// Template Registry\nexport { \n TemplateRegistry,\n type TemplateSearchFilters,\n type TemplateSearchOptions,\n type TemplateSearchResult,\n type TemplateVersion,\n type TemplateHistory,\n type TemplateUsageStats,\n type TemplateRegistryOptions\n} from './registry/template.registry';\n\n// 타입 정의\nexport type {\n AlimTalkTemplate,\n TemplateVariable,\n TemplateButton\n} from './types/template.types';\n\n// Enum 정의\nexport { TemplateType, TemplateCategory, TemplateStatus } from './types/template.types';","import { TemplateVariable } from '../types/template.types';\n\nexport class VariableParser {\n private static readonly VARIABLE_PATTERN = /#{([^}]+)}/g;\n\n /**\n * 템플릿 내용에서 변수를 추출합니다\n */\n static extractVariables(content: string): string[] {\n const variables: string[] = [];\n const matches = content.matchAll(this.VARIABLE_PATTERN);\n \n for (const match of matches) {\n const variableName = match[1].trim();\n if (variableName && !variables.includes(variableName)) {\n variables.push(variableName);\n }\n }\n \n return variables;\n }\n\n /**\n * 템플릿 내용의 변수를 실제 값으로 치환합니다\n */\n static replaceVariables(\n content: string,\n variables: Record<string, string | number | Date>\n ): string {\n return content.replace(this.VARIABLE_PATTERN, (match, variableName) => {\n const value = variables[variableName.trim()];\n \n if (value === undefined || value === null) {\n return match; // 값이 없으면 원래 변수 그대로 유지\n }\n \n if (value instanceof Date) {\n return value.toISOString();\n }\n \n return String(value);\n });\n }\n\n /**\n * 변수 정의와 실제 제공된 값을 검증합니다\n */\n static validateVariables(\n variableDefinitions: TemplateVariable[],\n providedVariables: Record<string, any>\n ): { isValid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n for (const definition of variableDefinitions) {\n const value = providedVariables[definition.name];\n\n // 필수 변수 체크\n if (definition.required && (value === undefined || value === null)) {\n errors.push(`Required variable '${definition.name}' is missing`);\n continue;\n }\n\n // 값이 없으면 옵셔널 변수로 간주하고 다음으로\n if (value === undefined || value === null) {\n continue;\n }\n\n // 타입 검증\n if (!this.validateVariableType(value, definition.type)) {\n errors.push(`Variable '${definition.name}' has invalid type. Expected: ${definition.type}`);\n }\n\n // 길이 검증\n if (definition.maxLength && String(value).length > definition.maxLength) {\n errors.push(`Variable '${definition.name}' exceeds maximum length of ${definition.maxLength}`);\n }\n\n // 포맷 검증 (정규식)\n if (definition.format && !new RegExp(definition.format).test(String(value))) {\n errors.push(`Variable '${definition.name}' does not match required format: ${definition.format}`);\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors\n };\n }\n\n private static validateVariableType(value: any, expectedType: string): boolean {\n switch (expectedType) {\n case 'string':\n return typeof value === 'string';\n case 'number':\n return typeof value === 'number' && !isNaN(value);\n case 'date':\n return value instanceof Date || !isNaN(Date.parse(value));\n case 'custom':\n return true; // 커스텀 타입은 별도 검증 로직 필요\n default:\n return false;\n }\n }\n\n /**\n * 템플릿에서 사용된 변수와 정의된 변수의 일치성을 검사합니다\n */\n static validateTemplateVariables(\n content: string,\n variableDefinitions: TemplateVariable[]\n ): { isValid: boolean; errors: string[] } {\n const usedVariables = this.extractVariables(content);\n const definedVariables = variableDefinitions.map(v => v.name);\n const errors: string[] = [];\n\n // 사용된 변수가 정의되어 있는지 확인\n for (const usedVar of usedVariables) {\n if (!definedVariables.includes(usedVar)) {\n errors.push(`Variable '${usedVar}' is used in template but not defined`);\n }\n }\n\n // 정의된 필수 변수가 템플릿에서 사용되는지 확인\n for (const definition of variableDefinitions) {\n if (definition.required && !usedVariables.includes(definition.name)) {\n errors.push(`Required variable '${definition.name}' is defined but not used in template`);\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors\n };\n }\n}","import { z } from 'zod';\n\nexport enum TemplateType {\n ALIMTALK = 'ALIMTALK',\n SMS = 'SMS', \n LMS = 'LMS',\n MMS = 'MMS',\n RCS = 'RCS'\n}\n\nexport enum TemplateCategory {\n AUTHENTICATION = 'AUTHENTICATION', // 인증\n NOTIFICATION = 'NOTIFICATION', // 알림\n PROMOTION = 'PROMOTION', // 프로모션\n INFORMATION = 'INFORMATION', // 정보성\n RESERVATION = 'RESERVATION', // 예약\n SHIPPING = 'SHIPPING', // 배송\n PAYMENT = 'PAYMENT' // 결제\n}\n\nexport enum TemplateStatus {\n DRAFT = 'DRAFT', // 초안\n PENDING = 'PENDING', // 검수 중\n APPROVED = 'APPROVED', // 승인됨\n REJECTED = 'REJECTED', // 반려됨\n DISABLED = 'DISABLED' // 비활성화\n}\n\nexport interface TemplateVariable {\n name: string; // 변수명 (#{name} 형식)\n type: 'string' | 'number' | 'date' | 'custom';\n required: boolean;\n maxLength?: number;\n format?: string; // 날짜 포맷 등\n description?: string;\n example?: string;\n}\n\nexport interface TemplateButton {\n type: 'WL' | 'AL' | 'DS' | 'BK' | 'MD';\n name: string;\n linkMobile?: string;\n linkPc?: string;\n linkIos?: string;\n linkAndroid?: string;\n schemeIos?: string;\n schemeAndroid?: string;\n}\n\nexport interface AlimTalkTemplate {\n id: string;\n code: string; // 프로바이더 템플릿 코드\n name: string;\n content: string; // #{변수} 포함 내용\n variables: TemplateVariable[]; // 변수 정의\n buttons?: TemplateButton[]; // 버튼 정의\n category: TemplateCategory; // 인증, 알림, 프로모션 등\n status: TemplateStatus; // 승인, 검수중, 반려\n provider: string; // 프로바이더 ID\n metadata: {\n createdAt: Date;\n updatedAt: Date;\n approvedAt?: Date;\n rejectedAt?: Date;\n rejectionReason?: string;\n usage: {\n sent: number;\n delivered: number;\n failed: number;\n };\n };\n}\n\n// Zod schemas\nexport const TemplateVariableSchema = z.object({\n name: z.string().min(1),\n type: z.enum(['string', 'number', 'date', 'custom']),\n required: z.boolean(),\n maxLength: z.number().optional(),\n format: z.string().optional(),\n description: z.string().optional(),\n example: z.string().optional(),\n});\n\nexport const TemplateButtonSchema = z.object({\n type: z.enum(['WL', 'AL', 'DS', 'BK', 'MD']),\n name: z.string().min(1),\n linkMobile: z.string().url().optional(),\n linkPc: z.string().url().optional(),\n linkIos: z.string().url().optional(),\n linkAndroid: z.string().url().optional(),\n schemeIos: z.string().optional(),\n schemeAndroid: z.string().optional(),\n});\n\nexport const AlimTalkTemplateSchema = z.object({\n id: z.string(),\n code: z.string(),\n name: z.string().min(1),\n content: z.string().min(1),\n variables: z.array(TemplateVariableSchema),\n buttons: z.array(TemplateButtonSchema).optional(),\n category: z.nativeEnum(TemplateCategory),\n status: z.nativeEnum(TemplateStatus),\n provider: z.string(),\n metadata: z.object({\n createdAt: z.date(),\n updatedAt: z.date(),\n approvedAt: z.date().optional(),\n rejectedAt: z.date().optional(),\n rejectionReason: z.string().optional(),\n usage: z.object({\n sent: z.number().min(0),\n delivered: z.number().min(0),\n failed: z.number().min(0),\n }),\n }),\n});\n\nexport type AlimTalkTemplateType = z.infer<typeof AlimTalkTemplateSchema>;\nexport type TemplateVariableType = z.infer<typeof TemplateVariableSchema>;\nexport type TemplateButtonType = z.infer<typeof TemplateButtonSchema>;","import { TemplateButton } from '../types/template.types';\n\nexport class ButtonParser {\n /**\n * 버튼 설정의 유효성을 검증합니다\n */\n static validateButtons(buttons: TemplateButton[]): { isValid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n if (buttons.length > 5) {\n errors.push('Maximum 5 buttons are allowed');\n }\n\n for (let i = 0; i < buttons.length; i++) {\n const button = buttons[i];\n const buttonIndex = i + 1;\n\n // 버튼 이름 검증\n if (!button.name || button.name.trim().length === 0) {\n errors.push(`Button ${buttonIndex}: name is required`);\n } else if (button.name.length > 14) {\n errors.push(`Button ${buttonIndex}: name cannot exceed 14 characters`);\n }\n\n // 버튼 타입별 검증\n this.validateButtonByType(button, buttonIndex, errors);\n }\n\n return {\n isValid: errors.length === 0,\n errors\n };\n }\n\n private static validateButtonByType(\n button: TemplateButton,\n buttonIndex: number,\n errors: string[]\n ): void {\n switch (button.type) {\n case 'WL': // 웹링크\n this.validateWebLinkButton(button, buttonIndex, errors);\n break;\n case 'AL': // 앱링크\n this.validateAppLinkButton(button, buttonIndex, errors);\n break;\n case 'DS': // 배송조회\n this.validateDeliveryButton(button, buttonIndex, errors);\n break;\n case 'BK': // 봇키워드\n this.validateBotKeywordButton(button, buttonIndex, errors);\n break;\n case 'MD': // 메시지전달\n this.validateMessageDeliveryButton(button, buttonIndex, errors);\n break;\n default:\n errors.push(`Button ${buttonIndex}: invalid button type '${button.type}'`);\n }\n }\n\n private static validateWebLinkButton(\n button: TemplateButton,\n buttonIndex: number,\n errors: string[]\n ): void {\n if (!button.linkMobile && !button.linkPc) {\n errors.push(`Button ${buttonIndex}: web link button must have at least mobile or PC link`);\n }\n\n if (button.linkMobile && !this.isValidUrl(button.linkMobile)) {\n errors.push(`Button ${buttonIndex}: invalid mobile link URL`);\n }\n\n if (button.linkPc && !this.isValidUrl(button.linkPc)) {\n errors.push(`Button ${buttonIndex}: invalid PC link URL`);\n }\n }\n\n private static validateAppLinkButton(\n button: TemplateButton,\n buttonIndex: number,\n errors: string[]\n ): void {\n const hasAnyLink = button.linkIos || button.linkAndroid || \n button.schemeIos || button.schemeAndroid;\n\n if (!hasAnyLink) {\n errors.push(`Button ${buttonIndex}: app link button must have at least one app link or scheme`);\n }\n\n if (button.linkIos && !this.isValidUrl(button.linkIos)) {\n errors.push(`Button ${buttonIndex}: invalid iOS link URL`);\n }\n\n if (button.linkAndroid && !this.isValidUrl(button.linkAndroid)) {\n errors.push(`Button ${buttonIndex}: invalid Android link URL`);\n }\n }\n\n private static validateDeliveryButton(\n button: TemplateButton,\n buttonIndex: number,\n errors: string[]\n ): void {\n // 배송조회 버튼은 특별한 검증 로직이 필요할 수 있음\n // 현재는 기본 검증만 수행\n }\n\n private static validateBotKeywordButton(\n button: TemplateButton,\n buttonIndex: number,\n errors: string[]\n ): void {\n // 봇키워드 버튼은 특별한 검증 로직이 필요할 수 있음\n // 현재는 기본 검증만 수행\n }\n\n private static validateMessageDeliveryButton(\n button: TemplateButton,\n buttonIndex: number,\n errors: string[]\n ): void {\n // 메시지전달 버튼은 특별한 검증 로직이 필요할 수 있음\n // 현재는 기본 검증만 수행\n }\n\n private static isValidUrl(url: string): boolean {\n try {\n new URL(url);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * 버튼을 JSON 문자열로 직렬화합니다 (카카오 API 형식)\n */\n static serializeButtons(buttons: TemplateButton[]): string {\n const serializedButtons = buttons.map(button => ({\n name: button.name,\n type: button.type,\n url_mobile: button.linkMobile,\n url_pc: button.linkPc,\n scheme_ios: button.schemeIos,\n scheme_android: button.schemeAndroid,\n }));\n\n return JSON.stringify(serializedButtons);\n }\n\n /**\n * JSON 문자열에서 버튼 배열로 역직렬화합니다\n */\n static deserializeButtons(buttonsJson: string): TemplateButton[] {\n try {\n const parsed = JSON.parse(buttonsJson);\n \n return parsed.map((button: any) => ({\n name: button.name,\n type: button.type,\n linkMobile: button.url_mobile,\n linkPc: button.url_pc,\n linkIos: button.url_ios,\n linkAndroid: button.url_android,\n schemeIos: button.scheme_ios,\n schemeAndroid: button.scheme_android,\n }));\n } catch (error) {\n throw new Error(`Failed to parse buttons JSON: ${error}`);\n }\n }\n}","import { AlimTalkTemplate, TemplateCategory } from '../types/template.types';\nimport { VariableParser } from './variable.parser';\nimport { ButtonParser } from './button.parser';\n\nexport interface ValidationResult {\n isValid: boolean;\n errors: string[];\n warnings: string[];\n}\n\nexport class TemplateValidator {\n /**\n * 알림톡 템플릿의 전체적인 유효성을 검증합니다\n */\n static validate(template: AlimTalkTemplate): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // 기본 필드 검증\n this.validateBasicFields(template, errors);\n\n // 내용 검증\n this.validateContent(template, errors, warnings);\n\n // 변수 검증\n const variableValidation = VariableParser.validateTemplateVariables(\n template.content,\n template.variables\n );\n errors.push(...variableValidation.errors);\n\n // 버튼 검증\n if (template.buttons && template.buttons.length > 0) {\n const buttonValidation = ButtonParser.validateButtons(template.buttons);\n errors.push(...buttonValidation.errors);\n }\n\n // 카테고리별 특수 검증\n this.validateByCategory(template, errors, warnings);\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings\n };\n }\n\n private static validateBasicFields(template: AlimTalkTemplate, errors: string[]): void {\n if (!template.name || template.name.trim().length === 0) {\n errors.push('Template name is required');\n }\n\n if (!template.code || template.code.trim().length === 0) {\n errors.push('Template code is required');\n }\n\n if (!template.provider || template.provider.trim().length === 0) {\n errors.push('Provider is required');\n }\n }\n\n private static validateContent(\n template: AlimTalkTemplate,\n errors: string[],\n warnings: string[]\n ): void {\n if (!template.content || template.content.trim().length === 0) {\n errors.push('Template content is required');\n return;\n }\n\n const content = template.content;\n\n // 길이 검증 (카카오 알림톡 제한)\n if (content.length > 1000) {\n errors.push('Template content cannot exceed 1000 characters');\n }\n\n // 특수 문자 검증\n if (this.containsProhibitedCharacters(content)) {\n errors.push('Template content contains prohibited characters');\n }\n\n // 줄바꿈 검증 (너무 많은 줄바꿈)\n const lineBreaks = (content.match(/\\n/g) || []).length;\n if (lineBreaks > 20) {\n warnings.push('Template content has many line breaks, which may affect readability');\n }\n\n // URL 검증\n this.validateUrlsInContent(content, warnings);\n }\n\n private static containsProhibitedCharacters(content: string): boolean {\n // 카카오에서 금지하는 특수 문자들 (예시)\n const prohibitedChars = /[<>]/;\n return prohibitedChars.test(content);\n }\n\n private static validateUrlsInContent(content: string, warnings: string[]): void {\n const urlPattern = /https?:\\/\\/[^\\s]+/g;\n const urls = content.match(urlPattern) || [];\n\n for (const url of urls) {\n try {\n new URL(url);\n } catch {\n warnings.push(`Invalid URL found in content: ${url}`);\n }\n }\n }\n\n private static validateByCategory(\n template: AlimTalkTemplate,\n errors: string[],\n warnings: string[]\n ): void {\n switch (template.category) {\n case TemplateCategory.AUTHENTICATION:\n this.validateAuthenticationTemplate(template, errors, warnings);\n break;\n case TemplateCategory.PROMOTION:\n this.validatePromotionTemplate(template, errors, warnings);\n break;\n case TemplateCategory.PAYMENT:\n this.validatePaymentTemplate(template, errors, warnings);\n break;\n // 다른 카테고리들도 필요에 따라 추가\n }\n }\n\n private static validateAuthenticationTemplate(\n template: AlimTalkTemplate,\n errors: string[],\n warnings: string[]\n ): void {\n // 인증 템플릿은 일반적으로 인증번호 변수를 포함해야 함\n const hasAuthCode = template.variables.some(v => \n v.name.includes('인증') || v.name.includes('코드') || v.name.includes('번호')\n );\n\n if (!hasAuthCode) {\n warnings.push('Authentication template should include an authentication code variable');\n }\n\n // 인증 템플릿은 일반적으로 버튼이 없어야 함\n if (template.buttons && template.buttons.length > 0) {\n warnings.push('Authentication templates typically should not have buttons');\n }\n }\n\n private static validatePromotionTemplate(\n template: AlimTalkTemplate,\n errors: string[],\n warnings: string[]\n ): void {\n // 프로모션 템플릿은 일반적으로 버튼을 포함해야 함\n if (!template.buttons || template.buttons.length === 0) {\n warnings.push('Promotion templates typically should have action buttons');\n }\n }\n\n private static validatePaymentTemplate(\n template: AlimTalkTemplate,\n errors: string[],\n warnings: string[]\n ): void {\n // 결제 템플릿은 금액 관련 변수를 포함해야 함\n const hasAmountVariable = template.variables.some(v => \n v.name.includes('금액') || v.name.includes('가격') || v.name.includes('원')\n );\n\n if (!hasAmountVariable) {\n warnings.push('Payment template should include an amount variable');\n }\n }\n\n /**\n * 빠른 검증 - 기본적인 필수 필드만 검사\n */\n static quickValidate(template: Partial<AlimTalkTemplate>): ValidationResult {\n const errors: string[] = [];\n\n if (!template.name) errors.push('Name is required');\n if (!template.content) errors.push('Content is required');\n if (!template.category) errors.push('Category is required');\n if (!template.provider) errors.push('Provider is required');\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings: []\n };\n }\n}","import type { AlimTalkTemplate, TemplateVariable, TemplateCategory, TemplateStatus } from '../types/template.types';\nimport { VariableParser } from '../parser/variable.parser';\nimport { TemplateValidator } from '../parser/validator';\n\nexport class TemplateService {\n private templates: Map<string, AlimTalkTemplate> = new Map();\n\n async createTemplate(template: Omit<AlimTalkTemplate, 'id' | 'metadata'>): Promise<AlimTalkTemplate> {\n const variables = VariableParser.extractVariables(template.content);\n \n const newTemplate: AlimTalkTemplate = {\n ...template,\n id: this.generateTemplateId(),\n variables: variables.map(name => ({\n name,\n type: 'string',\n required: true,\n })),\n metadata: {\n createdAt: new Date(),\n updatedAt: new Date(),\n usage: { sent: 0, delivered: 0, failed: 0 },\n },\n };\n\n // 템플릿 유효성 검사\n const validation = TemplateValidator.validate(newTemplate);\n if (!validation.isValid) {\n throw new Error(`Template validation failed: ${validation.errors.join(', ')}`);\n }\n\n this.templates.set(newTemplate.id, newTemplate);\n return newTemplate;\n }\n\n async getTemplate(templateId: string): Promise<AlimTalkTemplate | null> {\n return this.templates.get(templateId) || null;\n }\n\n async updateTemplate(templateId: string, updates: Partial<AlimTalkTemplate>): Promise<AlimTalkTemplate> {\n const template = this.templates.get(templateId);\n if (!template) {\n throw new Error(`Template ${templateId} not found`);\n }\n\n const updatedTemplate = {\n ...template,\n ...updates,\n metadata: {\n ...template.metadata,\n updatedAt: new Date(),\n },\n };\n\n this.templates.set(templateId, updatedTemplate);\n return updatedTemplate;\n }\n\n async deleteTemplate(templateId: string): Promise<void> {\n this.templates.delete(templateId);\n }\n\n async renderTemplate(templateId: string, variables: Record<string, any>): Promise<string> {\n const template = this.templates.get(templateId);\n if (!template) {\n throw new Error(`Template ${templateId} not found`);\n }\n\n // 변수 검증\n const validation = VariableParser.validateVariables(template.variables, variables);\n if (!validation.isValid) {\n throw new Error(`Variable validation failed: ${validation.errors.join(', ')}`);\n }\n\n return VariableParser.replaceVariables(template.content, variables);\n }\n\n private generateTemplateId(): string {\n return `tpl_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n}","/**\n * Template Builder - Fluent API for creating AlimTalk templates\n */\n\nimport {\n AlimTalkTemplate,\n TemplateVariable,\n TemplateButton,\n TemplateCategory,\n TemplateStatus\n} from '../types/template.types';\nimport { VariableParser } from '../parser/variable.parser';\nimport { TemplateValidator } from '../parser/validator';\n\nexport class TemplateBuilder {\n private template: Partial<AlimTalkTemplate> = {\n variables: [],\n buttons: [],\n status: TemplateStatus.DRAFT,\n metadata: {\n createdAt: new Date(),\n updatedAt: new Date(),\n usage: { sent: 0, delivered: 0, failed: 0 }\n }\n };\n\n /**\n * Set template name\n */\n name(name: string): TemplateBuilder {\n this.template.name = name;\n return this;\n }\n\n /**\n * Set template code (provider specific)\n */\n code(code: string): TemplateBuilder {\n this.template.code = code;\n return this;\n }\n\n /**\n * Set template content with variables\n */\n content(content: string): TemplateBuilder {\n this.template.content = content;\n\n // Auto-extract variables from content\n const extractedVariables = VariableParser.extractVariables(content);\n const existingVariableNames = (this.template.variables || []).map(v => v.name);\n\n // Add newly found variables as string type by default\n for (const varName of extractedVariables) {\n if (!existingVariableNames.includes(varName)) {\n this.variable(varName, 'string', true);\n }\n }\n\n return this;\n }\n\n /**\n * Set template category\n */\n category(category: TemplateCategory): TemplateBuilder {\n this.template.category = category;\n return this;\n }\n\n /**\n * Set template provider\n */\n provider(provider: string): TemplateBuilder {\n this.template.provider = provider;\n return this;\n }\n\n /**\n * Set template status\n */\n status(status: TemplateStatus): TemplateBuilder {\n this.template.status = status;\n return this;\n }\n\n /**\n * Add a variable definition\n */\n variable(\n name: string,\n type: 'string' | 'number' | 'date' | 'custom' = 'string',\n required: boolean = true,\n options: {\n maxLength?: number;\n format?: string;\n description?: string;\n example?: string;\n } = {}\n ): TemplateBuilder {\n if (!this.template.variables) {\n this.template.variables = [];\n }\n\n // Remove existing variable with same name\n this.template.variables = this.template.variables.filter(v => v.name !== name);\n\n const variable: TemplateVariable = {\n name,\n type,\n required,\n ...options\n };\n\n this.template.variables.push(variable);\n return this;\n }\n\n /**\n * Add multiple variables at once\n */\n variables(variables: Array<{\n name: string;\n type?: 'string' | 'number' | 'date' | 'custom';\n required?: boolean;\n maxLength?: number;\n format?: string;\n description?: string;\n example?: string;\n }>): TemplateBuilder {\n for (const variable of variables) {\n this.variable(\n variable.name,\n variable.type || 'string',\n variable.required ?? true,\n {\n maxLength: variable.maxLength,\n format: variable.format,\n description: variable.description,\n example: variable.example\n }\n );\n }\n return this;\n }\n\n /**\n * Add a web link button\n */\n webLinkButton(\n name: string,\n mobileUrl?: string,\n pcUrl?: string\n ): TemplateBuilder {\n return this.button({\n type: 'WL',\n name,\n linkMobile: mobileUrl,\n linkPc: pcUrl\n });\n }\n\n /**\n * Add an app link button\n */\n appLinkButton(\n name: string,\n options: {\n iosUrl?: string;\n androidUrl?: string;\n iosScheme?: string;\n androidScheme?: string;\n }\n ): TemplateBuilder {\n return this.button({\n type: 'AL',\n name,\n linkIos: options.iosUrl,\n linkAndroid: options.androidUrl,\n schemeIos: options.iosScheme,\n schemeAndroid: options.androidScheme\n });\n }\n\n /**\n * Add a delivery tracking button\n */\n deliveryButton(name: string): TemplateBuilder {\n return this.button({\n type: 'DS',\n name\n });\n }\n\n /**\n * Add a bot keyword button\n */\n botKeywordButton(name: string): TemplateBuilder {\n return this.button({\n type: 'BK',\n name\n });\n }\n\n /**\n * Add a message delivery button\n */\n messageDeliveryButton(name: string): TemplateBuilder {\n return this.button({\n type: 'MD',\n name\n });\n }\n\n /**\n * Add a custom button\n */\n button(button: TemplateButton): TemplateBuilder {\n if (!this.template.buttons) {\n this.template.buttons = [];\n }\n\n if (this.template.buttons.length >= 5) {\n throw new Error('Maximum 5 buttons are allowed per template');\n }\n\n this.template.buttons.push(button);\n return this;\n }\n\n /**\n * Clear all buttons\n */\n clearButtons(): TemplateBuilder {\n this.template.buttons = [];\n return this;\n }\n\n /**\n * Set template metadata\n */\n metadata(metadata: Partial<AlimTalkTemplate['metadata']>): TemplateBuilder {\n this.template.metadata = {\n ...this.template.metadata!,\n ...metadata,\n updatedAt: new Date()\n };\n return this;\n }\n\n /**\n * Validate the current template\n */\n validate(): { isValid: boolean; errors: string[]; warnings: string[] } {\n // Quick validation for required fields\n const quickValidation = TemplateValidator.quickValidate(this.template);\n if (!quickValidation.isValid) {\n return quickValidation;\n }\n\n // Full validation if template is complete enough\n try {\n const fullTemplate = this.build();\n return TemplateValidator.validate(fullTemplate);\n } catch (error) {\n return {\n isValid: false,\n errors: [error instanceof Error ? error.message : 'Unknown validation error'],\n warnings: []\n };\n }\n }\n\n /**\n * Preview the template with sample variables\n */\n preview(sampleVariables: Record<string, any> = {}): string {\n if (!this.template.content) {\n throw new Error('Template content is required for preview');\n }\n\n // Use provided sample variables or generate defaults\n const variables = { ...this.generateSampleVariables(), ...sampleVariables };\n\n return VariableParser.replaceVariables(this.template.content, variables);\n }\n\n /**\n * Generate sample variables based on variable definitions\n */\n private generateSampleVariables(): Record<string, any> {\n const samples: Record<string, any> = {};\n\n for (const variable of this.template.variables || []) {\n if (variable.example) {\n samples[variable.name] = variable.example;\n } else {\n // Generate default sample based on type\n switch (variable.type) {\n case 'string':\n samples[variable.name] = variable.name.includes('name') || variable.name.includes('이름')\n ? '홍길동'\n : variable.name.includes('code') || variable.name.includes('코드')\n ? '123456'\n : `샘플${variable.name}`;\n break;\n case 'number':\n samples[variable.name] = variable.name.includes('amount') || variable.name.includes('금액')\n ? 10000\n : variable.name.includes('count') || variable.name.includes('개수')\n ? 1\n : 123;\n break;\n case 'date':\n samples[variable.name] = new Date();\n break;\n default:\n samples[variable.name] = `샘플값`;\n }\n }\n }\n\n return samples;\n }\n\n /**\n * Clone the current builder\n */\n clone(): TemplateBuilder {\n const cloned = new TemplateBuilder();\n cloned.template = JSON.parse(JSON.stringify(this.template));\n return cloned;\n }\n\n /**\n * Reset the builder to start fresh\n */\n reset(): TemplateBuilder {\n this.template = {\n variables: [],\n buttons: [],\n status: TemplateStatus.DRAFT,\n metadata: {\n createdAt: new Date(),\n updatedAt: new Date(),\n usage: { sent: 0, delivered: 0, failed: 0 }\n }\n };\n return this;\n }\n\n /**\n * Build the final template\n */\n build(): AlimTalkTemplate {\n // Validate required fields\n if (!this.template.name) throw new Error('Template name is required');\n if (!this.template.code) throw new Error('Template code is required');\n if (!this.template.content) throw new Error('Template content is required');\n if (!this.template.category) throw new Error('Template category is required');\n if (!this.template.provider) throw new Error('Template provider is required');\n\n const template: AlimTalkTemplate = {\n id: this.template.id || this.generateTemplateId(),\n name: this.template.name,\n code: this.template.code,\n content: this.template.content,\n variables: this.template.variables || [],\n buttons: this.template.buttons,\n category: this.template.category,\n status: this.template.status || TemplateStatus.DRAFT,\n provider: this.template.provider,\n metadata: {\n ...this.template.metadata!,\n updatedAt: new Date()\n }\n };\n\n // Final validation\n const validation = TemplateValidator.validate(template);\n if (!validation.isValid) {\n throw new Error(`Template validation failed: ${validation.errors.join(', ')}`);\n }\n\n return template;\n }\n\n private generateTemplateId(): string {\n return `tpl_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n}\n\n/**\n * Static factory methods for common template types\n */\nexport const TemplateBuilders = {\n /**\n * Create an authentication template builder\n */\n authentication(name: string, provider: string): TemplateBuilder {\n return new TemplateBuilder()\n .name(name)\n .category(TemplateCategory.AUTHENTICATION)\n .provider(provider)\n .variable('code', 'string', true, {\n maxLength: 10,\n description: 'Authentication code',\n example: '123456'\n });\n },\n\n /**\n * Create a notification template builder\n */\n notification(name: string, provider: string): TemplateBuilder {\n return new TemplateBuilder()\n .name(name)\n .category(TemplateCategory.NOTIFICATION)\n .provider(provider)\n .variable('name', 'string', true, {\n description: 'Recipient name',\n example: '홍길동'\n });\n },\n\n /**\n * Create a promotion template builder\n */\n promotion(name: string, provider: string): TemplateBuilder {\n return new TemplateBuilder()\n .name(name)\n .category(TemplateCategory.PROMOTION)\n .provider(provider)\n .variable('name', 'string', true, {\n description: 'Customer name',\n example: '홍길동'\n })\n .variable('discount', 'number', false, {\n description: 'Discount percentage',\n example: '20'\n });\n },\n\n /**\n * Create a payment template builder\n */\n payment(name: string, provider: string): TemplateBuilder {\n return new TemplateBuilder()\n .name(name)\n .category(TemplateCategory.PAYMENT)\n .provider(provider)\n .variable('name', 'string', true, {\n description: 'Customer name',\n example: '홍길동'\n })\n .variable('amount', 'number', true, {\n description: 'Payment amount',\n example: '10000'\n });\n }\n};","/**\n * Template Registry - Manages templates across providers and categories\n */\n\nimport { EventEmitter } from 'events';\nimport {\n AlimTalkTemplate,\n TemplateCategory,\n TemplateStatus\n} from '../types/template.types';\nimport { TemplateValidator } from '../parser/validator';\n\nexport interface TemplateSearchFilters {\n provider?: string;\n category?: TemplateCategory;\n status?: TemplateStatus;\n nameContains?: string;\n codeContains?: string;\n createdAfter?: Date;\n createdBefore?: Date;\n usageMin?: number;\n usageMax?: number;\n}\n\nexport interface TemplateSearchOptions {\n page?: number;\n limit?: number;\n sortBy?: 'name' | 'code' | 'createdAt' | 'updatedAt' | 'usage';\n sortOrder?: 'asc' | 'desc';\n}\n\nexport interface TemplateSearchResult {\n templates: AlimTalkTemplate[];\n total: number;\n page: number;\n limit: number;\n hasMore: boolean;\n}\n\nexport interface TemplateVersion {\n version: number;\n template: AlimTalkTemplate;\n changes: string[];\n createdAt: Date;\n createdBy?: string;\n}\n\nexport interface TemplateHistory {\n templateId: string;\n versions: TemplateVersion[];\n currentVersion: number;\n}\n\nexport interface TemplateUsageStats {\n templateId: string;\n totalSent: number;\n totalDelivered: number;\n totalFailed: number;\n deliveryRate: number;\n failureRate: number;\n lastUsed?: Date;\n usageByDay: Array<{\n date: string;\n sent: number;\n delivered: number;\n failed: number;\n }>;\n}\n\nexport interface TemplateRegistryOptions {\n enableVersioning: boolean;\n maxVersionsPerTemplate: number;\n enableUsageTracking: boolean;\n enableAutoBackup: boolean;\n backupInterval: number; // in milliseconds\n enableValidationOnRegister: boolean;\n}\n\nexport class TemplateRegistry extends EventEmitter {\n private templates = new Map<string, AlimTalkTemplate>();\n private templatesByCode = new Map<string, AlimTalkTemplate>();\n private templatesByProvider = new Map<string, Set<string>>();\n private templatesByCategory = new Map<TemplateCategory, Set<string>>();\n private templateHistories = new Map<string, TemplateHistory>();\n private usageStats = new Map<string, TemplateUsageStats>();\n private backupTimer?: NodeJS.Timeout;\n\n private defaultOptions: TemplateRegistryOptions = {\n enableVersioning: true,\n maxVersionsPerTemplate: 10,\n enableUsageTracking: true,\n enableAutoBackup: false,\n backupInterval: 3600000, // 1 hour\n enableValidationOnRegister: true\n };\n\n constructor(private options: Partial<TemplateRegistryOptions> = {}) {\n super();\n this.options = { ...this.defaultOptions, ...options };\n\n if (this.options.enableAutoBackup) {\n this.startAutoBackup();\n }\n }\n\n /**\n * Register a new template\n */\n async register(template: AlimTalkTemplate): Promise<void> {\n // Validate template if enabled\n if (this.options.enableValidationOnRegister) {\n const validation = TemplateValidator.validate(template);\n if (!validation.isValid) {\n throw new Error(`Template validation failed: ${validation.errors.join(', ')}`);\n }\n }\n\n // Check for duplicate codes within the same provider\n const existingTemplate = this.getByCode(template.code, template.provider);\n if (existingTemplate && existingTemplate.id !== template.id) {\n throw new Error(`Template with code '${template.code}' already exists for provider '${template.provider}'`);\n }\n\n // Store the template\n this.templates.set(template.id, template);\n this.templatesByCode.set(`${template.provider}:${template.code}`, template);\n\n // Update indexes\n this.updateIndexes(template);\n\n // Initialize version history if enabled\n if (this.options.enableVersioning) {\n this.initializeVersionHistory(template);\n }\n\n // Initialize usage tracking if enabled\n if (this.options.enableUsageTracking) {\n this.initializeUsageStats(template);\n }\n\n this.emit('template:registered', { template });\n }\n\n /**\n * Update an existing template\n */\n async update(templateId: string, updates: Partial<AlimTalkTemplate>): Promise<AlimTalkTemplate> {\n const existing = this.templates.get(templateId);\n if (!existing) {\n throw new Error(`Template ${templateId} not found`);\n }\n\n // Create updated template\n const updatedTemplate: AlimTalkTemplate = {\n ...existing,\n ...updates,\n id: templateId, // Ensure ID doesn't change\n metadata: {\n ...existing.metadata,\n ...updates.metadata,\n updatedAt: new Date()\n }\n };\n\n // Validate if enabled\n if (this.options.enableValidationOnRegister) {\n const validation = TemplateValidator.validate(updatedTemplate);\n if (!validation.isValid) {\n throw new Error(`Template validation failed: ${validation.errors.join(', ')}`);\n }\n }\n\n // Update version history if enabled\n if (this.options.enableVersioning) {\n this.addVersionToHistory(existing, updatedTemplate);\n }\n\n // Update storage and indexes\n this.templates.set(templateId, updatedTemplate);\n this.templatesByCode.set(`${updatedTemplate.provider}:${updatedTemplate.code}`, updatedTemplate);\n this.updateIndexes(updatedTemplate);\n\n this.emit('template:updated', { \n oldTemplate: existing, \n newTemplate: updatedTemplate \n });\n\n return updatedTemplate;\n }\n\n /**\n * Get template by ID\n */\n get(templateId: string): AlimTalkTemplate | null {\n return this.templates.get(templateId) || null;\n }\n\n /**\n * Get template by code and provider\n */\n getByCode(code: string, provider: string): AlimTalkTemplate | null {\n return this.templatesByCode.get(`${provider}:${code}`) || null;\n }\n\n /**\n * Search templates with filters and pagination\n */\n search(\n filters: TemplateSearchFilters = {},\n options: TemplateSearchOptions = {}\n ): TemplateSearchResult {\n let templates = Array.from(this.templates.values());\n\n // Apply filters\n if (filters.provider) {\n templates = templates.filter(t => t.provider === filters.provider);\n }\n\n if (filters.category) {\n templates = templates.filter(t => t.category === filters.category);\n }\n\n if (filters.status) {\n templates = templates.filter(t => t.status === filters.status);\n }\n\n if (filters.nameContains) {\n const searchTerm = filters.nameContains.toLowerCase();\n templates = templates.filter(t => t.name.toLowerCase().includes(searchTerm));\n }\n\n if (filters.codeContains) {\n const searchTerm = filters.codeContains.toLowerCase();\n templates = templates.filter(t => t.code.toLowerCase().includes(searchTerm));\n }\n\n if (filters.createdAfter) {\n templates = templates.filter(t => t.metadata.createdAt >= filters.createdAfter!);\n }\n\n if (filters.createdBefore) {\n templates = templates.filter(t => t.metadata.createdAt <= filters.createdBefore!);\n }\n\n if (filters.usageMin !== undefined) {\n templates = templates.filter(t => t.metadata.usage.sent >= filters.usageMin!);\n }\n\n if (filters.usageMax !== undefined) {\n templates = templates.filter(t => t.metadata.usage.sent <= filters.usageMax!);\n }\n\n // Apply sorting\n const sortBy = options.sortBy || 'createdAt';\n const sortOrder = options.sortOrder || 'desc';\n\n templates.sort((a, b) => {\n let aValue, bValue;\n\n switch (sortBy) {\n case 'name':\n aValue = a.name;\n bValue = b.name;\n break;\n case 'code':\n aValue = a.code;\n bValue = b.code;\n break;\n case 'createdAt':\n aValue = a.metadata.createdAt.getTime();\n bValue = b.metadata.createdAt.getTime();\n break;\n case 'updatedAt':\n aValue = a.metadata.updatedAt.getTime();\n bValue = b.metadata.updatedAt.getTime();\n break;\n case 'usage':\n aValue = a.metadata.usage.sent;\n bValue = b.metadata.usage.sent;\n break;\n default:\n aValue = a.metadata.createdAt.getTime();\n bValue = b.metadata.createdAt.getTime();\n }\n\n if (sortOrder === 'asc') {\n return aValue < bValue ? -1 : aValue > bValue ? 1 : 0;\n } else {\n return aValue > bValue ? -1 : aValue < bValue ? 1 : 0;\n }\n });\n\n // Apply pagination\n const page = options.page || 1;\n const limit = options.limit || 20;\n const start = (page - 1) * limit;\n const end = start + limit;\n\n const paginatedTemplates = templates.slice(start, end);\n\n return {\n templates: paginatedTemplates,\n total: templates.length,\n page,\n limit,\n hasMore: end < templates.length\n };\n }\n\n /**\n * Get templates by provider\n */\n getByProvider(provider: string): AlimTalkTemplate[] {\n const templateIds = this.templatesByProvider.get(provider) || new Set();\n return Array.from(templateIds)\n .map(id => this.templates.get(id))\n .filter((template): template is AlimTalkTemplate => template !== undefined);\n }\n\n /**\n * Get templates by category\n */\n getByCategory(category: TemplateCategory): AlimTalkTemplate[] {\n const templateIds = this.templatesByCategory.get(category) || new Set();\n return Array.from(templateIds)\n .map(id => this.templates.get(id))\n .filter((template): template is AlimTalkTemplate => template !== undefined);\n }\n\n /**\n * Delete template\n */\n async delete(templateId: string): Promise<boolean> {\n const template = this.templates.get(templateId);\n if (!template) {\n return false;\n }\n\n // Remove from all indexes\n this.templates.delete(templateId);\n this.templatesByCode.delete(`${template.provider}:${template.code}`);\n\n const providerSet = this.templatesByProvider.get(template.provider);\n if (providerSet) {\n providerSet.delete(templateId);\n if (providerSet.size === 0) {\n this.templatesByProvider.delete(template.provider);\n }\n }\n\n const categorySet = this.templatesByCategory.get(template.category);\n if (categorySet) {\n categorySet.delete(templateId);\n if (categorySet.size === 0) {\n this.templatesByCategory.delete(template.category);\n }\n }\n\n // Clean up version history and usage stats\n this.templateHistories.delete(templateId);\n this.usageStats.delete(templateId);\n\n this.emit('template:deleted', { template });\n return true;\n }\n\n /**\n * Get template version history\n */\n getHistory(templateId: string): TemplateHistory | null {\n return this.templateHistories.get(templateId) || null;\n }\n\n /**\n * Get specific template version\n */\n getVersion(templateId: string, version: number): AlimTalkTemplate | null {\n const history = this.templateHistories.get(templateId);\n if (!history) return null;\n\n const versionEntry = history.versions.find(v => v.version === version);\n return versionEntry ? versionEntry.template : null;\n }\n\n /**\n * Restore template to a specific version\n */\n async restoreVersion(templateId: string, version: number): Promise<AlimTalkTemplate> {\n const versionTemplate = this.getVersion(templateId, version);\n if (!versionTemplate) {\n throw new Error(`Version ${version} not found for template ${templateId}`);\n }\n\n // Update to the version template (this will create a new version)\n return this.update(templateId, {\n ...versionTemplate,\n metadata: {\n ...versionTemplate.metadata,\n updatedAt: new Date()\n }\n });\n }\n\n /**\n * Get template usage statistics\n */\n getUsageStats(templateId: string): TemplateUsageStats | null {\n return this.usageStats.get(templateId) || null;\n }\n\n /**\n * Update template usage statistics\n */\n updateUsageStats(\n templateId: string,\n stats: {\n sent?: number;\n delivered?: number;\n failed?: number;\n }\n ): void {\n const template = this.templates.get(templateId);\n if (!template) return;\n\n // Update template metadata\n if (stats.sent) template.metadata.usage.sent += stats.sent;\n if (stats.delivered) template.metadata.usage.delivered += stats.delivered;\n if (stats.failed) template.metadata.usage.failed += stats.failed;\n\n // Update usage stats if tracking is enabled\n if (this.options.enableUsageTracking) {\n const usageStats = this.usageStats.get(templateId);\n if (usageStats) {\n if (stats.sent) usageStats.totalSent += stats.sent;\n if (stats.delivered) usageStats.totalDelivered += stats.delivered;\n if (stats.failed) usageStats.totalFailed += stats.failed;\n\n usageStats.deliveryRate = usageStats.totalSent > 0 \n ? (usageStats.totalDelivered / usageStats.totalSent) * 100 \n : 0;\n usageStats.failureRate = usageStats.totalSent > 0 \n ? (usageStats.totalFailed / usageStats.totalSent) * 100 \n : 0;\n usageStats.lastUsed = new Date();\n\n // Update daily stats\n const today = new Date().toISOString().split('T')[0];\n let todayStats = usageStats.usageByDay.find(d => d.date === today);\n \n if (!todayStats) {\n todayStats = { date: today, sent: 0, delivered: 0, failed: 0 };\n usageStats.usageByDay.push(todayStats);\n \n // Keep only last 30 days\n usageStats.usageByDay = usageStats.usageByDay\n .sort((a, b) => b.date.localeCompare(a.date))\n .slice(0, 30);\n }\n\n if (stats.sent) todayStats.sent += stats.sent;\n if (stats.delivered) todayStats.delivered += stats.delivered;\n if (stats.failed) todayStats.failed += stats.failed;\n }\n }\n\n this.emit('usage:updated', { templateId, stats });\n }\n\n /**\n * Get registry statistics\n */\n getStats(): {\n totalTemplates: number;\n byProvider: Record<string, number>;\n byCategory: Record<string, number>;\n byStatus: Record<string, number>;\n } {\n const templates = Array.from(this.templates.values());\n\n const byProvider: Record<string, number> = {};\n const byCategory: Record<string, number> = {};\n const byStatus: Record<string, number> = {};\n\n for (const template of templates) {\n byProvider[template.provider] = (byProvider[template.provider] || 0) + 1;\n byCategory[template.category] = (byCategory[template.category] || 0) + 1;\n byStatus[template.status] = (byStatus[template.status] || 0) + 1;\n }\n\n return {\n totalTemplates: templates.length,\n byProvider,\n byCategory,\n byStatus\n };\n }\n\n /**\n * Export templates to JSON\n */\n export(filters?: TemplateSearchFilters): string {\n const result = this.search(filters, { limit: 10000 });\n return JSON.stringify({\n templates: result.templates,\n exportedAt: new Date().toISOString(),\n total: result.total\n }, null, 2);\n }\n\n /**\n * Import templates from JSON\n */\n async import(jsonData: string, options: { overwrite?: boolean } = {}): Promise<{\n imported: number;\n skipped: number;\n errors: string[];\n }> {\n const result = { imported: 0, skipped: 0, errors: [] as string[] };\n\n try {\n const data = JSON.parse(jsonData);\n const templates = data.templates || [];\n\n for (const templateData of templates) {\n try {\n const existingTemplate = this.get(templateData.id);\n \n if (existingTemplate && !options.overwrite) {\n result.skipped++;\n continue;\n }\n\n await this.register(templateData);\n result.imported++;\n } catch (error) {\n result.errors.push(`Template ${templateData.id}: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n }\n } catch (error) {\n result.errors.push(`Invalid JSON format: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n\n return result;\n }\n\n /**\n * Clear all templates (use with caution!)\n */\n clear(): void {\n this.templates.clear();\n this.templatesByCode.clear();\n this.templatesByProvider.clear();\n this.templatesByCategory.clear();\n this.templateHistories.clear();\n this.usageStats.clear();\n \n this.emit('registry:cleared');\n }\n\n /**\n * Stop the registry and cleanup\n */\n destroy(): void {\n if (this.backupTimer) {\n clearInterval(this.backupTimer);\n this.backupTimer = undefined;\n }\n \n this.removeAllListeners();\n this.emit('registry:destroyed');\n }\n\n private updateIndexes(template: AlimTalkTemplate): void {\n // Update provider index\n if (!this.templatesByProvider.has(template.provider)) {\n this.templatesByProvider.set(template.provider, new Set());\n }\n this.templatesByProvider.get(template.provider)!.add(template.id);\n\n // Update category index\n if (!this.templatesByCategory.has(template.category)) {\n this.templatesByCategory.set(template.category, new Set());\n }\n this.templatesByCategory.get(template.category)!.add(template.id);\n }\n\n private initializeVersionHistory(template: AlimTalkTemplate): void {\n const history: TemplateHistory = {\n templateId: template.id,\n versions: [{\n version: 1,\n template: JSON.parse(JSON.stringify(template)),\n changes: ['Initial version'],\n createdAt: new Date()\n }],\n currentVersion: 1\n };\n\n this.templateHistories.set(template.id, history);\n }\n\n private addVersionToHistory(oldTemplate: AlimTalkTemplate, newTemplate: AlimTalkTemplate): void {\n const history = this.templateHistories.get(newTemplate.id);\n if (!history) return;\n\n // Detect changes\n const changes: string[] = [];\n if (oldTemplate.name !== newTemplate.name) changes.push('Name changed');\n if (oldTemplate.content !== newTemplate.content) changes.push('Content changed');\n if (oldTemplate.category !== newTemplate.category) changes.push('Category changed');\n if (oldTemplate.status !== newTemplate.status) changes.push('Status changed');\n if (JSON.stringify(oldTemplate.variables) !== JSON.stringify(newTemplate.variables)) {\n changes.push('Variables changed');\n }\n if (JSON.stringify(oldTemplate.buttons) !== JSON.stringify(newTemplate.buttons)) {\n changes.push('Buttons changed');\n }\n\n if (changes.length === 0) return; // No changes detected\n\n const newVersion: TemplateVersion = {\n version: history.currentVersion + 1,\n template: JSON.parse(JSON.stringify(newTemplate)),\n changes,\n createdAt: new Date()\n };\n\n history.versions.push(newVersion);\n history.currentVersion = newVersion.version;\n\n // Keep only max versions\n if (history.versions.length > this.options.maxVersionsPerTemplate!) {\n history.versions = history.versions.slice(-this.options.maxVersionsPerTemplate!);\n }\n }\n\n private initializeUsageStats(template: AlimTalkTemplate): void {\n const stats: TemplateUsageStats = {\n templateId: template.id,\n totalSent: template.metadata.usage.sent,\n totalDelivered: template.metadata.usage.delivered,\n totalFailed: template.metadata.usage.failed,\n deliveryRate: 0,\n failureRate: 0,\n usageByDay: []\n };\n\n if (stats.totalSent > 0) {\n stats.deliveryRate = (stats.totalDelivered / stats.totalSent) * 100;\n stats.failureRate = (stats.totalFailed / stats.totalSent) * 100;\n }\n\n this.usageStats.set(template.id, stats);\n }\n\n private startAutoBackup(): void {\n this.backupTimer = setInterval(() => {\n this.emit('backup:requested', {\n data: this.export(),\n timestamp: new Date()\n });\n }, this.options.backupInterval!);\n }\n}"],"mappings":"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","names":["TemplateType","TemplateCategory","TemplateStatus"]}
|
package/dist/index.d.cts
DELETED
|
@@ -1,463 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'events';
|
|
2
|
-
|
|
3
|
-
declare enum TemplateType {
|
|
4
|
-
ALIMTALK = "ALIMTALK",
|
|
5
|
-
SMS = "SMS",
|
|
6
|
-
LMS = "LMS",
|
|
7
|
-
MMS = "MMS",
|
|
8
|
-
RCS = "RCS"
|
|
9
|
-
}
|
|
10
|
-
declare enum TemplateCategory {
|
|
11
|
-
AUTHENTICATION = "AUTHENTICATION",// 인증
|
|
12
|
-
NOTIFICATION = "NOTIFICATION",// 알림
|
|
13
|
-
PROMOTION = "PROMOTION",// 프로모션
|
|
14
|
-
INFORMATION = "INFORMATION",// 정보성
|
|
15
|
-
RESERVATION = "RESERVATION",// 예약
|
|
16
|
-
SHIPPING = "SHIPPING",// 배송
|
|
17
|
-
PAYMENT = "PAYMENT"
|
|
18
|
-
}
|
|
19
|
-
declare enum TemplateStatus {
|
|
20
|
-
DRAFT = "DRAFT",// 초안
|
|
21
|
-
PENDING = "PENDING",// 검수 중
|
|
22
|
-
APPROVED = "APPROVED",// 승인됨
|
|
23
|
-
REJECTED = "REJECTED",// 반려됨
|
|
24
|
-
DISABLED = "DISABLED"
|
|
25
|
-
}
|
|
26
|
-
interface TemplateVariable {
|
|
27
|
-
name: string;
|
|
28
|
-
type: 'string' | 'number' | 'date' | 'custom';
|
|
29
|
-
required: boolean;
|
|
30
|
-
maxLength?: number;
|
|
31
|
-
format?: string;
|
|
32
|
-
description?: string;
|
|
33
|
-
example?: string;
|
|
34
|
-
}
|
|
35
|
-
interface TemplateButton {
|
|
36
|
-
type: 'WL' | 'AL' | 'DS' | 'BK' | 'MD';
|
|
37
|
-
name: string;
|
|
38
|
-
linkMobile?: string;
|
|
39
|
-
linkPc?: string;
|
|
40
|
-
linkIos?: string;
|
|
41
|
-
linkAndroid?: string;
|
|
42
|
-
schemeIos?: string;
|
|
43
|
-
schemeAndroid?: string;
|
|
44
|
-
}
|
|
45
|
-
interface AlimTalkTemplate {
|
|
46
|
-
id: string;
|
|
47
|
-
code: string;
|
|
48
|
-
name: string;
|
|
49
|
-
content: string;
|
|
50
|
-
variables: TemplateVariable[];
|
|
51
|
-
buttons?: TemplateButton[];
|
|
52
|
-
category: TemplateCategory;
|
|
53
|
-
status: TemplateStatus;
|
|
54
|
-
provider: string;
|
|
55
|
-
metadata: {
|
|
56
|
-
createdAt: Date;
|
|
57
|
-
updatedAt: Date;
|
|
58
|
-
approvedAt?: Date;
|
|
59
|
-
rejectedAt?: Date;
|
|
60
|
-
rejectionReason?: string;
|
|
61
|
-
usage: {
|
|
62
|
-
sent: number;
|
|
63
|
-
delivered: number;
|
|
64
|
-
failed: number;
|
|
65
|
-
};
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
declare class TemplateService {
|
|
70
|
-
private templates;
|
|
71
|
-
createTemplate(template: Omit<AlimTalkTemplate, 'id' | 'metadata'>): Promise<AlimTalkTemplate>;
|
|
72
|
-
getTemplate(templateId: string): Promise<AlimTalkTemplate | null>;
|
|
73
|
-
updateTemplate(templateId: string, updates: Partial<AlimTalkTemplate>): Promise<AlimTalkTemplate>;
|
|
74
|
-
deleteTemplate(templateId: string): Promise<void>;
|
|
75
|
-
renderTemplate(templateId: string, variables: Record<string, any>): Promise<string>;
|
|
76
|
-
private generateTemplateId;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
declare class VariableParser {
|
|
80
|
-
private static readonly VARIABLE_PATTERN;
|
|
81
|
-
/**
|
|
82
|
-
* 템플릿 내용에서 변수를 추출합니다
|
|
83
|
-
*/
|
|
84
|
-
static extractVariables(content: string): string[];
|
|
85
|
-
/**
|
|
86
|
-
* 템플릿 내용의 변수를 실제 값으로 치환합니다
|
|
87
|
-
*/
|
|
88
|
-
static replaceVariables(content: string, variables: Record<string, string | number | Date>): string;
|
|
89
|
-
/**
|
|
90
|
-
* 변수 정의와 실제 제공된 값을 검증합니다
|
|
91
|
-
*/
|
|
92
|
-
static validateVariables(variableDefinitions: TemplateVariable[], providedVariables: Record<string, any>): {
|
|
93
|
-
isValid: boolean;
|
|
94
|
-
errors: string[];
|
|
95
|
-
};
|
|
96
|
-
private static validateVariableType;
|
|
97
|
-
/**
|
|
98
|
-
* 템플릿에서 사용된 변수와 정의된 변수의 일치성을 검사합니다
|
|
99
|
-
*/
|
|
100
|
-
static validateTemplateVariables(content: string, variableDefinitions: TemplateVariable[]): {
|
|
101
|
-
isValid: boolean;
|
|
102
|
-
errors: string[];
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
declare class ButtonParser {
|
|
107
|
-
/**
|
|
108
|
-
* 버튼 설정의 유효성을 검증합니다
|
|
109
|
-
*/
|
|
110
|
-
static validateButtons(buttons: TemplateButton[]): {
|
|
111
|
-
isValid: boolean;
|
|
112
|
-
errors: string[];
|
|
113
|
-
};
|
|
114
|
-
private static validateButtonByType;
|
|
115
|
-
private static validateWebLinkButton;
|
|
116
|
-
private static validateAppLinkButton;
|
|
117
|
-
private static validateDeliveryButton;
|
|
118
|
-
private static validateBotKeywordButton;
|
|
119
|
-
private static validateMessageDeliveryButton;
|
|
120
|
-
private static isValidUrl;
|
|
121
|
-
/**
|
|
122
|
-
* 버튼을 JSON 문자열로 직렬화합니다 (카카오 API 형식)
|
|
123
|
-
*/
|
|
124
|
-
static serializeButtons(buttons: TemplateButton[]): string;
|
|
125
|
-
/**
|
|
126
|
-
* JSON 문자열에서 버튼 배열로 역직렬화합니다
|
|
127
|
-
*/
|
|
128
|
-
static deserializeButtons(buttonsJson: string): TemplateButton[];
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
interface ValidationResult {
|
|
132
|
-
isValid: boolean;
|
|
133
|
-
errors: string[];
|
|
134
|
-
warnings: string[];
|
|
135
|
-
}
|
|
136
|
-
declare class TemplateValidator {
|
|
137
|
-
/**
|
|
138
|
-
* 알림톡 템플릿의 전체적인 유효성을 검증합니다
|
|
139
|
-
*/
|
|
140
|
-
static validate(template: AlimTalkTemplate): ValidationResult;
|
|
141
|
-
private static validateBasicFields;
|
|
142
|
-
private static validateContent;
|
|
143
|
-
private static containsProhibitedCharacters;
|
|
144
|
-
private static validateUrlsInContent;
|
|
145
|
-
private static validateByCategory;
|
|
146
|
-
private static validateAuthenticationTemplate;
|
|
147
|
-
private static validatePromotionTemplate;
|
|
148
|
-
private static validatePaymentTemplate;
|
|
149
|
-
/**
|
|
150
|
-
* 빠른 검증 - 기본적인 필수 필드만 검사
|
|
151
|
-
*/
|
|
152
|
-
static quickValidate(template: Partial<AlimTalkTemplate>): ValidationResult;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Template Builder - Fluent API for creating AlimTalk templates
|
|
157
|
-
*/
|
|
158
|
-
|
|
159
|
-
declare class TemplateBuilder {
|
|
160
|
-
private template;
|
|
161
|
-
/**
|
|
162
|
-
* Set template name
|
|
163
|
-
*/
|
|
164
|
-
name(name: string): TemplateBuilder;
|
|
165
|
-
/**
|
|
166
|
-
* Set template code (provider specific)
|
|
167
|
-
*/
|
|
168
|
-
code(code: string): TemplateBuilder;
|
|
169
|
-
/**
|
|
170
|
-
* Set template content with variables
|
|
171
|
-
*/
|
|
172
|
-
content(content: string): TemplateBuilder;
|
|
173
|
-
/**
|
|
174
|
-
* Set template category
|
|
175
|
-
*/
|
|
176
|
-
category(category: TemplateCategory): TemplateBuilder;
|
|
177
|
-
/**
|
|
178
|
-
* Set template provider
|
|
179
|
-
*/
|
|
180
|
-
provider(provider: string): TemplateBuilder;
|
|
181
|
-
/**
|
|
182
|
-
* Set template status
|
|
183
|
-
*/
|
|
184
|
-
status(status: TemplateStatus): TemplateBuilder;
|
|
185
|
-
/**
|
|
186
|
-
* Add a variable definition
|
|
187
|
-
*/
|
|
188
|
-
variable(name: string, type?: 'string' | 'number' | 'date' | 'custom', required?: boolean, options?: {
|
|
189
|
-
maxLength?: number;
|
|
190
|
-
format?: string;
|
|
191
|
-
description?: string;
|
|
192
|
-
example?: string;
|
|
193
|
-
}): TemplateBuilder;
|
|
194
|
-
/**
|
|
195
|
-
* Add multiple variables at once
|
|
196
|
-
*/
|
|
197
|
-
variables(variables: Array<{
|
|
198
|
-
name: string;
|
|
199
|
-
type?: 'string' | 'number' | 'date' | 'custom';
|
|
200
|
-
required?: boolean;
|
|
201
|
-
maxLength?: number;
|
|
202
|
-
format?: string;
|
|
203
|
-
description?: string;
|
|
204
|
-
example?: string;
|
|
205
|
-
}>): TemplateBuilder;
|
|
206
|
-
/**
|
|
207
|
-
* Add a web link button
|
|
208
|
-
*/
|
|
209
|
-
webLinkButton(name: string, mobileUrl?: string, pcUrl?: string): TemplateBuilder;
|
|
210
|
-
/**
|
|
211
|
-
* Add an app link button
|
|
212
|
-
*/
|
|
213
|
-
appLinkButton(name: string, options: {
|
|
214
|
-
iosUrl?: string;
|
|
215
|
-
androidUrl?: string;
|
|
216
|
-
iosScheme?: string;
|
|
217
|
-
androidScheme?: string;
|
|
218
|
-
}): TemplateBuilder;
|
|
219
|
-
/**
|
|
220
|
-
* Add a delivery tracking button
|
|
221
|
-
*/
|
|
222
|
-
deliveryButton(name: string): TemplateBuilder;
|
|
223
|
-
/**
|
|
224
|
-
* Add a bot keyword button
|
|
225
|
-
*/
|
|
226
|
-
botKeywordButton(name: string): TemplateBuilder;
|
|
227
|
-
/**
|
|
228
|
-
* Add a message delivery button
|
|
229
|
-
*/
|
|
230
|
-
messageDeliveryButton(name: string): TemplateBuilder;
|
|
231
|
-
/**
|
|
232
|
-
* Add a custom button
|
|
233
|
-
*/
|
|
234
|
-
button(button: TemplateButton): TemplateBuilder;
|
|
235
|
-
/**
|
|
236
|
-
* Clear all buttons
|
|
237
|
-
*/
|
|
238
|
-
clearButtons(): TemplateBuilder;
|
|
239
|
-
/**
|
|
240
|
-
* Set template metadata
|
|
241
|
-
*/
|
|
242
|
-
metadata(metadata: Partial<AlimTalkTemplate['metadata']>): TemplateBuilder;
|
|
243
|
-
/**
|
|
244
|
-
* Validate the current template
|
|
245
|
-
*/
|
|
246
|
-
validate(): {
|
|
247
|
-
isValid: boolean;
|
|
248
|
-
errors: string[];
|
|
249
|
-
warnings: string[];
|
|
250
|
-
};
|
|
251
|
-
/**
|
|
252
|
-
* Preview the template with sample variables
|
|
253
|
-
*/
|
|
254
|
-
preview(sampleVariables?: Record<string, any>): string;
|
|
255
|
-
/**
|
|
256
|
-
* Generate sample variables based on variable definitions
|
|
257
|
-
*/
|
|
258
|
-
private generateSampleVariables;
|
|
259
|
-
/**
|
|
260
|
-
* Clone the current builder
|
|
261
|
-
*/
|
|
262
|
-
clone(): TemplateBuilder;
|
|
263
|
-
/**
|
|
264
|
-
* Reset the builder to start fresh
|
|
265
|
-
*/
|
|
266
|
-
reset(): TemplateBuilder;
|
|
267
|
-
/**
|
|
268
|
-
* Build the final template
|
|
269
|
-
*/
|
|
270
|
-
build(): AlimTalkTemplate;
|
|
271
|
-
private generateTemplateId;
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* Static factory methods for common template types
|
|
275
|
-
*/
|
|
276
|
-
declare const TemplateBuilders: {
|
|
277
|
-
/**
|
|
278
|
-
* Create an authentication template builder
|
|
279
|
-
*/
|
|
280
|
-
authentication(name: string, provider: string): TemplateBuilder;
|
|
281
|
-
/**
|
|
282
|
-
* Create a notification template builder
|
|
283
|
-
*/
|
|
284
|
-
notification(name: string, provider: string): TemplateBuilder;
|
|
285
|
-
/**
|
|
286
|
-
* Create a promotion template builder
|
|
287
|
-
*/
|
|
288
|
-
promotion(name: string, provider: string): TemplateBuilder;
|
|
289
|
-
/**
|
|
290
|
-
* Create a payment template builder
|
|
291
|
-
*/
|
|
292
|
-
payment(name: string, provider: string): TemplateBuilder;
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Template Registry - Manages templates across providers and categories
|
|
297
|
-
*/
|
|
298
|
-
|
|
299
|
-
interface TemplateSearchFilters {
|
|
300
|
-
provider?: string;
|
|
301
|
-
category?: TemplateCategory;
|
|
302
|
-
status?: TemplateStatus;
|
|
303
|
-
nameContains?: string;
|
|
304
|
-
codeContains?: string;
|
|
305
|
-
createdAfter?: Date;
|
|
306
|
-
createdBefore?: Date;
|
|
307
|
-
usageMin?: number;
|
|
308
|
-
usageMax?: number;
|
|
309
|
-
}
|
|
310
|
-
interface TemplateSearchOptions {
|
|
311
|
-
page?: number;
|
|
312
|
-
limit?: number;
|
|
313
|
-
sortBy?: 'name' | 'code' | 'createdAt' | 'updatedAt' | 'usage';
|
|
314
|
-
sortOrder?: 'asc' | 'desc';
|
|
315
|
-
}
|
|
316
|
-
interface TemplateSearchResult {
|
|
317
|
-
templates: AlimTalkTemplate[];
|
|
318
|
-
total: number;
|
|
319
|
-
page: number;
|
|
320
|
-
limit: number;
|
|
321
|
-
hasMore: boolean;
|
|
322
|
-
}
|
|
323
|
-
interface TemplateVersion {
|
|
324
|
-
version: number;
|
|
325
|
-
template: AlimTalkTemplate;
|
|
326
|
-
changes: string[];
|
|
327
|
-
createdAt: Date;
|
|
328
|
-
createdBy?: string;
|
|
329
|
-
}
|
|
330
|
-
interface TemplateHistory {
|
|
331
|
-
templateId: string;
|
|
332
|
-
versions: TemplateVersion[];
|
|
333
|
-
currentVersion: number;
|
|
334
|
-
}
|
|
335
|
-
interface TemplateUsageStats {
|
|
336
|
-
templateId: string;
|
|
337
|
-
totalSent: number;
|
|
338
|
-
totalDelivered: number;
|
|
339
|
-
totalFailed: number;
|
|
340
|
-
deliveryRate: number;
|
|
341
|
-
failureRate: number;
|
|
342
|
-
lastUsed?: Date;
|
|
343
|
-
usageByDay: Array<{
|
|
344
|
-
date: string;
|
|
345
|
-
sent: number;
|
|
346
|
-
delivered: number;
|
|
347
|
-
failed: number;
|
|
348
|
-
}>;
|
|
349
|
-
}
|
|
350
|
-
interface TemplateRegistryOptions {
|
|
351
|
-
enableVersioning: boolean;
|
|
352
|
-
maxVersionsPerTemplate: number;
|
|
353
|
-
enableUsageTracking: boolean;
|
|
354
|
-
enableAutoBackup: boolean;
|
|
355
|
-
backupInterval: number;
|
|
356
|
-
enableValidationOnRegister: boolean;
|
|
357
|
-
}
|
|
358
|
-
declare class TemplateRegistry extends EventEmitter {
|
|
359
|
-
private options;
|
|
360
|
-
private templates;
|
|
361
|
-
private templatesByCode;
|
|
362
|
-
private templatesByProvider;
|
|
363
|
-
private templatesByCategory;
|
|
364
|
-
private templateHistories;
|
|
365
|
-
private usageStats;
|
|
366
|
-
private backupTimer?;
|
|
367
|
-
private defaultOptions;
|
|
368
|
-
constructor(options?: Partial<TemplateRegistryOptions>);
|
|
369
|
-
/**
|
|
370
|
-
* Register a new template
|
|
371
|
-
*/
|
|
372
|
-
register(template: AlimTalkTemplate): Promise<void>;
|
|
373
|
-
/**
|
|
374
|
-
* Update an existing template
|
|
375
|
-
*/
|
|
376
|
-
update(templateId: string, updates: Partial<AlimTalkTemplate>): Promise<AlimTalkTemplate>;
|
|
377
|
-
/**
|
|
378
|
-
* Get template by ID
|
|
379
|
-
*/
|
|
380
|
-
get(templateId: string): AlimTalkTemplate | null;
|
|
381
|
-
/**
|
|
382
|
-
* Get template by code and provider
|
|
383
|
-
*/
|
|
384
|
-
getByCode(code: string, provider: string): AlimTalkTemplate | null;
|
|
385
|
-
/**
|
|
386
|
-
* Search templates with filters and pagination
|
|
387
|
-
*/
|
|
388
|
-
search(filters?: TemplateSearchFilters, options?: TemplateSearchOptions): TemplateSearchResult;
|
|
389
|
-
/**
|
|
390
|
-
* Get templates by provider
|
|
391
|
-
*/
|
|
392
|
-
getByProvider(provider: string): AlimTalkTemplate[];
|
|
393
|
-
/**
|
|
394
|
-
* Get templates by category
|
|
395
|
-
*/
|
|
396
|
-
getByCategory(category: TemplateCategory): AlimTalkTemplate[];
|
|
397
|
-
/**
|
|
398
|
-
* Delete template
|
|
399
|
-
*/
|
|
400
|
-
delete(templateId: string): Promise<boolean>;
|
|
401
|
-
/**
|
|
402
|
-
* Get template version history
|
|
403
|
-
*/
|
|
404
|
-
getHistory(templateId: string): TemplateHistory | null;
|
|
405
|
-
/**
|
|
406
|
-
* Get specific template version
|
|
407
|
-
*/
|
|
408
|
-
getVersion(templateId: string, version: number): AlimTalkTemplate | null;
|
|
409
|
-
/**
|
|
410
|
-
* Restore template to a specific version
|
|
411
|
-
*/
|
|
412
|
-
restoreVersion(templateId: string, version: number): Promise<AlimTalkTemplate>;
|
|
413
|
-
/**
|
|
414
|
-
* Get template usage statistics
|
|
415
|
-
*/
|
|
416
|
-
getUsageStats(templateId: string): TemplateUsageStats | null;
|
|
417
|
-
/**
|
|
418
|
-
* Update template usage statistics
|
|
419
|
-
*/
|
|
420
|
-
updateUsageStats(templateId: string, stats: {
|
|
421
|
-
sent?: number;
|
|
422
|
-
delivered?: number;
|
|
423
|
-
failed?: number;
|
|
424
|
-
}): void;
|
|
425
|
-
/**
|
|
426
|
-
* Get registry statistics
|
|
427
|
-
*/
|
|
428
|
-
getStats(): {
|
|
429
|
-
totalTemplates: number;
|
|
430
|
-
byProvider: Record<string, number>;
|
|
431
|
-
byCategory: Record<string, number>;
|
|
432
|
-
byStatus: Record<string, number>;
|
|
433
|
-
};
|
|
434
|
-
/**
|
|
435
|
-
* Export templates to JSON
|
|
436
|
-
*/
|
|
437
|
-
export(filters?: TemplateSearchFilters): string;
|
|
438
|
-
/**
|
|
439
|
-
* Import templates from JSON
|
|
440
|
-
*/
|
|
441
|
-
import(jsonData: string, options?: {
|
|
442
|
-
overwrite?: boolean;
|
|
443
|
-
}): Promise<{
|
|
444
|
-
imported: number;
|
|
445
|
-
skipped: number;
|
|
446
|
-
errors: string[];
|
|
447
|
-
}>;
|
|
448
|
-
/**
|
|
449
|
-
* Clear all templates (use with caution!)
|
|
450
|
-
*/
|
|
451
|
-
clear(): void;
|
|
452
|
-
/**
|
|
453
|
-
* Stop the registry and cleanup
|
|
454
|
-
*/
|
|
455
|
-
destroy(): void;
|
|
456
|
-
private updateIndexes;
|
|
457
|
-
private initializeVersionHistory;
|
|
458
|
-
private addVersionToHistory;
|
|
459
|
-
private initializeUsageStats;
|
|
460
|
-
private startAutoBackup;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
export { type AlimTalkTemplate, ButtonParser, TemplateBuilder, TemplateBuilders, type TemplateButton, TemplateCategory, type TemplateHistory, TemplateRegistry, type TemplateRegistryOptions, type TemplateSearchFilters, type TemplateSearchOptions, type TemplateSearchResult, TemplateService, TemplateStatus, TemplateType, type TemplateUsageStats, TemplateValidator, type TemplateVariable, type TemplateVersion, type ValidationResult, VariableParser };
|