@beignet/cli 0.0.32 → 0.0.34

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 (92) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +29 -19
  3. package/dist/choices.d.ts +3 -3
  4. package/dist/choices.d.ts.map +1 -1
  5. package/dist/choices.js +2 -0
  6. package/dist/choices.js.map +1 -1
  7. package/dist/config.d.ts +1 -0
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +1 -0
  10. package/dist/config.js.map +1 -1
  11. package/dist/db.js +1 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +279 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/inspect.d.ts.map +1 -1
  16. package/dist/inspect.js +800 -60
  17. package/dist/inspect.js.map +1 -1
  18. package/dist/make/inbox.d.ts.map +1 -1
  19. package/dist/make/inbox.js +8 -6
  20. package/dist/make/inbox.js.map +1 -1
  21. package/dist/make/payments.d.ts.map +1 -1
  22. package/dist/make/payments.js +61 -32
  23. package/dist/make/payments.js.map +1 -1
  24. package/dist/make/shared.d.ts +11 -2
  25. package/dist/make/shared.d.ts.map +1 -1
  26. package/dist/make/shared.js +45 -11
  27. package/dist/make/shared.js.map +1 -1
  28. package/dist/make/tenancy.d.ts.map +1 -1
  29. package/dist/make/tenancy.js +9 -7
  30. package/dist/make/tenancy.js.map +1 -1
  31. package/dist/make.d.ts.map +1 -1
  32. package/dist/make.js +134 -60
  33. package/dist/make.js.map +1 -1
  34. package/dist/outbox.d.ts +114 -1
  35. package/dist/outbox.d.ts.map +1 -1
  36. package/dist/outbox.js +190 -0
  37. package/dist/outbox.js.map +1 -1
  38. package/dist/preflight.js +1 -1
  39. package/dist/preflight.js.map +1 -1
  40. package/dist/provider-add.d.ts.map +1 -1
  41. package/dist/provider-add.js +91 -62
  42. package/dist/provider-add.js.map +1 -1
  43. package/dist/registry-edits.js +2 -1
  44. package/dist/registry-edits.js.map +1 -1
  45. package/dist/task.d.ts.map +1 -1
  46. package/dist/task.js +2 -3
  47. package/dist/task.js.map +1 -1
  48. package/dist/templates/agents.d.ts.map +1 -1
  49. package/dist/templates/agents.js +6 -3
  50. package/dist/templates/agents.js.map +1 -1
  51. package/dist/templates/base.js +6 -6
  52. package/dist/templates/base.js.map +1 -1
  53. package/dist/templates/index.d.ts.map +1 -1
  54. package/dist/templates/index.js +2 -0
  55. package/dist/templates/index.js.map +1 -1
  56. package/dist/templates/server.d.ts.map +1 -1
  57. package/dist/templates/server.js +17 -10
  58. package/dist/templates/server.js.map +1 -1
  59. package/dist/templates/shared.d.ts +3 -1
  60. package/dist/templates/shared.d.ts.map +1 -1
  61. package/dist/templates/shared.js +11 -1
  62. package/dist/templates/shared.js.map +1 -1
  63. package/dist/templates/testing.d.ts +5 -0
  64. package/dist/templates/testing.d.ts.map +1 -0
  65. package/dist/templates/testing.js +542 -0
  66. package/dist/templates/testing.js.map +1 -0
  67. package/dist/templates/todos.js +4 -4
  68. package/package.json +3 -2
  69. package/skills/app-structure/SKILL.md +14 -4
  70. package/src/choices.ts +3 -0
  71. package/src/config.ts +2 -0
  72. package/src/db.ts +1 -1
  73. package/src/index.ts +437 -1
  74. package/src/inspect.ts +1248 -156
  75. package/src/make/inbox.ts +8 -6
  76. package/src/make/payments.ts +61 -32
  77. package/src/make/shared.ts +79 -12
  78. package/src/make/tenancy.ts +9 -7
  79. package/src/make.ts +177 -59
  80. package/src/outbox.ts +363 -0
  81. package/src/preflight.ts +1 -1
  82. package/src/provider-add.ts +92 -62
  83. package/src/registry-edits.ts +2 -1
  84. package/src/task.ts +2 -3
  85. package/src/templates/agents.ts +6 -3
  86. package/src/templates/base.ts +6 -6
  87. package/src/templates/index.ts +2 -0
  88. package/src/templates/server.ts +17 -10
  89. package/src/templates/shared.ts +13 -1
  90. package/src/templates/testing.ts +545 -0
  91. package/src/templates/todos.ts +4 -4
  92. package/src/test-helpers/generated-app.ts +10 -6
package/src/make.ts CHANGED
@@ -30,6 +30,7 @@ import {
30
30
  assertUseCaseApp,
31
31
  beignetDependencyVersion,
32
32
  constantCase,
33
+ createListenersRegistrySource,
33
34
  type DatabaseName,
34
35
  type DrizzleDialect,
35
36
  defineUploadsInitializerInfo,
@@ -66,6 +67,7 @@ import {
66
67
  jobFilePath,
67
68
  type ListenerNames,
68
69
  listenerFilePath,
70
+ listenersFilePath,
69
71
  type MakeResult,
70
72
  mergeMakeResultInto,
71
73
  mergeMakeResults,
@@ -115,6 +117,7 @@ import {
115
117
  updateInfrastructureGatePolicies,
116
118
  updateInfrastructurePortStub,
117
119
  updateInfrastructurePorts,
120
+ updateListenersRegistrySource,
118
121
  updateOpenApiRoute,
119
122
  updatePackageDependencies,
120
123
  updatePackageJson,
@@ -143,6 +146,7 @@ import {
143
146
  identifiersFromArrayExpression,
144
147
  insertAfterImports,
145
148
  } from "./registry-edits.js";
149
+ import { testSupportTemplateFiles } from "./templates/testing.js";
146
150
 
147
151
  export type { MakeFeatureAddon, MakeFeatureRecipe } from "./choices.js";
148
152
  export {
@@ -1240,7 +1244,7 @@ export async function makeSeed(
1240
1244
  if (
1241
1245
  await updatePackageScripts(
1242
1246
  targetDir,
1243
- { "db:seed": `bun ${seedEntrypointPath(config)}` },
1247
+ { "db:seed": `tsx ${seedEntrypointPath(config)}` },
1244
1248
  { dryRun: Boolean(options.dryRun) },
1245
1249
  )
1246
1250
  ) {
@@ -1319,6 +1323,9 @@ export async function makeListener(
1319
1323
  if (!options.skipEventAssert) {
1320
1324
  await assertListenerEventExists(targetDir, names.event, config);
1321
1325
  }
1326
+ await updateListenerRegistry(targetDir, names, config, {
1327
+ dryRun: true,
1328
+ });
1322
1329
  await updateListenerProviderWiring(targetDir, names, config, {
1323
1330
  dryRun: true,
1324
1331
  });
@@ -1339,6 +1346,24 @@ export async function makeListener(
1339
1346
  },
1340
1347
  });
1341
1348
 
1349
+ const registryResult = await updateListenerRegistry(
1350
+ targetDir,
1351
+ names,
1352
+ config,
1353
+ {
1354
+ dryRun: Boolean(options.dryRun),
1355
+ },
1356
+ );
1357
+ if (registryResult === "created")
1358
+ result.createdFiles.push(listenersFilePath(config));
1359
+ if (registryResult === "updated")
1360
+ result.updatedFiles.push(listenersFilePath(config));
1361
+ if (registryResult === "skipped")
1362
+ result.skippedFiles.push(listenersFilePath(config));
1363
+ if (!result.files.includes(listenersFilePath(config))) {
1364
+ result.files.push(listenersFilePath(config));
1365
+ }
1366
+
1342
1367
  const providerResult = await updateListenerProviderWiring(
1343
1368
  targetDir,
1344
1369
  names,
@@ -1360,6 +1385,49 @@ export async function makeListener(
1360
1385
  return result;
1361
1386
  }
1362
1387
 
1388
+ async function updateListenerRegistry(
1389
+ targetDir: string,
1390
+ names: ListenerNames,
1391
+ config: ResolvedBeignetConfig,
1392
+ options: { dryRun: boolean },
1393
+ ): Promise<WriteGeneratedFileResult> {
1394
+ const file = listenersFilePath(config);
1395
+ const filePath = path.join(targetDir, file);
1396
+ const listenerIndex = featureArtifactIndexFile("listener", names, config);
1397
+ const original = await readOptionalFile(filePath);
1398
+
1399
+ if (original === undefined) {
1400
+ if (!options.dryRun) {
1401
+ await writeGeneratedFile(
1402
+ targetDir,
1403
+ {
1404
+ path: file,
1405
+ content: createListenersRegistrySource({
1406
+ registryName: listenerIndex.registryName,
1407
+ listenerModule: aliasModule(listenerIndex.path),
1408
+ }),
1409
+ },
1410
+ { force: false, dryRun: false },
1411
+ );
1412
+ }
1413
+ return "created";
1414
+ }
1415
+
1416
+ const result = updateListenersRegistrySource(original, {
1417
+ registryName: listenerIndex.registryName,
1418
+ listenerModule: aliasModule(listenerIndex.path),
1419
+ });
1420
+ if (result.kind === "missing") {
1421
+ throw new Error(
1422
+ `Could not find the exported listeners array in ${file}. Register ${listenerIndex.registryName} manually, or restore the generated listeners file before running make listener.`,
1423
+ );
1424
+ }
1425
+
1426
+ if (result.kind === "unchanged") return "skipped";
1427
+ if (!options.dryRun) await writeFile(filePath, result.source);
1428
+ return "updated";
1429
+ }
1430
+
1363
1431
  async function assertListenerEventExists(
1364
1432
  targetDir: string,
1365
1433
  names: EventNames,
@@ -1701,6 +1769,7 @@ async function updateOutboxPorts(
1701
1769
  const filePath = path.join(targetDir, config.paths.ports);
1702
1770
  const original = await readFile(filePath, "utf8");
1703
1771
  let next = addNamedTypeImport(original, "OutboxPort", "@beignet/core/outbox");
1772
+ next = addNamedTypeImport(next, "OutboxAdminPort", "@beignet/core/outbox");
1704
1773
  if (!typeHasTopLevelProperty(next, "AppPorts", "outbox")) {
1705
1774
  next = insertTypeProperty(
1706
1775
  next,
@@ -1709,6 +1778,14 @@ async function updateOutboxPorts(
1709
1778
  `Could not find AppPorts in ${config.paths.ports}. Add outbox: OutboxPort; manually, or restore the generated ports file before running make outbox.`,
1710
1779
  );
1711
1780
  }
1781
+ if (!typeHasTopLevelProperty(next, "AppPorts", "outboxAdmin")) {
1782
+ next = insertTypeProperty(
1783
+ next,
1784
+ "AppPorts",
1785
+ "outboxAdmin: OutboxAdminPort;",
1786
+ `Could not find AppPorts in ${config.paths.ports}. Add outboxAdmin: OutboxAdminPort; manually, or restore the generated ports file before running make outbox.`,
1787
+ );
1788
+ }
1712
1789
  if (!typeHasTopLevelProperty(next, "AppTransactionPorts", "outbox")) {
1713
1790
  next = insertTypeProperty(
1714
1791
  next,
@@ -1730,7 +1807,8 @@ async function updateOutboxInfrastructurePorts(
1730
1807
  ): Promise<boolean> {
1731
1808
  const filePath = path.join(targetDir, config.paths.infrastructurePorts);
1732
1809
  const original = await readFile(filePath, "utf8");
1733
- const next = appendDeferredPortKey(original, "outbox");
1810
+ let next = appendDeferredPortKey(original, "outbox");
1811
+ next = appendDeferredPortKey(next, "outboxAdmin");
1734
1812
 
1735
1813
  if (next === original) return false;
1736
1814
  if (!options.dryRun) await writeFile(filePath, next);
@@ -1748,13 +1826,20 @@ async function updateOutboxDatabaseProvider(
1748
1826
 
1749
1827
  const database = await detectResourceDatabase(targetDir, config);
1750
1828
  const factoryName = drizzleOutboxPortFactoryName(database);
1829
+ const adminFactoryName = drizzleOutboxAdminPortFactoryName(database);
1751
1830
  const original = await readFile(filePath, "utf8");
1752
1831
  let next = addNamedImport(
1753
1832
  original,
1754
1833
  factoryName,
1755
1834
  `@beignet/provider-db-drizzle/${database}`,
1756
1835
  );
1836
+ next = addNamedImport(
1837
+ next,
1838
+ adminFactoryName,
1839
+ `@beignet/provider-db-drizzle/${database}`,
1840
+ );
1757
1841
  next = appendPickStringLiteralMember(next, "AppPorts", "outbox");
1842
+ next = appendPickStringLiteralMember(next, "AppPorts", "outboxAdmin");
1758
1843
 
1759
1844
  if (!/\bconst\s+outbox\s*=/.test(next)) {
1760
1845
  const beforeOutboxConst = next;
@@ -1769,6 +1854,21 @@ async function updateOutboxDatabaseProvider(
1769
1854
  }
1770
1855
  }
1771
1856
 
1857
+ if (!/\bconst\s+outboxAdmin\s*=/.test(next)) {
1858
+ const beforeOutboxAdminConst = next;
1859
+ next = beforeOutboxAdminConst.replace(
1860
+ new RegExp(
1861
+ `(\\n\\s*const outbox = ${factoryName}\\((dbPort\\.(?:drizzle|db))\\);)`,
1862
+ ),
1863
+ `$1\n\t\tconst outboxAdmin = ${adminFactoryName}($2);`,
1864
+ );
1865
+ if (next === beforeOutboxAdminConst) {
1866
+ throw new Error(
1867
+ `Could not find the outbox port in ${file}. Add const outboxAdmin = ${adminFactoryName}(dbPort.drizzle) manually, or restore the generated database provider before running make outbox.`,
1868
+ );
1869
+ }
1870
+ }
1871
+
1772
1872
  if (!/\boutbox\s*,/.test(next)) {
1773
1873
  const withOutboxPort = next.replace(
1774
1874
  /(\n\s*idempotency,\n)/,
@@ -1782,6 +1882,19 @@ async function updateOutboxDatabaseProvider(
1782
1882
  next = withOutboxPort;
1783
1883
  }
1784
1884
 
1885
+ if (!/\boutboxAdmin\s*,/.test(next)) {
1886
+ const withOutboxAdminPort = next.replace(
1887
+ /(\n\s*outbox,\n)/,
1888
+ `$1\t\t\toutboxAdmin,\n`,
1889
+ );
1890
+ if (withOutboxAdminPort === next) {
1891
+ throw new Error(
1892
+ `Could not find outbox in providedPorts in ${file}. Add outboxAdmin to providedPorts manually, or restore the generated database provider before running make outbox.`,
1893
+ );
1894
+ }
1895
+ next = withOutboxAdminPort;
1896
+ }
1897
+
1785
1898
  if (!new RegExp(`outbox:\\s*${factoryName}\\(tx\\)`).test(next)) {
1786
1899
  const withTransactionOutbox = next.replace(
1787
1900
  /(\n\s*idempotency: createDrizzle[A-Za-z]+IdempotencyPort\(tx\),\n)/,
@@ -1881,6 +1994,12 @@ function drizzleOutboxPortFactoryName(database: DatabaseName): string {
1881
1994
  return "createDrizzleSqliteOutboxPort";
1882
1995
  }
1883
1996
 
1997
+ function drizzleOutboxAdminPortFactoryName(database: DatabaseName): string {
1998
+ if (database === "postgres") return "createDrizzlePostgresOutboxAdminPort";
1999
+ if (database === "mysql") return "createDrizzleMysqlOutboxAdminPort";
2000
+ return "createDrizzleSqliteOutboxAdminPort";
2001
+ }
2002
+
1884
2003
  async function applyOutboxDrainWiring(
1885
2004
  result: MakeResult,
1886
2005
  targetDir: string,
@@ -2514,6 +2633,7 @@ function resourceFiles(
2514
2633
  const infraDir = infrastructureDir(config);
2515
2634
  const featureDir = resourceFeatureDir(names, config);
2516
2635
  const files: GeneratedFile[] = [
2636
+ ...testSupportTemplateFiles,
2517
2637
  {
2518
2638
  path: resourceContractFilePath(names, config),
2519
2639
  content: contractFile(names, config, mode, options),
@@ -2670,6 +2790,7 @@ function testFiles(
2670
2790
  config: ResolvedBeignetConfig,
2671
2791
  ): GeneratedFile[] {
2672
2792
  return [
2793
+ ...testSupportTemplateFiles,
2673
2794
  {
2674
2795
  path: useCaseTestFilePath(names, config),
2675
2796
  content: useCaseTestFile(names, config),
@@ -3470,7 +3591,7 @@ function listUseCaseFile(
3470
3591
 
3471
3592
  return `import "@beignet/core/server-only";
3472
3593
  import { normalizeCursorPage } from "@beignet/core/pagination";
3473
- import { useCase } from "${relativeModule(filePath, config.paths.useCaseBuilder)}";
3594
+ ${options.tenant ? `import { requireTenantScope } from "@beignet/core/tenancy";\n` : ""}import { useCase } from "${relativeModule(filePath, config.paths.useCaseBuilder)}";
3474
3595
  import {
3475
3596
  decode${names.singularPascal}Cursor,
3476
3597
  List${names.pluralPascal}InputSchema,
@@ -3482,7 +3603,7 @@ export const list${names.pluralPascal}UseCase = useCase
3482
3603
  .input(List${names.pluralPascal}InputSchema)
3483
3604
  .output(List${names.pluralPascal}OutputSchema)
3484
3605
  .run(async ({ ctx, input }) => {
3485
- ${options.tenant ? `\t\tconst tenantId = ctx.tenant?.id;\n\t\tif (!tenantId) {\n\t\t\tthrow new Error("Tenant is required to list ${names.pluralKebab}.");\n\t\t}\n\n` : ""} const page = normalizeCursorPage(input, {
3606
+ ${options.tenant ? `\t\tconst scope = requireTenantScope(ctx);\n\n` : ""} const page = normalizeCursorPage(input, {
3486
3607
  defaultLimit: 20,
3487
3608
  maxLimit: 100,
3488
3609
  });
@@ -3493,7 +3614,7 @@ ${options.tenant ? `\t\tconst tenantId = ctx.tenant?.id;\n\t\tif (!tenantId) {\n
3493
3614
  name: input.name,
3494
3615
  sortBy: input.sortBy,
3495
3616
  sortDirection: input.sortDirection,
3496
- ${options.tenant ? `\t\t\ttenantId,\n` : ""} });
3617
+ }${options.tenant ? ", scope" : ""});
3497
3618
  });
3498
3619
  `;
3499
3620
  }
@@ -3509,7 +3630,7 @@ function createUseCaseFile(
3509
3630
  );
3510
3631
 
3511
3632
  return `import "@beignet/core/server-only";
3512
- import { useCase } from "${relativeModule(filePath, config.paths.useCaseBuilder)}";
3633
+ ${options.tenant ? `import { requireTenantScope } from "@beignet/core/tenancy";\n` : ""}import { useCase } from "${relativeModule(filePath, config.paths.useCaseBuilder)}";
3513
3634
  import {
3514
3635
  Create${names.singularPascal}InputSchema,
3515
3636
  ${names.singularPascal}Schema,
@@ -3521,9 +3642,7 @@ export const create${names.singularPascal}UseCase = useCase
3521
3642
  .input(Create${names.singularPascal}InputSchema)
3522
3643
  .output(${names.singularPascal}Schema)
3523
3644
  .run(async ({ ctx, input }) => {
3524
- ${options.tenant ? `\t\tconst tenantId = ctx.tenant?.id;\n\t\tif (!tenantId) {\n\t\t\tthrow new Error("Tenant is required to create ${names.singularKebab}.");\n\t\t}\n\n` : ""}${options.auth ? `\t\tawait ctx.gate.authorize("${names.pluralCamel}.create");\n\n` : ""} const ${names.singularCamel} = await ctx.ports.${names.pluralCamel}.create({
3525
- ...input,
3526
- ${options.tenant ? `\t\t\ttenantId,\n` : ""} });
3645
+ ${options.tenant ? `\t\tconst scope = requireTenantScope(ctx);\n\n` : ""}${options.auth ? `\t\tawait ctx.gate.authorize("${names.pluralCamel}.create");\n\n` : ""} const ${names.singularCamel} = await ctx.ports.${names.pluralCamel}.create(input${options.tenant ? ", scope" : ""});
3527
3646
  ${options.events ? `\n\t\tawait ctx.ports.eventBus.publish(${names.singularPascal}Created, {\n\t\t\tid: ${names.singularCamel}.id,\n\t\t});\n` : ""}
3528
3647
  return ${names.singularCamel};
3529
3648
  });
@@ -3541,7 +3660,7 @@ function getUseCaseFile(
3541
3660
  );
3542
3661
 
3543
3662
  return `import "@beignet/core/server-only";
3544
- import { appError } from "${relativeModule(filePath, resourceSharedErrorsPath(config))}";
3663
+ ${options.tenant ? `import { requireTenantScope } from "@beignet/core/tenancy";\n` : ""}import { appError } from "${relativeModule(filePath, resourceSharedErrorsPath(config))}";
3545
3664
  import { useCase } from "${relativeModule(filePath, config.paths.useCaseBuilder)}";
3546
3665
  import {
3547
3666
  ${names.singularPascal}IdInputSchema,
@@ -3553,7 +3672,7 @@ export const get${names.singularPascal}UseCase = useCase
3553
3672
  .input(${names.singularPascal}IdInputSchema)
3554
3673
  .output(${names.singularPascal}Schema)
3555
3674
  .run(async ({ ctx, input }) => {
3556
- ${options.tenant ? `\t\tconst tenantId = ctx.tenant?.id;\n\t\tif (!tenantId) {\n\t\t\tthrow new Error("Tenant is required to get ${names.singularKebab}.");\n\t\t}\n\n` : ""} const ${names.singularCamel} = await ctx.ports.${names.pluralCamel}.findById(input.id${options.tenant ? ", { tenantId }" : ""});
3675
+ ${options.tenant ? `\t\tconst scope = requireTenantScope(ctx);\n\n` : ""} const ${names.singularCamel} = await ctx.ports.${names.pluralCamel}.findById(input.id${options.tenant ? ", scope" : ""});
3557
3676
  if (!${names.singularCamel}) {
3558
3677
  throw appError("${names.singularPascal}NotFound", {
3559
3678
  details: { id: input.id },
@@ -3576,7 +3695,7 @@ function updateUseCaseFile(
3576
3695
  );
3577
3696
 
3578
3697
  return `import "@beignet/core/server-only";
3579
- import { appError } from "${relativeModule(filePath, resourceSharedErrorsPath(config))}";
3698
+ ${options.tenant ? `import { requireTenantScope } from "@beignet/core/tenancy";\n` : ""}import { appError } from "${relativeModule(filePath, resourceSharedErrorsPath(config))}";
3580
3699
  import { useCase } from "${relativeModule(filePath, config.paths.useCaseBuilder)}";
3581
3700
  ${options.events ? `import { ${names.singularPascal}Updated } from "../domain/events";\n` : ""}import {
3582
3701
  Update${names.singularPascal}InputSchema,
@@ -3588,7 +3707,7 @@ export const update${names.singularPascal}UseCase = useCase
3588
3707
  .input(Update${names.singularPascal}InputSchema)
3589
3708
  .output(${names.singularPascal}Schema)
3590
3709
  .run(async ({ ctx, input }) => {
3591
- ${options.tenant ? `\t\tconst tenantId = ctx.tenant?.id;\n\t\tif (!tenantId) {\n\t\t\tthrow new Error("Tenant is required to update ${names.singularKebab}.");\n\t\t}\n\n` : ""} const existing = await ctx.ports.${names.pluralCamel}.findById(input.id${options.tenant ? ", { tenantId }" : ""});
3710
+ ${options.tenant ? `\t\tconst scope = requireTenantScope(ctx);\n\n` : ""} const existing = await ctx.ports.${names.pluralCamel}.findById(input.id${options.tenant ? ", scope" : ""});
3592
3711
  if (!existing) {
3593
3712
  throw appError("${names.singularPascal}NotFound", {
3594
3713
  details: { id: input.id },
@@ -3602,7 +3721,7 @@ ${options.auth ? `\t\tawait ctx.gate.authorize("${names.pluralCamel}.update", ex
3602
3721
 
3603
3722
  const ${names.singularCamel} = await ctx.ports.${names.pluralCamel}.update({
3604
3723
  ...input,
3605
- ${options.tenant ? `\t\t\ttenantId,\n` : ""} });
3724
+ }${options.tenant ? ", scope" : ""});
3606
3725
  if (!${names.singularCamel}) {
3607
3726
  throw appError("${names.singularPascal}Conflict", {
3608
3727
  details: { id: input.id, expectedVersion: existing.version },
@@ -3626,7 +3745,7 @@ function deleteUseCaseFile(
3626
3745
 
3627
3746
  return `import "@beignet/core/server-only";
3628
3747
  import { z } from "zod";
3629
- import { appError } from "${relativeModule(filePath, resourceSharedErrorsPath(config))}";
3748
+ ${options.tenant ? `import { requireTenantScope } from "@beignet/core/tenancy";\n` : ""}import { appError } from "${relativeModule(filePath, resourceSharedErrorsPath(config))}";
3630
3749
  import { useCase } from "${relativeModule(filePath, config.paths.useCaseBuilder)}";
3631
3750
  ${options.events ? `import { ${names.singularPascal}Deleted } from "../domain/events";\n` : ""}import { ${names.singularPascal}IdInputSchema } from "../schemas";
3632
3751
 
@@ -3635,7 +3754,7 @@ export const delete${names.singularPascal}UseCase = useCase
3635
3754
  .input(${names.singularPascal}IdInputSchema)
3636
3755
  .output(z.void())
3637
3756
  .run(async ({ ctx, input }) => {
3638
- ${options.tenant ? `\t\tconst tenantId = ctx.tenant?.id;\n\t\tif (!tenantId) {\n\t\t\tthrow new Error("Tenant is required to delete ${names.singularKebab}.");\n\t\t}\n\n` : ""}${options.auth ? `\t\tconst existing = await ctx.ports.${names.pluralCamel}.findById(input.id${options.tenant ? ", { tenantId }" : ""});\n\t\tif (!existing) {\n\t\t\tthrow appError("${names.singularPascal}NotFound", {\n\t\t\t\tdetails: { id: input.id },\n\t\t\t});\n\t\t}\n\t\tawait ctx.gate.authorize("${names.pluralCamel}.delete", existing);\n\n` : ""} const deleted = await ctx.ports.${names.pluralCamel}.delete(input.id${options.tenant ? ", { tenantId }" : ""});
3757
+ ${options.tenant ? `\t\tconst scope = requireTenantScope(ctx);\n\n` : ""}${options.auth ? `\t\tconst existing = await ctx.ports.${names.pluralCamel}.findById(input.id${options.tenant ? ", scope" : ""});\n\t\tif (!existing) {\n\t\t\tthrow appError("${names.singularPascal}NotFound", {\n\t\t\t\tdetails: { id: input.id },\n\t\t\t});\n\t\t}\n\t\tawait ctx.gate.authorize("${names.pluralCamel}.delete", existing);\n\n` : ""} const deleted = await ctx.ports.${names.pluralCamel}.delete(input.id${options.tenant ? ", scope" : ""});
3639
3758
  if (!deleted) {
3640
3759
  throw appError("${names.singularPascal}NotFound", {
3641
3760
  details: { id: input.id },
@@ -3675,7 +3794,7 @@ function repositoryPortFile(
3675
3794
  PageResult,
3676
3795
  SortDirection,
3677
3796
  } from "@beignet/core/pagination";
3678
- import type {
3797
+ ${options.tenant ? `import type { TenantScope } from "@beignet/core/tenancy";\n` : ""}import type {
3679
3798
  Create${names.singularPascal}Input,
3680
3799
  ${names.singularPascal}Cursor,
3681
3800
  ${names.singularPascal}SortBy,
@@ -3689,13 +3808,12 @@ export type List${names.pluralPascal}Query = {
3689
3808
  name?: string;
3690
3809
  sortBy: ${names.singularPascal}SortBy;
3691
3810
  sortDirection: SortDirection;
3692
- ${options.tenant ? `\ttenantId: string;\n` : ""}};
3693
- ${options.tenant ? `export type ${names.singularPascal}TenantFilter = { tenantId: string };\nexport type Create${names.singularPascal}RepositoryInput = Create${names.singularPascal}Input & ${names.singularPascal}TenantFilter;\n${mode === "resource" ? `export type Update${names.singularPascal}RepositoryInput = Update${names.singularPascal}Input & ${names.singularPascal}TenantFilter;\n` : ""}` : ""}
3811
+ };
3694
3812
 
3695
3813
  export interface ${names.singularPascal}Repository {
3696
- list(query: List${names.pluralPascal}Query): Promise<List${names.pluralPascal}Result>;
3697
- create(input: ${options.tenant ? `Create${names.singularPascal}RepositoryInput` : `Create${names.singularPascal}Input`}): Promise<${names.singularPascal}>;
3698
- ${mode === "resource" ? ` findById(id: string${options.tenant ? `, filter: ${names.singularPascal}TenantFilter` : ""}): Promise<${names.singularPascal} | null>;\n update(input: ${options.tenant ? `Update${names.singularPascal}RepositoryInput` : `Update${names.singularPascal}Input`}): Promise<${names.singularPascal} | null>;\n delete(id: string${options.tenant ? `, filter: ${names.singularPascal}TenantFilter` : ""}): Promise<boolean>;\n` : ""}}
3814
+ list(query: List${names.pluralPascal}Query${options.tenant ? ", scope: TenantScope" : ""}): Promise<List${names.pluralPascal}Result>;
3815
+ create(input: Create${names.singularPascal}Input${options.tenant ? ", scope: TenantScope" : ""}): Promise<${names.singularPascal}>;
3816
+ ${mode === "resource" ? ` findById(id: string${options.tenant ? ", scope: TenantScope" : ""}): Promise<${names.singularPascal} | null>;\n update(input: Update${names.singularPascal}Input${options.tenant ? ", scope: TenantScope" : ""}): Promise<${names.singularPascal} | null>;\n delete(id: string${options.tenant ? ", scope: TenantScope" : ""}): Promise<boolean>;\n` : ""}}
3699
3817
  `;
3700
3818
  }
3701
3819
 
@@ -3729,14 +3847,14 @@ function inMemoryRepositoryFile(
3729
3847
  ? " || existing.deletedAt !== null"
3730
3848
  : "";
3731
3849
  const deleteImplementation = options.softDelete
3732
- ? `${options.tenant ? `\t\t\tconst existing = ${names.pluralCamel}.get(id);\n\t\t\tif (!existing || existing.tenantId !== filter.tenantId || existing.deletedAt !== null) return false;\n` : `\t\t\tconst existing = ${names.pluralCamel}.get(id);\n\t\t\tif (!existing || existing.deletedAt !== null) return false;\n`} const now = new Date().toISOString();
3850
+ ? `${options.tenant ? `\t\t\tconst existing = ${names.pluralCamel}.get(id);\n\t\t\tif (!existing || existing.tenantId !== tenantId || existing.deletedAt !== null) return false;\n` : `\t\t\tconst existing = ${names.pluralCamel}.get(id);\n\t\t\tif (!existing || existing.deletedAt !== null) return false;\n`} const now = new Date().toISOString();
3733
3851
  ${names.pluralCamel}.set(id, { ...existing, deletedAt: now, updatedAt: now });
3734
3852
  return true;`
3735
- : `${options.tenant ? `\t\t\tconst existing = ${names.pluralCamel}.get(id);\n\t\t\tif (existing?.tenantId !== filter.tenantId) return false;\n` : ""} return ${names.pluralCamel}.delete(id);`;
3853
+ : `${options.tenant ? `\t\t\tconst existing = ${names.pluralCamel}.get(id);\n\t\t\tif (existing?.tenantId !== tenantId) return false;\n` : ""} return ${names.pluralCamel}.delete(id);`;
3736
3854
 
3737
3855
  return `import "@beignet/core/server-only";
3738
3856
  import { cursorPageResult } from "@beignet/core/pagination";
3739
- import type { ${names.singularPascal}Repository } from "${aliasModule(repositoryPortPath)}";
3857
+ ${options.tenant ? `import { tenantScopeId } from "@beignet/core/tenancy";\n` : ""}import type { ${names.singularPascal}Repository } from "${aliasModule(repositoryPortPath)}";
3740
3858
  import { encode${names.singularPascal}Cursor } from "${aliasModule(resourceSchemaFilePath(names, config))}";
3741
3859
  import type {
3742
3860
  Create${names.singularPascal}Input,
@@ -3804,10 +3922,10 @@ export function createInMemory${names.singularPascal}Repository(
3804
3922
  );
3805
3923
 
3806
3924
  return {
3807
- async list(query) {
3925
+ async list(query${options.tenant ? ", scope" : ""}) {
3808
3926
  const name = query.name?.toLocaleLowerCase();
3809
- const all${names.pluralPascal} = Array.from(${names.pluralCamel}.values())
3810
- ${activeFilter}${options.tenant ? `\t\t\t\t.filter((${names.singularCamel}) => ${names.singularCamel}.tenantId === query.tenantId)\n` : ""} .filter((${names.singularCamel}) => !name || ${names.singularCamel}.name.toLocaleLowerCase().includes(name))
3927
+ ${options.tenant ? `\t\t\tconst tenantId = tenantScopeId(scope);\n` : ""} const all${names.pluralPascal} = Array.from(${names.pluralCamel}.values())
3928
+ ${activeFilter}${options.tenant ? `\t\t\t\t.filter((${names.singularCamel}) => ${names.singularCamel}.tenantId === tenantId)\n` : ""} .filter((${names.singularCamel}) => !name || ${names.singularCamel}.name.toLocaleLowerCase().includes(name))
3811
3929
  .sort((left, right) => compare${names.pluralPascal}(left, right, query))
3812
3930
  .filter((${names.singularCamel}) => isAfter${names.singularPascal}Cursor(${names.singularCamel}, query));
3813
3931
  const pageItems = all${names.pluralPascal}.slice(0, query.page.limit);
@@ -3822,11 +3940,11 @@ ${activeFilter}${options.tenant ? `\t\t\t\t.filter((${names.singularCamel}) => $
3822
3940
  nextCursor,
3823
3941
  );
3824
3942
  },
3825
- async create(input) {
3943
+ async create(input${options.tenant ? ", scope" : ""}) {
3826
3944
  const now = new Date().toISOString();
3827
- const ${names.singularCamel}: ${names.singularPascal} = {
3945
+ ${options.tenant ? `\t\t\tconst tenantId = tenantScopeId(scope);\n` : ""} const ${names.singularCamel}: ${names.singularPascal} = {
3828
3946
  id: crypto.randomUUID(),
3829
- ${options.tenant ? `\t\t\t\ttenantId: input.tenantId,\n` : ""} name: input.name,
3947
+ ${options.tenant ? `\t\t\t\ttenantId,\n` : ""} name: input.name,
3830
3948
  version: 1,
3831
3949
  createdAt: now,
3832
3950
  updatedAt: now,
@@ -3836,7 +3954,7 @@ ${options.tenant ? `\t\t\t\ttenantId: input.tenantId,\n` : ""} name: input.na
3836
3954
  ${newDeletedAtField} });
3837
3955
  return ${names.singularCamel};
3838
3956
  },
3839
- ${mode === "resource" ? ` async findById(id: string${options.tenant ? ", filter" : ""}) {\n const ${names.singularCamel} = ${names.pluralCamel}.get(id) ?? null;\n${options.tenant ? `\t\t\tif (${names.singularCamel}?.tenantId !== filter.tenantId) return null;\n` : ""}${findDeletedGuard} return ${names.singularCamel} ? to${names.singularPascal}(${names.singularCamel}) : null;\n },\n async update(input) {\n const existing = ${names.pluralCamel}.get(input.id);\n if (!existing${options.tenant ? " || existing.tenantId !== input.tenantId" : ""}${updateDeletedGuard} || existing.version !== input.version) return null;\n\n const next: ${mapValueType} = {\n ...existing,\n name: input.name,\n version: existing.version + 1,\n updatedAt: new Date().toISOString(),\n };\n ${names.pluralCamel}.set(input.id, next);\n return to${names.singularPascal}(next);\n },\n async delete(id: string${options.tenant ? ", filter" : ""}) {\n${deleteImplementation}\n },\n` : ""}
3957
+ ${mode === "resource" ? ` async findById(id: string${options.tenant ? ", scope" : ""}) {\n${options.tenant ? `\t\t\tconst tenantId = tenantScopeId(scope);\n` : ""} const ${names.singularCamel} = ${names.pluralCamel}.get(id) ?? null;\n${options.tenant ? `\t\t\tif (${names.singularCamel}?.tenantId !== tenantId) return null;\n` : ""}${findDeletedGuard} return ${names.singularCamel} ? to${names.singularPascal}(${names.singularCamel}) : null;\n },\n async update(input${options.tenant ? ", scope" : ""}) {\n${options.tenant ? `\t\t\tconst tenantId = tenantScopeId(scope);\n` : ""} const existing = ${names.pluralCamel}.get(input.id);\n if (!existing${options.tenant ? " || existing.tenantId !== tenantId" : ""}${updateDeletedGuard} || existing.version !== input.version) return null;\n\n const next: ${mapValueType} = {\n ...existing,\n name: input.name,\n version: existing.version + 1,\n updatedAt: new Date().toISOString(),\n };\n ${names.pluralCamel}.set(input.id, next);\n return to${names.singularPascal}(next);\n },\n async delete(id: string${options.tenant ? ", scope" : ""}) {\n${options.tenant ? `\t\t\tconst tenantId = tenantScopeId(scope);\n` : ""}${deleteImplementation}\n },\n` : ""}
3840
3958
  };
3841
3959
  }
3842
3960
  `;
@@ -3960,20 +4078,20 @@ function drizzleRepositoryFile(
3960
4078
  const findWhere = drizzleResourceWhere(names, options, [
3961
4079
  `eq(schema.${names.pluralCamel}.id, id)`,
3962
4080
  ...(options.tenant
3963
- ? [`eq(schema.${names.pluralCamel}.tenantId, filter.tenantId)`]
4081
+ ? [`eq(schema.${names.pluralCamel}.tenantId, tenantScopeId(scope))`]
3964
4082
  : []),
3965
4083
  ]);
3966
4084
  const updateWhere = drizzleResourceWhere(names, options, [
3967
4085
  `eq(schema.${names.pluralCamel}.id, input.id)`,
3968
4086
  `eq(schema.${names.pluralCamel}.version, input.version)`,
3969
4087
  ...(options.tenant
3970
- ? [`eq(schema.${names.pluralCamel}.tenantId, input.tenantId)`]
4088
+ ? [`eq(schema.${names.pluralCamel}.tenantId, tenantScopeId(scope))`]
3971
4089
  : []),
3972
4090
  ]);
3973
4091
  const deleteWhere = drizzleResourceWhere(names, options, [
3974
4092
  `eq(schema.${names.pluralCamel}.id, id)`,
3975
4093
  ...(options.tenant
3976
- ? [`eq(schema.${names.pluralCamel}.tenantId, filter.tenantId)`]
4094
+ ? [`eq(schema.${names.pluralCamel}.tenantId, tenantScopeId(scope))`]
3977
4095
  : []),
3978
4096
  ]);
3979
4097
  const drizzleImports = [
@@ -3991,7 +4109,7 @@ function drizzleRepositoryFile(
3991
4109
  // After a version-guarded update succeeds, re-select by identity only —
3992
4110
  // matching what `.returning()` yields on the dialects that support it.
3993
4111
  const updateReselectWhere = options.tenant
3994
- ? `and(eq(schema.${names.pluralCamel}.id, input.id), eq(schema.${names.pluralCamel}.tenantId, input.tenantId))`
4112
+ ? `and(eq(schema.${names.pluralCamel}.id, input.id), eq(schema.${names.pluralCamel}.tenantId, tenantScopeId(scope)))`
3995
4113
  : `eq(schema.${names.pluralCamel}.id, input.id)`;
3996
4114
  // drizzle-orm/mysql2 has no `.returning(...)`; mutations resolve to a
3997
4115
  // `[ResultSetHeader, FieldPacket[]]` tuple typed as `unknown` through the
@@ -4013,13 +4131,13 @@ function affectedRows(result: unknown): number {
4013
4131
  `
4014
4132
  : "";
4015
4133
  const createMethod = dialect.supportsReturning
4016
- ? ` async create(input) {
4134
+ ? ` async create(input${options.tenant ? ", scope" : ""}) {
4017
4135
  const now = new Date().toISOString();
4018
4136
  const [row] = await db
4019
4137
  .insert(schema.${names.pluralCamel})
4020
4138
  .values({
4021
4139
  id: crypto.randomUUID(),
4022
- ${options.tenant ? `\t\t\t\t\ttenantId: input.tenantId,\n` : ""} name: input.name,
4140
+ ${options.tenant ? `\t\t\t\t\ttenantId: tenantScopeId(scope),\n` : ""} name: input.name,
4023
4141
  version: 1,
4024
4142
  createdAt: now,
4025
4143
  updatedAt: now,
@@ -4033,11 +4151,11 @@ ${options.tenant ? `\t\t\t\t\ttenantId: input.tenantId,\n` : ""} name: input
4033
4151
  return to${names.singularPascal}(row);
4034
4152
  },
4035
4153
  `
4036
- : ` async create(input) {
4154
+ : ` async create(input${options.tenant ? ", scope" : ""}) {
4037
4155
  const now = new Date().toISOString();
4038
4156
  const ${names.singularCamel}: ${names.singularPascal} = {
4039
4157
  id: crypto.randomUUID(),
4040
- ${options.tenant ? `\t\t\t\ttenantId: input.tenantId,\n` : ""} name: input.name,
4158
+ ${options.tenant ? `\t\t\t\ttenantId: tenantScopeId(scope),\n` : ""} name: input.name,
4041
4159
  version: 1,
4042
4160
  createdAt: now,
4043
4161
  updatedAt: now,
@@ -4051,7 +4169,7 @@ ${options.tenant ? `\t\t\t\ttenantId: input.tenantId,\n` : ""} name: input.na
4051
4169
  mode !== "resource"
4052
4170
  ? ""
4053
4171
  : dialect.supportsReturning
4054
- ? ` async findById(id: string${options.tenant ? ", filter" : ""}) {
4172
+ ? ` async findById(id: string${options.tenant ? ", scope" : ""}) {
4055
4173
  const [row] = await db
4056
4174
  .select()
4057
4175
  .from(schema.${names.pluralCamel})
@@ -4060,7 +4178,7 @@ ${options.tenant ? `\t\t\t\ttenantId: input.tenantId,\n` : ""} name: input.na
4060
4178
 
4061
4179
  return row ? to${names.singularPascal}(row) : null;
4062
4180
  },
4063
- async update(input) {
4181
+ async update(input${options.tenant ? ", scope" : ""}) {
4064
4182
  const [row] = await db
4065
4183
  .update(schema.${names.pluralCamel})
4066
4184
  .set({
@@ -4073,12 +4191,12 @@ ${options.tenant ? `\t\t\t\ttenantId: input.tenantId,\n` : ""} name: input.na
4073
4191
 
4074
4192
  return row ? to${names.singularPascal}(row) : null;
4075
4193
  },
4076
- async delete(id: string${options.tenant ? ", filter" : ""}) {
4194
+ async delete(id: string${options.tenant ? ", scope" : ""}) {
4077
4195
  ${options.softDelete ? `\t\t\tconst now = new Date().toISOString();\n\t\t\tconst rows = await db\n\t\t\t\t.update(schema.${names.pluralCamel})\n\t\t\t\t.set({ deletedAt: now, updatedAt: now })\n\t\t\t\t.where(${deleteWhere})\n\t\t\t\t.returning({ id: schema.${names.pluralCamel}.id });\n` : `\t\t\tconst rows = await db\n\t\t\t\t.delete(schema.${names.pluralCamel})\n\t\t\t\t.where(${deleteWhere})\n\t\t\t\t.returning({ id: schema.${names.pluralCamel}.id });\n`}
4078
4196
  return rows.length > 0;
4079
4197
  },
4080
4198
  `
4081
- : ` async findById(id: string${options.tenant ? ", filter" : ""}) {
4199
+ : ` async findById(id: string${options.tenant ? ", scope" : ""}) {
4082
4200
  const [row] = await db
4083
4201
  .select()
4084
4202
  .from(schema.${names.pluralCamel})
@@ -4087,7 +4205,7 @@ ${options.softDelete ? `\t\t\tconst now = new Date().toISOString();\n\t\t\tconst
4087
4205
 
4088
4206
  return row ? to${names.singularPascal}(row) : null;
4089
4207
  },
4090
- async update(input) {
4208
+ async update(input${options.tenant ? ", scope" : ""}) {
4091
4209
  const result = await db
4092
4210
  .update(schema.${names.pluralCamel})
4093
4211
  .set({
@@ -4107,7 +4225,7 @@ ${options.softDelete ? `\t\t\tconst now = new Date().toISOString();\n\t\t\tconst
4107
4225
 
4108
4226
  return row ? to${names.singularPascal}(row) : null;
4109
4227
  },
4110
- async delete(id: string${options.tenant ? ", filter" : ""}) {
4228
+ async delete(id: string${options.tenant ? ", scope" : ""}) {
4111
4229
  ${options.softDelete ? `\t\t\tconst now = new Date().toISOString();\n\t\t\tconst result = await db\n\t\t\t\t.update(schema.${names.pluralCamel})\n\t\t\t\t.set({ deletedAt: now, updatedAt: now })\n\t\t\t\t.where(${deleteWhere});\n` : `\t\t\tconst result = await db\n\t\t\t\t.delete(schema.${names.pluralCamel})\n\t\t\t\t.where(${deleteWhere});\n`}
4112
4230
  return affectedRows(result) > 0;
4113
4231
  },
@@ -4115,7 +4233,7 @@ ${options.softDelete ? `\t\t\tconst now = new Date().toISOString();\n\t\t\tconst
4115
4233
 
4116
4234
  return `import "@beignet/core/server-only";
4117
4235
  import { cursorPageResult } from "@beignet/core/pagination";
4118
- import type { ${dialect.dbTypeName} } from "@beignet/provider-db-drizzle/${dialect.subpath}";
4236
+ ${options.tenant ? `import { tenantScopeId } from "@beignet/core/tenancy";\n` : ""}import type { ${dialect.dbTypeName} } from "@beignet/provider-db-drizzle/${dialect.subpath}";
4119
4237
  import { ${drizzleImports.join(", ")} } from "drizzle-orm";
4120
4238
  import type { ${names.singularPascal}Repository } from "${aliasModule(repositoryPortPath)}";
4121
4239
  import { encode${names.singularPascal}Cursor } from "${aliasModule(resourceSchemaFilePath(names, config))}";
@@ -4162,9 +4280,9 @@ function ${names.singularCamel}CursorFilter(
4162
4280
 
4163
4281
  function ${names.singularCamel}ListWhere(
4164
4282
  query: List${names.pluralPascal}Query,
4165
- ): SQL<unknown> | undefined {
4283
+ ${options.tenant ? `\tscope: Parameters<${names.singularPascal}Repository["list"]>[1],\n` : ""}): SQL<unknown> | undefined {
4166
4284
  const filters: SQL<unknown>[] = [
4167
- ${options.tenant ? `\t\teq(schema.${names.pluralCamel}.tenantId, query.tenantId),\n` : ""}${options.softDelete ? `\t\tisNull(schema.${names.pluralCamel}.deletedAt),\n` : ""} ];
4285
+ ${options.tenant ? `\t\teq(schema.${names.pluralCamel}.tenantId, tenantScopeId(scope)),\n` : ""}${options.softDelete ? `\t\tisNull(schema.${names.pluralCamel}.deletedAt),\n` : ""} ];
4168
4286
  const cursor = ${names.singularCamel}CursorFilter(query);
4169
4287
 
4170
4288
  if (query.name) {
@@ -4198,8 +4316,8 @@ export function createDrizzle${names.singularPascal}Repository(
4198
4316
  db: ${dialect.dbTypeName}<typeof schema>,
4199
4317
  ): ${names.singularPascal}Repository {
4200
4318
  return {
4201
- async list(query) {
4202
- const where = ${names.singularCamel}ListWhere(query);
4319
+ async list(query${options.tenant ? ", scope" : ""}) {
4320
+ const where = ${names.singularCamel}ListWhere(query${options.tenant ? ", scope" : ""});
4203
4321
  const rows = await db
4204
4322
  .select()
4205
4323
  .from(schema.${names.pluralCamel})
@@ -4379,11 +4497,11 @@ function useCaseTestFile(
4379
4497
  ): string {
4380
4498
  const filePath = useCaseTestFilePath(names, config);
4381
4499
 
4382
- return `import { describe, expect, it } from "bun:test";
4500
+ return `import { describe, expect, it } from "@/lib/beignet-test";
4383
4501
  import { createUseCaseTester } from "@beignet/core/application";
4384
4502
  import { createInMemoryDevtools } from "@beignet/devtools";
4385
4503
  import { createTestContextFactory, createTestPorts } from "@beignet/core/testing";
4386
- import { createTestAnonymousActor } from "@beignet/core/ports/testing";
4504
+ import { createTestAnonymousActor } from "@beignet/core/testing";
4387
4505
  import type { AppContext } from "${aliasModule(config.paths.appContext)}";
4388
4506
  import { appPorts } from "${aliasModule(config.paths.infrastructurePorts)}";
4389
4507
  import { ${names.exportName} } from "${relativeModule(filePath, useCaseFilePath(names, config))}";
@@ -4551,8 +4669,8 @@ function resourcePolicyTestFile(
4551
4669
  names: ResourceNames,
4552
4670
  options: ResourceGenerationOptions,
4553
4671
  ): string {
4554
- return `import { describe, expect, it } from "bun:test";
4555
- import { createPolicyTester } from "@beignet/core/ports/testing";
4672
+ return `import { describe, expect, it } from "@/lib/beignet-test";
4673
+ import { createPolicyTester } from "@beignet/core/testing";
4556
4674
  import { ${names.singularCamel}Policy } from "../policy";
4557
4675
  import type { ${names.singularPascal} } from "../schemas";
4558
4676
 
@@ -5131,7 +5249,7 @@ function routeGroupFile(
5131
5249
  const useCasesPath = resourceUseCaseIndexPath(names, config);
5132
5250
 
5133
5251
  return `import "@beignet/core/server-only";
5134
- import { defineRouteGroup } from "@beignet/next";
5252
+ import { defineRouteGroup } from "@beignet/core/server";
5135
5253
  import type { AppContext } from "${relativeModule(routeFilePath, config.paths.appContext)}";
5136
5254
  import {
5137
5255
  create${names.singularPascal},
@@ -5169,13 +5287,13 @@ function testFile(
5169
5287
  );
5170
5288
  const requestTarget = "app";
5171
5289
 
5172
- return `import { describe, expect, it } from "bun:test";
5290
+ return `import { describe, expect, it } from "@/lib/beignet-test";
5173
5291
  import { createUseCaseTester } from "@beignet/core/application";
5174
- ${mode === "resource" ? `import { isAppError } from "@beignet/core/errors";\n` : ""}import { defineRoutes } from "@beignet/web";
5292
+ ${mode === "resource" ? `import { isAppError } from "@beignet/core/errors";\n` : ""}import { defineRoutes } from "@beignet/core/server";
5175
5293
  import { createTestApp } from "@beignet/web/testing";
5176
5294
  import { createInMemoryDevtools } from "@beignet/devtools";
5177
5295
  import { createTestContextFactory, createTestPorts } from "@beignet/core/testing";
5178
- import { ${options.auth ? "createTestUserActor" : "createTestAnonymousActor"}${options.tenant ? ", createTestTenant" : ""} } from "@beignet/core/ports/testing";
5296
+ import { ${options.auth ? "createTestUserActor" : "createTestAnonymousActor"}${options.tenant ? ", createTestTenant" : ""} } from "@beignet/core/testing";
5179
5297
  import type { AppContext } from "${aliasModule(config.paths.appContext)}";
5180
5298
  import { appPorts } from "${aliasModule(config.paths.infrastructurePorts)}";
5181
5299
  import { appContext } from "${aliasModule(serverContextPath)}";