@shivaedev/create-app 0.2.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +5 -1
- package/dist/cli.js +72 -72
- package/dist/createApp.d.ts +3 -1
- package/dist/createApp.d.ts.map +1 -1
- package/dist/createApp.js +8 -3
- package/dist/createApp.js.map +1 -1
- package/dist/initializeGit.d.ts +6 -0
- package/dist/initializeGit.d.ts.map +1 -0
- package/dist/initializeGit.js +27 -0
- package/dist/initializeGit.js.map +1 -0
- package/docs/roadmap.md +4 -1
- package/package.json +2 -2
- package/src/cli.ts +5 -3
- package/src/createApp.ts +8 -3
- package/src/initializeGit.ts +34 -0
- package/template.json +1 -1
package/dist/createApp.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Effect, FileSystem, Schema } from "effect";
|
|
2
2
|
import { ChildProcessSpawner } from "effect/process";
|
|
3
3
|
import { CreateAppError } from "./CreateAppError.ts";
|
|
4
|
-
export declare const createApp: (folder: string, templatePath: string
|
|
4
|
+
export declare const createApp: (folder: string, templatePath: string, options: {
|
|
5
|
+
readonly git: boolean;
|
|
6
|
+
}) => Effect.Effect<undefined, CreateAppError | import("effect/PlatformError").PlatformError | Schema.SchemaError, ChildProcessSpawner.ChildProcessSpawner | FileSystem.FileSystem>;
|
|
5
7
|
//# sourceMappingURL=createApp.d.ts.map
|
package/dist/createApp.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createApp.d.ts","sourceRoot":"","sources":["../src/createApp.ts"],"names":[],"mappings":"AAGA,OAAO,EAAW,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAgB,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"createApp.d.ts","sourceRoot":"","sources":["../src/createApp.ts"],"names":[],"mappings":"AAGA,OAAO,EAAW,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAgB,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAMrD,eAAO,MAAM,SAAS;kBAA8G,OAAO;mLA0CzI,CAAC"}
|
package/dist/createApp.js
CHANGED
|
@@ -4,9 +4,10 @@ import { basename, dirname, join, resolve } from "node:path";
|
|
|
4
4
|
import { Console, Effect, FileSystem, Schema } from "effect";
|
|
5
5
|
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
6
6
|
import { CreateAppError } from "./CreateAppError.js";
|
|
7
|
+
import { commitGit, initializeGit } from "./initializeGit.js";
|
|
7
8
|
import { Template } from "./template.js";
|
|
8
9
|
const decodeName = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Record(Schema.String, Schema.Unknown)));
|
|
9
|
-
export const createApp = Effect.fn("CreateApp.createApp")(function* (folder, templatePath) {
|
|
10
|
+
export const createApp = Effect.fn("CreateApp.createApp")(function* (folder, templatePath, options) {
|
|
10
11
|
const fs = yield* FileSystem.FileSystem;
|
|
11
12
|
const target = resolve(folder);
|
|
12
13
|
const name = basename(target);
|
|
@@ -33,10 +34,14 @@ export const createApp = Effect.fn("CreateApp.createApp")(function* (folder, tem
|
|
|
33
34
|
.replace(/^[^a-z]/u, "app_$&")
|
|
34
35
|
.slice(0, 58);
|
|
35
36
|
yield* fs.writeFileString(join(target, ".env.local"), `DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:55432/${database}_dev\nTEST_DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:55432/${database}_test\nBETTER_AUTH_SECRET=${randomBytes(32).toString("base64url")}\n`, { flag: "wx", mode: 0o600 });
|
|
37
|
+
const initialized = options.git && (yield* initializeGit(target));
|
|
36
38
|
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
37
|
-
const code = yield* spawner.exitCode(ChildProcess.make("pnpm", ["
|
|
39
|
+
const code = yield* spawner.exitCode(ChildProcess.make("pnpm", ["run", "setup"], { cwd: target, stderr: "inherit", stdout: "inherit" }));
|
|
38
40
|
if (code !== 0) {
|
|
39
|
-
return yield* new CreateAppError({ message: `pnpm
|
|
41
|
+
return yield* new CreateAppError({ message: `pnpm run setup failed (exit ${code}). Run pnpm run setup in ${folder} to retry.` });
|
|
42
|
+
}
|
|
43
|
+
if (initialized) {
|
|
44
|
+
yield* commitGit(target);
|
|
40
45
|
}
|
|
41
46
|
const quotedFolder = `'${folder.replaceAll("'", "'\"'\"'")}'`;
|
|
42
47
|
yield* Console.log(`Created ${folder}.\n\nNext steps:\n cd ${quotedFolder}\n pnpm dev`);
|
package/dist/createApp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createApp.js","sourceRoot":"","sources":["../src/createApp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,UAAU,GAAG,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAEnH,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAc,EAAE,YAAoB;
|
|
1
|
+
{"version":3,"file":"createApp.js","sourceRoot":"","sources":["../src/createApp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { ChildProcessSpawner } from "effect/process";
|
|
3
|
+
import { CreateAppError } from "./CreateAppError.ts";
|
|
4
|
+
export declare const initializeGit: (cwd: string) => Effect.Effect<boolean, CreateAppError | import("effect/PlatformError").PlatformError, ChildProcessSpawner.ChildProcessSpawner>;
|
|
5
|
+
export declare const commitGit: (cwd: string) => Effect.Effect<void, CreateAppError | import("effect/PlatformError").PlatformError, ChildProcessSpawner.ChildProcessSpawner>;
|
|
6
|
+
//# sourceMappingURL=initializeGit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initializeGit.d.ts","sourceRoot":"","sources":["../src/initializeGit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAgB,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAerD,eAAO,MAAM,aAAa,iJASxB,CAAC;AAEH,eAAO,MAAM,SAAS,8IAKpB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
3
|
+
import { CreateAppError } from "./CreateAppError.js";
|
|
4
|
+
function git(cwd, args, inherit = false) {
|
|
5
|
+
return Effect.flatMap(ChildProcessSpawner.ChildProcessSpawner, (spawner) => spawner.exitCode(ChildProcess.make("git", args, { cwd, stderr: inherit ? "inherit" : "pipe", stdout: inherit ? "inherit" : "pipe" })));
|
|
6
|
+
}
|
|
7
|
+
const checkedGit = Effect.fn("CreateApp.checkedGit")(function* (cwd, args) {
|
|
8
|
+
const code = yield* git(cwd, args, true);
|
|
9
|
+
if (code !== 0) {
|
|
10
|
+
return yield* new CreateAppError({ message: `git ${args.join(" ")} failed (exit ${code}). The generated files remain in ${cwd}.` });
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
export const initializeGit = Effect.fn("CreateApp.initializeGit")(function* (cwd) {
|
|
14
|
+
const available = yield* git(cwd, ["--version"]).pipe(Effect.catch((error) => (error.reason._tag === "NotFound" ? Effect.succeed(-1) : Effect.fail(error))));
|
|
15
|
+
if (available !== 0 || (yield* git(cwd, ["rev-parse", "--git-dir"])) === 0) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
yield* checkedGit(cwd, ["init", "--initial-branch=main"]);
|
|
19
|
+
return true;
|
|
20
|
+
});
|
|
21
|
+
export const commitGit = Effect.fn("CreateApp.commitGit")(function* (cwd) {
|
|
22
|
+
const identity = yield* git(cwd, ["var", "GIT_AUTHOR_IDENT"]);
|
|
23
|
+
const fallback = identity === 0 ? [] : ["-c", "user.name=Create App", "-c", "user.email=create-app@localhost"];
|
|
24
|
+
yield* checkedGit(cwd, ["add", "--all"]);
|
|
25
|
+
yield* checkedGit(cwd, [...fallback, "commit", "-m", "Initialize a generated app"]);
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=initializeGit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initializeGit.js","sourceRoot":"","sources":["../src/initializeGit.ts"],"names":[],"mappings":"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"}
|
package/docs/roadmap.md
CHANGED
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
- Each generated app has a git-ignored local environment with a fresh authentication secret and app-specific development and test database URLs.
|
|
9
9
|
- The generated app prepares both local databases before development and loads its test database URL from the local environment.
|
|
10
10
|
- The published-starter check runs the packed command's output through typecheck, build and PostgreSQL/authenticated HTTP tests.
|
|
11
|
+
- A generated app gets an initial Git commit outside an enclosing repository when Git is available; `--no-git` opts out.
|
|
12
|
+
- Setup installs dependencies and Quality's hook after repository initialization; the initial commit runs lint and typecheck, and `pnpm ready` runs the full local gate.
|
|
13
|
+
- A generated app includes GitHub Actions checks against PostgreSQL and Railway build, migration, start and health-check configuration.
|
|
11
14
|
|
|
12
15
|
## Open questions
|
|
13
16
|
|
|
14
|
-
No
|
|
17
|
+
No open generator decisions.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/create-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Create and install a Platform application from the maintained starter",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/create-app#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@effect/platform-node": "4.0.4",
|
|
43
43
|
"@effect/platform-node-shared": "4.0.4",
|
|
44
|
-
"@shivaedev/quality": "0.
|
|
44
|
+
"@shivaedev/quality": "0.21.1",
|
|
45
45
|
"@types/node": "24.19.1",
|
|
46
46
|
"effect": "4.0.4",
|
|
47
47
|
"esbuild": "0.28.2",
|
package/src/cli.ts
CHANGED
|
@@ -3,15 +3,17 @@ import { fileURLToPath } from "node:url";
|
|
|
3
3
|
import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
|
|
4
4
|
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
5
5
|
import { Console, Effect, FileSystem, Schema } from "effect";
|
|
6
|
-
import { Argument, Command } from "effect/cli";
|
|
6
|
+
import { Argument, Command, Flag } from "effect/cli";
|
|
7
7
|
import { createApp } from "./createApp.ts";
|
|
8
8
|
|
|
9
9
|
const program = Effect.gen(function* () {
|
|
10
10
|
const fs = yield* FileSystem.FileSystem;
|
|
11
11
|
const manifest = yield* fs.readFileString(fileURLToPath(new URL("../package.json", import.meta.url)));
|
|
12
12
|
const { version } = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Struct({ version: Schema.String })))(manifest);
|
|
13
|
-
const cli = Command.make(
|
|
14
|
-
|
|
13
|
+
const cli = Command.make(
|
|
14
|
+
"create-app",
|
|
15
|
+
{ folder: Argument.String("folder"), git: Flag.Boolean("git").pipe(Flag.withDefault(true)) },
|
|
16
|
+
({ folder, git }) => createApp(folder, fileURLToPath(new URL("../template.json", import.meta.url)), { git }),
|
|
15
17
|
).pipe(Command.withDescription("Create and install a Platform application from the maintained starter."));
|
|
16
18
|
yield* Command.run(cli, { version });
|
|
17
19
|
});
|
package/src/createApp.ts
CHANGED
|
@@ -4,11 +4,12 @@ import { basename, dirname, join, resolve } from "node:path";
|
|
|
4
4
|
import { Console, Effect, FileSystem, Schema } from "effect";
|
|
5
5
|
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
6
6
|
import { CreateAppError } from "./CreateAppError.ts";
|
|
7
|
+
import { commitGit, initializeGit } from "./initializeGit.ts";
|
|
7
8
|
import { Template } from "./template.ts";
|
|
8
9
|
|
|
9
10
|
const decodeName = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Record(Schema.String, Schema.Unknown)));
|
|
10
11
|
|
|
11
|
-
export const createApp = Effect.fn("CreateApp.createApp")(function* (folder: string, templatePath: string) {
|
|
12
|
+
export const createApp = Effect.fn("CreateApp.createApp")(function* (folder: string, templatePath: string, options: { readonly git: boolean }) {
|
|
12
13
|
const fs = yield* FileSystem.FileSystem;
|
|
13
14
|
const target = resolve(folder);
|
|
14
15
|
const name = basename(target);
|
|
@@ -39,10 +40,14 @@ export const createApp = Effect.fn("CreateApp.createApp")(function* (folder: str
|
|
|
39
40
|
`DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:55432/${database}_dev\nTEST_DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:55432/${database}_test\nBETTER_AUTH_SECRET=${randomBytes(32).toString("base64url")}\n`,
|
|
40
41
|
{ flag: "wx", mode: 0o600 },
|
|
41
42
|
);
|
|
43
|
+
const initialized = options.git && (yield* initializeGit(target));
|
|
42
44
|
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
43
|
-
const code = yield* spawner.exitCode(ChildProcess.make("pnpm", ["
|
|
45
|
+
const code = yield* spawner.exitCode(ChildProcess.make("pnpm", ["run", "setup"], { cwd: target, stderr: "inherit", stdout: "inherit" }));
|
|
44
46
|
if (code !== 0) {
|
|
45
|
-
return yield* new CreateAppError({ message: `pnpm
|
|
47
|
+
return yield* new CreateAppError({ message: `pnpm run setup failed (exit ${code}). Run pnpm run setup in ${folder} to retry.` });
|
|
48
|
+
}
|
|
49
|
+
if (initialized) {
|
|
50
|
+
yield* commitGit(target);
|
|
46
51
|
}
|
|
47
52
|
const quotedFolder = `'${folder.replaceAll("'", "'\"'\"'")}'`;
|
|
48
53
|
yield* Console.log(`Created ${folder}.\n\nNext steps:\n cd ${quotedFolder}\n pnpm dev`);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
3
|
+
import { CreateAppError } from "./CreateAppError.ts";
|
|
4
|
+
|
|
5
|
+
function git(cwd: string, args: readonly string[], inherit = false) {
|
|
6
|
+
return Effect.flatMap(ChildProcessSpawner.ChildProcessSpawner, (spawner) =>
|
|
7
|
+
spawner.exitCode(ChildProcess.make("git", args, { cwd, stderr: inherit ? "inherit" : "pipe", stdout: inherit ? "inherit" : "pipe" })),
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const checkedGit = Effect.fn("CreateApp.checkedGit")(function* (cwd: string, args: readonly string[]) {
|
|
12
|
+
const code = yield* git(cwd, args, true);
|
|
13
|
+
if (code !== 0) {
|
|
14
|
+
return yield* new CreateAppError({ message: `git ${args.join(" ")} failed (exit ${code}). The generated files remain in ${cwd}.` });
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const initializeGit = Effect.fn("CreateApp.initializeGit")(function* (cwd: string) {
|
|
19
|
+
const available = yield* git(cwd, ["--version"]).pipe(
|
|
20
|
+
Effect.catch((error) => (error.reason._tag === "NotFound" ? Effect.succeed(-1) : Effect.fail(error))),
|
|
21
|
+
);
|
|
22
|
+
if (available !== 0 || (yield* git(cwd, ["rev-parse", "--git-dir"])) === 0) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
yield* checkedGit(cwd, ["init", "--initial-branch=main"]);
|
|
26
|
+
return true;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export const commitGit = Effect.fn("CreateApp.commitGit")(function* (cwd: string) {
|
|
30
|
+
const identity = yield* git(cwd, ["var", "GIT_AUTHOR_IDENT"]);
|
|
31
|
+
const fallback = identity === 0 ? [] : ["-c", "user.name=Create App", "-c", "user.email=create-app@localhost"];
|
|
32
|
+
yield* checkedGit(cwd, ["add", "--all"]);
|
|
33
|
+
yield* checkedGit(cwd, [...fallback, "commit", "-m", "Initialize a generated app"]);
|
|
34
|
+
});
|