create-react-native-airborne 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,6 +12,9 @@ bun create react-native-airborne my-app
12
12
 
13
13
  - `--skip-install`: skip `bun install --workspaces`
14
14
  - `--no-git`: skip `git init`
15
+ - `--nix`: include root-level `flake.nix`, `flake.lock`, and `.envrc`
16
+
17
+ If you use `--nix`, run `direnv allow` after `cd` into the generated project.
15
18
 
16
19
  ## Development
17
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-react-native-airborne",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "Scaffold a react-native-airborne starter project",
5
5
  "repository": {
6
6
  "type": "git",
package/src/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { mkdir, readdir, readFile, writeFile, copyFile, stat } from "node:fs/promises";
2
+ import { mkdir, readdir, readFile, writeFile, copyFile, rm, stat } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { spawnSync } from "node:child_process";
5
5
  import { fileURLToPath } from "node:url";
@@ -9,7 +9,9 @@ const flags = new Set(args.filter((arg) => arg.startsWith("--")));
9
9
  const projectNameArg = args.find((arg) => !arg.startsWith("--"));
10
10
 
11
11
  if (!projectNameArg) {
12
- console.error("Usage: bun create react-native-airborne <project-name> [--skip-install] [--no-git]");
12
+ console.error(
13
+ "Usage: bun create react-native-airborne <project-name> [--skip-install] [--no-git] [--nix]",
14
+ );
13
15
  process.exit(1);
14
16
  }
15
17
 
@@ -18,6 +20,7 @@ const projectSlug = projectName.toLowerCase().replace(/[^a-z0-9-]/g, "-").replac
18
20
  const targetDir = path.resolve(process.cwd(), projectName);
19
21
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
20
22
  const templateDir = path.resolve(__dirname, "../template");
23
+ const enableNix = flags.has("--nix");
21
24
 
22
25
  async function exists(filePath) {
23
26
  try {
@@ -81,6 +84,13 @@ if (await exists(targetDir)) {
81
84
  await copyDirectory(templateDir, targetDir);
82
85
  await replaceTokens(targetDir);
83
86
 
87
+ if (!enableNix) {
88
+ const optionalNixFiles = [".envrc", "flake.nix", "flake.lock"];
89
+ for (const file of optionalNixFiles) {
90
+ await rm(path.join(targetDir, file), { force: true });
91
+ }
92
+ }
93
+
84
94
  if (!flags.has("--skip-install")) {
85
95
  const install = spawnSync("bun", ["install", "--workspaces"], {
86
96
  cwd: targetDir,
@@ -101,4 +111,7 @@ console.log("\nNext steps:");
101
111
  console.log(` cd ${projectName}`);
102
112
  console.log(" cp client/.env.example client/.env");
103
113
  console.log(" cp server/.env.example server/.env");
114
+ if (enableNix) {
115
+ console.log(" direnv allow");
116
+ }
104
117
  console.log(" just dev");
@@ -0,0 +1 @@
1
+ use flake . --no-pure-eval
@@ -19,7 +19,7 @@ jobs:
19
19
  bun-version: "1.3.4"
20
20
 
21
21
  - name: "📦 Install dependencies"
22
- run: bun install --workspaces
22
+ run: bun install --workspaces --frozen-lockfile
23
23
 
24
24
  - name: "🔍 Lint"
25
25
  run: |
@@ -1,94 +1,102 @@
1
- # React Native Airborne
1
+ # __APP_NAME__
2
2
 
3
- Opinionated React Native starter for mobile-first apps with Expo + Convex.
3
+ This project was scaffolded with React Native Airborne.
4
4
 
5
- ## 🧰 Stack
5
+ ## 🧰 What You Get
6
6
 
7
7
  - Bun workspaces monorepo (`client/`, `server/`)
8
8
  - Expo + Expo Router + Native Tabs (SDK 55)
9
9
  - Uniwind + Tailwind v4
10
- - Clerk authentication
10
+ - Clerk auth flows
11
11
  - Convex backend + `convex-test`
12
- - Zustand + MMKV persistence
12
+ - Zustand + MMKV for non-sensitive local preferences
13
13
  - Expo push notifications
14
+ - Strict ESLint + Prettier + tests
14
15
 
15
- ## 🤝 Contributor Guide
16
+ ## 🗂️ Generated Project Layout
16
17
 
17
- Detailed implementation and maintenance notes for engineers/agents live in `AGENTS.md`.
18
+ ```text
19
+ __APP_NAME__/
20
+ client/ # Expo app
21
+ server/ # Convex backend
22
+ ```
18
23
 
19
24
  ## ✅ Prerequisites
20
25
 
21
26
  - Bun `1.3.4+`
22
27
  - `just` command runner
23
- - Expo toolchain for iOS/Android simulators
24
- - Clerk app + Convex project
28
+ - Expo toolchain for iOS/Android simulators/devices
29
+ - Clerk app with native API enabled
30
+ - Convex project/deployment
25
31
 
26
- ## ⚡ Quickstart
32
+ ## ⚡ Quickstart (After Scaffolding)
27
33
 
28
34
  ```bash
35
+ cd __APP_NAME__
29
36
  bun install --workspaces
30
37
  cp client/.env.example client/.env
31
38
  cp server/.env.example server/.env
32
39
  ```
33
40
 
34
- First-time Convex setup (one-time per new deployment):
41
+ First-time Convex setup (once per deployment):
35
42
 
36
43
  ```bash
37
44
  cd server
38
45
  bun run dev
39
46
  ```
40
47
 
41
- Then run both apps:
48
+ Then run app + backend together:
42
49
 
43
50
  ```bash
44
51
  just dev
45
52
  ```
46
53
 
47
- ## 🧪 Commands
54
+ ## 🔐 Environment Variables
55
+
56
+ Client (`client/.env`):
57
+
58
+ - `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY` (required)
59
+ - `EXPO_PUBLIC_CONVEX_URL` (required)
60
+ - `EXPO_PUBLIC_EAS_PROJECT_ID` (optional)
61
+
62
+ Server (`server/.env`):
63
+
64
+ - `CLERK_JWT_ISSUER_DOMAIN` (required in real environments)
65
+ - `EXPO_PUSH_ENDPOINT` (optional)
66
+ - `EXPO_ACCESS_TOKEN` (optional)
67
+
68
+ ## 🧪 Common Commands
48
69
 
49
70
  - `just dev`: start Expo + Convex
50
71
  - `just dev-client`: start Expo only
51
72
  - `just dev-server`: start Convex only
52
- - `just fmt`: run Prettier on client and server
53
- - `just prebuild`: generate local iOS/Android native folders
73
+ - `just prebuild`: generate local iOS/Android folders
54
74
  - `just ios`: launch iOS app
55
75
  - `just android`: launch Android app
56
- - `just lint`: lint/type lint checks
76
+ - `just fmt`: format client/server
77
+ - `just lint`: lint checks
57
78
  - `just typecheck`: TypeScript checks
58
79
  - `just test`: client + server tests
59
- - `just test-client`: client tests only
60
- - `just test-server`: server tests only
61
80
  - `just ci`: lint + typecheck + tests
62
81
 
63
- ## 📱 Native Projects
82
+ ## 📱 Native Folder Policy
64
83
 
65
- Generate native projects locally when needed:
84
+ `just prebuild` is supported for local native runs.
85
+ `client/ios` and `client/android` are generated locally and should not be committed.
66
86
 
67
- ```bash
68
- just prebuild
69
- ```
70
-
71
- `client/ios` and `client/android` are intentionally gitignored and should not be committed.
72
-
73
- ## 🔐 Environment Variables
74
-
75
- ### Client (`client/.env`)
87
+ ## 📝 Notes
76
88
 
77
- - `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY`
78
- - `EXPO_PUBLIC_CONVEX_URL`
79
- - `EXPO_PUBLIC_EAS_PROJECT_ID` (optional)
89
+ - Theme support is built-in for `light`, `dark`, and `system`.
90
+ - Do not store sensitive auth/session tokens in MMKV.
91
+ - Uniwind is configured via `client/global.css` and `client/metro.config.js`.
92
+ - `SafeAreaView` is wrapped with `withUniwind` in `client/src/components/screen.tsx`.
93
+ - `server/convex/_generated` ships with starter stubs; after connecting Convex, run `cd server && bun run codegen`.
94
+ - `.direnv/` is gitignored by default.
80
95
 
81
- ### Server (`server/.env`)
96
+ ## 🤝 Contributing
82
97
 
83
- - `CLERK_JWT_ISSUER_DOMAIN`
84
- - `EXPO_PUSH_ENDPOINT` (optional)
85
- - `EXPO_ACCESS_TOKEN` (optional)
98
+ See `AGENTS.md` for implementation notes and project conventions.
86
99
 
87
- ## 📝 Notes
100
+ ## 📄 License
88
101
 
89
- - Mobile-only target (iOS/Android).
90
- - Do not store sensitive auth tokens in MMKV.
91
- - Uniwind classes are enabled by `client/global.css` and `client/metro.config.js`.
92
- - `SafeAreaView` is wrapped with `withUniwind` in `client/src/components/screen.tsx` for className support.
93
- - `server/convex/_generated` ships with starter stubs so typecheck/tests pass before deployment setup.
94
- After connecting Convex, run `cd server && bun run codegen` to regenerate.
102
+ MIT
@@ -0,0 +1,104 @@
1
+ {
2
+ "nodes": {
3
+ "android-nixpkgs": {
4
+ "inputs": {
5
+ "devshell": "devshell",
6
+ "flake-utils": "flake-utils",
7
+ "nixpkgs": [
8
+ "nixpkgs"
9
+ ]
10
+ },
11
+ "locked": {
12
+ "lastModified": 1770842373,
13
+ "narHash": "sha256-uCxNWY8xGGtk8YwDJXsfpKUYw8GqR/3degPbIthtFTE=",
14
+ "owner": "tadfisher",
15
+ "repo": "android-nixpkgs",
16
+ "rev": "12878f0d54f923dff305b71d04c6d837df8ce5ab",
17
+ "type": "github"
18
+ },
19
+ "original": {
20
+ "owner": "tadfisher",
21
+ "repo": "android-nixpkgs",
22
+ "type": "github"
23
+ }
24
+ },
25
+ "devshell": {
26
+ "inputs": {
27
+ "nixpkgs": [
28
+ "android-nixpkgs",
29
+ "nixpkgs"
30
+ ]
31
+ },
32
+ "locked": {
33
+ "lastModified": 1768818222,
34
+ "narHash": "sha256-460jc0+CZfyaO8+w8JNtlClB2n4ui1RbHfPTLkpwhU8=",
35
+ "owner": "numtide",
36
+ "repo": "devshell",
37
+ "rev": "255a2b1725a20d060f566e4755dbf571bbbb5f76",
38
+ "type": "github"
39
+ },
40
+ "original": {
41
+ "owner": "numtide",
42
+ "repo": "devshell",
43
+ "type": "github"
44
+ }
45
+ },
46
+ "flake-utils": {
47
+ "inputs": {
48
+ "systems": "systems"
49
+ },
50
+ "locked": {
51
+ "lastModified": 1731533236,
52
+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
53
+ "owner": "numtide",
54
+ "repo": "flake-utils",
55
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
56
+ "type": "github"
57
+ },
58
+ "original": {
59
+ "owner": "numtide",
60
+ "repo": "flake-utils",
61
+ "type": "github"
62
+ }
63
+ },
64
+ "nixpkgs": {
65
+ "locked": {
66
+ "lastModified": 1770843696,
67
+ "narHash": "sha256-LovWTGDwXhkfCOmbgLVA10bvsi/P8eDDpRudgk68HA8=",
68
+ "owner": "NixOS",
69
+ "repo": "nixpkgs",
70
+ "rev": "2343bbb58f99267223bc2aac4fc9ea301a155a16",
71
+ "type": "github"
72
+ },
73
+ "original": {
74
+ "owner": "NixOS",
75
+ "ref": "nixpkgs-unstable",
76
+ "repo": "nixpkgs",
77
+ "type": "github"
78
+ }
79
+ },
80
+ "root": {
81
+ "inputs": {
82
+ "android-nixpkgs": "android-nixpkgs",
83
+ "nixpkgs": "nixpkgs"
84
+ }
85
+ },
86
+ "systems": {
87
+ "locked": {
88
+ "lastModified": 1681028828,
89
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
90
+ "owner": "nix-systems",
91
+ "repo": "default",
92
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
93
+ "type": "github"
94
+ },
95
+ "original": {
96
+ "owner": "nix-systems",
97
+ "repo": "default",
98
+ "type": "github"
99
+ }
100
+ }
101
+ },
102
+ "root": "root",
103
+ "version": 7
104
+ }
@@ -0,0 +1,164 @@
1
+ {
2
+ inputs = {
3
+ nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
4
+
5
+ android-nixpkgs = {
6
+ url = "github:tadfisher/android-nixpkgs";
7
+ inputs.nixpkgs.follows = "nixpkgs";
8
+ };
9
+ };
10
+
11
+ outputs =
12
+ {
13
+ self,
14
+ nixpkgs,
15
+ android-nixpkgs,
16
+ }:
17
+ let
18
+ systems = [
19
+ "aarch64-darwin"
20
+ "x86_64-linux"
21
+ ];
22
+ forAllSystems = nixpkgs.lib.genAttrs systems;
23
+
24
+ pkgsFor =
25
+ system:
26
+ import nixpkgs {
27
+ inherit system;
28
+ config = {
29
+ allowUnfree = true;
30
+ android_sdk.accept_license = true;
31
+ };
32
+ };
33
+
34
+ androidSdkFor =
35
+ system:
36
+ android-nixpkgs.sdk.${system} (
37
+ sdkPkgs: with sdkPkgs; [
38
+ cmdline-tools-latest
39
+ build-tools-35-0-0
40
+ build-tools-36-0-0
41
+ platform-tools
42
+ platforms-android-35
43
+ platforms-android-36
44
+ ndk-27-1-12297006
45
+ ndk-27-0-12077973
46
+ cmake-3-22-1
47
+ ]
48
+ );
49
+
50
+ darwinDerivations = {
51
+ xcode-wrapper =
52
+ pkgs:
53
+ pkgs.stdenv.mkDerivation {
54
+ name = "xcode-wrapper-16.4.0";
55
+ buildInputs = [ pkgs.darwin.cctools ];
56
+ buildCommand = ''
57
+ mkdir -p $out/bin
58
+
59
+ cat > $out/bin/xcodebuild << EOF
60
+ #!/bin/sh
61
+ exec /usr/bin/xcodebuild "\$@"
62
+ EOF
63
+
64
+ cat > $out/bin/xcrun << EOF
65
+ #!/bin/sh
66
+ exec /usr/bin/xcrun "\$@"
67
+ EOF
68
+
69
+ cat > $out/bin/xcode-select << EOF
70
+ #!/bin/sh
71
+ if [ "\$1" = "-p" ] && [ -n "\$DEVELOPER_DIR" ]; then
72
+ echo "\$DEVELOPER_DIR"
73
+ else
74
+ exec /usr/bin/xcode-select "\$@"
75
+ fi
76
+ EOF
77
+
78
+ cat > $out/bin/codesign << EOF
79
+ #!/bin/sh
80
+ exec /usr/bin/codesign "\$@"
81
+ EOF
82
+
83
+ cat > $out/bin/ld << EOF
84
+ #!/bin/sh
85
+ exec /usr/bin/ld "\$@"
86
+ EOF
87
+
88
+ cat > $out/bin/clang << EOF
89
+ #!/bin/sh
90
+ exec /usr/bin/clang "\$@"
91
+ EOF
92
+
93
+ chmod +x $out/bin/*
94
+
95
+ if [ -d "/Applications/Xcode.app" ]; then
96
+ DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"
97
+ elif [ -d "/Applications/Xcode-16.4.0.app" ]; then
98
+ DEVELOPER_DIR="/Applications/Xcode-16.4.0.app/Contents/Developer"
99
+ else
100
+ echo "Error: Xcode not found"
101
+ exit 1
102
+ fi
103
+
104
+ echo "export DEVELOPER_DIR=\"$DEVELOPER_DIR\"" > $out/bin/env.sh
105
+ '';
106
+ };
107
+
108
+ };
109
+
110
+ mkShellFor =
111
+ system:
112
+ let
113
+ pkgs = pkgsFor system;
114
+ androidSdk = androidSdkFor system;
115
+ basePackages = with pkgs; [
116
+ androidSdk
117
+ bun
118
+ just
119
+ ];
120
+
121
+ darwinPackages = with pkgs; [
122
+ bundler
123
+ cocoapods
124
+ (darwinDerivations.xcode-wrapper pkgs)
125
+ ];
126
+
127
+ darwinHook = ''
128
+ export LC_ALL=en_US.UTF-8
129
+ export LANG=en_US.UTF-8
130
+ export JAVA_HOME="${pkgs.jdk17.home}"
131
+
132
+ unset SDKROOT
133
+
134
+ if [ -f "${darwinDerivations.xcode-wrapper pkgs}/bin/env.sh" ]; then
135
+ source "${darwinDerivations.xcode-wrapper pkgs}/bin/env.sh"
136
+ fi
137
+
138
+ export LD=/usr/bin/clang
139
+ export LD_FOR_TARGET=/usr/bin/clang
140
+
141
+ echo "iOS development environment:"
142
+ echo "DEVELOPER_DIR: $DEVELOPER_DIR"
143
+ xcodebuild -version
144
+ '';
145
+
146
+ linuxHook = ''
147
+ export LC_ALL=en_US.UTF-8
148
+ export LANG=en_US.UTF-8
149
+ export JAVA_HOME="${pkgs.jdk17.home}"
150
+ '';
151
+
152
+ in
153
+ pkgs.mkShellNoCC {
154
+ buildInputs = if system == "aarch64-darwin" then basePackages ++ darwinPackages else basePackages;
155
+
156
+ shellHook = if system == "aarch64-darwin" then darwinHook else linuxHook;
157
+ };
158
+ in
159
+ {
160
+ devShells = forAllSystems (system: {
161
+ default = mkShellFor system;
162
+ });
163
+ };
164
+ }
@@ -25,3 +25,4 @@ coverage/
25
25
  # macOS
26
26
  .DS_Store
27
27
  .npmrc
28
+ .direnv/
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "__APP_NAME__",
3
- "version": "0.1.1",
3
+ "version": "0.1.0",
4
4
  "private": true,
5
5
  "packageManager": "bun@1.3.4",
6
6
  "workspaces": [