@flaredev/cli 0.12.0 → 0.12.1

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.
package/dist/index.js CHANGED
@@ -204,10 +204,12 @@ var PROVIDERS = {
204
204
  hint: { both: "a CDN with an uploader" },
205
205
  stacks: ["cloudflare", "next"],
206
206
  vars: {
207
- cloudflare: [{ name: "UPLOADTHING_TOKEN" }, { name: "UPLOADTHING_APP_ID", example: "a1b2c3d4e5" }],
208
- next: [{ name: "UPLOADTHING_TOKEN" }, { name: "UPLOADTHING_APP_ID", example: "a1b2c3d4e5" }]
207
+ // One variable, not two. The token is base64 JSON carrying the app id, so the
208
+ // driver reads the id out of it rather than asking for it a second time.
209
+ cloudflare: [{ name: "UPLOADTHING_TOKEN" }],
210
+ next: [{ name: "UPLOADTHING_TOKEN" }]
209
211
  },
210
- where: "UploadThing dashboard \u2192 your app \u2192 API Keys (the app id is in the same place)",
212
+ where: "UploadThing dashboard \u2192 your app \u2192 API Keys",
211
213
  console: "https://uploadthing.com/dashboard",
212
214
  docs: `${DOCS}/uploadthing/`,
213
215
  install: "uploadthing",
@@ -276,13 +278,17 @@ function storageEnvExample(name, stack) {
276
278
  lines.push("", `# Or switch driver: ${others.join(", ")} \u2014 see the guide above.`, "");
277
279
  return lines.join("\n");
278
280
  }
279
- function storageSetupSteps(name, stack) {
281
+ function storageSetupSteps(name, stack, options2 = {}) {
280
282
  const provider = STORAGE_PROVIDERS[name];
281
283
  const vars = storageVars(name, stack);
282
284
  const steps = [];
283
- if (provider.install) steps.push(`Install its SDK: ${provider.install}`);
285
+ const readyLocally = options2.local !== false && vars.length > 0 && vars.every((variable) => variable.local);
284
286
  if (vars.length > 0 && provider.console) {
285
- steps.push(`Get ${vars.map((variable) => variable.name).join(", ")} from ${provider.where ?? provider.console}`);
287
+ if (readyLocally) {
288
+ steps.push(`Works locally as it is. When you deploy, replace ${vars.map((variable) => variable.name).join(", ")}:`);
289
+ } else {
290
+ steps.push(`Get ${vars.map((variable) => variable.name).join(", ")} from ${provider.where ?? provider.console}`);
291
+ }
286
292
  steps.push(provider.console);
287
293
  }
288
294
  if (provider.caveat) steps.push(provider.caveat);
@@ -388,6 +394,9 @@ var NEXT_DEV_DEPENDENCIES = {
388
394
  tailwindcss: "^4.3.3",
389
395
  typescript: "~5.9.3"
390
396
  };
397
+ var STORAGE_DEPENDENCIES = {
398
+ uploadthing: "^7.7.4"
399
+ };
391
400
  var CLOUDFLARE_ONLY = [
392
401
  "wrangler.jsonc",
393
402
  "vite.config.ts",
@@ -502,7 +511,15 @@ function installArgs(pm) {
502
511
  }
503
512
 
504
513
  // src/commands/create.ts
505
- var ALLOW_BUILDS = ["'@prisma/engines': false", "esbuild: true", "prisma: true", "sharp: false", "workerd: true"].map((line) => ` ${line}`).join("\n");
514
+ var SEED_ADMIN = { email: "admin@example.com", password: "Password", name: "Admin" };
515
+ var ALLOW_BUILDS = [
516
+ "'@prisma/engines': false",
517
+ "esbuild: true",
518
+ "msgpackr-extract: false",
519
+ "prisma: true",
520
+ "sharp: false",
521
+ "workerd: true"
522
+ ].map((line) => ` ${line}`).join("\n");
506
523
  function toAppName(dir) {
507
524
  const name = basename(resolve2(dir)).toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
508
525
  if (!name) throw new Error(`Cannot derive an app name from "${dir}". Use letters, digits, and dashes.`);
@@ -574,12 +591,22 @@ storage/
574
591
  // Which stack this app targets. `flare gen` reads it; don't change it by hand.
575
592
  flare: { stack },
576
593
  scripts: stack === "next" ? {
594
+ // Prisma 7 generates its client into lib/generated/prisma, which is
595
+ // git-ignored and therefore absent from every fresh checkout — including
596
+ // the one `create` has just written. Without this the first `dev` fails on
597
+ // `Can't resolve './generated/prisma/client'` before serving a page, and
598
+ // so does `flare user:add`, which imports lib/db. postinstall rather than a
599
+ // step in `dev`, so a teammate cloning the repo is covered by the same line.
600
+ postinstall: "prisma generate",
577
601
  dev: "next dev",
578
602
  build: "prisma generate && next build",
579
603
  start: "next start",
580
604
  deploy: "vercel deploy --prod",
581
605
  "db:generate": "prisma generate",
582
606
  "db:migrate": "prisma migrate dev",
607
+ // An account to sign in with, so the app is reachable the moment the tables
608
+ // exist. Safe to run twice: --skip-existing makes a second run a no-op.
609
+ "db:seed": `flare user:add ${SEED_ADMIN.email} --password ${SEED_ADMIN.password} --name ${SEED_ADMIN.name} --role admin --skip-existing`,
583
610
  "db:studio": "prisma studio"
584
611
  } : {
585
612
  dev: "flare dev",
@@ -592,7 +619,10 @@ storage/
592
619
  },
593
620
  dependencies: {
594
621
  "@flaredev/core": flarePackageSpec("core", dir, packageManager),
595
- ...stack === "next" ? { ...uiOnly, ...shared, ...NEXT_DEPENDENCIES } : APP_DEPENDENCIES
622
+ ...stack === "next" ? { ...uiOnly, ...shared, ...NEXT_DEPENDENCIES } : APP_DEPENDENCIES,
623
+ // The chosen provider's SDK, where it has one, so the first upload works without
624
+ // a second install.
625
+ ...storage in STORAGE_DEPENDENCIES ? { [storage]: STORAGE_DEPENDENCIES[storage] } : {}
596
626
  },
597
627
  devDependencies: {
598
628
  "@flaredev/cli": flarePackageSpec("cli", dir, packageManager),
@@ -651,9 +681,15 @@ function copyLockfile(packageManager, dir, stack) {
651
681
  function printNextSteps(result, installed) {
652
682
  const rel = relative(process.cwd(), result.dir) || ".";
653
683
  const pm = result.packageManager;
684
+ const database = result.stack === "next" ? [
685
+ ["docker compose up -d", "Postgres, on the address .env already has"],
686
+ [`${pm} run db:migrate`, "create the tables"],
687
+ [`${pm} run db:seed`, "an account to sign in with"]
688
+ ] : [];
654
689
  const commands = [
655
690
  [`cd ${rel}`, "your new app"],
656
691
  ...installed ? [] : [[`${pm} install`, "dependencies first"]],
692
+ ...database,
657
693
  [`${pm} run dev`, "http://localhost:3000"],
658
694
  ["npx flare gen resource Contact", "a table, API and admin screens"],
659
695
  ["npx flare seed:resource Contact 1000", "fill it with sample rows"]
@@ -661,10 +697,20 @@ function printNextSteps(result, installed) {
661
697
  const width = Math.max(...commands.map(([command]) => command.length)) + 2;
662
698
  const steps = commands.map(([command, note2]) => `${pc.cyan(command.padEnd(width))}${pc.dim(note2)}`);
663
699
  prompts.note(steps.join("\n"), "Next");
664
- const storage = storageSetupSteps(result.storage, result.stack);
700
+ const storage = storageSetupSteps(result.storage, result.stack, { local: true });
665
701
  if (storage.length > 0) {
666
702
  prompts.note(storage.map((line) => line.startsWith("http") ? pc.cyan(line) : line).join("\n"), `Uploads \xB7 ${result.storage}`);
667
703
  }
704
+ if (result.stack === "next") {
705
+ prompts.note(
706
+ [
707
+ `${pc.cyan(SEED_ADMIN.email)} ${pc.dim("\xB7")} ${pc.cyan(SEED_ADMIN.password)}`,
708
+ "",
709
+ pc.dim(`Made by ${pm} run db:seed, as an admin. Change it before this app is anywhere but your machine.`)
710
+ ].join("\n"),
711
+ "Sign in with"
712
+ );
713
+ }
668
714
  prompts.outro(`${pc.bold(result.name)} is ready ${pc.dim("\xB7")} ${pc.cyan("https://flare-docs.codetotech.com/start/quickstart/")}`);
669
715
  }
670
716
 
@@ -3107,6 +3153,7 @@ ${result.output.trim()}`);
3107
3153
  // src/commands/user-add.ts
3108
3154
  var EMAIL = /^[^\s@'"\\]+@[^\s@'"\\]+\.[^\s@'"\\]+$/;
3109
3155
  var ROLE = /^[a-z][a-z0-9_-]{0,31}$/;
3156
+ var KEPT = -1;
3110
3157
  function generatePassword(length = 24) {
3111
3158
  const alphabet = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789";
3112
3159
  const bytes = crypto.getRandomValues(new Uint8Array(length));
@@ -3153,7 +3200,8 @@ async function addUser(email, options2 = {}) {
3153
3200
  const password = options2.password ?? generatePassword();
3154
3201
  const generated = options2.password === void 0;
3155
3202
  const rows = await credentialUserRows({ email: address, password, name: options2.name, role: options2.role });
3156
- const code = readStack(appRoot) === "next" ? await addOnPrisma(appRoot, rows, log2) : await addOnD1(appRoot, rows, options2, log2);
3203
+ const code = readStack(appRoot) === "next" ? await addOnPrisma(appRoot, rows, log2, options2.skipExisting) : await addOnD1(appRoot, rows, options2, log2);
3204
+ if (code === KEPT) return 0;
3157
3205
  if (code !== 0) return code;
3158
3206
  log2(pc9.green(`\u2714 ${address} can now sign in${options2.role ? ` as ${options2.role}` : ""}.`));
3159
3207
  if (generated) {
@@ -3186,6 +3234,10 @@ async function addOnD1(appRoot, rows, options2, log2) {
3186
3234
  ${existing.output.trim()}`);
3187
3235
  const [found] = extractJson(existing.output);
3188
3236
  if ((found?.results ?? []).length > 0) {
3237
+ if (options2.skipExisting) {
3238
+ log2(pc9.dim(`${rows.user.email} already has an account \u2014 left as it is.`));
3239
+ return KEPT;
3240
+ }
3189
3241
  log2(pc9.red(`${rows.user.email} already has an account.`));
3190
3242
  log2(pc9.dim("To change their role: flare user:role <email> <role>"));
3191
3243
  return 1;
@@ -3195,7 +3247,7 @@ ${existing.output.trim()}`);
3195
3247
  ${result.output.trim()}`);
3196
3248
  return 0;
3197
3249
  }
3198
- async function addOnPrisma(appRoot, rows, log2) {
3250
+ async function addOnPrisma(appRoot, rows, log2, skipExisting = false) {
3199
3251
  const runner = join15(appRoot, ".flare-user-add-runner.mts");
3200
3252
  const script = [
3201
3253
  `import "dotenv/config";`,
@@ -3222,6 +3274,10 @@ async function addOnPrisma(appRoot, rows, log2) {
3222
3274
  try {
3223
3275
  const code = await runNode([resolveBin(appRoot, "tsx", "tsx"), runner], appRoot);
3224
3276
  if (code === 3) {
3277
+ if (skipExisting) {
3278
+ log2(pc9.dim(`${rows.user.email} already has an account \u2014 left as it is.`));
3279
+ return KEPT;
3280
+ }
3225
3281
  log2(pc9.red(`${rows.user.email} already has an account.`));
3226
3282
  log2(pc9.dim("To change their role: flare user:role <email> <role>"));
3227
3283
  return 1;
@@ -7870,9 +7926,11 @@ function createCli() {
7870
7926
  cli.command("sync-types", "Regenerate schema, routes, clients, and validators from resource descriptors; report drift").option("--check", "Change nothing; exit 1 if anything is out of sync (CI)").option("--force", "Overwrite generated blocks that were edited by hand").action(async (options2) => {
7871
7927
  process.exitCode = await syncTypes(options2);
7872
7928
  });
7873
- cli.command("user:add <email>", "Create an account from the command line (the way in when signup is closed)").option("--role <role>", "Role to give them, e.g. admin").option("--password <password>", "Their password (generated and printed when omitted)").option("--name <name>", "Display name (default: the part before the @)").option("--remote", "Against the deployed database rather than the local one").option("--env <name>", "Wrangler environment").example("flare user:add ada@example.com --role admin").action(async (email, options2) => {
7874
- process.exitCode = await addUser(email, options2);
7875
- });
7929
+ cli.command("user:add <email>", "Create an account from the command line (the way in when signup is closed)").option("--role <role>", "Role to give them, e.g. admin").option("--password <password>", "Their password (generated and printed when omitted)").option("--name <name>", "Display name (default: the part before the @)").option("--remote", "Against the deployed database rather than the local one").option("--env <name>", "Wrangler environment").option("--skip-existing", "Succeed quietly if the account is already there (for seeds)").example("flare user:add ada@example.com --role admin").action(
7930
+ async (email, options2) => {
7931
+ process.exitCode = await addUser(email, options2);
7932
+ }
7933
+ );
7876
7934
  cli.command("doctor", "Check the things that are usually wrong: versions, env, bindings, migrations, drift, policies").option("--offline", "Skip the checks that ask the database").example("flare doctor").action(async (options2) => {
7877
7935
  process.exitCode = await doctor(options2);
7878
7936
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flaredev/cli",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "The flare command-line tool: create, generate, migrate, and deploy Flare apps",
5
5
  "license": "MIT",
6
6
  "author": "Muke Johnbaptist",
@@ -41,7 +41,7 @@
41
41
  "jiti": "^2.7.0",
42
42
  "jsonc-parser": "^3.3.1",
43
43
  "picocolors": "^1.1.1",
44
- "@flaredev/core": "0.12.0"
44
+ "@flaredev/core": "0.12.1"
45
45
  },
46
46
  "engines": {
47
47
  "node": ">=22"
@@ -19,9 +19,8 @@ MAIL_FROM=
19
19
  # CLOUDINARY_API_KEY=
20
20
  # CLOUDINARY_API_SECRET=
21
21
 
22
- # STORAGE_DRIVER=uploadthing # needs: pnpm add uploadthing
23
- # UPLOADTHING_TOKEN=
24
- # UPLOADTHING_APP_ID=
22
+ # STORAGE_DRIVER=uploadthing
23
+ # UPLOADTHING_TOKEN= # the app id is inside it; there is no second variable
25
24
 
26
25
  # Both serve files from their own CDN, so a read URL is public and does not expire.
27
26
  # Set this to keep every read signed and proxied by the app instead.
@@ -22,10 +22,13 @@ export interface UploadThingOptions {
22
22
  /** From the UploadThing dashboard. Defaults to `UPLOADTHING_TOKEN`. */
23
23
  token?: string;
24
24
  /**
25
- * The app id, which is the subdomain files are served from. Defaults to
26
- * `UPLOADTHING_APP_ID`.
25
+ * The app id, which is the subdomain files are served from.
26
+ *
27
+ * Almost never passed: it is already inside the token, and {@link appIdFromToken}
28
+ * reads it from there. Pass it only to serve from a different subdomain than the
29
+ * token names.
27
30
  */
28
- appId: string;
31
+ appId?: string;
29
32
  /**
30
33
  * Serve reads from UploadThing's CDN. Default true, which is the reason to use it.
31
34
  * See {@link StorageBucket.publicUrl}: those files are readable by anyone with the
@@ -50,6 +53,38 @@ export function customIdFor(key: string): string {
50
53
  return key.replace(/[^A-Za-z0-9.-]/g, (char) => `_${char.charCodeAt(0).toString(16).padStart(2, "0")}`);
51
54
  }
52
55
 
56
+ /**
57
+ * The app id carried inside an UploadThing token.
58
+ *
59
+ * A v7 token is base64 JSON — `{ apiKey, appId, regions }` — so the id of the app it
60
+ * belongs to is already in your hands the moment you have the token. Asking for
61
+ * `UPLOADTHING_APP_ID` as well was asking for a value that cannot disagree with the
62
+ * token without being wrong, and the failure it produced was a quiet one: uploads
63
+ * succeeded and every read 404'd from a subdomain belonging to another app.
64
+ *
65
+ * Only the `appId` is read here. The apiKey stays in the token, which is what the SDK
66
+ * itself is given.
67
+ */
68
+ export function appIdFromToken(token: string): string {
69
+ let decoded: string;
70
+ try {
71
+ decoded = typeof atob === "function" ? atob(token) : Buffer.from(token, "base64").toString("utf8");
72
+ } catch {
73
+ throw new Error("UPLOADTHING_TOKEN is not valid base64. Copy it again from https://uploadthing.com/dashboard.");
74
+ }
75
+ let parsed: unknown;
76
+ try {
77
+ parsed = JSON.parse(decoded);
78
+ } catch {
79
+ throw new Error("UPLOADTHING_TOKEN does not decode to JSON. Copy it again from https://uploadthing.com/dashboard.");
80
+ }
81
+ const appId = (parsed as { appId?: unknown } | null)?.appId;
82
+ if (typeof appId !== "string" || appId === "") {
83
+ throw new Error("UPLOADTHING_TOKEN has no appId in it. Copy it again from https://uploadthing.com/dashboard.");
84
+ }
85
+ return appId;
86
+ }
87
+
53
88
  /**
54
89
  * The part of UTApi this driver uses.
55
90
  *
@@ -82,7 +117,10 @@ async function api(token: string | undefined): Promise<UTApiLike> {
82
117
 
83
118
  export function uploadThingBucket(options: UploadThingOptions): StorageBucket {
84
119
  const publicDelivery = options.publicDelivery ?? true;
85
- const deliveryUrl = (key: string) => `https://${options.appId}.ufs.sh/f/${customIdFor(key)}`;
120
+ // Read once rather than per request, so a malformed token is an error at startup
121
+ // instead of a 404 on somebody's first upload.
122
+ const appId = options.appId ?? appIdFromToken(options.token ?? process.env.UPLOADTHING_TOKEN ?? "");
123
+ const deliveryUrl = (key: string) => `https://${appId}.ufs.sh/f/${customIdFor(key)}`;
86
124
 
87
125
  return {
88
126
  async get(key: string): Promise<StorageObjectBody | null> {
@@ -74,8 +74,8 @@ function selectBucket(): StorageBucket {
74
74
  });
75
75
  case "uploadthing":
76
76
  return uploadThingBucket({
77
+ // The app id lives inside the token; the driver reads it from there.
77
78
  token: required("UPLOADTHING_TOKEN"),
78
- appId: required("UPLOADTHING_APP_ID"),
79
79
  publicDelivery,
80
80
  });
81
81
  case "r2":
@@ -4290,9 +4290,9 @@
4290
4290
  "license": "MIT"
4291
4291
  },
4292
4292
  "node_modules/@tailwindcss/node": {
4293
- "version": "4.3.4",
4294
- "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.4.tgz",
4295
- "integrity": "sha512-b7QK/QG04v3j04NbpG82XLCedRyulnkuwUDwRa9oK/ypnJIzMapz2Wg+0TltVczjUzDaJJHIa1+jj9aMUOFMTQ==",
4293
+ "version": "4.3.5",
4294
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.5.tgz",
4295
+ "integrity": "sha512-yT53FzV4ke0cr/BguDxhWMpm5MJu1O2muzk+tKw6lKHjODAsYArBbWwFbJiaksfzFv1tpkO9QHGzmfs1hJT66g==",
4296
4296
  "dev": true,
4297
4297
  "license": "MIT",
4298
4298
  "dependencies": {
@@ -4302,37 +4302,37 @@
4302
4302
  "lightningcss": "1.33.0",
4303
4303
  "magic-string": "^1.1.0",
4304
4304
  "source-map-js": "^1.2.1",
4305
- "tailwindcss": "4.3.4"
4305
+ "tailwindcss": "4.3.5"
4306
4306
  }
4307
4307
  },
4308
4308
  "node_modules/@tailwindcss/oxide": {
4309
- "version": "4.3.4",
4310
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.4.tgz",
4311
- "integrity": "sha512-riqsRw2sLF7B1sNCCkTl3KYXEqvhTiABzZ/4oxxHfZ3c3Td60bCBfOrUuUGOiHagd3E7V+zG46c+XBDWZGFBcg==",
4309
+ "version": "4.3.5",
4310
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.5.tgz",
4311
+ "integrity": "sha512-PynqGLZsZvwM9tqD/CUxkOIfyd6K5elZ2MooauzJryP/UqXYgi3yYbtt3N0Xe+MHV/eFKPFQCEfIKAqlAS1CBg==",
4312
4312
  "dev": true,
4313
4313
  "license": "MIT",
4314
4314
  "engines": {
4315
4315
  "node": ">= 20"
4316
4316
  },
4317
4317
  "optionalDependencies": {
4318
- "@tailwindcss/oxide-android-arm64": "4.3.4",
4319
- "@tailwindcss/oxide-darwin-arm64": "4.3.4",
4320
- "@tailwindcss/oxide-darwin-x64": "4.3.4",
4321
- "@tailwindcss/oxide-freebsd-x64": "4.3.4",
4322
- "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.4",
4323
- "@tailwindcss/oxide-linux-arm64-gnu": "4.3.4",
4324
- "@tailwindcss/oxide-linux-arm64-musl": "4.3.4",
4325
- "@tailwindcss/oxide-linux-x64-gnu": "4.3.4",
4326
- "@tailwindcss/oxide-linux-x64-musl": "4.3.4",
4327
- "@tailwindcss/oxide-wasm32-wasi": "4.3.4",
4328
- "@tailwindcss/oxide-win32-arm64-msvc": "4.3.4",
4329
- "@tailwindcss/oxide-win32-x64-msvc": "4.3.4"
4318
+ "@tailwindcss/oxide-android-arm64": "4.3.5",
4319
+ "@tailwindcss/oxide-darwin-arm64": "4.3.5",
4320
+ "@tailwindcss/oxide-darwin-x64": "4.3.5",
4321
+ "@tailwindcss/oxide-freebsd-x64": "4.3.5",
4322
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.5",
4323
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.3.5",
4324
+ "@tailwindcss/oxide-linux-arm64-musl": "4.3.5",
4325
+ "@tailwindcss/oxide-linux-x64-gnu": "4.3.5",
4326
+ "@tailwindcss/oxide-linux-x64-musl": "4.3.5",
4327
+ "@tailwindcss/oxide-wasm32-wasi": "4.3.5",
4328
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.3.5",
4329
+ "@tailwindcss/oxide-win32-x64-msvc": "4.3.5"
4330
4330
  }
4331
4331
  },
4332
4332
  "node_modules/@tailwindcss/oxide-android-arm64": {
4333
- "version": "4.3.4",
4334
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.4.tgz",
4335
- "integrity": "sha512-qkjxt+EFocOi3mtsUS3ndlj6yj4SHubwBdvBynLnS8T4mvSzX0Enn0CpypJKmBEtczUAXOHVZKA2zTGzSNU2Sg==",
4333
+ "version": "4.3.5",
4334
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.5.tgz",
4335
+ "integrity": "sha512-Se0z5xMqcSQanJD1IYmO0cGpK3iv0fp3ZsIT7xRJZ1Da5PghvNoc46zz4jIQn+aan3dV9T8AermFNN9QPmsh0Q==",
4336
4336
  "cpu": [
4337
4337
  "arm64"
4338
4338
  ],
@@ -4347,9 +4347,9 @@
4347
4347
  }
4348
4348
  },
4349
4349
  "node_modules/@tailwindcss/oxide-darwin-arm64": {
4350
- "version": "4.3.4",
4351
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.4.tgz",
4352
- "integrity": "sha512-i/awUA/7mJQAbA3AzCW8aQtUh5goMieUdF1zOoclLaJUCxDvsXQ8VJqpQZY3dfcHS6PJjd3tw25nNneD/mEviQ==",
4350
+ "version": "4.3.5",
4351
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.5.tgz",
4352
+ "integrity": "sha512-UPrgTDuUbvmqGMZuCnmI3FKee/tYKzKdp00/kuB4oSGB213VYg8QTdF7lVhnPoBXq/mIfJ+ILoBFqNOboWcMwQ==",
4353
4353
  "cpu": [
4354
4354
  "arm64"
4355
4355
  ],
@@ -4364,9 +4364,9 @@
4364
4364
  }
4365
4365
  },
4366
4366
  "node_modules/@tailwindcss/oxide-darwin-x64": {
4367
- "version": "4.3.4",
4368
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.4.tgz",
4369
- "integrity": "sha512-q56V9U6AnoYz/yj/alkDLhSQ9AZoXQSEl93f7WETa0+32CudbqM57BXdYXfMYPKudueXKaA+MG6L/0KRseF7Jg==",
4367
+ "version": "4.3.5",
4368
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.5.tgz",
4369
+ "integrity": "sha512-E+p7HEtjI0b8D7kbbWxH067cGui6d4c79COGko9fAPVE3rwc1E7ld2HFCbaG86AOGWS5VKQYqZOaf38ya4uxTQ==",
4370
4370
  "cpu": [
4371
4371
  "x64"
4372
4372
  ],
@@ -4381,9 +4381,9 @@
4381
4381
  }
4382
4382
  },
4383
4383
  "node_modules/@tailwindcss/oxide-freebsd-x64": {
4384
- "version": "4.3.4",
4385
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.4.tgz",
4386
- "integrity": "sha512-r0W7A+Z9HTHh7bwihJl45E/zZKLjxD50/jToVF/E/RZHSl8+EWO+4yKKJpPMcUooT9hdoip3Zx1uWnbMg4N79g==",
4384
+ "version": "4.3.5",
4385
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.5.tgz",
4386
+ "integrity": "sha512-yWEWcWyAG7rWOcTpJTjdhQ3pcaFY2h+0bqTRfgU3G2fz87ZU3AKdvdZKhslD+kyHnjBUWKvNdRYwIYC5dI1tIg==",
4387
4387
  "cpu": [
4388
4388
  "x64"
4389
4389
  ],
@@ -4398,9 +4398,9 @@
4398
4398
  }
4399
4399
  },
4400
4400
  "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
4401
- "version": "4.3.4",
4402
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.4.tgz",
4403
- "integrity": "sha512-3aih/sRxzeYfi2Bkh+bGYNf2YU9Llamb2mpA7BNF1obYzdgEeWDAMQzK6BSwzLhs/eTdOaSur92qrGfchagUtQ==",
4401
+ "version": "4.3.5",
4402
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.5.tgz",
4403
+ "integrity": "sha512-WmeVjtJhZlr+smpqcdR2kQkkn6arHIJnUIBxTO2EJcTLGY1ecVXNo2hbSn8xc0IH2aEtys936iMWKGyj0GaKnA==",
4404
4404
  "cpu": [
4405
4405
  "arm"
4406
4406
  ],
@@ -4415,9 +4415,9 @@
4415
4415
  }
4416
4416
  },
4417
4417
  "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
4418
- "version": "4.3.4",
4419
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.4.tgz",
4420
- "integrity": "sha512-ktJSrPGQou4OqL88rDEx5CkeM9BjzrwZvYo8u7B7VL1zkBa2XBm351o4MQrek95qikb2M++26Y7w7vbH6Mgl8g==",
4418
+ "version": "4.3.5",
4419
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.5.tgz",
4420
+ "integrity": "sha512-DTCSyucc6ShMp1QMqV5R94Z7xlgNgUzkGmFF1rL5HH2Qjy4eSmEqy+YLGkqqYvWa4sILtgrBt1JjRKbneQtiFQ==",
4421
4421
  "cpu": [
4422
4422
  "arm64"
4423
4423
  ],
@@ -4435,9 +4435,9 @@
4435
4435
  }
4436
4436
  },
4437
4437
  "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
4438
- "version": "4.3.4",
4439
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.4.tgz",
4440
- "integrity": "sha512-rt3hjUxT7utAtcB+df6wHyaXDyxhE7Zd1x7L/nvB5Jb2qBb8dZwFUoWqeRja1BaF5OlSqkKSjBmVXj9OsevmCQ==",
4438
+ "version": "4.3.5",
4439
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.5.tgz",
4440
+ "integrity": "sha512-H9lsvO4x9E4nE4Hi8h7NHHw0O/kcVSu+iOyFHNGdYzazGgDjFHZbE6S3hQ8kMcbNXSBlMdNi67LV5EVqtpaJtw==",
4441
4441
  "cpu": [
4442
4442
  "arm64"
4443
4443
  ],
@@ -4455,9 +4455,9 @@
4455
4455
  }
4456
4456
  },
4457
4457
  "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
4458
- "version": "4.3.4",
4459
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.4.tgz",
4460
- "integrity": "sha512-XE3jO2yOOWjttpeGvpwf3/b274NMi3QapQSAI/EzsgrmYNan1Tw8dXT9JQkN7K0OgvuqiC8mcCyNvGzEkpVJPQ==",
4458
+ "version": "4.3.5",
4459
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.5.tgz",
4460
+ "integrity": "sha512-4uxQvtBvPuIdl13WfUBj9xMZHH14PtHZ8OZdtLmdyDtG66sCa1t599NZT+jagkUzRtWhuul1qRZQ1nAJscXN5g==",
4461
4461
  "cpu": [
4462
4462
  "x64"
4463
4463
  ],
@@ -4475,9 +4475,9 @@
4475
4475
  }
4476
4476
  },
4477
4477
  "node_modules/@tailwindcss/oxide-linux-x64-musl": {
4478
- "version": "4.3.4",
4479
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.4.tgz",
4480
- "integrity": "sha512-PaAZ2FjJaZk9SQLYtKIfQWiFm/xtl7pX2MKPgCzn0mS/VU54yu+vP457AJdB2XFLxU3gO2abLCt8N7Lg4EbKNg==",
4478
+ "version": "4.3.5",
4479
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.5.tgz",
4480
+ "integrity": "sha512-0JQAzs7jwbA7O6+z/adU+Jk3AXwsu3npAhtr5escXS7TqEqWcaDV7qHuI+0Vy/KQRuVGnLQREcSJWYauyV3oqg==",
4481
4481
  "cpu": [
4482
4482
  "x64"
4483
4483
  ],
@@ -4495,9 +4495,9 @@
4495
4495
  }
4496
4496
  },
4497
4497
  "node_modules/@tailwindcss/oxide-wasm32-wasi": {
4498
- "version": "4.3.4",
4499
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.4.tgz",
4500
- "integrity": "sha512-bjO9WmoM687p8AoCIyw1DUqzpAs4JICLvNmIPxIWDmhw8IOsdubtWQLShyJmISnDKtRy1BBApHVOUl6sNFQQJA==",
4498
+ "version": "4.3.5",
4499
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.5.tgz",
4500
+ "integrity": "sha512-OJhFmlEfdzMr+avACdi40RPtnkW0B6hXyxL/8r+tnEHBWZji36CYRjEXrrvgBmaYsD3oEOBqwYFRKsYvzFe7Bw==",
4501
4501
  "bundleDependencies": [
4502
4502
  "@napi-rs/wasm-runtime",
4503
4503
  "@emnapi/core",
@@ -4591,9 +4591,9 @@
4591
4591
  "optional": true
4592
4592
  },
4593
4593
  "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
4594
- "version": "4.3.4",
4595
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.4.tgz",
4596
- "integrity": "sha512-jCrwCvWVtt7ruMXp6dFPd5KBNU8o1tWtEdZbTL/w/hvD3lUYZA0E2mmfvTzW4QLHIx5wGQU9HeY7997R1QTrEg==",
4594
+ "version": "4.3.5",
4595
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.5.tgz",
4596
+ "integrity": "sha512-9o8jgthi+QE5eandnboiJT64VQfnIArfZzSTdgbhEK5aafdiu2jTW9Honi/mwYHxBZuH1vAC57IFyrh+0iK5Gg==",
4597
4597
  "cpu": [
4598
4598
  "arm64"
4599
4599
  ],
@@ -4608,9 +4608,9 @@
4608
4608
  }
4609
4609
  },
4610
4610
  "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
4611
- "version": "4.3.4",
4612
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.4.tgz",
4613
- "integrity": "sha512-cge1wcedn1FrRSXL22lF5sNDYr8c9+VImk7zFYLPs12jkDmchSrZNfzWqOKub+5Hb/aYRdDEqERGGDKONBlOzQ==",
4611
+ "version": "4.3.5",
4612
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.5.tgz",
4613
+ "integrity": "sha512-XiKFfIy1RWe7qK4WqByxNW7Oz1/nkOy8o/BWhHminyV1PmpUd8Eedj5v2A8h2kpqeVlz6xRnwk9Fr/ZXNLcZfg==",
4614
4614
  "cpu": [
4615
4615
  "x64"
4616
4616
  ],
@@ -4625,17 +4625,17 @@
4625
4625
  }
4626
4626
  },
4627
4627
  "node_modules/@tailwindcss/postcss": {
4628
- "version": "4.3.4",
4629
- "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.4.tgz",
4630
- "integrity": "sha512-6O0QLY+1CseO8ivlYK2Y7IxNPaQ8D5ypxrV+ws34mbxknWH824J+gEWtJ0gyFiYAudmdEeXdF8kqwgXIaZRyHw==",
4628
+ "version": "4.3.5",
4629
+ "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.5.tgz",
4630
+ "integrity": "sha512-FAV37Tlx9wBiT/hkfgVD0Q6CWsP2oUX3lf28nrfjW8+ksILjnpuFulUqWDfNR4/ZiEHHDRBX8DUTzD1Rys687A==",
4631
4631
  "dev": true,
4632
4632
  "license": "MIT",
4633
4633
  "dependencies": {
4634
4634
  "@alloc/quick-lru": "^5.2.0",
4635
- "@tailwindcss/node": "4.3.4",
4636
- "@tailwindcss/oxide": "4.3.4",
4635
+ "@tailwindcss/node": "4.3.5",
4636
+ "@tailwindcss/oxide": "4.3.5",
4637
4637
  "postcss": "^8.5.25",
4638
- "tailwindcss": "4.3.4"
4638
+ "tailwindcss": "4.3.5"
4639
4639
  }
4640
4640
  },
4641
4641
  "node_modules/@types/estree": {
@@ -7842,9 +7842,9 @@
7842
7842
  "license": "MIT"
7843
7843
  },
7844
7844
  "node_modules/schema-utils": {
7845
- "version": "4.8.2",
7846
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.8.2.tgz",
7847
- "integrity": "sha512-iKlak3OFHF0dgD1nZRvgWQzG+P1TiEcMnLSBtIVBg937z5Jd6WE1c3SyZkXIyCfPHowL35yMsVvIjotm1c1qiw==",
7845
+ "version": "4.8.3",
7846
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.8.3.tgz",
7847
+ "integrity": "sha512-qIfo3f+lRNqnMPgpXSKvUhsT3pY5U+ppmgGr4j8LanFP3W/Ze+xj8DY/dPb5qVu3m6qFIMyMWKVRLNKxrNhxWg==",
7848
7848
  "license": "MIT",
7849
7849
  "peer": true,
7850
7850
  "dependencies": {
@@ -7864,7 +7864,7 @@
7864
7864
  "url": "https://opencollective.com/webpack"
7865
7865
  },
7866
7866
  "peerDependencies": {
7867
- "webpack": "^5.112.0"
7867
+ "webpack": "^5.0.0"
7868
7868
  },
7869
7869
  "peerDependenciesMeta": {
7870
7870
  "webpack": {
@@ -8044,9 +8044,9 @@
8044
8044
  }
8045
8045
  },
8046
8046
  "node_modules/tailwindcss": {
8047
- "version": "4.3.4",
8048
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.4.tgz",
8049
- "integrity": "sha512-PCJZTFFdG+sL3gvnP1Do9o6GbkvH2q0p04xSs3f7cSvmAeK+sttG+/7ncK1fdRwKFfC7n+wDDJaOMBSefkI9ow==",
8047
+ "version": "4.3.5",
8048
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.5.tgz",
8049
+ "integrity": "sha512-FcQk9BuffmEHJP2G0XmB2SplU1aLTI7j07Kunk+U74Ny+XiWOtzXz9aujFZ/avntw1e2cOv/3PkgzflQ7gX2vQ==",
8050
8050
  "dev": true,
8051
8051
  "license": "MIT"
8052
8052
  },