three-blocks-login 0.0.4 → 0.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.
Files changed (2) hide show
  1. package/bin/login.js +36 -20
  2. package/package.json +12 -4
package/bin/login.js CHANGED
@@ -5,6 +5,10 @@
5
5
  import fs from "node:fs";
6
6
  import os from "node:os";
7
7
  import path from "node:path";
8
+ import { createRequire } from "node:module";
9
+
10
+ const require = createRequire(import.meta.url);
11
+ const pkg = require("../package.json");
8
12
 
9
13
  // Simple ANSI color helpers (no deps)
10
14
  const ESC = (n) => `\u001b[${n}m`;
@@ -15,7 +19,7 @@ const red = (s) => ESC(31) + s + reset;
15
19
  const green = (s) => ESC(32) + s + reset;
16
20
  const yellow = (s) => ESC(33) + s + reset;
17
21
  const cyan = (s) => ESC(36) + s + reset;
18
- const plainBanner = "[three-blocks-login]";
22
+ const plainBanner = `[three-blocks-login@${pkg.version}]`;
19
23
  const banner = bold(cyan(plainBanner));
20
24
 
21
25
  const args = parseArgs(process.argv.slice(2));
@@ -25,6 +29,8 @@ const SCOPE = (args.scope || "@three-blocks").replace(/^\s+|\s+$/g, "");
25
29
  const MODE = (args.mode || "env").toLowerCase(); // env | project | user
26
30
  const QUIET = !!args.quiet;
27
31
  const VERBOSE = !!args.verbose;
32
+ let CHANNEL = String(args.channel || process.env.THREE_BLOCKS_CHANNEL || "stable").toLowerCase();
33
+ if (!['stable','alpha','beta'].includes(CHANNEL)) CHANNEL = 'stable';
28
34
 
29
35
  // Load .env from current working directory (no deps)
30
36
  loadEnvFromDotfile(process.cwd());
@@ -35,7 +41,7 @@ const BROKER_URL =
35
41
  "http://localhost:3000/api/npm/token"; // your Astro broker endpoint
36
42
 
37
43
  const LICENSE =
38
- args.license || process.env.THREE_BLOCKS_SECRET_KEY || process.env.THREE_BLOCKS_LICENSE_KEY;
44
+ args.license || process.env.THREE_BLOCKS_SECRET_KEY;
39
45
 
40
46
  if (!LICENSE || String(LICENSE).trim() === "") {
41
47
  fail(
@@ -71,7 +77,7 @@ const log = {
71
77
 
72
78
  (async () => {
73
79
  try {
74
- const tokenData = await fetchToken(BROKER_URL, LICENSE_CLEAN);
80
+ const tokenData = await fetchToken(BROKER_URL, LICENSE_CLEAN, CHANNEL);
75
81
  const { registry, token, expiresAt } = tokenData;
76
82
 
77
83
  if (!registry || !token) fail("Broker response missing registry/token.");
@@ -98,6 +104,7 @@ const log = {
98
104
  `# scope: ${SCOPE} | registry: ${u.href} | expires: ${expiresAt ?? "unknown"}`,
99
105
  `export NPM_CONFIG_USERCONFIG="${tmpFile}"`,
100
106
  `export npm_config_userconfig="${tmpFile}"`,
107
+ `export THREE_BLOCKS_CHANNEL="${CHANNEL}"`,
101
108
  `echo "${plainBanner} ${SCOPE} -> ${u.href} (expires ${expiresAt ?? "unknown"})"`
102
109
  ];
103
110
  console.log(lines.join("\n"));
@@ -135,7 +142,7 @@ const log = {
135
142
  if (/ByteString/i.test(msg) || /character at index/i.test(msg)) {
136
143
  return fail("License appears malformed. Please copy your tb_… key exactly and retry.");
137
144
  }
138
- return fail("Request failed. Please try again. Use --verbose for details.");
145
+ return fail("Authentication failed. Please try again. Use --verbose for details.");
139
146
  }
140
147
  })();
141
148
 
@@ -149,30 +156,39 @@ function ensureTrailingSlash(url) {
149
156
 
150
157
  function loadEnvFromDotfile(dir) {
151
158
  try {
152
- const file = path.join(dir, ".env");
153
- if (!fs.existsSync(file)) return;
154
- const txt = fs.readFileSync(file, "utf8");
155
- for (const raw of txt.split(/\r?\n/)) {
156
- const line = raw.trim();
157
- if (!line || line.startsWith("#")) continue;
158
- const eq = line.indexOf("=");
159
- if (eq === -1) continue;
160
- const key = line.slice(0, eq).trim();
161
- let val = line.slice(eq + 1).trim();
162
- if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
163
- val = val.slice(1, -1);
159
+ const files = [path.join(dir, ".env.local"), path.join(dir, ".env")];
160
+ for (const file of files) {
161
+ if (!fs.existsSync(file)) continue;
162
+ const txt = fs.readFileSync(file, "utf8");
163
+ for (const raw of txt.split(/\r?\n/)) {
164
+ const line = raw.trim();
165
+ if (!line || line.startsWith("#")) continue;
166
+ const eq = line.indexOf("=");
167
+ if (eq === -1) continue;
168
+ const key = line.slice(0, eq).trim();
169
+ let val = line.slice(eq + 1).trim();
170
+ if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
171
+ val = val.slice(1, -1);
172
+ }
173
+ if (process.env[key] === undefined) process.env[key] = val;
164
174
  }
165
- if (process.env[key] === undefined) process.env[key] = val;
166
175
  }
167
176
  } catch {}
168
177
  }
169
178
 
170
- async function fetchToken(endpoint, license) {
171
- const res = await fetch(endpoint, {
179
+ async function fetchToken(endpoint, license, channel) {
180
+ let url = endpoint;
181
+ try {
182
+ const u = new URL(endpoint);
183
+ if (!u.searchParams.get('channel')) u.searchParams.set('channel', channel);
184
+ url = u.toString();
185
+ } catch {}
186
+ const res = await fetch(url, {
172
187
  method: "GET",
173
188
  headers: {
174
189
  "authorization": `Bearer ${license}`,
175
- "accept": "application/json"
190
+ "accept": "application/json",
191
+ "x-three-blocks-channel": channel
176
192
  }
177
193
  });
178
194
  if (!res.ok) {
package/package.json CHANGED
@@ -1,16 +1,24 @@
1
1
  {
2
2
  "name": "three-blocks-login",
3
- "version": "0.0.4",
3
+ "version": "0.1.1",
4
4
  "description": "Fetch a short-lived token from the three-blocks broker and configure npm for the current context.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "three-blocks-login": "bin/login.js"
8
8
  },
9
9
  "license": "MIT",
10
- "files": ["bin/"],
11
- "keywords": ["npm", "login", "three-blocks", "token", "ci"],
10
+ "files": [
11
+ "bin/"
12
+ ],
13
+ "keywords": [
14
+ "npm",
15
+ "login",
16
+ "three-blocks",
17
+ "token",
18
+ "ci"
19
+ ],
12
20
  "dependencies": {},
13
21
  "publishConfig": {
14
22
  "access": "public"
15
23
  }
16
- }
24
+ }