@rdlabo/workers-hono-kit 0.6.9 → 0.6.11
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/iap/apple.d.ts +13 -5
- package/dist/iap/apple.js +9 -2
- package/dist/iap/google.d.ts +9 -3
- package/dist/iap/google.js +10 -7
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/payment/failure.js +1 -1
- package/dist/stripe/failure.d.ts +5 -4
- package/dist/stripe/failure.js +17 -2
- package/package.json +1 -1
package/dist/iap/apple.d.ts
CHANGED
|
@@ -40,6 +40,18 @@ export interface AppleVerifyReceiptResponse {
|
|
|
40
40
|
* - `unknown` — indeterminate (no receipt, or expired with auto-renew on and no retry) → no-op.
|
|
41
41
|
*/
|
|
42
42
|
export type AppleRenewalState = 'billing_retry' | 'lapsed' | 'active' | 'unknown';
|
|
43
|
+
/** Apple renewal classification plus the exact provider fields used to reach it. */
|
|
44
|
+
export interface AppleRenewalClassification {
|
|
45
|
+
state: AppleRenewalState;
|
|
46
|
+
originalTransactionId?: string;
|
|
47
|
+
expiresDateMs?: string;
|
|
48
|
+
/** Apple verifyReceipt response status (normally 0 for a successfully verified receipt). */
|
|
49
|
+
statusCode?: number;
|
|
50
|
+
/** Value from the pending-renewal entry matched to `originalTransactionId`. */
|
|
51
|
+
billingRetryStatus?: string;
|
|
52
|
+
/** Value from the pending-renewal entry matched to `originalTransactionId`. */
|
|
53
|
+
autoRenewStatus?: string;
|
|
54
|
+
}
|
|
43
55
|
/**
|
|
44
56
|
* Classify an Apple verifyReceipt response into an {@link AppleRenewalState}.
|
|
45
57
|
*
|
|
@@ -52,11 +64,7 @@ export type AppleRenewalState = 'billing_retry' | 'lapsed' | 'active' | 'unknown
|
|
|
52
64
|
* @param now - Current epoch-ms (`Date.now()`); injected for determinism/testing.
|
|
53
65
|
* @returns The state plus the latest `original_transaction_id` / `expires_date_ms` (for the row key).
|
|
54
66
|
*/
|
|
55
|
-
export declare function classifyAppleRenewal(verify: unknown, now: number):
|
|
56
|
-
state: AppleRenewalState;
|
|
57
|
-
originalTransactionId?: string;
|
|
58
|
-
expiresDateMs?: string;
|
|
59
|
-
};
|
|
67
|
+
export declare function classifyAppleRenewal(verify: unknown, now: number): AppleRenewalClassification;
|
|
60
68
|
/**
|
|
61
69
|
* Verify an App Store receipt against Apple, falling back from production to sandbox.
|
|
62
70
|
*
|
package/dist/iap/apple.js
CHANGED
|
@@ -23,6 +23,7 @@ const toArray = (v) => (Array.isArray(v) ? v : []);
|
|
|
23
23
|
*/
|
|
24
24
|
export function classifyAppleRenewal(verify, now) {
|
|
25
25
|
const v = asRecord(verify);
|
|
26
|
+
const statusCode = typeof v?.status === 'number' ? v.status : undefined;
|
|
26
27
|
// 消耗型など expires_date_ms 欠損エントリを除外してから最新(max expires)を選ぶ。
|
|
27
28
|
// 欠損値を Number() すると NaN で比較が常に false になり、先頭の欠損行が最後まで残って
|
|
28
29
|
// 誤って 'active'(isExpired=false)を返すため、有効な expires を持つ行だけを対象にする。
|
|
@@ -35,7 +36,7 @@ export function classifyAppleRenewal(verify, now) {
|
|
|
35
36
|
}, undefined);
|
|
36
37
|
const originalTransactionId = latest?.original_transaction_id;
|
|
37
38
|
if (!latest || !originalTransactionId) {
|
|
38
|
-
return { state: 'unknown' };
|
|
39
|
+
return { state: 'unknown', statusCode };
|
|
39
40
|
}
|
|
40
41
|
// 複数サブスク商品時に別商品の renewal info を読まないよう、latest と同じ original_transaction_id の
|
|
41
42
|
// pending エントリを優先(無ければ先頭にフォールバック)。
|
|
@@ -43,7 +44,13 @@ export function classifyAppleRenewal(verify, now) {
|
|
|
43
44
|
const pending = pendingArr.find((p) => p.original_transaction_id === originalTransactionId) ?? pendingArr.at(0);
|
|
44
45
|
const expiresMs = Number(latest.expires_date_ms);
|
|
45
46
|
const isExpired = Number.isFinite(expiresMs) && expiresMs < now;
|
|
46
|
-
const base = {
|
|
47
|
+
const base = {
|
|
48
|
+
originalTransactionId,
|
|
49
|
+
expiresDateMs: latest.expires_date_ms,
|
|
50
|
+
statusCode,
|
|
51
|
+
billingRetryStatus: pending?.is_in_billing_retry_period,
|
|
52
|
+
autoRenewStatus: pending?.auto_renew_status,
|
|
53
|
+
};
|
|
47
54
|
if (pending?.is_in_billing_retry_period === '1') {
|
|
48
55
|
return { state: 'billing_retry', ...base };
|
|
49
56
|
}
|
package/dist/iap/google.d.ts
CHANGED
|
@@ -36,15 +36,21 @@ export interface GoogleSubscriptionPurchase {
|
|
|
36
36
|
* a member is semi-breaking for exhaustive `switch` consumers).
|
|
37
37
|
*/
|
|
38
38
|
export type GoogleSubscriptionState = 'canceled' | 'gone' | 'active' | 'unknown';
|
|
39
|
+
/** Google subscription classification plus provider diagnostic codes used by persistence. */
|
|
40
|
+
export interface GoogleSubscriptionClassification {
|
|
41
|
+
state: GoogleSubscriptionState;
|
|
42
|
+
/** Google error-body code, such as 410. */
|
|
43
|
+
statusCode?: number;
|
|
44
|
+
/** Google cancellation reason (0=user, 1=system, 2=replaced, 3=developer). */
|
|
45
|
+
cancelReason?: number;
|
|
46
|
+
}
|
|
39
47
|
/**
|
|
40
48
|
* Classify a Google subscriptions.get response into a {@link GoogleSubscriptionState}.
|
|
41
49
|
*
|
|
42
50
|
* @param purchase - The response body (duck-typed); may be `{ error: { code } }`.
|
|
43
51
|
* @param now - Current epoch-ms (`Date.now()`); injected for determinism/testing.
|
|
44
52
|
*/
|
|
45
|
-
export declare function classifyGoogleSubscription(purchase: unknown, now: number):
|
|
46
|
-
state: GoogleSubscriptionState;
|
|
47
|
-
};
|
|
53
|
+
export declare function classifyGoogleSubscription(purchase: unknown, now: number): GoogleSubscriptionClassification;
|
|
48
54
|
/** OAuth service-account credentials for the Android Publisher API (per-app; inject, never hardcode in kit). */
|
|
49
55
|
export interface GoogleOAuthCredentials {
|
|
50
56
|
client_id: string;
|
package/dist/iap/google.js
CHANGED
|
@@ -22,18 +22,21 @@ export function classifyGoogleSubscription(purchase, now) {
|
|
|
22
22
|
const err = asRecord(p.error);
|
|
23
23
|
if (err) {
|
|
24
24
|
// 410 = "The subscription purchase is no longer available for query" (expired too long) = churned.
|
|
25
|
-
|
|
25
|
+
const statusCode = typeof err.code === 'number' ? err.code : undefined;
|
|
26
|
+
return { state: statusCode === 410 ? 'gone' : 'unknown', statusCode };
|
|
26
27
|
}
|
|
27
28
|
const expiryMs = Number(p.expiryTimeMillis);
|
|
28
|
-
const
|
|
29
|
-
const
|
|
29
|
+
const hasValidExpiry = Number.isFinite(expiryMs);
|
|
30
|
+
const isExpired = hasValidExpiry && expiryMs < now;
|
|
31
|
+
const cancelReason = typeof p.cancelReason === 'number' ? p.cancelReason : undefined;
|
|
32
|
+
const willNotRenew = p.autoRenewing === false || cancelReason !== undefined;
|
|
30
33
|
if (isExpired && willNotRenew) {
|
|
31
|
-
return { state: 'canceled' };
|
|
34
|
+
return { state: 'canceled', cancelReason };
|
|
32
35
|
}
|
|
33
|
-
if (!isExpired) {
|
|
34
|
-
return { state: 'active' };
|
|
36
|
+
if (hasValidExpiry && !isExpired) {
|
|
37
|
+
return { state: 'active', cancelReason };
|
|
35
38
|
}
|
|
36
|
-
return { state: 'unknown' };
|
|
39
|
+
return { state: 'unknown', cancelReason };
|
|
37
40
|
}
|
|
38
41
|
/**
|
|
39
42
|
* Exchange a refresh token for an Android Publisher access token.
|
package/dist/index.d.ts
CHANGED
|
@@ -47,16 +47,16 @@ export { KVCache } from './cache/kv-cache.js';
|
|
|
47
47
|
export type { KVNamespace, KVCacheOptions } from './cache/kv-cache.js';
|
|
48
48
|
export { createStripeClient, verifyStripeWebhook } from './stripe/client.js';
|
|
49
49
|
export type { CreateStripeClientOptions } from './stripe/client.js';
|
|
50
|
-
export { extractStripeFailureReason, stripeFailureMessageJa, serializePaymentFailure, parsePaymentFailure, PaymentDeclinedError, toPaymentDeclinedError, } from './stripe/failure.js';
|
|
50
|
+
export { extractStripeFailureReason, stripeFailureMessageJa, serializePaymentFailure, serializeIapFailureReason, parsePaymentFailure, PaymentDeclinedError, toPaymentDeclinedError, } from './stripe/failure.js';
|
|
51
51
|
export type { StripeFailureReason, PaymentFailureSource, PaymentFailureRecord, PaymentFailureReason, IapFailureReason, PaymentDeclinedBody, } from './stripe/failure.js';
|
|
52
52
|
export { classifyStripeReconcile } from './stripe/reconcile.js';
|
|
53
53
|
export type { StripeReconcileAction } from './stripe/reconcile.js';
|
|
54
54
|
export { paymentFailureMessageJa, iapFailureKey, UNRESOLVED_PAYMENT_STATUSES } from './payment/failure.js';
|
|
55
55
|
export type { PaymentFailureStatus, PaymentFailureType } from './payment/failure.js';
|
|
56
56
|
export { classifyAppleRenewal, verifyAppleReceipt } from './iap/apple.js';
|
|
57
|
-
export type { AppleRenewalState, AppleVerifyReceiptResponse, ApplePendingRenewalInfo, AppleLatestReceiptInfo, } from './iap/apple.js';
|
|
57
|
+
export type { AppleRenewalClassification, AppleRenewalState, AppleVerifyReceiptResponse, ApplePendingRenewalInfo, AppleLatestReceiptInfo, } from './iap/apple.js';
|
|
58
58
|
export { classifyGoogleSubscription, getGoogleSubscription, googleAccessToken } from './iap/google.js';
|
|
59
|
-
export type { GoogleSubscriptionState, GoogleSubscriptionPurchase, GoogleOAuthCredentials } from './iap/google.js';
|
|
59
|
+
export type { GoogleSubscriptionClassification, GoogleSubscriptionState, GoogleSubscriptionPurchase, GoogleOAuthCredentials, } from './iap/google.js';
|
|
60
60
|
export { retryWhenDeadlock } from './db/retry.js';
|
|
61
61
|
export { sendInChunks } from './queue/send.js';
|
|
62
62
|
export type { QueueLike, QueueSendMessage } from './queue/send.js';
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ export { createSentryErrorReporter } from './http/http-error.js';
|
|
|
36
36
|
export { KVCache } from './cache/kv-cache.js';
|
|
37
37
|
// stripe
|
|
38
38
|
export { createStripeClient, verifyStripeWebhook } from './stripe/client.js';
|
|
39
|
-
export { extractStripeFailureReason, stripeFailureMessageJa, serializePaymentFailure, parsePaymentFailure, PaymentDeclinedError, toPaymentDeclinedError, } from './stripe/failure.js';
|
|
39
|
+
export { extractStripeFailureReason, stripeFailureMessageJa, serializePaymentFailure, serializeIapFailureReason, parsePaymentFailure, PaymentDeclinedError, toPaymentDeclinedError, } from './stripe/failure.js';
|
|
40
40
|
export { classifyStripeReconcile } from './stripe/reconcile.js';
|
|
41
41
|
// payment (provider-agnostic; web-standard only). reopenGuardedPaymentFailedSet is drizzle-based → './db'.
|
|
42
42
|
export { paymentFailureMessageJa, iapFailureKey, UNRESOLVED_PAYMENT_STATUSES } from './payment/failure.js';
|
package/dist/payment/failure.js
CHANGED
|
@@ -32,7 +32,7 @@ export function paymentFailureMessageJa(input) {
|
|
|
32
32
|
if (input.status === 'failed' && (input.type === 'ios' || input.type === 'android')) {
|
|
33
33
|
return IAP_FAILED_MESSAGE_JA[input.type];
|
|
34
34
|
}
|
|
35
|
-
const stripeReason = input.
|
|
35
|
+
const stripeReason = input.type === 'ios' || input.type === 'android' ? null : (input.reason ?? null);
|
|
36
36
|
return stripeFailureMessageJa(stripeReason);
|
|
37
37
|
}
|
|
38
38
|
/**
|
package/dist/stripe/failure.d.ts
CHANGED
|
@@ -24,8 +24,6 @@ export interface StripeFailureReason {
|
|
|
24
24
|
}
|
|
25
25
|
/** Normalized reason persisted for an App Store / Google Play subscription failure. */
|
|
26
26
|
export interface IapFailureReason {
|
|
27
|
-
/** Provider discriminator. */
|
|
28
|
-
provider: 'ios' | 'android';
|
|
29
27
|
/** Stable machine-readable classification. */
|
|
30
28
|
code: 'billing_retry' | 'auto_renew_off' | 'subscription_canceled' | 'subscription_gone';
|
|
31
29
|
/** Provider response status code when present (Apple verifyReceipt status / Google error code). */
|
|
@@ -50,9 +48,10 @@ export type PaymentFailureSource = 'webhook.invoice.payment_failed' | 'webhook.i
|
|
|
50
48
|
*/
|
|
51
49
|
export interface PaymentFailureRecord {
|
|
52
50
|
reason: PaymentFailureReason;
|
|
53
|
-
|
|
51
|
+
/** Capture path. Optional for IAP because `payment_failed.type` already identifies the provider/path. */
|
|
52
|
+
source?: PaymentFailureSource;
|
|
54
53
|
/** ISO 8601 timestamp of when the failure was captured. */
|
|
55
|
-
occurredAt
|
|
54
|
+
occurredAt?: string;
|
|
56
55
|
}
|
|
57
56
|
/**
|
|
58
57
|
* Extract a normalized {@link StripeFailureReason} from a Stripe `PaymentIntent`, `Invoice`, a
|
|
@@ -86,6 +85,8 @@ export declare function stripeFailureMessageJa(reason: StripeFailureReason | nul
|
|
|
86
85
|
* @returns A JSON string.
|
|
87
86
|
*/
|
|
88
87
|
export declare function serializePaymentFailure(record: PaymentFailureRecord): string;
|
|
88
|
+
/** Serialize an IAP reason directly, without redundant provider/source/timestamp wrappers. */
|
|
89
|
+
export declare function serializeIapFailureReason(reason: IapFailureReason): string;
|
|
89
90
|
/**
|
|
90
91
|
* Parse a `payment_failed.receipt` value back into a {@link PaymentFailureRecord}.
|
|
91
92
|
*
|
package/dist/stripe/failure.js
CHANGED
|
@@ -148,6 +148,10 @@ export function stripeFailureMessageJa(reason) {
|
|
|
148
148
|
export function serializePaymentFailure(record) {
|
|
149
149
|
return JSON.stringify(record);
|
|
150
150
|
}
|
|
151
|
+
/** Serialize an IAP reason directly, without redundant provider/source/timestamp wrappers. */
|
|
152
|
+
export function serializeIapFailureReason(reason) {
|
|
153
|
+
return JSON.stringify(reason);
|
|
154
|
+
}
|
|
151
155
|
/**
|
|
152
156
|
* Parse a `payment_failed.receipt` value back into a {@link PaymentFailureRecord}.
|
|
153
157
|
*
|
|
@@ -161,10 +165,21 @@ export function parsePaymentFailure(receipt) {
|
|
|
161
165
|
try {
|
|
162
166
|
const parsed = JSON.parse(receipt);
|
|
163
167
|
const r = asRecord(parsed);
|
|
164
|
-
if (!r
|
|
168
|
+
if (!r) {
|
|
165
169
|
return null;
|
|
166
170
|
}
|
|
167
|
-
|
|
171
|
+
if (asRecord(r.reason)) {
|
|
172
|
+
if ((r.source !== undefined && typeof r.source !== 'string') ||
|
|
173
|
+
(r.occurredAt !== undefined && typeof r.occurredAt !== 'string')) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
return parsed;
|
|
177
|
+
}
|
|
178
|
+
// IAP rows store the reason itself. `code` is required so arbitrary JSON is not accepted as a reason.
|
|
179
|
+
if (typeof r.code === 'string') {
|
|
180
|
+
return { reason: parsed };
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
168
183
|
}
|
|
169
184
|
catch {
|
|
170
185
|
return null;
|