poe-code 3.0.300 → 3.0.301

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poe-code",
3
- "version": "3.0.300",
3
+ "version": "3.0.301",
4
4
  "description": "CLI tool to configure Poe API for developer workflows.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -42,6 +42,9 @@ function parsePort(value) {
42
42
  if (value === undefined) {
43
43
  return 0;
44
44
  }
45
+ if (!isDecimalInteger(value)) {
46
+ throw new Error("--port must be an integer between 0 and 65535.");
47
+ }
45
48
  const port = Number(value);
46
49
  if (!Number.isInteger(port) || port < 0 || port > 65535) {
47
50
  throw new Error("--port must be an integer between 0 and 65535.");
@@ -52,12 +55,18 @@ function parsePositiveInteger(value, flagName) {
52
55
  if (value === undefined) {
53
56
  return 60;
54
57
  }
58
+ if (!isDecimalInteger(value)) {
59
+ throw new Error(`${flagName} must be a positive integer.`);
60
+ }
55
61
  const parsed = Number(value);
56
62
  if (!Number.isInteger(parsed) || parsed <= 0) {
57
63
  throw new Error(`${flagName} must be a positive integer.`);
58
64
  }
59
65
  return parsed;
60
66
  }
67
+ function isDecimalInteger(value) {
68
+ return value.length > 0 && [...value].every((character) => character >= "0" && character <= "9");
69
+ }
61
70
  function parseAbsoluteUrl(value, flagName) {
62
71
  if (value === undefined) {
63
72
  return undefined;
@@ -88,8 +97,10 @@ function parseScopes(value) {
88
97
  }
89
98
  const scopes = value
90
99
  .split(",")
91
- .map((scope) => scope.trim())
92
- .filter((scope) => scope.length > 0);
100
+ .map((scope) => scope.trim());
101
+ if (scopes.some((scope) => scope.length === 0)) {
102
+ throw new Error("--scopes must not contain empty entries.");
103
+ }
93
104
  if (scopes.length === 0) {
94
105
  throw new Error("--scopes must include at least one non-empty scope.");
95
106
  }
@@ -178,20 +189,27 @@ export async function runCli(args = process.argv.slice(2), dependencies = {}) {
178
189
  port: parsed.port,
179
190
  hostname: parsed.hostname,
180
191
  };
181
- const server = createMcpOAuthTestServer(serverOptions);
182
- const handle = await server.listen(listenOptions);
183
- stdout.write(`${packageInfo.name} ${packageInfo.version}\n`);
184
- stdout.write(`MCP URL: ${handle.mcpUrl}\n`);
185
- stdout.write(`PRM URL: ${handle.prmUrl}\n`);
186
- stdout.write(`AS issuer: ${handle.oauth.issuer}\n`);
187
- stdout.write(`Resource: ${handle.resource}\n`);
188
- if (parsed.printTestToken) {
189
- const token = await handle.oauth.issueTokenFor({
190
- clientId: "demo-client",
191
- resource: handle.resource,
192
- scopes: parsed.scopes ?? ["mcp.read"],
193
- });
194
- stdout.write(`Test bearer token: ${token}\n`);
192
+ let handle;
193
+ try {
194
+ const server = createMcpOAuthTestServer(serverOptions);
195
+ handle = await server.listen(listenOptions);
196
+ stdout.write(`${packageInfo.name} ${packageInfo.version}\n`);
197
+ stdout.write(`MCP URL: ${handle.mcpUrl}\n`);
198
+ stdout.write(`PRM URL: ${handle.prmUrl}\n`);
199
+ stdout.write(`AS issuer: ${handle.oauth.issuer}\n`);
200
+ stdout.write(`Resource: ${handle.resource}\n`);
201
+ if (parsed.printTestToken) {
202
+ const token = await handle.oauth.issueTokenFor({
203
+ clientId: "demo-client",
204
+ resource: handle.resource,
205
+ scopes: parsed.scopes ?? ["mcp.read"],
206
+ });
207
+ stdout.write(`Test bearer token: ${token}\n`);
208
+ }
209
+ }
210
+ catch (error) {
211
+ stderr.write(`${error instanceof Error ? error.message : String(error)}\n\n${HELP_TEXT}\n`);
212
+ return 1;
195
213
  }
196
214
  await (dependencies.waitForShutdown ?? waitForShutdown)(handle.close);
197
215
  return 0;
@@ -85,6 +85,9 @@ function normalizeScopes(scopes) {
85
85
  if (normalizedScopes.some((scope) => scope.trim().length === 0)) {
86
86
  throw new Error("scopes must contain non-empty values");
87
87
  }
88
+ if (normalizedScopes.some((scope) => scope.trim() !== scope || scope.includes(" "))) {
89
+ throw new Error("scope entries must not contain spaces");
90
+ }
88
91
  return normalizedScopes;
89
92
  }
90
93
  function normalizeTtlSeconds(ttlSeconds) {
@@ -94,6 +97,13 @@ function normalizeTtlSeconds(ttlSeconds) {
94
97
  }
95
98
  return normalizedTtlSeconds;
96
99
  }
100
+ function normalizeListenPort(port) {
101
+ const normalizedPort = port ?? 0;
102
+ if (!Number.isInteger(normalizedPort) || normalizedPort < 0 || normalizedPort > 65535) {
103
+ throw new Error("port must be an integer between 0 and 65535");
104
+ }
105
+ return normalizedPort;
106
+ }
97
107
  function closeServer(server) {
98
108
  return new Promise((resolve, reject) => {
99
109
  server.close((error) => {
@@ -135,9 +145,9 @@ export function createMcpOAuthTestServer(options = {}) {
135
145
  if (currentHandle !== null || listenPending) {
136
146
  throw new Error("MCP OAuth test server is already listening");
137
147
  }
138
- listenPending = true;
139
148
  const hostname = listenOptions.hostname ?? "127.0.0.1";
140
- const requestedPort = listenOptions.port ?? 0;
149
+ const requestedPort = normalizeListenPort(listenOptions.port);
150
+ listenPending = true;
141
151
  let lastError;
142
152
  for (let attempt = 0; attempt < 10; attempt += 1) {
143
153
  try {