@livx.cc/native-kit 0.18.0 → 0.19.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livx.cc/native-kit",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "Isomorphic native-capabilities kit for PWAs — same API in browser and in an appwrap native shell. Zero dependencies.",
5
5
  "license": "MIT",
6
6
  "author": "Elya Livshitz",
@@ -337,6 +337,7 @@ export class WebAdapter implements NativeKitAdapter {
337
337
  case 'billing.purchase':
338
338
  case 'billing.restore':
339
339
  case 'billing.entitlements':
340
+ case 'billing.appReceipt':
340
341
  case 'billing.manageSubscriptions':
341
342
  throw new KitError('UNSUPPORTED', 'No in-app purchases on web — use a web checkout');
342
343
 
@@ -79,6 +79,26 @@ export class BillingModule {
79
79
  return out;
80
80
  }
81
81
 
82
+ /**
83
+ * Confirm entitlements **silently** from the on-device App Store receipt — no Apple-ID
84
+ * prompt and no `restore()` round-trip (unlike {@link restore}/{@link entitlements} on
85
+ * StoreKit 1). For an in-place update of the SAME bundle id the receipt already holds the
86
+ * user's active/grandfathered subscriptions, so this is the zero-user-action path for
87
+ * migrating existing subscribers into a new build.
88
+ *
89
+ * Native iOS only, and only meaningful with a **server validator** (the bare receipt has no
90
+ * product id — a client-trusted validator can't interpret it). Resolves `[]` on the web,
91
+ * on Android (no StoreKit-1 receipt), or when no receipt is present (e.g. a dev build).
92
+ */
93
+ async entitlementsFromReceipt(): Promise<Entitlement[]> {
94
+ await this.kit.ready();
95
+ if (this.capability !== 'native') return []; // web, or a shell with no native store handler (Android today)
96
+ if (this.validator instanceof ClientTrustedValidator) return []; // bare receipt has no product id → would grant a bogus active entitlement; needs a server validator
97
+ const receipt = await this.kit.invoke<PurchaseReceipt>('billing.appReceipt');
98
+ if (!receipt?.appReceipt) return [];
99
+ return this.validator.validate(receipt); // server-of-record turns the receipt into entitlements
100
+ }
101
+
82
102
  /** Current entitlements from the configured server-of-record (web provider or validator). */
83
103
  async entitlements(): Promise<Entitlement[]> {
84
104
  await this.kit.ready();
@@ -44,6 +44,9 @@ export class UpdatesModule {
44
44
  private timer: ReturnType<typeof setInterval> | null = null;
45
45
  private unsubs: Unsubscribe[] = [];
46
46
  private listeners = new Set<(s: UpdateStatus) => void>();
47
+ /** The auto banner is shown at most once per JS session — so a dismissed prompt doesn't nag on
48
+ * every poll. A reload (the intended response) boots a fresh bundle/context and resets this; until
49
+ * then, {@link onAvailable} listeners still fire each check so an app can re-surface it itself. */
47
50
  private prompted = false;
48
51
 
49
52
  constructor(private kit: NativeKit) {}
@@ -110,7 +113,7 @@ export class UpdatesModule {
110
113
  this.stop(/* keepStarted */ true);
111
114
  }
112
115
  this.started = true;
113
- // A reload picks up the new bundle → allow a fresh prompt next time.
116
+ // Re-check whenever the app returns to the foreground (catches a deploy made while backgrounded).
114
117
  this.unsubs.push(this.kit.on('app.resume', () => void this.check()));
115
118
  // Banner tap (or any 'appwrap.update' action) → reload.
116
119
  this.unsubs.push(