@tinkerlandai/indiana-react-native 0.9.5 → 0.10.1
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 +3 -3
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +37281 -3203
- package/dist/index.d.ts +37281 -3203
- package/dist/index.js +2 -2
- package/native-sdk/android/java/ai/tinkerland/indiana/CustomerResponseSemantics.kt +7 -3
- package/native-sdk/android/java/ai/tinkerland/indiana/CustomerSemantics.kt +3 -3
- package/native-sdk/android/java/ai/tinkerland/indiana/GeneratedProtocol.kt +1 -1
- package/native-sdk/android/java/ai/tinkerland/indiana/IndianaClient.kt +2 -2
- package/native-sdk/android/java/ai/tinkerland/indiana/MerchantCommerceSemantics.kt +38 -0
- package/native-sdk/android/java/ai/tinkerland/indiana/NativeStoreOffer.kt +1 -1
- package/native-sdk/android/java/ai/tinkerland/indiana/SDKVersion.kt +1 -1
- package/native-sdk/android/resources/funnel-wire-schemas.json +1 -1
- package/native-sdk/ios/CustomerResponseSemantics.swift +7 -3
- package/native-sdk/ios/CustomerSemantics.swift +3 -3
- package/native-sdk/ios/GeneratedProtocol.swift +1 -1
- package/native-sdk/ios/IndianaClient.swift +2 -2
- package/native-sdk/ios/MerchantCommerceSemantics.swift +51 -0
- package/native-sdk/ios/NativeStoreOffer.swift +1 -1
- package/native-sdk/ios/SDKVersion.swift +1 -1
- package/native-sdk/ios/funnel-wire-schemas.json +1 -1
- package/package.json +1 -1
|
@@ -61,6 +61,7 @@ enum IndianaCustomerResponseSemantics {
|
|
|
61
61
|
}
|
|
62
62
|
static func object(_ input: O, fields: Set<String>, path: [String]) throws -> O {
|
|
63
63
|
var v = input
|
|
64
|
+
try IndianaMerchantCommerceSemantics.validate(v, fields: fields)
|
|
64
65
|
func has(_ keys: [String]) -> Bool { Set(keys).isSubset(of: fields) }
|
|
65
66
|
if has(["productKind", "seatBundle", "applePromotionalOffer", "replacement", "offerKind"]) {
|
|
66
67
|
let apple = s(v["provider"]) == "apple", member = s(v["productKind"]) == "membership", kind = s(v["offerKind"]), replacement = o(v["replacement"]), proof = o(v["applePromotionalOffer"])
|
|
@@ -107,7 +108,7 @@ enum IndianaCustomerResponseSemantics {
|
|
|
107
108
|
if has(["operationId", "lines", "discount", "charge", "nativeOffer", "execution"]) { try attachQuote(v) }
|
|
108
109
|
if has(["executor", "checkoutUrl", "execution"]) {
|
|
109
110
|
try require(nilValue(v["execution"]) || s(v["executor"]) == "merchant")
|
|
110
|
-
if has(["quoteFinalized", "orderId"]) { try require(nilValue(v["checkoutUrl"]) || s(v["executor"]) == "indiana") }
|
|
111
|
+
if has(["quoteFinalized", "orderId"]) { try require(nilValue(v["checkoutUrl"]) || s(v["executor"]) == "indiana" || s(o(v["merchantExecution"])["type"]) == "purchase") }
|
|
111
112
|
if !nilValue(v["checkoutUrl"]) { try require(URL(string: s(v["checkoutUrl"]))?.scheme == "https") }
|
|
112
113
|
}
|
|
113
114
|
if has(["action", "executor", "update", "cancel", "schedule", "release"]) {
|
|
@@ -187,7 +188,10 @@ enum IndianaCustomerResponseSemantics {
|
|
|
187
188
|
}
|
|
188
189
|
static func attachQuote(_ v: O) throws {
|
|
189
190
|
let lines = a(v["lines"]), trial = o(lines.first?["trial"]), execution = o(v["execution"]), discount = o(v["discount"]), provider = s(v["provider"])
|
|
190
|
-
if provider == "
|
|
191
|
+
if provider == "merchant" {
|
|
192
|
+
try require(s(execution["provider"]) == "merchant" && s(execution["operationId"]) == s(v["operationId"]) && n(execution["catalogAmountMinor"]) == n(v["catalogAmountMinor"]) && s(execution["currency"]) == s(v["currency"]) && time(execution["expiresAt"]) <= time(v["expiresAt"]))
|
|
193
|
+
try require(nilValue(execution["trialPeriodDays"]) == trial.isEmpty && (trial.isEmpty || n(execution["trialPeriodDays"]) == n(trial["days"])) && s(o(execution["discount"])["grantId"]) == s(discount["offerId"]) && v["nativeOffer"] == nil)
|
|
194
|
+
} else if provider == "stripe" {
|
|
191
195
|
if trial["cardRequired"] as? Bool == false && o(execution["invoiceMode"])["enabled"] as? Bool != true { try require(execution.isEmpty && discount.isEmpty) }
|
|
192
196
|
else {
|
|
193
197
|
try require(!execution.isEmpty && s(o(execution["metadata"])["grooveCheckoutId"]) == s(v["operationId"]) && time(execution["expiresAt"]) <= time(v["expiresAt"]))
|
|
@@ -200,7 +204,7 @@ enum IndianaCustomerResponseSemantics {
|
|
|
200
204
|
try require(v["nativeOffer"] == nil)
|
|
201
205
|
} else { let selection = o(v["nativeOffer"]); try require(execution.isEmpty && !selection.isEmpty && lines.count == 1 && n(selection["discountMinor"]) <= n(v["catalogAmountMinor"]) && nilValue(selection["trialDays"]) == trial.isEmpty && (trial.isEmpty || n(selection["trialDays"]) == n(trial["days"])) && (discount.isEmpty || n(selection["discountMinor"]) == n(discount["amountMinor"]))) }
|
|
202
206
|
if !discount.isEmpty {
|
|
203
|
-
let allocations = a(discount["allocations"]); try require(nilValue(v["billingSubscriptionId"]) && (
|
|
207
|
+
let allocations = a(discount["allocations"]); try require(nilValue(v["billingSubscriptionId"]) && (["stripe", "merchant"].contains(provider) || s(o(discount["duration"])["type"]) == "once") && n(discount["amountMinor"]) <= n(v["catalogAmountMinor"]) && allocations.count == lines.count)
|
|
204
208
|
for (row, line) in zip(allocations, lines) { try require(s(row["productVersionId"]) == s(line["productVersionId"]) && n(row["amountMinor"]) <= n(line["catalogAmountMinor"])) }; try require(allocations.reduce(0) { $0 + n($1["amountMinor"]) } == n(discount["amountMinor"]))
|
|
205
209
|
}
|
|
206
210
|
if let charge = v["charge"] as? O { try require(!nilValue(v["billingSubscriptionId"]) && n(charge["totalMinor"]) == n(charge["debitMinor"]) - n(charge["discountMinor"]) + n(charge["taxMinor"]) && n(charge["discountMinor"]) <= n(charge["debitMinor"]) && time(charge["periodEndsAt"]) > time(charge["effectiveAt"])) }
|
|
@@ -31,9 +31,9 @@ enum IndianaCustomerSemantics {
|
|
|
31
31
|
let plans = array(value["plans"]), provider = value["provider"]?.string
|
|
32
32
|
try require(Set(plans.compactMap { $0.object?["productVersionId"]?.string }).count == plans.count)
|
|
33
33
|
try require(plans.allSatisfy { ($0.object?["featureQuantities"]?.object?.count ?? 0) <= 100 })
|
|
34
|
-
try require(value["offerId"] == nil || value["billingSubscriptionId"] == nil && (
|
|
35
|
-
try require(value["nativeOffer"] == nil ||
|
|
36
|
-
try require(value["newBillingSubscription"] == nil ||
|
|
34
|
+
try require(value["offerId"] == nil || value["billingSubscriptionId"] == nil && (["stripe", "merchant"].contains(provider) || value["nativeOffer"] != nil))
|
|
35
|
+
try require(value["nativeOffer"] == nil || ["apple", "google"].contains(provider) && plans.count == 1)
|
|
36
|
+
try require(value["newBillingSubscription"] == nil || ["stripe", "merchant"].contains(provider) && value["billingSubscriptionId"] == nil)
|
|
37
37
|
try require(value["invoiceMode"]?.object?["enabled"] != .bool(true) || provider == "stripe" && value["entityId"] == nil)
|
|
38
38
|
if let offer = value["nativeOffer"]?.object {
|
|
39
39
|
try require(offer["offerKind"] != .string("none") || offer["offerId"] == .null && offer["discountMinor"] == .number(0) && offer["trialDays"] == .null)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import Foundation
|
|
3
3
|
public enum IndianaEnvironment: String, Codable, Sendable { case sandbox, live }
|
|
4
4
|
enum IndianaProtocol {
|
|
5
|
-
static let wireProtocol = "0.
|
|
5
|
+
static let wireProtocol = "0.10"
|
|
6
6
|
static let uuidPattern = "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
|
|
7
7
|
static let utcPattern = "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
|
|
8
8
|
static let scopeKeys: Set<String> = ["projectId", "environment"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
|
|
3
|
-
public enum IndianaSubscriptionProvider: String, Sendable { case stripe, apple, google }
|
|
3
|
+
public enum IndianaSubscriptionProvider: String, Sendable { case stripe, apple, google, merchant }
|
|
4
4
|
public struct IndianaSubscriptionPlan: Sendable {
|
|
5
5
|
public let productVersionId: UUID
|
|
6
6
|
public let seatQuantities: [String: Int]
|
|
@@ -502,7 +502,7 @@ public actor IndianaClient {
|
|
|
502
502
|
var fields: [String: IndianaJSON] = ["requestId":.string(requestId.uuidString.lowercased()), "plans":.array(entries), "provider":.string(provider.rawValue), "currency":.string(currency)]
|
|
503
503
|
if let billingSubscriptionId { fields["billingSubscriptionId"] = .string(billingSubscriptionId.uuidString.lowercased()) }
|
|
504
504
|
guard nativeOffer == nil || (nativeOffer!.matches(provider) && plans.count == 1),
|
|
505
|
-
offerId == nil || (billingSubscriptionId == nil && (provider == .stripe || nativeOffer != nil)) else { throw IndianaClientError.invalidResponse }
|
|
505
|
+
offerId == nil || (billingSubscriptionId == nil && (provider == .stripe || provider == .merchant || nativeOffer != nil)) else { throw IndianaClientError.invalidResponse }
|
|
506
506
|
if let offerId { fields["offerId"] = .string(offerId.uuidString.lowercased()) }
|
|
507
507
|
if let nativeOffer { fields["nativeOffer"] = nativeOffer.wire }
|
|
508
508
|
let body: IndianaJSON = .object(fields)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
/// Merchant refinements dispatch on generated DTO fields, not user JSON.
|
|
4
|
+
enum IndianaMerchantCommerceSemantics {
|
|
5
|
+
static func validate(_ v: [String: Any], fields: Set<String>) throws {
|
|
6
|
+
func has(_ keys: [String]) -> Bool { Set(keys).isSubset(of: fields) }
|
|
7
|
+
let require = IndianaCustomerResponseSemantics.require
|
|
8
|
+
let o = IndianaCustomerResponseSemantics.o, a = IndianaCustomerResponseSemantics.a
|
|
9
|
+
let s = IndianaCustomerResponseSemantics.s, n = IndianaCustomerResponseSemantics.n
|
|
10
|
+
let nilValue = IndianaCustomerResponseSemantics.nilValue
|
|
11
|
+
if has(["configurationRevision", "connectionRevision", "lineItems", "catalogAmountMinor", "discount"]) {
|
|
12
|
+
let lines = a(v["lineItems"]), discount = o(v["discount"])
|
|
13
|
+
try require(lines.reduce(0) { $0 + n($1["totalMinor"]) } == n(v["catalogAmountMinor"]) && (discount.isEmpty || n(discount["amountMinor"]) <= n(v["catalogAmountMinor"])) && Set(lines.map { s($0["priceId"]) }).count == lines.count)
|
|
14
|
+
}
|
|
15
|
+
if has(["phase", "code", "reason", "retryable", "recovery"]), s(v["reason"]) == "RESULT_UNKNOWN" {
|
|
16
|
+
try require(v["retryable"] as? Bool == false && s(v["recovery"]) == "recover_operation")
|
|
17
|
+
}
|
|
18
|
+
if has(["merchantExecutionId", "paymentStatus", "checkoutUrl", "checkoutExpiresAt"]), !nilValue(v["checkoutUrl"]) {
|
|
19
|
+
try require(["not_started", "pending"].contains(s(v["paymentStatus"])) && !nilValue(v["checkoutExpiresAt"]))
|
|
20
|
+
}
|
|
21
|
+
if has(["merchantExecutionId", "scheduledFor", "status"]) || has(["provider", "eventId", "subscription", "scheduledFor", "status"]) {
|
|
22
|
+
try require((s(v["status"]) == "scheduled") == !nilValue(v["scheduledFor"]))
|
|
23
|
+
}
|
|
24
|
+
if has(["merchantExecutionId", "merchantRefundId", "status"]), s(v["status"]) == "succeeded" { try require(!nilValue(v["merchantRefundId"])) }
|
|
25
|
+
if has(["lookup", "operationId", "customerId", "execution"]), let execution = v["execution"] as? [String: Any] {
|
|
26
|
+
try require(s(execution["operationId"]) == s(v["operationId"]) && s(execution["customerId"]) == s(v["customerId"]))
|
|
27
|
+
}
|
|
28
|
+
if has(["scope", "operationId", "customerId", "confirmedAt", "initialExecutionAllowed", "instruction"]) {
|
|
29
|
+
let instruction = o(v["instruction"])
|
|
30
|
+
try require(s(instruction["operationId"]) == s(v["operationId"]) && s(instruction["customerId"]) == s(v["customerId"]))
|
|
31
|
+
}
|
|
32
|
+
if has(["merchantSubscriptionId", "periodStartsAt", "periodEndsAt", "items"]) {
|
|
33
|
+
let items = a(v["items"])
|
|
34
|
+
try require(IndianaCustomerResponseSemantics.time(v["periodEndsAt"]) > IndianaCustomerResponseSemantics.time(v["periodStartsAt"]) && Set(items.map { s($0["priceId"]) }).count == items.count)
|
|
35
|
+
}
|
|
36
|
+
if has(["merchantInvoiceId", "subtotalMinor", "discountMinor", "taxMinor", "totalMinor", "paidMinor"]) {
|
|
37
|
+
try require(n(v["subtotalMinor"]) - n(v["discountMinor"]) + n(v["taxMinor"]) == n(v["totalMinor"]) && n(v["discountMinor"]) <= n(v["subtotalMinor"]) && n(v["paidMinor"]) == n(v["totalMinor"]))
|
|
38
|
+
}
|
|
39
|
+
if has(["merchantInvoiceId", "lines", "paidMinor"]) {
|
|
40
|
+
let lines = a(v["lines"])
|
|
41
|
+
try require(Set(lines.map { s($0["merchantLineId"]) }).count == lines.count)
|
|
42
|
+
for key in ["subtotalMinor", "discountMinor", "taxMinor", "totalMinor"] { try require(lines.reduce(0) { $0 + n($1[key]) } == n(v[key])) }
|
|
43
|
+
}
|
|
44
|
+
if has(["merchantLineId", "subtotalMinor", "discountMinor", "taxMinor", "totalMinor"]) {
|
|
45
|
+
let subtotal = n(v["subtotalMinor"]), discount = n(v["discountMinor"]), tax = n(v["taxMinor"])
|
|
46
|
+
try require(subtotal - discount + tax == n(v["totalMinor"]) && (subtotal < 0 ? discount == 0 && tax == 0 : discount <= subtotal))
|
|
47
|
+
}
|
|
48
|
+
if has(["provider", "eventId", "merchantOrderId", "paymentStatus", "invoice"]), s(v["paymentStatus"]) == "paid" { try require(!nilValue(v["invoice"])) }
|
|
49
|
+
if has(["provider", "merchantInvoiceId", "cancelSubscriptions", "entitlementAction", "amountMinor"]) || has(["provider", "eventId", "merchantRefundId", "amountMinor", "status"]) { try require(n(v["amountMinor"]) > 0) }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -24,7 +24,7 @@ public struct IndianaNativeStoreOffer: Sendable {
|
|
|
24
24
|
|
|
25
25
|
func matches(_ provider: IndianaSubscriptionProvider) -> Bool {
|
|
26
26
|
switch provider {
|
|
27
|
-
case .stripe: return false
|
|
27
|
+
case .stripe, .merchant: return false
|
|
28
28
|
case .apple: return (offerKind == .promotional) == (offerID != nil)
|
|
29
29
|
case .google:
|
|
30
30
|
return (offerKind == .none) == (offerID == nil) &&
|