Browse Source

revert BUILDING to master version

streamline-attempt
Matthew Raymer 1 week ago
parent
commit
f82e3d4590
  1. 733
      BUILDING.md

733
BUILDING.md

@ -1,6 +1,6 @@
# Building TimeSafari
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` |
| `capacitor-build.sh` | Capacitor build | `./scripts/build-capacitor.sh` |
| `web-dev.sh` | Web development | `./scripts/web-dev.sh` |
| `web-build.sh` | Web build | `./scripts/build-web.sh` |
### Environment Variables
All scripts automatically set the correct environment variables for their build type:
| Build Type | VITE_PLATFORM | VITE_PWA_ENABLED | VITE_DISABLE_PWA | NODE_ENV |
|------------|---------------|------------------|------------------|----------|
| `capacitor` | capacitor | false | true | - |
| `web` | web | true | false | - |
### CLI Options
All scripts support these options:
```bash
# Show help
./scripts/build-capacitor.sh --help
# Enable verbose logging
./scripts/build-capacitor.sh --verbose
# Show environment variables
./scripts/build-capacitor.sh --env
```
- For desktop builds: Additional build tools based on your OS
## Forks
@ -77,104 +30,18 @@ Install dependencies:
npm install
```
## Package Management
TimeSafari uses a mixed package management approach, combining npm and JSR (JavaScript Registry) for optimal dependency management.
### JSR Integration
Some packages are installed via JSR for better ESM support and modern TypeScript compatibility:
```bash
# Install JSR packages
npx jsr add @nostr/tools
```
### Package Migration History
#### nostr-tools → @nostr/tools
**Date**: June 2025
**Reason**: Resolved Vite/Rollup build issues with deep imports
**Before** (npm):
```typescript
import { finalizeEvent } from "nostr-tools/lib/cjs/index.js";
import { accountFromExtendedKey } from "nostr-tools/lib/cjs/nip06.js";
```
**After** (JSR):
```typescript
import { finalizeEvent } from "@nostr/tools";
import { accountFromExtendedKey } from "@nostr/tools/nip06";
```
**Benefits**:
- ✅ Proper ESM support
- ✅ No deep import issues with Vite/Rollup
- ✅ Better TypeScript compatibility
- ✅ Modern package structure
### Current Package Strategy
- **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
### When to Use JSR
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
### Vite Configuration
The build system is configured to handle both npm and JSR packages:
```typescript
// vite.config.common.mts
resolve: {
alias: {
'@nostr/tools': path.resolve(__dirname, 'node_modules/@nostr/tools'),
'@nostr/tools/nip06': path.resolve(__dirname, 'node_modules/@nostr/tools/nip06'),
}
}
```
### Troubleshooting Package Issues
1. **Build failures with deep imports**
- Check if package has ESM/CJS compatibility issues
- Consider JSR alternative if available
- Update Vite configuration if needed
2. **TypeScript errors**
- Ensure proper type definitions are available
- Check package exports in package.json
- Verify import paths match package structure
3. **Mixed package manager issues**
- Keep package.json and node_modules in sync
- Use `npm install` after JSR package additions
- Check for conflicting package versions
## Web Development
### Local Development
## Web Dev Locally
```bash
npm run dev
```
### Web Build for Server
## Web Build for Server
1. Run the production build:
```bash
rm -rf dist
npm run build:web
```
@ -182,278 +49,57 @@ resolve: {
2. To test the production build locally:
```bash
npm run serve
```
### Environment Configuration
For different environments, create `.env` files:
```bash
# .env.development
VITE_APP_SERVER=https://dev.timesafari.app
VITE_DEFAULT_ENDORSER_API_SERVER=https://dev-api.endorser.ch
VITE_DEFAULT_IMAGE_API_SERVER=https://dev-image-api.timesafari.app
VITE_DEFAULT_PARTNER_API_SERVER=https://dev-partner-api.endorser.ch
VITE_DEFAULT_PUSH_SERVER=https://dev.timesafari.app
VITE_PASSKEYS_ENABLED=true
# .env.production
VITE_APP_SERVER=https://timesafari.app
VITE_DEFAULT_ENDORSER_API_SERVER=https://api.endorser.ch
VITE_DEFAULT_IMAGE_API_SERVER=https://image-api.timesafari.app
VITE_DEFAULT_PARTNER_API_SERVER=https://partner-api.endorser.ch
VITE_DEFAULT_PUSH_SERVER=https://timesafari.app
VITE_PASSKEYS_ENABLED=true
```
## Desktop Build (Capacitor Electron)
### Prerequisites
1. Install Capacitor CLI:
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.
```bash
npm install -g @capacitor/cli
```
2. Add Electron platform:
```bash
npx cap add electron
npm run serve
```
### Development
For development with automatic environment setup:
```bash
# Build web assets
npm run build:capacitor
# Sync with Capacitor
npx cap sync electron
# Open in Electron
npx cap open electron
```
### Production Build
For production builds:
### Compile and minify for test & production
```bash
# Build web assets
npm run build:capacitor
* If there are DB changes: before updating the test server, open browser(s) with current version to test DB migrations.
# Sync with Capacitor
npx cap sync electron
* `npx prettier --write ./sw_scripts/`
# Build Electron app
npx cap build electron
```
* Update the ClickUp tasks & CHANGELOG.md & the version in package.json, run `npm install`.
### Packaging
Capacitor Electron uses electron-builder for packaging. Configure the build in `capacitor.config.json`:
```json
{
"plugins": {
"ElectronBuilder": {
"buildOptions": {
"appId": "app.timesafari.app",
"productName": "TimeSafari",
"directories": {
"output": "dist-electron-packages"
},
"files": [
"dist/**/*",
"electron/**/*"
],
"linux": {
"target": ["AppImage", "deb"],
"category": "Office"
},
"mac": {
"target": ["dmg", "zip"],
"category": "public.app-category.productivity"
},
"win": {
"target": ["nsis", "portable"]
}
}
}
}
}
```
### Running the Packaged App
* Run a build to make sure package-lock version is updated, linting works, etc: `npm install && npm run build`
- **Linux**: AppImage files are self-contained executables
- **macOS**: `.app` bundles can be dragged to Applications folder
- **Windows**: `.exe` installers or portable executables
## Mobile Builds (Capacitor)
### Android Build
* Commit everything (since the commit hash is used the app).
Prerequisites: Android Studio with Java SDK installed
* Put the commit hash in the changelog (which will help you remember to bump the version in the step later).
#### Complete Build Process
* 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`.
Use the unified Android build script:
* For test, build the app (because test server is not yet set up to build):
```bash
./scripts/build-android.sh
TIME_SAFARI_APP_TITLE="TimeSafari_Test" VITE_APP_SERVER=https://test.timesafari.app VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F VITE_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app VITE_DEFAULT_PARTNER_API_SERVER=https://test-partner-api.endorser.ch VITE_DEFAULT_PUSH_SERVER=https://test.timesafari.app VITE_PASSKEYS_ENABLED=true npm run build:web
```
This script automatically:
1. Sets up environment variables for Capacitor
2. Cleans previous builds
3. Builds web assets
4. Builds Capacitor version
5. Cleans and builds Gradle project
6. Syncs with Capacitor
7. Generates assets
8. Opens Android Studio
#### Manual Steps (if needed)
If you need to run individual steps:
1. Build the web assets:
```bash
npm run build:web
npm run build:capacitor
```
2. Update Android project:
```bash
npx cap sync android
```
... and transfer to the test server:
3. Generate assets:
```bash
npx capacitor-assets generate --android
```
4. Open in Android Studio:
```bash
npx cap open android
rsync -azvu -e "ssh -i ~/.ssh/..." dist ubuntutest@test.timesafari.app:time-safari
```
#### Console Build
(Let's replace that with a .env.development or .env.staging file.)
For building from the console:
(Note: The test BVC_MEETUPS_PROJECT_CLAIM_ID does not resolve as a URL because it's only in the test DB and the prod redirect won't redirect there.)
```bash
cd android
./gradlew clean
./gradlew build -Dlint.baselines.continue=true
cd -
```
For creating an `aab` file:
* For prod, get on the server and run the correct build:
```bash
cd android
./gradlew bundleDebug -Dlint.baselines.continue=true
cd -
```
For creating a signed release:
1. Setup signing configuration in `app/gradle.properties.secrets`
2. Add signing key file `app/time-safari-upload-key-pkcs12.jks`
3. Update version in `app/build.gradle`
4. Build release:
```bash
cd android
./gradlew bundleRelease -Dlint.baselines.continue=true
cd -
```
The `aab` file will be at `app/build/outputs/bundle/release`.
### iOS Build
Prerequisites: macOS with Xcode installed
#### First-time iOS Configuration
- Generate certificates inside Xcode
- Right-click on App and under Signing & Capabilities set the Team
#### Build Process
1. Build the web assets & update iOS:
```bash
npm run build:web
npm run build:capacitor
npx cap sync ios
```
2. Generate assets:
```bash
# Create required directories
mkdir -p ios/App/App/Assets.xcassets/AppIcon.appiconset
echo '{"images":[]}' > ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json
mkdir -p ios/App/App/Assets.xcassets/Splash.imageset
echo '{"images":[]}' > ios/App/App/Assets.xcassets/Splash.imageset/Contents.json
# Generate assets
npx capacitor-assets generate --ios
```
3. Update version to match Android & package.json:
```bash
cd ios/App
xcrun agvtool new-version 35
perl -p -i -e "s/MARKETING_VERSION = .*;/MARKETING_VERSION = 1.0.2;/g" App.xcodeproj/project.pbxproj
cd -
```
4. Open in Xcode:
```bash
npx cap open ios
```
... and log onto the server:
5. Build and run on simulator or device using Xcode
* `pkgx +npm sh`
#### Release Process
* `cd crowd-funder-for-time-pwa && git checkout master && git pull && git checkout 1.0.2 && npm install && npm run build:web && cd -`
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
(The plain `npm run build:web` uses the .env.production file.)
## Testing
* 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/`
### Complete Test Suite
Run all tests with automatic environment setup:
```bash
./scripts/test-all.sh
```
### Mobile Tests
Run mobile-specific tests:
```bash
./scripts/test-mobile.sh
```
### Environment Testing
Test environment variable handling:
```bash
./scripts/test-env.sh
```
* 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.
## Docker Deployment
@ -556,111 +202,280 @@ docker run -d \
- Check nginx configuration
- Verify caching settings
## Configuration
## Desktop Build (Electron)
### Deep Links
### Linux Build
#### Android Configuration
1. Build the electron app in production mode:
You must add the following intent filter to the `android/app/src/main/AndroidManifest.xml` file:
```bash
npm run build:electron-prod
```
```xml
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="timesafari" />
</intent-filter>
2. Package the Electron app for Linux:
```bash
# For AppImage (recommended)
npm run electron:build-linux
# For .deb package
npm run electron:build-linux-deb
```
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.
3. The packaged applications will be in `dist-electron-packages/`:
- AppImage: `dist-electron-packages/TimeSafari-x.x.x.AppImage`
- DEB: `dist-electron-packages/timesafari_x.x.x_amd64.deb`
#### iOS Configuration
### macOS Build
For iOS deep links, configure the URL scheme in Xcode:
1. Build the electron app in production mode:
1. Open the project in Xcode
2. Select your app target
3. Go to Info tab
4. Add URL Types with scheme `timesafari`
```bash
npm run build:web
npm run build:electron
npm run electron:build-mac
```
## Troubleshooting
2. Package the Electron app for macOS:
### Common Issues
```bash
# For Intel Macs
npm run electron:build-mac
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
# For Universal build (Intel + Apple Silicon)
npm run electron:build-mac-universal
```
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. The packaged applications will be in `dist-electron-packages/`:
- `.app` bundle: `TimeSafari.app`
- `.dmg` installer: `TimeSafari-x.x.x.dmg`
- `.zip` archive: `TimeSafari-x.x.x-mac.zip`
3. **Permission Issues**
- Make scripts executable: `chmod +x scripts/*.sh`
- Check file permissions on build directories
### Code Signing and Notarization (macOS)
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
For public distribution on macOS, you need to code sign and notarize your app:
### Getting Help
1. Set up environment variables:
```bash
export CSC_LINK=/path/to/your/certificate.p12
export CSC_KEY_PASSWORD=your_certificate_password
export APPLE_ID=your_apple_id
export APPLE_ID_PASSWORD=your_app_specific_password
```
- Check script help: `./scripts/build-capacitor.sh --help`
- Review script documentation in `scripts/README.md`
- Test environment setup: `./scripts/test-env.sh`
- Test common utilities: `./scripts/test-common.sh`
2. Build with signing:
```bash
npm run electron:build-mac
```
### Platform Support Matrix
### Running the Packaged App
| Platform | Mode | PWA Enabled | Native Features | Notes |
|----------|------|-------------|-----------------|-------|
| `web` | web | true | false | Standard web browser |
| `capacitor` | capacitor | false | true | Mobile app (iOS/Android) |
| `electron` | capacitor | false | true | Desktop app (via Capacitor Electron) |
- **Linux**:
- AppImage: Make executable and run
```bash
chmod +x dist-electron-packages/TimeSafari-*.AppImage
./dist-electron-packages/TimeSafari-*.AppImage
```
- DEB: Install and run
```bash
sudo dpkg -i dist-electron-packages/timesafari_*_amd64.deb
timesafari
```
- **macOS**:
- `.app` bundle: Double-click `TimeSafari.app` in Finder
- `.dmg` installer:
1. Double-click the `.dmg` file
2. Drag the app to your Applications folder
3. Launch from Applications
- `.zip` archive:
1. Extract the `.zip` file
2. Move `TimeSafari.app` to your Applications folder
3. Launch from Applications
Note: If you get a security warning when running the app:
1. Right-click the app
2. Select "Open"
3. Click "Open" in the security dialog
### Development Testing
For testing the Electron build before packaging:
## Platform Service Architecture
```bash
# Build and run in development mode (includes DevTools)
npm run electron:dev
TimeSafari uses a unified platform service architecture that works across all platforms:
# Build in production mode and test
npm run build:electron-prod && npm run electron:start
```
### Platform Detection
## Mobile Builds (Capacitor)
The `CapacitorPlatformService` automatically detects the platform and adjusts capabilities:
### iOS Build
```typescript
getCapabilities(): PlatformCapabilities {
const platform = Capacitor.getPlatform();
const isElectron = platform === "electron";
Prerequisites: macOS with Xcode installed
return {
hasFileSystem: true,
hasCamera: true,
isMobile: !isElectron, // false for Electron, true for mobile
isIOS: platform === "ios",
hasFileDownload: isElectron, // Electron can download files directly
needsFileHandlingInstructions: !isElectron, // Mobile needs instructions
isNativeApp: true,
};
}
```
#### First-time iOS Configuration
- Generate certificates inside XCode.
### Unified Database Layer
- Right-click on App and under Signing & Capabilities set the Team.
All platforms use the same SQLite database through Capacitor plugins:
#### Each Release
- **Mobile**: `@capacitor-community/sqlite` plugin
- **Desktop**: Same plugin via Capacitor Electron
- **Web**: IndexedDB fallback with absurd-sql
0. First time (or if dependencies change):
- `pkgx +rubygems.org sh`
- ... and you may have to fix these, especially with pkgx:
```bash
gem_path=$(which gem)
shortened_path="${gem_path:h:h}"
export GEM_HOME=$shortened_path
export GEM_PATH=$shortened_path
```
1. Build the web assets & update ios:
```bash
rm -rf dist
npm run build:web
npm run build:capacitor
npx cap sync ios
```
- If that fails with "Could not find..." then look at the "gem_path" instructions above.
3. Copy the assets:
```bash
# It makes no sense why capacitor-assets will not run without these but it actually changes the contents.
mkdir -p ios/App/App/Assets.xcassets/AppIcon.appiconset
echo '{"images":[]}' > ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json
mkdir -p ios/App/App/Assets.xcassets/Splash.imageset
echo '{"images":[]}' > ios/App/App/Assets.xcassets/Splash.imageset/Contents.json
npx capacitor-assets generate --ios
```
4. Bump the version to match Android & package.json:
```
cd ios/App && xcrun agvtool new-version 35 && perl -p -i -e "s/MARKETING_VERSION = .*;/MARKETING_VERSION = 1.0.2;/g" App.xcodeproj/project.pbxproj && cd -
# Unfortunately this edits Info.plist directly.
#xcrun agvtool new-marketing-version 0.4.5
```
### Feature Parity
5. Open the project in Xcode:
The same Capacitor plugins work across all platforms:
```bash
npx cap open ios
```
6. Use Xcode to build and run on simulator or device.
* Select Product -> Destination with some Simulator version. Then click the run arrow.
7. Release
* 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".
### Android Build
Prerequisites: Android Studio with Java SDK installed
1. Build the web assets:
```bash
rm -rf dist
npm run build:web
npm run build:capacitor
```
2. Update Android project with latest build:
```bash
npx cap sync android
```
3. Copy the assets
```bash
npx capacitor-assets generate --android
```
4. Bump version to match iOS & package.json: android/app/build.gradle
5. Open the project in Android Studio:
```bash
npx cap open android
```
6. Use Android Studio to build and run on emulator or device.
## Android Build from the console
```bash
cd android
./gradlew clean
./gradlew build -Dlint.baselines.continue=true
cd -
```
... or, to create the `aab` file, `bundle` instead of `build`:
```bash
./gradlew bundleDebug -Dlint.baselines.continue=true
```
... or, to create a signed release:
* 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
* Then `bundleRelease`:
```bash
cd android
./gradlew bundleRelease -Dlint.baselines.continue=true
cd -
```
... and find your `aab` file at app/build/outputs/bundle/release
At play.google.com/console:
- 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".
- 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.
## Android Configuration for deep links
You must add the following intent filter to the `android/app/src/main/AndroidManifest.xml` file:
```xml
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="timesafari" />
</intent-filter>
```
- 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]

Loading…
Cancel
Save