create-react-native-airborne 0.0.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.
Files changed (78) hide show
  1. package/README.md +24 -0
  2. package/package.json +21 -0
  3. package/src/index.mjs +103 -0
  4. package/template/.agents/skills/convex-best-practices/SKILL.md +333 -0
  5. package/template/.agents/skills/convex-file-storage/SKILL.md +466 -0
  6. package/template/.agents/skills/convex-security-audit/SKILL.md +538 -0
  7. package/template/.agents/skills/convex-security-check/SKILL.md +377 -0
  8. package/template/.github/workflows/ci.yml +130 -0
  9. package/template/.prettierignore +8 -0
  10. package/template/.prettierrc.json +6 -0
  11. package/template/AGENTS.md +156 -0
  12. package/template/Justfile +48 -0
  13. package/template/README.md +94 -0
  14. package/template/client/.env.example +3 -0
  15. package/template/client/.vscode/extensions.json +1 -0
  16. package/template/client/.vscode/settings.json +7 -0
  17. package/template/client/README.md +33 -0
  18. package/template/client/app/(app)/_layout.tsx +34 -0
  19. package/template/client/app/(app)/index.tsx +66 -0
  20. package/template/client/app/(app)/push.tsx +75 -0
  21. package/template/client/app/(app)/settings.tsx +36 -0
  22. package/template/client/app/(auth)/_layout.tsx +22 -0
  23. package/template/client/app/(auth)/sign-in.tsx +358 -0
  24. package/template/client/app/(auth)/sign-up.tsx +237 -0
  25. package/template/client/app/_layout.tsx +30 -0
  26. package/template/client/app/index.tsx +127 -0
  27. package/template/client/app.config.ts +30 -0
  28. package/template/client/assets/images/android-icon-background.png +0 -0
  29. package/template/client/assets/images/android-icon-foreground.png +0 -0
  30. package/template/client/assets/images/android-icon-monochrome.png +0 -0
  31. package/template/client/assets/images/favicon.png +0 -0
  32. package/template/client/assets/images/icon.png +0 -0
  33. package/template/client/assets/images/partial-react-logo.png +0 -0
  34. package/template/client/assets/images/react-logo.png +0 -0
  35. package/template/client/assets/images/react-logo@2x.png +0 -0
  36. package/template/client/assets/images/react-logo@3x.png +0 -0
  37. package/template/client/assets/images/splash-icon.png +0 -0
  38. package/template/client/eslint.config.js +10 -0
  39. package/template/client/global.css +2 -0
  40. package/template/client/metro.config.js +9 -0
  41. package/template/client/package.json +51 -0
  42. package/template/client/src/components/auth-shell.tsx +63 -0
  43. package/template/client/src/components/form-input.tsx +62 -0
  44. package/template/client/src/components/primary-button.tsx +37 -0
  45. package/template/client/src/components/screen.tsx +17 -0
  46. package/template/client/src/components/sign-out-button.tsx +32 -0
  47. package/template/client/src/hooks/use-theme-sync.ts +11 -0
  48. package/template/client/src/lib/convex.ts +6 -0
  49. package/template/client/src/lib/env-schema.ts +13 -0
  50. package/template/client/src/lib/env.test.ts +24 -0
  51. package/template/client/src/lib/env.ts +19 -0
  52. package/template/client/src/lib/notifications.ts +47 -0
  53. package/template/client/src/store/preferences-store.ts +42 -0
  54. package/template/client/src/types/theme.ts +1 -0
  55. package/template/client/tsconfig.json +18 -0
  56. package/template/client/uniwind-types.d.ts +10 -0
  57. package/template/client/vitest.config.ts +7 -0
  58. package/template/package.json +22 -0
  59. package/template/server/.env.example +8 -0
  60. package/template/server/README.md +31 -0
  61. package/template/server/convex/_generated/api.d.ts +55 -0
  62. package/template/server/convex/_generated/api.js +23 -0
  63. package/template/server/convex/_generated/dataModel.d.ts +60 -0
  64. package/template/server/convex/_generated/server.d.ts +143 -0
  65. package/template/server/convex/_generated/server.js +93 -0
  66. package/template/server/convex/auth.config.ts +11 -0
  67. package/template/server/convex/env.ts +18 -0
  68. package/template/server/convex/lib.ts +12 -0
  69. package/template/server/convex/push.ts +148 -0
  70. package/template/server/convex/schema.ts +22 -0
  71. package/template/server/convex/users.ts +54 -0
  72. package/template/server/convex.json +3 -0
  73. package/template/server/eslint.config.js +51 -0
  74. package/template/server/package.json +29 -0
  75. package/template/server/tests/convex.test.ts +52 -0
  76. package/template/server/tests/import-meta.d.ts +3 -0
  77. package/template/server/tsconfig.json +15 -0
  78. package/template/server/vitest.config.ts +13 -0
@@ -0,0 +1,54 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, query, type MutationCtx, type QueryCtx } from "./_generated/server";
3
+ import { requireUserIdentity } from "./lib";
4
+
5
+ async function getUserByClerkId(ctx: MutationCtx | QueryCtx, clerkUserId: string) {
6
+ return ctx.db
7
+ .query("users")
8
+ .withIndex("by_clerk_user_id", (q) => q.eq("clerkUserId", clerkUserId))
9
+ .unique();
10
+ }
11
+
12
+ export const bootstrap = mutation({
13
+ args: {
14
+ email: v.optional(v.string()),
15
+ name: v.optional(v.string()),
16
+ imageUrl: v.optional(v.string()),
17
+ },
18
+ handler: async (ctx, args) => {
19
+ const identity = await requireUserIdentity(ctx);
20
+ const now = Date.now();
21
+
22
+ const existing = await getUserByClerkId(ctx, identity.subject);
23
+
24
+ if (existing) {
25
+ await ctx.db.patch("users", existing._id, {
26
+ email: args.email ?? existing.email,
27
+ name: args.name ?? existing.name,
28
+ imageUrl: args.imageUrl ?? existing.imageUrl,
29
+ lastSeenAt: now,
30
+ });
31
+ return existing._id;
32
+ }
33
+
34
+ return ctx.db.insert("users", {
35
+ clerkUserId: identity.subject,
36
+ email: args.email,
37
+ name: args.name,
38
+ imageUrl: args.imageUrl,
39
+ lastSeenAt: now,
40
+ });
41
+ },
42
+ });
43
+
44
+ export const current = query({
45
+ args: {},
46
+ handler: async (ctx) => {
47
+ const identity = await ctx.auth.getUserIdentity();
48
+ if (!identity) {
49
+ return null;
50
+ }
51
+
52
+ return getUserByClerkId(ctx, identity.subject);
53
+ },
54
+ });
@@ -0,0 +1,3 @@
1
+ {
2
+ "functions": "convex"
3
+ }
@@ -0,0 +1,51 @@
1
+ import { defineConfig } from "eslint/config";
2
+ import js from "@eslint/js";
3
+ import convexPlugin from "@convex-dev/eslint-plugin";
4
+ import tseslint from "typescript-eslint";
5
+
6
+ export default defineConfig(
7
+ {
8
+ ignores: [
9
+ "node_modules/**",
10
+ "dist/**",
11
+ "coverage/**",
12
+ "convex/_generated/**",
13
+ "eslint.config.js",
14
+ ],
15
+ },
16
+ js.configs.recommended,
17
+ ...tseslint.configs.recommendedTypeChecked,
18
+ ...tseslint.configs.strictTypeChecked,
19
+ {
20
+ languageOptions: {
21
+ parserOptions: {
22
+ projectService: true,
23
+ tsconfigRootDir: import.meta.dirname,
24
+ },
25
+ },
26
+ rules: {
27
+ "@typescript-eslint/consistent-type-imports": [
28
+ "error",
29
+ { prefer: "type-imports", fixStyle: "inline-type-imports" },
30
+ ],
31
+ "@typescript-eslint/no-explicit-any": "off",
32
+ "@typescript-eslint/require-await": "off",
33
+ },
34
+ },
35
+ ...convexPlugin.configs.recommended,
36
+ {
37
+ files: ["convex/**/*.ts"],
38
+ rules: {
39
+ "@convex-dev/import-wrong-runtime": "warn",
40
+ },
41
+ },
42
+ {
43
+ files: ["tests/**/*.ts"],
44
+ rules: {
45
+ "@typescript-eslint/no-unsafe-assignment": "off",
46
+ "@typescript-eslint/no-unsafe-call": "off",
47
+ "@typescript-eslint/no-unsafe-member-access": "off",
48
+ "@typescript-eslint/no-unsafe-return": "off",
49
+ },
50
+ },
51
+ );
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "server",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "convex dev",
8
+ "codegen": "convex codegen",
9
+ "lint": "eslint . --max-warnings 0",
10
+ "typecheck": "tsc --noEmit",
11
+ "test": "vitest run",
12
+ "test:watch": "vitest"
13
+ },
14
+ "dependencies": {
15
+ "convex": "^1.28.2",
16
+ "zod": "^3.25.76"
17
+ },
18
+ "devDependencies": {
19
+ "@convex-dev/eslint-plugin": "^1.1.1",
20
+ "@eslint/js": "^9.38.0",
21
+ "@edge-runtime/vm": "^5.0.0",
22
+ "@types/node": "^24.3.0",
23
+ "convex-test": "^0.0.38",
24
+ "eslint": "^9.38.0",
25
+ "typescript": "^5.9.2",
26
+ "typescript-eslint": "^8.46.2",
27
+ "vitest": "^3.2.4"
28
+ }
29
+ }
@@ -0,0 +1,52 @@
1
+ import { convexTest } from "convex-test";
2
+ import { describe, expect, test } from "vitest";
3
+ import schema from "../convex/schema";
4
+ import { api } from "../convex/_generated/api";
5
+
6
+ const modules = import.meta.glob("../convex/**/*.ts");
7
+
8
+ describe("convex functions", () => {
9
+ test("users.bootstrap creates a user and can be queried", async () => {
10
+ const t = convexTest(schema, modules);
11
+
12
+ const authed = t.withIdentity({
13
+ subject: "user_123",
14
+ issuer: "https://example.clerk.accounts.dev",
15
+ tokenIdentifier: "test|user_123",
16
+ });
17
+
18
+ await authed.mutation(api.users.bootstrap, {
19
+ email: "test@example.com",
20
+ name: "Airborne User",
21
+ });
22
+
23
+ const current = await authed.query(api.users.current, {});
24
+ expect(current?.clerkUserId).toBe("user_123");
25
+ expect(current?.email).toBe("test@example.com");
26
+ });
27
+
28
+ test("push token register and unregister", async () => {
29
+ const t = convexTest(schema, modules);
30
+ const authed = t.withIdentity({
31
+ subject: "user_456",
32
+ issuer: "https://example.clerk.accounts.dev",
33
+ tokenIdentifier: "test|user_456",
34
+ });
35
+
36
+ await authed.mutation(api.users.bootstrap, {});
37
+ await authed.mutation(api.push.registerToken, {
38
+ token: "ExponentPushToken[example]",
39
+ platform: "ios",
40
+ });
41
+
42
+ const tokens = await authed.query(api.push.listMyTokens, {});
43
+ expect(tokens).toHaveLength(1);
44
+
45
+ await authed.mutation(api.push.unregisterToken, {
46
+ token: "ExponentPushToken[example]",
47
+ });
48
+
49
+ const after = await authed.query(api.push.listMyTokens, {});
50
+ expect(after).toHaveLength(0);
51
+ });
52
+ });
@@ -0,0 +1,3 @@
1
+ interface ImportMeta {
2
+ glob: (pattern: string) => Record<string, () => Promise<unknown>>;
3
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["ES2022", "DOM"],
5
+ "module": "ESNext",
6
+ "moduleResolution": "Bundler",
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "types": ["node", "vitest/globals"],
10
+ "allowSyntheticDefaultImports": true,
11
+ "skipLibCheck": true,
12
+ "resolveJsonModule": true
13
+ },
14
+ "include": ["convex/**/*.ts", "tests/**/*.ts", "tests/**/*.d.ts", "vitest.config.ts"]
15
+ }
@@ -0,0 +1,13 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ environment: "edge-runtime",
6
+ include: ["tests/**/*.test.ts"],
7
+ server: {
8
+ deps: {
9
+ inline: ["convex-test"],
10
+ },
11
+ },
12
+ },
13
+ });