mirror of
https://github.com/Sea-Haven-Industries/proposal-system.git
synced 2026-10-07 13:58:56 +00:00
Compare commits
3 commits
a9b720ee08
...
bd9fbb4da5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd9fbb4da5 | ||
|
|
a9c157dc95 | ||
|
|
da00d27049 |
11 changed files with 878 additions and 58 deletions
8
.github/workflows/deploy-mobile.yaml
vendored
8
.github/workflows/deploy-mobile.yaml
vendored
|
|
@ -1,11 +1,9 @@
|
||||||
name: Deploy Mobile (iOS)
|
name: Deploy Mobile (iOS)
|
||||||
|
|
||||||
# Disabled during development. To activate for V1 release, change to:
|
|
||||||
# on:
|
|
||||||
# push:
|
|
||||||
# branches: [main]
|
|
||||||
# paths: ["mobile/**"]
|
|
||||||
on:
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths: ["mobile/**"]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
|
|
|
||||||
21
README.md
21
README.md
|
|
@ -18,7 +18,7 @@ Monorepo with five primary services:
|
||||||
proposal-system/
|
proposal-system/
|
||||||
├── api/ .NET 8 Web API (Lambda-hosted, EF Core + PostgreSQL)
|
├── api/ .NET 8 Web API (Lambda-hosted, EF Core + PostgreSQL)
|
||||||
├── web/ React 19 + MUI v7 + Vite frontend
|
├── web/ React 19 + MUI v7 + Vite frontend
|
||||||
├── mobile/ React Native 0.79 iOS app
|
├── mobile/ React Native 0.85 iOS app
|
||||||
├── lambdas/ Python 3.12 processing functions (arm64)
|
├── lambdas/ Python 3.12 processing functions (arm64)
|
||||||
├── infra/ CDK TypeScript (3 stacks)
|
├── infra/ CDK TypeScript (3 stacks)
|
||||||
├── shared/ TypeScript API contracts (shared between web + mobile)
|
├── shared/ TypeScript API contracts (shared between web + mobile)
|
||||||
|
|
@ -33,7 +33,7 @@ proposal-system/
|
||||||
|---|---|
|
|---|---|
|
||||||
| API | .NET 8, ASP.NET Core, EF Core + Npgsql, FluentValidation, Cognito JWT, Amazon.Lambda.AspNetCoreServer |
|
| API | .NET 8, ASP.NET Core, EF Core + Npgsql, FluentValidation, Cognito JWT, Amazon.Lambda.AspNetCoreServer |
|
||||||
| Web | React 19, TypeScript, MUI v7, Vite, Redux Toolkit, TanStack Query, axios |
|
| Web | React 19, TypeScript, MUI v7, Vite, Redux Toolkit, TanStack Query, axios |
|
||||||
| Mobile | React Native CLI 0.79, React 19, React Native Paper, React Navigation, react-native-app-auth (PKCE), Keychain, offline draft queue |
|
| Mobile | React Native CLI 0.85, React 19, React Native Paper, React Navigation, react-native-app-auth (PKCE), amazon-cognito-identity-js (SRP), Keychain, offline draft queue |
|
||||||
| Lambdas | Python 3.12, arm64, pdfplumber, reportlab, httpx, boto3 |
|
| Lambdas | Python 3.12, arm64, pdfplumber, reportlab, httpx, boto3 |
|
||||||
| Infrastructure | CDK TypeScript (aws-cdk-lib 2.253.1) |
|
| Infrastructure | CDK TypeScript (aws-cdk-lib 2.253.1) |
|
||||||
| AI/RAG | Bedrock Knowledge Base (Titan Embeddings v2), OpenSearch Serverless, Claude via Bedrock Runtime |
|
| AI/RAG | Bedrock Knowledge Base (Titan Embeddings v2), OpenSearch Serverless, Claude via Bedrock Runtime |
|
||||||
|
|
@ -127,11 +127,13 @@ Calls `cd-cdk.yaml` reusable workflow:
|
||||||
|
|
||||||
Deploy uses OIDC role `githubdeploy-proposal-system`. Concurrency group prevents parallel deploys.
|
Deploy uses OIDC role `githubdeploy-proposal-system`. Concurrency group prevents parallel deploys.
|
||||||
|
|
||||||
### Mobile Deploy (currently disabled)
|
### Mobile Deploy
|
||||||
|
|
||||||
Workflow: `deploy-mobile.yaml` -- triggered by `workflow_dispatch` only (manual).
|
Workflow: `deploy-mobile.yaml` -- builds and uploads to TestFlight via `cd-mobile-ios.yaml` reusable workflow on `macos-26`.
|
||||||
|
|
||||||
To activate for release, change the trigger to push on main with path filter `mobile/**`.
|
Triggers:
|
||||||
|
- **Automatic**: push to `main` with changes in `mobile/**`
|
||||||
|
- **Manual**: `workflow_dispatch` for on-demand builds
|
||||||
|
|
||||||
## Mobile iOS
|
## Mobile iOS
|
||||||
|
|
||||||
|
|
@ -147,15 +149,6 @@ Build and upload to TestFlight is handled by the `cd-mobile-ios.yaml` reusable w
|
||||||
| `ASC_ISSUER_ID` | App Store Connect issuer |
|
| `ASC_ISSUER_ID` | App Store Connect issuer |
|
||||||
| `ASC_KEY_CONTENT` | App Store Connect API key (base64) |
|
| `ASC_KEY_CONTENT` | App Store Connect API key (base64) |
|
||||||
|
|
||||||
To activate automatic deploys, update `deploy-mobile.yaml` trigger from `workflow_dispatch` to:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main]
|
|
||||||
paths: ["mobile/**"]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Data Flow
|
## Data Flow
|
||||||
|
|
||||||
1. Dispatcher submits proposal request (web or mobile)
|
1. Dispatcher submits proposal request (web or mobile)
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,7 @@ export class FoundationStack extends cdk.Stack {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Web App Client (PKCE)
|
// Web App Client (PKCE)
|
||||||
userPool.addClient('WebClient', {
|
const webClient = userPool.addClient('WebClient', {
|
||||||
userPoolClientName: 'proposal-system-web',
|
userPoolClientName: 'proposal-system-web',
|
||||||
generateSecret: false,
|
generateSecret: false,
|
||||||
authFlows: {
|
authFlows: {
|
||||||
|
|
@ -235,7 +235,7 @@ export class FoundationStack extends cdk.Stack {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Mobile App Client (PKCE)
|
// Mobile App Client (PKCE)
|
||||||
userPool.addClient('MobileClient', {
|
const mobileClient = userPool.addClient('MobileClient', {
|
||||||
userPoolClientName: 'proposal-system-mobile',
|
userPoolClientName: 'proposal-system-mobile',
|
||||||
generateSecret: false,
|
generateSecret: false,
|
||||||
authFlows: {
|
authFlows: {
|
||||||
|
|
@ -248,8 +248,8 @@ export class FoundationStack extends cdk.Stack {
|
||||||
cognito.OAuthScope.EMAIL,
|
cognito.OAuthScope.EMAIL,
|
||||||
cognito.OAuthScope.PROFILE,
|
cognito.OAuthScope.PROFILE,
|
||||||
],
|
],
|
||||||
callbackUrls: ['proposalsystem://callback'],
|
callbackUrls: ['com.seahavenind.proposals://auth/callback'],
|
||||||
logoutUrls: ['proposalsystem://logout'],
|
logoutUrls: ['com.seahavenind.proposals://auth/logout'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -278,5 +278,7 @@ export class FoundationStack extends cdk.Stack {
|
||||||
new cdk.CfnOutput(this, 'LibraryBucketName', { value: this.libraryBucket.bucketName });
|
new cdk.CfnOutput(this, 'LibraryBucketName', { value: this.libraryBucket.bucketName });
|
||||||
new cdk.CfnOutput(this, 'JobsQueueUrl', { value: this.jobsQueue.queueUrl });
|
new cdk.CfnOutput(this, 'JobsQueueUrl', { value: this.jobsQueue.queueUrl });
|
||||||
new cdk.CfnOutput(this, 'DbSecretArn', { value: this.dbSecret.secretArn });
|
new cdk.CfnOutput(this, 'DbSecretArn', { value: this.dbSecret.secretArn });
|
||||||
|
new cdk.CfnOutput(this, 'WebClientId', { value: webClient.userPoolClientId });
|
||||||
|
new cdk.CfnOutput(this, 'MobileClientId', { value: mobileClient.userPoolClientId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
92
mobile/README.md
Normal file
92
mobile/README.md
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
# Proposal System — Mobile (iOS)
|
||||||
|
|
||||||
|
React Native 0.85 iOS app for Sea Haven Industries field dispatchers. Submit proposals, capture vendor documents, and manage drafts with offline support.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Node.js 24+
|
||||||
|
- Ruby 3.x (for Fastlane)
|
||||||
|
- Xcode 26+ with iOS 26 SDK
|
||||||
|
- CocoaPods (installed via Bundler)
|
||||||
|
|
||||||
|
## Local Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install JS dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Install Ruby dependencies (Fastlane, CocoaPods)
|
||||||
|
bundle install
|
||||||
|
|
||||||
|
# Install native pods
|
||||||
|
cd ios && bundle exec pod install && cd ..
|
||||||
|
|
||||||
|
# Start Metro bundler
|
||||||
|
npm start
|
||||||
|
|
||||||
|
# Run on iOS simulator
|
||||||
|
npm run ios
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment
|
||||||
|
|
||||||
|
The app reads configuration from `src/config.ts`. In development mode (`__DEV__`), the API URL points to `http://localhost:5000/api`. Run the .NET API locally or use the development proxy.
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
|
||||||
|
Two login methods are supported:
|
||||||
|
|
||||||
|
- **Email/Password** — direct Cognito SRP auth via `amazon-cognito-identity-js`
|
||||||
|
- **Google OAuth** — Cognito Hosted UI PKCE flow via `react-native-app-auth`
|
||||||
|
|
||||||
|
The iOS URL scheme `com.seahavenind.proposals` is registered in `Info.plist` for OAuth callbacks.
|
||||||
|
|
||||||
|
## Code Signing
|
||||||
|
|
||||||
|
Certificates and provisioning profiles are managed by **Fastlane Match** using S3 storage:
|
||||||
|
|
||||||
|
- **Bucket**: `seahaven-ios-certificates` (us-east-1)
|
||||||
|
- **Bundle ID**: `com.seahavenind.proposals`
|
||||||
|
- **Team ID**: `9KAQYC653W`
|
||||||
|
|
||||||
|
Match is configured in `fastlane/Matchfile`. The `MATCH_PASSWORD` secret decrypts signing assets.
|
||||||
|
|
||||||
|
## CI/CD
|
||||||
|
|
||||||
|
The `deploy-mobile.yaml` workflow triggers on push to `main` (with `mobile/**` path filter) or manual `workflow_dispatch`. It calls the `cd-mobile-ios.yaml` reusable workflow which:
|
||||||
|
|
||||||
|
1. Sets up `macos-26` runner with Xcode 26
|
||||||
|
2. Installs dependencies and pods
|
||||||
|
3. Retrieves signing assets via Match (S3)
|
||||||
|
4. Builds the IPA with Fastlane
|
||||||
|
5. Uploads to TestFlight
|
||||||
|
|
||||||
|
### Required GitHub Secrets
|
||||||
|
|
||||||
|
| Secret | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `AWS_DEPLOY_ROLE_ARN` | OIDC role for Match S3 access |
|
||||||
|
| `MATCH_PASSWORD` | Signing asset decryption passphrase |
|
||||||
|
| `ASC_KEY_ID` | App Store Connect API key ID |
|
||||||
|
| `ASC_ISSUER_ID` | App Store Connect API issuer |
|
||||||
|
| `ASC_KEY_CONTENT` | App Store Connect `.p8` key (base64) |
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
mobile/
|
||||||
|
├── src/
|
||||||
|
│ ├── screens/ Auth, dispatcher, and admin screens
|
||||||
|
│ ├── lib/api/ API clients (auth, proposals, line items, admin)
|
||||||
|
│ ├── store/ Redux Toolkit (auth slice)
|
||||||
|
│ ├── navigation/ React Navigation (RootNavigator)
|
||||||
|
│ ├── components/ Reusable UI components
|
||||||
|
│ ├── hooks/ useAuth, useOfflineDraft, usePaginatedList
|
||||||
|
│ ├── theme/ Material Design 3 theming
|
||||||
|
│ ├── constants/ App-wide constants
|
||||||
|
│ └── config.ts Cognito + API configuration
|
||||||
|
├── ios/ Xcode project, assets, Info.plist
|
||||||
|
├── fastlane/ Fastfile, Matchfile, Appfile
|
||||||
|
├── Gemfile Ruby dependencies
|
||||||
|
└── package.json React Native 0.85.3
|
||||||
|
```
|
||||||
452
mobile/package-lock.json
generated
452
mobile/package-lock.json
generated
|
|
@ -16,6 +16,7 @@
|
||||||
"@react-navigation/native-stack": "^7.2.0",
|
"@react-navigation/native-stack": "^7.2.0",
|
||||||
"@reduxjs/toolkit": "^2.11.2",
|
"@reduxjs/toolkit": "^2.11.2",
|
||||||
"@tanstack/react-query": "^5.100.10",
|
"@tanstack/react-query": "^5.100.10",
|
||||||
|
"amazon-cognito-identity-js": "^6.3.0",
|
||||||
"axios": "^1.16.0",
|
"axios": "^1.16.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-native": "^0.85.3",
|
"react-native": "^0.85.3",
|
||||||
|
|
@ -38,6 +39,7 @@
|
||||||
"@react-native/metro-config": "^0.85.3",
|
"@react-native/metro-config": "^0.85.3",
|
||||||
"@types/react": "^19.0.0",
|
"@types/react": "^19.0.0",
|
||||||
"@types/react-native-vector-icons": "^6.4.18",
|
"@types/react-native-vector-icons": "^6.4.18",
|
||||||
|
"patch-package": "^8.0.1",
|
||||||
"typescript": "~5.7.0"
|
"typescript": "~5.7.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -48,6 +50,62 @@
|
||||||
"typescript": "~5.7.0"
|
"typescript": "~5.7.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@aws-crypto/sha256-js": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@aws-crypto/util": "^1.2.2",
|
||||||
|
"@aws-sdk/types": "^3.1.0",
|
||||||
|
"tslib": "^1.11.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@aws-crypto/util": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@aws-sdk/types": "^3.1.0",
|
||||||
|
"@aws-sdk/util-utf8-browser": "^3.0.0",
|
||||||
|
"tslib": "^1.11.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@aws-sdk/types": {
|
||||||
|
"version": "3.973.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.8.tgz",
|
||||||
|
"integrity": "sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@smithy/types": "^4.14.1",
|
||||||
|
"tslib": "^2.6.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@aws-sdk/types/node_modules/tslib": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
|
"license": "0BSD"
|
||||||
|
},
|
||||||
|
"node_modules/@aws-sdk/util-utf8-browser": {
|
||||||
|
"version": "3.259.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz",
|
||||||
|
"integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@aws-sdk/util-utf8-browser/node_modules/tslib": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
|
"license": "0BSD"
|
||||||
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
|
||||||
|
|
@ -2139,6 +2197,24 @@
|
||||||
"integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==",
|
"integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@smithy/types": {
|
||||||
|
"version": "4.14.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.2.tgz",
|
||||||
|
"integrity": "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.6.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@smithy/types/node_modules/tslib": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
|
"license": "0BSD"
|
||||||
|
},
|
||||||
"node_modules/@standard-schema/spec": {
|
"node_modules/@standard-schema/spec": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
|
||||||
|
|
@ -2269,6 +2345,13 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@yarnpkg/lockfile": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause"
|
||||||
|
},
|
||||||
"node_modules/abort-controller": {
|
"node_modules/abort-controller": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||||
|
|
@ -2319,6 +2402,30 @@
|
||||||
"node": ">= 6.0.0"
|
"node": ">= 6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/amazon-cognito-identity-js": {
|
||||||
|
"version": "6.3.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.3.16.tgz",
|
||||||
|
"integrity": "sha512-HPGSBGD6Q36t99puWh0LnptxO/4icnk2kqIQ9cTJ2tFQo5NMUnWQIgtrTAk8nm+caqUbjDzXzG56GBjI2tS6jQ==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@aws-crypto/sha256-js": "1.2.2",
|
||||||
|
"buffer": "4.9.2",
|
||||||
|
"fast-base64-decode": "^1.0.0",
|
||||||
|
"isomorphic-unfetch": "^3.0.0",
|
||||||
|
"js-cookie": "^2.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/amazon-cognito-identity-js/node_modules/buffer": {
|
||||||
|
"version": "4.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
|
||||||
|
"integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "^1.0.2",
|
||||||
|
"ieee754": "^1.1.4",
|
||||||
|
"isarray": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/anser": {
|
"node_modules/anser": {
|
||||||
"version": "1.4.10",
|
"version": "1.4.10",
|
||||||
"resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz",
|
"resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz",
|
||||||
|
|
@ -2670,6 +2777,25 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/call-bind": {
|
||||||
|
"version": "1.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz",
|
||||||
|
"integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.2",
|
||||||
|
"es-define-property": "^1.0.1",
|
||||||
|
"get-intrinsic": "^1.3.0",
|
||||||
|
"set-function-length": "^1.2.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/call-bind-apply-helpers": {
|
"node_modules/call-bind-apply-helpers": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||||
|
|
@ -3116,6 +3242,24 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/define-data-property": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-define-property": "^1.0.0",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"gopd": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/delayed-stream": {
|
"node_modules/delayed-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
|
@ -3365,6 +3509,12 @@
|
||||||
"integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==",
|
"integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==",
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/fast-base64-decode": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fast-deep-equal": {
|
"node_modules/fast-deep-equal": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
|
|
@ -3544,6 +3694,16 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/find-yarn-workspace-root": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"micromatch": "^4.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/flow-enums-runtime": {
|
"node_modules/flow-enums-runtime": {
|
||||||
"version": "0.0.6",
|
"version": "0.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz",
|
||||||
|
|
@ -3727,6 +3887,19 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/has-property-descriptors": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-define-property": "^1.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/has-symbols": {
|
"node_modules/has-symbols": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
|
|
@ -3875,7 +4048,6 @@
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||||
"dev": true,
|
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
|
|
@ -4068,12 +4240,28 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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/isexe": {
|
"node_modules/isexe": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/isomorphic-unfetch": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"node-fetch": "^2.6.1",
|
||||||
|
"unfetch": "^4.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jest-get-type": {
|
"node_modules/jest-get-type": {
|
||||||
"version": "29.6.3",
|
"version": "29.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
|
||||||
|
|
@ -4176,6 +4364,12 @@
|
||||||
"@sideway/pinpoint": "^2.0.0"
|
"@sideway/pinpoint": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/js-cookie": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/js-tokens": {
|
"node_modules/js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
|
|
@ -4207,6 +4401,33 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/json-stable-stringify": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind": "^1.0.8",
|
||||||
|
"call-bound": "^1.0.4",
|
||||||
|
"isarray": "^2.0.5",
|
||||||
|
"jsonify": "^0.0.1",
|
||||||
|
"object-keys": "^1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/json-stable-stringify/node_modules/isarray": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/json5": {
|
"node_modules/json5": {
|
||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||||
|
|
@ -4229,6 +4450,26 @@
|
||||||
"graceful-fs": "^4.1.6"
|
"graceful-fs": "^4.1.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jsonify": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Public Domain",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/klaw-sync": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"graceful-fs": "^4.1.11"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/kleur": {
|
"node_modules/kleur": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||||
|
|
@ -4942,6 +5183,16 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/minimist": {
|
||||||
|
"version": "1.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||||
|
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mkdirp": {
|
"node_modules/mkdirp": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
|
@ -4998,6 +5249,26 @@
|
||||||
"node": ">=12.0.0"
|
"node": ">=12.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-fetch": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"whatwg-url": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "4.x || >=6.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"encoding": "^0.1.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"encoding": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-int64": {
|
"node_modules/node-int64": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||||
|
|
@ -5077,6 +5348,16 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/object-keys": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/on-finished": {
|
"node_modules/on-finished": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||||
|
|
@ -5226,6 +5507,103 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/patch-package": {
|
||||||
|
"version": "8.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.1.tgz",
|
||||||
|
"integrity": "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@yarnpkg/lockfile": "^1.1.0",
|
||||||
|
"chalk": "^4.1.2",
|
||||||
|
"ci-info": "^3.7.0",
|
||||||
|
"cross-spawn": "^7.0.3",
|
||||||
|
"find-yarn-workspace-root": "^2.0.0",
|
||||||
|
"fs-extra": "^10.0.0",
|
||||||
|
"json-stable-stringify": "^1.0.2",
|
||||||
|
"klaw-sync": "^6.0.0",
|
||||||
|
"minimist": "^1.2.6",
|
||||||
|
"open": "^7.4.2",
|
||||||
|
"semver": "^7.5.3",
|
||||||
|
"slash": "^2.0.0",
|
||||||
|
"tmp": "^0.2.4",
|
||||||
|
"yaml": "^2.2.2"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"patch-package": "index.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14",
|
||||||
|
"npm": ">5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/patch-package/node_modules/ci-info": {
|
||||||
|
"version": "3.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
|
||||||
|
"integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/sibiraj-s"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/patch-package/node_modules/fs-extra": {
|
||||||
|
"version": "10.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
|
||||||
|
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"graceful-fs": "^4.2.0",
|
||||||
|
"jsonfile": "^6.0.1",
|
||||||
|
"universalify": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/patch-package/node_modules/jsonfile": {
|
||||||
|
"version": "6.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz",
|
||||||
|
"integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"universalify": "^2.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"graceful-fs": "^4.1.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/patch-package/node_modules/semver": {
|
||||||
|
"version": "7.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz",
|
||||||
|
"integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/patch-package/node_modules/universalify": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/path-exists": {
|
"node_modules/path-exists": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
|
|
@ -6142,6 +6520,24 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/set-function-length": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"define-data-property": "^1.1.4",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"function-bind": "^1.1.2",
|
||||||
|
"get-intrinsic": "^1.2.4",
|
||||||
|
"gopd": "^1.0.1",
|
||||||
|
"has-property-descriptors": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"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",
|
||||||
|
|
@ -6295,6 +6691,16 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/slash": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/slice-ansi": {
|
"node_modules/slice-ansi": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
|
||||||
|
|
@ -6572,6 +6978,16 @@
|
||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tmp": {
|
||||||
|
"version": "0.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz",
|
||||||
|
"integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tmpl": {
|
"node_modules/tmpl": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
|
||||||
|
|
@ -6599,6 +7015,18 @@
|
||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tr46": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
|
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/tslib": {
|
||||||
|
"version": "1.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||||
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
||||||
|
"license": "0BSD"
|
||||||
|
},
|
||||||
"node_modules/type-fest": {
|
"node_modules/type-fest": {
|
||||||
"version": "0.7.1",
|
"version": "0.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz",
|
||||||
|
|
@ -6688,6 +7116,12 @@
|
||||||
"integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
|
"integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/unfetch": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/unicode-canonical-property-names-ecmascript": {
|
"node_modules/unicode-canonical-property-names-ecmascript": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz",
|
||||||
|
|
@ -6856,12 +7290,28 @@
|
||||||
"defaults": "^1.0.3"
|
"defaults": "^1.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webidl-conversions": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||||
|
"license": "BSD-2-Clause"
|
||||||
|
},
|
||||||
"node_modules/whatwg-fetch": {
|
"node_modules/whatwg-fetch": {
|
||||||
"version": "3.6.20",
|
"version": "3.6.20",
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz",
|
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz",
|
||||||
"integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==",
|
"integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/whatwg-url": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tr46": "~0.0.3",
|
||||||
|
"webidl-conversions": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@
|
||||||
"start": "react-native start",
|
"start": "react-native start",
|
||||||
"ios": "react-native run-ios",
|
"ios": "react-native run-ios",
|
||||||
"android": "react-native run-android",
|
"android": "react-native run-android",
|
||||||
"typecheck": "tsc --noEmit"
|
"typecheck": "tsc --noEmit",
|
||||||
|
"postinstall": "patch-package"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@proposal-system/api-contracts": "file:../shared/api-contracts",
|
"@proposal-system/api-contracts": "file:../shared/api-contracts",
|
||||||
|
|
@ -17,6 +18,7 @@
|
||||||
"@react-navigation/native-stack": "^7.2.0",
|
"@react-navigation/native-stack": "^7.2.0",
|
||||||
"@reduxjs/toolkit": "^2.11.2",
|
"@reduxjs/toolkit": "^2.11.2",
|
||||||
"@tanstack/react-query": "^5.100.10",
|
"@tanstack/react-query": "^5.100.10",
|
||||||
|
"amazon-cognito-identity-js": "^6.3.0",
|
||||||
"axios": "^1.16.0",
|
"axios": "^1.16.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-native": "^0.85.3",
|
"react-native": "^0.85.3",
|
||||||
|
|
@ -39,6 +41,7 @@
|
||||||
"@react-native/metro-config": "^0.85.3",
|
"@react-native/metro-config": "^0.85.3",
|
||||||
"@types/react": "^19.0.0",
|
"@types/react": "^19.0.0",
|
||||||
"@types/react-native-vector-icons": "^6.4.18",
|
"@types/react-native-vector-icons": "^6.4.18",
|
||||||
|
"patch-package": "^8.0.1",
|
||||||
"typescript": "~5.7.0"
|
"typescript": "~5.7.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
65
mobile/patches/@react-native-community+netinfo+12.0.1.patch
Normal file
65
mobile/patches/@react-native-community+netinfo+12.0.1.patch
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
diff --git a/node_modules/@react-native-community/netinfo/ios/RNCConnectionState.m b/node_modules/@react-native-community/netinfo/ios/RNCConnectionState.m
|
||||||
|
index 5a807a4..94e53f8 100644
|
||||||
|
--- a/node_modules/@react-native-community/netinfo/ios/RNCConnectionState.m
|
||||||
|
+++ b/node_modules/@react-native-community/netinfo/ios/RNCConnectionState.m
|
||||||
|
@@ -47,24 +47,28 @@
|
||||||
|
_expensive = true;
|
||||||
|
|
||||||
|
CTTelephonyNetworkInfo *netinfo = [[CTTelephonyNetworkInfo alloc] init];
|
||||||
|
- if (netinfo) {
|
||||||
|
- if ([netinfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyGPRS] ||
|
||||||
|
- [netinfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyEdge] ||
|
||||||
|
- [netinfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMA1x]) {
|
||||||
|
+ if (netinfo && [netinfo respondsToSelector:@selector(currentRadioAccessTechnology)]) {
|
||||||
|
+#pragma clang diagnostic push
|
||||||
|
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
+ NSString *radio = netinfo.currentRadioAccessTechnology;
|
||||||
|
+#pragma clang diagnostic pop
|
||||||
|
+ if ([radio isEqualToString:CTRadioAccessTechnologyGPRS] ||
|
||||||
|
+ [radio isEqualToString:CTRadioAccessTechnologyEdge] ||
|
||||||
|
+ [radio isEqualToString:CTRadioAccessTechnologyCDMA1x]) {
|
||||||
|
_cellularGeneration = RNCCellularGeneration2g;
|
||||||
|
- } else if ([netinfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyWCDMA] ||
|
||||||
|
- [netinfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyHSDPA] ||
|
||||||
|
- [netinfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyHSUPA] ||
|
||||||
|
- [netinfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORev0] ||
|
||||||
|
- [netinfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevA] ||
|
||||||
|
- [netinfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevB] ||
|
||||||
|
- [netinfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyeHRPD]) {
|
||||||
|
+ } else if ([radio isEqualToString:CTRadioAccessTechnologyWCDMA] ||
|
||||||
|
+ [radio isEqualToString:CTRadioAccessTechnologyHSDPA] ||
|
||||||
|
+ [radio isEqualToString:CTRadioAccessTechnologyHSUPA] ||
|
||||||
|
+ [radio isEqualToString:CTRadioAccessTechnologyCDMAEVDORev0] ||
|
||||||
|
+ [radio isEqualToString:CTRadioAccessTechnologyCDMAEVDORevA] ||
|
||||||
|
+ [radio isEqualToString:CTRadioAccessTechnologyCDMAEVDORevB] ||
|
||||||
|
+ [radio isEqualToString:CTRadioAccessTechnologyeHRPD]) {
|
||||||
|
_cellularGeneration = RNCCellularGeneration3g;
|
||||||
|
- } else if ([netinfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyLTE]) {
|
||||||
|
+ } else if ([radio isEqualToString:CTRadioAccessTechnologyLTE]) {
|
||||||
|
_cellularGeneration = RNCCellularGeneration4g;
|
||||||
|
} else if (@available(iOS 14.1, *)) {
|
||||||
|
- if ([netinfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyNRNSA] ||
|
||||||
|
- [netinfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyNR]) {
|
||||||
|
+ if ([radio isEqualToString:CTRadioAccessTechnologyNRNSA] ||
|
||||||
|
+ [radio isEqualToString:CTRadioAccessTechnologyNR]) {
|
||||||
|
_cellularGeneration = RNCCellularGeneration5g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/node_modules/@react-native-community/netinfo/ios/RNCNetInfo.mm b/node_modules/@react-native-community/netinfo/ios/RNCNetInfo.mm
|
||||||
|
index baa2de0..6b75224 100644
|
||||||
|
--- a/node_modules/@react-native-community/netinfo/ios/RNCNetInfo.mm
|
||||||
|
+++ b/node_modules/@react-native-community/netinfo/ios/RNCNetInfo.mm
|
||||||
|
@@ -190,7 +190,13 @@ RCT_EXPORT_METHOD(configure:(NSDictionary *)config)
|
||||||
|
return nil;
|
||||||
|
#else
|
||||||
|
CTTelephonyNetworkInfo *netinfo = [[CTTelephonyNetworkInfo alloc] init];
|
||||||
|
+ if (![netinfo respondsToSelector:@selector(subscriberCellularProvider)]) {
|
||||||
|
+ return nil;
|
||||||
|
+ }
|
||||||
|
+#pragma clang diagnostic push
|
||||||
|
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
CTCarrier *carrier = [netinfo subscriberCellularProvider];
|
||||||
|
+#pragma clang diagnostic pop
|
||||||
|
return carrier.carrierName;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
@ -2,9 +2,9 @@ const Config = {
|
||||||
API_URL: __DEV__
|
API_URL: __DEV__
|
||||||
? 'http://localhost:5000/api'
|
? 'http://localhost:5000/api'
|
||||||
: 'https://api.proposals.seahaven.com/api',
|
: 'https://api.proposals.seahaven.com/api',
|
||||||
COGNITO_DOMAIN: 'proposal-system.auth.us-east-1.amazoncognito.com',
|
COGNITO_DOMAIN: 'proposal-system-seahaven.auth.us-east-1.amazoncognito.com',
|
||||||
COGNITO_CLIENT_ID: '',
|
COGNITO_CLIENT_ID: '3egjbljml6o9qg3q155t784018',
|
||||||
COGNITO_USER_POOL_ID: '',
|
COGNITO_USER_POOL_ID: 'us-east-1_DfWcl2q5z',
|
||||||
COGNITO_REDIRECT_URI: 'com.seahavenind.proposals://auth/callback',
|
COGNITO_REDIRECT_URI: 'com.seahavenind.proposals://auth/callback',
|
||||||
COGNITO_SCOPES: ['openid', 'email', 'profile'],
|
COGNITO_SCOPES: ['openid', 'email', 'profile'],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { authorize, refresh, revoke } from 'react-native-app-auth';
|
import { authorize, refresh, revoke } from 'react-native-app-auth';
|
||||||
import Config from '../../config';
|
import Config from '../../config';
|
||||||
import apiClient from './client';
|
import apiClient from './client';
|
||||||
|
import { authenticateWithCredentials } from './cognito-auth';
|
||||||
import {
|
import {
|
||||||
tokenStorage,
|
tokenStorage,
|
||||||
userStorage,
|
userStorage,
|
||||||
|
|
@ -38,6 +39,25 @@ export const authApi = {
|
||||||
return profile;
|
return profile;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
loginWithCredentials: async (
|
||||||
|
email: string,
|
||||||
|
password: string,
|
||||||
|
): Promise<StoredUser> => {
|
||||||
|
const cognitoTokens = await authenticateWithCredentials(email, password);
|
||||||
|
|
||||||
|
const tokens: StoredTokens = {
|
||||||
|
accessToken: cognitoTokens.accessToken,
|
||||||
|
idToken: cognitoTokens.idToken,
|
||||||
|
refreshToken: cognitoTokens.refreshToken,
|
||||||
|
expiresAt: cognitoTokens.expiresAt,
|
||||||
|
};
|
||||||
|
await tokenStorage.save(tokens);
|
||||||
|
|
||||||
|
const profile = await authApi.getMe();
|
||||||
|
await userStorage.save(profile);
|
||||||
|
return profile;
|
||||||
|
},
|
||||||
|
|
||||||
refreshTokens: async (): Promise<void> => {
|
refreshTokens: async (): Promise<void> => {
|
||||||
const stored = await tokenStorage.get();
|
const stored = await tokenStorage.get();
|
||||||
if (!stored?.refreshToken) throw new Error('No refresh token');
|
if (!stored?.refreshToken) throw new Error('No refresh token');
|
||||||
|
|
|
||||||
68
mobile/src/lib/api/cognito-auth.ts
Normal file
68
mobile/src/lib/api/cognito-auth.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
import type { CognitoUserSession } from 'amazon-cognito-identity-js';
|
||||||
|
import Config from '../../config';
|
||||||
|
|
||||||
|
export interface CognitoTokens {
|
||||||
|
accessToken: string;
|
||||||
|
idToken: string;
|
||||||
|
refreshToken: string;
|
||||||
|
expiresAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractTokens(session: CognitoUserSession): CognitoTokens {
|
||||||
|
const accessToken = session.getAccessToken();
|
||||||
|
return {
|
||||||
|
accessToken: accessToken.getJwtToken(),
|
||||||
|
idToken: session.getIdToken().getJwtToken(),
|
||||||
|
refreshToken: session.getRefreshToken().getToken(),
|
||||||
|
expiresAt: new Date(accessToken.getExpiration() * 1000).toISOString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function authenticateWithCredentials(
|
||||||
|
email: string,
|
||||||
|
password: string,
|
||||||
|
): Promise<CognitoTokens> {
|
||||||
|
// Lazy-load to keep amazon-cognito-identity-js out of the startup module graph
|
||||||
|
const {
|
||||||
|
CognitoUserPool,
|
||||||
|
CognitoUser,
|
||||||
|
AuthenticationDetails,
|
||||||
|
} = await import('amazon-cognito-identity-js');
|
||||||
|
|
||||||
|
const userPool = new CognitoUserPool({
|
||||||
|
UserPoolId: Config.COGNITO_USER_POOL_ID,
|
||||||
|
ClientId: Config.COGNITO_CLIENT_ID,
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const cognitoUser = new CognitoUser({
|
||||||
|
Username: email,
|
||||||
|
Pool: userPool,
|
||||||
|
});
|
||||||
|
|
||||||
|
const authDetails = new AuthenticationDetails({
|
||||||
|
Username: email,
|
||||||
|
Password: password,
|
||||||
|
});
|
||||||
|
|
||||||
|
cognitoUser.authenticateUser(authDetails, {
|
||||||
|
onSuccess: (session) => {
|
||||||
|
resolve(extractTokens(session));
|
||||||
|
},
|
||||||
|
onFailure: (err) => {
|
||||||
|
if (err.code === 'NotAuthorizedException') {
|
||||||
|
reject(new Error('Incorrect email or password.'));
|
||||||
|
} else if (err.code === 'UserNotFoundException') {
|
||||||
|
reject(new Error('No account found with that email.'));
|
||||||
|
} else if (err.code === 'UserNotConfirmedException') {
|
||||||
|
reject(new Error('Account not confirmed. Contact your administrator.'));
|
||||||
|
} else {
|
||||||
|
reject(new Error(err.message || 'Authentication failed.'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
newPasswordRequired: () => {
|
||||||
|
reject(new Error('Password change required. Contact your administrator.'));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -1,23 +1,67 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { View, StyleSheet } from 'react-native';
|
import {
|
||||||
import { Button, Text, Surface } from 'react-native-paper';
|
View,
|
||||||
|
StyleSheet,
|
||||||
|
KeyboardAvoidingView,
|
||||||
|
Platform,
|
||||||
|
ScrollView,
|
||||||
|
} from 'react-native';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Text,
|
||||||
|
Surface,
|
||||||
|
TextInput,
|
||||||
|
Divider,
|
||||||
|
HelperText,
|
||||||
|
} from 'react-native-paper';
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { authApi } from '../../lib/api/auth';
|
import { authApi } from '../../lib/api/auth';
|
||||||
import { setUser, setError } from '../../store/slices/authSlice';
|
import { setUser, setError, clearError } from '../../store/slices/authSlice';
|
||||||
|
|
||||||
export function LoginScreen() {
|
export function LoginScreen() {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [email, setEmail] = useState('');
|
||||||
|
const [password, setPassword] = useState('');
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
const [localError, setLocalError] = useState('');
|
||||||
|
|
||||||
const handleLogin = async () => {
|
const handleGoogleLogin = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
setLocalError('');
|
||||||
|
dispatch(clearError());
|
||||||
try {
|
try {
|
||||||
const user = await authApi.login();
|
const user = await authApi.login();
|
||||||
dispatch(setUser(user));
|
dispatch(setUser(user));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const message =
|
const message =
|
||||||
err instanceof Error ? err.message : 'Login failed. Please try again.';
|
err instanceof Error ? err.message : 'Login failed. Please try again.';
|
||||||
|
setLocalError(message);
|
||||||
|
dispatch(setError(message));
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCredentialLogin = async () => {
|
||||||
|
if (!email.trim() || !password) {
|
||||||
|
setLocalError('Email and password are required.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setLoading(true);
|
||||||
|
setLocalError('');
|
||||||
|
dispatch(clearError());
|
||||||
|
try {
|
||||||
|
const user = await authApi.loginWithCredentials(
|
||||||
|
email.trim().toLowerCase(),
|
||||||
|
password,
|
||||||
|
);
|
||||||
|
dispatch(setUser(user));
|
||||||
|
} catch (err) {
|
||||||
|
const message =
|
||||||
|
err instanceof Error ? err.message : 'Login failed. Please try again.';
|
||||||
|
setLocalError(message);
|
||||||
dispatch(setError(message));
|
dispatch(setError(message));
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
@ -26,28 +70,92 @@ export function LoginScreen() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
<View style={styles.content}>
|
<KeyboardAvoidingView
|
||||||
<Surface style={styles.logoContainer} elevation={0}>
|
style={styles.flex}
|
||||||
<Text variant="headlineLarge" style={styles.brand}>
|
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||||
Sea Haven
|
>
|
||||||
</Text>
|
<ScrollView
|
||||||
<Text variant="titleMedium" style={styles.brandSub}>
|
contentContainerStyle={styles.content}
|
||||||
Industries
|
keyboardShouldPersistTaps="handled"
|
||||||
</Text>
|
>
|
||||||
</Surface>
|
<Surface style={styles.logoContainer} elevation={0}>
|
||||||
|
<Text variant="headlineLarge" style={styles.brand}>
|
||||||
|
Sea Haven
|
||||||
|
</Text>
|
||||||
|
<Text variant="titleMedium" style={styles.brandSub}>
|
||||||
|
Industries
|
||||||
|
</Text>
|
||||||
|
</Surface>
|
||||||
|
|
||||||
<Text variant="headlineSmall" style={styles.title}>
|
<Text variant="headlineSmall" style={styles.title}>
|
||||||
Proposal System
|
Proposal System
|
||||||
</Text>
|
</Text>
|
||||||
<Text variant="bodyLarge" style={styles.subtitle}>
|
<Text variant="bodyLarge" style={styles.subtitle}>
|
||||||
Submit and manage proposals from anywhere
|
Submit and manage proposals from anywhere
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
|
<View style={styles.form}>
|
||||||
|
<TextInput
|
||||||
|
label="Email"
|
||||||
|
value={email}
|
||||||
|
onChangeText={setEmail}
|
||||||
|
autoCapitalize="none"
|
||||||
|
autoComplete="email"
|
||||||
|
keyboardType="email-address"
|
||||||
|
textContentType="emailAddress"
|
||||||
|
mode="outlined"
|
||||||
|
disabled={loading}
|
||||||
|
style={styles.input}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label="Password"
|
||||||
|
value={password}
|
||||||
|
onChangeText={setPassword}
|
||||||
|
secureTextEntry={!showPassword}
|
||||||
|
autoCapitalize="none"
|
||||||
|
autoComplete="password"
|
||||||
|
textContentType="password"
|
||||||
|
mode="outlined"
|
||||||
|
disabled={loading}
|
||||||
|
style={styles.input}
|
||||||
|
right={
|
||||||
|
<TextInput.Icon
|
||||||
|
icon={showPassword ? 'eye-off' : 'eye'}
|
||||||
|
onPress={() => setShowPassword(!showPassword)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{localError ? (
|
||||||
|
<HelperText type="error" visible>
|
||||||
|
{localError}
|
||||||
|
</HelperText>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
mode="contained"
|
||||||
|
onPress={handleCredentialLogin}
|
||||||
|
loading={loading}
|
||||||
|
disabled={loading}
|
||||||
|
contentStyle={styles.buttonContent}
|
||||||
|
style={styles.button}
|
||||||
|
>
|
||||||
|
Sign In
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.dividerRow}>
|
||||||
|
<Divider style={styles.dividerLine} />
|
||||||
|
<Text variant="bodySmall" style={styles.dividerText}>
|
||||||
|
OR
|
||||||
|
</Text>
|
||||||
|
<Divider style={styles.dividerLine} />
|
||||||
|
</View>
|
||||||
|
|
||||||
<View style={styles.actions}>
|
|
||||||
<Button
|
<Button
|
||||||
mode="contained"
|
mode="outlined"
|
||||||
icon="google"
|
icon="google"
|
||||||
onPress={handleLogin}
|
onPress={handleGoogleLogin}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
contentStyle={styles.buttonContent}
|
contentStyle={styles.buttonContent}
|
||||||
|
|
@ -55,12 +163,12 @@ export function LoginScreen() {
|
||||||
>
|
>
|
||||||
Sign in with Google
|
Sign in with Google
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
|
||||||
|
|
||||||
<Text variant="bodySmall" style={styles.footer}>
|
<Text variant="bodySmall" style={styles.footer}>
|
||||||
Use your Sea Haven Workspace account
|
Use your Sea Haven email to sign in
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</ScrollView>
|
||||||
|
</KeyboardAvoidingView>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -70,11 +178,15 @@ const styles = StyleSheet.create({
|
||||||
flex: 1,
|
flex: 1,
|
||||||
backgroundColor: '#FAFAFA',
|
backgroundColor: '#FAFAFA',
|
||||||
},
|
},
|
||||||
content: {
|
flex: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
flexGrow: 1,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
paddingHorizontal: 32,
|
paddingHorizontal: 32,
|
||||||
|
paddingVertical: 24,
|
||||||
},
|
},
|
||||||
logoContainer: {
|
logoContainer: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
|
@ -97,16 +209,33 @@ const styles = StyleSheet.create({
|
||||||
subtitle: {
|
subtitle: {
|
||||||
color: '#757575',
|
color: '#757575',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
marginBottom: 48,
|
marginBottom: 32,
|
||||||
},
|
},
|
||||||
actions: {
|
form: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
},
|
},
|
||||||
|
input: {
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
buttonContent: {
|
buttonContent: {
|
||||||
paddingVertical: 8,
|
paddingVertical: 8,
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
dividerRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
width: '100%',
|
||||||
|
marginVertical: 20,
|
||||||
|
},
|
||||||
|
dividerLine: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
dividerText: {
|
||||||
|
color: '#9E9E9E',
|
||||||
|
marginHorizontal: 16,
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
color: '#9E9E9E',
|
color: '#9E9E9E',
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue