ocremote 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/rpc.mjs +14 -7
- package/oc-remote.mjs +22 -15
- package/package.json +1 -5
- /package/vendor/{qrcode.js → qrcode.cjs} +0 -0
package/lib/rpc.mjs
CHANGED
|
@@ -21,19 +21,24 @@ export class RpcAdapter {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
cancel(session, id) {
|
|
24
|
-
const
|
|
25
|
-
if (
|
|
26
|
-
controller.abort()
|
|
24
|
+
const entry = this.sessionMap(session).get(id)
|
|
25
|
+
if (entry) {
|
|
26
|
+
entry.controller.abort()
|
|
27
27
|
this.log(`rpc ${id} cancelled`)
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// The channel dropped. Reads are abandoned, but a mutating request keeps
|
|
32
|
+
// running: aborting it would leave the phone unable to tell whether the
|
|
33
|
+
// server applied it. Better to let it finish on the computer and let the
|
|
34
|
+
// client reconcile by inspecting state after reconnecting.
|
|
31
35
|
cancelAll(session) {
|
|
32
36
|
const map = this.active.get(session.id)
|
|
33
37
|
if (!map) return
|
|
34
|
-
for (const
|
|
38
|
+
for (const entry of map.values()) {
|
|
39
|
+
if (entry.mutating) continue
|
|
35
40
|
try {
|
|
36
|
-
controller.abort()
|
|
41
|
+
entry.controller.abort()
|
|
37
42
|
} catch {}
|
|
38
43
|
}
|
|
39
44
|
this.active.delete(session.id)
|
|
@@ -53,7 +58,9 @@ export class RpcAdapter {
|
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
const controller = new AbortController()
|
|
56
|
-
|
|
61
|
+
const method = (msg.method || 'GET').toUpperCase()
|
|
62
|
+
const mutating = method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'DELETE'
|
|
63
|
+
map.set(id, { controller, mutating })
|
|
57
64
|
const stream = msg.stream === true
|
|
58
65
|
let opened = false
|
|
59
66
|
try {
|
|
@@ -65,7 +72,7 @@ export class RpcAdapter {
|
|
|
65
72
|
}
|
|
66
73
|
}
|
|
67
74
|
const headers = { authorization: this.authHeader }
|
|
68
|
-
const init = { method
|
|
75
|
+
const init = { method, headers, signal: controller.signal }
|
|
69
76
|
if (msg.body) {
|
|
70
77
|
const body = Buffer.from(String(msg.body), 'base64')
|
|
71
78
|
if (body.length > MAX_UPLOAD) {
|
package/oc-remote.mjs
CHANGED
|
@@ -17,7 +17,7 @@ import { b64 } from './lib/crypto.mjs'
|
|
|
17
17
|
|
|
18
18
|
const require = createRequire(import.meta.url)
|
|
19
19
|
const NAME = 'oc-remote'
|
|
20
|
-
const VERSION = '1.3.
|
|
20
|
+
const VERSION = '1.3.1'
|
|
21
21
|
const LAUNCH_LABEL = 'com.raul.ocremote'
|
|
22
22
|
const LOG_PATH = path.join(os.homedir(), 'Library', 'Logs', 'oc-remote.log')
|
|
23
23
|
const STARTED_AT = Date.now()
|
|
@@ -26,7 +26,7 @@ const LOOPBACK = '127.0.0.1'
|
|
|
26
26
|
|
|
27
27
|
let qrcode = null
|
|
28
28
|
try {
|
|
29
|
-
qrcode = require(path.join(HERE, 'vendor', 'qrcode.
|
|
29
|
+
qrcode = require(path.join(HERE, 'vendor', 'qrcode.cjs'))
|
|
30
30
|
} catch {
|
|
31
31
|
qrcode = null
|
|
32
32
|
}
|
|
@@ -1552,7 +1552,7 @@ function printPairing() {
|
|
|
1552
1552
|
info(`pairing deep link: ${pairLink()}`)
|
|
1553
1553
|
if (!opts.printQr) return
|
|
1554
1554
|
if (!qrcode) {
|
|
1555
|
-
warn('QR unavailable: companion/vendor/qrcode.
|
|
1555
|
+
warn('QR unavailable: companion/vendor/qrcode.cjs not found')
|
|
1556
1556
|
return
|
|
1557
1557
|
}
|
|
1558
1558
|
const ascii = buildQr(pairLink()).createASCII(1, 4)
|
|
@@ -1613,10 +1613,7 @@ function printBanner(health) {
|
|
|
1613
1613
|
info(`opencode: ${opts.opencodeBin} v${health.version} -> http://${LOOPBACK}:${opts.opencodePort} (loopback only)`)
|
|
1614
1614
|
info(`proxy listening: ${opts.host}:${opts.port}`)
|
|
1615
1615
|
if (opts.noAuth) warn('AUTH DISABLED: anyone who can reach this port controls opencode')
|
|
1616
|
-
|
|
1617
|
-
? ['pair page: disabled (--no-auth)']
|
|
1618
|
-
: [`pair page (loopback): http://${LOOPBACK}:${opts.port}/_ocremote/pair`])
|
|
1619
|
-
info(line)
|
|
1616
|
+
if (opts.noAuth) info('pair page: disabled (--no-auth)')
|
|
1620
1617
|
if (opts.relay) info(`relay: ${opts.relay} (device ${opts.deviceName || os.hostname()})`)
|
|
1621
1618
|
info('self-check: oc-remote doctor')
|
|
1622
1619
|
printPairing()
|
|
@@ -2237,6 +2234,14 @@ async function main() {
|
|
|
2237
2234
|
opts.dir = dir
|
|
2238
2235
|
|
|
2239
2236
|
if (flags.daemon) {
|
|
2237
|
+
if (process.platform !== 'darwin') {
|
|
2238
|
+
const say = (line) => process.stdout.write(`${line}\n`)
|
|
2239
|
+
say('--daemon installs a macOS LaunchAgent.')
|
|
2240
|
+
say('On Linux: create a systemd user unit running `npx ocremote --pair` (systemctl --user enable --now ocremote).')
|
|
2241
|
+
say('On Windows: add a Task Scheduler entry running `npx ocremote --pair` at logon.')
|
|
2242
|
+
say('Either way the foreground mode below works everywhere: npx ocremote --pair')
|
|
2243
|
+
return 1
|
|
2244
|
+
}
|
|
2240
2245
|
const installer = path.join(HERE, 'install.sh')
|
|
2241
2246
|
if (!fs.existsSync(installer)) abort(`install.sh not found next to oc-remote.mjs`)
|
|
2242
2247
|
const args = [installer, '--dir', dir, '--port', String(opts.port)]
|
|
@@ -2347,21 +2352,23 @@ async function main() {
|
|
|
2347
2352
|
info(`opencode is healthy (v${health.version})`)
|
|
2348
2353
|
|
|
2349
2354
|
server = createProxyServer()
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
server.
|
|
2354
|
-
|
|
2355
|
+
try {
|
|
2356
|
+
await new Promise((resolve, reject) => {
|
|
2357
|
+
server.once('error', reject)
|
|
2358
|
+
server.listen(opts.port, opts.host, () => {
|
|
2359
|
+
server.off('error', reject)
|
|
2360
|
+
resolve()
|
|
2361
|
+
})
|
|
2355
2362
|
})
|
|
2356
|
-
}
|
|
2363
|
+
} catch (err) {
|
|
2357
2364
|
error(
|
|
2358
2365
|
err.code === 'EADDRINUSE'
|
|
2359
|
-
? `port ${opts.port} is already in use; pick another with --port`
|
|
2366
|
+
? `port ${opts.port} is already in use; pick another with --port (is the companion already running?)`
|
|
2360
2367
|
: `could not listen on ${opts.host}:${opts.port}: ${err.message}`
|
|
2361
2368
|
)
|
|
2362
2369
|
if (child && child.exitCode === null) child.kill('SIGKILL')
|
|
2363
2370
|
return 1
|
|
2364
|
-
}
|
|
2371
|
+
}
|
|
2365
2372
|
|
|
2366
2373
|
printBanner(health)
|
|
2367
2374
|
utilityServer = await createUtilityServer()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ocremote",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Control opencode on your computer from the OpenCode Remote iOS app: supervisor, pairing QR, relay and tunnel transports",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -15,10 +15,6 @@
|
|
|
15
15
|
"engines": {
|
|
16
16
|
"node": ">=20"
|
|
17
17
|
},
|
|
18
|
-
"os": [
|
|
19
|
-
"darwin",
|
|
20
|
-
"linux"
|
|
21
|
-
],
|
|
22
18
|
"keywords": [
|
|
23
19
|
"opencode",
|
|
24
20
|
"remote",
|
|
File without changes
|