@beignet/cli 0.0.1

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 ADDED
@@ -0,0 +1,5 @@
1
+ # @beignet/cli
2
+
3
+ ## 0.0.1
4
+
5
+ - Initial Beignet release under the `@beignet` npm scope.
package/README.md ADDED
@@ -0,0 +1,409 @@
1
+ # @beignet/cli
2
+
3
+ Command-line tools for creating and maintaining Beignet apps.
4
+
5
+ ## Create an app
6
+
7
+ ```bash
8
+ bunx -p @beignet/cli beignet create my-app
9
+ ```
10
+
11
+ Or use the package binary directly:
12
+
13
+ ```bash
14
+ bunx -p @beignet/cli create-beignet my-app
15
+ ```
16
+
17
+ By default the CLI creates a Next.js app with:
18
+
19
+ - Contract-first todos API routes
20
+ - App-owned ports and in-memory infra adapters
21
+ - Validated application use cases
22
+ - A Beignet server wired through Next.js route handlers
23
+ - App error helpers, auth helpers, env validation, health checks, and devtools
24
+ - A typed client
25
+ - TanStack Query
26
+ - React Hook Form
27
+ - OpenAPI output
28
+
29
+ The CLI writes files only. After creation:
30
+
31
+ ```bash
32
+ cd my-app
33
+ bun install
34
+ cp .env.example .env.local
35
+ bun run dev
36
+ ```
37
+
38
+ Common follow-up commands:
39
+
40
+ ```bash
41
+ # in another terminal, from my-app
42
+ bunx -p @beignet/cli beignet make resource projects
43
+ bunx -p @beignet/cli beignet routes
44
+ bunx -p @beignet/cli beignet lint
45
+ bunx -p @beignet/cli beignet doctor
46
+ ```
47
+
48
+ ## Options
49
+
50
+ ```bash
51
+ beignet create <directory> [options]
52
+ beignet make contract <name> [options]
53
+ beignet make event <feature>/<name> [options]
54
+ beignet make job <feature>/<name> [options]
55
+ beignet make listener <feature>/<name> --event <feature>/<event> [options]
56
+ beignet make schedule <feature>/<name> [options]
57
+ beignet make port <name> [options]
58
+ beignet make policy <name> [options]
59
+ beignet make adapter <name> [options]
60
+ beignet make resource <name> [options]
61
+ beignet make test <feature>/<action> [options]
62
+ beignet make use-case <feature>/<action> [options]
63
+ beignet routes [--json]
64
+ beignet lint [--json]
65
+ beignet doctor [--json] [--strict] [--fix]
66
+
67
+ Options:
68
+ --template next Template to use. Currently only `next`.
69
+ --preset standard `minimal` or `standard`.
70
+ --package-manager bun Package manager shown in next steps.
71
+ --feature react-query Add a starter feature. Repeatable.
72
+ --features client,openapi Add features from a comma-separated list.
73
+ --integration inngest Add an integration. Repeatable.
74
+ --integrations inngest,pino Add integrations from a comma-separated list.
75
+ --force Write into a non-empty directory.
76
+ --dry-run Preview make writes without changing files.
77
+ --json Print machine-readable output.
78
+ --event posts/published Event for `make listener`.
79
+ --cron "0 9 * * *" Cron expression for `make schedule`.
80
+ --timezone America/Chicago Timezone for `make schedule`.
81
+ --route Add a Next.js cron route for `make schedule`.
82
+ --strict Include CI-oriented doctor warnings and fail on warnings.
83
+ --fix Apply low-risk doctor fixes before reporting.
84
+ -h, --help Show help.
85
+ ```
86
+
87
+ ## App conventions
88
+
89
+ Beignet CLI commands are convention-aware. `routes`, `lint`, `doctor`, and
90
+ generators work best in the Next.js layout created by `beignet create`:
91
+
92
+ ```txt
93
+ features/
94
+ app/api/
95
+ server/index.ts
96
+ server/routes.ts
97
+ ```
98
+
99
+ Route inspection supports contract-group definitions and direct
100
+ `createContract({ method, path })` exports.
101
+
102
+ The standard app layout includes the files resource generators expect:
103
+
104
+ ```txt
105
+ app-context.ts
106
+ infra/app-ports.ts
107
+ ports/index.ts
108
+ lib/use-case.ts
109
+ ```
110
+
111
+ Generated apps include these files by default. The CLI uses this shape to
112
+ inspect routes, wire generated resources, and report drift safely. `beignet
113
+ doctor` reports when a directory does not match the app layout.
114
+
115
+ Use `beignet.config.ts`, `beignet.config.js`,
116
+ `beignet.config.mjs`, or `beignet.config.json` when your app keeps
117
+ the same architecture under different paths:
118
+
119
+ ```ts
120
+ // beignet.config.ts
121
+ import { defineConfig } from "@beignet/cli/config";
122
+
123
+ export default defineConfig({
124
+ paths: {
125
+ contracts: "src/features",
126
+ features: "src/features",
127
+ routes: "src/app/api",
128
+ server: "src/core/server/index.ts",
129
+ },
130
+ });
131
+ ```
132
+
133
+ Config values are optional overrides. Omitted paths fall back to the generated
134
+ defaults. `routes`, `lint`, `doctor`, and make generators all load the same resolved
135
+ config before inspecting or writing files.
136
+
137
+ ## Generate a contract
138
+
139
+ Use `make contract` when you want to start with the HTTP contract only:
140
+
141
+ ```bash
142
+ beignet make contract projects
143
+ ```
144
+
145
+ The command honors `beignet.config.*` path overrides and writes
146
+ `features/projects/contracts.ts`. It creates a self-contained contract group with a
147
+ starter list endpoint, schema, standard error response, and exported contract
148
+ list. It does not wire route handlers, use cases, ports, or OpenAPI; use
149
+ `make resource` when you want the full path from contract to tests.
150
+
151
+ Like `make resource`, `make contract` skips identical files and stops on
152
+ divergent files unless you pass `--force`.
153
+
154
+ ## Generate a use case
155
+
156
+ Use `make use-case` inside a Beignet app when you want a focused
157
+ application workflow without generating HTTP contracts or ports:
158
+
159
+ ```bash
160
+ beignet make use-case projects/archive-project
161
+ ```
162
+
163
+ The name uses `feature/action` format. The command writes
164
+ `features/projects/use-cases/archive-project.ts` and creates or updates
165
+ `features/projects/use-cases/index.ts`. Read-style actions that start with `get`, `list`,
166
+ `find`, `search`, or `count` generate `.query(...)`; other actions generate
167
+ `.command(...)`.
168
+
169
+ ## Generate a test
170
+
171
+ Use `make test` after generating a use case:
172
+
173
+ ```bash
174
+ beignet make use-case projects/archive-project
175
+ beignet make test projects/archive-project
176
+ ```
177
+
178
+ The command writes `features/projects/tests/archive-project.test.ts`, builds the
179
+ app context through `createUseCaseTester`, and asserts the starter
180
+ `{ ok: true }` response. It also adds a `test` script when the app does not
181
+ already define one. Treat the output as a compiling starting point: replace the
182
+ input, context setup, and assertion with behavior-specific coverage as the use
183
+ case grows.
184
+
185
+ ## Generate a port
186
+
187
+ Use `make port` inside a Beignet app when a use case needs a new
188
+ application boundary:
189
+
190
+ ```bash
191
+ beignet make port email
192
+ ```
193
+
194
+ The command writes `ports/email.ts`, adds the port to `AppPorts`, creates a
195
+ small fake adapter for tests, and wires a throwing infra stub so the app still
196
+ typechecks until you replace it with a real port adapter. The generated port
197
+ starts with a generic `execute` method; rename it to the domain operation your
198
+ use case needs.
199
+
200
+ ## Generate a policy
201
+
202
+ Use `make policy` when repeated authorization rules need a named home:
203
+
204
+ ```bash
205
+ beignet make policy posts
206
+ ```
207
+
208
+ The command writes `features/posts/policy.ts` with a `definePolicy(...)` starter.
209
+ Register the policy with `createGate(...)`, install the gate as a port, and
210
+ bind it into request context so use cases can call `ctx.gate.authorize(...)`.
211
+ For tenant, ownership, or role-heavy rules, add a matrix test with
212
+ `createPolicyTester(...)` from `@beignet/core/ports/testing`.
213
+
214
+ ## Generate a port adapter
215
+
216
+ Use `make adapter` after generating a port when you are ready to replace the
217
+ generated throwing stub with a concrete infra implementation.
218
+
219
+ ```bash
220
+ beignet make port email
221
+ beignet make adapter email
222
+ ```
223
+
224
+ The command writes `infra/email/email-adapter.ts` and replaces the generated
225
+ inline infra stub with `email: createEmailAdapter()`. The adapter still
226
+ throws by default; replace its implementation with real infrastructure code
227
+ while keeping use cases behind the port interface. If the infra wiring
228
+ was already customized, the command stops instead of guessing.
229
+
230
+ ## Generate a resource
231
+
232
+ Inside a Beignet app, scaffold a new vertical slice with:
233
+
234
+ ```bash
235
+ beignet make resource projects
236
+ ```
237
+
238
+ The command honors `beignet.config.*` path overrides. It writes:
239
+
240
+ - `features/projects/contracts.ts`
241
+ - `features/projects/use-cases/`
242
+ - `features/projects/ports.ts`
243
+ - `infra/projects/in-memory-project-repository.ts`
244
+ - `features/projects/routes.ts`
245
+ - `features/projects/tests/projects.test.ts`
246
+
247
+ It also wires the resource into the central route registry (`server/routes.ts`
248
+ in generated apps), `ports/index.ts`, `infra/app-ports.ts`, and adds a `test`
249
+ script if the app does not already have one. Apps that serve OpenAPI from
250
+ `server.contracts` or `contractsFromRoutes(routes)` stay in sync through the
251
+ registered route list. Legacy direct `createOpenAPIHandler([...])` arrays are
252
+ updated conservatively when possible.
253
+
254
+ In apps created with the `drizzle-turso` integration, the command also creates
255
+ `infra/db/schema/projects.ts`,
256
+ `infra/projects/drizzle-project-repository.ts`, and registers the repository in
257
+ `infra/db/repositories.ts`. The in-memory repository remains available as a test
258
+ fake.
259
+
260
+ The generated resource uses a small `name` field by default so the app stays
261
+ typecheckable immediately. Rename the fields in the generated schemas,
262
+ repository, and tests to match your domain.
263
+
264
+ ## Generate events, jobs, listeners, and schedules
265
+
266
+ Use feature artifact generators when a workflow grows beyond a single use case:
267
+
268
+ ```bash
269
+ beignet make event posts/published
270
+ beignet make job posts/send-published-email
271
+ beignet make listener posts/enqueue-published-email --event posts/published
272
+ beignet make schedule posts/daily-summary --cron "0 9 * * *" --timezone America/Chicago --route
273
+ ```
274
+
275
+ These commands use `feature/name` format and write colocated feature files:
276
+
277
+ - `features/posts/domain/events/published.ts`
278
+ - `features/posts/jobs/send-published-email.ts`
279
+ - `features/posts/listeners/enqueue-published-email.ts`
280
+ - `features/posts/schedules/daily-summary.ts`
281
+
282
+ Each command creates or updates the folder's `index.ts` with an exported
283
+ registry such as `postJobs`, `postListeners`, or `postSchedules`. Event and
284
+ listener generators add `@beignet/core/events`, job generators add
285
+ `@beignet/core/jobs`, and schedule
286
+ generators add `@beignet/core/schedules`; `--route` also writes a Next.js cron
287
+ route under `app/api/cron/<feature>/<name>/route.ts`. Generated cron routes
288
+ require `CRON_SECRET` and record schedule start, completion, and failure events
289
+ in devtools.
290
+
291
+ `make listener` expects the event file to exist at the canonical generated path.
292
+ Run `make event <feature>/<event>` first, then generate listeners for that event.
293
+
294
+ `make resource` is idempotent for unchanged generated files: repeated runs skip
295
+ identical files and avoid duplicate wiring. If a generated file exists with
296
+ different content, the command stops unless you pass `--force`.
297
+
298
+ Preview writes without changing files:
299
+
300
+ ```bash
301
+ beignet make resource projects --dry-run
302
+ ```
303
+
304
+ Use JSON output when another tool needs the exact planned changes:
305
+
306
+ ```bash
307
+ beignet make resource projects --dry-run --json
308
+ ```
309
+
310
+ ## Inspect app routes
311
+
312
+ Inside an app, list the contracts the CLI can match to Next.js route handlers:
313
+
314
+ ```bash
315
+ beignet routes
316
+ ```
317
+
318
+ Use JSON output when you want to feed the route catalog into another tool:
319
+
320
+ ```bash
321
+ beignet routes --json
322
+ ```
323
+
324
+ ## Lint app architecture
325
+
326
+ Run `lint` when you want the CLI to enforce Beignet dependency direction:
327
+
328
+ ```bash
329
+ beignet lint
330
+ ```
331
+
332
+ The command scans static imports and fails when core feature layers reach into
333
+ runtime or framework layers. It catches domain, use case, policy, port,
334
+ contract, and route files importing things like `infra/`, UI components,
335
+ client modules, provider packages, Next.js, React, or database vendors in the
336
+ wrong direction.
337
+
338
+ Use JSON output in CI or custom scripts:
339
+
340
+ ```bash
341
+ beignet lint --json
342
+ ```
343
+
344
+ ## Check for drift
345
+
346
+ Run `doctor` when you want quick feedback on contract wiring drift:
347
+
348
+ ```bash
349
+ beignet doctor
350
+ ```
351
+
352
+ Today it detects:
353
+
354
+ - Contracts without a matching Next.js route handler
355
+ - Feature route groups that are not registered in the central route list
356
+ - Next.js route handlers that do not map to known contracts
357
+ - OpenAPI drift in direct arrays and common exported contract lists
358
+ - Partially wired generated resource slices
359
+ - Provider packages without matching canonical app ports
360
+ - Generated ports without test fakes
361
+
362
+ Use `beignet doctor --strict` for CI-oriented checks that may be noisy
363
+ locally, such as missing generated resource tests. Use
364
+ `beignet doctor --json` in CI or custom scripts.
365
+
366
+ Use `beignet doctor --fix` for low-risk maintenance fixes. Today it can add
367
+ a missing `test` script and repair direct `createOpenAPIHandler([...])` arrays
368
+ when the missing contracts are already imported in the OpenAPI route.
369
+
370
+ Available presets:
371
+
372
+ - `minimal` - choose this when you want the small contract/core/server/use-case loop without the full app conventions.
373
+ - `standard` - choose this when you want the full app layout with app errors, env validation, devtools, provider wiring, health checks, and separated `ports/` + `infra/`.
374
+
375
+ Integrations are orthogonal to presets. Add only the services you want:
376
+
377
+ ```bash
378
+ bunx -p @beignet/cli beignet create my-app --preset standard --integrations drizzle-turso,inngest,resend
379
+ ```
380
+
381
+ Available features:
382
+
383
+ - `client`
384
+ - `react-query`
385
+ - `forms`
386
+ - `openapi`
387
+
388
+ Available integrations:
389
+
390
+ - `better-auth`
391
+ - `drizzle-turso`
392
+ - `inngest`
393
+ - `pino`
394
+ - `resend`
395
+ - `upstash-rate-limit`
396
+
397
+ With `--preset standard`, `drizzle-turso` also scaffolds `infra/db/schema/`, `infra/db/repositories.ts`, a Drizzle todo repository adapter, `drizzle.config.ts`, database scripts, and `TURSO_*` env examples so the generated todo resource uses durable persistence instead of the in-memory repository. Later `make resource` calls in that app generate both a Drizzle table/repository and an in-memory test fake.
398
+
399
+ With `--preset standard`, the starter includes a provider-neutral `AuthPort`,
400
+ anonymous auth adapter, typed `UNAUTHORIZED` and `FORBIDDEN` errors, a
401
+ request-bound authorization gate, and `requireUser(ctx)`. Use hooks for HTTP
402
+ boundary authentication and use cases or policies for business authorization.
403
+ The `better-auth` integration adds dependencies and setup notes, then you
404
+ replace the anonymous adapter once your app has a real Better Auth
405
+ session/database setup.
406
+
407
+ ## License
408
+
409
+ MIT
@@ -0,0 +1,31 @@
1
+ export type BeignetFramework = "next";
2
+ export type BeignetPaths = {
3
+ contracts: string;
4
+ routes: string;
5
+ server: string;
6
+ openapiRoute: string;
7
+ appContext: string;
8
+ ports: string;
9
+ infrastructurePorts: string;
10
+ features: string;
11
+ policies: string;
12
+ useCases: string;
13
+ useCaseBuilder: string;
14
+ tests: string;
15
+ };
16
+ export type BeignetConfig = {
17
+ framework?: BeignetFramework;
18
+ paths?: Partial<BeignetPaths>;
19
+ };
20
+ export type ResolvedBeignetConfig = {
21
+ framework: BeignetFramework;
22
+ paths: BeignetPaths;
23
+ configFile?: string;
24
+ };
25
+ export declare const defaultBeignetConfig: ResolvedBeignetConfig;
26
+ export declare function defineConfig(config: BeignetConfig): BeignetConfig;
27
+ export declare function resolveConfig(config?: BeignetConfig, configFile?: string): ResolvedBeignetConfig;
28
+ export declare function loadBeignetConfig(targetDir: string, files?: string[]): Promise<ResolvedBeignetConfig>;
29
+ export declare function normalizePath(filePath: string): string;
30
+ export declare function directoryPath(filePath: string): string;
31
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEtC,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,YAAY,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,qBAgBlC,CAAC;AAEF,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAEjE;AAED,wBAAgB,aAAa,CAC3B,MAAM,GAAE,aAAkB,EAC1B,UAAU,CAAC,EAAE,MAAM,GAClB,qBAAqB,CAWvB;AAED,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,MAAM,EAAE,GACf,OAAO,CAAC,qBAAqB,CAAC,CA+ChC;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD"}
package/dist/config.js ADDED
@@ -0,0 +1,131 @@
1
+ import { readFile, stat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { createJiti } from "jiti";
5
+ export const defaultBeignetConfig = {
6
+ framework: "next",
7
+ paths: {
8
+ contracts: "features",
9
+ routes: "app/api",
10
+ server: "server/index.ts",
11
+ openapiRoute: "app/api/openapi/route.ts",
12
+ appContext: "app-context.ts",
13
+ ports: "ports/index.ts",
14
+ infrastructurePorts: "infra/app-ports.ts",
15
+ features: "features",
16
+ policies: "features",
17
+ useCases: "features",
18
+ useCaseBuilder: "lib/use-case.ts",
19
+ tests: "tests",
20
+ },
21
+ };
22
+ export function defineConfig(config) {
23
+ return config;
24
+ }
25
+ export function resolveConfig(config = {}, configFile) {
26
+ const paths = {
27
+ ...defaultBeignetConfig.paths,
28
+ ...config.paths,
29
+ };
30
+ return {
31
+ framework: config.framework ?? defaultBeignetConfig.framework,
32
+ paths: normalizeConfigPaths(paths),
33
+ configFile,
34
+ };
35
+ }
36
+ export async function loadBeignetConfig(targetDir, files) {
37
+ const configFiles = await findConfigFiles(targetDir, files);
38
+ if (configFiles.length === 0) {
39
+ return resolveConfig();
40
+ }
41
+ if (configFiles.length > 1) {
42
+ throw new Error(`Multiple Beignet config files found: ${configFiles.join(", ")}. Keep only one config file.`);
43
+ }
44
+ const configFile = configFiles[0];
45
+ const configPath = path.join(targetDir, configFile);
46
+ if (configFile.endsWith(".json")) {
47
+ try {
48
+ const config = JSON.parse(await readFile(configPath, "utf8"));
49
+ return resolveConfig(assertConfigObject(config, configFile), configFile);
50
+ }
51
+ catch (error) {
52
+ if (error instanceof SyntaxError) {
53
+ throw new Error(`Invalid JSON in ${configFile}: ${error.message}`);
54
+ }
55
+ throw error;
56
+ }
57
+ }
58
+ if (configFile.endsWith(".ts")) {
59
+ const jiti = createJiti(import.meta.url);
60
+ const config = await jiti.import(configPath, {
61
+ default: true,
62
+ });
63
+ return resolveConfig(assertConfigObject(config, configFile), configFile);
64
+ }
65
+ const configModule = (await import(pathToFileURL(configPath).href));
66
+ return resolveConfig(assertConfigObject(configModule.default ?? {}, configFile), configFile);
67
+ }
68
+ export function normalizePath(filePath) {
69
+ return filePath.split(path.sep).join("/");
70
+ }
71
+ export function directoryPath(filePath) {
72
+ return normalizePath(filePath).replaceAll(/^\/+|\/+$/g, "");
73
+ }
74
+ const configFileNames = [
75
+ "beignet.config.ts",
76
+ "beignet.config.json",
77
+ "beignet.config.mjs",
78
+ "beignet.config.js",
79
+ ];
80
+ async function findConfigFiles(targetDir, files) {
81
+ if (files) {
82
+ return configFileNames.filter((file) => files.includes(file));
83
+ }
84
+ const found = [];
85
+ for (const file of configFileNames) {
86
+ try {
87
+ const stats = await stat(path.join(targetDir, file));
88
+ if (stats.isFile())
89
+ found.push(file);
90
+ }
91
+ catch {
92
+ // Missing config candidates are expected.
93
+ }
94
+ }
95
+ return found;
96
+ }
97
+ function assertConfigObject(config, configFile) {
98
+ if (!isRecord(config)) {
99
+ throw new Error(`${configFile} must export a Beignet config object.`);
100
+ }
101
+ if (config.framework !== undefined && config.framework !== "next") {
102
+ throw new Error(`${configFile} uses unsupported framework "${String(config.framework)}". Supported framework: "next".`);
103
+ }
104
+ if (config.paths !== undefined && !isRecord(config.paths)) {
105
+ throw new Error(`${configFile} paths must be an object.`);
106
+ }
107
+ return config;
108
+ }
109
+ function normalizeConfigPaths(paths) {
110
+ return Object.fromEntries(Object.entries(paths).map(([key, value]) => [
111
+ key,
112
+ normalizeConfigPath(key, value),
113
+ ]));
114
+ }
115
+ function normalizeConfigPath(key, value) {
116
+ if (typeof value !== "string" || value.trim() === "") {
117
+ throw new Error(`Beignet config path "${key}" must be a string.`);
118
+ }
119
+ if (path.isAbsolute(value)) {
120
+ throw new Error(`Beignet config path "${key}" must be relative to the project root: ${value}`);
121
+ }
122
+ const normalized = path.posix.normalize(normalizePath(value.trim()));
123
+ if (normalized === ".." || normalized.startsWith("../")) {
124
+ throw new Error(`Beignet config path "${key}" must stay inside the project root: ${value}`);
125
+ }
126
+ return directoryPath(normalized);
127
+ }
128
+ function isRecord(value) {
129
+ return typeof value === "object" && value !== null && !Array.isArray(value);
130
+ }
131
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=create-bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-bin.d.ts","sourceRoot":"","sources":["../src/create-bin.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import { main } from "./index.js";
3
+ const inputs = process.argv.slice(2);
4
+ const normalizedInputs = inputs[0] === "create" ? inputs : ["create", ...inputs];
5
+ main(normalizedInputs).catch((error) => {
6
+ console.error(error instanceof Error ? error.message : String(error));
7
+ process.exitCode = 1;
8
+ });
9
+ //# sourceMappingURL=create-bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-bin.js","sourceRoot":"","sources":["../src/create-bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAElC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACrC,MAAM,gBAAgB,GACpB,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,MAAM,CAAC,CAAC;AAE1D,IAAI,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9C,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { type FeatureName, type IntegrationName, type PackageManager, type PresetName, type TemplateName } from "./templates.js";
2
+ export type CreateOptions = {
3
+ name: string;
4
+ cwd?: string;
5
+ template?: TemplateName;
6
+ preset?: PresetName;
7
+ features?: FeatureName[];
8
+ packageManager?: PackageManager;
9
+ integrations?: IntegrationName[];
10
+ force?: boolean;
11
+ beignetVersion?: string;
12
+ };
13
+ export type CreateResult = {
14
+ name: string;
15
+ targetDir: string;
16
+ files: string[];
17
+ packageManager: PackageManager;
18
+ };
19
+ export declare function createProject(options: CreateOptions): Promise<CreateResult>;
20
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,WAAW,EAGhB,KAAK,eAAe,EAEpB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;IACzB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,YAAY,CAAC,EAAE,eAAe,EAAE,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,cAAc,EAAE,cAAc,CAAC;CAChC,CAAC;AAEF,wBAAsB,aAAa,CACjC,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,YAAY,CAAC,CAwCvB"}