@bobfrankston/lxlan 0.1.8 → 0.1.9
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/.hintrc +20 -0
- package/README.md +159 -0
- package/client.d.ts +0 -3
- package/client.js +19 -4
- package/device.d.ts +16 -0
- package/device.js +44 -3
- package/index.d.ts +1 -1
- package/package.json +10 -5
- package/protocol.d.ts +23 -21
- package/protocol.js +118 -62
- package/release-all.ps1 +168 -168
- package/transport.d.ts +4 -27
- package/transport.js +2 -5
- package/types.d.ts +23 -6
- package/.gitattributes +0 -5
- package/client.d.ts.map +0 -1
- package/client.js.map +0 -1
- package/device.d.ts.map +0 -1
- package/device.js.map +0 -1
- package/events.d.ts.map +0 -1
- package/events.js.map +0 -1
- package/index.d.ts.map +0 -1
- package/index.js.map +0 -1
- package/protocol.d.ts.map +0 -1
- package/protocol.js.map +0 -1
- package/transport.d.ts.map +0 -1
- package/transport.js.map +0 -1
- package/types.d.ts.map +0 -1
- package/types.js.map +0 -1
package/protocol.js
CHANGED
|
@@ -10,9 +10,9 @@ export function nextSequence() {
|
|
|
10
10
|
export function getSource() {
|
|
11
11
|
return globalSource;
|
|
12
12
|
}
|
|
13
|
-
/** MAC string to 8-byte
|
|
13
|
+
/** MAC string to 8-byte Uint8Array (6 bytes MAC + 2 padding) */
|
|
14
14
|
function macToBuffer(mac) {
|
|
15
|
-
const buf =
|
|
15
|
+
const buf = new Uint8Array(8);
|
|
16
16
|
if (mac && mac !== '00:00:00:00:00:00') {
|
|
17
17
|
const bytes = mac.split(':').map(b => parseInt(b, 16));
|
|
18
18
|
for (let i = 0; i < 6; i++)
|
|
@@ -20,7 +20,7 @@ function macToBuffer(mac) {
|
|
|
20
20
|
}
|
|
21
21
|
return buf;
|
|
22
22
|
}
|
|
23
|
-
/**
|
|
23
|
+
/** Uint8Array to MAC string */
|
|
24
24
|
function bufferToMac(buf, offset = 0) {
|
|
25
25
|
const parts = [];
|
|
26
26
|
for (let i = 0; i < 6; i++) {
|
|
@@ -28,51 +28,90 @@ function bufferToMac(buf, offset = 0) {
|
|
|
28
28
|
}
|
|
29
29
|
return parts.join(':');
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
// Helper for writing values to Uint8Array
|
|
32
|
+
function writeUInt16LE(buf, value, offset) {
|
|
33
|
+
buf[offset] = value & 0xFF;
|
|
34
|
+
buf[offset + 1] = (value >> 8) & 0xFF;
|
|
35
|
+
}
|
|
36
|
+
function writeUInt32LE(buf, value, offset) {
|
|
37
|
+
buf[offset] = value & 0xFF;
|
|
38
|
+
buf[offset + 1] = (value >> 8) & 0xFF;
|
|
39
|
+
buf[offset + 2] = (value >> 16) & 0xFF;
|
|
40
|
+
buf[offset + 3] = (value >> 24) & 0xFF;
|
|
41
|
+
}
|
|
42
|
+
function writeBigUInt64LE(buf, value, offset) {
|
|
43
|
+
for (let i = 0; i < 8; i++) {
|
|
44
|
+
buf[offset + i] = Number((value >> BigInt(i * 8)) & BigInt(0xFF));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function readUInt16LE(buf, offset) {
|
|
48
|
+
return buf[offset] | (buf[offset + 1] << 8);
|
|
49
|
+
}
|
|
50
|
+
function readUInt32LE(buf, offset) {
|
|
51
|
+
return (buf[offset] | (buf[offset + 1] << 8) | (buf[offset + 2] << 16) | (buf[offset + 3] << 24)) >>> 0;
|
|
52
|
+
}
|
|
53
|
+
function readBigUInt64LE(buf, offset) {
|
|
54
|
+
let result = BigInt(0);
|
|
55
|
+
for (let i = 0; i < 8; i++) {
|
|
56
|
+
result |= BigInt(buf[offset + i]) << BigInt(i * 8);
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
function readFloatLE(buf, offset) {
|
|
61
|
+
const view = new DataView(buf.buffer, buf.byteOffset + offset, 4);
|
|
62
|
+
return view.getFloat32(0, true);
|
|
63
|
+
}
|
|
64
|
+
function utf8Decode(buf, start, end) {
|
|
65
|
+
const decoder = new TextDecoder('utf-8');
|
|
66
|
+
return decoder.decode(buf.subarray(start, end)).replace(/\0+$/, '');
|
|
67
|
+
}
|
|
68
|
+
function utf8Encode(str, buf, offset, maxLen) {
|
|
69
|
+
const encoder = new TextEncoder();
|
|
70
|
+
const encoded = encoder.encode(str.substring(0, maxLen));
|
|
71
|
+
buf.set(encoded, offset);
|
|
72
|
+
}
|
|
73
|
+
/** Encode LIFX message to Uint8Array */
|
|
32
74
|
export function encodeMessage(options) {
|
|
33
|
-
const payload = options.payload ??
|
|
75
|
+
const payload = options.payload ?? new Uint8Array(0);
|
|
34
76
|
const size = HEADER_SIZE + payload.length;
|
|
35
|
-
const buf =
|
|
77
|
+
const buf = new Uint8Array(size);
|
|
36
78
|
const tagged = options.tagged ?? !options.target;
|
|
37
79
|
const target = options.target ?? '00:00:00:00:00:00';
|
|
38
80
|
const sequence = options.sequence ?? nextSequence();
|
|
39
81
|
// Frame (8 bytes)
|
|
40
|
-
|
|
41
|
-
const protocol = 1024 | (tagged ? 0x2000 : 0) | 0x1000;
|
|
42
|
-
|
|
43
|
-
|
|
82
|
+
writeUInt16LE(buf, size, 0);
|
|
83
|
+
const protocol = 1024 | (tagged ? 0x2000 : 0) | 0x1000;
|
|
84
|
+
writeUInt16LE(buf, protocol, 2);
|
|
85
|
+
writeUInt32LE(buf, globalSource, 4);
|
|
44
86
|
// Frame Address (16 bytes)
|
|
45
|
-
macToBuffer(target)
|
|
46
|
-
// reserved (6 bytes at offset 16)
|
|
87
|
+
buf.set(macToBuffer(target), 8);
|
|
47
88
|
const flags = (options.resRequired ? 0x01 : 0) | (options.ackRequired ? 0x02 : 0);
|
|
48
89
|
buf[22] = flags;
|
|
49
90
|
buf[23] = sequence;
|
|
50
91
|
// Protocol Header (12 bytes)
|
|
51
|
-
|
|
52
|
-
buf.writeUInt16LE(options.type, 32); // type
|
|
53
|
-
// reserved (2 bytes at offset 34)
|
|
92
|
+
writeUInt16LE(buf, options.type, 32);
|
|
54
93
|
// Payload
|
|
55
94
|
if (payload.length > 0) {
|
|
56
|
-
|
|
95
|
+
buf.set(payload, HEADER_SIZE);
|
|
57
96
|
}
|
|
58
97
|
return buf;
|
|
59
98
|
}
|
|
60
|
-
/** Decode LIFX message from
|
|
99
|
+
/** Decode LIFX message from Uint8Array */
|
|
61
100
|
export function decodeMessage(buf) {
|
|
62
101
|
if (buf.length < HEADER_SIZE) {
|
|
63
102
|
throw new Error(`Buffer too small: ${buf.length} < ${HEADER_SIZE}`);
|
|
64
103
|
}
|
|
65
|
-
const size =
|
|
66
|
-
const protocolBits =
|
|
104
|
+
const size = readUInt16LE(buf, 0);
|
|
105
|
+
const protocolBits = readUInt16LE(buf, 2);
|
|
67
106
|
const tagged = (protocolBits & 0x2000) !== 0;
|
|
68
107
|
const addressable = (protocolBits & 0x1000) !== 0;
|
|
69
108
|
const protocol = protocolBits & 0xFFF;
|
|
70
|
-
const source =
|
|
109
|
+
const source = readUInt32LE(buf, 4);
|
|
71
110
|
const target = bufferToMac(buf, 8);
|
|
72
111
|
const flags = buf[22];
|
|
73
112
|
const sequence = buf[23];
|
|
74
|
-
const type =
|
|
75
|
-
const payload = buf.length > HEADER_SIZE ? buf.subarray(HEADER_SIZE) :
|
|
113
|
+
const type = readUInt16LE(buf, 32);
|
|
114
|
+
const payload = buf.length > HEADER_SIZE ? buf.subarray(HEADER_SIZE) : new Uint8Array(0);
|
|
76
115
|
return {
|
|
77
116
|
size,
|
|
78
117
|
protocol,
|
|
@@ -88,39 +127,43 @@ export function decodeMessage(buf) {
|
|
|
88
127
|
};
|
|
89
128
|
}
|
|
90
129
|
/** Encode SetPower payload */
|
|
91
|
-
export function encodeSetPower(
|
|
92
|
-
const buf =
|
|
93
|
-
|
|
130
|
+
export function encodeSetPower(level) {
|
|
131
|
+
const buf = new Uint8Array(2);
|
|
132
|
+
writeUInt16LE(buf, level ? 0xFFFF : 0, 0);
|
|
94
133
|
return buf;
|
|
95
134
|
}
|
|
96
135
|
/** Encode SetColor payload */
|
|
97
136
|
export function encodeSetColor(hsbk, duration = 0) {
|
|
98
|
-
const buf =
|
|
99
|
-
buf[0] = 0;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
137
|
+
const buf = new Uint8Array(13);
|
|
138
|
+
buf[0] = 0;
|
|
139
|
+
writeUInt16LE(buf, hsbk.h, 1);
|
|
140
|
+
writeUInt16LE(buf, hsbk.s, 3);
|
|
141
|
+
writeUInt16LE(buf, hsbk.b, 5);
|
|
142
|
+
writeUInt16LE(buf, hsbk.k, 7);
|
|
143
|
+
writeUInt32LE(buf, duration, 9);
|
|
105
144
|
return buf;
|
|
106
145
|
}
|
|
107
146
|
/** Encode SetLabel payload */
|
|
108
147
|
export function encodeSetLabel(label) {
|
|
109
|
-
const buf =
|
|
110
|
-
|
|
148
|
+
const buf = new Uint8Array(32);
|
|
149
|
+
utf8Encode(label, buf, 0, 32);
|
|
111
150
|
return buf;
|
|
112
151
|
}
|
|
113
152
|
/** Encode SetGroup payload */
|
|
114
153
|
export function encodeSetGroup(id, label) {
|
|
115
|
-
const buf =
|
|
154
|
+
const buf = new Uint8Array(56);
|
|
116
155
|
// 16-byte group ID
|
|
117
|
-
const idBytes =
|
|
118
|
-
|
|
156
|
+
const idBytes = new Uint8Array(16);
|
|
157
|
+
const hexId = id.replace(/-/g, '');
|
|
158
|
+
for (let i = 0; i < Math.min(16, hexId.length / 2); i++) {
|
|
159
|
+
idBytes[i] = parseInt(hexId.substr(i * 2, 2), 16);
|
|
160
|
+
}
|
|
161
|
+
buf.set(idBytes, 0);
|
|
119
162
|
// 32-byte label
|
|
120
|
-
|
|
163
|
+
utf8Encode(label, buf, 16, 32);
|
|
121
164
|
// 8-byte updated_at timestamp (ns since epoch)
|
|
122
165
|
const now = BigInt(Date.now()) * BigInt(1000000);
|
|
123
|
-
|
|
166
|
+
writeBigUInt64LE(buf, now, 48);
|
|
124
167
|
return buf;
|
|
125
168
|
}
|
|
126
169
|
/** Encode SetLocation payload (same format as SetGroup) */
|
|
@@ -131,59 +174,59 @@ export function encodeSetLocation(id, label) {
|
|
|
131
174
|
export function decodeState(payload) {
|
|
132
175
|
return {
|
|
133
176
|
hsbk: {
|
|
134
|
-
h:
|
|
135
|
-
s:
|
|
136
|
-
b:
|
|
137
|
-
k:
|
|
177
|
+
h: readUInt16LE(payload, 0),
|
|
178
|
+
s: readUInt16LE(payload, 2),
|
|
179
|
+
b: readUInt16LE(payload, 4),
|
|
180
|
+
k: readUInt16LE(payload, 6)
|
|
138
181
|
},
|
|
139
|
-
power:
|
|
140
|
-
label: payload
|
|
182
|
+
power: readUInt16LE(payload, 10),
|
|
183
|
+
label: utf8Decode(payload, 12, 44)
|
|
141
184
|
};
|
|
142
185
|
}
|
|
143
186
|
/** Decode StatePower (22) payload */
|
|
144
187
|
export function decodeStatePower(payload) {
|
|
145
|
-
return
|
|
188
|
+
return readUInt16LE(payload, 0) > 0;
|
|
146
189
|
}
|
|
147
190
|
/** Decode StateLabel (25) payload */
|
|
148
191
|
export function decodeStateLabel(payload) {
|
|
149
|
-
return payload
|
|
192
|
+
return utf8Decode(payload, 0, 32);
|
|
150
193
|
}
|
|
151
194
|
/** Decode StateVersion (33) payload */
|
|
152
195
|
export function decodeStateVersion(payload) {
|
|
153
196
|
return {
|
|
154
|
-
vendor:
|
|
155
|
-
product:
|
|
156
|
-
version:
|
|
197
|
+
vendor: readUInt32LE(payload, 0),
|
|
198
|
+
product: readUInt32LE(payload, 4),
|
|
199
|
+
version: readUInt32LE(payload, 8)
|
|
157
200
|
};
|
|
158
201
|
}
|
|
159
202
|
/** Decode StateGroup (53) or StateLocation (50) payload */
|
|
160
203
|
export function decodeStateGroup(payload) {
|
|
161
204
|
const idBytes = payload.subarray(0, 16);
|
|
162
|
-
const id = idBytes.toString('
|
|
163
|
-
const label = payload
|
|
164
|
-
const updatedAt = Number(
|
|
205
|
+
const id = Array.from(idBytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
206
|
+
const label = utf8Decode(payload, 16, 48);
|
|
207
|
+
const updatedAt = Number(readBigUInt64LE(payload, 48) / BigInt(1000000));
|
|
165
208
|
return { id, label, updatedAt };
|
|
166
209
|
}
|
|
167
210
|
/** Decode StateService (3) payload */
|
|
168
211
|
export function decodeStateService(payload) {
|
|
169
212
|
return {
|
|
170
213
|
service: payload[0],
|
|
171
|
-
port:
|
|
214
|
+
port: readUInt32LE(payload, 1)
|
|
172
215
|
};
|
|
173
216
|
}
|
|
174
217
|
/** Decode StateHostInfo (13) payload */
|
|
175
218
|
export function decodeStateHostInfo(payload) {
|
|
176
219
|
return {
|
|
177
|
-
signal:
|
|
178
|
-
tx:
|
|
179
|
-
rx:
|
|
220
|
+
signal: readFloatLE(payload, 0),
|
|
221
|
+
tx: readUInt32LE(payload, 4),
|
|
222
|
+
rx: readUInt32LE(payload, 8)
|
|
180
223
|
};
|
|
181
224
|
}
|
|
182
225
|
/** Decode StateHostFirmware (15) payload */
|
|
183
226
|
export function decodeStateHostFirmware(payload) {
|
|
184
227
|
return {
|
|
185
|
-
build: Number(
|
|
186
|
-
version:
|
|
228
|
+
build: Number(readBigUInt64LE(payload, 0)),
|
|
229
|
+
version: readUInt32LE(payload, 8)
|
|
187
230
|
};
|
|
188
231
|
}
|
|
189
232
|
/** Decode StateWifiInfo (17) payload - same format as StateHostInfo */
|
|
@@ -193,9 +236,22 @@ export function decodeStateWifiInfo(payload) {
|
|
|
193
236
|
/** Decode StateInfo (35) payload */
|
|
194
237
|
export function decodeStateInfo(payload) {
|
|
195
238
|
return {
|
|
196
|
-
time: Number(
|
|
197
|
-
uptime: Number(
|
|
198
|
-
downtime: Number(
|
|
239
|
+
time: Number(readBigUInt64LE(payload, 0) / BigInt(1000000)),
|
|
240
|
+
uptime: Number(readBigUInt64LE(payload, 8) / BigInt(1000000)),
|
|
241
|
+
downtime: Number(readBigUInt64LE(payload, 16) / BigInt(1000000))
|
|
199
242
|
};
|
|
200
243
|
}
|
|
244
|
+
/** Encode GetService payload (empty) */
|
|
245
|
+
export function encodeGetService() {
|
|
246
|
+
return new Uint8Array(0);
|
|
247
|
+
}
|
|
248
|
+
// Buffer compatibility helper
|
|
249
|
+
const BufferImpl = typeof Buffer !== 'undefined' ? Buffer : class {
|
|
250
|
+
static alloc(size) {
|
|
251
|
+
return new Uint8Array(size);
|
|
252
|
+
}
|
|
253
|
+
static from(data) {
|
|
254
|
+
return new Uint8Array(data);
|
|
255
|
+
}
|
|
256
|
+
};
|
|
201
257
|
//# sourceMappingURL=protocol.js.map
|
package/release-all.ps1
CHANGED
|
@@ -1,168 +1,168 @@
|
|
|
1
|
-
#!/usr/bin/env pwsh
|
|
2
|
-
# Release all LIFX packages in dependency order
|
|
3
|
-
# Automatically handles missing git remotes and GitHub repositories
|
|
4
|
-
|
|
5
|
-
$ErrorActionPreference = "Stop"
|
|
6
|
-
|
|
7
|
-
# Suppress npm color output
|
|
8
|
-
$env:NO_COLOR = "1"
|
|
9
|
-
$env:FORCE_COLOR = "0"
|
|
10
|
-
$env:NPM_CONFIG_COLOR = "false"
|
|
11
|
-
|
|
12
|
-
# Function to ensure git remote and GitHub repo exist
|
|
13
|
-
function
|
|
14
|
-
param(
|
|
15
|
-
[string]$RepoPath,
|
|
16
|
-
[string]$RepoName,
|
|
17
|
-
[string]$Owner = "BobFrankston"
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
Push-Location $RepoPath
|
|
21
|
-
|
|
22
|
-
# Check if remote exists
|
|
23
|
-
$remote = git remote 2>$null
|
|
24
|
-
|
|
25
|
-
if (-not $remote -or $remote -notcontains "origin") {
|
|
26
|
-
Write-Host " → Setting up git remote..." -ForegroundColor Yellow
|
|
27
|
-
$remoteUrl = "https://github.com/$Owner/$RepoName.git"
|
|
28
|
-
git remote add origin $remoteUrl 2>$null
|
|
29
|
-
Write-Host " ✓ Added remote: $remoteUrl" -ForegroundColor Green
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
# Check if GitHub repo exists, create if needed
|
|
33
|
-
|
|
34
|
-
if ($LASTEXITCODE -ne 0) {
|
|
35
|
-
Write-Host " → Creating GitHub repository..." -ForegroundColor Yellow
|
|
36
|
-
$desc = "Part of LIFX LAN control suite"
|
|
37
|
-
gh repo create "$Owner/$RepoName" --public --description $desc
|
|
38
|
-
if ($LASTEXITCODE -eq 0) {
|
|
39
|
-
Write-Host " ✓ Repository created!" -ForegroundColor Green
|
|
40
|
-
} else {
|
|
41
|
-
Write-Host " ✗ Failed to create repository" -ForegroundColor Red
|
|
42
|
-
Pop-Location
|
|
43
|
-
exit 1
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
# Check if upstream is set
|
|
48
|
-
$upstreamBranch = git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>$null
|
|
49
|
-
if (-not $upstreamBranch) {
|
|
50
|
-
Write-Host " → Setting upstream branch..." -ForegroundColor Yellow
|
|
51
|
-
git push --set-upstream origin master 2>&1 | Out-Null
|
|
52
|
-
if ($LASTEXITCODE -eq 0) {
|
|
53
|
-
Write-Host " ✓ Upstream branch set" -ForegroundColor Green
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
Pop-Location
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
Write-Host ""
|
|
61
|
-
Write-Host "=== Releasing LIFX Packages ===" -ForegroundColor Cyan
|
|
62
|
-
Write-Host ""
|
|
63
|
-
|
|
64
|
-
# Base packages (no dependencies on each other)
|
|
65
|
-
Write-Host ">>> Releasing hlib..." -ForegroundColor Yellow
|
|
66
|
-
|
|
67
|
-
Set-Location "y:\dev\homecontrol\utils\hlib"
|
|
68
|
-
npm run release
|
|
69
|
-
if ($LASTEXITCODE -ne 0) {
|
|
70
|
-
Write-Host "ERROR: hlib release failed" -ForegroundColor Red
|
|
71
|
-
exit 1
|
|
72
|
-
}
|
|
73
|
-
Write-Host ""
|
|
74
|
-
|
|
75
|
-
Write-Host ">>> Releasing rmfudp..." -ForegroundColor Yellow
|
|
76
|
-
|
|
77
|
-
Set-Location "y:\dev\homecontrol\utils\rmfudp"
|
|
78
|
-
npm run release
|
|
79
|
-
if ($LASTEXITCODE -ne 0) {
|
|
80
|
-
Write-Host "ERROR: rmfudp release failed" -ForegroundColor Red
|
|
81
|
-
exit 1
|
|
82
|
-
}
|
|
83
|
-
Write-Host ""
|
|
84
|
-
|
|
85
|
-
Write-Host ">>> Releasing colorlib..." -ForegroundColor Yellow
|
|
86
|
-
|
|
87
|
-
Set-Location "y:\dev\homecontrol\utils\colorlib"
|
|
88
|
-
npm run release
|
|
89
|
-
if ($LASTEXITCODE -ne 0) {
|
|
90
|
-
Write-Host "ERROR: colorlib release failed" -ForegroundColor Red
|
|
91
|
-
exit 1
|
|
92
|
-
}
|
|
93
|
-
Write-Host ""
|
|
94
|
-
|
|
95
|
-
Write-Host ">>> Releasing lxlan..." -ForegroundColor Yellow
|
|
96
|
-
|
|
97
|
-
Set-Location "y:\dev\homecontrol\Others\LifX\Apps\lxlan"
|
|
98
|
-
npm run release
|
|
99
|
-
if ($LASTEXITCODE -ne 0) {
|
|
100
|
-
Write-Host "ERROR: lxlan release failed" -ForegroundColor Red
|
|
101
|
-
exit 1
|
|
102
|
-
}
|
|
103
|
-
Write-Host ""
|
|
104
|
-
|
|
105
|
-
# Update dependencies after base packages
|
|
106
|
-
Write-Host ">>> Updating lxlan-node dependencies..." -ForegroundColor Yellow
|
|
107
|
-
|
|
108
|
-
Set-Location "y:\dev\homecontrol\Others\LifX\Apps\lxlan-node"
|
|
109
|
-
npm install
|
|
110
|
-
if ($LASTEXITCODE -ne 0) {
|
|
111
|
-
Write-Host "ERROR: lxlan-node npm install failed" -ForegroundColor Red
|
|
112
|
-
exit 1
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
Write-Host ">>> Releasing lxlan-node..." -ForegroundColor Yellow
|
|
116
|
-
npm run release
|
|
117
|
-
if ($LASTEXITCODE -ne 0) {
|
|
118
|
-
Write-Host "ERROR: lxlan-node release failed" -ForegroundColor Red
|
|
119
|
-
exit 1
|
|
120
|
-
}
|
|
121
|
-
Write-Host ""
|
|
122
|
-
|
|
123
|
-
# Update lifxer dependencies
|
|
124
|
-
Write-Host ">>> Updating lifxer dependencies..." -ForegroundColor Yellow
|
|
125
|
-
|
|
126
|
-
Set-Location "y:\dev\homecontrol\Others\LifX\Apps\lifxer"
|
|
127
|
-
npm install
|
|
128
|
-
if ($LASTEXITCODE -ne 0) {
|
|
129
|
-
Write-Host "ERROR: lifxer npm install failed" -ForegroundColor Red
|
|
130
|
-
exit 1
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
Write-Host ">>> Releasing lifxer..." -ForegroundColor Yellow
|
|
134
|
-
npm run release
|
|
135
|
-
if ($LASTEXITCODE -ne 0) {
|
|
136
|
-
Write-Host "ERROR: lifxer release failed" -ForegroundColor Red
|
|
137
|
-
exit 1
|
|
138
|
-
}
|
|
139
|
-
Write-Host ""
|
|
140
|
-
|
|
141
|
-
# lxtest
|
|
142
|
-
Write-Host ">>> Updating lxtest dependencies..." -ForegroundColor Yellow
|
|
143
|
-
|
|
144
|
-
Set-Location "y:\dev\homecontrol\Others\LifX\Apps\lxtest"
|
|
145
|
-
npm install
|
|
146
|
-
if ($LASTEXITCODE -ne 0) {
|
|
147
|
-
Write-Host "ERROR: lxtest npm install failed" -ForegroundColor Red
|
|
148
|
-
exit 1
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
Write-Host ">>> Releasing lxtest..." -ForegroundColor Yellow
|
|
152
|
-
npm run release
|
|
153
|
-
if ($LASTEXITCODE -ne 0) {
|
|
154
|
-
Write-Host "ERROR: lxtest release failed" -ForegroundColor Red
|
|
155
|
-
exit 1
|
|
156
|
-
}
|
|
157
|
-
Write-Host ""
|
|
158
|
-
|
|
159
|
-
Write-Host "=== All releases completed successfully! ===" -ForegroundColor Green
|
|
160
|
-
Write-Host ""
|
|
161
|
-
Write-Host "Released packages:"
|
|
162
|
-
Write-Host " - @bobfrankston/hlib"
|
|
163
|
-
Write-Host " - @bobfrankston/rmfudp"
|
|
164
|
-
Write-Host " - @bobfrankston/colorlib"
|
|
165
|
-
Write-Host " - @bobfrankston/lxlan"
|
|
166
|
-
Write-Host " - @bobfrankston/lxlan-node"
|
|
167
|
-
Write-Host " - @bobfrankston/lifxer"
|
|
168
|
-
Write-Host " - lxtest"
|
|
1
|
+
#!/usr/bin/env pwsh
|
|
2
|
+
# Release all LIFX packages in dependency order
|
|
3
|
+
# Automatically handles missing git remotes and GitHub repositories
|
|
4
|
+
|
|
5
|
+
$ErrorActionPreference = "Stop"
|
|
6
|
+
|
|
7
|
+
# Suppress npm color output
|
|
8
|
+
$env:NO_COLOR = "1"
|
|
9
|
+
$env:FORCE_COLOR = "0"
|
|
10
|
+
$env:NPM_CONFIG_COLOR = "false"
|
|
11
|
+
|
|
12
|
+
# Function to ensure git remote and GitHub repo exist
|
|
13
|
+
function Initialize-GitRemote {
|
|
14
|
+
param(
|
|
15
|
+
[string]$RepoPath,
|
|
16
|
+
[string]$RepoName,
|
|
17
|
+
[string]$Owner = "BobFrankston"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
Push-Location $RepoPath
|
|
21
|
+
|
|
22
|
+
# Check if remote exists
|
|
23
|
+
$remote = git remote 2>$null
|
|
24
|
+
|
|
25
|
+
if (-not $remote -or $remote -notcontains "origin") {
|
|
26
|
+
Write-Host " → Setting up git remote..." -ForegroundColor Yellow
|
|
27
|
+
$remoteUrl = "https://github.com/$Owner/$RepoName.git"
|
|
28
|
+
git remote add origin $remoteUrl 2>$null
|
|
29
|
+
Write-Host " ✓ Added remote: $remoteUrl" -ForegroundColor Green
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# Check if GitHub repo exists, create if needed
|
|
33
|
+
gh repo view "$Owner/$RepoName" 2>$null | Out-Null
|
|
34
|
+
if ($LASTEXITCODE -ne 0) {
|
|
35
|
+
Write-Host " → Creating GitHub repository..." -ForegroundColor Yellow
|
|
36
|
+
$desc = "Part of LIFX LAN control suite"
|
|
37
|
+
gh repo create "$Owner/$RepoName" --public --description $desc
|
|
38
|
+
if ($LASTEXITCODE -eq 0) {
|
|
39
|
+
Write-Host " ✓ Repository created!" -ForegroundColor Green
|
|
40
|
+
} else {
|
|
41
|
+
Write-Host " ✗ Failed to create repository" -ForegroundColor Red
|
|
42
|
+
Pop-Location
|
|
43
|
+
exit 1
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Check if upstream is set
|
|
48
|
+
$upstreamBranch = git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>$null
|
|
49
|
+
if (-not $upstreamBranch) {
|
|
50
|
+
Write-Host " → Setting upstream branch..." -ForegroundColor Yellow
|
|
51
|
+
git push --set-upstream origin master 2>&1 | Out-Null
|
|
52
|
+
if ($LASTEXITCODE -eq 0) {
|
|
53
|
+
Write-Host " ✓ Upstream branch set" -ForegroundColor Green
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Pop-Location
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
Write-Host ""
|
|
61
|
+
Write-Host "=== Releasing LIFX Packages ===" -ForegroundColor Cyan
|
|
62
|
+
Write-Host ""
|
|
63
|
+
|
|
64
|
+
# Base packages (no dependencies on each other)
|
|
65
|
+
Write-Host ">>> Releasing hlib..." -ForegroundColor Yellow
|
|
66
|
+
Initialize-GitRemote -RepoPath "y:\dev\homecontrol\utils\hlib" -RepoName "hlib"
|
|
67
|
+
Set-Location "y:\dev\homecontrol\utils\hlib"
|
|
68
|
+
npm run release
|
|
69
|
+
if ($LASTEXITCODE -ne 0) {
|
|
70
|
+
Write-Host "ERROR: hlib release failed" -ForegroundColor Red
|
|
71
|
+
exit 1
|
|
72
|
+
}
|
|
73
|
+
Write-Host ""
|
|
74
|
+
|
|
75
|
+
Write-Host ">>> Releasing rmfudp..." -ForegroundColor Yellow
|
|
76
|
+
Initialize-GitRemote -RepoPath "y:\dev\homecontrol\utils\rmfudp" -RepoName "rmfudp"
|
|
77
|
+
Set-Location "y:\dev\homecontrol\utils\rmfudp"
|
|
78
|
+
npm run release
|
|
79
|
+
if ($LASTEXITCODE -ne 0) {
|
|
80
|
+
Write-Host "ERROR: rmfudp release failed" -ForegroundColor Red
|
|
81
|
+
exit 1
|
|
82
|
+
}
|
|
83
|
+
Write-Host ""
|
|
84
|
+
|
|
85
|
+
Write-Host ">>> Releasing colorlib..." -ForegroundColor Yellow
|
|
86
|
+
Initialize-GitRemote -RepoPath "y:\dev\homecontrol\utils\colorlib" -RepoName "colorlib"
|
|
87
|
+
Set-Location "y:\dev\homecontrol\utils\colorlib"
|
|
88
|
+
npm run release
|
|
89
|
+
if ($LASTEXITCODE -ne 0) {
|
|
90
|
+
Write-Host "ERROR: colorlib release failed" -ForegroundColor Red
|
|
91
|
+
exit 1
|
|
92
|
+
}
|
|
93
|
+
Write-Host ""
|
|
94
|
+
|
|
95
|
+
Write-Host ">>> Releasing lxlan..." -ForegroundColor Yellow
|
|
96
|
+
Initialize-GitRemote -RepoPath "y:\dev\homecontrol\Others\LifX\Apps\lxlan" -RepoName "lxlan"
|
|
97
|
+
Set-Location "y:\dev\homecontrol\Others\LifX\Apps\lxlan"
|
|
98
|
+
npm run release
|
|
99
|
+
if ($LASTEXITCODE -ne 0) {
|
|
100
|
+
Write-Host "ERROR: lxlan release failed" -ForegroundColor Red
|
|
101
|
+
exit 1
|
|
102
|
+
}
|
|
103
|
+
Write-Host ""
|
|
104
|
+
|
|
105
|
+
# Update dependencies after base packages
|
|
106
|
+
Write-Host ">>> Updating lxlan-node dependencies..." -ForegroundColor Yellow
|
|
107
|
+
Initialize-GitRemote -RepoPath "y:\dev\homecontrol\Others\LifX\Apps\lxlan-node" -RepoName "lxlan-node"
|
|
108
|
+
Set-Location "y:\dev\homecontrol\Others\LifX\Apps\lxlan-node"
|
|
109
|
+
npm install
|
|
110
|
+
if ($LASTEXITCODE -ne 0) {
|
|
111
|
+
Write-Host "ERROR: lxlan-node npm install failed" -ForegroundColor Red
|
|
112
|
+
exit 1
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
Write-Host ">>> Releasing lxlan-node..." -ForegroundColor Yellow
|
|
116
|
+
npm run release
|
|
117
|
+
if ($LASTEXITCODE -ne 0) {
|
|
118
|
+
Write-Host "ERROR: lxlan-node release failed" -ForegroundColor Red
|
|
119
|
+
exit 1
|
|
120
|
+
}
|
|
121
|
+
Write-Host ""
|
|
122
|
+
|
|
123
|
+
# Update lifxer dependencies
|
|
124
|
+
Write-Host ">>> Updating lifxer dependencies..." -ForegroundColor Yellow
|
|
125
|
+
Initialize-GitRemote -RepoPath "y:\dev\homecontrol\Others\LifX\Apps\lifxer" -RepoName "lifxer"
|
|
126
|
+
Set-Location "y:\dev\homecontrol\Others\LifX\Apps\lifxer"
|
|
127
|
+
npm install
|
|
128
|
+
if ($LASTEXITCODE -ne 0) {
|
|
129
|
+
Write-Host "ERROR: lifxer npm install failed" -ForegroundColor Red
|
|
130
|
+
exit 1
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
Write-Host ">>> Releasing lifxer..." -ForegroundColor Yellow
|
|
134
|
+
npm run release
|
|
135
|
+
if ($LASTEXITCODE -ne 0) {
|
|
136
|
+
Write-Host "ERROR: lifxer release failed" -ForegroundColor Red
|
|
137
|
+
exit 1
|
|
138
|
+
}
|
|
139
|
+
Write-Host ""
|
|
140
|
+
|
|
141
|
+
# lxtest
|
|
142
|
+
Write-Host ">>> Updating lxtest dependencies..." -ForegroundColor Yellow
|
|
143
|
+
Initialize-GitRemote -RepoPath "y:\dev\homecontrol\Others\LifX\Apps\lxtest" -RepoName "lxtest"
|
|
144
|
+
Set-Location "y:\dev\homecontrol\Others\LifX\Apps\lxtest"
|
|
145
|
+
npm install
|
|
146
|
+
if ($LASTEXITCODE -ne 0) {
|
|
147
|
+
Write-Host "ERROR: lxtest npm install failed" -ForegroundColor Red
|
|
148
|
+
exit 1
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
Write-Host ">>> Releasing lxtest..." -ForegroundColor Yellow
|
|
152
|
+
npm run release
|
|
153
|
+
if ($LASTEXITCODE -ne 0) {
|
|
154
|
+
Write-Host "ERROR: lxtest release failed" -ForegroundColor Red
|
|
155
|
+
exit 1
|
|
156
|
+
}
|
|
157
|
+
Write-Host ""
|
|
158
|
+
|
|
159
|
+
Write-Host "=== All releases completed successfully! ===" -ForegroundColor Green
|
|
160
|
+
Write-Host ""
|
|
161
|
+
Write-Host "Released packages:"
|
|
162
|
+
Write-Host " - @bobfrankston/hlib"
|
|
163
|
+
Write-Host " - @bobfrankston/rmfudp"
|
|
164
|
+
Write-Host " - @bobfrankston/colorlib"
|
|
165
|
+
Write-Host " - @bobfrankston/lxlan"
|
|
166
|
+
Write-Host " - @bobfrankston/lxlan-node"
|
|
167
|
+
Write-Host " - @bobfrankston/lifxer"
|
|
168
|
+
Write-Host " - lxtest"
|
package/transport.d.ts
CHANGED
|
@@ -1,30 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* - UDP (current: rmfudp)
|
|
5
|
-
* - HTTP (future: for web/browser support)
|
|
6
|
-
* - WebSocket (future: bidirectional web support)
|
|
2
|
+
* Re-export UDP transport interfaces from @bobfrankston/udp-transport
|
|
3
|
+
* LxTransport is kept as an alias for backwards compatibility
|
|
7
4
|
*/
|
|
8
|
-
|
|
9
|
-
export
|
|
10
|
-
address: string;
|
|
11
|
-
port: number;
|
|
12
|
-
}
|
|
13
|
-
/** Transport layer interface */
|
|
14
|
-
export interface LxTransport {
|
|
15
|
-
/** Bind/start the transport */
|
|
16
|
-
bind(): Promise<void>;
|
|
17
|
-
/** Close/stop the transport */
|
|
18
|
-
close(): void;
|
|
19
|
-
/** Send data to specific address */
|
|
20
|
-
send(ip: string, port: number, data: Buffer): void;
|
|
21
|
-
/** Broadcast data to all addresses */
|
|
22
|
-
broadcast(data: Buffer, port: number, addresses: string[]): void;
|
|
23
|
-
/** Register message handler */
|
|
24
|
-
onMessage(handler: (data: Buffer, rinfo: RemoteInfo) => void): void;
|
|
25
|
-
/** Register error handler */
|
|
26
|
-
onError(handler: (err: Error) => void): void;
|
|
27
|
-
/** Register close handler */
|
|
28
|
-
onClose(handler: () => void): void;
|
|
29
|
-
}
|
|
5
|
+
export { UdpTransport, RemoteInfo } from '@bobfrankston/udp-transport';
|
|
6
|
+
export { UdpTransport as LxTransport } from '@bobfrankston/udp-transport';
|
|
30
7
|
//# sourceMappingURL=transport.d.ts.map
|