@nzila/sdk 0.1.0 → 0.1.3
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 +27 -1
- package/dist/cli/constants.d.ts +13 -0
- package/dist/cli/constants.d.ts.map +1 -0
- package/dist/cli/constants.js +20 -0
- package/dist/cli/main.d.ts +3 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +223 -0
- package/dist/cli/open-browser.d.ts +2 -0
- package/dist/cli/open-browser.d.ts.map +1 -0
- package/dist/cli/open-browser.js +26 -0
- package/examples/COMPLEX-USAGE.md +113 -0
- package/examples/INDEX.md +27 -0
- package/examples/README.md +94 -0
- package/examples/RUNTIME-TRACE.md +222 -0
- package/examples/TRACING-FAILURES.md +186 -0
- package/examples/backend/error-tracing.test.ts +44 -0
- package/examples/backend/order-pricing.test.ts +54 -0
- package/examples/backend/order-pricing.ts +27 -0
- package/examples/backend/runtime-trace.example.ts +31 -0
- package/examples/backend/sample-payload.json +62 -0
- package/examples/backend/sample-tracing-payload.json +90 -0
- package/examples/complex/api-services.demo.ts +72 -0
- package/examples/complex/full-platform.demo.test.ts +46 -0
- package/examples/frontend/checkout-form.test.ts +54 -0
- package/examples/frontend/checkout-form.ts +29 -0
- package/examples/frontend/error-tracing.test.ts +59 -0
- package/examples/frontend/sample-payload.json +62 -0
- package/examples/frontend/sample-tracing-payload.json +73 -0
- package/examples/frontend-webhook-client.ts +32 -0
- package/examples/jest.config.example.cjs +18 -0
- package/examples/mocharc.nzila.example.cjs +21 -0
- package/examples/react/checkout-feature.example.tsx +41 -0
- package/examples/send-run-manual.mjs +16 -0
- package/examples/shared/feature-map.ts +24 -0
- package/examples/shared/load-env.mjs +24 -0
- package/examples/shared/send-webhook.mjs +43 -0
- package/examples/vitest.config.example.ts +20 -0
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -11,6 +11,21 @@ npm install @nzila/sdk
|
|
|
11
11
|
# Vitest projects also need vitest as a peer
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
+
## CLI (onboarding)
|
|
15
|
+
|
|
16
|
+
`npx @nzila/sdk` opens the [Nzila dashboard](https://nzila-kappa.vercel.app) and prints setup commands. No separate CLI package.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx @nzila/sdk # open app + help
|
|
20
|
+
npx @nzila/sdk login
|
|
21
|
+
npx @nzila/sdk link --api-key <key> --project-id <uuid>
|
|
22
|
+
npx @nzila/sdk doctor
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Also available as `npx nzila` after install. Override platform with `NZILA_APP_URL` or `--endpoint`.
|
|
26
|
+
|
|
27
|
+
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.
|
|
28
|
+
|
|
14
29
|
## Exports
|
|
15
30
|
|
|
16
31
|
| Path | Purpose |
|
|
@@ -67,4 +82,15 @@ const nzila = traceNzilaFeature("Checkout");
|
|
|
67
82
|
await nzila.runApi("charge", () => charge());
|
|
68
83
|
```
|
|
69
84
|
|
|
70
|
-
|
|
85
|
+
## Examples (included in this package)
|
|
86
|
+
|
|
87
|
+
After install, open **`node_modules/@nzila/sdk/examples/`**:
|
|
88
|
+
|
|
89
|
+
- **[INDEX.md](./examples/INDEX.md)** — map of all samples
|
|
90
|
+
- **[COMPLEX-USAGE.md](./examples/COMPLEX-USAGE.md)** — every feature (Vitest, runtime, `mapFeature`, webhooks)
|
|
91
|
+
- **[RUNTIME-TRACE.md](./examples/RUNTIME-TRACE.md)** — React + backend live tracing
|
|
92
|
+
- **[TRACING-FAILURES.md](./examples/TRACING-FAILURES.md)** — tests → dashboard
|
|
93
|
+
- Config: `vitest.config.example.ts`, `jest.config.example.cjs`, `mocharc.nzila.example.cjs`
|
|
94
|
+
- Code: `backend/`, `frontend/`, `complex/`, `react/checkout-feature.example.tsx`
|
|
95
|
+
|
|
96
|
+
All example imports use `@nzila/sdk` (same as your app).
|
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":""}
|
package/dist/cli/main.js
ADDED
|
@@ -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 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Complex usage — all Nzila SDK features
|
|
2
|
+
|
|
3
|
+
This guide ties together **test webhooks**, **runtime signals**, **mapFeature**, and **manual error reporting** in one flow. Use it after the quick starts in [README.md](README.md), [TRACING-FAILURES.md](TRACING-FAILURES.md), and [RUNTIME-TRACE.md](RUNTIME-TRACE.md).
|
|
4
|
+
|
|
5
|
+
## Feature matrix
|
|
6
|
+
|
|
7
|
+
| Capability | API | When to use |
|
|
8
|
+
|------------|-----|-------------|
|
|
9
|
+
| CI test run | `NzilaVitestReporter` / `NzilaJestReporter` / Mocha | Every `vitest run` / Jest / Mocha finish |
|
|
10
|
+
| Manual run POST | `sendNzilaRun(payload, { webhookUrl, apiKey })` | Custom runners, replay payloads |
|
|
11
|
+
| Feature naming | `mapFeature(describePath, testName)` | Suite title ≠ dashboard feature |
|
|
12
|
+
| Backend handler | `traceNzilaFeature("Checkout")` | First line of route/service |
|
|
13
|
+
| React screen | `useNzilaFeature("Checkout")` | Top of component matching tests |
|
|
14
|
+
| HTTP wrapper | `nzila.runApi("label", () => fetch…)` | Auto `api` success/failure |
|
|
15
|
+
| Handled errors | `nzila.captureError(err, { … })` | `catch`, validation, business rules |
|
|
16
|
+
| No handle in scope | `reportFeatureError("Checkout", err)` | Deep helper, fire-and-forget |
|
|
17
|
+
| API failure label | `nzila.captureApiError(err, "payment.charge")` | After failed call outside `runApi` |
|
|
18
|
+
| UI issues | `nzila.reportUi("custom_banner", { … })` | Non-throwing UX problems |
|
|
19
|
+
| Render errors | `NzilaFeatureBoundary` + `useNzilaFeature` | Child tree throws |
|
|
20
|
+
| Static demo payload | `shared/send-webhook.mjs` | No Vitest installed |
|
|
21
|
+
|
|
22
|
+
Use the **same feature strings** everywhere (e.g. `"Checkout"`, `"Inventory"`) so test failures and runtime signals land on one dashboard row.
|
|
23
|
+
|
|
24
|
+
## 1. Complex Vitest run (multi-feature, pass + fail)
|
|
25
|
+
|
|
26
|
+
**Files:** `complex/full-platform.demo.test.ts`, `vitest.complex.config.ts`, `shared/feature-map.ts`
|
|
27
|
+
|
|
28
|
+
- Three describe roots: `Checkout UI`, `Inventory`, `Authentication`
|
|
29
|
+
- `mapFeature` maps UI vs API names via `resolveFrontendFeature` / `resolveBackendFeature`
|
|
30
|
+
- Several tests **fail on purpose** so Nzila shows failure analysis
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# .env.local: NZILA_API_KEY, NZILA_WEBHOOK_URL
|
|
34
|
+
# Optional: NZILA_COMPLEX_APP_NAME=checkout-api (must exist in dashboard)
|
|
35
|
+
npm run example:test:complex
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Open **Runs** → latest run → failures grouped by feature.
|
|
39
|
+
|
|
40
|
+
## 2. Complex backend runtime (runApi + capture + reportFeatureError)
|
|
41
|
+
|
|
42
|
+
**File:** `complex/api-services.demo.ts`
|
|
43
|
+
|
|
44
|
+
Demonstrates:
|
|
45
|
+
|
|
46
|
+
1. `initNzilaRuntime({ signalsUrl, apiKey })`
|
|
47
|
+
2. `traceNzilaFeature("Checkout")` with `runApi` for inventory + payment
|
|
48
|
+
3. `captureError` for handled business failure (409)
|
|
49
|
+
4. `captureApiError` for pipeline failure
|
|
50
|
+
5. Second feature `Inventory` with `reportFeatureError` in a job
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm run example:runtime:complex
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Wait ~1s for batched flush, then check **Feature health** / runtime signals for `Checkout` and `Inventory`.
|
|
57
|
+
|
|
58
|
+
## 3. Tracing-only Vitest (focused failure fingerprints)
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm run example:test:tracing:all
|
|
62
|
+
npm run example:webhook:tracing
|
|
63
|
+
npm run example:webhook:tracing:frontend
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 4. React runtime (monorepo)
|
|
67
|
+
|
|
68
|
+
See [RUNTIME-TRACE.md](RUNTIME-TRACE.md). Pattern:
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
initNzilaRuntime({ signalsUrl, apiKey });
|
|
72
|
+
|
|
73
|
+
function CheckoutPage() {
|
|
74
|
+
const nzila = useNzilaFeature("Checkout");
|
|
75
|
+
async function pay() {
|
|
76
|
+
try {
|
|
77
|
+
await nzila.runApi("checkout.submit", () =>
|
|
78
|
+
fetch("/api/checkout", { method: "POST" }),
|
|
79
|
+
);
|
|
80
|
+
} catch (e) {
|
|
81
|
+
nzila.captureError(e, { step: "submit" });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return (
|
|
85
|
+
<NzilaFeatureBoundary feature="Checkout" nzila={nzila}>
|
|
86
|
+
{/* children */}
|
|
87
|
+
</NzilaFeatureBoundary>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 5. Jest and Mocha
|
|
93
|
+
|
|
94
|
+
- Jest: copy `jest.config.example.cjs` → wire `NzilaJestReporter` with same env vars as Vitest.
|
|
95
|
+
- Mocha: `mocharc.nzila.example.cjs` — register reporter, call `sendNzilaRun` on `end` if you roll your own.
|
|
96
|
+
|
|
97
|
+
## 6. End-to-end local checklist
|
|
98
|
+
|
|
99
|
+
1. `npm run dev` + `npm run worker`
|
|
100
|
+
2. Create app(s): `checkout-api`, `checkout-web` (or your `NZILA_COMPLEX_APP_NAME`)
|
|
101
|
+
3. API key in `.env.local`
|
|
102
|
+
4. `npm run example:test:complex` → webhook run
|
|
103
|
+
5. `npm run example:runtime:complex` → runtime signals
|
|
104
|
+
6. Dashboard: **Runs**, **Failures**, **Feature health** — same feature names
|
|
105
|
+
|
|
106
|
+
## Environment reference
|
|
107
|
+
|
|
108
|
+
| Variable | Used by |
|
|
109
|
+
|----------|---------|
|
|
110
|
+
| `NZILA_API_KEY` | Webhook + runtime |
|
|
111
|
+
| `NZILA_WEBHOOK_URL` | Vitest/Jest reporters, `sendNzilaRun` |
|
|
112
|
+
| `NZILA_SIGNALS_URL` | `initNzilaRuntime` (default `http://localhost:3000/api/signals/runtime`) |
|
|
113
|
+
| `NZILA_COMPLEX_APP_NAME` | Complex Vitest config only |
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# @nzila/sdk examples
|
|
2
|
+
|
|
3
|
+
These files ship inside the npm package under `node_modules/@nzila/sdk/examples/`.
|
|
4
|
+
|
|
5
|
+
| Topic | Files |
|
|
6
|
+
|-------|--------|
|
|
7
|
+
| Overview | [README from monorepo](./README.md) |
|
|
8
|
+
| All features walkthrough | [COMPLEX-USAGE.md](./COMPLEX-USAGE.md) |
|
|
9
|
+
| Live app tracing | [RUNTIME-TRACE.md](./RUNTIME-TRACE.md) |
|
|
10
|
+
| Test → dashboard mapping | [TRACING-FAILURES.md](./TRACING-FAILURES.md) |
|
|
11
|
+
| Vitest | [vitest.config.example.ts](./vitest.config.example.ts), [complex/](./complex/) |
|
|
12
|
+
| Jest | [jest.config.example.cjs](./jest.config.example.cjs) |
|
|
13
|
+
| Mocha | [mocharc.nzila.example.cjs](./mocharc.nzila.example.cjs) |
|
|
14
|
+
| Backend runtime | [backend/runtime-trace.example.ts](./backend/runtime-trace.example.ts), [complex/api-services.demo.ts](./complex/api-services.demo.ts) |
|
|
15
|
+
| React | [react/checkout-feature.example.tsx](./react/checkout-feature.example.tsx) |
|
|
16
|
+
| Manual webhook | [send-run-manual.mjs](./send-run-manual.mjs), [shared/send-webhook.mjs](./shared/send-webhook.mjs) |
|
|
17
|
+
| Sample payloads | [backend/sample-payload.json](./backend/sample-payload.json), [frontend/sample-payload.json](./frontend/sample-payload.json) |
|
|
18
|
+
|
|
19
|
+
## Environment
|
|
20
|
+
|
|
21
|
+
```env
|
|
22
|
+
NZILA_API_KEY=nzl_...
|
|
23
|
+
NZILA_WEBHOOK_URL=https://your-host/api/webhooks/tests
|
|
24
|
+
NZILA_SIGNALS_URL=https://your-host/api/signals/runtime
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Imports in these files use `@nzila/sdk` — the same as in your application after `npm install @nzila/sdk`.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
> **npm:** Start with [INDEX.md](./INDEX.md). Imports use `@nzila/sdk`.
|
|
2
|
+
|
|
3
|
+
# Nzila integration examples
|
|
4
|
+
|
|
5
|
+
End-to-end samples for **backend (API)** and **frontend (UI)** test flows.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
1. `npm run dev` and `npm run worker` (with `QUEUE_DRIVER` and DB migrated).
|
|
10
|
+
2. Register, create an API key at `/en/keys`.
|
|
11
|
+
3. In **`.env.local`**:
|
|
12
|
+
|
|
13
|
+
```env
|
|
14
|
+
NZILA_API_KEY=nzl_...
|
|
15
|
+
NZILA_WEBHOOK_URL=http://localhost:3000/api/webhooks/tests
|
|
16
|
+
HF_API_TOKEN=hf_... # optional, for AI summaries
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The same examples are published inside **`@nzila/sdk`** at `node_modules/@nzila/sdk/examples/` (see `INDEX.md` there).
|
|
20
|
+
|
|
21
|
+
## Layout
|
|
22
|
+
|
|
23
|
+
| Path | Purpose |
|
|
24
|
+
|------|---------|
|
|
25
|
+
| `backend/` | API-style unit tests (pricing, inventory, auth) |
|
|
26
|
+
| `frontend/` | UI logic tests (checkout form, product card) |
|
|
27
|
+
| `shared/send-webhook.mjs` | POST static JSON payloads (CI / manual) |
|
|
28
|
+
| `vitest.config.ts` | Vitest + Nzila reporter (fires webhook on finish) |
|
|
29
|
+
| `jest.config.example.cjs` | Jest + NzilaJestReporter |
|
|
30
|
+
| `mocharc.nzila.example.cjs` | Mocha reporter setup notes |
|
|
31
|
+
| `@nzila/sdk` | Installed npm package (you are reading its `examples/` folder) |
|
|
32
|
+
|
|
33
|
+
Each suite includes **passing and failing** tests so the dashboard shows real failure analysis.
|
|
34
|
+
|
|
35
|
+
## Trace failures (tests → dashboard)
|
|
36
|
+
|
|
37
|
+
See **[TRACING-FAILURES.md](TRACING-FAILURES.md)** for how `describe()` paths, fingerprints, and `errors[]` map to **Runs**, **Failures**, and **Feature health**.
|
|
38
|
+
|
|
39
|
+
## Complex usage (all features)
|
|
40
|
+
|
|
41
|
+
See **[COMPLEX-USAGE.md](COMPLEX-USAGE.md)** for a single walkthrough: multi-feature Vitest, `mapFeature`, runtime `runApi` / `captureError`, Jest/Mocha, and env vars.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm run example:test:complex # Vitest: Checkout UI + Inventory + Auth (pass/fail)
|
|
45
|
+
npm run example:runtime:complex # Backend: traceNzilaFeature + reportFeatureError
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Runtime trace (live app → Feature health)
|
|
49
|
+
|
|
50
|
+
See **[RUNTIME-TRACE.md](RUNTIME-TRACE.md)** for `useNzilaFeature` (React), `traceNzilaFeature` (backend), and **`captureError` / `reportFeatureError`** when you handle errors yourself.
|
|
51
|
+
|
|
52
|
+
Example backend handler: `backend/runtime-trace.example.ts`. Heavier demo: `complex/api-services.demo.ts`.
|
|
53
|
+
|
|
54
|
+
Quick demo (Vitest only):
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm run example:test:tracing # Vitest → webhook
|
|
58
|
+
npm run example:webhook:tracing # static JSON payload
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Run Vitest (sends one webhook per run)
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# All examples (mixed app name: nzila-demo)
|
|
65
|
+
npm run example:test
|
|
66
|
+
|
|
67
|
+
# Backend only → app name checkout-api
|
|
68
|
+
npm run example:test:backend
|
|
69
|
+
|
|
70
|
+
# Frontend only → app name checkout-web
|
|
71
|
+
npm run example:test:frontend
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Send sample payloads (no Vitest)
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm run example:webhook:backend
|
|
78
|
+
npm run example:webhook:frontend
|
|
79
|
+
npm run example:webhook # both
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Full local demo
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm run example:all # vitest + both webhooks (needs dev + worker up)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Server-side client
|
|
89
|
+
|
|
90
|
+
Use `frontend-webhook-client.ts` from a Route Handler or CI job — not from browser bundles.
|
|
91
|
+
|
|
92
|
+
## Payload contract
|
|
93
|
+
|
|
94
|
+
See `backend/sample-payload.json`, `frontend/sample-payload.json`, and `src/lib/webhook-schema.ts`.
|