This guide explains how to build TimeSafari for different platforms using our unified build scripts.
This guide explains how to build TimeSafari for different platforms.
## Prerequisites
@ -9,54 +9,7 @@ For a quick dev environment setup, use [pkgx](https://pkgx.dev).
- Node.js (LTS version recommended)
- npm (comes with Node.js)
- Git
- For mobile builds: Android Studio (Android) or Xcode (iOS)
- For desktop builds: Capacitor Electron platform
## Unified Build Scripts
TimeSafari now uses unified build scripts that automatically handle environment variables, logging, error handling, and timing. All scripts are located in the `scripts/` directory and use a common utilities library.
### Script Features
- **Automatic Environment Setup**: Each script sets the correct environment variables for its build type
- **Rich Logging**: Colored, timestamped output with different log levels
- **Error Handling**: Proper exit codes and graceful failure recovery
- **Timing**: Automatic execution time tracking for each step
- **Validation**: Checks for required dependencies and files
- **CLI Options**: `--help`, `--verbose`, `--env` flags for all scripts
### Available Scripts
| Script | Purpose | Command |
|--------|---------|---------|
| `capacitor-dev.sh` | Capacitor development | `./scripts/capacitor-dev.sh` |
- For desktop builds: Additional build tools based on your OS
## Forks
@ -77,305 +30,287 @@ Install dependencies:
npm install
```
## Package Management
## Web Dev Locally
TimeSafari uses a mixed package management approach, combining npm and JSR (JavaScript Registry) for optimal dependency management.
```bash
npm run dev
```
### JSR Integration
## Web Build for Server
Some packages are installed via JSR for better ESM support and modern TypeScript compatibility:
1. Run the production build:
```bash
# Install JSR packages
npx jsr add @nostr/tools
rm -rf dist
npm run build:web
```
### Package Migration History
#### nostr-tools → @nostr/tools
The built files will be in the `dist` directory.
**Date**: June 2025
**Reason**: Resolved Vite/Rollup build issues with deep imports
2. To test the production build locally:
**Before** (npm):
You'll likely want to use test locations for the Endorser & image & partner servers; see "DEFAULT_ENDORSER_API_SERVER" & "DEFAULT_IMAGE_API_SERVER" & "DEFAULT_PARTNER_API_SERVER" below.
```typescript
import { finalizeEvent } from "nostr-tools/lib/cjs/index.js";
import { accountFromExtendedKey } from "nostr-tools/lib/cjs/nip06.js";
```bash
npm run serve
```
**After** (JSR):
### Compile and minify for test & production
```typescript
import { finalizeEvent } from "@nostr/tools";
import { accountFromExtendedKey } from "@nostr/tools/nip06";
```
* If there are DB changes: before updating the test server, open browser(s) with current version to test DB migrations.
**Benefits**:
- ✅ Proper ESM support
- ✅ No deep import issues with Vite/Rollup
- ✅ Better TypeScript compatibility
- ✅ Modern package structure
* `npx prettier --write ./sw_scripts/`
### Current Package Strategy
* Update the ClickUp tasks & CHANGELOG.md & the version in package.json, run `npm install`.
- **npm**: Primary package manager for most dependencies
- **JSR**: Used for packages with better ESM support or modern alternatives
- **Mixed approach**: Allows using the best package for each dependency
* Run a build to make sure package-lock version is updated, linting works, etc: `npm install && npm run build`
### When to Use JSR
* Commit everything (since the commit hash is used the app).
Consider using JSR for:
- Packages with ESM/CJS compatibility issues in npm
- Modern TypeScript-first packages
- Packages that work better with modern bundlers
- New dependencies where JSR has a better alternative
* Put the commit hash in the changelog (which will help you remember to bump the version in the step later).
### Vite Configuration
* Tag with the new version, [online](https://gitea.anomalistdesign.com/trent_larson/crowd-funder-for-time-pwa/releases) or `git tag 1.0.2 && git push origin 1.0.2`.
The build system is configured to handle both npm and JSR packages:
* For test, build the app (because test server is not yet set up to build):
(The plain `npm run build:web` uses the .env.production file.)
```bash
npm run build:web
```
* Back up the time-safari/dist folder & deploy: `mv time-safari/dist time-safari-dist-prev-2 && mv crowd-funder-for-time-pwa/dist time-safari/`
The built files will be in the `dist` directory.
* Record the new hash in the changelog. Edit package.json to increment version & add "-beta", `npm install`, commit, and push. Also record what version is on production.
2. To test the production build locally:
## Docker Deployment
```bash
npm run serve
```
The application can be containerized using Docker for consistent deployment across environments.
### Prerequisites
### Environment Configuration
- Docker installed on your system
- Docker Compose (optional, for multi-container setups)
6. Use Xcode to build and run on simulator or device.
Test environment variable handling:
* Select Product -> Destination with some Simulator version. Then click the run arrow.
```bash
./scripts/test-env.sh
```
7. Release
## Docker Deployment
* Someday: Under "General" we want to rename a bunch of things to "Time Safari"
* Choose Product -> Destination -> Any iOS Device
* Choose Product -> Archive
* This will trigger a build and take time, needing user's "login" keychain password (user's login password), repeatedly.
* If it fails with `building for 'iOS', but linking in dylib (.../.pkgx/zlib.net/v1.3.0/lib/libz.1.3.dylib) built for 'macOS'` then run XCode outside that terminal (ie. not with `npx cap open ios`).
* Click Distribute -> App Store Connect
* In AppStoreConnect, add the build to the distribution: remove the current build with the "-" when you hover over it, then "Add Build" with the new build.
* May have to go to App Review, click Submission, then hover over the build and click "-".
* It can take 15 minutes for the build to show up in the list of builds.
* You'll probably have to "Manage" something about encryption, disallowed in France.
* Then "Save" and "Add to Review" and "Resubmit to App Review".
The application can be containerized using Docker for consistent deployment across environments.
### Prerequisites
- Docker installed on your system
- Docker Compose (optional, for multi-container setups)
### Android Build
### Building the Docker Image
Prerequisites: Android Studio with Java SDK installed
1. Build the Docker image:
1. Build the web assets:
```bash
docker build -t timesafari:latest .
rm -rf dist
npm run build:web
npm run build:capacitor
```
2. For development builds with specific environment variables:
For production deployment, consider the following:
1. Use specific version tags instead of 'latest'
2. Implement health checks
3. Configure proper logging
4. Set up reverse proxy with SSL termination
5. Use Docker secrets for sensitive data
... or, to create a signed release:
Example production deployment:
* Setup by adding the app/gradle.properties.secrets file (see properties at top of app/build.gradle) and the app/time-safari-upload-key-pkcs12.jks file
* In app/build.gradle, bump the versionCode and maybe the versionName
... and find your `aab` file at app/build/outputs/bundle/release
2. **Build fails**
- Ensure all dependencies are in package.json
- Check Dockerfile syntax
- Verify build context
At play.google.com/console:
3. **Performance issues**
- Monitor container resources: `docker stats`
- Check nginx configuration
- Verify caching settings
- Go to the Testing Track (eg. Closed).
- Click "Create new release".
- Upload the `aab` file.
- Hit "Next".
- Save, go to "Publishing Overview" as prompted, and click "Send changes for review".
## Configuration
- Note that if you add testers, you have to go to "Publishing Overview" and send those changes or your (closed) testers won't see it.
### Deep Links
#### Android Configuration
## Android Configuration for deep links
You must add the following intent filter to the `android/app/src/main/AndroidManifest.xml` file:
@ -573,94 +478,4 @@ You must add the following intent filter to the `android/app/src/main/AndroidMan
</intent-filter>
```
Note: When using `timesafari://` scheme, you may encounter build errors about missing http(s) scheme and host attributes. This is expected for custom URL schemes.
#### iOS Configuration
For iOS deep links, configure the URL scheme in Xcode:
1. Open the project in Xcode
2. Select your app target
3. Go to Info tab
4. Add URL Types with scheme `timesafari`
## Troubleshooting
### Common Issues
1. **Environment Variables Not Set**
- Use `--env` flag to check current environment: `./scripts/build-capacitor.sh --env`
- Verify `.env` file exists and is properly formatted
- Check script output for environment setup messages
2. **Build Failures**
- Use `--verbose` flag for detailed logging: `./scripts/build-capacitor.sh --verbose`
- Check prerequisites are installed
- Verify all dependencies are installed: `npm install`
3. **Permission Issues**
- Make scripts executable: `chmod +x scripts/*.sh`
- Check file permissions on build directories
4. **Platform-Specific Issues**
- **Android**: Verify Android Studio and SDK are properly configured
- **iOS**: Ensure Xcode and certificates are set up correctly
- **Electron**: Check Capacitor Electron platform installation
The same Capacitor plugins work across all platforms:
- File system operations
- Camera access
- SQLite database
- Deep linking
- Sharing functionality
... though when we tried that most recently it failed to 'build' the APK with: http(s) scheme and host attribute are missing, but are required for Android App Links [AppLinkUrlError]