@o-t-p-y/cli 0.3.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OTPy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # otpy-cli
2
+
3
+ The official CLI and automatic integration wizard for [OTPy.ir](https://otpy.ir).
4
+
5
+ ## Quick Start
6
+
7
+ Initialize OTP authentication in your existing project with one command:
8
+
9
+ ```bash
10
+ npx @o-t-p-y/cli init
11
+ ```
12
+
13
+ The CLI will:
14
+ 1. Detect your framework (Next.js App/Pages router, SvelteKit, Express, Python FastAPI/Django, Go, PHP Laravel).
15
+ 2. Ask for or detect your `OTPY_API_KEY` and safely update your `.env` or `.env.local`.
16
+ 3. Generate ready-to-run client and route handler files.
17
+
18
+ ## Other Commands
19
+
20
+ ### Send a Test OTP
21
+
22
+ ```bash
23
+ npx @o-t-p-y/cli test 09123456789
24
+ ```
25
+
26
+ ### View Daily Quota Usage
27
+
28
+ ```bash
29
+ npx @o-t-p-y/cli usage
30
+ ```
31
+
32
+ ### AI Integration Mode
33
+
34
+ ```bash
35
+ npx @o-t-p-y/cli init --ai
36
+ ```
37
+
38
+ Outputs prompt instructions for AI coding assistants (Cursor, Windsurf, Claude Code, GitHub Copilot).
39
+
40
+ ## License
41
+
42
+ MIT © [OTPy.ir](https://otpy.ir)
@@ -0,0 +1,11 @@
1
+ export type Framework = "next-app" | "next-pages" | "sveltekit" | "express" | "node-generic" | "python-fastapi" | "python-django" | "python-generic" | "php-laravel" | "php-generic" | "go" | "unknown";
2
+ export interface ProjectInfo {
3
+ framework: Framework;
4
+ isTypeScript: boolean;
5
+ hasSrcDir: boolean;
6
+ hasEnvFile: boolean;
7
+ envFilePath: string;
8
+ }
9
+ export type NextPagesRoot = "pages" | "src/pages";
10
+ export declare function detectNextPagesRoot(cwd?: string): NextPagesRoot;
11
+ export declare function detectProject(cwd?: string): ProjectInfo;
@@ -0,0 +1,116 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ // Next.js ignores src/pages when a root pages dir exists — root wins.
4
+ export function detectNextPagesRoot(cwd = process.cwd()) {
5
+ if (existsSync(join(cwd, "pages")))
6
+ return "pages";
7
+ if (existsSync(join(cwd, "src", "pages")))
8
+ return "src/pages";
9
+ return "pages";
10
+ }
11
+ export function detectProject(cwd = process.cwd()) {
12
+ const hasPkgJson = existsSync(join(cwd, "package.json"));
13
+ const hasTsConfig = existsSync(join(cwd, "tsconfig.json"));
14
+ const hasSrcDir = existsSync(join(cwd, "src"));
15
+ const envLocal = existsSync(join(cwd, ".env.local"));
16
+ const envMain = existsSync(join(cwd, ".env"));
17
+ const hasEnvFile = envLocal || envMain;
18
+ const envFilePath = envLocal ? join(cwd, ".env.local") : join(cwd, ".env");
19
+ if (hasPkgJson) {
20
+ try {
21
+ const pkg = JSON.parse(readFileSync(join(cwd, "package.json"), "utf8"));
22
+ const allDeps = {
23
+ ...pkg.dependencies,
24
+ ...pkg.devDependencies,
25
+ };
26
+ if (allDeps["next"]) {
27
+ const hasAppDir = existsSync(join(cwd, "app")) || existsSync(join(cwd, "src", "app"));
28
+ return {
29
+ framework: hasAppDir ? "next-app" : "next-pages",
30
+ isTypeScript: hasTsConfig,
31
+ hasSrcDir,
32
+ hasEnvFile,
33
+ envFilePath,
34
+ };
35
+ }
36
+ if (allDeps["@sveltejs/kit"]) {
37
+ return {
38
+ framework: "sveltekit",
39
+ isTypeScript: hasTsConfig,
40
+ hasSrcDir,
41
+ hasEnvFile,
42
+ envFilePath,
43
+ };
44
+ }
45
+ if (allDeps["express"] || allDeps["fastify"] || allDeps["koa"] || allDeps["hono"]) {
46
+ return {
47
+ framework: "express",
48
+ isTypeScript: hasTsConfig,
49
+ hasSrcDir,
50
+ hasEnvFile,
51
+ envFilePath,
52
+ };
53
+ }
54
+ return {
55
+ framework: "node-generic",
56
+ isTypeScript: hasTsConfig,
57
+ hasSrcDir,
58
+ hasEnvFile,
59
+ envFilePath,
60
+ };
61
+ }
62
+ catch {
63
+ // Fall through
64
+ }
65
+ }
66
+ // Check Python
67
+ if (existsSync(join(cwd, "pyproject.toml")) ||
68
+ existsSync(join(cwd, "requirements.txt")) ||
69
+ existsSync(join(cwd, "Pipfile"))) {
70
+ if (existsSync(join(cwd, "manage.py"))) {
71
+ return {
72
+ framework: "python-django",
73
+ isTypeScript: false,
74
+ hasSrcDir,
75
+ hasEnvFile,
76
+ envFilePath,
77
+ };
78
+ }
79
+ return {
80
+ framework: "python-fastapi",
81
+ isTypeScript: false,
82
+ hasSrcDir,
83
+ hasEnvFile,
84
+ envFilePath,
85
+ };
86
+ }
87
+ // Check PHP
88
+ if (existsSync(join(cwd, "composer.json"))) {
89
+ const isLaravel = existsSync(join(cwd, "artisan"));
90
+ return {
91
+ framework: isLaravel ? "php-laravel" : "php-generic",
92
+ isTypeScript: false,
93
+ hasSrcDir,
94
+ hasEnvFile,
95
+ envFilePath,
96
+ };
97
+ }
98
+ // Check Go
99
+ if (existsSync(join(cwd, "go.mod"))) {
100
+ return {
101
+ framework: "go",
102
+ isTypeScript: false,
103
+ hasSrcDir,
104
+ hasEnvFile,
105
+ envFilePath,
106
+ };
107
+ }
108
+ return {
109
+ framework: "unknown",
110
+ isTypeScript: hasTsConfig,
111
+ hasSrcDir,
112
+ hasEnvFile,
113
+ envFilePath,
114
+ };
115
+ }
116
+ //# sourceMappingURL=detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detector.js","sourceRoot":"","sources":["../src/detector.ts"],"names":[],"mappings":"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"}
package/dist/env.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function getExistingEnvKey(filePath: string, keyName?: string): string | null;
2
+ export declare function appendOrUpdateEnvKey(filePath: string, keyName: string, keyValue: string): void;
package/dist/env.js ADDED
@@ -0,0 +1,29 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ export function getExistingEnvKey(filePath, keyName = "OTPY_API_KEY") {
3
+ if (!existsSync(filePath))
4
+ return null;
5
+ try {
6
+ const content = readFileSync(filePath, "utf8");
7
+ const match = new RegExp(`^${keyName}=(.*)$`, "m").exec(content);
8
+ return match?.[1]?.trim() ?? null;
9
+ }
10
+ catch {
11
+ return null;
12
+ }
13
+ }
14
+ export function appendOrUpdateEnvKey(filePath, keyName, keyValue) {
15
+ let content = "";
16
+ if (existsSync(filePath)) {
17
+ content = readFileSync(filePath, "utf8");
18
+ }
19
+ const regex = new RegExp(`^${keyName}=.*$`, "m");
20
+ if (regex.test(content)) {
21
+ content = content.replace(regex, `${keyName}=${keyValue}`);
22
+ }
23
+ else {
24
+ const endsWithNewline = content.length === 0 || content.endsWith("\n");
25
+ content = `${content}${endsWithNewline ? "" : "\n"}${keyName}=${keyValue}\n`;
26
+ }
27
+ writeFileSync(filePath, content, "utf8");
28
+ }
29
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAElE,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,UAAkB,cAAc;IAClF,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,OAAO,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjE,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,OAAe,EAAE,QAAgB;IACtF,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,OAAO,MAAM,EAAE,GAAG,CAAC,CAAC;IACjD,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,OAAO,IAAI,QAAQ,EAAE,CAAC,CAAC;IAC7D,CAAC;SAAM,CAAC;QACN,MAAM,eAAe,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvE,OAAO,GAAG,GAAG,OAAO,GAAG,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,OAAO,IAAI,QAAQ,IAAI,CAAC;IAC/E,CAAC;IAED,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,243 @@
1
+ #!/usr/bin/env node
2
+ import { createInterface } from "node:readline";
3
+ import { dirname, join } from "node:path";
4
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
5
+ import packageMetadata from "../package.json" with { type: "json" };
6
+ import { detectNextPagesRoot, detectProject } from "./detector.js";
7
+ import { appendOrUpdateEnvKey, getExistingEnvKey } from "./env.js";
8
+ import { generateExpressTemplates, generateGoTemplates, generateNextAppTemplates, generateNextPagesTemplates, generatePhpLaravelTemplates, generatePythonFastApiTemplates, generateSvelteKitTemplates, phpLaravelRoutesSnippet, } from "./templates.js";
9
+ const args = process.argv.slice(2);
10
+ const command = args[0] || "init";
11
+ const placeholderApiKey = "otpy_test_key_replace_with_yours";
12
+ function printBanner() {
13
+ console.log(`
14
+ ┌────────────────────────────────────────────────────────┐
15
+ │ OTPy.ir — سامانه هوشمند ارسال پیامک کد ورود (OTP) │
16
+ │ سریع، اقتصادی، بدون خط اختصاصی و قرارداد │
17
+ └────────────────────────────────────────────────────────┘
18
+ `);
19
+ }
20
+ function prompt(question) {
21
+ const rl = createInterface({
22
+ input: process.stdin,
23
+ output: process.stdout,
24
+ });
25
+ return new Promise((resolve) => {
26
+ rl.question(question, (answer) => {
27
+ rl.close();
28
+ resolve(answer.trim());
29
+ });
30
+ });
31
+ }
32
+ async function runInit() {
33
+ printBanner();
34
+ const cwd = process.cwd();
35
+ const info = detectProject(cwd);
36
+ console.log(`🔍 بررسی پروژه...`);
37
+ console.log(` فریم‌ورک شناسایی شده: ${info.framework}`);
38
+ console.log(` پشتیبانی از تایپ‌اسکریپت: ${info.isTypeScript ? "بله" : "خیر"}`);
39
+ console.log(` فایل محیطی (.env): ${info.envFilePath}\n`);
40
+ let apiKey = getExistingEnvKey(info.envFilePath);
41
+ const cliKeyArgIndex = args.indexOf("--api-key");
42
+ if (cliKeyArgIndex !== -1 && args[cliKeyArgIndex + 1]) {
43
+ apiKey = args[cliKeyArgIndex + 1] ?? null;
44
+ }
45
+ if (!apiKey) {
46
+ console.log(`💡 کلید API پروژه خود را وارد کنید (یا از داشبورد https://dash.otpy.ir کپی کنید):`);
47
+ apiKey = (await prompt("🔑 کلید API: ")) || null;
48
+ }
49
+ if (apiKey && apiKey !== placeholderApiKey) {
50
+ appendOrUpdateEnvKey(info.envFilePath, "OTPY_API_KEY", apiKey);
51
+ console.log(`\n✔ کلید در فایل ${info.envFilePath} ذخیره شد.`);
52
+ }
53
+ else {
54
+ console.log(`\n💡 برای دریافت کلید API به https://dash.otpy.ir مراجعه کنید.`);
55
+ }
56
+ // Generate templates
57
+ let filesToGenerate = [];
58
+ if (info.framework === "next-app") {
59
+ filesToGenerate = generateNextAppTemplates(info.hasSrcDir, info.isTypeScript);
60
+ }
61
+ else if (info.framework === "next-pages") {
62
+ filesToGenerate = generateNextPagesTemplates(detectNextPagesRoot(cwd) === "src/pages", info.isTypeScript);
63
+ }
64
+ else if (info.framework === "sveltekit") {
65
+ filesToGenerate = generateSvelteKitTemplates();
66
+ }
67
+ else if (info.framework === "express" || info.framework === "node-generic") {
68
+ filesToGenerate = generateExpressTemplates(info.hasSrcDir, info.isTypeScript);
69
+ }
70
+ else if (info.framework === "python-fastapi" || info.framework === "python-django") {
71
+ filesToGenerate = generatePythonFastApiTemplates();
72
+ }
73
+ else if (info.framework === "go") {
74
+ filesToGenerate = generateGoTemplates();
75
+ }
76
+ else if (info.framework === "php-laravel") {
77
+ filesToGenerate = generatePhpLaravelTemplates();
78
+ if (existsSync(join(cwd, "routes/api.php"))) {
79
+ console.log(`\n📝 فایل routes/api.php از قبل موجود است؛ این خطوط را به آن اضافه کنید:`);
80
+ console.log(phpLaravelRoutesSnippet);
81
+ }
82
+ }
83
+ else if (info.framework === "php-generic") {
84
+ filesToGenerate = [];
85
+ console.log(`\n🐘 پروژه PHP شناسایی شد، اما فریم‌ورک پشتیبانی‌شده‌ای (Laravel) پیدا نشد.`);
86
+ console.log(` برای ادغام دستی، مستندات را ببینید: https://otpy.ir/docs`);
87
+ console.log(` نمونه ارسال با cURL:`);
88
+ console.log(` curl -X POST https://api.otpy.ir/v1/otp/send \\`);
89
+ console.log(` -H "Authorization: Bearer $OTPY_API_KEY" -H "Content-Type: application/json" \\`);
90
+ console.log(` -d '{"phone":"09123456789"}'`);
91
+ }
92
+ else {
93
+ filesToGenerate = generateNextAppTemplates(info.hasSrcDir, info.isTypeScript);
94
+ }
95
+ if (filesToGenerate.length > 0) {
96
+ console.log(`\n📦 در حال ایجاد فایل‌های ادغام و کلاینت:`);
97
+ for (const file of filesToGenerate) {
98
+ const fullPath = join(cwd, file.path);
99
+ const parentDir = dirname(fullPath);
100
+ if (!existsSync(parentDir)) {
101
+ mkdirSync(parentDir, { recursive: true });
102
+ }
103
+ if (!existsSync(fullPath)) {
104
+ writeFileSync(fullPath, file.content, "utf8");
105
+ console.log(` + ایجاد فایل: ${file.path}`);
106
+ }
107
+ else {
108
+ console.log(` ~ فایل موجود بود (رد شد): ${file.path}`);
109
+ }
110
+ }
111
+ }
112
+ if (args.includes("--ai")) {
113
+ console.log(`\n🤖 دستورالعمل هوش مصنوعی برای ابزارهای Cursor / Windsurf / Claude Code:`);
114
+ if (info.framework === "php-laravel" || info.framework === "php-generic") {
115
+ console.log(` - REST API: https://api.otpy.ir`);
116
+ console.log(` - ارسال: POST /v1/otp/send با بدنه {"phone": "09123456789"}`);
117
+ console.log(` - تایید: POST /v1/otp/verify با بدنه {"phone": "09123456789", "code": "123456"} → {verified: boolean}`);
118
+ }
119
+ else {
120
+ console.log(` - کتابخانه: @o-t-p-y/sdk`);
121
+ console.log(` - ارسال: otpy.sendOtp(phone) -> { request_id, ttl_seconds }`);
122
+ console.log(` - تایید: otpy.verifyOtp(phone, code) -> { verified: true }`);
123
+ }
124
+ }
125
+ if (info.framework === "php-generic") {
126
+ console.log(`
127
+ برای راهنمای کامل ادغام دستی به https://otpy.ir/docs مراجعه کنید.
128
+ داشبورد و آمار لحظه‌ای: https://dash.otpy.ir
129
+ `);
130
+ }
131
+ else if (info.framework === "php-laravel") {
132
+ console.log(`
133
+ 🎉 تبریک! ادغام با موفقیت انجام شد.
134
+
135
+ مراحل بعدی:
136
+ ۱. اجرای سرور محلی: php artisan serve
137
+ ۲. تست ارسال: curl -X POST http://localhost:8000/api/auth/otp/send -H "Content-Type: application/json" -d '{"phone":"09123456789"}'
138
+ ۳. داشبورد و آمار لحظه‌ای: https://dash.otpy.ir
139
+ `);
140
+ }
141
+ else {
142
+ console.log(`
143
+ 🎉 تبریک! ادغام با موفقیت انجام شد.
144
+
145
+ مراحل بعدی:
146
+ ۱. برای نصب پکیج: npm install @o-t-p-y/sdk
147
+ ۲. برای تست ارسال پیامک: npx @o-t-p-y/cli test 09123456789
148
+ ۳. داشبورد و آمار لحظه‌ای: https://dash.otpy.ir
149
+ `);
150
+ }
151
+ }
152
+ async function runTest() {
153
+ const phone = args[1];
154
+ if (!phone || !/^09\d{9}$/.test(phone)) {
155
+ console.log("❌ خطا: شماره موبایل معتبر الزامی است. مثال: npx @o-t-p-y/cli test 09123456789");
156
+ process.exit(1);
157
+ }
158
+ const info = detectProject(process.cwd());
159
+ const apiKey = getExistingEnvKey(info.envFilePath);
160
+ if (!apiKey) {
161
+ console.log("❌ کلید OTPY_API_KEY در فایل .env یافت نشد. ابتدا npx @o-t-p-y/cli init را اجرا کنید.");
162
+ process.exit(1);
163
+ }
164
+ console.log(`🚀 در حال ارسال کد تست به شماره ${phone}...`);
165
+ try {
166
+ const res = await fetch("https://api.otpy.ir/v1/otp/send", {
167
+ method: "POST",
168
+ headers: {
169
+ authorization: `Bearer ${apiKey}`,
170
+ "content-type": "application/json",
171
+ },
172
+ body: JSON.stringify({ phone }),
173
+ });
174
+ const data = (await res.json());
175
+ if (res.ok) {
176
+ console.log(`✔ پیامک ارسال شد!`);
177
+ console.log(` شناسه پیامک: ${data.request_id}`);
178
+ console.log(` نوع مصرف: ${data.free ? "سهمیه رایگان روزانه" : "شارژی"}`);
179
+ }
180
+ else {
181
+ console.log(`❌ خطا در ارسال پیامک: ${data.error || res.statusText}`);
182
+ }
183
+ }
184
+ catch (err) {
185
+ console.log(`❌ خطای شبکه: ${String(err)}`);
186
+ }
187
+ }
188
+ async function runUsage() {
189
+ const info = detectProject(process.cwd());
190
+ const apiKey = getExistingEnvKey(info.envFilePath);
191
+ if (!apiKey) {
192
+ console.log("❌ کلید OTPY_API_KEY در فایل .env یافت نشد.");
193
+ process.exit(1);
194
+ }
195
+ try {
196
+ const res = await fetch("https://api.otpy.ir/v1/usage", {
197
+ method: "GET",
198
+ headers: { authorization: `Bearer ${apiKey}` },
199
+ });
200
+ const data = (await res.json());
201
+ if (res.ok) {
202
+ console.log(`📊 آمار مصرف امروز:`);
203
+ console.log(` رایگان مصرف شده: ${data.free_used_today} از ${data.free_quota_today}`);
204
+ console.log(` پیامک‌های شارژی: ${data.paid_today}`);
205
+ console.log(` سقف کل روزانه: ${data.daily_limit ? data.daily_limit : "نامحدود"}`);
206
+ }
207
+ else {
208
+ console.log(`❌ خطا در استعلام آمار.`);
209
+ }
210
+ }
211
+ catch (err) {
212
+ console.log(`❌ خطای شبکه: ${String(err)}`);
213
+ }
214
+ }
215
+ if (command === "--version" || command === "-v") {
216
+ console.log(packageMetadata.version);
217
+ process.exit(0);
218
+ }
219
+ if (command === "--help" || command === "-h") {
220
+ console.log(`
221
+ استفاده از دستورات ابزار خط فرمان OTPy:
222
+ npx @o-t-p-y/cli init راه‌اندازی خودکار پروژه و تولید فایل‌های آماده
223
+ npx @o-t-p-y/cli init --ai راه‌اندازی به همراه راهنمای ایجنت‌های هوش مصنوعی
224
+ npx @o-t-p-y/cli test <phone> ارسال پیامک تست به شماره دلخواه
225
+ npx @o-t-p-y/cli usage مشاهده آمار مصرف امروز سهمیه
226
+ npx @o-t-p-y/cli --version نسخه CLI
227
+ `);
228
+ process.exit(0);
229
+ }
230
+ if (command === "init") {
231
+ runInit().catch(console.error);
232
+ }
233
+ else if (command === "test") {
234
+ runTest().catch(console.error);
235
+ }
236
+ else if (command === "usage") {
237
+ runUsage().catch(console.error);
238
+ }
239
+ else {
240
+ console.log(`دستور ناشناخته: ${command}\nبرای راهنما npx @o-t-p-y/cli --help را اجرا کنید.`);
241
+ process.exit(1);
242
+ }
243
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface GeneratedFile {
2
+ path: string;
3
+ content: string;
4
+ }
5
+ export declare function generateNextAppTemplates(hasSrc: boolean, isTs: boolean): GeneratedFile[];
6
+ export declare function generateNextPagesTemplates(hasSrcPages: boolean, isTs: boolean): GeneratedFile[];
7
+ export declare function generateSvelteKitTemplates(): GeneratedFile[];
8
+ export declare function generateExpressTemplates(hasSrc: boolean, isTs: boolean): GeneratedFile[];
9
+ export declare function generatePythonFastApiTemplates(): GeneratedFile[];
10
+ export declare const phpLaravelRoutesSnippet = "Route::post('/auth/otp/send', [OtpController::class, 'send']);\nRoute::post('/auth/otp/verify', [OtpController::class, 'verify']);\n";
11
+ export declare function generatePhpLaravelTemplates(): GeneratedFile[];
12
+ export declare function generateGoTemplates(): GeneratedFile[];
@@ -0,0 +1,517 @@
1
+ export function generateNextAppTemplates(hasSrc, isTs) {
2
+ const prefix = hasSrc ? "src/" : "";
3
+ const ext = isTs ? "ts" : "js";
4
+ const clientCode = isTs
5
+ ? `import { OtpyClient } from "@o-t-p-y/sdk";
6
+
7
+ export const otpy = new OtpyClient({
8
+ apiKey: process.env.OTPY_API_KEY!,
9
+ });
10
+ `
11
+ : `import { OtpyClient } from "@o-t-p-y/sdk";
12
+
13
+ export const otpy = new OtpyClient({
14
+ apiKey: process.env.OTPY_API_KEY,
15
+ });
16
+ `;
17
+ const sendRouteCode = isTs
18
+ ? `import { NextResponse } from "next/server";
19
+ import { otpy } from "@/lib/otpy";
20
+
21
+ export async function POST(request: Request) {
22
+ try {
23
+ const { phone } = await request.json();
24
+ if (!phone) {
25
+ return NextResponse.json({ error: "شماره موبایل الزامی است" }, { status: 400 });
26
+ }
27
+
28
+ const result = await otpy.sendOtp(phone);
29
+ return NextResponse.json(result);
30
+ } catch (error: any) {
31
+ return NextResponse.json(
32
+ { error: error.message || "خطا در ارسال پیامک" },
33
+ { status: error.status || 500 }
34
+ );
35
+ }
36
+ }
37
+ `
38
+ : `import { NextResponse } from "next/server";
39
+ import { otpy } from "@/lib/otpy";
40
+
41
+ export async function POST(request) {
42
+ try {
43
+ const { phone } = await request.json();
44
+ if (!phone) {
45
+ return NextResponse.json({ error: "شماره موبایل الزامی است" }, { status: 400 });
46
+ }
47
+
48
+ const result = await otpy.sendOtp(phone);
49
+ return NextResponse.json(result);
50
+ } catch (error) {
51
+ return NextResponse.json(
52
+ { error: error.message || "خطا در ارسال پیامک" },
53
+ { status: error.status || 500 }
54
+ );
55
+ }
56
+ }
57
+ `;
58
+ const verifyRouteCode = isTs
59
+ ? `import { NextResponse } from "next/server";
60
+ import { otpy } from "@/lib/otpy";
61
+
62
+ export async function POST(request: Request) {
63
+ try {
64
+ const { phone, code } = await request.json();
65
+ if (!phone || !code) {
66
+ return NextResponse.json({ error: "شماره موبایل و کد ورود الزامی است" }, { status: 400 });
67
+ }
68
+
69
+ const result = await otpy.verifyOtp(phone, code);
70
+ if (!result.verified) {
71
+ return NextResponse.json({ verified: false, error: "کد وارد شده اشتباه یا منقضی است" }, { status: 401 });
72
+ }
73
+
74
+ // TODO: احراز هویت موفق بود. اینجا سشن یا توکن لاگین کاربر را صادر کنید.
75
+ return NextResponse.json({ verified: true });
76
+ } catch (error: any) {
77
+ return NextResponse.json(
78
+ { error: error.message || "خطا در بررسی کد" },
79
+ { status: error.status || 500 }
80
+ );
81
+ }
82
+ }
83
+ `
84
+ : `import { NextResponse } from "next/server";
85
+ import { otpy } from "@/lib/otpy";
86
+
87
+ export async function POST(request) {
88
+ try {
89
+ const { phone, code } = await request.json();
90
+ if (!phone || !code) {
91
+ return NextResponse.json({ error: "شماره موبایل و کد ورود الزامی است" }, { status: 400 });
92
+ }
93
+
94
+ const result = await otpy.verifyOtp(phone, code);
95
+ if (!result.verified) {
96
+ return NextResponse.json({ verified: false, error: "کد وارد شده اشتباه یا منقضی است" }, { status: 401 });
97
+ }
98
+
99
+ // TODO: احراز هویت موفق بود. اینجا سشن یا توکن لاگین کاربر را صادر کنید.
100
+ return NextResponse.json({ verified: true });
101
+ } catch (error) {
102
+ return NextResponse.json(
103
+ { error: error.message || "خطا در بررسی کد" },
104
+ { status: error.status || 500 }
105
+ );
106
+ }
107
+ }
108
+ `;
109
+ return [
110
+ { path: `${prefix}lib/otpy.${ext}`, content: clientCode },
111
+ { path: `${prefix}app/api/auth/otp/send/route.${ext}`, content: sendRouteCode },
112
+ { path: `${prefix}app/api/auth/otp/verify/route.${ext}`, content: verifyRouteCode },
113
+ ];
114
+ }
115
+ export function generateNextPagesTemplates(hasSrcPages, isTs) {
116
+ const prefix = hasSrcPages ? "src/" : "";
117
+ const ext = isTs ? "ts" : "js";
118
+ const clientCode = isTs
119
+ ? `import { OtpyClient } from "@o-t-p-y/sdk";
120
+
121
+ export const otpy = new OtpyClient({
122
+ apiKey: process.env.OTPY_API_KEY!,
123
+ });
124
+ `
125
+ : `import { OtpyClient } from "@o-t-p-y/sdk";
126
+
127
+ export const otpy = new OtpyClient({
128
+ apiKey: process.env.OTPY_API_KEY,
129
+ });
130
+ `;
131
+ const sendHandlerCode = isTs
132
+ ? `import type { NextApiRequest, NextApiResponse } from "next";
133
+ import { OtpyError } from "@o-t-p-y/sdk";
134
+ import { otpy } from "../../../../lib/otpy";
135
+
136
+ export default async function handler(req: NextApiRequest, res: NextApiResponse) {
137
+ if (req.method !== "POST") {
138
+ res.setHeader("Allow", "POST");
139
+ return res.status(405).json({ error: "فقط متد POST مجاز است" });
140
+ }
141
+
142
+ try {
143
+ const { phone } = req.body;
144
+ if (!phone) {
145
+ return res.status(400).json({ error: "شماره موبایل الزامی است" });
146
+ }
147
+
148
+ const result = await otpy.sendOtp(phone);
149
+ return res.status(200).json(result);
150
+ } catch (error) {
151
+ if (error instanceof OtpyError) {
152
+ return res.status(error.status || 500).json({ error: error.code });
153
+ }
154
+ return res.status(500).json({ error: "خطا در ارسال پیامک" });
155
+ }
156
+ }
157
+ `
158
+ : `import { OtpyError } from "@o-t-p-y/sdk";
159
+ import { otpy } from "../../../../lib/otpy";
160
+
161
+ export default async function handler(req, res) {
162
+ if (req.method !== "POST") {
163
+ res.setHeader("Allow", "POST");
164
+ return res.status(405).json({ error: "فقط متد POST مجاز است" });
165
+ }
166
+
167
+ try {
168
+ const { phone } = req.body;
169
+ if (!phone) {
170
+ return res.status(400).json({ error: "شماره موبایل الزامی است" });
171
+ }
172
+
173
+ const result = await otpy.sendOtp(phone);
174
+ return res.status(200).json(result);
175
+ } catch (error) {
176
+ if (error instanceof OtpyError) {
177
+ return res.status(error.status || 500).json({ error: error.code });
178
+ }
179
+ return res.status(500).json({ error: "خطا در ارسال پیامک" });
180
+ }
181
+ }
182
+ `;
183
+ const verifyHandlerCode = isTs
184
+ ? `import type { NextApiRequest, NextApiResponse } from "next";
185
+ import { OtpyError } from "@o-t-p-y/sdk";
186
+ import { otpy } from "../../../../lib/otpy";
187
+
188
+ export default async function handler(req: NextApiRequest, res: NextApiResponse) {
189
+ if (req.method !== "POST") {
190
+ res.setHeader("Allow", "POST");
191
+ return res.status(405).json({ error: "فقط متد POST مجاز است" });
192
+ }
193
+
194
+ try {
195
+ const { phone, code } = req.body;
196
+ if (!phone || !code) {
197
+ return res.status(400).json({ error: "شماره موبایل و کد ورود الزامی است" });
198
+ }
199
+
200
+ const result = await otpy.verifyOtp(phone, code);
201
+ if (!result.verified) {
202
+ return res.status(401).json({ verified: false, error: "کد وارد شده اشتباه یا منقضی است" });
203
+ }
204
+
205
+ // TODO: احراز هویت موفق بود. اینجا سشن یا توکن لاگین کاربر را صادر کنید.
206
+ return res.status(200).json({ verified: true });
207
+ } catch (error) {
208
+ if (error instanceof OtpyError) {
209
+ return res.status(error.status || 500).json({ error: error.code });
210
+ }
211
+ return res.status(500).json({ error: "خطا در بررسی کد" });
212
+ }
213
+ }
214
+ `
215
+ : `import { OtpyError } from "@o-t-p-y/sdk";
216
+ import { otpy } from "../../../../lib/otpy";
217
+
218
+ export default async function handler(req, res) {
219
+ if (req.method !== "POST") {
220
+ res.setHeader("Allow", "POST");
221
+ return res.status(405).json({ error: "فقط متد POST مجاز است" });
222
+ }
223
+
224
+ try {
225
+ const { phone, code } = req.body;
226
+ if (!phone || !code) {
227
+ return res.status(400).json({ error: "شماره موبایل و کد ورود الزامی است" });
228
+ }
229
+
230
+ const result = await otpy.verifyOtp(phone, code);
231
+ if (!result.verified) {
232
+ return res.status(401).json({ verified: false, error: "کد وارد شده اشتباه یا منقضی است" });
233
+ }
234
+
235
+ // TODO: احراز هویت موفق بود. اینجا سشن یا توکن لاگین کاربر را صادر کنید.
236
+ return res.status(200).json({ verified: true });
237
+ } catch (error) {
238
+ if (error instanceof OtpyError) {
239
+ return res.status(error.status || 500).json({ error: error.code });
240
+ }
241
+ return res.status(500).json({ error: "خطا در بررسی کد" });
242
+ }
243
+ }
244
+ `;
245
+ return [
246
+ { path: `${prefix}lib/otpy.${ext}`, content: clientCode },
247
+ { path: `${prefix}pages/api/auth/otp/send.${ext}`, content: sendHandlerCode },
248
+ { path: `${prefix}pages/api/auth/otp/verify.${ext}`, content: verifyHandlerCode },
249
+ ];
250
+ }
251
+ export function generateSvelteKitTemplates() {
252
+ const clientCode = `import { OtpyClient } from "@o-t-p-y/sdk";
253
+ import { env } from "$env/dynamic/private";
254
+
255
+ export const otpy = new OtpyClient({
256
+ apiKey: env.OTPY_API_KEY ?? "",
257
+ });
258
+ `;
259
+ const sendRouteCode = `import { json, type RequestHandler } from "@sveltejs/kit";
260
+ import { OtpyError } from "@o-t-p-y/sdk";
261
+ import { otpy } from "$lib/otpy";
262
+
263
+ export const POST: RequestHandler = async ({ request }) => {
264
+ try {
265
+ const { phone } = (await request.json()) as { phone?: string };
266
+ if (!phone) {
267
+ return json({ error: "شماره موبایل الزامی است" }, { status: 400 });
268
+ }
269
+
270
+ const result = await otpy.sendOtp(phone);
271
+ return json(result);
272
+ } catch (error) {
273
+ if (error instanceof OtpyError) {
274
+ return json({ error: error.code }, { status: error.status || 500 });
275
+ }
276
+ return json({ error: "خطا در ارسال پیامک" }, { status: 500 });
277
+ }
278
+ };
279
+ `;
280
+ const verifyRouteCode = `import { json, type RequestHandler } from "@sveltejs/kit";
281
+ import { OtpyError } from "@o-t-p-y/sdk";
282
+ import { otpy } from "$lib/otpy";
283
+
284
+ export const POST: RequestHandler = async ({ request }) => {
285
+ try {
286
+ const { phone, code } = (await request.json()) as { phone?: string; code?: string };
287
+ if (!phone || !code) {
288
+ return json({ error: "شماره موبایل و کد ورود الزامی است" }, { status: 400 });
289
+ }
290
+
291
+ const result = await otpy.verifyOtp(phone, code);
292
+ if (!result.verified) {
293
+ return json({ verified: false, error: "کد وارد شده اشتباه یا منقضی است" }, { status: 401 });
294
+ }
295
+
296
+ // TODO: احراز هویت موفق بود. اینجا سشن یا توکن لاگین کاربر را صادر کنید.
297
+ return json({ verified: true });
298
+ } catch (error) {
299
+ if (error instanceof OtpyError) {
300
+ return json({ error: error.code }, { status: error.status || 500 });
301
+ }
302
+ return json({ error: "خطا در بررسی کد" }, { status: 500 });
303
+ }
304
+ };
305
+ `;
306
+ return [
307
+ { path: "src/lib/otpy.ts", content: clientCode },
308
+ { path: "src/routes/auth/otp/send/+server.ts", content: sendRouteCode },
309
+ { path: "src/routes/auth/otp/verify/+server.ts", content: verifyRouteCode },
310
+ ];
311
+ }
312
+ export function generateExpressTemplates(hasSrc, isTs) {
313
+ const prefix = hasSrc ? "src/" : "";
314
+ const ext = isTs ? "ts" : "js";
315
+ const clientCode = `import { OtpyClient } from "@o-t-p-y/sdk";
316
+
317
+ export const otpy = new OtpyClient({
318
+ apiKey: process.env.OTPY_API_KEY || "",
319
+ });
320
+ `;
321
+ const routerCode = `import { Router } from "express";
322
+ import { otpy } from "../lib/otpy.js";
323
+
324
+ const router = Router();
325
+
326
+ router.post("/send", async (req, res) => {
327
+ try {
328
+ const { phone } = req.body;
329
+ if (!phone) return res.status(400).json({ error: "شماره موبایل الزامی است" });
330
+ const result = await otpy.sendOtp(phone);
331
+ return res.json(result);
332
+ } catch (err) {
333
+ return res.status(err.status || 500).json({ error: err.code || "خطا در ارسال" });
334
+ }
335
+ });
336
+
337
+ router.post("/verify", async (req, res) => {
338
+ try {
339
+ const { phone, code } = req.body;
340
+ if (!phone || !code) return res.status(400).json({ error: "شماره موبایل و کد الزامی است" });
341
+ const result = await otpy.verifyOtp(phone, code);
342
+ return res.json(result);
343
+ } catch (err) {
344
+ return res.status(err.status || 500).json({ error: err.code || "خطا در تایید" });
345
+ }
346
+ });
347
+
348
+ export default router;
349
+ `;
350
+ return [
351
+ { path: `${prefix}lib/otpy.${ext}`, content: clientCode },
352
+ { path: `${prefix}routes/otp.${ext}`, content: routerCode },
353
+ ];
354
+ }
355
+ export function generatePythonFastApiTemplates() {
356
+ const code = `print("Install dependencies: pip install requests fastapi")
357
+
358
+ import os
359
+ import requests
360
+ from fastapi import APIRouter, HTTPException
361
+ from pydantic import BaseModel
362
+
363
+ router = APIRouter(prefix="/auth/otp", tags=["OTP"])
364
+
365
+ OTPY_API_KEY = os.getenv("OTPY_API_KEY", "")
366
+ HEADERS = {
367
+ "Authorization": f"Bearer {OTPY_API_KEY}",
368
+ "Content-Type": "application/json"
369
+ }
370
+
371
+ class SendOtpRequest(BaseModel):
372
+ phone: str
373
+
374
+ class VerifyOtpRequest(BaseModel):
375
+ phone: str
376
+ code: str
377
+
378
+ @router.post("/send")
379
+ def send_otp(req: SendOtpRequest):
380
+ res = requests.post("https://api.otpy.ir/v1/otp/send", json={"phone": req.phone}, headers=HEADERS)
381
+ if not res.ok:
382
+ raise HTTPException(status_code=res.status_code, detail=res.json().get("error", "Failed"))
383
+ return res.json()
384
+
385
+ @router.post("/verify")
386
+ def verify_otp(req: VerifyOtpRequest):
387
+ res = requests.post("https://api.otpy.ir/v1/otp/verify", json={"phone": req.phone, "code": req.code}, headers=HEADERS)
388
+ if not res.ok:
389
+ raise HTTPException(status_code=res.status_code, detail=res.json().get("error", "Failed"))
390
+ return res.json()
391
+ `;
392
+ return [{ path: "routers/otp.py", content: code }];
393
+ }
394
+ export const phpLaravelRoutesSnippet = `Route::post('/auth/otp/send', [OtpController::class, 'send']);
395
+ Route::post('/auth/otp/verify', [OtpController::class, 'verify']);
396
+ `;
397
+ export function generatePhpLaravelTemplates() {
398
+ const configCode = `<?php
399
+
400
+ return [
401
+ 'key' => env('OTPY_API_KEY', ''),
402
+ 'base_url' => env('OTPY_BASE_URL', 'https://api.otpy.ir'),
403
+ ];
404
+ `;
405
+ const controllerCode = `<?php
406
+
407
+ namespace App\\Http\\Controllers;
408
+
409
+ use Illuminate\\Http\\JsonResponse;
410
+ use Illuminate\\Http\\Request;
411
+ use Illuminate\\Support\\Facades\\Http;
412
+
413
+ class OtpController extends Controller
414
+ {
415
+ public function send(Request $request): JsonResponse
416
+ {
417
+ $validated = $request->validate([
418
+ 'phone' => 'required|string',
419
+ ]);
420
+
421
+ $response = Http::withToken(config('otpy.key'))
422
+ ->acceptJson()
423
+ ->post(config('otpy.base_url').'/v1/otp/send', [
424
+ 'phone' => $validated['phone'],
425
+ ]);
426
+
427
+ if ($response->failed()) {
428
+ return response()->json(
429
+ ['error' => $response->json('error', 'خطا در ارسال پیامک')],
430
+ $response->status()
431
+ );
432
+ }
433
+
434
+ return response()->json($response->json());
435
+ }
436
+
437
+ public function verify(Request $request): JsonResponse
438
+ {
439
+ $validated = $request->validate([
440
+ 'phone' => 'required|string',
441
+ 'code' => 'required|string',
442
+ ]);
443
+
444
+ $response = Http::withToken(config('otpy.key'))
445
+ ->acceptJson()
446
+ ->post(config('otpy.base_url').'/v1/otp/verify', [
447
+ 'phone' => $validated['phone'],
448
+ 'code' => $validated['code'],
449
+ ]);
450
+
451
+ if ($response->failed()) {
452
+ return response()->json(
453
+ ['error' => $response->json('error', 'خطا در بررسی کد')],
454
+ $response->status()
455
+ );
456
+ }
457
+
458
+ // TODO: احراز هویت موفق بود. اینجا سشن یا توکن لاگین کاربر را صادر کنید.
459
+ return response()->json(['verified' => (bool) $response->json('verified', false)]);
460
+ }
461
+ }
462
+ `;
463
+ const routesCode = `<?php
464
+
465
+ use App\\Http\\Controllers\\OtpController;
466
+ use Illuminate\\Support\\Facades\\Route;
467
+
468
+ ${phpLaravelRoutesSnippet}`;
469
+ return [
470
+ { path: "config/otpy.php", content: configCode },
471
+ { path: "app/Http/Controllers/OtpController.php", content: controllerCode },
472
+ { path: "routes/api.php", content: routesCode },
473
+ ];
474
+ }
475
+ export function generateGoTemplates() {
476
+ const code = `package otpy
477
+
478
+ import (
479
+ "bytes"
480
+ "encoding/json"
481
+ "fmt"
482
+ "net/http"
483
+ "os"
484
+ )
485
+
486
+ type OtpClient struct {
487
+ ApiKey string
488
+ BaseUrl string
489
+ }
490
+
491
+ func NewClient() *OtpClient {
492
+ return &OtpClient{
493
+ ApiKey: os.Getenv("OTPY_API_KEY"),
494
+ BaseUrl: "https://api.otpy.ir",
495
+ }
496
+ }
497
+
498
+ func (c *OtpClient) Send(phone string) (map[string]any, error) {
499
+ payload, _ := json.Marshal(map[string]string{"phone": phone})
500
+ req, _ := http.NewRequest("POST", c.BaseUrl+"/v1/otp/send", bytes.NewBuffer(payload))
501
+ req.Header.Set("Authorization", "Bearer "+c.ApiKey)
502
+ req.Header.Set("Content-Type", "application/json")
503
+
504
+ resp, err := http.DefaultClient.Do(req)
505
+ if err != nil {
506
+ return nil, err
507
+ }
508
+ defer resp.Body.Close()
509
+
510
+ var result map[string]any
511
+ json.NewDecoder(resp.Body).Decode(&result)
512
+ return result, nil
513
+ }
514
+ `;
515
+ return [{ path: "pkg/otpy/client.go", content: code }];
516
+ }
517
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@o-t-p-y/cli",
3
+ "version": "0.3.2",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "npx otpy-cli init — one-command OTPy integration (framework detection, code patching, AI mode).",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/o-t-p-y/cli.git",
11
+ "directory": "packages/cli"
12
+ },
13
+ "homepage": "https://otpy.ir",
14
+ "bugs": "https://github.com/o-t-p-y/cli/issues",
15
+ "keywords": [
16
+ "otp",
17
+ "otpy",
18
+ "sms",
19
+ "iranian-otp",
20
+ "cli",
21
+ "authentication"
22
+ ],
23
+ "bin": {
24
+ "otpy-cli": "./dist/index.js"
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.json",
37
+ "typecheck": "tsc --noEmit",
38
+ "dev": "tsx src/index.ts",
39
+ "test": "vitest run --passWithNoTests"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22.10.2",
43
+ "tsx": "^4.19.2",
44
+ "typescript": "^5.7.2",
45
+ "vitest": "^3.2.4"
46
+ }
47
+ }