k3-plugin-api 2.0.0 → 2.1.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 (2) hide show
  1. package/package.json +6 -2
  2. package/scripts/deploy.js +90 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "k3-plugin-api",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Official TypeScript types and plugin API for the K3 product configurator",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -15,8 +15,12 @@
15
15
  },
16
16
  "files": [
17
17
  "dist",
18
- "README.md"
18
+ "README.md",
19
+ "scripts"
19
20
  ],
21
+ "bin": {
22
+ "k3-deploy": "scripts/deploy.js"
23
+ },
20
24
  "keywords": [
21
25
  "k3",
22
26
  "k3-konfigurator",
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync, readdirSync, statSync } from 'node:fs';
3
+ import { join, relative } from 'node:path';
4
+
5
+ // Minimal .env parser — no dependencies needed
6
+ function loadEnv(path = '.env') {
7
+ try {
8
+ for (const line of readFileSync(path, 'utf-8').split('\n')) {
9
+ const trimmed = line.trim();
10
+ if (!trimmed || trimmed.startsWith('#')) continue;
11
+ const eq = trimmed.indexOf('=');
12
+ if (eq === -1) continue;
13
+ const key = trimmed.slice(0, eq).trim();
14
+ const val = trimmed.slice(eq + 1).trim().replace(/^['"]|['"]$/g, '');
15
+ if (!process.env[key]) process.env[key] = val;
16
+ }
17
+ } catch { /* .env is optional */ }
18
+ }
19
+
20
+ loadEnv();
21
+
22
+ const {
23
+ API_TOKEN,
24
+ PLUGIN_ID,
25
+ BACKEND_URL = 'https://k3-api.objectcode.de',
26
+ FEDERATION_NAME,
27
+ FEDERATION_MODULE,
28
+ } = process.env;
29
+
30
+ if (!API_TOKEN) { console.error('Error: API_TOKEN missing in .env'); process.exit(1); }
31
+ if (!PLUGIN_ID) { console.error('Error: PLUGIN_ID missing in .env'); process.exit(1); }
32
+
33
+ function collectFiles(dir, base = dir) {
34
+ const results = [];
35
+ for (const entry of readdirSync(dir)) {
36
+ const full = join(dir, entry);
37
+ if (statSync(full).isDirectory()) {
38
+ results.push(...collectFiles(full, base));
39
+ } else {
40
+ results.push({ full, rel: relative(base, full) });
41
+ }
42
+ }
43
+ return results;
44
+ }
45
+
46
+ const distPath = join(process.cwd(), 'dist');
47
+ let files;
48
+ try {
49
+ files = collectFiles(distPath);
50
+ } catch {
51
+ console.error('Error: dist/ not found. Run pnpm build first.');
52
+ process.exit(1);
53
+ }
54
+
55
+ console.log(`Deploying ${files.length} files for plugin ${PLUGIN_ID}...`);
56
+
57
+ const form = new FormData();
58
+
59
+ for (const { full, rel } of files) {
60
+ // PHP converts '.' in multipart field names to '_'. To avoid this and
61
+ // collisions with Vite chunk names (which contain '__'), we base64url-encode
62
+ // the full relative path as the field key.
63
+ const key = 'f_' + Buffer.from(rel).toString('base64').replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', '');
64
+ const blob = new Blob([readFileSync(full)]);
65
+ form.append(key, blob, rel.split('/').pop());
66
+ }
67
+
68
+ if (FEDERATION_NAME) form.append('name', FEDERATION_NAME);
69
+ if (FEDERATION_MODULE) form.append('module', FEDERATION_MODULE);
70
+
71
+ const url = `${BACKEND_URL}/api/v1.0/plugin/${PLUGIN_ID}/deploy`;
72
+ console.log(`POST ${url}`);
73
+
74
+ const res = await fetch(url, {
75
+ method: 'POST',
76
+ headers: { Authorization: `Bearer ${API_TOKEN}` },
77
+ body: form,
78
+ });
79
+
80
+ if (!res.ok) {
81
+ const text = await res.text();
82
+ console.error(`Deploy failed (${res.status}): ${text}`);
83
+ process.exit(1);
84
+ }
85
+
86
+ const result = await res.json();
87
+ console.log('');
88
+ console.log('✓ Deploy successful!');
89
+ console.log(' Version:', result.versionId);
90
+ console.log(' URL: ', result.url);