@gencow/core 0.1.28 → 0.1.30
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/auth-config.d.ts +92 -5
- package/dist/config.d.ts +107 -0
- package/dist/config.js +12 -0
- package/dist/context.d.ts +139 -0
- package/dist/context.js +3 -0
- package/dist/crud.d.ts +5 -5
- package/dist/crud.js +19 -35
- package/dist/document-types.d.ts +2 -2
- package/dist/http-action.d.ts +77 -0
- package/dist/http-action.js +41 -0
- package/dist/index.d.ts +21 -5
- package/dist/index.js +12 -3
- package/dist/platform-capacity-profile.d.ts +19 -0
- package/dist/platform-capacity-profile.js +94 -0
- package/dist/procedure.d.ts +58 -0
- package/dist/procedure.js +115 -0
- package/dist/rag-schema.d.ts +449 -540
- package/dist/reactive-mutation-types.d.ts +11 -0
- package/dist/reactive-mutation-types.js +1 -0
- package/dist/reactive-mutation.d.ts +51 -0
- package/dist/reactive-mutation.js +75 -0
- package/dist/reactive-query-types.d.ts +12 -0
- package/dist/reactive-query-types.js +1 -0
- package/dist/reactive-query.d.ts +14 -0
- package/dist/reactive-query.js +28 -0
- package/dist/reactive-realtime.d.ts +48 -0
- package/dist/reactive-realtime.js +236 -0
- package/dist/reactive.d.ts +16 -5
- package/dist/reactive.js +65 -0
- package/dist/runtime-env-policy.js +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/storage-metering.d.ts +13 -0
- package/dist/storage-metering.js +18 -0
- package/dist/storage.d.ts +3 -1
- package/dist/storage.js +11 -7
- package/dist/wake-app-result.d.ts +22 -0
- package/dist/wake-app-result.js +11 -0
- package/dist/workflow-json.d.ts +2 -0
- package/dist/workflow-json.js +5 -0
- package/dist/workflow-types.d.ts +13 -1
- package/dist/workflow.d.ts +1 -1
- package/dist/workflow.js +135 -12
- package/dist/workflows-api.js +72 -3
- package/package.json +4 -1
- package/src/auth-config.ts +104 -3
- package/src/config.ts +119 -0
- package/src/context.ts +152 -0
- package/src/crud.ts +18 -35
- package/src/document-types.ts +9 -2
- package/src/http-action.ts +101 -0
- package/src/index.ts +77 -19
- package/src/platform-capacity-profile.ts +114 -0
- package/src/procedure.ts +283 -0
- package/src/reactive-mutation-types.ts +13 -0
- package/src/reactive-mutation.ts +115 -0
- package/src/reactive-query-types.ts +14 -0
- package/src/reactive-query.ts +48 -0
- package/src/reactive-realtime.ts +267 -0
- package/src/runtime-env-policy.ts +1 -1
- package/src/server.ts +6 -1
- package/src/storage-metering.ts +35 -0
- package/src/storage.ts +14 -6
- package/src/wake-app-result.ts +37 -0
- package/src/workflow-json.ts +6 -0
- package/src/workflow-types.ts +13 -1
- package/src/workflow.ts +163 -13
- package/src/workflows-api.ts +83 -3
- package/src/reactive.ts +0 -593
package/src/config.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-facing project configuration for `gencow.config.ts`.
|
|
3
|
+
*
|
|
4
|
+
* The config file is intentionally small today, but we expose a stable typed
|
|
5
|
+
* contract so editors can offer autocomplete and inline explanations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Cloud deployment settings written to `gencow.config.ts`.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* deploy: {
|
|
14
|
+
* app: "my-todo",
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export interface GencowDeployConfig {
|
|
19
|
+
/**
|
|
20
|
+
* Default cloud app name to target for CLI flows that attach project metadata.
|
|
21
|
+
*
|
|
22
|
+
* This is commonly added automatically after `gencow app create`.
|
|
23
|
+
*/
|
|
24
|
+
app?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Local database settings for the Gencow dev server.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* db: {
|
|
33
|
+
* url: "./.gencow/data",
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export interface GencowDbConfig {
|
|
38
|
+
/**
|
|
39
|
+
* Local database path used by the default PGlite setup.
|
|
40
|
+
*
|
|
41
|
+
* Default: `"./.gencow/data"`
|
|
42
|
+
*/
|
|
43
|
+
url?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Project configuration for `gencow.config.ts`.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* import { defineConfig } from "@gencow/core";
|
|
52
|
+
*
|
|
53
|
+
* export default defineConfig({
|
|
54
|
+
* functionsDir: "./gencow",
|
|
55
|
+
* schema: ["./gencow/schema.ts", "./gencow/auth-schema.ts"],
|
|
56
|
+
* codegenOutDir: "./src/gencow",
|
|
57
|
+
* storage: "./.gencow/uploads",
|
|
58
|
+
* db: { url: "./.gencow/data" },
|
|
59
|
+
* port: 5456,
|
|
60
|
+
* deploy: { app: "my-app" },
|
|
61
|
+
* });
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export interface GencowConfig {
|
|
65
|
+
/**
|
|
66
|
+
* Directory containing your backend modules such as `index.ts`, `schema.ts`,
|
|
67
|
+
* and optional files like `crons.ts` or `seed.ts`.
|
|
68
|
+
*
|
|
69
|
+
* Default: `"./gencow"`
|
|
70
|
+
*/
|
|
71
|
+
functionsDir?: string;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Path to the Drizzle schema file, or multiple schema files when your project
|
|
75
|
+
* splits auth and application tables.
|
|
76
|
+
*
|
|
77
|
+
* Default: `"./gencow/schema.ts"`
|
|
78
|
+
*/
|
|
79
|
+
schema?: string | string[];
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Output directory for generated frontend codegen artifacts such as `api.ts`
|
|
83
|
+
* and declaration files.
|
|
84
|
+
*
|
|
85
|
+
* Default: `"./src/gencow"`
|
|
86
|
+
*/
|
|
87
|
+
codegenOutDir?: string;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Directory used for uploaded file storage in local development.
|
|
91
|
+
*
|
|
92
|
+
* Default: `"./.gencow/uploads"`
|
|
93
|
+
*/
|
|
94
|
+
storage?: string;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Local database configuration.
|
|
98
|
+
*/
|
|
99
|
+
db?: GencowDbConfig;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Port used by the local dev server.
|
|
103
|
+
*
|
|
104
|
+
* Default: `5456`
|
|
105
|
+
*/
|
|
106
|
+
port?: number;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Optional cloud deployment metadata.
|
|
110
|
+
*/
|
|
111
|
+
deploy?: GencowDeployConfig;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Helper for authoring typed `gencow.config.ts` files with editor autocomplete.
|
|
116
|
+
*/
|
|
117
|
+
export function defineConfig(config: GencowConfig): GencowConfig {
|
|
118
|
+
return config;
|
|
119
|
+
}
|
package/src/context.ts
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import type { Storage } from "./storage.js";
|
|
2
|
+
import type { Scheduler } from "./scheduler.js";
|
|
3
|
+
import type {
|
|
4
|
+
HybridSearchOptions,
|
|
5
|
+
SearchOptions,
|
|
6
|
+
SearchResponse,
|
|
7
|
+
VectorSearchOptions,
|
|
8
|
+
} from "./search-types.js";
|
|
9
|
+
import type { GencowServicesCtx } from "./document-types.js";
|
|
10
|
+
import type { GroundingRuntime } from "./grounded-answer-types.js";
|
|
11
|
+
import type { RetryOptions } from "./retry.js";
|
|
12
|
+
import type { GencowProcedureDef } from "./procedure.js";
|
|
13
|
+
|
|
14
|
+
// ─── GencowCtx — 사용자 함수에 주입되는 컨텍스트 ──────────
|
|
15
|
+
|
|
16
|
+
export interface UserIdentity {
|
|
17
|
+
id: string;
|
|
18
|
+
email: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface AuthCtx {
|
|
23
|
+
/** 현재 유저 반환 (비로그인 시 null) — Convex의 ctx.auth.getUserIdentity() */
|
|
24
|
+
getUserIdentity(): UserIdentity | null;
|
|
25
|
+
/** 현재 유저 반환 (비로그인 시 401 throw) */
|
|
26
|
+
requireAuth(): UserIdentity;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* mutation handler 내에서 구독자들에게 데이터를 즉시 push합니다.
|
|
31
|
+
* 클라이언트는 이 데이터를 받아 re-fetch 없이 state를 업데이트합니다.
|
|
32
|
+
*/
|
|
33
|
+
export interface RealtimeCtx {
|
|
34
|
+
/**
|
|
35
|
+
* 특정 queryKey를 구독 중인 클라이언트에 데이터를 즉시 push합니다.
|
|
36
|
+
* 초고빈도 mutation (채팅 등)에서 query re-run 비용을 회피할 때 사용.
|
|
37
|
+
*
|
|
38
|
+
* @param queryKey - 업데이트할 쿼리 키 (예: "tasks.list")
|
|
39
|
+
* @param data - push할 데이터 (해당 query 결과와 동일한 타입)
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* const freshList = await ctx.db.select().from(tasks);
|
|
43
|
+
* ctx.realtime.emit("tasks.list", freshList);
|
|
44
|
+
*/
|
|
45
|
+
emit(queryKey: string, data: unknown): void;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 특정 queryKey 구독자에게 재조회 신호만 보냅니다.
|
|
49
|
+
* private/RLS query처럼 서버가 안전하게 full payload를 만들 수 없는 경우 기본값입니다.
|
|
50
|
+
*/
|
|
51
|
+
invalidate(queryKey: string | string[]): void;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 수동 mutation에서 리얼타임 업데이트의 기본 권장 방식.
|
|
55
|
+
* mutation handler 완료 후 서버가 해당 query를 re-run하여 결과를 push합니다.
|
|
56
|
+
* 복잡한 JOIN query도 queryKey만 지정하면 됩니다.
|
|
57
|
+
*
|
|
58
|
+
* @param queryKey - re-run할 쿼리 키 (예: "dashboard.revenue")
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* mutation("orders.place", {
|
|
62
|
+
* handler: async (ctx, args) => {
|
|
63
|
+
* await ctx.db.insert(orders).values(args);
|
|
64
|
+
* ctx.realtime.refresh("orders.list");
|
|
65
|
+
* ctx.realtime.refresh("dashboard.revenue"); // JOIN query도 OK
|
|
66
|
+
* }
|
|
67
|
+
* });
|
|
68
|
+
*/
|
|
69
|
+
refresh(queryKey: string): void;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type RealtimeNotifyEvent =
|
|
73
|
+
| { type: "emit"; queryKey: string; data: unknown }
|
|
74
|
+
| { type: "invalidate"; queryKeys: string[] };
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 사용자 함수(query/mutation)에 주입되는 컨텍스트.
|
|
78
|
+
* Convex의 ctx 패턴과 동일하게, 이 객체를 통해서만 DB/Storage/Auth에 접근 가능.
|
|
79
|
+
* fs, child_process 등 원시 Node.js API는 노출되지 않음.
|
|
80
|
+
*/
|
|
81
|
+
// ─── AI Context ─────────────────────────────────────────
|
|
82
|
+
|
|
83
|
+
export interface AIMessage {
|
|
84
|
+
role: "user" | "system" | "assistant";
|
|
85
|
+
content: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface AIResult {
|
|
89
|
+
text: string;
|
|
90
|
+
usage: { promptTokens: number; completionTokens: number; totalTokens: number };
|
|
91
|
+
creditsCharged: number;
|
|
92
|
+
model: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface AIContext {
|
|
96
|
+
/** AI 텍스트 생성 */
|
|
97
|
+
chat: (opts: {
|
|
98
|
+
model?: string;
|
|
99
|
+
messages: AIMessage[];
|
|
100
|
+
/** System prompt — shorthand for adding a system message */
|
|
101
|
+
system?: string;
|
|
102
|
+
temperature?: number;
|
|
103
|
+
maxTokens?: number;
|
|
104
|
+
/** Response format — e.g. { type: "json_object" } for JSON mode */
|
|
105
|
+
responseFormat?: { type: string };
|
|
106
|
+
}) => Promise<AIResult>;
|
|
107
|
+
/** 텍스트 임베딩 (단일) */
|
|
108
|
+
embed: (text: string) => Promise<number[]>;
|
|
109
|
+
/** 배치 임베딩 */
|
|
110
|
+
embedMany: (texts: string[]) => Promise<number[][]>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface GencowCtx {
|
|
114
|
+
/** Drizzle DB 인스턴스 (scoped) — 스키마 filter 자동 적용, execute 차단 */
|
|
115
|
+
db: any; // typed per-app via generic
|
|
116
|
+
/** Raw Drizzle DB — 필터 없음, execute 허용. ⚠️ 이름이 곧 경고. */
|
|
117
|
+
unsafeDb: any;
|
|
118
|
+
/** 인증 컨텍스트 — ctx.auth.getUserIdentity() */
|
|
119
|
+
auth: AuthCtx;
|
|
120
|
+
/** 파일 스토리지 — ctx.storage.store(), ctx.storage.getUrl() */
|
|
121
|
+
storage: Storage;
|
|
122
|
+
/** 스케줄러 — ctx.scheduler.runAfter(), ctx.scheduler.cron() */
|
|
123
|
+
scheduler: Scheduler;
|
|
124
|
+
/** 실시간 push — ctx.realtime.emit(queryKey, data) */
|
|
125
|
+
realtime: RealtimeCtx;
|
|
126
|
+
/** 재시도 — ctx.retry(fn, opts) — exponential backoff + jitter */
|
|
127
|
+
retry: <T>(fn: () => Promise<T>, options?: RetryOptions) => Promise<T>;
|
|
128
|
+
/** 프레임워크 서비스 헬퍼 — workflow 전용 service는 별도 ctx에서 노출 */
|
|
129
|
+
services: GencowServicesCtx;
|
|
130
|
+
/** AI 헬퍼 */
|
|
131
|
+
ai?: AIContext;
|
|
132
|
+
/** Full-text / hybrid search helper */
|
|
133
|
+
search: (table: string, query: string, options: SearchOptions) => Promise<SearchResponse>;
|
|
134
|
+
/** Vector / semantic search helper */
|
|
135
|
+
vectorSearch: (table: string, options: VectorSearchOptions) => Promise<SearchResponse>;
|
|
136
|
+
/** Hybrid search helper (lexical + vector) */
|
|
137
|
+
hybridSearch: (table: string, query: string, options: HybridSearchOptions) => Promise<SearchResponse>;
|
|
138
|
+
/** Grounded answer helper over canonical rag_* tables */
|
|
139
|
+
grounding?: GroundingRuntime;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface GencowDefinition {
|
|
143
|
+
[procedureName: string]: GencowProcedureDef<any, any, any, any>;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface GencowApiDefinition {
|
|
147
|
+
procedures: GencowDefinition;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function defineApi<const TApi extends GencowApiDefinition>(api: TApi): TApi {
|
|
151
|
+
return api;
|
|
152
|
+
}
|
package/src/crud.ts
CHANGED
|
@@ -57,7 +57,9 @@ import {
|
|
|
57
57
|
} from "drizzle-orm";
|
|
58
58
|
import type { PgTable, AnyPgColumn } from "drizzle-orm/pg-core";
|
|
59
59
|
import { getTableConfig } from "drizzle-orm/pg-core";
|
|
60
|
-
import {
|
|
60
|
+
import { buildQuerySubscriptionKey } from "./reactive-realtime.js";
|
|
61
|
+
import { query } from "./reactive-query.js";
|
|
62
|
+
import { mutation } from "./reactive-mutation.js";
|
|
61
63
|
import { v } from "./v.js";
|
|
62
64
|
import { getOwnerRlsMeta, registerOwnerRls } from "./rls.js";
|
|
63
65
|
|
|
@@ -473,23 +475,12 @@ export function crud<T extends PgTable>(table: T, options?: CrudOptions<T>) {
|
|
|
473
475
|
return await fn(db);
|
|
474
476
|
}
|
|
475
477
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
// → 다른 사용자에게 타인 데이터가 push되지 않도록
|
|
483
|
-
let effectiveWhere = whereClause;
|
|
484
|
-
if (ownerMeta && userId && !ownerMeta.readPublic) {
|
|
485
|
-
const ownerFilter = eq(ownerMeta.column, userId);
|
|
486
|
-
effectiveWhere = effectiveWhere ? and(effectiveWhere, ownerFilter) : ownerFilter;
|
|
487
|
-
}
|
|
488
|
-
return await inRlsOrPlainTx(db, async (tx: any) => {
|
|
489
|
-
const data = await tx.select().from(anyTable).where(effectiveWhere).orderBy(desc(defaultOrderCol));
|
|
490
|
-
const countResult = await tx.select({ count: drizzleCount() }).from(anyTable).where(effectiveWhere);
|
|
491
|
-
return { data, total: Number(countResult[0]?.count ?? 0) };
|
|
492
|
-
});
|
|
478
|
+
function invalidateListRealtime(ctx: any) {
|
|
479
|
+
ctx.realtime.invalidate(`${prefix}.list`);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function invalidateGetRealtime(ctx: any, id: unknown) {
|
|
483
|
+
ctx.realtime.invalidate(buildQuerySubscriptionKey(`${prefix}.get`, { id }));
|
|
493
484
|
}
|
|
494
485
|
|
|
495
486
|
// ── methods 필터링: 지정된 메서드만 레지스트리 등록 ──
|
|
@@ -636,13 +627,9 @@ export function crud<T extends PgTable>(table: T, options?: CrudOptions<T>) {
|
|
|
636
627
|
tx.insert(anyTable).values(insertData).returning(),
|
|
637
628
|
);
|
|
638
629
|
|
|
639
|
-
// Realtime push
|
|
640
|
-
// ownerRls 시 해당 사용자 데이터만 push (타 사용자에게 누출 방지)
|
|
641
|
-
// S5: requireAuth로 확실한 userId 획득 (getUserIdentity null 방지)
|
|
630
|
+
// Realtime push: list는 payload 없이 invalidation으로 갱신
|
|
642
631
|
if (useRealtime && enabledMethods.has("list")) {
|
|
643
|
-
|
|
644
|
-
const listResult = await fetchListWithTotal(ctx.db, undefined, currentUserId);
|
|
645
|
-
ctx.realtime.emit(`${prefix}.list`, listResult);
|
|
632
|
+
invalidateListRealtime(ctx);
|
|
646
633
|
}
|
|
647
634
|
|
|
648
635
|
return result;
|
|
@@ -690,16 +677,15 @@ export function crud<T extends PgTable>(table: T, options?: CrudOptions<T>) {
|
|
|
690
677
|
tx.update(anyTable).set(updateData).where(updateWhere).returning(),
|
|
691
678
|
);
|
|
692
679
|
|
|
693
|
-
// Realtime push
|
|
694
|
-
// S5: ownerRls 시 user.id 사용 (getUserIdentity null 방지)
|
|
680
|
+
// Realtime push: list는 invalidation, public exact-id get만 full payload 유지
|
|
695
681
|
if (useRealtime) {
|
|
696
|
-
const currentUserId = ownerMeta ? user?.id : undefined;
|
|
697
682
|
if (enabledMethods.has("list")) {
|
|
698
|
-
|
|
699
|
-
ctx.realtime.emit(`${prefix}.list`, listResult);
|
|
683
|
+
invalidateListRealtime(ctx);
|
|
700
684
|
}
|
|
701
685
|
if (enabledMethods.has("get")) {
|
|
702
|
-
|
|
686
|
+
const getKey = buildQuerySubscriptionKey(`${prefix}.get`, { id });
|
|
687
|
+
if (isPublic && !ownerMeta) ctx.realtime.emit(getKey, result);
|
|
688
|
+
else invalidateGetRealtime(ctx, id);
|
|
703
689
|
}
|
|
704
690
|
}
|
|
705
691
|
|
|
@@ -736,12 +722,9 @@ export function crud<T extends PgTable>(table: T, options?: CrudOptions<T>) {
|
|
|
736
722
|
}
|
|
737
723
|
});
|
|
738
724
|
|
|
739
|
-
// Realtime push
|
|
740
|
-
// S5: ownerRls 시 user.id 사용
|
|
725
|
+
// Realtime push: list는 payload 없이 invalidation으로 갱신
|
|
741
726
|
if (useRealtime && enabledMethods.has("list")) {
|
|
742
|
-
|
|
743
|
-
const listResult = await fetchListWithTotal(ctx.db, undefined, currentUserId);
|
|
744
|
-
ctx.realtime.emit(`${prefix}.list`, listResult);
|
|
727
|
+
invalidateListRealtime(ctx);
|
|
745
728
|
}
|
|
746
729
|
|
|
747
730
|
return { success: true };
|
package/src/document-types.ts
CHANGED
|
@@ -6,9 +6,16 @@ export type DocumentConvertMode =
|
|
|
6
6
|
| "prefer-external"
|
|
7
7
|
| "force-external"
|
|
8
8
|
| "force-ocr";
|
|
9
|
-
export type DocumentConvertProvider =
|
|
9
|
+
export type DocumentConvertProvider =
|
|
10
|
+
| "auto"
|
|
11
|
+
| "local_text"
|
|
12
|
+
| "opendataloader"
|
|
13
|
+
| "gemini"
|
|
14
|
+
| "openai"
|
|
15
|
+
| "ocr"
|
|
16
|
+
| "custom_vlm";
|
|
10
17
|
export type DocumentResolvedProvider = Exclude<DocumentConvertProvider, "auto">;
|
|
11
|
-
export type DocumentProviderRoute = "local_text" | "vlm" | "ocr_fallback";
|
|
18
|
+
export type DocumentProviderRoute = "local_text" | "opendataloader" | "vlm" | "ocr_fallback";
|
|
12
19
|
export type DocumentCacheArtifact = "convert" | "embedding" | "summary" | "rerank";
|
|
13
20
|
|
|
14
21
|
export type DocumentConvertInput = {
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { GencowCtx } from "./context.js";
|
|
2
|
+
|
|
3
|
+
/** httpAction 핸들러 — Hono 대신 Request/Response 타입으로 full HTTP 제어. */
|
|
4
|
+
export type HttpActionHandler = (ctx: GencowCtx, req: HttpActionRequest) => Promise<HttpActionResponse>;
|
|
5
|
+
|
|
6
|
+
export interface HttpActionRequest {
|
|
7
|
+
/** HTTP method (GET, POST, PUT, DELETE, PATCH) */
|
|
8
|
+
method: string;
|
|
9
|
+
/** Full URL */
|
|
10
|
+
url: string;
|
|
11
|
+
/** URL path (e.g. /api/cli/auth-start) */
|
|
12
|
+
path: string;
|
|
13
|
+
/** Route params (e.g. { id: "abc" } for /api/apps/:id) */
|
|
14
|
+
params: Record<string, string>;
|
|
15
|
+
/** Query string params */
|
|
16
|
+
query: Record<string, string>;
|
|
17
|
+
/** Request headers */
|
|
18
|
+
headers: Record<string, string>;
|
|
19
|
+
/** Parse JSON body */
|
|
20
|
+
json: <T = unknown>() => Promise<T>;
|
|
21
|
+
/** Parse form data */
|
|
22
|
+
formData: () => Promise<FormData>;
|
|
23
|
+
/** Raw body as ArrayBuffer */
|
|
24
|
+
arrayBuffer: () => Promise<ArrayBuffer>;
|
|
25
|
+
/** Raw body as text */
|
|
26
|
+
text: () => Promise<string>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface HttpActionResponse {
|
|
30
|
+
status?: number;
|
|
31
|
+
headers?: Record<string, string>;
|
|
32
|
+
body?: unknown;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** httpAction 정의. 커스텀 HTTP 엔드포인트를 선언적으로 등록. */
|
|
36
|
+
export interface HttpActionDef {
|
|
37
|
+
/** HTTP method */
|
|
38
|
+
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
39
|
+
/** URL path (Hono 패턴 — /api/cli/:code 형태 지원) */
|
|
40
|
+
path: string;
|
|
41
|
+
/** true = 인증 없이 접근 가능, false(기본) = auth 필수 */
|
|
42
|
+
isPublic: boolean;
|
|
43
|
+
/** 핸들러 */
|
|
44
|
+
handler: HttpActionHandler;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ─── httpAction registry (globalThis) ───────────────────
|
|
48
|
+
// globalThis shared singleton — dual-bundle safe (see analysis-dual-module-registry.md).
|
|
49
|
+
|
|
50
|
+
declare global {
|
|
51
|
+
var __gencow_httpActionRegistry: HttpActionDef[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!globalThis.__gencow_httpActionRegistry) globalThis.__gencow_httpActionRegistry = [];
|
|
55
|
+
|
|
56
|
+
export const httpActionRegistry = globalThis.__gencow_httpActionRegistry;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 커스텀 HTTP 엔드포인트를 선언적으로 등록합니다.
|
|
60
|
+
* query/mutation은 RPC 패턴이지만, httpAction은 RESTful HTTP 라우트를 직접 정의합니다.
|
|
61
|
+
*
|
|
62
|
+
* 사용 사례:
|
|
63
|
+
* - CLI Device Auth (POST /api/cli/auth-start)
|
|
64
|
+
* - 파일 업로드 (POST /api/apps/:id/deploy)
|
|
65
|
+
* - Webhook 수신
|
|
66
|
+
* - 외부 서비스 콜백
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* import { httpAction } from "@gencow/core";
|
|
71
|
+
*
|
|
72
|
+
* export const authStart = httpAction({
|
|
73
|
+
* method: "POST",
|
|
74
|
+
* path: "/api/cli/auth-start",
|
|
75
|
+
* public: true,
|
|
76
|
+
* handler: async (ctx, req) => {
|
|
77
|
+
* const code = crypto.randomUUID().slice(0, 8);
|
|
78
|
+
* return { body: { code, url: `https://gencow.com/cli-auth?code=${code}` } };
|
|
79
|
+
* },
|
|
80
|
+
* });
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export function httpAction(def: {
|
|
84
|
+
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
85
|
+
path: string;
|
|
86
|
+
public?: boolean;
|
|
87
|
+
handler: HttpActionHandler;
|
|
88
|
+
}): HttpActionDef {
|
|
89
|
+
const actionDef: HttpActionDef = {
|
|
90
|
+
method: def.method,
|
|
91
|
+
path: def.path,
|
|
92
|
+
isPublic: def.public === true,
|
|
93
|
+
handler: def.handler,
|
|
94
|
+
};
|
|
95
|
+
httpActionRegistry.push(actionDef);
|
|
96
|
+
return actionDef;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function getRegisteredHttpActions(): HttpActionDef[] {
|
|
100
|
+
return [...httpActionRegistry];
|
|
101
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -9,17 +9,21 @@ export type {
|
|
|
9
9
|
GencowCtx,
|
|
10
10
|
AuthCtx,
|
|
11
11
|
UserIdentity,
|
|
12
|
-
QueryDef,
|
|
13
|
-
MutationDef,
|
|
14
12
|
RealtimeCtx,
|
|
13
|
+
RealtimeNotifyEvent,
|
|
14
|
+
AIContext,
|
|
15
|
+
AIMessage,
|
|
16
|
+
AIResult,
|
|
17
|
+
} from "./context.js";
|
|
18
|
+
export { defineApi } from "./context.js";
|
|
19
|
+
export type { QueryDef } from "./reactive-query-types.js";
|
|
20
|
+
export type { MutationDef } from "./reactive-mutation-types.js";
|
|
21
|
+
export type {
|
|
15
22
|
HttpActionDef,
|
|
16
23
|
HttpActionRequest,
|
|
17
24
|
HttpActionResponse,
|
|
18
25
|
HttpActionHandler,
|
|
19
|
-
|
|
20
|
-
AIMessage,
|
|
21
|
-
AIResult,
|
|
22
|
-
} from "./reactive.js";
|
|
26
|
+
} from "./http-action.js";
|
|
23
27
|
export type {
|
|
24
28
|
SearchPrimitive,
|
|
25
29
|
SearchScope,
|
|
@@ -47,6 +51,28 @@ export type {
|
|
|
47
51
|
WorkflowDocumentServicesCtx,
|
|
48
52
|
} from "./document-types.js";
|
|
49
53
|
export { buildDocumentCacheKey } from "./document-types.js";
|
|
54
|
+
export type {
|
|
55
|
+
WakeAppBootFailedResult,
|
|
56
|
+
WakeAppDeferredResult,
|
|
57
|
+
WakeAppDeferredStatus,
|
|
58
|
+
WakeAppResult,
|
|
59
|
+
WakeAppSuccessResult,
|
|
60
|
+
WakeAppSuccessStatus,
|
|
61
|
+
} from "./wake-app-result.js";
|
|
62
|
+
export {
|
|
63
|
+
DEFAULT_WAKE_RETRY_AFTER_SEC,
|
|
64
|
+
buildWakeAppBootFailedResult,
|
|
65
|
+
buildWakeAppSuccessResult,
|
|
66
|
+
isWakeAppDeferredResult,
|
|
67
|
+
} from "./wake-app-result.js";
|
|
68
|
+
export type { PlatformCapacityPreset, PlatformCapacityProfileName } from "./platform-capacity-profile.js";
|
|
69
|
+
export {
|
|
70
|
+
PLATFORM_CAPACITY_ENV_KEYS,
|
|
71
|
+
PLATFORM_CAPACITY_PRESETS,
|
|
72
|
+
PLATFORM_CAPACITY_PROFILE_ENV,
|
|
73
|
+
detectPlatformCapacityProfile,
|
|
74
|
+
resolvePlatformCapacityPreset,
|
|
75
|
+
} from "./platform-capacity-profile.js";
|
|
50
76
|
export type {
|
|
51
77
|
RagIngestReindexMode,
|
|
52
78
|
RagIngestInput,
|
|
@@ -83,23 +109,33 @@ export type {
|
|
|
83
109
|
RagReindexMode,
|
|
84
110
|
RagReindexPlan,
|
|
85
111
|
} from "./rag-operations-types.js";
|
|
86
|
-
export { ragCorpora, ragSources, ragSections, ragChunks, ragIngestJobs, ragOperationMetrics } from "./rag-schema.js";
|
|
87
112
|
export {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
113
|
+
ragCorpora,
|
|
114
|
+
ragSources,
|
|
115
|
+
ragSections,
|
|
116
|
+
ragChunks,
|
|
117
|
+
ragIngestJobs,
|
|
118
|
+
ragOperationMetrics,
|
|
119
|
+
} from "./rag-schema.js";
|
|
120
|
+
export { buildQuerySubscriptionKey, subscriptionKeyMatchesQueryKey } from "./reactive-realtime.js";
|
|
121
|
+
export { query, getQueryHandler, getQueryDef, getRegisteredQueries } from "./reactive-query.js";
|
|
122
|
+
export { mutation, getRegisteredMutations } from "./reactive-mutation.js";
|
|
123
|
+
export { procQuery, procMutation } from "./procedure.js";
|
|
124
|
+
export type {
|
|
125
|
+
GencowProcedureBuilder,
|
|
126
|
+
GencowProcedureDef,
|
|
127
|
+
GencowProcedureMiddleware,
|
|
128
|
+
GencowProcedureHandler,
|
|
129
|
+
} from "./procedure.js";
|
|
130
|
+
export { httpAction, getRegisteredHttpActions } from "./http-action.js";
|
|
131
|
+
export {
|
|
92
132
|
subscribe,
|
|
93
133
|
unsubscribe,
|
|
94
134
|
registerClient,
|
|
95
135
|
deregisterClient,
|
|
136
|
+
buildRealtimeCtx,
|
|
96
137
|
handleWsMessage,
|
|
97
|
-
|
|
98
|
-
getQueryDef,
|
|
99
|
-
getRegisteredQueries,
|
|
100
|
-
getRegisteredMutations,
|
|
101
|
-
getRegisteredHttpActions,
|
|
102
|
-
} from "./reactive.js";
|
|
138
|
+
} from "./reactive-realtime.js";
|
|
103
139
|
export type { Storage, StoredFile } from "./storage.js";
|
|
104
140
|
export { createScheduler, getSchedulerInfo } from "./scheduler.js";
|
|
105
141
|
export type {
|
|
@@ -150,14 +186,36 @@ export { filterTenantRuntimeEnvVars, isReservedTenantRuntimeEnvKey } from "./run
|
|
|
150
186
|
export { cronJobs } from "./crons.js";
|
|
151
187
|
export type { CronJobsBuilder, CronJobDef, IntervalOptions, DailyOptions, WeeklyOptions } from "./crons.js";
|
|
152
188
|
export { defineAuth } from "./auth-config.js";
|
|
153
|
-
export type {
|
|
189
|
+
export type {
|
|
190
|
+
GencowAuthConfig,
|
|
191
|
+
AuthEmailVerification,
|
|
192
|
+
AuthPasswordReset,
|
|
193
|
+
AuthEvents,
|
|
194
|
+
AuthHookContext,
|
|
195
|
+
AuthUserLike,
|
|
196
|
+
AuthOAuthConfig,
|
|
197
|
+
SocialProviderConfig,
|
|
198
|
+
SocialProvidersConfig,
|
|
199
|
+
KakaoConfig,
|
|
200
|
+
NaverConfig,
|
|
201
|
+
CustomOAuthProvider,
|
|
202
|
+
OAuthUserInfo,
|
|
203
|
+
} from "./auth-config.js";
|
|
204
|
+
export { defineConfig } from "./config.js";
|
|
205
|
+
export type { GencowConfig, GencowDbConfig, GencowDeployConfig } from "./config.js";
|
|
154
206
|
|
|
155
207
|
// ─── RLS + CRUD Factory ───────────
|
|
156
208
|
export { ownerRls, getOwnerRlsMeta, registerOwnerRls } from "./rls.js";
|
|
157
209
|
export type { OwnerRlsMeta } from "./rls.js";
|
|
158
210
|
export { createRlsDb } from "./rls-db.js";
|
|
159
211
|
export type { RlsSessionContext } from "./rls-db.js";
|
|
160
|
-
export {
|
|
212
|
+
export {
|
|
213
|
+
crud,
|
|
214
|
+
parseFilterNode,
|
|
215
|
+
applyFilterOp,
|
|
216
|
+
getOwnerRlsTables,
|
|
217
|
+
getRegisteredCrudCodegenMeta,
|
|
218
|
+
} from "./crud.js";
|
|
161
219
|
export type { CrudCodegenMeta } from "./crud.js";
|
|
162
220
|
|
|
163
221
|
// Deprecated alias — 하위호환용, 향후 메이저 버전에서 제거 예정
|