@neetru/sdk 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/ai.d.cts +1 -1
- package/dist/ai.d.ts +1 -1
- package/dist/auth.cjs +179 -2
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/auth.mjs +179 -2
- package/dist/auth.mjs.map +1 -1
- package/dist/catalog.d.cts +1 -1
- package/dist/catalog.d.ts +1 -1
- package/dist/checkout.d.cts +1 -1
- package/dist/checkout.d.ts +1 -1
- package/dist/db-react.d.cts +1 -1
- package/dist/db-react.d.ts +1 -1
- package/dist/db.cjs +17 -0
- package/dist/db.cjs.map +1 -1
- package/dist/db.d.cts +1 -1
- package/dist/db.d.ts +1 -1
- package/dist/db.mjs +17 -1
- package/dist/db.mjs.map +1 -1
- package/dist/entitlements.d.cts +1 -1
- package/dist/entitlements.d.ts +1 -1
- package/dist/firestore-compat.d.cts +1 -1
- package/dist/firestore-compat.d.ts +1 -1
- package/dist/index.cjs +180 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +180 -3
- package/dist/index.mjs.map +1 -1
- package/dist/mocks.cjs +68 -1
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.cts +17 -1
- package/dist/mocks.d.ts +17 -1
- package/dist/mocks.mjs +68 -1
- package/dist/mocks.mjs.map +1 -1
- package/dist/notifications.d.cts +1 -1
- package/dist/notifications.d.ts +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/support.cjs +98 -1
- package/dist/support.cjs.map +1 -1
- package/dist/support.d.cts +1 -1
- package/dist/support.d.ts +1 -1
- package/dist/support.mjs +98 -1
- package/dist/support.mjs.map +1 -1
- package/dist/telemetry.d.cts +1 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/{types-DQplLXIk.d.cts → types-BoFSCHF_.d.cts} +117 -2
- package/dist/{types-DslphKIM.d.ts → types-DdJyqBy-.d.ts} +117 -2
- package/dist/usage.d.cts +1 -1
- package/dist/usage.d.ts +1 -1
- package/dist/webhooks.d.cts +1 -1
- package/dist/webhooks.d.ts +1 -1
- package/package.json +1 -1
package/dist/auth.d.cts
CHANGED
package/dist/auth.d.ts
CHANGED
package/dist/auth.mjs
CHANGED
|
@@ -1582,6 +1582,7 @@ function toTicket(raw) {
|
|
|
1582
1582
|
if (typeof r.id !== "string") {
|
|
1583
1583
|
throw new NeetruError("invalid_response", "Ticket missing id");
|
|
1584
1584
|
}
|
|
1585
|
+
const firstAttachment = Array.isArray(r.attachments) && typeof r.attachments[0] === "string" ? r.attachments[0] : void 0;
|
|
1585
1586
|
return {
|
|
1586
1587
|
id: r.id,
|
|
1587
1588
|
subject: typeof r.subject === "string" ? r.subject : "",
|
|
@@ -1590,9 +1591,28 @@ function toTicket(raw) {
|
|
|
1590
1591
|
status: VALID_STATUSES.includes(r.status) ? r.status : "open",
|
|
1591
1592
|
createdAt: typeof r.createdAt === "string" ? r.createdAt : (/* @__PURE__ */ new Date()).toISOString(),
|
|
1592
1593
|
updatedAt: typeof r.updatedAt === "string" ? r.updatedAt : void 0,
|
|
1593
|
-
productSlug: typeof r.productId === "string" ? r.productId : typeof r.productSlug === "string" ? r.productSlug : void 0
|
|
1594
|
+
productSlug: typeof r.productId === "string" ? r.productId : typeof r.productSlug === "string" ? r.productSlug : void 0,
|
|
1595
|
+
pageUrl: typeof r.pageUrl === "string" ? r.pageUrl : null,
|
|
1596
|
+
screenshotUrl: typeof r.screenshotUrl === "string" ? r.screenshotUrl : firstAttachment ?? null,
|
|
1597
|
+
resolvedAt: typeof r.resolvedAt === "string" ? r.resolvedAt : null,
|
|
1598
|
+
resolvedNotifiedAt: typeof r.resolvedNotifiedAt === "string" ? r.resolvedNotifiedAt : null,
|
|
1599
|
+
satisfactionAttempts: typeof r.satisfactionAttempts === "number" && Number.isFinite(r.satisfactionAttempts) ? r.satisfactionAttempts : 0,
|
|
1600
|
+
lastSatisfactionAttemptAt: typeof r.lastSatisfactionAttemptAt === "string" ? r.lastSatisfactionAttemptAt : null,
|
|
1601
|
+
satisfiedAt: typeof r.satisfiedAt === "string" ? r.satisfiedAt : null,
|
|
1602
|
+
rating: typeof r.rating === "number" && Number.isFinite(r.rating) ? r.rating : null,
|
|
1603
|
+
satisfactionComment: typeof r.satisfactionComment === "string" ? r.satisfactionComment : null
|
|
1594
1604
|
};
|
|
1595
1605
|
}
|
|
1606
|
+
function assertTicketId(ticketId) {
|
|
1607
|
+
if (!ticketId || typeof ticketId !== "string") {
|
|
1608
|
+
throw new NeetruError("validation_failed", "ticketId is required");
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
function assertValidComment(comment) {
|
|
1612
|
+
if (typeof comment === "string" && comment.length > 2e3) {
|
|
1613
|
+
throw new NeetruError("validation_failed", "comment max 2000 chars");
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1596
1616
|
function resolveProductId(config, ...candidates) {
|
|
1597
1617
|
for (const c of candidates) {
|
|
1598
1618
|
if (typeof c === "string" && c.length > 0) {
|
|
@@ -1649,6 +1669,15 @@ function createSupportNamespace(config) {
|
|
|
1649
1669
|
if (input.metadata && typeof input.metadata === "object") {
|
|
1650
1670
|
body.metadata = input.metadata;
|
|
1651
1671
|
}
|
|
1672
|
+
if (typeof input.pageUrl === "string") {
|
|
1673
|
+
body.pageUrl = input.pageUrl;
|
|
1674
|
+
}
|
|
1675
|
+
if (typeof input.screenshotBase64 === "string") {
|
|
1676
|
+
body.screenshotBase64 = input.screenshotBase64;
|
|
1677
|
+
}
|
|
1678
|
+
if (typeof input.consoleLogs === "string") {
|
|
1679
|
+
body.consoleLogs = input.consoleLogs;
|
|
1680
|
+
}
|
|
1652
1681
|
const raw = await httpRequest(config, {
|
|
1653
1682
|
method: "POST",
|
|
1654
1683
|
path: "/api/sdk/v1/support/tickets",
|
|
@@ -1674,6 +1703,74 @@ function createSupportNamespace(config) {
|
|
|
1674
1703
|
});
|
|
1675
1704
|
const list = Array.isArray(raw) ? raw : raw && typeof raw === "object" && "tickets" in raw ? raw.tickets ?? [] : [];
|
|
1676
1705
|
return list.map(toTicket);
|
|
1706
|
+
},
|
|
1707
|
+
/**
|
|
1708
|
+
* 3.4: marca a notificação de resolução como vista (`resolvedNotifiedAt`,
|
|
1709
|
+
* idempotente no Core). Endpoint canonical:
|
|
1710
|
+
* `POST /api/sdk/v1/support/tickets/{id}/resolved-seen`.
|
|
1711
|
+
*/
|
|
1712
|
+
async markResolvedSeen(ticketId) {
|
|
1713
|
+
assertTicketId(ticketId);
|
|
1714
|
+
await httpRequest(config, {
|
|
1715
|
+
method: "POST",
|
|
1716
|
+
path: `/api/sdk/v1/support/tickets/${encodeURIComponent(ticketId)}/resolved-seen`,
|
|
1717
|
+
requireAuth: true
|
|
1718
|
+
});
|
|
1719
|
+
},
|
|
1720
|
+
/**
|
|
1721
|
+
* 3.4: registra uma tentativa de exibição do modal de satisfação
|
|
1722
|
+
* (`satisfactionAttempts += 1`). Chamar no SHOW do modal, não na
|
|
1723
|
+
* resposta. Endpoint canonical:
|
|
1724
|
+
* `POST /api/sdk/v1/support/tickets/{id}/satisfaction-attempt`.
|
|
1725
|
+
*/
|
|
1726
|
+
async recordSatisfactionAttempt(ticketId) {
|
|
1727
|
+
assertTicketId(ticketId);
|
|
1728
|
+
await httpRequest(config, {
|
|
1729
|
+
method: "POST",
|
|
1730
|
+
path: `/api/sdk/v1/support/tickets/${encodeURIComponent(ticketId)}/satisfaction-attempt`,
|
|
1731
|
+
requireAuth: true
|
|
1732
|
+
});
|
|
1733
|
+
},
|
|
1734
|
+
/**
|
|
1735
|
+
* 3.4: envia (ou pula) a avaliação de satisfação (CSAT 1-5). Endpoint
|
|
1736
|
+
* canonical: `POST /api/sdk/v1/support/tickets/{id}/satisfaction`.
|
|
1737
|
+
*/
|
|
1738
|
+
async submitSatisfaction(input) {
|
|
1739
|
+
if (!input || typeof input !== "object") {
|
|
1740
|
+
throw new NeetruError("validation_failed", "input is required");
|
|
1741
|
+
}
|
|
1742
|
+
assertTicketId(input.ticketId);
|
|
1743
|
+
if (input.rating !== null && input.rating !== void 0) {
|
|
1744
|
+
if (!Number.isInteger(input.rating) || input.rating < 1 || input.rating > 5) {
|
|
1745
|
+
throw new NeetruError("validation_failed", "rating must be an integer 1-5 or null");
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
assertValidComment(input.comment);
|
|
1749
|
+
await httpRequest(config, {
|
|
1750
|
+
method: "POST",
|
|
1751
|
+
path: `/api/sdk/v1/support/tickets/${encodeURIComponent(input.ticketId)}/satisfaction`,
|
|
1752
|
+
body: {
|
|
1753
|
+
rating: input.rating ?? null,
|
|
1754
|
+
comment: input.comment ?? null,
|
|
1755
|
+
skipped: input.skipped
|
|
1756
|
+
},
|
|
1757
|
+
requireAuth: true
|
|
1758
|
+
});
|
|
1759
|
+
},
|
|
1760
|
+
/**
|
|
1761
|
+
* 3.4: contesta um ticket resolvido — reabre e zera o ciclo de
|
|
1762
|
+
* satisfação/notificação. Endpoint canonical:
|
|
1763
|
+
* `POST /api/sdk/v1/support/tickets/{id}/contest`.
|
|
1764
|
+
*/
|
|
1765
|
+
async contestTicket(ticketId, opts) {
|
|
1766
|
+
assertTicketId(ticketId);
|
|
1767
|
+
assertValidComment(opts?.comment);
|
|
1768
|
+
await httpRequest(config, {
|
|
1769
|
+
method: "POST",
|
|
1770
|
+
path: `/api/sdk/v1/support/tickets/${encodeURIComponent(ticketId)}/contest`,
|
|
1771
|
+
body: { comment: opts?.comment ?? void 0 },
|
|
1772
|
+
requireAuth: true
|
|
1773
|
+
});
|
|
1677
1774
|
}
|
|
1678
1775
|
};
|
|
1679
1776
|
}
|
|
@@ -5094,7 +5191,20 @@ function buildTicketProvider(config, opts) {
|
|
|
5094
5191
|
return ticket;
|
|
5095
5192
|
};
|
|
5096
5193
|
}
|
|
5194
|
+
var _hasWarnedMissingDbId = false;
|
|
5195
|
+
function warnMissingDbIdOnce(config, dbOpts) {
|
|
5196
|
+
if (_hasWarnedMissingDbId) return;
|
|
5197
|
+
if (dbOpts.dbId) return;
|
|
5198
|
+
if (config.env === "prod") return;
|
|
5199
|
+
if (typeof window === "undefined") return;
|
|
5200
|
+
if (typeof console === "undefined" || typeof console.warn !== "function") return;
|
|
5201
|
+
_hasWarnedMissingDbId = true;
|
|
5202
|
+
console.warn(
|
|
5203
|
+
"[neetru/sdk] client.db sem `dbId` expl\xEDcito: escritas client-side (add/set/update/remove/list) caem no datastore gen\xE9rico do Core, escopado por tenant/produto (header x-neetru-tenant) \u2014 `dbId` s\xF3 nomeia o cache offline LOCAL (IndexedDB), n\xE3o roteia nem escopa nada no servidor. Veja o JSDoc de NeetruDbOptions.dbId."
|
|
5204
|
+
);
|
|
5205
|
+
}
|
|
5097
5206
|
function createNeetruDb(config, dbOpts = {}) {
|
|
5207
|
+
warnMissingDbIdOnce(config, dbOpts);
|
|
5098
5208
|
let resolvedTransport;
|
|
5099
5209
|
if (dbOpts.transport !== void 0) {
|
|
5100
5210
|
resolvedTransport = dbOpts.transport;
|
|
@@ -6517,7 +6627,18 @@ var MockSupport = class {
|
|
|
6517
6627
|
severity: input.severity ?? "normal",
|
|
6518
6628
|
status: "open",
|
|
6519
6629
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6520
|
-
productSlug: input.productSlug
|
|
6630
|
+
productSlug: input.productSlug,
|
|
6631
|
+
// 3.4 (product-feedback): espelha o contrato — campos novos nullable,
|
|
6632
|
+
// populados a partir do input quando fornecidos.
|
|
6633
|
+
pageUrl: typeof input.pageUrl === "string" ? input.pageUrl : null,
|
|
6634
|
+
screenshotUrl: typeof input.screenshotBase64 === "string" ? input.screenshotBase64 : null,
|
|
6635
|
+
resolvedAt: null,
|
|
6636
|
+
resolvedNotifiedAt: null,
|
|
6637
|
+
satisfactionAttempts: 0,
|
|
6638
|
+
lastSatisfactionAttemptAt: null,
|
|
6639
|
+
satisfiedAt: null,
|
|
6640
|
+
rating: null,
|
|
6641
|
+
satisfactionComment: null
|
|
6521
6642
|
};
|
|
6522
6643
|
this._tickets.push(ticket);
|
|
6523
6644
|
return ticket;
|
|
@@ -6528,6 +6649,62 @@ var MockSupport = class {
|
|
|
6528
6649
|
}
|
|
6529
6650
|
return [...this._tickets];
|
|
6530
6651
|
}
|
|
6652
|
+
_find(ticketId) {
|
|
6653
|
+
if (!ticketId || typeof ticketId !== "string") {
|
|
6654
|
+
throw new NeetruError("validation_failed", "ticketId is required");
|
|
6655
|
+
}
|
|
6656
|
+
const ticket = this._tickets.find((t) => t.id === ticketId);
|
|
6657
|
+
if (!ticket) {
|
|
6658
|
+
throw new NeetruError("not_found", `ticket ${ticketId} not found`);
|
|
6659
|
+
}
|
|
6660
|
+
return ticket;
|
|
6661
|
+
}
|
|
6662
|
+
/** 3.4: espelha `markResolvedSeen` — idempotente (só seta se ainda null). */
|
|
6663
|
+
async markResolvedSeen(ticketId) {
|
|
6664
|
+
const ticket = this._find(ticketId);
|
|
6665
|
+
if (ticket.resolvedNotifiedAt === null) {
|
|
6666
|
+
ticket.resolvedNotifiedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6667
|
+
}
|
|
6668
|
+
}
|
|
6669
|
+
/** 3.4: espelha `recordSatisfactionAttempt` — incrementa contador. */
|
|
6670
|
+
async recordSatisfactionAttempt(ticketId) {
|
|
6671
|
+
const ticket = this._find(ticketId);
|
|
6672
|
+
ticket.satisfactionAttempts += 1;
|
|
6673
|
+
ticket.lastSatisfactionAttemptAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6674
|
+
}
|
|
6675
|
+
/** 3.4: espelha `submitSatisfaction` — terminal, seta `satisfiedAt`. */
|
|
6676
|
+
async submitSatisfaction(input) {
|
|
6677
|
+
if (!input || typeof input !== "object") {
|
|
6678
|
+
throw new NeetruError("validation_failed", "input is required");
|
|
6679
|
+
}
|
|
6680
|
+
if (input.rating !== null && input.rating !== void 0) {
|
|
6681
|
+
if (!Number.isInteger(input.rating) || input.rating < 1 || input.rating > 5) {
|
|
6682
|
+
throw new NeetruError("validation_failed", "rating must be an integer 1-5 or null");
|
|
6683
|
+
}
|
|
6684
|
+
}
|
|
6685
|
+
if (typeof input.comment === "string" && input.comment.length > 2e3) {
|
|
6686
|
+
throw new NeetruError("validation_failed", "comment max 2000 chars");
|
|
6687
|
+
}
|
|
6688
|
+
const ticket = this._find(input.ticketId);
|
|
6689
|
+
ticket.satisfiedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6690
|
+
ticket.rating = input.rating ?? null;
|
|
6691
|
+
ticket.satisfactionComment = input.comment ?? null;
|
|
6692
|
+
}
|
|
6693
|
+
/** 3.4: espelha `contestTicket` — reabre e zera o ciclo de satisfação. */
|
|
6694
|
+
async contestTicket(ticketId, opts) {
|
|
6695
|
+
if (typeof opts?.comment === "string" && opts.comment.length > 2e3) {
|
|
6696
|
+
throw new NeetruError("validation_failed", "comment max 2000 chars");
|
|
6697
|
+
}
|
|
6698
|
+
const ticket = this._find(ticketId);
|
|
6699
|
+
ticket.status = "open";
|
|
6700
|
+
ticket.resolvedAt = null;
|
|
6701
|
+
ticket.resolvedNotifiedAt = null;
|
|
6702
|
+
ticket.satisfactionAttempts = 0;
|
|
6703
|
+
ticket.lastSatisfactionAttemptAt = null;
|
|
6704
|
+
ticket.satisfiedAt = null;
|
|
6705
|
+
ticket.rating = null;
|
|
6706
|
+
ticket.satisfactionComment = null;
|
|
6707
|
+
}
|
|
6531
6708
|
/** Test helper. */
|
|
6532
6709
|
__reset() {
|
|
6533
6710
|
this._tickets = [];
|