diff --git a/docs/superpowers/plans/2026-07-06-onboarding-soft-paywall-free-tier.md b/docs/superpowers/plans/2026-07-06-onboarding-soft-paywall-free-tier.md
index 6b9e84f..651f52c 100644
--- a/docs/superpowers/plans/2026-07-06-onboarding-soft-paywall-free-tier.md
+++ b/docs/superpowers/plans/2026-07-06-onboarding-soft-paywall-free-tier.md
@@ -22,12 +22,12 @@ Note: `onboarding/customize.tsx` stays out of the chain (as today). The spec lis
**Key backend facts:**
- `server/lib/billing.js`: `FREE_MONTHLY_CREDITS = 0` (line 3), `getAvailableCredits` returns 0 for non-pro (line 257), `consumeCredits` throws for non-pro (line 573), `alignAccountToCurrentCycle` self-heals allowance via `isAllowedMonthlyAllowance` (line 76) — legacy free accounts with stored allowance 0 auto-migrate once `FREE_MONTHLY_CREDITS` changes.
- Costs (`server/index.js:84-87`): scan primary 1, scan review 0, semantic search 2, health check 2.
-- Guests: `isGuest(userId)` = `userId === 'guest'`. Guests currently never reach credit consumption because `ensureActiveProEntitlement` throws first. **When removing it, guests must still be blocked server-side** — otherwise all guests share one global `'guest'` billing account and health checks become free for guests (`server/index.js:1005` skips charging guests).
+- Guests: `isGuest(userId)` = `userId === 'guest'`. Guests may run the limited pre-auth demo identification scan, but the demo scan must use the same AI identification path as a normal scan. Guests must still be blocked from health checks and semantic search because those would otherwise use one shared `'guest'` billing account.
- Scan model per plan: `server/lib/openai.js:33` `getScanModelChain(plan)` — free uses the cheap chain. Decision: free gets the pro chain (same quality).
- Billing summary shape (`buildBillingSummary`): `credits.cycleEndsAt` is the free-credit renewal date.
**Key app facts:**
-- `app/scanner.tsx`: `isDemoMode = !hasActiveEntitlement` (line 170) — ALL non-pro users currently get client-side mock scans (`getMockPlantByImage`), limited to 5/device via `guestScanCount`. New rule: demo mode = guests only (`!session`); signed-in free users do real scans with credits.
+- `app/scanner.tsx`: demo mode is guests only (`!session`), limited to 5/device via `guestScanCount`. Demo scans must call the normal identification service, not `getMockPlantByImage`; signed-in free users do real scans with credits.
- `app/profile/billing.tsx` (1779 lines): already contains the full paywall branch `showPaywallPlans` (line 360: `!session || (!isLoadingBilling && planId !== 'pro')`), purchase/restore/sync/Expo-Go-simulation logic, per-language copy via `getBillingCopy(language)`. We reuse ALL purchase logic — only the paywall trigger and the paywall JSX change.
- Theme: `useColors(isDarkMode, colorPalette)` from `constants/Colors.ts` (tokens like `colors.primary`, `colors.surface`, `colors.text`, `colors.primarySoft`, `colors.border`, `colors.onPrimary`, `colors.textSecondary`, `colors.textMuted`, `colors.surfaceMuted`). New screens must support dark mode via these tokens (Stitch dark variants exist as reference).
- New-screen copy: follow the `getBillingCopy(language)`-style local copy object pattern (de/es/en) — do NOT add keys to `utils/translations.ts` unless a screen already uses `t.` keys you're keeping.
@@ -235,19 +235,19 @@ git commit -m "feat(server): free tier with 3 monthly credits"
---
-### Task 3: Remove the server hard paywall (guests stay blocked)
+### Task 3: Remove the server hard paywall (guest demo scan allowed)
**Files:**
- Modify: `server/index.js:206-218` (helpers), `:734` (scan), `:742` (scan model), `:906` (semantic search), `:946` (health check)
-- [ ] **Step 1: Replace the pro-gate helper with a guest gate**
+- [ ] **Step 1: Replace the pro-gate helper with a guest gate for non-demo endpoints**
Replace lines 206-218 (`createHardPaywallError` + `ensureActiveProEntitlement`) with:
```js
const ensureNotGuest = (userId, requiredCredits) => {
- // Guests use the client-side demo scan; the shared 'guest' billing account
- // must never consume real credits or run free AI analyses.
+ // Guests may use the limited pre-auth demo scan, but the shared 'guest'
+ // billing account must never consume credits for non-demo endpoints.
if (isGuest(userId)) {
const error = new Error('Sign in to use scan credits.');
error.code = 'INSUFFICIENT_CREDITS';
@@ -262,7 +262,7 @@ Note: `isGuest` is defined at line 353, *after* this helper — that's fine (fun
- [ ] **Step 2: Swap the three call sites**
-- `server/index.js:734`: `ensureActiveProEntitlement(accountSnapshot, SCAN_PRIMARY_COST);` → `ensureNotGuest(userId, SCAN_PRIMARY_COST);`
+- `server/index.js:734`: remove the guest gate from `/v1/scan`; guest demo scans may run primary AI identification without consuming account credits.
- `server/index.js:906`: `ensureActiveProEntitlement(accountSnapshot, SEMANTIC_SEARCH_COST);` → `ensureNotGuest(userId, SEMANTIC_SEARCH_COST);`
- `server/index.js:946`: `ensureActiveProEntitlement(accountSnapshot, HEALTH_CHECK_COST);` → `ensureNotGuest(userId, HEALTH_CHECK_COST);`
@@ -507,7 +507,7 @@ git commit -m "feat(app): out-of-credits bottom sheet (Stitch design)"
---
-### Task 6: Scanner — demo mode for guests only, credits + sheet for free users
+### Task 6: Scanner — AI demo mode for guests only, credits + sheet for free users
**Files:**
- Modify: `app/scanner.tsx:168-172` (mode flags), `:269-297` (pre-checks), `:414-425` (402 handler)
@@ -519,7 +519,7 @@ Replace lines 168-172:
```tsx
const hasActiveEntitlement = billingSummary?.entitlement?.plan === 'pro'
&& billingSummary?.entitlement?.status === 'active';
-const isDemoMode = !session; // guests get the local demo scan; signed-in users burn real credits
+const isDemoMode = !session; // guests get limited AI demo scans; signed-in users burn real credits
const availableCredits = billingSummary?.credits.available ?? 0;
const demoScansRemaining = Math.max(0, DEMO_SCAN_LIMIT - guestScanCount);
```
@@ -1481,7 +1481,7 @@ Run: `npx expo export --platform android` → completes without errors.
1. Fresh install → welcome (social proof) → Let's Go → 3 slides → 4 question steps with progress bar → personalizing (auto) → paywall with trial toggle → ✕ → sign-up → tabs.
2. New account has 3 credits; scan works and decrements; after 3 scans the out-of-credits sheet appears; "See Pro Plans" opens the paywall; ✕ returns to the scanner (app still usable).
-3. Guest demo scan from welcome still works (5 local demo scans), server still 402s direct guest API calls.
+3. Guest demo scan from welcome still works (5 AI demo scans), direct guest health-check and semantic-search API calls still 402.
4. Existing pro account: no paywall anywhere, unchanged manage view under Profile → billing.
5. Login as existing free user: lands in tabs (no hard-paywall redirect), sees credit badge in scanner.
6. Dark mode: slides, questions, personalizing, paywall, sheet all render with dark tokens (compare `_dark_mode` mockups).
@@ -1501,5 +1501,5 @@ git commit -m "docs: mark onboarding/soft-paywall/free-tier spec as implemented"
## Self-review notes (already applied)
- Spec coverage: welcome ✓(T10) slides ✓(T11) questions ✓(T12) personalizing ✓(T13) paywall ✓(T7/8) sign-up/login ✓(T14) out-of-credits ✓(T5/6) free tier ✓(T1-3) soft gating ✓(T4/6) credits badge ✓(T6 step 6) analytics ✓(inline). Deviations from spec, both agreed-level "Kleinigkeiten": `customize.tsx` stays out of the chain (health-check is step 4), and sign-up shows no personal name (no name is collected).
-- Guest safety: T3 keeps guests blocked server-side (`ensureNotGuest`) — required because `getOrCreateAccount(db, 'guest')` would otherwise mint a shared free account.
+- Guest safety: T3 keeps guests blocked server-side for non-demo endpoints (`ensureNotGuest`) — required because `getOrCreateAccount(db, 'guest')` would otherwise mint a shared free account.
- Type consistency: `PreAuthOnboardingService` keys (`acquisitionSource`/`primaryGoal`/`experienceLevel`) match `OnboardingProgressService` setters; `OutOfCreditsSheet` props match the T6 call site; paywall param names (`view`, `context`) consistent across T6/T7/T13.
diff --git a/docs/superpowers/specs/2026-07-06-onboarding-soft-paywall-free-tier-design.md b/docs/superpowers/specs/2026-07-06-onboarding-soft-paywall-free-tier-design.md
index 4bfa911..6cfd0cd 100644
--- a/docs/superpowers/specs/2026-07-06-onboarding-soft-paywall-free-tier-design.md
+++ b/docs/superpowers/specs/2026-07-06-onboarding-soft-paywall-free-tier-design.md
@@ -20,7 +20,7 @@ Welcome (social proof)
→ App (tabs), free plan with 3 credits/month
```
-- The guest **demo scan stays** available from the welcome screen (existing `isGuest` server handling unchanged).
+- The guest **demo scan stays** available from the welcome screen, but it must use the same AI identification path as a normal scan. Demo scans must never return local hash/mock plant results or fake confidence values.
- Existing users: "Log in" link on the welcome screen → login.
- Paywall ✕ during onboarding → continues to sign-up. Paywall ✕ in-app → simply closes.
@@ -46,10 +46,11 @@ Known mockup fixes (agreed): replace AI-artifact photos (garbled phone UI on sca
## 3. Free tier (backend, `server/lib/billing.js` + `server/index.js`)
- `FREE_MONTHLY_CREDITS: 0 → 3`. Existing monthly-allowance reset logic already covers free accounts; verify reset works for plan `free`.
-- **Remove server hard paywall:** drop `ensureActiveProEntitlement` from scan and health-check endpoints (`server/index.js`). Credit consumption becomes the only gate; 0 credits → existing 402 `INSUFFICIENT_CREDITS` error.
-- **Same scan model for free and pro** (`getScanModel` returns the pro model for both plans). Cost accepted (~cents/user/month at 3 scans).
-- **Low-confidence AI review pass stays pro-only** (unchanged) so a free scan never burns 2 credits, and Pro keeps a quality edge.
-- Trial handling unchanged (yearly plan carries 7-day trial, 30 credits during trial).
+- **Remove server hard paywall:** drop `ensureActiveProEntitlement` from scan and health-check endpoints (`server/index.js`). Credit consumption becomes the only gate; 0 credits → existing 402 `INSUFFICIENT_CREDITS` error.
+- **Same scan model for free and pro** (`getScanModel` returns the pro model for both plans). Cost accepted (~cents/user/month at 3 scans).
+- **Low-confidence AI review pass stays pro-only** (unchanged) so a free scan never burns 2 credits, and Pro keeps a quality edge.
+- **Guest demo scans use AI identification without consuming account credits.** Guests remain blocked from health checks and semantic search, but `/v1/scan` may run the primary identification model for the limited pre-auth demo experience.
+- Trial handling unchanged (yearly plan carries 7-day trial, 30 credits during trial).
## 4. Soft paywall (app)
diff --git a/package-lock.json b/package-lock.json
index beae11d..1b93f1f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "greenlens",
- "version": "2.2.7",
+ "version": "2.2.9",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "greenlens",
- "version": "2.2.7",
+ "version": "2.2.9",
"hasInstallScript": true,
"dependencies": {
"@expo/vector-icons": "^15.0.3",
@@ -107,6 +107,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
@@ -1560,7 +1561,7 @@
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/@egjs/hammerjs": {
@@ -2341,7 +2342,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz",
"integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/types": "^29.6.3",
@@ -2359,7 +2360,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz",
"integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/console": "^29.7.0",
@@ -2407,7 +2408,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
@@ -2432,7 +2433,7 @@
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz",
"integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -2457,7 +2458,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz",
"integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"expect": "^29.7.0",
@@ -2471,7 +2472,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz",
"integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"jest-get-type": "^29.6.3"
@@ -2501,7 +2502,7 @@
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz",
"integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -2511,7 +2512,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz",
"integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/environment": "^29.7.0",
@@ -2527,7 +2528,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz",
"integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@bcoe/v8-coverage": "^0.2.3",
@@ -2571,7 +2572,7 @@
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@@ -2583,7 +2584,7 @@
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
- "dev": true,
+ "devOptional": true,
"license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
@@ -2604,7 +2605,7 @@
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz",
"integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==",
- "dev": true,
+ "devOptional": true,
"license": "BSD-3-Clause",
"dependencies": {
"@babel/core": "^7.23.9",
@@ -2621,7 +2622,7 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
+ "devOptional": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
@@ -2634,7 +2635,7 @@
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
- "dev": true,
+ "devOptional": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -2647,7 +2648,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
@@ -2672,7 +2673,7 @@
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz",
"integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.18",
@@ -2687,7 +2688,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz",
"integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/console": "^29.7.0",
@@ -2703,7 +2704,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz",
"integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/test-result": "^29.7.0",
@@ -3388,6 +3389,7 @@
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz",
"integrity": "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"merge-options": "^3.0.4"
},
@@ -3734,6 +3736,7 @@
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.28.tgz",
"integrity": "sha512-d1QDn+KNHfHGt3UIwOZvupvdsDdiHYZBEj7+wL2yDVo3tMezamYy60H9s3EnNVE1Ae1ty0trc7F2OKqo/RmsdQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@react-navigation/core": "^7.14.0",
"escape-string-regexp": "^4.0.0",
@@ -3843,7 +3846,7 @@
"version": "13.3.3",
"resolved": "https://registry.npmjs.org/@testing-library/react-native/-/react-native-13.3.3.tgz",
"integrity": "sha512-k6Mjsd9dbZgvY4Bl7P1NIpePQNi+dfYtlJ5voi9KQlynxSyQkfOgJmYGCYmw/aSgH/rUcFvG8u5gd4npzgRDyg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"jest-matcher-utils": "^30.0.5",
@@ -3870,7 +3873,7 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -3883,14 +3886,14 @@
"version": "0.34.48",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz",
"integrity": "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/@testing-library/react-native/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -3903,7 +3906,7 @@
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz",
"integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/diff-sequences": "30.0.1",
@@ -3919,7 +3922,7 @@
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz",
"integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.1.0",
@@ -3935,7 +3938,7 @@
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
"integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
@@ -3950,7 +3953,7 @@
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/@tootallnate/once": {
@@ -4079,8 +4082,9 @@
"version": "19.1.17",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.17.tgz",
"integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"csstype": "^3.0.2"
}
@@ -4781,6 +4785,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -4900,7 +4905,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -4958,7 +4963,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
"integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -5024,7 +5029,7 @@
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz",
"integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/cli-cursor": {
@@ -5096,7 +5101,7 @@
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"iojs": ">= 1.0.0",
@@ -5107,7 +5112,7 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz",
"integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/color": {
@@ -5286,7 +5291,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz",
"integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/types": "^29.6.3",
@@ -5468,7 +5473,7 @@
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/data-uri-to-buffer": {
@@ -5532,7 +5537,7 @@
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz",
"integrity": "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"peerDependencies": {
"babel-plugin-macros": "^3.1.0"
@@ -5658,7 +5663,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
"integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -5674,7 +5679,7 @@
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
"integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
@@ -5843,7 +5848,7 @@
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
"integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -5893,7 +5898,7 @@
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
"integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"is-arrayish": "^0.2.1"
@@ -5903,7 +5908,7 @@
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/error-stack-parser": {
@@ -6082,7 +6087,7 @@
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
"integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"cross-spawn": "^7.0.3",
@@ -6106,7 +6111,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -6116,7 +6121,7 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"mimic-fn": "^2.1.0"
@@ -6132,7 +6137,7 @@
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
"integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
- "dev": true,
+ "devOptional": true,
"engines": {
"node": ">= 0.8.0"
}
@@ -6141,7 +6146,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz",
"integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/expect-utils": "^29.7.0",
@@ -6159,6 +6164,7 @@
"resolved": "https://registry.npmjs.org/expo/-/expo-54.0.33.tgz",
"integrity": "sha512-3yOEfAKqo+gqHcV8vKcnq0uA5zxlohnhA3fu4G43likN8ct5ZZ3LjAh9wDdKteEkoad3tFPvwxmXW711S5OHUw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.20.0",
"@expo/cli": "54.0.23",
@@ -6325,6 +6331,7 @@
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.13.tgz",
"integrity": "sha512-FnZn12E1dRYKDHlAdIyNFhBurKTS3F9CrfrBDJI5m3D7U17KBHMQ6JEfYlSj7LG7t+Ulr+IKaj58L1k5gBwTcQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@expo/config": "~12.0.13",
"@expo/env": "~2.0.8"
@@ -6434,6 +6441,7 @@
"resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-19.0.21.tgz",
"integrity": "sha512-s3DlrDdiscBHtab/6W1osrjGL+C2bvoInPJD7sOwmxfJ5Woynv2oc+Fz1/xVXaE/V7HE/+xrHC/H45tu6lZzzg==",
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"expo": "*",
"react-native": "*"
@@ -6444,6 +6452,7 @@
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.11.tgz",
"integrity": "sha512-ga0q61ny4s/kr4k8JX9hVH69exVSIfcIc19+qZ7gt71Mqtm7xy2c6kwsPTCyhBW2Ro5yXTT8EaZOpuRi35rHbg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"fontfaceobserver": "^2.1.0"
},
@@ -6516,6 +6525,7 @@
"resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-8.0.11.tgz",
"integrity": "sha512-+VSaNL5om3kOp/SSKO5qe6cFgfSIWnnQDSbA7XLs3ECkYzXRquk5unxNS3pg7eK5kNUmQ4kgLI7MhTggAEUBLA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"expo-constants": "~18.0.12",
"invariant": "^2.2.4"
@@ -6530,6 +6540,7 @@
"resolved": "https://registry.npmjs.org/expo-localization/-/expo-localization-17.0.8.tgz",
"integrity": "sha512-UrdwklZBDJ+t+ZszMMiE0SXZ2eJxcquCuQcl6EvGHM9K+e6YqKVRQ+w8qE+iIB3H75v2RJy6MHAaLK+Mqeo04g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"rtl-detect": "^1.0.2"
},
@@ -7465,7 +7476,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -7710,7 +7721,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/http-errors": {
@@ -7787,7 +7798,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
- "dev": true,
+ "devOptional": true,
"license": "Apache-2.0",
"engines": {
"node": ">=10.17.0"
@@ -7860,7 +7871,7 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz",
"integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"pkg-dir": "^4.2.0",
@@ -7889,7 +7900,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -8013,7 +8024,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
"integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -8101,7 +8112,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -8179,7 +8190,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
"integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
- "dev": true,
+ "devOptional": true,
"license": "BSD-3-Clause",
"dependencies": {
"istanbul-lib-coverage": "^3.0.0",
@@ -8194,7 +8205,7 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
"integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
- "dev": true,
+ "devOptional": true,
"license": "BSD-3-Clause",
"dependencies": {
"debug": "^4.1.1",
@@ -8209,7 +8220,7 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true,
+ "devOptional": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -8219,7 +8230,7 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz",
"integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==",
- "dev": true,
+ "devOptional": true,
"license": "BSD-3-Clause",
"dependencies": {
"html-escaper": "^2.0.0",
@@ -8248,8 +8259,9 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@jest/core": "^29.7.0",
"@jest/types": "^29.6.3",
@@ -8275,7 +8287,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz",
"integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"execa": "^5.0.0",
@@ -8290,7 +8302,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz",
"integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/environment": "^29.7.0",
@@ -8322,7 +8334,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz",
"integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/core": "^29.7.0",
@@ -8356,7 +8368,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz",
"integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.11.6",
@@ -8402,7 +8414,7 @@
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@@ -8414,7 +8426,7 @@
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
- "dev": true,
+ "devOptional": true,
"license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
@@ -8435,7 +8447,7 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
+ "devOptional": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
@@ -8448,7 +8460,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -8461,7 +8473,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
"integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"chalk": "^4.0.0",
@@ -8477,7 +8489,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz",
"integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"detect-newline": "^3.0.0"
@@ -8490,7 +8502,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz",
"integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/types": "^29.6.3",
@@ -8622,7 +8634,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz",
"integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"jest-get-type": "^29.6.3",
@@ -8636,7 +8648,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz",
"integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"chalk": "^4.0.0",
@@ -8686,7 +8698,7 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
"integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -8713,7 +8725,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz",
"integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"chalk": "^4.0.0",
@@ -8734,7 +8746,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz",
"integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"jest-regex-util": "^29.6.3",
@@ -8748,7 +8760,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz",
"integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/console": "^29.7.0",
@@ -8781,7 +8793,7 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true,
+ "devOptional": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -8791,7 +8803,7 @@
"version": "0.5.13",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
"integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
@@ -8802,7 +8814,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz",
"integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/environment": "^29.7.0",
@@ -8836,7 +8848,7 @@
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@@ -8848,7 +8860,7 @@
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
- "dev": true,
+ "devOptional": true,
"license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
@@ -8869,7 +8881,7 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
+ "devOptional": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
@@ -8882,7 +8894,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz",
"integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.11.6",
@@ -8914,7 +8926,7 @@
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
- "dev": true,
+ "devOptional": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -9103,7 +9115,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz",
"integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@jest/test-result": "^29.7.0",
@@ -9287,7 +9299,7 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/json-schema-traverse": {
@@ -9844,7 +9856,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
"integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"semver": "^7.5.3"
@@ -9860,7 +9872,7 @@
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
- "dev": true,
+ "devOptional": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -10329,7 +10341,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -10431,7 +10443,7 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/negotiator": {
@@ -10548,7 +10560,7 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.0.0"
@@ -10855,7 +10867,7 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.0.0",
@@ -11046,7 +11058,7 @@
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"find-up": "^4.0.0"
@@ -11313,7 +11325,7 @@
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
"integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
- "dev": true,
+ "devOptional": true,
"funding": [
{
"type": "individual",
@@ -11397,6 +11409,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -11437,6 +11450,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"scheduler": "^0.26.0"
},
@@ -11473,6 +11487,7 @@
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.5.tgz",
"integrity": "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@jest/create-cache-key-function": "^29.7.0",
"@react-native/assets-registry": "0.81.5",
@@ -11530,6 +11545,7 @@
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.28.0.tgz",
"integrity": "sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@egjs/hammerjs": "^2.0.17",
"hoist-non-react-statics": "^3.3.0",
@@ -11555,6 +11571,7 @@
"resolved": "https://registry.npmjs.org/react-native-purchases/-/react-native-purchases-9.10.5.tgz",
"integrity": "sha512-ofs33aTgdjyjUDZgCtCKYfvl4gBtJrOV77/SXyDzSxTttNjg+8BWGckF3ALfBg69uU65xrXsqfyU3U+Cl86IdQ==",
"license": "MIT",
+ "peer": true,
"workspaces": [
"examples/purchaseTesterTypescript",
"react-native-purchases-ui"
@@ -11627,6 +11644,7 @@
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz",
"integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==",
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"react": "*",
"react-native": "*"
@@ -11637,6 +11655,7 @@
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz",
"integrity": "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"react-freeze": "^1.0.0",
"react-native-is-edge-to-edge": "^1.2.1",
@@ -11652,6 +11671,7 @@
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.12.1.tgz",
"integrity": "sha512-vCuZJDf8a5aNC2dlMovEv4Z0jjEUET53lm/iILFnFewa15b4atjVxU6Wirm6O9y6dEsdjDZVD7Q3QM4T1wlI8g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"css-select": "^5.1.0",
"css-tree": "^1.1.3",
@@ -11667,6 +11687,7 @@
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz",
"integrity": "sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.18.6",
"@react-native/normalize-colors": "^0.74.1",
@@ -11808,6 +11829,7 @@
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
"integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -11885,8 +11907,9 @@
"version": "19.1.0",
"resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-19.1.0.tgz",
"integrity": "sha512-jXkSl3CpvPYEF+p/eGDLB4sPoDX8pKkYvRl9+rR8HxLY0X04vW7hCm1/0zHoUSjPZ3bDa+wXWNTDVIw/R8aDVw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"react-is": "^19.1.0",
"scheduler": "^0.26.0"
@@ -11899,7 +11922,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
"integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"indent-string": "^4.0.0",
@@ -12039,7 +12062,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
"integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"resolve-from": "^5.0.0"
@@ -12655,7 +12678,7 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
"integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"char-regex": "^1.0.2",
@@ -12669,7 +12692,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
@@ -12769,7 +12792,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
"integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -12779,7 +12802,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -12789,7 +12812,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
"integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"min-indent": "^1.0.0"
@@ -13439,7 +13462,7 @@
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
"integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==",
- "dev": true,
+ "devOptional": true,
"license": "ISC",
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.12",
diff --git a/server/index.js b/server/index.js
index 83fa341..1d188a5 100644
--- a/server/index.js
+++ b/server/index.js
@@ -204,11 +204,11 @@ const resolveIdempotencyKey = (request) => {
return '';
};
-const ensureNotGuest = (userId, requiredCredits) => {
- // Guests use the client-side demo scan; the shared 'guest' billing account
- // must never consume real credits or run free AI analyses.
- if (isGuest(userId)) {
- const error = new Error('Sign in to use scan credits.');
+const ensureNotGuest = (userId, requiredCredits) => {
+ // Guests may use the limited pre-auth demo identification scan. Other
+ // endpoints must not consume credits from the shared 'guest' account.
+ if (isGuest(userId)) {
+ const error = new Error('Sign in to use scan credits.');
error.code = 'INSUFFICIENT_CREDITS';
error.status = 402;
error.metadata = { required: requiredCredits, available: 0 };
@@ -726,17 +726,20 @@ app.post('/v1/scan', async (request, response) => {
let modelUsed = null;
let modelFallbackCount = 0;
- const [accountSnapshot, catalogEntries] = await Promise.all([
- getAccountSnapshot(db, userId),
- getCachedCatalogEntries(db),
- ]);
- ensureNotGuest(userId, SCAN_PRIMARY_COST);
- creditsCharged += await consumeCreditsWithIdempotency(
- db,
- userId,
- chargeKey('scan-primary', userId, idempotencyKey),
- SCAN_PRIMARY_COST,
- );
+ const [accountSnapshot, catalogEntries] = await Promise.all([
+ getAccountSnapshot(db, userId),
+ getCachedCatalogEntries(db),
+ ]);
+ if (isGuest(userId)) {
+ modelPath.push('guest-demo-no-credit');
+ } else {
+ creditsCharged += await consumeCreditsWithIdempotency(
+ db,
+ userId,
+ chargeKey('scan-primary', userId, idempotencyKey),
+ SCAN_PRIMARY_COST,
+ );
+ }
// Free tier gets the same model quality; quantity (3 credits/month) is the differentiator.
const scanPlan = 'pro';
@@ -764,8 +767,14 @@ app.post('/v1/scan', async (request, response) => {
usedOpenAi = true;
modelUsed = openAiPrimary.modelUsed || modelUsed;
modelPath.push('openai-primary');
- if (grounded.grounded) modelPath.push('catalog-grounded-primary');
- } else {
+ if (grounded.grounded) modelPath.push('catalog-grounded-primary');
+ } else {
+ if (isGuest(userId)) {
+ const error = new Error('AI demo scan failed. Please try again with a clearer plant photo.');
+ error.code = 'PROVIDER_ERROR';
+ error.status = 502;
+ throw error;
+ }
console.warn(`OpenAI primary identification returned null for user ${userId} — using catalog fallback.`, {
attemptedModels: openAiPrimary?.attemptedModels,
plant: result?.name,
@@ -773,8 +782,14 @@ app.post('/v1/scan', async (request, response) => {
modelPath.push('openai-primary-failed');
modelPath.push('catalog-primary-fallback');
}
- } else {
- console.log(`OpenAI not configured, using catalog fallback for user ${userId}`);
+ } else {
+ if (isGuest(userId)) {
+ const error = new Error('AI demo scan is unavailable. Please configure OpenAI before enabling guest demo scans.');
+ error.code = 'PROVIDER_ERROR';
+ error.status = 502;
+ throw error;
+ }
+ console.log(`OpenAI not configured, using catalog fallback for user ${userId}`);
modelPath.push('openai-not-configured');
modelPath.push('catalog-primary-fallback');
}
diff --git a/services/backend/mockBackendService.ts b/services/backend/mockBackendService.ts
index 73ce4da..9863f0b 100644
--- a/services/backend/mockBackendService.ts
+++ b/services/backend/mockBackendService.ts
@@ -29,7 +29,7 @@ import { IdentificationResult, PlantHealthCheck } from '../../types';
const MOCK_ACCOUNT_STORE_KEY = 'greenlens_mock_backend_accounts_v1';
const MOCK_IDEMPOTENCY_STORE_KEY = 'greenlens_mock_backend_idempotency_v1';
-const FREE_MONTHLY_CREDITS = 0;
+const FREE_MONTHLY_CREDITS = 3;
const GUEST_TRIAL_CREDITS = 0;
const TRIAL_MONTHLY_CREDITS = 30;
const PRO_MONTHLY_CREDITS = 100;
@@ -827,38 +827,56 @@ export const mockBackendService = {
};
}
- let creditsCharged = 0;
- const modelPath: string[] = [];
-
- creditsCharged += consumeCreditsWithIdempotency(
- account,
- stores.idempotency,
- chargeKey('scan-primary', request.userId, request.idempotencyKey),
- SCAN_PRIMARY_COST,
- );
+ let creditsCharged = 0;
+ const modelPath: string[] = [];
+
+ if (request.userId === 'guest') {
+ modelPath.push('guest-demo-no-credit');
+ } else {
+ creditsCharged += consumeCreditsWithIdempotency(
+ account,
+ stores.idempotency,
+ chargeKey('scan-primary', request.userId, request.idempotencyKey),
+ SCAN_PRIMARY_COST,
+ );
+ }
let usedOpenAi = false;
let result: IdentificationResult = getMockPlantByImage(request.imageUri, request.language, false);
- if (openAiScanService.isConfigured()) {
- const openAiPrimary = await openAiScanService.identifyPlant(
- request.imageUri,
- request.language,
- 'primary',
- account.plan === 'pro' ? 'pro' : 'free',
- );
- if (openAiPrimary) {
- result = openAiPrimary;
- usedOpenAi = true;
- modelPath.push('openai-primary');
- } else {
- result = getMockPlantByImage(request.imageUri, request.language, false);
- modelPath.push('openai-primary-failed');
- modelPath.push('mock-primary-fallback');
- }
- } else {
- modelPath.push('mock-primary');
- }
+ if (openAiScanService.isConfigured()) {
+ const openAiPrimary = await openAiScanService.identifyPlant(
+ request.imageUri,
+ request.language,
+ 'primary',
+ 'pro',
+ );
+ if (openAiPrimary) {
+ result = openAiPrimary;
+ usedOpenAi = true;
+ modelPath.push('openai-primary');
+ } else {
+ if (request.userId === 'guest') {
+ throw new BackendApiError(
+ 'PROVIDER_ERROR',
+ 'AI demo scan failed. Please try again with a clearer plant photo.',
+ 502,
+ );
+ }
+ result = getMockPlantByImage(request.imageUri, request.language, false);
+ modelPath.push('openai-primary-failed');
+ modelPath.push('mock-primary-fallback');
+ }
+ } else {
+ if (request.userId === 'guest') {
+ throw new BackendApiError(
+ 'PROVIDER_ERROR',
+ 'AI demo scan is unavailable. Please configure OpenAI before enabling guest demo scans.',
+ 502,
+ );
+ }
+ modelPath.push('mock-primary');
+ }
const shouldReview = result.confidence < LOW_CONFIDENCE_REVIEW_THRESHOLD;
if (shouldReview && account.plan === 'pro') {
diff --git a/services/preAuthOnboardingService.ts b/services/preAuthOnboardingService.ts
index b8fa2ea..c24f25a 100644
--- a/services/preAuthOnboardingService.ts
+++ b/services/preAuthOnboardingService.ts
@@ -7,6 +7,7 @@ export type PreAuthAnswers = {
acquisitionSource?: string;
primaryGoal?: string;
experienceLevel?: string;
+ lightLevel?: string;
};
export const PreAuthOnboardingService = {
diff --git a/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_facebook_key_visual.png b/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_facebook_key_visual.png
new file mode 100644
index 0000000..bda4578
Binary files /dev/null and b/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_facebook_key_visual.png differ
diff --git a/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_01_3x4.png b/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_01_3x4.png
new file mode 100644
index 0000000..e2c849c
Binary files /dev/null and b/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_01_3x4.png differ
diff --git a/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_02_3x4.png b/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_02_3x4.png
new file mode 100644
index 0000000..1aec85b
Binary files /dev/null and b/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_02_3x4.png differ
diff --git a/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_03_3x4.png b/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_03_3x4.png
new file mode 100644
index 0000000..b714890
Binary files /dev/null and b/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_03_3x4.png differ
diff --git a/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_04_3x4.png b/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_04_3x4.png
new file mode 100644
index 0000000..a0b418c
Binary files /dev/null and b/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_04_3x4.png differ
diff --git a/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_05_3x4.png b/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_05_3x4.png
new file mode 100644
index 0000000..12956f2
Binary files /dev/null and b/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_05_3x4.png differ
diff --git a/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_06_3x4.png b/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_06_3x4.png
new file mode 100644
index 0000000..2b2fe4b
Binary files /dev/null and b/social_out/2026-07-06_root-rot-signs/greenlens_root_rot_slide_06_3x4.png differ
diff --git a/social_out/_shipping_note.txt b/social_out/_shipping_note.txt
new file mode 100644
index 0000000..8ae1da8
--- /dev/null
+++ b/social_out/_shipping_note.txt
@@ -0,0 +1,14 @@
+Ready for email delivery
+
+To send:
+1. Use the boards below as copy for each platform.
+2. QR Master image files:
+ - C:\Users\timo\Documents\greenlens\Greenlens\social_out\qrmaster_slides\slide_qr_1_dynamic.png
+ - C:\Users\timo\Documents\greenlens\Greenlens\social_out\qrmaster_slides\slide_qr_2_analytics.png
+ - C:\Users\timo\Documents\greenlens\Greenlens\social_out\qrmaster_slides\slide_qr_3_menu_update.png
+3. GreenLens Pro image files:
+ - C:\Users\timo\Documents\greenlens\Greenlens\social_out\greenlens_slides\slide_greenlens_1_cover.png
+
+Text:
+- C:\Users\timo\Documents\greenlens\Greenlens\social_out\qrmaster_posts\qrmaster_posts_en.txt
+- C:\Users\timo\Documents\greenlens\Greenlens\social_out\greenlens_posts\greenlens_posts_en.txt
diff --git a/social_out/greenlens_slides/slide_greenlens_1_cover.png b/social_out/greenlens_slides/slide_greenlens_1_cover.png
new file mode 100644
index 0000000..60904df
Binary files /dev/null and b/social_out/greenlens_slides/slide_greenlens_1_cover.png differ
diff --git a/social_out/greenlens_slides_contact_sheet.jpg b/social_out/greenlens_slides_contact_sheet.jpg
new file mode 100644
index 0000000..da3dc0e
Binary files /dev/null and b/social_out/greenlens_slides_contact_sheet.jpg differ
diff --git a/social_out/qrmaster_posts/qrmaster_posts_en.txt b/social_out/qrmaster_posts/qrmaster_posts_en.txt
new file mode 100644
index 0000000..5cf8ddf
--- /dev/null
+++ b/social_out/qrmaster_posts/qrmaster_posts_en.txt
@@ -0,0 +1,37 @@
+# QR Master — Social Posts
+
+## TikTok / Instagram / Facebook / X
+
+### Post A — Hook focused
+Most QR codes are disposable.
+One wrong print run means reprinting stickers, flyers and signs.
+QR Master lets you keep the same QR code and change the destination any time.
+No new artwork. No press shop. No waste.
+One code, endless updates.
+
+Perfect for menus, events, shop windows and campaigns.
+
+Stop printing forever. Start managing smarter:
+qrmaster.net
+
+### Post B — Analytics focused
+Don’t just count scans.
+Understand when people scan and where traffic drops off.
+QR Master shows simple scan analytics inside your dashboard.
+Track peaks. Spot time windows. Decide smarter.
+Great for restaurants, clubs, pop-ups and retail.
+
+Demo first, decide later:
+qrmaster.net
+
+### Post C — Use case: restaurant menu
+Restaurants change menus constantly.
+QR codes on tables shouldn’t.
+With QR Master:
+- Same code stays on tables
+- Update the menu URL in seconds
+- Track which hours get the most scans
+You focus on food. We keep the code working forever.
+
+Try it on your menu today:
+qrmaster.net
diff --git a/social_out/qrmaster_slides/slide_qr_1_dynamic.png b/social_out/qrmaster_slides/slide_qr_1_dynamic.png
new file mode 100644
index 0000000..f319046
Binary files /dev/null and b/social_out/qrmaster_slides/slide_qr_1_dynamic.png differ
diff --git a/social_out/qrmaster_slides/slide_qr_2_analytics.png b/social_out/qrmaster_slides/slide_qr_2_analytics.png
new file mode 100644
index 0000000..eb9d334
Binary files /dev/null and b/social_out/qrmaster_slides/slide_qr_2_analytics.png differ
diff --git a/social_out/qrmaster_slides/slide_qr_3_menu_update.png b/social_out/qrmaster_slides/slide_qr_3_menu_update.png
new file mode 100644
index 0000000..83bcf01
Binary files /dev/null and b/social_out/qrmaster_slides/slide_qr_3_menu_update.png differ
diff --git a/social_out/qrmaster_slides_contact_sheet.jpg b/social_out/qrmaster_slides_contact_sheet.jpg
new file mode 100644
index 0000000..df5e7e4
Binary files /dev/null and b/social_out/qrmaster_slides_contact_sheet.jpg differ
diff --git a/utils/translations.ts b/utils/translations.ts
index 065c2f6..32f0a9e 100644
--- a/utils/translations.ts
+++ b/utils/translations.ts
@@ -526,7 +526,7 @@ registerToSave: "Sign up to save",
welcomeHeadline: "Plant care\nstarts here",
welcomeSubheadline: "Scan a leaf, learn the plant, keep it healthy.",
welcomeFeatureIdentifyTitle: "AI plant identification",
- welcomeFeatureIdentifyDesc: "Try up to 5 demo scans on this device.",
+ welcomeFeatureIdentifyDesc: "Try up to 3 demo scans on this device.",
welcomeFeatureReminderTitle: "Care plan & reminders",
welcomeFeatureReminderDesc: "Get clear guidance for water, light, and placement.",
welcomeFeatureLibraryTitle: "Save your plants",
@@ -798,7 +798,7 @@ registerToSave: "Regístrate para guardar",
welcomeHeadline: "El cuidado\nempieza aquí",
welcomeSubheadline: "Escanea una hoja, conoce la planta y mantenla sana.",
welcomeFeatureIdentifyTitle: "Identificación con IA",
- welcomeFeatureIdentifyDesc: "Prueba hasta 5 escaneos demo en este dispositivo.",
+ welcomeFeatureIdentifyDesc: "Prueba hasta 3 escaneos demo en este dispositivo.",
welcomeFeatureReminderTitle: "Plan de cuidado y recordatorios",
welcomeFeatureReminderDesc: "Recibe consejos claros sobre riego, luz y ubicación.",
welcomeFeatureLibraryTitle: "Guardar tus plantas",