@cedarjs/cli 9.0.0-canary.1784 → 9.0.0-canary.3124

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 (277) hide show
  1. package/README.md +7 -10
  2. package/dist/cfw.js +10 -6
  3. package/dist/commands/build/buildHandler.js +220 -45
  4. package/dist/commands/build/buildPackagesTask.js +21 -20
  5. package/dist/commands/build.js +13 -2
  6. package/dist/commands/check.js +4 -6
  7. package/dist/commands/console.js +6 -4
  8. package/dist/commands/deploy/baremetal/SshExecutor.js +13 -4
  9. package/dist/commands/deploy/baremetal/baremetalHandler.js +116 -50
  10. package/dist/commands/deploy/baremetal.js +11 -4
  11. package/dist/commands/deploy/flightcontrolHandler.js +28 -15
  12. package/dist/commands/deploy/helpers/deployHandler.js +11 -6
  13. package/dist/commands/deploy/netlify.js +1 -1
  14. package/dist/commands/deploy/packing/nft.js +1 -2
  15. package/dist/commands/deploy/render.js +1 -1
  16. package/dist/commands/deploy/renderHandler.js +24 -13
  17. package/dist/commands/deploy/serverlessHandler.js +69 -27
  18. package/dist/commands/deploy/vercel.js +1 -1
  19. package/dist/commands/destroy/component/component.js +2 -3
  20. package/dist/commands/destroy/directive/directive.js +1 -3
  21. package/dist/commands/destroy/directive/directiveHandler.js +2 -4
  22. package/dist/commands/destroy/function/function.js +1 -3
  23. package/dist/commands/destroy/handlerHelpers.js +17 -17
  24. package/dist/commands/destroy/helpers.js +8 -2
  25. package/dist/commands/destroy/layout/layout.js +1 -2
  26. package/dist/commands/destroy/page/pageHandler.js +3 -3
  27. package/dist/commands/destroy/scaffold/scaffoldHandler.js +31 -12
  28. package/dist/commands/destroy/sdl/sdlHandler.js +3 -3
  29. package/dist/commands/dev/apiDebugFlag.js +5 -4
  30. package/dist/commands/dev/devHandler.js +219 -68
  31. package/dist/commands/dev/packageWatchCommands.js +8 -3
  32. package/dist/commands/dev.js +16 -6
  33. package/dist/commands/execHandler.js +49 -29
  34. package/dist/commands/experimental/live-queries/liveQueries.js +32 -0
  35. package/dist/commands/experimental/live-queries/liveQueriesHandler.js +448 -0
  36. package/dist/commands/experimental/live-queries/templates/liveQueriesListener.ts.template +153 -0
  37. package/dist/commands/experimental/live-queries/templates/migration.sql.template +100 -0
  38. package/dist/commands/experimental/setupInngest.js +2 -2
  39. package/dist/commands/experimental/setupInngestHandler.js +13 -12
  40. package/dist/commands/experimental/setupOpentelemetry.js +2 -2
  41. package/dist/commands/experimental/setupOpentelemetryHandler.js +14 -10
  42. package/dist/commands/experimental/setupReactCompiler.js +2 -2
  43. package/dist/commands/experimental/setupReactCompilerHandler.js +48 -33
  44. package/dist/commands/experimental/setupRsc.js +1 -1
  45. package/dist/commands/experimental/setupRscHandler.js +20 -16
  46. package/dist/commands/experimental/setupStreamingSsr.js +2 -2
  47. package/dist/commands/experimental/setupStreamingSsrHandler.js +49 -34
  48. package/dist/commands/experimental/templates/opentelemetry.ts.template +2 -1
  49. package/dist/commands/experimental/templates/rsc/Document.tsx.template +1 -1
  50. package/dist/commands/experimental/templates/rsc/entry.client.tsx.template +8 -8
  51. package/dist/commands/experimental/templates/streamingSsr/Document.tsx.template +1 -1
  52. package/dist/commands/experimental/templates/streamingSsr/entry.client.tsx.template +6 -6
  53. package/dist/commands/experimental/templates/streamingSsr/tsconfig.json.template +6 -6
  54. package/dist/commands/experimental/util.js +27 -25
  55. package/dist/commands/experimental.js +3 -2
  56. package/dist/commands/generate/cell/cell.js +20 -0
  57. package/dist/commands/generate/cell/cellHandler.js +89 -40
  58. package/dist/commands/generate/cell/templates/cell.tsx.template +21 -2
  59. package/dist/commands/generate/cell/templates/cellFragment.tsx.template +43 -0
  60. package/dist/commands/generate/cell/templates/cellList.tsx.template +21 -2
  61. package/dist/commands/generate/cell/templates/storiesFragment.tsx.template +23 -0
  62. package/dist/commands/generate/cell/templates/test.js.template +1 -1
  63. package/dist/commands/generate/cell/templates/testFragment.js.template +30 -0
  64. package/dist/commands/generate/component/componentHandler.js +14 -16
  65. package/dist/commands/generate/dataMigration/dataMigration.js +36 -18
  66. package/dist/commands/generate/dataMigration/templates/dataMigration.js.template +1 -1
  67. package/dist/commands/generate/dataMigration/templates/dataMigration.ts.template +1 -1
  68. package/dist/commands/generate/dbAuth/dbAuth.js +1 -0
  69. package/dist/commands/generate/dbAuth/dbAuthHandler.js +63 -34
  70. package/dist/commands/generate/dbAuth/templates/login.oauth.tsx.template +164 -0
  71. package/dist/commands/generate/dbAuth/templates/signup.oauth.tsx.template +147 -0
  72. package/dist/commands/generate/directive/directiveHandler.js +14 -16
  73. package/dist/commands/generate/function/function.js +1 -0
  74. package/dist/commands/generate/function/functionHandler.js +14 -19
  75. package/dist/commands/generate/helpers.js +34 -18
  76. package/dist/commands/generate/job/job.js +1 -0
  77. package/dist/commands/generate/job/jobHandler.js +20 -24
  78. package/dist/commands/generate/layout/layoutHandler.js +13 -16
  79. package/dist/commands/generate/model/model.js +1 -0
  80. package/dist/commands/generate/model/modelHandler.js +11 -5
  81. package/dist/commands/generate/ogImage/ogImage.js +1 -0
  82. package/dist/commands/generate/ogImage/ogImageHandler.js +18 -11
  83. package/dist/commands/generate/package/filesTask.js +9 -0
  84. package/dist/commands/generate/package/packageHandler.js +50 -61
  85. package/dist/commands/generate/package/templates/test.ts.template +2 -2
  86. package/dist/commands/generate/package/templates/vitest.config.ts.template +9 -0
  87. package/dist/commands/generate/page/pageHandler.js +27 -24
  88. package/dist/commands/generate/realtime/realtime.js +2 -2
  89. package/dist/commands/generate/realtime/realtimeHandler.js +51 -32
  90. package/dist/commands/generate/realtime/templates/subscriptions/blank/blank.ts.template +1 -1
  91. package/dist/commands/generate/scaffold/scaffold.js +1 -0
  92. package/dist/commands/generate/scaffold/scaffoldHandler.js +176 -49
  93. package/dist/commands/generate/scaffold/templates/lib/formatters.tsx.template +1 -1
  94. package/dist/commands/generate/script/script.js +1 -0
  95. package/dist/commands/generate/script/scriptHandler.js +10 -6
  96. package/dist/commands/generate/script/templates/script.ts.template +9 -4
  97. package/dist/commands/generate/script/templates/tsconfig.json.template +16 -2
  98. package/dist/commands/generate/sdl/sdl.js +4 -3
  99. package/dist/commands/generate/sdl/sdlHandler.js +135 -46
  100. package/dist/commands/generate/sdl/stubFiles.js +132 -0
  101. package/dist/commands/generate/sdl/templates/sdl.js.template +2 -1
  102. package/dist/commands/generate/sdl/templates/sdl.ts.template +2 -1
  103. package/dist/commands/generate/secret/secret.js +20 -20
  104. package/dist/commands/generate/service/service.js +5 -5
  105. package/dist/commands/generate/service/serviceHandler.js +126 -61
  106. package/dist/commands/generate/service/templates/scenarios.ts.template +4 -2
  107. package/dist/commands/generate/service/templates/service.ts.template +22 -8
  108. package/dist/commands/generate/service/templates/test.ts.template +2 -2
  109. package/dist/commands/generate/yargsCommandHelpers.js +7 -2
  110. package/dist/commands/generate/yargsHandlerHelpers.js +20 -18
  111. package/dist/commands/generate.js +4 -4
  112. package/dist/commands/info.js +2 -2
  113. package/dist/commands/jobsHandler.js +7 -4
  114. package/dist/commands/lint.js +26 -69
  115. package/dist/commands/prerenderHandler.js +95 -58
  116. package/dist/commands/prismaHandler.js +51 -26
  117. package/dist/commands/record/init.js +2 -2
  118. package/dist/commands/record.js +4 -3
  119. package/dist/commands/serve.js +245 -31
  120. package/dist/commands/serveApiHandler.js +7 -6
  121. package/dist/commands/serveBothHandler.js +22 -13
  122. package/dist/commands/serveWebHandler.js +3 -2
  123. package/dist/commands/setup/auth/auth.js +15 -11
  124. package/dist/commands/setup/cache/cache.js +1 -1
  125. package/dist/commands/setup/cache/cacheHandler.js +15 -9
  126. package/dist/commands/setup/database/database.js +15 -0
  127. package/dist/commands/setup/database/postgres.js +19 -0
  128. package/dist/commands/setup/database/postgresHandler.js +196 -0
  129. package/dist/commands/setup/database/templates/db.ts.template +32 -0
  130. package/dist/commands/setup/deploy/deploy.js +4 -3
  131. package/dist/commands/setup/deploy/helpers/helpers.js +5 -1
  132. package/dist/commands/setup/deploy/helpers/index.js +132 -6
  133. package/dist/commands/setup/deploy/providers/baremetalHandler.js +28 -6
  134. package/dist/commands/setup/deploy/providers/coherence.js +1 -1
  135. package/dist/commands/setup/deploy/providers/coherenceHandler.js +60 -31
  136. package/dist/commands/setup/deploy/providers/flightcontrolHandler.js +69 -51
  137. package/dist/commands/setup/deploy/providers/netlify.js +6 -0
  138. package/dist/commands/setup/deploy/providers/netlifyHandler.js +114 -13
  139. package/dist/commands/setup/deploy/providers/renderHandler.js +44 -41
  140. package/dist/commands/setup/deploy/providers/serverlessHandler.js +7 -5
  141. package/dist/commands/setup/deploy/providers/universal-deploy.js +11 -0
  142. package/dist/commands/setup/deploy/providers/universalDeployHandler.js +186 -0
  143. package/dist/commands/setup/deploy/providers/vercel.js +6 -0
  144. package/dist/commands/setup/deploy/providers/vercelHandler.js +115 -14
  145. package/dist/commands/setup/deploy/templates/baremetal.js +3 -2
  146. package/dist/commands/setup/deploy/templates/flightcontrol.js +60 -49
  147. package/dist/commands/setup/deploy/templates/netlify.js +2 -1
  148. package/dist/commands/setup/deploy/templates/netlifyUD.js +31 -0
  149. package/dist/commands/setup/deploy/templates/render.js +32 -17
  150. package/dist/commands/setup/docker/docker.js +2 -2
  151. package/dist/commands/setup/docker/dockerHandler.js +74 -39
  152. package/dist/commands/setup/docker/templates/Dockerfile.npm +119 -0
  153. package/dist/commands/setup/docker/templates/Dockerfile.pnpm +112 -0
  154. package/dist/commands/setup/docker/templates/{Dockerfile → Dockerfile.yarn} +4 -7
  155. package/dist/commands/setup/docker/templates/docker-compose.dev.yml +3 -3
  156. package/dist/commands/setup/docker/templates/docker-compose.prod.yml +2 -5
  157. package/dist/commands/setup/docker/templates/dockerignore +1 -0
  158. package/dist/commands/setup/generator/generator.js +1 -1
  159. package/dist/commands/setup/generator/generatorHandler.js +5 -4
  160. package/dist/commands/setup/graphql/features/fragments/appGqlConfigTransform.js +6 -3
  161. package/dist/commands/setup/graphql/features/fragments/fragments.js +1 -1
  162. package/dist/commands/setup/graphql/features/fragments/fragmentsHandler.js +5 -7
  163. package/dist/commands/setup/graphql/features/trustedDocuments/trustedDocuments.js +1 -1
  164. package/dist/commands/setup/graphql/features/trustedDocuments/trustedDocumentsHandler.js +4 -3
  165. package/dist/commands/setup/i18n/i18n.js +1 -1
  166. package/dist/commands/setup/i18n/i18nHandler.js +21 -17
  167. package/dist/commands/setup/jobs/jobs.js +1 -1
  168. package/dist/commands/setup/jobs/jobsHandler.js +17 -12
  169. package/dist/commands/setup/mailer/mailer.js +1 -1
  170. package/dist/commands/setup/mailer/mailerHandler.js +13 -11
  171. package/dist/commands/setup/middleware/ogImage/ogImage.js +1 -1
  172. package/dist/commands/setup/middleware/ogImage/ogImageHandler.js +2 -1
  173. package/dist/commands/setup/monitoring/sentry/sentry.js +1 -1
  174. package/dist/commands/setup/monitoring/sentry/sentryHandler.js +18 -12
  175. package/dist/commands/setup/neon/neon.js +35 -0
  176. package/dist/commands/setup/neon/neonHandler.js +264 -0
  177. package/dist/commands/setup/package/package.js +1 -1
  178. package/dist/commands/setup/package/packageHandler.js +18 -14
  179. package/dist/commands/setup/realtime/addRealtimeToGraphql.js +1 -1
  180. package/dist/commands/setup/realtime/realtime.js +1 -1
  181. package/dist/commands/setup/realtime/realtimeHandler.js +26 -37
  182. package/dist/commands/setup/realtime/templates/realtime.ts.template +1 -1
  183. package/dist/commands/setup/realtime/templates/subscriptions/countdown/countdown.ts.template +1 -1
  184. package/dist/commands/setup/realtime/templates/subscriptions/newMessage/newMessage.ts.template +1 -1
  185. package/dist/commands/setup/server-file/serverFile.js +1 -1
  186. package/dist/commands/setup/server-file/serverFileHandler.js +18 -10
  187. package/dist/commands/setup/tenancy/authCodemod.js +66 -0
  188. package/dist/commands/setup/tenancy/dbCodemod.js +64 -0
  189. package/dist/commands/setup/tenancy/graphqlCodemod.js +88 -0
  190. package/dist/commands/setup/tenancy/preflight.js +49 -0
  191. package/dist/commands/setup/tenancy/schemaPrisma.js +81 -0
  192. package/dist/commands/setup/tenancy/signupCodemod.js +153 -0
  193. package/dist/commands/setup/tenancy/templates/InvitePage.tsx.template +63 -0
  194. package/dist/commands/setup/tenancy/templates/OrgScope.tsx.template +40 -0
  195. package/dist/commands/setup/tenancy/templates/ensureDefaultOrganizations.dataMigration.ts.template +39 -0
  196. package/dist/commands/setup/tenancy/templates/organizations.scenarios.ts.template +59 -0
  197. package/dist/commands/setup/tenancy/templates/organizations.sdl.ts.template +89 -0
  198. package/dist/commands/setup/tenancy/templates/organizations.test.ts.template +389 -0
  199. package/dist/commands/setup/tenancy/templates/organizations.ts.template +394 -0
  200. package/dist/commands/setup/tenancy/templates/requireMembership.test.ts.template +35 -0
  201. package/dist/commands/setup/tenancy/templates/requireMembership.ts.template +25 -0
  202. package/dist/commands/setup/tenancy/tenancy.js +30 -0
  203. package/dist/commands/setup/tenancy/tenancyHandler.js +425 -0
  204. package/dist/commands/setup/ui/helpers/helpers.js +5 -1
  205. package/dist/commands/setup/ui/libraries/chakra-uiHandler.js +16 -8
  206. package/dist/commands/setup/ui/libraries/mantineHandler.js +26 -16
  207. package/dist/commands/setup/ui/libraries/tailwindcssHandler.js +40 -29
  208. package/dist/commands/setup/uploads/schemaPrisma.js +41 -0
  209. package/dist/commands/setup/uploads/serverFile.js +151 -0
  210. package/dist/commands/setup/uploads/templates/requireUploadToken.ts.template +15 -0
  211. package/dist/commands/setup/uploads/templates/srcLibUploads.ts.template +23 -24
  212. package/dist/commands/setup/uploads/templates/uploads.sdl.ts.template +79 -0
  213. package/dist/commands/setup/uploads/templates/uploads.ts.template +89 -0
  214. package/dist/commands/setup/uploads/templates/withDataUri.ts.template +14 -0
  215. package/dist/commands/setup/uploads/templates/withSignedUrl.ts.template +16 -0
  216. package/dist/commands/setup/uploads/uploads.js +49 -7
  217. package/dist/commands/setup/uploads/uploadsHandler.js +266 -72
  218. package/dist/commands/setup.js +5 -4
  219. package/dist/commands/studio.js +1 -1
  220. package/dist/commands/studioHandler.js +2 -2
  221. package/dist/commands/test/datasourceWarning.js +42 -0
  222. package/dist/commands/test/testHandler.js +104 -0
  223. package/dist/commands/test/viteVersionCheck.js +75 -0
  224. package/dist/commands/test.js +16 -19
  225. package/dist/commands/type-check.js +2 -1
  226. package/dist/commands/type-checkHandler.js +25 -18
  227. package/dist/commands/upgrade/preUpgradeScripts.js +11 -11
  228. package/dist/commands/upgrade/upgrade.js +4 -2
  229. package/dist/commands/upgrade/upgradeHandler.js +97 -73
  230. package/dist/index.js +15 -11
  231. package/dist/lib/background.js +22 -1
  232. package/dist/lib/configureStorybook.js +2 -2
  233. package/dist/lib/exec.js +68 -63
  234. package/dist/lib/exit.js +20 -5
  235. package/dist/lib/extendFile.js +23 -13
  236. package/dist/lib/generatePrismaClient.js +48 -12
  237. package/dist/lib/index.js +137 -106
  238. package/dist/lib/loadEnvFiles.js +1 -1
  239. package/dist/lib/locking.js +8 -4
  240. package/dist/lib/merge/algorithms.js +4 -1
  241. package/dist/lib/merge/index.js +78 -41
  242. package/dist/lib/merge/semanticIdentity.js +18 -6
  243. package/dist/lib/merge/strategy.js +86 -36
  244. package/dist/lib/packages.js +23 -13
  245. package/dist/lib/plugin.js +13 -7
  246. package/dist/lib/pluralHelpers.js +6 -2
  247. package/dist/lib/project.js +3 -1
  248. package/dist/lib/rollback.js +7 -7
  249. package/dist/lib/schemaHelpers.js +16 -19
  250. package/dist/lib/test.js +20 -5
  251. package/dist/lib/updateCheck.js +47 -18
  252. package/dist/middleware/checkNodeVersion.js +9 -4
  253. package/dist/middleware/{detectProjectRxVersion.js → detectProjectCedarVersion.js} +2 -2
  254. package/dist/plugin.js +18 -12
  255. package/dist/telemetry/exporter.js +12 -5
  256. package/dist/telemetry/index.js +4 -3
  257. package/dist/telemetry/resource.js +9 -12
  258. package/dist/telemetry/send.js +14 -10
  259. package/dist/testLib/cells.js +5 -3
  260. package/package.json +44 -41
  261. package/LICENSE +0 -21
  262. package/dist/commands/consoleHandler.js +0 -68
  263. package/dist/commands/setup/tsconfig/tsconfig.js +0 -25
  264. package/dist/commands/setup/tsconfig/tsconfigHandler.js +0 -59
  265. package/dist/commands/setup/uploads/dbCodemod.js +0 -28
  266. package/dist/commands/setup/uploads/templates/signedUrl.ts.template +0 -21
  267. package/dist/commands/setup/vite/templates/vite.config.ts.template +0 -19
  268. package/dist/commands/setup/vite/vite.js +0 -38
  269. package/dist/commands/setup/vite/viteHandler.js +0 -83
  270. package/dist/commands/testEsm.js +0 -36
  271. package/dist/commands/testHandler.js +0 -137
  272. package/dist/commands/testHandlerEsm.js +0 -85
  273. package/dist/commands/ts-to-js.js +0 -20
  274. package/dist/lib/cedarPluralize.js +0 -56
  275. package/dist/lib/colors.js +0 -18
  276. package/dist/testLib/getFilesWithPattern.js +0 -21
  277. /package/dist/{index.d.js → global.d.js} +0 -0
@@ -1,23 +1,28 @@
1
- import fs from "node:fs";
2
1
  import path from "node:path";
3
2
  import { paramCase } from "change-case";
4
3
  import { Listr } from "listr2";
5
4
  import { terminalLink } from "termi-link";
6
- import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
5
+ import { colors as c } from "@cedarjs/cli-helpers/colors";
6
+ import { formatCedarCommand } from "@cedarjs/cli-helpers/packageManager/display";
7
+ import { recordTelemetryAttributes } from "@cedarjs/cli-helpers/telemetry";
7
8
  import { getDataMigrationsPath } from "@cedarjs/project-config";
8
- import c from "../../../lib/colors.js";
9
- import { getPaths, writeFilesTask } from "../../../lib/index.js";
9
+ import {
10
+ generateTemplate,
11
+ getPaths,
12
+ writeFilesTask
13
+ } from "../../../lib/index.js";
10
14
  import { prepareForRollback } from "../../../lib/rollback.js";
11
15
  import { validateName } from "../helpers.js";
12
- import { getYargsDefaults } from "../yargsCommandHelpers.js";
13
- const POST_RUN_INSTRUCTIONS = `Next steps...
16
+ function getPostRunInstructions() {
17
+ const text = c.warning("After writing your migration, you can run it with:");
18
+ const command2 = formatCedarCommand(["dataMigrate", "up"]);
19
+ return `Next steps...
14
20
 
15
- ${c.warning(
16
- "After writing your migration, you can run it with:"
17
- )}
21
+ ${text}
18
22
 
19
- yarn cedar dataMigrate up
23
+ ${command2}
20
24
  `;
25
+ }
21
26
  const TEMPLATE_PATHS = {
22
27
  js: path.resolve(
23
28
  import.meta.dirname,
@@ -40,30 +45,42 @@ const files = async ({ name, typescript }) => {
40
45
  getPaths().api.prismaConfig
41
46
  );
42
47
  const outputPath = path.join(dataMigrationsPath, outputFilename);
48
+ const prismaImportSource = "src/lib/db";
43
49
  return {
44
- [outputPath]: fs.readFileSync(TEMPLATE_PATHS[extension]).toString()
50
+ [outputPath]: await generateTemplate(TEMPLATE_PATHS[extension], {
51
+ name,
52
+ prismaImportSource
53
+ })
45
54
  };
46
55
  };
47
56
  const command = "data-migration <name>";
48
57
  const aliases = ["dataMigration", "dm"];
49
58
  const description = "Generate a data migration";
50
59
  const builder = (yargs) => {
51
- yargs.positional("name", {
60
+ return yargs.positional("name", {
52
61
  description: "A descriptor of what this data migration does",
53
- type: "string"
62
+ type: "string",
63
+ demandOption: true
54
64
  }).option("rollback", {
55
65
  description: "Revert all generator actions if an error occurs",
56
66
  type: "boolean",
57
67
  default: true
68
+ }).option("force", {
69
+ alias: "f",
70
+ default: false,
71
+ description: "Overwrite existing files",
72
+ type: "boolean"
73
+ }).option("typescript", {
74
+ alias: "ts",
75
+ default: false,
76
+ description: "Generate TypeScript files",
77
+ type: "boolean"
58
78
  }).epilogue(
59
79
  `Also see the ${terminalLink(
60
80
  "CedarJS CLI Reference",
61
81
  "https://cedarjs.com/docs/cli-commands#generate-datamigration"
62
82
  )}`
63
83
  );
64
- Object.entries(getYargsDefaults()).forEach(([option, config]) => {
65
- yargs.option(option, config);
66
- });
67
84
  };
68
85
  const handler = async (args) => {
69
86
  recordTelemetryAttributes({
@@ -83,7 +100,7 @@ const handler = async (args) => {
83
100
  {
84
101
  title: "Next steps...",
85
102
  task: (_ctx, task) => {
86
- task.title = POST_RUN_INSTRUCTIONS;
103
+ task.title = getPostRunInstructions();
87
104
  }
88
105
  }
89
106
  ].filter(Boolean),
@@ -95,7 +112,7 @@ const handler = async (args) => {
95
112
  }
96
113
  await tasks.run();
97
114
  } catch (e) {
98
- console.log(c.error(e.message));
115
+ console.log(c.error(e instanceof Error ? e.message : String(e)));
99
116
  process.exit(1);
100
117
  }
101
118
  };
@@ -105,5 +122,6 @@ export {
105
122
  command,
106
123
  description,
107
124
  files,
125
+ getPostRunInstructions,
108
126
  handler
109
127
  };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @typedef { import("@prisma/client").PrismaClient } PrismaClient
2
+ * @typedef { import("${prismaImportSource}").PrismaClient } PrismaClient
3
3
  * @param {{db: PrismaClient}} db
4
4
  */
5
5
  export default async ({ db }) => {
@@ -1,4 +1,4 @@
1
- import type { PrismaClient } from '@prisma/client'
1
+ import type { PrismaClient } from '${prismaImportSource}'
2
2
 
3
3
  export default async ({ db }: { db: PrismaClient }) => {
4
4
  // Migration here...
@@ -45,6 +45,7 @@ const builder = (yargs) => {
45
45
  Object.entries(getYargsDefaults()).forEach(([option, config]) => {
46
46
  yargs.option(option, config);
47
47
  });
48
+ return yargs;
48
49
  };
49
50
  const handler = createHandler("dbAuth");
50
51
  export {
@@ -2,11 +2,12 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { ListrEnquirerPromptAdapter } from "@listr2/prompt-adapter-enquirer";
4
4
  import { camelCase } from "camel-case";
5
- import execa from "execa";
6
5
  import { Listr } from "listr2";
7
6
  import { titleCase } from "title-case";
8
- import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
9
- import c from "../../../lib/colors.js";
7
+ import { colors as c } from "@cedarjs/cli-helpers/colors";
8
+ import { formatCedarCommand } from "@cedarjs/cli-helpers/packageManager/display";
9
+ import { runBinSync } from "@cedarjs/cli-helpers/packageManager/exec";
10
+ import { recordTelemetryAttributes } from "@cedarjs/cli-helpers/telemetry";
10
11
  import {
11
12
  addRoutesToRouterTask,
12
13
  addScaffoldImport,
@@ -37,7 +38,11 @@ function getPostInstallMessage(isDbAuthSetup2) {
37
38
  " logged in. Also take a look in the onSubmit() functions in ForgotPasswordPage",
38
39
  " and ResetPasswordPage to change where the user redirects to after submitting",
39
40
  " those forms.\n",
40
- !isDbAuthSetup2 && " Oh, and if you haven't already, add the necessary dbAuth functions and\n app setup by running:\n\n yarn cedar setup auth dbAuth\n",
41
+ !isDbAuthSetup2 && ` Oh, and if you haven't already, add the necessary dbAuth functions and
42
+ app setup by running:
43
+
44
+ ${formatCedarCommand(["setup", "auth", "dbAuth"])}
45
+ `,
41
46
  " Happy authenticating!"
42
47
  ].filter(Boolean).join("\n");
43
48
  }
@@ -56,24 +61,29 @@ function getPostInstallWebauthnMessage(isDbAuthSetup2) {
56
61
  " logged in. Also take a look in the onSubmit() functions in ForgotPasswordPage",
57
62
  " and ResetPasswordPage to change where the user redirects to after submitting",
58
63
  " those forms.\n",
59
- !isDbAuthSetup2 && " Oh, and if you haven't already, add the necessary dbAuth functions and\n app setup by running:\n\n yarn cedar setup auth dbAuth\n",
64
+ !isDbAuthSetup2 && ` Oh, and if you haven't already, add the necessary dbAuth functions and
65
+ app setup by running:
66
+
67
+ ${formatCedarCommand(["setup", "auth", "dbAuth"])}
68
+ `,
60
69
  " Happy authenticating!"
61
70
  ].filter(Boolean).join("\n");
62
71
  }
63
72
  const files = async ({
64
- _tests,
65
73
  typescript,
66
74
  skipForgot,
67
75
  skipLogin,
68
76
  skipReset,
69
77
  skipSignup,
70
78
  webauthn,
79
+ oauth,
71
80
  usernameLabel,
72
81
  passwordLabel
73
82
  }) => {
74
- const files2 = [];
83
+ const filesList = [];
75
84
  usernameLabel = usernameLabel || "username";
76
85
  passwordLabel = passwordLabel || "password";
86
+ const oauthEnabled = oauth ?? isOAuthEnabled();
77
87
  const templateVars = {
78
88
  usernameLowerCase: usernameLabel.toLowerCase(),
79
89
  usernameCamelCase: camelCase(usernameLabel),
@@ -83,7 +93,7 @@ const files = async ({
83
93
  passwordTitleCase: titleCase(passwordLabel)
84
94
  };
85
95
  if (!skipForgot) {
86
- files2.push(
96
+ filesList.push(
87
97
  await templateForComponentFile({
88
98
  name: "ForgotPassword",
89
99
  suffix: "Page",
@@ -96,20 +106,20 @@ const files = async ({
96
106
  );
97
107
  }
98
108
  if (!skipLogin) {
99
- files2.push(
109
+ filesList.push(
100
110
  await templateForComponentFile({
101
111
  name: "Login",
102
112
  suffix: "Page",
103
113
  extension: typescript ? ".tsx" : ".jsx",
104
114
  webPathSection: "pages",
105
115
  generator: "dbAuth",
106
- templatePath: webauthn ? "login.webAuthn.tsx.template" : "login.tsx.template",
116
+ templatePath: loginTemplatePath(webauthn, oauthEnabled),
107
117
  templateVars
108
118
  })
109
119
  );
110
120
  }
111
121
  if (!skipReset) {
112
- files2.push(
122
+ filesList.push(
113
123
  await templateForComponentFile({
114
124
  name: "ResetPassword",
115
125
  suffix: "Page",
@@ -122,19 +132,19 @@ const files = async ({
122
132
  );
123
133
  }
124
134
  if (!skipSignup) {
125
- files2.push(
135
+ filesList.push(
126
136
  await templateForComponentFile({
127
137
  name: "Signup",
128
138
  suffix: "Page",
129
139
  extension: typescript ? ".tsx" : ".jsx",
130
140
  webPathSection: "pages",
131
141
  generator: "dbAuth",
132
- templatePath: "signup.tsx.template",
142
+ templatePath: oauthEnabled ? "signup.oauth.tsx.template" : "signup.tsx.template",
133
143
  templateVars
134
144
  })
135
145
  );
136
146
  }
137
- if (files2.length === 0) {
147
+ if (filesList.length === 0) {
138
148
  console.info(c.error("\nNo files to generate.\n"));
139
149
  process.exit(0);
140
150
  }
@@ -147,25 +157,27 @@ const files = async ({
147
157
  ),
148
158
  { name: "scaffold" }
149
159
  );
150
- files2.push([scaffoldOutputPath, scaffoldTemplate]);
160
+ filesList.push([scaffoldOutputPath, scaffoldTemplate]);
151
161
  }
152
- return files2.reduce(async (accP, [outputPath, content]) => {
153
- const acc = await accP;
154
- let template = content;
155
- if (outputPath.match(/\.[jt]sx?/) && !typescript) {
156
- template = await transformTSToJS(outputPath, content);
157
- }
158
- return {
159
- [outputPath]: template,
160
- ...acc
161
- };
162
- }, Promise.resolve({}));
162
+ return filesList.reduce(
163
+ async (accP, [outputPath, content]) => {
164
+ const acc = await accP;
165
+ let template = content;
166
+ if (outputPath.match(/\.[jt]sx?/) && !typescript) {
167
+ template = await transformTSToJS(outputPath, content);
168
+ }
169
+ return {
170
+ [outputPath]: template,
171
+ ...acc
172
+ };
173
+ },
174
+ Promise.resolve({})
175
+ );
163
176
  };
164
177
  const tasks = ({
165
178
  enquirer,
166
179
  listr2,
167
180
  force,
168
- tests,
169
181
  typescript,
170
182
  skipForgot,
171
183
  skipLogin,
@@ -276,7 +288,6 @@ const tasks = ({
276
288
  title: "Creating pages...",
277
289
  task: async () => {
278
290
  const filesObj = await files({
279
- tests,
280
291
  typescript,
281
292
  skipForgot,
282
293
  skipLogin,
@@ -304,7 +315,7 @@ const tasks = ({
304
315
  {
305
316
  title: "Generate types...",
306
317
  task: () => {
307
- execa.commandSync("yarn cedar g types");
318
+ runBinSync("cedar", ["g", "types"]);
308
319
  }
309
320
  },
310
321
  {
@@ -314,7 +325,7 @@ const tasks = ({
314
325
  }
315
326
  ],
316
327
  {
317
- silentRendererCondition: () => listr2?.silentRendererCondition,
328
+ silentRendererCondition: () => listr2?.silentRendererCondition ?? false,
318
329
  rendererOptions: { collapseSubtasks: false },
319
330
  ctx: { enquirer },
320
331
  exitOnError: true
@@ -328,7 +339,7 @@ const handler = async (yargs) => {
328
339
  skipLogin: yargs.skipLogin,
329
340
  skipReset: yargs.skipReset,
330
341
  skipSignup: yargs.skipSignup,
331
- webauthn: yargs.webauthn,
342
+ webauthn: yargs.webauthn ?? void 0,
332
343
  force: yargs.force,
333
344
  rollback: yargs.rollback
334
345
  });
@@ -340,10 +351,11 @@ const handler = async (yargs) => {
340
351
  await t.run();
341
352
  console.log("");
342
353
  console.log(
343
- yargs.webauthn || t.ctx.webauthn ? getPostInstallWebauthnMessage(isDbAuthSetup()) : getPostInstallMessage(isDbAuthSetup())
354
+ yargs.webauthn || t.ctx?.webauthn ? getPostInstallWebauthnMessage(isDbAuthSetup()) : getPostInstallMessage(isDbAuthSetup())
344
355
  );
345
356
  } catch (e) {
346
- console.log(c.error(e.message));
357
+ const msg = e instanceof Error ? e.message : String(e);
358
+ console.log(c.error(msg));
347
359
  }
348
360
  };
349
361
  function isDbAuthSetup() {
@@ -357,7 +369,7 @@ function isDbAuthSetup() {
357
369
  "auth." + webAuthExtension
358
370
  );
359
371
  return /^import (.*) from ['"]@cedarjs\/auth-dbauth-web['"]/m.test(
360
- fs.readFileSync(webAuthPath)
372
+ fs.readFileSync(webAuthPath, "utf-8")
361
373
  );
362
374
  }
363
375
  return false;
@@ -369,6 +381,23 @@ function isWebAuthnEnabled() {
369
381
  );
370
382
  return webPackageJson.includes('"@simplewebauthn/browser": ');
371
383
  }
384
+ function isOAuthEnabled() {
385
+ const apiPackageJsonPath = path.join(getPaths().base, "api", "package.json");
386
+ if (!fs.existsSync(apiPackageJsonPath)) {
387
+ return false;
388
+ }
389
+ const apiPackageJson = fs.readFileSync(apiPackageJsonPath, "utf-8");
390
+ return apiPackageJson.includes('"@cedarjs/auth-dbauth-oauth": ');
391
+ }
392
+ function loginTemplatePath(webauthn, oauth) {
393
+ if (webauthn) {
394
+ return "login.webAuthn.tsx.template";
395
+ }
396
+ if (oauth) {
397
+ return "login.oauth.tsx.template";
398
+ }
399
+ return "login.tsx.template";
400
+ }
372
401
  export {
373
402
  files,
374
403
  handler
@@ -0,0 +1,164 @@
1
+ import { useEffect, useRef } from 'react'
2
+
3
+ import {
4
+ Form,
5
+ Label,
6
+ TextField,
7
+ PasswordField,
8
+ Submit,
9
+ FieldError,
10
+ } from '@cedarjs/forms'
11
+ import { Link, navigate, routes } from '@cedarjs/router'
12
+ import { Metadata } from '@cedarjs/web'
13
+ import { toast, Toaster } from '@cedarjs/web/toast'
14
+
15
+ import { getOAuthUrl, getOAuthError } from '@cedarjs/auth-dbauth-web/oauth'
16
+
17
+ import { useAuth } from 'src/auth'
18
+
19
+ const LoginPage = () => {
20
+ const { isAuthenticated, logIn } = useAuth()
21
+
22
+ useEffect(() => {
23
+ if (isAuthenticated) {
24
+ navigate(routes.home())
25
+ }
26
+ }, [isAuthenticated])
27
+
28
+ // Surface an error that the OAuth provider redirect sent back, e.g.
29
+ // after the user cancels the provider's consent screen.
30
+ useEffect(() => {
31
+ const oauthError = getOAuthError(window.location.search)
32
+
33
+ if (oauthError) {
34
+ toast.error('Could not log in: ' + oauthError)
35
+ }
36
+ }, [])
37
+
38
+ const ${usernameCamelCase}Ref = useRef<HTMLInputElement>(null)
39
+ useEffect(() => {
40
+ ${usernameCamelCase}Ref.current?.focus()
41
+ }, [])
42
+
43
+ const onSubmit = async (data: Record<string, string>) => {
44
+ const response = await logIn({ username: data.${usernameCamelCase}, password: data.${passwordCamelCase} })
45
+
46
+ if (response.message) {
47
+ toast(response.message)
48
+ } else if (response.error) {
49
+ toast.error(response.error)
50
+ } else {
51
+ toast.success('Welcome back!')
52
+ }
53
+ }
54
+
55
+ return (
56
+ <>
57
+ <Metadata title="Login" />
58
+
59
+ <main className="rw-main">
60
+ <Toaster toastOptions={{ className: 'rw-toast', duration: 6000 }} />
61
+ <div className="rw-scaffold rw-login-container">
62
+ <div className="rw-segment">
63
+ <header className="rw-segment-header">
64
+ <h2 className="rw-heading rw-heading-secondary">Login</h2>
65
+ </header>
66
+
67
+ <div className="rw-segment-main">
68
+ <div className="rw-form-wrapper">
69
+ <Form onSubmit={onSubmit} className="rw-form-wrapper">
70
+ <Label
71
+ name="${usernameCamelCase}"
72
+ className="rw-label"
73
+ errorClassName="rw-label rw-label-error"
74
+ >
75
+ ${usernameTitleCase}
76
+ </Label>
77
+ <TextField
78
+ name="${usernameCamelCase}"
79
+ className="rw-input"
80
+ errorClassName="rw-input rw-input-error"
81
+ ref={${usernameCamelCase}Ref}
82
+ validation={{
83
+ required: {
84
+ value: true,
85
+ message: '${usernameTitleCase} is required',
86
+ },
87
+ }}
88
+ />
89
+
90
+ <FieldError name="${usernameCamelCase}" className="rw-field-error" />
91
+
92
+ <Label
93
+ name="${passwordCamelCase}"
94
+ className="rw-label"
95
+ errorClassName="rw-label rw-label-error"
96
+ >
97
+ ${passwordTitleCase}
98
+ </Label>
99
+ <PasswordField
100
+ name="${passwordCamelCase}"
101
+ className="rw-input"
102
+ errorClassName="rw-input rw-input-error"
103
+ autoComplete="current-password"
104
+ validation={{
105
+ required: {
106
+ value: true,
107
+ message: '${passwordTitleCase} is required',
108
+ },
109
+ }}
110
+ />
111
+
112
+ <div className="rw-forgot-link">
113
+ <Link
114
+ to={routes.forgotPassword()}
115
+ className="rw-forgot-link"
116
+ >
117
+ Forgot ${passwordTitleCase}?
118
+ </Link>
119
+ </div>
120
+
121
+ <FieldError name="${passwordCamelCase}" className="rw-field-error" />
122
+
123
+ <div className="rw-button-group">
124
+ <Submit className="rw-button rw-button-blue">Login</Submit>
125
+ </div>
126
+ </Form>
127
+
128
+ {/*
129
+ * OAuth login buttons. Delete the ones for providers you
130
+ * haven't configured in `cedar setup auth dbAuth --oauth`.
131
+ * Each link is a full-page navigation to the provider's
132
+ * authorize route — it must not be turned into a fetch/XHR
133
+ * call.
134
+ */}
135
+ <div className="rw-button-group">
136
+ <a
137
+ href={getOAuthUrl('google', { flow: 'login' })}
138
+ className="rw-button rw-button-blue"
139
+ >
140
+ Continue with Google
141
+ </a>
142
+ <a
143
+ href={getOAuthUrl('github', { flow: 'login' })}
144
+ className="rw-button rw-button-blue"
145
+ >
146
+ Continue with GitHub
147
+ </a>
148
+ </div>
149
+ </div>
150
+ </div>
151
+ </div>
152
+ <div className="rw-login-link">
153
+ <span>Don&apos;t have an account?</span>{' '}
154
+ <Link to={routes.signup()} className="rw-link">
155
+ Sign up!
156
+ </Link>
157
+ </div>
158
+ </div>
159
+ </main>
160
+ </>
161
+ )
162
+ }
163
+
164
+ export default LoginPage
@@ -0,0 +1,147 @@
1
+ import { useEffect, useRef } from 'react'
2
+
3
+ import {
4
+ Form,
5
+ Label,
6
+ TextField,
7
+ PasswordField,
8
+ FieldError,
9
+ Submit,
10
+ } from '@cedarjs/forms'
11
+ import { Link, navigate, routes } from '@cedarjs/router'
12
+ import { Metadata } from '@cedarjs/web'
13
+ import { toast, Toaster } from '@cedarjs/web/toast'
14
+
15
+ import { getOAuthUrl } from '@cedarjs/auth-dbauth-web/oauth'
16
+
17
+ import { useAuth } from 'src/auth'
18
+
19
+ const SignupPage = () => {
20
+ const { isAuthenticated, signUp } = useAuth()
21
+
22
+ useEffect(() => {
23
+ if (isAuthenticated) {
24
+ navigate(routes.home())
25
+ }
26
+ }, [isAuthenticated])
27
+
28
+ // focus on ${usernameLowerCase} box on page load
29
+ const ${usernameCamelCase}Ref = useRef<HTMLInputElement>(null)
30
+ useEffect(() => {
31
+ ${usernameCamelCase}Ref.current?.focus()
32
+ }, [])
33
+
34
+ const onSubmit = async (data: Record<string, string>) => {
35
+ const response = await signUp({ username: data.${usernameCamelCase}, password: data.${passwordCamelCase} })
36
+
37
+ if (response.message) {
38
+ toast(response.message)
39
+ } else if (response.error) {
40
+ toast.error(response.error)
41
+ } else {
42
+ // user is signed in automatically
43
+ toast.success('Welcome!')
44
+ }
45
+ }
46
+
47
+ return (
48
+ <>
49
+ <Metadata title="Signup" />
50
+
51
+ <main className="rw-main">
52
+ <Toaster toastOptions={{ className: 'rw-toast', duration: 6000 }} />
53
+ <div className="rw-scaffold rw-login-container">
54
+ <div className="rw-segment">
55
+ <header className="rw-segment-header">
56
+ <h2 className="rw-heading rw-heading-secondary">Signup</h2>
57
+ </header>
58
+
59
+ <div className="rw-segment-main">
60
+ <div className="rw-form-wrapper">
61
+ <Form onSubmit={onSubmit} className="rw-form-wrapper">
62
+ <Label
63
+ name="${usernameCamelCase}"
64
+ className="rw-label"
65
+ errorClassName="rw-label rw-label-error"
66
+ >
67
+ ${usernameTitleCase}
68
+ </Label>
69
+ <TextField
70
+ name="${usernameCamelCase}"
71
+ className="rw-input"
72
+ errorClassName="rw-input rw-input-error"
73
+ ref={${usernameCamelCase}Ref}
74
+ validation={{
75
+ required: {
76
+ value: true,
77
+ message: '${usernameTitleCase} is required',
78
+ },
79
+ }}
80
+ />
81
+ <FieldError name="${usernameCamelCase}" className="rw-field-error" />
82
+
83
+ <Label
84
+ name="${passwordCamelCase}"
85
+ className="rw-label"
86
+ errorClassName="rw-label rw-label-error"
87
+ >
88
+ ${passwordTitleCase}
89
+ </Label>
90
+ <PasswordField
91
+ name="${passwordCamelCase}"
92
+ className="rw-input"
93
+ errorClassName="rw-input rw-input-error"
94
+ autoComplete="current-password"
95
+ validation={{
96
+ required: {
97
+ value: true,
98
+ message: '${passwordTitleCase} is required',
99
+ },
100
+ }}
101
+ />
102
+ <FieldError name="${passwordCamelCase}" className="rw-field-error" />
103
+
104
+ <div className="rw-button-group">
105
+ <Submit className="rw-button rw-button-blue">
106
+ Sign Up
107
+ </Submit>
108
+ </div>
109
+ </Form>
110
+
111
+ {/*
112
+ * OAuth signup buttons. Delete the ones for providers you
113
+ * haven't configured in `cedar setup auth dbAuth --oauth`.
114
+ * Each link is a full-page navigation to the provider's
115
+ * authorize route — it must not be turned into a fetch/XHR
116
+ * call.
117
+ */}
118
+ <div className="rw-button-group">
119
+ <a
120
+ href={getOAuthUrl('google', { flow: 'signup' })}
121
+ className="rw-button rw-button-blue"
122
+ >
123
+ Continue with Google
124
+ </a>
125
+ <a
126
+ href={getOAuthUrl('github', { flow: 'signup' })}
127
+ className="rw-button rw-button-blue"
128
+ >
129
+ Continue with GitHub
130
+ </a>
131
+ </div>
132
+ </div>
133
+ </div>
134
+ </div>
135
+ <div className="rw-login-link">
136
+ <span>Already have an account?</span>{' '}
137
+ <Link to={routes.login()} className="rw-link">
138
+ Log in!
139
+ </Link>
140
+ </div>
141
+ </div>
142
+ </main>
143
+ </>
144
+ )
145
+ }
146
+
147
+ export default SignupPage