@nzila/sdk 0.1.6 → 0.1.9

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
@@ -25,6 +25,20 @@ Subpaths such as `@nzila/sdk/vitest` need **`moduleResolution`** set to **`bundl
25
25
 
26
26
  `@nzila/sdk@0.1.4+` also ships root `.d.ts` shims and `typesVersions` for broader editor support.
27
27
 
28
+ ### Vitest reporter API
29
+
30
+ `NzilaVitestReporter` implements Vitest’s `Reporter` interface and sends the webhook in **`onTestRunEnd`** (after all modules finish). Optional hooks like `onTestCaseResult` are not required.
31
+
32
+ ### Vitest: tests hang or never start?
33
+
34
+ Use the **tuple** from `nzilaVitestReporter()` — do **not** put `new NzilaVitestReporter()` in `vitest.config.ts`. Worker pools cannot serialize class instances.
35
+
36
+ ```ts
37
+ reporters: ["default", nzilaVitestReporter({ webhookUrl, apiKey, appName })],
38
+ ```
39
+
40
+ Equivalent: `reporters: ["default", ["@nzila/sdk/vitest", { … }]]`.
41
+
28
42
  ### Reporters not sending?
29
43
 
30
44
  1. Set **`NZILA_WEBHOOK_URL`**, **`NZILA_API_KEY`**, and **`NZILA_APP_NAME`** (must match the project app name in the dashboard), or pass them in the reporter constructor.
@@ -63,23 +77,34 @@ After you sign in on [nzila-kappa.vercel.app](https://nzila-kappa.vercel.app), t
63
77
  **Tests (CI):**
64
78
 
65
79
  ```ts
80
+ import nzilaConfig from "./nzila.config";
66
81
  import { nzilaVitestReporter } from "@nzila/sdk/vitest";
82
+ import { reporterOptionsFromNzilaConfig } from "@nzila/sdk";
67
83
 
68
84
  export default defineConfig({
69
85
  test: {
70
86
  reporters: [
71
87
  "default",
72
- nzilaVitestReporter({
73
- webhookUrl: process.env.NZILA_WEBHOOK_URL!,
74
- apiKey: process.env.NZILA_API_KEY!,
75
- appName: "my-app",
76
- mapFeature: (path) => path[0] ?? "general",
77
- }),
88
+ nzilaVitestReporter(reporterOptionsFromNzilaConfig(nzilaConfig)),
78
89
  ],
79
90
  },
80
91
  });
81
92
  ```
82
93
 
94
+ `nzila.config.ts` (from `npx @nzila/sdk link --api-key … --project-id <uuid> --app-name <app>`):
95
+
96
+ ```ts
97
+ export default {
98
+ apiKey: "nzl_…",
99
+ projectId: "00000000-0000-0000-0000-000000000000",
100
+ appName: "my-app",
101
+ endpoint: "https://nzila-kappa.vercel.app",
102
+ framework: "vitest",
103
+ } as const;
104
+ ```
105
+
106
+ Or set env vars: `NZILA_API_KEY`, `NZILA_PROJECT_ID`, `NZILA_APP_NAME`, `NZILA_WEBHOOK_URL`.
107
+
83
108
  **React (runtime):**
84
109
 
85
110
  ```ts
package/dist/cli/main.js CHANGED
@@ -16,13 +16,15 @@ async function loadConfig(cwd) {
16
16
  const source = await readFile(file, "utf8");
17
17
  const match = source.match(/apiKey:\s*["']([^"']+)["']/);
18
18
  const projectMatch = source.match(/projectId:\s*["']([^"']+)["']/);
19
+ const appMatch = source.match(/appName:\s*["']([^"']+)["']/);
19
20
  const endpointMatch = source.match(/endpoint:\s*["']([^"']+)["']/);
20
21
  const frameworkMatch = source.match(/framework:\s*["']([^"']+)["']/);
21
- if (!match?.[1] || !projectMatch?.[1])
22
+ if (!match?.[1] || !projectMatch?.[1] || !appMatch?.[1])
22
23
  return null;
23
24
  return {
24
25
  apiKey: match[1],
25
26
  projectId: projectMatch[1],
27
+ appName: appMatch[1],
26
28
  endpoint: endpointMatch?.[1] ?? defaultEndpoint(),
27
29
  framework: frameworkMatch?.[1] ?? "vitest",
28
30
  };
@@ -32,6 +34,7 @@ async function writeConfig(cwd, config) {
32
34
  export default {
33
35
  apiKey: "${config.apiKey}",
34
36
  projectId: "${config.projectId}",
37
+ appName: "${config.appName.replace(/"/g, '\\"')}",
35
38
  endpoint: "${config.endpoint.replace(/"/g, '\\"')}",
36
39
  framework: "${config.framework}",
37
40
  } as const;
@@ -65,17 +68,45 @@ function detectFramework(cwd) {
65
68
  return "playwright";
66
69
  return "vitest";
67
70
  }
68
- function printEnvSnippet(endpoint) {
69
- const paths = platformPaths(endpoint);
71
+ function printEnvSnippet(config) {
72
+ const paths = platformPaths(config.endpoint);
70
73
  console.log("");
71
- console.log("Add to your project .env.local:");
74
+ console.log("Optional .env.local (or use nzila.config.ts only):");
72
75
  console.log(`NZILA_WEBHOOK_URL=${paths.webhook}`);
73
76
  console.log(`NZILA_SIGNALS_URL=${paths.signals}`);
74
- console.log("NZILA_API_KEY=<from dashboard → API Keys>");
77
+ console.log(`NZILA_API_KEY=${config.apiKey}`);
78
+ console.log(`NZILA_PROJECT_ID=${config.projectId}`);
79
+ console.log(`NZILA_APP_NAME=${config.appName}`);
75
80
  console.log("");
76
- console.log(`SDK already installed via ${PKG}; add Vitest reporter from docs.`);
81
+ printReporterSnippet(config);
77
82
  console.log(`Docs: ${paths.docs}`);
78
83
  }
84
+ function printReporterSnippet(config) {
85
+ const paths = platformPaths(config.endpoint);
86
+ if (config.framework === "vitest") {
87
+ console.log("vitest.config.ts:");
88
+ console.log(` import nzilaConfig from "./${CONFIG_FILE.replace(".ts", "")}";`);
89
+ console.log(` import { nzilaVitestReporter } from "${PKG}/vitest";`);
90
+ console.log(` import { reporterOptionsFromNzilaConfig } from "${PKG}";`);
91
+ console.log(" reporters: [");
92
+ console.log(' "default",');
93
+ console.log(" nzilaVitestReporter(reporterOptionsFromNzilaConfig(nzilaConfig)),");
94
+ console.log(" ],");
95
+ }
96
+ else if (config.framework === "jest") {
97
+ console.log("jest.config:");
98
+ console.log(` reporters: ["default", ["${PKG}/jest", {`);
99
+ console.log(` webhookUrl: "${paths.webhook}",`);
100
+ console.log(` apiKey: nzilaConfig.apiKey,`);
101
+ console.log(` projectId: "${config.projectId}",`);
102
+ console.log(` appName: "${config.appName}",`);
103
+ console.log(" }]],");
104
+ }
105
+ else {
106
+ console.log(`Wire ${PKG} reporter for ${config.framework} — see docs.`);
107
+ }
108
+ console.log("");
109
+ }
79
110
  async function tryOpen(url, quiet = false) {
80
111
  try {
81
112
  await openBrowser(url);
@@ -104,9 +135,15 @@ async function cmdInit(flags) {
104
135
  console.log("Quick start:");
105
136
  console.log(` 1. npx ${PKG} login → sign in (opens browser)`);
106
137
  console.log(" 2. Create a project + API key in the dashboard");
107
- console.log(` 3. npx ${PKG} link --api-key nzl_… --project-id <uuid>`);
138
+ console.log(` 3. npx ${PKG} link --api-key nzl_… --project-id <uuid> --app-name <app>`);
108
139
  console.log(" 4. Wire @nzila/sdk/vitest and run tests");
109
- printEnvSnippet(base);
140
+ printEnvSnippet({
141
+ apiKey: "<api-key>",
142
+ projectId: "<project-uuid>",
143
+ appName: "<app-name>",
144
+ endpoint: base,
145
+ framework,
146
+ });
110
147
  if (flags.open !== false) {
111
148
  await tryOpen(paths.register, true);
112
149
  }
@@ -119,22 +156,24 @@ async function cmdLogin(flags) {
119
156
  console.log(` ${platformPaths(base).keys}`);
120
157
  console.log("");
121
158
  console.log("Then link this repo:");
122
- console.log(` npx ${PKG} link --api-key <key> --project-id <uuid>`);
159
+ console.log(` npx ${PKG} link --api-key <key> --project-id <uuid> --app-name <app>`);
123
160
  await tryOpen(loginUrl);
124
161
  }
125
162
  async function cmdLink(flags) {
126
163
  const apiKey = String(flags["api-key"] ?? flags.apiKey ?? "");
127
164
  const projectId = String(flags["project-id"] ?? flags.projectId ?? "");
165
+ const appName = String(flags["app-name"] ?? flags.appName ?? "");
128
166
  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>]`);
167
+ if (!apiKey || !projectId || !appName) {
168
+ console.error(`Usage: npx ${PKG} link --api-key <token> --project-id <uuid> --app-name <name> [--endpoint <url>]`);
131
169
  process.exit(1);
132
170
  }
133
171
  const cwd = process.cwd();
134
172
  const framework = detectFramework(cwd);
135
- await writeConfig(cwd, { apiKey, projectId, endpoint, framework });
173
+ const config = { apiKey, projectId, appName, endpoint, framework };
174
+ await writeConfig(cwd, config);
136
175
  console.log(`Wrote ${CONFIG_FILE} (endpoint: ${endpoint})`);
137
- printEnvSnippet(endpoint);
176
+ printEnvSnippet(config);
138
177
  }
139
178
  async function cmdDoctor() {
140
179
  const cwd = process.cwd();
@@ -146,6 +185,7 @@ async function cmdDoctor() {
146
185
  const paths = platformPaths(config.endpoint);
147
186
  console.log("Config OK:", {
148
187
  projectId: config.projectId,
188
+ appName: config.appName,
149
189
  endpoint: config.endpoint,
150
190
  framework: config.framework,
151
191
  });
@@ -159,13 +199,13 @@ Commands:
159
199
  open Open the dashboard in your browser (default)
160
200
  init Detect framework + show setup steps
161
201
  login Open sign-in and linking instructions
162
- link Write nzila.config.ts (--api-key, --project-id)
202
+ link Write nzila.config.ts (--api-key, --project-id, --app-name)
163
203
  doctor Validate nzila.config.ts
164
204
 
165
205
  Examples:
166
206
  npx ${PKG}
167
207
  npx ${PKG} login
168
- npx ${PKG} link --api-key nzl_… --project-id <uuid>
208
+ npx ${PKG} link --api-key nzl_… --project-id <uuid> --app-name <app>
169
209
 
170
210
  Docs: ${paths.docs}
171
211
  `);
@@ -1,5 +1,5 @@
1
1
  import type { TestModule } from "vitest/node";
2
2
  import type { NzilaClientOptions, NzilaTestCase } from "./types.js";
3
- /** Collect finished tests from Vitest 3+ `TestModule` reporters API. */
3
+ /** Collect finished tests from Vitest `onTestRunEnd` modules. */
4
4
  export declare function collectTestsFromVitestModules(modules: ReadonlyArray<TestModule>, options: NzilaClientOptions, runStartedAt: Date): NzilaTestCase[];
5
5
  //# sourceMappingURL=collect-vitest-tests.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"collect-vitest-tests.d.ts","sourceRoot":"","sources":["../src/collect-vitest-tests.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,UAAU,EAAa,MAAM,aAAa,CAAC;AACnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAmB,MAAM,YAAY,CAAC;AAmBrF,wEAAwE;AACxE,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,EAClC,OAAO,EAAE,kBAAkB,EAC3B,YAAY,EAAE,IAAI,GACjB,aAAa,EAAE,CAuCjB"}
1
+ {"version":3,"file":"collect-vitest-tests.d.ts","sourceRoot":"","sources":["../src/collect-vitest-tests.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAmB,MAAM,YAAY,CAAC;AA6BrF,iEAAiE;AACjE,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,EAClC,OAAO,EAAE,kBAAkB,EAC3B,YAAY,EAAE,IAAI,GACjB,aAAa,EAAE,CA0CjB"}
@@ -1,7 +1,12 @@
1
+ import { nzilaTestContext } from "./reporter-options.js";
1
2
  function describePathFor(test) {
2
3
  const path = [];
3
4
  let parent = test.parent;
4
- while (parent.type === "suite") {
5
+ const seen = new Set();
6
+ while (parent?.type === "suite") {
7
+ if (seen.has(parent))
8
+ break;
9
+ seen.add(parent);
5
10
  path.unshift(parent.name);
6
11
  parent = parent.parent;
7
12
  }
@@ -16,18 +21,22 @@ function mapStatus(state) {
16
21
  return "skipped";
17
22
  return "pending";
18
23
  }
19
- /** Collect finished tests from Vitest 3+ `TestModule` reporters API. */
24
+ /** Collect finished tests from Vitest `onTestRunEnd` modules. */
20
25
  export function collectTestsFromVitestModules(modules, options, runStartedAt) {
21
26
  const framework = options.framework ?? "vitest";
22
27
  const tests = [];
23
28
  const now = new Date().toISOString();
24
29
  for (const mod of modules) {
25
- for (const test of mod.children.allTests()) {
26
- const result = test.result();
30
+ const allTests = mod.children?.allTests?.();
31
+ if (!allTests)
32
+ continue;
33
+ for (const test of allTests) {
34
+ const node = test;
35
+ const result = node.result();
27
36
  if (result.state === "pending")
28
37
  continue;
29
- const describePath = describePathFor(test);
30
- const feature = options.mapFeature?.(describePath, test.name) ??
38
+ const describePath = describePathFor(node);
39
+ const feature = options.mapFeature?.(describePath, node.name) ??
31
40
  describePath[0] ??
32
41
  "general";
33
42
  const errors = result.errors?.map((e) => ({
@@ -41,10 +50,10 @@ export function collectTestsFromVitestModules(modules, options, runStartedAt) {
41
50
  finishedAt: now,
42
51
  describePath,
43
52
  feature,
44
- context: { layer: options.appName },
45
- testName: test.name,
53
+ context: nzilaTestContext(options),
54
+ testName: node.name,
46
55
  status: mapStatus(result.state),
47
- duration: test.diagnostic()?.duration ?? 0,
56
+ duration: node.diagnostic()?.duration ?? 0,
48
57
  errors,
49
58
  });
50
59
  }
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
  export { NZILA_TEST_FRAMEWORKS, type NzilaTestFramework, type NzilaTestStatus, type NzilaLocale, type NzilaTestCase, type NzilaRunPayload, type NzilaClientOptions, } from "./types.js";
7
7
  export { sendNzilaRun, resolveLocale, type DeliverOptions } from "./deliver.js";
8
+ export { type NzilaConfig, webhookUrlFromEndpoint, reporterOptionsFromNzilaConfig, } from "./nzila-config.js";
8
9
  export { initNzilaRuntime, isNzilaRuntimeReady, traceNzilaFeature, createFeatureHandle, reportFeatureError, captureFeatureError, extractErrorFields, type NzilaFeatureHandle, type NzilaRuntimeConfig, type NzilaRuntimeSignal, } from "./runtime/index.js";
9
10
  export { default as NzilaVitestReporter } from "./vitest-reporter.js";
10
11
  export { default as NzilaJestReporter } from "./jest-reporter.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,kBAAkB,GACxB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,kBAAkB,GACxB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EACL,KAAK,WAAW,EAChB,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
  export { NZILA_TEST_FRAMEWORKS, } from "./types.js";
7
7
  export { sendNzilaRun, resolveLocale } from "./deliver.js";
8
+ export { webhookUrlFromEndpoint, reporterOptionsFromNzilaConfig, } from "./nzila-config.js";
8
9
  export { initNzilaRuntime, isNzilaRuntimeReady, traceNzilaFeature, createFeatureHandle, reportFeatureError, captureFeatureError, extractErrorFields, } from "./runtime/index.js";
9
10
  export { default as NzilaVitestReporter } from "./vitest-reporter.js";
10
11
  export { default as NzilaJestReporter } from "./jest-reporter.js";
@@ -1 +1 @@
1
- {"version":3,"file":"jest-reporter.d.ts","sourceRoot":"","sources":["../src/jest-reporter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,kBAAkB,EAInB,MAAM,YAAY,CAAC;AAEpB,KAAK,aAAa,GAAG;IAAE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEpD,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;IAC1E,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,WAAW,EAAE;QACX,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;QAC1C,WAAW,EAAE,cAAc,EAAE,CAAC;KAC/B,EAAE,CAAC;CACL,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,OAAO,iBAAiB;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0C;IAClE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,IAAI,CAAS;gBAET,OAAO,EAAE,kBAAkB,EAAE,aAAa,CAAC,EAAE,OAAO;IAKhE,aAAa,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc;IAmDzD,OAAO,CAAC,SAAS;CAQlB;AAED,4CAA4C;AAC5C,YAAY,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"jest-reporter.d.ts","sourceRoot":"","sources":["../src/jest-reporter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,kBAAkB,EAInB,MAAM,YAAY,CAAC;AAEpB,KAAK,aAAa,GAAG;IAAE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEpD,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;IAC1E,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,WAAW,EAAE;QACX,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;QAC1C,WAAW,EAAE,cAAc,EAAE,CAAC;KAC/B,EAAE,CAAC;CACL,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,OAAO,iBAAiB;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0C;IAClE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,IAAI,CAAS;gBAET,OAAO,EAAE,kBAAkB,EAAE,aAAa,CAAC,EAAE,OAAO;IAKhE,aAAa,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc;IAoDzD,OAAO,CAAC,SAAS;CAQlB;AAED,4CAA4C;AAC5C,YAAY,EAAE,aAAa,EAAE,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { sendNzilaRun, resolveLocale } from "./deliver.js";
3
- import { resolveClientOptions } from "./reporter-options.js";
3
+ import { nzilaTestContext, resolveClientOptions } from "./reporter-options.js";
4
4
  /**
5
5
  * Jest reporter: aggregates results and POSTs one {@link sendNzilaRun} payload on `onRunComplete`.
6
6
  *
@@ -35,6 +35,7 @@ export default class NzilaJestReporter {
35
35
  finishedAt: new Date(file.perfStats.end).toISOString(),
36
36
  describePath,
37
37
  feature: describePath[0],
38
+ context: nzilaTestContext(this.options),
38
39
  testName: test.title,
39
40
  status: this.mapStatus(test.status),
40
41
  duration: test.duration ?? 0,
@@ -0,0 +1,28 @@
1
+ import type { NzilaClientOptions, NzilaTestFramework } from "./types.js";
2
+ /** Shape of `nzila.config.ts` written by `npx @nzila/sdk link`. */
3
+ export type NzilaConfig = {
4
+ apiKey: string;
5
+ /** Dashboard project UUID (API Keys → copy project ID). */
6
+ projectId: string;
7
+ /** Must match the project App name in Nzila (webhook payload). */
8
+ appName: string;
9
+ /** Platform base URL, e.g. https://nzila-kappa.vercel.app */
10
+ endpoint: string;
11
+ framework?: NzilaTestFramework;
12
+ locale?: NzilaClientOptions["locale"];
13
+ };
14
+ export declare function webhookUrlFromEndpoint(endpoint: string): string;
15
+ /**
16
+ * Build Vitest/Jest reporter options from `nzila.config.ts` (or the same fields inline).
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import nzilaConfig from "./nzila.config";
21
+ * import { nzilaVitestReporter } from "@nzila/sdk/vitest";
22
+ * import { reporterOptionsFromNzilaConfig } from "@nzila/sdk";
23
+ *
24
+ * reporters: ["default", nzilaVitestReporter(reporterOptionsFromNzilaConfig(nzilaConfig))],
25
+ * ```
26
+ */
27
+ export declare function reporterOptionsFromNzilaConfig(config: NzilaConfig): NzilaClientOptions;
28
+ //# sourceMappingURL=nzila-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nzila-config.d.ts","sourceRoot":"","sources":["../src/nzila-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEzE,mEAAmE;AACnE,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,MAAM,CAAC,EAAE,kBAAkB,CAAC,QAAQ,CAAC,CAAC;CACvC,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,WAAW,GAClB,kBAAkB,CASpB"}
@@ -0,0 +1,26 @@
1
+ export function webhookUrlFromEndpoint(endpoint) {
2
+ const base = endpoint.trim().replace(/\/$/, "");
3
+ return `${base}/api/webhooks/tests`;
4
+ }
5
+ /**
6
+ * Build Vitest/Jest reporter options from `nzila.config.ts` (or the same fields inline).
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import nzilaConfig from "./nzila.config";
11
+ * import { nzilaVitestReporter } from "@nzila/sdk/vitest";
12
+ * import { reporterOptionsFromNzilaConfig } from "@nzila/sdk";
13
+ *
14
+ * reporters: ["default", nzilaVitestReporter(reporterOptionsFromNzilaConfig(nzilaConfig))],
15
+ * ```
16
+ */
17
+ export function reporterOptionsFromNzilaConfig(config) {
18
+ return {
19
+ apiKey: config.apiKey,
20
+ projectId: config.projectId,
21
+ appName: config.appName,
22
+ webhookUrl: webhookUrlFromEndpoint(config.endpoint),
23
+ framework: config.framework,
24
+ locale: config.locale,
25
+ };
26
+ }
@@ -1,4 +1,5 @@
1
1
  import type { NzilaClientOptions } from "./types.js";
2
+ export declare function nzilaTestContext(options: Pick<NzilaClientOptions, "appName" | "projectId">): Record<string, unknown>;
2
3
  /** Merge reporter options with `NZILA_*` environment variables. */
3
4
  export declare function resolveClientOptions(options: NzilaClientOptions): NzilaClientOptions & {
4
5
  debug: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"reporter-options.d.ts","sourceRoot":"","sources":["../src/reporter-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,mEAAmE;AACnE,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,kBAAkB,GAC1B,kBAAkB,GAAG;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,CAQzC"}
1
+ {"version":3,"file":"reporter-options.d.ts","sourceRoot":"","sources":["../src/reporter-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,WAAW,CAAC,GACzD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKzB;AAED,mEAAmE;AACnE,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,kBAAkB,GAC1B,kBAAkB,GAAG;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,CAUzC"}
@@ -1,3 +1,9 @@
1
+ export function nzilaTestContext(options) {
2
+ return {
3
+ layer: options.appName,
4
+ ...(options.projectId ? { projectId: options.projectId } : {}),
5
+ };
6
+ }
1
7
  /** Merge reporter options with `NZILA_*` environment variables. */
2
8
  export function resolveClientOptions(options) {
3
9
  return {
@@ -5,6 +11,7 @@ export function resolveClientOptions(options) {
5
11
  webhookUrl: options.webhookUrl?.trim() || process.env.NZILA_WEBHOOK_URL?.trim() || "",
6
12
  apiKey: options.apiKey?.trim() || process.env.NZILA_API_KEY?.trim() || "",
7
13
  appName: options.appName?.trim() || process.env.NZILA_APP_NAME?.trim() || "",
14
+ projectId: options.projectId?.trim() || process.env.NZILA_PROJECT_ID?.trim() || undefined,
8
15
  debug: options.debug === true || process.env.NZILA_DEBUG === "1",
9
16
  };
10
17
  }
package/dist/types.d.ts CHANGED
@@ -39,6 +39,8 @@ export type NzilaClientOptions = {
39
39
  webhookUrl: string;
40
40
  apiKey: string;
41
41
  appName: string;
42
+ /** Dashboard project UUID — use in `nzila.config.ts` and `NZILA_PROJECT_ID` (metadata on payloads). */
43
+ projectId?: string;
42
44
  framework?: NzilaTestFramework;
43
45
  /** Defaults to a random UUID per reporter instance. */
44
46
  runId?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,eAAO,MAAM,qBAAqB,yGAUxB,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAE1E,kEAAkE;AAClE,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEpD,oDAAoD;AACpD,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,kBAAkB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC/C,CAAC;AAEF,sEAAsE;AACtE,MAAM,MAAM,eAAe,GAAG;IAC5B,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,kBAAkB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IAClE,qEAAqE;IACrE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,eAAO,MAAM,qBAAqB,yGAUxB,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAE1E,kEAAkE;AAClE,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEpD,oDAAoD;AACpD,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,kBAAkB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC/C,CAAC;AAEF,sEAAsE;AACtE,MAAM,MAAM,eAAe,GAAG;IAC5B,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,kBAAkB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,uGAAuG;IACvG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IAClE,qEAAqE;IACrE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC"}
@@ -2,25 +2,37 @@ import type { File } from "@vitest/runner";
2
2
  import type { Reporter, SerializedError, TestModule, TestRunEndReason } from "vitest/node";
3
3
  import type { NzilaClientOptions } from "./types.js";
4
4
  /**
5
- * Vitest reporter that POSTs one webhook per finished run via {@link sendNzilaRun}.
6
- * Supports Vitest 3+ (`onTestRunEnd`) and legacy `onFinished` file tasks.
5
+ * Vitest {@link Reporter} that POSTs one webhook per run on {@link onTestRunEnd}.
6
+ *
7
+ * @see https://vitest.dev/guide/advanced/reporters
7
8
  */
8
- export default class NzilaVitestReporter {
9
+ export default class NzilaVitestReporter implements Reporter {
9
10
  private readonly options;
10
11
  private startedAt;
11
12
  private sent;
12
13
  private readonly runId;
13
14
  constructor(options: NzilaClientOptions);
14
- onTestRunEnd(testModules: ReadonlyArray<TestModule>, _unhandledErrors?: ReadonlyArray<SerializedError>, _reason?: TestRunEndReason): void;
15
- /** @deprecated Vitest 2 still invoked in some setups */
16
- onFinished(files: File[], _errors: unknown[], _coverage?: unknown): void;
15
+ onTestRunStart(): void;
16
+ onTestRunEnd(testModules: ReadonlyArray<TestModule>, _unhandledErrors: ReadonlyArray<SerializedError>, _reason: TestRunEndReason): Promise<void>;
17
+ /**
18
+ * Vitest 2.x only — not part of the current `Reporter` interface.
19
+ * @deprecated Use Vitest 3+ `onTestRunEnd` instead.
20
+ */
21
+ onFinished(files: File[], _errors: unknown[], _coverage?: unknown): Promise<void>;
17
22
  private sendPayload;
18
23
  private walkTasks;
19
24
  private mapStatus;
20
25
  }
26
+ /** Vitest `reporters` entry — load by package name (works with `pool: forks` / `threads`). */
27
+ export declare const NZILA_VITEST_REPORTER: "@nzila/sdk/vitest";
28
+ export type NzilaVitestReporterEntry = [
29
+ typeof NZILA_VITEST_REPORTER,
30
+ NzilaClientOptions
31
+ ];
21
32
  /**
22
- * Returns a reporter instance typed for your project's Vitest config (`reporters` array).
23
- * Prefer this over `new NzilaVitestReporter()` when TypeScript reports a Reporter mismatch.
33
+ * Returns `['@nzila/sdk/vitest', options]` for `defineConfig({ test: { reporters } })`.
34
+ * Do **not** use `new NzilaVitestReporter()` in config worker pools cannot serialize instances.
24
35
  */
25
- export declare function nzilaVitestReporter(options: NzilaClientOptions): Reporter;
36
+ export declare function nzilaVitestReporter(options: NzilaClientOptions): NzilaVitestReporterEntry;
37
+ export type { Reporter as VitestReporter } from "vitest/node";
26
38
  //# sourceMappingURL=vitest-reporter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vitest-reporter.d.ts","sourceRoot":"","sources":["../src/vitest-reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAQ,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EACV,QAAQ,EACR,eAAe,EACf,UAAU,EACV,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAKrB,OAAO,KAAK,EAAE,kBAAkB,EAAmD,MAAM,YAAY,CAAC;AAEtG;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,mBAAmB;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0C;IAClE,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,OAAO,EAAE,kBAAkB;IAKvC,YAAY,CACV,WAAW,EAAE,aAAa,CAAC,UAAU,CAAC,EACtC,gBAAgB,CAAC,EAAE,aAAa,CAAC,eAAe,CAAC,EACjD,OAAO,CAAC,EAAE,gBAAgB;IAM5B,0DAA0D;IAC1D,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,SAAS,CAAC,EAAE,OAAO;YAQnD,WAAW;IA2BzB,OAAO,CAAC,SAAS;IAyCjB,OAAO,CAAC,SAAS;CAMlB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,GAAG,QAAQ,CAEzE"}
1
+ {"version":3,"file":"vitest-reporter.d.ts","sourceRoot":"","sources":["../src/vitest-reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAQ,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EACV,QAAQ,EACR,eAAe,EACf,UAAU,EACV,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAKrB,OAAO,KAAK,EAAE,kBAAkB,EAAmD,MAAM,YAAY,CAAC;AAEtG;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,mBAAoB,YAAW,QAAQ;IAC1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0C;IAClE,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,OAAO,EAAE,kBAAkB;IAKvC,cAAc;IAKR,YAAY,CAChB,WAAW,EAAE,aAAa,CAAC,UAAU,CAAC,EACtC,gBAAgB,EAAE,aAAa,CAAC,eAAe,CAAC,EAChD,OAAO,EAAE,gBAAgB;IAM3B;;;OAGG;IACG,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,SAAS,CAAC,EAAE,OAAO;YAQzD,WAAW;IA2BzB,OAAO,CAAC,SAAS;IAyCjB,OAAO,CAAC,SAAS;CAMlB;AAED,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB,EAAG,mBAA4B,CAAC;AAElE,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,qBAAqB;IAC5B,kBAAkB;CACnB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,kBAAkB,GAC1B,wBAAwB,CAE1B;AAED,YAAY,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,aAAa,CAAC"}
@@ -1,10 +1,11 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { collectTestsFromVitestModules } from "./collect-vitest-tests.js";
3
3
  import { sendNzilaRun, resolveLocale } from "./deliver.js";
4
- import { resolveClientOptions } from "./reporter-options.js";
4
+ import { nzilaTestContext, resolveClientOptions } from "./reporter-options.js";
5
5
  /**
6
- * Vitest reporter that POSTs one webhook per finished run via {@link sendNzilaRun}.
7
- * Supports Vitest 3+ (`onTestRunEnd`) and legacy `onFinished` file tasks.
6
+ * Vitest {@link Reporter} that POSTs one webhook per run on {@link onTestRunEnd}.
7
+ *
8
+ * @see https://vitest.dev/guide/advanced/reporters
8
9
  */
9
10
  export default class NzilaVitestReporter {
10
11
  constructor(options) {
@@ -13,17 +14,24 @@ export default class NzilaVitestReporter {
13
14
  this.options = resolveClientOptions(options);
14
15
  this.runId = this.options.runId ?? randomUUID();
15
16
  }
16
- onTestRunEnd(testModules, _unhandledErrors, _reason) {
17
+ onTestRunStart() {
18
+ this.startedAt = new Date();
19
+ this.sent = false;
20
+ }
21
+ async onTestRunEnd(testModules, _unhandledErrors, _reason) {
17
22
  const tests = collectTestsFromVitestModules(testModules, this.options, this.startedAt);
18
- void this.sendPayload(tests);
23
+ await this.sendPayload(tests);
19
24
  }
20
- /** @deprecated Vitest 2 — still invoked in some setups */
21
- onFinished(files, _errors, _coverage) {
25
+ /**
26
+ * Vitest 2.x only — not part of the current `Reporter` interface.
27
+ * @deprecated Use Vitest 3+ `onTestRunEnd` instead.
28
+ */
29
+ async onFinished(files, _errors, _coverage) {
22
30
  const tests = [];
23
31
  for (const file of files ?? []) {
24
32
  this.walkTasks(file.tasks, file.name.split("/").slice(0, -1), tests);
25
33
  }
26
- void this.sendPayload(tests);
34
+ await this.sendPayload(tests);
27
35
  }
28
36
  async sendPayload(tests) {
29
37
  if (!tests.length) {
@@ -76,7 +84,7 @@ export default class NzilaVitestReporter {
76
84
  finishedAt: now,
77
85
  describePath,
78
86
  feature,
79
- context: { layer: this.options.appName },
87
+ context: nzilaTestContext(this.options),
80
88
  testName: task.name,
81
89
  status: this.mapStatus(result?.state),
82
90
  duration: result?.duration ?? 0,
@@ -94,10 +102,12 @@ export default class NzilaVitestReporter {
94
102
  return "pending";
95
103
  }
96
104
  }
105
+ /** Vitest `reporters` entry — load by package name (works with `pool: forks` / `threads`). */
106
+ export const NZILA_VITEST_REPORTER = "@nzila/sdk/vitest";
97
107
  /**
98
- * Returns a reporter instance typed for your project's Vitest config (`reporters` array).
99
- * Prefer this over `new NzilaVitestReporter()` when TypeScript reports a Reporter mismatch.
108
+ * Returns `['@nzila/sdk/vitest', options]` for `defineConfig({ test: { reporters } })`.
109
+ * Do **not** use `new NzilaVitestReporter()` in config worker pools cannot serialize instances.
100
110
  */
101
111
  export function nzilaVitestReporter(options) {
102
- return new NzilaVitestReporter(options);
112
+ return [NZILA_VITEST_REPORTER, options];
103
113
  }
@@ -0,0 +1,8 @@
1
+ /** Example — copy to your app as `nzila.config.ts` */
2
+ export default {
3
+ apiKey: process.env.NZILA_API_KEY ?? "nzl_your_key_here",
4
+ projectId: process.env.NZILA_PROJECT_ID ?? "00000000-0000-0000-0000-000000000000",
5
+ appName: process.env.NZILA_APP_NAME ?? "your-app-name",
6
+ endpoint: process.env.NZILA_APP_URL ?? "https://nzila-kappa.vercel.app",
7
+ framework: "vitest" as const,
8
+ } as const;
@@ -3,13 +3,13 @@
3
3
  * Nzila repo uses examples/vitest.config.ts (and backend/frontend-specific configs).
4
4
  */
5
5
  import { defineConfig } from "vitest/config";
6
- import NzilaVitestReporter from "@nzila/sdk/vitest";
6
+ import { nzilaVitestReporter } from "@nzila/sdk/vitest";
7
7
 
8
8
  export default defineConfig({
9
9
  test: {
10
10
  reporters: [
11
11
  "default",
12
- new NzilaVitestReporter({
12
+ nzilaVitestReporter({
13
13
  webhookUrl: process.env.NZILA_WEBHOOK_URL ?? "http://localhost:3000/api/webhooks/tests",
14
14
  apiKey: process.env.NZILA_API_KEY!,
15
15
  appName: process.env.NZILA_APP_NAME ?? "my-app",
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Copy to your repo root as `nzila.config.ts` (or run `npx @nzila/sdk link`).
3
+ * Values come from the dashboard: API Keys → generate key + copy project ID.
4
+ */
5
+ export default {
6
+ apiKey: process.env.NZILA_API_KEY ?? "nzl_your_key_here",
7
+ projectId: process.env.NZILA_PROJECT_ID ?? "00000000-0000-0000-0000-000000000000",
8
+ appName: process.env.NZILA_APP_NAME ?? "your-app-name",
9
+ endpoint: process.env.NZILA_APP_URL ?? "https://nzila-kappa.vercel.app",
10
+ framework: "vitest" as const,
11
+ } as const;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nzila/sdk",
3
- "version": "0.1.6",
3
+ "version": "0.1.9",
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",
@@ -15,6 +15,7 @@
15
15
  "files": [
16
16
  "dist",
17
17
  "vitest.d.ts",
18
+ "nzila.config.example.ts",
18
19
  "jest.d.ts",
19
20
  "jest.cjs",
20
21
  "mocha.d.ts",
package/vitest.d.ts CHANGED
@@ -1,15 +1,19 @@
1
1
  import type { NzilaClientOptions } from "./dist/types.js";
2
2
 
3
- /** @see {@link nzilaVitestReporter} for use in `defineConfig({ test: { reporters } })`. */
3
+ export const NZILA_VITEST_REPORTER: "@nzila/sdk/vitest";
4
+
5
+ export type NzilaVitestReporterEntry = [typeof NZILA_VITEST_REPORTER, NzilaClientOptions];
6
+
7
+ /** Use in `reporters: ["default", nzilaVitestReporter({ ... })]` — not `new NzilaVitestReporter()`. */
8
+ export function nzilaVitestReporter(
9
+ options: NzilaClientOptions,
10
+ ): NzilaVitestReporterEntry;
11
+
12
+ /** @see nzilaVitestReporter — default export is the reporter class (loaded by Vitest from the tuple). */
4
13
  declare class NzilaVitestReporter {
5
14
  constructor(options: NzilaClientOptions);
6
15
  }
7
16
 
8
17
  export default NzilaVitestReporter;
9
18
 
10
- /** Vitest-config-safe factory (avoids duplicate `Reporter` types across packages). */
11
- export function nzilaVitestReporter(
12
- options: NzilaClientOptions,
13
- ): import("vitest/node").Reporter;
14
-
15
19
  export * from "./dist/vitest-reporter.js";