@beignet/cli 0.0.51 → 0.0.53
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 +46 -0
- package/README.md +182 -19
- package/dist/analysis/layers.d.ts +2 -0
- package/dist/analysis/layers.d.ts.map +1 -1
- package/dist/analysis/layers.js +9 -2
- package/dist/analysis/layers.js.map +1 -1
- package/dist/analysis/port-wiring.d.ts +4 -2
- package/dist/analysis/port-wiring.d.ts.map +1 -1
- package/dist/analysis/port-wiring.js +41 -11
- package/dist/analysis/port-wiring.js.map +1 -1
- package/dist/analysis/source-files.d.ts +15 -0
- package/dist/analysis/source-files.d.ts.map +1 -0
- package/dist/analysis/source-files.js +52 -0
- package/dist/analysis/source-files.js.map +1 -0
- package/dist/analysis/source-index.d.ts +2 -1
- package/dist/analysis/source-index.d.ts.map +1 -1
- package/dist/analysis/source-index.js +34 -5
- package/dist/analysis/source-index.js.map +1 -1
- package/dist/analysis/workspace-routes.d.ts +8 -0
- package/dist/analysis/workspace-routes.d.ts.map +1 -0
- package/dist/analysis/workspace-routes.js +291 -0
- package/dist/analysis/workspace-routes.js.map +1 -0
- package/dist/analysis/workspace.d.ts +24 -3
- package/dist/analysis/workspace.d.ts.map +1 -1
- package/dist/analysis/workspace.js +184 -43
- package/dist/analysis/workspace.js.map +1 -1
- package/dist/app-map-changes.d.ts.map +1 -1
- package/dist/app-map-changes.js +24 -14
- package/dist/app-map-changes.js.map +1 -1
- package/dist/app-map.d.ts.map +1 -1
- package/dist/app-map.js +87 -81
- package/dist/app-map.js.map +1 -1
- package/dist/check.d.ts +12 -0
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +92 -25
- package/dist/check.js.map +1 -1
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +19 -0
- package/dist/config.js.map +1 -1
- package/dist/git-changes.d.ts +17 -1
- package/dist/git-changes.d.ts.map +1 -1
- package/dist/git-changes.js +118 -84
- package/dist/git-changes.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -3
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +424 -129
- package/dist/inspect.js.map +1 -1
- package/dist/lint.d.ts.map +1 -1
- package/dist/lint.js +108 -43
- package/dist/lint.js.map +1 -1
- package/dist/make/shared.js +1 -1
- package/dist/make.js +18 -1
- package/dist/make.js.map +1 -1
- package/dist/mcp.js +1 -1
- package/dist/mcp.js.map +1 -1
- package/dist/provider-add.js +2 -2
- package/dist/provider-add.js.map +1 -1
- package/dist/provider-audit.d.ts.map +1 -1
- package/dist/provider-audit.js +22 -6
- package/dist/provider-audit.js.map +1 -1
- package/dist/templates/agents.d.ts.map +1 -1
- package/dist/templates/agents.js +36 -13
- package/dist/templates/agents.js.map +1 -1
- package/dist/templates/base.js +5 -5
- package/dist/templates/db/mysql.d.ts.map +1 -1
- package/dist/templates/db/mysql.js +51 -22
- package/dist/templates/db/mysql.js.map +1 -1
- package/dist/templates/db/postgres.d.ts.map +1 -1
- package/dist/templates/db/postgres.js +60 -20
- package/dist/templates/db/postgres.js.map +1 -1
- package/dist/templates/db/sqlite.d.ts.map +1 -1
- package/dist/templates/db/sqlite.js +51 -23
- package/dist/templates/db/sqlite.js.map +1 -1
- package/dist/templates/shadcn.js +1 -1
- package/dist/templates/shadcn.js.map +1 -1
- package/dist/templates/shared.js +6 -6
- package/dist/templates/shared.js.map +1 -1
- package/dist/templates/testing.d.ts.map +1 -1
- package/dist/templates/testing.js +7 -19
- package/dist/templates/testing.js.map +1 -1
- package/dist/test-discovery.d.ts +9 -0
- package/dist/test-discovery.d.ts.map +1 -0
- package/dist/test-discovery.js +40 -0
- package/dist/test-discovery.js.map +1 -0
- package/package.json +8 -5
- package/skills/app-structure/SKILL.md +74 -7
- package/src/analysis/layers.ts +13 -2
- package/src/analysis/port-wiring.ts +68 -11
- package/src/analysis/source-files.ts +61 -0
- package/src/analysis/source-index.ts +56 -4
- package/src/analysis/workspace-routes.ts +385 -0
- package/src/analysis/workspace.ts +302 -59
- package/src/app-map-changes.ts +41 -13
- package/src/app-map.ts +114 -103
- package/src/check.ts +115 -25
- package/src/config.ts +33 -0
- package/src/git-changes.ts +218 -86
- package/src/index.ts +33 -5
- package/src/inspect.ts +608 -156
- package/src/lint.ts +152 -48
- package/src/make/shared.ts +1 -1
- package/src/make.ts +31 -1
- package/src/mcp.ts +1 -1
- package/src/provider-add.ts +2 -2
- package/src/provider-audit.ts +30 -10
- package/src/templates/agents.ts +36 -13
- package/src/templates/base.ts +5 -5
- package/src/templates/db/mysql.ts +51 -22
- package/src/templates/db/postgres.ts +60 -20
- package/src/templates/db/sqlite.ts +51 -23
- package/src/templates/shadcn.ts +1 -1
- package/src/templates/shared.ts +6 -6
- package/src/templates/testing.ts +12 -19
- package/src/test-discovery.ts +53 -0
package/src/templates/agents.ts
CHANGED
|
@@ -41,8 +41,8 @@ https://beignetjs.com (agent-friendly index at https://beignetjs.com/llms.txt).
|
|
|
41
41
|
README.md covers setup and the app map; this file covers what is not
|
|
42
42
|
discoverable from the code.
|
|
43
43
|
|
|
44
|
-
This app requires Node.js 22.12 or newer. Bun
|
|
45
|
-
Beignet commands.
|
|
44
|
+
This app requires Node.js 22.12 or newer. Bun is optional; npm, pnpm, Yarn, and
|
|
45
|
+
Bun can run Beignet commands.
|
|
46
46
|
|
|
47
47
|
## Registration is explicit
|
|
48
48
|
|
|
@@ -71,6 +71,12 @@ is a silent failure — the file exists but never runs:
|
|
|
71
71
|
- Apps using runtime integrity must list workflow registries in
|
|
72
72
|
\`defineRuntimeManifest({...})\`.
|
|
73
73
|
|
|
74
|
+
Event schemas must output canonical JSON transport data. Use null, strings,
|
|
75
|
+
finite numbers, booleans, arrays, and plain objects. Keep validation
|
|
76
|
+
deterministic and side-effect-free, keep transforms idempotent, and represent
|
|
77
|
+
timestamps as strings or numbers rather than \`Date\` objects.
|
|
78
|
+
Beignet rejects payloads that would change when decoded and validated again.
|
|
79
|
+
|
|
74
80
|
The starter ships no workflow registries — generators create them on first
|
|
75
81
|
use, so their absence is fine. \`${cli} make event\`, \`${cli} make job\`,
|
|
76
82
|
\`${cli} make listener\`, \`${cli} make schedule\`, \`${cli} make task\`,
|
|
@@ -146,20 +152,37 @@ formatting. The individual commands (\`${lint}\`, \`${cli} lint\`,
|
|
|
146
152
|
\`${cli} doctor --strict\`, \`${test}\`, \`${typecheck}\`) still work when you
|
|
147
153
|
need one check alone.
|
|
148
154
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
+
Inside a Git worktree, \`${cli} check\` fingerprints HEAD, the index, the
|
|
156
|
+
worktree, and non-ignored untracked files before and after validation. If the
|
|
157
|
+
ending fingerprint differs from the baseline, the result is stale and
|
|
158
|
+
unsuccessful even when every step passed; rerun the check against the resulting
|
|
159
|
+
source. Outside Git, the same validation runs with source provenance marked
|
|
160
|
+
unavailable; report that limitation instead of describing the result as
|
|
161
|
+
source-current.
|
|
162
|
+
|
|
163
|
+
Beignet's architecture lint parses JavaScript and TypeScript imports and
|
|
164
|
+
re-exports, \`require()\`, import assignments, and literal dynamic imports, then
|
|
165
|
+
follows local value imports through feature-root helpers. This includes JSX
|
|
166
|
+
and the \`.mts\`, \`.cts\`, \`.mjs\`, and \`.cjs\` module variants. When lint
|
|
167
|
+
cannot verify a computed module reference inside a constrained layer, use a
|
|
168
|
+
string-literal specifier or move runtime loading behind an allowed boundary.
|
|
169
|
+
Move near-miss feature layers to the canonical path named in the diagnostic.
|
|
155
170
|
|
|
156
171
|
Before exploring unfamiliar code, run \`${cli} map\` for the human inventory
|
|
157
172
|
or \`${cli} map --json --feature <name>\` for an evidence-backed graph scoped
|
|
158
|
-
to one feature. The graph
|
|
159
|
-
\`
|
|
160
|
-
\`
|
|
161
|
-
|
|
162
|
-
|
|
173
|
+
to one feature. The graph analyzes JavaScript and TypeScript source and honors
|
|
174
|
+
the app's complete \`baseUrl\` and \`paths\` configuration from
|
|
175
|
+
\`tsconfig.json\`, or \`jsconfig.json\` when no TypeScript config exists. Fix
|
|
176
|
+
\`local_import_unresolved\` and \`contract_declaration_unresolved\` entries
|
|
177
|
+
rather than treating their missing edges as proof that no relationship exists.
|
|
178
|
+
Registration diagnostics expose the declaration as \`subject.file\` and
|
|
179
|
+
\`subject.exportName\`.
|
|
180
|
+
|
|
181
|
+
The graph includes JavaScript and TypeScript test/spec files under canonical
|
|
182
|
+
and configured app test roots. Feature tests retain feature ownership;
|
|
183
|
+
adjacent app, infra, server, and top-level tests remain app-level nodes and can
|
|
184
|
+
appear as reverse-import consumers in changed mode. Treat that as impact
|
|
185
|
+
evidence, not proof of behavioral coverage.
|
|
163
186
|
|
|
164
187
|
After editing in a Git worktree, run \`${cli} map --changed\` before the full
|
|
165
188
|
check. It reports direct changes, reverse imports, one-hop semantic consumers,
|
package/src/templates/base.ts
CHANGED
|
@@ -247,8 +247,8 @@ route groups such as \`app/(app)\` are not part of the URL.
|
|
|
247
247
|
|
|
248
248
|
Beignet app scaffolded with \`@beignet/cli\`.
|
|
249
249
|
|
|
250
|
-
Node.js 22.12 or newer is required. Bun
|
|
251
|
-
Beignet commands.
|
|
250
|
+
Node.js 22.12 or newer is required. Bun is optional; npm, pnpm, Yarn, and Bun
|
|
251
|
+
can run Beignet commands.
|
|
252
252
|
|
|
253
253
|
## Getting started
|
|
254
254
|
|
|
@@ -288,9 +288,9 @@ use cases, workflows, ports, providers, and tests connect. \`check\` runs the
|
|
|
288
288
|
whole validation loop in one pass: \`${cli} lint\` (dependency direction),
|
|
289
289
|
\`${cli} doctor --strict\` (route, OpenAPI, and resource drift), and the
|
|
290
290
|
\`lint\`, \`typecheck\`, and \`test\` package scripts. Use \`${format}\` to
|
|
291
|
-
apply Biome formatting. Beignet lint
|
|
292
|
-
feature-root helpers, and reports unverifiable computed module
|
|
293
|
-
constrained layers.
|
|
291
|
+
apply Biome formatting. Beignet lint analyzes JavaScript and TypeScript import
|
|
292
|
+
graphs, follows feature-root helpers, and reports unverifiable computed module
|
|
293
|
+
references in constrained layers.
|
|
294
294
|
${testingNotes}
|
|
295
295
|
## Coding agents
|
|
296
296
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// lives outside the app schema, so `db generate` never diffs against it.
|
|
16
16
|
//
|
|
17
17
|
// The Better Auth tables were generated with
|
|
18
|
-
// `bunx
|
|
18
|
+
// `bunx auth generate` against a scratch app configured with
|
|
19
19
|
// drizzleAdapter(db, { provider: "mysql" }), then normalized to the starter's
|
|
20
20
|
// conventions (tabs, no relations, no extra indexes, no column defaults).
|
|
21
21
|
// MySQL cannot put UNIQUE constraints on bare text columns, so identity
|
|
@@ -60,6 +60,7 @@ export function closeDatabaseClient(): Promise<void> {
|
|
|
60
60
|
mysqlTable,
|
|
61
61
|
text,
|
|
62
62
|
timestamp,
|
|
63
|
+
uniqueIndex,
|
|
63
64
|
varchar,
|
|
64
65
|
} from "drizzle-orm/mysql-core";
|
|
65
66
|
|
|
@@ -86,23 +87,33 @@ export const session = mysqlTable("session", {
|
|
|
86
87
|
.references(() => user.id, { onDelete: "cascade" }),
|
|
87
88
|
});
|
|
88
89
|
|
|
89
|
-
export const account = mysqlTable(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
.notNull()
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
90
|
+
export const account = mysqlTable(
|
|
91
|
+
"account",
|
|
92
|
+
{
|
|
93
|
+
id: varchar("id", { length: 36 }).primaryKey(),
|
|
94
|
+
issuer: varchar("issuer", { length: 255 }).notNull(),
|
|
95
|
+
accountId: varchar("account_id", { length: 255 }).notNull(),
|
|
96
|
+
providerId: text("provider_id").notNull(),
|
|
97
|
+
userId: varchar("user_id", { length: 36 })
|
|
98
|
+
.notNull()
|
|
99
|
+
.references(() => user.id, { onDelete: "cascade" }),
|
|
100
|
+
accessToken: text("access_token"),
|
|
101
|
+
refreshToken: text("refresh_token"),
|
|
102
|
+
idToken: text("id_token"),
|
|
103
|
+
accessTokenExpiresAt: timestamp("access_token_expires_at", { fsp: 3 }),
|
|
104
|
+
refreshTokenExpiresAt: timestamp("refresh_token_expires_at", { fsp: 3 }),
|
|
105
|
+
scope: text("scope"),
|
|
106
|
+
password: text("password"),
|
|
107
|
+
createdAt: timestamp("created_at", { fsp: 3 }).notNull(),
|
|
108
|
+
updatedAt: timestamp("updated_at", { fsp: 3 }).notNull(),
|
|
109
|
+
},
|
|
110
|
+
(table) => [
|
|
111
|
+
uniqueIndex("account_issuer_accountId_uidx").on(
|
|
112
|
+
table.issuer,
|
|
113
|
+
table.accountId,
|
|
114
|
+
),
|
|
115
|
+
],
|
|
116
|
+
);
|
|
106
117
|
|
|
107
118
|
export const verification = mysqlTable("verification", {
|
|
108
119
|
id: varchar("id", { length: 36 }).primaryKey(),
|
|
@@ -476,7 +487,8 @@ const mysqlStarterMigration = {
|
|
|
476
487
|
// above, with the provider idempotency setup statements appended.
|
|
477
488
|
starterMigrationSql: `CREATE TABLE \`account\` (
|
|
478
489
|
\`id\` varchar(36) NOT NULL,
|
|
479
|
-
\`
|
|
490
|
+
\`issuer\` varchar(255) NOT NULL,
|
|
491
|
+
\`account_id\` varchar(255) NOT NULL,
|
|
480
492
|
\`provider_id\` text NOT NULL,
|
|
481
493
|
\`user_id\` varchar(36) NOT NULL,
|
|
482
494
|
\`access_token\` text,
|
|
@@ -488,7 +500,8 @@ const mysqlStarterMigration = {
|
|
|
488
500
|
\`password\` text,
|
|
489
501
|
\`created_at\` timestamp(3) NOT NULL,
|
|
490
502
|
\`updated_at\` timestamp(3) NOT NULL,
|
|
491
|
-
CONSTRAINT \`account_id\` PRIMARY KEY(\`id\`)
|
|
503
|
+
CONSTRAINT \`account_id\` PRIMARY KEY(\`id\`),
|
|
504
|
+
CONSTRAINT \`account_issuer_accountId_uidx\` UNIQUE(\`issuer\`,\`account_id\`)
|
|
492
505
|
);
|
|
493
506
|
--> statement-breakpoint
|
|
494
507
|
CREATE TABLE \`session\` (
|
|
@@ -585,9 +598,16 @@ CREATE TABLE IF NOT EXISTS \`idempotency_records\` (
|
|
|
585
598
|
"notNull": true,
|
|
586
599
|
"autoincrement": false
|
|
587
600
|
},
|
|
601
|
+
"issuer": {
|
|
602
|
+
"name": "issuer",
|
|
603
|
+
"type": "varchar(255)",
|
|
604
|
+
"primaryKey": false,
|
|
605
|
+
"notNull": true,
|
|
606
|
+
"autoincrement": false
|
|
607
|
+
},
|
|
588
608
|
"account_id": {
|
|
589
609
|
"name": "account_id",
|
|
590
|
-
"type": "
|
|
610
|
+
"type": "varchar(255)",
|
|
591
611
|
"primaryKey": false,
|
|
592
612
|
"notNull": true,
|
|
593
613
|
"autoincrement": false
|
|
@@ -670,7 +690,16 @@ CREATE TABLE IF NOT EXISTS \`idempotency_records\` (
|
|
|
670
690
|
"autoincrement": false
|
|
671
691
|
}
|
|
672
692
|
},
|
|
673
|
-
"indexes": {
|
|
693
|
+
"indexes": {
|
|
694
|
+
"account_issuer_accountId_uidx": {
|
|
695
|
+
"name": "account_issuer_accountId_uidx",
|
|
696
|
+
"columns": [
|
|
697
|
+
"issuer",
|
|
698
|
+
"account_id"
|
|
699
|
+
],
|
|
700
|
+
"isUnique": true
|
|
701
|
+
}
|
|
702
|
+
},
|
|
674
703
|
"foreignKeys": {
|
|
675
704
|
"account_user_id_user_id_fk": {
|
|
676
705
|
"name": "account_user_id_user_id_fk",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// lives outside the app schema, so `db generate` never diffs against it.
|
|
16
16
|
//
|
|
17
17
|
// The Better Auth tables were generated with
|
|
18
|
-
// `bunx
|
|
18
|
+
// `bunx auth generate` against a scratch app configured with
|
|
19
19
|
// drizzleAdapter(db, { provider: "pg" }), then normalized to the starter's
|
|
20
20
|
// conventions (tabs, no relations, no extra indexes, no column defaults).
|
|
21
21
|
|
|
@@ -51,7 +51,7 @@ export function closeDatabaseClient(): Promise<void> {
|
|
|
51
51
|
return closePromise;
|
|
52
52
|
}
|
|
53
53
|
`,
|
|
54
|
-
dbSchema: `import { boolean, index, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
54
|
+
dbSchema: `import { boolean, index, pgTable, text, timestamp, uniqueIndex } from "drizzle-orm/pg-core";
|
|
55
55
|
|
|
56
56
|
export const user = pgTable("user", {
|
|
57
57
|
id: text("id").primaryKey(),
|
|
@@ -76,23 +76,33 @@ export const session = pgTable("session", {
|
|
|
76
76
|
.references(() => user.id, { onDelete: "cascade" }),
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
export const account = pgTable(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
.notNull()
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
79
|
+
export const account = pgTable(
|
|
80
|
+
"account",
|
|
81
|
+
{
|
|
82
|
+
id: text("id").primaryKey(),
|
|
83
|
+
issuer: text("issuer").notNull(),
|
|
84
|
+
accountId: text("account_id").notNull(),
|
|
85
|
+
providerId: text("provider_id").notNull(),
|
|
86
|
+
userId: text("user_id")
|
|
87
|
+
.notNull()
|
|
88
|
+
.references(() => user.id, { onDelete: "cascade" }),
|
|
89
|
+
accessToken: text("access_token"),
|
|
90
|
+
refreshToken: text("refresh_token"),
|
|
91
|
+
idToken: text("id_token"),
|
|
92
|
+
accessTokenExpiresAt: timestamp("access_token_expires_at"),
|
|
93
|
+
refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
|
|
94
|
+
scope: text("scope"),
|
|
95
|
+
password: text("password"),
|
|
96
|
+
createdAt: timestamp("created_at").notNull(),
|
|
97
|
+
updatedAt: timestamp("updated_at").notNull(),
|
|
98
|
+
},
|
|
99
|
+
(table) => [
|
|
100
|
+
uniqueIndex("account_issuer_accountId_uidx").on(
|
|
101
|
+
table.issuer,
|
|
102
|
+
table.accountId,
|
|
103
|
+
),
|
|
104
|
+
],
|
|
105
|
+
);
|
|
96
106
|
|
|
97
107
|
export const verification = pgTable("verification", {
|
|
98
108
|
id: text("id").primaryKey(),
|
|
@@ -413,6 +423,7 @@ const postgresStarterMigration = {
|
|
|
413
423
|
// above, with the provider idempotency setup statements appended.
|
|
414
424
|
starterMigrationSql: `CREATE TABLE "account" (
|
|
415
425
|
"id" text PRIMARY KEY NOT NULL,
|
|
426
|
+
"issuer" text NOT NULL,
|
|
416
427
|
"account_id" text NOT NULL,
|
|
417
428
|
"provider_id" text NOT NULL,
|
|
418
429
|
"user_id" text NOT NULL,
|
|
@@ -470,6 +481,7 @@ CREATE TABLE "verification" (
|
|
|
470
481
|
ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
471
482
|
ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
472
483
|
ALTER TABLE "todos" ADD CONSTRAINT "todos_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
484
|
+
CREATE UNIQUE INDEX "account_issuer_accountId_uidx" ON "account" USING btree ("issuer","account_id");--> statement-breakpoint
|
|
473
485
|
CREATE INDEX "todos_user_idx" ON "todos" USING btree ("user_id","created_at");
|
|
474
486
|
--> statement-breakpoint
|
|
475
487
|
CREATE TABLE IF NOT EXISTS "idempotency_records" (
|
|
@@ -517,6 +529,12 @@ CREATE INDEX IF NOT EXISTS "idempotency_records_expires_idx" ON "idempotency_rec
|
|
|
517
529
|
"primaryKey": true,
|
|
518
530
|
"notNull": true
|
|
519
531
|
},
|
|
532
|
+
"issuer": {
|
|
533
|
+
"name": "issuer",
|
|
534
|
+
"type": "text",
|
|
535
|
+
"primaryKey": false,
|
|
536
|
+
"notNull": true
|
|
537
|
+
},
|
|
520
538
|
"account_id": {
|
|
521
539
|
"name": "account_id",
|
|
522
540
|
"type": "text",
|
|
@@ -590,7 +608,29 @@ CREATE INDEX IF NOT EXISTS "idempotency_records_expires_idx" ON "idempotency_rec
|
|
|
590
608
|
"notNull": true
|
|
591
609
|
}
|
|
592
610
|
},
|
|
593
|
-
"indexes": {
|
|
611
|
+
"indexes": {
|
|
612
|
+
"account_issuer_accountId_uidx": {
|
|
613
|
+
"name": "account_issuer_accountId_uidx",
|
|
614
|
+
"columns": [
|
|
615
|
+
{
|
|
616
|
+
"expression": "issuer",
|
|
617
|
+
"isExpression": false,
|
|
618
|
+
"asc": true,
|
|
619
|
+
"nulls": "last"
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
"expression": "account_id",
|
|
623
|
+
"isExpression": false,
|
|
624
|
+
"asc": true,
|
|
625
|
+
"nulls": "last"
|
|
626
|
+
}
|
|
627
|
+
],
|
|
628
|
+
"isUnique": true,
|
|
629
|
+
"concurrently": false,
|
|
630
|
+
"method": "btree",
|
|
631
|
+
"with": {}
|
|
632
|
+
}
|
|
633
|
+
},
|
|
594
634
|
"foreignKeys": {
|
|
595
635
|
"account_user_id_user_id_fk": {
|
|
596
636
|
"name": "account_user_id_user_id_fk",
|
|
@@ -42,7 +42,7 @@ export function closeDatabaseClient(): Promise<void> {
|
|
|
42
42
|
return closePromise;
|
|
43
43
|
}
|
|
44
44
|
`,
|
|
45
|
-
dbSchema: `import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
|
45
|
+
dbSchema: `import { index, integer, sqliteTable, text, uniqueIndex } from "drizzle-orm/sqlite-core";
|
|
46
46
|
|
|
47
47
|
export const user = sqliteTable("user", {
|
|
48
48
|
id: text("id").primaryKey(),
|
|
@@ -69,27 +69,37 @@ export const session = sqliteTable("session", {
|
|
|
69
69
|
.references(() => user.id, { onDelete: "cascade" }),
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
export const account = sqliteTable(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
.notNull()
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
72
|
+
export const account = sqliteTable(
|
|
73
|
+
"account",
|
|
74
|
+
{
|
|
75
|
+
id: text("id").primaryKey(),
|
|
76
|
+
issuer: text("issuer").notNull(),
|
|
77
|
+
accountId: text("account_id").notNull(),
|
|
78
|
+
providerId: text("provider_id").notNull(),
|
|
79
|
+
userId: text("user_id")
|
|
80
|
+
.notNull()
|
|
81
|
+
.references(() => user.id, { onDelete: "cascade" }),
|
|
82
|
+
accessToken: text("access_token"),
|
|
83
|
+
refreshToken: text("refresh_token"),
|
|
84
|
+
idToken: text("id_token"),
|
|
85
|
+
accessTokenExpiresAt: integer("access_token_expires_at", {
|
|
86
|
+
mode: "timestamp",
|
|
87
|
+
}),
|
|
88
|
+
refreshTokenExpiresAt: integer("refresh_token_expires_at", {
|
|
89
|
+
mode: "timestamp",
|
|
90
|
+
}),
|
|
91
|
+
scope: text("scope"),
|
|
92
|
+
password: text("password"),
|
|
93
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
94
|
+
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
|
95
|
+
},
|
|
96
|
+
(table) => [
|
|
97
|
+
uniqueIndex("account_issuer_accountId_uidx").on(
|
|
98
|
+
table.issuer,
|
|
99
|
+
table.accountId,
|
|
100
|
+
),
|
|
101
|
+
],
|
|
102
|
+
);
|
|
93
103
|
|
|
94
104
|
export const verification = sqliteTable("verification", {
|
|
95
105
|
id: text("id").primaryKey(),
|
|
@@ -452,6 +462,7 @@ export async function createTestDatabase(): Promise<TestDatabase> {
|
|
|
452
462
|
// above, with the provider idempotency setup statements appended.
|
|
453
463
|
starterMigrationSql: `CREATE TABLE \`account\` (
|
|
454
464
|
\`id\` text PRIMARY KEY NOT NULL,
|
|
465
|
+
\`issuer\` text NOT NULL,
|
|
455
466
|
\`account_id\` text NOT NULL,
|
|
456
467
|
\`provider_id\` text NOT NULL,
|
|
457
468
|
\`user_id\` text NOT NULL,
|
|
@@ -467,6 +478,7 @@ export async function createTestDatabase(): Promise<TestDatabase> {
|
|
|
467
478
|
FOREIGN KEY (\`user_id\`) REFERENCES \`user\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
|
468
479
|
);
|
|
469
480
|
--> statement-breakpoint
|
|
481
|
+
CREATE UNIQUE INDEX \`account_issuer_accountId_uidx\` ON \`account\` (\`issuer\`,\`account_id\`);--> statement-breakpoint
|
|
470
482
|
CREATE TABLE \`session\` (
|
|
471
483
|
\`id\` text PRIMARY KEY NOT NULL,
|
|
472
484
|
\`expires_at\` integer NOT NULL,
|
|
@@ -555,6 +567,13 @@ CREATE INDEX IF NOT EXISTS "idempotency_records_expires_idx" ON "idempotency_rec
|
|
|
555
567
|
"notNull": true,
|
|
556
568
|
"autoincrement": false
|
|
557
569
|
},
|
|
570
|
+
"issuer": {
|
|
571
|
+
"name": "issuer",
|
|
572
|
+
"type": "text",
|
|
573
|
+
"primaryKey": false,
|
|
574
|
+
"notNull": true,
|
|
575
|
+
"autoincrement": false
|
|
576
|
+
},
|
|
558
577
|
"account_id": {
|
|
559
578
|
"name": "account_id",
|
|
560
579
|
"type": "text",
|
|
@@ -640,7 +659,16 @@ CREATE INDEX IF NOT EXISTS "idempotency_records_expires_idx" ON "idempotency_rec
|
|
|
640
659
|
"autoincrement": false
|
|
641
660
|
}
|
|
642
661
|
},
|
|
643
|
-
"indexes": {
|
|
662
|
+
"indexes": {
|
|
663
|
+
"account_issuer_accountId_uidx": {
|
|
664
|
+
"name": "account_issuer_accountId_uidx",
|
|
665
|
+
"columns": [
|
|
666
|
+
"issuer",
|
|
667
|
+
"account_id"
|
|
668
|
+
],
|
|
669
|
+
"isUnique": true
|
|
670
|
+
}
|
|
671
|
+
},
|
|
644
672
|
"foreignKeys": {
|
|
645
673
|
"account_user_id_user_id_fk": {
|
|
646
674
|
"name": "account_user_id_user_id_fk",
|
package/src/templates/shadcn.ts
CHANGED
|
@@ -561,7 +561,7 @@ export const shadcnDependencies: Record<string, string> = {
|
|
|
561
561
|
clsx: "^2.1.1",
|
|
562
562
|
"lucide-react": "^1.16.0",
|
|
563
563
|
"radix-ui": "^1.4.3",
|
|
564
|
-
shadcn: "^4.
|
|
564
|
+
shadcn: "^4.19.0",
|
|
565
565
|
"tailwind-merge": "^3.6.0",
|
|
566
566
|
"tw-animate-css": "^1.4.0",
|
|
567
567
|
};
|
package/src/templates/shared.ts
CHANGED
|
@@ -32,7 +32,7 @@ export type TemplateContext = {
|
|
|
32
32
|
|
|
33
33
|
export const externalVersions = {
|
|
34
34
|
biome: "^2.4.14",
|
|
35
|
-
next: "^16.
|
|
35
|
+
next: "^16.3.3",
|
|
36
36
|
react: "^19.2.5",
|
|
37
37
|
reactDom: "^19.2.5",
|
|
38
38
|
tsx: "^4.22.4",
|
|
@@ -41,16 +41,16 @@ export const externalVersions = {
|
|
|
41
41
|
typesReact: "^19.0.0",
|
|
42
42
|
typesReactDom: "^19.0.0",
|
|
43
43
|
zod: "^4.0.0",
|
|
44
|
-
tanstackReactQuery: "^5.
|
|
44
|
+
tanstackReactQuery: "^5.102.0",
|
|
45
45
|
hookformResolvers: "^5.0.0",
|
|
46
46
|
reactHookForm: "^7.74.0",
|
|
47
|
-
betterAuth: "1.
|
|
47
|
+
betterAuth: "1.7.1",
|
|
48
48
|
bullmq: "^5.0.0",
|
|
49
49
|
drizzleKit: "^0.31.10",
|
|
50
50
|
drizzleOrm: "^0.45.2",
|
|
51
|
-
inngest: "^4.
|
|
51
|
+
inngest: "^4.18.1",
|
|
52
52
|
libsqlClient: "^0.14.0",
|
|
53
|
-
vercelBlob: "^2.
|
|
53
|
+
vercelBlob: "^2.8.0",
|
|
54
54
|
mysql2: "^3.12.0",
|
|
55
55
|
pg: "^8.13.0",
|
|
56
56
|
pglite: "^0.5.2",
|
|
@@ -58,7 +58,7 @@ export const externalVersions = {
|
|
|
58
58
|
resend: "^6.14.0",
|
|
59
59
|
sentryNode: "^10.58.0",
|
|
60
60
|
stripe: "^22.2.1",
|
|
61
|
-
nodemailer: "^9.
|
|
61
|
+
nodemailer: "^9.1.1",
|
|
62
62
|
openFeatureServerSdk: "^1.22.0",
|
|
63
63
|
typesPg: "^8.11.0",
|
|
64
64
|
ioredis: "^5.0.0",
|
package/src/templates/testing.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appTestFilePattern,
|
|
3
|
+
configuredTestDirectoryPathKeys,
|
|
4
|
+
configuredTestFilePathKeys,
|
|
5
|
+
defaultAppTestRoots,
|
|
6
|
+
} from "../test-discovery.js";
|
|
1
7
|
import type { TemplateFile } from "./shared.js";
|
|
2
8
|
|
|
3
9
|
export const testHelperTemplateFile: TemplateFile = {
|
|
@@ -408,16 +414,9 @@ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
|
408
414
|
import path from "node:path";
|
|
409
415
|
import { pathToFileURL } from "node:url";
|
|
410
416
|
|
|
411
|
-
const defaultTestRoots =
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
"infra",
|
|
415
|
-
"lib",
|
|
416
|
-
"ports",
|
|
417
|
-
"server",
|
|
418
|
-
"tests",
|
|
419
|
-
"src/tests",
|
|
420
|
-
];
|
|
417
|
+
const defaultTestRoots = ${JSON.stringify(defaultAppTestRoots, null, 2)};
|
|
418
|
+
const configuredTestDirectoryPathKeys = ${JSON.stringify(configuredTestDirectoryPathKeys)};
|
|
419
|
+
const configuredTestFilePathKeys = ${JSON.stringify(configuredTestFilePathKeys)};
|
|
421
420
|
const ignoredDirectories = new Set([
|
|
422
421
|
".beignet-local",
|
|
423
422
|
".git",
|
|
@@ -427,7 +426,7 @@ const ignoredDirectories = new Set([
|
|
|
427
426
|
"dist",
|
|
428
427
|
"node_modules",
|
|
429
428
|
]);
|
|
430
|
-
const testFilePattern =
|
|
429
|
+
const testFilePattern = /${appTestFilePattern.source}/;
|
|
431
430
|
|
|
432
431
|
const configFileNames = [
|
|
433
432
|
"beignet.config.ts",
|
|
@@ -532,14 +531,8 @@ async function configuredRoots(cwd: string): Promise<string[]> {
|
|
|
532
531
|
}
|
|
533
532
|
const paths = isObjectRecord(config.paths) ? config.paths : {};
|
|
534
533
|
return [
|
|
535
|
-
paths
|
|
536
|
-
paths
|
|
537
|
-
parentPath(paths.routes),
|
|
538
|
-
parentPath(paths.server),
|
|
539
|
-
parentPath(paths.portWiring),
|
|
540
|
-
parentPath(paths.ports),
|
|
541
|
-
parentPath(paths.useCaseBuilder),
|
|
542
|
-
parentPath(paths.routesBuilder),
|
|
534
|
+
...configuredTestDirectoryPathKeys.map((key) => paths[key]),
|
|
535
|
+
...configuredTestFilePathKeys.map((key) => parentPath(paths[key])),
|
|
543
536
|
].filter((root): root is string => Boolean(root) && root !== ".");
|
|
544
537
|
}
|
|
545
538
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { type BeignetPaths, directoryPath } from "./config.js";
|
|
3
|
+
|
|
4
|
+
export const defaultAppTestRoots = [
|
|
5
|
+
"app",
|
|
6
|
+
"features",
|
|
7
|
+
"infra",
|
|
8
|
+
"lib",
|
|
9
|
+
"ports",
|
|
10
|
+
"server",
|
|
11
|
+
"tests",
|
|
12
|
+
"src/tests",
|
|
13
|
+
] as const;
|
|
14
|
+
|
|
15
|
+
export const configuredTestDirectoryPathKeys = [
|
|
16
|
+
"tests",
|
|
17
|
+
"features",
|
|
18
|
+
] as const satisfies readonly (keyof BeignetPaths)[];
|
|
19
|
+
|
|
20
|
+
export const configuredTestFilePathKeys = [
|
|
21
|
+
"routes",
|
|
22
|
+
"server",
|
|
23
|
+
"portWiring",
|
|
24
|
+
"ports",
|
|
25
|
+
"useCaseBuilder",
|
|
26
|
+
"routesBuilder",
|
|
27
|
+
] as const satisfies readonly (keyof BeignetPaths)[];
|
|
28
|
+
|
|
29
|
+
export const appTestFilePattern = /\.(test|spec)\.[cm]?[jt]sx?$/;
|
|
30
|
+
|
|
31
|
+
export function appTestRoots(paths: BeignetPaths): string[] {
|
|
32
|
+
const roots = [
|
|
33
|
+
...defaultAppTestRoots,
|
|
34
|
+
...configuredTestDirectoryPathKeys.map((key) => paths[key]),
|
|
35
|
+
...configuredTestFilePathKeys.map((key) =>
|
|
36
|
+
directoryPath(path.posix.dirname(paths[key])),
|
|
37
|
+
),
|
|
38
|
+
];
|
|
39
|
+
return Array.from(
|
|
40
|
+
new Set(roots.map(directoryPath).filter((root) => root && root !== ".")),
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function isAppTestFile(file: string): boolean {
|
|
45
|
+
return appTestFilePattern.test(file);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function isWithinAppTestRoots(
|
|
49
|
+
file: string,
|
|
50
|
+
roots: readonly string[],
|
|
51
|
+
): boolean {
|
|
52
|
+
return roots.some((root) => file.startsWith(`${root}/`));
|
|
53
|
+
}
|