@cedarjs/cli 7.0.0-canary.3260 → 7.0.0-rc.127

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 (168) 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 +1 -1
  5. package/dist/commands/deploy/baremetal.js +1 -1
  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 +1 -2
  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/dbAuthHandler.js +3 -23
  39. package/dist/commands/generate/directive/directiveHandler.js +1 -2
  40. package/dist/commands/generate/function/functionHandler.js +1 -2
  41. package/dist/commands/generate/job/jobHandler.js +1 -2
  42. package/dist/commands/generate/model/modelHandler.js +1 -2
  43. package/dist/commands/generate/ogImage/ogImageHandler.js +1 -2
  44. package/dist/commands/generate/package/filesTask.js +12 -9
  45. package/dist/commands/generate/package/packageHandler.js +4 -3
  46. package/dist/commands/generate/page/pageHandler.js +1 -2
  47. package/dist/commands/generate/realtime/realtime.js +1 -1
  48. package/dist/commands/generate/realtime/realtimeHandler.js +9 -2
  49. package/dist/commands/generate/realtime/templates/subscriptions/blank/blank.ts.template +1 -1
  50. package/dist/commands/generate/scaffold/scaffoldHandler.js +5 -10
  51. package/dist/commands/generate/scaffold/templates/components/NameForm.tsx.template +3 -3
  52. package/dist/commands/generate/scaffold/templates/lib/formatters.test.tsx.template +0 -11
  53. package/dist/commands/generate/scaffold/templates/lib/formatters.tsx.template +1 -13
  54. package/dist/commands/generate/script/scriptHandler.js +1 -2
  55. package/dist/commands/generate/sdl/sdlHandler.js +1 -2
  56. package/dist/commands/generate/secret/secret.js +1 -1
  57. package/dist/commands/generate/service/serviceHandler.js +38 -47
  58. package/dist/commands/generate/service/templates/service.ts.template +8 -22
  59. package/dist/commands/generate/service/templates/test.ts.template +1 -1
  60. package/dist/commands/generate/yargsCommandHelpers.js +1 -1
  61. package/dist/commands/generate/yargsHandlerHelpers.js +1 -2
  62. package/dist/commands/generate.js +1 -1
  63. package/dist/commands/info.js +1 -1
  64. package/dist/commands/lint.js +1 -1
  65. package/dist/commands/prerenderHandler.js +4 -11
  66. package/dist/commands/prismaHandler.js +2 -7
  67. package/dist/commands/record/init.js +1 -1
  68. package/dist/commands/serve.js +1 -2
  69. package/dist/commands/setup/auth/auth.js +4 -2
  70. package/dist/commands/setup/cache/cache.js +1 -1
  71. package/dist/commands/setup/cache/cacheHandler.js +1 -2
  72. package/dist/commands/setup/database/postgres.js +1 -1
  73. package/dist/commands/setup/database/postgresHandler.js +1 -3
  74. package/dist/commands/setup/deploy/providers/baremetalHandler.js +1 -2
  75. package/dist/commands/setup/deploy/providers/coherence.js +1 -1
  76. package/dist/commands/setup/deploy/providers/coherenceHandler.js +6 -7
  77. package/dist/commands/setup/deploy/providers/flightcontrolHandler.js +1 -2
  78. package/dist/commands/setup/deploy/providers/netlifyHandler.js +1 -2
  79. package/dist/commands/setup/deploy/providers/renderHandler.js +1 -2
  80. package/dist/commands/setup/deploy/providers/serverlessHandler.js +1 -2
  81. package/dist/commands/setup/deploy/providers/universalDeployHandler.js +6 -4
  82. package/dist/commands/setup/deploy/providers/vercelHandler.js +1 -2
  83. package/dist/commands/setup/docker/docker.js +1 -1
  84. package/dist/commands/setup/docker/dockerHandler.js +1 -2
  85. package/dist/commands/setup/generator/generator.js +1 -1
  86. package/dist/commands/setup/generator/generatorHandler.js +1 -1
  87. package/dist/commands/setup/graphql/features/fragments/fragments.js +1 -1
  88. package/dist/commands/setup/graphql/features/fragments/fragmentsHandler.js +5 -3
  89. package/dist/commands/setup/graphql/features/trustedDocuments/trustedDocuments.js +1 -1
  90. package/dist/commands/setup/graphql/features/trustedDocuments/trustedDocumentsHandler.js +1 -2
  91. package/dist/commands/setup/i18n/i18n.js +1 -1
  92. package/dist/commands/setup/i18n/i18nHandler.js +1 -1
  93. package/dist/commands/setup/jobs/jobs.js +1 -1
  94. package/dist/commands/setup/jobs/jobsHandler.js +1 -2
  95. package/dist/commands/setup/mailer/mailer.js +1 -1
  96. package/dist/commands/setup/mailer/mailerHandler.js +1 -2
  97. package/dist/commands/setup/middleware/ogImage/ogImage.js +1 -1
  98. package/dist/commands/setup/middleware/ogImage/ogImageHandler.js +1 -2
  99. package/dist/commands/setup/monitoring/sentry/sentry.js +1 -1
  100. package/dist/commands/setup/monitoring/sentry/sentryHandler.js +7 -8
  101. package/dist/commands/setup/neon/neon.js +1 -1
  102. package/dist/commands/setup/neon/neonHandler.js +9 -5
  103. package/dist/commands/setup/package/package.js +1 -1
  104. package/dist/commands/setup/package/packageHandler.js +4 -4
  105. package/dist/commands/setup/realtime/addRealtimeToGraphql.js +1 -1
  106. package/dist/commands/setup/realtime/realtime.js +1 -1
  107. package/dist/commands/setup/realtime/realtimeHandler.js +16 -4
  108. package/dist/commands/setup/realtime/templates/subscriptions/countdown/countdown.ts.template +1 -1
  109. package/dist/commands/setup/realtime/templates/subscriptions/newMessage/newMessage.ts.template +1 -1
  110. package/dist/commands/setup/server-file/serverFile.js +1 -1
  111. package/dist/commands/setup/server-file/serverFileHandler.js +1 -2
  112. package/dist/commands/setup/ui/libraries/chakra-uiHandler.js +1 -2
  113. package/dist/commands/setup/ui/libraries/mantineHandler.js +1 -2
  114. package/dist/commands/setup/ui/libraries/tailwindcssHandler.js +1 -2
  115. package/dist/commands/setup/uploads/dbCodemod.js +28 -0
  116. package/dist/commands/setup/uploads/templates/signedUrl.ts.template +21 -0
  117. package/dist/commands/setup/uploads/templates/srcLibUploads.ts.template +24 -23
  118. package/dist/commands/setup/uploads/uploads.js +7 -49
  119. package/dist/commands/setup/uploads/uploadsHandler.js +69 -256
  120. package/dist/commands/setup.js +1 -2
  121. package/dist/commands/studio.js +1 -1
  122. package/dist/commands/test/testHandler.js +71 -25
  123. package/dist/commands/test/testHandlerEsm.js +109 -0
  124. package/dist/commands/test.js +18 -10
  125. package/dist/commands/testEsm.js +41 -0
  126. package/dist/commands/type-checkHandler.js +1 -1
  127. package/dist/commands/upgrade/preUpgradeScripts.js +3 -3
  128. package/dist/commands/upgrade/upgrade.js +1 -1
  129. package/dist/commands/upgrade/upgradeHandler.js +1 -2
  130. package/dist/index.js +8 -5
  131. package/dist/lib/exit.js +1 -1
  132. package/dist/lib/index.js +25 -6
  133. package/dist/lib/loadEnvFiles.js +1 -1
  134. package/dist/lib/plugin.js +1 -1
  135. package/dist/lib/test.js +1 -1
  136. package/dist/lib/updateCheck.js +4 -4
  137. package/dist/middleware/checkNodeVersion.js +4 -4
  138. package/package.json +18 -18
  139. package/dist/commands/generate/cell/templates/cellFragment.tsx.template +0 -43
  140. package/dist/commands/generate/cell/templates/storiesFragment.tsx.template +0 -23
  141. package/dist/commands/generate/cell/templates/testFragment.js.template +0 -30
  142. package/dist/commands/generate/dbAuth/templates/login.oauth.tsx.template +0 -164
  143. package/dist/commands/generate/dbAuth/templates/signup.oauth.tsx.template +0 -147
  144. package/dist/commands/setup/tenancy/authCodemod.js +0 -66
  145. package/dist/commands/setup/tenancy/dbCodemod.js +0 -64
  146. package/dist/commands/setup/tenancy/graphqlCodemod.js +0 -88
  147. package/dist/commands/setup/tenancy/preflight.js +0 -49
  148. package/dist/commands/setup/tenancy/schemaPrisma.js +0 -81
  149. package/dist/commands/setup/tenancy/signupCodemod.js +0 -153
  150. package/dist/commands/setup/tenancy/templates/InvitePage.tsx.template +0 -63
  151. package/dist/commands/setup/tenancy/templates/OrgScope.tsx.template +0 -40
  152. package/dist/commands/setup/tenancy/templates/ensureDefaultOrganizations.dataMigration.ts.template +0 -39
  153. package/dist/commands/setup/tenancy/templates/organizations.scenarios.ts.template +0 -59
  154. package/dist/commands/setup/tenancy/templates/organizations.sdl.ts.template +0 -89
  155. package/dist/commands/setup/tenancy/templates/organizations.test.ts.template +0 -389
  156. package/dist/commands/setup/tenancy/templates/organizations.ts.template +0 -394
  157. package/dist/commands/setup/tenancy/templates/requireMembership.test.ts.template +0 -35
  158. package/dist/commands/setup/tenancy/templates/requireMembership.ts.template +0 -25
  159. package/dist/commands/setup/tenancy/tenancy.js +0 -30
  160. package/dist/commands/setup/tenancy/tenancyHandler.js +0 -425
  161. package/dist/commands/setup/uploads/schemaPrisma.js +0 -41
  162. package/dist/commands/setup/uploads/serverFile.js +0 -151
  163. package/dist/commands/setup/uploads/templates/requireUploadToken.ts.template +0 -15
  164. package/dist/commands/setup/uploads/templates/uploads.sdl.ts.template +0 -79
  165. package/dist/commands/setup/uploads/templates/uploads.ts.template +0 -89
  166. package/dist/commands/setup/uploads/templates/withDataUri.ts.template +0 -14
  167. package/dist/commands/setup/uploads/templates/withSignedUrl.ts.template +0 -16
  168. package/dist/commands/test/viteVersionCheck.js +0 -75
@@ -1,4 +1,4 @@
1
- import { recordTelemetryAttributes } from "@cedarjs/cli-helpers/telemetry";
1
+ import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
2
2
  const command = "server-file";
3
3
  const description = "Setup the server file";
4
4
  function builder(yargs) {
@@ -1,8 +1,7 @@
1
1
  import fs from "node:fs";
2
2
  import path from "path";
3
3
  import { Listr } from "listr2";
4
- import { colors as c } from "@cedarjs/cli-helpers/colors";
5
- import { addApiPackages } from "@cedarjs/cli-helpers/installHelpers";
4
+ import { addApiPackages, colors as c } from "@cedarjs/cli-helpers";
6
5
  import { errorTelemetry } from "@cedarjs/telemetry";
7
6
  import { getPaths, transformTSToJS, writeFile } from "../../../lib/index.js";
8
7
  import { isTypeScriptProject } from "../../../lib/project.js";
@@ -1,8 +1,7 @@
1
1
  import path from "path";
2
2
  import { Listr } from "listr2";
3
- import { colors as c } from "@cedarjs/cli-helpers/colors";
3
+ import { recordTelemetryAttributes, colors as c } from "@cedarjs/cli-helpers";
4
4
  import { addWorkspacePackages } from "@cedarjs/cli-helpers/packageManager/packages";
5
- import { recordTelemetryAttributes } from "@cedarjs/cli-helpers/telemetry";
6
5
  import extendStorybookConfiguration from "../../../../lib/configureStorybook.js";
7
6
  import { extendJSXFile, fileIncludes } from "../../../../lib/extendFile.js";
8
7
  import { getPaths, writeFile } from "../../../../lib/index.js";
@@ -1,9 +1,8 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { Listr } from "listr2";
4
- import { colors as c } from "@cedarjs/cli-helpers/colors";
4
+ import { recordTelemetryAttributes, colors as c } from "@cedarjs/cli-helpers";
5
5
  import { addWorkspacePackages } from "@cedarjs/cli-helpers/packageManager/packages";
6
- import { recordTelemetryAttributes } from "@cedarjs/cli-helpers/telemetry";
7
6
  import extendStorybookConfiguration from "../../../../lib/configureStorybook.js";
8
7
  import { extendJSXFile, fileIncludes } from "../../../../lib/extendFile.js";
9
8
  import { getPaths, writeFile } from "../../../../lib/index.js";
@@ -4,14 +4,13 @@ import { ListrEnquirerPromptAdapter } from "@listr2/prompt-adapter-enquirer";
4
4
  import execa from "execa";
5
5
  import { Listr } from "listr2";
6
6
  import { terminalLink } from "termi-link";
7
- import { colors as c } from "@cedarjs/cli-helpers/colors";
7
+ import { recordTelemetryAttributes, colors as c } from "@cedarjs/cli-helpers";
8
8
  import { formatCedarCommand } from "@cedarjs/cli-helpers/packageManager/display";
9
9
  import { runBin } from "@cedarjs/cli-helpers/packageManager/exec";
10
10
  import {
11
11
  addRootPackages,
12
12
  addWorkspacePackages
13
13
  } from "@cedarjs/cli-helpers/packageManager/packages";
14
- import { recordTelemetryAttributes } from "@cedarjs/cli-helpers/telemetry";
15
14
  import { errorTelemetry } from "@cedarjs/telemetry";
16
15
  import { getPaths, usingVSCode } from "../../../../lib/index.js";
17
16
  const tailwindDirectives = [
@@ -0,0 +1,28 @@
1
+ import j from "jscodeshift";
2
+ function transform(fileInfo) {
3
+ const root = j(fileInfo.source);
4
+ const imports = root.find(j.ImportDeclaration);
5
+ imports.at(-1).insertAfter(
6
+ j.importDeclaration(
7
+ [j.importSpecifier(j.identifier("storagePrismaExtension"))],
8
+ j.literal("./uploads.js")
9
+ )
10
+ );
11
+ root.find(j.VariableDeclaration, { declarations: [{ id: { name: "db" } }] }).forEach((path) => {
12
+ const dbDeclaration = path.node.declarations[0];
13
+ if (j.VariableDeclarator.check(dbDeclaration) && j.NewExpression.check(dbDeclaration.init)) {
14
+ throw new Error("RW_CODEMOD_ERR_OLD_FORMAT");
15
+ }
16
+ if (j.VariableDeclarator.check(dbDeclaration) && j.Expression.check(dbDeclaration.init)) {
17
+ const newInit = j.callExpression(
18
+ j.memberExpression(dbDeclaration.init, j.identifier("$extends")),
19
+ [j.identifier("storagePrismaExtension")]
20
+ );
21
+ dbDeclaration.init = newInit;
22
+ }
23
+ });
24
+ return root.toSource();
25
+ }
26
+ export {
27
+ transform as default
28
+ };
@@ -0,0 +1,21 @@
1
+ import type { APIGatewayEvent, Context } from 'aws-lambda'
2
+
3
+ import type { SignatureValidationArgs } from '@cedarjs/storage/UrlSigner'
4
+
5
+ import { urlSigner, fsStorage } from 'src/lib/uploads'
6
+
7
+ export const handler = async (event: APIGatewayEvent, _context: Context) => {
8
+ const fileToReturn = urlSigner.validateSignature(
9
+ event.queryStringParameters as SignatureValidationArgs
10
+ )
11
+
12
+ const { contents, type } = await fsStorage.read(fileToReturn)
13
+
14
+ return {
15
+ statusCode: 200,
16
+ headers: {
17
+ 'Content-Type': type,
18
+ },
19
+ body: contents,
20
+ }
21
+ }
@@ -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,265 +1,93 @@
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 { addUploadModel } from "./schemaPrisma.js";
22
- import {
23
- addUploadsPlugin,
24
- detectServerAuth,
25
- hasUploadsPlugin
26
- } from "./serverFile.js";
27
- const UPPY_VERSION = "^6.0.0";
28
- const S3_IMPORTS = `import { S3Client } from '@aws-sdk/client-s3'
29
-
30
- import { createS3Provider } from '@cedarjs/uploads/s3'
31
- `;
32
- const S3_CLIENT = `
33
- // Your own S3 client. It stays available for S3-specific work (lifecycle
34
- // rules, CORS, and so on) alongside the storage target below. Credentials
35
- // come from the SDK's default chain: AWS_ACCESS_KEY_ID and
36
- // AWS_SECRET_ACCESS_KEY in .env, or an IAM role, SSO, or container
37
- // credentials in production. For an S3-compatible service, add \`endpoint\`
38
- // and \`forcePathStyle: true\`.
39
- export const s3Client = new S3Client({
40
- region: process.env.AWS_REGION,
41
- })
42
- `;
43
- const TARGET_BLOCKS = {
44
- fs: ` // Files uploaded through the api server and stored on local disk. Good for
45
- // development and single-server deploys.
46
- local: createFsProvider({
47
- uploadDir: path.join(getPaths().api.base, '.uploads'),
48
- serveBaseUrl: process.env.UPLOAD_SERVE_BASE_URL,
49
- signSecret: process.env.UPLOAD_TOKEN_SECRET,
50
- }),
51
- `,
52
- db: ` // Small files stored inline in the Upload row (avatars, thumbnails).
53
- thumbnails: createDbProvider(),
54
- `,
55
- s3: ` // Files uploaded straight from the browser to S3 with presigned URLs.
56
- files: createS3Provider({
57
- client: s3Client,
58
- bucket: process.env.S3_BUCKET_UPLOADS,
59
- region: process.env.AWS_REGION,
60
- keyPrefix: 'uploads/',
61
- }),
62
- `
63
- };
64
- const PROFILE_BLOCKS = {
65
- fs: ` attachment: {
66
- target: 'local',
67
- allowedMimeTypes: ['application/pdf', 'image/png', 'image/jpeg'],
68
- maxFileSize: 25 * 1024 * 1024,
69
- maxFiles: 10,
70
- },
71
- `,
72
- db: ` avatar: {
73
- target: 'thumbnails',
74
- allowedMimeTypes: ['image/png', 'image/jpeg'],
75
- maxFileSize: DB_MAX_FILE_SIZE,
76
- maxFiles: 1,
77
- },
78
- `,
79
- s3: ` document: {
80
- target: 'files',
81
- allowedMimeTypes: ['application/pdf', 'image/*'],
82
- maxFileSize: 100 * 1024 * 1024,
83
- maxFiles: 5,
84
- },
85
- `
86
- };
87
- const handler = async ({ targets, force }) => {
88
- const paths = getPaths();
15
+ import { runTransform } from "../../../lib/runTransform.js";
16
+ const handler = async ({ force }) => {
89
17
  const projectIsTypescript = isTypeScriptProject();
90
- const ext = projectIsTypescript ? "ts" : "js";
91
- const wantsFs = targets.includes("fs");
92
- const wantsDb = targets.includes("db");
93
- const wantsS3 = targets.includes("s3");
94
- const wantsUppy = wantsFs || wantsS3;
95
- 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
+ });
96
21
  const cedarVersion = packageJson.default.devDependencies["@cedarjs/core"] ?? "latest";
97
- const serverFilePath = path.join(paths.api.src, `server.${ext}`);
98
- const writeTemplateFile = async (templateFile, outputPath, replacements = {}) => {
99
- const templatePath = path.resolve(
100
- import.meta.dirname,
101
- "templates",
102
- templateFile
103
- );
104
- let templateContent = fs.readFileSync(templatePath, "utf-8");
105
- for (const [token, value] of Object.entries(replacements)) {
106
- templateContent = templateContent.replaceAll(token, value);
107
- }
108
- const content = projectIsTypescript ? templateContent : await transformTSToJS(outputPath, templateContent);
109
- return writeFile(outputPath, content, { overwriteExisting: force });
110
- };
111
- const apiPackages = [`@cedarjs/uploads@${cedarVersion}`];
112
- const webPackages = [`@cedarjs/uploads@${cedarVersion}`];
113
- if (wantsS3) {
114
- apiPackages.push("@aws-sdk/client-s3", "@aws-sdk/s3-request-presigner");
115
- }
116
- if (wantsUppy) {
117
- webPackages.push(
118
- `@uppy/core@${UPPY_VERSION}`,
119
- `@uppy/react@${UPPY_VERSION}`,
120
- `@uppy/dashboard@${UPPY_VERSION}`
121
- );
122
- }
123
- if (wantsFs) {
124
- webPackages.push(`@uppy/xhr-upload@${UPPY_VERSION}`);
125
- }
126
- if (wantsS3) {
127
- webPackages.push(`@uppy/aws-s3@${UPPY_VERSION}`);
128
- }
129
22
  const tasks = new Listr(
130
23
  [
131
24
  {
132
- ...addApiPackages(apiPackages),
133
- title: "Adding @cedarjs/uploads to your api side..."
134
- },
135
- {
136
- ...addWebPackages(webPackages),
137
- title: "Adding @cedarjs/uploads to your web side..."
138
- },
139
- {
140
- title: "Adding the Upload model to schema.prisma...",
141
- task: async () => {
142
- const schemaPath = await getSchemaPath(paths.api.prismaConfig);
143
- const schema = fs.readFileSync(schemaPath, "utf-8");
144
- fs.writeFileSync(schemaPath, addUploadModel(schema));
145
- }
146
- },
147
- {
148
- title: `Adding api/src/lib/uploads.${ext}...`,
25
+ title: `Adding api/src/lib/uploads.${projectIsTypescript ? "ts" : "js"}...`,
149
26
  task: async () => {
150
- await writeTemplateFile(
151
- "srcLibUploads.ts.template",
152
- path.join(paths.api.lib, `uploads.${ext}`),
153
- {
154
- __S3_IMPORTS__: wantsS3 ? S3_IMPORTS : "",
155
- __S3_CLIENT__: wantsS3 ? S3_CLIENT : "",
156
- __FS_IMPORT__: wantsFs ? "createFsProvider," : "",
157
- __DB_IMPORT__: wantsDb ? "createDbProvider," : "",
158
- __DB_MAX_IMPORT__: wantsDb ? "DB_MAX_FILE_SIZE," : "",
159
- __PATH_IMPORT__: wantsFs ? "import path from 'node:path'\n\n" : "",
160
- __GET_PATHS_IMPORT__: wantsFs ? "import { getPaths } from '@cedarjs/project-config'\n" : "",
161
- __TARGETS__: targets.map((t) => TARGET_BLOCKS[t]).join("\n"),
162
- __PROFILES__: targets.map((t) => PROFILE_BLOCKS[t]).join("\n")
163
- }
27
+ const templatePath = path.resolve(
28
+ import.meta.dirname,
29
+ "templates",
30
+ "srcLibUploads.ts.template"
164
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"}`
39
+ );
40
+ const uploadsContent = projectIsTypescript ? templateContent : await transformTSToJS(uploadsPath, templateContent);
41
+ return writeFile(uploadsPath, uploadsContent, {
42
+ overwriteExisting: force
43
+ });
165
44
  }
166
45
  },
167
46
  {
168
- title: "Adding the uploads SDL and service...",
47
+ title: `Adding signedUrl function...`,
169
48
  task: async () => {
170
- await writeTemplateFile(
171
- "uploads.sdl.ts.template",
172
- path.join(paths.api.graphql, `uploads.sdl.${ext}`)
49
+ const templatePath = path.resolve(
50
+ import.meta.dirname,
51
+ "templates",
52
+ "signedUrl.ts.template"
173
53
  );
174
- await writeTemplateFile(
175
- "uploads.ts.template",
176
- 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"}`
177
61
  );
62
+ const uploadsContent = projectIsTypescript ? templateContent : await transformTSToJS(uploadsPath, templateContent);
63
+ return writeFile(uploadsPath, uploadsContent, {
64
+ overwriteExisting: force
65
+ });
178
66
  }
179
67
  },
180
68
  {
181
- title: "Adding the upload directives...",
182
- task: async () => {
183
- const directives = ["requireUploadToken", "withSignedUrl"];
184
- if (wantsDb) {
185
- directives.push("withDataUri");
186
- }
187
- for (const name of directives) {
188
- await writeTemplateFile(
189
- `${name}.ts.template`,
190
- path.join(paths.api.directives, name, `${name}.${ext}`)
191
- );
192
- }
193
- }
69
+ ...addApiPackages([`@cedarjs/storage@${cedarVersion}`]),
70
+ title: "Adding dependencies to your api side..."
194
71
  },
195
72
  {
196
- title: "Adding the server file...",
197
- task: (_ctx, task) => task.newListr(setupServerFileTasks({ force: false })),
198
- skip: () => fs.existsSync(serverFilePath) ? "api/src/server already exists; skipping." : false
199
- },
200
- {
201
- title: "Registering the upload plugin in api/src/server...",
202
- task: async (_ctx, task) => {
203
- const source = fs.readFileSync(serverFilePath, "utf-8");
204
- if (hasUploadsPlugin(source)) {
205
- task.skip("The upload plugin is already registered; skipping.");
206
- return;
207
- }
208
- const graphqlPath = path.join(paths.api.functions, `graphql.${ext}`);
209
- const authPath = path.join(paths.api.lib, `auth.${ext}`);
210
- const auth = fs.existsSync(graphqlPath) && fs.existsSync(authPath) && fs.readFileSync(authPath, "utf-8").includes("getCurrentUser") ? detectServerAuth(fs.readFileSync(graphqlPath, "utf-8")) : null;
211
- let updated;
212
- try {
213
- updated = addUploadsPlugin(source, { auth });
214
- } catch {
215
- throw new Error(
216
- `Could not find \`await server.start()\` in ${path.relative(
217
- paths.base,
218
- serverFilePath
219
- )}. Register the plugin by hand before the server starts:
220
-
221
- import { cedarUploadsPlugin } from '@cedarjs/uploads'
222
- import { db } from 'src/lib/db'
223
- import { targets } from 'src/lib/uploads'
224
-
225
- await server.register(cedarUploadsPlugin, {
226
- tokenSecret: process.env.UPLOAD_TOKEN_SECRET,
227
- targets,
228
- db,
229
- })
230
- `
231
- );
232
- }
233
- fs.writeFileSync(serverFilePath, updated);
234
- }
235
- },
236
- {
237
- title: "Adding environment variables to .env...",
238
- task: () => {
239
- addEnvVar(
240
- "UPLOAD_TOKEN_SECRET",
241
- generateSecret(),
242
- "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"}`
243
78
  );
244
- if (wantsFs) {
245
- addEnvVar(
246
- "UPLOAD_SERVE_BASE_URL",
247
- "http://localhost:8911",
248
- "Origin the api server is reachable at, used to build signed URLs for locally stored files."
249
- );
250
- }
251
- if (wantsS3) {
252
- addEnvVar(
253
- "AWS_REGION",
254
- "us-east-1",
255
- "Region of the uploads bucket."
256
- );
257
- addEnvVar("AWS_ACCESS_KEY_ID", "replace-me", "");
258
- addEnvVar("AWS_SECRET_ACCESS_KEY", "replace-me", "");
259
- addEnvVar(
260
- "S3_BUCKET_UPLOADS",
261
- "replace-me",
262
- "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"
263
91
  );
264
92
  }
265
93
  }
@@ -268,10 +96,10 @@ const handler = async ({ targets, force }) => {
268
96
  title: "Prettifying changed files",
269
97
  task: async (_ctx, task) => {
270
98
  const prettifyPaths = [
271
- serverFilePath,
272
- path.join(paths.api.lib, `uploads.${ext}`),
273
- path.join(paths.api.graphql, `uploads.sdl.${ext}`),
274
- 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")
275
103
  ];
276
104
  for (const prettifyPath of prettifyPaths) {
277
105
  try {
@@ -280,11 +108,11 @@ const handler = async ({ targets, force }) => {
280
108
  }
281
109
  const source = fs.readFileSync(prettifyPath, "utf-8");
282
110
  const prettierOptions = await getPrettierOptions();
283
- const prettified = await format(source, {
111
+ const prettifiedApp = await format(source, {
284
112
  ...prettierOptions,
285
113
  parser: "babel-ts"
286
114
  });
287
- fs.writeFileSync(prettifyPath, prettified, "utf-8");
115
+ fs.writeFileSync(prettifyPath, prettifiedApp, "utf-8");
288
116
  } catch {
289
117
  task.output = "Couldn't prettify the changes. Please reformat the files manually if needed.";
290
118
  }
@@ -294,30 +122,15 @@ const handler = async ({ targets, force }) => {
294
122
  {
295
123
  title: "One more thing...",
296
124
  task: (_ctx, task) => {
297
- const migrate = c.highlight(
298
- formatCedarCommand(["prisma", "migrate", "dev"])
299
- );
300
- const types = c.highlight(formatCedarCommand(["generate", "types"]));
301
125
  task.title = `One more thing...
302
126
 
303
- ${c.success("Uploads configured!")}
304
-
305
- Next steps:
306
-
307
- 1. Apply the schema change: ${migrate}
308
- 2. Regenerate types: ${types}
309
- 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" : ""}
127
+ ${c.success("\nUploads and storage configured!\n")}
310
128
 
311
- Upload tokens are bound to the logged-in user when the app has auth.
312
- If you add auth later, pass
313
- \`authenticate: createUploadAuthenticator({ authDecoder, getCurrentUser })\`
314
- to the plugin in api/src/server.${ext}.
315
-
316
- Schedule cleanupStaleUploads() from a recurring job to sweep uploads
317
- that never completed.
129
+ Remember to add UPLOADS_SECRET to your .env file. You can generate one with ${c.highlight(formatCedarCommand(["generate", "secret"]))}
318
130
 
319
131
  Check out the docs for more info:
320
132
  ${terminalLink("", "https://cedarjs.com/docs/uploads")}
133
+
321
134
  `;
322
135
  }
323
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) {