@o-t-p-y/cli 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/env.d.ts +12 -0
- package/dist/env.js +67 -1
- package/dist/env.js.map +1 -1
- package/dist/index.js +87 -65
- package/dist/index.js.map +1 -1
- package/dist/templates.js +27 -0
- package/dist/templates.js.map +1 -1
- package/dist/ui.d.ts +20 -0
- package/dist/ui.js +105 -0
- package/dist/ui.js.map +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @o-t-p-y/cli
|
|
2
2
|
|
|
3
3
|
The official CLI and automatic integration wizard for [OTPy.ir](https://otpy.ir).
|
|
4
4
|
|
|
@@ -15,6 +15,8 @@ The CLI will:
|
|
|
15
15
|
2. Ask for or detect your `OTPY_API_KEY` and safely update your `.env` or `.env.local`.
|
|
16
16
|
3. Generate ready-to-run client and route handler files.
|
|
17
17
|
|
|
18
|
+
The supplied key is checked against `GET /v1/usage`; an unavailable or rejected check prints a warning and the wizard continues. If no supported framework is detected, the wizard prints the REST integration guide and does not create framework files.
|
|
19
|
+
|
|
18
20
|
## Other Commands
|
|
19
21
|
|
|
20
22
|
### Send a Test OTP
|
package/dist/env.d.ts
CHANGED
|
@@ -1,2 +1,14 @@
|
|
|
1
1
|
export declare function getExistingEnvKey(filePath: string, keyName?: string): string | null;
|
|
2
2
|
export declare function appendOrUpdateEnvKey(filePath: string, keyName: string, keyValue: string): void;
|
|
3
|
+
/**
|
|
4
|
+
* Add the selected env file to the repository's .gitignore when it is not
|
|
5
|
+
* already ignored. Returns false when the project is not inside a git repo or
|
|
6
|
+
* the file is already covered by an ignore rule.
|
|
7
|
+
*/
|
|
8
|
+
export declare function ensureEnvFileIgnored(cwd: string, filePath: string): boolean;
|
|
9
|
+
export interface ApiKeyValidation {
|
|
10
|
+
ok: boolean;
|
|
11
|
+
reason?: string;
|
|
12
|
+
}
|
|
13
|
+
/** Validate a key without making init fail when the API is unavailable. */
|
|
14
|
+
export declare function validateApiKey(apiKey: string, fetchFn?: typeof globalThis.fetch, baseUrl?: string): Promise<ApiKeyValidation>;
|
package/dist/env.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { basename, join, relative, resolve, sep } from "node:path";
|
|
2
4
|
export function getExistingEnvKey(filePath, keyName = "OTPY_API_KEY") {
|
|
3
5
|
if (!existsSync(filePath))
|
|
4
6
|
return null;
|
|
@@ -26,4 +28,68 @@ export function appendOrUpdateEnvKey(filePath, keyName, keyValue) {
|
|
|
26
28
|
}
|
|
27
29
|
writeFileSync(filePath, content, "utf8");
|
|
28
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Add the selected env file to the repository's .gitignore when it is not
|
|
33
|
+
* already ignored. Returns false when the project is not inside a git repo or
|
|
34
|
+
* the file is already covered by an ignore rule.
|
|
35
|
+
*/
|
|
36
|
+
export function ensureEnvFileIgnored(cwd, filePath) {
|
|
37
|
+
let repoRoot;
|
|
38
|
+
try {
|
|
39
|
+
repoRoot = execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
40
|
+
cwd,
|
|
41
|
+
encoding: "utf8",
|
|
42
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
43
|
+
}).trim();
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
// macOS commonly exposes /var through a /private/var symlink while git
|
|
49
|
+
// returns the canonical /private path. Normalize both sides before taking
|
|
50
|
+
// the relative path so a valid git checkout is not mistaken for a sibling.
|
|
51
|
+
const realRepoRoot = realpathSync(repoRoot);
|
|
52
|
+
const realCwd = realpathSync(cwd);
|
|
53
|
+
const pathFromCwd = relative(resolve(cwd), resolve(filePath));
|
|
54
|
+
const absoluteEnvPath = resolve(realCwd, pathFromCwd);
|
|
55
|
+
const relativeEnvPath = relative(realRepoRoot, absoluteEnvPath).split(sep).join("/");
|
|
56
|
+
if (!relativeEnvPath || relativeEnvPath.startsWith("../"))
|
|
57
|
+
return false;
|
|
58
|
+
try {
|
|
59
|
+
execFileSync("git", ["check-ignore", "--no-index", "-q", "--", relativeEnvPath], {
|
|
60
|
+
cwd: realRepoRoot,
|
|
61
|
+
stdio: "ignore",
|
|
62
|
+
});
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// No matching ignore rule: append an exact path below.
|
|
67
|
+
}
|
|
68
|
+
const gitignorePath = join(repoRoot, ".gitignore");
|
|
69
|
+
const existing = existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf8") : "";
|
|
70
|
+
const suffix = existing.length === 0 || existing.endsWith("\n") ? "" : "\n";
|
|
71
|
+
const entry = relativeEnvPath === basename(relativeEnvPath) ? relativeEnvPath : `/${relativeEnvPath}`;
|
|
72
|
+
writeFileSync(gitignorePath, `${existing}${suffix}${entry}\n`, "utf8");
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
/** Validate a key without making init fail when the API is unavailable. */
|
|
76
|
+
export async function validateApiKey(apiKey, fetchFn = globalThis.fetch, baseUrl = process.env.OTPY_BASE_URL || "https://api.otpy.ir") {
|
|
77
|
+
const controller = new AbortController();
|
|
78
|
+
const timeout = setTimeout(() => controller.abort(), 3_000);
|
|
79
|
+
try {
|
|
80
|
+
const response = await fetchFn(`${baseUrl.replace(/\/+$/, "")}/v1/usage`, {
|
|
81
|
+
headers: { authorization: `Bearer ${apiKey}` },
|
|
82
|
+
signal: controller.signal,
|
|
83
|
+
});
|
|
84
|
+
return response.ok
|
|
85
|
+
? { ok: true }
|
|
86
|
+
: { ok: false, reason: `API returned HTTP ${response.status}` };
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
return { ok: false, reason: `network check failed (${String(error)})` };
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
clearTimeout(timeout);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
29
95
|
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
CHANGED
|
@@ -1 +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;
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -4,19 +4,12 @@ import { dirname, join } from "node:path";
|
|
|
4
4
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
5
5
|
import packageMetadata from "../package.json" with { type: "json" };
|
|
6
6
|
import { detectNextPagesRoot, detectProject } from "./detector.js";
|
|
7
|
-
import { appendOrUpdateEnvKey, getExistingEnvKey } from "./env.js";
|
|
7
|
+
import { appendOrUpdateEnvKey, ensureEnvFileIgnored, getExistingEnvKey, validateApiKey } from "./env.js";
|
|
8
8
|
import { generateExpressTemplates, generateGoTemplates, generateNextAppTemplates, generateNextPagesTemplates, generatePhpLaravelTemplates, generatePythonFastApiTemplates, generateSvelteKitTemplates, phpLaravelRoutesSnippet, } from "./templates.js";
|
|
9
|
+
import { printBanner, spinner } from "./ui.js";
|
|
9
10
|
const args = process.argv.slice(2);
|
|
10
11
|
const command = args[0] || "init";
|
|
11
12
|
const placeholderApiKey = "otpy_test_key_replace_with_yours";
|
|
12
|
-
function printBanner() {
|
|
13
|
-
console.log(`
|
|
14
|
-
┌────────────────────────────────────────────────────────┐
|
|
15
|
-
│ OTPy.ir — سامانه هوشمند ارسال پیامک کد ورود (OTP) │
|
|
16
|
-
│ سریع، اقتصادی، بدون خط اختصاصی و قرارداد │
|
|
17
|
-
└────────────────────────────────────────────────────────┘
|
|
18
|
-
`);
|
|
19
|
-
}
|
|
20
13
|
function prompt(question) {
|
|
21
14
|
const rl = createInterface({
|
|
22
15
|
input: process.stdin,
|
|
@@ -33,25 +26,36 @@ async function runInit() {
|
|
|
33
26
|
printBanner();
|
|
34
27
|
const cwd = process.cwd();
|
|
35
28
|
const info = detectProject(cwd);
|
|
36
|
-
console.log(`🔍
|
|
37
|
-
console.log(`
|
|
38
|
-
console.log(`
|
|
39
|
-
console.log(`
|
|
29
|
+
console.log(`🔍 Scanning project...`);
|
|
30
|
+
console.log(` Detected framework: ${info.framework}`);
|
|
31
|
+
console.log(` TypeScript: ${info.isTypeScript ? "yes" : "no"}`);
|
|
32
|
+
console.log(` Env file: ${info.envFilePath}\n`);
|
|
40
33
|
let apiKey = getExistingEnvKey(info.envFilePath);
|
|
41
34
|
const cliKeyArgIndex = args.indexOf("--api-key");
|
|
42
35
|
if (cliKeyArgIndex !== -1 && args[cliKeyArgIndex + 1]) {
|
|
43
36
|
apiKey = args[cliKeyArgIndex + 1] ?? null;
|
|
44
37
|
}
|
|
45
38
|
if (!apiKey) {
|
|
46
|
-
console.log(`💡
|
|
47
|
-
apiKey = (await prompt("🔑
|
|
39
|
+
console.log(`💡 Enter your project API key (copy it from https://dash.otpy.ir):`);
|
|
40
|
+
apiKey = (await prompt("🔑 API key: ")) || null;
|
|
48
41
|
}
|
|
49
42
|
if (apiKey && apiKey !== placeholderApiKey) {
|
|
43
|
+
const s = spinner("🔑 Validating API key...");
|
|
44
|
+
const validation = await validateApiKey(apiKey).finally(() => s.stop());
|
|
45
|
+
if (validation.ok) {
|
|
46
|
+
console.log(`✅ API key validated.`);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
console.log(`⚠️ Key validation failed (${validation.reason}). Continuing anyway — double-check the key later.`);
|
|
50
|
+
}
|
|
50
51
|
appendOrUpdateEnvKey(info.envFilePath, "OTPY_API_KEY", apiKey);
|
|
51
|
-
console.log(`\n
|
|
52
|
+
console.log(`\n✅ Key saved to ${info.envFilePath}.`);
|
|
52
53
|
}
|
|
53
54
|
else {
|
|
54
|
-
console.log(`\n💡
|
|
55
|
+
console.log(`\n💡 Get your API key at https://dash.otpy.ir`);
|
|
56
|
+
}
|
|
57
|
+
if (ensureEnvFileIgnored(cwd, info.envFilePath)) {
|
|
58
|
+
console.log(`✅ Added ${info.envFilePath} to .gitignore.`);
|
|
55
59
|
}
|
|
56
60
|
// Generate templates
|
|
57
61
|
let filesToGenerate = [];
|
|
@@ -76,24 +80,34 @@ async function runInit() {
|
|
|
76
80
|
else if (info.framework === "php-laravel") {
|
|
77
81
|
filesToGenerate = generatePhpLaravelTemplates();
|
|
78
82
|
if (existsSync(join(cwd, "routes/api.php"))) {
|
|
79
|
-
console.log(`\n📝
|
|
83
|
+
console.log(`\n📝 routes/api.php already exists — append these lines manually:`);
|
|
80
84
|
console.log(phpLaravelRoutesSnippet);
|
|
81
85
|
}
|
|
82
86
|
}
|
|
83
87
|
else if (info.framework === "php-generic") {
|
|
84
88
|
filesToGenerate = [];
|
|
85
|
-
console.log(`\n🐘
|
|
86
|
-
console.log(`
|
|
87
|
-
console.log(`
|
|
89
|
+
console.log(`\n🐘 PHP project detected, but no supported framework (Laravel) found.`);
|
|
90
|
+
console.log(` Manual integration guide: https://otpy.ir/docs`);
|
|
91
|
+
console.log(` Send OTP with cURL:`);
|
|
88
92
|
console.log(` curl -X POST https://api.otpy.ir/v1/otp/send \\`);
|
|
89
93
|
console.log(` -H "Authorization: Bearer $OTPY_API_KEY" -H "Content-Type: application/json" \\`);
|
|
90
94
|
console.log(` -d '{"phone":"09123456789"}'`);
|
|
91
95
|
}
|
|
92
96
|
else {
|
|
93
|
-
filesToGenerate =
|
|
97
|
+
filesToGenerate = [];
|
|
98
|
+
console.log(`\n📝 No supported framework detected; no files were generated.`);
|
|
99
|
+
console.log(` Manual integration guide: https://otpy.ir/docs`);
|
|
100
|
+
console.log(`\n Send:`);
|
|
101
|
+
console.log(` curl -X POST https://api.otpy.ir/v1/otp/send \\`);
|
|
102
|
+
console.log(` -H "Authorization: Bearer $OTPY_API_KEY" -H "Content-Type: application/json" \\`);
|
|
103
|
+
console.log(` -d '{"phone":"09123456789"}'`);
|
|
104
|
+
console.log(`\n Verify:`);
|
|
105
|
+
console.log(` curl -X POST https://api.otpy.ir/v1/otp/verify \\`);
|
|
106
|
+
console.log(` -H "Authorization: Bearer $OTPY_API_KEY" -H "Content-Type: application/json" \\`);
|
|
107
|
+
console.log(` -d '{"phone":"09123456789","code":"123456"}'`);
|
|
94
108
|
}
|
|
95
109
|
if (filesToGenerate.length > 0) {
|
|
96
|
-
console.log(`\n📦
|
|
110
|
+
console.log(`\n📦 Generating integration files:`);
|
|
97
111
|
for (const file of filesToGenerate) {
|
|
98
112
|
const fullPath = join(cwd, file.path);
|
|
99
113
|
const parentDir = dirname(fullPath);
|
|
@@ -102,66 +116,67 @@ async function runInit() {
|
|
|
102
116
|
}
|
|
103
117
|
if (!existsSync(fullPath)) {
|
|
104
118
|
writeFileSync(fullPath, file.content, "utf8");
|
|
105
|
-
console.log(`
|
|
119
|
+
console.log(` ✅ created ${file.path}`);
|
|
106
120
|
}
|
|
107
121
|
else {
|
|
108
|
-
console.log(`
|
|
122
|
+
console.log(` ⏭️ skipped (exists): ${file.path}`);
|
|
109
123
|
}
|
|
110
124
|
}
|
|
111
125
|
}
|
|
112
126
|
if (args.includes("--ai")) {
|
|
113
|
-
console.log(`\n🤖
|
|
127
|
+
console.log(`\n🤖 AI assistant instructions (Cursor / Windsurf / Claude Code):`);
|
|
114
128
|
if (info.framework === "php-laravel" || info.framework === "php-generic") {
|
|
115
129
|
console.log(` - REST API: https://api.otpy.ir`);
|
|
116
|
-
console.log(` -
|
|
117
|
-
console.log(` -
|
|
130
|
+
console.log(` - Send: POST /v1/otp/send with body {"phone": "09123456789"}`);
|
|
131
|
+
console.log(` - Verify: POST /v1/otp/verify with body {"phone": "09123456789", "code": "123456"} → {verified: boolean}`);
|
|
118
132
|
}
|
|
119
133
|
else {
|
|
120
|
-
console.log(` -
|
|
121
|
-
console.log(` -
|
|
122
|
-
console.log(` -
|
|
134
|
+
console.log(` - Library: @o-t-p-y/sdk`);
|
|
135
|
+
console.log(` - Send: otpy.sendOtp(phone) -> { request_id, ttl_seconds }`);
|
|
136
|
+
console.log(` - Verify: otpy.verifyOtp(phone, code) -> { verified: true }`);
|
|
123
137
|
}
|
|
124
138
|
}
|
|
125
139
|
if (info.framework === "php-generic") {
|
|
126
140
|
console.log(`
|
|
127
|
-
|
|
128
|
-
|
|
141
|
+
For the full manual integration guide, see https://otpy.ir/docs
|
|
142
|
+
Dashboard & live stats: https://dash.otpy.ir
|
|
129
143
|
`);
|
|
130
144
|
}
|
|
131
145
|
else if (info.framework === "php-laravel") {
|
|
132
146
|
console.log(`
|
|
133
|
-
🎉
|
|
147
|
+
🎉 Integration complete!
|
|
134
148
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
149
|
+
Next steps:
|
|
150
|
+
1. Start the dev server: php artisan serve
|
|
151
|
+
2. Test send: curl -X POST http://localhost:8000/api/auth/otp/send -H "Content-Type: application/json" -d '{"phone":"09123456789"}'
|
|
152
|
+
3. Dashboard & live stats: https://dash.otpy.ir
|
|
139
153
|
`);
|
|
140
154
|
}
|
|
141
155
|
else {
|
|
142
156
|
console.log(`
|
|
143
|
-
🎉
|
|
157
|
+
🎉 Integration complete!
|
|
144
158
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
159
|
+
Next steps:
|
|
160
|
+
1. Install the SDK: npm install @o-t-p-y/sdk
|
|
161
|
+
2. Send a test SMS: npx @o-t-p-y/cli test 09123456789
|
|
162
|
+
3. Dashboard & live stats: https://dash.otpy.ir
|
|
149
163
|
`);
|
|
150
164
|
}
|
|
151
165
|
}
|
|
152
166
|
async function runTest() {
|
|
153
167
|
const phone = args[1];
|
|
154
168
|
if (!phone || !/^09\d{9}$/.test(phone)) {
|
|
155
|
-
|
|
169
|
+
// Error lines stay on stdout (behavior preserved); only the spinner uses stderr.
|
|
170
|
+
console.log("❌ Error: a valid mobile number is required. Example: npx @o-t-p-y/cli test 09123456789");
|
|
156
171
|
process.exit(1);
|
|
157
172
|
}
|
|
158
173
|
const info = detectProject(process.cwd());
|
|
159
174
|
const apiKey = getExistingEnvKey(info.envFilePath);
|
|
160
175
|
if (!apiKey) {
|
|
161
|
-
console.log("❌
|
|
176
|
+
console.log("❌ OTPY_API_KEY not found in .env — run npx @o-t-p-y/cli init first.");
|
|
162
177
|
process.exit(1);
|
|
163
178
|
}
|
|
164
|
-
|
|
179
|
+
const s = spinner(`🚀 Sending test OTP to ${phone}...`);
|
|
165
180
|
try {
|
|
166
181
|
const res = await fetch("https://api.otpy.ir/v1/otp/send", {
|
|
167
182
|
method: "POST",
|
|
@@ -170,46 +185,53 @@ async function runTest() {
|
|
|
170
185
|
"content-type": "application/json",
|
|
171
186
|
},
|
|
172
187
|
body: JSON.stringify({ phone }),
|
|
188
|
+
signal: AbortSignal.timeout(10_000),
|
|
173
189
|
});
|
|
174
190
|
const data = (await res.json());
|
|
191
|
+
s.stop();
|
|
175
192
|
if (res.ok) {
|
|
176
|
-
console.log(
|
|
177
|
-
console.log(`
|
|
178
|
-
console.log(`
|
|
193
|
+
console.log(`✅ SMS sent!`);
|
|
194
|
+
console.log(` Request ID: ${data.request_id}`);
|
|
195
|
+
console.log(` Billing: ${data.free ? "daily free quota" : "paid credit"}`);
|
|
179
196
|
}
|
|
180
197
|
else {
|
|
181
|
-
console.log(`❌
|
|
198
|
+
console.log(`❌ Failed to send SMS: ${data.error || res.statusText}`);
|
|
182
199
|
}
|
|
183
200
|
}
|
|
184
201
|
catch (err) {
|
|
185
|
-
|
|
202
|
+
s.stop();
|
|
203
|
+
console.log(`❌ Network error: ${String(err)}`);
|
|
186
204
|
}
|
|
187
205
|
}
|
|
188
206
|
async function runUsage() {
|
|
189
207
|
const info = detectProject(process.cwd());
|
|
190
208
|
const apiKey = getExistingEnvKey(info.envFilePath);
|
|
191
209
|
if (!apiKey) {
|
|
192
|
-
console.log("❌
|
|
210
|
+
console.log("❌ OTPY_API_KEY not found in .env — run npx @o-t-p-y/cli init first.");
|
|
193
211
|
process.exit(1);
|
|
194
212
|
}
|
|
213
|
+
const s = spinner(`📊 Fetching usage...`);
|
|
195
214
|
try {
|
|
196
215
|
const res = await fetch("https://api.otpy.ir/v1/usage", {
|
|
197
216
|
method: "GET",
|
|
198
217
|
headers: { authorization: `Bearer ${apiKey}` },
|
|
218
|
+
signal: AbortSignal.timeout(10_000),
|
|
199
219
|
});
|
|
200
220
|
const data = (await res.json());
|
|
221
|
+
s.stop();
|
|
201
222
|
if (res.ok) {
|
|
202
|
-
console.log(`📊
|
|
203
|
-
console.log(`
|
|
204
|
-
console.log(`
|
|
205
|
-
console.log(`
|
|
223
|
+
console.log(`📊 Today's usage:`);
|
|
224
|
+
console.log(` Free quota used: ${data.free_used_today} of ${data.free_quota_today}`);
|
|
225
|
+
console.log(` Paid SMS: ${data.paid_today}`);
|
|
226
|
+
console.log(` Daily limit: ${data.daily_limit ? data.daily_limit : "unlimited"}`);
|
|
206
227
|
}
|
|
207
228
|
else {
|
|
208
|
-
console.log(`❌
|
|
229
|
+
console.log(`❌ Failed to fetch usage.`);
|
|
209
230
|
}
|
|
210
231
|
}
|
|
211
232
|
catch (err) {
|
|
212
|
-
|
|
233
|
+
s.stop();
|
|
234
|
+
console.log(`❌ Network error: ${String(err)}`);
|
|
213
235
|
}
|
|
214
236
|
}
|
|
215
237
|
if (command === "--version" || command === "-v") {
|
|
@@ -218,12 +240,12 @@ if (command === "--version" || command === "-v") {
|
|
|
218
240
|
}
|
|
219
241
|
if (command === "--help" || command === "-h") {
|
|
220
242
|
console.log(`
|
|
221
|
-
|
|
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
|
|
243
|
+
Usage: npx @o-t-p-y/cli <command>
|
|
244
|
+
npx @o-t-p-y/cli init Set up your project and generate integration files
|
|
245
|
+
npx @o-t-p-y/cli init --ai Set up with AI assistant instructions
|
|
246
|
+
npx @o-t-p-y/cli test <phone> Send a test OTP SMS to any number
|
|
247
|
+
npx @o-t-p-y/cli usage Show today's usage and quota
|
|
248
|
+
npx @o-t-p-y/cli --version CLI version
|
|
227
249
|
`);
|
|
228
250
|
process.exit(0);
|
|
229
251
|
}
|
|
@@ -237,7 +259,7 @@ else if (command === "usage") {
|
|
|
237
259
|
runUsage().catch(console.error);
|
|
238
260
|
}
|
|
239
261
|
else {
|
|
240
|
-
console.log(
|
|
262
|
+
console.log(`Unknown command: ${command}\nRun npx @o-t-p-y/cli --help for usage.`);
|
|
241
263
|
process.exit(1);
|
|
242
264
|
}
|
|
243
265
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,eAAe,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/templates.js
CHANGED
|
@@ -391,6 +391,9 @@ def verify_otp(req: VerifyOtpRequest):
|
|
|
391
391
|
`;
|
|
392
392
|
return [{ path: "routers/otp.py", content: code }];
|
|
393
393
|
}
|
|
394
|
+
// Printed to the terminal via index.ts — keep this snippet ASCII-only so the
|
|
395
|
+
// CLI's English-only output invariant holds. Never print other template
|
|
396
|
+
// contents (they carry intentional Persian end-user error strings).
|
|
394
397
|
export const phpLaravelRoutesSnippet = `Route::post('/auth/otp/send', [OtpController::class, 'send']);
|
|
395
398
|
Route::post('/auth/otp/verify', [OtpController::class, 'verify']);
|
|
396
399
|
`;
|
|
@@ -511,6 +514,30 @@ func (c *OtpClient) Send(phone string) (map[string]any, error) {
|
|
|
511
514
|
json.NewDecoder(resp.Body).Decode(&result)
|
|
512
515
|
return result, nil
|
|
513
516
|
}
|
|
517
|
+
|
|
518
|
+
func (c *OtpClient) Verify(phone, code string) (bool, error) {
|
|
519
|
+
payload, _ := json.Marshal(map[string]string{"phone": phone, "code": code})
|
|
520
|
+
req, _ := http.NewRequest("POST", c.BaseUrl+"/v1/otp/verify", bytes.NewBuffer(payload))
|
|
521
|
+
req.Header.Set("Authorization", "Bearer "+c.ApiKey)
|
|
522
|
+
req.Header.Set("Content-Type", "application/json")
|
|
523
|
+
|
|
524
|
+
resp, err := http.DefaultClient.Do(req)
|
|
525
|
+
if err != nil {
|
|
526
|
+
return false, err
|
|
527
|
+
}
|
|
528
|
+
defer resp.Body.Close()
|
|
529
|
+
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
530
|
+
return false, fmt.Errorf("otpy verify: HTTP %s", resp.Status)
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
var result struct {
|
|
534
|
+
Verified bool \`json:"verified"\`
|
|
535
|
+
}
|
|
536
|
+
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
|
537
|
+
return false, err
|
|
538
|
+
}
|
|
539
|
+
return result.Verified, nil
|
|
540
|
+
}
|
|
514
541
|
`;
|
|
515
542
|
return [{ path: "pkg/otpy/client.go", content: code }];
|
|
516
543
|
}
|
package/dist/templates.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"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"}
|
package/dist/ui.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const BANNER_TEXT = "\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 OTPy.ir - Smart OTP SMS (Iran) \u2502\n\u2502 Fast, affordable. No contracts, no dedicated line. \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n";
|
|
2
|
+
export declare const BRAILLE_FRAMES = "\u280B\u2819\u2839\u2838\u283C\u2834\u2826\u2827\u2807\u280F";
|
|
3
|
+
export declare const ASCII_FRAMES = "|/-\\";
|
|
4
|
+
export declare function printBanner(): void;
|
|
5
|
+
/**
|
|
6
|
+
* True only for a real terminal that can animate safely. `OTPY_NO_SPINNER=1`
|
|
7
|
+
* is the explicit escape hatch for PTY-wrapping agent harnesses where isTTY is
|
|
8
|
+
* true but frames would pollute captured transcripts.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isInteractive(): boolean;
|
|
11
|
+
export interface Spinner {
|
|
12
|
+
succeed(text?: string): void;
|
|
13
|
+
fail(text?: string): void;
|
|
14
|
+
stop(): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Start a spinner. Non-interactive environments (pipes, CI, AI-agent TUIs)
|
|
18
|
+
* degrade to one static stderr line with no frames, `\r`, or ANSI.
|
|
19
|
+
*/
|
|
20
|
+
export declare function spinner(text: string): Spinner;
|
package/dist/ui.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Terminal output helpers. Zero runtime deps (AGENTS.md hard rule).
|
|
2
|
+
//
|
|
3
|
+
// Stream convention: progress (spinner) goes to stderr, data and results go to
|
|
4
|
+
// stdout. That keeps `otpy-cli init | tee log` clean in every mode and lets the
|
|
5
|
+
// no-`\r` / no-ANSI test invariants hold on both streams.
|
|
6
|
+
export const BANNER_TEXT = `
|
|
7
|
+
┌──────────────────────────────────────────────────────┐
|
|
8
|
+
│ OTPy.ir - Smart OTP SMS (Iran) │
|
|
9
|
+
│ Fast, affordable. No contracts, no dedicated line. │
|
|
10
|
+
└──────────────────────────────────────────────────────┘
|
|
11
|
+
`;
|
|
12
|
+
// U+28xx braille — exactly ten frames. Do not substitute look-alike U+29xx
|
|
13
|
+
// glyphs; the ui test pins the code-point range to catch copy-paste drift.
|
|
14
|
+
export const BRAILLE_FRAMES = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏";
|
|
15
|
+
export const ASCII_FRAMES = "|/-\\";
|
|
16
|
+
export function printBanner() {
|
|
17
|
+
console.log(BANNER_TEXT);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* True only for a real terminal that can animate safely. `OTPY_NO_SPINNER=1`
|
|
21
|
+
* is the explicit escape hatch for PTY-wrapping agent harnesses where isTTY is
|
|
22
|
+
* true but frames would pollute captured transcripts.
|
|
23
|
+
*/
|
|
24
|
+
export function isInteractive() {
|
|
25
|
+
return (Boolean(process.stderr.isTTY) &&
|
|
26
|
+
process.env.TERM !== "dumb" &&
|
|
27
|
+
!process.env.CI &&
|
|
28
|
+
!process.env.OTPY_NO_SPINNER);
|
|
29
|
+
}
|
|
30
|
+
function spinnerFrames() {
|
|
31
|
+
// Legacy Windows conhost raster fonts lack braille / VT processing.
|
|
32
|
+
const legacyWindows = process.platform === "win32" && !process.env.WT_SESSION && !process.env.TERM_PROGRAM;
|
|
33
|
+
return (legacyWindows ? ASCII_FRAMES : BRAILLE_FRAMES).split("");
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Start a spinner. Non-interactive environments (pipes, CI, AI-agent TUIs)
|
|
37
|
+
* degrade to one static stderr line with no frames, `\r`, or ANSI.
|
|
38
|
+
*/
|
|
39
|
+
export function spinner(text) {
|
|
40
|
+
const stream = process.stderr;
|
|
41
|
+
if (!isInteractive()) {
|
|
42
|
+
stream.write(`${text}\n`);
|
|
43
|
+
let finished = false;
|
|
44
|
+
const finish = (final) => {
|
|
45
|
+
if (finished)
|
|
46
|
+
return;
|
|
47
|
+
finished = true;
|
|
48
|
+
stream.write(`${final}\n`);
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
succeed(final) {
|
|
52
|
+
finish(final ?? text);
|
|
53
|
+
},
|
|
54
|
+
fail(final) {
|
|
55
|
+
finish(final ?? text);
|
|
56
|
+
},
|
|
57
|
+
stop() {
|
|
58
|
+
finished = true;
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const frames = spinnerFrames();
|
|
63
|
+
const maxWidth = Math.max(0, (stream.columns ?? 80) - 4);
|
|
64
|
+
const render = (line) => stream.write(`\r${line.slice(0, maxWidth)}`);
|
|
65
|
+
const clear = () => stream.write("\r\x1b[K");
|
|
66
|
+
let frameIndex = 0;
|
|
67
|
+
render(`${frames[0]} ${text}`);
|
|
68
|
+
const interval = setInterval(() => {
|
|
69
|
+
frameIndex = (frameIndex + 1) % frames.length;
|
|
70
|
+
render(`${frames[frameIndex]} ${text}`);
|
|
71
|
+
}, 80);
|
|
72
|
+
// Safe: a pending fetch holds its own libuv handle, so unref only means the
|
|
73
|
+
// timer alone never keeps the process alive.
|
|
74
|
+
interval.unref();
|
|
75
|
+
let stopped = false;
|
|
76
|
+
const stop = () => {
|
|
77
|
+
if (stopped)
|
|
78
|
+
return;
|
|
79
|
+
stopped = true;
|
|
80
|
+
clearInterval(interval);
|
|
81
|
+
process.removeListener("SIGINT", onSigint);
|
|
82
|
+
clear();
|
|
83
|
+
};
|
|
84
|
+
const onSigint = () => {
|
|
85
|
+
stop();
|
|
86
|
+
process.exit(130);
|
|
87
|
+
};
|
|
88
|
+
process.once("SIGINT", onSigint);
|
|
89
|
+
const finish = (final) => {
|
|
90
|
+
if (stopped)
|
|
91
|
+
return;
|
|
92
|
+
stop();
|
|
93
|
+
stream.write(`${final}\n`);
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
succeed(final) {
|
|
97
|
+
finish(final ?? text);
|
|
98
|
+
},
|
|
99
|
+
fail(final) {
|
|
100
|
+
finish(final ?? text);
|
|
101
|
+
},
|
|
102
|
+
stop,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=ui.js.map
|
package/dist/ui.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@o-t-p-y/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
|
-
"description": "npx
|
|
6
|
+
"description": "npx @o-t-p-y/cli init — one-command OTPy integration (framework detection, code patching, AI mode).",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|