@gurulu/cli 1.6.6 → 1.6.7

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/bin.js CHANGED
@@ -39672,6 +39672,84 @@ var validateCmd = defineCommand({
39672
39672
  }
39673
39673
  });
39674
39674
 
39675
+ // src/wizard/verify.ts
39676
+ import { randomUUID } from "node:crypto";
39677
+ function deriveIngestEndpoint(apiEndpoint) {
39678
+ try {
39679
+ const u3 = new URL(apiEndpoint);
39680
+ if (u3.hostname.startsWith("api.")) {
39681
+ u3.hostname = `ingest.${u3.hostname.slice(4)}`;
39682
+ return u3.origin;
39683
+ }
39684
+ if (u3.hostname === "localhost" || u3.hostname === "127.0.0.1")
39685
+ return apiEndpoint;
39686
+ return u3.origin;
39687
+ } catch {
39688
+ return "https://ingest.gurulu.io";
39689
+ }
39690
+ }
39691
+ async function selfVerify(opts) {
39692
+ const fetchImpl2 = opts.fetchImpl ?? fetch;
39693
+ const nowMs = (opts.now ?? Date.now)();
39694
+ const anonymousId = `gurulu_verify_${nowMs.toString(36)}${Math.floor(nowMs % 1000)}`;
39695
+ const sessionId = randomUUID();
39696
+ const eventType = opts.eventType ?? "interaction";
39697
+ const payload = {
39698
+ event_key: opts.eventKey,
39699
+ event_type: eventType,
39700
+ occurred_at: new Date(nowMs).toISOString(),
39701
+ anonymous_id: anonymousId,
39702
+ session_id: sessionId,
39703
+ producer: opts.producer ?? "sdk_web",
39704
+ properties: { ...opts.properties ?? {}, gurulu_install_verify: true },
39705
+ test_mode: true
39706
+ };
39707
+ let resp;
39708
+ try {
39709
+ const r3 = await fetchImpl2(`${opts.ingestEndpoint}/v1/ingest/event`, {
39710
+ method: "POST",
39711
+ headers: {
39712
+ "Content-Type": "application/json",
39713
+ Authorization: `Bearer ${opts.writeKey}`
39714
+ },
39715
+ body: JSON.stringify(payload)
39716
+ });
39717
+ if (r3.status === 401 || r3.status === 403) {
39718
+ return mk("error", false, [`ingest auth reddetti (${r3.status}) — write key geçersiz`], opts, anonymousId);
39719
+ }
39720
+ if (r3.status >= 500) {
39721
+ return mk("error", false, [`ingest ${r3.status} — sunucu hatası`], opts, anonymousId);
39722
+ }
39723
+ resp = await r3.json().catch(() => ({}));
39724
+ } catch (e2) {
39725
+ const msg = e2 instanceof Error ? e2.message : String(e2);
39726
+ return mk("error", false, [`ingest erişilemedi: ${msg}`], opts, anonymousId);
39727
+ }
39728
+ const decision = resp.decision ?? "error";
39729
+ const ok = decision === "accept" || decision === "warn";
39730
+ const reasons = (resp.reasons ?? []).map((x2) => String(x2));
39731
+ const result = mk(decision, ok, reasons, opts, anonymousId);
39732
+ if (ok && opts.client) {
39733
+ result.landedInClickhouse = await pollRecent(opts.client, opts.eventKey, anonymousId);
39734
+ }
39735
+ return result;
39736
+ }
39737
+ function mk(decision, ok, reasons, opts, anonymousId) {
39738
+ return { ok, decision, reasons, eventKey: opts.eventKey, anonymousId };
39739
+ }
39740
+ async function pollRecent(client, eventKey, anonymousId, attempts = 8, delayMs = 3000) {
39741
+ for (let i2 = 0;i2 < attempts; i2++) {
39742
+ try {
39743
+ const res = await client.recentEvents({ event_key: eventKey, limit: 50 });
39744
+ if (res.events.some((e2) => e2.anonymous_id === anonymousId))
39745
+ return true;
39746
+ } catch {}
39747
+ if (i2 < attempts - 1)
39748
+ await new Promise((r3) => setTimeout(r3, delayMs));
39749
+ }
39750
+ return false;
39751
+ }
39752
+
39675
39753
  // src/commands/doctor.ts
39676
39754
  async function runDoctor(opts = {}) {
39677
39755
  const cwd = opts.cwd ?? process.cwd();
@@ -39780,6 +39858,39 @@ async function runDoctor(opts = {}) {
39780
39858
  message: `health overview unavailable: ${err instanceof Error ? err.message : String(err)}`
39781
39859
  });
39782
39860
  }
39861
+ if (manifest && manifest.events.length > 0) {
39862
+ const candidate = manifest.events.find((e2) => e2.lifecycle === "active" && e2.type === "interaction" && e2.producerAllowed.includes("sdk_web"));
39863
+ if (candidate) {
39864
+ const props = {};
39865
+ for (const pr of candidate.properties) {
39866
+ if (!pr.required)
39867
+ continue;
39868
+ props[pr.name] = pr.type === "number" ? 1 : pr.type === "boolean" ? true : pr.type === "array" ? [] : pr.type === "json" ? {} : "e2e";
39869
+ }
39870
+ const vr = await selfVerify({
39871
+ ingestEndpoint: deriveIngestEndpoint(project.endpoint ?? cred.endpoint),
39872
+ writeKey: cred.apiKey,
39873
+ eventKey: candidate.key,
39874
+ eventType: candidate.type,
39875
+ producer: "sdk_web",
39876
+ properties: props,
39877
+ client
39878
+ });
39879
+ const landed = vr.landedInClickhouse;
39880
+ checks.push({
39881
+ name: "end_to_end",
39882
+ status: landed === true ? "pass" : vr.ok ? "warn" : "fail",
39883
+ message: landed === true ? "test event ingest→pipeline→dashboard ulaştı (uçtan uca çalışıyor)" : vr.ok ? "ingest kabul etti ama event ~24sn'de dashboard'a ULAŞMADI — pipeline gecikmesi/sorunu" : `test event '${candidate.key}' ${vr.decision}: ${vr.reasons[0] ?? "doğrulanamadı"}`,
39884
+ detail: { decision: vr.decision, landed_in_clickhouse: landed ?? null }
39885
+ });
39886
+ } else {
39887
+ checks.push({
39888
+ name: "end_to_end",
39889
+ status: "skip",
39890
+ message: "uygun test event yok (aktif interaction + sdk_web producer) — E2E atlandı"
39891
+ });
39892
+ }
39893
+ }
39783
39894
  try {
39784
39895
  const scan = runValidate({ cwd });
39785
39896
  const total = scan.deprecated_calls.length + scan.unknown_calls.length;
@@ -41980,81 +42091,6 @@ async function renderPlan(plan) {
41980
42091
  return plan.events;
41981
42092
  }
41982
42093
 
41983
- // src/wizard/verify.ts
41984
- function deriveIngestEndpoint(apiEndpoint) {
41985
- try {
41986
- const u3 = new URL(apiEndpoint);
41987
- if (u3.hostname.startsWith("api.")) {
41988
- u3.hostname = `ingest.${u3.hostname.slice(4)}`;
41989
- return u3.origin;
41990
- }
41991
- if (u3.hostname === "localhost" || u3.hostname === "127.0.0.1")
41992
- return apiEndpoint;
41993
- return u3.origin;
41994
- } catch {
41995
- return "https://ingest.gurulu.io";
41996
- }
41997
- }
41998
- async function selfVerify(opts) {
41999
- const fetchImpl2 = opts.fetchImpl ?? fetch;
42000
- const nowMs = (opts.now ?? Date.now)();
42001
- const anonymousId = `gurulu_verify_${nowMs.toString(36)}${Math.floor(nowMs % 1000)}`;
42002
- const eventType = opts.eventType ?? "interaction";
42003
- const payload = {
42004
- event_key: opts.eventKey,
42005
- event_type: eventType,
42006
- occurred_at: new Date(nowMs).toISOString(),
42007
- anonymous_id: anonymousId,
42008
- producer: "sdk",
42009
- properties: { gurulu_install_verify: true },
42010
- test_mode: true
42011
- };
42012
- let resp;
42013
- try {
42014
- const r3 = await fetchImpl2(`${opts.ingestEndpoint}/v1/ingest/event`, {
42015
- method: "POST",
42016
- headers: {
42017
- "Content-Type": "application/json",
42018
- Authorization: `Bearer ${opts.writeKey}`
42019
- },
42020
- body: JSON.stringify(payload)
42021
- });
42022
- if (r3.status === 401 || r3.status === 403) {
42023
- return mk("error", false, [`ingest auth reddetti (${r3.status}) — write key geçersiz`], opts, anonymousId);
42024
- }
42025
- if (r3.status >= 500) {
42026
- return mk("error", false, [`ingest ${r3.status} — sunucu hatası`], opts, anonymousId);
42027
- }
42028
- resp = await r3.json().catch(() => ({}));
42029
- } catch (e2) {
42030
- const msg = e2 instanceof Error ? e2.message : String(e2);
42031
- return mk("error", false, [`ingest erişilemedi: ${msg}`], opts, anonymousId);
42032
- }
42033
- const decision = resp.decision ?? "error";
42034
- const ok = decision === "accept" || decision === "warn";
42035
- const reasons = (resp.reasons ?? []).map((x2) => String(x2));
42036
- const result = mk(decision, ok, reasons, opts, anonymousId);
42037
- if (ok && opts.client) {
42038
- result.landedInClickhouse = await pollRecent(opts.client, opts.eventKey, anonymousId);
42039
- }
42040
- return result;
42041
- }
42042
- function mk(decision, ok, reasons, opts, anonymousId) {
42043
- return { ok, decision, reasons, eventKey: opts.eventKey, anonymousId };
42044
- }
42045
- async function pollRecent(client, eventKey, anonymousId, attempts = 4, delayMs = 1500) {
42046
- for (let i2 = 0;i2 < attempts; i2++) {
42047
- try {
42048
- const res = await client.recentEvents({ event_key: eventKey, limit: 50 });
42049
- if (res.events.some((e2) => e2.anonymous_id === anonymousId))
42050
- return true;
42051
- } catch {}
42052
- if (i2 < attempts - 1)
42053
- await new Promise((r3) => setTimeout(r3, delayMs));
42054
- }
42055
- return false;
42056
- }
42057
-
42058
42094
  // src/wizard/wire.ts
42059
42095
  import { existsSync as existsSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync10 } from "node:fs";
42060
42096
 
@@ -42737,7 +42773,13 @@ ${captureGuide(approvedEvents, identifyHint, isNode)}`);
42737
42773
  if (inj.strategy === "manual")
42738
42774
  p4.log.message(plan.initSnippet);
42739
42775
  }
42740
- p4.outro(`${c3.neon("\uD83E\uDD89 Hazır!")} ${c3.dim("Doğrula:")} ${c3.bold("gurulu doctor")} ${c3.dim("·")} ${c3.dim("Dashboard:")} ${c3.cyan("https://dashboard.gurulu.io/app?onboard=done")}`);
42776
+ const e2eOk = verifyResult?.landedInClickhouse === true;
42777
+ const e2eFailed = verifyResult != null && (verifyResult.landedInClickhouse === false || !verifyResult.ok);
42778
+ if (e2eFailed) {
42779
+ p4.outro(`${c3.bold("⚠ Kurulum yapıldı ama UÇTAN UCA DOĞRULANAMADI")} — kod + kayıt tamam, ama test event dashboard'a ulaşmadı (ingest kabul etti/pipeline'da kayboldu). ${c3.dim("Tekrar:")} ${c3.bold("gurulu doctor")}`);
42780
+ } else {
42781
+ p4.outro(`${c3.neon("\uD83E\uDD89 Hazır!")}${e2eOk ? c3.dim(" · uçtan uca doğrulandı") : ""} ${c3.dim("Doğrula:")} ${c3.bold("gurulu doctor")} ${c3.dim("·")} ${c3.dim("Dashboard:")} ${c3.cyan("https://dashboard.gurulu.io/app?onboard=done")}`);
42782
+ }
42741
42783
  }
42742
42784
  async function resolveWorkspace(client, authWorkspaceId, opts) {
42743
42785
  if (opts.writeKey) {
@@ -42775,7 +42817,13 @@ function verifyLabel(v2) {
42775
42817
  switch (v2.decision) {
42776
42818
  case "accept":
42777
42819
  case "warn":
42778
- return `✓ test event kabul edildi (${v2.decision}) pipeline doğrulandı`;
42820
+ if (v2.landedInClickhouse === false) {
42821
+ return "⚠ ingest kabul etti ama event dashboard'a ULAŞMADI (~24sn) — pipeline gecikmesi/sorunu; `gurulu doctor` ile tekrar dene";
42822
+ }
42823
+ if (v2.landedInClickhouse === true) {
42824
+ return "✓ uçtan uca doğrulandı — test event dashboard'a ulaştı";
42825
+ }
42826
+ return `✓ test event kabul edildi (${v2.decision})`;
42779
42827
  case "quarantine":
42780
42828
  return `⚠ event kayıtlı ama eksik prop (quarantine) — Gurulu'ya bağlısın`;
42781
42829
  case "reject":
@@ -43186,7 +43234,7 @@ var uninstallCmd = defineCommand({
43186
43234
  });
43187
43235
 
43188
43236
  // src/index.ts
43189
- var VERSION = "1.6.6";
43237
+ var VERSION = "1.6.7";
43190
43238
  var mainCmd = defineCommand({
43191
43239
  meta: {
43192
43240
  name: "gurulu",
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACrE;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,SAAS,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAiK/E;AA2BD,eAAO,MAAM,SAAS,qDAkBpB,CAAC"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACrE;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,SAAS,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAuN/E;AA2BD,eAAO,MAAM,SAAS,qDAkBpB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const VERSION = "1.6.6";
1
+ export declare const VERSION = "1.6.7";
2
2
  declare const mainCmd: import("citty").CommandDef<{
3
3
  workspace: {
4
4
  type: "string";
package/dist/index.js CHANGED
@@ -39249,6 +39249,84 @@ var validateCmd = defineCommand({
39249
39249
  }
39250
39250
  });
39251
39251
 
39252
+ // src/wizard/verify.ts
39253
+ import { randomUUID } from "node:crypto";
39254
+ function deriveIngestEndpoint(apiEndpoint) {
39255
+ try {
39256
+ const u3 = new URL(apiEndpoint);
39257
+ if (u3.hostname.startsWith("api.")) {
39258
+ u3.hostname = `ingest.${u3.hostname.slice(4)}`;
39259
+ return u3.origin;
39260
+ }
39261
+ if (u3.hostname === "localhost" || u3.hostname === "127.0.0.1")
39262
+ return apiEndpoint;
39263
+ return u3.origin;
39264
+ } catch {
39265
+ return "https://ingest.gurulu.io";
39266
+ }
39267
+ }
39268
+ async function selfVerify(opts) {
39269
+ const fetchImpl2 = opts.fetchImpl ?? fetch;
39270
+ const nowMs = (opts.now ?? Date.now)();
39271
+ const anonymousId = `gurulu_verify_${nowMs.toString(36)}${Math.floor(nowMs % 1000)}`;
39272
+ const sessionId = randomUUID();
39273
+ const eventType = opts.eventType ?? "interaction";
39274
+ const payload = {
39275
+ event_key: opts.eventKey,
39276
+ event_type: eventType,
39277
+ occurred_at: new Date(nowMs).toISOString(),
39278
+ anonymous_id: anonymousId,
39279
+ session_id: sessionId,
39280
+ producer: opts.producer ?? "sdk_web",
39281
+ properties: { ...opts.properties ?? {}, gurulu_install_verify: true },
39282
+ test_mode: true
39283
+ };
39284
+ let resp;
39285
+ try {
39286
+ const r3 = await fetchImpl2(`${opts.ingestEndpoint}/v1/ingest/event`, {
39287
+ method: "POST",
39288
+ headers: {
39289
+ "Content-Type": "application/json",
39290
+ Authorization: `Bearer ${opts.writeKey}`
39291
+ },
39292
+ body: JSON.stringify(payload)
39293
+ });
39294
+ if (r3.status === 401 || r3.status === 403) {
39295
+ return mk("error", false, [`ingest auth reddetti (${r3.status}) — write key geçersiz`], opts, anonymousId);
39296
+ }
39297
+ if (r3.status >= 500) {
39298
+ return mk("error", false, [`ingest ${r3.status} — sunucu hatası`], opts, anonymousId);
39299
+ }
39300
+ resp = await r3.json().catch(() => ({}));
39301
+ } catch (e2) {
39302
+ const msg = e2 instanceof Error ? e2.message : String(e2);
39303
+ return mk("error", false, [`ingest erişilemedi: ${msg}`], opts, anonymousId);
39304
+ }
39305
+ const decision = resp.decision ?? "error";
39306
+ const ok = decision === "accept" || decision === "warn";
39307
+ const reasons = (resp.reasons ?? []).map((x2) => String(x2));
39308
+ const result = mk(decision, ok, reasons, opts, anonymousId);
39309
+ if (ok && opts.client) {
39310
+ result.landedInClickhouse = await pollRecent(opts.client, opts.eventKey, anonymousId);
39311
+ }
39312
+ return result;
39313
+ }
39314
+ function mk(decision, ok, reasons, opts, anonymousId) {
39315
+ return { ok, decision, reasons, eventKey: opts.eventKey, anonymousId };
39316
+ }
39317
+ async function pollRecent(client, eventKey, anonymousId, attempts = 8, delayMs = 3000) {
39318
+ for (let i2 = 0;i2 < attempts; i2++) {
39319
+ try {
39320
+ const res = await client.recentEvents({ event_key: eventKey, limit: 50 });
39321
+ if (res.events.some((e2) => e2.anonymous_id === anonymousId))
39322
+ return true;
39323
+ } catch {}
39324
+ if (i2 < attempts - 1)
39325
+ await new Promise((r3) => setTimeout(r3, delayMs));
39326
+ }
39327
+ return false;
39328
+ }
39329
+
39252
39330
  // src/commands/doctor.ts
39253
39331
  async function runDoctor(opts = {}) {
39254
39332
  const cwd = opts.cwd ?? process.cwd();
@@ -39357,6 +39435,39 @@ async function runDoctor(opts = {}) {
39357
39435
  message: `health overview unavailable: ${err instanceof Error ? err.message : String(err)}`
39358
39436
  });
39359
39437
  }
39438
+ if (manifest && manifest.events.length > 0) {
39439
+ const candidate = manifest.events.find((e2) => e2.lifecycle === "active" && e2.type === "interaction" && e2.producerAllowed.includes("sdk_web"));
39440
+ if (candidate) {
39441
+ const props = {};
39442
+ for (const pr of candidate.properties) {
39443
+ if (!pr.required)
39444
+ continue;
39445
+ props[pr.name] = pr.type === "number" ? 1 : pr.type === "boolean" ? true : pr.type === "array" ? [] : pr.type === "json" ? {} : "e2e";
39446
+ }
39447
+ const vr = await selfVerify({
39448
+ ingestEndpoint: deriveIngestEndpoint(project.endpoint ?? cred.endpoint),
39449
+ writeKey: cred.apiKey,
39450
+ eventKey: candidate.key,
39451
+ eventType: candidate.type,
39452
+ producer: "sdk_web",
39453
+ properties: props,
39454
+ client
39455
+ });
39456
+ const landed = vr.landedInClickhouse;
39457
+ checks.push({
39458
+ name: "end_to_end",
39459
+ status: landed === true ? "pass" : vr.ok ? "warn" : "fail",
39460
+ message: landed === true ? "test event ingest→pipeline→dashboard ulaştı (uçtan uca çalışıyor)" : vr.ok ? "ingest kabul etti ama event ~24sn'de dashboard'a ULAŞMADI — pipeline gecikmesi/sorunu" : `test event '${candidate.key}' ${vr.decision}: ${vr.reasons[0] ?? "doğrulanamadı"}`,
39461
+ detail: { decision: vr.decision, landed_in_clickhouse: landed ?? null }
39462
+ });
39463
+ } else {
39464
+ checks.push({
39465
+ name: "end_to_end",
39466
+ status: "skip",
39467
+ message: "uygun test event yok (aktif interaction + sdk_web producer) — E2E atlandı"
39468
+ });
39469
+ }
39470
+ }
39360
39471
  try {
39361
39472
  const scan = runValidate({ cwd });
39362
39473
  const total = scan.deprecated_calls.length + scan.unknown_calls.length;
@@ -41557,81 +41668,6 @@ async function renderPlan(plan) {
41557
41668
  return plan.events;
41558
41669
  }
41559
41670
 
41560
- // src/wizard/verify.ts
41561
- function deriveIngestEndpoint(apiEndpoint) {
41562
- try {
41563
- const u3 = new URL(apiEndpoint);
41564
- if (u3.hostname.startsWith("api.")) {
41565
- u3.hostname = `ingest.${u3.hostname.slice(4)}`;
41566
- return u3.origin;
41567
- }
41568
- if (u3.hostname === "localhost" || u3.hostname === "127.0.0.1")
41569
- return apiEndpoint;
41570
- return u3.origin;
41571
- } catch {
41572
- return "https://ingest.gurulu.io";
41573
- }
41574
- }
41575
- async function selfVerify(opts) {
41576
- const fetchImpl2 = opts.fetchImpl ?? fetch;
41577
- const nowMs = (opts.now ?? Date.now)();
41578
- const anonymousId = `gurulu_verify_${nowMs.toString(36)}${Math.floor(nowMs % 1000)}`;
41579
- const eventType = opts.eventType ?? "interaction";
41580
- const payload = {
41581
- event_key: opts.eventKey,
41582
- event_type: eventType,
41583
- occurred_at: new Date(nowMs).toISOString(),
41584
- anonymous_id: anonymousId,
41585
- producer: "sdk",
41586
- properties: { gurulu_install_verify: true },
41587
- test_mode: true
41588
- };
41589
- let resp;
41590
- try {
41591
- const r3 = await fetchImpl2(`${opts.ingestEndpoint}/v1/ingest/event`, {
41592
- method: "POST",
41593
- headers: {
41594
- "Content-Type": "application/json",
41595
- Authorization: `Bearer ${opts.writeKey}`
41596
- },
41597
- body: JSON.stringify(payload)
41598
- });
41599
- if (r3.status === 401 || r3.status === 403) {
41600
- return mk("error", false, [`ingest auth reddetti (${r3.status}) — write key geçersiz`], opts, anonymousId);
41601
- }
41602
- if (r3.status >= 500) {
41603
- return mk("error", false, [`ingest ${r3.status} — sunucu hatası`], opts, anonymousId);
41604
- }
41605
- resp = await r3.json().catch(() => ({}));
41606
- } catch (e2) {
41607
- const msg = e2 instanceof Error ? e2.message : String(e2);
41608
- return mk("error", false, [`ingest erişilemedi: ${msg}`], opts, anonymousId);
41609
- }
41610
- const decision = resp.decision ?? "error";
41611
- const ok = decision === "accept" || decision === "warn";
41612
- const reasons = (resp.reasons ?? []).map((x2) => String(x2));
41613
- const result = mk(decision, ok, reasons, opts, anonymousId);
41614
- if (ok && opts.client) {
41615
- result.landedInClickhouse = await pollRecent(opts.client, opts.eventKey, anonymousId);
41616
- }
41617
- return result;
41618
- }
41619
- function mk(decision, ok, reasons, opts, anonymousId) {
41620
- return { ok, decision, reasons, eventKey: opts.eventKey, anonymousId };
41621
- }
41622
- async function pollRecent(client, eventKey, anonymousId, attempts = 4, delayMs = 1500) {
41623
- for (let i2 = 0;i2 < attempts; i2++) {
41624
- try {
41625
- const res = await client.recentEvents({ event_key: eventKey, limit: 50 });
41626
- if (res.events.some((e2) => e2.anonymous_id === anonymousId))
41627
- return true;
41628
- } catch {}
41629
- if (i2 < attempts - 1)
41630
- await new Promise((r3) => setTimeout(r3, delayMs));
41631
- }
41632
- return false;
41633
- }
41634
-
41635
41671
  // src/wizard/wire.ts
41636
41672
  import { existsSync as existsSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync10 } from "node:fs";
41637
41673
 
@@ -42314,7 +42350,13 @@ ${captureGuide(approvedEvents, identifyHint, isNode)}`);
42314
42350
  if (inj.strategy === "manual")
42315
42351
  p4.log.message(plan.initSnippet);
42316
42352
  }
42317
- p4.outro(`${c3.neon("\uD83E\uDD89 Hazır!")} ${c3.dim("Doğrula:")} ${c3.bold("gurulu doctor")} ${c3.dim("·")} ${c3.dim("Dashboard:")} ${c3.cyan("https://dashboard.gurulu.io/app?onboard=done")}`);
42353
+ const e2eOk = verifyResult?.landedInClickhouse === true;
42354
+ const e2eFailed = verifyResult != null && (verifyResult.landedInClickhouse === false || !verifyResult.ok);
42355
+ if (e2eFailed) {
42356
+ p4.outro(`${c3.bold("⚠ Kurulum yapıldı ama UÇTAN UCA DOĞRULANAMADI")} — kod + kayıt tamam, ama test event dashboard'a ulaşmadı (ingest kabul etti/pipeline'da kayboldu). ${c3.dim("Tekrar:")} ${c3.bold("gurulu doctor")}`);
42357
+ } else {
42358
+ p4.outro(`${c3.neon("\uD83E\uDD89 Hazır!")}${e2eOk ? c3.dim(" · uçtan uca doğrulandı") : ""} ${c3.dim("Doğrula:")} ${c3.bold("gurulu doctor")} ${c3.dim("·")} ${c3.dim("Dashboard:")} ${c3.cyan("https://dashboard.gurulu.io/app?onboard=done")}`);
42359
+ }
42318
42360
  }
42319
42361
  async function resolveWorkspace(client, authWorkspaceId, opts) {
42320
42362
  if (opts.writeKey) {
@@ -42352,7 +42394,13 @@ function verifyLabel(v2) {
42352
42394
  switch (v2.decision) {
42353
42395
  case "accept":
42354
42396
  case "warn":
42355
- return `✓ test event kabul edildi (${v2.decision}) pipeline doğrulandı`;
42397
+ if (v2.landedInClickhouse === false) {
42398
+ return "⚠ ingest kabul etti ama event dashboard'a ULAŞMADI (~24sn) — pipeline gecikmesi/sorunu; `gurulu doctor` ile tekrar dene";
42399
+ }
42400
+ if (v2.landedInClickhouse === true) {
42401
+ return "✓ uçtan uca doğrulandı — test event dashboard'a ulaştı";
42402
+ }
42403
+ return `✓ test event kabul edildi (${v2.decision})`;
42356
42404
  case "quarantine":
42357
42405
  return `⚠ event kayıtlı ama eksik prop (quarantine) — Gurulu'ya bağlısın`;
42358
42406
  case "reject":
@@ -42763,7 +42811,7 @@ var uninstallCmd = defineCommand({
42763
42811
  });
42764
42812
 
42765
42813
  // src/index.ts
42766
- var VERSION = "1.6.6";
42814
+ var VERSION = "1.6.7";
42767
42815
  var mainCmd = defineCommand({
42768
42816
  meta: {
42769
42817
  name: "gurulu",
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/wizard/run.ts"],"names":[],"mappings":"AAuCA,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,4CAA4C;IAC5C,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,sFAAsF;IACtF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AA0DD,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAwdlE"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/wizard/run.ts"],"names":[],"mappings":"AAuCA,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,4CAA4C;IAC5C,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,sFAAsF;IACtF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AA0DD,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAmelE"}
@@ -17,6 +17,10 @@ export interface SelfVerifyOptions {
17
17
  writeKey: string;
18
18
  eventKey: string;
19
19
  eventType?: 'interaction' | 'intent' | 'outcome';
20
+ /** Event'in izin verdiği producer (default 'sdk_web'). Yanlış producer → reject. */
21
+ producer?: string;
22
+ /** Zorunlu prop'ları doldur → quarantine yerine accept (E2E poll CH'ye ulaşsın). */
23
+ properties?: Record<string, unknown>;
20
24
  /** CH'de de doğrula (recentEvents poll). Default false — senkron decision yeter. */
21
25
  client?: ApiClient;
22
26
  /** Test-injection (fetch mock). */
@@ -1 +1 @@
1
- {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/wizard/verify.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,CAAC;AAEjG,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,cAAc,CAAC;IACzB,+DAA+D;IAC/D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AASD,mFAAmF;AACnF,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAahE;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;IACjD,oFAAoF;IACpF,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,mCAAmC;IACnC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAuD/E"}
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/wizard/verify.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,CAAC;AAEjG,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,cAAc,CAAC;IACzB,+DAA+D;IAC/D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AASD,mFAAmF;AACnF,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAahE;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;IACjD,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,oFAAoF;IACpF,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,mCAAmC;IACnC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CA4D/E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gurulu/cli",
3
- "version": "1.6.6",
3
+ "version": "1.6.7",
4
4
  "private": false,
5
5
  "license": "BUSL-1.1",
6
6
  "publishConfig": {