@neetru/sdk 1.0.0 → 1.1.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 +32 -1
- package/dist/auth.cjs +177 -1
- 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 +177 -1
- package/dist/auth.mjs.map +1 -1
- package/dist/catalog.d.cts +1 -1
- package/dist/catalog.d.ts +1 -1
- package/dist/checkout.cjs +275 -0
- package/dist/checkout.cjs.map +1 -0
- package/dist/checkout.d.cts +1 -0
- package/dist/checkout.d.ts +1 -0
- package/dist/checkout.mjs +272 -0
- package/dist/checkout.mjs.map +1 -0
- package/dist/db.d.cts +1 -1
- package/dist/db.d.ts +1 -1
- package/dist/entitlements.d.cts +1 -1
- package/dist/entitlements.d.ts +1 -1
- package/dist/index.cjs +180 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +179 -3
- package/dist/index.mjs.map +1 -1
- package/dist/mocks.d.cts +1 -1
- package/dist/mocks.d.ts +1 -1
- package/dist/react.cjs +158 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +112 -0
- package/dist/react.d.ts +112 -0
- package/dist/react.mjs +134 -0
- package/dist/react.mjs.map +1 -0
- package/dist/support.d.cts +1 -1
- package/dist/support.d.ts +1 -1
- package/dist/telemetry.d.cts +1 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/{types-PKUaFtBY.d.cts → types-BA53dd8S.d.cts} +83 -1
- package/dist/{types-PKUaFtBY.d.ts → types-BA53dd8S.d.ts} +83 -1
- package/dist/usage.d.cts +1 -1
- package/dist/usage.d.ts +1 -1
- package/package.json +18 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,12 +7,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
-
### Planned (post-1.
|
|
10
|
+
### Planned (post-1.1)
|
|
11
11
|
- Telemetry batching + flush on unload.
|
|
12
12
|
- LRU cache em entitlements.check (TTL configurável).
|
|
13
13
|
- size-limit budget no CI (<12KB gz core com db namespace).
|
|
14
14
|
- CDN distribution (`cdn.neetru.com/sdk/v1/`).
|
|
15
15
|
|
|
16
|
+
## [1.1.0] - 2026-05-08 — **Checkout namespace + React helpers**
|
|
17
|
+
|
|
18
|
+
Adiciona o namespace `client.checkout` (start/get/cancel intent) com auto-redirect
|
|
19
|
+
em browser. Suporte ao fluxo Sprint 13 onde produtos SaaS delegam checkout pro
|
|
20
|
+
portal `minhaconta.neetru.com` via `POST /api/v1/checkout/intents`.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- **`client.checkout.start({productId, planId, callbackUrl, tenantType?, tenantId?})`** — cria
|
|
24
|
+
`checkout_intents/{intentId}` no Core e (em browser) redireciona automaticamente
|
|
25
|
+
pra `minhaconta.neetru.com/portal/checkout/{intentId}`. Em Node/SSR retorna
|
|
26
|
+
`{intentId, redirectUrl}` sem efeito colateral.
|
|
27
|
+
- **`client.checkout.get(intentId)`** — lê estado atual do intent.
|
|
28
|
+
- **`client.checkout.cancel(intentId)`** — marca intent como `cancelled`.
|
|
29
|
+
- **Subpath `@neetru/sdk/react`** — componente `<CheckoutLink>` (wrapper de `<a>`
|
|
30
|
+
que dispara `start()` no click) + `<EntitlementGate mode="block|readonly">`
|
|
31
|
+
+ hook `useEntitlementContext()` pra desabilitar escritas quando free tier
|
|
32
|
+
estoura limite (decisão CEO §5 — read-only sempre, não hard-block).
|
|
33
|
+
- **`MockCheckout`** — implementação dev (`NEETRU_ENV=dev`) sem network. Retorna
|
|
34
|
+
URL fake `https://localhost:9003/portal/checkout/{intentId}` pra dev externo
|
|
35
|
+
testar UI sem provisionar conta Neetru.
|
|
36
|
+
- **Peer dep `react ^18 || ^19`** marcado opcional (só carregado se import `/react`).
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
- `VERSION` const bump `1.0.0 → 1.1.0`.
|
|
40
|
+
- `NeetruClient.checkout` adicionado — backward-compatible (caller que não usa
|
|
41
|
+
o namespace não é afetado).
|
|
42
|
+
|
|
43
|
+
### Notes
|
|
44
|
+
- API stability test (`api-surface-stability.test.ts`) atualizado pra incluir
|
|
45
|
+
`checkout` no inventário canônico.
|
|
46
|
+
|
|
16
47
|
## [1.0.0] - 2026-05-06 — **GA (General Availability)**
|
|
17
48
|
|
|
18
49
|
Marco de estabilidade. A partir desta versão, **a superfície pública do SDK
|
package/dist/auth.cjs
CHANGED
|
@@ -692,6 +692,181 @@ function createDbNamespace(config) {
|
|
|
692
692
|
};
|
|
693
693
|
}
|
|
694
694
|
|
|
695
|
+
// src/checkout.ts
|
|
696
|
+
function parseStartResponse(raw) {
|
|
697
|
+
if (!raw || typeof raw !== "object") {
|
|
698
|
+
throw new NeetruError("invalid_response", "checkout.start response is not an object");
|
|
699
|
+
}
|
|
700
|
+
const r = raw;
|
|
701
|
+
if (typeof r.intentId !== "string" || !r.intentId) {
|
|
702
|
+
throw new NeetruError("invalid_response", "checkout.start response missing intentId");
|
|
703
|
+
}
|
|
704
|
+
if (typeof r.redirectUrl !== "string" || !r.redirectUrl) {
|
|
705
|
+
throw new NeetruError("invalid_response", "checkout.start response missing redirectUrl");
|
|
706
|
+
}
|
|
707
|
+
return {
|
|
708
|
+
intentId: r.intentId,
|
|
709
|
+
redirectUrl: r.redirectUrl,
|
|
710
|
+
status: r.status ?? "pending",
|
|
711
|
+
expiresAt: typeof r.expiresAt === "string" ? r.expiresAt : (/* @__PURE__ */ new Date()).toISOString(),
|
|
712
|
+
requiresKyc: r.requiresKyc === true
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
function parseGetResponse(raw) {
|
|
716
|
+
if (!raw || typeof raw !== "object") {
|
|
717
|
+
throw new NeetruError("invalid_response", "checkout.get response is not an object");
|
|
718
|
+
}
|
|
719
|
+
const r = raw;
|
|
720
|
+
const intent = r.intent;
|
|
721
|
+
if (!intent || typeof intent !== "object") {
|
|
722
|
+
throw new NeetruError("invalid_response", "checkout.get response missing intent");
|
|
723
|
+
}
|
|
724
|
+
if (typeof intent.intentId !== "string") {
|
|
725
|
+
throw new NeetruError("invalid_response", "checkout.get response missing intentId");
|
|
726
|
+
}
|
|
727
|
+
return {
|
|
728
|
+
intentId: intent.intentId,
|
|
729
|
+
uid: intent.uid ?? "",
|
|
730
|
+
targetTenantId: intent.targetTenantId ?? "",
|
|
731
|
+
targetTenantType: intent.targetTenantType ?? "pf",
|
|
732
|
+
productId: intent.productId ?? "",
|
|
733
|
+
planId: intent.planId ?? "",
|
|
734
|
+
callbackUrl: intent.callbackUrl ?? "",
|
|
735
|
+
status: intent.status ?? "pending",
|
|
736
|
+
stripeSessionId: intent.stripeSessionId ?? null,
|
|
737
|
+
expiresAt: intent.expiresAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
738
|
+
isStale: r.isStale === true
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
function inBrowser() {
|
|
742
|
+
try {
|
|
743
|
+
return typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined" && typeof globalThis.location !== "undefined" && typeof globalThis.location.assign === "function";
|
|
744
|
+
} catch {
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
function performRedirect(url) {
|
|
749
|
+
try {
|
|
750
|
+
globalThis.location.assign(url);
|
|
751
|
+
} catch {
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
function createHttpCheckoutNamespace(config) {
|
|
755
|
+
return {
|
|
756
|
+
async start(input) {
|
|
757
|
+
if (!input?.productId) {
|
|
758
|
+
throw new NeetruError("validation_failed", "checkout.start: productId is required");
|
|
759
|
+
}
|
|
760
|
+
if (!input?.planId) {
|
|
761
|
+
throw new NeetruError("validation_failed", "checkout.start: planId is required");
|
|
762
|
+
}
|
|
763
|
+
if (!input?.callbackUrl) {
|
|
764
|
+
throw new NeetruError("validation_failed", "checkout.start: callbackUrl is required");
|
|
765
|
+
}
|
|
766
|
+
const body = {
|
|
767
|
+
productId: input.productId,
|
|
768
|
+
planId: input.planId,
|
|
769
|
+
callbackUrl: input.callbackUrl
|
|
770
|
+
};
|
|
771
|
+
if (input.tenantType) body.targetTenantType = input.tenantType;
|
|
772
|
+
if (input.tenantId) body.targetTenantId = input.tenantId;
|
|
773
|
+
const raw = await httpRequest(config, {
|
|
774
|
+
method: "POST",
|
|
775
|
+
path: "/api/v1/checkout/intents",
|
|
776
|
+
body,
|
|
777
|
+
requireAuth: true
|
|
778
|
+
});
|
|
779
|
+
const result = parseStartResponse(raw);
|
|
780
|
+
const shouldRedirect = input.autoRedirect !== false;
|
|
781
|
+
if (shouldRedirect && inBrowser()) {
|
|
782
|
+
performRedirect(result.redirectUrl);
|
|
783
|
+
}
|
|
784
|
+
return result;
|
|
785
|
+
},
|
|
786
|
+
async get(intentId) {
|
|
787
|
+
if (!intentId || typeof intentId !== "string") {
|
|
788
|
+
throw new NeetruError("validation_failed", "checkout.get: intentId is required");
|
|
789
|
+
}
|
|
790
|
+
const raw = await httpRequest(config, {
|
|
791
|
+
method: "GET",
|
|
792
|
+
path: `/api/v1/checkout/intents/${encodeURIComponent(intentId)}`,
|
|
793
|
+
requireAuth: true
|
|
794
|
+
});
|
|
795
|
+
return parseGetResponse(raw);
|
|
796
|
+
},
|
|
797
|
+
async cancel(intentId) {
|
|
798
|
+
if (!intentId || typeof intentId !== "string") {
|
|
799
|
+
throw new NeetruError("validation_failed", "checkout.cancel: intentId is required");
|
|
800
|
+
}
|
|
801
|
+
const raw = await httpRequest(config, {
|
|
802
|
+
method: "DELETE",
|
|
803
|
+
path: `/api/v1/checkout/intents/${encodeURIComponent(intentId)}`,
|
|
804
|
+
requireAuth: true
|
|
805
|
+
});
|
|
806
|
+
return {
|
|
807
|
+
ok: true,
|
|
808
|
+
alreadyCancelled: raw?.alreadyCancelled === true
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
var MockCheckout = class {
|
|
814
|
+
intents = /* @__PURE__ */ new Map();
|
|
815
|
+
async start(input) {
|
|
816
|
+
if (!input?.productId) {
|
|
817
|
+
throw new NeetruError("validation_failed", "checkout.start: productId is required");
|
|
818
|
+
}
|
|
819
|
+
if (!input?.planId) {
|
|
820
|
+
throw new NeetruError("validation_failed", "checkout.start: planId is required");
|
|
821
|
+
}
|
|
822
|
+
if (!input?.callbackUrl) {
|
|
823
|
+
throw new NeetruError("validation_failed", "checkout.start: callbackUrl is required");
|
|
824
|
+
}
|
|
825
|
+
const intentId = `chk_mock_${Math.random().toString(36).slice(2, 10)}`;
|
|
826
|
+
const expiresAt = new Date(Date.now() + 15 * 60 * 1e3).toISOString();
|
|
827
|
+
const redirectUrl = `https://localhost:9003/portal/checkout/${intentId}`;
|
|
828
|
+
this.intents.set(intentId, {
|
|
829
|
+
intentId,
|
|
830
|
+
uid: "dev-fixture-uid",
|
|
831
|
+
targetTenantId: input.tenantId ?? "dev-fixture-uid",
|
|
832
|
+
targetTenantType: input.tenantType ?? "pf",
|
|
833
|
+
productId: input.productId,
|
|
834
|
+
planId: input.planId,
|
|
835
|
+
callbackUrl: input.callbackUrl,
|
|
836
|
+
status: "pending",
|
|
837
|
+
stripeSessionId: null,
|
|
838
|
+
expiresAt
|
|
839
|
+
});
|
|
840
|
+
return {
|
|
841
|
+
intentId,
|
|
842
|
+
redirectUrl,
|
|
843
|
+
status: "pending",
|
|
844
|
+
expiresAt,
|
|
845
|
+
requiresKyc: false
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
async get(intentId) {
|
|
849
|
+
const found = this.intents.get(intentId);
|
|
850
|
+
if (!found) {
|
|
851
|
+
throw new NeetruError("not_found", `Mock intent ${intentId} not found`);
|
|
852
|
+
}
|
|
853
|
+
return { ...found };
|
|
854
|
+
}
|
|
855
|
+
async cancel(intentId) {
|
|
856
|
+
const found = this.intents.get(intentId);
|
|
857
|
+
if (!found) {
|
|
858
|
+
throw new NeetruError("not_found", `Mock intent ${intentId} not found`);
|
|
859
|
+
}
|
|
860
|
+
const alreadyCancelled = found.status === "cancelled";
|
|
861
|
+
this.intents.set(intentId, { ...found, status: "cancelled" });
|
|
862
|
+
return { ok: true, alreadyCancelled };
|
|
863
|
+
}
|
|
864
|
+
};
|
|
865
|
+
function createCheckoutNamespace(config) {
|
|
866
|
+
if (config.env === "dev") return new MockCheckout();
|
|
867
|
+
return createHttpCheckoutNamespace(config);
|
|
868
|
+
}
|
|
869
|
+
|
|
695
870
|
// src/mocks.ts
|
|
696
871
|
var DEV_FIXTURE_USER = Object.freeze({
|
|
697
872
|
uid: "dev-fixture-uid-0001",
|
|
@@ -1127,7 +1302,8 @@ function createNeetruClient(config = {}) {
|
|
|
1127
1302
|
telemetry: createTelemetryNamespace(resolved),
|
|
1128
1303
|
usage,
|
|
1129
1304
|
support,
|
|
1130
|
-
db
|
|
1305
|
+
db,
|
|
1306
|
+
checkout: createCheckoutNamespace(resolved)
|
|
1131
1307
|
});
|
|
1132
1308
|
return client;
|
|
1133
1309
|
}
|