create-absolutejs 0.17.3 → 0.19.0

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 (100) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +37 -4
  3. package/changelog.json +24 -0
  4. package/dist/commands/migrateDatabase.d.ts +6 -0
  5. package/dist/commands/migrateDatabase.js +53 -0
  6. package/dist/data.d.ts +1 -1
  7. package/dist/data.js +1 -1
  8. package/dist/generators/angular/generateAngularPage.d.ts +5 -6
  9. package/dist/generators/angular/generateAngularPage.js +16 -33
  10. package/dist/generators/angular/scaffoldAngular.d.ts +1 -1
  11. package/dist/generators/angular/scaffoldAngular.js +8 -9
  12. package/dist/generators/configurations/generateDrizzleConfig.d.ts +5 -3
  13. package/dist/generators/configurations/generateDrizzleConfig.js +40 -14
  14. package/dist/generators/configurations/generateEnv.js +6 -0
  15. package/dist/generators/configurations/generateEslintConfig.js +4 -2
  16. package/dist/generators/configurations/generatePackageJson.js +33 -6
  17. package/dist/generators/db/drizzleTargets.d.ts +5 -0
  18. package/dist/generators/db/drizzleTargets.js +27 -0
  19. package/dist/generators/db/generateDatabaseTypes.js +21 -24
  20. package/dist/generators/db/generateDockerContainer.d.ts +5 -0
  21. package/dist/generators/db/generateDockerContainer.js +22 -4
  22. package/dist/generators/db/generateDrizzleSchema.js +65 -77
  23. package/dist/generators/db/generateHandlers.js +3 -2
  24. package/dist/generators/db/generateRelationalSchema.d.ts +1 -1
  25. package/dist/generators/db/generateRelationalSchema.js +1 -1
  26. package/dist/generators/db/handlerTemplates.d.ts +11 -5
  27. package/dist/generators/db/handlerTemplates.js +14 -12
  28. package/dist/generators/db/scaffoldDatabase.d.ts +2 -1
  29. package/dist/generators/db/scaffoldDatabase.js +25 -10
  30. package/dist/generators/db/scaffoldDocker.d.ts +3 -1
  31. package/dist/generators/db/scaffoldDocker.js +11 -5
  32. package/dist/generators/htmx/scaffoldHTMX.js +1 -0
  33. package/dist/generators/project/generateAbsoluteAuthConfig.d.ts +1 -1
  34. package/dist/generators/project/generateAbsoluteAuthConfig.js +11 -10
  35. package/dist/generators/project/generateDBBlock.js +16 -7
  36. package/dist/generators/project/generateIdentity.d.ts +1 -0
  37. package/dist/generators/project/generateIdentity.js +15 -0
  38. package/dist/generators/project/generateImportsBlock.js +15 -15
  39. package/dist/generators/project/generateRoutesBlock.d.ts +2 -1
  40. package/dist/generators/project/generateRoutesBlock.js +8 -13
  41. package/dist/generators/project/generateServer.js +26 -16
  42. package/dist/generators/project/scaffoldAgentic.d.ts +1 -1
  43. package/dist/generators/project/scaffoldAgentic.js +45 -45
  44. package/dist/generators/project/scaffoldBackend.js +4 -9
  45. package/dist/generators/react/scaffoldReact.js +2 -2
  46. package/dist/index.js +2 -1
  47. package/dist/messages.d.ts +2 -1
  48. package/dist/messages.js +2 -1
  49. package/dist/prompt.js +3 -2
  50. package/dist/questions/authOption.js +4 -1
  51. package/dist/questions/databaseEngine.d.ts +1 -1
  52. package/dist/questions/orm.js +2 -5
  53. package/dist/scaffold.d.ts +3 -1
  54. package/dist/scaffold.js +33 -4
  55. package/dist/templates/configurations/eslint.config.example.mjs +81 -41
  56. package/dist/templates/db/migrations/cockroach-count-history/20260926210314_init/migration.sql +5 -0
  57. package/dist/templates/db/migrations/cockroach-count-history/20260926210314_init/snapshot.json +69 -0
  58. package/dist/templates/db/migrations/cockroach-users/20260926210315_init/migration.sql +5 -0
  59. package/dist/templates/db/migrations/cockroach-users/20260926210315_init/snapshot.json +62 -0
  60. package/dist/templates/db/migrations/mssql-count-history/20260926210316_init/migration.sql +6 -0
  61. package/dist/templates/db/migrations/mssql-count-history/20260926210316_init/snapshot.json +64 -0
  62. package/dist/templates/db/migrations/mssql-users/20260926210317_init/migration.sql +6 -0
  63. package/dist/templates/db/migrations/mssql-users/20260926210317_init/snapshot.json +70 -0
  64. package/dist/templates/db/migrations/mysql-count-history/20260926210318_init/migration.sql +5 -0
  65. package/dist/templates/db/migrations/mysql-count-history/20260926210318_init/snapshot.json +61 -0
  66. package/dist/templates/db/migrations/mysql-users/20260926210319_init/migration.sql +5 -0
  67. package/dist/templates/db/migrations/mysql-users/20260926210319_init/snapshot.json +61 -0
  68. package/dist/templates/db/migrations/postgresql-count-history/20260926210320_init/migration.sql +5 -0
  69. package/dist/templates/db/migrations/postgresql-count-history/20260926210320_init/snapshot.json +71 -0
  70. package/dist/templates/db/migrations/postgresql-users/20260926210320_init/migration.sql +5 -0
  71. package/dist/templates/db/migrations/postgresql-users/20260926210320_init/snapshot.json +62 -0
  72. package/dist/templates/db/migrations/singlestore-count-history/20260926210321_init/migration.sql +5 -0
  73. package/dist/templates/db/migrations/singlestore-count-history/20260926210321_init/snapshot.json +61 -0
  74. package/dist/templates/db/migrations/singlestore-users/20260926210322_init/migration.sql +5 -0
  75. package/dist/templates/db/migrations/singlestore-users/20260926210322_init/snapshot.json +61 -0
  76. package/dist/templates/db/migrations/sqlite-count-history/20260926210323_init/migration.sql +5 -0
  77. package/dist/templates/db/migrations/sqlite-count-history/20260926210323_init/snapshot.json +50 -0
  78. package/dist/templates/db/migrations/sqlite-users/20260926210324_init/migration.sql +5 -0
  79. package/dist/templates/db/migrations/sqlite-users/20260926210324_init/snapshot.json +50 -0
  80. package/dist/templates/db/migrations/turso-count-history/20260926210324_init/migration.sql +5 -0
  81. package/dist/templates/db/migrations/turso-count-history/20260926210324_init/snapshot.json +50 -0
  82. package/dist/templates/db/migrations/turso-users/20260926210325_init/migration.sql +5 -0
  83. package/dist/templates/db/migrations/turso-users/20260926210325_init/snapshot.json +50 -0
  84. package/dist/templates/git/gitignore +0 -3
  85. package/dist/templates/htmx/LICENSE +13 -0
  86. package/dist/templates/htmx/htmx.2.0.11.min.js +1 -0
  87. package/dist/typeGuards.js +2 -2
  88. package/dist/utils/abort.d.ts +1 -1
  89. package/dist/utils/abort.js +2 -4
  90. package/dist/utils/getPackageVersion.js +7 -2
  91. package/dist/utils/parseCommandLineOptions.js +17 -34
  92. package/dist/utils/registryChannel.d.ts +2 -0
  93. package/dist/utils/registryChannel.js +20 -0
  94. package/dist/utils/validateDatabaseSelection.d.ts +11 -0
  95. package/dist/utils/validateDatabaseSelection.js +31 -0
  96. package/dist/versions.d.ts +66 -65
  97. package/dist/versions.js +66 -65
  98. package/package.json +27 -22
  99. package/dist/templates/configurations/drizzle.config.ts +0 -13
  100. package/dist/templates/htmx/htmx.2.0.6.min.js +0 -1
@@ -12,15 +12,6 @@ const defaultProviderConfigurations = {
12
12
  searchParams: [['access_type', 'offline']]
13
13
  }
14
14
  };
15
- /* Mirrors the `User` shape the raw-SQL path writes into types/databaseTypes, so
16
- an auth scaffold without a database resolves the same type from the same
17
- module the example page already imports. */
18
- export const generateSessionUserType = () => `export type User = {
19
- auth_sub: string;
20
- created_at: Date;
21
- metadata: Record<string, unknown>;
22
- };
23
- `;
24
15
  export const generateAbsoluteAuthConfig = (absProviders, hasDatabase) => {
25
16
  const providerConfigs = (absProviders ?? [])
26
17
  .map((provider) => {
@@ -81,6 +72,7 @@ import {
81
72
  } from '@absolutejs/auth';
82
73
  import { DatabaseType, User } from '../../types/databaseTypes';
83
74
  import { createUser, getUser } from '../handlers/userHandlers';
75
+ import { parseUserIdentity } from '../../types/userIdentity';
84
76
 
85
77
  export const absoluteAuthConfig = (db: DatabaseType) =>
86
78
  defineAuthConfig<User>({
@@ -144,7 +136,7 @@ ${providerConfigs}
144
136
  try {
145
137
  const newUser = await createUser(db, {
146
138
  auth_sub: authSub,
147
- metadata: userIdentity
139
+ metadata: parseUserIdentity(userIdentity)
148
140
  });
149
141
  return newUser;
150
142
  } catch (error) {
@@ -159,3 +151,12 @@ ${providerConfigs}
159
151
  });
160
152
  `;
161
153
  };
154
+ /* Mirrors the `User` shape the raw-SQL path writes into types/databaseTypes, so
155
+ an auth scaffold without a database resolves the same type from the same
156
+ module the example page already imports. */
157
+ export const generateSessionUserType = () => `export type User = {
158
+ auth_sub: string;
159
+ created_at: Date;
160
+ metadata: Record<string, unknown>;
161
+ };
162
+ `;
@@ -1,4 +1,7 @@
1
1
  import { availableDrizzleDialects } from '../../data';
2
+ /* A Turso database needs its auth token; a local libSQL `file:` URL has none,
3
+ so the token stays optional. */
4
+ const tursoClient = 'createClient({ authToken: env.DATABASE_AUTH_TOKEN, url: getEnv("DATABASE_URL") })';
2
5
  const connectionMap = {
3
6
  cockroachdb: {
4
7
  none: { expr: 'new SQL(getEnv("DATABASE_URL"))' }
@@ -10,7 +13,7 @@ const connectionMap = {
10
13
  none: { expr: 'new SQL(getEnv("DATABASE_URL"))' }
11
14
  },
12
15
  mongodb: {
13
- none: { expr: 'new MongoClient(getEnv("DATABASE_URL"))' }
16
+ none: { expr: 'new MongoClient(getEnv("DATABASE_URL")).db()' }
14
17
  },
15
18
  mssql: {
16
19
  none: { expr: 'await connect(getEnv("DATABASE_URL"))' }
@@ -36,13 +39,13 @@ const connectionMap = {
36
39
  },
37
40
  sqlite: {
38
41
  none: { expr: 'new Database("db/database.sqlite")' },
39
- turso: { expr: 'createClient({ url: getEnv("DATABASE_URL") })' }
42
+ turso: { expr: tursoClient }
40
43
  }
41
44
  };
42
45
  const remoteDrizzleInit = {
43
46
  neon: 'neon(getEnv("DATABASE_URL"));',
44
47
  planetscale: 'new Client({ url: getEnv("DATABASE_URL") })',
45
- turso: 'createClient({ url: getEnv("DATABASE_URL") })'
48
+ turso: tursoClient
46
49
  };
47
50
  const drizzleDialectSet = new Set([...availableDrizzleDialects]);
48
51
  export const generateDBBlock = ({ databaseEngine, orm, databaseHost }) => {
@@ -66,23 +69,29 @@ export const generateDBBlock = ({ databaseEngine, orm, databaseHost }) => {
66
69
  databaseHost !== 'planetscale') {
67
70
  return `
68
71
  const pool = createPool(getEnv("DATABASE_URL"))
69
- const db = drizzle(pool, { schema, mode: 'default' })
72
+ const db = drizzle({ client: pool })
73
+ `;
74
+ }
75
+ if (databaseEngine === 'cockroachdb') {
76
+ return `
77
+ const pool = new Pool({ connectionString: getEnv("DATABASE_URL") })
78
+ const db = drizzle({ client: pool })
70
79
  `;
71
80
  }
72
81
  if (databaseEngine === 'mssql' && hostKey === 'none') {
73
82
  return `
74
83
  const pool = await connect(getEnv("DATABASE_URL"))
75
- const db = drizzle({ client: pool }, { schema })
84
+ const db = drizzle({ client: pool })
76
85
  `;
77
86
  }
78
87
  if (databaseEngine === 'postgresql' && databaseHost === 'neon') {
79
88
  return `
80
89
  const sql = neon(getEnv('DATABASE_URL'));
81
- const db = drizzle(sql, { schema });
90
+ const db = drizzle({ client: sql });
82
91
  `;
83
92
  }
84
93
  return `
85
94
  const pool = ${expr}
86
- const db = drizzle(pool, { schema })
95
+ const db = drizzle({ client: pool })
87
96
  `;
88
97
  };
@@ -0,0 +1 @@
1
+ export declare const generateIdentity: () => string;
@@ -0,0 +1,15 @@
1
+ export const generateIdentity = () => `
2
+ export type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };
3
+ export type UserIdentity = Record<string, JsonValue>;
4
+ const isJsonValue = (value: unknown): value is JsonValue => {
5
+ if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;
6
+ if (typeof value === 'number') return Number.isFinite(value);
7
+ if (Array.isArray(value)) return value.every(isJsonValue);
8
+ return typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype && Object.values(value).every(isJsonValue);
9
+ };
10
+ const isIdentity = (value: Record<string, unknown>): value is UserIdentity => Object.values(value).every(isJsonValue);
11
+ export const parseUserIdentity = (value: Record<string, unknown>): UserIdentity => {
12
+ if (!isIdentity(value)) throw new Error('Provider identity must contain JSON values');
13
+ return value;
14
+ };
15
+ `;
@@ -10,10 +10,10 @@ export const generateImportsBlock = ({ deps, flags, orm, authOption, databaseEng
10
10
  pushHandler(flags.requiresVue, 'handleVuePageRequest', '@absolutejs/absolute/vue');
11
11
  pushHandler(flags.requiresVue, 'generateHeadElement');
12
12
  pushHandler(flags.requiresHtmx, 'handleHTMXPageRequest');
13
- for (const dependency of deps) {
13
+ deps.forEach((dependency) => {
14
14
  const importsList = dependency.imports ?? [];
15
15
  if (importsList.length === 0)
16
- continue;
16
+ return;
17
17
  const bySource = new Map();
18
18
  for (const imported of importsList) {
19
19
  const source = imported.importFrom ?? dependency.value;
@@ -25,7 +25,7 @@ export const generateImportsBlock = ({ deps, flags, orm, authOption, databaseEng
25
25
  for (const [source, names] of bySource) {
26
26
  rawImports.push(`import { ${names.sort().join(', ')} } from '${source}'`);
27
27
  }
28
- }
28
+ });
29
29
  const buildExamplePath = (dir, file) => `../frontend${dir ? `/${dir}` : ''}/pages/${file}`;
30
30
  const reactDir = frontendDirectories.react;
31
31
  const svelteDir = frontendDirectories.svelte;
@@ -42,7 +42,10 @@ export const generateImportsBlock = ({ deps, flags, orm, authOption, databaseEng
42
42
  const connectorImports = {
43
43
  neon: [`import { neon } from '@neondatabase/serverless'`],
44
44
  planetscale: [`import { Client } from '@planetscale/database'`],
45
- turso: [`import { createClient } from '@libsql/client'`]
45
+ turso: [
46
+ `import { createClient } from '@libsql/client'`,
47
+ `import { env } from 'bun'`
48
+ ]
46
49
  };
47
50
  const dialectImports = {
48
51
  neon: [`import { drizzle } from 'drizzle-orm/neon-http'`],
@@ -59,10 +62,7 @@ export const generateImportsBlock = ({ deps, flags, orm, authOption, databaseEng
59
62
  `import { Elysia } from 'elysia'`,
60
63
  ...(databaseEngine === 'sqlite' && !isRemoteHost
61
64
  ? []
62
- : [`import { getEnv } from '@absolutejs/absolute'`]),
63
- ...(authOption === 'abs'
64
- ? [`import { schema } from '../../db/schema'`]
65
- : [`import { schema } from '../../db/schema'`])
65
+ : [`import { getEnv } from '@absolutejs/absolute'`])
66
66
  ]
67
67
  };
68
68
  const getPostgresqlOrmDatabaseImports = () => {
@@ -80,13 +80,15 @@ export const generateImportsBlock = ({ deps, flags, orm, authOption, databaseEng
80
80
  };
81
81
  const ormDatabaseImports = {
82
82
  drizzle: {
83
- gel: [
84
- `import { createClient } from 'gel'`,
85
- `import { drizzle } from 'drizzle-orm/gel'`
83
+ cockroachdb: [
84
+ `import { drizzle } from 'drizzle-orm/cockroach'`,
85
+ `import { Pool } from 'pg'`
86
86
  ],
87
+ /* drizzle-orm/mysql2 1.0 sets options on the pool's `config`, which
88
+ only mysql2's callback pool has; it wraps it in .promise() itself. */
87
89
  mariadb: [
88
90
  `import { drizzle } from 'drizzle-orm/mysql2'`,
89
- `import { createPool } from 'mysql2/promise'`
91
+ `import { createPool } from 'mysql2'`
90
92
  ],
91
93
  mssql: [
92
94
  `import { connect } from 'mssql'`,
@@ -95,7 +97,7 @@ export const generateImportsBlock = ({ deps, flags, orm, authOption, databaseEng
95
97
  mysql: !isRemoteHost
96
98
  ? [
97
99
  `import { drizzle } from 'drizzle-orm/mysql2'`,
98
- `import { createPool } from 'mysql2/promise'`
100
+ `import { createPool } from 'mysql2'`
99
101
  ]
100
102
  : [],
101
103
  postgresql: getPostgresqlOrmDatabaseImports(),
@@ -188,8 +190,6 @@ export const generateImportsBlock = ({ deps, flags, orm, authOption, databaseEng
188
190
  }
189
191
  if (authOption === 'abs')
190
192
  rawImports.push(`import { absoluteAuthConfig } from './utils/absoluteAuthConfig'`, `import { t } from 'elysia'`, `import { authClientOption, authIntentOption, getStatus, providers, ProviderOption, userSessionIdTypebox } from '@absolutejs/auth'`);
191
- if (hasDatabase && (authOption === undefined || authOption === 'none'))
192
- rawImports.push(`import { getCountHistory, createCountHistory } from './handlers/countHistoryHandlers'`, `import { t } from 'elysia'`);
193
193
  const importMap = new Map();
194
194
  for (const stmt of rawImports) {
195
195
  const match = stmt.match(/^import\s+(.+)\s+from\s+['"](.+)['"];?/);
@@ -3,6 +3,7 @@ type GenerateRoutesBlockProps = {
3
3
  databaseEngine: CreateConfiguration['databaseEngine'];
4
4
  frontendDirectories: FrontendDirectories;
5
5
  authOption: AuthOption;
6
+ includeDatabaseRoutes?: boolean;
6
7
  };
7
- export declare const generateRoutesBlock: ({ databaseEngine, frontendDirectories, authOption }: GenerateRoutesBlockProps) => string;
8
+ export declare const generateRoutesBlock: ({ databaseEngine, frontendDirectories, authOption, includeDatabaseRoutes }: GenerateRoutesBlockProps) => string;
8
9
  export {};
@@ -1,5 +1,5 @@
1
1
  import { isFrontend } from '../../typeGuards';
2
- export const generateRoutesBlock = ({ databaseEngine, frontendDirectories, authOption }) => {
2
+ export const generateRoutesBlock = ({ databaseEngine, frontendDirectories, authOption, includeDatabaseRoutes = true }) => {
3
3
  const hasDatabase = databaseEngine !== undefined && databaseEngine !== 'none';
4
4
  const routes = [];
5
5
  const wrap = (handlerCall, isAsync = false) => authOption === 'abs'
@@ -19,14 +19,14 @@ export const generateRoutesBlock = ({ databaseEngine, frontendDirectories, authO
19
19
  : `${isAsync ? 'async ' : ''}() => ${handlerCall}`;
20
20
  const createHandlerCall = (frontend) => {
21
21
  if (frontend === 'angular')
22
- return `handleAngularPageRequest<typeof AngularExamplePage>({
22
+ return `handleAngularPageRequest<AngularExamplePage.Context>({
23
23
  headTag: generateHeadElement({
24
24
  cssPath: asset(manifest, 'AngularExampleCSS'),
25
25
  title: 'AbsoluteJS + Angular'
26
26
  }),
27
27
  indexPath: asset(manifest, 'AngularExampleIndex'),
28
28
  pagePath: asset(manifest, 'AngularExample'),
29
- props: { initialCount: 0 }
29
+ requestContext: { initialCount: 0 }
30
30
  })`;
31
31
  if (frontend === 'html')
32
32
  return `handleHTMLPageRequest(asset(manifest, 'HTMLExample'))`;
@@ -51,10 +51,7 @@ export const generateRoutesBlock = ({ databaseEngine, frontendDirectories, authO
51
51
  if (frontend === 'vue')
52
52
  return `handleVuePageRequest<typeof VueExample>({
53
53
  headTag: generateHeadElement({
54
- cssPath: [
55
- asset(manifest, 'VueExampleCSS'),
56
- asset(manifest, 'VueExampleCompiledCSS')
57
- ],
54
+ cssPath: asset(manifest, 'VueExampleCSS'),
58
55
  title: 'AbsoluteJS + Vue'
59
56
  }),
60
57
  indexPath: asset(manifest, 'VueExampleIndex'),
@@ -82,12 +79,10 @@ export const generateRoutesBlock = ({ databaseEngine, frontendDirectories, authO
82
79
  routes.push(`.get('/${frontend}', ${handler})`);
83
80
  }
84
81
  });
85
- if (hasDatabase && (authOption === undefined || authOption === 'none')) {
86
- routes.push(`.get('/count/:uid', ({ params: { uid } }) => getCountHistory(db, uid), {
87
- params: t.Object({ uid: t.Number() })
88
- })`, `.post('/count', ({ body: { count } }) => createCountHistory(db, count), {
89
- body: t.Object({ count: t.Number() })
90
- })`);
82
+ if (includeDatabaseRoutes &&
83
+ hasDatabase &&
84
+ (authOption === undefined || authOption === 'none')) {
85
+ routes.push(`.get('/count/:uid', { params: t.Object({ uid: t.Number() }) }, ({ params: { uid } }) => getCountHistory(db, uid))`, `.post('/count', { body: t.Object({ count: t.Number() }) }, ({ body: { count } }) => createCountHistory(db, count))`);
91
86
  }
92
87
  return routes.join('\n ');
93
88
  };
@@ -34,20 +34,21 @@ export const generateServerFile = ({ tailwind, authOption, plugins, buildDirecto
34
34
  const useBlock = deps
35
35
  .flatMap((dependency) => dependency.imports ?? [])
36
36
  .filter((pluginImport) => pluginImport.isPlugin &&
37
- pluginImport.packageName !== 'networking')
37
+ pluginImport.packageName !== 'networking' &&
38
+ pluginImport.packageName !== 'openapi')
38
39
  .map((pluginImport) => {
39
40
  if (pluginImport.packageName === 'auth') {
40
- return `.use(authPlugin)`;
41
+ return 'authPlugin';
41
42
  }
42
43
  if (pluginImport.config === undefined) {
43
- return `.use(${pluginImport.packageName})`;
44
+ return pluginImport.packageName;
44
45
  }
45
46
  if (pluginImport.config === null) {
46
- return `.use(${pluginImport.packageName}())`;
47
+ return `${pluginImport.packageName}()`;
47
48
  }
48
- return `.use(${pluginImport.packageName}(${JSON.stringify(pluginImport.config)}))`;
49
+ return `${pluginImport.packageName}(${JSON.stringify(pluginImport.config)})`;
49
50
  })
50
- .join('\n');
51
+ .join(', ');
51
52
  const guardBlock = `.guard({
52
53
  cookie: t.Cookie({
53
54
  auth_client: authClientOption,
@@ -58,29 +59,38 @@ export const generateServerFile = ({ tailwind, authOption, plugins, buildDirecto
58
59
  const routesBlock = generateRoutesBlock({
59
60
  authOption,
60
61
  databaseEngine,
61
- frontendDirectories
62
+ frontendDirectories,
63
+ includeDatabaseRoutes: false
62
64
  });
63
65
  const hasDatabase = databaseEngine !== undefined && databaseEngine !== 'none';
64
- /* `auth()` is async, so it is hoisted out of the `.use()` chain rather than
65
- inlined — Elysia accepts the promise as a plugin. */
66
+ /* Resolve async auth before composing the shallow plugin array. */
66
67
  const authBlock = authOption === 'abs'
67
- ? `const authPlugin = auth(absoluteAuthConfig(${hasDatabase ? 'db' : ''}))\n`
68
+ ? `const authPlugin = await auth(absoluteAuthConfig(${hasDatabase ? 'db' : ''}))\n`
68
69
  : '';
69
70
  const content = `${importsBlock}
70
- import { api } from './api'
71
+ import { ${hasDatabase && authOption !== 'abs' ? 'createApi' : 'api'} } from './api'
71
72
 
72
73
  ${manifestBlock}
73
- ${dbBlock ? `${dbBlock}\n` : ''}${authBlock}
74
+ ${dbBlock ? `${dbBlock}\n` : ''}${hasDatabase && authOption !== 'abs' ? 'const api = createApi(db)\n' : ''}${authBlock}
74
75
  export const server = new Elysia()
75
- .use([absolutejs, api])
76
- ${useBlock}${authOption === 'abs' ? `\n${guardBlock}` : ''}
76
+ .use([absolutejs, api${useBlock ? `, ${useBlock}` : ''}])
77
+ ${authOption === 'abs' ? `\n${guardBlock}` : ''}
77
78
  ${routesBlock}
78
- .use(networking)
79
+ ${plugins.includes('@elysia/openapi') ? '.use(openapi())' : ''}
79
80
  .error(({ request, error }) => {
80
81
  console.error(\`Server error on \${request.method} \${request.url}\`, error)
81
82
  })
83
+ .use(networking)
82
84
 
83
85
  `;
84
- writeFileSync(join(backendDirectory, 'api.ts'), "import { Elysia } from 'elysia'\n\n// Add typed JSON subapps here; keep page rendering and lifecycle in server.ts.\nexport const api = new Elysia({ name: 'application-api' })\nexport type Api = typeof api\n");
86
+ writeFileSync(join(backendDirectory, 'api.ts'), hasDatabase && authOption !== 'abs'
87
+ ? `import { Elysia, t } from 'elysia'
88
+ import type { DatabaseType } from '../types/databaseTypes'
89
+ import { getCountHistory, createCountHistory } from './handlers/countHistoryHandlers'
90
+ export const createApi = (db: DatabaseType) => new Elysia({name:'application-api'})
91
+ ${generateRoutesBlock({ authOption: 'none', databaseEngine, frontendDirectories: {} })}
92
+ export type Api = ReturnType<typeof createApi>
93
+ `
94
+ : "import { Elysia } from 'elysia'\n\n// Add typed JSON subapps here; keep page rendering and lifecycle in server.ts.\nexport const api = new Elysia({ name: 'application-api' })\nexport type Api = typeof api\n");
85
95
  writeFileSync(serverFilePath, content);
86
96
  };
@@ -1,5 +1,5 @@
1
- export declare const agentRuntimeSource = "import {\n\tcreateAgency,\n\tcreateAgentControlPlane,\n\tcreateMemoryAgencyStore,\n\tcreateMemoryAgentControlStore,\n\tdenyAllPolicy\n} from '@absolutejs/agency'\nimport {\n\tcreateAgentRuntime,\n\tcreateMemoryAgentRuntimeStore\n} from '@absolutejs/agent-runtime'\n\n// Memory stores are development defaults. Replace them with durable stores\n// before running more than one process or accepting production actions.\nexport const agentControl = createAgentControlPlane({\n\tsources: [],\n\tstore: createMemoryAgentControlStore()\n})\n\n// Intentionally deny-by-default. Replace denyAllPolicy() with your policy\n// decision point only after declaring each action's effects and scopes.\nexport const agency = createAgency({\n\tcontrol: agentControl,\n\tpolicy: denyAllPolicy(),\n\tstore: createMemoryAgencyStore()\n})\n\n// Durable run semantics are available from the first commit. The placeholder\n// driver fails closed until the application supplies its model/tool loop.\nexport const agentRuntime = createAgentRuntime({\n\tstore: createMemoryAgentRuntimeStore(),\n\tdriver: {\n\t\tnext: async () => ({\n\t\t\ttype: 'fail',\n\t\t\tcode: 'agent_not_configured',\n\t\t\tmessage: 'Configure the agent driver before accepting runs'\n\t\t})\n\t},\n\teffects: {\n\t\texecute: async () => {\n\t\t\tthrow new Error('Agent effects are not configured')\n\t\t}\n\t}\n})\n";
2
1
  export declare const agentDiscoverySource = "import {\n\tABSOLUTE_AGENT_SCHEMA,\n\tcreateAgentDiscoveryHandler,\n\tsignAgentDocument,\n\ttype AgentDiscoveryDocument,\n\ttype DiscoverySigner\n} from '@absolutejs/agent-discovery'\n\n// Keep this document specific and keyword-rich: registries rank declared\n// capabilities, effects, scopes, interfaces, examples, and publisher trust.\nexport const createAgentDocument = ({\n\torigin,\n\tpublishedAt,\n\tversion\n}: {\n\torigin: string\n\tpublishedAt: string\n\tversion: string\n}): AgentDiscoveryDocument => ({\n\t$schema: ABSOLUTE_AGENT_SCHEMA,\n\tid: `${origin}/agents/main`,\n\tname: 'Replace with your agent name',\n\tdescription: 'Replace with a precise description of the outcomes this agent delivers.',\n\tversion,\n\turl: origin,\n\tpublisher: {\n\t\tid: origin,\n\t\tname: 'Replace with your organization',\n\t\tjwksUri: `${origin}/.well-known/jwks.json`\n\t},\n\tcapabilities: [{\n\t\tid: 'status.read',\n\t\ttitle: 'Read service status',\n\t\tdescription: 'Returns the public health and readiness status of this agent.',\n\t\ttags: ['status', 'health', 'readiness'],\n\t\teffects: ['read'],\n\t\tapproval: 'never'\n\t}],\n\tinterfaces: [{\n\t\ttype: 'http',\n\t\turl: `${origin}/api/agents/main`,\n\t\tcontentTypes: ['application/json']\n\t}],\n\tcategories: ['replace-with-domain-category'],\n\ttags: ['replace-with-user-intent', 'replace-with-outcome'],\n\tlanguages: ['en'],\n\tdocumentationUrl: `${origin}/docs/agents/main`,\n\texamples: [{\n\t\ttitle: 'Check whether the agent is ready',\n\t\tprompt: 'Check the agent service status.',\n\t\tcapabilityId: 'status.read'\n\t}],\n\tcreatedAt: publishedAt,\n\tupdatedAt: publishedAt\n})\n\n// Use a KMS/HSM-backed signer in production. Mount the returned fetch handler\n// at the origin root so all well-known, A2A, JSON-LD, agents.txt, and sitemap\n// discovery surfaces are served from one signed descriptor.\nexport const createAgentDiscovery = async ({\n\tsigner,\n\torigin,\n\tpublishedAt,\n\tversion\n}: {\n\tsigner: DiscoverySigner\n\torigin: string\n\tpublishedAt: string\n\tversion: string\n}) =>\n\tcreateAgentDiscoveryHandler({\n\t\tdocuments: [await signAgentDocument(\n\t\t\tcreateAgentDocument({ origin, publishedAt, version }),\n\t\t\tsigner\n\t\t)]\n\t})\n";
2
+ export declare const agentRuntimeSource = "import {\n\tcreateAgency,\n\tcreateAgentControlPlane,\n\tcreateMemoryAgencyStore,\n\tcreateMemoryAgentControlStore,\n\tdenyAllPolicy\n} from '@absolutejs/agency'\nimport {\n\tcreateAgentRuntime,\n\tcreateMemoryAgentRuntimeStore\n} from '@absolutejs/agent-runtime'\n\n// Memory stores are development defaults. Replace them with durable stores\n// before running more than one process or accepting production actions.\nexport const agentControl = createAgentControlPlane({\n\tsources: [],\n\tstore: createMemoryAgentControlStore()\n})\n\n// Intentionally deny-by-default. Replace denyAllPolicy() with your policy\n// decision point only after declaring each action's effects and scopes.\nexport const agency = createAgency({\n\tcontrol: agentControl,\n\tpolicy: denyAllPolicy(),\n\tstore: createMemoryAgencyStore()\n})\n\n// Durable run semantics are available from the first commit. The placeholder\n// driver fails closed until the application supplies its model/tool loop.\nexport const agentRuntime = createAgentRuntime({\n\tstore: createMemoryAgentRuntimeStore(),\n\tdriver: {\n\t\tnext: async () => ({\n\t\t\ttype: 'fail',\n\t\t\tcode: 'agent_not_configured',\n\t\t\tmessage: 'Configure the agent driver before accepting runs'\n\t\t})\n\t},\n\teffects: {\n\t\texecute: async () => {\n\t\t\tthrow new Error('Agent effects are not configured')\n\t\t}\n\t}\n})\n";
3
3
  export declare const agentsGuide = "# Agent execution contract\n\nThis project uses the AbsoluteJS provider-neutral agent stack.\n\n- Authenticate agents and bind every delegation to a user with\n `@absolutejs/auth`. Never treat model-provided identity as authenticated.\n- Route every effectful tool through `agency` in `src/backend/agent.ts`.\n Approval is exact-input-bound; execution requires a fresh single-use lease.\n- Declare tool effects, scopes, approval policy, idempotency keys,\n reversibility, destinations, and spend fields in manifest contract 2.\n- Keep raw credentials host-side with `@absolutejs/secrets` credential\n operations. Agents receive operation results, never secret values.\n- Give agents bounded wallet allowances and signed mandates. The host resolves\n ledger destinations; an agent never supplies the recipient account id.\n- Bind MCP task handles to the authenticated actor on get, update, and cancel.\n- Use `@absolutejs/execution` for idempotent effects and its transactional\n PostgreSQL outbox before handing work to a durable queue.\n- Publish and consume remote agents with `@absolutejs/a2a` using A2A 1.0;\n preserve the authenticated tenant and actor binding at every task boundary.\n- Route outbound HTTP through `@absolutejs/egress`. Authorize host, method,\n resolved public IP, redirects, byte limits, and injected credentials host-side.\n- Store immutable, digest-addressed policy revisions with `@absolutejs/policy`\n and atomically activate only reviewed versions.\n- Publish the signed descriptor in `src/backend/agent-discovery.ts` through\n `@absolutejs/agent-discovery`. Keep capabilities, examples, tags, effects,\n scopes, A2A/MCP interfaces, JSON-LD, agents.txt, and sitemap surfaces current.\n- Run long-lived work through `@absolutejs/agent-runtime`; use its leases,\n checkpoints, timers, budgets, cancellation, and crash-safe effect recovery.\n- Authorize all HTTP/filesystem/process access with expiring\n `@absolutejs/agent-sandbox` grants. There is no ambient agent authority.\n- Preserve instruction/data separation and provenance taints with\n `@absolutejs/agent-trust`; external content never becomes an instruction.\n- Store scoped, expiring, provenance-bearing data with\n `@absolutejs/agent-memory`, and validate writes against memory poisoning.\n- Receive only verified events through `@absolutejs/agent-inbox`; durable\n leases, retries, dead letters, and schedules do not require Redis.\n- Use OpenID AuthZEN AARP for requestable approvals and COAZ mappings for\n parameter-level MCP authorization. Approval always triggers re-evaluation.\n- Protect operator actions with `@absolutejs/agent-control` scopes, a\n kill-switch-first check, and leased idempotency records.\n- Use `@absolutejs/sync-bus-pg` for durable framework channels. Redis is an\n optional at-most-once fanout adapter, not a source of truth or work queue.\n- Run `@absolutejs/agent-conformance` suites for every new action, capability,\n credential, wallet, egress, execution, control, and task adapter.\n- Use the control plane kill switch for incident response. It blocks new\n requests, lease issuance, and execution before downstream revocation fans out.\n\nMemory stores are for local development only. Production stores must be\ndurable and enforce lease/capability consumption atomically. Apply each\npackage's exported PostgreSQL schema in a migration before enabling traffic.\n";
4
4
  export declare const scaffoldAgentic: ({ backendDirectory, projectName }: {
5
5
  backendDirectory: string;
@@ -1,50 +1,5 @@
1
1
  import { mkdirSync, writeFileSync } from 'fs';
2
2
  import { join } from 'path';
3
- export const agentRuntimeSource = `import {
4
- createAgency,
5
- createAgentControlPlane,
6
- createMemoryAgencyStore,
7
- createMemoryAgentControlStore,
8
- denyAllPolicy
9
- } from '@absolutejs/agency'
10
- import {
11
- createAgentRuntime,
12
- createMemoryAgentRuntimeStore
13
- } from '@absolutejs/agent-runtime'
14
-
15
- // Memory stores are development defaults. Replace them with durable stores
16
- // before running more than one process or accepting production actions.
17
- export const agentControl = createAgentControlPlane({
18
- sources: [],
19
- store: createMemoryAgentControlStore()
20
- })
21
-
22
- // Intentionally deny-by-default. Replace denyAllPolicy() with your policy
23
- // decision point only after declaring each action's effects and scopes.
24
- export const agency = createAgency({
25
- control: agentControl,
26
- policy: denyAllPolicy(),
27
- store: createMemoryAgencyStore()
28
- })
29
-
30
- // Durable run semantics are available from the first commit. The placeholder
31
- // driver fails closed until the application supplies its model/tool loop.
32
- export const agentRuntime = createAgentRuntime({
33
- store: createMemoryAgentRuntimeStore(),
34
- driver: {
35
- next: async () => ({
36
- type: 'fail',
37
- code: 'agent_not_configured',
38
- message: 'Configure the agent driver before accepting runs'
39
- })
40
- },
41
- effects: {
42
- execute: async () => {
43
- throw new Error('Agent effects are not configured')
44
- }
45
- }
46
- })
47
- `;
48
3
  export const agentDiscoverySource = `import {
49
4
  ABSOLUTE_AGENT_SCHEMA,
50
5
  createAgentDiscoveryHandler,
@@ -122,6 +77,51 @@ export const createAgentDiscovery = async ({
122
77
  )]
123
78
  })
124
79
  `;
80
+ export const agentRuntimeSource = `import {
81
+ createAgency,
82
+ createAgentControlPlane,
83
+ createMemoryAgencyStore,
84
+ createMemoryAgentControlStore,
85
+ denyAllPolicy
86
+ } from '@absolutejs/agency'
87
+ import {
88
+ createAgentRuntime,
89
+ createMemoryAgentRuntimeStore
90
+ } from '@absolutejs/agent-runtime'
91
+
92
+ // Memory stores are development defaults. Replace them with durable stores
93
+ // before running more than one process or accepting production actions.
94
+ export const agentControl = createAgentControlPlane({
95
+ sources: [],
96
+ store: createMemoryAgentControlStore()
97
+ })
98
+
99
+ // Intentionally deny-by-default. Replace denyAllPolicy() with your policy
100
+ // decision point only after declaring each action's effects and scopes.
101
+ export const agency = createAgency({
102
+ control: agentControl,
103
+ policy: denyAllPolicy(),
104
+ store: createMemoryAgencyStore()
105
+ })
106
+
107
+ // Durable run semantics are available from the first commit. The placeholder
108
+ // driver fails closed until the application supplies its model/tool loop.
109
+ export const agentRuntime = createAgentRuntime({
110
+ store: createMemoryAgentRuntimeStore(),
111
+ driver: {
112
+ next: async () => ({
113
+ type: 'fail',
114
+ code: 'agent_not_configured',
115
+ message: 'Configure the agent driver before accepting runs'
116
+ })
117
+ },
118
+ effects: {
119
+ execute: async () => {
120
+ throw new Error('Agent effects are not configured')
121
+ }
122
+ }
123
+ })
124
+ `;
125
125
  export const agentsGuide = `# Agent execution contract
126
126
 
127
127
  This project uses the AbsoluteJS provider-neutral agent stack.
@@ -1,6 +1,7 @@
1
1
  import { mkdirSync, writeFileSync } from 'fs';
2
2
  import { join } from 'path';
3
- import { generateAbsoluteAuthConfig, generateSessionUserType } from './generateAbsoluteAuthConfig';
3
+ import { generateAbsoluteAuthConfig } from './generateAbsoluteAuthConfig';
4
+ import { generateIdentity } from './generateIdentity';
4
5
  import { generateServerFile } from './generateServer';
5
6
  export const scaffoldBackend = ({ assetsDirectory, authOption, absProviders, backendDirectory, buildDirectory, databaseEngine, databaseHost, frontendDirectories, orm, plugins, publicDirectory, tailwind, typesDirectory }) => {
6
7
  generateServerFile({
@@ -17,17 +18,11 @@ export const scaffoldBackend = ({ assetsDirectory, authOption, absProviders, bac
17
18
  tailwind
18
19
  });
19
20
  if (authOption === 'abs') {
21
+ mkdirSync(typesDirectory, { recursive: true });
22
+ writeFileSync(join(typesDirectory, 'userIdentity.ts'), generateIdentity());
20
23
  mkdirSync(join(backendDirectory, 'utils'), { recursive: true });
21
24
  const hasDatabase = databaseEngine !== undefined && databaseEngine !== 'none';
22
25
  const absoluteAuthConfig = generateAbsoluteAuthConfig(absProviders, hasDatabase);
23
26
  writeFileSync(join(backendDirectory, 'utils', 'absoluteAuthConfig.ts'), absoluteAuthConfig, 'utf-8');
24
- /* The auth config and the example page both import `User` from
25
- types/databaseTypes, which scaffoldDatabase only writes when there is
26
- a database. Without one, emit the session user shape on its own so the
27
- auth scaffold still type-checks. */
28
- if (!hasDatabase) {
29
- mkdirSync(typesDirectory, { recursive: true });
30
- writeFileSync(join(typesDirectory, 'databaseTypes.ts'), generateSessionUserType(), 'utf-8');
31
- }
32
27
  }
33
28
  };
@@ -19,8 +19,8 @@ export const scaffoldReact = ({ authOption, directory, editBasePath, includeExam
19
19
  dependency of `@absolutejs/auth`. Without Absolute Auth the import cannot
20
20
  resolve, so the component is left out entirely. */
21
21
  cpSync(join(templatesDirectory, 'react'), targetDirectory, {
22
- filter: (source) => authOption === 'abs' || basename(source) !== 'OAuthLink.tsx',
23
- recursive: true
22
+ recursive: true,
23
+ filter: (source) => authOption === 'abs' || basename(source) !== 'OAuthLink.tsx'
24
24
  });
25
25
  const appComponent = generateAppComponent(frontends, editBasePath);
26
26
  writeFileSync(join(targetDirectory, 'components', 'App.tsx'), appComponent, 'utf-8');
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ if (help === true) {
14
14
  exit(0);
15
15
  }
16
16
  const response = await prompt(argumentConfiguration);
17
- const { dockerFreshInstall } = await scaffold({
17
+ const { databaseMigrationPending, dockerFreshInstall } = await scaffold({
18
18
  envVariables,
19
19
  latest,
20
20
  packageManager,
@@ -27,6 +27,7 @@ const debugMessage = debug !== false
27
27
  })
28
28
  : '';
29
29
  const outroMessage = getOutroMessage({
30
+ databaseMigrationPending,
30
31
  installDependenciesNow: response.installDependenciesNow,
31
32
  packageManager,
32
33
  projectName: response.projectName
@@ -4,8 +4,9 @@ type OutroMessageProps = {
4
4
  projectName: string;
5
5
  packageManager: string;
6
6
  installDependenciesNow: boolean;
7
+ databaseMigrationPending: boolean;
7
8
  };
8
- export declare const getOutroMessage: ({ projectName, packageManager, installDependenciesNow }: OutroMessageProps) => string;
9
+ export declare const getOutroMessage: ({ databaseMigrationPending, projectName, packageManager, installDependenciesNow }: OutroMessageProps) => string;
9
10
  type DebugMessageProps = {
10
11
  response: CreateConfiguration;
11
12
  packageManager: string;
package/dist/messages.js CHANGED
@@ -46,9 +46,10 @@ Options:
46
46
  ${cyan('--vue')} Include a Vue frontend
47
47
  ${cyan('--vue-dir')} ${dim(cyan('<directory>'))} Specify the directory for and use the Vue frontend
48
48
  `;
49
- export const getOutroMessage = ({ projectName, packageManager, installDependenciesNow }) => `${green('Created successfully')}, you can now run:\n\n` +
49
+ export const getOutroMessage = ({ databaseMigrationPending, projectName, packageManager, installDependenciesNow }) => `${green('Created successfully')}, you can now run:\n\n` +
50
50
  `${cyan('cd')} ${projectName}\n` +
51
51
  `${installDependenciesNow ? '' : `${cyan(`${packageManager} install`)}\n`}` +
52
+ `${databaseMigrationPending ? `${cyan(`${packageManager} run db:migrate`)}\n` : ''}` +
52
53
  `${cyan(`${packageManager} dev`)}`; // TODO: Some package managers need run
53
54
  export const getDebugMessage = ({ response: { agentic, projectName, codeQualityTool, directoryConfig, useTailwind, tailwind, frontends, includeExamples, useHTMLScripts, frontendDirectories, buildDirectory, assetsDirectory, databaseEngine, databaseHost, databaseDirectory, orm, authOption, plugins, initializeGitNow, installDependenciesNow }, packageManager }) => {
54
55
  const htmlScriptingValue = useHTMLScripts
package/dist/prompt.js CHANGED
@@ -1,5 +1,5 @@
1
- import { getAuthOption } from './questions/authOption';
2
1
  import { getAgentic } from './questions/agentic';
2
+ import { getAuthOption } from './questions/authOption';
3
3
  import { getCodeQualityTool } from './questions/codeQualityTool';
4
4
  import { getConfigurationType } from './questions/configurationType';
5
5
  import { getDatabaseEngine } from './questions/databaseEngine';
@@ -97,8 +97,9 @@ export const prompt = async (argumentConfiguration) => {
97
97
  const installDependenciesNow = argumentConfiguration.installDependenciesNow ??
98
98
  (await orPrompt('--install/--no-install', getInstallDependencies));
99
99
  const values = {
100
+ // Google is the provider with a complete generated configuration.
101
+ absProviders: argumentConfiguration.absProviders?.filter((provider) => provider !== undefined) ?? (authOption === 'abs' ? ['google'] : undefined),
100
102
  agentic,
101
- absProviders: argumentConfiguration.absProviders?.filter((provider) => provider !== undefined),
102
103
  assetsDirectory,
103
104
  authOption,
104
105
  buildDirectory,
@@ -6,7 +6,10 @@ export const getAuthOption = async () => {
6
6
  message: 'Auth provider:',
7
7
  options: [
8
8
  { label: 'None', value: 'none' },
9
- { label: cyan('Absolute Auth'), value: 'abs' }
9
+ {
10
+ label: cyan('Absolute Auth (Google; requires a database)'),
11
+ value: 'abs'
12
+ }
10
13
  ]
11
14
  });
12
15
  if (isCancel(authOption))
@@ -1 +1 @@
1
- export declare const getDatabaseEngine: () => Promise<"gel" | "mariadb" | "mssql" | "mysql" | "postgresql" | "singlestore" | "sqlite" | "mongodb" | "cockroachdb" | undefined>;
1
+ export declare const getDatabaseEngine: () => Promise<"cockroachdb" | "mariadb" | "mssql" | "mysql" | "postgresql" | "singlestore" | "sqlite" | "mongodb" | "gel" | undefined>;
@@ -1,6 +1,6 @@
1
1
  import { select, isCancel } from '@clack/prompts';
2
- import { cyan, magenta } from 'picocolors';
3
- import { isDrizzleDialect, isPrismaDialect } from '../typeGuards';
2
+ import { cyan } from 'picocolors';
3
+ import { isDrizzleDialect } from '../typeGuards';
4
4
  import { abort } from '../utils/abort';
5
5
  export const getORM = async (databaseEngine) => {
6
6
  const options = [
@@ -9,9 +9,6 @@ export const getORM = async (databaseEngine) => {
9
9
  if (isDrizzleDialect(databaseEngine)) {
10
10
  options.push({ label: cyan('Drizzle'), value: 'drizzle' });
11
11
  }
12
- if (isPrismaDialect(databaseEngine)) {
13
- options.push({ label: magenta('Prisma'), value: 'prisma' });
14
- }
15
12
  const orm = await select({
16
13
  message: 'Choose an ORM for your database:',
17
14
  options
@@ -4,8 +4,10 @@ type ScaffoldProps = {
4
4
  packageManager: PackageManager;
5
5
  latest: boolean;
6
6
  envVariables: string[] | undefined;
7
+ verifyLocalDatabase?: boolean;
7
8
  };
8
- export declare const scaffold: ({ response: { agentic, projectName, codeQualityTool, initializeGitNow, githubLink, githubRepoUrl, githubVisibility, databaseEngine, databaseHost, useHTMLScripts, useTailwind, databaseDirectory, absProviders, includeExamples, orm, frontends, plugins, authOption, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, envVariables, packageManager }: ScaffoldProps) => Promise<{
9
+ export declare const scaffold: ({ response: { agentic, projectName, codeQualityTool, initializeGitNow, githubLink, githubRepoUrl, githubVisibility, databaseEngine, databaseHost, useHTMLScripts, useTailwind, databaseDirectory, absProviders, includeExamples, orm, frontends, plugins, authOption, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, verifyLocalDatabase, envVariables, packageManager }: ScaffoldProps) => Promise<{
10
+ databaseMigrationPending: boolean;
9
11
  dockerFreshInstall: boolean;
10
12
  }>;
11
13
  export {};