@nubase/create 0.1.24 → 0.1.25

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nubase/create",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "description": "Create a new Nubase application",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,34 @@
1
+ import { createHandlerFactory } from "@nubase/backend";
2
+ import { apiEndpoints, type ApiEndpoints } from "schema";
3
+ import type { __PROJECT_NAME_PASCAL__User } from "../auth";
4
+
5
+ /**
6
+ * Pre-configured handler factory for __PROJECT_NAME_PASCAL__.
7
+ *
8
+ * This factory pre-binds:
9
+ * - The apiEndpoints object for endpoint schema inference
10
+ * - The __PROJECT_NAME_PASCAL__User type for authenticated handlers
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // Required auth - user is guaranteed to be __PROJECT_NAME_PASCAL__User
15
+ * getTickets: createHandler((e) => e.getTickets, {
16
+ * auth: "required",
17
+ * handler: async ({ params, user, ctx }) => { ... },
18
+ * }),
19
+ *
20
+ * // No auth (default) - no user in handler
21
+ * loginStart: createHandler((e) => e.loginStart, {
22
+ * handler: async ({ body }) => { ... },
23
+ * }),
24
+ *
25
+ * // Optional auth - user may be null
26
+ * getMe: createHandler((e) => e.getMe, {
27
+ * auth: "optional",
28
+ * handler: async ({ user }) => { ... },
29
+ * }),
30
+ * ```
31
+ */
32
+ export const createHandler = createHandlerFactory<ApiEndpoints, __PROJECT_NAME_PASCAL__User>({
33
+ endpoints: apiEndpoints,
34
+ });
@@ -1,20 +1,15 @@
1
- import {
2
- createHttpHandler,
3
- getAuthController,
4
- HttpError,
5
- } from "@nubase/backend";
1
+ import { getAuthController, HttpError } from "@nubase/backend";
6
2
  import bcrypt from "bcrypt";
7
3
  import { and, eq, inArray } from "drizzle-orm";
8
- import { apiEndpoints } from "schema";
9
4
  import jwt from "jsonwebtoken";
10
5
  import type { __PROJECT_NAME_PASCAL__User } from "../../auth";
11
6
  import { getAdminDb } from "../../db/helpers/drizzle";
12
7
  import { users, userWorkspaces, workspaces } from "../../db/schema";
8
+ import { createHandler } from "../handler-factory";
13
9
 
14
10
  // Short-lived secret for login tokens (in production, use a proper secret)
15
11
  const LOGIN_TOKEN_SECRET =
16
- process.env.LOGIN_TOKEN_SECRET ||
17
- "nubase-login-token-secret-change-in-production";
12
+ process.env.LOGIN_TOKEN_SECRET || "nubase-login-token-secret-change-in-production";
18
13
  const LOGIN_TOKEN_EXPIRY = "5m"; // 5 minutes to complete workspace selection
19
14
 
20
15
  interface LoginTokenPayload {
@@ -27,8 +22,7 @@ export const authHandlers = {
27
22
  * Login Start handler - Step 1 of two-step auth.
28
23
  * Validates credentials and returns list of workspaces.
29
24
  */
30
- loginStart: createHttpHandler({
31
- endpoint: apiEndpoints.loginStart,
25
+ loginStart: createHandler((e) => e.loginStart, {
32
26
  handler: async ({ body }) => {
33
27
  // Find user by email
34
28
  const [user] = await getAdminDb()
@@ -41,10 +35,7 @@ export const authHandlers = {
41
35
  }
42
36
 
43
37
  // Verify password
44
- const isValidPassword = await bcrypt.compare(
45
- body.password,
46
- user.passwordHash,
47
- );
38
+ const isValidPassword = await bcrypt.compare(body.password, user.passwordHash);
48
39
  if (!isValidPassword) {
49
40
  throw new HttpError(401, "Invalid email or password");
50
41
  }
@@ -92,18 +83,14 @@ export const authHandlers = {
92
83
  * Login Complete handler - Step 2 of two-step auth.
93
84
  * Validates the login token and selected workspace.
94
85
  */
95
- loginComplete: createHttpHandler({
96
- endpoint: apiEndpoints.loginComplete,
86
+ loginComplete: createHandler((e) => e.loginComplete, {
97
87
  handler: async ({ body, ctx }) => {
98
88
  const authController = getAuthController<__PROJECT_NAME_PASCAL__User>(ctx);
99
89
 
100
90
  // Verify the login token
101
91
  let decoded: LoginTokenPayload;
102
92
  try {
103
- decoded = jwt.verify(
104
- body.loginToken,
105
- LOGIN_TOKEN_SECRET,
106
- ) as LoginTokenPayload;
93
+ decoded = jwt.verify(body.loginToken, LOGIN_TOKEN_SECRET) as LoginTokenPayload;
107
94
  } catch {
108
95
  throw new HttpError(401, "Invalid or expired login token");
109
96
  }
@@ -174,8 +161,7 @@ export const authHandlers = {
174
161
  * Legacy Login handler - validates credentials and sets HttpOnly cookie.
175
162
  * @deprecated Use loginStart and loginComplete for two-step flow
176
163
  */
177
- login: createHttpHandler({
178
- endpoint: apiEndpoints.login,
164
+ login: createHandler((e) => e.login, {
179
165
  handler: async ({ body, ctx }) => {
180
166
  const authController = getAuthController<__PROJECT_NAME_PASCAL__User>(ctx);
181
167
 
@@ -200,10 +186,7 @@ export const authHandlers = {
200
186
  }
201
187
 
202
188
  // Verify password
203
- const isValidPassword = await bcrypt.compare(
204
- body.password,
205
- dbUser.passwordHash,
206
- );
189
+ const isValidPassword = await bcrypt.compare(body.password, dbUser.passwordHash);
207
190
  if (!isValidPassword) {
208
191
  throw new HttpError(401, "Invalid email or password");
209
192
  }
@@ -246,8 +229,7 @@ export const authHandlers = {
246
229
  }),
247
230
 
248
231
  /** Logout handler - clears the auth cookie. */
249
- logout: createHttpHandler({
250
- endpoint: apiEndpoints.logout,
232
+ logout: createHandler((e) => e.logout, {
251
233
  handler: async ({ ctx }) => {
252
234
  const authController = getAuthController(ctx);
253
235
  authController.clearTokenFromResponse(ctx);
@@ -256,12 +238,7 @@ export const authHandlers = {
256
238
  }),
257
239
 
258
240
  /** Get current user handler. */
259
- getMe: createHttpHandler<
260
- typeof apiEndpoints.getMe,
261
- "optional",
262
- __PROJECT_NAME_PASCAL__User
263
- >({
264
- endpoint: apiEndpoints.getMe,
241
+ getMe: createHandler((e) => e.getMe, {
265
242
  auth: "optional",
266
243
  handler: async ({ user }) => {
267
244
  if (!user) {
@@ -279,8 +256,7 @@ export const authHandlers = {
279
256
  }),
280
257
 
281
258
  /** Signup handler - creates a new workspace and admin user. */
282
- signup: createHttpHandler({
283
- endpoint: apiEndpoints.signup,
259
+ signup: createHandler((e) => e.signup, {
284
260
  handler: async ({ body, ctx }) => {
285
261
  const authController = getAuthController<__PROJECT_NAME_PASCAL__User>(ctx);
286
262
 
@@ -1,5 +1,4 @@
1
- import { createHttpHandler } from "@nubase/backend";
2
- import { apiEndpoints } from "schema";
1
+ import { createHandler } from "../handler-factory";
3
2
 
4
3
  /**
5
4
  * Dashboard widget endpoints.
@@ -7,8 +6,7 @@ import { apiEndpoints } from "schema";
7
6
  */
8
7
  export const dashboardHandlers = {
9
8
  /** Revenue chart - returns series data for area/line/bar charts. */
10
- getRevenueChart: createHttpHandler({
11
- endpoint: apiEndpoints.getRevenueChart,
9
+ getRevenueChart: createHandler((e) => e.getRevenueChart, {
12
10
  handler: async () => ({
13
11
  type: "series",
14
12
  config: {
@@ -26,8 +24,7 @@ export const dashboardHandlers = {
26
24
  }),
27
25
 
28
26
  /** Browser stats - returns proportional data for pie/donut charts. */
29
- getBrowserStats: createHttpHandler({
30
- endpoint: apiEndpoints.getBrowserStats,
27
+ getBrowserStats: createHandler((e) => e.getBrowserStats, {
31
28
  handler: async () => ({
32
29
  type: "proportional",
33
30
  data: [
@@ -41,8 +38,7 @@ export const dashboardHandlers = {
41
38
  }),
42
39
 
43
40
  /** Total revenue KPI - returns single value with trend. */
44
- getTotalRevenue: createHttpHandler({
45
- endpoint: apiEndpoints.getTotalRevenue,
41
+ getTotalRevenue: createHandler((e) => e.getTotalRevenue, {
46
42
  handler: async () => ({
47
43
  type: "kpi",
48
44
  value: "$45,231.89",
@@ -53,8 +49,7 @@ export const dashboardHandlers = {
53
49
  }),
54
50
 
55
51
  /** Active users KPI - returns single value with trend. */
56
- getActiveUsers: createHttpHandler({
57
- endpoint: apiEndpoints.getActiveUsers,
52
+ getActiveUsers: createHandler((e) => e.getActiveUsers, {
58
53
  handler: async () => ({
59
54
  type: "kpi",
60
55
  value: "+2,350",
@@ -65,8 +60,7 @@ export const dashboardHandlers = {
65
60
  }),
66
61
 
67
62
  /** Sales chart - returns series data for bar charts. */
68
- getSalesChart: createHttpHandler({
69
- endpoint: apiEndpoints.getSalesChart,
63
+ getSalesChart: createHandler((e) => e.getSalesChart, {
70
64
  handler: async () => ({
71
65
  type: "series",
72
66
  config: {
@@ -85,8 +79,7 @@ export const dashboardHandlers = {
85
79
  }),
86
80
 
87
81
  /** Recent activity - returns table data. */
88
- getRecentActivity: createHttpHandler({
89
- endpoint: apiEndpoints.getRecentActivity,
82
+ getRecentActivity: createHandler((e) => e.getRecentActivity, {
90
83
  handler: async () => ({
91
84
  type: "table",
92
85
  columns: [
@@ -1,13 +1,12 @@
1
- import { createHttpHandler, HttpError } from "@nubase/backend";
1
+ import { HttpError } from "@nubase/backend";
2
2
  import type { SQL } from "drizzle-orm";
3
3
  import { and, eq, ilike, inArray, or } from "drizzle-orm";
4
- import { apiEndpoints } from "schema";
5
4
  import { getDb } from "../../db/helpers/drizzle";
6
5
  import { tickets } from "../../db/schema";
6
+ import { createHandler } from "../handler-factory";
7
7
 
8
8
  export const ticketHandlers = {
9
- getTickets: createHttpHandler({
10
- endpoint: apiEndpoints.getTickets,
9
+ getTickets: createHandler((e) => e.getTickets, {
11
10
  handler: async ({ params }) => {
12
11
  const db = getDb();
13
12
 
@@ -64,8 +63,7 @@ export const ticketHandlers = {
64
63
  },
65
64
  }),
66
65
 
67
- getTicket: createHttpHandler({
68
- endpoint: apiEndpoints.getTicket,
66
+ getTicket: createHandler((e) => e.getTicket, {
69
67
  handler: async ({ params }) => {
70
68
  const [ticket] = await getDb()
71
69
  .select()
@@ -85,8 +83,7 @@ export const ticketHandlers = {
85
83
  },
86
84
  }),
87
85
 
88
- postTicket: createHttpHandler({
89
- endpoint: apiEndpoints.postTicket,
86
+ postTicket: createHandler((e) => e.postTicket, {
90
87
  handler: async ({ body }) => {
91
88
  const [ticket] = await getDb()
92
89
  .insert(tickets)
@@ -111,8 +108,7 @@ export const ticketHandlers = {
111
108
  },
112
109
  }),
113
110
 
114
- patchTicket: createHttpHandler({
115
- endpoint: apiEndpoints.patchTicket,
111
+ patchTicket: createHandler((e) => e.patchTicket, {
116
112
  handler: async ({ params, body }) => {
117
113
  const updateData: {
118
114
  title?: string;
@@ -152,8 +148,7 @@ export const ticketHandlers = {
152
148
  },
153
149
  }),
154
150
 
155
- deleteTicket: createHttpHandler({
156
- endpoint: apiEndpoints.deleteTicket,
151
+ deleteTicket: createHandler((e) => e.deleteTicket, {
157
152
  handler: async ({ params }) => {
158
153
  const [deleted] = await getDb()
159
154
  .delete(tickets)
@@ -1,14 +1,13 @@
1
- import { createHttpHandler, HttpError } from "@nubase/backend";
1
+ import { HttpError } from "@nubase/backend";
2
2
  import type { SQL } from "drizzle-orm";
3
3
  import { and, eq, ilike, or } from "drizzle-orm";
4
- import { apiEndpoints } from "schema";
5
4
  import { getDb } from "../../db/helpers/drizzle";
6
5
  import { users } from "../../db/schema";
6
+ import { createHandler } from "../handler-factory";
7
7
 
8
8
  export const userHandlers = {
9
9
  /** Get all users with optional filters. */
10
- getUsers: createHttpHandler({
11
- endpoint: apiEndpoints.getUsers,
10
+ getUsers: createHandler((e) => e.getUsers, {
12
11
  handler: async ({ params }) => {
13
12
  const db = getDb();
14
13
 
@@ -53,8 +52,7 @@ export const userHandlers = {
53
52
  }),
54
53
 
55
54
  /** Get a single user by ID. */
56
- getUser: createHttpHandler({
57
- endpoint: apiEndpoints.getUser,
55
+ getUser: createHandler((e) => e.getUser, {
58
56
  handler: async ({ params }) => {
59
57
  const db = getDb();
60
58
  const [user] = await db.select().from(users).where(eq(users.id, params.id));
@@ -72,8 +70,7 @@ export const userHandlers = {
72
70
  }),
73
71
 
74
72
  /** Create a new user. */
75
- postUser: createHttpHandler({
76
- endpoint: apiEndpoints.postUser,
73
+ postUser: createHandler((e) => e.postUser, {
77
74
  handler: async ({ body }) => {
78
75
  const db = getDb();
79
76
 
@@ -106,8 +103,7 @@ export const userHandlers = {
106
103
  }),
107
104
 
108
105
  /** Update a user by ID. */
109
- patchUser: createHttpHandler({
110
- endpoint: apiEndpoints.patchUser,
106
+ patchUser: createHandler((e) => e.patchUser, {
111
107
  handler: async ({ params, body }) => {
112
108
  const db = getDb();
113
109
 
@@ -138,8 +134,7 @@ export const userHandlers = {
138
134
  }),
139
135
 
140
136
  /** Delete a user by ID. */
141
- deleteUser: createHttpHandler({
142
- endpoint: apiEndpoints.deleteUser,
137
+ deleteUser: createHandler((e) => e.deleteUser, {
143
138
  handler: async ({ params }) => {
144
139
  const db = getDb();
145
140
 
@@ -154,8 +149,7 @@ export const userHandlers = {
154
149
  }),
155
150
 
156
151
  /** Lookup users for select/autocomplete fields. */
157
- lookupUsers: createHttpHandler({
158
- endpoint: apiEndpoints.lookupUsers,
152
+ lookupUsers: createHandler((e) => e.lookupUsers, {
159
153
  handler: async ({ params }) => {
160
154
  const db = getDb();
161
155