create-absolutejs 0.13.5 → 0.13.7
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/initializeGit.d.ts +9 -1
- package/dist/commands/initializeGit.js +46 -2
- package/dist/generators/configurations/generatePackageJson.d.ts +2 -1
- package/dist/generators/configurations/generatePackageJson.js +11 -2
- package/dist/generators/db/generateDatabaseTypes.d.ts +3 -2
- package/dist/generators/db/generateDatabaseTypes.js +106 -1
- package/dist/generators/db/generateRelationalSchema.d.ts +3 -0
- package/dist/generators/db/generateRelationalSchema.js +52 -0
- package/dist/generators/db/handlerTemplates.js +1 -0
- package/dist/generators/db/scaffoldDatabase.js +27 -1
- package/dist/generators/project/generateDBBlock.js +4 -1
- package/dist/generators/project/generateImportsBlock.js +4 -1
- package/dist/generators/react/generateReactComponents.js +1 -1
- package/dist/prompt.js +23 -0
- package/dist/questions/githubLink.d.ts +7 -0
- package/dist/questions/githubLink.js +84 -0
- package/dist/scaffold.d.ts +1 -1
- package/dist/scaffold.js +8 -2
- package/dist/typeGuards.d.ts +2 -1
- package/dist/typeGuards.js +1 -0
- package/dist/types.d.ts +4 -0
- package/dist/utils/github.d.ts +16 -0
- package/dist/utils/github.js +41 -0
- package/dist/utils/parseCommandLineOptions.js +14 -1
- package/dist/versions.d.ts +1 -1
- package/dist/versions.js +1 -1
- package/package.json +2 -2
|
@@ -1 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import type { GithubLinkOption } from '../types';
|
|
2
|
+
type InitializeGitProps = {
|
|
3
|
+
projectName: string;
|
|
4
|
+
githubLink: GithubLinkOption;
|
|
5
|
+
githubRepoUrl: string | undefined;
|
|
6
|
+
githubVisibility: 'public' | 'private' | undefined;
|
|
7
|
+
};
|
|
8
|
+
export declare const initializeGit: ({ projectName, githubLink, githubRepoUrl, githubVisibility }: InitializeGitProps) => Promise<void>;
|
|
9
|
+
export {};
|
|
@@ -1,7 +1,45 @@
|
|
|
1
|
+
import { basename } from 'path';
|
|
1
2
|
import { spinner } from '@clack/prompts';
|
|
2
3
|
import { $ } from 'bun';
|
|
3
|
-
import { green, red } from 'picocolors';
|
|
4
|
-
|
|
4
|
+
import { dim, green, red, yellow } from 'picocolors';
|
|
5
|
+
const note = (message) => console.log(`${dim('│')} ${yellow('▲')} ${message}`);
|
|
6
|
+
const connectExistingRepo = async (projectName, repoUrl) => {
|
|
7
|
+
const spin = spinner();
|
|
8
|
+
spin.start(`Connecting to ${repoUrl}…`);
|
|
9
|
+
await $ `git remote add origin ${`${repoUrl}.git`}`
|
|
10
|
+
.cwd(projectName)
|
|
11
|
+
.quiet()
|
|
12
|
+
.nothrow();
|
|
13
|
+
const push = await $ `git push -u origin main`
|
|
14
|
+
.cwd(projectName)
|
|
15
|
+
.quiet()
|
|
16
|
+
.nothrow();
|
|
17
|
+
if (push.exitCode === 0) {
|
|
18
|
+
spin.stop(green(`Pushed to ${repoUrl}`));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
spin.stop(yellow(`Added remote ${repoUrl}, but the push didn't complete`));
|
|
22
|
+
note('Finish it manually with: git push -u origin main');
|
|
23
|
+
};
|
|
24
|
+
const createGithubRepo = async (projectName, visibility, repoUrl) => {
|
|
25
|
+
const repoName = basename(projectName);
|
|
26
|
+
const label = repoUrl ?? repoName;
|
|
27
|
+
const visibilityFlag = visibility === 'public' ? '--public' : '--private';
|
|
28
|
+
const spin = spinner();
|
|
29
|
+
spin.start(`Creating ${visibility} repository ${label} on GitHub…`);
|
|
30
|
+
const res = await $ `gh repo create ${repoName} ${visibilityFlag} --source=. --remote=origin --push`
|
|
31
|
+
.cwd(projectName)
|
|
32
|
+
.quiet()
|
|
33
|
+
.nothrow();
|
|
34
|
+
if (res.exitCode === 0) {
|
|
35
|
+
spin.stop(green(`Created and pushed ${label}`));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
spin.stop(red('Failed to create the GitHub repository'));
|
|
39
|
+
note(res.stderr.toString().trim() || 'gh repo create failed');
|
|
40
|
+
note('Create it manually, then: git remote add origin <url> && git push -u origin main');
|
|
41
|
+
};
|
|
42
|
+
export const initializeGit = async ({ projectName, githubLink, githubRepoUrl, githubVisibility }) => {
|
|
5
43
|
const spin = spinner();
|
|
6
44
|
try {
|
|
7
45
|
spin.start('Initializing git repository…');
|
|
@@ -14,4 +52,10 @@ export const initializeGit = async (projectName) => {
|
|
|
14
52
|
spin.cancel(red('Failed to initialize git'));
|
|
15
53
|
throw err;
|
|
16
54
|
}
|
|
55
|
+
if (githubLink === 'existing' && githubRepoUrl) {
|
|
56
|
+
await connectExistingRepo(projectName, githubRepoUrl);
|
|
57
|
+
}
|
|
58
|
+
else if (githubLink === 'create' && githubVisibility) {
|
|
59
|
+
await createGithubRepo(projectName, githubVisibility, githubRepoUrl);
|
|
60
|
+
}
|
|
17
61
|
};
|
|
@@ -2,6 +2,7 @@ import type { CreateConfiguration } from '../../types';
|
|
|
2
2
|
type CreatePackageJsonProps = Pick<CreateConfiguration, 'authOption' | 'useTailwind' | 'databaseEngine' | 'databaseHost' | 'plugins' | 'orm' | 'frontendDirectories' | 'codeQualityTool'> & {
|
|
3
3
|
projectName: string;
|
|
4
4
|
latest: boolean;
|
|
5
|
+
repositoryUrl: string | undefined;
|
|
5
6
|
};
|
|
6
|
-
export declare const createPackageJson: ({ projectName, authOption, plugins, databaseEngine, orm, databaseHost, useTailwind, latest, frontendDirectories, codeQualityTool }: CreatePackageJsonProps) => Promise<void>;
|
|
7
|
+
export declare const createPackageJson: ({ projectName, authOption, plugins, databaseEngine, orm, databaseHost, useTailwind, latest, frontendDirectories, codeQualityTool, repositoryUrl }: CreatePackageJsonProps) => Promise<void>;
|
|
7
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 }) => {
|
|
19
|
+
export const createPackageJson = async ({ 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 ─────────── */
|
|
@@ -250,7 +250,16 @@ export const createPackageJson = async ({ projectName, authOption, plugins, data
|
|
|
250
250
|
name: projectName,
|
|
251
251
|
scripts,
|
|
252
252
|
type: 'module',
|
|
253
|
-
version: '0.0.0'
|
|
253
|
+
version: '0.0.0',
|
|
254
|
+
// When the project is linked to a GitHub repo, ship the standard npm
|
|
255
|
+
// support metadata up front so the package never reads as incomplete.
|
|
256
|
+
...(repositoryUrl
|
|
257
|
+
? {
|
|
258
|
+
bugs: { url: `${repositoryUrl}/issues` },
|
|
259
|
+
homepage: repositoryUrl,
|
|
260
|
+
repository: { type: 'git', url: `${repositoryUrl}.git` }
|
|
261
|
+
}
|
|
262
|
+
: {})
|
|
254
263
|
};
|
|
255
264
|
writeFileSync(join(projectName, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
256
265
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { AuthOption, DatabaseEngine, DatabaseHost } from '../../types';
|
|
1
|
+
import { AuthOption, DatabaseEngine, DatabaseHost, ORM } from '../../types';
|
|
2
2
|
type GenerateTypesProps = {
|
|
3
3
|
databaseEngine: DatabaseEngine;
|
|
4
4
|
databaseHost: DatabaseHost;
|
|
5
5
|
authOption: AuthOption;
|
|
6
|
+
orm?: ORM;
|
|
6
7
|
};
|
|
7
|
-
export declare const generateDatabaseTypes: ({ databaseEngine, databaseHost, authOption }: GenerateTypesProps) => string;
|
|
8
|
+
export declare const generateDatabaseTypes: ({ databaseEngine, databaseHost, authOption, orm }: GenerateTypesProps) => string;
|
|
8
9
|
export {};
|
|
@@ -1,5 +1,110 @@
|
|
|
1
1
|
import { isDrizzleDialect } from '../../typeGuards';
|
|
2
|
-
|
|
2
|
+
// Driver type used as `DatabaseType` on the raw-SQL (no-ORM) path. Keyed by
|
|
3
|
+
// `${engine}:${host}` where host is 'none' for a locally-hosted engine. These
|
|
4
|
+
// MUST stay in sync with the `dbType` values in handlerTemplates.ts and the
|
|
5
|
+
// `const db = ...` expression in generateDBBlock.ts, otherwise the generated
|
|
6
|
+
// handler's `db` parameter type won't match the value the server constructs.
|
|
7
|
+
const SQL_DRIVER_TYPES = {
|
|
8
|
+
'cockroachdb:none': {
|
|
9
|
+
importLine: `import type { SQL } from 'bun';`,
|
|
10
|
+
typeName: 'SQL'
|
|
11
|
+
},
|
|
12
|
+
'gel:none': {
|
|
13
|
+
importLine: `import type { Client } from 'gel';`,
|
|
14
|
+
typeName: 'Client'
|
|
15
|
+
},
|
|
16
|
+
'mariadb:none': {
|
|
17
|
+
importLine: `import type { SQL } from 'bun';`,
|
|
18
|
+
typeName: 'SQL'
|
|
19
|
+
},
|
|
20
|
+
'mongodb:none': {
|
|
21
|
+
importLine: `import type { Db } from 'mongodb';`,
|
|
22
|
+
typeName: 'Db'
|
|
23
|
+
},
|
|
24
|
+
'mssql:none': {
|
|
25
|
+
importLine: `import type { ConnectionPool } from 'mssql';`,
|
|
26
|
+
typeName: 'ConnectionPool'
|
|
27
|
+
},
|
|
28
|
+
'mysql:none': {
|
|
29
|
+
importLine: `import type { SQL } from 'bun';`,
|
|
30
|
+
typeName: 'SQL'
|
|
31
|
+
},
|
|
32
|
+
'mysql:planetscale': {
|
|
33
|
+
importLine: `import type { Client } from '@planetscale/database';`,
|
|
34
|
+
typeName: 'Client'
|
|
35
|
+
},
|
|
36
|
+
'postgresql:neon': {
|
|
37
|
+
importLine: `import type { Pool } from '@neondatabase/serverless';`,
|
|
38
|
+
typeName: 'Pool'
|
|
39
|
+
},
|
|
40
|
+
'postgresql:none': {
|
|
41
|
+
importLine: `import type { SQL } from 'bun';`,
|
|
42
|
+
typeName: 'SQL'
|
|
43
|
+
},
|
|
44
|
+
'postgresql:planetscale': {
|
|
45
|
+
importLine: `import type { Pool } from 'pg';`,
|
|
46
|
+
typeName: 'Pool'
|
|
47
|
+
},
|
|
48
|
+
'singlestore:none': {
|
|
49
|
+
importLine: `import type { Pool } from 'mysql2/promise';`,
|
|
50
|
+
typeName: 'Pool'
|
|
51
|
+
},
|
|
52
|
+
'sqlite:none': {
|
|
53
|
+
importLine: `import type { Database } from 'bun:sqlite';`,
|
|
54
|
+
typeName: 'Database'
|
|
55
|
+
},
|
|
56
|
+
'sqlite:turso': {
|
|
57
|
+
importLine: `import type { Client } from '@libsql/client';`,
|
|
58
|
+
typeName: 'Client'
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
// Raw-SQL (no-ORM) `databaseTypes.ts`. The drizzle path infers User/NewUser
|
|
62
|
+
// from the schema's `$inferSelect`/`$inferInsert`; without an ORM there is no
|
|
63
|
+
// schema module, so we hand-roll types that mirror the columns emitted by
|
|
64
|
+
// generateSqliteSchema / the relational DDL. Returns rows are untyped at the
|
|
65
|
+
// driver level, so these are the source of truth for consumers (auth config,
|
|
66
|
+
// handlers, the example page).
|
|
67
|
+
const generateSqlDatabaseTypes = ({ databaseEngine, databaseHost, authOption }) => {
|
|
68
|
+
const host = databaseHost && databaseHost !== 'none' ? databaseHost : 'none';
|
|
69
|
+
const driver = SQL_DRIVER_TYPES[`${databaseEngine}:${host}`];
|
|
70
|
+
const driverImport = driver ? `${driver.importLine}\n` : '';
|
|
71
|
+
const databaseTypeLine = driver
|
|
72
|
+
? `export type DatabaseType = ${driver.typeName};`
|
|
73
|
+
: 'export type DatabaseType = unknown;';
|
|
74
|
+
const entityTypes = authOption === 'abs'
|
|
75
|
+
? `export type User = {
|
|
76
|
+
auth_sub: string;
|
|
77
|
+
created_at: Date;
|
|
78
|
+
metadata: Record<string, unknown>;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export type NewUser = {
|
|
82
|
+
auth_sub: string;
|
|
83
|
+
metadata?: Record<string, unknown>;
|
|
84
|
+
};`
|
|
85
|
+
: `export type CountHistory = {
|
|
86
|
+
uid: number;
|
|
87
|
+
count: number;
|
|
88
|
+
created_at: Date;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export type NewCountHistory = {
|
|
92
|
+
count: number;
|
|
93
|
+
};`;
|
|
94
|
+
return `${driverImport}
|
|
95
|
+
${databaseTypeLine}
|
|
96
|
+
|
|
97
|
+
${entityTypes}
|
|
98
|
+
`;
|
|
99
|
+
};
|
|
100
|
+
export const generateDatabaseTypes = ({ databaseEngine, databaseHost, authOption, orm }) => {
|
|
101
|
+
if (orm !== 'drizzle') {
|
|
102
|
+
return generateSqlDatabaseTypes({
|
|
103
|
+
authOption,
|
|
104
|
+
databaseEngine,
|
|
105
|
+
databaseHost
|
|
106
|
+
});
|
|
107
|
+
}
|
|
3
108
|
let dbImport = '';
|
|
4
109
|
let dbTypeLine = '';
|
|
5
110
|
if (databaseHost === 'neon') {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const DIALECTS = {
|
|
2
|
+
cockroachdb: {
|
|
3
|
+
json: 'JSONB',
|
|
4
|
+
pk: 'INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY',
|
|
5
|
+
string: 'VARCHAR(255)',
|
|
6
|
+
timestamp: 'TIMESTAMP NOT NULL DEFAULT now()'
|
|
7
|
+
},
|
|
8
|
+
mariadb: {
|
|
9
|
+
json: 'JSON',
|
|
10
|
+
pk: 'INT AUTO_INCREMENT PRIMARY KEY',
|
|
11
|
+
string: 'VARCHAR(255)',
|
|
12
|
+
timestamp: 'TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP'
|
|
13
|
+
},
|
|
14
|
+
mysql: {
|
|
15
|
+
json: 'JSON',
|
|
16
|
+
pk: 'INT AUTO_INCREMENT PRIMARY KEY',
|
|
17
|
+
string: 'VARCHAR(255)',
|
|
18
|
+
timestamp: 'TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP'
|
|
19
|
+
},
|
|
20
|
+
postgresql: {
|
|
21
|
+
json: 'JSONB',
|
|
22
|
+
pk: 'INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY',
|
|
23
|
+
string: 'VARCHAR(255)',
|
|
24
|
+
timestamp: 'TIMESTAMP NOT NULL DEFAULT now()'
|
|
25
|
+
},
|
|
26
|
+
singlestore: {
|
|
27
|
+
json: 'JSON',
|
|
28
|
+
pk: 'INT AUTO_INCREMENT PRIMARY KEY',
|
|
29
|
+
string: 'VARCHAR(255)',
|
|
30
|
+
timestamp: 'TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP'
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
export const supportsRelationalSchema = (engine) => engine !== undefined && engine in DIALECTS;
|
|
34
|
+
export const generateRelationalSchema = (databaseEngine, authOption) => {
|
|
35
|
+
if (databaseEngine === undefined || !(databaseEngine in DIALECTS)) {
|
|
36
|
+
throw new Error(`Internal error: no relational DDL for engine "${databaseEngine}"`);
|
|
37
|
+
}
|
|
38
|
+
const d = DIALECTS[databaseEngine];
|
|
39
|
+
return authOption === 'abs'
|
|
40
|
+
? `CREATE TABLE IF NOT EXISTS users (
|
|
41
|
+
auth_sub ${d.string} PRIMARY KEY,
|
|
42
|
+
created_at ${d.timestamp},
|
|
43
|
+
metadata ${d.json} DEFAULT ('{}')
|
|
44
|
+
);
|
|
45
|
+
`
|
|
46
|
+
: `CREATE TABLE IF NOT EXISTS count_history (
|
|
47
|
+
uid ${d.pk},
|
|
48
|
+
count INT NOT NULL,
|
|
49
|
+
created_at ${d.timestamp}
|
|
50
|
+
);
|
|
51
|
+
`;
|
|
52
|
+
};
|
|
@@ -7,6 +7,7 @@ export const getUser = async (db: DatabaseType, authSub: string) => {
|
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
export const createUser = async (db: DatabaseType, newUserData: NewUser) => {
|
|
10
|
+
const { auth_sub: authSub, metadata: userIdentity } = newUserData;
|
|
10
11
|
${queries.insertUser}
|
|
11
12
|
}`;
|
|
12
13
|
const buildSqlCountTemplate = ({ importLines, dbType, queries }) => `
|
|
@@ -8,6 +8,7 @@ import { createDrizzleConfig } from '../configurations/generateDrizzleConfig';
|
|
|
8
8
|
import { generateDatabaseTypes } from './generateDatabaseTypes';
|
|
9
9
|
import { generateDrizzleSchema } from './generateDrizzleSchema';
|
|
10
10
|
import { generateDBHandlers } from './generateHandlers';
|
|
11
|
+
import { generateRelationalSchema, supportsRelationalSchema } from './generateRelationalSchema';
|
|
11
12
|
import { generateSqliteSchema } from './generateSqliteSchema';
|
|
12
13
|
import { scaffoldDocker } from './scaffoldDocker';
|
|
13
14
|
export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHost, databaseDirectory, backendDirectory, authOption, orm, typesDirectory }) => {
|
|
@@ -26,6 +27,30 @@ export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHo
|
|
|
26
27
|
usesAuth
|
|
27
28
|
});
|
|
28
29
|
writeFileSync(join(handlerDirectory, handlerFileName), dbHandlers, 'utf-8');
|
|
30
|
+
// Raw-SQL (no-ORM) auth handlers import `DatabaseType`/`NewUser` from
|
|
31
|
+
// types/databaseTypes (so do the auth config and the example page), but
|
|
32
|
+
// the drizzle-backed type module below is only written on the drizzle
|
|
33
|
+
// path. Generate a self-contained, driver-typed version here so the
|
|
34
|
+
// non-drizzle auth scaffold actually type-checks and builds.
|
|
35
|
+
if (usesAuth && orm !== 'drizzle') {
|
|
36
|
+
mkdirSync(typesDirectory, { recursive: true });
|
|
37
|
+
const sqlTypes = generateDatabaseTypes({
|
|
38
|
+
authOption,
|
|
39
|
+
databaseEngine,
|
|
40
|
+
databaseHost,
|
|
41
|
+
orm
|
|
42
|
+
});
|
|
43
|
+
writeFileSync(join(typesDirectory, 'databaseTypes.ts'), sqlTypes);
|
|
44
|
+
}
|
|
45
|
+
// Hosted relational engines on the raw-SQL path get no migration tooling
|
|
46
|
+
// (no drizzle-kit, no local sqlite3). Emit a plain DDL file so the tables
|
|
47
|
+
// the handlers query can be created against the hosted database.
|
|
48
|
+
const isRemoteHost = databaseHost !== undefined && databaseHost !== 'none';
|
|
49
|
+
if (isRemoteHost &&
|
|
50
|
+
orm !== 'drizzle' &&
|
|
51
|
+
supportsRelationalSchema(databaseEngine)) {
|
|
52
|
+
writeFileSync(join(projectDatabaseDirectory, 'schema.sql'), generateRelationalSchema(databaseEngine, authOption));
|
|
53
|
+
}
|
|
29
54
|
if (databaseEngine === 'sqlite') {
|
|
30
55
|
void ((orm === undefined || orm === 'none') &&
|
|
31
56
|
(await checkSqliteInstalled()));
|
|
@@ -58,7 +83,8 @@ export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHo
|
|
|
58
83
|
const drizzleTypes = generateDatabaseTypes({
|
|
59
84
|
authOption,
|
|
60
85
|
databaseEngine,
|
|
61
|
-
databaseHost
|
|
86
|
+
databaseHost,
|
|
87
|
+
orm
|
|
62
88
|
});
|
|
63
89
|
writeFileSync(join(typesDirectory, 'databaseTypes.ts'), drizzleTypes);
|
|
64
90
|
return { dockerFreshInstall: false };
|
|
@@ -20,8 +20,11 @@ const connectionMap = {
|
|
|
20
20
|
planetscale: { expr: 'new Client({ url: getEnv("DATABASE_URL") })' }
|
|
21
21
|
},
|
|
22
22
|
postgresql: {
|
|
23
|
+
// Raw-SQL (no-ORM) neon uses the driver's `Pool`, whose `.query(text,
|
|
24
|
+
// params)` → `{ rows }` API matches the generated handler. The drizzle
|
|
25
|
+
// path is handled separately below and still uses `neon()` http.
|
|
23
26
|
neon: {
|
|
24
|
-
expr: '
|
|
27
|
+
expr: 'new Pool({ connectionString: getEnv("DATABASE_URL") })'
|
|
25
28
|
},
|
|
26
29
|
none: { expr: 'new SQL(getEnv("DATABASE_URL"))' },
|
|
27
30
|
planetscale: {
|
|
@@ -107,7 +107,10 @@ export const generateImportsBlock = ({ deps, flags, orm, authOption, databaseEng
|
|
|
107
107
|
const getPostgresqlNoOrmImports = () => {
|
|
108
108
|
if (isRemoteHost && databaseHost === 'neon')
|
|
109
109
|
return [
|
|
110
|
-
...
|
|
110
|
+
// No-ORM neon constructs `new Pool(...)` (see generateDBBlock),
|
|
111
|
+
// whose `.query()` API matches the generated SQL handler. The
|
|
112
|
+
// `neon()` http client is only used on the drizzle path.
|
|
113
|
+
`import { Pool } from '@neondatabase/serverless'`,
|
|
111
114
|
`import { getEnv } from '@absolutejs/absolute'`
|
|
112
115
|
];
|
|
113
116
|
if (isRemoteHost && databaseHost === 'planetscale')
|
|
@@ -122,7 +122,7 @@ export const generateReactExamplePage = (authOption) => {
|
|
|
122
122
|
: `<Dropdown />`;
|
|
123
123
|
const closing = authOption === 'abs' ? `};` : `);`;
|
|
124
124
|
return `
|
|
125
|
-
${authOption === 'abs' ? `import { User } from '../../../types/databaseTypes';\nimport { extractPropFromIdentity
|
|
125
|
+
${authOption === 'abs' ? `import type { User } from '../../../types/databaseTypes';\nimport { extractPropFromIdentity } from '@absolutejs/auth';\nimport type { ProviderConfiguration } from '@absolutejs/auth';` : ''}
|
|
126
126
|
import { App } from '../components/App';
|
|
127
127
|
import { Dropdown } from '../components/Dropdown';
|
|
128
128
|
import { Head } from '../components/Head';
|
package/dist/prompt.js
CHANGED
|
@@ -6,6 +6,7 @@ import { getDatabaseHost } from './questions/databaseHost';
|
|
|
6
6
|
import { getDirectoryConfiguration } from './questions/directoryConfiguration';
|
|
7
7
|
import { getFrontendDirectoryConfigurations } from './questions/frontendDirectoryConfigurations';
|
|
8
8
|
import { getFrontends } from './questions/frontends';
|
|
9
|
+
import { getGithubLink } from './questions/githubLink';
|
|
9
10
|
import { getHtmlScriptingOption } from './questions/htmlScriptingOption';
|
|
10
11
|
import { getInitializeGit } from './questions/initializeGitNow';
|
|
11
12
|
import { getInstallDependencies } from './questions/installDependenciesNow';
|
|
@@ -56,6 +57,25 @@ export const prompt = async (argumentConfiguration) => {
|
|
|
56
57
|
const plugins = argumentConfiguration.plugins?.filter((plugin) => plugin !== undefined) ?? (await getPlugins());
|
|
57
58
|
// 14. Initialize Git repository
|
|
58
59
|
const initializeGitNow = argumentConfiguration.initializeGitNow ?? (await getInitializeGit());
|
|
60
|
+
// 14b. Optionally connect the new project to GitHub
|
|
61
|
+
const resolveGithubLink = async () => {
|
|
62
|
+
if (!initializeGitNow) {
|
|
63
|
+
return {
|
|
64
|
+
githubLink: 'skip',
|
|
65
|
+
githubRepoUrl: undefined,
|
|
66
|
+
githubVisibility: undefined
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (argumentConfiguration.githubLink) {
|
|
70
|
+
return {
|
|
71
|
+
githubLink: argumentConfiguration.githubLink,
|
|
72
|
+
githubRepoUrl: argumentConfiguration.githubRepoUrl,
|
|
73
|
+
githubVisibility: argumentConfiguration.githubVisibility
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return getGithubLink(projectName);
|
|
77
|
+
};
|
|
78
|
+
const { githubLink, githubRepoUrl, githubVisibility } = await resolveGithubLink();
|
|
59
79
|
// 15. Install dependencies
|
|
60
80
|
const installDependenciesNow = argumentConfiguration.installDependenciesNow ??
|
|
61
81
|
(await getInstallDependencies());
|
|
@@ -71,6 +91,9 @@ export const prompt = async (argumentConfiguration) => {
|
|
|
71
91
|
directoryConfig,
|
|
72
92
|
frontendDirectories,
|
|
73
93
|
frontends,
|
|
94
|
+
githubLink,
|
|
95
|
+
githubRepoUrl,
|
|
96
|
+
githubVisibility,
|
|
74
97
|
initializeGitNow,
|
|
75
98
|
installDependenciesNow,
|
|
76
99
|
orm,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { GithubLinkOption } from '../types';
|
|
2
|
+
export type GithubLinkResult = {
|
|
3
|
+
githubLink: GithubLinkOption;
|
|
4
|
+
githubRepoUrl: string | undefined;
|
|
5
|
+
githubVisibility: 'public' | 'private' | undefined;
|
|
6
|
+
};
|
|
7
|
+
export declare const getGithubLink: (projectName: string) => Promise<GithubLinkResult>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { basename } from 'path';
|
|
2
|
+
import { isCancel, select, text } from '@clack/prompts';
|
|
3
|
+
import { dim, yellow } from 'picocolors';
|
|
4
|
+
import { abort } from '../utils/abort';
|
|
5
|
+
import { getGhLogin, hasGh, isGhAuthenticated, normalizeRepoInput } from '../utils/github';
|
|
6
|
+
const SKIP = {
|
|
7
|
+
githubLink: 'skip',
|
|
8
|
+
githubRepoUrl: undefined,
|
|
9
|
+
githubVisibility: undefined
|
|
10
|
+
};
|
|
11
|
+
const warn = (message) => console.log(`${dim('│')}\n${yellow('▲')} ${message}`);
|
|
12
|
+
const linkExistingRepo = async () => {
|
|
13
|
+
const entered = await text({
|
|
14
|
+
message: 'Repository (owner/name or full GitHub URL):',
|
|
15
|
+
placeholder: 'your-org/your-repo',
|
|
16
|
+
validate: (value) => normalizeRepoInput(value)
|
|
17
|
+
? undefined
|
|
18
|
+
: 'Enter owner/name or a github.com URL'
|
|
19
|
+
});
|
|
20
|
+
if (isCancel(entered))
|
|
21
|
+
abort();
|
|
22
|
+
const result = {
|
|
23
|
+
githubLink: 'existing',
|
|
24
|
+
githubRepoUrl: normalizeRepoInput(entered)?.httpsUrl,
|
|
25
|
+
githubVisibility: undefined
|
|
26
|
+
};
|
|
27
|
+
return result;
|
|
28
|
+
};
|
|
29
|
+
const createNewRepo = async (projectName) => {
|
|
30
|
+
if (!(await hasGh())) {
|
|
31
|
+
warn('GitHub CLI (gh) not found — skipping GitHub setup. Install it from https://cli.github.com, then push manually.');
|
|
32
|
+
return SKIP;
|
|
33
|
+
}
|
|
34
|
+
if (!(await isGhAuthenticated())) {
|
|
35
|
+
warn('GitHub CLI is not authenticated — run `gh auth login`, then re-run. Skipping GitHub setup.');
|
|
36
|
+
return SKIP;
|
|
37
|
+
}
|
|
38
|
+
const login = await getGhLogin();
|
|
39
|
+
if (!login) {
|
|
40
|
+
warn("Couldn't resolve your GitHub account — skipping GitHub setup.");
|
|
41
|
+
return SKIP;
|
|
42
|
+
}
|
|
43
|
+
const repoName = basename(projectName);
|
|
44
|
+
const visibility = await select({
|
|
45
|
+
message: `Visibility for github.com/${login}/${repoName}:`,
|
|
46
|
+
options: [
|
|
47
|
+
{ label: 'Private', value: 'private' },
|
|
48
|
+
{ label: 'Public', value: 'public' }
|
|
49
|
+
]
|
|
50
|
+
});
|
|
51
|
+
if (isCancel(visibility))
|
|
52
|
+
abort();
|
|
53
|
+
const result = {
|
|
54
|
+
githubLink: 'create',
|
|
55
|
+
githubRepoUrl: `https://github.com/${login}/${repoName}`,
|
|
56
|
+
githubVisibility: visibility === 'public' ? 'public' : 'private'
|
|
57
|
+
};
|
|
58
|
+
return result;
|
|
59
|
+
};
|
|
60
|
+
export const getGithubLink = async (projectName) => {
|
|
61
|
+
const choice = await select({
|
|
62
|
+
message: 'Connect this project to GitHub?',
|
|
63
|
+
options: [
|
|
64
|
+
{
|
|
65
|
+
hint: 'set the remote to a repo you already own',
|
|
66
|
+
label: 'Link an existing repository',
|
|
67
|
+
value: 'existing'
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
hint: 'create one for you with the GitHub CLI',
|
|
71
|
+
label: 'Create a new repository',
|
|
72
|
+
value: 'create'
|
|
73
|
+
},
|
|
74
|
+
{ label: 'Skip', value: 'skip' }
|
|
75
|
+
]
|
|
76
|
+
});
|
|
77
|
+
if (isCancel(choice))
|
|
78
|
+
abort();
|
|
79
|
+
if (choice === 'existing')
|
|
80
|
+
return linkExistingRepo();
|
|
81
|
+
if (choice === 'create')
|
|
82
|
+
return createNewRepo(projectName);
|
|
83
|
+
return SKIP;
|
|
84
|
+
};
|
package/dist/scaffold.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ type ScaffoldProps = {
|
|
|
5
5
|
latest: boolean;
|
|
6
6
|
envVariables: string[] | undefined;
|
|
7
7
|
};
|
|
8
|
-
export declare const scaffold: ({ response: { projectName, codeQualityTool, initializeGitNow, databaseEngine, databaseHost, useHTMLScripts, useTailwind, databaseDirectory, absProviders, orm, frontends, plugins, authOption, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, envVariables, packageManager }: ScaffoldProps) => Promise<{
|
|
8
|
+
export declare const scaffold: ({ response: { projectName, codeQualityTool, initializeGitNow, githubLink, githubRepoUrl, githubVisibility, databaseEngine, databaseHost, useHTMLScripts, useTailwind, databaseDirectory, absProviders, orm, frontends, plugins, authOption, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, envVariables, packageManager }: ScaffoldProps) => Promise<{
|
|
9
9
|
dockerFreshInstall: boolean;
|
|
10
10
|
}>;
|
|
11
11
|
export {};
|
package/dist/scaffold.js
CHANGED
|
@@ -10,7 +10,7 @@ import { scaffoldConfigurationFiles } from './generators/configurations/scaffold
|
|
|
10
10
|
import { scaffoldDatabase } from './generators/db/scaffoldDatabase';
|
|
11
11
|
import { scaffoldBackend } from './generators/project/scaffoldBackend';
|
|
12
12
|
import { scaffoldFrontends } from './generators/project/scaffoldFrontends';
|
|
13
|
-
export const scaffold = async ({ response: { projectName, codeQualityTool, initializeGitNow, databaseEngine, databaseHost, useHTMLScripts, useTailwind, databaseDirectory, absProviders, orm, frontends, plugins, authOption, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, envVariables, packageManager }) => {
|
|
13
|
+
export const scaffold = async ({ response: { projectName, codeQualityTool, initializeGitNow, githubLink, githubRepoUrl, githubVisibility, databaseEngine, databaseHost, useHTMLScripts, useTailwind, databaseDirectory, absProviders, orm, frontends, plugins, authOption, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, envVariables, packageManager }) => {
|
|
14
14
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
15
|
const templatesDirectory = join(__dirname, '/templates');
|
|
16
16
|
const { frontendDirectory, backendDirectory, projectAssetsDirectory, typesDirectory } = initalizeRoot(projectName, templatesDirectory);
|
|
@@ -36,6 +36,7 @@ export const scaffold = async ({ response: { projectName, codeQualityTool, initi
|
|
|
36
36
|
orm,
|
|
37
37
|
plugins,
|
|
38
38
|
projectName,
|
|
39
|
+
repositoryUrl: githubRepoUrl,
|
|
39
40
|
useTailwind
|
|
40
41
|
});
|
|
41
42
|
scaffoldBackend({
|
|
@@ -102,7 +103,12 @@ export const server = treaty<Server>(serverUrl)
|
|
|
102
103
|
projectName
|
|
103
104
|
});
|
|
104
105
|
if (initializeGitNow) {
|
|
105
|
-
await initializeGit(
|
|
106
|
+
await initializeGit({
|
|
107
|
+
githubLink,
|
|
108
|
+
githubRepoUrl,
|
|
109
|
+
githubVisibility,
|
|
110
|
+
projectName
|
|
111
|
+
});
|
|
106
112
|
}
|
|
107
113
|
return { dockerFreshInstall };
|
|
108
114
|
};
|
package/dist/typeGuards.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type { AuthOption, AvailableDrizzleDialect, CodeQualityTool, DatabaseEngine, DatabaseHost, Frontend, ORM } from './types';
|
|
1
|
+
import type { AuthOption, AvailableDrizzleDialect, CodeQualityTool, DatabaseEngine, DatabaseHost, Frontend, GithubLinkOption, ORM } from './types';
|
|
2
2
|
export declare const isCodeQualityTool: (value: string | undefined) => value is CodeQualityTool;
|
|
3
3
|
export declare const isDatabaseEngine: (value: string | undefined) => value is DatabaseEngine;
|
|
4
4
|
export declare const isDatabaseHost: (value: string | undefined) => value is DatabaseHost;
|
|
5
5
|
export declare const isDirectoryConfig: (value: string) => value is "default" | "custom";
|
|
6
6
|
export declare const isDrizzleDialect: (value: string | undefined) => value is AvailableDrizzleDialect;
|
|
7
7
|
export declare const isFrontend: (value: string | undefined) => value is Frontend;
|
|
8
|
+
export declare const isGithubLinkOption: (value: string | undefined) => value is GithubLinkOption;
|
|
8
9
|
export declare const isORM: (value: string | undefined) => value is ORM;
|
|
9
10
|
export declare const isPrismaDialect: (value: string | undefined) => value is string;
|
|
10
11
|
export declare const isValidAuthOption: (value: string | undefined) => value is AuthOption;
|
package/dist/typeGuards.js
CHANGED
|
@@ -5,6 +5,7 @@ export const isDatabaseHost = (value) => availableDatabaseHosts.some((host) => h
|
|
|
5
5
|
export const isDirectoryConfig = (value) => value === 'default' || value === 'custom';
|
|
6
6
|
export const isDrizzleDialect = (value) => availableDrizzleDialects.some((dialect) => dialect === value);
|
|
7
7
|
export const isFrontend = (value) => value !== undefined && Object.keys(frontendLabels).includes(value);
|
|
8
|
+
export const isGithubLinkOption = (value) => value === 'existing' || value === 'create' || value === 'skip';
|
|
8
9
|
export const isORM = (value) => value === 'drizzle' || value === 'prisma' || value === undefined;
|
|
9
10
|
export const isPrismaDialect = (value) => availablePrismaDialects.some((dialect) => dialect === value);
|
|
10
11
|
export const isValidAuthOption = (value) => value === 'abs' || value === 'none' || value === undefined;
|
package/dist/types.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export type TailwindConfig = {
|
|
|
40
40
|
input: string;
|
|
41
41
|
output: string;
|
|
42
42
|
} | undefined;
|
|
43
|
+
export type GithubLinkOption = 'existing' | 'create' | 'skip';
|
|
43
44
|
export type CreateConfiguration = {
|
|
44
45
|
absProviders: ProviderOption[] | undefined;
|
|
45
46
|
assetsDirectory: string;
|
|
@@ -51,6 +52,9 @@ export type CreateConfiguration = {
|
|
|
51
52
|
frontends: Frontend[];
|
|
52
53
|
useHTMLScripts: boolean;
|
|
53
54
|
initializeGitNow: boolean;
|
|
55
|
+
githubLink: GithubLinkOption;
|
|
56
|
+
githubRepoUrl: string | undefined;
|
|
57
|
+
githubVisibility: 'public' | 'private' | undefined;
|
|
54
58
|
installDependenciesNow: boolean;
|
|
55
59
|
codeQualityTool: CodeQualityTool;
|
|
56
60
|
orm: ORM;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** The authenticated GitHub login, or undefined when it can't be resolved. */
|
|
2
|
+
export declare const getGhLogin: () => Promise<string | undefined>;
|
|
3
|
+
/** True when the GitHub CLI (`gh`) is on the PATH. */
|
|
4
|
+
export declare const hasGh: () => Promise<boolean>;
|
|
5
|
+
/** True when `gh` has an authenticated account. */
|
|
6
|
+
export declare const isGhAuthenticated: () => Promise<boolean>;
|
|
7
|
+
/**
|
|
8
|
+
* Accepts `owner/name`, `https://github.com/owner/name(.git)`, or
|
|
9
|
+
* `git@github.com:owner/name(.git)` and returns a normalized https URL plus
|
|
10
|
+
* the parsed owner/name. Returns undefined when the input isn't recognizable.
|
|
11
|
+
*/
|
|
12
|
+
export declare const normalizeRepoInput: (input: string | undefined) => {
|
|
13
|
+
httpsUrl: string;
|
|
14
|
+
name: string;
|
|
15
|
+
owner: string;
|
|
16
|
+
} | undefined;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { platform } from 'process';
|
|
2
|
+
import { $ } from 'bun';
|
|
3
|
+
/** The authenticated GitHub login, or undefined when it can't be resolved. */
|
|
4
|
+
export const getGhLogin = async () => {
|
|
5
|
+
const res = await $ `gh api user --jq .login`.quiet().nothrow();
|
|
6
|
+
if (res.exitCode !== 0)
|
|
7
|
+
return undefined;
|
|
8
|
+
return res.stdout.toString().trim() || undefined;
|
|
9
|
+
};
|
|
10
|
+
/** True when the GitHub CLI (`gh`) is on the PATH. */
|
|
11
|
+
export const hasGh = async () => (platform === 'win32'
|
|
12
|
+
? await $ `where gh`.quiet().nothrow()
|
|
13
|
+
: await $ `command -v gh`.quiet().nothrow()).exitCode === 0;
|
|
14
|
+
/** True when `gh` has an authenticated account. */
|
|
15
|
+
export const isGhAuthenticated = async () => (await $ `gh auth status`.quiet().nothrow()).exitCode === 0;
|
|
16
|
+
/**
|
|
17
|
+
* Accepts `owner/name`, `https://github.com/owner/name(.git)`, or
|
|
18
|
+
* `git@github.com:owner/name(.git)` and returns a normalized https URL plus
|
|
19
|
+
* the parsed owner/name. Returns undefined when the input isn't recognizable.
|
|
20
|
+
*/
|
|
21
|
+
export const normalizeRepoInput = (input) => {
|
|
22
|
+
const trimmed = (input ?? '').trim().replace(/\.git$/, '');
|
|
23
|
+
const patterns = [
|
|
24
|
+
/^https?:\/\/github\.com\/([^/\s]+)\/([^/\s]+)$/i,
|
|
25
|
+
/^git@github\.com:([^/\s]+)\/([^/\s]+)$/i,
|
|
26
|
+
/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)$/
|
|
27
|
+
];
|
|
28
|
+
for (const pattern of patterns) {
|
|
29
|
+
const match = trimmed.match(pattern);
|
|
30
|
+
const owner = match?.[1];
|
|
31
|
+
const name = match?.[2];
|
|
32
|
+
if (owner && name) {
|
|
33
|
+
return {
|
|
34
|
+
httpsUrl: `https://github.com/${owner}/${name}`,
|
|
35
|
+
name,
|
|
36
|
+
owner
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
};
|
|
@@ -3,7 +3,8 @@ import { parseArgs } from 'util';
|
|
|
3
3
|
import { isValidProviderOption, providers } from '@absolutejs/auth';
|
|
4
4
|
import { DEFAULT_ARG_LENGTH } from '../constants';
|
|
5
5
|
import { availableAuthProviders, availableDatabaseEngines, availableDatabaseHosts, availableDirectoryConfigurations, availableDrizzleDialects, availableORMs, availablePrismaDialects } from '../data';
|
|
6
|
-
import { isValidAuthOption, isDatabaseEngine, isDatabaseHost, isDirectoryConfig, isDrizzleDialect, isORM, isPrismaDialect } from '../typeGuards';
|
|
6
|
+
import { isValidAuthOption, isDatabaseEngine, isDatabaseHost, isDirectoryConfig, isDrizzleDialect, isGithubLinkOption, isORM, isPrismaDialect } from '../typeGuards';
|
|
7
|
+
import { normalizeRepoInput } from './github';
|
|
7
8
|
export const parseCommandLineOptions = () => {
|
|
8
9
|
const { values, positionals } = parseArgs({
|
|
9
10
|
allowNegative: true,
|
|
@@ -25,6 +26,7 @@ export const parseCommandLineOptions = () => {
|
|
|
25
26
|
env: { multiple: true, type: 'string' },
|
|
26
27
|
'eslint+prettier': { type: 'boolean' },
|
|
27
28
|
git: { type: 'boolean' },
|
|
29
|
+
github: { type: 'string' },
|
|
28
30
|
help: { default: false, short: 'h', type: 'boolean' },
|
|
29
31
|
html: { type: 'boolean' },
|
|
30
32
|
'html-dir': { type: 'string' },
|
|
@@ -37,6 +39,8 @@ export const parseCommandLineOptions = () => {
|
|
|
37
39
|
plugin: { multiple: true, type: 'string' },
|
|
38
40
|
react: { type: 'boolean' },
|
|
39
41
|
'react-dir': { type: 'string' },
|
|
42
|
+
repo: { type: 'string' },
|
|
43
|
+
'repo-visibility': { type: 'string' },
|
|
40
44
|
skip: { type: 'boolean' },
|
|
41
45
|
svelte: { type: 'boolean' },
|
|
42
46
|
'svelte-dir': { type: 'string' },
|
|
@@ -232,6 +236,10 @@ export const parseCommandLineOptions = () => {
|
|
|
232
236
|
validEnv.push(entry);
|
|
233
237
|
}
|
|
234
238
|
values.env = validEnv.length ? validEnv : undefined;
|
|
239
|
+
const repoVisibility = values['repo-visibility'];
|
|
240
|
+
const githubVisibility = repoVisibility === 'public' || repoVisibility === 'private'
|
|
241
|
+
? repoVisibility
|
|
242
|
+
: undefined;
|
|
235
243
|
const argumentConfiguration = {
|
|
236
244
|
absProviders: absProviders.length ? absProviders : undefined,
|
|
237
245
|
assetsDirectory: values.assets,
|
|
@@ -244,6 +252,11 @@ export const parseCommandLineOptions = () => {
|
|
|
244
252
|
directoryConfig,
|
|
245
253
|
frontendDirectories,
|
|
246
254
|
frontends: selectedFrontends.length ? selectedFrontends : undefined,
|
|
255
|
+
githubLink: isGithubLinkOption(values.github)
|
|
256
|
+
? values.github
|
|
257
|
+
: undefined,
|
|
258
|
+
githubRepoUrl: normalizeRepoInput(values.repo)?.httpsUrl,
|
|
259
|
+
githubVisibility,
|
|
247
260
|
initializeGitNow: values.git,
|
|
248
261
|
installDependenciesNow: values.install,
|
|
249
262
|
orm,
|
package/dist/versions.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Run `bun run check-versions` to compare against latest npm versions.
|
|
5
5
|
*/
|
|
6
6
|
export declare const versions: {
|
|
7
|
-
readonly '@absolutejs/absolute': "0.19.0-beta.
|
|
7
|
+
readonly '@absolutejs/absolute': "0.19.0-beta.1081";
|
|
8
8
|
readonly '@absolutejs/auth': "0.22.7";
|
|
9
9
|
readonly '@angular/common': "21.2.0";
|
|
10
10
|
readonly '@angular/compiler': "21.2.0";
|
package/dist/versions.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export const versions = {
|
|
7
7
|
/* ── Core ─────────────────────────────────────────────── */
|
|
8
|
-
'@absolutejs/absolute': '0.19.0-beta.
|
|
8
|
+
'@absolutejs/absolute': '0.19.0-beta.1081',
|
|
9
9
|
'@absolutejs/auth': '0.22.7',
|
|
10
10
|
/* ── Angular ─────────────────────────────────────────── */
|
|
11
11
|
'@angular/common': '21.2.0',
|
package/package.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"description": "A CLI tool to create a new AbsoluteJS project",
|
|
12
12
|
"devDependencies": {
|
|
13
|
-
"@absolutejs/absolute": "0.19.0-beta.
|
|
13
|
+
"@absolutejs/absolute": "0.19.0-beta.1081",
|
|
14
14
|
"@eslint/compat": "2.0.2",
|
|
15
15
|
"@stylistic/eslint-plugin": "5.9.0",
|
|
16
16
|
"@types/bun": "1.3.8",
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"typecheck": "bun run tsc --noEmit"
|
|
53
53
|
},
|
|
54
54
|
"type": "module",
|
|
55
|
-
"version": "0.13.
|
|
55
|
+
"version": "0.13.7"
|
|
56
56
|
}
|