@ze-norm/cli 0.3.0 → 0.4.0
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/dist/api/client.d.ts +2 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +4 -0
- package/dist/auth/device-flow.d.ts.map +1 -1
- package/dist/auth/device-flow.js +25 -15
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +10 -6
- package/dist/config/defaults.d.ts +2 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +9 -1
- package/package.json +1 -1
package/dist/api/client.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export declare class ZenormClient {
|
|
|
13
13
|
constructor(opts?: ApiClientOptions);
|
|
14
14
|
private getHeaders;
|
|
15
15
|
private isLocalBaseUrl;
|
|
16
|
+
/** True when this client targets a localhost API (dev-bypass eligible). */
|
|
17
|
+
isLocalDevTarget(): boolean;
|
|
16
18
|
private request;
|
|
17
19
|
get<T>(path: string): Promise<T>;
|
|
18
20
|
post<T>(path: string, body?: unknown): Promise<T>;
|
package/dist/api/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0BD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAgB;gBAEjB,IAAI,CAAC,EAAE,gBAAgB;IAKnC,OAAO,CAAC,UAAU;IAqBlB,OAAO,CAAC,cAAc;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0BD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAgB;gBAEjB,IAAI,CAAC,EAAE,gBAAgB;IAKnC,OAAO,CAAC,UAAU;IAqBlB,OAAO,CAAC,cAAc;IAStB,2EAA2E;IAC3E,gBAAgB,IAAI,OAAO;YAIb,OAAO;IAwCf,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIjD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhD,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIlD,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAIzC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;CAG7C"}
|
package/dist/api/client.js
CHANGED
|
@@ -57,6 +57,10 @@ export class ZenormClient {
|
|
|
57
57
|
return false;
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
+
/** True when this client targets a localhost API (dev-bypass eligible). */
|
|
61
|
+
isLocalDevTarget() {
|
|
62
|
+
return this.isLocalBaseUrl();
|
|
63
|
+
}
|
|
60
64
|
async request(method, path, body) {
|
|
61
65
|
const url = `${this.baseUrl}${path}`;
|
|
62
66
|
const init = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device-flow.d.ts","sourceRoot":"","sources":["../../src/auth/device-flow.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"device-flow.d.ts","sourceRoot":"","sources":["../../src/auth/device-flow.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAuKpD;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAkDpE"}
|
package/dist/auth/device-flow.js
CHANGED
|
@@ -4,7 +4,27 @@ import { exec } from "node:child_process";
|
|
|
4
4
|
import { platform } from "node:os";
|
|
5
5
|
import { URL, URLSearchParams } from "node:url";
|
|
6
6
|
import { log } from "../util/logger.js";
|
|
7
|
-
import { PRODUCTION_CLERK_CLIENT_ID, PRODUCTION_CLERK_ISSUER, } from "../config/defaults.js";
|
|
7
|
+
import { CLI_CALLBACK_PORTS, PRODUCTION_CLERK_CLIENT_ID, PRODUCTION_CLERK_ISSUER, } from "../config/defaults.js";
|
|
8
|
+
/**
|
|
9
|
+
* Find the first pre-registered callback port that is free to bind. Clerk
|
|
10
|
+
* matches redirect_uris exactly, so the local listener must use one of the
|
|
11
|
+
* ports registered on the OAuth app — not a random OS-assigned port.
|
|
12
|
+
*/
|
|
13
|
+
async function pickFreeCallbackPort() {
|
|
14
|
+
for (const candidate of CLI_CALLBACK_PORTS) {
|
|
15
|
+
const free = await new Promise((resolve) => {
|
|
16
|
+
const srv = createServer();
|
|
17
|
+
srv.once("error", () => resolve(false));
|
|
18
|
+
srv.listen(candidate, "127.0.0.1", () => {
|
|
19
|
+
srv.close(() => resolve(true));
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
if (free)
|
|
23
|
+
return candidate;
|
|
24
|
+
}
|
|
25
|
+
throw new Error(`All CLI callback ports are in use (${CLI_CALLBACK_PORTS.join(", ")}). ` +
|
|
26
|
+
`Free one of them and run \`zenorm login\` again.`);
|
|
27
|
+
}
|
|
8
28
|
function getClerkIssuer() {
|
|
9
29
|
return process.env["ZENORM_CLERK_ISSUER"] ?? PRODUCTION_CLERK_ISSUER;
|
|
10
30
|
}
|
|
@@ -126,20 +146,10 @@ export async function runDeviceAuthFlow() {
|
|
|
126
146
|
const codeVerifier = generateCodeVerifier();
|
|
127
147
|
const codeChallenge = generateCodeChallenge(codeVerifier);
|
|
128
148
|
const state = generateState();
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const addr = srv.address();
|
|
134
|
-
if (!addr || typeof addr === "string") {
|
|
135
|
-
srv.close();
|
|
136
|
-
reject(new Error("Failed to get server address"));
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
const p = addr.port;
|
|
140
|
-
srv.close(() => resolve(p));
|
|
141
|
-
});
|
|
142
|
-
});
|
|
149
|
+
// Clerk enforces exact redirect_uri matching, so the callback must land on one
|
|
150
|
+
// of the OAuth app's pre-registered fixed ports — a random OS-assigned port
|
|
151
|
+
// would never match. Pick the first registered port that is currently free.
|
|
152
|
+
const port = await pickFreeCallbackPort();
|
|
143
153
|
const redirectUri = `http://localhost:${port}/callback`;
|
|
144
154
|
const authUrl = new URL(`${getClerkIssuer()}/oauth/authorize`);
|
|
145
155
|
authUrl.searchParams.set("response_type", "code");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAMA,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuChE"}
|
package/dist/commands/login.js
CHANGED
|
@@ -2,7 +2,6 @@ import { parseArgs } from "node:util";
|
|
|
2
2
|
import { runDeviceAuthFlow } from "../auth/device-flow.js";
|
|
3
3
|
import { saveCredentials } from "../auth/store.js";
|
|
4
4
|
import { ZenormClient } from "../api/client.js";
|
|
5
|
-
import { AuthError } from "../util/errors.js";
|
|
6
5
|
import { log } from "../util/logger.js";
|
|
7
6
|
export async function loginCommand(argv) {
|
|
8
7
|
const { values } = parseArgs({
|
|
@@ -39,15 +38,20 @@ export async function loginCommand(argv) {
|
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
40
|
async function tryLocalDevelopmentLogin() {
|
|
41
|
+
const client = new ZenormClient();
|
|
42
|
+
// Only localhost targets use the dev-bypass header path. For hosted/prod APIs
|
|
43
|
+
// we must always run the real OAuth flow — never silently report a successful
|
|
44
|
+
// "local development mode" login against production.
|
|
45
|
+
if (!client.isLocalDevTarget()) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
42
48
|
try {
|
|
43
|
-
const client = new ZenormClient();
|
|
44
49
|
const ctx = await client.getAuthContext();
|
|
45
50
|
return { userId: ctx.userId, orgId: ctx.orgId };
|
|
46
51
|
}
|
|
47
|
-
catch
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
52
|
+
catch {
|
|
53
|
+
// Local API unreachable or rejected the dev headers — fall through to the
|
|
54
|
+
// browser OAuth flow rather than masking the failure.
|
|
51
55
|
return null;
|
|
52
56
|
}
|
|
53
57
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare const PRODUCTION_API_URL = "https://api.zenorm.com";
|
|
2
2
|
export declare const PRODUCTION_CLERK_ISSUER = "https://clerk.zenorm.com";
|
|
3
|
-
export declare const PRODUCTION_CLERK_CLIENT_ID = "
|
|
3
|
+
export declare const PRODUCTION_CLERK_CLIENT_ID = "nUFCpxIFWJ4YSB3A";
|
|
4
|
+
export declare const CLI_CALLBACK_PORTS: readonly [4571, 4572, 4573];
|
|
4
5
|
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,2BAA2B,CAAC;AAC3D,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,2BAA2B,CAAC;AAC3D,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAKlE,eAAO,MAAM,0BAA0B,qBAAqB,CAAC;AAK7D,eAAO,MAAM,kBAAkB,6BAA8B,CAAC"}
|
package/dist/config/defaults.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
export const PRODUCTION_API_URL = "https://api.zenorm.com";
|
|
2
2
|
export const PRODUCTION_CLERK_ISSUER = "https://clerk.zenorm.com";
|
|
3
|
-
|
|
3
|
+
// Clerk OAuth Application client id for the public CLI (prod instance
|
|
4
|
+
// clerk.zenorm.com). NOT the publishable key — this is the OAuth 2.0 client id
|
|
5
|
+
// from the "ZeNorm CLI" OAuth app. Its registered redirect_uris are the fixed
|
|
6
|
+
// localhost callback ports in CLI_CALLBACK_PORTS below.
|
|
7
|
+
export const PRODUCTION_CLERK_CLIENT_ID = "nUFCpxIFWJ4YSB3A";
|
|
8
|
+
// Fixed localhost callback ports the device-auth flow binds, in order. Clerk
|
|
9
|
+
// enforces exact redirect_uri matching, so these MUST stay in sync with the
|
|
10
|
+
// OAuth app's pre-registered redirect_uris (http://localhost:<port>/callback).
|
|
11
|
+
export const CLI_CALLBACK_PORTS = [4571, 4572, 4573];
|