channel-worker 1.0.33 → 1.1.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/bin/cli.js CHANGED
@@ -37,35 +37,88 @@ function saveConfig(config) {
37
37
  const args = parseArgs(process.argv.slice(2));
38
38
  const cmd = args._cmd || 'start';
39
39
 
40
- if (cmd === 'init') {
40
+ if (cmd === 'pair') {
41
+ // Pair with dashboard using one-time code
42
+ const code = args.code;
43
+ const apiUrl = args.api || 'https://api.channel.tunasm.art';
44
+ const nstKey = args['nst-key'] || '';
45
+ const extensionPath = args.extension || '';
46
+ const maxConcurrent = parseInt(args.concurrent || '2', 10);
47
+
48
+ if (!code) {
49
+ console.error('[channel-worker] Error: --code required. Get a pairing code from the dashboard.');
50
+ process.exit(1);
51
+ }
52
+
53
+ (async () => {
54
+ try {
55
+ console.log(`[channel-worker] Pairing with code: ${code}`);
56
+ const res = await fetch(`${apiUrl}/workers/pair`, {
57
+ method: 'POST',
58
+ headers: { 'Content-Type': 'application/json' },
59
+ body: JSON.stringify({
60
+ code,
61
+ ip_address: getLocalIP(),
62
+ max_concurrent: maxConcurrent,
63
+ }),
64
+ });
65
+ const json = await res.json();
66
+
67
+ if (!json.success) {
68
+ console.error(`[channel-worker] Pairing failed: ${json.message}`);
69
+ process.exit(1);
70
+ }
71
+
72
+ const config = {
73
+ worker_id: json.data.worker_id,
74
+ worker_token: json.data.worker_token,
75
+ api_url: apiUrl,
76
+ max_concurrent: maxConcurrent,
77
+ nst_api_key: nstKey,
78
+ extension_path: extensionPath,
79
+ };
80
+ saveConfig(config);
81
+
82
+ console.log(`[channel-worker] Paired successfully!`);
83
+ console.log(` Worker ID: ${config.worker_id}`);
84
+ console.log(` Config saved to: ${CONFIG_FILE}`);
85
+ console.log(`\nRun: channel-worker start`);
86
+ } catch (err) {
87
+ console.error(`[channel-worker] Error: ${err.message}`);
88
+ process.exit(1);
89
+ }
90
+ })();
91
+
92
+ } else if (cmd === 'init') {
41
93
  const config = {
42
94
  worker_id: args.id || `worker-${os.hostname()}`,
43
95
  api_url: args.api || 'http://localhost:3001',
44
96
  max_concurrent: parseInt(args.concurrent || '2', 10),
45
97
  nst_api_key: args['nst-key'] || '',
46
98
  extension_path: args.extension || '',
99
+ worker_token: args.token || '',
47
100
  };
48
101
  saveConfig(config);
49
102
  console.log(`[channel-worker] Config saved to ${CONFIG_FILE}`);
50
103
  console.log(JSON.stringify(config, null, 2));
51
104
  console.log('\nRun: channel-worker start');
52
105
  process.exit(0);
53
- }
54
106
 
55
- if (cmd === 'start') {
107
+ } else if (cmd === 'start') {
56
108
  // Merge CLI args over saved config
57
109
  const saved = loadConfig();
58
110
  const config = {
59
111
  worker_id: args.id || saved.worker_id || `worker-${os.hostname()}`,
60
- api_url: args.api || saved.api_url || 'http://localhost:3001',
112
+ api_url: args.api || saved.api_url || 'https://api.channel.tunasm.art',
61
113
  max_concurrent: parseInt(args.concurrent || saved.max_concurrent || '2', 10),
62
114
  nst_api_key: args['nst-key'] || saved.nst_api_key || '',
63
115
  extension_path: args.extension || saved.extension_path || '',
116
+ worker_token: args.token || saved.worker_token || '',
64
117
  verbose: !!args.verbose,
65
118
  };
66
119
 
67
- if (!config.worker_id) {
68
- console.error('[channel-worker] Error: --id required. Run: channel-worker init --id <name> --api <url>');
120
+ if (!config.worker_token) {
121
+ console.error('[channel-worker] Error: No worker token. Run: channel-worker pair --code <CODE> --api <URL>');
69
122
  process.exit(1);
70
123
  }
71
124
 
@@ -78,28 +131,44 @@ if (cmd === 'start') {
78
131
 
79
132
  } else if (cmd === 'config') {
80
133
  const config = loadConfig();
81
- console.log(JSON.stringify(config, null, 2));
134
+ // Hide token in display
135
+ const display = { ...config };
136
+ if (display.worker_token) display.worker_token = display.worker_token.slice(0, 8) + '...';
137
+ console.log(JSON.stringify(display, null, 2));
82
138
 
83
139
  } else {
84
140
  console.log(`
85
141
  channel-worker — Channel Manager worker daemon
86
142
 
87
143
  Commands:
88
- init Configure worker (saves to ~/.channel-worker/config.json)
144
+ pair Pair with dashboard using a one-time code (recommended)
145
+ init Configure worker manually
89
146
  start Start the daemon
90
147
  config Show current config
91
148
 
149
+ Pairing (recommended):
150
+ channel-worker pair --code <CODE> --api <URL>
151
+
92
152
  Options:
93
- --id <name> Worker ID (unique name)
94
- --api <url> Dashboard API URL (http://host:3001)
95
- --concurrent <n> Max concurrent browser instances (default: 2)
153
+ --code <code> Pairing code from dashboard (for pair command)
154
+ --api <url> API URL (default: https://api.channel.tunasm.art)
155
+ --concurrent <n> Max concurrent browsers (default: 2)
96
156
  --nst-key <key> Nstbrowser API key
97
157
  --extension <path> Path to content-creator extension
98
158
  --verbose Enable verbose logging
99
159
 
100
160
  Examples:
101
- channel-worker init --id win-worker --api http://192.168.1.52:3001
161
+ channel-worker pair --code A3F1B2 --api https://api.channel.tunasm.art
102
162
  channel-worker start
103
- channel-worker start --id win-worker --api http://192.168.1.52:3001
104
163
  `);
105
164
  }
165
+
166
+ function getLocalIP() {
167
+ const interfaces = os.networkInterfaces();
168
+ for (const name of Object.keys(interfaces)) {
169
+ for (const iface of interfaces[name]) {
170
+ if (iface.family === 'IPv4' && !iface.internal) return iface.address;
171
+ }
172
+ }
173
+ return '127.0.0.1';
174
+ }
package/lib/api-client.js CHANGED
@@ -1,13 +1,17 @@
1
1
  class ApiClient {
2
- constructor(baseUrl) {
2
+ constructor(baseUrl, workerToken) {
3
3
  this.baseUrl = baseUrl.replace(/\/$/, '');
4
+ this.workerToken = workerToken || '';
4
5
  }
5
6
 
6
7
  async request(method, path, body = null) {
7
8
  const url = `${this.baseUrl}${path}`;
8
9
  const options = {
9
10
  method,
10
- headers: { 'Content-Type': 'application/json' },
11
+ headers: {
12
+ 'Content-Type': 'application/json',
13
+ 'x-worker-token': this.workerToken,
14
+ },
11
15
  };
12
16
  if (body) options.body = JSON.stringify(body);
13
17
 
@@ -117,6 +117,7 @@ class CommandPoller {
117
117
  fs.writeFileSync(path.join(uniqueExtPath, 'config.json'), JSON.stringify({
118
118
  channelManagerApi: 'https://api.channel.tunasm.art',
119
119
  profileId: profile_id,
120
+ workerToken: this.config.worker_token || '',
120
121
  }));
121
122
  extensionPath = uniqueExtPath;
122
123
  console.log(`[commands] Extension dir: ${uniqueExtPath}`);
package/lib/daemon.js CHANGED
@@ -7,7 +7,7 @@ const os = require('os');
7
7
  class Daemon {
8
8
  constructor(config) {
9
9
  this.config = config;
10
- this.api = new ApiClient(config.api_url);
10
+ this.api = new ApiClient(config.api_url, config.worker_token);
11
11
  this.heartbeat = new Heartbeat(this.api, config.worker_id);
12
12
  this.poller = new JobPoller(this.api, config);
13
13
  this.commandPoller = new CommandPoller(this.api, config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "channel-worker",
3
- "version": "1.0.33",
3
+ "version": "1.1.1",
4
4
  "description": "Channel Manager worker daemon — runs on remote machines to execute video pipeline jobs",
5
5
  "main": "lib/daemon.js",
6
6
  "bin": {