@k-msg/template 0.1.0 → 0.1.2

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.
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Interpolates variables into a string using the #{key} syntax.
3
+ *
4
+ * @param text The string to interpolate
5
+ * @param vars A record of key-value pairs to replace
6
+ * @returns The interpolated string
7
+ */
8
+ export declare function interpolate(text: string, vars: Record<string, any>): string;
@@ -0,0 +1,25 @@
1
+ import type { TemplateButton } from "../types/template.types";
2
+ export declare class ButtonParser {
3
+ /**
4
+ * 버튼 설정의 유효성을 검증합니다
5
+ */
6
+ static validateButtons(buttons: TemplateButton[]): {
7
+ isValid: boolean;
8
+ errors: string[];
9
+ };
10
+ private static validateButtonByType;
11
+ private static validateWebLinkButton;
12
+ private static validateAppLinkButton;
13
+ private static validateDeliveryButton;
14
+ private static validateBotKeywordButton;
15
+ private static validateMessageDeliveryButton;
16
+ private static isValidUrl;
17
+ /**
18
+ * 버튼을 JSON 문자열로 직렬화합니다 (카카오 API 형식)
19
+ */
20
+ static serializeButtons(buttons: TemplateButton[]): string;
21
+ /**
22
+ * JSON 문자열에서 버튼 배열로 역직렬화합니다
23
+ */
24
+ static deserializeButtons(buttonsJson: string): TemplateButton[];
25
+ }
@@ -0,0 +1,24 @@
1
+ import { type AlimTalkTemplate } from "../types/template.types";
2
+ export interface ValidationResult {
3
+ isValid: boolean;
4
+ errors: string[];
5
+ warnings: string[];
6
+ }
7
+ export declare class TemplateValidator {
8
+ /**
9
+ * 알림톡 템플릿의 전체적인 유효성을 검증합니다
10
+ */
11
+ static validate(template: AlimTalkTemplate): ValidationResult;
12
+ private static validateBasicFields;
13
+ private static validateContent;
14
+ private static containsProhibitedCharacters;
15
+ private static validateUrlsInContent;
16
+ private static validateByCategory;
17
+ private static validateAuthenticationTemplate;
18
+ private static validatePromotionTemplate;
19
+ private static validatePaymentTemplate;
20
+ /**
21
+ * 빠른 검증 - 기본적인 필수 필드만 검사
22
+ */
23
+ static quickValidate(template: Partial<AlimTalkTemplate>): ValidationResult;
24
+ }
@@ -0,0 +1,27 @@
1
+ import type { TemplateVariable } from "../types/template.types";
2
+ export declare class VariableParser {
3
+ private static readonly VARIABLE_PATTERN;
4
+ /**
5
+ * 템플릿 내용에서 변수를 추출합니다
6
+ */
7
+ static extractVariables(content: string): string[];
8
+ /**
9
+ * 템플릿 내용의 변수를 실제 값으로 치환합니다
10
+ */
11
+ static replaceVariables(content: string, variables: Record<string, string | number | Date>): string;
12
+ /**
13
+ * 변수 정의와 실제 제공된 값을 검증합니다
14
+ */
15
+ static validateVariables(variableDefinitions: TemplateVariable[], providedVariables: Record<string, any>): {
16
+ isValid: boolean;
17
+ errors: string[];
18
+ };
19
+ private static validateVariableType;
20
+ /**
21
+ * 템플릿에서 사용된 변수와 정의된 변수의 일치성을 검사합니다
22
+ */
23
+ static validateTemplateVariables(content: string, variableDefinitions: TemplateVariable[]): {
24
+ isValid: boolean;
25
+ errors: string[];
26
+ };
27
+ }
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Template Registry - Manages templates across providers and categories
3
+ */
4
+ import { EventEmitter } from "events";
5
+ import type { AlimTalkTemplate, TemplateCategory, TemplateStatus } from "../types/template.types";
6
+ export interface TemplateSearchFilters {
7
+ provider?: string;
8
+ category?: TemplateCategory;
9
+ status?: TemplateStatus;
10
+ nameContains?: string;
11
+ codeContains?: string;
12
+ createdAfter?: Date;
13
+ createdBefore?: Date;
14
+ usageMin?: number;
15
+ usageMax?: number;
16
+ }
17
+ export interface TemplateSearchOptions {
18
+ page?: number;
19
+ limit?: number;
20
+ sortBy?: "name" | "code" | "createdAt" | "updatedAt" | "usage";
21
+ sortOrder?: "asc" | "desc";
22
+ }
23
+ export interface TemplateSearchResult {
24
+ templates: AlimTalkTemplate[];
25
+ total: number;
26
+ page: number;
27
+ limit: number;
28
+ hasMore: boolean;
29
+ }
30
+ export interface TemplateVersion {
31
+ version: number;
32
+ template: AlimTalkTemplate;
33
+ changes: string[];
34
+ createdAt: Date;
35
+ createdBy?: string;
36
+ }
37
+ export interface TemplateHistory {
38
+ templateId: string;
39
+ versions: TemplateVersion[];
40
+ currentVersion: number;
41
+ }
42
+ export interface TemplateUsageStats {
43
+ templateId: string;
44
+ totalSent: number;
45
+ totalDelivered: number;
46
+ totalFailed: number;
47
+ deliveryRate: number;
48
+ failureRate: number;
49
+ lastUsed?: Date;
50
+ usageByDay: Array<{
51
+ date: string;
52
+ sent: number;
53
+ delivered: number;
54
+ failed: number;
55
+ }>;
56
+ }
57
+ export interface TemplateRegistryOptions {
58
+ enableVersioning: boolean;
59
+ maxVersionsPerTemplate: number;
60
+ enableUsageTracking: boolean;
61
+ enableAutoBackup: boolean;
62
+ backupInterval: number;
63
+ enableValidationOnRegister: boolean;
64
+ }
65
+ export declare class TemplateRegistry extends EventEmitter {
66
+ private options;
67
+ private templates;
68
+ private templatesByCode;
69
+ private templatesByProvider;
70
+ private templatesByCategory;
71
+ private templateHistories;
72
+ private usageStats;
73
+ private backupTimer?;
74
+ private defaultOptions;
75
+ constructor(options?: Partial<TemplateRegistryOptions>);
76
+ /**
77
+ * Register a new template
78
+ */
79
+ register(template: AlimTalkTemplate): Promise<void>;
80
+ /**
81
+ * Update an existing template
82
+ */
83
+ update(templateId: string, updates: Partial<AlimTalkTemplate>): Promise<AlimTalkTemplate>;
84
+ /**
85
+ * Get template by ID
86
+ */
87
+ get(templateId: string): AlimTalkTemplate | null;
88
+ /**
89
+ * Get template by code and provider
90
+ */
91
+ getByCode(code: string, provider: string): AlimTalkTemplate | null;
92
+ /**
93
+ * Search templates with filters and pagination
94
+ */
95
+ search(filters?: TemplateSearchFilters, options?: TemplateSearchOptions): TemplateSearchResult;
96
+ /**
97
+ * Get templates by provider
98
+ */
99
+ getByProvider(provider: string): AlimTalkTemplate[];
100
+ /**
101
+ * Get templates by category
102
+ */
103
+ getByCategory(category: TemplateCategory): AlimTalkTemplate[];
104
+ /**
105
+ * Delete template
106
+ */
107
+ delete(templateId: string): Promise<boolean>;
108
+ /**
109
+ * Get template version history
110
+ */
111
+ getHistory(templateId: string): TemplateHistory | null;
112
+ /**
113
+ * Get specific template version
114
+ */
115
+ getVersion(templateId: string, version: number): AlimTalkTemplate | null;
116
+ /**
117
+ * Restore template to a specific version
118
+ */
119
+ restoreVersion(templateId: string, version: number): Promise<AlimTalkTemplate>;
120
+ /**
121
+ * Get template usage statistics
122
+ */
123
+ getUsageStats(templateId: string): TemplateUsageStats | null;
124
+ /**
125
+ * Update template usage statistics
126
+ */
127
+ updateUsageStats(templateId: string, stats: {
128
+ sent?: number;
129
+ delivered?: number;
130
+ failed?: number;
131
+ }): void;
132
+ /**
133
+ * Get registry statistics
134
+ */
135
+ getStats(): {
136
+ totalTemplates: number;
137
+ byProvider: Record<string, number>;
138
+ byCategory: Record<string, number>;
139
+ byStatus: Record<string, number>;
140
+ };
141
+ /**
142
+ * Export templates to JSON
143
+ */
144
+ export(filters?: TemplateSearchFilters): string;
145
+ /**
146
+ * Import templates from JSON
147
+ */
148
+ import(jsonData: string, options?: {
149
+ overwrite?: boolean;
150
+ }): Promise<{
151
+ imported: number;
152
+ skipped: number;
153
+ errors: string[];
154
+ }>;
155
+ /**
156
+ * Clear all templates (use with caution!)
157
+ */
158
+ clear(): void;
159
+ /**
160
+ * Stop the registry and cleanup
161
+ */
162
+ destroy(): void;
163
+ private updateIndexes;
164
+ private initializeVersionHistory;
165
+ private addVersionToHistory;
166
+ private initializeUsageStats;
167
+ private startAutoBackup;
168
+ }
@@ -0,0 +1,14 @@
1
+ import { KMsgError, type Result, type Template, type TemplateProvider } from "@k-msg/core";
2
+ export declare class TemplateService {
3
+ private readonly provider;
4
+ constructor(provider: TemplateProvider);
5
+ create(template: Omit<Template, "id" | "status" | "createdAt" | "updatedAt">): Promise<Result<Template, KMsgError>>;
6
+ update(code: string, template: Partial<Omit<Template, "id" | "code" | "status" | "createdAt" | "updatedAt">>): Promise<Result<Template, KMsgError>>;
7
+ delete(code: string): Promise<Result<void, KMsgError>>;
8
+ get(code: string): Promise<Result<Template, KMsgError>>;
9
+ list(params?: {
10
+ status?: string;
11
+ page?: number;
12
+ limit?: number;
13
+ }): Promise<Result<Template[], KMsgError>>;
14
+ }
@@ -0,0 +1,10 @@
1
+ import type { AlimTalkTemplate } from "../types/template.types";
2
+ export declare class TemplateService {
3
+ private templates;
4
+ createTemplate(template: Omit<AlimTalkTemplate, "id" | "metadata">): Promise<AlimTalkTemplate>;
5
+ getTemplate(templateId: string): Promise<AlimTalkTemplate | null>;
6
+ updateTemplate(templateId: string, updates: Partial<AlimTalkTemplate>): Promise<AlimTalkTemplate>;
7
+ deleteTemplate(templateId: string): Promise<void>;
8
+ renderTemplate(templateId: string, variables: Record<string, any>): Promise<string>;
9
+ private generateTemplateId;
10
+ }
@@ -0,0 +1,150 @@
1
+ import { z } from "zod";
2
+ export declare enum TemplateType {
3
+ ALIMTALK = "ALIMTALK",
4
+ SMS = "SMS",
5
+ LMS = "LMS",
6
+ MMS = "MMS",
7
+ RCS = "RCS"
8
+ }
9
+ export declare enum TemplateCategory {
10
+ AUTHENTICATION = "AUTHENTICATION",// 인증
11
+ NOTIFICATION = "NOTIFICATION",// 알림
12
+ PROMOTION = "PROMOTION",// 프로모션
13
+ INFORMATION = "INFORMATION",// 정보성
14
+ RESERVATION = "RESERVATION",// 예약
15
+ SHIPPING = "SHIPPING",// 배송
16
+ PAYMENT = "PAYMENT"
17
+ }
18
+ export declare enum TemplateStatus {
19
+ DRAFT = "DRAFT",// 초안
20
+ PENDING = "PENDING",// 검수 중
21
+ APPROVED = "APPROVED",// 승인됨
22
+ REJECTED = "REJECTED",// 반려됨
23
+ DISABLED = "DISABLED"
24
+ }
25
+ export interface TemplateVariable {
26
+ name: string;
27
+ type: "string" | "number" | "date" | "custom";
28
+ required: boolean;
29
+ maxLength?: number;
30
+ format?: string;
31
+ description?: string;
32
+ example?: string;
33
+ }
34
+ export interface TemplateButton {
35
+ type: "WL" | "AL" | "DS" | "BK" | "MD";
36
+ name: string;
37
+ linkMobile?: string;
38
+ linkPc?: string;
39
+ linkIos?: string;
40
+ linkAndroid?: string;
41
+ schemeIos?: string;
42
+ schemeAndroid?: string;
43
+ }
44
+ export interface AlimTalkTemplate {
45
+ id: string;
46
+ code: string;
47
+ name: string;
48
+ content: string;
49
+ variables?: TemplateVariable[];
50
+ buttons?: TemplateButton[];
51
+ category: TemplateCategory;
52
+ status: TemplateStatus;
53
+ provider: string;
54
+ metadata: {
55
+ createdAt: Date;
56
+ updatedAt: Date;
57
+ approvedAt?: Date;
58
+ rejectedAt?: Date;
59
+ rejectionReason?: string;
60
+ usage: {
61
+ sent: number;
62
+ delivered: number;
63
+ failed: number;
64
+ };
65
+ };
66
+ }
67
+ export declare const TemplateVariableSchema: z.ZodObject<{
68
+ name: z.ZodString;
69
+ type: z.ZodEnum<{
70
+ string: "string";
71
+ number: "number";
72
+ date: "date";
73
+ custom: "custom";
74
+ }>;
75
+ required: z.ZodBoolean;
76
+ maxLength: z.ZodOptional<z.ZodNumber>;
77
+ format: z.ZodOptional<z.ZodString>;
78
+ description: z.ZodOptional<z.ZodString>;
79
+ example: z.ZodOptional<z.ZodString>;
80
+ }, z.core.$strip>;
81
+ export declare const TemplateButtonSchema: z.ZodObject<{
82
+ type: z.ZodEnum<{
83
+ WL: "WL";
84
+ AL: "AL";
85
+ DS: "DS";
86
+ BK: "BK";
87
+ MD: "MD";
88
+ }>;
89
+ name: z.ZodString;
90
+ linkMobile: z.ZodOptional<z.ZodString>;
91
+ linkPc: z.ZodOptional<z.ZodString>;
92
+ linkIos: z.ZodOptional<z.ZodString>;
93
+ linkAndroid: z.ZodOptional<z.ZodString>;
94
+ schemeIos: z.ZodOptional<z.ZodString>;
95
+ schemeAndroid: z.ZodOptional<z.ZodString>;
96
+ }, z.core.$strip>;
97
+ export declare const AlimTalkTemplateSchema: z.ZodObject<{
98
+ id: z.ZodString;
99
+ code: z.ZodString;
100
+ name: z.ZodString;
101
+ content: z.ZodString;
102
+ variables: z.ZodArray<z.ZodObject<{
103
+ name: z.ZodString;
104
+ type: z.ZodEnum<{
105
+ string: "string";
106
+ number: "number";
107
+ date: "date";
108
+ custom: "custom";
109
+ }>;
110
+ required: z.ZodBoolean;
111
+ maxLength: z.ZodOptional<z.ZodNumber>;
112
+ format: z.ZodOptional<z.ZodString>;
113
+ description: z.ZodOptional<z.ZodString>;
114
+ example: z.ZodOptional<z.ZodString>;
115
+ }, z.core.$strip>>;
116
+ buttons: z.ZodOptional<z.ZodArray<z.ZodObject<{
117
+ type: z.ZodEnum<{
118
+ WL: "WL";
119
+ AL: "AL";
120
+ DS: "DS";
121
+ BK: "BK";
122
+ MD: "MD";
123
+ }>;
124
+ name: z.ZodString;
125
+ linkMobile: z.ZodOptional<z.ZodString>;
126
+ linkPc: z.ZodOptional<z.ZodString>;
127
+ linkIos: z.ZodOptional<z.ZodString>;
128
+ linkAndroid: z.ZodOptional<z.ZodString>;
129
+ schemeIos: z.ZodOptional<z.ZodString>;
130
+ schemeAndroid: z.ZodOptional<z.ZodString>;
131
+ }, z.core.$strip>>>;
132
+ category: z.ZodEnum<typeof TemplateCategory>;
133
+ status: z.ZodEnum<typeof TemplateStatus>;
134
+ provider: z.ZodString;
135
+ metadata: z.ZodObject<{
136
+ createdAt: z.ZodDate;
137
+ updatedAt: z.ZodDate;
138
+ approvedAt: z.ZodOptional<z.ZodDate>;
139
+ rejectedAt: z.ZodOptional<z.ZodDate>;
140
+ rejectionReason: z.ZodOptional<z.ZodString>;
141
+ usage: z.ZodObject<{
142
+ sent: z.ZodNumber;
143
+ delivered: z.ZodNumber;
144
+ failed: z.ZodNumber;
145
+ }, z.core.$strip>;
146
+ }, z.core.$strip>;
147
+ }, z.core.$strip>;
148
+ export type AlimTalkTemplateType = z.infer<typeof AlimTalkTemplateSchema>;
149
+ export type TemplateVariableType = z.infer<typeof TemplateVariableSchema>;
150
+ export type TemplateButtonType = z.infer<typeof TemplateButtonSchema>;
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@k-msg/template",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
+ "packageManager": "bun@1.3.8",
4
5
  "description": "AlimTalk template engine for parsing, building and managing templates",
5
6
  "type": "module",
6
7
  "main": "dist/index.js",
@@ -17,19 +18,24 @@
17
18
  "access": "public"
18
19
  },
19
20
  "scripts": {
20
- "build": "tsup",
21
+ "build": "bun run build:esm && bun run build:cjs && bun run build:types",
22
+ "build:esm": "bun build ./src/index.ts --outdir ./dist --format esm --minify --sourcemap --entry-naming '[name].mjs' --external 'bun:test'",
23
+ "build:cjs": "bun build ./src/index.ts --outdir ./dist --format cjs --minify --sourcemap --entry-naming '[name].js' --external 'bun:test'",
24
+ "build:types": "tsc",
21
25
  "dev": "tsc --watch",
22
26
  "test": "bun test",
23
- "clean": "rm -rf dist"
27
+ "clean": "rm -rf dist",
28
+ "pack": "bun pm pack",
29
+ "publish": "bun publish --access public"
24
30
  },
25
31
  "dependencies": {
26
- "zod": "catalog:"
32
+ "@k-msg/core": "0.1.1",
33
+ "zod": "^4.0.14"
27
34
  },
28
35
  "devDependencies": {
29
- "typescript": "catalog:",
30
- "@types/bun": "catalog:",
31
- "@types/node": "catalog:",
32
- "tsup": "^8.5.0"
36
+ "typescript": "^5.7.2",
37
+ "@types/bun": "latest",
38
+ "@types/node": "^22.0.0"
33
39
  },
34
40
  "keywords": [
35
41
  "alimtalk",
@@ -44,12 +50,12 @@
44
50
  ],
45
51
  "repository": {
46
52
  "type": "git",
47
- "url": "git+https://github.com/k-otp/k-message.git"
53
+ "url": "git+https://github.com/k-otp/k-msg.git"
48
54
  },
49
- "homepage": "https://github.com/k-otp/k-message",
55
+ "homepage": "https://github.com/k-otp/k-msg",
50
56
  "bugs": {
51
- "url": "https://github.com/k-otp/k-message/issues"
57
+ "url": "https://github.com/k-otp/k-msg/issues"
52
58
  },
53
59
  "author": "imjlk",
54
60
  "license": "MIT"
55
- }
61
+ }