@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
@@ -2,13 +2,14 @@ import ansis from "ansis";
2
2
  import boxen from "boxen";
3
3
  import camelcase from "camelcase";
4
4
  import { Listr } from "listr2";
5
- 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";
6
8
  import { generate as generateTypes } from "@cedarjs/internal/dist/generate/generate";
7
9
  import { getConfig } from "@cedarjs/project-config";
8
10
  import { errorTelemetry } from "@cedarjs/telemetry";
9
- import { pluralize } from "../../../lib/cedarPluralize.js";
10
- import c from "../../../lib/colors.js";
11
- import { transformTSToJS, writeFilesTask } from "../../../lib/index.js";
11
+ import { pluralize } from "@cedarjs/utils/cedarPluralize";
12
+ import { transformTSToJS } from "../../../lib/index.js";
12
13
  import {
13
14
  prepareForRollback,
14
15
  addFunctionToRollback
@@ -18,9 +19,14 @@ import {
18
19
  getEnum,
19
20
  verifyModelName
20
21
  } from "../../../lib/schemaHelpers.js";
21
- import { relationsForModel } from "../helpers.js";
22
+ import { redactedModelFields, relationsForModel } from "../helpers.js";
22
23
  import { files as serviceFiles } from "../service/serviceHandler.js";
23
24
  import { templateForFile } from "../yargsHandlerHelpers.js";
25
+ import {
26
+ addStubHeader,
27
+ missingRelatedModels,
28
+ writeFilesWithStubsTask
29
+ } from "./stubFiles.js";
24
30
  const DEFAULT_IGNORE_FIELDS_FOR_INPUT = ["createdAt", "updatedAt"];
25
31
  const missingIdConsoleMessage = () => {
26
32
  const line1 = ansis.bold.yellow("WARNING") + ": Cannot generate CRUD SDL without an `@id` database column.";
@@ -47,12 +53,8 @@ const addFieldGraphQLComment = (field, str) => {
47
53
  const modelFieldToSDL = ({
48
54
  field,
49
55
  required = true,
50
- types = {},
51
56
  docs = false
52
57
  }) => {
53
- if (Object.entries(types).length) {
54
- field.type = field.kind === "object" ? idType(types[field.type]) : field.type;
55
- }
56
58
  const prismaTypeToGraphqlType = {
57
59
  Json: "JSON",
58
60
  Decimal: "Float",
@@ -68,40 +70,45 @@ const modelFieldToSDL = ({
68
70
  return fieldContent;
69
71
  }
70
72
  };
73
+ const modelRedactedFields = (model) => {
74
+ return redactedModelFields(model.fields.map((field) => field.name));
75
+ };
71
76
  const querySDL = (model, docs = false) => {
72
- return model.fields.map((field) => modelFieldToSDL({ field, docs }));
77
+ const redactedFields = modelRedactedFields(model);
78
+ return model.fields.filter((field) => !redactedFields.includes(field.name)).map((field) => modelFieldToSDL({ field, docs }));
73
79
  };
74
- const inputSDL = (model, required, types = {}, docs = false) => {
75
- const ignoredFields = DEFAULT_IGNORE_FIELDS_FOR_INPUT;
80
+ const inputSDL = (model, required, docs = false) => {
81
+ const ignoredFields = [
82
+ ...DEFAULT_IGNORE_FIELDS_FOR_INPUT,
83
+ ...modelRedactedFields(model)
84
+ ];
85
+ const idField = model.fields.find((field) => field.isId);
86
+ if (idField?.default !== void 0) {
87
+ ignoredFields.push(idField.name);
88
+ }
76
89
  return model.fields.filter((field) => {
77
- const idField = model.fields.find((field2) => field2.isId);
78
- if (idField && idField.default) {
79
- ignoredFields.push(idField.name);
80
- }
81
- return ignoredFields.indexOf(field.name) === -1 && field.kind !== "object";
82
- }).map((field) => modelFieldToSDL({ field, required, types, docs }));
90
+ return !ignoredFields.includes(field.name) && field.kind !== "object";
91
+ }).map((field) => modelFieldToSDL({ field, required, docs }));
83
92
  };
84
- const idInputSDL = (idType2, docs) => {
93
+ function idInputSDL(idType2, docs) {
85
94
  if (!Array.isArray(idType2)) {
86
95
  return [];
87
96
  }
88
- return idType2.map(
89
- (field) => modelFieldToSDL({ field, required: true, types: {}, docs })
90
- );
97
+ return idType2.map((field) => modelFieldToSDL({ field, required: true, docs }));
98
+ }
99
+ const createInputSDL = (model, docs = false) => {
100
+ return inputSDL(model, true, docs);
91
101
  };
92
- const createInputSDL = (model, types = {}, docs = false) => {
93
- return inputSDL(model, true, types, docs);
102
+ const updateInputSDL = (model, docs = false) => {
103
+ return inputSDL(model, false, docs);
94
104
  };
95
- const updateInputSDL = (model, types = {}, docs = false) => {
96
- return inputSDL(model, false, types, docs);
97
- };
98
- const idType = (model, crud) => {
99
- if (!crud) {
105
+ function idType(model, crud) {
106
+ if (!crud || !model) {
100
107
  return void 0;
101
108
  }
102
109
  if (model.primaryKey?.fields.length) {
103
110
  const { fields: fieldNames } = model.primaryKey;
104
- return fieldNames.map((name) => model.fields.find((f) => f.name === name));
111
+ return fieldNames.map((name) => model.fields.find((f) => f.name === name)).filter((f) => f !== void 0);
105
112
  }
106
113
  const idField = model.fields.find((field) => field.isId);
107
114
  if (!idField) {
@@ -109,7 +116,7 @@ const idType = (model, crud) => {
109
116
  throw new Error("Failed: Could not generate SDL");
110
117
  }
111
118
  return idField.type;
112
- };
119
+ }
113
120
  const idName = (model, crud) => {
114
121
  if (!crud) {
115
122
  return void 0;
@@ -122,13 +129,13 @@ const idName = (model, crud) => {
122
129
  return idField.name;
123
130
  };
124
131
  const sdlFromSchemaModel = async (name, crud, docs = false) => {
125
- const model = await getSchema(name);
126
- const types = (await Promise.all(
127
- model.fields.filter((field) => field.kind === "object").map(async (field) => {
128
- const model2 = await getSchema(field.type);
129
- return model2;
130
- })
131
- )).reduce((acc, cur) => ({ ...acc, [cur.name]: cur }), {});
132
+ const schemaResult = await getSchema(name);
133
+ if (!schemaResult || !("fields" in schemaResult)) {
134
+ throw new Error(
135
+ `No schema definition found for \`${name}\` in schema.prisma file`
136
+ );
137
+ }
138
+ const model = schemaResult;
132
139
  const enums = (await Promise.all(
133
140
  model.fields.filter((field) => field.kind === "enum").map(async (field) => {
134
141
  const enumDef = await getEnum(field.type);
@@ -142,8 +149,8 @@ const sdlFromSchemaModel = async (name, crud, docs = false) => {
142
149
  modelName,
143
150
  modelDescription,
144
151
  query: querySDL(model, docs).join("\n "),
145
- createInput: createInputSDL(model, types, docs).join("\n "),
146
- updateInput: updateInputSDL(model, types, docs).join("\n "),
152
+ createInput: createInputSDL(model, docs).join("\n "),
153
+ updateInput: updateInputSDL(model, docs).join("\n "),
147
154
  idInput: idInputSDL(idTypeRes, docs).join("\n "),
148
155
  idType: idType(model, crud),
149
156
  idName: idName(model, crud),
@@ -181,6 +188,55 @@ const files = async ({
181
188
  })
182
189
  };
183
190
  };
191
+ const stubFiles = async (models, generatedFor, { docs = false, typescript }) => {
192
+ const generatedFiles = {};
193
+ for (const stubModel of models) {
194
+ const stubModelFiles = await files({
195
+ name: stubModel,
196
+ crud: false,
197
+ docs,
198
+ tests: false,
199
+ typescript
200
+ });
201
+ for (const [stubPath, stubContent] of Object.entries(stubModelFiles)) {
202
+ generatedFiles[stubPath] = addStubHeader({
203
+ content: stubContent,
204
+ stubModel,
205
+ generatedFor
206
+ });
207
+ }
208
+ }
209
+ return generatedFiles;
210
+ };
211
+ const redactedSensitiveFields = async (modelNames) => {
212
+ const redacted = [];
213
+ for (const modelName of modelNames) {
214
+ const model = await getSchema(modelName);
215
+ if (!model || !("fields" in model)) {
216
+ continue;
217
+ }
218
+ for (const fieldName of modelRedactedFields(model)) {
219
+ redacted.push(`${model.name}.${fieldName}`);
220
+ }
221
+ }
222
+ return redacted;
223
+ };
224
+ const printRedactedFieldsNote = (redactedFields) => {
225
+ if (redactedFields.length === 0) {
226
+ return;
227
+ }
228
+ console.log();
229
+ console.log(
230
+ c.warning(
231
+ `The following fields were excluded from the generated SDL because they may contain sensitive data: ${redactedFields.join(", ")}`
232
+ )
233
+ );
234
+ console.log(
235
+ c.warning(
236
+ "If you want to expose any of them through your GraphQL API you can add them to the SDL file manually."
237
+ )
238
+ );
239
+ };
184
240
  const handler = async ({
185
241
  model,
186
242
  crud,
@@ -204,13 +260,21 @@ const handler = async ({
204
260
  });
205
261
  try {
206
262
  const { name } = await verifyModelName({ name: model });
263
+ const missingModels = await missingRelatedModels(name);
264
+ const redactedFields = await redactedSensitiveFields([
265
+ name,
266
+ ...missingModels
267
+ ]);
207
268
  const tasks = new Listr(
208
269
  [
209
270
  {
210
271
  title: "Generating SDL files...",
211
272
  task: async () => {
212
- const f = await files({ name, tests, crud, typescript, docs });
213
- return writeFilesTask(f, { overwriteExisting: force });
273
+ const f = {
274
+ ...await files({ name, tests, crud, typescript, docs }),
275
+ ...await stubFiles(missingModels, name, { typescript, docs })
276
+ };
277
+ return writeFilesWithStubsTask(f, { overwriteExisting: force });
214
278
  }
215
279
  },
216
280
  {
@@ -237,13 +301,38 @@ const handler = async ({
237
301
  prepareForRollback(tasks);
238
302
  }
239
303
  await tasks.run();
304
+ if (missingModels.length > 0) {
305
+ console.log();
306
+ console.log(
307
+ c.info(
308
+ `${name} has relations to models that don't have SDL files of their own yet: ${missingModels.join(", ")}`
309
+ )
310
+ );
311
+ console.log(
312
+ c.info(
313
+ "Read-only SDL stubs were generated for them, since GraphQL type generation fails otherwise."
314
+ )
315
+ );
316
+ console.log(c.info("To replace a stub with a full SDL and service, run"));
317
+ for (const stubModel of missingModels) {
318
+ console.log(
319
+ c.info(` ${formatCedarCommand(["generate", "sdl", stubModel])}`)
320
+ );
321
+ }
322
+ }
323
+ printRedactedFieldsNote(redactedFields);
240
324
  } catch (e) {
241
- errorTelemetry(process.argv, e.message);
242
- console.error(c.error(e.message));
243
- process.exit(e?.exitCode || 1);
325
+ const message = e instanceof Error ? e.message : String(e);
326
+ const exitCode = e instanceof Error && "exitCode" in e && typeof e.exitCode === "number" ? e.exitCode : 1;
327
+ errorTelemetry(process.argv, message);
328
+ console.error(c.error(message));
329
+ process.exit(exitCode);
244
330
  }
245
331
  };
246
332
  export {
247
333
  files,
248
- handler
334
+ handler,
335
+ printRedactedFieldsNote,
336
+ redactedSensitiveFields,
337
+ stubFiles
249
338
  };
@@ -0,0 +1,132 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { Listr } from "listr2";
5
+ import { getPaths } from "@cedarjs/project-config";
6
+ import { writeFile } from "../../../lib/index.js";
7
+ import { getSchema } from "../../../lib/schemaHelpers.js";
8
+ const STUB_HASH_MARKER = "@cedar-generator-stub-hash";
9
+ const STUB_HASH_MARKER_REGEX = new RegExp(
10
+ `^// ${STUB_HASH_MARKER} ([0-9a-f]+)$`,
11
+ "m"
12
+ );
13
+ function stubHash(contents) {
14
+ return crypto.createHash("sha256").update(contents).digest("hex").slice(0, 16);
15
+ }
16
+ function addStubHeader({
17
+ content,
18
+ stubModel,
19
+ generatedFor
20
+ }) {
21
+ const body = "\n\n" + content;
22
+ const marker = `// ${STUB_HASH_MARKER} PLACEHOLDER`;
23
+ const header = [
24
+ `// Generated as a read-only stub by \`cedar generate sdl ${generatedFor}\`,`,
25
+ `// because ${generatedFor} has a relation to ${stubModel}, which had no SDL yet.`,
26
+ `// Run \`cedar generate sdl ${stubModel}\` to replace this stub with the real thing.`,
27
+ `// If you edit this file, the hash below will stop matching and you'll`,
28
+ `// need to pass \`--force\` to overwrite it.`,
29
+ marker
30
+ ].join("\n");
31
+ const contentToHash = header + body;
32
+ const hash = stubHash(contentToHash);
33
+ const finalMarker = `// ${STUB_HASH_MARKER} ${hash}`;
34
+ return (header + body).replace(marker, finalMarker);
35
+ }
36
+ function isPristineStub(contents) {
37
+ const match = STUB_HASH_MARKER_REGEX.exec(contents);
38
+ if (!match) {
39
+ return false;
40
+ }
41
+ const contentToHash = contents.replace(
42
+ match[0],
43
+ `// ${STUB_HASH_MARKER} PLACEHOLDER`
44
+ );
45
+ return stubHash(contentToHash) === match[1];
46
+ }
47
+ function readExistingSdlFiles() {
48
+ const graphqlDir = getPaths().api.graphql;
49
+ if (!fs.existsSync(graphqlDir)) {
50
+ return [];
51
+ }
52
+ const contents = [];
53
+ const dirsToWalk = [graphqlDir];
54
+ while (dirsToWalk.length > 0) {
55
+ const dir = dirsToWalk.shift();
56
+ if (!dir) {
57
+ break;
58
+ }
59
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
60
+ const entryPath = path.join(dir, entry.name);
61
+ if (entry.isDirectory()) {
62
+ dirsToWalk.push(entryPath);
63
+ } else if (/\.sdl\.(js|ts)$/.test(entry.name)) {
64
+ contents.push(fs.readFileSync(entryPath, "utf-8"));
65
+ }
66
+ }
67
+ }
68
+ return contents;
69
+ }
70
+ async function missingRelatedModels(modelName) {
71
+ const existingSdls = readExistingSdlFiles();
72
+ const isDefined = (typeName) => existingSdls.some(
73
+ (sdl) => new RegExp(`\\btype\\s+${typeName}\\b`).test(sdl)
74
+ );
75
+ const seen = /* @__PURE__ */ new Set([modelName]);
76
+ const missing = [];
77
+ const queue = [modelName];
78
+ while (queue.length > 0) {
79
+ const current = queue.shift();
80
+ if (!current) {
81
+ break;
82
+ }
83
+ const model = await getSchema(current);
84
+ if (!model || !("fields" in model)) {
85
+ continue;
86
+ }
87
+ for (const field of model.fields) {
88
+ if (!field.relationName || seen.has(field.type)) {
89
+ continue;
90
+ }
91
+ seen.add(field.type);
92
+ queue.push(field.type);
93
+ if (!isDefined(field.type)) {
94
+ missing.push(field.type);
95
+ }
96
+ }
97
+ }
98
+ return missing;
99
+ }
100
+ function writeFilesWithStubsTask(files, { overwriteExisting = false } = {}) {
101
+ const { base } = getPaths();
102
+ return new Listr(
103
+ Object.entries(files).map(([file, contents]) => ({
104
+ title: `...waiting to write file \`./${path.relative(base, file)}\`...`,
105
+ task: (_ctx, task) => {
106
+ let canOverwrite = overwriteExisting;
107
+ if (!canOverwrite && fs.existsSync(file)) {
108
+ const existingContents = fs.readFileSync(file, "utf-8");
109
+ if (isPristineStub(existingContents)) {
110
+ canOverwrite = true;
111
+ } else if (STUB_HASH_MARKER_REGEX.test(existingContents)) {
112
+ throw new Error(
113
+ `${file} started out as a generated stub, but has since been edited. Use \`--force\` to overwrite it.`
114
+ );
115
+ }
116
+ }
117
+ return writeFile(
118
+ file,
119
+ contents,
120
+ { overwriteExisting: canOverwrite },
121
+ task
122
+ );
123
+ }
124
+ }))
125
+ );
126
+ }
127
+ export {
128
+ addStubHeader,
129
+ isPristineStub,
130
+ missingRelatedModels,
131
+ writeFilesWithStubsTask
132
+ };
@@ -30,6 +30,7 @@ export const schema = gql`
30
30
  <% } %>${singularCamelName}(${idName}: ${idType}!): ${singularPascalName} @requireAuth<% } %>
31
31
  }
32
32
 
33
+ <% if (crud) { %>
33
34
  <% if (docs) { %>
34
35
  """Autogenerated input type of Input${singularPascalName}."""
35
36
  <% } %>
@@ -51,7 +52,7 @@ export const schema = gql`
51
52
  <% } %>
52
53
  input Update${singularPascalName}Input {
53
54
  ${updateInput}
54
- }<% if (crud) { %>
55
+ }
55
56
 
56
57
  <% if (docs) { %>
57
58
  """About mutations"""
@@ -30,6 +30,7 @@ export const schema = gql`
30
30
  <% } %>${singularCamelName}(${idName}: ${idType}!): ${singularPascalName} @requireAuth<% } %>
31
31
  }
32
32
 
33
+ <% if (crud) { %>
33
34
  <% if (docs) { %>
34
35
  """Autogenerated input type of Input${singularPascalName}."""
35
36
  <% } %>
@@ -51,7 +52,7 @@ export const schema = gql`
51
52
  <% } %>
52
53
  input Update${singularPascalName}Input {
53
54
  ${updateInput}
54
- }<% if (crud) { %>
55
+ }
55
56
 
56
57
  <% if (docs) { %>
57
58
  """About mutations"""
@@ -1,29 +1,29 @@
1
1
  import crypto from "node:crypto";
2
2
  import { terminalLink } from "termi-link";
3
- import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
3
+ import { recordTelemetryAttributes } from "@cedarjs/cli-helpers/telemetry";
4
4
  const DEFAULT_LENGTH = 32;
5
5
  const generateSecret = (length = DEFAULT_LENGTH) => {
6
- return crypto.randomBytes(length).toString("base64");
6
+ return crypto.randomBytes(Math.trunc(length)).toString("base64");
7
7
  };
8
8
  const command = "secret";
9
9
  const description = "Generates a secret key using a cryptographically-secure source of entropy";
10
- const builder = (yargs) => yargs.option("length", {
11
- description: "Length of the generated secret",
12
- type: "integer",
13
- required: false,
14
- default: DEFAULT_LENGTH
15
- }).option("raw", {
16
- description: "Prints just the raw secret",
17
- type: "boolean",
18
- required: false,
19
- default: false
20
- }).epilogue(
21
- `Also see the ${terminalLink(
22
- "CedarJS CLI Reference",
23
- "https://cedarjs.com/docs/cli-commands#generate-secret"
24
- )}`
25
- );
26
- const handler = ({ length, raw }) => {
10
+ function builder(yargs) {
11
+ return yargs.option("length", {
12
+ description: "Length of the generated secret",
13
+ type: "number",
14
+ default: DEFAULT_LENGTH
15
+ }).option("raw", {
16
+ description: "Prints just the raw secret",
17
+ type: "boolean",
18
+ default: false
19
+ }).epilogue(
20
+ `Also see the ${terminalLink(
21
+ "CedarJS CLI Reference",
22
+ "https://cedarjs.com/docs/cli-commands#generate-secret"
23
+ )}`
24
+ );
25
+ }
26
+ function handler({ length, raw }) {
27
27
  recordTelemetryAttributes({
28
28
  command: "generate secret",
29
29
  length,
@@ -41,7 +41,7 @@ const handler = ({ length, raw }) => {
41
41
  );
42
42
  console.info("");
43
43
  console.info("Keep it secret, keep it safe!");
44
- };
44
+ }
45
45
  export {
46
46
  DEFAULT_LENGTH,
47
47
  builder,
@@ -5,8 +5,8 @@ import {
5
5
  createHandler,
6
6
  getYargsDefaults
7
7
  } from "../yargsCommandHelpers.js";
8
- const defaults = () => {
9
- const defaults2 = {
8
+ const getDefaultOptions = () => {
9
+ return {
10
10
  ...getYargsDefaults(),
11
11
  tests: {
12
12
  description: "Generate test files",
@@ -18,7 +18,6 @@ const defaults = () => {
18
18
  type: "boolean"
19
19
  }
20
20
  };
21
- return defaults2;
22
21
  };
23
22
  const command = createCommand("service");
24
23
  const description = createDescription("service");
@@ -36,15 +35,16 @@ const builder = (yargs) => {
36
35
  "https://cedarjs.com/docs/cli-commands#generate-service"
37
36
  )}`
38
37
  );
39
- Object.entries(defaults()).forEach(([option, config]) => {
38
+ Object.entries(getDefaultOptions()).forEach(([option, config]) => {
40
39
  yargs.option(option, config);
41
40
  });
41
+ return yargs;
42
42
  };
43
43
  const handler = createHandler("service");
44
44
  export {
45
45
  builder,
46
46
  command,
47
- defaults,
48
47
  description,
48
+ getDefaultOptions,
49
49
  handler
50
50
  };