@cedarjs/cli 8.0.0-canary.3525 → 8.0.0-canary.3526

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.
@@ -53,12 +53,26 @@ function transform(fileInfo) {
53
53
  if (!selectFound) {
54
54
  throw new Error("CEDAR_CODEMOD_ERR_AUTH_SHAPE_NOT_FOUND");
55
55
  }
56
- const tenancyExportSnippet = `export { hasOrgRole, requireMembership } from '@cedarjs/tenancy'
57
- `;
58
- const tenancyExport = j.withParser("ts")(tenancyExportSnippet).find(j.ExportNamedDeclaration).nodes()[0];
59
- root.find(j.Program).forEach((path) => {
60
- path.node.body.push(tenancyExport);
56
+ const exported = /* @__PURE__ */ new Set();
57
+ root.find(j.ExportNamedDeclaration, { source: { value: "@cedarjs/tenancy" } }).forEach((path) => {
58
+ for (const specifier of path.node.specifiers ?? []) {
59
+ if (j.Identifier.check(specifier.exported)) {
60
+ exported.add(specifier.exported.name);
61
+ }
62
+ }
61
63
  });
64
+ const missing = ["hasOrgRole", "requireMembership"].filter(
65
+ (name) => !exported.has(name)
66
+ );
67
+ if (missing.length > 0) {
68
+ const tenancyExport = j.withParser("ts")(
69
+ `export { ${missing.join(", ")} } from '@cedarjs/tenancy'
70
+ `
71
+ ).find(j.ExportNamedDeclaration).nodes()[0];
72
+ root.find(j.Program).forEach((path) => {
73
+ path.node.body.push(tenancyExport);
74
+ });
75
+ }
62
76
  return root.toSource();
63
77
  }
64
78
  export {
@@ -2,14 +2,23 @@ import j from "jscodeshift";
2
2
  const DEFAULT_GLOBAL_MODELS = ["user", "organization", "membership"];
3
3
  function transform(fileInfo, _api, options) {
4
4
  const root = j.withParser("tsx")(fileInfo.source);
5
+ if (root.find(j.CallExpression, {
6
+ callee: { name: "createTenancyExtension" }
7
+ }).length > 0) {
8
+ return fileInfo.source;
9
+ }
10
+ const hasImport = root.find(j.ImportSpecifier, {
11
+ imported: { name: "createTenancyExtension" }
12
+ }).length > 0;
13
+ if (!hasImport) {
14
+ root.find(j.ImportDeclaration).at(-1).insertAfter(
15
+ j.importDeclaration(
16
+ [j.importSpecifier(j.identifier("createTenancyExtension"))],
17
+ j.literal("@cedarjs/tenancy")
18
+ )
19
+ );
20
+ }
5
21
  const tenantField = typeof options.tenantField === "string" ? options.tenantField : void 0;
6
- const imports = root.find(j.ImportDeclaration);
7
- imports.at(-1).insertAfter(
8
- j.importDeclaration(
9
- [j.importSpecifier(j.identifier("createTenancyExtension"))],
10
- j.literal("@cedarjs/tenancy")
11
- )
12
- );
13
22
  const configProperties = [
14
23
  ...tenantField ? [
15
24
  j.objectProperty(
@@ -47,16 +47,25 @@ function buildContextProperty() {
47
47
  return property;
48
48
  }
49
49
  function addNamedImport(root, names, source) {
50
+ const missing = names.filter(
51
+ (name) => root.find(j.ImportSpecifier, { local: { name } }).length === 0
52
+ );
53
+ if (missing.length === 0) {
54
+ return;
55
+ }
50
56
  const imports = root.find(j.ImportDeclaration);
51
57
  imports.at(-1).insertAfter(
52
58
  j.importDeclaration(
53
- names.map((name) => j.importSpecifier(j.identifier(name))),
59
+ missing.map((name) => j.importSpecifier(j.identifier(name))),
54
60
  j.literal(source)
55
61
  )
56
62
  );
57
63
  }
58
64
  function transform(fileInfo) {
59
65
  const root = j.withParser("tsx")(fileInfo.source);
66
+ if (root.find(j.CallExpression, { callee: { name: "resolveCurrentOrg" } }).length > 0) {
67
+ return fileInfo.source;
68
+ }
60
69
  const handlerCalls = root.find(j.CallExpression, {
61
70
  callee: { name: "createGraphQLHandler" }
62
71
  });
@@ -15,7 +15,7 @@ const MEMBERSHIP_MODEL = `model Membership {
15
15
  invitedById String?
16
16
  invitationToken String? @unique
17
17
  createdAt DateTime @default(now())
18
- updatedAt DateTime @updatedAt
18
+ updatedAt DateTime @updatedAt
19
19
  user User? @relation(fields: [userId], references: [id])
20
20
  organization Organization @relation(fields: [organizationId], references: [id])
21
21
  invitedBy Membership? @relation("Inviter", fields: [invitedById], references: [id])
@@ -30,6 +30,10 @@ const RW_DATA_MIGRATION_MODEL = `model RW_DataMigration {
30
30
  startedAt DateTime
31
31
  finishedAt DateTime
32
32
  }`;
33
+ const collapseWhitespace = (text) => text.replace(/\s+/g, " ").trim();
34
+ function hasCanonicalModel(schema, model) {
35
+ return collapseWhitespace(schema).includes(collapseWhitespace(model));
36
+ }
33
37
  function hasModel(schema, modelName) {
34
38
  return new RegExp(`\\bmodel\\s+${modelName}\\s*\\{`).test(schema);
35
39
  }
@@ -37,7 +41,7 @@ function addTenancyModels(schema) {
37
41
  return [ORGANIZATION_MODEL, MEMBERSHIP_MODEL].reduce(appendModel, schema);
38
42
  }
39
43
  function appendModel(schema, model) {
40
- if (schema.includes(model)) {
44
+ if (hasCanonicalModel(schema, model)) {
41
45
  return schema;
42
46
  }
43
47
  return `${schema.trimEnd()}
@@ -58,8 +62,8 @@ function editSchema(schema, options) {
58
62
  if (!hasModel(schema, "User")) {
59
63
  throw new Error("CEDAR_TENANCY_ERR_NO_USER_MODEL");
60
64
  }
61
- const organizationIsCustomized = hasModel(schema, "Organization") && !schema.includes(ORGANIZATION_MODEL);
62
- const membershipIsCustomized = hasModel(schema, "Membership") && !schema.includes(MEMBERSHIP_MODEL);
65
+ const organizationIsCustomized = hasModel(schema, "Organization") && !hasCanonicalModel(schema, ORGANIZATION_MODEL);
66
+ const membershipIsCustomized = hasModel(schema, "Membership") && !hasCanonicalModel(schema, MEMBERSHIP_MODEL);
63
67
  const modelsCustomized = organizationIsCustomized || membershipIsCustomized;
64
68
  if (modelsCustomized && !options.force) {
65
69
  return { schema: addDataMigrationModel(schema), outcome: "skipped" };
@@ -70,12 +74,70 @@ function editSchema(schema, options) {
70
74
  outcome: modelsCustomized ? "forced" : "added"
71
75
  };
72
76
  }
77
+ const SCALAR_PLACEHOLDERS = {
78
+ String: "'__NAME__ __N__'",
79
+ Int: "__N__",
80
+ BigInt: "__N__",
81
+ Float: "__N__",
82
+ Decimal: "__N__",
83
+ Boolean: "false",
84
+ DateTime: "new Date()",
85
+ Json: "{}",
86
+ Bytes: "new Uint8Array()"
87
+ };
88
+ const FILLED_USER_FIELDS = ["email", "hashedPassword", "salt"];
89
+ function requiredUserFields(schema) {
90
+ const body = schema.match(/\bmodel\s+User\s*\{([\s\S]*?)\n\}/)?.[1];
91
+ if (!body) {
92
+ return [];
93
+ }
94
+ const enumValues = (name) => schema.match(new RegExp(`\\benum\\s+${name}\\s*\\{([\\s\\S]*?)\\}`))?.[1].split("\n").map(
95
+ (line) => line.replace(/\/\/.*/, "").trim().match(/^([A-Za-z_]\w*)(?:\s|$)/)?.[1]
96
+ ).find((member) => member !== void 0);
97
+ const relationKeys = [
98
+ ...body.matchAll(/@relation\([^)]*fields:\s*\[([^\]]*)\]/g)
99
+ ].flatMap((match) => match[1].split(",").map((key) => key.trim()));
100
+ return body.split("\n").flatMap((line) => {
101
+ const field = line.replace(/\/\/.*/, "").trim().match(/^(\w+)\s+(\w+)(\?|\[\])?(.*)$/);
102
+ if (!field) {
103
+ return [];
104
+ }
105
+ const [, name, type, modifier, attributes] = field;
106
+ if (modifier || FILLED_USER_FIELDS.includes(name) || relationKeys.includes(name) || /@(default|updatedAt|relation)\b/.test(attributes)) {
107
+ return [];
108
+ }
109
+ const scalar = SCALAR_PLACEHOLDERS[type];
110
+ if (scalar) {
111
+ return [{ name, value: scalar.replace("__NAME__", name) }];
112
+ }
113
+ const enumValue = enumValues(type);
114
+ return enumValue ? [{ name, value: `'${enumValue}'` }] : [];
115
+ });
116
+ }
117
+ function addRequiredUserFields(source, fields, { firstNumber = 1 } = {}) {
118
+ if (fields.length === 0) {
119
+ return source;
120
+ }
121
+ let n = firstNumber - 1;
122
+ return source.replace(/^(\s*)salt: 'x',$/gm, (line, indent) => {
123
+ n++;
124
+ return [
125
+ line,
126
+ ...fields.map(
127
+ (field) => `${indent}${field.name}: ${field.value.replaceAll("__N__", String(n))},`
128
+ )
129
+ ].join("\n");
130
+ });
131
+ }
73
132
  export {
74
133
  MEMBERSHIP_MODEL,
75
134
  ORGANIZATION_MODEL,
76
135
  RW_DATA_MIGRATION_MODEL,
77
136
  addDataMigrationModel,
137
+ addRequiredUserFields,
78
138
  addTenancyModels,
79
139
  editSchema,
80
- hasModel
140
+ hasCanonicalModel,
141
+ hasModel,
142
+ requiredUserFields
81
143
  };
@@ -110,6 +110,14 @@ function wrapCreateCall(fn) {
110
110
  }
111
111
  function transform(fileInfo) {
112
112
  const root = j.withParser("tsx")(fileInfo.source);
113
+ if (root.find(j.CallExpression, {
114
+ callee: { name: "ensureDefaultOrganization" }
115
+ }).length > 0) {
116
+ return fileInfo.source;
117
+ }
118
+ const hasImport = root.find(j.ImportSpecifier, {
119
+ local: { name: "ensureDefaultOrganization" }
120
+ }).length > 0;
113
121
  const signupOptionsDeclarators = root.find(j.VariableDeclarator, {
114
122
  id: { name: "signupOptions" }
115
123
  });
@@ -140,13 +148,14 @@ function transform(fileInfo) {
140
148
  throw new Error("CEDAR_CODEMOD_ERR_SIGNUP_SHAPE_NOT_FOUND");
141
149
  }
142
150
  addInvitationTokenToUserAttributes(root);
143
- const imports = root.find(j.ImportDeclaration);
144
- imports.at(-1).insertAfter(
145
- j.importDeclaration(
146
- [j.importSpecifier(j.identifier("ensureDefaultOrganization"))],
147
- j.literal("src/services/organizations/organizations")
148
- )
149
- );
151
+ if (!hasImport) {
152
+ root.find(j.ImportDeclaration).at(-1).insertAfter(
153
+ j.importDeclaration(
154
+ [j.importSpecifier(j.identifier("ensureDefaultOrganization"))],
155
+ j.literal("src/services/organizations/organizations")
156
+ )
157
+ );
158
+ }
150
159
  return root.toSource();
151
160
  }
152
161
  export {
@@ -11,7 +11,8 @@ const BATCH_SIZE = 100
11
11
  *
12
12
  * Run with `__DATA_MIGRATE_UP_COMMAND__`, after
13
13
  * `__PRISMA_MIGRATE_DEV_COMMAND__` has applied the
14
- * `Organization`/`Membership` migration.
14
+ * `Organization`/`Membership` migration and `__PRISMA_GENERATE_COMMAND__`
15
+ * has updated the Prisma client.
15
16
  */
16
17
  export default async ({ db }: { db: PrismaClient }) => {
17
18
  let cursor: string | undefined
@@ -3,8 +3,9 @@ import type { ScenarioData } from '@cedarjs/testing/api'
3
3
  import type { Membership, Organization, Prisma } from 'src/lib/db'
4
4
 
5
5
  // This scenario assumes a dbAuth-style `User` model (`email`,
6
- // `hashedPassword`, `salt`). Adjust the `user` fixture below to match your
7
- // app's actual `User` fields if you use a different auth provider.
6
+ // `hashedPassword`, `salt`), plus placeholders for any other fields your
7
+ // `User` requires. Adjust the `user` fixtures below if you use a different
8
+ // auth provider.
8
9
  export const standard = defineScenario<
9
10
  Prisma.OrganizationCreateArgs | Prisma.MembershipCreateArgs
10
11
  >({
@@ -11,7 +11,10 @@ import {
11
11
  addWebPackages
12
12
  } from "@cedarjs/cli-helpers/installHelpers";
13
13
  import { formatCedarCommand } from "@cedarjs/cli-helpers/packageManager/display";
14
- import { runTransitiveBin } from "@cedarjs/cli-helpers/packageManager/exec";
14
+ import {
15
+ runBinSync,
16
+ runTransitiveBin
17
+ } from "@cedarjs/cli-helpers/packageManager/exec";
15
18
  import { getDataMigrationsPath, getSchemaPath } from "@cedarjs/project-config";
16
19
  import { errorTelemetry } from "@cedarjs/telemetry";
17
20
  import { getPaths, transformTSToJS, writeFile } from "../../../lib/index.js";
@@ -23,10 +26,12 @@ import {
23
26
  noUserModelMessage
24
27
  } from "./preflight.js";
25
28
  import {
29
+ addRequiredUserFields,
26
30
  editSchema,
27
31
  hasModel,
28
32
  MEMBERSHIP_MODEL,
29
- ORGANIZATION_MODEL
33
+ ORGANIZATION_MODEL,
34
+ requiredUserFields
30
35
  } from "./schemaPrisma.js";
31
36
  const DEFAULT_TENANT_FIELD = "organizationId";
32
37
  const AUTH_SNIPPET = `
@@ -87,14 +92,22 @@ const handler = async ({ tenantField, force }) => {
87
92
  const graphqlPath = path.join(paths.api.functions, `graphql.${ext}`);
88
93
  const functionsAuthPath = path.join(paths.api.functions, `auth.${ext}`);
89
94
  const isDbAuthProject = fs.existsSync(functionsAuthPath) && fs.readFileSync(functionsAuthPath, "utf-8").includes("DbAuthHandler");
90
- const writeTemplateFile = async (templateFile, outputPath, replacements = {}) => {
95
+ const writtenFiles = [];
96
+ const keptFiles = [];
97
+ const writeTemplateFile = async (templateFile, outputPath, replacements = {}, transform = (content) => content) => {
91
98
  const dirname = import.meta.dirname;
92
99
  const templatePath = path.resolve(dirname, "templates", templateFile);
93
100
  let templateContent = fs.readFileSync(templatePath, "utf-8");
94
101
  for (const [token, value] of Object.entries(replacements)) {
95
102
  templateContent = templateContent.replaceAll(token, value);
96
103
  }
104
+ templateContent = transform(templateContent);
97
105
  const content = projectIsTypescript ? templateContent : await transformTSToJS(outputPath, templateContent);
106
+ if (fs.existsSync(outputPath) && !force) {
107
+ keptFiles.push(outputPath);
108
+ return;
109
+ }
110
+ writtenFiles.push(outputPath);
98
111
  return writeFile(outputPath, content, { overwriteExisting: force });
99
112
  };
100
113
  const tasks = new Listr(
@@ -153,9 +166,9 @@ Re-run with --force to have this command append its own versions beside them ins
153
166
  "`prisma format` failed, so the `memberships` relation was not added to the `User` model. Add it by hand: `memberships Membership[]` as the last field of `model User { ... }`, then re-run this command."
154
167
  );
155
168
  }
156
- const membershipsOccurrences = (schema2) => (schema2.match(/memberships\s+Membership\[\]/g) ?? []).length;
157
169
  const formattedSchema = fs.readFileSync(schemaPath, "utf-8");
158
- if (membershipsOccurrences(formattedSchema) <= membershipsOccurrences(editResult.schema)) {
170
+ const userModel = formattedSchema.match(/\bmodel\s+User\s*\{[\s\S]*?\n\}/)?.[0] ?? "";
171
+ if (!/^\s*memberships\s+Membership\[\]/m.test(userModel)) {
159
172
  if (editResult.outcome === "forced") {
160
173
  task.output = 'The `memberships` relation was not added to the `User` model, likely because of the clash from --force. Continuing with the rest of the setup; see "Next steps" for how to merge the appended models by hand.';
161
174
  return;
@@ -260,17 +273,28 @@ ${SIGNUP_SNIPPET}`;
260
273
  title: "Adding the organizations service...",
261
274
  task: async () => {
262
275
  const serviceDir = path.join(paths.api.services, "organizations");
276
+ const userFields = requiredUserFields(
277
+ fs.readFileSync(
278
+ await getSchemaPath(paths.api.prismaConfig),
279
+ "utf-8"
280
+ )
281
+ );
282
+ const withUserFields = (firstNumber) => (content) => addRequiredUserFields(content, userFields, { firstNumber });
263
283
  await writeTemplateFile(
264
284
  "organizations.ts.template",
265
285
  path.join(serviceDir, `organizations.${ext}`)
266
286
  );
267
287
  await writeTemplateFile(
268
288
  "organizations.test.ts.template",
269
- path.join(serviceDir, `organizations.test.${ext}`)
289
+ path.join(serviceDir, `organizations.test.${ext}`),
290
+ {},
291
+ withUserFields(101)
270
292
  );
271
293
  await writeTemplateFile(
272
294
  "organizations.scenarios.ts.template",
273
- path.join(serviceDir, `organizations.scenarios.${ext}`)
295
+ path.join(serviceDir, `organizations.scenarios.${ext}`),
296
+ {},
297
+ withUserFields(1)
274
298
  );
275
299
  await writeTemplateFile(
276
300
  "organizations.sdl.ts.template",
@@ -280,10 +304,17 @@ ${SIGNUP_SNIPPET}`;
280
304
  },
281
305
  {
282
306
  title: "Adding a data migration to backfill existing users...",
283
- task: async () => {
307
+ task: async (_ctx, task) => {
284
308
  const dataMigrationsPath = await getDataMigrationsPath(
285
309
  paths.api.prismaConfig
286
310
  );
311
+ const existing = fs.existsSync(dataMigrationsPath) && fs.readdirSync(dataMigrationsPath).find(
312
+ (file) => /-ensure-default-organizations\.[jt]s$/.test(file)
313
+ );
314
+ if (existing) {
315
+ task.skip(`Already added: ${existing}`);
316
+ return;
317
+ }
287
318
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().split(".")[0].replace(/\D/g, "");
288
319
  await writeTemplateFile(
289
320
  "ensureDefaultOrganizations.dataMigration.ts.template",
@@ -300,6 +331,10 @@ ${SIGNUP_SNIPPET}`;
300
331
  "prisma",
301
332
  "migrate",
302
333
  "dev"
334
+ ]),
335
+ __PRISMA_GENERATE_COMMAND__: formatCedarCommand([
336
+ "prisma",
337
+ "generate"
303
338
  ])
304
339
  }
305
340
  );
@@ -327,34 +362,39 @@ ${SIGNUP_SNIPPET}`;
327
362
  }
328
363
  },
329
364
  {
330
- title: "Prettifying changed files",
365
+ title: "Formatting and linting changed files...",
331
366
  task: async (_ctx, task) => {
332
- const prettifyPaths = [
333
- path.join(paths.api.lib, "db.js"),
334
- path.join(paths.api.lib, "db.ts"),
335
- path.join(paths.api.lib, "auth.js"),
336
- path.join(paths.api.lib, "auth.ts"),
337
- path.join(paths.api.functions, "graphql.js"),
338
- path.join(paths.api.functions, "graphql.ts"),
339
- path.join(paths.api.functions, "auth.js"),
340
- path.join(paths.api.functions, "auth.ts")
341
- ];
342
- for (const prettifyPath of prettifyPaths) {
367
+ const changedFiles = [
368
+ ...writtenFiles,
369
+ ...["db", "auth"].map((name) => path.join(paths.api.lib, name)),
370
+ ...["graphql", "auth"].map(
371
+ (name) => path.join(paths.api.functions, name)
372
+ )
373
+ ].flatMap(
374
+ (file) => path.extname(file) ? [file] : [`${file}.js`, `${file}.ts`]
375
+ ).filter((file) => fs.existsSync(file));
376
+ const prettierOptions = await getPrettierOptions();
377
+ for (const file of changedFiles) {
343
378
  try {
344
- if (!fs.existsSync(prettifyPath)) {
345
- continue;
346
- }
347
- const source = fs.readFileSync(prettifyPath, "utf-8");
348
- const prettierOptions = await getPrettierOptions();
349
- const prettifiedApp = await format(source, {
379
+ const source = fs.readFileSync(file, "utf-8");
380
+ const formatted = await format(source, {
350
381
  ...prettierOptions,
351
382
  parser: "babel-ts"
352
383
  });
353
- fs.writeFileSync(prettifyPath, prettifiedApp, "utf-8");
384
+ fs.writeFileSync(file, formatted, "utf-8");
354
385
  } catch {
355
386
  task.output = "Couldn't prettify the changes. Please reformat the files manually if needed.";
356
387
  }
357
388
  }
389
+ try {
390
+ runBinSync("eslint", ["--fix", ...changedFiles], {
391
+ cwd: paths.base
392
+ });
393
+ } catch {
394
+ task.output = `Some of the changed files still have lint errors. Run ${c.highlight(
395
+ formatCedarCommand(["lint"])
396
+ )} to see them.`;
397
+ }
358
398
  }
359
399
  },
360
400
  {
@@ -365,6 +405,7 @@ ${SIGNUP_SNIPPET}`;
365
405
  "migrate",
366
406
  "dev"
367
407
  ]);
408
+ const generateCommand = formatCedarCommand(["prisma", "generate"]);
368
409
  const dataMigrateCommand = formatCedarCommand(["data-migrate", "up"]);
369
410
  const modelsExistWarning = ctx.modelsExistOutcome === "forced" ? c.error(
370
411
  "\nschema.prisma is currently invalid (as requested by --force): merge the appended Organization/Membership blocks with your existing ones, then run `prisma format`.\n"
@@ -376,12 +417,14 @@ ${SIGNUP_SNIPPET}`;
376
417
  ${c.success("\nMulti-tenancy configured!\n")}
377
418
  ${modelsExistWarning}
378
419
  1. Run ${c.highlight(migrateCommand)} to create the Organization/Membership
379
- tables, then ${c.highlight(dataMigrateCommand)} to give every existing
380
- user a default organization.
420
+ tables and ${c.highlight(generateCommand)} to update the Prisma client,
421
+ then ${c.highlight(dataMigrateCommand)} to give every existing user a
422
+ default organization.
381
423
  2. \`db.ts\`'s tenancy extension scopes every model except
382
424
  User/Organization/Membership. For each existing model (e.g.
383
- Contact) whose rows belong to one organization, add ${c.highlight("organizationId String")} plus ${c.highlight("@@index([organizationId])")}
384
- to it in schema.prisma; for each one that stays global, add it
425
+ Contact) whose rows belong to one organization, add
426
+ ${c.highlight("organizationId String")} plus ${c.highlight("@@index([organizationId])")} to it in
427
+ schema.prisma; for each one that stays global, add it
385
428
  to the ${c.highlight("allExcept")} list in api/src/lib/db instead.
386
429
  3. Wrap your organization routes with the generated OrgScope in
387
430
  web/src/Routes.tsx:
@@ -399,7 +442,12 @@ ${SIGNUP_SNIPPET}`;
399
442
  "@cedarjs/tenancy"
400
443
  )}.
401
444
 
402
- Check out the docs for more info:
445
+ ${keptFiles.length > 0 ? `
446
+ Kept these existing files rather than overwriting them (run with
447
+ ${c.highlight("--force")} to overwrite):
448
+ ${keptFiles.map((file) => ` ${path.relative(paths.base, file)}`).join("\n")}
449
+
450
+ ` : ""} Check out the docs for more info:
403
451
  ${terminalLink("", "https://cedarjs.com/docs/tenancy")}
404
452
 
405
453
  `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cedarjs/cli",
3
- "version": "8.0.0-canary.3525",
3
+ "version": "8.0.0-canary.3526",
4
4
  "description": "The CedarJS Command Line",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,17 +36,17 @@
36
36
  "@babel/preset-typescript": "7.29.7",
37
37
  "@babel/traverse": "7.29.10",
38
38
  "@babel/types": "7.29.8",
39
- "@cedarjs/api-server": "8.0.0-canary.3525",
40
- "@cedarjs/babel-config": "8.0.0-canary.3525",
41
- "@cedarjs/cli-helpers": "8.0.0-canary.3525",
42
- "@cedarjs/internal": "8.0.0-canary.3525",
43
- "@cedarjs/prerender": "8.0.0-canary.3525",
44
- "@cedarjs/project-config": "8.0.0-canary.3525",
45
- "@cedarjs/structure": "8.0.0-canary.3525",
46
- "@cedarjs/telemetry": "8.0.0-canary.3525",
47
- "@cedarjs/utils": "8.0.0-canary.3525",
48
- "@cedarjs/vite": "8.0.0-canary.3525",
49
- "@cedarjs/web-server": "8.0.0-canary.3525",
39
+ "@cedarjs/api-server": "8.0.0-canary.3526",
40
+ "@cedarjs/babel-config": "8.0.0-canary.3526",
41
+ "@cedarjs/cli-helpers": "8.0.0-canary.3526",
42
+ "@cedarjs/internal": "8.0.0-canary.3526",
43
+ "@cedarjs/prerender": "8.0.0-canary.3526",
44
+ "@cedarjs/project-config": "8.0.0-canary.3526",
45
+ "@cedarjs/structure": "8.0.0-canary.3526",
46
+ "@cedarjs/telemetry": "8.0.0-canary.3526",
47
+ "@cedarjs/utils": "8.0.0-canary.3526",
48
+ "@cedarjs/vite": "8.0.0-canary.3526",
49
+ "@cedarjs/web-server": "8.0.0-canary.3526",
50
50
  "@listr2/prompt-adapter-enquirer": "4.4.3",
51
51
  "@opentelemetry/api": "1.9.1",
52
52
  "@opentelemetry/core": "2.12.0",
@@ -94,7 +94,7 @@
94
94
  "yargs": "18.2.0"
95
95
  },
96
96
  "devDependencies": {
97
- "@cedarjs/framework-tools": "8.0.0-canary.3525",
97
+ "@cedarjs/framework-tools": "8.0.0-canary.3526",
98
98
  "@prisma/dmmf": "7.10.1",
99
99
  "@types/archiver": "^7.0.0",
100
100
  "memfs": "4.80.0",