@cedarjs/cli 7.0.1-next.467 → 7.1.0-rc.32

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 (194) hide show
  1. package/dist/commands/build/buildHandler.js +1 -2
  2. package/dist/commands/build.js +1 -1
  3. package/dist/commands/check.js +1 -2
  4. package/dist/commands/deploy/baremetal/baremetalHandler.js +73 -364
  5. package/dist/commands/deploy/baremetal.js +1 -7
  6. package/dist/commands/deploy/flightcontrolHandler.js +1 -1
  7. package/dist/commands/deploy/helpers/deployHandler.js +1 -1
  8. package/dist/commands/deploy/netlify.js +1 -1
  9. package/dist/commands/deploy/renderHandler.js +1 -1
  10. package/dist/commands/deploy/serverlessHandler.js +1 -2
  11. package/dist/commands/deploy/vercel.js +1 -1
  12. package/dist/commands/destroy/handlerHelpers.js +1 -1
  13. package/dist/commands/destroy/page/pageHandler.js +1 -2
  14. package/dist/commands/destroy/scaffold/scaffoldHandler.js +26 -65
  15. package/dist/commands/destroy/sdl/sdlHandler.js +1 -2
  16. package/dist/commands/dev/devHandler.js +4 -3
  17. package/dist/commands/dev/packageWatchCommands.js +3 -8
  18. package/dist/commands/dev.js +1 -1
  19. package/dist/commands/execHandler.js +1 -2
  20. package/dist/commands/experimental/live-queries/liveQueries.js +1 -1
  21. package/dist/commands/experimental/live-queries/liveQueriesHandler.js +3 -3
  22. package/dist/commands/experimental/setupInngest.js +1 -1
  23. package/dist/commands/experimental/setupInngestHandler.js +1 -1
  24. package/dist/commands/experimental/setupOpentelemetry.js +1 -1
  25. package/dist/commands/experimental/setupOpentelemetryHandler.js +1 -2
  26. package/dist/commands/experimental/setupReactCompiler.js +1 -1
  27. package/dist/commands/experimental/setupReactCompilerHandler.js +4 -4
  28. package/dist/commands/experimental/setupRsc.js +1 -1
  29. package/dist/commands/experimental/setupRscHandler.js +1 -2
  30. package/dist/commands/experimental/setupStreamingSsr.js +1 -1
  31. package/dist/commands/experimental/setupStreamingSsrHandler.js +2 -3
  32. package/dist/commands/generate/cell/cell.js +0 -20
  33. package/dist/commands/generate/cell/cellHandler.js +20 -68
  34. package/dist/commands/generate/cell/templates/cell.tsx.template +2 -21
  35. package/dist/commands/generate/cell/templates/cellList.tsx.template +2 -21
  36. package/dist/commands/generate/cell/templates/test.js.template +1 -1
  37. package/dist/commands/generate/dataMigration/dataMigration.js +1 -2
  38. package/dist/commands/generate/dbAuth/dbAuth.js +2 -6
  39. package/dist/commands/generate/dbAuth/dbAuthHandler.js +17 -80
  40. package/dist/commands/generate/dbAuth/templates/login.webAuthn.tsx.template +12 -20
  41. package/dist/commands/generate/directive/directiveHandler.js +1 -2
  42. package/dist/commands/generate/function/functionHandler.js +1 -2
  43. package/dist/commands/generate/helpers.js +0 -26
  44. package/dist/commands/generate/job/jobHandler.js +1 -2
  45. package/dist/commands/generate/model/modelHandler.js +1 -2
  46. package/dist/commands/generate/ogImage/ogImageHandler.js +1 -2
  47. package/dist/commands/generate/ogImage/templates/ogImage.og.tsx.template +1 -1
  48. package/dist/commands/generate/package/filesTask.js +12 -9
  49. package/dist/commands/generate/package/packageHandler.js +4 -3
  50. package/dist/commands/generate/package/templates/tsconfig.json.template +0 -1
  51. package/dist/commands/generate/page/pageHandler.js +1 -2
  52. package/dist/commands/generate/realtime/realtime.js +1 -1
  53. package/dist/commands/generate/realtime/realtimeHandler.js +9 -2
  54. package/dist/commands/generate/realtime/templates/liveQueries/blank/blank.service.ts.template +4 -12
  55. package/dist/commands/generate/realtime/templates/subscriptions/blank/blank.service.ts.template +2 -2
  56. package/dist/commands/generate/realtime/templates/subscriptions/blank/blank.ts.template +4 -4
  57. package/dist/commands/generate/scaffold/scaffold.js +1 -1
  58. package/dist/commands/generate/scaffold/scaffoldHandler.js +49 -93
  59. package/dist/commands/generate/scaffold/templates/assets/scaffold.tailwind.css.template +7 -12
  60. package/dist/commands/generate/scaffold/templates/components/EditNameCell.tsx.template +7 -5
  61. package/dist/commands/generate/scaffold/templates/components/NameForm.tsx.template +9 -10
  62. package/dist/commands/generate/scaffold/templates/lib/formatters.test.tsx.template +0 -11
  63. package/dist/commands/generate/scaffold/templates/lib/formatters.tsx.template +4 -16
  64. package/dist/commands/generate/script/scriptHandler.js +1 -2
  65. package/dist/commands/generate/script/templates/tsconfig.json.template +0 -1
  66. package/dist/commands/generate/sdl/sdlHandler.js +4 -10
  67. package/dist/commands/generate/secret/secret.js +1 -1
  68. package/dist/commands/generate/service/serviceHandler.js +49 -79
  69. package/dist/commands/generate/service/templates/service.ts.template +13 -40
  70. package/dist/commands/generate/service/templates/test.ts.template +6 -8
  71. package/dist/commands/generate/yargsCommandHelpers.js +1 -1
  72. package/dist/commands/generate/yargsHandlerHelpers.js +1 -2
  73. package/dist/commands/generate.js +1 -1
  74. package/dist/commands/info.js +1 -1
  75. package/dist/commands/jobsHandler.js +3 -5
  76. package/dist/commands/lint.js +1 -1
  77. package/dist/commands/prerenderHandler.js +4 -11
  78. package/dist/commands/prismaHandler.js +2 -7
  79. package/dist/commands/record/init.js +1 -1
  80. package/dist/commands/serve.js +1 -2
  81. package/dist/commands/setup/auth/auth.js +4 -2
  82. package/dist/commands/setup/cache/cache.js +1 -1
  83. package/dist/commands/setup/cache/cacheHandler.js +1 -2
  84. package/dist/commands/setup/cache/templates/memcached.ts.template +17 -14
  85. package/dist/commands/setup/cache/templates/redis.ts.template +20 -12
  86. package/dist/commands/setup/database/postgres.js +1 -1
  87. package/dist/commands/setup/database/postgresHandler.js +1 -3
  88. package/dist/commands/setup/deploy/providers/baremetal.js +0 -7
  89. package/dist/commands/setup/deploy/providers/baremetalHandler.js +21 -130
  90. package/dist/commands/setup/deploy/providers/coherence.js +1 -1
  91. package/dist/commands/setup/deploy/providers/coherenceHandler.js +6 -7
  92. package/dist/commands/setup/deploy/providers/flightcontrolHandler.js +1 -2
  93. package/dist/commands/setup/deploy/providers/netlifyHandler.js +1 -2
  94. package/dist/commands/setup/deploy/providers/renderHandler.js +1 -2
  95. package/dist/commands/setup/deploy/providers/serverlessHandler.js +1 -2
  96. package/dist/commands/setup/deploy/providers/universalDeployHandler.js +6 -4
  97. package/dist/commands/setup/deploy/providers/vercelHandler.js +1 -2
  98. package/dist/commands/setup/deploy/templates/baremetal.js +9 -119
  99. package/dist/commands/setup/deploy/templates/netlifyUD.js +0 -3
  100. package/dist/commands/setup/docker/docker.js +1 -1
  101. package/dist/commands/setup/docker/dockerHandler.js +1 -2
  102. package/dist/commands/setup/generator/generator.js +1 -1
  103. package/dist/commands/setup/generator/generatorHandler.js +1 -1
  104. package/dist/commands/setup/graphql/features/fragments/fragments.js +1 -1
  105. package/dist/commands/setup/graphql/features/fragments/fragmentsHandler.js +5 -3
  106. package/dist/commands/setup/graphql/features/trustedDocuments/trustedDocuments.js +1 -1
  107. package/dist/commands/setup/graphql/features/trustedDocuments/trustedDocumentsHandler.js +1 -2
  108. package/dist/commands/setup/i18n/i18n.js +1 -1
  109. package/dist/commands/setup/i18n/i18nHandler.js +1 -1
  110. package/dist/commands/setup/jobs/jobs.js +1 -1
  111. package/dist/commands/setup/jobs/jobsHandler.js +1 -4
  112. package/dist/commands/setup/mailer/mailer.js +1 -1
  113. package/dist/commands/setup/mailer/mailerHandler.js +1 -2
  114. package/dist/commands/setup/middleware/ogImage/ogImage.js +1 -1
  115. package/dist/commands/setup/middleware/ogImage/ogImageHandler.js +1 -2
  116. package/dist/commands/setup/monitoring/sentry/sentry.js +1 -1
  117. package/dist/commands/setup/monitoring/sentry/sentryHandler.js +9 -13
  118. package/dist/commands/setup/monitoring/sentry/templates/sentryApi.ts.template +4 -1
  119. package/dist/commands/setup/monitoring/sentry/templates/sentryWeb.ts.template +4 -7
  120. package/dist/commands/setup/neon/neon.js +1 -1
  121. package/dist/commands/setup/neon/neonHandler.js +9 -5
  122. package/dist/commands/setup/package/package.js +1 -1
  123. package/dist/commands/setup/package/packageHandler.js +4 -4
  124. package/dist/commands/setup/realtime/addRealtimeToGraphql.js +1 -1
  125. package/dist/commands/setup/realtime/realtime.js +1 -1
  126. package/dist/commands/setup/realtime/realtimeHandler.js +16 -4
  127. package/dist/commands/setup/realtime/templates/defer/fastAndSlowFields/fastAndSlowFields.ts.template +1 -4
  128. package/dist/commands/setup/realtime/templates/liveQueries/auctions/auctions.ts.template +4 -12
  129. package/dist/commands/setup/realtime/templates/subscriptions/countdown/countdown.ts.template +1 -1
  130. package/dist/commands/setup/realtime/templates/subscriptions/newMessage/newMessage.ts.template +2 -2
  131. package/dist/commands/setup/server-file/serverFile.js +1 -1
  132. package/dist/commands/setup/server-file/serverFileHandler.js +1 -2
  133. package/dist/commands/setup/ui/libraries/chakra-uiHandler.js +1 -2
  134. package/dist/commands/setup/ui/libraries/mantineHandler.js +1 -2
  135. package/dist/commands/setup/ui/libraries/tailwindcssHandler.js +82 -63
  136. package/dist/commands/setup/ui/templates/postcss.config.cjs.template +9 -0
  137. package/dist/commands/setup/uploads/dbCodemod.js +28 -0
  138. package/dist/commands/setup/uploads/templates/signedUrl.ts.template +21 -0
  139. package/dist/commands/setup/uploads/templates/srcLibUploads.ts.template +24 -23
  140. package/dist/commands/setup/uploads/uploads.js +7 -49
  141. package/dist/commands/setup/uploads/uploadsHandler.js +69 -277
  142. package/dist/commands/setup.js +1 -2
  143. package/dist/commands/studio.js +1 -1
  144. package/dist/commands/test/testHandler.js +71 -25
  145. package/dist/commands/test/testHandlerEsm.js +109 -0
  146. package/dist/commands/test.js +18 -10
  147. package/dist/commands/testEsm.js +41 -0
  148. package/dist/commands/type-checkHandler.js +1 -1
  149. package/dist/commands/upgrade/preUpgradeScripts.js +3 -3
  150. package/dist/commands/upgrade/upgrade.js +1 -1
  151. package/dist/commands/upgrade/upgradeHandler.js +1 -2
  152. package/dist/index.js +8 -5
  153. package/dist/lib/exit.js +1 -1
  154. package/dist/lib/index.js +31 -16
  155. package/dist/lib/loadEnvFiles.js +1 -1
  156. package/dist/lib/plugin.js +1 -1
  157. package/dist/lib/test.js +1 -1
  158. package/dist/lib/updateCheck.js +4 -4
  159. package/dist/middleware/checkNodeVersion.js +4 -4
  160. package/package.json +27 -27
  161. package/dist/commands/deploy/baremetal/monitors.js +0 -66
  162. package/dist/commands/generate/cell/templates/cellFragment.tsx.template +0 -43
  163. package/dist/commands/generate/cell/templates/storiesFragment.tsx.template +0 -23
  164. package/dist/commands/generate/cell/templates/testFragment.js.template +0 -30
  165. package/dist/commands/generate/dbAuth/templates/changePassword.tsx.template +0 -131
  166. package/dist/commands/generate/dbAuth/templates/login.oauth.tsx.template +0 -164
  167. package/dist/commands/generate/dbAuth/templates/signup.oauth.tsx.template +0 -147
  168. package/dist/commands/generate/scaffold/templates/layouts/NamesScaffoldLayout.tsx.template +0 -18
  169. package/dist/commands/setup/tenancy/authCodemod.js +0 -66
  170. package/dist/commands/setup/tenancy/dbCodemod.js +0 -64
  171. package/dist/commands/setup/tenancy/graphqlCodemod.js +0 -88
  172. package/dist/commands/setup/tenancy/preflight.js +0 -49
  173. package/dist/commands/setup/tenancy/schemaPrisma.js +0 -81
  174. package/dist/commands/setup/tenancy/signupCodemod.js +0 -154
  175. package/dist/commands/setup/tenancy/templates/InvitePage.tsx.template +0 -72
  176. package/dist/commands/setup/tenancy/templates/OrgScope.tsx.template +0 -40
  177. package/dist/commands/setup/tenancy/templates/ensureDefaultOrganizations.dataMigration.ts.template +0 -39
  178. package/dist/commands/setup/tenancy/templates/organizations.scenarios.ts.template +0 -57
  179. package/dist/commands/setup/tenancy/templates/organizations.sdl.ts.template +0 -89
  180. package/dist/commands/setup/tenancy/templates/organizations.test.ts.template +0 -381
  181. package/dist/commands/setup/tenancy/templates/organizations.ts.template +0 -394
  182. package/dist/commands/setup/tenancy/templates/requireMembership.test.ts.template +0 -35
  183. package/dist/commands/setup/tenancy/templates/requireMembership.ts.template +0 -25
  184. package/dist/commands/setup/tenancy/tenancy.js +0 -30
  185. package/dist/commands/setup/tenancy/tenancyHandler.js +0 -425
  186. package/dist/commands/setup/uploads/gitignore.js +0 -17
  187. package/dist/commands/setup/uploads/schemaPrisma.js +0 -41
  188. package/dist/commands/setup/uploads/serverFile.js +0 -217
  189. package/dist/commands/setup/uploads/templates/requireUploadToken.ts.template +0 -15
  190. package/dist/commands/setup/uploads/templates/uploads.sdl.ts.template +0 -79
  191. package/dist/commands/setup/uploads/templates/uploads.ts.template +0 -98
  192. package/dist/commands/setup/uploads/templates/withDataUri.ts.template +0 -14
  193. package/dist/commands/setup/uploads/templates/withSignedUrl.ts.template +0 -16
  194. package/dist/commands/test/viteVersionCheck.js +0 -75
@@ -1,24 +1,25 @@
1
- __PATH_IMPORT____S3_IMPORTS__import {
2
- __FS_IMPORT__
3
- __DB_IMPORT__
4
- __DB_MAX_IMPORT__
5
- defineStorageTargets,
6
- defineUploadProfiles,
7
- } from '@cedarjs/uploads'
8
- __GET_PATHS_IMPORT__
9
- __S3_CLIENT__
10
- /**
11
- * Where files live. Each target is a provider instance; the Upload row
12
- * records which target holds a file so it can be read, served, and deleted
13
- * later. Look one up by name with `resolveTarget(targets, upload.target)`.
14
- */
15
- export const targets = defineStorageTargets({
16
- __TARGETS__})
1
+ import { createUploadsConfig, setupStorage } from '@cedarjs/storage'
2
+ import { FileSystemStorage } from '@cedarjs/storage/FileSystemStorage'
3
+ import { UrlSigner } from '@cedarjs/storage/UrlSigner'
17
4
 
18
- /**
19
- * What clients may upload. A profile names a target and the constraints the
20
- * server signs into every upload token issued for it. The client never
21
- * supplies constraints; it names a profile.
22
- */
23
- export const profiles = defineUploadProfiles({
24
- __PROFILES__})
5
+ const uploadsConfig = createUploadsConfig({
6
+ // Configure your fields here
7
+ // e.g. modelName: { fields: ['fieldWithUpload']}
8
+ })
9
+
10
+ export const fsStorage = new FileSystemStorage({
11
+ baseDir: './uploads',
12
+ })
13
+
14
+ export const urlSigner = new UrlSigner({
15
+ secret: process.env.UPLOADS_SECRET,
16
+ endpoint: '/signedUrl',
17
+ })
18
+
19
+ const { saveFiles, storagePrismaExtension } = setupStorage({
20
+ uploadsConfig,
21
+ storageAdapter: fsStorage,
22
+ urlSigner,
23
+ })
24
+
25
+ export { saveFiles, storagePrismaExtension }
@@ -1,68 +1,26 @@
1
- import prompts from "prompts";
2
- import { recordTelemetryAttributes } from "@cedarjs/cli-helpers/telemetry";
3
- import { requireTTYOrExit } from "@cedarjs/cli-helpers/tty";
1
+ import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
4
2
  const command = "uploads";
5
- const description = "Set up file uploads and storage: storage targets, upload profiles, the upload routes, and the GraphQL API";
6
- const TARGET_CHOICES = ["fs", "db", "s3"];
7
- const TARGET_DESCRIPTIONS = {
8
- fs: "Local filesystem, uploaded through the api server (development, single-server deploys)",
9
- db: "Inline in the database, for small files like avatars and thumbnails",
10
- s3: "S3 or S3-compatible storage, uploaded straight from the browser with presigned URLs"
11
- };
3
+ const description = "Setup uploads and storage. This will install the required packages and add the required initial configuration to your redwood app.";
12
4
  const builder = (yargs) => {
13
- return yargs.option("targets", {
14
- choices: TARGET_CHOICES,
15
- description: "Storage targets to configure: fs (local filesystem), db (inline in the database), s3 (direct-to-S3 presigned uploads). Prompts when omitted.",
16
- type: "array"
17
- }).option("force", {
5
+ yargs.option("force", {
18
6
  alias: "f",
19
7
  default: false,
20
8
  description: "Overwrite existing configuration",
21
9
  type: "boolean"
22
10
  });
23
11
  };
24
- function toTargetChoices(values) {
25
- const choices = TARGET_CHOICES;
26
- return [...new Set(values)].filter(
27
- (t) => choices.includes(t)
28
- );
29
- }
30
- async function promptForTargets() {
31
- requireTTYOrExit("--targets");
32
- const response = await prompts({
33
- type: "multiselect",
34
- name: "targets",
35
- message: "Which storage targets do you want to configure?",
36
- instructions: false,
37
- hint: "Space to toggle, enter to confirm",
38
- min: 1,
39
- choices: TARGET_CHOICES.map((value) => ({
40
- title: value,
41
- description: TARGET_DESCRIPTIONS[value],
42
- value,
43
- selected: value !== "s3"
44
- }))
45
- });
46
- if (response.targets === void 0) {
47
- process.exit(0);
48
- }
49
- return toTargetChoices(response.targets);
50
- }
51
12
  const handler = async (options) => {
52
- const targets = options.targets?.length ? toTargetChoices(options.targets) : await promptForTargets();
53
13
  recordTelemetryAttributes({
54
14
  command: "setup uploads",
55
- targets: targets.join(","),
56
- force: options.force
15
+ force: options.force,
16
+ skipExamples: options.skipExamples
57
17
  });
58
18
  const { handler: handler2 } = await import("./uploadsHandler.js");
59
- return handler2({ targets, force: options.force });
19
+ return handler2(options);
60
20
  };
61
21
  export {
62
- TARGET_CHOICES,
63
22
  builder,
64
23
  command,
65
24
  description,
66
- handler,
67
- toTargetChoices
25
+ handler
68
26
  };
@@ -1,298 +1,105 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- import { pathToFileURL } from "node:url";
4
3
  import { Listr } from "listr2";
5
4
  import { format } from "prettier";
6
5
  import { terminalLink } from "termi-link";
7
- import { colors as c } from "@cedarjs/cli-helpers/colors";
8
- import { getPrettierOptions } from "@cedarjs/cli-helpers/fileHelpers";
9
6
  import {
10
7
  addApiPackages,
11
- addWebPackages
12
- } from "@cedarjs/cli-helpers/installHelpers";
8
+ getPrettierOptions,
9
+ colors as c
10
+ } from "@cedarjs/cli-helpers";
13
11
  import { formatCedarCommand } from "@cedarjs/cli-helpers/packageManager/display";
14
- import { addEnvVar } from "@cedarjs/cli-helpers/project";
15
- import { getSchemaPath } from "@cedarjs/project-config";
16
12
  import { errorTelemetry } from "@cedarjs/telemetry";
17
13
  import { getPaths, transformTSToJS, writeFile } from "../../../lib/index.js";
18
14
  import { isTypeScriptProject } from "../../../lib/project.js";
19
- import { generateSecret } from "../../generate/secret/secret.js";
20
- import { setupServerFileTasks } from "../server-file/serverFileHandler.js";
21
- import { transformGitignore } from "./gitignore.js";
22
- import { addUploadModel } from "./schemaPrisma.js";
23
- import {
24
- addUploadsPlugin,
25
- detectServerAuth,
26
- hasUploadsPlugin
27
- } from "./serverFile.js";
28
- const UPPY_VERSION = "^6.0.0";
29
- const S3_IMPORTS = `import { S3Client } from '@aws-sdk/client-s3'
30
-
31
- import { createS3Provider } from '@cedarjs/uploads/s3'
32
- `;
33
- const S3_CLIENT = `
34
- // Your own S3 client. It stays available for S3-specific work (lifecycle
35
- // rules, CORS, and so on) alongside the storage target below. Credentials
36
- // come from the SDK's default chain: AWS_ACCESS_KEY_ID and
37
- // AWS_SECRET_ACCESS_KEY in .env, or an IAM role, SSO, or container
38
- // credentials in production. For an S3-compatible service, add \`endpoint\`
39
- // and \`forcePathStyle: true\`.
40
- export const s3Client = new S3Client({
41
- region: process.env.AWS_REGION,
42
- })
43
-
44
- const s3Bucket = process.env.S3_BUCKET_UPLOADS
45
-
46
- if (!s3Bucket) {
47
- throw new Error('Set S3_BUCKET_UPLOADS in .env to use the S3 storage target')
48
- }
49
- `;
50
- const TARGET_BLOCKS = {
51
- fs: ` // Files uploaded through the api server and stored on local disk. Good for
52
- // development and single-server deploys.
53
- local: createFsProvider({
54
- uploadDir: path.join(getPaths().api.base, '.uploads'),
55
- serveBaseUrl: process.env.UPLOAD_SERVE_BASE_URL,
56
- signSecret: process.env.UPLOAD_TOKEN_SECRET,
57
- }),
58
- `,
59
- db: ` // Small files stored inline in the Upload row (avatars, thumbnails).
60
- thumbnails: createDbProvider(),
61
- `,
62
- s3: ` // Files uploaded straight from the browser to S3 with presigned URLs.
63
- files: createS3Provider({
64
- client: s3Client,
65
- bucket: s3Bucket,
66
- region: process.env.AWS_REGION,
67
- keyPrefix: 'uploads/',
68
- }),
69
- `
70
- };
71
- const PROFILE_BLOCKS = {
72
- fs: ` attachment: {
73
- target: 'local',
74
- allowedMimeTypes: ['application/pdf', 'image/png', 'image/jpeg'],
75
- maxFileSize: 25 * 1024 * 1024,
76
- maxFiles: 10,
77
- },
78
- `,
79
- db: ` avatar: {
80
- target: 'thumbnails',
81
- allowedMimeTypes: ['image/png', 'image/jpeg'],
82
- maxFileSize: DB_MAX_FILE_SIZE,
83
- maxFiles: 1,
84
- },
85
- `,
86
- s3: ` document: {
87
- target: 'files',
88
- allowedMimeTypes: ['application/pdf', 'image/*'],
89
- maxFileSize: 100 * 1024 * 1024,
90
- maxFiles: 5,
91
- },
92
- `
93
- };
94
- const handler = async ({ targets, force }) => {
95
- const paths = getPaths();
15
+ import { runTransform } from "../../../lib/runTransform.js";
16
+ const handler = async ({ force }) => {
96
17
  const projectIsTypescript = isTypeScriptProject();
97
- const ext = projectIsTypescript ? "ts" : "js";
98
- const wantsFs = targets.includes("fs");
99
- const wantsDb = targets.includes("db");
100
- const wantsS3 = targets.includes("s3");
101
- const wantsUppy = wantsFs || wantsS3;
102
- const packageJson = await import(pathToFileURL(path.join(paths.base, "package.json")).href, { with: { type: "json" } });
18
+ const packageJson = await import(path.join(getPaths().base, "package.json"), {
19
+ with: { type: "json" }
20
+ });
103
21
  const cedarVersion = packageJson.default.devDependencies["@cedarjs/core"] ?? "latest";
104
- const serverFilePath = path.join(paths.api.src, `server.${ext}`);
105
- const writeTemplateFile = async (templateFile, outputPath, replacements = {}) => {
106
- const templatePath = path.resolve(
107
- import.meta.dirname,
108
- "templates",
109
- templateFile
110
- );
111
- let templateContent = fs.readFileSync(templatePath, "utf-8");
112
- for (const [token, value] of Object.entries(replacements)) {
113
- templateContent = templateContent.replaceAll(token, value);
114
- }
115
- const content = projectIsTypescript ? templateContent : await transformTSToJS(outputPath, templateContent);
116
- return writeFile(outputPath, content, { overwriteExisting: force });
117
- };
118
- const apiPackages = [`@cedarjs/uploads@${cedarVersion}`];
119
- const webPackages = [`@cedarjs/uploads@${cedarVersion}`];
120
- if (wantsS3) {
121
- apiPackages.push("@aws-sdk/client-s3", "@aws-sdk/s3-request-presigner");
122
- }
123
- if (wantsUppy) {
124
- webPackages.push(
125
- `@uppy/core@${UPPY_VERSION}`,
126
- `@uppy/react@${UPPY_VERSION}`,
127
- `@uppy/dashboard@${UPPY_VERSION}`
128
- );
129
- }
130
- if (wantsFs) {
131
- webPackages.push(`@uppy/xhr-upload@${UPPY_VERSION}`);
132
- }
133
- if (wantsS3) {
134
- webPackages.push(`@uppy/aws-s3@${UPPY_VERSION}`);
135
- }
136
22
  const tasks = new Listr(
137
23
  [
138
24
  {
139
- ...addApiPackages(apiPackages),
140
- title: "Adding @cedarjs/uploads to your api side..."
141
- },
142
- {
143
- ...addWebPackages(webPackages),
144
- title: "Adding @cedarjs/uploads to your web side..."
145
- },
146
- {
147
- title: "Adding the Upload model to schema.prisma...",
25
+ title: `Adding api/src/lib/uploads.${projectIsTypescript ? "ts" : "js"}...`,
148
26
  task: async () => {
149
- const schemaPath = await getSchemaPath(paths.api.prismaConfig);
150
- const schema = fs.readFileSync(schemaPath, "utf-8");
151
- fs.writeFileSync(schemaPath, addUploadModel(schema));
152
- }
153
- },
154
- {
155
- title: `Adding api/src/lib/uploads.${ext}...`,
156
- task: async () => {
157
- await writeTemplateFile(
158
- "srcLibUploads.ts.template",
159
- path.join(paths.api.lib, `uploads.${ext}`),
160
- {
161
- __S3_IMPORTS__: wantsS3 ? S3_IMPORTS : "",
162
- __S3_CLIENT__: wantsS3 ? S3_CLIENT : "",
163
- __FS_IMPORT__: wantsFs ? "createFsProvider," : "",
164
- __DB_IMPORT__: wantsDb ? "createDbProvider," : "",
165
- __DB_MAX_IMPORT__: wantsDb ? "DB_MAX_FILE_SIZE," : "",
166
- __PATH_IMPORT__: wantsFs ? "import path from 'node:path'\n\n" : "",
167
- __GET_PATHS_IMPORT__: wantsFs ? "import { getPaths } from '@cedarjs/project-config'\n" : "",
168
- __TARGETS__: targets.map((t) => TARGET_BLOCKS[t]).join("\n"),
169
- __PROFILES__: targets.map((t) => PROFILE_BLOCKS[t]).join("\n")
170
- }
27
+ const templatePath = path.resolve(
28
+ import.meta.dirname,
29
+ "templates",
30
+ "srcLibUploads.ts.template"
31
+ );
32
+ const templateContent = fs.readFileSync(templatePath, {
33
+ encoding: "utf8",
34
+ flag: "r"
35
+ });
36
+ const uploadsPath = path.join(
37
+ getPaths().api.lib,
38
+ `uploads.${projectIsTypescript ? "ts" : "js"}`
171
39
  );
40
+ const uploadsContent = projectIsTypescript ? templateContent : await transformTSToJS(uploadsPath, templateContent);
41
+ return writeFile(uploadsPath, uploadsContent, {
42
+ overwriteExisting: force
43
+ });
172
44
  }
173
45
  },
174
46
  {
175
- title: "Adding the uploads SDL and service...",
47
+ title: `Adding signedUrl function...`,
176
48
  task: async () => {
177
- await writeTemplateFile(
178
- "uploads.sdl.ts.template",
179
- path.join(paths.api.graphql, `uploads.sdl.${ext}`)
49
+ const templatePath = path.resolve(
50
+ import.meta.dirname,
51
+ "templates",
52
+ "signedUrl.ts.template"
180
53
  );
181
- await writeTemplateFile(
182
- "uploads.ts.template",
183
- path.join(paths.api.services, "uploads", `uploads.${ext}`)
54
+ const templateContent = fs.readFileSync(templatePath, {
55
+ encoding: "utf8",
56
+ flag: "r"
57
+ });
58
+ const uploadsPath = path.join(
59
+ getPaths().api.functions,
60
+ `signedUrl.${projectIsTypescript ? "ts" : "js"}`
184
61
  );
62
+ const uploadsContent = projectIsTypescript ? templateContent : await transformTSToJS(uploadsPath, templateContent);
63
+ return writeFile(uploadsPath, uploadsContent, {
64
+ overwriteExisting: force
65
+ });
185
66
  }
186
67
  },
187
68
  {
188
- title: "Adding the upload directives...",
189
- task: async () => {
190
- const directives = ["requireUploadToken", "withSignedUrl"];
191
- if (wantsDb) {
192
- directives.push("withDataUri");
193
- }
194
- for (const name of directives) {
195
- await writeTemplateFile(
196
- `${name}.ts.template`,
197
- path.join(paths.api.directives, name, `${name}.${ext}`)
198
- );
199
- }
200
- }
201
- },
202
- {
203
- title: "Adding the server file...",
204
- task: (_ctx, task) => task.newListr(setupServerFileTasks({ force: false })),
205
- skip: () => fs.existsSync(serverFilePath) ? "api/src/server already exists; skipping." : false
206
- },
207
- {
208
- title: "Registering the upload plugin in api/src/server...",
209
- task: async (_ctx, task) => {
210
- const source = fs.readFileSync(serverFilePath, "utf-8");
211
- if (hasUploadsPlugin(source)) {
212
- task.skip("The upload plugin is already registered; skipping.");
213
- return;
214
- }
215
- const graphqlPath = path.join(paths.api.functions, `graphql.${ext}`);
216
- const authPath = path.join(paths.api.lib, `auth.${ext}`);
217
- const auth = fs.existsSync(graphqlPath) && fs.existsSync(authPath) && fs.readFileSync(authPath, "utf-8").includes("getCurrentUser") ? detectServerAuth(fs.readFileSync(graphqlPath, "utf-8")) : null;
218
- let updated;
219
- try {
220
- updated = addUploadsPlugin(source, { auth });
221
- } catch {
222
- throw new Error(
223
- `Could not find \`await server.start()\` in ${path.relative(
224
- paths.base,
225
- serverFilePath
226
- )}. Register the plugin by hand before the server starts:
227
-
228
- import { cedarUploadsPlugin } from '@cedarjs/uploads'
229
- import { db } from 'src/lib/db'
230
- import { targets } from 'src/lib/uploads'
231
-
232
- await server.register(cedarUploadsPlugin, {
233
- tokenSecret: process.env.UPLOAD_TOKEN_SECRET,
234
- targets,
235
- db,
236
- })
237
- `
238
- );
239
- }
240
- fs.writeFileSync(serverFilePath, updated);
241
- }
69
+ ...addApiPackages([`@cedarjs/storage@${cedarVersion}`]),
70
+ title: "Adding dependencies to your api side..."
242
71
  },
243
72
  {
244
- title: "Adding environment variables to .env...",
245
- task: () => {
246
- addEnvVar(
247
- "UPLOAD_TOKEN_SECRET",
248
- generateSecret(),
249
- "Signs upload tokens and file-serving URLs. Keep it secret and use a different value per environment."
73
+ title: "Modifying api/src/lib/db to add uploads prisma extension..",
74
+ task: async () => {
75
+ const dbPath = path.join(
76
+ getPaths().api.lib,
77
+ `db.${projectIsTypescript ? "ts" : "js"}`
250
78
  );
251
- if (wantsFs) {
252
- addEnvVar(
253
- "UPLOAD_SERVE_BASE_URL",
254
- "http://localhost:8911",
255
- "Origin the api server is reachable at, used to build signed URLs for locally stored files."
256
- );
257
- }
258
- if (wantsS3) {
259
- addEnvVar(
260
- "AWS_REGION",
261
- "us-east-1",
262
- "Region of the uploads bucket."
263
- );
264
- addEnvVar("AWS_ACCESS_KEY_ID", "replace-me", "");
265
- addEnvVar("AWS_SECRET_ACCESS_KEY", "replace-me", "");
266
- addEnvVar(
267
- "S3_BUCKET_UPLOADS",
268
- "replace-me",
269
- "Bucket direct uploads land in."
79
+ const transformResult = await runTransform({
80
+ transformPath: path.join(import.meta.dirname, "dbCodemod.js"),
81
+ targetPaths: [dbPath]
82
+ });
83
+ if (transformResult.error) {
84
+ if (transformResult.error === "RW_CODEMOD_ERR_OLD_FORMAT") {
85
+ throw new Error(
86
+ "It looks like your src/lib/db file is using the old format. Please update it as per the v8 upgrade guide: https://cedarjs.com/docs/8.x/upgrade-guides/v8#database-file-structure-change. And run again. \n\nYou can also manually modify your api/src/lib/db to include the prisma extension: https://cedarjs.com/docs/uploads/#attaching-the-prisma-extension"
87
+ );
88
+ }
89
+ throw new Error(
90
+ "Could not add the prisma extension. \n Please modify your api/src/lib/db to include the prisma extension: https://cedarjs.com/docs/uploads/#attaching-the-prisma-extension"
270
91
  );
271
92
  }
272
93
  }
273
94
  },
274
- {
275
- title: "Adding the fs upload directory to .gitignore...",
276
- skip: () => wantsFs ? false : "No fs target selected; skipping.",
277
- task: (_ctx, task) => {
278
- const gitignorePath = path.join(paths.base, ".gitignore");
279
- const source = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, "utf-8") : "";
280
- const updated = transformGitignore(source);
281
- if (updated === source) {
282
- task.skip(".gitignore already up to date");
283
- return;
284
- }
285
- fs.writeFileSync(gitignorePath, updated, "utf-8");
286
- }
287
- },
288
95
  {
289
96
  title: "Prettifying changed files",
290
97
  task: async (_ctx, task) => {
291
98
  const prettifyPaths = [
292
- serverFilePath,
293
- path.join(paths.api.lib, `uploads.${ext}`),
294
- path.join(paths.api.graphql, `uploads.sdl.${ext}`),
295
- path.join(paths.api.services, "uploads", `uploads.${ext}`)
99
+ path.join(getPaths().api.lib, "db.js"),
100
+ path.join(getPaths().api.lib, "db.ts"),
101
+ path.join(getPaths().api.lib, "uploads.js"),
102
+ path.join(getPaths().api.lib, "uploads.ts")
296
103
  ];
297
104
  for (const prettifyPath of prettifyPaths) {
298
105
  try {
@@ -301,11 +108,11 @@ const handler = async ({ targets, force }) => {
301
108
  }
302
109
  const source = fs.readFileSync(prettifyPath, "utf-8");
303
110
  const prettierOptions = await getPrettierOptions();
304
- const prettified = await format(source, {
111
+ const prettifiedApp = await format(source, {
305
112
  ...prettierOptions,
306
113
  parser: "babel-ts"
307
114
  });
308
- fs.writeFileSync(prettifyPath, prettified, "utf-8");
115
+ fs.writeFileSync(prettifyPath, prettifiedApp, "utf-8");
309
116
  } catch {
310
117
  task.output = "Couldn't prettify the changes. Please reformat the files manually if needed.";
311
118
  }
@@ -315,30 +122,15 @@ const handler = async ({ targets, force }) => {
315
122
  {
316
123
  title: "One more thing...",
317
124
  task: (_ctx, task) => {
318
- const migrate = c.highlight(
319
- formatCedarCommand(["prisma", "migrate", "dev"])
320
- );
321
- const types = c.highlight(formatCedarCommand(["generate", "types"]));
322
125
  task.title = `One more thing...
323
126
 
324
- ${c.success("Uploads configured!")}
325
-
326
- Next steps:
127
+ ${c.success("\nUploads and storage configured!\n")}
327
128
 
328
- 1. Apply the schema change: ${migrate}
329
- 2. Regenerate types: ${types}
330
- 3. Review the storage targets and upload profiles in api/src/lib/uploads.${ext}${wantsS3 ? "\n 4. Fill in the AWS_* and S3_BUCKET_UPLOADS values in .env" : ""}
331
-
332
- Upload tokens are bound to the logged-in user when the app has auth.
333
- If you add auth later, pass
334
- \`authenticate: createUploadAuthenticator({ authDecoder, getCurrentUser })\`
335
- to the plugin in api/src/server.${ext}.
336
-
337
- Schedule cleanupStaleUploads() from a recurring job to sweep uploads
338
- that never completed.
129
+ Remember to add UPLOADS_SECRET to your .env file. You can generate one with ${c.highlight(formatCedarCommand(["generate", "secret"]))}
339
130
 
340
131
  Check out the docs for more info:
341
132
  ${terminalLink("", "https://cedarjs.com/docs/uploads")}
133
+
342
134
  `;
343
135
  }
344
136
  }
@@ -16,12 +16,11 @@ import * as setupNeon from "./setup/neon/neon.js";
16
16
  import * as setupPackage from "./setup/package/package.js";
17
17
  import * as setupRealtime from "./setup/realtime/realtime.js";
18
18
  import * as setupServerFile from "./setup/server-file/serverFile.js";
19
- import * as setupTenancy from "./setup/tenancy/tenancy.js";
20
19
  import * as setupUi from "./setup/ui/ui.js";
21
20
  import * as setupUploads from "./setup/uploads/uploads.js";
22
21
  const command = "setup <command>";
23
22
  const description = "Initialize project config and install packages";
24
- const builder = (yargs) => yargs.command(setupAuth).command(setupCache).command(setupDatabase).command(setupDeploy).command(setupDocker).command(setupGenerator).command(setupGraphql).command(setupI18n).command(setupJobs).command(setupMailer).command(setupMiddleware).command(setupMonitoring).command(setupNeon).command(setupPackage).command(setupRealtime).command(setupServerFile).command(setupTenancy).command(setupUi).command(setupUploads).demandCommand().middleware(detectCedarVersion).epilogue(
23
+ const builder = (yargs) => yargs.command(setupAuth).command(setupCache).command(setupDatabase).command(setupDeploy).command(setupDocker).command(setupGenerator).command(setupGraphql).command(setupI18n).command(setupJobs).command(setupMailer).command(setupMiddleware).command(setupMonitoring).command(setupNeon).command(setupPackage).command(setupRealtime).command(setupServerFile).command(setupUi).command(setupUploads).demandCommand().middleware(detectCedarVersion).epilogue(
25
24
  `Also see the ${terminalLink(
26
25
  "CedarJS CLI Reference",
27
26
  "https://cedarjs.com/docs/cli-commands#setup"
@@ -1,4 +1,4 @@
1
- import { recordTelemetryAttributes } from "@cedarjs/cli-helpers/telemetry";
1
+ import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
2
2
  const command = "studio";
3
3
  const description = "Run the CedarJS development studio";
4
4
  function builder(yargs) {