javer-cli 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/lib/zip.js ADDED
@@ -0,0 +1,174 @@
1
+ /* JAVER-SIGNATURE-START
2
+ JAV
3
+ E RJ
4
+ A o VE
5
+ RJA VERJ
6
+ A V ERJA
7
+ V ER JA
8
+ V ER JA
9
+ VE RJA V
10
+ ER JAVE
11
+ RJ AVE
12
+ RJAVERJAV
13
+ E RJ
14
+ AVERJ AV
15
+ javer.pro — built in-house, not outsourced. signed: lemons
16
+ JAVER-SIGNATURE-END */
17
+
18
+ // A minimal ZIP writer, so `javer deploy` can send the current folder.
19
+ //
20
+ // Node ships zlib but no archive format, and this CLI has no dependencies and
21
+ // is not getting any — a hosting tool people install globally should not drag a
22
+ // tree of packages onto their machine. Shelling out to `zip` was the other
23
+ // option and it is not installed by default on most systems.
24
+ //
25
+ // So: deflate each file with zlib (ZIP method 8 is raw deflate, which
26
+ // deflateRawSync produces directly) and write the three structures the format
27
+ // needs — a local header per file, a central directory, and an end record.
28
+ const fs = require('fs');
29
+ const path = require('path');
30
+ const zlib = require('zlib');
31
+
32
+ let TABLE = null;
33
+ const crcTable = () => {
34
+ if (TABLE) return TABLE;
35
+ TABLE = new Int32Array(256);
36
+ for (let n = 0; n < 256; n++) {
37
+ let c = n;
38
+ for (let k = 0; k < 8; k++) c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
39
+ TABLE[n] = c;
40
+ }
41
+ return TABLE;
42
+ };
43
+
44
+ const crc32 = (buf) => {
45
+ const t = crcTable();
46
+ let c = -1;
47
+ for (let i = 0; i < buf.length; i++) c = t[(c ^ buf[i]) & 0xFF] ^ (c >>> 8);
48
+ return (c ^ -1) >>> 0;
49
+ };
50
+
51
+ // Anything here is either not the customer's source, or actively harmful to
52
+ // upload. node_modules especially: the server runs npm install itself, and
53
+ // including it would blow the upload limit on even a small project.
54
+ const SKIP_DIRS = new Set([
55
+ 'node_modules', '.git', '.svn', '.hg', 'dist', 'build', '.next', '.nuxt',
56
+ '.cache', 'coverage', '.venv', 'venv', '__pycache__', '.idea', '.vscode',
57
+ 'vendor', 'target', '.terraform'
58
+ ]);
59
+ // .env is deliberate: environment variables belong in the panel, not baked
60
+ // into a deployment. Sending one would put live secrets in an upload and then
61
+ // leave them sitting in the app directory on disk.
62
+ const SKIP_FILES = new Set(['.DS_Store', 'Thumbs.db', '.env']);
63
+ const SKIP_EXT = new Set(['.log', '.zip', '.tar', '.gz', '.tgz', '.sqlite', '.db']);
64
+
65
+ // Walk a directory into a flat list of {name, abs} with POSIX-style names,
66
+ // which is what the ZIP format wants regardless of the host platform.
67
+ const collect = (root) => {
68
+ const out = [];
69
+ const walk = (dir, prefix) => {
70
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
71
+ const name = entry.name;
72
+ if (entry.isDirectory()) {
73
+ if (SKIP_DIRS.has(name) || name.startsWith('.git')) continue;
74
+ walk(path.join(dir, name), prefix ? `${prefix}/${name}` : name);
75
+ } else if (entry.isFile()) {
76
+ if (SKIP_FILES.has(name)) continue;
77
+ if (name.startsWith('.env.')) continue;
78
+ if (SKIP_EXT.has(path.extname(name).toLowerCase())) continue;
79
+ out.push({ name: prefix ? `${prefix}/${name}` : name, abs: path.join(dir, name) });
80
+ }
81
+ // Symlinks are skipped on purpose: following one can walk out of the
82
+ // project entirely, and storing it would be meaningless once extracted.
83
+ }
84
+ };
85
+ walk(root, '');
86
+ return out.sort((a, b) => a.name.localeCompare(b.name));
87
+ };
88
+
89
+ // DOS time/date. The epoch is 1980 and there is no timezone; a file older than
90
+ // that clamps rather than writing a negative year the reader would reject.
91
+ const dosStamp = (mtime) => {
92
+ const d = mtime instanceof Date ? mtime : new Date(mtime);
93
+ const year = Math.max(1980, d.getFullYear());
94
+ return {
95
+ time: ((d.getHours() & 31) << 11) | ((d.getMinutes() & 63) << 5) | ((Math.floor(d.getSeconds() / 2)) & 31),
96
+ date: (((year - 1980) & 127) << 9) | (((d.getMonth() + 1) & 15) << 5) | (d.getDate() & 31)
97
+ };
98
+ };
99
+
100
+ const zipDir = (root) => {
101
+ const files = collect(root);
102
+ if (!files.length) throw new Error('nothing to deploy — this folder has no files the platform would accept');
103
+
104
+ const locals = [];
105
+ const central = [];
106
+ let offset = 0;
107
+ let rawTotal = 0;
108
+
109
+ for (const f of files) {
110
+ const stat = fs.statSync(f.abs);
111
+ const data = fs.readFileSync(f.abs);
112
+ rawTotal += data.length;
113
+ const comp = zlib.deflateRawSync(data, { level: 9 });
114
+ const crc = crc32(data);
115
+ const nameBuf = Buffer.from(f.name, 'utf8');
116
+ const { time, date } = dosStamp(stat.mtime);
117
+
118
+ const lh = Buffer.alloc(30);
119
+ lh.writeUInt32LE(0x04034b50, 0);
120
+ lh.writeUInt16LE(20, 4); // version needed
121
+ lh.writeUInt16LE(0, 6); // flags
122
+ lh.writeUInt16LE(8, 8); // method: deflate
123
+ lh.writeUInt16LE(time, 10);
124
+ lh.writeUInt16LE(date, 12);
125
+ lh.writeUInt32LE(crc, 14);
126
+ lh.writeUInt32LE(comp.length, 18);
127
+ lh.writeUInt32LE(data.length, 22);
128
+ lh.writeUInt16LE(nameBuf.length, 26);
129
+ lh.writeUInt16LE(0, 28); // extra field length
130
+ locals.push(lh, nameBuf, comp);
131
+
132
+ const ch = Buffer.alloc(46);
133
+ ch.writeUInt32LE(0x02014b50, 0);
134
+ ch.writeUInt16LE(20, 4); // version made by
135
+ ch.writeUInt16LE(20, 6); // version needed
136
+ ch.writeUInt16LE(0, 8);
137
+ ch.writeUInt16LE(8, 10);
138
+ ch.writeUInt16LE(time, 12);
139
+ ch.writeUInt16LE(date, 14);
140
+ ch.writeUInt32LE(crc, 16);
141
+ ch.writeUInt32LE(comp.length, 20);
142
+ ch.writeUInt32LE(data.length, 24);
143
+ ch.writeUInt16LE(nameBuf.length, 28);
144
+ ch.writeUInt16LE(0, 30); // extra
145
+ ch.writeUInt16LE(0, 32); // comment
146
+ ch.writeUInt16LE(0, 34); // disk number
147
+ ch.writeUInt16LE(0, 36); // internal attrs
148
+ ch.writeUInt32LE(0, 38); // external attrs
149
+ ch.writeUInt32LE(offset, 42); // offset of local header
150
+ central.push(ch, nameBuf);
151
+
152
+ offset += lh.length + nameBuf.length + comp.length;
153
+ }
154
+
155
+ const centralBuf = Buffer.concat(central);
156
+ const eocd = Buffer.alloc(22);
157
+ eocd.writeUInt32LE(0x06054b50, 0);
158
+ eocd.writeUInt16LE(0, 4);
159
+ eocd.writeUInt16LE(0, 6);
160
+ eocd.writeUInt16LE(files.length, 8);
161
+ eocd.writeUInt16LE(files.length, 10);
162
+ eocd.writeUInt32LE(centralBuf.length, 12);
163
+ eocd.writeUInt32LE(offset, 16);
164
+ eocd.writeUInt16LE(0, 20);
165
+
166
+ return {
167
+ buffer: Buffer.concat([...locals, centralBuf, eocd]),
168
+ fileCount: files.length,
169
+ rawBytes: rawTotal,
170
+ names: files.map((f) => f.name)
171
+ };
172
+ };
173
+
174
+ module.exports = { zipDir, collect, crc32 };
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "javer-cli",
3
+ "version": "1.0.0",
4
+ "description": "Javer Webhost from the command line — apps, VMs, databases and domains. No dependencies.",
5
+ "keywords": [
6
+ "javer",
7
+ "hosting",
8
+ "deploy",
9
+ "cli",
10
+ "paas",
11
+ "webhost",
12
+ "vps"
13
+ ],
14
+ "homepage": "https://javer.pro/docs/cli",
15
+ "bugs": {
16
+ "url": "https://javer.pro/support"
17
+ },
18
+ "author": "Javer Studios",
19
+ "license": "MIT",
20
+ "bin": {
21
+ "javer": "index.js"
22
+ },
23
+ "type": "commonjs",
24
+ "engines": {
25
+ "node": ">=18"
26
+ },
27
+ "os": [
28
+ "linux",
29
+ "darwin",
30
+ "win32"
31
+ ],
32
+ "files": [
33
+ "index.js",
34
+ "lib/",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "private": false
39
+ }