create-nexwire 4.1.1 → 4.2.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.
Files changed (58) hide show
  1. package/express/gitignore-stub +31 -24
  2. package/express/package.json +3 -3
  3. package/express/src/database/migrations/sqlite/0000_init.sql +60 -60
  4. package/express/src/database/migrations/sqlite/meta/0000_snapshot.json +1 -1
  5. package/express/src/database/migrations/sqlite/meta/_journal.json +1 -1
  6. package/express/src/database/schema.ts +3 -3
  7. package/express/src/framework/maker-cli/db/index.mjs +1 -1
  8. package/express/src/framework/maker-cli/deploy/core.mjs +0 -1
  9. package/express/src/framework/maker-cli/index.mjs +13 -3
  10. package/express/src/framework/maker-cli/module/core.mjs +121 -43
  11. package/express/src/framework/maker-cli/runtime/core.mjs +26 -7
  12. package/express/src/framework/maker-cli/runtime/index.mjs +120 -104
  13. package/express/src/framework/maker-cli/stubs/controller/openapi.ts.stub +6 -6
  14. package/express/src/framework/maker-cli/stubs/controller/plain.ts.stub +6 -6
  15. package/express/src/framework/maker-cli/stubs/helper/name.ts.stub +1 -1
  16. package/express/src/framework/maker-cli/stubs/seeder/name.ts.stub +17 -19
  17. package/express/src/framework/maker-cli/stubs/seeder/standalone.ts.stub +22 -0
  18. package/express/src/framework/maker-cli/stubs/service/name.plain.ts.stub +2 -2
  19. package/express/src/framework/maker-cli/stubs/service/name.ts.stub +1 -1
  20. package/express/src/framework/maker-cli/utils/help.mjs +374 -50
  21. package/express/src/framework/maker-cli/utils/naming.mjs +83 -20
  22. package/express/src/framework/maker-cli/utils/project-commands.mjs +140 -0
  23. package/express/src/framework/queue/queue.ts +402 -342
  24. package/express/src/modules/auth/database/seeders/role.ts +18 -18
  25. package/express/src/modules/auth/database/seeders/user.ts +35 -35
  26. package/express/src/storage/database/nexwire.sqlite +0 -0
  27. package/express/vitest.config.ts +38 -23
  28. package/hono/gitignore-stub +31 -24
  29. package/hono/package.json +3 -3
  30. package/hono/src/database/migrations/sqlite/0000_init.sql +60 -60
  31. package/hono/src/database/migrations/sqlite/meta/0000_snapshot.json +1 -1
  32. package/hono/src/database/migrations/sqlite/meta/_journal.json +1 -1
  33. package/hono/src/database/schema.ts +3 -3
  34. package/hono/src/framework/database/paginate.ts +253 -253
  35. package/hono/src/framework/maker-cli/db/index.mjs +1 -1
  36. package/hono/src/framework/maker-cli/deploy/core.mjs +0 -1
  37. package/hono/src/framework/maker-cli/index.mjs +13 -3
  38. package/hono/src/framework/maker-cli/module/core.mjs +116 -38
  39. package/hono/src/framework/maker-cli/runtime/core.mjs +24 -6
  40. package/hono/src/framework/maker-cli/runtime/index.mjs +120 -104
  41. package/hono/src/framework/maker-cli/stubs/controller/openapi.ts.stub +6 -6
  42. package/hono/src/framework/maker-cli/stubs/controller/plain.ts.stub +6 -6
  43. package/hono/src/framework/maker-cli/stubs/helper/name.ts.stub +1 -1
  44. package/hono/src/framework/maker-cli/stubs/seeder/name.ts.stub +17 -19
  45. package/hono/src/framework/maker-cli/stubs/seeder/standalone.ts.stub +22 -0
  46. package/hono/src/framework/maker-cli/stubs/service/name.plain.ts.stub +2 -2
  47. package/hono/src/framework/maker-cli/stubs/service/name.ts.stub +1 -1
  48. package/hono/src/framework/maker-cli/utils/help.mjs +374 -50
  49. package/hono/src/framework/maker-cli/utils/naming.mjs +83 -20
  50. package/hono/src/framework/maker-cli/utils/project-commands.mjs +140 -0
  51. package/hono/src/framework/queue/queue.ts +402 -342
  52. package/hono/src/modules/auth/database/seeders/role.ts +18 -18
  53. package/hono/src/modules/auth/database/seeders/user.ts +35 -35
  54. package/hono/src/storage/database/nexwire.sqlite +0 -0
  55. package/hono/vitest.config.ts +38 -23
  56. package/package.json +1 -1
  57. package/express/src/framework/maker-cli/stubs/controller/openapi.with-model.ts.stub +0 -73
  58. package/hono/src/framework/maker-cli/stubs/controller/openapi.with-model.ts.stub +0 -69
@@ -1,253 +1,253 @@
1
- import { count, getTableColumns, type SQL, sql } from "drizzle-orm";
2
- import { db } from "@/framework/database/connection.js";
3
-
4
- type PaginateOptions = {
5
- page?: number;
6
- perPage?: number;
7
- maxPerPage?: number;
8
- path?: string;
9
- where?: SQL<unknown>;
10
- orderBy?: unknown[];
11
- };
12
-
13
- type RequestLike = {
14
- req: {
15
- query: (key: string) => string | undefined;
16
- path: string;
17
- url?: string;
18
- };
19
- };
20
-
21
- type PaginateQueryOptions<T> = {
22
- page?: number;
23
- perPage?: number;
24
- maxPerPage?: number;
25
- path?: string;
26
- total: () => Promise<number>;
27
- data: (limit: number, offset: number) => Promise<T[]>;
28
- };
29
-
30
- type PaginateModelOptions<T = any> = {
31
- table?: any;
32
- query?: { findMany: (args: Record<string, any>) => Promise<T[]> };
33
- where?: SQL<unknown>;
34
- with?: Record<string, any>;
35
- columns?: Record<string, any>;
36
- extras?: Record<string, any>;
37
- orderBy?: unknown;
38
- page?: number;
39
- perPage?: number;
40
- maxPerPage?: number;
41
- path?: string;
42
- total?: () => Promise<number>;
43
- data?: (params: { limit: number; offset: number }) => Promise<T[]>;
44
- };
45
-
46
- export type PaginatedResult<T> = {
47
- current_page: number;
48
- data: T[];
49
- first_page_url: string | null;
50
- from: number | null;
51
- last_page: number;
52
- last_page_url: string | null;
53
- links: Array<{ url: string | null; label: string; page: number | null; active: boolean }>;
54
- next_page_url: string | null;
55
- path: string;
56
- per_page: number;
57
- prev_page_url: string | null;
58
- to: number | null;
59
- total: number;
60
- };
61
-
62
- function toPositiveInt(value: unknown, fallback: number) {
63
- const parsed = Number(value);
64
- if (!Number.isFinite(parsed) || parsed < 1) return fallback;
65
- return Math.floor(parsed);
66
- }
67
-
68
- function pageUrl(path: string, page: number, perPage: number) {
69
- if (!path) return null;
70
- const delimiter = path.includes("?") ? "&" : "?";
71
- return `${path}${delimiter}page=${page}&per_page=${perPage}`;
72
- }
73
-
74
- function resolvePath(c: RequestLike, path?: string) {
75
- if (path) return path;
76
- const fallbackPath = c.req.path;
77
- if (!c.req.url) return fallbackPath;
78
- try {
79
- const parsed = new URL(c.req.url);
80
- return `${parsed.origin}${parsed.pathname}`;
81
- } catch {
82
- return fallbackPath;
83
- }
84
- }
85
-
86
- /**
87
- * Why: Generic paginator for custom total/data callbacks.
88
- * When: You need pagination outside direct table helpers.
89
- * Where: Controllers/services composing complex queries.
90
- * How: Normalizes page params, computes URLs/meta, and executes callbacks.
91
- */
92
- export async function paginateQuery<T = any>(options: PaginateQueryOptions<T>): Promise<PaginatedResult<T>> {
93
- const maxPerPage = toPositiveInt(options.maxPerPage, 100);
94
- const perPage = Math.min(toPositiveInt(options.perPage, 15), maxPerPage);
95
- const page = toPositiveInt(options.page, 1);
96
-
97
- const total = Number(await options.total());
98
- const lastPage = Math.max(1, Math.ceil(total / perPage));
99
- const currentPage = Math.min(page, lastPage);
100
- const safeOffset = (currentPage - 1) * perPage;
101
- const data = await options.data(perPage, safeOffset);
102
-
103
- const from = total === 0 ? null : safeOffset + 1;
104
- const to = total === 0 ? null : safeOffset + data.length;
105
- const path = options.path || "";
106
- const firstPageUrl = pageUrl(path, 1, perPage);
107
- const lastPageUrl = pageUrl(path, lastPage, perPage);
108
- const prevPageUrl = currentPage > 1 ? pageUrl(path, currentPage - 1, perPage) : null;
109
- const nextPageUrl = currentPage < lastPage ? pageUrl(path, currentPage + 1, perPage) : null;
110
-
111
- const links: Array<{ url: string | null; label: string; page: number | null; active: boolean }> = [
112
- {
113
- url: prevPageUrl,
114
- label: "&laquo; Previous",
115
- page: currentPage > 1 ? currentPage - 1 : null,
116
- active: false
117
- }
118
- ];
119
-
120
- for (let p = 1; p <= lastPage; p += 1) {
121
- links.push({
122
- url: pageUrl(path, p, perPage),
123
- label: String(p),
124
- page: p,
125
- active: p === currentPage
126
- });
127
- }
128
-
129
- links.push({
130
- url: nextPageUrl,
131
- label: "Next &raquo;",
132
- page: currentPage < lastPage ? currentPage + 1 : null,
133
- active: false
134
- });
135
-
136
- return {
137
- current_page: currentPage,
138
- data,
139
- first_page_url: firstPageUrl,
140
- from,
141
- last_page: lastPage,
142
- last_page_url: lastPageUrl,
143
- links,
144
- next_page_url: nextPageUrl,
145
- path,
146
- per_page: perPage,
147
- prev_page_url: prevPageUrl,
148
- to,
149
- total
150
- };
151
- }
152
-
153
- /**
154
- * Why: Paginates a Drizzle query using request query params.
155
- * When: Route handlers receive `page/per_page` from client.
156
- * Where: API controllers returning list resources.
157
- * How: Builds count subquery and applies limit/offset to source query.
158
- */
159
- export async function paginate<T = any>(
160
- c: RequestLike,
161
- query: any,
162
- perPage = 15,
163
- options: { maxPerPage?: number; path?: string } = {}
164
- ): Promise<PaginatedResult<T>> {
165
- const page = Number(c.req.query("page") || 1);
166
- const size = c.req.query("size");
167
- const perPageQuery = c.req.query("per_page");
168
- const perPageValue = Number(size || perPageQuery || perPage);
169
- const resolvedPath = resolvePath(c, options.path);
170
-
171
- return paginateQuery<T>({
172
- page,
173
- perPage: perPageValue,
174
- maxPerPage: options.maxPerPage,
175
- path: resolvedPath,
176
- total: async () => {
177
- const inner = db.select({ val: sql`1` }).from(query.as("_inner"));
178
- const [row] = await db.select({ total: count() }).from(inner);
179
- return Number(row?.total ?? 0);
180
- },
181
- data: (limit, offset) => query.limit(limit).offset(offset)
182
- });
183
- }
184
-
185
- /**
186
- * Why: Laravel-style pagination for Drizzle relational queries.
187
- * When: Controllers need eager loading via `db.query.table.findMany({ with })`.
188
- * Where: Use beside `paginate`; this targets model/relational API, not select builders.
189
- * How: Counts the base table separately, then runs `findMany` with limit/offset.
190
- */
191
- export async function paginateModel<T = any>(c: RequestLike, options: PaginateModelOptions<T>): Promise<PaginatedResult<T>> {
192
- const page = Number(c.req.query("page") || options.page || 1);
193
- const size = c.req.query("size");
194
- const perPageQuery = c.req.query("per_page");
195
- const perPageValue = Number(size || perPageQuery || options.perPage || 15);
196
- const resolvedPath = resolvePath(c, options.path);
197
-
198
- return paginateQuery<T>({
199
- page,
200
- perPage: perPageValue,
201
- maxPerPage: options.maxPerPage,
202
- path: resolvedPath,
203
- total: async () => {
204
- if (options.total) return Number(await options.total());
205
- if (!options.table) throw new Error("paginateModel requires either table or total callback");
206
-
207
- let totalQuery = db.select({ total: count() }).from(options.table);
208
- if (options.where) totalQuery = totalQuery.where(options.where);
209
- const [row] = await totalQuery;
210
- return Number(row?.total ?? 0);
211
- },
212
- data: async (limit, offset) => {
213
- if (options.data) return options.data({ limit, offset });
214
- if (!options.query) throw new Error("paginateModel requires either query or data callback");
215
-
216
- const args: Record<string, any> = { limit, offset };
217
- if (options.where) args.where = options.where;
218
- if (options.with) args.with = options.with;
219
- if (options.columns) args.columns = options.columns;
220
- if (options.extras) args.extras = options.extras;
221
- if (options.orderBy) args.orderBy = options.orderBy;
222
-
223
- return options.query.findMany(args);
224
- }
225
- });
226
- }
227
-
228
- /**
229
- * Why: Paginates a full table with optional filters/sorting.
230
- * When: CRUD list endpoints need simple table pagination.
231
- * Where: Service/controller code using table helpers.
232
- * How: Runs total + paged select with where/order options.
233
- */
234
- export async function paginateTable<T = any>(db: any, table: any, options: PaginateOptions = {}): Promise<PaginatedResult<T>> {
235
- return paginateQuery<T>({
236
- page: options.page,
237
- perPage: options.perPage,
238
- maxPerPage: options.maxPerPage,
239
- path: options.path,
240
- total: async () => {
241
- let totalQuery = db.select({ total: count() }).from(table);
242
- if (options.where) totalQuery = totalQuery.where(options.where);
243
- const totalRow = await totalQuery;
244
- return Number(totalRow[0]?.total ?? 0);
245
- },
246
- data: async (limit, offset) => {
247
- let dataQuery = db.select(getTableColumns(table)).from(table);
248
- if (options.where) dataQuery = dataQuery.where(options.where);
249
- if (options.orderBy?.length) dataQuery = dataQuery.orderBy(...options.orderBy);
250
- return dataQuery.limit(limit).offset(offset);
251
- }
252
- });
253
- }
1
+ import { count, getTableColumns, type SQL, sql } from "drizzle-orm";
2
+ import { db } from "@/framework/database/connection.js";
3
+
4
+ type PaginateOptions = {
5
+ page?: number;
6
+ perPage?: number;
7
+ maxPerPage?: number;
8
+ path?: string;
9
+ where?: SQL<unknown>;
10
+ orderBy?: unknown[];
11
+ };
12
+
13
+ type RequestLike = {
14
+ req: {
15
+ query: (key: string) => string | undefined;
16
+ path: string;
17
+ url?: string;
18
+ };
19
+ };
20
+
21
+ type PaginateQueryOptions<T> = {
22
+ page?: number;
23
+ perPage?: number;
24
+ maxPerPage?: number;
25
+ path?: string;
26
+ total: () => Promise<number>;
27
+ data: (limit: number, offset: number) => Promise<T[]>;
28
+ };
29
+
30
+ type PaginateModelOptions<T = any> = {
31
+ table?: any;
32
+ query?: { findMany: (args: Record<string, any>) => Promise<T[]> };
33
+ where?: SQL<unknown>;
34
+ with?: Record<string, any>;
35
+ columns?: Record<string, any>;
36
+ extras?: Record<string, any>;
37
+ orderBy?: unknown;
38
+ page?: number;
39
+ perPage?: number;
40
+ maxPerPage?: number;
41
+ path?: string;
42
+ total?: () => Promise<number>;
43
+ data?: (params: { limit: number; offset: number }) => Promise<T[]>;
44
+ };
45
+
46
+ export type PaginatedResult<T> = {
47
+ current_page: number;
48
+ data: T[];
49
+ first_page_url: string | null;
50
+ from: number | null;
51
+ last_page: number;
52
+ last_page_url: string | null;
53
+ links: Array<{ url: string | null; label: string; page: number | null; active: boolean }>;
54
+ next_page_url: string | null;
55
+ path: string;
56
+ per_page: number;
57
+ prev_page_url: string | null;
58
+ to: number | null;
59
+ total: number;
60
+ };
61
+
62
+ function toPositiveInt(value: unknown, fallback: number) {
63
+ const parsed = Number(value);
64
+ if (!Number.isFinite(parsed) || parsed < 1) return fallback;
65
+ return Math.floor(parsed);
66
+ }
67
+
68
+ function pageUrl(path: string, page: number, perPage: number) {
69
+ if (!path) return null;
70
+ const delimiter = path.includes("?") ? "&" : "?";
71
+ return `${path}${delimiter}page=${page}&per_page=${perPage}`;
72
+ }
73
+
74
+ function resolvePath(c: RequestLike, path?: string) {
75
+ if (path) return path;
76
+ const fallbackPath = c.req.path;
77
+ if (!c.req.url) return fallbackPath;
78
+ try {
79
+ const parsed = new URL(c.req.url);
80
+ return `${parsed.origin}${parsed.pathname}`;
81
+ } catch {
82
+ return fallbackPath;
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Why: Generic paginator for custom total/data callbacks.
88
+ * When: You need pagination outside direct table helpers.
89
+ * Where: Controllers/services composing complex queries.
90
+ * How: Normalizes page params, computes URLs/meta, and executes callbacks.
91
+ */
92
+ export async function paginateQuery<T = any>(options: PaginateQueryOptions<T>): Promise<PaginatedResult<T>> {
93
+ const maxPerPage = toPositiveInt(options.maxPerPage, 100);
94
+ const perPage = Math.min(toPositiveInt(options.perPage, 15), maxPerPage);
95
+ const page = toPositiveInt(options.page, 1);
96
+
97
+ const total = Number(await options.total());
98
+ const lastPage = Math.max(1, Math.ceil(total / perPage));
99
+ const currentPage = Math.min(page, lastPage);
100
+ const safeOffset = (currentPage - 1) * perPage;
101
+ const data = await options.data(perPage, safeOffset);
102
+
103
+ const from = total === 0 ? null : safeOffset + 1;
104
+ const to = total === 0 ? null : safeOffset + data.length;
105
+ const path = options.path || "";
106
+ const firstPageUrl = pageUrl(path, 1, perPage);
107
+ const lastPageUrl = pageUrl(path, lastPage, perPage);
108
+ const prevPageUrl = currentPage > 1 ? pageUrl(path, currentPage - 1, perPage) : null;
109
+ const nextPageUrl = currentPage < lastPage ? pageUrl(path, currentPage + 1, perPage) : null;
110
+
111
+ const links: Array<{ url: string | null; label: string; page: number | null; active: boolean }> = [
112
+ {
113
+ url: prevPageUrl,
114
+ label: "&laquo; Previous",
115
+ page: currentPage > 1 ? currentPage - 1 : null,
116
+ active: false
117
+ }
118
+ ];
119
+
120
+ for (let p = 1; p <= lastPage; p += 1) {
121
+ links.push({
122
+ url: pageUrl(path, p, perPage),
123
+ label: String(p),
124
+ page: p,
125
+ active: p === currentPage
126
+ });
127
+ }
128
+
129
+ links.push({
130
+ url: nextPageUrl,
131
+ label: "Next &raquo;",
132
+ page: currentPage < lastPage ? currentPage + 1 : null,
133
+ active: false
134
+ });
135
+
136
+ return {
137
+ current_page: currentPage,
138
+ data,
139
+ first_page_url: firstPageUrl,
140
+ from,
141
+ last_page: lastPage,
142
+ last_page_url: lastPageUrl,
143
+ links,
144
+ next_page_url: nextPageUrl,
145
+ path,
146
+ per_page: perPage,
147
+ prev_page_url: prevPageUrl,
148
+ to,
149
+ total
150
+ };
151
+ }
152
+
153
+ /**
154
+ * Why: Paginates a Drizzle query using request query params.
155
+ * When: Route handlers receive `page/per_page` from client.
156
+ * Where: API controllers returning list resources.
157
+ * How: Builds count subquery and applies limit/offset to source query.
158
+ */
159
+ export async function paginate<T = any>(
160
+ c: RequestLike,
161
+ query: any,
162
+ perPage = 15,
163
+ options: { maxPerPage?: number; path?: string } = {}
164
+ ): Promise<PaginatedResult<T>> {
165
+ const page = Number(c.req.query("page") || 1);
166
+ const size = c.req.query("size");
167
+ const perPageQuery = c.req.query("per_page");
168
+ const perPageValue = Number(size || perPageQuery || perPage);
169
+ const resolvedPath = resolvePath(c, options.path);
170
+
171
+ return paginateQuery<T>({
172
+ page,
173
+ perPage: perPageValue,
174
+ maxPerPage: options.maxPerPage,
175
+ path: resolvedPath,
176
+ total: async () => {
177
+ const inner = db.select({ val: sql`1` }).from(query.as("_inner"));
178
+ const [row] = await db.select({ total: count() }).from(inner);
179
+ return Number(row?.total ?? 0);
180
+ },
181
+ data: (limit, offset) => query.limit(limit).offset(offset)
182
+ });
183
+ }
184
+
185
+ /**
186
+ * Why: Pagination for Drizzle relational queries.
187
+ * When: Controllers need eager loading via `db.query.table.findMany({ with })`.
188
+ * Where: Use beside `paginate`; this targets model/relational API, not select builders.
189
+ * How: Counts the base table separately, then runs `findMany` with limit/offset.
190
+ */
191
+ export async function paginateModel<T = any>(c: RequestLike, options: PaginateModelOptions<T>): Promise<PaginatedResult<T>> {
192
+ const page = Number(c.req.query("page") || options.page || 1);
193
+ const size = c.req.query("size");
194
+ const perPageQuery = c.req.query("per_page");
195
+ const perPageValue = Number(size || perPageQuery || options.perPage || 15);
196
+ const resolvedPath = resolvePath(c, options.path);
197
+
198
+ return paginateQuery<T>({
199
+ page,
200
+ perPage: perPageValue,
201
+ maxPerPage: options.maxPerPage,
202
+ path: resolvedPath,
203
+ total: async () => {
204
+ if (options.total) return Number(await options.total());
205
+ if (!options.table) throw new Error("paginateModel requires either table or total callback");
206
+
207
+ let totalQuery = db.select({ total: count() }).from(options.table);
208
+ if (options.where) totalQuery = totalQuery.where(options.where);
209
+ const [row] = await totalQuery;
210
+ return Number(row?.total ?? 0);
211
+ },
212
+ data: async (limit, offset) => {
213
+ if (options.data) return options.data({ limit, offset });
214
+ if (!options.query) throw new Error("paginateModel requires either query or data callback");
215
+
216
+ const args: Record<string, any> = { limit, offset };
217
+ if (options.where) args.where = options.where;
218
+ if (options.with) args.with = options.with;
219
+ if (options.columns) args.columns = options.columns;
220
+ if (options.extras) args.extras = options.extras;
221
+ if (options.orderBy) args.orderBy = options.orderBy;
222
+
223
+ return options.query.findMany(args);
224
+ }
225
+ });
226
+ }
227
+
228
+ /**
229
+ * Why: Paginates a full table with optional filters/sorting.
230
+ * When: CRUD list endpoints need simple table pagination.
231
+ * Where: Service/controller code using table helpers.
232
+ * How: Runs total + paged select with where/order options.
233
+ */
234
+ export async function paginateTable<T = any>(db: any, table: any, options: PaginateOptions = {}): Promise<PaginatedResult<T>> {
235
+ return paginateQuery<T>({
236
+ page: options.page,
237
+ perPage: options.perPage,
238
+ maxPerPage: options.maxPerPage,
239
+ path: options.path,
240
+ total: async () => {
241
+ let totalQuery = db.select({ total: count() }).from(table);
242
+ if (options.where) totalQuery = totalQuery.where(options.where);
243
+ const totalRow = await totalQuery;
244
+ return Number(totalRow[0]?.total ?? 0);
245
+ },
246
+ data: async (limit, offset) => {
247
+ let dataQuery = db.select(getTableColumns(table)).from(table);
248
+ if (options.where) dataQuery = dataQuery.where(options.where);
249
+ if (options.orderBy?.length) dataQuery = dataQuery.orderBy(...options.orderBy);
250
+ return dataQuery.limit(limit).offset(offset);
251
+ }
252
+ });
253
+ }
@@ -42,7 +42,7 @@ function assertName(value, label) {
42
42
 
43
43
  function unsupported() {
44
44
  console.error(
45
- 'Drizzle Kit does not support Laravel-style rollback/refresh migrations. Use "npm run maker db:fresh -- --seed" (or "bun maker db:fresh --seed") for a SQLite development reset, or manage rollback SQL manually for production databases.'
45
+ 'Drizzle Kit does not support rollback/refresh migrations. Use "npm run maker db:fresh -- --seed" (or "bun maker db:fresh --seed") for a SQLite development reset, or manage rollback SQL manually for production databases.'
46
46
  );
47
47
  process.exit(1);
48
48
  }
@@ -69,7 +69,6 @@ const STUBS = {
69
69
  },
70
70
  controller: {
71
71
  openapi: "controller/openapi.ts.stub",
72
- openapiWithModel: "controller/openapi.with-model.ts.stub",
73
72
  plain: "controller/plain.ts.stub",
74
73
  schema: {
75
74
  openapi: "controller/schema.ts.stub",
@@ -6,7 +6,8 @@ import { registerDbCommands } from "./db/index.mjs";
6
6
  import { registerMiddlewareCommands } from "./middleware/index.mjs";
7
7
  import { registerModuleCommands } from "./module/index.mjs";
8
8
  import { registerRuntimeCommands } from "./runtime/index.mjs";
9
- import { makerCommandPrefix, showHelp } from "./utils/help.mjs";
9
+ import { configureGroupedHelp, makerCommandPrefix, showHelp } from "./utils/help.mjs";
10
+ import { registerProjectCommands } from "./utils/project-commands.mjs";
10
11
 
11
12
  const args = process.argv.slice(2);
12
13
  const [command] = args;
@@ -33,8 +34,11 @@ try {
33
34
  .name(namePrefix ? `${namePrefix} maker` : "maker")
34
35
  .allowUnknownOption(true)
35
36
  .allowExcessArguments(true)
36
- .helpOption("-h, --help")
37
- .addHelpText("beforeAll", "nexwire maker\n");
37
+ .helpOption("-h, --help");
38
+
39
+ // Grouped command list. Must be set before anything prints help. Per-command
40
+ // help is untouched, so `maker <command> --help` still uses commander's layout.
41
+ configureGroupedHelp(program);
38
42
 
39
43
  registerMiddlewareCommands(program, args);
40
44
  registerModuleCommands(program, args);
@@ -42,6 +46,12 @@ try {
42
46
  registerDbCommands(program, args);
43
47
  registerRuntimeCommands(program, args);
44
48
 
49
+ // The project's own commands come last, so a built-in always wins a name
50
+ // clash. Absent file is silent and free; a file that is present but broken
51
+ // throws, and the catch below reports it and exits rather than leaving the
52
+ // developer with commands that silently do not exist.
53
+ await registerProjectCommands(program, args);
54
+
45
55
  if (!command) {
46
56
  showHelp(program);
47
57
  } else {