teamx-projects 1.0.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 +30 -0
- package/index.js +197 -0
- package/package.json +16 -0
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Projects API Client (CommonJS, .js)
|
|
2
|
+
|
|
3
|
+
Node 18+ (uses built-in `fetch`).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Run
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx teamx-projects list
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Commands
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
list
|
|
21
|
+
status <projectId>
|
|
22
|
+
artifacts <projectId>
|
|
23
|
+
deploy <projectId> --env production|staging|dev --by someone@teamx.com
|
|
24
|
+
create --name <projectName> --path <folderPath> --lang ts|js
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Env
|
|
28
|
+
|
|
29
|
+
- `BASE_URL` (optional) default: `https://teamx-discord-services.fly.dev`
|
|
30
|
+
- `TEAMX_API_KEY` (optional) Bearer token header
|
package/index.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* TeamX Projects
|
|
4
|
+
* Node 18+ (built-in fetch)
|
|
5
|
+
*
|
|
6
|
+
* Commands:
|
|
7
|
+
* list
|
|
8
|
+
* status <projectId>
|
|
9
|
+
* artifacts <projectId>
|
|
10
|
+
* deploy <projectId> --env production|staging|dev --by email
|
|
11
|
+
* create --name <projectName> --path <folderPath> --lang ts|js
|
|
12
|
+
*
|
|
13
|
+
* Optional env:
|
|
14
|
+
* BASE_URL=https://teamx-discord-services.fly.dev
|
|
15
|
+
* TEAMX_API_KEY=... (Bearer token, optional)
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require("node:fs");
|
|
19
|
+
const path = require("node:path");
|
|
20
|
+
const yazl = require("yazl");
|
|
21
|
+
|
|
22
|
+
const BASEFIX = "https://teamx-discord-services.fly.dev"
|
|
23
|
+
const BASE_URL = BASEFIX.replace(/\/$/, "");
|
|
24
|
+
const API_KEY = process.env.TEAMX_API_KEY || "";
|
|
25
|
+
|
|
26
|
+
function usage(exitCode = 1) {
|
|
27
|
+
console.log(`
|
|
28
|
+
TeamX Projects API Client (CJS)
|
|
29
|
+
|
|
30
|
+
Commands:
|
|
31
|
+
list
|
|
32
|
+
status <projectId>
|
|
33
|
+
artifacts <projectId>
|
|
34
|
+
deploy <projectId> [--env production|staging|dev] [--by email]
|
|
35
|
+
create --name <projectName> --path <folderPath> [--lang ts|js]
|
|
36
|
+
|
|
37
|
+
`);
|
|
38
|
+
process.exit(exitCode);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function argValue(flag, def = "") {
|
|
42
|
+
const i = process.argv.indexOf(flag);
|
|
43
|
+
if (i === -1) return def;
|
|
44
|
+
return process.argv[i + 1] ?? def;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function fetchJson(p, opts = {}) {
|
|
48
|
+
const url = `${BASE_URL}${p}`;
|
|
49
|
+
|
|
50
|
+
const headers = { "content-type": "application/json", ...(opts.headers || {}) };
|
|
51
|
+
if (API_KEY) headers.Authorization = `Bearer ${API_KEY}`;
|
|
52
|
+
|
|
53
|
+
const res = await fetch(url, { ...opts, headers });
|
|
54
|
+
|
|
55
|
+
const text = await res.text();
|
|
56
|
+
let data;
|
|
57
|
+
try {
|
|
58
|
+
data = text ? JSON.parse(text) : null;
|
|
59
|
+
} catch {
|
|
60
|
+
data = { raw: text };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!res.ok) {
|
|
64
|
+
const msg = (data && data.error) || res.statusText || "Request failed";
|
|
65
|
+
const err = new Error(`${res.status} ${msg}`);
|
|
66
|
+
err.status = res.status;
|
|
67
|
+
err.data = data;
|
|
68
|
+
throw err;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return data;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function print(obj) {
|
|
75
|
+
console.log(JSON.stringify(obj, null, 2));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Zip a directory into an in-memory Buffer (no temp files).
|
|
80
|
+
*/
|
|
81
|
+
function zipDirToBuffer(dir) {
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
const zipfile = new yazl.ZipFile();
|
|
84
|
+
const chunks = [];
|
|
85
|
+
const out = zipfile.outputStream;
|
|
86
|
+
|
|
87
|
+
out.on("data", (c) => chunks.push(c));
|
|
88
|
+
out.on("error", reject);
|
|
89
|
+
out.on("end", () => resolve(Buffer.concat(chunks)));
|
|
90
|
+
|
|
91
|
+
function walk(folder, prefix = "") {
|
|
92
|
+
const entries = fs.readdirSync(folder, { withFileTypes: true });
|
|
93
|
+
for (const e of entries) {
|
|
94
|
+
const full = path.join(folder, e.name);
|
|
95
|
+
const rel = path.join(prefix, e.name);
|
|
96
|
+
|
|
97
|
+
// Skip common junk
|
|
98
|
+
if (e.name === "node_modules" || e.name === ".git") continue;
|
|
99
|
+
|
|
100
|
+
if (e.isDirectory()) walk(full, rel);
|
|
101
|
+
else zipfile.addFile(full, rel);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
walk(dir);
|
|
106
|
+
zipfile.end();
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function main() {
|
|
111
|
+
const [, , cmd, ...rest] = process.argv;
|
|
112
|
+
if (!cmd) usage(1);
|
|
113
|
+
|
|
114
|
+
if (cmd === "list") {
|
|
115
|
+
const projects = await fetchJson("/api/projects");
|
|
116
|
+
print(projects);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (cmd === "status") {
|
|
121
|
+
const id = rest[0];
|
|
122
|
+
if (!id) usage(1);
|
|
123
|
+
const status = await fetchJson(`/api/projects/${encodeURIComponent(id)}/status`);
|
|
124
|
+
print(status);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (cmd === "artifacts") {
|
|
129
|
+
const id = rest[0];
|
|
130
|
+
if (!id) usage(1);
|
|
131
|
+
const artifacts = await fetchJson(`/api/projects/${encodeURIComponent(id)}/artifacts`);
|
|
132
|
+
print(artifacts);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (cmd === "deploy") {
|
|
137
|
+
const id = rest[0];
|
|
138
|
+
if (!id) usage(1);
|
|
139
|
+
|
|
140
|
+
const environment = argValue("--env", "production");
|
|
141
|
+
const initiated_by = argValue("--by", "");
|
|
142
|
+
|
|
143
|
+
const payload = { environment, initiated_by };
|
|
144
|
+
const deploy = await fetchJson(`/api/projects/${encodeURIComponent(id)}/deploy`, {
|
|
145
|
+
method: "POST",
|
|
146
|
+
body: JSON.stringify(payload),
|
|
147
|
+
});
|
|
148
|
+
print(deploy);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (cmd === "create") {
|
|
153
|
+
const name = argValue("--name");
|
|
154
|
+
const folderPath = argValue("--path");
|
|
155
|
+
const language = argValue("--lang", "ts");
|
|
156
|
+
|
|
157
|
+
if (!name || !folderPath) usage(1);
|
|
158
|
+
|
|
159
|
+
const abs = path.resolve(folderPath);
|
|
160
|
+
if (!fs.existsSync(abs) || !fs.statSync(abs).isDirectory()) {
|
|
161
|
+
throw new Error(`Invalid --path folder: ${abs}`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const zipBuf = await zipDirToBuffer(abs);
|
|
165
|
+
const source = zipBuf.toString("base64");
|
|
166
|
+
|
|
167
|
+
// If your backend expects different keys, change them here.
|
|
168
|
+
const payload = {
|
|
169
|
+
name,
|
|
170
|
+
template: "advanced-discord-bot",
|
|
171
|
+
language,
|
|
172
|
+
source, // base64 zip
|
|
173
|
+
meta: {
|
|
174
|
+
createdAt: new Date().toISOString(),
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const created = await fetchJson("/api/projects", {
|
|
179
|
+
method: "POST",
|
|
180
|
+
body: JSON.stringify(payload),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
print(created);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
usage(1);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
main().catch((e) => {
|
|
191
|
+
console.error("Error:", e.message);
|
|
192
|
+
if (e.data) {
|
|
193
|
+
console.error("Details:");
|
|
194
|
+
console.error(JSON.stringify(e.data, null, 2));
|
|
195
|
+
}
|
|
196
|
+
process.exit(1);
|
|
197
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "teamx-projects",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "commonjs",
|
|
5
|
+
"description": "Projects API Client for TeamX Discord Services",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"teamx-projects": "index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"client": "node index.js"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"yazl": "^2.5.1"
|
|
15
|
+
}
|
|
16
|
+
}
|