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.
- package/dist/commands/formatProject.js +6 -4
- package/dist/data.js +1 -1
- package/dist/generators/configurations/generatePackageJson.d.ts +2 -2
- package/dist/generators/configurations/generatePackageJson.js +52 -1
- package/dist/generators/db/generateDatabaseTypes.js +1 -1
- package/dist/generators/db/handlerTemplates.d.ts +0 -24
- package/dist/generators/db/handlerTemplates.js +26 -31
- package/dist/generators/db/scaffoldDatabase.js +6 -6
- package/dist/generators/project/generateAbsoluteAuthConfig.d.ts +1 -0
- package/dist/generators/project/generateAbsoluteAuthConfig.js +31 -15
- package/dist/generators/project/generateRoutesBlock.js +3 -2
- package/dist/generators/project/generateServer.js +9 -6
- package/dist/generators/project/scaffoldAgentic.d.ts +7 -0
- package/dist/generators/project/scaffoldAgentic.js +181 -0
- package/dist/generators/project/scaffoldBackend.d.ts +2 -1
- package/dist/generators/project/scaffoldBackend.js +10 -2
- package/dist/generators/project/scaffoldFrontends.js +6 -0
- package/dist/generators/react/generateReactComponents.d.ts +1 -1
- package/dist/generators/react/generateReactComponents.js +7 -3
- package/dist/generators/react/scaffoldReact.d.ts +1 -1
- package/dist/generators/react/scaffoldReact.js +9 -4
- package/dist/messages.d.ts +1 -1
- package/dist/messages.js +3 -1
- package/dist/prompt.js +23 -9
- package/dist/questions/agentic.d.ts +1 -0
- package/dist/questions/agentic.js +11 -0
- package/dist/scaffold.d.ts +1 -1
- package/dist/scaffold.js +7 -2
- package/dist/types.d.ts +4 -0
- package/dist/utils/parseCommandLineOptions.js +14 -5
- package/dist/versions.d.ts +24 -4
- package/dist/versions.js +25 -4
- 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
|
|
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 =
|
|
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
|
@@ -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
|
-
|
|
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
|
-
|
|
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:
|
|
31
|
+
export const getCountHistory = async (db: DatabaseType, uid: number) => {
|
|
16
32
|
${queries.selectHistory}
|
|
17
33
|
}
|
|
18
34
|
|
|
19
|
-
export const createCountHistory = async (db:
|
|
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(
|
|
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)
|
|
30
|
-
// types/databaseTypes (so do the auth config and the example
|
|
31
|
-
// the drizzle-backed type module below is only written on the
|
|
32
|
-
// path. Generate a self-contained, driver-typed version here so the
|
|
33
|
-
// non-drizzle
|
|
34
|
-
if (
|
|
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,
|
|
@@ -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
|
-
|
|
49
|
-
|
|
57
|
+
createInMemoryAuthSessionStore,
|
|
58
|
+
defineAuthConfig
|
|
50
59
|
} from '@absolutejs/auth';
|
|
60
|
+
import { User } from '../../types/databaseTypes';
|
|
51
61
|
|
|
52
|
-
export const absoluteAuthConfig = ()
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 === '
|
|
40
|
-
|
|
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;
|