@nzila/sdk 0.1.1 → 0.1.4

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/README.md CHANGED
@@ -11,6 +11,35 @@ npm install @nzila/sdk
11
11
  # Vitest projects also need vitest as a peer
12
12
  ```
13
13
 
14
+ ### TypeScript
15
+
16
+ Subpaths such as `@nzila/sdk/vitest` need **`moduleResolution`** set to **`bundler`**, **`node16`**, or **`nodenext`** (recommended for Vitest/Vite repos). If you still use legacy `"node"` resolution, upgrade to one of those options in `tsconfig.json`:
17
+
18
+ ```json
19
+ {
20
+ "compilerOptions": {
21
+ "moduleResolution": "bundler"
22
+ }
23
+ }
24
+ ```
25
+
26
+ `@nzila/sdk@0.1.4+` also ships root `.d.ts` shims and `typesVersions` for broader editor support.
27
+
28
+ ## CLI (onboarding)
29
+
30
+ `npx @nzila/sdk` opens the [Nzila dashboard](https://nzila-kappa.vercel.app) and prints setup commands. No separate CLI package.
31
+
32
+ ```bash
33
+ npx @nzila/sdk # open app + help
34
+ npx @nzila/sdk login
35
+ npx @nzila/sdk link --api-key <key> --project-id <uuid>
36
+ npx @nzila/sdk doctor
37
+ ```
38
+
39
+ Also available as `npx nzila` after install. Override platform with `NZILA_APP_URL` or `--endpoint`.
40
+
41
+ After you sign in on [nzila-kappa.vercel.app](https://nzila-kappa.vercel.app), the dashboard runs a **first-visit tour** per section (localized). Use **Guide** in the header to replay.
42
+
14
43
  ## Exports
15
44
 
16
45
  | Path | Purpose |
@@ -0,0 +1,13 @@
1
+ /** Hosted Nzila dashboard — override with NZILA_APP_URL or --endpoint */
2
+ export declare const NZILA_PLATFORM_URL = "https://nzila-kappa.vercel.app";
3
+ export declare function resolvePlatformUrl(): string;
4
+ export declare function platformPaths(base: string): {
5
+ home: string;
6
+ login: string;
7
+ register: string;
8
+ docs: string;
9
+ keys: string;
10
+ webhook: string;
11
+ signals: string;
12
+ };
13
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/cli/constants.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,eAAO,MAAM,kBAAkB,mCAAmC,CAAC;AAEnE,wBAAgB,kBAAkB,IAAI,MAAM,CAM3C;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM;;;;;;;;EAWzC"}
@@ -0,0 +1,20 @@
1
+ /** Hosted Nzila dashboard — override with NZILA_APP_URL or --endpoint */
2
+ export const NZILA_PLATFORM_URL = "https://nzila-kappa.vercel.app";
3
+ export function resolvePlatformUrl() {
4
+ const raw = process.env.NZILA_APP_URL?.trim() ||
5
+ process.env.NZILA_ENDPOINT?.trim() ||
6
+ NZILA_PLATFORM_URL;
7
+ return raw.replace(/\/$/, "");
8
+ }
9
+ export function platformPaths(base) {
10
+ const root = base.replace(/\/$/, "");
11
+ return {
12
+ home: `${root}/en`,
13
+ login: `${root}/en/login`,
14
+ register: `${root}/en/register`,
15
+ docs: `${root}/en/docs`,
16
+ keys: `${root}/en/keys`,
17
+ webhook: `${root}/api/webhooks/tests`,
18
+ signals: `${root}/api/signals/runtime`,
19
+ };
20
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":""}
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env node
2
+ import { readFile, writeFile } from "node:fs/promises";
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ import path from "node:path";
5
+ import { platformPaths, resolvePlatformUrl } from "./constants.js";
6
+ import { openBrowser } from "./open-browser.js";
7
+ const PKG = "@nzila/sdk";
8
+ const CONFIG_FILE = "nzila.config.ts";
9
+ function defaultEndpoint() {
10
+ return resolvePlatformUrl();
11
+ }
12
+ async function loadConfig(cwd) {
13
+ const file = path.join(cwd, CONFIG_FILE);
14
+ if (!existsSync(file))
15
+ return null;
16
+ const source = await readFile(file, "utf8");
17
+ const match = source.match(/apiKey:\s*["']([^"']+)["']/);
18
+ const projectMatch = source.match(/projectId:\s*["']([^"']+)["']/);
19
+ const endpointMatch = source.match(/endpoint:\s*["']([^"']+)["']/);
20
+ const frameworkMatch = source.match(/framework:\s*["']([^"']+)["']/);
21
+ if (!match?.[1] || !projectMatch?.[1])
22
+ return null;
23
+ return {
24
+ apiKey: match[1],
25
+ projectId: projectMatch[1],
26
+ endpoint: endpointMatch?.[1] ?? defaultEndpoint(),
27
+ framework: frameworkMatch?.[1] ?? "vitest",
28
+ };
29
+ }
30
+ async function writeConfig(cwd, config) {
31
+ const body = `/** Generated by ${PKG} — do not commit secrets to public repos */
32
+ export default {
33
+ apiKey: "${config.apiKey}",
34
+ projectId: "${config.projectId}",
35
+ endpoint: "${config.endpoint.replace(/"/g, '\\"')}",
36
+ framework: "${config.framework}",
37
+ } as const;
38
+ `;
39
+ await writeFile(path.join(cwd, CONFIG_FILE), body, "utf8");
40
+ }
41
+ function detectFramework(cwd) {
42
+ const pkgPath = path.join(cwd, "package.json");
43
+ if (existsSync(pkgPath)) {
44
+ try {
45
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
46
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
47
+ if (deps["@playwright/test"] || deps.playwright)
48
+ return "playwright";
49
+ if (deps.jest)
50
+ return "jest";
51
+ if (deps.vitest)
52
+ return "vitest";
53
+ }
54
+ catch {
55
+ /* fall through */
56
+ }
57
+ }
58
+ if (existsSync(path.join(cwd, "vitest.config.ts")) || existsSync(path.join(cwd, "vitest.config.mts"))) {
59
+ return "vitest";
60
+ }
61
+ if (existsSync(path.join(cwd, "jest.config.js")) || existsSync(path.join(cwd, "jest.config.ts"))) {
62
+ return "jest";
63
+ }
64
+ if (existsSync(path.join(cwd, "playwright.config.ts")))
65
+ return "playwright";
66
+ return "vitest";
67
+ }
68
+ function printEnvSnippet(endpoint) {
69
+ const paths = platformPaths(endpoint);
70
+ console.log("");
71
+ console.log("Add to your project .env.local:");
72
+ console.log(`NZILA_WEBHOOK_URL=${paths.webhook}`);
73
+ console.log(`NZILA_SIGNALS_URL=${paths.signals}`);
74
+ console.log("NZILA_API_KEY=<from dashboard → API Keys>");
75
+ console.log("");
76
+ console.log(`SDK already installed via ${PKG}; add Vitest reporter from docs.`);
77
+ console.log(`Docs: ${paths.docs}`);
78
+ }
79
+ async function tryOpen(url, quiet = false) {
80
+ try {
81
+ await openBrowser(url);
82
+ if (!quiet)
83
+ console.log(`Opened ${url}`);
84
+ }
85
+ catch {
86
+ if (!quiet)
87
+ console.log(`Open in your browser: ${url}`);
88
+ }
89
+ }
90
+ async function cmdOpen(flags) {
91
+ const base = String(flags.endpoint ?? defaultEndpoint()).replace(/\/$/, "");
92
+ const paths = platformPaths(base);
93
+ const target = flags.register ? paths.register : flags.login ? paths.login : paths.home;
94
+ await tryOpen(target);
95
+ }
96
+ async function cmdInit(flags) {
97
+ const cwd = process.cwd();
98
+ const framework = detectFramework(cwd);
99
+ const base = defaultEndpoint();
100
+ const paths = platformPaths(base);
101
+ console.log(`Nzila — platform: ${base}`);
102
+ console.log(`Detected test framework: ${framework}`);
103
+ console.log("");
104
+ console.log("Quick start:");
105
+ console.log(` 1. npx ${PKG} login → sign in (opens browser)`);
106
+ console.log(" 2. Create a project + API key in the dashboard");
107
+ console.log(` 3. npx ${PKG} link --api-key nzl_… --project-id <uuid>`);
108
+ console.log(" 4. Wire @nzila/sdk/vitest and run tests");
109
+ printEnvSnippet(base);
110
+ if (flags.open !== false) {
111
+ await tryOpen(paths.register, true);
112
+ }
113
+ }
114
+ async function cmdLogin(flags) {
115
+ const base = String(flags.endpoint ?? defaultEndpoint()).replace(/\/$/, "");
116
+ const loginUrl = `${platformPaths(base).login}?cli=1`;
117
+ console.log(`Nzila platform: ${base}`);
118
+ console.log("Sign in, then create an API key:");
119
+ console.log(` ${platformPaths(base).keys}`);
120
+ console.log("");
121
+ console.log("Then link this repo:");
122
+ console.log(` npx ${PKG} link --api-key <key> --project-id <uuid>`);
123
+ await tryOpen(loginUrl);
124
+ }
125
+ async function cmdLink(flags) {
126
+ const apiKey = String(flags["api-key"] ?? flags.apiKey ?? "");
127
+ const projectId = String(flags["project-id"] ?? flags.projectId ?? "");
128
+ const endpoint = String(flags.endpoint ?? defaultEndpoint()).replace(/\/$/, "");
129
+ if (!apiKey || !projectId) {
130
+ console.error(`Usage: npx ${PKG} link --api-key <token> --project-id <uuid> [--endpoint <url>]`);
131
+ process.exit(1);
132
+ }
133
+ const cwd = process.cwd();
134
+ const framework = detectFramework(cwd);
135
+ await writeConfig(cwd, { apiKey, projectId, endpoint, framework });
136
+ console.log(`Wrote ${CONFIG_FILE} (endpoint: ${endpoint})`);
137
+ printEnvSnippet(endpoint);
138
+ }
139
+ async function cmdDoctor() {
140
+ const cwd = process.cwd();
141
+ const config = await loadConfig(cwd);
142
+ if (!config) {
143
+ console.log(`No nzila.config.ts — run \`npx ${PKG} link\` first.`);
144
+ process.exit(1);
145
+ }
146
+ const paths = platformPaths(config.endpoint);
147
+ console.log("Config OK:", {
148
+ projectId: config.projectId,
149
+ endpoint: config.endpoint,
150
+ framework: config.framework,
151
+ });
152
+ console.log("Webhook URL:", paths.webhook);
153
+ }
154
+ function printHelp(base) {
155
+ const paths = platformPaths(base);
156
+ console.log(`Nzila (${PKG}) — ${base}
157
+
158
+ Commands:
159
+ open Open the dashboard in your browser (default)
160
+ init Detect framework + show setup steps
161
+ login Open sign-in and linking instructions
162
+ link Write nzila.config.ts (--api-key, --project-id)
163
+ doctor Validate nzila.config.ts
164
+
165
+ Examples:
166
+ npx ${PKG}
167
+ npx ${PKG} login
168
+ npx ${PKG} link --api-key nzl_… --project-id <uuid>
169
+
170
+ Docs: ${paths.docs}
171
+ `);
172
+ }
173
+ function parseArgs(argv) {
174
+ const [command, ...rest] = argv;
175
+ const flags = {};
176
+ for (let i = 0; i < rest.length; i++) {
177
+ const token = rest[i];
178
+ if (token.startsWith("--")) {
179
+ const key = token.slice(2);
180
+ const next = rest[i + 1];
181
+ if (next && !next.startsWith("--")) {
182
+ flags[key] = next;
183
+ i++;
184
+ }
185
+ else {
186
+ flags[key] = true;
187
+ }
188
+ }
189
+ }
190
+ return { command: command ?? "", flags };
191
+ }
192
+ async function main() {
193
+ const { command, flags } = parseArgs(process.argv.slice(2));
194
+ const base = defaultEndpoint();
195
+ if (!command || command === "open" || command === "start") {
196
+ if (!command)
197
+ await tryOpen(platformPaths(base).home);
198
+ else
199
+ await cmdOpen(flags);
200
+ if (!command)
201
+ printHelp(base);
202
+ return;
203
+ }
204
+ if (command === "init")
205
+ return cmdInit(flags);
206
+ if (command === "login")
207
+ return cmdLogin(flags);
208
+ if (command === "link")
209
+ return cmdLink(flags);
210
+ if (command === "doctor")
211
+ return cmdDoctor();
212
+ if (command === "help" || command === "-h" || command === "--help") {
213
+ printHelp(base);
214
+ return;
215
+ }
216
+ console.error(`Unknown command: ${command}`);
217
+ printHelp(base);
218
+ process.exit(1);
219
+ }
220
+ main().catch((err) => {
221
+ console.error(err instanceof Error ? err.message : err);
222
+ process.exit(1);
223
+ });
@@ -0,0 +1,2 @@
1
+ export declare function openBrowser(url: string): Promise<void>;
2
+ //# sourceMappingURL=open-browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-browser.d.ts","sourceRoot":"","sources":["../../src/cli/open-browser.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBtD"}
@@ -0,0 +1,26 @@
1
+ import { execFile } from "node:child_process";
2
+ export function openBrowser(url) {
3
+ return new Promise((resolve, reject) => {
4
+ const platform = process.platform;
5
+ let command;
6
+ let args;
7
+ if (platform === "win32") {
8
+ command = "cmd";
9
+ args = ["/c", "start", "", url];
10
+ }
11
+ else if (platform === "darwin") {
12
+ command = "open";
13
+ args = [url];
14
+ }
15
+ else {
16
+ command = "xdg-open";
17
+ args = [url];
18
+ }
19
+ execFile(command, args, (err) => {
20
+ if (err)
21
+ reject(err);
22
+ else
23
+ resolve();
24
+ });
25
+ });
26
+ }
package/jest.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { default } from "./dist/jest-reporter.js";
2
+ export * from "./dist/jest-reporter.js";
package/mocha.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { default } from "./dist/mocha-reporter.js";
2
+ export * from "./dist/mocha-reporter.js";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nzila/sdk",
3
- "version": "0.1.1",
4
- "description": "Send test runs to Nzila and trace live feature errors (Vitest, Jest, Mocha, React, Node).",
3
+ "version": "0.1.4",
4
+ "description": "Send test runs to Nzila, trace live feature errors, and onboard via npx @nzila/sdk.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -14,35 +14,57 @@
14
14
  },
15
15
  "files": [
16
16
  "dist",
17
+ "vitest.d.ts",
18
+ "jest.d.ts",
19
+ "mocha.d.ts",
20
+ "runtime.d.ts",
21
+ "react.d.ts",
17
22
  "README.md",
18
23
  "examples"
19
24
  ],
25
+ "typesVersions": {
26
+ "*": {
27
+ "vitest": ["./dist/vitest-reporter.d.ts"],
28
+ "jest": ["./dist/jest-reporter.d.ts"],
29
+ "mocha": ["./dist/mocha-reporter.d.ts"],
30
+ "runtime": ["./dist/runtime/index.d.ts"],
31
+ "react": ["./dist/react/index.d.ts"]
32
+ }
33
+ },
20
34
  "main": "./dist/index.js",
21
35
  "types": "./dist/index.d.ts",
36
+ "bin": {
37
+ "nzila": "dist/cli/main.js"
38
+ },
22
39
  "exports": {
23
40
  ".": {
24
41
  "types": "./dist/index.d.ts",
25
42
  "import": "./dist/index.js"
26
43
  },
27
44
  "./vitest": {
28
- "types": "./dist/vitest-reporter.d.ts",
29
- "import": "./dist/vitest-reporter.js"
45
+ "types": "./vitest.d.ts",
46
+ "import": "./dist/vitest-reporter.js",
47
+ "default": "./dist/vitest-reporter.js"
30
48
  },
31
49
  "./jest": {
32
- "types": "./dist/jest-reporter.d.ts",
33
- "import": "./dist/jest-reporter.js"
50
+ "types": "./jest.d.ts",
51
+ "import": "./dist/jest-reporter.js",
52
+ "default": "./dist/jest-reporter.js"
34
53
  },
35
54
  "./mocha": {
36
- "types": "./dist/mocha-reporter.d.ts",
37
- "import": "./dist/mocha-reporter.js"
55
+ "types": "./mocha.d.ts",
56
+ "import": "./dist/mocha-reporter.js",
57
+ "default": "./dist/mocha-reporter.js"
38
58
  },
39
59
  "./runtime": {
40
- "types": "./dist/runtime/index.d.ts",
41
- "import": "./dist/runtime/index.js"
60
+ "types": "./runtime.d.ts",
61
+ "import": "./dist/runtime/index.js",
62
+ "default": "./dist/runtime/index.js"
42
63
  },
43
64
  "./react": {
44
- "types": "./dist/react/index.d.ts",
45
- "import": "./dist/react/index.js"
65
+ "types": "./react.d.ts",
66
+ "import": "./dist/react/index.js",
67
+ "default": "./dist/react/index.js"
46
68
  }
47
69
  },
48
70
  "scripts": {
package/react.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./dist/react/index.js";
package/runtime.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./dist/runtime/index.js";
package/vitest.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { default } from "./dist/vitest-reporter.js";
2
+ export * from "./dist/vitest-reporter.js";