create-absolutejs 0.15.2 → 0.15.4

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 (33) hide show
  1. package/dist/commands/formatProject.js +6 -4
  2. package/dist/data.js +1 -1
  3. package/dist/generators/configurations/generatePackageJson.d.ts +2 -2
  4. package/dist/generators/configurations/generatePackageJson.js +52 -1
  5. package/dist/generators/db/generateDatabaseTypes.js +1 -1
  6. package/dist/generators/db/handlerTemplates.d.ts +0 -24
  7. package/dist/generators/db/handlerTemplates.js +26 -31
  8. package/dist/generators/db/scaffoldDatabase.js +6 -6
  9. package/dist/generators/project/generateAbsoluteAuthConfig.d.ts +1 -0
  10. package/dist/generators/project/generateAbsoluteAuthConfig.js +31 -15
  11. package/dist/generators/project/generateRoutesBlock.js +3 -2
  12. package/dist/generators/project/generateServer.js +9 -6
  13. package/dist/generators/project/scaffoldAgentic.d.ts +7 -0
  14. package/dist/generators/project/scaffoldAgentic.js +181 -0
  15. package/dist/generators/project/scaffoldBackend.d.ts +2 -1
  16. package/dist/generators/project/scaffoldBackend.js +10 -2
  17. package/dist/generators/project/scaffoldFrontends.js +6 -0
  18. package/dist/generators/react/generateReactComponents.d.ts +1 -1
  19. package/dist/generators/react/generateReactComponents.js +7 -3
  20. package/dist/generators/react/scaffoldReact.d.ts +1 -1
  21. package/dist/generators/react/scaffoldReact.js +9 -4
  22. package/dist/messages.d.ts +1 -1
  23. package/dist/messages.js +3 -1
  24. package/dist/prompt.js +23 -9
  25. package/dist/questions/agentic.d.ts +1 -0
  26. package/dist/questions/agentic.js +11 -0
  27. package/dist/scaffold.d.ts +1 -1
  28. package/dist/scaffold.js +7 -2
  29. package/dist/types.d.ts +4 -0
  30. package/dist/utils/parseCommandLineOptions.js +14 -5
  31. package/dist/versions.d.ts +24 -4
  32. package/dist/versions.js +25 -4
  33. package/package.json +2 -2
@@ -2,13 +2,15 @@ import { exit } from 'process';
2
2
  import { spinner } from '@clack/prompts';
3
3
  import { $ } from 'bun';
4
4
  import { green, red } from 'picocolors';
5
- import { formatCommands, formatNoInstallCommands } from '../utils/commandMaps';
5
+ import { formatCommands } from '../utils/commandMaps';
6
6
  export const formatProject = async ({ projectName, packageManager, installDependenciesNow }) => {
7
+ // A no-install scaffold must be fully offline and must not assume a global
8
+ // formatter. Templates are already formatted in the published package.
9
+ if (!installDependenciesNow)
10
+ return;
7
11
  const spin = spinner();
8
12
  try {
9
- const fmt = installDependenciesNow
10
- ? formatCommands[packageManager]
11
- : formatNoInstallCommands[packageManager];
13
+ const fmt = formatCommands[packageManager];
12
14
  spin.start('Formatting files…');
13
15
  const [bin, ...args] = fmt.split(' ');
14
16
  await $ `${bin} ${args}`.cwd(projectName).quiet();
package/dist/data.js CHANGED
@@ -7,7 +7,7 @@ export const absoluteAuthPlugin = {
7
7
  providersConfiguration: {}
8
8
  },
9
9
  isPlugin: true,
10
- packageName: 'absoluteAuth'
10
+ packageName: 'auth'
11
11
  }
12
12
  ],
13
13
  latestVersion: versions['@absolutejs/auth'],
@@ -1,8 +1,8 @@
1
1
  import type { CreateConfiguration } from '../../types';
2
- type CreatePackageJsonProps = Pick<CreateConfiguration, 'authOption' | 'useTailwind' | 'databaseEngine' | 'databaseHost' | 'plugins' | 'orm' | 'frontendDirectories' | 'codeQualityTool'> & {
2
+ type CreatePackageJsonProps = Pick<CreateConfiguration, 'authOption' | 'agentic' | 'useTailwind' | 'databaseEngine' | 'databaseHost' | 'plugins' | 'orm' | 'frontendDirectories' | 'codeQualityTool'> & {
3
3
  projectName: string;
4
4
  latest: boolean;
5
5
  repositoryUrl: string | undefined;
6
6
  };
7
- export declare const createPackageJson: ({ projectName, authOption, plugins, databaseEngine, orm, databaseHost, useTailwind, latest, frontendDirectories, codeQualityTool, repositoryUrl }: CreatePackageJsonProps) => Promise<void>;
7
+ export declare const createPackageJson: ({ agentic, projectName, authOption, plugins, databaseEngine, orm, databaseHost, useTailwind, latest, frontendDirectories, codeQualityTool, repositoryUrl }: CreatePackageJsonProps) => Promise<void>;
8
8
  export {};
@@ -16,7 +16,7 @@ const dbClientCommands = {
16
16
  postgresql: 'psql -h localhost -U user -d database',
17
17
  singlestore: 'singlestore -u root -ppassword -D database'
18
18
  };
19
- export const createPackageJson = async ({ projectName, authOption, plugins, databaseEngine, orm, databaseHost, useTailwind, latest, frontendDirectories, codeQualityTool, repositoryUrl }) => {
19
+ export const createPackageJson = async ({ agentic, projectName, authOption, plugins, databaseEngine, orm, databaseHost, useTailwind, latest, frontendDirectories, codeQualityTool, repositoryUrl }) => {
20
20
  const flags = computeFlags(frontendDirectories);
21
21
  const isLocal = !databaseHost || databaseHost === 'none';
22
22
  /* ── Collect all package names that need versions ─────────── */
@@ -28,6 +28,27 @@ export const createPackageJson = async ({ projectName, authOption, plugins, data
28
28
  packageNames.add(dep.value);
29
29
  if (authOption === 'abs')
30
30
  packageNames.add(absoluteAuthPlugin.value);
31
+ if (agentic) {
32
+ packageNames.add('@absolutejs/a2a');
33
+ packageNames.add('@absolutejs/agency');
34
+ packageNames.add('@absolutejs/agent-conformance');
35
+ packageNames.add('@absolutejs/agent-discovery');
36
+ packageNames.add('@absolutejs/agent-inbox');
37
+ packageNames.add('@absolutejs/agent-memory');
38
+ packageNames.add('@absolutejs/agent-runtime');
39
+ packageNames.add('@absolutejs/agent-sandbox');
40
+ packageNames.add('@absolutejs/agent-trust');
41
+ packageNames.add('@absolutejs/agent-control');
42
+ packageNames.add('@absolutejs/auth');
43
+ packageNames.add('@absolutejs/egress');
44
+ packageNames.add('@absolutejs/execution');
45
+ packageNames.add('@absolutejs/manifest');
46
+ packageNames.add('@absolutejs/mcp');
47
+ packageNames.add('@absolutejs/policy');
48
+ packageNames.add('@absolutejs/secrets');
49
+ packageNames.add('@absolutejs/sync-bus-pg');
50
+ packageNames.add('@absolutejs/wallet');
51
+ }
31
52
  for (const pluginValue of plugins) {
32
53
  const meta = availablePlugins.find((p) => p.value === pluginValue);
33
54
  if (meta)
@@ -113,6 +134,9 @@ export const createPackageJson = async ({ projectName, authOption, plugins, data
113
134
  const dependencies = {};
114
135
  const devDependencies = {};
115
136
  devDependencies['typescript'] = resolveVersion('typescript', versions['typescript']);
137
+ /* Every scaffolded project runs on Bun, and the local database drivers type
138
+ against its built-in modules (`bun:sqlite`, `SQL` from `bun`). */
139
+ devDependencies['@types/bun'] = resolveVersion('@types/bun', versions['@types/bun']);
116
140
  for (const p of defaultPlugins) {
117
141
  dependencies[p.value] = resolveVersion(p.value, p.latestVersion);
118
142
  }
@@ -122,6 +146,31 @@ export const createPackageJson = async ({ projectName, authOption, plugins, data
122
146
  if (authOption === 'abs') {
123
147
  dependencies[absoluteAuthPlugin.value] = resolveVersion(absoluteAuthPlugin.value, absoluteAuthPlugin.latestVersion);
124
148
  }
149
+ if (agentic) {
150
+ for (const name of [
151
+ '@absolutejs/a2a',
152
+ '@absolutejs/agency',
153
+ '@absolutejs/agent-discovery',
154
+ '@absolutejs/agent-inbox',
155
+ '@absolutejs/agent-memory',
156
+ '@absolutejs/agent-runtime',
157
+ '@absolutejs/agent-sandbox',
158
+ '@absolutejs/agent-trust',
159
+ '@absolutejs/agent-control',
160
+ '@absolutejs/auth',
161
+ '@absolutejs/egress',
162
+ '@absolutejs/execution',
163
+ '@absolutejs/manifest',
164
+ '@absolutejs/mcp',
165
+ '@absolutejs/policy',
166
+ '@absolutejs/secrets',
167
+ '@absolutejs/sync-bus-pg',
168
+ '@absolutejs/wallet'
169
+ ]) {
170
+ dependencies[name] = resolveVersion(name, versions[name]);
171
+ }
172
+ devDependencies['@absolutejs/agent-conformance'] = resolveVersion('@absolutejs/agent-conformance', versions['@absolutejs/agent-conformance']);
173
+ }
125
174
  for (const pluginValue of plugins) {
126
175
  const meta = availablePlugins.find((p) => p.value === pluginValue);
127
176
  if (!meta)
@@ -243,6 +292,8 @@ export const createPackageJson = async ({ projectName, authOption, plugins, data
243
292
  if (orm === 'drizzle') {
244
293
  scripts['db:studio'] = 'drizzle-kit studio';
245
294
  scripts['db:push'] = 'drizzle-kit push';
295
+ /* `drizzle.config.ts` imports it and the scripts above shell out to it. */
296
+ devDependencies['drizzle-kit'] = resolveVersion('drizzle-kit', versions['drizzle-kit']);
246
297
  }
247
298
  const packageJson = {
248
299
  dependencies,
@@ -163,7 +163,7 @@ export const generateDatabaseTypes = ({ databaseEngine, databaseHost, authOption
163
163
  }
164
164
  const schemaImport = authOption === 'abs'
165
165
  ? `import { users, schema } from '../../db/schema';`
166
- : `import { countHistory } from '../../db/schema';`;
166
+ : `import { countHistory, schema } from '../../db/schema';`;
167
167
  const extraTypes = authOption === 'abs'
168
168
  ? `export type User = typeof users.$inferSelect;
169
169
  export type NewUser = typeof users.$inferInsert;`
@@ -6,122 +6,98 @@ type QueryOperations = {
6
6
  };
7
7
  declare const driverConfigurations: {
8
8
  readonly 'cockroachdb:sql:local': {
9
- readonly dbType: "SQL";
10
9
  readonly importLines: "";
11
10
  readonly queries: QueryOperations;
12
11
  };
13
12
  readonly 'gel:drizzle:local': {
14
- readonly dbType: "GelJsDatabase<SchemaType>";
15
13
  readonly importLines: "import { eq } from 'drizzle-orm'\nimport { schema } from '../../../db/schema'\n";
16
14
  readonly queries: QueryOperations;
17
15
  };
18
16
  readonly 'gel:sql:local': {
19
- readonly dbType: "Client";
20
17
  readonly importLines: "";
21
18
  readonly queries: QueryOperations;
22
19
  };
23
20
  readonly 'mariadb:drizzle:local': {
24
- readonly dbType: "MySql2Database<SchemaType>";
25
21
  readonly importLines: "import { eq } from 'drizzle-orm'\nimport { schema } from '../../../db/schema'";
26
22
  readonly queries: QueryOperations;
27
23
  };
28
24
  readonly 'mariadb:sql:local': {
29
- readonly dbType: "SQL";
30
25
  readonly importLines: "";
31
26
  readonly queries: QueryOperations;
32
27
  };
33
28
  readonly 'mongodb:sql:local': {
34
- readonly dbType: "Db";
35
29
  readonly importLines: "";
36
30
  readonly queries: QueryOperations;
37
31
  };
38
32
  readonly 'mssql:drizzle:local': {
39
- readonly dbType: "NodeMssqlDatabase<SchemaType>";
40
33
  readonly importLines: "import { eq } from 'drizzle-orm'\nimport { schema } from '../../../db/schema'";
41
34
  readonly queries: QueryOperations;
42
35
  };
43
36
  readonly 'mssql:sql:local': {
44
- readonly dbType: "ConnectionPool";
45
37
  readonly importLines: "";
46
38
  readonly queries: QueryOperations;
47
39
  };
48
40
  readonly 'mysql:drizzle:local': {
49
- readonly dbType: "MySql2Database<SchemaType>";
50
41
  readonly importLines: "import { eq } from 'drizzle-orm'\nimport { schema } from '../../../db/schema'";
51
42
  readonly queries: QueryOperations;
52
43
  };
53
44
  readonly 'mysql:drizzle:planetscale': {
54
- readonly dbType: "PlanetScaleDatabase<SchemaType>";
55
45
  readonly importLines: "import { eq } from 'drizzle-orm'\nimport { schema } from '../../../db/schema'";
56
46
  readonly queries: QueryOperations;
57
47
  };
58
48
  readonly 'mysql:sql:local': {
59
- readonly dbType: "SQL";
60
49
  readonly importLines: "";
61
50
  readonly queries: QueryOperations;
62
51
  };
63
52
  readonly 'mysql:sql:planetscale': {
64
- readonly dbType: "Client";
65
53
  readonly importLines: "";
66
54
  readonly queries: QueryOperations;
67
55
  };
68
56
  readonly 'postgresql:drizzle:local': {
69
- readonly dbType: "BunSQLDatabase<SchemaType>";
70
57
  readonly importLines: "import { eq } from 'drizzle-orm'\nimport { schema } from '../../../db/schema'";
71
58
  readonly queries: QueryOperations;
72
59
  };
73
60
  readonly 'postgresql:drizzle:neon': {
74
- readonly dbType: "NeonDatabase<SchemaType>";
75
61
  readonly importLines: "import { eq } from 'drizzle-orm'\nimport { schema } from '../../../db/schema'";
76
62
  readonly queries: QueryOperations;
77
63
  };
78
64
  readonly 'postgresql:drizzle:planetscale': {
79
- readonly dbType: "NodePgDatabase<SchemaType>";
80
65
  readonly importLines: "import { eq } from 'drizzle-orm'\nimport { schema } from '../../../db/schema'";
81
66
  readonly queries: QueryOperations;
82
67
  };
83
68
  readonly 'postgresql:sql:local': {
84
- readonly dbType: "SQL";
85
69
  readonly importLines: "";
86
70
  readonly queries: QueryOperations;
87
71
  };
88
72
  readonly 'postgresql:sql:neon': {
89
- readonly dbType: "Pool";
90
73
  readonly importLines: "";
91
74
  readonly queries: QueryOperations;
92
75
  };
93
76
  readonly 'postgresql:sql:planetscale': {
94
- readonly dbType: "Pool";
95
77
  readonly importLines: "";
96
78
  readonly queries: QueryOperations;
97
79
  };
98
80
  readonly 'singlestore:drizzle:local': {
99
- readonly dbType: "SingleStoreDriverDatabase<SchemaType>";
100
81
  readonly importLines: "import { eq } from 'drizzle-orm'\nimport { schema } from '../../../db/schema'";
101
82
  readonly queries: QueryOperations;
102
83
  };
103
84
  readonly 'singlestore:sql:local': {
104
- readonly dbType: "Pool";
105
85
  readonly importLines: "import { RowDataPacket } from 'mysql2/promise'\n";
106
86
  readonly queries: QueryOperations;
107
87
  };
108
88
  readonly 'sqlite:drizzle:local': {
109
- readonly dbType: "BunSQLiteDatabase<SchemaType>";
110
89
  readonly importLines: "import { eq } from 'drizzle-orm'\nimport { schema } from '../../../db/schema'";
111
90
  readonly queries: QueryOperations;
112
91
  };
113
92
  readonly 'sqlite:drizzle:turso': {
114
- readonly dbType: "LibSQLDatabase<SchemaType>";
115
93
  readonly importLines: "import { eq } from 'drizzle-orm'\nimport { schema } from '../../../db/schema'";
116
94
  readonly queries: QueryOperations;
117
95
  };
118
96
  readonly 'sqlite:sql:local': {
119
- readonly dbType: "Database";
120
97
  readonly importLines: "";
121
98
  readonly queries: QueryOperations;
122
99
  };
123
100
  readonly 'sqlite:sql:turso': {
124
- readonly dbType: "Client";
125
101
  readonly importLines: "";
126
102
  readonly queries: QueryOperations;
127
103
  };
@@ -1,22 +1,38 @@
1
- const buildSqlAuthTemplate = ({ importLines, queries }) => `
2
- import { DatabaseType, NewUser } from '../../types/databaseTypes';
1
+ const buildSqlAuthTemplate = ({ importLines, queries, rowsAreTyped }) => `
2
+ import { DatabaseType, NewUser${rowsAreTyped ? '' : ', User'} } from '../../types/databaseTypes';
3
3
  ${importLines}
4
4
 
5
- export const getUser = async (db: DatabaseType, authSub: string) => {
5
+ ${rowsAreTyped
6
+ ? `export const getUser = async (db: DatabaseType, authSub: string) => {
7
+ ${queries.selectUser}
8
+ };`
9
+ : `const selectUserRow = async (db: DatabaseType, authSub: string) => {
6
10
  ${queries.selectUser}
7
11
  };
8
12
 
13
+ /* The driver returns the row untyped, so it is asserted to the shape the query
14
+ above selects. */
15
+ export const getUser = async (
16
+ db: DatabaseType,
17
+ authSub: string
18
+ ): Promise<User | null> =>
19
+ ((await selectUserRow(db, authSub)) as User | null) ?? null;`}
20
+
9
21
  export const createUser = async (db: DatabaseType, newUserData: NewUser) => {
10
22
  const { auth_sub: authSub, metadata: userIdentity } = newUserData;
11
23
  ${queries.insertUser}
12
24
  }`;
13
- const buildSqlCountTemplate = ({ importLines, dbType, queries }) => `
25
+ /* Takes `db` as the `DatabaseType` alias rather than naming the driver type
26
+ inline, matching the auth template — the driver type is only ever spelled out
27
+ in types/databaseTypes, so it does not need importing at every call site. */
28
+ const buildSqlCountTemplate = ({ importLines, queries }) => `
29
+ import { DatabaseType } from '../../types/databaseTypes';
14
30
  ${importLines}
15
- export const getCountHistory = async (db: ${dbType}, uid: number) => {
31
+ export const getCountHistory = async (db: DatabaseType, uid: number) => {
16
32
  ${queries.selectHistory}
17
33
  }
18
34
 
19
- export const createCountHistory = async (db: ${dbType}, count: number) => {
35
+ export const createCountHistory = async (db: DatabaseType, count: number) => {
20
36
  ${queries.insertHistory}
21
37
  }
22
38
  `;
@@ -322,135 +338,111 @@ const mysqlPlanetScaleQueryOperations = {
322
338
  };
323
339
  const driverConfigurations = {
324
340
  'cockroachdb:sql:local': {
325
- dbType: 'SQL',
326
341
  importLines: ``,
327
342
  queries: postgresSqlQueryOperations
328
343
  },
329
344
  'gel:drizzle:local': {
330
- dbType: 'GelJsDatabase<SchemaType>',
331
345
  importLines: `import { eq } from 'drizzle-orm'
332
346
  import { schema } from '../../../db/schema'
333
347
  `,
334
348
  queries: drizzleQueryOperations
335
349
  },
336
350
  'gel:sql:local': {
337
- dbType: 'Client',
338
351
  importLines: ``,
339
352
  queries: gelClientQueryOperations
340
353
  },
341
354
  'mariadb:drizzle:local': {
342
- dbType: 'MySql2Database<SchemaType>',
343
355
  importLines: `import { eq } from 'drizzle-orm'
344
356
  import { schema } from '../../../db/schema'`,
345
357
  queries: mysqlDrizzleQueryOperations
346
358
  },
347
359
  'mariadb:sql:local': {
348
- dbType: 'SQL',
349
360
  importLines: ``,
350
361
  queries: mysqlSqlQueryOperations
351
362
  },
352
363
  'mongodb:sql:local': {
353
- dbType: 'Db',
354
364
  importLines: ``,
355
365
  queries: mongodbQueryOperations
356
366
  },
357
367
  'mssql:drizzle:local': {
358
- dbType: 'NodeMssqlDatabase<SchemaType>',
359
368
  importLines: `import { eq } from 'drizzle-orm'
360
369
  import { schema } from '../../../db/schema'`,
361
370
  queries: drizzleQueryOperations
362
371
  },
363
372
  'mssql:sql:local': {
364
- dbType: 'ConnectionPool',
365
373
  importLines: ``,
366
374
  queries: mssqlSqlQueryOperations
367
375
  },
368
376
  'mysql:drizzle:local': {
369
- dbType: 'MySql2Database<SchemaType>',
370
377
  importLines: `import { eq } from 'drizzle-orm'
371
378
  import { schema } from '../../../db/schema'`,
372
379
  queries: mysqlDrizzleQueryOperations
373
380
  },
374
381
  'mysql:drizzle:planetscale': {
375
- dbType: 'PlanetScaleDatabase<SchemaType>',
376
382
  importLines: `import { eq } from 'drizzle-orm'
377
383
  import { schema } from '../../../db/schema'`,
378
384
  queries: mysqlDrizzleQueryOperations
379
385
  },
380
386
  'mysql:sql:local': {
381
- dbType: 'SQL',
382
387
  importLines: ``,
383
388
  queries: mysqlSqlQueryOperations
384
389
  },
385
390
  'mysql:sql:planetscale': {
386
- dbType: 'Client',
387
391
  importLines: ``,
388
392
  queries: mysqlPlanetScaleQueryOperations
389
393
  },
390
394
  'postgresql:drizzle:local': {
391
- dbType: 'BunSQLDatabase<SchemaType>',
392
395
  importLines: `import { eq } from 'drizzle-orm'
393
396
  import { schema } from '../../../db/schema'`,
394
397
  queries: drizzleQueryOperations
395
398
  },
396
399
  'postgresql:drizzle:neon': {
397
- dbType: 'NeonDatabase<SchemaType>',
398
400
  importLines: `import { eq } from 'drizzle-orm'
399
401
  import { schema } from '../../../db/schema'`,
400
402
  queries: drizzleQueryOperations
401
403
  },
402
404
  'postgresql:drizzle:planetscale': {
403
- dbType: 'NodePgDatabase<SchemaType>',
404
405
  importLines: `import { eq } from 'drizzle-orm'
405
406
  import { schema } from '../../../db/schema'`,
406
407
  queries: drizzleQueryOperations
407
408
  },
408
409
  'postgresql:sql:local': {
409
- dbType: 'SQL',
410
410
  importLines: ``,
411
411
  queries: postgresSqlQueryOperations
412
412
  },
413
413
  'postgresql:sql:neon': {
414
- dbType: 'Pool',
415
414
  importLines: ``,
416
415
  queries: postgresQueryOperations
417
416
  },
418
417
  'postgresql:sql:planetscale': {
419
- dbType: 'Pool',
420
418
  importLines: ``,
421
419
  queries: postgresQueryOperations
422
420
  },
423
421
  'singlestore:drizzle:local': {
424
- dbType: 'SingleStoreDriverDatabase<SchemaType>',
425
422
  importLines: `import { eq } from 'drizzle-orm'
426
423
  import { schema } from '../../../db/schema'`,
427
424
  queries: mysqlDrizzleQueryOperations
428
425
  },
429
426
  'singlestore:sql:local': {
430
- dbType: 'Pool',
431
427
  importLines: `import { RowDataPacket } from 'mysql2/promise'
432
428
  `,
433
429
  queries: singlestoreSqlQueryOperations
434
430
  },
435
431
  'sqlite:drizzle:local': {
436
- dbType: 'BunSQLiteDatabase<SchemaType>',
437
432
  importLines: `import { eq } from 'drizzle-orm'
438
433
  import { schema } from '../../../db/schema'`,
439
434
  queries: drizzleQueryOperations
440
435
  },
441
436
  'sqlite:drizzle:turso': {
442
- dbType: 'LibSQLDatabase<SchemaType>',
443
437
  importLines: `import { eq } from 'drizzle-orm'
444
438
  import { schema } from '../../../db/schema'`,
445
439
  queries: drizzleQueryOperations
446
440
  },
447
441
  'sqlite:sql:local': {
448
- dbType: 'Database',
449
442
  importLines: ``,
450
443
  queries: bunSqliteQueryOperations
451
444
  },
452
445
  'sqlite:sql:turso': {
453
- dbType: 'Client',
454
446
  importLines: ``,
455
447
  queries: libsqlQueryOperations
456
448
  }
@@ -459,7 +451,10 @@ export const getAuthTemplate = (key) => {
459
451
  const configuration = driverConfigurations[key];
460
452
  if (!configuration)
461
453
  throw new Error(`Unsupported driver configuration: ${key}`);
462
- return buildSqlAuthTemplate(configuration);
454
+ return buildSqlAuthTemplate({
455
+ ...configuration,
456
+ rowsAreTyped: key.includes(':drizzle:')
457
+ });
463
458
  };
464
459
  export const getCountTemplate = (key) => {
465
460
  const configuration = driverConfigurations[key];
@@ -26,12 +26,12 @@ export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHo
26
26
  usesAuth
27
27
  });
28
28
  writeFileSync(join(handlerDirectory, handlerFileName), dbHandlers, 'utf-8');
29
- // Raw-SQL (no-ORM) auth handlers import `DatabaseType`/`NewUser` from
30
- // types/databaseTypes (so do the auth config and the example page), but
31
- // the drizzle-backed type module below is only written on the drizzle
32
- // path. Generate a self-contained, driver-typed version here so the
33
- // non-drizzle auth scaffold actually type-checks and builds.
34
- if (usesAuth && orm !== 'drizzle') {
29
+ // Raw-SQL (no-ORM) handlers import `DatabaseType` (and `NewUser` on the auth
30
+ // path) from types/databaseTypes (so do the auth config and the example
31
+ // page), but the drizzle-backed type module below is only written on the
32
+ // drizzle path. Generate a self-contained, driver-typed version here so the
33
+ // non-drizzle scaffold actually type-checks and builds.
34
+ if (orm !== 'drizzle') {
35
35
  mkdirSync(typesDirectory, { recursive: true });
36
36
  const sqlTypes = generateDatabaseTypes({
37
37
  authOption,
@@ -1,2 +1,3 @@
1
1
  import { ProviderOption } from '@absolutejs/auth';
2
+ export declare const generateSessionUserType: () => string;
2
3
  export declare const generateAbsoluteAuthConfig: (absProviders: ProviderOption[] | undefined, hasDatabase: boolean) => string;
@@ -12,6 +12,15 @@ 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
+ `;
15
24
  export const generateAbsoluteAuthConfig = (absProviders, hasDatabase) => {
16
25
  const providerConfigs = (absProviders ?? [])
17
26
  .map((provider) => {
@@ -45,38 +54,46 @@ ${credentialsLines}
45
54
  if (!hasDatabase) {
46
55
  return `import { getEnv } from '@absolutejs/absolute';
47
56
  import {
48
- AbsoluteAuthProps,
49
- createInMemoryAuthSessionStore
57
+ createInMemoryAuthSessionStore,
58
+ defineAuthConfig
50
59
  } from '@absolutejs/auth';
60
+ import { User } from '../../types/databaseTypes';
51
61
 
52
- export const absoluteAuthConfig = (): AbsoluteAuthProps => ({
53
- authSessionStore: createInMemoryAuthSessionStore(),
54
- providersConfiguration: {
62
+ export const absoluteAuthConfig = () =>
63
+ defineAuthConfig<User>({
64
+ authSessionStore: createInMemoryAuthSessionStore(),
65
+ /* Without a database there is nowhere to persist users, so no user is
66
+ ever registered and this resolver has nothing to look a subject up in.
67
+ Scaffold with a database to persist users and resolve them here. */
68
+ getUser: () => null,
69
+ providersConfiguration: {
55
70
  ${providerConfigs}
56
- }
57
- });
71
+ }
72
+ });
58
73
  `;
59
74
  }
60
75
  return `import { getEnv } from '@absolutejs/absolute';
61
76
  import {
62
- AbsoluteAuthProps,
63
77
  createInMemoryAuthSessionStore,
78
+ defineAuthConfig,
64
79
  extractPropFromIdentity,
65
- instantiateUserSession,
66
- providers
80
+ instantiateUserSession
67
81
  } from '@absolutejs/auth';
68
82
  import { DatabaseType, User } from '../../types/databaseTypes';
69
83
  import { createUser, getUser } from '../handlers/userHandlers';
70
84
 
71
- export const absoluteAuthConfig = (
72
- db: DatabaseType
73
- ): AbsoluteAuthProps<User> => ({
85
+ export const absoluteAuthConfig = (db: DatabaseType) =>
86
+ defineAuthConfig<User>({
74
87
  authSessionStore: createInMemoryAuthSessionStore(),
88
+ getUser: async (sub) => (await getUser(db, sub)) ?? null,
75
89
  providersConfiguration: {
76
90
  ${providerConfigs}
77
91
  },
92
+ /* \`providerConfiguration\` is handed to the callback rather than looked up by
93
+ name, so identity extraction also works for custom providers. */
78
94
  onCallbackSuccess: async ({
79
95
  authProvider,
96
+ providerConfiguration,
80
97
  providerInstance,
81
98
  tokenResponse,
82
99
  unregisteredSession,
@@ -86,6 +103,7 @@ ${providerConfigs}
86
103
  }) =>
87
104
  instantiateUserSession({
88
105
  authProvider,
106
+ providerConfiguration,
89
107
  providerInstance,
90
108
  session,
91
109
  tokenResponse,
@@ -93,7 +111,6 @@ ${providerConfigs}
93
111
  user_session_id,
94
112
  getUser: async (userIdentity) => {
95
113
  const provider = authProvider.toUpperCase();
96
- const providerConfiguration = providers[authProvider];
97
114
 
98
115
  const subject = extractPropFromIdentity(
99
116
  userIdentity,
@@ -116,7 +133,6 @@ ${providerConfigs}
116
133
  },
117
134
  onNewUser: async (userIdentity) => {
118
135
  const provider = authProvider.toUpperCase();
119
- const providerConfiguration = providers[authProvider];
120
136
 
121
137
  const subject = extractPropFromIdentity(
122
138
  userIdentity,
@@ -10,8 +10,9 @@ export const generateRoutesBlock = ({ databaseEngine, frontendDirectories, authO
10
10
  return status(error.code, error.message);
11
11
  }
12
12
 
13
- const providerConfiguration =
14
- auth_client.value && providers[auth_client.value as ProviderOption];
13
+ const providerConfiguration = auth_client.value
14
+ ? providers[auth_client.value as ProviderOption]
15
+ : undefined;
15
16
 
16
17
  return ${handlerCall};
17
18
  }`
@@ -36,11 +36,8 @@ export const generateServerFile = ({ tailwind, authOption, plugins, buildDirecto
36
36
  .filter((pluginImport) => pluginImport.isPlugin &&
37
37
  pluginImport.packageName !== 'networking')
38
38
  .map((pluginImport) => {
39
- if (pluginImport.packageName === 'absoluteAuth') {
40
- const hasDatabase = databaseEngine !== undefined && databaseEngine !== 'none';
41
- return hasDatabase
42
- ? `.use(absoluteAuth(absoluteAuthConfig(db)))`
43
- : `.use(absoluteAuth(absoluteAuthConfig()))`;
39
+ if (pluginImport.packageName === 'auth') {
40
+ return `.use(authPlugin)`;
44
41
  }
45
42
  if (pluginImport.config === undefined) {
46
43
  return `.use(${pluginImport.packageName})`;
@@ -63,10 +60,16 @@ export const generateServerFile = ({ tailwind, authOption, plugins, buildDirecto
63
60
  databaseEngine,
64
61
  frontendDirectories
65
62
  });
63
+ 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
+ const authBlock = authOption === 'abs'
67
+ ? `const authPlugin = auth(absoluteAuthConfig(${hasDatabase ? 'db' : ''}))\n`
68
+ : '';
66
69
  const content = `${importsBlock}
67
70
 
68
71
  ${manifestBlock}
69
- ${dbBlock ? `${dbBlock}\n` : ''}
72
+ ${dbBlock ? `${dbBlock}\n` : ''}${authBlock}
70
73
  const server = new Elysia()
71
74
  .use(absolutejs)
72
75
  ${useBlock}${authOption === 'abs' ? `\n${guardBlock}` : ''}
@@ -0,0 +1,7 @@
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
+ 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";
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
+ export declare const scaffoldAgentic: ({ backendDirectory, projectName }: {
5
+ backendDirectory: string;
6
+ projectName: string;
7
+ }) => void;