@onborn/billing 0.1.0-beta.2 → 0.1.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/adapters/nativeStores.d.ts +1 -0
- package/dist/adapters/nativeStores.js +2 -1
- package/dist/client.d.ts +5 -0
- package/dist/client.js +28 -1
- package/dist/validation.js +13 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.0-beta.3
|
|
4
|
+
|
|
5
|
+
- Fixed StoreKit 2 purchases incorrectly using the signed transaction JWS as
|
|
6
|
+
the transaction identifier.
|
|
7
|
+
- Bounded purchase idempotency keys when only a signed purchase token is
|
|
8
|
+
available.
|
|
9
|
+
- Added structured billing request errors with backend messages and codes.
|
|
10
|
+
|
|
3
11
|
## 0.1.0-beta.2
|
|
4
12
|
|
|
5
13
|
- Removed `offeringId` from `useOnbornOffering` and
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { NativeStoreRestoredPurchase } from "@onborn/sdk-contracts";
|
|
2
2
|
import type { OnbornBillingAdapter, OnbornLoadProductsInput, OnbornPurchaseInput, OnbornRestoreInput } from "../types";
|
|
3
3
|
type NativeStoresPurchase = {
|
|
4
|
+
id?: string;
|
|
4
5
|
productId?: string;
|
|
5
6
|
storeProductId?: string;
|
|
6
7
|
transactionId?: string;
|
|
@@ -143,6 +143,7 @@ function normalizeNativeRestoredPurchase(value) {
|
|
|
143
143
|
store,
|
|
144
144
|
storeProductId,
|
|
145
145
|
transactionId: readString(record.transactionId) ??
|
|
146
|
+
readString(record.id) ??
|
|
146
147
|
readString(record.originalTransactionIdentifierIOS),
|
|
147
148
|
purchaseToken: readString(record.purchaseToken),
|
|
148
149
|
raw: record.raw ?? value,
|
|
@@ -150,7 +151,7 @@ function normalizeNativeRestoredPurchase(value) {
|
|
|
150
151
|
}
|
|
151
152
|
function readTransactionId(purchase) {
|
|
152
153
|
return (purchase?.transactionId ??
|
|
153
|
-
purchase?.
|
|
154
|
+
purchase?.id ??
|
|
154
155
|
purchase?.originalTransactionIdentifierIOS);
|
|
155
156
|
}
|
|
156
157
|
function readString(value) {
|
package/dist/client.d.ts
CHANGED
|
@@ -2,6 +2,11 @@ import { type CustomerEntitlementsResponse, type GetOfferingResponse, type GetPa
|
|
|
2
2
|
export type BillingClientOptions = {
|
|
3
3
|
sourceId?: string;
|
|
4
4
|
};
|
|
5
|
+
export declare class OnbornBillingRequestError extends Error {
|
|
6
|
+
readonly status: number;
|
|
7
|
+
readonly code?: string | undefined;
|
|
8
|
+
constructor(message: string, status: number, code?: string | undefined);
|
|
9
|
+
}
|
|
5
10
|
export declare class BillingClient {
|
|
6
11
|
private readonly options;
|
|
7
12
|
private readonly config;
|
package/dist/client.js
CHANGED
|
@@ -2,6 +2,16 @@ import { Onborn, } from "@onborn/analytics";
|
|
|
2
2
|
import { resolveOnbornBillingConfig } from "./runtime";
|
|
3
3
|
import { CustomerEntitlementsResponseSchema, GetOfferingResponseSchema, GetPaywallResponseSchema, PurchaseValidationResponseSchema, } from "@onborn/sdk-contracts";
|
|
4
4
|
const ONBORN_API_BASE_URL = "https://api.testing.onborn.app";
|
|
5
|
+
export class OnbornBillingRequestError extends Error {
|
|
6
|
+
status;
|
|
7
|
+
code;
|
|
8
|
+
constructor(message, status, code) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.status = status;
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.name = "OnbornBillingRequestError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
5
15
|
export class BillingClient {
|
|
6
16
|
options;
|
|
7
17
|
config;
|
|
@@ -113,7 +123,8 @@ export class BillingClient {
|
|
|
113
123
|
body: JSON.stringify(payload),
|
|
114
124
|
});
|
|
115
125
|
if (!response.ok) {
|
|
116
|
-
|
|
126
|
+
const failure = await readBillingFailure(response);
|
|
127
|
+
throw new OnbornBillingRequestError(failure.message ?? `Purchase request failed (${response.status})`, response.status, failure.code);
|
|
117
128
|
}
|
|
118
129
|
const parsed = PurchaseValidationResponseSchema.safeParse(await response.json());
|
|
119
130
|
if (!parsed.success) {
|
|
@@ -135,6 +146,22 @@ export class BillingClient {
|
|
|
135
146
|
});
|
|
136
147
|
}
|
|
137
148
|
}
|
|
149
|
+
async function readBillingFailure(response) {
|
|
150
|
+
try {
|
|
151
|
+
const payload = (await response.json());
|
|
152
|
+
return {
|
|
153
|
+
message: typeof payload.error === "string"
|
|
154
|
+
? payload.error
|
|
155
|
+
: typeof payload.message === "string"
|
|
156
|
+
? payload.message
|
|
157
|
+
: undefined,
|
|
158
|
+
code: typeof payload.code === "string" ? payload.code : undefined,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return {};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
138
165
|
export function createBillingClient(options = {}) {
|
|
139
166
|
return new BillingClient(options);
|
|
140
167
|
}
|
package/dist/validation.js
CHANGED
|
@@ -44,7 +44,7 @@ export async function validateBillingRestore(input) {
|
|
|
44
44
|
}
|
|
45
45
|
function createPurchaseIdempotencyKey(input) {
|
|
46
46
|
const stablePart = input.result.transactionId ??
|
|
47
|
-
input.result.purchaseToken ??
|
|
47
|
+
fingerprintIdempotencyValue(input.result.purchaseToken) ??
|
|
48
48
|
input.result.productId ??
|
|
49
49
|
input.item.product?.storeProductId ??
|
|
50
50
|
input.item.package.id;
|
|
@@ -55,6 +55,18 @@ function createPurchaseIdempotencyKey(input) {
|
|
|
55
55
|
stablePart,
|
|
56
56
|
].join(":");
|
|
57
57
|
}
|
|
58
|
+
function fingerprintIdempotencyValue(value) {
|
|
59
|
+
if (!value)
|
|
60
|
+
return undefined;
|
|
61
|
+
let first = 0x811c9dc5;
|
|
62
|
+
let second = 0x9e3779b9;
|
|
63
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
64
|
+
const code = value.charCodeAt(index);
|
|
65
|
+
first = Math.imul(first ^ code, 0x01000193);
|
|
66
|
+
second = Math.imul(second ^ code, 0x85ebca6b);
|
|
67
|
+
}
|
|
68
|
+
return `${(first >>> 0).toString(36)}${(second >>> 0).toString(36)}`;
|
|
69
|
+
}
|
|
58
70
|
function createRestoreIdempotencyKey(input) {
|
|
59
71
|
return ["restore", input.offering?.id ?? "unknown", String(Date.now())].join(":");
|
|
60
72
|
}
|