@longleash/cli 0.1.0-rc.1 → 0.1.0-rc.3
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/bin/longleash.mjs +1782 -39
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -1
- package/runtime/app/dist/assets/{app-CxamvvoS.js → app-NKyZHFwH.js} +2 -2
- package/runtime/app/dist/assets/welcome-Df4xKIqw.js +31 -0
- package/runtime/app/dist/build.json +1 -1
- package/runtime/app/dist/index.html +1 -1
- package/runtime/app/dist/welcome.html +1 -1
- package/runtime/daemon/bin/longleashd.mjs +153 -28
- package/runtime/app/dist/assets/welcome-CG_rEa--.js +0 -27
package/bin/longleash.mjs
CHANGED
|
@@ -1,11 +1,1106 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
|
|
28
|
+
// ../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMode.js
|
|
29
|
+
var require_QRMode = __commonJS({
|
|
30
|
+
"../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMode.js"(exports, module) {
|
|
31
|
+
module.exports = {
|
|
32
|
+
MODE_NUMBER: 1 << 0,
|
|
33
|
+
MODE_ALPHA_NUM: 1 << 1,
|
|
34
|
+
MODE_8BIT_BYTE: 1 << 2,
|
|
35
|
+
MODE_KANJI: 1 << 3
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// ../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QR8bitByte.js
|
|
41
|
+
var require_QR8bitByte = __commonJS({
|
|
42
|
+
"../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QR8bitByte.js"(exports, module) {
|
|
43
|
+
var QRMode = require_QRMode();
|
|
44
|
+
function QR8bitByte(data) {
|
|
45
|
+
this.mode = QRMode.MODE_8BIT_BYTE;
|
|
46
|
+
this.data = data;
|
|
47
|
+
}
|
|
48
|
+
QR8bitByte.prototype = {
|
|
49
|
+
getLength: function() {
|
|
50
|
+
return this.data.length;
|
|
51
|
+
},
|
|
52
|
+
write: function(buffer) {
|
|
53
|
+
for (var i = 0; i < this.data.length; i++) {
|
|
54
|
+
buffer.put(this.data.charCodeAt(i), 8);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
module.exports = QR8bitByte;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// ../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMath.js
|
|
63
|
+
var require_QRMath = __commonJS({
|
|
64
|
+
"../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMath.js"(exports, module) {
|
|
65
|
+
var QRMath = {
|
|
66
|
+
glog: function(n) {
|
|
67
|
+
if (n < 1) {
|
|
68
|
+
throw new Error("glog(" + n + ")");
|
|
69
|
+
}
|
|
70
|
+
return QRMath.LOG_TABLE[n];
|
|
71
|
+
},
|
|
72
|
+
gexp: function(n) {
|
|
73
|
+
while (n < 0) {
|
|
74
|
+
n += 255;
|
|
75
|
+
}
|
|
76
|
+
while (n >= 256) {
|
|
77
|
+
n -= 255;
|
|
78
|
+
}
|
|
79
|
+
return QRMath.EXP_TABLE[n];
|
|
80
|
+
},
|
|
81
|
+
EXP_TABLE: new Array(256),
|
|
82
|
+
LOG_TABLE: new Array(256)
|
|
83
|
+
};
|
|
84
|
+
for (i = 0; i < 8; i++) {
|
|
85
|
+
QRMath.EXP_TABLE[i] = 1 << i;
|
|
86
|
+
}
|
|
87
|
+
var i;
|
|
88
|
+
for (i = 8; i < 256; i++) {
|
|
89
|
+
QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8];
|
|
90
|
+
}
|
|
91
|
+
var i;
|
|
92
|
+
for (i = 0; i < 255; i++) {
|
|
93
|
+
QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
|
|
94
|
+
}
|
|
95
|
+
var i;
|
|
96
|
+
module.exports = QRMath;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// ../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRPolynomial.js
|
|
101
|
+
var require_QRPolynomial = __commonJS({
|
|
102
|
+
"../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRPolynomial.js"(exports, module) {
|
|
103
|
+
var QRMath = require_QRMath();
|
|
104
|
+
function QRPolynomial(num, shift) {
|
|
105
|
+
if (num.length === void 0) {
|
|
106
|
+
throw new Error(num.length + "/" + shift);
|
|
107
|
+
}
|
|
108
|
+
var offset = 0;
|
|
109
|
+
while (offset < num.length && num[offset] === 0) {
|
|
110
|
+
offset++;
|
|
111
|
+
}
|
|
112
|
+
this.num = new Array(num.length - offset + shift);
|
|
113
|
+
for (var i = 0; i < num.length - offset; i++) {
|
|
114
|
+
this.num[i] = num[i + offset];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
QRPolynomial.prototype = {
|
|
118
|
+
get: function(index) {
|
|
119
|
+
return this.num[index];
|
|
120
|
+
},
|
|
121
|
+
getLength: function() {
|
|
122
|
+
return this.num.length;
|
|
123
|
+
},
|
|
124
|
+
multiply: function(e) {
|
|
125
|
+
var num = new Array(this.getLength() + e.getLength() - 1);
|
|
126
|
+
for (var i = 0; i < this.getLength(); i++) {
|
|
127
|
+
for (var j = 0; j < e.getLength(); j++) {
|
|
128
|
+
num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return new QRPolynomial(num, 0);
|
|
132
|
+
},
|
|
133
|
+
mod: function(e) {
|
|
134
|
+
if (this.getLength() - e.getLength() < 0) {
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
|
|
138
|
+
var num = new Array(this.getLength());
|
|
139
|
+
for (var i = 0; i < this.getLength(); i++) {
|
|
140
|
+
num[i] = this.get(i);
|
|
141
|
+
}
|
|
142
|
+
for (var x = 0; x < e.getLength(); x++) {
|
|
143
|
+
num[x] ^= QRMath.gexp(QRMath.glog(e.get(x)) + ratio);
|
|
144
|
+
}
|
|
145
|
+
return new QRPolynomial(num, 0).mod(e);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
module.exports = QRPolynomial;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// ../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMaskPattern.js
|
|
153
|
+
var require_QRMaskPattern = __commonJS({
|
|
154
|
+
"../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMaskPattern.js"(exports, module) {
|
|
155
|
+
module.exports = {
|
|
156
|
+
PATTERN000: 0,
|
|
157
|
+
PATTERN001: 1,
|
|
158
|
+
PATTERN010: 2,
|
|
159
|
+
PATTERN011: 3,
|
|
160
|
+
PATTERN100: 4,
|
|
161
|
+
PATTERN101: 5,
|
|
162
|
+
PATTERN110: 6,
|
|
163
|
+
PATTERN111: 7
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// ../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRUtil.js
|
|
169
|
+
var require_QRUtil = __commonJS({
|
|
170
|
+
"../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRUtil.js"(exports, module) {
|
|
171
|
+
var QRMode = require_QRMode();
|
|
172
|
+
var QRPolynomial = require_QRPolynomial();
|
|
173
|
+
var QRMath = require_QRMath();
|
|
174
|
+
var QRMaskPattern = require_QRMaskPattern();
|
|
175
|
+
var QRUtil = {
|
|
176
|
+
PATTERN_POSITION_TABLE: [
|
|
177
|
+
[],
|
|
178
|
+
[6, 18],
|
|
179
|
+
[6, 22],
|
|
180
|
+
[6, 26],
|
|
181
|
+
[6, 30],
|
|
182
|
+
[6, 34],
|
|
183
|
+
[6, 22, 38],
|
|
184
|
+
[6, 24, 42],
|
|
185
|
+
[6, 26, 46],
|
|
186
|
+
[6, 28, 50],
|
|
187
|
+
[6, 30, 54],
|
|
188
|
+
[6, 32, 58],
|
|
189
|
+
[6, 34, 62],
|
|
190
|
+
[6, 26, 46, 66],
|
|
191
|
+
[6, 26, 48, 70],
|
|
192
|
+
[6, 26, 50, 74],
|
|
193
|
+
[6, 30, 54, 78],
|
|
194
|
+
[6, 30, 56, 82],
|
|
195
|
+
[6, 30, 58, 86],
|
|
196
|
+
[6, 34, 62, 90],
|
|
197
|
+
[6, 28, 50, 72, 94],
|
|
198
|
+
[6, 26, 50, 74, 98],
|
|
199
|
+
[6, 30, 54, 78, 102],
|
|
200
|
+
[6, 28, 54, 80, 106],
|
|
201
|
+
[6, 32, 58, 84, 110],
|
|
202
|
+
[6, 30, 58, 86, 114],
|
|
203
|
+
[6, 34, 62, 90, 118],
|
|
204
|
+
[6, 26, 50, 74, 98, 122],
|
|
205
|
+
[6, 30, 54, 78, 102, 126],
|
|
206
|
+
[6, 26, 52, 78, 104, 130],
|
|
207
|
+
[6, 30, 56, 82, 108, 134],
|
|
208
|
+
[6, 34, 60, 86, 112, 138],
|
|
209
|
+
[6, 30, 58, 86, 114, 142],
|
|
210
|
+
[6, 34, 62, 90, 118, 146],
|
|
211
|
+
[6, 30, 54, 78, 102, 126, 150],
|
|
212
|
+
[6, 24, 50, 76, 102, 128, 154],
|
|
213
|
+
[6, 28, 54, 80, 106, 132, 158],
|
|
214
|
+
[6, 32, 58, 84, 110, 136, 162],
|
|
215
|
+
[6, 26, 54, 82, 110, 138, 166],
|
|
216
|
+
[6, 30, 58, 86, 114, 142, 170]
|
|
217
|
+
],
|
|
218
|
+
G15: 1 << 10 | 1 << 8 | 1 << 5 | 1 << 4 | 1 << 2 | 1 << 1 | 1 << 0,
|
|
219
|
+
G18: 1 << 12 | 1 << 11 | 1 << 10 | 1 << 9 | 1 << 8 | 1 << 5 | 1 << 2 | 1 << 0,
|
|
220
|
+
G15_MASK: 1 << 14 | 1 << 12 | 1 << 10 | 1 << 4 | 1 << 1,
|
|
221
|
+
getBCHTypeInfo: function(data) {
|
|
222
|
+
var d = data << 10;
|
|
223
|
+
while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
|
|
224
|
+
d ^= QRUtil.G15 << QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15);
|
|
225
|
+
}
|
|
226
|
+
return (data << 10 | d) ^ QRUtil.G15_MASK;
|
|
227
|
+
},
|
|
228
|
+
getBCHTypeNumber: function(data) {
|
|
229
|
+
var d = data << 12;
|
|
230
|
+
while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
|
|
231
|
+
d ^= QRUtil.G18 << QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18);
|
|
232
|
+
}
|
|
233
|
+
return data << 12 | d;
|
|
234
|
+
},
|
|
235
|
+
getBCHDigit: function(data) {
|
|
236
|
+
var digit = 0;
|
|
237
|
+
while (data !== 0) {
|
|
238
|
+
digit++;
|
|
239
|
+
data >>>= 1;
|
|
240
|
+
}
|
|
241
|
+
return digit;
|
|
242
|
+
},
|
|
243
|
+
getPatternPosition: function(typeNumber) {
|
|
244
|
+
return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
|
|
245
|
+
},
|
|
246
|
+
getMask: function(maskPattern, i, j) {
|
|
247
|
+
switch (maskPattern) {
|
|
248
|
+
case QRMaskPattern.PATTERN000:
|
|
249
|
+
return (i + j) % 2 === 0;
|
|
250
|
+
case QRMaskPattern.PATTERN001:
|
|
251
|
+
return i % 2 === 0;
|
|
252
|
+
case QRMaskPattern.PATTERN010:
|
|
253
|
+
return j % 3 === 0;
|
|
254
|
+
case QRMaskPattern.PATTERN011:
|
|
255
|
+
return (i + j) % 3 === 0;
|
|
256
|
+
case QRMaskPattern.PATTERN100:
|
|
257
|
+
return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 === 0;
|
|
258
|
+
case QRMaskPattern.PATTERN101:
|
|
259
|
+
return i * j % 2 + i * j % 3 === 0;
|
|
260
|
+
case QRMaskPattern.PATTERN110:
|
|
261
|
+
return (i * j % 2 + i * j % 3) % 2 === 0;
|
|
262
|
+
case QRMaskPattern.PATTERN111:
|
|
263
|
+
return (i * j % 3 + (i + j) % 2) % 2 === 0;
|
|
264
|
+
default:
|
|
265
|
+
throw new Error("bad maskPattern:" + maskPattern);
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
getErrorCorrectPolynomial: function(errorCorrectLength) {
|
|
269
|
+
var a = new QRPolynomial([1], 0);
|
|
270
|
+
for (var i = 0; i < errorCorrectLength; i++) {
|
|
271
|
+
a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
|
|
272
|
+
}
|
|
273
|
+
return a;
|
|
274
|
+
},
|
|
275
|
+
getLengthInBits: function(mode, type) {
|
|
276
|
+
if (1 <= type && type < 10) {
|
|
277
|
+
switch (mode) {
|
|
278
|
+
case QRMode.MODE_NUMBER:
|
|
279
|
+
return 10;
|
|
280
|
+
case QRMode.MODE_ALPHA_NUM:
|
|
281
|
+
return 9;
|
|
282
|
+
case QRMode.MODE_8BIT_BYTE:
|
|
283
|
+
return 8;
|
|
284
|
+
case QRMode.MODE_KANJI:
|
|
285
|
+
return 8;
|
|
286
|
+
default:
|
|
287
|
+
throw new Error("mode:" + mode);
|
|
288
|
+
}
|
|
289
|
+
} else if (type < 27) {
|
|
290
|
+
switch (mode) {
|
|
291
|
+
case QRMode.MODE_NUMBER:
|
|
292
|
+
return 12;
|
|
293
|
+
case QRMode.MODE_ALPHA_NUM:
|
|
294
|
+
return 11;
|
|
295
|
+
case QRMode.MODE_8BIT_BYTE:
|
|
296
|
+
return 16;
|
|
297
|
+
case QRMode.MODE_KANJI:
|
|
298
|
+
return 10;
|
|
299
|
+
default:
|
|
300
|
+
throw new Error("mode:" + mode);
|
|
301
|
+
}
|
|
302
|
+
} else if (type < 41) {
|
|
303
|
+
switch (mode) {
|
|
304
|
+
case QRMode.MODE_NUMBER:
|
|
305
|
+
return 14;
|
|
306
|
+
case QRMode.MODE_ALPHA_NUM:
|
|
307
|
+
return 13;
|
|
308
|
+
case QRMode.MODE_8BIT_BYTE:
|
|
309
|
+
return 16;
|
|
310
|
+
case QRMode.MODE_KANJI:
|
|
311
|
+
return 12;
|
|
312
|
+
default:
|
|
313
|
+
throw new Error("mode:" + mode);
|
|
314
|
+
}
|
|
315
|
+
} else {
|
|
316
|
+
throw new Error("type:" + type);
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
getLostPoint: function(qrCode) {
|
|
320
|
+
var moduleCount = qrCode.getModuleCount();
|
|
321
|
+
var lostPoint = 0;
|
|
322
|
+
var row = 0;
|
|
323
|
+
var col = 0;
|
|
324
|
+
for (row = 0; row < moduleCount; row++) {
|
|
325
|
+
for (col = 0; col < moduleCount; col++) {
|
|
326
|
+
var sameCount = 0;
|
|
327
|
+
var dark = qrCode.isDark(row, col);
|
|
328
|
+
for (var r = -1; r <= 1; r++) {
|
|
329
|
+
if (row + r < 0 || moduleCount <= row + r) {
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
for (var c = -1; c <= 1; c++) {
|
|
333
|
+
if (col + c < 0 || moduleCount <= col + c) {
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
if (r === 0 && c === 0) {
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
if (dark === qrCode.isDark(row + r, col + c)) {
|
|
340
|
+
sameCount++;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (sameCount > 5) {
|
|
345
|
+
lostPoint += 3 + sameCount - 5;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
for (row = 0; row < moduleCount - 1; row++) {
|
|
350
|
+
for (col = 0; col < moduleCount - 1; col++) {
|
|
351
|
+
var count = 0;
|
|
352
|
+
if (qrCode.isDark(row, col)) count++;
|
|
353
|
+
if (qrCode.isDark(row + 1, col)) count++;
|
|
354
|
+
if (qrCode.isDark(row, col + 1)) count++;
|
|
355
|
+
if (qrCode.isDark(row + 1, col + 1)) count++;
|
|
356
|
+
if (count === 0 || count === 4) {
|
|
357
|
+
lostPoint += 3;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
for (row = 0; row < moduleCount; row++) {
|
|
362
|
+
for (col = 0; col < moduleCount - 6; col++) {
|
|
363
|
+
if (qrCode.isDark(row, col) && !qrCode.isDark(row, col + 1) && qrCode.isDark(row, col + 2) && qrCode.isDark(row, col + 3) && qrCode.isDark(row, col + 4) && !qrCode.isDark(row, col + 5) && qrCode.isDark(row, col + 6)) {
|
|
364
|
+
lostPoint += 40;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
for (col = 0; col < moduleCount; col++) {
|
|
369
|
+
for (row = 0; row < moduleCount - 6; row++) {
|
|
370
|
+
if (qrCode.isDark(row, col) && !qrCode.isDark(row + 1, col) && qrCode.isDark(row + 2, col) && qrCode.isDark(row + 3, col) && qrCode.isDark(row + 4, col) && !qrCode.isDark(row + 5, col) && qrCode.isDark(row + 6, col)) {
|
|
371
|
+
lostPoint += 40;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
var darkCount = 0;
|
|
376
|
+
for (col = 0; col < moduleCount; col++) {
|
|
377
|
+
for (row = 0; row < moduleCount; row++) {
|
|
378
|
+
if (qrCode.isDark(row, col)) {
|
|
379
|
+
darkCount++;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
|
|
384
|
+
lostPoint += ratio * 10;
|
|
385
|
+
return lostPoint;
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
module.exports = QRUtil;
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// ../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js
|
|
393
|
+
var require_QRErrorCorrectLevel = __commonJS({
|
|
394
|
+
"../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js"(exports, module) {
|
|
395
|
+
module.exports = {
|
|
396
|
+
L: 1,
|
|
397
|
+
M: 0,
|
|
398
|
+
Q: 3,
|
|
399
|
+
H: 2
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
// ../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRRSBlock.js
|
|
405
|
+
var require_QRRSBlock = __commonJS({
|
|
406
|
+
"../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRRSBlock.js"(exports, module) {
|
|
407
|
+
var QRErrorCorrectLevel = require_QRErrorCorrectLevel();
|
|
408
|
+
function QRRSBlock(totalCount, dataCount) {
|
|
409
|
+
this.totalCount = totalCount;
|
|
410
|
+
this.dataCount = dataCount;
|
|
411
|
+
}
|
|
412
|
+
QRRSBlock.RS_BLOCK_TABLE = [
|
|
413
|
+
// L
|
|
414
|
+
// M
|
|
415
|
+
// Q
|
|
416
|
+
// H
|
|
417
|
+
// 1
|
|
418
|
+
[1, 26, 19],
|
|
419
|
+
[1, 26, 16],
|
|
420
|
+
[1, 26, 13],
|
|
421
|
+
[1, 26, 9],
|
|
422
|
+
// 2
|
|
423
|
+
[1, 44, 34],
|
|
424
|
+
[1, 44, 28],
|
|
425
|
+
[1, 44, 22],
|
|
426
|
+
[1, 44, 16],
|
|
427
|
+
// 3
|
|
428
|
+
[1, 70, 55],
|
|
429
|
+
[1, 70, 44],
|
|
430
|
+
[2, 35, 17],
|
|
431
|
+
[2, 35, 13],
|
|
432
|
+
// 4
|
|
433
|
+
[1, 100, 80],
|
|
434
|
+
[2, 50, 32],
|
|
435
|
+
[2, 50, 24],
|
|
436
|
+
[4, 25, 9],
|
|
437
|
+
// 5
|
|
438
|
+
[1, 134, 108],
|
|
439
|
+
[2, 67, 43],
|
|
440
|
+
[2, 33, 15, 2, 34, 16],
|
|
441
|
+
[2, 33, 11, 2, 34, 12],
|
|
442
|
+
// 6
|
|
443
|
+
[2, 86, 68],
|
|
444
|
+
[4, 43, 27],
|
|
445
|
+
[4, 43, 19],
|
|
446
|
+
[4, 43, 15],
|
|
447
|
+
// 7
|
|
448
|
+
[2, 98, 78],
|
|
449
|
+
[4, 49, 31],
|
|
450
|
+
[2, 32, 14, 4, 33, 15],
|
|
451
|
+
[4, 39, 13, 1, 40, 14],
|
|
452
|
+
// 8
|
|
453
|
+
[2, 121, 97],
|
|
454
|
+
[2, 60, 38, 2, 61, 39],
|
|
455
|
+
[4, 40, 18, 2, 41, 19],
|
|
456
|
+
[4, 40, 14, 2, 41, 15],
|
|
457
|
+
// 9
|
|
458
|
+
[2, 146, 116],
|
|
459
|
+
[3, 58, 36, 2, 59, 37],
|
|
460
|
+
[4, 36, 16, 4, 37, 17],
|
|
461
|
+
[4, 36, 12, 4, 37, 13],
|
|
462
|
+
// 10
|
|
463
|
+
[2, 86, 68, 2, 87, 69],
|
|
464
|
+
[4, 69, 43, 1, 70, 44],
|
|
465
|
+
[6, 43, 19, 2, 44, 20],
|
|
466
|
+
[6, 43, 15, 2, 44, 16],
|
|
467
|
+
// 11
|
|
468
|
+
[4, 101, 81],
|
|
469
|
+
[1, 80, 50, 4, 81, 51],
|
|
470
|
+
[4, 50, 22, 4, 51, 23],
|
|
471
|
+
[3, 36, 12, 8, 37, 13],
|
|
472
|
+
// 12
|
|
473
|
+
[2, 116, 92, 2, 117, 93],
|
|
474
|
+
[6, 58, 36, 2, 59, 37],
|
|
475
|
+
[4, 46, 20, 6, 47, 21],
|
|
476
|
+
[7, 42, 14, 4, 43, 15],
|
|
477
|
+
// 13
|
|
478
|
+
[4, 133, 107],
|
|
479
|
+
[8, 59, 37, 1, 60, 38],
|
|
480
|
+
[8, 44, 20, 4, 45, 21],
|
|
481
|
+
[12, 33, 11, 4, 34, 12],
|
|
482
|
+
// 14
|
|
483
|
+
[3, 145, 115, 1, 146, 116],
|
|
484
|
+
[4, 64, 40, 5, 65, 41],
|
|
485
|
+
[11, 36, 16, 5, 37, 17],
|
|
486
|
+
[11, 36, 12, 5, 37, 13],
|
|
487
|
+
// 15
|
|
488
|
+
[5, 109, 87, 1, 110, 88],
|
|
489
|
+
[5, 65, 41, 5, 66, 42],
|
|
490
|
+
[5, 54, 24, 7, 55, 25],
|
|
491
|
+
[11, 36, 12],
|
|
492
|
+
// 16
|
|
493
|
+
[5, 122, 98, 1, 123, 99],
|
|
494
|
+
[7, 73, 45, 3, 74, 46],
|
|
495
|
+
[15, 43, 19, 2, 44, 20],
|
|
496
|
+
[3, 45, 15, 13, 46, 16],
|
|
497
|
+
// 17
|
|
498
|
+
[1, 135, 107, 5, 136, 108],
|
|
499
|
+
[10, 74, 46, 1, 75, 47],
|
|
500
|
+
[1, 50, 22, 15, 51, 23],
|
|
501
|
+
[2, 42, 14, 17, 43, 15],
|
|
502
|
+
// 18
|
|
503
|
+
[5, 150, 120, 1, 151, 121],
|
|
504
|
+
[9, 69, 43, 4, 70, 44],
|
|
505
|
+
[17, 50, 22, 1, 51, 23],
|
|
506
|
+
[2, 42, 14, 19, 43, 15],
|
|
507
|
+
// 19
|
|
508
|
+
[3, 141, 113, 4, 142, 114],
|
|
509
|
+
[3, 70, 44, 11, 71, 45],
|
|
510
|
+
[17, 47, 21, 4, 48, 22],
|
|
511
|
+
[9, 39, 13, 16, 40, 14],
|
|
512
|
+
// 20
|
|
513
|
+
[3, 135, 107, 5, 136, 108],
|
|
514
|
+
[3, 67, 41, 13, 68, 42],
|
|
515
|
+
[15, 54, 24, 5, 55, 25],
|
|
516
|
+
[15, 43, 15, 10, 44, 16],
|
|
517
|
+
// 21
|
|
518
|
+
[4, 144, 116, 4, 145, 117],
|
|
519
|
+
[17, 68, 42],
|
|
520
|
+
[17, 50, 22, 6, 51, 23],
|
|
521
|
+
[19, 46, 16, 6, 47, 17],
|
|
522
|
+
// 22
|
|
523
|
+
[2, 139, 111, 7, 140, 112],
|
|
524
|
+
[17, 74, 46],
|
|
525
|
+
[7, 54, 24, 16, 55, 25],
|
|
526
|
+
[34, 37, 13],
|
|
527
|
+
// 23
|
|
528
|
+
[4, 151, 121, 5, 152, 122],
|
|
529
|
+
[4, 75, 47, 14, 76, 48],
|
|
530
|
+
[11, 54, 24, 14, 55, 25],
|
|
531
|
+
[16, 45, 15, 14, 46, 16],
|
|
532
|
+
// 24
|
|
533
|
+
[6, 147, 117, 4, 148, 118],
|
|
534
|
+
[6, 73, 45, 14, 74, 46],
|
|
535
|
+
[11, 54, 24, 16, 55, 25],
|
|
536
|
+
[30, 46, 16, 2, 47, 17],
|
|
537
|
+
// 25
|
|
538
|
+
[8, 132, 106, 4, 133, 107],
|
|
539
|
+
[8, 75, 47, 13, 76, 48],
|
|
540
|
+
[7, 54, 24, 22, 55, 25],
|
|
541
|
+
[22, 45, 15, 13, 46, 16],
|
|
542
|
+
// 26
|
|
543
|
+
[10, 142, 114, 2, 143, 115],
|
|
544
|
+
[19, 74, 46, 4, 75, 47],
|
|
545
|
+
[28, 50, 22, 6, 51, 23],
|
|
546
|
+
[33, 46, 16, 4, 47, 17],
|
|
547
|
+
// 27
|
|
548
|
+
[8, 152, 122, 4, 153, 123],
|
|
549
|
+
[22, 73, 45, 3, 74, 46],
|
|
550
|
+
[8, 53, 23, 26, 54, 24],
|
|
551
|
+
[12, 45, 15, 28, 46, 16],
|
|
552
|
+
// 28
|
|
553
|
+
[3, 147, 117, 10, 148, 118],
|
|
554
|
+
[3, 73, 45, 23, 74, 46],
|
|
555
|
+
[4, 54, 24, 31, 55, 25],
|
|
556
|
+
[11, 45, 15, 31, 46, 16],
|
|
557
|
+
// 29
|
|
558
|
+
[7, 146, 116, 7, 147, 117],
|
|
559
|
+
[21, 73, 45, 7, 74, 46],
|
|
560
|
+
[1, 53, 23, 37, 54, 24],
|
|
561
|
+
[19, 45, 15, 26, 46, 16],
|
|
562
|
+
// 30
|
|
563
|
+
[5, 145, 115, 10, 146, 116],
|
|
564
|
+
[19, 75, 47, 10, 76, 48],
|
|
565
|
+
[15, 54, 24, 25, 55, 25],
|
|
566
|
+
[23, 45, 15, 25, 46, 16],
|
|
567
|
+
// 31
|
|
568
|
+
[13, 145, 115, 3, 146, 116],
|
|
569
|
+
[2, 74, 46, 29, 75, 47],
|
|
570
|
+
[42, 54, 24, 1, 55, 25],
|
|
571
|
+
[23, 45, 15, 28, 46, 16],
|
|
572
|
+
// 32
|
|
573
|
+
[17, 145, 115],
|
|
574
|
+
[10, 74, 46, 23, 75, 47],
|
|
575
|
+
[10, 54, 24, 35, 55, 25],
|
|
576
|
+
[19, 45, 15, 35, 46, 16],
|
|
577
|
+
// 33
|
|
578
|
+
[17, 145, 115, 1, 146, 116],
|
|
579
|
+
[14, 74, 46, 21, 75, 47],
|
|
580
|
+
[29, 54, 24, 19, 55, 25],
|
|
581
|
+
[11, 45, 15, 46, 46, 16],
|
|
582
|
+
// 34
|
|
583
|
+
[13, 145, 115, 6, 146, 116],
|
|
584
|
+
[14, 74, 46, 23, 75, 47],
|
|
585
|
+
[44, 54, 24, 7, 55, 25],
|
|
586
|
+
[59, 46, 16, 1, 47, 17],
|
|
587
|
+
// 35
|
|
588
|
+
[12, 151, 121, 7, 152, 122],
|
|
589
|
+
[12, 75, 47, 26, 76, 48],
|
|
590
|
+
[39, 54, 24, 14, 55, 25],
|
|
591
|
+
[22, 45, 15, 41, 46, 16],
|
|
592
|
+
// 36
|
|
593
|
+
[6, 151, 121, 14, 152, 122],
|
|
594
|
+
[6, 75, 47, 34, 76, 48],
|
|
595
|
+
[46, 54, 24, 10, 55, 25],
|
|
596
|
+
[2, 45, 15, 64, 46, 16],
|
|
597
|
+
// 37
|
|
598
|
+
[17, 152, 122, 4, 153, 123],
|
|
599
|
+
[29, 74, 46, 14, 75, 47],
|
|
600
|
+
[49, 54, 24, 10, 55, 25],
|
|
601
|
+
[24, 45, 15, 46, 46, 16],
|
|
602
|
+
// 38
|
|
603
|
+
[4, 152, 122, 18, 153, 123],
|
|
604
|
+
[13, 74, 46, 32, 75, 47],
|
|
605
|
+
[48, 54, 24, 14, 55, 25],
|
|
606
|
+
[42, 45, 15, 32, 46, 16],
|
|
607
|
+
// 39
|
|
608
|
+
[20, 147, 117, 4, 148, 118],
|
|
609
|
+
[40, 75, 47, 7, 76, 48],
|
|
610
|
+
[43, 54, 24, 22, 55, 25],
|
|
611
|
+
[10, 45, 15, 67, 46, 16],
|
|
612
|
+
// 40
|
|
613
|
+
[19, 148, 118, 6, 149, 119],
|
|
614
|
+
[18, 75, 47, 31, 76, 48],
|
|
615
|
+
[34, 54, 24, 34, 55, 25],
|
|
616
|
+
[20, 45, 15, 61, 46, 16]
|
|
617
|
+
];
|
|
618
|
+
QRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) {
|
|
619
|
+
var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
|
|
620
|
+
if (rsBlock === void 0) {
|
|
621
|
+
throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel);
|
|
622
|
+
}
|
|
623
|
+
var length = rsBlock.length / 3;
|
|
624
|
+
var list = [];
|
|
625
|
+
for (var i = 0; i < length; i++) {
|
|
626
|
+
var count = rsBlock[i * 3 + 0];
|
|
627
|
+
var totalCount = rsBlock[i * 3 + 1];
|
|
628
|
+
var dataCount = rsBlock[i * 3 + 2];
|
|
629
|
+
for (var j = 0; j < count; j++) {
|
|
630
|
+
list.push(new QRRSBlock(totalCount, dataCount));
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
return list;
|
|
634
|
+
};
|
|
635
|
+
QRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) {
|
|
636
|
+
switch (errorCorrectLevel) {
|
|
637
|
+
case QRErrorCorrectLevel.L:
|
|
638
|
+
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
|
|
639
|
+
case QRErrorCorrectLevel.M:
|
|
640
|
+
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
|
|
641
|
+
case QRErrorCorrectLevel.Q:
|
|
642
|
+
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
|
|
643
|
+
case QRErrorCorrectLevel.H:
|
|
644
|
+
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
|
|
645
|
+
default:
|
|
646
|
+
return void 0;
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
module.exports = QRRSBlock;
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
// ../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRBitBuffer.js
|
|
654
|
+
var require_QRBitBuffer = __commonJS({
|
|
655
|
+
"../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRBitBuffer.js"(exports, module) {
|
|
656
|
+
function QRBitBuffer() {
|
|
657
|
+
this.buffer = [];
|
|
658
|
+
this.length = 0;
|
|
659
|
+
}
|
|
660
|
+
QRBitBuffer.prototype = {
|
|
661
|
+
get: function(index) {
|
|
662
|
+
var bufIndex = Math.floor(index / 8);
|
|
663
|
+
return (this.buffer[bufIndex] >>> 7 - index % 8 & 1) == 1;
|
|
664
|
+
},
|
|
665
|
+
put: function(num, length) {
|
|
666
|
+
for (var i = 0; i < length; i++) {
|
|
667
|
+
this.putBit((num >>> length - i - 1 & 1) == 1);
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
getLengthInBits: function() {
|
|
671
|
+
return this.length;
|
|
672
|
+
},
|
|
673
|
+
putBit: function(bit) {
|
|
674
|
+
var bufIndex = Math.floor(this.length / 8);
|
|
675
|
+
if (this.buffer.length <= bufIndex) {
|
|
676
|
+
this.buffer.push(0);
|
|
677
|
+
}
|
|
678
|
+
if (bit) {
|
|
679
|
+
this.buffer[bufIndex] |= 128 >>> this.length % 8;
|
|
680
|
+
}
|
|
681
|
+
this.length++;
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
module.exports = QRBitBuffer;
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
// ../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/index.js
|
|
689
|
+
var require_QRCode = __commonJS({
|
|
690
|
+
"../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/index.js"(exports, module) {
|
|
691
|
+
var QR8bitByte = require_QR8bitByte();
|
|
692
|
+
var QRUtil = require_QRUtil();
|
|
693
|
+
var QRPolynomial = require_QRPolynomial();
|
|
694
|
+
var QRRSBlock = require_QRRSBlock();
|
|
695
|
+
var QRBitBuffer = require_QRBitBuffer();
|
|
696
|
+
function QRCode(typeNumber, errorCorrectLevel) {
|
|
697
|
+
this.typeNumber = typeNumber;
|
|
698
|
+
this.errorCorrectLevel = errorCorrectLevel;
|
|
699
|
+
this.modules = null;
|
|
700
|
+
this.moduleCount = 0;
|
|
701
|
+
this.dataCache = null;
|
|
702
|
+
this.dataList = [];
|
|
703
|
+
}
|
|
704
|
+
QRCode.prototype = {
|
|
705
|
+
addData: function(data) {
|
|
706
|
+
var newData = new QR8bitByte(data);
|
|
707
|
+
this.dataList.push(newData);
|
|
708
|
+
this.dataCache = null;
|
|
709
|
+
},
|
|
710
|
+
isDark: function(row, col) {
|
|
711
|
+
if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
|
|
712
|
+
throw new Error(row + "," + col);
|
|
713
|
+
}
|
|
714
|
+
return this.modules[row][col];
|
|
715
|
+
},
|
|
716
|
+
getModuleCount: function() {
|
|
717
|
+
return this.moduleCount;
|
|
718
|
+
},
|
|
719
|
+
make: function() {
|
|
720
|
+
if (this.typeNumber < 1) {
|
|
721
|
+
var typeNumber = 1;
|
|
722
|
+
for (typeNumber = 1; typeNumber < 40; typeNumber++) {
|
|
723
|
+
var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel);
|
|
724
|
+
var buffer = new QRBitBuffer();
|
|
725
|
+
var totalDataCount = 0;
|
|
726
|
+
for (var i = 0; i < rsBlocks.length; i++) {
|
|
727
|
+
totalDataCount += rsBlocks[i].dataCount;
|
|
728
|
+
}
|
|
729
|
+
for (var x = 0; x < this.dataList.length; x++) {
|
|
730
|
+
var data = this.dataList[x];
|
|
731
|
+
buffer.put(data.mode, 4);
|
|
732
|
+
buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
|
|
733
|
+
data.write(buffer);
|
|
734
|
+
}
|
|
735
|
+
if (buffer.getLengthInBits() <= totalDataCount * 8)
|
|
736
|
+
break;
|
|
737
|
+
}
|
|
738
|
+
this.typeNumber = typeNumber;
|
|
739
|
+
}
|
|
740
|
+
this.makeImpl(false, this.getBestMaskPattern());
|
|
741
|
+
},
|
|
742
|
+
makeImpl: function(test, maskPattern) {
|
|
743
|
+
this.moduleCount = this.typeNumber * 4 + 17;
|
|
744
|
+
this.modules = new Array(this.moduleCount);
|
|
745
|
+
for (var row = 0; row < this.moduleCount; row++) {
|
|
746
|
+
this.modules[row] = new Array(this.moduleCount);
|
|
747
|
+
for (var col = 0; col < this.moduleCount; col++) {
|
|
748
|
+
this.modules[row][col] = null;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
this.setupPositionProbePattern(0, 0);
|
|
752
|
+
this.setupPositionProbePattern(this.moduleCount - 7, 0);
|
|
753
|
+
this.setupPositionProbePattern(0, this.moduleCount - 7);
|
|
754
|
+
this.setupPositionAdjustPattern();
|
|
755
|
+
this.setupTimingPattern();
|
|
756
|
+
this.setupTypeInfo(test, maskPattern);
|
|
757
|
+
if (this.typeNumber >= 7) {
|
|
758
|
+
this.setupTypeNumber(test);
|
|
759
|
+
}
|
|
760
|
+
if (this.dataCache === null) {
|
|
761
|
+
this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
|
|
762
|
+
}
|
|
763
|
+
this.mapData(this.dataCache, maskPattern);
|
|
764
|
+
},
|
|
765
|
+
setupPositionProbePattern: function(row, col) {
|
|
766
|
+
for (var r = -1; r <= 7; r++) {
|
|
767
|
+
if (row + r <= -1 || this.moduleCount <= row + r) continue;
|
|
768
|
+
for (var c = -1; c <= 7; c++) {
|
|
769
|
+
if (col + c <= -1 || this.moduleCount <= col + c) continue;
|
|
770
|
+
if (0 <= r && r <= 6 && (c === 0 || c === 6) || 0 <= c && c <= 6 && (r === 0 || r === 6) || 2 <= r && r <= 4 && 2 <= c && c <= 4) {
|
|
771
|
+
this.modules[row + r][col + c] = true;
|
|
772
|
+
} else {
|
|
773
|
+
this.modules[row + r][col + c] = false;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
},
|
|
778
|
+
getBestMaskPattern: function() {
|
|
779
|
+
var minLostPoint = 0;
|
|
780
|
+
var pattern = 0;
|
|
781
|
+
for (var i = 0; i < 8; i++) {
|
|
782
|
+
this.makeImpl(true, i);
|
|
783
|
+
var lostPoint = QRUtil.getLostPoint(this);
|
|
784
|
+
if (i === 0 || minLostPoint > lostPoint) {
|
|
785
|
+
minLostPoint = lostPoint;
|
|
786
|
+
pattern = i;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return pattern;
|
|
790
|
+
},
|
|
791
|
+
createMovieClip: function(target_mc, instance_name, depth) {
|
|
792
|
+
var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
|
|
793
|
+
var cs = 1;
|
|
794
|
+
this.make();
|
|
795
|
+
for (var row = 0; row < this.modules.length; row++) {
|
|
796
|
+
var y = row * cs;
|
|
797
|
+
for (var col = 0; col < this.modules[row].length; col++) {
|
|
798
|
+
var x = col * cs;
|
|
799
|
+
var dark = this.modules[row][col];
|
|
800
|
+
if (dark) {
|
|
801
|
+
qr_mc.beginFill(0, 100);
|
|
802
|
+
qr_mc.moveTo(x, y);
|
|
803
|
+
qr_mc.lineTo(x + cs, y);
|
|
804
|
+
qr_mc.lineTo(x + cs, y + cs);
|
|
805
|
+
qr_mc.lineTo(x, y + cs);
|
|
806
|
+
qr_mc.endFill();
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
return qr_mc;
|
|
811
|
+
},
|
|
812
|
+
setupTimingPattern: function() {
|
|
813
|
+
for (var r = 8; r < this.moduleCount - 8; r++) {
|
|
814
|
+
if (this.modules[r][6] !== null) {
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
817
|
+
this.modules[r][6] = r % 2 === 0;
|
|
818
|
+
}
|
|
819
|
+
for (var c = 8; c < this.moduleCount - 8; c++) {
|
|
820
|
+
if (this.modules[6][c] !== null) {
|
|
821
|
+
continue;
|
|
822
|
+
}
|
|
823
|
+
this.modules[6][c] = c % 2 === 0;
|
|
824
|
+
}
|
|
825
|
+
},
|
|
826
|
+
setupPositionAdjustPattern: function() {
|
|
827
|
+
var pos = QRUtil.getPatternPosition(this.typeNumber);
|
|
828
|
+
for (var i = 0; i < pos.length; i++) {
|
|
829
|
+
for (var j = 0; j < pos.length; j++) {
|
|
830
|
+
var row = pos[i];
|
|
831
|
+
var col = pos[j];
|
|
832
|
+
if (this.modules[row][col] !== null) {
|
|
833
|
+
continue;
|
|
834
|
+
}
|
|
835
|
+
for (var r = -2; r <= 2; r++) {
|
|
836
|
+
for (var c = -2; c <= 2; c++) {
|
|
837
|
+
if (Math.abs(r) === 2 || Math.abs(c) === 2 || r === 0 && c === 0) {
|
|
838
|
+
this.modules[row + r][col + c] = true;
|
|
839
|
+
} else {
|
|
840
|
+
this.modules[row + r][col + c] = false;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
},
|
|
847
|
+
setupTypeNumber: function(test) {
|
|
848
|
+
var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
|
|
849
|
+
var mod;
|
|
850
|
+
for (var i = 0; i < 18; i++) {
|
|
851
|
+
mod = !test && (bits >> i & 1) === 1;
|
|
852
|
+
this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
|
|
853
|
+
}
|
|
854
|
+
for (var x = 0; x < 18; x++) {
|
|
855
|
+
mod = !test && (bits >> x & 1) === 1;
|
|
856
|
+
this.modules[x % 3 + this.moduleCount - 8 - 3][Math.floor(x / 3)] = mod;
|
|
857
|
+
}
|
|
858
|
+
},
|
|
859
|
+
setupTypeInfo: function(test, maskPattern) {
|
|
860
|
+
var data = this.errorCorrectLevel << 3 | maskPattern;
|
|
861
|
+
var bits = QRUtil.getBCHTypeInfo(data);
|
|
862
|
+
var mod;
|
|
863
|
+
for (var v = 0; v < 15; v++) {
|
|
864
|
+
mod = !test && (bits >> v & 1) === 1;
|
|
865
|
+
if (v < 6) {
|
|
866
|
+
this.modules[v][8] = mod;
|
|
867
|
+
} else if (v < 8) {
|
|
868
|
+
this.modules[v + 1][8] = mod;
|
|
869
|
+
} else {
|
|
870
|
+
this.modules[this.moduleCount - 15 + v][8] = mod;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
for (var h = 0; h < 15; h++) {
|
|
874
|
+
mod = !test && (bits >> h & 1) === 1;
|
|
875
|
+
if (h < 8) {
|
|
876
|
+
this.modules[8][this.moduleCount - h - 1] = mod;
|
|
877
|
+
} else if (h < 9) {
|
|
878
|
+
this.modules[8][15 - h - 1 + 1] = mod;
|
|
879
|
+
} else {
|
|
880
|
+
this.modules[8][15 - h - 1] = mod;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
this.modules[this.moduleCount - 8][8] = !test;
|
|
884
|
+
},
|
|
885
|
+
mapData: function(data, maskPattern) {
|
|
886
|
+
var inc = -1;
|
|
887
|
+
var row = this.moduleCount - 1;
|
|
888
|
+
var bitIndex = 7;
|
|
889
|
+
var byteIndex = 0;
|
|
890
|
+
for (var col = this.moduleCount - 1; col > 0; col -= 2) {
|
|
891
|
+
if (col === 6) col--;
|
|
892
|
+
while (true) {
|
|
893
|
+
for (var c = 0; c < 2; c++) {
|
|
894
|
+
if (this.modules[row][col - c] === null) {
|
|
895
|
+
var dark = false;
|
|
896
|
+
if (byteIndex < data.length) {
|
|
897
|
+
dark = (data[byteIndex] >>> bitIndex & 1) === 1;
|
|
898
|
+
}
|
|
899
|
+
var mask = QRUtil.getMask(maskPattern, row, col - c);
|
|
900
|
+
if (mask) {
|
|
901
|
+
dark = !dark;
|
|
902
|
+
}
|
|
903
|
+
this.modules[row][col - c] = dark;
|
|
904
|
+
bitIndex--;
|
|
905
|
+
if (bitIndex === -1) {
|
|
906
|
+
byteIndex++;
|
|
907
|
+
bitIndex = 7;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
row += inc;
|
|
912
|
+
if (row < 0 || this.moduleCount <= row) {
|
|
913
|
+
row -= inc;
|
|
914
|
+
inc = -inc;
|
|
915
|
+
break;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
QRCode.PAD0 = 236;
|
|
922
|
+
QRCode.PAD1 = 17;
|
|
923
|
+
QRCode.createData = function(typeNumber, errorCorrectLevel, dataList) {
|
|
924
|
+
var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
|
|
925
|
+
var buffer = new QRBitBuffer();
|
|
926
|
+
for (var i = 0; i < dataList.length; i++) {
|
|
927
|
+
var data = dataList[i];
|
|
928
|
+
buffer.put(data.mode, 4);
|
|
929
|
+
buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
|
|
930
|
+
data.write(buffer);
|
|
931
|
+
}
|
|
932
|
+
var totalDataCount = 0;
|
|
933
|
+
for (var x = 0; x < rsBlocks.length; x++) {
|
|
934
|
+
totalDataCount += rsBlocks[x].dataCount;
|
|
935
|
+
}
|
|
936
|
+
if (buffer.getLengthInBits() > totalDataCount * 8) {
|
|
937
|
+
throw new Error("code length overflow. (" + buffer.getLengthInBits() + ">" + totalDataCount * 8 + ")");
|
|
938
|
+
}
|
|
939
|
+
if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
|
|
940
|
+
buffer.put(0, 4);
|
|
941
|
+
}
|
|
942
|
+
while (buffer.getLengthInBits() % 8 !== 0) {
|
|
943
|
+
buffer.putBit(false);
|
|
944
|
+
}
|
|
945
|
+
while (true) {
|
|
946
|
+
if (buffer.getLengthInBits() >= totalDataCount * 8) {
|
|
947
|
+
break;
|
|
948
|
+
}
|
|
949
|
+
buffer.put(QRCode.PAD0, 8);
|
|
950
|
+
if (buffer.getLengthInBits() >= totalDataCount * 8) {
|
|
951
|
+
break;
|
|
952
|
+
}
|
|
953
|
+
buffer.put(QRCode.PAD1, 8);
|
|
954
|
+
}
|
|
955
|
+
return QRCode.createBytes(buffer, rsBlocks);
|
|
956
|
+
};
|
|
957
|
+
QRCode.createBytes = function(buffer, rsBlocks) {
|
|
958
|
+
var offset = 0;
|
|
959
|
+
var maxDcCount = 0;
|
|
960
|
+
var maxEcCount = 0;
|
|
961
|
+
var dcdata = new Array(rsBlocks.length);
|
|
962
|
+
var ecdata = new Array(rsBlocks.length);
|
|
963
|
+
for (var r = 0; r < rsBlocks.length; r++) {
|
|
964
|
+
var dcCount = rsBlocks[r].dataCount;
|
|
965
|
+
var ecCount = rsBlocks[r].totalCount - dcCount;
|
|
966
|
+
maxDcCount = Math.max(maxDcCount, dcCount);
|
|
967
|
+
maxEcCount = Math.max(maxEcCount, ecCount);
|
|
968
|
+
dcdata[r] = new Array(dcCount);
|
|
969
|
+
for (var i = 0; i < dcdata[r].length; i++) {
|
|
970
|
+
dcdata[r][i] = 255 & buffer.buffer[i + offset];
|
|
971
|
+
}
|
|
972
|
+
offset += dcCount;
|
|
973
|
+
var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
|
|
974
|
+
var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
|
|
975
|
+
var modPoly = rawPoly.mod(rsPoly);
|
|
976
|
+
ecdata[r] = new Array(rsPoly.getLength() - 1);
|
|
977
|
+
for (var x = 0; x < ecdata[r].length; x++) {
|
|
978
|
+
var modIndex = x + modPoly.getLength() - ecdata[r].length;
|
|
979
|
+
ecdata[r][x] = modIndex >= 0 ? modPoly.get(modIndex) : 0;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
var totalCodeCount = 0;
|
|
983
|
+
for (var y = 0; y < rsBlocks.length; y++) {
|
|
984
|
+
totalCodeCount += rsBlocks[y].totalCount;
|
|
985
|
+
}
|
|
986
|
+
var data = new Array(totalCodeCount);
|
|
987
|
+
var index = 0;
|
|
988
|
+
for (var z = 0; z < maxDcCount; z++) {
|
|
989
|
+
for (var s = 0; s < rsBlocks.length; s++) {
|
|
990
|
+
if (z < dcdata[s].length) {
|
|
991
|
+
data[index++] = dcdata[s][z];
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
for (var xx = 0; xx < maxEcCount; xx++) {
|
|
996
|
+
for (var t = 0; t < rsBlocks.length; t++) {
|
|
997
|
+
if (xx < ecdata[t].length) {
|
|
998
|
+
data[index++] = ecdata[t][xx];
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
return data;
|
|
1003
|
+
};
|
|
1004
|
+
module.exports = QRCode;
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
// ../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/lib/main.js
|
|
1009
|
+
var require_main = __commonJS({
|
|
1010
|
+
"../../node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/lib/main.js"(exports, module) {
|
|
1011
|
+
var QRCode = require_QRCode();
|
|
1012
|
+
var QRErrorCorrectLevel = require_QRErrorCorrectLevel();
|
|
1013
|
+
var black = "\x1B[40m \x1B[0m";
|
|
1014
|
+
var white = "\x1B[47m \x1B[0m";
|
|
1015
|
+
var toCell = function(isBlack) {
|
|
1016
|
+
return isBlack ? black : white;
|
|
1017
|
+
};
|
|
1018
|
+
var repeat = function(color) {
|
|
1019
|
+
return {
|
|
1020
|
+
times: function(count) {
|
|
1021
|
+
return new Array(count).join(color);
|
|
1022
|
+
}
|
|
1023
|
+
};
|
|
1024
|
+
};
|
|
1025
|
+
var fill = function(length, value) {
|
|
1026
|
+
var arr = new Array(length);
|
|
1027
|
+
for (var i = 0; i < length; i++) {
|
|
1028
|
+
arr[i] = value;
|
|
1029
|
+
}
|
|
1030
|
+
return arr;
|
|
1031
|
+
};
|
|
1032
|
+
module.exports = {
|
|
1033
|
+
error: QRErrorCorrectLevel.L,
|
|
1034
|
+
generate: function(input2, opts, cb) {
|
|
1035
|
+
if (typeof opts === "function") {
|
|
1036
|
+
cb = opts;
|
|
1037
|
+
opts = {};
|
|
1038
|
+
}
|
|
1039
|
+
var qrcode2 = new QRCode(-1, this.error);
|
|
1040
|
+
qrcode2.addData(input2);
|
|
1041
|
+
qrcode2.make();
|
|
1042
|
+
var output2 = "";
|
|
1043
|
+
if (opts && opts.small) {
|
|
1044
|
+
var BLACK = true, WHITE = false;
|
|
1045
|
+
var moduleCount = qrcode2.getModuleCount();
|
|
1046
|
+
var moduleData = qrcode2.modules.slice();
|
|
1047
|
+
var oddRow = moduleCount % 2 === 1;
|
|
1048
|
+
if (oddRow) {
|
|
1049
|
+
moduleData.push(fill(moduleCount, WHITE));
|
|
1050
|
+
}
|
|
1051
|
+
var platte = {
|
|
1052
|
+
WHITE_ALL: "\u2588",
|
|
1053
|
+
WHITE_BLACK: "\u2580",
|
|
1054
|
+
BLACK_WHITE: "\u2584",
|
|
1055
|
+
BLACK_ALL: " "
|
|
1056
|
+
};
|
|
1057
|
+
var borderTop = repeat(platte.BLACK_WHITE).times(moduleCount + 3);
|
|
1058
|
+
var borderBottom = repeat(platte.WHITE_BLACK).times(moduleCount + 3);
|
|
1059
|
+
output2 += borderTop + "\n";
|
|
1060
|
+
for (var row = 0; row < moduleCount; row += 2) {
|
|
1061
|
+
output2 += platte.WHITE_ALL;
|
|
1062
|
+
for (var col = 0; col < moduleCount; col++) {
|
|
1063
|
+
if (moduleData[row][col] === WHITE && moduleData[row + 1][col] === WHITE) {
|
|
1064
|
+
output2 += platte.WHITE_ALL;
|
|
1065
|
+
} else if (moduleData[row][col] === WHITE && moduleData[row + 1][col] === BLACK) {
|
|
1066
|
+
output2 += platte.WHITE_BLACK;
|
|
1067
|
+
} else if (moduleData[row][col] === BLACK && moduleData[row + 1][col] === WHITE) {
|
|
1068
|
+
output2 += platte.BLACK_WHITE;
|
|
1069
|
+
} else {
|
|
1070
|
+
output2 += platte.BLACK_ALL;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
output2 += platte.WHITE_ALL + "\n";
|
|
1074
|
+
}
|
|
1075
|
+
if (!oddRow) {
|
|
1076
|
+
output2 += borderBottom;
|
|
1077
|
+
}
|
|
1078
|
+
} else {
|
|
1079
|
+
var border = repeat(white).times(qrcode2.getModuleCount() + 3);
|
|
1080
|
+
output2 += border + "\n";
|
|
1081
|
+
qrcode2.modules.forEach(function(row2) {
|
|
1082
|
+
output2 += white;
|
|
1083
|
+
output2 += row2.map(toCell).join("");
|
|
1084
|
+
output2 += white + "\n";
|
|
1085
|
+
});
|
|
1086
|
+
output2 += border;
|
|
1087
|
+
}
|
|
1088
|
+
if (cb) cb(output2);
|
|
1089
|
+
else console.log(output2);
|
|
1090
|
+
},
|
|
1091
|
+
setErrorLevel: function(error) {
|
|
1092
|
+
this.error = QRErrorCorrectLevel[error] || this.error;
|
|
1093
|
+
}
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
});
|
|
2
1097
|
|
|
3
1098
|
// src/cli.ts
|
|
4
|
-
import { existsSync as
|
|
5
|
-
import { homedir as
|
|
6
|
-
import { delimiter, dirname as
|
|
1099
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "node:fs";
|
|
1100
|
+
import { homedir as homedir4 } from "node:os";
|
|
1101
|
+
import { delimiter, dirname as dirname4, join as join4, resolve as resolve4 } from "node:path";
|
|
7
1102
|
import { fileURLToPath } from "node:url";
|
|
8
|
-
import { spawn, spawnSync as
|
|
1103
|
+
import { spawn, spawnSync as spawnSync3 } from "node:child_process";
|
|
9
1104
|
import { createInterface } from "node:readline/promises";
|
|
10
1105
|
import { stdin as input, stdout as output } from "node:process";
|
|
11
1106
|
|
|
@@ -100,12 +1195,12 @@ function captureConfigSnapshot(path = configPath()) {
|
|
|
100
1195
|
previous: captureFile(`${path}.previous`)
|
|
101
1196
|
};
|
|
102
1197
|
}
|
|
103
|
-
function restoreConfigSnapshot(
|
|
104
|
-
const previous = `${
|
|
105
|
-
assertNotSymlink(
|
|
1198
|
+
function restoreConfigSnapshot(snapshot2) {
|
|
1199
|
+
const previous = `${snapshot2.path}.previous`;
|
|
1200
|
+
assertNotSymlink(snapshot2.path);
|
|
106
1201
|
assertNotSymlink(previous);
|
|
107
|
-
restoreFile(previous,
|
|
108
|
-
restoreFile(
|
|
1202
|
+
restoreFile(previous, snapshot2.previous);
|
|
1203
|
+
restoreFile(snapshot2.path, snapshot2.config);
|
|
109
1204
|
}
|
|
110
1205
|
function configuredRoots(config) {
|
|
111
1206
|
return Array.isArray(config.allowedRoots) ? config.allowedRoots.filter((root) => typeof root === "string" && root !== "") : [];
|
|
@@ -129,13 +1224,13 @@ function pathExists(path) {
|
|
|
129
1224
|
throw error;
|
|
130
1225
|
}
|
|
131
1226
|
}
|
|
132
|
-
function restoreFile(path,
|
|
133
|
-
if (
|
|
1227
|
+
function restoreFile(path, snapshot2) {
|
|
1228
|
+
if (snapshot2.content === null) {
|
|
134
1229
|
rmSync(path, { force: true });
|
|
135
1230
|
return;
|
|
136
1231
|
}
|
|
137
1232
|
mkdirSync(dirname(path), { recursive: true, mode: 448 });
|
|
138
|
-
writeBytesAtomically(path,
|
|
1233
|
+
writeBytesAtomically(path, snapshot2.content, snapshot2.mode);
|
|
139
1234
|
}
|
|
140
1235
|
function writeBytesAtomically(path, content, mode) {
|
|
141
1236
|
const temp = createTemporaryFile(path, content, mode, "atomic");
|
|
@@ -319,7 +1414,7 @@ function prepareManagedInstall(version, env = process.env) {
|
|
|
319
1414
|
previousMarker = readFileSync2(marker, "utf8");
|
|
320
1415
|
}
|
|
321
1416
|
const activeCli = join2(paths.current, "node_modules", "@longleash", "cli", "bin", "longleash.mjs");
|
|
322
|
-
writeExecutableAtomically(paths.wrapper, wrapper(activeCli));
|
|
1417
|
+
writeExecutableAtomically(paths.wrapper, wrapper(activeCli, process.execPath));
|
|
323
1418
|
wrapperWritten = true;
|
|
324
1419
|
writeFileAtomically(marker, `${JSON.stringify({ schema: 1, package: PACKAGE_NAME }, null, 2)}
|
|
325
1420
|
`, 384);
|
|
@@ -391,10 +1486,10 @@ function uninstallManagedRuntime(env = process.env) {
|
|
|
391
1486
|
rmSync2(paths.home, { recursive: true });
|
|
392
1487
|
return { removed: true, configPreserved: resolve2(env.LONGLEASH_DATA ?? join2(homedir2(), ".longleash")) };
|
|
393
1488
|
}
|
|
394
|
-
function wrapper(cli) {
|
|
1489
|
+
function wrapper(cli, node) {
|
|
395
1490
|
return `#!/bin/sh
|
|
396
1491
|
${WRAPPER_MARKER}
|
|
397
|
-
exec node ${shellQuote(cli)} "$@"
|
|
1492
|
+
exec ${shellQuote(node)} ${shellQuote(cli)} "$@"
|
|
398
1493
|
`;
|
|
399
1494
|
}
|
|
400
1495
|
function shellQuote(value) {
|
|
@@ -516,15 +1611,492 @@ function processAlive(pid) {
|
|
|
516
1611
|
}
|
|
517
1612
|
}
|
|
518
1613
|
|
|
1614
|
+
// src/service.ts
|
|
1615
|
+
import {
|
|
1616
|
+
chmodSync as chmodSync2,
|
|
1617
|
+
existsSync as existsSync2,
|
|
1618
|
+
lstatSync as lstatSync3,
|
|
1619
|
+
mkdirSync as mkdirSync3,
|
|
1620
|
+
readFileSync as readFileSync3,
|
|
1621
|
+
renameSync as renameSync3,
|
|
1622
|
+
rmSync as rmSync3,
|
|
1623
|
+
writeFileSync as writeFileSync3
|
|
1624
|
+
} from "node:fs";
|
|
1625
|
+
import { homedir as homedir3 } from "node:os";
|
|
1626
|
+
import { dirname as dirname3, join as join3, resolve as resolve3 } from "node:path";
|
|
1627
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
1628
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
1629
|
+
var SERVICE_LABEL = "dev.longleash.daemon";
|
|
1630
|
+
var SYSTEMD_UNIT = "longleash.service";
|
|
1631
|
+
var MANAGED_MARKER = "Managed by @longleash/cli";
|
|
1632
|
+
function servicePaths(context = {}) {
|
|
1633
|
+
const env = context.env ?? process.env;
|
|
1634
|
+
const platform = supportedPlatform(context.platform ?? process.platform);
|
|
1635
|
+
const home = resolve3(context.home ?? homedir3());
|
|
1636
|
+
const data = dataDir(env);
|
|
1637
|
+
const logs = join3(data, "logs");
|
|
1638
|
+
const wrapper2 = installPaths(env).wrapper;
|
|
1639
|
+
if (platform === "darwin") {
|
|
1640
|
+
return {
|
|
1641
|
+
data,
|
|
1642
|
+
logs,
|
|
1643
|
+
stdout: join3(logs, "daemon.stdout.log"),
|
|
1644
|
+
stderr: join3(logs, "daemon.stderr.log"),
|
|
1645
|
+
definition: join3(home, "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`),
|
|
1646
|
+
wrapper: wrapper2
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
return {
|
|
1650
|
+
data,
|
|
1651
|
+
logs,
|
|
1652
|
+
stdout: "journal",
|
|
1653
|
+
stderr: "journal",
|
|
1654
|
+
definition: join3(home, ".config", "systemd", "user", SYSTEMD_UNIT),
|
|
1655
|
+
environment: join3(home, ".config", "longleash", "service.env"),
|
|
1656
|
+
wrapper: wrapper2
|
|
1657
|
+
};
|
|
1658
|
+
}
|
|
1659
|
+
function renderLaunchAgent(paths, env = process.env) {
|
|
1660
|
+
const path = requiredEnvironment(env, "PATH", "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin");
|
|
1661
|
+
const home = resolve3(env.HOME ?? homedir3());
|
|
1662
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
1663
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
1664
|
+
<!-- ${MANAGED_MARKER} -->
|
|
1665
|
+
<plist version="1.0">
|
|
1666
|
+
<dict>
|
|
1667
|
+
<key>Label</key>
|
|
1668
|
+
<string>${xml(SERVICE_LABEL)}</string>
|
|
1669
|
+
<key>ProgramArguments</key>
|
|
1670
|
+
<array>
|
|
1671
|
+
<string>${xml(paths.wrapper)}</string>
|
|
1672
|
+
<string>run</string>
|
|
1673
|
+
</array>
|
|
1674
|
+
<key>EnvironmentVariables</key>
|
|
1675
|
+
<dict>
|
|
1676
|
+
<key>HOME</key>
|
|
1677
|
+
<string>${xml(home)}</string>
|
|
1678
|
+
<key>PATH</key>
|
|
1679
|
+
<string>${xml(path)}</string>
|
|
1680
|
+
<key>LONGLEASH_DATA</key>
|
|
1681
|
+
<string>${xml(paths.data)}</string>
|
|
1682
|
+
<key>LONGLEASH_SERVICE</key>
|
|
1683
|
+
<string>1</string>
|
|
1684
|
+
</dict>
|
|
1685
|
+
<key>WorkingDirectory</key>
|
|
1686
|
+
<string>${xml(home)}</string>
|
|
1687
|
+
<key>RunAtLoad</key>
|
|
1688
|
+
<true/>
|
|
1689
|
+
<key>KeepAlive</key>
|
|
1690
|
+
<true/>
|
|
1691
|
+
<key>ThrottleInterval</key>
|
|
1692
|
+
<integer>15</integer>
|
|
1693
|
+
<key>ProcessType</key>
|
|
1694
|
+
<string>Background</string>
|
|
1695
|
+
<key>Umask</key>
|
|
1696
|
+
<integer>63</integer>
|
|
1697
|
+
<key>StandardOutPath</key>
|
|
1698
|
+
<string>${xml(paths.stdout)}</string>
|
|
1699
|
+
<key>StandardErrorPath</key>
|
|
1700
|
+
<string>${xml(paths.stderr)}</string>
|
|
1701
|
+
</dict>
|
|
1702
|
+
</plist>
|
|
1703
|
+
`;
|
|
1704
|
+
}
|
|
1705
|
+
function renderSystemdUnit(paths, home) {
|
|
1706
|
+
if (!paths.environment) throw new Error("The Linux service environment path is missing.");
|
|
1707
|
+
return `# ${MANAGED_MARKER}
|
|
1708
|
+
[Unit]
|
|
1709
|
+
Description=LongLeash phone control plane
|
|
1710
|
+
Documentation=https://longleash.dev/docs/background-service
|
|
1711
|
+
StartLimitIntervalSec=60
|
|
1712
|
+
StartLimitBurst=5
|
|
1713
|
+
|
|
1714
|
+
[Service]
|
|
1715
|
+
Type=simple
|
|
1716
|
+
ExecStart=${systemdQuote(paths.wrapper)} run
|
|
1717
|
+
EnvironmentFile=${systemdQuote(paths.environment)}
|
|
1718
|
+
WorkingDirectory=${systemdQuote(home)}
|
|
1719
|
+
UMask=0077
|
|
1720
|
+
Restart=on-failure
|
|
1721
|
+
RestartSec=5s
|
|
1722
|
+
TimeoutStopSec=30s
|
|
1723
|
+
KillMode=mixed
|
|
1724
|
+
|
|
1725
|
+
[Install]
|
|
1726
|
+
WantedBy=default.target
|
|
1727
|
+
`;
|
|
1728
|
+
}
|
|
1729
|
+
function renderSystemdEnvironment(paths, env = process.env) {
|
|
1730
|
+
const home = resolve3(env.HOME ?? homedir3());
|
|
1731
|
+
const path = requiredEnvironment(env, "PATH", "/usr/local/bin:/usr/bin:/bin");
|
|
1732
|
+
return `# ${MANAGED_MARKER}
|
|
1733
|
+
HOME=${environmentQuote(home)}
|
|
1734
|
+
PATH=${environmentQuote(path)}
|
|
1735
|
+
LONGLEASH_DATA=${environmentQuote(paths.data)}
|
|
1736
|
+
LONGLEASH_SERVICE=1
|
|
1737
|
+
`;
|
|
1738
|
+
}
|
|
1739
|
+
function serviceState(context = {}) {
|
|
1740
|
+
const resolved = resolveContext(context);
|
|
1741
|
+
const installed = managedDefinitionExists(resolved.paths.definition);
|
|
1742
|
+
if (installed && resolved.paths.environment) assertManagedDefinition(resolved.paths.environment);
|
|
1743
|
+
if (resolved.platform === "darwin") {
|
|
1744
|
+
const loaded2 = launchdLoaded(resolved);
|
|
1745
|
+
return {
|
|
1746
|
+
platform: "darwin",
|
|
1747
|
+
installed,
|
|
1748
|
+
loaded: loaded2,
|
|
1749
|
+
active: loaded2,
|
|
1750
|
+
definition: resolved.paths.definition,
|
|
1751
|
+
logs: resolved.paths.logs,
|
|
1752
|
+
loginOnly: false
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
const loaded = run(resolved, "systemctl", ["--user", "is-enabled", "--quiet", SYSTEMD_UNIT]).status === 0;
|
|
1756
|
+
const active = run(resolved, "systemctl", ["--user", "is-active", "--quiet", SYSTEMD_UNIT]).status === 0;
|
|
1757
|
+
return {
|
|
1758
|
+
platform: "linux",
|
|
1759
|
+
installed,
|
|
1760
|
+
loaded,
|
|
1761
|
+
active,
|
|
1762
|
+
definition: resolved.paths.definition,
|
|
1763
|
+
logs: "journalctl --user-unit longleash.service",
|
|
1764
|
+
loginOnly: !lingerEnabled(resolved)
|
|
1765
|
+
};
|
|
1766
|
+
}
|
|
1767
|
+
function installService(context = {}) {
|
|
1768
|
+
const resolved = resolveContext(context);
|
|
1769
|
+
assertManagedWrapper(resolved.paths.wrapper);
|
|
1770
|
+
mkdirSync3(resolved.paths.logs, { recursive: true, mode: 448 });
|
|
1771
|
+
if (resolved.platform === "darwin") installLaunchAgent(resolved);
|
|
1772
|
+
else installSystemdService(resolved);
|
|
1773
|
+
return serviceState(context);
|
|
1774
|
+
}
|
|
1775
|
+
function startService(context = {}) {
|
|
1776
|
+
const resolved = resolveContext(context);
|
|
1777
|
+
assertServiceInstallation(resolved);
|
|
1778
|
+
if (resolved.platform === "darwin") {
|
|
1779
|
+
if (launchdLoaded(resolved)) requireSuccess(resolved, "/bin/launchctl", ["kickstart", "-k", serviceTarget(resolved)]);
|
|
1780
|
+
else requireSuccess(resolved, "/bin/launchctl", ["bootstrap", launchDomain(resolved), resolved.paths.definition]);
|
|
1781
|
+
} else {
|
|
1782
|
+
requireSuccess(resolved, "systemctl", ["--user", "start", SYSTEMD_UNIT]);
|
|
1783
|
+
}
|
|
1784
|
+
return serviceState(context);
|
|
1785
|
+
}
|
|
1786
|
+
function stopService(context = {}) {
|
|
1787
|
+
const resolved = resolveContext(context);
|
|
1788
|
+
if (resolved.platform === "darwin") {
|
|
1789
|
+
const loaded = launchdLoaded(resolved);
|
|
1790
|
+
if (loaded) {
|
|
1791
|
+
assertManagedDefinition(resolved.paths.definition);
|
|
1792
|
+
requireSuccess(resolved, "/bin/launchctl", ["bootout", serviceTarget(resolved)]);
|
|
1793
|
+
}
|
|
1794
|
+
} else if (run(resolved, "systemctl", ["--user", "is-active", "--quiet", SYSTEMD_UNIT]).status === 0) {
|
|
1795
|
+
assertManagedDefinition(resolved.paths.definition);
|
|
1796
|
+
requireSuccess(resolved, "systemctl", ["--user", "stop", SYSTEMD_UNIT]);
|
|
1797
|
+
}
|
|
1798
|
+
return serviceState(context);
|
|
1799
|
+
}
|
|
1800
|
+
function restartService(context = {}) {
|
|
1801
|
+
const resolved = resolveContext(context);
|
|
1802
|
+
assertServiceInstallation(resolved);
|
|
1803
|
+
if (resolved.platform === "darwin") {
|
|
1804
|
+
if (launchdLoaded(resolved)) requireSuccess(resolved, "/bin/launchctl", ["kickstart", "-k", serviceTarget(resolved)]);
|
|
1805
|
+
else requireSuccess(resolved, "/bin/launchctl", ["bootstrap", launchDomain(resolved), resolved.paths.definition]);
|
|
1806
|
+
} else {
|
|
1807
|
+
requireSuccess(resolved, "systemctl", ["--user", "restart", SYSTEMD_UNIT]);
|
|
1808
|
+
}
|
|
1809
|
+
return serviceState(context);
|
|
1810
|
+
}
|
|
1811
|
+
function uninstallService(context = {}) {
|
|
1812
|
+
const resolved = resolveContext(context);
|
|
1813
|
+
const installed = managedDefinitionExists(resolved.paths.definition);
|
|
1814
|
+
if (resolved.platform === "darwin") {
|
|
1815
|
+
const loaded = launchdLoaded(resolved);
|
|
1816
|
+
if (loaded && !installed) {
|
|
1817
|
+
throw new Error(`Refusing to stop an unowned launchd job without a managed definition: ${resolved.paths.definition}`);
|
|
1818
|
+
}
|
|
1819
|
+
if (loaded) requireSuccess(resolved, "/bin/launchctl", ["bootout", serviceTarget(resolved)]);
|
|
1820
|
+
if (installed) rmSync3(resolved.paths.definition);
|
|
1821
|
+
} else {
|
|
1822
|
+
if (installed) {
|
|
1823
|
+
const disabled = run(resolved, "systemctl", ["--user", "disable", "--now", SYSTEMD_UNIT]);
|
|
1824
|
+
if (disabled.status !== 0 && run(resolved, "systemctl", ["--user", "is-enabled", "--quiet", SYSTEMD_UNIT]).status === 0) {
|
|
1825
|
+
throw commandError("systemctl", ["--user", "disable", "--now", SYSTEMD_UNIT], disabled);
|
|
1826
|
+
}
|
|
1827
|
+
rmSync3(resolved.paths.definition);
|
|
1828
|
+
}
|
|
1829
|
+
if (resolved.paths.environment && managedFileExists(resolved.paths.environment)) {
|
|
1830
|
+
assertManagedDefinition(resolved.paths.environment);
|
|
1831
|
+
rmSync3(resolved.paths.environment);
|
|
1832
|
+
}
|
|
1833
|
+
requireSuccess(resolved, "systemctl", ["--user", "daemon-reload"]);
|
|
1834
|
+
run(resolved, "systemctl", ["--user", "reset-failed", SYSTEMD_UNIT]);
|
|
1835
|
+
}
|
|
1836
|
+
return serviceState(context);
|
|
1837
|
+
}
|
|
1838
|
+
function showServiceLogs(follow, context = {}) {
|
|
1839
|
+
const resolved = resolveContext(context);
|
|
1840
|
+
if (resolved.platform === "darwin") {
|
|
1841
|
+
mkdirSync3(resolved.paths.logs, { recursive: true, mode: 448 });
|
|
1842
|
+
for (const path of [resolved.paths.stdout, resolved.paths.stderr]) {
|
|
1843
|
+
if (!existsSync2(path)) writeFileSync3(path, "", { mode: 384 });
|
|
1844
|
+
}
|
|
1845
|
+
return passthrough(resolved, "/usr/bin/tail", [...follow ? ["-f"] : [], "-n", "200", resolved.paths.stdout, resolved.paths.stderr]);
|
|
1846
|
+
}
|
|
1847
|
+
return passthrough(resolved, "journalctl", ["--user-unit", SYSTEMD_UNIT, "-n", "200", "--no-pager", ...follow ? ["--follow"] : []]);
|
|
1848
|
+
}
|
|
1849
|
+
function installLaunchAgent(context) {
|
|
1850
|
+
const content = renderLaunchAgent(context.paths, context.env);
|
|
1851
|
+
const previous = snapshot(context.paths.definition);
|
|
1852
|
+
const wasLoaded = launchdLoaded(context);
|
|
1853
|
+
if (wasLoaded && previous === null) {
|
|
1854
|
+
throw new Error(`Refusing to replace an unowned launchd job without a managed definition: ${context.paths.definition}`);
|
|
1855
|
+
}
|
|
1856
|
+
if (wasLoaded) requireSuccess(context, "/bin/launchctl", ["bootout", serviceTarget(context)]);
|
|
1857
|
+
try {
|
|
1858
|
+
writeManagedAtomically(context.paths.definition, content, 384, (temporary) => {
|
|
1859
|
+
requireSuccess(context, "/usr/bin/plutil", ["-lint", temporary]);
|
|
1860
|
+
});
|
|
1861
|
+
requireSuccess(context, "/bin/launchctl", ["bootstrap", launchDomain(context), context.paths.definition]);
|
|
1862
|
+
} catch (error) {
|
|
1863
|
+
restore(context.paths.definition, previous);
|
|
1864
|
+
if (previous !== null && wasLoaded) run(context, "/bin/launchctl", ["bootstrap", launchDomain(context), context.paths.definition]);
|
|
1865
|
+
throw error;
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
function installSystemdService(context) {
|
|
1869
|
+
if (!context.paths.environment) throw new Error("The Linux service environment path is missing.");
|
|
1870
|
+
const previousUnit = snapshot(context.paths.definition);
|
|
1871
|
+
const previousEnvironment = snapshot(context.paths.environment);
|
|
1872
|
+
try {
|
|
1873
|
+
writeManagedAtomically(context.paths.environment, renderSystemdEnvironment(context.paths, context.env), 384);
|
|
1874
|
+
writeManagedAtomically(context.paths.definition, renderSystemdUnit(context.paths, context.home), 384);
|
|
1875
|
+
requireSuccess(context, "systemctl", ["--user", "daemon-reload"]);
|
|
1876
|
+
requireSuccess(context, "systemctl", ["--user", "enable", "--now", SYSTEMD_UNIT]);
|
|
1877
|
+
} catch (error) {
|
|
1878
|
+
restore(context.paths.environment, previousEnvironment);
|
|
1879
|
+
restore(context.paths.definition, previousUnit);
|
|
1880
|
+
run(context, "systemctl", ["--user", "daemon-reload"]);
|
|
1881
|
+
if (previousUnit !== null) run(context, "systemctl", ["--user", "enable", "--now", SYSTEMD_UNIT]);
|
|
1882
|
+
throw error;
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
function resolveContext(context) {
|
|
1886
|
+
const env = context.env ?? process.env;
|
|
1887
|
+
const platform = supportedPlatform(context.platform ?? process.platform);
|
|
1888
|
+
const home = resolve3(context.home ?? homedir3());
|
|
1889
|
+
const uid = context.uid ?? process.getuid?.();
|
|
1890
|
+
if (!Number.isSafeInteger(uid) || uid < 0) throw new Error("Could not determine the current user id for the service manager.");
|
|
1891
|
+
return {
|
|
1892
|
+
env,
|
|
1893
|
+
platform,
|
|
1894
|
+
home,
|
|
1895
|
+
uid,
|
|
1896
|
+
runner: context.runner ?? defaultRunner,
|
|
1897
|
+
paths: servicePaths({ env, platform, home })
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1900
|
+
function supportedPlatform(platform) {
|
|
1901
|
+
if (platform !== "darwin" && platform !== "linux") {
|
|
1902
|
+
throw new Error(`Background services are supported on macOS and systemd Linux, not ${platform}. Use \`longleash run\` instead.`);
|
|
1903
|
+
}
|
|
1904
|
+
return platform;
|
|
1905
|
+
}
|
|
1906
|
+
function defaultRunner(file, args, options = { encoding: "utf8" }) {
|
|
1907
|
+
const result = spawnSync2(file, args, { ...options, encoding: "utf8" });
|
|
1908
|
+
return {
|
|
1909
|
+
status: result.status ?? (result.error ? 1 : 0),
|
|
1910
|
+
stdout: result.stdout ?? "",
|
|
1911
|
+
stderr: result.stderr ?? (result.error?.message ?? "")
|
|
1912
|
+
};
|
|
1913
|
+
}
|
|
1914
|
+
function run(context, file, args) {
|
|
1915
|
+
return context.runner(file, args, { encoding: "utf8", env: context.env });
|
|
1916
|
+
}
|
|
1917
|
+
function requireSuccess(context, file, args) {
|
|
1918
|
+
const result = run(context, file, args);
|
|
1919
|
+
if (result.status !== 0) throw commandError(file, args, result);
|
|
1920
|
+
return result;
|
|
1921
|
+
}
|
|
1922
|
+
function commandError(file, args, result) {
|
|
1923
|
+
const detail = (result.stderr || result.stdout).trim().replace(/\s+/g, " ").slice(0, 400);
|
|
1924
|
+
return new Error(`${file} ${args.join(" ")} failed${detail ? `: ${detail}` : "."}`);
|
|
1925
|
+
}
|
|
1926
|
+
function passthrough(context, file, args) {
|
|
1927
|
+
const result = spawnSync2(file, args, { stdio: "inherit", env: context.env });
|
|
1928
|
+
return result.status ?? 1;
|
|
1929
|
+
}
|
|
1930
|
+
function launchDomain(context) {
|
|
1931
|
+
return `gui/${context.uid}`;
|
|
1932
|
+
}
|
|
1933
|
+
function serviceTarget(context) {
|
|
1934
|
+
return `${launchDomain(context)}/${SERVICE_LABEL}`;
|
|
1935
|
+
}
|
|
1936
|
+
function launchdLoaded(context) {
|
|
1937
|
+
return run(context, "/bin/launchctl", ["print", serviceTarget(context)]).status === 0;
|
|
1938
|
+
}
|
|
1939
|
+
function lingerEnabled(context) {
|
|
1940
|
+
const result = run(context, "loginctl", ["show-user", String(context.uid), "--property=Linger", "--value"]);
|
|
1941
|
+
return result.status === 0 && result.stdout.trim().toLowerCase() === "yes";
|
|
1942
|
+
}
|
|
1943
|
+
function assertManagedWrapper(path) {
|
|
1944
|
+
if (!existsSync2(path)) throw new Error(`Managed LongLeash executable is missing: ${path}. Run \`longleash setup\` first.`);
|
|
1945
|
+
if (lstatSync3(path).isSymbolicLink()) throw new Error(`Refusing symlinked LongLeash executable: ${path}`);
|
|
1946
|
+
if (!readFileSync3(path, "utf8").includes(MANAGED_MARKER)) throw new Error(`Refusing unmanaged LongLeash executable: ${path}`);
|
|
1947
|
+
}
|
|
1948
|
+
function assertManagedDefinition(path) {
|
|
1949
|
+
if (!managedFileExists(path)) throw new Error(`LongLeash background service is not installed: ${path}`);
|
|
1950
|
+
if (!readFileSync3(path, "utf8").includes(MANAGED_MARKER)) throw new Error(`Refusing unmanaged service definition: ${path}`);
|
|
1951
|
+
}
|
|
1952
|
+
function assertServiceInstallation(context) {
|
|
1953
|
+
assertManagedDefinition(context.paths.definition);
|
|
1954
|
+
if (context.paths.environment) assertManagedDefinition(context.paths.environment);
|
|
1955
|
+
assertManagedWrapper(context.paths.wrapper);
|
|
1956
|
+
}
|
|
1957
|
+
function managedDefinitionExists(path) {
|
|
1958
|
+
if (!managedFileExists(path)) return false;
|
|
1959
|
+
assertManagedDefinition(path);
|
|
1960
|
+
return true;
|
|
1961
|
+
}
|
|
1962
|
+
function managedFileExists(path) {
|
|
1963
|
+
if (!existsSync2(path)) return false;
|
|
1964
|
+
if (lstatSync3(path).isSymbolicLink()) throw new Error(`Refusing symlinked service path: ${path}`);
|
|
1965
|
+
return true;
|
|
1966
|
+
}
|
|
1967
|
+
function snapshot(path) {
|
|
1968
|
+
if (!managedFileExists(path)) return null;
|
|
1969
|
+
assertManagedDefinition(path);
|
|
1970
|
+
return { content: readFileSync3(path, "utf8"), mode: lstatSync3(path).mode & 511 };
|
|
1971
|
+
}
|
|
1972
|
+
function restore(path, previous) {
|
|
1973
|
+
if (previous === null) rmSync3(path, { force: true });
|
|
1974
|
+
else writeManagedAtomically(path, previous.content, previous.mode);
|
|
1975
|
+
}
|
|
1976
|
+
function writeManagedAtomically(path, content, mode, validate) {
|
|
1977
|
+
if (!content.includes(MANAGED_MARKER)) throw new Error("Refusing to write an unmarked service definition.");
|
|
1978
|
+
if (managedFileExists(path)) assertManagedDefinition(path);
|
|
1979
|
+
mkdirSync3(dirname3(path), { recursive: true, mode: 448 });
|
|
1980
|
+
const temporary = `${path}.${process.pid}.${randomUUID3()}.tmp`;
|
|
1981
|
+
try {
|
|
1982
|
+
writeFileSync3(temporary, content, { encoding: "utf8", mode, flag: "wx" });
|
|
1983
|
+
chmodSync2(temporary, mode);
|
|
1984
|
+
validate?.(temporary);
|
|
1985
|
+
renameSync3(temporary, path);
|
|
1986
|
+
} catch (error) {
|
|
1987
|
+
rmSync3(temporary, { force: true });
|
|
1988
|
+
throw error;
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
function requiredEnvironment(env, name, fallback) {
|
|
1992
|
+
const value = env[name] || fallback;
|
|
1993
|
+
if (/[\0\r\n]/.test(value)) throw new Error(`Unsafe ${name} value for background service.`);
|
|
1994
|
+
return value;
|
|
1995
|
+
}
|
|
1996
|
+
function xml(value) {
|
|
1997
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1998
|
+
}
|
|
1999
|
+
function systemdQuote(value) {
|
|
2000
|
+
if (/[\0\r\n]/.test(value)) throw new Error("Service paths may not contain control characters.");
|
|
2001
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/%/g, "%%")}"`;
|
|
2002
|
+
}
|
|
2003
|
+
function environmentQuote(value) {
|
|
2004
|
+
if (/[\0\r\n]/.test(value)) throw new Error("Service environment values may not contain control characters.");
|
|
2005
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
// src/terminal-qr.ts
|
|
2009
|
+
var import_qrcode_terminal = __toESM(require_main(), 1);
|
|
2010
|
+
function terminalQr(input2) {
|
|
2011
|
+
const source = qrModules(input2);
|
|
2012
|
+
const quiet = 4;
|
|
2013
|
+
const whiteRow = Array(source.length + quiet * 2).fill(false);
|
|
2014
|
+
const padded = [
|
|
2015
|
+
...Array.from({ length: quiet }, () => [...whiteRow]),
|
|
2016
|
+
...source.map((row) => [
|
|
2017
|
+
...Array(quiet).fill(false),
|
|
2018
|
+
...row,
|
|
2019
|
+
...Array(quiet).fill(false)
|
|
2020
|
+
]),
|
|
2021
|
+
...Array.from({ length: quiet }, () => [...whiteRow])
|
|
2022
|
+
];
|
|
2023
|
+
if (padded.length % 2 !== 0) padded.push([...whiteRow]);
|
|
2024
|
+
const output2 = [];
|
|
2025
|
+
for (let row = 0; row < padded.length; row += 2) {
|
|
2026
|
+
const top = padded[row];
|
|
2027
|
+
const bottom = padded[row + 1];
|
|
2028
|
+
if (!top || !bottom) throw new Error("QR row pairing failed");
|
|
2029
|
+
let line = "";
|
|
2030
|
+
let lastStyle = "";
|
|
2031
|
+
for (let col = 0; col < top.length; col += 1) {
|
|
2032
|
+
const rendered = cell(top[col] ?? false, bottom[col] ?? false);
|
|
2033
|
+
if (rendered.style !== lastStyle) {
|
|
2034
|
+
line += rendered.style;
|
|
2035
|
+
lastStyle = rendered.style;
|
|
2036
|
+
}
|
|
2037
|
+
line += rendered.glyph;
|
|
2038
|
+
}
|
|
2039
|
+
output2.push(`${line}\x1B[0m`);
|
|
2040
|
+
}
|
|
2041
|
+
return output2.join("\n");
|
|
2042
|
+
}
|
|
2043
|
+
function qrModules(input2) {
|
|
2044
|
+
let compact = "";
|
|
2045
|
+
import_qrcode_terminal.default.generate(input2, { small: true }, (value) => {
|
|
2046
|
+
compact = value;
|
|
2047
|
+
});
|
|
2048
|
+
const lines = compact.replace(/\n$/, "").split("\n");
|
|
2049
|
+
if (lines.length < 2) throw new Error("QR renderer returned no module rows");
|
|
2050
|
+
const moduleCount = [...lines[1] ?? ""].length - 2;
|
|
2051
|
+
if (moduleCount < 21) throw new Error("QR renderer returned an invalid module grid");
|
|
2052
|
+
const modules = [];
|
|
2053
|
+
for (const line of lines.slice(1)) {
|
|
2054
|
+
const cells = [...line].slice(1, moduleCount + 1);
|
|
2055
|
+
if (cells.length !== moduleCount) throw new Error("QR renderer returned a ragged module grid");
|
|
2056
|
+
const top = [];
|
|
2057
|
+
const bottom = [];
|
|
2058
|
+
for (const value of cells) {
|
|
2059
|
+
if (value === "\u2588") {
|
|
2060
|
+
top.push(false);
|
|
2061
|
+
bottom.push(false);
|
|
2062
|
+
} else if (value === "\u2580") {
|
|
2063
|
+
top.push(false);
|
|
2064
|
+
bottom.push(true);
|
|
2065
|
+
} else if (value === "\u2584") {
|
|
2066
|
+
top.push(true);
|
|
2067
|
+
bottom.push(false);
|
|
2068
|
+
} else if (value === " ") {
|
|
2069
|
+
top.push(true);
|
|
2070
|
+
bottom.push(true);
|
|
2071
|
+
} else throw new Error(`QR renderer returned an unknown cell ${JSON.stringify(value)}`);
|
|
2072
|
+
}
|
|
2073
|
+
modules.push(top, bottom);
|
|
2074
|
+
}
|
|
2075
|
+
return modules.slice(0, moduleCount);
|
|
2076
|
+
}
|
|
2077
|
+
function cell(top, bottom) {
|
|
2078
|
+
const black = "0;0;0";
|
|
2079
|
+
const white = "255;255;255";
|
|
2080
|
+
if (top === bottom) {
|
|
2081
|
+
const colour = top ? black : white;
|
|
2082
|
+
return { style: `\x1B[38;2;${colour};48;2;${colour}m`, glyph: "\u2588" };
|
|
2083
|
+
}
|
|
2084
|
+
return {
|
|
2085
|
+
// Black remains the continuous cell background, avoiding font seams through finder patterns.
|
|
2086
|
+
style: `\x1B[38;2;${white};48;2;${black}m`,
|
|
2087
|
+
glyph: top ? "\u2584" : "\u2580"
|
|
2088
|
+
};
|
|
2089
|
+
}
|
|
2090
|
+
|
|
519
2091
|
// src/cli.ts
|
|
520
|
-
var here =
|
|
521
|
-
var packageRoot =
|
|
522
|
-
var manifest = JSON.parse(
|
|
2092
|
+
var here = dirname4(fileURLToPath(import.meta.url));
|
|
2093
|
+
var packageRoot = resolve4(here, "..");
|
|
2094
|
+
var manifest = JSON.parse(readFileSync4(join4(packageRoot, "package.json"), "utf8"));
|
|
523
2095
|
var VERSION = manifest.version;
|
|
524
|
-
var runtime =
|
|
525
|
-
var daemonEntry =
|
|
526
|
-
var hooks =
|
|
527
|
-
var devicesEntry =
|
|
2096
|
+
var runtime = join4(packageRoot, "runtime", "daemon");
|
|
2097
|
+
var daemonEntry = join4(runtime, "bin", "longleashd.mjs");
|
|
2098
|
+
var hooks = join4(runtime, "hooks");
|
|
2099
|
+
var devicesEntry = join4(runtime, "bin", "longleash-devices.mjs");
|
|
528
2100
|
async function main() {
|
|
529
2101
|
const args = process.argv.slice(2);
|
|
530
2102
|
const command = args[0];
|
|
@@ -541,6 +2113,8 @@ async function main() {
|
|
|
541
2113
|
return 0;
|
|
542
2114
|
}
|
|
543
2115
|
if (command === "setup") return setup(parseSetup(args.slice(1)));
|
|
2116
|
+
if (command === "service") return serviceCommand(args.slice(1));
|
|
2117
|
+
if (command === "pair") return pair();
|
|
544
2118
|
if (command === "doctor") return doctor(args.includes("--json"));
|
|
545
2119
|
if (command === "hooks") return runHooks(args.slice(1));
|
|
546
2120
|
if (command === "devices") return runNode(devicesEntry, []);
|
|
@@ -561,6 +2135,13 @@ function help() {
|
|
|
561
2135
|
|
|
562
2136
|
Usage:
|
|
563
2137
|
longleash setup configure a stable user-local installation
|
|
2138
|
+
longleash service status show manager and authenticated daemon health
|
|
2139
|
+
longleash service start start the per-user background service
|
|
2140
|
+
longleash service stop stop it without removing settings or devices
|
|
2141
|
+
longleash service restart restart it after a configuration change
|
|
2142
|
+
longleash service logs [-f] show redacted persistent service logs
|
|
2143
|
+
longleash service uninstall remove only the background service
|
|
2144
|
+
longleash pair print a fresh pairing QR from the running service
|
|
564
2145
|
longleash run [folders...] run in the foreground (terminal stays open)
|
|
565
2146
|
longleash [folders...] shorthand for run
|
|
566
2147
|
longleash doctor [--json] report package, config, and daemon health
|
|
@@ -569,12 +2150,18 @@ Usage:
|
|
|
569
2150
|
longleash revoke <id|--all> revoke paired phone access
|
|
570
2151
|
longleash update [version] atomically install latest or an exact version
|
|
571
2152
|
longleash uninstall remove runtime and hooks; preserve user data
|
|
572
|
-
longleash where print the active npm package directory
|
|
573
|
-
|
|
574
|
-
Setup never starts the daemon. Background service commands arrive in Workstream C.`);
|
|
2153
|
+
longleash where print the active npm package directory`);
|
|
575
2154
|
}
|
|
576
2155
|
function parseSetup(args) {
|
|
577
|
-
const options = {
|
|
2156
|
+
const options = {
|
|
2157
|
+
roots: [],
|
|
2158
|
+
relay: "",
|
|
2159
|
+
yes: false,
|
|
2160
|
+
reuse: false,
|
|
2161
|
+
configureOnly: false,
|
|
2162
|
+
skipHooks: false,
|
|
2163
|
+
service: "default"
|
|
2164
|
+
};
|
|
578
2165
|
for (let i = 0; i < args.length; i += 1) {
|
|
579
2166
|
const arg = args[i];
|
|
580
2167
|
if (arg === "--root") {
|
|
@@ -589,6 +2176,8 @@ function parseSetup(args) {
|
|
|
589
2176
|
else if (arg === "--reuse-config") options.reuse = true;
|
|
590
2177
|
else if (arg === "--configure-only") options.configureOnly = true;
|
|
591
2178
|
else if (arg === "--skip-hooks") options.skipHooks = true;
|
|
2179
|
+
else if (arg === "--service") options.service = "install";
|
|
2180
|
+
else if (arg === "--no-service") options.service = "skip";
|
|
592
2181
|
else throw new Error(`Unknown setup option: ${arg}`);
|
|
593
2182
|
}
|
|
594
2183
|
return options;
|
|
@@ -608,6 +2197,11 @@ async function setup(options) {
|
|
|
608
2197
|
options.relay = typeof existing.relayUrl === "string" ? existing.relayUrl : "off";
|
|
609
2198
|
options.yes = true;
|
|
610
2199
|
}
|
|
2200
|
+
let existingService = false;
|
|
2201
|
+
try {
|
|
2202
|
+
existingService = serviceState().installed;
|
|
2203
|
+
} catch {
|
|
2204
|
+
}
|
|
611
2205
|
if (options.roots.length === 0 && options.yes) {
|
|
612
2206
|
throw new Error("Non-interactive setup requires at least one explicit --root, or --reuse-config.");
|
|
613
2207
|
}
|
|
@@ -624,12 +2218,14 @@ async function setup(options) {
|
|
|
624
2218
|
console.log("\nConnectivity: hosted works away from home; LAN-only has no internet relay.");
|
|
625
2219
|
const relayAnswer = await prompt.question("Relay [hosted / lan / wss://your-relay/ws] (hosted): ");
|
|
626
2220
|
options.relay = relayAnswer.trim() || "hosted";
|
|
2221
|
+
const serviceAnswer = await prompt.question("Keep LongLeash available after this terminal closes? [Y/n] ");
|
|
2222
|
+
options.service = /^n(?:o)?$/i.test(serviceAnswer.trim()) ? "skip" : "install";
|
|
627
2223
|
const roots2 = normalizeRoots(options.roots);
|
|
628
2224
|
const relay2 = normalizeRelay(options.relay);
|
|
629
2225
|
console.log("\nReview before anything changes:");
|
|
630
2226
|
for (const root of roots2) console.log(` allowed root ${root}`);
|
|
631
2227
|
console.log(` connectivity ${relay2 ?? "LAN-only (no relay)"}`);
|
|
632
|
-
console.log(
|
|
2228
|
+
console.log(` service ${options.service === "install" ? "per-user background service at login" : "foreground only"}`);
|
|
633
2229
|
const accepted = await prompt.question("\nApply this setup? [y/N] ");
|
|
634
2230
|
if (!/^y(?:es)?$/i.test(accepted.trim())) {
|
|
635
2231
|
console.log("Nothing changed.");
|
|
@@ -653,7 +2249,7 @@ async function setup(options) {
|
|
|
653
2249
|
relay ?? "off",
|
|
654
2250
|
"--skip-hooks"
|
|
655
2251
|
];
|
|
656
|
-
const configured =
|
|
2252
|
+
const configured = spawnSync3(process.execPath, [prepared.cli, ...forwarded], {
|
|
657
2253
|
stdio: "inherit",
|
|
658
2254
|
env: { ...process.env, LONGLEASH_INTERNAL_CONFIGURE: VERSION }
|
|
659
2255
|
});
|
|
@@ -672,7 +2268,7 @@ async function setup(options) {
|
|
|
672
2268
|
console.log(`
|
|
673
2269
|
Activated @longleash/cli ${VERSION}.`);
|
|
674
2270
|
if (!options.skipHooks) {
|
|
675
|
-
const hooked =
|
|
2271
|
+
const hooked = spawnSync3(process.execPath, [prepared.cli, "hooks"], { stdio: "inherit", env: process.env });
|
|
676
2272
|
if (hooked.error || hooked.status !== 0) {
|
|
677
2273
|
console.error("Provider hook setup needs attention. The runtime is installed; run `longleash hooks` after fixing the message above.");
|
|
678
2274
|
}
|
|
@@ -687,6 +2283,22 @@ The executable is installed at ${paths.wrapper}, but ${paths.bin} is not on PATH
|
|
|
687
2283
|
console.log(` export PATH=${quoteForShell(paths.bin)}:"$PATH"`);
|
|
688
2284
|
console.log(`You can use ${paths.wrapper} immediately.`);
|
|
689
2285
|
}
|
|
2286
|
+
const manageService = options.service === "install" || options.service === "default" && (options.reuse ? existingService : true);
|
|
2287
|
+
if (manageService) {
|
|
2288
|
+
try {
|
|
2289
|
+
const state = installService();
|
|
2290
|
+
const healthy = await waitForDaemon(15e3);
|
|
2291
|
+
if (!healthy) {
|
|
2292
|
+
throw new Error("The service manager started LongLeash, but its authenticated health check did not become ready. Run `longleash service logs`.");
|
|
2293
|
+
}
|
|
2294
|
+
console.log(`Background service installed and running (${state.platform}).`);
|
|
2295
|
+
console.log("Run `longleash pair` for a fresh QR; pairing secrets are not stored in service logs.");
|
|
2296
|
+
} catch (error) {
|
|
2297
|
+
throw new Error(`The verified runtime is installed, but the background service could not be activated: ${message(error)} You can use \`longleash run\` while diagnosing it.`);
|
|
2298
|
+
}
|
|
2299
|
+
} else {
|
|
2300
|
+
console.log("Background service was not installed. Run `longleash run` for foreground use or `longleash service install` later.");
|
|
2301
|
+
}
|
|
690
2302
|
return 0;
|
|
691
2303
|
}
|
|
692
2304
|
const next = { ...existing, cliSchemaVersion: 1, allowedRoots: roots };
|
|
@@ -694,17 +2306,98 @@ The executable is installed at ${paths.wrapper}, but ${paths.bin} is not on PATH
|
|
|
694
2306
|
else next.relayUrl = relay;
|
|
695
2307
|
saveConfig(next);
|
|
696
2308
|
console.log(`Saved configuration to ${configPath()}`);
|
|
697
|
-
console.log("
|
|
2309
|
+
console.log("Configuration saved. The outer setup transaction decides whether to start the service.");
|
|
2310
|
+
return 0;
|
|
2311
|
+
}
|
|
2312
|
+
async function serviceCommand(args) {
|
|
2313
|
+
const command = args[0] ?? "status";
|
|
2314
|
+
if (command === "install") {
|
|
2315
|
+
const state = installService();
|
|
2316
|
+
if (!await waitForDaemon(15e3)) throw new Error("The service was installed but did not become healthy. Run `longleash service logs`.");
|
|
2317
|
+
printServiceState(state, true);
|
|
2318
|
+
return 0;
|
|
2319
|
+
}
|
|
2320
|
+
if (command === "start") {
|
|
2321
|
+
const state = startService();
|
|
2322
|
+
if (!await waitForDaemon(15e3)) throw new Error("The service manager started the job but the daemon did not become healthy. Run `longleash service logs`.");
|
|
2323
|
+
printServiceState(state, true);
|
|
2324
|
+
return 0;
|
|
2325
|
+
}
|
|
2326
|
+
if (command === "stop") {
|
|
2327
|
+
const state = stopService();
|
|
2328
|
+
printServiceState(state, false);
|
|
2329
|
+
return 0;
|
|
2330
|
+
}
|
|
2331
|
+
if (command === "restart") {
|
|
2332
|
+
const state = restartService();
|
|
2333
|
+
if (!await waitForDaemon(15e3)) throw new Error("The service restarted but the daemon did not become healthy. Run `longleash service logs`.");
|
|
2334
|
+
printServiceState(state, true);
|
|
2335
|
+
return 0;
|
|
2336
|
+
}
|
|
2337
|
+
if (command === "uninstall") {
|
|
2338
|
+
uninstallService();
|
|
2339
|
+
console.log(`Removed the per-user background service. Settings, devices, audit data, and runtime remain in ${configPath()}.`);
|
|
2340
|
+
return 0;
|
|
2341
|
+
}
|
|
2342
|
+
if (command === "logs") return showServiceLogs(args.includes("--follow") || args.includes("-f"));
|
|
2343
|
+
if (command === "status") {
|
|
2344
|
+
const state = serviceState();
|
|
2345
|
+
const healthy = await daemonHealth();
|
|
2346
|
+
if (args.includes("--json")) console.log(JSON.stringify({ ...state, healthy }, null, 2));
|
|
2347
|
+
else printServiceState(state, healthy);
|
|
2348
|
+
return state.installed && healthy ? 0 : 1;
|
|
2349
|
+
}
|
|
2350
|
+
throw new Error(`Unknown service command: ${command}`);
|
|
2351
|
+
}
|
|
2352
|
+
function printServiceState(state, healthy) {
|
|
2353
|
+
console.log("");
|
|
2354
|
+
console.log(` service ${state.installed ? "installed" : "not installed"} (${state.platform})`);
|
|
2355
|
+
console.log(` manager ${state.loaded ? "loaded" : "not loaded"}${state.active ? " \xB7 active" : ""}`);
|
|
2356
|
+
console.log(` daemon ${healthy ? "authenticated health check passed" : "not reachable"}`);
|
|
2357
|
+
console.log(` definition ${state.definition}`);
|
|
2358
|
+
console.log(` logs ${state.logs}`);
|
|
2359
|
+
if (state.platform === "linux" && state.loginOnly) {
|
|
2360
|
+
console.log(" login scope stops after logout; optional lingering is not enabled by LongLeash");
|
|
2361
|
+
}
|
|
2362
|
+
console.log("");
|
|
2363
|
+
}
|
|
2364
|
+
async function pair() {
|
|
2365
|
+
const response = await localDaemonRequest("/local/pairing", { method: "POST" });
|
|
2366
|
+
if (!response.ok) throw new Error(`The running daemon could not create a pairing challenge (${response.status}).`);
|
|
2367
|
+
const body = await response.json();
|
|
2368
|
+
if (typeof body.url !== "string" || !/^https?:\/\//.test(body.url)) throw new Error("The daemon returned an invalid pairing challenge.");
|
|
2369
|
+
console.log("\nScan this with your phone. The link is single-use and expires:\n");
|
|
2370
|
+
console.log(terminalQr(body.url));
|
|
2371
|
+
console.log(`
|
|
2372
|
+
${body.url}
|
|
2373
|
+
`);
|
|
698
2374
|
return 0;
|
|
699
2375
|
}
|
|
700
2376
|
async function runDaemon(explicitRoots) {
|
|
701
|
-
if (!
|
|
2377
|
+
if (!existsSync3(daemonEntry)) throw new Error("The npm package is incomplete: daemon runtime is missing.");
|
|
702
2378
|
const config = loadConfig();
|
|
703
2379
|
const roots = normalizeRoots(explicitRoots.length > 0 ? explicitRoots : configuredRoots(config));
|
|
704
2380
|
const child = spawn(process.execPath, [daemonEntry, ...roots], { stdio: "inherit", env: process.env });
|
|
705
2381
|
return await new Promise((resolveExit, reject) => {
|
|
706
|
-
|
|
707
|
-
|
|
2382
|
+
const forward = (signal) => {
|
|
2383
|
+
if (child.exitCode === null && child.signalCode === null) child.kill(signal);
|
|
2384
|
+
};
|
|
2385
|
+
const interrupt = () => forward("SIGINT");
|
|
2386
|
+
const terminate = () => forward("SIGTERM");
|
|
2387
|
+
const cleanup = () => {
|
|
2388
|
+
process.off("SIGINT", interrupt);
|
|
2389
|
+
process.off("SIGTERM", terminate);
|
|
2390
|
+
};
|
|
2391
|
+
process.on("SIGINT", interrupt);
|
|
2392
|
+
process.on("SIGTERM", terminate);
|
|
2393
|
+
child.once("error", (error) => {
|
|
2394
|
+
cleanup();
|
|
2395
|
+
reject(error);
|
|
2396
|
+
});
|
|
2397
|
+
child.once("exit", (code, signal) => {
|
|
2398
|
+
cleanup();
|
|
2399
|
+
resolveExit(code ?? (signal ? 1 : 0));
|
|
2400
|
+
});
|
|
708
2401
|
});
|
|
709
2402
|
}
|
|
710
2403
|
async function doctor(json) {
|
|
@@ -715,10 +2408,10 @@ async function doctor(json) {
|
|
|
715
2408
|
} catch (error) {
|
|
716
2409
|
configError = message(error);
|
|
717
2410
|
}
|
|
718
|
-
const endpointPath =
|
|
2411
|
+
const endpointPath = join4(process.env.LONGLEASH_DATA ?? join4(homedir4(), ".longleash"), "hook-endpoint.json");
|
|
719
2412
|
let daemon = { reachable: false };
|
|
720
2413
|
try {
|
|
721
|
-
const endpoint = JSON.parse(
|
|
2414
|
+
const endpoint = JSON.parse(readFileSync4(endpointPath, "utf8"));
|
|
722
2415
|
if (endpoint.url && endpoint.secret) {
|
|
723
2416
|
const response = await fetch(endpoint.url.replace(/\/hook$/, "/health"), {
|
|
724
2417
|
headers: { "x-longleash-hook": endpoint.secret },
|
|
@@ -759,8 +2452,8 @@ LongLeash ${VERSION}`);
|
|
|
759
2452
|
async function runHooks(args) {
|
|
760
2453
|
const remove = args.includes("--remove");
|
|
761
2454
|
let failed = false;
|
|
762
|
-
if (commandAvailable("claude") || remove) failed = await runNode(
|
|
763
|
-
if (commandAvailable("codex") || remove) failed = await runNode(
|
|
2455
|
+
if (commandAvailable("claude") || remove) failed = await runNode(join4(hooks, "install-hooks.mjs"), remove ? ["--remove"] : []) !== 0 || failed;
|
|
2456
|
+
if (commandAvailable("codex") || remove) failed = await runNode(join4(hooks, "install-codex-hooks.mjs"), remove ? ["--remove"] : []) !== 0 || failed;
|
|
764
2457
|
return failed ? 1 : 0;
|
|
765
2458
|
}
|
|
766
2459
|
async function update(target) {
|
|
@@ -785,6 +2478,11 @@ async function update(target) {
|
|
|
785
2478
|
});
|
|
786
2479
|
}
|
|
787
2480
|
async function uninstall() {
|
|
2481
|
+
try {
|
|
2482
|
+
if (serviceState().installed) uninstallService();
|
|
2483
|
+
} catch (error) {
|
|
2484
|
+
throw new Error(`The background service could not be removed safely, so the runtime was preserved: ${message(error)}`);
|
|
2485
|
+
}
|
|
788
2486
|
const hooksRemoved = await runHooks(["--remove"]);
|
|
789
2487
|
if (hooksRemoved !== 0) throw new Error("Provider hooks could not be removed safely. The managed runtime was preserved.");
|
|
790
2488
|
const result = uninstallManagedRuntime();
|
|
@@ -792,11 +2490,56 @@ async function uninstall() {
|
|
|
792
2490
|
console.log(`Preserved settings, paired devices, and audit data in ${result.configPreserved}.`);
|
|
793
2491
|
return 0;
|
|
794
2492
|
}
|
|
2493
|
+
async function daemonHealth() {
|
|
2494
|
+
try {
|
|
2495
|
+
const response = await localDaemonRequest("/health", { method: "GET" }, 1500);
|
|
2496
|
+
if (!response.ok) return false;
|
|
2497
|
+
const body = await response.json();
|
|
2498
|
+
return body.name === "longleash";
|
|
2499
|
+
} catch {
|
|
2500
|
+
return false;
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
async function waitForDaemon(timeoutMs) {
|
|
2504
|
+
const deadline = Date.now() + timeoutMs;
|
|
2505
|
+
while (Date.now() < deadline) {
|
|
2506
|
+
if (await daemonHealth()) return true;
|
|
2507
|
+
await new Promise((resolveWait) => setTimeout(resolveWait, 200));
|
|
2508
|
+
}
|
|
2509
|
+
return false;
|
|
2510
|
+
}
|
|
2511
|
+
async function localDaemonRequest(path, init, timeoutMs = 5e3) {
|
|
2512
|
+
const endpointPath = join4(process.env.LONGLEASH_DATA ?? join4(homedir4(), ".longleash"), "hook-endpoint.json");
|
|
2513
|
+
let endpoint;
|
|
2514
|
+
try {
|
|
2515
|
+
endpoint = JSON.parse(readFileSync4(endpointPath, "utf8"));
|
|
2516
|
+
} catch {
|
|
2517
|
+
throw new Error("LongLeash is not reachable. Start it with `longleash service start` or `longleash run`.");
|
|
2518
|
+
}
|
|
2519
|
+
if (typeof endpoint.url !== "string" || typeof endpoint.secret !== "string" || endpoint.secret === "") {
|
|
2520
|
+
throw new Error(`Invalid local daemon endpoint: ${endpointPath}`);
|
|
2521
|
+
}
|
|
2522
|
+
const url = new URL(endpoint.url);
|
|
2523
|
+
if (url.protocol !== "http:" || url.pathname !== "/hook" || !localAddress(url.hostname)) {
|
|
2524
|
+
throw new Error(`Refusing a non-local daemon endpoint in ${endpointPath}`);
|
|
2525
|
+
}
|
|
2526
|
+
return fetch(`${url.origin}${path}`, {
|
|
2527
|
+
...init,
|
|
2528
|
+
headers: { ...init.headers, "x-longleash-hook": endpoint.secret },
|
|
2529
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
2530
|
+
});
|
|
2531
|
+
}
|
|
2532
|
+
function localAddress(hostname) {
|
|
2533
|
+
if (hostname === "localhost" || hostname === "::1") return true;
|
|
2534
|
+
if (/^127\./.test(hostname) || /^10\./.test(hostname) || /^192\.168\./.test(hostname)) return true;
|
|
2535
|
+
const match = hostname.match(/^172\.(\d+)\./);
|
|
2536
|
+
return match !== null && Number(match[1]) >= 16 && Number(match[1]) <= 31;
|
|
2537
|
+
}
|
|
795
2538
|
function commandAvailable(command) {
|
|
796
|
-
return
|
|
2539
|
+
return spawnSync3(command, ["--version"], { stdio: "ignore", timeout: 3e3 }).status === 0;
|
|
797
2540
|
}
|
|
798
2541
|
function pathDirectories() {
|
|
799
|
-
return (process.env.PATH ?? "").split(delimiter).filter(Boolean).map((path) =>
|
|
2542
|
+
return (process.env.PATH ?? "").split(delimiter).filter(Boolean).map((path) => resolve4(path));
|
|
800
2543
|
}
|
|
801
2544
|
function quoteForShell(value) {
|
|
802
2545
|
return `'${value.replace(/'/g, `'"'"'`)}'`;
|