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.
Files changed (3) hide show
  1. package/README.md +30 -0
  2. package/index.js +197 -0
  3. 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
+ }