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
## Prerequisites
@ -9,54 +9,7 @@ For a quick dev environment setup, use [pkgx](https://pkgx.dev).
- Node.js (LTS version recommended)
- Node.js (LTS version recommended)
- npm (comes with Node.js)
- npm (comes with Node.js)
- Git
- Git
- For mobile builds: Android Studio (Android) or Xcode (iOS)
- For desktop builds: Additional build tools based on your OS
- 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` |
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
```bash
# Install JSR packages
rm -rf dist
npx jsr add @nostr/tools
npm run build:web
```
```
### Package Migration History
The built files will be in the `dist` directory.
#### nostr-tools → @nostr/tools
**Date**: June 2025
2. To test the production build locally:
**Reason**: Resolved Vite/Rollup build issues with deep imports
**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
```bash
import { finalizeEvent } from "nostr-tools/lib/cjs/index.js";
npm run serve
import { accountFromExtendedKey } from "nostr-tools/lib/cjs/nip06.js";
```
```
**After** (JSR):
### Compile and minify for test & production
```typescript
* If there are DB changes: before updating the test server, open browser(s) with current version to test DB migrations.
import { finalizeEvent } from "@nostr/tools";
import { accountFromExtendedKey } from "@nostr/tools/nip06";
```
**Benefits**:
* `npx prettier --write ./sw_scripts/`
- ✅ Proper ESM support
- ✅ No deep import issues with Vite/Rollup
- ✅ Better TypeScript compatibility
- ✅ Modern package structure
### Current Package Strategy
* Update the ClickUp tasks & CHANGELOG.md & the version in package.json, run `npm install`.
- **npm**: Primary package manager for most dependencies
* Run a build to make sure package-lock version is updated, linting works, etc: `npm install && npm run build`
- **JSR**: Used for packages with better ESM support or modern alternatives
- **Mixed approach**: Allows using the best package for each dependency
### When to Use JSR
* Commit everything (since the commit hash is used the app).
Consider using JSR for:
* Put the commit hash in the changelog (which will help you remember to bump the version in the step later).
- 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
### 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
* 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/`
npm run build:web
```
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
The application can be containerized using Docker for consistent deployment across environments.
npm run serve
```
### Prerequisites
### Environment Configuration
- Docker installed on your system
- Docker Compose (optional, for multi-container setups)
5. Build and run on simulator or device using Xcode
# Unfortunately this edits Info.plist directly.
#xcrun agvtool new-marketing-version 0.4.5
#### Release Process
1. Choose Product -> Destination -> Any iOS Device
2. Choose Product -> Archive
3. Click Distribute -> App Store Connect
4. In App Store Connect, add the build to the distribution
## Testing
### Complete Test Suite
Run all tests with automatic environment setup:
```bash
./scripts/test-all.sh
```
```
### Mobile Tests
5. Open the project in Xcode:
Run mobile-specific tests:
```bash
```bash
./scripts/test-mobile.sh
npx cap open ios
```
```
### Environment Testing
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
7. Release
./scripts/test-env.sh
```
## 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.
### Android Build
### Prerequisites
- Docker installed on your system
- Docker Compose (optional, for multi-container setups)
### Building the Docker Image
Prerequisites: Android Studio with Java SDK installed
1. Build the Docker image:
1. Build the web assets:
```bash
```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
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
1. **Container fails to start**
- Check logs: `docker logs <container_id>`
- Verify port availability
- Check environment variables
2. **Build fails**
At play.google.com/console:
- Ensure all dependencies are in package.json
- Check Dockerfile syntax
- Verify build context
3. **Performance issues**
- Go to the Testing Track (eg. Closed).
- Monitor container resources: `docker stats`
- Click "Create new release".
- Check nginx configuration
- Upload the `aab` file.
- Verify caching settings
- 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:
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>
</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.
... 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]
#### 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