@proofkit/cli 1.0.0-beta.0

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 (317) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +19 -0
  4. package/dist/acorn-AKFTBDM6.js +15 -0
  5. package/dist/angular-BOQ6FHSU.js +2 -0
  6. package/dist/babel-ZTOORN7K.js +15 -0
  7. package/dist/chunk-4LISTI44.js +1 -0
  8. package/dist/estree-KOJPX4S6.js +36 -0
  9. package/dist/flow-RCI44GYZ.js +19 -0
  10. package/dist/glimmer-GV5EF5E4.js +30 -0
  11. package/dist/graphql-YXQNPQWM.js +29 -0
  12. package/dist/html-ZAJTRROK.js +22 -0
  13. package/dist/index.js +300 -0
  14. package/dist/markdown-Q75DTQI7.js +63 -0
  15. package/dist/meriyah-32K7GBV5.js +4 -0
  16. package/dist/postcss-WWYO4PGL.js +54 -0
  17. package/dist/typescript-M6N7JDNQ.js +20 -0
  18. package/dist/yaml-LY7PNAYV.js +161 -0
  19. package/index.d.ts +19 -0
  20. package/package.json +122 -0
  21. package/template/extras/_cursor/conditional-rules/nextjs-framework.mdc +51 -0
  22. package/template/extras/_cursor/conditional-rules/npm.mdc +60 -0
  23. package/template/extras/_cursor/conditional-rules/pnpm.mdc +65 -0
  24. package/template/extras/_cursor/conditional-rules/yarn.mdc +60 -0
  25. package/template/extras/_cursor/rules/cursor-rules.mdc +88 -0
  26. package/template/extras/_cursor/rules/filemaker-api.mdc +176 -0
  27. package/template/extras/_cursor/rules/troubleshooting-patterns.mdc +240 -0
  28. package/template/extras/_cursor/rules/ui-components.mdc +57 -0
  29. package/template/extras/config/_eslint.js +27 -0
  30. package/template/extras/config/_prettier.config.js +6 -0
  31. package/template/extras/config/drizzle-config-mysql.ts +12 -0
  32. package/template/extras/config/drizzle-config-postgres.ts +12 -0
  33. package/template/extras/config/drizzle-config-sqlite.ts +12 -0
  34. package/template/extras/config/fmschema.config.mjs +9 -0
  35. package/template/extras/config/get-query-client.ts +6 -0
  36. package/template/extras/config/postcss.config.cjs +7 -0
  37. package/template/extras/config/query-provider-vite.tsx +19 -0
  38. package/template/extras/config/query-provider.tsx +21 -0
  39. package/template/extras/emailProviders/none/email.tsx +24 -0
  40. package/template/extras/emailProviders/plunk/email.tsx +26 -0
  41. package/template/extras/emailProviders/plunk/service.ts +4 -0
  42. package/template/extras/emailProviders/resend/email.tsx +23 -0
  43. package/template/extras/emailProviders/resend/service.ts +4 -0
  44. package/template/extras/fmaddon-auth/app/(main)/auth/profile/actions.ts +93 -0
  45. package/template/extras/fmaddon-auth/app/(main)/auth/profile/page.tsx +27 -0
  46. package/template/extras/fmaddon-auth/app/(main)/auth/profile/profile-form.tsx +56 -0
  47. package/template/extras/fmaddon-auth/app/(main)/auth/profile/reset-password-form.tsx +110 -0
  48. package/template/extras/fmaddon-auth/app/(main)/auth/profile/schema.ts +19 -0
  49. package/template/extras/fmaddon-auth/app/auth/forgot-password/actions.ts +37 -0
  50. package/template/extras/fmaddon-auth/app/auth/forgot-password/forgot-form.tsx +41 -0
  51. package/template/extras/fmaddon-auth/app/auth/forgot-password/page.tsx +21 -0
  52. package/template/extras/fmaddon-auth/app/auth/forgot-password/schema.ts +5 -0
  53. package/template/extras/fmaddon-auth/app/auth/login/actions.ts +34 -0
  54. package/template/extras/fmaddon-auth/app/auth/login/login-form.tsx +64 -0
  55. package/template/extras/fmaddon-auth/app/auth/login/page.tsx +26 -0
  56. package/template/extras/fmaddon-auth/app/auth/login/schema.ts +6 -0
  57. package/template/extras/fmaddon-auth/app/auth/reset-password/actions.ts +50 -0
  58. package/template/extras/fmaddon-auth/app/auth/reset-password/page.tsx +32 -0
  59. package/template/extras/fmaddon-auth/app/auth/reset-password/reset-password-form.tsx +59 -0
  60. package/template/extras/fmaddon-auth/app/auth/reset-password/schema.ts +14 -0
  61. package/template/extras/fmaddon-auth/app/auth/reset-password/verify-email/actions.ts +45 -0
  62. package/template/extras/fmaddon-auth/app/auth/reset-password/verify-email/page.tsx +32 -0
  63. package/template/extras/fmaddon-auth/app/auth/reset-password/verify-email/schema.ts +5 -0
  64. package/template/extras/fmaddon-auth/app/auth/reset-password/verify-email/verify-email-form.tsx +48 -0
  65. package/template/extras/fmaddon-auth/app/auth/signup/actions.ts +49 -0
  66. package/template/extras/fmaddon-auth/app/auth/signup/page.tsx +26 -0
  67. package/template/extras/fmaddon-auth/app/auth/signup/schema.ts +12 -0
  68. package/template/extras/fmaddon-auth/app/auth/signup/signup-form.tsx +67 -0
  69. package/template/extras/fmaddon-auth/app/auth/verify-email/actions.ts +110 -0
  70. package/template/extras/fmaddon-auth/app/auth/verify-email/email-verification-form.tsx +45 -0
  71. package/template/extras/fmaddon-auth/app/auth/verify-email/page.tsx +38 -0
  72. package/template/extras/fmaddon-auth/app/auth/verify-email/resend-button.tsx +35 -0
  73. package/template/extras/fmaddon-auth/app/auth/verify-email/schema.ts +5 -0
  74. package/template/extras/fmaddon-auth/components/auth/actions.ts +16 -0
  75. package/template/extras/fmaddon-auth/components/auth/protect.tsx +17 -0
  76. package/template/extras/fmaddon-auth/components/auth/redirect.tsx +26 -0
  77. package/template/extras/fmaddon-auth/components/auth/use-user.ts +59 -0
  78. package/template/extras/fmaddon-auth/components/auth/user-menu.tsx +51 -0
  79. package/template/extras/fmaddon-auth/emails/auth-code.tsx +156 -0
  80. package/template/extras/fmaddon-auth/middleware.ts +45 -0
  81. package/template/extras/fmaddon-auth/server/auth/utils/email-verification.ts +136 -0
  82. package/template/extras/fmaddon-auth/server/auth/utils/encryption.ts +51 -0
  83. package/template/extras/fmaddon-auth/server/auth/utils/index.ts +16 -0
  84. package/template/extras/fmaddon-auth/server/auth/utils/password-reset.ts +152 -0
  85. package/template/extras/fmaddon-auth/server/auth/utils/password.ts +67 -0
  86. package/template/extras/fmaddon-auth/server/auth/utils/redirect.ts +8 -0
  87. package/template/extras/fmaddon-auth/server/auth/utils/session.ts +192 -0
  88. package/template/extras/fmaddon-auth/server/auth/utils/user.ts +147 -0
  89. package/template/extras/prisma/schema/base-planetscale.prisma +24 -0
  90. package/template/extras/prisma/schema/base.prisma +20 -0
  91. package/template/extras/prisma/schema/with-auth-planetscale.prisma +77 -0
  92. package/template/extras/prisma/schema/with-auth.prisma +74 -0
  93. package/template/extras/src/app/_components/post-tw.tsx +50 -0
  94. package/template/extras/src/app/_components/post.tsx +54 -0
  95. package/template/extras/src/app/api/auth/[...nextauth]/route.ts +4 -0
  96. package/template/extras/src/app/api/trpc/[trpc]/route.ts +34 -0
  97. package/template/extras/src/app/clerk-auth/layout.tsx +10 -0
  98. package/template/extras/src/app/clerk-auth/signin/[[...sign-in]]/page.tsx +5 -0
  99. package/template/extras/src/app/clerk-auth/signup/[[...sign-up]]/page.tsx +5 -0
  100. package/template/extras/src/app/layout/base.tsx +34 -0
  101. package/template/extras/src/app/layout/main-shell.tsx +37 -0
  102. package/template/extras/src/app/layout/with-trpc-tw.tsx +24 -0
  103. package/template/extras/src/app/layout/with-trpc.tsx +24 -0
  104. package/template/extras/src/app/layout/with-tw.tsx +20 -0
  105. package/template/extras/src/app/next-auth/layout.tsx +22 -0
  106. package/template/extras/src/app/next-auth/signin/page.tsx +82 -0
  107. package/template/extras/src/app/next-auth/signup/action.ts +24 -0
  108. package/template/extras/src/app/next-auth/signup/page.tsx +40 -0
  109. package/template/extras/src/app/next-auth/signup/validation.ts +12 -0
  110. package/template/extras/src/app/page/base.tsx +6 -0
  111. package/template/extras/src/app/page/with-auth-trpc-tw.tsx +67 -0
  112. package/template/extras/src/app/page/with-auth-trpc.tsx +68 -0
  113. package/template/extras/src/app/page/with-trpc-tw.tsx +53 -0
  114. package/template/extras/src/app/page/with-trpc.tsx +54 -0
  115. package/template/extras/src/app/page/with-tw.tsx +37 -0
  116. package/template/extras/src/components/clerk-auth/clerk-provider.tsx +18 -0
  117. package/template/extras/src/components/clerk-auth/user-menu-mobile.tsx +36 -0
  118. package/template/extras/src/components/clerk-auth/user-menu.tsx +24 -0
  119. package/template/extras/src/components/next-auth/next-auth-provider.tsx +14 -0
  120. package/template/extras/src/components/next-auth/user-menu-mobile.tsx +31 -0
  121. package/template/extras/src/components/next-auth/user-menu.tsx +38 -0
  122. package/template/extras/src/env/with-auth.ts +31 -0
  123. package/template/extras/src/env/with-clerk.ts +20 -0
  124. package/template/extras/src/index.module.css +177 -0
  125. package/template/extras/src/middleware/clerk.ts +20 -0
  126. package/template/extras/src/middleware/next-auth.ts +5 -0
  127. package/template/extras/src/pages/_app/base.tsx +14 -0
  128. package/template/extras/src/pages/_app/with-auth-trpc-tw.tsx +23 -0
  129. package/template/extras/src/pages/_app/with-auth-trpc.tsx +23 -0
  130. package/template/extras/src/pages/_app/with-auth-tw.tsx +21 -0
  131. package/template/extras/src/pages/_app/with-auth.tsx +21 -0
  132. package/template/extras/src/pages/_app/with-trpc-tw.tsx +16 -0
  133. package/template/extras/src/pages/_app/with-trpc.tsx +16 -0
  134. package/template/extras/src/pages/_app/with-tw.tsx +14 -0
  135. package/template/extras/src/pages/api/auth/[...nextauth].ts +5 -0
  136. package/template/extras/src/pages/api/trpc/[trpc].ts +19 -0
  137. package/template/extras/src/pages/index/base.tsx +47 -0
  138. package/template/extras/src/pages/index/with-auth-trpc-tw.tsx +80 -0
  139. package/template/extras/src/pages/index/with-auth-trpc.tsx +81 -0
  140. package/template/extras/src/pages/index/with-trpc-tw.tsx +52 -0
  141. package/template/extras/src/pages/index/with-trpc.tsx +53 -0
  142. package/template/extras/src/pages/index/with-tw.tsx +45 -0
  143. package/template/extras/src/server/api/root.ts +23 -0
  144. package/template/extras/src/server/api/routers/post/base.ts +40 -0
  145. package/template/extras/src/server/api/routers/post/with-auth-drizzle.ts +39 -0
  146. package/template/extras/src/server/api/routers/post/with-auth-prisma.ts +41 -0
  147. package/template/extras/src/server/api/routers/post/with-auth.ts +37 -0
  148. package/template/extras/src/server/api/routers/post/with-drizzle.ts +30 -0
  149. package/template/extras/src/server/api/routers/post/with-prisma.ts +31 -0
  150. package/template/extras/src/server/api/trpc-app/base.ts +103 -0
  151. package/template/extras/src/server/api/trpc-app/with-auth-db.ts +133 -0
  152. package/template/extras/src/server/api/trpc-app/with-auth.ts +130 -0
  153. package/template/extras/src/server/api/trpc-app/with-db.ts +106 -0
  154. package/template/extras/src/server/api/trpc-pages/base.ts +122 -0
  155. package/template/extras/src/server/api/trpc-pages/with-auth-db.ts +160 -0
  156. package/template/extras/src/server/api/trpc-pages/with-auth.ts +158 -0
  157. package/template/extras/src/server/api/trpc-pages/with-db.ts +125 -0
  158. package/template/extras/src/server/data/users.ts +23 -0
  159. package/template/extras/src/server/db/db-prisma-planetscale.ts +22 -0
  160. package/template/extras/src/server/db/db-prisma.ts +17 -0
  161. package/template/extras/src/server/db/index-drizzle/with-mysql.ts +18 -0
  162. package/template/extras/src/server/db/index-drizzle/with-planetscale.ts +7 -0
  163. package/template/extras/src/server/db/index-drizzle/with-postgres.ts +18 -0
  164. package/template/extras/src/server/db/index-drizzle/with-sqlite.ts +19 -0
  165. package/template/extras/src/server/db/schema-drizzle/base-mysql.ts +34 -0
  166. package/template/extras/src/server/db/schema-drizzle/base-planetscale.ts +34 -0
  167. package/template/extras/src/server/db/schema-drizzle/base-postgres.ts +36 -0
  168. package/template/extras/src/server/db/schema-drizzle/base-sqlite.ts +30 -0
  169. package/template/extras/src/server/db/schema-drizzle/with-auth-mysql.ts +123 -0
  170. package/template/extras/src/server/db/schema-drizzle/with-auth-planetscale.ts +117 -0
  171. package/template/extras/src/server/db/schema-drizzle/with-auth-postgres.ts +130 -0
  172. package/template/extras/src/server/db/schema-drizzle/with-auth-sqlite.ts +116 -0
  173. package/template/extras/src/server/next-auth/base.ts +111 -0
  174. package/template/extras/src/server/next-auth/password.ts +13 -0
  175. package/template/extras/src/server/next-auth/with-drizzle.ts +83 -0
  176. package/template/extras/src/server/next-auth/with-prisma.ts +72 -0
  177. package/template/extras/src/trpc/query-client.ts +25 -0
  178. package/template/extras/src/trpc/react.tsx +76 -0
  179. package/template/extras/src/trpc/server.ts +30 -0
  180. package/template/extras/src/utils/api.ts +68 -0
  181. package/template/extras/start-database/mysql.sh +54 -0
  182. package/template/extras/start-database/postgres.sh +55 -0
  183. package/template/fm-addon/ProofKitAuth/de.xml +518 -0
  184. package/template/fm-addon/ProofKitAuth/en.xml +518 -0
  185. package/template/fm-addon/ProofKitAuth/es.xml +518 -0
  186. package/template/fm-addon/ProofKitAuth/fr.xml +518 -0
  187. package/template/fm-addon/ProofKitAuth/icon.png +0 -0
  188. package/template/fm-addon/ProofKitAuth/icon@2x.png +0 -0
  189. package/template/fm-addon/ProofKitAuth/info.json +11 -0
  190. package/template/fm-addon/ProofKitAuth/info_de.json +18 -0
  191. package/template/fm-addon/ProofKitAuth/info_en.json +8 -0
  192. package/template/fm-addon/ProofKitAuth/info_es.json +18 -0
  193. package/template/fm-addon/ProofKitAuth/info_fr.json +18 -0
  194. package/template/fm-addon/ProofKitAuth/info_it.json +18 -0
  195. package/template/fm-addon/ProofKitAuth/info_ja.json +18 -0
  196. package/template/fm-addon/ProofKitAuth/info_ko.json +18 -0
  197. package/template/fm-addon/ProofKitAuth/info_nl.json +18 -0
  198. package/template/fm-addon/ProofKitAuth/info_pt.json +18 -0
  199. package/template/fm-addon/ProofKitAuth/info_sv.json +18 -0
  200. package/template/fm-addon/ProofKitAuth/info_zh.json +18 -0
  201. package/template/fm-addon/ProofKitAuth/it.xml +518 -0
  202. package/template/fm-addon/ProofKitAuth/ja.xml +518 -0
  203. package/template/fm-addon/ProofKitAuth/ko.xml +518 -0
  204. package/template/fm-addon/ProofKitAuth/nl.xml +518 -0
  205. package/template/fm-addon/ProofKitAuth/preview.png +0 -0
  206. package/template/fm-addon/ProofKitAuth/pt.xml +518 -0
  207. package/template/fm-addon/ProofKitAuth/sv.xml +518 -0
  208. package/template/fm-addon/ProofKitAuth/template.xml +0 -0
  209. package/template/fm-addon/ProofKitAuth/zh.xml +518 -0
  210. package/template/fm-addon/ProofKitWV/de.xml +896 -0
  211. package/template/fm-addon/ProofKitWV/en.xml +896 -0
  212. package/template/fm-addon/ProofKitWV/es.xml +896 -0
  213. package/template/fm-addon/ProofKitWV/fr.xml +896 -0
  214. package/template/fm-addon/ProofKitWV/icon.png +0 -0
  215. package/template/fm-addon/ProofKitWV/icon@2x.png +0 -0
  216. package/template/fm-addon/ProofKitWV/info.json +11 -0
  217. package/template/fm-addon/ProofKitWV/info_de.json +18 -0
  218. package/template/fm-addon/ProofKitWV/info_en.json +11 -0
  219. package/template/fm-addon/ProofKitWV/info_es.json +18 -0
  220. package/template/fm-addon/ProofKitWV/info_fr.json +18 -0
  221. package/template/fm-addon/ProofKitWV/info_it.json +18 -0
  222. package/template/fm-addon/ProofKitWV/info_ja.json +18 -0
  223. package/template/fm-addon/ProofKitWV/info_ko.json +18 -0
  224. package/template/fm-addon/ProofKitWV/info_nl.json +18 -0
  225. package/template/fm-addon/ProofKitWV/info_pt.json +18 -0
  226. package/template/fm-addon/ProofKitWV/info_sv.json +18 -0
  227. package/template/fm-addon/ProofKitWV/info_zh.json +18 -0
  228. package/template/fm-addon/ProofKitWV/it.xml +896 -0
  229. package/template/fm-addon/ProofKitWV/ja.xml +896 -0
  230. package/template/fm-addon/ProofKitWV/ko.xml +896 -0
  231. package/template/fm-addon/ProofKitWV/nl.xml +896 -0
  232. package/template/fm-addon/ProofKitWV/preview.png +0 -0
  233. package/template/fm-addon/ProofKitWV/pt.xml +896 -0
  234. package/template/fm-addon/ProofKitWV/records_de.xml +0 -0
  235. package/template/fm-addon/ProofKitWV/records_en.xml +0 -0
  236. package/template/fm-addon/ProofKitWV/records_es.xml +0 -0
  237. package/template/fm-addon/ProofKitWV/records_fr.xml +0 -0
  238. package/template/fm-addon/ProofKitWV/records_it.xml +0 -0
  239. package/template/fm-addon/ProofKitWV/records_ja.xml +0 -0
  240. package/template/fm-addon/ProofKitWV/records_ko.xml +0 -0
  241. package/template/fm-addon/ProofKitWV/records_nl.xml +0 -0
  242. package/template/fm-addon/ProofKitWV/records_pt.xml +0 -0
  243. package/template/fm-addon/ProofKitWV/records_sv.xml +0 -0
  244. package/template/fm-addon/ProofKitWV/records_zh.xml +0 -0
  245. package/template/fm-addon/ProofKitWV/sv.xml +896 -0
  246. package/template/fm-addon/ProofKitWV/template.xml +0 -0
  247. package/template/fm-addon/ProofKitWV/zh.xml +896 -0
  248. package/template/nextjs/README.md +27 -0
  249. package/template/nextjs/_gitignore +37 -0
  250. package/template/nextjs/next.config.ts +12 -0
  251. package/template/nextjs/package.json +50 -0
  252. package/template/nextjs/postcss.config.cjs +14 -0
  253. package/template/nextjs/proofkit.json +1 -0
  254. package/template/nextjs/public/favicon.ico +0 -0
  255. package/template/nextjs/public/proofkit.png +0 -0
  256. package/template/nextjs/src/app/(main)/layout.tsx +6 -0
  257. package/template/nextjs/src/app/(main)/page.tsx +90 -0
  258. package/template/nextjs/src/app/layout.tsx +39 -0
  259. package/template/nextjs/src/app/navigation.tsx +12 -0
  260. package/template/nextjs/src/components/AppLogo.tsx +6 -0
  261. package/template/nextjs/src/components/AppShell/internal/AppShell.tsx +21 -0
  262. package/template/nextjs/src/components/AppShell/internal/Header.module.css +40 -0
  263. package/template/nextjs/src/components/AppShell/internal/Header.tsx +34 -0
  264. package/template/nextjs/src/components/AppShell/internal/HeaderMobileMenu.tsx +27 -0
  265. package/template/nextjs/src/components/AppShell/internal/HeaderNavLink.tsx +31 -0
  266. package/template/nextjs/src/components/AppShell/internal/config.ts +1 -0
  267. package/template/nextjs/src/components/AppShell/slot-header-center.tsx +13 -0
  268. package/template/nextjs/src/components/AppShell/slot-header-left.tsx +23 -0
  269. package/template/nextjs/src/components/AppShell/slot-header-mobile-content.tsx +43 -0
  270. package/template/nextjs/src/components/AppShell/slot-header-right.tsx +26 -0
  271. package/template/nextjs/src/config/env.ts +13 -0
  272. package/template/nextjs/src/config/theme/globals.css +1 -0
  273. package/template/nextjs/src/config/theme/mantine-theme.ts +22 -0
  274. package/template/nextjs/src/server/safe-action.ts +3 -0
  275. package/template/nextjs/src/utils/notification-helpers.ts +32 -0
  276. package/template/nextjs/tsconfig.json +40 -0
  277. package/template/pages/nextjs/blank/page.tsx +5 -0
  278. package/template/pages/nextjs/table/page.tsx +17 -0
  279. package/template/pages/nextjs/table/table.tsx +18 -0
  280. package/template/pages/nextjs/table-edit/actions.ts +23 -0
  281. package/template/pages/nextjs/table-edit/page.tsx +28 -0
  282. package/template/pages/nextjs/table-edit/schema.ts +4 -0
  283. package/template/pages/nextjs/table-edit/table.tsx +43 -0
  284. package/template/pages/nextjs/table-infinite/actions.ts +62 -0
  285. package/template/pages/nextjs/table-infinite/page.tsx +11 -0
  286. package/template/pages/nextjs/table-infinite/query.ts +44 -0
  287. package/template/pages/nextjs/table-infinite/table.tsx +107 -0
  288. package/template/pages/nextjs/table-infinite-edit/actions.ts +84 -0
  289. package/template/pages/nextjs/table-infinite-edit/page.tsx +23 -0
  290. package/template/pages/nextjs/table-infinite-edit/query.ts +81 -0
  291. package/template/pages/nextjs/table-infinite-edit/schema.ts +4 -0
  292. package/template/pages/nextjs/table-infinite-edit/table.tsx +130 -0
  293. package/template/pages/vite-wv/blank/index.tsx +0 -0
  294. package/template/pages/vite-wv/table/index.tsx +34 -0
  295. package/template/pages/vite-wv/table-edit/index.tsx +72 -0
  296. package/template/vite-wv/.vscode/settings.json +11 -0
  297. package/template/vite-wv/_gitignore +18 -0
  298. package/template/vite-wv/index.html +13 -0
  299. package/template/vite-wv/package.json +52 -0
  300. package/template/vite-wv/pnpm-lock.yaml +2294 -0
  301. package/template/vite-wv/postcss.config.cjs +14 -0
  302. package/template/vite-wv/proofkit.json +1 -0
  303. package/template/vite-wv/scripts/launch-fm.sh +3 -0
  304. package/template/vite-wv/scripts/upload.js +21 -0
  305. package/template/vite-wv/src/components/AppLogo.tsx +5 -0
  306. package/template/vite-wv/src/components/full-screen-loader.tsx +9 -0
  307. package/template/vite-wv/src/config/env.ts +16 -0
  308. package/template/vite-wv/src/config/theme/globals.css +1 -0
  309. package/template/vite-wv/src/config/theme/mantine-theme.ts +22 -0
  310. package/template/vite-wv/src/main.tsx +42 -0
  311. package/template/vite-wv/src/routeTree.gen.ts +111 -0
  312. package/template/vite-wv/src/routes/__root.tsx +21 -0
  313. package/template/vite-wv/src/routes/index.tsx +63 -0
  314. package/template/vite-wv/src/routes/secondary.tsx +28 -0
  315. package/template/vite-wv/src/utils/notification-helpers.ts +32 -0
  316. package/template/vite-wv/tsconfig.json +14 -0
  317. package/template/vite-wv/vite.config.ts +18 -0
@@ -0,0 +1,192 @@
1
+ import {
2
+ encodeBase32LowerCaseNoPadding,
3
+ encodeHexLowerCase,
4
+ } from "@oslojs/encoding";
5
+ import { sha256 } from "@oslojs/crypto/sha2";
6
+ import { cookies } from "next/headers";
7
+ import { cache } from "react";
8
+ import type { User } from "./user";
9
+
10
+ import { sessionsLayout } from "../db/client";
11
+ import { Tsessions as _Session } from "../db/sessions";
12
+
13
+ /**
14
+ * Generate a random session token with sufficient entropy for a session ID.
15
+ * @returns The session token.
16
+ */
17
+ export function generateSessionToken(): string {
18
+ const bytes = new Uint8Array(20);
19
+ crypto.getRandomValues(bytes);
20
+ const token = encodeBase32LowerCaseNoPadding(bytes);
21
+ return token;
22
+ }
23
+
24
+ /**
25
+ * Create a new session for a user and save it to the database.
26
+ * @param token - The session token.
27
+ * @param userId - The ID of the user.
28
+ * @returns The session.
29
+ */
30
+ export async function createSession(
31
+ token: string,
32
+ userId: string,
33
+ ): Promise<Session> {
34
+ const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
35
+ const session: Session = {
36
+ id: sessionId,
37
+ id_user: userId,
38
+ expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30),
39
+ };
40
+
41
+ // create session in DB
42
+ await sessionsLayout.create({
43
+ fieldData: {
44
+ id: session.id,
45
+ id_user: session.id_user,
46
+ expiresAt: Math.floor(session.expiresAt.getTime() / 1000),
47
+ },
48
+ });
49
+
50
+ return session;
51
+ }
52
+
53
+ /**
54
+ * Invalidate a session by deleting it from the database.
55
+ * @param sessionId - The ID of the session to invalidate.
56
+ */
57
+ export async function invalidateSession(sessionId: string): Promise<void> {
58
+ const fmResult = await sessionsLayout.maybeFindFirst({
59
+ query: { id: `==${sessionId}` },
60
+ });
61
+ if (fmResult === null) {
62
+ return;
63
+ }
64
+ await sessionsLayout.delete({ recordId: fmResult.data.recordId });
65
+ }
66
+
67
+ /**
68
+ * Validate a session token to make sure it still exists in the database and hasn't expired.
69
+ * @param token - The session token.
70
+ * @returns The session, or null if it doesn't exist.
71
+ */
72
+ export async function validateSessionToken(
73
+ token: string,
74
+ ): Promise<SessionValidationResult> {
75
+ const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
76
+
77
+ const result = await sessionsLayout.maybeFindFirst({
78
+ query: { id: `==${sessionId}` },
79
+ });
80
+ if (result === null) {
81
+ return { session: null, user: null };
82
+ }
83
+
84
+ const fmResult = result.data.fieldData;
85
+ const recordId = result.data.recordId;
86
+ const session: Session = {
87
+ id: fmResult.id,
88
+ id_user: fmResult.id_user,
89
+ expiresAt: fmResult.expiresAt
90
+ ? new Date(fmResult.expiresAt * 1000)
91
+ : new Date(Date.now() + 1000 * 60 * 60 * 24 * 30),
92
+ };
93
+
94
+ const user: User = {
95
+ id: session.id_user,
96
+ email: fmResult["proofkit_auth_users::email"],
97
+ emailVerified: Boolean(fmResult["proofkit_auth_users::emailVerified"]),
98
+ username: fmResult["proofkit_auth_users::username"],
99
+ };
100
+
101
+ // delete session if it has expired
102
+ if (Date.now() >= session.expiresAt.getTime()) {
103
+ await sessionsLayout.delete({ recordId });
104
+ return { session: null, user: null };
105
+ }
106
+
107
+ // extend session if it's going to expire soon
108
+ // You may want to customize this logic to better suit your app's requirements
109
+ if (Date.now() >= session.expiresAt.getTime() - 1000 * 60 * 60 * 24 * 15) {
110
+ session.expiresAt = new Date(Date.now() + 1000 * 60 * 60 * 24 * 30);
111
+ await sessionsLayout.update({
112
+ recordId,
113
+ fieldData: {
114
+ expiresAt: Math.floor(session.expiresAt.getTime() / 1000),
115
+ },
116
+ });
117
+ }
118
+
119
+ return { session, user };
120
+ }
121
+
122
+ /**
123
+ * Get the current session from the cookie.
124
+ * Wrapped in a React cache to avoid calling the database more than once per request
125
+ * This function can be used in server components, server actions, and route handlers (but importantly not middleware).
126
+ * @returns The session, or null if it doesn't exist.
127
+ */
128
+ export const getCurrentSession = cache(
129
+ async (): Promise<SessionValidationResult> => {
130
+ const token = (await cookies()).get("session")?.value ?? null;
131
+ if (token === null) {
132
+ return { session: null, user: null };
133
+ }
134
+ const result = await validateSessionToken(token);
135
+ return result;
136
+ },
137
+ );
138
+
139
+ /**
140
+ * Invalidate all sessions for a user by deleting them from the database.
141
+ * @param userId - The ID of the user.
142
+ */
143
+ export async function invalidateUserSessions(userId: string): Promise<void> {
144
+ const sessions = await sessionsLayout.findAll({
145
+ query: { id_user: `==${userId}` },
146
+ });
147
+ for (const session of sessions) {
148
+ await sessionsLayout.delete({ recordId: session.recordId });
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Set a cookie for a session.
154
+ * @param token - The session token.
155
+ * @param expiresAt - The expiration date of the session.
156
+ */
157
+ export async function setSessionTokenCookie(
158
+ token: string,
159
+ expiresAt: Date,
160
+ ): Promise<void> {
161
+ (await cookies()).set("session", token, {
162
+ httpOnly: true,
163
+ path: "/",
164
+ secure: process.env.NODE_ENV === "production",
165
+ sameSite: "lax",
166
+ expires: expiresAt,
167
+ });
168
+ }
169
+
170
+
171
+ /**
172
+ * Delete the session cookie.
173
+ */
174
+ export async function deleteSessionTokenCookie(): Promise<void> {
175
+ (await cookies()).set("session", "", {
176
+ httpOnly: true,
177
+ path: "/",
178
+ secure: process.env.NODE_ENV === "production",
179
+ sameSite: "lax",
180
+ maxAge: 0,
181
+ });
182
+ }
183
+
184
+ export interface Session {
185
+ id: string;
186
+ expiresAt: Date;
187
+ id_user: string;
188
+ }
189
+
190
+ type SessionValidationResult =
191
+ | { session: Session; user: User }
192
+ | { session: null; user: null };
@@ -0,0 +1,147 @@
1
+ import { usersLayout } from "../db/client";
2
+ import { Tusers as _User } from "../db/users";
3
+
4
+ export type User = Partial<
5
+ Omit<_User, "id" | "password_hash" | "recovery_code" | "emailVerified">
6
+ > & {
7
+ id: string;
8
+ email: string;
9
+ emailVerified: boolean;
10
+ };
11
+
12
+ import { hashPassword, verifyPasswordHash } from "./password";
13
+
14
+ /** An internal helper function to fetch a user from the database. */
15
+ async function fetchUser(userId: string) {
16
+ const { data } = await usersLayout.findOne({
17
+ query: { id: `==${userId}` },
18
+ });
19
+ return data;
20
+ }
21
+
22
+ /** Create a new user in the database. */
23
+ export async function createUser(
24
+ email: string,
25
+ password: string
26
+ ): Promise<User> {
27
+ const password_hash = await hashPassword(password);
28
+ const { recordId } = await usersLayout.create({
29
+ fieldData: {
30
+ email,
31
+ password_hash,
32
+ emailVerified: 0,
33
+ },
34
+ });
35
+ const fmResult = await usersLayout.get({ recordId });
36
+ const { fieldData } = fmResult.data[0];
37
+
38
+ const user: User = {
39
+ id: fieldData.id,
40
+ email,
41
+ emailVerified: false,
42
+ username: "",
43
+ };
44
+ return user;
45
+ }
46
+
47
+ /** Update a user's password in the database. */
48
+ export async function updateUserPassword(
49
+ userId: string,
50
+ password: string
51
+ ): Promise<void> {
52
+ const password_hash = await hashPassword(password);
53
+ const { recordId } = await fetchUser(userId);
54
+
55
+ await usersLayout.update({ recordId, fieldData: { password_hash } });
56
+ }
57
+
58
+ export async function updateUserEmailAndSetEmailAsVerified(
59
+ userId: string,
60
+ email: string
61
+ ): Promise<void> {
62
+ const { recordId } = await fetchUser(userId);
63
+ await usersLayout.update({
64
+ recordId,
65
+ fieldData: { email, emailVerified: 1 },
66
+ });
67
+ }
68
+
69
+ export async function setUserAsEmailVerifiedIfEmailMatches(
70
+ userId: string,
71
+ email: string
72
+ ): Promise<boolean> {
73
+ try {
74
+ const {
75
+ data: { recordId },
76
+ } = await usersLayout.findOne({
77
+ query: { id: `==${userId}`, email: `==${email}` },
78
+ });
79
+ await usersLayout.update({ recordId, fieldData: { emailVerified: 1 } });
80
+ return true;
81
+ } catch (error) {
82
+ return false;
83
+ }
84
+ }
85
+
86
+ export async function getUserFromEmail(email: string): Promise<User | null> {
87
+ const fmResult = await usersLayout.maybeFindFirst({
88
+ query: { email: `==${email}` },
89
+ });
90
+ if (fmResult === null) return null;
91
+
92
+ const {
93
+ data: { fieldData },
94
+ } = fmResult;
95
+
96
+ const user: User = {
97
+ id: fieldData.id,
98
+ email: fieldData.email,
99
+ emailVerified: Boolean(fieldData.emailVerified),
100
+ username: fieldData.username,
101
+ };
102
+ return user;
103
+ }
104
+
105
+ /**
106
+ * Validate a user's email/password combination.
107
+ * @param email - The user's email.
108
+ * @param password - The user's password.
109
+ * @returns The user, or null if the login is invalid.
110
+ */
111
+ export async function validateLogin(
112
+ email: string,
113
+ password: string
114
+ ): Promise<User | null> {
115
+ try {
116
+ const {
117
+ data: { fieldData },
118
+ } = await usersLayout.findOne({
119
+ query: { email: `==${email}` },
120
+ });
121
+
122
+ const validPassword = await verifyPasswordHash(
123
+ fieldData.password_hash,
124
+ password
125
+ );
126
+ if (!validPassword) {
127
+ return null;
128
+ }
129
+ const user: User = {
130
+ id: fieldData.id,
131
+ email: fieldData.email,
132
+ emailVerified: Boolean(fieldData.emailVerified),
133
+ username: fieldData.username,
134
+ };
135
+ return user;
136
+ } catch (error) {
137
+ return null;
138
+ }
139
+ }
140
+
141
+ export async function checkEmailAvailability(email: string): Promise<boolean> {
142
+ const { data } = await usersLayout.find({
143
+ query: { email: `==${email}` },
144
+ ignoreEmptyResult: true,
145
+ });
146
+ return data.length === 0;
147
+ }
@@ -0,0 +1,24 @@
1
+ // This is your Prisma schema file,
2
+ // learn more about it in the docs: https://pris.ly/d/prisma-schema
3
+
4
+ generator client {
5
+ provider = "prisma-client-js"
6
+ previewFeatures = ["driverAdapters"]
7
+ }
8
+
9
+ datasource db {
10
+ provider = "mysql"
11
+ url = env("DATABASE_URL")
12
+
13
+ // If you have enabled foreign key constraints for your database, remove this line.
14
+ relationMode = "prisma"
15
+ }
16
+
17
+ model Post {
18
+ id Int @id @default(autoincrement())
19
+ name String
20
+ createdAt DateTime @default(now())
21
+ updatedAt DateTime @updatedAt
22
+
23
+ @@index([name])
24
+ }
@@ -0,0 +1,20 @@
1
+ // This is your Prisma schema file,
2
+ // learn more about it in the docs: https://pris.ly/d/prisma-schema
3
+
4
+ generator client {
5
+ provider = "prisma-client-js"
6
+ }
7
+
8
+ datasource db {
9
+ provider = "sqlite"
10
+ url = env("DATABASE_URL")
11
+ }
12
+
13
+ model Post {
14
+ id Int @id @default(autoincrement())
15
+ name String
16
+ createdAt DateTime @default(now())
17
+ updatedAt DateTime @updatedAt
18
+
19
+ @@index([name])
20
+ }
@@ -0,0 +1,77 @@
1
+ // This is your Prisma schema file,
2
+ // learn more about it in the docs: https://pris.ly/d/prisma-schema
3
+
4
+ generator client {
5
+ provider = "prisma-client-js"
6
+ previewFeatures = ["driverAdapters"]
7
+ }
8
+
9
+ datasource db {
10
+ provider = "mysql"
11
+ url = env("DATABASE_URL")
12
+
13
+ // If you have enabled foreign key constraints for your database, remove this line.
14
+ relationMode = "prisma"
15
+ }
16
+
17
+ model Post {
18
+ id Int @id @default(autoincrement())
19
+ name String
20
+ createdAt DateTime @default(now())
21
+ updatedAt DateTime @updatedAt
22
+
23
+ createdBy User @relation(fields: [createdById], references: [id])
24
+ createdById String
25
+
26
+ @@index([name])
27
+ @@index([createdById])
28
+ }
29
+
30
+ // Necessary for Next auth
31
+ model Account {
32
+ id String @id @default(cuid())
33
+ userId String
34
+ type String
35
+ provider String
36
+ providerAccountId String
37
+ refresh_token String? @db.Text
38
+ access_token String? @db.Text
39
+ expires_at Int?
40
+ token_type String?
41
+ scope String?
42
+ id_token String? @db.Text
43
+ session_state String?
44
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
45
+
46
+ @@unique([provider, providerAccountId])
47
+ @@index([userId])
48
+ }
49
+
50
+ model Session {
51
+ id String @id @default(cuid())
52
+ sessionToken String @unique
53
+ userId String
54
+ expires DateTime
55
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
56
+
57
+ @@index([userId])
58
+ }
59
+
60
+ model User {
61
+ id String @id @default(cuid())
62
+ name String?
63
+ email String? @unique
64
+ emailVerified DateTime?
65
+ image String?
66
+ accounts Account[]
67
+ sessions Session[]
68
+ posts Post[]
69
+ }
70
+
71
+ model VerificationToken {
72
+ identifier String
73
+ token String @unique
74
+ expires DateTime
75
+
76
+ @@unique([identifier, token])
77
+ }
@@ -0,0 +1,74 @@
1
+ // This is your Prisma schema file,
2
+ // learn more about it in the docs: https://pris.ly/d/prisma-schema
3
+
4
+ generator client {
5
+ provider = "prisma-client-js"
6
+ }
7
+
8
+ datasource db {
9
+ provider = "sqlite"
10
+ // NOTE: When using mysql or sqlserver, uncomment the @db.Text annotations in model Account below
11
+ // Further reading:
12
+ // https://next-auth.js.org/adapters/prisma#create-the-prisma-schema
13
+ // https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string
14
+ url = env("DATABASE_URL")
15
+ }
16
+
17
+ model Post {
18
+ id Int @id @default(autoincrement())
19
+ name String
20
+ createdAt DateTime @default(now())
21
+ updatedAt DateTime @updatedAt
22
+
23
+ createdBy User @relation(fields: [createdById], references: [id])
24
+ createdById String
25
+
26
+ @@index([name])
27
+ }
28
+
29
+ // Necessary for Next auth
30
+ model Account {
31
+ id String @id @default(cuid())
32
+ userId String
33
+ type String
34
+ provider String
35
+ providerAccountId String
36
+ refresh_token String? // @db.Text
37
+ access_token String? // @db.Text
38
+ expires_at Int?
39
+ token_type String?
40
+ scope String?
41
+ id_token String? // @db.Text
42
+ session_state String?
43
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
44
+ refresh_token_expires_in Int?
45
+
46
+ @@unique([provider, providerAccountId])
47
+ }
48
+
49
+ model Session {
50
+ id String @id @default(cuid())
51
+ sessionToken String @unique
52
+ userId String
53
+ expires DateTime
54
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
55
+ }
56
+
57
+ model User {
58
+ id String @id @default(cuid())
59
+ name String?
60
+ email String? @unique
61
+ emailVerified DateTime?
62
+ image String?
63
+ accounts Account[]
64
+ sessions Session[]
65
+ posts Post[]
66
+ }
67
+
68
+ model VerificationToken {
69
+ identifier String
70
+ token String @unique
71
+ expires DateTime
72
+
73
+ @@unique([identifier, token])
74
+ }
@@ -0,0 +1,50 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+
5
+ import { api } from "~/trpc/react";
6
+
7
+ export function LatestPost() {
8
+ const [latestPost] = api.post.getLatest.useSuspenseQuery();
9
+
10
+ const utils = api.useUtils();
11
+ const [name, setName] = useState("");
12
+ const createPost = api.post.create.useMutation({
13
+ onSuccess: async () => {
14
+ await utils.post.invalidate();
15
+ setName("");
16
+ },
17
+ });
18
+
19
+ return (
20
+ <div className="w-full max-w-xs">
21
+ {latestPost ? (
22
+ <p className="truncate">Your most recent post: {latestPost.name}</p>
23
+ ) : (
24
+ <p>You have no posts yet.</p>
25
+ )}
26
+ <form
27
+ onSubmit={(e) => {
28
+ e.preventDefault();
29
+ createPost.mutate({ name });
30
+ }}
31
+ className="flex flex-col gap-2"
32
+ >
33
+ <input
34
+ type="text"
35
+ placeholder="Title"
36
+ value={name}
37
+ onChange={(e) => setName(e.target.value)}
38
+ className="w-full rounded-full px-4 py-2 text-black"
39
+ />
40
+ <button
41
+ type="submit"
42
+ className="rounded-full bg-white/10 px-10 py-3 font-semibold transition hover:bg-white/20"
43
+ disabled={createPost.isPending}
44
+ >
45
+ {createPost.isPending ? "Submitting..." : "Submit"}
46
+ </button>
47
+ </form>
48
+ </div>
49
+ );
50
+ }
@@ -0,0 +1,54 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+
5
+ import { api } from "~/trpc/react";
6
+ import styles from "../index.module.css";
7
+
8
+ export function LatestPost() {
9
+ const [latestPost] = api.post.getLatest.useSuspenseQuery();
10
+
11
+ const utils = api.useUtils();
12
+ const [name, setName] = useState("");
13
+ const createPost = api.post.create.useMutation({
14
+ onSuccess: async () => {
15
+ await utils.post.invalidate();
16
+ setName("");
17
+ },
18
+ });
19
+
20
+ return (
21
+ <div className={styles.showcaseContainer}>
22
+ {latestPost ? (
23
+ <p className={styles.showcaseText}>
24
+ Your most recent post: {latestPost.name}
25
+ </p>
26
+ ) : (
27
+ <p className={styles.showcaseText}>You have no posts yet.</p>
28
+ )}
29
+
30
+ <form
31
+ onSubmit={(e) => {
32
+ e.preventDefault();
33
+ createPost.mutate({ name });
34
+ }}
35
+ className={styles.form}
36
+ >
37
+ <input
38
+ type="text"
39
+ placeholder="Title"
40
+ value={name}
41
+ onChange={(e) => setName(e.target.value)}
42
+ className={styles.input}
43
+ />
44
+ <button
45
+ type="submit"
46
+ className={styles.submitButton}
47
+ disabled={createPost.isPending}
48
+ >
49
+ {createPost.isPending ? "Submitting..." : "Submit"}
50
+ </button>
51
+ </form>
52
+ </div>
53
+ );
54
+ }
@@ -0,0 +1,4 @@
1
+ import { handlers } from "@/server/auth"; // Referring to the auth.ts we just created
2
+
3
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
4
+ export const { GET, POST } = handlers;
@@ -0,0 +1,34 @@
1
+ import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
2
+ import { type NextRequest } from "next/server";
3
+
4
+ import { env } from "~/env";
5
+ import { appRouter } from "~/server/api/root";
6
+ import { createTRPCContext } from "~/server/api/trpc";
7
+
8
+ /**
9
+ * This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when
10
+ * handling a HTTP request (e.g. when you make requests from Client Components).
11
+ */
12
+ const createContext = async (req: NextRequest) => {
13
+ return createTRPCContext({
14
+ headers: req.headers,
15
+ });
16
+ };
17
+
18
+ const handler = (req: NextRequest) =>
19
+ fetchRequestHandler({
20
+ endpoint: "/api/trpc",
21
+ req,
22
+ router: appRouter,
23
+ createContext: () => createContext(req),
24
+ onError:
25
+ env.NODE_ENV === "development"
26
+ ? ({ path, error }) => {
27
+ console.error(
28
+ `❌ tRPC failed on ${path ?? "<no-path>"}: ${error.message}`
29
+ );
30
+ }
31
+ : undefined,
32
+ });
33
+
34
+ export { handler as GET, handler as POST };
@@ -0,0 +1,10 @@
1
+ import { Center } from "@mantine/core";
2
+ import React from "react";
3
+
4
+ export default function AuthLayout({
5
+ children,
6
+ }: {
7
+ children: React.ReactNode;
8
+ }) {
9
+ return <Center h="100vh">{children}</Center>;
10
+ }
@@ -0,0 +1,5 @@
1
+ import { SignIn } from "@clerk/nextjs";
2
+
3
+ export default function Page() {
4
+ return <SignIn />;
5
+ }