Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a172fce56 |
No files matched your search
@@ -36,61 +36,3 @@ jobs:
|
|||||||
--app chat_web_app \
|
--app chat_web_app \
|
||||||
--env prod \
|
--env prod \
|
||||||
--ref "${{ gitea.sha }}"
|
--ref "${{ gitea.sha }}"
|
||||||
|
|
||||||
# Same commit the workflow was started from (the branch picked in Run workflow).
|
|
||||||
android-release:
|
|
||||||
needs: deploy-prod
|
|
||||||
runs-on: self-hosted
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: llm-fe
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: ${{ gitea.sha }}
|
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "20"
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Resolve Play version
|
|
||||||
env:
|
|
||||||
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GITEA_SHA: ${{ gitea.sha }}
|
|
||||||
run: node scripts/android-version.mjs
|
|
||||||
|
|
||||||
- name: Build store web bundle
|
|
||||||
run: npm run build:android:store
|
|
||||||
|
|
||||||
- name: Sign with the Play upload key
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
test -f /home/westfarn/.android/hesychia-keystore.properties
|
|
||||||
test -f /home/westfarn/.android/hesychia-upload.jks
|
|
||||||
test -d /home/westfarn/Android/Sdk
|
|
||||||
ln -sfn /home/westfarn/.android/hesychia-keystore.properties android/keystore.properties
|
|
||||||
printf 'sdk.dir=%s\n' /home/westfarn/Android/Sdk > android/local.properties
|
|
||||||
|
|
||||||
- name: Package signed app bundle
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
cd android
|
|
||||||
chmod +x ./gradlew
|
|
||||||
./gradlew bundleRelease \
|
|
||||||
-PhesychiaVersionCode="$HESYCHIA_VERSION_CODE" \
|
|
||||||
-PhesychiaVersionName="$HESYCHIA_VERSION_NAME"
|
|
||||||
jarsigner -verify app/build/outputs/bundle/release/app-release.aab >/tmp/jarsigner-aab.txt 2>&1
|
|
||||||
echo "jar verified"
|
|
||||||
|
|
||||||
- name: Publish Gitea release
|
|
||||||
env:
|
|
||||||
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GITEA_SHA: ${{ gitea.sha }}
|
|
||||||
GITEA_REF_NAME: ${{ gitea.ref_name }}
|
|
||||||
run: node scripts/publish-android-gitea-release.mjs
|
|
||||||
@@ -4,9 +4,3 @@
|
|||||||
# REACT_APP_BACKEND_WS_API_BASE_URL=wss://beta.chatbackend.aimloperations.com/ws/chat_again/
|
# REACT_APP_BACKEND_WS_API_BASE_URL=wss://beta.chatbackend.aimloperations.com/ws/chat_again/
|
||||||
REACT_APP_BACKEND_REST_API_BASE_URL=https://chatbackend.aimloperations.com/api/
|
REACT_APP_BACKEND_REST_API_BASE_URL=https://chatbackend.aimloperations.com/api/
|
||||||
REACT_APP_BACKEND_WS_API_BASE_URL=wss://chatbackend.aimloperations.com/ws/chat_again/
|
REACT_APP_BACKEND_WS_API_BASE_URL=wss://chatbackend.aimloperations.com/ws/chat_again/
|
||||||
|
|
||||||
# RevenueCat public SDK keys (native IAP). Leave empty until store apps are wired.
|
|
||||||
REACT_APP_REVENUECAT_APPLE_API_KEY=
|
|
||||||
REACT_APP_REVENUECAT_GOOGLE_API_KEY=
|
|
||||||
# Optional: pin a specific offering identifier (defaults to current offering).
|
|
||||||
# REACT_APP_REVENUECAT_OFFERING_ID=
|
|
||||||
@@ -23,18 +23,6 @@
|
|||||||
*.keystore
|
*.keystore
|
||||||
*.jks
|
*.jks
|
||||||
|
|
||||||
# Capacitor / iOS CocoaPods + build artifacts (keep ios/ source; ignore Pods / DerivedData)
|
|
||||||
/ios/App/Pods/
|
|
||||||
/ios/App/build/
|
|
||||||
/ios/App/output/
|
|
||||||
/ios/App/App/public/
|
|
||||||
/ios/DerivedData/
|
|
||||||
/ios/**/xcuserdata/
|
|
||||||
*.mobileprovision
|
|
||||||
*.p12
|
|
||||||
*.cer
|
|
||||||
ExportOptions.plist
|
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.env.local
|
.env.local
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ Page views: always via `Tracker` / `tracker.js` on prod + beta.
|
|||||||
| Message Rated | `MESSAGE_RATED` | MessageActions | `{ rating: 'up' \| 'down' \| 'cleared' }` |
|
| Message Rated | `MESSAGE_RATED` | MessageActions | `{ rating: 'up' \| 'down' \| 'cleared' }` |
|
||||||
| Message Rating Reason | `MESSAGE_RATING_REASON` | MessageActions | `{ reason, hasComment }` |
|
| Message Rating Reason | `MESSAGE_RATING_REASON` | MessageActions | `{ reason, hasComment }` |
|
||||||
| Message Exported | `MESSAGE_EXPORTED` | MessageActions, AsyncDashboard2 | `{ format, scope }` |
|
| Message Exported | `MESSAGE_EXPORTED` | MessageActions, AsyncDashboard2 | `{ format, scope }` |
|
||||||
| Activity Stage Completed | `ACTIVITY_STAGE_COMPLETED` | MessageContext | `{ stage, durationMs }` (no label/detail text) |
|
|
||||||
|
|
||||||
## Identify
|
## Identify
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
# Android (Capacitor)
|
# Android (Capacitor)
|
||||||
|
|
||||||
Ship the CRA web build as an Android app via [Capacitor](https://capacitorjs.com/).
|
Ship the CRA web build as an Android app via [Capacitor](https://capacitorjs.com/).
|
||||||
One codebase: `llm-fe/` → web + Android + iOS WebView.
|
One codebase: `llm-fe/` → web + Android WebView.
|
||||||
|
|
||||||
**Build & Play deploy steps:** [`android/README.md`](android/README.md).
|
**Build & Play deploy steps:** [`android/README.md`](android/README.md).
|
||||||
**iOS sibling:** [`IOS.md`](IOS.md) / [`ios/README.md`](ios/README.md).
|
|
||||||
|
|
||||||
Prerequisites for blockers already merged: JWT-only auth (#22), WebSocket lifecycle (#23), HashRouter (#24).
|
Prerequisites for blockers already merged: JWT-only auth (#22), WebSocket lifecycle (#23), HashRouter (#24).
|
||||||
|
|
||||||
@@ -40,47 +39,14 @@ npm run android:sync
|
|||||||
|
|
||||||
Default `.env.mobile` matches production (`chatbackend.aimloperations.com`). Point it at beta to flip the shell without touching web deploys. Optional gitignored override: `.env.mobile.local`.
|
Default `.env.mobile` matches production (`chatbackend.aimloperations.com`). Point it at beta to flip the shell without touching web deploys. Optional gitignored override: `.env.mobile.local`.
|
||||||
|
|
||||||
### Play Billing (#78)
|
|
||||||
|
|
||||||
Native billing uses the local Capacitor plugin `native-store-billing` (Play Billing on Android, StoreKit on iOS). Web keeps Stripe Checkout / Customer Portal.
|
|
||||||
|
|
||||||
The Play product id is the plan's `store_product_id`. The backend verifies the purchase token with the Play Developer API (`GOOGLE_PLAY_SERVICE_ACCOUNT_JSON`). More detail: [`MONETIZATION.md`](MONETIZATION.md).
|
|
||||||
|
|
||||||
After plugin changes: `npm run build:mobile` (runs `cap sync`).
|
|
||||||
|
|
||||||
## Versioning
|
## Versioning
|
||||||
|
|
||||||
`android/app/build.gradle` keeps a floor:
|
In `android/app/build.gradle`:
|
||||||
|
|
||||||
- `hesychiaVersionNameFloor` — `"0.1.0"` (user-visible string)
|
- **versionName** — user-visible string; keep aligned with `package.json` `version` (currently `0.1.0`)
|
||||||
- `hesychiaVersionCodeFloor` — `1` (integer; Play requires a higher code on every upload)
|
- **versionCode** — integer; **must increase** for every Play Store upload
|
||||||
|
|
||||||
Local `./gradlew bundleRelease` uses that floor when you do not pass properties. **Deploy Prod** does not edit the file. After the web deploy it looks up existing `android-v*` Gitea releases, reuses the pair when the tag already points at this commit, otherwise ships the next patch and the next `versionCode` via `-PhesychiaVersionName` / `-PhesychiaVersionCode`.
|
Bump both before each store release.
|
||||||
|
|
||||||
Raise the floor in git only when you want the next automatic release to jump ahead of older tags.
|
|
||||||
|
|
||||||
## Deploy Prod publishes the Play bundle
|
|
||||||
|
|
||||||
**Deploy Prod** (`.gitea/workflows/deploy-prod.yml`) runs `android-release` after the prod web deploy of the same commit. The job:
|
|
||||||
|
|
||||||
1. Resolves the Play version (`llm-fe/scripts/android-version.mjs`)
|
|
||||||
2. `npm run build:android:store` — `.env.mobile` (prod API) plus `cap sync android`
|
|
||||||
3. Signs with the upload keystore on the runner (`~/.android/`, not in git)
|
|
||||||
4. `jarsigner -verify` on `app-release.aab`
|
|
||||||
5. Creates or reuses a Gitea release tagged `android-v<versionName>-<versionCode>` and attaches `hesychia-<versionName>-<versionCode>.aab`
|
|
||||||
|
|
||||||
Example of the same shape on RealPath: [android-v1.0.2-3](https://git.aimloperations.com/Ditch_The_Agent/dta_webapp/releases/tag/android-v1.0.2-3).
|
|
||||||
|
|
||||||
Download that AAB from the Gitea release and upload it to the Play **internal** track. Deploy Prod does not call the Play Developer API. A separate **Deploy Android** workflow is not used ([#58](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/58) is superseded by this job, [#121](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/121)).
|
|
||||||
|
|
||||||
Manual store binary (same web bundle the job builds):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd llm-fe
|
|
||||||
npm run build:android:store
|
|
||||||
cd android
|
|
||||||
./gradlew bundleRelease
|
|
||||||
```
|
|
||||||
|
|
||||||
## Icons / splash
|
## Icons / splash
|
||||||
|
|
||||||
@@ -97,43 +63,25 @@ Regenerate Android densities after changing source art:
|
|||||||
npm run assets:generate
|
npm run assets:generate
|
||||||
```
|
```
|
||||||
|
|
||||||
Same command also regenerates iOS `Assets.xcassets` (see [`IOS.md`](IOS.md)).
|
|
||||||
|
|
||||||
## Signing (upload keystore)
|
## Signing (upload keystore)
|
||||||
|
|
||||||
**Never commit keystores or `keystore.properties`.** Passwords stay on the runner, not in Gitea Actions secrets.
|
**Never commit keystores.** Store outside the repo (e.g. host secrets / password manager).
|
||||||
|
|
||||||
Deploy Prod expects these host files (separate from RealPath’s `keystore.properties`, so the two apps do not share one symlink target):
|
|
||||||
|
|
||||||
```text
|
|
||||||
/home/westfarn/.android/hesychia-upload.jks
|
|
||||||
/home/westfarn/.android/hesychia-keystore.properties # mode 600
|
|
||||||
```
|
|
||||||
|
|
||||||
Create the upload key **once**. If Play already has an upload key for `ai.hesychia.chat`, reuse that keystore. A second keystore will not upload.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
keytool -genkey -v \
|
keytool -genkey -v -keystore ~/Documents/secrets/aiml-chat-upload.jks \
|
||||||
-keystore /home/westfarn/.android/hesychia-upload.jks \
|
|
||||||
-keyalg RSA -keysize 2048 -validity 10000 \
|
-keyalg RSA -keysize 2048 -validity 10000 \
|
||||||
-alias aiml-chat-upload
|
-alias aiml-chat-upload
|
||||||
```
|
```
|
||||||
|
|
||||||
`hesychia-keystore.properties` (`storeFile` may be absolute):
|
Create `llm-fe/android/keystore.properties` (gitignored):
|
||||||
|
|
||||||
```properties
|
```properties
|
||||||
storeFile=/home/westfarn/.android/hesychia-upload.jks
|
storeFile=/absolute/path/to/aiml-chat-upload.jks
|
||||||
storePassword=...
|
storePassword=...
|
||||||
keyAlias=aiml-chat-upload
|
keyAlias=aiml-chat-upload
|
||||||
keyPassword=...
|
keyPassword=...
|
||||||
```
|
```
|
||||||
|
|
||||||
The workflow symlinks that file to `llm-fe/android/keystore.properties` and writes `android/local.properties` with `sdk.dir=/home/westfarn/Android/Sdk`. For a local release build, put the same `keystore.properties` in `llm-fe/android/` (gitignored).
|
|
||||||
|
|
||||||
Also on the runner: JDK 17+ and Android SDK Platform 35 at `/home/westfarn/Android/Sdk`.
|
|
||||||
|
|
||||||
Gitea Actions secret on `chat_web_app`: `GITHUB_TOKEN` (repo release write). The workflow maps it to `GITEA_TOKEN` for version lookup and release upload. Purchase verification uses backend `GOOGLE_PLAY_SERVICE_ACCOUNT_JSON`, not this keystore.
|
|
||||||
|
|
||||||
Release App Bundle:
|
Release App Bundle:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -167,20 +115,12 @@ Out of band ops (not automated here):
|
|||||||
|
|
||||||
1. Google Play developer account
|
1. Google Play developer account
|
||||||
2. Privacy policy URL (product site / legal)
|
2. Privacy policy URL (product site / legal)
|
||||||
3. **Account deletion URL** (Data safety / Account deletion) → public page:
|
3. Data safety form (JWT auth, chat content, analytics if Tianji runs in WebView)
|
||||||
- Canonical: `https://hesychia.ai/account-deletion/`
|
4. Screenshots for phone (+ tablet if targeting)
|
||||||
- Legacy host until DNS cutover: `https://chat.aimloperations.com/account-deletion/`
|
5. Upload `.aab` to **internal testing** track before production
|
||||||
- Capacitor HashRouter: `/#/account-deletion/`
|
|
||||||
4. Data safety form (JWT auth, chat content, analytics if Tianji runs in WebView)
|
|
||||||
5. Screenshots for phone (+ tablet if targeting)
|
|
||||||
6. Upload `.aab` to **internal testing** track before production
|
|
||||||
|
|
||||||
In-app delete remains Account → **Delete my account** (`DELETE /api/user/`). The public URL
|
|
||||||
above is for Play reviewers and users who never open the app (#103).
|
|
||||||
|
|
||||||
## Related issues
|
## Related issues
|
||||||
|
|
||||||
- [#20](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/20) — this Android wrap
|
- [#20](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/20) — this Android wrap
|
||||||
- [#21](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/21) — iOS (reuses this scaffolding)
|
- [#21](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/21) — iOS (reuses this scaffolding)
|
||||||
- [#22](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/22) / [#23](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/23) / [#24](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/24) — auth / WS / routing
|
- [#22](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/22) / [#23](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/23) / [#24](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/24) — auth / WS / routing
|
||||||
- [#103](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/103) — Play public account-deletion URL
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
# iOS (Capacitor)
|
|
||||||
|
|
||||||
Ship the CRA web build as an iOS app via [Capacitor](https://capacitorjs.com/)
|
|
||||||
WKWebView. One codebase: `llm-fe/` → web + Android + iOS.
|
|
||||||
|
|
||||||
**Build & Xcode steps:** [`ios/README.md`](ios/README.md).
|
|
||||||
|
|
||||||
Prerequisites already merged: JWT-only auth (#22), WebSocket lifecycle (#23),
|
|
||||||
HashRouter (#24), Android Capacitor scaffolding (#20).
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- **macOS** with **Xcode** 15+ (CI runners are Linux — iOS builds are **manual**
|
|
||||||
on a Mac until a hosted macOS runner is added)
|
|
||||||
- **Node.js 20** (matches CI; Capacitor **7.x**)
|
|
||||||
- **CocoaPods** (`sudo gem install cocoapods` or Homebrew `pod`)
|
|
||||||
- Apple Developer Program membership for device / TestFlight / App Store signing
|
|
||||||
(simulator debug runs without a paid membership using automatic signing)
|
|
||||||
|
|
||||||
## One-time / day-to-day
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd llm-fe
|
|
||||||
npm ci
|
|
||||||
npm run build:mobile # .env.mobile → CRA build → cap sync (android + ios)
|
|
||||||
npm run ios:open # opens ios/App/App.xcworkspace in Xcode
|
|
||||||
```
|
|
||||||
|
|
||||||
Or sync only after an existing `build/`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run ios:sync
|
|
||||||
```
|
|
||||||
|
|
||||||
**Always open the `.xcworkspace`**, not the `.xcodeproj` (CocoaPods).
|
|
||||||
|
|
||||||
## Environment
|
|
||||||
|
|
||||||
Same as Android — see [`ANDROID.md`](ANDROID.md) § Environment.
|
|
||||||
|
|
||||||
| File | Purpose |
|
|
||||||
|------|---------|
|
|
||||||
| `.env.mobile` | Endpoints baked into the **mobile** bundle (`build:mobile`) |
|
|
||||||
| `.env.mobile.local` | Optional gitignored override |
|
|
||||||
|
|
||||||
Default `.env.mobile` points at production (`chatbackend.aimloperations.com`).
|
|
||||||
|
|
||||||
WebView origin is `capacitor://localhost`. Backend CORS/CSRF already trusts it
|
|
||||||
(`chat_backend` `CAPACITOR_WEBVIEW_ORIGINS`). Auth is header JWT — no cookies.
|
|
||||||
|
|
||||||
## Versioning
|
|
||||||
|
|
||||||
In Xcode target **App** → General, or `ios/App/App.xcodeproj/project.pbxproj`:
|
|
||||||
|
|
||||||
| Field | Xcode / build setting | Align with |
|
|
||||||
|-------|----------------------|------------|
|
|
||||||
| Version | `MARKETING_VERSION` (`CFBundleShortVersionString`) | `package.json` `version` + Android `versionName` (currently `0.1.0`) |
|
|
||||||
| Build | `CURRENT_PROJECT_VERSION` (`CFBundleVersion`) | Android `versionCode` (integer; **must increase** every TestFlight / App Store upload) |
|
|
||||||
|
|
||||||
## Icons / splash
|
|
||||||
|
|
||||||
Source art in `llm-fe/assets/` (same as Android):
|
|
||||||
|
|
||||||
- `icon.png` / `splash.png` / `splash-dark.png`
|
|
||||||
|
|
||||||
Regenerate iOS + Android densities:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run assets:generate
|
|
||||||
```
|
|
||||||
|
|
||||||
## Signing
|
|
||||||
|
|
||||||
**Never commit certificates, profiles, or `.p12` files.**
|
|
||||||
|
|
||||||
1. Xcode → Signing & Capabilities → Team (Automatic for debug / internal).
|
|
||||||
2. Bundle ID: **`ai.hesychia.chat`** (matches Android `applicationId` / Capacitor `appId`).
|
|
||||||
3. For distribution: App Store Connect app, distribution cert, provisioning profile
|
|
||||||
— keep credentials outside the repo (password manager / CI secrets later).
|
|
||||||
|
|
||||||
## Manual QA checklist
|
|
||||||
|
|
||||||
On **simulator and physical iPhone**:
|
|
||||||
|
|
||||||
- [ ] Login / logout / password reset
|
|
||||||
- [ ] Chat streaming + markdown / code blocks (selection + copy)
|
|
||||||
- [ ] Charts (`recharts`)
|
|
||||||
- [ ] Dark / light theme
|
|
||||||
- [ ] Keyboard does not cover compose input; notch / Dynamic Island / home indicator OK
|
|
||||||
- [ ] No rubber-band overscroll on chat shell
|
|
||||||
- [ ] Background → resume keeps or reconnects WebSocket (`appStateChange` + visibility)
|
|
||||||
- [ ] Cellular ↔ Wi‑Fi switch reconnects socket
|
|
||||||
- [ ] Airplane mode → restore reconnects
|
|
||||||
|
|
||||||
## TestFlight / App Store (follow-on)
|
|
||||||
|
|
||||||
Out of band (not automated here; separate deploy tickets):
|
|
||||||
|
|
||||||
1. Apple Developer Program + App ID `ai.hesychia.chat`
|
|
||||||
2. Privacy policy URL + App Privacy questionnaire
|
|
||||||
3. In-app account deletion if sign-up is offered (guideline)
|
|
||||||
4. Enough native shell value that review does not reject as 4.2 “repackaged website”
|
|
||||||
5. Archive → Upload → TestFlight internal → App Store
|
|
||||||
|
|
||||||
Push notifications, offline cache, Sign in with Apple — out of scope for this wrap.
|
|
||||||
|
|
||||||
## Related issues
|
|
||||||
|
|
||||||
- [#21](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/21) — this iOS wrap
|
|
||||||
- [#20](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/20) — Android scaffolding
|
|
||||||
- [#22](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/22) / [#23](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/23) / [#24](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/24) — auth / WS / routing
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# Monetization (web Stripe + native store billing)
|
|
||||||
|
|
||||||
## Channels
|
|
||||||
|
|
||||||
| Runtime | Checkout / manage | Ledger |
|
|
||||||
|---------|-------------------|--------|
|
|
||||||
| Web (`!isNativePlatform`) | Stripe Checkout + Customer Portal via `/monetization/...` | Stripe webhooks |
|
|
||||||
| Native Capacitor | StoreKit (iOS) and Play Billing (Android) | `POST /monetization/store/confirm/` verifies the store transaction and writes the same invoice/payment tables |
|
|
||||||
|
|
||||||
There is no App Store, Play, or RevenueCat webhook. After the store sheet succeeds, the app sends the signed StoreKit transaction or the Play purchase token. The backend checks it before granting access. Renewals and restores send the current store entitlement again. Access ends when the verified period end passes.
|
|
||||||
|
|
||||||
FE displays whatever `/monetization/invoices/` (and subscription) returns after refresh. Provider badge uses `provider` (`app_store`, `play_store`, or legacy `revenuecat`) plus `revenuecat_store`.
|
|
||||||
|
|
||||||
## Store account token
|
|
||||||
|
|
||||||
`GET /monetization/subscription/` returns `store_account_token`. The native purchase passes that value as StoreKit `appAccountToken` and Play Billing `obfuscatedAccountId`. The backend rejects a token that belongs to a different user, and rejects a transaction already linked to another account.
|
|
||||||
|
|
||||||
Plan rows expose `store_product_id` (the store product identifier). Configure it on `SubscriptionPlan.revenuecat_product_id`, or set `REVENUECAT_PRODUCT_PLAN_MAP` so a product id maps to a plan slug.
|
|
||||||
|
|
||||||
## Related
|
|
||||||
|
|
||||||
- Backend issue #78
|
|
||||||
- [`ANDROID.md`](ANDROID.md) / [`IOS.md`](IOS.md) for store builds
|
|
||||||
@@ -19,8 +19,7 @@ From the **npm root** (`llm-fe/`, one level up):
|
|||||||
```bash
|
```bash
|
||||||
cd ..
|
cd ..
|
||||||
npm ci
|
npm ci
|
||||||
npm run build:android:store # Play binary: .env.mobile → build → cap sync android
|
npm run build:mobile # .env.mobile → react-scripts build → cap sync android
|
||||||
# npm run build:mobile # same web env, also syncs iOS
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Open this project in Android Studio:
|
Open this project in Android Studio:
|
||||||
@@ -55,11 +54,11 @@ adb install -r app/build/outputs/apk/debug/app-debug.apk
|
|||||||
|
|
||||||
## Version before a store release
|
## Version before a store release
|
||||||
|
|
||||||
`app/build.gradle` stores the floor (`hesychiaVersionNameFloor` / `hesychiaVersionCodeFloor`). A local `bundleRelease` uses that floor. **Deploy Prod** passes the next pair with `-PhesychiaVersionName` and `-PhesychiaVersionCode` after reading `android-v*` Gitea releases, so a prod run does not need a version commit.
|
Edit `app/build.gradle` → `defaultConfig`:
|
||||||
|
|
||||||
| Field | Rule |
|
| Field | Rule |
|
||||||
|-------|------|
|
|-------|------|
|
||||||
| `versionName` | User-visible `major.minor.patch` |
|
| `versionName` | User-visible string; keep in sync with `../package.json` `version` |
|
||||||
| `versionCode` | Integer; **must increase** for every Play upload |
|
| `versionCode` | Integer; **must increase** for every Play upload |
|
||||||
|
|
||||||
## Sign a release build
|
## Sign a release build
|
||||||
@@ -69,17 +68,15 @@ adb install -r app/build/outputs/apk/debug/app-debug.apk
|
|||||||
1. Create an upload keystore (once), outside the repo:
|
1. Create an upload keystore (once), outside the repo:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
keytool -genkey -v -keystore /home/westfarn/.android/hesychia-upload.jks \
|
keytool -genkey -v -keystore ~/Documents/secrets/aiml-chat-upload.jks \
|
||||||
-keyalg RSA -keysize 2048 -validity 10000 \
|
-keyalg RSA -keysize 2048 -validity 10000 \
|
||||||
-alias aiml-chat-upload
|
-alias aiml-chat-upload
|
||||||
```
|
```
|
||||||
|
|
||||||
Reuse an existing Play upload key. Do not generate a second keystore for an app that already has one.
|
2. Create `keystore.properties` in **this** directory (`android/`, gitignored):
|
||||||
|
|
||||||
2. Create `keystore.properties` in **this** directory (`android/`, gitignored). On the Deploy Prod runner the file is `/home/westfarn/.android/hesychia-keystore.properties` (not RealPath’s `keystore.properties`):
|
|
||||||
|
|
||||||
```properties
|
```properties
|
||||||
storeFile=/home/westfarn/.android/hesychia-upload.jks
|
storeFile=/absolute/path/to/aiml-chat-upload.jks
|
||||||
storePassword=REPLACE_ME
|
storePassword=REPLACE_ME
|
||||||
keyAlias=aiml-chat-upload
|
keyAlias=aiml-chat-upload
|
||||||
keyPassword=REPLACE_ME
|
keyPassword=REPLACE_ME
|
||||||
@@ -108,19 +105,11 @@ Without `keystore.properties`, release builds are unsigned; debug builds do not
|
|||||||
|
|
||||||
## Deploy to Google Play
|
## Deploy to Google Play
|
||||||
|
|
||||||
**Deploy Prod** builds the signed AAB and attaches it to a Gitea release (`android-v<versionName>-<versionCode>`, asset `hesychia-<versionName>-<versionCode>.aab`). Download that asset and upload it yourself. See [`../ANDROID.md`](../ANDROID.md).
|
|
||||||
|
|
||||||
1. [Play Console](https://play.google.com/console) → app **Hesychia** (`ai.hesychia.chat`).
|
1. [Play Console](https://play.google.com/console) → app **Hesychia** (`ai.hesychia.chat`).
|
||||||
2. Complete store listing: privacy policy URL, data-safety form, screenshots.
|
2. Complete store listing: privacy policy URL, data-safety form, screenshots.
|
||||||
3. Set **Account deletion URL** to the public instructions page (no sign-in required):
|
3. **Testing → Internal testing** → create release → upload `app-release.aab`.
|
||||||
- `https://hesychia.ai/account-deletion/` (preferred product host)
|
4. Add testers, roll out internal track, verify on devices.
|
||||||
- or `https://chat.aimloperations.com/account-deletion/` until hesychia.ai cutover
|
5. Promote to closed / open / production only after internal QA passes.
|
||||||
4. **Testing → Internal testing** → create release → upload `app-release.aab`.
|
|
||||||
5. Add testers, roll out internal track, verify on devices.
|
|
||||||
6. Promote to closed / open / production only after internal QA passes.
|
|
||||||
|
|
||||||
See also [`../ANDROID.md`](../ANDROID.md) Play checklist and issue
|
|
||||||
[#103](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/103).
|
|
||||||
|
|
||||||
Each new upload needs a higher `versionCode`.
|
Each new upload needs a higher `versionCode`.
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,5 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
// Last bundle recorded in git. Prod deploy passes -PhesychiaVersionCode and
|
|
||||||
// -PhesychiaVersionName; these stay the floor when those properties are absent.
|
|
||||||
def hesychiaVersionCodeFloor = 1
|
|
||||||
def hesychiaVersionNameFloor = "0.1.0"
|
|
||||||
|
|
||||||
// Resolve before the android block. A parenthesized expression on the versionCode
|
|
||||||
// setter is parsed as a cast of the setter result, so AGP throws "Value is null".
|
|
||||||
def hesychiaVersionCodeProp = project.findProperty('hesychiaVersionCode')?.toString()?.trim()
|
|
||||||
def hesychiaVersionNameProp = project.findProperty('hesychiaVersionName')?.toString()?.trim()
|
|
||||||
def resolvedVersionCode = hesychiaVersionCodeProp ? hesychiaVersionCodeProp.toInteger() : hesychiaVersionCodeFloor
|
|
||||||
def resolvedVersionName = hesychiaVersionNameProp ? hesychiaVersionNameProp : hesychiaVersionNameFloor
|
|
||||||
|
|
||||||
def keystorePropertiesFile = rootProject.file('keystore.properties')
|
def keystorePropertiesFile = rootProject.file('keystore.properties')
|
||||||
def keystoreProperties = new Properties()
|
def keystoreProperties = new Properties()
|
||||||
if (keystorePropertiesFile.exists()) {
|
if (keystorePropertiesFile.exists()) {
|
||||||
@@ -25,8 +13,8 @@ android {
|
|||||||
applicationId "ai.hesychia.chat"
|
applicationId "ai.hesychia.chat"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode resolvedVersionCode
|
versionCode 1
|
||||||
versionName resolvedVersionName
|
versionName "0.1.0"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
aaptOptions {
|
aaptOptions {
|
||||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||||
@@ -39,7 +27,7 @@ android {
|
|||||||
if (keystorePropertiesFile.exists()) {
|
if (keystorePropertiesFile.exists()) {
|
||||||
keyAlias keystoreProperties['keyAlias']
|
keyAlias keystoreProperties['keyAlias']
|
||||||
keyPassword keystoreProperties['keyPassword']
|
keyPassword keystoreProperties['keyPassword']
|
||||||
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
storeFile file(keystoreProperties['storeFile'])
|
||||||
storePassword keystoreProperties['storePassword']
|
storePassword keystoreProperties['storePassword']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ dependencies {
|
|||||||
implementation project(':capacitor-keyboard')
|
implementation project(':capacitor-keyboard')
|
||||||
implementation project(':capacitor-preferences')
|
implementation project(':capacitor-preferences')
|
||||||
implementation project(':capacitor-status-bar')
|
implementation project(':capacitor-status-bar')
|
||||||
implementation project(':native-store-billing')
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 428 KiB After Width: | Height: | Size: 427 KiB |
|
Before Width: | Height: | Size: 644 KiB After Width: | Height: | Size: 643 KiB |
|
Before Width: | Height: | Size: 895 KiB After Width: | Height: | Size: 894 KiB |
|
Before Width: | Height: | Size: 428 KiB After Width: | Height: | Size: 427 KiB |
|
Before Width: | Height: | Size: 644 KiB After Width: | Height: | Size: 643 KiB |
|
Before Width: | Height: | Size: 895 KiB After Width: | Height: | Size: 894 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 413 KiB After Width: | Height: | Size: 412 KiB |
|
Before Width: | Height: | Size: 623 KiB After Width: | Height: | Size: 622 KiB |
|
Before Width: | Height: | Size: 875 KiB After Width: | Height: | Size: 874 KiB |
|
Before Width: | Height: | Size: 413 KiB After Width: | Height: | Size: 412 KiB |
|
Before Width: | Height: | Size: 623 KiB After Width: | Height: | Size: 622 KiB |
|
Before Width: | Height: | Size: 875 KiB After Width: | Height: | Size: 874 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 276 B After Width: | Height: | Size: 277 B |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 201 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
@@ -13,6 +13,3 @@ project(':capacitor-preferences').projectDir = new File('../node_modules/@capaci
|
|||||||
|
|
||||||
include ':capacitor-status-bar'
|
include ':capacitor-status-bar'
|
||||||
project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android')
|
project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android')
|
||||||
|
|
||||||
include ':native-store-billing'
|
|
||||||
project(':native-store-billing').projectDir = new File('../plugins/native-store-billing/android')
|
|
||||||
@@ -6,20 +6,11 @@ const config: CapacitorConfig = {
|
|||||||
webDir: 'build',
|
webDir: 'build',
|
||||||
server: {
|
server: {
|
||||||
// Bundled assets; HashRouter (#24) handles deep links without a rewrite server.
|
// Bundled assets; HashRouter (#24) handles deep links without a rewrite server.
|
||||||
// Android: https://localhost — iOS: capacitor://localhost (CORS trusted in chat_backend).
|
|
||||||
androidScheme: 'https',
|
androidScheme: 'https',
|
||||||
iosScheme: 'capacitor',
|
|
||||||
},
|
},
|
||||||
android: {
|
android: {
|
||||||
allowMixedContent: false,
|
allowMixedContent: false,
|
||||||
},
|
},
|
||||||
ios: {
|
|
||||||
// Prefer content-driven insets; CSS env(safe-area-inset-*) handles notch / home indicator.
|
|
||||||
contentInset: 'automatic',
|
|
||||||
// Keep WebView scroll on; rubber-band bounce disabled in AppDelegate after load.
|
|
||||||
scrollEnabled: true,
|
|
||||||
preferredContentMode: 'mobile',
|
|
||||||
},
|
|
||||||
plugins: {
|
plugins: {
|
||||||
SplashScreen: {
|
SplashScreen: {
|
||||||
launchAutoHide: true,
|
launchAutoHide: true,
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 113 KiB |
|
Before Width: | Height: | Size: 118 KiB |
@@ -1,20 +0,0 @@
|
|||||||
App/build
|
|
||||||
App/Pods
|
|
||||||
App/output
|
|
||||||
App/App/public
|
|
||||||
DerivedData
|
|
||||||
xcuserdata
|
|
||||||
|
|
||||||
# Cordova plugins for Capacitor
|
|
||||||
capacitor-cordova-ios-plugins
|
|
||||||
|
|
||||||
# Generated Config files
|
|
||||||
App/App/capacitor.config.json
|
|
||||||
App/App/config.xml
|
|
||||||
|
|
||||||
# Signing / export artifacts — never commit
|
|
||||||
*.mobileprovision
|
|
||||||
*.p12
|
|
||||||
*.cer
|
|
||||||
ExportOptions.plist
|
|
||||||
*.ipa
|
|
||||||
@@ -1,408 +0,0 @@
|
|||||||
// !$*UTF8*$!
|
|
||||||
{
|
|
||||||
archiveVersion = 1;
|
|
||||||
classes = {
|
|
||||||
};
|
|
||||||
objectVersion = 48;
|
|
||||||
objects = {
|
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
|
||||||
2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
|
|
||||||
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
|
|
||||||
504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
|
|
||||||
504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; };
|
|
||||||
504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; };
|
|
||||||
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; };
|
|
||||||
50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
|
|
||||||
A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; };
|
|
||||||
/* End PBXBuildFile section */
|
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
|
||||||
2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
|
|
||||||
50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
|
|
||||||
504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
|
||||||
504EC30C1FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
|
||||||
504EC30E1FED79650016851F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
|
||||||
504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
|
||||||
504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
|
||||||
50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = "<group>"; };
|
|
||||||
AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
|
||||||
504EC3011FED79650016851F /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXFrameworksBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
|
||||||
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */,
|
|
||||||
);
|
|
||||||
name = Frameworks;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
504EC2FB1FED79650016851F = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
504EC3061FED79650016851F /* App */,
|
|
||||||
504EC3051FED79650016851F /* Products */,
|
|
||||||
7F8756D8B27F46E3366F6CEA /* Pods */,
|
|
||||||
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */,
|
|
||||||
);
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
504EC3051FED79650016851F /* Products */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
504EC3041FED79650016851F /* App.app */,
|
|
||||||
);
|
|
||||||
name = Products;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
504EC3061FED79650016851F /* App */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
50379B222058CBB4000EE86E /* capacitor.config.json */,
|
|
||||||
504EC3071FED79650016851F /* AppDelegate.swift */,
|
|
||||||
504EC30B1FED79650016851F /* Main.storyboard */,
|
|
||||||
504EC30E1FED79650016851F /* Assets.xcassets */,
|
|
||||||
504EC3101FED79650016851F /* LaunchScreen.storyboard */,
|
|
||||||
504EC3131FED79650016851F /* Info.plist */,
|
|
||||||
2FAD9762203C412B000D30F8 /* config.xml */,
|
|
||||||
50B271D01FEDC1A000F3C39B /* public */,
|
|
||||||
);
|
|
||||||
path = App;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
7F8756D8B27F46E3366F6CEA /* Pods */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */,
|
|
||||||
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */,
|
|
||||||
);
|
|
||||||
name = Pods;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
|
||||||
504EC3031FED79650016851F /* App */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = 504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */;
|
|
||||||
buildPhases = (
|
|
||||||
6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */,
|
|
||||||
504EC3001FED79650016851F /* Sources */,
|
|
||||||
504EC3011FED79650016851F /* Frameworks */,
|
|
||||||
504EC3021FED79650016851F /* Resources */,
|
|
||||||
9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
);
|
|
||||||
name = App;
|
|
||||||
productName = App;
|
|
||||||
productReference = 504EC3041FED79650016851F /* App.app */;
|
|
||||||
productType = "com.apple.product-type.application";
|
|
||||||
};
|
|
||||||
/* End PBXNativeTarget section */
|
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
|
||||||
504EC2FC1FED79650016851F /* Project object */ = {
|
|
||||||
isa = PBXProject;
|
|
||||||
attributes = {
|
|
||||||
LastSwiftUpdateCheck = 920;
|
|
||||||
LastUpgradeCheck = 920;
|
|
||||||
TargetAttributes = {
|
|
||||||
504EC3031FED79650016851F = {
|
|
||||||
CreatedOnToolsVersion = 9.2;
|
|
||||||
LastSwiftMigration = 1100;
|
|
||||||
ProvisioningStyle = Automatic;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
buildConfigurationList = 504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */;
|
|
||||||
compatibilityVersion = "Xcode 8.0";
|
|
||||||
developmentRegion = en;
|
|
||||||
hasScannedForEncodings = 0;
|
|
||||||
knownRegions = (
|
|
||||||
en,
|
|
||||||
Base,
|
|
||||||
);
|
|
||||||
mainGroup = 504EC2FB1FED79650016851F;
|
|
||||||
packageReferences = (
|
|
||||||
);
|
|
||||||
productRefGroup = 504EC3051FED79650016851F /* Products */;
|
|
||||||
projectDirPath = "";
|
|
||||||
projectRoot = "";
|
|
||||||
targets = (
|
|
||||||
504EC3031FED79650016851F /* App */,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
/* End PBXProject section */
|
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase section */
|
|
||||||
504EC3021FED79650016851F /* Resources */ = {
|
|
||||||
isa = PBXResourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */,
|
|
||||||
50B271D11FEDC1A000F3C39B /* public in Resources */,
|
|
||||||
504EC30F1FED79650016851F /* Assets.xcassets in Resources */,
|
|
||||||
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
|
|
||||||
504EC30D1FED79650016851F /* Main.storyboard in Resources */,
|
|
||||||
2FAD9763203C412B000D30F8 /* config.xml in Resources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXResourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
|
||||||
6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
|
||||||
"${PODS_ROOT}/Manifest.lock",
|
|
||||||
);
|
|
||||||
name = "[CP] Check Pods Manifest.lock";
|
|
||||||
outputPaths = (
|
|
||||||
"$(DERIVED_FILE_DIR)/Pods-App-checkManifestLockResult.txt",
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "[CP] Embed Pods Frameworks";
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App/Pods-App-frameworks.sh\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
/* End PBXShellScriptBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
|
||||||
504EC3001FED79650016851F /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
504EC3081FED79650016851F /* AppDelegate.swift in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXSourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
|
||||||
504EC30B1FED79650016851F /* Main.storyboard */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
504EC30C1FED79650016851F /* Base */,
|
|
||||||
);
|
|
||||||
name = Main.storyboard;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
504EC3101FED79650016851F /* LaunchScreen.storyboard */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
504EC3111FED79650016851F /* Base */,
|
|
||||||
);
|
|
||||||
name = LaunchScreen.storyboard;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXVariantGroup section */
|
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
|
||||||
504EC3141FED79650016851F /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
ENABLE_TESTABILITY = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
|
||||||
"DEBUG=1",
|
|
||||||
"$(inherited)",
|
|
||||||
);
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
504EC3151FED79650016851F /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
|
||||||
VALIDATE_PRODUCT = YES;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
504EC3171FED79650016851F /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
baseConfigurationReference = FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */;
|
|
||||||
buildSettings = {
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
|
||||||
INFOPLIST_FILE = App/Info.plist;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
|
||||||
MARKETING_VERSION = 0.1.0;
|
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = ai.hesychia.chat;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
504EC3181FED79650016851F /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
baseConfigurationReference = AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */;
|
|
||||||
buildSettings = {
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
|
||||||
INFOPLIST_FILE = App/Info.plist;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
|
||||||
MARKETING_VERSION = 0.1.0;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = ai.hesychia.chat;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
/* End XCBuildConfiguration section */
|
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
|
||||||
504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
504EC3141FED79650016851F /* Debug */,
|
|
||||||
504EC3151FED79650016851F /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
504EC3171FED79650016851F /* Debug */,
|
|
||||||
504EC3181FED79650016851F /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
/* End XCConfigurationList section */
|
|
||||||
};
|
|
||||||
rootObject = 504EC2FC1FED79650016851F /* Project object */;
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "group:App.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
<FileRef
|
|
||||||
location = "group:Pods/Pods.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
import UIKit
|
|
||||||
import Capacitor
|
|
||||||
|
|
||||||
@UIApplicationMain
|
|
||||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
|
||||||
|
|
||||||
var window: UIWindow?
|
|
||||||
|
|
||||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
|
||||||
// Disable WKWebView rubber-band overscroll so the MUI chat layout feels native.
|
|
||||||
NotificationCenter.default.addObserver(
|
|
||||||
self,
|
|
||||||
selector: #selector(disableWebViewBounce),
|
|
||||||
name: UIApplication.didBecomeActiveNotification,
|
|
||||||
object: nil
|
|
||||||
)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func disableWebViewBounce() {
|
|
||||||
guard let root = window?.rootViewController else { return }
|
|
||||||
applyNoBounce(to: root)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func applyNoBounce(to controller: UIViewController) {
|
|
||||||
if let bridge = controller as? CAPBridgeViewController,
|
|
||||||
let scrollView = bridge.webView?.scrollView {
|
|
||||||
scrollView.bounces = false
|
|
||||||
scrollView.alwaysBounceVertical = false
|
|
||||||
scrollView.alwaysBounceHorizontal = false
|
|
||||||
}
|
|
||||||
for child in controller.children {
|
|
||||||
applyNoBounce(to: child)
|
|
||||||
}
|
|
||||||
if let presented = controller.presentedViewController {
|
|
||||||
applyNoBounce(to: presented)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func applicationWillResignActive(_ application: UIApplication) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
|
||||||
disableWebViewBounce()
|
|
||||||
}
|
|
||||||
|
|
||||||
func applicationWillTerminate(_ application: UIApplication) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
|
|
||||||
return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
|
|
||||||
}
|
|
||||||
|
|
||||||
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
|
|
||||||
return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 874 KiB |
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"images": [
|
|
||||||
{
|
|
||||||
"idiom": "universal",
|
|
||||||
"size": "1024x1024",
|
|
||||||
"filename": "AppIcon-512@2x.png",
|
|
||||||
"platform": "ios"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info": {
|
|
||||||
"author": "xcode",
|
|
||||||
"version": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
{
|
|
||||||
"images": [
|
|
||||||
{
|
|
||||||
"idiom": "universal",
|
|
||||||
"filename": "Default@1x~universal~anyany.png",
|
|
||||||
"scale": "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "universal",
|
|
||||||
"filename": "Default@2x~universal~anyany.png",
|
|
||||||
"scale": "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "universal",
|
|
||||||
"filename": "Default@3x~universal~anyany.png",
|
|
||||||
"scale": "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"appearances": [
|
|
||||||
{
|
|
||||||
"appearance": "luminosity",
|
|
||||||
"value": "dark"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"idiom": "universal",
|
|
||||||
"scale": "1x",
|
|
||||||
"filename": "Default@1x~universal~anyany-dark.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"appearances": [
|
|
||||||
{
|
|
||||||
"appearance": "luminosity",
|
|
||||||
"value": "dark"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"idiom": "universal",
|
|
||||||
"scale": "2x",
|
|
||||||
"filename": "Default@2x~universal~anyany-dark.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"appearances": [
|
|
||||||
{
|
|
||||||
"appearance": "luminosity",
|
|
||||||
"value": "dark"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"idiom": "universal",
|
|
||||||
"scale": "3x",
|
|
||||||
"filename": "Default@3x~universal~anyany-dark.png"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info": {
|
|
||||||
"version": 1,
|
|
||||||
"author": "xcode"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 1.7 MiB |
@@ -1,32 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17132" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
|
||||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
|
||||||
<dependencies>
|
|
||||||
<deployment identifier="iOS"/>
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17105"/>
|
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
||||||
</dependencies>
|
|
||||||
<scenes>
|
|
||||||
<!--View Controller-->
|
|
||||||
<scene sceneID="EHf-IW-A2E">
|
|
||||||
<objects>
|
|
||||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
|
||||||
<imageView key="view" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Splash" id="snD-IY-ifK">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
|
||||||
</imageView>
|
|
||||||
</viewController>
|
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
|
||||||
</objects>
|
|
||||||
<point key="canvasLocation" x="53" y="375"/>
|
|
||||||
</scene>
|
|
||||||
</scenes>
|
|
||||||
<resources>
|
|
||||||
<image name="Splash" width="1366" height="1366"/>
|
|
||||||
<systemColor name="systemBackgroundColor">
|
|
||||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
|
||||||
</systemColor>
|
|
||||||
</resources>
|
|
||||||
</document>
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14111" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
|
||||||
<device id="retina4_7" orientation="portrait">
|
|
||||||
<adaptation id="fullscreen"/>
|
|
||||||
</device>
|
|
||||||
<dependencies>
|
|
||||||
<deployment identifier="iOS"/>
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
|
||||||
</dependencies>
|
|
||||||
<scenes>
|
|
||||||
<!--Bridge View Controller-->
|
|
||||||
<scene sceneID="tne-QT-ifu">
|
|
||||||
<objects>
|
|
||||||
<viewController id="BYZ-38-t0r" customClass="CAPBridgeViewController" customModule="Capacitor" sceneMemberID="viewController"/>
|
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
|
||||||
</objects>
|
|
||||||
</scene>
|
|
||||||
</scenes>
|
|
||||||
</document>
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>en</string>
|
|
||||||
<key>CFBundleDisplayName</key>
|
|
||||||
<string>Hesychia</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>$(PRODUCT_NAME)</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>$(MARKETING_VERSION)</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
|
||||||
<key>LSRequiresIPhoneOS</key>
|
|
||||||
<true/>
|
|
||||||
<key>UILaunchStoryboardName</key>
|
|
||||||
<string>LaunchScreen</string>
|
|
||||||
<key>UIMainStoryboardFile</key>
|
|
||||||
<string>Main</string>
|
|
||||||
<key>UIRequiredDeviceCapabilities</key>
|
|
||||||
<array>
|
|
||||||
<string>armv7</string>
|
|
||||||
</array>
|
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
|
|
||||||
|
|
||||||
platform :ios, '15.0'
|
|
||||||
use_frameworks!
|
|
||||||
|
|
||||||
# workaround to avoid Xcode caching of Pods that requires
|
|
||||||
# Product -> Clean Build Folder after new Cordova plugins installed
|
|
||||||
# Requires CocoaPods 1.6 or newer
|
|
||||||
install! 'cocoapods', :disable_input_output_paths => true
|
|
||||||
|
|
||||||
def capacitor_pods
|
|
||||||
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
|
|
||||||
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
|
|
||||||
pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
|
|
||||||
pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
|
|
||||||
pod 'CapacitorPreferences', :path => '../../node_modules/@capacitor/preferences'
|
|
||||||
pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
|
|
||||||
pod 'NativeStoreBilling', :path => '../../plugins/native-store-billing'
|
|
||||||
end
|
|
||||||
|
|
||||||
target 'App' do
|
|
||||||
capacitor_pods
|
|
||||||
# Add your Pods here
|
|
||||||
end
|
|
||||||
|
|
||||||
post_install do |installer|
|
|
||||||
assertDeploymentTarget(installer)
|
|
||||||
end
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
PODS:
|
|
||||||
- Capacitor (7.6.8):
|
|
||||||
- CapacitorCordova
|
|
||||||
- CapacitorApp (7.1.2):
|
|
||||||
- Capacitor
|
|
||||||
- CapacitorCordova (7.6.8)
|
|
||||||
- CapacitorKeyboard (7.0.6):
|
|
||||||
- Capacitor
|
|
||||||
- CapacitorPreferences (7.0.4):
|
|
||||||
- Capacitor
|
|
||||||
- CapacitorStatusBar (7.0.6):
|
|
||||||
- Capacitor
|
|
||||||
|
|
||||||
DEPENDENCIES:
|
|
||||||
- "Capacitor (from `../../node_modules/@capacitor/ios`)"
|
|
||||||
- "CapacitorApp (from `../../node_modules/@capacitor/app`)"
|
|
||||||
- "CapacitorCordova (from `../../node_modules/@capacitor/ios`)"
|
|
||||||
- "CapacitorKeyboard (from `../../node_modules/@capacitor/keyboard`)"
|
|
||||||
- "CapacitorPreferences (from `../../node_modules/@capacitor/preferences`)"
|
|
||||||
- "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)"
|
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
|
||||||
Capacitor:
|
|
||||||
:path: "../../node_modules/@capacitor/ios"
|
|
||||||
CapacitorApp:
|
|
||||||
:path: "../../node_modules/@capacitor/app"
|
|
||||||
CapacitorCordova:
|
|
||||||
:path: "../../node_modules/@capacitor/ios"
|
|
||||||
CapacitorKeyboard:
|
|
||||||
:path: "../../node_modules/@capacitor/keyboard"
|
|
||||||
CapacitorPreferences:
|
|
||||||
:path: "../../node_modules/@capacitor/preferences"
|
|
||||||
CapacitorStatusBar:
|
|
||||||
:path: "../../node_modules/@capacitor/status-bar"
|
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
|
||||||
Capacitor: ff6bf01336ac353098378828aff465095a89e459
|
|
||||||
CapacitorApp: f01a913211780e0718dae9750442c3e23f96e106
|
|
||||||
CapacitorCordova: e61ee8c40101b8cd011d0224261606a290c082cf
|
|
||||||
CapacitorKeyboard: a2e0869edd229490ce36aed2549c0d6b95e27ee8
|
|
||||||
CapacitorPreferences: 69d9991307507aeab8ef8019c10b9babfda0e9ca
|
|
||||||
CapacitorStatusBar: 416e9e53fd6397e668d4a181cd2131617d949bd6
|
|
||||||
|
|
||||||
PODFILE CHECKSUM: c2e7da979a3cb960e70090cd1956727cb3ca3413
|
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
# Hesychia — iOS
|
|
||||||
|
|
||||||
Native Capacitor project for `ai.hesychia.chat`. Web UI comes from the CRA
|
|
||||||
`build/` output in the parent `llm-fe/` package (synced with `npx cap sync`).
|
|
||||||
|
|
||||||
Broader Capacitor notes (env files, icons, QA, TestFlight): [`../IOS.md`](../IOS.md).
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- macOS + **Xcode** 15+
|
|
||||||
- Node.js **20**
|
|
||||||
- **CocoaPods** (`pod --version`)
|
|
||||||
- Open **`App.xcworkspace`** (not `.xcodeproj`)
|
|
||||||
|
|
||||||
## Build the web bundle and sync
|
|
||||||
|
|
||||||
From the **npm root** (`llm-fe/`, one level up):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ..
|
|
||||||
npm ci
|
|
||||||
npm run build:mobile # .env.mobile → react-scripts build → cap sync
|
|
||||||
```
|
|
||||||
|
|
||||||
Open in Xcode:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run ios:open
|
|
||||||
# or: npx cap open ios
|
|
||||||
```
|
|
||||||
|
|
||||||
Re-sync after changing web code (with an existing `build/`):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run ios:sync
|
|
||||||
```
|
|
||||||
|
|
||||||
Backend URLs are baked in at web-build time via `../.env.mobile` (prod by default).
|
|
||||||
|
|
||||||
After cloning, if Pods are missing:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd App
|
|
||||||
pod install
|
|
||||||
```
|
|
||||||
|
|
||||||
## Run on a simulator / device
|
|
||||||
|
|
||||||
1. Open `App/App.xcworkspace` in Xcode.
|
|
||||||
2. Pick a simulator or a paired iPhone (Signing & Capabilities → your Team).
|
|
||||||
3. Product → Run (⌘R).
|
|
||||||
|
|
||||||
CLI (optional):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
xcodebuild -workspace App/App.xcworkspace \
|
|
||||||
-scheme App \
|
|
||||||
-destination 'platform=iOS Simulator,name=iPhone 16' \
|
|
||||||
build
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version before a store release
|
|
||||||
|
|
||||||
Edit target **App** → General, or `App.xcodeproj` build settings:
|
|
||||||
|
|
||||||
| Field | Build setting | Rule |
|
|
||||||
|-------|---------------|------|
|
|
||||||
| Version | `MARKETING_VERSION` | Keep in sync with `../package.json` `version` + Android `versionName` |
|
|
||||||
| Build | `CURRENT_PROJECT_VERSION` | Integer; **must increase** for every TestFlight / App Store upload |
|
|
||||||
|
|
||||||
Currently: version **0.1.0**, build **1**.
|
|
||||||
|
|
||||||
## Signing
|
|
||||||
|
|
||||||
**Do not commit** `.p12`, `.mobileprovision`, or export option files with secrets.
|
|
||||||
|
|
||||||
Debug / simulator: Automatic signing with a personal team is enough.
|
|
||||||
|
|
||||||
Distribution: App Store Connect + distribution certificate + profile — credentials
|
|
||||||
live outside this repo. CI/TestFlight automation is a follow-on ticket.
|
|
||||||
|
|
||||||
## Useful paths
|
|
||||||
|
|
||||||
| Path | Purpose |
|
|
||||||
|------|---------|
|
|
||||||
| `App/App/AppDelegate.swift` | Disables WKWebView rubber-band bounce |
|
|
||||||
| `App/App/Info.plist` | Display name **Hesychia**, version keys |
|
|
||||||
| `App/App/Assets.xcassets` | App icon + splash (regenerate via `npm run assets:generate`) |
|
|
||||||
| `App/Podfile` / `Podfile.lock` | CocoaPods (commit lockfile; Pods/ is gitignored) |
|
|
||||||
@@ -12,14 +12,12 @@
|
|||||||
"@capacitor/app": "^7.1.2",
|
"@capacitor/app": "^7.1.2",
|
||||||
"@capacitor/cli": "^7.6.8",
|
"@capacitor/cli": "^7.6.8",
|
||||||
"@capacitor/core": "^7.6.8",
|
"@capacitor/core": "^7.6.8",
|
||||||
"@capacitor/ios": "^7.6.8",
|
|
||||||
"@capacitor/keyboard": "^7.0.6",
|
"@capacitor/keyboard": "^7.0.6",
|
||||||
"@capacitor/preferences": "^7.0.4",
|
"@capacitor/preferences": "^7.0.4",
|
||||||
"@capacitor/status-bar": "^7.0.6",
|
"@capacitor/status-bar": "^7.0.6",
|
||||||
"@emotion/cache": "^11.14.0",
|
"@emotion/cache": "^11.14.0",
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.14.0",
|
"@emotion/styled": "^11.14.0",
|
||||||
"@heycatch/sdk": "^0.8.3",
|
|
||||||
"@mui/icons-material": "^5.16.11",
|
"@mui/icons-material": "^5.16.11",
|
||||||
"@mui/material": "^5.16.11",
|
"@mui/material": "^5.16.11",
|
||||||
"@testing-library/jest-dom": "^6.6.3",
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
@@ -34,12 +32,12 @@
|
|||||||
"bootstrap": "^5.3.3",
|
"bootstrap": "^5.3.3",
|
||||||
"brace-expansion": "file:vendor/brace-expansion-compat",
|
"brace-expansion": "file:vendor/brace-expansion-compat",
|
||||||
"chroma-js": "^3.1.2",
|
"chroma-js": "^3.1.2",
|
||||||
|
"docx": "^9.7.1",
|
||||||
"formik": "^2.4.6",
|
"formik": "^2.4.6",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"markdown-to-jsx": "^7.7.2",
|
"markdown-to-jsx": "^7.7.2",
|
||||||
"mini.css": "^3.0.1",
|
"mini.css": "^3.0.1",
|
||||||
"native-store-billing": "file:plugins/native-store-billing",
|
|
||||||
"papaparse": "^5.5.4",
|
"papaparse": "^5.5.4",
|
||||||
"pdfmake": "^0.3.11",
|
"pdfmake": "^0.3.11",
|
||||||
"react-bootstrap": "^2.10.6",
|
"react-bootstrap": "^2.10.6",
|
||||||
@@ -2467,15 +2465,6 @@
|
|||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@capacitor/ios": {
|
|
||||||
"version": "7.6.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-7.6.8.tgz",
|
|
||||||
"integrity": "sha512-TAM1FdI1Cfl8e/wLBo7x5m61V/J1fMEpyxU2psZzHzsa436k2pwEME6CQoBRYdw6Q6gud0jZSPwOVrNn+MI7Ag==",
|
|
||||||
"license": "MIT",
|
|
||||||
"peerDependencies": {
|
|
||||||
"@capacitor/core": "^7.6.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@capacitor/keyboard": {
|
"node_modules/@capacitor/keyboard": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-7.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-7.0.6.tgz",
|
||||||
@@ -2507,7 +2496,7 @@
|
|||||||
"version": "0.8.1",
|
"version": "0.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||||
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/trace-mapping": "0.3.9"
|
"@jridgewell/trace-mapping": "0.3.9"
|
||||||
@@ -2520,7 +2509,7 @@
|
|||||||
"version": "0.3.9",
|
"version": "0.3.9",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
|
||||||
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/resolve-uri": "^3.0.3",
|
"@jridgewell/resolve-uri": "^3.0.3",
|
||||||
@@ -3084,103 +3073,6 @@
|
|||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@heycatch/sdk": {
|
|
||||||
"version": "0.8.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@heycatch/sdk/-/sdk-0.8.3.tgz",
|
|
||||||
"integrity": "sha512-7knqXfptgctAIHu5IXwd/WnivY+wwYAws2Xr0ZuARottBnbQteFbxZP7TyEDWCyz6A5+PcGlzlPxeTdq5uyGoA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"posthog-react-native": "^4.61.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=22"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"expo-router": "*",
|
|
||||||
"react": "^18.2.0 || ^19.0.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"expo-router": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"react": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@heycatch/sdk/node_modules/posthog-react-native": {
|
|
||||||
"version": "4.81.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/posthog-react-native/-/posthog-react-native-4.81.2.tgz",
|
|
||||||
"integrity": "sha512-w9UUocpnS9u+CO+37Q32W/zSgL8/fSFhIB9tUZfSDc1D4rE7XShyfCwwXD6efjmP19Gu941kuXdRgTbuV8Mkig==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@posthog/core": "^1.59.1",
|
|
||||||
"@posthog/types": "^1.416.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"posthog-react-native-xcode": "tooling/posthog-xcode.sh"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@posthog/react-native-plugin": ">= 2.9.3",
|
|
||||||
"@react-native-async-storage/async-storage": ">=1.0.0",
|
|
||||||
"@react-navigation/native": ">= 5.0.0",
|
|
||||||
"expo-application": ">= 4.0.0",
|
|
||||||
"expo-device": ">= 4.0.0",
|
|
||||||
"expo-file-system": ">= 13.0.0",
|
|
||||||
"expo-localization": ">= 11.0.0",
|
|
||||||
"expo-updates": ">= 0.25.0",
|
|
||||||
"posthog-react-native-session-replay": ">= 1.6.0",
|
|
||||||
"react-native-device-info": ">= 10.0.0",
|
|
||||||
"react-native-localize": ">= 3.0.0",
|
|
||||||
"react-native-navigation": ">= 6.0.0",
|
|
||||||
"react-native-safe-area-context": ">= 4.0.0",
|
|
||||||
"react-native-svg": ">= 15.0.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"@posthog/react-native-plugin": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"@react-native-async-storage/async-storage": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"@react-navigation/native": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"expo-application": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"expo-device": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"expo-file-system": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"expo-localization": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"expo-updates": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"posthog-react-native-session-replay": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"react-native-device-info": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"react-native-localize": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"react-native-navigation": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"react-native-safe-area-context": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"react-native-svg": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@humanwhocodes/config-array": {
|
||||||
"version": "0.13.0",
|
"version": "0.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
|
||||||
@@ -5253,21 +5145,6 @@
|
|||||||
"url": "https://opencollective.com/popperjs"
|
"url": "https://opencollective.com/popperjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@posthog/core": {
|
|
||||||
"version": "1.59.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.59.1.tgz",
|
|
||||||
"integrity": "sha512-P39YgzQVDh6oz6wAzQXEnoHgTYpM7gifonmVKq1scAJco79h31XmmNVurRq9tTmmyIrr1uX8FHT0riCsyfV9AQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@posthog/types": "^1.416.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@posthog/types": {
|
|
||||||
"version": "1.416.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@posthog/types/-/types-1.416.0.tgz",
|
|
||||||
"integrity": "sha512-0/9+02s/0uDyrH4G/qUg1yyl6gXUg8Uuxw/PlDad3KLzo9FFS9zS/kAQaEshx/saVGupj1aAy/4EUBxWisBogw==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@prettier/plugin-xml": {
|
"node_modules/@prettier/plugin-xml": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-2.2.0.tgz",
|
||||||
@@ -5703,6 +5580,7 @@
|
|||||||
"version": "10.4.1",
|
"version": "10.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
|
||||||
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
|
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.10.4",
|
"@babel/code-frame": "^7.10.4",
|
||||||
@@ -6095,34 +5973,35 @@
|
|||||||
"version": "1.0.12",
|
"version": "1.0.12",
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
|
||||||
"integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==",
|
"integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@tsconfig/node12": {
|
"node_modules/@tsconfig/node12": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
|
||||||
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@tsconfig/node14": {
|
"node_modules/@tsconfig/node14": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
|
||||||
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@tsconfig/node16": {
|
"node_modules/@tsconfig/node16": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
|
||||||
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
|
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/aria-query": {
|
"node_modules/@types/aria-query": {
|
||||||
"version": "5.0.4",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
||||||
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
|
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/babel__core": {
|
"node_modules/@types/babel__core": {
|
||||||
@@ -6535,7 +6414,7 @@
|
|||||||
"version": "18.3.5",
|
"version": "18.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz",
|
||||||
"integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==",
|
"integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^18.0.0"
|
"@types/react": "^18.0.0"
|
||||||
}
|
}
|
||||||
@@ -9146,7 +9025,7 @@
|
|||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
@@ -10015,10 +9894,61 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/docx": {
|
||||||
|
"version": "9.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/docx/-/docx-9.7.1.tgz",
|
||||||
|
"integrity": "sha512-ilXFf9Moz47ABjFpDiA5s1w9lpb4EFSp7+5iiJSbfyYDM+bpZdAgLlSr7fW4aXhVe/E+F6QCv0EvRVFEd5CsWg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "^25.2.3",
|
||||||
|
"hash.js": "^1.1.7",
|
||||||
|
"jszip": "^3.10.1",
|
||||||
|
"nanoid": "^5.1.3",
|
||||||
|
"xml": "^1.0.1",
|
||||||
|
"xml-js": "^1.6.8"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/docx/node_modules/@types/node": {
|
||||||
|
"version": "25.9.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.5.tgz",
|
||||||
|
"integrity": "sha512-OScDchr2fwuUmWdf4kZ9h7PcJiYDVInhJizG/biAq3cAvqwYktuy/TYGGdZNMtNTFUP7rnb0NU4TUdm82kt4Rg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": ">=7.24.0 <7.24.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/docx/node_modules/nanoid": {
|
||||||
|
"version": "5.1.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.16.tgz",
|
||||||
|
"integrity": "sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18 || >=20"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/docx/node_modules/undici-types": {
|
||||||
|
"version": "7.24.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz",
|
||||||
|
"integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/dom-accessibility-api": {
|
"node_modules/dom-accessibility-api": {
|
||||||
"version": "0.5.16",
|
"version": "0.5.16",
|
||||||
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
|
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
|
||||||
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
|
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/dom-converter": {
|
"node_modules/dom-converter": {
|
||||||
@@ -12510,6 +12440,16 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/hash.js": {
|
||||||
|
"version": "1.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
||||||
|
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"minimalistic-assert": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hasown": {
|
"node_modules/hasown": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
|
||||||
@@ -12906,6 +12846,12 @@
|
|||||||
"node": ">= 4"
|
"node": ">= 4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/immediate": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/immer": {
|
"node_modules/immer": {
|
||||||
"version": "9.0.21",
|
"version": "9.0.21",
|
||||||
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
|
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
|
||||||
@@ -15823,6 +15769,54 @@
|
|||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jszip": {
|
||||||
|
"version": "3.10.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
|
||||||
|
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
|
||||||
|
"license": "(MIT OR GPL-3.0-or-later)",
|
||||||
|
"dependencies": {
|
||||||
|
"lie": "~3.3.0",
|
||||||
|
"pako": "~1.0.2",
|
||||||
|
"readable-stream": "~2.3.6",
|
||||||
|
"setimmediate": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jszip/node_modules/isarray": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/jszip/node_modules/readable-stream": {
|
||||||
|
"version": "2.3.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||||
|
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jszip/node_modules/safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/jszip/node_modules/string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jwt-decode": {
|
"node_modules/jwt-decode": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
|
||||||
@@ -15909,6 +15903,15 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lie": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"immediate": "~3.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lilconfig": {
|
"node_modules/lilconfig": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
||||||
@@ -16106,6 +16109,7 @@
|
|||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
|
||||||
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
|
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"lz-string": "bin/bin.js"
|
"lz-string": "bin/bin.js"
|
||||||
@@ -16148,7 +16152,7 @@
|
|||||||
"version": "1.3.6",
|
"version": "1.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/makeerror": {
|
"node_modules/makeerror": {
|
||||||
@@ -16734,10 +16738,6 @@
|
|||||||
"node": ">= 10.x"
|
"node": ">= 10.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/native-store-billing": {
|
|
||||||
"resolved": "plugins/native-store-billing",
|
|
||||||
"link": true
|
|
||||||
},
|
|
||||||
"node_modules/natural-compare": {
|
"node_modules/natural-compare": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||||
@@ -19062,6 +19062,7 @@
|
|||||||
"version": "18.3.1",
|
"version": "18.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.1.0"
|
"loose-envify": "^1.1.0"
|
||||||
},
|
},
|
||||||
@@ -19272,6 +19273,7 @@
|
|||||||
"version": "18.3.1",
|
"version": "18.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"scheduler": "^0.23.2"
|
"scheduler": "^0.23.2"
|
||||||
@@ -20719,6 +20721,7 @@
|
|||||||
"version": "0.23.2",
|
"version": "0.23.2",
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||||
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
|
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.1.0"
|
"loose-envify": "^1.1.0"
|
||||||
}
|
}
|
||||||
@@ -20986,6 +20989,12 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/setimmediate": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/setprototypeof": {
|
"node_modules/setprototypeof": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||||
@@ -21809,12 +21818,6 @@
|
|||||||
"postcss": "^8.2.15"
|
"postcss": "^8.2.15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/stylis": {
|
|
||||||
"version": "4.3.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz",
|
|
||||||
"integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==",
|
|
||||||
"peer": true
|
|
||||||
},
|
|
||||||
"node_modules/stylis-plugin-rtl": {
|
"node_modules/stylis-plugin-rtl": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/stylis-plugin-rtl/-/stylis-plugin-rtl-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/stylis-plugin-rtl/-/stylis-plugin-rtl-2.1.1.tgz",
|
||||||
@@ -22399,7 +22402,7 @@
|
|||||||
"version": "10.9.2",
|
"version": "10.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
|
||||||
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
|
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cspotcode/source-map-support": "^0.8.0",
|
"@cspotcode/source-map-support": "^0.8.0",
|
||||||
@@ -22443,7 +22446,7 @@
|
|||||||
"version": "8.3.5",
|
"version": "8.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz",
|
||||||
"integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==",
|
"integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.11.0"
|
"acorn": "^8.11.0"
|
||||||
@@ -22456,14 +22459,14 @@
|
|||||||
"version": "4.1.3",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
||||||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/ts-node/node_modules/diff": {
|
"node_modules/ts-node/node_modules/diff": {
|
||||||
"version": "4.0.4",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz",
|
||||||
"integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==",
|
"integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.3.1"
|
"node": ">=0.3.1"
|
||||||
@@ -22648,6 +22651,7 @@
|
|||||||
"version": "4.9.5",
|
"version": "4.9.5",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||||
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -22895,7 +22899,7 @@
|
|||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||||
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/v8-to-istanbul": {
|
"node_modules/v8-to-istanbul": {
|
||||||
@@ -23899,11 +23903,16 @@
|
|||||||
"node": ">=0.8"
|
"node": ">=0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/xml": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/xml-js": {
|
"node_modules/xml-js": {
|
||||||
"version": "1.6.11",
|
"version": "1.6.11",
|
||||||
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
|
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
|
||||||
"integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
|
"integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"sax": "^1.2.4"
|
"sax": "^1.2.4"
|
||||||
@@ -24044,7 +24053,7 @@
|
|||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
||||||
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
@@ -24083,12 +24092,6 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"plugins/native-store-billing": {
|
|
||||||
"version": "0.1.0",
|
|
||||||
"peerDependencies": {
|
|
||||||
"@capacitor/core": ">=7.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vendor/brace-expansion-compat": {
|
"vendor/brace-expansion-compat": {
|
||||||
"name": "brace-expansion",
|
"name": "brace-expansion",
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
|
|||||||
@@ -7,14 +7,12 @@
|
|||||||
"@capacitor/app": "^7.1.2",
|
"@capacitor/app": "^7.1.2",
|
||||||
"@capacitor/cli": "^7.6.8",
|
"@capacitor/cli": "^7.6.8",
|
||||||
"@capacitor/core": "^7.6.8",
|
"@capacitor/core": "^7.6.8",
|
||||||
"@capacitor/ios": "^7.6.8",
|
|
||||||
"@capacitor/keyboard": "^7.0.6",
|
"@capacitor/keyboard": "^7.0.6",
|
||||||
"@capacitor/preferences": "^7.0.4",
|
"@capacitor/preferences": "^7.0.4",
|
||||||
"@capacitor/status-bar": "^7.0.6",
|
"@capacitor/status-bar": "^7.0.6",
|
||||||
"@emotion/cache": "^11.14.0",
|
"@emotion/cache": "^11.14.0",
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.14.0",
|
"@emotion/styled": "^11.14.0",
|
||||||
"@heycatch/sdk": "^0.8.3",
|
|
||||||
"@mui/icons-material": "^5.16.11",
|
"@mui/icons-material": "^5.16.11",
|
||||||
"@mui/material": "^5.16.11",
|
"@mui/material": "^5.16.11",
|
||||||
"@testing-library/jest-dom": "^6.6.3",
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
@@ -29,12 +27,12 @@
|
|||||||
"bootstrap": "^5.3.3",
|
"bootstrap": "^5.3.3",
|
||||||
"brace-expansion": "file:vendor/brace-expansion-compat",
|
"brace-expansion": "file:vendor/brace-expansion-compat",
|
||||||
"chroma-js": "^3.1.2",
|
"chroma-js": "^3.1.2",
|
||||||
|
"docx": "^9.7.1",
|
||||||
"formik": "^2.4.6",
|
"formik": "^2.4.6",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"markdown-to-jsx": "^7.7.2",
|
"markdown-to-jsx": "^7.7.2",
|
||||||
"mini.css": "^3.0.1",
|
"mini.css": "^3.0.1",
|
||||||
"native-store-billing": "file:plugins/native-store-billing",
|
|
||||||
"papaparse": "^5.5.4",
|
"papaparse": "^5.5.4",
|
||||||
"pdfmake": "^0.3.11",
|
"pdfmake": "^0.3.11",
|
||||||
"react-bootstrap": "^2.10.6",
|
"react-bootstrap": "^2.10.6",
|
||||||
@@ -54,18 +52,15 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "NODE_ENV=development react-scripts start",
|
"start": "NODE_ENV=development react-scripts start",
|
||||||
"build": "node scripts/writeSitemap.js && NODE_ENV=production react-scripts build && node scripts/stampCanonicals.js",
|
"build": "NODE_ENV=production react-scripts build",
|
||||||
"build:prod": "node scripts/writeSitemap.js && NODE_ENV=production react-scripts build && node scripts/stampCanonicals.js && mkdir -p /var/www/prod.chat.aimloperations/html && cp -r ./build/* /var/www/prod.chat.aimloperations/html/ && node scripts/pingIndexNow.js",
|
"build:prod": "NODE_ENV=production react-scripts build && mkdir -p /var/www/prod.chat.aimloperations/html && cp -r ./build/* /var/www/prod.chat.aimloperations/html/",
|
||||||
"build:beta": "node scripts/writeSitemap.js && bash -c 'set -a; source .env.beta; set +a; NODE_ENV=production react-scripts build' && node scripts/stampCanonicals.js && mkdir -p /var/www/beta.chat.aimloperations/html && cp -r ./build/* /var/www/beta.chat.aimloperations/html/",
|
"build:beta": "bash -c 'set -a; source .env.beta; set +a; NODE_ENV=production react-scripts build' && mkdir -p /var/www/beta.chat.aimloperations/html && cp -r ./build/* /var/www/beta.chat.aimloperations/html/",
|
||||||
"build:mobile": "bash -c 'set -a; source .env.mobile; set +a; NODE_ENV=production react-scripts build' && npx cap sync",
|
"build:mobile": "bash -c 'set -a; source .env.mobile; set +a; NODE_ENV=production react-scripts build' && npx cap sync android",
|
||||||
"build:android:store": "bash -c 'set -a; source .env.mobile; set +a; NODE_ENV=production react-scripts build' && npx cap sync android",
|
|
||||||
"android:open": "npx cap open android",
|
"android:open": "npx cap open android",
|
||||||
"android:sync": "npx cap sync android",
|
"android:sync": "npx cap sync android",
|
||||||
"ios:open": "npx cap open ios",
|
"assets:generate": "npx capacitor-assets generate --android",
|
||||||
"ios:sync": "npx cap sync ios",
|
|
||||||
"assets:generate": "npx capacitor-assets generate --ios --android",
|
|
||||||
"test": "NODE_ENV=development react-scripts test",
|
"test": "NODE_ENV=development react-scripts test",
|
||||||
"test:ci": "CI=true NODE_ENV=development react-scripts test --watchAll=false --coverage=false && node --test scripts/stampCanonicals.test.js scripts/sitemap.test.js scripts/android-version.test.mjs",
|
"test:ci": "CI=true NODE_ENV=development react-scripts test --watchAll=false --coverage=false",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
require 'json'
|
|
||||||
|
|
||||||
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
||||||
|
|
||||||
Pod::Spec.new do |s|
|
|
||||||
s.name = 'NativeStoreBilling'
|
|
||||||
s.version = package['version']
|
|
||||||
s.summary = package['description']
|
|
||||||
s.license = 'MIT'
|
|
||||||
s.homepage = 'https://aimloperations.com'
|
|
||||||
s.author = 'AI ML Operations'
|
|
||||||
s.source = { :path => '.' }
|
|
||||||
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
|
|
||||||
s.ios.deployment_target = '15.0'
|
|
||||||
s.dependency 'Capacitor'
|
|
||||||
s.swift_version = '5.1'
|
|
||||||
end
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
apply plugin: 'com.android.library'
|
|
||||||
|
|
||||||
android {
|
|
||||||
namespace "ai.hesychia.chat.billing"
|
|
||||||
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
|
|
||||||
defaultConfig {
|
|
||||||
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
|
|
||||||
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
|
|
||||||
versionCode 1
|
|
||||||
versionName "1.0"
|
|
||||||
}
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_21
|
|
||||||
targetCompatibility JavaVersion.VERSION_21
|
|
||||||
}
|
|
||||||
lintOptions {
|
|
||||||
abortOnError false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation project(':capacitor-android')
|
|
||||||
implementation "androidx.appcompat:appcompat:1.7.0"
|
|
||||||
implementation "com.android.billingclient:billing:7.1.1"
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
</manifest>
|
|
||||||
@@ -1,243 +0,0 @@
|
|||||||
package ai.hesychia.chat.billing;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import com.android.billingclient.api.AcknowledgePurchaseParams;
|
|
||||||
import com.android.billingclient.api.BillingClient;
|
|
||||||
import com.android.billingclient.api.BillingClientStateListener;
|
|
||||||
import com.android.billingclient.api.BillingFlowParams;
|
|
||||||
import com.android.billingclient.api.BillingResult;
|
|
||||||
import com.android.billingclient.api.PendingPurchasesParams;
|
|
||||||
import com.android.billingclient.api.ProductDetails;
|
|
||||||
import com.android.billingclient.api.Purchase;
|
|
||||||
import com.android.billingclient.api.PurchasesUpdatedListener;
|
|
||||||
import com.android.billingclient.api.QueryProductDetailsParams;
|
|
||||||
import com.android.billingclient.api.QueryPurchasesParams;
|
|
||||||
import com.getcapacitor.JSArray;
|
|
||||||
import com.getcapacitor.JSObject;
|
|
||||||
import com.getcapacitor.Plugin;
|
|
||||||
import com.getcapacitor.PluginCall;
|
|
||||||
import com.getcapacitor.PluginMethod;
|
|
||||||
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
@CapacitorPlugin(name = "NativeStoreBilling")
|
|
||||||
public class NativeStoreBillingPlugin extends Plugin implements PurchasesUpdatedListener {
|
|
||||||
|
|
||||||
private BillingClient billingClient;
|
|
||||||
private PluginCall pendingPurchase;
|
|
||||||
private String pendingProductId = "";
|
|
||||||
|
|
||||||
@PluginMethod
|
|
||||||
public void purchase(PluginCall call) {
|
|
||||||
String productId = call.getString("productId", "");
|
|
||||||
String accountToken = call.getString("accountToken", "");
|
|
||||||
if (productId == null || productId.isEmpty()) {
|
|
||||||
call.reject("productId is required");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Activity activity = getActivity();
|
|
||||||
if (activity == null) {
|
|
||||||
call.reject("Play Billing needs a foreground activity");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
activity.runOnUiThread(() ->
|
|
||||||
connect(call, () -> queryAndLaunch(call, productId, accountToken == null ? "" : accountToken))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PluginMethod
|
|
||||||
public void restore(PluginCall call) {
|
|
||||||
Activity activity = getActivity();
|
|
||||||
if (activity == null) {
|
|
||||||
call.reject("Play Billing needs a foreground activity");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
activity.runOnUiThread(() -> connect(call, () -> queryOwned(call, "")));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void connect(PluginCall call, Runnable whenReady) {
|
|
||||||
if (billingClient != null && billingClient.isReady()) {
|
|
||||||
whenReady.run();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
billingClient = BillingClient.newBuilder(getContext())
|
|
||||||
.setListener(this)
|
|
||||||
.enablePendingPurchases(
|
|
||||||
PendingPurchasesParams.newBuilder().enableOneTimeProducts().build()
|
|
||||||
)
|
|
||||||
.build();
|
|
||||||
billingClient.startConnection(
|
|
||||||
new BillingClientStateListener() {
|
|
||||||
@Override
|
|
||||||
public void onBillingSetupFinished(BillingResult billingResult) {
|
|
||||||
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
|
|
||||||
whenReady.run();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
call.reject("Play Billing setup failed: " + billingResult.getDebugMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBillingServiceDisconnected() {
|
|
||||||
// The next purchase reconnects.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void queryAndLaunch(PluginCall call, String productId, String accountToken) {
|
|
||||||
QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder()
|
|
||||||
.setProductList(
|
|
||||||
Collections.singletonList(
|
|
||||||
QueryProductDetailsParams.Product.newBuilder()
|
|
||||||
.setProductId(productId)
|
|
||||||
.setProductType(BillingClient.ProductType.SUBS)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.build();
|
|
||||||
billingClient.queryProductDetailsAsync(params, (billingResult, productDetailsList) -> {
|
|
||||||
if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) {
|
|
||||||
call.reject("Could not load Play product: " + billingResult.getDebugMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (productDetailsList == null || productDetailsList.isEmpty()) {
|
|
||||||
call.reject("Play product was not found: " + productId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ProductDetails details = productDetailsList.get(0);
|
|
||||||
List<ProductDetails.SubscriptionOfferDetails> offers = details.getSubscriptionOfferDetails();
|
|
||||||
if (offers == null || offers.isEmpty()) {
|
|
||||||
call.reject("Play product has no subscription offer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String offerToken = offers.get(0).getOfferToken();
|
|
||||||
BillingFlowParams.ProductDetailsParams productParams = BillingFlowParams.ProductDetailsParams.newBuilder()
|
|
||||||
.setProductDetails(details)
|
|
||||||
.setOfferToken(offerToken)
|
|
||||||
.build();
|
|
||||||
BillingFlowParams.Builder flow = BillingFlowParams.newBuilder()
|
|
||||||
.setProductDetailsParamsList(Collections.singletonList(productParams));
|
|
||||||
if (!accountToken.isEmpty()) {
|
|
||||||
flow.setObfuscatedAccountId(accountToken);
|
|
||||||
}
|
|
||||||
Activity activity = getActivity();
|
|
||||||
if (activity == null) {
|
|
||||||
call.reject("Play Billing needs a foreground activity");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
activity.runOnUiThread(() -> {
|
|
||||||
pendingPurchase = call;
|
|
||||||
pendingProductId = productId;
|
|
||||||
BillingResult launched = billingClient.launchBillingFlow(activity, flow.build());
|
|
||||||
if (launched.getResponseCode() != BillingClient.BillingResponseCode.OK) {
|
|
||||||
pendingPurchase = null;
|
|
||||||
call.reject("Could not open Play purchase sheet: " + launched.getDebugMessage());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
|
|
||||||
PluginCall call = pendingPurchase;
|
|
||||||
pendingPurchase = null;
|
|
||||||
if (call == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int code = billingResult.getResponseCode();
|
|
||||||
if (code == BillingClient.BillingResponseCode.USER_CANCELED) {
|
|
||||||
JSObject data = new JSObject();
|
|
||||||
data.put("userCancelled", true);
|
|
||||||
call.reject("Purchase cancelled", "PURCHASE_CANCELLED", null, data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (code == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
|
|
||||||
queryOwned(call, pendingProductId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (code != BillingClient.BillingResponseCode.OK || purchases == null || purchases.isEmpty()) {
|
|
||||||
call.reject("Play purchase failed: " + billingResult.getDebugMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Purchase match = null;
|
|
||||||
for (Purchase purchase : purchases) {
|
|
||||||
if (purchase.getPurchaseState() != Purchase.PurchaseState.PURCHASED) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (pendingProductId.isEmpty() || purchase.getProducts().contains(pendingProductId)) {
|
|
||||||
match = purchase;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (match == null) {
|
|
||||||
call.reject("Play purchase did not complete");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
acknowledge(match);
|
|
||||||
call.resolve(purchaseToJson(match));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void queryOwned(PluginCall call, String productId) {
|
|
||||||
QueryPurchasesParams params = QueryPurchasesParams.newBuilder()
|
|
||||||
.setProductType(BillingClient.ProductType.SUBS)
|
|
||||||
.build();
|
|
||||||
billingClient.queryPurchasesAsync(params, (billingResult, purchases) -> {
|
|
||||||
if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) {
|
|
||||||
call.reject("Could not restore Play purchases: " + billingResult.getDebugMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
JSArray rows = new JSArray();
|
|
||||||
Purchase single = null;
|
|
||||||
List<Purchase> owned = purchases == null ? new ArrayList<>() : purchases;
|
|
||||||
for (Purchase purchase : owned) {
|
|
||||||
if (purchase.getPurchaseState() != Purchase.PurchaseState.PURCHASED) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!productId.isEmpty() && !purchase.getProducts().contains(productId)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
acknowledge(purchase);
|
|
||||||
JSONObject row = purchaseToJson(purchase);
|
|
||||||
rows.put(row);
|
|
||||||
single = purchase;
|
|
||||||
}
|
|
||||||
if (!productId.isEmpty()) {
|
|
||||||
if (single == null) {
|
|
||||||
call.reject("No active Play purchase for " + productId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
call.resolve(purchaseToJson(single));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
JSObject result = new JSObject();
|
|
||||||
result.put("transactions", rows);
|
|
||||||
call.resolve(result);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void acknowledge(Purchase purchase) {
|
|
||||||
if (purchase.isAcknowledged() || billingClient == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AcknowledgePurchaseParams params = AcknowledgePurchaseParams.newBuilder()
|
|
||||||
.setPurchaseToken(purchase.getPurchaseToken())
|
|
||||||
.build();
|
|
||||||
billingClient.acknowledgePurchase(params, billingResult -> { });
|
|
||||||
}
|
|
||||||
|
|
||||||
private JSObject purchaseToJson(Purchase purchase) {
|
|
||||||
String productId = purchase.getProducts().isEmpty() ? "" : purchase.getProducts().get(0);
|
|
||||||
String orderId = purchase.getOrderId() == null ? purchase.getPurchaseToken() : purchase.getOrderId();
|
|
||||||
JSObject row = new JSObject();
|
|
||||||
row.put("store", "play_store");
|
|
||||||
row.put("productId", productId);
|
|
||||||
row.put("transactionId", orderId);
|
|
||||||
row.put("purchaseToken", purchase.getPurchaseToken());
|
|
||||||
row.put("signedTransaction", "");
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export {};
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
// Native code is loaded by Capacitor. The web app registers the plugin from src.
|
|
||||||
module.exports = {};
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
import Capacitor
|
|
||||||
import StoreKit
|
|
||||||
|
|
||||||
@objc(NativeStoreBillingPlugin)
|
|
||||||
public class NativeStoreBillingPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
||||||
public let identifier = "NativeStoreBillingPlugin"
|
|
||||||
public let jsName = "NativeStoreBilling"
|
|
||||||
public let pluginMethods: [CAPPluginMethod] = [
|
|
||||||
CAPPluginMethod(name: "purchase", returnType: CAPPluginReturnPromise),
|
|
||||||
CAPPluginMethod(name: "restore", returnType: CAPPluginReturnPromise)
|
|
||||||
]
|
|
||||||
|
|
||||||
@objc func purchase(_ call: CAPPluginCall) {
|
|
||||||
let productId = call.getString("productId") ?? ""
|
|
||||||
let accountToken = call.getString("accountToken") ?? ""
|
|
||||||
if productId.isEmpty {
|
|
||||||
call.reject("productId is required")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
Task {
|
|
||||||
do {
|
|
||||||
let products = try await Product.products(for: [productId])
|
|
||||||
guard let product = products.first else {
|
|
||||||
call.reject("App Store product was not found: \(productId)")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var options = Set<Product.PurchaseOption>()
|
|
||||||
if let uuid = UUID(uuidString: accountToken) {
|
|
||||||
options.insert(.appAccountToken(uuid))
|
|
||||||
}
|
|
||||||
let result = try await product.purchase(options: options)
|
|
||||||
switch result {
|
|
||||||
case .success(let verification):
|
|
||||||
let transaction = try Self.checkVerified(verification)
|
|
||||||
let payload = Self.payload(transaction: transaction, jws: verification.jwsRepresentation)
|
|
||||||
await transaction.finish()
|
|
||||||
call.resolve(payload)
|
|
||||||
case .userCancelled:
|
|
||||||
call.reject("Purchase cancelled", "PURCHASE_CANCELLED", nil, ["userCancelled": true])
|
|
||||||
case .pending:
|
|
||||||
call.reject("App Store purchase is still pending")
|
|
||||||
@unknown default:
|
|
||||||
call.reject("Unknown App Store purchase result")
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
call.reject(error.localizedDescription)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func restore(_ call: CAPPluginCall) {
|
|
||||||
Task {
|
|
||||||
var rows: [JSObject] = []
|
|
||||||
for await result in Transaction.currentEntitlements {
|
|
||||||
guard case .verified(let transaction) = result else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if transaction.revocationDate != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rows.append(Self.payload(transaction: transaction, jws: result.jwsRepresentation))
|
|
||||||
}
|
|
||||||
call.resolve(["transactions": rows])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func checkVerified<T>(_ result: VerificationResult<T>) throws -> T {
|
|
||||||
switch result {
|
|
||||||
case .unverified:
|
|
||||||
throw NSError(
|
|
||||||
domain: "NativeStoreBilling",
|
|
||||||
code: 1,
|
|
||||||
userInfo: [NSLocalizedDescriptionKey: "App Store could not verify this transaction"]
|
|
||||||
)
|
|
||||||
case .verified(let safe):
|
|
||||||
return safe
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func payload(transaction: Transaction, jws: String) -> JSObject {
|
|
||||||
var row: JSObject = [
|
|
||||||
"store": "app_store",
|
|
||||||
"productId": transaction.productID,
|
|
||||||
"transactionId": String(transaction.id),
|
|
||||||
"purchaseToken": "",
|
|
||||||
"signedTransaction": jws
|
|
||||||
]
|
|
||||||
if let expires = transaction.expirationDate {
|
|
||||||
row["expiresAt"] = ISO8601DateFormatter().string(from: expires)
|
|
||||||
}
|
|
||||||
return row
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "native-store-billing",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"private": true,
|
|
||||||
"description": "StoreKit and Play Billing purchases for the Hesychia Capacitor shell.",
|
|
||||||
"main": "dist/index.js",
|
|
||||||
"types": "dist/index.d.ts",
|
|
||||||
"capacitor": {
|
|
||||||
"ios": {
|
|
||||||
"src": "ios"
|
|
||||||
},
|
|
||||||
"android": {
|
|
||||||
"src": "android"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"android/src/main/",
|
|
||||||
"android/build.gradle",
|
|
||||||
"ios/Sources",
|
|
||||||
"NativeStoreBilling.podspec",
|
|
||||||
"dist/"
|
|
||||||
],
|
|
||||||
"peerDependencies": {
|
|
||||||
"@capacitor/core": ">=7.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<title>The page is not found — Hesychia</title>
|
|
||||||
<meta name="description" content="The page is not found. This address is not a Hesychia page. Open the home page to read what the product does, what it costs, and how to start an account." />
|
|
||||||
<meta property="og:title" content="The page is not found — Hesychia" />
|
|
||||||
<meta property="og:description" content="The page is not found. This address is not a Hesychia page. Open the home page to read what the product does, what it costs, and how to start an account." />
|
|
||||||
<meta property="og:url" content="https://hesychia.ai/404.html" />
|
|
||||||
<meta property="og:image" content="https://hesychia.ai/og-image.png" />
|
|
||||||
<meta property="og:image:width" content="1200" />
|
|
||||||
<meta property="og:image:height" content="630" />
|
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
|
||||||
<meta name="twitter:title" content="The page is not found — Hesychia" />
|
|
||||||
<meta name="twitter:description" content="The page is not found. This address is not a Hesychia page. Open the home page to read what the product does, what it costs, and how to start an account." />
|
|
||||||
<meta name="twitter:image" content="https://hesychia.ai/og-image.png" />
|
|
||||||
<script type="application/ld+json">
|
|
||||||
{
|
|
||||||
"@context": "https://schema.org",
|
|
||||||
"@graph": [
|
|
||||||
{
|
|
||||||
"@type": "WebPage",
|
|
||||||
"headline": "The page is not found — Hesychia",
|
|
||||||
"url": "https://hesychia.ai/404.html",
|
|
||||||
"mainEntityOfPage": "https://hesychia.ai/404.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"@type": "Organization",
|
|
||||||
"name": "Hesychia",
|
|
||||||
"url": "https://hesychia.ai",
|
|
||||||
"logo": "https://hesychia.ai/apple-touch-icon.png",
|
|
||||||
"parentOrganization": {
|
|
||||||
"@type": "Organization",
|
|
||||||
"name": "AI ML Operations, LLC",
|
|
||||||
"url": "https://www.aimloperations.com"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Not Found</h1>
|
|
||||||
<p>The page is not found, and this address is not a Hesychia page.</p>
|
|
||||||
<p>Open the home page to read what the product does, what it costs, and how to start an account.</p>
|
|
||||||
<nav aria-label="Related pages"><a href="/">What Hesychia is</a><a href="/pricing/">Hesychia pricing — $10/month, no ads</a><a href="/privacy/">What Hesychia stores and does not sell</a><a href="/changelog/">Dated Hesychia product updates</a></nav>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
8d1667dd71c6ef137171989c26eeb632
|
|
||||||
@@ -8,62 +8,11 @@
|
|||||||
<link rel="icon" type="image/png" sizes="16x16" href="%PUBLIC_URL%/favicon-16x16.png" />
|
<link rel="icon" type="image/png" sizes="16x16" href="%PUBLIC_URL%/favicon-16x16.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta name="description" content="Hesychia is a $10/month AI chat product from AI ML Operations, LLC. It stores your documents so answers can use your files." />
|
<meta name="description" content="Hesychia — a calm AI assistant by AI ML Operations, LLC" />
|
||||||
<meta name="application-name" content="Hesychia" />
|
<meta name="application-name" content="Hesychia" />
|
||||||
<link rel="canonical" href="https://hesychia.ai/" />
|
<meta property="og:title" content="Hesychia" />
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:description" content="Hesychia — quiet, focused AI chat at hesychia.ai" />
|
||||||
<meta property="og:title" content="Hesychia — quiet, focused AI chat" />
|
<meta property="og:url" content="https://hesychia.ai" />
|
||||||
<meta property="og:description" content="Hesychia is a $10/month AI chat product from AI ML Operations, LLC. It stores your documents so answers can use your files." />
|
|
||||||
<meta property="og:url" content="https://hesychia.ai/" />
|
|
||||||
<meta property="og:image" content="https://hesychia.ai/og-image.png" />
|
|
||||||
<meta property="og:image:width" content="1200" />
|
|
||||||
<meta property="og:image:height" content="630" />
|
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
|
||||||
<meta name="twitter:title" content="Hesychia — quiet, focused AI chat" />
|
|
||||||
<meta name="twitter:description" content="Hesychia is a $10/month AI chat product from AI ML Operations, LLC. It stores your documents so answers can use your files." />
|
|
||||||
<meta name="twitter:image" content="https://hesychia.ai/og-image.png" />
|
|
||||||
<script type="application/ld+json">
|
|
||||||
{
|
|
||||||
"@context": "https://schema.org",
|
|
||||||
"@graph": [
|
|
||||||
{
|
|
||||||
"@type": "WebPage",
|
|
||||||
"headline": "Hesychia — quiet, focused AI chat",
|
|
||||||
"url": "https://hesychia.ai/",
|
|
||||||
"mainEntityOfPage": "https://hesychia.ai/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"@type": "Organization",
|
|
||||||
"name": "Hesychia",
|
|
||||||
"url": "https://hesychia.ai",
|
|
||||||
"logo": "https://hesychia.ai/apple-touch-icon.png",
|
|
||||||
"parentOrganization": {
|
|
||||||
"@type": "Organization",
|
|
||||||
"name": "AI ML Operations, LLC",
|
|
||||||
"url": "https://www.aimloperations.com"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"@type": "SoftwareApplication",
|
|
||||||
"name": "Hesychia",
|
|
||||||
"applicationCategory": "BusinessApplication",
|
|
||||||
"operatingSystem": "Web",
|
|
||||||
"url": "https://hesychia.ai/",
|
|
||||||
"description": "Hesychia is a $10/month AI chat product from AI ML Operations, LLC. It stores your documents so answers can use your files.",
|
|
||||||
"offers": {
|
|
||||||
"@type": "Offer",
|
|
||||||
"price": "10.00",
|
|
||||||
"priceCurrency": "USD"
|
|
||||||
},
|
|
||||||
"provider": {
|
|
||||||
"@type": "Organization",
|
|
||||||
"name": "AI ML Operations, LLC",
|
|
||||||
"url": "https://www.aimloperations.com"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="%PUBLIC_URL%/apple-touch-icon.png" />
|
<link rel="apple-touch-icon" sizes="180x180" href="%PUBLIC_URL%/apple-touch-icon.png" />
|
||||||
<!--
|
<!--
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
@@ -79,11 +28,11 @@
|
|||||||
work correctly both with client-side routing and a non-root public URL.
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<title>Hesychia — quiet, focused AI chat</title>
|
<title>Hesychia</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="root"><h1>Hesychia is a calm AI assistant.</h1><div id="crawler-prose"><p>Quiet, focused AI chat — private by default — is how this Hesychia product is built.</p><p>It remembers what you told it and your documents, so you never start over, and conversation memory is a setting you control.</p><p>We store your account, your conversations, and the documents you upload.</p><p>We do not sell your data, and we do not use advertising cookies.</p><p>Canceling does not delete documents, and they stay until you delete them or delete the account, and account deletion is a soft-delete.</p><p>It remembers what you told it and your documents, so you never start over.</p><p>Your documents stay stored and searchable, and answers are grounded in your own files.</p><p>Business accounts are simple management for your team, and company managers can manage team accounts.</p><p>Early adopters pay $10 per month, locked for the lifetime of the account, and that price never goes up.</p><p>Image generation is on the roadmap, so a prompt can create a picture inside Hesychia.</p><p>Vision is on the roadmap, so you can ask questions about an image you upload.</p></div><nav aria-label="Related pages"><a href="/pricing/">Hesychia pricing — $10/month, no ads</a><a href="/privacy/">What Hesychia stores and does not sell</a><a href="/changelog/">Dated Hesychia product updates</a><a href="/terms_of_service/">Hesychia terms of service</a><a href="/account-deletion/">How to request Hesychia account deletion</a></nav></div>
|
<div id="root"></div>
|
||||||
<!--
|
<!--
|
||||||
This HTML file is a template.
|
This HTML file is a template.
|
||||||
If you open it directly in the browser, you will see an empty page.
|
If you open it directly in the browser, you will see an empty page.
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
# Hesychia
|
|
||||||
|
|
||||||
> Hesychia is a calm AI assistant with quiet, focused AI chat that stays private by default.
|
|
||||||
|
|
||||||
Hesychia is a $10/month AI chat product from AI ML Operations, LLC. Early adopters pay $10 per month, locked for the lifetime of the account, and that price never goes up. It stores your documents so answers can use your files, and company managers can manage team accounts. Conversation memory is a setting you control, and canceling a subscription does not delete documents. Account deletion is a soft-delete, and stored account data may remain. Image generation and vision are on the roadmap.
|
|
||||||
|
|
||||||
## Pages
|
|
||||||
|
|
||||||
- [Home](https://hesychia.ai/): what Hesychia is, who it is for, and how to start
|
|
||||||
- [Pricing](https://hesychia.ai/pricing/): $10/month early adopter, locked for life, never goes up
|
|
||||||
- [Privacy](https://hesychia.ai/privacy/): what is stored, what is not sold, what cancel does to documents
|
|
||||||
- [Changelog](https://hesychia.ai/changelog/): dated product updates
|
|
||||||
- [Terms of Service](https://hesychia.ai/terms_of_service/): the binding terms
|
|
||||||
- [Account deletion](https://hesychia.ai/account-deletion/): how to delete an account and what soft-delete keeps
|
|
||||||
|
|
||||||
## Operator
|
|
||||||
|
|
||||||
AI ML Operations, LLC — https://www.aimloperations.com
|
|
||||||
|
Before Width: | Height: | Size: 212 KiB |