@gencow/core 0.1.1 → 0.1.3

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/dist/index.d.ts CHANGED
@@ -4,8 +4,8 @@
4
4
  * Provides: query, mutation, storage, scheduler, auth
5
5
  * All with Convex-compatible DX patterns.
6
6
  */
7
- export type { GencowCtx, AuthCtx, UserIdentity, QueryDef, MutationDef, RealtimeCtx } from "./reactive";
8
- export { query, mutation, invalidateQueries, buildRealtimeCtx, subscribe, unsubscribe, registerClient, deregisterClient, handleWsMessage, getQueryHandler, getQueryDef, getRegisteredQueries, getRegisteredMutations } from "./reactive";
7
+ export type { GencowCtx, AuthCtx, UserIdentity, QueryDef, MutationDef, RealtimeCtx, HttpActionDef, HttpActionRequest, HttpActionResponse, HttpActionHandler } from "./reactive";
8
+ export { query, mutation, httpAction, invalidateQueries, buildRealtimeCtx, subscribe, unsubscribe, registerClient, deregisterClient, handleWsMessage, getQueryHandler, getQueryDef, getRegisteredQueries, getRegisteredMutations, getRegisteredHttpActions } from "./reactive";
9
9
  export type { Storage } from "./storage";
10
10
  export { createScheduler, getSchedulerInfo } from "./scheduler";
11
11
  export type { Scheduler } from "./scheduler";
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Provides: query, mutation, storage, scheduler, auth
5
5
  * All with Convex-compatible DX patterns.
6
6
  */
7
- export { query, mutation, invalidateQueries, buildRealtimeCtx, subscribe, unsubscribe, registerClient, deregisterClient, handleWsMessage, getQueryHandler, getQueryDef, getRegisteredQueries, getRegisteredMutations } from "./reactive";
7
+ export { query, mutation, httpAction, invalidateQueries, buildRealtimeCtx, subscribe, unsubscribe, registerClient, deregisterClient, handleWsMessage, getQueryHandler, getQueryDef, getRegisteredQueries, getRegisteredMutations, getRegisteredHttpActions } from "./reactive";
8
8
  export { createScheduler, getSchedulerInfo } from "./scheduler";
9
9
  export { v, parseArgs, GencowValidationError } from "./v";
10
10
  export { withRetry } from "./retry";
@@ -49,6 +49,38 @@ export interface GencowCtx {
49
49
  }
50
50
  type QueryHandler<TArgs = any, TReturn = any> = (ctx: GencowCtx, args: TArgs) => Promise<TReturn>;
51
51
  type MutationHandler<TArgs = any, TReturn = any> = (ctx: GencowCtx, args: TArgs) => Promise<TReturn>;
52
+ /**
53
+ * httpAction 핸들러의 Request/Response 타입.
54
+ * Hono의 Context를 직접 받아 full HTTP 제어 가능.
55
+ */
56
+ export type HttpActionHandler = (ctx: GencowCtx, req: HttpActionRequest) => Promise<HttpActionResponse>;
57
+ export interface HttpActionRequest {
58
+ /** HTTP method (GET, POST, PUT, DELETE, PATCH) */
59
+ method: string;
60
+ /** Full URL */
61
+ url: string;
62
+ /** URL path (e.g. /api/cli/auth-start) */
63
+ path: string;
64
+ /** Route params (e.g. { id: "abc" } for /api/apps/:id) */
65
+ params: Record<string, string>;
66
+ /** Query string params */
67
+ query: Record<string, string>;
68
+ /** Request headers */
69
+ headers: Record<string, string>;
70
+ /** Parse JSON body */
71
+ json: <T = unknown>() => Promise<T>;
72
+ /** Parse form data */
73
+ formData: () => Promise<FormData>;
74
+ /** Raw body as ArrayBuffer */
75
+ arrayBuffer: () => Promise<ArrayBuffer>;
76
+ /** Raw body as text */
77
+ text: () => Promise<string>;
78
+ }
79
+ export interface HttpActionResponse {
80
+ status?: number;
81
+ headers?: Record<string, string>;
82
+ body?: unknown;
83
+ }
52
84
  export interface QueryDef<TSchema = any, TReturn = any> {
53
85
  key: string;
54
86
  handler: QueryHandler<InferArgs<TSchema>, TReturn>;
@@ -67,6 +99,17 @@ export interface MutationDef<TSchema = any, TReturn = any> {
67
99
  _args?: InferArgs<TSchema>;
68
100
  _return?: TReturn;
69
101
  }
102
+ /** httpAction 정의. 커스텀 HTTP 엔드포인트를 선언적으로 등록. */
103
+ export interface HttpActionDef {
104
+ /** HTTP method */
105
+ method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
106
+ /** URL path (Hono 패턴 — /api/cli/:code 형태 지원) */
107
+ path: string;
108
+ /** true = 인증 없이 접근 가능, false(기본) = auth 필수 */
109
+ isPublic: boolean;
110
+ /** 핸들러 */
111
+ handler: HttpActionHandler;
112
+ }
70
113
  declare global {
71
114
  var __gencow_queryRegistry: Map<string, QueryDef<any, any>>;
72
115
  var __gencow_mutationRegistry: (MutationDef<any, any> & {
@@ -74,6 +117,7 @@ declare global {
74
117
  })[];
75
118
  var __gencow_subscribers: Map<string, Set<WSContext>>;
76
119
  var __gencow_connectedClients: Set<WSContext>;
120
+ var __gencow_httpActionRegistry: HttpActionDef[];
77
121
  }
78
122
  export declare function query<TSchema = any, TReturn = any>(key: string, handlerOrDef: QueryHandler<InferArgs<TSchema>, TReturn> | {
79
123
  args?: TSchema;
@@ -87,6 +131,38 @@ export declare function mutation<TSchema = any, TReturn = any>(invalidatesOrDef:
87
131
  invalidates: string[];
88
132
  handler: MutationHandler<InferArgs<TSchema>, TReturn>;
89
133
  }, handler?: MutationHandler<InferArgs<TSchema>, TReturn>, name?: string): MutationDef<TSchema, TReturn>;
134
+ /**
135
+ * 커스텀 HTTP 엔드포인트를 선언적으로 등록합니다.
136
+ * query/mutation은 RPC 패턴이지만, httpAction은 RESTful HTTP 라우트를 직접 정의합니다.
137
+ *
138
+ * 사용 사례:
139
+ * - CLI Device Auth (POST /api/cli/auth-start)
140
+ * - 파일 업로드 (POST /api/apps/:id/deploy)
141
+ * - Webhook 수신
142
+ * - 외부 서비스 콜백
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * import { httpAction } from "@gencow/core";
147
+ *
148
+ * export const authStart = httpAction({
149
+ * method: "POST",
150
+ * path: "/api/cli/auth-start",
151
+ * public: true,
152
+ * handler: async (ctx, req) => {
153
+ * const code = crypto.randomUUID().slice(0, 8);
154
+ * return { body: { code, url: `https://gencow.com/cli-auth?code=${code}` } };
155
+ * },
156
+ * });
157
+ * ```
158
+ */
159
+ export declare function httpAction(def: {
160
+ method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
161
+ path: string;
162
+ public?: boolean;
163
+ handler: HttpActionHandler;
164
+ }): HttpActionDef;
165
+ export declare function getRegisteredHttpActions(): HttpActionDef[];
90
166
  export declare function subscribe(queryKey: string, ws: WSContext): void;
91
167
  export declare function unsubscribe(ws: WSContext): void;
92
168
  /** Register a raw WS connection without any query subscription (e.g. admin dashboard) */
package/dist/reactive.js CHANGED
@@ -6,8 +6,11 @@ if (!globalThis.__gencow_subscribers)
6
6
  globalThis.__gencow_subscribers = new Map();
7
7
  if (!globalThis.__gencow_connectedClients)
8
8
  globalThis.__gencow_connectedClients = new Set();
9
+ if (!globalThis.__gencow_httpActionRegistry)
10
+ globalThis.__gencow_httpActionRegistry = [];
9
11
  const queryRegistry = globalThis.__gencow_queryRegistry;
10
12
  const mutationRegistry = globalThis.__gencow_mutationRegistry;
13
+ const httpActionRegistry = globalThis.__gencow_httpActionRegistry;
11
14
  const subscribers = globalThis.__gencow_subscribers;
12
15
  /**
13
16
  * Every WebSocket client that ever establishes a connection is tracked here.
@@ -63,6 +66,45 @@ export function mutation(invalidatesOrDef, handler, name) {
63
66
  mutationRegistry.push(def);
64
67
  return def;
65
68
  }
69
+ // ─── httpAction (커스텀 HTTP 엔드포인트) ────────────────
70
+ /**
71
+ * 커스텀 HTTP 엔드포인트를 선언적으로 등록합니다.
72
+ * query/mutation은 RPC 패턴이지만, httpAction은 RESTful HTTP 라우트를 직접 정의합니다.
73
+ *
74
+ * 사용 사례:
75
+ * - CLI Device Auth (POST /api/cli/auth-start)
76
+ * - 파일 업로드 (POST /api/apps/:id/deploy)
77
+ * - Webhook 수신
78
+ * - 외부 서비스 콜백
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * import { httpAction } from "@gencow/core";
83
+ *
84
+ * export const authStart = httpAction({
85
+ * method: "POST",
86
+ * path: "/api/cli/auth-start",
87
+ * public: true,
88
+ * handler: async (ctx, req) => {
89
+ * const code = crypto.randomUUID().slice(0, 8);
90
+ * return { body: { code, url: `https://gencow.com/cli-auth?code=${code}` } };
91
+ * },
92
+ * });
93
+ * ```
94
+ */
95
+ export function httpAction(def) {
96
+ const actionDef = {
97
+ method: def.method,
98
+ path: def.path,
99
+ isPublic: def.public === true,
100
+ handler: def.handler,
101
+ };
102
+ httpActionRegistry.push(actionDef);
103
+ return actionDef;
104
+ }
105
+ export function getRegisteredHttpActions() {
106
+ return [...httpActionRegistry];
107
+ }
66
108
  // ─── WebSocket subscription management ──────────────────
67
109
  export function subscribe(queryKey, ws) {
68
110
  connectedClients.add(ws);
package/package.json CHANGED
@@ -1,39 +1,38 @@
1
1
  {
2
- "name": "@gencow/core",
3
- "version": "0.1.1",
4
- "description": "Gencow core library — defineQuery, defineMutation, reactive subscriptions",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "import": "./dist/index.js",
11
- "types": "./dist/index.d.ts"
12
- },
13
- "./server": {
14
- "import": "./dist/server.js",
15
- "types": "./dist/server.d.ts"
16
- }
2
+ "name": "@gencow/core",
3
+ "version": "0.1.3",
4
+ "description": "Gencow core library — defineQuery, defineMutation, reactive subscriptions",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
17
12
  },
18
- "files": [
19
- "dist/",
20
- "src/"
21
- ],
22
- "scripts": {
23
- "build": "tsc",
24
- "typecheck": "tsc --noEmit",
25
- "prepublishOnly": "npm run build"
26
- },
27
- "dependencies": {
28
- "@electric-sql/pglite": "^0.3.15",
29
- "drizzle-orm": "^0.45.1",
30
- "hono": "^4.12.0",
31
- "node-cron": "^4.2.1"
32
- },
33
- "devDependencies": {
34
- "@types/bun": "^1.3.9",
35
- "@types/node": "^25.3.0",
36
- "@types/node-cron": "^3.0.11",
37
- "typescript": "^5.9.3"
13
+ "./server": {
14
+ "import": "./dist/server.js",
15
+ "types": "./dist/server.d.ts"
38
16
  }
17
+ },
18
+ "files": [
19
+ "dist/",
20
+ "src/"
21
+ ],
22
+ "dependencies": {
23
+ "@electric-sql/pglite": "^0.3.15",
24
+ "drizzle-orm": "^0.45.1",
25
+ "hono": "^4.12.0",
26
+ "node-cron": "^4.2.1"
27
+ },
28
+ "devDependencies": {
29
+ "@types/bun": "^1.3.9",
30
+ "@types/node": "^25.3.0",
31
+ "@types/node-cron": "^3.0.11",
32
+ "typescript": "^5.9.3"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc",
36
+ "typecheck": "tsc --noEmit"
37
+ }
39
38
  }
package/src/index.ts CHANGED
@@ -5,8 +5,8 @@
5
5
  * All with Convex-compatible DX patterns.
6
6
  */
7
7
 
8
- export type { GencowCtx, AuthCtx, UserIdentity, QueryDef, MutationDef, RealtimeCtx } from "./reactive";
9
- export { query, mutation, invalidateQueries, buildRealtimeCtx, subscribe, unsubscribe, registerClient, deregisterClient, handleWsMessage, getQueryHandler, getQueryDef, getRegisteredQueries, getRegisteredMutations } from "./reactive";
8
+ export type { GencowCtx, AuthCtx, UserIdentity, QueryDef, MutationDef, RealtimeCtx, HttpActionDef, HttpActionRequest, HttpActionResponse, HttpActionHandler } from "./reactive";
9
+ export { query, mutation, httpAction, invalidateQueries, buildRealtimeCtx, subscribe, unsubscribe, registerClient, deregisterClient, handleWsMessage, getQueryHandler, getQueryDef, getRegisteredQueries, getRegisteredMutations, getRegisteredHttpActions } from "./reactive";
10
10
  export type { Storage } from "./storage";
11
11
  export { createScheduler, getSchedulerInfo } from "./scheduler";
12
12
  export type { Scheduler } from "./scheduler";
package/src/reactive.ts CHANGED
@@ -61,6 +61,41 @@ type QueryHandler<TArgs = any, TReturn = any> = (ctx: GencowCtx, args: TArgs) =>
61
61
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
62
  type MutationHandler<TArgs = any, TReturn = any> = (ctx: GencowCtx, args: TArgs) => Promise<TReturn>;
63
63
 
64
+ /**
65
+ * httpAction 핸들러의 Request/Response 타입.
66
+ * Hono의 Context를 직접 받아 full HTTP 제어 가능.
67
+ */
68
+ export type HttpActionHandler = (ctx: GencowCtx, req: HttpActionRequest) => Promise<HttpActionResponse>;
69
+
70
+ export interface HttpActionRequest {
71
+ /** HTTP method (GET, POST, PUT, DELETE, PATCH) */
72
+ method: string;
73
+ /** Full URL */
74
+ url: string;
75
+ /** URL path (e.g. /api/cli/auth-start) */
76
+ path: string;
77
+ /** Route params (e.g. { id: "abc" } for /api/apps/:id) */
78
+ params: Record<string, string>;
79
+ /** Query string params */
80
+ query: Record<string, string>;
81
+ /** Request headers */
82
+ headers: Record<string, string>;
83
+ /** Parse JSON body */
84
+ json: <T = unknown>() => Promise<T>;
85
+ /** Parse form data */
86
+ formData: () => Promise<FormData>;
87
+ /** Raw body as ArrayBuffer */
88
+ arrayBuffer: () => Promise<ArrayBuffer>;
89
+ /** Raw body as text */
90
+ text: () => Promise<string>;
91
+ }
92
+
93
+ export interface HttpActionResponse {
94
+ status?: number;
95
+ headers?: Record<string, string>;
96
+ body?: unknown;
97
+ }
98
+
64
99
  export interface QueryDef<TSchema = any, TReturn = any> {
65
100
  key: string;
66
101
  handler: QueryHandler<InferArgs<TSchema>, TReturn>;
@@ -81,6 +116,18 @@ export interface MutationDef<TSchema = any, TReturn = any> {
81
116
  _return?: TReturn;
82
117
  }
83
118
 
119
+ /** httpAction 정의. 커스텀 HTTP 엔드포인트를 선언적으로 등록. */
120
+ export interface HttpActionDef {
121
+ /** HTTP method */
122
+ method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
123
+ /** URL path (Hono 패턴 — /api/cli/:code 형태 지원) */
124
+ path: string;
125
+ /** true = 인증 없이 접근 가능, false(기본) = auth 필수 */
126
+ isPublic: boolean;
127
+ /** 핸들러 */
128
+ handler: HttpActionHandler;
129
+ }
130
+
84
131
  // ─── Registry ───────────────────────────────────────────
85
132
  //
86
133
  // globalThis 기반 — 서버 번들(인라인)과 node_modules/@gencow/core 양쪽에서
@@ -96,15 +143,19 @@ declare global {
96
143
  var __gencow_subscribers: Map<string, Set<WSContext>>;
97
144
  // eslint-disable-next-line no-var
98
145
  var __gencow_connectedClients: Set<WSContext>;
146
+ // eslint-disable-next-line no-var
147
+ var __gencow_httpActionRegistry: HttpActionDef[];
99
148
  }
100
149
 
101
150
  if (!globalThis.__gencow_queryRegistry) globalThis.__gencow_queryRegistry = new Map();
102
151
  if (!globalThis.__gencow_mutationRegistry) globalThis.__gencow_mutationRegistry = [];
103
152
  if (!globalThis.__gencow_subscribers) globalThis.__gencow_subscribers = new Map();
104
153
  if (!globalThis.__gencow_connectedClients) globalThis.__gencow_connectedClients = new Set();
154
+ if (!globalThis.__gencow_httpActionRegistry) globalThis.__gencow_httpActionRegistry = [];
105
155
 
106
156
  const queryRegistry = globalThis.__gencow_queryRegistry;
107
157
  const mutationRegistry = globalThis.__gencow_mutationRegistry;
158
+ const httpActionRegistry = globalThis.__gencow_httpActionRegistry;
108
159
  const subscribers = globalThis.__gencow_subscribers;
109
160
 
110
161
  /**
@@ -174,6 +225,53 @@ export function mutation<TSchema = any, TReturn = any>(
174
225
  return def;
175
226
  }
176
227
 
228
+ // ─── httpAction (커스텀 HTTP 엔드포인트) ────────────────
229
+
230
+ /**
231
+ * 커스텀 HTTP 엔드포인트를 선언적으로 등록합니다.
232
+ * query/mutation은 RPC 패턴이지만, httpAction은 RESTful HTTP 라우트를 직접 정의합니다.
233
+ *
234
+ * 사용 사례:
235
+ * - CLI Device Auth (POST /api/cli/auth-start)
236
+ * - 파일 업로드 (POST /api/apps/:id/deploy)
237
+ * - Webhook 수신
238
+ * - 외부 서비스 콜백
239
+ *
240
+ * @example
241
+ * ```typescript
242
+ * import { httpAction } from "@gencow/core";
243
+ *
244
+ * export const authStart = httpAction({
245
+ * method: "POST",
246
+ * path: "/api/cli/auth-start",
247
+ * public: true,
248
+ * handler: async (ctx, req) => {
249
+ * const code = crypto.randomUUID().slice(0, 8);
250
+ * return { body: { code, url: `https://gencow.com/cli-auth?code=${code}` } };
251
+ * },
252
+ * });
253
+ * ```
254
+ */
255
+ export function httpAction(def: {
256
+ method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
257
+ path: string;
258
+ public?: boolean;
259
+ handler: HttpActionHandler;
260
+ }): HttpActionDef {
261
+ const actionDef: HttpActionDef = {
262
+ method: def.method,
263
+ path: def.path,
264
+ isPublic: def.public === true,
265
+ handler: def.handler,
266
+ };
267
+ httpActionRegistry.push(actionDef);
268
+ return actionDef;
269
+ }
270
+
271
+ export function getRegisteredHttpActions(): HttpActionDef[] {
272
+ return [...httpActionRegistry];
273
+ }
274
+
177
275
  // ─── WebSocket subscription management ──────────────────
178
276
 
179
277
  export function subscribe(queryKey: string, ws: WSContext) {