test-bdk-cli 1.0.6 → 1.0.8
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 +21 -2
- package/dist/commands/run.js +66 -1
- package/dist/lib/localstore.js +208 -0
- package/package.json +18 -16
package/README.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
-
# BoldDesk
|
|
1
|
+
# BoldDesk Marketplace SDK CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The BoldDesk Marketplace SDK CLI enables seamless integration of the BoldDesk marketplace tools into your development workflow. It provides a command-line interface to create, validate, pack, and publish BoldDesk apps with full TypeScript support.
|
|
4
|
+
|
|
5
|
+
📘 Documentation
|
|
6
|
+
👉 Visit the [BoldDesk Support Portal] for complete setup guides and API references.
|
|
7
|
+
|
|
8
|
+
📝 License
|
|
9
|
+
The BoldDesk Marketplace SDK CLI is protected by See [LICENSE](https://www.bolddesk.com/legal/terms-of-use) for licensing details.
|
|
10
|
+
|
|
11
|
+
# Commands
|
|
12
|
+
|
|
13
|
+
- `bdk apps:create` - create a new BoldDesk app
|
|
14
|
+
- `bdk apps:pack` - package a BoldDesk app
|
|
15
|
+
- `bdk apps:run` - run a BoldDesk app locally
|
|
16
|
+
- `bdk apps:test` - test a BoldDesk app
|
|
17
|
+
- `bdk apps:validate` - validate a BoldDesk app manifest
|
|
18
|
+
- `bdk apps:version` - display version information
|
|
19
|
+
|
|
20
|
+
Readme
|
|
21
|
+
Keywords
|
|
22
|
+
bolddesk-marketplace-sdkcli-sdkcommand-line-tools
|
package/dist/commands/run.js
CHANGED
|
@@ -38,6 +38,7 @@ const http = __importStar(require("http"));
|
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
40
|
const child_process_1 = require("child_process");
|
|
41
|
+
const localstore_1 = require("../lib/localstore");
|
|
41
42
|
function registerRun(program) {
|
|
42
43
|
program
|
|
43
44
|
.command('run [source]')
|
|
@@ -56,8 +57,71 @@ function registerRun(program) {
|
|
|
56
57
|
console.error(`manifest.json not found in ${sourceDir}`);
|
|
57
58
|
process.exit(1);
|
|
58
59
|
}
|
|
59
|
-
//
|
|
60
|
+
// Initialize LocalStore for local database operations
|
|
61
|
+
const localStore = new localstore_1.LocalStore(path.join(sourceDir, '.bdk/localstore'));
|
|
62
|
+
// Handler for database operations
|
|
63
|
+
const handleDBRequest = (operation, key, value) => {
|
|
64
|
+
try {
|
|
65
|
+
switch (operation) {
|
|
66
|
+
case 'set':
|
|
67
|
+
return localStore.store(key, value);
|
|
68
|
+
case 'get':
|
|
69
|
+
return localStore.fetch(key);
|
|
70
|
+
case 'update':
|
|
71
|
+
return localStore.update(key, value);
|
|
72
|
+
case 'delete':
|
|
73
|
+
return localStore.delete(key);
|
|
74
|
+
default:
|
|
75
|
+
throw new Error(`Unknown database operation: ${operation}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error(`[DB] ERROR (${operation} ${key}): ${error.message}`);
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
// Create HTTP server
|
|
60
84
|
const server = http.createServer((req, res) => {
|
|
85
|
+
var _a;
|
|
86
|
+
// Add CORS headers
|
|
87
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
88
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
89
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
90
|
+
// Handle OPTIONS requests
|
|
91
|
+
if (req.method === 'OPTIONS') {
|
|
92
|
+
res.writeHead(200);
|
|
93
|
+
res.end();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Handle database API requests
|
|
97
|
+
if (((_a = req.url) === null || _a === void 0 ? void 0 : _a.startsWith('/api/db')) && req.method === 'POST') {
|
|
98
|
+
let body = '';
|
|
99
|
+
req.on('data', (chunk) => {
|
|
100
|
+
body += chunk.toString();
|
|
101
|
+
});
|
|
102
|
+
req.on('error', (error) => {
|
|
103
|
+
console.error(`[DB] Request error:`, error);
|
|
104
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
105
|
+
res.end(JSON.stringify({ success: false, error: 'Request error' }));
|
|
106
|
+
});
|
|
107
|
+
req.on('end', () => {
|
|
108
|
+
try {
|
|
109
|
+
if (!body)
|
|
110
|
+
throw new Error('Empty request body');
|
|
111
|
+
const payload = JSON.parse(body);
|
|
112
|
+
const result = handleDBRequest(payload.operation, payload.key, payload.value);
|
|
113
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
114
|
+
res.end(JSON.stringify({ success: true, data: result }));
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
console.error(`[DB] Error:`, error);
|
|
118
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
119
|
+
res.end(JSON.stringify({ success: false, error: error.message }));
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// Handle static file requests
|
|
61
125
|
let filePath = req.url || '/';
|
|
62
126
|
if (filePath === '/') {
|
|
63
127
|
filePath = '/assets/iframe.html';
|
|
@@ -123,6 +187,7 @@ function registerRun(program) {
|
|
|
123
187
|
console.log(`✅ Dev server started on http://localhost:${port} (env=${env})`);
|
|
124
188
|
console.log(`📁 Serving from: ${sourceDir}`);
|
|
125
189
|
console.log(`📄 Iframe: http://localhost:${port}/assets/iframe.html`);
|
|
190
|
+
console.log(`💾 Database: Local storage at ${localStore.getFilePath()}`);
|
|
126
191
|
console.log(`\nPress Ctrl+C to stop the server\n`);
|
|
127
192
|
// Open browser if --open flag is set
|
|
128
193
|
if (opts.open) {
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* BoldDesk LocalStore - Persistent local data storage during development
|
|
4
|
+
*
|
|
5
|
+
* Similar to Freshdesk FDK's DataStore (lib/utils/data.js)
|
|
6
|
+
* Stores key-value data in .bolddesk/localstore JSON file
|
|
7
|
+
*
|
|
8
|
+
* Key Format: '1234' or '1234:{jiraId:9878}' (first part is the key)
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.LocalStore = void 0;
|
|
45
|
+
const fs = __importStar(require("fs"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
/**
|
|
48
|
+
* LocalStore class for managing persistent local storage
|
|
49
|
+
* Mirrors Freshdesk's DataStore functionality
|
|
50
|
+
*/
|
|
51
|
+
class LocalStore {
|
|
52
|
+
constructor(filePath = '.bdk/localstore') {
|
|
53
|
+
this.data = {};
|
|
54
|
+
this.filePath = filePath;
|
|
55
|
+
this.ensureStore();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Ensure localstore folder and file exist
|
|
59
|
+
* Creates folder and file if they don't exist
|
|
60
|
+
* Handles case where folder is deleted mid-operation
|
|
61
|
+
*/
|
|
62
|
+
ensureStore() {
|
|
63
|
+
const folder = path.dirname(this.filePath);
|
|
64
|
+
try {
|
|
65
|
+
// Create folder if it doesn't exist
|
|
66
|
+
if (!fs.existsSync(folder)) {
|
|
67
|
+
fs.mkdirSync(folder, { recursive: true });
|
|
68
|
+
}
|
|
69
|
+
// Create file if it doesn't exist
|
|
70
|
+
if (!fs.existsSync(this.filePath)) {
|
|
71
|
+
fs.writeFileSync(this.filePath, JSON.stringify({}));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
console.error(`[LocalStore] Error in ensureStore: ${error.message}`);
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Validate key format and constraints
|
|
81
|
+
* - Max 60 characters
|
|
82
|
+
* - Cannot be empty
|
|
83
|
+
* - Alphanumeric, dash, underscore, colon allowed
|
|
84
|
+
*/
|
|
85
|
+
validateKey(key) {
|
|
86
|
+
if (!key || typeof key !== 'string') {
|
|
87
|
+
throw new Error('The key cannot be blank');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Read localstore file from disk
|
|
92
|
+
* Returns parsed JSON object
|
|
93
|
+
* Returns empty object on error
|
|
94
|
+
*/
|
|
95
|
+
readLocalStore() {
|
|
96
|
+
try {
|
|
97
|
+
if (!fs.existsSync(this.filePath)) {
|
|
98
|
+
return {};
|
|
99
|
+
}
|
|
100
|
+
const content = fs.readFileSync(this.filePath, 'utf-8');
|
|
101
|
+
return JSON.parse(content);
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
console.error(`[LocalStore] Error reading file: ${e.message}`);
|
|
105
|
+
return {};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Write localstore file to disk
|
|
110
|
+
* Pretty-prints JSON for human readability
|
|
111
|
+
* Recreates folder if it was deleted
|
|
112
|
+
*/
|
|
113
|
+
writeLocalStore(data) {
|
|
114
|
+
try {
|
|
115
|
+
const folder = path.dirname(this.filePath);
|
|
116
|
+
// Explicitly ensure folder exists before writing
|
|
117
|
+
if (!fs.existsSync(folder)) {
|
|
118
|
+
fs.mkdirSync(folder, { recursive: true });
|
|
119
|
+
}
|
|
120
|
+
// Write the file
|
|
121
|
+
fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2));
|
|
122
|
+
}
|
|
123
|
+
catch (e) {
|
|
124
|
+
console.error(`[LocalStore] Error writing file: ${e.message}`);
|
|
125
|
+
throw e;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Store operation - SET key/value
|
|
130
|
+
* Stores data as-is without modification
|
|
131
|
+
*
|
|
132
|
+
* @param key Storage key (e.g., 'ticket-001')
|
|
133
|
+
* @param data Value to store (JSON object)
|
|
134
|
+
* @returns { Created: true }
|
|
135
|
+
*/
|
|
136
|
+
store(key, data) {
|
|
137
|
+
this.validateKey(key);
|
|
138
|
+
this.ensureStore();
|
|
139
|
+
const localStoreData = this.readLocalStore();
|
|
140
|
+
localStoreData[key] = data;
|
|
141
|
+
this.writeLocalStore(localStoreData);
|
|
142
|
+
return { Created: true };
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Fetch operation - GET key/value
|
|
146
|
+
* Retrieves stored data for a key
|
|
147
|
+
*
|
|
148
|
+
* @param key Storage key to retrieve
|
|
149
|
+
* @returns Stored data or undefined if not found
|
|
150
|
+
*/
|
|
151
|
+
fetch(key) {
|
|
152
|
+
const localStoreData = this.readLocalStore();
|
|
153
|
+
return localStoreData[key];
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Update operation - PATCH key with new values
|
|
157
|
+
* Merges attributes with existing data
|
|
158
|
+
*
|
|
159
|
+
* @param key Storage key to update
|
|
160
|
+
* @param attributes Object with fields to merge
|
|
161
|
+
* @returns { Updated: true }
|
|
162
|
+
*/
|
|
163
|
+
update(key, attributes) {
|
|
164
|
+
this.validateKey(key);
|
|
165
|
+
this.ensureStore();
|
|
166
|
+
const localStoreData = this.readLocalStore();
|
|
167
|
+
const existingRecord = localStoreData[key];
|
|
168
|
+
if (!existingRecord) {
|
|
169
|
+
throw new Error(`Record not found for key: ${key}`);
|
|
170
|
+
}
|
|
171
|
+
localStoreData[key] = { ...existingRecord, ...attributes };
|
|
172
|
+
this.writeLocalStore(localStoreData);
|
|
173
|
+
return { Updated: true };
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Delete operation - DELETE key
|
|
177
|
+
* Similar to Freshdesk DataStore.delete()
|
|
178
|
+
*
|
|
179
|
+
* @param key Storage key to delete
|
|
180
|
+
* @returns { Deleted: true }
|
|
181
|
+
*/
|
|
182
|
+
delete(key) {
|
|
183
|
+
this.ensureStore();
|
|
184
|
+
const localStoreData = this.readLocalStore();
|
|
185
|
+
delete localStoreData[key];
|
|
186
|
+
this.writeLocalStore(localStoreData);
|
|
187
|
+
return { Deleted: true };
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get the file path to localstore
|
|
191
|
+
*/
|
|
192
|
+
getFilePath() {
|
|
193
|
+
return this.filePath;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Get all stored data (for debugging)
|
|
197
|
+
*/
|
|
198
|
+
getAll() {
|
|
199
|
+
return this.readLocalStore();
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Clear all data from localstore
|
|
203
|
+
*/
|
|
204
|
+
clear() {
|
|
205
|
+
this.writeLocalStore({});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
exports.LocalStore = LocalStore;
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "test-bdk-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "test CLI",
|
|
5
5
|
"author": "@BoldDesk",
|
|
6
6
|
"bin": {
|
|
7
7
|
"bdk": "dist/index.js"
|
|
8
8
|
},
|
|
9
9
|
"npmRegistry": "https://registry.npmjs.org",
|
|
10
|
-
"license": "
|
|
10
|
+
"license": "SEE LICENSE IN README.md",
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "npx tsc -p tsconfig.json",
|
|
13
13
|
"dev": "ts-node src/index.ts",
|
|
@@ -15,25 +15,24 @@
|
|
|
15
15
|
"test": "jest"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"ajv": "^8.
|
|
19
|
-
"archiver": "^5.3.
|
|
20
|
-
"chokidar": "^3.
|
|
21
|
-
"commander": "^10.0.
|
|
22
|
-
"form-data": "^4.0.
|
|
23
|
-
"inquirer": "^9.
|
|
24
|
-
"node-fetch": "^2.
|
|
18
|
+
"ajv": "^8.20.0",
|
|
19
|
+
"archiver": "^5.3.2",
|
|
20
|
+
"chokidar": "^3.6.0",
|
|
21
|
+
"commander": "^10.0.1",
|
|
22
|
+
"form-data": "^4.0.5",
|
|
23
|
+
"inquirer": "^9.3.8",
|
|
24
|
+
"node-fetch": "^2.7.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/archiver": "^7.0.0",
|
|
28
|
-
"@types/commander": "^2.12.2",
|
|
29
28
|
"@types/inquirer": "^9.0.9",
|
|
30
29
|
"@types/jest": "^30.0.0",
|
|
31
|
-
"@types/node": "^
|
|
30
|
+
"@types/node": "^20.0.0",
|
|
32
31
|
"@types/node-fetch": "^2.6.13",
|
|
33
|
-
"jest": "^29.
|
|
34
|
-
"ts-jest": "^29.
|
|
35
|
-
"ts-node": "^10.9.
|
|
36
|
-
"typescript": "^5.
|
|
32
|
+
"jest": "^29.7.0",
|
|
33
|
+
"ts-jest": "^29.4.11",
|
|
34
|
+
"ts-node": "^10.9.2",
|
|
35
|
+
"typescript": "^5.3.0"
|
|
37
36
|
},
|
|
38
37
|
"main": "dist/index.js",
|
|
39
38
|
"files": [
|
|
@@ -61,7 +60,10 @@
|
|
|
61
60
|
"/src/"
|
|
62
61
|
],
|
|
63
62
|
"transform": {
|
|
64
|
-
"^.+\\.tsx?$": [
|
|
63
|
+
"^.+\\.tsx?$": [
|
|
64
|
+
"ts-jest",
|
|
65
|
+
{}
|
|
66
|
+
]
|
|
65
67
|
}
|
|
66
68
|
}
|
|
67
69
|
}
|