tsp-scale-sdk 1.2.0 → 1.2.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/README.md CHANGED
@@ -7,7 +7,7 @@ Official Node.js SDK for TSP Scale.
7
7
  Initialize your project in seconds. This will link your project, create a secure hidden config, and add it to your `.gitignore` automatically.
8
8
 
9
9
  ```bash
10
- npx tsp-scale init
10
+ npx tsp-scale-sdk init
11
11
  ```
12
12
 
13
13
  ### Manual Installation
package/bin/tsp-scale.js CHANGED
@@ -2,12 +2,11 @@
2
2
 
3
3
  const { execSync } = require('child_process');
4
4
  const path = require('path');
5
+ const os = require('os');
6
+ const fs = require('fs');
5
7
 
6
8
  try {
7
- // We reuse the curl CLI logic if available, or implement a lightweight version here
8
- // For simplicity, we'll just implement the init logic here for the SDK
9
9
  const readline = require('readline');
10
- const fs = require('fs');
11
10
  const crypto = require('crypto');
12
11
  const https = require('https');
13
12
 
@@ -24,7 +23,13 @@ try {
24
23
  }, res => {
25
24
  let body = '';
26
25
  res.on('data', chunk => body += chunk);
27
- res.on('end', () => resolve({ ok: res.statusCode < 300, json: () => JSON.parse(body) }));
26
+ res.on('end', () => {
27
+ try {
28
+ resolve({ ok: res.statusCode < 300, json: () => JSON.parse(body) });
29
+ } catch (e) {
30
+ resolve({ ok: false, json: () => ({ message: 'Invalid JSON response from server' }) });
31
+ }
32
+ });
28
33
  });
29
34
  req.on('error', reject);
30
35
  req.write(JSON.stringify(data));
@@ -34,17 +39,29 @@ try {
34
39
 
35
40
  async function init() {
36
41
  console.log("\nšŸš€ TSP Scale SDK - Initializing Project\n");
37
- const apiKey = await ask("šŸ”‘ Enter your API Key: ");
38
- if (!apiKey) return console.error("Error: API Key is required.");
39
42
 
40
- const projectIdentifier = await ask("šŸ“‚ Enter Project Name: ");
41
43
  const projectId = crypto.createHash('md5').update(process.cwd()).digest('hex');
44
+ const localConfigPath = path.join(process.cwd(), '.tspscale');
45
+ let existingConfig = null;
46
+
47
+ if (fs.existsSync(localConfigPath)) {
48
+ try {
49
+ existingConfig = JSON.parse(fs.readFileSync(localConfigPath, 'utf8'));
50
+ } catch (e) {}
51
+ }
52
+
53
+ const apiKey = await ask(`šŸ”‘ Enter your API Key${existingConfig ? ` (Current: ${existingConfig.apiKey.substring(0, 12)}...)` : ''}: `);
54
+ const finalKey = apiKey || (existingConfig ? existingConfig.apiKey : null);
55
+
56
+ if (!finalKey) return console.error("āŒ Error: API Key is required.");
57
+
58
+ const projectIdentifier = await ask("šŸ“‚ Enter Project Name: ");
42
59
 
43
60
  console.log("ā³ Verifying with server...");
44
61
 
45
62
  try {
46
63
  const res = await post("https://api.tspscale.in/api/v1/apikeys/verify", {
47
- key: apiKey,
64
+ key: finalKey,
48
65
  projectId,
49
66
  projectIdentifier: projectIdentifier || "NodeJS Project"
50
67
  });
@@ -54,10 +71,10 @@ try {
54
71
  // 1. Save to Global Vault (Fallback)
55
72
  const configDir = path.join(os.homedir(), '.tsp-scale');
56
73
  if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true });
57
- fs.writeFileSync(path.join(configDir, 'config.json'), JSON.stringify({ apiKey }, null, 2));
74
+ fs.writeFileSync(path.join(configDir, 'config.json'), JSON.stringify({ apiKey: finalKey }, null, 2));
58
75
 
59
76
  // 2. Save to Local Hidden Config (.tspscale) - Primary
60
- fs.writeFileSync(path.join(process.cwd(), '.tspscale'), JSON.stringify({ apiKey, projectId }, null, 2));
77
+ fs.writeFileSync(localConfigPath, JSON.stringify({ apiKey: finalKey, projectId }, null, 2));
61
78
 
62
79
  // 3. Auto-GitIgnore
63
80
  const gitignorePath = path.join(process.cwd(), '.gitignore');
@@ -79,34 +96,50 @@ try {
79
96
  console.log("When you deploy to Railway, Vercel, or a VPS,");
80
97
  console.log("add these two Environment Variables:");
81
98
  console.log("");
82
- console.log(` TSP_API_KEY = ${apiKey}`);
99
+ console.log(` TSP_API_KEY = ${finalKey}`);
83
100
  console.log(` TSP_PROJECT_ID = ${projectId}`);
84
101
  console.log("-------------------------------------------\n");
85
102
 
86
- const install = await ask("šŸ“¦ Would you like to install the 'tsp-scale-sdk' in this project? (y/n): ");
87
- if (install.toLowerCase() === 'y') {
88
- console.log("ā³ Installing...");
89
- try {
90
- execSync('npm install tsp-scale-sdk', { stdio: 'inherit' });
91
- console.log("\nāœ… SDK installed successfully!");
92
- } catch (e) {
93
- console.error("\nāŒ Installation failed. Please run 'npm install tsp-scale-sdk' manually.");
103
+ // --- SMART INSTALL CHECK ---
104
+ let isInstalled = false;
105
+ try {
106
+ const pkgJson = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8'));
107
+ if (pkgJson.dependencies && pkgJson.dependencies['tsp-scale-sdk']) isInstalled = true;
108
+ if (pkgJson.devDependencies && pkgJson.devDependencies['tsp-scale-sdk']) isInstalled = true;
109
+ } catch (e) {}
110
+
111
+ if (isInstalled) {
112
+ console.log("šŸ“¦ SDK already detected in package.json. Skipping installation. āœ…\n");
113
+ } else {
114
+ const install = await ask("šŸ“¦ Would you like to install the 'tsp-scale-sdk' in this project? (y/n): ");
115
+ if (install.toLowerCase() === 'y') {
116
+ console.log("ā³ Installing...");
117
+ try {
118
+ execSync('npm install tsp-scale-sdk', { stdio: 'inherit' });
119
+ console.log("\nāœ… SDK installed successfully!");
120
+ } catch (e) {
121
+ console.error("\nāŒ Installation failed. Please run 'npm install tsp-scale-sdk' manually.");
122
+ }
94
123
  }
95
124
  }
96
125
 
97
- const example = await ask("šŸ“„ Would you like to generate a sample 'tsp-test.js' script? (y/n): ");
98
- if (example.toLowerCase() === 'y') {
99
- const sampleCode = `const { TspScaleClient } = require('tsp-scale-sdk');
100
- require('dotenv').config();
126
+ const examplePath = path.join(process.cwd(), "tsp-test.js");
127
+ if (fs.existsSync(examplePath)) {
128
+ console.log("šŸ“„ Sample 'tsp-test.js' already exists. Skipping generator. āœ…\n");
129
+ } else {
130
+ const example = await ask("šŸ“„ Would you like to generate a sample 'tsp-test.js' script? (y/n): ");
131
+ if (example.toLowerCase() === 'y') {
132
+ const sampleCode = `const { TspScaleClient } = require('tsp-scale-sdk');
101
133
 
102
- const client = new TspScaleClient(process.env.TSP_API_KEY);
134
+ // Smart Auth: Automatically uses .tspscale or environment variables
135
+ const client = new TspScaleClient();
103
136
 
104
137
  async function main() {
105
138
  console.log("Sending test email...");
106
139
  try {
107
140
  const res = await client.sendEmail({
108
- from: "support@yourdomain.com", // Replace with your verified sender
109
- to: "recipient@example.com",
141
+ // 'from' is optional if your key is locked to a sender identity
142
+ to: "recipient@example.com",
110
143
  subject: "TSP Scale Test",
111
144
  html: "<h1>It works!</h1>"
112
145
  });
@@ -117,8 +150,9 @@ async function main() {
117
150
  }
118
151
 
119
152
  main();`;
120
- fs.writeFileSync(path.join(process.cwd(), "tsp-test.js"), sampleCode);
121
- console.log("\nāœ… 'tsp-test.js' created. Run it with: node tsp-test.js");
153
+ fs.writeFileSync(examplePath, sampleCode);
154
+ console.log("\nāœ… 'tsp-test.js' created. Run it with: node tsp-test.js");
155
+ }
122
156
  }
123
157
  } catch (err) {
124
158
  console.error(`\nāŒ Error: ${err.message}`);
@@ -129,7 +163,7 @@ main();`;
129
163
  if (command === 'init') {
130
164
  init();
131
165
  } else {
132
- console.log("Usage: npx tsp-scale init");
166
+ console.log("Usage: npx tsp-scale-sdk init");
133
167
  }
134
168
 
135
169
  } catch (err) {
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var d=require("crypto"),m="1.2.0",y={prod:"https://api.tspscale.in/api/v1",staging:"https://staging-api.tspscale.in/api/v1",local:"http://localhost:4000/api/v1"};function g(l){if(l.baseUrl)return l.baseUrl;let t=(l.env||"prod").toLowerCase();return y[t]||y.prod}var f=class{constructor(t){let s={};typeof t=="string"?s={apiKey:t}:s=t||{};let e=require("fs"),o=require("path"),a=require("os"),n=this._loadLocalConfig();if(this.apiKey=s.apiKey||process.env.TSP_API_KEY||n.apiKey||this._loadGlobalKey(),this.projectId=s.projectId||process.env.TSP_PROJECT_ID||n.projectId,this.apiKey||console.warn("\u26A0\uFE0F TSP Scale: No API Key found. Run 'npx tsp-scale init'."),this.baseUrl=g(s).replace(/\/+$/,""),this.timeoutMs=s.timeoutMs||15e3,this.fetchImpl=s.fetchImpl||globalThis.fetch,typeof this.fetchImpl!="function")throw new Error("Fetch implementation is not available. Use Node 18+ or pass fetchImpl.")}_loadLocalConfig(){try{let t=require("fs"),e=require("path").join(process.cwd(),".tspscale");if(t.existsSync(e))return JSON.parse(t.readFileSync(e,"utf8"))}catch{}return{}}_loadGlobalKey(){try{let t=require("fs"),s=require("path"),e=require("os"),o=s.join(e.homedir(),".tsp-scale","config.json");if(t.existsSync(o))return JSON.parse(t.readFileSync(o,"utf8")).apiKey}catch{}return null}async sendEmail(t){let s="/emails/send",e=`${this.baseUrl}${s}`,o=JSON.stringify(t||{}),a=Date.now().toString(),n=d.randomBytes(16).toString("hex"),h=this._sign({timestamp:a,nonce:n,method:"POST",path:s,body:o}),p=new AbortController,u=setTimeout(()=>p.abort(),this.timeoutMs);try{let i=await this.fetchImpl(e,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this.apiKey,"x-tsp-client":`tsp-scale-sdk/${m}`,"x-tsp-timestamp":a,"x-tsp-nonce":n,"x-tsp-signature":h,...this.projectId?{"x-tsp-project-id":this.projectId}:{}},body:o,signal:p.signal}),r=await i.json().catch(()=>({}));if(!i.ok){let c=new Error(r?.error||`Request failed with status ${i.status}`);throw c.status=i.status,c.response=r,c}return r}finally{clearTimeout(u)}}async sendWhatsApp(t){let s="/whatsapp/messages/send",e=`${this.baseUrl}${s}`,o=JSON.stringify(t||{}),a=Date.now().toString(),n=d.randomBytes(16).toString("hex"),h=this._sign({timestamp:a,nonce:n,method:"POST",path:s,body:o}),p=new AbortController,u=setTimeout(()=>p.abort(),this.timeoutMs);try{let i=await this.fetchImpl(e,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this.apiKey,"x-tsp-client":`tsp-scale-sdk/${m}`,"x-tsp-timestamp":a,"x-tsp-nonce":n,"x-tsp-signature":h},body:o,signal:p.signal}),r=await i.json().catch(()=>({}));if(!i.ok){let c=new Error(r?.error||`Request failed with status ${i.status}`);throw c.status=i.status,c.response=r,c}return r}finally{clearTimeout(u)}}_sign({timestamp:t,nonce:s,method:e,path:o,body:a}){let n=`${t}.${s}.${e}.${o}.${a}`;return d.createHmac("sha256",this.apiKey).update(n).digest("hex")}};module.exports={TspScaleClient:f};
1
+ var d=require("crypto"),m="1.2.2",y={prod:"https://api.tspscale.in/api/v1",staging:"https://staging-api.tspscale.in/api/v1",local:"http://localhost:4000/api/v1"};function g(l){if(l.baseUrl)return l.baseUrl;let t=(l.env||"prod").toLowerCase();return y[t]||y.prod}var f=class{constructor(t){let s={};typeof t=="string"?s={apiKey:t}:s=t||{};let e=require("fs"),o=require("path"),a=require("os"),n=this._loadLocalConfig();if(this.apiKey=s.apiKey||process.env.TSP_API_KEY||n.apiKey||this._loadGlobalKey(),this.projectId=s.projectId||process.env.TSP_PROJECT_ID||n.projectId,this.apiKey||console.warn("\u26A0\uFE0F TSP Scale: No API Key found. Run 'npx tsp-scale init'."),this.baseUrl=g(s).replace(/\/+$/,""),this.timeoutMs=s.timeoutMs||15e3,this.fetchImpl=s.fetchImpl||globalThis.fetch,typeof this.fetchImpl!="function")throw new Error("Fetch implementation is not available. Use Node 18+ or pass fetchImpl.")}_loadLocalConfig(){try{let t=require("fs"),e=require("path").join(process.cwd(),".tspscale");if(t.existsSync(e))return JSON.parse(t.readFileSync(e,"utf8"))}catch{}return{}}_loadGlobalKey(){try{let t=require("fs"),s=require("path"),e=require("os"),o=s.join(e.homedir(),".tsp-scale","config.json");if(t.existsSync(o))return JSON.parse(t.readFileSync(o,"utf8")).apiKey}catch{}return null}async sendEmail(t){let s="/emails/send",e=`${this.baseUrl}${s}`,o=JSON.stringify(t||{}),a=Date.now().toString(),n=d.randomBytes(16).toString("hex"),h=this._sign({timestamp:a,nonce:n,method:"POST",path:s,body:o}),p=new AbortController,u=setTimeout(()=>p.abort(),this.timeoutMs);try{let i=await this.fetchImpl(e,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this.apiKey,"x-tsp-client":`tsp-scale-sdk/${m}`,"x-tsp-timestamp":a,"x-tsp-nonce":n,"x-tsp-signature":h,...this.projectId?{"x-tsp-project-id":this.projectId}:{}},body:o,signal:p.signal}),r=await i.json().catch(()=>({}));if(!i.ok){let c=new Error(r?.error||`Request failed with status ${i.status}`);throw c.status=i.status,c.response=r,c}return r}finally{clearTimeout(u)}}async sendWhatsApp(t){let s="/whatsapp/messages/send",e=`${this.baseUrl}${s}`,o=JSON.stringify(t||{}),a=Date.now().toString(),n=d.randomBytes(16).toString("hex"),h=this._sign({timestamp:a,nonce:n,method:"POST",path:s,body:o}),p=new AbortController,u=setTimeout(()=>p.abort(),this.timeoutMs);try{let i=await this.fetchImpl(e,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this.apiKey,"x-tsp-client":`tsp-scale-sdk/${m}`,"x-tsp-timestamp":a,"x-tsp-nonce":n,"x-tsp-signature":h},body:o,signal:p.signal}),r=await i.json().catch(()=>({}));if(!i.ok){let c=new Error(r?.error||`Request failed with status ${i.status}`);throw c.status=i.status,c.response=r,c}return r}finally{clearTimeout(u)}}_sign({timestamp:t,nonce:s,method:e,path:o,body:a}){let n=`${t}.${s}.${e}.${o}.${a}`;return d.createHmac("sha256",this.apiKey).update(n).digest("hex")}};module.exports={TspScaleClient:f};
2
2
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsp-scale-sdk",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Official Node.js client for TSP Scale Email and WhatsApp API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",